Adsense HTML/JavaScript

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.

No comments:

Post a Comment