master
Ondřej Hruška 9 years ago
parent e226999fb8
commit fd5b0685e9
  1. 0
      projects/rgb_anim_rainbow/Makefile
  2. 0
      projects/rgb_anim_rainbow/lib/arduino_pins.h
  3. 0
      projects/rgb_anim_rainbow/lib/calc.h
  4. 0
      projects/rgb_anim_rainbow/lib/colors.h
  5. 0
      projects/rgb_anim_rainbow/lib/meta.h
  6. 0
      projects/rgb_anim_rainbow/lib/nsdelay.h
  7. 0
      projects/rgb_anim_rainbow/lib/pins.h
  8. 0
      projects/rgb_anim_rainbow/lib/ws2812.h
  9. 0
      projects/rgb_anim_rainbow/main.c
  10. 169
      projects/rgb_random_hsl/Makefile
  11. 3
      projects/rgb_random_hsl/README.md
  12. 10
      projects/rgb_random_hsl/lib/README.md
  13. 46
      projects/rgb_random_hsl/lib/adc.c
  14. 19
      projects/rgb_random_hsl/lib/adc.h
  15. 0
      projects/rgb_random_hsl/lib/arduino_pins.h
  16. 0
      projects/rgb_random_hsl/lib/calc.h
  17. 84
      projects/rgb_random_hsl/lib/colors.h
  18. 45
      projects/rgb_random_hsl/lib/debounce.c
  19. 63
      projects/rgb_random_hsl/lib/debounce.h
  20. 76
      projects/rgb_random_hsl/lib/hsl.c
  21. 22
      projects/rgb_random_hsl/lib/hsl.h
  22. 284
      projects/rgb_random_hsl/lib/lcd.c
  23. 130
      projects/rgb_random_hsl/lib/lcd.h
  24. 13
      projects/rgb_random_hsl/lib/linear_fade.h
  25. 0
      projects/rgb_random_hsl/lib/loops.h
  26. 0
      projects/rgb_random_hsl/lib/meta.h
  27. 0
      projects/rgb_random_hsl/lib/nsdelay.h
  28. 0
      projects/rgb_random_hsl/lib/pins.h
  29. 0
      projects/rgb_random_hsl/lib/ws_rgb.h
  30. 66
      projects/rgb_random_hsl/main.c
  31. 0
      projects/rgb_random_wander/Makefile
  32. 0
      projects/rgb_random_wander/lib/README.md
  33. 0
      projects/rgb_random_wander/lib/adc.h
  34. 42
      projects/rgb_random_wander/lib/arduino_pins.h
  35. 89
      projects/rgb_random_wander/lib/calc.h
  36. 0
      projects/rgb_random_wander/lib/colors.h
  37. 0
      projects/rgb_random_wander/lib/debounce.h
  38. 0
      projects/rgb_random_wander/lib/lcd.h
  39. 22
      projects/rgb_random_wander/lib/loops.h
  40. 6
      projects/rgb_random_wander/lib/meta.h
  41. 21
      projects/rgb_random_wander/lib/nsdelay.h
  42. 107
      projects/rgb_random_wander/lib/pins.h
  43. 98
      projects/rgb_random_wander/lib/ws_rgb.h
  44. 0
      projects/rgb_random_wander/lib/yeolde.h
  45. 2
      projects/rgb_random_wander/main.c

@ -0,0 +1,169 @@
MCU = atmega328p
F_CPU = 16000000
LFUSE = 0xFF
HFUSE = 0xDE
EFUSE = 0x05
MAIN = main.c
## If you've split your program into multiple files,
## include the additional .c source (in same directory) here
## (and include the .h files in your foo.c)
LOCAL_SOURCE =
## Here you can link to one more directory (and multiple .c files)
# EXTRA_SOURCE_DIR = ../AVR-Programming-Library/
EXTRA_SOURCE_DIR = lib/
EXTRA_SOURCE_FILES = colors.c adc.c hsl.h
EXTRA_FLAGS = -DHSL_LINEAR=1
##########------------------------------------------------------##########
########## Programmer Defaults ##########
########## Set up once, then forget about it ##########
########## (Can override. See bottom of file.) ##########
##########------------------------------------------------------##########
#19200
PROGRAMMER_TYPE = arduino
PROGRAMMER_ARGS = -b 57600 -P /dev/ttyUSB0
##########------------------------------------------------------##########
########## Makefile Magic! ##########
########## Summary: ##########
########## We want a .hex file ##########
########## Compile source files into .elf ##########
########## Convert .elf file into .hex ##########
########## You shouldn't need to edit below. ##########
##########------------------------------------------------------##########
## Defined programs / locations
CC = avr-gcc
OBJCOPY = avr-objcopy
OBJDUMP = avr-objdump
AVRSIZE = avr-size
AVRDUDE = avrdude
## Compilation options, type man avr-gcc if you're curious.
CFLAGS = -std=gnu99 -mmcu=$(MCU) -DF_CPU=$(F_CPU)UL -I. -I$(EXTRA_SOURCE_DIR)
CFLAGS += -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums
CFLAGS += -Wall -Wno-main -Wno-strict-prototypes -Wno-comment
CFLAGS += -g2 -Wextra -pedantic -Wfatal-errors
CFLAGS += -ffunction-sections -fdata-sections -Wl,--gc-sections -Wl,--relax
CFLAGS += $(EXTRA_FLAGS)
CFLAGS_BUILD = $(CFLAGS) -Os
# CFLAGS += -lm
## CFLAGS += -Wl,-u,vfprintf -lprintf_flt -lm ## for floating-point printf
## CFLAGS += -Wl,-u,vfprintf -lprintf_min ## for smaller printf
## Lump target and extra source files together
TARGET = $(strip $(basename $(MAIN)))
SRC1 = $(TARGET).c
SRC = $(SRC1)
EXTRA_SOURCE = $(addprefix $(EXTRA_SOURCE_DIR), $(EXTRA_SOURCE_FILES))
SRC += $(EXTRA_SOURCE)
SRC += $(LOCAL_SOURCE)
## List of all header files
HEADERS = $(SRC:.c=.h)
## For every .c file, compile an .o object file
OBJ = $(SRC:.c=.o)
## Generic Makefile targets. (Only .hex file is necessary)
all: $(TARGET).hex size
pre: $(TARGET).pre
%.hex: %.elf
$(OBJCOPY) -R .eeprom -O ihex $< $@
%.elf: $(SRC)
$(CC) $(CFLAGS_BUILD) $(SRC) --output $@
%.pre: $(SRC1)
$(CC) $(CFLAGS) -E $(SRC1) --output $@
%.eeprom: %.elf
$(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O ihex $< $@
debug:
@echo
@echo "Source files:" $(SRC)
@echo "MCU, F_CPU, BAUD:" $(MCU), $(F_CPU), $(BAUD)
@echo
# Optionally create listing file from .elf
# This creates approximate assembly-language equivalent of your code.
# Useful for debugging time-sensitive bits,
# or making sure the compiler does what you want.
disassemble: $(TARGET).lst
dis: disassemble
lst: disassemble
eeprom: $(TARGET).eeprom
%.lst: %.elf
$(OBJDUMP) -S $< > $@
# Optionally show how big the resulting program is
size: $(TARGET).elf
$(AVRSIZE) -C --mcu=$(MCU) $(TARGET).elf
clean:
rm -f $(TARGET).elf $(TARGET).hex $(TARGET).obj \
$(TARGET).o $(TARGET).d $(TARGET).eep $(TARGET).lst \
$(TARGET).lss $(TARGET).sym $(TARGET).map $(TARGET)~ \
$(TARGET).eeprom
squeaky_clean:
rm -f *.elf *.hex *.obj *.o *.d *.eep *.lst *.lss *.sym *.map *~
##########------------------------------------------------------##########
########## Programmer-specific details ##########
########## Flashing code to AVR using avrdude ##########
##########------------------------------------------------------##########
flash: $(TARGET).hex
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U flash:w:$<
flash_eeprom: $(TARGET).eeprom
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U eeprom:w:$<
terminal:
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nt
flash_arduino: PROGRAMMER_TYPE = arduino
flash_arduino: PROGRAMMER_ARGS =
flash_arduino: flash
flash_dragon_isp: PROGRAMMER_TYPE = dragon_isp
flash_dragon_isp: PROGRAMMER_ARGS =
flash_dragon_isp: flash
##########------------------------------------------------------##########
########## Fuse settings and suitable defaults ##########
##########------------------------------------------------------##########
## Generic
FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m
fuses:
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) \
$(PROGRAMMER_ARGS) $(FUSE_STRING)
show_fuses:
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nv
## Called with no extra definitions, sets to defaults
set_default_fuses: FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m
set_default_fuses: fuses

