Skip to content

Commit 5c33c9d

Browse files
committed
Fix SAMD
RTC needed to wait for sync. NeoPixel on SAMD doesn't need disabled caches. It just needed timing adjustment for 120mhz clock speed.
1 parent 1a0b419 commit 5c33c9d

File tree

5 files changed

+28
-44
lines changed

5 files changed

+28
-44
lines changed

main.c

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -485,11 +485,10 @@ STATIC bool run_code_py(safe_mode_t safe_mode) {
485485
time_to_next_change = MIN(time_to_next_change, time_to_epaper_refresh);
486486
}
487487
#endif
488-
if (time_to_next_change > 0) {
489-
// time_to_next_change is in ms and ticks are slightly shorter so
490-
// we'll undersleep just a little. It shouldn't matter.
491-
port_interrupt_after_ticks(time_to_next_change);
492-
}
488+
489+
// time_to_next_change is in ms and ticks are slightly shorter so
490+
// we'll undersleep just a little. It shouldn't matter.
491+
port_interrupt_after_ticks(time_to_next_change);
493492
#endif
494493
port_idle_until_interrupt();
495494
}

ports/atmel-samd/boards/feather_m4_express/mpconfigboard.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
// QSPI Data pins
1313
#define MICROPY_PORT_A (PORT_PA08 | PORT_PA09 | PORT_PA10 | PORT_PA11)
1414
// QSPI CS, QSPI SCK and NeoPixel pin
15-
#define MICROPY_PORT_B (PORT_PB03 | PORT_PB10 | PORT_PB11)
15+
#define MICROPY_PORT_B (PORT_PB10 | PORT_PB11)
1616
#define MICROPY_PORT_C (0)
1717
#define MICROPY_PORT_D (0)
1818

ports/atmel-samd/common-hal/neopixel_write/__init__.c

