OS-ucos

来源:互联网 发布:被淘宝删除评价怎么办 编辑:程序博客网 时间:2024/03/29 02:26

基于44b0xucos开发,网上开源很多,可以参考,但是最有益的是一切从头自己搭建,自己调试!环境基于ADS+wiggler调试。

平台最主要的是清晰,一目了然,而且换不同cpu不同的os,代码结构不需要重大更改,比如ucos升级到新的版本,直接替换相应目录即可;比如如果应用比较大,需要更换操作系统,kernel的系统api做封装就不用担心了;比如cpu芯片更换或者升级,只需要更换相应的bsp;总之改动做到最小

搭建的环境目录如下:

ucos目录是官方os代码

bsp/common目录是ucos的基于ARM7的官方SDK

bsp/cpu目录是三星44b0x的官方SDK包,增加bsp.c文件,包含系统的外部中断处理函数,以及系统时钟的实现,延时函数,当然cpu的初始化函数port_init也在此实现

kernel目录是提供os的系统API封装,printfudelay

app目录是main函数入口,主要是多任务调度以及消息队列

file://D:/ucos2   (7 folders, 2 files, 445.72 KB, 4.46 MB in total.)

ucos.elf   234.92 KB

ucos2.mcp   210.81 KB

├─app   (0 folders, 2 files, 15.86 KB, 15.86 KB in total.)

main.c   7.64 KB

main.c.bak   8.22 KB

├─bsp   (2 folders, 0 files, 0 bytes, 125.74 KB in total.)

├─cpu   (2 folders, 0 files, 0 bytes, 67.50 KB in total.)

│├─src   (0 folders, 5 files, 37.76 KB, 37.76 KB in total.)

││44binit.s   13.63 KB

││44blib.c   8.38 KB

││bsp.c   4.87 KB

││bsp.c.bak   3.00 KB

││rtl8019.c   7.88 KB

│└─inc   (0 folders, 11 files, 29.73 KB, 29.73 KB in total.)

│44b.h   15.28 KB

│44blib.h   1.54 KB

│bsp.h   460 bytes

│bsp.h.bak   486 bytes

│def.h   434 bytes

│includes.h   1.30 KB

│Memcfg.s   2.49 KB

│Option.h   837 bytes

│Option.s   1.22 KB

│rtl8019.h   5.02 KB

│types.h   751 bytes

└─common   (3 folders, 0 files, 0 bytes, 58.24 KB in total.)

├─src   (2 folders, 1 files, 11.97 KB, 31.38 KB in total.)

│os_cpu_c.c   11.97 KB

│├─arm   (0 folders, 1 files, 9.95 KB, 9.95 KB in total.)

││os_cpu_a.S   9.95 KB

│└─gcc   (0 folders, 1 files, 9.46 KB, 9.46 KB in total.)

│os_cpu_a.Sgcc   9.46 KB

├─arm   (0 folders, 1 files, 4.04 KB, 4.04 KB in total.)

│ac_halt.c   4.04 KB

└─inc   (0 folders, 5 files, 22.82 KB, 22.82 KB in total.)

armdefs.h   2.21 KB

def.h   2.59 KB

halt.h   2.57 KB

os_cfg.h   8.15 KB

os_cpu.h   7.30 KB

├─kernel   (0 folders, 2 files, 502 bytes, 502 bytes in total.)

xkernel.c   223 bytes

xkernel.h   279 bytes

├─lwip-1.1.0   (2 folders, 4 files, 22.65 KB, 659.37 KB in total.)

.......

├─shell   (0 folders, 3 files, 36.02 KB, 36.02 KB in total.)

cmds.c   15.17 KB

shell.c   18.83 KB

shell.h   2.01 KB

├─ucos   (0 folders, 10 files, 294.83 KB, 294.83 KB in total.)

os_core.c   43.44 KB

os_flag.c   43.76 KB

os_mbox.c   23.29 KB

os_mem.c   13.79 KB

os_mutex.c   27.26 KB

os_q.c   33.79 KB

os_sem.c   19.04 KB

os_task.c   35.21 KB

os_time.c   9.68 KB

