基于之前的分析,freeRTOS的移植主要集中在以下部分,
它们对应的源文件如下
移植之前必须清楚待移植嵌入式系统的硬件架构,尤其是CPU和存储器的相关细节。后边将一一提到。实际上freeRTOS需要移植的必要代码都已经在portable.h中声明(不含freeRTOS_Config.h配置的可选功能),我们只需要按照该文件填写好对应的宏和函数即可。
以下将以freeRTOS官网上给出的基于ZYNQ_ZC702的工程,对一些常见的需要移植的代码进行分析。
初始化Task Stack
对应函数声明强制如下,
StackType_t*pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void*pvParameters )
其在freeRTOS创建TASK时被调用,用于初始化TASK的STACK,细节参考API函数xTaskCreate()、xTaskCreateStatic()、xTaskCreateRestricted和xTaskCreateRestrictedStatic()。
该函数的处理十分简单,实际就是压栈过程,但寄存器的取值完全用用户确定,但是需要注意以下几点
前两点需要用户查询CPU相关硬件手册,是必须做的。后两者并不强制要求,但是在实际移植中常常用到,可以用来检测OS崩溃。
若业务代码没有频繁创建TASK,处于便于维护的考虑,建议用C语言实现。
以下为freeRTOS官网提供的部分代码,可见其认为栈是向下生长的,按照R15到R0的顺序进行入栈的,出栈时必须保证这样的顺序。
启动调度器
对应函数声明强制如下,
BaseType_t xPortStartScheduler( void )
其在freeRTOS提供的API函数vTaskStartScheduler()中调用,用于OS启动时设置ISR、初始系统硬件和运行firstTASK。
其中,
freeRTOS官网上的代码实际上是使用函数vConfigureTickInterrupt()来设置中断和完成硬件初始化的,然后调用汇编语言实现的函数vPortRestoreTaskContext()运行first TASK
vConfigureTickInterrupt()的基本流程如下图所示,其中使用了大量的ZYNQ 7000的提供的BSP,对于其他的硬件模块,也可以使用类似的流程完成相应中断设置和初始化
其中,
只需要在首次配置中断时使用,使用BSP提供的API函数XScuGic_CfgInitialize()
以下为相应代码,实际上所有外设中断都可以如是配置。
vPortRestoreTaskContext()实际上就是出栈的处理过程,也用于任务切换的处理过程,在后边会提到。
ISR
一般而言,ISR处理过程如下图所示,包含压栈、用户自定义处理和出栈过程,
其中,
该部分的移植需要特别考虑如何提高出栈和压栈代码的效率,以及提供给用户更加方便的用户自定义处理过程的API接口。
除此之外,还需要考虑如何将ISR注册到CPU认可的中断向量表中去。
FreeRTOS使用了中断向量表替换的方式来完成注册,如下图所示,其中的函数vPortInstallFreeRTOSVectorTable()需要在操作系统启动前调用
对应的中断处理向量表freertos_vector_table如下,
PS:freertos_vector_table需要在链接器文件中注册,其中尤其要注意把vector_table的KEEP修饰关键字去掉
freeRTOS提供了名为FreeRTOS_IRQ_Handler的函数来实现ISR,细节如下。
压栈过程代码如下,其中的176行即对当前TASK进行压栈,在此之前,保存了了R14和SPSR,然后切入到SVC模式。
用户自定义处理过程相关代码如下,其中,
出栈过程相关代码如下,其中
TASK切换
如之前所述,TASK切换主要是压栈和出栈操作。freeRTOS还提供了了以API函数用于选取当前处于ready状态的优先级最高的TASK,即vTaskSwitchContextConst(),并且freeRTOS还提供了名为pxCurrentTCB的变量用于指示当前TASK的栈顶地址。
freeRTOS提供函数FreeRTOS_SWI_Handler用于TASK切换,
其中portSAVE_CONTEXT为实现压栈的宏,其中首先切换到了SYS模式,然后将必要的寄存器,中断嵌套层数(ulCriticalNestingConst)等全部入栈保存。
其中portRESTORE_CONTEXT为实现压栈的宏,其中过程与portSTORE_CONTEXT()刚好相反,但是由于OS提供的vTaskSwitchContextConst()中已经改变了当前OS执行TASK信息(pxCurrentTCBConst),因此出栈后切换到到了另外一TASK。
中断控制
如之前所属,OS基于中断实现了临界区和主动触发TASK切换的功能,它们以宏的方式定义,名称如下,
freeRTOS官网上提供了相关代码,非常简单易懂,这里就不在累述。