最新消息: USBMI致力于为网友们分享Windows、安卓、IOS等主流手机系统相关的资讯以及评测、同时提供相关教程、应用、软件下载等服务。

OS

互联网 admin 23浏览 0评论

OS

基于44b0x的ucos开发,网上开源很多,可以参考,但是最有益的是一切从头自己搭建,自己调试!环境基于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封装,printf,udelay等

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.        移植流程

内部时钟:先搭好ucos和bsp,不需要修改任何文件,新建main.c,新建两个task看能否在之间调度;显然是不可能的,所以动手写的第一行代码就是系统时钟函数,新建bsp.c,作为三星的SDK的补充来用,用timer0做系统tick,定时会产生内部中断,__vT0Interrupt是中断处理函数,这里挂ucos的BSP的API就行,当然别忘记了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_SEC个tick产生,这个根据实际需要更改 */ 

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_entry的task,为了方便调试,这里是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) 这样烧入不成功的,跳了好久呢,没搞清楚 ro和rw的不同

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

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

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

 

 

OS

基于44b0x的ucos开发,网上开源很多,可以参考,但是最有益的是一切从头自己搭建,自己调试!环境基于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封装,printf,udelay等

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.        移植流程

内部时钟:先搭好ucos和bsp,不需要修改任何文件,新建main.c,新建两个task看能否在之间调度;显然是不可能的,所以动手写的第一行代码就是系统时钟函数,新建bsp.c,作为三星的SDK的补充来用,用timer0做系统tick,定时会产生内部中断,__vT0Interrupt是中断处理函数,这里挂ucos的BSP的API就行,当然别忘记了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_SEC个tick产生,这个根据实际需要更改 */ 

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_entry的task,为了方便调试,这里是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) 这样烧入不成功的,跳了好久呢,没搞清楚 ro和rw的不同

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

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

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

 

 

发布评论

评论列表 (0)

  1. 暂无评论