ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_sdmmc_spi.h File Reference

SD card driver in SPI-mode (PMOD-attached cards). More...

#include <stdint.h>
#include "ra8_err.h"
#include "ra8_fs.h"
#include "ra8_port_constants.h"
Include dependency graph for ra8_sdmmc_spi.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  ra8_sdmmc_spi_transport_t
 Driver-to-bus binding (Dependency Inversion seam). More...
struct  ra8_sdmmc_spi_sci_pins_t
 The four bus pins of an SCI Simple-SPI SD slot. More...

Typedefs

typedef ra8_err_t(* ra8_sdmmc_spi_set_clock_fn_t) (void *ctx, uint32_t hz)
 Set the SPI clock frequency.
typedef ra8_err_t(* ra8_sdmmc_spi_cs_fn_t) (void *ctx, bool asserted)
 Drive the chip-select line of the SD card.
typedef ra8_err_t(* ra8_sdmmc_spi_xfer_fn_t) (void *ctx, const uint8_t *tx, uint8_t *rx, uint32_t len)
 Exchange len bytes full-duplex on the SPI bus.

Enumerations

enum  ra8_sdmmc_spi_limits_t : uint16_t {
  k_ra8_sdmmc_spi_block_size = 512U ,
  k_ra8_sdmmc_spi_cmd_frame_bytes = 6U ,
  k_ra8_sdmmc_spi_csd_response_len = 16U
}
 Block-I/O size constants. More...
enum  ra8_sdmmc_spi_clock_t : uint32_t {
  k_ra8_sdmmc_spi_clock_init_hz = 400000U ,
  k_ra8_sdmmc_spi_clock_data_hz = 25000000U
}
 Canonical SPI clock rates used by ra8_sdmmc_spi_init. More...
enum  ra8_sdmmc_spi_card_type_t : uint8_t {
  k_ra8_sdmmc_spi_type_unknown = 0U ,
  k_ra8_sdmmc_spi_type_sdv1 = 1U ,
  k_ra8_sdmmc_spi_type_sdv2 = 2U ,
  k_ra8_sdmmc_spi_type_sdhc = 3U
}
 Detected SD card capacity / addressing class. More...

Functions

ra8_err_t ra8_sdmmc_spi_transport_sci (uint8_t sci_channel, uint32_t pclk_hz, const ra8_sdmmc_spi_sci_pins_t *pins, ra8_sdmmc_spi_transport_t *out)
 Build the standard EK-RA8D2 SCI Simple-SPI transport for an SD card.
ra8_err_t ra8_sdmmc_spi_init (const ra8_sdmmc_spi_transport_t *transport)
 Run the SD SPI-mode identification sequence on a card.
ra8_err_t ra8_sdmmc_spi_deinit (void)
 Tear down the driver and release the transport binding.
ra8_err_t ra8_sdmmc_spi_read_block (uint32_t lba, uint8_t *buf)
 Read one 512-byte block at logical block address lba.
ra8_err_t ra8_sdmmc_spi_read_blocks (uint32_t lba, uint8_t *buf, uint32_t count)
 Read count contiguous 512-byte blocks in one CMD18 transaction.
ra8_err_t ra8_sdmmc_spi_write_block (uint32_t lba, const uint8_t *buf)
 Write one 512-byte block at logical block address lba.
ra8_err_t ra8_sdmmc_spi_write_blocks (uint32_t lba, const uint8_t *buf, uint32_t count)
 Write count contiguous 512-byte blocks in one CMD25 transaction.
ra8_err_t ra8_sdmmc_spi_erase_blocks (uint32_t lba, uint32_t count)
 Bulk-erase count blocks at lba, guaranteeing a zero read-back.
ra8_err_t ra8_sdmmc_spi_get_capacity (uint32_t *out_blocks)
 Return the card capacity in 512-byte blocks.
ra8_err_t ra8_sdmmc_spi_get_card_type (ra8_sdmmc_spi_card_type_t *out_type)
 Return the detected card type.
ra8_err_t ra8_sdmmc_spi_bind_fs_backend (ra8_fs_backend_t *out_backend)
 Populate an ra8_fs_backend_t that mounts onto this SD driver.
uint8_t ra8_sdmmc_spi_crc7 (const uint8_t *data, uint32_t len)
 Compute the SD-spec CRC7 over an arbitrary byte run.
uint16_t ra8_sdmmc_spi_crc16 (const uint8_t *data, uint32_t len)
 Compute the SD-spec CRC16-CCITT over an arbitrary byte run.

Detailed Description

SD card driver in SPI-mode (PMOD-attached cards).

Tag
[Ring 3 / HAL] {World: NS}

SPI-mode SD/SDHC/SDXC card driver. The card sits on an SPI bus (RSPI / SPI_B or any compatible 8-bit full-duplex transport) and answers the standard SD command set wrapped in the SPI-mode framing defined in SD Specification Part 1 Physical Layer Simplified Specification v9.10 section 7 ("SPI Mode").

