Adsense HTML/JavaScript

Showing posts with label STM32F411. Show all posts
Showing posts with label STM32F411. Show all posts

Sunday, October 17, 2021

STM32F411/CircuitPython 7, with 2" 240x320 SPI ST7789 IPS LCD

To use ST7789 SPI LCD on STM32F411/CircuitPython 7.0.0, basically same as shown in the post: "CircuitPython 7 exercises on STM32F411, with SPI ST7735 LCD", except using library of adafruit_st7789 instead of using adafruit_st7735/adafruit_st7735r.


cpyF411_st7789_240x320.py
"""
CircuitPython 7 exercise run on STM32F411
with 2" 240x320 SPI ST7789 IPS

"""

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

from adafruit_st7789 import ST7789 as TFT_ST77xx
from adafruit_st7789 import __name__ as ST77xx_NAME
from adafruit_st7789 import __version__ as ST77xx_VERSION

from adafruit_display_text import label

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

#Connection between STM32F411 and SPI ST7789 display
#marking on display     
tft_sck = board.B13     #SCL
tft_mosi = board.A1     #SDA


tft_dc = board.A2       #DC
tft_reset = board.A3    #RES
tft_cs = board.A4       #CS
#Backlight (LED/BLK) connect to STM32F411 3V3
#TFT VCC - STM32F411 3V3
#TFT GND - STM32F411 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_ST77xx(display_bus, width=320, height=240,
                     colstart=0, rowstart=0,
                     rotation=90,
                     )

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 = "STM32F411"
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 = ST77xx_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 = ST77xx_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


Friday, October 15, 2021

STM32F411/CircuitPython 7, read SD Card, load bitmap and display on ST7735 LCD

The former STM32F411/CircuitPython 7 exercise show display on SPI ST7735 LCD. This exercise connect to a MicroSD card adapter, read text file, load bitmap and display on SPI ST7735 LCD.

It's assumed CircuitPython 7.0.0 is installed on STM32F411 development board, a STM32F411CE Black Pill-like board. To install CircuitPython firmware on STM32F411, refer to the post "Flash CircuitPython to STM32F411, and install Thonny IDE on Ubuntu 20.10", with list to more exercises.

The MicroSD adapter used support Micro SD <=2G, Micro SDHC <=32G, require operating voltage of 4.5~5.5V, with 3.3/5V interface voltage. So connect STM32F411 5V to MicroSD adapter's VCC, GND to GND. Other pins refer to the exercise code, marked in blue.

The libraries needed in this exercise include adafruit_sdcard.mpy, adafruit_st7735r.mpy and adafruit_imageload.

Visit https://circuitpython.org/libraries, download the appropriate bundle (adafruit-circuitpython-bundle-7.x-mpy- here) for your version of CircuitPython. Unzip the file, copy adafruit_sdcard.mpy, adafruit_st7735r.mpy and adafruit_imageload folder from the "lib" folder to the "lib" folder on your CIRCUITPY drive. (refer to the video in last post "CircuitPython 7 exercises on STM32F411, with SSD1306 I2C OLED")

Exercise code

cpyF411_SD.py, simple print the files in microSD. There are one text file (hello.txt) and three bmp files (logo.bmp, photo_01.bmp and photo_02.bmp) in my microSD card.
"""
CircuitPython exercise running on STM32F411:
Read SD Card using adafruit_sdcard library
https://circuitpython.readthedocs.io/projects/sd/en/3.3.5/api.html

List files on SD Card
"""

import board
from sys import implementation as sysImplementation
import busio
import digitalio
import adafruit_sdcard
import storage
import os

sd_path = "/sd"

print(board.board_id)
strSys = sysImplementation[0] + ' ' + \
         str(sysImplementation[1][0]) +'.'+ \
         str(sysImplementation[1][1]) +'.'+ \
         str(sysImplementation[1][2])
