Subversion Repositories Code-Repo

Rev

Rev 281 | Blame | Last modification | View Log | RSS feed

#include "defines.h"
#include "NEOPIXEL.h"

extern NEOPIXEL_DATA neopixel_data;

void NeoPixel_Init(void) {

    // Clear buffer
    for (uint8_t i = 0; i < NEOPIXEL_LENGTH * 3; i++) {
        neopixel_data.values[i] = 0x0;
    }

    neopixel_data.offset = 0;

    // 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_Offet(uint8_t value) {
    neopixel_data.offset = value;
}

void NeoPixel_Clear(void) {
    // Clear buffer
    for (uint8_t i = 0; i < NEOPIXEL_LENGTH * 3; i++) {
        neopixel_data.values[i] = 0x0;
    }
}

void NeoPixel_Set(uint8_t index, uint8_t R, uint8_t G, uint8_t B, uint8_t multiplier) {
    uint8_t i = ((index + neopixel_data.offset) % NEOPIXEL_LENGTH);
    
    if (G == 0)
        neopixel_data.values[(i * 3) + 0] = 0;
    else
        neopixel_data.values[(i * 3) + 0] = (G * multiplier) - 1;
    if (R == 0)
        neopixel_data.values[(i * 3) + 1] = 0;
    else
        neopixel_data.values[(i * 3) + 1] = (R * multiplier) - 1;
    if (B == 0)
        neopixel_data.values[(i * 3) + 2] = 0;
    else
        neopixel_data.values[(i * 3) + 2] = (B * multiplier) - 1;
}

void NeoPixel_Or(uint8_t index, uint8_t R, uint8_t G, uint8_t B, uint8_t multiplier) {
    uint8_t i = ((index + neopixel_data.offset) % NEOPIXEL_LENGTH);

    if (G != 0)
        neopixel_data.values[(i * 3) + 0] |= (G * multiplier) - 1;
    if (R != 0)
        neopixel_data.values[(i * 3) + 1] |= (R * multiplier) - 1;
    if (B != 0)
        neopixel_data.values[(i * 3) + 2] |= (B * multiplier) - 1;
}

void NeoPixel_Write_All(void) {
    for (uint8_t i = 0; i < NEOPIXEL_LENGTH * 3; i++) {
        NeoPixel_Write_One(neopixel_data.values[i]);
    }
    // Delay for 50us to latch data
    __delay_us(50);
}

void NeoPixel_Write_One(uint8_t 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;
}