ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_sdmmc_spi_io.c
Go to the documentation of this file.
1
25
26#include <stdint.h>
27#include <string.h>
28
29#include "ra8_check.h"
30#include "ra8_err.h"
31#include "ra8_gpio_constants.h"
32#include "ra8_log.h"
33#include "ra8_port_utils.h"
34#include "ra8_sci_spi.h"
35#include "ra8_sdmmc_spi.h"
38#include "ra8_spi.h"
39
40/* ---------------------------------------------------------------------------
41 * Log tag
42 * ---------------------------------------------------------------------------
43 */
44
51static const char* s_tag = "SDSPI";
52
53/* ===========================================================================
54 * Convenience SCI Simple-SPI transport factory (Pmod SD on EK-RA8D2)
55 * ===========================================================================
56 */
57
66typedef struct {
67 uint8_t channel;
68 uint32_t pclka_hz;
71
80
99{
100 RA8_CHECK_NULL_PTR(ctx, s_tag, "ctx");
101 const sci_bus_ctx_t* c = (const sci_bus_ctx_t*)ctx;
102 return ra8_sci_spi_set_clock(c->channel, hz, c->pclka_hz);
103}
104
123RA8_INTERNAL static ra8_err_t internal_sci_transport_cs(void* ctx, bool asserted)
124{
125 RA8_CHECK_NULL_PTR(ctx, s_tag, "ctx");
126 const sci_bus_ctx_t* c = (const sci_bus_ctx_t*)ctx;
127 return ra8_gpio_write(c->cs, asserted ? k_ra8_level_low : k_ra8_level_high);
128}
129
150internal_sci_transport_xfer(void* ctx, const uint8_t* tx, uint8_t* rx, uint32_t len)
151{
152 RA8_CHECK_NULL_PTR(ctx, s_tag, "ctx");
153 const sci_bus_ctx_t* c = (const sci_bus_ctx_t*)ctx;
154 return ra8_sci_spi_xfer(c->channel, tx, rx, len);
155}
156
178 uint32_t pclk_hz,
179 const ra8_sdmmc_spi_sci_pins_t* pins)
180{
181 RA8_CHECK_NULL_PTR(pins, s_tag, "pins");
182
184 if (err != k_ra8_ok) {
185 return err;
186 }
187 err = ra8_pfs_route_peripheral(pins->cipo, k_ra8_psel_sci_async, "sdspi.cipo");
188 if (err != k_ra8_ok) {
189 return err;
190 }
191 err = ra8_pfs_route_peripheral(pins->copi, k_ra8_psel_sci_async, "sdspi.copi");
192 if (err != k_ra8_ok) {
193 return err;
194 }
196 if (err != k_ra8_ok) {
197 return err;
198 }
199 const ra8_sci_spi_cfg_t spi_cfg = {
200 .baud_hz = (uint32_t)k_ra8_sdmmc_spi_clock_init_hz,
201 .pclk_hz = pclk_hz,
202 .mode = k_ra8_spi_mode_0,
203 .lsb_first = false,
204 };
205 return ra8_sci_spi_init(channel, &spi_cfg);
206}
207
209 uint32_t pclk_hz,
210 const ra8_sdmmc_spi_sci_pins_t* pins,
212{
213 RA8_CHECK_NULL_PTR(pins, s_tag, "pins");
214 RA8_CHECK_NULL_PTR(out, s_tag, "out");
215 if (pclk_hz == 0U) {
217 }
218
219 ra8_err_t err = internal_sci_transport_bringup(sci_channel, pclk_hz, pins);
220 if (err != k_ra8_ok) {
221 return err;
222 }
223
224 s_sci_ctx.channel = sci_channel;
225 s_sci_ctx.pclka_hz = pclk_hz;
226 s_sci_ctx.cs = pins->cs;
227
231 out->ctx = &s_sci_ctx;
232 return k_ra8_ok;
233}
234
235/* ===========================================================================
236 * Public API
237 * ===========================================================================
238 */
239
240/* see header for full description */
242{
243 if (g_sdmmc_spi_state.initialized) {
244 ra8_log_error(s_tag, "already initialized");
246 }
247 g_sdmmc_spi_state.transport = *transport;
249 g_sdmmc_spi_state.capacity_blocks = 0U;
250 return g_sdmmc_spi_state.transport.set_clock(g_sdmmc_spi_state.transport.ctx,
252}
253
254/* see header for full description */
256{
257 ra8_err_t err = g_sdmmc_spi_state.transport.set_clock(g_sdmmc_spi_state.transport.ctx,
259 if (err != k_ra8_ok) {
260 return err;
261 }
262 g_sdmmc_spi_state.initialized = true;
263 return k_ra8_ok;
264}
265
267{
269 RA8_RETURN_ON_ERROR(err, s_tag, "transport invalid");
270 err = internal_prepare_init(transport);
271 RA8_RETURN_ON_ERROR(err, s_tag, "prepare init");
273 RA8_RETURN_ON_ERROR(err, s_tag, "SD init sequence");
275 RA8_RETURN_ON_ERROR(err, s_tag, "finalize init");
276 return k_ra8_ok;
277}
278
280{
281 g_sdmmc_spi_state.initialized = false;
283 g_sdmmc_spi_state.capacity_blocks = 0U;
284 return k_ra8_ok;
285}
286
287/* see header for full description */
288RA8_INTERNAL static uint32_t internal_lba_to_arg(uint32_t lba)
289{
291 return lba;
292 }
293 return lba * (uint32_t)k_ra8_sdmmc_spi_block_size;
294}
295
296/* see header for full description */
298{
300 if (err != k_ra8_ok) {
301 return err;
302 }
303 uint8_t r1 = 0U;
304 err = priv_sdmmc_spi_send_command(cmd, arg, &r1);
306 if (err != k_ra8_ok) {
307 return err;
308 }
309 if (r1 != 0U) {
311 }
312 return k_ra8_ok;
313}
314
315/* see header for full description */
316RA8_INTERNAL static ra8_err_t internal_erase_range(uint32_t lba, uint32_t count)
317{
319 if (err != k_ra8_ok) {
320 return err;
321 }
322 err =
324 if (err != k_ra8_ok) {
325 return err;
326 }
327 /* CMD38 then a long busy wait -- a bulk erase can hold the card busy for
328 * seconds, far longer than a single-block write. */
330 if (err != k_ra8_ok) {
331 return err;
332 }
333 uint8_t r1 = 0U;
335 if (err != k_ra8_ok) {
337 return err;
338 }
339 if (r1 != 0U) {
342 }
345 return err;
346}
347
348/* see header for full description */
350{
351 for (uint32_t i = 0U; i < (uint32_t)k_ra8_sdmmc_spi_block_size; i++) {
352 ra8_err_t err = priv_sdmmc_spi_xfer_one((uint8_t)k_sd_token_idle, &buf[i]);
353 if (err != k_ra8_ok) {
354 return err;
355 }
356 }
357 return k_ra8_ok;
358}
359
360/* see header for full description */
362{
363 uint8_t crc_hi = 0U;
364 uint8_t crc_lo = 0U;
365 (void)priv_sdmmc_spi_xfer_one((uint8_t)k_sd_token_idle, &crc_hi);
366 (void)priv_sdmmc_spi_xfer_one((uint8_t)k_sd_token_idle, &crc_lo);
367 const uint16_t expected = ra8_sdmmc_spi_crc16(buf, (uint32_t)k_ra8_sdmmc_spi_block_size);
368 const uint16_t actual = (uint16_t)(((uint16_t)crc_hi << k_sd_bit_byte) | (uint16_t)crc_lo);
369 if (expected != actual) {
371 }
372 return k_ra8_ok;
373}
374
375/* see header for full description */
376RA8_INTERNAL static ra8_err_t internal_read_data_phase(uint32_t lba, uint8_t* buf)
377{
378 uint8_t r1 = 0U;
379 ra8_err_t err =
381 if (err != k_ra8_ok) {
382 return err;
383 }
384 if (r1 != 0U) {
386 }
388 if (err != k_ra8_ok) {
389 return err;
390 }
392 if (err != k_ra8_ok) {
393 return err;
394 }
396}
397
398ra8_err_t ra8_sdmmc_spi_read_block(uint32_t lba, uint8_t* buf)
399{
400 RA8_CHECK_NULL_PTR(buf, s_tag, "buf is null");
401 if (!g_sdmmc_spi_state.initialized) {
403 }
404 if (lba >= g_sdmmc_spi_state.capacity_blocks) {
406 }
408 RA8_RETURN_ON_ERROR(err, s_tag, "cs assert");
409 err = internal_read_data_phase(lba, buf);
411 return err;
412}
413
414/* Drain @p count streamed blocks (token + payload + CRC) of an open CMD18 --
415 * see implementation for details. */
416RA8_INTERNAL static ra8_err_t internal_read_multi_stream(uint8_t* buf, uint32_t count)
417{
418 for (uint32_t i = 0U; i < count; i++) {
419 uint8_t* block = &buf[(size_t)i * (size_t)k_ra8_sdmmc_spi_block_size];
421 if (err != k_ra8_ok) {
422 return err;
423 }
424 err = internal_read_block_payload(block);
425 if (err != k_ra8_ok) {
426 return err;
427 }
429 if (err != k_ra8_ok) {
430 return err;
431 }
432 }
433 return k_ra8_ok;
434}
435
436/* see header for full description */
438{
439 uint8_t r1 = 0U;
441 if (err != k_ra8_ok) {
442 return err;
443 }
444 if (r1 != 0U) {
447 }
449}
450
451ra8_err_t ra8_sdmmc_spi_read_blocks(uint32_t lba, uint8_t* buf, uint32_t count)
452{
453 RA8_CHECK_NULL_PTR(buf, s_tag, "buf is null");
454 if (!g_sdmmc_spi_state.initialized) {
456 }
457 if (count == 0U) {
458 return k_ra8_ok;
459 }
460 if ((lba >= g_sdmmc_spi_state.capacity_blocks) ||
461 (count > (g_sdmmc_spi_state.capacity_blocks - lba))) {
463 }
464 if (count == 1U) {
465 return ra8_sdmmc_spi_read_block(lba, buf);
466 }
468 RA8_RETURN_ON_ERROR(err, s_tag, "cs assert");
469 uint8_t r1 = 0U;
471 if ((err != k_ra8_ok) || (r1 != 0U)) {
473 return (err != k_ra8_ok) ? err : k_ra8_err_protocol_error;
474 }
475 err = internal_read_multi_stream(buf, count);
476 /* CMD12 runs on the success AND the abort path: the card keeps streaming
477 * read data until it sees STOP_TRANSMISSION, so it must leave the data
478 * state before CS is released or the next command collides with the
479 * still-open stream. A stream error takes precedence over a stop error. */
480 const ra8_err_t stop_err = internal_read_multi_stop();
482 if (err != k_ra8_ok) {
483 return err;
484 }
485 return stop_err;
486}
487
488/* see header for full description */
489RA8_INTERNAL static ra8_err_t internal_write_data_block(const uint8_t* buf, uint8_t start_token)
490{
491 ra8_err_t err = priv_sdmmc_spi_send_idle(1U); /* N_WR pad (spec >= 1 byte). */
492 if (err != k_ra8_ok) {
493 return err;
494 }
495 err = priv_sdmmc_spi_xfer_one(start_token, nullptr);
496 if (err != k_ra8_ok) {
497 return err;
498 }
499 err = g_sdmmc_spi_state.transport.xfer(g_sdmmc_spi_state.transport.ctx,
500 buf,
501 nullptr,
503 if (err != k_ra8_ok) {
504 /* Some transports require non-NULL rx -- fall back to per-byte. */
505 for (uint32_t i = 0U; i < (uint32_t)k_ra8_sdmmc_spi_block_size; i++) {
506 uint8_t dummy = 0U;
507 err = priv_sdmmc_spi_xfer_one(buf[i], &dummy);
508 if (err != k_ra8_ok) {
509 return err;
510 }
511 }
512 }
513 const uint16_t crc = ra8_sdmmc_spi_crc16(buf, (uint32_t)k_ra8_sdmmc_spi_block_size);
515 (uint8_t)((uint32_t)(crc >> k_sd_bit_byte) & (uint32_t)k_sd_mask_byte),
516 nullptr);
517 (void)priv_sdmmc_spi_xfer_one((uint8_t)((uint32_t)crc & (uint32_t)k_sd_mask_byte), nullptr);
518 uint8_t response = 0U;
519 err = priv_sdmmc_spi_xfer_one((uint8_t)k_sd_token_idle, &response);
520 if (err != k_ra8_ok) {
521 return err;
522 }
523 if ((response & (uint8_t)k_sd_data_response_mask) != (uint8_t)k_sd_data_response_accepted) {
526 }
528}
529
530ra8_err_t ra8_sdmmc_spi_write_block(uint32_t lba, const uint8_t* buf)
531{
532 RA8_CHECK_NULL_PTR(buf, s_tag, "buf is null");
533 if (!g_sdmmc_spi_state.initialized) {
535 }
536 if (lba >= g_sdmmc_spi_state.capacity_blocks) {
538 }
540 RA8_RETURN_ON_ERROR(err, s_tag, "cs assert");
541 uint8_t r1 = 0U;
543 if (err != k_ra8_ok) {
545 return err;
546 }
547 if (r1 != 0U) {
550 }
553 return err;
554}
555
556/* see header for full description */
557RA8_INTERNAL static ra8_err_t internal_write_multi_stream(const uint8_t* buf, uint32_t count)
558{
559 for (uint32_t i = 0U; i < count; i++) {
560 const ra8_err_t err =
563 if (err != k_ra8_ok) {
564 return err;
565 }
566 }
567 (void)priv_sdmmc_spi_send_idle(1U);
568 (void)priv_sdmmc_spi_xfer_one((uint8_t)k_sd_token_stop_multi, nullptr);
569 (void)priv_sdmmc_spi_send_idle(1U);
571}
572
604ra8_err_t ra8_sdmmc_spi_write_blocks(uint32_t lba, const uint8_t* buf, uint32_t count)
605{
606 RA8_CHECK_NULL_PTR(buf, s_tag, "buf is null");
607 if (!g_sdmmc_spi_state.initialized) {
609 }
610 if (count == 0U) {
611 return k_ra8_ok;
612 }
613 if ((lba >= g_sdmmc_spi_state.capacity_blocks) ||
614 (count > (g_sdmmc_spi_state.capacity_blocks - lba))) {
616 }
617 if (count == 1U) {
618 return ra8_sdmmc_spi_write_block(lba, buf);
619 }
621 RA8_RETURN_ON_ERROR(err, s_tag, "cs assert");
622 /* Pre-erase hint (ACMD23): best-effort -- ignore the response so a card that
623 * does not implement it still streams correctly below. */
624 uint8_t acmd_r1 = 0U;
626 uint8_t r1 = 0U;
628 if ((err != k_ra8_ok) || (r1 != 0U)) {
630 return (err != k_ra8_ok) ? err : k_ra8_err_protocol_error;
631 }
632 err = internal_write_multi_stream(buf, count);
634 return err;
635}
636
637ra8_err_t ra8_sdmmc_spi_erase_blocks(uint32_t lba, uint32_t count)
638{
639 if (!g_sdmmc_spi_state.initialized) {
641 }
642 if (count == 0U) {
644 }
645 if ((lba >= g_sdmmc_spi_state.capacity_blocks) ||
646 (count > (g_sdmmc_spi_state.capacity_blocks - lba))) {
648 }
649 /* Probe: erase only the FIRST block and read it back. The SD post-erase value
650 * is card-dependent (0x00 on some, 0xFF on others), and the SCR
651 * DATA_STAT_AFTER_ERASE bit's polarity is unreliable in practice, so measure
652 * it. A non-zero read-back means this card erases to ones: report "not
653 * supported" so the caller writes zeros -- and skip erasing the rest, which
654 * would be wasted work (a one-block probe instead of the whole region). */
655 ra8_err_t err = internal_erase_range(lba, 1U);
656 if (err != k_ra8_ok) {
657 return err;
658 }
659 uint8_t blk[k_ra8_sdmmc_spi_block_size] = {};
660 err = ra8_sdmmc_spi_read_block(lba, blk);
661 if (err != k_ra8_ok) {
662 return err;
663 }
664 for (uint32_t i = 0U; i < (uint32_t)k_ra8_sdmmc_spi_block_size; i++) {
665 if (blk[i] != 0U) {
667 }
668 }
669 /* The card erases to zero: erase the remaining range in one operation. */
670 if (count > 1U) {
671 err = internal_erase_range(lba + 1U, count - 1U);
672 if (err != k_ra8_ok) {
673 return err;
674 }
675 }
676 return k_ra8_ok;
677}
678
680{
681 RA8_CHECK_NULL_PTR(out_blocks, s_tag, "out_blocks is null");
682 if (!g_sdmmc_spi_state.initialized) {
684 }
685 *out_blocks = g_sdmmc_spi_state.capacity_blocks;
686 return k_ra8_ok;
687}
688
690{
691 RA8_CHECK_NULL_PTR(out_type, s_tag, "out_type is null");
692 if (!g_sdmmc_spi_state.initialized) {
694 }
695 *out_type = g_sdmmc_spi_state.card_type;
696 return k_ra8_ok;
697}
698
699/* ===========================================================================
700 * ra8_fs backend adapter
701 * ===========================================================================
702 */
703
704/* see header for full description */
706internal_fs_read_block(void* ctx, uint64_t lba, uint32_t count, uint8_t* buf)
707{
708 (void)ctx;
709 if (buf == nullptr) {
710 return k_ra8_err_null_ptr;
711 }
712 /* SD block numbers are 32-bit (SDXC tops out at 2 TiB), so an address past
713 * that reach is refused rather than truncated -- the 64-bit `ra8_fs`
714 * backend interface (#683) simply exceeds what this medium can hold. */
715 if (lba > (uint64_t)UINT32_MAX) {
717 }
718 /* One CMD18 multi-block transaction for the whole run (fast); the
719 * single-block path is used only for a lone block. */
720 return ra8_sdmmc_spi_read_blocks((uint32_t)lba, buf, count);
721}
722
723/* see header for full description */
725internal_fs_write_block(void* ctx, uint64_t lba, uint32_t count, const uint8_t* buf)
726{
727 (void)ctx;
728 if (buf == nullptr) {
729 return k_ra8_err_null_ptr;
730 }
731 if (lba > (uint64_t)UINT32_MAX) {
732 return k_ra8_err_out_of_range; /* SD block numbers are 32-bit; see the read
733 shim */
734 }
735 /* One CMD25 multi-block transaction for the whole run (fast); the
736 * single-block path is used only for a lone block. */
737 return ra8_sdmmc_spi_write_blocks((uint32_t)lba, buf, count);
738}
739
740/* see header for full description */
741RA8_INTERNAL static ra8_err_t internal_fs_erase_block(void* ctx, uint64_t lba, uint64_t count)
742{
743 (void)ctx;
744 if ((lba > (uint64_t)UINT32_MAX) || (count > (uint64_t)UINT32_MAX)) {
745 return k_ra8_err_out_of_range; /* SD block numbers are 32-bit; see the read
746 shim */
747 }
748 return ra8_sdmmc_spi_erase_blocks((uint32_t)lba, (uint32_t)count);
749}
750
751/* see header for full description */
753internal_fs_get_capacity(void* ctx, uint64_t* block_count, uint32_t* block_size)
754{
755 (void)ctx;
756 if ((block_count == nullptr) || (block_size == nullptr)) {
757 return k_ra8_err_null_ptr;
758 }
759 if (!g_sdmmc_spi_state.initialized) {
761 }
762 *block_count = g_sdmmc_spi_state.capacity_blocks;
763 *block_size = (uint32_t)k_ra8_sdmmc_spi_block_size;
764 return k_ra8_ok;
765}
766
768{
769 RA8_CHECK_NULL_PTR(out_backend, s_tag, "out_backend is null");
770 if (!g_sdmmc_spi_state.initialized) {
772 }
773 out_backend->read_block = internal_fs_read_block;
777 out_backend->ctx = nullptr;
778 return k_ra8_ok;
779}
static const char * s_tag
Logging / check tag.
Definition ra8_app.c:17
#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
#define RA8_CHECK_NULL_PTR(ptr, tag, message)
Reject nullptr pointer, returning k_ra8_err_null_ptr.
Definition ra8_check.h:243
Error Code Definitions for ra8-firmware.
@ k_ra8_err_not_supported
Requested feature not compiled in, not wired, or not supported by this MCU variant.
Definition ra8_err.h:180
@ k_ra8_err_crc_mismatch
CRC mismatch detected on received data.
Definition ra8_err.h:423
@ k_ra8_err_out_of_range
Sensor or peripheral output out of valid range.
Definition ra8_err.h:337
@ k_ra8_err_invalid_arg
Invalid function argument.
Definition ra8_err.h:152
@ k_ra8_err_invalid_state
Module in wrong state for requested operation.
Definition ra8_err.h:161
@ 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.
@ k_ra8_psel_sci_async
00100b: SCI async serial (UART).
static ra8_err_t internal_fs_get_capacity(void *ctx, uint64_t *block_count, uint32_t *block_size)
ra8_fs capacity trampoline – map block-device caps to (count, size).
Lightweight Logging Interface for ra8-firmware.
#define ra8_log_error(tag, message)
RA8 log error.
Definition ra8_log.h:335
ra8_port_pin_t
Packed (port << 8) | pin pin identifier.
@ k_ra8_level_high
Drive or read 1.
@ k_ra8_level_low
Drive or read 0.
High-level GPIO helpers on top of the PORT + PFS register layer.
ra8_err_t ra8_gpio_output_init(ra8_port_pin_t pin, ra8_level_t init_level)
Configure a pin as a digital output and drive it to an initial level.
Definition gpio.c:88
ra8_err_t ra8_gpio_write(ra8_port_pin_t pin, ra8_level_t level)
Drive a previously-configured output to the given level.
Definition gpio.c:154
ra8_err_t ra8_pfs_route_peripheral(ra8_port_pin_t pin, ra8_psel_t psel, const char *owner)
Route a pin to a non-IRQ peripheral function via PFS.PSEL.
Definition gpio.c:238
SCI Simple-SPI controller-mode driver (polling, full-duplex).
ra8_err_t ra8_sci_spi_set_clock(uint8_t channel, uint32_t baud_hz, uint32_t pclk_hz)
Re-program the bit-rate without otherwise reconfiguring.
ra8_err_t ra8_sci_spi_xfer(uint8_t channel, const uint8_t *tx, uint8_t *rx, uint32_t len)
Full-duplex multi-byte transfer.
ra8_err_t ra8_sci_spi_init(uint8_t channel, const ra8_sci_spi_cfg_t *cfg)
Bring an SCI channel up as a Simple-SPI controller.
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_acmd(sd_cmd_t acmd, uint32_t arg, uint8_t *out_r1)
Send an ACMD by prefixing it with CMD55 (APP_CMD).
sd_state_t g_sdmmc_spi_state
Single driver instance (the module's one external definition).
ra8_err_t priv_sdmmc_spi_wait_not_busy(void)
Wait for the card to release the busy token (CIPO returns to 0xFF).
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.
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.
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_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.
ra8_err_t priv_sdmmc_spi_wait_data_token(void)
Poll for the data-start token (0xFE), bounded by a retry budget.
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_clock_data_hz
Default-speed data clock.
@ k_ra8_sdmmc_spi_clock_init_hz
Mandatory init clock floor.
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_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_unknown
Not yet probed / probe failed.
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_token_data_start_multi
Multi-block start.
@ k_sd_max_erase_poll_bytes
Busy ceiling for a bulk CMD38 erase (seconds).
@ k_sd_mask_byte
Low 8 bits of a wider value.
@ k_sd_data_response_mask
SD data response mask.
@ k_sd_data_response_accepted
0b00101 – data accepted.
sd_cmd_t
Wire-byte for every command used by this driver.
@ k_sd_cmd_read_multi_block
CMD18.
@ k_sd_cmd_read_single_block
CMD17.
@ k_sd_acmd_set_wr_blk_erase_count
ACMD23.
@ k_sd_cmd_erase_wr_blk_start
CMD32.
@ k_sd_cmd_erase_wr_blk_end
CMD33.
@ k_sd_cmd_write_single_block
CMD24.
@ k_sd_cmd_write_multi_block
CMD25.
@ k_sd_cmd_erase
CMD38.
@ k_sd_bit_byte
SD bit byte.
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.
static ra8_err_t internal_prepare_init(const ra8_sdmmc_spi_transport_t *transport)
static ra8_err_t internal_cmd_require_ready(sd_cmd_t cmd, uint32_t arg)
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_read_block_payload(uint8_t *buf)
static ra8_err_t internal_read_data_phase(uint32_t lba, uint8_t *buf)
static ra8_err_t internal_write_data_block(const uint8_t *buf, uint8_t start_token)
static ra8_err_t internal_fs_get_capacity(void *ctx, uint64_t *block_count, uint32_t *block_size)
static ra8_err_t internal_finalize_init(void)
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_erase_range(uint32_t lba, uint32_t count)
static sci_bus_ctx_t s_sci_ctx
Single-shot bus context backing the factory's transport callbacks.
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_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_set_clock(void *ctx, uint32_t hz)
Factory transport set-clock shim: retune the SCI baud divider.
static ra8_err_t internal_read_multi_stream(uint8_t *buf, uint32_t count)
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.
static ra8_err_t internal_fs_erase_block(void *ctx, uint64_t lba, uint64_t count)
static ra8_err_t internal_read_block_crc_check(const uint8_t *buf)
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_read_block(uint32_t lba, uint8_t *buf)
Read one 512-byte block at logical block address lba.
static ra8_err_t internal_fs_read_block(void *ctx, uint64_t lba, uint32_t count, uint8_t *buf)
static ra8_err_t internal_write_multi_stream(const uint8_t *buf, uint32_t count)
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_init(const ra8_sdmmc_spi_transport_t *transport)
Run the SD SPI-mode identification sequence on a card.
static uint32_t internal_lba_to_arg(uint32_t lba)
static ra8_err_t internal_fs_write_block(void *ctx, uint64_t lba, uint32_t count, const uint8_t *buf)
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_deinit(void)
Tear down the driver and release the transport binding.
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_read_multi_stop(void)
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.
Contracts for file-local SD block-I/O helpers.
SPI_B controller driver (RA8D2 Type-B SPI peripheral).
@ k_ra8_spi_mode_0
CPOL=0, CPHA=0.
Definition ra8_spi.h:62
Block-device interface that ra8_fs runs on top of.
ra8_err_t(* read_block)(void *ctx, uint64_t lba, uint32_t count, uint8_t *buf)
Read count consecutive blocks starting at lba.
ra8_err_t(* write_block)(void *ctx, uint64_t lba, uint32_t count, const uint8_t *buf)
Write count consecutive blocks starting at lba.
ra8_err_t(* erase_blocks)(void *ctx, uint64_t lba, uint64_t count)
OPTIONAL: bulk-erase count blocks at lba to all-zero bytes.
void * ctx
Caller-owned context passed back into the function pointers.
ra8_err_t(* get_capacity)(void *ctx, uint64_t *block_count, uint32_t *block_size)
Report the device size.
Configuration descriptor for ra8_sci_spi_init.
Definition ra8_sci_spi.h:49
The four bus pins of an SCI Simple-SPI SD slot.
ra8_port_pin_t copi
Controller-Out / Peripheral-In pin (COPIn).
ra8_port_pin_t sck
SPI clock pin (routed to SCKn).
ra8_port_pin_t cipo
Controller-In / Peripheral-Out pin (CIPOn).
ra8_port_pin_t cs
Chip-select pin, driven as a GPIO output.
Driver-to-bus binding (Dependency Inversion seam).
void * ctx
Caller context.
ra8_sdmmc_spi_set_clock_fn_t set_clock
Set the bus clock.
ra8_sdmmc_spi_xfer_fn_t xfer
Exchange bytes.
ra8_sdmmc_spi_cs_fn_t cs
Drive chip select.
Bus context handed to the factory's transport callbacks.
ra8_port_pin_t cs
Chip-select GPIO pin (active-low).
uint8_t channel
SCI Simple-SPI channel index.
uint32_t pclka_hz
PCLKA rate (Hz) for the baud shim.