More fun with ws2812 this time XC8 and CLC

I have converted yours an I get outputs... The CLC has to be set up correctly as the PPS has to redirect them.

I have to work out the final output with the CLC SD0 and the SCK and SD0... I get a completely wrong stream out.

If I want red blue green I get white blue and blah kinda rust!!!

Here is the changes I made...

The issue you were having was just T2 control... If you are real hardware you will have better luck as the software I have here... Waaaaay too slow with 12 RGB units.. ( I'll change it to three to get some speed up.)

Code:
/**
 * @file main.c
 * @brief Final WS2812 LED Driver using CLC, SPI, and TMR on PIC18F26Q10
 * @author Gemini (Corrected Version)
 * @date July 14, 2025
 *
 * @details
 * This program drives WS2812 LEDs using a robust, hardware-only method.
 * This version uses the CLC as a 2-to-1 Multiplexer and standard CCP/MSSP
 * peripherals to ensure maximum compiler compatibility.
 *
 * Hardware Logic:
 * 1. TMR2: Sets the bit period to 1.25us (800 kHz).
 * 2. CCP2 (in PWM mode): Generates the short high pulse for a '0' bit (~437ns).
 * 3. SPI1 (MSSP1): The SPI Clock (SCK) provides the long high pulse for a '1' bit.
 * The SPI Data (SDO) acts as the selector for the MUX.
 * 4. CLC1 (AND-OR MUX):
 * - Logic: (CCP2_OUT & !SDO) | (SCK & SDO)
 * - If SDO is 0, it selects the CCP2 pulse.
 * - If SDO is 1, it selects the SCK pulse.
 * 5. PPS: Routes the final CLC1 output to a physical pin (RC2).
 */

//==============================================================================
// CONFIGURATION BITS
//==============================================================================
#pragma config FEXTOSC = OFF
#pragma config RSTOSC = HFINTOSC_64MHZ // IMPORTANT: 64MHz Clock is required
#pragma config CLKOUTEN = OFF
#pragma config CSWEN = ON
#pragma config FCMEN = ON
#pragma config MCLRE = INTMCLR
#pragma config PWRTE = ON
#pragma config BOREN = SBORDIS
#pragma config BORV = VBOR_190
#pragma config ZCD = OFF
#pragma config PPS1WAY = ON
#pragma config STVREN = ON
#pragma config WDTE = OFF

//==============================================================================
// INCLUDES
//==============================================================================
#include <xc.h>
#include <stdint.h>
#include <string.h>

//==============================================================================
// DEFINES
//==============================================================================
#define _XTAL_FREQ 64000000UL
#define NUM_LEDS 12 // Define how many LEDs are in your strip
#define DIAGNOSTIC_LED_LAT LATCbits.LATC0

// Buffer to hold the GRB color data for each LED
static uint8_t led_color_data[NUM_LEDS * 3];

//==============================================================================
// PROTOTYPES
//==============================================================================
void SYSTEM_Initialize(void);
void PINS_Initialize(void);
void TMR2_Initialize(void);
void CCP2_Initialize(void);
void SPI_Initialize(void);
void CLC_Initialize(void);

void WS2812_SetPixelColor(uint16_t pixel, uint8_t red, uint8_t green, uint8_t blue);
void WS2812_Show(void);

//==============================================================================
// DRIVER FUNCTIONS
//==============================================================================

void WS2812_SetPixelColor(uint16_t pixel, uint8_t red, uint8_t green, uint8_t blue) {
    if (pixel < NUM_LEDS) {
        uint16_t index = pixel * 3;
        led_color_data[index + 0] = green;
        led_color_data[index + 1] = red;
        led_color_data[index + 2] = blue;
    }
}

void WS2812_Show(void) {
    for(uint16_t i = 0; i < sizeof(led_color_data); i++) {
        SSP1IF = 0;
        SSP1BUF = led_color_data[i];
        while(!SSP1IF); // Wait for transmission to complete
    }
    __delay_us(100); // Latch pulse
}


//==============================================================================
// INITIALIZATION ROUTINES
//==============================================================================

void SYSTEM_Initialize(void) {
    OSCCON1 = 0x60;
    OSCFRQ = 0x08;
    
    PINS_Initialize();
    TMR2_Initialize();
    CCP2_Initialize(); // Use CCP2 instead of PWM6
    SPI_Initialize();
    CLC_Initialize();
}

void PINS_Initialize(void) {
    ANSELC = 0x00;
    TRISC = 0x00; // Set all PORTC pins as output for simplicity
    LATC = 0x00;  // Start with all pins low

    PPSLOCK = 0x55;
    PPSLOCK = 0xAA;
    PPSLOCK = 0x00; // Unlock PPS

    RC1PPS = 0x10; // SDO1 -> RC1
    RC3PPS = 0x0F; // SCK1 -> RC3
    RC2PPS = 0x18; // CLC1OUT -> RC2
    
    PPSLOCK = 0x55;
    PPSLOCK = 0xAA;
    PPSLOCK = 0x01; // Lock PPS
}

void TMR2_Initialize(void) {
    T2PR = 19; // Period = (19+1) * 4 * (1/64MHz) = 1.25us => 800kHz

    T2CLKCON = 3;
    T2HLT = 3;
    T2CON = 0b10000000;
}

void CCP2_Initialize(void) {
    // FIX: Use the correct register name as suggested by the compiler.
    CCPTMRSbits.C2TSEL = 0b01;

    // Configure CCP2 for PWM mode
    // FIX: Removed reference to non-existent DC2B bit. The lower two bits
    // of the duty cycle are set to 0 by this single assignment.
    CCP2CON = 0b10001100; // Enable PWM, P2M<1:0> = 00 for single output

    // Set Duty Cycle for the '0' bit high time (~437.5ns)
    // Duty cycle value is 10 bits. (437.5ns / 62.5ns) = 7
    CCPR2L = 7;
}

void SPI_Initialize(void) {
    SSP1ADD = 0; // Not used when clock is TMR2
    SSP1STAT = 0b01000000; // CKE=1
    // SSPM<3:0> = 1011 -> Master mode, clock = TMR2_match/2
    SSP1CON1 = 0b00100011; // SSPEN=1, Set clock source to TMR2
}

void CLC_Initialize(void) {
    // Configure CLC1 as a MUX: (CCP2_OUT & !SDO) | (SCK & SDO)
    CLC1SEL0 = 0x19;       // Input 1: CCP2_OUT
    CLC1SEL1 = 0x2D;       // Input 2: SDO1  
    CLC1SEL2 = 0x2E;       // Input 3: SCK1
    CLC1SEL3 = 0x2D;       // Input 4: SDO1

    CLC1GLS0 = 0b00000010; // Gate 1 logic = S1
    CLC1GLS1 = 0b00001000; // Gate 2 logic = S2
    CLC1GLS2 = 0b00100000; // Gate 3 logic = S3
    CLC1GLS3 = 0b10000000; // Gate 4 logic = S4

    CLC1POL = 0b00000010; // Invert Gate 2 output to get !SDO
    
    CLC1CON = 0b10000100;  // Enable, AND-OR mode
}

//==============================================================================
// MAIN APPLICATION
//==============================================================================
void main(void) {
    SYSTEM_Initialize();
    __delay_ms(10);

    memset(led_color_data, 0, sizeof(led_color_data));
    WS2812_Show();
    __delay_ms(10);

    uint8_t led_position = 0;

    while (1) {
        DIAGNOSTIC_LED_LAT = ~DIAGNOSTIC_LED_LAT;
        
        for (uint8_t i = 0; i < NUM_LEDS; i++) {
            if (i == led_position) {
                WS2812_SetPixelColor(i, 0, 150, 0); // Dim Green
            } else {
                WS2812_SetPixelColor(i, 150, 0, 00);
            }
        }
        WS2812_Show();

        led_position++;
        if (led_position >= NUM_LEDS) {
            led_position = 0;
        }

        __delay_ms(100);
    }
}
 
Timing the trick to get colors right my code it made only white I got new logic tool to find the problem I’ll try out your code Ian thanks
 
I ran this by AI the color problem is timing and from what it said spi is to fast so the high for a 1 is not solid its bunch
of fast toggles
 
Cookies are required to use this site. You must accept them to continue using the site. Learn more…