2025-02-26 9:52 AM - edited 2025-02-26 10:16 AM
Hello,
I'm using AzRTOS with FileX. Currently, I can detect when the SD card is plugged in, then I initialize the hardware, and call fx_media_open(). The filesystem works as expected.
I can also unmount the media with fx_media_close(), and the user can pull out the card. That works.
The problem is when the user pulls the SDcard when the media is open. I detect the card removal and try to call fx_media_close(), but that just hangs the system when calling fx_media_close(). Is there a special procedure needed to recover when the media is removed?
thanks
Matthew
Solved! Go to Solution.
2025-02-26 12:22 PM
Ok, it seems that re-initializing the SD card hardware using MX_SDMMC1_SD_Init(void) does everything except clear the old error flags in the driver. So when I try to reset the driver it gives a SDMMC_ERROR_CMD_RSP_TIMEOUT error from the last time the card was pulled out and then jumps into the error_handler().
To get around this, I call HAL_SD_DeInit(&hsd1) which clears the errors in the driver when the card is removed. then call fx_media_abort() to clean up all the AzRtos stuff.
Now the only problem is how to fix the extra long timeout delay without CubeMX wiping out the fix???
2025-02-26 10:25 AM
There is a coding bug in stm32h7xx_II_sdmmc.c. The code:
/**
* @brief Checks for error conditions for R1 response.
* @PAram hsd: SD handle
* @PAram SD_CMD: The sent command index
* @retval SD Card error state
*/
uint32_t SDMMC_GetCmdResp1(SDMMC_TypeDef *SDMMCx, uint8_t SD_CMD, uint32_t Timeout)
{
uint32_t response_r1;
uint32_t sta_reg;
/* 8 is the number of required instructions cycles for the below loop statement.
The Timeout is expressed in ms */
uint32_t count = Timeout * (SystemCoreClock / 8U / 1000U);
do
{
if (count-- == 0U)
{
return SDMMC_ERROR_TIMEOUT;
}
sta_reg = SDMMCx->STA;
} while (((sta_reg & (SDMMC_FLAG_CCRCFAIL | SDMMC_FLAG_CMDREND | SDMMC_FLAG_CTIMEOUT |
SDMMC_FLAG_BUSYD0END)) == 0U) || ((sta_reg & SDMMC_FLAG_CMDACT) != 0U));
if (__SDMMC_GET_FLAG(SDMMCx, SDMMC_FLAG_CTIMEOUT))
{
__SDMMC_CLEAR_FLAG(SDMMCx, SDMMC_FLAG_CTIMEOUT);
return SDMMC_ERROR_CMD_RSP_TIMEOUT;
}
else if (__SDMMC_GET_FLAG(SDMMCx, SDMMC_FLAG_CCRCFAIL))
{
__SDMMC_CLEAR_FLAG(SDMMCx, SDMMC_FLAG_CCRCFAIL);
return SDMMC_ERROR_CMD_CRC_FAIL;
}
else
{
/* Nothing to do */
}
/* Clear all the static flags */
__SDMMC_CLEAR_FLAG(SDMMCx, SDMMC_STATIC_CMD_FLAGS);
/* Check response received is of desired command */
if (SDMMC_GetCommandResponse(SDMMCx) != SD_CMD)
{
return SDMMC_ERROR_CMD_CRC_FAIL;
}
/* We have received response, retrieve it for analysis */
response_r1 = SDMMC_GetResponse(SDMMCx, SDMMC_RESP1);
if ((response_r1 & SDMMC_OCR_ERRORBITS) == SDMMC_ALLZERO)
{
return SDMMC_ERROR_NONE;
}
else if ((response_r1 & SDMMC_OCR_ADDR_OUT_OF_RANGE) == SDMMC_OCR_ADDR_OUT_OF_RANGE)
{
return SDMMC_ERROR_ADDR_OUT_OF_RANGE;
}
else if ((response_r1 & SDMMC_OCR_ADDR_MISALIGNED) == SDMMC_OCR_ADDR_MISALIGNED)
{
return SDMMC_ERROR_ADDR_MISALIGNED;
}
else if ((response_r1 & SDMMC_OCR_BLOCK_LEN_ERR) == SDMMC_OCR_BLOCK_LEN_ERR)
{
return SDMMC_ERROR_BLOCK_LEN_ERR;
}
else if ((response_r1 & SDMMC_OCR_ERASE_SEQ_ERR) == SDMMC_OCR_ERASE_SEQ_ERR)
{
return SDMMC_ERROR_ERASE_SEQ_ERR;
}
else if ((response_r1 & SDMMC_OCR_BAD_ERASE_PARAM) == SDMMC_OCR_BAD_ERASE_PARAM)
{
return SDMMC_ERROR_BAD_ERASE_PARAM;
}
else if ((response_r1 & SDMMC_OCR_WRITE_PROT_VIOLATION) == SDMMC_OCR_WRITE_PROT_VIOLATION)
{
return SDMMC_ERROR_WRITE_PROT_VIOLATION;
}
else if ((response_r1 & SDMMC_OCR_LOCK_UNLOCK_FAILED) == SDMMC_OCR_LOCK_UNLOCK_FAILED)
{
return SDMMC_ERROR_LOCK_UNLOCK_FAILED;
}
else if ((response_r1 & SDMMC_OCR_COM_CRC_FAILED) == SDMMC_OCR_COM_CRC_FAILED)
{
return SDMMC_ERROR_COM_CRC_FAILED;
}
else if ((response_r1 & SDMMC_OCR_ILLEGAL_CMD) == SDMMC_OCR_ILLEGAL_CMD)
{
return SDMMC_ERROR_ILLEGAL_CMD;
}
else if ((response_r1 & SDMMC_OCR_CARD_ECC_FAILED) == SDMMC_OCR_CARD_ECC_FAILED)
{
return SDMMC_ERROR_CARD_ECC_FAILED;
}
else if ((response_r1 & SDMMC_OCR_CC_ERROR) == SDMMC_OCR_CC_ERROR)
{
return SDMMC_ERROR_CC_ERR;
}
else if ((response_r1 & SDMMC_OCR_STREAM_READ_UNDERRUN) == SDMMC_OCR_STREAM_READ_UNDERRUN)
{
return SDMMC_ERROR_STREAM_READ_UNDERRUN;
}
else if ((response_r1 & SDMMC_OCR_STREAM_WRITE_OVERRUN) == SDMMC_OCR_STREAM_WRITE_OVERRUN)
{
return SDMMC_ERROR_STREAM_WRITE_OVERRUN;
}
else if ((response_r1 & SDMMC_OCR_CID_CSD_OVERWRITE) == SDMMC_OCR_CID_CSD_OVERWRITE)
{
return SDMMC_ERROR_CID_CSD_OVERWRITE;
}
else if ((response_r1 & SDMMC_OCR_WP_ERASE_SKIP) == SDMMC_OCR_WP_ERASE_SKIP)
{
return SDMMC_ERROR_WP_ERASE_SKIP;
}
else if ((response_r1 & SDMMC_OCR_CARD_ECC_DISABLED) == SDMMC_OCR_CARD_ECC_DISABLED)
{
return SDMMC_ERROR_CARD_ECC_DISABLED;
}
else if ((response_r1 & SDMMC_OCR_ERASE_RESET) == SDMMC_OCR_ERASE_RESET)
{
return SDMMC_ERROR_ERASE_RESET;
}
else if ((response_r1 & SDMMC_OCR_AKE_SEQ_ERROR) == SDMMC_OCR_AKE_SEQ_ERROR)
{
return SDMMC_ERROR_AKE_SEQ_ERR;
}
else
{
return SDMMC_ERROR_GENERAL_UNKNOWN_ERR;
}
}
the way the timeout is calculated is completely wrong...
count = Timeout * (SystemCoreClock / 8U / 1000U)
Timeout = 5000
SystemCoreClock = 480,000,000
That's one very long timeout....
Now the question is how to fix this without CubeMX wiping out the fix???
2025-02-26 10:34 AM
Have you tried using the debugger to find where, exactly, it "hangs" ?
Looking at the source code, it seems that it will write to the media:
/**************************************************************************/ /* */ /* FUNCTION RELEASE */ /* */ /* _fx_media_close PORTABLE C */ /* 6.1 */ /* AUTHOR */ /* */ /* William E. Lamie, Microsoft Corporation */ /* */ /* DESCRIPTION */ /* */ /* This function examines the list of open files for this media and */ /* closes each file. If a file has been written to, the file's */ /* directory information is also written out to the media. After */ /* the files have been closed, the internal logical sector is */ /* flushed and a flush command is sent to the attached driver. */ /* Finally, this media control block is removed from the list of */ /* opened media control blocks and is marked as closed. */ /* */
https://github.com/eclipse-threadx/filex/blob/master/common/src/fx_media_close.c
so maybe not surprising that it fails when the media has been removed?
maybe fx_media_abort() is what you need?
https://github.com/eclipse-threadx/filex/blob/master/common/src/fx_media_abort.c
2025-02-26 10:55 AM
Hi Andrew,
Well, the fx_media_abort() cleans up all the AzRtos stuff, so that's half the battle. I waited for the extra long timeout to expire, but it ended up in the error handler... So I will check that next.
Thanks for the fx_media_abort() tip
2025-02-26 12:22 PM
Ok, it seems that re-initializing the SD card hardware using MX_SDMMC1_SD_Init(void) does everything except clear the old error flags in the driver. So when I try to reset the driver it gives a SDMMC_ERROR_CMD_RSP_TIMEOUT error from the last time the card was pulled out and then jumps into the error_handler().
To get around this, I call HAL_SD_DeInit(&hsd1) which clears the errors in the driver when the card is removed. then call fx_media_abort() to clean up all the AzRtos stuff.
Now the only problem is how to fix the extra long timeout delay without CubeMX wiping out the fix???