Skip to content

Commit afa00b8

Browse files
committed
mimxrt/sdcard: Implement proper timeout in sdcard_transfer_blocking.
The previous implementation used USDHC_TransferBlocking which has infinite loops in USDHC_WaitCommandDone and USDHC_TransferDataBlocking with no timeout mechanism. Even though the wrapper had a timeout loop, once inside the SDK function there was no way to abort. This change replaces USDHC_TransferBlocking with USDHC_TransferNonBlocking combined with polling of interrupt status flags and proper timeout handling. The function now: - Checks for card busy state with timeout before starting transfer - Uses non-blocking SDK transfer to avoid infinite loops - Polls interrupt flags with timeout for completion - Properly handles both command-only and data transfers - Calls error recovery on timeout or error conditions This ensures that SD card operations will not hang indefinitely when hardware doesn't respond as expected. Signed-off-by: Andrew Leech <[email protected]>
1 parent 832e10a commit afa00b8

File tree

1 file changed

+41
-7
lines changed

1 file changed

+41
-7
lines changed

ports/mimxrt/sdcard.c

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -309,20 +309,54 @@ static status_t sdcard_transfer_blocking(USDHC_Type *base, usdhc_handle_t *handl
309309
// Wait while the card is busy before a transfer
310310
status = kStatus_Timeout;
311311
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)) ||
312+
// Wait until Data0 is not low any more. Low indicates "Busy".
313+
if (((transfer->data == NULL) || ((transfer->data->txData == NULL) && (transfer->data->rxData == NULL))) ||
314314
(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) {
315+
// Not busy anymore or no data transfer
316+
status = kStatus_Success;
317+
break;
318+
}
319+
ticks_delay_us64(10);
320+
}
321+
322+
if (status != kStatus_Success) {
323+
return kStatus_Timeout;
324+
}
325+
326+
// Use non-blocking transfer with polling to implement timeout
327+
status = USDHC_TransferNonBlocking(base, handle, &dma_config, transfer);
328+
if (status != kStatus_Success) {
329+
return status;
330+
}
331+
332+
// Poll for transfer completion with timeout
333+
uint32_t interruptStatus = 0;
334+
uint32_t waitFlags = (transfer->data != NULL) ?
335+
(kUSDHC_CommandFlag | kUSDHC_DataDMAFlag) : kUSDHC_CommandFlag;
336+
337+
for (uint32_t i = 0; i < timeout_ms * 100; i++) {
338+
interruptStatus = USDHC_GetInterruptStatusFlags(base);
339+
340+
// Check for completion or error
341+
if ((interruptStatus & waitFlags) != 0) {
342+
// Transfer completed (either success or error)
343+
// Call the IRQ handler to complete the transfer and invoke callbacks
344+
USDHC_TransferHandleIRQ(base, handle);
345+
346+
// Check if transfer was successful
347+
if ((interruptStatus & kUSDHC_ErrorFlag) != 0) {
318348
sdcard_error_recovery(base);
349+
return kStatus_Fail;
319350
}
320-
break;
351+
return kStatus_Success;
321352
}
353+
322354
ticks_delay_us64(10);
323355
}
324-
return status;
325356

357+
// Timeout occurred
358+
sdcard_error_recovery(base);
359+
return kStatus_Timeout;
326360
}
327361

328362
static void sdcard_decode_csd(mimxrt_sdcard_obj_t *card, csd_t *csd) {

0 commit comments

Comments
 (0)