Improve CC13xx/CC26xx LPM logic

This commit applies a number of improvements to the logic used when trying to drop to a CC13xx/CC26xx low-power mode:

* We identify whether there are any pending etimers by using `etimer_pending()` instead of `etimer_next_expiration_time()`. This subsequently allows us to also identify whether an etimer is set to fire at time 0.
* We run a larger portion of the code with the global interrupt disabled. This prevents a number of messy conditions that can occur if an interrupt fires after we have started the low-power sequence.
* We check whether there are pending events earlier in the sequence.
* We make sure to schedule a next wakeup event even when an LPM module prohibits deep sleep and forces sleep instead.

This fixes some of the issues discussed in #1236
This commit is contained in:
George Oikonomou 2015-11-09 13:36:11 +00:00
parent 08fddb6598
commit 571cf9364a

View File

@ -244,8 +244,18 @@ lpm_drop()
uint32_t domains = LOCKABLE_DOMAINS;
/* Critical. Don't get interrupted! */
ti_lib_int_master_disable();
/* Check if any events fired before we turned interrupts off. If so, abort */
if(process_nevents()) {
ti_lib_int_master_enable();
return;
}
if(RTIMER_CLOCK_LT(soc_rtc_get_next_trigger(),
RTIMER_NOW() + STANDBY_MIN_DURATION)) {
ti_lib_int_master_enable();
lpm_sleep();
return;
}
@ -261,30 +271,20 @@ lpm_drop()
}
}
/* Check if any events fired during this process. Last chance to abort */
if(process_nevents()) {
return;
/* Reschedule AON RTC CH1 to fire just in time for the next etimer event */
next_event = etimer_next_expiration_time();
if(etimer_pending()) {
next_event = next_event - clock_time();
soc_rtc_schedule_one_shot(AON_RTC_CH1, soc_rtc_last_isr_time() +
(next_event * (RTIMER_SECOND / CLOCK_SECOND)));
}
/* Drop */
if(max_pm == LPM_MODE_SLEEP) {
ti_lib_int_master_enable();
lpm_sleep();
} else {
/* Critical. Don't get interrupted! */
ti_lib_int_master_disable();
/*
* Reschedule AON RTC CH1 to fire an event N ticks before the next etimer
* event
*/
next_event = etimer_next_expiration_time();
if(next_event) {
next_event = next_event - clock_time();
soc_rtc_schedule_one_shot(AON_RTC_CH1, soc_rtc_last_isr_time() +
(next_event * (RTIMER_SECOND / CLOCK_SECOND)));
}
/*
* Notify all registered modules that we are dropping to mode X. We do not
* need to do this for simple sleep.