Skip to content

Commit 181fe50

Browse files
committed
cc3200: Add RTC callback with wake-up from sleep capability.
1 parent 6de1b39 commit 181fe50

3 files changed

Lines changed: 152 additions & 26 deletions

File tree

cc3200/mods/pybrtc.c

Lines changed: 45 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,16 @@
5454
/// print(rtc.datetime())
5555

5656
/******************************************************************************
57-
DECLARE TYPES
57+
DECLARE CONSTANTS
58+
******************************************************************************/
59+
#define PYBRTC_CLOCK_FREQUENCY_HZ 32768
60+
#define PYBRTC_MIN_INTERVAL_VALUE 25
61+
62+
/******************************************************************************
63+
DEFINE TYPES
5864
******************************************************************************/
5965
typedef struct {
60-
uint32_t alarm_sec;
61-
uint16_t alarm_msec;
62-
uint8_t pwrmode;
66+
byte prwmode;
6367
} pybrtc_data_t;
6468

6569
/******************************************************************************
@@ -92,11 +96,26 @@ void pybrtc_init(void) {
9296
DECLARE PRIVATE FUNCTIONS
9397
******************************************************************************/
9498
STATIC void pyb_rtc_callback_enable (mp_obj_t self_in) {
95-
99+
// check the wake from param
100+
if (pybrtc_data.prwmode & PYB_PWR_MODE_ACTIVE) {
101+
// enable the slow clock interrupt
102+
MAP_PRCMIntEnable(PRCM_INT_SLOW_CLK_CTR);
103+
}
104+
else {
105+
// just in case it was already enabled before
106+
MAP_PRCMIntDisable(PRCM_INT_SLOW_CLK_CTR);
107+
}
108+
pybsleep_configure_timer_wakeup (pybrtc_data.prwmode);
96109
}
97110

98111
STATIC void pyb_rtc_callback_disable (mp_obj_t self_in) {
99-
112+
// check the wake from param
113+
if (pybrtc_data.prwmode & PYB_PWR_MODE_ACTIVE) {
114+
// enable the slow clock interrupt
115+
MAP_PRCMIntDisable(PRCM_INT_SLOW_CLK_CTR);
116+
}
117+
// disable wake from ldps and hibernate
118+
pybsleep_configure_timer_wakeup (PYB_PWR_MODE_ACTIVE);
100119
}
101120

102121
/******************************************************************************/
@@ -171,32 +190,34 @@ STATIC mp_obj_t pyb_rtc_callback (mp_uint_t n_args, const mp_obj_t *pos_args, mp
171190
// check if any parameters were passed
172191
mp_obj_t _callback = mpcallback_find((mp_obj_t)&pyb_rtc_obj);
173192
if (kw_args->used > 0 || _callback == mp_const_none) {
193+
uint32_t f_mseconds = args[3].u_int;
174194
uint32_t seconds;
175195
uint16_t mseconds;
176196
// get the seconds and the milliseconds from the RTC
177197
MAP_PRCMRTCGet(&seconds, &mseconds);
178198
mseconds = RTC_CYCLES_U16MS(mseconds);
179199

180200
// configure the rtc alarm accordingly
181-
seconds += args[3].u_int / 1000;
182-
mseconds += args[3].u_int - ((args[3].u_int / 1000) * 1000);
183-
if (mseconds > 1000) {
184-
seconds++;
185-
mseconds -= 1000;
186-
}
187-
188-
// check the wake from param
189-
if (args[4].u_int & PYB_PWR_MODE_ACTIVE) {
190-
MAP_PRCMRTCMatchSet(seconds, mseconds);
191-
}
192-
193-
// save the alarm config for later
194-
pybrtc_data.alarm_sec = seconds;
195-
pybrtc_data.alarm_msec = mseconds;
196-
pybrtc_data.pwrmode = args[4].u_int;
197-
198-
// create the new callback
201+
seconds += f_mseconds / 1000;
202+
mseconds += f_mseconds - ((f_mseconds / 1000) * 1000);
203+
204+
// set the match value
205+
MAP_PRCMRTCMatchSet(seconds, mseconds);
206+
207+
// save the match data for later
208+
pybrtc_data.prwmode = args[4].u_int;
209+
210+
// create the callback
199211
_callback = mpcallback_new ((mp_obj_t)&pyb_rtc_obj, args[1].u_obj, &pybrtc_cb_methods);
212+
213+
// set the lpds callback
214+
pybsleep_set_timer_lpds_callback(_callback);
215+
216+
// the interrupt priority is ignored since is already set to to highest level by the sleep module
217+
// to make sure that the wakeup callbacks are always called first when resuming from sleep
218+
219+
// enable the interrupt (the object is not relevant here, the function already knows it)
220+
pyb_rtc_callback_enable(NULL);
200221
}
201222
return _callback;
202223
}

cc3200/mods/pybsleep.c

Lines changed: 106 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,9 @@
6767
#define WAKEUP_TIME_LPDS (LPDS_UP_TIME + LPDS_DOWN_TIME + USER_OFFSET) // 20 msec
6868
#define WAKEUP_TIME_HIB (32768) // 1 s
6969

70+
#define FORCED_TIMER_INTERRUPT_MS (1)
71+
#define FAILED_SLEEP_DELAY_MS (FORCED_TIMER_INTERRUPT_MS * 3)
72+
7073
/******************************************************************************
7174
DECLARE PRIVATE TYPES
7275
******************************************************************************/
@@ -110,6 +113,7 @@ typedef struct {
110113
mp_obj_t wlan_lpds_wake_cb;
111114
mp_obj_t timer_lpds_wake_cb;
112115
mp_obj_t gpio_lpds_wake_cb;
116+
uint timer_wake_pwrmode;
113117
} pybsleep_wake_cb_t;
114118

115119
/******************************************************************************
@@ -131,6 +135,8 @@ void pybsleep_suspend_exit (void);
131135
STATIC void pybsleep_obj_wakeup (void);
132136
STATIC void PRCMInterruptHandler (void);
133137
STATIC void pybsleep_iopark (void);
138+
STATIC bool setup_timer_lpds_wake (void);
139+
STATIC bool setup_timer_hibernate_wake (void);
134140

135141
/******************************************************************************
136142
DEFINE PUBLIC FUNCTIONS
@@ -151,8 +157,8 @@ void pybsleep_init0 (void) {
151157
// disable all LPDS and hibernate wake up sources (WLAN is disabed/enabled before entering LDPS mode)
152158
MAP_PRCMLPDSWakeupSourceDisable(PRCM_LPDS_GPIO);
153159
MAP_PRCMLPDSWakeupSourceDisable(PRCM_LPDS_TIMER);
154-
MAP_PRCMHibernateWakeupSourceDisable(PRCM_HIB_SLOW_CLK_CTR | PRCM_HIB_GPIO2 | PRCM_HIB_GPIO4 | PRCM_HIB_GPIO13 |
155-
PRCM_HIB_GPIO17 | PRCM_HIB_GPIO11 | PRCM_HIB_GPIO24 | PRCM_HIB_GPIO26);
160+
MAP_PRCMHibernateWakeupSourceDisable(PRCM_HIB_SLOW_CLK_CTR | PRCM_HIB_GPIO2 | PRCM_HIB_GPIO4 | PRCM_HIB_GPIO13 |
161+
PRCM_HIB_GPIO17 | PRCM_HIB_GPIO11 | PRCM_HIB_GPIO24 | PRCM_HIB_GPIO26);
156162

157163
// store the reset casue (if it's soft reset, leave it as it is)
158164
if (pybsleep_reset_cause != PYB_SLP_SOFT_RESET) {
@@ -216,6 +222,10 @@ void pybsleep_set_timer_lpds_callback (mp_obj_t cb_obj) {
216222
pybsleep_wake_cb.timer_lpds_wake_cb = cb_obj;
217223
}
218224

225+
void pybsleep_configure_timer_wakeup (uint pwrmode) {
226+
pybsleep_wake_cb.timer_wake_pwrmode = pwrmode;
227+
}
228+
219229
/******************************************************************************
220230
DEFINE PRIVATE FUNCTIONS
221231
******************************************************************************/
@@ -405,6 +415,9 @@ STATIC void PRCMInterruptHandler (void) {
405415
}
406416
break;
407417
case PRCM_LPDS_TIMER:
418+
// disable timer was wake-up source
419+
pybsleep_wake_cb.timer_wake_pwrmode &= ~PYB_PWR_MODE_LPDS;
420+
MAP_PRCMLPDSWakeupSourceDisable(PRCM_LPDS_TIMER);
408421
if (pybsleep_wake_cb.timer_lpds_wake_cb) {
409422
mpcallback_handler(pybsleep_wake_cb.timer_lpds_wake_cb);
410423
}
@@ -466,6 +479,77 @@ STATIC void pybsleep_iopark (void) {
466479
HWREG(0x4402E10C) = 0x00000E61;
467480
}
468481

