文章编号:554 .2798

『关闭窗口』

UCOSII AVR移植全过程及心得(zz)(JKRL)


UCOSII AVR移植全过程及心得
音乐乐乐
Stonkson@163.com
Stonkson@yahoo.com.cn

经过近一个星期的战斗,现在的ucosii终于成功的移植到了avr单片机上,我发过帖子,觉
得还是有很多朋友对这个比较感兴趣的,所以我把我记录的移植全过程及一些心得写出来与
大家分享。
出于兴趣 ,本人也想再avr单片机上跑个操作系统玩玩,大家都知道,对于这样的单片机而
言,ucosii当然是首选。
听说网上有现成的范例,偶用力搜搜搜,嘿嘿,结果搜到了两个例子,一个是8515的,另一
个是103的,陶醉中…赶紧打开ICCAvr,编译…. Faint,出了一大堆错误,修改了半天也没
弄好,没办法,还是自己移植吧。
先是买了邵贝贝翻译的那本第二版的书,躲在宿舍看了整整两天,先是完整的看一遍,从封
面到封底,除8086移植范例外一字不漏,嘿嘿,发现我看得时候基本都明白,看完了好像都
忘的差不多了 :( ,不过没关系,关键是移植嘛,对操作系统的运行原理有一些感性认识
就可以了;好,现在开始专攻移植部分,又仔细的看了一遍第13章。
准备工作做好了接下来开始动手!ucos的任务调度机制网上有很多“专著”,我就不罗嗦
了,其移植原理也比较简单,主要就是寄存器的保护合恢复。需要改写的有4个文件,
OS_CPU.h,OS_CPU.c,OS_CPU_asm.s,OS_CFG.h, 再这里合理的设计这些contex的结构是很关
键的一步。
需要修改的函数主要有一个C函数OSTaskStkInit();和4个汇编函数,OSStartHighRdy
();OSCtxSw();OSIntCtxSw();OSTickISR();
一、             误入歧途
这是我开始设计的contex结构:
OSTCB->SP——> |_________
                            |      SREG
                         |      R0
                            |      R1
                ………….
                            |      R27
                            |      R30
                            |___       R31____
       根据这样的结构,相应的移植程序如下:
OS_STK  *OSTaskStkInit (void (*task)(void *pd), void *pdata, OS_STK *ptos,
INT16U opt)
{
    INT8U *stk;
    INT8U i;
    INT16U temp;

    opt    = opt;                           /* 'opt' is not used, prevent
warning                      */
    stk    = (INT8U *)ptos;                /* Load stack pointer   */
    
    temp=(unsigned int)task;
    temp=*(const unsigned int*)temp; //////////////////////////////
    *stk-- =(unsigned char)(temp&0xff);           //save PC low  
    *stk--=(unsigned char)(temp>>8);             //Pc high
    for(i=0;i<12;i++)                       //32 General Purpose  Registers
    {                                       //Form R31R30,R27 to R18
        *stk-- = 0;                                    
    }         
    *stk-- =(unsigned char)((unsigned int )pdata>>8);             //pdata saves
in R6,R17
    *stk-- =(unsigned char)((unsigned int)pdata&0xff);
    for(i=0;i<16;i++)
    {
         *stk--=0;                           //From R15 to R0         
    }  
    *stk-- = 0x80;           //SREG initial value,Interrupt opened.        
    return ((OS_STK *)stk);
}


#define PUSH_R()       asm("PUSH R31");      asm("PUSH R30");      asm("PUSH
R27");      asm("PUSH R26");      asm("PUSH R25");      asm("PUSH R24");      
asm("PUSH R23");      asm("PUSH R22");      asm("PUSH R21");      asm("PUSH
R20");      asm("PUSH R19");      asm("PUSH R18");      asm("PUSH R17");      
asm("PUSH R16");      asm("PUSH R15");      asm("PUSH R14");      asm("PUSH
R13");      asm("PUSH R12");      asm("PUSH R11");      asm("PUSH R10");      
asm("PUSH R9");      asm("PUSH R8");      asm("PUSH R7");      asm("PUSH
R6");      asm("PUSH R5");      asm("PUSH R4");      asm("PUSH R3");      asm
("PUSH R2");      asm("PUSH R1");      asm("PUSH R0")
#define POP_R()       asm("POP R0");      asm("POP R1");      asm("POP
R2");      asm("POP R3");      asm("POP R4");      asm("POP R5");      asm("POP
R6");      asm("POP R7");      asm("POP R8");      asm("POP R9");      asm("POP
R10");      asm("POP R11");      asm("POP R12");      asm("POP R13");      asm
("POP R14");      asm("POP R15");      asm("POP R16");      asm("POP
R17");      asm("POP R18");      asm("POP R19");      asm("POP R20");      asm
("POP R21");      asm("POP R22");      asm("POP R23");      asm("POP
R24");      asm("POP R25");      asm("POP R26");      asm("POP R27");      asm
("POP R30");      asm("POP R31")

        
void OSStartHighRdy(void)
{
    unsigned char *stk_temp,*pdest;//The Middle SP Variable
    unsigned char s0,s1;
    
     OSTaskSwHook();     
     OSRunning=1;    //set flag
    stk_temp=OSTCBHighRdy->OSTCBStkPtr;
    s0=(unsigned char)((unsigned int)stk_temp&0xff);            //sp low 8bit
    s1=(unsigned char)((unsigned int)stk_temp>>8);  //sp high 8bit
    asm(
         "OUT 0x3d, %s0\n"
         "OUT 0x3e, %s1");
    asm("POP R0\n"                     //Restore SREG
         "OUT 0x3f, R0");
    POP_R();                              //Restore R0--R31
}

      
     

            
/***************************************************/       
void       OSCtxSw(void)
{
    unsigned char i,j;
    unsigned char *psrc,*next_sp;
    unsigned int temp;
    PUSH_R();     //save R31--R0
   asm("IN R0, 0x3f\n"
         "PUSH R0");  //save SREG
       asm("IN %i, 0x3d\n"
       "IN %j, 0x3e");
    temp=(j<<8)+i;
    OSTCBCur->OSTCBStkPtr=(unsigned char*)temp; //SAVE  current task sp  in
TCBcur
    OSTaskSwHook();
      OSTCBCur=OSTCBHighRdy;
      OSPrioCur=OSPrioHighRdy;
      next_sp=OSTCBHighRdy->OSTCBStkPtr;
      i=(unsigned char)((unsigned int)next_sp&0xff);
      j=(unsigned char)((unsigned int)next_sp>>8);
      asm("OUT 0x3d, %i\n"//Get sp
          "OUT 0x3e,%j" );
      asm("POP  %i \n"  /////////Restore SREG
          "OUT 0x3f,%i" );
          
    POP_R();        ///////////Restore R
}

/*******************************************************************/


void       OSIntCtxSw(void)
{
     unsigned char i,j;
     unsigned char*next_sp;
     OSTaskSwHook();
      OSTCBCur=OSTCBHighRdy;
      OSPrioCur=OSPrioHighRdy;
      next_sp=OSTCBHighRdy->OSTCBStkPtr;
      i=(unsigned char)((unsigned int)next_sp&0xff);
      j=(unsigned char)((unsigned int)next_sp>>8);
      asm("OUT 0x3d, %i\n"//Get sp
          "OUT 0x3e,%j" );
      asm("POP  %i \n"  /////////Restore SREG
          "OUT 0x3f,%i" );
          
    POP_R();        ///////////Restore R
}
/*************************************************/

#pragma interrupt_handler  OSTickISR:TIMER_INT_VECTOR
#pragma ctask OSTickISR
void       OSTickISR(void)
{
     unsigned char i,j;
     unsigned int sptemp;
     PUSH_R();     //save R31--R0
     TCNT0 = 0xb2; //reload counter value
     asm("IN R0, 0x3f\n"
         "PUSH R0");  //save SREG
     ///i=j=0;              This is used ONLY TO AVOID THE WARNING.
     OSIntNesting++;
     asm("IN %i,0x3d\n"     //Get SP Value
        "IN %j,0x3e");
     sptemp=(j<<8)+i;
     if(OSIntNesting==1)
     {
        OSTCBCur->OSTCBStkPtr=(unsigned char*)sptemp;
     }  
     OSTimeTick();
     OSIntExit();
    
     asm("POP %i\n"         //Restore SREG
         "OUT 0x3f, %i");
     POP_R();              //Restore R0--R31
}

我写了个测试程序:其中自己建立了两个任务,LED()用于控制数码管的亮与暗,
key_scan()用与判断是否按下了PA0,为了调试程序的方便,没有用OS提供的通讯机制,直
接用了一个全局变量 key_press;再任务key_scan里,当检测到按键按下时设置
key_press=1,否则设置为0;而任务LED()则根据key_press的值控制LED的亮与暗。
源程序如下:
#include "includes.h"

#define LED_ON() PORTB|=0x1
#define LED_OFF() PORTB&=0xfe
#define key_scan_StkSize 50
#define LED_StkSize 50

OS_STK LEDStk[LED_StkSize];
OS_STK key_scanStk[key_scan_StkSize];

unsigned char key_press;
void LED(void*pdata);
void key_scan(void*pdata);

void main(void)
{
    OSInit();
    OSTaskCreate(LED,(void*)0,&LEDStk[LED_StkSize-1],0);
    OSTaskCreate(key_scan,(void*)0,&key_scanStk[key_scan_StkSize-1],8);
    OSStart();
}


void LED(void*pdata)
{
     pdata=pdata;
    //OSStatInit();
    while(1)
    {
         if(key_press)
            LED_ON();
        else
            LED_OFF();            
         OSTimeDly(2);    
    }
}
void key_scan(void*pdata)
{
    while(1)
    {
         if(PINA&0x1)
             key_press=1;
        else
             key_press=0;
         OSTimeDly(1);    
    }
}
好,开始把程序下载到双龙SL-DIY02-1开发板上运行,嘿嘿,It works!又是陶醉中…※%
……%¥#¥×)(×※……¥#¥◎  哎呀,完了!死机了!!不到十分钟就死了!按下
按键LED死活不动!
再Studio上模拟跟踪反汇编后发现,#pragma ctask 对中断程序不起作用!我们来看看这会
引起什么也的后果:
       当执行定时器中断的时候,编译器会保存一些寄存器的值,如果再ISR中没有任务切
换,那么中断执行完会弹出堆栈,没有什么问题,但是如果再ISR中发生了任务切换,那么
这些被保存的寄存器就得不到恢复!使得这个堆栈变的越来越大!最后系统崩溃!!!
       这样看来,没办法,这个OSTickISR必须用汇编写了。改后的汇编如下:

TCNT = $32
   
   .macro  PUSH_ALL
     push R31
     push R30
     
     push R27
     push R26
     push R25
     push R24
     push R23
     push R22
     push R21
     push R20
     push R19
     push R18
     push R17
     push R16
     push R15
     push R14
     push R13
     push R12
     push R11
     push R10
     push R9
     push R8
     push R7
     push R6
     push R5
     push R4
     push R3
     push R2
     push R1
     push R0
     
     in   R0,     0x3f //Save SREG
     push R0
   .endmacro
   
   .macro POP_ALL
     pop  R0
    out  0x3f,   R0   //Restore SREG
     pop  R0
     pop  R1
     pop  R2
     pop  R3
     pop  R4
     pop  R5
     pop  R6
     pop  R7
     pop  R8
     pop  R9
     pop  R10
     pop  R11
     pop  R12
     pop  R13
     pop  R14
     pop  R15
     pop  R16
     pop  R17
     pop  R18
     pop  R19
     pop  R20
     pop  R21
     pop  R22
     pop  R23
     pop  R24
     pop  R25
     pop  R26
     pop  R27
     
     pop  R30
     pop  R31
   .endmacro
   
   
  _OSTickISR::

     PUSH_ALL
     ldi  R19,   0xf1;0xb2
    out  TCNT,  R19
     
     lds  R16, _OSIntNesting //OSIntNesting++;
     inc  R16
     sts  _OSIntNesting, R16
     
    cpi   R16,   1
     brne  NO_SAVE_SP
    in    R16,  0x3d       //save sp to current tcb
    in    R17,  0x3e
     sts   _OSTCBCur, R16
     sts   (_OSTCBCur+1),R17
     
NO_SAVE_SP:
     
     rcall _OSTimeTick
     rcall _OSIntExit  
     POP_ALL
     reti
重新编译运行。嘿嘿,这次好了,一天也没有死机!本以为这下子可以轻松一下,享受一下
OS的快乐了,可没想到。。。。


(文章推荐人:丁丁)

 

返回大虾论坛 返回首页