print(strSys)
print(adafruit_sdcard.__name__, " ", adafruit_sdcard.__version__)
print()

#Connection between SDCard and STM32F411
#SD Card VCC - 5V
#SD Card GND - GND
sd_SCK = board.B3
sd_MISO = board.B4
sd_MOSI = board.B5
sd_CS = board.A15
spi = busio.SPI(sd_SCK, sd_MOSI, sd_MISO)
cs = digitalio.DigitalInOut(sd_CS)

# ref:
# https://circuitpython.readthedocs.io/projects/sd/en/3.3.5/examples.html
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)

try:
    sdcard = adafruit_sdcard.SDCard(spi, cs)
    vfs = storage.VfsFat(sdcard)
    storage.mount(vfs, sd_path)
    
    print("Files on filesystem:")
    print("====================")
    print_directory(sd_path)

except OSError as exc:
    print(exc.args[0])


cpyF411_SD_textfile.py, read the "hello.txt" from microSD Card.
"""
CircuitPython exercise running on STM32F411:
Read SD Card using adafruit_sdcard library

Read the "hello.txt" from SD Card
"""

import board
from sys import implementation as sysImplementation
import busio
import digitalio
import adafruit_sdcard
import storage
import os

sd_path = "/sd"

print(board.board_id)
strSys = sysImplementation[0] + ' ' + \
         str(sysImplementation[1][0]) +'.'+ \
         str(sysImplementation[1][1]) +'.'+ \
         str(sysImplementation[1][2])
print(strSys)
print(adafruit_sdcard.__name__, " ", adafruit_sdcard.__version__)
print()

#Connection between SDCard and STM32F411
#SD Card VCC - 5V
#SD Card GND - GND
sd_SCK = board.B3
sd_MISO = board.B4
sd_MOSI = board.B5
sd_CS = board.A15
spi = busio.SPI(sd_SCK, sd_MOSI, sd_MISO)
cs = digitalio.DigitalInOut(sd_CS)

# ref:
# https://circuitpython.readthedocs.io/projects/sd/en/3.3.5/examples.html
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)

try:
    sdcard = adafruit_sdcard.SDCard(spi, cs)
    vfs = storage.VfsFat(sdcard)
    storage.mount(vfs, sd_path)
    
    print("Files on filesystem:")
    print("====================")
    print_directory(sd_path)
    print("====================")
    print()
    
    textfile = sd_path+"/hello.txt"
    print("text file:", textfile)
    print("========================")
    with open(textfile, "r") as f:
        line = f.readline()
        while line != '':
            print(line)
            line = f.readline()


except OSError as exc:
    print(exc.args[0])


cpyF411_SD_bitmap_logo.py, read a single bmp file (logo.bmp) from SD Card using displayio.OnDiskBitmap(), and display on SPI ST7735 LCD
"""
CircuitPython exercise running on STM32F411:
Read SD Card using adafruit_sdcard library

Read a single bmp from SD Card using displayio.OnDiskBitmap()

and display on SPI ST7735 LCD
"""

import board
from sys import implementation as sysImplementation
import busio
import digitalio
import adafruit_sdcard
import storage
import os
import displayio

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

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

sd_path = "/sd"

print(board.board_id)
strSys = sysImplementation[0] + ' ' + \
         str(sysImplementation[1][0]) +'.'+ \
         str(sysImplementation[1][1]) +'.'+ \
         str(sysImplementation[1][2])
print(strSys)
print(adafruit_sdcard.__name__, " ", adafruit_sdcard.__version__)
print(ST7735_NAME, " ", ST7735_VERSION)
print()

#Connection between SDCard and STM32F411
#SD Card VCC - 5V
#SD Card GND - GND
sd_SCK = board.B3
sd_MISO = board.B4
sd_MOSI = board.B5
sd_CS = board.A15
sd_spi = busio.SPI(sd_SCK, sd_MOSI, sd_MISO)
sd_cs = digitalio.DigitalInOut(sd_CS)

