【STM32 UCOSIII】UCOSIII中断原理、以及相关指令LDR、STRB解析

目录

*注意事项

一、中断优先级寄存器

1.1 那么uC/OS-III如何配置PendSV和Systick中断优先级?

1.11 PendSV优先级的设置:

1.13 Systic优先级的设置:

二、中断相关寄存器

2.1 三个中断屏蔽寄存器

三、LDR指令的格式:

四、STRB指令

五、CPS指令用法:

六、NMI和Hard Fault


*注意事项

  • 中断函数要求响应快,时间短效率高,所以不能有太多复杂函数和任务

  • 中断可以嵌套,高优先级可以打断低优先级中断

  • 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)。

  1. 非屏蔽中断(NMI)是一种特殊类型的中断,它具有最高的中断优先级,无法被其他中断打断。它用于处理严重的系统级事件,例如电源故障、存储器校验失败或外部引脚的特殊事件。由于NMI是非屏蔽的,即使处理器处于屏蔽其他中断的状态,NMI中断仍会被触发,以确保重要事件的处理。

  2. 硬件错误中断(Hard Fault)是由于发生了无法修复的硬件故障或软件错误而触发的中断。这可能包括未定义的指令、非法访问存储器或其他硬件错误条件。当系统发生硬件错误时,处理器会转入硬件错误处理例程,也就是硬件错误中断。在该中断处理例程中,您可以执行一些诊断操作、记录错误信息或采取适当的措施来恢复系统。

在STM32上,NMI和硬FAULT的中断优先级都非常高,因此它们可以用于处理系统中的关键事件和错误情况。

猜你喜欢

转载自blog.csdn.net/dagengen12138/article/details/131284569