| 279 |
Kevin |
1 |
#include <xc.h>
|
|
|
2 |
#include "defines.h"
|
|
|
3 |
#include "NEOPIXEL.h"
|
|
|
4 |
|
|
|
5 |
static NEOPIXEL_DATA* neopixel_data_ptr;
|
|
|
6 |
|
|
|
7 |
void NeoPixel_Init(NEOPIXEL_DATA *data) {
|
|
|
8 |
neopixel_data_ptr = data;
|
|
|
9 |
|
|
|
10 |
// Clear buffer
|
|
|
11 |
for (char i = 0; i < NEOPIXEL_LENGTH * 3; i++) {
|
|
|
12 |
neopixel_data_ptr->values[i] = 0x0;
|
|
|
13 |
}
|
|
|
14 |
|
|
|
15 |
// Output pin initially blocked
|
|
|
16 |
NEOPIXEL_TRIS = 1;
|
|
|
17 |
|
|
|
18 |
/* Initialize PWM module */
|
|
|
19 |
PR2 = 0x09; // 1.25us @ 32MHz
|
|
|
20 |
CCP1CONbits.P1M = 0b00; // Single output, P1A modulated only
|
|
|
21 |
CCP1CONbits.CCP1M = 0b1100; // PWM mode, P1A active-high, P1B active-high
|
|
|
22 |
|
|
|
23 |
// Idle the output till width is specified
|
|
|
24 |
CCPR1L = 0x00;
|
|
|
25 |
CCP1CONbits.DC1B = 0b00;
|
|
|
26 |
|
|
|
27 |
/* Initialize Timer 2 */
|
|
|
28 |
PIR1bits.TMR2IF = 0; // Clear the interrupt flag for Timer 2
|
|
|
29 |
T2CONbits.T2CKPS = 0b00; // Set a prescaler of 1:1
|
|
|
30 |
T2CONbits.TMR2ON = 1; // Enable the timer
|
|
|
31 |
|
|
|
32 |
// Wait for the timer to overflow before enabling output
|
|
|
33 |
while (!PIR1bits.TMR2IF);
|
|
|
34 |
NEOPIXEL_TRIS = 0;
|
|
|
35 |
}
|
|
|
36 |
|
|
|
37 |
void NeoPixel_Set(char index, char R, char G, char B) {
|
|
|
38 |
if (index >= NEOPIXEL_LENGTH) return;
|
|
|
39 |
|
|
|
40 |
neopixel_data_ptr->values[(index * 3) + 0] = G;
|
|
|
41 |
neopixel_data_ptr->values[(index * 3) + 1] = R;
|
|
|
42 |
neopixel_data_ptr->values[(index * 3) + 2] = B;
|
|
|
43 |
}
|
|
|
44 |
|
|
|
45 |
void NeoPixel_Write_All(void) {
|
|
|
46 |
for (char i = 0; i < NEOPIXEL_LENGTH * 3; i++) {
|
|
|
47 |
NeoPixel_Write_One(neopixel_data_ptr->values[i]);
|
|
|
48 |
}
|
|
|
49 |
// Delay for 50us to latch data
|
|
|
50 |
__delay_us(50);
|
|
|
51 |
}
|
|
|
52 |
|
|
|
53 |
void NeoPixel_Write_One(char value) {
|
|
|
54 |
// Enable timer and wait for it to overflow
|
|
|
55 |
T2CONbits.TMR2ON = 1;
|
|
|
56 |
while (!PIR1bits.TMR2IF);
|
|
|
57 |
|
|
|
58 |
// Set pulse width for bit 7
|
|
|
59 |
if (value & 0x80) {
|
|
|
60 |
CCPR1L = NEOPIXEL_LOGIC_1; // ~800ns high, ~450ns low (logic 1)
|
|
|
61 |
} else {
|
|
|
62 |
CCPR1L = NEOPIXEL_LOGIC_0; // ~400ns high, ~850ns low (logic 0)
|
|
|
63 |
}
|
|
|
64 |
while (!PIR1bits.TMR2IF);
|
|
|
65 |
|
|
|
66 |
// Set pulse width for bit 6
|
|
|
67 |
if (value & 0x40) {
|
|
|
68 |
CCPR1L = NEOPIXEL_LOGIC_1; // ~800ns high, ~450ns low (logic 1)
|
|
|
69 |
} else {
|
|
|
70 |
CCPR1L = NEOPIXEL_LOGIC_0; // ~400ns high, ~850ns low (logic 0)
|
|
|
71 |
}
|
|
|
72 |
while (!PIR1bits.TMR2IF);
|
|
|
73 |
|
|
|
74 |
// Set pulse width for bit 5
|
|
|
75 |
if (value & 0x20) {
|
|
|
76 |
CCPR1L = NEOPIXEL_LOGIC_1; // ~800ns high, ~450ns low (logic 1)
|
|
|
77 |
} else {
|
|
|
78 |
CCPR1L = NEOPIXEL_LOGIC_0; // ~400ns high, ~850ns low (logic 0)
|
|
|
79 |
}
|
|
|
80 |
while (!PIR1bits.TMR2IF);
|
|
|
81 |
|
|
|
82 |
// Set pulse width for bit 4
|
|
|
83 |
if (value & 0x10) {
|
|
|
84 |
CCPR1L = NEOPIXEL_LOGIC_1; // ~800ns high, ~450ns low (logic 1)
|
|
|
85 |
} else {
|
|
|
86 |
CCPR1L = NEOPIXEL_LOGIC_0; // ~400ns high, ~850ns low (logic 0)
|
|
|
87 |
}
|
|
|
88 |
while (!PIR1bits.TMR2IF);
|
|
|
89 |
|
|
|
90 |
// Set pulse width for bit 3
|
|
|
91 |
if (value & 0x08) {
|
|
|
92 |
CCPR1L = NEOPIXEL_LOGIC_1; // ~800ns high, ~450ns low (logic 1)
|
|
|
93 |
} else {
|
|
|
94 |
CCPR1L = NEOPIXEL_LOGIC_0; // ~400ns high, ~850ns low (logic 0)
|
|
|
95 |
}
|
|
|
96 |
while (!PIR1bits.TMR2IF);
|
|
|
97 |
|
|
|
98 |
// Set pulse width for bit 2
|
|
|
99 |
if (value & 0x04) {
|
|
|
100 |
CCPR1L = NEOPIXEL_LOGIC_1; // ~800ns high, ~450ns low (logic 1)
|
|
|
101 |
} else {
|
|
|
102 |
CCPR1L = NEOPIXEL_LOGIC_0; // ~400ns high, ~850ns low (logic 0)
|
|
|
103 |
}
|
|
|
104 |
while (!PIR1bits.TMR2IF);
|
|
|
105 |
|
|
|
106 |
// Set pulse width for bit 1
|
|
|
107 |
if (value & 0x02) {
|
|
|
108 |
CCPR1L = NEOPIXEL_LOGIC_1; // ~800ns high, ~450ns low (logic 1)
|
|
|
109 |
} else {
|
|
|
110 |
CCPR1L = NEOPIXEL_LOGIC_0; // ~400ns high, ~850ns low (logic 0)
|
|
|
111 |
}
|
|
|
112 |
while (!PIR1bits.TMR2IF);
|
|
|
113 |
|
|
|
114 |
// Set pulse width for bit 0
|
|
|
115 |
if (value & 0x01) {
|
|
|
116 |
CCPR1L = NEOPIXEL_LOGIC_1; // ~800ns high, ~450ns low (logic 1)
|
|
|
117 |
} else {
|
|
|
118 |
CCPR1L = NEOPIXEL_LOGIC_0; // ~400ns high, ~850ns low (logic 0)
|
|
|
119 |
}
|
|
|
120 |
|
|
|
121 |
// Idle line low
|
|
|
122 |
while (!PIR1bits.TMR2IF);
|
|
|
123 |
asm("NOP");
|
|
|
124 |
asm("NOP");
|
|
|
125 |
asm("NOP");
|
|
|
126 |
asm("NOP");
|
|
|
127 |
asm("NOP");
|
|
|
128 |
CCPR1L = 0b00000000;
|
|
|
129 |
|
|
|
130 |
// Disable and reset timer
|
|
|
131 |
while (!PIR1bits.TMR2IF);
|
|
|
132 |
asm("NOP");
|
|
|
133 |
asm("NOP");
|
|
|
134 |
T2CONbits.TMR2ON = 0;
|
|
|
135 |
TMR2 = 0x0;
|
|
|
136 |
}
|