@ -0,0 +1,3 @@
Randomly turns on and the fades out pixels
Uses HSL for picking the color.

@ -0,0 +1,10 @@
AVR utils library
=================
This is my ever-evolving library (not only) for AVR programming.
When I'm done with a project, I copy the current library to the project, so it doesn't break when I do further improvements.
Each library file contains a large comment block explaining it's function.
You may need to add "c" files to your makefile for some of the library files.

@ -0,0 +1,46 @@
#include <avr/io.h>
#include <stdbool.h>
#include "calc.h"
#include "adc.h"
/** Initialize the ADC */
void adc_init()
{
ADCSRA |= _BV(ADPS2) | _BV(ADPS1) | _BV(ADPS0); // 128 prescaler -> 125 kHz
ADMUX |= _BV(REFS0); // Voltage reference
sbi(ADCSRA, ADEN); // Enable ADC
}
/** Disable AD */
void adc_disable()
{
cbi(ADCSRA, ADEN);
}
/** Sample analog pin with 8-bit precision */
uint8_t adc_read_byte(uint8_t channel)
{
write_low_nibble(ADMUX, channel); // Select channel to sample
sbi(ADMUX, ADLAR); // Align result to left
sbi(ADCSRA, ADSC); // Start conversion
while(bit_is_high(ADCSRA, ADSC)); // Wait for it...
return ADCH; // The upper 8 bits of ADC result
}
/** Sample analog pin with 10-bit precision */
uint16_t adc_read_word(uint8_t channel)
{
write_low_nibble(ADMUX, channel); // Select channel to sample
cbi(ADMUX, ADLAR); // Align result to right
sbi(ADCSRA, ADSC); // Start conversion
while(get_bit(ADCSRA, ADSC)); // Wait for it...
return ADCW; // The whole ADC word (10 bits)
}

@ -0,0 +1,19 @@
#pragma once
/*
Utilities for build-in A/D converter
*/
#include <avr/io.h>
/** Initialize the ADC */
void adc_init();
/** Disable AD (for power saving?) */
void adc_disable();
/** Sample analog pin with 8-bit precision */
uint8_t adc_read_byte(uint8_t channel);
/** Sample analog pin with 10-bit precision */
uint16_t adc_read_word(uint8_t channel);

@ -0,0 +1,84 @@
#pragma once
/*
Some useful utilities for RGB color manipulation
The XXXc macros don't use cast, so they can be used in array initializers.
xrgb ... 3-byte true-color RGB (8 bits per component)
rgbXX ... XX-bit color value, with equal nr of bits per component
XX_r (_g, _b) ... extract component from the color, and convert it to 0..255
*/
typedef struct {
uint8_t r;
uint8_t g;
uint8_t b;
} xrgb_t;
typedef uint32_t rgb24_t;
typedef uint16_t rgb16_t;
typedef uint16_t rgb12_t;
typedef uint8_t rgb6_t;
#define xrgb(rr, gg, bb) ((xrgb_t)xrgbc(rr, gg, bb))
// xrgb for constant array declarations
#define xrgbc(rr, gg, bb) { .r = ((uint8_t)(rr)), .g = ((uint8_t)(gg)), .b = ((uint8_t)(bb)) }
#define xrgb_r(c) ((uint8_t)(c.r))
#define xrgb_g(c) ((uint8_t)(c.g))
#define xrgb_b(c) ((uint8_t)(c.b))
#define xrgb_rgb24(c) ((((rgb24_t)c.r) << 16) | (((rgb24_t)c.g) << 8) | (((rgb24_t)c.b)))
#define xrgb_rgb15(c) (((((rgb15_t)c.r) & 0xF8) << 7) | ((((rgb15_t)c.g) & 0xF8) << 2) | ((((rgb15_t)c.b) & 0xF8) >> 3))
#define xrgb_rgb12(c) (((((rgb12_t)c.r) & 0xF0) << 4) | ((((rgb12_t)c.g) & 0xF0)) | ((((rgb12_t)c.b) & 0xF0) >> 4))
#define xrgb_rgb6(c) (((((rgb6_t)c.r) & 0xC0) >> 2) | ((((rgb6_t)c.g) & 0xC0) >> 4) | ((((rgb6_t)c.b) & 0xC0) >> 6))
#define rgb24c(r,g,b) (((((rgb24_t)r) & 0xFF) << 16) | ((((rgb24_t)g) & 0xFF) << 8) | (((rgb24_t)b) & 0xFF))
#define rgb24(r,g,b) ((rgb24_t) rgb24(r,g,b))
#define rgb24_r(c) ((((rgb24_t) (c)) >> 16) & 0xFF)
#define rgb24_g(c) ((((rgb24_t) (c)) >> 8) & 0xFF)
#define rgb24_b(c) ((((rgb24_t) (c)) >> 0) & 0xFF)
#define rgb24_xrgb(c) xrgb(rgb24_r(c), rgb24_g(c), rgb24_b(c))
#define rgb24_xrgbc(c) xrgbc(rgb24_r(c), rgb24_g(c), rgb24_b(c))
#define rgb15(r,g,b) ((rgb16_t) rgb15c(r,g,b))
#define rgb15c(r,g,b) (((r & 0x1F) << 10) | ((g & 0x1F) << 5) | (b & 0x1F))
#define rgb15_r(c) ((((rgb15_t) (c)) & 0x7C00) >> 7)
#define rgb15_g(c) ((((rgb15_t) (c)) & 0x3E0) >> 2)
#define rgb15_b(c) ((((rgb15_t) (c)) & 0x1F) << 3)
#define rgb15_xrgb(c) xrgb(rgb15_r(c), rgb15_g(c), rgb15_b(c))
#define rgb15_rgb24(c) rgb24(rgb15_r(c), rgb15_g(c), rgb15_b(c))
#define rgb15_rgb24c(c) rgb24c(rgb15_r(c), rgb15_g(c), rgb15_b(c))
#define rgb12(r,g,b) ((rgb12_t) rgb12c(r,g,b))
#define rgb12c(r,g,b) (((r & 0xF) << 8) | ((g & 0xF) << 4) | (b & 0xF))
#define rgb12_r(c) ((((rgb12_t) (c)) & 0xF00) >> 4)
#define rgb12_g(c) (((rgb12_t) (c)) & 0xF0)
#define rgb12_b(c) (((r(rgb12_t) (c)gb) & 0x0F) << 4)
#define rgb12_xrgb(c) xrgb(rgb12_r(c), rgb12_g(c), rgb12_b(c))
#define rgb12_xrgbc(c) xrgbc(rgb12_r(c), rgb12_g(c), rgb12_b(c))
#define rgb12_rgb24(c) rgb24(rgb12_r(c), rgb12_g(c), rgb12_b(c))
#define rgb12_rgb24c(c) rgb24c(rgb12_r(c), rgb12_g(c), rgb12_b(c))
#define rgb6(r,g,b) ((rgb6_t) rgb6c(r,g,b))
#define rgb6c(r,g,b) (((r & 3) << 4) | ((g & 3) << 2) | (b & 3))
#define rgb6_r(c) ((((rgb6_t) (c)) & 0x30) << 2)
#define rgb6_g(c) ((((rgb6_t) (c)) & 0xC) << 4)
#define rgb6_b(c) ((((rgb6_t) (c)) & 0x3) << 6)
#define rgb6_xrgb(c) xrgb(rgb6_r(c), rgb6_g(c), rgb6_b(c))
#define rgb6_xrgbc(c) xrgbc(rgb6_r(c), rgb6_g(c), rgb6_b(c))
#define rgb6_rgb24(c) rgb24(rgb6_r(c), rgb6_g(c), rgb6_b(c))
#define rgb6_rgb24c(c) rgb24c(rgb6_r(c), rgb6_g(c), rgb6_b(c))
#define add_xrgb(x, y) ((xrgb_t) { (((y).r > (255 - (x).r)) ? 255 : ((x).r + (y).r)), (((y).g > (255 - (x).g)) ? 255 : ((x).g + (y).g)), (((y).b > 255 - (x).b) ? 255 : ((x).b + (y).b)) })

@ -0,0 +1,45 @@
#include <avr/io.h>
#include <stdbool.h>
#include "debounce.h"
#include "calc.h"
#include "pins.h"
#include "debo_config.h"
/** Debounce data array */
uint8_t debo_next_slot = 0;
uint8_t debo_register(PORT_P reg, uint8_t bit, bool invert)
{
debo_slots[debo_next_slot] = (debo_slot_t){
.reg = reg,
.bit = bit | ((invert & 1) << 7) | (get_bit_p(reg, bit) << 6), // bit 7 = invert, bit 6 = state
.count = 0,
};
return debo_next_slot++;
}
/** Check debounced pins, should be called periodically. */
void debo_tick()
{
for (uint8_t i = 0; i < debo_next_slot; i++) {
// current pin value (right 3 bits, xored with inverse bit)
bool value = get_bit_p(debo_slots[i].reg, debo_slots[i].bit & 0x7);
if (value != get_bit(debo_slots[i].bit, 6)) {
// different pin state than last recorded state
if (debo_slots[i].count < DEBO_TICKS) {
debo_slots[i].count++;
} else {
// overflown -> latch value
set_bit(debo_slots[i].bit, 6, value); // set state bit
debo_slots[i].count = 0;
}
} else {
debo_slots[i].count = 0; // reset the counter
}
}
}

@ -0,0 +1,63 @@
#pragma once
/**
An implementation of button debouncer.
----
You must provide a config file debo_config.h (next to your main.c)
Example:
#pragma once
#define DEBO_CHANNELS 2
#define DDEBO_TICKS 5
----
A pin is registered like this:
#define BTN1 B,0
#define BTN2 B,1
debo_add(BTN0); // The function returns number assigned to the pin (0, 1, ...)
debo_add_rev(BTN1); // active low
debo_register(&PINB, PB2, 0); // direct access - register, pin & invert
Then periodically call the tick function (perhaps in a timer interrupt):
debo_tick();
To check if input is active, use
debo_get_pin(0); // state of input #0 (registered first)
debo_get_pin(1); // state of input #1 (registered second)
*/
#include <avr/io.h>
#include <stdbool.h>
#include "calc.h"
#include "pins.h"
#include "debo_config.h"
/* Internal deboucer entry */
typedef struct {
PORT_P reg; // pointer to IO register
uint8_t bit; // bits 6 and 7 of this hold "state" & "invert" flag
uint8_t count; // number of ticks this was in the new state
} debo_slot_t;
debo_slot_t debo_slots[DEBO_CHANNELS];
/** Add a pin for debouncing */
#define debo_add_rev(io) debo_register(&io2pin(io_pack(io)), io2n(io_pack(io)), 1)
#define debo_add(io) debo_register(&io2pin(io_pack(io)), io2n(io_pack(io)), 0)
/** Add a pin for debouncing (low level function) */
uint8_t debo_register(PORT_P pin_reg_pointer, uint8_t bit, bool invert);
/** Check debounced pins, should be called periodically. */
void debo_tick();
/** Get a value of debounced pin */
#define debo_get_pin(i) (get_bit(debo_slots[i].bit, 6) ^ get_bit(debo_slots[i].bit, 7))

