STM32F407 DSP教程第七章 ARM DSP源代码及库移植方法IAR

完整版教程下载地址:

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

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

目录

7.1 初学者重要提示,IAR请使用8.30及以上版本,CMSIS请使用5.6.0及以上版本。 IAR工程的创建、下载和调试方法详见V6用户手册: 。 7.2 DSP库下载及说明

下面将详细讲解官方DSP库的移植。

7.2.1 DSP库下载

DSP库包含在CMSIS软件包(Cortex Microcontroller Software Interface Standard)中,因此下载DSP库也就是下载CMSIS软件包。 这里有三个地方可以下载:

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

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

安装新版本MDK后,CMSIS软件包将存在于路径:ARM\PACK\ARM\CMSIS\5.6.0\CMSIS。

如果有新版本,建议您使用最新版本。 MDK软件包下载地址:.

嵌入式软件工程师_嵌入式软件开发需要学什么_dsp嵌入式软件

通过GitHub获取也比较方便,地址:。 点击右上角下载CMSIS软件包。

嵌入式软件工程师_dsp嵌入式软件_嵌入式软件开发需要学什么

当然,你也可以从ARM官网下载。 然而ARM官网这两年升级非常频繁,通过搜索功能查找信息非常麻烦。 因此,不建议您从ARM官网下载信息。

7.2.2 DSP 库说明

这里我们使用CMSIS V5.6.0作为移植的标准。 打开固件库中的CMSIS文件,可以看到以下文件:

嵌入式软件工程师_dsp嵌入式软件_嵌入式软件开发需要学什么

DSP文件夹就是我们需要的:

dsp嵌入式软件_嵌入式软件工程师_嵌入式软件开发需要学什么

Examples文件夹下的文件如下,主要提供一些示例:

dsp嵌入式软件_嵌入式软件开发需要学什么_嵌入式软件工程师

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

嵌入式软件工程师_嵌入式软件开发需要学什么_dsp嵌入式软件

Lib文件夹内有MDK(ARM)、IAR和CGG库文件:

嵌入式软件工程师_嵌入式软件开发需要学什么_dsp嵌入式软件

Projects文件夹中的文件如下。 提供了三个版本的项目模板。 所有源代码文件都添加到每个模板中:

嵌入式软件开发需要学什么_dsp嵌入式软件_嵌入式软件工程师

Source文件夹中的文件如下。 这是DSP的源代码文件:

dsp嵌入式软件_嵌入式软件开发需要学什么_嵌入式软件工程师

7.3 DSP库版本差异

IAR版本的DSP库如下:

dsp嵌入式软件_嵌入式软件工程师_嵌入式软件开发需要学什么

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

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

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

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

STM32F4是M4核,单精度浮点,一般采用little-endian格式,所以我们选择库

arm_cortexM4lf_math.lib

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

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

dsp嵌入式软件_嵌入式软件工程师_嵌入式软件开发需要学什么

下面对这些预定义宏进行介绍:

大端格式。

检查矩阵的输入和输出大小。

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

主要用于浮点数转换为Q32、Q15、Q7时类似舍入的处理。 其他功能不使用。

用于 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 IAR上的DSP库移植(源码移植方式)

接下来我们讲解如何在IAR上移植DSP库源码。 DSP库的移植相对容易。

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

为了方便起见,我们这里不再专门创建MDK项目。 我们可以直接使用V6开发板中的示例:V7-001_marquee例程作为模板(注意必须使用我们的HAL版本示例)来添加。 打开此实例并在左侧添加组 CMSIS/DSP:

嵌入式软件开发需要学什么_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,不方便查看源码:

嵌入式软件工程师_嵌入式软件开发需要学什么_dsp嵌入式软件

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

添加DSP所需的头文件路径。 该头文件路径已添加到模板工程中。 我只是想在这里强调一下:

嵌入式软件工程师_嵌入式软件开发需要学什么_dsp嵌入式软件

这里需要注意的一点是,为什么可以直接在Libraries\CMSIS\Include路径下添加头文件,而不是添加Libraries\CMSIS\DSP\Include。 这是因为路径Libraries\CMSIS\Include已经包含了DSP库的头文件。 。

7.5.3 第三步:添加宏定义

这里我们只启用一个宏定义ARM_MATH_LOOPUNROLL:

嵌入式软件开发需要学什么_dsp嵌入式软件_嵌入式软件工程师

7.5.4 步骤4:打开FPU

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

嵌入式软件开发需要学什么_嵌入式软件工程师_dsp嵌入式软件

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

使用DSP库函数的文件必须添加#include “arm_math.h”来调用DSP库的API。 至此,DSP库的移植就完成了。

7.6 IAR上的DSP库移植(库移植方法)

移植方法与本章7.5节相同,只是第一步将源代码添加改为库添加:

dsp嵌入式软件_嵌入式软件开发需要学什么_嵌入式软件工程师

7.7 升级到最新版本DSP库方法

由于CMSIS软件包是实时更新的,这里介绍一个简单的升级方法。 按照本章7.1节的说明下载最新版本的CMSIS软件包,然后直接覆盖DSP工程中的CMSIS文件夹。

7.8 简单DSP库函数验证

这里我们主要运行arm_abs_f32、arm_abs_q31、arm_abs_q15这三个函数来验证我们移植的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嵌入式软件

编程:

程序的设计也比较简单。 不同的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\r\n", pDst);                    break;                                    case KEY_DOWN_K2:              /* K2键按下 */                    pSrc1 -= 1;                    arm_abs_q31(&pSrc1, &pDst1, 1);                    printf("pDst1 = %d\r\n", pDst1);                    break;                case KEY_DOWN_K3:              /* K3键按下 */                    pSrc2 -= 1;                    arm_abs_q15(&pSrc2, &pDst2, 1);                    printf("pDst2 = %d\r\n", pDst2);                    break;                                default:                    break;            }        }    }}

7.9 总结

本教程主要向您介绍DSP官方库的移植。 相对而言,移植比较简单。 建议初学者按照这个步骤重新移植一下。