Some old AVR projects
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

127 lines
4.3 KiB

#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_sap_i = 0; __ws_sap_i < length; __ws_sap_i++) { \
style ## _t __ws_sap2 = (rgbs)[__ws_sap_i]; \
ws_send_ ## style(io_pack(io), __ws_sap2); \
} \
} while(0)
/** Send a 2D array to a zig-zag display */
#define ws_send_xrgb_array_zigzag(io, rgbs, width, height) do { \
int8_t __ws_sxaz_y, __ws_sxaz_x; \
for(__ws_sxaz_y = 0; __ws_sxaz_y < (height); __ws_sxaz_y ++) { \
for(__ws_sxaz_x = 0; __ws_sxaz_x < (width); __ws_sxaz_x++) { \
ws_send_xrgb(io_pack(io), (rgbs)[__ws_sxaz_y][__ws_sxaz_x]); \
} \
__ws_sxaz_y++; \
for(__ws_sxaz_x = (width) - 1; __ws_sxaz_x >= 0; __ws_sxaz_x--) { \
ws_send_xrgb(io_pack(io), (rgbs)[__ws_sxaz_y][__ws_sxaz_x]); \
} \
} \
} while(0)
/** Send a linear array to a zig-zag display as a n*m board (row-by-row) */
#define ws_send_xrgb_array_zigzag_linear(io, rgbs, width, height) do { \
int8_t __ws_sxazl_x, __ws_sxazl_y; \
for(__ws_sxazl_y = 0; __ws_sxazl_y < (height); __ws_sxazl_y++) { \
for(__ws_sxazl_x = 0; __ws_sxazl_x < (width); __ws_sxazl_x++) { \
ws_send_xrgb(io_pack(io), (rgbs)[__ws_sxazl_y * (width) + __ws_sxazl_x]); \
} \
__ws_sxazl_y++; \
for(__ws_sxazl_x = width-1; __ws_sxazl_x >=0; __ws_sxazl_x--) { \
ws_send_xrgb(io_pack(io), (rgbs)[__ws_sxazl_y * (width) + __ws_sxazl_x]); \
} \
} \
} while(0)