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.

ns to us delay

Im runing at 64 mhz trying to come up with a delay for ns

Heres the code its for ws2812b leds
Code:
/*
 * File:   newmain.c
 * Author: burt
 *
 * Created on March 8, 2025, 3:44 PM
 */

#define _XTAL_FREQ 64000000
#include <xc.h>
#include <stdint.h>
//#include <libpic30.h> // For delay functions

// Configuration bits for PIC18F25Q10 (adjust as needed)
#pragma config FEXTOSC = OFF, RSTOSC = HFINTOSC_64MHZ // Use internal 64MHz oscillator
#pragma config CLKOUTEN = OFF, CSWEN = ON, FCMEN = ON
#pragma config MCLRE = ON, PWRTE = OFF, WDTE = OFF, LPBOREN = OFF, BOREN = OFF
#pragma config LVP = OFF, PPS1WAY = ON, STVREN = ON, DEBUG = OFF
#pragma config WRT = OFF, CP = OFF, CPD = OFF

#define WS2812_PIN LATCbits.LATC0 // Use RC0 for WS2812B data
#define WS2812_TRIS TRISCbits.TRISC0

// Timing constants (adjust if needed, based on 64MHz clock)
//#define T0H 350 // Time high for 0 bit (ns)
//#define T0L 900 // Time low for 0 bit (ns)
//#define T1H 800 // Time high for 1 bit (ns)
//#define T1L 450 // Time low for 1 bit (ns)
//#define RESET_TIME 55 // Reset time in microseconds

#define NUM_LEDS 30 // Number of LEDs
uint8_t ledData[NUM_LEDS * 3]; // RGB data

void sendBit(uint8_t bit) {
    WS2812_PIN = 1;
    if (bit) {
        __delay_ns(800);
        WS2812_PIN = 0;
        __delay_ns(450);
    } else {
        __delay_ns(350);
        WS2812_PIN = 0;
        __delay_ns(900);
    }
}

void sendByte(uint8_t byte) {
    for (int i = 7; i >= 0; i--) {
        sendBit((byte >> i) & 1);
    }
}

void sendLEDData() {
    for (int i = 0; i < NUM_LEDS * 3; i++) {
        sendByte(ledData[i]);
    }
    __delay_us(55);
}

void main(void) {
    // Oscillator setup (if needed, but 64MHz is set in config)
    // OSCCON1 = 0x60; // Select HFINTOSC (already in config)

    WS2812_TRIS = 0; // Set RC0 as output

    // Initialize LED data (example: red, green, blue pattern)
    for (int i = 0; i < NUM_LEDS; i++) {
        if(i%3 == 0){ledData[i * 3] = 255; ledData[i * 3 + 1] = 0; ledData[i * 3 + 2] = 0;} //red
        else if (i%3 == 1){ledData[i * 3] = 0; ledData[i * 3 + 1] = 255; ledData[i * 3 + 2] = 0;} //green
        else{ledData[i * 3] = 0; ledData[i * 3 + 1] = 0; ledData[i * 3 + 2] = 255;} //blue
    }

    while (1) {
        sendLEDData();
        __delay_ms(20); // Delay between frames
    }
}
 
this did build
Code:
/*
 * File:   newmain.c
 * Author: burt
 *
 * Created on March 8, 2025, 3:44 PM
 */

#define _XTAL_FREQ 64000000
#include <xc.h>
#include <stdint.h>
//#include <libpic30.h> // For delay functions

// Configuration bits for PIC18F25Q10 (adjust as needed)
#pragma config FEXTOSC = OFF, RSTOSC = HFINTOSC_64MHZ // Use internal 64MHz oscillator
#pragma config CLKOUTEN = OFF, CSWEN = ON, FCMEN = ON
#pragma config MCLRE = EXTMCLR, PWRTE = OFF, WDTE = OFF, LPBOREN = OFF, BOREN = OFF
#pragma config LVP = OFF, PPS1WAY = ON, STVREN = ON
#pragma config CP = OFF, CPD = OFF
#pragma config WRT0 = OFF       // Write Protection Block 0 (Block 0 (000800-001FFFh) not write-protected)
#pragma config WRT1 = OFF       // Write Protection Block 1 (Block 1 (002000-003FFFh) not write-protected)
#pragma config WRT2 = OFF       // Write Protection Block 2 (Block 2 (004000-005FFFh) not write-protected)
#pragma config WRT3 = OFF       // Write Protection Block 3 (Block 3 (006000-007FFFh) not write-protected)

#define WS2812_PIN LATCbits.LATC0 // Use RC0 for WS2812B data
#define WS2812_TRIS TRISCbits.TRISC0

