commit c1b0c31e0ccb9009b946c55aa825e71b776d2fbc Author: DarkSpir Date: Thu Feb 4 15:14:26 2021 +0100 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e494714 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.elf +*.o diff --git a/attiny10-lantern.cpp b/attiny10-lantern.cpp new file mode 100644 index 0000000..cc91f80 --- /dev/null +++ b/attiny10-lantern.cpp @@ -0,0 +1,233 @@ +// Features + +// #define FEAT_UNDERVOLTSLEEP +// Activates VLM Feature of Tiny10 (Voltage Level Monitoring) and sets it to the lowest value Vcc=2.5V +// In 3V supply scenarios (2 AG13/LR44 button cells in serial) this makes no sense because Vcc almost immediately drops below 2.5V + +#define FEAT_STANDBY +// Activates PB1 and PB2. PB2 is the standby button, pull it to ground to activate deep sleep or wake up. Its pullup resistor is enabled. +// PB1 is set to high when awake and low when asleep. Can be used to disable external hardware during sleep mode + +// Color values +#define R_STATIC 110 //80 +#define G_HIGH 55 //40 +#define B_STATIC 0 // 0 +#define G_BURN 46 //34 +#define G_FLICKER 43 //31 +#define G_FLUTTER 35 //49 //25 + +// Timings +#define T_ON 5 +#define T_BURN 4 +#define T_FLICKER 3 +#define T_FLUTTER 2 + +#ifndef F_CPU + #define F_CPU 8000000UL +#endif + +#include +#include +#include + +extern "C" { + #include "ws2812_config.h" + #include "light_ws2812.h" +} + +struct cRGB led[1]; + +volatile uint8_t timertick = 0; + +void delayms(uint16_t ms); + + +#ifdef FEAT_STANDBY + void buttonrelease() { + while ((PINB & (1< g_low; led[0].g--) { + ws2812_setleds(led,1); + delayms(gdelay); + } + for (led[0].g = g_low; led[0].g < g_high; led[0].g++) { + ws2812_setleds(led,1); + delayms(gdelay); + } + #ifdef FEAT_STANDBY + checksleep(); + #endif +} + +void on(uint8_t f) { + led[0].g = G_HIGH; + ws2812_setleds(led,1); + for (uint8_t t = f<<4; t > 0; t--) { // f*16 + delayms(62); + #ifdef FEAT_STANDBY + checksleep(); + #endif + } +} + +void burn(uint8_t f) { + for(uint8_t var = f<<4; var > 0; var--) { // f*16 + fire(G_BURN, G_HIGH, T_BURN); + } +} + +void flicker(uint8_t f) { + fire(G_BURN,G_HIGH,T_BURN); + for(uint8_t var = f<<4; var > 0; var--) { // f*16 + fire(G_FLICKER,G_HIGH,T_FLICKER); + } + fire(G_BURN,G_HIGH,T_BURN); + fire(G_BURN,G_HIGH,T_BURN); + fire(G_BURN,G_HIGH,T_BURN); +} + +void flutter(uint8_t f) { + fire(G_BURN,G_HIGH,T_BURN); + fire(G_FLICKER,G_HIGH,T_FLICKER); + for(uint8_t var = f<<4; var > 0; var--) { // f*16 + fire(G_FLUTTER,G_HIGH,T_FLUTTER); + } + fire(G_FLICKER,G_HIGH,T_FLICKER); + fire(G_BURN,G_HIGH,T_BURN); + fire(G_BURN,G_HIGH,T_BURN); +} + +void delayms(uint16_t ms) { + timertick = 0; + cli(); + PRR &= ~(1< +#include +#include + +// Setleds for standard RGB +void inline ws2812_setleds(struct cRGB *ledarray, uint16_t leds) +{ + ws2812_setleds_pin(ledarray,leds, _BV(ws2812_pin)); +} + +void inline ws2812_setleds_pin(struct cRGB *ledarray, uint16_t leds, uint8_t pinmask) +{ + ws2812_sendarray_mask((uint8_t*)ledarray,leds+leds+leds,pinmask); + _delay_us(ws2812_resettime); +} + +// Setleds for SK6812RGBW +void inline ws2812_setleds_rgbw(struct cRGBW *ledarray, uint16_t leds) +{ + ws2812_sendarray_mask((uint8_t*)ledarray,leds<<2,_BV(ws2812_pin)); + _delay_us(ws2812_resettime); +} + +void ws2812_sendarray(uint8_t *data,uint16_t datlen) +{ + ws2812_sendarray_mask(data,datlen,_BV(ws2812_pin)); +} + +/* + This routine writes an array of bytes with RGB values to the Dataout pin + using the fast 800kHz clockless WS2811/2812 protocol. +*/ + +// Timing in ns +#define w_zeropulse 350 +#define w_onepulse 900 +#define w_totalperiod 1250 + +// Fixed cycles used by the inner loop +#define w_fixedlow 2 +#define w_fixedhigh 4 +#define w_fixedtotal 8 + +// Insert NOPs to match the timing, if possible +#define w_zerocycles (((F_CPU/1000)*w_zeropulse )/1000000) +#define w_onecycles (((F_CPU/1000)*w_onepulse +500000)/1000000) +#define w_totalcycles (((F_CPU/1000)*w_totalperiod +500000)/1000000) + +// w1 - nops between rising edge and falling edge - low +#define w1 (w_zerocycles-w_fixedlow) +// w2 nops between fe low and fe high +#define w2 (w_onecycles-w_fixedhigh-w1) +// w3 nops to complete loop +#define w3 (w_totalcycles-w_fixedtotal-w1-w2) + +#if w1>0 + #define w1_nops w1 +#else + #define w1_nops 0 +#endif + +// The only critical timing parameter is the minimum pulse length of the "0" +// Warn or throw error if this timing can not be met with current F_CPU settings. +#define w_lowtime ((w1_nops+w_fixedlow)*1000000)/(F_CPU/1000) +#if w_lowtime>550 + #error "Light_ws2812: Sorry, the clock speed is too low. Did you set F_CPU correctly?" +#elif w_lowtime>450 + #warning "Light_ws2812: The timing is critical and may only work on WS2812B, not on WS2812(S)." + #warning "Please consider a higher clockspeed, if possible" +#endif + +#if w2>0 +#define w2_nops w2 +#else +#define w2_nops 0 +#endif + +#if w3>0 +#define w3_nops w3 +#else +#define w3_nops 0 +#endif + +#define w_nop1 "nop \n\t" +#define w_nop2 "rjmp .+0 \n\t" +#define w_nop4 w_nop2 w_nop2 +#define w_nop8 w_nop4 w_nop4 +#define w_nop16 w_nop8 w_nop8 + +void inline ws2812_sendarray_mask(uint8_t *data,uint16_t datlen,uint8_t maskhi) +{ + uint8_t curbyte,ctr,masklo; + uint8_t sreg_prev; + + ws2812_DDRREG |= maskhi; // Enable output + + masklo =~maskhi&ws2812_PORTREG; + maskhi |= ws2812_PORTREG; + + sreg_prev=SREG; + cli(); + + while (datlen--) { + curbyte=*data++; + + asm volatile( + " ldi %0,8 \n\t" + "loop%=: \n\t" + " out %2,%3 \n\t" // '1' [01] '0' [01] - re +#if (w1_nops&1) +w_nop1 +#endif +#if (w1_nops&2) +w_nop2 +#endif +#if (w1_nops&4) +w_nop4 +#endif +#if (w1_nops&8) +w_nop8 +#endif +#if (w1_nops&16) +w_nop16 +#endif + " sbrs %1,7 \n\t" // '1' [03] '0' [02] + " out %2,%4 \n\t" // '1' [--] '0' [03] - fe-low + " lsl %1 \n\t" // '1' [04] '0' [04] +#if (w2_nops&1) + w_nop1 +#endif +#if (w2_nops&2) + w_nop2 +#endif +#if (w2_nops&4) + w_nop4 +#endif +#if (w2_nops&8) + w_nop8 +#endif +#if (w2_nops&16) + w_nop16 +#endif + " out %2,%4 \n\t" // '1' [+1] '0' [+1] - fe-high +#if (w3_nops&1) +w_nop1 +#endif +#if (w3_nops&2) +w_nop2 +#endif +#if (w3_nops&4) +w_nop4 +#endif +#if (w3_nops&8) +w_nop8 +#endif +#if (w3_nops&16) +w_nop16 +#endif + + " dec %0 \n\t" // '1' [+2] '0' [+2] + " brne loop%=\n\t" // '1' [+3] '0' [+4] + : "=&d" (ctr) + : "r" (curbyte), "I" (_SFR_IO_ADDR(ws2812_PORTREG)), "r" (maskhi), "r" (masklo) + ); + } + + SREG=sreg_prev; +} diff --git a/light_ws2812.h b/light_ws2812.h new file mode 100644 index 0000000..950e08a --- /dev/null +++ b/light_ws2812.h @@ -0,0 +1,97 @@ +/* + * light weight WS2812 lib include + * + * Version 2.3 - Nev 29th 2015 + * Author: Tim (cpldcpu@gmail.com) + * + * Please do not change this file! All configuration is handled in "ws2812_config.h" + * + * License: GNU GPL v2+ (see License.txt) + + + */ + +#ifndef LIGHT_WS2812_H_ +#define LIGHT_WS2812_H_ + +#include +#include + +/////////////////////////////////////////////////////////////////////// +// Define Reset time in µs. +// +// This is the time the library spends waiting after writing the data. +// +// WS2813 needs 300 µs reset time +// WS2812 and clones only need 50 µs +// +/////////////////////////////////////////////////////////////////////// +#if !defined(ws2812_resettime) +#define ws2812_resettime 300 +#endif + +/////////////////////////////////////////////////////////////////////// +// Define I/O pin +/////////////////////////////////////////////////////////////////////// +#if !defined(ws2812_port) +#define ws2812_port B // Data port +#endif + +#if !defined(ws2812_pin) +#define ws2812_pin 0 // Data out pin +#endif + +/* + * Structure of the LED array + * + * cRGB: RGB for WS2812S/B/C/D, SK6812, SK6812Mini, SK6812WWA, APA104, APA106 + * cRGBW: RGBW for SK6812RGBW + */ + +struct cRGB { uint8_t r; uint8_t g; uint8_t b; }; +struct cRGBW { uint8_t g; uint8_t r; uint8_t b; uint8_t w;}; + + + +/* User Interface + * + * Input: + * ledarray: An array of GRB data describing the LED colors + * number_of_leds: The number of LEDs to write + * pinmask (optional): Bitmask describing the output bin. e.g. _BV(PB0) + * + * The functions will perform the following actions: + * - Set the data-out pin as output + * - Send out the LED data + * - Wait 50µs to reset the LEDs + */ + +void ws2812_setleds (struct cRGB *ledarray, uint16_t number_of_leds); +void ws2812_setleds_pin (struct cRGB *ledarray, uint16_t number_of_leds,uint8_t pinmask); +void ws2812_setleds_rgbw(struct cRGBW *ledarray, uint16_t number_of_leds); + +/* + * Old interface / Internal functions + * + * The functions take a byte-array and send to the data output as WS2812 bitstream. + * The length is the number of bytes to send - three per LED. + */ + +void ws2812_sendarray (uint8_t *array,uint16_t length); +void ws2812_sendarray_mask(uint8_t *array,uint16_t length, uint8_t pinmask); + + +/* + * Internal defines + */ +#if !defined(CONCAT) +#define CONCAT(a, b) a ## b +#endif + +#if !defined(CONCAT_EXP) +#define CONCAT_EXP(a, b) CONCAT(a, b) +#endif + +#define ws2812_PORTREG CONCAT_EXP(PORT,ws2812_port) +#define ws2812_DDRREG CONCAT_EXP(DDR,ws2812_port) + +#endif /* LIGHT_WS2812_H_ */ diff --git a/makefile b/makefile new file mode 100644 index 0000000..13a8e37 --- /dev/null +++ b/makefile @@ -0,0 +1,31 @@ +CC = avr-gcc +UC = attiny10 +COMPOPT = -mmcu=$(UC) -DF_CPU=8000000 -g -Os -flto -mtiny-stack -maccumulate-args -fno-inline-small-functions -mcall-prologues -fno-caller-saves -ffunction-sections +LINKOPT = -mmcu=$(UC) -flto -mrelax -Wl,--gc-sections +OBJ = attiny10-lantern.o light_ws2812.o + +.PHONY: clean upload + +all: attiny10-lantern.elf + +attiny10-lantern.elf: $(OBJ) + $(CC) $(LINKOPT) -o attiny10-lantern.elf $(OBJ) + avr-size --mcu=attiny10 -C attiny10-lantern.elf + +attiny10-lantern.o: attiny10-lantern.cpp + $(CC) $(COMPOPT) -c attiny10-lantern.cpp + +light_ws2812.o: light_ws2812.c + $(CC) $(COMPOPT) -c light_ws2812.c + +clean: + rm -f *.o *.elf + +install: attiny10-lantern.elf + avrdude -C /etc/avrdude.conf -c usbasp -p t10 -U flash:w:attiny10-lantern.elf + avr-size --mcu=attiny10 -C attiny10-lantern.elf + +# Binary Size: 990 byte +# -flto: 844 byte +# -mtiny-stack: 842 byte +# Code adv: 818 byte diff --git a/ws2812_config.h b/ws2812_config.h new file mode 100644 index 0000000..43c08d4 --- /dev/null +++ b/ws2812_config.h @@ -0,0 +1,34 @@ +/* + * light_ws2812_config.h + * + * v2.4 - Nov 27, 2016 + * + * User Configuration file for the light_ws2812_lib + * + */ + + +#ifndef WS2812_CONFIG_H_ +#define WS2812_CONFIG_H_ + +/////////////////////////////////////////////////////////////////////// +// Define Reset time in µs. +// +// This is the time the library spends waiting after writing the data. +// +// WS2813 needs 300 µs reset time +// WS2812 and clones only need 50 µs +// +/////////////////////////////////////////////////////////////////////// + +#define ws2812_resettime 50 + +/////////////////////////////////////////////////////////////////////// +// Define I/O pin +/////////////////////////////////////////////////////////////////////// + + +#define ws2812_port B // Data port +#define ws2812_pin 2 // Data out pin + +#endif /* WS2812_CONFIG_H_ */