Blame | Last modification | View Log | RSS feed
#include <xc.h>
#include "defines.h"
#include "NEOPIXEL.h"
static NEOPIXEL_DATA* neopixel_data_ptr;
void NeoPixel_Init(NEOPIXEL_DATA *data) {
neopixel_data_ptr = data;
// Clear buffer
for (char i = 0; i < NEOPIXEL_LENGTH * 3; i++) {
neopixel_data_ptr->values[i] = 0x0;
}
// Output pin initially blocked
NEOPIXEL_TRIS = 1;
/* Initialize PWM module */
PR2 = 0x09; // 1.25us @ 32MHz
CCP1CONbits.P1M = 0b00; // Single output, P1A modulated only
CCP1CONbits.CCP1M = 0b1100; // PWM mode, P1A active-high, P1B active-high
// Idle the output till width is specified
CCPR1L = 0x00;
CCP1CONbits.DC1B = 0b00;
/* Initialize Timer 2 */
PIR1bits.TMR2IF = 0; // Clear the interrupt flag for Timer 2
T2CONbits.T2CKPS = 0b00; // Set a prescaler of 1:1
T2CONbits.TMR2ON = 1; // Enable the timer
// Wait for the timer to overflow before enabling output
while (!PIR1bits.TMR2IF);
NEOPIXEL_TRIS = 0;
}
void NeoPixel_Set(char index, char R, char G, char B) {
if (index >= NEOPIXEL_LENGTH) return;
neopixel_data_ptr->values[(index * 3) + 0] = G;
neopixel_data_ptr->values[(index * 3) + 1] = R;
neopixel_data_ptr->values[(index * 3) + 2] = B;
}
void NeoPixel_Write_All(void) {
for (char i = 0; i < NEOPIXEL_LENGTH * 3; i++) {
NeoPixel_Write_One(neopixel_data_ptr->values[i]);
}
// Delay for 50us to latch data
__delay_us(50);
}
void NeoPixel_Write_One(char value) {
// Enable timer and wait for it to overflow
T2CONbits.TMR2ON = 1;
while (!PIR1bits.TMR2IF);
// Set pulse width for bit 7
if (value & 0x80) {
CCPR1L = NEOPIXEL_LOGIC_1; // ~800ns high, ~450ns low (logic 1)
} else {
CCPR1L = NEOPIXEL_LOGIC_0; // ~400ns high, ~850ns low (logic 0)
}
while (!PIR1bits.TMR2IF);
// Set pulse width for bit 6
if (value & 0x40) {
CCPR1L = NEOPIXEL_LOGIC_1; // ~800ns high, ~450ns low (logic 1)
} else {
CCPR1L = NEOPIXEL_LOGIC_0; // ~400ns high, ~850ns low (logic 0)
}
while (!PIR1bits.TMR2IF);
// Set pulse width for bit 5
if (value & 0x20) {
CCPR1L = NEOPIXEL_LOGIC_1; // ~800ns high, ~450ns low (logic 1)
} else {
CCPR1L = NEOPIXEL_LOGIC_0; // ~400ns high, ~850ns low (logic 0)
}
while (!PIR1bits.TMR2IF);
// Set pulse width for bit 4
if (value & 0x10) {
CCPR1L = NEOPIXEL_LOGIC_1; // ~800ns high, ~450ns low (logic 1)
} else {
CCPR1L = NEOPIXEL_LOGIC_0; // ~400ns high, ~850ns low (logic 0)
}
while (!PIR1bits.TMR2IF);
// Set pulse width for bit 3
if (value & 0x08) {
CCPR1L = NEOPIXEL_LOGIC_1; // ~800ns high, ~450ns low (logic 1)
} else {
CCPR1L = NEOPIXEL_LOGIC_0; // ~400ns high, ~850ns low (logic 0)
}
while (!PIR1bits.TMR2IF);
// Set pulse width for bit 2
if (value & 0x04) {
CCPR1L = NEOPIXEL_LOGIC_1; // ~800ns high, ~450ns low (logic 1)
} else {
CCPR1L = NEOPIXEL_LOGIC_0; // ~400ns high, ~850ns low (logic 0)
}
while (!PIR1bits.TMR2IF);
// Set pulse width for bit 1
if (value & 0x02) {
CCPR1L = NEOPIXEL_LOGIC_1; // ~800ns high, ~450ns low (logic 1)
} else {
CCPR1L = NEOPIXEL_LOGIC_0; // ~400ns high, ~850ns low (logic 0)
}
while (!PIR1bits.TMR2IF);
// Set pulse width for bit 0
if (value & 0x01) {
CCPR1L = NEOPIXEL_LOGIC_1; // ~800ns high, ~450ns low (logic 1)
} else {
CCPR1L = NEOPIXEL_LOGIC_0; // ~400ns high, ~850ns low (logic 0)
}
// Idle line low
while (!PIR1bits.TMR2IF);
asm("NOP");
asm("NOP");
asm("NOP");
asm("NOP");
asm("NOP");
CCPR1L = 0b00000000;
// Disable and reset timer
while (!PIR1bits.TMR2IF);
asm("NOP");
asm("NOP");
T2CONbits.TMR2ON = 0;
TMR2 = 0x0;
}