Use SPI to send commands to the WS2801 strip
This commit is contained in:
parent
2437c7b18d
commit
9b9f6ee3d6
2
Makefile
2
Makefile
|
@ -7,7 +7,7 @@ LD=gcc
|
||||||
|
|
||||||
# default build configuration
|
# default build configuration
|
||||||
# "make BUILD=release" does a release build
|
# "make BUILD=release" does a release build
|
||||||
BUILD:=release
|
BUILD:=debug
|
||||||
|
|
||||||
# basic build flags configuration
|
# basic build flags configuration
|
||||||
CFLAGS+=-std=c99 -Wall -pedantic -Wno-long-long -D_POSIX_C_SOURCE=20120607L -D_FILE_OFFSET_BITS=64
|
CFLAGS+=-std=c99 -Wall -pedantic -Wno-long-long -D_POSIX_C_SOURCE=20120607L -D_FILE_OFFSET_BITS=64
|
||||||
|
|
125
src/ws2801.c
125
src/ws2801.c
|
@ -3,76 +3,77 @@
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
#include <wiringPi.h>
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <linux/spi/spidev.h>
|
||||||
|
|
||||||
|
//#include <wiringPi.h>
|
||||||
|
|
||||||
#include "../include/logger.h"
|
#include "../include/logger.h"
|
||||||
#include "../include/ws2801.h"
|
#include "../include/ws2801.h"
|
||||||
|
|
||||||
#define WS2801_CLK_GPIO 17
|
static const char *spi_dev = "/dev/spidev0.0";
|
||||||
#define WS2801_DAT_GPIO 18
|
static const uint32_t spi_speed = 250000; // clock freq in Hz
|
||||||
|
static const uint16_t spi_delay = 0; // us
|
||||||
|
static const uint8_t spi_bits = 8; // bits per word
|
||||||
|
|
||||||
// the interface rpi->ws2801 is active low
|
|
||||||
#define BUS_HIGH LOW
|
|
||||||
#define BUS_LOW HIGH
|
|
||||||
|
|
||||||
uint8_t *modRed = NULL;
|
|
||||||
uint8_t *modGreen = NULL;
|
|
||||||
uint8_t *modBlue = NULL;
|
|
||||||
uint8_t numModules;
|
uint8_t numModules;
|
||||||
|
uint8_t *message;
|
||||||
|
|
||||||
void busy_wait(void)
|
int spi_fd = 0;
|
||||||
|
|
||||||
|
void send_message(void)
|
||||||
{
|
{
|
||||||
static const struct timespec bitsleep = {0, 1000};
|
struct spi_ioc_transfer tr = {
|
||||||
nanosleep(&bitsleep, NULL);
|
.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));
|
||||||
}
|
}
|
||||||
|
|
||||||
void send_bit(uint8_t value)
|
|
||||||
{
|
|
||||||
digitalWrite(WS2801_DAT_GPIO, (value ? BUS_HIGH : BUS_LOW));
|
|
||||||
|
|
||||||
digitalWrite(WS2801_CLK_GPIO, BUS_LOW);
|
|
||||||
busy_wait();
|
|
||||||
|
|
||||||
// rising edge at clock
|
|
||||||
digitalWrite(WS2801_CLK_GPIO, BUS_HIGH);
|
|
||||||
busy_wait();
|
|
||||||
}
|
|
||||||
|
|
||||||
void send_commit_condition(void)
|
|
||||||
{
|
|
||||||
digitalWrite(WS2801_DAT_GPIO, BUS_LOW);
|
|
||||||
digitalWrite(WS2801_CLK_GPIO, BUS_LOW);
|
|
||||||
}
|
|
||||||
|
|
||||||
void send_byte(uint8_t byte)
|
|
||||||
{
|
|
||||||
for(int i = 0; i <= 7; i++) {
|
|
||||||
send_bit(byte & 0x1);
|
|
||||||
byte >>= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void send_colour(uint8_t red, uint8_t green, uint8_t blue)
|
|
||||||
{
|
|
||||||
send_byte(red);
|
|
||||||
send_byte(green);
|
|
||||||
send_byte(blue);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int ws2801_init(uint8_t nMod)
|
int ws2801_init(uint8_t nMod)
|
||||||
{
|
{
|
||||||
if(wiringPiSetupGpio() == -1) {
|
// Initialize SPI
|
||||||
LOG(LVL_FATAL, "ws2801: wiringPi setup failed: %s", strerror(errno));
|
// 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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
numModules = nMod;
|
if(ioctl(spi_fd, SPI_IOC_WR_MODE, &spi_mode) == -1) {
|
||||||
modRed = malloc(nMod * sizeof(uint8_t));
|
LOG(LVL_ERR, "ws2801: cannot change SPI mode: %s", strerror(errno));
|
||||||
modGreen = malloc(nMod * sizeof(uint8_t));
|
return -1;
|
||||||
modBlue = malloc(nMod * sizeof(uint8_t));
|
}
|
||||||
|
|
||||||
if(!modRed || !modGreen || !modBlue) {
|
if(ioctl(spi_fd, SPI_IOC_WR_BITS_PER_WORD, &spi_bits) == -1) {
|
||||||
LOG(LVL_ERR, "ws2801: could not allocate all colour arrays!");
|
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 -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,25 +82,21 @@ int ws2801_init(uint8_t nMod)
|
||||||
|
|
||||||
void ws2801_shutdown(void)
|
void ws2801_shutdown(void)
|
||||||
{
|
{
|
||||||
if(modRed != NULL) { free(modRed); modRed = NULL; }
|
close(spi_fd);
|
||||||
if(modGreen != NULL) { free(modGreen); modGreen = NULL; }
|
|
||||||
if(modBlue != NULL) { free(modBlue); modBlue = NULL; }
|
if(message != NULL) { free(message); message = NULL; }
|
||||||
}
|
}
|
||||||
|
|
||||||
void ws2801_set_colour(uint8_t module, uint8_t red, uint8_t green, uint8_t blue)
|
void ws2801_set_colour(uint8_t module, uint8_t red, uint8_t green, uint8_t blue)
|
||||||
{
|
{
|
||||||
modRed[module] = red;
|
message[3*module + 0] = ~red;
|
||||||
modGreen[module] = green;
|
message[3*module + 1] = ~green;
|
||||||
modBlue[module] = blue;
|
message[3*module + 2] = ~blue;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ws2801_send_update(void)
|
void ws2801_send_update(void)
|
||||||
{
|
{
|
||||||
for(uint8_t i = 0; i < numModules; i++) {
|
send_message();
|
||||||
send_colour(modRed[i], modGreen[i], modBlue[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
send_commit_condition();
|
|
||||||
|
|
||||||
static const struct timespec sleepval = {0, 550000};
|
static const struct timespec sleepval = {0, 550000};
|
||||||
nanosleep(&sleepval, NULL);
|
nanosleep(&sleepval, NULL);
|
||||||
|
|
Loading…
Reference in a new issue