| | |
| | | #include "mk_i2c.h" |
| | | #endif |
| | | |
| | | #ifndef LOW_POWER_CLOCK_PPM |
| | | #define LOW_POWER_CLOCK_PPM (50) |
| | | #endif |
| | | |
| | | #ifndef SYS_CLK_SOURCE |
| | | #define SYS_CLK_SOURCE CLOCK_62P4M_XTAL38P4M_TO_SYS_CLK |
| | | #endif |
| | | |
| | | // Including 38.4MHz clock PLL ready time and application recovery time, unit: us |
| | | #define RECOVERY_TIME_FROM_LOW_POWER (1000) |
| | | /** XTAL32K clock source ppm */ |
| | | #ifndef LOW_POWER_CLOCK_PPM |
| | | #define LOW_POWER_CLOCK_PPM (100) |
| | | #endif |
| | | |
| | | // Considering 32KHz clock ppm and sleep time, x = sleep time (us), the result should < PHY_SLEEP_TIME_US_MIN |
| | | #define WAKEUP_IN_ADVANCE_TIME(x) (RECOVERY_TIME_FROM_LOW_POWER + (x)*LOW_POWER_CLOCK_PPM / 1000000) |
| | | /** RCO32K clock source ppm */ |
| | | #ifndef LOW_POWER_CLOCK_PPM_RCO |
| | | #define LOW_POWER_CLOCK_PPM_RCO (1000) |
| | | #endif |
| | | |
| | | // Including 38.4MHz clock PLL ready time and application recovery time, unit: 32768Hz tick. 32tick ~= 1ms |
| | | #define RECOVERY_TIME_FROM_LOW_POWER (32) |
| | | |
| | | // Considering 32KHz clock ppm and power down time, x = low power ticks to power down ( unit: 32768 tick) |
| | | #define WAKEUP_IN_ADVANCE_TIME(x) \ |
| | | (x - (RECOVERY_TIME_FROM_LOW_POWER + (x) * ((SYSCON->SYS_CMU & SYSCON_SYS_CMU_32K_CLK_SEL_MSK) ? LOW_POWER_CLOCK_PPM : LOW_POWER_CLOCK_PPM_RCO) / 1000000)) |
| | | |
| | | #ifdef UWB_EN |
| | | extern uint32_t slp_cnt; |
| | |
| | | } |
| | | else |
| | | { |
| | | // enable PMU, disable Xtal32k |
| | | SYSCON->PMU_CTRL0 |= (1U << 31) | (1 << 7); |
| | | // enable PMU |
| | | SYSCON->PMU_CTRL0 |= (1U << 31); |
| | | } |
| | | |
| | | // DG REF from LP_BG |
| | |
| | | NVIC_ClearPendingIRQ(WAKEUP_IRQn); |
| | | NVIC_EnableIRQ(WAKEUP_IRQn); |
| | | |
| | | // flash power down - by flash_close() |
| | | flash_power_down(FLASH_ID0); |
| | | |
| | | uint8_t val = REG_READ_BYTE(EFUSE_SHADOW_BASE + 0x67); |
| | | if ((val & 0x80) == 0) |
| | | { |
| | | // flash power down - by flash_close() |
| | | flash_power_down(FLASH_ID0); |
| | | // switch to external flash io |
| | | REG_WRITE_BYTE(EFUSE_SHADOW_BASE + 0x67, val | 0x80); |
| | | } |
| | |
| | | SYSCON->IO_SLP_PUP[0] = SYSCON->IO_PUP[0]; |
| | | SYSCON->IO_SLP_PUP[1] = SYSCON->IO_PUP[1]; |
| | | SYSCON->IO_SLP_PUP[2] = SYSCON->IO_PUP[2]; |
| | | // SYSCON->IO_SLP_AEN |= (1U << 31); |
| | | |
| | | // reduce DG current 60% |
| | | SYSCON->CAP_DIV_CFG = 0x0; |
| | |
| | | // Clock on - CALIB |
| | | SYSCON->SYS_CMU |= (1U << CLOCK_CALIB); |
| | | |
| | | SYSCON->CAP_DIV_CFG = 0x7; |
| | | |
| | | if ((val & 0x80) == 0) |
| | | { |
| | | // switch to internal flash io |
| | | REG_WRITE_BYTE(EFUSE_SHADOW_BASE + 0x67, val & 0x7f); |
| | | // flash power up |
| | | flash_power_up(FLASH_ID0); |
| | | } |
| | | |
| | | SYSCON->CAP_DIV_CFG = 0x7; |
| | | |
| | | // flash power up |
| | | flash_power_up(FLASH_ID0); |
| | | |
| | | #ifdef XIP_EN |
| | | flash_open_for_xip(FLASH_ID0); |
| | | #endif |
| | | |
| | | NVIC_DisableIRQ(WAKEUP_IRQn); |
| | | NVIC_ClearPendingIRQ(WAKEUP_IRQn); |
| | | |
| | | // Restore IO |
| | | GPIO->DATAOUT = SYSCON->IO_SLP_OUT; |
| | | GPIO->OUTENSET = SYSCON->IO_SLP_OE; |
| | | // SYSCON->IO_SLP_AEN &= ~(1U << 31); |
| | | |
| | | #ifdef SWD_WAKEUP_EN |
| | | // power_swd_restore(); |
| | |
| | | SYSCON->PMU_CTRL1 &= ~((1U << 7) | (1U << 5)); |
| | | } |
| | | |
| | | // switch system clock from XTAL to RO |
| | | // switch system clock from XTAL_38M4 to RO_48M |
| | | clock_attach(CLOCK_48M_RO_TO_SYS_CLK); |
| | | |
| | | // for XIP |
| | |
| | | // REFPLL - ON |
| | | SYSCON->PMU_CTRL0 &= ~(1U << 10); |
| | | |
| | | // switch system clock from RO to XTAL |
| | | // switch system clock from RO_48M to XTAL_38M4 |
| | | clock_attach(SYS_CLK_SOURCE); |
| | | |
| | | #ifdef UWB_EN |
| | |
| | | } |
| | | |
| | | #ifdef UWB_EN |
| | | /* |
| | | * nextExpiration can also be zero for an active timer, as said in WsfTimerNextExpiration's brief. |
| | | * But we are calling this WsfTimerNextExpiration with |
| | | * 1. disabling global interrupt at first, (at the beginning of power_manage()) |
| | | * 2. then checking WSF_TIMER_EVENT is not set (POWER_UNIT_OS is cleared for all power modes). |
| | | * So here nextExpiration can not be zero for an active wsf timer. |
| | | */ |
| | | static uint32_t os_timer_tick_left(void) |
| | | { |
| | | uint32_t left = UINT32_MAX; |
| | | |
| | | #ifdef WSF_EN |
| | | uint32_t nextExpiration = WsfTimerNextExpiration(); |
| | | |
| | | if (nextExpiration != UINT32_MAX) |
| | | { |
| | | uint32_t elapsed_ticks = sys_tick_elapse_ticks(); |
| | | if (nextExpiration > elapsed_ticks) |
| | | left = nextExpiration - elapsed_ticks; |
| | | else |
| | | left = 0; |
| | | } |
| | | #endif |
| | | return left; |
| | | } |
| | | |
| | | #ifdef WSF_EN |
| | | static wsfTimer_t phy_pd_ctrl_timer = { |
| | | .msg = |
| | | { |
| | | .event = PHY_PD_TIMER_EVENT, |
| | | }, |
| | | }; |
| | | #endif |
| | | |
| | | static void power_check_uwb_power_mode(void) |
| | | { |
| | | enum POWER_MODE_T pm; |
| | | // check os timer |
| | | uint32_t os_time_ms = PHY_SLEEP_TIME_MS_MAX; |
| | | uint32_t phy_time_us = PHY_SLEEP_TIME_MS_MAX * 1000; |
| | | enum POWER_MODE_T pm = POWER_MODE_SLEEP; |
| | | |
| | | #ifdef WSF_EN |
| | | if (wsfOsReadyToSleep()) |
| | | // power_check_if_power_mode() may request active or sleep mode, then abort here |
| | | if ((false == mac_is_busy()) && (power_env.power_request[POWER_MODE_SLEEP] == 0)) |
| | | { |
| | | pm = WsfTimerSleepCheck(&os_time_ms); |
| | | |
| | | if (pm) |
| | | uint32_t pd_tick = phy_timer_lp_tick_left(); |
| | | if (pd_tick != UINT32_MAX) |
| | | { |
| | | #endif |
| | | uint8_t busy = mac_is_busy(); |
| | | if (busy) |
| | | { |
| | | pm = POWER_MODE_SLEEP; |
| | | } |
| | | else |
| | | { |
| | | if (phy_timer_is_programmed()) |
| | | { |
| | | // check phy timer |
| | | uint32_t phy_time_tick = phy_timer_count_left(); |
| | | phy_time_us = PHY_TIMER_COUNT_TO_US(phy_time_tick); |
| | | } |
| | | pd_tick += sys_tick_elapse_ticks(); |
| | | WsfTimerStartTick(&phy_pd_ctrl_timer, pd_tick, WSF_TIMER_ONE_SHOT); |
| | | } |
| | | |
| | | // sleep time |
| | | uint32_t sleep_time_us = MIN((uint32_t)(os_time_ms * 1000), (uint32_t)phy_time_us); |
| | | |
| | | if (sleep_time_us > PHY_SLEEP_TIME_US_MIN) |
| | | { |
| | | pm = POWER_MODE_POWER_DOWN; |
| | | // make sure wakeup in advance, need to correct by 32K ppm |
| | | sleep_time_us -= WAKEUP_IN_ADVANCE_TIME(sleep_time_us); |
| | | |
| | | uint32_t sleep_time_tick = __US_TO_32K_CNT(sleep_time_us); |
| | | |
| | | sleep_timer_start(sleep_time_tick); |
| | | } |
| | | else |
| | | { |
| | | pm = POWER_MODE_SLEEP; |
| | | } |
| | | } |
| | | #ifdef WSF_EN |
| | | pd_tick = os_timer_tick_left(); |
| | | if (pd_tick > POWER_DOWN_TIME_TICK_MIN) |
| | | { |
| | | pm = POWER_MODE_POWER_DOWN; |
| | | // make sure wakeup in advance, need to correct by 32K ppm |
| | | sleep_timer_start(WAKEUP_IN_ADVANCE_TIME(pd_tick)); |
| | | } |
| | | else if (pd_tick == UINT32_MAX) |
| | | { |
| | | pm = POWER_MODE_DEEP_POWER_DOWN; |
| | | } |
| | | } |
| | | else |
| | | { |
| | | pm = POWER_MODE_ACTIVE; |
| | | } |
| | | #endif |
| | | |
| | | power_mode_request(POWER_UNIT_UWB, pm); |
| | | } |
| | | #endif |
| | |
| | | |
| | | // check GPIO wakeup source |
| | | power_check_io_power_mode(); |
| | | // check interface wakeup source |
| | | power_check_if_power_mode(); |
| | | |
| | | if (power_env.power_request[POWER_MODE_ACTIVE]) |
| | | { |
| | |
| | | #ifdef UWB_EN |
| | | power_check_uwb_power_mode(); |
| | | #endif |
| | | power_check_if_power_mode(); |
| | | |
| | | if (power_env.power_request[POWER_MODE_ACTIVE]) |
| | | { |
| | | // stay in active mode |
| | | } |
| | | else if (power_env.power_request[POWER_MODE_SLEEP]) |
| | | if (power_env.power_request[POWER_MODE_SLEEP]) |
| | | { |
| | | // enter sleep mode |
| | | power_enter_sleep_mode(); |
| | |
| | | power_enter_shelf_mode(); |
| | | } |
| | | |
| | | power_clear_if_power_mode(); |
| | | #ifdef UWB_EN |
| | | power_mode_clear(POWER_UNIT_UWB); |
| | | #endif |
| | | } |
| | | |
| | | // uint32_t int_pending = REG_READ(0xE000E200); |
| | | power_clear_if_power_mode(); |
| | | |
| | | int_unlock(lock); |
| | | |
| | | if (wakeup_from_power_down) |