mirror of
https://github.com/PaulStoffregen/Tlc5940
synced 2025-09-27 18:12:22 +02:00
Merge 7b5a398459
into 54c4315c84
This commit is contained in:
@@ -1,3 +1,11 @@
|
|||||||
|
Fork of https://github.com/PaulStoffregen/Tlc5940 with ESP32 support
|
||||||
|
|
||||||
|
Tested on ESP32, but should work on ESP32-S2, S3, etc. with no or minimal mods
|
||||||
|
Requires the following board support package in Arduino IDE (Tools -> Board -> Boards Manager…): esp32 by Espressif Systems
|
||||||
|
|
||||||
|
DOT Correction can be set for each channel individually.
|
||||||
|
Animation doesn't work as PROGMEM snippets for ESP32 were not finished.
|
||||||
|
|
||||||
# Tlc5940 Library
|
# Tlc5940 Library
|
||||||
|
|
||||||
16 channel PWM LED driver based on the Texas Instruments TLC5940 chip.
|
16 channel PWM LED driver based on the Texas Instruments TLC5940 chip.
|
||||||
|
261
Tlc5940.cpp
261
Tlc5940.cpp
@@ -23,6 +23,15 @@
|
|||||||
#include "pinouts/pin_functions.h"
|
#include "pinouts/pin_functions.h"
|
||||||
|
|
||||||
|
|
||||||
|
int sin_pin;
|
||||||
|
int sout_pin;
|
||||||
|
int sclk_pin;
|
||||||
|
int xlat_pin;
|
||||||
|
int blank_pin;
|
||||||
|
int gsclk_pin;
|
||||||
|
int vprg_pin;
|
||||||
|
int xerr_pin;
|
||||||
|
|
||||||
/** This will be true (!= 0) if update was just called and the data has not
|
/** This will be true (!= 0) if update was just called and the data has not
|
||||||
been latched in yet. */
|
been latched in yet. */
|
||||||
volatile uint8_t tlc_needXLAT;
|
volatile uint8_t tlc_needXLAT;
|
||||||
@@ -49,6 +58,9 @@ volatile void (*tlc_onUpdateFinished)(void);
|
|||||||
the array is the same as the format of the TLC's serial interface. */
|
the array is the same as the format of the TLC's serial interface. */
|
||||||
uint8_t tlc_GSData[NUM_TLCS * 24];
|
uint8_t tlc_GSData[NUM_TLCS * 24];
|
||||||
|
|
||||||
|
/** Packed DOT Correction data, 12 bytes (16 * 6 bits) per TLC. */
|
||||||
|
uint8_t tlc_DCData[NUM_TLCS * 12];
|
||||||
|
|
||||||
/** Don't add an extra SCLK pulse after switching from dot-correction mode. */
|
/** Don't add an extra SCLK pulse after switching from dot-correction mode. */
|
||||||
static uint8_t firstGSInput;
|
static uint8_t firstGSInput;
|
||||||
|
|
||||||
@@ -85,6 +97,37 @@ void ftm1_isr(void)
|
|||||||
Tlc5940_interrupt();
|
Tlc5940_interrupt();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#elif defined (ARDUINO_ARCH_ESP32)
|
||||||
|
portMUX_TYPE TLC5940_timerMux = portMUX_INITIALIZER_UNLOCKED;
|
||||||
|
// volatile int TLC5940_xlat_enabled = 0;
|
||||||
|
// volatile int TLC5940_interrupt_enabled = 0;
|
||||||
|
|
||||||
|
void IRAM_ATTR TLC5940_onTimer()
|
||||||
|
{
|
||||||
|
portENTER_CRITICAL_ISR(&TLC5940_timerMux);
|
||||||
|
int xlat_enabled = Tlc.TLC5940_xlat_enabled;
|
||||||
|
int interrupt_enabled = Tlc.TLC5940_interrupt_enabled;
|
||||||
|
portEXIT_CRITICAL_ISR(&TLC5940_timerMux);
|
||||||
|
|
||||||
|
// BLANK, XLAT
|
||||||
|
set_pin(blank_pin);
|
||||||
|
if (xlat_enabled)
|
||||||
|
{
|
||||||
|
set_pin(xlat_pin);
|
||||||
|
clear_pin(xlat_pin);
|
||||||
|
}
|
||||||
|
clear_pin(blank_pin);
|
||||||
|
|
||||||
|
if (interrupt_enabled)
|
||||||
|
Tlc5940_interrupt();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined (ARDUINO_ARCH_ESP32)
|
||||||
|
// SPI to send gray-scale data
|
||||||
|
const uint32_t TLC5940_SPI_CLK = 8000000; // 8MHz
|
||||||
|
SPIClass* TLC5940_vspi = NULL;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/** \defgroup ReqVPRG_ENABLED Functions that Require VPRG_ENABLED
|
/** \defgroup ReqVPRG_ENABLED Functions that Require VPRG_ENABLED
|
||||||
@@ -107,20 +150,52 @@ void ftm1_isr(void)
|
|||||||
zeros, or whatever initialValue is set to and the Timers will start.
|
zeros, or whatever initialValue is set to and the Timers will start.
|
||||||
\param initialValue = 0, optional parameter specifing the inital startup
|
\param initialValue = 0, optional parameter specifing the inital startup
|
||||||
value */
|
value */
|
||||||
void Tlc5940::init(uint16_t initialValue)
|
void Tlc5940::init( uint16_t initialValue, int sin, int sout, int sclk, int xlat, int blank, int gsclk, int vprg, int xerr )
|
||||||
{
|
{
|
||||||
/* Pin Setup */
|
/* Pin Setup */
|
||||||
|
#if defined (ARDUINO_ARCH_ESP32)
|
||||||
|
sin_pin = sin;
|
||||||
|
sout_pin = sout;
|
||||||
|
sclk_pin = sclk;
|
||||||
|
xlat_pin = xlat;
|
||||||
|
blank_pin = blank;
|
||||||
|
gsclk_pin = gsclk;
|
||||||
|
vprg_pin = vprg;
|
||||||
|
xerr_pin = xerr;
|
||||||
|
|
||||||
|
output_pin(xlat_pin);
|
||||||
|
output_pin(blank_pin);
|
||||||
|
clear_pin(xlat_pin);
|
||||||
|
set_pin(blank_pin); // start with BLANK
|
||||||
|
#if VPRG_ENABLED
|
||||||
|
if (vprg_pin >= 0)
|
||||||
|
{
|
||||||
|
output_pin(vprg_pin);
|
||||||
|
clear_pin(vprg_pin); // LOW: GS-reg, HIGH: DC-reg
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if XERR_ENABLED
|
||||||
|
if (xerr_pin >= 0)
|
||||||
|
{
|
||||||
|
pullup_pin(xerr_pin);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
set_pin(blank_pin); // leave blank high (until the timers start)
|
||||||
|
#elif
|
||||||
output_pin(XLAT_DDR, XLAT_PIN);
|
output_pin(XLAT_DDR, XLAT_PIN);
|
||||||
output_pin(BLANK_DDR, BLANK_PIN);
|
output_pin(BLANK_DDR, BLANK_PIN);
|
||||||
output_pin(GSCLK_DDR, GSCLK_PIN);
|
output_pin(GSCLK_DDR, GSCLK_PIN);
|
||||||
#if VPRG_ENABLED
|
|
||||||
|
#if VPRG_ENABLED
|
||||||
output_pin(VPRG_DDR, VPRG_PIN);
|
output_pin(VPRG_DDR, VPRG_PIN);
|
||||||
clear_pin(VPRG_PORT, VPRG_PIN); // grayscale mode (VPRG low)
|
clear_pin(VPRG_PORT, VPRG_PIN); // grayscale mode (VPRG low)
|
||||||
#endif
|
#endif
|
||||||
#if XERR_ENABLED
|
#if XERR_ENABLED
|
||||||
pullup_pin(XERR_DDR, XERR_PORT, XERR_PIN); // XERR as input, enable pull-up resistor
|
pullup_pin(XERR_DDR, XERR_PORT, XERR_PIN); // XERR as input, enable pull-up resistor
|
||||||
|
#endif
|
||||||
|
|
||||||
|
set_pin(BLANK_PORT, BLANK_PIN); // leave blank high (until the timers start)
|
||||||
#endif
|
#endif
|
||||||
set_pin(BLANK_PORT, BLANK_PIN); // leave blank high (until the timers start)
|
|
||||||
|
|
||||||
tlc_shift8_init();
|
tlc_shift8_init();
|
||||||
|
|
||||||
@@ -129,7 +204,11 @@ void Tlc5940::init(uint16_t initialValue)
|
|||||||
disable_XLAT_pulses();
|
disable_XLAT_pulses();
|
||||||
clear_XLAT_interrupt();
|
clear_XLAT_interrupt();
|
||||||
tlc_needXLAT = 0;
|
tlc_needXLAT = 0;
|
||||||
pulse_pin(XLAT_PORT, XLAT_PIN);
|
#if defined (ARDUINO_ARCH_ESP32)
|
||||||
|
pulse_pin(xlat_pin);
|
||||||
|
#elif
|
||||||
|
pulse_pin(XLAT_PORT, XLAT_PIN);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* Timer Setup */
|
/* Timer Setup */
|
||||||
@@ -218,6 +297,28 @@ void Tlc5940::init(uint16_t initialValue)
|
|||||||
NVIC_ENABLE_IRQ(IRQ_FTM1);
|
NVIC_ENABLE_IRQ(IRQ_FTM1);
|
||||||
CORE_PIN4_CONFIG = PORT_PCR_MUX(3)|PORT_PCR_DSE|PORT_PCR_SRE;
|
CORE_PIN4_CONFIG = PORT_PCR_MUX(3)|PORT_PCR_DSE|PORT_PCR_SRE;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#elif defined(ARDUINO_ARCH_ESP32)
|
||||||
|
const uint8_t TIMER_NUM = 0; // hardware timer number
|
||||||
|
const uint16_t TIMER_DIV = 80; // timer divider to make 1MHz from 80MHz
|
||||||
|
const uint64_t TIMER_ALM = 2050; // interrupt every 2.050ms
|
||||||
|
hw_timer_t* TLC5940_timer = NULL;
|
||||||
|
|
||||||
|
// start timer
|
||||||
|
TLC5940_timer = timerBegin(TIMER_NUM, TIMER_DIV, true); // increment mode
|
||||||
|
timerAttachInterrupt(TLC5940_timer, &TLC5940_onTimer, true); // edge mode
|
||||||
|
timerAlarmWrite(TLC5940_timer, TIMER_ALM, true); // auto-reload mode
|
||||||
|
timerAlarmEnable(TLC5940_timer);
|
||||||
|
|
||||||
|
// LEDC for GS(Gray-scale) clock
|
||||||
|
const uint8_t TLC5940_LEDC_CHN = 0; // LEDC channel
|
||||||
|
const double TLC5940_LEDC_FRQ = 2e6; // LEDC frequency 2MHz
|
||||||
|
const uint8_t TLC5940_LEDC_RSL = 5; // LEDC resolution 5bit = 32
|
||||||
|
const uint32_t TLC5940_LEDC_DTY = 8; // LEDC duty 25% .. 8 / 32
|
||||||
|
|
||||||
|
ledcSetup(TLC5940_LEDC_CHN, TLC5940_LEDC_FRQ, TLC5940_LEDC_RSL);
|
||||||
|
ledcAttachPin(gsclk_pin, TLC5940_LEDC_CHN);
|
||||||
|
ledcWrite(TLC5940_LEDC_CHN, TLC5940_LEDC_DTY);
|
||||||
#endif
|
#endif
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
@@ -249,7 +350,14 @@ uint8_t Tlc5940::update(void)
|
|||||||
// adds an extra SCLK pulse unless we've just set dot-correction data
|
// adds an extra SCLK pulse unless we've just set dot-correction data
|
||||||
firstGSInput = 0;
|
firstGSInput = 0;
|
||||||
} else {
|
} else {
|
||||||
|
#if defined (ARDUINO_ARCH_ESP32)
|
||||||
|
TLC5940_vspi->end(); // Release SCLK pin
|
||||||
|
output_pin(sclk_pin);
|
||||||
|
pulse_pin(sclk_pin);
|
||||||
|
TLC5940_vspi->begin(sclk_pin, sout_pin, sin_pin, -1);
|
||||||
|
#elif
|
||||||
pulse_pin(SCLK_PORT, SCLK_PIN);
|
pulse_pin(SCLK_PORT, SCLK_PIN);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
uint8_t *p = tlc_GSData;
|
uint8_t *p = tlc_GSData;
|
||||||
while (p < tlc_GSData + NUM_TLCS * 24) {
|
while (p < tlc_GSData + NUM_TLCS * 24) {
|
||||||
@@ -319,12 +427,85 @@ void Tlc5940::setAll(uint16_t value)
|
|||||||
|
|
||||||
#if VPRG_ENABLED
|
#if VPRG_ENABLED
|
||||||
|
|
||||||
|
static inline uint8_t byte_mask(uint8_t bit_ofs, uint8_t bit_num)
|
||||||
|
{
|
||||||
|
uint8_t result = 0;
|
||||||
|
uint8_t num = bit_num;
|
||||||
|
for (uint8_t i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
if (i >= bit_ofs && num)
|
||||||
|
{
|
||||||
|
result |= (uint8_t)(1 << i);
|
||||||
|
num--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/** \addtogroup ReqVPRG_ENABLED
|
/** \addtogroup ReqVPRG_ENABLED
|
||||||
From the \ref CoreFunctions "Core Functions":
|
From the \ref CoreFunctions "Core Functions":
|
||||||
- \link Tlc5940::setAllDC Tlc.setAllDC(uint8_t value(0-63)) \endlink - sets
|
- \link Tlc5940::setAllDC Tlc.setAllDC(uint8_t value(0-63)) \endlink - sets
|
||||||
all the dot correction data to value */
|
all the dot correction data to value */
|
||||||
/* @{ */
|
/* @{ */
|
||||||
|
|
||||||
|
/** Shifts in the data from the DOT Correction data array, #tlc_DCData.
|
||||||
|
*/
|
||||||
|
void Tlc5940::updateDC(void)
|
||||||
|
{
|
||||||
|
tlc_dcModeStart();
|
||||||
|
|
||||||
|
uint8_t *p = tlc_DCData;
|
||||||
|
while (p < tlc_DCData + NUM_TLCS * 12) {
|
||||||
|
tlc_shift8(*p++);
|
||||||
|
tlc_shift8(*p++);
|
||||||
|
tlc_shift8(*p++);
|
||||||
|
}
|
||||||
|
|
||||||
|
// dot correction data latch
|
||||||
|
#if defined (ARDUINO_ARCH_ESP32)
|
||||||
|
pulse_pin(xlat_pin);
|
||||||
|
#elif
|
||||||
|
pulse_pin(XLAT_PORT, XLAT_PIN);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
tlc_dcModeStop();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Sets channel to value in the DOT Correction data array, #tlc_DCData.
|
||||||
|
\param channel (0 to #NUM_TLCS * 16 - 1). OUT0 of the first TLC is
|
||||||
|
channel 0, OUT0 of the next TLC is channel 16, etc.
|
||||||
|
\param value (0-63). The DOT Correction value, 63 is maximum.
|
||||||
|
\see get */
|
||||||
|
void Tlc5940::setDC(TLC_CHANNEL_TYPE channel, uint8_t value)
|
||||||
|
{
|
||||||
|
TLC_CHANNEL_TYPE index8 = (NUM_TLCS * 16 - 1) - channel;
|
||||||
|
uint8_t *index6p = tlc_DCData + ((((uint16_t)index8) * 3) >> 2);
|
||||||
|
int8_t offset = ((((uint16_t)index8) * 3) % 4) * 2;
|
||||||
|
|
||||||
|
value &= 0x3F;
|
||||||
|
|
||||||
|
*index6p = (*index6p & ~byte_mask(offset, min(8 - offset, 6))) | (value << offset);
|
||||||
|
*(index6p+1) = (*(index6p+1) & ~byte_mask(0, max(offset - 2, 0))) | (value >> min(8 - offset, 6));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Gets the current DOT Correction value for a channel
|
||||||
|
\param channel (0 to #NUM_TLCS * 16 - 1). OUT0 of the first TLC is
|
||||||
|
channel 0, OUT0 of the next TLC is channel 16, etc.
|
||||||
|
\returns current DOT Correction value (0 - 63) for channel
|
||||||
|
\see set */
|
||||||
|
uint8_t Tlc5940::getDC(TLC_CHANNEL_TYPE channel)
|
||||||
|
{
|
||||||
|
TLC_CHANNEL_TYPE index8 = (NUM_TLCS * 16 - 1) - channel;
|
||||||
|
uint8_t *index6p = tlc_DCData + ((((uint16_t)index8) * 3) >> 2);
|
||||||
|
int8_t offset = ((((uint16_t)index8) * 3) % 4) * 2;
|
||||||
|
uint8_t result = 0;
|
||||||
|
|
||||||
|
result |= (*index6p & byte_mask(offset, min(8 - offset, 6))) >> offset;
|
||||||
|
result |= (*(index6p+1) & byte_mask(0, max(offset - 2, 0))) << min(8 - offset, 6);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/** Sets the dot correction for all channels to value. The dot correction
|
/** Sets the dot correction for all channels to value. The dot correction
|
||||||
value correspondes to maximum output current by
|
value correspondes to maximum output current by
|
||||||
\f$\displaystyle I_{OUT_n} = I_{max} \times \frac{DCn}{63} \f$
|
\f$\displaystyle I_{OUT_n} = I_{max} \times \frac{DCn}{63} \f$
|
||||||
@@ -335,20 +516,15 @@ void Tlc5940::setAll(uint16_t value)
|
|||||||
\param value (0-63) */
|
\param value (0-63) */
|
||||||
void Tlc5940::setAllDC(uint8_t value)
|
void Tlc5940::setAllDC(uint8_t value)
|
||||||
{
|
{
|
||||||
tlc_dcModeStart();
|
|
||||||
|
|
||||||
uint8_t firstByte = value << 2 | value >> 4;
|
uint8_t firstByte = value << 2 | value >> 4;
|
||||||
uint8_t secondByte = value << 4 | value >> 2;
|
uint8_t secondByte = value << 4 | value >> 2;
|
||||||
uint8_t thirdByte = value << 6 | value;
|
uint8_t thirdByte = value << 6 | value;
|
||||||
|
uint8_t *p = tlc_DCData;
|
||||||
for (TLC_CHANNEL_TYPE i = 0; i < NUM_TLCS * 12; i += 3) {
|
while (p < tlc_DCData + NUM_TLCS * 12) {
|
||||||
tlc_shift8(firstByte);
|
*p++ = firstByte;
|
||||||
tlc_shift8(secondByte);
|
*p++ = secondByte;
|
||||||
tlc_shift8(thirdByte);
|
*p++ = thirdByte;
|
||||||
}
|
}
|
||||||
pulse_pin(XLAT_PORT, XLAT_PIN);
|
|
||||||
|
|
||||||
tlc_dcModeStop();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* @} */
|
/* @} */
|
||||||
@@ -361,13 +537,28 @@ void Tlc5940::setAllDC(uint8_t value)
|
|||||||
\returns 1 if a TLC is reporting an error, 0 otherwise. */
|
\returns 1 if a TLC is reporting an error, 0 otherwise. */
|
||||||
uint8_t Tlc5940::readXERR(void)
|
uint8_t Tlc5940::readXERR(void)
|
||||||
{
|
{
|
||||||
return ((XERR_PINS & _BV(XERR_PIN)) == 0);
|
#if defined (ARDUINO_ARCH_ESP32)
|
||||||
|
return (digitalRead(xerr_pin) == LOW);
|
||||||
|
#elif
|
||||||
|
return ((XERR_PINS & _BV(XERR_PIN)) == 0);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* @} */
|
/* @} */
|
||||||
|
|
||||||
|
#if defined (ARDUINO_ARCH_ESP32)
|
||||||
|
void Tlc5940::XLAT_mode(int val)
|
||||||
|
{
|
||||||
|
TLC5940_xlat_enabled = val;
|
||||||
|
}
|
||||||
|
void Tlc5940::INT_mode(int val)
|
||||||
|
{
|
||||||
|
TLC5940_interrupt_enabled = val;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#if DATA_TRANSFER_MODE == TLC_BITBANG
|
#if DATA_TRANSFER_MODE == TLC_BITBANG
|
||||||
|
|
||||||
/** Sets all the bit-bang pins to output */
|
/** Sets all the bit-bang pins to output */
|
||||||
@@ -393,6 +584,27 @@ void tlc_shift8(uint8_t byte)
|
|||||||
|
|
||||||
#elif DATA_TRANSFER_MODE == TLC_SPI
|
#elif DATA_TRANSFER_MODE == TLC_SPI
|
||||||
|
|
||||||
|
#if defined (ARDUINO_ARCH_ESP32)
|
||||||
|
|
||||||
|
/** Initializes the SPI module */
|
||||||
|
|
||||||
|
void tlc_shift8_init(void)
|
||||||
|
{
|
||||||
|
TLC5940_vspi = new SPIClass(VSPI);
|
||||||
|
TLC5940_vspi->begin(sclk_pin, sout_pin, sin_pin, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Shifts out a byte, MSB first */
|
||||||
|
void tlc_shift8(uint8_t byte)
|
||||||
|
{
|
||||||
|
TLC5940_vspi->beginTransaction(SPISettings(TLC5940_SPI_CLK, MSBFIRST, SPI_MODE0));
|
||||||
|
TLC5940_vspi->transfer(byte);
|
||||||
|
TLC5940_vspi->endTransaction();
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif
|
||||||
|
|
||||||
|
|
||||||
/** Initializes the SPI module to double speed (f_osc / 2) */
|
/** Initializes the SPI module to double speed (f_osc / 2) */
|
||||||
void tlc_shift8_init(void)
|
void tlc_shift8_init(void)
|
||||||
{
|
{
|
||||||
@@ -414,7 +626,7 @@ void tlc_shift8(uint8_t byte)
|
|||||||
while (!(SPSR & _BV(SPIF)))
|
while (!(SPSR & _BV(SPIF)))
|
||||||
; // wait for transmission complete
|
; // wait for transmission complete
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if VPRG_ENABLED
|
#if VPRG_ENABLED
|
||||||
@@ -425,13 +637,22 @@ void tlc_dcModeStart(void)
|
|||||||
disable_XLAT_pulses(); // ensure that no latches happen
|
disable_XLAT_pulses(); // ensure that no latches happen
|
||||||
clear_XLAT_interrupt(); // (in case this was called right after update)
|
clear_XLAT_interrupt(); // (in case this was called right after update)
|
||||||
tlc_needXLAT = 0;
|
tlc_needXLAT = 0;
|
||||||
set_pin(VPRG_PORT, VPRG_PIN); // dot correction mode
|
#if defined (ARDUINO_ARCH_ESP32)
|
||||||
|
set_pin(vprg_pin); // dot correction mode
|
||||||
|
#elif
|
||||||
|
set_pin(VPRG_PORT, VPRG_PIN); // dot correction mode
|
||||||
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Switches back to grayscale mode. */
|
/** Switches back to grayscale mode. */
|
||||||
void tlc_dcModeStop(void)
|
void tlc_dcModeStop(void)
|
||||||
{
|
{
|
||||||
clear_pin(VPRG_PORT, VPRG_PIN); // back to grayscale mode
|
#if defined (ARDUINO_ARCH_ESP32)
|
||||||
|
clear_pin(vprg_pin); // back to grayscale mode
|
||||||
|
#elif
|
||||||
|
clear_pin(VPRG_PORT, VPRG_PIN); // back to grayscale mode
|
||||||
|
#endif
|
||||||
firstGSInput = 1;
|
firstGSInput = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
40
Tlc5940.h
40
Tlc5940.h
@@ -25,6 +25,16 @@
|
|||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include "tlc_config.h"
|
#include "tlc_config.h"
|
||||||
|
|
||||||
|
#define min(a,b) \
|
||||||
|
({ __typeof__ (a) _a = (a); \
|
||||||
|
__typeof__ (b) _b = (b); \
|
||||||
|
_a < _b ? _a : _b; })
|
||||||
|
|
||||||
|
#define max(a,b) \
|
||||||
|
({ __typeof__ (a) _a = (a); \
|
||||||
|
__typeof__ (b) _b = (b); \
|
||||||
|
_a > _b ? _a : _b; })
|
||||||
|
|
||||||
#if defined(__AVR__)
|
#if defined(__AVR__)
|
||||||
#ifdef TLC_ATMEGA_8_H
|
#ifdef TLC_ATMEGA_8_H
|
||||||
|
|
||||||
@@ -71,24 +81,43 @@
|
|||||||
extern volatile uint8_t tlc_needXLAT;
|
extern volatile uint8_t tlc_needXLAT;
|
||||||
extern volatile void (*tlc_onUpdateFinished)(void);
|
extern volatile void (*tlc_onUpdateFinished)(void);
|
||||||
extern uint8_t tlc_GSData[NUM_TLCS * 24];
|
extern uint8_t tlc_GSData[NUM_TLCS * 24];
|
||||||
|
extern uint8_t tlc_DCData[NUM_TLCS * 12];
|
||||||
|
|
||||||
/** The main Tlc5940 class for the entire library. An instance of this class
|
/** The main Tlc5940 class for the entire library. An instance of this class
|
||||||
will be preinstantiated as Tlc. */
|
will be preinstantiated as Tlc. */
|
||||||
class Tlc5940
|
class Tlc5940
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void init(uint16_t initialValue = 0);
|
void init( uint16_t initialValue = 0,
|
||||||
|
int sin = DEFAULT_TLC_MOSI_PIN,
|
||||||
|
int sout = DEFAULT_TLC_MISO_PIN,
|
||||||
|
int sclk = DEFAULT_TLC_SCK_PIN,
|
||||||
|
int xlat = DEFAULT_XLAT_PIN,
|
||||||
|
int blank = DEFAULT_BLANK_PIN,
|
||||||
|
int gsclk = DEFAULT_GSCLK_PIN,
|
||||||
|
int vprg = DEFAULT_VPRG_PIN,
|
||||||
|
int xerr = DEFAULT_XERR_PIN );
|
||||||
void clear(void);
|
void clear(void);
|
||||||
uint8_t update(void);
|
uint8_t update(void);
|
||||||
void set(TLC_CHANNEL_TYPE channel, uint16_t value);
|
void set(TLC_CHANNEL_TYPE channel, uint16_t value);
|
||||||
uint16_t get(TLC_CHANNEL_TYPE channel);
|
uint16_t get(TLC_CHANNEL_TYPE channel);
|
||||||
void setAll(uint16_t value);
|
void setAll(uint16_t value);
|
||||||
#if VPRG_ENABLED
|
#if VPRG_ENABLED
|
||||||
void setAllDC(uint8_t value);
|
void updateDC(void);
|
||||||
|
void setDC(TLC_CHANNEL_TYPE channel, uint8_t value);
|
||||||
|
uint8_t getDC(TLC_CHANNEL_TYPE channel);
|
||||||
|
void setAllDC(uint8_t value);
|
||||||
#endif
|
#endif
|
||||||
#if XERR_ENABLED
|
#if XERR_ENABLED
|
||||||
uint8_t readXERR(void);
|
uint8_t readXERR(void);
|
||||||
#endif
|
#endif
|
||||||
|
#if defined (ARDUINO_ARCH_ESP32)
|
||||||
|
volatile int TLC5940_xlat_enabled = 0;
|
||||||
|
volatile int TLC5940_interrupt_enabled = 0;
|
||||||
|
|
||||||
|
void XLAT_mode(int val);
|
||||||
|
void INT_mode(int val);
|
||||||
|
#endif
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -103,5 +132,12 @@ void tlc_dcModeStop(void);
|
|||||||
// for the preinstantiated Tlc variable.
|
// for the preinstantiated Tlc variable.
|
||||||
extern Tlc5940 Tlc;
|
extern Tlc5940 Tlc;
|
||||||
|
|
||||||
|
#if defined (ARDUINO_ARCH_ESP32)
|
||||||
|
#define set_XLAT_interrupt() Tlc.XLAT_mode(1)
|
||||||
|
#define clear_XLAT_interrupt() Tlc.XLAT_mode(0)
|
||||||
|
#define enable_XLAT_pulses() Tlc.INT_mode(1)
|
||||||
|
#define disable_XLAT_pulses() Tlc.INT_mode(0)
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
51
pinouts/Espressif_ESP32.h
Normal file
51
pinouts/Espressif_ESP32.h
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
/* Copyright (c) 2009 by Alex Leone <acleone ~AT~ gmail.com>
|
||||||
|
|
||||||
|
This file is part of the Arduino TLC5940 Library.
|
||||||
|
|
||||||
|
The Arduino TLC5940 Library is free software: you can redistribute it
|
||||||
|
and/or modify it under the terms of the GNU General Public License as
|
||||||
|
published by the Free Software Foundation, either version 3 of the
|
||||||
|
License, or (at your option) any later version.
|
||||||
|
|
||||||
|
The Arduino TLC5940 Library is distributed in the hope that it will be
|
||||||
|
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with The Arduino TLC5940 Library. If not, see
|
||||||
|
<http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#ifndef ESPRESSIF_ESP32_H
|
||||||
|
#define ESPRESSIF_ESP32_H
|
||||||
|
|
||||||
|
/** \file
|
||||||
|
Default pins for the ESP32. Don't edit these. All
|
||||||
|
changeable pins are defined through Tlc5940::init */
|
||||||
|
|
||||||
|
/** MOSI (ESP32 pin 33) -> SIN (TLC pin 26) */
|
||||||
|
#define DEFAULT_TLC_MOSI_PIN 33
|
||||||
|
|
||||||
|
/** MISO (ESP32 pin 25) -> SOUT (TLC pin 17) */
|
||||||
|
#define DEFAULT_TLC_MISO_PIN 25
|
||||||
|
|
||||||
|
/** SCK (ESP32 pin 32) -> SCLK (TLC pin 25) */
|
||||||
|
#define DEFAULT_TLC_SCK_PIN 32
|
||||||
|
|
||||||
|
/** XLAT (ESP32 pin 27) -> XLAT (TLC pin 24) */
|
||||||
|
#define DEFAULT_XLAT_PIN 27
|
||||||
|
|
||||||
|
/** BLANK (ESP32 pin 23) -> BLANK (TLC pin 23) */
|
||||||
|
#define DEFAULT_BLANK_PIN 23
|
||||||
|
|
||||||
|
/** GSCLK (ESP32 pin 12) -> GSCLK (TLC pin 18) */
|
||||||
|
#define DEFAULT_GSCLK_PIN 12
|
||||||
|
|
||||||
|
/** VPRG (Disabled by default) -> VPRG (TLC pin 27) */
|
||||||
|
#define DEFAULT_VPRG_PIN -1
|
||||||
|
|
||||||
|
/** XERR (Disabled by default) -> XERR (TLC pin 16) */
|
||||||
|
#define DEFAULT_XERR_PIN -1
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@@ -125,6 +125,11 @@
|
|||||||
/* Teensy 4.0, 4.1, MicroMod */
|
/* Teensy 4.0, 4.1, MicroMod */
|
||||||
#include "Teensy_IMXRT.h"
|
#include "Teensy_IMXRT.h"
|
||||||
|
|
||||||
|
#elif defined (ARDUINO_ARCH_ESP32)
|
||||||
|
|
||||||
|
#include "Espressif_ESP32.h"
|
||||||
|
#include <SPI.h>
|
||||||
|
|
||||||
#else
|
#else
|
||||||
#error "Unknown Chip!"
|
#error "Unknown Chip!"
|
||||||
#endif
|
#endif
|
||||||
|
@@ -19,6 +19,12 @@
|
|||||||
#define clear_pin(port, pin) digitalWriteFast(pin, LOW)
|
#define clear_pin(port, pin) digitalWriteFast(pin, LOW)
|
||||||
#define output_pin(ddr, pin) pinMode(pin, OUTPUT)
|
#define output_pin(ddr, pin) pinMode(pin, OUTPUT)
|
||||||
#define pullup_pin(ddr, port, pin) pinMode(pin, INPUT_PULLUP)
|
#define pullup_pin(ddr, port, pin) pinMode(pin, INPUT_PULLUP)
|
||||||
|
#elif defined (ARDUINO_ARCH_ESP32)
|
||||||
|
#define pulse_pin(pin) digitalWrite(pin, HIGH); digitalWrite(pin, LOW)
|
||||||
|
#define set_pin(pin) digitalWrite(pin, HIGH)
|
||||||
|
#define clear_pin(pin) digitalWrite(pin, LOW)
|
||||||
|
#define output_pin(pin) pinMode(pin, OUTPUT)
|
||||||
|
#define pullup_pin(pin) pinMode(pin, INPUT_PULLUP)
|
||||||
#else
|
#else
|
||||||
#define pulse_pin(port, pin) digitalWrite(pin, HIGH); digitalWrite(pin, LOW)
|
#define pulse_pin(port, pin) digitalWrite(pin, HIGH); digitalWrite(pin, LOW)
|
||||||
#define set_pin(port, pin) digitalWrite(pin, HIGH)
|
#define set_pin(port, pin) digitalWrite(pin, HIGH)
|
||||||
|
@@ -22,8 +22,10 @@
|
|||||||
/** \file
|
/** \file
|
||||||
TLC Animation functions. These play animations from PROGMEM. */
|
TLC Animation functions. These play animations from PROGMEM. */
|
||||||
|
|
||||||
|
#if !defined (ARDUINO_ARCH_ESP32)
|
||||||
#include <avr/pgmspace.h>
|
#include <avr/pgmspace.h>
|
||||||
#include <avr/io.h>
|
#include <avr/io.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "tlc_config.h"
|
#include "tlc_config.h"
|
||||||
#include "Tlc5940.h"
|
#include "Tlc5940.h"
|
||||||
|
@@ -53,7 +53,7 @@
|
|||||||
are attached normally.
|
are attached normally.
|
||||||
\note Each TLC needs it's own IREF resistor */
|
\note Each TLC needs it's own IREF resistor */
|
||||||
#ifndef NUM_TLCS
|
#ifndef NUM_TLCS
|
||||||
#define NUM_TLCS 1
|
#define NUM_TLCS 2
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/** Determines how data should be transfered to the TLCs. Bit-banging can use
|
/** Determines how data should be transfered to the TLCs. Bit-banging can use
|
||||||
@@ -108,7 +108,7 @@
|
|||||||
- 1 VPRG is connected
|
- 1 VPRG is connected
|
||||||
\note VPRG to GND inputs grayscale data, VPRG to Vcc inputs dot-correction
|
\note VPRG to GND inputs grayscale data, VPRG to Vcc inputs dot-correction
|
||||||
data */
|
data */
|
||||||
#define VPRG_ENABLED 0
|
#define VPRG_ENABLED 1
|
||||||
|
|
||||||
/** Enables/disables XERR (TLC pin 16) functionality to check for shorted/broken
|
/** Enables/disables XERR (TLC pin 16) functionality to check for shorted/broken
|
||||||
LEDs
|
LEDs
|
||||||
|
@@ -22,7 +22,9 @@
|
|||||||
/** \file
|
/** \file
|
||||||
TLC fading functions. */
|
TLC fading functions. */
|
||||||
|
|
||||||
|
#if !defined (ARDUINO_ARCH_ESP32)
|
||||||
#include <avr/interrupt.h>
|
#include <avr/interrupt.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "Tlc5940.h"
|
#include "Tlc5940.h"
|
||||||
|
|
||||||
|
@@ -103,18 +103,15 @@ tlc_setDCfromProgmem(dcArray1);
|
|||||||
|
|
||||||
\param dcArray A progmem array of dot correction data to be shifted out.
|
\param dcArray A progmem array of dot correction data to be shifted out.
|
||||||
\see \link Tlc5940::setAllDC Tlc.setAllDC \endlink */
|
\see \link Tlc5940::setAllDC Tlc.setAllDC \endlink */
|
||||||
void tlc_setDCfromProgmem(const uint8_t PROGMEM *dcArray)
|
void tlc_setDCfromProgmem(const uint8_t /*PROGMEM*/ *dcArray)
|
||||||
{
|
{
|
||||||
tlc_dcModeStart();
|
const uint8_t /*PROGMEM*/ *dcArrayp = dcArray;
|
||||||
|
uint8_t *dcDatap = tlc_DCData;
|
||||||
const uint8_t PROGMEM *p = dcArray;
|
while (dcDatap < tlc_DCData + NUM_TLCS * 12) {
|
||||||
const uint8_t PROGMEM *dcArrayEnd = dcArray + NUM_TLCS * 12;
|
*dcDatap++ = pgm_read_byte(dcArrayp++);
|
||||||
while (p < dcArrayEnd) {
|
*dcDatap++ = pgm_read_byte(dcArrayp++);
|
||||||
tlc_shift8(pgm_read_byte(p++));
|
*dcDatap++ = pgm_read_byte(dcArrayp++);
|
||||||
}
|
}
|
||||||
pulse_pin(XLAT_PORT, XLAT_PIN);
|
|
||||||
|
|
||||||
tlc_dcModeStop();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* @} */
|
/* @} */
|
||||||
|
Reference in New Issue
Block a user