From 94d98858ec55676a5465e8630f7d5e6e91bc19e1 Mon Sep 17 00:00:00 2001 From: andrey_gulyants Date: Tue, 10 Oct 2023 20:34:00 +0100 Subject: [PATCH 1/3] ESP32 support --- Tlc5940.cpp | 244 ++++++++++++++++++++++++++++++++++---- Tlc5940.h | 40 ++++++- pinouts/Espressif_ESP32.h | 51 ++++++++ pinouts/chip_includes.h | 5 + pinouts/pin_functions.h | 6 + tlc_animations.h | 2 + tlc_config.h | 2 +- tlc_fades.h | 2 + 8 files changed, 329 insertions(+), 23 deletions(-) create mode 100644 pinouts/Espressif_ESP32.h diff --git a/Tlc5940.cpp b/Tlc5940.cpp index e1bf9bf..38d2b10 100644 --- a/Tlc5940.cpp +++ b/Tlc5940.cpp @@ -22,6 +22,14 @@ #include "Tlc5940.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 been latched in yet. */ @@ -85,6 +93,31 @@ void ftm1_isr(void) Tlc5940_interrupt(); } #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 /** \defgroup ReqVPRG_ENABLED Functions that Require VPRG_ENABLED @@ -107,20 +140,52 @@ void ftm1_isr(void) zeros, or whatever initialValue is set to and the Timers will start. \param initialValue = 0, optional parameter specifing the inital startup 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 */ +#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(BLANK_DDR, BLANK_PIN); output_pin(GSCLK_DDR, GSCLK_PIN); -#if VPRG_ENABLED + + #if VPRG_ENABLED output_pin(VPRG_DDR, VPRG_PIN); clear_pin(VPRG_PORT, VPRG_PIN); // grayscale mode (VPRG low) -#endif -#if XERR_ENABLED + #endif + #if XERR_ENABLED 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 - set_pin(BLANK_PORT, BLANK_PIN); // leave blank high (until the timers start) tlc_shift8_init(); @@ -129,7 +194,11 @@ void Tlc5940::init(uint16_t initialValue) disable_XLAT_pulses(); clear_XLAT_interrupt(); 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 */ @@ -218,6 +287,28 @@ void Tlc5940::init(uint16_t initialValue) NVIC_ENABLE_IRQ(IRQ_FTM1); CORE_PIN4_CONFIG = PORT_PCR_MUX(3)|PORT_PCR_DSE|PORT_PCR_SRE; #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 update(); } @@ -249,7 +340,11 @@ uint8_t Tlc5940::update(void) // adds an extra SCLK pulse unless we've just set dot-correction data firstGSInput = 0; } else { +#if defined (ARDUINO_ARCH_ESP32) + pulse_pin(sclk_pin); +#elif pulse_pin(SCLK_PORT, SCLK_PIN); +#endif } uint8_t *p = tlc_GSData; while (p < tlc_GSData + NUM_TLCS * 24) { @@ -319,12 +414,77 @@ void Tlc5940::setAll(uint16_t value) #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 From the \ref CoreFunctions "Core Functions": - \link Tlc5940::setAllDC Tlc.setAllDC(uint8_t value(0-63)) \endlink - sets 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++); + } + 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 value correspondes to maximum output current by \f$\displaystyle I_{OUT_n} = I_{max} \times \frac{DCn}{63} \f$ @@ -335,20 +495,15 @@ void Tlc5940::setAll(uint16_t value) \param value (0-63) */ void Tlc5940::setAllDC(uint8_t value) { - tlc_dcModeStart(); - uint8_t firstByte = value << 2 | value >> 4; uint8_t secondByte = value << 4 | value >> 2; uint8_t thirdByte = value << 6 | value; - - for (TLC_CHANNEL_TYPE i = 0; i < NUM_TLCS * 12; i += 3) { - tlc_shift8(firstByte); - tlc_shift8(secondByte); - tlc_shift8(thirdByte); + + while (p < tlc_DCData + NUM_TLCS * 12) { + *p++ = firstByte; + *p++ = secondByte; + *p++ = thirdByte; } - pulse_pin(XLAT_PORT, XLAT_PIN); - - tlc_dcModeStop(); } /* @} */ @@ -361,13 +516,28 @@ void Tlc5940::setAllDC(uint8_t value) \returns 1 if a TLC is reporting an error, 0 otherwise. */ 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 /* @} */ +#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 /** Sets all the bit-bang pins to output */ @@ -393,6 +563,31 @@ void tlc_shift8(uint8_t byte) #elif DATA_TRANSFER_MODE == TLC_SPI + #if defined (ARDUINO_ARCH_ESP32) + +/** Initializes the SPI module */ + +// SPI to send gray-scale data +const uint32_t TLC5940_SPI_CLK = 8000000; // 8MHz +SPIClass* TLC5940_vspi = NULL; + +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) */ void tlc_shift8_init(void) { @@ -414,7 +609,7 @@ void tlc_shift8(uint8_t byte) while (!(SPSR & _BV(SPIF))) ; // wait for transmission complete } - + #endif #endif #if VPRG_ENABLED @@ -425,13 +620,22 @@ void tlc_dcModeStart(void) disable_XLAT_pulses(); // ensure that no latches happen clear_XLAT_interrupt(); // (in case this was called right after update) 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. */ 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; } diff --git a/Tlc5940.h b/Tlc5940.h index 2a1cdd3..6acdf01 100644 --- a/Tlc5940.h +++ b/Tlc5940.h @@ -25,6 +25,16 @@ #include #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__) #ifdef TLC_ATMEGA_8_H @@ -71,24 +81,43 @@ extern volatile uint8_t tlc_needXLAT; extern volatile void (*tlc_onUpdateFinished)(void); 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 will be preinstantiated as Tlc. */ class Tlc5940 { 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); uint8_t update(void); void set(TLC_CHANNEL_TYPE channel, uint16_t value); uint16_t get(TLC_CHANNEL_TYPE channel); void setAll(uint16_t value); #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 #if XERR_ENABLED uint8_t readXERR(void); #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. 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 diff --git a/pinouts/Espressif_ESP32.h b/pinouts/Espressif_ESP32.h new file mode 100644 index 0000000..bbbe1a4 --- /dev/null +++ b/pinouts/Espressif_ESP32.h @@ -0,0 +1,51 @@ +/* Copyright (c) 2009 by Alex Leone + + 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 + . */ + +#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 + diff --git a/pinouts/chip_includes.h b/pinouts/chip_includes.h index b831a93..9f4ba1b 100644 --- a/pinouts/chip_includes.h +++ b/pinouts/chip_includes.h @@ -125,6 +125,11 @@ /* Teensy 4.0, 4.1, MicroMod */ #include "Teensy_IMXRT.h" +#elif defined (ARDUINO_ARCH_ESP32) + +#include "Espressif_ESP32.h" +#include + #else #error "Unknown Chip!" #endif diff --git a/pinouts/pin_functions.h b/pinouts/pin_functions.h index b0f6bd8..fdef266 100644 --- a/pinouts/pin_functions.h +++ b/pinouts/pin_functions.h @@ -19,6 +19,12 @@ #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) +#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 #define pulse_pin(port, pin) digitalWrite(pin, HIGH); digitalWrite(pin, LOW) #define set_pin(port, pin) digitalWrite(pin, HIGH) diff --git a/tlc_animations.h b/tlc_animations.h index e604349..1c7c42f 100644 --- a/tlc_animations.h +++ b/tlc_animations.h @@ -22,8 +22,10 @@ /** \file TLC Animation functions. These play animations from PROGMEM. */ +#if !defined (ARDUINO_ARCH_ESP32) #include #include +#endif #include "tlc_config.h" #include "Tlc5940.h" diff --git a/tlc_config.h b/tlc_config.h index 2db99c6..b8675ef 100644 --- a/tlc_config.h +++ b/tlc_config.h @@ -53,7 +53,7 @@ are attached normally. \note Each TLC needs it's own IREF resistor */ #ifndef NUM_TLCS -#define NUM_TLCS 1 +#define NUM_TLCS 2 #endif /** Determines how data should be transfered to the TLCs. Bit-banging can use diff --git a/tlc_fades.h b/tlc_fades.h index cb466a6..efc77ec 100644 --- a/tlc_fades.h +++ b/tlc_fades.h @@ -22,7 +22,9 @@ /** \file TLC fading functions. */ +#if !defined (ARDUINO_ARCH_ESP32) #include +#endif #include "Tlc5940.h" From cdddb8bf423c0bf435f84a63b3993e2e9547d15e Mon Sep 17 00:00:00 2001 From: andrey_gulyants Date: Fri, 27 Oct 2023 17:13:21 +0100 Subject: [PATCH 2/3] 1. SCLK additional pulse fix 2. Minor bugs --- Tlc5940.cpp | 27 ++++++++++++++++++++++----- tlc_config.h | 2 +- tlc_progmem_utils.h | 17 +++++++---------- 3 files changed, 30 insertions(+), 16 deletions(-) diff --git a/Tlc5940.cpp b/Tlc5940.cpp index 38d2b10..fbe69d7 100644 --- a/Tlc5940.cpp +++ b/Tlc5940.cpp @@ -22,6 +22,7 @@ #include "Tlc5940.h" #include "pinouts/pin_functions.h" + int sin_pin; int sout_pin; int sclk_pin; @@ -57,6 +58,9 @@ volatile void (*tlc_onUpdateFinished)(void); the array is the same as the format of the TLC's serial interface. */ 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. */ static uint8_t firstGSInput; @@ -120,6 +124,12 @@ void IRAM_ATTR TLC5940_onTimer() } #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 + /** \defgroup ReqVPRG_ENABLED Functions that Require VPRG_ENABLED Functions that require VPRG_ENABLED == 1. You can enable VPRG by changing @@ -341,7 +351,10 @@ uint8_t Tlc5940::update(void) firstGSInput = 0; } 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); #endif @@ -447,6 +460,14 @@ void Tlc5940::updateDC(void) 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(); } @@ -498,7 +519,7 @@ void Tlc5940::setAllDC(uint8_t value) uint8_t firstByte = value << 2 | value >> 4; uint8_t secondByte = value << 4 | value >> 2; uint8_t thirdByte = value << 6 | value; - + uint8_t *p = tlc_DCData; while (p < tlc_DCData + NUM_TLCS * 12) { *p++ = firstByte; *p++ = secondByte; @@ -567,10 +588,6 @@ void tlc_shift8(uint8_t byte) /** Initializes the SPI module */ -// SPI to send gray-scale data -const uint32_t TLC5940_SPI_CLK = 8000000; // 8MHz -SPIClass* TLC5940_vspi = NULL; - void tlc_shift8_init(void) { TLC5940_vspi = new SPIClass(VSPI); diff --git a/tlc_config.h b/tlc_config.h index b8675ef..ee61ca1 100644 --- a/tlc_config.h +++ b/tlc_config.h @@ -108,7 +108,7 @@ - 1 VPRG is connected \note VPRG to GND inputs grayscale data, VPRG to Vcc inputs dot-correction data */ -#define VPRG_ENABLED 0 +#define VPRG_ENABLED 1 /** Enables/disables XERR (TLC pin 16) functionality to check for shorted/broken LEDs diff --git a/tlc_progmem_utils.h b/tlc_progmem_utils.h index a87ae28..eeed4bd 100644 --- a/tlc_progmem_utils.h +++ b/tlc_progmem_utils.h @@ -103,18 +103,15 @@ tlc_setDCfromProgmem(dcArray1); \param dcArray A progmem array of dot correction data to be shifted out. \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 *p = dcArray; - const uint8_t PROGMEM *dcArrayEnd = dcArray + NUM_TLCS * 12; - while (p < dcArrayEnd) { - tlc_shift8(pgm_read_byte(p++)); + const uint8_t /*PROGMEM*/ *dcArrayp = dcArray; + uint8_t *dcDatap = tlc_DCData; + while (dcDatap < tlc_DCData + NUM_TLCS * 12) { + *dcDatap++ = pgm_read_byte(dcArrayp++); + *dcDatap++ = pgm_read_byte(dcArrayp++); + *dcDatap++ = pgm_read_byte(dcArrayp++); } - pulse_pin(XLAT_PORT, XLAT_PIN); - - tlc_dcModeStop(); } /* @} */ From 7b5a398459f77b0838fac8cb1d1320e635301436 Mon Sep 17 00:00:00 2001 From: reykada Date: Thu, 11 Jan 2024 19:36:57 +0000 Subject: [PATCH 3/3] Update README.md --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index 81f2208..b8cc37a 100644 --- a/README.md +++ b/README.md @@ -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 16 channel PWM LED driver based on the Texas Instruments TLC5940 chip.