Adsense HTML/JavaScript

Showing posts with label ESP32-S2. Show all posts
Showing posts with label ESP32-S2. Show all posts

Tuesday, April 26, 2022

ESP32-S2 (arduino-esp32) display on ILI9341 SPI TFT with Touch, using TFT_eSPI Library.

TFT_eSPI is a Arduino and PlatformIO IDE compatible TFT library optimized for the Raspberry Pi Pico (RP2040), STM32, ESP8266 and ESP32 that supports different driver chips.

Connection:


ILI9488
-------
1  - VCC	VCC
2  - GND	GND
3  - CS		34
4  - RESET	38
5  - DC		39
6  - SDI(MOSI)	35
7  - SCK	36
8  - LED	VCC
9  - SDO (MISO)	37
10 - T_CLK	(SCK)
11 - T_CS	40
12 - T_DIN	(MOSI)
13 - T_DO	(MISO)
14 - T_IRQ	no connection
In arduino-esp32, the default pins of ESP32S2 Dev Module for SPI are:
Default SS:         34
Default MOSI:    35
Default MISO:    37
Default SCK:      36

In TFT_eSPI, the SPI bus for the touch controller is shared with the TFT and only an additional chip select line is needed.

Setup TFT_eSPI Library:

This video show how to setup TFT_eSPI library in Arduino IDE, tested on ESP32-S2-Saola-1, with 2.4inch SPI Module ILI9341 SKU:MSP2402 with Touch.


Refer to "Tips" section in the TFT_eSPI page:

If you load a new copy of TFT_eSPI then it will overwrite your setups if they are kept within the TFT_eSPI folder. One way around this is to create a new folder in your Arduino library folder called "TFT_eSPI_Setups". You then place your custom setup.h files in there. After an upgrade simply edit the User_Setup_Select.h file to point to your custom setup file.

You can take this one step further and have your own setup select file and then you only need to replace the Setup.h line reference in User_Setup_Select.h to.

mySetup70_ESP32_S2_ILI9341.h, my custom setup.h for ESP32-S2 using ILI9341.
// Setup for the ESP32 S2 with ILI9341 display
// Note SPI DMA with ESP32 S2 is not currently supported
#define USER_SETUP_ID 70
// See SetupX_Template.h for all options available
#define ILI9341_DRIVER
/*
                    // Typical board default pins
#define TFT_CS   10 //     10 or 34

#define TFT_MOSI 11 //     11 or 35
#define TFT_SCLK 12 //     12 or 36
#define TFT_MISO 13 //     13 or 37

#define TFT_DC   14
#define TFT_RST  15
*/
#define TFT_MISO 37
#define TFT_MOSI 35
#define TFT_SCLK 36
#define TFT_CS   34
#define TFT_DC   39
#define TFT_RST  38

//#define TOUCH_CS 16 // Optional for touch screen
#define TOUCH_CS 40


#define LOAD_GLCD
#define LOAD_FONT2
#define LOAD_FONT4
#define LOAD_FONT6
#define LOAD_FONT7
#define LOAD_FONT8
#define LOAD_GFXFF

#define SMOOTH_FONT

// FSPI port will be used unless the following is defined
#define USE_HSPI_PORT

//#define SPI_FREQUENCY  27000000
#define SPI_FREQUENCY  40000000   // Maximum for ILI9341

#define SPI_READ_FREQUENCY  6000000 // 6 MHz is the maximum SPI read speed for the ST7789V

#define SPI_TOUCH_FREQUENCY 2500000


Updated User_Setup_Select.h.
// This header file contains a list of user setup files and defines which one the
// compiler uses when the IDE performs a Verify/Compile or Upload.
//
// Users can create configurations for different Espressif boards and TFT displays.
// This makes selecting between hardware setups easy by "uncommenting" one line.

// The advantage of this hardware configuration method is that the examples provided
// with the library should work with different setups immediately without any other
// changes being needed. It also improves the portability of users sketches to other
// hardware configurations and compatible libraries.
//
// Create a shortcut to this file on your desktop to permit quick access for editing.
// Re-compile and upload after making and saving any changes to this file.

// Customised User_Setup files are stored in the "User_Setups" folder.

#ifndef USER_SETUP_LOADED //  Lets PlatformIO users define settings in
                          //  platformio.ini, see notes in "Tools" folder.

// Only ONE line below should be uncommented.  Add extra lines and files as needed.

//#include <User_Setup.h>           // Default setup is root library folder
#include <../TFT_eSPI_Setups/mySetup70_ESP32_S2_ILI9341.h>

//...




Friday, October 29, 2021

arduino-esp32 CameraWebServer example, run on ESP32-S2-Saola-1 with ov2640

This post show how to run arduino-esp32 CameraWebServer example on ESP32-S2-Saola-1 with ov2640 camera.


For convenience, I connect ov2640 pins all in one side of ESP32-S2-Saola-1:

Connection between ESP32-S2-Saola-1 and ov2640

	ov2640
	+-----------+
3V3	|3V3	GND |	GND
IO9	|SIOC	SIOD|	IO1
IO10	|VSYNC	HREF|	IO2
IO11	|PCLK	XCLK|	IO3
IO12	|D9	D8  |	IO4
IO13	|D7	D6  |	IO5
IO14	|D5	D4  |	IO6
IO15	|D3	D2  |	IO7
IO16	|RESET	PWDN|	-
-	|D1	D0  |	-
	+-----------+
		
ESP32-S2-Saola-1
------+
 GND  |	- cam.GND
 5V   |
 IO17 |
 IO16 | - cam.RESET
 IO15 |	- cam.D3
 IO14 |	- cam.D5
 IO13 |	- cam.D7
 IO12 |	- cam.D9
 IO11 |	- cam.PCLK
 IO10 |	- cam.VSYNC
 IO9  |	- cam.SIOC
 IO8  |
 IO7  |	- cam.D2
 IO6  |	- cam.D4
 IO5  |	- cam.D6
 IO4  |	- cam.D8
 IO3  |	- cam.XCLK
 IO2  | - cam.HREF
 IO1  |	- cam.SIOD
 IO0  |
 3V3  |	- cam.3V3
------+
 
*cam.SIOC/SIOD are I2C-like control pins, pull-up resistors are needed.
 I use 2K ohm resistor for it.

To program ESP32-S2 on Arduino IDE, arduino-esp32 2.0.0 is needed. Select board of "ESP32S2 Dev Module".

Load CameraServer example:
Click on Menu : File > Examples > ESP32 > Camera > CameraWebServer

Edit camera_pins.h, update pins definition to match connection:

// for ESP32-S2-Saola-1/ov2640
#define PWDN_GPIO_NUM    -1
#define RESET_GPIO_NUM   16
#define XCLK_GPIO_NUM    3
#define SIOD_GPIO_NUM    1
#define SIOC_GPIO_NUM    9

#define Y9_GPIO_NUM      12
#define Y8_GPIO_NUM      4
#define Y7_GPIO_NUM      13
#define Y6_GPIO_NUM      5
#define Y5_GPIO_NUM      14
#define Y4_GPIO_NUM      6
#define Y3_GPIO_NUM      15
#define Y2_GPIO_NUM      7
#define VSYNC_GPIO_NUM   10
#define HREF_GPIO_NUM    2
#define PCLK_GPIO_NUM    11


Update ssid/password in your main code for your WiFi network.


Upload to board, if fail with error of "frame buffer malloc failed", Select PSRAM option to "Enabled".


If success, you can open browser (in the same WiFi network) to visit the CameraServer.







Tuesday, October 26, 2021

arduino-esp32, drive SSD1306 I2C OLED with ESP32/C3/S2 using esp8266-oled-ssd1306 library


With arduino-esp32 2.0.0 installed on Arduino IDE, this post run examples on ESP32-DevKitC V4/ESP32-S2-Saola-1/ESP32-C3-DevKitM-1 to drive SSD1306 I2C OLED, using esp8266-oled-ssd1306 library.


Open Library Manager in Arduino IDE, install "ESP8266 and ESP32 OLED driver for SSD1306 displays" by ThingPulse, currently 4.2.1. (esp8266-oled-ssd1306)


