社区导航

 

搜索
查看: 10380|回复: 33

利用浮点库实现两路FIR滤波(F28335)

  [复制链接]

364

TA的帖子

16

TA的资源

纯净的硅(高级)

Rank: 6Rank: 6

发表于 2013-8-16 21:09 | 显示全部楼层 |阅读模式
       此文素材来源于在项目中增加两路FIR滤波算法进行过程中而遇到的问题以及探索出的解决方法。以controlSUITE上的一个demo——2833x_FIR为基,一步步展示遇到的问题与解决方案。
文章中涉及到的软、硬件信息:XP or Win7系统  CCSV5.2  TMS320F28335
本文主要分三个部分,1、建立自己的工程基石,后续项目开发工程以此为奠基,并能传承给下一位开发者或维护者  2、修改demo,展示两种错误,并解决,实现两路FIR滤波  3、解决Release版本中的问题

       P.S.已经了解怎么打造自己的工程可以直接跳过第一部分。第一部分因为dontium版主已经做过详细的介绍,因此第一部分写的相对简洁。初学者或有意详细了解的,可查看该主题《打造自己的C2000 LaunchPad项目》
http://bbs.eeworld.com.cn/thread-360489-1-1.html
       篇幅比较长,请耐心,附上工程和pdf(各收取1芯片作为劳务费啊)。原pdf图片与文字不匹配,现已更正。


[ 本帖最后由 newofcortexm3 于 2013-8-16 22:24 编辑 ]

F28335_FIR_FPU.rar

309.88 KB, 下载次数: 173

售价: 1 枚芯币  [记录]

利用浮点库实现两路FIR滤波.pdf

1.31 MB, 下载次数: 229

售价: 1 枚芯币  [记录]



回复

使用道具 举报

2992

TA的帖子

260

TA的资源

五彩晶圆(高级)

Rank: 9Rank: 9Rank: 9

荣誉会员勋章测评达人

发表于 2013-8-17 09:52 | 显示全部楼层
这一类东西应用性很强,而且论坛这一方面的东西偏少,必须赞啊。

点评

能为网友提供可参考意见是我的荣幸啊!以后还请斑竹多多指教!:tongue:  详情 回复 发表于 2013-8-17 21:38


回复

使用道具 举报

364

TA的帖子

16

TA的资源

纯净的硅(高级)

Rank: 6Rank: 6

 楼主| 发表于 2013-8-16 21:58 | 显示全部楼层

第三部分

第三部分:Release模式下解决编译不通过的问题。
      Release模式会对程序进行优化,常常以这个模式下生成的代码作为发布的版本。Release模式与Debug模式相比,编译选项不同,因此对某些库链接时会发生编译错误。
在将可发布的版本固化在flash过程中,在Release模式下遇到的编译问题如图16所示,其中错误的描述见Console,如图17,指工程链接的库与ISA版本不合适。关于这个问题的解决方法的描述的官方链接如下,但是没法解决实际遇到的问题。
图16.jpg
16:编译遇到的问题与警告
图17.jpg
17:编译错误的具体描述
首先解决错误,与第一部分中Include库文件类似,在Properties->C2000 Linker->Include library file or command file as input (--library,-l)中添加“libc.a”库,如图18所示,即可解决错误问题。libc.a是标准C语言库,一般情况下自动被gcc链接,这个库提供了通常与C语言相关的函数。关于libc.a的介绍可以查看链接http://www.delorie.com/djgpp/doc/libc/libc_1.html
http://www.delorie.com/djgpp/doc/libc/libc_530.html

图18.jpg
18:添加libc.a
警告的解决与第二部分中修改cmd文件类似,但稍稍有些不同。具体的修改是在F28335.cmd文件末尾添加下文的代码。此时一个可发布的实现两路FIR滤波程序就大功告成了。Please Enjoy!!
SECTIONS
{
   firldb   align(0x400) > FLASHH   PAGE = 0
   firldb_c   align(0x400) > FLASHH   PAGE = 0

   firfilt      align(0x400) > RAML1   PAGE = 0
   firfilt_c  align(0x400) > RAML1   PAGE = 0
   coefffilt  align(0x800)> RAML2   PAGE = 0
}   


