CCSv5.2中DSP/BIOS的搭建
前言:
DSP/BIOS是TI公司专门为DSP开发的嵌入式实时操作系统,主要分为五大部分如下图左边所示:
1.创建常规的CCS5.2工程
(1)打开CCS,选择Project -> New CCS Project.
(2)在 Project name 栏输入要创建的工程名字
(3) 在Family栏选定你所使用的DSP的家族系列
(4) 在Variant栏选定你所使用的DSP系列
(5) 在Connection栏选择你所使用的仿真器型号。
(6) Advanced settings高级选项,主要时选择芯片的大小端,编译器版本,一般情况下这里不需要设置。
(7)在Project templates and examples栏选中带main.c的空白工程。
(8)点击Finish按钮,完成。
如图:
2.引入DSP/BIOS系统
注1:因为刚才在创建工程的时候已经产生了一个名为C6455.cmd的链接命令文件,在这里需要删除这个链接命令文件,因为DSP/BIOS在创建的过程中会产生一份新的链接命令文件。并且新的链接命令文件会把一些用到的应用库包含进来,例如bios.a62,rtdx.lib,rts64plus.lib等程序库。大多数DSP/BIOS生成的链接命令文件会满足所有的存储段分配,也可以后续再通过MEM管理器进行控制。
注2:假如你的工程之前有包含vectors.asm源文件,同样需要移除这个文件,因为DSP/BIOS会自动定义硬件中断向量表。就是说假如你使用了DSP/BIOS系统,中断向量的管理权也就交给了DSP/BIOS。
我们这里以一个最简单的应用例程进行说明,在这里会带领大家创建一个包含有两个任务的应用程序,第一个任务执行把LED点亮的工作,第二个任务执行把LED点灭的工作。
1) 选择工程名 New > Other 如图选中 DSP/BIOS v5.x Configuration File 点击Next 如图:
(2) 选择所属的器件型号平台,点击Next按钮 如图:
(3)将默认选中三个DSP/BIOS特性选中,点击Finish按钮。
Real-Time Analysis 若禁止,则LOG、STS不可用。
RTDX
若禁止,则实时分析数据不可实现。
TSK Manager 允许你使用信号量和任务让出功能。
在这里你可以先编译一下你所创建的工程,如果你是按照我所描述的步骤进行创建的话,编译应该是没有错误可以通过编译的。
注:编译通过后你可以在左侧工程导航栏的Debug文件夹下看到一系列DSP/BIOS所创建的文件,如
testcfg_c.c文件: 定义DSP/BIOS结构体和内容。
testcfg.cmd文件 链接命令文件
testcfg.h文件 包含DSP/BIOS模块头文件、声明对象的外部变量。
testcfg.s62文件 DSP/BIOS配置的汇编文件
testcfg.h62
文件 汇编语言头文件 如图:
3.DSP/BIOS系统配置
(1)全局属性设置
在左侧的工程导航栏双击test.tcf打开管理器,选中System 栏下的Global Settings,右键,选择属性按钮,进行如下设置,这里主要是设置CPU运行的时钟,因为我将来要把我的DSP运行在1GHz的频率,外部接的晶振是20MHz,所以设置如下。
内存段设置
鼠标右键MEM-Memory Section Manager点击Properties如图
取消 No Dynamic Memory Heaps 选项
鼠标右键IRAM点击Properties 如图
选择 created a heap in this memory 并设置大小 如图
鼠标右键MEM-Memory Section Manager点击Properties 并设置Segment For DSP/BIOS Object 和 Segment For malloc/free 如图
(2)LOG模块的设置
注:LOG模块可以帮助我们调试将来的代码,可以利用模块本身的LOG_printf函数在CCS环境里面打印信息,对我们调试代码十分有用。而且占用的CPU资源很小,几乎不影响CPU的性能。
选择Instrumentation子目录下的LOG-Event
Log Manager,右键选择Insert LOG,在打开的对话框中为你要创建的模块起个名字,一般以trace命名。如图:
下面说一下使用举例,很简单 LOG_printf(&trace,”Task1 LED on”); 就可以在CCS的相应窗口中看到打印信息。
(3)PRD对象的创建
PRD又叫周期函数管理器,它使用系统时钟CLK进行驱动,为任务的睡眠提供依据。很多DSP/BIOS函数都有一个超时参数timeout,例如你在任务中使用TSK_sleep()的函数,这个函数是一个具有超时参数的函数,被调用之后,当系统时钟的变化次数达到超时参数的值时,任务将会推出被阻塞状态。
假如你的系统时钟配置分辨率设置为1ms,并且希望当前任务阻塞1s的时间,那么应该这样调用TSK_sleep(); TSK_sleep(1000); 任务将被阻塞1s钟。这里使用C6455的定时器0来做为CLK模块的驱动源,使用低分辨率时钟指定输入时钟源为20MHz。设置时间精度为1ms一次.
选择Scheduling子目录下的CLK-Manager,右键选择属性按钮。如图:
(4)任务创建
注:每个任务都拥有自己独立的堆栈,任务共有四种状态
运行态(Running)
就绪态(Ready) 已被调度,等待执行
挂起态(Block) 也叫阻塞态,等待某个事件发生或某些资源可用
终止态(Terminated) 被终止,不会再执行
其中相同优先级的任务,任务调度器会根据它们在配置工具里列出的顺序进行调度。空闲任务属于DSP/BIOS系统的后台线程,有限地最低,其它任何任务线程都可以抢占它,空闲任务用来监测系统状态或执行其它后台操作。
选择 TSK – Task Manager ,右键选择插入,并为每个任务起个名字,这里我命名了两个名称分别为TSK_ledon、TSK_ledoff的任务。优先级分别为2和1。两个任务一个用来点亮led,一个用来灭掉led。这样程序运行起来就会看到led在闪烁。 创建后如图:
上述只是创建了任务,接下来还要在为每个任务指定一个函数入口名称。
选中TSK_ledon,右键选择属性,进行设置,在弹出的对话框中选择Function选项,在Task function:栏输入要调用的函数入口名称,这里我命名为taskledon。
注:taskledon前面要加上一个下划线,这一点一定不能忘记。 如图:
同样为TSK_ledoff任务指定入口函数名称为taskledoff。
再此先将代码部分贴出来:
首先在主函数开始前需要包含几个必要的头文件过来
#include
#include
#include
#include "testcfg.h"
#include "hw_types.h"
#include "psc.h"
#include "soc_C6748.h"
#include "gpio.h"
void Delay(unsigned int delay)
{
while(delay--);
}
//主函数,我手里的板子在GP2_1上接的是一只Led。对应管脚号为34,主函数再此小工程里主要完成GPIO的初始化工作。
int main(void)
{
PSCModuleControl(SOC_PSC_1_REGS, HW_PSC_GPIO, PSC_POWERDOMAIN_ALWAYS_ON, PSC_MDCTL_NEXT_ENABLE);
HWREG(0x01C14138) = 0x08000000u;
GPIODirModeSet(SOC_GPIO_0_REGS, 34, GPIO_DIR_OUTPUT);
GPIOPinWrite(SOC_GPIO_0_REGS, 34,GPIO_PIN_LOW);
Delay(5000000);
GPIOPinWrite(SOC_GPIO_0_REGS, 34,GPIO_PIN_HIGH);
SEM_post(&SEM0);
return 0;
}
void taskledon()
{
while(1)
{
SEM_pend(&SEM0, SYS_FOREVER);
GPIOPinWrite(SOC_GPIO_0_REGS, 34,GPIO_PIN_LOW);
TSK_sleep(500);
//Delay(5000000);
SEM_post(&SEM1);
LOG_printf(&trace, "Task ledon DONE");
}
}
void taskledoff()
{
while(1)
{
SEM_pend(&SEM1, SYS_FOREVER);
GPIOPinWrite(SOC_GPIO_0_REGS, 34,GPIO_PIN_HIGH);
TSK_sleep(500);
//Delay(5000000);
SEM_post(&SEM0);
LOG_printf(&trace, "Task ledoff DONE");
}
}
(5)创建信号灯
上述两个任务之间依赖信号灯来触发任务进入就绪状态,实现任务之间的同步和通信。信号灯有一个内部计数器,计有效的资源数,若信号灯大于0,任务请求该信号灯不会被阻塞。
SEM_pend(sem,timeout):等待一个信号灯,如果信号灯值大于0,则对计数值做简单的减1并返回,否则等待SEM_post发布信号。超时参数允许任务等待直到超时,或无限等待(SYS_FOREVER),或者不等待(取值0),返回值代表请求信号灯是否成功。
SEM_post(sem):发布信号灯。若有任务等待该信号灯,SEM_post会从等待队列中将该任务删除并将其放入就绪队列等待调度。如果没有任务等待这个信号,SEM_post则简单将计数值加1并返回。
细心的你可能已经发现上述贴出来的示例代码用到了两个信号灯,分别为SEM0,SEM1。其中SEM0用来调度点亮LED的任务taskledon,SEM1用来调度灭掉LED的任务taskledoff。
选择Synchronization子目录的SEM-Semaphore Manager,右键选择插入选项。
最后运行 编译,编译没有错误这样就搭建简单的DSP/BIOS应用工程了。