完整版教程下载地址:

第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官方库的移植。 相对而言,移植比较简单。 建议初学者按照这个步骤重新移植一下。

作者 admin