Hi everyone!
I am trying to write an add-on for the TLC5940 library for Teensy 4.x. I have already used this library for the Teensy 3.6 platform and am now migrating to the Teensy 4.0 platform.
I am not good at working with registers and it is still very difficult for me to understand counters, timers and interrupts.
Now I manage to light up the LEDs at the setup () stage. But none of this makes sense without interrupts.
Here is my code, which I integrated into the TLC5940 standard library:
I ask to help me with interrupts for Teensy 4.0, and to be more specific, for the timer QuadTimer3 Module0 (see //TODO for T4 in code)
I think it will be useful for the whole community.
Best regards.
I am trying to write an add-on for the TLC5940 library for Teensy 4.x. I have already used this library for the Teensy 3.6 platform and am now migrating to the Teensy 4.0 platform.
I am not good at working with registers and it is still very difficult for me to understand counters, timers and interrupts.
Now I manage to light up the LEDs at the setup () stage. But none of this makes sense without interrupts.
Here is my code, which I integrated into the TLC5940 standard library:
Code:
/****************************************** LIBRARIES ******************************************/
#include <Arduino.h>
#//include <SPI.h>
#include <math.h>
/****************************************** DEFINITIONS & MACROS ******************************************/
#define NUM_TLCS 2
#define CHANNELS 16 * NUM_TLCS
#define CHNBITS CHANNELS * 12
#define CHNBYTES CHNBITS / 8
#define TLC_CHANNEL_TYPE uint8_t
#define F_BUS 75000000 // 30000000 для F_CPU 180-120MHz; 24000000 для F_CPU 96-48MHz; 18000000 для F_CPU 72MHz; 12000000 для F_CPU 24MHz
#define TLC_PORT_RES 12 // bitness port
#define FREQ (F_BUS/pow(2, TLC_PORT_RES))*2 // frequency port
#define GS_VAL_INIT 333 // from 0 to 1023
#define PORT_DUTY GS_VAL_INIT*4 // GS_VALUE/4GS_VALUE/4 - 1024 transferred to 4096
#define GS_VALUE_TEST 10 //Gray Scale value to test
#define SIN_BB 6 //FlexPWM2 Module2 // pin 6, 9
#define SCLK_BB 7 //FlexPWM1 Module3 // pin 7, 8, 25
#define XLAT 19 //QuadTimer3 Module0 // pin 19
#define BLANK 18 //QuadTimer3 Module1 // pin 18
#define GSCLK 5 //FlexPWM2 Module1 // pin 5
/*-------------------------------------------- Pin functions --------------------------------------------*/
#define pulse_pin(port, pin) digitalWriteFast(pin, HIGH); digitalWriteFast(pin, LOW)
#define set_pin(port, pin) digitalWriteFast(pin, HIGH)
#define clear_pin(port, pin) digitalWriteFast(pin, LOW)
#define output_pin(ddr, pin) pinMode(pin, OUTPUT)
#define pullup_pin(ddr, port, pin) pinMode(pin, INPUT_PULLUP)
/** GSCLK pin setup and PWM output*/
#define gsclk_pin_setup(pin, freq, res) analogWriteFrequency(pin, freq); analogWriteResolution(res);
#define gsclk_pin_pulse(pin, duty) analogWrite(pin, duty);
/** Enables the output of XLAT pulses */ //TODO for T4
//#define enable_XLAT_pulses() CORE_PIN3_CONFIG = PORT_PCR_MUX(3)|PORT_PCR_DSE|PORT_PCR_SRE
//#define disable_XLAT_pulses() CORE_PIN3_CONFIG = PORT_PCR_MUX(1)|PORT_PCR_DSE|PORT_PCR_SRE
#define enable_XLAT_pulses() digitalWriteFast(XLAT, HIGH); delayMicroseconds(1); digitalWriteFast(XLAT, LOW); // TODO timer on millis???
#define disable_XLAT_pulses() digitalWriteFast(XLAT, HIGH); delayMicroseconds(1); digitalWriteFast(XLAT, LOW); // TODO timer on millis???
/**Enables the QuadTimer3_0 Overflow interrupt, which will fire after an XLAT pulse */ //TODO for T4
//#define set_XLAT_interrupt() FTM1_SC = FTM_SC_CLKS(1) | FTM_SC_CPWMS | FTM_SC_TOIE | (FTM1_SC & FTM_SC_PS(7))
//#define clear_XLAT_interrupt() FTM1_SC = FTM_SC_CLKS(1) | FTM_SC_CPWMS | (FTM1_SC & FTM_SC_PS(7))
#define set_XLAT_interrupt() // attachInterrupt (pin, func, mode)
#define clear_XLAT_interrupt() // detachInterrupt(pin);
/****************************************** FUNCTIONS & VARIABLES ******************************************/
//Variables
uint8_t tlc_GSData[NUM_TLCS * 24];
uint16_t initialValue = GS_VAL_INIT;
uint16_t value = GS_VALUE_TEST;
volatile uint8_t tlc_needXLAT;
static uint8_t firstGSInput;
//BitBang SPI
/** Initializes the SPI module */
void tlc_shift8_init(void) {
output_pin(SIN_BB, SIN_BB); // SIN as output
output_pin(SCLK_BB, SCLK_BB); // SCLK as output
clear_pin(SCLK_BB, SCLK_BB); // SCLK to LOW
}
/** Shifts a byte out, MSB first */
void tlc_shift8(uint8_t byte) {
for (uint8_t bit = 0x80; bit; bit >>= 1) {
if (bit & byte) {
set_pin(SIN_BB, SIN_BB);
} else {
clear_pin(SIN_BB, SIN_BB);
}
pulse_pin(SCLK_BB, SCLK_BB);
}
}
//Interrupts //TODO for T4
////////////////////////////////////////////
/*
// Interrupt called after an XLAT pulse to prevent more XLAT pulses.
static inline void Tlc5940_interrupt(void)
{
disable_XLAT_pulses();
clear_XLAT_interrupt();
tlc_needXLAT = 0;
if (tlc_onUpdateFinished) {
sei();
tlc_onUpdateFinished();
}
}
void ftm1_isr(void)
{
uint32_t sc = FTM1_SC;
if (sc & 0x80) FTM1_SC = sc & 0x7F;
Tlc5940_interrupt();
}
*/
///////////////////////////////////////////
volatile void (*tlc_onUpdateFinished)(void);
/** Interrupt called after an XLAT pulse to prevent more XLAT pulses. */
static inline void Tlc5940_interrupt(void)
{
disable_XLAT_pulses();
clear_XLAT_interrupt();
tlc_needXLAT = 0;
if (tlc_onUpdateFinished) {
sei();
tlc_onUpdateFinished();
}
}
void my_isr(void)
{
FLEXPWM1_SM3STS = FLEXPWM_SMSTS_RF; //TODO QTIMER3_0
Tlc5940_interrupt();
}
//Functions TLCs
void setAll(uint16_t value) {
uint8_t firstByte = value >> 4;
uint8_t secondByte = (value << 4) | (value >> 8);
uint8_t *p = tlc_GSData;
while (p < tlc_GSData + NUM_TLCS * 24) {
*p++ = firstByte;
*p++ = secondByte;
*p++ = (uint8_t)value;
}
}
void set(TLC_CHANNEL_TYPE channel, uint16_t value) {
TLC_CHANNEL_TYPE index8 = (NUM_TLCS * 16 - 1) - channel;
uint8_t *index12p = tlc_GSData + ((((uint16_t)index8) * 3) >> 1);
if (index8 & 1) { // starts in the middle
// first 4 bits intact | 4 top bits of value
*index12p = (*index12p & 0xF0) | (value >> 8);
// 8 lower bits of value
*(++index12p) = value & 0xFF;
} else { // starts clean
// 8 upper bits of value
*(index12p++) = value >> 4;
// 4 lower bits of value | last 4 bits intact
*index12p = ((uint8_t)(value << 4)) | (*index12p & 0xF);
}
}
uint8_t update(void) {
if (tlc_needXLAT) {
return 1;
}
disable_XLAT_pulses();
if (firstGSInput) {
// adds an extra SCLK pulse unless we've just set dot-correction data
firstGSInput = 0;
} else {
pulse_pin(SCLK_BB, SCLK_BB);
uint8_t *p = tlc_GSData;
while (p < tlc_GSData + NUM_TLCS * 24) {
tlc_shift8(*p++);
tlc_shift8(*p++);
tlc_shift8(*p++);
}
tlc_needXLAT = 1;
enable_XLAT_pulses();
set_XLAT_interrupt();
return 0;
}
}
/****************************************** SETUP ******************************************/
void setup() {
/****************************************** INIT ******************************************/
output_pin(BLANK, BLANK);
output_pin(XLAT, XLAT);
output_pin(GSCLK, GSCLK);
//output_pin(SCLK_BB, SCLK_BB);
//output_pin(SIN_BB, SIN_BB);
set_pin(BLANK, BLANK); // leave blank high (until the timers start)
tlc_shift8_init();
setAll(initialValue);
update();
disable_XLAT_pulses();
clear_XLAT_interrupt();
tlc_needXLAT = 0;
pulse_pin(XLAT, XLAT);
//PWM setup
gsclk_pin_setup (GSCLK, FREQ, TLC_PORT_RES);
//BLANK_pulse
set_pin(BLANK, BLANK);
delayMicroseconds(1);
clear_pin(BLANK, BLANK);
delayMicroseconds(1);
//GSCLK_output
gsclk_pin_pulse (GSCLK, PORT_DUTY);
delayMicroseconds(2);
//Interrupt TODO: must be here
set_XLAT_interrupt();
update();
}
void loop() {
//setAll(GS_VALUE_TEST);
//for (int channel = 0; channel < 32; channel++) { // TODO 32 #define NUM_CHNLS NUM_TLCS*16
// set(channel, GS_VALUE_TEST); // Setting the brightness of all channels from 0 to 1023 (10 bit ADC)
//}
//update();
}
I ask to help me with interrupts for Teensy 4.0, and to be more specific, for the timer QuadTimer3 Module0 (see //TODO for T4 in code)
I think it will be useful for the whole community.
Best regards.