STM32F407ZET6_MRB/Core/Src/user_power_mgmt.c

174 lines
5.1 KiB
C

#include "stm32f4xx_hal.h"
#include "user_power_mgmt.h"
typedef struct {
RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_ClkInitTypeDef RCC_ClkInitStruct;
uint32_t Flash_Latency;
uint32_t Voltage_Scale;
} user_pm_vfs_t;
// C standard guarantees uninitialized parts are zeros.
static user_pm_vfs_t s_user_vfs_table[] = {
{
.RCC_OscInitStruct = {
.OscillatorType = RCC_OSCILLATORTYPE_HSI,
.HSIState = RCC_HSI_ON,
.PLL.PLLState = RCC_PLL_NONE,
},
.RCC_ClkInitStruct = {
.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK
| RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2,
.SYSCLKSource = RCC_SYSCLKSOURCE_HSI,
.AHBCLKDivider = RCC_SYSCLK_DIV1,
.APB1CLKDivider = RCC_HCLK_DIV1,
.APB2CLKDivider = RCC_HCLK_DIV1,
},
.Flash_Latency = FLASH_LATENCY_0,
.Voltage_Scale = PWR_REGULATOR_VOLTAGE_SCALE2,
},
{
.RCC_OscInitStruct = {
.OscillatorType = RCC_OSCILLATORTYPE_HSE,
.HSEState = RCC_HSE_ON,
.PLL.PLLState = RCC_PLL_ON,
.PLL.PLLSource = RCC_PLLSOURCE_HSE,
.PLL.PLLM = 4,
.PLL.PLLN = 168,
.PLL.PLLP = RCC_PLLP_DIV2,
.PLL.PLLQ = 4,
},
.RCC_ClkInitStruct = {
.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2,
.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK,
.AHBCLKDivider = RCC_SYSCLK_DIV1,
.APB1CLKDivider = RCC_HCLK_DIV4,
.APB2CLKDivider = RCC_HCLK_DIV2,
},
.Flash_Latency = FLASH_LATENCY_5,
.Voltage_Scale = PWR_REGULATOR_VOLTAGE_SCALE1,
},
{
.RCC_OscInitStruct = {
.OscillatorType = RCC_OSCILLATORTYPE_HSE,
.HSEState = RCC_HSE_ON,
.PLL.PLLState = RCC_PLL_ON,
.PLL.PLLSource = RCC_PLLSOURCE_HSE,
.PLL.PLLM = 4,
.PLL.PLLN = 144,
.PLL.PLLP = RCC_PLLP_DIV2,
.PLL.PLLQ = 4,
},
.RCC_ClkInitStruct = {
.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2,
.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK,
.AHBCLKDivider = RCC_SYSCLK_DIV1,
.APB1CLKDivider = RCC_HCLK_DIV4,
.APB2CLKDivider = RCC_HCLK_DIV2,
},
.Flash_Latency = FLASH_LATENCY_4,
.Voltage_Scale = PWR_REGULATOR_VOLTAGE_SCALE2,
},
{
.RCC_OscInitStruct = {
.OscillatorType = RCC_OSCILLATORTYPE_HSE,
.HSEState = RCC_HSE_ON,
.PLL.PLLState = RCC_PLL_ON,
.PLL.PLLSource = RCC_PLLSOURCE_HSE,
.PLL.PLLM = 4,
.PLL.PLLN = 84,
.PLL.PLLP = RCC_PLLP_DIV2,
.PLL.PLLQ = 4,
},
.RCC_ClkInitStruct = {
.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2,
.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK,
.AHBCLKDivider = RCC_SYSCLK_DIV1,
.APB1CLKDivider = RCC_HCLK_DIV2,
.APB2CLKDivider = RCC_HCLK_DIV2,
},
.Flash_Latency = FLASH_LATENCY_2,
.Voltage_Scale = PWR_REGULATOR_VOLTAGE_SCALE2,
},
};
static void user_pm_error_handler(void) {
while(1) {
//
}
}
static void user_pm_enter_sleep(void) {
//
}
static void user_pm_exit_sleep(void) {
//
}
/**
* @brief Set VFS mode, bad things happens if wrong sequence applied.
*
* @param vfs
* @return HAL_StatusTypeDef
*/
static HAL_StatusTypeDef user_pm_set_vfs_mode(user_pm_vfs_t *vfs) {
//Temporary raise voltage to SCALE 1
if(HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1) != HAL_OK) {
return HAL_ERROR;
}
// Set oscillators and PLLs.
if(HAL_RCC_OscConfig(&vfs->RCC_OscInitStruct) != HAL_OK) {
return HAL_ERROR;
}
// Apply system clock settings and bus clock settings.
if(HAL_RCC_ClockConfig(&vfs->RCC_ClkInitStruct, vfs->Flash_Latency) != HAL_OK) {
return HAL_ERROR;
}
// Set correct voltage scale.
if(HAL_PWREx_ControlVoltageScaling(vfs->Voltage_Scale) != HAL_OK) {
return HAL_ERROR;
}
return HAL_OK;
}
/**
* @brief Scale system frequency to specified preset
*
* @param preset: Target VFS preset
* @return Status
*/
HAL_StatusTypeDef user_pm_scale_vfs(user_pm_vfs_preset_t preset) {
// Transition system to a stable state.
if(user_pm_set_vfs_mode(&s_user_vfs_table[USER_PM_VFS_SAFE]) != HAL_OK) {
// Something bad happened.
user_pm_error_handler();
}
// Apply new frequency settings.
if(user_pm_set_vfs_mode(&s_user_vfs_table[preset]) != HAL_OK) {
// Another bad thing happened.
user_pm_error_handler();
}
return HAL_OK;
}
/**
* @brief Sleep for specific timeout
*
* @param sleep_msec: Time to sleep
* @return Time actually in sleep mode
*/
uint32_t user_pm_idle_timeout(uint32_t sleep_msec) {
return 0;
}