回复

使用道具 举报

364

TA的帖子

16

TA的资源

纯净的硅(高级)

Rank: 6Rank: 6

 楼主| 发表于 2013-8-16 21:27 | 显示全部楼层

第一部分

        第一部分:如何将demo打造成自己的工程,并能实现移植(拷贝到其他人的电脑上能直接buildDebug)。demo路径:C:\ti\controlSUITE\libs\dsp\FPU\v131\examples\2833x_FIR
         如何导入工程并拷贝到自己的workspace就不再累述。重点是如何添加所需的文件。在此demo中,主程序文件在source目录下,其他的外设配置程序和cmd文件都是链接(link)过去的。
         1.拷贝外设配置的头文件和用到的浮点库文件到工程目录中,并对这些文件添加到工程中作include配置。头文件路径:
C:\ti\controlSUITE\device_support\f2833x\v133\DSP2833x_common\include   
此目录里的文件主要是对外设的一些宏定义(跟手册中一致)和对中断处理程序作了定义与声明。
   
C:\ti\controlSUITE\device_support\f2833x\v133\DSP2833x_headers\include      

此目录中的文件就是外设寄存器的结构体定义与基本配置的一些函数。
        将这些文件拷贝到工程目录下的include(新创建)文件夹中。拷贝库文件C28x_FPU_Lib.libFPU.h文件到工程目录的lib文件夹下,C28x_FPU_Lib.libFPU.h分别在目录:C:\ti\controlSUITE\libs\dsp\FPU\v131\lib  C:\ti\controlSUITE\libs\dsp\FPU\v131\include
       (1.Include头文件的配置:右击工程,点击PropertiesProject->Properties亦可),在CCSProperties->C2000 Compiler->Include OptionsAdd dir to #include search path中删除 "${INSTALLROOT_TO_FPU_V131}/include"FPU.h的路径)、"${INSTALLROOT_2833X_V133}/DSP2833x_common/include""${INSTALLROOT_2833X_V133}/DSP2833x_headers/include"
添加 "${PROJECT_ROOT}/include""${PROJECT_ROOT}/lib/include",如图1所示。
         INSTALLROOT_2833X_V133INSTALLROOT_TO_FPU_V131具体代表什么意思,可在Properties->Resource->Linked ResourcePath Variables中查看,如图2所示。
        (2).Include库文件的配置:右击工程,点击Properties(Project->Properties亦可),在Properties->C2000 Linker-> File Search Path删除"${INSTALLROOT_TO_FPU_V131}/lib",增加 "${PROJECT_ROOT}/lib",如图3所示。

图1.jpg

图 1:Include Options
图2.jpg
图 2:Linked Resource
图3.jpg
图 3:File Search Path
        2.拷贝外设配置文件到工程目录的src文件夹下(CCS会自动把文件更新到Project Explorer窗口),外设配置文件的路径:
C:\ti\controlSUITE\device_support\f2833x\v133\DSP2833x_common\source
这个路径可通过右击链接的文件,点击Properties,在Properties->Resource中查看到,如图4。当然这些文件中有些是不常用的,在编译时可以不用build,能加快编译的速度,并且杜绝某些错误。
        如何不需要的文件跳过编译?选中不需要编译的文件右击,选择Resource Configurations->Exclude from build,在弹出的窗口中点击Select All。下次需要编译时选择Deselect All即可,当然DebugRelease是可选的,如图5。通用的外设配置文件见图6黑色部分,图6中灰色部分是demo
中不需要用到的外设,以后可根据项目的需要添加外设,而把这些配置程序包含进工程。

图4.jpg

图 4:文件Resource
图5.jpg
图 5:Exclude from build
图6.jpg
图 6:Files Include or Exclude from build
       3.拷贝cmd文件到工程目录下。C2000cmd文件主要有两类,第一类与BIOS系统有关,以用到的TMS320F28335为例,其与系统相关的cmd文件有DSP2833x_Headers_nonBIOS.cmdDSP2833x_Headers_BIOS.cmd;第二类与可执行文件(CCS生成的.out文件)存储的介质有关,例如28335_RAM_lnk.cmdF28335.cmd。在用于C2000微处理器的资料与工具集软件controlSUITE中,DSP2833x_Headers_nonBIOS.cmdDSP2833x_Headers_BIOS.cmd的路径:
C:\ti\controlSUITE\device_support\f2833x\v133\DSP2833x_headers\cmd
28335_RAM_lnk.cmdF28335.cmd的路径:
C:\ti\controlSUITE\device_support\f2833x\v133\DSP2833x_common\cmd
       上述目录中28335_RAM_lnk.cmdF28335.cmdTI官方提供的,未根据特殊的实例作优化。在本demo中,已经针对FIR滤波算法对28335_RAM_lnk.cmd做过修改,该文件已重命名为28335_FIR_RAM_lnk.cmd,其目录:
C:\ti\controlSUITE\libs\dsp\FPU\v131\cmd\28335_FIR_RAM_lnk.cmd
       4.将链接(linked)的文件(带有小箭头的文件)全部删除,把不需要编译的文件Exclude from build,可执行文件是在RamFlash中运行可通过Exclude from build选择,具体操作见2。此时你自己的工程就打造完毕了。


[ 本帖最后由 newofcortexm3 于 2013-8-16 21:37 编辑 ]


回复

使用道具 举报

364

TA的帖子

16

TA的资源

纯净的硅(高级)

Rank: 6Rank: 6

 楼主| 发表于 2013-8-16 21:42 | 显示全部楼层

第二部分第一个错误

第二部分:实现两路FIR滤波过程中遇到的问题与解决方法。
第一个错误:
主要部分的代码:
……
#define FIR_ORDER   63     /* ORDER = NUM_TAPS - 1 */  
#define SIGNAL_LENGTH (FIR_ORDER+1)* 4  

#pragma DATA_SECTION(firFP, "firfilt");
FIR_FP  firFP = FIR_FP_DEFAULTS;

#pragma DATA_SECTION(dbuffer, "firldb")
float dbuffer[FIR_ORDER+1];

//#pragma DATA_SECTION(sigIn, "sigIn");
//#pragma DATA_SECTION(sigOut, "sigOut");
float sigIn[SIGNAL_LENGTH];
float sigOut[SIGNAL_LENGTH];
float sigIn_c[SIGNAL_LENGTH];
float sigOut_c[SIGNAL_LENGTH];

#pragma DATA_SECTION(coeff, "coefffilt");
float const coeff[FIR_ORDER+1]= FIR_FP_LPF64;

float xn,xn_c,yn,yn_c;
float Fir_filter(float intput);
……
void main( )
{
          ……
        firFP.order=FIR_ORDER;
        firFP.dbuffer_ptr=dbuffer;
        firFP.coeff_ptr=(float *)coeff;
        firFP.init(&firFP);

       for(i=0; i < SIGNAL_LENGTH; i++)
       {
         //xn=0.5*sin(Rad) + 0.5*sin(Rad2); //Q15
              xn=0.5;
              sigIn=xn;
              yn = Fir_filter(xn);
              sigOut=yn;

              xn_c=0.6;
              sigIn_c=xn_c;
              yn_c= Fir_filter(xn_c);
              sigOut_c=yn_c;

          Rad = Rad + RadStep;
         Rad2 = Rad2 + RadStep2;
      }
……
}

float Fir_filter(float intput)
{
        float output;
        firFP.input= intput;
        firFP.calc(&firFP);
        output = firFP.output;
        return output;
       }
      程序Debug时的结果如图789所示,从图7中可以很明显的看到,ynyn_c的值均受到了影响。图8、图9分别是数组sigOutsigOut_c存储的对0.50.6滤波的结果,这两组数据均是有偏移的。(0.5的滤波结果是0.4818870.6的滤波结果是0.5782644
,这两个值均是通过单路滤波得到)。
result_problem_fun.jpg

图 7:滤波函数输出的结果
result_problem_fun11.jpg
图 8:第一个错误下数组sigOut存储的滤波结果
result_problem_fun12.jpg
图 9:第一个错误下数组sigOut_c存储的滤波结果


[ 本帖最后由 newofcortexm3 于 2013-8-16 21:44 编辑 ]


回复

使用道具 举报

364

TA的帖子

16