#Connection between STM32F411 and SPI ST7735 display
#marking on display     #128x128   #80x160
tft_sck = board.B13     #SCK       #SCL
tft_mosi = board.A1     #SDA       #SDA

tft_dc = board.A2       #A0        #DC
tft_reset = board.A3    #RESET     #RES
tft_cs = board.A4       #CS        #CS
#Backlight (LED/BLK) connect to STM32F411 3V3
#TFT VCC - STM32F411 3V3
#TFT GND - STM32F411 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=128, height=128,
                     rotation=180,
                     bgr=True)

print(type(display))
print("display.width:  ", display.width)
print("display.height: ", display.height)
print()
            
try:
    sdcard = adafruit_sdcard.SDCard(sd_spi, sd_cs)
    vfs = storage.VfsFat(sdcard)
    storage.mount(vfs, sd_path)
    
    print("========================")
    bmpfile = sd_path+"/logo.bmp"
    print("bitmap file:", bmpfile)
    
    bitmap = displayio.OnDiskBitmap(bmpfile)

    # Create a TileGrid to hold the bitmap
    tile_grid = displayio.TileGrid(bitmap, pixel_shader=bitmap.pixel_shader)

    # Create a Group to hold the TileGrid
    group = displayio.Group()

    # Add the TileGrid to the Group
    group.append(tile_grid)

    # Add the Group to the Display
    display.show(group)

            
except OSError as exc:
    print(exc.args[0])

while True:
    pass

displayio.OnDiskBitmap vs adafruit_imageload

OnDiskBitmap source the bitmap image directly from flash memory storage. This is like reading the image from disk instead of loading it into memory first imageload). The trade off of using OnDiskBitmap is the reduced use of memory for potentially slower pixel draw times.

ref:

cpyF411_SD_bitmap_rot_.py, repeatedly load bmp files (logo.bmp, photo_01.bmp and photo_02.bmp) from SD Card using adafruit_imageload (marked in red) or displayio.OnDiskBitmap (marked in green), then display on SPI ST7735 LCD.
"""
CircuitPython exercise running on STM32F411:
Read SD Card using adafruit_sdcard library

Repeatly load bmp(s) from SD Card using:
- adafruit_imageload
- displayio.OnDiskBitmap

and display on SPI ST7735 LCD
"""

import board
from sys import implementation as sysImplementation
import busio
import digitalio
import adafruit_sdcard
import storage
import os
import displayio
import adafruit_imageload
import time

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

import gc

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

sd_path = "/sd"

print(board.board_id)
strSys = sysImplementation[0] + ' ' + \
         str(sysImplementation[1][0]) +'.'+ \
         str(sysImplementation[1][1]) +'.'+ \
         str(sysImplementation[1][2])
print(strSys)
print(adafruit_sdcard.__name__, " ", adafruit_sdcard.__version__)
print(adafruit_imageload.__name__, " ", adafruit_imageload.__version__)
print(ST7735_NAME, " ", ST7735_VERSION)
print()

#Connection between SDCard and STM32F411
#SD Card VCC - 5V
#SD Card GND - GND
sd_SCK = board.B3
sd_MISO = board.B4
sd_MOSI = board.B5
sd_CS = board.A15
sd_spi = busio.SPI(sd_SCK, sd_MOSI, sd_MISO)
sd_cs = digitalio.DigitalInOut(sd_CS)

#Connection between STM32F411 and SPI ST7735 display
#marking on display     #128x128   #80x160
tft_sck = board.B13     #SCK       #SCL
tft_mosi = board.A1     #SDA       #SDA

tft_dc = board.A2       #A0        #DC
tft_reset = board.A3    #RESET     #RES
tft_cs = board.A4       #CS        #CS
#Backlight (LED/BLK) connect to STM32F411 3V3
#TFT VCC - STM32F411 3V3
#TFT GND - STM32F411 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=128, height=128,
                     rotation=180,
                     bgr=True)

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

