adafruit / circuitpython

CircuitPython - a Python implementation for teaching coding with microcontrollers
https://circuitpython.org
Other
4.13k stars 1.22k forks source link

SPI SD Cards don't mount both when on the same SPI bus #6290

Open DanWill7 opened 2 years ago

DanWill7 commented 2 years ago

CircuitPython version

Adafruit CircuitPython 7.2.0 on 2022-17-4; Raspberry Pi Pico with rp2040

Code/REPL

import time
import board, busio, digitalio
import os, storage
from sdcardio import SDCard

spi = busio.SPI(clock=board.GP18, MOSI=board.GP19, MISO=board.GP16)
sdcs1_pin = board.GP6
sdcs2_pin = board.GP7

print("Starting")
sd1 = SDCard(spi, sdcs1_pin)
vfs1 = storage.VfsFat(sd1)
storage.mount(vfs1, "/sd1")
print("SD 1 Mounted")
print(os.listdir("/sd1"))
storage.umount(vfs1)

sd2 = SDCard(spi, sdcs2_pin)
vfs2 = storage.VfsFat(sd2)
storage.mount(vfs2, "/sd2")
print("SD 2 Mounted")
print(os.listdir("/sd2"))

while True:
    print("loop")
    time.sleep(1)

Behavior

Below is the error from the code. When run, only one of the SPI SD Card modules is recognized. You can change which one is mounted by unplugging the power and swapping in the code the CS pins. A few times, it successfully mounted both SD cards, but I cant reproduce that event anymore.

>>> %Run -c $EDITOR_CONTENT
Starting
SD 1 Mounted
[]
Traceback (most recent call last):
  File "<stdin>", line 18, in <module>
OSError: no SD card

Description

-Error with mounting two SPI SD Card modules -MCU is Raspberry Pi Pico

Additional information

No response

anecdata commented 2 years ago

This was discussed and tested at length on Discord. I think it needs someone with two of the Adafruit flash-chip SD Card breakouts to try to replicate. Confirmed that one regular SD Card breakout + one flash-chip SD Card breakout work fine on RP2040 port, but I don't have two flash-chip breakouts to test.

jerryneedell commented 2 years ago

reproduced using 2 SPI SMT SDCard breakout (PID 4899)

Auto-reload is on. Simply save files over USB to run them or enter REPL to disable.

Press any key to enter the REPL. Use CTRL-D to reload.

Adafruit CircuitPython 7.3.0-beta.1-7-g87b3998d6 on 2022-04-18; Raspberry Pi Pico with rp2040
>>> import sdtest
Starting
SD 1 Mounted
[]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "sdtest.py", line 18, in <module>
OSError: no SD card
>>> 
jerryneedell commented 2 years ago

I get the same failure with one SPI SMT breakout and one Micro-SDCard breakout

jerryneedell commented 2 years ago

However -- using 2 MicroSdcard breakouts works fine!


Adafruit CircuitPython 7.3.0-beta.1-7-g87b3998d6 on 2022-04-18; Raspberry Pi Pico with rp2040
>>> import sdtest
Starting
SD 1 Mounted
['.Spotlight-V100', 'EEPROM.DAT', '.Trashes', 'CE5_Support.gcode', 'CE5_FrontPlate.gcode', 'CE5_BackPlate.gcode']
SD 2 Mounted
['.Spotlight-V100', '.fseventsd']
loop
loop
ladyada commented 2 years ago

it coudl be those chips do not properly release the MISO line - it can happen with non-standard components and cannot be fixed in software

anecdata commented 2 years ago

I get the same failure with one SPI SMT breakout and one Micro-SDCard breakout

Interesting. I saw it working with one of each, though for RP2040 I had to update to CP 7.2.5. Perhaps something marginal.

KurtE commented 2 years ago

Sorry, I have not looked at this one yet... I have done similar on Arduino/Teensy stuff. And the first place I would try might include, where you have:

sdcs1_pin = board.GP6
sdcs2_pin = board.GP7

Is to try setting both of them HIGH before your init code is called. I have not played enough with these boards and all of the breakouts to know if they have built-in Pull UP resistors on their Chip select pins.

So often times in Arduino I would add to start of sketch something like: pinMode(sdcs1_pin, OUTPUT); digitalWrite(sdcs1_pin, HIGH); dito for the other pin... And see if that helps.

Or if breadboard, I would hook up external resistors to the CS pins and +3.3v ...

Just a thought

jerryneedell commented 2 years ago

I tried adding 10K pullups to the CS lines, but it did not seem to help -- same failure. Looking at the schematic, they are already present on the board.

KurtE commented 2 years ago

While searching around to see what all I need to do to try to add SDIO support for the MIMXRT boards (Teensy 4.x) I remember reading something about sharing the SPI buss.

Found it: https://docs.circuitpython.org/en/latest/shared-bindings/sdcardio/index.html

If the same SPI bus is shared with other peripherals, it is important that the SD card be initialized before accessing any other peripheral on the bus. Failure to do so can prevent the SD card from being recognized until it is powered off or re-inserted.

Not sure why or if it is still true, but wondered...

DanWill7 commented 2 years ago

While searching around to see what all I need to do to try to add SDIO support for the MIMXRT boards (Teensy 4.x) I remember reading something about sharing the SPI buss.

Found it: https://docs.circuitpython.org/en/latest/shared-bindings/sdcardio/index.html

If the same SPI bus is shared with other peripherals, it is important that the SD card be initialized before accessing any other peripheral on the bus. Failure to do so can prevent the SD card from being recognized until it is powered off or re-inserted.

Not sure why or if it is still true, but wondered...

Are there any work arounds for this?

KurtE commented 2 years ago

Sorry again I don't understand why there would be such a limitation.

But for the heck of it I downloaded the sources of the library, so I could run from sources instead of the compiled version and it does print out some additional information on failures...

Also note: that same warning about sharing the SPI buss is on the Readme file for that library!

Also I get some different results depending on what cards I plug in. For example when I plugged in an 1gb or 8gb card it failed with traceback like:

Traceback (most recent call last):
  File "code.py", line 28, in <module>
  File "/lib/adafruit_sdcard.py", line 100, in __init__
  File "/lib/adafruit_sdcard.py", line 127, in _init_card
  File "/lib/adafruit_sdcard.py", line 181, in _init_card_v2
OSError: timeout waiting for v2 card

Maybe they are not V2 cards...

When I tried with a 32gb card, it did not timeout, but failed in the mount as unsupported operation... Not sure yet if you can mount multiple or not...

When I plugged in 64gb card it failed again...

I have tried to use Logic Analyzer to look at conversations, but the first setup is not allowing me easy access to CS signal... May change or see if I can dig out the SD breakout board.

mjs513 commented 2 years ago

@KurtE Been playing around with different processor and SD Cards. And it seems some SD cards will work and some not. I have been using 3 different SD Cards for testing

  1. Samsung 64GB Ultra
  2. Samsung 32GB EVO
  3. Transcend 8GB premium.
  4. Adafruit SPI Flash SD Card (yep picked one up)

The 64GB worked without an issue, for the 32GB card had to increase the timeout in the SD lib to 400 from 200 and then it worked. The 8GB had a problem with-didn't want to work. The Flash SD Card only worked with certain processors. Here I what I found so far:

Adafruit QT PY RP2040
SPI Flash first card on D0 and SD Card on D1 chained both worked together

T41
SD Card and SPI Flash SD Card worked together.

TMM
2 SD cards are read but NAND SD Card does not work by itself
getting no sd card found

Sparkfun SAMD51 Micromod
Only Card reader on ML Carrier worked with a 64GB Samsung Ultra
Either No SD card found or timeout V2

ESP32S3
only the flash SD Card breakout works.  Getting No SD Card found for the SD cards.

Adafruit STM32F405 express
Only flash SD Card breakout works, Either No SD card found or timeout V2

There is only one set of connections going to the processor board. So don't think its a wiring problem. Whether its a timing or other issue with the SD Library don't know yet.

mjs513 commented 2 years ago

