cancel
Showing results for 
Search instead for 
Did you mean: 

FileX SD card insertion/removal handling

Pajaka
Associate III

Hi,

how am I supposed so handle the reinsertion event while using the FileX with an SD card? All the examples I saw assume the SD card cannot be ejected while in use which is obviously unrealistic.

I tried to do it according to the official docs and when the ejection is detected I call the fx_media_abort and fx_stm32_sd_deinit. But during the reinsertion when I call the fx_media_open again I get the FX_IO_ERROR. At this point the driver should be in an uninitialized state and the fx_media_open should call the fx_stm32_sd_init function.

Can anyone relate to this problem? Here is the code example. The FX_STM32_SD_INIT macro is defined.

 

if(card_insertion_flag.Get(0x03, EventGroup::Access::bit_or_clear, TX_WAIT_FOREVER,flag))
{
	if(flag & 0x01)
	{
		//Card inserted
		uint8_t cntr = 0;
		do
		{
			status = fx_media_open(&this->sdio_disk, (char* )"SD card", fx_stm32_sd_driver, 0, (VOID *) media_memory, this->media_memory_size);
			HAL_Delay(50);
		}
		while(cntr++ < 50 && status != FX_SUCCESS);

		if(status != FX_SUCCESS)
		{
			Error_Handler();
		}

		status = fx_file_open(...
	}
	else
	{
		//Here I tried all this and its combinations
		//status = fx_media_abort(&this->sdio_disk);
		//status = fx_media_close(&this->sdio_disk);
		//fx_stm32_sd_deinit(0);
	}
}

 

 

9 REPLIES 9
Haithem Rahmani
ST Employee

hi @Pajaka 

Not clear on which STM32 you are working but below application code that support uSD hot plug.

https://github.com/STMicroelectronics/STM32CubeU5/blob/main/Projects/STM32U575I-EV/Applications/FileX/Fx_uSD_File_Edit/FileX/App/app_filex.c

regards
Haithem.

Pajaka
Associate III

Thanks for your reply, but I cannot see how the code provided handles a hot plug at all. What happens when the SD card is ejected and the code is already beyond the line 232 (app_filex.c) as shown below?

if (media_status == MEDIA_CLOSED)

 Is it assumed that the code gets executed so fast that you cannot physically manage to insert and eject the card during one execution of the while loop? What if I need to stream a long (mins to 1h) experimental data to a file? Should I mount and unmount the media between each writes as shown in the example? That would create a huge overhead. I could create a large buffer that gets written to the file every X seconds, but then what if the card is ejected before the write operation? I would lose my data.

The problem is that I cannot unmount the media when streaming the data. When the card is ejected, I call the fx_media_abort and wait for the card insertion. After that when I call the fx_media_open again, I get the FX_IO_ERROR. This is definitely a FW error as it runs correctly again when I restart the MCU. 

I will try to unmount the media when not used and then get along with the fact that during the experiment I cannot handle the ejection gracefully and simply restart the MCU.

>what if the card is ejected before the write operation? I would lose my data.

Right - or the card might be damaged, if pulled out, while writing.

Just try it on your PC: write a big file to the card, pull it out, while writing - then insert it, and see, what the PC telling you about the card now...

There is no simple solution to the problem...

but in FileX there is :

AScha3_0-1713250263072.png

Maybe this could help - at least, not destroy the whole file system, when power off or pull out at wrong moment.

Try it and tell ... (I am about to test it next time also.)

If you feel a post has answered your question, please click "Accept as Solution".

This is all known to me, that the filesystem may end up being corrupted, but the problem is when the card is reinserted and I try to mount it - fx_media_open returns IO_ERROR. Corrupted filesystem would result in a different error code.

When I reset the MCU after the reinsertion, everything works good, so it must be a FW problem. Some initialization code that runs at the startup and is not called during the repeated card insertion.

I forgot to mention that I use a L562RE MCU and a 4bit SDMMC. Code is written in C++ and everything works as expected except the reinsertion handling.

Ok, so ... did you try :

  	fresult = HAL_SD_DeInit(&hsd1);   	//error...MX_FATFS_Init
...
//with new inserted card ->
    	fresult = HAL_SD_InitCard(&hsd1);   	// insert -> then new init
If you feel a post has answered your question, please click "Accept as Solution".

I haven't tried this yet. I will test it in a few hours and come back. I tried the following in a similar fashion

fx_stm32_sd_deinit(0);

 with no luck. 

Pajaka
Associate III

It was indeed a FW error. I performed a debug session and pin pointed an exact point of failure which turned out to be the cube generated macro

FX_STM32_SD_PRE_INIT(media_ptr);
//which expands to this:
do { \
    if ((tx_semaphore_create(&sd_rx_semaphore, "sd rx transfer semaphore", 0) != TX_SUCCESS) || \
    (tx_semaphore_create(&sd_tx_semaphore, "sd tx transfer semaphore", 0) != TX_SUCCESS))  \
    { \
	_media_ptr->fx_media_driver_status = FX_IO_ERROR; \
    } \
} while(0)

Inside this macro the rx and tx semaphores for the SDMMC are created and the return value is expected to be TX_SUCCESS which is not because the semaphores already exist from the previous initialization. I use the Debug configuration right now so the variables (and structures) get null initialized. That's why it worked when I restarted the MCU during reinsertion.

So what I did is deleting those semaphores in the uSD ejection handling so that these semaphores can get created during the repeated insertion. My code looks like this now.

//after includes
extern TX_SEMAPHORE sd_tx_semaphore;
extern TX_SEMAPHORE sd_rx_semaphore;
//actual Task
while (this->should_run)
{
	if (card_insertion_flag.Get(0x03, EventGroup::Access::bit_or_clear, TX_WAIT_FOREVER, flag))
	{
		if (flag & 0x01)
		{
			//Card inserted
			memset((void*)&this->sdio_disk,0,sizeof(FX_MEDIA));
			MX_SDMMC1_SD_Init();
			status = fx_media_open(&this->sdio_disk, (char* )"SD card", fx_stm32_sd_driver, 0, (VOID *) this->media_memory, this->media_memory_size);
			if (status != FX_SUCCESS)
			{
				Error_Handler();
			}

			LoadSettings();
			LoadAccCal();
			LoadMagCal();
			msg.event_type = static_cast<uint32_t>(FilesystemEventID::settings_parsed);
			app.Notify(this, msg);
		}
		else
		{
			status = fx_media_abort(&this->sdio_disk);
			HAL_SD_DeInit(&hsd1);
			tx_semaphore_delete(&sd_rx_semaphore);
			tx_semaphore_delete(&sd_tx_semaphore);
		}
	}
}

 Please add a function that deletes these semaphores during the SD deinit. Or you can test whether these semaphores were already initialized during the SD init - check the semaphore ID for instance, it gets initialized to a non zero value after creation.

HI @Pajaka 

thanks indeed for the sharing. the issue will be reported and fixed as soon as possible.

Could you please provide details on which STM32 are you working?

regards
Haithem.

Hi @Pajaka,

After checking further, you'll be able to solve your issue. when calling fx_media_abort(), the macro FX_STM32_SD_POST_ABORT(_media_ptr) https://github.com/STMicroelectronics/STM32CubeU5/blob/f0f063146b444e37ef6b1b3d2f219df728a12407/Projects/STM32U575I-EV/Applications/FileX/Fx_uSD_File_Edit/FileX/Target/fx_stm32_sd_driver.h#L107 will be called.

you can simply define it as done for FX_STM32_SD_POST_DEINIT(_media_ptr)

 

#define FX_STM32_SD_POST_DEINIT(_media_ptr)             do { \
                                                          tx_semaphore_delete(&sd_rx_semaphore); \
                                                          tx_semaphore_delete(&sd_tx_semaphore); \
                                                        } while(0)

/* USER CODE END FX_STM32_SD_POST_DEINIT_TX */

/* Macro called after the abort request */
/* USER CODE BEGIN FX_STM32_SD_POST_ABORT */

#define FX_STM32_SD_POST_ABORT(_media_ptr) FX_STM32_SD_POST_DEINIT(_media_ptr)

Could you try and let us know?

 

regards
Haithem.