Compare commits
5 Commits
Author | SHA1 | Date |
---|---|---|
Savanni D'Gerinel | 136a1da5b3 | |
Savanni D'Gerinel | 5c28706133 | |
Savanni D'Gerinel | ade8034b0b | |
Savanni D'Gerinel | a16cb1d54e | |
Savanni D'Gerinel | 6c9dbec322 |
27
flake.nix
27
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" =
|
devShell."x86_64-linux" =
|
||||||
let
|
let
|
||||||
pkgs = import nixpkgs { system = "x86_64-linux"; };
|
pkgs = import nixpkgs { system = "x86_64-linux"; };
|
||||||
|
@ -297,9 +319,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;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1 +1,2 @@
|
||||||
avrdude -c usbtiny -p attiny85 -U flash:w:$1:i; sleep 5; avrdude -c usbtiny -p attiny85 -D -U flash:w:$1:i
|
avrdude -c usbtiny -p attiny85 -U flash:w:$1:i; sleep 5; avrdude -c usbtiny -p attiny85 -D -U flash:w:$1:i
|
||||||
|
# avrdude -c usbtiny -p attiny85 -D -U flash:w:$1:i
|
||||||
|
|
|
@ -0,0 +1,74 @@
|
||||||
|
#include <avr/io.h>
|
||||||
|
#include <util/delay.h>
|
||||||
|
#include <avr/interrupt.h>
|
||||||
|
|
||||||
|
#include <base.h>
|
||||||
|
|
||||||
|
#define FIVE_SECOND_TICK (8000000 * 10) / 256
|
||||||
|
|
||||||
|
volatile uint32_t iteration = 0;
|
||||||
|
|
||||||
|
void set_up_pwm(void);
|
||||||
|
void start_pwm(void);
|
||||||
|
|
||||||
|
ISR(TIMER0_OVF_vect) {
|
||||||
|
if (iteration >= FIVE_SECOND_TICK) {
|
||||||
|
GTCCR |= _BV(TSM);
|
||||||
|
/*
|
||||||
|
PORTB &= ~(_BV(2));
|
||||||
|
PORTB |= _BV(1);
|
||||||
|
*/
|
||||||
|
PORTB = _BV(1);
|
||||||
|
} else {
|
||||||
|
iteration += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_up_pwm(void) {
|
||||||
|
// Stop the clock
|
||||||
|
GTCCR = _BV(TSM) | _BV(PSR0);
|
||||||
|
|
||||||
|
TCCR0B = _BV(CS00);
|
||||||
|
|
||||||
|
// Set normal mode
|
||||||
|
TCCR0A = _BV(COM0A1) | _BV(WGM01) | _BV(WGM00);
|
||||||
|
|
||||||
|
// Enable the overflow interrupt
|
||||||
|
TIMSK = _BV(TOIE0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void start_pwm(void) {
|
||||||
|
GTCCR &= ~(_BV(TSM));
|
||||||
|
}
|
||||||
|
|
||||||
|
int main (void) {
|
||||||
|
int8_t step = 1;
|
||||||
|
uint8_t target = 0;
|
||||||
|
|
||||||
|
set_up_pwm();
|
||||||
|
OCR0A = 0;
|
||||||
|
|
||||||
|
PORTB = 0;
|
||||||
|
DDRB = _BV(2) | _BV(1) | _BV(0);
|
||||||
|
_delay_ms(50);
|
||||||
|
PORTB |= _BV(2);
|
||||||
|
|
||||||
|
sei();
|
||||||
|
start_pwm();
|
||||||
|
|
||||||
|
while (iteration != FIVE_SECOND_TICK) {
|
||||||
|
OCR0A = target;
|
||||||
|
target += step;
|
||||||
|
|
||||||
|
if (target == 255) {
|
||||||
|
step = -1;
|
||||||
|
} else if (target == 0) {
|
||||||
|
step = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
_delay_ms(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (1) {}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
// I have reduced noops at the end of each of these to take into account that there are several additional clock ticks of setup, after. However, I'm not totally sure that I get things right, seeing that there are four possible sequences, and I'm not really accounting for the timing of all four of them.
|
||||||
|
#define write_zero(port, bit) \
|
||||||
|
__asm__ __volatile__ ( \
|
||||||
|
"sbi %0, %1" "\n\t" \
|
||||||
|
"nop" "\n\t" \
|
||||||
|
"cbi %0, %1" "\n\t" \
|
||||||
|
"nop" "\n\t" \
|
||||||
|
: /* no outputs */ \
|
||||||
|
: "I" (_SFR_IO_ADDR(port)), \
|
||||||
|
"I" (bit) \
|
||||||
|
)
|
||||||
|
|
||||||
|
#define write_one(port, bit) \
|
||||||
|
__asm__ __volatile__ ( \
|
||||||
|
"sbi %0, %1" "\n\t" \
|
||||||
|
"nop" "\n\t" \
|
||||||
|
"nop" "\n\t" \
|
||||||
|
"nop" "\n\t" \
|
||||||
|
"nop" "\n\t" \
|
||||||
|
"nop" "\n\t" \
|
||||||
|
"cbi %0, %1" "\n\t" \
|
||||||
|
: /* no outputs */ \
|
||||||
|
: "I" (_SFR_IO_ADDR(port)), \
|
||||||
|
"I" (bit) \
|
||||||
|
)
|
||||||
|
|
||||||
|
#define write_byte(port, bit, byte) \
|
||||||
|
__asm__ __volatile__ ( \
|
||||||
|
; 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) \
|
||||||
|
)
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
#include <avr/io.h>
|
||||||
|
#include <util/delay.h>
|
||||||
|
#include <dio.h>
|
||||||
|
#include "ws2812.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
#include <simavr/avr/avr_mcu_section.h>
|
||||||
|
AVR_MCU(F_CPU, "attiny85");
|
||||||
|
|
||||||
|
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 1
|
||||||
|
const rgb_t pixels[PIXEL_COUNT] = {
|
||||||
|
(rgb_t){ .r = 255, .g = 0, .b = 255, },
|
||||||
|
};
|
||||||
|
|
||||||
|
int main (void) {
|
||||||
|
dio_t pin = (dio_t){ .ddr = &DDRB, .port = &PORTB, .pin = &PINB, .addr = 2 };
|
||||||
|
dio_set_direction(&pin, LINE_OUT);
|
||||||
|
|
||||||
|
np_write_rgb(&pin, pixels, PIXEL_COUNT);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
#ifndef __neopixels_h__
|
||||||
|
#define __neopixels_h__
|
||||||
|
|
||||||
|
#include <avr/io.h>
|
||||||
|
#include <dio.h>
|
||||||
|
|
||||||
|
typedef struct RGB_s {
|
||||||
|
uint8_t r;
|
||||||
|
uint8_t g;
|
||||||
|
uint8_t b;
|
||||||
|
} rgb_t;
|
||||||
|
|
||||||
|
typedef struct RGBW_s {
|
||||||
|
uint8_t r;
|
||||||
|
uint8_t g;
|
||||||
|
uint8_t b;
|
||||||
|
uint8_t w;
|
||||||
|
} rgbw_t;
|
||||||
|
|
||||||
|
// void np_initialize();
|
||||||
|
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);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue