Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sdcard in core #2863

Merged
merged 8 commits into from Jun 29, 2020
Merged

Sdcard in core #2863

merged 8 commits into from Jun 29, 2020

Conversation

jepler
Copy link
Member

@jepler jepler commented May 6, 2020

This pull request adds sdcardio.SDCard and, for select atmel-sam boards, sdio.SDCard.

sdcardio.SDCard is nearly, but not quite, compatible with adafruit_sdcard.SDCard: It takes a microcontroller.Pin for the chip select (cs) line, not a digitalio.DigitalInOut object, because this simplifies object lifetime and may help us to someday let vfs mounts survive soft-reset. It also defaults to a higher baudrate, 8MHz instead of 1.32MHz.

sdcardio benchmarks vary from card to card, but on one 4GB card, I measured an increase in read rates from 583 kB/s to 838.2kB/s, an increase of about 40%. Write rates remain very low, just 4kB/s(!) with adafruit_sdcard and sdcardio.

All sdcardio testing was on a PyGamer with built in SD card slot. Three SD cards were tested (4GB Sandisk, 8GB Sandisk, 64GB Samsung). Some lower capacity SD cards are on order and I'll verify they all work, or if they don't whether they work under adafruit_sdcard.

sdcardio is enabled on all "full-build"s except M0, PCA10100, and litex, for reasons outlined in the individual commits.

sdioio implements an SD card interface using the SDIO bus. This is enabled and tested on the Microchip SAME54 Xplained Pro board and is also enabled on the Grand Central. The relevant pins are on headers of the Grand Central M4 Express, but (likely due to dodgy wiring) did not work in my testing.

Known problems:

  • If no card is detected, sdioio.SDCard hangs at initialization
  • sdcardio.SDCard misidentifies the capacity of a particular 64GB card I have for testing, same as adafruit_sdcard

We made the decision to deprioritize the stm32f405 feather support for SDIO SD cards. This work is not finished and has not been renamed to suit the latest decisions, and so it have been removed from this PR. See https://github.com/jepler/circuitpython/tree/sdio-stm32-broken-rename -- We will get back to this at some point, but we would also love to see a community member pick up the work. Two main things remain to be done: Follow the naming convention of sdioio and finish the pin logic in the constructor.

@jepler jepler force-pushed the sdcard-in-core branch 2 times, most recently from 1d2fc3f to a2becfa Compare May 8, 2020 19:22
@jepler jepler marked this pull request as ready for review May 9, 2020 15:18
@tannewt tannewt requested a review from dhalbert May 11, 2020 22:59
@tannewt
Copy link
Member

tannewt commented May 15, 2020

@dhalbert is this review on your radar?

@tannewt
Copy link
Member

tannewt commented May 15, 2020

For now, let's call this _sdcardio just in the top level so that we can evolve the API as SDIO support is added. Internally the names can stay the same.

@dhalbert
Copy link
Collaborator

@tannewt Sorry, I looked for this the other day, and it seemed like a number of changes were pending, so I waited.

Copy link
Collaborator

@jerryneedell jerryneedell left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK -- I found the commit fixing the doc example -- thanks !

shared-bindings/sdcardio/SDCard.c Outdated Show resolved Hide resolved
Copy link
Collaborator

@dhalbert dhalbert left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I only had stylistic comments. It looks good but I have not tested it. Are we going to rewrite adafruit_sdcard to be a thin wrapper around this for now, or just deprecate it?

ports/litex/mpconfigport.mk Outdated Show resolved Hide resolved
ports/nrf/boards/pca10100/mpconfigboard.mk Outdated Show resolved Hide resolved
shared-bindings/sdcardio/SDCard.c Outdated Show resolved Hide resolved
shared-bindings/sdcardio/SDCard.c Outdated Show resolved Hide resolved
shared-bindings/sdcardio/SDCard.c Outdated Show resolved Hide resolved
shared-bindings/sdcardio/__init__.c Show resolved Hide resolved
shared-module/sdcardio/SDCard.c Outdated Show resolved Hide resolved
shared-module/sdcardio/SDCard.c Outdated Show resolved Hide resolved
shared-module/sdcardio/SDCard.c Show resolved Hide resolved
shared-module/sdcardio/SDCard.c Outdated Show resolved Hide resolved
@jepler
Copy link
Member Author

jepler commented May 15, 2020

Thanks @dhalbert I'll take your comments into account when I revise the PR to rename it as _sdcardio.

@jepler
Copy link
Member Author

jepler commented May 15, 2020

I think adafruit_sdcard will still be used for M0 devices where we don't have space for sdcardio in flash.

adafruit_sdcard could check for the existence of _sdcardio and use it instead if it's present. So there could be one version of various programs for both M0 and M4 boards.

@jerryneedell
Copy link
Collaborator

jerryneedell commented May 19, 2020

tested this PR on a grand_central_m4_express
It works!

Press any key to enter the REPL. Use CTRL-D to reload.
Adafruit CircuitPython 5.3.0-187-g82024d078 on 2020-05-19; Adafruit Grand Central M4 Express with samd51p20
>>> import sdcardio_test
['hello.py', 'images']
>>> 

I had to make a few changes to the example since the Grand Central M4 does not use the statndar SPI bus for the SD Card. here is the example I ran

import adafruit_sdcard
import busio
import sdcardio
import digitalio
import board
import storage
import sys
import os

# Connect to the card and mount the filesystem.
spi = busio.SPI(board.SD_SCK, board.SD_MOSI, board.SD_MISO)
sdcard = sdcardio.SDCard(spi, board.SD_CS)
vfs = storage.VfsFat(sdcard)
storage.mount(vfs, "/sd")
print(os.listdir('/sd'))

took it one step further and actually executed a python script (hello.py) from the sdcard

Press any key to enter the REPL. Use CTRL-D to reload.
Adafruit CircuitPython 5.3.0-187-g82024d078 on 2020-05-19; Adafruit Grand Central M4 Express with samd51p20
>>> 
>>> 
>>> import sdcardio_lib
>>> import hello
Howdy
>>> 

here is the example sdcardio_lib.py

import adafruit_sdcard
import busio
import sdcardio
import digitalio
import board
import storage
import sys
import os

# Connect to the card and mount the filesystem.
spi = busio.SPI(board.SD_SCK, board.SD_MOSI, board.SD_MISO)
sdcard = sdcardio.SDCard(spi, board.SD_CS)
vfs = storage.VfsFat(sdcard)
storage.mount(vfs, "/sd")
sys.path.append("/sd")
sys.path.append("/sd/lib")

oops _I noticed that I was still importing adafruit_sdcard -- It still works when I remove it!

jerryneedell@jerryneedell-ubuntu-macmini:~/projects/grand_central$ cat sdcardio_test.py 
import busio
import sdcardio
import board
import storage
import sys
import os

# Connect to the card and mount the filesystem.
spi = busio.SPI(board.SD_SCK, board.SD_MOSI, board.SD_MISO)
sdcard = sdcardio.SDCard(spi, board.SD_CS)
vfs = storage.VfsFat(sdcard)
storage.mount(vfs, "/sd")
print(os.listdir('/sd'))

and

jerryneedell@jerryneedell-ubuntu-macmini:~/projects/grand_central$ cat sdcardio_lib.py 
import busio
import sdcardio
import board
import storage
import sys
import os

# Connect to the card and mount the filesystem.
spi = busio.SPI(board.SD_SCK, board.SD_MOSI, board.SD_MISO)
sdcard = sdcardio.SDCard(spi, board.SD_CS)
vfs = storage.VfsFat(sdcard)
storage.mount(vfs, "/sd")
sys.path.append("/sd")
sys.path.append("/sd/lib")

@dhalbert
Copy link
Collaborator

dhalbert commented Jun 1, 2020

@jepler There are still some unresolved comments above (alphabetization and "not bitbangio.SPI")

@jepler jepler marked this pull request as draft June 1, 2020 19:48
@jepler
Copy link
Member Author

jepler commented Jun 2, 2020

This has been updated with SDIO for STM32F405 Feather.

@jerryneedell
Copy link
Collaborator

Tested SDIOCard example on feather_stm32f405_express -- worked fine!
Also tested adding /sd to path and executed simple script from the sdcard.

Copy link
Member Author

@jepler jepler left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note for myself: https://github.com/avrxml/asf/blame/61c7353e0183bbd0615db1d0a3144cbdcd09983a/common/components/memory/sd_mmc/sd_mmc.c

Also, this PR presently reverts two submodules to an intended ref. oof.

ports/stm/Makefile Outdated Show resolved Hide resolved
ports/stm/supervisor/port.c Outdated Show resolved Hide resolved
py/circuitpy_mpconfig.mk Outdated Show resolved Hide resolved
@tannewt
Copy link
Member

tannewt commented Jun 3, 2020

I think it'd be better to separate the bus from the SDCard APIs here.

# Connect to the card and mount the filesystem.
bus = busio.SPI(board.SD_SCK, board.SD_MOSI, board.SD_MISO)
device = adafruit_bus_device.SPIDevice(bus, board.SD_CS) # Also takes frequency, polarity and phase.
# For SDIO
# device = sdioio.SDIO(clock=board.SDIO_CLOCK, command=board.SDIO_COMMAND, data=(board.SDIO_DATA,), frequency=25000000)
sdcard = sdcardio.SDCard(device)

Copy link
Collaborator

@hierophect hierophect left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a couple comments about the Systick and peripherals structures. I'm going to take a closer look at HAL_GetTick and try to get a handle on what's going on with the low power code.

ports/stm/common-hal/_sdcardio/SDIOSDCard.c Outdated Show resolved Hide resolved
ports/stm/common-hal/_sdcardio/SDIOSDCard.c Outdated Show resolved Hide resolved
ports/stm/supervisor/port.c Outdated Show resolved Hide resolved
@tannewt tannewt changed the base branch from master to main June 9, 2020 20:06
@jepler jepler force-pushed the sdcard-in-core branch 4 times, most recently from 52e6ec5 to 7499e1c Compare June 25, 2020 15:14
@jepler
Copy link
Member Author

jepler commented Jun 25, 2020

This has grown and is really multiple different topics. We need to split it up into multiple PRs. Our priority list becomes:

  1. SPI SD card in core, supporting all platforms
  2. SAM D5x/E5x SDIO
  3. STM SDIO

(that's not to say we wouldn't love someone to pick up #3 before I get a chance to! It's still the only reasonable way to use the SD card on the STM32F405 Feather. The main thing that needs completion on STM32F405 is handling of pin assignments, instead of ignoring them as now)

We also need to nail down what the API is going to look like, to avoid more renames and incompatible changes if possible. We have discussed this informally a number of times, but I'd like to get to an official decision.

  1. How many modules, 1 or 2? How are they named? Suggestion: sdcardio for SPI interface SD cards and sdioio (for SDIO interface) Conclusion: 2 modules
  2. Are the module names underscored (_sdcardio) or not (sdcardio)? My preference: No underscore Conclusion: No underscore
  3. Does the SPI interface take (spi: busio.SPI, cs: microcontroller.Pin) or (bus: adafruit_busdevice.spi_device.SPIDevice)? My preference: (spi, cs). One reason: we require that the SPI bus is a real hardware SPI bus, and that the CS is a real physical pin, while SPIDevice requires no such things. Conclusion: This is a good trade-off.

If you take my suggestions/preferences, this leads to the following code snippets for mounting SD storage, depending on interface:

sd = sdioio.SDCard(clock=board.SDIO_CLOCK, command=board.SDIO_COMMAND, data=board.SDIO_DATA)
vfs = storage.VfsFat(sd)
storage.mount(vfs, "/sd")

and

sd = sdcardio.SDCard(spi=board.SPI(), cs=board.SD_CS)
vfs = storage.VfsFat(sd)
storage.mount(vfs, "/sd")

We are going to do priorities 1 and 2 in this PR and push #3 to a separate PR or issue.

(comment updated based on discussion with @tannewt via discord)

@jepler
Copy link
Member Author

jepler commented Jun 25, 2020

@tannewt @dhalbert your comment on the above would be very welcome.

@jepler jepler force-pushed the sdcard-in-core branch 2 times, most recently from 46096e6 to 28b1d0b Compare June 26, 2020 16:24
@jepler jepler marked this pull request as ready for review June 26, 2020 16:25
Testing performed: That a card is successfully mounted on Pygamer with
the built in SD card slot

This module is enabled for most FULL_BUILD boards, but is disabled for
samd21 ("M0"), litex, and pca10100 for various reasons.
This will ultimately be used by SDIO, where a variable length list
of data lines is called for.
There is no implementation yet.
@jepler
Copy link
Member Author

jepler commented Jun 26, 2020

@tannewt @dhalbert I think this is ready for another round of review. The initial description of the PR has been heavily updated to reflect the current state of this branch.

@jepler jepler requested a review from tannewt June 26, 2020 16:56
Copy link
Member

@tannewt tannewt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A couple minor things.

ports/atmel-samd/common-hal/sdioio/SDCard.c Outdated Show resolved Hide resolved
shared-bindings/sdcardio/SDCard.c Outdated Show resolved Hide resolved
shared-bindings/sdioio/SDCard.c Outdated Show resolved Hide resolved
@jepler jepler requested a review from tannewt June 29, 2020 13:08
@jepler jepler dismissed stale reviews from tannewt and dhalbert June 29, 2020 13:10

I believe I've addressed all your requested changes

Copy link
Member

@tannewt tannewt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for this! Folks will be excited for the speedups!

@tannewt tannewt merged commit 111f7dd into adafruit:main Jun 29, 2020
@jepler jepler deleted the sdcard-in-core branch November 3, 2021 21:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants