From 379e73af2e55b1f0c517883360e29d5dbc27a20b Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Mon, 12 Oct 2020 18:36:18 -0700 Subject: [PATCH] Finer grained, per port tick locking Fixes #3504 hopefully. --- ports/atmel-samd/common-hal/pulseio/PulseIn.h | 1 - ports/atmel-samd/supervisor/port.c | 37 +++++++++++++------ ports/litex/supervisor/port.c | 6 ++- ports/nrf/supervisor/port.c | 6 ++- supervisor/shared/tick.c | 2 - 5 files changed, 35 insertions(+), 17 deletions(-) diff --git a/ports/atmel-samd/common-hal/pulseio/PulseIn.h b/ports/atmel-samd/common-hal/pulseio/PulseIn.h index 99358178f2..b91bbd703b 100644 --- a/ports/atmel-samd/common-hal/pulseio/PulseIn.h +++ b/ports/atmel-samd/common-hal/pulseio/PulseIn.h @@ -51,7 +51,6 @@ void pulsein_reset(void); void pulsein_interrupt_handler(uint8_t channel); void pulsein_timer_interrupt_handler(uint8_t index); #ifdef SAMD21 -void rtc_set_continuous(void); void rtc_start_pulsein(void); void rtc_end_pulsein(void); #endif diff --git a/ports/atmel-samd/supervisor/port.c b/ports/atmel-samd/supervisor/port.c index e69062296d..6686d794c4 100644 --- a/ports/atmel-samd/supervisor/port.c +++ b/ports/atmel-samd/supervisor/port.c @@ -96,19 +96,21 @@ #endif volatile bool hold_interrupt = false; #ifdef SAMD21 +static void rtc_set_continuous(bool continuous) { + while (RTC->MODE0.STATUS.bit.SYNCBUSY); + // TODO: DaveP: Do we need the RREQ here? + RTC->MODE0.READREQ.reg = RTC_READREQ_RREQ | (continuous ? RTC_READREQ_RCONT : 0) | 0x0010; + while (RTC->MODE0.STATUS.bit.SYNCBUSY); +} + void rtc_start_pulsein(void) { - rtc_set_continuous(); + rtc_set_continuous(true); hold_interrupt = true; } void rtc_end_pulsein(void) { hold_interrupt = false; -} - -void rtc_set_continuous(void) { - while (RTC->MODE0.STATUS.bit.SYNCBUSY); - RTC->MODE0.READREQ.reg = RTC_READREQ_RREQ | RTC_READREQ_RCONT | 0x0010; - while (RTC->MODE0.STATUS.bit.SYNCBUSY); + rtc_set_continuous(false); } #endif @@ -430,19 +432,28 @@ uint32_t port_get_saved_word(void) { static volatile uint64_t overflowed_ticks = 0; static volatile bool _ticks_enabled = false; -static uint32_t _get_count(void) { +static uint32_t _get_count(uint32_t* overflow_count) { #ifdef SAM_D5X_E5X while ((RTC->MODE0.SYNCBUSY.reg & (RTC_MODE0_SYNCBUSY_COUNTSYNC | RTC_MODE0_SYNCBUSY_COUNT)) != 0) {} #endif #ifdef SAMD21 + // Request a read so we don't stall the bus later. See section 14.3.1.5 Read Request + RTC->MODE0.READREQ.reg = RTC_READREQ_RREQ | 0x0010; while (RTC->MODE0.STATUS.bit.SYNCBUSY != 0) {} #endif + // Disable interrupts so we can grab the count and the overflow. + common_hal_mcu_disable_interrupts(); + uint32_t count = RTC->MODE0.COUNT.reg; + if (overflow_count != NULL) { + *overflow_count = overflowed_ticks; + } + common_hal_mcu_enable_interrupts(); - return RTC->MODE0.COUNT.reg; + return count; } static void _port_interrupt_after_ticks(uint32_t ticks) { - uint32_t current_ticks = _get_count(); + uint32_t current_ticks = _get_count(NULL); if (ticks > 1 << 28) { // We'll interrupt sooner with an overflow. return; @@ -490,12 +501,13 @@ void RTC_Handler(void) { } uint64_t port_get_raw_ticks(uint8_t* subticks) { - uint32_t current_ticks = _get_count(); + uint32_t overflow_count; + uint32_t current_ticks = _get_count(&overflow_count); if (subticks != NULL) { *subticks = (current_ticks % 16) * 2; } - return overflowed_ticks + current_ticks / 16; + return overflow_count + current_ticks / 16; } // Enable 1/1024 second tick. @@ -505,6 +517,7 @@ void port_enable_tick(void) { RTC->MODE0.INTENSET.reg = RTC_MODE0_INTENSET_PER2; #endif #ifdef SAMD21 + // TODO: Switch to using the PER *event* from the RTC to generate an interrupt via EVSYS. _ticks_enabled = true; _port_interrupt_after_ticks(1); #endif diff --git a/ports/litex/supervisor/port.c b/ports/litex/supervisor/port.c index e55eb49f00..02617b9af7 100644 --- a/ports/litex/supervisor/port.c +++ b/ports/litex/supervisor/port.c @@ -128,7 +128,11 @@ uint32_t port_get_saved_word(void) { } uint64_t port_get_raw_ticks(uint8_t* subticks) { - return raw_ticks; + // Reading 64 bits may take two loads, so turn of interrupts while we do it. + irq_setie(false); + uint64_t raw_tick_snapshot = raw_ticks; + irq_setie(true); + return raw_tick_snapshot; } // Enable 1/1024 second tick. diff --git a/ports/nrf/supervisor/port.c b/ports/nrf/supervisor/port.c index bc8b47be77..493de43e0f 100644 --- a/ports/nrf/supervisor/port.c +++ b/ports/nrf/supervisor/port.c @@ -274,11 +274,15 @@ uint32_t port_get_saved_word(void) { } uint64_t port_get_raw_ticks(uint8_t* subticks) { + common_hal_mcu_disable_interrupts(); uint32_t rtc = nrfx_rtc_counter_get(&rtc_instance); + uint32_t overflow_count = overflow_tracker.overflowed_ticks; + common_hal_mcu_enable_interrupts(); + if (subticks != NULL) { *subticks = (rtc % 32); } - return overflow_tracker.overflowed_ticks + rtc / 32; + return overflow_count + rtc / 32; } // Enable 1/1024 second tick. diff --git a/supervisor/shared/tick.c b/supervisor/shared/tick.c index 91ffa307d7..a2855a5706 100644 --- a/supervisor/shared/tick.c +++ b/supervisor/shared/tick.c @@ -125,9 +125,7 @@ void supervisor_tick(void) { uint64_t supervisor_ticks_ms64() { uint64_t result; - common_hal_mcu_disable_interrupts(); result = port_get_raw_ticks(NULL); - common_hal_mcu_enable_interrupts(); result = result * 1000 / 1024; return result; }