micropython / micropython

MicroPython - a lean and efficient Python implementation for microcontrollers and constrained systems
https://micropython.org
Other
19.02k stars 7.62k forks source link

SDCard not supported for ESP32C3 #12447

Open specternecter opened 11 months ago

specternecter commented 11 months ago

I have a custom ESP32C3 board that has an SD Card on it. I can easily run SD Card functions in Arduino with it but when I put micropython on it using the latest release, SDCard isn't even found when you try to call it. It's not my first time compiling my own board though so went into ports/esp32/boards/ESP32_GENERIC_C3/mpconfigboard.h (Using v5.1 of esp-idf and a current copy of this repository), changed #define MICROPY_HW_ENABLE_SDCARD (0) to #define MICROPY_HW_ENABLE_SDCARD (1) and then changed ports/esp32/machine_sdcard.c to the proper pins of sck=4 miso=5 and mosi=6 (also cs=1 in my case). I get the following errors...

/home/brad/esp-idf/micropython/ports/esp32/machine_sdcard.c:124:20: error: 'SPI3_HOST' undeclared here (not in a function); did you mean 'SPI2_HOST'? 124 | .host_id = SPI3_HOST, | ^~~~~ | SPI2_HOST /home/brad/esp-idf/micropython/ports/esp32/machine_sdcard.c: In function 'machine_sdcard_make_new': /home/brad/esp-idf/micropython/ports/esp32/machine_sdcard.c:238:35: error: implicit declaration of function 'SDMMC_HOST_DEFAULT'; did you mean 'SDSPI_HOST_DEFAULT'? [-Werror=implicit-function-declaration] 238 | sdmmc_host_t _temp_host = SDMMC_HOST_DEFAULT(); | ^~~~~~ | SDSPI_HOST_DEFAULT /home/brad/esp-idf/micropython/ports/esp32/machine_sdcard.c:238:35: error: invalid initializer /home/brad/esp-idf/micropython/ports/esp32/machine_sdcard.c:295:9: error: unknown type name 'sdmmc_slot_config_t' 295 | sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT(); | ^~~~~~~ /home/brad/esp-idf/micropython/ports/esp32/machine_sdcard.c:295:43: error: implicit declaration of function 'SDMMC_SLOT_CONFIG_DEFAULT'; did you mean 'SDSPI_DEVICE_CONFIG_DEFAULT'? [-Werror=implicit-function-declaration] 295 | sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT(); | ^~~~~~~~~ | SDSPI_DEVICE_CONFIG_DEFAULT /home/brad/esp-idf/micropython/ports/esp32/machine_sdcard.c:136:11: error: request for member 'gpio_cd' in something not a structure or union 136 | config.pin_var = machine_pin_get_id(arg_vals[arg_id].u_obj) | ^ /home/brad/esp-idf/micropython/ports/esp32/machine_sdcard.c:301:9: note: in expansion of macro 'SET_CONFIG_PIN' 301 | SET_CONFIG_PIN(slot_config, gpio_cd, ARG_cd); | ^~~~~~ /home/brad/esp-idf/micropython/ports/esp32/machine_sdcard.c:136:11: error: request for member 'gpio_wp' in something not a structure or union 136 | config.pin_var = machine_pin_get_id(arg_vals[arg_id].u_obj) | ^ /home/brad/esp-idf/micropython/ports/esp32/machine_sdcard.c:302:9: note: in expansion of macro 'SET_CONFIG_PIN' 302 | SET_CONFIG_PIN(slot_config, gpio_wp, ARG_wp); | ^~~~~~ /home/brad/esp-idf/micropython/ports/esp32/machine_sdcard.c:306:24: error: request for member 'width' in something not a structure or union 306 | slot_config.width = width; | ^ /home/brad/esp-idf/micropython/ports/esp32/machine_sdcard.c:312:23: error: implicit declaration of function 'sdmmc_host_init_slot' [-Werror=implicit-function-declaration] 312 | check_esp_err(sdmmc_host_init_slot(self->host.slot, &slot_config)); | ^~~~~~~~ cc1: some warnings being treated as errors ninja: build stopped: subcommand failed. ninja failed with exit code 1, output of the command is in the /home/brad/esp-idf/micropython/ports/esp32/build-ESP32_GENERIC_C3/log/idf_py_stderr_output_1718238 and /home/brad/esp-idf/micropython/ports/esp32/build-ESP32_GENERIC_C3/log/idf_py_stdout_output_1718238 -e See https://github.com/micropython/micropython/wiki/Build-Troubleshooting make: *** [Makefile:62: all] Error 1

