Fixed numeruous bus in CC26xx-CC13xx lpm
Bug fixes include: - keep interrupts disabled during lpm_sleep() so that we don't miss any interrupts we may have been expecting - check that the pending etimer isn't already expired (and don't sleep at all if it is) - check that the about-to-be scheduled rtimer wakeup is neither too far into the future nor too close into the future (or even in the past) before actually setting the interrupt (should fix #1509); If the time is out of bounds we use a default min or max value instead. - Correctly handle LPM_MODE_MAX_SUPPORTED set to zero (and added a macro for the zero value) so that sleeping can be disabled altogether - If no etimer is set, we specify a wakeup time which is reasonably far into the future instead of setting none at all (this will save on power consumption whenever no etimers are set). Also did a bit of refactoring in that some long functions were broken into multiple functions.
This commit is contained in:
parent
287092db42
commit
786aa19cbd
|
@ -76,6 +76,11 @@ LIST(modules_list);
|
||||||
* in less than STANDBY_MIN_DURATION rtimer ticks
|
* in less than STANDBY_MIN_DURATION rtimer ticks
|
||||||
*/
|
*/
|
||||||
#define STANDBY_MIN_DURATION (RTIMER_SECOND >> 11)
|
#define STANDBY_MIN_DURATION (RTIMER_SECOND >> 11)
|
||||||
|
#define MINIMAL_SAFE_SCHEDUAL 8u
|
||||||
|
#define MAX_SLEEP_TIME RTIMER_SECOND
|
||||||
|
#define DEFAULT_SLEEP_TIME RTIMER_SECOND
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
#define CLK_TO_RT(c) ((c) * (RTIMER_SECOND / CLOCK_SECOND))
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
/* Prototype of a function in clock.c. Called every time we come out of DS */
|
/* Prototype of a function in clock.c. Called every time we come out of DS */
|
||||||
void clock_update(void);
|
void clock_update(void);
|
||||||
|
@ -234,57 +239,12 @@ wake_up(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
void
|
static void
|
||||||
lpm_drop()
|
deep_sleep(void)
|
||||||
{
|
{
|
||||||
lpm_registered_module_t *module;
|
|
||||||
uint8_t max_pm = LPM_MODE_MAX_SUPPORTED;
|
|
||||||
uint8_t module_pm;
|
|
||||||
clock_time_t next_event;
|
|
||||||
|
|
||||||
uint32_t domains = LOCKABLE_DOMAINS;
|
uint32_t domains = LOCKABLE_DOMAINS;
|
||||||
|
lpm_registered_module_t *module;
|
||||||
|
|
||||||
/* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Collect max allowed PM permission from interested modules */
|
|
||||||
for(module = list_head(modules_list); module != NULL;
|
|
||||||
module = module->next) {
|
|
||||||
if(module->request_max_pm) {
|
|
||||||
module_pm = module->request_max_pm();
|
|
||||||
if(module_pm < max_pm) {
|
|
||||||
max_pm = module_pm;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 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 {
|
|
||||||
/*
|
/*
|
||||||
* Notify all registered modules that we are dropping to mode X. We do not
|
* Notify all registered modules that we are dropping to mode X. We do not
|
||||||
* need to do this for simple sleep.
|
* need to do this for simple sleep.
|
||||||
|
@ -302,7 +262,7 @@ lpm_drop()
|
||||||
for(module = list_head(modules_list); module != NULL;
|
for(module = list_head(modules_list); module != NULL;
|
||||||
module = module->next) {
|
module = module->next) {
|
||||||
if(module->shutdown) {
|
if(module->shutdown) {
|
||||||
module->shutdown(max_pm);
|
module->shutdown(LPM_MODE_DEEP_SLEEP);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Clear the bits specified in the lock */
|
/* Clear the bits specified in the lock */
|
||||||
|
@ -409,9 +369,109 @@ lpm_drop()
|
||||||
* unpending events so the handlers can fire
|
* unpending events so the handlers can fire
|
||||||
*/
|
*/
|
||||||
wake_up();
|
wake_up();
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static void
|
||||||
|
safe_schedule_rtimer(rtimer_clock_t time, rtimer_clock_t now, int pm)
|
||||||
|
{
|
||||||
|
rtimer_clock_t min_sleep;
|
||||||
|
rtimer_clock_t max_sleep;
|
||||||
|
|
||||||
|
min_sleep = now + MINIMAL_SAFE_SCHEDUAL;
|
||||||
|
max_sleep = now + MAX_SLEEP_TIME;
|
||||||
|
|
||||||
|
if(RTIMER_CLOCK_LT(time, min_sleep)) {
|
||||||
|
/* ensure that we schedule sleep a minimal number of ticks into the
|
||||||
|
future */
|
||||||
|
soc_rtc_schedule_one_shot(AON_RTC_CH1, min_sleep);
|
||||||
|
} else if((pm == LPM_MODE_SLEEP) && RTIMER_CLOCK_LT(max_sleep, time)) {
|
||||||
|
/* if max_pm is LPM_MODE_SLEEP, we could trigger the watchdog if we slept
|
||||||
|
for too long. */
|
||||||
|
soc_rtc_schedule_one_shot(AON_RTC_CH1, max_sleep);
|
||||||
|
} else {
|
||||||
|
soc_rtc_schedule_one_shot(AON_RTC_CH1, time);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static int
|
||||||
|
setup_sleep_mode(void)
|
||||||
|
{
|
||||||
|
rtimer_clock_t et_distance = 0;
|
||||||
|
|
||||||
|
lpm_registered_module_t *module;
|
||||||
|
int max_pm;
|
||||||
|
int module_pm;
|
||||||
|
int etimer_is_pending;
|
||||||
|
rtimer_clock_t now;
|
||||||
|
rtimer_clock_t et_time;
|
||||||
|
rtimer_clock_t next_trig;
|
||||||
|
|
||||||
|
max_pm = LPM_MODE_MAX_SUPPORTED;
|
||||||
|
now = RTIMER_NOW();
|
||||||
|
|
||||||
|
if((LPM_MODE_MAX_SUPPORTED == LPM_MODE_AWAKE) || process_nevents()) {
|
||||||
|
return LPM_MODE_AWAKE;
|
||||||
|
}
|
||||||
|
|
||||||
|
etimer_is_pending = etimer_pending();
|
||||||
|
|
||||||
|
if(etimer_is_pending) {
|
||||||
|
et_distance = CLK_TO_RT(etimer_next_expiration_time() - clock_time());
|
||||||
|
|
||||||
|
if(RTIMER_CLOCK_LT(et_distance, 1)) {
|
||||||
|
/* there is an etimer which is already expired; we shouldn't go to
|
||||||
|
sleep at all */
|
||||||
|
return LPM_MODE_AWAKE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
next_trig = soc_rtc_get_next_trigger();
|
||||||
|
if(RTIMER_CLOCK_LT(next_trig, now + STANDBY_MIN_DURATION)) {
|
||||||
|
return LPM_MODE_SLEEP;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Collect max allowed PM permission from interested modules */
|
||||||
|
for(module = list_head(modules_list); module != NULL;
|
||||||
|
module = module->next) {
|
||||||
|
if(module->request_max_pm) {
|
||||||
|
module_pm = module->request_max_pm();
|
||||||
|
if(module_pm < max_pm) {
|
||||||
|
max_pm = module_pm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reschedule AON RTC CH1 to fire just in time for the next etimer event */
|
||||||
|
if(etimer_is_pending) {
|
||||||
|
et_time = soc_rtc_last_isr_time() + et_distance;
|
||||||
|
|
||||||
|
safe_schedule_rtimer(et_time, now, max_pm);
|
||||||
|
} else {
|
||||||
|
/* set a maximal sleep period if no etimers are queued */
|
||||||
|
soc_rtc_schedule_one_shot(AON_RTC_CH1, now + DEFAULT_SLEEP_TIME);
|
||||||
|
}
|
||||||
|
|
||||||
|
return max_pm;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
lpm_drop()
|
||||||
|
{
|
||||||
|
uint8_t max_pm;
|
||||||
|
|
||||||
|
/* Critical. Don't get interrupted! */
|
||||||
|
ti_lib_int_master_disable();
|
||||||
|
|
||||||
|
max_pm = setup_sleep_mode();
|
||||||
|
|
||||||
|
/* Drop */
|
||||||
|
if(max_pm == LPM_MODE_SLEEP) {
|
||||||
|
lpm_sleep();
|
||||||
|
} else if(max_pm == LPM_MODE_DEEP_SLEEP) {
|
||||||
|
deep_sleep();
|
||||||
|
}
|
||||||
|
|
||||||
ti_lib_int_master_enable();
|
ti_lib_int_master_enable();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
void
|
void
|
||||||
|
|
|
@ -49,6 +49,7 @@
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
|
#define LPM_MODE_AWAKE 0
|
||||||
#define LPM_MODE_SLEEP 1
|
#define LPM_MODE_SLEEP 1
|
||||||
#define LPM_MODE_DEEP_SLEEP 2
|
#define LPM_MODE_DEEP_SLEEP 2
|
||||||
#define LPM_MODE_SHUTDOWN 3
|
#define LPM_MODE_SHUTDOWN 3
|
||||||
|
|
Loading…
Reference in a new issue