STM32F407: CMSIS-DSP库的移植(基于库文件)

目录

1. 源码下载

2. DSP库源码简介

3.基于库的移植(DSP库的使用)

3.1 实验1

3.2 实验2

4. 使用V6版本的编译器进行编译


上一篇:STM32F407-Discovery的硬件FPU-CSDN博客

1. 源码下载

Github地址:GitHub - ARM-software/CMSIS_5: CMSIS Version 5 Development Repository

最新版本是5.9.0,也可以使用HAL库里自带的,本文基于STM32Cube_FW_F4_V1.27.0里自带的DSP版本

2. DSP库源码简介

目录结构如下:\Drivers\CMSIS\DSP

Example:官方自带的一些示例

Include:公共头文件夹目录,其中比较重要的是arm_math.h

Projects:官方自带的工程示例

Source:DSP的源码实现,是重点目录

Source目录下各个文件夹实现功能简介如下表:

文件夹

实现的功能(API)

BasicMathFunctions

实现基本数学函数,有浮点/定点/向量等基本运算

CommonTables

一些公用的参数表

ComplexMathFunctions

复数的计算:加减乘除、取模等

ControllerFunctions

一些控制功能函数:比如PID控制算法

FastMathFunctions

纯数学理论实现的一些快速计算算法:求正余弦/快速开方

FilteringFunctions

滤波功能的实现:IIR/FIR/LMS/求卷积等

MatrixFunctions

矩阵运算相关API:加减法、转置、求逆等

StatisticsFunctions

常用的统计学方法:求均值/方差/标准差/均方根等

SupportFunctions

功能性函数:数据拷贝(连续的一大块)/定点浮点之间的转换

TransformFunctions

变换函数实现:复数/实数的FFT/IFFT以及离散余弦变换DCT

对应的DSP LIB库:\Drivers\CMSIS\Lib\ARM:

STM32F4是M4内核,FPU支持单精度浮点数据运算,小端模式,所以:arm_cortexM4lf_math.lib是重点文件。

3.基于库的移植(DSP库的使用)

仿照源代码库文件所在的目录结构,新建文件夹:Drivers\CMSIS\Lib\ARM

然后直接拷贝arm_cortexM4lf_math.lib到ARM目录下。

仿照源代码库的目录结构,新建文件夹:Drivers\CMSIS\DSP\Include

同样将源码目录中的三个头文件拷贝过来:

将库文件添加到Keil工程,并且添加头文件路径:

到此,库的移植已经完毕,接下来是预处理定义一些宏。

(1) 首先是硬件FPU要开启:取决于__FPU_PRESENT__FPU_USED

详见上一篇:STM32F407-Discovery的硬件FPU-CSDN博客

(2) 使用DSP库中的基本数学运算实现,比如sin()/cos():ARM_MATH_DSP

(3) 如果使用矩阵运算,则矩阵大小是个很值得注意的问题,运算前要对输入矩阵的大小进行检查:ARM_MATH_MATRIX_CHECK

(4) 浮点数转 Q32/Q15/Q7 时,处理四舍五入,最大限度确保数据精度不丢失: ARM_MATH_ROUNDING

(5) 批量处理数据时,加快执行速度,比如批量求绝对值: ARM_MATH_LOOPUNROLL

(6) 最后是CM4内核的一个宏:ARM_MATH_CM4

把这些添加到全局的宏定义中:

USE_HAL_DRIVER,STM32F407xx,USE_STM32F4_DISCO,ARM_MATH_MATRIX_CHECK,ARM_MATH_ROUNDING,ARM_MATH_LOOPUNROLL,ARM_MATH_CM4

3.1 实验1

对比MDK标准库函数和DSP库函数的计算速度。

Main.c

/* Includes ------------------------------------------------------------------*/
#include "main.h"

#define DELTA   0.0001f         /* 误差值 */
extern TIM_HandleTypeDef g_timx_handle;
uint8_t g_timeout;

/**
 * @brief       sin cos 测试
 * @param       angle : 起始角度
 * @param       times : 运算次数
 * @param       mode  : 是否使用DSP库
 *   @arg       0 , 不使用DSP库;
 *   @arg       1 , 使用DSP库;
 *
 * @retval      无
 */
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;                                   /* 任务完成 */
}

