rt-thread-official/bsp/stm32/stm32mp157a-st-discovery/board/ports/drv_pwr.c

203 lines
5.5 KiB
C

/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2020-07-27 thread-liu first version
*/
#include "board.h"
//#define DRV_DEBUG
#define LOG_TAG "drv.pwr"
#include <drv_log.h>
extern int lptim_start(void);
extern int lptim_stop(void);
static RCC_ClkInitTypeDef RCC_ClkInit = {0};
#define __WAIT_EVENT_TIMEOUT(__CONDITION__, __TIMEOUT_VAL__) \
do { \
__IO uint32_t count = __TIMEOUT_VAL__ * (SystemCoreClock / 20U / 1000U); \
do \
{ \
if (count-- == 0U) \
{ \
return HAL_TIMEOUT; \
} \
} \
while (__CONDITION__ == 0U); \
} while(0)
/* Back up clock tree */
static void backup_cm4_clocks(void)
{
rt_uint32_t *pFLatency = NULL;
/* Back up MCU clock configuration */
HAL_RCC_GetClockConfig(&RCC_ClkInit, pFLatency);
}
/* Restore the CM4 clock source muxer and the CM4 prescaler. */
rt_err_t restore_cm4_clock(void)
{
/* Update SystemCoreClock variable */
SystemCoreClock = HAL_RCC_GetSystemCoreClockFreq();
/* Enable PLL3 if needed */
if (RCC_ClkInit.MCUInit.MCU_Clock == RCC_MCUSSOURCE_PLL3)
{
/* Enable PLL3 */
__HAL_RCC_PLL3_ENABLE();
/* Wait till PLL3 is ready */
__WAIT_EVENT_TIMEOUT(__HAL_RCC_GET_FLAG(RCC_FLAG_PLL3RDY), CLOCKSWITCH_TIMEOUT_VALUE);
/* Enable PLL3 outputs */
__HAL_RCC_PLL3CLKOUT_ENABLE(RCC_PLL3_DIVP | RCC_PLL3_DIVQ | RCC_PLL3_DIVR);
}
/* Configure MCU clock only */
__HAL_RCC_MCU_SOURCE(RCC_ClkInit.MCUInit.MCU_Clock);
/* Wait till MCU is ready */
__WAIT_EVENT_TIMEOUT(__HAL_RCC_GET_FLAG(RCC_FLAG_MCUSSRCRDY),
CLOCKSWITCH_TIMEOUT_VALUE);
/* Update SystemCoreClock variable */
SystemCoreClock = HAL_RCC_GetSystemCoreClockFreq();
/* Reconfigure Systick */
if (HAL_InitTick(uwTickPrio) != HAL_OK)
{
return -RT_ERROR;
}
/* Set MCU division factor */
__HAL_RCC_MCU_DIV(RCC_ClkInit.MCUInit.MCU_Div);
/* Wait till MCUDIV is ready */
__WAIT_EVENT_TIMEOUT(__HAL_RCC_GET_FLAG(RCC_FLAG_MCUDIVRDY),
CLOCKSWITCH_TIMEOUT_VALUE);
/* Update SystemCoreClock variable */
SystemCoreClock = HAL_RCC_GetSystemCoreClockFreq();
/* Reconfigure Systick */
if (HAL_InitTick(uwTickPrio) != HAL_OK)
{
return -RT_ERROR;
}
return RT_EOK;
}
void RCC_WAKEUP_IRQHandler(void)
{
/* enter interrupt */
rt_interrupt_enter();
HAL_RCC_WAKEUP_IRQHandler();
/* leave interrupt */
rt_interrupt_leave();
}
void HAL_RCC_WAKEUP_Callback()
{
if (__HAL_PWR_GET_FLAG(PWR_FLAG_STOP) == 1U)
{
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_STOP);
}
restore_cm4_clock();
/* All level of ITs can interrupt */
__set_BASEPRI(0U);
rt_kprintf("system exit stop mode success!\n");
}
static void enter_sleep_mode(void)
{
__set_BASEPRI((1) << (8 - __NVIC_PRIO_BITS));
lptim_start();
HAL_PWR_EnterSLEEPMode(PWR_LOWPOWERREGULATOR_ON, PWR_SLEEPENTRY_WFI);
}
static void enter_stop_mode(void)
{
/*
* Only the IT with the highest priority (0 value) can interrupt.
* RCC_WAKEUP_IRQn IT is intended to have the highest priority and to be the
* only one IT having this value
* RCC_WAKEUP_IRQn is generated only when RCC is completely resumed from
* CSTOP (protection mechanism)
*/
__set_BASEPRI((1) << (8 - __NVIC_PRIO_BITS));
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_STOP);
backup_cm4_clocks();
HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
}
static void pm_wackup_key_init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitStruct.Pin = GPIO_PIN_13;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
HAL_NVIC_SetPriority(EXTI13_IRQn, 0x01, 0);
HAL_NVIC_EnableIRQ(EXTI13_IRQn);
}
int drv_pm_hw_init(void)
{
pm_wackup_key_init();
return RT_EOK;
}
INIT_BOARD_EXPORT(drv_pm_hw_init);
static int pwr_sample(int argc, char *argv[])
{
if (argc > 1)
{
if (!rt_strcmp(argv[1], "stop"))
{
rt_kprintf("system will enter stop mode! you can press USER2 button to exit this mode\n");
enter_stop_mode();
return RT_EOK;
}
else if (!rt_strcmp(argv[1], "sleep"))
{
rt_kprintf("system will enter sleep mode! lptim1 will wake up the system\n");
enter_sleep_mode();
return RT_EOK;
}
else
{
goto _exit;
}
}
_exit:
{
rt_kprintf("Usage:\n");
rt_kprintf("pwr_sample stop - system enter stop mode\n");
rt_kprintf("pwr_sample sleep - system enter sleep mode\n");
}
return -RT_ERROR;
}
MSH_CMD_EXPORT(pwr_sample, enter low power mode sample);