目录
1.1 那么uC/OS-III如何配置PendSV和Systick中断优先级?
*注意事项
-
中断函数要求响应快,时间短效率高,所以不能有太多复杂函数和任务
-
中断可以嵌套,高优先级可以打断低优先级中断
-
STM32只用了一个寄存器中的某8位的4-7位来设置优先级,也就是优先级数值范围是:0~15!!优先级只有16个等级
-
UCOS默认管理优先级范围为:4~15级,如果需要设置这个范围比如想管理0~16位,需要去CPU_CFG_KA_IPL_BOUNDA改变
只有在UCOS管理的中断优先级范围内的中断函数才能调用Ucos的API函数!
一、中断优先级寄存器
SHPR1寄存器:0xE000_ED18
SHPR2寄存器:0xE000_ED1C
SHPR3寄存器:0xE000_ED20 Pendsv:实现任务切换;SysTick:提供UcosIII的系统节拍
注:一个地址8个位,那么一个寄存器就是32位
1.1 那么uC/OS-III如何配置PendSV和Systick中断优先级?
1.11 PendSV优先级的设置:
OSStartHighRdy
LDR R0, =NVIC_SYSPRI14 ; Set the PendSV exception priority
LDR R1, =NVIC_PENDSV_PRI
STRB R1, [R0]
(LDR和STRB指令的用法请参照下面的章节)简单来说就是:
-
把(图2)NVIC_SYSPRI14的地址通过LDR指令复制给R0,
-
将NVIC_PENDSV_PRI优先级设置为0XFF(即15,因为只有高4位有效(0-15),0XFF加粗的F代表15)
-
用STRB指令,将RI的数值写入R0地址的寄存器中,从而完成PENDSV的优先级设置
1.12 为什么将其PENDSV任务切换优先级设置为15?
中断可以打断任务,而任务不可以打断中断!
1.13 Systic优先级的设置:
CPU_CFG_NVIC_PRIO_BITS代表4
第一行:将UCOSIII管理优先级最低级设为4,代码含义:将4左移4位
第三行:将SHPRI3寄存器的基地址赋值给prio
第四行:与操作,将高八位清0其他位不变,为什么是高8位,因为在32位的SHPRI3寄存器中,高8位代表SYStick的优先级(见图1)
第五行:或操作,将高8位设置为4,将优先级4左移24位,即将将高8位设置为4,高8位代表SYStick的优先级
第六行:将整体设置好的32位再赋值给宏定义的寄存器
第七行:定义寄存器地址
Systick设置的优先级最高,是为了保证系统接拍的精度!所以:Pendsv设置最低优先级,Systick设置最高优先级
二、中断相关寄存器
2.1 三个中断屏蔽寄存器
三个中断屏蔽寄存器,分别为 PRIMASK、 FAULTMASK 和BASEPRI
PRIMASK 寄存器有 32bit,但只有 bit0 有效,是可读可写的,将 PRIMASK 寄存器设置为 1 用于屏蔽除 NMI 和 HardFault 外的所有异常和中断,将 PRIMASK 寄存器清 0 用于使能中断。
FAULTMASK:相比于上一个,最简单来说就是这个功能屏蔽的更加厉害,只有NMI可以响应。
BASEPRI:屏蔽优先级低于某一个阈值的中断,当设置为0时,则不关闭任何中断
比如: BASEPRI设置为0x40,代表中断优先级在4~15内的均被屏蔽,0~3的中断优先级正常执行
进入临界区,以及退出临界区,就是操作BASEPRI寄存器!
//CPS指令用法:
CPSIE I /* 清除 PRIMASK = 0(使能中断) */ //开中断
CPSID I /* 设置 PRIMASK = 1(屏蔽中断) */ //关中断
三、LDR指令的格式:
LDR{条件} 目的寄存器 <存储器地址>
作用:将 存储器地址 所指地址处连续的4个字节(1个字)的数据传送到目的寄存器中。
LDR指令的寻址方式比较灵活,实例如下:
LDR R0,[R1] ;将存储器地址为R1的字数据读入寄存器R0。
LDR R0,[R1,R2] ;将存储器地址为R1+R2的字数据读入寄存器R0。
LDR R0,[R1,#8] ;将存储器地址为R1+8的字数据读入寄存器R0。
LDR R0,[R1],R2 ;将存储器地址为R1的字数据读入寄存器R0,并将R1+R2的值存入R1。
LDR R0,[R1],#8 ;将存储器地址为R1的字数据读入寄存器R0,并将R1+8的值存入R1。
LDR R0,[R1,R2]! ;将存储器地址为R1+R2的字数据读入寄存器R0,并将R1+R2的值存入R1。
LDR R0,[R1,LSL #3] ;将存储器地址为R1*8的字数据读入寄存器R0。
LDR R0,[R1,R2,LSL #2] ;将存储器地址为R1+R2*4的字数据读入寄存器R0。
LDR R0,[R1,,R2,LSL #2]! ;将存储器地址为R1+R2*4的字数据读入寄存器R0,并将R1+R2*4的值存入R1。
LDR R0,[R1],R2,LSL #2 ;将存储器地址为R1的字数据读入寄存器R0,并将R1+R2*4的值存入R1。
LDR R0,Label ;Label为程序标号,Label必须是当前指令的-4~4KB范围内。
要注意的是
LDR Rd,[Rn],#0x04 ;这里Rd不允许是R15。
另外LDRB 的指令格式与LDR相似,只不过它是将存储器地址中的8位(1个字节)读到目的寄存器中。
LDRH的指令格式也与LDR相似,它是将内存中的16位(半字)读到目的寄存器中。
LDR R0,=0xff
这里的LDR不是arm指令,而是伪指令。这个时候与MOVE很相似,只不过MOV指令后的立即数是有限制的。这个立即数必须是0X00-OXFF范围内的数经过偶数次右移得到的数,所以MOV用起来比较麻烦,因为有些数不那么容易看出来是否合法。
四、STRB指令
STRB指令的格式为:
STR{条件}B 源寄存器,<存储器地址>
STRB指令用于从源寄存器中将一个8位的字节数据传送到存储器中。该字节数据为源寄存器中的低8位。
指令示例:
STRB R0,[R1] ;将寄存器R0中的字节数据写入以R1为地址的存储器中。
STRB R0,[R1,#8] ;将寄存器R0中的字节数据写入以R1+8为地址的存储器中。
五、CPS指令用法:
CPSIE I /* 清除 PRIMASK = 0(使能中断) */ //开中断
CPSID I / * 设置 PRIMASK = 1(屏蔽中断) */ //关中断
六、NMI和Hard Fault
在STM32微控制器中,NMI代表非屏蔽中断(Non-Maskable Interrupt),而硬FAULT代表硬件错误中断(Hard Fault)。
-
非屏蔽中断(NMI)是一种特殊类型的中断,它具有最高的中断优先级,无法被其他中断打断。它用于处理严重的系统级事件,例如电源故障、存储器校验失败或外部引脚的特殊事件。由于NMI是非屏蔽的,即使处理器处于屏蔽其他中断的状态,NMI中断仍会被触发,以确保重要事件的处理。
-
硬件错误中断(Hard Fault)是由于发生了无法修复的硬件故障或软件错误而触发的中断。这可能包括未定义的指令、非法访问存储器或其他硬件错误条件。当系统发生硬件错误时,处理器会转入硬件错误处理例程,也就是硬件错误中断。在该中断处理例程中,您可以执行一些诊断操作、记录错误信息或采取适当的措施来恢复系统。
在STM32上,NMI和硬FAULT的中断优先级都非常高,因此它们可以用于处理系统中的关键事件和错误情况。