@ -0,0 +1,76 @@
#include <stdlib.h>
#include <stdint.h>
#include "colors.h"
#include "hsl.h"
// based on: https://github.com/lewisd32/avr-hsl2rgb
xrgb_t hsl2xrgb(const hsl_t cc)
{
// 0 .. 256*3
const uint16_t hh = (uint16_t) cc.h * 3;
const uint8_t hue_mod = hh % 256;
uint8_t r_temp, g_temp, b_temp;
if (hh < 256) {
r_temp = hue_mod ^ 255;
g_temp = hue_mod;
b_temp = 0;
} else if (hh < 512) {
r_temp = 0;
g_temp = hue_mod ^ 255;
b_temp = hue_mod;
} else if (hh < 768) {
r_temp = hue_mod;
g_temp = 0;
b_temp = hue_mod ^ 255;
} else {
r_temp = 0;
g_temp = 0;
b_temp = 0;
}
const uint8_t inverse_sat = (cc.s ^ 255);
xrgb_t rgb;
uint8_t t8;
uint16_t t16;
#ifdef HSL_LINEAR
const uint8_t bri = FADE_128[cc.l>>1];
#else
const uint8_t bri = cc.l;
#endif
t8 = r_temp;
t16 = t8 * cc.s + t8;
t16 = t16 + t8;
t8 = t16 >> 8;
t8 = t8 + inverse_sat;
t16 = t8 * bri;
t16 = t16 + t8;
t8 = t16 >> 8;
rgb.r = t8;
t8 = g_temp;
t16 = t8 * cc.s;
t16 = t16 + t8;
t8 = t16 >> 8;
t8 = t8 + inverse_sat;
t16 = t8 * bri;
t16 = t16 + t8;
t8 = t16 >> 8;
rgb.g = t8;
t8 = b_temp;
t16 = t8 * cc.s;
t16 = t16 + t8;
t8 = t16 >> 8;
t8 = t8 + inverse_sat;
t16 = t8 * bri;
t16 = t16 + t8;
t8 = t16 >> 8;
rgb.b = t8;
return rgb;
}

@ -0,0 +1,22 @@
#pragma once
/*
HSL support (addition to colors.h)
*/
#include "colors.h"
// Define HSL_LINEAR to get more linear brightness in hsl->rgb conversion
#ifdef HSL_LINEAR
# include "linear_fade.h"
#endif
// HSL data structure
typedef struct {
uint8_t h;
uint8_t s;
uint8_t l;
} hsl_t;
/* Convert HSL to XRGB */
xrgb_t hsl2xrgb(const hsl_t color);

