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

SD card driver in SPI-mode – protocol implementation. More...

#include "ra8_sdmmc_spi.h"
#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_core_contracts_internal.h"
#include "ra8_sdmmc_spi_internal.h"
#include "ra8_spi.h"
Include dependency graph for ra8_sdmmc_spi.c:

Go to the source code of this file.

Enumerations

enum  sd_csd_field_t : uint32_t {
  k_sd_cmd_frame_len = 5U ,
  k_sd_csize_msb_mask = 0x3FU ,
  k_sd_read_bl_mask = 0x0FU ,
  k_sd_csize_shift = 10U ,
  k_sd_csize_lo_mask = 0xC0U ,
  k_sd_mult_lo_mask = 0x80U ,
  k_sd_mult_shift = 7U
}
 SD CSD field masks/shifts and command framing. More...
enum  sd_r1_bit_t : uint8_t {
  k_sd_r1_idle_state = 0x01U ,
  k_sd_r1_erase_reset = 0x02U ,
  k_sd_r1_illegal_command = 0x04U ,
  k_sd_r1_com_crc_error = 0x08U ,
  k_sd_r1_erase_sequence_error = 0x10U ,
  k_sd_r1_address_error = 0x20U ,
  k_sd_r1_parameter_error = 0x40U ,
  k_sd_r1_sentinel = 0x80U
}
 R1 response bit definitions (SD spec PHY v9 section 7.3.2.1). More...
enum  sd_cmd_arg_idx_t : uint8_t {
  k_sd_frame_idx_cmd = 0U ,
  k_sd_frame_idx_arg_msb = 1U ,
  k_sd_frame_idx_arg_byte2 = 2U ,
  k_sd_frame_idx_arg_byte1 = 3U ,
  k_sd_frame_idx_arg_lsb = 4U ,
  k_sd_frame_idx_crc = 5U
}
 Byte indices inside a 6-byte SD command frame. More...
enum  sd_csd_layout_t : uint8_t {
  k_sd_csd_byte_version = 0U ,
  k_sd_csd_version_shift = 6U ,
  k_sd_csd_v2_byte_csize_msb = 7U ,
  k_sd_csd_v2_byte_csize_mid = 8U ,
  k_sd_csd_v2_byte_csize_lsb = 9U ,
  k_sd_csd_v2_blocks_shift = 10U
}
 Selected CSD-byte indices and bit shifts (SD spec PHY v9 section 5). More...
enum  sd_crc7_const_t : uint8_t {
  k_sd_crc7_msb_test = 0x40U ,
  k_sd_crc7_byte_msb = 0x80U ,
  k_sd_crc7_register_mask = 0x7FU ,
  k_sd_crc7_poly_low7 = 0x09U
}
 CRC7 polynomial and mask constants (SD spec PHY v9 section 4.5). More...
enum  sd_crc16_const_t : uint16_t {
  k_sd_crc16_msb_test = 0x8000U ,
  k_sd_crc16_poly = 0x1021U
}
 CRC16-CCITT polynomial and mask constants (SD spec PHY v9 section 4.5). More...

Functions

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.
ra8_err_t priv_sdmmc_spi_xfer_one (uint8_t tx, uint8_t *rx)
 Shift out one byte and capture the response over the transport.
ra8_err_t priv_sdmmc_spi_send_idle (uint32_t n)
 Shift n idle bytes (0xFF) and discard the response.
ra8_err_t priv_sdmmc_spi_cs_assert (void)
 Drive CS low and clock a single idle byte so CIPO is sampled.
ra8_err_t priv_sdmmc_spi_cs_release (void)
 Drive CS high after clocking one idle byte (SD spec section 7.2.4).
static void internal_build_frame (sd_cmd_t cmd, uint32_t arg, uint8_t *out_frame)
static ra8_err_t internal_read_r1 (uint8_t *out_r1)
ra8_err_t priv_sdmmc_spi_send_command (sd_cmd_t cmd, uint32_t arg, uint8_t *out_r1)
 Send a command frame and capture the R1 response byte.
ra8_err_t priv_sdmmc_spi_send_acmd (sd_cmd_t acmd, uint32_t arg, uint8_t *out_r1)
 Send an ACMD by prefixing it with CMD55 (APP_CMD).
ra8_err_t priv_sdmmc_spi_send_stop_transmission (uint8_t *out_r1)
 Send CMD12 (STOP_TRANSMISSION) and capture its R1 response byte.
