I've spent most of today trying to get this to work to no avail unfortunately. What I have done however, is use joan's excellent c file as the basis for a bare minimum example, where I simply build each of the 3 LED driver registers, setting each LED to the colour red (RGB(65535, 0, 0)), and then writing out the three registers.
I've added a printf component for each of the 28 bytes of data for each of the 3 registers, so ensure the register data I build is correct. So far I've been through each bit against the TLC5971 LED driver datasheet and it's correct. Bear in mind the exact same register values were working successfully using sysfs yesterday, so I'd have been quite surprised if they weren't correct.
This is the c file I'm currently running on my RPi2:
Code: Select all
/*
minimal_gpio.c
2016-04-30
Public Domain
*/
/*
gcc -o minimal_gpio minimal_gpio.c
sudo ./minimal_gpio
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdint.h>
#include <string.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#define GPIO_BASE (piPeriphBase + 0x200000)
#define GPIO_LEN 0xB4
#define GPSET0 7
#define GPSET1 8
#define GPCLR0 10
#define GPCLR1 11
#define GPLEV0 13
#define GPLEV1 14
static volatile uint32_t *gpioReg = MAP_FAILED;
char packets[3][28];
#define PI_BANK (gpio>>5)
#define PI_BIT (1<<(gpio&0x1F))
/* gpio modes. */
//#define PI_INPUT 0
//#define PI_OUTPUT 1
void gpioSetMode(unsigned gpio, unsigned mode)
{
int reg, shift;
reg = gpio/10;
shift = (gpio%10) * 3;
gpioReg[reg] = (gpioReg[reg] & ~(7<<shift)) | (mode<<shift);
}
void gpioWrite()
{
//char packets[3][28];
int p;
for (p = 0; p < 3; p = p + 1) {
long packetHeader = 0b10010111000 << (32-6-5);
unsigned char ledBrightnessWorking = 0xFF;
ledBrightnessWorking >>= 1;
packetHeader |= ledBrightnessWorking;
packetHeader |= (long)ledBrightnessWorking << 7;
packetHeader |= (long)ledBrightnessWorking << 7*2;
packets[p][0] = packetHeader >> 8*3;
packets[p][1] = packetHeader >> 8*2;
packets[p][2] = packetHeader >> 8;
packets[p][3] = packetHeader;
}
int m;
int i;
int value;
for (m = 0; m < 3; m = m + 1) {
for (i = 0; i < 12; i = i + 1) {
if (i == 2 || i == 5 || i == 8 || i == 11) {
value = 65535;
} else {
value = 0;
}
packets[m][i*2 + 4] = value >> 8;
packets[m][i*2 + 5] = value;
}
int j;
int k;
int bitData;
unsigned gpio;
for (j = 0; j < 28; j = j + 1) {
for (k = 0; k < 8; k = k + 1) {
bitData = !!(packets[m][j] & (1 << (7 - k)));
if (bitData == 0) {
*(gpioReg + GPCLR0 + PI_BANK) = PI_BIT;
} else {
*(gpioReg + GPSET0 + PI_BANK) = PI_BIT;
}
gpio = 6;
*(gpioReg + GPSET0 + PI_BANK) = PI_BIT;
*(gpioReg + GPCLR0 + PI_BANK) = PI_BIT;
}
}
int x;
for (x = 0; x < 28; x = x + 1) {
printf("%d: %02X \n", x, packets[m][x]);
}
}
}
static uint32_t * initMapMem(int fd, uint32_t addr, uint32_t len)
{
return (uint32_t *) mmap(0, len,
PROT_READ|PROT_WRITE|PROT_EXEC,
MAP_SHARED|MAP_LOCKED,
fd, addr);
}
int gpioInitialise(void)
{
int fd;
static volatile uint32_t piModel = 2;
int chars = 6;
static volatile uint32_t piPeriphBase = 0x3F000000;
static volatile uint32_t piBusAddr = 0xC0000000;
fd = open("/dev/mem", O_RDWR | O_SYNC) ;
if (fd < 0)
{
fprintf(stderr,
"This program needs root privileges. Try using sudo\n");
return -1;
}
gpioReg = initMapMem(fd, GPIO_BASE, GPIO_LEN);
close(fd);
if ((gpioReg == MAP_FAILED)) {
fprintf(stderr,
"Bad, mmap failed\n");
return -1;
}
return 0;
}
main()
{
int i;
if (gpioInitialise() < 0) return 1;
gpioSetMode(5, 1);
gpioSetMode(6, 1);
//while(1) {
// gpioWrite();
//usleep(10000);
//}
gpioWrite();
}
For context, the packet structure for each of the 3 LED drivers is as follows:
6 bits Write Command (100101) - 5 bits Function Command (11000) - 21 bits Brightness Control (1111111 1111111 1111111) - 192 bits GS Data (B3 (16 bits), G3 (16 bits), R3 (16 bits), ... , B0 (16 bits), G0 (16 bits), R0 (16 bits)).
When running this example, the first 4 LEDs (all on LED driver 1) turn on with the colour Green. It doesn't matter what I set the register values to (colour or brightness), only these 4 LEDs turn on, and they are always green.
The printf statements in the code above align with the datasheet structure exactly, so at this point I can only think that I'm using the mmap process incorrectly.