ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
board_periph_sd.c
Go to the documentation of this file.
1
32
33#include "board_periph_sd.h"
34
35#include <stdint.h>
36#include <stdio.h>
37#include <string.h>
38
39#include "board_console.h"
41
43typedef enum : uint32_t {
47
56static uint32_t s_sd_spi_block_reads;
57
79
81board_sd_state_t g_board_sd = {.image_fd = -1};
82
100RA8_INTERNAL static uint16_t internal_board_sd_crc16(const uint8_t* data, uint32_t len)
101{
102 uint16_t crc = 0U;
103 for (uint32_t i = 0U; i < len; i++) {
104 crc ^= (uint16_t)((uint16_t)data[i] << (uint16_t)k_sd_byte_bits);
105 for (uint8_t b = 0U; b < (uint8_t)k_sd_byte_bits; b++) {
106 const bool msb = (crc & (uint16_t)k_sd_crc_msb) != 0U;
107 crc = (uint16_t)(crc << 1U);
108 if (msb) {
109 crc = (uint16_t)(crc ^ (uint16_t)k_sd_crc_poly);
110 }
111 }
112 }
113 return crc;
114}
115
136RA8_INTERNAL static bool
137internal_board_sd_fill_block(const board_sd_state_t* c, uint64_t off, uint8_t* blk)
138{
139 (void)memset(blk, 0, (size_t)k_sd_block);
140 if (off >= c->image_len) {
141 return true;
142 }
143 const uint64_t available = c->image_len - off;
144 const size_t count = (available < (uint64_t)k_sd_block) ? (size_t)available : (size_t)k_sd_block;
145 return priv_board_sd_storage_read(off, blk, count);
146}
147
163RA8_INTERNAL static void
164internal_board_sd_stage_block(board_sd_state_t* c, const uint8_t* payload, uint32_t len)
165{
166 c->resp[0] = (uint8_t)k_sd_r1_ready;
167 c->resp[1] = (uint8_t)k_sd_tok_data;
168 memcpy(&c->resp[2], payload, len);
169 const uint16_t crc = internal_board_sd_crc16(&c->resp[2], len);
170 c->resp[2U + len] = (uint8_t)(crc >> (uint16_t)k_sd_byte_bits);
171 c->resp[2U + len + 1U] = (uint8_t)(crc & (uint16_t)k_sd_byte_mask);
172 c->resp_len = 2U + len + 2U;
173 /* Console SD tab: anti-flood -- the first block and then every Nth, so a
174 * book-sized multi-block read shows activity without swamping the ring. */
176 bool sd_report = (s_sd_spi_block_reads == 1U);
177 if ((s_sd_spi_block_reads % (uint32_t)k_sd_console_rd_every) == 0U) {
178 sd_report = true;
179 }
180 if (sd_report) {
181 char ln[k_sd_console_line_cap];
182 (void)
183 snprintf(ln, sizeof(ln), "SDSPI rd %uB (#%u)", (unsigned)len, (unsigned)s_sd_spi_block_reads);
185 }
186}
187
207RA8_INTERNAL static void
208internal_board_sd_begin_read(board_sd_state_t* c, uint8_t idx, uint32_t arg)
209{
210 uint8_t blk[k_sd_block] = {};
211 const uint64_t off = (uint64_t)arg * (uint64_t)k_sd_block;
212 if (!internal_board_sd_fill_block(c, off, blk)) {
213 c->resp[0] = (uint8_t)k_sd_r1_param_err;
214 c->resp_len = 1U;
215 c->rd_multi = false;
216 return;
217 }
218 internal_board_sd_stage_block(c, blk, (uint32_t)k_sd_block);
219 c->rd_multi = (idx == (uint8_t)k_sd_idx_cmd18);
220 c->rd_off = off + (uint64_t)k_sd_block;
221}
222
241{
242 uint8_t blk[k_sd_block] = {};
243 if (!internal_board_sd_fill_block(c, c->rd_off, blk)) {
244 c->resp[0] = (uint8_t)k_sd_read_error;
245 c->resp_len = 1U;
246 c->resp_pos = 0U;
247 c->rd_multi = false;
248 return;
249 }
250 internal_board_sd_stage_block(c, blk, (uint32_t)k_sd_block);
251 c->resp_pos = 1U; /* skip the R1 slot: mid-stream blocks carry none. */
252 c->rd_off += (uint64_t)k_sd_block;
253}
254
274{
275 c->rd_multi = false;
276 c->resp[0] = (uint8_t)k_sd_idle; /* stuff byte (tail of the cut stream). */
277 c->resp[1] = r1;
278 c->resp[2] = (uint8_t)k_sd_busy;
279 c->resp[3] = (uint8_t)k_sd_idle;
280 c->resp_len = 4U;
281}
282
303RA8_INTERNAL static void
304internal_board_sd_begin_write(board_sd_state_t* c, uint8_t idx, uint32_t arg, uint8_t r1)
305{
306 c->resp[0] = r1;
307 c->resp_len = 1U;
309 c->wr_multi = (idx == (uint8_t)k_sd_idx_cmd25);
310 c->wr_off = (uint64_t)arg * (uint64_t)k_sd_block;
311 c->wr_cnt = 0U;
312 /* Console SD tab: one line per SD-over-SPI block-write command. */
313 char ln[k_sd_console_line_cap];
314 (void)snprintf(ln, sizeof(ln), "SDSPI wr blk=%u", (unsigned)arg);
316}
317
338{
339 if ((tx == (uint8_t)k_sd_tok_data) || (tx == (uint8_t)k_sd_tok_wmulti)) {
341 c->wr_cnt = 0U;
342 } else if (c->wr_multi && (tx == (uint8_t)k_sd_tok_stop)) {
344 c->wr_multi = false;
345 c->resp[0] = (uint8_t)k_sd_busy; /* program time, then done. */
346 c->resp[1] = (uint8_t)k_sd_idle;
347 c->resp_len = 2U;
348 c->resp_pos = 0U;
349 } else {
350 /* Not a token the card acts on: ignored. */
351 }
352}
353
370{
371 if (c->wr_cnt < (uint32_t)k_sd_block) {
372 c->wr_block[c->wr_cnt] = tx;
373 }
374 c->wr_cnt++;
375 if (c->wr_cnt >= (uint32_t)k_sd_block) {
377 c->wr_cnt = 0U;
378 }
379}
380
400{
401 c->wr_cnt++;
402 if (c->wr_cnt < (uint32_t)k_sd_crc_len) {
403 return;
404 }
405 const bool write_ok = priv_board_sd_storage_write(c->wr_off, c->wr_block, (size_t)k_sd_block);
406 c->resp[0] = write_ok ? (uint8_t)k_sd_data_accept : (uint8_t)k_sd_data_error;
407 c->resp[1] = (uint8_t)k_sd_busy;
408 c->resp[2] = (uint8_t)k_sd_idle;
409 c->resp_len = 3U;
410 c->resp_pos = 0U;
411 c->wr_cnt = 0U;
412 if (c->wr_multi) {
413 c->wr_off += (uint64_t)k_sd_block; /* next block of the multi-write. */
415 } else {
417 }
418}
419
444{
445 if (c->wr_phase == k_sd_wr_token) {
447 } else if (c->wr_phase == k_sd_wr_data) {
449 } else {
451 }
452 return (uint8_t)k_sd_idle;
453}
454
477{
478 uint8_t csd[k_sd_csd_len];
479 memset(csd, 0, sizeof(csd));
480 csd[0] = (uint8_t)k_sd_csd_v2;
481 uint32_t csize = (uint32_t)k_sd_csd_csize; /* fallback: 8 MiB. */
482 if (c->image_len >= (uint32_t)k_sd_csd_unit) {
483 csize = (c->image_len / (uint32_t)k_sd_csd_unit) - 1U;
484 }
485 csd[k_sd_csd_csize_b7] =
486 (uint8_t)((csize >> (uint32_t)k_sd_arg_sh1) & (uint32_t)k_sd_csize_b7_mask);
487 csd[k_sd_csd_csize_b8] =
488 (uint8_t)((csize >> (uint32_t)k_sd_byte_bits) & (uint16_t)k_sd_byte_mask);
489 csd[k_sd_csd_off] = (uint8_t)(csize & (uint16_t)k_sd_byte_mask);
491}
492
515RA8_INTERNAL static bool
517{
518 switch (idx) {
519 case (uint8_t)k_sd_idx_cmd0:
520 c->resp[0] = (uint8_t)k_sd_r1_idle;
521 c->resp_len = 1U;
522 break;
523 case (uint8_t)k_sd_idx_cmd8: /* R7: R1 + 0x000001AA echo. */
524 c->resp[0] = (uint8_t)k_sd_r1_idle;
525 c->resp[1] = 0U;
526 c->resp[2] = 0U;
527 c->resp[3] = 1U;
528 c->resp[4] = (uint8_t)k_sd_cmd8_echo;
529 c->resp_len = (uint8_t)k_sd_r7_len;
530 break;
531 case (uint8_t)k_sd_idx_cmd55:
532 c->app_cmd = true;
533 c->resp[0] = (uint8_t)k_sd_r1_idle;
534 c->resp_len = 1U;
535 break;
536 case (uint8_t)k_sd_idx_cmd58: /* R3: R1 + OCR (CCS=1 -> SDHC). */
537 c->resp[0] = r1;
538 c->resp[1] = (uint8_t)k_sd_ocr_pwrccs;
539 c->resp[2] = (uint8_t)k_sd_idle;
540 c->resp[3] = (uint8_t)k_sd_ocr_volt;
541 c->resp[4] = 0U;
542 c->resp_len = (uint8_t)k_sd_r7_len;
543 break;
544 case (uint8_t)k_sd_idx_cmd16:
545 c->resp[0] = (uint8_t)k_sd_r1_ready;
546 c->resp_len = 1U;
547 break;
548 default:
549 return false;
550 }
551 return true;
552}
553
573RA8_INTERNAL static void
574internal_board_sd_cmd_erase_bound(board_sd_state_t* c, uint32_t* bound, uint32_t arg, uint8_t r1)
575{
576 *bound = arg;
577 c->resp[0] = r1;
578 c->resp_len = 1U;
579}
580
600{
601 if (c->erase_end >= c->erase_start) {
602 const uint64_t lo = (uint64_t)c->erase_start * (uint64_t)k_sd_block;
603 const uint64_t hi = ((uint64_t)c->erase_end + 1U) * (uint64_t)k_sd_block;
604 const uint64_t end = (hi < c->image_len) ? hi : c->image_len;
605 if (lo < end) {
606 if (!priv_board_sd_storage_zero(lo, end - lo)) {
607 r1 = (uint8_t)k_sd_r1_param_err;
608 }
609 }
610 }
611 c->resp[0] = r1;
612 c->resp_len = 1U;
613}
614
637RA8_INTERNAL static void
638internal_board_sd_dispatch_data(board_sd_state_t* c, uint8_t idx, uint32_t arg, uint8_t r1)
639{
640 switch (idx) {
641 case (uint8_t)k_sd_idx_cmd9: /* SEND_CSD: 16-byte CSD v2.0 data block. */
643 break;
644 case (uint8_t)k_sd_idx_cmd17: /* READ_SINGLE_BLOCK (SDHC: arg = block). */
645 case (uint8_t)k_sd_idx_cmd18: /* READ_MULTIPLE_BLOCK -- streams to CMD12. */
646 internal_board_sd_begin_read(c, idx, arg);
647 break;
648 case (uint8_t)k_sd_idx_cmd12: /* STOP_TRANSMISSION: end a CMD18 stream. */
650 break;
651 case (uint8_t)k_sd_idx_cmd24: /* WRITE_SINGLE_BLOCK */
652 case (uint8_t)k_sd_idx_cmd25: /* WRITE_MULTIPLE_BLOCK */
653 internal_board_sd_begin_write(c, idx, arg, r1);
654 break;
655 case (uint8_t)k_sd_idx_cmd32: /* ERASE_WR_BLK_START (SDHC: arg = block). */
657 break;
658 case (uint8_t)k_sd_idx_cmd33: /* ERASE_WR_BLK_END (SDHC: arg = block). */
660 break;
661 case (uint8_t)k_sd_idx_cmd38: /* ERASE: zero the latched [start, end] range. */
663 break;
664 default:
665 c->resp[0] = r1;
666 c->resp_len = 1U;
667 break;
668 }
669}
670
685{
686 const uint8_t idx = (uint8_t)(c->cmd[0] & (uint8_t)k_sd_idx_mask);
687 const uint32_t arg = ((uint32_t)c->cmd[1] << (uint32_t)k_sd_arg_sh0) |
688 ((uint32_t)c->cmd[2] << (uint32_t)k_sd_arg_sh1) |
689 ((uint32_t)c->cmd[3] << (uint32_t)k_sd_byte_bits) | (uint32_t)c->cmd[4];
690 const bool was_app = c->app_cmd;
691 const uint8_t r1 = c->ready ? (uint8_t)k_sd_r1_ready : (uint8_t)k_sd_r1_idle;
692 c->app_cmd = false;
693 c->resp_pos = 0U;
694 c->resp_len = 0U;
695
696 if ((idx == (uint8_t)k_sd_idx_acmd41) && was_app) { /* ACMD41 -- init done. */
697 c->ready = true;
698 c->resp[0] = (uint8_t)k_sd_r1_ready;
699 c->resp_len = 1U;
700 return;
701 }
702 if (internal_board_sd_dispatch_ident(c, idx, r1)) {
703 return;
704 }
705 internal_board_sd_dispatch_data(c, idx, arg, r1);
706}
707
708uint8_t board_sd_exchange(uint8_t tx)
709{
710 if (g_board_sd.resp_pos < g_board_sd.resp_len) {
711 return g_board_sd.resp[g_board_sd.resp_pos++];
712 }
713 if (g_board_sd.wr_phase != k_sd_wr_idle) {
715 }
716 if (g_board_sd.collecting) {
717 g_board_sd.cmd[g_board_sd.cmd_idx] = tx;
718 g_board_sd.cmd_idx++;
719 if (g_board_sd.cmd_idx >= (uint32_t)k_sd_cmd_len) {
720 g_board_sd.collecting = false;
722 }
723 return (uint8_t)k_sd_idle;
724 }
725 if ((tx & (uint8_t)k_sd_cmd_mask) == (uint8_t)k_sd_cmd_start) {
726 g_board_sd.collecting = true;
727 g_board_sd.cmd[0] = tx;
728 g_board_sd.cmd_idx = 1U;
729 return (uint8_t)k_sd_idle;
730 }
731 if (g_board_sd.rd_multi) {
732 /* Open CMD18 stream: the host clocking idle is fetching the next block.
733 * The command-start check above stays first so a CMD12 frame interrupts
734 * the stream instead of being swallowed as read clocking. */
736 return g_board_sd.resp[g_board_sd.resp_pos++];
737 }
738 return (uint8_t)k_sd_idle;
739}
740
741bool board_sd_read_block(uint32_t lba, uint8_t* dst)
742{
743 if (!g_board_sd.attached || (g_board_sd.image_fd < 0) || (dst == nullptr)) {
744 return false;
745 }
746 /* Same SDHC block-addressing as the CMD17 path: arg is a block index. */
747 const uint64_t off = (uint64_t)lba * (uint64_t)k_sd_block;
748 if (off >= g_board_sd.image_len) {
749 return false; /* past the end of the card -- let the real driver error out. */
750 }
751 uint8_t block[k_sd_block];
752 if (!internal_board_sd_fill_block(&g_board_sd, off, block)) {
753 return false;
754 }
755 (void)memcpy(dst, block, sizeof(block));
756 return true;
757}
758
759bool board_sd_write_block(uint32_t lba, const uint8_t* src)
760{
761 if (!g_board_sd.attached || (g_board_sd.image_fd < 0) || (src == nullptr)) {
762 return false;
763 }
764 /* Same SDHC block-addressing as the CMD24 path: arg is a block index. */
765 const uint64_t off = (uint64_t)lba * (uint64_t)k_sd_block;
766 if (off >= g_board_sd.image_len) {
767 return false; /* past the end of the card -- let the real driver error out. */
768 }
769 if ((off + (uint64_t)k_sd_block) > g_board_sd.image_len) {
770 return false; /* a full block would run off the end of the image. */
771 }
772 return priv_board_sd_storage_write(off, src, (size_t)k_sd_block);
773}
774
776{
777 g_board_sd.collecting = false;
778 g_board_sd.app_cmd = false;
779 g_board_sd.ready = false;
780 g_board_sd.cmd_idx = 0U;
781 g_board_sd.resp_len = 0U;
782 g_board_sd.resp_pos = 0U;
783 g_board_sd.wr_phase = k_sd_wr_idle;
784 g_board_sd.wr_multi = false;
785 g_board_sd.wr_off = 0U;
786 g_board_sd.wr_cnt = 0U;
787 g_board_sd.rd_multi = false;
788 g_board_sd.rd_off = 0U;
789}
Multi-channel console log store backing the board view's tabbed console.
void board_console_push(board_console_ch_t ch, const char *line)
Append one completed line to a channel ring and the ALL ring.
@ k_board_console_ch_sd
SD (SDHI + SD-over-SPI) block summaries.
static bool internal_board_sd_fill_block(const board_sd_state_t *c, uint64_t off, uint8_t *blk)
Copy one 512-byte block out of the backing image (zero past the end).
static void internal_sd_write_crc(board_sd_state_t *c)
Swallow the two block-CRC bytes, then acknowledge the block.
static void internal_board_sd_cmd_erase(board_sd_state_t *c, uint8_t r1)
Zero the latched [start, end] block range – CMD38 (ERASE).
static void internal_board_sd_stop_read(board_sd_state_t *c, uint8_t r1)
Answer CMD12 STOP_TRANSMISSION and close any open CMD18 stream.
static void internal_board_sd_cmd_send_csd(board_sd_state_t *c)
Stage the 16-byte CSD v2.0 data block for a CMD9 (SEND_CSD) reply.
static void internal_board_sd_stage_block(board_sd_state_t *c, const uint8_t *payload, uint32_t len)
Stage the R1 + data-token + payload + CRC16 reply for a block read.
sd_console_t
Console-tap sizing for SD-over-SPI block summaries.
@ k_sd_console_rd_every
Push 1 read line per N blocks (anti-flood).
@ k_sd_console_line_cap
Max chars in an "SDSPI .. .." line.
static bool internal_board_sd_dispatch_ident(board_sd_state_t *c, uint8_t idx, uint8_t r1)
Handle the identification / configuration commands (CMD0/8/55/58/16).
static void internal_board_sd_begin_read(board_sd_state_t *c, uint8_t idx, uint32_t arg)
Accept a CMD17/CMD18 block-read command and stage the first block.
static void internal_sd_write_token(board_sd_state_t *c, uint8_t tx)
Handle a byte while the model waits for a write data token.
bool board_sd_read_block(uint32_t lba, uint8_t *dst)
Copy one 512-byte block straight out of the backing image.
static uint16_t internal_board_sd_crc16(const uint8_t *data, uint32_t len)
CRC16-CCITT (poly 0x1021, init 0) over a buffer.
static void internal_sd_write_data(board_sd_state_t *c, uint8_t tx)
Absorb one payload byte of a write block.
static uint8_t internal_board_sd_write_byte(board_sd_state_t *c, uint8_t tx)
Feed one host byte into an in-flight block write; return the CIPO byte.
uint8_t board_sd_exchange(uint8_t tx)
Exchange one full-duplex SPI byte with the modelled card.
static void internal_board_sd_read_stream_next(board_sd_state_t *c)
Stage the next block of an open CMD18 stream (token + payload + CRC).
static void internal_board_sd_process_cmd(board_sd_state_t *c)
Build the response for a completed 6-byte command frame.
bool board_sd_write_block(uint32_t lba, const uint8_t *src)
Copy one 512-byte block straight into the backing image.
static void internal_board_sd_dispatch_data(board_sd_state_t *c, uint8_t idx, uint32_t arg, uint8_t r1)
Handle the data-transfer and erase commands (CMD9/17/18/12/24/25/32/33/38).
static uint32_t s_sd_spi_block_reads
Count of SD-over-SPI data blocks staged for read this run.
void board_sd_reset(void)
Reset the card's command / response framing to power-on.
static void internal_board_sd_cmd_erase_bound(board_sd_state_t *c, uint32_t *bound, uint32_t arg, uint8_t r1)
Record one bound of the CMD32/CMD33 erase range and acknowledge it.
board_sd_cmd_idx_t
SD SPI command indices answered by the model (low 6 bits of byte 0).
@ k_sd_idx_cmd33
ERASE_WR_BLK_END.
@ k_sd_idx_cmd32
ERASE_WR_BLK_START.
@ k_sd_idx_cmd17
READ_SINGLE.
@ k_sd_idx_cmd38
ERASE.
@ k_sd_idx_cmd18
READ_MULTIPLE.
@ k_sd_idx_acmd41
SD_SEND_OP_COND.
@ k_sd_idx_cmd8
SEND_IF_COND.
@ k_sd_idx_cmd55
APP_CMD.
@ k_sd_idx_cmd12
STOP_TRANSMISSION.
@ k_sd_idx_cmd25
WRITE_MULTIPLE.
@ k_sd_idx_cmd16
SET_BLOCKLEN.
@ k_sd_idx_cmd0
GO_IDLE_STATE.
@ k_sd_idx_cmd24
WRITE_SINGLE.
@ k_sd_idx_cmd58
READ_OCR.
@ k_sd_idx_cmd9
SEND_CSD.
static void internal_board_sd_begin_write(board_sd_state_t *c, uint8_t idx, uint32_t arg, uint8_t r1)
Accept a CMD24/CMD25 block-write command and arm the data phase.
SD-card-over-SPI device model for ra8_emulator (attached to SPI_B).
Module-private FAT formatter shared by the board_periph_sd TUs.
bool priv_board_sd_storage_write(uint64_t offset, const void *src, size_t count)
Write exactly to the current sparse backend at a checked byte offset.
bool priv_board_sd_storage_zero(uint64_t offset, uint64_t count)
Make a checked byte range read as zero while preserving sparse storage.
board_sd_state_t g_board_sd
The single modelled SD card (defined in board_periph_sd.c).
@ k_sd_wr_idle
Not in a write transaction.
@ k_sd_wr_token
Awaiting the data-start (or stop-tran) token.
@ k_sd_wr_data
Collecting the 512 payload bytes.
@ k_sd_wr_crc
Collecting the trailing 2 CRC bytes.
@ k_sd_csd_unit
CSD v2.0 C_SIZE unit: 512 KiB.
bool priv_board_sd_storage_read(uint64_t offset, void *dst, size_t count)
Read exactly from the current sparse backend at a checked byte offset.
@ k_sd_csd_csize_b7
C_SIZE high byte offset in the CSD.
@ k_sd_tok_wmulti
Multi-block write data-start token.
@ k_sd_csd_v2
CSD_STRUCTURE = 01b (v2.0 / SDHC).
@ k_sd_r7_len
R1 + 4-byte tail.
@ k_sd_csd_csize
C_SIZE byte (=> 8 MiB modelled card).
@ k_sd_cmd_mask
Mask isolating the lead bits.
@ k_sd_crc_len
Trailing CRC16 bytes after a data block.
@ k_sd_data_error
Data-response token: backend write error.
@ k_sd_cmd_len
Command frame: opcode + 4 arg + crc.
@ k_sd_data_accept
Data-response token: block accepted.
@ k_sd_csd_off
C_SIZE LSB byte offset in the CSD.
@ k_sd_byte_bits
Bits per byte (shift amount).
@ k_sd_crc_poly
CRC16-CCITT polynomial.
@ k_sd_arg_sh1
Arg byte 1 shift.
@ k_sd_idle
Bus idle / CIPO-high byte.
@ k_sd_ocr_pwrccs
OCR byte 0: power-up done + CCS.
@ k_sd_r1_param_err
R1 parameter/backend range error.
@ k_sd_arg_sh0
Arg byte 0 (MSB) shift.
@ k_sd_idx_mask
Command index in the lead byte.
@ k_sd_ocr_volt
OCR byte 2: voltage window.
@ k_sd_block
Bytes per SD block.
@ k_sd_tok_stop
Multi-block write stop-tran token.
@ k_sd_cmd8_echo
CMD8 check pattern echo.
@ k_sd_r1_idle
R1 with IDLE set.
@ k_sd_read_error
Read data-error token: backend fault.
@ k_sd_tok_data
Single-block read / write data token.
@ k_sd_cmd_start
SPI command lead bits (01xxxxxx).
@ k_sd_csd_csize_b8
C_SIZE mid byte offset in the CSD.
@ k_sd_crc_msb
Top bit of the 16-bit CRC register.
@ k_sd_csize_b7_mask
C_SIZE field spans only 6 bits in b7.
@ k_sd_busy
CIPO held low while the card programs.
@ k_sd_csd_len
CSD register length.
@ k_sd_r1_ready
R1, card ready.
@ k_sd_byte_mask
Low-byte mask.
Definition main.c:78
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
void * memset(void *dst, int value, size_t n)
Fill memory with a constant byte value.
void * memcpy(void *dst, const void *src, size_t n)
Copy memory area between non-overlapping regions.
The modelled card: backing image + command/response framing.
uint8_t cmd[k_sd_cmd_len]
Cmd.
uint32_t resp_pos
Resp pos.
bool ready
ACMD41 has completed.
uint32_t erase_start
CMD32 ERASE_WR_BLK_START block.
bool app_cmd
Previous command was CMD55 (APP_CMD).
uint64_t rd_off
Byte offset of the next streamed CMD18 block.
board_sd_wr_phase_t wr_phase
CMD24/CMD25 write sub-state.
bool wr_multi
Write is CMD25 (multi-block).
bool rd_multi
An open CMD18 read stream.
uint64_t image_len
Image size in bytes (64-bit: cards > 4 GB).
uint32_t resp_len
Resp length.
uint64_t wr_off
Byte offset of the current block.
uint32_t wr_cnt
Bytes seen in the data/CRC phase.
uint8_t resp[k_sd_resp_cap]
Resp.
uint8_t wr_block[k_sd_block]
Bounded block-write staging buffer.
uint32_t erase_end
CMD33 ERASE_WR_BLK_END block.