Simple way of driving WS2812b RGB LEDs

I wrote this to work with ATTiny13, they dont have much flash, so I needed the smallest working WS-driver and Neo was far too large. I was running this as part of a larger program at 9.6mhz on the t13.. works perfectly, but may need adapting

Anyway, in a round about way I came up with this, its quite funny really if you look at the assembler...

#define DIGITAL_PIN   (2)         // Digital port number
#define PORT          (PORTB)     // Digital pin's port
#define PORT_PIN      (PORTB2)    // Digital pin's bit position
#define NUM_CHANS     (4)
uint8_t WSData[NUM_CHANS];

void setup(void) {
  DDRB |= 0b00000100; // set data direction for WS2812 output
}

void loop(void) {
  cli();
  WS2812();
    // do something else here
}

void WS2812(void) { 
    for (volatile uint8_t y=1; y<NUM_CHANS; y++) {
      asm volatile(
          "ldi  %3, 8\n\t"      // reset number of bits
        "nextbit:\n\t"          // label                       
          "sbi  %0, %1\n\t"     // SET OUTPUT HIGH
          "sbrs %4, 7\n\t"      // Skip output low if HiBit in value is set  
            "cbi %0, %1\n\t"      // SET OUTPUT LOW, early for a low
          "sbrc %4, 7\n\t"      // Skip output low if HiBit in value is clear  
            "cbi %0, %1\n\t"      // SET OUTPUT LOW, late for a high
          "rol  %4\n\t"         // shift value left to get to next bit
          "dec  %3\n\t"         // decrement nBits
          "brne nextbit\n\t"    // branch if bits not finished
          ::
          "I" (_SFR_IO_ADDR(PORT)), // %0
          "I" (PORT_PIN),           // %1
          "e" (&PORT),              // %a2
          "r" (8),                  // %3
          "r" (WSData[y])          // %4
        ); // asm
    } // x loop
    delay(10);
}

using the Tiny13 cores, this compiles in under 300 bytes !!

Thanks mcnobby, could be useful one day.

Is the timing likely to close enough on a tiny85 @ 8MHz?

Is the data in WSdata[] preserved?

Paul

Well, as far as timing is concerned, I dont think I have managed 800khz, but in saying that I think the WS2812's are pretty tolerant, I had much slower routines running well before I came up with this, its so simple its almost cheeky !!

Yes, the data is preserved, each array byte is passed into the assembler and immediately goes into a register and then manipulated/bit-rolled/etc

If you ran the t85 at 16mhz you would easily achieve 800khz, although it would be best to try and scope the cycle just to check

Regards

Incidentally, the delay(10); is just there as a simple delay, the actual delay required after the data has been loaded into the devices is 50us

Have you looked at

There's some info there on what the actual tolerances are in the real world and there's quite a bit of difference from the datasheet.

Very very useful bit of information EvilDave, thanks very much !!