The driver is transport-agnostic. Callers wire it up by passing a ra8_sdmmc_spi_transport_t descriptor that holds three function pointers (clock-rate set, CS drive, full-duplex byte exchange). The host-side unit tests inject a mock transport; the firmware application binds the real ra8_spi HAL driver through a tiny adapter that lives in the example app.

Public API:

  • ra8_sdmmc_spi_init(...) – send CMD0/CMD8/ACMD41/CMD58 probe, learn capacity, escalate the SPI clock to data speed.
  • ra8_sdmmc_spi_read_block(...) – single-block read (CMD17).
  • ra8_sdmmc_spi_read_blocks(...) – multi-block read (CMD18 + CMD12).
  • ra8_sdmmc_spi_write_block(...) – single-block write (CMD24).
  • ra8_sdmmc_spi_write_blocks(...)– multi-block write (CMD25).
  • ra8_sdmmc_spi_get_capacity(...)– expose the 512-byte block count.
  • ra8_sdmmc_spi_get_card_type(...)– SDSC / SDHC / SDXC.
  • ra8_sdmmc_spi_deinit(...) – release the transport.

The block I/O API takes a logical block address. Inside the driver the address is converted to a byte address for SDSC cards (CMD17/24 argument is in bytes for v1.x cards) and left as a block address for SDHC / SDXC cards (CMD17/24 argument is in blocks for v2.x cards with the CCS bit set). Callers always speak in 512-byte blocks.

The driver also exposes a small ra8_fs_backend_t adapter (ra8_sdmmc_spi_bind_fs_backend) that plugs the SD card straight into the ra8_fs FAT filesystem layer without any extra glue in the application.

Definition in file ra8_sdmmc_spi.h.

Typedef Documentation

◆ ra8_sdmmc_spi_cs_fn_t

typedef ra8_err_t(* ra8_sdmmc_spi_cs_fn_t) (void *ctx, bool asserted)

Drive the chip-select line of the SD card.

Parameters
[in]ctxTransport context cookie.
[in]assertedtrue to drive CS low (selected), false to release CS high.
Returns
ra8_err_t error code (k_ra8_ok on success).
Since
0.1.0

Definition at line 135 of file ra8_sdmmc_spi.h.

◆ ra8_sdmmc_spi_set_clock_fn_t

typedef ra8_err_t(* ra8_sdmmc_spi_set_clock_fn_t) (void *ctx, uint32_t hz)

Set the SPI clock frequency.

Parameters
[in]ctxTransport context cookie.
[in]hzTarget clock rate in Hz.
Returns
ra8_err_t
Return values
k_ra8_okClock applied.
k_ra8_err_invalid_arghz outside the transport's range.
Since
0.1.0

Definition at line 122 of file ra8_sdmmc_spi.h.

◆ ra8_sdmmc_spi_xfer_fn_t

typedef ra8_err_t(* ra8_sdmmc_spi_xfer_fn_t) (void *ctx, const uint8_t *tx, uint8_t *rx, uint32_t len)

Exchange len bytes full-duplex on the SPI bus.

Parameters
[in]ctxTransport context cookie.
[in]txTX buffer; if NULL the transport shall shift out 0xFF (idle pattern – SD spec PHY v9 section 7.2.4).
[out]rxRX buffer; if NULL the transport shall discard.
[in]lenNumber of bytes to exchange; must be > 0.
Returns
ra8_err_t error code.
Since
0.1.0

Definition at line 150 of file ra8_sdmmc_spi.h.

Enumeration Type Documentation

◆ ra8_sdmmc_spi_card_type_t

enum ra8_sdmmc_spi_card_type_t : uint8_t

Detected SD card capacity / addressing class.

Enumerator
k_ra8_sdmmc_spi_type_unknown 

Not yet probed / probe failed.

k_ra8_sdmmc_spi_type_sdv1 

SD v1.x (byte-addressed).

k_ra8_sdmmc_spi_type_sdv2 

SD v2.x SC (byte-addressed).

k_ra8_sdmmc_spi_type_sdhc 

SDHC / SDXC v2.x (block-addressed).

Definition at line 98 of file ra8_sdmmc_spi.h.

◆ ra8_sdmmc_spi_clock_t

enum ra8_sdmmc_spi_clock_t : uint32_t

Canonical SPI clock rates used by ra8_sdmmc_spi_init.

The SD spec mandates the host opens the bus at 100-400 kHz for the identification sequence (CMD0 ... ACMD41 ... CMD58) and only then escalates to data-transfer speed (default-speed = 25 MHz, high-speed = 50 MHz). We pick 25 MHz as the default-speed target – it is the universal floor the v1.x and v2.x card families all support.

Enumerator
k_ra8_sdmmc_spi_clock_init_hz 

