Hello,
I am trying to send data to the TLC5940 using SPI on a MEGA. I found an example that works, but the GSCLK pin is pulse in the main loop. I'm trying to use a CTC hardware toggle to pulse the pin and then load the data in between clock cycles. I have this method working without SPI, but whn I add the SPI it stops uploading the data.
Here is the broken code
#include <stdint.h>
// Definition of interrupt names
#include <avr/interrupt.h>
// ISR interrupt service routine
#include <avr/io.h>
// TLC5940 pin definitions
// PWM PIN 11
#define GSCLK_DDR DDRB
#define GSCLK_PORT PORTB
#define GSCLK_PIN PB5
// MOSI PIN 51
#define SIN_DDR DDRB
#define SIN_PORT PORTB
#define SIN_PIN PB2
// SCK PIN 52
#define SCLK_DDR DDRB
#define SCLK_PORT PORTB
#define SCLK_PIN PB1
// SS PIN 53
#define BLANK_DDR DDRL
#define BLANK_PORT PORTL
#define BLANK_PIN PL0
#define DCPRG_DDR DDRC
#define DCPRG_PORT PORTC
#define DCPRG_PIN PC4
#define VPRG_DDR DDRC
#define VPRG_PORT PORTC
#define VPRG_PIN PC7
#define XLAT_DDR DDRC
#define XLAT_PORT PORTC
#define XLAT_PIN PC1
#define DATAIN 50 //MISO - not used, but part of builtin SPI
#define SLAVESELECT 53//ss
#define TLC5940_N 1
// Macros
#define setOutput(ddr, pin) ((ddr) |= (1 << (pin)))
#define setLow(port, pin) ((port) &= ~(1 << (pin)))
#define setHigh(port, pin) ((port) |= (1 << (pin)))
#define outputState(port, pin) ((port) & (1 << (pin)))
#if (12 * TLC5940_N > 255)
#define dcData_t uint16_t
#else
#define dcData_t uint8_t
#endif
#if (24 * TLC5940_N > 255)
#define gsData_t uint16_t
#else
#define gsData_t uint8_t
#endif
#define dcDataSize ((dcData_t)12 * TLC5940_N)
#define gsDataSize ((gsData_t)24 * TLC5940_N)
// Array for Dot Correction Data
uint8_t dcData[12 * TLC5940_N] = {
0b11111111,
0b11111111,
0b11111111,
0b11111111,
0b11111111,
0b11111111,
0b11111111,
0b11111111,
0b11111111,
0b11111111,
0b11111111,
0b11111111,
};
// Array for GreyScale Data
uint8_t gsData[24 * TLC5940_N] = {
0b11111111,
0b11111111,
0b11111111,
0b11111111,
0b11111111,
0b11111111,
0b11111111,
0b11111111,
0b11111111,
0b00000000,
0b10000000,
0b00010000,
0b00000010,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00001111,
0b11111111,
};
inline void pulse(uint8_t port, uint8_t pin)
{
setHigh(port, pin);
setLow(port, pin);
}
void TLC5940_Init(void) {
setOutput(GSCLK_DDR, GSCLK_PIN);
setOutput(SCLK_DDR, SCLK_PIN);
setOutput(DCPRG_DDR, DCPRG_PIN);
setOutput(VPRG_DDR, VPRG_PIN);
setOutput(XLAT_DDR, XLAT_PIN);
setOutput(BLANK_DDR, BLANK_PIN);
setOutput(SIN_DDR, SIN_PIN);
pinMode(DATAIN, INPUT);
pinMode(SLAVESELECT,OUTPUT);
digitalWrite(SLAVESELECT,HIGH); //disable device
setLow(GSCLK_PORT, GSCLK_PIN);
setLow(SCLK_PORT, SCLK_PIN);
setLow(DCPRG_PORT, DCPRG_PIN);
setHigh(VPRG_PORT, VPRG_PIN);
setLow(XLAT_PORT, XLAT_PIN);
setHigh(BLANK_PORT, BLANK_PIN);
// Enable SPI, Master, set clock rate fck/2
SPCR = (1 << SPE) | (1 << MSTR);
SPSR = (1 << SPI2X);
byte clr;
clr=SPSR;
clr=SPDR;
delay(10);
// Dont need to call sei(); because Arduino already does this
// SET TIMERS
// Clear TIMER1 Reg back to default
TCCR1A = B00000000;
TCCR1B = B00000000;
// Enable timer 1 Compare Output channel A in toggle mode
TCCR1A |= (1 << COM1A0);
// Configure timer 1 for CTC mode
TCCR1B |= (1 << WGM12);
// Set up timer to fCPU (no Prescale) = 16Mhz/1 = 16Mhz
TCCR1B |= (1 << CS10);
// Set CTC compare value to pulse PIN at 8Mhz
// (1 / Target Frequency) / (1 / Timer Clock Frequency) - 1
// (1/16000000)/(1/16000000)-1 = 0 = 16Mhz
// Full period of PIN 11 pulse requires 2 clock ticks (HIGH, LOW)
// So = f/2 = 16Mhz/2 = 8Mhz
OCR1A = 0;
// Clear TIMER3 Reg back to default
TCCR3A = B00000000;
TCCR3B = B00000000;
// Configure timer 3 for CTC mode
TCCR3B |= (1 << WGM32);
// Set up timer to fCPU (no prescale) = 16Mhz/1 = 16Mhz
TCCR3B |= (1 << CS30);
// Set CTC compare value to 4096 full clock periods so 4096 @ 8Mhz
// Hence (GSCLK value @ 16Mhz * 2 to bring it down to 8Mhz) -1
OCR3A = (4096*2) - 1;
// Enable Timer/Counter3 Compare Match A interrupt
TIMSK3 |= (1 << OCIE3A);
}
void TLC5940_ClockInDC(void) {
setHigh(DCPRG_PORT, DCPRG_PIN);
setHigh(VPRG_PORT, VPRG_PIN);
for (dcData_t i = 0; i < dcDataSize; i++) {
// Start transmission
SPDR = dcData[i];
// Wait for transmission complete
while (!(SPSR & (1 << SPIF))){};
}
pulse(XLAT_PORT, XLAT_PIN);
}
ISR(TIMER3_COMPA_vect) {
static uint8_t xlatNeedsPulse = 0;
setHigh(BLANK_PORT, BLANK_PIN);
if (outputState(VPRG_PORT, VPRG_PIN)) {
setLow(VPRG_PORT, VPRG_PIN);
if (xlatNeedsPulse) {
pulse(XLAT_PORT, XLAT_PIN);
xlatNeedsPulse = 0;
}
pulse(SCLK_PORT, SCLK_PIN);
}
else if (xlatNeedsPulse) {
pulse(XLAT_PORT, XLAT_PIN);
xlatNeedsPulse = 0;
}
setLow(BLANK_PORT, BLANK_PIN);
// Below this we have 4096 cycles to shift in the data for the next cycle
for (gsData_t i = 0; i < gsDataSize; i++) {
SPDR = gsData[i];
while (!(SPSR & (1 << SPIF))){};
}
xlatNeedsPulse = 1;
}
void setup(){
Serial.begin(9600);
TLC5940_Init();
//*** for now keep this out and just hold DCPROG LOW using the default EEPROM value
TLC5940_ClockInDC();
}
void loop() {
}
and here is the post I found with working SPI but no hardware CTC pin toggle
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1200704490
Thanks for any thoughts, and please feel free to point out anything I could clean up in my code
always trying to learn to code little better.