tinygo.org/x/drivers@v0.27.1-0.20240509133757-7dbca2a54349/ws2812/ws2812_avr.go (about) 1 //go:build avr 2 3 package ws2812 4 5 // This file implements the WS2812 protocol for AVR microcontrollers. 6 7 import ( 8 "machine" 9 "runtime/interrupt" 10 "unsafe" 11 ) 12 13 /* 14 #include <stdint.h> 15 16 __attribute__((always_inline)) 17 void ws2812_writeByte16(char c, uint8_t *port, uint8_t maskSet, uint8_t maskClear) { 18 // See: 19 // https://wp.josh.com/2014/05/13/ws2812-neopixels-are-not-so-finicky-once-you-get-to-know-them/ 20 // T0H: 4 cycles or 250ns 21 // T0L: 14 cycles or 875ns -> together 18 cycles or 1125ns 22 // T1H: 9 cycles or 562ns 23 // T1L: 8 cycles or 500ns -> together 17 cycles or 1062ns 24 char i = 8; 25 __asm__ __volatile__( 26 "1:\n" 27 "\t st %[port], %[maskSet] ; [2] set output high\n" 28 "\t lsl %[value] ; [1] shift off the next bit, store it in C\n" 29 "\t brcs 2f ; [1/2] branch if this bit is high (long pulse)\n" 30 "\t st %[port], %[maskClear] ; [2] set output low (short pulse)\n" 31 "\t2:\n" 32 "\t nop ; [4] wait before changing the output again\n" 33 "\t nop\n" 34 "\t nop\n" 35 "\t nop\n" 36 "\t st %[port], %[maskClear] ; [2] set output low (end of pulse)\n" 37 "\t nop ; [3]\n" 38 "\t nop\n" 39 "\t nop\n" 40 "\t subi %[i], 1 ; [1] subtract one (for the loop)\n" 41 "\t brne 1b ; [1/2] send the next bit, if not at the end of the loop\n" 42 : [value]"+r"(c), 43 [i]"+r"(i) 44 : [maskSet]"r"(maskSet), 45 [maskClear]"r"(maskClear), 46 [port]"m"(*port)); 47 } 48 */ 49 import "C" 50 51 // Send a single byte using the WS2812 protocol. 52 func (d Device) WriteByte(c byte) error { 53 // On AVR, the port is always the same for setting and clearing a register 54 // so use only one. This avoids the following error: 55 // error: inline assembly requires more registers than available 56 // Probably this is about pointer registers, which are very limited on AVR. 57 port, maskSet := d.Pin.PortMaskSet() 58 _, maskClear := d.Pin.PortMaskClear() 59 mask := interrupt.Disable() 60 61 switch machine.CPUFrequency() { 62 case 16e6: // 16MHz 63 C.ws2812_writeByte16(C.char(c), (*C.uint8_t)(unsafe.Pointer(port)), C.uint8_t(maskSet), C.uint8_t(maskClear)) 64 interrupt.Restore(mask) 65 return nil 66 default: 67 interrupt.Restore(mask) 68 return errUnknownClockSpeed 69 } 70 }