In the library examples, OLED display is initialized using pre-defined SDA and SCL based on your board's pins_arduino.h.
SSD1306Wire display(0x3c, SDA, SCL);   // ADDRESS, SDA, SCL


for ESP32 Dev Module:
SDA:  21
SCL:  22

for ESP32S2 Dev Module:
SDA:  8
SCL:  9

for ESP32C2 Dev Module:
SDA:  8
SCL:  9

* But on ESP32-C3-DevKitM-1 I used to test for ESP32C2 Dev Module, GPIO8 is connected to onboardRGB LED. (refer to the post "Drive ESP32-C3-DevKitM-1/ESP32-S2-Saola-1 on-board RGB LED (WS2812) in Arduino Framework") So I re-allocate to:
SDA:  19
SCL:  18

same GPIOs assigned in "ESP32-C3/MicroPython + SSD1306 I2C OLED".
SSD1306Wire display(0x3c, 19, 18);   // ADDRESS, SDA, SCL

Also connect ESP32 dev board's 3V3 and GND to SSD1306 VCC and GND.

Monday, October 25, 2021

arduino-esp32, list the pre-defined function pins of ESP32C3/S2 Dev Module

With arduino-esp32 2.0.0 installed on Arduino IDE, the following exercise run on ESP32-C3-DevKitM-1/ESP32-S2-Saola-1 to list the pre-defined function pins of ESP32C3/S2 Dev Module.

This video also show how to locate pins_arduino.h where it defined.


Test on ESP32-C3-DevKitM-1, ESP32-S2-Saola-1 and ESP32-DevKitC V4.

ESP32C3_pins.ino for board of ESP32C3 Dev Module, run on ESP32-C3-DevKitM-1
void setup() {
  // put your setup code here, to run once:
  delay(500);
  Serial.begin(115200);
  delay(500);
  Serial.println("\n\n================================");
  Serial.printf("Chip Model: %s\n", ESP.getChipModel());
  Serial.println("================================");

#ifdef EXTERNAL_NUM_INTERRUPTS
  Serial.printf("EXTERNAL_NUM_INTERRUPTS = %d\n", EXTERNAL_NUM_INTERRUPTS);
#endif
#ifdef NUM_DIGITAL_PINS
  Serial.printf("NUM_DIGITAL_PINS = %d\n", NUM_DIGITAL_PINS);
#endif
#ifdef NUM_ANALOG_INPUTS
  Serial.printf("NUM_ANALOG_INPUTS = %d\n", NUM_ANALOG_INPUTS);
#endif
  Serial.println();
  Serial.printf("Default TX:   %d\n", TX);
  Serial.printf("Default RX:   %d\n", RX);
  Serial.println();
  Serial.printf("Default SDA:  %d\n", SDA);
  Serial.printf("Default SCL:  %d\n", SCL);
  Serial.println();
  Serial.printf("Default SS:   %d\n", SS);
  Serial.printf("Default MOSI: %d\n", MOSI);
  Serial.printf("Default MISO: %d\n", MISO);
  Serial.printf("Default SCK:  %d\n", SCK);
  Serial.println();
  Serial.printf("Default A0:   %d\n", A0);
  Serial.printf("Default A1:   %d\n", A1);
  Serial.printf("Default A2:   %d\n", A2);
  Serial.printf("Default A3:   %d\n", A3);
  Serial.printf("Default A4:   %d\n", A4);
  Serial.printf("Default A5:   %d\n", A5);
  Serial.println("================================");
}

void loop() {
  // put your main code here, to run repeatedly:

}


output:
================================
Chip Model: ESP32-C3
================================
EXTERNAL_NUM_INTERRUPTS = 22
NUM_DIGITAL_PINS = 22
NUM_ANALOG_INPUTS = 6

Default TX:   21
Default RX:   20

Default SDA:  8
Default SCL:  9

Default SS:   7
Default MOSI: 6
Default MISO: 5
Default SCK:  4

Default A0:   0
Default A1:   1
Default A2:   2
Default A3:   3
Default A4:   4
Default A5:   5
================================

ESP32-C3-DevKitM-1 Pin Layout


ESP32S2_pins.ino for board of ESP32S2 Dev Module, run on ESP32-S2-Saola-1
void setup() {
  // put your setup code here, to run once:
  delay(500);
  Serial.begin(115200);
  delay(500);
  Serial.println("\n\n================================");
  Serial.printf("Chip Model: %s\n", ESP.getChipModel());
  Serial.println("================================");

#ifdef EXTERNAL_NUM_INTERRUPTS
  Serial.printf("EXTERNAL_NUM_INTERRUPTS = %d\n", EXTERNAL_NUM_INTERRUPTS);
#endif
#ifdef NUM_DIGITAL_PINS
  Serial.printf("NUM_DIGITAL_PINS = %d\n", NUM_DIGITAL_PINS);
#endif
#ifdef NUM_ANALOG_INPUTS
  Serial.printf("NUM_ANALOG_INPUTS = %d\n", NUM_ANALOG_INPUTS);
#endif
  Serial.println();
  Serial.printf("Default TX:   %d\n", TX);
  Serial.printf("Default RX:   %d\n", RX);
  Serial.println();
  Serial.printf("Default SDA:  %d\n", SDA);
  Serial.printf("Default SCL:  %d\n", SCL);
  Serial.println();
  Serial.printf("Default SS:   %d\n", SS);
  Serial.printf("Default MOSI: %d\n", MOSI);
  Serial.printf("Default MISO: %d\n", MISO);
  Serial.printf("Default SCK:  %d\n", SCK);

  Serial.println();
  Serial.printf("A0\tA1\tA2\tA3\tA4\tA5\tA6\tA7\tA8\tA9\n");
  Serial.printf("%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\n", 
                 A0, A1, A2, A3, A4, A5, A6, A7, A8, A9);
  Serial.println();
  Serial.printf("A10\tA11\tA12\tA13\tA14\tA15\tA16\tA17\tA18\tA19\n");
  Serial.printf("%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\n", 
                 A10, A11, A12, A13, A14, A15, A16, A17, A18, A19);
  Serial.println();

  Serial.printf("T1\tT2\tT3\tT4\tT5\tT6\tT7\tT8\tT9\tT10\n");
  Serial.printf("%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\n", 
                 T1, T2, T3, T4, T5, T6, T7, T8, T9, T10);
  Serial.println();
  Serial.printf("T11\tT12\tT13\tT14\n");
  Serial.printf("%d\t%d\t%d\t%d\n", 
                 T11, T12, T13, T14);
  Serial.println();
  Serial.printf("Default DAC1:  %d\n", DAC1);
  Serial.printf("Default DAC2:  %d\n", DAC2);
  Serial.println("================================");
}

void loop() {
  // put your main code here, to run repeatedly:

}


output:
================================
Chip Model: ESP32-S2
================================
EXTERNAL_NUM_INTERRUPTS = 46
NUM_DIGITAL_PINS = 48
NUM_ANALOG_INPUTS = 20

Default TX:   43
Default RX:   44

Default SDA:  8
Default SCL:  9

Default SS:   34
Default MOSI: 35
Default MISO: 37
Default SCK:  36

A0	A1	A2	A3	A4	A5	A6	A7	A8	A9
1	2	3	4	5	6	7	8	9	10

A10	A11	A12	A13	A14	A15	A16	A17	A18	A19
11	12	13	14	15	16	17	18	19	20

T1	T2	T3	T4	T5	T6	T7	T8	T9	T10
1	2	3	4	5	6	7	8	9	10

T11	T12	T13	T14
11	12	13	14

Default DAC1:  17
Default DAC2:  18
================================


ESP32-S2-Saola-1 Pin Layout


