μCOS-Ⅲ+GD32_SysTick与PendSV中断管理配置浅解

μCOS-Ⅲ+GD32_SysTick与PendSV中断管理配置浅解

GD32移植μCOS-Ⅲ时,需要特别关注的两个与系统相关的且非常重要的中断,一个是提供OS系统时基的滴答定时器(SysTick_Handler中断),另一个是跟任务调度有关的(PendSV_Handler中断),成功移植后简单扒了一下GD32中断知识和μCOS-Ⅲ关于这两个中断的配置和管理方式。



前言

μcos-III是一个可以基于ROM运行的、可裁剪的、抢占式、实时多任务内核,具有高度可移植性,特点:公开源代码、可移植性、可固化、可裁剪、多任务、占先式,特别适合于微处理器和控制器,适合很多商业操作系统性能相当的实时操作系统(RTOS)。在使用GD32F103单片机项目使用过μcos-III,这里作为一个关于SysTick与PendSV中断管理的笔记,欢迎大佬指正!!!!

一、GD32的中断

1.中断与中断优先级

中断:让CPU打断正常运行的程序,转而去处理紧急的事件,中断的一般步骤
1.中断请求:外设产生中断请求(GPIO外部中断、定时器中断)
2. 响应中断:CPU停止执行当前程序,转而去执行中断处理程序
3. 退出中断:执行完毕,返回被打断的程序处,继续往下执行

ARM Cortex-M使用了8位宽的寄存器来配置中断优先级(中断优先级配置寄存器)
GD32和STM32 只是用了中断优先级配置寄存器的[7:4]四位,0-15一共16级的中断优先级等级
数值越小优先级越高。高优先级中断可以打断低优先级中断,支持中断嵌套。

抢占优先级:抢占优先级高的可以打断抢占优先级低的中断(数值越小优先级越高)
子优先级:抢占优先级相同,子优先级数值越低优先执行,但不能互相打断(数值越小优先级越高)
为了方便管理还提出了中断优先级分组,每个分组分配了不同的抢占优先级数和子优先级数,可根据实际情况进行选择,分组配置是在寄存器SCB->AIRCR中配置。

优先级分组AIRCR[10:8]IP Bit[7:4]分配情况
NVIC_PriorityGroup_01110:40位抢占优先级 4子优先级
NVIC_PriorityGroup_11101:31位抢占优先级 3子优先级
NVIC_PriorityGroup_21012:22位抢占优先级 2子优先级
NVIC_PriorityGroup_31003:13位抢占优先级 1子优先级
NVIC_PriorityGroup_40114:04位抢占优先级 0子优先级

特别注意:一个程序代码里只能有一个中断优先级分组在程序初始化时就配置完成,存在多个 优先级分组可能会导致程序出现奇奇怪怪的错误!

2.异常向量表

在谈μCOS-Ⅲ的中断管理之前再说一下GD32的异常向量表:
对于GD32,当某一个外设的中断发生时,CPU如何去调用相应外设的中断服务函数?这时异常向量表就非常重要了。GD32在起始文件中初始化的中断向量表可以看成是一个32位的指针数组,每个成员对应一种异常,这个数组的成员里存放的是一个的中断服务函数的入口地址(向量表首地址规定是栈顶指针)。当识别到到某个中断产生时,硬件会根据我们提供的中断号自动跳转到向量表中与这个中断号对应的这个中断服务函数的入口地址,执行相应的中断服务函数。

__Vectors           DCD     __initial_sp                      ; Top of Stack
                    DCD     Reset_Handler                     ; Reset Handler
                    DCD     NMI_Handler                       ; NMI Handler
                    DCD     HardFault_Handler                 ; Hard Fault Handler
                    DCD     MemManage_Handler                 ; MPU Fault Handler
                    DCD     BusFault_Handler                  ; Bus Fault Handler
                    DCD     UsageFault_Handler                ; Usage Fault Handler
                    DCD     0                                 ; Reserved
                    DCD     0                                 ; Reserved
                    DCD     0                                 ; Reserved
                    DCD     0                                 ; Reserved
                    DCD     SVC_Handler                       ; SVCall Handler
                    DCD     DebugMon_Handler                  ; Debug Monitor Handler
                    DCD     0                                 ; Reserved
                    DCD     PendSV_Handler             		  ; PendSV Handler
                    DCD     SysTick_Handler                   ; SysTick Handler

