| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656 |
- /*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2015 Daniel Campora
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
- #include <stdint.h>
- #include <string.h>
- #include "py/runtime.h"
- #include "py/mphal.h"
- #include "inc/hw_types.h"
- #include "inc/hw_ints.h"
- #include "inc/hw_nvic.h"
- #include "inc/hw_common_reg.h"
- #include "inc/hw_memmap.h"
- #include "cc3200_asm.h"
- #include "rom_map.h"
- #include "interrupt.h"
- #include "systick.h"
- #include "prcm.h"
- #include "spi.h"
- #include "pin.h"
- #include "pybsleep.h"
- #include "mpirq.h"
- #include "pybpin.h"
- #include "simplelink.h"
- #include "modnetwork.h"
- #include "modwlan.h"
- #include "osi.h"
- #include "debug.h"
- #include "mpexception.h"
- #include "mperror.h"
- #include "sleeprestore.h"
- #include "serverstask.h"
- #include "antenna.h"
- #include "cryptohash.h"
- #include "pybrtc.h"
- /******************************************************************************
- DECLARE PRIVATE CONSTANTS
- ******************************************************************************/
- #define SPIFLASH_INSTR_READ_STATUS (0x05)
- #define SPIFLASH_INSTR_DEEP_POWER_DOWN (0xB9)
- #define SPIFLASH_STATUS_BUSY (0x01)
- #define LPDS_UP_TIME (425) // 13 msec
- #define LPDS_DOWN_TIME (98) // 3 msec
- #define USER_OFFSET (131) // 4 smec
- #define WAKEUP_TIME_LPDS (LPDS_UP_TIME + LPDS_DOWN_TIME + USER_OFFSET) // 20 msec
- #define WAKEUP_TIME_HIB (32768) // 1 s
- #define FORCED_TIMER_INTERRUPT_MS (PYB_RTC_MIN_ALARM_TIME_MS)
- #define FAILED_SLEEP_DELAY_MS (FORCED_TIMER_INTERRUPT_MS * 3)
- /******************************************************************************
- DECLARE PRIVATE TYPES
- ******************************************************************************/
- // storage memory for Cortex M4 registers
- typedef struct {
- uint32_t msp;
- uint32_t psp;
- uint32_t psr;
- uint32_t primask;
- uint32_t faultmask;
- uint32_t basepri;
- uint32_t control;
- } arm_cm4_core_regs_t;
- // storage memory for the NVIC registers
- typedef struct {
- uint32_t vector_table; // Vector Table Offset
- uint32_t aux_ctrl; // Auxiliary control register
- uint32_t int_ctrl_state; // Interrupt Control and State
- uint32_t app_int; // Application Interrupt Reset control
- uint32_t sys_ctrl; // System control
- uint32_t config_ctrl; // Configuration control
- uint32_t sys_pri_1; // System Handler Priority 1
- uint32_t sys_pri_2; // System Handler Priority 2
- uint32_t sys_pri_3; // System Handler Priority 3
- uint32_t sys_hcrs; // System Handler control and state register
- uint32_t systick_ctrl; // SysTick Control Status
- uint32_t systick_reload; // SysTick Reload
- uint32_t systick_calib; // SysTick Calibration
- uint32_t int_en[6]; // Interrupt set enable
- uint32_t int_priority[49]; // Interrupt priority
- } nvic_reg_store_t;
- typedef struct {
- mp_obj_base_t base;
- mp_obj_t obj;
- WakeUpCB_t wakeup;
- } pyb_sleep_obj_t;
- typedef struct {
- mp_obj_t gpio_lpds_wake_cb;
- wlan_obj_t *wlan_obj;
- pyb_rtc_obj_t *rtc_obj;
- } pybsleep_data_t;
- /******************************************************************************
- DECLARE PRIVATE DATA
- ******************************************************************************/
- STATIC nvic_reg_store_t *nvic_reg_store;
- STATIC pybsleep_data_t pybsleep_data = {NULL, NULL, NULL};
- volatile arm_cm4_core_regs_t vault_arm_registers;
- STATIC pybsleep_reset_cause_t pybsleep_reset_cause = PYB_SLP_PWRON_RESET;
- STATIC pybsleep_wake_reason_t pybsleep_wake_reason = PYB_SLP_WAKED_PWRON;
- STATIC const mp_obj_type_t pyb_sleep_type = {
- { &mp_type_type },
- .name = MP_QSTR_sleep,
- };
- /******************************************************************************
- DECLARE PRIVATE FUNCTIONS
- ******************************************************************************/
- STATIC pyb_sleep_obj_t *pyb_sleep_find (mp_obj_t obj);
- STATIC void pyb_sleep_flash_powerdown (void);
- STATIC NORETURN void pyb_sleep_suspend_enter (void);
- void pyb_sleep_suspend_exit (void);
- STATIC void pyb_sleep_obj_wakeup (void);
- STATIC void PRCMInterruptHandler (void);
- STATIC void pyb_sleep_iopark (bool hibernate);
- STATIC bool setup_timer_lpds_wake (void);
- STATIC bool setup_timer_hibernate_wake (void);
- /******************************************************************************
- DEFINE PUBLIC FUNCTIONS
- ******************************************************************************/
- __attribute__ ((section (".boot")))
- void pyb_sleep_pre_init (void) {
- // allocate memory for nvic registers vault
- ASSERT ((nvic_reg_store = mem_Malloc(sizeof(nvic_reg_store_t))) != NULL);
- }
- void pyb_sleep_init0 (void) {
- // initialize the sleep objects list
- mp_obj_list_init(&MP_STATE_PORT(pyb_sleep_obj_list), 0);
- // register and enable the PRCM interrupt
- osi_InterruptRegister(INT_PRCM, (P_OSI_INTR_ENTRY)PRCMInterruptHandler, INT_PRIORITY_LVL_1);
- // disable all LPDS and hibernate wake up sources (WLAN is disabed/enabled before entering LDPS mode)
- MAP_PRCMLPDSWakeupSourceDisable(PRCM_LPDS_GPIO);
- MAP_PRCMLPDSWakeupSourceDisable(PRCM_LPDS_TIMER);
- MAP_PRCMHibernateWakeupSourceDisable(PRCM_HIB_SLOW_CLK_CTR | PRCM_HIB_GPIO2 | PRCM_HIB_GPIO4 | PRCM_HIB_GPIO13 |
- PRCM_HIB_GPIO17 | PRCM_HIB_GPIO11 | PRCM_HIB_GPIO24 | PRCM_HIB_GPIO26);
- // check the reset casue (if it's soft reset, leave it as it is)
- if (pybsleep_reset_cause != PYB_SLP_SOFT_RESET) {
- switch (MAP_PRCMSysResetCauseGet()) {
- case PRCM_POWER_ON:
- pybsleep_reset_cause = PYB_SLP_PWRON_RESET;
- break;
- case PRCM_CORE_RESET:
- case PRCM_MCU_RESET:
- case PRCM_SOC_RESET:
- pybsleep_reset_cause = PYB_SLP_HARD_RESET;
- break;
- case PRCM_WDT_RESET:
- pybsleep_reset_cause = PYB_SLP_WDT_RESET;
- break;
- case PRCM_HIB_EXIT:
- if (PRCMGetSpecialBit(PRCM_WDT_RESET_BIT)) {
- pybsleep_reset_cause = PYB_SLP_WDT_RESET;
- }
- else {
- pybsleep_reset_cause = PYB_SLP_HIB_RESET;
- // set the correct wake reason
- switch (MAP_PRCMHibernateWakeupCauseGet()) {
- case PRCM_HIB_WAKEUP_CAUSE_SLOW_CLOCK:
- pybsleep_wake_reason = PYB_SLP_WAKED_BY_RTC;
- // TODO repeat the alarm
- break;
- case PRCM_HIB_WAKEUP_CAUSE_GPIO:
- pybsleep_wake_reason = PYB_SLP_WAKED_BY_GPIO;
- break;
- default:
- break;
- }
- }
- break;
- default:
- break;
- }
- }
- }
- void pyb_sleep_signal_soft_reset (void) {
- pybsleep_reset_cause = PYB_SLP_SOFT_RESET;
- }
- void pyb_sleep_add (const mp_obj_t obj, WakeUpCB_t wakeup) {
- pyb_sleep_obj_t *sleep_obj = m_new_obj(pyb_sleep_obj_t);
- sleep_obj->base.type = &pyb_sleep_type;
- sleep_obj->obj = obj;
- sleep_obj->wakeup = wakeup;
- // remove it in case it was already registered
- pyb_sleep_remove (obj);
- mp_obj_list_append(&MP_STATE_PORT(pyb_sleep_obj_list), sleep_obj);
- }
- void pyb_sleep_remove (const mp_obj_t obj) {
- pyb_sleep_obj_t *sleep_obj;
- if ((sleep_obj = pyb_sleep_find(obj))) {
- mp_obj_list_remove(&MP_STATE_PORT(pyb_sleep_obj_list), sleep_obj);
- }
- }
- void pyb_sleep_set_gpio_lpds_callback (mp_obj_t cb_obj) {
- pybsleep_data.gpio_lpds_wake_cb = cb_obj;
- }
- void pyb_sleep_set_wlan_obj (mp_obj_t wlan_obj) {
- pybsleep_data.wlan_obj = (wlan_obj_t *)wlan_obj;
- }
- void pyb_sleep_set_rtc_obj (mp_obj_t rtc_obj) {
- pybsleep_data.rtc_obj = (pyb_rtc_obj_t *)rtc_obj;
- }
- void pyb_sleep_sleep (void) {
- nlr_buf_t nlr;
- // check if we should enable timer wake-up
- if (pybsleep_data.rtc_obj->irq_enabled && (pybsleep_data.rtc_obj->pwrmode & PYB_PWR_MODE_LPDS)) {
- if (!setup_timer_lpds_wake()) {
- // lpds entering is not possible, wait for the forced interrupt and return
- mp_hal_delay_ms(FAILED_SLEEP_DELAY_MS);
- return;
- }
- } else {
- // disable the timer as wake source
- MAP_PRCMLPDSWakeupSourceDisable(PRCM_LPDS_TIMER);
- }
- // do we need network wake-up?
- if (pybsleep_data.wlan_obj->irq_enabled) {
- MAP_PRCMLPDSWakeupSourceEnable (PRCM_LPDS_HOST_IRQ);
- server_sleep_sockets();
- } else {
- MAP_PRCMLPDSWakeupSourceDisable (PRCM_LPDS_HOST_IRQ);
- }
- // entering and exiting suspended mode must be an atomic operation
- // therefore interrupts need to be disabled
- uint primsk = disable_irq();
- if (nlr_push(&nlr) == 0) {
- pyb_sleep_suspend_enter();
- nlr_pop();
- }
- // an exception is always raised when exiting suspend mode
- enable_irq(primsk);
- }
- void pyb_sleep_deepsleep (void) {
- // check if we should enable timer wake-up
- if (pybsleep_data.rtc_obj->irq_enabled && (pybsleep_data.rtc_obj->pwrmode & PYB_PWR_MODE_HIBERNATE)) {
- if (!setup_timer_hibernate_wake()) {
- // hibernating is not possible, wait for the forced interrupt and return
- mp_hal_delay_ms(FAILED_SLEEP_DELAY_MS);
- return;
- }
- } else {
- // disable the timer as hibernate wake source
- MAP_PRCMLPDSWakeupSourceDisable(PRCM_HIB_SLOW_CLK_CTR);
- }
- wlan_stop(SL_STOP_TIMEOUT);
- pyb_sleep_flash_powerdown();
- // must be done just before entering hibernate mode
- pyb_sleep_iopark(true);
- MAP_PRCMHibernateEnter();
- }
- pybsleep_reset_cause_t pyb_sleep_get_reset_cause (void) {
- return pybsleep_reset_cause;
- }
- pybsleep_wake_reason_t pyb_sleep_get_wake_reason (void) {
- return pybsleep_wake_reason;
- }
- /******************************************************************************
- DEFINE PRIVATE FUNCTIONS
- ******************************************************************************/
- STATIC pyb_sleep_obj_t *pyb_sleep_find (mp_obj_t obj) {
- for (mp_uint_t i = 0; i < MP_STATE_PORT(pyb_sleep_obj_list).len; i++) {
- // search for the object and then remove it
- pyb_sleep_obj_t *sleep_obj = ((pyb_sleep_obj_t *)(MP_STATE_PORT(pyb_sleep_obj_list).items[i]));
- if (sleep_obj->obj == obj) {
- return sleep_obj;
- }
- }
- return NULL;
- }
- STATIC void pyb_sleep_flash_powerdown (void) {
- uint32_t status;
- // Enable clock for SSPI module
- MAP_PRCMPeripheralClkEnable(PRCM_SSPI, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK);
- // Reset SSPI at PRCM level and wait for reset to complete
- MAP_PRCMPeripheralReset(PRCM_SSPI);
- while(!MAP_PRCMPeripheralStatusGet(PRCM_SSPI));
- // Reset SSPI at module level
- MAP_SPIReset(SSPI_BASE);
- // Configure SSPI module
- MAP_SPIConfigSetExpClk (SSPI_BASE, PRCMPeripheralClockGet(PRCM_SSPI),
- 20000000, SPI_MODE_MASTER,SPI_SUB_MODE_0,
- (SPI_SW_CTRL_CS |
- SPI_4PIN_MODE |
- SPI_TURBO_OFF |
- SPI_CS_ACTIVELOW |
- SPI_WL_8));
- // Enable SSPI module
- MAP_SPIEnable(SSPI_BASE);
- // Enable chip select for the spi flash.
- MAP_SPICSEnable(SSPI_BASE);
- // Wait for the spi flash
- do {
- // Send the status register read instruction and read back a dummy byte.
- MAP_SPIDataPut(SSPI_BASE, SPIFLASH_INSTR_READ_STATUS);
- MAP_SPIDataGet(SSPI_BASE, &status);
- // Write a dummy byte then read back the actual status.
- MAP_SPIDataPut(SSPI_BASE, 0xFF);
- MAP_SPIDataGet(SSPI_BASE, &status);
- } while ((status & 0xFF) == SPIFLASH_STATUS_BUSY);
- // Disable chip select for the spi flash.
- MAP_SPICSDisable(SSPI_BASE);
- // Start another CS enable sequence for Power down command.
- MAP_SPICSEnable(SSPI_BASE);
- // Send Deep Power Down command to spi flash
- MAP_SPIDataPut(SSPI_BASE, SPIFLASH_INSTR_DEEP_POWER_DOWN);
- // Disable chip select for the spi flash.
- MAP_SPICSDisable(SSPI_BASE);
- }
- STATIC NORETURN void pyb_sleep_suspend_enter (void) {
- // enable full RAM retention
- MAP_PRCMSRAMRetentionEnable(PRCM_SRAM_COL_1 | PRCM_SRAM_COL_2 | PRCM_SRAM_COL_3 | PRCM_SRAM_COL_4, PRCM_SRAM_LPDS_RET);
- // save the NVIC control registers
- nvic_reg_store->vector_table = HWREG(NVIC_VTABLE);
- nvic_reg_store->aux_ctrl = HWREG(NVIC_ACTLR);
- nvic_reg_store->int_ctrl_state = HWREG(NVIC_INT_CTRL);
- nvic_reg_store->app_int = HWREG(NVIC_APINT);
- nvic_reg_store->sys_ctrl = HWREG(NVIC_SYS_CTRL);
- nvic_reg_store->config_ctrl = HWREG(NVIC_CFG_CTRL);
- nvic_reg_store->sys_pri_1 = HWREG(NVIC_SYS_PRI1);
- nvic_reg_store->sys_pri_2 = HWREG(NVIC_SYS_PRI2);
- nvic_reg_store->sys_pri_3 = HWREG(NVIC_SYS_PRI3);
- nvic_reg_store->sys_hcrs = HWREG(NVIC_SYS_HND_CTRL);
- // save the systick registers
- nvic_reg_store->systick_ctrl = HWREG(NVIC_ST_CTRL);
- nvic_reg_store->systick_reload = HWREG(NVIC_ST_RELOAD);
- nvic_reg_store->systick_calib = HWREG(NVIC_ST_CAL);
- // save the interrupt enable registers
- uint32_t *base_reg_addr = (uint32_t *)NVIC_EN0;
- for(int32_t i = 0; i < (sizeof(nvic_reg_store->int_en) / 4); i++) {
- nvic_reg_store->int_en[i] = base_reg_addr[i];
- }
- // save the interrupt priority registers
- base_reg_addr = (uint32_t *)NVIC_PRI0;
- for(int32_t i = 0; i < (sizeof(nvic_reg_store->int_priority) / 4); i++) {
- nvic_reg_store->int_priority[i] = base_reg_addr[i];
- }
- // switch off the heartbeat led (this makes sure it will blink as soon as we wake up)
- mperror_heartbeat_switch_off();
- // park the gpio pins
- pyb_sleep_iopark(false);
- // store the cpu registers
- sleep_store();
- // save the restore info and enter LPDS
- MAP_PRCMLPDSRestoreInfoSet(vault_arm_registers.psp, (uint32_t)sleep_restore);
- MAP_PRCMLPDSEnter();
- // let the cpu fade away...
- for ( ; ; );
- }
- void pyb_sleep_suspend_exit (void) {
- // take the I2C semaphore
- uint32_t reg = HWREG(COMMON_REG_BASE + COMMON_REG_O_I2C_Properties_Register);
- reg = (reg & ~0x3) | 0x1;
- HWREG(COMMON_REG_BASE + COMMON_REG_O_I2C_Properties_Register) = reg;
- // take the GPIO semaphore
- reg = HWREG(COMMON_REG_BASE + COMMON_REG_O_GPIO_properties_register);
- reg = (reg & ~0x3FF) | 0x155;
- HWREG(COMMON_REG_BASE + COMMON_REG_O_GPIO_properties_register) = reg;
- // restore de NVIC control registers
- HWREG(NVIC_VTABLE) = nvic_reg_store->vector_table;
- HWREG(NVIC_ACTLR) = nvic_reg_store->aux_ctrl;
- HWREG(NVIC_INT_CTRL) = nvic_reg_store->int_ctrl_state;
- HWREG(NVIC_APINT) = nvic_reg_store->app_int;
- HWREG(NVIC_SYS_CTRL) = nvic_reg_store->sys_ctrl;
- HWREG(NVIC_CFG_CTRL) = nvic_reg_store->config_ctrl;
- HWREG(NVIC_SYS_PRI1) = nvic_reg_store->sys_pri_1;
- HWREG(NVIC_SYS_PRI2) = nvic_reg_store->sys_pri_2;
- HWREG(NVIC_SYS_PRI3) = nvic_reg_store->sys_pri_3;
- HWREG(NVIC_SYS_HND_CTRL) = nvic_reg_store->sys_hcrs;
- // restore the systick register
- HWREG(NVIC_ST_CTRL) = nvic_reg_store->systick_ctrl;
- HWREG(NVIC_ST_RELOAD) = nvic_reg_store->systick_reload;
- HWREG(NVIC_ST_CAL) = nvic_reg_store->systick_calib;
- // restore the interrupt priority registers
- uint32_t *base_reg_addr = (uint32_t *)NVIC_PRI0;
- for (uint32_t i = 0; i < (sizeof(nvic_reg_store->int_priority) / 4); i++) {
- base_reg_addr[i] = nvic_reg_store->int_priority[i];
- }
- // restore the interrupt enable registers
- base_reg_addr = (uint32_t *)NVIC_EN0;
- for(uint32_t i = 0; i < (sizeof(nvic_reg_store->int_en) / 4); i++) {
- base_reg_addr[i] = nvic_reg_store->int_en[i];
- }
- HAL_INTRODUCE_SYNC_BARRIER();
- // ungate the clock to the shared spi bus
- MAP_PRCMPeripheralClkEnable(PRCM_SSPI, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK);
- #if MICROPY_HW_ANTENNA_DIVERSITY
- // re-configure the antenna selection pins
- antenna_init0();
- #endif
- // reinitialize simplelink's interface
- sl_IfOpen (NULL, 0);
- // restore the configuration of all active peripherals
- pyb_sleep_obj_wakeup();
- // reconfigure all the previously enabled interrupts
- mp_irq_wake_all();
- // we need to init the crypto hash engine again
- //CRYPTOHASH_Init();
- // trigger a sw interrupt
- MAP_IntPendSet(INT_PRCM);
- // force an exception to go back to the point where suspend mode was entered
- nlr_raise(mp_obj_new_exception(&mp_type_SystemExit));
- }
- STATIC void PRCMInterruptHandler (void) {
- // reading the interrupt status automatically clears the interrupt
- if (PRCM_INT_SLOW_CLK_CTR == MAP_PRCMIntStatus()) {
- // reconfigure it again (if repeat is true)
- pyb_rtc_repeat_alarm (pybsleep_data.rtc_obj);
- pybsleep_data.rtc_obj->irq_flags = PYB_RTC_ALARM0;
- // need to check if irq's are enabled from the user point of view
- if (pybsleep_data.rtc_obj->irq_enabled && (pybsleep_data.rtc_obj->pwrmode & PYB_PWR_MODE_ACTIVE)) {
- mp_irq_handler(pybsleep_data.rtc_obj->irq_obj);
- }
- pybsleep_data.rtc_obj->irq_flags = 0;
- } else {
- // interrupt has been triggered while waking up from LPDS
- switch (MAP_PRCMLPDSWakeupCauseGet()) {
- case PRCM_LPDS_HOST_IRQ:
- pybsleep_data.wlan_obj->irq_flags = MODWLAN_WIFI_EVENT_ANY;
- mp_irq_handler(pybsleep_data.wlan_obj->irq_obj);
- pybsleep_wake_reason = PYB_SLP_WAKED_BY_WLAN;
- pybsleep_data.wlan_obj->irq_flags = 0;
- break;
- case PRCM_LPDS_GPIO:
- mp_irq_handler(pybsleep_data.gpio_lpds_wake_cb);
- pybsleep_wake_reason = PYB_SLP_WAKED_BY_GPIO;
- break;
- case PRCM_LPDS_TIMER:
- // reconfigure it again if repeat is true
- pyb_rtc_repeat_alarm (pybsleep_data.rtc_obj);
- pybsleep_data.rtc_obj->irq_flags = PYB_RTC_ALARM0;
- // next one clears the wake cause flag
- MAP_PRCMLPDSWakeupSourceDisable(PRCM_LPDS_TIMER);
- mp_irq_handler(pybsleep_data.rtc_obj->irq_obj);
- pybsleep_data.rtc_obj->irq_flags = 0;
- pybsleep_wake_reason = PYB_SLP_WAKED_BY_RTC;
- break;
- default:
- break;
- }
- }
- }
- STATIC void pyb_sleep_obj_wakeup (void) {
- for (mp_uint_t i = 0; i < MP_STATE_PORT(pyb_sleep_obj_list).len; i++) {
- pyb_sleep_obj_t *sleep_obj = ((pyb_sleep_obj_t *)MP_STATE_PORT(pyb_sleep_obj_list).items[i]);
- sleep_obj->wakeup(sleep_obj->obj);
- }
- }
- STATIC void pyb_sleep_iopark (bool hibernate) {
- const mp_map_t *named_map = &pin_board_pins_locals_dict.map;
- for (uint i = 0; i < named_map->used; i++) {
- pin_obj_t * pin = (pin_obj_t *)named_map->table[i].value;
- switch (pin->pin_num) {
- #ifdef DEBUG
- // skip the JTAG pins
- case PIN_16:
- case PIN_17:
- case PIN_19:
- case PIN_20:
- break;
- #endif
- default:
- // enable a weak pull-up if the pin is unused
- if (!pin->used) {
- MAP_PinConfigSet(pin->pin_num, pin->strength, PIN_TYPE_STD_PU);
- }
- if (hibernate) {
- // make it an input
- MAP_PinDirModeSet(pin->pin_num, PIN_DIR_MODE_IN);
- }
- break;
- }
- }
- // park the sflash pins
- HWREG(0x4402E0E8) &= ~(0x3 << 8);
- HWREG(0x4402E0E8) |= (0x2 << 8);
- HWREG(0x4402E0EC) &= ~(0x3 << 8);
- HWREG(0x4402E0EC) |= (0x2 << 8);
- HWREG(0x4402E0F0) &= ~(0x3 << 8);
- HWREG(0x4402E0F0) |= (0x2 << 8);
- HWREG(0x4402E0F4) &= ~(0x3 << 8);
- HWREG(0x4402E0F4) |= (0x1 << 8);
- // if the board has antenna diversity, only park the antenna
- // selection pins when going into hibernation
- #if MICROPY_HW_ANTENNA_DIVERSITY
- if (hibernate) {
- #endif
- // park the antenna selection pins
- // (tri-stated with pull down enabled)
- HWREG(0x4402E108) = 0x00000E61;
- HWREG(0x4402E10C) = 0x00000E61;
- #if MICROPY_HW_ANTENNA_DIVERSITY
- } else {
- // park the antenna selection pins
- // (tri-stated without changing the pull up/down resistors)
- HWREG(0x4402E108) &= ~0x000000FF;
- HWREG(0x4402E108) |= 0x00000C61;
- HWREG(0x4402E10C) &= ~0x000000FF;
- HWREG(0x4402E10C) |= 0x00000C61;
- }
- #endif
- }
- STATIC bool setup_timer_lpds_wake (void) {
- uint64_t t_match, t_curr;
- int64_t t_remaining;
- // get the time remaining for the RTC timer to expire
- t_match = MAP_PRCMSlowClkCtrMatchGet();
- t_curr = MAP_PRCMSlowClkCtrGet();
- // get the time remaining in terms of slow clocks
- t_remaining = (t_match - t_curr);
- if (t_remaining > WAKEUP_TIME_LPDS) {
- // subtract the time it takes to wakeup from lpds
- t_remaining -= WAKEUP_TIME_LPDS;
- t_remaining = (t_remaining > 0xFFFFFFFF) ? 0xFFFFFFFF: t_remaining;
- // setup the LPDS wake time
- MAP_PRCMLPDSIntervalSet((uint32_t)t_remaining);
- // enable the wake source
- MAP_PRCMLPDSWakeupSourceEnable(PRCM_LPDS_TIMER);
- return true;
- }
- // disable the timer as wake source
- MAP_PRCMLPDSWakeupSourceDisable(PRCM_LPDS_TIMER);
- uint32_t f_seconds;
- uint16_t f_mseconds;
- // setup a timer interrupt immediately
- pyb_rtc_calc_future_time (FORCED_TIMER_INTERRUPT_MS, &f_seconds, &f_mseconds);
- MAP_PRCMRTCMatchSet(f_seconds, f_mseconds);
- // LPDS wake by timer was not possible, force an interrupt in active mode instead
- MAP_PRCMIntEnable(PRCM_INT_SLOW_CLK_CTR);
- return false;
- }
- STATIC bool setup_timer_hibernate_wake (void) {
- uint64_t t_match, t_curr;
- int64_t t_remaining;
- // get the time remaining for the RTC timer to expire
- t_match = MAP_PRCMSlowClkCtrMatchGet();
- t_curr = MAP_PRCMSlowClkCtrGet();
- // get the time remaining in terms of slow clocks
- t_remaining = (t_match - t_curr);
- if (t_remaining > WAKEUP_TIME_HIB) {
- // subtract the time it takes for wakeup from hibernate
- t_remaining -= WAKEUP_TIME_HIB;
- // setup the LPDS wake time
- MAP_PRCMHibernateIntervalSet((uint32_t)t_remaining);
- // enable the wake source
- MAP_PRCMHibernateWakeupSourceEnable(PRCM_HIB_SLOW_CLK_CTR);
- return true;
- }
- // disable the timer as wake source
- MAP_PRCMLPDSWakeupSourceDisable(PRCM_HIB_SLOW_CLK_CTR);
- uint32_t f_seconds;
- uint16_t f_mseconds;
- // setup a timer interrupt immediately
- pyb_rtc_calc_future_time (FORCED_TIMER_INTERRUPT_MS, &f_seconds, &f_mseconds);
- MAP_PRCMRTCMatchSet(f_seconds, f_mseconds);
- // LPDS wake by timer was not possible, force an interrupt in active mode instead
- MAP_PRCMIntEnable(PRCM_INT_SLOW_CLK_CTR);
- return false;
- }
|