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; }
//**************************************************************************** // //! \brief Setting various wake sources for the device //! //! \param target is the lowest power mode that the deveice will exercise //! //! \return 0 if success, -1 in case of error // //**************************************************************************** int set_wkup_srcs(enum soc_pm target) { int iRetVal = -1; switch(target) { case e_pm_S0: case e_pm_S1: case e_pm_S2: /* These handle the cases of run, sleep, deepsleep. Wake source is configured outside this scope in individual peripherals */ break; case e_pm_S3: if(lpds_wk_info.wk_type & WK_RTC) { /* Setup the LPDS wake time */ MAP_PRCMLPDSIntervalSet(lpds_wk_info.timer_interval * 32768); /* Enable the wake source to be timer */ MAP_PRCMLPDSWakeupSourceEnable(PRCM_LPDS_TIMER); iRetVal = 0; } if(lpds_wk_info.wk_type & WK_GPIO) { MAP_PRCMLPDSWakeUpGPIOSelect(lpds_wk_info.wk_gpio_pin,lpds_wk_info.trigger_type); MAP_PRCMLPDSWakeupSourceEnable(PRCM_LPDS_GPIO); iRetVal = 0; } if(lpds_wk_info.wk_type & WK_HOST_IRQ) { /* Set LPDS Wakeup source as NWP request */ MAP_PRCMLPDSWakeupSourceEnable(PRCM_LPDS_HOST_IRQ); iRetVal = 0; } if(lpds_wk_info.is_periodic == false) { lpds_wk_info.wk_type &= (~WK_RTC); } break; case e_pm_S4: if(hib_wk_info.wk_type & WK_RTC) { /* Setup the LPDS wake time */ MAP_PRCMHibernateIntervalSet(hib_wk_info.timer_interval * 32768); /* Enable the wake source to be timer */ MAP_PRCMHibernateWakeupSourceEnable(PRCM_HIB_SLOW_CLK_CTR); iRetVal = 0; } if(hib_wk_info.wk_type & WK_GPIO) { MAP_PRCMHibernateWakeUpGPIOSelect(hib_wk_info.wk_gpio_pin,hib_wk_info.trigger_type); MAP_PRCMHibernateWakeupSourceEnable(hib_wk_info.wk_gpio_pin); iRetVal = 0; } break; default: return -1; } return iRetVal; }
/* Sets up wake-up sources for indicated power mode */ i32 cc_set_up_wkup_srcs(enum soc_pm target) { i32 nw_ret = -1, gpio_ret = -1, timer_ret = -1; switch(target) { case e_pm_S0: case e_pm_S1: case e_pm_S2: /* These handle the cases of run, sleep, deepsleep. Wake source is configured outside this scope in individual peripherals */ break; case e_pm_S3: /* Low power deep sleep condition */ /* Network (Host IRQ) based wakeup is always enabled */ nw_ret = setup_S3_wakeup_from_nw(); /* Check and enable GPIO based wakeup */ gpio_ret = check_n_setup_S3_wakeup_from_gpio(); /* Check and enable LRT based wakeup */ timer_ret = check_n_setup_S3_wakeup_from_timer(); break; case e_pm_S4: /* Hibernate condition */ /* Check and enable GPIO based wakeup */ gpio_ret = check_n_setup_S4_wakeup_from_gpio(); /* Check and enable LRT based wakeup */ timer_ret = check_n_setup_S4_wakeup_from_timer(); break; default: break; } if(ERR_TIMER_TO_WAKE == timer_ret) { return -1; } if((nw_ret < 0) && (gpio_ret < 0) && (timer_ret < 0)) { return -1; } else if((gpio_ret < 0) && (timer_ret < 0)) { /* Setup the LPDS wake time */ MAP_PRCMLPDSIntervalSet(LPDS_WDOG_TIME); /* Enable the wake source to be timer */ MAP_PRCMLPDSWakeupSourceEnable( PRCM_LPDS_TIMER); } return 0; }
/* Timer based wakeup from S3 (LPDS) */ static i32 check_n_setup_S3_wakeup_from_timer() { u64 scc_match, scc_curr, scc_remaining; /* Check if there is an alarm set */ if(cc_rtc_has_alarm()) { /* Get the time remaining for the RTC timer to expire */ scc_match = MAP_PRCMSlowClkCtrMatchGet(); scc_curr = MAP_PRCMSlowClkCtrGet(); if(scc_match > scc_curr) { /* Get the time remaining in terms of slow clocks */ scc_remaining = (scc_match - scc_curr); if(scc_remaining > WAKEUP_TIME_LPDS) { /* Subtract the time it takes for wakeup from S3 (LPDS) */ scc_remaining -= WAKEUP_TIME_LPDS; scc_remaining = (scc_remaining > 0xFFFFFFFF)? 0xFFFFFFFF: scc_remaining; /* Setup the LPDS wake time */ MAP_PRCMLPDSIntervalSet( (u32)scc_remaining); /* Enable the wake source to be timer */ MAP_PRCMLPDSWakeupSourceEnable( PRCM_LPDS_TIMER); } else { /* Cannot enter LPDS */ return ERR_TIMER_TO_WAKE; } } else { return ERR_TIMER_TO_WAKE; } } else { /* Disable timer as the wake source */ MAP_PRCMLPDSWakeupSourceDisable(PRCM_LPDS_TIMER); return -1; } return 0; }
/* * ======== PowerCC3200_sleepPolicy ======== */ void PowerCC3200_sleepPolicy() { bool returnFromSleep = FALSE; uint32_t constraintMask; uint32_t ticks; uint64_t time; uint64_t match; uint64_t curr; uint64_t remain; uint32_t taskKey; uint32_t swiKey; /* disable interrupts */ CPUcpsid(); /* disable Swi and Task scheduling */ swiKey = Swi_disable(); taskKey = Task_disable(); /* query the declared constraints */ constraintMask = Power_getConstraintMask(); /* * Do not go into LPDS if not allowed into DEEPSLEEP. * Check to see if we can go into LPDS (lowest level sleep). * If not allowed, then attempt to go into DEEPSLEEP. * If not allowed in DEEPSLEEP then just SLEEP. */ /* check if we are allowed to go to LPDS */ if ((constraintMask & ((1 << PowerCC3200_DISALLOW_LPDS) | (1 << PowerCC3200_DISALLOW_DEEPSLEEP))) == 0) { /* * Check how many ticks until the next scheduled wakeup. A value of * zero indicates a wakeup will occur as the current Clock tick period * expires; a very large value indicates a very large number of Clock * tick periods will occur before the next scheduled wakeup. */ /* Get the time remaining for the RTC timer to expire */ ticks = Clock_getTicksUntilInterrupt(); /* convert ticks to microseconds */ time = ticks * Clock_tickPeriod; /* check if can go to LPDS */ if (time > Power_getTransitionLatency(PowerCC3200_LPDS, Power_TOTAL)) { /* get the current and match values for RTC */ match = MAP_PRCMSlowClkCtrMatchGet(); curr = MAP_PRCMSlowClkCtrGet(); remain = match - curr - (((uint64_t)PowerCC3200_TOTALTIMELPDS * 32768) / 1000000); /* set the LPDS wakeup time interval */ MAP_PRCMLPDSIntervalSet(remain); /* enable the wake source to be timer */ MAP_PRCMLPDSWakeupSourceEnable(PRCM_LPDS_TIMER); /* go to LPDS mode */ Power_sleep(PowerCC3200_LPDS); /* set 'returnFromSleep' to TRUE*/ returnFromSleep = TRUE; } } /* check if we are allowed to go to DEEPSLEEP */ if ((constraintMask & (1 << PowerCC3200_DISALLOW_DEEPSLEEP) == 0) && (!returnFromSleep)) { /* * Check how many ticks until the next scheduled wakeup. A value of * zero indicates a wakeup will occur as the current Clock tick period * expires; a very large value indicates a very large number of Clock * tick periods will occur before the next scheduled wakeup. */ ticks = Clock_getTicksUntilInterrupt(); /* convert ticks to microseconds */ time = ticks * Clock_tickPeriod; /* check if can go to DEEPSLEEP */ if (time > Power_getTransitionLatency(PowerCC3200_DEEPSLEEP, Power_TOTAL)) { /* schedule the wakeup event */ ticks -= PowerCC3200_RESUMETIMEDEEPSLEEP / Clock_tickPeriod; Clock_setTimeout(Clock_handle(&clockObj), ticks); Clock_start(Clock_handle(&clockObj)); /* go to DEEPSLEEP mode */ Power_sleep(PowerCC3200_DEEPSLEEP); Clock_stop(Clock_handle(&clockObj)); /* set 'returnFromSleep' to TRUE so we don't go to sleep (below) */ returnFromSleep = TRUE; } } /* re-enable interrupts */ CPUcpsie(); /* restore Swi scheduling */ Swi_restore(swiKey); /* restore Task scheduling */ Task_restore(taskKey); /* sleep only if we are not returning from one of the sleep modes above */ if (!(returnFromSleep)) { MAP_PRCMSleepEnter(); } }