Skip to content

Commit

Permalink
atmel-samd: Fix neopixel timing by forcing the NVM cache to be determ…
Browse files Browse the repository at this point in the history
…inisticly timed. Otherwise, bit order changes code timing. Fixes #74
  • Loading branch information
tannewt committed Jan 18, 2017
1 parent 42926c6 commit 1a86968
Showing 1 changed file with 11 additions and 10 deletions.
21 changes: 11 additions & 10 deletions atmel-samd/common-hal/neopixel_write/__init__.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ void common_hal_neopixel_write(const nativeio_digitalinout_obj_t* digitalinout,
// Turn off interrupts of any kind during timing-sensitive code.
mp_hal_disable_all_interrupts();

// Make sure the NVM cache is consistently timed.
NVMCTRL->CTRLB.bit.READMODE = NVMCTRL_CTRLB_READMODE_DETERMINISTIC_Val;

uint32_t pin = digitalinout->pin->pin;
port = port_get_group_from_gpio_pin(pin);
pinMask = (1UL << (pin % 32)); // From port_pin_set_output_level ASF code.
Expand All @@ -56,17 +59,14 @@ void common_hal_neopixel_write(const nativeio_digitalinout_obj_t* digitalinout,
*set = pinMask;
asm("nop; nop;");
if(p & bitMask) {
asm("nop; nop; nop; nop; nop; nop; nop; nop;"
"nop; nop; nop; nop; nop;");
asm("nop; nop; nop; nop; nop; nop; nop;");
*clr = pinMask;
} else {
*clr = pinMask;
asm("nop; nop; nop; nop; nop; nop; nop; nop;"
"nop; nop; nop; nop; nop; nop; nop; nop;"
"nop; nop;");
asm("nop; nop;");
}
if((bitMask >>= 1) != 0) {
asm("nop; nop; nop; nop; nop; nop; nop; nop; nop;");
asm("nop; nop; nop; nop; nop;");
} else {
if(ptr >= end) break;
p = *ptr++;
Expand All @@ -76,12 +76,10 @@ void common_hal_neopixel_write(const nativeio_digitalinout_obj_t* digitalinout,
} else { // 400 KHz bitstream
for(;;) {
*set = pinMask;
// 11 cycles high regardless
asm("nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop;");

asm("nop; nop; nop; nop; nop; nop; nop;");
if(p & bitMask) {
// 27 cycles high
asm("nop; nop; nop; nop; nop; nop; nop; nop;"
"nop; nop; nop; nop; nop; nop; nop; nop;"
"nop; nop; nop; nop; nop; nop; nop; nop;"
"nop; nop; nop;");
*clr = pinMask;
Expand All @@ -106,6 +104,9 @@ void common_hal_neopixel_write(const nativeio_digitalinout_obj_t* digitalinout,
}
}

// Speed up! (But inconsistent timing.)
NVMCTRL->CTRLB.bit.READMODE = NVMCTRL_CTRLB_READMODE_NO_MISS_PENALTY_Val;

// Turn on interrupts after timing-sensitive code.
mp_hal_enable_all_interrupts();

Expand Down

0 comments on commit 1a86968

Please sign in to comment.