FreeRTOS实时操作系统(四)中断任务管理

系列文章目录


文章目录

  • 系列文章目录
  • 前言
  • 中断优先级
  • FreeRTOS中的中断管理
  • 一系列中断管理寄存器
    • 中断配置寄存器
    • 中断屏蔽寄存器
  • 中断管理实战


前言

跟着正点原子学习一下中断管理,正好之间没有总结过,还有些地方不清楚。


中断优先级

中断的工作方式就不介绍了,一般ARM-Cortex-M使用的是8位的寄存器来配置中断的优先级,但是在STM32中,只使用了高4位来配置中断优先级,所以最大只有16级。

FreeRTOS实时操作系统(四)中断任务管理_第1张图片
STM32的中断优先级分为抢占优先级和子优先级

抢占优先级:高优先级可以打断低优先级的中断
子优先级:相同抢占优先级的两个中断同时发生的时候,子优先级数值小的先执行(数值小优先级高)(子优先级的中断之间不会抢占)

FreeRTOS实时操作系统(四)中断任务管理_第2张图片
一般这个优先级设置在HAL_Init()函数中(HAl库),通过调用HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4)完成设置。

FreeRTOS中的中断管理

要点:
1、低于configMAX_SYSCALL_INTERRUPT_PRIORITY优先级的中断里才允许调用FreeRTOS 的API函数。
2、建议将所有优先级位指定为抢占优先级位,方便FreeRTOS管理(设置成分组4),HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4)。
3、中断优先级数值越小越优先,任务优先级数值越大越优先。

一系列中断管理寄存器

中断配置寄存器

SHPR1寄存器地址:0xE000ED18-0xE000ED1B
SHPR2寄存器地址:0xE000ED1C-0xE000ED1F
SHPR3寄存器地址:0xE000ED20-0xE000ED23
FreeRTOS实时操作系统(四)中断任务管理_第3张图片
上表出自《Cortex M3权威指南(中文)》第286页。

在STM32cubeMX中生成的HAL库FreeRTOS中,SHPR3寄存器的名字及地址如下:
FreeRTOS实时操作系统(四)中断任务管理_第4张图片

这里需要注意PendSV的优先级和SysTick的优先级,他们两是关于系统工作和任务调度的,所以保证其他中断能随时打断任务切换等,在库中按照如下方式设置优先级为最低。

在Cortex-M3中,如果OS在某个中断活跃时,抢占了该中断,而且又发生了任务调度,并执行了任务,切换到了线程运行模式,将直接触发Fault异常。(所以把SysTick和PendSV中断优先级设置最低也是有原因的,就是为了OS调度不抢占其他中断导致Fault的问题)

虽然这样看系统工作时钟会不稳定,但是没有办法,有文章说如果外部IRQ很多,那么可以考虑提高SysTick优先级,PendSV一直设置最低,来适当解决OS调度SysTick被抢占太厉害的问题。

在FreeRTOS中,需要设置这两个优先级:

1.首先,由于高四位是用来设置优先级的,所以,要设置这两个优先级为15,就需要将15左移4位
FreeRTOS实时操作系统(四)中断任务管理_第5张图片
FreeRTOS实时操作系统(四)中断任务管理_第6张图片
2.由于SHPR3寄存器是4个地址,每个地址是8位的,所以按照上表,PendSV需要左移16位,SysTick需要左移24位,UL是标记该宏是无符号长整型十进制数据。
FreeRTOS实时操作系统(四)中断任务管理_第7张图片
3.将PendSV和SysTick的优先级设置为15,即最低优先级。
FreeRTOS实时操作系统(四)中断任务管理_第8张图片

中断屏蔽寄存器

平常见的有三种:
1.PRIMASK:1,关闭所有,只剩下NMI和硬fault两个中断,默认是0;
2.FAULTMASK:1,关闭所有,只有NMI可以相应。默认是0;
3.BASEPRI:最多有9位,当他设置为某个值的时候,优先级比这个值低的全部为屏蔽(数值比这个值大),默认是0,不关闭任何中断。

在FreeRTOS中,利用的就是BASEPRI这个寄存器。比如设置为0x50的时候,优先级在5-15内的所有都被屏蔽,0-4的正常运行。

FreeRTOS实时操作系统(四)中断任务管理_第9张图片

__asm 关键字用于调用内联汇编程序,并且可在 C 或 C++ 语句合法时出现,__asm与大括号一起使用,则该关键字表示大括号之间的每一行都是一条汇编语言语句。

FreeRTOS实时操作系统(四)中断任务管理_第10张图片FreeRTOS实时操作系统(四)中断任务管理_第11张图片
默认生成的HAl中,如果调用该函数就把优先级为5-15的中断全部都关闭了,可以自己更改第一张图中的u1NEWBASEPRI的值来更改屏蔽的寄存器优先级

FreeRTOS实时操作系统(四)中断任务管理_第12张图片
5-15的优先级中断被FreeRTOS所屏蔽,不会直接触发中断,要经过内核的管控,可能会存在一些延时,所以一般将一些实时性高的中断放在0-4中。而在5-15的中断中,可以应用FreeRTOS的API函数,但这些必须以“FromISR”结束

中断管理实战

void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{
    if (htim->Instance == BTIM_TIMX_INT)
    {
        BTIM_TIMX_INT_CLK_ENABLE();                     /* 使能TIMx时钟 */
        HAL_NVIC_SetPriority(BTIM_TIMX_INT_IRQn, 6, 0); /* 抢占6,子优先级0 */
        HAL_NVIC_EnableIRQ(BTIM_TIMX_INT_IRQn);         /* 开启ITMx中断 */
    }
    if(htim->Instance == BTIM_TIM7_INT)
    {
        BTIM_TIM7_INT_CLK_ENABLE();                     /* 使能TIM7时钟 */
        HAL_NVIC_SetPriority(BTIM_TIM7_INT_IRQn, 4, 0); /* 抢占4,子优先级0 */
        HAL_NVIC_EnableIRQ(BTIM_TIM7_INT_IRQn);         /* 开启ITM7中断 */
    }
}

正点原子的程序中,设置两个定时器中断的优先级为4和6,然后再任务中进行关闭和打开

void task1( void * pvParameters )
{
    uint8_t task1_num = 0;
    while(1)
    {
        if(++task1_num == 5)
        {
            task1_num = 0;
            printf("关中断!!\r\n");
            portDISABLE_INTERRUPTS();
            delay_ms(5000);
            printf("开中断!!!\r\n");
            portENABLE_INTERRUPTS();
        }
        vTaskDelay(1000);
    }
}

FreeRTOS实时操作系统(四)中断任务管理_第13张图片
这里使用delay_ms(5000);而不使用vTaskDelay(1000);是因为vTaskDelay()函数内部中,在其内部的临界区调用了开中断的函数,使得中断会自动打开。
FreeRTOS实时操作系统(四)中断任务管理_第14张图片
FreeRTOS实时操作系统(四)中断任务管理_第15张图片

你可能感兴趣的:(FreeRTOS,stm32,FreeRTOS,嵌入式操作系统)