482+
STATIC bool setup_timer_lpds_wake (void) {
483+
uint64_t t_match, t_curr, t_remaining;
484+
485+
// get the time remaining for the RTC timer to expire
486+
t_match = MAP_PRCMSlowClkCtrMatchGet();
487+
t_curr = MAP_PRCMSlowClkCtrGet();
488+
489+
if (t_match > t_curr) {
490+
// get the time remaining in terms of slow clocks
491+
t_remaining = (t_match - t_curr);
492+
if (t_remaining > WAKEUP_TIME_LPDS) {
493+
// subtract the time it takes for wakeup from lpds
494+
t_remaining -= WAKEUP_TIME_LPDS;
495+
t_remaining = (t_remaining > 0xFFFFFFFF) ? 0xFFFFFFFF: t_remaining;
496+
// setup the LPDS wake time
497+
MAP_PRCMLPDSIntervalSet((uint32_t)t_remaining);
498+
// enable the wake source
499+
MAP_PRCMLPDSWakeupSourceEnable(PRCM_LPDS_TIMER);
500+
return true;
501+
}
502+
}
503+
else {
504+
// setup a timer interrupt immediately
505+
MAP_PRCMRTCMatchSet(0, FORCED_TIMER_INTERRUPT_MS);
506+
}
507+
508+
// disable the timer as wake source
509+
MAP_PRCMLPDSWakeupSourceDisable(PRCM_LPDS_TIMER);
510+
511+
// LPDS wake by timer was not possible, force
512+
// an interrupt in active mode instead
513+
MAP_PRCMIntEnable(PRCM_INT_SLOW_CLK_CTR);
514+
515+
return false;
516+
}
517+
518+
STATIC bool setup_timer_hibernate_wake (void) {
519+
uint64_t t_match, t_curr, t_remaining;
520+
521+
// get the time remaining for the RTC timer to expire
522+
t_match = MAP_PRCMSlowClkCtrMatchGet();
523+
t_curr = MAP_PRCMSlowClkCtrGet();
524+
525+
if (t_match > t_curr) {
526+
// get the time remaining in terms of slow clocks
527+
t_remaining = (t_match - t_curr);
528+
if (t_remaining > WAKEUP_TIME_HIB) {
529+
// subtract the time it takes for wakeup from hibernate
530+
t_remaining -= WAKEUP_TIME_HIB;
531+
// setup the LPDS wake time
532+
MAP_PRCMHibernateIntervalSet((uint32_t)t_remaining);
533+
// enable the wake source
534+
MAP_PRCMHibernateWakeupSourceEnable(PRCM_HIB_SLOW_CLK_CTR);
535+
return true;
536+
}
537+
}
538+
else {
539+
// setup a timer interrupt immediately
540+
MAP_PRCMRTCMatchSet(0, FORCED_TIMER_INTERRUPT_MS);
541+
}
542+
543+
// disable the timer as wake source
544+
MAP_PRCMLPDSWakeupSourceDisable(PRCM_HIB_SLOW_CLK_CTR);
545+
546+
// hibernate wake by timer was not possible, force
547+
// an interrupt in active mode instead
548+
MAP_PRCMIntEnable(PRCM_INT_SLOW_CLK_CTR);
549+
550+
return false;
551+
}
552+
469553
/******************************************************************************/
470554
// Micro Python bindings; Sleep class
471555

@@ -483,6 +567,16 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_sleep_idle_obj, pyb_sleep_idle);
483567
STATIC mp_obj_t pyb_sleep_suspend (mp_obj_t self_in) {
484568
nlr_buf_t nlr;
485569

570+
// check if we should enable timer wake-up
571+
if (pybsleep_wake_cb.timer_wake_pwrmode & PYB_PWR_MODE_LPDS) {
572+
if (!setup_timer_lpds_wake()) {
573+
// lpds entering is not possible, wait for the forced interrupt and return
574+
pybsleep_wake_cb.timer_wake_pwrmode &= ~PYB_PWR_MODE_LPDS;
575+
HAL_Delay (FAILED_SLEEP_DELAY_MS);
576+
return mp_const_none;
577+
}
578+
}
579+
486580
// check if we need to enable network wake-up
487581
if (pybsleep_wake_cb.wlan_lpds_wake_cb) {
488582
MAP_PRCMLPDSWakeupSourceEnable (PRCM_LPDS_HOST_IRQ);
@@ -498,6 +592,7 @@ STATIC mp_obj_t pyb_sleep_suspend (mp_obj_t self_in) {
498592
pybsleep_suspend_enter();
499593
nlr_pop();
500594
}
595+
501596
// an exception is always raised when exiting suspend mode
502597
enable_irq(primsk);
503598

@@ -509,6 +604,15 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_sleep_suspend_obj, pyb_sleep_suspend);
509604
/// Enters hibernate mode. Wake up sources should have been enable prior to
510605
/// calling this method.
511606
STATIC mp_obj_t pyb_sleep_hibernate (mp_obj_t self_in) {
607+
// check if we should enable timer wake-up
608+
if (pybsleep_wake_cb.timer_wake_pwrmode & PYB_PWR_MODE_HIBERNATE) {
609+
if (!setup_timer_hibernate_wake()) {
610+
// hibernating is not possible, wait for the forced interrupt and return
611+
pybsleep_wake_cb.timer_wake_pwrmode &= ~PYB_PWR_MODE_HIBERNATE;
612+
HAL_Delay (FAILED_SLEEP_DELAY_MS);
613+
return mp_const_none;
614+
}
615+
}
512616
wlan_stop();
513617
pybsleep_flash_powerdown();
514618
MAP_PRCMHibernateEnter();

cc3200/mods/pybsleep.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,5 +71,6 @@ void pybsleep_remove (const mp_obj_t obj);
7171
void pybsleep_set_wlan_lpds_callback (mp_obj_t cb_obj);
7272
void pybsleep_set_gpio_lpds_callback (mp_obj_t cb_obj);
7373
void pybsleep_set_timer_lpds_callback (mp_obj_t cb_obj);
74+
void pybsleep_configure_timer_wakeup (uint pwrmode);
7475

7576
#endif /* PYBSLEEP_H_ */

0 commit comments

Comments
 (0)