Skip to content

Commit

Permalink
Merge pull request #9 from carlk3/dev
Browse files Browse the repository at this point in the history
Update PlatformIO examples
  • Loading branch information
carlk3 authored Oct 10, 2023
2 parents 5ede7f8 + 26e0a34 commit a840af6
Show file tree
Hide file tree
Showing 36 changed files with 2,583 additions and 780 deletions.
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,27 @@ It is possible to put more than one card on an SDIO bus (each card has an addres
One strategy: use SDIO for cache and SPI for backing store.
A similar strategy that I have used: SDIO for fast, interactive use, and SPI to offload data.

## Notes about FreeRTOS
This library is not specifically designed for use with FreeRTOS.
For use with FreeRTOS, I suggest you consider [FreeRTOS-FAT-CLI-for-RPi-Pico](https://github.com/carlk3/FreeRTOS-FAT-CLI-for-RPi-Pico) instead. That implementation is designed from the ground up for FreeRTOS.

While FatFS has some support for “re-entrancy” or thread safety (where "thread" == "task", in FreeRTOS terminology), it is limited to operations such as:

- f_read
- f_write
- f_sync
- f_close
- f_lseek
- f_closedir
- f_readdir
- f_truncate

There does not appear to be sufficient FAT and directory locking in FatFS to make operations like f_mkdir, f_chdir and f_getcwd thread safe. If your application has a static directory tree, it should be OK in a multi-tasking application with FatFS. Otherwise, you probably need to add some additional locking.

Then, there are the facilities used for mutual exclusion and various ways of waiting (delay, wait for interrupt, etc.). This library uses the Pico SDK facilities (which are oriented towards multi-processing on the two cores), but FreeRTOS-FAT-CLI-for-RPi-Pico uses the FreeRTOS facilities, which put the waiting task into a Blocked state, allowing other, Ready tasks to run.

FreeRTOS-FAT-CLI-for-RPi-Pico is designed to maximize parallelism. So, if you have two cores and multiple SD card buses (SPI or SDIO), multiple FreeRTOS tasks can keep them all busy simultaneously.

## Hardware
### My boards
* [Pico SD Card Development Board](https://forums.raspberrypi.com/viewtopic.php?p=2123146#p2123146)
Expand Down
13 changes: 5 additions & 8 deletions examples/PlatformIO/bench2/platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ platform = https://github.com/maxgerhardt/platform-raspberrypi.git
board = pico
framework = arduino
board_build.core = earlephilhower
debug_tool = picoprobe
upload_protocol = picoprobe
monitor_port = COM4
; debug_tool = picoprobe
; upload_protocol = picoprobe
monitor_port = COM8
monitor_speed = 115200

build_type = release
Expand All @@ -37,12 +37,9 @@ build_flags =
; carlk3/no-OS-FatFS-SD-SPI-RPi-Pico@^1.0.2

; Get the latest straight from github:
; lib_deps =
; https://github.com/carlk3/no-OS-FatFS-SD-SPI-RPi-Pico.git#sdio

; lib_deps = https://github.com/carlk3/no-OS-FatFS-SD-SDIO-SPI-RPi-Pico.git
; Use local copy:
lib_deps =
no-OS-FatFS-SD-SPI-RPi-Pico.dev_sdio
lib_deps = no-OS-FatFS-SD-SDIO-SPI-RPi-Pico
lib_extra_dirs = ../../../..

; lib_ldf_mode = deep+
195 changes: 99 additions & 96 deletions examples/PlatformIO/bench2/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
using namespace FatFsNs;

/* Infrastructure*/
#if 1
// This implementation has the advantage that it works for
// printfs elsewhere in the system; e.g., in an assert
// somewhere in the runtime.
Expand All @@ -28,10 +27,6 @@ extern "C" int printf(const char* __restrict format, ...) {
extern "C" int puts(const char* s) {
return Serial1.write(s);
}
#else
#define printf Serial1.printf
#define puts Serial1.println
#endif

#define error(s) \
{ \
Expand Down Expand Up @@ -70,28 +65,6 @@ static const uint8_t READ_COUNT = 2;
// static const uint32_t FILE_SIZE = 1000000UL * FILE_SIZE_MB;
static const uint32_t FILE_SIZE = (1024 * 1024 * FILE_SIZE_MiB);

static void cidDmp(SdCard* SdCard_p) {
cid_t cid;
if (!SdCard_p->readCID(&cid)) {
error("readCID failed");
}
printf("\nManufacturer ID: ");
printf("0x%x\n", cid.mid);
printf("OEM ID: ");
printf("%c%c\n", cid.oid[0], cid.oid[1]);
printf("Product: ");
for (uint8_t i = 0; i < 5; i++) {
printf("%c", cid.pnm[i]);
}
printf("\nRevision: ");
printf("%d.%d\n", CID_prvN(&cid), CID_prvM(&cid));
printf("Serial number: ");
printf("0x%lx\n", CID_psn(&cid));
printf("Manufacturing date: ");
printf("%d/%d\n", CID_mdtMonth(&cid), CID_mdtYear(&cid));
printf("\n");
}

// First (if s is not NULL and *s is not a null byte ('\0')) the argument string s is printed,
// followed by a colon and a blank. Then the FRESULT error message and a new-line.
static void chk_result(const char* s, FRESULT fr) {
Expand All @@ -115,63 +88,90 @@ void setup() {

/*
This example assumes the following wiring for SD card 0:
| signal | SPI1 | GPIO | card | Description |
| ------ | ---- | ---- | ---- | ---------------------- |
| MISO | RX | 12 | DO | Master In, Slave Out |
| CS0 | CSn | 09 | CS | Slave (or Chip) Select |
| SCK | SCK | 14 | SCLK | SPI clock |
| MOSI | TX | 15 | DI | Master Out, Slave In |
| CD | | 13 | DET | Card Detect |
| GPIO | Function | SD Card | SPI0 |
| ---- | -------------------------------- | ------- | -------- |
| GP2 | SCK | CLK | SPI0_SCK |
| GP3 | MOSI (COPI or Peripheral's SDI) | CMD/DI | SPI0_TX |
| GP4 | MISO (CIPO or Peripheral's SDO) | D0/DO | SPI0_RX |
| GP7 | SS (CS) | D3/CS | |
| GP9 | Card Detect | DET | |
This example assumes the following wiring for SD card 1:
| GPIO | card | Function |
| ---- | ---- | ----------- |
| 16 | DET | Card Detect |
| 17 | CLK | SDIO_CLK |
| 18 | CMD | SDIO_CMD |
| 19 | DAT0 | SDIO_D0 |
| 20 | DAT1 | SDIO_D1 |
| 21 | DAT2 | SDIO_D2 |
| 22 | DAT3 | SDIO_D3 |
| GPIO | SD Card |
| ---- | ------- |
| GP16 | CLK |
| GP17 | CMD |
| GP18 | D0 |
| GP19 | D1 |
| GP20 | D2 |
| GP21 | D3 |
| GP22 | DET |
*/

/* Hardware Configuration of SPI object */
static spi_t spi = {
.hw_inst = spi0, // RP2040 SPI component
.miso_gpio = 4,
.mosi_gpio = 3,
.sck_gpio = 2, // GPIO number (not Pico pin number)
.baud_rate = 12 * 1000 * 1000 // Actual frequency: 10416666.
};

static sd_spi_if_t spi_if = {
.spi = &spi, // Pointer to the SPI driving this card
.ss_gpio = 7 // The SPI slave select GPIO for this SD card
};

static sd_sdio_if_t sdio_if = {
/*
Pins CLK_gpio, D1_gpio, D2_gpio, and D3_gpio are at offsets from pin D0_gpio.
The offsets are determined by sd_driver\SDIO\rp2040_sdio.pio.
CLK_gpio = (D0_gpio + SDIO_CLK_PIN_D0_OFFSET) % 32;
As of this writing, SDIO_CLK_PIN_D0_OFFSET is 30,
which is -2 in mod32 arithmetic, so:
CLK_gpio = D0_gpio -2.
D1_gpio = D0_gpio + 1;
D2_gpio = D0_gpio + 2;
D3_gpio = D0_gpio + 3;
*/
.CMD_gpio = 17,
.D0_gpio = 18,
.SDIO_PIO = pio1,
.DMA_IRQ_num = DMA_IRQ_1,
.baud_rate = 15 * 1000 * 1000 // 15 MHz
};

// Hardware Configuration of the SD Card "objects"
static sd_card_t sd_cards[] = {
{ // sd_cards[0]
/* "pcName" is the FatFs "logical drive" identifier.
(See http://elm-chan.org/fsw/ff/doc/filename.html#vol) */
.pcName = "0:",
.type = SD_IF_SPI,
.spi_if_p = &spi_if, // Pointer to the SPI interface driving this card
.use_card_detect = true,
.card_detect_gpio = 9,
.card_detected_true = 0, // What the GPIO read returns when a card is present.
.card_detect_use_pull = true,
.card_detect_pull_hi = true
},
{ // sd_cards[1]
/* "pcName" is the FatFs "logical drive" identifier.
(See http://elm-chan.org/fsw/ff/doc/filename.html#vol) */
.pcName = "1:",
.type = SD_IF_SDIO,
.sdio_if_p = &sdio_if,
// SD Card detect:
.use_card_detect = true,
.card_detect_gpio = 22,
.card_detected_true = 0, // What the GPIO read returns when a card is present.
.card_detect_use_pull = true,
.card_detect_pull_hi = true
}
};

// GPIO numbers, not Pico pin numbers!
SpiCfg spi(
spi1, // spi_inst_t *hw_inst,
12, // uint miso_gpio,
15, // uint mosi_gpio,
14, // uint sck_gpio
25 * 1000 * 1000 // uint baud_rate
);
spi_handle_t spi_handle = FatFs::add_spi(spi);

/* Hardware Configuration of the SD Card objects */

SdCardSpiCfg spi_sd_card(
spi_handle, // spi_handle_t spi_handle,
"0:", // const char *pcName,
9, // uint ss_gpio, // Slave select for this SD card
true, // bool use_card_detect = false,
13, // uint card_detect_gpio = 0, // Card detect; ignored if !use_card_detect
1 // uint card_detected_true = false // Varies with card socket; ignored if !use_card_detect
);
FatFs::add_sd_card(spi_sd_card);

// Add another SD card:
SdCardSdioCfg sdio_sd_card(
"1:", // const char *pcName,
18, // uint CMD_gpio,
19, // uint D0_gpio, // D0
true, // bool use_card_detect = false,
16, // uint card_detect_gpio = 0, // Card detect, ignored if !use_card_detect
1, // uint card_detected_true = 0, // Varies with card socket, ignored if !use_card_detect
pio1, // PIO SDIO_PIO = pio0, // either pio0 or pio1
DMA_IRQ_1 // uint DMA_IRQ_num = DMA_IRQ_0 // DMA_IRQ_0 or DMA_IRQ_1
);
FatFs::add_sd_card(sdio_sd_card);
FatFs::add_sd_card(&sd_cards[0]);
FatFs::add_sd_card(&sd_cards[1]);

if (!FatFs::begin())
error("Driver initialization failed\n");
Expand Down Expand Up @@ -230,16 +230,15 @@ static void bench(char const* logdrv) {
printf("%.2f", SdCard_p->get_num_sectors() * 512E-9);
printf(" GB (GB = 1E9 bytes)\n");

cidDmp(SdCard_p);
// typedef int (*printer_t)(const char* format, ...);

SdCard_p->cidDmp(printf);
SdCard_p->csdDmp(printf);

// fr = f_mount(&SdCard_p->fatfs, SdCard_p->pcName, 1);
SdCard_p->mount();
chk_result("f_mount", fr);

// open or create file - truncate existing file.
fr = file.open("bench.dat", FA_READ | FA_WRITE | FA_CREATE_ALWAYS);
chk_result("open", fr);

// fill buf with known data
if (BUF_SIZE > 1) {
for (size_t i = 0; i < (BUF_SIZE - 2); i++) {
Expand All @@ -249,6 +248,19 @@ static void bench(char const* logdrv) {
}
buf[BUF_SIZE - 1] = '\n';

// Open or create file.
// FA_CREATE_ALWAYS:
// Creates a new file.
// If the file is existing, it will be truncated and overwritten.
fr = file.open("bench.dat", FA_READ | FA_WRITE | FA_CREATE_ALWAYS);
chk_result("open", fr);

// Open with FA_CREATE_ALWAYS creates a new file,
// and if the file is existing, it will be truncated and overwritten.
if (PRE_ALLOCATE) {
fr = file.expand(FILE_SIZE);
chk_result("file.expand", fr);
}
printf("FILE_SIZE_MB = %lu\n", FILE_SIZE_MiB);
printf("BUF_SIZE = %zu\n", BUF_SIZE);
printf("Starting write test, please wait.\n\n");
Expand All @@ -259,18 +271,9 @@ static void bench(char const* logdrv) {
printf("speed,max,min,avg\n");
printf("KB/Sec,usec,usec,usec\n");
for (uint8_t nTest = 0; nTest < WRITE_COUNT; nTest++) {
// Open with FA_CREATE_ALWAYS creates a new file,
// and if the file is existing, it will be truncated and overwritten.
if (PRE_ALLOCATE) {
fr = file.lseek(FILE_SIZE);
chk_result("file.lseek", fr);
if (file.tell() != FILE_SIZE) {
printf("Disk full!\n");
for (;;) __breakpoint();
}
fr = file.rewind();
chk_result("file.rewind", fr);
}
fr = file.rewind();
chk_result("file.rewind", fr);

maxLatency = 0;
minLatency = 9999999;
totalLatency = 0;
Expand Down
13 changes: 5 additions & 8 deletions examples/PlatformIO/data_logger/platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ platform = https://github.com/maxgerhardt/platform-raspberrypi.git
board = pico
framework = arduino
board_build.core = earlephilhower
debug_tool = picoprobe
upload_protocol = picoprobe
monitor_port = COM4
; debug_tool = picoprobe
; upload_protocol = picoprobe
monitor_port = COM8
monitor_speed = 115200

build_flags =
Expand All @@ -28,10 +28,7 @@ build_flags =
; carlk3/no-OS-FatFS-SD-SPI-RPi-Pico@^1.0.2

; Get the latest straight from github:
; lib_deps =
; https://github.com/carlk3/no-OS-FatFS-SD-SPI-RPi-Pico.git#sdio

; lib_deps = https://github.com/carlk3/no-OS-FatFS-SD-SDIO-SPI-RPi-Pico.git
; Use local copy:
lib_deps =
no-OS-FatFS-SD-SPI-RPi-Pico.dev_sdio
lib_deps = no-OS-FatFS-SD-SDIO-SPI-RPi-Pico
lib_extra_dirs = ../../../..
Loading

0 comments on commit a840af6

Please sign in to comment.