打印
[其他ST产品]

FreeRTOS 在STM32上的移植 V1.0

[复制链接]
374|10
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主

FreeRTOS作为开源的轻量级实时性操作系统,不仅实现了基本的实时调度、信号量、队列和存储管理,而且在商业应用上不需要授权费。
        FreeRTOS的实现主要由list.c、queue.c、croutine.c和tasks.c 4个文件组成。list.c 是一个链表的实现,主要供给内核调度器使用;queue.c 是一个队列的实现,支持中断环境和信号量控制;croutine.c 和task.c是两种任务的组织实现。对于croutine,各任务共享同一个堆栈,使RAM的需求进一步缩小,但也正因如此,他的使用受到相对严格的限制。而task则是传统的实现,各任务使用各自的堆栈,支持完全的抢占式调度。
         FreeRTOS的主要功能可以归结为以下几点:
                    1) 优先级调度、相同优先级任务的轮转调度,同时可设成可剥夺内核或不可剥夺内核
                    2) 任务可选择是否共享堆栈(co-routines & tasks),并且没有任务数限制
                    3) 消息队列,二值信号量,计数信号量,递归互斥体
                    4) 时间管理
                    5) 内存管理
         与UC/OSII一样,FreeRTOS在STM32的移植大致由3个文件实现,一个.h文件定义编译器相关的数据类型和中断处理的宏定义;一个.c文件实现任务的堆栈初始化、系统心跳的管理和任务切换的请求;一个.s文件实现具体的任务切换。
        在本次移植中,使用的编译软件为IAR EWARM 5.2。


使用特权

评论回复
沙发
花间一壶酒sd|  楼主 | 2021-3-31 23:53 | 只看该作者
一、各文件关键部分的实现:



1、PORTMACRO.H  宏定义部分
1)定义编译器相关的各种数据类型
#define portCHAR  char
#define portFLOAT  float
#define portDOUBLE  double
#define portLONG  long
#define portSHORT  short
#define portSTACK_TYPE unsigned portLONG
#define portBASE_TYPE long

使用特权

评论回复
板凳
花间一壶酒sd|  楼主 | 2021-3-31 23:53 | 只看该作者
2)架构相关的定义
Cortex-M3的堆栈增长方向为高地址向低地址增长
#define portSTACK_GROWTH ( -1 )
每毫秒的心跳次数
#define portTICK_RATE_MS ( ( portTickType ) 1000 / configTICK_RATE_HZ )
访问SRAM的字节对齐
#define portBYTE_ALIGNMENT 8

使用特权

评论回复
地板
花间一壶酒sd|  楼主 | 2021-3-31 23:54 | 只看该作者
3)定义用户主动引起内核调度的2个函数
强制上下文切换,用在任务环境中调用
#define portYIELD()  vPortYieldFromISR()
强制上下文切换,用在中断处理环境中调用
#define portEND_SWITCHING_ISR( xSwitchRequired )  if( xSwitchRequired ) vPortYieldFromISR()

使用特权

评论回复
5
花间一壶酒sd|  楼主 | 2021-3-31 23:55 | 只看该作者
4)定义临界区的管理函数
中断允许和关闭
#define portDISABLE_INTERRUPTS() vPortSetInterruptMask()
#define portENABLE_INTERRUPTS()  vPortClearInterruptMask()
临界区进入和退出
#define portENTER_CRITICAL()  vPortEnterCritical()
#define portEXIT_CRITICAL()  vPortExitCritical()
用于在中断环境的中断允许和关闭
#define portSET_INTERRUPT_MASK_FROM_ISR()  0;vPortSetInterruptMask()
#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) vPortClearInterruptMask();(void)x

使用特权

评论回复
6
花间一壶酒sd|  楼主 | 2021-3-31 23:56 | 只看该作者

FreeRTOS作为开源的轻量级实时性操作系统,不仅实现了基本的实时调度、信号量、队列和存储管理,而且在商业应用上不需要授权费。
        FreeRTOS的实现主要由list.c、queue.c、croutine.c和tasks.c 4个文件组成。list.c 是一个链表的实现,主要供给内核调度器使用;queue.c 是一个队列的实现,支持中断环境和信号量控制;croutine.c 和task.c是两种任务的组织实现。对于croutine,各任务共享同一个堆栈,使RAM的需求进一步缩小,但也正因如此,他的使用受到相对严格的限制。而task则是传统的实现,各任务使用各自的堆栈,支持完全的抢占式调度。

         FreeRTOS的主要功能可以归结为以下几点:
                    1) 优先级调度、相同优先级任务的轮转调度,同时可设成可剥夺内核或不可剥夺内核
                    2) 任务可选择是否共享堆栈(co-routines & tasks),并且没有任务数限制
                    3) 消息队列,二值信号量,计数信号量,递归互斥体
                    4) 时间管理
                    5) 内存管理

         与UC/OSII一样,FreeRTOS在STM32的移植大致由3个文件实现,一个.h文件定义编译器相关的数据类型和中断处理的宏定义;一个.c文件实现任务的堆栈初始化、系统心跳的管理和任务切换的请求;一个.s文件实现具体的任务切换。

        在本次移植中,使用的编译软件为IAR EWARM 5.2。
一、各文件关键部分的实现:



1、PORTMACRO.H  宏定义部分
1)定义编译器相关的各种数据类型
#define portCHAR  char
#define portFLOAT  float
#define portDOUBLE  double
#define portLONG  long
#define portSHORT  short
#define portSTACK_TYPE unsigned portLONG
#define portBASE_TYPE long

