DX3906 发表于 2023-12-14 11:32:19

FATFS写SD卡偶尔出现写失败和打开文件失败

本帖最后由 DX3906 于 2023-12-14 11:34 编辑

我在at32f435上用fatfs周期写16KB数据到sd卡,偶尔会出现写文件失败和打开文件失败,有时候重新上电几次之后又能长时间稳定写入,fatfs报错是FR_DISK_ERR,但是sdio驱动和fatfs都是直接用的官方的,换了几张卡都有一定几率出现
想问下各位大佬这可能是哪些方面的问题呢?



这个是我的测试代码,在freertos下跑的,只有这一个任务
void log_store_init(void)
{
FRESULT ret;

ret = f_mount(NULL, "1:", 1);
ret = f_mount(&fs, "1:", 1);
if(ret){
    DEBUG_PRINTF("fs mount err:%d.\r\n", ret);
    if(ret == FR_NO_FILESYSTEM){
      DEBUG_PRINTF("create fatfs..\r\n");
      BYTE *work= (BYTE *)pvPortMalloc(FF_MAX_SS);
      ret = f_mkfs("1:", 0, work, sizeof(work));
      if(ret){
      DEBUG_PRINTF("creates fatfs err:%d.\r\n", ret);
      return;
      }
      else{
      DEBUG_PRINTF("creates fatfs ok.\r\n");
      }
      ret = f_mount(NULL, "1:", 1);
      ret = f_mount(&fs, "1:", 1);
      if(ret){
      DEBUG_PRINTF("fs mount err:%d.\r\n", ret);
      return;
      }
      else{
      DEBUG_PRINTF("fs mount ok.\r\n");
      }
    }
    else{
      return;
    }
}
else{
    DEBUG_PRINTF("fs mount ok.\r\n");
}
}

char filename[] = "1:/test_data0000.bin";
void write_sd_test(void)
{
FIL file0;
FRESULT ret;
uint32_t len = 0;
static uint64_t total_len = 0;
static uint16_t file_count = 0;

if(file_count >= 940)
{
    file_count = 0;
}

char *filename = (char *)pvPortMalloc(22);
sprintf(filename, "1:/test_data%04d.bin", file_count);
if(filename == NULL)
{
    DEBUG_PRINTF("firename malloc failed.\r\n");
    return;
}

ret = f_open(&file0, filename, FA_WRITE | FA_CREATE_ALWAYS | FA_OPEN_ALWAYS);
if(ret){
    DEBUG_PRINTF("open file err:%d.\r\n", ret);
}
else{
    DEBUG_PRINTF("open file ok. %s\r\n", filename);
    uint8_t *buf = (uint8_t *)pvPortMalloc(16384);
    if(buf == NULL)
    {
      DEBUG_PRINTF("buf malloc failed.\r\n");
      if(filename != NULL)
      vPortFree(filename);
      f_close(&file0);
      return;
    }
    else
    {
      for(uint32_t i = 0; i < 500; i++)
      {
      for(uint16_t j = 0; j < 16384; j++)
      {
          buf = rand();
      }
      f_lseek(&file0, len);
      ret = f_write(&file0, (uint8_t*)buf, 16384, &bytes_written);
      if(ret){
          DEBUG_PRINTF("write file err:%d.\r\n", ret);
          f_close(&file0);
          ret = f_mount(NULL, "1:", 1);
          ret = f_mount(&fs, "1:", 1);
          if(ret){
            DEBUG_PRINTF("fs mount err:%d.\r\n", ret);
            return;
          }
          else{
            DEBUG_PRINTF("fs mount ok.\r\n");
          }
          break;
      }
      else{
          f_sync(&file0);
          len += bytes_written;
          total_len += bytes_written;
          DEBUG_PRINTF("write file ok, byte:%u, total:%lld\r\n", bytes_written, total_len);
      }
      vTaskDelay(1);
      }
      f_close(&file0);
      file_count++;
    }
    if(buf != NULL)
      vPortFree(buf);
}
if(filename != NULL)
    vPortFree(filename);
}

static void log_task(void* parameter)
{
portBASE_TYPE uxHighWaterMark;
__IO size_t xFreeStackSpace;

log_store_init();

while(1)
{
    xFreeStackSpace = xPortGetFreeHeapSize();
    DEBUG_PRINTF("free heap size: %d\r\n", xFreeStackSpace);
    write_sd_test();
    DEBUG_PRINTF("%s runing\r\n", LOG_TASK_NAME);

    vTaskDelay(1);
}
}

eric2013 发表于 2023-12-14 14:16:55

1、是不是开DMA了,要特别注意4字节对齐问题。
2、不建议重复的挂载卸载,推荐fopen后,后面仅调用fwrite和f_sync即可,fclose不需要调用,试试是否好点。

a2412462142 发表于 2023-12-14 15:54:19

频率太高了吧

DX3906 发表于 2023-12-14 16:11:06

用的是阻塞读写
开始以为是重新下程序后sd卡内部没复位,想着报错的时候重新挂载初始化一下试试,没有f_close的话文件不会异常吗?

无关风月 发表于 2023-12-15 08:37:51

之前遇到过类似的,原因是SD卡用了DMA, UI任务操作LTDC寄存器时 APB2总线会暂停,导致DMA出错

eric2013 发表于 2023-12-15 08:41:08

DX3906 发表于 2023-12-14 16:11
用的是阻塞读写
开始以为是重新下程序后sd卡内部没复位,想着报错的时候重新挂载初始化一下试试,没有f_cl ...

不会,f_sync也会将数据实际写入文件。

DX3906 发表于 2023-12-15 09:42:19

eric2013 发表于 2023-12-15 08:41
不会,f_sync也会将数据实际写入文件。

好的,我一会儿试试

DX3906 发表于 2023-12-15 09:43:05

无关风月 发表于 2023-12-15 08:37
之前遇到过类似的,原因是SD卡用了DMA, UI任务操作LTDC寄存器时 APB2总线会暂停,导致DMA出错

老哥用的是什么芯片,dma是sdio里的dma吗?

无关风月 发表于 2023-12-15 13:24:37

DX3906 发表于 2023-12-15 09:43
老哥用的是什么芯片,dma是sdio里的dma吗?

stm32f4
Care must be taken when accessing the LTDC registers since the APB2 bus is stalling when
the following operations are ongoing:
• Register write access and update for 6 xPCKL2 period + 5x LCD_CLK period (5x
HCLK period for register on AHB clock domain)
• Register read access for 7xPCKL2 period + 5x LCD_CLK period (5x HCLK period for
register on AHB clock domain).
For registers on PCLK2 clock domain, APB2 bus is stalling during the register write access
for 6 xPCKL2 period and 7xPCKL2 period for read access.

DX3906 发表于 2023-12-18 10:34:43

说下这几天的测试结论,不是驱动和f_close的问题,是卡的写入速度慢了,虽然用的是class10的卡,但是用工具测出来单次小数据量的写入速度非常慢
我分别测了杂牌的c10卡、闪迪的c10卡和移速的u3高速卡,在单次写入16KB这一项的速度差距很大
杂牌卡的16KB写入速度只有4MB/S多点,而我的测试代码是1ms循环写入16KB数据,卡跟不上所以报错了,把循环里的延时调大以后就可以稳定了

大家挑sd卡最好还是挑品牌卡比较好,然后能用高速卡尽量用高速卡


杂牌c10卡


闪迪c10卡


移速u3卡


页: [1]
查看完整版本: FATFS写SD卡偶尔出现写失败和打开文件失败