本文于20200415更新,针对旧版本的Bug做了修改,重新完善了流程,所搭建的工程在280049C的LaunchPad上做了初步验证,未来发现新的问题或者解决方案会继续更新。
每次折腾Code Composer Studio (CCS)都被各种warning和error怼的生活不能自理,而且随着新芯片的不断出现,软件版本的不断提高,网上的许多教程都有些过时,进一步增大了学习难度。这次折腾的时候还发现官方的代码库有一些小Bug,而且TI在19年4月的时候就知道了[15],到现在最新的支持库中居然还没改……
这回折腾的感想是多翻翻C2000ware的安装文件夹,里面有好多官方文档帮助入门。在这里首先推荐C:\ti\c2000\C2000Ware_3_01_00_00\device_support\f28004x\docs目录下的《F28004x_FRM_EX_UG》,有这个基本就可以入门了,其他的芯片也类似。另外推荐文献[16],里面可以找到许多文档和工具来辅助设计。
本博客后续与280049C相关的学习都在本文的工程上进行。
很多时候我们需要与其他人共享项目代码,但其他人可能并没有与自己一样的软件环境,所以有必要使用完全可移植的工程文件。本篇博文记录使用CCS9.3新建适用于280049C工程的方法,所有参考文献链接列在文章最后,在此对各个参考资料的作者表示感谢!整个文章的结构参考了[1],关于链接源文件时碰到的绝对路径和相对路径的问题,可以参考[2]。
由于工程同时兼容了较多的文件,目前本文的方法还有一些缺陷,后续如果找到解决方法会逐步修复。这里列出已经发现的问题:
在CCS软件中点击project->New CCS Project,并按照需要进行设置,工程名可以随意设置,本文取为F280049C_Template。
在Tool-chain中设置Output format为eabi(ELF)
点击Finish之后获得如下图所示的工程文件
工程文件夹下的文件如下:
后续称该文件夹为“工程文件夹”,将向其中拷贝许多文件。
在软件的安装位置 C:\ti\c2000\C2000Ware_2_01_00_00\device_support\f28004x内有该DSP的支持文件,接下来分别复制到自建的工程中。
将C:\ti\c2000\C2000Ware_2_01_00_00\device_support\f28004x\common文件夹下的source文件夹整体拷贝至工程文件夹
将C:\ti\c2000\C2000Ware_3_01_00_00\device_support\f28004x\headers\source文件夹下的这个文件复制到工程文件夹刚才的source文件夹中;
将C:\ti\c2000\C2000Ware_3_01_00_00\device_support\f28004x\common下的include文件夹整体复制到工程文件夹
将C:\ti\c2000\C2000Ware_3_01_00_00\device_support\f28004x\headers\include中的所有文件复制到工程文件夹的include文件夹中
复制C:\ti\c2000\C2000Ware_3_01_00_00\device_support\f28004x\common\cmd中的4个.cmd文件到工程文件夹(事实上其中两个与cla有关的cmd文件在本文范围内不会用到,不复制也可以),关于这些cmd文件的区别可以参考[11][12]。
复制库函数,这些文件都在C:\ti\c2000\C2000Ware_3_01_00_00\driverlib\f28004x\driverlib这个文件夹下。如下图,文件夹中有2个子文件夹和一系列.c和.h文件,需要分别操作。
将ccs和inc两个文件夹直接复制到工程文件夹。
删除ccs文件夹中多余的文件,如下图选中的文件。另外由于采用eabi输出,所以ccs文件夹中与COFF输出有关的文件也可以删除。
复制C:\ti\ccs\tools\compiler\ti-cgt-c2000_18.12.4.LTS\lib 和 C:\ti\c2000\C2000Ware_3_01_00_00\libraries\math\FPUfastRTS\c28\lib中的数学运算库到工程文件夹。关于各个库文件名后缀的具体意义,可以参考[4]的8.1.7节。TI还提供了其他库,在C:\ti\c2000\C2000Ware_3_01_00_00\libraries文件夹,需要时也可以复制过来。这里先不复制。完成上述复制后的工程如下图所示:
这个cmd文件其实我一直没搞懂它的作用,应该是将一些寄存器分配到指定的存储空间。
该文件的位置在C:\ti\c2000\C2000Ware_3_01_00_00\device_support\f28004x\headers\cmd
将其复制到工程文件夹即可。
为了同时实现库函数编程和寄存器编程,并解决[15]和[17]中的问题,需要对TI官方的文件做一些编辑,需要修改3个地方。
至此已经完成了必要文件的复制,但是工程还不能正确的检索到它们,因此需要添加一些索引路径。一般在debug时希望工程从RAM中执行,本节讨论从RAM中执行时的配置。
首先,右键点击项目浏览器中的项目名,打开Properties(属性),设定成DEBUG。这里的名字实际上也可以根据自己的喜好随便改。
后续添加文件路径的时候会涉及到一些缩写,这些缩写在如下位置做了定义:
同样右键点击项目浏览器中的项目名,打开Properties(属性)进行设置。
${PROJECT_ROOT}/rts2800_fpu32_eabi.lib
${PROJECT_ROOT}/rts2800_fpu32_fast_supplement_eabi.lib
其中默认的库文件是libc.a,根据本文开头提到的官网文档,可以直接删除。
快速运行库rts2800_fpu32_fast_supplement.lib是rts2800_fpu32.lib的一个函数子集,它是对rts2800_fpu32.lib中一些函数进行重写,提高运算速度,所以添加是有次序要求,需要进行设置如下:
link order中添加这两个库,排序rts2800_fpu32_fast_supplement.lib在前rts2800_fpu32.lib在后
同样右键点击项目浏览器中的项目名,打开Properties(属性)进行设置。 关于编译器–fp_mode的设置等信息可以参考文献[4]的2.3节。
目前不推荐启用–idiv_support,在本工程中启用该选项会导致程序无法正确运行。
这一步不是必须的。
官方的例程基于ControlCard编写,如果想直接在LaunchPad上运行,需要定义这样一个指令。如果自己完全从零开始编辑代码,不需要做这一步。
对于280049C,其官方的LaunchPad开发板使用了XDS110仿真器的两线调试模式,而官方的ControlCard使用的是XDS100V2仿真器,开发时需要注意区分,并分别设置。本文以采用两线制调试的XDS110仿真器为例进行设置。
右键点击工程名,选择New—>TargetConfiguration File,File name取名任意,这里取为LaunchPad.ccxml,点击Finish。
这一步会将有用的那个.cmd文件重新加回来。右键工程名,属性,在如下图所示的对话框中把cmd文件包含进来。
尽管这里使用了绝对路径,但系统会自动切换成相对路径。只要再次打开属性面板就会发现已经自动切换了。而且需要用到的.cmd也自动地重新解除了Exclude from Build的状态。
至此,从RAM中运行的配置全部结束。
当代码调试完毕,需要将代码烧录到FLASH中,这样DSP就可以脱离仿真器运行了。配置步骤与从RAM中执行相似,具体如下:
首先切换到FLASH配置界面
然后重复与RAM中执行类似的配置,具体包括以下几步,本节不在赘述:
为了使程序正确的从flash启动,编程时通常有一些特殊的代码需要运行(通常TI都已经在库函数中提供)。为了确保这些代码能够正确编译,执行本步骤。
与之前相同,只不过这次是将FLASH相关的cmd加进来。
至此,FLASH中的配置结束。
接下来使用简单的代码对搭建的工程进行验证,在主函数main.c中输入如下代码,并编译。下载运行后,LaunchPad的红色Led会闪烁,频率1Hz。
如果是在FLASH中编译,会报如下警告:
#10063-D entry-point symbol other than “_c_int00” specified: “code_start”
并不会影响到程序的运行,报错原因和解决措施仍在探索中。
#include "F28x_Project.h"
#include "device.h"
#include "math.h"
#define DEVICE_GPIO_PIN_LED1 23U // GPIO number for LD4
#define DEVICE_GPIO_PIN_LED2 34U // GPIO number for LD5
void main(void)
{
// 初始化时钟和外设 Initialize device clock and peripherals
Device_init();
// InitSysCtrl(); //本工程不能使用寄存器的InitSysCtrl();函数初始化。
/*//库函数版配置
// 初始化GPIO并设置为推挽输出 Initialize GPIO and configure the GPIO pin as a push-pull output
Device_initGPIO();
GPIO_setPadConfig(DEVICE_GPIO_PIN_LED1, GPIO_PIN_TYPE_STD); // Push-pull output or floating input
GPIO_setDirectionMode(DEVICE_GPIO_PIN_LED1, GPIO_DIR_MODE_OUT);
*/
InitGpio(); //寄存器指令配置
GPIO_SetupPinMux(DEVICE_GPIO_PIN_LED1, GPIO_MUX_CPU1, 0);
GPIO_SetupPinOptions(DEVICE_GPIO_PIN_LED1, GPIO_OUTPUT, GPIO_PUSHPULL);
// 初始化PIE并清空PIE寄存器,关闭CPU中断
// Initialize PIE and clear PIE registers. Disables CPU interrupts.
Interrupt_initModule();
// 初始化PIE向量表
// Initialize the PIE vector table with pointers to the shell Interrupt
// Service Routines (ISR).
Interrupt_initVectorTable();
// Enable Global Interrupt (INTM) and realtime interrupt (DBGM)
EINT;
ERTM;
float a=cos((float)3.1415926/4); // FPU32
float b=__sin((float)(3.14/4)); // TMU
for(;;)
{
// Turn on LED
// 硬件电路设计是GPIO输出低电平时LED亮
GPIO_writePin(DEVICE_GPIO_PIN_LED1, 0);
// 延迟0.5s Delay for a bit.
DEVICE_DELAY_US(500000);
// Turn off LED
GPIO_writePin(DEVICE_GPIO_PIN_LED1, 1);
// Delay for a bit.
DEVICE_DELAY_US(500000);
}
}
注意:本文提供的工程下载资源中的文件版本是第一次修订后的结果,无法从FLASH运行。如有需要,需参考相关章节进行配置。