38 #include <sys/ioctl.h> 41 #include <linux/types.h> 42 #include <linux/spi/spidev.h> 56 #define BUS_TO_PHYS(x) ((x)&~0xC0000000) 58 #define OSC_FREQ 19200000 // crystal frequency 59 #define OSC_FREQ_PI4 54000000 // Pi 4 crystal frequency 63 #define LED_RESET_uS 55 64 #define LED_BIT_COUNT(leds, freq) ((leds * LED_COLOURS * 8 * 3) + ((LED_RESET_uS * \ 65 (freq * 3)) / 1000000)) 68 #define LED_RESET_WAIT_TIME 300 71 #define PWM_BYTE_COUNT(leds, freq) (((((LED_BIT_COUNT(leds, freq) >> 3) & ~0x7) + 4) + 4) * \ 73 #define PCM_BYTE_COUNT(leds, freq) ((((LED_BIT_COUNT(leds, freq) >> 3) & ~0x7) + 4) + 4) 76 #define SYMBOL_HIGH 0x6 // 1 1 0 77 #define SYMBOL_LOW 0x4 // 1 0 0 80 #define SYMBOL_HIGH_INV 0x1 // 0 0 1 81 #define SYMBOL_LOW_INV 0x3 // 0 1 1 127 if (clock_gettime(CLOCK_MONOTONIC_RAW, &t) != 0) {
131 return (uint64_t) t.tv_sec * 1000000 + t.tv_nsec / 1000;
280 uint32_t offset = (uint8_t *)virt - mbox->
virt_addr;
295 volatile pwm_t *pwm = device->
pwm;
296 volatile cm_clk_t *cm_clk = device->
cm_clk;
319 volatile pcm_t *pcm = device->
pcm;
320 volatile cm_clk_t *cm_clk = device->
cm_clk;
343 volatile dma_t *dma = device->
dma;
344 volatile dma_cb_t *dma_cb = device->
dma_cb;
345 volatile pwm_t *pwm = device->
pwm;
346 volatile cm_clk_t *cm_clk = device->
cm_clk;
348 uint32_t freq = ws2811->
freq;
352 const uint32_t rpi_type = rpi_hw->
type;
405 dma_cb->txfr_len = byte_count;
407 dma_cb->nextconbk = 0;
425 volatile dma_t *dma = device->
dma;
426 volatile dma_cb_t *dma_cb = device->
dma_cb;
427 volatile pcm_t *pcm = device->
pcm;
428 volatile cm_clk_t *cm_clk = device->
cm_clk;
431 uint32_t freq = ws2811->
freq;
435 const uint32_t rpi_type = rpi_hw->
type;
478 dma_cb->txfr_len = byte_count;
480 dma_cb->nextconbk = 0;
499 volatile dma_t *dma = device->
dma;
500 volatile pcm_t *pcm = device->
pcm;
509 dma->conblk_ad = dma_cb_addr;
576 volatile uint32_t *pxl_raw = (uint32_t *)ws2811->
device->
pxl_raw;
584 int i, wordpos = chan;
586 for (i = 0; i < wordcount; i++)
588 pxl_raw[wordpos] = 0x0;
604 volatile uint32_t *pxl_raw = (uint32_t *)ws2811->
device->
pxl_raw;
609 for (i = 0; i < wordcount; i++)
653 if (device && (device->
spi_fd > 0))
668 if (gpionum == 18 || gpionum == 12) {
672 if (gpionum2 == 0 || gpionum2 == 13 || gpionum2 == 19) {
676 else if (gpionum == 21 || gpionum == 31) {
679 else if (gpionum == 10) {
683 fprintf(stderr,
"gpionum %d not allowed\n", gpionum);
696 int gpionums_B1[] = { 10, 18, 21 };
697 int gpionums_B2[] = { 10, 18, 31 };
698 int gpionums_40p[] = { 10, 12, 18, 21};
702 hwver = rpi_hw->
hwver & 0x0000ffff;
706 for ( i = 0; i < (int)(
sizeof(gpionums_B1) /
sizeof(gpionums_B1[0])); i++)
708 if (gpionums_B1[i] == gpionum) {
714 else if (hwver >= 0x0004 && hwver <= 0x000f)
716 for ( i = 0; i < (int)(
sizeof(gpionums_B2) /
sizeof(gpionums_B2[0])); i++)
718 if (gpionums_B2[i] == gpionum) {
724 else if (hwver >= 0x010)
731 if ((gpionum == 13) || (gpionum == 19))
740 for ( i = 0; i < (int)(
sizeof(gpionums_40p) /
sizeof(gpionums_40p[0])); i++)
742 if (gpionums_40p[i] == gpionum) {
748 fprintf(stderr,
"Gpio %d is illegal for LED channel 0\n", gpionum);
756 static uint8_t bits = 8;
757 uint32_t speed = ws2811->
freq * 3;
762 spi_fd = open(
"/dev/spidev0.0", O_RDWR);
764 fprintf(stderr,
"Cannot open /dev/spidev0.0. spi_bcm2835 module not loaded?\n");
765 return WS2811_ERROR_SPI_SETUP;
770 if (ioctl(spi_fd, SPI_IOC_WR_MODE, &mode) < 0)
772 return WS2811_ERROR_SPI_SETUP;
774 if (ioctl(spi_fd, SPI_IOC_RD_MODE, &mode) < 0)
776 return WS2811_ERROR_SPI_SETUP;
780 if (ioctl(spi_fd, SPI_IOC_WR_BITS_PER_WORD, &bits) < 0)
782 return WS2811_ERROR_SPI_SETUP;
784 if (ioctl(spi_fd, SPI_IOC_RD_BITS_PER_WORD, &bits) < 0)
786 return WS2811_ERROR_SPI_SETUP;
790 if (ioctl(spi_fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed) < 0)
792 return WS2811_ERROR_SPI_SETUP;
794 if (ioctl(spi_fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed) < 0)
796 return WS2811_ERROR_SPI_SETUP;
814 return WS2811_ERROR_SPI_SETUP;
824 return WS2811_ERROR_OUT_OF_MEMORY;
835 channel->
gamma = malloc(
sizeof(uint8_t) * 256);
837 for(x = 0; x < 256; x++){
838 channel->
gamma[x] = x;
852 return WS2811_ERROR_OUT_OF_MEMORY;
856 return WS2811_SUCCESS;
862 struct spi_ioc_transfer tr;
864 memset(&tr, 0,
sizeof(
struct spi_ioc_transfer));
869 ret = ioctl(ws2811->
device->
spi_fd, SPI_IOC_MESSAGE(1), &tr);
872 fprintf(stderr,
"Can't send spi message");
873 return WS2811_ERROR_SPI_TRANSFER;
876 return WS2811_SUCCESS;
903 return WS2811_ERROR_HW_NOT_SUPPORTED;
910 return WS2811_ERROR_OUT_OF_MEMORY;
917 return WS2811_ERROR_ILLEGAL_GPIO;
944 return WS2811_ERROR_MAILBOX_DEVICE;
951 return WS2811_ERROR_OUT_OF_MEMORY;
958 return WS2811_ERROR_MEM_LOCK;
968 return WS2811_ERROR_MMAP;
988 return WS2811_ERROR_OUT_OF_MEMORY;
1001 channel->
gamma = malloc(
sizeof(uint8_t) * 256);
1003 for(x = 0; x < 256; x++){
1004 channel->
gamma[x] = x;
1028 memset((dma_cb_t *)device->
dma_cb, 0,
sizeof(dma_cb_t));
1037 return WS2811_ERROR_MAP_REGISTERS;
1045 return WS2811_ERROR_GPIO_INIT;
1055 return WS2811_ERROR_PWM_SETUP;
1064 return WS2811_ERROR_PCM_SETUP;
1069 return WS2811_SUCCESS;
1081 volatile pcm_t *pcm = ws2811->
device->
pcm;
1108 volatile dma_t *dma = ws2811->
device->
dma;
1112 return WS2811_SUCCESS;
1123 fprintf(stderr,
"DMA Error: %08x\n", dma->debug);
1124 return WS2811_ERROR_DMA;
1127 return WS2811_SUCCESS;
1146 uint32_t protocol_time = 0;
1147 static uint64_t previous_timestamp = 0;
1149 bitpos = (driver_mode ==
SPI ? 7 : 31);
1157 const int scale = (channel->
brightness & 0xff) + 1;
1158 uint8_t array_size = 3;
1167 const uint32_t channel_protocol_time = channel->
count * array_size * 8 * 1.25;
1170 if (channel_protocol_time > protocol_time)
1172 protocol_time = channel_protocol_time;
1175 for (i = 0; i < channel->
count; i++)
1179 channel->
gamma[(((channel->
leds[i] >> channel->
rshift) & 0xff) * scale) >> 8],
1180 channel->
gamma[(((channel->
leds[i] >> channel->
gshift) & 0xff) * scale) >> 8],
1181 channel->
gamma[(((channel->
leds[i] >> channel->
bshift) & 0xff) * scale) >> 8],
1182 channel->
gamma[(((channel->
leds[i] >> channel->
wshift) & 0xff) * scale) >> 8],
1185 for (j = 0; j < array_size; j++)
1187 for (k = 7; k >= 0; k--)
1193 if (color[j] & (1 << k))
1199 for (l = 2; l >= 0; l--)
1201 uint32_t *wordptr = &((uint32_t *)pxl_raw)[wordpos];
1202 volatile uint8_t *byteptr = &pxl_raw[bytepos];
1204 if (driver_mode ==
SPI)
1206 *byteptr &= ~(1 << bitpos);
1207 if (symbol & (1 << l))
1209 *byteptr |= (1 << bitpos);
1214 *wordptr &= ~(1 << bitpos);
1215 if (symbol & (1 << l))
1217 *wordptr |= (1 << bitpos);
1224 if (driver_mode ==
SPI)
1232 wordpos += (driver_mode ==
PWM ? 2 : 1);
1243 if ((ret =
ws2811_wait(ws2811)) != WS2811_SUCCESS)
1250 uint64_t time_diff = current_timestamp - previous_timestamp;
1257 if (driver_mode !=
SPI)
1275 const int index = -state;
1278 if (index < (
int)(
sizeof(ret_state_str) /
sizeof(ret_state_str[0])))
1280 return ret_state_str[index];
1296 for(counter = 0; counter < 256; counter++)
1299 channel->
gamma[counter] = (gamma_factor > 0)? (
int)(pow((
float)counter / (
float)255.00, gamma_factor) * 255.00 + 0.5) : counter;
const rpi_hw_t * rpi_hw_detect(void)
#define RPI_PCM_MODE_FSLEN(val)
struct ws2811_device * device
#define RPI_DMA_CS_ACTIVE
static void stop_pcm(ws2811_t *ws2811)
void ws2811_cleanup(ws2811_t *ws2811)
static int setup_pcm(ws2811_t *ws2811)
static int gpio_init(ws2811_t *ws2811)
#define CM_CLK_DIV_PASSWD
#define RPI_PWM_CTL_MODE2
#define RPI_DMA_CS_PRIORITY(val)
void mbox_close(int file_desc)
uint32_t mem_lock(int file_desc, uint32_t handle)
ws2811_channel_t channel[RPI_PWM_CHANNELS]
static ws2811_return_t spi_transfer(ws2811_t *ws2811)
#define RPI_PWM_DMAC_PANIC(val)
#define RPI_DMA_TI_SRC_INC
static uint64_t get_microsecond_timestamp()
void pcm_raw_init(ws2811_t *ws2811)
#define RPI_PWM_CTL_MODE1
static int set_driver_mode(ws2811_t *ws2811, int gpionum)
#define WS2811_RETURN_STATES(X)
#define RPI_PWM_CTL_POLA1
#define RPI_DMA_TI_WAIT_RESP
void pwm_raw_init(ws2811_t *ws2811)
#define SK6812_SHIFT_WMASK
uint32_t dmanum_to_offset(int dmanum)
#define LED_RESET_WAIT_TIME
#define WS2811_RETURN_STATES_STRING(state, name, str)
#define RPI_PCM_MODE_FLEN(val)
static int check_hwver_and_gpionum(ws2811_t *ws2811)
volatile cm_clk_t * cm_clk
volatile uint8_t * pxl_raw
#define RPI_PWM_DMAC_DREQ(val)
struct ws2811_device ws2811_device_t
void * mapmem(uint32_t base, uint32_t size, const char *mem_dev)
#define RPI_PCM_TXC_CH1EN
volatile dma_cb_t * dma_cb
ws2811_return_t ws2811_init(ws2811_t *ws2811)
uint64_t render_wait_time
#define RPI_DMA_TI_NO_WIDE_BURSTS
void * unmapmem(void *addr, uint32_t size)
#define RPI_PCM_TXC_CH1WID(val)
#define RPI_PWM_CTL_USEF1
uint32_t mem_alloc(int file_desc, uint32_t size, uint32_t align, uint32_t flags)
static void stop_pwm(ws2811_t *ws2811)
int pcm_pin_alt(int pcmfun, int pinnum)
ws2811_return_t ws2811_render(ws2811_t *ws2811)
#define RPI_PWM_CTL_PWEN1
#define RPI_PCM_DREQ_TX_PANIC(val)
ws2811_return_t ws2811_wait(ws2811_t *ws2811)
#define RPI_HWVER_TYPE_PI4
static uint32_t addr_to_bus(ws2811_device_t *device, const volatile void *virt)
#define RPI_PWM_CTL_CLRF1
static int map_registers(ws2811_t *ws2811)
static int setup_pwm(ws2811_t *ws2811)
const char * ws2811_get_return_t_str(const ws2811_return_t state)
void ws2811_fini(ws2811_t *ws2811)
#define RPI_DMA_TI_PERMAP(val)
uint32_t mem_unlock(int file_desc, uint32_t handle)
static void gpio_function_set(volatile gpio_t *gpio, uint8_t pin, uint8_t function)
#define RPI_PCM_TXC_CH1WEX
#define PWM_BYTE_COUNT(leds, freq)
static int max_channel_led_count(ws2811_t *ws2811)
#define RPI_PWM_CTL_PWEN2
#define RPI_PCM_DREQ_TX(val)
#define RPI_PWM_DMAC_ENAB
static void unmap_registers(ws2811_t *ws2811)
#define RPI_PWM_CTL_USEF2
#define PCM_BYTE_COUNT(leds, freq)
#define RPI_DMA_CS_PANIC_PRIORITY(val)
#define RPI_DMA_TI_DEST_DREQ
#define RPI_PCM_TXC_CH1POS(val)
static ws2811_return_t spi_init(ws2811_t *ws2811)
#define RPI_DMA_CS_WAIT_OUTSTANDING_WRITES
static void dma_start(ws2811_t *ws2811)
uint32_t mem_free(int file_desc, uint32_t handle)
#define RPI_PWM_CTL_POLA2
#define CM_CLK_CTL_SRC_OSC
int pwm_pin_alt(int chan, int pinnum)
#define CM_CLK_DIV_DIVI(val)
void ws2811_set_custom_gamma_factor(ws2811_t *ws2811, double gamma_factor)
#define CM_CLK_CTL_PASSWD
struct videocore_mbox videocore_mbox_t