1、第四章 DSP的C语言程序设计DSP的C语言程序设计一、为什么要使用C语言对DSP编程?C语言是高级语言,易学易用。C语言的编程效率极高,易于调试。C语言的可移植性好。二、C程序的结构及组成完整的C程序是由一个主函数main()和其它的子函数组成的,每一个子函数完成特定的功能。DSP的C语言的入口地址固定为c_int00,在rts.lib中定义。C语言支持丰富的数据类型和数据结构,在ccs集成开发环境中,为C语言提供了完整的支持硬件的底层函数库和支持算法的DSP函数库。在使用C语言的库函数时,在工程中必须包括相应的函数库和rts.lib运行时支持库。下面是一般C语言程序的结构和组成框架。一般C
2、程序的结构如下: / #include包含语句定义程序中使用的函数库对应的. h头文件#include “函数库1”#include #include “函数库3” / #define 定义程序中所有的宏替换 #define 宏替换名 替换内容 /本程序的内部函数声明,这些函数一般放在main()函数的后面 函数类型 函数名(函数参数列表); /中断服务程序(函数)的声明interrupt void function_name (void); /全局变量声明 变量类型 全局变量名; /主函数main() void main(void) /局部变量定义 for(;) /调用子函数来处理数据/完成
3、数据的输入和输出功能/本程序的内部函数函数类型 函数名(函数参数列表) /本函数的局部变量定义 /本函数中的算法 /程序结束三、数据类型C语言支持的数据类型很丰富,包括字符型、短整型、整型、长整型、枚举型、浮点型、双精度浮点型、长双精度浮点型、数据指针及程序指针,要注意的是由于54x DSP是16位的处理器,它的字符型数据的长度是16位的,另外注意比较各种数据类型的长度、内容以及所表示的值的范围大小,可以发现短整型和整型数据类型是一致的,浮点型、双精度浮点型和长双精度浮点型是一致的,这是因为54x DSP的C语言编译器为了适应不同的编程习惯而这样定义的,所以实际使用中可以将常用的数据类型进行适
4、当简化,即将短整型、整型统一为整型(int),将各种浮点类型统一为浮点型(float)。另外,为了简化书写,用户可以自定义数据类型,例如在type.h中的定义:typedef float f32; /浮点型typedef long s32; /有符号的长整型typedef int s16; /有符号的整型typedef unsigned char u8; /无符号的字符型typedef unsigned int u16; /无符号的整型typedef unsigned long u32; /无符号的长整型 详细内容请参考头文件type.h。四、头文件中存储器映射寄存器(MMR)的定义和访问对于
5、DSP的软件设计,首先必须明了DSP的可用片内资源及其访问方法,包括DSP的片上存储器映射寄存器、程序存储器、数据存储器、I/O空间的寻址范围、寻址方式,片上外设的寄存器定义、工作流程以及编程控制方法。54X DSP的片内寄存器资源是通过两个头文件Regs.h 和Regs54x.h进行定义的,这些头文件位于 c:tic5400dsk5402include目录下,在这两个文件中定义了C54x DSP中涉及到的所有寄存器及其所包含的控制和状态比特,这些定义是使用宏替换定义#define进行的,例如:串口控制寄存器中接收移位寄存器满标志位的比特域定义:# define RSRFULL 13 /RSR
6、FULL标志比特位于寄存器的bit13位置#define RSRFULL_SZ 1 /此标志的长度为1个比特我们只需要了解这些寄存器定义,在编程过程中直接使用而不需要自己来重新定义。Reg54xx.h是对Regs.h的扩展和补充,并且Reg54xx.h头文件包含Regs.h。注意#define的语句中“”是续行符。在Regs.h和Regs54xx.h中还定义了寄存器的访问方式宏定义,如: REG_READ(addr); /寄存器读 REG_WRITE(addr,val); /寄存器写 RESET_BIT(addr,bit); /bit位清零 GET_BIT(addr,bit); /取得bit位
7、的值 SET-BIT(addr,bit); /bit位置1 详细内容请参考c:tic5400dsk5402include目录下的头文件Regs.h 和Regs54x.h。在头文件中,采用了以下几种方法对DSP内部的存储器映射寄存器(MMR)进行定义和访问:1使用#define宏定义语句定义MMR的地址,有两种定义方法:统一定义法:如MCBSP串口接收寄存器的定义:#define DRR2_ADDR(port) (port? 0x40:0x20)#define DRR1_ADDR(Port) (port? 0x41:0x21)它把MCBSP0和MCBSP1的串口接收寄存器合在一起进行了定义,通过
8、port参数进行区分。单独定义法:#define DRR20_ADDR 0x20#define DRR10_ADDR 0x21#define DRR21_ADDR 0x40#define DRR11_ADDR 0x41分别将MCBSP0和MCBSP1的串口接收寄存器进行了定义。统一定义法定义的寄存器用于对二者同时进行访问时比较方便,单独定义法定义的寄存器用于单独访问某个外设时比较方便。访问时使用“指针前缀+地址”的方式,例如:* (volatile unsigned int *) DXR1_ADDR(Port)=value; /写DXR1寄存器variable=* (volatile unsi
9、gned int *) DRR1_ADDR(Port); /读DRR1寄存器使用宏定义函数进行访问。在regs.h和reg54xx.h头文件中,定义了如下的宏函数,可以使用它们对寄存器或存储器进行访问。 REG_READ(addr); /寄存器读,addr为寄存器地址 REG_WRITE(addr,value); /寄存器写,addr为寄存器地址,value为要写入的值例如: REG_READ(DDR1_ADDR (port)); /读DRR1寄存器 REG_WRITE(DXR1_ADDR (port),value); /写DXR1寄存器,value为要写入的值2直接使用* (volatile
10、 unsigned int *) +地址的指针方式定义寄存器,其中“volutile”关键字用来防止C编译器对本条语句进行优化。 例如:#define DRR20 * (volatile unsigned int *)0x200x20是寄存器的地址,相当于&p,(volatile unsigned int *)0x20相当于一个地址变量p,* (volatile unsigned int *)0x20相当于指针数据类型。访问时直接使用即可,例如:DXR20=value; /写寄存器DXR20Variable=DRR20; /读寄存器DRR20在头文件中,习惯上使用 “寄存器名+_+ ADDR”
11、表示寄存器的地址宏定义,而是用寄存器名表示寄存器指针方式的宏定义,请注意区分,并在实际编程时遵守这一习惯。由于54X DSP的存储器映像寄存器在头文件Regs.h 和Regs54x.h中已经按方式进行了定义,所以推荐使用方式访问DSP的存储器映像寄存器,不需要自己重新进行宏替换定义。对于RAM存贮器可使用变量、数据指针、结构、联合、枚举等方式进行访问。其它等效的定义和访问方式除了的定义和访问方法之外,还有一些等效的定义和访问方法,这些方法不建议大家使用,只需要进行了解。定义: #define BSPC0 (volatile unsigned int*)0x22使用: *BSPC0=value;
12、 /写寄存器 reg_value=*BSPC0; /读寄存器五、DSP I/O空间的访问方式1:在C语言中访问DSP的I/O空间借助于关键字ioport来进行,注意,此关键字只为DSP 54xx的编译器所识别和使用。在54xx中其定义格式为: ioport unsigned int porthex_num其中的import和port均为关键字,unsigned int 是I/O数据类型,在54xx中,I/O空间共有64K字,所以数据类型只能是char 、short、 int等16位的类型。一般使用格式如下:volatile ioport unsigned int portxx; /xx为16进
13、制(hex)格式地址portxx=value; /写I/O端口variable=portxx; /读I/O端口例如:当访问I/O空间在200H地址时,可以采取以下定义形式:ioport unsigned int port200;unsigned int test;test=port200; /读I/O端口,port200作为一个变量使用port200=test; /写I/O端口,port200作为一个变量使用更进一步地,可以使用ioport关键字和宏替换来定义I/O地址。例如:volatile ioport unsigned int portxx; /xx为16进制(hex)格式地址#defi
14、ne portA portxx /使用宏替换对portxx端口进行进一步定义portA=value; /写I/O端口varich=portA; /读I/O端口 例如,在board.h中对cpld扩展I/O寄存器的定义如下:/port declarations used to access CPLD registersvolatile ioport u16 port0;volatile ioport u16 port1;volatile ioport u16 port2;volatile ioport u16 port3;volatile ioport u16 port4;volatile io
15、port u16 port5;volatile ioport u16 port6;volatile ioport u16 port7;#define CPLD_CTRL1_REG port0#define CPLD_STAT_REG port1#define CPLD_DMCTRL_REG port2#define CPLD_DBIO_REG port3#define CPLD_CTRL2_REG port4#define CPLD_SEM0_REG port5#define CPLD_SEM1_REG port6#define CPLD_SLIC_REG port7方式2:借助于库函数por
16、tRead(port)和portWrite(port)对一段连续I/O端口进行读写在portio.h头中定义了portRead()、portWrite()函数。/*/* Copyright (c) Texas Instruments, Incorporated 2000 */*/*/*/* portio.h - Header file for portio_.asm */* */* */* FUNCTIONS: */* */* portRead() */* portWrite() */* */* */* STATIC FUNCTIONS: */* None */* */* */* GLOBAL
17、 VARIABLES DEFINED */* */* */ /*/#ifndef _PORTIO_H#define _PORTIO_H#include /*/* s16 portRead(u16 port) */* */ /* This routine reads a word from the specified port. */* */* Parameters: */* - port - port address (HEX) */* */* Return: */* - returns value read from port. */* */* Notes: */* */ /*/s16 po
18、rtRead(u16 port);/*/* portWrite(u16 port, s16 value) */* */ /* This routine writes a word to the specified port. */* */* Parameters: */* - port - port address (HEX) */* - value - 16 bit word to write. */* */* Return: */* - none */* */* Notes: */* */ /*/void portWrite(u16 port, s16 value);#endif /* e
19、nd of #ifndef _PORTIO_H */使用时,先使用宏替换或枚举定义I/O端口的地址,然后使用portRead()和portWrite()函数访问I/O端口例如:#include portio.h /所需要的函数包含在portio.h中#define portA 0x00 /使用宏替换定义I/O端口的地址#define portB 0x01或typedef enum /使用枚举定义I/O端口的地址portA=0x00;portB=0x01; cpldReg, *pcpldReg. Variable=portRead(portA); /读I/O端口 portwrite (portB
20、)=Value; /写I/O端口四、CCS中与C54xx相关的头文件CCS中与C54xx相关的所有头文件位于C:tic5400dsk5402include目录下,可以分为两类:一类头文件对DSP本身及外部接口电路所拥有的硬件资源进行描述定义,如Regs.h 、Regs54xx.h。另一类头文件对这些资源的设置和使用的接口函数库进行了描述,使用户可以不关心底层的驱动程序,直接调用库函数即可实现对硬件的控制,这些往往都是硬件开发人员所完成的,如CCS中的board.h 和mcbsp54.h.c5400cgtoolsinclude目录与c5400dsk5402include目录中的头文件类型不同。c
21、5400cgtoolsinclude目录下是5000系列DSP的通用头文件,与硬件无关。c5400dsk5402include目录下是硬件专用头文件,包括DSP芯片和dsk板。头文件和特定的库文件相关联,c5400cgtoolsinclude目录下的头文件与运行时支持库rts.lib相关联,c5400dsk5402include目录中的部分头文件与dsk板库文件drv5402.lib和dsk5402.lib相关联。drv5402.lib和dsk5402.lib函数库在c5400dsk5402lib目录下,dsk5402.lib是一个主要的库函数,内部使用了drv5402.lib。五、关于DSP
22、程序中段的定义一个程序中到底有哪些段定义?一般地,对于固定的硬件应用系统,其存储器的配置也较为固定,存储器的配置需要设计者自己定义,但理解了基本的段如:.text 、.data、 .stack 、.bss之外,用C语言编程时,对程序中所使用的段并不十分清楚,可以在写 .CMD文件时,只将MEMORY部分写出,而暂时省略掉SECTIONS定义,CCS集成开发环境会自动生成 .map文件,其中详细记录了存储器和段的配置和使用情况、各个段的绝对地址和重新分配后的全局符号,根据其中的段的描述,我们反过来再重新修改 .CMD文件,进行合理地段到存储器的分配。DSP C语言开发环境所必有的段定义: Cin
23、it ;C语言初始化段,包括初始化变量和常量表text ;代码段,包括可执行代码、字符串和常量Vectors ;中断向量段stack ;堆栈段,为C的系统堆栈分配存储空间,用于变量的传递trapconst ;包括字符串常量和以const关键字定义的常量data ;数据段bss ;保留全局和静态变量空间cioswitch ;为 .const语句建立的表格system ;为动态存储器函数malloc、calloc、realloc分配存储空间DSP的C语言程序设计实验一、分析工程blink.pjt中的程序blink.c,了解C语言程序的一般结构以及头文件和函数库的关系,并解读头文件的内容二、修改程序
24、blink.c,使三个发光二极管指示灯依次流水点亮熄灭例:编写程序blink.c主要说明: DSP C程序编制的流程函数库中函数的使用(例如Board.h)Project的建立、编译、调试、执行CMD文件的编写试重新定义 .CMD文件,重新对project进行编译运行。自编写CODEC程序,.h头文件在c5400dsk5402include目录下,头文件对应的函数在c5400dsk5402libdrv5402.lib和dsk5402.lib 中。 dsk5402是一个主要的库函数,内部使用了drv5402.lib。5402上有两个多通道缓冲串行口(MCBSP0和MCBSP1),其寄存器定义位于
25、头文件Regs.h和Reg54xx.h当中。 如果在File菜单中头“load program”项说明目标报未正常连接,注意观察 条提示:VECS:0080h length=0080h /*internetPRAM:orgin=7600h,length=8000h program Ran */Scratch RAN5402 DSP 程序寄存储藏256K 如同加载执行 DSP 5402 64K(更多)程序存储器空间 64K(更多)数据存储器空间 64K I/O存储器空间可以由:片上ROM,片上RAN,片外floah,片外RAN构成取决定于:MP/MC OVLY FLASHENB,当map在外部存
26、储器时,由于FLASHE决定访问FLAH=1还是外部RAN=0,OVLY FLASH 可以由片上RAM、RAN,片外flash RAM构成取决于DROM DMSEL,当map外部存储器空间时,由DMSEL决定是访问FLASH/RAM(DMSEL=0)还是子报存储器,FLASH14个等待周期;RAM1个等待周期。 C5402 Device Simulater; Mp/mc=1 Ovly=1 DRAM=05402 DSK load program 后:mp/mc=1 OVLY=1 DROM=0运行程序后:mp/mc=0 OVLY=1 DROM=0与管脚一致,suwsr等待状态寄存器D844 1 1
27、 0 1 1 0 0 0 01 00 0 100 I/O空间 高32K 低32K 高32K 低32K 5 4 1 0 4MCBSP串口以及AD50的初始化,AD50初始化包括以下步骤:1打开CODEC 获取句柄(指针)2设置AD转换的工作方式3设置DA转换的工作方式4设置模拟输入增益5设置模输出增益6设置取样率 board init Flagcade init Flag code_setup_serial_port 设置串口 code_reset codee复位 cline_reset code_disable_tx_isr code_disable_vx_isr code_write_regs code_setup_serical_port serial_reset D:DSPTEST、DTKfftdee5416.c 把Project中所用到的所有头文件、库文件、包含文件均方向在Project目录下,解析此工程,了解库函数的定义与源程序,Code 的操作 串口(MCBSP)的操作MCBSP:TMS320C5000系统DSP系统设计与开发实例,熟悉多通道缓冲串口的结构组成以及各个寄存器的内容工作方式,编程方法:MCBSP的初始化串口复位(发送复位、接收复位)设置所有寄存器的值SPCR1、SPCR2、RCR1、RCR2、XCR1、XC