try:
    sdcard = adafruit_sdcard.SDCard(sd_spi, sd_cs)
    vfs = storage.VfsFat(sdcard)
    storage.mount(vfs, sd_path)
    
    # Create a Group to hold the TileGrid
    group = displayio.Group()
    
    pToBmp = ["logo.bmp", "photo_01.bmp", "photo_02.bmp"]
    
    while True:
        for b in pToBmp:
            print("========================")
            bmpfile = sd_path + "/" + b
            print("bitmap file:", bmpfile)
            
            print("free mem@before bitmap", gc.mem_free())
            
            # using adafruit_imageload
            bitmap, palette = adafruit_imageload.load(bmpfile,
                                                  bitmap=displayio.Bitmap,
                                                  palette=displayio.Palette)
            
            #using displayio.OnDiskBitmap
            #bitmap = displayio.OnDiskBitmap(bmpfile)
            #palette = bitmap.pixel_shader
            
            print("free mem@after bitmap", gc.mem_free())
            gc.collect()
            print("free mem@after gc.collect()", gc.mem_free())
            
            print(bitmap.width, " x ", bitmap.height)
    
            # Create a TileGrid to hold the bitmap
            tile_grid = displayio.TileGrid(bitmap, pixel_shader=palette)

            # Add the TileGrid to the Group
            group.append(tile_grid)
            print("index: ", group.index(tile_grid))

            # Add the Group to the Display
            display.show(group)
            
            time.sleep(3)
            group.remove(tile_grid)
            
except OSError as exc:
    print(exc.args[0])

while True:
    pass

bmp files used here:

logo.bmp
photo_01.bmp
photo_02.bmp









Not all BMP file formats are supported by CircuitPython. You will need to make sure you have an indexed BMP file. Follow HERE for some good info on how to convert or create such a BMP file.

Wednesday, October 13, 2021

CircuitPython 7 exercises on STM32F411, identify pins

Get Pins name

Many pins on CircuitPython compatible microcontroller boards have multiple names, however, typically, there's only one name labeled on the physical board. So how do you find out what the other available pin names are? Simple, with the following script! Each line printed out to the serial console contains the set of names for a particular pin.

~ ref: https://learn.adafruit.com/circuitpython-essentials/circuitpython-pins-and-modules

"""CircuitPython Essentials Pin Map Script"""
import microcontroller
import board

board_pins = []
for pin in dir(microcontroller.pin):
    if isinstance(getattr(microcontroller.pin, pin), microcontroller.Pin):
        pins = []
        for alias in dir(board):
            if getattr(board, alias) is getattr(microcontroller.pin, pin):
                pins.append("board.{}".format(alias))
        if len(pins) > 0:
            board_pins.append(" ".join(pins))
for pins in sorted(board_pins):
    print(pins)

Tested on STM32F411 Dev. Board with CircuitPython 7.0.0




List I2C possible pin-pair
"""CircuitPython Essentials I2C possible pin-pair identifying script"""
import board
import busio
from microcontroller import Pin

def is_hardware_I2C(scl, sda):
    try:
        p = busio.I2C(scl, sda)
        p.deinit()
        return True
    except ValueError:
        return False
    except RuntimeError:
        return True

def get_unique_pins():
    exclude = ['NEOPIXEL', 'APA102_MOSI', 'APA102_SCK']
    pins = [pin for pin in [
        getattr(board, p) for p in dir(board) if p not in exclude]
            if isinstance(pin, Pin)]
    unique = []
    for p in pins:
        if p not in unique:
            unique.append(p)
    return unique

for scl_pin in get_unique_pins():
    for sda_pin in get_unique_pins():
        if scl_pin is sda_pin:
            continue
        if is_hardware_I2C(scl_pin, sda_pin):
            print("SCL pin:", scl_pin, "\t SDA pin:", sda_pin)






