Adsense HTML/JavaScript

Sunday, February 27, 2022

Install CircuitPython 7.2.0 on ESP32-C3 (ESP32-C3-DevKitM-1/NodeMCU ESP-C3-32S-Kit)

CircuitPython 7.2.0 was released. With espressif ESP32-S3 and ESP32-C3 supported (considered alpha and will have bugs and missing functionality).


This post show how to install CircuitPython 7.2.0 on ESP32-C3-DevKitM-1 (ESP32-C3-MINI-1), using Raspberry Pi 4B running Raspberry Pi OS 32-bit (buster). Then test with exercise to read system info, control onboard RGB (NEOPIXEL), and 0.96" 80x160 IPS.



Download Firmware:

Visit CircuitPython Download page, search C3.

I can't find exact board named "ESP32-C3-DevKitM-1", so I try "ESP32-C3-DevKitC-1-N4 by Espressif". DOWNLOAD .BIN NOW under CircuitPython 7.2.0, it's adafruit-circuitpython-espressif_esp32c3_devkitm_1_n4-en_US-7.2.0.bin.

Identify USB port:

Before connect the board to USB.
Run the command to clear dmesg buffer -
$ sudo dmesg -c

Connect the ESP32-C3-DevKitM-1 board to USB.
Run dmesg again, the connected port will be shown -
$ dmesg

Install CircuitPython firmware using esptool:

esptool is needed to flash firmware on ESP devices.
~ Install esptool on Raspberry Pi OS (32 bit)

With esptool installed, you can check the ESP chip ID and Flash using commands:
$ esptool.py --chip auto --port /dev/ttyUSB0 chip_id
$ esptool.py --chip auto --port /dev/ttyUSB0 flash_id

To erase the flash, enter:
$ esptool.py --port /dev/ttyUSB0 erase_flash

To flash the firmware, I follow the command in MicroPython document > Getting started with MicroPython on the ESP32 > Deploying the firmware.
replace:
- chip to esp32c3
- port
- address start from 0x0
- file name
$ esptool.py --chip esp32c3 --port /dev/ttyUSB0 write_flash \-z 0x0 \
adafruit-circuitpython-espressif_esp32c3_devkitm_1_n4-en_US-7.2.0.bin
Exercise code:

cpyESP32C3_info.py, get CircuitPython info
"""
CircuitPython 7.2.0 exercise run on ESP32-C3,
get system info.
"""
import board
import sys
import os
"""
ref:
The entire table of ANSI color codes working in C:
https://gist.github.com/RabaDabaDoba/145049536f815903c79944599c6f952a
"""
class color:
   RED = '\033[1;31;48m'
   BLUE = '\033[1;34;48m'
   BLACK = '\033[1;30;48m'
   END = '\033[1;37;0m'

print(board.board_id)
print(sys.implementation[0] + ' ' +
      str(sys.implementation[1][0]) +'.'+
      str(sys.implementation[1][1]) +'.'+
      str(sys.implementation[1][2]))
print("==========================================")
info = color.RED + \
       sys.implementation[0] + ' ' + \
       os.uname()[3] + color.END + '\n' + \
       'run on ' + color.BLUE + os.uname()[4] + color.END
print(info)
print("==========================================")

print()

cpyESP32C3_NEOPIXEL.py, control onboard RGB (Neopixel).
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("Hello ESP32-C3/CircuitPython NeoPixel exercise")
#print(os.uname())
for u in os.uname():
    print(u)
print()
print("neopixel version: " + neopixel.__version__)
print()

