sk6812d/src/ws2801.c

108 lines
2.4 KiB
C

#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);
}