CircuitPython 7 exercises on STM32F411, with SPI ST7735 LCD

Test on 3 type of ST7735 SPI LCD with STM32F411/CircuitPython 7.0.0:
- 1.44" 128x128 (KMR1441_SPI V2)
- 0.96" 80x160 IPS
- 1.8" 128x160 TFT

It's assumed CircuitPython 7.0.0 is installed on STM32F411 minimum development board, a STM32F411CE Black Pill-like board. To install CircuitPython firmware on STM32F411, refer to the post "Flash CircuitPython to STM32F411, and install Thonny IDE on Ubuntu 20.10".

Library

adafruit_st7735, adafruit_st7735r and adafruit_display_text are needed in the following exercises.

Visit https://circuitpython.org/libraries, download the appropriate bundle (adafruit-circuitpython-bundle-7.x-mpy- here) for your version of CircuitPython. Unzip the file, copy adafruit_st7735.mpy, adafruit_st7735r.mpy and adafruit_display_text folder from the "lib" folder to the "lib" folder on your CIRCUITPY drive. (refer to the video in last post "CircuitPython 7 exercises on STM32F411, with SSD1306 I2C OLED")


Connection

Please notice that 1.44" 128x128 (KMR1441_SPI V2) and 1.8" 128x160 TFT have same pin assignment, 0.96" 80x160 IPS have different pin order and pin name but same function.

The connection refer to the exercise code, marked blue.

Exercise code

The code in red show the difference between them.

cpyF411_st7735_128x128.py for 1.44" 128x128 (KMR1441_SPI V2)
"""
CircuitPython 7 exercise run on STM32F411
with 128x128 SPI ST7735

ref:
adafruit/Adafruit_CircuitPython_ST7735
https://github.com/adafruit/Adafruit_CircuitPython_ST7735
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_st7735 import ST7735 as TFT_ST7735
from adafruit_st7735 import __name__ as ST7735_NAME
from adafruit_st7735 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 STM32F411 and SPI ST7735 display
#marking on display     #128x128   #80x160
tft_sck = board.B13     #SCK       #SCL
tft_mosi = board.A1     #SDA       #SDA

tft_dc = board.A2       #A0        #DC
tft_reset = board.A3    #RESET     #RES
tft_cs = board.A4       #CS        #CS
#Backlight (LED/BLK) connect to STM32F411 3V3
#TFT VCC - STM32F411 3V3
#TFT GND - STM32F411 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=128, height=128,
                     rotation=90,
                     )

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 = "STM32F411"
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


cpyF411_st7735_80x160.py for 0.96" 80x160 IPS
"""
CircuitPython 7 exercise run on STM32F411
with 80x160 SPI ST7735 IPS

ref:
adafruit/Adafruit_CircuitPython_ST7735
https://github.com/adafruit/Adafruit_CircuitPython_ST7735
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 STM32F411 and SPI ST7735 display
#marking on display     #128x128   #80x160
tft_sck = board.B13     #SCK       #SCL
tft_mosi = board.A1     #SDA       #SDA

tft_dc = board.A2       #A0        #DC
tft_reset = board.A3    #RESET     #RES
tft_cs = board.A4       #CS        #CS
#Backlight (LED/BLK) connect to STM32F411 3V3
#TFT VCC - STM32F411 3V3
#TFT GND - STM32F411 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)

	[... same as in cpyF411_st7735_128x128.py ...]

