你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【STM32F769I-DISC1】移植基于FreeRTOS的FATFS

[复制链接]
lugl 发布时间:2025-3-16 11:32

【前言】

我的上一篇文章【STM32F769】实现SD卡的FATFS - ST中文论坛活动 ST意法半导体中文论坛

在这基础之上,配置好RTC+FreeRTOS,然后添加一个综合测试的文件,最后实现综合的测试效果。

【感谢】

这半个月,我一直在折腾基于SD卡的文件系统,常常搞到半夜,总是有一些这样那样的问题,从BSP工程中移植等等,都没有实现好。最好我找出了前面没有好好阅读的书《STM32Cube高效开发教程》这本书的高级篇理,详细的记录如何使用FatFS的使用,我用心的读完以后,再进行配置,就没有遇到什么问题了。

image.png

【移植过程】

1、在stm32cubeMX配置中添加RTC,打开RTC与日历。再打开freertos。freertos使用V2版本。修改默认栈为1024。最后生成工程。

确保工程如下:

image.png

然后还需要把sd的中断级别调为6:

image.png

最后在工程中添加file_opera.c/h(文件见回复1)

在freertos.c添加测试代码:

void StartDefaultTask(void *argument)
{
  /* USER CODE BEGIN StartDefaultTask */
  FRESULT res;
  res = f_mount(&SDFatFS, SDPath, 1);
  if (res != FR_OK) {
    printf("SD Card Mount Failed\r\n");
  }
  else
  {
    printf("SD Card Mounted\r\n");
  }
  fatTest_GetDiskInfo();
  fatTest_GetFileInfo("0:/test.txt");
  fatTest_WriteTXTFile("FREERTOS_TEST.TXT",2025,3,16,10,22,33);
  fatTest_ReadTXTFile("FREERTOS_TEST.TXT");
  fatTest_ScanDir("0:/");
  fatTest_GetFileInfo("0:/FREERTOS_TEST.TXT");

  /* Infinite loop */
  for(;;)
  {
    osDelay(1);
  }
  /* USER CODE END StartDefaultTask */
}

下载到开发板后,效果如下:

image.png

【总结】

到此为止,我在使用STM32F769上的SD卡的FATFS学习差不多有10天。经过各种学习,最后总结了一点,就是卡在sdmmc2的实始化上面,需要先初始1bit,初始化好后,再转化为4bit。还有就是如果开启了D-Cache,在DMA传输前,需要清一下缓存,要不写入的为乱码。

收藏 评论1 发布时间:2025-3-16 11:32

举报

1个回答
lugl 回答时间:2025-3-16 11:33:31

file_opera.c:

#include "file_opera.h"
#include "main.h"

#include "rtc.h"
#include "fatfs.h"
#include <stdio.h>
#include "ff.h"
/*   三个功能函数 */
// 用RTC格式的日期和时间更新文件时间戳
void fat_SetTimeStamp(TCHAR *fileName, const RTC_DateTypeDef *sDate, const RTC_TimeTypeDef *sTime)
{
  FILINFO fno;
  WORD date = (2000+sDate->Year - 1980) << 9;
  WORD month = (sDate->Month)<<5;
  fno.fdate = date | month | sDate->Date;
  WORD time = (sTime->Hours) << 11;
  time = time | (sTime->Minutes) << 5;
  time = time | (sTime->Seconds) >> 1; 
  fno.ftime = time;
  f_utime(fileName, &fno);
}
// 将文件的时间戳读出并转换为RTC格式的日期和时间
void fat_GetTimeStamp(const FILINFO *fno, RTC_DateTypeDef *sDate, RTC_TimeTypeDef *sTime)
{
    WORD date = fno->fdate;
    WORD time = fno->ftime;
    sDate->Year = (date-2000) + 1980;
    sDate->Month = date & 0x0F;
    sDate->Date = date & 0x1F;

    sTime->Seconds = (time & 0x1F) << 1;
    sTime->Minutes = (time >> 5) & 0x3F;
    sTime->Hours = (time >> 11) & 0x1F;
}
// 从RTC获取时间作FatFs文件时间戳
DWORD fat_GetFatTimeFromRTC(void)
{
    RTC_DateTypeDef sDate;
    RTC_TimeTypeDef sTime;
    if(HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BIN) != HAL_OK)
    {
        return 0;
    }
    else
    {
      HAL_RTC_GetDate(&hrtc, &sDate, RTC_FORMAT_BIN);  
      WORD date = (2000+sDate.Year - 1980) << 9;
      date = date | (sDate.Month << 5) | sDate.Date;
      WORD time = (sTime.Hours << 11) | (sTime.Minutes << 5) | (sTime.Seconds >> 1);
      return (DWORD)(date << 16) | time;
    }
}

