这里以STM32F4-Cortex-M4内核为例,来记录下面这些配置是什么意思。
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 0xf
这个是内核优先级分组的位数,对于STM32F4来说,使用了4位来表示优先级。这里把优先级 设置到最低,主要是能够为了其它中断能够打断内核的中断(滴答,pendsv),以达到实时性
*/
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 2
上面的优先级说的意思就是,不要让抢占优先级大于configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY的中断调用rtos的api(_fromISR). 注意这里,在使用中断时,一定不要忘记配置中断优先级(默认为2),设置的优先级一定要小于这个值(数字要大于) 比如下面配置为2,那么优先级number小于2的,一定不要调用rtos api。如果调用了,rtos的一些状态就乱了(比如中断嵌套层数)系统就跑死掉了。
#define configKERNEL_INTERRUPT_PRIORITY ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
上面这个主要是为了获取到当前平台所支持的最小优先级。这里上面已经配置了configLIBRARY_LOWEST_INTERRUPT_PRIORITY 为0xf,因为configPRIO_BITS在cmisc中配置为4。所以这里是左移4.之所以减掉4,是为了获取剩余不用的位数。为什么要把kernel设置为最低优先级,这个我认为是为了确保系统实时性。因为已经有了pendsv中断,有些中断是能延迟响应的。
#define configMAX_SYSCALL_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
这个同上面一样,获取最大允许使用系统API的应用权限等级。目前configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 定义为2,则2<<(8-4) 即32.,只允许中断优先级大于2的中断调用系统API。
调度器代码记录:
BaseType_t xPortStartScheduler( void )
{
#if( configASSERT_DEFINED == 1 )
{
volatile uint32_t ulOriginalPriority;
volatile uint8_t * const pucFirstUserPriorityRegister = ( uint8_t * ) ( portNVIC_IP_REGISTERS_OFFSET_16 + portFIRST_USER_INTERRUPT_NUMBER );
volatile uint8_t ucMaxPriorityValue;
ulOriginalPriority = *pucFirstUserPriorityRegister;
*pucFirstUserPriorityRegister = portMAX_8_BIT_VALUE;
ucMaxPriorityValue = *pucFirstUserPriorityRegister;
LOGD("armwind:%x,%x",ucMaxPriorityValue, portMAX_8_BIT_VALUE);
configASSERT( ucMaxPriorityValue == ( configKERNEL_INTERRUPT_PRIORITY & ucMaxPriorityValue ) );
LOGD("ucMaxPriorityValue:%x,KER_INT:%x", ucMaxPriorityValue, configKERNEL_INTERRUPT_PRIORITY);
ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;
ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS;
while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
{
ulMaxPRIGROUPValue--;
ucMaxPriorityValue <<= ( uint8_t ) 0x01;
}
ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;
*pucFirstUserPriorityRegister = ulOriginalPriority;
}
#endif
portNVIC_SYSPRI2_REG |= portNVIC_PENDSV_PRI;
portNVIC_SYSPRI2_REG |= portNVIC_SYSTICK_PRI;
下面是我加的日志打印出来的,可以看到明明写入的是0xff,可是读过来的是0xf0,这也就是所使用4bit作为优先级
RTOS_CORE [D] xPortStartScheduler:369 armwind:f0,ff RTOS_CORE [D] xPortStartScheduler:373 ucMaxPriorityValue:f0,KER_INT:f0
上面可以看到最大的优先级分组为0x300,而且FREERTOS官网也建议将Cortex-M4优先级分组设置为Group4,即0x300。默认情况下如果不设置Group4,内核是跑不稳定的,一般是卡死了。这里我特意将stm32f4的中断优先级分组设置为Group3,档案是肯定的,内核卡死。来看一段日志
#if( configASSERT_DEFINED == 1 )
void vPortValidateInterruptPriority( void )
{
uint32_t ulCurrentInterrupt;
uint8_t ucCurrentPriority;
ulCurrentInterrupt = vPortGetIPSR();
LOGI("ulCurrentInterrupt:0x%d",ulCurrentInterrupt);
if( ulCurrentInterrupt >= portFIRST_USER_INTERRUPT_NUMBER )
{
ucCurrentPriority = pcInterruptPriorityRegisters[ ulCurrentInterrupt ];
LOGI("ucCurrentPriority:0x%x,ucMaxSysCallPriority:0x%x",ucCurrentPriority, ucMaxSysCallPriority);
LOGI("result:%d",ucCurrentPriority >= ucMaxSysCallPriority);
configASSERT( ucCurrentPriority >= ucMaxSysCallPriority );
}
configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue ); -------line798
}
#endif
上面如果我们将优先级分组设置为Group3,则前面计算出来的ulMaxPRIGROUPValue=0x300;
RTOS_CORE [D] xMBPortEventPost:137 obj:20019dcc,role:0,ev:EV_READY
RTOS_CORE [I] vPortValidateInterruptPriority:750 ulCurrentInterrupt:0x44
RTOS_CORE [I] vPortValidateInterruptPriority:781 ucCurrentPriority:0x50,ucMaxSysCallPriority:32
RTOS_CORE [E] vPortValidateInterruptPriority:798 ASSERT ERROR:0
.由于Group3对应的是0x400,所以上面的断言就为假了,就卡死在哪里。
#define NVIC_PriorityGroup_0 ((uint32_t)0x700)
#define NVIC_PriorityGroup_1 ((uint32_t)0x600)
#define NVIC_PriorityGroup_2 ((uint32_t)0x500)
#define NVIC_PriorityGroup_3 ((uint32_t)0x400)
#define NVIC_PriorityGroup_4 ((uint32_t)0x300)
优先级分组:
|