这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 综合技术 » 基础知识 » 44B0,uc,os 测试44B0上的uc/os,遇见几个奇特的问题,请教高手!

共2条 1/1 1 跳转至

44B0,uc,os 测试44B0上的uc/os,遇见几个奇特的问题,请教高手!

院士
2006-09-17 18:14:16     打赏
44B0,uc,os 测试44B0上的uc/os,遇见几个奇特的问题,请教高手!



关键词: 测试     上的     遇见     几个     奇特     问题     请教     高手    

院士
2006-12-22 22:43:00     打赏
2楼
问 硬件:三星44B0X的公板,8MB RAM,2MB FLASH ROM。

第一个问题:
   移植完成之后,在无用户任务的环境测试uc/os本身,发现系统最后并不能执行空闲任务,经过单步调试,发现OSStartHighRdy函数中,在最后恢复空闲任务的CPSR之后,会改变SP的内容,使得后面的R0~R12,LR,PC寄存器被弹出不期望的值,从而导致PC中的内容不是空闲任务的入口地址,以至程序飞掉。

关键代码:
1.main函数   //不创建任何任务,测试OS本身,(注:在OS_cfg.h中,已经将OS_TASK_STAT_EN定义成0,即表示也无OS_TaskStat任务,于是系统只剩一个空闲任务)

int Main(int argc, char **argv)
{
    OSInit();
    OSStart();
    return 0;
}
////////////////////////////////////////////////////////////////
2. 来自文件:OS_CPU_A.S
   描述:OSSart()函数末尾调用OSStartHighRdy过程来完成向优先级最高的任务的调度(由于没有创建用户任务,因此,此时调度的是空闲任务)。
   备注:问题就出在倒数第二条语句“MSR cpsr_cxsf, r4”,使得SP被改变!

      AREA    |subr|, CODE, READONLY

EXPORT     OSStartHighRdy
    IMPORT    OSTaskSwHook
    IMPORT  OSTCBHighRdy
    IMPORT  OSRunning
OSStartHighRdy
        BL     OSTaskSwHook             ; Call user-defined hook function

        LDR     r4,=OSRunning            ; Indicate that multitasking has started
        MOV     r5, #1                   
        STRB     r5, [r4]                 ; OSRunning = true

        LDR     r4, =OSTCBHighRdy        ; Get highest priority task TCB address
        LDR     r4, [r4]                 ; get stack pointer
        LDR     sp, [r4]                 ; switch to the new stack

        LDMFD     sp!, {r4}                ; pop new task s psr
        MSR     cpsr_cxsf, r4
        LDMFD     sp!, {r0-r12,lr,pc}      ; pop new task s r0-r12,lr & pc

/////////////////////////////////////////////////////////////////


3.来自文件OS_CPU_C.C  
  描述:关键代码,任务堆栈初始化函数

OS_STK * OSTaskStkInit (void (*task)(void *pd), void *pdata, OS_STK *ptos, INT16U opt)
{
    unsigned int *stk;

    opt    = opt;                           /* 'opt' is not used, prevent warning                      */
    stk    = (unsigned int *)ptos;          /* Load stack pointer                                      */

    /* build a context for the new task */
    *--stk = (unsigned int) task;       /* pc */
    *--stk = (unsigned int) task;       /* lr */

    *--stk = 0;                         /* r12 */
    *--stk = 0;                         /* r11 */
    *--stk = 0;                         /* r10 */
    *--stk = 0;                         /* r9 */
    *--stk = 0;                         /* r8 */
    *--stk = 0;                         /* r7 */
    *--stk = 0;                         /* r6 */
    *--stk = 0;                         /* r5 */
    *--stk = 0;                         /* r4 */
    *--stk = 0;                         /* r3 */
    *--stk = 0;                         /* r2 */
    *--stk = 0;                         /* r1 */
    *--stk = (unsigned int) pdata;      /* r0 */
    *--stk = (SVC32MODE|0x40);     /* cpsr  FIQ disable*/

    return ((OS_STK *)stk);
}
/////////////////////////////////////////////////////////////////


当完成44Binit.s初始化之后,程序开始执行main函数,main函数中的OSInit()函数调用OSTaskCreateExt函数,创建了一个空闲任务OS_TaskIdle(),此时我记下了OS_TaskIdle对应的地址值为0x0c001170。
  之后,OSStart()函数便开始调用OSStartHighRdy过程,开始从任务栈中恢复上下文给空闲任务OS_TaskIdle(),使得其开始运行。

问题出在这里:
OSStartHighRdy过程的最后三条语句:
        LDMFD     sp!, {r4}                ;  注释(1)
        MSR     cpsr_cxsf, r4            ;  注释(2)
        LDMFD     sp!, {r0-r12,lr,pc}      ;  注释(3)

注释(1):当此条语句执行完成之后,SP的内容为0x0c5009a0,;
注释(2):问题出现了,当执行完此语句时,SP的内容不再是0x0c5009a0,而是另外一个0x0c7fxxxx的值。此时cpsr_cxsf的值为0x60000053,和原来的一样。
注释(3):因此,就导致LDMFD sp!, {r0-r12,lr,pc}所弹出来的值并不是需要的值,PC的内容不是空闲任务OS_TaskIdle对应的地址值0x0c001170,从而程序跑飞了。

  于是我们在
        MSR     cpsr_cxsf, r4 的语句后添了一条测试语句:

        LDR       sp, =0x0c5009a0          ;添的测试语句,将sp改回来

        LDMFD     sp!, {r0-r12,lr,pc}      ;  再恢复上下文

这下单步调试OK,程序进入了空闲任务OS_TaskIdle。



由于我对ARM这几种工作模式到底优越在什么地方并不太了解,所以这个问题让我们觉得不好解释,更为疑惑的问题还在后面:


问题2:参考各位大虾的OSStartHighRdy代码,我们认为代码本身没有问题,因为我们又做了下一个测试:去掉刚才在上面的OSStartHighRdy代码中加了那条LDR       sp, =0x0c5009a0     测试语句,在main函数中创建一个简单的任务,在串口输出数据后马上调用OSTimeDly,使得空闲任务OS_TaskIdle得以运行。

而这次的测试,由于我只想单步运行来验证第一个问题,因此,我没有对时钟节拍中断进行初始化,而这个时候发现刚才还出现sp内容被更改的问题的三条语句
        LDMFD     sp!, {r4}                ;  注释(1)
        MSR     cpsr_cxsf, r4            ;  注释(2)
        LDMFD     sp!, {r0-r12,lr,pc}      ;  注释(3)

这次没有被更改,又可以正确调度task1了,即第一次执行到上面注释(3)的
LDMFD     sp!, {r0-r12,lr,pc}语句后,程序进入了task1.

我留意了一下,有一个区别是:空闲任务OS_TaskIdle是由OSTaskCreateExt函数创建的,而task1是由OSTaskCreate函数创建的。

这是一个令人头疼的问题。请高手指点!


///////////////////////////////////////////////////////

第二个问题:OSSchedLock()函数的问题使得程序跑飞。

问题描述:进入任务调度器上锁函数OSSchedLock()之后,运行ARMDisableInt()没有问题,运行到ARMEnableInt()中的MOV PC,LR就发现PC并不能返回到OSSchedLock()中去,而是执行了紧跟其后的下一条指令。
后来,我完全初始化时钟中断,并按正常的流程创建两个任务,结果程序仍然运行到OSSchedLock()函数中后就飞掉了。

#define    OS_ENTER_CRITICAL()    ARMDisableInt()
#define    OS_EXIT_CRITICAL()             ARMEnableInt()

OSSchedLock()函数调用OS_ENTER_CRITICAL()、OS_EXIT_CRITICAL()来关中断和恢复cpsr。

EXPORT     ARMDisableInt
ARMDisableInt
    MRS    r0, cpsr
    STMFD    sp!, {r0}             ; push current PSR
    ORR    r0, r0, #0xC0
    MSR    cpsr_c, r0         ; disable IRQ Int s

    MOV    pc, lr      //注释(4),运行到这里能正常返回到
                              //能正常返回到OSSchedLock()函数中去

        EXPORT     ARMEnableInt
ARMEnableInt
    LDMFD    sp!, {r0}                ; pop current PSR
    MSR    cpsr_c, r0               ; restore original cpsr    
    MOV    pc, lr     //注释(5),而运行到这里却不能返回OSSchedLock()函数,而是执行紧跟下面的DmpStk中的指令去了!

        //Dmpstk程序为网友 YJ 所添加,我移植他的代码时也没有删除此程序。
EXPORT    DmpStk
DmpStk
        LDR        r0, =Dump_Pool
        MOV        r1, sp
        MOV        r2, sp
        ADD        r2, r2, #64
DmpLoop
        LDR        r3, [r1]
        STR        r3, [r0]
        ADD        r0, r0, #4
        ADD        r1, r1, #4
        CMP        r1, r2
        BNE        DmpLoop
        MOV        pc, lr

        ALIGN
Dump_Pool    DCD        0
            DCD        0
            DCD        0
            DCD        0
            DCD        0
            DCD        0
            DCD        0
            DCD        0
            DCD        0
            DCD        0
            DCD        0
            DCD        0
            DCD        0
            DCD        0
            DCD        0
            DCD        0
            DCD        0
            DCD        0
            DCD        0
        END


//////////////////////////////////

#define    N_TASKS            5                    // Number of tasks
#define    TASK_STK_SIZE    1024                // Stack size, in sizeof OS_STK, or int 32bit

OS_STK    TaskStk[N_TASKS][TASK_STK_SIZE];    // Tasks stacks


void Task1(void *);


int Main(int argc, char **argv)
{
    int task_1 = 0;
    sys_init();          
    OSInit();
    OSTaskCreate(Task1, &task_1, &TaskStk[0][TASK_STK_SIZE-1], 1);  
    OSStart();
    return 0;
}

//  task1中,我并没有初始化时钟节拍中断,
void Task1(void * pParam)
{
        Uart_Printf(" Task1 is run!\n");
          
        while (1)
        {
             OSSchedLock();   
             Uart_Printf(" Task1 is run!\n");
             OSSchedUnlock();
        OSTimeDly(7);
        }
}



1: 我想,可能问题还是出在ARM工作模式改变的问题上这两个问题出现之前都有一条MSR指令...


刚开始学习ARM不久,有许多不懂的地方,因此请各位站友指点一下小弟,碧水长天在此先行谢过。 2: 440还没试过,不过自己在LPC2214上成功过。关键是模式的切换和中断嵌套一定要处理好,不然会出很多莫名其妙的问题 3: 不清楚,给你顶吧,11 4: 谢谢楼上的二位站友我尝试分析了一下:

在44binit.s中,并没有设置用户模式的初始化堆栈,而我觉得ARM初始化之后进入C程序之前,一般需要将处理器设为用户模式,但这里似乎并没有这样做。
而在第一个问题中,我单步执行OSStartHighRdy程序,发现引起SP改变的MSR cpsr_cxsf,r4指令确将ARM模式更改到SVC模式(因为此时我们发现r4的内容为0X60000053),那么任务堆栈的指针就改变了。不知是否跟此有关?

还望前辈们指点。
44BINIT.s中的一些代码,初始化ARM之后进入main之前,并没有将ARM设为用户模式。

    ;****************************************************
    ;*    Initialize stacks                *
    ;****************************************************
    ldr        sp, =SVCStack    ;Why?????????
    bl        InitStacks

InitStacks

    mrs        r0,cpsr
    bic        r0,r0,#MODEMASK
    orr        r1,r0,#UNDEFMODE|NOINT
    msr        cpsr_cxsf,r1        ;UndefMode
    ldr        sp,=UndefStack
    
    orr        r1,r0,#ABORTMODE|NOINT
    msr        cpsr_cxsf,r1             ;AbortMode
    ldr        sp,=AbortStack

    orr        r1,r0,#IRQMODE|NOINT
    msr        cpsr_cxsf,r1             ;IRQMode
    ldr        sp,=IRQStack
    
    orr        r1,r0,#FIQMODE|NOINT
    msr        cpsr_cxsf,r1             ;FIQMode
    ldr        sp,=FIQStack

    bic        r0,r0,#MODEMASK|NOINT
    orr        r1,r0,#SVCMODE
    msr        cpsr_cxsf,r1             ;SVCMode
    ldr        sp,=SVCStack

    ;USER mode is not initialized. 没有初始化
    mov        pc,lr ; 5: 今天又调试了一下进一步确定量问题的所在,反汇编OSSchedLock函数,发现其调用OS_EXIT_CRITICAL函数时存在问题,说明如下:
...
if(OSRunnig == TRUE){
...
     OS_ENTER_CRITICAL();

     if (OSLockNesting < 255){
        OSLockNesting ++;
     }

     OS_EXIT_CRITICAL();
[0xe8bd4010] ldmfd   r13!,{r4,r14}
[0xea000fa8] b       ARMEnableInt

编译器将此处的OS_EXIT_CRITICAL()函数编译成了两条汇编语句,而我在调试时,发现其他的恢复cpsr是的 OS_EXIT_CRITICAL()函数只汇编成一条
  bl ARMEnableInt指令!
正是此处的 ldmfd    r13!,{r4,r14}指令使得r13被改变(但观察时发现r13从调用前的0x0x500ff8竟变成了0x0c501000!),因此cpsr恢复错误,导致ARM的工作模式从SVC意外变成了USR态,使得程序出现异常。


有高手能解释一下这个现象么,谢谢。

共2条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]