Save the ws2812 current progress
This commit is contained in:
parent
a16cb1d54e
commit
ade8034b0b
|
@ -297,9 +297,8 @@
|
||||||
];
|
];
|
||||||
in
|
in
|
||||||
pkgs.mkShell {
|
pkgs.mkShell {
|
||||||
name = "avr-shell";
|
name = "Wearables-shell";
|
||||||
buildInputs = avr;
|
buildInputs = avr ++ [ pkgs.gnumake ];
|
||||||
|
|
||||||
GCC = pkgs.pkgsCross.avr.buildPackages.gcc;
|
GCC = pkgs.pkgsCross.avr.buildPackages.gcc;
|
||||||
SIMAVR = pkgs.pkgsCross.avr.buildPackages.simavr;
|
SIMAVR = pkgs.pkgsCross.avr.buildPackages.simavr;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -3,29 +3,22 @@
|
||||||
#include "ws2812.h"
|
#include "ws2812.h"
|
||||||
#include "np_common.c"
|
#include "np_common.c"
|
||||||
|
|
||||||
/*
|
|
||||||
#include <simavr/avr/avr_mcu_section.h>
|
#include <simavr/avr/avr_mcu_section.h>
|
||||||
AVR_MCU(F_CPU, "attiny85");
|
AVR_MCU(F_CPU, "attiny85");
|
||||||
|
|
||||||
const struct avr_mmcu_vcd_trace_t _mytrace[] _MMCU_ = {
|
const struct avr_mmcu_vcd_trace_t _mytrace[] _MMCU_ = {
|
||||||
{ AVR_MCU_VCD_SYMBOL("GTCCR"), .what = (void*)>CCR, },
|
{ AVR_MCU_VCD_SYMBOL("DDRB"), .what = (void*)&DDRB, },
|
||||||
// { 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("PORTB"), .what = (void*)&PORTB, },
|
{ 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
|
#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] =
|
const uint8_t pixels_1[PIXEL_COUNT * 4] =
|
||||||
{ 0, 0, 0, 0,
|
{ 0, 0, 0, 0,
|
||||||
32, 0, 0, 0,
|
32, 0, 0, 0,
|
||||||
|
@ -68,19 +61,47 @@ void blink(void) {
|
||||||
PORTB &= ~(_BV(2));
|
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;
|
PORTB = 0;
|
||||||
DDRB = _BV(0) | _BV(1) | _BV(2);
|
DDRB = _BV(0) | _BV(1) | _BV(2) | _BV(3);
|
||||||
_delay_ms(50);
|
_delay_ms(50);
|
||||||
|
|
||||||
blink();
|
blink();
|
||||||
np_initialize();
|
|
||||||
sei();
|
|
||||||
|
|
||||||
_delay_ms(500);
|
_delay_ms(500);
|
||||||
|
|
||||||
|
/*
|
||||||
while (1) {
|
while (1) {
|
||||||
blink();
|
blink();
|
||||||
write_pixels(pixels_1, PIXEL_COUNT * 4);
|
write_pixels(pixels_1, PIXEL_COUNT * 4);
|
||||||
|
@ -90,5 +111,61 @@ int main (void) {
|
||||||
write_pixels(pixels_3, PIXEL_COUNT * 4);
|
write_pixels(pixels_3, PIXEL_COUNT * 4);
|
||||||
_delay_ms(1000);
|
_delay_ms(1000);
|
||||||
write_pixels(pixels_4, PIXEL_COUNT * 4);
|
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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,67 +17,73 @@ void latch(io_pin_t *addr) {
|
||||||
#define T1_HIGH 7
|
#define T1_HIGH 7
|
||||||
#define T_FRAME 11
|
#define T_FRAME 11
|
||||||
|
|
||||||
volatile uint8_t bit = 0;
|
#define write_bit(label, bit) \
|
||||||
volatile uint8_t val = 0;
|
"out %[port], %[hi]" "\n\t" \
|
||||||
volatile uint32_t idx = 0;
|
"nop" "\n\t" \
|
||||||
volatile uint8_t sub_idx = 0;
|
"sbrc %[byte], " #bit "\n\t" \
|
||||||
volatile const uint8_t *data = NULL;
|
"rjmp .+0" "\n\t" \
|
||||||
volatile uint32_t cnt = 0;
|
"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
|
#define write_bit(label, bit) \
|
||||||
if (idx >= cnt) {
|
"bst %[byte], " #bit "\n\t" \
|
||||||
// Turn off the clock
|
"out %[port], %[hi]" "\n\t" \
|
||||||
TCCR0B &= ~(_BV(CS00));
|
"nop" "\n\t" \
|
||||||
// Disconnect OC0A and OC0B
|
"brtc " label "\n\t" \
|
||||||
TCCR0A &= ~(_BV(COM0A1) | _BV(COM0A0) | _BV(COM0B1) | _BV(COM0B0));
|
"rjmp .+0" "\n\t" \
|
||||||
// Write a 0 to the PORTB[1] / OC0B
|
label ": " "out %[port], %[low]" "\n\t" \
|
||||||
PORTB &= ~(_BV(1));
|
"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.
|
inline void write_byte(volatile uint8_t *port, uint8_t hi, uint8_t low, uint8_t byte) {
|
||||||
// Otherwise, assert for T0_HIGH ticks.
|
__asm__ __volatile__ (
|
||||||
OCR0B = bit ? T1_HIGH : T0_HIGH;
|
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
|
// __asm__ __volatile__ (
|
||||||
|
/*
|
||||||
// If we're at the last bit for the curret byte, let's move on to the next byte
|
"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
|
||||||
if (sub_idx == 8) {
|
"lsl %[byte]" "\n\t" // output data left, saving the msb in SREG (1 cycle)
|
||||||
sub_idx = 0;
|
"bst sreg, 0" "\n\t" // Save hte carry flag to the transfer bit
|
||||||
idx++;
|
"L_%=: " "out %[port], %[hi]" "\n\t" // enable the port
|
||||||
val = data[idx];
|
"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"
|
||||||
// Load the bit from the current value
|
"nop" "\n\t"
|
||||||
bit = val & _BV(sub_idx);
|
"I_%=: " "out %[port], %[low]" "\n\t" // now clear the pin
|
||||||
|
// I now have five ticks before I can re-enable the pin
|
||||||
// And then increment to the next bit for the next iteration
|
"lsl %[byte]" "\n\t" // Shift out the next bit
|
||||||
sub_idx++;
|
"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) {
|
void write_pixels(const uint8_t *pixels, uint8_t length) {
|
||||||
data = pixels;
|
uint8_t hi = PORTB | (1 << 3);
|
||||||
cnt = length;
|
uint8_t low = PORTB & ~(1 << 3);
|
||||||
|
cli();
|
||||||
// Set OC0B to Fast PWM, Clear on Match, Set on Bottom mode
|
for (int idx = 0; idx < length; idx++) {
|
||||||
TCCR0A |= _BV(COM0B1);
|
write_byte(&PORTB, hi, low, pixels[idx]);
|
||||||
|
}
|
||||||
// Enable the clock
|
_delay_us(100);
|
||||||
TCCR0B |= _BV(CS00);
|
sei();
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,8 +17,8 @@ typedef struct RGBW_s {
|
||||||
uint8_t w;
|
uint8_t w;
|
||||||
} rgbw_t;
|
} rgbw_t;
|
||||||
|
|
||||||
void np_initialize();
|
// void np_initialize();
|
||||||
void np_write_rgb(io_pin_t *addr, rgb_t *values, uint8_t length);
|
// 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 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_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_rgbw(io_pin_t *addr, rgbw_t *values, uint8_t length);
|
||||||
|
|
Loading…
Reference in New Issue