OWN WS2812 Lib

Hi everyone,

I am currently trying to transfer the WS2812 lib I wrote for the Cortex M0 to the Arduino Nano. I just can’t figure out what’s wrong or why it’s not working. Only the first RGB lights up and no matter which values I define in the code, it is always white with the maximum luminosity.

Maybe you can help me with that.

Cpp:

#include "WS2812.h"

WS2812::WS2812(int DataPin, int Lenght){
    pinMode(DataPin, OUTPUT);
    _data = DataPin;
    _lenght = Lenght;
    pinMode(_data, OUTPUT);
};

void WS2812::WriteLed(int pos, uint8_t r, uint8_t g, uint8_t b){    // define the register
    _ledmatrix[pos][0] = g;      // green register
    _ledmatrix[pos][1] = r;      // red register
    _ledmatrix[pos][2] = b;      // blue register
}

void WS2812::WriteLedBit(char wert){
    
    if(wert){           // example: if(1) than make what is declatrated
        digitalWrite(_data, HIGH);
            delayMicroseconds(0.5);
            //for(int i=0;i<HIGH_SIGNAL;i++) NOP;     // wait is to slow, becouse reset = 50µs
        digitalWrite(_data, LOW);
            delayMicroseconds(0.2);
            //for(int i=0;i<LOW_SIGNAL;i++) NOP;
    }
    
    else{   // else make this
        digitalWrite(_data, HIGH);
            delayMicroseconds(0.2);
            //for(int i=0;i<LOW_SIGNAL;i++) NOP;
        digitalWrite(_data, LOW);
        delayMicroseconds(0.5);
            //for(int i=0;i<HIGH_SIGNAL;i++) NOP;
    }
}

void WS2812::wirte(int position, uint8_t red, uint8_t green, uint8_t blue){
    WriteLed(position,  red,  green, blue);

    for(int led = 0; led < _lenght; led++){     // write the matrix on the RGBs
        for(int i = 0; i < 3; i++){         // write the position
            for(int b = 0; b < 8; b++){     // write the bit
                WriteLedBit(_ledmatrix[led][i] & 1<<b);  // write the byte on the RGBs
            }
        }
    }
    _delay_us(DELAY);
}

Header:

#ifndef WS2812_h
#define WS2812_h

#include <Arduino.h>

class WS2812{
    #define HIGH_SIGNAL 5
    #define LOW_SIGNAL 0
    #define DELAY 0.1
    #define NOP __asm__("nop\n\t")

    public:
        void wirte(int position, uint8_t red, uint8_t green, uint8_t blue);
        WS2812(int DataPin, int Lenght);
    private:
        void WriteLedBit(char wert);
        void WriteLed(int pos, uint8_t g, uint8_t r, uint8_t b);
        int _data, _lenght;
        uint8_t _ledmatrix[3][3];
};

#endif

main:

#include <Arduino.h>
#include "WS2812.h"

WS2812 ws2812(7, 3);

void setup() {
    // put your setup code here, to run once:
}

void loop() {
    // put your main code here, to run repeatedly:
    ws2812.wirte(0,0,0,50);
}

Please post the full code here. If possible you should always post code directly in the forum thread as text using code tags (</> button on the toolbar). This will make it easy for anyone to look at it, which will increase the likelihood of you getting help. If the code is longer than the forum will allow then it’s ok to add it as an attachment. Don’t put your code in some external file service like dropbox, etc. We shouldn’t need to go to an external website just to help you. I do feel it’s reasonable to post a link to code hosted on GitHub or similar code hosting sites since that’s an platform specifically designed for this sort of thing

Please provide a complete description of what’s not working.

I think that digitalWrite() is too slow. Try to wrote to the GPIO-registers directly.

I have now accessed the GPIO ports directly and it still seems to be a timing problem. None of the RGBs are glowing.

These is my reworked code. I used this website to see how I can write to the ports directly:(How to control arduino pins from registers without digitalWrite and digitalRead | eprojectszone)

WS2812::WS2812(int DataPin, int Lenght){
    _data = DataPin;
    _lenght = Lenght;
    DDRD |= (1<<DD7);
};

void WS2812::WriteLedBit(char wert){
    
    if(wert){           // example: if(1) than make what is declatrated
        PORTD |= (1<<PORTD7);   // set high
            //delayMicroseconds(0.5);
            for(int i=0;i<HIGH_SIGNAL;i++) NOP;     // wait is to slow, becouse reset = 50µs
        PORTD &=~(1<<PORTD7);   // set low
            //delayMicroseconds(0.2);
            for(int i=0;i<LOW_SIGNAL;i++) NOP;
    }
    
    else{   // else make this
        DDRD |= (1<<DD7);   // set high
            //delayMicroseconds(0.2);
            for(int i=0;i<LOW_SIGNAL;i++) NOP;
        PORTD &=~(1<<PORTD7);   // set low
            //delayMicroseconds(0.5);
            for(int i=0;i<HIGH_SIGNAL;i++) NOP;
    }
}

Does this compile for ARM? I think DDRD and PORTD are AVR-only.

Rintin: Does this compile for ARM? I think DDRD and PORTD are AVR-only.

Yes read what he is trying to do

I am currently trying to transfer the WS2812 lib I wrote for the Cortex M0 to the Arduino Nano

So he is right to use AVR only port addresses.

To the OP you need to look with an oscilloscope to see if your timing is correct.

Ok thanks. I'll see in the next few days if my timing is correct.

Grumpy_Mike:
Yes read what he is trying to doSo he is right to use AVR only port addresses.

Ok… need more sleep…

For AVR you have to count clock cycles to make the driver work. And don’t forget to disable interrupts.
You have to switch to assembler like this code