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

SD card driver in SPI-mode – public block I/O and SCI factory. More...

#include <stdint.h>
#include <string.h>
#include "ra8_check.h"
#include "ra8_err.h"
#include "ra8_gpio_constants.h"
#include "ra8_log.h"
#include "ra8_port_utils.h"
#include "ra8_sci_spi.h"
#include "ra8_sdmmc_spi.h"
#include "ra8_sdmmc_spi_internal.h"
#include "ra8_sdmmc_spi_io_contracts_internal.h"
#include "ra8_spi.h"
Include dependency graph for ra8_sdmmc_spi_io.c:

Go to the source code of this file.

Data Structures

struct  sci_bus_ctx_t
 Bus context handed to the factory's transport callbacks. More...

Functions

static ra8_err_t internal_sci_transport_set_clock (void *ctx, uint32_t hz)
 Factory transport set-clock shim: retune the SCI baud divider.
static ra8_err_t internal_sci_transport_cs (void *ctx, bool asserted)
 Factory transport chip-select shim: drive CS low (asserted) or high.
static ra8_err_t internal_sci_transport_xfer (void *ctx, const uint8_t *tx, uint8_t *rx, uint32_t len)
 Factory transport transfer shim: full-duplex byte exchange.
static ra8_err_t internal_sci_transport_bringup (uint8_t channel, uint32_t pclk_hz, const ra8_sdmmc_spi_sci_pins_t *pins)
 Route the four Pmod SPI pins and bring up the SCI Simple-SPI channel.
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.
static ra8_err_t internal_prepare_init (const ra8_sdmmc_spi_transport_t *transport)
static ra8_err_t internal_finalize_init (void)
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.
static uint32_t internal_lba_to_arg (uint32_t lba)
static ra8_err_t internal_cmd_require_ready (sd_cmd_t cmd, uint32_t arg)
static ra8_err_t internal_erase_range (uint32_t lba, uint32_t count)
static ra8_err_t internal_read_block_payload (uint8_t *buf)
static ra8_err_t internal_read_block_crc_check (const uint8_t *buf)
static ra8_err_t internal_read_data_phase (uint32_t lba, uint8_t *buf)
ra8_err_t ra8_sdmmc_spi_read_block (uint32_t lba, uint8_t *buf)
 Read one 512-byte block at logical block address lba.
static ra8_err_t internal_read_multi_stream (uint8_t *buf, uint32_t count)
static ra8_err_t internal_read_multi_stop (void)
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.
static ra8_err_t internal_write_data_block (const uint8_t *buf, uint8_t start_token)
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.
static ra8_err_t internal_write_multi_stream (const uint8_t *buf, uint32_t count)
ra8_err_t ra8_sdmmc_spi_write_blocks (uint32_t lba, const uint8_t *buf, uint32_t count)
 Write count contiguous 512-byte blocks with 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.
static ra8_err_t internal_fs_read_block (void *ctx, uint64_t lba, uint32_t count, uint8_t *buf)
static ra8_err_t internal_fs_write_block (void *ctx, uint64_t lba, uint32_t count, const uint8_t *buf)
static ra8_err_t internal_fs_erase_block (void *ctx, uint64_t lba, uint64_t count)
static ra8_err_t internal_fs_get_capacity (void *ctx, uint64_t *block_count, uint32_t *block_size)
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.

Variables

static const char * s_tag = "SDSPI"
 Log tag for diagnostics emitted by this module.
static sci_bus_ctx_t s_sci_ctx
 Single-shot bus context backing the factory's transport callbacks.

Detailed Description

SD card driver in SPI-mode – public block I/O and SCI factory.

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

Block-level public API of the SPI-mode SD card driver declared in ra8_sdmmc_spi.h: init/deinit, single- and multi-block read/write, erase, capacity/type queries, the ra8_fs backend adapter, and the convenience SCI Simple-SPI transport factory (Pmod SD on EK-RA8D2).

The wire-level protocol primitives (CRC, command framing, the card identification sequence) live in the sibling translation unit ra8_sdmmc_spi.c; this unit reaches them through the module-private ra8_sdmmc_spi_internal.h surface. All data-token, data-response, and CRC behaviour follows SD Specification Part 1 Physical Layer Simplified Specification v9.10 section 7 ("SPI Mode").

Since
0.1.0

