STM32汇编关键字含义:
IMPORT OSxx ;//IMPORT声明了OSxx在外文件定义
EXPORT OSxx ;//EXPORT声明OSxx可以被外文件使用,相当于全局性声明
LDR R0,=label ;//这是ARM的RISC指令下一个用于内存和CPU寄存器交换数据的指令,用法比较复杂。具体百度。
;//这里的含义就是把label的地址值赋值给R0,和 LDR R0,label 不同,没有'='的是取其地址的值传递给R0
;//
LDR R0,label ;//取label其地址的值传递给R0
LDR?R0,0x12345678 ;//就是把0x12345678这个地址中的值存放到r0中
THUMB ;//THUMB指的是ARM中为提高代码密度而保有16位指令,也有THUMB指令的叫法。THUMB就是为了声明下面的是THUMB指令
;//具体要学习下ARM指令或者CM3的指令含义
关闭中断的进入关键区的定义
首先要知道ucos提供了3中关闭总中断的方法,第三中最为严密,第一种最为简单。要想知道为啥用第三种,
//OS_CRITICAL_METHOD = 1
//OS_CRITICAL_METHOD = 2
//OS_CRITICAL_METHOD = 3
#define OS_CRITICAL_METHOD 3
#if OS_CRITICAL_METHOD == 3
#define OS_ENTER_CRITICAL() {cpu_sr = OS_CPU_SR_Save();}
#define OS_EXIT_CRITICAL() {OS_CPU_SR_Restore(cpu_sr);}
#endif
OS_CPU_SR_Save和OS_CPU_SR_Restore为用汇编写的一小段代码,不多
OS_CPU_SR_Save
MRS R0, PRIMASK ;读取PRIMASK的值到R0,R0就是返回的值,将赋值给cpu_sr
CPSID I ;PRIMASK=1
BX LR
OS_CPU_SR_Restore
MSR PRIMASK, R0 ;读取R0的值赋值给PRIMASK,R0为入口参数值
BX LR
触发软件中断
PUSH {R4, R5}
LDR R4, =NVIC_INT_CTRL
那么中断后栈中是个什么情形呢,<>中9.1.1有介绍,xPSR,PC,LR,R12,R3-R0被自动保存到栈中的,R11-R4如果需要保存,只能手工保存。
中断是由系统调度 OS_Sched ()触发,其调用了 OS_TASK_SW();
void OS_Sched (void)
{
#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */
OS_CPU_SR cpu_sr = 0u;
#endif
//.................有省略
OS_TASK_SW(); /* Perform a context switch */
}
}
}
OS_EXIT_CRITICAL();
}
//在os_cpu.h中有以下宏
//任务切换宏,由汇编实现.
#define OS_TASK_SW() OSCtxSw()
OSCtxSw()是由汇编写的代码,主要是触发软件中断,在STM32中是PendSV异常中
OSCtxSw
PUSH {R4, R5}
LDR R4, =NVIC_INT_CTRL ;触发PendSV异常 (causes context switch)
LDR R5, =NVIC_PENDSVSET ;NVIC_PENDSVSET和NVIC_INT_CTRL是ASM文件下的宏定义,
STR R5, [R4]
POP {R4, R5}
BX
由于在执行OS_Sched()中是中断关闭的,执行完函数最后OS_EXIT_CRITICAL()后就会触发中断,当然根据设置的中断优先级,如果有更高优先级的未处理完,则等处理完就会
响应执行PendSV中断。
PendSV中断的处理代码如下
PendSV_Handler
CPSID I ; Prevent interruption during context switch
MRS R0, PSP ; PSP is process stack pointer 如果在用PSP堆栈,则可以忽略保存寄存器,参考CM3权威中的双堆栈-白菜注 OSIntExit()同样调用OSIntCtxSw()触发软件中断,硬件保存了R4-R11是不是【不用保存R4-R11】了呢
CBZ R0, PendSV_Handler_Nosave ; Skip register save the first time
SUBS R0, R0, #0x20 ; Save remaining regs r4-11 on process stack
STM R0, {R4-R11}
LDR R1, =OSTCBCur ; OSTCBCur->OSTCBStkPtr = SP;
LDR R1, [R1]
STR R0, [R1] ; R0 is SP of process being switched out
SUBS R0, R0, #0x20 ;为啥减的是32 ,堆栈向下生长(高地址向低地址),4*8=32
STM R0, {R4-R11} ;就是保存任务堆栈的了语句了。
;所以可见堆栈保存工作不是在任务切换中做的,而是在PendSV中断函数中处理的。
;PendSV_Handler_Nosave也是一个汇编函数。
; At this point, entire context of process has been saved
PendSV_Handler_Nosave ;实现找到当前最高优先级的任务的任务堆栈,并将其值取出来,分别赋值给R4-R11寄存器
PUSH {R14} ; Save LR exc_return value
LDR R0, =OSTaskSwHook ; OSTaskSwHook();
BLX R0 ;转向执行OSTaskSwHook();
POP {R14}
LDR R0, =OSPrioCur ; OSPrioCur = OSPrioHighRdy;
LDR R1, =OSPrioHighRdy
LDRB R2, [R1]
STRB R2, [R0] ;*R0 = R2 (OSTCBCur = OSTCBHighRdy)
LDR R0, =OSTCBCur ; OSTCBCur = OSTCBHighRdy;
LDR R1, =OSTCBHighRdy
LDR R2, [R1]
STR R2, [R0]
LDR R0, [R2] ; R0=*R2,R0 is new process SP ; SP = OSTCBHighRdy->OSTCBStkPtr,注意OSTCBStkPtr是OSTCB的第一个变量;
LDM R0, {R4-R11} ; Restore r4-11 from new process stack
ADDS R0, R0, #0x20
MSR PSP, R0 ; Load PSP with new process SP
ORR LR, LR, #0x04 ; Ensure exception return uses process stack
CPSIE I
BX LR ; Exception return will restore remaining context
end
参考资料《ucosii在STM32上的移植详解》