Tried cleaning things up and putting out some new assembly
didn't work
This commit is contained in:
parent
5c28706133
commit
136a1da5b3
22
flake.nix
22
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"; };
|
||||
|
|
|
@ -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) \
|
||||
)
|
||||
|
|
163
ws2812/main.c
163
ws2812/main.c
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue