新闻中心

EEPW首页>嵌入式系统>设计应用> 移植ucosII到STM32F103ZE(五)

移植ucosII到STM32F103ZE(五)

作者: 时间:2016-11-25 来源:网络 收藏
os_cpu_a.asm
这个文件包含着必须用汇编写的代码。
EXTERNOSRunning; External references
EXTERNOSPrioCur
EXTERNOSPrioHighRdy
EXTERNOSTCBCur
EXTERNOSTCBHighRdy
EXTERNOSIntNesting
EXTERNOSIntExit
EXTERNOSTaskSwHook
申明这些变量是在其他文件定义的,本文件只做引用(有几个好像并未引用,不过没有关系)。
EXPORTOS_CPU_SR_Save; Functions declared in this file
EXPORTOS_CPU_SR_Restore
EXPORTOSStartHighRdy
EXPORTOSCtxSw
EXPORTOSIntCtxSw
EXPORTOS_CPU_PendSVHandler; #0
#0这里 OS_CPU_PendSVHandler 要替换为PendSV_Handler;如下图:

替换后的 PPendSV中断
声明这些函数是在本文件中定义的。EXPORT这个关键字是跟编译器有关的,能被keil识别,但不能被IAR 识别。
NVIC_INT_CTTRLEQU0xE000ED04;中断控制及状态寄存器 ICSR 的地址
NVIC_SYSPRI14EQU0xE000ED22;PendSV优先级寄存器的地址
NVIC_PENDSV_PRIEQU00xFF; PendSV 中断的优先级为 255(最低)
NVIC_PENDSVSETEQU0x10000000; 位 28 为 1
;定义几个常量,类似 C 语言中的#define预处理指令。
S_CPU_SR_Save
MRSR0, PRIMASK;读取 PRIMASK 到R0 中,R0 为返回值
CPSIDI;PRIMASK=1,关中断(NMI 和硬 fault 可以响应)
BXLR;返回

OS_CPU_SR_Restore
MSRPRIMASK, R0;读取 R0 到PRIMASK 中,R0 为参数
BXLR;返回

OSStartHighRdy()由 OSStart()调用,用来启动最高优先级任务,当然任务必须在OSStart()前已被创建。
OSStartHighRdy
;设置 PendSV 中断的优先级 #1
LDRR0, =NVIC_SYSPRI14;R0 = NVIC_SYSPRI14
LDRR1, =NVIC_PENDSV_PRI;R1 = NVIC_PENDSV_PRI
STRBR1, [R0]; *(uint8_t *)NVIC_SYSPRI14 = NVIC_PENDSV_PRI
;设置 PSP 为0#2
MOVSR0, #0;R0 = 0
MSRPSP, R0;PSP = R0
;设置 OSRunning 为TRUE
LDRR0, =OSRunning;R0 = OSRunning
MOVSR1, #1;R1 = 1
STRBR1, [R0];OSRunning = 1
;触发 PendSV 中断 #3
LDRR0, =NVIC_INT_CTRL;R0 = NVIC_INT_CTRL
LDRR1, =NVIC_PENDSVSET;R1 = NVIC_PENDSVSET
STRR1, [R0]; *(uint32_t *)NVIC_INT_CTRL = NVIC_PENDSVSET
CPSIEI;开中断
OSStartHang
;死循环,应该不会到这里
BOSStartHang
#1.PendSV 中断的优先级应该为最低优先级,原因在<>的 7.6 节已有说明。
#2.PSP 设置为 0,是告诉具体的任务切换程序(OS_CPU_PendSVHandler()),这是第一次任务切换。做过切换后 PSP 就不会为0了,后面会看到。
#3.往中断控制及状态寄存器 ICSR(0xE000ED04)第 28 位写 1 即可产生 PendSV 中断。这个<>8.4.5 其它异常的配置寄存器有说明。
当一个任务放弃 cpu 的使用权,就会调用OS_TASK_SW()宏,而 OS_TASK_SW()就是 OSCtxSw()。OSCtxSw()应该做任务切换。但是在 CM3 中,所有任务切换都被放到PendSV 的中断处理函数中去做了,因此 OSCtxSw() 只需简单的触发 PendSV中断即可。OS_TASK_SW()是由OS_Sched()调用。
voidOS_Sched (void)
{
# ifOS_CRITICAL_METHOD==3
OS_CPU_SRcpu_sr = 0;
#endif
OS_ENTER_CRITICAL();

if (OSIntNesting ==0) {
if (OSLockNesting == 0) {
OS_SchedNew();
if (OSPrioHighRdy != OSPrioCur)
{
OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];
#if OS_TASK_PROFILE_EN > 0
OSTCBHighRdy->OSTCBCtxSwCtr++;
#endif
OSCtxSwCtr++;
OS_TASK_SW();
}
}
}

OS_EXIT_CRITICAL();
}

OSCtxSw;触发PendSV 中断
LDRR0, =NVIC_INT_CTRL;R0 = NVIC_INT_CTRL
LDRR1, =NVIC_PENDSVSET;R1 = NVIC_PENDSVSET
STRR1, [R0];*(uint32_t *)NVIC_INT_CTRL = NVIC_PENDSVSET
BXLR;返回
当一个中断处理函数退出时,OSIntExit()会被调用来决定是否有优先级更高的任务需要执行。如果有
OSIntExit()对调用 OSIntCtxSw()做任务切换。
OSIntCtxSw;触发 PendSV 中断
LDRR0, =NVIC_INT_CTRL
LDRR1, =NVIC_PENDSVSET
STRR1, [R0]
BXLR
看到这里有人可能奇怪怎么 OSCtxSw()和OSIntCtxSw()完全一样,事实上,这两个函数的意义是不一样的,OSCtxSw()做的是任务之间的切换,如任务 A 因为等待某个资源或是做延时切换到任务 B,而
OSIntCtxSw()则是中断退出时,由中断状态切换到另一个任务。由中断切换到任务时,CPU 寄存器入栈的工作已经做完了,所以无需做第二次了(参考邵老师书的 3.10 节)。这里只不过由于 CM3 的特殊机制导致了在这两个函数中只要做触发 PendSV中断即可,具体切换由 PendSV 中断来处理。
前面已经说过真正的任务切换是在 PendSV 中断处理函数里做的,由于 CM3 在中断时会有一半的寄存器自动保存到任务堆栈里,所以在 PendSV 中断处理函数中只需保存 R4-R11并调节堆栈指针即可。

上一页 1 2 下一页

评论


技术专区

关闭