Tried cleaning things up and putting out some new assembly

didn't work
ws2812
Savanni D'Gerinel 2023-06-24 23:48:09 -04:00
parent 5c28706133
commit 136a1da5b3
7 changed files with 162 additions and 260 deletions

View File

@ -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"; };

View File

@ -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) \
)

View File

@ -1,8 +1,9 @@
#include <avr/io.h>
#include <util/delay.h>
#include <dio.h>
#include "ws2812.h"
#include "np_common.c"
/*
#include <simavr/avr/avr_mcu_section.h>
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;
}

View File

@ -1,89 +0,0 @@
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <stddef.h>
#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();
}

View File

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

108
ws2812/ws2812.c Normal file
View File

@ -0,0 +1,108 @@
#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();
}

View File

@ -2,7 +2,7 @@
#define __neopixels_h__
#include <avr/io.h>
#include <base.h>
#include <dio.h>
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);