summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorScott Shawcroft <scott@tannewt.org>2020-04-03 18:07:56 -0700
committerScott Shawcroft <scott@tannewt.org>2020-04-03 18:07:56 -0700
commite99cf6e441db5f8f3c6378cf0a0ce2b12f1b72cd (patch)
tree2985ddc568ecada1a70e6564be415ae9bdca8b72
parent7e69d30c027659540860af894342872129e4343f (diff)
Rework sleep timing
It didn't account for background task time and could end up sleeping for way longer than it should because the RTC compare time had already passed.
-rw-r--r--ports/atmel-samd/common-hal/pulseio/PulseIn.c13
-rw-r--r--ports/atmel-samd/supervisor/port.c1
-rw-r--r--supervisor/shared/tick.c33
3 files changed, 27 insertions, 20 deletions
diff --git a/ports/atmel-samd/common-hal/pulseio/PulseIn.c b/ports/atmel-samd/common-hal/pulseio/PulseIn.c
index 4ddee4933..54343a8e3 100644
--- a/ports/atmel-samd/common-hal/pulseio/PulseIn.c
+++ b/ports/atmel-samd/common-hal/pulseio/PulseIn.c
@@ -79,6 +79,11 @@ void pulsein_interrupt_handler(uint8_t channel) {
// Grab the current time first.
uint32_t current_overflow = overflow_count;
Tc* tc = tc_insts[pulsein_tc_index];
+ #ifdef SAMD51
+ tc->COUNT16.CTRLBSET.reg = TC_CTRLBSET_CMD_READSYNC;
+ while (tc->COUNT16.SYNCBUSY.bit.COUNT == 1 ||
+ tc->COUNT16.CTRLBSET.bit.CMD == TC_CTRLBSET_CMD_READSYNC_Val) {}
+ #endif
uint32_t current_count = tc->COUNT16.COUNT.reg;
pulseio_pulsein_obj_t* self = get_eic_channel_data(channel);
@@ -119,6 +124,12 @@ void pulsein_interrupt_handler(uint8_t channel) {
self->last_count = current_count;
}
+void pulsein_reset() {
+ refcount = 0;
+ pulsein_tc_index = 0xff;
+ overflow_count = 0;
+}
+
void common_hal_pulseio_pulsein_construct(pulseio_pulsein_obj_t* self,
const mcu_pin_obj_t* pin, uint16_t maxlen, bool idle_state) {
if (!pin->has_extint) {
@@ -189,8 +200,6 @@ void common_hal_pulseio_pulsein_construct(pulseio_pulsein_obj_t* self,
tc_enable_interrupts(pulsein_tc_index);
tc->COUNT16.CTRLBSET.reg = TC_CTRLBSET_CMD_RETRIGGER;
- //mp_printf(&mp_plat_print, "timer started\n");
-
overflow_count = 0;
}
refcount++;
diff --git a/ports/atmel-samd/supervisor/port.c b/ports/atmel-samd/supervisor/port.c
index 92ef35680..271faecd9 100644
--- a/ports/atmel-samd/supervisor/port.c
+++ b/ports/atmel-samd/supervisor/port.c
@@ -306,6 +306,7 @@ void reset_port(void) {
#endif
eic_reset();
#if CIRCUITPY_PULSEIO
+ pulsein_reset();
pulseout_reset();
pwmout_reset();
#endif
diff --git a/supervisor/shared/tick.c b/supervisor/shared/tick.c
index 516dff747..dc38e76f6 100644
--- a/supervisor/shared/tick.c
+++ b/supervisor/shared/tick.c
@@ -79,39 +79,36 @@ uint32_t supervisor_ticks_ms32() {
extern void run_background_tasks(void);
void PLACE_IN_ITCM(supervisor_run_background_tasks_if_tick)() {
- uint8_t subticks;
- uint64_t now = port_get_raw_ticks(&subticks);
-
- if (now == background_ticks && (subticks & 0x3) != 0) {
- return;
- }
- background_ticks = now;
-
+ // TODO: Add a global that can be set by anyone to indicate we should run background tasks. That
+ // way we can short circuit the background tasks early. We used to do it based on time but it
+ // breaks cases where we wake up for a short period and then sleep. If we skipped the last
+ // background task or more before sleeping we may end up starving a task like USB.
run_background_tasks();
}
-void supervisor_fake_tick() {
- uint32_t now = port_get_raw_ticks(NULL);
- background_ticks = (now - 1);
-}
-
void mp_hal_delay_ms(mp_uint_t delay) {
uint64_t start_tick = port_get_raw_ticks(NULL);
// Adjust the delay to ticks vs ms.
delay = delay * 1024 / 1000;
- uint64_t duration = 0;
- port_interrupt_after_ticks(delay);
- while (duration < delay) {
+ uint64_t end_tick = start_tick + delay;
+ int64_t remaining = delay;
+ while (remaining > 0) {
RUN_BACKGROUND_TASKS;
// Check to see if we've been CTRL-Ced by autoreload or the user.
if(MP_STATE_VM(mp_pending_exception) == MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception)) ||
MP_STATE_VM(mp_pending_exception) == MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_reload_exception))) {
break;
}
+ remaining = end_tick - port_get_raw_ticks(NULL);
+ // We break a bit early so we don't risk setting the alarm before the time when we call
+ // sleep.
+ if (remaining < 1) {
+ break;
+ }
+ port_interrupt_after_ticks(remaining);
// Sleep until an interrupt happens.
port_sleep_until_interrupt();
- duration = (port_get_raw_ticks(NULL) - start_tick);
- port_interrupt_after_ticks(duration);
+ remaining = end_tick - port_get_raw_ticks(NULL);
}
}