@@ -6,11 +6,49 @@ package ws2812
66// This file implements the WS2812 protocol for AVR microcontrollers.
77
88import (
9- "device/avr"
109 "machine"
1110 "runtime/interrupt"
11+ "unsafe"
1212)
1313
14+ /*
15+ #include <stdint.h>
16+
17+ __attribute__((always_inline))
18+ void ws2812_writeByte16(char c, uint8_t *port, uint8_t maskSet, uint8_t maskClear) {
19+ // See:
20+ // https://wp.josh.com/2014/05/13/ws2812-neopixels-are-not-so-finicky-once-you-get-to-know-them/
21+ // T0H: 4 cycles or 250ns
22+ // T0L: 14 cycles or 875ns -> together 18 cycles or 1125ns
23+ // T1H: 9 cycles or 562ns
24+ // T1L: 8 cycles or 500ns -> together 17 cycles or 1062ns
25+ char i = 8;
26+ __asm__ __volatile__(
27+ "1:\n"
28+ "\t st %[port], %[maskSet] ; [2] set output high\n"
29+ "\t lsl %[value] ; [1] shift off the next bit, store it in C\n"
30+ "\t brcs 2f ; [1/2] branch if this bit is high (long pulse)\n"
31+ "\t st %[port], %[maskClear] ; [2] set output low (short pulse)\n"
32+ "\t2:\n"
33+ "\t nop ; [4] wait before changing the output again\n"
34+ "\t nop\n"
35+ "\t nop\n"
36+ "\t nop\n"
37+ "\t st %[port], %[maskClear] ; [2] set output low (end of pulse)\n"
38+ "\t nop ; [3]\n"
39+ "\t nop\n"
40+ "\t nop\n"
41+ "\t subi %[i], 1 ; [1] subtract one (for the loop)\n"
42+ "\t brne 1b ; [1/2] send the next bit, if not at the end of the loop\n"
43+ : [value]"+r"(c),
44+ [i]"+r"(i)
45+ : [maskSet]"r"(maskSet),
46+ [maskClear]"r"(maskClear),
47+ [port]"m"(*port));
48+ }
49+ */
50+ import "C"
51+
1452// Send a single byte using the WS2812 protocol.
1553func (d Device ) WriteByte (c byte ) error {
1654 // On AVR, the port is always the same for setting and clearing a register
@@ -23,37 +61,7 @@ func (d Device) WriteByte(c byte) error {
2361
2462 switch machine .CPUFrequency () {
2563 case 16e6 : // 16MHz
26- // See:
27- // https://wp.josh.com/2014/05/13/ws2812-neopixels-are-not-so-finicky-once-you-get-to-know-them/
28- // T0H: 4 cycles or 250ns
29- // T0L: 14 cycles or 875ns -> together 18 cycles or 1125ns
30- // T1H: 9 cycles or 562ns
31- // T1L: 8 cycles or 500ns -> together 17 cycles or 1062ns
32- avr .AsmFull (`
33- send_bit:
34- st {portSet}, {maskSet} ; [2] set output high
35- lsl {value} ; [1] shift off the next bit, store it in C
36- brcs skip_store ; [1/2] branch if this bit is high (long pulse)
37- st {portClear}, {maskClear} ; [2] set output low (short pulse)
38- skip_store:
39- nop ; [4] wait before changing the output again
40- nop
41- nop
42- nop
43- st {portClear}, {maskClear} ; [2] set output low (end of pulse)
44- nop ; [3]
45- nop
46- nop
47- subi {i}, 1 ; [1] subtract one (for the loop)
48- brne send_bit ; [1/2] send the next bit, if not at the end of the loop
49- ` , map [string ]interface {}{
50- "value" : c ,
51- "i" : byte (8 ),
52- "maskSet" : maskSet ,
53- "portSet" : port ,
54- "maskClear" : maskClear ,
55- "portClear" : port ,
56- })
64+ C .ws2812_writeByte16 (C .char (c ), (* uint8 )(unsafe .Pointer (port )), maskSet , maskClear )
5765 interrupt .Restore (mask )
5866 return nil
5967 default :
0 commit comments