Adsense HTML/JavaScript

Wednesday, September 29, 2021

CircuitPython 7 exercises on STM32F411

It's my first try CircuitPython 7.0.0 on STM32F411 minimum development board (Blackpill-like but NOT Blackpill).

cpyF411_info.py
"""
CircuitPython exercise run on STM32F411CE,
get system info.
"""

import os
import microcontroller
import sys

print("- sys.implementation -")
for i in sys.implementation:
    print(i)
print()

print("- os.uname() -")
for u in os.uname():
    print(u)
print()

print("microcontroller.cpu.frequency:\t\t" + str(microcontroller.cpu.frequency))
print("microcontroller.cpu.temperature:\t" + str(microcontroller.cpu.temperature))
print("microcontroller.cpu.voltage:\t\t" + str(microcontroller.cpu.voltage))


cpyF411_listdir.pya
"""
CircuitPython List Files:

The original example list files in SDCard,
now modified to list files in current working directory.

ref:
https://learn.adafruit.com/micropython-hardware-sd-cards/tdicola-circuitpython
scroll down to "List Files"
"""

import os

def print_directory(path, tabs=0):
    for file in os.listdir(path):
        stats = os.stat(path + "/" + file)
        filesize = stats[6]
        isdir = stats[0] & 0x4000

        if filesize < 1000:
            sizestr = str(filesize) + " by"
        elif filesize < 1000000:
            sizestr = "%0.1f KB" % (filesize / 1000)
        else:
            sizestr = "%0.1f MB" % (filesize / 1000000)

        prettyprintname = ""
        for _ in range(tabs):
            prettyprintname += "   "
        prettyprintname += file
        if isdir:
            prettyprintname += "/"
        print('{0:<40} Size: {1:>10}'.format(prettyprintname, sizestr))

        # recursively print directory contents
        if isdir:
            print_directory(path + "/" + file, tabs + 1)

currentDirectory = os.getcwd()
print("Files on filesystem: ", currentDirectory)
print("====================")

print_directory(currentDirectory)


cpyF411_readfile.py
"""
CircuitPython exercise run on STM32F411CE,
get system info.
"""

import os

textfile = "/boot_out.txt"
print("text file:", textfile)
print("========================")
with open(textfile, "r") as f:
    print("Read line from file:")
    print(f.readline())


cpyF411_hello.py
"""
CircuitPython exercise run on STM32F411CE,
toggle onboard LED.
"""

import board
import digitalio
import time

print("\ndir(board):")
print(dir(board))

led = digitalio.DigitalInOut(board.LED)
led.direction = digitalio.Direction.OUTPUT

while True:
    led.value = True   #LED Off
    time.sleep(0.3)
    led.value = False  #LED On
    time.sleep(0.3)
    led.value = True   #LED Off
    time.sleep(0.3)
    led.value = False  #LED On
    time.sleep(0.3)
    led.value = True   #LED Off
    time.sleep(0.3)
    led.value = False  #LED On
    time.sleep(1.5)



Next exercise of STM32F411/CircuitPython 7"

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: