pybsleep.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656
  1. /*
  2. * This file is part of the MicroPython project, http://micropython.org/
  3. *
  4. * The MIT License (MIT)
  5. *
  6. * Copyright (c) 2015 Daniel Campora
  7. *
  8. * Permission is hereby granted, free of charge, to any person obtaining a copy
  9. * of this software and associated documentation files (the "Software"), to deal
  10. * in the Software without restriction, including without limitation the rights
  11. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  12. * copies of the Software, and to permit persons to whom the Software is
  13. * furnished to do so, subject to the following conditions:
  14. *
  15. * The above copyright notice and this permission notice shall be included in
  16. * all copies or substantial portions of the Software.
  17. *
  18. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  21. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  24. * THE SOFTWARE.
  25. */
  26. #include <stdint.h>
  27. #include <string.h>
  28. #include "py/runtime.h"
  29. #include "py/mphal.h"
  30. #include "inc/hw_types.h"
  31. #include "inc/hw_ints.h"
  32. #include "inc/hw_nvic.h"
  33. #include "inc/hw_common_reg.h"
  34. #include "inc/hw_memmap.h"
  35. #include "cc3200_asm.h"
  36. #include "rom_map.h"
  37. #include "interrupt.h"
  38. #include "systick.h"
  39. #include "prcm.h"
  40. #include "spi.h"
  41. #include "pin.h"
  42. #include "pybsleep.h"
  43. #include "mpirq.h"
  44. #include "pybpin.h"
  45. #include "simplelink.h"
  46. #include "modnetwork.h"
  47. #include "modwlan.h"
  48. #include "osi.h"
  49. #include "debug.h"
  50. #include "mpexception.h"
  51. #include "mperror.h"
  52. #include "sleeprestore.h"
  53. #include "serverstask.h"
  54. #include "antenna.h"
  55. #include "cryptohash.h"
  56. #include "pybrtc.h"
  57. /******************************************************************************
  58. DECLARE PRIVATE CONSTANTS
  59. ******************************************************************************/
  60. #define SPIFLASH_INSTR_READ_STATUS (0x05)
  61. #define SPIFLASH_INSTR_DEEP_POWER_DOWN (0xB9)
  62. #define SPIFLASH_STATUS_BUSY (0x01)
  63. #define LPDS_UP_TIME (425) // 13 msec
  64. #define LPDS_DOWN_TIME (98) // 3 msec
  65. #define USER_OFFSET (131) // 4 smec
  66. #define WAKEUP_TIME_LPDS (LPDS_UP_TIME + LPDS_DOWN_TIME + USER_OFFSET) // 20 msec
  67. #define WAKEUP_TIME_HIB (32768) // 1 s
  68. #define FORCED_TIMER_INTERRUPT_MS (PYB_RTC_MIN_ALARM_TIME_MS)
  69. #define FAILED_SLEEP_DELAY_MS (FORCED_TIMER_INTERRUPT_MS * 3)
  70. /******************************************************************************
  71. DECLARE PRIVATE TYPES
  72. ******************************************************************************/
  73. // storage memory for Cortex M4 registers
  74. typedef struct {
  75. uint32_t msp;
  76. uint32_t psp;
  77. uint32_t psr;
  78. uint32_t primask;
  79. uint32_t faultmask;
  80. uint32_t basepri;
  81. uint32_t control;
  82. } arm_cm4_core_regs_t;
  83. // storage memory for the NVIC registers
  84. typedef struct {
  85. uint32_t vector_table; // Vector Table Offset
  86. uint32_t aux_ctrl; // Auxiliary control register
  87. uint32_t int_ctrl_state; // Interrupt Control and State
  88. uint32_t app_int; // Application Interrupt Reset control
  89. uint32_t sys_ctrl; // System control
  90. uint32_t config_ctrl; // Configuration control
  91. uint32_t sys_pri_1; // System Handler Priority 1
  92. uint32_t sys_pri_2; // System Handler Priority 2
  93. uint32_t sys_pri_3; // System Handler Priority 3
  94. uint32_t sys_hcrs; // System Handler control and state register
  95. uint32_t systick_ctrl; // SysTick Control Status
  96. uint32_t systick_reload; // SysTick Reload
  97. uint32_t systick_calib; // SysTick Calibration
  98. uint32_t int_en[6]; // Interrupt set enable
  99. uint32_t int_priority[49]; // Interrupt priority
  100. } nvic_reg_store_t;
  101. typedef struct {
  102. mp_obj_base_t base;
  103. mp_obj_t obj;
  104. WakeUpCB_t wakeup;
  105. } pyb_sleep_obj_t;
  106. typedef struct {
  107. mp_obj_t gpio_lpds_wake_cb;
  108. wlan_obj_t *wlan_obj;
  109. pyb_rtc_obj_t *rtc_obj;
  110. } pybsleep_data_t;
  111. /******************************************************************************
  112. DECLARE PRIVATE DATA
  113. ******************************************************************************/
  114. STATIC nvic_reg_store_t *nvic_reg_store;
  115. STATIC pybsleep_data_t pybsleep_data = {NULL, NULL, NULL};
  116. volatile arm_cm4_core_regs_t vault_arm_registers;
  117. STATIC pybsleep_reset_cause_t pybsleep_reset_cause = PYB_SLP_PWRON_RESET;
  118. STATIC pybsleep_wake_reason_t pybsleep_wake_reason = PYB_SLP_WAKED_PWRON;
  119. STATIC const mp_obj_type_t pyb_sleep_type = {
  120. { &mp_type_type },
  121. .name = MP_QSTR_sleep,
  122. };
  123. /******************************************************************************
  124. DECLARE PRIVATE FUNCTIONS
  125. ******************************************************************************/
  126. STATIC pyb_sleep_obj_t *pyb_sleep_find (mp_obj_t obj);
  127. STATIC void pyb_sleep_flash_powerdown (void);
  128. STATIC NORETURN void pyb_sleep_suspend_enter (void);
  129. void pyb_sleep_suspend_exit (void);
  130. STATIC void pyb_sleep_obj_wakeup (void);
  131. STATIC void PRCMInterruptHandler (void);
  132. STATIC void pyb_sleep_iopark (bool hibernate);
  133. STATIC bool setup_timer_lpds_wake (void);
  134. STATIC bool setup_timer_hibernate_wake (void);
  135. /******************************************************************************
  136. DEFINE PUBLIC FUNCTIONS
  137. ******************************************************************************/
  138. __attribute__ ((section (".boot")))
  139. void pyb_sleep_pre_init (void) {
  140. // allocate memory for nvic registers vault
  141. ASSERT ((nvic_reg_store = mem_Malloc(sizeof(nvic_reg_store_t))) != NULL);
  142. }
  143. void pyb_sleep_init0 (void) {
  144. // initialize the sleep objects list
  145. mp_obj_list_init(&MP_STATE_PORT(pyb_sleep_obj_list), 0);
  146. // register and enable the PRCM interrupt
  147. osi_InterruptRegister(INT_PRCM, (P_OSI_INTR_ENTRY)PRCMInterruptHandler, INT_PRIORITY_LVL_1);
  148. // disable all LPDS and hibernate wake up sources (WLAN is disabed/enabled before entering LDPS mode)
  149. MAP_PRCMLPDSWakeupSourceDisable(PRCM_LPDS_GPIO);
  150. MAP_PRCMLPDSWakeupSourceDisable(PRCM_LPDS_TIMER);
  151. MAP_PRCMHibernateWakeupSourceDisable(PRCM_HIB_SLOW_CLK_CTR | PRCM_HIB_GPIO2 | PRCM_HIB_GPIO4 | PRCM_HIB_GPIO13 |
  152. PRCM_HIB_GPIO17 | PRCM_HIB_GPIO11 | PRCM_HIB_GPIO24 | PRCM_HIB_GPIO26);
  153. // check the reset casue (if it's soft reset, leave it as it is)
  154. if (pybsleep_reset_cause != PYB_SLP_SOFT_RESET) {
  155. switch (MAP_PRCMSysResetCauseGet()) {
  156. case PRCM_POWER_ON:
  157. pybsleep_reset_cause = PYB_SLP_PWRON_RESET;
  158. break;
  159. case PRCM_CORE_RESET:
  160. case PRCM_MCU_RESET:
  161. case PRCM_SOC_RESET:
  162. pybsleep_reset_cause = PYB_SLP_HARD_RESET;
  163. break;
  164. case PRCM_WDT_RESET:
  165. pybsleep_reset_cause = PYB_SLP_WDT_RESET;
  166. break;
  167. case PRCM_HIB_EXIT:
  168. if (PRCMGetSpecialBit(PRCM_WDT_RESET_BIT)) {
  169. pybsleep_reset_cause = PYB_SLP_WDT_RESET;
  170. }
  171. else {
  172. pybsleep_reset_cause = PYB_SLP_HIB_RESET;
  173. // set the correct wake reason
  174. switch (MAP_PRCMHibernateWakeupCauseGet()) {
  175. case PRCM_HIB_WAKEUP_CAUSE_SLOW_CLOCK:
  176. pybsleep_wake_reason = PYB_SLP_WAKED_BY_RTC;
  177. // TODO repeat the alarm
  178. break;
  179. case PRCM_HIB_WAKEUP_CAUSE_GPIO:
  180. pybsleep_wake_reason = PYB_SLP_WAKED_BY_GPIO;
  181. break;
  182. default:
  183. break;
  184. }
  185. }
  186. break;
  187. default:
  188. break;
  189. }
  190. }
  191. }
  192. void pyb_sleep_signal_soft_reset (void) {
  193. pybsleep_reset_cause = PYB_SLP_SOFT_RESET;
  194. }
  195. void pyb_sleep_add (const mp_obj_t obj, WakeUpCB_t wakeup) {
  196. pyb_sleep_obj_t *sleep_obj = m_new_obj(pyb_sleep_obj_t);
  197. sleep_obj->base.type = &pyb_sleep_type;
  198. sleep_obj->obj = obj;
  199. sleep_obj->wakeup = wakeup;
  200. // remove it in case it was already registered
  201. pyb_sleep_remove (obj);
  202. mp_obj_list_append(&MP_STATE_PORT(pyb_sleep_obj_list), sleep_obj);
  203. }
  204. void pyb_sleep_remove (const mp_obj_t obj) {
  205. pyb_sleep_obj_t *sleep_obj;
  206. if ((sleep_obj = pyb_sleep_find(obj))) {
  207. mp_obj_list_remove(&MP_STATE_PORT(pyb_sleep_obj_list), sleep_obj);
  208. }
  209. }
  210. void pyb_sleep_set_gpio_lpds_callback (mp_obj_t cb_obj) {
  211. pybsleep_data.gpio_lpds_wake_cb = cb_obj;
  212. }
  213. void pyb_sleep_set_wlan_obj (mp_obj_t wlan_obj) {
  214. pybsleep_data.wlan_obj = (wlan_obj_t *)wlan_obj;
  215. }
  216. void pyb_sleep_set_rtc_obj (mp_obj_t rtc_obj) {
  217. pybsleep_data.rtc_obj = (pyb_rtc_obj_t *)rtc_obj;
  218. }
  219. void pyb_sleep_sleep (void) {
  220. nlr_buf_t nlr;
  221. // check if we should enable timer wake-up
  222. if (pybsleep_data.rtc_obj->irq_enabled && (pybsleep_data.rtc_obj->pwrmode & PYB_PWR_MODE_LPDS)) {
  223. if (!setup_timer_lpds_wake()) {
  224. // lpds entering is not possible, wait for the forced interrupt and return
  225. mp_hal_delay_ms(FAILED_SLEEP_DELAY_MS);
  226. return;
  227. }
  228. } else {
  229. // disable the timer as wake source
  230. MAP_PRCMLPDSWakeupSourceDisable(PRCM_LPDS_TIMER);
  231. }
  232. // do we need network wake-up?
  233. if (pybsleep_data.wlan_obj->irq_enabled) {
  234. MAP_PRCMLPDSWakeupSourceEnable (PRCM_LPDS_HOST_IRQ);
  235. server_sleep_sockets();
  236. } else {
  237. MAP_PRCMLPDSWakeupSourceDisable (PRCM_LPDS_HOST_IRQ);
  238. }
  239. // entering and exiting suspended mode must be an atomic operation
  240. // therefore interrupts need to be disabled
  241. uint primsk = disable_irq();
  242. if (nlr_push(&nlr) == 0) {
  243. pyb_sleep_suspend_enter();
  244. nlr_pop();
  245. }
  246. // an exception is always raised when exiting suspend mode
  247. enable_irq(primsk);
  248. }
  249. void pyb_sleep_deepsleep (void) {
  250. // check if we should enable timer wake-up
  251. if (pybsleep_data.rtc_obj->irq_enabled && (pybsleep_data.rtc_obj->pwrmode & PYB_PWR_MODE_HIBERNATE)) {
  252. if (!setup_timer_hibernate_wake()) {
  253. // hibernating is not possible, wait for the forced interrupt and return
  254. mp_hal_delay_ms(FAILED_SLEEP_DELAY_MS);
  255. return;
  256. }
  257. } else {
  258. // disable the timer as hibernate wake source
  259. MAP_PRCMLPDSWakeupSourceDisable(PRCM_HIB_SLOW_CLK_CTR);
  260. }
  261. wlan_stop(SL_STOP_TIMEOUT);
  262. pyb_sleep_flash_powerdown();
  263. // must be done just before entering hibernate mode
  264. pyb_sleep_iopark(true);
  265. MAP_PRCMHibernateEnter();
  266. }
  267. pybsleep_reset_cause_t pyb_sleep_get_reset_cause (void) {
  268. return pybsleep_reset_cause;
  269. }
  270. pybsleep_wake_reason_t pyb_sleep_get_wake_reason (void) {
  271. return pybsleep_wake_reason;
  272. }
  273. /******************************************************************************
  274. DEFINE PRIVATE FUNCTIONS
  275. ******************************************************************************/
  276. STATIC pyb_sleep_obj_t *pyb_sleep_find (mp_obj_t obj) {
  277. for (mp_uint_t i = 0; i < MP_STATE_PORT(pyb_sleep_obj_list).len; i++) {
  278. // search for the object and then remove it
  279. pyb_sleep_obj_t *sleep_obj = ((pyb_sleep_obj_t *)(MP_STATE_PORT(pyb_sleep_obj_list).items[i]));
  280. if (sleep_obj->obj == obj) {
  281. return sleep_obj;
  282. }
  283. }
  284. return NULL;
  285. }
  286. STATIC void pyb_sleep_flash_powerdown (void) {
  287. uint32_t status;
  288. // Enable clock for SSPI module
  289. MAP_PRCMPeripheralClkEnable(PRCM_SSPI, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK);
  290. // Reset SSPI at PRCM level and wait for reset to complete
  291. MAP_PRCMPeripheralReset(PRCM_SSPI);
  292. while(!MAP_PRCMPeripheralStatusGet(PRCM_SSPI));
  293. // Reset SSPI at module level
  294. MAP_SPIReset(SSPI_BASE);
  295. // Configure SSPI module
  296. MAP_SPIConfigSetExpClk (SSPI_BASE, PRCMPeripheralClockGet(PRCM_SSPI),
  297. 20000000, SPI_MODE_MASTER,SPI_SUB_MODE_0,
  298. (SPI_SW_CTRL_CS |
  299. SPI_4PIN_MODE |
  300. SPI_TURBO_OFF |
  301. SPI_CS_ACTIVELOW |
  302. SPI_WL_8));
  303. // Enable SSPI module
  304. MAP_SPIEnable(SSPI_BASE);
  305. // Enable chip select for the spi flash.
  306. MAP_SPICSEnable(SSPI_BASE);
  307. // Wait for the spi flash
  308. do {
  309. // Send the status register read instruction and read back a dummy byte.
  310. MAP_SPIDataPut(SSPI_BASE, SPIFLASH_INSTR_READ_STATUS);
  311. MAP_SPIDataGet(SSPI_BASE, &status);
  312. // Write a dummy byte then read back the actual status.
  313. MAP_SPIDataPut(SSPI_BASE, 0xFF);
  314. MAP_SPIDataGet(SSPI_BASE, &status);
  315. } while ((status & 0xFF) == SPIFLASH_STATUS_BUSY);
  316. // Disable chip select for the spi flash.
  317. MAP_SPICSDisable(SSPI_BASE);
  318. // Start another CS enable sequence for Power down command.
  319. MAP_SPICSEnable(SSPI_BASE);
  320. // Send Deep Power Down command to spi flash
  321. MAP_SPIDataPut(SSPI_BASE, SPIFLASH_INSTR_DEEP_POWER_DOWN);
  322. // Disable chip select for the spi flash.
  323. MAP_SPICSDisable(SSPI_BASE);
  324. }
  325. STATIC NORETURN void pyb_sleep_suspend_enter (void) {
  326. // enable full RAM retention
  327. MAP_PRCMSRAMRetentionEnable(PRCM_SRAM_COL_1 | PRCM_SRAM_COL_2 | PRCM_SRAM_COL_3 | PRCM_SRAM_COL_4, PRCM_SRAM_LPDS_RET);
  328. // save the NVIC control registers
  329. nvic_reg_store->vector_table = HWREG(NVIC_VTABLE);
  330. nvic_reg_store->aux_ctrl = HWREG(NVIC_ACTLR);
  331. nvic_reg_store->int_ctrl_state = HWREG(NVIC_INT_CTRL);
  332. nvic_reg_store->app_int = HWREG(NVIC_APINT);
  333. nvic_reg_store->sys_ctrl = HWREG(NVIC_SYS_CTRL);
  334. nvic_reg_store->config_ctrl = HWREG(NVIC_CFG_CTRL);
  335. nvic_reg_store->sys_pri_1 = HWREG(NVIC_SYS_PRI1);
  336. nvic_reg_store->sys_pri_2 = HWREG(NVIC_SYS_PRI2);
  337. nvic_reg_store->sys_pri_3 = HWREG(NVIC_SYS_PRI3);
  338. nvic_reg_store->sys_hcrs = HWREG(NVIC_SYS_HND_CTRL);
  339. // save the systick registers
  340. nvic_reg_store->systick_ctrl = HWREG(NVIC_ST_CTRL);
  341. nvic_reg_store->systick_reload = HWREG(NVIC_ST_RELOAD);
  342. nvic_reg_store->systick_calib = HWREG(NVIC_ST_CAL);
  343. // save the interrupt enable registers
  344. uint32_t *base_reg_addr = (uint32_t *)NVIC_EN0;
  345. for(int32_t i = 0; i < (sizeof(nvic_reg_store->int_en) / 4); i++) {
  346. nvic_reg_store->int_en[i] = base_reg_addr[i];
  347. }
  348. // save the interrupt priority registers
  349. base_reg_addr = (uint32_t *)NVIC_PRI0;
  350. for(int32_t i = 0; i < (sizeof(nvic_reg_store->int_priority) / 4); i++) {
  351. nvic_reg_store->int_priority[i] = base_reg_addr[i];
  352. }
  353. // switch off the heartbeat led (this makes sure it will blink as soon as we wake up)
  354. mperror_heartbeat_switch_off();
  355. // park the gpio pins
  356. pyb_sleep_iopark(false);
  357. // store the cpu registers
  358. sleep_store();
  359. // save the restore info and enter LPDS
  360. MAP_PRCMLPDSRestoreInfoSet(vault_arm_registers.psp, (uint32_t)sleep_restore);
  361. MAP_PRCMLPDSEnter();
  362. // let the cpu fade away...
  363. for ( ; ; );
  364. }
  365. void pyb_sleep_suspend_exit (void) {
  366. // take the I2C semaphore
  367. uint32_t reg = HWREG(COMMON_REG_BASE + COMMON_REG_O_I2C_Properties_Register);
  368. reg = (reg & ~0x3) | 0x1;
  369. HWREG(COMMON_REG_BASE + COMMON_REG_O_I2C_Properties_Register) = reg;
  370. // take the GPIO semaphore
  371. reg = HWREG(COMMON_REG_BASE + COMMON_REG_O_GPIO_properties_register);
  372. reg = (reg & ~0x3FF) | 0x155;
  373. HWREG(COMMON_REG_BASE + COMMON_REG_O_GPIO_properties_register) = reg;
  374. // restore de NVIC control registers
  375. HWREG(NVIC_VTABLE) = nvic_reg_store->vector_table;
  376. HWREG(NVIC_ACTLR) = nvic_reg_store->aux_ctrl;
  377. HWREG(NVIC_INT_CTRL) = nvic_reg_store->int_ctrl_state;
  378. HWREG(NVIC_APINT) = nvic_reg_store->app_int;
  379. HWREG(NVIC_SYS_CTRL) = nvic_reg_store->sys_ctrl;
  380. HWREG(NVIC_CFG_CTRL) = nvic_reg_store->config_ctrl;
  381. HWREG(NVIC_SYS_PRI1) = nvic_reg_store->sys_pri_1;
  382. HWREG(NVIC_SYS_PRI2) = nvic_reg_store->sys_pri_2;
  383. HWREG(NVIC_SYS_PRI3) = nvic_reg_store->sys_pri_3;
  384. HWREG(NVIC_SYS_HND_CTRL) = nvic_reg_store->sys_hcrs;
  385. // restore the systick register
  386. HWREG(NVIC_ST_CTRL) = nvic_reg_store->systick_ctrl;
  387. HWREG(NVIC_ST_RELOAD) = nvic_reg_store->systick_reload;
  388. HWREG(NVIC_ST_CAL) = nvic_reg_store->systick_calib;
  389. // restore the interrupt priority registers
  390. uint32_t *base_reg_addr = (uint32_t *)NVIC_PRI0;
  391. for (uint32_t i = 0; i < (sizeof(nvic_reg_store->int_priority) / 4); i++) {
  392. base_reg_addr[i] = nvic_reg_store->int_priority[i];
  393. }
  394. // restore the interrupt enable registers
  395. base_reg_addr = (uint32_t *)NVIC_EN0;
  396. for(uint32_t i = 0; i < (sizeof(nvic_reg_store->int_en) / 4); i++) {
  397. base_reg_addr[i] = nvic_reg_store->int_en[i];
  398. }
  399. HAL_INTRODUCE_SYNC_BARRIER();
  400. // ungate the clock to the shared spi bus
  401. MAP_PRCMPeripheralClkEnable(PRCM_SSPI, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK);
  402. #if MICROPY_HW_ANTENNA_DIVERSITY
  403. // re-configure the antenna selection pins
  404. antenna_init0();
  405. #endif
  406. // reinitialize simplelink's interface
  407. sl_IfOpen (NULL, 0);
  408. // restore the configuration of all active peripherals
  409. pyb_sleep_obj_wakeup();
  410. // reconfigure all the previously enabled interrupts
  411. mp_irq_wake_all();
  412. // we need to init the crypto hash engine again
  413. //CRYPTOHASH_Init();
  414. // trigger a sw interrupt
  415. MAP_IntPendSet(INT_PRCM);
  416. // force an exception to go back to the point where suspend mode was entered
  417. nlr_raise(mp_obj_new_exception(&mp_type_SystemExit));
  418. }
  419. STATIC void PRCMInterruptHandler (void) {
  420. // reading the interrupt status automatically clears the interrupt
  421. if (PRCM_INT_SLOW_CLK_CTR == MAP_PRCMIntStatus()) {
  422. // reconfigure it again (if repeat is true)
  423. pyb_rtc_repeat_alarm (pybsleep_data.rtc_obj);
  424. pybsleep_data.rtc_obj->irq_flags = PYB_RTC_ALARM0;
  425. // need to check if irq's are enabled from the user point of view
  426. if (pybsleep_data.rtc_obj->irq_enabled && (pybsleep_data.rtc_obj->pwrmode & PYB_PWR_MODE_ACTIVE)) {
  427. mp_irq_handler(pybsleep_data.rtc_obj->irq_obj);
  428. }
  429. pybsleep_data.rtc_obj->irq_flags = 0;
  430. } else {
  431. // interrupt has been triggered while waking up from LPDS
  432. switch (MAP_PRCMLPDSWakeupCauseGet()) {
  433. case PRCM_LPDS_HOST_IRQ:
  434. pybsleep_data.wlan_obj->irq_flags = MODWLAN_WIFI_EVENT_ANY;
  435. mp_irq_handler(pybsleep_data.wlan_obj->irq_obj);
  436. pybsleep_wake_reason = PYB_SLP_WAKED_BY_WLAN;
  437. pybsleep_data.wlan_obj->irq_flags = 0;
  438. break;
  439. case PRCM_LPDS_GPIO:
  440. mp_irq_handler(pybsleep_data.gpio_lpds_wake_cb);
  441. pybsleep_wake_reason = PYB_SLP_WAKED_BY_GPIO;
  442. break;
  443. case PRCM_LPDS_TIMER:
  444. // reconfigure it again if repeat is true
  445. pyb_rtc_repeat_alarm (pybsleep_data.rtc_obj);
  446. pybsleep_data.rtc_obj->irq_flags = PYB_RTC_ALARM0;
  447. // next one clears the wake cause flag
  448. MAP_PRCMLPDSWakeupSourceDisable(PRCM_LPDS_TIMER);
  449. mp_irq_handler(pybsleep_data.rtc_obj->irq_obj);
  450. pybsleep_data.rtc_obj->irq_flags = 0;
  451. pybsleep_wake_reason = PYB_SLP_WAKED_BY_RTC;
  452. break;
  453. default:
  454. break;
  455. }
  456. }
  457. }
  458. STATIC void pyb_sleep_obj_wakeup (void) {
  459. for (mp_uint_t i = 0; i < MP_STATE_PORT(pyb_sleep_obj_list).len; i++) {
  460. pyb_sleep_obj_t *sleep_obj = ((pyb_sleep_obj_t *)MP_STATE_PORT(pyb_sleep_obj_list).items[i]);
  461. sleep_obj->wakeup(sleep_obj->obj);
  462. }
  463. }
  464. STATIC void pyb_sleep_iopark (bool hibernate) {
  465. const mp_map_t *named_map = &pin_board_pins_locals_dict.map;
  466. for (uint i = 0; i < named_map->used; i++) {
  467. pin_obj_t * pin = (pin_obj_t *)named_map->table[i].value;
  468. switch (pin->pin_num) {
  469. #ifdef DEBUG
  470. // skip the JTAG pins
  471. case PIN_16:
  472. case PIN_17:
  473. case PIN_19:
  474. case PIN_20:
  475. break;
  476. #endif
  477. default:
  478. // enable a weak pull-up if the pin is unused
  479. if (!pin->used) {
  480. MAP_PinConfigSet(pin->pin_num, pin->strength, PIN_TYPE_STD_PU);
  481. }
  482. if (hibernate) {
  483. // make it an input
  484. MAP_PinDirModeSet(pin->pin_num, PIN_DIR_MODE_IN);
  485. }
  486. break;
  487. }
  488. }
  489. // park the sflash pins
  490. HWREG(0x4402E0E8) &= ~(0x3 << 8);
  491. HWREG(0x4402E0E8) |= (0x2 << 8);
  492. HWREG(0x4402E0EC) &= ~(0x3 << 8);
  493. HWREG(0x4402E0EC) |= (0x2 << 8);
  494. HWREG(0x4402E0F0) &= ~(0x3 << 8);
  495. HWREG(0x4402E0F0) |= (0x2 << 8);
  496. HWREG(0x4402E0F4) &= ~(0x3 << 8);
  497. HWREG(0x4402E0F4) |= (0x1 << 8);
  498. // if the board has antenna diversity, only park the antenna
  499. // selection pins when going into hibernation
  500. #if MICROPY_HW_ANTENNA_DIVERSITY
  501. if (hibernate) {
  502. #endif
  503. // park the antenna selection pins
  504. // (tri-stated with pull down enabled)
  505. HWREG(0x4402E108) = 0x00000E61;
  506. HWREG(0x4402E10C) = 0x00000E61;
  507. #if MICROPY_HW_ANTENNA_DIVERSITY
  508. } else {
  509. // park the antenna selection pins
  510. // (tri-stated without changing the pull up/down resistors)
  511. HWREG(0x4402E108) &= ~0x000000FF;
  512. HWREG(0x4402E108) |= 0x00000C61;
  513. HWREG(0x4402E10C) &= ~0x000000FF;
  514. HWREG(0x4402E10C) |= 0x00000C61;
  515. }
  516. #endif
  517. }
  518. STATIC bool setup_timer_lpds_wake (void) {
  519. uint64_t t_match, t_curr;
  520. int64_t t_remaining;
  521. // get the time remaining for the RTC timer to expire
  522. t_match = MAP_PRCMSlowClkCtrMatchGet();
  523. t_curr = MAP_PRCMSlowClkCtrGet();
  524. // get the time remaining in terms of slow clocks
  525. t_remaining = (t_match - t_curr);
  526. if (t_remaining > WAKEUP_TIME_LPDS) {
  527. // subtract the time it takes to wakeup from lpds
  528. t_remaining -= WAKEUP_TIME_LPDS;
  529. t_remaining = (t_remaining > 0xFFFFFFFF) ? 0xFFFFFFFF: t_remaining;
  530. // setup the LPDS wake time
  531. MAP_PRCMLPDSIntervalSet((uint32_t)t_remaining);
  532. // enable the wake source
  533. MAP_PRCMLPDSWakeupSourceEnable(PRCM_LPDS_TIMER);
  534. return true;
  535. }
  536. // disable the timer as wake source
  537. MAP_PRCMLPDSWakeupSourceDisable(PRCM_LPDS_TIMER);
  538. uint32_t f_seconds;
  539. uint16_t f_mseconds;
  540. // setup a timer interrupt immediately
  541. pyb_rtc_calc_future_time (FORCED_TIMER_INTERRUPT_MS, &f_seconds, &f_mseconds);
  542. MAP_PRCMRTCMatchSet(f_seconds, f_mseconds);
  543. // LPDS wake by timer was not possible, force an interrupt in active mode instead
  544. MAP_PRCMIntEnable(PRCM_INT_SLOW_CLK_CTR);
  545. return false;
  546. }
  547. STATIC bool setup_timer_hibernate_wake (void) {
  548. uint64_t t_match, t_curr;
  549. int64_t t_remaining;
  550. // get the time remaining for the RTC timer to expire
  551. t_match = MAP_PRCMSlowClkCtrMatchGet();
  552. t_curr = MAP_PRCMSlowClkCtrGet();
  553. // get the time remaining in terms of slow clocks
  554. t_remaining = (t_match - t_curr);
  555. if (t_remaining > WAKEUP_TIME_HIB) {
  556. // subtract the time it takes for wakeup from hibernate
  557. t_remaining -= WAKEUP_TIME_HIB;
  558. // setup the LPDS wake time
  559. MAP_PRCMHibernateIntervalSet((uint32_t)t_remaining);
  560. // enable the wake source
  561. MAP_PRCMHibernateWakeupSourceEnable(PRCM_HIB_SLOW_CLK_CTR);
  562. return true;
  563. }
  564. // disable the timer as wake source
  565. MAP_PRCMLPDSWakeupSourceDisable(PRCM_HIB_SLOW_CLK_CTR);
  566. uint32_t f_seconds;
  567. uint16_t f_mseconds;
  568. // setup a timer interrupt immediately
  569. pyb_rtc_calc_future_time (FORCED_TIMER_INTERRUPT_MS, &f_seconds, &f_mseconds);
  570. MAP_PRCMRTCMatchSet(f_seconds, f_mseconds);
  571. // LPDS wake by timer was not possible, force an interrupt in active mode instead
  572. MAP_PRCMIntEnable(PRCM_INT_SLOW_CLK_CTR);
  573. return false;
  574. }