文章目录
上一文链接:FreeRTOS笔记(二)移植STM32F407
01 - FreeRTOS内核剪裁
1.1 - FreeRTOSConfig.h文件
在上一文中,针对官方给出的STM32F407例程Demo,很容易移植了FreeRTOS到STM32F407上并成功运行。容易的原因是官方Demo中对FreeRTOS内核的配置已经完全对应了STM32F407的硬件配置,配置文件就是FreeRTOSConfig.h。
打开官方的API手册,可以看到,第7章就是内核配置文件的描述:
能够看到,FreeRTOSConfig.h其实就是对内核进行剪裁的配置文件,主体宏分为两部分,一部分是前缀为INCLUER_的宏,另一部分是前缀为config的宏,它们的用处文档有很详细的结束,小白简单总结如下:
1.2 - FreeRTOSConfig.h内容
在FreeRTOSConfig.h中,我们暂时只关心一些常用内容的配置,根据官方文档,能够知道config前缀宏的映射内容,下面是部分的注释:
#define configUSE_PREEMPTION 1 //0-协程调度,1-抢占式调度
#define configUSE_IDLE_HOOK 0 //0-除能空闲任务的钩子函数,1-使能
#define configUSE_TICK_HOOK 0 //0-除能时间片钩子函数,1-使能
#define configCPU_CLOCK_HZ ( SystemCoreClock ) //设置CPU频率
#define configTICK_RATE_HZ ( ( TickType_t ) 1000 ) //设置滴答计时器的中断频率,为HZ/1000=1ms
#define configMAX_PRIORITIES ( 5 ) //任务优先级是0~(configMAX_PRIORITIES-1)
#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 130 ) //设置空闲任务的堆栈大小,单位是字(4字节)
#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 75 * 1024 ) ) //设置系统总堆栈大小
#define configMAX_TASK_NAME_LEN ( 10 ) //设置任务名最大长度
#define configUSE_TRACE_FACILITY 1 //0-除能可视化跟踪调试,1-使能
#define configUSE_16_BIT_TICKS 0 //节拍计时器变量范围,0-16位,1-32位
#define configIDLE_SHOULD_YIELD 1 //0-空闲任务不会让出CPU给同等优先级的任务,1-会让出CPU
#define configUSE_MUTEXES 1 //0-除能互斥信号量,1-使能
#define configQUEUE_REGISTRY_SIZE 8 //0-除能内核调试中查看队列和信号量数量,>0-可以注册的数量
#define configCHECK_FOR_STACK_OVERFLOW 0 //0-除能堆栈溢出检测,1-使能
#define configUSE_RECURSIVE_MUTEXES 1 //0-除能递归互斥信号量,1-使能
#define configUSE_MALLOC_FAILED_HOOK 0 //0-除能malloc失败时调用的钩子函数,1-使能
#define configUSE_APPLICATION_TASK_TAG 0 //0-除能一些应用程序钩子函数,1-使能
#define configUSE_COUNTING_SEMAPHORES 1 //0-除能计数信号量,1-使能
#define configGENERATE_RUN_TIME_STATS 0 //0-除能时间统计功能,1-使能
……
//硬件相关的中断位数
#ifdef __NVIC_PRIO_BITS
/* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */
#define configPRIO_BITS __NVIC_PRIO_BITS
#else
#define configPRIO_BITS 4 /* 15 priority levels */
#endif
//最低优先级,一般与configPRIO_BITS对应,2^configPRIO_BITS-1
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 0xf
//可管理的最大优先级(设置STM的BASEPRI寄存器)
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5
//真正的中断优先级,用于设置滴答中断等等的优先级
#define configKERNEL_INTERRUPT_PRIORITY ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
//真正的中断优先级,最大可以使用FreeRTOS-API的中断优先级
#define configMAX_SYSCALL_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
FreeRTOSConfig.h前部分是一些CPU、调度算法等配置,后部分是中断配置。能够清晰观测到,只有配置了例如CPU频率、滴答时钟频率等等的硬件相关内容才能成功移植,而其它的一些例如信号量、钩子函数等等的内容是根据实际情况而定的。
前部分的内容是硬件能运行的基本配置,而后部分的中断配置是实时嵌入式系统的需求配置,中断配置内存如下:
-
FreeRTOS中断配置
- 1、 确定逻辑上表达中断优先级数量的寄存器位数: STM32F407为4位,共16个优先级
- 2、 确定逻辑上最低优先级: STMF407为2^4 - 1 = 15
- 3、 确定逻辑上FreeRTOS可管理的最大优先级: 设置为5,意味着优先级>=5的优先级不受FreeRTOS管理和处理
- 4、 确定寄存器上真正的最低优先级: STM使用寄存器的高位,摒弃低位,因此需要移位
- 5、 确定寄存器上FreeRTOS可管理的最大优先级: 需要移位
可管理的最大优先级描述如下:
02 - 测试剪裁内容
2.1 - 任务设计
在此我们测试FreeRTOSConfig.h中的中断配置,可管理的最大优先级为5,也就优先级<5的中断不归FreeRTOS管理,于是设计测试程序逻辑如下:
在上一文的工程中进行编程,先编写定时器代码,再编写任务代码。其中定时器使用通用定时器3和5,两者都是定时1s,唯一不同的是优先级,定时器3的优先级是4(超过了FreeRTOS管理的优先级),定时器5的优先级是6(可以被FreeRTOS管理)。
定时器配置代码区别的位置如下:
// 定时器3
……
NVIC_struct.NVIC_IRQChannel = TIM3_IRQn;
NVIC_struct.NVIC_IRQChannelPreemptionPriority = 0x04; //抢占优先级4
NVIC_struct.NVIC_IRQChannelSubPriority = 0x00;
NVIC_struct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_struct);
……
……
// 定时器5
NVIC_struct.NVIC_IRQChannel = TIM5_IRQn;
NVIC_struct.NVIC_IRQChannelPreemptionPriority = 0x06; //抢占优先级4
NVIC_struct.NVIC_IRQChannelSubPriority = 0x00;
NVIC_struct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_struct);
……
/* ----------------------------中断函数---------------------------*/
void TIM5_IRQHandler(void)
{
//溢出中断
if(TIM_GetITStatus(TIM5,TIM_IT_Update) == SET)
{
printf("timer5 with priority 6 \r\n");
}
TIM_ClearITPendingBit(TIM5,TIM_IT_Update);
}
void TIM3_IRQHandler(void)
{
//溢出中断
if(TIM_GetITStatus(TIM3,TIM_IT_Update) == SET)
{
printf("timer3 with priority 4 \r\n");
}
TIM_ClearITPendingBit(TIM3,TIM_IT_Update);
}
开关中断我们采用注释然后重新编辑的方式去实现,不能使用vTaskDelay()来进行间隔开关中断,因为vTaskDelay()会挂起调度器,导致不能进行任务切换,但是同时也开启了中断,不能起到关中断的作用。
/* Start 任务 */
void start_task(void *pParam)
{
//portDISABLE_INTERRUPTS();
for(;;)
{
portDISABLE_INTERRUPTS();
printf("satrt portDISABLE_INTERRUPTS()\r\n");
vTaskDelay(5000);
portENABLE_INTERRUPTS();
printf("satrt portENABLE_INTERRUPTS()\r\n");
vTaskDelay(5000);
}
}
2.2 - 测试结果
首先测试statr开中断(默认),运行结果如下,两个定时器都在相继输出
然后是关闭中断,运行结果如下。只有time3在输出,因为time3优先级为4,超出了FreeRTOS配置的最大可管理优先级5,所有timer3不受管理,而time5优先级是6,在FreeRTOS中断管理优先级内,于是timer5被关闭。
03 - 总结
- FreeRTOS内核剪裁配置文件是FreeRTOSConfig.h
- FreeRTOSConfig.h前部分是一些CPU、调度算法等配置,后部分是中断配置
- FreeRTOSConfig.h的中断配置使得FreeRTOS系统可以理会和不理会某些中断