移植CMSIS-DSP库到CodeWarrior的步骤以及Kinetis FPU单元应用的对比

Document created by Const Yu Employee on Nov 29, 2013
Version 1Show Document
  • View in full screen mode

在电机控制,Audio等很多应用中,我们经常会用到一些常见的正余弦,矩阵变换,FFT等一些DSP函数,提到DSP库,通常会想到使用ARM 公司提供的 CMSIS 库。CMSIS 库是ARM和一些半导体厂家针对Cortex-M系列制定的一套接口标准,包括针对内核操作的CMSIS-CORE API,针对DSP应用的CMSIS-DSP Library,针对RTOSCMSIS-RTOS API,与外设接口的CMSIS-SVD以及提供Debug访问接口的CMSIS-DAP 其中,又以DSP应用的CMSIS-DSP 库的应用最为广泛。针对Cortex-M4中的DSP功能,CMSIS-DSP部分提供了超过60多种功能的DSP算法库,尤其是随着Cortex-M4中集成了FPU硬件单元,CMSIS-DSP 库的应用也越来越广泛。

KEIL IAR中都集成了对CMSIS的支持,然而在CodeWarrior中没有直接支持CMSIS,需要用户移植到自己的CW工程中,所以就需要使用者了解CMSIS的结构,手动添加库文件和头文件,并完成一些重要的编译参数配置。特别是有些芯片支持FPU浮点运算单元,有些不支持,在配置选项上差别很大。在飞思卡尔Kinetis系列芯片中,FPU浮点运算单元也是一个可选的部件,只有在名称中带有FNFX的芯片才支持FPU硬件浮点功能,如MK60FN1M0, MK60FX512。本文档分别介绍在使用和不使用FPU的情况下如何一步步移植CMSISDSP库到自己的CodeWarrior工程中。

需要注意的是 FPU 单元是指的芯片上的一个独立于 CPU 处理的浮点运算单元,整个单元在大多数厂家的芯片中都是可以被使能和关闭的。相对于芯片,编译器也设置了相应的 FPU 功能开启/关闭的选项,在编译时需要告诉编译器是否开启 FPU 功能。编译器一旦开启 FPU 功能,在处理单精度浮点运算的语句时就会用带 V-开头的汇编指令进行编译。如果编译器使能了 FPU 功能,而芯片未开启 FPU 单元,程序运行到浮点语句时就会出现异常。相反,如果编译器未使能 FPU 功能,芯片即使开启了 FPU单元,程序还是会按照未使能 FPU 的代码进行处理。在本例程中,为对比分析是否采用FPU的编译指令差别以及在板的执行效率,选用Kinetis K70FN1M为实验对象。

硬件平台:TWR-K70F120M核心板      软件环境:CodeWarrior v10.5        CMSIS版本 :V3.2

一. 准备工作:

下载CMSIS的库,当前最新的版本为V3.2,解压后名称为CMSIS-SP-00300-r3p2-00rel1,其目录结构如下图。分别包含CMSIS-DSP, CMSIS-RTOSCMSIS-SVD的库文件。在本Cortex M4CMSIS-DSP的应用中,真正用到的文件包括CMSIS\IncludeCM4相关的头文件,CMSIS\Lib\GCC文件夹中的库文件libarm_cortexM4l_math.a(软浮点)libarm_cortexM4lf_math.a(硬浮点),以及Device\ARM\ARMCM4\include中外设访问相关的两个头文件。

1.bmp

二. 不使用K70FPU浮点运算单元,移植CMSISDSP库到CW的步骤;


     Step 1:    新建一个Baremental的工程,选择器件器件MK70FN1M0(支持硬件FPU);

2.bmp

    Step 2:    选择Floating Point浮点运算实现的类型,即指定编译器将C代码编译成汇编代码时使用的规则;

3.bmp

Floating Point四个选项含义如下:

    • Software选项:表示不使用FPU硬件,而是使用GCC的整数算术运算来模拟浮点运算;
    • Handware(-mfloat –abi=hard) 选项:表示使用FPU硬件来进行浮点运算,函数的参数直接传递到FPU的寄存器(s0-d0)中;
    • Handware(-mfloat –abi=softfp)选项:表示使用FPU硬件来进行浮点运算,但是函数的参数传递到整数寄存器(r0-r3)中,然后再传递到FPU中;
    • Handware(-mfloat –abi=softfp –fshort -double)选项:其配置项同上,只不过使能了fshort  double功能,并且此处的double数据的宽度等同于float

有兴趣研究各个选项意义的可以参考CW for MCU技术文档的第3章,在本例程中使用的是软浮点,所以选择Software项。需要注意的是:此配置选项仅出现支持FPU硬件单元的芯片工程中,如MK60FN1M0, MK60FX512等,否则默认没有此选项,默认为软件浮点。

Step 3:    点击“Next”进入下图,选择使用Processor Expert,点击“Finish“完成工程的建立;

4.bmp

Step 4:    进入当前工程的文件夹,新建文件夹CMSIS,从之前在准备步骤解压的CMSIS文件包\...\CMSIS-SP-00300-r3p2-00rel1\CMSIS中拷贝IncludeLib文件夹到当前工程新建的CMSIS文件夹。另外,拷贝\...\CMSIS-SP-00300-r3p2-00rel1\Device\ARM\ARMCM4\Include中的ARMCM4.hsystem_ARMCM4.h到当前工程新建的CMSIS文件夹中;

5.bmp

Step 5:    回到CodeWarrior界面选择新建的工程文件,F5刷新可以看到CMSIS出现在工程文件中。其中IncludeCMSIS库的一些头文件,包括M0+/M3/M4的一些头文件;在Lib文件中是已经编译好的库文件,ARM文件夹是使用在KEIL IDE中的库文件,G++文件夹是使用在IAR中的库文件,而由于当前CW工程使用的GCC的编译器,所以GCC文件夹才是CW需要的,因此,为缩减工程大小可以删除ARMG++文件夹;