Definition in file ra8_sdmmc_spi_io.c.

Function Documentation

◆ internal_cmd_require_ready()

ra8_err_t internal_cmd_require_ready ( sd_cmd_t cmd,
uint32_t arg )
static

◆ internal_erase_range()

◆ internal_finalize_init()

ra8_err_t internal_finalize_init ( void )
static

◆ internal_fs_erase_block()

ra8_err_t internal_fs_erase_block ( void * ctx,
uint64_t lba,
uint64_t count )
static

◆ internal_fs_get_capacity()

ra8_err_t internal_fs_get_capacity ( void * ctx,
uint64_t * block_count,
uint32_t * block_size )
static

◆ internal_fs_read_block()

ra8_err_t internal_fs_read_block ( void * ctx,
uint64_t lba,
uint32_t count,
uint8_t * buf )
static

◆ internal_fs_write_block()

ra8_err_t internal_fs_write_block ( void * ctx,
uint64_t lba,
uint32_t count,
const uint8_t * buf )
static

◆ internal_lba_to_arg()

◆ internal_prepare_init()

◆ internal_read_block_crc_check()

◆ internal_read_block_payload()

ra8_err_t internal_read_block_payload ( uint8_t * buf)
static

◆ internal_read_data_phase()

◆ internal_read_multi_stop()

ra8_err_t internal_read_multi_stop ( void )
static

◆ internal_read_multi_stream()

ra8_err_t internal_read_multi_stream ( uint8_t * buf,
uint32_t count )
static

◆ internal_sci_transport_bringup()

ra8_err_t internal_sci_transport_bringup ( uint8_t channel,
uint32_t pclk_hz,
const ra8_sdmmc_spi_sci_pins_t * pins )
static

Route the four Pmod SPI pins and bring up the SCI Simple-SPI channel.

Muxes SCK/CIPO/COPI to the SCI async function, claims CS as a GPIO output held high, then initialises the SCI channel at the SD power-on clock. All HAL calls are reused (no register access here).

Parameters
[in]channelSCI channel index (0..9).
[in]pclk_hzPCLKA rate (Hz) feeding the baud divider; non-zero.
[in]pinsNon-NULL SCK / CIPO / COPI / CS descriptor.
Returns
ra8_err_t Error code.
Return values
k_ra8_okPins routed, CS claimed high, SCI channel up.
k_ra8_err_null_ptrpins is NULL.
otherPropagated from ra8_pfs_route_peripheral / ra8_gpio_output_init / ra8_sci_spi_init.
Precondition
ra8_cgc_init has run; pclk_hz is the live PCLKA rate.
The four pins are free (not routed to another peripheral).
Postcondition
On success the four pins are muxed and the SCI channel is configured.
On failure the affected pins are left in their prior state.
Note
CS is a plain GPIO output (SD SPI-mode holds CS across a frame).
Since
0.1.0

Definition at line 177 of file ra8_sdmmc_spi_io.c.

References ra8_sdmmc_spi_sci_pins_t::cipo, ra8_sdmmc_spi_sci_pins_t::copi, ra8_sdmmc_spi_sci_pins_t::cs, k_ra8_level_high, k_ra8_ok, k_ra8_psel_sci_async, k_ra8_sdmmc_spi_clock_init_hz, k_ra8_spi_mode_0, RA8_CHECK_NULL_PTR, ra8_gpio_output_init(), RA8_INTERNAL, ra8_pfs_route_peripheral(), ra8_sci_spi_init(), s_tag, and ra8_sdmmc_spi_sci_pins_t::sck.

Referenced by ra8_sdmmc_spi_transport_sci().

◆ internal_sci_transport_cs()

ra8_err_t internal_sci_transport_cs ( void * ctx,
bool asserted )
static

Factory transport chip-select shim: drive CS low (asserted) or high.

Drives the chip-select GPIO from the bus context (active-low select); carries no register access of its own.

Parameters
[in]ctxBus context (sci_bus_ctx_t*); must be non-NULL.
[in]assertedtrue to select (CS low), false to release (CS high).
Returns
ra8_err_t passthrough from ra8_gpio_write.
Return values
k_ra8_okCS driven to the requested level.
k_ra8_err_null_ptrctx is NULL.
Precondition
ctx points to the live s_sci_ctx.
The CS pin was claimed as a GPIO output by ra8_sdmmc_spi_transport_sci.
Postcondition
On success the CS pin reflects asserted.
No other pin or bus state changes.
Note
ISR-unsafe. ctx is non-const to match the transport function-pointer type (constParameterCallback suppressed in-tree).
Since
0.1.0