int main(void)
{
	float time;
	uint8_t res;

	/* STM32F4xx HAL library initialization:
	- Configure the Flash prefetch, instruction and Data caches
	- Configure the Systick to generate an interrupt each 1 msec
	- Set NVIC Group Priority to 4
	- Global MSP (MCU Support Package) initialization
	*/
	HAL_Init();
/* Configure the system clock to 168 MHz */
	SystemClock_Config();

	/* 串口2初始化: 只用tx功能 */
	if(uart2_init(9600))
	{
		Error_Handler();
	}

#if 1
//	BSP_LED_Off(LED6);
//	HAL_Delay(200);
//
//	BSP_LED_On(LED6);
//	//HAL_Delay(1000);
//	//test_fpu_tmp1();
//	fft_test();
//	BSP_LED_Off(LED6);
//	for (int i=0; i <N; i++) { //打印很耗时
//		printf("ifft: OUTPUT_SEQ[%d].real=%f, OUTPUT_SEQ[%d].img=%f\n", i, OUTPUT_SEQ[i].real, i, OUTPUT_SEQ[i].img);
//	}
//	printf("\n\n");

   //不用GPIO来测量时长了,改用定时器
	btim_timx_int_init(65535, 8400 - 1);
	__HAL_TIM_SET_COUNTER(&g_timx_handle, 0); /* 重设TIM6定时器的计数器值 */
	g_timeout = 0;
	 res = sin_cos_test(PI / 6, 200000, 0);
	//HAL_Delay(1000);

	time = __HAL_TIM_GET_COUNTER(&g_timx_handle) + (uint32_t)g_timeout * 65536;
    printf("%0.1fms\r\n", time / 10);

	/* 使用DSP优化 */
	__HAL_TIM_SET_COUNTER(&g_timx_handle, 0);                           /* 重设TIM6定时器的计数器值 */
	g_timeout = 0;
	res = sin_cos_test(PI / 6, 200000, 1);
	time = __HAL_TIM_GET_COUNTER(&g_timx_handle) + (uint32_t)g_timeout * 65536;
	printf("%0.1fms\r\n", time / 10);
#endif

	printf("__CC_ARM:%d\n", __CC_ARM);
	printf("__FPU_PRESENT:%d\n", __FPU_PRESENT);
	printf("__FPU_USED:%d\n", __FPU_USED);
	printf("SCB->CPACR:0x%x\n", SCB->CPACR);

	while(1){
		;
	}

	return 0;
}

/**
  * @brief  System Clock Configuration
  *         The system Clock is configured as follow :
  *            System Clock source            = PLL (HSE)
  *            SYSCLK(Hz)                     = 168000000
  *            HCLK(Hz)                       = 168000000
  *            AHB Prescaler                  = 1
  *            APB1 Prescaler                 = 4
  *            APB2 Prescaler                 = 2
  *            HSE Frequency(Hz)              = 8000000
  *            PLL_M                          = 8
  *            PLL_N                          = 336
  *            PLL_P                          = 2
  *            PLL_Q                          = 7
  *            VDD(V)                         = 3.3
  *            Main regulator output voltage  = Scale1 mode
  *            Flash Latency(WS)              = 5
  * @param  None
  * @retval None
  */
