compiling ucos_ii.c...解决方法:将ucos_ii.c 从工程中移除。
linking...
.\out\test.axf: Error: L6200E: Symbol OSEventTbl multiply defined (by ucos_ii.o and os_core.o).
.\out\test.axf: Error: L6200E: Symbol OSFlagTbl multiply defined (by ucos_ii.o and os_core.o).
.\out\test.axf: Error: L6200E: Symbol OSTaskStatStk multiply defined (by ucos_ii.o and os_core.o).
.\out\test.axf: Error: L6200E: Symbol OSRdyTbl multiply defined (by ucos_ii.o and os_core.o).
.\out\test.axf: Error: L6200E: Symbol OSTaskIdleStk multiply defined (by ucos_ii.o and os_core.o).
.\out\test.axf: Error: L6200E: Symbol OSTCBPrioTbl multiply defined (by ucos_ii.o and os_core.o).
.\out\test.axf: Error: L6200E: Symbol OSTCBTbl multiply defined (by ucos_ii.o and os_core.o).
.... 还有很多
typedef unsigned char BOOLEAN;
typedef unsigned char INT8U; /* Unsigned 8 bit quantity */
typedef signed char INT8S; /* Signed 8 bit quantity */
typedef unsigned short INT16U; /* Unsigned 16 bit quantity */
typedef signed short INT16S; /* Signed 16 bit quantity */
typedef unsigned int INT32U; /* Unsigned 32 bit quantity */
typedef signed int INT32S; /* Signed 32 bit quantity */
typedef float FP32; /* Single precision floating point */
typedef double FP64; /* Double precision floating point */
typedef unsigned int OS_STK; /* Each stack entry is 32-bit wide */
typedef unsigned int OS_CPU_SR; /* Define size of CPU status register (PSR = 32 bits) */
#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);}
3、定义栈的生长方式#endif
#if OS_CRITICAL_METHOD == 3 /* See OS_CPU_A.ASM */6、声明函数 这些函数都是要自己实现或修改
OS_CPU_SR OS_CPU_SR_Save(void);
void OS_CPU_SR_Restore(OS_CPU_SR cpu_sr);#endif
void OSCtxSw(void); // 任务级切换 触发PendSV异常
void OSIntCtxSw(void); // 中断级切换 触发PendSV异常
void OSStartHighRdy(void); // 运行最高优先级的任务
void OS_CPU_PendSVHandler(void); // 发生PendSV异常时被触发,OSCtxSw()、OSIntCtxSw() 最终实现 即任务切换
void OS_CPU_SysTickHandler(void); /* See OS_CPU_C.C */
void OS_CPU_SysTickInit(void); // 系统时钟节拍初始化 用于任务切换
INT32U OS_CPU_SysTickClkFreq(void); /* See BSP.C OS_CPU_SysTickInit(void);用来获得硬件的时钟频率,这里是直接指定并没有用上。*/
OS_CPU_PendSVHandler(void)、OS_CPU_SysTickHandler(void) 需要在 startup_LPC11xx.s 定义
// 创建任务时被调用 初始化任务堆栈 具体实现不是很明白2、实现 void OS_CPU_SysTickInit (void)、void OS_CPU_SysTickHandler (void)
OS_STK *OSTaskStkInit (void (*task)(void *p_arg), void *p_arg, OS_STK *ptos, INT16U opt)
{
OS_STK *stk;
(void)opt; /* 'opt' is not used, prevent warning */
stk = ptos; /* Load stack pointer 获取堆栈指针 */
/* Registers stacked as if auto-saved on exception */
*(stk) = (INT32U)0x01000000L; /* xPSR */
*(--stk) = (INT32U)task; /* Entry Point 保存任务函数地址 */
*(--stk) = (INT32U)0xFFFFFFFEL; /* R14 (LR) (init value will cause fault if ever used)*/
*(--stk) = (INT32U)0x12121212L; /* R12 */
*(--stk) = (INT32U)0x03030303L; /* R3 */
*(--stk) = (INT32U)0x02020202L; /* R2 */
*(--stk) = (INT32U)0x01010101L; /* R1 */
*(--stk) = (INT32U)p_arg; /* R0 : argument 保存参数 */
/* Remaining registers saved on process stack */
*(--stk) = (INT32U)0x11111111L; /* R11 */
*(--stk) = (INT32U)0x10101010L; /* R10 */
*(--stk) = (INT32U)0x09090909L; /* R9 */
*(--stk) = (INT32U)0x08080808L; /* R8 */
*(--stk) = (INT32U)0x07070707L; /* R7 */
*(--stk) = (INT32U)0x06060606L; /* R6 */
*(--stk) = (INT32U)0x05050505L; /* R5 */
*(--stk) = (INT32U)0x04040404L; /* R4 */
return (stk);
}
void OS_CPU_SysTickInit (void)
{
INT32U cnts;
/* cnts = OS_CPU_SysTickClkFreq() / OS_TICKS_PER_SEC; */
cnts = 48000000 / OS_TICKS_PER_SEC; // OS_TICKS_PER_SEC 10ms 产生一次中断
OS_CPU_CM3_NVIC_ST_RELOAD = (cnts - 1);
OS_CPU_CM3_NVIC_ST_CURRENT = 0;
/* Set Priority of SysTick to 2 (0-3, 0 is highest) */
cnts = OS_CPU_CM0_NVIC_SHPR3;
cnts &= 0x00FFFFFF;
cnts |= 0x80000000;
OS_CPU_CM0_NVIC_SHPR3 = cnts;
/* Enable timer. */
OS_CPU_CM3_NVIC_ST_CTRL |= OS_CPU_CM3_NVIC_ST_CTRL_CLK_SRC | OS_CPU_CM3_NVIC_ST_CTRL_ENABLE;
/* Enable timer interrupt. */
OS_CPU_CM3_NVIC_ST_CTRL |= OS_CPU_CM3_NVIC_ST_CTRL_INTEN;
}
void OS_CPU_SysTickHandler (void)
{
OS_CPU_SR cpu_sr;
OS_ENTER_CRITICAL(); /* Tell uC/OS-II that we are starting an ISR */
OSIntNesting++;
OS_EXIT_CRITICAL();
OSTimeTick(); /* Call uC/OS-II's OSTimeTick() */
OSIntExit(); /* Tell uC/OS-II that we are leaving the ISR */
}
NVIC_SCB_SHPR3 EQU 0xE000ED202、实现 OS_CPU_SR_Save()、OS_CPU_SR_Restore()、OSStartHighRdy()、OSCtxSw()、OSIntCtxSw()、OS_CPU_PendSVHandler()
NVIC_PENDSV_PRI EQU 0x00FF0000
NVIC_PENDSVSET EQU 0x10000000 ; Value to trigger PendSV exception.
OS_CPU_SR_Save ; 保存中断状态 MRS R0, PRIMASK ; Set prio int mask to mask all (except faults) CPSID I BX LR
OS_CPU_SR_Restore ; 恢复中断状态 MSR PRIMASK, R0 BX LR
// 实现 OSStartHighRdy()
// 启动优先级最高的任务
OSStartHighRdy; 设置PendSV 异常优先级为最低
; 初始化PSP设置为 0 MOVS R0, #0 ; Set the PSP to 0 for initial context switch call MSR PSP, R0 ; PSP为0 告诉上下文切换,这是第一次运行
; 设置 任务运行状态为 1 LDR R0, =OSRunning ; OSRunning = TRUE MOVS R1, #1 STRB R1, [R0]
; 触发PendSV 异常,实现任务切换 LDR R0, =NVIC_INT_CTRL ; Trigger the PendSV exception (causes context switch) LDR R1, =NVIC_PENDSVSET STR R1, [R0]
; PendSV 异常处理函数会关闭中断,所以需要开中断 CPSIE I ; 使能中断 Enable interrupts at processor level
OSStartHang B OSStartHang ; Should never get here
[size=14.44444465637207px]// 实现 OSCtxSw() 任务级切换任务
// 触发PendSV 异常,实现任务切换
OSCtxSw LDR R0, =NVIC_INT_CTRL ; Trigger the PendSV exception (causes context switch) LDR R1, =NVIC_PENDSVSET STR R1, [R0] BX LR
[size=14.44444465637207px]// 实现 OSIntCtxSw() 中断级切换任务
// 触发PendSV 异常,实现任务切换
OSIntCtxSw
LDR R0, =NVIC_INT_CTRL ; Trigger the PendSV exception (causes context switch)
LDR R1, =NVIC_PENDSVSET
STR R1, [R0]
BX LR
;/* Pendsv 中断函数 */
;/* 用于实现时间片轮转法 中断级任务调度、任务级中断调度 切换上下文*/
; 进入PendSV时:
; xPSR、PC、LR、R12、R0~R3 已经在处理栈中被保存
; 处理模式切换到线程模式
; 栈是主堆栈
OS_CPU_PendSVHandler
CPSID I ; 关闭中断,避免上下文切换时发送中断。
MRS R0, PSP ; PSP is process stack pointer
;CBZ R0, OS_CPU_PendSVHandler_nosave ; Skip register save the first time
cmp r0, #0 ; 如果获取任务的SP 为0 则跳到 OS_CPU_PendSVHandler_nosave
beq OS_CPU_PendSVHandler_nosave
; 保存R3~R11和SP
SUBS R0, R0, #0x20 ; Save remaining regs r4-11 on process stack
stm r0!, {r4-r7}
mov r1, r8
mov r2, r9
mov r3, r10
mov r4, r11
stm r0!, {r1-r4}
subs r0, r0, #0x20
; 将当前的堆栈指针给当前进程的任务块
LDR R1, =OSTCBCur ; OSTCBCur->OSTCBStkPtr = SP;
LDR R1, [R1]
STR R0, [R1] ; R0 is SP of process being switched out
; At this point, entire context of process has been saved
OS_CPU_PendSVHandler_nosave
; 调用 OSTaskSwHook() 函数 用于扩展
mov r0, lr
push {r0}
ldr r0, =OSTaskSwHook
blx r0
pop {r0}
mov lr, r0
; 获取当前最高优先级的任务
LDR R0, =OSPrioCur ; OSPrioCur = OSPrioHighRdy;
LDR R1, =OSPrioHighRdy
LDRB R2, [R1]
STRB R2, [R0]
; 获取当前就绪的线程
LDR R0, =OSTCBCur ; OSTCBCur = OSTCBHighRdy;
LDR R1, =OSTCBHighRdy
LDR R2, [R1]
STR R2, [R0]
; 得到新任务的SP和线程恢复 R4~R11
LDR R0, [R2] ; R0 is new process SP; SP = OSTCBHighRdy->OSTCBStkPtr;
ldm r0!, {r4-r7}
ldm r0!, {r1-r3}
mov r8, r1
mov r9, r2
mov r10, r3
ldm r0!, {r1}
mov r11, r1
; 载入新的SP和返回
MSR PSP, R0 ; Load PSP with new process SP
mov r0, lr
movs r1, #0x04
orrs r0, r0, r1
mov lr, r0
CPSIE I ; 开启中断
BX LR ; Exception return will restore remaining context
b .
END
移植uCOS II 的难点在于:函数的实现。
总结:
OS_CPU_C.C:
void OS_CPU_SysTickInit (void)、void OS_CPU_SysTickHandler (void)
任务调度,产生系统时钟节拍,每一次节拍就切换一次当前就绪表中优先级最高的任务
OS_CPU_A.S:
OS_CPU_SR_Save()、OS_CPU_SR_Restore():
用于任务保存和恢复自身的中断状态。用于临界区代码。
OSStartHighRdy():
寻找就绪表中优先级最高的任务。
OSCtxSw()、OSIntCtxSw()、OS_CPU_PendSVHandler()
OSCtxSw()、OSIntCtxSw()都是通过触发PendSV异常进行任务切换
OSCtxSw():一般是在任务调用延时函数 如OSTimeDlyHMSM(0, 0, 0, 300); 时调用的。
OSIntCtxSw():一般用在系统时钟节拍中断时,会采用这种方式调度新的任务。
OS_CPU_PendSVHandler() 产生异常PendSV异常就进行一次任务切换
欢迎光临 (http://www.51hei.com/bbs/) | Powered by Discuz! X3.1 |