ESP32_pins.ino for board of ESP32 Dev Module, run on ESP32-DevKitC V4
void setup() {
  // put your setup code here, to run once:
  delay(500);
  Serial.begin(115200);
  delay(500);
  Serial.println("\n\n================================");
  Serial.printf("Chip Model: %s\n", ESP.getChipModel());
  Serial.println("================================");

#ifdef EXTERNAL_NUM_INTERRUPTS
  Serial.printf("EXTERNAL_NUM_INTERRUPTS = %d\n", EXTERNAL_NUM_INTERRUPTS);
#endif
#ifdef NUM_DIGITAL_PINS
  Serial.printf("NUM_DIGITAL_PINS = %d\n", NUM_DIGITAL_PINS);
#endif
#ifdef NUM_ANALOG_INPUTS
  Serial.printf("NUM_ANALOG_INPUTS = %d\n", NUM_ANALOG_INPUTS);
#endif
  Serial.println();
  Serial.printf("Default TX:   %d\n", TX);
  Serial.printf("Default RX:   %d\n", RX);
  Serial.println();
  Serial.printf("Default SDA:  %d\n", SDA);
  Serial.printf("Default SCL:  %d\n", SCL);
  Serial.println();
  Serial.printf("Default SS:   %d\n", SS);
  Serial.printf("Default MOSI: %d\n", MOSI);
  Serial.printf("Default MISO: %d\n", MISO);
  Serial.printf("Default SCK:  %d\n", SCK);

  Serial.println();
  Serial.printf("A0\t\t\tA3\tA4\tA5\tA6\tA7\n");
  Serial.printf("%d\t\t\t%d\t%d\t%d\t%d\t%d\n", 
                 A0, A3, A4, A5, A6, A7);
  Serial.println();
  Serial.printf("A10\tA11\tA12\tA13\tA14\tA15\tA16\tA17\tA18\tA19\n");
  Serial.printf("%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\n", 
                 A10, A11, A12, A13, A14, A15, A16, A17, A18, A19);
  Serial.println();

  Serial.printf("T0\tT1\tT2\tT3\tT4\tT5\tT6\tT7\tT8\tT9\n");
  Serial.printf("%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\n", 
                 T0, T1, T2, T3, T4, T5, T6, T7, T8, T9);
  Serial.println();

  Serial.printf("Default DAC1:  %d\n", DAC1);
  Serial.printf("Default DAC2:  %d\n", DAC2);
  Serial.println("================================");
}

void loop() {
  // put your main code here, to run repeatedly:

}

output:
================================
Chip Model: ESP32-D0WDQ5
================================
EXTERNAL_NUM_INTERRUPTS = 16
NUM_DIGITAL_PINS = 40
NUM_ANALOG_INPUTS = 16

Default TX:   1
Default RX:   3

Default SDA:  21
Default SCL:  22

Default SS:   5
Default MOSI: 23
Default MISO: 19
Default SCK:  18

A0			A3	A4	A5	A6	A7
36			39	32	33	34	35

A10	A11	A12	A13	A14	A15	A16	A17	A18	A19
4	0	2	15	13	12	14	27	25	26

T0	T1	T2	T3	T4	T5	T6	T7	T8	T9
4	0	2	15	13	12	14	27	33	32

Default DAC1:  25
Default DAC2:  26
================================


ESP32-DevKitC V4 Pin Layout
source: ESP32-DevKitC V4 Getting Started Guide :Pin Layout

Remark:
Please notice that GPIO8 on ESP32-C3-DevKitM-1 and GPIO18 on ESP32-S2-Saola-1 are connected to onboard RGB LED. Ref last post "Drive ESP32-C3-DevKitM-1/ESP32-S2-Saola-1 on-board RGB LED (WS2812) in Arduino Framework".

Thursday, October 21, 2021

Install arduino-esp32 2 on Arduino IDE, to program ESP32-C3/S2/S3


Currently, with development release arduino-esp32 2.0.0 installed, you can program ESP32-S2/C3 using Arduino IDE.
 

Install arduino-esp32 2.0.0:
- In Arduino IDE Menu, click File > Preferences

Add ESP32 boards:
- Open Boards Manager
- Search and install esp32 by Espressif system, currently version 2.0.0.

ESP32C3 and ESP32S2 Dev Module are now available in ESP32 Arduino board list.

ESP32C3_info.ino, get chip related info.
#include <Esp.h>

