diff --git a/flake.nix b/flake.nix index 12ab68c..9f9e167 100644 --- a/flake.nix +++ b/flake.nix @@ -297,9 +297,8 @@ ]; in pkgs.mkShell { - name = "avr-shell"; - buildInputs = avr; - + name = "Wearables-shell"; + buildInputs = avr ++ [ pkgs.gnumake ]; GCC = pkgs.pkgsCross.avr.buildPackages.gcc; SIMAVR = pkgs.pkgsCross.avr.buildPackages.simavr; }; diff --git a/ws2812/Makefile b/ws2812/Makefile new file mode 100644 index 0000000..f691b83 --- /dev/null +++ b/ws2812/Makefile @@ -0,0 +1,11 @@ +MCU=attiny85 +CHIP_SELECT=AVR_ATtiny85 +F_CPU=8000000 +CFLAGS=-O -finline-functions -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes -DF_CPU=${F_CPU} -std=gnu99 -D__${CHIP_SELECT}__=1 -mmcu=${MCU} + +main: + ${GCC}/bin/avr-gcc ${CFLAGS} -I../base/include/ -E -o main.E src/main.c + ${GCC}/bin/avr-gcc ${CFLAGS} -I../base/include/ -S -o main.S src/main.c + ${GCC}/bin/avr-gcc ${CFLAGS} -I${SIMAVR}/include/ -I../base/include/ -o main.elf src/main.c + ${OBJCOPY} -O ihex main.elf main.hex + diff --git a/ws2812/src/main.c b/ws2812/src/main.c index 091dbd2..b5c2b95 100644 --- a/ws2812/src/main.c +++ b/ws2812/src/main.c @@ -3,29 +3,22 @@ #include "ws2812.h" #include "np_common.c" -/* #include AVR_MCU(F_CPU, "attiny85"); const struct avr_mmcu_vcd_trace_t _mytrace[] _MMCU_ = { - { AVR_MCU_VCD_SYMBOL("GTCCR"), .what = (void*)>CCR, }, - // { AVR_MCU_VCD_SYMBOL("TCCR0B"), .what = (void*)&TCCR0B, }, - { AVR_MCU_VCD_SYMBOL("TIMSK"), .what = (void*)&TIMSK, }, - { AVR_MCU_VCD_SYMBOL("TIFR"), .what = (void*)&TIFR, }, - { AVR_MCU_VCD_SYMBOL("OCR0A"), .what = (void*)&OCR0A, }, - { AVR_MCU_VCD_SYMBOL("OCR0B"), .what = (void*)&OCR0B, }, - { AVR_MCU_VCD_SYMBOL("current"), .what = (void*)¤t, }, - { AVR_MCU_VCD_SYMBOL("idx"), .what = (void*)&idx, }, - { AVR_MCU_VCD_SYMBOL("cnt"), .what = (void*)&cnt, }, - { AVR_MCU_VCD_SYMBOL("val"), .what = (void*)&val, }, - // { AVR_MCU_VCD_SYMBOL("DDRB"), .what = (void*)&DDRB, }, + { AVR_MCU_VCD_SYMBOL("DDRB"), .what = (void*)&DDRB, }, { AVR_MCU_VCD_SYMBOL("PORTB"), .what = (void*)&PORTB, }, - // { AVR_MCU_VCD_SYMBOL("TCNT0"), .what = (void*)&TCNT0, }, - // { AVR_MCU_VCD_SYMBOL("TCNT1"), .what = (void*)&TCNT1, }, }; -*/ #define PIXEL_COUNT 7 +/* +const uint8_t pixels_0[PIXEL_COUNT * 3] = + { 255, 0, 255, + 255, 255, 0, + 255, 255, 255 }; + */ + const uint8_t pixels_1[PIXEL_COUNT * 4] = { 0, 0, 0, 0, 32, 0, 0, 0, @@ -68,19 +61,47 @@ void blink(void) { PORTB &= ~(_BV(2)); } -int main (void) { - _delay_ms(1000); +/* +void fade_in(const uint8_t *pixels); +void fade_out(void); +void fade_in(const uint8_t *pixels) { + uint8_t current[PIXEL_COUNT * 4]; + for (int i = 0; i < 255; i++) { + for (int idx = 0; idx < PIXEL_COUNT * 4; idx++) { + if (current[idx] < pixels[idx]) { + current[idx] += 1; + } + } + write_pixels(current, PIXEL_COUNT * 4); + _delay_ms(5); + } +} + +void fade_out() { + uint8_t current[PIXEL_COUNT * 4]; + for (int i = 0; i < 255; i++) { + for (int idx = 0; idx < PIXEL_COUNT * 4; idx++) { + if (current[idx] > 0) { + current[idx] -= 1; + } + } + write_pixels(current, PIXEL_COUNT * 4); + _delay_ms(5); + } +} +*/ + +int main (void) { PORTB = 0; - DDRB = _BV(0) | _BV(1) | _BV(2); + DDRB = _BV(0) | _BV(1) | _BV(2) | _BV(3); _delay_ms(50); blink(); - np_initialize(); - sei(); _delay_ms(500); + /* while (1) { blink(); write_pixels(pixels_1, PIXEL_COUNT * 4); @@ -90,5 +111,61 @@ int main (void) { write_pixels(pixels_3, PIXEL_COUNT * 4); _delay_ms(1000); write_pixels(pixels_4, PIXEL_COUNT * 4); + _delay_ms(1000); } + */ + + + uint8_t pixels[7 * 3]; + for (uint8_t i = 0; i < 7 * 3; i++) { + pixels[i] = 0; + } + + int8_t r_step = 1; + int8_t g_step = 0; + int8_t b_step = 0; + while (1) { + pixels[0] += r_step; + pixels[3] += r_step; + pixels[6] += r_step; + pixels[9] += r_step; + pixels[12] += r_step; + pixels[15] += r_step; + pixels[18] += r_step; + // pixels[1] += g_step; + // pixels[2] += b_step; + write_pixels(pixels, 7 * 3); + if (pixels[0] == 255) { + r_step = -1; + } else if (pixels[0] == 0) { + r_step = 1; + } + /* + if (pixels[0] == 255) { + r_step = -1; + g_step = 1; + } else if (pixels[0] == 0 && r_step == -1) { + r_step = 0; + } + */ + + /* + if (pixels[1] == 255) { + g_step = -1; + b_step = 1; + } else if (pixels[1] == 0 && g_step == -1) { + g_step = 0; + } + + if (pixels[2] == 255) { + b_step = -1; + r_step = 1; + } else if (pixels[2] == 0 && b_step == -1) { + b_step = 0; + } + */ + _delay_ms(5); + } + + return 0; } diff --git a/ws2812/src/np_common.c b/ws2812/src/np_common.c index 7968c41..e11649d 100644 --- a/ws2812/src/np_common.c +++ b/ws2812/src/np_common.c @@ -17,67 +17,73 @@ void latch(io_pin_t *addr) { #define T1_HIGH 7 #define T_FRAME 11 -volatile uint8_t bit = 0; -volatile uint8_t val = 0; -volatile uint32_t idx = 0; -volatile uint8_t sub_idx = 0; -volatile const uint8_t *data = NULL; -volatile uint32_t cnt = 0; +#define write_bit(label, bit) \ + "out %[port], %[hi]" "\n\t" \ + "nop" "\n\t" \ + "sbrc %[byte], " #bit "\n\t" \ + "rjmp .+0" "\n\t" \ + "out %[port], %[low]" "\n\t" \ + "rjmp .+0" "\n\t" \ + "rjmp .+0" "\n\t" \ -ISR(TIMER0_OVF_vect) { - // If we have sent all of the bytes - if (idx >= cnt) { - // Turn off the clock - TCCR0B &= ~(_BV(CS00)); - // Disconnect OC0A and OC0B - TCCR0A &= ~(_BV(COM0A1) | _BV(COM0A0) | _BV(COM0B1) | _BV(COM0B0)); - // Write a 0 to the PORTB[1] / OC0B - PORTB &= ~(_BV(1)); +/* +#define write_bit(label, bit) \ + "bst %[byte], " #bit "\n\t" \ + "out %[port], %[hi]" "\n\t" \ + "nop" "\n\t" \ + "brtc " label "\n\t" \ + "rjmp .+0" "\n\t" \ + label ": " "out %[port], %[low]" "\n\t" \ + "rjmp .+0" "\n\t" \ + "rjmp .+0" "\n\t" + */ - // After this, the timer should be stopped and we shouldn't see any further interrupts. - return; - } - // if the current bit is high, spend T1_HIGH ticks with the line asserted. - // Otherwise, assert for T0_HIGH ticks. - OCR0B = bit ? T1_HIGH : T0_HIGH; +inline void write_byte(volatile uint8_t *port, uint8_t hi, uint8_t low, uint8_t byte) { + __asm__ __volatile__ ( + write_bit("A_%=", 7) + write_bit("B_%=", 6) + write_bit("C_%=", 5) + write_bit("D_%=", 4) + write_bit("E_%=", 3) + write_bit("F_%=", 2) + write_bit("G_%=", 1) + write_bit("H_%=", 0) + : /* No outputs */ + : [port] "I" (_SFR_IO_ADDR(PORTB)), + [hi] "r" (hi), + [low] "r" (low), + [byte] "r" (byte) + ); - // Now that we have the timer set correctly, let's preload the next bit - - // If we're at the last bit for the curret byte, let's move on to the next byte - if (sub_idx == 8) { - sub_idx = 0; - idx++; - val = data[idx]; - } - - // Load the bit from the current value - bit = val & _BV(sub_idx); - - // And then increment to the next bit for the next iteration - sub_idx++; + // __asm__ __volatile__ ( + /* + "ldi r24, 8" "\n\t" // count out eight bits. One higher than normal because I do the final check *after* the counter decrements. I'm effectively 1-based + "lsl %[byte]" "\n\t" // output data left, saving the msb in SREG (1 cycle) + "bst sreg, 0" "\n\t" // Save hte carry flag to the transfer bit + "L_%=: " "out %[port], %[hi]" "\n\t" // enable the port + "brtc I_%=" "\n\t" // If we shifted out a 0, if SREG[C] is clear, immediately branch I_%= (2 cycles if true, 1 cycle if false) + "nop" "\n\t" // We shifted out a 1, so wait just a touch longer + "nop" "\n\t" + "nop" "\n\t" + "I_%=: " "out %[port], %[low]" "\n\t" // now clear the pin + // I now have five ticks before I can re-enable the pin + "lsl %[byte]" "\n\t" // Shift out the next bit + "bst sreg, 0" "\n\t" + "dec r24" "\n\t" // Decrement the bit counter + "cpi r24, 0" "\n\t" // Is the bit counter 0? + "brne L_%=" "\n\t" // If we haven't reached 0, we have more data to send + */ } void write_pixels(const uint8_t *pixels, uint8_t length) { - data = pixels; - cnt = length; - - // Set OC0B to Fast PWM, Clear on Match, Set on Bottom mode - TCCR0A |= _BV(COM0B1); - - // Enable the clock - TCCR0B |= _BV(CS00); - - // Now wait until the clock gets turned off. - while (TCCR0B & _BV(CS00)) { } -} - -void np_initialize() { - // latch(addr); - - TCCR0B = _BV(WGM02); - TCCR0A = _BV(WGM01) | _BV(WGM00); - TIMSK = _BV(TOIE0); - OCR0A = T_FRAME; + uint8_t hi = PORTB | (1 << 3); + uint8_t low = PORTB & ~(1 << 3); + cli(); + for (int idx = 0; idx < length; idx++) { + write_byte(&PORTB, hi, low, pixels[idx]); + } + _delay_us(100); + sei(); } diff --git a/ws2812/src/ws2812.h b/ws2812/src/ws2812.h index 9f5656b..35cba1b 100644 --- a/ws2812/src/ws2812.h +++ b/ws2812/src/ws2812.h @@ -17,8 +17,8 @@ typedef struct RGBW_s { uint8_t w; } rgbw_t; -void np_initialize(); -void np_write_rgb(io_pin_t *addr, rgb_t *values, uint8_t length); +// void np_initialize(); +// void np_write_rgb(io_pin_t *addr, rgb_t *values, uint8_t length); void write_pixels(const uint8_t *pixels, uint8_t length); // void np_write_grb(io_pin_t *addr, rgb_t *values, uint8_t length); // void np_write_rgbw(io_pin_t *addr, rgbw_t *values, uint8_t length);