我的FreeRTOS学习,是从朱工的FreeRTOS系列博客开始的,感谢朱工的悉心整理,文章很不错,适合学习。
根据朱工的博客,按照我自己的习惯和思路,把最关键的信息抓取下来,以备快速理清思路。
具体展开和丰富,需要移步朱工的文章,或者参考官方网站的资料。
1. 什么是FreeRTOS
开源,免费,用户量大,内核简练的一个实时操作系统。
因为开源免费,所以用的人多,所有bug少。
核心是任务调度器,比较短小,3个C文件,学习压力相对小。
官网 www.freertos.org
2. 简单入门
文档
- 指南
- 手册
- demo文档, 官网左侧Supported Devices & Demos
源码
- 内核源码
- 移植包
结构
- 顶层
- FreeRTOS-Plus
- FreeRTOS 主要关注这个
FreeRTOS
FreeRTOS
|+-- Demo 包含演示例程工程;
|+-- Source 包含实时内核源文件。
tasks.c
queue.c
list.c 以上3个是主要的文件,下面3个是可选的
timers.c
event_group.c
croutine.c
FreeRTOS/Source
FreeRTOS
| +-- Source FreeRTOS内核代码文件
| |+-- include FreeRTOS内核代码头文件
| |+-- Portable 处理器特定代码
| | |+--Compiler x 支持编译器x的所有移植包
| | |+--Compiler y 支持编译器y的所有移植包
| | |+--MemMang 内存堆实现范例
- 处理器架构相关代码
- FreeRTOS/Source/Portable/[相应编译器]/[相应CPU架构]子目录
- 堆栈设计
- FreeRTOS/Source/portable/MemMang目录下heap_x.c
演示例程
FreeRTOS
|+-- Demo
| |+-- Common 所有例程都可以使用的演示例程文件
| |+-- Dir x 用于x平台的演示例程工程文件
| |+-- Dir y 用于y平台的演示例程工程文件
如果有演示例程中相同的设备,就可以开始编译和查看结果。
3. 移植
演示例程都是针对特定的对象
- 特定的微控制器
- 开发工具(编译器,调试器)
- 特定的平台(开发板,样机)
官方例程没有的,就需要移植。
最简单的上前两条都相同,只是不同的开发板。直接开始编译就可以,target都是一样的。
但是GPIO管脚什么的肯定不一样,所以即使能编译过,一些功能测试函数肯定也是功能错误的。
partest.c里边的vParTestInitialise()用于IO端口配置,vParTestSetLED和vParTestToggleLED用来测试GPIO,这些需要根据当前的target改改,然后在main里边调用测试
int main( void )
{
volatile unsigned long ul; /* 禁止编译器优化此变量 */
/* 初始化LED IO为输出-注:prvSetupHardware()也可能会被调用*/
vParTestInitialise();
/*不断开启LED */
for( ;; )
{
/* 我们暂时不使用RTOS,这里只是使用一个非常粗糙的延时*/
for( ul = 0; ul < 0xfffff; ul++ )
{
}
/* 开启4个LED */
vParTestToggleLED( 0 );
vParTestToggleLED( 1 );
vParTestToggleLED( 2 );
vParTestToggleLED( 3 );
}
return 0;
}
LED点灯测试没有问题了,就可以开始测试任务调度了
使用vStartLEDFlashTasks() 测试任务调度,如果例程不包含,就添加FreeRTOS/Demo/Common/Minimal/Flash.c到工程中,功能是让几个LED等以不公的频率闪。
int main( void )
{
/* 设置用于演示的微控制器硬件 */
prvSetupHardware();
/* 留下这个函数 */
vCreateFlashTasks();
/* 所有的其它创建任务的函数统统注释掉
vCreatePollQTasks();
vCreateComTestTasks();
//等等…
xTaskCreate( vCheckTask,"check", STACK_SIZE, NULL, TASK_PRIORITY, NULL );
*/
/*启动RTOS调度器. */
vTaskStartScheduler();
/* 永远不会执行到这里! */
return 0;
}
能看到主要的函数就3个
- prvSetupHardware() 设置硬件
- vCreateFlashTasks() 创建闪灯任务
- vTaskStartScheduler() 启动调度
特定target的内核文件
特定平台,大多数文件位于
- FreeRTOS/source/portable/[编译器]/[微控制器/port.c
- FreeRTOS/source/portable/[编译器]/[微控制器]/portmacro.h
- 可能还有portasm.s或者portasm.asm
4. 编码标准
FreeRTOS的核心源代码遵从MISRA编码标准指南。
不展开了。
5. CM3的移植
准备
- 开发板
- FreeRTOS程序包
- CMSIS-M3,core_cm3.h
过程
- 核心代码加入工程
- taks.c, queue.c, list.c
- port.c
- heap_1.c
- 头文件路径
- …\FreeRTOS\Source\portable\RVDS\ARM_CM3
- …\FreeRTOS\Source\include
- 编写FreeRTOSConfig.h文件,下一节介绍
- 编写钩子函数
- 如果配置了configUSE_TICK_HOOK=1,需要编写voidvApplicationTickHook( void )
- 如果配置了configCHECK_FOR_STACK_OVERFLOW=1或=2,需要编写voidvApplicationStackOverflowHook( xTaskHandle pxTask, signed char *pcTaskName )
- 检查硬件,亮一下LED或者UART串口发个字符
#include"task.h"
#include"queue.h"
#include"list.h"
#include"portable.h"
#include"debug.h"
int main(void)
{
init_rtos_debug(); //初始化调试串口
MAP_UARTCharPut('A'); //发送一个字符
while(1);
}
5. 挂接中断,在startup.s中,使用IMPORT关键字声明要挂接的异常中断服务函数名
DCD SVC_Handler 换成: DCD vPortSVCHandler
DCD PendSV_Handler 换成: DCD xPortPendSVHandler
DCD SysTick_Handler 换成: DCD xPortSysTickHandler
6. 建立第一个任务,每隔一秒钟发送一个字符
voidvTask(void *pvParameters)
{
while(1)
{
MAP_UARTCharPut(0x31);
vTaskDelay(1000/portTICK_RATE_MS);
}
}
其中vTaskDelay()是API函数。
7. 设置节拍时钟,每10ms产生一个中断,只需要在FreeRTOSConfig.h里边做下配置
- configCPU_CLOCK_HZ (/你的硬件平台CPU系统时钟,Fcclk/)
- configTICK_RATE_HZ ((portTickType)100)
在prot.c中,函数vPortSetupTimerInterrupt()设置节拍时钟,由函数vTaskStartScheduler()调用,这个函数用于启动调度器。
8. 设置中断优先级宏,在FreeRTOSConfig.h中
#ifdef __NVIC_PRIO_BITS
#defineconfigPRIO_BITS __NVIC_PRIO_BITS
#else
#defineconfigPRIO_BITS 5 /*lpc177x_8x微处理器使用优先级寄存器的