6.bmp

    Step 6:    打开工程属性框,选择Target ProcessorFloat ABINo FPU

7.bmp

Step 7:    GCC ComplierDefined symbols中添加编译的宏定义ARM_MATH_CM4

8.bmp

Step 8:    GCC ComplierInclude paths中添加CMSIS库的头文件,路径为:工程目录\CMSIS\Include

9.bmp

Step 9:    GCC C LinkerMiscellaneous项的Other objects中指定使用的库文件(位于CMSIS\Lib\GCC文件夹中)。因为本例程中不使用FPU,所以选择libarm_cortexM4l_math.a,此处需要特别注意,否则编译会报错;

10.bmp

Step 10: ProcessorExpert.c文件中添加代码;

#include <math.h>

#include "arm_math.h"

 

#define DELTA    (0.000001f)

 

const float32_t testRefOutput_f32 = 1.000000000;

const float32_t radians=1.047197533333333;

 

float32_t  cosOutput, sinOutput, diff;

float32_t cosSquareOutput,sinSquareOutput,testOutput;

 

int main(void)

{

  int m,n;

  PE_low_level_init();

 

  cosOutput = arm_cos_f32(radians); /*求正余弦*/

                  sinOutput = arm_sin_f32(radians);

             

                  arm_mult_f32(&cosOutput, &cosOutput, &cosSquareOutput, 1); /*求积运算*/

  arm_mult_f32(&sinOutput, &sinOutput, &sinSquareOutput, 1);

             

arm_add_f32(&cosSquareOutput, &sinSquareOutput, &testOutput, 1); /*求和运算*/

  diff = fabsf(testRefOutput_f32 - testOutput);  /* 求绝对值 */

             

  if(diff > DELTA)

  {

                        while(1)

                                {

                                  for(m=0;m<2000;m++)

                                                for(n=0;n<200;n++){};

                                                D7_NegVal();

                                }

    }

                }

Step 11:    编译并下载Debug,在  sinOutput = arm_sin_f32(radians);处设置断点,可以看到CMSIS-DSP库中的正余弦浮点数运算函数运算正常,其反汇编的得到为普通的ARM指令(FPU 单元汇编指令通常在普通指令前加字母V,仅在 FPU 功能被使能时使用),完成一个正弦计算;

11.bmp

至此,完成了不使用K70FPU浮点运算单元,移植CMSISDSP库到CW的步骤。


    三.     使用K70FPU浮点运算单元,移植CMSISDSP库到Codewarrior的步骤


使用K70FPU硬件浮点运算单元,移植CMSISDSP库到Codewarrior的方法有两种:一种是按照上面软浮点的方式Step By Step的建立工程,步骤和上面二的步骤基本一致,主要的两个区别在于:(1). Step 2要选择Handware(-mfloat abi=hard) 选项,(2). Step 9 改为libarm_cortexM4lf_math.a。另外一种就是在上面工程的基础上修改配置选项。鉴于方便,本教程采用第二种方案,完成在Codewarrior中调用CMSISDSP库,通过K70FPU浮点运算单元执行浮点运算,即硬浮点。

Step 1:    打开工程属性对话框选择Target ProcessorFloat ABIFPU with hard vfp passing(-mfloat –abi=hard)

12.bmp

Step 2:    GCC ComplierDefined symbols中添加编译的宏定义:_VFPV4

13.bmp

Step 3: GCC C LinkerLibraries项的library search path中指定链接的规则,把上面工程中默认的"${MCUToolsBaseDir}/ARM_GCC_Support/ewl/lib/armv7e-m"修改为 "${MCUToolsBaseDir}/ARM_GCC_Support/ewl/lib/armv7e-m/fpu"

14.bmp

Step 4:    GCC C LinkerMiscellaneous项的Other objects中指定使用的库文件(位于CMSIS\Lib\GCC文件夹中)。因为本例程中使用FPU,所以选择libarm_cortexM4lf_math.a,此处需要特别注意,否则编译会报错;

15.bmp

Step 5:    完成以上配置后,编译工程并下载调试(此处建议编译之前先Clean一下整个工程),同样,在  sinOutput = arm_sin_f32(radians);处设置断点,可以看到CMSIS-DSP库中的正余弦浮点数运算函数运算正常,其反汇编的得到为FPU指令(FPU指令通常是指在普通指令前加字母V,仅在 FPU功能被使能时使用),并且在Register观察窗口中也多了个FPU寄存器列表,感兴趣的读者可以对比一下和前面实验汇编出代码的差异,此处不再赘述;

16.bmp

至此,分别完成了使用和不适用K70FPU浮点运算单元情况下, CMSISDSP库到Codewarrior的移植。在实际应用中需要用到更多的DSP函数,在项目中直接调用即可。下一步, Just Enjoy The Convenience of  The CMSIS!

有一点需要说明的是,前文中讲到使用FPU单元需要两步设置:(1). 在编译器中开启相应的 FPU 功能选项;(2). 开启芯片FPU 单元。似乎我们前面的设置是完成了第一个步骤,然而第二个步骤呢?仔细查看_arm_atart.c文件,可以发现代码_fp_init()正是完成了开启芯片FPU单元的过程,如下图,是一个条件编译函数,这也就解释了为什么在上面Step 2中定义了_VFPV4,其本质也就是使能芯片的FPU单元,其具体实现可以查看ARM手册的第74页的描述

#ifdef   __VFPV4__        //Step 2中的宏定义

                __fp_init();      // 开启芯片的FPU单元

#endif

Attachments

    Outcomes