
今天测试的主要对象是NUCLEO-G431RB 的浮点计算能力,通过进行FFT侧面验证Nucleo-G431RB的计算能力。 一、背景知识 ![]() 二、工程建立与代码移植 ![]() 静态库位置在:G4固件库(STM32Cube_FW_G4_Vx.x.x)\Drviers\CMSIS\DSP\Lib)目录中,根据开发环境选择不同的库文件,包括大小端系统环境选择,是否浮点的库。 ![]() ![]() ![]() ![]() ![]() 添加编译静态库文件位置 ![]() 添加文件路径 ![]() 添加编译宏定义 在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 */ …… /* 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 volatile __IO uint32_t Tick; uint32_t ifftFlag = 0; uint32_t doBitReverse = 1; float32_t fft_x[FFT_LENGTH * 2]; float32_t fft_input[FFT_LENGTH * 2]; float32_t fft_output[FFT_LENGTH]; //NPT/2 CORE_TICKS total_time; /* USER CODE END PD */ …… /* 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 */ …… 添加相关函数定义 …… /* 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; 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); } }…… 系统printf输出串口定义 #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 */ ▲ 左右移动,查看完整代码 三、FFT计算能力对比及数值校验 同样的代码移植到Nucleo-F446ZE的项目中,这里有一个小插曲,本想用Nucleo-F301R8的板子对比速度,但因F301R8的Flash、RAM比较小,无法支持带DSP静态库的应用代码,改用速度相近的F4板子Nucleo-F446进行功能验证和对比,以下是对比结果: ![]() 数值图形展示及验证: ![]() 相关频点和幅值计算的结果如下图: ![]() ![]() 180频率,约7。 ![]() 390频率,约1.5。 ![]() 600频率,约5.1。 FFT计算及验证正确,单次FFT计算速度接近1毫秒,可用于DSP某些领域的数据处理。另外,相关数值计算还可通过上位机的Matelab、Python等工具进行计算并展示相关图形信息,用于验证FFT的处理结果对比。 |
已修改
好的,谢谢,已经调整
谢谢!