freertos代码结构
1. FreeRTOS系统架构
# FreeRTOS 内核源码
SOURCE_FILES += $(KERNEL_DIR)/tasks.c \$(KERNEL_DIR)/list.c \$(KERNEL_DIR)/queue.c \$(KERNEL_DIR)/timers.c \...(其他内核文件)$(KERNEL_DIR)/portable/GCC/RISC-V/port.c # RISC-V 移植层# 汇编文件(启动代码、中断向量等)
ASM_SOURCE_FILES += $(KERNEL_DIR)/portable/GCC/RISC-V/portASM.S \./start.S \./RegTest.S \./vector.S# 演示项目源码
SOURCE_FILES += $(COMMON_DEMO_FILES)/AbortDelay.c \$(COMMON_DEMO_FILES)/BlockQ.c \...(其他演示文件)$(DEMO_PROJECT)/main.c \$(DEMO_PROJECT)/ns16550.c # UART 驱动
2.FreeRTOS系统启动流程
sequenceDiagramparticipant ResetHandler as 复位处理函数(Reset_Handler)participant SystemInit as 系统初始化(SystemInit)participant Main as 主函数(main)participant TaskCreate as 创建任务(xTaskCreate)participant StartScheduler as 启动调度器(vTaskStartScheduler)participant IdleTask as 创建空闲任务participant TimerTask as 创建定时器任务(可选)participant InitVars as 初始化关键变量participant PortStart as 启动第一个任务(xPortStartScheduler)participant FirstTask as 第一个任务ResetHandler->>SystemInit: 调用SystemInit->>Main: 调用Main->>TaskCreate: 调用TaskCreate->>Main: 返回Main->>StartScheduler: 调用StartScheduler->>IdleTask: 创建StartScheduler->>TimerTask: 创建(如果需要)StartScheduler->>InitVars: 初始化StartScheduler->>PortStart: 调用PortStart->>FirstTask: 启动
在 FreeRTOS 中使用文件系统,核心是通过“可裁剪的文件系统组件”与 FreeRTOS 内核协同,实现对存储介质(如 Flash、SD 卡、EEPROM)的文件级操作(创建/读写/删除文件、管理目录等)。FreeRTOS 本身不自带文件系统,但支持与主流开源文件系统(如 FatFS、LittleFS)集成,同时提供任务安全机制(如互斥锁)确保多任务访问文件时的数据一致性。
3.FreeRTOS 集成文件系统的核心逻辑
FreeRTOS 作为实时操作系统,其文件系统使用需满足两个关键需求:
- 资源轻量化:适配嵌入式硬件的有限 RAM/Flash(如 KB 级 RAM);
- 任务安全:避免多任务并发访问文件时的“竞态条件”(如两个任务同时写同一文件导致数据损坏)。
集成逻辑如下:
[FreeRTOS 内核] ←→ [互斥锁/信号量] ←→ [文件系统适配层] ←→ [文件系统(FatFS/LittleFS)] ←→ [存储介质驱动]
- 互斥锁/信号量:FreeRTOS 提供同步机制,确保同一时间只有一个任务操作文件系统;
- 文件系统适配层:将文件系统的“阻塞操作”(如 SD 卡读写等待)与 FreeRTOS 任务调度兼容(避免阻塞整个系统);
- 存储介质驱动:对接硬件(如 SPI Flash、SD 卡的 SPI/SDIO 接口),提供底层读写函数(如
disk_read
/disk_write
)。
4.主流文件系统选择与适配
FreeRTOS 常用的文件系统有 FatFS(通用、兼容 Windows)和 LittleFS(专为 Flash 优化、支持磨损均衡),两者均为开源、轻量级,无需依赖操作系统,但需与 FreeRTOS 做简单适配。
4.1. FatFS:通用兼容型文件系统
- 特点:支持 FAT12/FAT16/FAT32/exFAT 格式,兼容 Windows/macOS,可直接读取存储介质(如 SD 卡插电脑可识别);
- 资源占用:RAM 占用 ~5KB(配置为最小模式),代码体积 ~10KB,适合 SD 卡、大容量 Flash;
- 适配核心:将 FatFS 的“定时器等待”(如 SD 卡初始化超时)替换为 FreeRTOS 的
vTaskDelay
,并通过互斥锁保护文件操作。
4.2. LittleFS:Flash 专用优化型文件系统
- 特点:专为嵌入式 Flash 设计,支持磨损均衡(延长 Flash 寿命)、掉电数据保护,不兼容 Windows(需专用工具读取);
- 资源占用:RAM 占用 ~2KB,代码体积 ~8KB,适合小容量 Flash(如 SPI Flash、片内 Flash);
- 适配核心:LittleFS 的“块设备操作”(读/写/擦除 Flash)需对接硬件驱动,同时用 FreeRTOS 互斥锁确保多任务安全。
5. FreeRTOS 集成 FatFS 实操步骤(以 STM32 + SD 卡为例)
以 STM32F4(Cortex-M4)单片机、SD 卡(SPI 接口)、FreeRTOS 10.4 为例,演示集成 FatFS 的关键步骤:
5.1. 准备基础组件
- FreeRTOS 内核:确保已移植完成(任务调度、定时器正常工作);
- SD 卡驱动:实现底层硬件驱动(SPI 初始化、SD 卡初始化、读/写扇区函数),示例函数:
// SD 卡初始化 HAL_StatusTypeDef SD_Init(void); // 读扇区:从扇区 addr 读 len 个扇区到 buf HAL_StatusTypeDef SD_ReadSector(uint32_t addr, uint8_t *buf, uint32_t len); // 写扇区:将 buf 中 len 个扇区写入扇区 addr HAL_StatusTypeDef SD_WriteSector(uint32_t addr, const uint8_t *buf, uint32_t len);
5.2. 移植 FatFS 到 FreeRTOS
- 下载 FatFS:从 FatFS 官网 下载最新版本(如 R0.15);
- 添加文件到工程:将 FatFS 核心文件(
ff.c
、ff.h
、ff_gen_drv.c
、ff_gen_drv.h
)添加到项目,并创建 SD 卡设备驱动文件sd_diskio.c
; - 实现 FatFS 设备接口:在
sd_diskio.c
中实现 FatFS 要求的 6 个底层函数(对接 SD 卡驱动):函数名 功能 实现逻辑 disk_initialize
初始化存储设备 调用 SD_Init()
disk_status
获取设备状态 返回 SD 卡是否就绪 disk_read
读扇区 调用 SD_ReadSector()
disk_write
写扇区 调用 SD_WriteSector()
disk_ioctl
设备控制(如获取扇区数) 返回 SD 卡参数(扇区大小、总扇区数) get_fattime
获取当前时间(可选) 返回固定时间或 FreeRTOS 系统时间
5.3. 加 FreeRTOS 任务安全保护
FatFS 默认不支持多任务并发访问,需通过 FreeRTOS 互斥锁确保安全:
- 创建互斥锁:在 FreeRTOS 初始化时创建文件系统互斥锁:
SemaphoreHandle_t xFileSystemMutex; xFileSystemMutex = xSemaphoreCreateMutex(); // 创建互斥锁
- 包装文件操作函数:将 FatFS 的 API(如
f_open
、f_write
)包装为带互斥锁保护的函数:
同理包装// 包装 f_open:加锁后打开文件 FRESULT f_open_safe(FIL *fp, const TCHAR *path, BYTE mode) {FRESULT res;if (xSemaphoreTake(xFileSystemMutex, portMAX_DELAY) == pdPASS) { // 获取互斥锁res = f_open(fp, path, mode);xSemaphoreGive(xFileSystemMutex); // 释放互斥锁}return res; }
f_write
、f_read
、f_close
等函数,避免多任务同时操作文件。
5.4. 在 FreeRTOS 任务中使用文件系统
创建两个任务,分别实现“写文件”和“读文件”,验证多任务安全:
// 任务 1:写文件到 SD 卡
void vFileWriteTask(void *pvParameters) {FIL fp;FRESULT res;char buf[] = "FreeRTOS FatFS Test: Hello World!\r\n";uint32_t bytes_written;for (;;) {// 打开文件(追加模式)res = f_open_safe(&fp, "test.txt", FA_OPEN_ALWAYS | FA_WRITE);if (res == FR_OK) {f_lseek(&fp, f_size(&fp)); // 移动到文件末尾f_write(&fp, buf, sizeof(buf)-1, &bytes_written); // 写数据f_close_safe(&fp); // 关闭文件printf("Write %d bytes to test.txt\r\n", bytes_written);} else {printf("Open file failed: %d\r\n", res);}vTaskDelay(pdMS_TO_TICKS(1000)); // 每隔 1 秒写一次}
}// 任务 2:读文件从 SD 卡
void vFileReadTask(void *pvParameters) {FIL fp;FRESULT res;char buf[128];uint32_t bytes_read;for (;;) {// 打开文件(只读模式)res = f_open_safe(&fp, "test.txt", FA_OPEN_EXISTING | FA_READ);if (res == FR_OK) {f_read(&fp, buf, sizeof(buf)-1, &bytes_read); // 读数据buf[bytes_read] = '\0'; // 加字符串结束符printf("Read from test.txt: %s\r\n", buf);f_close_safe(&fp); // 关闭文件} else {printf("Open file failed: %d\r\n", res);}vTaskDelay(pdMS_TO_TICKS(2000)); // 每隔 2 秒读一次}
}// main 函数中创建任务并启动调度器
int main(void) {// 1. 硬件初始化(时钟、SPI、UART)HAL_Init();SystemClock_Config();SPI_SD_Init();UART_Init();// 2. 创建文件系统互斥锁和任务xFileSystemMutex = xSemaphoreCreateMutex();xTaskCreate(vFileWriteTask, "FileWrite", 1024, NULL, 2, NULL);xTaskCreate(vFileReadTask, "FileRead", 1024, NULL, 1, NULL); // 优先级低于写任务// 3. 启动 FreeRTOS 调度器vTaskStartScheduler();for (;;) { return 0; }
}
6.关键注意事项
-
资源配置优化:
- FatFS 可通过
ff.h
中的宏裁剪功能(如FF_FS_READONLY=1
关闭写功能、FF_USE_STRFUNC=0
关闭字符串操作),减少 RAM/Flash 占用; - 任务栈大小需足够(文件操作需较大栈空间,建议至少 512 字,即 2KB for 32 位 CPU)。
- FatFS 可通过
-
掉电数据保护:
- 写文件时需确保数据完全写入存储介质(如 SD 卡的
disk_write
需等待写完成),避免掉电导致文件损坏; - LittleFS 天然支持掉电保护,FatFS 需通过
f_sync
函数强制刷新缓存到硬件。
- 写文件时需确保数据完全写入存储介质(如 SD 卡的
-
多任务优先级设计:
- 高优先级任务操作文件时,低优先级任务会被阻塞,需合理设置优先级(如“数据采集任务”优先级高于“日志写入任务”,避免采集丢失)。
-
错误处理:
- 必须处理 FatFS 的返回值(如
FR_NO_FILE
、FR_DISK_ERR
),避免因 SD 卡拔插、Flash 损坏导致系统崩溃。
- 必须处理 FatFS 的返回值(如
7.扩展场景
- 集成 LittleFS:流程与 FatFS 类似,核心是实现 LittleFS 的块设备接口(
lfs_disk_t
),对接 Flash 驱动; - 网络文件系统:通过 FreeRTOS 集成 LWIP 协议栈,再对接 TFTP/SMB 客户端,实现对网络共享文件的访问;
- 片内 Flash 文件系统:对于无外部存储的场景,可将片内 Flash 划分为“代码区”和“文件区”,用 FatFS/LittleFS 管理文件区。
8.总结
FreeRTOS 本身不提供文件系统,但通过与 FatFS、LittleFS 等轻量级文件系统集成,可实现对各类存储介质的文件管理。核心是“底层驱动对接+任务安全保护”——前者确保文件系统能操作硬件,后者避免多任务并发访问导致的数据问题。这种方案兼顾了 FreeRTOS 的实时性和文件系统的实用性,广泛应用于嵌入式数据日志、配置存储、固件升级等场景。