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; }
/* 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; }
/* Timer based wakeup from S4 (HIB) */ static i32 check_n_setup_S4_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_HIB) { /* Subtract the time it takes for wakeup from S4 (HIB) */ scc_remaining -= WAKEUP_TIME_HIB; /* Setup the HIB wake time */ MAP_PRCMHibernateIntervalSet(scc_remaining); /* Enable the wake source to be RTC */ MAP_PRCMHibernateWakeupSourceEnable( PRCM_HIB_SLOW_CLK_CTR); } else { /* Cannot enter HIB */ return ERR_TIMER_TO_WAKE; } } else { return -1; } } else { /* Disable Timer as wake source */ MAP_PRCMHibernateWakeupSourceDisable(PRCM_HIB_SLOW_CLK_CTR); 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(); } }