Definition at line 123 of file ra8_sdmmc_spi_io.c.

References sci_bus_ctx_t::cs, k_ra8_level_high, k_ra8_level_low, RA8_CHECK_NULL_PTR, ra8_gpio_write(), RA8_INTERNAL, and s_tag.

Referenced by ra8_sdmmc_spi_transport_sci().

◆ internal_sci_transport_set_clock()

ra8_err_t internal_sci_transport_set_clock ( void * ctx,
uint32_t hz )
static

Factory transport set-clock shim: retune the SCI baud divider.

Recovers the SCI channel + PCLKA from the bus context and forwards to ra8_sci_spi_set_clock; carries no register access of its own.

Parameters
[in]ctxBus context (sci_bus_ctx_t*); must be non-NULL.
[in]hzTarget SPI clock in Hz.
Returns
ra8_err_t passthrough from ra8_sci_spi_set_clock.
Return values
k_ra8_okBaud divider retuned.
k_ra8_err_null_ptrctx is NULL.
Precondition
ctx points to the live s_sci_ctx.
ra8_sci_spi_init has configured the SCI channel.
Postcondition
On success the SCI channel clock is retuned to hz.
No bus transaction is issued (clock configuration only).
Note
ISR-unsafe; blocking. ctx is non-const to match the transport function-pointer type (constParameterCallback suppressed in-tree).
Since
0.1.0

Definition at line 98 of file ra8_sdmmc_spi_io.c.

References sci_bus_ctx_t::channel, sci_bus_ctx_t::pclka_hz, RA8_CHECK_NULL_PTR, RA8_INTERNAL, ra8_sci_spi_set_clock(), and s_tag.

Referenced by ra8_sdmmc_spi_transport_sci().

◆ internal_sci_transport_xfer()

ra8_err_t internal_sci_transport_xfer ( void * ctx,
const uint8_t * tx,
uint8_t * rx,
uint32_t len )
static

Factory transport transfer shim: full-duplex byte exchange.

Forwards a full-duplex byte exchange to the SCI channel from the bus context; carries no register access of its own.

Parameters
[in]ctxBus context (sci_bus_ctx_t*); must be non-NULL.
[in]txTX bytes, or NULL to shift idle 0xFF.
[out]rxRX buffer, or NULL to discard.
[in]lenByte count; must be > 0.
Returns
ra8_err_t passthrough from ra8_sci_spi_xfer.
Return values
k_ra8_oklen bytes clocked on the bus.
k_ra8_err_null_ptrctx is NULL.
Precondition
ctx points to the live s_sci_ctx.
ra8_sci_spi_init configured the channel and CS is asserted.
Postcondition
On success rx holds the received bytes when non-NULL.
No state beyond rx and the SCI data registers is modified.
Note
ISR-unsafe; blocking. ctx is non-const to match the transport function-pointer type (constParameterCallback suppressed in-tree).
Since
0.1.0

Definition at line 150 of file ra8_sdmmc_spi_io.c.

References sci_bus_ctx_t::channel, RA8_CHECK_NULL_PTR, ra8_sci_spi_xfer(), and s_tag.

Referenced by ra8_sdmmc_spi_transport_sci().

◆ internal_write_data_block()

◆ internal_write_multi_stream()

◆ 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_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 with one CMD25 transaction.

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().

Variable Documentation

◆ s_sci_ctx

sci_bus_ctx_t s_sci_ctx
static

Single-shot bus context backing the factory's transport callbacks.

Warning
Mutated by ra8_sdmmc_spi_transport_sci; not thread-safe and only one SD bus may be brought up through the factory at a time.
Since
0.1.0

Definition at line 79 of file ra8_sdmmc_spi_io.c.

Referenced by ra8_sdmmc_spi_transport_sci().

◆ s_tag

const char* s_tag = "SDSPI"
static

Log tag for diagnostics emitted by this module.

Note
File-scope, read-only after init.
Since
0.1.0

Definition at line 51 of file ra8_sdmmc_spi_io.c.