
/*
 * ws2812.s
 *
 * Created: 12.12.2012 01:09:32
 *  Author: adrock
 */ 

 #include <avr/io.h>
 #include "asmdefs.h"

 #define    F_OUT   800000
 #define    F_CPU   16000000

 #define    CNT_TOTAL   ((F_CPU/F_OUT)-1)
 #define    CNT_LOW     ((F_CPU/F_OUT)/3-1)
 #define    CNT_HIGH    (((F_CPU/F_OUT)*2)/3-1)

 .global WS_init
 .global WS_put


WS_init:
    cbi     _SFR_IO_ADDR(PORTB), PB1
    sbi     _SFR_IO_ADDR(DDRB), PB1
    ldi     r24, (1<<COM0B1)|(1<<WGM01)|(1<<WGM00)
    STORE   TCCR0A, r24
    ldi     r24, CNT_TOTAL
    STORE   OCR0A, r24
   
    ret


WS_put:
    movw    r26, r24
    movw    r24, r22
  
    ldi     r22, (1<<OCF0A)             // r22 = value to reset OCF0A
    ldi     r23, (1<<CS00)|(1<<WGM02)   // r23 = value to start counter
    ldi     r18, CNT_LOW                // r18 = low OCR0B value
    ldi     r19, CNT_HIGH               // r19 = high OCR0B value

    STORE   OCR0B, r1                   // OCR0B = 0 -> zero cycle at beginning
    STORE   TCNT0, r1                   // Clear timer
    STORE   TCCR0B, r23                 // start timer

    // X: ptr to next byte, r24/r25: Output byte counter

WS_put1:
    sbiw    r24, 0x01                   // dec counter
    brcs    WS_put_end                  // no more bytes

    ld      r0, X+                      // Get next byte

    // Some loop unrolling to save cycles...

.macro  BITOUT bitnum
    STORE   TIFR, r22                   // clear OCF0A flag

    STORE   OCR0B, r18                  // set OCR0B to low val
    sbrc    r0, \bitnum                 // skip if bit is cleared
    STORE   OCR0B, r19                  // set OCR0B to high val

WS_put_bit_\bitnum:
    LOAD    r20, TIFR
    sbrs    r20, OCF0A
    rjmp    WS_put_bit_\bitnum
.endm

    BITOUT  7
    BITOUT  6
    BITOUT  5
    BITOUT  4
    BITOUT  3
    BITOUT  2
    BITOUT  1
    BITOUT  0

    rjmp    WS_put1

WS_put_end:
    STORE   TIFR, r22                   // clear OCF0A flag
    STORE   OCR0B, r1                   // last OCR0B = 0 

WS_put_waitfinal:
    LOAD    r20, TIFR
    sbrs    r20, OCF0A
    rjmp    WS_put_waitfinal

    STORE   TCCR0B, r1                  // stop timer
    ret