CMSIS-RTOS 中断处理Interrupt Handling

本文介绍了RTOS中的中断处理机制,特别是在Cortex-M微控制器上的应用。通过将中断处理设计为高优先级线程的方式,有效地提高了系统的响应速度。文中详细解释了如何在中断服务程序中设置信号标志来触发线程,以及如何配置线程以获得访问NVIC寄存器的权限。

RTOS中断处理Interrupt Handling

在RTOS中使用信号来触发线程间的行为是比较简单和高效的,而对于Cortex-M微控制器来讲,从中断源获取信号来触发线程同样是一种重要的方式。虽然在中断服务程序ISR中运行一段代码也可以,但在RTOS系统中,在中断运行的时间越短越好,因为太长的时间会延长定时器的节拍,并破坏RTOS内核。系统节拍运行的优先级在NVIC中是最低的,因此任何中断服务程序都会打断它。

这里写图片描述

在RTOS中最好把中断服务代码设计成一个线程,并分配给它一个比较高的优先级。中断服务线程里的第一行代码应该是等待一个信号标志,当中断到来时,中断处理程序Handler唯一的任务就是设置信号标志,然后就结束运行。中断服务线程为中断事件提供服务,并在服务完成后重新进入循环等待信号标志的再次到来。

这里写图片描述

在RTOS里,中断服务代码作为线程运行,当中断到来时,中断处理程序Handler给中断服务线程发信号。然后交给内核根据线程的优先级进行调度。

void Thread3(void)
{
    while(1)
    {
        osSignalWait(isrSignal, waitForever);//等待ISR触发一个事件
        ...//处理中断
    }     
}

实际的中断程序只包含一点点代码:

void IRQ_Handler(void)
{
    osSignalSet(thread3, isrSignal);//给线程3发信号
}

练习:中断信号

CMSIS-RTOS不会在中断服务里引入任何延迟,但是如果你锁住系统节拍中断时间太长的话,就会干扰RTOS的正常运行。这个练习展示了如何从中断处理程序Handler给一个线程发信号,然后在线程里给中断提供服务,这和常规的ISR不同。

打开Pack Installer,选择”Ex 9 Interrupt Signals”,然后install到你的指定路径

在main函数里,我们初始化ADC,并且创建了一个ADC线程,并给它分配一个所有线程中最高的优先级:

osThreadDef(adc_Thread, osPriorityAboveNormal, 1, 0);
int main(void){
    LED_Init();
    init_ADC();
    T_led_ID1 = osThreadCreate(osThread(led_Thread1), NULL);
    T_led_ID2 = osThreadCreate(osThread(led_Thread2), NULL);
    T_adc_ID = osThreadCreate(osThread(adc_Thread), NULL);
}

然而,在我们进入main函数后,会遇到一个问题:RTOS配置运行的所有线程都没有特权,因此我们就无法访问NVIC寄存器,针对这个问题有几种处理办法,最简单的就是给线程开放特权访问权限,只需要在RTX_Conf_CM.c文件里进行设置就可以了:

这里写图片描述

这里我们把线程执行模式切换到特权模式,这样线程就拥有访问Cortex-M处理器的所有访问权限,这里我们需要增加一个线程,同时可运行线程的个数也要增加一个。

编译工程并打开debugger仿真环境

在led_Thread2, adc_Thread和AD1_2_IRQHandler分别设置断点
这里写图片描述

这里写图片描述

全速运行代码

你会在启动ADC转换的地方遇到第一个断点,然后继续运行,进入ADC中断处理程序,该处理程序给adc线程完发信号就退出。发出的这个信号会让adc线程抢占其他正在运行的线程,紧接着adc线程运行ADC服务程序,然后就会重新挂起,等待下一个信号的到来。

练习:Keil RTX 和 SVC异常

在上一个例子中可以看到,当我们进入一个线程里,它就会运行到一个非特权模式。最简单的方法就是配置线程运行进入特权模式,但是这样就会运行线程拥有访问处理器的所有权限,就会引起潜在的运行时间错误。在这个例子中我们将看到如何使用系统调用异常来进入特权模式,进而运行系统级的代码。

打开Pack Installer,选择“Ex 10 Interrupt Signals”,然后install到你的指定路径。