cpyF411_st7735_128x160.py for 1.8" 128x160 TFT
"""
CircuitPython 7 exercise run on STM32F411
with 128x160 SPI ST7735

ref:
adafruit/Adafruit_CircuitPython_ST7735
https://github.com/adafruit/Adafruit_CircuitPython_ST7735
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 STM32F411 and SPI ST7735 display
#marking on display     #128x128   #80x160
                        #128x160
tft_sck = board.B13     #SCK       #SCL
tft_mosi = board.A1     #SDA       #SDA

tft_dc = board.A2       #A0        #DC
tft_reset = board.A3    #RESET     #RES
tft_cs = board.A4       #CS        #CS
#Backlight (LED/BLK) connect to STM32F411 3V3
#TFT VCC - STM32F411 3V3
#TFT GND - STM32F411 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=128,
                     rotation=90,
                     )

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

	[... same as in cpyF411_st7735_128x128.py ...]
next:


Remark@2021-10-15

Fix color order

Noted that the color order (RED/GREEN/BLUE shown in the video) is in-correct. To fix it:
- Use adafruit_st7735r library.
- add the parameter bgr=True when you create display object.







Monday, October 11, 2021

CircuitPython 7 exercises on STM32F411, with SSD1306 I2C OLED

This post show how to run CircuitPython code on STM32F411, display on SSD1306 I2C 128x64 OLED using adafruit_ssd1306 library.

It's assumed CircuitPython 7.0.0 is installed on STM32F411 minimum development board, a STM32F411CE Black Pill-like board. To install CircuitPython firmware on STM32F411, refer to the post "Flash CircuitPython to STM32F411, and install Thonny IDE on Ubuntu 20.10".

Connection

SSD1306 I2C	STM32F411
-------------------------
GND		GND
VCC		3V3
SCL		B6
SDA		B7

Library

To run the exercise code,  Adafruit CircuitPython Library Bundle's adafruit_ssd1306 and font5x8.bin is need.

Visit https://circuitpython.org/libraries, download the appropriate bundle (adafruit-circuitpython-bundle-7.x-mpy- here) for your version of CircuitPython.

Unzip the file, copy adafruit_ssd1306.mpy, and adafruit_framebuf.mpy from the "lib" folder to the lib folder on your CIRCUITPY drive. 

And copy font5x8.bin from the unzipped "examples" folder to CIRCUITPY driver.

Exercise code

cpyF411_scanI2C.py, scan the address of connected I2C devices.
import os
import busio
import board

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

#Assign I2C:
#https://circuitpython.readthedocs.io/en/latest/shared-bindings/board/index.html#board.I2C
print(dir(board))
print("SCL: ", board.SCL)
print("SDA: ", board.SDA)
i2c = board.I2C()
print(i2c)
print()

#Scan I2C devices
if(i2c.try_lock()):
    print("i2c.scan(): " + str(i2c.scan()))
    i2c.unlock()
print()


cpyF411_SSD1306.py
from os import uname
from board import SCL, SDA
from sys import implementation as sysImplementation
import busio
import time

import adafruit_ssd1306


# Create the I2C interface and display object of SSD1306_I2C.
i2c = busio.I2C(SCL, SDA)
display = adafruit_ssd1306.SSD1306_I2C(128, 64, i2c)

for u in uname():
    print(u)
print()
for s in sysImplementation:
    print(s)
print()

print(display)
print("display.width x height: ", display.width, " x ", display.height)
print(dir(display))
    
display.fill(0)
display.show()
time.sleep(1)
display.fill(1)
display.show()
time.sleep(1)

display.fill(0)


strSys = sysImplementation[0] + ' ' + \
         str(sysImplementation[1][0]) +'.'+ \
         str(sysImplementation[1][1]) +'.'+ \
         str(sysImplementation[1][2])

strLib = adafruit_ssd1306.__name__ + '\n' + adafruit_ssd1306.__version__

def drawInfo():
    display.text(strSys, 0, 0, 1)
    display.text(strLib, 0, 10, 1)
    display.text("STM32F411", 0, 30, 1)
    display.text("SSD1306", 0, 40, 1)
    strResolution = str(display.rotation) + ' : ' + str(display.width) + ' x ' + str(display.height)
    display.text(strResolution, 0, 50, 1)
    
for r in range(0, 4):
    display.fill(0)
    display.rotation = r
    drawInfo()
    display.show()
    time.sleep(3)

display.rotation = 0

#draw rectangle
display.fill(0)
display.rect(0, 0, display.width, display.height, 1)
display.show()
time.sleep(1)
display.fill(0)
display.fill_rect(0, 0, display.width, display.height, 1)
display.show()
time.sleep(1)

#draw circle
display.fill(0)
if display.width > display.height:
    r = (int)(display.height/2)
else:
    r = (int)(display.width/2)
display.circle((int)(display.width/2), (int)(display.height/2), r, 1)
display.show()
time.sleep(1)

display.fill(0)
display.show()

# draw pixels
for y in range(0, display.height, 8):
    for x in range(0, display.width, 8):
        display.pixel(x, y, 1)
        display.show()
time.sleep(1)
display.invert(1)
time.sleep(2)
display.invert(0)
time.sleep(1)

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, January 25, 2021

STM32F411/CircuitPython drive NeoPixel

With CircuitPython installed on STM32F411 dev. board, it cab be programmed to drive NeoPixel using Adafruit CircuitPython Library. This post show how to drive 8X NeoPixel Ring.



Basically the steps to install library is same as in nanoESP32-S2/CircuitPython control on-board NeoPixel, using Adafruit CircuitPython Library Bundle and nanoESP32-S2/CircuitPython exercise: to control external NeoPixel. Visit CircuitPython Libraries to download the matched Bundle Version. Unzip the file, open the resulting folder and find the lib folder. Copy the library neopixel.mpy file you need to the lib folder on your CIRCUITPY drive.



CircuitPython code to test the 8X NeoPixel Ring, F411_testNeopixel.py
import time
import os
import microcontroller
import neopixel
import board
import random

NumOfPixel_ring = 8

def offAllPixel():
    fillAllPixel(0, 0, 0)
    
def fillAllPixel(r, g, b):
    pixel_ring.fill((r, g, b))


print("==============================")
print(os.uname())
print("STM32F411/CircuitPython NeoPixel example")
print("Test on:")
print("8X NeoPixel Ring")
print("cpu.temperature: " + str(microcontroller.cpu.temperature))
print()
print("neopixel version: " + neopixel.__version__)
print()

# Create the NeoPixel object
pixel_ring = neopixel.NeoPixel(board.A7, NumOfPixel_ring, 
                    brightness=0.1,
                    pixel_order=neopixel.GRB)

offAllPixel()

while True:
    
    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))

    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")`
My 8X NeoPixel Ring is work on 5V, connect 5V of STM32F411 board to 5V of NeoPixel.
Connect GND of STM32F411 to GND of NeoPixel.
Connect A7 of STM32F411 to DIN of NeoPixel, to match with board.A7 assigned in thte code.

Friday, January 22, 2021

Flash CircuitPython to STM32F411, and install Thonny IDE on Ubuntu 20.10

This post show the steps to flash CircuitPython 6.1.0 to STM32F411 dev. board, and install Thonny IDE on Ubuntu 20.10. Tested on VirtualBox 6.1/Windows 10.

The target board is a STM32F411CEU6 minimum development board, it should be compatible with STM32F411CE Black Pill, I guess.

Visit CircuitPython Download page to download CircuitPython match your board. It's "STM32F411CE Black Pill" in my case.

Install dfu-util:
dfu-util is a program that implements the host (computer) side of the USB DFU (Universal Serial Bus Device Firmware Upgrade) protocol. DFU is intended to download and upload firmware to/from devices connected over USB. It ranges from small devices like micro-controller boards to mobile phones. Using dfu-util you can download firmware to your DFU-enabled device or upload firmware from it.

$ sudo apt install dfu-util

You can list the currently attached DFU capable USB devices with -l option:

$ sudo dfu-util -l

Flash downloaded CircuitPython bin to STM32F411:

$ sudo dfu-util -d 0483:df11 -a 0 -s 0x08000000:leave -D <circuitpython bin file>

After flashed, in my try, have to un-plug and re-plug the USB of the STM32F411 Dev.board, to make it recognized. A new driver "CIRCUITPY" appear.

Install Thonny IDE:

$ sudo apt-get install python3-pip
$ sudo pip3 install thonny
$ sudo apt install python3-tk

And add yourself to the 'dialout' group:

$ sudo usermod -a -G dialout <user>

After installed, you can run thonny by enter "thonny" in Terminal.

cpyHelloSTM32F411.py, the testing circuitpython code run in the video.
import os
import microcontroller
import board
import digitalio
import time

print(os.uname())
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))

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)


Extra remark about using USB Device Filters for VirtualBox:

You can create filters for specified USB devices. Matched USB devices will be automatically passed to the guest once they are attached to the host. Such that you need not manually pass to guest everytime the USB device attached.





Example of STM32F411/CircuitPython: 

More Exercise of STM32F411/CircuitPython 7:

Monday, August 17, 2020

STM32F411CEU6 + SSD1306 I2C OLED

 

This video show 0.96 inch 128x64 OLED with SSD1306 I2C driver, drive by STM32F411CEU6 minimum development board, STM32F411CEU6 minimum development board + SSD1306 I2C OLED, using stm32duino/Arduino_Core_STM32 on Arduino IDE using ssd1306 library.

To install stm32duino/Arduino_Core_STM32 on Arduino IDE/Windows 10 and program STM32F411CEU6 minimum development board, read the post HERE.

Then:

- Install ssd1306 library in Arduino IDE Library Manager.

- Open Examples > ssd1306 > demos > ssd1306_demo

- Connect the SSD1306 I2C OLED to STM32F411CEU6 minimum development board following the comments in the demo code.


STM32F411	SSD1306 I2C OLED
----------------------------
3V3			VCC
GND			GND
B7			SDA
B6			SCL


Sunday, June 28, 2020

STM32F411CEU6 minimum development board, and install stm32duino/Arduino_Core_STM32 on Arduino IDE/Windows 10.

Just received a STM32F411CEU6 minimum development board:



claimed:
STM32F411 Development Board
- Frequency up to 100 MHz
- Up to 512 Kbytes of Flash memory
- 128 Kbytes of SRAM

Information available at https://pan.baidu.com/s/1MDfunchq5IWM3hQ6MRw18A with access code: xbc9

But I'm outside China Mainland, so I cannot access Baidu cloud storage!


Test with stm32duino/Arduino_Core_STM32 on Arduino IDE/Windows 10

This board used DFU to upload program, so have to install STM32CubeProgrammer first.

Visit https://www.st.com/en/development-tools/stm32cubeprog.html, follow the steps to install STM32CubeProgrammer.

Then add the path of bin directory of installed STM32CubeProgrammer to your system PATH.




Install stm32duino/Arduino_Core_STM32, this repo adds the support of STM32 MCU in Arduino IDE.

To install Arduino_Core_STM32, open Arduino IDE.

Click Menu > File > Preferences, add the following URL to Additional Boards Manager URLs:
https://github.com/stm32duino/BoardManagerFiles/raw/master/STM32/package_stm_index.json


> Tools > Board: STM32 Boards (slected from submenu) > Generic STM32F4 series

> Tools > select submenu of Board part number > BlackPill F411CE

> Tools > Upload method > STM32CubeProgrammer (DFU)

Load the example Blink

Now press the buttons on the board to enter DFU mode.
> Press and hold the button BOOT0
> Preess and release the button RST
> Release the button BOOT0

The LED D3 will OFF.

Now you can verify and upload the program to the board.

Done. Now the LED D3 will start to blink.


remark:
Before trying BlackPill F411CE, I tried board part number of Generic F411CE. Success to verify and upload, but the LED not turn on.



Next: 

Related: