Pico supports SD cards and FatFS

ChaN's FatFs - Generic FAT Filesystem Module is at the heart of this program. It also includes an SPI SD Card block driver for the Raspberry Pi Pico RP2040 Microcontroller, which is developed from SDBlockDevice from Mbed OS 5. It's packaged as a fully functional project that includes a command line interface, self-tests, and a sample data logging application.

SD Cards on the Pico
https://github.com/carlk3/no-OS-FatFS-SD-SPI-RPi-Pico

Characteristics:

  • Multiple SD Cards are supported.
  • Multiple SPIs are supported.
  • Multiple SD Cards per SPI are supported.
  • Maintains file and directory time stamps using a Real Time Clock.
  • Cyclic Redundancy Check is supported (CRC)
  • Plus, FatFS has a lot of cool features.

Exemplification

Making use of a Debug build: Writing and reading a 0xC0000000 (3,221,225,472) random bytes (3 GiB) file on a SanDisk 32GB card at an SPI baud rate of 12,500,000:
  • Writing time was 4113.8 seconds, and the transfer rate was 764.7 KiB/s.
The act of reading (and verifying)
  • 3396.9 seconds have passed.
  • 926.1 KiB/s transfer rate
I was able to increase the SPI baud rate on a SanDisk Class 4 16 GB card to 20,833,333, which increased the transfer speed proportionally (albeit SDIO would be quicker!).

Requirements:

Formation:

  • I didn't bother with a schematic because the wiring is so straightforward. I simply referenced to the table above and wired the Pico's Pin column to the Transflash's MicroSD 0 column point-to-point.
  • Card Detection is an optional feature. Some SD card sockets aren't compatible with it. Even if the hardware provides it, you may not care if you plan to leave the card in all the time, in which case you can omit it and save an I/O pin.
  • You have the option of using one or both of the Pico's SPIs.
  • Short and direct wires should be used. SPI uses HF radio frequencies to communicate.

Resistors should be pulled up

  • The SPI MISO (DO on SD card, SPIx RX on Pico) is a collector that is open to the public (or tristate). It needs to be hauled up. Pico's internal gpio pull up is inefficient, drawing roughly 56uA or 60k. An external pull-up resistor of roughly 5k to 3.3v is recommended. If you only use one SD card and don't use a high SPI baud rate, you might be able to get by without one.
  • The SPI Slave Select (SS) or Chip Select (CS) line allows one SPI slave on the bus to control several slaves. This is what, among other things, allows the tristate buffer for Data Out (DO). It's advisable to pull CS up before the Pico GPIO is initialised so that it doesn't float. If there are any devices on the bus that haven't been initialised, it's critical to pull it up. You can't let the CS float on the unused one if you have two SD cards on one bus but the firmware only recognises one (see hw config.c).

Firmware

  • Set up the development environment by following the instructions in Getting started with Raspberry Pi Pico.
  • Source code should be installed. git clone --recurse-submodules git@github.com:carlk3/no-OS-FatFS-SD-SPI-RPi-Pico.git no-OS-FatFS
  • Personalize: 
  1. Tailor sd_driver/hw_config.c to match hardware
  2. Customize ff14a/source/ffconf.h as desired
  3. Customize pico_enable_stdio_uart and pico_enable_stdio_usb in CMakeLists.txt as you prefer 
  • Build: 
cd no-OS-FatFS
mkdir build
cd build
cmake ..
make
  • Set up the hardware

Operation: 

  • Connect a terminal. PuTTY or tio work OK. For example:
tio -m ODELBS /dev/ttyACM0
  • To start the CLI, press Enter. You should see something along the lines of:
  > 
  • The help command lists the commands that are available:
setrtc <DD> <MM> <YY> <hh> <mm> <ss>:
Set Real Time Clock
Parameters: new date (DD MM YY) new time in 24-hour format (hh mm ss)
e.g.:setrtc 16 3 21 0 4 0

date:
Print current date and time

lliot <drive#>:
!DESTRUCTIVE! Low Level I/O Driver Test
e.g.: lliot 1

