FreeRTOS下载包中已经包含很多演示例程- 每一个例程都是针对于:
- 特定的微控制器;
- 特定的开发工具(编译器、调试器等等);
- 特定的硬件平台(样机或评估板)。
可以在官方网站首页左侧的树形菜单 'Supported Devices' 中找到这些例程介绍。
可惜的是不可能为所有微控制器、编译器和评估板提供演示例程。因此,官方提供的演示例程可能不完全符合你正在使用的开发平台。本章描述如何通过修改或合并官方提供的演示例程,来满足自己的开发平台需求(包括微处理器和编译器)。
修改一个现有的评估板例程,使之运行到另一个同类评估板上,通常是比较简单的,稍微复杂些的是跨编译器移植。本文介绍这两情况下的修改,只是对相似的平台有效。然而,将FreeRTOS移植到一个全新的平台、未支持的处理器架构,并不是件简单的事情。本文不讨论如何将FreeRTOS移植到一个全新平台。
1.修改例程使之运行到不同评估板
本节描述如何通过修改一个官方提供的演示例程,使之运行到另一个评估板,这里两个评估板使用同系列微处理器,使用相同编译器。在这个例子中,将运行于SAM7S-EK硬件开发板上的IAR SAM7S演示例程,修改使之运行到Olimex SAM7-P64开发板。(注:两块开发板都是使用ATMEL公司的ARM7微处理器,前者使用AT91SAM7S256,后者使用AT91SAM7S64)
1.1初始编译
作为修改练习的起点,被修改的演示例程是要能使用的。因此,在未做任何修改之前,首先检查下载的演示例程能否被正确的编译。绝大多数情况下,演示例程编译后是没有任何错误和警告的。
关于演示例程所在目录,参考《FreeRTOS系列第2篇---FreeRTOS入门指南》一文的第三节。
1.2修改LED IO端口
LED灯是用来指示演示例程运行的最简单方法,因此点亮新硬件平台上的LED灯通常是最容易的。
两个不同评估板上的LED连接到相同的IO端口通常是不太可能的,因此,一些小幅度修改是必须的。
在partest.c文件中的vParTestInitialise() 函数包含IO端口的模式和方向配置。在main.c文件中的prvSetupHardware()函数包含更多的硬件初始化(比如,使能IO外设的时钟模块),可能需要根据不同的使用进行一些修改。
根据目标评估板的硬件,在上面两个函数中做必要的修改,然后写一段简单程序,来检查硬件LED是否完好。这个简单程序不使用FreeRTOS,只是为了确保硬件LED能够正常工作。因此,注释掉之前的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;
}
1.3 RTOS调度器简介
一旦确定硬件LED可以正常工作,就可以恢复原来的main()函数。
作为入门级的多任务应用程序应该尽量的简单,LED闪烁测试程序常常担任这样的角色,可以堪比经典的“Hello Wold”。这个任务几乎在所有演示例程中都能看到,在main()函数中调用vStartLEDFlashTasks() (使用协程版本时调用vStartFlashCoRoutines())来实现。如果你使用的演示例程main()函数中并没有调用vStartLEDFlashTasks()(或vStartFlashCoRoutines()),那么需要你将FreeRTOS/Demo/Common/Minimal/Flash.c文件添加到你的工程,并在main()函数手动的增加vStartLEDFlashTasks()函数。
除了调用vStartLEDFlashTasks()外,注释掉所有用于启动一个或多个演示任务的函数。最后的main()函数仅调用三个函数:prvSetupHardware()、vStartLEDFlashTasks()和vTaskStartScheduler()。例如(基于典型的main()函数):
int main( void )
{
/* 设置用于演示的微控制器硬件 */
prvSetupHardware();
/* 留下这个函数 */
vCreateFlashTasks();
/* 所有的其它创建任务的函数统统注释掉
vCreatePollQTasks();
vCreateComTestTasks();
//等等…
xTaskCreate( vCheckTask,"check", STACK_SIZE, NULL, TASK_PRIORITY, NULL );
*/
/*启动RTOS调度器. */
vTaskStartScheduler();
/* 永远不会执行到这里! */
return 0;
}
这是一个非常简单的应用程序,正确执行后,LED0~2(包括2)或分别按照不同的频率闪烁。
1.4 收尾工作
一旦简单的LED闪烁例程正确执行后,你可以恢复之前注释掉的所有的演示任务。
以下要点需牢记:
如果你使用的演示例程最初并没有调用vTaskCreateFlashTasks()函数,而是手动的增加了这个函数,那么应该再手动的删除掉这个函数。主要有两个方面的原因:第一是这个LED闪烁任务用到的IO可能也被演示例程的其它任务使用,第二是演示例程可能已经占用了所有的RAM,已经没有空余RAM用来增加新的任务。
标准的“通讯测试(comtest)”(如果演示例程中有的话)任务使用到微控制器的一个UART外设。检测硬件是可用的。
有些外设不进行修改就想用于任何不同的硬件或接口是不可能的,比如LCD。
2.合并或修改官方演示工程
本节主要描述如何修改一个现存的工程或者按照需求合并两个现存的工程。比如,你希望使用GCC编译器创建一个STR9演示工程(demo project),并且你下载的FreeRTOS软件包中并没有GCC版本的STR9演示例程,但是FreeRTOS下载包中有IAR版本的STR9演示例程和GCC版本的STR75x演示例程。则可以通过这两个现存的工程来创建GCC版本的STR9演示工程。可以有两种方式完成:
使用GCC版本的STR75x演示工程,修改使之符合指定的微处理器(STR9评估板上的微处理器)。
使用GCC创建一个新的工程。从IAR版本的STR9演示工程中获取文件和配置信息,使之符合GCC编译器需求。
2.1识别用于特定微控制器的FreeRTOS内核文件
对于一个特定平台,大多数(不是全部)硬件接口代码包含在一个叫做FreeRTOS/source/portable/[编译器]/[微控制器/port.c的文件中,和它对应的头文件是FreeRTOS/source/portable/[编译器]/[微控制器]/portmacro.h。
对于一些编译器来说,port.c和portmacro.h就是所需要的全部硬件接口代码。另一些还需要一些汇编文件,这些文件叫做portasm.s或者portasm.asm。
最后,仅对于ARM7 GCC移植,同样存在一个类似的硬件接口文件:portISR.c,portISR.c是从port.c中分离出来的,这些代码必须在ARM模式下编译,port.c中剩余的代码既可以在ARM模式下编译,也可在THUMB模式下编译。
2.2识别用于特定编译器的文件
编译器可以为嵌入式系统提供某些特定的C语言扩展。比如某个特定关键字可以标识出一个函数是中断处理服务函数。
扩展的C语言部分,是不属于标准C语言规范的。因此,编译器与编译器之间是有差别的。FreeRTOS的文件中就包含类似的非标准C语言语法,在文件夹FreeRTOS/source/portable中(上文中提到的特定微控制器硬件接口代码也在这个文件中)。此外,一些演示例程会使用到中断服务程序,这些中断服务程序并不属于FreeRTOS的一部分,并且如何定义和使用这些中断服务程序也是编译器所特定的。
2.3硬件底层文件
C启动文件和链接脚本都属于处理器和编译器特定的。不推荐尝试从无到有的创建这些文件,应该到FreeRTOS演示工程中寻找一个合适的来修改。
要特别小心ARM7启动文件。它必须将IRQ中断服务程序入口地址配置到快速中断处理向量表或者普通中断向量表中。这两种情况,演示工程都提供了例子。
链接脚本必须正确的描述当前使用处理器的内存映射。
2.4工程设置
每一个工程通常都会定义一些宏,这些预处理宏定义了一些要被编译的特定的硬件接口代码。要包含portmacro.h文件才能识别这些宏。比如,当使用GCC编译MegaAVR硬件接口代码时,宏GCC_MEGA_AVR必须被定义;当使用IAR编译MegaAVR硬件接口代码时,宏IAR_MEGA_AVR必须被定义等等。参考演示例程工程以及FreeRTOS/source/include/portable.h文件可以查找当前工程定义了那些宏。如果预处理宏未定义,那么portmacro.h文件所在目录的路径必须被包含到预处理器的搜索路径中。
其它的编译器设置,比如优化选项,也是很关键的。可以参考提供的演示工程。
具有IDE的编译器通常具有目标微控制器选项并将它作为工程设置的一部分,所以新的工程也必须适应新的目标微控制器,同样的,如果使用到makefile文件,则makefile文件也必须更新以符合新的目标微控制器。
2.5配置系统节拍时钟中断
调用函数prvSetupTimerInterrupt()来配置系统节拍中断,这个函数可以在以下路径的文件中找到:FreeRTOS/source/portable/[compiler]/[microcontroller]/port.c
2.6 RAM和ROM的使用
FreeRTOS内存管理一章中描述了FreeRTOS如何使用RAM,并且描述了RAM是如何分配给RTOS内核的。
如果你要将演示例程移植到一个RAM稍小的微处理器上,那么你可能需要减少configTOTAL_HEAP_SIZE的值(位于FreeRTOSConfig.h),并且减少演示例程的任务个数。可以通过简单的注释掉不需要的任务来实现。
如果你要将演示例程移植到一个ROM较小的微处理器中,那么你可能需要减少应用例程的文件数目,他们位于FreeRTOS/Demo/common文件夹目录下。同时你还要删除main函数中对他们的调用函数。
注:可能你是通过搜索引擎找到这篇文章,满怀希望的点进来,以为能解决自己移植的所有问题,但是看完后却发现本文站的角度太高,并不是特别适合对移植一无所知的你。先别急着以为本文是标题党而点踩,可能有一篇文章适合你,这篇文章以Cortex-M3硬件平台为例,详细的介绍移植过程,请点击这里。
相关阅读
FreeRTOS系列第2篇---FreeRTOS入门指南
FreeRTOS系列第1篇---为什么选择FreeRTOS?
作者:朱工
首发博客:https://blog.csdn.net/zhzht19861011/article/details/49961843
关注FreeRTOS从基础到高级专栏,即时收取FreeRTOS系列文章。