-
Notifications
You must be signed in to change notification settings - Fork 311
/
neopixel.h
90 lines (78 loc) · 3.35 KB
/
neopixel.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#ifndef DEVICE_NEOPIXEL_H
#define DEVICE_NEOPIXEL_H
#ifdef BOARD_NEOPIXEL_PIN
// The timings are taken from Adafruit's NeoPixel library
static void neopixel_send_buffer_core(volatile uint32_t *clraddr, uint32_t pinMask,
const uint8_t *ptr, int numBytes) __attribute__((naked));
static void neopixel_send_buffer_core(volatile uint32_t *clraddr, uint32_t pinMask,
const uint8_t *ptr, int numBytes) {
asm volatile(" push {r4, r5, r6, lr};"
" add r3, r2, r3;"
"loopLoad:"
" ldrb r5, [r2, #0];" // r5 := *ptr
" add r2, #1;" // ptr++
" movs r4, #128;" // r4-mask, 0x80
"loopBit:"
" str r1, [r0, #4];" // set
#ifdef SAMD21
" movs r6, #3; d2: sub r6, #1; bne d2;" // delay 3
#endif
#ifdef SAMD51
" movs r6, #3; d2: subs r6, #1; bne d2;" // delay 3
#endif
" tst r4, r5;" // mask&r5
" bne skipclr;"
" str r1, [r0, #0];" // clr
"skipclr:"
#ifdef SAMD21
" movs r6, #6; d0: sub r6, #1; bne d0;" // delay 6
#endif
#ifdef SAMD51
" movs r6, #6; d0: subs r6, #1; bne d0;" // delay 6
#endif
" str r1, [r0, #0];" // clr (possibly again, doesn't matter)
#ifdef SAMD21
" asr r4, r4, #1;" // mask >>= 1
#endif
#ifdef SAMD51
" asrs r4, r4, #1;" // mask >>= 1
#endif
" beq nextbyte;"
" uxtb r4, r4;"
#ifdef SAMD21
" movs r6, #2; d1: sub r6, #1; bne d1;" // delay 2
#endif
#ifdef SAMD51
" movs r6, #2; d1: subs r6, #1; bne d1;" // delay 2
#endif
" b loopBit;"
"nextbyte:"
" cmp r2, r3;"
" bcs stop;"
" b loopLoad;"
"stop:"
" pop {r4, r5, r6, pc};"
"");
}
// this assumes the pin has been configured correctly
static inline void neopixel_send_buffer(const uint8_t *ptr, int numBytes) {
uint8_t portNum = BOARD_NEOPIXEL_PIN / 32;
uint32_t pinMask = 1ul << (BOARD_NEOPIXEL_PIN % 32);
PINOP(BOARD_NEOPIXEL_PIN, DIRSET);
// turn off mux too, needed for metro m0 but no harm done!
PORT->Group[BOARD_NEOPIXEL_PIN / 32].PINCFG[BOARD_NEOPIXEL_PIN % 32].reg =
(uint8_t)(PORT_PINCFG_INEN);
PINOP(BOARD_NEOPIXEL_PIN, OUTCLR);
delay(1);
volatile uint32_t *clraddr = &PORT->Group[portNum].OUTCLR.reg;
// equivalent to cpu_irq_is_enabled()
if (__get_PRIMASK() == 0) {
__disable_irq();
neopixel_send_buffer_core(clraddr, pinMask, ptr, numBytes);
__enable_irq();
} else {
neopixel_send_buffer_core(clraddr, pinMask, ptr, numBytes);
}
}
#endif
#endif