static ra8_err_t internal_read_r3_or_r7_tail (uint32_t *out_word)
ra8_err_t priv_sdmmc_spi_wait_data_token (void)
 Poll for the data-start token (0xFE), bounded by a retry budget.
ra8_err_t priv_sdmmc_spi_wait_not_busy_bounded (uint32_t max_polls)
 Wait for the card to release busy (CIPO -> 0xFF), bounded by max_polls.
ra8_err_t priv_sdmmc_spi_wait_not_busy (void)
 Wait for the card to release the busy token (CIPO returns to 0xFF).
static uint32_t internal_csd_to_blocks (const uint8_t *csd)
ra8_err_t priv_sdmmc_spi_validate_transport (const ra8_sdmmc_spi_transport_t *transport)
 Validate the transport descriptor: every callback non-NULL.
static void internal_recover_stuck_card (void)
 Best-effort recovery for a card stranded mid-write by an interrupted transaction (e.g.
static ra8_err_t internal_wake_card (void)
static ra8_err_t internal_send_cmd0 (void)
static ra8_err_t internal_send_cmd8 (bool *out_is_v2)
static ra8_err_t internal_acmd41_loop (bool is_v2)
static ra8_err_t internal_read_ocr (bool *out_is_hc)
static ra8_err_t internal_read_csd (uint32_t *out_blocks)
static ra8_err_t internal_set_block_len (void)
static ra8_sdmmc_spi_card_type_t internal_classify_card (bool is_v2, bool is_hc)
static ra8_err_t internal_probe_card (bool *out_is_v2, bool *out_is_hc)
ra8_err_t priv_sdmmc_spi_run_init_sequence (void)
 Walk the full SD identification sequence and learn capacity / type.

Variables

static const char * s_tag = "SDSPI"
 Log tag for diagnostics emitted by this module.
sd_state_t g_sdmmc_spi_state = {}
 Single driver instance (the module's one external definition).

Detailed Description

SD card driver in SPI-mode – protocol implementation.

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

Implementation of the SPI-mode SD card driver declared in ra8_sdmmc_spi.h. The protocol follows SD Specification Part 1 Physical Layer Simplified Specification v9.10 section 7 ("SPI Mode"). Command framing, response classes (R1, R1b, R3, R7), data tokens, CRC7 and CRC16 polynomials, and the v1.x vs v2.x card discrimination flow are all documented inline at their first use.

The driver is transport-agnostic: every byte exchange goes through the caller-supplied ra8_sdmmc_spi_transport_t. This lets the host tests inject a mock and the firmware app inject the real ra8_spi HAL driver through a thin shim that lives in the example app.

Definition in file ra8_sdmmc_spi.c.

Enumeration Type Documentation

◆ sd_cmd_arg_idx_t

enum sd_cmd_arg_idx_t : uint8_t

Byte indices inside a 6-byte SD command frame.

Frame layout (SD spec PHY v9 section 7.3.1.1 "Command Format"): byte 0 = 0x40 | cmd_index; bytes 1..4 = arg MSB..LSB; byte 5 = (CRC7 << 1) | 1.

Enumerator
k_sd_frame_idx_cmd 

SD frame index cmd.

k_sd_frame_idx_arg_msb 

SD frame index arg msb.

k_sd_frame_idx_arg_byte2 

SD frame index arg byte2.

k_sd_frame_idx_arg_byte1 

SD frame index arg byte1.

k_sd_frame_idx_arg_lsb 

SD frame index arg lsb.

k_sd_frame_idx_crc 

SD frame index CRC.

Definition at line 94 of file ra8_sdmmc_spi.c.

◆ sd_crc16_const_t

enum sd_crc16_const_t : uint16_t

CRC16-CCITT polynomial and mask constants (SD spec PHY v9 section 4.5).

CRC16-CCITT generator polynomial G(x) = x^16 + x^12 + x^5 + 1 encoded as 0x1021 with the implicit x^16 term. k_sd_crc16_msb_test isolates the top bit of the 16-bit working register so the test can decide whether to XOR the polynomial in.

Enumerator
k_sd_crc16_msb_test 

Top bit of the 16-bit working CRC.

k_sd_crc16_poly 

CRC16-CCITT polynomial.

Definition at line 146 of file ra8_sdmmc_spi.c.

◆ sd_crc7_const_t

enum sd_crc7_const_t : uint8_t

CRC7 polynomial and mask constants (SD spec PHY v9 section 4.5).

CRC7 generator polynomial G(x) = x^7 + x^3 + 1. Stored as a 7-bit value in the low bits of a byte; the mask keeps the working CRC register inside 7 bits while shifting.

Enumerator
k_sd_crc7_msb_test 

Top bit of the 7-bit working CRC.

k_sd_crc7_byte_msb 

Top bit of an input byte.

k_sd_crc7_register_mask 

Mask the 7-bit working register.

k_sd_crc7_poly_low7 

G(x) low 7 bits: 0b0001001.

Definition at line 128 of file ra8_sdmmc_spi.c.

◆ sd_csd_field_t

enum sd_csd_field_t : uint32_t

SD CSD field masks/shifts and command framing.

Enumerator
k_sd_cmd_frame_len 

Command bytes preceding the CRC7.

k_sd_csize_msb_mask 

CSD v2 C_SIZE MSB field (6-bit).

k_sd_read_bl_mask 

READ_BL_LEN (4-bit).

k_sd_csize_shift 

CSD v1 C_SIZE high-bits shift.

k_sd_csize_lo_mask 

CSD v1 C_SIZE low 2 bits (byte 8).

k_sd_mult_lo_mask 

C_SIZE_MULT low bit (byte 10).

k_sd_mult_shift 

C_SIZE_MULT low-bit shift.

Definition at line 59 of file ra8_sdmmc_spi.c.

◆ sd_csd_layout_t

enum sd_csd_layout_t : uint8_t

Selected CSD-byte indices and bit shifts (SD spec PHY v9 section 5).

Enumerator
k_sd_csd_byte_version 

SD csd byte version.

k_sd_csd_version_shift 

SD csd version shift.

k_sd_csd_v2_byte_csize_msb 

SD csd v2 byte csize msb.

k_sd_csd_v2_byte_csize_mid 

SD csd v2 byte csize mid.

k_sd_csd_v2_byte_csize_lsb 

SD csd v2 byte csize lsb.

k_sd_csd_v2_blocks_shift 

SD csd v2 blocks shift.

Definition at line 107 of file ra8_sdmmc_spi.c.

◆ sd_r1_bit_t

enum sd_r1_bit_t : uint8_t

R1 response bit definitions (SD spec PHY v9 section 7.3.2.1).

Enumerator
k_sd_r1_idle_state 

SD r1 idle state.

k_sd_r1_erase_reset 

SD r1 erase reset.

k_sd_r1_illegal_command 

SD r1 illegal command.

k_sd_r1_com_crc_error 

SD r1 com CRC error.

k_sd_r1_erase_sequence_error 

SD r1 erase sequence error.

k_sd_r1_address_error 

SD r1 address error.

k_sd_r1_parameter_error 

SD r1 parameter error.

k_sd_r1_sentinel 

SD r1 sentinel.

Definition at line 73 of file ra8_sdmmc_spi.c.

Function Documentation

◆ internal_acmd41_loop()

◆ internal_build_frame()

◆ internal_classify_card()

ra8_sdmmc_spi_card_type_t internal_classify_card ( bool is_v2,
bool is_hc )
static

◆ internal_csd_to_blocks()

◆ internal_probe_card()

◆ internal_read_csd()

◆ internal_read_ocr()

◆ internal_read_r1()

◆ internal_read_r3_or_r7_tail()

ra8_err_t internal_read_r3_or_r7_tail ( uint32_t * out_word)
static

◆ internal_recover_stuck_card()

void internal_recover_stuck_card ( void )
static

Best-effort recovery for a card stranded mid-write by an interrupted transaction (e.g.

an MCU reset during a long format).

Four phases, each safe to run against an already-idle card (0xFD and 0xFF are both non-command bytes that clock past as idle, and CMD12 on an idle card is a no-op that returns to idle):

  1. CS released, a long idle burst – lets a card still BUSY (programming) from the interrupted write drain its internal timer, and resets the card's byte framing for the next CS assertion (a reset mid-byte can leave it misaligned).
  2. CS asserted, a stop-tran token then >= 512 + CRC idle bytes – aborts a wedged CMD25 multi-block write and completes a wedged CMD24 single-block data phase, so the card programs the slack and returns to the transfer state; then wait out the programming.
  3. CMD12 STOP_TRANSMISSION – aborts any open multi-block transfer the card still believes is active; wait out the trailing busy.
  4. CS released, a final idle burst to settle framing before the wake/CMD0.

Run before each wake/CMD0 retry so a stuck card can re-init without a physical power cycle. (Limits: cannot recover a card whose controller needs a true power-on reset, since the MCU cannot remove card VBUS.)

Returns
None.
Precondition
The transport is bound (called from the init probe).
All transport callbacks (cs, xfer) are non-NULL in g_sdmmc_spi_state.transport.
Postcondition
Any in-flight write/read transaction is terminated and the bus is idle.
CS is released.
Note
Not thread-safe; part of single-threaded init.
Since
0.1.0

Definition at line 532 of file ra8_sdmmc_spi.c.

References g_sdmmc_spi_state, k_ra8_ok, k_sd_cmd_stop_transmission, k_sd_recover_flush_bytes, k_sd_recover_idle_bytes, k_sd_token_stop_multi, priv_sdmmc_spi_send_command(), priv_sdmmc_spi_send_idle(), priv_sdmmc_spi_wait_not_busy(), priv_sdmmc_spi_xfer_one(), and RA8_INTERNAL.

Referenced by internal_probe_card().

◆ internal_send_cmd0()

◆ internal_send_cmd8()

◆ internal_set_block_len()

◆ internal_wake_card()

ra8_err_t internal_wake_card ( void )
static

◆ priv_sdmmc_spi_cs_assert()

ra8_err_t priv_sdmmc_spi_cs_assert ( void )

Drive CS low and clock a single idle byte so CIPO is sampled.

Selects the card and emits one idle byte to align framing.

Returns
ra8_err_t Error code.
Return values
k_ra8_okCS asserted and one idle byte clocked.
otherPropagated from the transport cs / xfer callbacks.
Precondition
The transport is bound.
The transport cs callback is non-NULL.
Postcondition
On success CS is asserted (low).
One idle byte has been clocked on success.
Note
Not thread-safe.
Since
0.1.0

Definition at line 249 of file ra8_sdmmc_spi.c.

References g_sdmmc_spi_state, k_ra8_ok, priv_sdmmc_spi_send_idle(), and RA8_PRIV.

Referenced by internal_acmd41_loop(), internal_cmd_require_ready(), internal_erase_range(), internal_read_csd(), internal_read_ocr(), internal_send_cmd0(), internal_send_cmd8(), internal_set_block_len(), ra8_sdmmc_spi_read_block(), ra8_sdmmc_spi_read_blocks(), ra8_sdmmc_spi_write_block(), and ra8_sdmmc_spi_write_blocks().

◆ priv_sdmmc_spi_cs_release()

ra8_err_t priv_sdmmc_spi_cs_release ( void )

Drive CS high after clocking one idle byte (SD spec section 7.2.4).

Releases the card and emits trailing idle clocks so the card can finish any pending internal state transition.

Returns
ra8_err_t Error code.
Return values
k_ra8_okCS released and one idle byte clocked.
otherPropagated from the transport cs / xfer callbacks.
Precondition
The transport is bound.
The transport cs callback is non-NULL.
Postcondition
On success CS is released (high).
One idle byte has been clocked on success.
Note
Not thread-safe.
Since
0.1.0

Definition at line 260 of file ra8_sdmmc_spi.c.

References g_sdmmc_spi_state, k_ra8_ok, priv_sdmmc_spi_send_idle(), and RA8_PRIV.

Referenced by internal_acmd41_loop(), internal_cmd_require_ready(), internal_erase_range(), internal_read_csd(), internal_read_ocr(), internal_send_cmd0(), internal_send_cmd8(), internal_set_block_len(), ra8_sdmmc_spi_read_block(), ra8_sdmmc_spi_read_blocks(), ra8_sdmmc_spi_write_block(), and ra8_sdmmc_spi_write_blocks().

◆ priv_sdmmc_spi_run_init_sequence()

ra8_err_t priv_sdmmc_spi_run_init_sequence ( void )

Walk the full SD identification sequence and learn capacity / type.

Runs the CMD0/CMD8/ACMD41/CMD58/CMD9/CMD16 probe and records the card type and capacity into g_sdmmc_spi_state.

Returns
ra8_err_t Error code.
Return values
k_ra8_okCard identified; type and capacity cached.
k_ra8_err_protocol_errorA response was malformed.
otherPropagated from the probe steps.
Precondition
The transport is bound and the init clock is set.
CS is released on entry.
Postcondition
On success ::g_sdmmc_spi_state.card_type and .capacity_blocks are set.
CS is released.
Note
Not thread-safe; single-threaded init.
Since
0.1.0

Definition at line 777 of file ra8_sdmmc_spi.c.

References g_sdmmc_spi_state, internal_classify_card(), internal_probe_card(), internal_read_csd(), internal_set_block_len(), k_ra8_ok, RA8_PRIV, RA8_RETURN_ON_ERROR, and s_tag.

Referenced by ra8_sdmmc_spi_init().

◆ priv_sdmmc_spi_send_acmd()

ra8_err_t priv_sdmmc_spi_send_acmd ( sd_cmd_t acmd,
uint32_t arg,
uint8_t * out_r1 )

Send an ACMD by prefixing it with CMD55 (APP_CMD).

Issues CMD55 then the application command, returning the application command's R1.

Parameters
[in]acmdApplication command wire byte.
[in]arg32-bit command argument.
[out]out_r1Captured R1 response byte of the application command.
Returns
ra8_err_t Error code.
Return values
k_ra8_okBoth commands sent and R1 captured.
otherPropagated from the transport callbacks.
Precondition
The transport is bound.
out_r1 is non-NULL.
Postcondition
On success out_r1 holds the application command R1.
No driver state beyond out_r1 is modified.
Note
Not thread-safe.
Since
0.1.0

Definition at line 333 of file ra8_sdmmc_spi.c.

References k_ra8_ok, k_sd_cmd_app_cmd, priv_sdmmc_spi_send_command(), and RA8_PRIV.

Referenced by internal_acmd41_loop(), and ra8_sdmmc_spi_write_blocks().

◆ priv_sdmmc_spi_send_command()

ra8_err_t priv_sdmmc_spi_send_command ( sd_cmd_t cmd,
uint32_t arg,
uint8_t * out_r1 )

Send a command frame and capture the R1 response byte.

Builds the 6-byte frame (CRC7 included), clocks it out, then polls for the R1 token.

Parameters
[in]cmdCommand wire byte.
[in]arg32-bit command argument.
[out]out_r1Captured R1 response byte.
Returns
ra8_err_t Error code.
Return values
k_ra8_okCommand sent and R1 captured.
k_ra8_err_hw_timeoutR1 did not appear within budget.
otherPropagated from the transport callbacks.
Precondition
The transport is bound.
out_r1 is non-NULL.
Postcondition
On success out_r1 holds the R1 byte.
No driver state beyond out_r1 is modified.
Note
Not thread-safe.
Since
0.1.0

Definition at line 316 of file ra8_sdmmc_spi.c.

References g_sdmmc_spi_state, internal_build_frame(), internal_read_r1(), k_ra8_ok, k_ra8_sdmmc_spi_cmd_frame_bytes, and RA8_PRIV.

Referenced by internal_cmd_require_ready(), internal_erase_range(), internal_read_csd(), internal_read_data_phase(), internal_read_ocr(), internal_recover_stuck_card(), internal_send_cmd0(), internal_send_cmd8(), internal_set_block_len(), priv_sdmmc_spi_send_acmd(), ra8_sdmmc_spi_read_blocks(), ra8_sdmmc_spi_write_block(), and ra8_sdmmc_spi_write_blocks().

◆ priv_sdmmc_spi_send_idle()

ra8_err_t priv_sdmmc_spi_send_idle ( uint32_t n)

Shift n idle bytes (0xFF) and discard the response.

Bounded by n; clocks the bus idle to advance card timers.

Parameters
[in]nNumber of idle bytes to clock.
Returns
ra8_err_t Error code.
Return values
k_ra8_okAll n bytes clocked.
otherPropagated from the transport xfer callback.
Precondition
The transport is bound.
The transport xfer callback is non-NULL.
Postcondition
Exactly n idle bytes were clocked on success.
No driver state is modified.
Note
Not thread-safe.
Since
0.1.0

Definition at line 235 of file ra8_sdmmc_spi.c.

References k_ra8_ok, k_sd_token_idle, priv_sdmmc_spi_xfer_one(), and RA8_PRIV.

Referenced by internal_recover_stuck_card(), internal_wake_card(), internal_write_data_block(), internal_write_multi_stream(), priv_sdmmc_spi_cs_assert(), priv_sdmmc_spi_cs_release(), and priv_sdmmc_spi_send_stop_transmission().

◆ priv_sdmmc_spi_send_stop_transmission()

ra8_err_t priv_sdmmc_spi_send_stop_transmission ( uint8_t * out_r1)

Send CMD12 (STOP_TRANSMISSION) and capture its R1 response byte.

Builds and clocks the 6-byte CMD12 frame, discards the one stuff byte that follows it (the tail of the interrupted read stream – its value is undefined, and a bit7-clear garbage byte would be misread as R1), then polls for the R1 token. Terminates a CMD18 READ_MULTIPLE_BLOCK stream; the plain priv_sdmmc_spi_send_command cannot be used because it polls for R1 straight after the frame.

Parameters
[out]out_r1Captured R1 response byte.
Returns
ra8_err_t Error code.
Return values
k_ra8_okCMD12 sent and R1 captured.
k_ra8_err_hw_timeoutR1 did not appear within budget.
otherPropagated from the transport callbacks.
Precondition
The transport is bound.
out_r1 is non-NULL.
Postcondition
On success out_r1 holds the CMD12 R1 byte.
No driver state beyond out_r1 is modified.
Note
Not thread-safe.
Since
0.1.0

Definition at line 346 of file ra8_sdmmc_spi.c.

References g_sdmmc_spi_state, internal_build_frame(), internal_read_r1(), k_ra8_ok, k_ra8_sdmmc_spi_cmd_frame_bytes, k_sd_cmd_stop_transmission, priv_sdmmc_spi_send_idle(), and RA8_PRIV.

Referenced by internal_read_multi_stop().

◆ priv_sdmmc_spi_validate_transport()

ra8_err_t priv_sdmmc_spi_validate_transport ( const ra8_sdmmc_spi_transport_t * transport)

Validate the transport descriptor: every callback non-NULL.

Rejects a NULL descriptor or any NULL callback before bind.

Parameters
[in]transportTransport descriptor to check.
Returns
ra8_err_t Error code.
Return values
k_ra8_okDescriptor and all callbacks are non-NULL.
k_ra8_err_null_ptrtransport is NULL.
k_ra8_err_invalid_argA callback is NULL.
Precondition
None.
None.
Postcondition
No driver state is modified.
Return reflects only the descriptor contents.
Note
Not thread-safe.
Since
0.1.0

Definition at line 488 of file ra8_sdmmc_spi.c.

References k_ra8_err_invalid_arg, k_ra8_err_null_ptr, k_ra8_ok, and RA8_PRIV.

Referenced by ra8_sdmmc_spi_init().

◆ priv_sdmmc_spi_wait_data_token()

ra8_err_t priv_sdmmc_spi_wait_data_token ( void )

Poll for the data-start token (0xFE), bounded by a retry budget.

Clocks idle bytes until the single-block data-start token appears or the poll budget is exhausted.

Returns
ra8_err_t Error code.
Return values
k_ra8_okData-start token observed.
k_ra8_err_hw_timeoutToken did not appear within budget.
otherPropagated from the transport callbacks.
Precondition
The transport is bound.
CS is asserted by the caller.
Postcondition
On success the next byte clocked is the first payload byte.
No driver state is modified.
Note
Not thread-safe.
Since
0.1.0

Definition at line 404 of file ra8_sdmmc_spi.c.

References k_ra8_err_hw_timeout, k_ra8_ok, k_sd_max_data_token_polls, k_sd_token_data_start_single, k_sd_token_idle, priv_sdmmc_spi_xfer_one(), and RA8_PRIV.

Referenced by internal_read_csd(), internal_read_data_phase(), and internal_read_multi_stream().

◆ priv_sdmmc_spi_wait_not_busy()

ra8_err_t priv_sdmmc_spi_wait_not_busy ( void )

Wait for the card to release the busy token (CIPO returns to 0xFF).

Convenience wrapper over priv_sdmmc_spi_wait_not_busy_bounded with the default worst-case write timeout.

Returns
ra8_err_t Error code.
Return values
k_ra8_okCard released busy.
k_ra8_err_hw_timeoutCard stayed busy beyond the default budget.
otherPropagated from the transport callbacks.
Precondition
The transport is bound.
CS is asserted by the caller.
Postcondition
On success the card is no longer busy.
No driver state is modified.
Note
Not thread-safe.
Since
0.1.0

Definition at line 438 of file ra8_sdmmc_spi.c.

References k_sd_max_busy_poll_bytes, priv_sdmmc_spi_wait_not_busy_bounded(), and RA8_PRIV.

Referenced by internal_read_multi_stop(), internal_recover_stuck_card(), internal_write_data_block(), and internal_write_multi_stream().

◆ priv_sdmmc_spi_wait_not_busy_bounded()

ra8_err_t priv_sdmmc_spi_wait_not_busy_bounded ( uint32_t max_polls)

Wait for the card to release busy (CIPO -> 0xFF), bounded by max_polls.

Clocks idle bytes until the card stops holding CIPO low or the poll budget is exhausted.

Parameters
[in]max_pollsMaximum idle bytes to clock before timing out.
Returns
ra8_err_t Error code.
Return values
k_ra8_okCard released busy.
k_ra8_err_hw_timeoutCard stayed busy beyond max_polls.
otherPropagated from the transport callbacks.
Precondition
The transport is bound.
CS is asserted by the caller.
Postcondition
On success the card is no longer busy.
No driver state is modified.
Note
Not thread-safe.
Since
0.1.0

Definition at line 421 of file ra8_sdmmc_spi.c.

References k_ra8_err_hw_timeout, k_ra8_ok, k_sd_token_idle, priv_sdmmc_spi_xfer_one(), and RA8_PRIV.

Referenced by internal_erase_range(), and priv_sdmmc_spi_wait_not_busy().

◆ priv_sdmmc_spi_xfer_one()

ra8_err_t priv_sdmmc_spi_xfer_one ( uint8_t tx,
uint8_t * rx )

Shift out one byte and capture the response over the transport.

Wraps a single-byte full-duplex transfer through the bound g_sdmmc_spi_state.transport so callers need not stage 1-byte buffers themselves.

Parameters
[in]txByte to clock out.
[out]rxReceived byte, or NULL to discard.
Returns
ra8_err_t Error code.
Return values
k_ra8_okByte exchanged.
otherPropagated from the transport xfer callback.
Precondition
The transport is bound (driver init has begun).
The transport xfer callback is non-NULL.
Postcondition
On success rx holds the received byte when non-NULL.
No driver state beyond rx is modified.
Note
Not thread-safe.
Since
0.1.0

Definition at line 218 of file ra8_sdmmc_spi.c.

References g_sdmmc_spi_state, k_ra8_ok, and RA8_PRIV.

Referenced by internal_read_block_crc_check(), internal_read_block_payload(), internal_read_csd(), internal_read_r1(), internal_read_r3_or_r7_tail(), internal_recover_stuck_card(), internal_write_data_block(), internal_write_multi_stream(), priv_sdmmc_spi_send_idle(), priv_sdmmc_spi_wait_data_token(), and priv_sdmmc_spi_wait_not_busy_bounded().

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

Variable Documentation

◆ g_sdmmc_spi_state

sd_state_t g_sdmmc_spi_state = {}

Single driver instance (the module's one external definition).

Single driver instance, defined in ra8_sdmmc_spi.c.

Shared with the block-I/O TU through ra8_sdmmc_spi_internal.h; this file owns the sole definition.

Note
Internal mutable state; access from a single thread only.
Since
0.1.0

Mutable protocol state shared between the core/init TU and the block-I/O TU. Renamed with the module infix so it is link-unique.

Note
Internal mutable state; access from a single thread only.
Warning
Do not duplicate; exactly one definition exists in ra8_sdmmc_spi.c.
Since
0.1.0

Definition at line 164 of file ra8_sdmmc_spi.c.

Referenced by internal_finalize_init(), internal_fs_get_capacity(), internal_lba_to_arg(), internal_prepare_init(), internal_read_r3_or_r7_tail(), internal_recover_stuck_card(), internal_wake_card(), internal_write_data_block(), priv_sdmmc_spi_cs_assert(), priv_sdmmc_spi_cs_release(), priv_sdmmc_spi_run_init_sequence(), priv_sdmmc_spi_send_command(), priv_sdmmc_spi_send_stop_transmission(), priv_sdmmc_spi_xfer_one(), ra8_sdmmc_spi_bind_fs_backend(), ra8_sdmmc_spi_deinit(), ra8_sdmmc_spi_erase_blocks(), ra8_sdmmc_spi_get_capacity(), ra8_sdmmc_spi_get_card_type(), ra8_sdmmc_spi_read_block(), ra8_sdmmc_spi_read_blocks(), ra8_sdmmc_spi_write_block(), and ra8_sdmmc_spi_write_blocks().

◆ 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.c.