Mandatory init clock floor.

k_ra8_sdmmc_spi_clock_data_hz 

Default-speed data clock.

Definition at line 89 of file ra8_sdmmc_spi.h.

◆ ra8_sdmmc_spi_limits_t

enum ra8_sdmmc_spi_limits_t : uint16_t

Block-I/O size constants.

Enumerator
k_ra8_sdmmc_spi_block_size 

512-byte block (SD spec PHY v9 section 7.2.2).

k_ra8_sdmmc_spi_cmd_frame_bytes 

1 cmd-byte + 4 arg-bytes + 1 CRC-byte.

k_ra8_sdmmc_spi_csd_response_len 

CMD9 CSD register payload bytes.

Definition at line 72 of file ra8_sdmmc_spi.h.

Function Documentation

◆ ra8_sdmmc_spi_bind_fs_backend()

ra8_err_t ra8_sdmmc_spi_bind_fs_backend ( ra8_fs_backend_t * out_backend)
nodiscard

Populate an ra8_fs_backend_t that mounts onto this SD driver.

Once ra8_sdmmc_spi_init has returned k_ra8_ok, the caller can invoke this helper to bind the SD card into the ra8_fs FAT layer:

ra8_fs_mount_t* mount = nullptr;
(void)ra8_fs_mount(&backend, &mount);
ra8_err_t ra8_fs_mount(const ra8_fs_backend_t *backend, ra8_fs_mount_t **out_handle)
Mount a FAT volume from a block-device backend, auto-selecting the first partition.
ra8_err_t ra8_sdmmc_spi_bind_fs_backend(ra8_fs_backend_t *out_backend)
Populate an ra8_fs_backend_t that mounts onto this SD driver.
Block-device interface that ra8_fs runs on top of.
Cached parse of one mounted FAT volume.

The backend forwards read_block / write_block to the SD driver one block at a time and reports the capacity in 512-byte blocks. The ctx field is left NULL because the SD driver has a single global instance.

Parameters
[out]out_backendPopulated backend descriptor; non-NULL.
Returns
ra8_err_t
Return values
k_ra8_okBackend populated.
k_ra8_err_null_ptrout_backend is NULL.
k_ra8_err_invalid_stateDriver not initialized.
Precondition
out_backend is non-NULL.
ra8_sdmmc_spi_init has returned k_ra8_ok.
Postcondition
*out_backend carries non-NULL read_block / write_block / get_capacity pointers.
Since
0.1.0

Definition at line 767 of file ra8_sdmmc_spi_io.c.

References ra8_fs_backend_t::ctx, ra8_fs_backend_t::erase_blocks, g_sdmmc_spi_state, ra8_fs_backend_t::get_capacity, internal_fs_erase_block(), internal_fs_get_capacity(), internal_fs_read_block(), internal_fs_write_block(), k_ra8_err_invalid_state, k_ra8_ok, RA8_CHECK_NULL_PTR, ra8_fs_backend_t::read_block, s_tag, and ra8_fs_backend_t::write_block.

Referenced by eoh_mount_or_halt(), etoc_mount_or_halt(), fs_fmt_run_exfat(), fs_fmt_run_one_type(), imp_mount_or_halt(), internal_mount(), internal_mount_sd(), internal_pc_mount_or_halt(), sd_demo_mount_or_halt(), and sh_sd_mount().

◆ ra8_sdmmc_spi_crc16()

uint16_t ra8_sdmmc_spi_crc16 ( const uint8_t * data,
uint32_t len )

Compute the SD-spec CRC16-CCITT over an arbitrary byte run.

Polynomial 0x1021 (x^16 + x^12 + x^5 + 1), seed 0x0000, as defined in SD spec PHY v9 section 4.5 "CRC16". The wire format is big-endian.

Parameters
[in]dataBuffer to hash; non-NULL when len > 0.
[in]lenByte count; may be zero.
Returns
uint16_t CRC16-CCITT over data[0..len-1].
Return values
0..0xFFFFComputed CRC16. Returns 0 on NULL input.
Precondition
data is non-NULL or len == 0.
Caller serializes the result big-endian on the wire.
Postcondition
No side effects.
Driver state is unchanged.
Note
Thread-safe; pure function with no global state.
Since
0.1.0

Definition at line 192 of file ra8_sdmmc_spi.c.

References k_sd_bit_byte, k_sd_crc16_msb_test, and k_sd_crc16_poly.

Referenced by internal_read_block_crc_check(), and internal_write_data_block().

◆ ra8_sdmmc_spi_crc7()

uint8_t ra8_sdmmc_spi_crc7 ( const uint8_t * data,
uint32_t len )

Compute the SD-spec CRC7 over an arbitrary byte run.

Polynomial 0x09 (x^7 + x^3 + 1), left-shifted, as defined in SD spec PHY v9 section 4.5 "CRC7". Used internally to seed every CMD frame's trailing CRC byte (the bottom bit of the CRC byte is the "end bit", always 1, so the wire value is (crc7 << 1) | 1U).

