STM32H743-ARM例程21-DSP
摘要:本文介绍了基于STM32H743XIH6开发板的DSP功能实验。实验使用STM32CubeMX生成工程,配置硬件FPU单元和DSP指令集(包括单周期MAC指令和SIMD指令)。详细说明了DSP库的获取方法、环境搭建步骤,并通过对比测试展示了DSP数学库的运算效率优势。实验代码实现了正弦/余弦函数计算,分别测试了常规方法和DSP优化方法的执行时间,验证了Cortex-M7内核在数字信号处理方面
实验平台
硬件:银杏科技GT7000双核心开发板-ARM-STM32H743XIH6,银杏科技iToolXE仿真器
软件:最新版本STM32CubeH7固件库,STM32CubeMX v6.10.0,开发板环境MDK v5.35,串口工具putty
网盘资料包:链接: https://pan.baidu.com/s/1Y3nwaY4SMxfoUsdqPm2R3w?pwd=inba 提取码: inba
DSP
STMH32H7采用Cortex-M7内核,相比Cortex-M3系列除了内置硬件FPU单元,在数字信号处理方面还增加了DSP指令集,支持诸如单周期乘加指令(MAC),优化的单指令多数据指令(SIMD),饱和算数等多种数字信号处理指令集。相比Cortex-M3,Cortex-M4在数字信号处理能力方面得到了大大的提升。Cortex-M7执行所有的DSP指令集都可以在单周期内完成,而Cortex-M3需要多个指令和多个周期才能完成同样的功能。
DSP库使用
获取DSP库
在前面CubeMX新建HAL库MDK工程章节我们生成了STM32H7工程文件,在其目录/Template/Dirvers/CMSIS/DSP/Lib/ARM下包含ST提供的标准库—DSP库
DSP库介绍
ST提供了.lib格式的文件,方便使用这些库。这些.lib文件就是由Source文件夹下的源码编译生成的,如果想看某个函数的源码,可以在Source文件夹下面查找。
DSP库编程环境搭建
- 首先添加库文件。在工程目录下新建DSP_LIB文件夹用于存放库文件。然后把arm_cortexM7lfdp_math.lib和相关头文件(Template\Drivers\CMSIS\DSP\Include)拷贝到DSP_LIB文件夹中。

- 然后打开工程,新建DSP_LIB分组,并将arm_cortexM7lfdp_math.lib添加到工程里面。
- 添加好文件之后,需要添加头文件包含路径,将第一步拷贝的Include文件夹和DSP_LIB文件夹,加入头文件包含路径。打开工程属性设置面板,然后点击”C/C++“选项卡,点击对号处,弹出include path设置面板。添加”…\DSP_LIB“和“…\DSP_LIB\Include“两个路径。


DSP指令
接下来我们来看看Cortex-M7的两个DSP指令:MAC指令(32位乘法累加)和SIMD指令。
32位乘法累加(MAC)单元包括新的指令集,能够在单周期内完成一个32×32+64→64的操作或两个16×16的操作,其计算能力,如下表所示:
Cortex-M7支持SIMD指令集,这在Cortex-M3/M0系列是不可用的。上述表中的指令,有的属于SIMD指令。与硬件乘法器一起工作(MAC),使所有这些指令都能在单个周期内执行。受益于SIMD指令的支持,Cortex-M4处理器能在单周期内完成高达32×32+64→64的运算,为其他任务释放处理器的带宽,而不是被乘法和加法消耗运算资源。
比如一个比较复杂的运算:两个16×16乘法加上一个32位加法,如图所示:

STM32CubeMX生成工程
我们参考前面章节STM32H743-结合CubeMX新建HAL库MDK工程,打开CubeMX软件,重复步骤不再展示。
实验代码
1. 主函数
int main(void)
{
int i,j;
int res;
int time[2];
static int error_flag = 0;
MPU_Config();
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART6_UART_Init();
uart6.initialize(115200);
uart6.printf("\x0c"); //清屏
uart6.printf("\033[1;32;40m"); //设置终端字体为绿色
uart6.printf("Hello, I am GT7000!\r\n\r\n");
uart6.printf("DSP BasicMath TEST......\r\n\r\n");
//通过两个嵌套的for循环对testInput_f32数组中的元素进行遍历
uwTick = 0;
for(j = 0;j < 10000;j++)
{
for(i = 0;i < MAX_BLOCKSIZE;i ++)
{
res = SinCos_Test(testInput_f32[i],0);
//调用SinCos_Test函数对当前元素进行处理
if(res != 0)error_flag ++;
}
}
time[0] = HAL_GetTick();//调用HAL_GetTick函数获取当前的系统时间(未使用DSP)
//循环思路与上同理
uwTick = 0;
for(j = 0;j < 10000;j++)
{
for(i = 0;i < MAX_BLOCKSIZE;i ++)
{
res = SinCos_Test(testInput_f32[i],1);//调用SinCos_Test函数时,传入的第二个参数为1,表示使用DSP数学库进行处理
if(res != 0)error_flag ++;
}
}
time[1] = HAL_GetTick();//调用HAL_GetTick函数获取当前的系统时间(使用DSP)
//如果error_flag为0,表示没有错误发生,将使用UART输出两个运行时间
//如果error_flag不为0,表示出现了错误,使用UART输出错误信息
if(error_flag == 0)
{
uart6.printf("The test is successful, and the following is the operation time comparison!\r\n\r\n");
uart6.printf("*NO DSP MATHLIB runtime:%dms *USE DSP MATHLIB runtime:%dms\r",time[0], time[1]);
}
else
{
uart6.printf("Error\r");
}
while (1)
{
}
2. SinCos_Test函数
//比较不使用DSP数学库和使用DSP数学库计算正弦和余弦函数的结果,并判断它们与理论值的差异是否在可接受的范围内。
int SinCos_Test(float testInput,unsigned char mode)
{
float Sinx,Cosx;
float Result;
switch (mode){
case 0://不使用DSP MATH库
Sinx = sinf(testInput);
Cosx = cosf(testInput);
Result = Sinx*Sinx + Cosx*Cosx;
Result = fabsf(Result-1.0f);//计算差值
if(Result > DELTA)return -1;
break;
case 1://使用DSP MATH库
Sinx = arm_sin_f32(testInput);
Cosx = arm_cos_f32(testInput);
Result = Sinx*Sinx + Cosx*Cosx;
Result = fabsf(Result-1.0f);//计算差值
if(Result > DELTA)return -1;
break;
default://如果mode不等于0或1,则函数直接结束
break;
}
return 0;
}
实验现象
本实验进行进行DSP浮点运算测试,分别测试出不使用DSP MATH和使用DSP MATH的运算时间,进行对比。测试在终端上显示不使用DSP MATH和使用DSP MATH的运算时间;测试失败在终端上显示“Error”。
更多推荐



所有评论(0)