|
目的:基本的任务能在目标板上跑起来
经过一段时间的摸索基本完成的了既定的任务,下面有些我的体会和疑惑和大家一起分享
1.从uCOS官方网站上下了LPC2378的代码基本拿来就能用,只是在外设上与少许的不同(比如led灯)
但从学习的角度出发没有这样做,而是自己独立建立工程,一步步的移植。由于uCOS的可移植性
很好,所以工作量不大,而且邵贝贝那本书对移植也说的很清楚。
2.首先,从启动的*.s文件入手。基本上很简单,大家要注意的是中断表的处理。
Keil for arm 的默认启动文件是这样的
Vectors LDR PC, Reset_Addr
LDR PC, Undef_Addr
LDR PC, SWI_Addr
LDR PC, PAbt_Addr
LDR PC, DAbt_Addr
NOP ; Reserved Vector
;LDR PC, IRQ_Addr 这个别注释掉了
LDR PC, [PC, #-0x0120] ; Vector from VicVectAddr
LDR PC, FIQ_Addr
其中特别有意思的是 LDR PC, [PC, #-0x0120],因为它取代了我们比较熟悉的 LDR PC, IRQ_Addr
其原因就是LCP23XX系统的arm7有个内部VIC,其中断发生后都由它来处理,做第二次跳转,而这个内部的VIC的寄存器
地址是0xFFFF FF00。IQR响应地址为0x0000 0020.(0x0000 0020 - 0x0000 0120 = 0xFFFF FF00) 所以,LDR PC, [PC, #-0x0120],
就正好跳到了要到的地方。真是个不错的方法,当uCOSII的标准做法就不是这样的了,他仍然是采用了LDR PC, IRQ_Addr
代码如下:
Vectors
ldr pc, Reset_Addr
ldr pc, Undef_Addr
ldr pc, SWI_Addr
ldr pc, Prefetch_Addr
ldr pc, Abort_Addr
nop
ldr pc, IRQ_Addr
ldr pc, FIQ_Addr
Reset_Addr dcd ResetHndlr
Undef_Addr dcd OS_CPU_ARM_ExceptUndefInstrHndlr
SWI_Addr dcd OS_CPU_ARM_ExceptSwiHndlr
Prefetch_Addr dcd OS_CPU_ARM_ExceptPrefetchAbortHndlr
Abort_Addr dcd OS_CPU_ARM_ExceptDataAbortHndlr
nop
IRQ_Addr dcd OS_CPU_ARM_ExceptIrqHndlr
FIQ_Addr dcd OS_CPU_ARM_ExceptFiqHndlr
大家会发现他是跳到了 OS_CPU_ARM_ExceptIrqHndlr 这个地方去了,具体位置写到另一个汇编文件中,代码为
OS_CPU_ARM_ExceptIrqHndlr
SUB LR, LR, #4 ; LR offset to return from this exception: -4.
STMFD SP!, {R0-R12, LR} ; Push working registers.
MOV R3, LR ; Save link register.
MOV R0, #OS_CPU_ARM_EXCEPT_IRQ ; Set exception ID to OS_CPU_ARM_EXCEPT_IRQ.
B OS_CPU_ARM_ExceptHndlr
这是一个就有了一个参数“OS_CPU_ARM_EXCEPT_IRQ”,通过R0,传给了一个C程序,代码为
void OS_CPU_ExceptHndlr (CPU_DATA except_id)
{
CPU_FNCT_VOID pfnct;
CPU_INT32U *sp;
if ((except_id == OS_CPU_ARM_EXCEPT_IRQ) || (except_id == OS_CPU_ARM_EXCEPT_FIQ)) {
pfnct = (CPU_FNCT_VOID)VICAddress; /* Read the interrupt vector from the VIC */
if (pfnct != (CPU_FNCT_VOID)0) { /* Make sure we don't have a NULL pointer */
(*pfnct)(); /* Execute the ISR for the interrupting device */
VICAddress = 1; /* Acknowlege the VIC interrupt */
}
} else {
sp = (CPU_INT32U *)OSTCBCur->OSTCBStkPtr;
APP_TRACE_INFO(("\nCPU_ARM_EXCEPTION #%d trapped.\n", except_id));
APP_TRACE_INFO(("R0 : 0x%08x\n", *(sp + 0x01)));
APP_TRACE_INFO(("R1 : 0x%08x\n", *(sp + 0x02)));
APP_TRACE_INFO(("R2 : 0x%08x\n", *(sp + 0x03)));
APP_TRACE_INFO(("R3 : 0x%08x\n", *(sp + 0x04)));
APP_TRACE_INFO(("R4 : 0x%08x\n", *(sp + 0x05)));
APP_TRACE_INFO(("R5 : 0x%08x\n", *(sp + 0x06)));
APP_TRACE_INFO(("R6 : 0x%08x\n", *(sp + 0x07)));
APP_TRACE_INFO(("R7 : 0x%08x\n", *(sp + 0x08)));
APP_TRACE_INFO(("R8 : 0x%08x\n", *(sp + 0x09)));
APP_TRACE_INFO(("R9 : 0x%08x\n", *(sp + 0x0A)));
APP_TRACE_INFO(("R10 : 0x%08x\n", *(sp + 0x0B)));
APP_TRACE_INFO(("R11 : 0x%08x\n", *(sp + 0x0C)));
APP_TRACE_INFO(("R12 : 0x%08x\n", *(sp + 0x0D)));
APP_TRACE_INFO(("SP : 0x%08x\n", sp));
APP_TRACE_INFO(("LR : 0x%08x\n", *(sp + 0x0E)));
APP_TRACE_INFO(("PC : 0x%08x\n", *(sp + 0x0F)));
APP_TRACE_INFO(("CPSR: 0x%08x\n", *(sp + 0x00)));
while (DEF_TRUE) {
;
}
}
}
这就是uCOS对于中断的处理。
3.书上说的OSTickISQ()这个用来产生节拍信号的函数没有了。别一个时钟中断处理程序取代了。下面是初始化时钟中断和中断处理函数的代码
static void Tmr_TickInit (void)
{
CPU_INT32U pclk_freq;
CPU_INT32U rld_cnts;
/* VIC timer #0 Initialization */
VICIntSelect &= ~(1 << VIC_TIMER0); /* Configure the timer interrupt as an IRQ source */
VICVectAddr4 = (CPU_INT32U)Tmr_TickISR_Handler; /* Set the vector address */
VICIntEnable = (1 << VIC_TIMER0); /* Enable the timer interrupt source */
pclk_freq = BSP_CPU_PclkFreq(PCLK_TIMER0); /* Get the peripheral clock frequency */
rld_cnts = pclk_freq / OS_TICKS_PER_SEC; /* Calculate the # of counts necessary for the OS ticker */
T0TCR = (1 << 1); /* Disable and reset counter 0 and the prescale counter 0 */
T0TCR = 0; /* Clear the reset bit */
T0PC = 0; /* Prescaler is set to no division */
T0MR0 = rld_cnts;
T0MCR = 3; /* Interrupt on MR0 (reset TC), stop TC */
T0CCR = 0; /* Capture is disabled. */
T0EMR = 0; /* No external match output. */
T0TCR = 1; /* Enable timer 0 */
}
void Tmr_TickISR_Handler (void)
{
T0IR = 0xFF; /* Clear timer #0 interrupt */
OSTimeTick(); /* Call uC/OS-II's OSTimeTick() */
}
4.在移植的过程中遇到了一个我百思不得其解的问题。就是我移植完成以后,进入不到main(),单步仿真后发现
在进入main()前keil for arm 的编译器增加了很多代码,个人理解为:为C程序的运行建立必要的环境。可我
移植的程序一到这里就跑飞了,不知道做什么去了。在这里郁闷了很长时间,后来经过仔细的调试,发现在我的
程序中出现了一天软中断语句 SWI ,这就让程序自动跳到了的中断处理程序中,大家通过看上面的中断处理程序
就能发现如果不是IRQ或者FIQ中断,就会进入到APP_TRACE_INFO(("R0 : 0x%08x\n", *(sp + 0x01)));等这些,保护
报错部分。而到了这里程序就跑飞了。直接把响应的所以APP_TRACE_INFO。。。。都删除后。问题就解决了,而且
再也没出现SWI这样的软中断,我彻底无语了。那位高手能解释一下进入main()前keil for arm 的编译器增加了很多代码
到底做了些什么(我的汇编水平实在有限,想看都看不下去,呵呵),还有我出现的这个怪问题到底是什么原因产生的
5.那位高手能解释一下进入main()前keil for arm 的编译器增加了很多代码 到底做了些什么(我的汇编水平实在有限,
想看都看不下去,呵呵),还有我出现的这个怪问题到底是什么原因产生的,谢谢!
6.最后,做了两个独立的任务,去闪灯
这是源代码ourdev_428707.rar(文件大小:642K) (原文件名:myucos.rar) |
阿莫论坛20周年了!感谢大家的支持与爱护!!
知道什么是神吗?其实神本来也是人,只不过神做了人做不到的事情 所以才成了神。 (头文字D, 杜汶泽)
|