您好,欢迎访问三七文档
当前位置:首页 > 行业资料 > 其它行业文档 > ADSP基础入门-第6讲-Blackfin嵌入式C编程
TheWorldLeaderinHighPerformanceSignalProcessingSolutionsBlackfinCprogrammingBlackfin嵌入式C编程电子工程学院陈子为成信院-ADI联合实验室2C/C++编译器简介VisualDSP++使用ccblkfn编译器,此C/C++编译器有如下功能:处理C和C++源文件,产生机器级源代码和目标文件。在目标文件中包含可重定位的代码和调试信息。在处理器存储区中提供可由链接器替换的可重定位数据和程序存储段。C/C++编译器处理C和C++语言源文件并生成Blackfin汇编源文件。汇编源文件由BlackfinDSP系列汇编器(easmblkfn.exe)汇编产生。汇编器进一步产生ELF(ExecutableandLinkableFormat)目标文件,由它可以链接(使用链接器)产生一个BlackfinDSP可执行文件或将其包含在一个档案文件库(elfar.exe)中。编译器如何控制处理过程的汇编,链接和存档阶段取决于输入源文件和所用的编译器选项。成信院-ADI联合实验室3BlackfinC/C++编译器支持的数据类型类型位大小数学表示方式使用sizeof()返回值char8位有符号8位二进制补码1unsignedchar8位无符号8位无符号量1short16位有符号16位二进制补码2unsignedshort16位无符号16位无符号量2int32位有符号32位二进制补码4unsignedint32位无符号32位无符号量4long32位有符号32位二进制补码4unsignedlong32位无符号32位无符号量4指针32位32位二进制补码4函数指针32位32位二进制补码4float32位32位IEEE单精度4double64位64位IEEE双精度8fract1616位有符号1.15小数形式2fract3232位有符号1.31小数形式4成信院-ADI联合实验室4注意:Blackfin定点处理器只支持定点运算,宽度最高32位,所以浮点数据及64位数据不直接支持,需通过软件转换来实现转换,速度会降低很多。分数形式的数据类型fract16和fract32并不是实际存在的数据类型,事实上就是以short和int形式存储,即1.15的16位有符号short整型(定点型),1.31的32位有符号int整型(定点型),用于表示有符号小数。typedefshortfract16;typedefintfract32;使用该数据类型时需要先#includefract.h成信院-ADI联合实验室5逻辑操作符与位操作符逻辑操作符——与(&&)、或(||)、非(!)对操作数执行逻辑操作,主要用于if等判断语句中。例如:if(xSCR_XSIZE&&SCR_YSIZE)位操作符——与(&)、或(|)、求反(~)、异或(^)、左移()、右移()&位与——清除某个位或某些位例:#definepLCDCON(volatileunsignedint*)0x1F00000*pLCDCON&=0xfffffffe;//清除LCD控制寄存器的最低位来关闭LCD|位或——设置某个位或某些位例:*pLCDCON|=0x1;//设置LCD控制寄存器的最低位来打开LCD^位异或——将某个位或某些位取反成信院-ADI联合实验室6左移——设置寄存器的位或乘以2n例:*pLCDCON=0x66;//设置LCDCON寄存器的第6位、第7位为1*pLCDCON=(*pLCDCON&0xFFF0FFFF)|(0x0516);//保持其它位不变,单独设置第16~18位为101右移——实现除法(除以2n)如果除数是2的n次方,编译器就会调用移位操作来完成除法运算(无符号除法比有符合除法的效率高)。~求反——将每一位取反。例如:HC595_SendDat(~DISP_TAB[i]);//输出LED显示数据成信院-ADI联合实验室7Volatile的用法volatile在英文字典的解释为“易变的,反复无常的(性格)”。编译器有一种技术叫数据流分析,分析程序中的变量在哪里赋值、哪里使用、哪里失效,分析结果可以用于常量合并,常量传播等优化。当它觉察到你的代码没有修改变量的值时,它就可能在你访问变量时提供上次访问的缓冲值,这能够提高程序的效率。但这些优化可能会带来问题(特别是对硬件寄存器操作的程序中),这时需要用volatile关键词来禁止做这些优化。——告诉编译器:变量已经变化,不要用缓存值(变量可能会随时改变,不要对其优化,而是每次用的时候去读写该变量。)成信院-ADI联合实验室8使用volatile变量的场合硬件寄存器通常要加volatile说明。#definepFlashA_PortA_Dir(volatileunsignedchar*)0x20270006在中断服务程序中修改的供其它程序检测的变量需要加volatile。例如:中断服务程序常常通过改变一些全局变量来通知应用程序某个外部事件已经发生,这些全局变量不应该被优化。多任务环境中各任务间共享的标志应该加volatile。成信院-ADI联合实验室9C/C++编译语言扩展编译器支持对ISO/ANSI标准的C语言和C++语言的扩展。为了使C/C++扩展中附加关键字与ISO/ANSI标准C/C++的关键字不冲突,C/C++扩展中附加关键字在形式上均以双下划线“__”打头。标准C/C++关键字用一个下划线“_”打头,编译器扩展C/C++关键字用两个下划线“__”打头;标准库函数名用一个下划线“_”打头,编译器扩展的库函数(由编译器给出的内嵌函数)名用两个下划线“__”打头。成信院-ADI联合实验室10C/C++编译语言扩展内联函数关键字(inline),ccblkfn的inline关键字使声明为inline类型的函数代码内嵌到调用它的地方。inline是C++的标准特点,ccblkfn将它作为C的扩展。使用该选项节省了调用函数的额外时间开销,因此提高了程序执行速度。内联汇编语言关键字(asm),ccblkfn的asm()结构可在C/C++函数中内嵌BlackfinDSP汇编语言指令。对程序中用C或C++不易或不能高效实现的地方可以用asm()结构利用汇编语言实现。成信院-ADI联合实验室11指定要放置数据的存储器位置的关键字(section),section关键字使编译器在汇编器的交叉输出文件的.SECTION中放置目标或函数代码。可以用section()中的字符串参数命名.SECTION。如果对目标或函数声明没有指定section(),编译器会使用默认值。例如:section(“buffer”)intin[1024]={#include“sine.dat”};指针受限关键字(restrict),restrict关键字支持受限制的指针特性。restrict的使用局限于声明一个指针,并指明指针是访问它所指向内容的惟一途径。简单来说,restrict使指针不能使用别名,即两个不同受限指针不能指向同一个对象(指针不能有别名)。成信院-ADI联合实验室12内置函数(buildin),编译器支持使用内置函数,从而有效利用硬件资源。有关这些函数的信息已经内嵌在编译器中。用户程序使用正常的函数调用句法调用它们。编译器处理此类函数调用,会生成一条或多条机器指令,就像处理正常的操作符(如+和*)那样。内置函数名是以__builtin_开始的。头文件为内置函数定义一个可读性更好的名称,这个名称不使用__builtin_前缀。例如在ccblkfn.h中:#definesysreg_write(A,B)__builtin_sysreg_write(A,B)成信院-ADI联合实验室13预处理命令预处理器在编译器之前运行,它在编译之前对等待处理的代码进行预处理。预处理器指令以“#”开始,以回车符结束(不能有“;”号),如何预处理器指令长于一行,用“\”续行。预处理器指令对大小写敏感,必须用小写。预处理命令的功能如下包含系统和用户定义头文件,例如#include定义宏和标志常量,例如#define提供条件汇编和编译,例如#ifdef、#ifndef、#if(均以#endif结束)成信院-ADI联合实验室14#if和#endif条件编译指令,例如:#defineLCD_TYPEMLCD_320_240#if(LCD_TYPE==MLCD_320_240)#defineSCR_XSIZE(640)#defineSCR_XSIZE(480)#defineLCD_XSIZE(320)#defineLCD_XSIZE(240)#if(LCD_TYPE==CLCD_240_320)#defineSCR_XSIZE(640)#defineSCR_XSIZE(480)#defineLCD_XSIZE(240)#defineLCD_XSIZE(320)#endif技巧:在程序调试中,可以用#if临时注释掉一段代码,如下所示:#if0…#endif当需要这段代码时,只需将0变为1即可。成信院-ADI联合实验室15系统库函数(内置函数)编译器内置函数(CompilerBuiltinFunction),主要针对一些常用的操作,其实现大多与处理器硬件电路有关。内置函数一般采用汇编语言编写,一旦用户调用此函数,编译器直接映射到相应的汇编代码中(会被编译器识别出来,使用固定的汇编语句来代替库函数的调用),运行效率很高。有一些内置函数是系统管理函数,这些内置函数将系统管理的各项操作封装成函数,直接调用这些内置函数将能提高代码的可读性。例如:获取系统时钟周期的函数示例如下//使用内联汇编程序,程序可读性差//使用ADI提供的内置函数,可读性好unsignedintget_cycles(void){unsignedintret_val;asm(“%0=CYCLES;”:”=d”.(ret_val)::);returnret_val;}#includeccblkfn.h#includesysreg.hunsignedintget_cycles(void){returnsysreg_read(reg_CYCLES);}Clevelfunctionswithseveralassemblyinstructionsandexpandedintocompilerintermediateinstruction成信院-ADI联合实验室16系统库函数内部函数通常支持16位或32位数的操作包括libc、libdsp、libetsi、libio、lwip、libbtc等库,支持如下的操作和函数:小数值内部函数ETSI(欧洲电信标准协会)标准的支持复数小数数据和操作Viterbi编码和解码函数循环缓冲区函数高低字节交换(Endian-swapping)函数系统内部函数视频操作函数未对齐的数据函数内部函数支持防止溢出的饱和算法,这一点与标准C程序不同。库文件位置:安装目录\Blackfin\lib\头文件位置:安装目录\Blackfin\includes\源代码位置:安装目录\Blackfin\lib\src\可根据需要对源代码进行修改,请将文件复制到其它地方,重命名后再进行修改。调用库文件时需要先引用相应的头文件。成信院-ADI联合实验室17示例完成一个256阶的FIR滤波器:intfilter(short*in,short*coeff){inti;intacc=0;for(i=0;i128;i++){acc+=((in[i]*coeff[i])15);}returnacc;}#includefract.hfract32filter(fract16*in,fract16*coeff){inti;fract32acc=0;for(i=0;i128;i++){acc=add_f
本文标题:ADSP基础入门-第6讲-Blackfin嵌入式C编程
链接地址:https://www.777doc.com/doc-6284890 .html