TA的资源

纯净的硅(高级)

Rank: 6Rank: 6

 楼主| 发表于 2013-8-16 21:48 | 显示全部楼层

第二部分第二个错误

     第二个错误:
还是先看代码:
……
#define FIR_ORDER      63     /* ORDER = NUM_TAPS - 1 */     
#define SIGNAL_LENGTH (FIR_ORDER+1)* 4
                                    
#pragma DATA_SECTION(firFP, "firfilt")
#pragma DATA_SECTION(firFP_c, "firfilt_c")
FIR_FP  firFP = FIR_FP_DEFAULTS;
FIR_FP  firFP_c = FIR_FP_DEFAULTS;
                                            
#pragma DATA_SECTION(dbuffer, "firldb")
float dbuffer[FIR_ORDER+1];

//#pragma DATA_SECTION(sigIn, "sigIn");
//#pragma DATA_SECTION(sigOut, "sigOut");
float sigIn[SIGNAL_LENGTH];
float sigIn_c[SIGNAL_LENGTH];
float sigOut[SIGNAL_LENGTH];
float sigOut_c[SIGNAL_LENGTH];
         
#pragma DATA_SECTION(coeff, "coefffilt");
float const coeff[FIR_ORDER+1]= FIR_FP_LPF64;

float xn,xn_c,yn,yn_c;
……
void main()
{
         ……
         firFP.order=FIR_ORDER;
         firFP.dbuffer_ptr=dbuffer;
         firFP.coeff_ptr=(float *)coeff;
         firFP.init(&firFP);

         firFP_c.order=FIR_ORDER;
         firFP_c.dbuffer_ptr=dbuffer;
         firFP_c.coeff_ptr=(float *)coeff;
         firFP_c.init(&firFP_c);

     for(i=0; i < SIGNAL_LENGTH; i++)
       {
         //xn=0.5*sin(Rad) + 0.5*sin(Rad2); //Q15
        xn = 0.5;
        sigIn=xn;
        firFP.input= xn;
        firFP.calc(&firFP);
        yn = firFP.output;
        sigOut=yn;

        xn_c=0.6;
        sigIn_c=xn_c;
        firFP_c.input = xn_c;
        firFP_c.calc(&firFP_c);
        yn_c = firFP_c.output;

        sigOut_c=yn;
        Rad = Rad + RadStep;
        Rad2 = Rad2 + RadStep2;
     }
……
}
程序在Debug模式下在线仿真的结如图101112所示,从图10中可以很明显的看到,yn的值收到yn_c的影响。图11、图12分别是数组sigOutsigOut_c存储的对0.50.6滤波的结果,图12存储的滤波结果是正确的,而图11的滤波结果受到了影响。

result_problem2.jpg

10:滤波结果
result_problem21.jpg
11:第二个错误下数组sigOut存储的滤波结果
result_problem22.jpg
12:第二个错误下数组sigOut_c存储的滤波结果


[ 本帖最后由 newofcortexm3 于 2013-8-16 21:54 编辑 ]


回复

使用道具 举报

364

TA的帖子

16

TA的资源

纯净的硅(高级)

Rank: 6Rank: 6

 楼主| 发表于 2013-8-16 21:52 | 显示全部楼层

第二部分实现两路FIR滤波

以上两个错误的原因是没有清醒的认识FIR_FP这个结构体,其定义如下:
typedef struct {
float *coeff_ptr;
float *dbuffer_ptr;
int cbindex;
int order;
float input;
float output;
void (*init)(void*);
void (*calc)(void*);
}FIR_FP;
其中,*coeff_ptr*dbuffer_ptr都是指针,即每定义一个FIR_FP结构体,必须给这两个指针指定指向的地址空间。以上的两个错误都是符合理论的,但是执行的过程中出现了错误,是因为执行FIR滤波时两个input都会存放在同一个dbuffer中。以下是两路的FIR滤波是实现的部分程序:
……
#define FIR_ORDER      63         
#define SIGNAL_LENGTH (FIR_ORDER+1)* 4
                                                                             
#pragma DATA_SECTION(firFP, "firfilt")
#pragma DATA_SECTION(firFP_c, "firfilt_c")
FIR_FP  firFP = FIR_FP_DEFAULTS;
FIR_FP  firFP_c = FIR_FP_DEFAULTS;
                                            
