资源篇
外观还是一如既往的靓,简洁美观。板子搭载的是M4内核,速度快,高达170M主频,和数学运算加速器CORDIC大大提高运算能力, 输入电压范围1.71~3.6V,512Flash,128的SRAM,1个用户LED,一个用户按键,32.768khz的外部低速晶振,外接24M的高速晶振,Micro-AB连接器,Arduino™ Uno V3连接器可扩与Arduino™ Uno V3连接,板载STLINK_V3仿真调试器,调试器的主控是STM32F723,下载速度得到的很大的提高。
STM32G474资源介绍:
STM32G474开发板实物图:
▲ 开发板实物图 开发板分为上下两部分,上半部分为ST-LINK-V3仿真器,可以给开发板进行调试和程序下载。下半部分是G474的最小系统板:全IO引出,兼容流行的Arduino扩展口如下图所示。值得一提的是:上半部分的ST-LINK是可以通过断开跳帽之后可以单独作为调试器使用。
实战篇
测试内容:
1. LED和GPIO测试1
(1) 原理:短按一下按键,LED点亮,再短按一下按键LED熄灭。(2) 步骤:使用CubeCubeMx生成工程。 ▲ 引脚配置 时钟配置:外接24M晶振,高达170M主频
生成工程,固件包版本V1.1.0。
代码:
结果:短按一下按键,LED点亮,再短按一下按键LED熄灭。
结论:使用MX配置简单快速。
2. VCP虚拟串口测试1
(1) 原理: MCU与stlik连接
虚拟串口连接MCU的LPUART1
(2) 配置工程:
相关代码:
(3)结果:如下所示,按一次按键就打印一个“OK”,LED一亮灭交替。
结论:这个功能在我们调试的时候十分方便,节省了很多的资源和时间。
3.FPU性能测试1
原理: FPU浮点运算单元,如果CPU上没有FPU进行浮点运算的话必须按照IEEE标准进行运算十分的耗时,相较之下具有FPU的处理器在计算浮点运算是非常快的,G474Nucleo板载FPU运算加速器,运算性能非常出色,我们可以通过简单的测试来测一下板子的FPU的性能,可以通过计算使用FPU时单精度的乘除法使用的时间和没有使用FPU时消耗的时间进行比较来得出结论,其中时间的计数我们使用的是systick定时器。
步骤: 首先我们要学会打开硬件FPU,我们要设置 CPACR寄存器,其中在SystemInit函数中已经写好怎么配置,如下图:
我们只需要添加宏定义__FPU_PRESENT =1 ,_FPU_USED=1就可以了,而默认已经定义了__FPU_PRESENT =1,我们还需要添加_FPU_USED=1,在target 的Code Generation 选single Precision 就行了,如下图。
相关代码如下:双精度和单精度计算函数
- /**
- * @name DoubleD
- * @brief 双精度乘除法.
- * @param angle:起始值,times:计算次数,
- *mod:1除法0乘法
- */
- void DoubleD(double angle,uint32_t times,uint8_t mode)
- {
- uint32_t i;
- double result;
- if(mode)//除法
- {
- for(i=0;i<times;i++)
- {
- result = angle/PI;
- angle += 0.00001f;
- }
- }
- else//乘法
- {
- for(i=0;i<times;i++)
- {
- result = angle*PI;
- angle += 0.00001f;
- }
- }
- }
复制代码
- /**
- * @name FloatXFloat
- * @brief 单精度乘除法.
- * @param angle:起始值,times:计算次数,*mod:1除法0乘法
- */
- void FloatXFloat(float angle,uint32_t times,uint8_t mode)
- {
- uint32_t i;
- float result;
- if(mode)//除法
- {
- for(i=0;i<times;i++)
- {
- result = angle/PI;
- angle += 0.00001f;
- }
- }
- else//乘法
- {
- for(i=0;i<times;i++)
- {
- result = angle*PI;
- angle += 0.00001f;
- }
- }
- }
复制代码
主函数
- int main(void)
- {
- /* USER CODE BEGIN 1 */
- /* USER CODE END 1 */
- /* MCU Configuration--------------------------------------------------------*
- /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
- HAL_Init();
- /* USER CODE BEGIN Init */
- /* USER CODE END Init */
- /* Configure the system clock */
- SystemClock_Config();
- /* USER CODE BEGIN SysInit */
- /* USER CODE END SysInit */
- /* Initialize all configured peripherals */
- MX_GPIO_Init();
- MX_USART1_UART_Init();
- MX_LPUART1_UART_Init();
- /* USER CODE BEGIN 2 */
- HAL_Init();
- /* USER CODE END 2 */
- /* Infinite loop */
- /* USER CODE BEGIN WHILE */
- while (1)
- {
- /* USER CODE END WHILE */
- /* USER CODE BEGIN 3 */
- printf("---------------NOT USER FPU----------------------\n");
- //-------------------测试单精度乘法----------------------------------------
- start_tim = HAL_GetTick();
- //乘法
- FloatXFloat(PI/6,TIMES,0);
- end_tim = HAL_GetTick();
- if(end_tim > start_tim)
- {
- tim_cnt = end_tim - start_tim;
- }
- else
- {
- tim_cnt = 0xffffffff - start_tim + end_tim;
- }
- printf("单精度乘法-- %d ms\r\n",tim_cnt); //显示运行时间
- //-----------------测试单精度除法-------------------------------------------
- start_tim = HAL_GetTick();
- //除法
- FloatXFloat(PI/6,TIMES,1);
- end_tim = HAL_GetTick();
- if(end_tim > start_tim)
- {
- tim_cnt = end_tim - start_tim;
- }
- else
- {
- tim_cnt = 0xffffffff - start_tim + end_tim;
- }
- printf("单精度除法-- %d ms\r\n",tim_cnt); //显示运行时间
- //-----------------测试双精度乘法-------------------------------------------
- start_tim = HAL_GetTick();
- //乘法
- DoubleD(PI/6,TIMES,1);
- end_tim = HAL_GetTick();
- if(end_tim > start_tim)
- {
- tim_cnt = end_tim - start_tim;
- }
- else
- {
- tim_cnt = 0xffffffff - start_tim + end_tim;
- }
- printf("双精度乘法-- %d ms\r\n",tim_cnt); //显示运行时间
- //-----------------测试双精度除法-------------------------------------------
- start_tim = HAL_GetTick();
- //除法
- DoubleD(PI/6,TIMES,1);
- end_tim = HAL_GetTick();
- if(end_tim > start_tim)
- {
- tim_cnt = end_tim - start_tim;
- }
- else
- {
- tim_cnt = 0xffffffff - start_tim + end_tim;
- }
- printf("双精度除法-- %d ms\r\n",tim_cnt); //显示运行时间
- HAL_GPIO_TogglePin(USER_LED_GPIO_Port,USER_LED_Pin);
- HAL_Delay(500);
- }
- /* USER CODE END 3 */
- }
复制代码
测试结果:
条件:输入参数angle:起始值 = π/6,times:计算次数 = 20000(两万),mod:乘除法时。
(1)没有打开FPU
(2)打开FPU
数据比较
| 打开FPU(ms) | 关闭FPU(ms) | 比例 | 单精度乘法 | 1 | 9 | 9 | 单精度除法 | 3 | 13 | 4.3 | 双精度乘法 | 17 | 16 | 0.9 | 双精度乘法 | 21 | 21 | 1 |
得出结论: 打开FPU和没有打开FPU在浮点计算性能上有明显的提高,测试中可以看出在单精度乘法上性能上比较明显,速度大概是没有打开FPU的9倍左右,单精度除法则提升没有那么高4.3倍左右,在双精度上的运算则没有起到作用,耗时基本相同,所以FPU在单精度上计算速度上比较快对于双精度计算则不起作用。
4. DSP测试1
原理: M4内核除了集成硬件FPU外,还带有DSP指令,还有相应的加速单元增加了数据的处理能力和运算速度,ST还提供了DSP算法相关的库 ,大大的提高了我们开发速度和效率 ,为了展示DSP的性能,我使用ST提供的标准库数学运算的运算速度和使用DSP库的提供的数学函数的运算速度比较,参考原子的比较方式,现在我们用过sin(x)² +cos(x)² = 1 这个运算,首先我们以x为变量,x从π/6开始,每次累加0.001,累加200000次,每次的结果的误差不能大于0.00005的运算时间进行比较,可以得到使用DSP和不使用DSP运算速度上的差别。 步骤: 在原来的工程上加入DSP库的头文件和源文件,并包含头文件路径,还要打开硬件FPU,添加宏定义,添加头文件和lib。
打开FPU,在target 的Code Generation 选singlePrecision。
减价宏定义ARM_MATH_CM4。
测试主要代码: 运算函数:
- //sin cos测试
- //angle:起始角度
- //times:运算次数
- //mode:0,不使用DSP库;1,使用DSP库
- //返回值:0,成功;0XFF,出错
- uint8_t sin_cos_test(float angle,uint32_t times,uint8_t mode)
- {
- float sinx,cosx;
- float result;
- uint32_t i=0;
- if(mode==0)
- {
- for(i=0;i<times;i++)
- {
- cosx=cosf(angle); //不使用DSP优化的sin,cos函数
- sinx=sinf(angle);
- result=sinx*sinx+cosx*cosx;//计算结果应该等于1
- result=fabsf(result-1.0f);//对比与1的差值
- if(result>DELTA)
- {
- return 0XFF; //判断失败
- }
- angle+=0.001f; //角度自增
- }
- }
- else
- {
- for(i=0;i<times;i++)
- {
- cosx=arm_cos_f32(angle);//使用DSP优化的sin,cos函数
- sinx=arm_sin_f32(angle);
- result=sinx*sinx+cosx*cosx; //计算结果应该等于1
- result=fabsf(result-1.0f); //对比与1的差值
- if(result>DELTA)
- {
- return 0XFF;//判断失败
- }
- angle+=0.001f; //角度自增
- }
- }
- return 0;//任务完成
- }
复制代码
函数中当输入参数mode为1时使用DSP库提供的arm_cos_f32和arm_sin_f32计算sin(x)² +cos(x)² = 1,输入参数angle为其实角度,计算一次增加0.001,输入的参数timers是要计算的次数,计算的次数越多越消耗时间,对硬件的资源要求就越高,mode为1时则使用st标准库提供的sin,cos函数,所以通过两者的比较得出那种方式比较节省时间。
主函数
- /**
- * @brief The application entry point.
- * @retval int
- */
- int main(void)
- {
- /* USER CODE BEGIN 1 */
- /* USER CODE END 1 */
- /* MCU Configuration--------------------------------------------------------*/
- /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
- HAL_Init();
- /* USER CODE BEGIN Init */
- /* USER CODE END Init */
- /* Configure the system clock */
- SystemClock_Config();
- /* USER CODE BEGIN SysInit */
- /* USER CODE END SysInit */
- /* Initialize all configured peripherals */
- MX_GPIO_Init();
- MX_USART1_UART_Init();
- MX_LPUART1_UART_Init();
- /* USER CODE BEGIN 2 */
- HAL_Init();
- /* USER CODE END 2 */
- /* Infinite loop */
- /* USER CODE BEGIN WHILE */
- while (1)
- {
- /* USER CODE END WHILE */
- /* USER CODE BEGIN 3 */
- //使用DSP优化
- start_tim = HAL_GetTick();
- status = sin_cos_test(PI/6,200000,1);
- end_tim = HAL_GetTick();
- if(end_tim > start_tim)
- {
- tim_cnt = end_tim - start_tim;
- }
- else
- {
- tim_cnt = 0xffffffff - start_tim + end_tim;
- }
- if(status==0)
- {
- printf("USER DSP-- %d ms\r\n",tim_cnt); //显示运行时间
- }
- else
- {
- printf("USER DSP ERROR\n"); //显示当前运行情况
- }
- //不使用DSP优化
- start_tim = HAL_GetTick();
- status = sin_cos_test(PI/6,200000,0);
- end_tim = HAL_GetTick();
- if(end_tim > start_tim)
- {
- tim_cnt = end_tim - start_tim;
- }
- else
- {
- tim_cnt = 0xffffffff - start_tim + end_tim;
- }
- if(status==0)
- {
- printf("NOT USER DSP-- %d-ms\r\n",tim_cnt); //显示运行时间
- }
- else
- {
- printf("NOT USER DSP ERROR\n"); //显示当前运行情况
- }
- HAL_GPIO_TogglePin(USER_LED_GPIO_Port,USER_LED_Pin);
- HAL_Delay(500);
复制代码
参数:angle : 起始角度 = π/6 ; times : 运算次数 = 10 000(1万);
结果如下图:使用DSP是8ms,没有使用DSP是12ms;12/8= 1.5倍。 参数:angle : 起始角度 = π/6 ; times : 运算次数 = 100 000(10万);
结果如下图:使用DSP是86ms,没有使用DSP是129ms;129/86= 1.5倍。
参数:angle : 起始角度 = π/6 ; times : 运算次数 = 200000(20万);
结果如下图:使用DSP是172ms,没有使用DSP是258ms;258/172= 1.5倍。
总结:在单精度数学运算方面使用DSP加数的效果还是比较明显的,平均来说是没有说使用DSP的15倍。
|