;                   /* external interrupts handler */
                    DCD     WWDGT_IRQHandler                  ; 16:Window Watchdog Timer
                    DCD     LVD_IRQHandler                    ; 17:LVD through EXTI Line detect
                    DCD     TAMPER_IRQHandler                 ; 18:Tamper Interrupt   
                    DCD     RTC_IRQHandler                    ; 19:RTC through EXTI Line
                    DCD     FMC_IRQHandler                    ; 20:FMC
                    DCD     RCU_IRQHandler                    ; 21:RCU
                    DCD     EXTI0_IRQHandler                  ; 22:EXTI Line 0
                    DCD     EXTI1_IRQHandler                  ; 23:EXTI Line 1
                    DCD     EXTI2_IRQHandler                  ; 24:EXTI Line 2
                    DCD     EXTI3_IRQHandler                  ; 25:EXTI Line 3
                    DCD     EXTI4_IRQHandler                  ; 26:EXTI Line 4
                    DCD     DMA0_Channel0_IRQHandler          ; 27:DMA0 Channel 0
                    DCD     DMA0_Channel1_IRQHandler          ; 28:DMA0 Channel 1
                    DCD     DMA0_Channel2_IRQHandler          ; 29:DMA0 Channel 2
                    DCD     DMA0_Channel3_IRQHandler          ; 30:DMA0 Channel 3
                    DCD     DMA0_Channel4_IRQHandler          ; 31:DMA0 Channel 4
                    DCD     DMA0_Channel5_IRQHandler          ; 32:DMA0 Channel 5 
                    DCD     DMA0_Channel6_IRQHandler          ; 33:DMA0 Channel 6
                    DCD     ADC0_1_IRQHandler                 ; 34:ADC0 and ADC1
                    DCD     USBD_HP_CAN0_TX_IRQHandler        ; 35:USBD and CAN0 TX
                    DCD     USBD_LP_CAN0_RX0_IRQHandler       ; 36:USBD and CAN0 RX0
                    DCD     CAN0_RX1_IRQHandler               ; 37:CAN0 RX1
                    DCD     CAN0_EWMC_IRQHandler              ; 38:CAN0 EWMC
                    DCD     EXTI5_9_IRQHandler                ; 39:EXTI Line 5 to EXTI Line 9
                    DCD     TIMER0_BRK_IRQHandler             ; 40:TIMER0 Break
                    DCD     TIMER0_UP_IRQHandler              ; 41:TIMER0 Update
                    DCD     TIMER0_TRG_CMT_IRQHandler         ; 42:TIMER0 Trigger and Commutation
                    DCD     TIMER0_Channel_IRQHandler         ; 43:TIMER0 Channel Capture Compare
                    DCD     TIMER1_IRQHandler                 ; 44:TIMER1
                    DCD     TIMER2_IRQHandler                 ; 45:TIMER2
                    DCD     TIMER3_IRQHandler                 ; 46:TIMER3
                    DCD     I2C0_EV_IRQHandler                ; 47:I2C0 Event
                    DCD     I2C0_ER_IRQHandler                ; 48:I2C0 Error
                    DCD     I2C1_EV_IRQHandler                ; 49:I2C1 Event
                    DCD     I2C1_ER_IRQHandler                ; 50:I2C1 Error
                    DCD     SPI0_IRQHandler                   ; 51:SPI0
                    DCD     SPI1_IRQHandler                   ; 52:SPI1
                    DCD     USART0_IRQHandler                 ; 53:USART0
                    DCD     USART1_IRQHandler                 ; 54:USART1
                    DCD     USART2_IRQHandler                 ; 55:USART2
                    DCD     EXTI10_15_IRQHandler              ; 56:EXTI Line 10 to EXTI Line 15
                    DCD     RTC_Alarm_IRQHandler              ; 57:RTC Alarm through EXTI Line
                    DCD     USBD_WKUP_IRQHandler              ; 58:USBD WakeUp from suspend through EXTI Line
                    DCD     TIMER7_BRK_IRQHandler             ; 59:TIMER7 Break Interrupt
                    DCD     TIMER7_UP_IRQHandler              ; 60:TIMER7 Update Interrupt
                    DCD     TIMER7_TRG_CMT_IRQHandler         ; 61:TIMER7 Trigger and Commutation Interrupt
                    DCD     TIMER7_Channel_IRQHandler         ; 62:TIMER7 Channel Capture Compare 
                    DCD     ADC2_IRQHandler                   ; 63:ADC2
                    DCD     EXMC_IRQHandler                   ; 64:EXMC
                    DCD     SDIO_IRQHandler                   ; 65:SDIO
                    DCD     TIMER4_IRQHandler                 ; 66:TIMER4
                    DCD     SPI2_IRQHandler                   ; 67:SPI2
                    DCD     UART3_IRQHandler                  ; 68:UART3
                    DCD     UART4_IRQHandler                  ; 69:UART4
                    DCD     TIMER5_IRQHandler                 ; 70:TIMER5
                    DCD     TIMER6_IRQHandler                 ; 71:TIMER6
                    DCD     DMA1_Channel0_IRQHandler          ; 72:DMA1 Channel0
                    DCD     DMA1_Channel1_IRQHandler          ; 73:DMA1 Channel1
                    DCD     DMA1_Channel2_IRQHandler          ; 74:DMA1 Channel2
                    DCD     DMA1_Channel3_4_IRQHandler        ; 75:DMA1 Channel3 and Channel4