Parameters
[in]dataBuffer to hash; non-NULL when len > 0.
[in]lenByte count; may be zero.
Returns
uint8_t CRC7 in the low 7 bits.
Return values
0..0x7FComputed CRC7. Returns 0 on NULL input.
Precondition
data is non-NULL or len == 0.
Caller treats the return value as a 7-bit CRC, not 8.
Postcondition
No side effects.
Driver state is unchanged.
Note
Thread-safe; pure function with no global state.
Since
0.1.0

Definition at line 171 of file ra8_sdmmc_spi.c.

References k_sd_bit_byte, k_sd_crc7_byte_msb, k_sd_crc7_msb_test, k_sd_crc7_poly_low7, and k_sd_crc7_register_mask.

Referenced by internal_build_frame().

◆ ra8_sdmmc_spi_deinit()

ra8_err_t ra8_sdmmc_spi_deinit ( void )
nodiscard

Tear down the driver and release the transport binding.

Returns
ra8_err_t
Return values
k_ra8_okAlways (idempotent).
Precondition
None.
Postcondition
Internal state is the same as before the first ra8_sdmmc_spi_init.
Subsequent ra8_sdmmc_spi_init may re-bind a new transport.
Since
0.1.0

Definition at line 279 of file ra8_sdmmc_spi_io.c.

References g_sdmmc_spi_state, k_ra8_ok, and k_ra8_sdmmc_spi_type_unknown.

◆ ra8_sdmmc_spi_erase_blocks()

ra8_err_t ra8_sdmmc_spi_erase_blocks ( uint32_t lba,
uint32_t count )
nodiscard

Bulk-erase count blocks at lba, guaranteeing a zero read-back.

The CMD32/CMD33/CMD38 erase sequence. The card erases the range internally in one operation – vastly faster than streaming zeros for a large region (e.g. the ~30 MB FAT of a 128 GB FAT32 card). The post-erase value is card-dependent (0x00 on some cards, 0xFF on others), and the SCR DATA_STAT_AFTER_ERASE bit's polarity is unreliable in practice, so this call probes: it erases only the first block, reads it back, and proceeds to erase the rest of the range only when that block is actually all-zero. A non-zero probe yields k_ra8_err_not_supported (the card erases to ones), letting the caller fall back to writing zeros without having wasted a full-region erase. A k_ra8_ok return is therefore a verified "this region now reads as all-zero bytes".

Parameters
[in]lbaFirst LBA in 512-byte units. lba + count <= capacity.
[in]countNumber of contiguous blocks to erase (>= 1).
Returns
ra8_err_t
Return values
k_ra8_okRange erased AND verified to read back as zero.
k_ra8_err_invalid_stateDriver not initialized.
k_ra8_err_invalid_argcount is 0.
k_ra8_err_out_of_rangelba + count exceeds capacity.
k_ra8_err_not_supportedCard erases to a non-zero value (read-back != 0).
k_ra8_err_protocol_errorA command R1 was rejected.
k_ra8_err_hw_timeoutThe post-erase busy wait timed out.
Precondition
ra8_sdmmc_spi_init has returned k_ra8_ok.
lba + count <= capacity (in 512-byte blocks).
Postcondition
On k_ra8_ok, lba .. lba+count-1 read back as 0x00.
Card remains in tran state.
Note
Erase granularity is the card's internal AU; the spec guarantees the addressed range is fully erased without disturbing blocks outside it.
Since
0.1.0

Definition at line 637 of file ra8_sdmmc_spi_io.c.

References g_sdmmc_spi_state, internal_erase_range(), k_ra8_err_invalid_arg, k_ra8_err_invalid_state, k_ra8_err_not_supported, k_ra8_err_out_of_range, k_ra8_ok, k_ra8_sdmmc_spi_block_size, and ra8_sdmmc_spi_read_block().

Referenced by internal_fs_erase_block(), and internal_sdspi_erase().

◆ ra8_sdmmc_spi_get_capacity()

ra8_err_t ra8_sdmmc_spi_get_capacity ( uint32_t * out_blocks)
nodiscard

Return the card capacity in 512-byte blocks.

Parameters
[out]out_blocksReceives the block count; non-NULL.
Returns
ra8_err_t
Return values
k_ra8_okSuccess.
k_ra8_err_null_ptrout_blocks is NULL.
k_ra8_err_invalid_stateDriver not initialized.
Precondition
out_blocks is non-NULL.
ra8_sdmmc_spi_init has returned k_ra8_ok.
Postcondition
On success *out_blocks > 0.
Driver state unchanged.
Since
0.1.0

Definition at line 679 of file ra8_sdmmc_spi_io.c.

