该函数的作用
用于设置NVIC优先级分组,分配抢占优先级和响应优先级各自所占的比例。
优先级的基本定义
- 在 Cortex-M3(CM3)中,优先级对于异常来说很关键的,它会影响一个异常是否能被响应,以及何时可以响应。
- 优先级的数值越小,则优先级越高。
- CM3 支持中断嵌套,使得高优先级异常会抢占(preempt)低优先级异常。
- 有 3 个系统异常:复位,NMI 以及硬 fault,它们有固定的优先级,并且它们的优先级号是负数,从而高于所有其它异常。
- CM3 支持 3 个固定的高优先级和多达 256 级的可编程优先级,并且支持 128级抢占,但是绝大多数芯片在设计时会裁掉表达优先级的几个低端有效位,以达到减少优先级数的目的。
为什么要设置抢占优先级和响应优先级
为了使抢占机能变得更可控,CM3把 256 级优先级按位分成高低两段,即抢占优先级和亚优先级。 函数代码理解void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup) { /* Check the parameters */ assert_param(IS_NVIC_PRIORITY_GROUP(NVIC_PriorityGroup)); /* Set the PRIGROUP[10:8] bits according to NVIC_PriorityGroup value */ SCB->AIRCR = AIRCR_VECTKEY_MASK | NVIC_PriorityGroup; }
在这个函数中,我们需要选择NVIC分组类型作为参数进入该函数,该参数在misc.h文件中有定义
可见共有4bit用于设置优先级分组,而不同的分组类型决定抢占优先级和响应优先级各自所占的bit比例。如果各占2bit,那么抢占优先级和响应优先级就各有2²=4的优先级值。
看回到函数第一行代码
assert_param(IS_NVIC_PRIORITY_GROUP(NVIC_PriorityGroup));
该函数用于判断用户输入的参数是否有错。在misc.h文件中有一个带参宏定义。
#define IS_NVIC_PRIORITY_GROUP(GROUP) (((GROUP) == NVIC_PriorityGroup_0) || \ ((GROUP) == NVIC_PriorityGroup_1) || \ ((GROUP) == NVIC_PriorityGroup_2) || \ ((GROUP) == NVIC_PriorityGroup_3) || \ ((GROUP) == NVIC_PriorityGroup_4))
如果参数正确则会返回true值。我们再看到以下代码
#ifdef USE_FULL_ASSERT /** * @brief The assert_param macro is used for function's parameters check. * @param expr: If expr is false, it calls assert_failed function which reports * the name of the source file and the source line number of the call * that failed. If expr is true, it returns no value. * @retval None */ #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__)) /* Exported functions ------------------------------------------------------- */ void assert_failed(uint8_t* file, uint32_t line); #else #define assert_param(expr) ((void)0) #endif /* USE_FULL_ASSERT */ #endif /* __STM32F10x_CONF_H */
可以看到当定义USE_FULL_ASSERT时,当此前函数返回的值为true,则函数不执行任何操作,如果返回的值为false,则assert_failed()会报告错误文件和错误行。但在代码中能够发现assert_failed()仅仅是个框架,因此需要开发者自己编写。
通常USE_FULL_ASSERT是没有被定义的,那么该函数往往不会执行任何操作。
看到原函数第二行代码
SCB->AIRCR = AIRCR_VECTKEY_MASK | NVIC_PriorityGroup;
首先是执行了一次或运算,在头文件中有给出AIRCR_VECTKEY_MASK的值
#define AIRCR_VECTKEY_MASK ((uint32_t)0x05FA0000)
该函数用于配置AIRCR寄存器(应用程序中断及复位控制寄存器)。根据规定,任何对该寄存器的写操作都要把0x05FA写入31:16位段,否则该操作会被忽略。
同时我们也可以看到共有3bit用于配置优先级分组,具体值在头文件中宏定义的NVIC优先级分组给出。
其中SCB只是个结构体,在core_cm3.h中给出,里面定义了一些寄存器的数据类型。
最终加*问钥匙后,我们把值写入AIRCR寄存器,完成优先级分组的配置。
参考资料
Cortex-M3权威指南(中文)