#pragma DATA_SECTION(dbuffer, "firldb")
#pragma DATA_SECTION(dbuffer_c, "firldb_c")
float dbuffer[FIR_ORDER+1];
float dbuffer_c[FIR_ORDER+1];

//#pragma DATA_SECTION(sigIn, "sigIn");
//#pragma DATA_SECTION(sigOut, "sigOut");
float sigIn[SIGNAL_LENGTH];
float sigIn_c[SIGNAL_LENGTH];
float sigOut[SIGNAL_LENGTH];
float sigOut_c[SIGNAL_LENGTH];
         
#pragma DATA_SECTION(coeff, "coefffilt");
float const coeff[FIR_ORDER+1]= FIR_FP_LPF64;
float xn,xn_c,yn,yn_c;
……
void main()
{
         ……
         firFP.order=FIR_ORDER;
         firFP.dbuffer_ptr=dbuffer;
         firFP.coeff_ptr=(float *)coeff;
         firFP.init(&firFP);
         
         firFP_c.order=FIR_ORDER;
         firFP_c.dbuffer_ptr=dbuffer_c;
         firFP_c.coeff_ptr=(float *)coeff;
         firFP_c.init(&firFP_c);

       for(i=0; i < SIGNAL_LENGTH; i++)
       {
          xn=0.5*sin(Rad) + 0.5*sin(Rad2); //Q15
           //xn = 0.5;
         sigIn=xn;
        firFP.input= xn;
        firFP.calc(&firFP);
        yn = firFP.output;
        sigOut=yn;

        xn_c=sin(Rad) + sin(Rad2); //Q15
        sigIn_c=xn_c;
        firFP_c.input = xn_c;
        firFP_c.calc(&firFP_c);
        yn_c = firFP_c.output;
        sigOut_c=yn_c;

        Rad = Rad + RadStep;
        Rad2 = Rad2 + RadStep2;
     }
……
}
         程序是没问题了,但编译还会出现警告(与图16中显示的基本一致),此时我们需要对28335_FIR_RAM_lnk.cmd做些修改。将原来
firldb   align(0x800) > RAML0   PAGE = 0
   firfilt       align(0x800) > RAML1   PAGE = 0  
   coefffilt  align(0x800)> RAML2   PAGE = 0
   sigIn align(0x800) > RAML6   PAGE = 1  
   sigOut     align(0x800) > RAML7   PAGE = 1
修改为:
firldb   align(0x400) > RAML0   PAGE = 0
   firldb_c   align(0x400) > RAML0   PAGE = 0
   firfilt         align(0x400) > RAML1   PAGE = 0
   firfilt_c   align(0x400) > RAML1   PAGE = 0
   coefffilt align(0x800)> RAML2   PAGE = 0
cmd文件的配置格式和具体存储区的划分方式可参考文档TMS320C28x Assembly Language Tools User's Guide v6.1.pdf,编号spru513E。在此处描述为什么align(0x400)(指定0x400字空间)。
在文档C28-FPU-LIB-UG.pdfC:\ti\controlSUITE\libs\dsp\FPU\v131\doc3.16节中指出缓冲区的最小值必须是2*order+1)字。在工程链接文件中,firdb指定的空间大于或等于最小需求。在本例中,最小的空间为2*63+1=128words,而align(0x400)的空间为4*162=1024words,已经满足要求。
修改完之后编译,Debug,程序执行结果如图131415所示。从图13中可知xn_cxn2倍,符合程序,滤波的结果yn_c亦是yn2倍,证明两路FIR滤波已经实现。图1415分别存储了正弦函数不同幅值下滤波的结果,对比两图发现,数组sigOut_c中的元素是数组sigOut中相同下标元素的2倍。

结果1.jpg

13:两路FIR滤波实现结果
结果21.jpg
14xn=0.5*sin(Rad) + 0.5*sin(Rad2)的滤波结果
结果22.jpg
15xn_c=sin(Rad) + sin(Rad2)的滤波结果
      此时在Debug模式下,两路FIR滤波算法已经实现,在下一部分将介绍在Release模式下实现两路FIR滤波。

[ 本帖最后由 newofcortexm3 于 2013-8-16 21:53 编辑 ]


回复

使用道具 举报

364

TA的帖子

16

TA的资源

纯净的硅(高级)

Rank: 6Rank: 6

 楼主| 发表于 2013-8-16 22:03 | 显示全部楼层

发现一个问题,一旦文字多的时候,字体和大小就不可控了,编辑变得非常困难。
花了两天时间重跑程序、截图、整理文字,现在终于休息下了。


回复

使用道具 举报

3365

TA的帖子

420

TA的资源

五彩晶圆(中级)

Rank: 8Rank: 8

荣誉会员勋章

发表于 2013-8-16 22:16 | 显示全部楼层
果断收藏备用


回复

使用道具 举报

364

TA的帖子

16

TA的资源

纯净的硅(高级)

Rank: 6Rank: 6

 楼主| 发表于 2013-8-17 21:38 | 显示全部楼层

回复 9楼ltbytyn 的帖子

能为网友提供可参考意见是我的荣幸啊!以后还请斑竹多多指教!


回复

使用道具 举报

6918

TA的帖子

90

TA的资源

裸片初长成(初级)

Rank: 10Rank: 10Rank: 10

发表于 2013-8-19 09:08 | 显示全部楼层
精华呀,谢谢分享!


回复

使用道具 举报

8

TA的帖子

0

TA的资源

一粒金砂(中级)

Rank: 2

发表于 2013-9-22 11:28 | 显示全部楼层
mark 收藏


回复

使用道具 举报

1万

TA的帖子

33

TA的资源

版主

Rank: 6Rank: 6

发表于 2013-9-22 21:57 | 显示全部楼层
好文章 !!!

楼主也学会使用"${PROJECT_ROOT}"了啊

[ 本帖最后由 dontium 于 2013-9-22 22:00 编辑 ]


回复

使用道具 举报

6

TA的帖子

0

TA的资源

一粒金砂(初级)

Rank: 1

发表于 2014-1-2 14:30 | 显示全部楼层
3q楼主啊,正在搞dft的移植,很有帮助


回复

使用道具 举报

21

TA的帖子

0

TA的资源

一粒金砂(中级)

Rank: 2

发表于 2014-4-3 10:19 | 显示全部楼层
我还没有看完,就决定必须要给楼主一个赞了!我觉得之前在网上找的资料根本没有这样手把手教的,都是千篇一律的告诉大家导入工程,根本没什么用,先谢谢楼主了!


回复

使用道具 举报

212

TA的帖子

7

TA的资源

一粒金砂(中级)

Rank: 2

发表于 2014-4-7 15:22 | 显示全部楼层
现在还没用到这些,先收藏了,谢谢楼主慷慨分享。
每天进步一点,大神带菜鸟,真是谢谢您们的支持、帮助和无私的奉献。


回复

使用道具 举报

8

TA的帖子

0

TA的资源

一粒金砂(初级)

Rank: 1

发表于 2014-7-10 10:23 | 显示全部楼层
不错的资料


回复

使用道具 举报

12

TA的帖子

1

TA的资源

一粒金砂(初级)

Rank: 1

发表于 2014-7-10 14:03 | 显示全部楼层
学习学习                          


回复

使用道具 举报

21

TA的帖子

0

TA的资源

一粒金砂(初级)

Rank: 1

发表于 2014-7-25 08:40 | 显示全部楼层
感谢分享


回复

使用道具 举报

2

TA的帖子

0

TA的资源

一粒金砂(初级)

Rank: 1

发表于 2014-10-9 10:18 | 显示全部楼层
感谢分享,很好啊


回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

关闭

站长推荐上一条 /7 下一条

  • 论坛活动 E手掌握

    扫码关注
    EEWORLD 官方微信

  • EE福利  唾手可得

    扫码关注
    EE福利 唾手可得

Archiver|手机版|小黑屋|电子工程世界 ( 京ICP证 060456 )

GMT+8, 2019-11-20 05:24 , Processed in 0.584642 second(s), 21 queries , Gzip On, MemCache On.

快速回复 返回顶部 返回列表