From 136a1da5b3c497fa583fdb6e8e1a3ae48610a476 Mon Sep 17 00:00:00 2001 From: Savanni D'Gerinel Date: Sat, 24 Jun 2023 23:48:09 -0400 Subject: [PATCH] Tried cleaning things up and putting out some new assembly didn't work --- flake.nix | 22 +++++ ws2812/direct_write_assembly.c | 30 ++++-- ws2812/main.c | 163 ++------------------------------- ws2812/np_common.c | 89 ------------------ ws2812/np_rgb.c | 5 - ws2812/ws2812.c | 108 ++++++++++++++++++++++ ws2812/ws2812.h | 5 +- 7 files changed, 162 insertions(+), 260 deletions(-) delete mode 100644 ws2812/np_common.c delete mode 100644 ws2812/np_rgb.c create mode 100644 ws2812/ws2812.c diff --git a/flake.nix b/flake.nix index 9f9e167..1a2e50c 100644 --- a/flake.nix +++ b/flake.nix @@ -284,6 +284,28 @@ ]; }; + packages."x86_64-linux"."ws2812_" = + let + pkgs = import nixpkgs { system = "x86_64-linux"; }; + avr = pkgs.pkgsCross.avr.buildPackages; + in packages."x86_64-linux"."ws2812" { gcc = "${avr.gcc}/bin/avr-gcc"; cflags = mcu_cflags attiny85; avr = true; }; + packages."x86_64-linux"."ws2812" = + { gcc, cflags, avr }: + let + pkgs = import nixpkgs { system = "x86_64-linux"; }; + in mkProgram { + pkgs = pkgs; + gcc = gcc; + cflags = cflags; + pname = "ws2812"; + psrc = ./ws2812; + inherit avr; + + pbuildInputs = [ + (packages."x86_64-linux"."dio" { inherit gcc cflags; }) + ]; + }; + devShell."x86_64-linux" = let pkgs = import nixpkgs { system = "x86_64-linux"; }; diff --git a/ws2812/direct_write_assembly.c b/ws2812/direct_write_assembly.c index 58d02c2..9e085c4 100644 --- a/ws2812/direct_write_assembly.c +++ b/ws2812/direct_write_assembly.c @@ -26,16 +26,26 @@ #define write_byte(port, bit, byte) \ __asm__ __volatile__ ( \ - "ldi %z, 8" "\n\t" \ // count out eight bits - "ld __tmp_reg__, %[byte]" "\n\t" \ // load the current byte into a temporary register - "L_%=: " "lsl __tmp_reg__" "\n\t" \ // shift the temporary register left, saving the msb in SREG (1 cycle) - "brbs I_%=" "\n\t" \ // if SREG is set, branch to I_%= (2 cycles if true, 1 cycle if false) - write_zero(port, bit) \ // SREG was zero, so write a zero to the port - "rjmp J_%=" "\n\t" \ // Jump to J_%=, the loop cleanup (2 cycles) - "I_%=: " write_one(port, bit) \ // SREG was one, so write a one to the port - "J_%=: " "dec %z" "\n\t" \ // Decrement the bits counter (1 cycle) - "cpi %z, 0" "\n\t" \ // are there any bits left to send? (1 cycle) - "brne L_%=" "\n\t" \ // there are, so go back to L_%= (2 cycles) + ; count out eight bits \ + "ldi %z, 8" "\n\t" \ + ; load the current byte into a temporary register \ + "ld __tmp_reg__, %[byte]" "\n\t" \ + ; shift the temporary register left, saving the msb in SREG (1 cycle) \ + "L_%=: " "lsl __tmp_reg__" "\n\t" \ + ; if SREG is set, branch to I_%= (2 cycles if true, 1 cycle if false) \ + "brbs I_%=" "\n\t" \ + ; SREG was zero, so write a zero to the port \ + write_zero(port, bit) \ + ; Jump to J_%=, the loop cleanup (2 cycles) \ + "rjmp J_%=" "\n\t" \ + ; SREG was one, so write a one to the port \ + "I_%=: " write_one(port, bit) \ + ; Decrement the bits counter (1 cycle) \ + "J_%=: " "dec %z" "\n\t" \ + ; are there any bits left to send? (1 cycle) \ + "cpi %z, 0" "\n\t" \ + ; there are, so go back to L_%= (2 cycles) \ + "brne L_%=" "\n\t" \ : /* no outputs */ \ : [byte] "I" (byte) \ ) diff --git a/ws2812/main.c b/ws2812/main.c index b5c2b95..bec9e65 100644 --- a/ws2812/main.c +++ b/ws2812/main.c @@ -1,8 +1,9 @@ #include #include +#include #include "ws2812.h" -#include "np_common.c" +/* #include AVR_MCU(F_CPU, "attiny85"); @@ -10,162 +11,18 @@ const struct avr_mmcu_vcd_trace_t _mytrace[] _MMCU_ = { { AVR_MCU_VCD_SYMBOL("DDRB"), .what = (void*)&DDRB, }, { AVR_MCU_VCD_SYMBOL("PORTB"), .what = (void*)&PORTB, }, }; - -#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, - 64, 0, 0, 0, - 96, 0, 0, 0, - 128, 0, 0, 0, - 160, 0, 0, 0, - 192, 0, 0, 0 }; - -const uint8_t pixels_2[PIXEL_COUNT * 4] = - { 0, 0, 0, 0, - 0, 32, 0, 0, - 0, 64, 0, 0, - 0, 96, 0, 0, - 0, 128, 0, 0, - 0, 160, 0, 0, - 0, 192, 0, 0 }; - -const uint8_t pixels_3[PIXEL_COUNT * 4] = - { 0, 0, 0, 0, - 0, 0, 32, 0, - 0, 0, 64, 0, - 0, 0, 96, 0, - 0, 0, 128, 0, - 0, 0, 160, 0, - 0, 0, 192, 0 }; - -const uint8_t pixels_4[PIXEL_COUNT * 4] = - { 0, 0, 0, 0, - 0, 0, 0, 32, - 0, 0, 0, 64, - 0, 0, 0, 96, - 0, 0, 0, 128, - 0, 0, 0, 160, - 0, 0, 0, 192 }; - -void blink(void) { - PORTB |= _BV(2); - _delay_ms(100); - PORTB &= ~(_BV(2)); -} - -/* -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); - } -} */ +#define PIXEL_COUNT 1 +const rgb_t pixels[PIXEL_COUNT] = { + (rgb_t){ .r = 255, .g = 0, .b = 255, }, +}; + int main (void) { - PORTB = 0; - DDRB = _BV(0) | _BV(1) | _BV(2) | _BV(3); - _delay_ms(50); + dio_t pin = (dio_t){ .ddr = &DDRB, .port = &PORTB, .pin = &PINB, .addr = 2 }; + dio_set_direction(&pin, LINE_OUT); - blink(); - - _delay_ms(500); - - /* - while (1) { - blink(); - write_pixels(pixels_1, PIXEL_COUNT * 4); - _delay_ms(1000); - write_pixels(pixels_2, PIXEL_COUNT * 4); - _delay_ms(1000); - 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); - } + np_write_rgb(&pin, pixels, PIXEL_COUNT); return 0; } diff --git a/ws2812/np_common.c b/ws2812/np_common.c deleted file mode 100644 index e11649d..0000000 --- a/ws2812/np_common.c +++ /dev/null @@ -1,89 +0,0 @@ -#include -#include -#include -#include - -#include "ws2812.h" - -/* -void latch(io_pin_t *addr) { - if (addr->bit >= 8) return; - *(addr->port) &= ~(1<<0); - _delay_us(50); -} -*/ - -#define T0_HIGH 4 -#define T1_HIGH 7 -#define T_FRAME 11 - -#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" \ - -/* -#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" - */ - - -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) - ); - - // __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) { - 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/np_rgb.c b/ws2812/np_rgb.c deleted file mode 100644 index 23e4658..0000000 --- a/ws2812/np_rgb.c +++ /dev/null @@ -1,5 +0,0 @@ -#include "np_common.c" - -void np_write_rgb(io_pin_t *addr, rgb_t *values, uint8_t length) { - write_pixels(addr, values, length * 3); -} diff --git a/ws2812/ws2812.c b/ws2812/ws2812.c new file mode 100644 index 0000000..07a4ffc --- /dev/null +++ b/ws2812/ws2812.c @@ -0,0 +1,108 @@ +#include +# 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(); +} + diff --git a/ws2812/ws2812.h b/ws2812/ws2812.h index 35cba1b..c99ecbc 100644 --- a/ws2812/ws2812.h +++ b/ws2812/ws2812.h @@ -2,7 +2,7 @@ #define __neopixels_h__ #include -#include +#include typedef struct RGB_s { uint8_t r; @@ -18,8 +18,7 @@ typedef struct RGBW_s { } rgbw_t; // 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_rgb(dio_t *, const rgb_t *, uint8_t); // 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); // void np_write_grbw(io_pin_t *addr, rgbw_t *values, uint8_t length);