ucos_ii.h   45.59 KB

└─

1.       移植流程

内部时钟:先搭好ucosbsp,不需要修改任何文件,新建main.c,新建两个task看能否在之间调度;显然是不可能的,所以动手写的第一行代码就是系统时钟函数,新建bsp.c,作为三星的SDK的补充来用,用timer0做系统tick,定时会产生内部中断,__vT0Interrupt是中断处理函数,这里挂ucosBSPAPI就行,当然别忘记了rINTMSK = ~(BIT_GLOBAL |BIT_TIMER0); 打开timer0中断,至于中断方式是向量中断还是非向量中断方式,在interrupt文章中记录,具体配置参考注释

rTCFG0=(MCLK>>1)/1000000-1;

/*此为预分频值,MCLK为外部时钟频率 */

rTCFG1=0x00000000;

/* mux0 = 1/2 */

/*定时器0输入时钟频率=MCLK/(预分频值+1)/mux0,=MCLK/[(MCLK>>1)/1000000-1 + 1]/(1/2),计算得输入时钟频率为1M */

/*实际应用中是根据需要的输入时钟频率来赋值1000000 */      

rTCNTB0= 1000000/OS_TICKS_PER_SEC;

/*每一秒有OS_TICKS_PER_SECtick产生,这个根据实际需要更改 */ 

rTCMPB0= 0x0;

rTCON=0x2;           

rTCON=0x9;

/*内部中断控制寄存器配置 */         

pISR_TIMER0= (unsigned)__vT0Interrupt;

 

中断:有点小复杂,单独新开一篇中断的总结

中断函数添加之后,调试用的printf,就是一个最基础的驱动了

int printf(const char* pbFmt, ...)

{

   va_list pArg;

   char abString[256];

   int rv;

 

   va_start(pArg, pbFmt);

   /* 根据最后一个固定参数取可变参数表的首地址,以后可以根据该首地址逐一取各变量地址;此时pArg指向第一个可变参数 */

   rv = vsprintf(abString, pbFmt, pArg);

   /* sprintf一样*/

   Uart_SendString(abString);

   /* 调底层驱动 */

   va_end(pArg);

 

   return rv;

}

 

串口接收就需要起一个dbg_entrytask,为了方便调试,这里是porting一个命令行过来,这几个函数是从RTEMS移植过来的,可以自行添加调试命令,Uart_GetString(line)函数也可以实现记忆小功能,包括上下左右等键

 

void dbg_entry(void* Id)

{

   unsigned char line[MAX_COUNT];

   unsigned char * dbg_prompt_s ;

 

   dbg_prompt_s = (unsigned char *) "dbg> " ;

   printf("OSPrioCur = %d/n", OSPrioCur);

 

   memset(line, 0, sizeof(line));

 

   shell_add_cmd(NULL, NULL, NULL, NULL); /* init the chain list*/

   /* 这个就是porting过来的一个命令行调试函数 */

   for (; ;)

   {

       printf((char *) dbg_prompt_s);

       if (Uart_GetString(line) < 0)    /* 底层驱动函数 */

           break;         

       if ((line[0] == 0) || (line[0] == '/n'))

           continue;

       process_line(line);

       /* 这个也是porting过来的解析命令行调试函数 */

   }

}

 

内存分配:挂接预先分配好的44b0x的堆的首地址和尾地址

延时函数,因为OSTimeDly是基于tick数目来的,所以做一个封装,转换成ms可读性强的API

 

 

 

void udelay(unsigned short ms)

{

   unsigned short ucos_timeout;

 

   if(ms)

   {

       ucos_timeout = (ms * OS_TICKS_PER_SEC)/1000;

 

       if(ucos_timeout < 1)

           ucos_timeout = 1;

       else if(ucos_timeout > 65535)

           ucos_timeout = 65535;

   }

   else

   {

       ucos_timeout = 0;

   }

   OSTimeDly(ucos_timeout);

 

}

ucos的系统api,因为ucos相对简单,任务间通信不复杂的平台采用它最好不过了,任务状态也相对简单----休眠,等待,就绪,运行