在这个工程里我们已经添加了一个新的文件叫SVC_Table.s,
添加方法:右击Source Group 1,点击’Add New Item’,选择‘User Code Template’,然后选择CMSIS-RTOS User SVC。(实际工程中已经添加完这个文件——译者注)。

这个就是SVC中断查找表:

这里写图片描述

在这个文件里,我们需要为每个__SVC函数添加导入名称和表入口,在我们的例子里只需要__SVC_1

现在我们可以把ADC初始化函数转变成一个服务调用异常:
这里写图片描述

这里写图片描述

编译工程并启动仿真环境

在init_ADC()函数前设置断点。
这里写图片描述

然后从左侧的寄存器窗口查看操作模式
这里我们处于Thread模式,非特权,使用进程栈指针:

这里写图片描述

继续单步运行,穿过汇编代码,进入init_ADC函数

这里写图片描述

这时我们可以看到已经进入了Handler模式,特权权限,使用主栈指针。这样我们就可以设置ADC,并拥有访问NVIC的权限了。

### S32K3 Microcontroller FreeRTOS Interrupt Handling Implementation In the context of configuring interrupts on an S32K3 microcontroller with FreeRTOS, it is essential to understand how priority levels are managed within the operating system framework. The configuration parameters `configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY` and `configMAX_SYSCALL_INTERRUPT_PRIORITY`, defined in `FreeRTOSConfig.h`, play a critical role in ensuring that certain high-priority tasks can preempt lower ones without causing issues such as priority inversion or deadlocks. For instance, setting `configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY = 0x01` indicates that any interrupt at this level or below will be allowed to execute while the scheduler lock is held[^1]. This means these interrupts won't cause delays when performing operations like task switching. Additionally, defining `configPRIO_BITS = 4` specifies four bits used for encoding priorities across all available hardware interrupt lines. To implement proper interrupt handling under FreeRTOS: #### Configuring NVIC Priorities The Nested Vectored Interrupt Controller (NVIC) must have its priorities configured according to the values set by FreeRTOS configurations mentioned above. Here’s an example code snippet demonstrating how one might configure an external line interrupt using CMSIS functions provided specifically for S32 devices: ```c #include "fsl_common.h" #include "FreeRTOS.h" void setup_interrupt(void){ /* Enable clock gate */ CLOCK_EnableClock(kCLOCK_PortA); PORT_SetPinInterruptConfig(PORTA, kPORT_IntFallingEdge); /* Set Priority Level */ NVIC_SetPriority(EXTI_IRQn, configLIBRARY_LOWEST_INTERRUPT_PRIORITY); /* Unmask IRQ Channel */ NVIC_ClearPendingIRQ(EXTI_IRQn); NVIC_EnableIRQ(EXTI_IRQn); } ``` This function sets up port A pin interrupts where falling edges trigger events. It also assigns the lowest possible priority value (`configLIBRARY_LOWEST_INTERRUPT_PRIORITY`) which ensures compatibility with other higher-level ISRs already running inside FreeRTOS environment. #### Implementing ISR Functions When writing actual Interrupt Service Routines (ISR), care should be taken not only about what happens during execution but also regarding reentrancy into RTOS APIs from within those routines. Below shows a typical way to handle GPIO edge-triggered interrupts safely alongside FreeRTOS: ```c extern void EXTI_IRQHandler(void) { BaseType_t xHigherPriorityTaskWoken; if ((GPIO_GetPinsInterruptFlags(GPIOA)) != 0U ) { // Clear flag first before doing anything else. GPIO_ClearPinsInterruptFlags(GPIOA, 1 << 17); // Post event to queue/task/semaphore etc., potentially waking another thread. xQueueSendFromISR(my_queue_handle, &data_to_send, &xHigherPriorityTaskWoken); // Ensure correct scheduling after returning control back to OS kernel. portYIELD_FROM_ISR(xHigherPriorityTaskWoken); } } ``` Here, once triggered, the handler clears pending flags immediately followed by sending data through queues or semaphores depending upon application needs. Finally, calling `portYIELD_FROM_ISR()` allows immediate rescheduling based on updated states caused due to received messages. --related questions-- 1. How does changing `configPRIO_BITS` affect overall system performance? 2. What precautions need consideration when integrating third-party libraries requiring their own ISRs? 3. Can you provide more details on best practices concerning nested interrupts management? 4. Is there any specific toolchain support required for implementing safe ISR programming patterns?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值