• 【STM32F407的DSP教程】第7章 ARM DSP源码和库移植方法(IAR8)


    完整版教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=94547

    第7章   ARM DSP源码和库移植方法(IAR8)

    本期教程主要讲解ARM官方DSP源码和库的移植以及一些相关知识的介绍。

    7.1 初学者重要提示

    7.2 DSP库的下载和说明

    7.3 DSP库版本的区别

    7.4 DSP库的几个重要的预定义宏含义

    7.5 DSP库在IAR上的移植(源码方式)

    7.6 DSP库在IAR上的移植(库方式)

    7.7 升级到最新版DSP库方法

    7.8 简易DSP库函数验证

    7.9 总结

    7.1   初学者重要提示

    1.   IAR请使用8.30及其以上版本,CMSIS请使用5.6.0及其以上版本。
    2.   IAR的工程创建,下载和调试方法,在V6用户手册有详细说明:http://www.armbbs.cn/forum.php?mod=viewthread&tid=93255

    7.2   DSP库的下载和说明

    下面详细的给大家讲解一下官方DSP库的移植。

    7.2.1  DSP库的下载

    DSP库是包含在CMSIS软件包(Cortex Microcontroller Software Interface Standard)里面,所以下载DSP库也就是下载CMSIS软件包。这里提供三个可以下载的地方:

    •   方式一:STM32CubeH7软件包里面。

    每个版本的Cube软件包都会携带CMSIS文件夹,只是版本比较老,不推荐。即使是最新的CubeH7

    软件包,包含的CMSIS软件包版本也有点低。

    •   方式二:MDK安装目录(下面是5.6.0版本的路径)。

    大家安装了新版MDK后,CMSIS软件包会存在于路径:ARMPACKARMCMSIS5.6.0CMSIS。

    如果有更新的版本,推荐大家使用最新版本,MDK的软包下载地址:http://www.keil.com/dd2/Pack/

     

    •   方式三:GitHub。

    通过GitHub获取也比较方便,地址:https://github.com/ARM-software/CMSIS_5 。点击右上角就可以下载CMSIS软件包了。

     

    当然,也可以在ARM官网下载,只是这两年ARM官网升级得非常频繁,通过检索功能找资料非常麻烦。所以不推荐大家到ARM官网下载资料了。

    7.2.2  DSP库的说明

    这里我们以CMSIS V5.6.0为标准进行移植。打开固件库里面的CMSIS文件,可以看到如下几个文件:

     

    其中DSP文件夹是我们需要的:

     

    Examples文件夹中的文件如下,主要是提供了一些例子:

     

    Include文件夹里面是DSP库的头文件:

     

    Lib文件夹里面是MDK(ARM),IAR和CGG版库文件:

    Projects文件夹里面的文件如下,提供了三个版本的工程模板,每个模板里面都是把所有源码文件添加了进来:

     

    Source文件夹中的文件如下,这个是DSP的源码文件:

     

    7.3   DSP库版本的区别

    IAR版本的DSP库如下:

     

    •   arm_cortexM4lf_math.lib

    Cortex-M4内核,l表示小端格式,f表示带FPU单元,M4仅支持Single Precision单精度浮点。

    •   arm_cortexM4l_math.lib

    Cortex-M4内核,l表示小端格式。

    •   arm_cortexM4bf_math.lib

    Cortex-M4内核,b表示大端格式,f表示带FPU单元,M4仅支持Single Precision单精度浮点。

    •   arm_cortexM4b_math.lib

    Cortex-M4内核,b表示大端格式。

    STM32F4是M4内核,单精度浮点,一般使用小端格式,所以我们选择库

    arm_cortexM4lf_math.lib

    7.4   DSP库的几个重要的预定义宏含义

    根据用户的使用要求,这几个预定义宏可以添加到IAR的预定义选项中:

     

    这里将这几个预定义宏做个介绍:

    •  ARM_MATH_BIG_ENDIAN:

    大端格式。

    •  ARM_MATH_MATRIX_CHECK:

    检测矩阵的输入输出大小。

    • ARM_MATH_NEON:
    • ARM_MATH_NEON_EXPERIMENTAL:

    这两个暂时用不到,因为M0,M3,M4和M7内核不支持NEON指令,需要等待升级到ARMv8.1-M架构。

    •   ARM_MATH_ROUNDING:

    主要用在浮点数转Q32,Q15和Q7时,类似四舍五入的处理上,其它函数没用到。

    •   ARM_MATH_LOOPUNROLL:

    用于4个为一组的的小批量处理上,加快执行速度。

    通过下面的求绝对值函数,可以方便的看出区别:

    void arm_abs_f32(
      const float32_t * pSrc,
            float32_t * pDst,
            uint32_t blockSize)
    {
            uint32_t blkCnt;                               /* Loop counter */
    
    #if defined(ARM_MATH_NEON)
        float32x4_t vec1;
        float32x4_t res;
    
        /* Compute 4 outputs at a time */
        blkCnt = blockSize >> 2U;
    
        while (blkCnt > 0U)
        {
            /* C = |A| */
    
                /* Calculate absolute values and then store the results in the destination buffer. */
            vec1 = vld1q_f32(pSrc);
            res = vabsq_f32(vec1);
            vst1q_f32(pDst, res);
    
            /* Increment pointers */
            pSrc += 4;
            pDst += 4;
            
            /* Decrement the loop counter */
            blkCnt--;
        }
    
        /* Tail */
        blkCnt = blockSize & 0x3;
    
    #else
    #if defined (ARM_MATH_LOOPUNROLL)
    
      /* Loop unrolling: Compute 4 outputs at a time */
      blkCnt = blockSize >> 2U;
    
      while (blkCnt > 0U)
      {
        /* C = |A| */
    
        /* Calculate absolute and store result in destination buffer. */
        *pDst++ = fabsf(*pSrc++);
    
        *pDst++ = fabsf(*pSrc++);
    
        *pDst++ = fabsf(*pSrc++);
    
        *pDst++ = fabsf(*pSrc++);
    
        /* Decrement loop counter */
        blkCnt--;
      }
    
      /* Loop unrolling: Compute remaining outputs */
      blkCnt = blockSize % 0x4U;
    
    #else
    
      /* Initialize blkCnt with number of samples */
      blkCnt = blockSize;
    
    #endif /* #if defined (ARM_MATH_LOOPUNROLL) */
    #endif /* #if defined(ARM_MATH_NEON) */
    
      while (blkCnt > 0U)
      {
        /* C = |A| */
    
        /* Calculate absolute and store result in destination buffer. */
        *pDst++ = fabsf(*pSrc++);
    
        /* Decrement loop counter */
        blkCnt--;
      }
    
    }

    7.5   DSP库在IAR上的移植(源码移植方式)

    下面我们讲解下如何在IAR上面移植DSP库源码,DSP库的移植相对比较容易。

    7.5.1  第一步:建立IAR工程并添加DSP库

    为了方便起见,我们这里不再专门建立一个MDK工程了,直接以V6开发板中的例子:V7-001_跑马灯例程为模板(注意,要使用我们HAL版本例子)进行添加即可。打开这个实例并在左侧添加分组CMSIS/DSP:

     

    我们这里不需要添加每个C文件源码,仅需添加包含这些C文件的汇总文件,比如BasicMathFunctions.c文件里面包含的C文件就是:

    #include "arm_abs_f32.c"
    #include "arm_abs_q15.c"
    #include "arm_abs_q31.c"
    #include "arm_abs_q7.c"
    #include "arm_add_f32.c"
    #include "arm_add_q15.c"
    #include "arm_add_q31.c"
    #include "arm_add_q7.c"
    #include "arm_dot_prod_f32.c"
    #include "arm_dot_prod_q15.c"
    #include "arm_dot_prod_q31.c"
    #include "arm_dot_prod_q7.c"
    #include "arm_mult_f32.c"
    #include "arm_mult_q15.c"
    #include "arm_mult_q31.c"
    #include "arm_mult_q7.c"
    #include "arm_negate_f32.c"
    #include "arm_negate_q15.c"
    #include "arm_negate_q31.c"
    #include "arm_negate_q7.c"
    #include "arm_offset_f32.c"
    #include "arm_offset_q15.c"
    #include "arm_offset_q31.c"
    #include "arm_offset_q7.c"
    #include "arm_scale_f32.c"
    #include "arm_scale_q15.c"
    #include "arm_scale_q31.c"
    #include "arm_scale_q7.c"
    #include "arm_shift_q15.c"
    #include "arm_shift_q31.c"
    #include "arm_shift_q7.c"
    #include "arm_sub_f32.c"
    #include "arm_sub_q15.c"
    #include "arm_sub_q31.c"
    #include "arm_sub_q7.c"

    这样一来,IAR编译后会自动关联,查看源码非方便:

     

    7.5.2  第二步:添加头文件路径

    添加DSP所需的头文件路径,这个头文件路径是已经在模板工程中添加好的,这里只是跟大家强调一下:

     

    这里要注意一点,为什么直接添加路径LibrariesCMSISInclude里面的头文件即可,而没有添加LibrariesCMSISDSPInclude,这是因为路径LibrariesCMSISInclude里面已经包含了DSP库的头文件。

    7.5.3  第三步:添加宏定义

    我们这里仅使能一个宏定义ARM_MATH_LOOPUNROLL:

     

    7.5.4  第四步:开启FPU

    需要客户通过MDK开启FPU,由于STM32F4支持单精度浮点,这里要开启Sing  Precision。

     

    7.5.5  第五步:添加头文件arm_math.h

    用到DSP库函数的文件得添加#include "arm_math.h"就可以调用DSP库的API了。至此就完成了DSP库的移植。

    7.6   DSP库在IAR上的移植(库移植方式)

    移植方法与本章7.5小节的相同,仅第1步不同,将源码的添加修改为库添加:

     

    7.7   升级到最新版DSP库方法

    由于CMSIS软件包试试实时更新的,这里提供一种升级的简单办法,按照本章7.1小节的说明下载到最新版CMSIS软件包,然后直接覆盖DSP工程里面的CMSIS文件夹即可。

    7.8   简易DSP库函数验证

    这里我们主要运行arm_abs_f32,arm_abs_q31,arm_abs_q15这三个函数,以此来验证我们移植的DSP库是否正确。

    配套例子:

    本章配套了如下两个例子:

    •   V6-200_DSP程序模板(源码方式)
    •   V6-201_DSP程序模板(库方式)

    实验目的:

    1. 学习官方DSP库的移植

    实验内容:

    1. 按下按键K1, 串口打印函数arm_abs_f32的输出结果

    2. 按下按键K2, 串口打印函数arm_abs_q31的输出结果

    3. 按下按键K3, 串口打印函数arm_abs_q15的输出结果

    实验现象:

           通过串口上位机软件SecureCRT看打印信息现象如下(分别按几次K1,K2,K3)。如果编译的是MDK的AC6工程,特别要注意本章7.7小节所说的问题。

     

    程序设计:

    程序的设计也比较简单,通过按下不同的按键从而打印不同的DSP库函数执行结果,主程序如下:

    #include "bsp.h"            /* 底层硬件驱动 */
    #include "arm_math.h"
    
    
    
    /* 定义例程名和例程发布日期 */
    #define EXAMPLE_NAME    "V7-ARM的DSP移植模板(源码方式)"
    #define EXAMPLE_DATE    "2019-07-31"
    #define DEMO_VER        "1.0"
    
    static void PrintfLogo(void);
    static void PrintfHelp(void);
    
    /*
    *********************************************************************************************************
    *    函 数 名: main
    *    功能说明: c程序入口
    *    形    参: 无
    *    返 回 值: 错误代码(无需处理)
    *********************************************************************************************************
    */
    int main(void)
    {
        uint8_t ucKeyCode;        /* 按键代码 */
        float32_t pSrc;
        float32_t pDst;
        q31_t pSrc1;
        q31_t pDst1;
        q15_t pSrc2;
        q15_t pDst2;
    
        
        bsp_Init();        /* 硬件初始化 */
        
        PrintfLogo();    /* 打印例程名称和版本等信息 */
        PrintfHelp();    /* 打印操作提示 */
    
        bsp_StartAutoTimer(0, 100);    /* 启动1个100ms的自动重装的定时器 */
        
        /* 主程序大循环 */
        while (1)
        {
            /* CPU空闲时执行的函数,在 bsp.c */
            bsp_Idle();        
            
            /* 判断定时器超时时间 */
            if (bsp_CheckTimer(0))    
            {
                /* 每隔100ms 进来一次 */
                /* 翻转LED2的状态 */
                bsp_LedToggle(2);    
            }
    
            /* 处理按键事件 */
            ucKeyCode = bsp_GetKey();
            if (ucKeyCode > 0)
            {
                /* 有键按下 */
                switch (ucKeyCode)
                {
                    case KEY_DOWN_K1:               /* K1键按下 */
                        pSrc -= 1.23f;
                        arm_abs_f32(&pSrc, &pDst, 1);
                        printf("pDst = %f
    ", pDst);
                        break;
                        
                    case KEY_DOWN_K2:              /* K2键按下 */
                        pSrc1 -= 1;
                        arm_abs_q31(&pSrc1, &pDst1, 1);
                        printf("pDst1 = %d
    ", pDst1);
                        break;
    
                    case KEY_DOWN_K3:              /* K3键按下 */
                        pSrc2 -= 1;
                        arm_abs_q15(&pSrc2, &pDst2, 1);
                        printf("pDst2 = %d
    ", pDst2);
                        break;
                    
                    default:
                        break;
                }
            }
        }
    }

    7.9   总结

    本期教程主要跟大家介绍了官方DSP库的移植,相对来说移植也比较简单,建议初学的同学按照这个步骤移植一遍。

  • 相关阅读:
    BZOJ 1726 洛谷 2865 [USACO06NOV]路障Roadblocks【次短路】
    BZOJ 1699 [Usaco2007 Jan]Balanced Lineup排队
    洛谷 2777 [AHOI2016初中组]自行车比赛
    BZOJ 1832、1787 洛谷 4281 [AHOI2008]紧急集合
    BZOJ 4385 洛谷3594 POI2015 WIL-Wilcze doły
    【HDU 3037】Saving Beans(卢卡斯模板)
    【POJ 1061】青蛙的约会(EXGCD)
    【HIHOCODER 1469 】福字(DP)
    【BZOJ 1076】[SCOI2008]奖励关(期望)
    【HIHOCODER 1509 】 异或排序
  • 原文地址:https://www.cnblogs.com/armfly/p/12653672.html
Copyright © 2020-2023  润新知