【问题标题】:FatFS f_write not workingFatFS f_write 不工作
【发布时间】:2016-07-14 11:02:05
【问题描述】:

我在 ZedBoard 上,我正在尝试在 SD 卡上写字。 我正在开发嵌入式系统,我没有任何操作系统,我正在运行裸机。

我可以从 SD 卡中正常读取,它们没问题。

但是当我尝试阅读时,我有一些奇怪的行为:

  • f_write 返回 FR_OK
  • bw(写入的字节数)变量是正确的
  • 文件已创建(从 PC 读取 SD 卡时可以看到)

但是当我读取文件时,它是空的。

这是我的代码:

void WriteFile(char const* fileName, char* buffer, size_t size)
{
    FIL file;
    FATFS fs;
    UINT bw;
    FRESULT fr;

    f_mount(&fs, "", 0);
    f_open(&file, fileName, FA_WRITE | FA_CREATE_ALWAYS);
    fr = f_write(&file, buffer, size, &bw);
    if (size != bw || fr != FR_OK)
        PRINT(("Error in writing !\n"));
    f_close(&file);
    f_mount(NULL, "", 0);
}

我这样称呼这个方法:

 WriteFile("Hello.txt", "Hello World !", 13);

知道我做错了什么吗?

【问题讨论】:

  • FatFs 不提供低级设备 I/O - 您必须由第三方(例如板卡或芯片供应商)自己提供,所以这可能是一个问题,尽管它很难看出文件是如何创建的。此外,FatFs 可以配置为“只读”文件系统 - 但再次创建了文件,因此情况似乎并非如此。无论如何,问题似乎不在于您提供的代码级别,而在于库配置级别的驱动程序,因此就目前而言,您不太可能得到“这是您的问题”的答案。跨度>
  • 我和你有同样的问题 Aymen 但是当我尝试在从我的电脑创建的文本文件上使用 f_write 时,我可以覆盖该文件的内容。但我无法让它与我用 f_open 创建的空文件一起工作。
  • @Frostbite :当您说覆盖时,您的意思是在其中添加您自己的数据,而不仅仅是一个空白文件?有趣,我还没有尝试过……但是在阅读了您的消息后,我记得我应该更新要回答的问题,因为我找到了一个可行的解决方案。
  • 我很确定 f_sync() 可以完成这项工作,如下文stackoverflow.com/a/37568289/558639中所述

标签: c embedded sd-card bare-metal fatfs


【解决方案1】:

这是来自 Nordic NRF52 devkit,但我的症状与您的完全一样,因为我的每一个 f_write 调用都发生在中断或北欧事件通知中,我猜这是不允许的。

我的解决方法:我创建了一个 WriteFromInterrupt() 函数,以便从中断和回调中调用,将写入放入队列中,然后从我的 main() 循环中进行另一个调用,最终通过调用 @987654323 清空队列@和f_sync

