← index #15979Issue #15892
Related · medium · value 0.529
QUERY · ISSUE

SPI Connection to SD Card Fails to Recognize Chinese Directories

openby ideasworkcnopened 2024-10-08updated 2026-01-20
bugunicode

Port, board and/or hardware

esp32

MicroPython version

When using SPI to connect an SD card in a MicroPython environment, directories with Chinese characters in their names are not recognized correctly. This results in errors or the directories being displayed as garbled text.

Reproduction

1.Connect an SD card to a MicroPython device using SPI.
2.list a directory on the SD card with a name containing Chinese characters.
3.list the Chinese directory contents using os.listdir().

Expected behaviour

The directory with Chinese characters should be listed correctly without errors.

Observed behaviour

The directory name appears as garbled text, and accessing it may result in errors.

Additional Information

No, I've provided everything above.

Code of Conduct

Yes, I agree

CANDIDATE · ISSUE

Unable to use both SD card and display when they share SPI pins. (Erratic behavior from both)

closedby echo-laliaopened 2024-09-22updated 2024-11-07
bug

Port, board and/or hardware

ESP32 (Lilygo TDeck with ESP32-S3)

MicroPython version

Tested with:

  • MicroPython v1.22.2 on 2024-02-22; Generic ESP32S3 module with Octal-SPIRAM with ESP32S3
  • MicroPython v1.23.0 on 2024-06-02; Generic ESP32S3 module with Octal-SPIRAM with ESP32S3
  • MicroPython v1.23.0 on 2024-06-02; Generic ESP32S3 module with ESP32S3
  • MicroPython v1.24.0-preview 335 gb08ddbba5

Reproduction

I know this is a lot, but the behavior of the issue is hard for me to describe, so I tried writing a short script that can demonstrate the issues I'm having, with multiple tests:

from machine import SPI, Pin, SDCard
import framebuf
import random
import os

# ~~~~~~~~~~~~~~ SETUP: ~~~~~~~~~~~~~~

# Enable TDeck peripherals:
enable = Pin(10, Pin.OUT, value=1)

# spi pins:
sck = Pin(40)
miso = Pin(38)
mosi = Pin(41)

# sdcard select
sdcard_cs = Pin(39)

# display pins
display_cs = Pin(12, Pin.OUT, value=1)
display_dc = Pin(11, Pin.OUT, value=1)
backlight = Pin(42, Pin.OUT, value=1)

# dummy/test image:
fbuf = framebuf.FrameBuffer(bytearray(320*240*2), 320, 240, framebuf.RGB565)


# helpers for the tests below:
def make_display():
    return SPI(1, baudrate=40_000_000, sck=sck, mosi=mosi, miso=miso)

def make_sd():
    return SDCard(slot=2, sck=sck, miso=miso, mosi=mosi, cs=sdcard_cs)

# Display must have already been initialized elsewhere for this simple function to work:
def write_to_display(display, text, deinit=True):
    fbuf.text(
        text,
        random.randint(0,300),
        random.randint(0,230),
        65535,
    )
    display_cs.off()
    display.init()
    display.write(fbuf)
    if deinit:
        display.deinit()
    display_cs.on()


# ~~~~~~~~~~~~~~ TEST0: ~~~~~~~~~~~~~~
def test0():
    """SD mounted after display init."""
    # sd first:
    sd = make_sd()
    display = make_display()

    # If this is the first time, OsError(16):
    # (If the code is run twice, it mounts correctly)
    os.mount(sd, '/sd')
    os.chdir("sd")
    # Display write does nothing:
    write_to_display(display, "testing!")
    # UnicodeError():
    print(os.listdir())
    # REPL may or may not also disconnect.
    

# ~~~~~~~~~~~~~~ TEST1: ~~~~~~~~~~~~~~
def test1():
    """SD read is corrupted when display is used."""
    # display first:
    display = make_display()
    sd = make_sd()

    # SDCard mounts successfully:
    os.mount(sd, '/sd')
    # Display writes successfully:
    write_to_display(display, "First write")
    os.chdir("sd")
    # Display writes successfully:
    write_to_display(display, "Second write")
    # UnicodeError():
    print(os.listdir())
    # REPL may or may not also disconnect.


# ~~~~~~~~~~~~~~ TEST2: ~~~~~~~~~~~~~~
def test2():
    """Display does nothing when not deinitialized."""
    # order does not matter:
    display = make_display()
    sd = make_sd()

    # SDCard mounts successfully:
    os.mount(sd, '/sd')
    # Display does nothing:
    write_to_display(display, "First write", deinit=False)
    os.chdir("sd")
    # Display does nothing:
    write_to_display(display, "Second write", deinit=False)
    # SDCard is read with no issue:
    print(os.listdir())


# ~~~~~~~~~~~~~~ TEST3: ~~~~~~~~~~~~~~
def test3():
    """SD can not be mounted after display deinit."""
    # display first:
    display = make_display()
    sd = make_sd()
    
    # display does nothing:
    write_to_display(display, "Testing!")
    # OSError(16):
    os.mount(sd, '/sd')


# ~~~~~~~~~~~~~~ TEST4: ~~~~~~~~~~~~~~
def test4():
    """SD can not be mounted after display deinit."""
    # sdcard first:
    sd = make_sd()
    display = make_display()
    
    # display writes successfully (usually):
    write_to_display(display, "Testing!")
    # OSError(16):
    os.mount(sd, '/sd')
    

test0()

Expected behaviour

Regardless of difficulty, I would expect it to be somehow possible to use the SDCard and display alongside each other. However, I can not find any approach that makes the behavior stable, and so I think there may be something unexpected happening under the surface.

Observed behaviour

If an SDCard object and an SPI object for the display, exist at the same time, one or both of them always seems to stop working in unexpected ways. The exact issues that pop up depend on the order the objects are created/accessed with.

If I init() and deinit() the display every time I write to it, then:

  • If the SDCard is created before the display:

    • The SDCard can not be mounted.
    • The display may or may not be written to successfully.
  • If the display is created before the SDCard:

    • If the SDCard is mounted before writing to the display:
      • The display can be written to with no issue, throws a UnicodeError() when reading SD contents.
    • If the display is written to before mounting the SDCard:
      • The SDCard can not be mounted (OSError(16))

If I don't deinit() the display after writing to it, then:

  • The SDCard has no issues, but the display never updates.

(Skipping the init() doesn't seem to do anything to this behavior, either.)

Additional Information

I'm using a Lilygo TDeck, which has all of the SPI devices (Specifically, an ST7789 display and a micro-sdcard reader) connected to the same SPI pins.

I did also test the above code using an M5Stack Cardputer (Which is the only other device I have to test this on, and unfortunately does have the same ESP32-S3 controller). And the behaviour seemed to be the same, except the UnicodeError never happens, and instead some garbled file names get printed.

Code of Conduct

Yes, I agree

Keyboard

j / / n
next pair
k / / p
previous pair
1 / / h
show query pane
2 / / l
show candidate pane
c
copy suggested comment
r
toggle reasoning
g i
go to index
?
show this help
esc
close overlays

press ? or esc to close

copied