avr/ws2812/ws2812.c

109 lines
2.9 KiB
C

#include <avr/interrupt.h>
# include "ws2812.h"
// inline void write_zero(dio_t *pin, uint8_t hi, uint8_t low) {
// uint8_t *val;
// uint8_t *hi_reg;
// uint8_t *low_reg;
// __asm__ __volatile__ (
// "ldd %[hi_reg], %[hi]\n"
// "ldd %[low_reg], %[low]\n"
// "ldd %[val], %[pin]\n"
// "or %[val], %[hi_reg]\n"
// "std %[pin], %[val]\n"
// "nop\n"
// "nop\n"
// "and %[val], %[hi_reg]\n"
// "std %[pin], %[val]\n"
// "nop\n"
// "nop\n"
// "nop\n"
// /* Need another 5 cycles */
// : [val] "=r" (val), [hi_reg] "=r" (hi_reg), [low_reg] "=r" (low_reg)
// : [pin] "m" (pin->port), [hi] "m" (hi), [low] "m" (low)
// );
// }
// inline void write_one(dio_t *port, uint8_t hi, uint8_t low) {
// __asm__ __volatile__ (
// "or %0, %1\n"
// "nop\n"
// "nop\n"
// "nop\n"
// "nop\n"
// "nop\n"
// "nop\n"
// "and %0, %1\n"
// /* Need another 5 cycles */
// : /* no outputs */
// : "m" (port->port),
// "m" (hi),
// "m" (low)
// );
// }
inline void write_byte(dio_t *pin, uint8_t hi, uint8_t low, const uint8_t value) {
uint8_t *state_r;
uint8_t *hi_r;
uint8_t *low_r;
uint8_t *counter;
__asm__ __volatile__ (
"ldi r16, 8\n"
"ldi r17, %[value]\n"
"ldd %[hi_r], %[hi]\n"
"ldd %[low_r], %[low]\n"
"ldd %[state_r], %[pin]\n"
"L_%=: " "lsl __tmp_reg__\n"
"brbs I_%=\n"
"or %[state_r], %[hi_r]\n"
"nop\n"
"nop\n"
"and %[state_r], %[low_r]\n"
"nop\n"
"nop\n"
"nop\n"
"rjmp J_%=\n"
"I_%=: "
"brbs I_%=\n"
"or %[state_r], %[hi_r]\n"
"nop\n"
"nop\n"
"nop\n"
"nop\n"
"nop\n"
"and %[state_r], %[low_r]\n"
"J_%=: " "dec %[counter]\n"
"cpi %[counter], 0\n"
"brne L_%="
: [state_r] "=r" (state_r),
[hi_r] "=r" (hi_r),
[low_r] "=r" (low_r),
[counter] "=r" (counter)
: [pin] "m" (pin->port),
[hi] "m" (hi),
[low] "m" (low),
[value] "m" (value)
);
}
void np_write_rgb(dio_t *pin, const rgb_t *pixels, uint8_t length) {
cli();
uint8_t hi = 1 << pin->addr;
uint8_t low = ~hi;
for (int idx = 0; idx < length; idx++) {
write_byte(pin, hi, low, pixels[idx].r);
write_byte(pin, hi, low, pixels[idx].g);
write_byte(pin, hi, low, pixels[idx].b);
}
sei();
}