PendSV 中断处理函数伪代码如下:
OS_CPU_PendSVHandler()
{
if (PSP != NULL) {
Save R4-R11 onto task stack;
OSTCBCur->OSTCBStkPtr = SP;
}
OSTaskSwHook();
OSPrioCur = OSPrioHighRdy;
OSTCBCur = OSTCBHighRdy;
PSP = OSTCBHighRdy->OSTCBStkPtr;
Restore
R4-R11 from new task stack;
Return
from exception;
}
OS_CPU_PendSVHandler
;xPSR, PC, LR, R12, R0-R3 已自动保存 #0
CPSID
I
;任务切换期间需要关中断
MRS
R0, PSP
;R0 = PSP
;如果 PSP ==0,跳到OS_CPU_PendSVHandler_nosave 执行 #1
CBZ
R0, OS_CPU_PendSVHandler_nosave
;保存 R4-R11 到任务堆栈
SUBS
R0, R0, #0x20
;R0 -= 0x20
STM
R0, {R4-R11}
;保存 R4-R11 到任务堆栈
;OSTCBCur->OSTCBStkPtr = SP;
LDR
R1, =OSTCBCur
;R1 = &OSTCBCur
LDR
R1, [R1]
;R1 = *R1 (R1 = OSTCBCur)
STR
R0, [R1]
;*R1 = R0 (*OSTCBCur = SP) #2
OS_CPU_PendSVHandler_nosave
;调用 OSTaskSwHook()
PUSH
{R14}
;保存 R14,因为后面要调用函数
LDR
R0, =OSTaskSwHook
;R0 = &OSTaskSwHook
BLX
R0
;调用 OSTaskSwHook()
POP
{R14}
;恢复 R14
;OSPrioCur = OSPrioHighRdy;
LDR
R0, =OSPrioCur
;R0 = &OSPrioCur
LDR
R1, =OSPrioHighRdy
;R1 = &OSPrioHighRdy
LDRB
R2, [R1]
;R2 = *R1 (R2 = OSPrioHighRdy)
STRB
R2, [R0]
;*R0 = R2 (OSPrioCur = OSPrioHighRdy)
;OSTCBCur = OSTCBHighRdy;
LDR
R0, =OSTCBCur
;R0 = &OSTCBCur
LDR
R1, =OSTCBHighRdy
;R1 = &OSTCBHighRdy
LDR
R2, [R1]
;R2 = *R1 (R2 = OSTCBHighRdy)
STR
R2, [R0]
;*R0 = R2 (OSTCBCur = OSTCBHighRdy)
LDR
R0, [R2]
;R0 = *R2 (R0 = OSTCBHighRdy), 此时 R0 是新任务的 SP
;SP = OSTCBHighRdy->OSTCBStkPtr
#3
LDM
R0, {R4-R11}
;从任务堆栈 SP 恢复 R4-R11
ADDS
R0, R0, #0x20
;R0 += 0x20
MSR
PSP, R0
;PSP = R0,用新任务的 SP 加载PSP
ORR
LR, LR, #0x04
;确保 LR 位2 为1,返回后使用进程堆栈 #4
CPSIE
I
;开中断
BX
LR
;中断返回
END
#0 OS_CPU_PendSVHandler 要替换为 PendSV_Handler。

#1 如果 PSP==0,说明OSStartHighRdy()启动后第一次做任务切换,而任务刚创建时 R4-R11 已经保存在堆栈中了,所以不需要再保存一次了。
#2 OSTCBStkPtr 是任务控制块结构体的第一个变量,所以*OSTCBCur = SP(不是很科学)就是
OSTCBCur->OSTCBStkPtr = SP;
#3 和#2 类似。
#4 因为在中断处理函数中使用的是 MSP,所以在返回任务后必须使用PSP,所以LR位2必须为1。
os_dbg.c
用于系统调试,可以不管。
需要修改的代码就介绍到这里,如果还有不明白之处,就再看看 AN-1018.pdf,邵老师的书和<
Cortex-M3 权威指南>>。
App.c
App.c文件中建立如下函数
App文件中有对 SysTick的初始化函数(上面已经解释过)。
static void systick_init(void); //函数声明
static void systick_init(void)
{
RCC_ClocksTypeDef
rcc_clocks;
RCC_GetClocksFreq(&rcc_clocks);
//调用标准库函数,获取系统时钟。
SysTick_Config(rcc_clocks.HCLK_Frequency / OS_TICKS_PER_SEC);
//调用库函数,初始化并使能 SysTick
//OS_TICKS_PER_SEC是在 os_cfg.h 中定义的
}
os_cfg.h 是用来配置 ucosii 系统的,对其做如下修改:
共9处
#define
OS_APP_HOOKS_EN
0
//关掉App 钩子功能
#define
OS_DEBUG_EN
0
//关掉uC/OS 自带调试功能
#define
OS_EVENT_MULTI_EN
0
//
#define
OS_SCHED_LOCK_EN
0
//关掉调度加锁功能
#define
OS_TASK_CHANGE_PRIO_EN
0
//关掉改变任务优先级功能
#define
OS_TASK_QUERY_EN
0
//关掉任务查询功能
#define
OS_TASK_STAT_EN
0
//关掉 CPU 使用率统计功能
#define
OS_TASK_STAT_STK_CHK_EN
0
//关掉 CPU 使用率统计功能的堆栈设置
#define
OS_TASK_SUSPEND_EN
0
//关掉任务挂起功能
所做的修改主要是把一些功能给去掉,减少内核大小,也利于调试。等移植完成后,如果需要该功能,
再做开启。
最后,还要记得把stm32f10x_it.h文件中的void PendSV_Handler(void);注释掉,以防和 OS_CPU.HH
文件中的声明冲突,stm32f10x_it.c 中的相应函数体也得注释掉。如图:


注释掉多余的PendSV 声明
关键词:
移植ucosIISTM32F103Z
加入微信
获取电子行业最新资讯
搜索微信公众号:EEPW
或用微信扫描左侧二维码