手把手教UCOS II移植到DSP 2803x(28035为例)
2019-07-13 10:07发布
生成海报
移植前说明:
相信学过UCOS的人都看过下面这张图,这张图讲解了UCOS移植的方法。这是ARM芯片移植UCOS的体系结构图,当然对于其它芯片也是适用的,只是个别文件名不同而已。移植的时候,图示红 {MOD}部分是不需要去修改的,需要修改的是蓝 {MOD}部分(这部分与芯片的型号是相关的,不同芯片是不一样的),绿 {MOD}部分也可以适当更改。可以通过os_cfg.h裁剪UCOS代码,因为UCOS相对来说还是比较臃肿的。
移植前准备:
一、 准备一个28035的开发例程(也可以自己写的,注:我使用的是CCS7.2版本,不同版本文件结构可能不同)
下面是一个28035的例程整体框架,例程功能是定时器time0每500ms中断一次,中断程序中翻转GPIO口的输出状态,以此来让开发板上的LED灯闪烁。文件说明:include是头文件,在这里没有展开。这是一个最基本的28035开发例程。
二、准备UCOS II移植文件
在Micrium官网下载micrium提供的关于28335的移植例程(到目前为止只有28335),整体框架如下图所示。
文件很多,这里先不用理会,后面会讲各个文件的功能。
三、 开始移植
1、 把前面两个工程文件合并起来。
官网下载的移植文件说明:一共就这几个文件,分别是APP, BSP, UC_CPU, UC_LIB, UCOS_II。
APP包含了用户应用代码,其中各种.h文件是对ucos的一些配置。.h文件保留,并新建一个CONFIG文件夹保存起来。app.c文件删除,用自己写的文件代替。
BSP称作板级支持包,这个相当于官方提供的例程中所使用的各种.c文件。这个文件也要删除,用.c文件代替。为什么要删除BSP文件,因为这个是为28335写的文件,在28035已经不适用了。还有一个问题是,官网28335这个例程只是定义了一些用到的寄存器,还有很多寄存器没有定义,如果要用到那些寄存器则要自己去定义,这就相当于本来提供的各种.c文件都要自己重新写,很烦锁。
uC_CPU是基于 micrium 官方评估板的 ucosii 移植代码,这个直接复制过来。
uC_LIB这个是micrium 官方的一个库代码,也复制过来。
uCOS_II这个文件是ucos_ii源代码,移植的时候需要修改的文件。但是官方已经帮我们修改好了。所以直接复制过来用就可以了。
可能有人会有疑问,这个28335的CPU文件适用于28035么?答案是肯定的。看到上面的C28X目录么,就是说这个移植文件是适用于所有C28X芯片的。因为28335和28035都属于C28X系列,所以此文件也适用于28035芯片。
把上面几个文件复制到第一个工程例程,修改后的框架如下图所示:
文件说明:CONFIG文件夹文件是从上面APP文件夹里复制而来的.h文件。main文件的Example_2803xLEDBlink.c是要修改的,下一步会介绍。SXD28035_common及SXD28035_headers文件,是原来工程的文件,没有修改。uC_CPU, uC_LIB, uCOS_II这三个文件是从官网例程复制过来的。F28035.cmd文件也要自己写。
2、 修改文件路径
3、 编写主程序(主程序代替APP程序)
main / Example_2803xLEDBlink.c程序如下:
#include
#include
#include
#include
#include
#include "DSP28x_Project.h"
#define LED0 GpioDataRegs.GPBTOGGLE.bit.GPIO34
CPU_STK_SIZE App_TaskStartStk[APP_CFG_TASK_STK_SIZE];
CPU_STK_SIZE App_TaskPendStk[APP_CFG_TASK_STK_SIZE];
CPU_STK_SIZE App_TaskPostStk[APP_CFG_TASK_STK_SIZE];
static OS_EVENT *AppTaskObjSem;
static void App_TaskStart(void *p_arg);
static void App_TaskPing (void *p_arg);
static void App_TaskPong (void *p_arg);
interrupt void cpu_timer0_isr(void);
void BSP_Tick_Init(void);
void BSP_Tick_Init(void)
{
EALLOW;
PieVectTable.TINT0 = &cpu_timer0_isr;
PieVectTable.OS_CPU_RTOSINT = &OS_CPU_RTOSINT_Handler;
EDIS;
InitCpuTimers();
ConfigCpuTimer(&CpuTimer0, 60, 1000);
CpuTimer0Regs.TCR.all = 0x4001;
IER |= M_INT1;
PieCtrlRegs.PIEIER1.bit.INTx7 = 1;
EINT;
ERTM;
}
void main(void)
{
InitSysCtrl();
DINT;
InitPieCtrl();
IER = 0x0000;
IFR = 0x0000;
InitPieVectTable();
EALLOW;
GpioCtrlRegs.GPBMUX1.bit.GPIO34 = 0;
GpioCtrlRegs.GPBDIR.bit.GPIO34 = 1;
EDIS;
EINT;
ERTM;
OSInit();
OSTaskCreateExt(App_TaskStart,
(void *)0,
(CPU_STK *)&App_TaskStartStk[0],
(INT8U )APP_CFG_TASK_START_PRIO,
(INT16U )APP_CFG_TASK_START_PRIO,
(CPU_STK *)&App_TaskStartStk[APP_CFG_TASK_STK_SIZE - 1u],
(INT32U )APP_CFG_TASK_STK_SIZE,
(void *)0,
(INT16U )(OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR));
OSStart();
while (DEF_TRUE) {
;
}
}
static void App_TaskStart (void *p_arg)
{
volatile CPU_INT08U os_err;
(void)&p_arg;
BSP_Tick_Init();
AppTaskObjSem = OSSemCreate(0);
OSTaskCreateExt(App_TaskPing,
(void *)0,
(CPU_STK *)&App_TaskPendStk[0],
(INT8U )APP_CFG_TASK_PEND_PRIO,
(INT16U )APP_CFG_TASK_PEND_PRIO,
(CPU_STK *)&App_TaskPendStk[APP_CFG_TASK_STK_SIZE - 1u],
(INT32U )APP_CFG_TASK_STK_SIZE,
(void *)0,
(INT16U )(OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR));
OSTaskCreateExt(App_TaskPong,
(void *)0,
(CPU_STK *)&App_TaskPostStk[0],
(INT8U )APP_CFG_TASK_POST_PRIO,
(INT16U )APP_CFG_TASK_POST_PRIO,
(CPU_STK *)&App_TaskPostStk[APP_CFG_TASK_STK_SIZE - 1u],
(INT32U )APP_CFG_TASK_STK_SIZE,
(void *)0,
(INT16U )(OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR));
while (DEF_TRUE) {
os_err = OSSemPost(AppTaskObjSem);
OSTimeDlyHMSM(0, 0, 0, 1);
}
}
static void App_TaskPing (void *p_arg)
{
CPU_INT08U os_err;
(void)&p_arg;
while (DEF_TRUE)
{
OSSemPend( AppTaskObjSem,
0,
&os_err);
}
}
static void App_TaskPong (void *p_arg)
{
(void)&p_arg;
while (DEF_TRUE)
{
OSTimeDlyHMSM(0, 0, 0, 300);
LED0=1;
CpuTimer0.InterruptCount++;
}
}
interrupt void cpu_timer0_isr(void)
{
PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;
OSIntEnter();
OSTimeTick();
OSIntExit();
}
程序说明:BSP_Tick_Init(void)和interrupt void cpu_timer0_isr(void)函数为ucos系统提供时钟节拍,第一个函数是初始化timer,此处设置的是1ms定时一到就会跳入中断函数,中断函数中调用OSTimeTick()函数为ucos提供时钟节拍。注意这里设置了OS_CPU_RTOSINT_Handler,这个后面还会讲到。
后面的函数都是官网例程的代码直接复制过来的。在void App_TaskPong (void *p_arg)函数做了一些修改,改成自己开发板用的代码及测试代码。
4、 编写CMD文件。
这个很重要,如果不懂CMD文件的可以用我这个文件。千万不要乱改,否则会出现各种各样的问题,而且极难调试。
MEMORY
{
PAGE 0: /* Program Memory */
/* Memory (RAM/FLASH/OTP) blocks can be moved to PAGE1 for data allocation */
RAML0 : origin = 0x008000, length = 0x000800 /* on-chip RAM block L0 */
RAML1 : origin = 0x008800, length = 0x000400 /* on-chip RAM block L1 */
OTP : origin = 0x3D7800, length = 0x000400 /* on-chip OTP */
FLASHH : origin = 0x3E8000, length = 0x002000 /* on-chip FLASH */
FLASHG : origin = 0x3EA000, length = 0x002000 /* on-chip FLASH */
FLASHF : origin = 0x3EC000, length = 0x002000 /* on-chip FLASH */
FLASHE : origin = 0x3EE000, length = 0x002000 /* on-chip FLASH */
FLASHD : origin = 0x3F0000, length = 0x002000 /* on-chip FLASH */
FLASHC : origin = 0x3F2000, length = 0x002000 /* on-chip FLASH */
/* FLASHA : origin = 0x3F6000, length = 0x001F80 */ /* on-chip FLASH */
FLASHA : origin = 0x3F5000, length = 0x002F80 /* test */
CSM_RSVD : origin = 0x3F7F80, length = 0x000076 /* Part of FLASHA. Program with all 0x0000 when CSM is in use. */
BEGIN : origin = 0x3F7FF6, length = 0x000002 /* Part of FLASHA. Used for "boot to Flash" bootloader mode. */
CSM_PWL_P0 : origin = 0x3F7FF8, length = 0x000008 /* Part of FLASHA. CSM password locations in FLASHA */
IQTABLES : origin = 0x3FE000, length = 0x000B50 /* IQ Math Tables in Boot ROM */
IQTABLES2 : origin = 0x3FEB50, length = 0x00008C /* IQ Math Tables in Boot ROM */
IQTABLES3 : origin = 0x3FEBDC, length = 0x0000AA /* IQ Math Tables in Boot ROM */
ROM : origin = 0x3FF27C, length = 0x000D44 /* Boot ROM */
RESET : origin = 0x3FFFC0, length = 0x000002 /* part of boot ROM */
VECTORS : origin = 0x3FFFC2, length = 0x00003E /* part of boot ROM */
PAGE 1 : /* Data Memory */
/* Memory (RAM/FLASH/OTP) blocks can be moved to PAGE0 for program allocation */
/* Registers remain on PAGE1 */
BOOT_RSVD : origin = 0x000000, length = 0x000050 /* Part of M0, BOOT rom will use this for stack */
RAMM0 : origin = 0x000050, length = 0x0003B0 /* on-chip RAM block M0 */
RAMM1 : origin = 0x000400, length = 0x000400 /* on-chip RAM block M1 */
RAML2 : origin = 0x008C00, length = 0x000400 /* on-chip RAM block L2 */
RAML3 : origin = 0x009000, length = 0x001000 /* on-chip RAM block L3 */
FLASHB : origin = 0x3F4000, length = 0x002000 /* on-chip FLASH */
}
SECTIONS
{
/* Allocate program areas: */
.cinit : > FLASHA PAGE = 0
.pinit : > FLASHA PAGE = 0
.text : > FLASHA PAGE = 0
codestart : > BEGIN PAGE = 0
ramfuncs : LOAD = FLASHD,
RUN = RAML0,
LOAD_START(_RamfuncsLoadStart),
LOAD_END(_RamfuncsLoadEnd),
RUN_START(_RamfuncsRunStart),
PAGE = 0
csmpasswds : > CSM_PWL_P0 PAGE = 0
csm_rsvd : > CSM_RSVD PAGE = 0
/* Allocate uninitalized data sections: */
.stack : > RAMM0 PAGE = 1
.ebss : > RAML2 | RAML3 PAGE = 1
.esysmem : > RAML2 | RAML3 PAGE = 1
/* Initalized sections go in Flash */
/* For SDFlash to program these, they must be allocated to page 0 */
.econst : > FLASHA PAGE = 0
.switch : > FLASHA PAGE = 0
/* Allocate IQ math areas: */
IQmath : > FLASHA PAGE = 0 /* Math Code */
IQmathTables : > IQTABLES, PAGE = 0, TYPE = NOLOAD
.reset : > RESET, PAGE = 0, TYPE = DSECT
vectors : > VECTORS PAGE = 0, TYPE = DSECT
}
5、 设置堆栈(stack)大小。
右键工程项目名,选择properties。出现下面框图,如图,修改为0x3b0。这个设置跟CMD文件要对应上。CMD文件上.stack设为RAMMO段,其大小正好为0x3B0。请看上面代码。
6、 取消浮点运算float支持
因为28035是定点芯片,所以要取消浮点运算。
右键工程项目名,选择properties。出现下面框图,如图,选择softlib。fpu32用于支持浮点运算的芯片。
7、 设置OS_CPU_RTOSINT_Handler 中断
UCOS任务的跳转是调用了OSINTCTXSW这个宏定义。这个宏定义就是:asm(” TRAP #16”); TRAP #16定义为RTOSINT_ISR中断,在SXD28035_common->DSP2803X_DefaultIsr.c文件中可以看到interrupt void RTOSINT_ISR(void)函数是空的。关于cpu寄存器的操作是在ucosii>prots>C28x->generic>ccs>os_cpu_a.asm这个文件中的_OS_CPU_RTOSINT_Handler: 函数。所以在这里要把OS_CPU_RTOSINT_Handler定义为16号中断入口地址。具体做法如下:
1) 在main程序中修改RTOSINT中断的入口地址,如下,取消第一条指令,加上第二条指令。
// PieVectTable.RTOSINT = &RTOSINT_ISR; // test
PieVectTable.OS_CPU_RTOSINT = &OS_CPU_RTOSINT_Handler; // RTOS
2) 修改中断向量表。路径为SXD28035_headers->include->DSP2803x_PieVect.h。修改后如下所示:
3) 中断向量表初始化也要修改。路径为SXD28035_headers->include->DSP2803x_PieVect.c。修改后如下所示:
注意:在DSP2803x_PieVect.c 文件中添加os_cpu.h 头文件,否则编译器会找不到OS_CPU_RTOSINT_Handler 。 #include “os_cpu.h”
4)取消interrupt void RTOSINT_ISR(void)中断。路径为SXD28035_common->DSP2803X_DefaultIsr.c。修改后如下所示:
5) 好了,来看看OS_CPU_RTOSINT_Handler的定义长什么样子。路径为ucosii>prots>C28x->generic>ccs>os_cpu_a.asm
8、 裁剪代码
为什么要裁剪代码呢?一方面是因为UCOS代码比较臃肿;另一方面是不想去修改CMD文件。在这里直接把暂时没用到的代码取消就可以了。
1)uC_LIB文件夹中的lib_ascii.c, lib_math.c, lib_mem.c, lib_str.c。这四个文件取消编译。
2)裁剪UCOS II内核代码。路径为CONFIG->os_cfg.h。把暂时不用的功能注消。如下图
最后编译0错误,0警告,下载,运行正常。大功告成!
打开微信“扫一扫”,打开网页后点击屏幕右上角分享按钮