
今天测试的主要对象是NUCLEO-G431RB 的浮点计算能力,通过进行FFT侧面验证Nucleo-G431RB的计算能力。 一、背景知识 9 A7 K' l( V1 ]* R$ f* |6 t ![]() / Z: S/ o* G; N0 P. P 二、工程建立与代码移植 / L1 ?: _+ A" ], }8 g2 w- Q/ o ST为此提供了一套静态库,分别为Keil、IAR、GCC这三个开发环境提供相关的数学运算库。; l7 Q4 t2 h1 J$ O8 K![]() % u# P: k0 _! W1 W5 \ 引用头文件位置在:G4固件库STM32Cube_FW_G4_Vx.x.x)\Drviers\CMSIS\DSP\Include 目录中;! _' [6 S, [2 Y- _: t& E0 x1 x2 W静态库位置在:G4固件库(STM32Cube_FW_G4_Vx.x.x)\Drviers\CMSIS\DSP\Lib)目录中,根据开发环境选择不同的库文件,包括大小端系统环境选择,是否浮点的库。 ![]() ![]() ! k1 }; z/ `/ n* W 其中libarm_cortexM4l_math.a 代表设备为小端模式;其中libarm_cortexM4lf_math.a 代表设备为浮点小端模式;![]() % F4 y/ h& ^. c) x. }$ o3 s) f* P 其中iar_cortexM4b_math.a代表设备为大端模式;其中iar_cortexM4bf_math.a代表设备为浮点大端模式;其中iar_cortexM4l_math.a代表设备为小端模式;其中iar_cortexM4lf_math.a代表设备为浮点小端模式; 此次体验期间适合STM32G431RB的免费的开发环境为STM32CubeIDE,该工具是在Eclipse 环境下使用的编译器为GCC。因此,适合搭建FFT测试内容是带浮点的库文件为:libarm_cortexM4lf_math.a![]() ![]() 添加编译静态库文件位置 ![]() 添加文件路径 * b5 V5 E7 B% c/ x! ~6 j ![]() 添加编译宏定义 在Main.c文件头部添加以下定义代码: /* USER CODE BEGIN Includes */ #include <stdio.h> #include <stdlib.h> #include <inttypes.h> #include "arm_math.h" #include "arm_const_structs.h" /* USER CODE END Includes */ …… /* USER CODE BEGIN PTD */ typedef unsigned int ee_u32; typedef clock_t CORE_TICKS; typedef ee_u32 secs_ret; /* USER CODE END PTD */ …… 4 h/ u: A# U1 K; s* g0 V! ~5 i( { /* USER CODE BEGIN PD */ #define EE_TICKS_PER_SEC 1000 //#define NPT 2048//4096 #define SysTick_Counter_Disable ((uint32_t)0xFFFFFFFE) #define SysTick_Counter_Enable ((uint32_t)0x00000001) #define SysTick_Counter_Clear ((uint32_t)0x00000000) #define FFT_LENGTH 1024 //FFT长度,默认是1024点FFT . x& h( j9 U' X3 G: f8 w" f" M! uvolatile __IO uint32_t Tick; uint32_t ifftFlag = 0; uint32_t doBitReverse = 1; 6 [4 x- ?% h% C0 u7 q# I3 {float32_t fft_x[FFT_LENGTH * 2]; float32_t fft_input[FFT_LENGTH * 2]; float32_t fft_output[FFT_LENGTH]; //NPT/2 1 Y+ f4 X4 t' U: S, P: Q5 \CORE_TICKS total_time; /* USER CODE END PD */ …… ' x! \9 c; [" ~( ?/* USER CODE BEGIN PFP */ void fft_test(); void start_time(void); void stop_time(void); CORE_TICKS get_time(void); secs_ret time_in_secs(CORE_TICKS ticks); secs_ret time_in_subsecs(CORE_TICKS ticks); /* USER CODE END PFP */ …… 在main()函数中增加以下代码 …… /* USER CODE BEGIN 2 */ printf("NucleoG431RB Test FFT Speed!\n"); printf("FFT Point Number:%d\n",FFT_LENGTH); printf("CLKFreq:%d\n", HAL_RCC_GetHCLKFreq()); fft_test(); /* USER CODE END 2 */ …… 添加相关函数定义 4 m9 m, h$ a; k9 }1 D$ x$ U …… /* USER CODE BEGIN 4 */ void start_time(void) { //GETMYTIME(&start_time_val ); Tick = 0; SysTick_Config(HAL_RCC_GetHCLKFreq() / 1000); } void stop_time(void) { //GETMYTIME(&stop_time_val ); /* Stop the Timer and get the encoding time */ SysTick->CTRL &= SysTick_Counter_Disable; /* Clear the SysTick Counter */ SysTick->VAL = SysTick_Counter_Clear; } CORE_TICKS get_time(void) { //CORE_TICKS elapsed = (CORE_TICKS)(MYTIMEDIFF(stop_time_val, start_time_val)); CORE_TICKS elapsed = (CORE_TICKS) Tick; return elapsed; } secs_ret time_in_secs(CORE_TICKS ticks) { secs_ret retval = ((secs_ret) ticks) / (secs_ret) EE_TICKS_PER_SEC; return retval; } secs_ret time_in_subsecs(CORE_TICKS ticks) { secs_ret retval = ((secs_ret) ticks); return retval; } …… FFT主函数 …… void fft_test() { int i, j = 0; 5 c$ m: {2 }$ _9 l! m6 V2 ^# Y int Adc = 3; //直流分量幅度 float32_t A1 = 7.0; //频率F1 信号的幅度 float32_t A2 = 1.5; //频率F2信号的幅度 float32_t A3 = 5.1; //频率F3信号的幅度 float32_t F1 = 180.0; //信号1频率(Hz) float32_t F2 = 390.0; //信号2频率(Hz) float32_t F3 = 600.0; //信号3频率(Hz) float32_t P1 = 0.0; //信号1相位(度) float32_t P2 = 0.0; //信号2相位(度) float32_t P3 = 0.0; //信号3相位(度) //float32_t Fs = (float32_t)FFT_LENGTH; //采样频率(Hz) //float32_t N = (float32_t)FFT_LENGTH*2; //采样点数 //生成信号序列 for (i = 0; i < FFT_LENGTH; i++) { //采样时刻 i/Fs fft_x[2 * i] = 10 + A1 * arm_sin_f32(2 * PI * i * F1 / FFT_LENGTH + PI * P1 / 180) + A2 * arm_sin_f32(2 * PI * i * F2 / FFT_LENGTH + PI * P2 / 180) + A3 * arm_sin_f32(2 * PI * i * F3 / FFT_LENGTH + PI * P3 / 180); //虚部全部为0 fft_x[2 * i + 1] = 0; } start_time(); for (j = 0; j < 1000; j++) { //arm_cfft_sR_f32_len1024,该变量即为"arm_const_structs.h"提供的配置变量,包含头文件后,直接调用即可。 //memset(fft_output, 0x00, sizeof(float32_t)*FFT_LENGTH); memcpy(fft_input, fft_x, sizeof(float32_t)*FFT_LENGTH * 2); arm_cfft_f32(&arm_cfft_sR_f32_len1024, fft_input, ifftFlag, doBitReverse); //把运算结果复数求模得幅值 arm_cmplx_mag_f32(fft_input, fft_output, FFT_LENGTH); } stop_time(); total_time = get_time(); printf("Total time (sub_secs): %d\n", time_in_subsecs(total_time)); for (i = 0; i < FFT_LENGTH; i++) { printf("%f\r\n", i, fft_output); } }…… 4 q2 U7 [9 m$ H( Y# m* H! P" _ 系统printf输出串口定义 : K$ m# @' i" d4 a1 P #ifdef __GNUC__ /* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf * set to 'Yes') calls __io_putchar() */ #define PUTCHAR_PROTOTYPE int __io_putchar(int ch) #else #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f) #endif /* __GNUC__ */ /** * @brief Retargets the C library printf function to the USART. * @param None * @retval None */ PUTCHAR_PROTOTYPE { /* Place your implementation of fputc here */ /* e.g. write a character to the EVAL_COM1 and Loop until the end of transmission */ HAL_UART_Transmit(&hlpuart1, (uint8_t*) &ch, 1, 0xFFFF); return ch; } /* USER CODE END 4 */ ▲ 左右移动,查看完整代码 7 D4 y. n9 w! D: Y: g 编译后下载即可实现FFT相关计算。 , L2 \' G# y. m0 T4 Z0 Q6 g' { 三、FFT计算能力对比及数值校验 同样的代码移植到Nucleo-F446ZE的项目中,这里有一个小插曲,本想用Nucleo-F301R8的板子对比速度,但因F301R8的Flash、RAM比较小,无法支持带DSP静态库的应用代码,改用速度相近的F4板子Nucleo-F446进行功能验证和对比,以下是对比结果:: I2 U. l+ k7 A9 H2 {" Z ![]() 数值图形展示及验证: ![]() 相关频点和幅值计算的结果如下图: ![]() ![]() 180频率,约7。 ![]() 390频率,约1.5。 ![]() 600频率,约5.1。 FFT计算及验证正确,单次FFT计算速度接近1毫秒,可用于DSP某些领域的数据处理。另外,相关数值计算还可通过上位机的Matelab、Python等工具进行计算并展示相关图形信息,用于验证FFT的处理结果对比。 |
已修改
好的,谢谢,已经调整
谢谢!