STM32H750时钟频率和功耗和RTC功能测试
- ????相关篇《STM32H750片外QSPI启动配置简要》
✨在使用STM32CubeMX修改STM32H750时钟树参数时,如果使用软件自动求解,这是一个非常耗时的操作,有时候还不一定成功,还是推荐使用手动方式进行配置,这一点和STM32其他系列不同,像STM32F1系列,输入频率参数回车确认后,自动求解很快就自动配置完成了。可能和时钟配置参数的复杂度有关。
????STM32H750时钟频率和功耗粗略统计对比
- ????以下是在的单片机正常运行模式下的测试数据。(以个人自制的STM32H750核心板测试为例,数据不代表所有实际使用的STM32H750的运行状态能耗)
- ????外部晶振25MHz , 480MHz主频,电流220mA,1.1w,芯片发热很大
- ????外部晶振 25MHz,400MHz,电流164mA,0.82w,芯片发热比较大
- ???? 外部晶振25MHz, 250MHz,电流75mA,0.4w,芯片稍微发热
- 功耗主要源头和主频关系非常大,与是否使能的外设多少,测试没有明显的影响。
- 如果跑满单片机主频(480MHz),长期运行,最好贴个散热片辅助散热,供电方面,至少500mA或以上输出能力的电源。
- ????STM32H750工程编译器推荐使用AC6版本的编译器,编译速度会比AC5版本快很多,在STM32H7上,这一点体现尤为明显。
????时钟频率配置参数
- ????25MHz外部晶振,配置480MHz
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Supply configuration update enable
*/
HAL_PWREx_ConfigSupply(PWR_LDO_SUPPLY);
/** Configure the main internal regulator output voltage
*/
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}
__HAL_RCC_SYSCFG_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE0);
while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}
/** Configure LSE Drive Capability
*/
HAL_PWR_EnableBkUpAccess();
__HAL_RCC_LSEDRIVE_CONFIG(RCC_LSEDRIVE_LOW);
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE|RCC_OSCILLATORTYPE_LSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.LSEState = RCC_LSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 5;
RCC_OscInitStruct.PLL.PLLN = 192;
RCC_OscInitStruct.PLL.PLLP = 2;
RCC_OscInitStruct.PLL.PLLQ = 2;
RCC_OscInitStruct.PLL.PLLR = 2;
RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_2;
RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;
RCC_OscInitStruct.PLL.PLLFRACN = 0;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2
|RCC_CLOCKTYPE_D3PCLK1|RCC_CLOCKTYPE_D1PCLK1;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2;
RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2;
RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)
{
Error_Handler();
}
}
- ????25MHz外部晶振,配置400MHz
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Supply configuration update enable
*/
HAL_PWREx_ConfigSupply(PWR_LDO_SUPPLY);
/** Configure the main internal regulator output voltage
*/
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}
/** Configure LSE Drive Capability
*/
HAL_PWR_EnableBkUpAccess();
__HAL_RCC_LSEDRIVE_CONFIG(RCC_LSEDRIVE_LOW);
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE|RCC_OSCILLATORTYPE_LSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.LSEState = RCC_LSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 5;
RCC_OscInitStruct.PLL.PLLN = 160;
RCC_OscInitStruct.PLL.PLLP = 2;
RCC_OscInitStruct.PLL.PLLQ = 2;
RCC_OscInitStruct.PLL.PLLR = 2;
RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_2;
RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;
RCC_OscInitStruct.PLL.PLLFRACN = 0;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2
|RCC_CLOCKTYPE_D3PCLK1|RCC_CLOCKTYPE_D1PCLK1;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2;
RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2;
RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
}
- ????8MHz外部晶振,配置480MHz
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Supply configuration update enable
*/
HAL_PWREx_ConfigSupply(PWR_LDO_SUPPLY);
/** Configure the main internal regulator output voltage
*/
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}
__HAL_RCC_SYSCFG_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE0);
while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}
/** Configure LSE Drive Capability
*/
HAL_PWR_EnableBkUpAccess();
__HAL_RCC_LSEDRIVE_CONFIG(RCC_LSEDRIVE_LOW);
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE|RCC_OSCILLATORTYPE_LSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.LSEState = RCC_LSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 32;
RCC_OscInitStruct.PLL.PLLN = 240;
RCC_OscInitStruct.PLL.PLLP = 2;
RCC_OscInitStruct.PLL.PLLQ = 2;
RCC_OscInitStruct.PLL.PLLR = 2;
RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_2;
RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;
RCC_OscInitStruct.PLL.PLLFRACN = 7753;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2
|RCC_CLOCKTYPE_D3PCLK1|RCC_CLOCKTYPE_D1PCLK1;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2;
RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2;
RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)
{
Error_Handler();
}
}
- ????8MHz外部晶振,配置400MHz:
RCC_OscInitStruct.PLL.PLLN = 240;
????RTC时钟功能
-
????在使能RTC日历,配置参数时,最好选择
RTC_FORMAT_BIN
数据格式,在使用RTC_FORMAT_BCD
数据格式,在读取数据就可以省去转换。 -
????如果使用RTC_FORMAT_BCD数据格式,转换为常规的十进制数参考代码:
RTC_HandleTypeDef hrtc;
void HAL_RTC_MspInit(RTC_HandleTypeDef *hrtc)
{
/* Enable RTC clock */
__HAL_RCC_RTC_ENABLE();
}
void RTC_BCDToDecimal(RTC_TimeTypeDef *sTime)
{
sTime->Hours = ((sTime->Hours & 0xF0) >> 4) * 10 + (sTime->Hours & 0x0F);
sTime->Minutes = ((sTime->Minutes & 0xF0) >> 4) * 10 + (sTime->Minutes & 0x0F);
sTime->Seconds = ((sTime->Seconds & 0xF0) >> 4) * 10 + (sTime->Seconds & 0x0F);
}
int main(void)
{
RTC_TimeTypeDef sTime;
/* Initialize RTC */
/* Get RTC time */
HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BCD);
/* Convert BCD to decimal */
RTC_BCDToDecimal(&sTime);
/* Use sTime.Hours, sTime.Minutes, sTime.Seconds as decimal values */
while (1)
{
/* Application code */
}
}
????RTC功能测试代码
- ✨个人采用的是外部flash运行程序,下载算法和程序地址,和常规片内运行的程序有所不同,这一点需要注意。
int main(void)
{
/* USER CODE BEGIN 1 */
uint8_t Rtctmp=0;
RTC_DateTypeDef GetData = {0}; //获取日期结构体
RTC_TimeTypeDef GetTime = {0}; //获取时间结构体
SCB->VTOR = 0x90000000; /*设置中断向量表偏移地址 */
/* USER CODE END 1 */
/* Enable the CPU Cache */
/* Enable I-Cache---------------------------------------------------------*/
SCB_EnableICache();
/* Enable D-Cache---------------------------------------------------------*/
SCB_EnableDCache();
/* 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_RTC_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
/* 使能 PWR 时钟 */
// __HAL_RCC_RTC_ENABLE();
/* PWR_CR:DBF置1,使能RTC、RTC备份寄存器和备份SRAM的访问 */
// HAL_PWR_EnableBkUpAccess();
/* 等待 RTC APB 寄存器同步 */
// HAL_RTC_WaitForSynchro(&hrtc);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while(1) {
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_RTC_GetTime(&hrtc, &GetTime, RTC_FORMAT_BIN);//RTC_FORMAT_BCD
HAL_RTC_GetDate(&hrtc, &GetData, RTC_FORMAT_BIN); //RTC_FORMAT_BIN
// 每秒打印一次
if(Rtctmp != GetTime.Seconds)
{
printf("Data:%04d-%02d-%02d\r\n", 2000 + GetData.Year, GetData.Month, GetData.Date);
printf("Time:%02d:%02d:%02d\r\n", GetTime.Hours, GetTime.Minutes, GetTime.Seconds);
HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin);
printf("STM32H750 SysClockFreq:%d \r\n", SystemCoreClock);
// printf("STM32H750 SysClockFreq:%d \r\n", HAL_RCC_GetSysClockFreq());
// (void)RTC->DR;
}
Rtctmp = GetTime.Seconds;
}
/* USER CODE END 3 */
}
????RTC不走时的相关原因分析
- ????在调用读取时间数据 接口函数时,需要同时一起调用时间和日期对应的函数:
HAL_RTC_GetTime(&hrtc, &GetTime, RTC_FORMAT_BIN);
HAL_RTC_GetDate(&hrtc, &GetData, RTC_FORMAT_BIN);
- ????在调用上面两个接口函数时,注意第一个形参,该形参是rtc被初始化过的句柄,被定义在:
rtc.c
中:
RTC_HandleTypeDef hrtc;
/* RTC init function */
void MX_RTC_Init(void)
{
/* USER CODE BEGIN RTC_Init 0 */
/* USER CODE END RTC_Init 0 */
RTC_TimeTypeDef sTime = {0};
RTC_DateTypeDef DateToUpdate = {0};
/* USER CODE BEGIN RTC_Init 1 */
/* USER CODE END RTC_Init 1 */
/** Initialize RTC Only
*/
hrtc.Instance = RTC;
hrtc.Init.AsynchPrediv = RTC_AUTO_1_SECOND;
hrtc.Init.OutPut = RTC_OUTPUTSOURCE_ALARM;
if (HAL_RTC_Init(&hrtc) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN Check_RTC_BKUP */
/* USER CODE END Check_RTC_BKUP */
/** Initialize RTC and set the Time and Date
*/
sTime.Hours = 0x20;
sTime.Minutes = 0x35;
sTime.Seconds = 0x35;
if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BCD) != HAL_OK)
{
Error_Handler();
}
DateToUpdate.WeekDay = RTC_WEEKDAY_MONDAY;
DateToUpdate.Month = RTC_MONTH_APRIL;
DateToUpdate.Date = 0x22;
DateToUpdate.Year = 0x24;
if (HAL_RTC_SetDate(&hrtc, &DateToUpdate, RTC_FORMAT_BCD) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN RTC_Init 2 */
/* USER CODE END RTC_Init 2 */
}
- ????如果传递的是一个自己定义的一个rtc句柄(例如:
RTC_HandleTypeDef Rtc_Handle;
),而未进行初始化操作,直接作为形参传入该句柄,将会导致不走时。- ????设置RTC时间的时候,用的那个变量作为句柄的,在调用读取时间信息的时候,也必须要使用相同的变量作为句柄来读取。
- ????如果必须要需使用自己定义的句柄,参考代码如下来做:
RTC_HandleTypeDef Rtc_Handle;
/**
* @brief 设置时间和日期
* @param 无
* @retval 无
*/
void RTC_TimeAndDate_Set(void)
{
RTC_DateTypeDef RTC_DateStructure;
RTC_TimeTypeDef RTC_TimeStructure;
// 初始化时间
RTC_TimeStructure.TimeFormat = RTC_HOURFORMAT12_AM;
RTC_TimeStructure.Hours = 8;
RTC_TimeStructure.Minutes = 12;
RTC_TimeStructure.Seconds = 26;
HAL_RTC_SetTime(&Rtc_Handle,&RTC_TimeStructure, RTC_FORMAT_BIN);
// 初始化日期
RTC_DateStructure.WeekDay = RTC_WEEKDAY_TUESDAY;
RTC_DateStructure.Date = 23;
RTC_DateStructure.Month = RTC_MONTH_APRIL;
RTC_DateStructure.Year = 24;
HAL_RTC_SetDate(&Rtc_Handle,&RTC_DateStructure, RTC_FORMAT_BIN);
}
/**
* @brief 显示时间和日期
* @param 无
* @retval 无
*/
void RTC_TimeAndDate_Show(void)
{
uint8_t Rtctmp=0;
RTC_TimeTypeDef RTC_TimeStructure;
RTC_DateTypeDef RTC_DateStructure;
while(1)
{
// 获取日历
HAL_RTC_GetTime(&Rtc_Handle, &RTC_TimeStructure, RTC_FORMAT_BIN);
HAL_RTC_GetDate(&Rtc_Handle, &RTC_DateStructure, RTC_FORMAT_BIN);
// 每秒打印一次
if(Rtctmp != RTC_TimeStructure.Seconds)
{
// 打印日期
printf("The Date : Y:20%0.2d - M:%0.2d - D:%0.2d - W:%0.2d\r\n",
RTC_DateStructure.Year,
RTC_DateStructure.Month,
RTC_DateStructure.Date,
RTC_DateStructure.WeekDay);
// 打印时间
printf("The Time : %0.2d:%0.2d:%0.2d \r\n\r\n",
RTC_TimeStructure.Hours,
RTC_TimeStructure.Minutes,
RTC_TimeStructure.Seconds);
}
Rtctmp = RTC_TimeStructure.Seconds;
}
}
- ????另一个时钟不走时的可能就是,在使用外部低速时钟源作为时钟源时,外部32.756KHz晶振没有起振所致。排查此原因也很简单,将低速时钟源改为内部时钟32KHz进行验证。