format [<drive#:>]:
Creates an FAT/exFAT volume on the logical drive.
e.g.: format 0:

mount [<drive#:>]:
Register the work area of the volume
e.g.: mount 0:

unmount <drive#:>:
Unregister the work area of the volume

chdrive <drive#:>:
Changes the current directory of the logical drive.
<path> Specifies the directory to be set as current directory.
e.g.: chdrive 1:

getfree [<drive#:>]:
Print the free space on drive

cd <path>:
Changes the current directory of the logical drive.
<path> Specifies the directory to be set as current directory.
e.g.: cd 1:/dir1

mkdir <path>:
Make a new directory.
<path> Specifies the name of the directory to be created.
e.g.: mkdir /dir1

ls:
List directory

cat <filename>:
Type file contents

simple:
Run simple FS tests

big_file_test <pathname> <size in bytes> <seed>:
Writes random data to file <pathname>.
<size in bytes> must be multiple of 512.
e.g.: big_file_test bf 1048576 1
or: big_file_test big3G-3 0xC0000000 3

cdef:
Create Disk and Example Files
Expects card to be already formatted and mounted

start_logger:
Start Data Log Demo

stop_logger:
Stop Data Log Demo

Problem-solving

  • Lowering the SPI baud rate (see hw config.c) is the first thing to do. It will also be easier to employ logic analyzers as a result of this.
  • Switch to a different brand of SD card. Some people are more adept at using the SPI protocol than others. (The SDIO interface is used by most consumer electronics like as cameras and computers.) I've had a lot of success with SanDisk.
  • Tracing: Near the top of most source files are a pair of lines that say:
#define TRACE_PRINTF(fmt, args...) // Disable tracing //#define TRACE_PRINTF printf // Trace with printf
To allow tracing of what's going on in that file, switch the comments.
  • Comidox 1Set USB Logic Analyzer Device Set USB Cable is a logic analyzer that costs less than ten dollars. As long as you don't run the baud rate too high, 24MHz 8CH 24MHz 8 Channel UART IIC SPI Debug for Arduino ARM FPGA M100 Hot and PulseView - sigrok make a wonderful combo for looking at SPI.

Next Step:

data log demo.c contains an example data logging programme. The start logger command may be used to start logger it from the CLI. (Use the stop logger command to terminate it.) It saves the temperature recorded by the RP2040 internal Temperature Sensor in files called /data/2021-03-21/11.csv once per second. Make your own data recording application using this as a starting point!

Use something like: FatFs SPI as a library embedded in another project if you wish to use FatFs SPI as a library embedded in another project.
git submodule add git@github.com:carlk3/no-OS-FatFS-SD-SPI-RPi-Pico.git
or
git submodule add https://github.com/carlk3/no-OS-FatFS-SD-SPI-RPi-Pico.git
You'll need to look in CMakeLists.txt for the library:
add_subdirectory(no-OS-FatFS-SD-SPI-RPi-Pico/FatFs_SPI build)
target_link_libraries(_my_app_ FatFs_SPI)
and #include "ff.h".

Adding More Cards to the Appendix

It's always beneficial to have redundancy when it comes to information storage. SPIs and SD cards can be used in a variety of ways. Putting numerous SD cards on the same SPI bus is one of them, and it costs one (or two) more Pico I/O pins (depending on whether or you care about Card Detect). I'll use this example to demonstrate my point.

Connect a second SD card in parallel to the same SPI, except that it will require a separate GPIO for Card Select/Slave Select (CSn) and another for Card Detect (CD) (optional).
https://github.com/carlk3/no-OS-FatFS-SD-SPI-RPi-Pico
https://github.com/carlk3/no-OS-FatFS-SD-SPI-RPi-Pico

The only new signals are CD1 and CS1, as you can see from the table above. Otherwise, the new card is connected to the first in a parallel configuration.

Firmware:

  • sd_driver/hw_config.c must be edited to add a new instance to static sd_card_t sd_cards[]
  • Edit ff14a/source/ffconf.h. In particular, FF_VOLUMES:
#define FF_VOLUMES		2