首先在os_cfg.h中使能需要用到的api,这里配置至少需要任务,事件,信号量,消息队列,系统心跳数以及时钟函数

#define OS_MAX_TASKS            63    /* Max. number of tasks in your application ...                */

#define OS_FLAG_EN               1    /* Enable (1) or Disable (0) code generation for EVENT FLAGS   */

#define OS_SEM_EN                1    /* Enable (1) or Disable (0) code generation for SEMAPHORES    */

#define OS_Q_EN                  1    /* Enable (1) or Disable (0) code generation for QUEUES        */

 

#define OS_TICKS_PER_SEC       200    /* Set the number of ticks in one second                       */

#define OS_TIME_GET_SET_EN       1    /*     Include code for OSTimeGet() and OSTimeSet()            */

 

接下来就创建任务间需要传递的信号量和消息队列,当然任务也根据需要创建,注释代码如下

 

   OS_EVENT* RecTcpQFlag;   

   RecPackedFlag = OSSemCreate(0);

   /* 创建一个信号量 */

   RecUdpQFlag = OSQCreate(&RecUdpQ[0], Q_Max_Size);

   /* 创建一个消息队列,RecUdpQFlag是这个消息队列对应的事件 */

   OSTaskCreate(task1, (void *) &Id1, (OS_STK *) &Stack1[STACKSIZE - 1], 1);

   OSTaskCreate(task2, (void *) &Id2, (OS_STK *) &Stack2[STACKSIZE - 1], 2);

   /* 创建两个任务,STACKSIZE是他们的栈大小,这个时候任务处于休眠状态 */

   FRMWRK_vStartTicker(OS_TICKS_PER_SEC);  /* os_cfg.h */

   /* 起系统的tick */

   OSStart();

   /* 任务非休眠状态了,或等待或就绪或运行 */

 

task1通过UdpTemp = OSQPend(RecUdpQFlag, 0, &eer);处于等待状态,在等待在RecUdpQFlag事件,task2处于运行状态,如果这个时候task2调用一个发送消息队列的函数OSQPost(RecUdpQFlag, (void *) send_buf);task可以顺利的接收数据到UdpTemp

如果这个task2也等待一个事件,并且是在task1中发送的,那么这样就死锁了     

 

void task1(void* Id)

{

   void* UdpTemp;

   U8 eer;

   printf("OSPrioCur = %d/n", OSPrioCur);

 

 

   for (; ;)

   {

       UdpTemp = OSQPend(RecUdpQFlag, 0, &eer);

       /* 0代表tick数,最好的方法是利用(ms * OS_TICKS_PER_SEC)/1000转换一下,ms代表n毫秒,超时后如果还没有得到消息则恢复成就绪状态,并返回error,如果该值设置成零则表示任务将持续地等待消息 */

       if (eer == OS_NO_ERR)

       {

           printf("UdpTemp:0x%x", UdpTemp);

           eer = eer;

       }

   }

}

 

再结合外围接口的驱动代码和文件系统,这样整个平台就搭建起来了,就可以开工写应用代码了,用ucos做应用也只用到这些API了,也足够应付一个普通平台的设计了

 

2.       ucos的移植分析

       EXPORT  OSStartHighRdy

       EXPORT  OSCtxSw

       EXPORT  OSIntCtxSw

       EXPORT  UCOS_IRQHandler   

 

和底层相关的压栈,出栈,挂接中断函数后的处理

 

3.       小结

买公司性质的板子,服务配套好,读书时候的板子是周立功的,平台几乎都帮你搭好了,省了很多事;相反山寨一切都要自己弄,不过更能锻炼人,对整个平台细节都非常清晰

ADS中为了编写烧入flash跑的bin,采用-info totals -ro-base 0 -first 44binit.o(init) 这样烧入不成功的,跳了好久呢,没搞清楚 rorw的不同

MCLK要根据实际硬件来,要不然配置串口的时候波特率后,串口打的是乱码

OS_Q_EN默认的没开启,需要使能,要不然编译出错

uart_initportinit之前就做,因为我中断函数加了打印信息,中断初始化后中断马上来了,这个时候串口没来得及初始化

 

 

原创粉丝点击