// Timing constants (adjust if needed, based on 64MHz clock)
//#define T0H 350 // Time high for 0 bit (ns)
//#define T0L 900 // Time low for 0 bit (ns)
//#define T1H 800 // Time high for 1 bit (ns)
//#define T1L 450 // Time low for 1 bit (ns)
//#define RESET_TIME 55 // Reset time in microseconds

#define NUM_LEDS 30 // Number of LEDs
uint8_t ledData[NUM_LEDS * 3]; // RGB data

void sendBit(uint8_t bit) {
    WS2812_PIN = 1;
    if (bit) {
        __delay_ms(.8);
        WS2812_PIN = 0;
        __delay_ms(.45);
    } else {
        __delay_ms(.35);
        WS2812_PIN = 0;
        __delay_ms(.9);
    }
}

void sendByte(uint8_t byte) {
    for (int i = 7; i >= 0; i--) {
        sendBit((byte >> i) & 1);
    }
}

void sendLEDData() {
    for (int i = 0; i < NUM_LEDS * 3; i++) {
        sendByte(ledData[i]);
    }
    __delay_us(55);
}

void main(void) {
    // Oscillator setup (if needed, but 64MHz is set in config)
    // OSCCON1 = 0x60; // Select HFINTOSC (already in config)
    ANSELCbits.ANSELC0 = 0;
    WS2812_TRIS = 0; // Set RC0 as output

    // Initialize LED data (example: red, green, blue pattern)
    for (int i = 0; i < NUM_LEDS; i++) {
        if(i%3 == 0){ledData[i * 3] = 255; ledData[i * 3 + 1] = 0; ledData[i * 3 + 2] = 0;} //red
        else if (i%3 == 1){ledData[i * 3] = 0; ledData[i * 3 + 1] = 255; ledData[i * 3 + 2] = 0;} //green
        else{ledData[i * 3] = 0; ledData[i * 3 + 1] = 0; ledData[i * 3 + 2] = 255;} //blue
    }

    while (1) {
        sendLEDData();
        __delay_ms(20); // Delay between frames
    }
}
 
Last edited:
You can just execute about 12
NOP();
Instructions and you'll have your 800nSec delay (do the math, this is an estimate for four clock cycles per instruction at 64MHz
 
That’s to easy I’d miss every one reply’s
13 is closer libpic30.h has __delay_ns was hoping for something like it.
 
Last edited:
I have a work-in-progress neopixels style driver that may help;

I was formatting the data bytes up to padded 32 bit values, then use SPI to DMA blast it to the LEDs.

C:
//
// Convert a byte to neopixel format
//
void repack(uint32_t *outbits, int8_t inp) {
    //
    //
    uint32_t *pixbits;
    int8_t val;
    pixbits = outbits;
    val = inp;
        
    *pixbits = 0x88888888L;
        
    if(val & 0x01) *pixbits |= 0x00000004L;
    if(val & 0x02) *pixbits |= 0x00000040L;
    if(val & 0x04) *pixbits |= 0x00000400L;
    if(val & 0x08) *pixbits |= 0x00004000L;
    if(val & 0x10) *pixbits |= 0x00040000L;
    if(val & 0x20) *pixbits |= 0x00400000L;
    if(val & 0x40) *pixbits |= 0x04000000L;
    if(val & 0x80) *pixbits |= 0x40000000L;
        
}


Using ping-pong buffering, so two buffer sets, one for loading and one for output. With the CCS compiler I use, a DMA output is a single line instruction. There is also a function to check when that is complete.

C:
//
        // ping-pong buffer system;
        // exchange input and output buffers each time through.
        bufsel++;
        
        if(bufsel & 1) {
            b_set = buffer_b;
            b_out = buffer_a;
        }
        else {
            b_set = buffer_a;
            b_out = buffer_b;
        }
        
        
        // Send last updated buffer
        spi_transfer_write(b_out, cbytes);

I'm aiming for smooth animation speeds on large strings or arrays..
The MCU is a DSPIC33E series, so lots of RAM available.

A similar routine could be used to output one pixel worth at a time though, using SPI to send one pixel while preparing the next.
 
I imagine if you're wanting nS delays, then ASM is the way to go, as you don't really know what the C compiler is going to do with the code - particularly with the free version of XC8.

You've also got the added issue of the surrounding code, calling and returning from the delay - which could easily mess it up.

However, there's example code for NeoPixels at MicroChip, using the CLC - I've used that for various PIC processors and all have worked fine - which just very minor tweaks.

Here's a YouTube video:

 

Latest threads

Back
Top