cc3200: Add RTC callback with wake-up from sleep capability.
This commit is contained in:
parent
6de1b39368
commit
181fe5016c
|
@ -54,12 +54,16 @@
|
|||
/// print(rtc.datetime())
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE TYPES
|
||||
DECLARE CONSTANTS
|
||||
******************************************************************************/
|
||||
#define PYBRTC_CLOCK_FREQUENCY_HZ 32768
|
||||
#define PYBRTC_MIN_INTERVAL_VALUE 25
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE TYPES
|
||||
******************************************************************************/
|
||||
typedef struct {
|
||||
uint32_t alarm_sec;
|
||||
uint16_t alarm_msec;
|
||||
uint8_t pwrmode;
|
||||
byte prwmode;
|
||||
} pybrtc_data_t;
|
||||
|
||||
/******************************************************************************
|
||||
|
@ -92,11 +96,26 @@ void pybrtc_init(void) {
|
|||
DECLARE PRIVATE FUNCTIONS
|
||||
******************************************************************************/
|
||||
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) {
|
||||
|
||||
// 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
|
|||
// check if any parameters were passed
|
||||
mp_obj_t _callback = mpcallback_find((mp_obj_t)&pyb_rtc_obj);
|
||||
if (kw_args->used > 0 || _callback == mp_const_none) {
|
||||
uint32_t f_mseconds = args[3].u_int;
|
||||
uint32_t seconds;
|
||||
uint16_t mseconds;
|
||||
// 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
|
|||
mseconds = RTC_CYCLES_U16MS(mseconds);
|
||||
|
||||
// configure the rtc alarm accordingly
|
||||
seconds += args[3].u_int / 1000;
|
||||
mseconds += args[3].u_int - ((args[3].u_int / 1000) * 1000);
|
||||
if (mseconds > 1000) {
|
||||
seconds++;
|
||||
mseconds -= 1000;
|
||||
}
|
||||
seconds += f_mseconds / 1000;
|
||||
mseconds += f_mseconds - ((f_mseconds / 1000) * 1000);
|
||||
|
||||
// check the wake from param
|
||||
if (args[4].u_int & PYB_PWR_MODE_ACTIVE) {
|
||||
MAP_PRCMRTCMatchSet(seconds, mseconds);
|
||||
}
|
||||
// set the match value
|
||||
MAP_PRCMRTCMatchSet(seconds, mseconds);
|
||||
|
||||
// save the alarm config for later
|
||||
pybrtc_data.alarm_sec = seconds;
|
||||
pybrtc_data.alarm_msec = mseconds;
|
||||
pybrtc_data.pwrmode = args[4].u_int;
|
||||
// save the match data for later
|
||||
pybrtc_data.prwmode = args[4].u_int;
|
||||
|
||||
// create the new callback
|
||||
// create the callback
|
||||
_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;
|
||||
}
|
||||
|
|
|
@ -67,6 +67,9 @@
|
|||
#define WAKEUP_TIME_LPDS (LPDS_UP_TIME + LPDS_DOWN_TIME + USER_OFFSET) // 20 msec
|
||||
#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
|
||||
******************************************************************************/
|
||||
|
@ -110,6 +113,7 @@ typedef struct {
|
|||
mp_obj_t wlan_lpds_wake_cb;
|
||||
mp_obj_t timer_lpds_wake_cb;
|
||||
mp_obj_t gpio_lpds_wake_cb;
|
||||
uint timer_wake_pwrmode;
|
||||
} pybsleep_wake_cb_t;
|
||||
|
||||
/******************************************************************************
|
||||
|
@ -131,6 +135,8 @@ void pybsleep_suspend_exit (void);
|
|||
STATIC void pybsleep_obj_wakeup (void);
|
||||
STATIC void PRCMInterruptHandler (void);
|
||||
STATIC void pybsleep_iopark (void);
|
||||
STATIC bool setup_timer_lpds_wake (void);
|
||||
STATIC bool setup_timer_hibernate_wake (void);
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PUBLIC FUNCTIONS
|
||||
|
@ -151,8 +157,8 @@ void pybsleep_init0 (void) {
|
|||
// 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_TIMER);
|
||||
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);
|
||||
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);
|
||||
|
||||
// store the reset casue (if it's soft reset, leave it as it is)
|
||||
if (pybsleep_reset_cause != PYB_SLP_SOFT_RESET) {
|
||||
|
@ -216,6 +222,10 @@ void pybsleep_set_timer_lpds_callback (mp_obj_t 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
|
||||
******************************************************************************/
|
||||
|
@ -405,6 +415,9 @@ STATIC void PRCMInterruptHandler (void) {
|
|||
}
|
||||
break;
|
||||
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) {
|
||||
mpcallback_handler(pybsleep_wake_cb.timer_lpds_wake_cb);
|
||||
}
|
||||
|
@ -466,6 +479,77 @@ STATIC void pybsleep_iopark (void) {
|
|||
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
|
||||
|
||||
|
@ -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) {
|
||||
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
|
||||
if (pybsleep_wake_cb.wlan_lpds_wake_cb) {
|
||||
MAP_PRCMLPDSWakeupSourceEnable (PRCM_LPDS_HOST_IRQ);
|
||||
|
@ -498,6 +592,7 @@ STATIC mp_obj_t pyb_sleep_suspend (mp_obj_t self_in) {
|
|||
pybsleep_suspend_enter();
|
||||
nlr_pop();
|
||||
}
|
||||
|
||||
// an exception is always raised when exiting suspend mode
|
||||
enable_irq(primsk);
|
||||
|
||||
|
@ -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
|
||||
/// calling this method.
|
||||
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();
|
||||
pybsleep_flash_powerdown();
|
||||
MAP_PRCMHibernateEnter();
|
||||
|
|
|
@ -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_gpio_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_ */
|
||||
|
|
Loading…
Reference in New Issue