AnsweredAssumed Answered

SDIO FatFS Problems without Delays Between Block Writes

Question asked by John Craven on Aug 11, 2017
Latest reply on Aug 15, 2017 by John Craven

I have been playing with 4bit SDIO and FatFS.

I was able to get good write speeds (8-9 MB/s) but i would often get errors and the SD card lock up. No read/write.

Project is CUBE 4.21.0 generated for the STM32-407G-Disco1 board.

After a lot of testing with different hardware for the SD card holder/circuit, i have found this is code based issue.

 

App is simple. 

  • If user button is held on startup, then format the card
  • If not, write N files, of a given file size, using a given buffer/block size.
  • Calculate the average write rate.

 

Works great, but only if i add a short delay, HAL_Delay(1) after each f_write, see line 149.

If the delay is not present, the SD locks up randomly a few writes to a few files.

 

With 1ms delay and it works great all day, can write any number of files, any file size, any buffer/chunk size until the SD card is full. Filled many 32GB cards. Data on card has been validated.

 

Using 32kB writes, i get 8.5MB/s. I can live with that.

 

I had tested multiple SD cards and SD holder/circuits. It don't think its hardware.

I understand SD card latency issues.

Any latency, and waiting should done/handled in the drivers, and not require my arbitrary waiting between writes. 

 

Why does my test writing always fail, without the 1ms delay after each block write?

 

Full project is attached. Only file changed for Cube generation is main.c

/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "stm32f4xx_hal.h"
#include "fatfs.h"
#include "sdio.h"
#include "tim.h"
#include "gpio.h"

/* USER CODE BEGIN Includes */

#include "string.h"

/* USER CODE END Includes */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/

SD_HandleTypeDef hsd;
HAL_SD_CardInfoTypeDef SDCardInfo;

FATFS fatfs; /* FAT File System */
FRESULT fresult; /* FAT File Result */

#define TESTLENGTH     1
#define FILESIZE     (0x100000 * 1024) //1MB x A
#define CHUNKSIZE     (0x000400 * 32) //1KB x B
#define chunks          (FILESIZE/CHUNKSIZE)

char bigbuffer[CHUNKSIZE];

int numfileswritten = 0;
uint32_t totaltime;
uint32_t filetime;
uint32_t chunktime;
uint32_t avgperiod;
float rate;

uint32_t timeout;

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);

/* USER CODE BEGIN PFP */
/* Private function prototypes -----------------------------------------------*/

/* USER CODE END PFP */

/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

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_FATFS_Init();
     MX_TIM2_Init();

     /* USER CODE BEGIN 2 */

     //fill buffer with some data for external checks
     for (int i = 0; i < CHUNKSIZE; i++) {
          bigbuffer[i] = 0x21 + i % 0x50;
     }

     //1us count up 32bit timer for rate calcs
     HAL_TIM_Base_Start(&htim2);

     if (BSP_SD_Init() == MSD_OK) {
          //mount sd
          fresult = f_mount(&fatfs, (TCHAR const*) SD_Path, 0);

          //if user button is pressed then reformat the sd
          if (HAL_GPIO_ReadPin(BUT_GPIO_Port, BUT_Pin) == GPIO_PIN_SET) {
               HAL_GPIO_WritePin(LD6_GPIO_Port, LD6_Pin, GPIO_PIN_SET);
               fresult = f_mkfs((TCHAR const*) SD_Path, 0, 0);
               HAL_GPIO_WritePin(LD6_GPIO_Port, LD6_Pin, GPIO_PIN_RESET);

               HAL_Delay(1000);
          } else {
               //if mount and/or format are good, start writing files
               if (fresult == FR_OK) {
                    int fn = 0;
                    while (fn < TESTLENGTH) {
                         char fnbuffer[32];
                         snprintf(fnbuffer, sizeof(char) * 32, "data%i.txt", fn);

                         FIL myfile;
                         fresult = f_open(&myfile, fnbuffer,
                         FA_CREATE_ALWAYS | FA_WRITE);

                         if (fresult == FR_OK) {
                              long count = 0;
                              UINT bw;

                              //turn of green LED on while writing
                              HAL_GPIO_WritePin(LD4_GPIO_Port, LD4_Pin, GPIO_PIN_SET);

                              //write chunks
                              while (count++ < chunks) {
                                   //Tried checking SD status before writing (without delay), but doesn't fix problem
                                   //========================================================================
                                   //timeout = SD_DATATIMEOUT;
                                   //while(BSP_SD_GetCardState()!= MSD_OK)
                                   //{
                                   //  if (timeout-- == 0)
                                   //  {
                                   //     return 0;
                                   //  }
                                   //}
                                   //========================================================================

                                   //reset timer
                                   __HAL_TIM_SET_COUNTER(&htim2, 0);

                                   //write the a chunk
                                   fresult = f_write(&myfile, bigbuffer, CHUNKSIZE, &bw);

                                   //add timer count to total write time
                                   totaltime += __HAL_TIM_GET_COUNTER(&htim2);

                                   //Works with this delay, but is unreliable without this delay
                                   //========================================================================
                                   HAL_Delay(1);
                                   //========================================================================
                              }

                              fresult = f_close(&myfile);

                              //turn of green LED between files
                              HAL_GPIO_WritePin(LD4_GPIO_Port, LD4_Pin,
                                        GPIO_PIN_RESET);

                              //update rate calcs
                              numfileswritten++;
                              avgperiod = totaltime / numfileswritten;
                              rate = (float) FILESIZE / (float) avgperiod;

                              fn++;
                              //short pause just to see when file write ends on green led
                              HAL_Delay(100);
                         } else {
                              //red LED for mount/format error
                              HAL_GPIO_WritePin(LD5_GPIO_Port, LD5_Pin, GPIO_PIN_SET);
                              break;
                         }
                    }
               }
          }
     }

     //orange LED
     HAL_GPIO_WritePin(LD3_GPIO_Port, LD3_Pin, GPIO_PIN_SET);

     /* USER CODE END 2 */

     /* Infinite loop */
     /* USER CODE BEGIN WHILE */
     while (1) {
          /* USER CODE END WHILE */

          /* USER CODE BEGIN 3 */
          HAL_Delay(1);
     }
     /* USER CODE END 3 */

}

Attachments

Outcomes