Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

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
 

Latest threads

New Articles From Microcontroller Tips

Back
Top