@@ -167,38 +167,73 @@ pub enum Error {
167
167
TxUnderrun ,
168
168
}
169
169
170
- macro_rules! datapath_err {
171
- ( $sta: expr) => {
170
+ macro_rules! sta_rx_tx_err {
171
+ ( $sta: expr, $sdmmc : expr ) => {
172
172
if $sta. dcrcfail( ) . bit( ) {
173
+ clear_static_data_flags( & $sdmmc. icr) ;
174
+
173
175
return Err ( Error :: DataCrc ) ;
174
176
}
175
177
176
178
if $sta. dtimeout( ) . bit( ) {
179
+ clear_static_data_flags( & $sdmmc. icr) ;
180
+
177
181
return Err ( Error :: Timeout ) ;
178
182
}
179
183
} ;
180
184
}
181
185
182
- macro_rules! datapath_rx_err {
183
- ( $sta: expr) => {
184
- if $sta. rxoverr( ) . bit( ) {
186
+ macro_rules! sta_rx {
187
+ ( $sdmmc: expr) => { {
188
+ let sta = $sdmmc. sta. read( ) ;
189
+
190
+ if sta. rxoverr( ) . bit( ) {
191
+ clear_static_data_flags( & $sdmmc. icr) ;
192
+
185
193
return Err ( Error :: RxOverrun ) ;
186
194
}
187
195
188
- datapath_err!( $sta)
189
- } ;
196
+ sta_rx_tx_err!( sta, $sdmmc) ;
197
+
198
+ sta
199
+ } } ;
190
200
}
191
201
192
- macro_rules! datapath_tx_err {
193
- ( $sta: expr) => {
194
- if $sta. rxoverr( ) . bit( ) {
195
- return Err ( Error :: RxOverrun ) ;
202
+ macro_rules! sta_tx {
203
+ ( $sdmmc: expr) => { {
204
+ let sta = $sdmmc. sta. read( ) ;
205
+
206
+ if sta. txunderr( ) . bit( ) {
207
+ clear_static_data_flags( & $sdmmc. icr) ;
208
+
209
+ return Err ( Error :: TxUnderrun ) ;
196
210
}
197
211
198
- datapath_err!( $sta)
199
- } ;
212
+ sta_rx_tx_err!( sta, $sdmmc) ;
213
+
214
+ sta
215
+ } } ;
200
216
}
201
217
218
+ #[ inline]
219
+ fn clear_static_data_flags ( icr : & sdmmc1:: ICR ) {
220
+ icr. modify ( |_, w| {
221
+ w. dcrcfailc ( )
222
+ . set_bit ( )
223
+ . dtimeoutc ( )
224
+ . set_bit ( )
225
+ . txunderrc ( )
226
+ . set_bit ( )
227
+ . rxoverrc ( )
228
+ . set_bit ( )
229
+ . dataendc ( )
230
+ . set_bit ( )
231
+ . dbckendc ( )
232
+ . set_bit ( )
233
+ } )
234
+ }
235
+
236
+ #[ inline]
202
237
fn clear_all_interrupts ( icr : & sdmmc1:: ICR ) {
203
238
icr. modify ( |_, w| {
204
239
w. ccrcfailc ( )
@@ -440,40 +475,64 @@ impl Sdmmc {
440
475
441
476
self . cmd ( common_cmd:: set_block_length ( 512 ) ) ?;
442
477
443
- let bytes = blocks. len ( ) * 512 ;
444
- self . start_datapath_transfer ( bytes as u32 , 9 , Dir :: CardToHost ) ;
478
+ let block_count = blocks. len ( ) ;
479
+ let byte_count = block_count * 512 ;
480
+ self . start_datapath_transfer ( byte_count as u32 , 9 , Dir :: CardToHost ) ;
445
481
446
- match blocks . len ( ) {
482
+ match block_count {
447
483
0 => return Ok ( ( ) ) ,
448
484
1 => self . cmd ( common_cmd:: read_single_block ( addr) ) ?,
449
485
_ => self . cmd ( common_cmd:: read_multiple_blocks ( addr) ) ?,
450
486
}
451
487
488
+ let mut current_block = & mut blocks[ 0 ] ;
489
+
452
490
let mut i = 0 ;
453
491
let timeout: u32 = 0xffff_ffff ;
454
492
for _ in 0 ..timeout {
455
- let sta = self . sdmmc . sta . read ( ) ;
456
-
457
- datapath_rx_err ! ( sta) ;
493
+ let sta = sta_rx ! ( self . sdmmc) ;
458
494
459
- if i == bytes {
495
+ // If we received all data, wait for transfer to end.
496
+ if i == byte_count {
460
497
if sta. dbckend ( ) . bit ( ) {
461
- if blocks. len ( ) > 1 {
498
+ clear_static_data_flags ( & self . sdmmc . icr ) ;
499
+
500
+ if block_count > 1 {
462
501
self . cmd ( common_cmd:: stop_transmission ( ) ) ?;
463
502
}
464
503
465
504
return Ok ( ( ) ) ;
466
505
}
467
- } else if sta. rxfifohf ( ) . bit ( ) {
468
- for _ in 0 ..8 {
469
- let bits = u32:: from_be ( self . sdmmc . fifo . read ( ) . bits ( ) ) ;
470
- let start = i % 512 ;
471
- blocks[ i / 512 ] [ start..( start + 4 ) ] . copy_from_slice ( & bits. to_be_bytes ( ) ) ;
472
- i += 4 ;
506
+ }
507
+ // If the FIFO is half-full, receive some data.
508
+ else if sta. rxfifohf ( ) . bit ( ) {
509
+ let offset = i % 512 ;
510
+
511
+ // SAFETY: We always read exactly 32 bytes from the FIFO into
512
+ // a 512-byte block. We move to the next block if needed before
513
+ // the next iteration.
514
+ //
515
+ // NOTE: This is needed since checked access takes to long and
516
+ // results in a FIFO overrun error on higher clock speeds.
517
+ unsafe {
518
+ for j in 0 ..8 {
519
+ let current_block = current_block. as_mut_ptr ( ) as * mut [ u8 ; 4 ] ;
520
+ let current_bytes = & mut * current_block. add ( offset / 4 + j) ;
521
+
522
+ let bytes = u32:: from_be ( self . sdmmc . fifo . read ( ) . bits ( ) ) . to_be_bytes ( ) ;
523
+ * current_bytes = bytes;
524
+ }
525
+ }
526
+
527
+ i += 4 * 8 ;
528
+
529
+ if i % 512 == 0 && i != byte_count {
530
+ current_block = & mut blocks[ i / 512 ] ;
473
531
}
474
532
}
475
533
}
476
534
535
+ clear_static_data_flags ( & self . sdmmc . icr ) ;
477
536
Err ( Error :: SoftwareTimeout )
478
537
}
479
538
@@ -499,51 +558,64 @@ impl Sdmmc {
499
558
_ => addr,
500
559
} ;
501
560
502
- let bytes = blocks. len ( ) * 512 ;
561
+ let byte_count = blocks. len ( ) * 512 ;
503
562
self . cmd ( common_cmd:: set_block_length ( 512 ) ) ?;
504
- self . start_datapath_transfer ( bytes as u32 , 9 , Dir :: HostToCard ) ;
563
+ self . start_datapath_transfer ( byte_count as u32 , 9 , Dir :: HostToCard ) ;
505
564
506
565
match blocks. len ( ) {
507
566
0 => return Ok ( ( ) ) ,
508
567
1 => self . cmd ( common_cmd:: write_single_block ( addr) ) ?,
509
568
_ => self . cmd ( common_cmd:: write_multiple_blocks ( addr) ) ?,
510
569
}
511
570
571
+ let mut current_block = & blocks[ 0 ] ;
572
+
512
573
let mut i = 0 ;
513
574
loop {
514
- let sta = self . sdmmc . sta . read ( ) ;
515
-
516
- datapath_tx_err ! ( sta) ;
575
+ let sta = sta_tx ! ( self . sdmmc) ;
517
576
518
- if i == bytes {
519
- // If we sent all data, wait for transfer to end.
577
+ // If we sent all data, wait for transfer to end.
578
+ if i == byte_count {
520
579
if sta. dbckend ( ) . bit ( ) {
580
+ clear_static_data_flags ( & self . sdmmc . icr ) ;
581
+
521
582
if blocks. len ( ) > 1 {
522
583
self . cmd ( common_cmd:: stop_transmission ( ) ) ?;
523
584
}
524
585
525
586
break ;
526
587
}
527
- } else {
528
- // If the FIFO is half-empty, send some data.
529
- if sta. txfifohe ( ) . bit ( ) {
530
- for _ in 0 ..8 {
531
- let block = & blocks[ i / 512 ] ;
532
- let start = i % 512 ;
533
-
534
- let bits = u32:: from_be_bytes ( [
535
- block[ start] ,
536
- block[ start + 1 ] ,
537
- block[ start + 2 ] ,
538
- block[ start + 3 ] ,
539
- ] ) ;
540
- self . sdmmc . fifo . write ( |w| unsafe { w. bits ( bits. to_be ( ) ) } ) ;
541
- i += 4 ;
588
+ }
589
+ // If the FIFO is half-empty, send some data.
590
+ else if sta. txfifohe ( ) . bit ( ) {
591
+ let offset = i % 512 ;
592
+
593
+ // SAFETY: We always write exactly 32 bytes into the FIFO from
594
+ // a 512-byte block. We move to the next block if needed before
595
+ // the next iteration.
596
+ //
597
+ // NOTE: This is needed since checked access takes to long and
598
+ // results in a FIFO underrun error on higher clock speeds.
599
+ unsafe {
600
+ for j in 0 ..8 {
601
+ let current_block = current_block. as_ptr ( ) as * const [ u8 ; 4 ] ;
602
+ let current_bytes = & * current_block. add ( offset / 4 + j) ;
603
+
604
+ let bits = u32:: from_be_bytes ( * current_bytes) . to_be ( ) ;
605
+ self . sdmmc . fifo . write ( |w| w. bits ( bits) ) ;
542
606
}
543
607
}
608
+
609
+ i += 4 * 8 ;
610
+
611
+ if i % 512 == 0 && i != byte_count {
612
+ current_block = & blocks[ i / 512 ] ;
613
+ }
544
614
}
545
615
}
546
616
617
+ clear_static_data_flags ( & self . sdmmc . icr ) ;
618
+
547
619
let timeout: u32 = 0xffff_ffff ;
548
620
for _ in 0 ..timeout {
549
621
if self . card_ready ( ) ? {
@@ -631,23 +703,22 @@ impl Sdmmc {
631
703
632
704
let timeout: u32 = 0xffff_ffff ;
633
705
for _ in 0 ..timeout {
634
- let sta = self . sdmmc . sta . read ( ) ;
635
-
636
- datapath_rx_err ! ( sta) ;
706
+ let sta = sta_rx ! ( self . sdmmc) ;
637
707
708
+ // If we received all data, wait for transfer to end.
638
709
if i == 0 {
639
710
if sta. dbckend ( ) . bit ( ) {
711
+ clear_static_data_flags ( & self . sdmmc . icr ) ;
712
+
640
713
return Ok ( SCR :: from ( scr) ) ;
641
714
}
642
- } else {
643
- if sta. rxdavl ( ) . bit_is_set ( ) {
644
- i -= 1 ;
715
+ } else if sta. rxdavl ( ) . bit_is_set ( ) {
716
+ i -= 1 ;
645
717
646
- let bits = u32:: from_be ( self . sdmmc . fifo . read ( ) . bits ( ) ) ;
647
- scr[ i] = bits. to_le ( ) ;
718
+ let bits = u32:: from_be ( self . sdmmc . fifo . read ( ) . bits ( ) ) ;
719
+ scr[ i] = bits. to_le ( ) ;
648
720
649
- continue ;
650
- }
721
+ continue ;
651
722
}
652
723
}
653
724
@@ -688,12 +759,13 @@ impl Sdmmc {
688
759
let mut i = sd_status. len ( ) ;
689
760
let timeout: u32 = 0xffff_ffff ;
690
761
for _ in 0 ..timeout {
691
- let sta = self . sdmmc . sta . read ( ) ;
692
-
693
- datapath_rx_err ! ( sta) ;
762
+ let sta = sta_rx ! ( self . sdmmc) ;
694
763
764
+ // If we received all data, wait for transfer to end.
695
765
if i == 0 {
696
766
if sta. dbckend ( ) . bit ( ) {
767
+ clear_static_data_flags ( & self . sdmmc . icr ) ;
768
+
697
769
return Ok ( SDStatus :: from ( sd_status) ) ;
698
770
}
699
771
} else if sta. rxfifohf ( ) . bit ( ) {
@@ -764,29 +836,33 @@ impl Sdmmc {
764
836
for _ in 0 ..timeout {
765
837
let sta = self . sdmmc . sta . read ( ) ;
766
838
839
+ // Command transfer still in progress.
767
840
if sta. cmdact ( ) . bit_is_set ( ) {
768
- // Command transfer still in progress.
769
841
continue ;
770
842
}
771
843
772
- if cmd. response_len ( ) == ResponseLen :: Zero {
773
- if sta. ctimeout ( ) . bit ( ) {
774
- return Err ( Error :: Timeout ) ;
775
- }
844
+ if sta. ctimeout ( ) . bit ( ) {
845
+ self . sdmmc . icr . modify ( |_, w| w. ctimeoutc ( ) . set_bit ( ) ) ;
776
846
847
+ return Err ( Error :: Timeout ) ;
848
+ }
849
+
850
+ if cmd. response_len ( ) == ResponseLen :: Zero {
777
851
if sta. cmdsent ( ) . bit ( ) {
852
+ self . sdmmc . icr . modify ( |_, w| w. cmdsentc ( ) . set_bit ( ) ) ;
853
+
778
854
return Ok ( ( ) ) ;
779
855
}
780
856
} else {
781
- if sta. ctimeout ( ) . bit ( ) {
782
- return Err ( Error :: Timeout ) ;
783
- }
784
-
785
857
if sta. ccrcfail ( ) . bit ( ) {
858
+ self . sdmmc . icr . modify ( |_, w| w. ccrcfailc ( ) . set_bit ( ) ) ;
859
+
786
860
return Err ( Error :: CommandCrc ) ;
787
861
}
788
862
789
863
if sta. cmdrend ( ) . bit ( ) {
864
+ self . sdmmc . icr . modify ( |_, w| w. cmdrendc ( ) . set_bit ( ) ) ;
865
+
790
866
return Ok ( ( ) ) ;
791
867
}
792
868
}
0 commit comments