Like I said, SD works perfectly fine in Arduino so I know there's no hardware issue or anything like that because I know I'm calling the proper pins. When I change things back to #define MICROPY_HW_ENABLE_SDCARD (0) everything compiles fine, but obviously there's no way to use an sd card without it set to 1. It's also obvious there are no definitions in machine_sdcard.c to support the ESP32C3, but I don't know how to fix it aside from changing to the necessary SPI pins.

jimmo commented 11 months ago

@specternecter The machine.SDCard bindings for the ESP32 port are written in such a way that they expect the device to support both MMC and SD. The C3 doesn't support MMC (see https://docs.espressif.com/projects/esp-idf/en/latest/esp32c3/api-reference/storage/sdmmc.html#_CPPv415sdmmc_card_initPK12sdmmc_host_tP12sdmmc_card_t).

It would be relatively straightforward to conditionally remove the MMC bits from esp32/machine_sdcard.c when compiling for C3. But because it's never been enabled, esp32/machine_sdcard.c also hasn't had other tweaks put in place for C3 support like which SPI peripheral to use, pins, etc (i.e. it's only been set up for ESP32/ESP32S2/ESP32S3). That also shouldn't be too difficult.

In the meantime I suggest using the pure-python sdcard driver which you can install from micropython-lib which works on all ports (even with SoftSPI). https://github.com/micropython/micropython-lib/tree/master/micropython/drivers/storage/sdcard

specternecter commented 11 months ago

Thank you, this is very helpful

Tomblarom commented 6 months ago

hey @specternecter, have you figured out another way to use SD-Card with ESP32-C3?

specternecter commented 6 months ago

Like many things with the C3, sd card operations are a little finicky. This is a modified version of sdcard.py that is probably the best it's gonna get. Upload it to your board and then you can see how my custom boot file handles sd operations.

specternecter commented 6 months ago

c3sd.zip

Sorry, I didn't realize you can't upload python files unless they're zipped. I zipped them on android so if you're using windows you'll probably have to use 7zip to unzip it properly.

specternecter commented 6 months ago

Oh and you may have to use "import sdcard". That's probably not in the boot file because these files are from my own compiled version of micropython with sdcard.py frozen into it.

Tomblarom commented 6 months ago

Will test it, just now! Thanks a lot! :)

Tomblarom commented 6 months ago

I got ImportError: no module named 'ledColor', but I can import it like this. :)

specternecter commented 6 months ago

No problem. Let me know how it goes

specternecter commented 6 months ago

Oh yeah that's for a neopixel and you can just comment those out. The sd card portions of that boot file are how you can do those operations. That boot file is checking for an sd card to see whether to run the file system from flash or sd card. If an sd card is detected it's actually writing default files. I can take a look and see if I can explain it better

Tomblarom commented 6 months ago

I just discovered, that I don't have an SPI on my devboard. It's directly wired using CMD, CLK, D0, D1, ...

specternecter commented 6 months ago

You can flash my custom version if you want to make it easier but you must use the native usb port. This board doesn't use the UART port. But that will use the sd card for all files if it's present. DDC3_microPython-8bin_0603_074724.zip

Mounting the sd card goes like this: `try: os.mount(sd, '/sd') except:

retry

    time.sleep(0.25)
    try:
        os.mount(sd, '/sd')
    except:
        useInternal = True
        imReason = 'Failed to Mount SD Card'`
specternecter commented 6 months ago

Oh yeah you may not be able to use my version I provided.

But this is how sd is set up: spi = SPI(1, baudrate=10000000, polarity=0, phase=0, sck=Pin(4), mosi=Pin(6), miso=Pin(5)) sd = None

You should be able to just change the pins

Tomblarom commented 6 months ago

I flashed and getting the following endlessly spamming into the console:

...
invalid header: 0xffffffff
invalid header: 0xffffffff
invalid header: 0xffffffff
invalid header: 0xffESP-ROM:esp32c3-api1-20210207
Build:Feb  7 2021
rst:0x7 (TG0WDT_SYS_RST),boot:0x8 (SPI_FAST_FLASH_BOOT)
Saved PC:0x40053f88
invalid header: 0xffffffff
invalid header: 0xffffffff
invalid header: 0xffffffff
...
specternecter commented 6 months ago

Erase the flash, then reflash to 0x0

specternecter commented 6 months ago

But if your sd card pins don't match what I listed above, the version I provided won't work

Tomblarom commented 6 months ago

