Skip to main content
matt-crc
Senior III
Feb 26, 2025 5:52 PM UTC
Solved

FileX - does any one know how to close_media without the system hanging? - BUG-

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

 

This topic has been closed for replies.
matt-crc
matt-crcBest answer
Senior III
Feb 26, 2025 8:22 PM UTC

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???

 

4 replies

matt-crc
matt-crcAuthor
Senior III
Feb 26, 2025 6:25 PM UTC

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???

 

Andrew Neil
Super User
Feb 26, 2025 6:34 PM UTC

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

A complex system that works is invariably found to have evolved from a simple system that worked.A complex system designed from scratch never works and cannot be patched up to make it work.
matt-crc
matt-crcAuthor
Senior III
Feb 26, 2025 6:55 PM UTC

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

matt-crc
matt-crcAuthorBest answer
Senior III
Feb 26, 2025 8:22 PM UTC

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???