上一节讲到M3任务切换是基于PendSV异常的,这一节就着重讲一下这个PendSV异常优先级设置以及它是怎么进行触发的,然后说一下接下来的讲解思路。
PendSV异常的优先级设置和触发
PendSV优先级的设置比较简单,往PendSV 的优先级寄存器里写优先级别即可,其寄存器地址为0xE000ED22,详见权威指南,在代码中的操作在uC/OS-III中有汇编实现。
汇编实现(在os_cpu_a.s中):
NVIC_SYSPRI4 EQU 0xE000ED22 ; PendSV异常优先级寄存器地址
NVIC_PENDSV_PRI EQU 0xFFFF ; PendSV异常优先级
//下面是OSStartHighRdy函数中的一段代码
//这段代码即实现设置PendSV优先级为最低
LDR R0, =NVIC_SYSPRI4
LDR R1, =NVIC_PENDSV_PRI
STRB R1, [R0] ;R1低8位写到0xE000ED22地址中
当然,你也可以用c语言实现,详细见下面的PendSV触发实现解析,
PendSV异常的触发是把中断控制寄存器的28位置位即可,该控制寄存器地址为0xE000ED04,详见权威指南,在代码中的操作在uC/OS-III中有汇编实现和c语言实现,如下:
汇编实现(在os_cpu_a.s中):
NVIC_INT_CTRL EQU 0xE000ED04 ; 中断控制寄存器
NVIC_PENDSVSET EQU 0x10000000 ; 触发PendSV异常的值.
//下面是OSStartHighRdy函数中的一段代码
//这段代码即实现把ox10000000写入地址为0xE000ED04的寄存器中,实现触发PendSV异常
LDR R0, =NVIC_INT_CTRL
LDR R1, =NVIC_PENDSVSET
STR R1, [R0]
c语言实现(在os_cpu.h中):
#ifndef NVIC_INT_CTRL
#define NVIC_INT_CTRL *((CPU_REG32 *)0xE000ED04)
#endif
#ifndef NVIC_PENDSVSET
#define NVIC_PENDSVSET 0x10000000
#endif
#define OS_TASK_SW() NVIC_INT_CTRL = NVIC_PENDSVSET
#define OSIntCtxSw() NVIC_INT_CTRL = NVIC_PENDSVSET
NVIC_INT_CTRL = NVIC_PENDSVSET这一句就是c语言实现,即:
*((CPU_REG32 *)0xE000ED04)=0x10000000
这样就实现了PendSV异常的触发。其实OS_TASK_SW()这一句用在了OSSched()函数中,这个就是uC/OS-III任务切换的函数,一般在一些教材中也称任务调度。
接下来要讲什么
前面讲到了PendSV异常的优先级设置和触发操作,按理说,下面我应该讲触发异常后异常具体都做了什么(在uC/OS-III里,是具体实现任务切换过程),这时候我发现了一个问题,就是要理解透PendSV异常处理代码,就会涉及到许多其他知识点,包括任务结构,任务管理(就绪表,优先级表等)如果我抛开那些知识点硬讲,对于刚接触uC/OS-III的人来说,会看得云里雾里,这不是我写这个系列博客的初衷所在,如果完全展开细讲,然后篇幅过大,不利于初学者很好地在脑海中建立一个大致的较为清晰的结构,所以该从哪里开始讲,讲哪些,是我思考的一个问题,啊!头好大!原谅我比较懒,不太喜欢动脑!
言归正传,因为PendSV异常实现任务切换,而任务切换涉及任务管理,那么这里必须要知道的就是任务如何管理,在uC/OS-III里任务的结构是怎样的,以及怎么样根据任务结构和管理实现了任务切换。接下来,且听我慢慢分析:(我把这些知识点放到下一节来讲,因为篇幅较大,另外就是读者如果对我这系列博客有兴趣,可否点个赞让我知道我花时间这么做是否有意义,另外如果有错误和不足之处,可以在评论中指出来让我好及时改正以免误人子弟!)