/* FatFs 文件读写测试函数 */
void fatTest_WriteBinFile(TCHAR *filename, uint32_t pointCount, uint32_t sampFreq);
void fatTest_ReadBinFile(TCHAR *filename);
void fatTest_WriteTXTFile(TCHAR *filename, uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, uint8_t second)
{
    FIL file;
    FRESULT res;
    printf("*** WRITE TXT FILE ***\r\n");
    res = f_open(&file, filename, FA_CREATE_ALWAYS | FA_WRITE);
    if(res!= FR_OK)
    {
        printf("f_open error\r\n");
        return;
    }
    else
    {
        TCHAR str[] = "Line1: Hello, FatFs!\n";  // 字符串必须有换行符\n
        f_puts(str, &file);
        TCHAR str2[] = "Line2: UPC lugl.\n";
        f_puts(str2, &file);
        f_printf(&file, "Line3: %d-%d-%d %d:%d:%d\n", year, month, day, hour, minute, second);
        f_close(&file);
        printf("WRITE TXT FILE END\r\n");
    }
}

void fatTest_ReadTXTFile(TCHAR *filename)
{
    FIL file;
    FRESULT res;
    printf("*** READ TXT FILE ***\r\n"); 
    res = f_open(&file, filename, FA_OPEN_EXISTING | FA_READ);
    if(res != FR_OK)
    {
        printf("f_open error\r\n");
    }
    else if(res == FR_NO_FILE)
    {
        printf("file not exist\r\n"); 
    }
    else if(res == FR_OK)
    {
        TCHAR str[100];
        while(!f_eof(&file))
        {
            f_gets(str, sizeof(str), &file);
            printf("%s", str);
        }
    }
    else
    {
        printf("READ TXT FILE error%d\r\n",res);
    }
    f_close(&file);
    printf("READ TXT FILE END\r\n");
}

void fatTest_GetDiskInfo(void)
{
   FATFS *fs; 
   FRESULT res;
   DWORD fre_clust;
   res = f_getfree("0:", &fre_clust, &fs);
   if(res != FR_OK)
   {
      printf("f_getfree error\r\n");
      return;
   }
   printf("*** FAT disk info ***\r\n");
   DWORD tot_sect = (fs->n_fatent - 2) * fs->csize; //总扇区数
   DWORD free_sect = fre_clust * fs->csize;
#if _MAX_SS == _MIN_SS // 对于U盘和SD卡 SD卡的MIN_SS和MAX_SS相等,即扇区大小为512字节
      DWORD freespace = (free_sect>>11); //剩余空间,单位MB 用于SD卡和U盘
      DWORD totalspace = (tot_sect>>11); //总空间,单位MB 用于SD卡和U盘
      printf("Total space: %ld MB\r\n", totalspace);
      printf("Free space: %ld MB\r\n", freespace);
#else //Flash 存储器 小容量
      DWORD freespace = (free_sect*fs->ssize)>>10; //剩余空间,单位KB
      DWORD totalspace = (tot_sect*fs->ssize)>>10; //总空间,单位KB
      printf("Total space: %d KB\r\n", totalspace);
      printf("Free space: %d KB\r\n", freespace);
#endif
/*   显示盘的类型 */
   printf("[1=FAT12, 2=FAT16, 3=FAT32, 4=exFAT]\r\n");
   printf("Disk type: %d\r\n", fs->fs_type);
   printf("********************\r\n");
   printf("GET DISK INFO END\r\n");
}
void fatTest_GetFileInfo(TCHAR *filename)
{
    FILINFO fno;
    FRESULT fr;
    printf("*** GET FILE INFO ***\r\n"); 
    fr = f_stat(filename, &fno);
    if(fr == FR_OK)
    {
        printf("File size: %ld bytes\r\n", fno.fsize);
        printf("File attributes: %d\r\n", fno.fattrib);
        printf("File Name: %s\r\n", fno.fname);

        RTC_DateTypeDef sDate;
        RTC_TimeTypeDef sTime;
        fat_GetTimeStamp(&fno, &sDate, &sTime);
        printf("File Time: %d-%d-%d %d:%d:%d\r\n", sDate.Year, sDate.Month, sDate.Date, sTime.Hours, sTime.Minutes, sTime.Seconds);
    }
    else if(fr == FR_NO_FILE)
    {
        printf("File not exist\r\n");
    }
    else
    {
        printf("GET FILE INFO error\r\n");
    }
}
void fatTest_ScanDir(TCHAR *pathName)
{
    DIR dir;
    FILINFO fno;
    FRESULT res;
    printf("*** SCAN DIR ***\r\n");
    res = f_opendir(&dir, pathName);
    if(res != FR_OK)
    {
      f_closedir(&dir);
      printf("f_opendir error\r\n");
      return; 
    }
    printf("ALL entries in dir %s:\r\n", pathName);
    while(1)
    {
        res = f_readdir(&dir, &fno);
        if(res!= FR_OK || fno.fname[0] == 0)
        {
            break; // 读取目录失败或者已经读取到最后一个文件
        } 
        if(fno.fattrib & AM_DIR)  // 是目录
        {
            printf("<DIR> %s\r\n", fno.fname);
        }
        else  // 是文件
        {
            printf("<FILE> %s\r\n", fno.fname);
        }
    }
    f_closedir(&dir);
    printf("SCAN DIR END\r\n");
}
void fatTest_RmoveAllFile(TCHAR *path);
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版