Refactored to sk6812; Added white channel

This commit is contained in:
Thomas Kolb 2018-06-13 23:06:45 +02:00
parent f033119aa8
commit bca64a858a
9 changed files with 115 additions and 152 deletions

View file

@ -13,12 +13,12 @@ set(sources
src/main.c src/main.c
src/udpproto.c src/udpproto.c
src/utils.c src/utils.c
src/ws2801.c src/sk6812.c
src/fader.h src/fader.h
src/logger.h src/logger.h
src/udpproto.h src/udpproto.h
src/utils.h src/utils.h
src/ws2801.h src/sk6812.h
) )
include_directories( include_directories(

View file

@ -2,7 +2,7 @@
#include "logger.h" #include "logger.h"
#include "utils.h" #include "utils.h"
#include "ws2801.h" #include "sk6812.h"
#include "fader.h" #include "fader.h"
@ -11,18 +11,20 @@ uint32_t numModules;
float fadestep = 1; float fadestep = 1;
double nextFrame; double nextFrame;
int somethingChanged = 0; // indicates when a ws2801 update is required int somethingChanged = 0; // indicates when a sk6812 update is required
static const double interval = 0.01f; static const double interval = 0.01f;
struct Colour { struct Colour {
float red, green, blue; // value range is 0.0 to 255.0 float red, green, blue, white; // value range is 0.0 to 255.0
}; };
struct Colour *curColour; struct Colour *curColour;
struct Colour *targetColour; struct Colour *targetColour;
int fader_init(uint32_t nMod) struct sk6812_ctx *ledCtx; // global context for the one strip we control
int fader_init(uint32_t nMod, struct sk6812_ctx *ctx)
{ {
numModules = nMod; numModules = nMod;
@ -42,8 +44,12 @@ int fader_init(uint32_t nMod)
curColour[i].red = targetColour[i].red = 0; curColour[i].red = targetColour[i].red = 0;
curColour[i].green = targetColour[i].green = 0; curColour[i].green = targetColour[i].green = 0;
curColour[i].blue = targetColour[i].blue = 0; curColour[i].blue = targetColour[i].blue = 0;
curColour[i].white = targetColour[i].white = 0;
} }
// store LED context (initalized externally)
ledCtx = ctx;
// timestamp for the first frame // timestamp for the first frame
nextFrame = get_hires_time() + interval; nextFrame = get_hires_time() + interval;
@ -56,39 +62,37 @@ void fader_shutdown(void)
free(targetColour); free(targetColour);
} }
void fader_set_colour(uint32_t module, uint8_t r, uint8_t g, uint8_t b) void fader_set_colour(uint32_t module, uint8_t r, uint8_t g, uint8_t b, uint8_t w)
{ {
curColour[module].red = targetColour[module].red = r; curColour[module].red = targetColour[module].red = r;
curColour[module].green = targetColour[module].green = g; curColour[module].green = targetColour[module].green = g;
curColour[module].blue = targetColour[module].blue = b; curColour[module].blue = targetColour[module].blue = b;
curColour[module].white = targetColour[module].white = w;
somethingChanged = 1; somethingChanged = 1;
} }
void fader_fade_colour(uint32_t module, uint8_t r, uint8_t g, uint8_t b) void fader_fade_colour(uint32_t module, uint8_t r, uint8_t g, uint8_t b, uint8_t w)
{ {
targetColour[module].red = r; targetColour[module].red = r;
targetColour[module].green = g; targetColour[module].green = g;
targetColour[module].blue = b; targetColour[module].blue = b;
targetColour[module].white = w;
} }
void fader_add_colour(uint32_t module, uint8_t r, uint8_t g, uint8_t b) void fader_add_colour(uint32_t module, uint8_t r, uint8_t g, uint8_t b, uint8_t w)
{ {
curColour[module].red += r; curColour[module].red += r;
curColour[module].green += g; curColour[module].green += g;
curColour[module].blue += b; curColour[module].blue += b;
curColour[module].white += w;
if(curColour[module].red > 255) { curColour[module].red = 255; } if(curColour[module].red > 255) { curColour[module].red = 255; }
if(curColour[module].green > 255) { curColour[module].green = 255; } if(curColour[module].green > 255) { curColour[module].green = 255; }
if(curColour[module].blue > 255) { curColour[module].blue = 255; } if(curColour[module].blue > 255) { curColour[module].blue = 255; }
if(curColour[module].white > 255) { curColour[module].white = 255; }
targetColour[module].red += r; targetColour[module] = curColour[module];
targetColour[module].green += g;
targetColour[module].blue += b;
if(targetColour[module].red > 255) { targetColour[module].red = 255; }
if(targetColour[module].green > 255) { targetColour[module].green = 255; }
if(targetColour[module].blue > 255) { targetColour[module].blue = 255; }
somethingChanged = 1; somethingChanged = 1;
} }
@ -137,15 +141,17 @@ void fader_update(void)
fade_colour(&(curColour[i].red), &(targetColour[i].red), &somethingChanged); fade_colour(&(curColour[i].red), &(targetColour[i].red), &somethingChanged);
fade_colour(&(curColour[i].green), &(targetColour[i].green), &somethingChanged); fade_colour(&(curColour[i].green), &(targetColour[i].green), &somethingChanged);
fade_colour(&(curColour[i].blue), &(targetColour[i].blue), &somethingChanged); fade_colour(&(curColour[i].blue), &(targetColour[i].blue), &somethingChanged);
fade_colour(&(curColour[i].white), &(targetColour[i].white), &somethingChanged);
ws2801_set_colour(i, sk6812_set_colour(ledCtx, i,
(uint8_t)curColour[i].red, (uint8_t)curColour[i].red,
(uint8_t)curColour[i].green, (uint8_t)curColour[i].green,
(uint8_t)curColour[i].blue); (uint8_t)curColour[i].blue,
(uint8_t)curColour[i].white);
} }
if(somethingChanged) { if(somethingChanged) {
ws2801_send_update(); sk6812_send_update(ledCtx);
somethingChanged = 0; somethingChanged = 0;
} }
} }

View file

@ -3,11 +3,13 @@
#include <stdint.h> #include <stdint.h>
int fader_init(uint32_t nMod); struct sk6812_ctx;
int fader_init(uint32_t nMod, struct sk6812_ctx *ctx);
void fader_shutdown(void); void fader_shutdown(void);
void fader_set_colour(uint32_t module, uint8_t r, uint8_t g, uint8_t b); void fader_set_colour(uint32_t module, uint8_t r, uint8_t g, uint8_t b, uint8_t w);
void fader_fade_colour(uint32_t module, uint8_t r, uint8_t g, uint8_t b); void fader_fade_colour(uint32_t module, uint8_t r, uint8_t g, uint8_t b, uint8_t w);
void fader_add_colour(uint32_t module, uint8_t r, uint8_t g, uint8_t b); void fader_add_colour(uint32_t module, uint8_t r, uint8_t g, uint8_t b, uint8_t w);
void fader_set_fadestep(uint8_t newFadestep); void fader_set_fadestep(uint8_t newFadestep);
void fader_update(void); void fader_update(void);
void fader_wait_frame(void); void fader_wait_frame(void);

View file

@ -5,7 +5,7 @@
#include <errno.h> #include <errno.h>
#include <stdint.h> #include <stdint.h>
#include "ws2801.h" #include "sk6812.h"
#include "logger.h" #include "logger.h"
#include "fader.h" #include "fader.h"
#include "udpproto.h" #include "udpproto.h"
@ -13,9 +13,13 @@
#define PORT 2703 #define PORT 2703
#define NUM_MODULES 160 #define NUM_MODULES 160
#define GPIO_IDX 960
#define BASE_ADDR ((void*)0x40000000U)
int main(void) int main(void)
{ {
struct sk6812_ctx ctx;
// initialize logger // initialize logger
logger_init(); logger_init();
@ -26,13 +30,13 @@ int main(void)
} }
// initialize ws2801 library // initialize ws2801 library
if(ws2801_init(NUM_MODULES) == -1) { if(sk6812_init(&ctx, GPIO_IDX, BASE_ADDR, NUM_MODULES) == -1) {
LOG(LVL_FATAL, "Could not initialize WS2801 library."); LOG(LVL_FATAL, "Could not initialize SK6812 library.");
return 1; return 1;
} }
// initialise the LED fader // initialise the LED fader
if(fader_init(NUM_MODULES) == -1) { if(fader_init(NUM_MODULES, &ctx) == -1) {
LOG(LVL_FATAL, "Could not initialize the LED fader."); LOG(LVL_FATAL, "Could not initialize the LED fader.");
return 1; return 1;
} }
@ -47,7 +51,7 @@ int main(void)
// shut down all modules // shut down all modules
fader_shutdown(); fader_shutdown();
ws2801_shutdown(); sk6812_shutdown(&ctx);
udpproto_shutdown(); udpproto_shutdown();
return 0; return 0;