2)架构相关的定义
Cortex-M3的堆栈增长方向为高地址向低地址增长
#define portSTACK_GROWTH ( -1 )
每毫秒的心跳次数
#define portTICK_RATE_MS ( ( portTickType ) 1000 / configTICK_RATE_HZ )
访问SRAM的字节对齐
#define portBYTE_ALIGNMENT 8

3)定义用户主动引起内核调度的2个函数
强制上下文切换,用在任务环境中调用
#define portYIELD()  vPortYieldFromISR()
强制上下文切换,用在中断处理环境中调用
#define portEND_SWITCHING_ISR( xSwitchRequired )  if( xSwitchRequired ) vPortYieldFromISR()

4)定义临界区的管理函数
中断允许和关闭
#define portDISABLE_INTERRUPTS() vPortSetInterruptMask()
#define portENABLE_INTERRUPTS()  vPortClearInterruptMask()
临界区进入和退出
#define portENTER_CRITICAL()  vPortEnterCritical()
#define portEXIT_CRITICAL()  vPortExitCritical()
用于在中断环境的中断允许和关闭
#define portSET_INTERRUPT_MASK_FROM_ISR()  0;vPortSetInterruptMask()
#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) vPortClearInterruptMask();(void)x

2、PORT.C  C接口部分
1)堆栈初始化
portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE pxCode, void *pvParameters )
{
*pxTopOfStack = portINITIAL_XPSR; /* 程序状态寄存器 */
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) pxCode; /* 任务的入口点 */
pxTopOfStack--;
*pxTopOfStack = 0; /* LR */
pxTopOfStack -= 5; /* R12, R3, R2 and R1. */
*pxTopOfStack = ( portSTACK_TYPE ) pvParameters; /* 任务的参数 */
pxTopOfStack -= 8; /* R11, R10, R9, R8, R7, R6, R5 and R4. */
return pxTopOfStack;
}

使用特权

评论回复
7
花间一壶酒sd|  楼主 | 2021-3-31 23:57 | 只看该作者
2)启动任务调度
portBASE_TYPE xPortStartScheduler( void )
{
让任务切换中断和心跳中断位于最低的优先级,使更高优先级可以抢占mcu
*(portNVIC_SYSPRI2) |= portNVIC_PENDSV_PRI;
*(portNVIC_SYSPRI2) |= portNVIC_SYSTICK_PRI;

设置并启动系统的心跳时钟
prvSetupTimerInterrupt();

初始化临界区的嵌套的个数
uxCriticalNesting = 0;

启动第一个任务
vPortStartFirstTask();

执行到vPortStartFirstTask函数,内核已经开始正常的调度
return 0;
}

使用特权

评论回复
8
花间一壶酒sd|  楼主 | 2021-3-31 23:58 | 只看该作者
3)主动释放mcu使用权
void vPortYieldFromISR( void )
{
触发PendSV系统服务中断,中断到来时由汇编函数xPortPendSVHandler()处理
*(portNVIC_INT_CTRL) = portNVIC_PENDSVSET;
}
进入临界区时,首先关闭中断;当退出所以嵌套的临界区后再使能中断
void vPortEnterCritical( void )
{
portDISABLE_INTERRUPTS();
uxCriticalNesting++;
}
void vPortExitCritical( void )
{
uxCriticalNesting--;
if( uxCriticalNesting == 0 )
{
  portENABLE_INTERRUPTS();
}
}

使用特权

评论回复
9
花间一壶酒sd|  楼主 | 2021-3-31 23:59 | 只看该作者
4)心跳时钟处理函数
void xPortSysTickHandler( void )
{
unsigned portLONG ulDummy;

如果是抢占式调度,首先看一下有没有需要调度的任务
#if configUSE_PREEMPTION == 1
  *(portNVIC_INT_CTRL) = portNVIC_PENDSVSET;
#endif

ulDummy = portSET_INTERRUPT_MASK_FROM_ISR();
{ 通过task.c的心跳处理函数vTaskIncrementTick(),进行时钟计数和延时任务的处理
  vTaskIncrementTick();
}
portCLEAR_INTERRUPT_MASK_FROM_ISR( ulDummy );
}

使用特权

评论回复
10
花间一壶酒sd|  楼主 | 2021-3-31 23:59 | 只看该作者
3、PORTASM.S  汇编处理部分
1)请求切换任务
xPortPendSVHandler:
保存当前任务的上下文到其任务控制块
mrs r0, psp  
ldr r3, =pxCurrentTCB 获取当前任务的任务控制块指针
ldr r2, [r3]      

stmdb r0!, {r4-r11}  保存R4-R11到该任务的堆栈
str r0, [r2]   将最后的堆栈指针保存到任务控制块的pxTopOfStack

stmdb sp!, {r3, r14}
关闭中断
mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY
msr basepri, r0
切换任务的上下文,pxCurrentTCB已指向新的任务

bl vTaskSwitchContext
mov r0, #0
msr basepri, r0
ldmia sp!, {r3, r14}
恢复新任务的上下文到各寄存器
ldr r1, [r3]     
ldr r0, [r1]    /* The first item in pxCurrentTCB is the task top of stack. */
ldmia r0!, {r4-r11}   /* Pop the registers. */
msr psp, r0      
bx r14

使用特权

评论回复
11
zhengfish| | 2021-4-1 07:45 | 只看该作者
这壶酒不错

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

84

主题

1129

帖子

2

粉丝