STM32 FreeRTOS中断管理
STM32 FreeRTOS 中断管理
一、中断优先级配置
在STM32上使用FreeRTOS时,合理配置中断优先级是非常重要的。STM32使用8位宽的寄存器来配置中断的优先等级,但实际只使用了高4位(7:4),因此提供了最大16级的中断优先级。中断优先级数值越小,优先级越高。
二、中断优先级分组
STM32的中断优先级可以分为抢占优先级和子优先级:
• 抢占优先级:抢占优先级高的中断可以打断正在执行但抢占优先级低的中断。
• 子优先级:当同时发生具有相同抢占优先级的中断时,子优先级数值小的优先执行,但不能互相打断。
为了方便FreeRTOS管理,建议将所有优先级位指定为抢占优先级位,即将优先级分组设置为组4。可以通过以下代码设置:
HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);
这样,4位优先级就都作为抢占优先级,没有子优先级,共有0~15共16个优先级。
三、FreeRTOS 中断管理
1. 中断优先级配置
FreeRTOS通过宏configMAX_SYSCALL_INTERRUPT_PRIORITY来定义可管理的最高中断优先级。例如:
#define configMAX_SYSCALL_INTERRUPT_PRIORITY (5 << 4)
这意味着FreeRTOS可以管理优先级数值大于等于5的中断。
2. 中断服务例程(ISR)
在中断服务例程中,如果需要调用FreeRTOS的API函数,只能使用带“FromISR”后缀的函数。例如:
xQueueSendFromISR(queue, &data, &higherPriorityTaskWoken);
这样可以确保在中断服务例程中安全地与FreeRTOS任务进行通信。
3. 临界区保护
FreeRTOS提供了宏taskENTER_CRITICAL()和taskEXIT_CRITICAL()来进入和退出临界区。这些宏通过禁用和启用中断来保护临界区代码。例如:
void vPortEnterCritical(void) {
portDISABLE_INTERRUPTS();
uxCriticalNesting++;
if (uxCriticalNesting == 1) {
configASSERT((portNVIC_INT_CTRL_REG & portVECTACTIVE_MASK) == 0);
}
}
void vPortExitCritical(void) {
configASSERT(uxCriticalNesting);
uxCriticalNesting--;
if (uxCriticalNesting == 0) {
portENABLE_INTERRUPTS();
}
}
这些宏确保在临界区代码执行期间,不会被其他中断打断,从而保证操作的原子性。
四、中断控制器配置
在使用FreeRTOS时,需要合理配置中断控制器。例如,设置SysTick和PendSV中断的优先级:
#define configMAX_SYSCALL_INTERRUPT_PRIORITY (5 << 4)
NVIC_SetPriorityGrouping(0);
NVIC_SetPriority(SysTick_IRQn, configMAX_SYSCALL_INTERRUPT_PRIORITY);
NVIC_SetPriority(PendSV_IRQn, configMAX_SYSCALL_INTERRUPT_PRIORITY);
这样可以确保FreeRTOS的系统任务切换不会阻塞其他中断的响应。
五、延迟中断处理
FreeRTOS采用延迟中断处理机制,将中断处理任务延迟到RTOS任务中执行。例如:
• t1-t2这段时间低优先级的任务Task1正在执行,高优先级的任务Task2因等待事件被阻塞。
• t2时刻发生了中断,该中断就是Task2等待的事件,因此Task2进入就绪态。
• t3时刻中断服务程序执行完毕,由于就绪任务中Task2优先级更高,因此调度器选择Task2进入运行态。
六、实际案例
以下是一个实际案例,展示了如何在STM32上使用FreeRTOS进行中断处理和任务调度:
1. 初始化代码
#include "stm32f10x.h"
#include "OLED.h"
#include "FreeRTOS.h"
#include "task.h"
#include "FreeRTOS_experiment.h"
#include "Key.h"
#include "LED.h"
#include "Timer.h"
int main(void) {
Key_Init();
LED_Init();
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
Timer2_Init();
Timer3_Init();
FreeRTOS_Test();
while (1) {
}
}
void TIM2_IRQHandler(void) {
if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET) {
LED1_Turn();
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
}
}
void TIM3_IRQHandler(void) {
if (TIM_GetITStatus(TIM3, TIM_IT_Update) == SET) {
LED2_Turn();
TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
}
}
2. 任务创建和调度
#include "FreeRTOS.h"
#include "task.h"
#include "LED.h"
#include "Key.h"
#include "Delay.h"
#define START_TASK_STACK_SIZE 128
#define START_TASK_PRIO 1
#define TASK3_STACK_SIZE 128
#define TASK3_PRIO 4
void start_task(void);
void task3(void);
TaskHandle_t start_task_handler;
TaskHandle_t task3_handler;
void FreeRTOS_Test(void) {
xTaskCreate((TaskFunction_t)start_task,
"start_task",
START_TASK_STACK_SIZE,
NULL,
START_TASK_PRIO,
(TaskHandle_t *)&start_task_handler);
vTaskStartScheduler();
}
void start_task(void) {
taskENTER_CRITICAL();
xTaskCreate((TaskFunction_t)task3,
"task3",
TASK3_STACK_SIZE,
NULL,
TASK3_PRIO,
(TaskHandle_t *)&task3_handler);
vTaskDelete(NULL);
taskEXIT_CRITICAL();
}
void task3(void) {
uint8_t key = 0;
while (1) {
key = Key_GetNum();
if (key == 1) {
portDISABLE_INTERRUPTS();
}
if (key == 2) {
portENABLE_INTERRUPTS();
}
Delay_ms(10);
}
}
七、总结
通过合理配置中断优先级、使用临界区保护、延迟中断处理等机制,FreeRTOS可以在STM32上实现高效、稳定的中断管理。这些机制不仅提高了系统的实时性,还确保了任务调度的正确性和可靠性。