@@ -211,18 +211,14 @@ mimxrt_sdcard_obj_t mimxrt_sdcard_objs[] =
211211// ---
212212// Local function declarations
213213// ---
214- static status_t sdcard_transfer_blocking (USDHC_Type * base ,
215- usdhc_handle_t * handle ,
216- usdhc_transfer_t * transfer ,
217- uint32_t timeout_ms );
214+ static status_t sdcard_transfer_blocking (USDHC_Type * base , usdhc_transfer_t * transfer , uint32_t timeout_ms );
218215static void sdcard_decode_csd (mimxrt_sdcard_obj_t * sdcard , csd_t * csd );
219216static bool sdcard_reset (mimxrt_sdcard_obj_t * card );
220217static inline void sdcard_init_pin (const machine_pin_obj_t * pin , uint8_t af_idx , uint32_t config_value );
221218
222219// SD Card interrupt callbacks
223220void sdcard_card_inserted_callback (USDHC_Type * base , void * userData );
224221void sdcard_card_removed_callback (USDHC_Type * base , void * userData );
225- void sdcard_transfer_complete_callback (USDHC_Type * base , usdhc_handle_t * handle , status_t status , void * userData );
226222void sdcard_dummy_callback (USDHC_Type * base , void * userData );
227223
228224// SD Card commands
@@ -237,6 +233,8 @@ static bool sdcard_cmd_send_csd(mimxrt_sdcard_obj_t *card, csd_t *csd);
237233static bool sdcard_cmd_select_card (mimxrt_sdcard_obj_t * sdcard );
238234static bool sdcard_cmd_set_blocklen (mimxrt_sdcard_obj_t * sdcard );
239235static bool sdcard_cmd_set_bus_width (mimxrt_sdcard_obj_t * sdcard , usdhc_data_bus_width_t bus_width );
236+ static bool sdcard_cmd_send_status (mimxrt_sdcard_obj_t * card );
237+ static bool sdcard_wait_ready (mimxrt_sdcard_obj_t * card , uint32_t timeout_ms );
240238
241239void sdcard_card_inserted_callback (USDHC_Type * base , void * userData ) {
242240 #if defined MICROPY_USDHC1 && USDHC1_AVAIL
@@ -291,38 +289,43 @@ static void sdcard_error_recovery(USDHC_Type *base) {
291289 }
292290}
293291
294- static status_t sdcard_transfer_blocking (USDHC_Type * base , usdhc_handle_t * handle , usdhc_transfer_t * transfer , uint32_t timeout_ms ) {
295- status_t status ;
292+ // Wait for card to be ready by polling Data0 line.
293+ // Data0 low indicates card is busy.
294+ static bool sdcard_wait_data0_ready (USDHC_Type * base , uint32_t timeout_ms ) {
295+ for (uint32_t i = 0 ; i < timeout_ms ; i ++ ) {
296+ if ((USDHC_GetPresentStatusFlags (base ) & (uint32_t )kUSDHC_Data0LineLevelFlag ) != 0 ) {
297+ return true;
298+ }
299+ mp_hal_delay_ms (1 );
300+ }
301+ return false;
302+ }
296303
297- usdhc_adma_config_t dma_config ;
304+ // Wrapper around SDK's USDHC_TransferBlocking.
305+ // Waits for card to be ready before starting transfer.
306+ static status_t sdcard_transfer_blocking (USDHC_Type * base , usdhc_transfer_t * transfer , uint32_t timeout_ms ) {
307+ usdhc_adma_config_t dma_config = {
308+ .dmaMode = kUSDHC_DmaModeAdma2 ,
309+ #if !(defined (FSL_FEATURE_USDHC_HAS_NO_RW_BURST_LEN ) && FSL_FEATURE_USDHC_HAS_NO_RW_BURST_LEN )
310+ .burstLen = kUSDHC_EnBurstLenForINCR ,
311+ #endif
312+ .admaTable = sdcard_adma_descriptor_table ,
313+ .admaTableWords = DMA_DESCRIPTOR_BUFFER_SIZE ,
314+ };
298315
299- (void )memset (& dma_config , 0 , sizeof (usdhc_adma_config_t ));
300- dma_config .dmaMode = kUSDHC_DmaModeAdma2 ;
316+ // For command-only transfers (no data), skip the busy wait
317+ bool has_data = (transfer -> data != NULL ) &&
318+ ((transfer -> data -> txData != NULL ) || (transfer -> data -> rxData != NULL ));
301319
302- # if !(defined( FSL_FEATURE_USDHC_HAS_NO_RW_BURST_LEN ) && FSL_FEATURE_USDHC_HAS_NO_RW_BURST_LEN )
303- dma_config . burstLen = kUSDHC_EnBurstLenForINCR ;
304- #endif
320+ if ( has_data && ! sdcard_wait_data0_ready ( base , timeout_ms )) {
321+ return kStatus_Timeout ;
322+ }
305323
306- dma_config .admaTable = sdcard_adma_descriptor_table ;
307- dma_config .admaTableWords = DMA_DESCRIPTOR_BUFFER_SIZE ;
308-
309- // Wait while the card is busy before a transfer
310- status = kStatus_Timeout ;
311- for (int i = 0 ; i < timeout_ms * 100 ; i ++ ) {
312- // Wait until Data0 is low any more. Low indicates "Busy".
313- if (((transfer -> data -> txData == NULL ) && (transfer -> data -> rxData == NULL )) ||
314- (USDHC_GetPresentStatusFlags (base ) & (uint32_t )kUSDHC_Data0LineLevelFlag ) != 0 ) {
315- // Not busy anymore or no TX-Data
316- status = USDHC_TransferBlocking (base , & dma_config , transfer );
317- if (status != kStatus_Success ) {
318- sdcard_error_recovery (base );
319- }
320- break ;
321- }
322- ticks_delay_us64 (10 );
324+ status_t status = USDHC_TransferBlocking (base , & dma_config , transfer );
325+ if (status != kStatus_Success ) {
326+ sdcard_error_recovery (base );
323327 }
324328 return status ;
325-
326329}
327330
328331static void sdcard_decode_csd (mimxrt_sdcard_obj_t * card , csd_t * csd ) {
@@ -381,7 +384,7 @@ static bool sdcard_cmd_go_idle_state(mimxrt_sdcard_obj_t *card) {
381384 .command = & command ,
382385 };
383386
384- status = sdcard_transfer_blocking (card -> usdhc_inst , & card -> handle , & transfer , 250 );
387+ status = sdcard_transfer_blocking (card -> usdhc_inst , & transfer , 250 );
385388
386389 if (status == kStatus_Success ) {
387390 return true;
@@ -403,7 +406,7 @@ static bool sdcard_cmd_oper_cond(mimxrt_sdcard_obj_t *card) {
403406 .command = & command ,
404407 };
405408
406- status = sdcard_transfer_blocking (card -> usdhc_inst , & card -> handle , & transfer , 250 );
409+ status = sdcard_transfer_blocking (card -> usdhc_inst , & transfer , 250 );
407410
408411 if (status == kStatus_Success ) {
409412 card -> oper_cond = command .response [0 ];
@@ -426,7 +429,7 @@ static bool sdcard_cmd_app_cmd(mimxrt_sdcard_obj_t *card) {
426429 .command = & command ,
427430 };
428431
429- status = sdcard_transfer_blocking (card -> usdhc_inst , & card -> handle , & transfer , 250 );
432+ status = sdcard_transfer_blocking (card -> usdhc_inst , & transfer , 250 );
430433
431434 if (status == kStatus_Success ) {
432435 card -> status = command .response [0 ];
@@ -454,7 +457,7 @@ static bool sdcard_cmd_sd_app_op_cond(mimxrt_sdcard_obj_t *card, uint32_t argume
454457 .command = & command ,
455458 };
456459
457- status = sdcard_transfer_blocking (card -> usdhc_inst , & card -> handle , & transfer , 250 );
460+ status = sdcard_transfer_blocking (card -> usdhc_inst , & transfer , 250 );
458461
459462 if (status == kStatus_Success ) {
460463 card -> oper_cond = command .response [0 ];
@@ -477,7 +480,7 @@ static bool sdcard_cmd_all_send_cid(mimxrt_sdcard_obj_t *card, cid_t *cid) {
477480 .command = & command ,
478481 };
479482
480- status = sdcard_transfer_blocking (card -> usdhc_inst , & card -> handle , & transfer , 250 );
483+ status = sdcard_transfer_blocking (card -> usdhc_inst , & transfer , 250 );
481484
482485 if (status == kStatus_Success ) {
483486 cid -> mdt = (uint16_t )((command .response [0 ] & 0xFFF00U ) >> 8U );
@@ -510,7 +513,7 @@ static bool sdcard_cmd_send_cid(mimxrt_sdcard_obj_t *card, cid_t *cid) {
510513 .command = & command ,
511514 };
512515
513- status = sdcard_transfer_blocking (card -> usdhc_inst , & card -> handle , & transfer , 250 );
516+ status = sdcard_transfer_blocking (card -> usdhc_inst , & transfer , 250 );
514517
515518 if (status == kStatus_Success ) {
516519 cid -> mdt = (uint16_t )((command .response [0 ] & 0xFFF00U ) >> 8U );
@@ -543,7 +546,7 @@ static bool sdcard_cmd_set_rel_add(mimxrt_sdcard_obj_t *card) {
543546 .command = & command ,
544547 };
545548
546- status = sdcard_transfer_blocking (card -> usdhc_inst , & card -> handle , & transfer , 250 );
549+ status = sdcard_transfer_blocking (card -> usdhc_inst , & transfer , 250 );
547550
548551 if (status == kStatus_Success ) {
549552 card -> rca = 0xFFFFFFFF & (command .response [0 ] >> 16 );
@@ -566,7 +569,7 @@ static bool sdcard_cmd_send_csd(mimxrt_sdcard_obj_t *card, csd_t *csd) {
566569 .command = & command ,
567570 };
568571
569- status = sdcard_transfer_blocking (card -> usdhc_inst , & card -> handle , & transfer , 250 );
572+ status = sdcard_transfer_blocking (card -> usdhc_inst , & transfer , 250 );
570573
571574 if (status == kStatus_Success ) {
572575 csd -> data [0 ] = command .response [0 ];
@@ -593,7 +596,7 @@ static bool sdcard_cmd_select_card(mimxrt_sdcard_obj_t *card) {
593596 .command = & command ,
594597 };
595598
596- status = sdcard_transfer_blocking (card -> usdhc_inst , & card -> handle , & transfer , 250 );
599+ status = sdcard_transfer_blocking (card -> usdhc_inst , & transfer , 250 );
597600
598601 if (status == kStatus_Success ) {
599602 card -> status = command .response [0 ];
@@ -617,7 +620,7 @@ static bool sdcard_cmd_set_blocklen(mimxrt_sdcard_obj_t *card) {
617620 .command = & command ,
618621 };
619622
620- status = sdcard_transfer_blocking (card -> usdhc_inst , & card -> handle , & transfer , 250 );
623+ status = sdcard_transfer_blocking (card -> usdhc_inst , & transfer , 250 );
621624
622625 if (status == kStatus_Success ) {
623626 card -> status = command .response [0 ];
@@ -652,7 +655,31 @@ static bool sdcard_cmd_set_bus_width(mimxrt_sdcard_obj_t *card, usdhc_data_bus_w
652655 .command = & command ,
653656 };
654657
655- status = sdcard_transfer_blocking (card -> usdhc_inst , & card -> handle , & transfer , 250 );
658+ status = sdcard_transfer_blocking (card -> usdhc_inst , & transfer , 250 );
659+
660+ if (status == kStatus_Success ) {
661+ card -> status = command .response [0 ];
662+ return true;
663+ } else {
664+ return false;
665+ }
666+ }
667+
668+ static bool sdcard_cmd_send_status (mimxrt_sdcard_obj_t * card ) {
669+ status_t status ;
670+ usdhc_command_t command = {
671+ .index = SDCARD_CMD_SEND_STATUS ,
672+ .argument = (card -> rca << 16 ),
673+ .type = kCARD_CommandTypeNormal ,
674+ .responseType = kCARD_ResponseTypeR1 ,
675+ .responseErrorFlags = SDMMC_R1_ALL_ERROR_FLAG ,
676+ };
677+ usdhc_transfer_t transfer = {
678+ .data = NULL ,
679+ .command = & command ,
680+ };
681+
682+ status = sdcard_transfer_blocking (card -> usdhc_inst , & transfer , 250 );
656683
657684 if (status == kStatus_Success ) {
658685 card -> status = command .response [0 ];
@@ -662,6 +689,30 @@ static bool sdcard_cmd_set_bus_width(mimxrt_sdcard_obj_t *card, usdhc_data_bus_w
662689 }
663690}
664691
692+ static bool sdcard_wait_ready (mimxrt_sdcard_obj_t * card , uint32_t timeout_ms ) {
693+ uint32_t start = mp_hal_ticks_ms ();
694+
695+ while ((mp_hal_ticks_ms () - start ) < timeout_ms ) {
696+ if (!sdcard_cmd_send_status (card )) {
697+ return false;
698+ }
699+
700+ // Check if card is ready for data (bit 8) and in transfer state (bits 9-12 == 4)
701+ uint32_t card_state = SDMMC_R1_CURRENT_STATE (card -> status );
702+ bool ready_for_data = (card -> status & SDMMC_MASK (SDCARD_STATUS_READY_FOR_DATA_SHIFT )) != 0 ;
703+
704+ if (ready_for_data && (card_state == SDCARD_STATE_TRANSFER )) {
705+ return true;
706+ }
707+
708+ // Allow other MicroPython tasks to run while polling
709+ MICROPY_EVENT_POLL_HOOK ;
710+ mp_hal_delay_ms (1 ); // Wait 1ms between polls
711+ }
712+
713+ return false; // Timeout
714+ }
715+
665716static bool sdcard_reset (mimxrt_sdcard_obj_t * card ) {
666717 card -> block_len = SDCARD_DEFAULT_BLOCK_SIZE ;
667718 card -> rca = 0UL ;
@@ -708,6 +759,19 @@ void sdcard_init(mimxrt_sdcard_obj_t *card, uint32_t base_clk) {
708759
709760 #endif // MIMXRT117x_SERIES
710761
762+ // ERR050396 workaround: Disable cacheable AXI transactions for USDHC
763+ // This is critical when GC heap is in cacheable OCRAM (SDRAM disabled).
764+ // The GPR28/GPR13 ARCACHE/AWCACHE bits control USDHC's AXI cache attributes
765+ // at the hardware level, ensuring DMA accesses bypass the L1 D-cache.
766+ #ifdef MIMXRT117x_SERIES
767+ IOMUXC_GPR -> GPR28 &= ~(IOMUXC_GPR_GPR28_ARCACHE_USDHC_MASK | IOMUXC_GPR_GPR28_AWCACHE_USDHC_MASK );
768+ #else
769+ #if defined(IOMUXC_GPR_GPR13_ARCACHE_USDHC_MASK )
770+ IOMUXC_GPR -> GPR13 &= ~(IOMUXC_GPR_GPR13_ARCACHE_USDHC_MASK | IOMUXC_GPR_GPR13_AWCACHE_USDHC_MASK );
771+ #endif
772+ #endif
773+ __DSB (); // Ensure GPR setting completes before USDHC initialization
774+
711775 // Initialize USDHC
712776 const usdhc_config_t config = {
713777 .endianMode = kUSDHC_EndianModeLittle ,
@@ -725,6 +789,7 @@ void sdcard_init(mimxrt_sdcard_obj_t *card, uint32_t base_clk) {
725789 .CardRemoved = sdcard_card_removed_callback ,
726790 .SdioInterrupt = sdcard_dummy_callback ,
727791 .BlockGap = sdcard_dummy_callback ,
792+ .TransferComplete = NULL , // Not used - we use blocking transfers
728793 .ReTuning = sdcard_dummy_callback ,
729794 };
730795
@@ -779,6 +844,10 @@ bool sdcard_read(mimxrt_sdcard_obj_t *card, uint8_t *buffer, uint32_t block_num,
779844 return false;
780845 }
781846
847+ // Ensure cache is flushed and invalidated so when DMA updates RAM
848+ // from the peripheral, the CPU reads the new data.
849+ MP_HAL_CLEANINVALIDATE_DCACHE (buffer , block_count * card -> block_len );
850+
782851 usdhc_data_t data = {
783852 .enableAutoCommand12 = true,
784853 .enableAutoCommand23 = false,
@@ -803,10 +872,13 @@ bool sdcard_read(mimxrt_sdcard_obj_t *card, uint8_t *buffer, uint32_t block_num,
803872 .command = & command ,
804873 };
805874
806- status_t status = sdcard_transfer_blocking (card -> usdhc_inst , & card -> handle , & transfer , 500 );
875+ status_t status = sdcard_transfer_blocking (card -> usdhc_inst , & transfer , 500 );
807876
808877 if (status == kStatus_Success ) {
809878 card -> status = command .response [0 ];
879+ // Invalidate cache again after DMA completes to discard any speculative
880+ // cache line fills that may have occurred during the transfer.
881+ MP_HAL_CLEANINVALIDATE_DCACHE (buffer , block_count * card -> block_len );
810882 return true;
811883 } else {
812884 return false;
@@ -818,6 +890,9 @@ bool sdcard_write(mimxrt_sdcard_obj_t *card, uint8_t *buffer, uint32_t block_num
818890 return false;
819891 }
820892
893+ // Ensure cache is flushed to RAM so DMA can read the correct data.
894+ MP_HAL_CLEAN_DCACHE (buffer , block_count * card -> block_len );
895+
821896 usdhc_data_t data = {
822897 .enableAutoCommand12 = true,
823898 .enableAutoCommand23 = false,
@@ -842,14 +917,21 @@ bool sdcard_write(mimxrt_sdcard_obj_t *card, uint8_t *buffer, uint32_t block_num
842917 .command = & command ,
843918 };
844919
845- status_t status = sdcard_transfer_blocking (card -> usdhc_inst , & card -> handle , & transfer , 3000 );
920+ status_t status = sdcard_transfer_blocking (card -> usdhc_inst , & transfer , 3000 );
846921
847- if (status == kStatus_Success ) {
848- card -> status = command .response [0 ];
849- return true;
850- } else {
922+ if (status != kStatus_Success ) {
851923 return false;
852924 }
925+
926+ card -> status = command .response [0 ];
927+
928+ // Wait for the card to complete programming the data to flash.
929+ // The transfer above only ensures the data has been sent to the card's buffer.
930+ if (!sdcard_wait_ready (card , 5000 )) {
931+ return false;
932+ }
933+
934+ return true;
853935}
854936
855937bool sdcard_set_active (mimxrt_sdcard_obj_t * card ) {
@@ -873,7 +955,7 @@ bool sdcard_probe_bus_voltage(mimxrt_sdcard_obj_t *card) {
873955 /* Get operating voltage*/
874956 valid_voltage = (((card -> oper_cond >> 31U ) == 1U ) ? true : false);
875957 count ++ ;
876- ticks_delay_us64 ( 1000 );
958+ mp_hal_delay_ms ( 1 );
877959 }
878960
879961 if (count >= SDCARD_MAX_VOLT_TRIAL ) {
0 commit comments