Skip to main content
AFahr.1
Associate III
May 26, 2021
Question

STM32L496 - SD Card SDIO write speeds (FreeRTOS, FATFS and USB), how to get "fast" (> 100kbytes/sec) throughput?

  • May 26, 2021
  • 28 replies
  • 6523 views

Hi all,

I need to stream data into an SD card, at about 25KBytes/sec max. Currently I'm stuck at 11kBytes/sec, but the SDIO data transfer works, kind of. I'm using an STM32L496 board, FATFS and FreeRTOS, as well as USB.

The USB part works actually really well. Every time I plug in I'm able to download at ~400kBytes/sec and copy to the SD card at say ~200Kbytes/sec. I don't need more than that.

When the USB is unplugged, I copy data from different sensors onto a StreamBuffer (FreeRTOS), and once I get 512 bytes, I copy them over to the SD card using f_write(...) through an additional buffer. I have several issues with this:

  • If I set the clock on the SD card to be less than 2, it fails very often, seconds after it starts
hsd1.Init.ClockDiv = 2;

  • If I set the bus to be 4 bits wide with the clock 2 or more, f_write returns 1 (DISK ERROR) after about 6 seconds.
  • If I set the bus to be 1 bit wide with clock 2 or more, f_write returns 1 after a few minutes, 3-5.
  • My SD write function for FatFS is below:
DRESULT SD_write(BYTE lun, const BYTE *buff, DWORD sector, UINT count)
{
	DRESULT res = RES_ERROR;
	uint32_t timeout;
	uint32_t time;
	HAL_StatusTypeDef retval;
	HAL_SD_CardStateTypedef cardState;
	bool sd_wait = true;
 
 
	timeout = count * 500; //Timeout in MS per block
	sd_wait = true;
 
	if(true == sd_card_ready)
	{
	 	retval = HAL_SD_WriteBlocks(&hsd1, (uint8_t *)buff, sector, count, timeout);
	 	cardState = HAL_SD_GetCardState(&hsd1);
 
	 	if (HAL_OK == retval)
		{
			time = HAL_GetTick();
			while(true == sd_wait)
			{
				cardState = HAL_SD_GetCardState(&hsd1);
 
				if(HAL_SD_CARD_TRANSFER == cardState)
				{
					sd_wait = false;
					res = RES_OK;
				}
 
				if((HAL_GetTick() - time) > timeout)
				{
					sd_wait = false;
					HAL_SD_Abort(&hsd1);
				}
			}
		}
	}
 
 return res;
}

The above code is the same for the USB transfer.

I'm at a loss a bit, I thought writing a block (512bytes) of data would increase the data throughput to the SD card, and I have a lot of contiguous data blocks, all the time. Data is constantly read in at about 11 KBytes/sec.

I read somewhere else that doing a pre-check on the data alignment before the "HAL_SD_WriteBlocks" call would help. I might need to try that out.

If anyone can point me in the right direction with examples, links, explanations, etc, I'd really appreciate it. I am able to buffer up to ~500ms of data if necessary... maybe more, how can I detect or recover from a slow (250ms or so) write cycle?

Cheers,

Alberto

    This topic has been closed for replies.

    28 replies

    Jtron.11
    Senior
    June 21, 2021

    Alberto,

    Please disregard the question. I got it work, but I still don't understand. I am using the power USB hub to the PC. If I switch the power on for the USB port that plugged the USB MSC in, the PC will have the issue to recognize the USB MSC; however, when I switched of the power on the port, the USB MSC is recognize and working.

    AFahr.1
    AFahr.1Author
    Associate III
    June 22, 2021

    Sorry, in your sentence above it's not clear which is on or off? You mention 'on' twice. Do you power your board with the USB port?

    Maybe it has to do with the fact that you are using VBUS sense and I'm not. I'm only using the pin as GPIO to sense the input. If you are using VBUS (maybe the dev kit uses VBUS), then that might be the issue.

    Jtron.11
    Senior
    June 22, 2021

    Alberto,

    So sorry to bother you. Can you please give me some pointers?

    Now I got the USB MSC and SDMMC is partially working. At the time I plug in the USB to PC, the PC is recognize and register the drive, and asked me to format the drive. When I performed the format, it got error (I think the time out) and said Window couldn't perform the format.

    I believe it is related to the SDMMCCLK clock divide factor. I have my USB and SDMMC1 configure at 48MHz, the USB MSC set up is 12Mbits/s and my SDMMCCLK divide factor is 4 (to match 12MHz with USB).

    When I tried to use 5, the PC won't even recognize the USB MSC since there was a query for descriptor error.

    Questions:

    1. What tis the SDMMCCLK you set for your system? What is the speed you set for your USB CDC MSC and what is the setting for your SDMMCx?
    2. How do you prevent the PC asking you to format the uSD everytime you plug in the USB cable?