References g_sdmmc_spi_state, k_ra8_err_invalid_state, k_ra8_ok, RA8_CHECK_NULL_PTR, and s_tag.

Referenced by internal_sdspi_get_caps(), microsd_sd_snapshot(), sd_demo_print_capacity(), and sdmsc_card_up().

◆ ra8_sdmmc_spi_get_card_type()

ra8_err_t ra8_sdmmc_spi_get_card_type ( ra8_sdmmc_spi_card_type_t * out_type)
nodiscard

Return the detected card type.

Parameters
[out]out_typeReceives the card type; non-NULL.
Returns
ra8_err_t
Return values
k_ra8_okSuccess.
k_ra8_err_null_ptrout_type is NULL.
k_ra8_err_invalid_stateDriver not initialized.
Precondition
out_type is non-NULL.
ra8_sdmmc_spi_init has returned k_ra8_ok.
Postcondition
Driver state unchanged.
Since
0.1.0

Definition at line 689 of file ra8_sdmmc_spi_io.c.

References g_sdmmc_spi_state, k_ra8_err_invalid_state, k_ra8_ok, RA8_CHECK_NULL_PTR, and s_tag.

◆ ra8_sdmmc_spi_init()

ra8_err_t ra8_sdmmc_spi_init ( const ra8_sdmmc_spi_transport_t * transport)
nodiscard

Run the SD SPI-mode identification sequence on a card.

Steps (SD spec PHY v9 section 7.2.1 "Mode Selection and Initialization"):

  1. Set bus clock to 400 kHz, send >= 74 dummy clocks with CS high.
  2. Assert CS, send CMD0 (GO_IDLE_STATE), expect R1 = 0x01 (idle).
  3. Send CMD8 (SEND_IF_COND, arg = 0x000001AA). R7 echo of the low 12 bits classifies the card as v2.x; "illegal command" (R1.bit2 set) classifies it as v1.x.
  4. Loop ACMD41 (CMD55 + CMD41, HCS = 1 for v2.x cards) until R1 reports "ready" (bit 0 of R1 == 0).
  5. For v2.x cards, send CMD58 (READ_OCR) and capture the CCS bit; CCS == 1 means SDHC/SDXC (block-addressed).
  6. Send CMD9 (SEND_CSD), parse the CSD-v1 or CSD-v2 fields to compute the capacity in 512-byte blocks.
  7. Send CMD16 (SET_BLOCKLEN, 512) to lock the block size.
  8. Bump the bus clock to k_ra8_sdmmc_spi_clock_data_hz (25 MHz).
Parameters
[in]transportNon-NULL transport descriptor with all three function pointers populated. The struct is copied so the caller may free its storage on return.
Returns
ra8_err_t
Return values
k_ra8_okCard probed and ready.
k_ra8_err_null_ptrtransport or any callback is NULL.
k_ra8_err_invalid_stateDriver already initialized.
k_ra8_err_hw_timeoutCMD0 / ACMD41 never produced a response.
k_ra8_err_protocol_errorCMD8 echo mismatch, unexpected R1 bits.
k_ra8_err_crc_mismatchCMD response CRC7 mismatch.
k_ra8_err_hw_init_failedACMD41 init loop exceeded retry budget.
Precondition
transport is non-NULL.
transport->set_clock / cs / xfer are all non-NULL.
Postcondition
On success ra8_sdmmc_spi_get_capacity returns a non-zero block count.
On success the SPI bus runs at k_ra8_sdmmc_spi_clock_data_hz.
Note
Blocking, polled implementation; not safe to call from an ISR.
Since
0.1.0

Definition at line 266 of file ra8_sdmmc_spi_io.c.

References internal_finalize_init(), internal_prepare_init(), k_ra8_ok, priv_sdmmc_spi_run_init_sequence(), priv_sdmmc_spi_validate_transport(), RA8_RETURN_ON_ERROR, and s_tag.

Referenced by eoh_init_card_or_halt(), etoc_init_card_or_halt(), fs_fmt_init_card_or_halt(), imp_init_card_or_halt(), internal_mount(), internal_mount_sd(), internal_pc_init_card_or_halt(), internal_sd_demo_init_card_or_halt(), microsd_sd_snapshot(), sd_demo_init_card_or_halt(), sdmsc_card_up(), and sh_sd_mount().

◆ ra8_sdmmc_spi_read_block()

ra8_err_t ra8_sdmmc_spi_read_block ( uint32_t lba,
uint8_t * buf )
nodiscard

Read one 512-byte block at logical block address lba.

Issues CMD17 (READ_SINGLE_BLOCK) with the appropriate byte/block address conversion for the detected card type. Waits for the data token (0xFE), drains 512 payload bytes, then drains the trailing 2-byte CRC16 (SD spec PHY v9 section 7.3.3.2 "Start Block Token"). The CRC16 is checked.

