5b3a143ffe
The tick timer needed to be reworked because the ASF delay functions also use the SysTick timer. Now, it uses TC5 and calls out to the autoreset logic every tick. Fixes #43. Added neopixel status colors and corrected the latch time from ms to us. Fixes #42.
114 lines
3.6 KiB
C
114 lines
3.6 KiB
C
#include "asf/common2/services/delay/delay.h"
|
|
#include "asf/sam0/drivers/port/port.h"
|
|
|
|
#include "mphalport.h"
|
|
|
|
#include "samdneopixel.h"
|
|
|
|
#ifdef MICROPY_HW_NEOPIXEL
|
|
static uint8_t status_neopixel_color[3];
|
|
#endif
|
|
|
|
extern void new_status_color(uint8_t r, uint8_t g, uint8_t b) {
|
|
#ifdef MICROPY_HW_NEOPIXEL
|
|
status_neopixel_color[0] = g;
|
|
status_neopixel_color[1] = r;
|
|
status_neopixel_color[2] = b;
|
|
samd_neopixel_write(MICROPY_HW_NEOPIXEL, status_neopixel_color, 3, true);
|
|
#endif
|
|
}
|
|
extern void temp_status_color(uint8_t r, uint8_t g, uint8_t b) {
|
|
#ifdef MICROPY_HW_NEOPIXEL
|
|
uint8_t colors[3] = {g, r, b};
|
|
samd_neopixel_write(MICROPY_HW_NEOPIXEL, colors, 3, true);
|
|
#endif
|
|
}
|
|
extern void clear_temp_status() {
|
|
#ifdef MICROPY_HW_NEOPIXEL
|
|
samd_neopixel_write(MICROPY_HW_NEOPIXEL, status_neopixel_color, 3, true);
|
|
#endif
|
|
}
|
|
|
|
void samd_neopixel_write(uint32_t pin, uint8_t *pixels, uint32_t numBytes, bool is800KHz) {
|
|
// This is adapted directly from the Adafruit NeoPixel library SAMD21G18A code:
|
|
// https://github.com/adafruit/Adafruit_NeoPixel/blob/master/Adafruit_NeoPixel.cpp
|
|
uint8_t *ptr, *end, p, bitMask;
|
|
uint32_t pinMask;
|
|
PortGroup* port;
|
|
|
|
// Turn off interrupts of any kind during timing-sensitive code.
|
|
mp_hal_disable_all_interrupts();
|
|
|
|
port = port_get_group_from_gpio_pin(pin);
|
|
pinMask = (1UL << (pin % 32)); // From port_pin_set_output_level ASF code.
|
|
ptr = pixels;
|
|
end = ptr + numBytes;
|
|
p = *ptr++;
|
|
bitMask = 0x80;
|
|
|
|
volatile uint32_t *set = &(port->OUTSET.reg),
|
|
*clr = &(port->OUTCLR.reg);
|
|
|
|
if(is800KHz) {
|
|
for(;;) {
|
|
*set = pinMask;
|
|
asm("nop; nop; nop; nop; nop; nop; nop; nop;");
|
|
if(p & bitMask) {
|
|
asm("nop; nop; nop; nop; nop; nop; nop; nop;"
|
|
"nop; nop; nop; nop; nop; 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; nop; nop;");
|
|
}
|
|
if(bitMask >>= 1) {
|
|
asm("nop; nop; nop; nop; nop; nop; nop; nop; nop;");
|
|
} else {
|
|
if(ptr >= end) break;
|
|
p = *ptr++;
|
|
bitMask = 0x80;
|
|
}
|
|
}
|
|
} else { // 400 KHz bitstream
|
|
for(;;) {
|
|
*set = pinMask;
|
|
asm("nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop;");
|
|
if(p & bitMask) {
|
|
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;
|
|
} else {
|
|
*clr = pinMask;
|
|
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;");
|
|
}
|
|
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; nop; nop; nop; nop; nop;");
|
|
if(bitMask >>= 1) {
|
|
asm("nop; nop; nop; nop; nop; nop; nop;");
|
|
} else {
|
|
if(ptr >= end) break;
|
|
p = *ptr++;
|
|
bitMask = 0x80;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Turn on interrupts after timing-sensitive code.
|
|
mp_hal_enable_all_interrupts();
|
|
|
|
// 50us delay to let pixels latch to the data that was just sent.
|
|
// This could be optimized to only occur before pixel writes when necessary,
|
|
// like in the Arduino library.
|
|
delay_us(50);
|
|
}
|