45
src/sk6812.c Normal file
View file

@ -0,0 +1,45 @@
#include <time.h>
#include <string.h>
#include <malloc.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <linux/spi/spidev.h>
#include "logger.h"
#include "sk6812.h"
int sk6812_init(struct sk6812_ctx *ctx, uint32_t gpio_idx, void *phys_baseptr, uint32_t num_modules)
{
// TODO:
// - map memory
// - setup GPIO
return 0;
}
void sk6812_shutdown(struct sk6812_ctx *ctx)
{
// TODO:
// - unmap memory
}
void sk6812_set_colour(struct sk6812_ctx *ctx, uint32_t module, uint8_t red, uint8_t green, uint8_t blue, uint8_t white)
{
uint32_t value =
((uint32_t)red << 24U) |
((uint32_t)green << 16U) |
((uint32_t)blue << 8U) |
(uint32_t)white;
ctx->memptr->led_data[module] = value;
}
void sk6812_send_update(struct sk6812_ctx *ctx)
{
// TODO: generate rising edge on GPIO
}

23
src/sk6812.h Normal file
View file

@ -0,0 +1,23 @@
#ifndef SK6812_H
#define SK6812_H
#include <stdint.h>
struct sk6812_memory
{
uint32_t num_leds;
uint32_t led_data[];
};
struct sk6812_ctx
{
struct sk6812_memory *memptr;
char *gpio_value_path;
};
int sk6812_init(struct sk6812_ctx *ctx, uint32_t gpio_idx, void *phys_baseptr, uint32_t num_modules);
void sk6812_shutdown(struct sk6812_ctx *ctx);
void sk6812_set_colour(struct sk6812_ctx *ctx, uint32_t module, uint8_t red, uint8_t green, uint8_t blue, uint8_t white);
void sk6812_send_update(struct sk6812_ctx *ctx);
#endif // SK6812_H

View file

@ -50,7 +50,7 @@ int udpproto_process(void)
uint8_t pkgbuf[65536]; uint8_t pkgbuf[65536];
ssize_t rcvbytes, offset = 0; ssize_t rcvbytes, offset = 0;
uint8_t r, g, b, action, module; uint8_t r, g, b, w, action, module;
int fds_ready; int fds_ready;
// check if there is data to be read (to prevent blocking) // check if there is data to be read (to prevent blocking)
@ -81,25 +81,26 @@ int udpproto_process(void)
// parse commands from packet // parse commands from packet
offset = 0; offset = 0;
while(offset <= rcvbytes - 4) { while(offset <= rcvbytes - 5) {
action = pkgbuf[offset + 0]; action = pkgbuf[offset + 0];
module = pkgbuf[offset + 1]; module = pkgbuf[offset + 1];
r = pkgbuf[offset + 2]; r = pkgbuf[offset + 2];
g = pkgbuf[offset + 3]; g = pkgbuf[offset + 3];
b = pkgbuf[offset + 4]; b = pkgbuf[offset + 4];
w = pkgbuf[offset + 5];
offset += 5; offset += 5;
switch(action) { switch(action) {
case SET_COLOUR: case SET_COLOUR:
fader_set_colour(module, r, g, b); fader_set_colour(module, r, g, b, w);
break; break;
case FADE_COLOUR: case FADE_COLOUR:
fader_fade_colour(module, r, g, b); fader_fade_colour(module, r, g, b, w);
break; break;
case ADD_COLOUR: case ADD_COLOUR:
fader_add_colour(module, r, g, b); fader_add_colour(module, r, g, b, w);
break; break;
case SET_FADESTEP: case SET_FADESTEP:
@ -111,7 +112,7 @@ int udpproto_process(void)
} }
} }
return rcvbytes / 5; // number of commands in packet return rcvbytes / 6; // number of commands in packet
} }
void udpproto_shutdown(void) void udpproto_shutdown(void)

View file

@ -1,107 +0,0 @@
#include <time.h>
#include <string.h>
#include <malloc.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <linux/spi/spidev.h>
//#include <wiringPi.h>
#include "logger.h"
#include "ws2801.h"
static const char *spi_dev = "/dev/spidev0.0";
static const uint32_t spi_speed = 1000000; // clock freq in Hz
static const uint16_t spi_delay = 0; // us
static const uint8_t spi_bits = 8; // bits per word
uint32_t numModules;
uint8_t *message;
int spi_fd = 0;
void send_message(void)
{
struct spi_ioc_transfer tr = {
.tx_buf = (unsigned long)message,
.rx_buf = (unsigned long)NULL,
.len = 3 * numModules,
.delay_usecs = spi_delay,
.speed_hz = spi_speed,
.bits_per_word = 8
};
if(ioctl(spi_fd, SPI_IOC_MESSAGE(1), &tr) < 0) {
LOG(LVL_ERR, "ws2801: could not send SPI message: %s", strerror(errno));
}
}
int ws2801_init(uint32_t nMod)
{
// Initialize SPI
// We need to have stable data at falling edge of the spi interface (this
// means rising edge at the led strip, as the signal is inverted.
uint8_t spi_mode = SPI_NO_CS; // | SPI_CPOL;
spi_fd = open(spi_dev, O_RDWR);
if(spi_fd < 0) {
LOG(LVL_ERR, "ws2801: cannot open %s: %s", spi_dev, strerror(errno));
return -1;
}
if(ioctl(spi_fd, SPI_IOC_WR_MODE, &spi_mode) == -1) {
LOG(LVL_ERR, "ws2801: cannot change SPI mode: %s", strerror(errno));
return -1;
}
if(ioctl(spi_fd, SPI_IOC_WR_BITS_PER_WORD, &spi_bits) == -1) {
LOG(LVL_ERR, "ws2801: cannot change SPI bits per word: %s", strerror(errno));
return -1;
}
if(ioctl(spi_fd, SPI_IOC_WR_MAX_SPEED_HZ, &spi_speed) == -1) {
LOG(LVL_ERR, "ws2801: cannot change SPI speed: %s", strerror(errno));
return -1;
}
// create the message array
numModules = nMod;
message = malloc(3 * nMod * sizeof(uint8_t));
if(!message) {
LOG(LVL_ERR, "ws2801: could not allocate the message array!");
return -1;
}
return 0;
}
void ws2801_shutdown(void)
{
close(spi_fd);
if(message != NULL) { free(message); message = NULL; }
}
void ws2801_set_colour(uint32_t module, uint8_t red, uint8_t green, uint8_t blue)
{
//message[3*module + 0] = ~red;
//message[3*module + 1] = ~green;
//message[3*module + 2] = ~blue;
message[3*module + 0] = red;
message[3*module + 1] = blue;
message[3*module + 2] = green;
}
void ws2801_send_update(void)
{
send_message();
static const struct timespec sleepval = {0, 550000};
nanosleep(&sleepval, NULL);
}

View file

@ -1,11 +0,0 @@
#ifndef WS2801_H
#define WS2801_H
#include <stdint.h>
int ws2801_init(uint32_t num_modules);
void ws2801_shutdown(void);
void ws2801_set_colour(uint32_t module, uint8_t red, uint8_t green, uint8_t blue);
void ws2801_send_update(void);
#endif // WS2801_H