diff --git a/main.c b/main.c index 78303e1235..1caeb12e2f 100755 --- a/main.c +++ b/main.c @@ -485,11 +485,10 @@ STATIC bool run_code_py(safe_mode_t safe_mode) { time_to_next_change = MIN(time_to_next_change, time_to_epaper_refresh); } #endif - if (time_to_next_change > 0) { - // time_to_next_change is in ms and ticks are slightly shorter so - // we'll undersleep just a little. It shouldn't matter. - port_interrupt_after_ticks(time_to_next_change); - } + + // time_to_next_change is in ms and ticks are slightly shorter so + // we'll undersleep just a little. It shouldn't matter. + port_interrupt_after_ticks(time_to_next_change); #endif port_idle_until_interrupt(); } diff --git a/ports/atmel-samd/boards/feather_m4_express/mpconfigboard.h b/ports/atmel-samd/boards/feather_m4_express/mpconfigboard.h index a57b18e24a..ef4a556227 100644 --- a/ports/atmel-samd/boards/feather_m4_express/mpconfigboard.h +++ b/ports/atmel-samd/boards/feather_m4_express/mpconfigboard.h @@ -12,7 +12,7 @@ // QSPI Data pins #define MICROPY_PORT_A (PORT_PA08 | PORT_PA09 | PORT_PA10 | PORT_PA11) // QSPI CS, QSPI SCK and NeoPixel pin -#define MICROPY_PORT_B (PORT_PB03 | PORT_PB10 | PORT_PB11) +#define MICROPY_PORT_B (PORT_PB10 | PORT_PB11) #define MICROPY_PORT_C (0) #define MICROPY_PORT_D (0) diff --git a/ports/atmel-samd/common-hal/neopixel_write/__init__.c b/ports/atmel-samd/common-hal/neopixel_write/__init__.c index 4677437f90..754bc97fdf 100644 --- a/ports/atmel-samd/common-hal/neopixel_write/__init__.c +++ b/ports/atmel-samd/common-hal/neopixel_write/__init__.c @@ -60,7 +60,7 @@ static void neopixel_send_buffer_core(volatile uint32_t *clraddr, uint32_t pinMa " movs r6, #3; d2: sub r6, #1; bne d2;" // delay 3 #endif #ifdef SAM_D5X_E5X - " movs r6, #3; d2: subs r6, #1; bne d2;" // delay 3 + " movs r6, #16; d2: subs r6, #1; bne d2;" // delay 3 #endif " tst r4, r5;" // mask&r5 " bne skipclr;" @@ -70,7 +70,7 @@ static void neopixel_send_buffer_core(volatile uint32_t *clraddr, uint32_t pinMa " movs r6, #6; d0: sub r6, #1; bne d0;" // delay 6 #endif #ifdef SAM_D5X_E5X - " movs r6, #6; d0: subs r6, #1; bne d0;" // delay 6 + " movs r6, #16; d0: subs r6, #1; bne d0;" // delay 6 #endif " str r1, [r0, #0];" // clr (possibly again, doesn't matter) #ifdef SAMD21 @@ -85,10 +85,13 @@ static void neopixel_send_buffer_core(volatile uint32_t *clraddr, uint32_t pinMa " movs r6, #2; d1: sub r6, #1; bne d1;" // delay 2 #endif #ifdef SAM_D5X_E5X - " movs r6, #2; d1: subs r6, #1; bne d1;" // delay 2 + " movs r6, #15; d1: subs r6, #1; bne d1;" // delay 2 #endif " b loopBit;" "nextbyte:" + #ifdef SAM_D5X_E5X + " movs r6, #12; d3: subs r6, #1; bne d3;" // delay 2 + #endif " cmp r2, r3;" " bcs neopixel_stop;" " b loopLoad;" @@ -114,42 +117,12 @@ void common_hal_neopixel_write(const digitalio_digitalinout_obj_t *digitalinout, // Turn off interrupts of any kind during timing-sensitive code. mp_hal_disable_all_interrupts(); - - #ifdef SAM_D5X_E5X - // When this routine is positioned at certain addresses, the timing logic - // below can be too fast by about 2.5x. This is some kind of (un)fortunate code - // positioning with respect to a cache line. - // Theoretically we should turn on off the CMCC caches and the - // NVM caches to ensure consistent timing. Testing shows the the NVMCTRL - // cache disabling seems to make the difference. But turn both off to make sure. - // It's difficult to test because additions to the code before the timing loop - // below change instruction placement. (though this should be less true now that - // the main code is in the cache-aligned function neopixel_send_buffer_core) - // Testing was done by adding cache changes below the loop (so only the - // first time through is wrong). - // - // Turn off instruction, data, and NVM caches to force consistent timing. - // Invalidate existing cache entries. - hri_cmcc_set_CFG_reg(CMCC, CMCC_CFG_DCDIS | CMCC_CFG_ICDIS); - hri_cmcc_write_MAINT0_reg(CMCC, CMCC_MAINT0_INVALL); - hri_nvmctrl_set_CTRLA_CACHEDIS0_bit(NVMCTRL); - hri_nvmctrl_set_CTRLA_CACHEDIS1_bit(NVMCTRL); - #endif - uint32_t pin = digitalinout->pin->number; port = &PORT->Group[GPIO_PORT(pin)]; // Convert GPIO # to port register pinMask = (1UL << (pin % 32)); // From port_pin_set_output_level ASF code. volatile uint32_t *clr = &(port->OUTCLR.reg); neopixel_send_buffer_core(clr, pinMask, pixels, numBytes); - #ifdef SAM_D5X_E5X - // Turn instruction, data, and NVM caches back on. - hri_cmcc_clear_CFG_reg(CMCC, CMCC_CFG_DCDIS | CMCC_CFG_ICDIS); - hri_nvmctrl_clear_CTRLA_CACHEDIS0_bit(NVMCTRL); - hri_nvmctrl_clear_CTRLA_CACHEDIS1_bit(NVMCTRL); - - #endif - // Update the next start. next_start_raw_ticks = port_get_raw_ticks(NULL) + 4; diff --git a/ports/atmel-samd/supervisor/port.c b/ports/atmel-samd/supervisor/port.c index 15112f5ba7..0ba6019e07 100644 --- a/ports/atmel-samd/supervisor/port.c +++ b/ports/atmel-samd/supervisor/port.c @@ -462,6 +462,8 @@ static uint32_t _get_count(uint64_t *overflow_count) { return count; } +volatile bool _woken_up; + static void _port_interrupt_after_ticks(uint32_t ticks) { uint32_t current_ticks = _get_count(NULL); if (ticks > 1 << 28) { @@ -473,9 +475,16 @@ static void _port_interrupt_after_ticks(uint32_t ticks) { return; } #endif - RTC->MODE0.COMP[0].reg = current_ticks + (ticks << 4); + uint32_t target = current_ticks + (ticks << 4); + RTC->MODE0.COMP[0].reg = target; + #ifdef SAM_D5X_E5X + while ((RTC->MODE0.SYNCBUSY.reg & (RTC_MODE0_SYNCBUSY_COMP0)) != 0) { + } + #endif RTC->MODE0.INTFLAG.reg = RTC_MODE0_INTFLAG_CMP0; RTC->MODE0.INTENSET.reg = RTC_MODE0_INTENSET_CMP0; + current_ticks = _get_count(NULL); + _woken_up = current_ticks >= target; } void RTC_Handler(void) { @@ -485,15 +494,18 @@ void RTC_Handler(void) { // Our RTC is 32 bits and we're clocking it at 16.384khz which is 16 (2 ** 4) subticks per // tick. overflowed_ticks += (1L << (32 - 4)); + } #ifdef SAM_D5X_E5X - } else if (intflag & RTC_MODE0_INTFLAG_PER2) { + if (intflag & RTC_MODE0_INTFLAG_PER2) { RTC->MODE0.INTFLAG.reg = RTC_MODE0_INTFLAG_PER2; // Do things common to all ports when the tick occurs supervisor_tick(); + } #endif - } else if (intflag & RTC_MODE0_INTFLAG_CMP0) { + if (intflag & RTC_MODE0_INTFLAG_CMP0) { // Clear the interrupt because we may have hit a sleep and _ticks_enabled RTC->MODE0.INTFLAG.reg = RTC_MODE0_INTFLAG_CMP0; + _woken_up = true; #ifdef SAMD21 if (_ticks_enabled) { // Do things common to all ports when the tick occurs. @@ -565,7 +577,7 @@ void port_idle_until_interrupt(void) { } #endif common_hal_mcu_disable_interrupts(); - if (!tud_task_event_ready() && !hold_interrupt) { + if (!tud_task_event_ready() && !hold_interrupt && !_woken_up) { __DSB(); __WFI(); } diff --git a/ports/nrf/boards/feather_nrf52840_express/mpconfigboard.h b/ports/nrf/boards/feather_nrf52840_express/mpconfigboard.h index 8e4cd2287a..64988e1a28 100644 --- a/ports/nrf/boards/feather_nrf52840_express/mpconfigboard.h +++ b/ports/nrf/boards/feather_nrf52840_express/mpconfigboard.h @@ -30,7 +30,7 @@ #define MICROPY_HW_BOARD_NAME "Adafruit Feather nRF52840 Express" #define MICROPY_HW_MCU_NAME "nRF52840" -// #define MICROPY_HW_NEOPIXEL (&pin_P0_16) +#define MICROPY_HW_NEOPIXEL (&pin_P0_16) #define MICROPY_HW_LED_STATUS (&pin_P1_15)