//go:build avr package ws2812 // This file implements the WS2812 protocol for AVR microcontrollers. import ( "machine" "runtime/interrupt" "unsafe" ) /* #include __attribute__((always_inline)) void ws2812_writeByte16(char c, uint8_t *port, uint8_t maskSet, uint8_t maskClear) { // See: // https://wp.josh.com/2014/05/13/ws2812-neopixels-are-not-so-finicky-once-you-get-to-know-them/ // T0H: 4 cycles or 250ns // T0L: 14 cycles or 875ns -> together 18 cycles or 1125ns // T1H: 9 cycles or 562ns // T1L: 8 cycles or 500ns -> together 17 cycles or 1062ns char i = 8; __asm__ __volatile__( "1:\n" "\t st %[port], %[maskSet] ; [2] set output high\n" "\t lsl %[value] ; [1] shift off the next bit, store it in C\n" "\t brcs 2f ; [1/2] branch if this bit is high (long pulse)\n" "\t st %[port], %[maskClear] ; [2] set output low (short pulse)\n" "\t2:\n" "\t nop ; [4] wait before changing the output again\n" "\t nop\n" "\t nop\n" "\t nop\n" "\t st %[port], %[maskClear] ; [2] set output low (end of pulse)\n" "\t nop ; [3]\n" "\t nop\n" "\t nop\n" "\t subi %[i], 1 ; [1] subtract one (for the loop)\n" "\t brne 1b ; [1/2] send the next bit, if not at the end of the loop\n" : [value]"+r"(c), [i]"+r"(i) : [maskSet]"r"(maskSet), [maskClear]"r"(maskClear), [port]"m"(*port)); } */ import "C" // Send a single byte using the WS2812 protocol. func (d Device) WriteByte(c byte) error { // On AVR, the port is always the same for setting and clearing a register // so use only one. This avoids the following error: // error: inline assembly requires more registers than available // Probably this is about pointer registers, which are very limited on AVR. port, maskSet := d.Pin.PortMaskSet() _, maskClear := d.Pin.PortMaskClear() mask := interrupt.Disable() switch machine.CPUFrequency() { case 16e6: // 16MHz C.ws2812_writeByte16(C.char(c), (*C.uint8_t)(unsafe.Pointer(port)), C.uint8_t(maskSet), C.uint8_t(maskClear)) interrupt.Restore(mask) return nil default: interrupt.Restore(mask) return errUnknownClockSpeed } }