Parameters
[in]lbaLBA in 512-byte units. Must satisfy lba < capacity.
[out]bufDestination buffer, exactly 512 bytes.
Returns
ra8_err_t
Return values
k_ra8_okBlock read and CRC verified.
k_ra8_err_null_ptrbuf is NULL.
k_ra8_err_invalid_stateDriver not initialized.
k_ra8_err_out_of_rangelba >= capacity.
k_ra8_err_hw_timeoutData token never arrived.
k_ra8_err_crc_mismatchCRC16 mismatch on the payload.
k_ra8_err_protocol_errorCard returned non-zero R1.
Precondition
ra8_sdmmc_spi_init has returned k_ra8_ok.
buf is non-NULL.
Postcondition
On success, buf[0..511] holds the requested block.
Card remains in tran state.
Since
0.1.0

Definition at line 398 of file ra8_sdmmc_spi_io.c.

References g_sdmmc_spi_state, internal_read_data_phase(), k_ra8_err_invalid_state, k_ra8_err_out_of_range, priv_sdmmc_spi_cs_assert(), priv_sdmmc_spi_cs_release(), RA8_CHECK_NULL_PTR, RA8_RETURN_ON_ERROR, and s_tag.

Referenced by microsd_sd_snapshot(), ra8_sdmmc_spi_erase_blocks(), and ra8_sdmmc_spi_read_blocks().

◆ ra8_sdmmc_spi_read_blocks()

ra8_err_t ra8_sdmmc_spi_read_blocks ( uint32_t lba,
uint8_t * buf,
uint32_t count )
nodiscard

Read count contiguous 512-byte blocks in one CMD18 transaction.

The fast bulk-read path and the mirror of ra8_sdmmc_spi_write_blocks: a single READ_MULTIPLE_BLOCK (CMD18) command streams every block – data-start token (0xFE), 512 payload bytes, and a verified CRC16 trailer per block – and is terminated by CMD12 (STOP_TRANSMISSION). One command for the whole run instead of count CMD17 single-block reads. Falls back to ra8_sdmmc_spi_read_block when count == 1. On a mid-stream error (missing token, CRC mismatch, bus fault) CMD12 is still issued so the card leaves the data state before CS is released; the stream error takes precedence over any stop error.

Parameters
[in]lbaFirst LBA in 512-byte units. lba + count <= capacity.
[out]bufDestination buffer of exactly count * 512 bytes.
[in]countNumber of contiguous blocks to read (0 is a no-op).
Returns
ra8_err_t
Return values
k_ra8_okAll blocks read and every CRC16 verified (also returned for the count == 0 no-op).
k_ra8_err_null_ptrbuf is NULL.
k_ra8_err_invalid_stateDriver not initialized.
k_ra8_err_out_of_rangelba + count exceeds capacity.
k_ra8_err_hw_timeoutA data token never arrived.
k_ra8_err_crc_mismatchCRC16 mismatch on a block payload.
k_ra8_err_protocol_errorCMD18 or CMD12 returned non-zero R1.
Precondition
ra8_sdmmc_spi_init has returned k_ra8_ok.
buf is writable for at least count * 512 bytes.
Postcondition
On success buf[0 .. (count * 512) - 1] holds the requested blocks.
CMD12 has been sent (count > 1) and the card is back in tran state; CS is released on every return path.
Note
Not thread-safe; serialise card access. Blocking, polled implementation – not safe to call from an ISR.
See also
ra8_sdmmc_spi_read_block() Single-block CMD17 read.
ra8_sdmmc_spi_write_blocks() The CMD25 bulk-write mirror.
Since
0.1.0

Definition at line 451 of file ra8_sdmmc_spi_io.c.

References g_sdmmc_spi_state, internal_lba_to_arg(), internal_read_multi_stop(), internal_read_multi_stream(), k_ra8_err_invalid_state, k_ra8_err_out_of_range, k_ra8_err_protocol_error, k_ra8_ok, k_sd_cmd_read_multi_block, priv_sdmmc_spi_cs_assert(), priv_sdmmc_spi_cs_release(), priv_sdmmc_spi_send_command(), RA8_CHECK_NULL_PTR, RA8_RETURN_ON_ERROR, ra8_sdmmc_spi_read_block(), and s_tag.

Referenced by internal_fs_read_block(), internal_sdspi_read(), and sdmsc_msc_read().

◆ ra8_sdmmc_spi_transport_sci()

ra8_err_t ra8_sdmmc_spi_transport_sci ( uint8_t sci_channel,
uint32_t pclk_hz,
const ra8_sdmmc_spi_sci_pins_t * pins,
ra8_sdmmc_spi_transport_t * out )
nodiscard

Build the standard EK-RA8D2 SCI Simple-SPI transport for an SD card.

One-line bring-up that gives SD-over-SPI the same ergonomics the SDHI host controller already has: instead of every app hand-writing the three set_clock / cs / xfer callbacks plus the pin routing, this factory does all of it and hands back a ready-to-use transport descriptor.