Did a bit of reconfiguring of the STM32F405 so tested the following

  1. Only a SD card reader (Adafruit SDIO/SPI Card Reader) was attached on pin 10 and the STM32F405 was able to read the 64GB card.
  2. attached a SPI SD flash breakout where the SD Card was connected to the Flash SD and then to the STM and only the sd Flash card was able to read. The SD Card reader show "No SD Card"

UPDATE: Got it working when I put the SD Card first then the sd flash breakout

DanWill7 commented 2 years ago

Did a bit of reconfiguring of the STM32F405 so tested the following

  1. Only a SD card reader (Adafruit SDIO/SPI Card Reader) was attached on pin 10 and the STM32F405 was able to read the 64GB card.
  2. attached a SPI SD flash breakout where the SD Card was connected to the Flash SD and then to the STM and only the sd Flash card was able to read. The SD Card reader show "No SD Card"

UPDATE: Got it working when I put the SD Card first then the sd flash breakout

Have you had any luck with two SPI SD flash breakouts working?

mjs513 commented 2 years ago

Have you had any luck with two SPI SD flash breakouts working?

Haven't tried 2 yet. Still have to solder up the second breakout board I got.

KurtE commented 2 years ago

I keep meaning to order some of these, but as I have said before (broken record) I can not order direct from Adafruit... Won't ship to PO or PMB...

Looked at Amazon, but price was considerably higher and delivery slow.... So next options are Digikey/Mouser...

KurtE commented 2 years ago

Note: so far digikey and mouser don't have them and/or in stock... Will check a few others

mjs513 commented 2 years ago

@DanWill7 @KurtE @anecdata

Have you had any luck with two SPI SD flash breakouts working?

So I soldered up another of Flash SD Cards so I am now using 2 of the Flash SD Cards seems like ONLY ONE CAN BE USED AT A TIME. I tried this with 3 separate processors - QTPY RP2040, Teensy 4.1 and a STM32F405. Unfortunately don't have any other Adafruit boards to test with so maybe some else can.

mjs513 commented 2 years ago

All this is a bit of an update. I rewickered the script to trap the error and continue just in case to:

import os
import busio
import digitalio
import board
import storage
import adafruit_sdcard
import time

# This helper function will print the contents of the SD
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) + " bytes"
        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)

SD_CS = board.D0  # setup for M0 Adalogger; change as needed
sdcs2_pin = board.D1

# Connect to the card and mount the filesystem.
spi = busio.SPI(board.SCK, board.MOSI, board.MISO)
cs = digitalio.DigitalInOut(SD_CS)
cs2 = digitalio.DigitalInOut(sdcs2_pin)
print("Files on filesystem:")
print("====================")

print("SPI NAND FLASH DRIVE 1")
try:
    sdcard = adafruit_sdcard.SDCard(spi, cs)
    vfs = storage.VfsFat(sdcard)
    storage.mount(vfs, "/sd")
    print_directory("/sd")
except Exception as e:
    print("Error sd card 1:", e)
    print("continuing")

print("\nSPI NAND FLASH DRIVE 2")
try:
    sdcard2 = adafruit_sdcard.SDCard(spi, cs2)
    vfs2 = storage.VfsFat(sdcard2)
    storage.mount(vfs2,"/sd2")
    print_directory("/sd2")
except Exception as e:
    print("Error sd card 2:", e)
    print("continuing")

Now we can clearly see that only one Flash is found.

 code.py output:
Files on filesystem:
====================
SPI NAND FLASH DRIVE 1

SPI NAND FLASH DRIVE 2
Error sd card 2: no SD card
continuing
KurtE commented 2 years ago

I wonder if it would be worth it to add some instrumentation in the SD Code base to get more clues on where it is failing...

But for now maybe, just note that it does not appear to work, with multiple devices.

bablokb commented 1 year ago

I have the same problem with a simple sd-card reader and a spi-display. I can use both individually, but once I loaded the storage/adafruit_sdcard stuff, the display won't work. I confirmed that the cs-pin of the sd-card reader is high before trying to use the display.