esptool --chip esp32c3 --port COM4 --baud 460800 write_flash -z 0x0 DDC3_microPython-8.bin flashed, but I'm getting AttributeError: 'NoneType' object has no attribute 'readblocks' when trying your os.mount(sd, '/sd') code.

Maybe Arduino-based is easier to implement 😅

specternecter commented 6 months ago

That looks like the pins don't match what the boot file is defining as the sd card pins

Tomblarom commented 6 months ago

Yes my pinout is different: CMD=GPIO4, CLK=GPIO5, D0=GPIO6, D3=GPIO7..

specternecter commented 6 months ago

Since you can't change them, that boot file should work in the standard version of micropython. Just change the pin numbers accordingly and comment out anything you see that says ledColor.

specternecter commented 6 months ago

I could compile a version to match your pins but it would be later tonight before I could get to it

specternecter commented 6 months ago

As for the boot file, you probably don't want to actually run that unless you're actually using my version. It's more for an example to see how I'm mounting and writing to the sd card

Tomblarom commented 6 months ago

Yeah will revert to ESP32_GENERIC_C3-20240222-v1.22.2.bin. But since I'm not utilizing SPI on my devboard how is it supposed to be compatible with your sdcard.py?

specternecter commented 6 months ago

As for whether arduino is easier to implement... yeah it actually is, especially if you're not that familiar with micropython. Micropython is far easier to develop with though because there's no waiting for compilation just to find there's an error 30 times until you figure it out

specternecter commented 6 months ago

Where you see spi toward the beginning of the boot file, change those pins

specternecter commented 6 months ago

I'm pretty sure all spi in micropython is software spi if that's what you mean. So it should run on any pins you set (except a few that would conflict with other hardware). Spi is a requirement for sd card though. If your dev board put the sd card on those pins, spi can work on them.

Tomblarom commented 5 months ago

Yes I wanted to use MicroPython for ease of use, rather than developing my own solution in order to use it in MicroPython :D Will try directly with ESP-IDF example: https://github.com/espressif/esp-idf/tree/master/examples/storage/sd_card/sdspi

robert-hh commented 5 months ago

machine.SPI is usually hardware SPI, machine.SoftSPI is (guess what) Software SPI. The assignment of Pins to hardware SPI signals is port-specific. The ESP32 allows to assign almost every Pin to any hardware SPI signal. So I see not reason why the SDCARD driver should not run with the generic firmware. You have to create a SPI object with the proper pins and choose a Pin for CS. That's all.

specternecter commented 5 months ago

Yeah implementing new things in micropython can be difficult and confusing. The reason I compiled my own version of micropython was specifically because sd card wasn't supported by default and I wanted people to easily be able to flip between arduino and micropython. I also made my own arduino core because the standard core for the c3 is absolutely riddled with bugs and the people that are in charge of that would much rather steer you around the bugs rather than fixing them or even accepting a fix. That's why I used the true spi pins when i designed that board. That's what arduino wants if you want things to work smoothly with minimal effort. If you have too much trouble and really want to use micropython, come back and I'll compile a version that matches the pins of your board. It would literally only take me a couple minutes but I won't have access to the computer that can run that until later tonight

robert-hh commented 5 months ago

So I grabbed a simple generic ESP32_C3 board (2$ from Ali), a passive SD-Card plug, wired it up to that board at pins 5 to 8 and copied sdcard.py to the board. Code, typed at the REPL prompt

>>> from machine import SPI, Pin
>>> import os
>>> import sdcard
>>> spi=SPI(1, miso=5, mosi=6, sck=7)
>>> sd=sdcard.SDCard(spi, Pin(8))
>>> os.mount(sd, "/sd")
>>> os.listdir("/sd")
['NB1-41019.dup', 'updater.elf', 'upgdiff_33080-to-41019.dup', 'upgdiff_39529-to-41019.dup', 'upgdiff_40343-to-41019.dup', 'upgdiff_41065-to-41019.dup', 'main.py', 'noboot.py', 'LOST.DIR', '.android_secure', 'Android', 'messages.db', 'NB1-46262.dup', 'vfstest.py', 'sdcard_stress_test.py', 'test_file.txt', 'boot.py', 'mount.py', 'looptest.py', 'rats.txt', '.Trash-1000', 'rats1.txt', 'test01.txt', 'test', 't_read.py', 'btest']
>>> 

The pins I used are not special. Note that when creating the sd object a SD card has to be present.

jonnor commented 16 hours ago

Problem does not seem to be reproducible. Proposing to close issue.