【讨论】:

    【解决方案2】:

    我知道这是一篇旧帖子,但如果有人遇到这个问题,我可以通过添加 f_sync(&myFile); 来解决它

                char myData[] = "Hello from STM32";
                if(f_write(&myFile, myData, strlen(myData), &myBytes) == FR_OK)
                {
                    if(f_sync(&myFile) == FR_OK){
                        HAL_GPIO_WritePin(LED3_GPIO_Port, LED3_Pin, GPIO_PIN_RESET);
                        HAL_Delay(500);
                        HAL_GPIO_WritePin(LED3_GPIO_Port, LED3_Pin, GPIO_PIN_SET);
                    }
                }
    

    【讨论】:

      【解决方案3】:

      我在尝试使用赛灵思 SoC(如 ZedBoard)在 SD 上写入时遇到了同样的问题。我无法将数据写入 SD 卡,即使:

      • 所有函数都成功。

      • 我能够删除和创建文件(所以我不在只读状态)。

      • 当我读回我写在卡片上的内容时(使用 f_lseek 回到 0 和 f_read)我读到了正确的数据。

      每次我在重新启动后读取文件时,它都是空的。

      我尝试了以前的解决方案,但都没有奏效。 史蒂夫的回答让我走上了正轨。

      修复:我需要按 256 字节的块写入数据才能将我的数据实际写入 SD。 256 字节是我 SD 卡中页面的大小,所以它很重要有道理。

      如果写入不是 256 的倍数,则不会写入所有数据。 例如:

      使用 f_write 写入的字节数 -> 实际写入文件的字节数

      512 -> 512

      480 -> 256

      255 -> 0

      256 -> 256

      希望它可以帮助某人:)

      【讨论】:

      • 这并不能真正回答问题。如果您有其他问题,可以点击 提问。一旦你有足够的reputation,你也可以add a bounty 来引起对这个问题的更多关注。 - From Review
      • @madlymad 我认为 OP 在写问题时打错了:...但是当我尝试 read 时,我有...通过代码,他想写入文件并且不能这样做。所以我认为我的回答很好地回应了:知道我做错了什么吗?至于为什么“Hello World!”大小为 13 字节的文件不会写入文件。我编辑的答案更清楚了吗?
      【解决方案4】:

      fatfs 创建文件时遇到了同样的问题,但不会向其中写入任何数据。 fatfs 函数没有产生错误,所以我被困了 2 天,然后我发现如果我在 i/o 层中发送 512 字节块之后放置一个断点,在我的代码中它的函数 send_datablock(buff, 0xFE )) 它会起作用的。

      我发现在写入数据块后,SD 需要时间才能将这个块实际写入内部闪存,请参阅

      http://elm-chan.org/docs/mmc/mmc_e.html

      在单块写入繁忙时段 DO 行下,您必须等待此时段结束才能发送任何其他命令(即另一个 CMD24 单块写入),否则 SD 会丢弃最后一个 CMD24,因此您会丢失刚刚的数据已发送。

      我像这样在 send_datablock 函数的末尾放了一个等待循环

          /* if not accepted, return with error */
          if((data & 0x1F) != 0x05)
          {
              return 0;
          }
          else
          {
              /* wait for SD to finish writing data */
              tmr = 5000;
              do
              {
                  data = get_response(SDEXIChannel);
                  if(data != 0x00)
                  {
                      break;
                  }
                  udelay(100);
                  tmr--;
              } while(0 != tmr);
      
              /* did we time out ? if so return with error */
              if(tmr == 0)
              {
                  return 0;
              }
      

      这似乎解决了我的问题,我现在可以写入 SD 卡上的文件,无论如何希望可以节省两天的调试时间!

      【讨论】:

        【解决方案5】:

        您可以只刷新缓冲区 (f_sync):

                FRESULT result;
                FATFS fs;
                FIL file;
        
                const char string[] = "Hallo world\0";
                uint16_t written = 0;
                FILINFO fno;
        
                /* Open or create a log file and ready to append */
                printf("mount:%d",f_mount(&fs, "", 1));
                printf("open: %d", f_open(&file, "log.txt", FA_WRITE  | FA_OPEN_ALWAYS ));
                printf("stat: %d", f_stat("log3.txt", &fno));
                printf("write: %d wr: %d", f_write(&file, string, 11, &written), written);
                printf("flush: %d", f_sync(&file));
                printf("close: %d", f_close(&file)); /* close performs sync before close */
        

        【讨论】:

          【解决方案6】:

          我发现一个小技巧可以解决我的问题:
          基本上它不会写入 SD 卡,因为缓冲区尚未满(在 XILINX 的低级 API 中)。
          所以我所做的很简单:我只写一次数据。虽然文件的大小不等于或大于写入数据的大小,但我写了 0(按 32 块)
          另外,另一件重要的事情:你写的数据必须是 32 字节对齐的!\ 这是我的(工作)代码:

          size_t SizeOfFile(char const *path)
          {
              FILE *fp = fopen(path, "r");
              fseek(fp, 0, SEEK_END);
              size_t fsize = (size_t) ftell(fp);
              fclose(fp);
              return fsize;
          }
          
          void WriteFile( char const* fileName, char* buffer, size_t size )
          {
              size_t allignement = ( size + 32 - 1 ) & ~ ( 32 - 1 );  // We must allign by 32
              char* Buffer_logger = pleb_malloc( allignement );
              pleb_memset( Buffer_logger, 0, allignement );
              pleb_memcpy( Buffer_logger, buffer, size );
          
              unsigned int BytesWr;
              size_t accum = 0;
              result = f_open( &file, fileName, FA_CREATE_ALWAYS | FA_WRITE | FA_READ );
              if ( result != 0 )
              {
                  return;
              }
          
              sprintf( Buffer_logger, "%s", buffer );
          
              while ( SizeOfFile( fileName ) == 0 )
              {
                  // Open log for writing
                  result = f_open( &file, fileName, FA_WRITE );
                  if ( result != 0 )
                  {
                      return;
                  }
          
                  // Point to the EOF
                  result = f_lseek( &file, accum );
                  if ( result != 0 )
                  {
                      return;
                  }
          
                  // Write to log
                  result = f_write( &file, (const void*) Buffer_logger, size, &BytesWr );
                  if ( result != 0 )
                  {
                      return;
                  }
          
                  accum += accum + strlen( Buffer_logger );
          
                  //Close file.
                  result = f_close( &file );
                  if ( result != 0 )
                  {
                      return;
                  }
          
                  pleb_memset( Buffer_logger, 0, allignement );
          
                  size = 32;
                  pleb_memset( Buffer_logger, 0, size );
              }
              pleb_free( Buffer_logger );
              PRINT( ("Data written to log Successfully\r\n") );
          }
          

          【讨论】:

          • 我遇到的一个问题是附加到文件中的数据不是 32 位对齐的。每当写入跨越块大小边界时,它要么添加 2 个字节,要么从我的数据中删除 2 个字节。让数据 32 位对齐解决了这个问题。这个答案帮助我找到了问题!谢谢!
          猜你喜欢
          • 1970-01-01
          • 2020-06-04
          • 2023-04-08
          • 2020-06-05
          • 2020-11-18
          • 2018-05-16
          • 2018-12-31
          • 2016-10-20
          • 2019-06-03
          相关资源
          最近更新 更多