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  }