1use crate::errors::SdioError;
5use crate::registers::{SdCic, SdCid, SdCsd, SdOcr};
6use core::{cmp, mem};
7use bytemuck::{bytes_of_mut, bytes_of};
8use cortex_m::singleton;
9use embedded_io::blocking::{Read, Seek, Write};
10use embedded_io::{Io, SeekFrom};
11use hal::dma::single_buffer;
12use hal::dma::single_buffer::Transfer;
13use hal::dma::SingleChannel as SingleChannelDma;
14use hal::pio::{
15 InstalledProgram, MovStatusConfig, PIOBuilder, PIOExt, PinDir, Running, Rx, ShiftDirection,
16 StateMachine, Tx, UninitStateMachine, PIO, SM0, SM1,
17};
18use hal::Timer;
19use pio::{Instruction, InstructionOperands, OutDestination, SetDestination};
20use pio_proc::pio_file;
21use rp2040_hal as hal;
22
23pub const SD_CMD_TIMEOUT_MS: u64 = 1_000;
25
26pub const SD_STARTUP_MS: u64 = 2;
28
29pub const SD_OCR_VOLT_RANGE: u32 = 0b0011_0000__0000_0000_0000_0000;
31
32pub const SD_BLOCK_LEN: usize = 512;
34
35pub const SD_BLOCK_CRC_LEN: usize = 8;
37
38pub const SD_BLOCK_END_LEN: usize = 4;
41
42pub const SD_BLOCK_LEN_TOTAL: usize = SD_BLOCK_LEN + SD_BLOCK_CRC_LEN + SD_BLOCK_END_LEN;
45
46pub const SD_NIBBLE_MULT: usize = 2;
49
50pub const SD_WORD_DIV: usize = 4;
53
54pub const SD_CRC_IDX_MSB: usize = SD_BLOCK_LEN / SD_WORD_DIV;
57pub const SD_CRC_IDX_LSB: usize = SD_CRC_IDX_MSB + 1;
58pub const SD_TEND_IDX: usize = SD_CRC_IDX_LSB + 1;
59
60pub const SD_CLK_DIV_INIT: u16 = 25;
62
63pub const SD_RETRIES: usize = 3;
65
66pub static CRC7_TABLE: [u8; 256] = [
68 0x00, 0x12, 0x24, 0x36, 0x48, 0x5a, 0x6c, 0x7e, 0x90, 0x82, 0xb4, 0xa6, 0xd8, 0xca, 0xfc, 0xee,
69 0x32, 0x20, 0x16, 0x04, 0x7a, 0x68, 0x5e, 0x4c, 0xa2, 0xb0, 0x86, 0x94, 0xea, 0xf8, 0xce, 0xdc,
70 0x64, 0x76, 0x40, 0x52, 0x2c, 0x3e, 0x08, 0x1a, 0xf4, 0xe6, 0xd0, 0xc2, 0xbc, 0xae, 0x98, 0x8a,
71 0x56, 0x44, 0x72, 0x60, 0x1e, 0x0c, 0x3a, 0x28, 0xc6, 0xd4, 0xe2, 0xf0, 0x8e, 0x9c, 0xaa, 0xb8,
72 0xc8, 0xda, 0xec, 0xfe, 0x80, 0x92, 0xa4, 0xb6, 0x58, 0x4a, 0x7c, 0x6e, 0x10, 0x02, 0x34, 0x26,
73 0xfa, 0xe8, 0xde, 0xcc, 0xb2, 0xa0, 0x96, 0x84, 0x6a, 0x78, 0x4e, 0x5c, 0x22, 0x30, 0x06, 0x14,
74 0xac, 0xbe, 0x88, 0x9a, 0xe4, 0xf6, 0xc0, 0xd2, 0x3c, 0x2e, 0x18, 0x0a, 0x74, 0x66, 0x50, 0x42,
75 0x9e, 0x8c, 0xba, 0xa8, 0xd6, 0xc4, 0xf2, 0xe0, 0x0e, 0x1c, 0x2a, 0x38, 0x46, 0x54, 0x62, 0x70,
76 0x82, 0x90, 0xa6, 0xb4, 0xca, 0xd8, 0xee, 0xfc, 0x12, 0x00, 0x36, 0x24, 0x5a, 0x48, 0x7e, 0x6c,
77 0xb0, 0xa2, 0x94, 0x86, 0xf8, 0xea, 0xdc, 0xce, 0x20, 0x32, 0x04, 0x16, 0x68, 0x7a, 0x4c, 0x5e,
78 0xe6, 0xf4, 0xc2, 0xd0, 0xae, 0xbc, 0x8a, 0x98, 0x76, 0x64, 0x52, 0x40, 0x3e, 0x2c, 0x1a, 0x08,
79 0xd4, 0xc6, 0xf0, 0xe2, 0x9c, 0x8e, 0xb8, 0xaa, 0x44, 0x56, 0x60, 0x72, 0x0c, 0x1e, 0x28, 0x3a,
80 0x4a, 0x58, 0x6e, 0x7c, 0x02, 0x10, 0x26, 0x34, 0xda, 0xc8, 0xfe, 0xec, 0x92, 0x80, 0xb6, 0xa4,
81 0x78, 0x6a, 0x5c, 0x4e, 0x30, 0x22, 0x14, 0x06, 0xe8, 0xfa, 0xcc, 0xde, 0xa0, 0xb2, 0x84, 0x96,
82 0x2e, 0x3c, 0x0a, 0x18, 0x66, 0x74, 0x42, 0x50, 0xbe, 0xac, 0x9a, 0x88, 0xf6, 0xe4, 0xd2, 0xc0,
83 0x1c, 0x0e, 0x38, 0x2a, 0x54, 0x46, 0x70, 0x62, 0x8c, 0x9e, 0xa8, 0xba, 0xc4, 0xd6, 0xe0, 0xf2,
84];
85
86pub fn calculate_crc7_from_words(words: &[u32], skip: usize, len: usize) -> u8 {
90 let mut crc: u8 = 0;
91
92 let start_word = skip / 4; let start_shift = 24 - ((skip % 4) * 8);
94
95 let mut word = start_word;
96 let mut shift = start_shift;
97
98 for _ in 0..len {
99 let byte = ((words[word] >> shift) & 0xFF) as u8;
101 let index = byte ^ crc;
102 crc = CRC7_TABLE[index as usize];
103
104 if shift == 0 {
107 shift = 24;
108 word += 1;
109 } else {
110 shift -= 8;
111 }
112 }
113
114 crc
115}
116
117pub fn crc16_4bit(data: &[u32]) -> u64 {
121 let mut crc = 0;
122 for word in data {
124 let data_in = word.swap_bytes();
128
129 let mut data_out: u32 = (crc >> 32) as u32;
132 crc <<= 32;
133
134 data_out ^= (data_out ^ data_in) >> 16;
138
139 let xorred: u64 = (data_out ^ data_in) as u64;
141
142 crc ^= xorred;
144 crc ^= xorred << (5 * 4);
145 crc ^= xorred << (12 * 4);
146 }
147
148 crc
149}
150
151const FLAG_ACMD: u16 = 0x40;
152const FLAG_R0: u16 = 0x00;
153const FLAG_R1: u16 = 0x80;
154const FLAG_R1B: u16 = 0x100;
155const FLAG_R2: u16 = 0x180;
156const FLAG_R3: u16 = 0x200;
157const FLAG_R6: u16 = 0x280;
158const FLAG_R7: u16 = 0x300;
159const FLAGS_R: u16 = 0x380;
160
161#[derive(PartialEq, Clone, Copy)]
162#[repr(u16)]
163pub enum SdCmd {
166 GoIdleState = FLAG_R0 | 0,
168 AllSendCid = FLAG_R2 | 2,
170 SendRelativeAddr = FLAG_R6 | 3,
172 SelectDeselectCard(u16) = FLAG_R1B | 7,
176 SendIfCond(u8) = FLAG_R7 | 8,
179 SendCsd(u16) = FLAG_R2 | 9,
182 SetBlockLen(u32) = FLAG_R1 | 16,
188 ReadSingleBlock(u32) = FLAG_R1 | 17,
191 WriteBlock(u32) = FLAG_R1 | 24,
195 AppCmd(u16) = FLAG_R1 | 55,
203 SetBusWidth(bool) = FLAG_R1 | FLAG_ACMD | 6,
207 SdAppOpCond(bool, bool, bool, u32) = FLAG_R3 | FLAG_ACMD | 41,
213 }
216
217impl Into<u16> for SdCmd {
218 fn into(self) -> u16 {
219 unsafe { (&self as *const Self).cast::<u16>().read() }
221 }
222}
223
224impl SdCmd {
225 #[inline]
226 pub fn get_cmd_index(&self) -> u32 {
228 let val: u16 = (*self).into();
229
230 (val & 0x3f) as u32
232 }
233
234 pub fn get_cmd_response(&self) -> SdCmdResponseType {
236 let val: u16 = (*self).into();
237
238 match val & FLAGS_R {
239 FLAG_R1 => SdCmdResponseType::R1,
240 FLAG_R1B => SdCmdResponseType::R1b,
241 FLAG_R2 => SdCmdResponseType::R2,
242 FLAG_R3 => SdCmdResponseType::R3,
243 FLAG_R6 => SdCmdResponseType::R6,
244 FLAG_R7 => SdCmdResponseType::R7,
245 _ => SdCmdResponseType::R0,
246 }
247 }
248
249 #[inline]
250 pub fn is_acmd(&self) -> bool {
252 let val: u16 = (*self).into();
253
254 (val & FLAG_ACMD) != 0
255 }
256
257 pub fn format(&self) -> [u32; 2] {
259 let mut data: [u32; 2] = [
268 0b0010_1111_0100_0000__0000_0000_0000_0000,
269 0b0000_0000_0000_0000__0000_0001_0000_0000,
270 ];
271
272 data[0] |= self.get_cmd_index() << 16;
274
275 match self {
279 Self::SetBlockLen(unsigned32)
280 | Self::ReadSingleBlock(unsigned32)
281 | Self::WriteBlock(unsigned32) => {
282 data[0] |= (unsigned32 >> 16) & 0xFFFF;
283 data[1] |= (unsigned32 << 16) & 0xFFFF_0000;
284 }
285 Self::GoIdleState | Self::AllSendCid | Self::SendRelativeAddr => {}
287 Self::SelectDeselectCard(rca) | Self::SendCsd(rca) | Self::AppCmd(rca) => {
288 data[0] |= *rca as u32;
290 }
291 Self::SetBusWidth(fourbit) => {
292 data[1] |= match fourbit {
293 true => 0b10 << 16,
294 false => 0,
295 }
296 }
297 Self::SendIfCond(test_pattern) => {
298 data[1] |= 0b0001 << 24;
303 data[1] |= (*test_pattern as u32) << 16;
305 }
306 Self::SdAppOpCond(hcs, xpc, s18r, voltage_window) => {
307 if *hcs {
310 data[0] |= 1 << 14;
311 }
312 if *xpc {
315 data[0] |= 1 << 12;
316 }
317 if *s18r {
320 data[0] |= 1 << 8;
321 }
322
323 data[0] |= (voltage_window >> 16) & 0xFF;
325 data[1] |= (voltage_window << 16) & 0xFFFF_0000;
326 }
327 }
328
329 let crc = calculate_crc7_from_words(&data, 1, 5);
331 data[1] |= (crc as u32) << 8;
332
333 let response_len = self.get_cmd_response().get_response_len() as u32;
335
336 if response_len > 0 {
337 data[1] |= response_len - 1;
338 }
339
340 data
341 }
342}
343
344#[derive(PartialEq)]
346pub enum SdCmdResponseType {
347 R0,
349 R1,
351 R1b,
353 R2,
355 R3,
357 R6,
359 R7,
361}
362
363impl SdCmdResponseType {
364 pub fn get_response_len(&self) -> u8 {
366 match self {
367 SdCmdResponseType::R0 => 0,
368 SdCmdResponseType::R1
369 | SdCmdResponseType::R1b
370 | SdCmdResponseType::R3
371 | SdCmdResponseType::R6
372 | SdCmdResponseType::R7 => 48,
373 SdCmdResponseType::R2 => 136,
374 }
375 }
376}
377
378pub enum SdCmdResponse {
380 R0,
382 R1(SdCardStatus),
384 R1b(SdCardStatus),
386 R2([u32; 4]),
388 R3(SdOcr),
390 R6(u16),
392 R7(SdCic),
394}
395
396pub struct SdCardStatus {
398 pub card_status: u32,
399}
400
401impl SdCardStatus {
402 pub fn get_current_state(&self) -> SdCurrentState {
404 let current_state = (self.card_status >> 9) & 0xF;
405
406 SdCurrentState::from_int(current_state as u8)
407 }
408
409 pub fn get_worst_error(&self) -> Result<(), SdioError> {
410 if (self.card_status & 0b1111_1101_1111_1001__1000_0000_0000_1000) == 0 {
412 return Ok(());
413 }
414
415 if self.cc_error() {
418 return Err(SdioError::CcError {});
419 }
420
421 if self.com_crc_error() {
422 return Err(SdioError::BadTxCrc7 {});
423 }
424
425 if self.illegal_command() {
426 return Err(SdioError::IllegalCommand {});
427 }
428
429 if self.card_ecc_failed() {
430 return Err(SdioError::CardEccFailed {});
431 }
432
433 if self.out_of_range() {
434 return Err(SdioError::OutOfRange {});
435 }
436
437 if self.address_error() {
438 return Err(SdioError::AddressError {});
439 }
440
441 if self.block_len_error() {
442 return Err(SdioError::BlockLenError {});
443 }
444
445 if self.erase_seq_error() {
446 return Err(SdioError::EraseSeqError {});
447 }
448
449 if self.erase_param() {
450 return Err(SdioError::EraseParamError {});
451 }
452
453 if self.wp_violation() {
454 return Err(SdioError::WpViolation {});
455 }
456
457 if self.lock_unlocked_failed() {
458 return Err(SdioError::LockUnlockFailed {});
459 }
460
461 if self.wp_erase_skip() {
462 return Err(SdioError::WpEraseSkip {});
463 }
464
465 if self.ake_seq_error() {
466 return Err(SdioError::AkeSeqError {});
467 }
468
469 Err(SdioError::CmdUnknownErr {})
470 }
471
472 #[inline]
473 pub fn out_of_range(&self) -> bool {
475 (self.card_status & (1 << 31)) > 0
476 }
477 #[inline]
478 pub fn address_error(&self) -> bool {
480 (self.card_status & (1 << 30)) > 0
481 }
482 #[inline]
483 pub fn block_len_error(&self) -> bool {
485 (self.card_status & (1 << 29)) > 0
486 }
487 #[inline]
488 pub fn erase_seq_error(&self) -> bool {
490 (self.card_status & (1 << 28)) > 0
491 }
492 #[inline]
493 pub fn erase_param(&self) -> bool {
495 (self.card_status & (1 << 27)) > 0
496 }
497 #[inline]
498 pub fn wp_violation(&self) -> bool {
500 (self.card_status & (1 << 26)) > 0
501 }
502 #[inline]
503 pub fn card_is_locked(&self) -> bool {
505 (self.card_status & (1 << 25)) > 0
506 }
507 #[inline]
508 pub fn lock_unlocked_failed(&self) -> bool {
510 (self.card_status & (1 << 24)) > 0
511 }
512 #[inline]
513 pub fn com_crc_error(&self) -> bool {
515 (self.card_status & (1 << 23)) > 0
516 }
517 #[inline]
518 pub fn illegal_command(&self) -> bool {
520 (self.card_status & (1 << 22)) > 0
521 }
522 #[inline]
523 pub fn card_ecc_failed(&self) -> bool {
525 (self.card_status & (1 << 21)) > 0
526 }
527 #[inline]
528 pub fn cc_error(&self) -> bool {
530 (self.card_status & (1 << 20)) > 0
531 }
532 #[inline]
533 pub fn error(&self) -> bool {
535 (self.card_status & (1 << 19)) > 0
536 }
537 #[inline]
538 pub fn csd_overwrite(&self) -> bool {
540 (self.card_status & (1 << 16)) > 0
541 }
542 #[inline]
543 pub fn wp_erase_skip(&self) -> bool {
545 (self.card_status & (1 << 15)) > 0
546 }
547 #[inline]
548 pub fn card_ecc_disabled(&self) -> bool {
550 (self.card_status & (1 << 14)) > 0
551 }
552 #[inline]
553 pub fn erase_reset(&self) -> bool {
555 (self.card_status & (1 << 13)) > 0
556 }
557 #[inline]
558 pub fn ready_for_data(&self) -> bool {
560 (self.card_status & (1 << 8)) > 0
561 }
562 #[inline]
563 pub fn fx_event(&self) -> bool {
565 (self.card_status & (1 << 6)) > 0
566 }
567 #[inline]
568 pub fn app_cmd(&self) -> bool {
570 (self.card_status & (1 << 5)) > 0
571 }
572 #[inline]
573 pub fn ake_seq_error(&self) -> bool {
575 (self.card_status & (1 << 3)) > 0
576 }
577}
578
579pub enum SdCurrentState {
580 Idle,
581 Ready,
582 Ident,
583 Stby,
584 Tran,
585 Data,
586 Rcv,
587 Prg,
588 Dis,
589 Reserved,
590}
591
592impl SdCurrentState {
593 pub fn from_int(nibble: u8) -> Self {
595 match nibble {
596 0 => Self::Idle,
597 1 => Self::Ready,
598 2 => Self::Ident,
599 3 => Self::Stby,
600 4 => Self::Tran,
601 5 => Self::Data,
602 6 => Self::Rcv,
603 7 => Self::Prg,
604 8 => Self::Dis,
605 _ => Self::Reserved,
606 }
607 }
608}
609
610pub struct Sdio4bit<'a, DmaCh: SingleChannelDma, P: PIOExt> {
612 dma: Option<DmaCh>,
614 timer: &'a Timer,
616 sm_cmd: StateMachine<(P, SM0), Running>,
618 sm_cmd_rx: Rx<(P, SM0)>,
619 sm_cmd_tx: Tx<(P, SM0)>,
620 sm_dat: Option<UninitStateMachine<(P, SM1)>>,
623 sd_dat_base_id: u8,
625 program_data_rx: Option<InstalledProgram<P>>,
627 program_data_tx: Option<InstalledProgram<P>>,
630
631 cid: SdCid,
633 rca: u16,
635 csd: SdCsd,
637
638 working_block: Option<&'static mut [u32; SD_BLOCK_LEN_TOTAL / SD_WORD_DIV]>,
640 working_block_num: u32,
642 dirty: bool,
644
645 position: u64,
647 size: u32,
649
650 sm_dat_rx: Option<Rx<(P, SM1)>>,
652 sm_dat_tx: Option<Tx<(P, SM1)>>,
653
654 tx_dma_in_use:
656 Option<Transfer<DmaCh, &'static mut [u32; SD_BLOCK_LEN_TOTAL / SD_WORD_DIV], Tx<(P, SM1)>>>,
657 rx_dma_in_use:
659 Option<Transfer<DmaCh, Rx<(P, SM1)>, &'static mut [u32; SD_BLOCK_LEN_TOTAL / SD_WORD_DIV]>>,
660 sm_in_use: Option<StateMachine<(P, SM1), Running>>,
662
663 sd_full_clk_div: u16,
665}
666
667impl<'a, DmaCh: SingleChannelDma, P: PIOExt> Sdio4bit<'a, DmaCh, P> {
668 pub fn new(
670 pio: &mut PIO<P>,
671 dma: DmaCh,
672 timer: &'a Timer,
673 sm0: UninitStateMachine<(P, SM0)>,
674 sm1: UninitStateMachine<(P, SM1)>,
675 sd_clk_id: u8,
676 sd_cmd_id: u8,
677 sd_dat_base_id: u8,
678 sd_full_clk_div: u16,
679 ) -> Self {
680 let program_cmd_clk =
682 pio_file!("src/rp2040_sdio.pio", select_program("sdio_cmd_clk")).program;
683 let program_data_rx =
684 pio_file!("src/rp2040_sdio.pio", select_program("sdio_data_rx")).program;
685 let program_data_tx =
686 pio_file!("src/rp2040_sdio.pio", select_program("sdio_data_tx")).program;
687
688 let program_cmd_clk = pio.install(&program_cmd_clk).unwrap();
690 let program_data_rx = pio.install(&program_data_rx).unwrap();
691 let program_data_tx = pio.install(&program_data_tx).unwrap();
692
693 let (mut sm_cmd, sm_cmd_rx, sm_cmd_tx) = PIOBuilder::from_program(program_cmd_clk)
694 .set_mov_status_config(MovStatusConfig::Tx(2))
695 .set_pins(sd_cmd_id, 1)
696 .out_pins(sd_cmd_id, 1)
697 .in_pin_base(sd_cmd_id)
698 .jmp_pin(sd_cmd_id)
699 .side_set_pin_base(sd_clk_id)
700 .out_shift_direction(ShiftDirection::Left)
701 .in_shift_direction(ShiftDirection::Left)
702 .clock_divisor_fixed_point(SD_CLK_DIV_INIT, 0)
704 .autopush(true)
705 .autopull(true)
706 .build(sm0);
707
708 let working_block = singleton!(: [u32; SD_BLOCK_LEN_TOTAL / SD_WORD_DIV] = [0xAF; SD_BLOCK_LEN_TOTAL / SD_WORD_DIV]).unwrap();
709
710 sm_cmd.set_pindirs([(sd_clk_id, PinDir::Output), (sd_cmd_id, PinDir::Output)]);
711 let sm_cmd = sm_cmd.start();
713
714 let sm_dat = sm1;
715
716 Self {
717 dma: Some(dma),
718 timer,
719 sm_cmd,
720 sm_cmd_rx,
721 sm_cmd_tx,
722 sm_dat: Some(sm_dat),
723 sd_dat_base_id,
724 program_data_rx: Some(program_data_rx),
725 program_data_tx: Some(program_data_tx),
726 cid: SdCid::new([0; 4]),
727 rca: 0,
729 csd: SdCsd::new([0; 4]),
730
731 working_block: Some(working_block),
732 working_block_num: 0,
733 dirty: false,
734
735 position: 0,
736 size: 0,
737 sm_dat_rx: None,
739 sm_dat_tx: None,
740 tx_dma_in_use: None,
741 rx_dma_in_use: None,
742 sm_in_use: None,
743 sd_full_clk_div,
744 }
745 }
746
747 pub fn send_command(&mut self, command: SdCmd) -> Result<SdCmdResponse, SdioError> {
749 if command.is_acmd() {
751 self.send_command(SdCmd::AppCmd(self.rca))?;
752 }
753
754 let command_data = command.format();
756
757 self.sm_cmd_tx.write(command_data[0]);
759 self.sm_cmd_tx.write(command_data[1]);
760
761 let response_type = command.get_cmd_response();
762
763 let mut resp_buf: [u32; 5] = [0; 5];
766
767 let resp_len_bits = response_type.get_response_len();
770 let resp_len: usize = ((resp_len_bits / 32) + 1) as usize;
771
772 for i in 0..resp_len {
773 let start_time = self.timer.get_counter();
774 while self.sm_cmd_rx.is_empty() {
775 let current_time = self.timer.get_counter();
776
777 let time_delta = current_time
778 .checked_duration_since(start_time)
779 .unwrap()
780 .to_millis();
781
782 if time_delta > SD_CMD_TIMEOUT_MS {
783 return Err(SdioError::CmdTimeout {
784 cmd: command.get_cmd_index() as u8,
785 time_ms: time_delta,
786 });
787 }
788 }
789
790 resp_buf[i] = self.sm_cmd_rx.read().unwrap();
791 }
792
793 resp_buf[resp_len - 1] = resp_buf[resp_len - 1] << (32 - (resp_len_bits % 32));
796
797 if response_type == SdCmdResponseType::R0 {
799 return Ok(SdCmdResponse::R0);
800 }
801
802 if response_type != SdCmdResponseType::R2 && response_type != SdCmdResponseType::R3 {
804 let good_crc = calculate_crc7_from_words(&resp_buf, 0, 5);
808
809 let crc = ((resp_buf[1] >> 16) & 0xFE) as u8;
810
811 if good_crc != crc {
812 return Err(SdioError::BadRxCrc7 {
813 good_crc,
814 bad_crc: crc,
815 });
816 }
817
818 let good_command_index = command.get_cmd_index();
819
820 let command_index = (resp_buf[0] >> 24) & 0x3F;
821
822 if good_command_index != command_index {
823 return Err(SdioError::WrongCmd {
824 good_cmd: good_command_index as u8,
825 bad_cmd: command_index as u8,
826 });
827 }
828 }
829
830 match response_type {
832 SdCmdResponseType::R1 => {
833 let card_status = SdCardStatus {
834 card_status: ((resp_buf[0] & 0x00FF_FFFF) << 8)
835 | ((resp_buf[1] & 0xFF00_0000) >> 24),
836 };
837
838 card_status.get_worst_error()?;
840
841 Ok(SdCmdResponse::R1(card_status))
842 }
843 SdCmdResponseType::R1b => {
844 let card_status = SdCardStatus {
845 card_status: ((resp_buf[0] & 0x00FF_FFFF) << 8)
846 | ((resp_buf[1] & 0xFF00_0000) >> 24),
847 };
848
849 card_status.get_worst_error()?;
850
851 Ok(SdCmdResponse::R1b(card_status))
852 }
853 SdCmdResponseType::R2 => {
854 let mut words: [u32; 4] = [0; 4];
855
856 words[0] = ((resp_buf[0] & 0x00FF_FFFF) << 8) | ((resp_buf[1] & 0xFF00_0000) >> 24);
859 words[1] = ((resp_buf[1] & 0x00FF_FFFF) << 8) | ((resp_buf[2] & 0xFF00_0000) >> 24);
860 words[2] = ((resp_buf[2] & 0x00FF_FFFF) << 8) | ((resp_buf[3] & 0xFF00_0000) >> 24);
861 words[3] = ((resp_buf[3] & 0x00FF_FFFF) << 8) | ((resp_buf[4] & 0xFF00_0000) >> 24);
862
863 Ok(SdCmdResponse::R2(words))
864 }
865 SdCmdResponseType::R3 => {
866 let ocr = ((resp_buf[0] & 0x00FF_FFFF) << 8) | ((resp_buf[1] & 0xFF00_0000) >> 24);
867
868 Ok(SdCmdResponse::R3(SdOcr { ocr }))
869 }
870 SdCmdResponseType::R6 => {
871 let rca: u16 = ((resp_buf[0] & 0x00FF_FF00) >> 8) as u16;
872
873 Ok(SdCmdResponse::R6(rca))
878 }
879 SdCmdResponseType::R7 => {
880 let good_check_pattern = match command {
881 SdCmd::SendIfCond(check_pattern) => check_pattern,
882 _ => panic!("Command repsonds with R7, not SendIfCond!"),
883 };
884 let supports_1p2v = (resp_buf[0] & 0x0000_0000_0000_0000__0000_0000_0010_0000) > 0;
888 let supports_pcie = (resp_buf[0] & 0x0000_0000_0000_0000__0000_0000_0001_0000) > 0;
889
890 let voltage = (resp_buf[0] & 0x0000_0000_0000_0000__0000_0000_0000_1111) as u8;
892
893 if voltage != 0b0001 {
894 return Err(SdioError::BadVoltage { bad_volt: voltage });
895 }
896
897 let check_pattern = ((resp_buf[1] >> 24) & 0xFF) as u8;
899
900 if check_pattern != good_check_pattern {
901 return Err(SdioError::BadCheck {
902 good_check: good_check_pattern,
903 bad_check: check_pattern,
904 });
905 }
906
907 Ok(SdCmdResponse::R7(SdCic {
908 supports_1p2v,
909 supports_pcie,
910 }))
911 }
912 SdCmdResponseType::R0 => {
913 panic!("Reached R0 somehow!");
914 } }
916 }
917
918 pub fn start_block_tx(&mut self) -> Result<(), SdioError> {
920 let sm_dat = match mem::take(&mut self.sm_dat) {
922 Some(sm) => sm,
923
924 None => {
925 return Err(SdioError::InTxRx {});
926 }
927 };
928
929 let dma = mem::take(&mut self.dma).unwrap();
933 let program = mem::take(&mut self.program_data_tx).unwrap();
934 let working_block = mem::take(&mut self.working_block).unwrap();
935
936 let crc = crc16_4bit(&working_block[..SD_BLOCK_LEN / SD_WORD_DIV]);
938
939 working_block[SD_CRC_IDX_LSB] = ((crc & 0xFFFF_FFFF) as u32).swap_bytes();
940 working_block[SD_CRC_IDX_MSB] = (((crc >> 32) & 0xFFFF_FFFF) as u32).swap_bytes();
941
942 working_block[SD_TEND_IDX] = 0xFFFF_FFFF;
944
945 let (mut sm_dat, sm_dat_rx, mut sm_dat_tx) = PIOBuilder::from_program(program)
947 .in_pin_base(self.sd_dat_base_id)
948 .set_pins(self.sd_dat_base_id, 4)
949 .out_pins(self.sd_dat_base_id, 4)
950 .in_shift_direction(ShiftDirection::Left)
951 .out_shift_direction(ShiftDirection::Left)
952 .autopush(false)
953 .autopull(true)
954 .clock_divisor_fixed_point(self.sd_full_clk_div, 0)
955 .build(sm_dat);
956
957 sm_dat_tx.write((SD_BLOCK_LEN_TOTAL * SD_NIBBLE_MULT) as u32);
959 sm_dat.exec_instruction(Instruction {
960 operands: InstructionOperands::OUT {
961 destination: OutDestination::X,
962 bit_count: 32,
963 },
964 delay: 0,
965 side_set: None,
966 });
967
968 sm_dat_tx.write(31);
969 sm_dat.exec_instruction(Instruction {
970 operands: InstructionOperands::OUT {
971 destination: OutDestination::Y,
972 bit_count: 32,
973 },
974 delay: 0,
975 side_set: None,
976 });
977
978 sm_dat.exec_instruction(Instruction {
980 operands: InstructionOperands::SET {
981 destination: SetDestination::PINS,
982 data: 0xF,
983 },
984 delay: 0,
985 side_set: None,
986 });
987
988 sm_dat.exec_instruction(Instruction {
989 operands: InstructionOperands::SET {
990 destination: SetDestination::PINDIRS,
991 data: 0xF,
992 },
993 delay: 0,
994 side_set: None,
995 });
996
997 sm_dat_tx.write(0b1111_1111_1111_1111__1111_1111_1111_0000);
999
1000 let mut tx_transfer = single_buffer::Config::new(dma, working_block, sm_dat_tx);
1002 tx_transfer.bswap(true);
1003
1004 self.send_command(SdCmd::WriteBlock(self.working_block_num))?;
1006
1007 let tx_transfer = tx_transfer.start();
1009 let sm_dat = sm_dat.start();
1010
1011 self.tx_dma_in_use = Some(tx_transfer);
1013 self.sm_in_use = Some(sm_dat);
1014 self.sm_dat_rx = Some(sm_dat_rx);
1015
1016 Ok(())
1017 }
1018
1019 pub fn check_write_response(mut response: u32) -> Result<(), SdioError> {
1023 if (!response & 0xFFFF_0000) == 0 {
1024 response <<= 16;
1025 }
1026
1027 if (!response & 0xFF00_0000) == 0 {
1028 response <<= 8;
1029 }
1030
1031 if (!response & 0xF000_0000) == 0 {
1032 response <<= 4;
1033 }
1034
1035 if (!response & 0xC000_0000) == 0 {
1036 response <<= 2;
1037 }
1038
1039 if (!response & 0x8000_0000) == 0 {
1040 response <<= 1;
1041 }
1042
1043 response = response >> 28 & 7;
1044
1045 match response {
1046 2 => Ok(()),
1047 5 => Err(SdioError::BadTxCrc16 {}),
1048 6 => Err(SdioError::WriteFail {}),
1049 _ => Err(SdioError::WriteUnknown { response }),
1050 }
1051 }
1052
1053 #[inline]
1054 pub fn is_tx(&self) -> bool {
1056 match &self.tx_dma_in_use {
1057 Some(_) => true,
1058 None => false,
1059 }
1060 }
1061
1062 pub fn poll_tx(&mut self) -> Result<bool, SdioError> {
1064 let ready = match &self.tx_dma_in_use {
1066 Some(tx_dma) => tx_dma.is_done(),
1067 None => return Ok(false),
1068 };
1069
1070 if !ready {
1071 return Ok(true);
1072 }
1073
1074 let start_time = self.timer.get_counter();
1076 let mut time_delta = 0;
1077 while self.sm_dat_rx.as_ref().unwrap().is_empty() {
1078 let current_time = self.timer.get_counter();
1079
1080 time_delta = current_time
1081 .checked_duration_since(start_time)
1082 .unwrap()
1083 .to_millis();
1084
1085 if time_delta > SD_CMD_TIMEOUT_MS {
1086 break;
1087 }
1088 }
1089
1090 let response = self.sm_dat_rx.as_mut().unwrap().read();
1093
1094 let (dma, working_block, sm_dat_tx) = mem::take(&mut self.tx_dma_in_use).unwrap().wait();
1097
1098 let sm_dat_rx = mem::take(&mut self.sm_dat_rx).unwrap();
1100 let (sm_dat, program_data_tx) = mem::take(&mut self.sm_in_use)
1101 .unwrap()
1102 .uninit(sm_dat_rx, sm_dat_tx);
1103
1104 self.program_data_tx = Some(program_data_tx);
1106 self.dma = Some(dma);
1107 self.working_block = Some(working_block);
1108 self.sm_dat = Some(sm_dat);
1109
1110 let response = match response {
1111 Some(response) => response,
1112 None => {
1113 return Err(SdioError::WriteTimeout {
1114 time_ms: time_delta,
1115 });
1116 }
1117 };
1118
1119 Self::check_write_response(response)?;
1121
1122 Ok(false)
1124 }
1125
1126 #[inline]
1127 pub fn wait_tx(&mut self) -> Result<(), SdioError> {
1129 while self.poll_tx()? {}
1130
1131 Ok(())
1132 }
1133
1134 #[inline]
1135 pub fn start_block_rx(&mut self) -> Result<(), SdioError> {
1137 let sm_dat = match mem::take(&mut self.sm_dat) {
1139 Some(sm) => sm,
1140
1141 None => {
1142 return Err(SdioError::InTxRx {});
1143 }
1144 };
1145
1146 let dma = mem::take(&mut self.dma).unwrap();
1150 let program = mem::take(&mut self.program_data_rx).unwrap();
1151 let working_block = mem::take(&mut self.working_block).unwrap();
1152
1153 let (mut sm_dat, sm_dat_rx, mut sm_dat_tx) = PIOBuilder::from_program(program)
1155 .in_pin_base(self.sd_dat_base_id)
1156 .set_pins(self.sd_dat_base_id, 4)
1157 .out_pins(self.sd_dat_base_id, 4)
1158 .in_shift_direction(ShiftDirection::Left)
1159 .autopush(true)
1160 .autopull(true)
1161 .clock_divisor_fixed_point(self.sd_full_clk_div, 0)
1162 .build(sm_dat);
1163
1164 sm_dat_tx.write((SD_BLOCK_LEN_TOTAL * SD_NIBBLE_MULT) as u32);
1166 sm_dat.exec_instruction(Instruction {
1167 operands: InstructionOperands::OUT {
1168 destination: OutDestination::X,
1169 bit_count: 32,
1170 },
1171 delay: 0,
1172 side_set: None,
1173 });
1174
1175 sm_dat.exec_instruction(Instruction {
1178 operands: InstructionOperands::SET {
1179 destination: SetDestination::PINS,
1180 data: 0xF,
1181 },
1182 delay: 0,
1183 side_set: None,
1184 });
1185
1186 sm_dat.exec_instruction(Instruction {
1187 operands: InstructionOperands::SET {
1188 destination: SetDestination::PINDIRS,
1189 data: 0xF,
1190 },
1191 delay: 0,
1192 side_set: None,
1193 });
1194
1195 sm_dat.exec_instruction(Instruction {
1197 operands: InstructionOperands::SET {
1198 destination: SetDestination::PINDIRS,
1199 data: 0x0,
1200 },
1201 delay: 0,
1202 side_set: None,
1203 });
1204
1205 let mut rx_transfer = single_buffer::Config::new(dma, sm_dat_rx, working_block);
1207 rx_transfer.bswap(true);
1208
1209 let rx_transfer = rx_transfer.start();
1211 let sm_dat = sm_dat.start();
1212
1213 self.send_command(SdCmd::ReadSingleBlock(self.working_block_num))?;
1215
1216 self.rx_dma_in_use = Some(rx_transfer);
1218 self.sm_in_use = Some(sm_dat);
1219 self.sm_dat_tx = Some(sm_dat_tx);
1220
1221 Ok(())
1222 }
1223
1224 #[inline]
1225 pub fn is_rx(&self) -> bool {
1227 match &self.rx_dma_in_use {
1228 Some(_) => true,
1229 None => false,
1230 }
1231 }
1232
1233 pub fn poll_rx(&mut self) -> Result<bool, SdioError> {
1235 let ready = match &self.rx_dma_in_use {
1237 Some(rx_dma) => rx_dma.is_done(),
1238 None => return Ok(false),
1239 };
1240
1241 if !ready {
1242 return Ok(true);
1243 }
1244
1245 let (dma, sm_dat_rx, working_block) = mem::take(&mut self.rx_dma_in_use).unwrap().wait();
1248
1249 let sm_dat_tx = mem::take(&mut self.sm_dat_tx).unwrap();
1251 let (sm_dat, program_data_rx) = mem::take(&mut self.sm_in_use)
1252 .unwrap()
1253 .uninit(sm_dat_rx, sm_dat_tx);
1254
1255 let crc: u64 =
1258 (working_block[SD_CRC_IDX_LSB].swap_bytes() as u64) | ((working_block[SD_CRC_IDX_MSB].swap_bytes() as u64) << 32);
1259 let good_crc = crc16_4bit(&working_block[..SD_BLOCK_LEN / SD_WORD_DIV]);
1260
1261 self.program_data_rx = Some(program_data_rx);
1263 self.dma = Some(dma);
1264 self.working_block = Some(working_block);
1265 self.sm_dat = Some(sm_dat);
1266
1267
1268 if crc != good_crc {
1271 return Err(SdioError::BadRxCrc16 {
1272 good_crc,
1273 bad_crc: crc,
1274 });
1275 }
1276
1277 Ok(false)
1279 }
1280
1281 #[inline]
1282 pub fn wait_rx(&mut self) -> Result<(), SdioError> {
1284 while self.poll_rx()? {}
1285
1286 Ok(())
1287 }
1288
1289 pub fn is_rx_tx(&self) -> bool {
1291 self.is_rx() | self.is_tx()
1292 }
1293
1294 pub fn poll_rx_tx(&mut self) -> Result<bool, SdioError> {
1296 if let Some(_) = self.tx_dma_in_use {
1298 return self.poll_tx();
1299 }
1300
1301 if let Some(_) = self.rx_dma_in_use {
1302 return self.poll_rx();
1303 }
1304
1305 Ok(false)
1307 }
1308
1309 pub fn wait_rx_tx(&mut self) -> Result<(), SdioError> {
1311 while self.poll_rx_tx()? {}
1312
1313 Ok(())
1314 }
1315
1316 pub fn init(&mut self) -> Result<(), SdioError> {
1318 let start_time = self.timer.get_counter();
1320 let mut current_time = start_time;
1321 while current_time
1322 .checked_duration_since(start_time)
1323 .unwrap()
1324 .to_millis()
1325 < SD_STARTUP_MS
1326 {
1327 current_time = self.timer.get_counter();
1328 }
1329
1330 self.send_command(SdCmd::GoIdleState)?;
1332
1333 let cic = match self.send_command(SdCmd::SendIfCond(0xAA))? {
1336 SdCmdResponse::R7(cic) => cic,
1337 _ => {
1338 panic!("Incorrect response type!");
1339 }
1340 };
1341
1342 let acmd41 = SdCmd::SdAppOpCond(true, true, false, SD_OCR_VOLT_RANGE);
1345
1346 let mut is_busy = true;
1347 let mut ocr = SdOcr { ocr: 0 };
1348
1349 while is_busy {
1350 ocr = match self.send_command(acmd41)? {
1351 SdCmdResponse::R3(ocr) => ocr,
1352 _ => {
1353 panic!("Incorrect response type!");
1354 }
1355 };
1356
1357 is_busy = ocr.is_busy();
1358 }
1359
1360 let voltage_range = ocr.get_voltage_window();
1361 if (voltage_range & SD_OCR_VOLT_RANGE) != SD_OCR_VOLT_RANGE {
1362 return Err(SdioError::BadVoltRange {
1363 range: voltage_range,
1364 });
1365 }
1366
1367 let cid = match self.send_command(SdCmd::AllSendCid)? {
1369 SdCmdResponse::R2(cid) => cid,
1370 _ => panic!("Incorrect response type!"),
1371 };
1372
1373 self.cid = SdCid::new(cid);
1374
1375 let rca = match self.send_command(SdCmd::SendRelativeAddr)? {
1377 SdCmdResponse::R6(rca) => rca,
1378 _ => {
1379 panic!("Incorrect response type!");
1380 }
1381 };
1382
1383 self.rca = rca;
1384
1385 let csd = match self.send_command(SdCmd::SendCsd(rca))? {
1387 SdCmdResponse::R2(csd) => csd,
1388 _ => {
1389 panic!("Incorrect response type!");
1390 }
1391 };
1392
1393 self.csd = SdCsd::new(csd);
1394
1395 self.send_command(SdCmd::SelectDeselectCard(rca))?;
1397
1398 self.send_command(SdCmd::SetBusWidth(true))?;
1400
1401 self.send_command(SdCmd::SetBlockLen(SD_BLOCK_LEN as u32))?;
1403
1404 self.sm_cmd
1406 .clock_divisor_fixed_point(self.sd_full_clk_div, 0);
1407
1408 self.start_block_rx()?;
1410 self.wait_rx()?;
1411 Ok(())
1412 }
1413}
1414
1415impl<'a, DmaCh: SingleChannelDma, P: PIOExt> Io for Sdio4bit<'a, DmaCh, P> {
1416 type Error = SdioError;
1417}
1418
1419impl<'a, DmaCh: SingleChannelDma, P: PIOExt> Read for Sdio4bit<'a, DmaCh, P> {
1420 fn read(&mut self, buffer: &mut [u8]) -> Result<usize, SdioError> {
1421 self.wait_rx_tx()?;
1423
1424 let current_block_num = (self.position / (SD_BLOCK_LEN as u64)) as u32;
1427
1428 if current_block_num != self.working_block_num {
1429 self.flush()?;
1430 self.wait_tx()?;
1431
1432 self.working_block_num = current_block_num;
1433 self.start_block_rx()?;
1434 self.wait_rx()?;
1435 }
1436
1437 let working_block = & **self.working_block.as_ref().unwrap();
1438 let working_block_bytes = bytes_of(working_block);
1439
1440 let block_index: usize = (self.position % (SD_BLOCK_LEN as u64)) as usize;
1441
1442 let bytes_transfered = cmp::min(SD_BLOCK_LEN - block_index, buffer.len());
1443
1444 buffer[..bytes_transfered].copy_from_slice(&working_block_bytes[block_index..block_index + bytes_transfered]);
1445
1446 self.position += bytes_transfered as u64;
1447
1448 Ok(bytes_transfered)
1449 }
1450}
1451
1452impl<'a, DmaCh: SingleChannelDma, P: PIOExt> Write for Sdio4bit<'a, DmaCh, P> {
1453 fn write(&mut self, buffer: &[u8]) -> Result<usize, SdioError> {
1458 self.wait_rx_tx()?;
1460
1461 let current_block_num = (self.position / (SD_BLOCK_LEN as u64)) as u32;
1464
1465 if current_block_num != self.working_block_num {
1466 self.flush()?;
1467 self.wait_tx()?;
1468
1469 self.working_block_num = current_block_num;
1470 self.start_block_rx()?;
1471 self.wait_rx()?;
1472 }
1473
1474 self.dirty = true;
1476
1477 let working_block = &mut **self.working_block.as_mut().unwrap();
1478 let working_block_bytes = bytes_of_mut(working_block);
1479
1480 let block_index: usize = (self.position % (SD_BLOCK_LEN as u64)) as usize;
1481
1482 let bytes_transfered = cmp::min(SD_BLOCK_LEN - block_index, buffer.len());
1483
1484 working_block_bytes[block_index..block_index + bytes_transfered].copy_from_slice(&buffer[..bytes_transfered]);
1485
1486 self.position += bytes_transfered as u64;
1487
1488 Ok(bytes_transfered)
1489
1490 }
1491
1492 fn flush(&mut self) -> Result<(), SdioError> {
1493 if !self.dirty {
1495 return Ok(());
1496 }
1497
1498 self.dirty = false;
1500
1501 if self.is_tx() {
1503 return Ok(());
1504 }
1505
1506 self.wait_rx()?;
1508
1509 self.start_block_tx()?;
1510
1511 Ok(())
1512 }
1513}
1514
1515impl<'a, DmaCh: SingleChannelDma, P: PIOExt> Seek for Sdio4bit<'a, DmaCh, P> {
1516 fn seek(&mut self, position: SeekFrom) -> Result<u64, SdioError> {
1517 Ok(match position {
1518 SeekFrom::Start(position) => {
1519 self.position = position;
1520 self.position
1521 }
1522 SeekFrom::End(position) => {
1523 todo!()
1524 }
1525 SeekFrom::Current(delta) => {
1526 self.position = ((self.position as i64) + delta) as u64;
1527 self.position
1528 }
1529 })
1530 }
1531}