drv_pm.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. /*
  2. * Copyright (c) 2006-2024 RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2019-05-06 Zero-Free first version
  9. * 2024-07-04 wdfk-prog lptimer is supported
  10. */
  11. #include <board.h>
  12. #include <drv_lptim.h>
  13. #include <rtdevice.h>
  14. /*#define DRV_DEBUG*/
  15. #define LOG_TAG "drv.pm"
  16. #include <drv_log.h>
  17. #ifdef RT_USING_PM
  18. #ifndef BSP_USING_PM_TIMER
  19. /*
  20. ! Using LPTIM timer, the maximum sleep time is 65535, less than 1 min. Use RTC alarm timers for longer periods.
  21. ! For example: packages can be used :https://packages.rt-thread.org/detail.html?package=multi_rtimer
  22. */
  23. #ifdef BSP_USING_LPTIM1
  24. #define BSP_USING_PM_TIMER "lptim1"
  25. #elif BSP_USING_LPTIM2
  26. #define BSP_USING_PM_TIMER "lptim2"
  27. #elif BSP_USING_LPTIM3
  28. #define BSP_USING_PM_TIMER "lptim3"
  29. #else
  30. #error "Please define BSP_USING_PM_TIMER"
  31. #endif
  32. static rt_device_t timer = RT_NULL;
  33. /* Re-configure the system clock */
  34. rt_weak void SystemClock_ReConfig(uint8_t run_mode)
  35. {
  36. /*todo add your code here*/
  37. }
  38. rt_weak void stm32_pm_device_run(struct rt_pm *pm, uint8_t mode)
  39. {
  40. /*todo add your code here*/
  41. }
  42. /**
  43. * This function will put STM32L4xx into sleep mode.
  44. *
  45. * @param pm pointer to power manage structure
  46. */
  47. static void sleep(struct rt_pm *pm, uint8_t mode)
  48. {
  49. switch (mode)
  50. {
  51. case PM_SLEEP_MODE_NONE:
  52. break;
  53. case PM_SLEEP_MODE_IDLE:
  54. break;
  55. case PM_SLEEP_MODE_LIGHT:
  56. if (pm->run_mode == PM_RUN_MODE_LOW_SPEED)
  57. {
  58. /* Enter LP SLEEP Mode, Enable low-power regulator */
  59. HAL_PWR_EnterSLEEPMode(PWR_LOWPOWERREGULATOR_ON, PWR_SLEEPENTRY_WFI);
  60. }
  61. else
  62. {
  63. /* Enter SLEEP Mode, Main regulator is ON */
  64. HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI);
  65. }
  66. break;
  67. case PM_SLEEP_MODE_DEEP:
  68. #if defined(SOC_SERIES_STM32L4)
  69. /* Enter STOP 2 mode */
  70. HAL_PWREx_EnterSTOP2Mode(PWR_STOPENTRY_WFI);
  71. /* Re-configure the system clock */
  72. SystemClock_ReConfig(pm->run_mode);
  73. #endif /* defined(SOC_SERIES_STM32L4) */
  74. break;
  75. case PM_SLEEP_MODE_STANDBY:
  76. /* Enter STANDBY mode */
  77. HAL_PWR_EnterSTANDBYMode();
  78. break;
  79. case PM_SLEEP_MODE_SHUTDOWN:
  80. #if defined(SOC_SERIES_STM32L4)
  81. /* Enter SHUTDOWNN mode */
  82. HAL_PWREx_EnterSHUTDOWNMode();
  83. #endif /* defined(SOC_SERIES_STM32L4) */
  84. break;
  85. default:
  86. break;
  87. }
  88. }
  89. /**
  90. * This function caculate the PM tick from OS tick
  91. *
  92. * @param tick OS tick
  93. *
  94. * @return the PM tick
  95. */
  96. static rt_tick_t stm32_pm_tick_from_os_tick(rt_tick_t tick)
  97. {
  98. rt_uint32_t freq = 0;
  99. rt_err_t ret = rt_device_control(timer, DRV_HW_LPTIMER_CTRL_GET_FREQ, &freq);
  100. if(ret != RT_EOK)
  101. {
  102. LOG_E("Get PM timer %s frequency failed %d", timer->parent.name, ret);
  103. return 0;
  104. }
  105. else
  106. {
  107. LOG_D("Get PM timer %s frequency %d", timer->parent.name, freq);
  108. }
  109. return (freq * tick / RT_TICK_PER_SECOND);
  110. }
  111. /**
  112. * This function caculate the OS tick from PM tick
  113. *
  114. * @param tick PM tick
  115. *
  116. * @return the OS tick
  117. */
  118. static rt_tick_t stm32_os_tick_from_pm_tick(rt_uint32_t tick)
  119. {
  120. static rt_uint32_t os_tick_remain = 0;
  121. rt_tick_t os_tick = 0;
  122. rt_uint32_t freq = 0;
  123. rt_err_t ret = rt_device_control(timer, DRV_HW_LPTIMER_CTRL_GET_FREQ, &freq);
  124. if(ret != RT_EOK)
  125. {
  126. LOG_E("Get PM timer %s frequency failed %d", timer->parent.name, ret);
  127. return 0;
  128. }
  129. os_tick = (tick * RT_TICK_PER_SECOND + os_tick_remain) / freq;
  130. os_tick_remain += (tick * RT_TICK_PER_SECOND);
  131. os_tick_remain %= freq;
  132. return os_tick;
  133. }
  134. /**
  135. * This function start the timer of pm
  136. *
  137. * @param pm Pointer to power manage structure
  138. * @param timeout How many OS Ticks that MCU can sleep
  139. */
  140. static void pm_timer_start(struct rt_pm *pm, rt_uint32_t timeout)
  141. {
  142. RT_ASSERT(pm != RT_NULL);
  143. RT_ASSERT(timeout > 0);
  144. RT_ASSERT(timer != RT_NULL);
  145. if (timeout != RT_TICK_MAX)
  146. {
  147. rt_uint32_t max_tick = 0;
  148. rt_err_t ret = rt_device_control(timer, DRV_HW_LPTIMER_CTRL_GET_TICK_MAX, &max_tick);
  149. if(ret != RT_EOK)
  150. {
  151. LOG_E("Get PM timer %s max tick failed %d", timer->parent.name, ret);
  152. return;
  153. }
  154. /* Convert OS Tick to pmtimer timeout value */
  155. timeout = stm32_pm_tick_from_os_tick(timeout);
  156. if (timeout > max_tick)
  157. {
  158. timeout = max_tick;
  159. }
  160. /* Enter PM_TIMER_MODE */
  161. ret = rt_device_control(timer, DRV_HW_LPTIMER_CTRL_START, &timeout);
  162. if(ret != RT_EOK)
  163. {
  164. LOG_E("Get PM timer %s max tick failed %d", timer->parent.name, ret);
  165. return;
  166. }
  167. }
  168. }
  169. /**
  170. * This function stop the timer of pm
  171. *
  172. * @param pm Pointer to power manage structure
  173. */
  174. static void pm_timer_stop(struct rt_pm *pm)
  175. {
  176. RT_ASSERT(pm != RT_NULL);
  177. /* Reset pmtimer status */
  178. rt_device_control(timer, HWTIMER_CTRL_STOP, RT_NULL);
  179. }
  180. /**
  181. * This function calculate how many OS Ticks that MCU have suspended
  182. *
  183. * @param pm Pointer to power manage structure
  184. *
  185. * @return OS Ticks
  186. */
  187. static rt_tick_t pm_timer_get_tick(struct rt_pm *pm)
  188. {
  189. rt_uint32_t timer_tick;
  190. RT_ASSERT(pm != RT_NULL);
  191. rt_err_t ret = rt_device_control(timer, DRV_HW_LPTIMER_CTRL_GET_COUNT, &timer_tick);
  192. if(ret != RT_EOK)
  193. {
  194. LOG_E("Get PM timer %s count failed %d", timer->parent.name, ret);
  195. return 0;
  196. }
  197. else
  198. {
  199. return stm32_os_tick_from_pm_tick(timer_tick);
  200. }
  201. }
  202. static const struct rt_pm_ops _ops =
  203. {
  204. sleep,
  205. stm32_pm_device_run,
  206. pm_timer_start,
  207. pm_timer_stop,
  208. pm_timer_get_tick
  209. };
  210. /**
  211. * This function initialize the power manager
  212. */
  213. int drv_pm_hw_init(void)
  214. {
  215. rt_uint8_t timer_mask = 0;
  216. /* Enable Power Clock */
  217. #if !defined(SOC_SERIES_STM32H7) && !defined(SOC_SERIES_STM32WL) && !defined(SOC_SERIES_STM32WB)
  218. __HAL_RCC_PWR_CLK_ENABLE();
  219. #ifdef SOC_SERIES_STM32F1
  220. __HAL_RCC_BKP_CLK_ENABLE();
  221. #endif
  222. #endif
  223. /* initialize timer mask */
  224. timer_mask = 1UL << PM_SLEEP_MODE_DEEP;
  225. /* initialize system pm module */
  226. rt_system_pm_init(&_ops, timer_mask, RT_NULL);
  227. timer = rt_device_find(BSP_USING_PM_TIMER);
  228. if(timer == RT_NULL)
  229. {
  230. LOG_E("Can't find PM timer device");
  231. return -RT_ERROR;
  232. }
  233. else
  234. {
  235. return rt_device_init(timer);
  236. }
  237. }
  238. INIT_CORE_EXPORT(drv_pm_hw_init);
  239. #endif /* RT_USING_PM */