parent
2204211cb4
commit
130e7fd781
@ -0,0 +1,103 @@ |
||||
#include <avr/io.h> |
||||
#include <util/delay.h> |
||||
#include <stdint.h> |
||||
|
||||
#include "iopins.h" |
||||
#include "nsdelay.h" |
||||
#include "color.h" |
||||
|
||||
|
||||
// --- HSL ---
|
||||
|
||||
#ifdef HSL_LINEAR |
||||
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 |
||||
}; |
||||
#endif |
||||
|
||||
// based on: https://github.com/lewisd32/avr-hsl2rgb
|
||||
xrgb_t hsl_xrgb(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,57 @@ |
||||
#pragma once |
||||
|
||||
// --- color types ---
|
||||
//
|
||||
// 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)
|
||||
// rgb24 ... 24-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
|
||||
|
||||
// Define HSL_LINEAR to get more linear brightness in hsl->rgb conversion
|
||||
|
||||
|
||||
typedef struct |
||||
{ |
||||
uint8_t r; |
||||
uint8_t g; |
||||
uint8_t b; |
||||
} xrgb_t; |
||||
|
||||
|
||||
typedef uint32_t rgb24_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 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)) }) |
||||
|
||||
|
||||
// HSL data structure
|
||||
typedef struct |
||||
{ |
||||
uint8_t h; |
||||
uint8_t s; |
||||
uint8_t l; |
||||
} hsl_t; |
||||
|
||||
/* Convert HSL to XRGB */ |
||||
xrgb_t hsl_xrgb(const hsl_t color); |
@ -0,0 +1,49 @@ |
||||
#include <avr/io.h> |
||||
#include <stdbool.h> |
||||
|
||||
#include "debounce.h" |
||||
#include "calc.h" |
||||
#include "iopins.h" |
||||
|
||||
/** Debounce data array */ |
||||
uint8_t debo_next_slot = 0; |
||||
|
||||
/** bit - range 0-63 */ |
||||
uint8_t debo_register(PORT_P reg, uint8_t bit, bool invert, DebouncerCallback callback) |
||||
{ |
||||
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, |
||||
.callback = callback, |
||||
}; |
||||
|
||||
return debo_next_slot++; |
||||
} |
||||
|
||||
/** Check debounced pins, should be called periodically. */ |
||||
void debo_tick(void) |
||||
{ |
||||
for (uint8_t i = 0; i < debo_next_slot; i++) { |
||||
// current pin value
|
||||
bool value = get_bit_p(debo_slots[i].reg, debo_slots[i].bit & 0x3F) |
||||
^get_bit(debo_slots[i].bit, 7); |
||||
|
||||
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; |
||||
// Fire the callback, if not NULL
|
||||
if (debo_slots[i].callback) { |
||||
debo_slots[i].callback(i, value); |
||||
} |
||||
} |
||||
} else { |
||||
debo_slots[i].count = 0; // reset the counter
|
||||
} |
||||
} |
||||
} |
@ -0,0 +1,84 @@ |
||||
#ifndef DEBOUNCE_H |
||||
#define DEBOUNCE_H |
||||
|
||||
//
|
||||
// An implementation of button debouncer.
|
||||
//
|
||||
// ----
|
||||
//
|
||||
// You must provide a config file debo_config.h (next to your main.c)
|
||||
//
|
||||
// A pin is registered like this:
|
||||
//
|
||||
// #define BTN1 12 // pin D12
|
||||
// #define BTN2 13
|
||||
//
|
||||
// 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 <stdint.h> |
||||
|
||||
#include "calc.h" |
||||
#include "iopins.h" |
||||
|
||||
// Update as needed
|
||||
#define DEBO_CHANNELS 5 |
||||
#define DEBO_TICKS 50 // ms
|
||||
|
||||
/** Debouncer callback; state - state after applying inverse bit */ |
||||
typedef void(*DebouncerCallback)(uint8_t n, bool state); |
||||
|
||||
/* Internal debouncer 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
|
||||
DebouncerCallback callback; |
||||
} debo_slot_t; |
||||
|
||||
debo_slot_t debo_slots[DEBO_CHANNELS]; |
||||
|
||||
/**
|
||||
* Add a pin for debouncing (low level function) |
||||
* |
||||
* @param pin_reg_pointer - PINx pointer |
||||
* @param bit - number of the debounced bit in the register (0-7) |
||||
* @param invert - invert the value when reading (for buttons to GND, for example) |
||||
*/ |
||||
uint8_t debo_register(PORT_P pin_reg_pointer, uint8_t bit, bool invert, DebouncerCallback cbk); |
||||
|
||||
/**
|
||||
* Add a pin for debouncing (must be used with constant args). |
||||
* Returns index in debouncer, used for callbacks. |
||||
* |
||||
* Arg: pin number, defined in iopins.h |
||||
*/ |
||||
#define debo_add(pin, callback) debo_register(&_pin(pin), _pn(pin), false, callback) |
||||
#define debo_add_rev(pin, callback) debo_register(&_pin(pin), _pn(pin), true, callback) |
||||
|
||||
/**
|
||||
* Check debounced pins, should be called periodically. |
||||
* Updates internal states and fires callbacks. |
||||
*/ |
||||
void debo_tick(void); |
||||
|
||||
/**
|
||||
* Get a value of debounced pin (after debounce - latched state) |
||||
*/ |
||||
#define debo_get_pin(i) (get_bit(debo_slots[i].bit, 6) ^ get_bit(debo_slots[i].bit, 7)) |
||||
|
||||
#endif |
@ -0,0 +1,131 @@ |
||||
#include <avr/io.h> |
||||
#include <util/delay.h> |
||||
#include <stdint.h> |
||||
|
||||
#include "iopins.h" |
||||
#include "nsdelay.h" |
||||
|
||||
#include "wsrgb.h" |
||||
#include "color.h" |
||||
|
||||
/* Driver code for WS2812B */ |
||||
|
||||
void ws_init() |
||||
{ |
||||
as_output(WS_PIN); |
||||
} |
||||
|
||||
/** Wait long enough for the colors to show */ |
||||
void ws_show() |
||||
{ |
||||
delay_ns_c(WS_T_LATCH, 0); |
||||
} |
||||
|
||||
/** Send one byte to the RGB strip */ |
||||
void ws_send_byte(const uint8_t bb) |
||||
{ |
||||
for (volatile int8_t i = 7; i >= 0; --i) { |
||||
if ((bb) & (1 << i)) { |
||||
pin_up(WS_PIN); |
||||
delay_ns_c(WS_T_1H, -2); |
||||
|
||||
pin_down(WS_PIN); |
||||
delay_ns_c(WS_T_1L, -10); |
||||
} else { |
||||
pin_up(WS_PIN); |
||||
delay_ns_c(WS_T_0H, -2); |
||||
|
||||
pin_down(WS_PIN); |
||||
delay_ns_c(WS_T_0L, -10); |
||||
} |
||||
} |
||||
} |
||||
|
||||
|
||||
/** Send R,G,B color to the strip */ |
||||
void ws_send_rgb(const uint8_t r, const uint8_t g, const uint8_t b) |
||||
{ |
||||
ws_send_byte(g); |
||||
ws_send_byte(r); |
||||
ws_send_byte(b); |
||||
} |
||||
|
||||
|
||||
/** Send a RGB struct */ |
||||
void ws_send_xrgb(xrgb_t xrgb) |
||||
{ |
||||
ws_send_byte(xrgb.g); |
||||
ws_send_byte(xrgb.r); |
||||
ws_send_byte(xrgb.b); |
||||
} |
||||
|
||||
|
||||
/** Send color hex */ |
||||
void ws_send_rgb24(rgb24_t rgb) |
||||
{ |
||||
ws_send_byte(rgb24_g(rgb)); |
||||
ws_send_byte(rgb24_r(rgb)); |
||||
ws_send_byte(rgb24_b(rgb)); |
||||
} |
||||
|
||||
/** Send array of colors */ |
||||
void ws_send_xrgb_array(const xrgb_t rgbs[], const uint8_t length) |
||||
{ |
||||
for (uint8_t i = 0; i < length; i++) { |
||||
const xrgb_t c = rgbs[i]; |
||||
ws_send_byte(c.g); |
||||
ws_send_byte(c.r); |
||||
ws_send_byte(c.b); |
||||
} |
||||
} |
||||
|
||||
/** Send array of colors */ |
||||
void ws_send_rgb24_array(const rgb24_t rgbs[], const uint8_t length) |
||||
{ |
||||
for (uint8_t i = 0; i < length; i++) { |
||||
const rgb24_t c = rgbs[i]; |
||||
ws_send_byte(rgb24_g(c)); |
||||
ws_send_byte(rgb24_r(c)); |
||||
ws_send_byte(rgb24_b(c)); |
||||
} |
||||
} |
||||
|
||||
//#define ws_send_rgb24_array(rgbs, length) __ws_send_array_proto((rgbs), (length), rgb24)
|
||||
|
||||
// prototype for sending array. it's ugly, sorry.
|
||||
/*#define __ws_send_array_proto(rgbs, length, style) { \
|
||||
for (uint8_t __rgb_sap_i = 0; __rgb_sap_i < length; __rgb_sap_i++) { \
|
||||
style ## _t __rgb_sap2 = (rgbs)[__rgb_sap_i]; \
|
||||
ws_send_ ## style(__rgb_sap2); \
|
||||
} \
|
||||
}*/ |
||||
|
||||
|
||||
// /** Send a 2D array to a zig-zag display */
|
||||
// #define ws_send_xrgb_array_zigzag(rgbs, width, height) { \
|
||||
// int8_t __rgb_sxaz_y, __rgb_sxaz_x; \
|
||||
// for(__rgb_sxaz_y = 0; __rgb_sxaz_y < (height); __rgb_sxaz_y ++) { \
|
||||
// for(__rgb_sxaz_x = 0; __rgb_sxaz_x < (width); __rgb_sxaz_x++) { \
|
||||
// ws_send_xrgb((rgbs)[__rgb_sxaz_y][__rgb_sxaz_x]); \
|
||||
// } \
|
||||
// __rgb_sxaz_y++; \
|
||||
// for(__rgb_sxaz_x = (width) - 1; __rgb_sxaz_x >= 0; __rgb_sxaz_x--) { \
|
||||
// ws_send_xrgb((rgbs)[__rgb_sxaz_y][__rgb_sxaz_x]); \
|
||||
// } \
|
||||
// } \
|
||||
// }
|
||||
|
||||
|
||||
// /* Send a linear array to a zig-zag display as a n*m board (row-by-row)
|
||||
// #define ws_send_xrgb_array_zigzag_linear(rgbs, width, height) { \
|
||||
// int8_t __rgb_sxazl_x, __rgb_sxazl_y; \
|
||||
// for(__rgb_sxazl_y = 0; __rgb_sxazl_y < (height); __rgb_sxazl_y++) { \
|
||||
// for(__rgb_sxazl_x = 0; __rgb_sxazl_x < (width); __rgb_sxazl_x++) { \
|
||||
// ws_send_xrgb((rgbs)[__rgb_sxazl_y * (width) + __rgb_sxazl_x]); \
|
||||
// } \
|
||||
// __rgb_sxazl_y++; \
|
||||
// for(__rgb_sxazl_x = width-1; __rgb_sxazl_x >=0; __rgb_sxazl_x--) { \
|
||||
// ws_send_xrgb((rgbs)[__rgb_sxazl_y * (width) + __rgb_sxazl_x]); \
|
||||
// } \
|
||||
// } \
|
||||
// }
|
@ -0,0 +1,46 @@ |
||||
#pragma once |
||||
|
||||
//
|
||||
// Utils for driving a WS2812 RGB LED strips, and color manipulation in general.
|
||||
//
|
||||
// Timing is critical!
|
||||
//
|
||||
|
||||
#include <stdint.h> |
||||
|
||||
#include "iopins.h" |
||||
#include "color.h" |
||||
|
||||
// Config
|
||||
#define WS_T_1H 700 |
||||
#define WS_T_1L 150 |
||||
#define WS_T_0H 150 |
||||
#define WS_T_0L 700 |
||||
#define WS_T_LATCH 7000 |
||||
#define WS_PIN 2 |
||||
|
||||
// --- functions for RGB strips ---
|
||||
|
||||
/** Initialize OI */ |
||||
void ws_init(); |
||||
|
||||
/** Wait long enough for the colors to show */ |
||||
void ws_show(); |
||||
|
||||
/** Send one byte to the RGB strip */ |
||||
void ws_send_byte(const uint8_t bb); |
||||
|
||||
/** Send R,G,B color to the strip */ |
||||
void ws_send_rgb(const uint8_t r, const uint8_t g, const uint8_t b); |
||||
|
||||
/** Send a RGB struct */ |
||||
void ws_send_xrgb(xrgb_t xrgb); |
||||
|
||||
/** Send color hex */ |
||||
void ws_send_rgb24(rgb24_t rgb); |
||||
|
||||
/** Send array of colors */ |
||||
void ws_send_xrgb_array(const xrgb_t rgbs[], const uint8_t length); |
||||
|
||||
/** Send array of colors */ |
||||
void ws_send_rgb24_array(const rgb24_t rgbs[], const uint8_t length); |
Loading…
Reference in new issue