summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authordanicampora <danicampora@gmail.com>2015-03-17 13:20:15 +0100
committerdanicampora <danicampora@gmail.com>2015-03-17 13:26:08 +0100
commit181fe5016c6b9c0fbe0eae10a03ffa3c3c480338 (patch)
treea3e1d8be433a5c1a1f5b64e285aa80e7a53a9eb0
parent6de1b39368efc27d7a90d64f28f99b9e46422f5b (diff)
downloadmicropython-181fe5016c6b9c0fbe0eae10a03ffa3c3c480338.tar.gz
micropython-181fe5016c6b9c0fbe0eae10a03ffa3c3c480338.zip
cc3200: Add RTC callback with wake-up from sleep capability.
-rw-r--r--cc3200/mods/pybrtc.c69
-rw-r--r--cc3200/mods/pybsleep.c108
-rw-r--r--cc3200/mods/pybsleep.h1
3 files changed, 152 insertions, 26 deletions
diff --git a/cc3200/mods/pybrtc.c b/cc3200/mods/pybrtc.c
index 686bfcc1a9..4d22c85f76 100644
--- a/cc3200/mods/pybrtc.c
+++ b/cc3200/mods/pybrtc.c
@@ -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;
- }
-
- // check the wake from param
- if (args[4].u_int & PYB_PWR_MODE_ACTIVE) {
- 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;
-
- // create the new callback
+ seconds += f_mseconds / 1000;
+ mseconds += f_mseconds - ((f_mseconds / 1000) * 1000);
+
+ // set the match value
+ MAP_PRCMRTCMatchSet(seconds, mseconds);
+
+ // save the match data for later
+ pybrtc_data.prwmode = args[4].u_int;
+
+ // 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;
}
diff --git a/cc3200/mods/pybsleep.c b/cc3200/mods/pybsleep.c
index aa87e5fd41..2a519f5e94 100644
--- a/cc3200/mods/pybsleep.c
+++ b/cc3200/mods/pybsleep.c
@@ -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();
diff --git a/cc3200/mods/pybsleep.h b/cc3200/mods/pybsleep.h
index 17833669b1..7835153784 100644
--- a/cc3200/mods/pybsleep.h
+++ b/cc3200/mods/pybsleep.h
@@ -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_ */