完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
本章节为大家讲解FreeRTOS中断优先级配置,此章节非常重要,初学者经常在这里犯迷糊。对于初学者来说,本章节务必要整明白。
12.1 NVIC基础知识 12.2 使用FreeRTOS时如何配置外设NVIC 12.3 FreeRTOS配置选项中NVIC相关配置 12.4 不受FreeRTOS管理中的的深入讨论 12.5总结 12.1 NVIC基础知识 NVIC的全称是Nested vectoredinterrupt controller,即嵌套向量中断控制器。 对于M3和M4内核的MCU,每个中断的优先级都是用寄存器中的8位来设置的。8位的话就可以设置2^8 =256级中断,实际中用不了这么多,所以芯片厂商根据自己生产的芯片做出了调整。比如ST的STM32F1xx和F4xx只使用了这个8位中的高四位[7:4],低四位取零,这样2^4=16,只能表示16级中断嵌套。 对于这个NVIC,有个重要的知识点就是优先级分组,抢占优先级和子优先级,下面就以STM32为例进行介绍,STM32F1xx和F4xx都是只使用了这个8位寄存器的高四位[7:4]。 图12.1 优先级分组 |
|
相关推荐
|
|
从上面的表格可以看出,STM32支持5种优先级分组,系统上电复位后,默认使用的是优先级分组0,也就是没有抢占式优先级,只有子优先级,关于这个抢占优先级和这个子优先级有几点一定要说清楚。
l 具有高抢占式优先级的中断可以在具有低抢占式优先级的中断服务程序执行过程中被响应,即中断嵌套,或者说高抢占式优先级的中断可以抢占低抢占式优先级的中断的执行。 l 在抢占式优先级相同的情况下,有几个子优先级不同的中断同时到来,那么高子优先级的中断优先被响应。 l 在抢占式优先级相同的情况下,如果有低子优先级中断正在执行,高子优先级的中断要等待已被响应的低子优先级中断执行结束后才能得到响应,即子优先级不支持中断嵌套。 l Reset、NMI、Hard Fault 优先级为负数,高于普通中断优先级,且优先级不可配置。 l 对于初学者还有一个比较纠结的问题就是系统中断(比如:PendSV,SVC,SysTick)是不是一定比外部中断(比如SPI,USART)要高,答案:不是的,它们是在同一个NVIC下面设置的。 掌握了这些基础知识基本就够用了。另外特别注意一点,配置抢占优先级和子优先级,他们合并成的4bit数字的数值越小,优先级越高,这一点千万不要搞错了,下面通过12.2小节举一个实例。 |
|
|
|
|
|
12.2 使用FreeRTOS时如何配置外设NVIC
强烈推荐用户将Cortex-M3内核的STM32F103和Cortex-M4内核的STM32F407以及STM32F429的NVIC优先级分组设置为4,即:NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);这样中断优先级的管理将非常方便。这个也是官方强烈建议的。此函数在bsp_Init中第一个被调用: /* ********************************************************************************************************* * 函 数 名: bsp_Init * 功能说明: 初始化硬件设备。只需要调用一次。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。 * 全局变量。 * 形 参: 无 * 返 回 值: 无 ********************************************************************************************************* */ void bsp_Init(void) { /* 优先级分组设置为4, 优先配置好NVIC */ NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4); bsp_InitUart(); /* 初始化串口 */ bsp_InitLed(); /* 初始LED指示灯端口 */ bsp_InitKey(); /* 初始化按键 */ } |
|
|
|
|
|
(注意:一旦初始化好NVIC的优先级分组后,切不可以在应用中再次更改。)
设置NVIC的优先级分组为4表示支持0-15级抢占优先级(注意,0-15级是16个级别,包含0级),不支持子优先级。反映在STM32标准库的配置上就是如下: /* ********************************************************************************************************* * 函 数 名: TIM_Config * 功能说明: 配置定时器TIM2的中断 * 形 参:无 * 返 回 值: 无 ********************************************************************************************************* */ static void TIM_Config(void) { NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; /* 抢占优先级设置,优先级分组为4的情况下,抢占优先级可设置范围0-15 */ NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; /* 子优先级设置,优先级分组为4的情况下,子优先级无效,取数值0即可 */ NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); } |
|
|
|
|
|
12.3 FreeRTOS配置选项中NVIC相关配置
FreeRTOSConfig.h配置文件中设置到NVIC中断的有如下几个选项: /* Cortex-M specific definitions. */ #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 /* The lowest interrupt priority that can be used in a call to a "set priority" function. */ #define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 0x0f /* 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 0x01 /* 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) ) /* !!!! 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) ) |
|
|
|
|
|
u #define configPRIO_BITS 4
此宏定义用于配置STM32的8位优先级设置寄存器实际使用的位数。STM32F103,STM32F407和STM32F429都是使用的4位。另外注意一点,这里使用了一个条件编译,用户可以选择将条件编译删掉,直接定义一个#defineconfigPRIO_BITS 4即可。使用条件编译的好处就是方便与系统统一。这个__NVIC_PRIO_BITS在STM32F103标准库的头文件stm32f10x.h中以及STM32F407/439的标准库的头文件stm32f4xx.h中分别有定义。如果用户在FreeRTOSConfig.h文件里面包含了这个标准库的头文件,那么就会执行条件编译选项: #define configPRIO_BITS __NVIC_PRIO_BITS l __NVIC_PRIO_BITS 关于这个__NVIC_PRIO_BITS有必要跟大家深入的说明下,我们要刨根问底。在CMSIS软件包的M3内核头文件core_cm3.h和M4内核的头文件core_cm4.h文件里面已经进行了定义: #ifndef __NVIC_PRIO_BITS #define __NVIC_PRIO_BITS 4U #endif 也就是说,如果用户没有定义的话,这里的定义就会起作用。而STM32F103标准库的头文件stm32f10x.h和STM32F407/439的标准库的头文件stm32f4xx.h有定义了,而且相应的头文件core_cm3.h和core_cm4.h是放在了宏定义#define __NVIC_PRIO_BITS 4的后面,如此一来,头文件core_cm3.h和core_cm4.h的定义就会被屏蔽掉。STM32F103标准库的头文件stm32f10x.h和STM32F407/439的标准库的头文件stm32f4xx.h里面的定义是有效的。 u #define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 0x0f 此宏定义是用来配置FreeRTOS用到的SysTick中断和PendSV中断的优先级。在NVIC分组设置为4的情况下,此宏定义的范围就是0-15,即专门配置抢占优先级。这里配置为了0x0f,即SysTick和PendSV都是配置为了最低优先级,实际项目中也建议大家配置最低优先级即可。 |
|
|
|
|
|
l SVC中断
在FreeRTOS的移植文件ports.c中有用到SVC中断的0号系统服务,即SVC 0。此中断在FreeRTOS中仅执行一次,用于启动第一个要执行的任务。另外,由于FreeRTOS没有配置SVC的中断优先级,默认没有配置的情况下,SVC中断的优先级就是最高的0。如果用户在不清楚自己配置的PendSV和SysTick中断是否跟实际情况一致时,可以进行硬件调试。比如MDK,我们可以在硬件调试的状态下,先点击全速运行,然后查看如下调试组件: 打开后可以看到如下状态,其中SysTick和PendSV中断的优先级240就是0x0f左移4位的结果。这里为什么要左移四位呢,前面我们已经多次强调了,STM32的优先级设置仅使用高4位。而SVC的优先级就是0,可以理解为0左移4位还是0。 |
|
|
|
|
|
u #define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 0x01
此宏定义比较重要,定义了受FreeRTOS管理的最高优先级中断。简单的说就是允许用户在这个中断服务程序里面调用FreeRTOS的API的最高优先级。设置NVIC的优先级分组为4的情况下。配置configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY为0x01表示用户可以在抢占式优先级为1到15的中断里面调用FreeRTOS的API函数,抢占式优先级为0的中断里面是不允许调用的。不受FreeRTOS管理的中断有什么深层的含义吗?且看12.4小节继续为大家讲解。 u #define configKERNEL_INTERRUPT_PRIORITY 宏定义configLIBRARY_LOWEST_INTERRUPT_PRIORITY的数值经过4bit偏移后得到一个8bit的优先级数值,即宏定义configKERNEL_INTERRUPT_PRIORITY的数值。这个8bit的数值才可以实际赋值给相应中断的优先级寄存器。 也许初学者有疑问了,为什么前面NVIC配置的时候不是8bit的方式进行配置?这是因为ST的库函数NVIC_Init()已经为我们做好了。这里的宏定义数值是供PendSV和SysTick中断进行优先级配置的。比如:我们这里配置宏定义configLIBRARY_LOWEST_INTERRUPT_PRIORITY是0x0f,经过4bit偏移后就是0xf0,即SysTick和PendSV的中断优先级就是240。 u #define configMAX_SYSCALL_INTERRUPT_PRIORITY 宏定义configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY的数值经过4bit偏移后得到一个8bit的优先级数值,即宏定义configMAX_SYSCALL_INTERRUPT_PRIORITY的数值。这个数值是赋值给寄存器basepri使用的,8bit的数值才可以实际赋值给相应中断的优先级寄存器。 这里的宏定义数值赋给寄存器basepri后就可以实现全局的开关中断操作了。比如:我们这里配置宏定义configLIBRARY_LOWEST_INTERRUPT_PRIORITY是0x01,经过4bit偏移后就是0x10,即16。调用了FreeRTOS的关中断后,所有优先级数值大于等于16的中断都会被关闭。优先级数值小于16的中断不会被关闭,对寄存器basepri寄存器赋值0,那么被关闭的中断会被打开。 |
|
|
|
|
|
12.4 不受FreeRTOS管理中断的深入讨论
讲解不受FreeRTOS管理的中断之前要说一个小知识点----中断延迟。中断延迟时间是衡量RTOS实时操作系统的一项重要指标,那什么又是中断延迟呢?从中断触发到执行中断服务程序的第一条指令这段时间就是中断延迟时间。 FreeRTOS内核源码中有多处开关全局中断的地方,这些开关全局中断会加大中断延迟时间。比如在源码的某个地方关闭了全局中断,但是此时有外部中断触发,这个中断的服务程序就需要等到再次开启全局中断后才可以得到执行。开关中断之间的时间越长,中断延迟时间就越大,这样极其影响系统的实时性。如果这是一个紧急的中断事件,得不到及时执行的话,后果是可想而知的。 针对这种情况,FreeRTOS就专门做了一种新的开关中断实现机制。关闭中断时仅关闭受FreeRTOS管理的中断,不受FreeRTOS管理的中断不关闭,这些不受管理的中断都是高优先级的中断,用户可以在这些中断里面加入需要实时响应的程序。FreeRTOS能够实现这种功能的奥秘就在于FreeRTOS开关中断使用的是寄存器basepri,而像uCOS这种使用的是primask,详情请看下面整理的表格: 对寄存器basepri我们举一个例子,帮助大家理解,比我们配置寄存器basepri的数值为16,所有优先级数值大于等于16的中断都会被关闭,优先级数值小于16的中断不会被关闭。对寄存器basepri寄存器赋值0,那么被关闭的中断会被打开。这个就是FreeRTOS开关中断的实现方案。 |
|
|
|
|
|
12.5 总结
本章节为大家讲解FreeRTOS中断优先级配置,内容相比前面章节要复杂些,不知道大家是否已经理解透彻了?如果没有理解透彻,务必多读几遍,直到完全弄明白。 |
|
|
|
|
|
386 浏览 0 评论
求助一下关于51系列单片机的Timer0的计时问题,TH0、TL0+1的时间是怎么算的?
1670 浏览 1 评论
【RA-Eco-RA4E2-64PIN-V1.0开发板试用】开箱+Keil环境搭建+点灯+点亮OLED
1123 浏览 0 评论
【敏矽微ME32G070开发板免费体验】使用coremark测试敏矽微ME32G070 跑分
1005 浏览 0 评论
【敏矽微ME32G070开发板免费体验】开箱+点灯+点亮OLED
1229 浏览 2 评论
【youyeetoo X1 windows 开发板体验】少儿AI智能STEAM积木平台
12017 浏览 31 评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-23 10:26 , Processed in 0.762872 second(s), Total 83, Slave 66 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号