Concretely it:

  1. Routes pins->sck / cipo / copi to the SCI Simple-SPI function via ra8_pfs_route_peripheral (PSEL = SCI async) and claims pins->cs as a GPIO output held high (card deselected).
  2. Brings the SCI channel up in Simple-SPI controller mode at the SD power-on clock (k_ra8_sdmmc_spi_clock_init_hz) via ra8_sci_spi_init.
  3. Caches the bus parameters into module-private storage and wires the three transport callbacks to the existing ra8_sci_spi / GPIO HAL.

The returned transport is then passed straight to ra8_sdmmc_spi_init:

};
(void)ra8_sdmmc_spi_transport_sci(0U, pclka_hz, &pins, &tr);
(void)ra8_sdmmc_spi_init(&tr);
@ k_ra8_board_pmod2_spi_cipo
Pmod2.3 CIPO (CIPO0_B), P602.
@ k_ra8_board_pmod2_spi_cs
Pmod2.1 CS (SS0_B), P604.
@ k_ra8_board_pmod2_spi_copi
Pmod2.2 COPI (COPI0_B), P603.
@ k_ra8_board_pmod2_spi_sck
Pmod2.4 SCK (SCK0_B), P601.
ra8_port_pin_t
Packed (port << 8) | pin pin identifier.
ra8_err_t ra8_sdmmc_spi_transport_sci(uint8_t sci_channel, uint32_t pclk_hz, const ra8_sdmmc_spi_sci_pins_t *pins, ra8_sdmmc_spi_transport_t *out)
Build the standard EK-RA8D2 SCI Simple-SPI transport for an SD card.
ra8_err_t ra8_sdmmc_spi_init(const ra8_sdmmc_spi_transport_t *transport)
Run the SD SPI-mode identification sequence on a card.
The four bus pins of an SCI Simple-SPI SD slot.
Driver-to-bus binding (Dependency Inversion seam).

The factory is an opt-in convenience: ra8_sdmmc_spi_init still accepts any caller-built ra8_sdmmc_spi_transport_t, so an app needing a custom bus (different SCI channel mux, bit-banged transport, mock) skips this helper and populates the descriptor itself.

Parameters
[in]sci_channelSCI channel index (0..9) wired to Simple-SPI mode.
[in]pclk_hzPCLKA rate (Hz) feeding the SCI baud divider; non-zero.
[in]pinsNon-NULL SCK / CIPO / COPI / CS pin descriptor.
[out]outNon-NULL transport descriptor populated on success.
Returns
ra8_err_t
Return values
k_ra8_okPins routed, SCI up, out populated.
k_ra8_err_null_ptrpins or out is NULL.
k_ra8_err_invalid_argpclk_hz is 0.
otherPropagated from ra8_pfs_route_peripheral / ra8_gpio_output_init / ra8_sci_spi_init.
Precondition
ra8_cgc_init has run and pclk_hz is the live PCLKA rate.
pins references four pins free for the SCI Simple-SPI mux.
Postcondition
On success out carries non-NULL set_clock / cs / xfer pointers and a ctx cookie pointing at module-private bus state.
On success the SCI channel is configured at the SD init clock and CS is deasserted.
Note
Single-shot module state backs the transport ctx, so only one SD bus may be brought up through this factory at a time. Not thread-safe and not ISR-safe; call once from the single-threaded init path.
See also
ra8_sdmmc_spi_init
Since
0.1.0

Definition at line 208 of file ra8_sdmmc_spi_io.c.

References ra8_sdmmc_spi_sci_pins_t::cs, ra8_sdmmc_spi_transport_t::cs, ra8_sdmmc_spi_transport_t::ctx, internal_sci_transport_bringup(), internal_sci_transport_cs(), internal_sci_transport_set_clock(), internal_sci_transport_xfer(), k_ra8_err_invalid_arg, k_ra8_ok, RA8_CHECK_NULL_PTR, s_sci_ctx, s_tag, ra8_sdmmc_spi_transport_t::set_clock, and ra8_sdmmc_spi_transport_t::xfer.

Referenced by imp_init_card_or_halt(), internal_mount_sd(), internal_sd_demo_init_card_or_halt(), and sdmsc_card_up().

◆ ra8_sdmmc_spi_write_block()

ra8_err_t ra8_sdmmc_spi_write_block ( uint32_t lba,
const uint8_t * buf )
nodiscard

Write one 512-byte block at logical block address lba.

Issues CMD24 (WRITE_BLOCK), sends the data-block token (0xFE), the 512 payload bytes, the 2-byte CRC16, then polls until the card de-asserts the busy-token (CIPO == 0xFF). The data-response token is checked for "data accepted" (xxx00101).

