STM32H743-ARM例程21-DSP
目录
- 实验平台
- DSP
- DSP库使用
- DSP指令
- STM32CubeMX生成工程
- 实验代码
- 实验现象
实验平台
硬件:银杏科技GT7000双核心开发板-ARM-STM32H743XIH6,银杏科技iToolXE仿真器
软件:最新版本STM32CubeH7固件库,STM32CubeMX v6.10.0,开发板环境MDK v5.35,串口工具putty
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”。