笔记内容参考(正点原子的FreeRTOS开发手册、cortex-m3权威指南、Cortex-M3和Cortex-M4权威指南等)
文中stm32指的是F1及F4
1、中断配置宏
STM32使用FreeRTOS,须将优先级分组设为组4(4位全部是抢占优先级),所以就有(0-15)16个优先级。且优先级数字越小,优先级越高。
1.1 configPRIO_BITS
设置MCU使用几位作为优先级配置,定义优先级的寄存器有8位,但STM32只使用了高4位做为优先级配置,所以此宏定义为4
1.2 configLIBRARY_LOWEST_INTERRUPT_PRIORITY
设置最低优先级15
1.3 configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY
定义了受FreeRTOS管理的最高优先级中断。简单的说就是允许用户在这个中断服务程序里面调用FreeRTOS的API的最高优先级。设置NVIC的优先级分组为4的情况下。配置configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY为5,表示用户可以在抢占式优先级为5-15的中断里面调用FreeRTOS的API函数,抢占式优先级为0-4的中断里面是不允许调用的。不受FreeRTOS管理的中断有什么深层的含义吗?
讲解不受FreeRTOS管理的中断之前要说一个小知识点----中断延迟。中断延迟时间是衡量RTOS实时操作系统的一项重要指标,那什么又是中断延迟呢?从中断触发到执行中断服务程序的第一条指令这段时间就是中断延迟时间。
FreeRTOS内核源码中有多处开关全局中断的地方,这些开关全局中断会加大中断延迟时间。比如在源码的某个地方关闭了全局中断,但是此时有外部中断触发,这个中断的服务程序就需要等到再次开启全局中断后才可以得到执行。开关中断之间的时间越长,中断延迟时间就越大,这样极其影响系统的实时性。如果这是一个紧急的中断事件,得不到及时执行的话,后果是可想而知的。
针对这种情况,FreeRTOS就专门做了一种新的开关中断实现机制。关闭中断时仅关闭受FreeRTOS管理的中断,不受FreeRTOS管理的中断不关闭,这些不受管理的中断都是高优先级的中断,用户可以在这些中断里面加入需要实时响应的程序。FreeRTOS能够实现这种功能的奥秘就在于FreeRTOS开关中断使用的是寄存器BASEPRI,这个在下面的链接记录(2.3.1 PRIMASK, FAULTMASK 和 BASEPRI)
2、配置Pendsv和Systick优先级
设置Pendsv和Systick优先级为最低优先级(优先级0-15,数字越大优先级越高,所以在此设置优先级为15),为什么要设置最低,因为任务切换就是在PendSV中运行,为了让其他中断能够及时的运行,为什么要在PendSV中切换任务。
这个涉及到了任务切换,在其他博客记录。
在任务调度器开始函数vTaskStartScheduler() 里面有接口xPortStartScheduler(),用来初始化与调度器相关的硬件(比如滴答定时器、FPU单元[浮点运算]、PendSV中断)
//代码缩减后
void vTaskStartScheduler( void )
{
if( xPortStartScheduler() != pdFALSE )
}
/*
* See header file for description.
*/
BaseType_t xPortStartScheduler( void )
{
/* Make PendSV and SysTick the lowest priority interrupts. */
portNVIC_SYSPRI2_REG |= portNVIC_PENDSV_PRI;
portNVIC_SYSPRI2_REG |= portNVIC_SYSTICK_PRI;
}
/*-----------------------------------------------------------*/
设置PENDSV_PRI和SYSTICK_PRI优先级是向portNVIC_SYSPRI2_REG写数据
#define portNVIC_SYSPRI2_REG ( * ( ( volatile uint32_t * ) 0xe000ed20 ) )
4 个相临的优先级寄存器(8位)拼成一个 32 位寄存器。所以上面就是直接对0xE000_ED20进行写设置PendSV和Systick优先级
#define portNVIC_PENDSV_PRI ( ( ( uint32_t ) configKERNEL_INTERRUPT_PRIORITY ) << 16UL )
#define portNVIC_SYSTICK_PRI ( ( ( uint32_t ) configKERNEL_INTERRUPT_PRIORITY ) << 24UL )
这里的configKERNEL_INTERRUPT_PRIORITY分别左移16和24,因为这是由4个相邻的寄存器拼接成一个32位寄存器,所以左移16位设置PendSV,左移24设置Systick。
/* Interrupt priorities used by the kernel port layer itself. These are generic
to all Cortex-M ports, and do not rely on any particular library functions. */
#define configKERNEL_INTERRUPT_PRIORITY ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
configKERNEL_INTERRUPT_PRIORITY是实际写入寄存器的数,因为不可能将configLIBRARY_LOWEST_INTERRUPT_PRIORITY(15)直接写入寄存器,所以需要转换,因为STM32使用了高四位作为优先级,所以需要将15左移4位才是真正的优先级。(8 - configPRIO_BITS) 就是4。
2.1 硬件调试查看Pendsv和Systick优先级
在进入调试后全速运行,选择外设-> 内核外设 -> NVIC
这里pendsv和systick的优先级都是15,即最低优先级,240是15左移4位构成的,因为定义优先级的寄存器是8位,而STM32使用高四位作为优先级配置,所以15左移4位
3、用于中断屏蔽的特殊寄存器
PRIMASK, FAULTMASK 和 BASEPRI这三个寄存器,可以参考上面链接【Cortex-M3笔记_基础】,大致了解这三个中断屏蔽寄存器。BASEPRI寄存器可以只屏蔽低于某一阈值的优先级中断,FreeRTOS的开关中断就是通过BASEPRI这个寄存器实现。
想屏蔽某一阈值之下的优先级,直接将优先级写进寄存器即可,写入0就停止屏蔽中断
4、FreeRTOS开关中断
开中断vPortRaiseBASEPRI,关中断vPortSetBASEPRI,关中断写0
static portFORCE_INLINE void vPortRaiseBASEPRI( void )
{
uint32_t ulNewBASEPRI = configMAX_SYSCALL_INTERRUPT_PRIORITY;
__asm
{
/* Set BASEPRI to the max syscall priority to effect a critical
section. */
msr basepri, ulNewBASEPRI
dsb
isb
}
}
static portFORCE_INLINE void vPortSetBASEPRI( uint32_t ulBASEPRI )
{
__asm
{
/* Barrier instructions are not used as this function is only used to
lower the BASEPRI value. */
msr basepri, ulBASEPRI
}
}
这里的configMAX_SYSCALL_INTERRUPT_PRIORITY定义如下
/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!!
See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */
#define configMAX_SYSCALL_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
/* The highest interrupt priority that can be used by any interrupt service
routine that makes calls to interrupt safe FreeRTOS API functions. DO NOT CALL
INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER
PRIORITY THAN THIS! (higher priorities are lower numeric values. */
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5
相关宏定义在上面。