__Vectors_End

例如产生了复位异常,那么MCU会在异常向量表找到Reset_Handler函数的地址,然后跳转到该函数执行;与μCOS-Ⅲ密切相关的SysTick与PendSV中断也在异常向量表中实现了,下图为向量表结构(《CortexM3权威指南(中文)》,P45):
在这里插入图片描述
在这里插入图片描述

向量表的存储位置是可以设置的,通过 NVIC 中的一个重定位寄存器来指出向量表的地址。在复位后,该寄存器的值为 0。因此,在地址 0 处必须包含一张向量表,用于初始时的异常分配。初始化时会根据配置条件将异常向量表加载到程序起始运行地址处,在SystemInit(void)函数底部有这样一段代码描述的就是加载异常向量表的储存位置:

#ifdef VECT_TAB_SRAM
    nvic_vector_table_set(NVIC_VECTTAB_RAM, VECT_TAB_OFFSET);
#else
    nvic_vector_table_set(NVIC_VECTTAB_FLASH,VECT_TAB_OFFSET);
#endif

所以单片机手撸Bootloader的时候,记得更改Bootloader和APP的异常向量表的映射地址。

二、μCOS-Ⅲ的中断与异常

在μCOS-Ⅲ中有两个与系统非常密切的中断,一个是提供OS系统时基的滴答定时器(SysTick_Handler中断),另一个是跟任务调度有关的(PendSV_Handler中断),根据Cortex‐M3 中的异常类型表(《CortexM3权威指南(中文)》,P45),我们可以知道编号为 1-15 的对应系统异常,大于等于 16 的则全是外部中断。除了个别异常的优先级被定死外, 其它异常的优先级都是可编程的。SysTick与PendSV分别是系统中断中编号为15和14的异常。编号为1-3的异常优先级被定死不能更改,所以μCOS也不能对其进行编程操作。(注意: 所有能打断正常执行流的事件都称为异常,没有编号为 0 的异常)
在这里插入图片描述
结合第一章第一节中的描述,在μCOS-Ⅲ中,使用的是NVIC_PriorityGroup_4 优先级分组,相当于有0-15共16个抢占优先级,但是可供μCOS-Ⅲ管理的优先级只有4-15这12个,通过CPU_CFG_KA_IPL_BOUNDARY 设置,如果将宏定义为4,即中断优先级范围为4~15。
在这里插入图片描述

1.滴答定时器SysTick中断

要将SysTick作为μCOS的时基计数,首先需要明确SysTick的优先级和中断时间。整个OS运行的时间计数都由SysTick的中断产生,所以无论MCU在干什么只要SysTick中断触发就必须雷打不动地调用SysTick_Handler进行计数以保证系统时钟精度,所以SysTick的优先级必须为最高优级;其次中断周期决定了计数频率,相当于OS的系统频率,不能太快也不能太慢(太慢系统利用率不高,太快mcu频繁触发中断,时间都用来计数了),一般通过宏OS_CFG_TICK_RATE_HZ 设置为1000即可。

函数在开始任务时,需要调用OS_CPU_SysTickInit(cntr)来初始化SysTick;参数cntr决定SysTick的中断频率,一般这样设置先获取SysTick系统时钟,再除以滴答定时器中断频率得到cntr的值。

 CPU_INT32U cntr = 0;
 cntr = rcu_clock_freq_get(CK_SYS) / OS_CFG_TICK_RATE_HZ;
  
 CPU_Init();
 OS_CPU_SysTickInit(cntr);

OS_CPU_SysTickInit(cntr)函数内部:
在这里插入图片描述
在这里插入图片描述
这样就完成了SysTickInit的优先级和中断频率的配置,然后就是每次触发中断调用SysTick_Handle函数时调用OS的计数函数OS_CPU_SysTickHandler,转到OS系统;或将.s启动文件将SysTick_Handle函数名全部换成OS_CPU_SysTickHandler也可以。这样就完成了整个OS的时基配置。

2.任务切换PendSV中断

要将PendSV作为μCOS的任务切换的一个重要机制,OS在没有PendSV时,直接由当OS进行多个任务切换时候,如果此时产生 SysTick 异常时正在响应一个中断,则SysTick异常 因为优先级较高会抢占其 ISR。此时OS 不能执行上下文切换,否则将使中断请求被延迟,而且在真实系统中延迟时间往往又会有诸多变数,所以有任何实时性要求的系统都不会这么干。

后来演变早期的 OS 大多会检测当前是否有中断在活跃中,只有没有任何中断需要响应时,才执行上下文切换(切换期间无法响应中断)。然而,这种方法的弊端在于,它可以把任务切换动作拖延很久(因为如果抢占了 IRQ,则本次 SysTick 在执行后不得作上下文切换,只能等待下一次 SysTick 异常),尤其是当某中断源的频率和 SysTick 异常的频率比较接近时,会发生“共振”,这种情况会更加频繁发生。

后来出现PendSV,PendSV 异常会自动延迟上下文切换的请求,后来主要利用的是其“缓期执行”的特点——直到其它的 ISR 都完成了处理后才放行。为实现这个机制,需要把 PendSV 编程为最低优先。如果 OS 检测到某 IRQ 正在活动并且被 SysTick 抢占,它将悬起一个 PendSV 异常,以便缓期执行上下文切换。

PendSV在OS中是如何进行任务切换的,这里几句话可说不清楚,后面我专门讲任务切换,只需要知道通过SHPR3(地址:0xE000ED22)将PendSV设置为μC/OS系统最低优先级,保证系统任务切换不会阻塞系统其他中断的响应,函数OSStartHighRdy()中有如下代码:
在这里插入图片描述


总结

主要知识点就两个:
■μC/OS-III直接参与管理的中断优先级为4-15,
■与μC/OS-III系统直接相关的中断有两个,一个SysTick负责系统时基中断需要在优先级最高,一个PendSV负责任务切换中断需要优先级最低

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值