Parameters
[in]lbaLBA in 512-byte units. Must satisfy lba < capacity.
[in]bufSource buffer, exactly 512 bytes.
Returns
ra8_err_t
Return values
k_ra8_okBlock written and card became idle.
k_ra8_err_null_ptrbuf is NULL.
k_ra8_err_invalid_stateDriver not initialized.
k_ra8_err_out_of_rangelba >= capacity.
k_ra8_err_hw_timeoutCard never released busy.
k_ra8_err_protocol_errorData-response token != "accepted".
Precondition
ra8_sdmmc_spi_init has returned k_ra8_ok.
buf is non-NULL.
Postcondition
On success, the card's storage at LBA lba matches buf.
Card remains in tran state.
Since
0.1.0

Definition at line 530 of file ra8_sdmmc_spi_io.c.

References g_sdmmc_spi_state, internal_lba_to_arg(), internal_write_data_block(), k_ra8_err_invalid_state, k_ra8_err_out_of_range, k_ra8_err_protocol_error, k_ra8_ok, k_sd_cmd_write_single_block, k_sd_token_data_start_single, priv_sdmmc_spi_cs_assert(), priv_sdmmc_spi_cs_release(), priv_sdmmc_spi_send_command(), RA8_CHECK_NULL_PTR, RA8_RETURN_ON_ERROR, and s_tag.

Referenced by ra8_sdmmc_spi_write_blocks().

◆ ra8_sdmmc_spi_write_blocks()

ra8_err_t ra8_sdmmc_spi_write_blocks ( uint32_t lba,
const uint8_t * buf,
uint32_t count )
nodiscard

Write count contiguous 512-byte blocks in one CMD25 transaction.

The fast bulk-write path: ACMD23 pre-erase hint (best-effort) plus a single WRITE_MULTIPLE_BLOCK streaming every block, terminated by the stop token. One command for the whole run instead of count CMD24 single-block writes – far faster for clearing a large region such as a multi-MB FAT during format. Falls back to ra8_sdmmc_spi_write_block when count == 1.

Parameters
[in]lbaFirst LBA in 512-byte units. lba + count <= capacity.
[in]bufSource buffer of exactly count * 512 bytes.
[in]countNumber of contiguous blocks to write (>= 1).
Returns
ra8_err_t
Return values
k_ra8_okAll blocks written and the card became idle.
k_ra8_err_null_ptrbuf is NULL.
k_ra8_err_invalid_stateDriver not initialized.
k_ra8_err_out_of_rangelba + count exceeds capacity.
k_ra8_err_protocol_errorA command R1 or data-response token rejected.
Precondition
ra8_sdmmc_spi_init has returned k_ra8_ok.
buf holds at least count * 512 bytes.
Postcondition
On success, the card's storage at lba .. lba+count-1 matches buf.
Card remains in tran state.
Since
0.1.0

Write count contiguous 512-byte blocks in one CMD25 transaction.

The fast bulk-write path: an optional ACMD23 pre-erase hint, then a single WRITE_MULTIPLE_BLOCK (CMD25) streaming every block with the multi-block data-start token (0xFC), terminated by the stop-tran token (0xFD). One command for the whole run instead of count single-block CMD24 writes – the SD spec fast path for clearing a large region (e.g. a multi-MB FAT during format).

Parameters
[in]lbaFirst logical block address.
[in]bufSource buffer of count * 512 bytes.
[in]countNumber of contiguous blocks (>= 1).
Returns
ra8_err_t Error code.
Return values
k_ra8_okAll count blocks were accepted and programmed.
k_ra8_err_null_ptrbuf is NULL.
k_ra8_err_invalid_stateThe driver is not initialised.
k_ra8_err_out_of_rangelba + count exceeds the card capacity.
k_ra8_err_protocol_errorA command R1 or data-response token rejected.
Precondition
The driver is initialised and a card is present.
buf holds at least count * 512 bytes.
Postcondition
The stop token has been sent and the card is no longer busy.
CS is released on every return path.
Note
Not thread-safe; serialise card access. ACMD23 is best-effort – a card that rejects it still gets a correct (if unpre-erased) CMD25 stream.
Since
0.1.0

Definition at line 604 of file ra8_sdmmc_spi_io.c.

References g_sdmmc_spi_state, internal_lba_to_arg(), internal_write_multi_stream(), k_ra8_err_invalid_state, k_ra8_err_out_of_range, k_ra8_err_protocol_error, k_ra8_ok, k_sd_acmd_set_wr_blk_erase_count, k_sd_cmd_write_multi_block, priv_sdmmc_spi_cs_assert(), priv_sdmmc_spi_cs_release(), priv_sdmmc_spi_send_acmd(), priv_sdmmc_spi_send_command(), RA8_CHECK_NULL_PTR, RA8_RETURN_ON_ERROR, ra8_sdmmc_spi_write_block(), and s_tag.

Referenced by internal_fs_write_block(), internal_sdspi_write(), and sdmsc_msc_write().