circuitpython/atmel-samd/samdneopixel.c
Scott Shawcroft 5b3a143ffe atmel-samd: Rework tick timer to use TC5 and support neopixel status LED.
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.
2016-10-28 20:16:39 -07:00

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);
}