From 8880e751f216a0b852bc3cfe132f84df59ab752d Mon Sep 17 00:00:00 2001 From: thread-liu Date: Sat, 5 Dec 2020 11:53:22 +0800 Subject: [PATCH] [add] low power and lptim driver. --- .../CM4/Src/stm32mp1xx_hal_msp.c | 2 +- bsp/stm32/stm32mp157a-st-ev1/board/Kconfig | 16 ++ bsp/stm32/stm32mp157a-st-ev1/board/SConscript | 6 + .../board/ports/drv_lptim.c | 163 ++++++++++++++ .../stm32mp157a-st-ev1/board/ports/drv_pwr.c | 202 ++++++++++++++++++ 5 files changed, 388 insertions(+), 1 deletion(-) create mode 100644 bsp/stm32/stm32mp157a-st-ev1/board/ports/drv_lptim.c create mode 100644 bsp/stm32/stm32mp157a-st-ev1/board/ports/drv_pwr.c diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/CubeMX_Config/CM4/Src/stm32mp1xx_hal_msp.c b/bsp/stm32/stm32mp157a-st-ev1/board/CubeMX_Config/CM4/Src/stm32mp1xx_hal_msp.c index 1958e2e516..739e195f39 100644 --- a/bsp/stm32/stm32mp157a-st-ev1/board/CubeMX_Config/CM4/Src/stm32mp1xx_hal_msp.c +++ b/bsp/stm32/stm32mp157a-st-ev1/board/CubeMX_Config/CM4/Src/stm32mp1xx_hal_msp.c @@ -297,7 +297,7 @@ void HAL_LPTIM_MspInit(LPTIM_HandleTypeDef* hlptim) /** Initializes the peripherals clock */ PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_LPTIM1; - PeriphClkInit.Lptim1ClockSelection = RCC_LPTIM1CLKSOURCE_PCLK1; + PeriphClkInit.Lptim1ClockSelection = RCC_LPTIM1CLKSOURCE_LSE; if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) { Error_Handler(); diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/Kconfig b/bsp/stm32/stm32mp157a-st-ev1/board/Kconfig index e276e98a08..971107f30e 100644 --- a/bsp/stm32/stm32mp157a-st-ev1/board/Kconfig +++ b/bsp/stm32/stm32mp157a-st-ev1/board/Kconfig @@ -25,6 +25,12 @@ menu "Onboard Peripheral Drivers" select BSP_USING_I2C3 default y + config BSP_USING_PWR + bool "Enable PM (power control)" + select BSP_USING_LPTIM + select BSP_USING_LPTIM1 + default n + config BSP_USING_NAND bool "Enable FMC (MT29F8G08ABACAH4)" select RT_USING_FMC @@ -181,6 +187,16 @@ menu "On-chip Peripheral Drivers" default n endif + menuconfig BSP_USING_LPTIM + bool "Enable lptimer" + default n + select RT_USING_LPTIMER + if BSP_USING_LPTIM + config BSP_USING_LPTIM1 + bool "Enable LPTIM1" + default n + endif + menuconfig BSP_USING_PWM bool "Enable pwm" default n diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/SConscript b/bsp/stm32/stm32mp157a-st-ev1/board/SConscript index 0fc2c5a919..b3fd565887 100644 --- a/bsp/stm32/stm32mp157a-st-ev1/board/SConscript +++ b/bsp/stm32/stm32mp157a-st-ev1/board/SConscript @@ -64,6 +64,12 @@ if GetDepend(['BSP_USING_EXTI']): if GetDepend(['BSP_USING_RNG']) or GetDepend(['BSP_USING_HASH']) or GetDepend(['BSP_USING_CRC']) or GetDepend(['BSP_USING_CRYP']): src += Glob('ports/crypto_sample.c') +if GetDepend(['BSP_USING_PWR']): + src += Glob('ports/drv_pwr.c') + +if GetDepend(['BSP_USING_LPTIM1']): + src += Glob('ports/drv_lptim.c') + if GetDepend(['BSP_USING_OPENAMP']): src += Glob('CubeMX_Config/CM4/Src/ipcc.c') src += Glob('CubeMX_Config/CM4/Src/openamp.c') diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/drv_lptim.c b/bsp/stm32/stm32mp157a-st-ev1/board/ports/drv_lptim.c new file mode 100644 index 0000000000..195345c19d --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/drv_lptim.c @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2006-2018, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2020-06-19 thread-liu first version + */ + +#include + +#ifdef BSP_USING_LPTIM +#include "drv_config.h" +#include +#include + +//#define DRV_DEBUG +#define LOG_TAG "drv.lptimer" +#include + +#define LED5_PIN GET_PIN(D, 9) +LPTIM_HandleTypeDef hlptim1; + +extern int lptim_stop(void); + +void LPTIM1_IRQHandler(void) +{ + /* enter interrupt */ + rt_interrupt_enter(); + + HAL_LPTIM_IRQHandler(&hlptim1); + + /* leave interrupt */ + rt_interrupt_leave(); +} + +void HAL_LPTIM_AutoReloadMatchCallback(LPTIM_HandleTypeDef *hlptim) +{ + if(hlptim->Instance == LPTIM1) + { + HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_9); + } + +#if defined(BSP_USING_PWR) + /* All level of ITs can interrupt */ + __set_BASEPRI(0U); + + lptim_stop(); + rt_kprintf("system returns to normal!\n"); +#endif +} + +static int lptim_control(uint8_t pre_value) +{ + if(pre_value > 7) + { + pre_value = 7; + } + hlptim1.Instance->CFGR &= ~(7 << 9); /* clear PRESC[2:0] */ + hlptim1.Instance->CFGR |= pre_value << 9; /* set PRESC[2:0] */ + rt_kprintf("set lptim pre value [0x%x] success!\n", pre_value); + + return RT_EOK; +} + +int lptim_start(void) +{ + /* ### Start counting in interrupt mode ############################# */ + if (HAL_LPTIM_Counter_Start_IT(&hlptim1, 32767) != HAL_OK) + { + LOG_D("lptim1 start counting failed!\n"); + return -RT_ERROR; + } + + LOG_D("lptim1 start counting success!\n"); + + return RT_EOK; +} + +int lptim_stop(void) +{ + if (HAL_LPTIM_Counter_Stop_IT(&hlptim1) != HAL_OK) + { + LOG_D("lptim1 stop failed!\n"); + return -RT_ERROR; + } + + LOG_D("lptim1 stop counting success!\n"); + + return RT_EOK; +} + +int lptim_init(void) +{ + rt_pin_mode(LED5_PIN, PIN_MODE_OUTPUT); + + hlptim1.Instance = LPTIM1; + hlptim1.Init.Clock.Source = LPTIM_CLOCKSOURCE_APBCLOCK_LPOSC; + hlptim1.Init.Clock.Prescaler = LPTIM_PRESCALER_DIV8; + hlptim1.Init.UltraLowPowerClock.Polarity = LPTIM_CLOCKPOLARITY_RISING; + hlptim1.Init.UltraLowPowerClock.SampleTime = LPTIM_CLOCKSAMPLETIME_DIRECTTRANSITION; + hlptim1.Init.Trigger.Source = LPTIM_TRIGSOURCE_SOFTWARE; + hlptim1.Init.OutputPolarity = LPTIM_OUTPUTPOLARITY_HIGH; + hlptim1.Init.UpdateMode = LPTIM_UPDATE_IMMEDIATE; + hlptim1.Init.CounterSource = LPTIM_COUNTERSOURCE_INTERNAL; + hlptim1.Init.Input1Source = LPTIM_INPUT1SOURCE_GPIO; + hlptim1.Init.Input2Source = LPTIM_INPUT2SOURCE_GPIO; + if (HAL_LPTIM_Init(&hlptim1) != HAL_OK) + { + LOG_D("lptim init failed!\n"); + return -RT_ERROR; + } + LOG_D("lptim init success!\n"); + + return RT_EOK; +} +INIT_DEVICE_EXPORT(lptim_init); + +static int lptim_sample(int argc, char *argv[]) +{ + if (argc > 1) + { + if (!strcmp(argv[1], "start")) + { + lptim_start(); + return RT_EOK; + } + else if (!strcmp(argv[1], "stop")) + { + lptim_stop(); + return RT_EOK; + } + else if (!strcmp(argv[1], "set")) + { + if (argc > 2) + { + lptim_control(atoi(argv[2])); + return RT_EOK; + } + else + { + goto _exit; + } + } + else + { + goto _exit; + } + } +_exit: + { + rt_kprintf("Usage:\n"); + rt_kprintf("lptim_sample start - start lptim, the LED5 will start blink\n"); + rt_kprintf("lptim_sample stop - stop lptim, the LED5 will stop blink\n"); + rt_kprintf("lptim_sample set - set the lptim prescaler to change LED5 blink frquency, lptim_sample set [0 - 7]\n"); + } + + return -RT_ERROR; +} +MSH_CMD_EXPORT(lptim_sample, low power timer sample); + +#endif diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/drv_pwr.c b/bsp/stm32/stm32mp157a-st-ev1/board/ports/drv_pwr.c new file mode 100644 index 0000000000..3aac57603d --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/drv_pwr.c @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2006-2022, 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 + +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); -- GitLab