FreeRTOS学习笔记 11 - 中断管理

目录

1. 中断配置

2. 中断处理原则

2.1 发送事件

2.2 发送邮件

2.3 发送消息队列

4. 进入中断和离开中断

5. 禁止中断和使能中断

6. 实例


FreeRTOS的中断处理方式和RT Thread有点不同,在中断处理函数中Free RTOS都会有对应的API,例如xQueueSend对应xQueueSendFromISR,即API函数名加上后缀“FromISR”就是中断中的API函数。它们的区别是“FromISR” API函数执行完后不会立即进行任务调度,只是标记,等退出中断后再进行任务调度。

1. 中断配置

FreeRTOSConfig.h中的宏定义configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY

这个宏定义的含义是指FreeRTOS能管理优先级在 x ~ 15 之间的的优先级,比如设置为x = 5,则表示FREERTOS不能管理优先级在0~4的中断,FreeRTOS打断不了0-4的中断。

a. 在0-4的中断里不能调用freertos的api函数

b. 可以在5-15的中断中调用以FromISR结尾的api函数,并且可以中断嵌套

2. 中断处理原则

对于RTOS来说,中断处理原则上要尽可能短,尽可能不调用OS的API函数。一般设计成发送事件、邮箱之类的通知任务处理即可。

2.1 发送事件

#define rtosEventSendFromISR(                           \
    handle,                                             \
    set                                                 \
    )                                                   \
    {                                                   \
        xEventGroupSetBitsFromISR(handle, set, NULL);   \
    }

xEventGroupSetBitsFromISR比xEventGroupSetBits多一个参数,第三个参数是一个BOOL型的返回值,为pdTRUE时表示中断结束时需要任务切换,否则表示不需要。这里为了兼容性,不用这个参数,设置为NULL。

2.2 发送邮件

#define rtosMailboxSendFromISR(                         \
    handle,                                             \
    value                                               \
    )                                                   \
    {                                                   \
        uint32_t *pValue = (void *)&value;              \
        uint32_t ret =                                  \
        xQueueSendFromISR(handle, (void *)&pValue,      \
                NULL);                                  \
    }

xQueueSendFromISR和xQueueSend的区别是第三个参数不同,xQueueSend是设置超时时间,而xQueueSendFromISR的含义与xEventGroupSetBitsFromISR相同。

2.3 发送消息队列

#define rtosMQSendFromISR(                              \
    handle,                                             \
    buffer,                                             \
    size,                                               \
    ret                                                 \
    )                                                   \
    {                                                   \
        ret = xQueueSendFromISR(handle,                 \
            (void *)&buffer, NULL);                     \
    }

#define rtosMQSendUrgentFromISR(                        \
    handle,                                             \
    buffer,                                             \
    size,                                               \
    ret                                                 \
    )                                                   \
    {                                                   \
        ret = xQueueSendToFrontFromISR(handle,          \
            (void *)&buffer, NULL);                     \
    }

对应NULL的参数含义与xEventGroupSetBitsFromISR相同。

4. 进入中断和离开中断

#define rtosIntEnter()          
#define rtosIntLeave()          portYIELD_FROM_ISR(pdTRUE)

 为了保持和RTT的兼容性、中断处理的及时性和程序简单化,在退出中断时默认做任务切换。不过这种方式实际是破坏了FreeRTOS在设计中断时的切换速度。

5. 禁止中断和使能中断

#define rtosIntEnable()         portENABLE_INTERRUPTS()
#define rtosIntDisable()        portDISABLE_INTERRUPTS()

6. 实例

利用按键的GPIO中断检测,当发生GPIOI中断时,进入中断发送消息。

GPIO中断初始化代码如下:

void gpioIntInit(void)
{
    //GPIOA0 is user key input pin.
    EXTI_InitTypeDef EXTI_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
    
    RCC->APB2ENR |= RCC_APB2Periph_SYSCFG;
    
    RCC->AHB1ENR |= RCC_AHB1Periph_GPIOA;
    
    GPIOA->OSPEEDR |= ((uint32_t)0x0000000F << (6 * 2));  //All are 50MHz
    GPIOA->MODER |= (uint32_t)GPIO_Mode_IN << (0 * 2);
    GPIOA->PUPDR &= ~((uint32_t)0x00000003 << (6 * 2));   //GPIO_PuPd_NOPULL

    SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource0);
    EXTI_InitStructure.EXTI_Line = EXTI_Line0;
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;
    EXTI_Init(&EXTI_InitStructure);
    
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
    NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 5;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}

注意,这里中断优先级设置为5。

中断处理函数根据FreeRTOS的特性改一下(RTT的也要加上这些FromISR的宏定义)

void EXTI0_IRQHandler(void)
{
    /* enter interrupt */
    rtosIntEnter();
    
    if(EXTI_GetITStatus(EXTI_Line0) != RESET)
    {
        static char str1[] = "gpio int\n";
        EXTI_ClearITPendingBit(EXTI_Line0);
        rtosMailboxSendFromISR(mailbox, str1);
    }

    /* leave interrupt */
    rtosIntLeave();
}

验证结果和RTT的一样。

将中断优先级改为0

vNVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;

可以看到程序会死在rtosMailboxSendFromISR(mailbox, str1);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值