# Create the NeoPixel object
pixel = neopixel.NeoPixel(board.NEOPIXEL,
                          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")

cpyESP32C3_st7735_80x160.py, test with 0.96" 80x160 IPS.
"""
CircuitPython 7.2.0 exercise run on ESP32-C3
with unknown brand 0.96 inch 80x160 SPI ST7735 IPS

ref:
adafruit/Adafruit_CircuitPython_ST7735R
https://github.com/adafruit/Adafruit_CircuitPython_ST7735R
"""

from sys import implementation as sysImplementation
import time
import board
import busio
import displayio
import terminalio

from adafruit_st7735r import ST7735R as TFT_ST7735
from adafruit_st7735r import __name__ as ST7735_NAME
from adafruit_st7735r import __version__ as ST7735_VERSION

from adafruit_display_text import label

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

#Connection between ESP32-C3 and SPI ST7735 display
                        #marking on display
tft_sck = board.IO2     #SCL
tft_mosi = board.IO3    #SDA
tft_reset = board.IO0   #RES
tft_dc = board.IO1      #DC
tft_cs = board.IO10     #CS
#Backlight (BLK) connect to ESP32-C3 3V3
#TFT VCC - ESP32-C31 3V3
#TFT GND - ESP32-C3 GND

tft_spi = busio.SPI(clock=tft_sck, MOSI=tft_mosi)
display_bus = displayio.FourWire(
    tft_spi, command=tft_dc, chip_select=tft_cs, reset=tft_reset
)

# I find out colrstart/rowstart by try/error and retry
display = TFT_ST7735(display_bus, width=160, height=80,
                     colstart=26, rowstart=1,
                     rotation=90,
                     invert=True
                     )

print(type(display))
print("display.width:  ", display.width)
print("display.height: ", display.height)

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

color_bitmap = displayio.Bitmap(display.width, display.height, 1)
color_palette = displayio.Palette(1)
color_palette[0] = 0x000000
time.sleep(1)

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

for c in [["RED", 0xFF0000],
          ["GREEN", 0x00FF00],
          ["BLUE", 0x0000FF]]:
    print(c[0], " : ", hex(c[1]))
    color_palette[0] = c[1]
    time.sleep(2)

splash.remove(bg_sprite)
#---

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

color_bitmap = displayio.Bitmap(display.width, display.height, 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(display.width-2, display.height-2, 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(scale=1, x=5, y=10)
text1 = "ESP32-C3"
text_area1 = label.Label(terminalio.FONT, text=text1, color=0xFF0000)
text_group1.append(text_area1)  # Subgroup for text scaling

# Draw a label
strSys = sysImplementation[0] + ' ' + \
         str(sysImplementation[1][0]) +'.'+ \
         str(sysImplementation[1][1]) +'.'+ \
         str(sysImplementation[1][2])
text_group2 = displayio.Group(scale=1, x=5, y=25)
text2 = strSys
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(scale=1, x=5, y=40)
text3 = ST7735_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(scale=1, x=5, y=55)
text4 = ST7735_VERSION
text_area4 = label.Label(terminalio.FONT, text=text4, color=0x000000)
text_group4.append(text_area4)  # Subgroup for text scaling

text_group5 = displayio.Group(scale=1, x=5, y=70)
text5 = str(display.width) + " x " + str(display.height)
text_area5 = label.Label(terminalio.FONT, text=text5, color=0x000000)
text_group5.append(text_area5)  # Subgroup for text scaling

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

time.sleep(3.0)

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

Download firmware for "ESP-C3-32S by Ai-Thinker",  adafruit-circuitpython-ai_thinker_esp32-c3s-en_US-7.2.0.bin.



Replace the file name in flashing command:
$ esptool.py --chip esp32c3 --port /dev/ttyUSB0 write_flash \-z 0x0
adafruit-circuitpython-ai_thinker_esp32-c3s-en_US-7.2.0.bin
cpyESP32C3_info.py run on NodeMCU ESP-C3-32S-Kit:


check the board assignment:





next:
ESP32-C3/CircuitPython 7.2.0 + ST7735 TFT, display bmp in slideshow, and using displayio.OnDiskBitmap/adafruit_imageload.

Wednesday, February 16, 2022

ESP32-C3/arduino-esp32 + 0.96" 80x160 IPS, create custom class extends Adafruit ST7735 library.

 This exercise run on ESP32-C3-DevKitM-1 in arduino-esp32 2.0.2, display on unknown brand 0.96" 80x160 IPS. 

Library used:
- Adafruit ST7735 and ST7789 Library
- Adafruit GFX Library


Connect:

	TFT_ST7735 ESP32-C3
	-------------------
	VCC        3V3
	GND        GND
	CS         10
	RESET      9
	A0(DC)     8
	SDA        6
	SCK        4
	LED        3V3
	
In my test, if Adafruit_ST7735 is used directly (as in another exercise "ESP32-C3/arduino-esp32 to display on ST7735 and ST7789 SPI LCDs") with option INITR_MINI160x80, the drawing area is shifted and REG and BLUE is swapped.


In this exercise, I create a custom class (MyST7735) extend Adafruit_ST7735:
- call setColRowStart(26, 1) in init() to correct the shifting.
- override setRotation() function, to use ST7735_MADCTL_BGR instead of ST77xx_MADCTL_RGB.

Exercise code:

ESP32C3_ST7735_MINI160x80.ino
/*
 * arduino-esp32 exercise run on ESP32-C3-DevKitM-1,
 * display on 0.96" 80x160 TFT with SPI ST7735,
 * using 'Adafruit ST7735 and ST7789 Library'.
 * 
 * Base on Adafruit ST7735 and ST7789 Library 1.9.1
 * 
 * Fix offset and color with
 * custom class (MyST7735) extending Adafruit_ST7735,
 * to call protected function setColRowStart(),
 * and override setRotation().
 * 
 * ref:
 * Adafruit-ST7735-Library:
 * https://github.com/adafruit/Adafruit-ST7735-Library
 * Adafruit-GFX-Library:
 * https://github.com/adafruit/Adafruit-GFX-Library
 *
 */

#include <Adafruit_GFX.h>    // Core graphics library

//#include <Adafruit_ST7735.h> // Hardware-specific library for ST7735
#include "MyST7735.h"

#define TFT_CS_ST7735   10
#define TFT_RST_ST7735  9 // Or set to -1 and connect to Arduino RESET pin
#define TFT_CS_ST7789   2
#define TFT_RST_ST7789  3   
#define TFT_DC          8

/*
 * Erik:
 * on ESP32-C3-DevKitM-1
 * SS:   7  - not used
 * MOSI: 6
 * MISO: 5  - not used
 * SCK:  4
 * ===================
 * Conection:
 * 
 * TFT_ST7735 ESP32-C3
 * -------------------
 * VCC        3V3
 * GND        GND
 * CS         10
 * RESET      9
 * A0(DC)     8
 * SDA        6
 * SCK        4
 * LED        3V3
 *
 */

//Adafruit_ST7735 tft_ST7735 = Adafruit_ST7735(TFT_CS_ST7735, TFT_DC, TFT_RST_ST7735);
MyST7735 tft_ST7735 = MyST7735(TFT_CS_ST7735, TFT_DC, TFT_RST_ST7735);

void setup(void) {
  delay(500);
  Serial.begin(115200);
  delay(500);
  Serial.print(F("Hello!\n"));
  Serial.print(F("0.96 80X160 (RGB) IPS Test\n\n"));

  //tft_ST7735.initR(INITR_MINI160x80); // Init ST7735S mini display
  tft_ST7735.init();
  
  tft_ST7735.invertDisplay(true);
  tft_ST7735.setRotation(3);
  
  // SPI speed defaults to SPI_DEFAULT_FREQ defined in the library, you can override it here
  // Note that speed allowable depends on chip and quality of wiring, if you go too fast,
  // you may end up with a black screen some times, or all the time.
  //tft.setSPISpeed(40000000);

  Serial.println(F("Initialized"));


  // large block of text
  tft_ST7735.fillScreen(ST77XX_BLACK);
  tft_ST7735.setTextWrap(true);
  tft_ST7735.setTextColor(ST77XX_WHITE);

  drawBorderline();

  delay(1000);
  
  tft_ST7735.setCursor(0, 0);
  tft_ST7735.print("Hello ESP32C3");

  tft_ST7735.setCursor(0, 20);
  tft_ST7735.print("Chip Model: " + String(ESP.getChipModel()));
  tft_ST7735.setCursor(0, 30);
  tft_ST7735.print("rotation: " + String(tft_ST7735.getRotation()));
  tft_ST7735.setCursor(0, 40);
  tft_ST7735.print(String(tft_ST7735.width()) + " x " + String(tft_ST7735.height()));

  delay(1000);
  colorTest();

  delay(1000);
  for(int offset=0; offset<tft_ST7735.height()/2-10; offset++){
    int col;
    if(offset%4 == 0)
      col = ST77XX_WHITE;
    else
      col = ST77XX_BLACK;
      
    tft_ST7735.drawRect(offset, offset, 
                 tft_ST7735.width()-1-2*offset, tft_ST7735.height()-1-2*offset,
                 col);
    delay(100);
  }

  delay(2000);

  tft_ST7735.setRotation(0);

  tft_ST7735.fillScreen(ST77XX_BLACK);
  tft_ST7735.setTextWrap(true);
  tft_ST7735.setTextColor(ST77XX_WHITE);

  tft_ST7735.drawRect(0, 0, 
                 tft_ST7735.width()-1, tft_ST7735.height()-1,
                 ST77XX_WHITE);

  delay(1000);
  colorTest();

  drawBorderline();

  Serial.println("\n\n- setup() end -\n");
  delay(1000);
}

void drawBorderline(){
  tft_ST7735.fillScreen(ST77XX_BLACK);
  tft_ST7735.drawRect(0, 0, 
                 tft_ST7735.width()-1, tft_ST7735.height()-1,
                 ST77XX_WHITE);
  Serial.println();
  Serial.printf("\nrotation %d", tft_ST7735.getRotation());
  Serial.printf("\nwidth %d", tft_ST7735.width());
  Serial.printf("\nheight %d", tft_ST7735.height());
}

void colorTest(){
  tft_ST7735.fillScreen(ST77XX_RED);
  tft_ST7735.setCursor(50, 50);
  tft_ST7735.print("RED");
  delay(1000);
  tft_ST7735.fillScreen(ST77XX_GREEN);
  tft_ST7735.setCursor(50, 50);
  tft_ST7735.print("GREEN");
  delay(1000);
  tft_ST7735.fillScreen(ST77XX_BLUE);
  tft_ST7735.setCursor(50, 50);
  tft_ST7735.print("BLUE");
  delay(1000);
}

/*
 * Cnvert R, G, B (in uint8_t)
 * to color (in uint16_t) in 565 format for Adafruit GFX library
 * rrrrrggg gggbbbbb
 */
uint16_t convertRGBtoColor(uint8_t r, uint8_t g, uint8_t b){
  return (((r & 0xF8) << 8) |
          ((g & 0xFC) << 3) |
          (b >> 3));
}

void loop() {
  
  tft_ST7735.setRotation(1);  
  for (int x = 0; x < tft_ST7735.width(); x++){
    int c =255 *  x/tft_ST7735.width();
    uint16_t color = convertRGBtoColor(c, c, c);
    tft_ST7735.drawLine(x, 0, x, tft_ST7735.height()-1, color);
  }
  delay(1000);
  
  tft_ST7735.setRotation(2);
  for (int x = 0; x < tft_ST7735.width(); x++){
    int r =255 *  x/tft_ST7735.width();
    uint16_t color = convertRGBtoColor(r, 0, 0);
    tft_ST7735.drawLine(x, 0, x, tft_ST7735.height()-1, color);
  }
  delay(1000);
  
  tft_ST7735.setRotation(3);
  for (int x = 0; x < tft_ST7735.width(); x++){
    int g =255 *  x/tft_ST7735.width();
    uint16_t color = convertRGBtoColor(0, g, 0);
    tft_ST7735.drawLine(x, 0, x, tft_ST7735.height()-1, color);
  }
  delay(1000);
  
  tft_ST7735.setRotation(4);
  for (int x = 0; x < tft_ST7735.width(); x++){
    int b =255 *  x/tft_ST7735.width();
    uint16_t color = convertRGBtoColor(0, 0, b);
    tft_ST7735.drawLine(x, 0, x, tft_ST7735.height()-1, color);
  }
  delay(1000);
}


MyST7735.cpp
#include "MyST7735.h"
#include "Adafruit_ST7735.h"
#include "Adafruit_ST77xx.h"

MyST7735::MyST7735(int8_t cs, int8_t dc, int8_t rst)
    : Adafruit_ST7735(cs, dc, rst) {}

/*************************************************************************
    init() to fix offset
    by calling protected function setColRowStart().
*************************************************************************/

void MyST7735::init(void) {
  initR(INITR_MINI160x80);
  setColRowStart(26, 1);
}

/*************************************************************************
    override setRotation() to fix color order using ST7735_MADCTL_BGR.
    To make it simple, option INITR_MINI160x80 is assumed and handled only.
*************************************************************************/
void MyST7735::setRotation(uint8_t m) {
  uint8_t madctl = 0;

  rotation = m & 3; // can't be higher than 3

  switch (rotation) {
  case 0:

    madctl = ST77XX_MADCTL_MX | ST77XX_MADCTL_MY | ST7735_MADCTL_BGR;
    _height = ST7735_TFTHEIGHT_160;
    _width = ST7735_TFTWIDTH_80;
    _xstart = _colstart;
    _ystart = _rowstart;
    break;
  case 1:

    madctl = ST77XX_MADCTL_MY | ST77XX_MADCTL_MV | ST7735_MADCTL_BGR;
    _width = ST7735_TFTHEIGHT_160;
    _height = ST7735_TFTWIDTH_80;
    _ystart = _colstart;
    _xstart = _rowstart;
    break;
  case 2:
    madctl = ST7735_MADCTL_BGR;
    _height = ST7735_TFTHEIGHT_160;
    _width = ST7735_TFTWIDTH_80;
    _xstart = _colstart;
    _ystart = _rowstart;
    break;
  case 3:

    madctl = ST77XX_MADCTL_MX | ST77XX_MADCTL_MV | ST7735_MADCTL_BGR;
    _width = ST7735_TFTHEIGHT_160;
    _height = ST7735_TFTWIDTH_80;
    _ystart = _colstart;
    _xstart = _rowstart;
    break;
  }

  sendCommand(ST77XX_MADCTL, &madctl, 1);
}


MyST7735.h
#ifndef _MyST7735_
#define _MyST7735_

#include "Adafruit_ST77xx.h"
#include "Adafruit_ST7735.h"

#define ST7735_MADCTL_BGR 0x08
#define ST77XX_MADCTL_RGB 0x00

class MyST7735 : public Adafruit_ST7735 {

  public:
  MyST7735(int8_t cs, int8_t dc, int8_t rst);
  void init(void);
  void setRotation(uint8_t m);
  
};

#endif // _MyST7735_