static void SystemClock_Config(void)
{
  RCC_ClkInitTypeDef RCC_ClkInitStruct;
  RCC_OscInitTypeDef RCC_OscInitStruct;

  /* Enable Power Control clock */
  __HAL_RCC_PWR_CLK_ENABLE();

  /* The voltage scaling allows optimizing the power consumption when the device is
     clocked below the maximum system frequency, to update the voltage scaling value
     regarding system frequency refer to product datasheet.  */
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);


  /* Enable HSE Oscillator and activate PLL with HSE as source */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = 8;
  RCC_OscInitStruct.PLL.PLLN = 336;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = 7;

  if(HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /* Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2
     clocks dividers */
  RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
  if(HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
  {
    Error_Handler();
  }

  /* STM32F405x/407x/415x/417x Revision Z devices: prefetch is supported  */
  if (HAL_GetREVID() == 0x1001)
  {
    /* Enable the Flash prefetch */
    __HAL_FLASH_PREFETCH_BUFFER_ENABLE();
  }
}

运行结果如下:

[22:54:44.691]  315.0ms  //使用库函数

[22:54:44.851]  153.9ms  //使用DSP

[22:54:44.851]  __CC_ARM:1

[22:54:44.867]  __FPU_PRESENT:1

[22:54:44.883]  __FPU_USED:1

[22:54:44.898]  SCB->CPACR:0xf00000

3.2 实验2

测量计算1024个点的复数FFT运行时长

main.c

/* FFT长度,如果不指定,则默认是1024个点
 * 长度可选范围: 16, 64, 256, 1024.
 */
#define FFT_LENGTH      1024

float fft_inputbuf[FFT_LENGTH * 2];     /* FFT输入数组 */
float fft_outputbuf[FFT_LENGTH];        /* FFT输出数组 */
uint8_t g_timeout;
extern TIM_HandleTypeDef g_timx_handle;

int main(void)
{
	float time;
	uint8_t res;
	int i;
	arm_cfft_radix4_instance_f32 scfft;

	/* STM32F4xx HAL library initialization:
	- Configure the Flash prefetch, instruction and Data caches
	- Configure the Systick to generate an interrupt each 1 msec
	- Set NVIC Group Priority to 4
	- Global MSP (MCU Support Package) initialization
	*/
	HAL_Init();

	/* Configure the system clock to 168 MHz */
	SystemClock_Config();

	/* 串口2初始化: 只用tx功能 */
	if(uart2_init(9600))
	{
		Error_Handler();
	}

	/* 初始化scfft结构体,设置相关参数 */
	arm_cfft_radix4_init_f32(&scfft, FFT_LENGTH, 0, 1);

#if 1
	/* 初始化输入序列 */
	for (i = 0; i < FFT_LENGTH; i++)
	{
		fft_inputbuf[2 * i] = 100 +
													10 * arm_sin_f32(2 * PI * i / FFT_LENGTH) +
													30 * arm_sin_f32(2 * PI * i * 4 / FFT_LENGTH) +
													50 * arm_cos_f32(2 * PI * i * 8 / FFT_LENGTH);    /* 实部 */
		fft_inputbuf[2 * i + 1] = 0;    /* 虚部: 都是0 */
	}
	
	btim_timx_int_init(65535, 8400 - 1);
	__HAL_TIM_SET_COUNTER(&g_timx_handle, 0); /* 重设TIM6定时器的计数器值 */
	g_timeout = 0;

	arm_cfft_radix4_f32(&scfft, fft_inputbuf);                      /* FFT(基4) */

	/* 计算运行时间 */
	time =__HAL_TIM_GET_COUNTER(&g_timx_handle) + (uint32_t)g_timeout * 65536;
	printf("%0.1fms\r\n", time / 10);

	arm_cmplx_mag_f32(fft_inputbuf, fft_outputbuf, FFT_LENGTH);     /* 求模 */

	printf("\r\n%d point FFT runtime:%0.1fms\r\n", FFT_LENGTH, time / 10);
//	printf("FFT Result:\r\n");

//	for (i = 0; i < FFT_LENGTH; i++)
//	{
//		printf("fft_outputbuf[%d]:%f\r\n", i, fft_outputbuf[i]);
//	}
#endif

	printf("__CC_ARM:%d\n", __CC_ARM);
	printf("__FPU_PRESENT:%d\n", __FPU_PRESENT);
	printf("__FPU_USED:%d\n", __FPU_USED);
	printf("SCB->CPACR:0x%x\n", SCB->CPACR);

	while(1){
		;
	}

	return 0;
}

打印:大概是0.6ms完成一个1024点的复数运算

[23:39:30.141]  0.6ms

[23:39:30.141]  

[23:39:30.141]  1024 point FFT runtime:0.0ms

[23:39:30.172]  __CC_ARM:1

[23:39:30.188]  __FPU_PRESENT:1

[23:39:30.204]  __FPU_USED:1

[23:39:30.220]  SCB->CPACR:0xf00000

4. 使用V6版本的编译器进行编译

编译出现一堆错:ArmClang: error: unsupported option '--C99'

将--C99改为-xc -std=c99即可:

更改如下:

注:

(1)如果要用V5编译器,则该选项要改回--C99

(2)V6版本的编译器对浮点数运算有做优化,将优化等级配置为fast mode后,相对V5版本有明显速度的提升,如下:

AC6版本编译器配置

基于上面的实验2:运行结果用了0.5ms

[10:47:32.200]  test_fft()->times: 0.500000ms

[10:47:32.232]  __FPU_PRESENT:1

[10:47:32.248]  __FPU_USED:1

[10:47:32.264]  SCB->CPACR:0xf00000

关于MDK5的AC5,AC6编译器对比,可以参考这个论坛:

https://www.armbbs.cn/forum.php?mod=viewthread&tid=95455

测试代码:main.c

/**
  ******************************************************************************
  * @file    UART/UART_TwoBoards_ComPolling/Src/main.c
  * @author  MCD Application Team
  * @brief   This sample code shows how to use STM32F4xx UART HAL API to transmit
  *          and receive a data buffer with a communication process based on
  *          polling transfer.
  *          The communication is done using 2 Boards.
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2017 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "main.h"

/** @addtogroup STM32F4xx_HAL_Examples
  * @{
  */

/** @addtogroup UART_TwoBoards_ComPolling
  * @{
  */

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define TRANSMITTER_BOARD

/* Private function prototypes -----------------------------------------------*/
static void SystemClock_Config(void);
static void Error_Handler(void);

/* Private functions ---------------------------------------------------------*/

extern TIM_HandleTypeDef g_timx_handle;
uint8_t g_timeout;

float re_dat;
float a=0.14f;
float b=0.26f;

void test_fpu_tmp1(void)
{
		long i, j;
		float re_nul;
		float time;

		/* 初始化定时器6 */
		btim_timx_int_init(65535, 8400 - 1);
		/* 重设TIM6定时器的计数器值 */
		__HAL_TIM_SET_COUNTER(&g_timx_handle, 0);
		g_timeout = 0;

		for(i=0; i<10000; i++) {
			for(j=0; j<2; j++) {
				re_nul=a*b;
				re_dat=re_dat+re_nul;
				a=a+0.1f;
				b=b+0.1f;
			}
		}

		/* 计算运行时间 */
		time =__HAL_TIM_GET_COUNTER(&g_timx_handle) + (uint32_t)g_timeout * 65536;
		printf("%s()->times: %fms\r\n", __func__, time / 10);

		btim_timx_int_deinit(65535, 8400 - 1);
		printf("re_dat:%f\n", re_dat);

}

complex INPUT_SEQ[FFT_LEN], RES_SEQ[FFT_LEN], OUTPUT_SEQ[FFT_LEN];
float SEQ_DAT[FFT_LEN], dataR[FFT_LEN], dataI[FFT_LEN];
int fft_priv_test(void)
{
		int i, j;
		float time;

		//构造实数序列
		for (i=0; i < FFT_LEN; i++) {
			SEQ_DAT[i]=i+0.0f;
		}

		//构造虚数序列
		for (j=0; j<FFT_LEN; j++) {
			INPUT_SEQ[j].real= SEQ_DAT[j];
			INPUT_SEQ[j].img=0.0f;
		}

//		for (i=0; i <FFT_LEN; i++) {
//			printf("before fft: INPUT_SEQ[%d].real=%f, INPUT_SEQ[%d].img=%f\n", i, INPUT_SEQ[i].real, i, INPUT_SEQ[i].img);
//		}
//		printf("\n\n");

		/* 初始化定时器6 */
		btim_timx_int_init(65535, 8400 - 1);
		/* 重设TIM6定时器的计数器值 */
		__HAL_TIM_SET_COUNTER(&g_timx_handle, 0);
		g_timeout = 0;

#if 1
		FFT(INPUT_SEQ, FFT_LEN, FFT_ORDER, RES_SEQ);
//		for (i=0; i <FFT_LEN; i++) {
//			printf("fft: RES_SEQ[%d].real=%f, RES_SEQ[%d].img=%f\n", i, RES_SEQ[i].real, i, RES_SEQ[i].img);
//		}
//		printf("\n\n");

		iFFT(RES_SEQ, FFT_LEN, FFT_ORDER, OUTPUT_SEQ);
		/* 计算运行时间 */
		time =__HAL_TIM_GET_COUNTER(&g_timx_handle) + (uint32_t)g_timeout * 65536;
		printf("%s()->times: %fms\r\n", __func__, time / 10);

		btim_timx_int_deinit(65535, 8400 - 1);

#else
		HAL_Delay(1000);
#endif

//		for (i=0; i <FFT_LEN; i++) { //打印很耗时
//			printf("ifft: OUTPUT_SEQ[%d].real=%f, OUTPUT_SEQ[%d].img=%f\n", i, OUTPUT_SEQ[i].real, i, OUTPUT_SEQ[i].img);
//		}
//		printf("\n\n");

		return 0;
}

#define DELTA   0.0001f         /* 误差值 */

/**
 * @brief       sin cos 测试
 * @param       angle : 起始角度
 * @param       times : 运算次数
 * @param       mode  : 是否使用DSP库
 *   @arg       0 , 不使用DSP库;
 *   @arg       1 , 使用DSP库;
 *
 * @retval      无
 */
uint8_t sin_cos_test(float angle, uint32_t times, uint8_t mode)
{
    float sinx, cosx;
    float result;
		float time;
    uint32_t i = 0;

		/* 初始化定时器6 */
		btim_timx_int_init(65535, 8400 - 1);
		/* 重设TIM6定时器的计数器值 */
		__HAL_TIM_SET_COUNTER(&g_timx_handle, 0);
		g_timeout = 0;

    if (mode == 0)
    {
    		printf("not use DSP\n");
        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
    {
    		printf("use DSP\n");
        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;                    /* 角度自增 */
        }
    }

		/* 计算运行时间 */
		time =__HAL_TIM_GET_COUNTER(&g_timx_handle) + (uint32_t)g_timeout * 65536;
		printf("%s()->times: %fms\r\n", __func__, time / 10);

		btim_timx_int_deinit(65535, 8400 - 1);
    return 0;                                   /* 任务完成 */
}


/******************************************************************/
/* FFT长度,如果不指定,则默认是1024个点
 * 长度可选范围: 16, 64, 256, 1024.
 */
#define FFT_LENGTH	1024
float fft_inputbuf[FFT_LENGTH * 2];     /* FFT输入数组 */
float fft_outputbuf[FFT_LENGTH];        /* FFT输出数组 */

void test_fft(void)
{
		int i;
		float time;
		arm_cfft_radix4_instance_f32 scfft;

		/* 初始化scfft结构体,设置相关参数 */
		arm_cfft_radix4_init_f32(&scfft, FFT_LENGTH, 0, 1);

		/* 初始化输入序列 */
		for (i = 0; i < FFT_LENGTH; i++)
		{
			/* 实部 */
			fft_inputbuf[2 * i] = 100 +
														10 * arm_sin_f32(2 * PI * i / FFT_LENGTH) +
														30 * arm_sin_f32(2 * PI * i * 4 / FFT_LENGTH) +
														50 * arm_cos_f32(2 * PI * i * 8 / FFT_LENGTH);
			/* 虚部: 都是0 */
			fft_inputbuf[2 * i + 1] = 0;
		}

		/* 初始化定时器6 */
		btim_timx_int_init(65535, 8400 - 1);
		/* 重设TIM6定时器的计数器值 */
		__HAL_TIM_SET_COUNTER(&g_timx_handle, 0);
		g_timeout = 0;

		/* FFT(基4) */
		arm_cfft_radix4_f32(&scfft, fft_inputbuf);

		/* 计算运行时间 */
		time =__HAL_TIM_GET_COUNTER(&g_timx_handle) + (uint32_t)g_timeout * 65536;
		printf("%s()->times: %fms\r\n", __func__, time / 10);

		/* 求模 */
//		arm_cmplx_mag_f32(fft_inputbuf, fft_outputbuf, FFT_LENGTH);
//
//		printf("\r\n%d point FFT runtime:%0.1fms\r\n", FFT_LENGTH, time / 10);
//		printf("FFT Result:\r\n");
//
//		for (i = 0; i < FFT_LENGTH; i++)
//		{
//			printf("fft_outputbuf[%d]:%f\r\n", i, fft_outputbuf[i]);
//		}
		btim_timx_int_deinit(65535, 8400 - 1);
}
/******************************************************************/

int main(void)
{
		uint8_t res;

		/* STM32F4xx HAL library initialization:
		- Configure the Flash prefetch, instruction and Data caches
		- Configure the Systick to generate an interrupt each 1 msec
		- Set NVIC Group Priority to 4
		- Global MSP (MCU Support Package) initialization
		*/
		HAL_Init();

		/* Configure the system clock to 168 MHz */
		SystemClock_Config();

		/* 串口2初始化: 只用tx功能 */
		if(uart2_init(9600))
		{
			Error_Handler();
		}

#if 1
			test_fft();
//		res=sin_cos_test(PI / 6, 200000, 0);
//		res=sin_cos_test(PI / 6, 200000, 1);
//		res=fft_priv_test();
//		test_fpu_tmp1();
#endif

		//printf("__CC_ARM:%d\n", __CC_ARM);
		printf("__FPU_PRESENT:%d\n", __FPU_PRESENT);
		printf("__FPU_USED:%d\n", __FPU_USED);
		printf("SCB->CPACR:0x%x\n", SCB->CPACR);

		while(1){
			;
		}

		return 0;
}

/**
  * @brief  System Clock Configuration
  *         The system Clock is configured as follow :
  *            System Clock source            = PLL (HSE)
  *            SYSCLK(Hz)                     = 168000000
  *            HCLK(Hz)                       = 168000000
  *            AHB Prescaler                  = 1
  *            APB1 Prescaler                 = 4
  *            APB2 Prescaler                 = 2
  *            HSE Frequency(Hz)              = 8000000
  *            PLL_M                          = 8
  *            PLL_N                          = 336
  *            PLL_P                          = 2
  *            PLL_Q                          = 7
  *            VDD(V)                         = 3.3
  *            Main regulator output voltage  = Scale1 mode
  *            Flash Latency(WS)              = 5
  * @param  None
  * @retval None
  */
static void SystemClock_Config(void)
{
  RCC_ClkInitTypeDef RCC_ClkInitStruct;
  RCC_OscInitTypeDef RCC_OscInitStruct;

  /* Enable Power Control clock */
  __HAL_RCC_PWR_CLK_ENABLE();

  /* The voltage scaling allows optimizing the power consumption when the device is
     clocked below the maximum system frequency, to update the voltage scaling value
     regarding system frequency refer to product datasheet.  */
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);


  /* Enable HSE Oscillator and activate PLL with HSE as source */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = 8;
  RCC_OscInitStruct.PLL.PLLN = 336;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = 7;

  if(HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /* Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2
     clocks dividers */
  RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
  if(HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
  {
    Error_Handler();
  }

  /* STM32F405x/407x/415x/417x Revision Z devices: prefetch is supported  */
  if (HAL_GetREVID() == 0x1001)
  {
    /* Enable the Flash prefetch */
    __HAL_FLASH_PREFETCH_BUFFER_ENABLE();
  }
}

/**
  * @brief  UART error callbacks
  * @param  UartHandle: UART handle
  * @note   This example shows a simple way to report transfer error, and you can
  *         add your own implementation.
  * @retval None
  */
void HAL_UART_ErrorCallback(UART_HandleTypeDef *UartHandle)
{
  /* Turn LED3 on: Transfer error in reception/transmission process */
  BSP_LED_On(LED3);
}


/**
  * @brief  This function is executed in case of error occurrence.
  * @param  None
  * @retval None
  */
static void Error_Handler(void)
{
  /* Turn LED5 on */
  BSP_LED_On(LED5);
  while(1)
  {
  }
}

#ifdef  USE_FULL_ASSERT

/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t* file, uint32_t line)
{
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */

  /* Infinite loop */
  while (1)
  {
  }
}
#endif

/**
  * @}
  */

/**
  * @}
  */

下一篇:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/135124.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

开发知识点-Vue-Electron

Electron ElectronVue打包.exe桌面程序 ElectronVue打包.exe桌面程序 为了不报错 卸载以前的脚手架 npm uninstall -g vue-cli安装最新版脚手架 cnpm install -g vue/cli创建一个 vue 随便起个名 vue create electron-vue-example (随便起个名字electron-vue-example)进入 创建…

中国国内机场信息集成系统厂家现状情况

机场信息集成系统在本世纪初进入中国市场&#xff0c;早期的信息集成系统提供商以外企为主&#xff0c;后来国内企业迅速发展。但在2008年前&#xff0c;民航总局设立了机场信息系统的入门门槛&#xff0c;也就是需要民航空管工程及机场弱电系统建设资质要求&#xff0c;该要求…

MySQL 约束特殊查询

MySQL 约束&特殊查询 文章目录 MySQL 约束&特殊查询1. 数据库约束1.1 约束类型1.2 NULL约束1.3 NUIQUE&#xff1a;唯一约束1.4 DEFAULT&#xff1a;默认值约束1.5 PRIMARY KEY&#xff1a;主键约束1.6 FOREIGN KEY&#xff1a;外键约束1.7 CHECK约束 2. 表的关系2.1 一…

IPV4过渡IPV6的关键技术NAT(Network AddressTranslation,网络地址转换)

文章目录 NAT的由来NAT基本工作机制NAT技术的分类推荐阅读 NAT的由来 随着物联网、工业互联网、5G的快速发展&#xff0c;网络应用对IP地址的需求呈现出爆炸式的增长。 然而&#xff0c;早在2011年&#xff0c;ICANN就发布公告称最后五组IP地址已分配完毕&#xff0c;已无IPv4…

常微分方程

什么是常微分方程&#xff1a; 未知函数为单变量(一元)函数 例1 设有温度为100摄氏度的物体放置在20摄氏度的空气冷却&#xff0c;求物体温度随时间 变化 的规律。 解&#xff1a;设t时刻物体温度为T 对两边求共积分 设比例系数为k>0 令C, 微分方程&#xff1a; 联系着…

如何删除英文键盘ENG

1.打开设置&#xff1a;时间和语言2.选择语言&#xff0c;查看首选列表&#xff0c;如果有多种语言&#xff0c;删除其他的语言就可以&#xff0c;如果只有中文&#xff0c;需要点击添加语言 3.选择安装的语言 这个时候点击英语&#xff0c;在选项中就可以看到它的默认键盘&…

【博士每天一篇文献-算法】Imposing Connectome-Derived Topology on an Echo State Network

阅读时间&#xff1a;2023-11-5 1 介绍 年份&#xff1a;2022 作者&#xff1a;Jacob Morra, Mark Daley 西部大学 期刊&#xff1a;2022 International Joint Conference on Neural Networks (IJCNN) 引用量&#xff1a;3 研究了果蝇连接图的拓扑结构对混沌时间序列预测中回…

【信息安全原理】——传输层安全(学习笔记)

&#x1f4d6; 前言&#xff1a;为保证网络应用&#xff0c;特别是应用广泛的Web应用数据传输的安全性&#xff08;机密性、完整性和真实性&#xff09;&#xff0c;可以在多个网络层次上采取安全措施。本篇主要介绍传输层提供应用数据安全传输服务的协议&#xff0c;包括&…

代码随想录算法训练营第18天|513. 找树左下角的值 112. 路径总和 113.路径总和ii 106.从中序与后序遍历序列构造二叉树

JAVA代码编写 513. 找树左下角的值 给定一个二叉树的 根节点 root&#xff0c;请找出该二叉树的 最底层 最左边 节点的值。 假设二叉树中至少有一个节点。 示例 1: 输入: root [2,1,3] 输出: 1示例 2: 输入: [1,2,3,4,null,5,6,null,null,7] 输出: 7提示: 二叉树的节点个…

FlinkSQL聚合函数(Aggregate Function)详解

使用场景&#xff1a; 聚合函数即 UDAF&#xff0c;常⽤于进多条数据&#xff0c;出⼀条数据的场景。 上图展示了⼀个 聚合函数的例⼦ 以及 聚合函数包含的重要⽅法。 案例场景&#xff1a; 关于饮料的表&#xff0c;有三个字段&#xff0c;分别是 id、name、price&#xff0…

[C++随想录] map和set的封装

map和set的封装 1. 红黑树模版的改变1.1 RBTree类模板 头的改变1.2 封装迭代器类1.2.1 构造 && 拷贝构造1.2.2. 1.2.3. - -1.2.4. 其他运算符重载 1.3 RBTree类实现普通迭代器和const迭代器 2. set的底层逻辑3. map的底层逻辑4. 源码4.1 RBTree类4.2 set类4.3 map类 1.…

搭建Docker

一、概念 云服务器大家肯定不陌生了&#xff0c;相比较传统物理服务器来说他的价格&#xff0c;个性化的配置服务&#xff0c;节省了很多的运维成本&#xff0c;越来越多的企业以及个人开发者更加的青睐于云服务器。有了属于自己的服务器就可以部署搭建自己个人网站了&#xf…

js动态显示当前时间

目录 1、封装时间函数 2、在页面写一个div标签&#xff0c;用来存放时间 3、获取div标签&#xff0c;开启定时器&#xff0c;时间为1000ms 4、先调用时间函数&#xff0c;防止页面加载延迟&#xff0c;再在定时器里调用 完整代码 效果图 1、封装时间函数 function getTi…

asp.net 在线音乐网站系统VS开发sqlserver数据库web结构c#编程Microsoft Visual Studio

一、源码特点 asp.net 在线音乐网站系统是一套完善的web设计管理系统&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为vs2010&#xff0c;数据库为sqlserver2008&#xff0c;使用c#语言 开发 asp.net 在线音乐网站系统1 应用…

Least Square Method 最小二乘法(图文详解,必懂)

最小二乘法是一种求解线性回归模型的优化方法&#xff0c;其目标是最小化数据点和拟合直线之间的残差平方和。这意味着最小二乘法关注的是找到一个直线&#xff0c;使得所有数据点与该直线的偏差的平方和最小。在数学公式中&#xff0c;如果y是实际值&#xff0c;y是函数估计值…

计算机组成原理第四章(存储系统)(一)

一、存储器概述 1.分类&#xff1a; 存取方式&#xff1a;随机存储器&#xff08;RAM&#xff09;、顺序存储器&#xff08;SAM&#xff09;、直接存储器&#xff08;DAM&#xff09; 存储介质&#xff1a;磁性材料存储器、半导体存储器、光存储器 功能和存取速度&#xff1a; …

【阿里云】函数计算 X 通义千问快速部署

写在前面&#xff1a;博主是一只经过实战开发历练后投身培训事业的“小山猪”&#xff0c;昵称取自动画片《狮子王》中的“彭彭”&#xff0c;总是以乐观、积极的心态对待周边的事物。本人的技术路线从Java全栈工程师一路奔向大数据开发、数据挖掘领域&#xff0c;如今终有小成…

2023年施工升降机司机(建筑特殊工种)证模拟考试题库及施工升降机司机(建筑特殊工种)理论考试试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2023年施工升降机司机(建筑特殊工种)证模拟考试题库及施工升降机司机(建筑特殊工种)理论考试试题是由安全生产模拟考试一点通提供&#xff0c;施工升降机司机(建筑特殊工种)证模拟考试题库是根据施工升降机司机(建筑特…

论文笔记--Baichuan 2: Open Large-scale Language Models

论文笔记--Baichuan 2: Open Large-scale Language Models 1. 文章简介2. 文章概括3 文章重点技术3.1 预训练3.1.1 预训练数据3.1.2 模型架构 3.2 对齐3.2.1 SFT3.2.2 Reward Model(RM)3.2.3 PPO 3.3 安全性 4. 文章亮点5. 原文传送门 1. 文章简介 标题&#xff1a;Baichuan 2…

IP-guard Webserver view 远程命令执行漏洞【2023最新漏洞】

IP-guard Webserver view 远程命令执行漏洞【2023最新漏洞】 一、漏洞描述二、漏洞影响三、漏洞危害四、FOFA语句五、漏洞复现1、手动复现yaml pocburp发包 2、自动化复现小龙POC检测工具下载地址 免责声明&#xff1a;请勿利用文章内的相关技术从事非法测试&#xff0c;由于传…