Commit 181fe501 authored by danicampora's avatar danicampora
Browse files

cc3200: Add RTC callback with wake-up from sleep capability.

parent 6de1b393
...@@ -54,12 +54,16 @@ ...@@ -54,12 +54,16 @@
/// print(rtc.datetime()) /// print(rtc.datetime())
/****************************************************************************** /******************************************************************************
DECLARE TYPES DECLARE CONSTANTS
******************************************************************************/
#define PYBRTC_CLOCK_FREQUENCY_HZ 32768
#define PYBRTC_MIN_INTERVAL_VALUE 25
/******************************************************************************
DEFINE TYPES
******************************************************************************/ ******************************************************************************/
typedef struct { typedef struct {
uint32_t alarm_sec; byte prwmode;
uint16_t alarm_msec;
uint8_t pwrmode;
} pybrtc_data_t; } pybrtc_data_t;
/****************************************************************************** /******************************************************************************
...@@ -92,11 +96,26 @@ void pybrtc_init(void) { ...@@ -92,11 +96,26 @@ void pybrtc_init(void) {
DECLARE PRIVATE FUNCTIONS DECLARE PRIVATE FUNCTIONS
******************************************************************************/ ******************************************************************************/
STATIC void pyb_rtc_callback_enable (mp_obj_t self_in) { STATIC void pyb_rtc_callback_enable (mp_obj_t self_in) {
// check the wake from param
if (pybrtc_data.prwmode & PYB_PWR_MODE_ACTIVE) {
// enable the slow clock interrupt
MAP_PRCMIntEnable(PRCM_INT_SLOW_CLK_CTR);
}
else {
// just in case it was already enabled before
MAP_PRCMIntDisable(PRCM_INT_SLOW_CLK_CTR);
}
pybsleep_configure_timer_wakeup (pybrtc_data.prwmode);
} }
STATIC void pyb_rtc_callback_disable (mp_obj_t self_in) { STATIC void pyb_rtc_callback_disable (mp_obj_t self_in) {
// check the wake from param
if (pybrtc_data.prwmode & PYB_PWR_MODE_ACTIVE) {
// enable the slow clock interrupt
MAP_PRCMIntDisable(PRCM_INT_SLOW_CLK_CTR);
}
// disable wake from ldps and hibernate
pybsleep_configure_timer_wakeup (PYB_PWR_MODE_ACTIVE);
} }
/******************************************************************************/ /******************************************************************************/
...@@ -171,6 +190,7 @@ STATIC mp_obj_t pyb_rtc_callback (mp_uint_t n_args, const mp_obj_t *pos_args, mp ...@@ -171,6 +190,7 @@ STATIC mp_obj_t pyb_rtc_callback (mp_uint_t n_args, const mp_obj_t *pos_args, mp
// check if any parameters were passed // check if any parameters were passed
mp_obj_t _callback = mpcallback_find((mp_obj_t)&pyb_rtc_obj); mp_obj_t _callback = mpcallback_find((mp_obj_t)&pyb_rtc_obj);
if (kw_args->used > 0 || _callback == mp_const_none) { if (kw_args->used > 0 || _callback == mp_const_none) {
uint32_t f_mseconds = args[3].u_int;
uint32_t seconds; uint32_t seconds;
uint16_t mseconds; uint16_t mseconds;
// get the seconds and the milliseconds from the RTC // get the seconds and the milliseconds from the RTC
...@@ -178,25 +198,26 @@ STATIC mp_obj_t pyb_rtc_callback (mp_uint_t n_args, const mp_obj_t *pos_args, mp ...@@ -178,25 +198,26 @@ STATIC mp_obj_t pyb_rtc_callback (mp_uint_t n_args, const mp_obj_t *pos_args, mp
mseconds = RTC_CYCLES_U16MS(mseconds); mseconds = RTC_CYCLES_U16MS(mseconds);
// configure the rtc alarm accordingly // configure the rtc alarm accordingly
seconds += args[3].u_int / 1000; seconds += f_mseconds / 1000;
mseconds += args[3].u_int - ((args[3].u_int / 1000) * 1000); mseconds += f_mseconds - ((f_mseconds / 1000) * 1000);
if (mseconds > 1000) {
seconds++; // set the match value
mseconds -= 1000; MAP_PRCMRTCMatchSet(seconds, mseconds);
}
// save the match data for later
// check the wake from param pybrtc_data.prwmode = args[4].u_int;
if (args[4].u_int & PYB_PWR_MODE_ACTIVE) {
MAP_PRCMRTCMatchSet(seconds, mseconds); // create the callback
}
// save the alarm config for later
pybrtc_data.alarm_sec = seconds;
pybrtc_data.alarm_msec = mseconds;
pybrtc_data.pwrmode = args[4].u_int;
// create the new callback
_callback = mpcallback_new ((mp_obj_t)&pyb_rtc_obj, args[1].u_obj, &pybrtc_cb_methods); _callback = mpcallback_new ((mp_obj_t)&pyb_rtc_obj, args[1].u_obj, &pybrtc_cb_methods);
// set the lpds callback
pybsleep_set_timer_lpds_callback(_callback);
// the interrupt priority is ignored since is already set to to highest level by the sleep module
// to make sure that the wakeup callbacks are always called first when resuming from sleep
// enable the interrupt (the object is not relevant here, the function already knows it)
pyb_rtc_callback_enable(NULL);
} }
return _callback; return _callback;
} }
......
...@@ -67,6 +67,9 @@ ...@@ -67,6 +67,9 @@
#define WAKEUP_TIME_LPDS (LPDS_UP_TIME + LPDS_DOWN_TIME + USER_OFFSET) // 20 msec #define WAKEUP_TIME_LPDS (LPDS_UP_TIME + LPDS_DOWN_TIME + USER_OFFSET) // 20 msec
#define WAKEUP_TIME_HIB (32768) // 1 s #define WAKEUP_TIME_HIB (32768) // 1 s
#define FORCED_TIMER_INTERRUPT_MS (1)
#define FAILED_SLEEP_DELAY_MS (FORCED_TIMER_INTERRUPT_MS * 3)
/****************************************************************************** /******************************************************************************
DECLARE PRIVATE TYPES DECLARE PRIVATE TYPES
******************************************************************************/ ******************************************************************************/
...@@ -110,6 +113,7 @@ typedef struct { ...@@ -110,6 +113,7 @@ typedef struct {
mp_obj_t wlan_lpds_wake_cb; mp_obj_t wlan_lpds_wake_cb;
mp_obj_t timer_lpds_wake_cb; mp_obj_t timer_lpds_wake_cb;
mp_obj_t gpio_lpds_wake_cb; mp_obj_t gpio_lpds_wake_cb;
uint timer_wake_pwrmode;
} pybsleep_wake_cb_t; } pybsleep_wake_cb_t;
/****************************************************************************** /******************************************************************************
...@@ -131,6 +135,8 @@ void pybsleep_suspend_exit (void); ...@@ -131,6 +135,8 @@ void pybsleep_suspend_exit (void);
STATIC void pybsleep_obj_wakeup (void); STATIC void pybsleep_obj_wakeup (void);
STATIC void PRCMInterruptHandler (void); STATIC void PRCMInterruptHandler (void);
STATIC void pybsleep_iopark (void); STATIC void pybsleep_iopark (void);
STATIC bool setup_timer_lpds_wake (void);
STATIC bool setup_timer_hibernate_wake (void);
/****************************************************************************** /******************************************************************************
DEFINE PUBLIC FUNCTIONS DEFINE PUBLIC FUNCTIONS
...@@ -151,8 +157,8 @@ void pybsleep_init0 (void) { ...@@ -151,8 +157,8 @@ void pybsleep_init0 (void) {
// disable all LPDS and hibernate wake up sources (WLAN is disabed/enabled before entering LDPS mode) // disable all LPDS and hibernate wake up sources (WLAN is disabed/enabled before entering LDPS mode)
MAP_PRCMLPDSWakeupSourceDisable(PRCM_LPDS_GPIO); MAP_PRCMLPDSWakeupSourceDisable(PRCM_LPDS_GPIO);
MAP_PRCMLPDSWakeupSourceDisable(PRCM_LPDS_TIMER); MAP_PRCMLPDSWakeupSourceDisable(PRCM_LPDS_TIMER);
MAP_PRCMHibernateWakeupSourceDisable(PRCM_HIB_SLOW_CLK_CTR | PRCM_HIB_GPIO2 | PRCM_HIB_GPIO4 | PRCM_HIB_GPIO13 | MAP_PRCMHibernateWakeupSourceDisable(PRCM_HIB_SLOW_CLK_CTR | PRCM_HIB_GPIO2 | PRCM_HIB_GPIO4 | PRCM_HIB_GPIO13 |
PRCM_HIB_GPIO17 | PRCM_HIB_GPIO11 | PRCM_HIB_GPIO24 | PRCM_HIB_GPIO26); PRCM_HIB_GPIO17 | PRCM_HIB_GPIO11 | PRCM_HIB_GPIO24 | PRCM_HIB_GPIO26);
// store the reset casue (if it's soft reset, leave it as it is) // store the reset casue (if it's soft reset, leave it as it is)
if (pybsleep_reset_cause != PYB_SLP_SOFT_RESET) { if (pybsleep_reset_cause != PYB_SLP_SOFT_RESET) {
...@@ -216,6 +222,10 @@ void pybsleep_set_timer_lpds_callback (mp_obj_t cb_obj) { ...@@ -216,6 +222,10 @@ void pybsleep_set_timer_lpds_callback (mp_obj_t cb_obj) {
pybsleep_wake_cb.timer_lpds_wake_cb = cb_obj; pybsleep_wake_cb.timer_lpds_wake_cb = cb_obj;
} }
void pybsleep_configure_timer_wakeup (uint pwrmode) {
pybsleep_wake_cb.timer_wake_pwrmode = pwrmode;
}
/****************************************************************************** /******************************************************************************
DEFINE PRIVATE FUNCTIONS DEFINE PRIVATE FUNCTIONS
******************************************************************************/ ******************************************************************************/
...@@ -405,6 +415,9 @@ STATIC void PRCMInterruptHandler (void) { ...@@ -405,6 +415,9 @@ STATIC void PRCMInterruptHandler (void) {
} }
break; break;
case PRCM_LPDS_TIMER: case PRCM_LPDS_TIMER:
// disable timer was wake-up source
pybsleep_wake_cb.timer_wake_pwrmode &= ~PYB_PWR_MODE_LPDS;
MAP_PRCMLPDSWakeupSourceDisable(PRCM_LPDS_TIMER);
if (pybsleep_wake_cb.timer_lpds_wake_cb) { if (pybsleep_wake_cb.timer_lpds_wake_cb) {
mpcallback_handler(pybsleep_wake_cb.timer_lpds_wake_cb); mpcallback_handler(pybsleep_wake_cb.timer_lpds_wake_cb);
} }
...@@ -466,6 +479,77 @@ STATIC void pybsleep_iopark (void) { ...@@ -466,6 +479,77 @@ STATIC void pybsleep_iopark (void) {
HWREG(0x4402E10C) = 0x00000E61; HWREG(0x4402E10C) = 0x00000E61;
} }
STATIC bool setup_timer_lpds_wake (void) {
uint64_t t_match, t_curr, t_remaining;
// get the time remaining for the RTC timer to expire
t_match = MAP_PRCMSlowClkCtrMatchGet();
t_curr = MAP_PRCMSlowClkCtrGet();
if (t_match > t_curr) {
// 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 for 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;
}
}
else {
// setup a timer interrupt immediately
MAP_PRCMRTCMatchSet(0, FORCED_TIMER_INTERRUPT_MS);
}
// disable the timer as wake source
MAP_PRCMLPDSWakeupSourceDisable(PRCM_LPDS_TIMER);
// LPDS wake by timer was not possible, force
// an interrupt in active mode instead
MAP_PRCMIntEnable(PRCM_INT_SLOW_CLK_CTR);
return false;
}
STATIC bool setup_timer_hibernate_wake (void) {
uint64_t t_match, t_curr, t_remaining;
// get the time remaining for the RTC timer to expire
t_match = MAP_PRCMSlowClkCtrMatchGet();
t_curr = MAP_PRCMSlowClkCtrGet();
if (t_match > t_curr) {
// 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;
}
}
else {
// setup a timer interrupt immediately
MAP_PRCMRTCMatchSet(0, FORCED_TIMER_INTERRUPT_MS);
}
// disable the timer as wake source
MAP_PRCMLPDSWakeupSourceDisable(PRCM_HIB_SLOW_CLK_CTR);
// hibernate wake by timer was not possible, force
// an interrupt in active mode instead
MAP_PRCMIntEnable(PRCM_INT_SLOW_CLK_CTR);
return false;
}
/******************************************************************************/ /******************************************************************************/
// Micro Python bindings; Sleep class // Micro Python bindings; Sleep class
...@@ -483,6 +567,16 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_sleep_idle_obj, pyb_sleep_idle); ...@@ -483,6 +567,16 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_sleep_idle_obj, pyb_sleep_idle);
STATIC mp_obj_t pyb_sleep_suspend (mp_obj_t self_in) { STATIC mp_obj_t pyb_sleep_suspend (mp_obj_t self_in) {
nlr_buf_t nlr; nlr_buf_t nlr;
// check if we should enable timer wake-up
if (pybsleep_wake_cb.timer_wake_pwrmode & PYB_PWR_MODE_LPDS) {
if (!setup_timer_lpds_wake()) {
// lpds entering is not possible, wait for the forced interrupt and return
pybsleep_wake_cb.timer_wake_pwrmode &= ~PYB_PWR_MODE_LPDS;
HAL_Delay (FAILED_SLEEP_DELAY_MS);
return mp_const_none;
}
}
// check if we need to enable network wake-up // check if we need to enable network wake-up
if (pybsleep_wake_cb.wlan_lpds_wake_cb) { if (pybsleep_wake_cb.wlan_lpds_wake_cb) {
MAP_PRCMLPDSWakeupSourceEnable (PRCM_LPDS_HOST_IRQ); MAP_PRCMLPDSWakeupSourceEnable (PRCM_LPDS_HOST_IRQ);
...@@ -498,6 +592,7 @@ STATIC mp_obj_t pyb_sleep_suspend (mp_obj_t self_in) { ...@@ -498,6 +592,7 @@ STATIC mp_obj_t pyb_sleep_suspend (mp_obj_t self_in) {
pybsleep_suspend_enter(); pybsleep_suspend_enter();
nlr_pop(); nlr_pop();
} }
// an exception is always raised when exiting suspend mode // an exception is always raised when exiting suspend mode
enable_irq(primsk); enable_irq(primsk);
...@@ -509,6 +604,15 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_sleep_suspend_obj, pyb_sleep_suspend); ...@@ -509,6 +604,15 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_sleep_suspend_obj, pyb_sleep_suspend);
/// Enters hibernate mode. Wake up sources should have been enable prior to /// Enters hibernate mode. Wake up sources should have been enable prior to
/// calling this method. /// calling this method.
STATIC mp_obj_t pyb_sleep_hibernate (mp_obj_t self_in) { STATIC mp_obj_t pyb_sleep_hibernate (mp_obj_t self_in) {
// check if we should enable timer wake-up
if (pybsleep_wake_cb.timer_wake_pwrmode & PYB_PWR_MODE_HIBERNATE) {
if (!setup_timer_hibernate_wake()) {
// hibernating is not possible, wait for the forced interrupt and return
pybsleep_wake_cb.timer_wake_pwrmode &= ~PYB_PWR_MODE_HIBERNATE;
HAL_Delay (FAILED_SLEEP_DELAY_MS);
return mp_const_none;
}
}
wlan_stop(); wlan_stop();
pybsleep_flash_powerdown(); pybsleep_flash_powerdown();
MAP_PRCMHibernateEnter(); MAP_PRCMHibernateEnter();
......
...@@ -71,5 +71,6 @@ void pybsleep_remove (const mp_obj_t obj); ...@@ -71,5 +71,6 @@ void pybsleep_remove (const mp_obj_t obj);
void pybsleep_set_wlan_lpds_callback (mp_obj_t cb_obj); void pybsleep_set_wlan_lpds_callback (mp_obj_t cb_obj);
void pybsleep_set_gpio_lpds_callback (mp_obj_t cb_obj); void pybsleep_set_gpio_lpds_callback (mp_obj_t cb_obj);
void pybsleep_set_timer_lpds_callback (mp_obj_t cb_obj); void pybsleep_set_timer_lpds_callback (mp_obj_t cb_obj);
void pybsleep_configure_timer_wakeup (uint pwrmode);
#endif /* PYBSLEEP_H_ */ #endif /* PYBSLEEP_H_ */
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment