这篇文章有什么用?
FreeRTOS已经包含很多范例程序——每一个均用于:
1. 一个特定的微控制器
2. 一个特定的开发工具(编译器,调试器,等等)
3. 一个特定的硬件平台(原型或评估板)
在官方主页左边的’RTOS Ports‘菜单下有大量的文档。
然而不可能为每一个微控制器、编译器和评估板的组合提供一个范例工程——因此有可能没有一个范例程序与你的需求完全吻合。这个文档就是指导你如何修改与组合范例程序来更好的符合你的要求。
十分容易就可以使用一个现有的评估板范例经过修改然后用在另外一个上——如果是从一个编译器修改到另外一个可能会复杂一点。这个文档提供相 似平台的移植指引。然而把FreeRTOS从一个平台移植到另外一个完全不同的、还未被支持的处理器内核体系并不是一件容易的工作。因此这个文档不会包括 建立一个全新的FreeRTOS平台的内容。
转换一个范例用于不同的评估板
这部分描述把一个已有的范例程序从一个原型板转换到另一个的步骤,没有改变使用的微控制器与编译器。作为例子,这些指引将用来把运行于SAM7S硬件上的IAR SAM7S的范例转换为运行于Olimex SAM7-P64原型板。
在进行下一步前要保证前面的步骤完全成功:
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; /* volatile so it is not optimized away. */
/* 初始化LED输出——注意prvSetupHardware()有可能也需要调用*/
vParTestInitialise();
/* 反复闪烁LED */
for( ;; )
{
/* 现在我们并不需要使用RTOS的特性,所以只是用一个延时来代替 */
for( ul = 0; ul < 0xfffff; ul++ )
{
}
/* 点亮前4个LED(假设至少有四个LED) */
vParTestToggleLED( 0 );
vParTestToggleLED( 1 );
vParTestToggleLED( 2 );
vParTestToggleLED( 3 );
}
return 0;
}
3. 介绍调度器:
- 一旦确认LED可以正常工作,上面那个main()函数就可以删除,恢复原来的main()函数。
- 建议先从一个最简单的多任务程序开始。标准的‘闪光’任务经常会用来作为一个多任务的‘hello world’应用程序。
- 标准的‘闪光测试’任务使用3个非常简单的任务——每一个都以固定的频率闪亮LED,各个的频率都不同。这些任务几乎包含于每一个范例程 序中,在 main() 函数中调用vStartLEDFlashTasks()(如果使用联合程序则应该用vStartFlashCoRoutines()来代替)。如果你使用 的范例中的main()函数没有调用vStartLEDFlashTasks() (或 vStartFlashCoRoutines()) ,则应该简单的添加 FreeRTOS/Demo/Common/Minimal/Flash.c到你的工程,然后手工调用vStartLEDFlashTasks()。
- 把用来开始一个或多个范例任务的所有函数注释掉,除了vStartLEDFlashTasks()函数。此时,main()函数很有可能 只调用三个函数: prvSetupHardware(), vStartLEDFlashTasks(), and vTaskStartScheduler()。例如: (基于前面对典型main()的介绍):
int main( void )
{
/* 为范例设置微控制器硬件 */
prvSetupHardware();
/* 保留此函数 */
vCreateFlashTasks();
/* 把其他创建任务的函数注释掉
vCreatePollQTasks();
vCreateComTestTasks();
等等
xTaskCreate( vCheckTask, "check", STACK_SIZE, NULL, TASK_PRIORITY, NULL );
*/
启动调度器 */
vTaskStartScheduler();
/* 不会运行到这里 */
return 0;
}
- 如果LED0到LED2受到‘闪光’函数控制并且以一个预定的频率闪烁,则表明这个简单的程序正确运行。
4. 完成:
- 一旦这个简单的闪光范例可以运行你就可以恢复到前面那个包含全部任务的完整范例程序。
- 需要紧记的几点:
- 如果范例程序开始时没有调用vTaskCreateFlashTasks(),那么就要手工添加调用这个函数,当可正确运行后要把这个调用删掉。这样做是 由于两个原因,其一就是‘闪光’任务使用的LED输出可能在范例的其他地方已经用了,其二是完整的范例可能已经使用了所有可用的RAM,意味着没有位置来 创建这个任务。
- 标准的‘串口测试’任务(如果范例中包含)会使用微控制器的一个UART外设。请检查你移植的硬件的串口是可用的。
- 有些外设(如LCD)很有可能在修改之前无法用于其他的硬件或接口。
组合或修改已有的范例工程
这部分将重点讲解修改一个已有的工程或组合两个已有工程需要考虑的细节,两者均是为了创建一个工程来满足你特定的需要。例如,你可能想创建一个使用 GCC编译器的STR9范例工程,但是FreeRTOS的下载中还没有包含一个GCC的STR9范例,它只包含一个IAR STR9范例与一个GCC STR75x范例。因此创建STR9 GCC工程的信息可以从已有的两个工程中收集。
可以通过两种方式来实现:
1. 使用一个现有的范例工程,使用同一个编译器,从新配置到另外一个需要的微控制器。
2. 使用你选择的编译器创建一个新的工程。当你这样做时,可以使用一个已有的范例来指引你需要使用哪些文件与设置,虽然已有的工程用的是另外一种编译器。
下面的说明将突出显示需要哪些信息,无论你用的是哪种方法:
- 确认哪些与平台相关的FreeRTOS内核文件将被使用:
- FreeRTOS源代码组织文档提供了解FreeRTOS目录结构需要的所有信息。
- 大部分(如果不是全部)与某一平台相关的代码均包含在一个叫FreeRTOS/source/portable/[compiler] /[microcontroller]/port.c的文件中,伴随的有一个叫FreeRTOS/source/portable/[compiler] /[microcontroller]/portmacro.h 的文件。此处[compiler]是使用编译器的名字,[microcontroller]是使用的微控制器家族的名字。
- 某些编译器需要port.c 与 portmacro.h文件,而另外的编译器(那些缺少灵活特性的)还需要一个称为portasm.s或portasm.asm的汇编文件。
- 最后,只是对ARM7 GCC平台特定的,需要把一个叫做portISR.c的文件从port.c文件中分离出来,因为其总是编译为ARM模式——而保留在port.c中的代码可以编译为ARM模式或THUMB模式。
- 确认哪些与编译器相关的文件将被使用:
- 嵌入式系统专用的编译器会提供某些C语言的扩展。例如,可能会使用一个特定的关键字识别某个函数应该编译为中断处理函数。
- C语言的扩展在定义上超出了C标准,因此不同的编译器见会有所不同。在FreeRTOS的文件中,此类非标准的语法包含于 FreeRTOS/source /portable目录树下(如上所述)。另外,一些范例程序会加入非FreeRTOS的中断处理,这些中断处理函数与其加入的方式也是与编译器相关的。
- 底层文件:
- C启动文件与链接脚本一般都是跟处理器与编译器相关的。请不要尝试从零开始创建此类文件——你应该浏览已有的FreeRTOS范例工程获取一个适合的候选文件用于修改。
- 请特别小心处理ARM7的C启动文件。这里必须设置IRQ向量直接指向一个中断处理程序或者指向一个公用的切入点。这两种方法的例子均有 提供。无论是使用哪种方法,在跳转后首要运行的必须是FreeRTOS上下文保存代码,没有处理器会提供中间代码。再一次提醒——使用一个已有的文件作为 参考。
- 链接脚本必须做适当的修改以正确的描述将要使用的微控制器的内存映射。
- 工程设置:
- 每个工程都必须定义与将要编译的平台相关的预处理宏。这些预处理宏将确认哪个portmacro.h文件将被包含。例如,当使用GCC来 编译 MegaAVR平台的工程时,GCC_MEGA_AVR必须定义;使用IAR编译MegaAVR的工程时IAR_MEGA_AVR必须定义,等等。参考已 有的范例程序工程以及FreeRTOS/source/include/portable.h 文件来查找你的工程的正确定义。
- 其他的编译器设置,如优化选项,也是关键的,可以参考已有的范例程序工程。
- 拥有IDE界面的编译器一般会把目标微处理器作为工程设置的一部分——当使用新的目标时必须做出调整。同样地,如果使用makefile,makefile内的选项也必须正确的更新到新的微控制器。
- 配置时间滴答中断:
- 时间滴答中断通过调用prvSetupTimerInterrupt()函数来配置,此函数位于FreeRTOS/source/portable/[compiler]/[microcontroller]/port.c文件中。
- RAM与ROM使用:
- 内存管理部分提供了解FreeRTOS如何使用RAM以及RAM如何分配给内核所需要的所有信息。
- 如果你要把一个已有的范例程序移植到一个有更少RAM的微控制器上,你可能需要减小configTOTAL_HEAP_SIZE的值(位 于FreeRTOSConfig.h中),并且减少创建的任务的数量 。减少任务的数量可以通过简单的把main()函数中用来创建任务的函数注释掉来达到,如前面的示范。
- 如果你要把已有的范例程序运行于一个有更少ROM的微处理器上,你需要减少范例程序包含的文件数量。这些文件存放于FreeRTOS/Demo/common目录树下。当你把一个范例文件从编译中删除时也应该把main()函数中用于调用创建此类任务的函数删除。