SD Card sector read delay
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2020-04-18 3:22 AM
I am making an stm32 driven music player that reads from a text file containing binary PCM data. (not the right way to do it i know but it gets the job done) I did a test by doing an f_read 1 byte at a time at the sample frequency (44100) to see if the performance is adequate. It works fine most of the time but whenever i read the 512th byte (going into a new sector) the read time jumps from sub-milliseconds to roughly 2 ms which introduces a noticable delay in the audio (chrunching the number results in a 2 ms delay nearly every 11 ms). This is the case whether i read 1, 512 or 1024 bytes and occurs every time i read across sectors. I wanted to know if this is a feature of the sd specification or is it something Im doing wrong. I tracked the cause of the delay to HAL_SD_ReadBlocks function (as expected) if it is of any help. Is there a method of mitigating the 2 ms delay altogether or should I just reduce its occurence by reading as much data as i can and hope that it doesn't get heard? I am using this board fyi: https://github.com/mcauser/BLACK_F407ZG
My main.c (stripped to make it fit):
FATFS myFATFS;
FIL myFILE;
UINT testByte;
uint8_t buffer[512];
const double sampling_freq = 44100;
uint32_t sampling_period_us = 0;
uint64_t system_clock = 0;
uint64_t micros_start = 0;
double m_total = 0;
char myPATH[] = "1khz441K.TXT\0";
uint64_t microseconds(void){
return system_clock*1000 + ((SysTick->LOAD - SysTick->VAL)/168);
}
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_SDIO_SD_Init();
MX_USART1_UART_Init();
MX_FATFS_Init();
MX_DAC_Init();
MX_RTC_Init();
/* USER CODE BEGIN 2 */
SysTick_Config(SystemCoreClock/1000);//set systick up
HAL_DAC_Start(&hdac, DAC_CHANNEL_1);
HAL_DAC_Start(&hdac, DAC_CHANNEL_2);
sampling_period_us = (uint32_t)((1/sampling_freq)*1000000);
if(f_mount(&myFATFS, SDPath, 1)==FR_OK){
f_open(&myFILE, myPATH, FA_READ | FA_OPEN_ALWAYS);
}
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
// char myPATH[] = "WRITE1.TXT\0";
// f_open(&myFILE, myPATH, FA_WRITE | FA_CREATE_ALWAYS);
// if(f_open(&myFILE, myPATH, FA_WRITE | FA_CREATE_ALWAYS)==FR_OK){
// micros_start = microseconds();
// write_result = f_write(&myFILE, buffer, sizeof(buffer), &testByte);
// m_total = ((double)(microseconds()-micros_start))/1000;
// f_close(&myFILE);
// HAL_Delay(1000);
// }
micros_start = microseconds();
f_read(&myFILE, buffer, 1, &testByte);
HAL_DAC_SetValue(&hdac, DAC_CHANNEL_2, DAC_ALIGN_8B_R, buffer[0]);
while((microseconds() - micros_start) < sampling_period_us);
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
Last note: My main objective is to use an sd card as a black box for a drone project i have been working on and this is more of a getting used to the sd peripheral project for me. The drone's loop runs at 500hz so a delay of 2ms is absolutely unacceptable for my taste (Thats why i don't see uart as a propper solution). I tried out the write performance in some of the commented out code up above. Unfortunately same results. Thanks in advance to anyone who is willing to help.
- Labels:
-
FatFS
-
SDIO-SDMMC
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2020-04-18 4:20 AM
This is not how to approach the problem.
Reading 1 byte for f_read() has a lot of overhead.
Reading one sector is also the slowest method possible due to the inherent command-response behavior of a slow MCU in the card itself.
​
What you need to do in the loop is read much larger blocks, that constitute half a buffer, using a TIM and DMA to feed the DAC at the appropriate pacing. You fill in inactive half of the buffer based on the HT and TC interrupts from the DMA.
​
You can likely read 16 sectors in a similar length of time.
​
You need to move beyond the simple linear programming model so you can do useful work concurrently as different tasks wait for slower​ hardware to deliver data.
Up vote any posts that you find helpful, it shows what's working..
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2020-04-18 4:39 AM
Thank you for your input. Ok so realistically the only way to get rid of that occasional 2 ms delay would be to use a dma for sdio. If i use the blocking mode of the sdio peripheral i need any and all f_write functions to take less than 100 us. Can writing larger chunks of data provide such a time saving? If not I suppose dma for sd would solve the issue?