void setup() {
  delay(500);
  Serial.begin(115200);
  delay(500);
  Serial.println("\n\n================================");
  Serial.printf("Chip Model: %s\n", ESP.getChipModel());
  Serial.printf("Chip Revision: %d\n", ESP.getChipRevision());
  Serial.printf("with %d core\n", ESP.getChipCores());
  Serial.printf("Flash Chip Size : %d \n", ESP.getFlashChipSize());
  Serial.printf("Flash Chip Speed : %d \n", ESP.getFlashChipSpeed());

  esp_chip_info_t chip_info;
  esp_chip_info(&chip_info);
  Serial.printf("\nFeatures included:\n %s\n %s\n %s\n %s\n %s\n",
      (chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "embedded flash" : "",
      (chip_info.features & CHIP_FEATURE_WIFI_BGN) ? "2.4GHz WiFi" : "",
      (chip_info.features & CHIP_FEATURE_BLE) ? "Bluetooth LE" : "",
      (chip_info.features & CHIP_FEATURE_BT) ? "Bluetooth Classic" : "",
      (chip_info.features & CHIP_FEATURE_IEEE802154) ? "IEEE 802.15.4" : "");
  
  Serial.println();

  Serial.println();
  Serial.println("\n- end of setup() -");

}

void loop() {
  // put your main code here, to run repeatedly:

}



Updated@2022-02-19:

Currently, ESP32 Arduino 2.0.2 is stable. So you can enter Stable release link (https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json) into Additional Board Manager URLs field, instead of Development release link (https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_dev_index.json).







ref:
~ ESP32 Arduino Core’s documentation


Updated@2022-05-12

With arduino-esp32 updated 2.0.3, ESP32-S3 support added.



ESP32 Arduino 2.0.3 release notice


Sunday, October 17, 2021

Identify ESP chip and flash using esptool

Here to identify ESP chip and flash using esptool.py

First, you have to identify the USB port connect to ESP. In Linux/Raspberry Pi

- Before connect your ESP device to USB, run following command to clear dmesg buffer:

$ sudo dmesg -c

- Connect your ESP32 device to USB, and then run dmesg:

$ dmesg

-  You will find some like "cp210x converter now attached to ttyUSB0". Where /dev/ttyUSB0 is the USB port connected to ESP device.

TO Read Chip ID, enter the command:

$ esptool.py --chip auto --port /dev/ttyUSB0 chip_id
TO read SPI flash manufacturer and device ID, enter the command:
$ esptool.py --chip auto --port /dev/ttyUSB0 flash_id
Here is the output for ESP32-DevKitC V4 with ESP32-D0WD-V3 (revision 3) chip and 8MB flash.


ESP8266 with ESP8266EX chip and 4MB flash.


ESP32-S2-Saola-1 with ESP32-S2 chip and 4MB flash.


ESP32-C3-DevKitM-1 with unknown ESP32-C3 (revision 3) and 4MB flash.






Monday, September 27, 2021

nanoESP32-S2 + ov7670 cam module/ST7789 SPI TFT (CircuitPython 7.0.0)


The previous post descripted how to install CircuitPython 7.0.0 and Library Bundle on nanoESP32-S2, and and SPI ST7789 LCD. This exercise capture image from ov7670 camera module and display it on ST7789 SPI LCD.


Libraries

adafruit_ov7670 and adafruit_st7789. How to download and install Adafruit Library, refer to the previous post.


Connection between nanoESP32-S2 and ov7670 cam module/ST7789 SPI TFT


	ov7670 header
	+-----------+
3V3	|3V3	DGND|	GND
IO7	|SCL*	SDA*|	IO8
IO9	|VS	HS  |	IO10
IO11	|PLK	XLK |	IO12
IO40	|D7	D6  |	IO39
IO38	|D5	D4  |	IO37
IO36	|D3	D2  |	IO35
IO34	|D1	D0  |	IO33
IO13	|RET	PWDN|
	+-----------+
		
*cam.SCL/SDA are I2C control pin, pull-up resistors are needed.
 I use 2K ohm resistor for it.


ST7789	    +-------------------------------+
-----       |				    |
 GND | -----+	+-------------------+	    |
 VCC | -------- | 3V3	        GND | ------+
 SCL | -------- | 0		RST |
 SDA | -------- | 1		46  |
 RES | -------- | 2		45  |
 DC  | -------- | 3		44  |
 CS  | -------- | 4		43  |
 BLK | -------- | 5		42  |
----- 		| 6		41  |
	cam.scl	| 7		40  | cam.D7
	cam.sda	| 8		39  | cam.D6
	cam.VS	| 9		38  | cam.D5
	cam.HS	| 10		37  | cam.D4
	cam.PLK	| 11		36  | cam.D3
	cam.XLK	| 12		35  | cam.D2
	cam.RET	| 13		34  | cam.D1
		| 14		33  | cam.D0
		| 15		26  |
		| 16		21  | 
		| 17		20  | 
		| 5V0		19  | 
		| GND		18  | 
		+-------------------+
		nanoESP32-S2

Exercise code

ov7670_displayio_nanoESP32S2_st7789_2in.py
"""
CircuitPython (7.0.0) exercise run on nanoESP32-S2,
capture image from ov7670 camera module and
display it on ST7789 SPI LCD.

Modified from ov7670_displayio_pico_st7789_2in.py example
in CircuitPython Bundle for Version 7.x
"""

import time
from displayio import (
    Bitmap,
    Group,
    TileGrid,
    FourWire,
    release_displays,
    ColorConverter,
    Colorspace,
)
import adafruit_st7789
import board
import busio
import digitalio
import adafruit_ov7670

import gc

print(adafruit_ov7670.__name__, ":", adafruit_ov7670.__version__)
print(adafruit_st7789.__name__, ":", adafruit_st7789.__version__)
print()
time.sleep(1)
gc.collect()
print("free mem@power up", gc.mem_free())  # print free memory

# Set up the display (You must customize this block for your display!)
release_displays()

#assign pins for nanoESP32-S2
tft_blk = board.IO5
tft_cs = board.IO4
tft_dc = board.IO3
tft_res = board.IO2
spi_mosi = board.IO1
spi_clk = board.IO0

pin_blk = digitalio.DigitalInOut(tft_blk)
pin_blk.direction = digitalio.Direction.OUTPUT
pin_blk.value = True

spi = busio.SPI(spi_clk, MOSI=spi_mosi)

display_bus = FourWire(
    spi, command=tft_dc, chip_select=tft_cs, reset=tft_res
)

#for 240x320
display = adafruit_st7789.ST7789(display_bus,
                    width=320, height=240, rotation=90)

cam_scl = board.IO7
cam_sda = board.IO8
cam_reset = board.IO13

# Ensure the camera is shut down, so that it releases the SDA/SCL lines,
# then create the configuration I2C bus

with digitalio.DigitalInOut(cam_reset ) as reset:
    reset.switch_to_output(False)
    time.sleep(0.001)
    bus = busio.I2C(scl=cam_scl, sda=cam_sda)

# Set up the camera (you must customize this for your board!)
cam = adafruit_ov7670.OV7670(
    bus,
    data_pins=[
        board.IO33,
        board.IO34,
        board.IO35,
        board.IO36,
        board.IO37,
        board.IO38,
        board.IO39,
        board.IO40,
    ], 
    clock=board.IO11,   #PLK
    vsync=board.IO9,    #VS
    href=board.IO10,    #HS
    mclk=board.IO12,    #XLK
    shutdown=None,
    reset=cam_reset ,
)  # [14]

width = display.width
height = display.height

# cam.test_pattern = OV7670_TEST_PATTERN_COLOR_BAR

bitmap = None
# Select the biggest size for which we can allocate a bitmap successfully, and
# which is not bigger than the display
#
# *** Remark by Erik: due to limited memory for bitmap,
# *** OV7670_SIZE_DIV8 (80x60) is selected.
#
gc.collect()
print("free mem@before bitmap", gc.mem_free())  # print free memory

for size in range(adafruit_ov7670.OV7670_SIZE_DIV1,
                  adafruit_ov7670.OV7670_SIZE_DIV16 + 1):
    cam.size = size
    if cam.width > width:
        continue
    if cam.height > height:
        continue
    try:
        bitmap = Bitmap(cam.width, cam.height, 65536)
        break
    except MemoryError:
        print("MemoryError in allocate bitmap", cam.width, " x ", cam.height)
        continue

"""
# Erik: to use fixed cam.size
cam.size = adafruit_ov7670.OV7670_SIZE_DIV8
bitmap = Bitmap(cam.width, cam.height, 65536)
"""

print("free mem@after bitmap", gc.mem_free())  # print free memory

print(width, height, cam.width, cam.height)
print()

if bitmap is None:
    raise SystemExit("Could not allocate a bitmap")

# Erik: change gScale to enlarge image on screen
gScale = 1
g = Group(scale=gScale,
          x=(width - (gScale*cam.width)) // 2,
          y=(height - (gScale*cam.height)) // 2)

tg = TileGrid(
    bitmap, pixel_shader=ColorConverter(input_colorspace=Colorspace.RGB565_SWAPPED)
)
g.append(tg)
display.show(g)

t0 = time.monotonic_ns()
display.auto_refresh = False
while True:
    cam.capture(bitmap)
    bitmap.dirty()
    display.refresh(minimum_frames_per_second=0)
    t1 = time.monotonic_ns()
    print("fps", 1e9 / (t1 - t0))
    t0 = t1

In my test, due to limited memory, I can create bitmap of 80x60 only!



Friday, September 24, 2021

nanoESP32-S2/CircuitPython 7 + SPI ST7789 LCD (first try CircuitPython 7)

This video show how to flash nanoESP32-S2 with latest stable CircuitPython 7.0.0 firmware, install libraries, and run exercise to display on 2.0" IPS 240x320 RGB LCD with SPI ST7789 driver. It's my first time to run stable CircuitPython 7.


Download and install CircuitPython firmware on nanoESP32-S2

Visit https://circuitpython.org/downloads to download CircuitPython firmware:

Search "ESP32 S2" and select "NanoESP32 S2 w/WROVER".
Download .BIN for CircuitPython 7.0.0, it's the latest stable release of CircuitPython currently.

Now going to identify the USB will be conneted to ESP32-S2:

- Before ESP32-S2 connected, clear dmesg buffer.
$ sudo dmesg -c

- Connect USB to onboard USB port marked "ch340"
- identify connected USB port.
$ dmesg

ttyUSB0 connected in my case.
  
To flash nanoESP32-S2 with CircuitPython firmware:
$ esptool.py --chip auto --port <COM PORT> -b 460800 --before=default_reset \
--after=hard_reset write_flash --flash_mode dio --flash_freq 40m --flash_size 4MB 0x0000 \
<DOWNLOADED FILE>
Prepare Libraries

Visit https://circuitpython.org/libraries, download Bundle for Version 7.x.

Unzip the downloaded file, copy adafruit_st7789.mpy, adafruit_display_text and adafruit_display_shapes folder to the lib folder on your CIRCUITPY drive.

Connection between SPI ST7789 and nanoESP32-S2

         +-----------------------------------+
-----    |                                   |
 GND | --+        -----------------------    |
 VCC | --------- | 3V3		     GND | --+
 SCL | --------- | 0			 |
 SDA | --------- | 1			 |
 RES | --------- | 2	nanoESP32-S2	 |
 DC  | --------- | 3			 |
 CS  | --------- | 4			 |
 BLK | --------- | 5			 |
----
SPI ST7789 LCD

Exercise:

cpyNanoESP32S2_spiST7789.py
"""
Example of CircuitPython 7/nanoESP32-S2
to display on ST7789 SPI IPS Screen

Connection between nanoESP32-S2 and
the IPS screen, with ST7789 SPI interface.
GP5  - BLK
GP4  - CS
GP3  - DC
GP2  - RES
GP1  - SDA
GP0  - SCL
3V3  - VCC
GND  - GND
"""

import os
import board
import time
import terminalio
import displayio
import busio
from adafruit_display_text import label
#from adafruit_st7789 import ST7789
import adafruit_st7789

import digitalio

print("==============================")
print(os.uname())
print("Hello nanoESP32-S2/CircuitPython ST7789 SPI IPS Display")
print(adafruit_st7789.__name__ + " version: " + adafruit_st7789.__version__)
print()

# Release any resources currently in use for the displays
displayio.release_displays()

#assign pins for nanoESP32-S2
tft_blk = board.IO5
tft_cs = board.IO4
tft_dc = board.IO3
tft_res = board.IO2
spi_mosi = board.IO1
spi_clk = board.IO0

pin_blk = digitalio.DigitalInOut(tft_blk)
pin_blk.direction = digitalio.Direction.OUTPUT
pin_blk.value = True

spi = busio.SPI(spi_clk, MOSI=spi_mosi)

display_bus = displayio.FourWire(
    spi, command=tft_dc, chip_select=tft_cs, reset=tft_res
)

#for 240x320
display = adafruit_st7789.ST7789(display_bus,
                    width=240, height=320)

#for 240x240
#display = adafruit_st7789.ST7789(display_bus,
#                    width=240, height=240, rowstart=80)

# Make the display context

#Erik: CircuitPython 6 changed to 7
splash = displayio.Group()   #splash = displayio.Group(max_size=10)

display.show(splash)

color_bitmap = displayio.Bitmap(135, 240, 1)
color_palette = displayio.Palette(1)
color_palette[0] = 0x00FF00

bg_sprite = displayio.TileGrid(color_bitmap,
                               pixel_shader=color_palette, x=0, y=0)
splash.append(bg_sprite)

# Draw a smaller inner rectangle
inner_bitmap = displayio.Bitmap(133, 238, 1)
inner_palette = displayio.Palette(1)
inner_palette[0] = 0x0000FF
inner_sprite = displayio.TileGrid(inner_bitmap,
                                  pixel_shader=inner_palette, x=1, y=1)
splash.append(inner_sprite)

# Draw a label

#Erik: CircuitPython 6 changed to 7
#text_group1 = displayio.Group(max_size=10, scale=2, x=20, y=40)
text_group1 = displayio.Group(scale=2, x=20, y=40)

text1 = "ESP32-S2"
text_area1 = label.Label(terminalio.FONT, text=text1, color=0xFF0000)
text_group1.append(text_area1)  # Subgroup for text scaling
# Draw a label

#Erik: CircuitPython 6 changed to 7
#text_group2 = displayio.Group(max_size=10, scale=1, x=20, y=60)
text_group2 = displayio.Group(scale=1, x=20, y=60)

text2 = "CircuitPython"
text_area2 = label.Label(terminalio.FONT, text=text2, color=0xFFFFFF)
text_group2.append(text_area2)  # Subgroup for text scaling

text_group2b = displayio.Group(scale=1, x=20, y=76)
text2b = os.uname()[2]
text_area2b = label.Label(terminalio.FONT, text=text2b, color=0xFFFFFF)
text_group2b.append(text_area2b)  # Subgroup for text scaling

# Draw a label
#Erik: CircuitPython 6 changed to 7
#text_group3 = displayio.Group(max_size=10, scale=1, x=20, y=100)
text_group3 = displayio.Group(scale=1, x=20, y=100)

text3 = adafruit_st7789.__name__
text_area3 = label.Label(terminalio.FONT, text=text3, color=0x0000000)
text_group3.append(text_area3)  # Subgroup for text scaling
# Draw a label
#Erik: CircuitPython 6 changed to 7
#text_group4 = displayio.Group(max_size=10, scale=2, x=20, y=120)
text_group4 = displayio.Group(scale=2, x=20, y=120)

text4 = adafruit_st7789.__version__
text_area4 = label.Label(terminalio.FONT, text=text4, color=0x000000)
text_group4.append(text_area4)  # Subgroup for text scaling

splash.append(text_group1)
splash.append(text_group2)
splash.append(text_group2b)
splash.append(text_group3)
splash.append(text_group4)

time.sleep(3.0)

rot = 0
while True:
    time.sleep(5.0)
    rot = rot + 90
    if (rot>=360):
        rot =0
    display.rotation = rot

cpyNanoESP32S2__spiST7789_shape.py
"""
Example of CircuitPython 7/nanoESP32-S2
to display on ST7789 SPI IPS Screen

Connection between nanoESP32-S2 and
the IPS screen, with ST7789 SPI interface.
GP5  - BLK
GP4  - CS
GP3  - DC
GP2  - RES
GP1  - SDA
GP0  - SCL
3V3  - VCC
GND  - GND
"""

import os
import board
import time
import terminalio
import displayio
import busio
import adafruit_st7789
from adafruit_display_shapes.rect import Rect
from adafruit_display_shapes.circle import Circle
from adafruit_display_shapes.roundrect import RoundRect
from adafruit_display_shapes.triangle import Triangle
from adafruit_display_shapes.sparkline import Sparkline

import digitalio

print("==============================")
print(os.uname())
print("Hello nanoESP32-S2/CircuitPython ST7789 SPI IPS Display")
print(adafruit_st7789.__name__ + " version: " + adafruit_st7789.__version__)
print()

# Release any resources currently in use for the displays
displayio.release_displays()

#assign pins for nanoESP32-S2
tft_blk = board.IO5
tft_cs = board.IO4
tft_dc = board.IO3
tft_res = board.IO2
spi_mosi = board.IO1
spi_clk = board.IO0

pin_blk = digitalio.DigitalInOut(tft_blk)
pin_blk.direction = digitalio.Direction.OUTPUT
pin_blk.value = True

spi = busio.SPI(spi_clk, MOSI=spi_mosi)

display_bus = displayio.FourWire(
    spi, command=tft_dc, chip_select=tft_cs, reset=tft_res
)

#for 240x320
display = adafruit_st7789.ST7789(display_bus,
                    width=240, height=320)

#for 240x240
#display = adafruit_st7789.ST7789(display_bus,
#                    width=240, height=240, rowstart=80)

display.rotation = 270

print(display.width, " x ", display.height)

splash = displayio.Group()
display.show(splash)

color_bitmap = displayio.Bitmap(display.width, display.height, 1)
color_palette = displayio.Palette(1)
color_palette[0] = 0xFFFFFF
bg_sprite = displayio.TileGrid(color_bitmap, pixel_shader=color_palette, x=0, y=0)
splash.append(bg_sprite)

"""
ref:
Adafruit Display_Shapes Library
https://circuitpython.readthedocs.io/projects/display-shapes/en/latest/index.html
"""

triangle = Triangle(0, 0, 0, 60, 80, 0, fill=0xFF0000, outline=0xFF00FF)
splash.append(triangle)
time.sleep(1)

for i in range(180):
    time.sleep(0.05)
    triangle.x=i
    triangle.y=i
    triangle.fill=int((i*0x000100) + i)
    triangle.outline=(int)((i/10)*0x010000)

centerX = (int)(display.width/2)
centerY = (int)(display.height/2)
circle = Circle(centerX, centerY, 100, fill=0x000000, outline=0xFF0000)
splash.append(circle)
time.sleep(1)

for i in range(0xFF):
    time.sleep(0.01)
    circle.fill=(int)(i*0x010101)

triangle.fill=0x0000FF
triangle.outline=0x000000
for i in range(180):
    time.sleep(0.05)
    triangle.x=180-i

#re-order triangle to front
splash.remove(triangle)
splash.append(triangle)
triangle.fill=0x00FF00
triangle.outline=0x000000

for i in range(180):
    time.sleep(0.05)
    triangle.x=i
    triangle.y=180-i

print("--- finished ---")
while True:
    pass


Remark for change from CircuitPython 6 to 7


Please note that defination of displayio.Group() change from:

CircuitPython 6.3.x:
classdisplayio.Group(*, max_size: int = 4, scale: int = 1, x: int = 0, y: int = 0)
CircuitPython 7.0.x:
classdisplayio.Group(*, scale: int = 1, x: int = 0, y: int = 0)

So I have to modify accordingly.


Next:

Wednesday, December 16, 2020

ESP32-S2/CircuitPython: display on IPS screen (ST7789/SPI) using adafruit_st7789/displayio lib


This post show how to program in CircuitPython run on ESP32-S2(nanoESP32-S2 dev. board) to display on 1.14" 135x240 IPS Screen with ST7789V driver/SPI interface, using adafruit_st7789/displayio library.

The display is 1.14" 135x240 (RGB) IPS (SKU: MSP1141), details refer to : LCDwiki - 1.14inch IPS Module

Connection:


Library:

In this exercise, adafruit_st7789 and adafruit_display_text of Adafruit CircuitPython Library Bundle is needed.

Visit https://circuitpython.org/libraries, download the appropriate bundle for your version of CircuitPython.

Unzip the file, copy adafruit_st7789.mpy and adafruit_display_text folder to the lib folder on your CIRCUITPY drive.

Example code:

Copy below examples code to code.py on CIRCUITPY drive to run.

spiST7789

"""
Example of CircuitPython/ESP32-S2 (run on nanoESP32-S2)
to display on 1.14" 135x240 (RGB) IPS screen
with ST7789 driver via SPI interface.

Connection between nanoESP32 and
the IPS screen, with ST7789 SPI interface.
3V3  - BLK (backlight, always on)
IO37 - CS
IO38 - DC
IO39 - RES
IO40 - SDA
IO41 - SCL
3V3  - VCC
GND  - GND
"""

import os
import board
import time
import terminalio
import displayio
import busio
from adafruit_display_text import label
#from adafruit_st7789 import ST7789
import adafruit_st7789

print("==============================")
print(os.uname())
print("Hello nanoESP32-S2/CircuitPython ST7789 SPI IPS Display")
print(adafruit_st7789.__name__ + " version: " + adafruit_st7789.__version__)
print()

# Release any resources currently in use for the displays
displayio.release_displays()

tft_cs = board.IO37
tft_dc = board.IO38
tft_res = board.IO39
spi_mosi = board.IO40
spi_clk = board.IO41

"""
classbusio.SPI(clock: microcontroller.Pin,
                MOSI: Optional[microcontroller.Pin] = None,
                MISO: Optional[microcontroller.Pin] = None)
"""
spi = busio.SPI(spi_clk, MOSI=spi_mosi)

display_bus = displayio.FourWire(
    spi, command=tft_dc, chip_select=tft_cs, reset=tft_res
)

#I get the parameters by guessing and trying
#display = ST7789(display_bus, width=135, height=240, rowstart=40, colstart=53)
display = adafruit_st7789.ST7789(display_bus,
                    width=135, height=240,
                    rowstart=40, colstart=53)

# Make the display context
splash = displayio.Group(max_size=10)
display.show(splash)

color_bitmap = displayio.Bitmap(135, 240, 1)
color_palette = displayio.Palette(1)
color_palette[0] = 0x00FF00

bg_sprite = displayio.TileGrid(color_bitmap, pixel_shader=color_palette, x=0, y=0)
splash.append(bg_sprite)

# Draw a smaller inner rectangle
inner_bitmap = displayio.Bitmap(133, 238, 1)
inner_palette = displayio.Palette(1)
inner_palette[0] = 0x0000FF
inner_sprite = displayio.TileGrid(inner_bitmap, pixel_shader=inner_palette, x=1, y=1)
splash.append(inner_sprite)

# Draw a label
text_group1 = displayio.Group(max_size=10, scale=2, x=20, y=40)
text1 = "ESP32-S2"
text_area1 = label.Label(terminalio.FONT, text=text1, color=0xFF0000)
text_group1.append(text_area1)  # Subgroup for text scaling
# Draw a label
text_group2 = displayio.Group(max_size=10, scale=1, x=20, y=60)
text2 = "CircuitPython"
text_area2 = label.Label(terminalio.FONT, text=text2, color=0xFFFFFF)
text_group2.append(text_area2)  # Subgroup for text scaling

# Draw a label
text_group3 = displayio.Group(max_size=10, scale=1, x=20, y=100)
text3 = adafruit_st7789.__name__
text_area3 = label.Label(terminalio.FONT, text=text3, color=0x0000000)
text_group3.append(text_area3)  # Subgroup for text scaling
# Draw a label
text_group4 = displayio.Group(max_size=10, scale=2, x=20, y=120)
text4 = adafruit_st7789.__version__
text_area4 = label.Label(terminalio.FONT, text=text4, color=0x000000)
text_group4.append(text_area4)  # Subgroup for text scaling

splash.append(text_group1)
splash.append(text_group2)
splash.append(text_group3)
splash.append(text_group4)

time.sleep(3.0)

rot = 0
while True:
    time.sleep(5.0)
    rot = rot + 90
    if (rot>=360):
        rot =0
    display.rotation = rot
    

spiST7789_bitmap
"""
Example of CircuitPython/ESP32-S2 (run on nanoESP32-S2)
to display on 1.14" 135x240 (RGB) IPS screen
with ST7789 driver via SPI interface.

Connection between nanoESP32 and
the IPS screen, with ST7789 SPI interface.
3V3  - BLK (backlight, always on)
IO37 - CS
IO38 - DC
IO39 - RES
IO40 - SDA
IO41 - SCL
3V3  - VCC
GND  - GND
"""

import os
import board
import time
import terminalio
import displayio
import busio
from adafruit_display_text import label
import adafruit_st7789

print("==============================")
print(os.uname())
print("Hello nanoESP32-S2/CircuitPython ST7789 SPI IPS Display")
print(adafruit_st7789.__name__ + " version: " + adafruit_st7789.__version__)
print()

# Release any resources currently in use for the displays
displayio.release_displays()

tft_cs = board.IO37
tft_dc = board.IO38
tft_res = board.IO39
spi_mosi = board.IO40
spi_clk = board.IO41

"""
classbusio.SPI(clock: microcontroller.Pin,
                MOSI: Optional[microcontroller.Pin] = None,
                MISO: Optional[microcontroller.Pin] = None)
"""
spi = busio.SPI(spi_clk, MOSI=spi_mosi)

display_bus = displayio.FourWire(
    spi, command=tft_dc, chip_select=tft_cs, reset=tft_res
)

display = adafruit_st7789.ST7789(display_bus,
                    width=135, height=240,
                    rowstart=40, colstart=53)
display.rotation = 270

group = displayio.Group(max_size=10)
display.show(group)

bitmap = displayio.Bitmap(240, 135, 135)

palette = displayio.Palette(135)
for p in range(135):
    palette[p] = (0x010000*p) + (0x0100*p) + p

for y in range(135):
    for x in range(240):
        bitmap[x,y] = y
        
tileGrid = displayio.TileGrid(bitmap, pixel_shader=palette, x=0, y=0)
group.append(tileGrid)

time.sleep(3.0)

while True:
    for p in range(135):
        palette[p] = p
    time.sleep(3.0)

    for p in range(135):
        palette[p] = 0x0100 * p
    time.sleep(3.0)

    for p in range(135):
        palette[p] = 0x010000 * p
    time.sleep(3.0)

spiST7789_terminal
"""
Example of CircuitPython/ESP32-S2 (run on nanoESP32-S2)
to display on 1.14" 135x240 (RGB) IPS screen
with ST7789 driver via SPI interface.

Connection between nanoESP32 and
the IPS screen, with ST7789 SPI interface.
3V3  - BLK (backlight, always on)
IO37 - CS
IO38 - DC
IO39 - RES
IO40 - SDA
IO41 - SCL
3V3  - VCC
GND  - GND
"""

import os
import board
import time
import terminalio
import displayio
import busio
from adafruit_display_text import label
#from adafruit_st7789 import ST7789
import adafruit_st7789

print("==============================")
print(os.uname())
print("Hello nanoESP32-S2/CircuitPython ST7789 SPI IPS Display")
print(adafruit_st7789.__name__ + " version: " + adafruit_st7789.__version__)
print()

# Release any resources currently in use for the displays
displayio.release_displays()

tft_cs = board.IO37
tft_dc = board.IO38
tft_res = board.IO39
spi_mosi = board.IO40
spi_clk = board.IO41

"""
classbusio.SPI(clock: microcontroller.Pin,
                MOSI: Optional[microcontroller.Pin] = None,
                MISO: Optional[microcontroller.Pin] = None)
"""
spi = busio.SPI(spi_clk, MOSI=spi_mosi)

display_bus = displayio.FourWire(
    spi, command=tft_dc, chip_select=tft_cs, reset=tft_res
)

#I get the parameters by guessing and trying
#display = ST7789(display_bus, width=135, height=240, rowstart=40, colstart=53)
display = adafruit_st7789.ST7789(display_bus,
                    width=135, height=240,
                    rowstart=40, colstart=53)
display.rotation = 270

"""
Now click on to activate Serial Console,
Press any key to enter the REPL.
You would have a terminal that you could type at and have the screen update.
"""


~ More example of ESP32-S2/CircuitPython

Saturday, December 12, 2020

nanoESP32-S2/CircuitPython: I2C and 128x64 SSD1306 OLED

Trying I2C on nanoESP32-S2/CircuitPython, and display on 128x64 OLED with I2C SSD1306 driver (3.3V), using adafruit_ssd1306.mpy and adafruit_framebuf.mpy of Adafruit CircuitPython Library Bundle.

Connection between nanoESP32-S2 and 128x64 I2C SSD1306 OLED:

ESP32-S2 - OLED
3V3 VCC
GND GND
IO40           SDA
IO41           SCL 

Exercise to 128x64 OLED with I2C SSD1306 driver:

import time
import os
import board
import busio
import adafruit_ssd1306
# lib needed:
# adafruit_ssd1306.mpy
# adafruit_framebuf.mpy

# Helper function to draw a circle from a given position with a given radius
# This is an implementation of the midpoint circle algorithm,
# see https://en.wikipedia.org/wiki/Midpoint_circle_algorithm#C_example for details
def draw_circle(xpos0, ypos0, rad, col=1):
    x = rad - 1
    y = 0
    dx = 1
    dy = 1
    err = dx - (rad << 1)
    while x >= y:
        display.pixel(xpos0 + x, ypos0 + y, col)
        display.pixel(xpos0 + y, ypos0 + x, col)
        display.pixel(xpos0 - y, ypos0 + x, col)
        display.pixel(xpos0 - x, ypos0 + y, col)
        display.pixel(xpos0 - x, ypos0 - y, col)
        display.pixel(xpos0 - y, ypos0 - x, col)
        display.pixel(xpos0 + y, ypos0 - x, col)
        display.pixel(xpos0 + x, ypos0 - y, col)
        if err <= 0:
            y += 1
            err += dy
            dy += 2
        if err > 0:
            x -= 1
            dx += 2
            err += dx - (rad << 1)
    display.show()

print("==============================")
print(os.uname())
print("Hello nanoESP32-S2/CircuitPython ssd1306 OLED example")
print(adafruit_ssd1306.__name__ + "version: " + adafruit_ssd1306.__version__)
print()

WIDTH = 128
HEIGHT = 64
CENTER_X = int(WIDTH/2)
CENTER_Y = int(HEIGHT/2)

SDA = board.IO40
SCL = board.IO41
i2c = busio.I2C(SCL, SDA)

if(i2c.try_lock()):
    print("i2c.scan(): " + str(i2c.scan()))
    i2c.unlock()

display = adafruit_ssd1306.SSD1306_I2C(WIDTH, HEIGHT, i2c)

display.fill(0)
display.show()
time.sleep(1.0)
display.fill(1)
display.show()
time.sleep(1.0)
display.fill(0)
display.show()
time.sleep(1.0)

for y in range(HEIGHT):
    for x in range(WIDTH):
        display.pixel(x, y, 1)
    display.show()
    
draw_circle(CENTER_X, CENTER_Y, 25, 0)

print("- bye -\n")

~ more exercises on nanoESP32-S2/CircuitPython.



Remark about ESP32-S2 pull-up resistor for I2C:

As mentioned in Espressif document ESP-IDF Programming Guide :  API Reference > Peripherals API > I2C DriverESP32-S2’s internal pull-ups are in the range of tens of kOhm, which is, in most cases, insufficient for use as I2C pull-ups. Users are advised to use external pull-ups with values described in the I2C specification.

As I understand, most I2C SSD1306 OLED module have pull-up resistors. It's no external resistor needed in this exercise.

Next:






Monday, December 7, 2020

nanoESP32-S2/CircuitPython exercise: to control external NeoPixel

Previous exercise show how to install Adafruit CircuitPython Library Bundle to nanoESP32-S2 dev. board, and drive the onboard NeoPixel. This post show how to drive external NeoPixel (Ring and Square).

IO45 is used to drive the 8X NeoPixel Ring. connect to its DI.
IO42 is used to drive the 4X4 NeoPixel Square, connect to its DI.
IO18 is used to drive the onboard NeoPixel.
In the exercise of ADCNeoPixel, IO1 is used as analog input, convert to digital and display on 8X NeoPixel Ring.

All the NeoPixels have color order of  GRB, so have to set pixel_order=neopixel.GRB.

Just copy the code to code.py on your nanoESP32-S2 board, save to run.

ADCNeoPixel.py
import time
import os
import microcontroller
import board
import analogio
import neopixel

adc01=analogio.AnalogIn(board.IO1)

NumOfPixel_ring = 8

def offAllPixel():
    pixel_ring.fill((0, 0, 0))
    onboard_pixel[0] = (0, 0, 0)
    pixel_ring.show()
    onboard_pixel.show()

print("==============================")
print(os.uname())
print("Hello nanoESP32-S2/CircuitPython NeoPixel/ADC example")
print("cpu.temperature: " + str(microcontroller.cpu.temperature))
print("neopixel version: " + neopixel.__version__)
print()

ref = adc01.reference_voltage
print("reference voltage: " + str(ref))

# Create the NeoPixel objects
# onboard NeoPixel = IO18
onboard_pixel = neopixel.NeoPixel(board.NEOPIXEL, 1, 
                    auto_write=False,
                    brightness=0.02,
                    pixel_order=neopixel.GRB)
                    
pixel_ring = neopixel.NeoPixel(board.IO45, NumOfPixel_ring, 
                    auto_write=False,
                    brightness=0.3,
                    pixel_order=neopixel.GRB)

offAllPixel()
#blink neopixels to start
time.sleep(0.5)
onboard_pixel[0] = (255, 0, 0)
onboard_pixel.show()
time.sleep(0.5)
onboard_pixel[0] = (0, 255, 0)
onboard_pixel.show()
time.sleep(0.5)
onboard_pixel[0] = (20, 0, 255)
onboard_pixel.show()
time.sleep(0.5)
onboard_pixel[0] = (0, 0, 0)
onboard_pixel.show()

pixel_ring.fill((0, 0, 0))
pixel_ring.show()
time.sleep(1.0)

while True:
    value01=adc01.value
    step = int(value01/8192)
    offAllPixel()
    for i in range(step):
        pixel_ring[i] = (255, 255, 255)
    pixel_ring.show()
    
    onboard_pixel.brightness = step/10
    onboard_pixel[0] = (0, 0, 255)
    onboard_pixel.show()

    time.sleep(0.1)

print("- bye -\n")


testNeopixel.py
import time
import os
import microcontroller
import neopixel
import board
import random

NumOfPixel_ring = 8
NumOfPixel_sq = 16

def offAllPixel():
    fillAllPixel(0, 0, 0)
    
def fillAllPixel(r, g, b):
    pixel_ring.fill((r, g, b))
    pixel_sq.fill((r, g, b))
    onboard_pixel[0] = (r, g, b)


print("==============================")
print(os.uname())
print("Hello nanoESP32-S2/CircuitPython NeoPixel example")
print("Test on:")
print("Onboard NEOPIXEL")
print("8X NeoPixel Ring")
print("4X4 NeoPixel Square")
print("cpu.temperature: " + str(microcontroller.cpu.temperature))
print()
print("neopixel version: " + neopixel.__version__)
print()

# Create the NeoPixel objects
# onboard NeoPixel = IO18
onboard_pixel = neopixel.NeoPixel(board.NEOPIXEL, 1, 
                    brightness=0.1,
                    pixel_order=neopixel.GRB)
                    
pixel_ring = neopixel.NeoPixel(board.IO45, NumOfPixel_ring, 
                    brightness=0.1,
                    pixel_order=neopixel.GRB)
                    
pixel_sq = neopixel.NeoPixel(board.IO42, NumOfPixel_sq, 
                    brightness=0.1, pixel_order=neopixel.GRB)

offAllPixel()

#blink neopixels to start
time.sleep(0.5)
onboard_pixel[0] = (255, 0, 0)
time.sleep(0.5)
onboard_pixel[0] = (0, 255, 0)
time.sleep(0.5)
onboard_pixel[0] = (20, 0, 255)
time.sleep(0.5)
onboard_pixel[0] = (0, 0, 0)

for i in range(NumOfPixel_ring):
    pixel_ring.fill((0, 0, 0))
    pixel_ring[i] = (255, 255, 255)
    time.sleep(0.5)
pixel_ring.fill((0, 0, 0))

for i in range(NumOfPixel_sq):
    pixel_sq.fill((0, 0, 0))
    pixel_sq[i] = (255, 255, 255)
    time.sleep(0.5)
pixel_sq.fill((0, 0, 0))
time.sleep(0.5)

fillAllPixel(255, 0, 0)
time.sleep(1.0)
fillAllPixel(0, 255, 0)
time.sleep(1.0)
fillAllPixel(0, 0, 255)
time.sleep(1.0)

offAllPixel()
time.sleep(2.0)

print("- bye -\n")

randomNeopixel.py
import time
import os
import microcontroller
import neopixel
import board
import random

NumOfPixel_ring = 8
NumOfPixel_sq = 16

def offAllPixel():
    fillAllPixel(0, 0, 0)
    
def fillAllPixel(r, g, b):
    pixel_ring.fill((r, g, b))
    pixel_sq.fill((r, g, b))
    onboard_pixel[0] = (r, g, b)
    
def randomNeopixel():

    for r in range(2000):
        r = random.randint(0, 255)
        g = random.randint(0, 255)
        b = random.randint(0, 255)
        
        onboard_pixel[0] = (r, g, b)
        i = random.randint(0, NumOfPixel_ring-1)
        pixel_ring[i] = (r, g, b)
        i = random.randint(0, NumOfPixel_sq-1)
        pixel_sq[i] = (r, g, b)
        
        time.sleep(0.2)


print("==============================")
print(os.uname())
print("Hello nanoESP32-S2/CircuitPython NeoPixel example")
print("Generate random color on:")
print("Onboard NEOPIXEL")
print("8X NeoPixel Ring")
print("4X4 NeoPixel Square")
print("cpu.temperature: " + str(microcontroller.cpu.temperature))
print()
print("neopixel version: " + neopixel.__version__)
print()

# Create the NeoPixel objects
# onboard NeoPixel = IO18
onboard_pixel = neopixel.NeoPixel(board.NEOPIXEL, 1, 
                    brightness=0.05,
                    pixel_order=neopixel.GRB)
                    
pixel_ring = neopixel.NeoPixel(board.IO45, NumOfPixel_ring, 
                    brightness=0.05,
                    pixel_order=neopixel.GRB)
                    
pixel_sq = neopixel.NeoPixel(board.IO42, NumOfPixel_sq, 
                    brightness=0.05, pixel_order=neopixel.GRB)

offAllPixel()

#blink neopixels to start
time.sleep(0.5)
onboard_pixel[0] = (255, 0, 0)
time.sleep(0.5)
onboard_pixel[0] = (0, 255, 0)
time.sleep(0.5)
onboard_pixel[0] = (20, 0, 255)
time.sleep(0.5)
onboard_pixel[0] = (0, 0, 0)

randomNeopixel()

offAllPixel()
time.sleep(2.0)

print("- bye -\n")


Related:

Sunday, December 6, 2020

nanoESP32-S2/CircuitPython exercise: ADC (Analog to Digital Converter)

This exercise run on nanoESP32-S2/CircuitPython, read analog input from IO1, and convert to voltage. Then display on Mu editor's Plotter.

import time
import os
import microcontroller
import board
import analogio

adc01=analogio.AnalogIn(board.IO1)

print("==============================")
print(os.uname())
print("Hello nanoESP32-S2/CircuitPython ADC example")
print("cpu.temperature: " + str(microcontroller.cpu.temperature))
print()

ref = adc01.reference_voltage
print("reference voltage: " + str(ref))

while True:
    value01=adc01.value
    voltage = ref * value01/65535
    print((ref, voltage))
    time.sleep(0.5)

print("- bye -\n")


remark:
As shown in the video, the ADC measured voltage cannot reached 3.3V.
 
I checked the voltage on IO1, is 3.3V. But the returned value of adc01 (analogio.AnalogIn(board.IO1)) is 51871, correspond 2.6V.
 

To get the reference voltage used by the ADC, e can read the property analogio.AnalogIn.reference_voltage.

For ADC values in CircuitPython you’ll find they’re all put into the range of 16-bit unsigned values. This means the possible values you’ll read from the ADC fall within the range of 0 to 65535 (or 2^16 - 1).

(ref: CircuitPython Basics: Analog Inputs & Outputs > Analog to Digital Converter (Inputs))


Next:

Friday, December 4, 2020

CircuitPython 6.1.0 Beta 2 released

CircuitPython 6.1.0 Beta 2 is released (2020-12-03). The downloads page is here, select the correct file and language for your board. 

As mentioned in the Release Notes for 6.1.0-beta.2, Please use 6.0.x if you need a stable version of CircuitPython on all ports except ESP32-S2. Please use this release or newer for the ESP32-S2

To Install CircuitPython to nanoESP32-S2, refer here.

For more exercise of using ESP32-S2, refer here.

Saturday, November 28, 2020

nanoESP32-S2/CircuitPython control on-board NeoPixel, using Adafruit CircuitPython Library Bundle

With CircuitPython installed to nanoESP32-S2, we are going to program nanoESP32-S2 with CircuitPython, using neopixel library come from Adafruit CircuitPython Library Bundle.


The CircuitPython Library Bundle contains all current libraries available for CircuitPython.

To use neopixel library, we have to install Adafruit CircuitPython Library Bundle to our CircuitPython board, nanoESP32-S2. 

- Visit CircuitPython Libraries, download the appropriate bundle for your version of CircuitPython, it is adafruit-circuitpython-bundle-6.x-mpy-20201126.zip in my case. Unzip the file, open the resulting folder and find the lib folder. Open the lib folder and find the library files you need to load. Copy the individual library files you need to the lib folder on your CIRCUITPY drive.

- And we have to check the IO assigned to nanoESP32-S2 on-board NeoPixel.
Visit GitHub wuxx/nanoESP32-S2/schematic/nanoESP32S2-v1.2.pdf to check the schematic. 

Found that the IO assigned to DIN of WS2812B is GPIO18, board.IO18 in CircuitPython.  Actually, board.NEOPIXEL is defined as board.IO18.

WS2812B is a intelligent control LED light source that the control circuit and RGB chip are integrated in a package of 5050 components, the NeoPixel.

- Edit code.py in CIRCUITPY, save and run it:
import time
import os
import microcontroller
import neopixel
import board

def cycleNeopixel(wait):
    for r in range(255):
        pixel[0] = (r, 0, 0)
        time.sleep(wait)
    for r in range(255, 0, -1):
        pixel[0] = (r, 0, 0)
        time.sleep(wait)
        
    for g in range(255):
        pixel[0] = (0, g, 0)
        time.sleep(wait)
    for g in range(255, 0, -1):
        pixel[0] = (0, g, 0)
        time.sleep(wait)
        
    for b in range(255):
        pixel[0] = (0, 0, b)
        time.sleep(wait)
    for b in range(255, 0, -1):
        pixel[0] = (0, 0, b)
        time.sleep(wait)
        
print("==============================")
print(os.uname())
print("Hello nanoESP32-S2/CircuitPython NeoPixel example")
print("cpu.temperature: " + str(microcontroller.cpu.temperature))
print()
print("neopixel version: " + neopixel.__version__)
print()

# Create the NeoPixel object
pixel = neopixel.NeoPixel(board.IO18, 1, pixel_order=neopixel.RGB)
pixel[0] = (0, 0, 0)
time.sleep(2.0)

cycleNeopixel(0.01)

pixel[0] = (0, 0, 0)
time.sleep(2.0)

print("- bye -\n")


Check in the video:


It seem R and G is swapped in my unit, it should be GRB order for the build-in NeoPixel. To correct it, have to change "pixel_order=neopixel.RGB" to "pixel_order=neopixel.GRB" to match. It will be fixed in next exercise.

Next: