#include "FreeRTOS.h" #include "task.h" #include "soc_api.h" #if BLE_EN #include "pan_ble.h" #endif #if CONFIG_SYSTEM_WATCH_DOG_ENABLE extern void WDT_Stop(void); extern void WDT_Start(void); void system_watch_dog_init(void) { CLK_APB1PeriphClockCmd(CLK_APB1Periph_WDT | CLK_APB1Periph_MILI_CLK, ENABLE); // Select Clock Source CLK_SetWdtClkSrc(CLK_APB1_WDTSEL_MILLI_PULSE); // Enable WDT, disable Reset Mode, disable Wakeup Signal WDT_Open(WDT_TIMEOUT_2POW16, WDT_RESET_DELAY_2CLK, TRUE, FALSE); WDT_Start(); } #endif /* CONFIG_SYSTEM_WATCH_DOG_ENABLE */ #if (CONFIG_OS_EN && configUSE_TICKLESS_IDLE) extern void vPortSysTickRestart(uint32_t tick); /*************** Do not modify these definition ***************/ #define SETUP_TIME 14 #ifdef IP_107x #define WAKEUP_CNT (2 + LP_DLY_TICK + 7) #elif defined(IP_101x) #define WAKEUP_CNT (2 + LP_DLY_TICK + 7 + 4) #endif #define REG_CNT 30 #define MINIEST_SLP_CNT 25 #define LP_TIMER_FOREVER 0xFFFFFFFF extern uint32_t ulTimerCountsForOneTick; extern void UpdateTickAndSch(void); extern const uint32_t PanFlashLineMode; extern const bool PanFlashEnhanceEnable; volatile static bool ble_more_closer = false; /*************************************************************/ void sleep_timer0_handler(void) { /* Overrides the default slptmr 0 handler defined in soc_pm.c and just do nothing here */ } CONFIG_RAM_CODE void deepsleep_pre_process( uint32_t xLP_SleepTime ) { #if 1//CONFIG_KEEP_FLASH_POWER_IN_LP_MODE // Enable flash auto dp FLCTL->X_FL_DP_CTL |= 1u; #endif /* Set timeout of slptmr0 (for os tick use) */ ANA->LP_SPACING_TIME0 = (xLP_SleepTime - WAKEUP_CNT); /* Insure we are going to enter hw-deep-sleep mode */ SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk; ANA->LP_FL_CTRL_3V = (ANA->LP_FL_CTRL_3V & ~ANAC_FL_SLEEP_MODE_SEL_Msk) | (LP_MODE_SEL_DEEPSLEEP_MODE << ANAC_FL_SLEEP_MODE_SEL_Pos); /* Do AON register (3v) sync manually */ ANA->LP_REG_SYNC |= ANAC_LP_REG_SYNC_3V_Msk | ANAC_LP_REG_SYNC_3V_TRG_Msk; while(ANA->LP_REG_SYNC & (ANAC_LP_REG_SYNC_3V_TRG_Msk)); } CONFIG_RAM_CODE void deepsleep_post_process( uint32_t xExpectedIdleTime ) { /* Clear CPU core deepsleep ctrl flag */ SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk; /* Reset SoC lp mode to sleep mode (1.2v area, do not need 3v sync) */ ANA->LP_FL_CTRL_3V = (ANA->LP_FL_CTRL_3V & ~ANAC_FL_SLEEP_MODE_SEL_Msk) | (LP_MODE_SEL_SLEEP_MODE << ANAC_FL_SLEEP_MODE_SEL_Pos); #if 1//CONFIG_KEEP_FLASH_POWER_IN_LP_MODE // Re-disable flash auto dp FLCTL->X_FL_DP_CTL &= ~1u; #endif #if 0 /* Wait for 3v sync ready in case that cpu may be waked up too quick */ ANA->LP_REG_SYNC |= (ANAC_LP_REG_SYNC_3V_Msk | ANAC_LP_REG_SYNC_3V_TRG_Msk); while (ANA->LP_REG_SYNC & ANAC_LP_REG_SYNC_3V_TRG_Msk) {} #endif #if BLE_EN pan_ll_pm_post_handler(); #endif } #if BLE_EN CONFIG_RAM_CODE uint32_t pan_deep_sleep_flow(TickType_t xExpectedIdleTime) { uint32_t ll_remain_sleep_cyc = pan_get_ll_idle_time(); uint32_t os_decided_sleep_cyc; if(xExpectedIdleTime == portMAX_DELAY) { os_decided_sleep_cyc = LP_TIMER_FOREVER; } else { os_decided_sleep_cyc = (uint32_t)xExpectedIdleTime; } /* Check if the active 32K is used to LL timer */ if (ANA->ACT_32K_CTRL & ANAC_ACT_32K_SEL_Msk) { return 0; } /* * Update final sleep time to meet the need of BLE Controller if it needs * an earlier wakeup than other threads. */ if (ll_remain_sleep_cyc < os_decided_sleep_cyc) { ble_more_closer = true; if ((ll_remain_sleep_cyc > (SETUP_TIME + WAKEUP_CNT + REG_CNT)) && (ll_remain_sleep_cyc < 400000)) { if (rf_check_sleep_state()) { return ll_remain_sleep_cyc; } else { /* Fall back to Sleep Flow */ return 0; } } else { /* Fall back to Sleep Flow */ return 0; } } else { ble_more_closer = false; if (rf_check_sleep_state()) { if (os_decided_sleep_cyc > (MINIEST_SLP_CNT)) { return os_decided_sleep_cyc; } else { /* Fall back to Sleep Flow */ return 0; } } else { /* Fall back to Sleep Flow */ return 0; } } } #else /*deep sleep check without ble event*/ CONFIG_RAM_CODE uint32_t pan_deep_sleep_flow(TickType_t xExpectedIdleTime) { uint32_t os_decided_sleep_cyc; if(xExpectedIdleTime == portMAX_DELAY) { os_decided_sleep_cyc = LP_TIMER_FOREVER; } else { os_decided_sleep_cyc = (uint32_t)xExpectedIdleTime; } /* Check if the active 32K is used to LL timer */ if (ANA->ACT_32K_CTRL & ANAC_ACT_32K_SEL_Msk) { return 0; } if (os_decided_sleep_cyc > (MINIEST_SLP_CNT)) { return os_decided_sleep_cyc; } else { /* Fall back to Sleep Flow */ return 0; } } #endif /* * This function can be override by APP to add customized procedure * BEFORE SoC enter DeepSleep State */ __WEAK void vSocDeepSleepEnterHook(void) { /* Do nothing here */ } /* * This function can be override by APP to add customized procedure * AFTER SoC exit DeepSleep State */ __WEAK void vSocDeepSleepExitHook(void) { /* Do nothing here */ } __WEAK uint8_t user_is_sleep_allow(void) { return true; } CONFIG_RAM_CODE void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime ) { uint32_t xLPSleepTime; eSleepModeStatus eSleepStatus; /* Enter a critical section but don't use the taskENTER_CRITICAL() * method as that will mask interrupts that should exit sleep mode. */ __set_PRIMASK(1); /* If a context switch is pending or a task is waiting for the scheduler * to be unsuspended then abandon the low power entry. */ eSleepStatus = eTaskConfirmSleepModeStatus(); if( eSleepStatus == eAbortSleep ) { vTaskTickSet(lp_get_curr_tmr_cnt()); vTaskStepTick(0); /* Re-enable interrupts - see comments above the __disable_irq() * call above. */ __set_PRIMASK(0); return; } /* Sleep until something happens. configPRE_SLEEP_PROCESSING() can * set its parameter to 0 to indicate that its implementation contains * its own wait for interrupt or wait for event instruction, and so wfi * should not be executed again. However, the original expected idle * time variable must remain unmodified, so a copy is taken. */ xLPSleepTime = pan_deep_sleep_flow(xExpectedIdleTime); if(!user_is_sleep_allow()){ goto user_sleep_enter; } if(xLPSleepTime) { /* Stop the SysTick momentarily. The time the SysTick is stopped for * is accounted for as best it can be, but using the tickless mode will * inevitably result in some tiny drift of the time maintained by the * kernel with respect to calendar time. */ SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; /* * This function can be override by APP to add customized procedure * BEFORE SoC enter DeepSleep State */ vSocDeepSleepEnterHook(); configPRE_SLEEP_PROCESSING( xModifiableIdleTime ); #if CONFIG_SYSTEM_WATCH_DOG_ENABLE WDT_Stop(); #endif /* Store and Clear NVIC Interrupt Enable Register */ uint32_t nvicInt = NVIC->ISER[0U]; NVIC->ICER[0U] = 0xFFFFFFFF; /* Enable LP IRQ to make sure related ISR would trigger after wake up */ NVIC_EnableIRQ(LP_IRQn); /* Deepsleep Pre handler */ deepsleep_pre_process( xLPSleepTime ); /* Records the time the current timestamp is used to calculate the sleep * value after the system wakes up */ vTaskTickSet(lp_get_curr_tmr_cnt()); PAN_IO_TIMING_TRACK_LEVEL(CONFIG_TRACK_PIN_DEEPSLEEP_MODE, 0); __WFI(); // Try to enter DeepSleep mode PAN_IO_TIMING_TRACK_LEVEL(CONFIG_TRACK_PIN_DEEPSLEEP_MODE, 1); /* Restore NVIC Interrupt Enable Register */ NVIC->ISER[0U] = nvicInt; #if ((!CONFIG_KEEP_FLASH_POWER_IN_LP_MODE) && (CONFIG_FLASH_LINE_MODE == FLASH_X4_MODE)) /* Set en_burst_wrap in FMC */ FLCTL->X_FL_X_MODE |= (0x1 << 16); /* Re-issue burst_wrap command to flash if is X4 mode */ FLCTL->X_FL_CTL = (0 << 8) | (0x05 << 0); FLCTL->X_FL_WD[0] = CMD_BURST_READ; FLCTL->X_FL_WD[4] = BURST_READ_MODE_32 << 5; FLCTL->X_FL_TRIG = CMD_TRIG; while (FLCTL->X_FL_TRIG) { __NOP(); } #endif #if CONFIG_SYSTEM_WATCH_DOG_ENABLE WDT_Start(); #endif /* Deepsleep Post handler */ deepsleep_post_process( xExpectedIdleTime ); configPOST_SLEEP_PROCESSING( xExpectedIdleTime ); UpdateTickAndSch(); /* restart systick, use configTICK_ON_WAKING_RATE_HZ */ vPortSysTickRestart(ulTimerCountsForOneTick); /* * This function can be override by APP to add customized procedure * AFTER SoC exit DeepSleep State */ vSocDeepSleepExitHook(); /* Exit with interrupts enabled. */ __set_PRIMASK(0); } else { /*enter mcu sleep, not deep sleep*/ user_sleep_enter: if(ble_more_closer) { /*system will wakeup from ble interrupt*/ #if !CONFIG_HCLK_OPTIMIZE_EN __set_PRIMASK(0); #endif #if CONFIG_SYSTEM_WATCH_DOG_ENABLE WDT_Stop(); #endif PAN_IO_TIMING_TRACK_LEVEL(CONFIG_TRACK_PIN_SLEEP_MODE, 0); #if CONFIG_HCLK_OPTIMIZE_EN uint32_t tmp = CLK->CLK_TOP_CTRL_3V; //CLK_HCLKConfig(15); // 4MHz CLK_HCLKConfig(7); // 8MHz //CLK_HCLKConfig(3); // 16MHz __WFI(); CLK->CLK_TOP_CTRL_3V = tmp; __set_PRIMASK(0); #else __WFI(); #endif PAN_IO_TIMING_TRACK_LEVEL(CONFIG_TRACK_PIN_SLEEP_MODE, 1); #if CONFIG_SYSTEM_WATCH_DOG_ENABLE WDT_Start(); #endif } else { uint32_t lp_count = xExpectedIdleTime; /* Configure SysTick to interrupt at the requested rate. */ vPortSysTickRestart(ulTimerCountsForOneTick * lp_count); __set_PRIMASK(0); #if CONFIG_SYSTEM_WATCH_DOG_ENABLE WDT_Stop(); #endif PAN_IO_TIMING_TRACK_LEVEL(CONFIG_TRACK_PIN_SLEEP_MODE, 0); __WFI(); PAN_IO_TIMING_TRACK_LEVEL(CONFIG_TRACK_PIN_SLEEP_MODE, 1); #if CONFIG_SYSTEM_WATCH_DOG_ENABLE WDT_Start(); #endif } } } #endif /* CONFIG_OS_EN && configUSE_TICKLESS_IDLE */