Lines changed: 6 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ static void neopixel_send_buffer_core(volatile uint32_t *clraddr, uint32_t pinMa
6060
" movs r6, #3; d2: sub r6, #1; bne d2;" // delay 3
6161
#endif
6262
#ifdef SAM_D5X_E5X
63-
" movs r6, #3; d2: subs r6, #1; bne d2;" // delay 3
63+
" movs r6, #16; d2: subs r6, #1; bne d2;" // delay 3
6464
#endif
6565
" tst r4, r5;" // mask&r5
6666
" bne skipclr;"
@@ -70,7 +70,7 @@ static void neopixel_send_buffer_core(volatile uint32_t *clraddr, uint32_t pinMa
7070
" movs r6, #6; d0: sub r6, #1; bne d0;" // delay 6
7171
#endif
7272
#ifdef SAM_D5X_E5X
73-
" movs r6, #6; d0: subs r6, #1; bne d0;" // delay 6
73+
" movs r6, #16; d0: subs r6, #1; bne d0;" // delay 6
7474
#endif
7575
" str r1, [r0, #0];" // clr (possibly again, doesn't matter)
7676
#ifdef SAMD21
@@ -85,10 +85,13 @@ static void neopixel_send_buffer_core(volatile uint32_t *clraddr, uint32_t pinMa
8585
" movs r6, #2; d1: sub r6, #1; bne d1;" // delay 2
8686
#endif
8787
#ifdef SAM_D5X_E5X
88-
" movs r6, #2; d1: subs r6, #1; bne d1;" // delay 2
88+
" movs r6, #15; d1: subs r6, #1; bne d1;" // delay 2
8989
#endif
9090
" b loopBit;"
9191
"nextbyte:"
92+
#ifdef SAM_D5X_E5X
93+
" movs r6, #12; d3: subs r6, #1; bne d3;" // delay 2
94+
#endif
9295
" cmp r2, r3;"
9396
" bcs neopixel_stop;"
9497
" b loopLoad;"
@@ -114,42 +117,12 @@ void common_hal_neopixel_write(const digitalio_digitalinout_obj_t *digitalinout,
114117
// Turn off interrupts of any kind during timing-sensitive code.
115118
mp_hal_disable_all_interrupts();
116119

117-
118-
#ifdef SAM_D5X_E5X
119-
// When this routine is positioned at certain addresses, the timing logic
120-
// below can be too fast by about 2.5x. This is some kind of (un)fortunate code
121-
// positioning with respect to a cache line.
122-
// Theoretically we should turn on off the CMCC caches and the
123-
// NVM caches to ensure consistent timing. Testing shows the the NVMCTRL
124-
// cache disabling seems to make the difference. But turn both off to make sure.
125-
// It's difficult to test because additions to the code before the timing loop
126-
// below change instruction placement. (though this should be less true now that
127-
// the main code is in the cache-aligned function neopixel_send_buffer_core)
128-
// Testing was done by adding cache changes below the loop (so only the
129-
// first time through is wrong).
130-
//
131-
// Turn off instruction, data, and NVM caches to force consistent timing.
132-
// Invalidate existing cache entries.
133-
hri_cmcc_set_CFG_reg(CMCC, CMCC_CFG_DCDIS | CMCC_CFG_ICDIS);
134-
hri_cmcc_write_MAINT0_reg(CMCC, CMCC_MAINT0_INVALL);
135-
hri_nvmctrl_set_CTRLA_CACHEDIS0_bit(NVMCTRL);
136-
hri_nvmctrl_set_CTRLA_CACHEDIS1_bit(NVMCTRL);
137-
#endif
138-
139120
uint32_t pin = digitalinout->pin->number;
140121
port = &PORT->Group[GPIO_PORT(pin)]; // Convert GPIO # to port register
141122
pinMask = (1UL << (pin % 32)); // From port_pin_set_output_level ASF code.
142123
volatile uint32_t *clr = &(port->OUTCLR.reg);
143124
neopixel_send_buffer_core(clr, pinMask, pixels, numBytes);
144125

145-
#ifdef SAM_D5X_E5X
146-
// Turn instruction, data, and NVM caches back on.
147-
hri_cmcc_clear_CFG_reg(CMCC, CMCC_CFG_DCDIS | CMCC_CFG_ICDIS);
148-
hri_nvmctrl_clear_CTRLA_CACHEDIS0_bit(NVMCTRL);
149-
hri_nvmctrl_clear_CTRLA_CACHEDIS1_bit(NVMCTRL);
150-
151-
#endif
152-
153126
// Update the next start.
154127
next_start_raw_ticks = port_get_raw_ticks(NULL) + 4;
155128

ports/atmel-samd/supervisor/port.c

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,8 @@ static uint32_t _get_count(uint64_t *overflow_count) {
462462
return count;
463463
}
464464

465+
volatile bool _woken_up;
466+
465467
static void _port_interrupt_after_ticks(uint32_t ticks) {
466468
uint32_t current_ticks = _get_count(NULL);
467469
if (ticks > 1 << 28) {
@@ -473,9 +475,16 @@ static void _port_interrupt_after_ticks(uint32_t ticks) {
473475
return;
474476
}
475477
#endif
476-
RTC->MODE0.COMP[0].reg = current_ticks + (ticks << 4);
478+
uint32_t target = current_ticks + (ticks << 4);
479+
RTC->MODE0.COMP[0].reg = target;
480+
#ifdef SAM_D5X_E5X
481+
while ((RTC->MODE0.SYNCBUSY.reg & (RTC_MODE0_SYNCBUSY_COMP0)) != 0) {
482+
}
483+
#endif
477484
RTC->MODE0.INTFLAG.reg = RTC_MODE0_INTFLAG_CMP0;
478485
RTC->MODE0.INTENSET.reg = RTC_MODE0_INTENSET_CMP0;
486+
current_ticks = _get_count(NULL);
487+
_woken_up = current_ticks >= target;
479488
}
480489

481490
void RTC_Handler(void) {
@@ -485,15 +494,18 @@ void RTC_Handler(void) {
485494
// Our RTC is 32 bits and we're clocking it at 16.384khz which is 16 (2 ** 4) subticks per
486495
// tick.
487496
overflowed_ticks += (1L << (32 - 4));
497+
}
488498
#ifdef SAM_D5X_E5X
489-
} else if (intflag & RTC_MODE0_INTFLAG_PER2) {
499+
if (intflag & RTC_MODE0_INTFLAG_PER2) {
490500
RTC->MODE0.INTFLAG.reg = RTC_MODE0_INTFLAG_PER2;
491501
// Do things common to all ports when the tick occurs
492502
supervisor_tick();
503+
}
493504
#endif
494-
} else if (intflag & RTC_MODE0_INTFLAG_CMP0) {
505+
if (intflag & RTC_MODE0_INTFLAG_CMP0) {
495506
// Clear the interrupt because we may have hit a sleep and _ticks_enabled
496507
RTC->MODE0.INTFLAG.reg = RTC_MODE0_INTFLAG_CMP0;
508+
_woken_up = true;
497509
#ifdef SAMD21
498510
if (_ticks_enabled) {
499511
// Do things common to all ports when the tick occurs.
@@ -565,7 +577,7 @@ void port_idle_until_interrupt(void) {
565577
}
566578
#endif
567579
common_hal_mcu_disable_interrupts();
568-
if (!tud_task_event_ready() && !hold_interrupt) {
580+
if (!tud_task_event_ready() && !hold_interrupt && !_woken_up) {
569581
__DSB();
570582
__WFI();
571583
}

ports/nrf/boards/feather_nrf52840_express/mpconfigboard.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
#define MICROPY_HW_BOARD_NAME "Adafruit Feather nRF52840 Express"
3131
#define MICROPY_HW_MCU_NAME "nRF52840"
3232

33-
// #define MICROPY_HW_NEOPIXEL (&pin_P0_16)
33+
#define MICROPY_HW_NEOPIXEL (&pin_P0_16)
3434

3535
#define MICROPY_HW_LED_STATUS (&pin_P1_15)
3636

0 commit comments

Comments
 (0)