efm32_emu.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. /***************************************************************************//**
  2. * @file
  3. * @brief Energy management unit (EMU) peripheral module peripheral API
  4. * for EFM32.
  5. * @author Energy Micro AS
  6. * @version 1.3.0
  7. *******************************************************************************
  8. * @section License
  9. * <b>(C) Copyright 2010 Energy Micro AS, http://www.energymicro.com</b>
  10. *******************************************************************************
  11. *
  12. * This source code is the property of Energy Micro AS. The source and compiled
  13. * code may only be used on Energy Micro "EFM32" microcontrollers.
  14. *
  15. * This copyright notice may not be removed from the source code nor changed.
  16. *
  17. * DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Energy Micro AS has no
  18. * obligation to support this Software. Energy Micro AS is providing the
  19. * Software "AS IS", with no express or implied warranties of any kind,
  20. * including, but not limited to, any implied warranties of merchantability
  21. * or fitness for any particular purpose or warranties against infringement
  22. * of any proprietary rights of a third party.
  23. *
  24. * Energy Micro AS will not be liable for any consequential, incidental, or
  25. * special damages, or any other relief, or for any claim by any third party,
  26. * arising from your use of this Software.
  27. *
  28. ******************************************************************************/
  29. #include "efm32_emu.h"
  30. #include "efm32_cmu.h"
  31. #include "efm32_assert.h"
  32. /***************************************************************************//**
  33. * @addtogroup EFM32_Library
  34. * @{
  35. ******************************************************************************/
  36. /***************************************************************************//**
  37. * @addtogroup EMU
  38. * @brief EFM32 energy management unit utilities.
  39. * @{
  40. ******************************************************************************/
  41. /* Consistency check, since restoring assumes similar bitpositions in */
  42. /* CMU OSCENCMD and STATUS regs */
  43. #if (CMU_STATUS_AUXHFRCOENS != CMU_OSCENCMD_AUXHFRCOEN)
  44. #error Conflict in AUXHFRCOENS and AUXHFRCOEN bitpositions
  45. #endif
  46. #if (CMU_STATUS_HFXCOENS != CMU_OSCENCMD_HFXCOEN)
  47. #error Conflict in HFXOENS and HFXOEN bitpositions
  48. #endif
  49. #if (CMU_STATUS_LFRCOENS != CMU_OSCENCMD_LFRCOEN)
  50. #error Conflict in LFRCOENS and LFRCOEN bitpositions
  51. #endif
  52. #if (CMU_STATUS_LFXCOENS != CMU_OSCENCMD_LFXCOEN)
  53. #error Conflict in LFXOENS and LFXOEN bitpositions
  54. #endif
  55. /*******************************************************************************
  56. ************************** LOCAL VARIABLES ********************************
  57. ******************************************************************************/
  58. /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
  59. /**
  60. * CMU configured oscillator selection and oscillator enable status. When a
  61. * user configures oscillators, this varaiable shall shadow the configuration.
  62. * It is used by the EMU module in order to be able to restore the oscillator
  63. * config after having been in certain energy modes (since HW may automatically
  64. * alter config when going into an energy mode). It is the responsibility of
  65. * the CMU module to keep it up-to-date (or a user if not using the CMU API
  66. * for oscillator control).
  67. */
  68. static uint16_t cmuStatus;
  69. /** @endcond (DO_NOT_INCLUDE_WITH_DOXYGEN) */
  70. /*******************************************************************************
  71. ************************** LOCAL FUNCTIONS ********************************
  72. ******************************************************************************/
  73. /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
  74. /***************************************************************************//**
  75. * @brief
  76. * Restore oscillators and core clock after having been in EM2 or EM3.
  77. ******************************************************************************/
  78. static void EMU_Restore(void)
  79. {
  80. uint32_t cmuLocked;
  81. /* Although we could use the CMU API for most of the below handling, we */
  82. /* would like this function to be as efficient as possible. */
  83. /* CMU registers may be locked */
  84. cmuLocked = CMU->LOCK & CMU_LOCK_LOCKKEY_LOCKED;
  85. CMU_Unlock();
  86. /* AUXHFRCO was automatically disabled (except if using debugger). */
  87. /* HFXO was automatically disabled. */
  88. /* LFRCO/LFXO were possibly disabled by SW in EM3. */
  89. /* Restore according to status prior to entering EM. */
  90. CMU->OSCENCMD = cmuStatus & (CMU_STATUS_AUXHFRCOENS |
  91. CMU_STATUS_HFXOENS |
  92. CMU_STATUS_LFRCOENS |
  93. CMU_STATUS_LFXOENS);
  94. /* Restore oscillator used for clocking core */
  95. switch (cmuStatus & (CMU_STATUS_HFXOSEL | CMU_STATUS_HFRCOSEL |
  96. CMU_STATUS_LFXOSEL | CMU_STATUS_LFRCOSEL))
  97. {
  98. case CMU_STATUS_LFRCOSEL:
  99. /* Wait for LFRCO to stabilize */
  100. while (!(CMU->STATUS & CMU_STATUS_LFRCORDY)) ;
  101. CMU->CMD = CMU_CMD_HFCLKSEL_LFRCO;
  102. break;
  103. case CMU_STATUS_LFXOSEL:
  104. /* Wait for LFXO to stabilize */
  105. while (!(CMU->STATUS & CMU_STATUS_LFXORDY)) ;
  106. CMU->CMD = CMU_CMD_HFCLKSEL_LFXO;
  107. break;
  108. case CMU_STATUS_HFXOSEL:
  109. /* Wait for HFXO to stabilize */
  110. while (!(CMU->STATUS & CMU_STATUS_HFXORDY)) ;
  111. CMU->CMD = CMU_CMD_HFCLKSEL_HFXO;
  112. break;
  113. default: /* CMU_STATUS_HFRCOSEL */
  114. /* If core clock was HFRCO core clock, it is automatically restored to */
  115. /* state prior to entering energy mode. No need for further action. */
  116. break;
  117. }
  118. /* Restore CMU register locking */
  119. if (cmuLocked)
  120. {
  121. CMU_Lock();
  122. }
  123. }
  124. /** @endcond (DO_NOT_INCLUDE_WITH_DOXYGEN) */
  125. /*******************************************************************************
  126. ************************** GLOBAL FUNCTIONS *******************************
  127. ******************************************************************************/
  128. /***************************************************************************//**
  129. * @brief
  130. * Enter energy mode 2 (EM2).
  131. *
  132. * @details
  133. * When entering EM2, the high frequency clocks are disabled, ie HFXO, HFRCO
  134. * and AUXHFRCO (for AUXHFRCO, see exception note below). When re-entering
  135. * EM0, HFRCO is re-enabled and the core will be clocked by the configured
  136. * HFRCO band. This ensures a quick wakeup from EM2.
  137. *
  138. * However, prior to entering EM2, the core may have been using another
  139. * oscillator than HFRCO. The @p restore parameter gives the user the option
  140. * to restore all HF oscillators according to state prior to entering EM2,
  141. * as well as the clock used to clock the core. This restore procedure is
  142. * handled by SW. However, since handled by SW, it will not be restored
  143. * before completing the interrupt function(s) waking up the core!
  144. *
  145. * @note
  146. * If restoring core clock to use the HFXO oscillator, which has been
  147. * disabled during EM2 mode, this function will stall until the oscillator
  148. * has stabilized. Stalling time can be reduced by adding interrupt
  149. * support detecting stable oscillator, and an asynchronous switch to the
  150. * original oscillator. See CMU documentation. Such a feature is however
  151. * outside the scope of the implementation in this function.
  152. * @par
  153. * If HFXO is re-enabled by this function, and NOT used to clock the core,
  154. * this function will not wait for HFXO to stabilize. This must be considered
  155. * by the application if trying to use features relying on that oscillator
  156. * upon return.
  157. * @par
  158. * If a debugger is attached, the AUXHFRCO will not be disabled if enabled
  159. * upon entering EM2. It will thus remain enabled when returning to EM0
  160. * regardless of the @p restore parameter.
  161. *
  162. * @param[in] restore
  163. * @li true - restore oscillators and clocks, see function details.
  164. * @li false - do not restore oscillators and clocks, see function details.
  165. * @par
  166. * The @p restore option should only be used if all clock control is done
  167. * via the CMU API.
  168. ******************************************************************************/
  169. void EMU_EnterEM2(bool restore)
  170. {
  171. /* Auto-update CMU status just in case before entering energy mode. */
  172. /* This variable is normally kept up-to-date by the CMU API. */
  173. cmuStatus = (uint16_t)(CMU->STATUS);
  174. /* Enter Cortex-M3 deep sleep mode */
  175. SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
  176. __WFI();
  177. /* Restore oscillators/clocks if specified */
  178. if (restore)
  179. {
  180. EMU_Restore();
  181. }
  182. /* If not restoring, and original clock was not HFRCO, we have to */
  183. /* update CMSIS core clock variable since core clock has changed */
  184. /* to using HFRCO. */
  185. else if (!(cmuStatus & CMU_STATUS_HFRCOSEL))
  186. {
  187. SystemCoreClockUpdate();
  188. }
  189. }
  190. /***************************************************************************//**
  191. * @brief
  192. * Enter energy mode 3 (EM3).
  193. *
  194. * @details
  195. * When entering EM3, the high frequency clocks are disabled by HW, ie HFXO,
  196. * HFRCO and AUXHFRCO (for AUXHFRCO, see exception note below). In addition,
  197. * the low frequency clocks, ie LFXO and LFRCO are disabled by SW. When
  198. * re-entering EM0, HFRCO is re-enabled and the core will be clocked by the
  199. * configured HFRCO band. This ensures a quick wakeup from EM3.
  200. *
  201. * However, prior to entering EM3, the core may have been using another
  202. * oscillator than HFRCO. The @p restore parameter gives the user the option
  203. * to restore all HF/LF oscillators according to state prior to entering EM3,
  204. * as well as the clock used to clock the core. This restore procedure is
  205. * handled by SW. However, since handled by SW, it will not be restored
  206. * before completing the interrupt function(s) waking up the core!
  207. *
  208. * @note
  209. * If restoring core clock to use an oscillator other than HFRCO, this
  210. * function will stall until the oscillator has stabilized. Stalling time
  211. * can be reduced by adding interrupt support detecting stable oscillator,
  212. * and an asynchronous switch to the original oscillator. See CMU
  213. * documentation. Such a feature is however outside the scope of the
  214. * implementation in this function.
  215. * @par
  216. * If HFXO/LFXO/LFRCO are re-enabled by this function, and NOT used to clock
  217. * the core, this function will not wait for those oscillators to stabilize.
  218. * This must be considered by the application if trying to use features
  219. * relying on those oscillators upon return.
  220. * @par
  221. * If a debugger is attached, the AUXHFRCO will not be disabled if enabled
  222. * upon entering EM3. It will thus remain enabled when returning to EM0
  223. * regardless of the @p restore parameter.
  224. *
  225. * @param[in] restore
  226. * @li true - restore oscillators and clocks, see function details.
  227. * @li false - do not restore oscillators and clocks, see function details.
  228. * @par
  229. * The @p restore option should only be used if all clock control is done
  230. * via the CMU API.
  231. ******************************************************************************/
  232. void EMU_EnterEM3(bool restore)
  233. {
  234. uint32_t cmuLocked;
  235. /* Auto-update CMU status just in case before entering energy mode. */
  236. /* This variable is normally kept up-to-date by the CMU API. */
  237. cmuStatus = (uint16_t)(CMU->STATUS);
  238. /* CMU registers may be locked */
  239. cmuLocked = CMU->LOCK & CMU_LOCK_LOCKKEY_LOCKED;
  240. CMU_Unlock();
  241. /* Disable LF oscillators */
  242. CMU->OSCENCMD = CMU_OSCENCMD_LFXODIS | CMU_OSCENCMD_LFRCODIS;
  243. /* Restore CMU register locking */
  244. if (cmuLocked)
  245. {
  246. CMU_Lock();
  247. }
  248. /* Enter Cortex-M3 deep sleep mode */
  249. SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
  250. __WFI();
  251. /* Restore oscillators/clocks if specified */
  252. if (restore)
  253. {
  254. EMU_Restore();
  255. }
  256. /* If not restoring, and original clock was not HFRCO, we have to */
  257. /* update CMSIS core clock variable since core clock has changed */
  258. /* to using HFRCO. */
  259. else if (!(cmuStatus & CMU_STATUS_HFRCOSEL))
  260. {
  261. SystemCoreClockUpdate();
  262. }
  263. }
  264. /***************************************************************************//**
  265. * @brief
  266. * Enter energy mode 4 (EM4).
  267. *
  268. * @note
  269. * Only a power on reset or external reset pin can wake the device from EM4.
  270. ******************************************************************************/
  271. void EMU_EnterEM4(void)
  272. {
  273. int i;
  274. /* Make sure register write lock is disabled */
  275. EMU->LOCK = EMU_LOCK_LOCKKEY_UNLOCK;
  276. for (i = 0; i < 4; i++)
  277. {
  278. EMU->CTRL = (2 << _EMU_CTRL_EM4CTRL_SHIFT);
  279. EMU->CTRL = (3 << _EMU_CTRL_EM4CTRL_SHIFT);
  280. }
  281. EMU->CTRL = (2 << _EMU_CTRL_EM4CTRL_SHIFT);
  282. }
  283. /***************************************************************************//**
  284. * @brief
  285. * Power down memory block.
  286. *
  287. * @param[in] blocks
  288. * Specifies a logical OR of bits indicating memory blocks to power down.
  289. * Bit 0 selects block 1, bit 1 selects block 2, etc. Memory block 0 cannot
  290. * be disabled. Please refer to the EFM32 reference manual for available
  291. * memory blocks for a device.
  292. *
  293. * @note
  294. * Only a reset can make the specified memory block(s) available for use
  295. * after having been powered down. Function will be void for devices not
  296. * supporting this feature.
  297. ******************************************************************************/
  298. void EMU_MemPwrDown(uint32_t blocks)
  299. {
  300. #if defined( _EMU_MEMCTRL_RESETVALUE )
  301. EFM_ASSERT(blocks <= _EMU_MEMCTRL_MASK);
  302. EMU->MEMCTRL = blocks;
  303. #else
  304. (void) blocks;
  305. #endif
  306. }
  307. /***************************************************************************//**
  308. * @brief
  309. * Update EMU module with CMU oscillator selection/enable status.
  310. *
  311. * @details
  312. * When entering EM2 and EM3, the HW may change the core clock oscillator
  313. * used, as well as disabling some oscillators. The user may optionally select
  314. * to restore the oscillators after waking up from EM2 and EM3 through the
  315. * SW API.
  316. *
  317. * However, in order to support this in a safe way, the EMU module must
  318. * be kept up-to-date on the actual selected configuration. The CMU
  319. * module must keep the EMU module up-to-date.
  320. *
  321. * This function is mainly intended for internal use by the CMU module,
  322. * but if the applications changes oscillator configurations without
  323. * using the CMU API, this function can be used to keep the EMU module
  324. * up-to-date.
  325. ******************************************************************************/
  326. void EMU_UpdateOscConfig(void)
  327. {
  328. /* Fetch current configuration */
  329. cmuStatus = (uint16_t)(CMU->STATUS);
  330. }
  331. /** @} (end addtogroup EMU) */
  332. /** @} (end addtogroup EFM32_Library) */