Skip to content

Commit

Permalink
Merge pull request #42 from carlk3/dev
Browse files Browse the repository at this point in the history
Accommodate running without CS (SS)
  • Loading branch information
carlk3 authored Sep 7, 2024
2 parents a6fa5eb + 8b2abec commit 6c4a0ec
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 10 deletions.
39 changes: 32 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# FreeRTOS-FAT-CLI-for-RPi-Pico
# v2.11.0
# v2.12.0
=============================
## C/C++ Library for SD Cards on the Pico

Expand All @@ -16,6 +16,8 @@ and/or a 4-bit Secure Digital Input Output (SDIO) driver derived from
It is wrapped up in a complete runnable project, with a little command line interface, some self tests, and an example data logging application.

## What's new
### v2.12.0
Add support for running without Chip Select (CS) (formerly Slave Select [SS]).
### v2.11.0
* Add `spi_mode` to the hardware configuration.
For SPI attached cards, SPI Mode 3 can significantly improve performance.
Expand Down Expand Up @@ -136,7 +138,9 @@ or you can use something like
* For each SPI controller used, two DMA channels are claimed with `dma_claim_unused_channel`.
* A configurable DMA IRQ is hooked with `irq_add_shared_handler` or `irq_set_exclusive_handler` (configurable) and enabled.
* For each SPI controller used, one GPIO is needed for each of RX, TX, and SCK. Note: each SPI controller can only use a limited set of GPIOs for these functions.
* For each SD card attached to an SPI controller, a GPIO is needed for slave (or "chip") select (SS or "CS"), and, optionally, another for Card Detect (CD or "DET").
* For each SD card attached to an SPI controller:
* (Optional, if there's only one SD card) A GPIO for slave (or "chip") select (SS or "CS"). (See [Running without Chip Select (CS) (formerly Slave Select [SS])](#running-without-chip-select-cs-formerly-slave-select-ss).)
* (Optional) A GPIO for Card Detect (CD or "DET"). (See [Notes about Card Detect](#notes-about-card-detect).)
* SDIO attached cards:
* A PIO block
* Two DMA channels claimed with `dma_claim_unused_channel`
Expand Down Expand Up @@ -359,9 +363,27 @@ or polling.
* Some workarounds for absence of Card Detect:
* If you don't care much about performance or battery life, you could mount the card before each access and unmount it after. This might be a good strategy for a slow data logging application, for example.
* Some other form of polling: if the card is periodically accessed at rate faster than the user can swap cards, then the temporary absence of a card will be noticed, so a swap will be detected. For example, if a data logging application writes a log record to the card once per second, it is unlikely that the user could swap cards between accesses.
<!--
![image](https://github.com/carlk3/FreeRTOS-FAT-CLI-for-RPi-Pico/blob/master/images/IMG_1478.JPG "Prototype")
-->

## Running without Chip Select (CS) (formerly Slave Select [SS])
If you have only one SD card, and you are short on GPIOs, you may be able to run without CS/SS.
I know of no guarantee that this will work for all SD cards.
The [Physical Layer Simplified Specification](https://www.sdcard.org/downloads/pls/) says
> Every command or data block is
> built of 8-bit bytes and is byte aligned with the CS signal...
> The card starts to count SPI bus clock cycle at the assertion of the CS signal...
> The host
> starts every bus transaction by asserting the CS signal low.
It doesn't say what happens if the CS signal is always asserted.
However, it worked for me with:
* [Silicon Power 3D NAND U1 32GB microSD card](https://www.amazon.com/gp/product/B07RSXSYJC/)
* [SanDisk 16GB Ultra microSDHC UHS-I Memory Card ](https://www.amazon.com/gp/product/B089DPCJS1/ref=ppx_yo_dt_b_search_asin_title?th=1)
* [PNY 16GB Elite Class 10 U1 microSDHC Flash Memory Card](https://www.amazon.com/gp/product/B08QDN7CVN/ref=ppx_yo_dt_b_search_asin_title)

You will need to pull down the CS/SS line on the SD card with hardware. (I.e., connect CS to GND. CS is active low.)

In the hardware configuration definition, set `ss_gpio` to -1.
See [An instance of `sd_spi_if_t` describes the configuration of one SPI to SD card interface.](#an-instance-of-sd_spi_if_t-describes-the-configuration-of-one-spi-to-sd-card-interface).

## Firmware
### Dependencies
Expand Down Expand Up @@ -568,7 +590,10 @@ typedef struct sd_spi_if_t {
} sd_spi_if_t;
```
* `spi` Points to the instance of `spi_t` that is to be used as the SPI to drive this interface
* `ss_gpio` Slave Select (SS) (or "Chip Select [CS]") GPIO for the SD card socket associated with this interface
* `ss_gpio` Slave Select (SS) (or "Chip Select [CS]") GPIO for the SD card socket associated with this interface.
Set this to -1 to disable it.
(See [Running without Chip Select (CS) (formerly Slave Select [SS])](#running-without-chip-select-cs-formerly-slave-select-ss).)
*Note:* 0 is a valid GPIO number, so you must explicitly set it to -1 to disable it.
* `set_drive_strength` Enable explicit specification of output drive strength of `ss_gpio_drive_strength`.
If false, the GPIO's drive strength will be implicitly set to 4 mA.
* `ss_gpio_drive_strength` Drive strength for the SS (or CS).
Expand All @@ -583,7 +608,7 @@ If false, the GPIO's drive strength will be implicitly set to 4 mA.
An instance of `spi_t` describes the configuration of one RP2040 SPI controller.
```C
typedef struct spi_t {
spi_inst_t *hw_inst; // SPI HW
spi_inst_t *hw_inst; // SPI HW
uint miso_gpio; // SPI MISO GPIO number (not pin number)
uint mosi_gpio;
uint sck_gpio;
Expand Down
8 changes: 5 additions & 3 deletions src/FreeRTOS+FAT+CLI/portable/RP2040/SPI/sd_card_spi.c
Original file line number Diff line number Diff line change
Expand Up @@ -1697,9 +1697,10 @@ static void sd_deinit(sd_card_t *sd_card_p) {
sd_card_p->state.m_Status |= STA_NOINIT;
sd_card_p->state.card_type = SDCARD_NONE;

// Chip select is active-low
gpio_deinit(sd_card_p->spi_if_p->ss_gpio);
gpio_set_dir(sd_card_p->spi_if_p->ss_gpio, GPIO_IN);
if ((uint)-1 != sd_card_p->spi_if_p->ss_gpio) {
gpio_deinit(sd_card_p->spi_if_p->ss_gpio);
gpio_set_dir(sd_card_p->spi_if_p->ss_gpio, GPIO_IN);
}
}

/**
Expand All @@ -1724,6 +1725,7 @@ void sd_spi_ctor(sd_card_t *sd_card_p) {

// Chip select is active-low, so we'll initialise it to a
// driven-high state.
if ((uint)-1 == sd_card_p->spi_if_p->ss_gpio) return;
gpio_init(sd_card_p->spi_if_p->ss_gpio);
gpio_put(sd_card_p->spi_if_p->ss_gpio, 1); // Avoid any glitches when enabling output
gpio_set_dir(sd_card_p->spi_if_p->ss_gpio, GPIO_OUT);
Expand Down
1 change: 1 addition & 0 deletions src/FreeRTOS+FAT+CLI/portable/RP2040/SPI/sd_spi.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ This sequence is a contiguous stream of logical ‘1’s. The sequence length is
provided to eliminate power-up synchronization problems.
*/
void sd_spi_send_initializing_sequence(sd_card_t *sd_card_p) {
if ((uint)-1 == sd_card_p->spi_if_p->ss_gpio) return;
bool old_ss = gpio_get(sd_card_p->spi_if_p->ss_gpio);
// Set DI and CS high and apply 74 or more clock pulses to SCLK:
gpio_put(sd_card_p->spi_if_p->ss_gpio, 1);
Expand Down
2 changes: 2 additions & 0 deletions src/FreeRTOS+FAT+CLI/portable/RP2040/SPI/sd_spi.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,13 +90,15 @@ static inline uint8_t sd_spi_write_read(sd_card_t *sd_card_p, const uint8_t valu

// Would do nothing if sd_card_p->spi_if_p->ss_gpio were set to GPIO_FUNC_SPI.
static inline void sd_spi_select(sd_card_t *sd_card_p) {
if ((uint)-1 == sd_card_p->spi_if_p->ss_gpio) return;
gpio_put(sd_card_p->spi_if_p->ss_gpio, 0);
// See http://elm-chan.org/docs/mmc/mmc_e.html#spibus
sd_spi_write(sd_card_p, SPI_FILL_CHAR);
LED_ON();
}

static inline void sd_spi_deselect(sd_card_t *sd_card_p) {
if ((uint)-1 == sd_card_p->spi_if_p->ss_gpio) return;
gpio_put(sd_card_p->spi_if_p->ss_gpio, 1);
LED_OFF();
/*
Expand Down

0 comments on commit 6c4a0ec

Please sign in to comment.