@ -0,0 +1,284 @@
#include <stdbool.h>
#include <stdint.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <util/delay.h>
#include "calc.h"
#include "pins.h"
#include "nsdelay.h"
#include "lcd.h"
#include "lcd_config.h"
// Start address of rows
const uint8_t LCD_ROW_ADDR[] = {0x00, 0x40, 0x14, 0x54};
// Internal prototypes
void _lcd_mode_r();
void _lcd_mode_w();
void _lcd_clk();
void _lcd_wait_bf();
void _lcd_write_byte(uint8_t bb);
uint8_t _lcd_read_byte();
// Write utilities
#define _lcd_write_low(bb) _lcd_write_nibble((bb) & 0x0F)
#define _lcd_write_high(bb) _lcd_write_nibble(((bb) & 0xF0) >> 4)
#define _lcd_write_nibble(nib) do { \
write_pin(LCD_D7, get_bit((nib), 3)); \
write_pin(LCD_D6, get_bit((nib), 2)); \
write_pin(LCD_D5, get_bit((nib), 1)); \
write_pin(LCD_D4, get_bit((nib), 0)); \
} while(0)
// 0 W, 1 R
bool _lcd_mode;
/** Initialize the display */
void lcd_init()
{
// configure pins as output
as_output(LCD_E);
as_output(LCD_RW);
as_output(LCD_RS);
_lcd_mode = 1; // force data pins to output
_lcd_mode_w();
// Magic sequence to invoke Cthulhu (or enter 4-bit mode)
_delay_ms(16);
_lcd_write_nibble(0b0011);
_lcd_clk();
_delay_ms(5);
_lcd_clk();
_delay_ms(5);
_lcd_clk();
_delay_ms(5);
_lcd_write_nibble(0b0010);
_lcd_clk();
_delay_us(100);
// Configure the display
lcd_write_command(LCD_IFACE_4BIT_2LINE);
lcd_write_command(LCD_DISABLE);
lcd_write_command(LCD_CLEAR);
lcd_write_command(LCD_MODE_INC);
// mark as enabled
lcd_enable();
}
/** Send a pulse on the ENABLE line */
void _lcd_clk()
{
pin_up(LCD_E);
delay_ns(420);
pin_down(LCD_E);
}
/** Enter READ mode */
void _lcd_mode_r()
{
if (_lcd_mode == 1) return; // already in R mode
pin_up(LCD_RW);
as_input_pu(LCD_D7);
as_input_pu(LCD_D6);
as_input_pu(LCD_D5);
as_input_pu(LCD_D4);
_lcd_mode = 1;
}
/** Enter WRITE mode */
void _lcd_mode_w()
{
if (_lcd_mode == 0) return; // already in W mode
pin_down(LCD_RW);
as_output(LCD_D7);
as_output(LCD_D6);
as_output(LCD_D5);
as_output(LCD_D4);
_lcd_mode = 0;
}
/** Read a byte */
uint8_t _lcd_read_byte()
{
_lcd_mode_r();
uint8_t res = 0;
_lcd_clk();
res = (read_pin(LCD_D7) << 7) | (read_pin(LCD_D6) << 6) | (read_pin(LCD_D5) << 5) | (read_pin(LCD_D4) << 4);
_lcd_clk();
res |= (read_pin(LCD_D7) << 3) | (read_pin(LCD_D6) << 2) | (read_pin(LCD_D5) << 1) | (read_pin(LCD_D4) << 0);
return res;
}
/** Write an instruction byte */
void lcd_write_command(uint8_t bb)
{
_lcd_wait_bf();
pin_down(LCD_RS); // select instruction register
_lcd_write_byte(bb); // send instruction byte
}
/** Write a data byte */
void lcd_write_data(uint8_t bb)
{
_lcd_wait_bf();
pin_up(LCD_RS); // select data register
_lcd_write_byte(bb); // send data byte
}
/** Read BF & Address */
uint8_t lcd_read_bf_addr()
{
pin_down(LCD_RS);
return _lcd_read_byte();
}
/** Read CGRAM or DDRAM */
uint8_t lcd_read_ram()
{
pin_up(LCD_RS);
return _lcd_read_byte();
}
/** Write a byte using the 8-bit interface */
void _lcd_write_byte(uint8_t bb)
{
_lcd_mode_w(); // enter W mode
_lcd_write_high(bb);
_lcd_clk();
_lcd_write_low(bb);
_lcd_clk();
}
/** Wait until the device is ready */
void _lcd_wait_bf()
{
uint8_t d = 0;
while(d++ < 120 && lcd_read_bf_addr() & _BV(7))
_delay_us(1);
}
/** Send a string to LCD */
void lcd_str(char* str_p)
{
while (*str_p)
lcd_char(*str_p++);
}
/** Sedn a char to LCD */
void lcd_char(const char c)
{
lcd_write_data(c);
}
/** Set cursor position */
void lcd_xy(const uint8_t x, const uint8_t y)
{
lcd_set_addr(LCD_ROW_ADDR[y] + (x));
}
uint8_t _lcd_old_cursor = CURSOR_NONE;
bool _lcd_enabled = false;
/** Set LCD cursor. If not enabled, only remember it. */
void lcd_cursor(uint8_t type)
{
_lcd_old_cursor = (type & CURSOR_BOTH);
if (_lcd_enabled) lcd_write_command(LCD_CURSOR_NONE | _lcd_old_cursor);
}
/** Display display (preserving cursor) */
void lcd_disable()
{
lcd_write_command(LCD_DISABLE);
_lcd_enabled = false;
}
/** Enable display (restoring cursor) */
void lcd_enable()
{
_lcd_enabled = true;
lcd_cursor(_lcd_old_cursor);
}
/** Go home */
void lcd_home()
{
lcd_write_command(LCD_HOME);
}
/** Clear the screen */
void lcd_clear()
{
lcd_write_command(LCD_CLEAR);
}
/** Define a glyph */
void lcd_define_glyph(const uint8_t index, const uint8_t* array)
{
lcd_set_addr_cgram(index * 8);
for (uint8_t i = 0; i < 8; ++i) {
lcd_write_data(array[i]);
}
}
/** Define a glyph */
void lcd_define_glyph_pgm(const uint8_t index, const uint8_t* array)
{
lcd_set_addr_cgram(index * 8);
for (uint8_t i = 0; i < 8; ++i) {
lcd_write_data(pgm_read_byte(&array[i]));
}
}
/** Set address in CGRAM */
void lcd_set_addr_cgram(const uint8_t acg)
{
lcd_write_command(0b01000000 | ((acg) & 0b00111111));
}
/** Set address in DDRAM */
void lcd_set_addr(const uint8_t add)
{
lcd_write_command(0b10000000 | ((add) & 0b01111111));
}

@ -0,0 +1,130 @@
#pragma once
/*
HD44780 LCD display driver - 4-bit mode
LCD pins are configured using a file lcd_config.h, which you
have to add next to your main.c file.
Content can be something like this:
#pragma once
#include "lib/arduino_pins.h"
#define LCD_RS D10
#define LCD_RW D11
#define LCD_E D12
#define LCD_D4 D13
#define LCD_D5 D14
#define LCD_D6 D15
#define LCD_D7 D16
*/
#include <stdint.h>
#include "lcd_config.h"
// Commands
// Clear screen (reset)
#define LCD_CLEAR 0b00000001
// Move cursor to (0,0), unshift...
#define LCD_HOME 0b00000010
// Set mode: Increment + NoShift
#define LCD_MODE_INC 0b00000110
// Set mode: Increment + Shift
#define LCD_MODE_INC_SHIFT 0b00000111
// Set mode: Decrement + NoShift
#define LCD_MODE_DEC 0b00000100
// Set mode: Decrement + Shift
#define LCD_MODE_DEC_SHIFT 0b00000101
// Disable display (data remains untouched)
#define LCD_DISABLE 0b00001000
// Disable cursor
#define LCD_CURSOR_NONE 0b00001100
// Set cursor to still underscore
#define LCD_CURSOR_BAR 0b00001110
// Set cursor to blinking block
#define LCD_CURSOR_BLINK 0b00001101
// Set cursor to both of the above at once
#define LCD_CURSOR_BOTH (LCD_CURSOR_BAR | LCD_CURSOR_BLINK)
// Move cursor
#define LCD_MOVE_LEFT 0b00010000
#define LCD_MOVE_RIGHT 0b00010100
// Shift display
#define LCD_SHIFT_LEFT 0b00011000
#define LCD_SHIFT_RIGHT 0b00011100
// Set iface to 5x7 font, 1-line
#define LCD_IFACE_4BIT_1LINE 0b00100000
#define LCD_IFACE_8BIT_1LINE 0b00110000
// Set iface to 5x7 font, 2-line
#define LCD_IFACE_4BIT_2LINE 0b00101000
#define LCD_IFACE_8BIT_2LINE 0b00111000
/** Initialize the display */
void lcd_init();
/** Write an instruction byte */
void lcd_write_command(uint8_t bb);
/** Write a data byte */
void lcd_write_data(uint8_t bb);
/** Read BF & Address */
uint8_t lcd_read_bf_addr();
/** Read CGRAM or DDRAM */
uint8_t lcd_read_ram();
/** Send a string to LCD */
void lcd_str(char* str_p);
/** Sedn a char to LCD */
void lcd_char(const char c);
/** Show string at X, Y */
#define lcd_str_xy(x, y, str_p) do { lcd_xy((x), (y)); lcd_str((str_p)); } while(0)
/** Show char at X, Y */
#define lcd_char_xy(x, y, c) do { lcd_xy((x), (y)); lcd_char((c)); } while(0)
/** Set cursor position */
void lcd_xy(const uint8_t x, const uint8_t y);
/** Set LCD cursor. If not enabled, only remember it. */
#define CURSOR_NONE 0b00
#define CURSOR_BAR 0b10
#define CURSOR_BLINK 0b01
#define CURSOR_BOTH 0b11
void lcd_cursor(uint8_t type);
/** Display display (preserving cursor) */
void lcd_disable();
/** Enable display (restoring cursor) */
void lcd_enable();
/** Go home */
void lcd_home();
/** Clear the screen */
void lcd_clear();
/** Define a glyph */
void lcd_define_glyph(const uint8_t index, const uint8_t* array);
/** Define a glyph */
void lcd_define_glyph_pgm(const uint8_t index, const uint8_t* array);
/** Set address in CGRAM */
void lcd_set_addr_cgram(const uint8_t acg);
/** Set address in DDRAM */
void lcd_set_addr(const uint8_t add);

@ -0,0 +1,13 @@
#pragma once
#include <stdint.h>
const uint8_t FADE_128[] = {
0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4,
5, 5, 6, 6, 6, 7, 7, 8, 8, 8, 9, 10, 10, 10, 11, 12, 13, 14,
14, 15, 16, 17, 18, 20, 21, 22, 24, 26, 27, 28, 30, 31, 32, 34, 35, 36,
38, 39, 40, 41, 42, 44, 45, 46, 48, 49, 50, 52, 54, 56, 58, 59, 61, 63,
65, 67, 68, 69, 71, 72, 74, 76, 78, 80, 82, 85, 88, 90, 92, 95, 98, 100,
103, 106, 109, 112, 116, 119, 122, 125, 129, 134, 138, 142, 147, 151,
153, 156, 160, 163, 165, 170, 175, 180, 185, 190, 195, 200, 207, 214, 218,
221, 225, 228, 232, 234, 241, 248, 254, 255
};

@ -0,0 +1,66 @@
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <stdint.h>
#include <stdlib.h>
#include "lib/meta.h"
#include "lib/arduino_pins.h"
#include "lib/calc.h"
#include "lib/colors.h"
#include "lib/hsl.h"
#include "lib/adc.h"
#define WS_T_1H 800
#define WS_T_1L 400
#define WS_T_0H 120
#define WS_T_0L 900
#include "lib/ws_rgb.h"
#define WS1 D2
void SECTION(".init8") init()
{
adc_init();
srand(adc_read_word(0));
as_output(WS1);
}
void main()
{
#define SIZE 16
hsl_t board[SIZE];
xrgb_t screen[SIZE];
for (uint8_t i = 0; i < SIZE; i++) {
board[i] = (hsl_t) {.h=0, .s=255, .l=0};
screen[i] = (xrgb_t) {.r=0, .g=0, .b=0};
}
while(1) {
for(uint8_t i = 0; i < SIZE; i++) {
if (board[i].l > 0) {
board[i].l--;
}
screen[i] = hsl2xrgb(board[i]);
}
if (rand() % 50 == 0) {
uint8_t i = rand() % SIZE;
if (board[i].l == 0) {
board[i].h = rand() % 256;
board[i].s = 200 + rand() % 56;
board[i].l = 255;
}
}
ws_send_xrgb_array(WS1, screen, SIZE);
_delay_ms(2);
}
}

@ -0,0 +1,42 @@
#pragma once
/**
Pin definitions for Arduino (Pro Mini with ATmega328P)
*/
#include "pins.h"
#define D0 D,0
#define D1 D,1
#define D2 D,2
#define D3 D,3
#define D4 D,4
#define D5 D,5
#define D6 D,6
#define D7 D,7
#define D8 B,0
#define D9 B,1
#define D10 B,2
// MOSI MISO SCK - not good for input
#define D11 B,3
#define D12 B,4
#define D13 B,5
#define D14 C,0
#define D15 C,1
#define D16 C,2
#define D17 C,3
#define D18 C,4
#define D19 C,5
#define D20 C,6
#define D21 C,7
#define A0 C,0
#define A1 C,1
#define A2 C,2
#define A3 C,3
#define A4 C,4
#define A5 C,5
#define A6 C,6
#define A7 C,7

@ -0,0 +1,89 @@
#pragma once
/**
Bit and byte manipulation utilities
*/
// --- Increment in range ---
// when overflown, wraps within range. Lower bound < upper bound.
// ..., upper bound excluded
#define inc_wrap(var, min, max) do { if ((var) >= (max - 1)) { (var) = (min); } else { (var)++; } } while(0)
// ..., upper bound included
#define inc_wrapi(var, min, max) inc_wrap((var), (min), (max) + 1)
// --- Decrement in range ---
// when underflown, wraps within range. Lower bound < upper bound.
// ..., upper bound excluded
#define dec_wrap(var, min, max) do { if ((var) <= (min)) { (var) = (max) - 1; } else { (var)--; } } while(0)
// ..., upper bound included
#define dec_wrapi(var, min, max) dec_wrap((var), (min), (max) + 1)
// --- Bit manipulation --
// Set bit
#define sbi(reg, bit) do { (reg) |= (1 << (uint8_t)(bit)); } while(0)
// Clear bit
#define cbi(reg, bit) do { (reg) &= ~(1 << (uint8_t)(bit)); } while(0)
// Get n-th bit
#define read_bit(reg, bit) (((reg) >> (uint8_t)(bit)) & 0x1)
#define get_bit(reg, bit) read_bit(reg, bit)
// Test n-th bit (Can't use bit_is_set, as it's redefined in sfr_def.h)
#define bit_is_high(reg, bit) read_bit(reg, bit)
#define bit_is_low(reg, bit) (!read_bit(reg, bit))
// Write value to n-th bit
#define write_bit(reg, bit, value) do { (reg) = ((reg) & ~(1 << (uint8_t)(bit))) | (((uint8_t)(value) & 0x1) << (uint8_t)(bit)); } while(0)
#define set_bit(reg, bit, value) write_bit(reg, bit, value)
// Invert n-th bit
#define toggle_bit(reg, bit) do { (reg) ^= (1 << (uint8_t)(bit)); } while(0)
// --- Bit manipulation with pointer to variable ---
// Set n-th bit in pointee
#define sbi_p(reg_p, bit) do { (*(reg_p)) |= (1 << (uint8_t)(bit)); } while(0)
// Clear n-th bit in pointee
#define cbi_p(reg_p, bit) do { (*(reg_p)) &= ~(1 << (uint8_t)(bit)); } while(0)
// Get n-th bit in pointee
#define read_bit_p(reg_p, bit) ((*(reg_p) >> (uint8_t)(bit)) & 0x1)
#define get_bit_p(reg_p, bit) read_bit_p(reg_p, bit)
// Test n-th bit in pointee (Can't use bit_is_set, as it's redefined in sfr_def.h)
#define bit_is_high_p(reg_p, bit) read_bit_p(reg_p, bit)
#define bit_is_low_p(reg_p, bit) (!read_bit_p(reg_p, bit))
// Write value to a bit in pointee
#define write_bit_p(reg_p, bit, value) do { *(reg_p) = (*(reg_p) & ~(1 << ((uint8_t)(bit) & 0x1))) | (((uint8_t)(value) & 0x1) << (uint8_t)(bit)); } while(0)
#define set_bit_p(reg_p, bit, value) write_bit_p(reg_p, bit, value)
#define toggle_bit_p(reg_p, bit) do { *(reg_p) ^= (1 << (uint8_t)(bit)); } while(0)
// --- Nibble manipulation ---
// Replace nibble in a byte
#define write_low_nibble(reg, value) do { (reg) = ((reg) & 0xF0) | ((uint8_t)(value) & 0xF); } while(0)
#define write_high_nibble(reg, value) do { (reg) = ((reg) & 0x0F) | (((uint8_t)(value) & 0xF) << 4); } while(0)
#define write_low_nibble_p(reg_p, value) do { *(reg_p) = (*(reg_p) & 0xF0) | ((uint8_t)(value) & 0xF); } while(0)
#define write_high_nibble_p(reg_p, value) do { *(reg_p) = (*(reg_p) & 0x0F) | (((uint8_t)(value) & 0xF) << 4); } while(0)
// --- Range tests ---
// Test if X is within low..high, regardless of bounds order
#define in_range(x, low, high) ((((low) < (high)) && ((x) >= (low) && (x) < (high))) || (((low) > (high)) && ((x) >= (high) && (x) < (low))))
// ..., include greater bound
#define in_rangei(x, low, high) ((((low) <= (high)) && ((x) >= (low) && (x) <= (high))) || (((low) > (high)) && ((x) >= (high) && (x) <= (low))))
// Test if X in low..high, wrap around ends if needed.
#define in_range_wrap(x, low, high) ((((low) < (high)) && ((x) >= (low) && (x) < (high))) || (((low) > (high)) && ((x) >= (low) || (x) < (high))))
// ..., include upper bound
#define in_range_wrapi(x, low, high) ((((low) <= (high)) && ((x) >= (low) && (x) <= (high))) || (((low) > (high)) && ((x) >= (low) || (x) <= (high))))

@ -0,0 +1,22 @@
#pragma once
/**
Custom loops
*/
// Repeat code n times (uint8_t counter)
#define repeat(count) repeat_aux(count, _repeat_##__COUNTER__)
#define repeat_aux(count, cntvar) for (uint8_t cntvar = 0; cntvar < (count); cntvar++)
// Repeat code n times (uint16_t counter)
#define repeatx(count) repeatx_aux(count, _repeatx_##__COUNTER__)
#define repeatx_aux(count, cntvar) for (uint16_t cntvar = 0; cntvar < (count); cntvar++)
// Repeat with custom counter name (uint8_t)
#define loop(var, count) repeat_aux(count, var)
// ..., uint16_t
#define loopx(var, count) repeatx_aux(count, var)
// Do until condition is met
#define until(what) while(!(what))

@ -0,0 +1,6 @@
#pragma once
/** Weird constructs for the compiler */
// general macros
#define SECTION(pos) __attribute__((naked, used, section(pos)))

@ -0,0 +1,21 @@
#pragma once
/**
Functions for precise delays (nanoseconds / cycles)
*/
#include <avr/io.h>
#include <util/delay_basic.h>
#include <stdint.h>
/* Convert nanoseconds to cycle count */
#define ns2cycles(ns) ( (ns) / (1000000000L / (signed long) F_CPU) )
/** Wait c cycles */
#define delay_c(c) (((c) > 0) ? __builtin_avr_delay_cycles(c) : __builtin_avr_delay_cycles(0))
/** Wait n nanoseconds, plus c cycles */
#define delay_ns_c(ns, c) delay_c(ns2cycles(ns) + (c))
/** Wait n nanoseconds */
#define delay_ns(ns) delay_c(ns2cycles(ns))

