TLC59711
The TLC59711 by Texas Instruments is a 16 bit 12 channel LED driver. It has a 224 bit stream required for each chip. The stream has 32 bits of configuration data (config + 21 brightness), and 192 bits for the LEDs. It is programmed via SPI or software.
Usage
There is an Adafruit reference library which can be used Adafruit_TLC59711. Note that this library uses bit banging. The data sheet is also helpful.
Speed of TLC59711 vs. WS2811
The TI part here is 224 bits (12 channel), while the WS is 24 bits per chip (3 channel), and for three or four chips it's going to be 96 bits. You might think that Neopixels are faster. Not so. The TI part is able to get faster 1's, and 0's (and the speeds can vary - it's a shift register). The WS2811 however has only two speeds it can run at, and its bits are in fast mode a logic high or low is a combination of two ~300ns + ~500ns signals each. See the video on the side.
Example Code
This code runs on an Olimex PIC32-HMZ144 development board. Note that SPI mode 3 must be used. The SPI mode refers to whether bits are
The SPI clock (SCK) polarity (parameter clock_idle) The SPI data out transmit edge (parameter edge) The SPI "Modes" SPI knows 4 "standard" modes, reflecting the SCK's polarity (CPOL) and the SCK's phase (CPHA). The definition is: SPI Mode CPOL CPHA 0 (or 0,0) 0 0 1 (or 0,1) 0 1 2 (or 1,0) 1 0 3 (or 1,1) 1 1 The meaning is: CPOL: 0 = Clock Idle low level 1 = Clock Idle high level CPHA: 0 = SDO transmit edge (*) active to idle 1 = SDO transmit edge idle to active (*): the transmit edge is the clock edge at which the SDO level changes
Ref: http://www.rosseeld.be/DRO/PIC/SPI_Timing.htm
main.c
// DEVCFG3 // USERID = No Setting #pragma config FMIIEN = OFF // Ethernet RMII/MII Enable (MII Enabled) #pragma config FETHIO = OFF // Ethernet I/O Pin Select (Default Ethernet I/O) #pragma config PGL1WAY = OFF // Permission Group Lock One Way Configuration (Allow only one reconfiguration) #pragma config PMDL1WAY = ON // Peripheral Module Disable Configuration (Allow only one reconfiguration) #pragma config IOL1WAY = ON // Peripheral Pin Select Configuration (Allow only one reconfiguration) #pragma config FUSBIDIO = OFF // USB USBID Selection (Controlled by the USB Module) #pragma config POSCMOD = HS #pragma config FNOSC = SPLL #pragma config FPLLICLK= PLL_POSC #pragma config FPLLIDIV= DIV_2 // 6MHz #pragma config FPLLRNG = RANGE_5_10_MHZ #pragma config FPLLMULT= MUL_66 // 396MHz #pragma config FPLLODIV= DIV_2 // 198MHz #define SYSFREQ (198000000L) #pragma config UPLLFSEL = FREQ_24MHZ // USB PLL Input Frequency Selection (USB PLL input is 24 MHz) #pragma config UPLLEN = OFF #pragma config DMTINTV = WIN_127_128 // DMT Count Window Interval (Window/Interval value is 127/128 counter value) #pragma config WDTPS = PS1048576 // Watchdog Timer Postscaler (1:1048576) #pragma config WDTSPGM = STOP // Watchdog Timer Stop During Flash Programming (WDT stops during Flash programming) #pragma config WINDIS = NORMAL // Watchdog Timer Window Mode (Watchdog Timer is in non-Window mode) #pragma config FWDTEN = OFF // Watchdog Timer Enable (WDT Enabled) #pragma config FWDTWINSZ = WINSZ_25 // Watchdog Timer Window Size (Window size is 25%) #pragma config DMTCNT = DMT31 // Deadman Timer Count Selection (2^31 (2147483648)) #pragma config FDMTEN = OFF // Deadman Timer Enable (Deadman Timer is enabled) // DEVCFG0 #pragma config DEBUG = OFF // Background Debugger Enable (Debugger is disabled) #pragma config JTAGEN = OFF // JTAG Enable (JTAG Port Enabled) #pragma config ICESEL = ICS_PGx2 // ICE/ICD Comm Channel Select (Communicate on PGEC2/PGED2) #pragma config TRCEN = OFF // Trace Enable (Trace features in the CPU are enabled) #pragma config BOOTISA = MIPS32 // Boot ISA Selection (Boot code and Exception code is MIPS32) #pragma config FECCCON = OFF_UNLOCKED // Dynamic Flash ECC Configuration (ECC and Dynamic ECC are disabled (ECCCON bits are writable)) #pragma config FSLEEP = OFF // Flash Sleep Mode (Flash is powered down when the device is in Sleep mode) #pragma config DBGPER = PG_ALL // Debug Mode CPU Access Permission (Allow CPU access to all permission regions) #pragma config EJTAGBEN = NORMAL // EJTAG Boot (Normal EJTAG functionality) // DEVCP0 #pragma config CP = OFF // Code Protect (Protection Disabled) //TLC5971 //0x25 b100101 //0x16 b10110 //17 x 3 bits high (brightness) //16 x 3 bits colour unsigned char __attribute__((coherent))testTI[28] = {0b10010110, //25, then half of 16 0b11011111, //some of 16 (3 bits), and start of brightness (5 bits for brightness) 0xFF,0xFF,//end brightness //for color, 16 bits each 0,0,0,0,0,0,0,0, //color data for 12 channels 0,0,0,0,0,0,0,0, // 0,0,0,0,0,0,0xFF,0xFF};// channels 0 are here //224 / 8 == 28. 4 bytes for config/brightness. 24 bytes for colour. unsigned char __attribute__((coherent))testTI2[28] = {0b10010110, 0b11011111, 0xFF,0xFF, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0xFF,0xFF,0,0,0,0}; void configurePorts (void){ AD1CON1 = 0; // disable ADC //SPI Ports //UEXT / RD15 SCK6, AN33, RPD15, RD15 SPI6CONCLR = _SPI6CON_ON_MASK; ANSELD = 0; ANSELDCLR = _ANSELD_ANSD15_MASK; TRISDbits.TRISD15 = 0; //output RPD15Rbits.RPD15R = 0b0101; //assign SDO1 to RPD15 //RPD15R; SPI6CON } void configureSPI(void){ IEC3bits.SPI1EIE = 0; //disable interrupts IEC3bits.SPI1RXIE = 0; IEC3bits.SPI1TXIE = 0; IEC3bits.SPI1EIE = 0; //enable general error flag (all three get flagged, in practice) IEC3bits.SPI1RXIE = 0; //SPI Priority for Interrupts IPC27bits.SPI1TXIP = 6; //priority IPC27bits.SPI1TXIS = 2; IPC27bits.SPI1RXIP = 7; //priority IPC27bits.SPI1RXIS = 3; rData = SPI1BUF; //enable SPI SPI1CONbits.ON = 0; //stop & reset module SPI1BUF = 0; //clear buffer (rx/tx) SPI1STATbits.SPIROV = 0; //clear rx overflow SPI1CONbits.MSTEN = 1; //master (not slave mode) SPI1CONbits.ON = 1; //enable SPI //Adafruit website (see led docs) remarks spi mode 3 needed so... SPI1CONbits.CKP = 1; SPI1CONbits.SMP = 1;//sample phase (clock "phase" to sample) SPI1CONbits.CKE = 0; //REQUIRED } //non dma spi void SPITransmit(void){ int receivebin[150]; int number = 0; while (number < 28){ //transmit SPI1BUF = testTI[number]; //receive while(SPI1STATbits.SPIRBF == 0); //wait for rx buffer to be full receivebin[number] = SPI1BUF; // goes to /dev/null number++; } }//SPI1STAT//SPI1BUF //non dma spi void SPITransmit2(void){ //Yes, I know this is a duplicate. Just testing. int receivebin[150]; int number = 0; while (number < 28){ //transmit SPI1BUF = testTI2[number]; //receive while(SPI1STATbits.SPIRBE); //wait for buffer receivebin[number] = SPI1BUF; // goes to /dev/null number++; } }//SPI1STAT//SPI1BUF//SPI1CON main(){ configurePorts(); configureSPI(); int cat = 0; while(1){ SPITransmit(); for(cat = 0;cat<400000;cat++){ asm("nop"); } SPITransmit2(); for(cat = 0;cat<400000;cat++){ asm("nop"); } }
I also have prefetch disabled. See https://microchipdeveloper.com/32bit:mz-cache-disable
The example code should alternately blink one, then another LED.
todo: test code
References
|