ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_sdmmc_spi.c
Go to the documentation of this file.
1
24
25#include "ra8_sdmmc_spi.h"
26
27#include <stdint.h>
28#include <string.h>
29
30#include "ra8_check.h"
31#include "ra8_err.h"
32#include "ra8_gpio_constants.h"
33#include "ra8_log.h"
34#include "ra8_port_utils.h"
35#include "ra8_sci_spi.h"
38#include "ra8_spi.h"
39
40/* ---------------------------------------------------------------------------
41 * Log tag
42 * ---------------------------------------------------------------------------
43 */
44
51static const char* s_tag = "SDSPI";
52
53/* ---------------------------------------------------------------------------
54 * Protocol constants (SD spec PHY v9 section 7)
55 * ---------------------------------------------------------------------------
56 */
57
68
73typedef enum : uint8_t {
81 /* The top bit (0x80) is always zero -- used as the R1 sentinel. */
84
102
107typedef enum : uint8_t {
108 /* CSD version lives in byte 0 bits 7:6: 0 = CSD v1, 1 = CSD v2. */
111 /* CSD v2: C_SIZE is a 22-bit field spanning bytes 7..9. */
115 /* Bit shift to go from C_SIZE to block count: ((C_SIZE + 1) * 1024). */
118
134
146typedef enum : uint16_t {
148 k_sd_crc16_poly = 0x1021U,
150
151/* ---------------------------------------------------------------------------
152 * Driver state (single global instance -- one card per board today)
153 * ---------------------------------------------------------------------------
154 */
155
165
166/* ===========================================================================
167 * CRC helpers (public for unit-test coverage)
168 * ===========================================================================
169 */
170
171uint8_t ra8_sdmmc_spi_crc7(const uint8_t* data, uint32_t len)
172{
173 uint8_t crc = 0U;
174 if (data == nullptr) {
175 return 0U;
176 }
177 for (uint32_t i = 0U; i < len; i++) {
178 uint8_t byte = data[i];
179 for (uint8_t b = 0U; b < (uint8_t)k_sd_bit_byte; b++) {
180 const uint8_t top = (uint8_t)((crc & (uint8_t)k_sd_crc7_msb_test) ^
181 ((byte & (uint8_t)k_sd_crc7_byte_msb) >> 1U));
182 crc = (uint8_t)((crc << 1U) & (uint8_t)k_sd_crc7_register_mask);
183 if (top != 0U) {
184 crc ^= (uint8_t)k_sd_crc7_poly_low7;
185 }
186 byte = (uint8_t)(byte << 1U);
187 }
188 }
189 return crc;
190}
191
192uint16_t ra8_sdmmc_spi_crc16(const uint8_t* data, uint32_t len)
193{
194 uint16_t crc = 0U;
195 if (data == nullptr) {
196 return 0U;
197 }
198 for (uint32_t i = 0U; i < len; i++) {
199 crc ^= (uint16_t)((uint16_t)data[i] << k_sd_bit_byte);
200 for (uint8_t b = 0U; b < (uint8_t)k_sd_bit_byte; b++) {
201 if ((crc & (uint16_t)k_sd_crc16_msb_test) != 0U) {
202 crc = (uint16_t)((crc << 1U) ^ (uint16_t)k_sd_crc16_poly);
203 } else {
204 crc = (uint16_t)(crc << 1U);
205 }
206 }
207 }
208 return crc;
209}
210
211/* ===========================================================================
212 * Low-level byte exchange wrappers
213 * ===========================================================================
214 */
215
216/* Shift out one byte and capture the response -- see implementation for
217 * details. */
219{
220 const uint8_t tx_buf[1] = {tx};
221 uint8_t rx_buf[1] = {};
222 ra8_err_t err =
223 g_sdmmc_spi_state.transport.xfer(g_sdmmc_spi_state.transport.ctx, tx_buf, rx_buf, 1U);
224 if (err != k_ra8_ok) {
225 return err;
226 }
227 if (rx != nullptr) {
228 *rx = rx_buf[0];
229 }
230 return k_ra8_ok;
231}
232
233/* Shift ``n`` idle bytes (0xFF) and discard the response -- see implementation
234 * for details. */
236{
237 uint8_t byte;
238 for (uint32_t i = 0U; i < n; i++) {
240 if (err != k_ra8_ok) {
241 return err;
242 }
243 }
244 return k_ra8_ok;
245}
246
247/* Drive CS low and clock a single idle byte so CIPO is sampled -- see
248 * implementation for details. */
250{
251 ra8_err_t err = g_sdmmc_spi_state.transport.cs(g_sdmmc_spi_state.transport.ctx, true);
252 if (err != k_ra8_ok) {
253 return err;
254 }
255 return priv_sdmmc_spi_send_idle(1U);
256}
257
258/* Drive CS high after clocking one idle byte (SD spec section 7.2.4) -- see
259 * implementation for details. */
261{
262 ra8_err_t err = g_sdmmc_spi_state.transport.cs(g_sdmmc_spi_state.transport.ctx, false);
263 if (err != k_ra8_ok) {
264 return err;
265 }
266 /* Clock 8 idle cycles after CS release so the card can finish any
267 * pending internal state transition (SD spec PHY v9 section 7.2.4). */
268 return priv_sdmmc_spi_send_idle(1U);
269}
270
271/* ===========================================================================
272 * Command framing
273 * ===========================================================================
274 */
275
276/* see header for full description */
277RA8_INTERNAL static void internal_build_frame(sd_cmd_t cmd, uint32_t arg, uint8_t* out_frame)
278{
279 out_frame[k_sd_frame_idx_cmd] = (uint8_t)cmd;
280 out_frame[k_sd_frame_idx_arg_msb] =
281 (uint8_t)((arg >> k_sd_bit_three_byte) & (uint32_t)k_sd_mask_byte);
282 out_frame[k_sd_frame_idx_arg_byte2] =
283 (uint8_t)((arg >> k_sd_bit_two_byte) & (uint32_t)k_sd_mask_byte);
284 out_frame[k_sd_frame_idx_arg_byte1] =
285 (uint8_t)((arg >> k_sd_bit_byte) & (uint32_t)k_sd_mask_byte);
286 out_frame[k_sd_frame_idx_arg_lsb] = (uint8_t)(arg & (uint32_t)k_sd_mask_byte);
287 if (cmd == k_sd_cmd_go_idle_state) {
288 out_frame[k_sd_frame_idx_crc] = (uint8_t)k_sd_crc7_cmd0_byte;
289 } else if ((cmd == k_sd_cmd_send_if_cond) && (arg == (uint32_t)k_sd_cmd8_arg_check_pattern)) {
290 out_frame[k_sd_frame_idx_crc] = (uint8_t)k_sd_crc7_cmd8_byte;
291 } else {
292 const uint8_t crc7 = ra8_sdmmc_spi_crc7(out_frame, k_sd_cmd_frame_len);
293 out_frame[k_sd_frame_idx_crc] = (uint8_t)(((uint32_t)crc7 << 1U) | 1U);
294 }
295}
296
297/* see header for full description */
299{
300 for (uint32_t i = 0U; i < (uint32_t)k_sd_max_r1_wait_bytes; i++) {
301 uint8_t byte = 0U;
303 if (err != k_ra8_ok) {
304 return err;
305 }
306 if ((byte & (uint8_t)k_sd_r1_sentinel) == 0U) {
307 *out_r1 = byte;
308 return k_ra8_ok;
309 }
310 }
312}
313
314/* Send a command frame and capture the R1 response byte -- see implementation
315 * for details. */
316RA8_PRIV ra8_err_t priv_sdmmc_spi_send_command(sd_cmd_t cmd, uint32_t arg, uint8_t* out_r1)
317{
318 uint8_t frame[k_ra8_sdmmc_spi_cmd_frame_bytes];
319 internal_build_frame(cmd, arg, frame);
320 uint8_t rx_dummy[k_ra8_sdmmc_spi_cmd_frame_bytes];
321 ra8_err_t err = g_sdmmc_spi_state.transport.xfer(g_sdmmc_spi_state.transport.ctx,
322 frame,
323 rx_dummy,
325 if (err != k_ra8_ok) {
326 return err;
327 }
328 return internal_read_r1(out_r1);
329}
330
331/* Send an ACMD by prefixing it with CMD55 (APP_CMD) -- see implementation for
332 * details. */
333RA8_PRIV ra8_err_t priv_sdmmc_spi_send_acmd(sd_cmd_t acmd, uint32_t arg, uint8_t* out_r1)
334{
335 uint8_t r1 = 0U;
337 if (err != k_ra8_ok) {
338 return err;
339 }
340 /* CMD55 is allowed to leave R1 == idle (0x01) during the init loop. */
341 return priv_sdmmc_spi_send_command(acmd, arg, out_r1);
342}
343
344/* Send CMD12 (STOP_TRANSMISSION) with the stuff-byte skip before R1 -- see
345 * implementation for details. */
347{
348 uint8_t frame[k_ra8_sdmmc_spi_cmd_frame_bytes];
350 uint8_t rx_dummy[k_ra8_sdmmc_spi_cmd_frame_bytes];
351 ra8_err_t err = g_sdmmc_spi_state.transport.xfer(g_sdmmc_spi_state.transport.ctx,
352 frame,
353 rx_dummy,
355 if (err != k_ra8_ok) {
356 return err;
357 }
358 /* The byte immediately following the CMD12 frame is a stuff byte: it
359 * carries the tail of the interrupted read stream and its value is
360 * undefined, so it must be discarded before the R1 poll -- a bit7-clear
361 * garbage byte would otherwise be misread as the response. This is why
362 * CMD12 cannot go through priv_sdmmc_spi_send_command, which polls for R1
363 * straight after the frame. */
364 err = priv_sdmmc_spi_send_idle(1U);
365 if (err != k_ra8_ok) {
366 return err;
367 }
368 return internal_read_r1(out_r1);
369}
370
371/* ===========================================================================
372 * R7 / R3 extension responses (CMD8, CMD58)
373 * ===========================================================================
374 */
375
376/* see header for full description */
378{
379 uint8_t bytes[4] = {};
380 ra8_err_t err =
381 g_sdmmc_spi_state.transport.xfer(g_sdmmc_spi_state.transport.ctx, nullptr, bytes, 4U);
382 if (err != k_ra8_ok) {
383 /* Some transports do not allow NULL tx; fall back to per-byte. */
384 for (uint32_t i = 0U; i < 4U; i++) {
385 err = priv_sdmmc_spi_xfer_one((uint8_t)k_sd_token_idle, &bytes[i]);
386 if (err != k_ra8_ok) {
387 return err;
388 }
389 }
390 }
391 *out_word = ((uint32_t)bytes[0] << k_sd_bit_three_byte) |
392 ((uint32_t)bytes[1] << k_sd_bit_two_byte) | ((uint32_t)bytes[2] << k_sd_bit_byte) |
393 (uint32_t)bytes[3];
394 return k_ra8_ok;
395}
396
397/* ===========================================================================
398 * Data-token I/O
399 * ===========================================================================
400 */
401
402/* Poll for the data-start token (0xFE), bounded by a retry budget -- see
403 * implementation for details. */
405{
406 for (uint32_t i = 0U; i < (uint32_t)k_sd_max_data_token_polls; i++) {
407 uint8_t byte = 0U;
409 if (err != k_ra8_ok) {
410 return err;
411 }
412 if (byte == (uint8_t)k_sd_token_data_start_single) {
413 return k_ra8_ok;
414 }
415 }
417}
418
419/* Wait for the card to release busy (CIPO -> 0xFF), bounded by @p max_polls --
420 * see implementation for details. */
422{
423 for (uint32_t i = 0U; i < max_polls; i++) {
424 uint8_t byte = 0U;
426 if (err != k_ra8_ok) {
427 return err;
428 }
429 if (byte == (uint8_t)k_sd_token_idle) {
430 return k_ra8_ok;
431 }
432 }
434}
435
436/* Wait for the card to release the busy token (CIPO returns to 0xFF) -- see
437 * implementation for details. */
442
443/* ===========================================================================
444 * CSD parsing (capacity decode)
445 * ===========================================================================
446 */
447
448/* see header for full description */
449RA8_INTERNAL static uint32_t internal_csd_to_blocks(const uint8_t* csd)
450{
451 const uint8_t version = (uint8_t)((csd[k_sd_csd_byte_version] >> k_sd_csd_version_shift) & 0x03U);
452 if (version == 1U) {
453 /* CSD v2: ``capacity = (C_SIZE + 1) * 512 * 1024 / 512``. */
454 const uint32_t c_size =
456 ((uint32_t)csd[k_sd_csd_v2_byte_csize_mid] << k_sd_bit_byte) |
457 (uint32_t)csd[k_sd_csd_v2_byte_csize_lsb];
458 return (c_size + 1U) << (uint32_t)k_sd_csd_v2_blocks_shift;
459 }
460 if (version == 0U) {
461 /* CSD v1 (SD spec PHY v9 section 5.3.2):
462 * capacity = (C_SIZE+1) * 2^(C_SIZE_MULT+2) * 2^READ_BL_LEN / 512.
463 * C_SIZE is a 12-bit field spanning csd[6][1:0] (high 2 bits),
464 * csd[7] (middle 8 bits), csd[8][7:6] (low 2 bits). */
465 const uint8_t read_bl_len = (uint8_t)(csd[5] & k_sd_read_bl_mask);
466 const uint32_t c_size = (((uint32_t)csd[6] & 0x03U) << k_sd_csize_shift) |
467 ((uint32_t)csd[7] << 2U) |
468 ((uint32_t)(csd[8] & k_sd_csize_lo_mask) >> 6U);
469 const uint8_t c_size_mult =
470 (uint8_t)((((uint8_t)csd[9] & 0x03U) << 1U) |
471 (((uint8_t)csd[10] & k_sd_mult_lo_mask) >> k_sd_mult_shift));
472 const uint32_t mult = (uint32_t)1U << ((uint32_t)c_size_mult + 2U);
473 const uint32_t block_len = (uint32_t)1U << (uint32_t)read_bl_len;
474 /* Multiply in 64 bits to avoid overflow before dividing by 512. */
475 const uint64_t bytes = (uint64_t)(c_size + 1U) * (uint64_t)mult * (uint64_t)block_len;
476 return (uint32_t)(bytes / (uint64_t)k_ra8_sdmmc_spi_block_size);
477 }
478 return 0U;
479}
480
481/* ===========================================================================
482 * Init sequence
483 * ===========================================================================
484 */
485
486/* Validate the transport descriptor: every callback non-NULL -- see
487 * implementation for details. */
489{
490 if (transport == nullptr) {
491 return k_ra8_err_null_ptr;
492 }
493 if ((transport->set_clock == nullptr) || (transport->cs == nullptr) ||
494 (transport->xfer == nullptr)) {
496 }
497 return k_ra8_ok;
498}
499
533{
534 /* Phase 1: drain busy + reset byte framing with CS released. */
535 (void)g_sdmmc_spi_state.transport.cs(g_sdmmc_spi_state.transport.ctx, false);
537
538 /* Phase 2: complete/abort a wedged data phase with CS asserted. */
539 if (g_sdmmc_spi_state.transport.cs(g_sdmmc_spi_state.transport.ctx, true) != k_ra8_ok) {
540 return;
541 }
542 (void)priv_sdmmc_spi_xfer_one((uint8_t)k_sd_token_stop_multi, nullptr);
545
546 /* Phase 3: explicit STOP_TRANSMISSION for any open multi-block transfer. */
547 uint8_t r1 = 0U;
550 (void)g_sdmmc_spi_state.transport.cs(g_sdmmc_spi_state.transport.ctx, false);
551
552 /* Phase 4: settle framing before the caller's wake/CMD0. */
554}
555
556/* Drive >= 74 dummy clocks with CS high to wake the card (SD spec
557 * section 7.2.1) -- see implementation for details. */
559{
560 ra8_err_t err = g_sdmmc_spi_state.transport.cs(g_sdmmc_spi_state.transport.ctx, false);
561 if (err != k_ra8_ok) {
562 return err;
563 }
565}
566
567/* see header for full description */
569{
571 if (err != k_ra8_ok) {
572 return err;
573 }
574 uint8_t r1 = 0U;
577 if (err != k_ra8_ok) {
578 return err;
579 }
580 if (r1 != (uint8_t)k_sd_r1_idle_state) {
582 }
583 return k_ra8_ok;
584}
585
586/* see header for full description */
588{
590 if (err != k_ra8_ok) {
591 return err;
592 }
593 uint8_t r1 = 0U;
594 err =
596 if (err != k_ra8_ok) {
598 return err;
599 }
600 if ((r1 & (uint8_t)k_sd_r1_illegal_command) != 0U) {
601 *out_is_v2 = false;
603 return k_ra8_ok;
604 }
605 uint32_t echo = 0U;
606 err = internal_read_r3_or_r7_tail(&echo);
608 if (err != k_ra8_ok) {
609 return err;
610 }
611 if ((echo & (uint32_t)k_sd_mask_12bit) !=
612 ((uint32_t)k_sd_cmd8_arg_check_pattern & (uint32_t)k_sd_mask_12bit)) {
614 }
615 *out_is_v2 = true;
616 return k_ra8_ok;
617}
618
619/* see header for full description */
621{
622 const uint32_t arg = is_v2 ? (uint32_t)k_sd_acmd41_arg_hcs : 0U;
623 for (uint32_t i = 0U; i < (uint32_t)k_sd_max_acmd41_attempts; i++) {
625 if (err != k_ra8_ok) {
626 return err;
627 }
628 uint8_t r1 = 0U;
631 if (err != k_ra8_ok) {
632 return err;
633 }
634 if ((r1 & (uint8_t)k_sd_r1_idle_state) == 0U) {
635 return k_ra8_ok;
636 }
637 }
639}
640
641/* see header for full description */
643{
645 if (err != k_ra8_ok) {
646 return err;
647 }
648 uint8_t r1 = 0U;
650 if (err != k_ra8_ok) {
652 return err;
653 }
654 uint32_t ocr = 0U;
655 err = internal_read_r3_or_r7_tail(&ocr);
657 if (err != k_ra8_ok) {
658 return err;
659 }
660 *out_is_hc = ((ocr & (uint32_t)k_sd_ocr_ccs_bit) != 0U);
661 return k_ra8_ok;
662}
663
664/* Send CMD9 (SEND_CSD) and parse capacity -- see implementation for details. */
665RA8_INTERNAL static ra8_err_t internal_read_csd(uint32_t* out_blocks)
666{
668 if (err != k_ra8_ok) {
669 return err;
670 }
671 uint8_t r1 = 0U;
673 if (err != k_ra8_ok) {
675 return err;
676 }
677 if (r1 != 0U) {
680 }
682 if (err != k_ra8_ok) {
684 return err;
685 }
686 uint8_t csd[k_ra8_sdmmc_spi_csd_response_len] = {};
687 for (uint32_t i = 0U; i < (uint32_t)k_ra8_sdmmc_spi_csd_response_len; i++) {
688 err = priv_sdmmc_spi_xfer_one((uint8_t)k_sd_token_idle, &csd[i]);
689 if (err != k_ra8_ok) {
691 return err;
692 }
693 }
694 /* Drain trailing CRC16 (2 bytes). */
695 uint8_t crc_bytes[2] = {};
696 (void)priv_sdmmc_spi_xfer_one((uint8_t)k_sd_token_idle, &crc_bytes[0]);
697 (void)priv_sdmmc_spi_xfer_one((uint8_t)k_sd_token_idle, &crc_bytes[1]);
699 *out_blocks = internal_csd_to_blocks(csd);
700 if (*out_blocks == 0U) {
702 }
703 return k_ra8_ok;
704}
705
706/* see header for full description */
708{
710 if (err != k_ra8_ok) {
711 return err;
712 }
713 uint8_t r1 = 0U;
714 err =
717 if (err != k_ra8_ok) {
718 return err;
719 }
720 if (r1 != 0U) {
722 }
723 return k_ra8_ok;
724}
725
726/* see header for full description */
728{
729 if (is_hc) {
731 }
732 if (is_v2) {
734 }
736}
737
738/* see header for full description */
739RA8_INTERNAL static ra8_err_t internal_probe_card(bool* out_is_v2, bool* out_is_hc)
740{
742 if (err == k_ra8_ok) {
743 err = internal_send_cmd0();
744 }
745 /* CMD0 failed: the card may be stranded mid-write from an interrupted
746 * transaction. Flush it and retry, escalating across a few attempts. A
747 * healthy card answers CMD0 on the first pass and never enters this loop, so
748 * the recovery cannot disturb a normal bring-up. */
749 for (uint32_t attempt = 0U; (err != k_ra8_ok) && (attempt < (uint32_t)k_sd_max_recover_attempts);
750 attempt++) {
752 err = internal_wake_card();
753 if (err == k_ra8_ok) {
754 err = internal_send_cmd0();
755 }
756 }
757 if (err != k_ra8_ok) {
758 return err;
759 }
760 err = internal_send_cmd8(out_is_v2);
761 if (err != k_ra8_ok) {
762 return err;
763 }
764 err = internal_acmd41_loop(*out_is_v2);
765 if (err != k_ra8_ok) {
766 return err;
767 }
768 *out_is_hc = false;
769 if (*out_is_v2) {
770 err = internal_read_ocr(out_is_hc);
771 }
772 return err;
773}
774
775/* Walk the full SD identification sequence and learn capacity / type -- see
776 * implementation for details. */
778{
779 bool is_v2 = false;
780 bool is_hc = false;
781 ra8_err_t err = internal_probe_card(&is_v2, &is_hc);
782 if (err != k_ra8_ok) {
783 return err;
784 }
785 uint32_t blocks = 0U;
786 err = internal_read_csd(&blocks);
787 RA8_RETURN_ON_ERROR(err, s_tag, "CMD9 SEND_CSD");
788 /* SDSC (v1.x or v2.x SDSC) needs an explicit block-size set; HC cards
789 * accept it as a no-op but the spec says we should still issue it. */
791 RA8_RETURN_ON_ERROR(err, s_tag, "CMD16 SET_BLOCKLEN");
792 g_sdmmc_spi_state.card_type = internal_classify_card(is_v2, is_hc);
793 g_sdmmc_spi_state.capacity_blocks = blocks;
794 return k_ra8_ok;
795}
static const char * s_tag
Logging / check tag.
Definition ra8_app.c:17
#define RA8_PRIV
Module-private helper: shared across TUs but only inside one library.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
Validation and Error-Checking Macros for ra8-firmware.
#define RA8_RETURN_ON_ERROR(err, tag, message)
Early return on error, propagating the code upward.
Definition ra8_check.h:184
Error Code Definitions for ra8-firmware.
@ k_ra8_err_hw_init_failed
Hardware peripheral failed to initialise.
Definition ra8_err.h:290
@ k_ra8_err_invalid_arg
Invalid function argument.
Definition ra8_err.h:152
@ k_ra8_err_hw_timeout
Hardware timed out waiting for a flag or handshake.
Definition ra8_err.h:304
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
@ k_ra8_err_null_ptr
Pointer was NULL where a valid pointer was required.
Definition ra8_err.h:478
@ k_ra8_err_protocol_error
Protocol-level error (e.g.
Definition ra8_err.h:429
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
PSEL codes for peripheral pin routing on the RA8D2.
Lightweight Logging Interface for ra8-firmware.
High-level GPIO helpers on top of the PORT + PFS register layer.
SCI Simple-SPI controller-mode driver (polling, full-duplex).
sd_csd_field_t
SD CSD register field masks, shifts and block size.
Definition ra8_sdcard.c:47
@ k_sd_read_bl_mask
READ_BL_LEN (4-bit).
Definition ra8_sdcard.c:51
static ra8_err_t internal_read_csd(uint32_t *out_blocks)
sd_crc16_const_t
CRC16-CCITT polynomial and mask constants (SD spec PHY v9 section 4.5).
@ k_sd_crc16_poly
CRC16-CCITT polynomial.
@ k_sd_crc16_msb_test
Top bit of the 16-bit working CRC.
static ra8_err_t internal_read_r3_or_r7_tail(uint32_t *out_word)
sd_r1_bit_t
R1 response bit definitions (SD spec PHY v9 section 7.3.2.1).
@ k_sd_r1_parameter_error
SD r1 parameter error.
@ k_sd_r1_address_error
SD r1 address error.
@ k_sd_r1_sentinel
SD r1 sentinel.
@ k_sd_r1_com_crc_error
SD r1 com CRC error.
@ k_sd_r1_illegal_command
SD r1 illegal command.
@ k_sd_r1_erase_sequence_error
SD r1 erase sequence error.
@ k_sd_r1_erase_reset
SD r1 erase reset.
@ k_sd_r1_idle_state
SD r1 idle state.
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.
static ra8_err_t internal_read_ocr(bool *out_is_hc)
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).
static void internal_build_frame(sd_cmd_t cmd, uint32_t arg, uint8_t *out_frame)
static ra8_err_t internal_wake_card(void)
static ra8_err_t internal_send_cmd0(void)
sd_state_t g_sdmmc_spi_state
Single driver instance (the module's one external definition).
uint8_t ra8_sdmmc_spi_crc7(const uint8_t *data, uint32_t len)
Compute the SD-spec CRC7 over an arbitrary byte run.
sd_csd_layout_t
Selected CSD-byte indices and bit shifts (SD spec PHY v9 section 5).
@ 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_byte_version
SD csd byte version.
@ k_sd_csd_v2_byte_csize_lsb
SD csd v2 byte csize lsb.
@ k_sd_csd_version_shift
SD csd version shift.
@ k_sd_csd_v2_blocks_shift
SD csd v2 blocks shift.
static ra8_err_t internal_probe_card(bool *out_is_v2, bool *out_is_hc)
ra8_err_t priv_sdmmc_spi_wait_not_busy(void)
Wait for the card to release the busy token (CIPO returns to 0xFF).
static ra8_err_t internal_read_r1(uint8_t *out_r1)
ra8_err_t priv_sdmmc_spi_cs_release(void)
Drive CS high after clocking one idle byte (SD spec section 7.2.4).
ra8_err_t priv_sdmmc_spi_send_idle(uint32_t n)
Shift n idle bytes (0xFF) and discard the response.
static ra8_err_t internal_set_block_len(void)
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_run_init_sequence(void)
Walk the full SD identification sequence and learn capacity / type.
ra8_err_t priv_sdmmc_spi_send_stop_transmission(uint8_t *out_r1)
Send CMD12 (STOP_TRANSMISSION) and capture its R1 response byte.
sd_crc7_const_t
CRC7 polynomial and mask constants (SD spec PHY v9 section 4.5).
@ k_sd_crc7_msb_test
Top bit of the 7-bit working CRC.
@ k_sd_crc7_register_mask
Mask the 7-bit working register.
@ k_sd_crc7_byte_msb
Top bit of an input byte.
@ k_sd_crc7_poly_low7
G(x) low 7 bits: 0b0001001.
static ra8_sdmmc_spi_card_type_t internal_classify_card(bool is_v2, bool is_hc)
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.
static ra8_err_t internal_acmd41_loop(bool is_v2)
@ k_sd_csize_msb_mask
CSD v2 C_SIZE MSB field (6-bit).
@ k_sd_cmd_frame_len
Command bytes preceding the CRC7.
@ k_sd_mult_lo_mask
C_SIZE_MULT low bit (byte 10).
@ k_sd_csize_lo_mask
CSD v1 C_SIZE low 2 bits (byte 8).
@ k_sd_mult_shift
C_SIZE_MULT low-bit shift.
@ k_sd_csize_shift
CSD v1 C_SIZE high-bits shift.
ra8_err_t priv_sdmmc_spi_validate_transport(const ra8_sdmmc_spi_transport_t *transport)
Validate the transport descriptor: every callback non-NULL.
ra8_err_t priv_sdmmc_spi_cs_assert(void)
Drive CS low and clock a single idle byte so CIPO is sampled.
static uint32_t internal_csd_to_blocks(const uint8_t *csd)
uint16_t ra8_sdmmc_spi_crc16(const uint8_t *data, uint32_t len)
Compute the SD-spec CRC16-CCITT over an arbitrary byte run.
sd_cmd_arg_idx_t
Byte indices inside a 6-byte SD command frame.
@ k_sd_frame_idx_crc
SD frame index CRC.
@ 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_msb
SD frame index arg msb.
@ k_sd_frame_idx_arg_lsb
SD frame index arg lsb.
@ k_sd_frame_idx_cmd
SD frame index cmd.
static void internal_recover_stuck_card(void)
Best-effort recovery for a card stranded mid-write by an interrupted transaction (e....
ra8_err_t priv_sdmmc_spi_wait_data_token(void)
Poll for the data-start token (0xFE), bounded by a retry budget.
static ra8_err_t internal_send_cmd8(bool *out_is_v2)
SD card driver in SPI-mode (PMOD-attached cards).
@ k_ra8_sdmmc_spi_block_size
512-byte block (SD spec PHY v9 section 7.2.2).
@ k_ra8_sdmmc_spi_csd_response_len
CMD9 CSD register payload bytes.
@ k_ra8_sdmmc_spi_cmd_frame_bytes
1 cmd-byte + 4 arg-bytes + 1 CRC-byte.
ra8_sdmmc_spi_card_type_t
Detected SD card capacity / addressing class.
@ k_ra8_sdmmc_spi_type_sdhc
SDHC / SDXC v2.x (block-addressed).
@ k_ra8_sdmmc_spi_type_sdv2
SD v2.x SC (byte-addressed).
@ k_ra8_sdmmc_spi_type_sdv1
SD v1.x (byte-addressed).
Contracts for file-local SD protocol helpers.
Module-private cross-TU surface for the SPI-mode SD card driver.
@ k_sd_token_stop_multi
Multi-block stop.
@ k_sd_token_data_start_single
Single-block start.
@ k_sd_token_idle
Idle bus.
@ k_sd_max_busy_poll_bytes
Worst-case write timeout.
@ k_sd_crc7_cmd0_byte
SD crc7 cmd0 byte.
@ k_sd_max_recover_attempts
Re-flush + retry CMD0 before failing.
@ k_sd_cmd8_arg_check_pattern
SD cmd8 arg check pattern.
@ k_sd_ocr_ccs_bit
SD ocr ccs bit.
@ k_sd_max_r1_wait_bytes
R1 must appear within 8 bytes per spec; 2x slack.
@ k_sd_recover_idle_bytes
512 CS-released clocks drain busy + reset framing.
@ k_sd_max_data_token_polls
~500 ms at 100 us / poll.
@ k_sd_crc7_cmd8_byte
SD crc7 cmd8 byte.
@ k_sd_max_acmd41_attempts
1 s at 1 ms / attempt.
@ k_sd_init_dummy_clocks
80 clocks = 10 bytes of 0xFF (>=74 required).
@ k_sd_acmd41_arg_hcs
SD acmd41 arg hcs.
@ k_sd_recover_flush_bytes
>= 512 data + 2 CRC + token to flush a stuck write.
@ k_sd_mask_byte
Low 8 bits of a wider value.
@ k_sd_mask_12bit
CMD8 R7 echo voltage-range + check pattern.
sd_cmd_t
Wire-byte for every command used by this driver.
@ k_sd_cmd_set_blocklen
CMD16.
@ k_sd_cmd_app_cmd
CMD55.
@ k_sd_acmd_sd_send_op_cond
ACMD41.
@ k_sd_cmd_stop_transmission
CMD12.
@ k_sd_cmd_send_csd
CMD9.
@ k_sd_cmd_send_if_cond
CMD8.
@ k_sd_cmd_read_ocr
CMD58.
@ k_sd_cmd_go_idle_state
CMD0.
@ k_sd_bit_three_byte
SD bit three byte.
@ k_sd_bit_byte
SD bit byte.
@ k_sd_bit_two_byte
SD bit two byte.
SPI_B controller driver (RA8D2 Type-B SPI peripheral).
Driver-to-bus binding (Dependency Inversion seam).
Cached protocol state held across the driver public API.