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

【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中文论坛活动

即日起开启活动话题入口,之后的活动统一都放在此处,欢迎大家的加入!


最新内容

相似分享

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版