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);
}