@ -0,0 +1,107 @@
#pragma once
/**
This file provides macros for pin manipulation.
You can define your application pins like so:
// Led at PORTB, pin 1
#define LED B,1
// Switch at PORTD, pin 7
#define SW1 D,7
Now you can use macros from this file to wirh with the pins, eg:
as_output(LED);
as_input(SW1);
pullup_on(SW1);
toggle_pin(LED);
while (pin_is_low(SW1));
- The macros io2XXX() can be used to get literal name of register associated with the pin.
- io2n() provides pin number.
- The XXX_aux() macros are internal and should not be used elsewhere.
- The io_pack() macro is used to pass pin (io) to other macro without expanding it.
*/
#include <avr/io.h>
#include "calc.h"
// Get particular register associated with the name X (eg. D -> PORTD)
#define reg_ddr(X) DDR ## X
#define reg_port(X) PORT ## X
#define reg_pin(X) PIN ## X
#define io2ddr_aux(reg, bit) reg_ddr(reg)
#define io2ddr(io) io2ddr_aux(io)
#define io2port_aux(reg, bit) reg_port(reg)
#define io2port(io) io2port_aux(io)
#define io2pin_aux(reg, bit) reg_pin(reg)
#define io2pin(io) io2pin_aux(io)
#define io2n_aux(reg, bit) bit
#define io2n(io) io2n_aux(io)
#define io_pack(port, bit) port, bit
// pointer to port
typedef volatile uint8_t* PORT_P;
// number of bit in port
typedef uint8_t BIT_N;
// === pin manipulation ===
#define set_pin_aux(port, bit) sbi(reg_port(port), (bit))
#define clear_pin_aux(port, bit) cbi(reg_port(port), (bit))
#define read_pin_aux(port, bit) get_bit(reg_pin(port), (bit))
#define write_pin_aux(port, bit, value) set_bit(reg_port(port), (bit), (value))
#define toggle_pin_aux(port, bit) sbi(reg_pin(port), (bit))
#define pin_up(io) set_pin_aux(io)
#define pin_high(io) set_pin_aux(io)
#define pin_down(io) clear_pin_aux(io)
#define pin_low(io) clear_pin_aux(io)
#define get_pin(io) read_pin_aux(io)
#define read_pin(io) read_pin_aux(io)
#define pin_is_low(io) !read_pin_aux(io)
#define pin_is_high(io) read_pin_aux(io)
#define set_pin(io, value) write_pin_aux(io, (value))
#define write_pin(io, value) write_pin_aux(io, (value))
#define toggle_pin(io) toggle_pin_aux(io)
// setting pin direction
#define as_input_aux(port, bit) cbi(reg_ddr(port), (bit))
#define as_output_aux(port, bit) sbi(reg_ddr(port), (bit))
#define set_dir_aux(port, bit, dir) write_bit(reg_ddr(port), (bit), (dir))
#define as_input(io) as_input_aux(io)
#define as_input_pu(io) do { as_input_aux(io); pullup_enable_aux(io); } while(0)
#define as_output(io) as_output_aux(io)
#define set_dir(io, dir) set_dir_aux(io, (dir))
// setting pullup
#define pullup_enable_aux(port, bit) sbi(reg_port(port), (bit))
#define pullup_disable_aux(port, bit) cbi(reg_port(port), (bit))
#define set_pullup_aux(port, bit, on) write_bit(reg_port(port), (bit), (on))
#define pullup_enable(io) pullup_enable_aux(io)
#define pullup_on(io) pullup_enable_aux(io)
#define pullup_disable(io) pullup_disable_aux(io)
#define pullup_off(io) pullup_disable_aux(io)
#define set_pullup(io, on) set_pullup_aux(io, on)

@ -0,0 +1,98 @@
#pragma once
/**
Utils for driving a WS28xx (tested on WS2812B) RGB LED strips.
It's implemented as macros to avoid overhead when passing values, and to
enable driving multiple strips at once.
To avoid bloating your code, try to reduce the number of invocations -
compute color and then send it.
[IMPORTANT]
Some seemingly random influences can ruin the communication.
If you have enough memory, consider preparing the colors in array,
and sending this array using one of the "ws_send_XXX_array" macros.
*/
#include <avr/io.h>
#include "pins.h"
#include "nsdelay.h"
#include "colors.h"
/* Driver code for WS2812B */
// --- timing constraints (NS) ---
#ifndef WS_T_1H
# define WS_T_1H 700
#endif
#ifndef WS_T_1L
# define WS_T_1L 150
#endif
#ifndef WS_T_0H
# define WS_T_0H 150
#endif
#ifndef WS_T_0L
# define WS_T_0L 700
#endif
#ifndef WS_T_LATCH
# define WS_T_LATCH 7000
#endif
/** Wait long enough for the colors to show */
#define ws_show() do {delay_ns_c(WS_T_LATCH, 0); } while(0)
/** Send one byte to the RGB strip */
#define ws_send_byte(io, bb) do { \
for (volatile int8_t __ws_tmp = 7; __ws_tmp >= 0; --__ws_tmp) { \
if ((bb) & (1 << __ws_tmp)) { \
pin_high(io_pack(io)); delay_ns_c(WS_T_1H, -2); \
pin_low(io_pack(io)); delay_ns_c(WS_T_1L, -10); \
} else { \
pin_high(io_pack(io)); delay_ns_c(WS_T_0H, -2); \
pin_low(io_pack(io)); delay_ns_c(WS_T_0L, -10); \
} \
} \
} while(0)
/** Send R,G,B color to the strip */
#define ws_send_rgb(io, r, g, b) do { \
ws_send_byte(io_pack(io), g); \
ws_send_byte(io_pack(io), r); \
ws_send_byte(io_pack(io), b); \
} while(0)
/** Send a RGB struct */
#define ws_send_xrgb(io, xrgb) ws_send_rgb(io_pack(io), (xrgb).r, (xrgb).g, (xrgb).b)
/** Send color hex */
#define ws_send_rgb24(io, rgb) ws_send_rgb(io_pack(io), rgb24_r(rgb), rgb24_g(rgb), rgb24_b(rgb))
#define ws_send_rgb15(io, rgb) ws_send_rgb(io_pack(io), rgb15_r(rgb), rgb15_g(rgb), rgb15_b(rgb))
#define ws_send_rgb12(io, rgb) ws_send_rgb(io_pack(io), rgb12_r(rgb), rgb12_g(rgb), rgb12_b(rgb))
#define ws_send_rgb6(io, rgb) ws_send_rgb(io_pack(io), rgb6_r(rgb), rgb6_g(rgb), rgb6_b(rgb))
/** Send array of colors */
#define ws_send_xrgb_array(io, rgbs, length) __ws_send_array_proto(io_pack(io), (rgbs), (length), xrgb)
#define ws_send_rgb24_array(io, rgbs, length) __ws_send_array_proto(io_pack(io), (rgbs), (length), rgb24)
#define ws_send_rgb15_array(io, rgbs, length) __ws_send_array_proto(io_pack(io), (rgbs), (length), rgb15)
#define ws_send_rgb12_array(io, rgbs, length) __ws_send_array_proto(io_pack(io), (rgbs), (length), rgb12)
#define ws_send_rgb6_array(io, rgbs, length) __ws_send_array_proto(io_pack(io), (rgbs), (length), rgb6)
// prototype for sending array. it's ugly, sorry.
#define __ws_send_array_proto(io, rgbs, length, style) do { \
for (uint8_t __ws_tmp_sap_i = 0; __ws_tmp_sap_i < length; __ws_tmp_sap_i++) { \
style ## _t __ws_tmp_sap2 = (rgbs)[__ws_tmp_sap_i]; \
ws_send_ ## style(io_pack(io), __ws_tmp_sap2); \
} \
} while(0)

@ -74,7 +74,7 @@ void update_cell(cell_t* cell)
void main()
{
#define LEN 8
#define LEN 16
cell_t rainbow[LEN];
for(uint8_t i=0; i<LEN; i++) {
Loading…
Cancel
Save