Can WLED be combined with an LCD to display additional info?

Just curious whether WLED could be coded to utilize a TTGO T-Display (which includes a small LCD screen)? I have several of these boards on hand, and I just loaded “stock” version of WLED (for the ESP32) and connected a series of 4 individual Neopixels.

After confirming it works - I am now wondering about possible applications for the screen…

I have noticed however, that some of the effects look odd with just these 4 LEDs connected. Is this a symptom of the ESP32 hardware change, or is it because the effects don’t work well with a small number of LEDs?

Thanks!

Meant to include a link to the board I am referring to:

Please see usermods folder. There is a few mods with OLED displays.

I will check in there. I know that this particular screen requires a pair of libraries:


I figure I may be coming close to the max flash capacity - so I am hoping I can eliminate some of the extra functionalities if needed to free up space.

Thanks

Hello again…

Looking for some guidance with a little project that I am working on here just to see if I can get the voltage to display on the TTGO T-Display board referenced earlier in this thread. I have added the two libraries (TFT-eSPI and Button2) that this board requires when working with the Arduino IDE into the /led00/src/dependencies folder.
I then added my code to the usermod.cpp file as best I could (I also included declarations for the functions that are needed - I think). (I am not very experienced with coding, so I likely did a lot wrong here).

The code I placed in the usermod.cpp file is basically a modified version of this, with a bunch of stuff stripped out to ONLY show the voltage:

This is the stripped down code I am using:
#include “wled.h”

#include <TFT_eSPI.h>

#include <SPI.h>

#include "WiFi.h"

#include <Wire.h>

#include <Button2.h>

#include "esp_adc_cal.h"

#ifndef TFT_DISPOFF

#define TFT_DISPOFF 0x28

#endif

#ifndef TFT_SLPIN

#define TFT_SLPIN   0x10

#endif

#define TFT_MOSI            19

#define TFT_SCLK            18

#define TFT_CS              5

#define TFT_DC              16

#define TFT_RST             23

#define TFT_BL          4  // Display backlight control pin

#define ADC_EN          14

#define ADC_PIN         34

#define BUTTON_1        35

#define BUTTON_2        0

void espDelay(int ms);

void showVoltage();

TFT_eSPI tft = TFT_eSPI(135, 240); // Invoke custom library

//Button2 btn1(BUTTON_1);

//Button2 btn2(BUTTON_2);

char buff[512];

int vref = 1100;

int btnCick = false;

const int freq = 5000;

const int ledChannel = 3;

const int resolution = 8;

const int BLDutyCycle = 32; //PWM duty cycle for display backlight

//! Long time delay, it is recommended to use shallow sleep, which can effectively reduce the current consumption

void espDelay(int ms)

{   

    esp_sleep_enable_timer_wakeup(ms * 1000);

    esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH,ESP_PD_OPTION_ON);

    esp_light_sleep_start();

}

void showVoltage()

{

    static uint64_t timeStamp = 0;

    if (millis() - timeStamp > 1000) {

        timeStamp = millis();

        uint16_t v = analogRead(ADC_PIN);

        float battery_voltage = ((float)v / 4095.0) * 2.0 * 3.3 * (vref / 1000.0);

        String voltage = "Voltage :" + String(battery_voltage) + "V";

        Serial.println(voltage);

        tft.setTextSize(2);

        tft.fillScreen(TFT_BLACK);

        tft.setTextDatum(MC_DATUM);

        tft.drawString(voltage,  tft.width() / 2, tft.height() / 2 );

        espDelay(3000);   //testing current draw during shallow sleep

    }

}

/*

 * This file allows you to add own functionality to WLED more easily

 * See: https://github.com/Aircoookie/WLED/wiki/Add-own-functionality

 * EEPROM bytes 2750+ are reserved for your custom use case. (if you extend #define EEPSIZE in const.h)

 * bytes 2400+ are currently ununsed, but might be used for future wled features

 */

//Use userVar0 and userVar1 (API calls &U0=,&U1=, uint16_t)

//gets called once at boot. Do all initialization that doesn't depend on network here

void userSetup()

{

    Serial.begin(115200);

    Serial.println("Start");

    tft.init();

    tft.setRotation(1);

    tft.fillScreen(TFT_BLACK);

    tft.setTextSize(2);

    tft.setTextColor(TFT_WHITE);

    tft.setCursor(0, 0);

    tft.setTextDatum(MC_DATUM);

    tft.setTextSize(2);

    //ledcSetup(ledChannel, freq, resolution);

    //ledcAttachPin(TFT_BL, ledChannel);

    if (TFT_BL > 0) { // TFT_BL has been set in the TFT_eSPI library in the User Setup file TTGO_T_Display.h

         pinMode(TFT_BL, OUTPUT); // Set backlight pin to output mode

         //ledcSetup(ledChannel, freq, resolution);

         //ledcAttachPin(TFT_BL, ledChannel);

         digitalWrite(TFT_BL, HIGH); // Turn backlight on. TFT_BACKLIGHT_ON has been set in the TFT_eSPI library in the User Setup file TTGO_T_Display.h

         //ledcWrite(ledChannel, BLDutyCycle);

    }

    //tft.setSwapBytes(true);

    //tft.pushImage(0, 0,  240, 135, ttgo);

    //espDelay(30000);  //testing current draw during shallow sleep

    tft.setRotation(1);

//    button_init();

    esp_adc_cal_characteristics_t adc_chars;

    esp_adc_cal_value_t val_type = esp_adc_cal_characterize((adc_unit_t)ADC_UNIT_1, (adc_atten_t)ADC1_CHANNEL_6, (adc_bits_width_t)ADC_WIDTH_BIT_12, 1100, &adc_chars);

    //Check type of calibration value used to characterize ADC

    if (val_type == ESP_ADC_CAL_VAL_EFUSE_VREF) {

        Serial.printf("eFuse Vref:%u mV", adc_chars.vref);

        Serial.println(" ");

        vref = adc_chars.vref;

    } else if (val_type == ESP_ADC_CAL_VAL_EFUSE_TP) {

        Serial.printf("Two Point --> coeff_a:%umV coeff_b:%umV\n", adc_chars.coeff_a, adc_chars.coeff_b);

        Serial.println(" ");

    } else {

        Serial.println("Default Vref: 1100mV");

    }

}

//gets called every time WiFi is (re-)connected. Initialize own network interfaces here

void userConnected()

{

}

//loop. You can use "if (WLED_CONNECTED)" to check for successful connection

void userLoop()

{

  showVoltage();

}

When I attempt to build, I get a LOT of errors - here is a snippet of them:
wled00\src\dependencies\TFT_eSPI-master\Fonts\Font72x53rle.c:118:9: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘attribute’ before
‘const’
PROGMEM const unsigned char chr_f72_34[] =
^
wled00\src\dependencies\TFT_eSPI-master\Fonts\Font16.c:118:9: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘attribute’ before ‘const’
PROGMEM const unsigned char chr_f16_2D[16] = // 1 unsigned char per row
^
wled00\src\dependencies\TFT_eSPI-master\Extensions\Button.cpp:74:72: error: ‘_yd’ was not declared in this scope
_gfx->drawString(long_name, _x1 + (_w/2) + _xd, _y1 + (_h/2) - 4 + _yd);
^
wled00\src\dependencies\TFT_eSPI-master\Extensions\Smooth_font.cpp:149:6: error: ‘TFT_eSPI’ has not been declared
void TFT_eSPI::loadMetrics(void)
^
*** [.pio\build\esp32dev\src\src\dependencies\TFT_eSPI-master\Processors\TFT_eSPI_ESP32.c.o] Error 1
wled00\src\dependencies\TFT_eSPI-master\Fonts\Font64rle.c:164:9: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘attribute’ before ‘const’
PROGMEM const unsigned char chr_f64_37[] =
^
wled00\src\dependencies\TFT_eSPI-master\Fonts\Font32rle.c:181:9: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘attribute’ before ‘const’
PROGMEM const unsigned char chr_f32_31[] =
^
wled00\src\dependencies\TFT_eSPI-master\Fonts\Font16.c:124:9: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘attribute’ before ‘const’
PROGMEM const unsigned char chr_f16_2E[16] = // 1 unsigned char per row
^
wled00\src\dependencies\TFT_eSPI-master\Fonts\Font7srle.c:182:9: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘attribute’ before ‘const’
PROGMEM const unsigned char chr_f7s_37[] =
^
wled00\src\dependencies\TFT_eSPI-master\Extensions\Touch.cpp:98:1: error: ‘uint16_t’ does not name a type
uint16_t TFT_eSPI::getTouchRawZ(void){
^
wled00\src\dependencies\TFT_eSPI-master\Extensions\Button.cpp:75:22: error: ‘tempdatum’ was not declared in this scope
_gfx->setTextDatum(tempdatum);
^
wled00\src\dependencies\TFT_eSPI-master\Extensions\Touch.cpp:118:1: error: ‘uint8_t’ does not name a type
uint8_t TFT_eSPI::validTouch(uint16_t *x, uint16_t *y, uint16_t threshold){
^
wled00\src\dependencies\TFT_eSPI-master\Fonts\Font16.c:130:9: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘attribute’ before ‘const’
PROGMEM const unsigned char chr_f16_2F[16] = // 1 unsigned char per row
^

I also added the two libraries to my lib_deps:
TFT_eSPI@>=2.2.8
Button2@>=1.2.0

I was able to get the arduino code to compile “by itself” in Platformio, albeit with some issues in the graphics rendering - which I still need to figure out. I am just not sure how to get it to run concurrently with WLED.

Another update: I just noticed that my Arduino library was out of date, so I updated it and complied my program in the Arduino IDE and I am getting the same graphical anomaly i see when I did it with PlatformIO. So there must have been something that changed in the library that isn’t compatible with my original voltage code. I am further investigating this, but I still can’t get past the 400+ errors in compilation in the WLED version.

Yet another update…

I managed to get it to compile by REMOVING the library folders I copied into the /wled00/src/dependencies folder, and leaving the two libraries named in the lib_deps section. However, I need to edit one of the files in the library that I am using to “enable” the correct display, and I don’t have a file in the project to edit.

When I did this with another project (outside of WLED), when I added the two libraries into the lib_deps section of the platformio.ini file, I ended up with a folder in my tree that was named “libdeps\esp32dev”, and I was able to edit the file in there. But this folder doesn’t appear in my WLED project after compiling. Is there a trick to make this show up in VSCode?

Last Update (hopefully):

I think i solved it. I just didn’t see the file i was looking for. It was in the .pio/libdeps/esp32dev/ folder.

SO I AM GOOD! WHEW

Ooof. Spoke too soon.

I am not getting the WLED-AP to show up now. The LEDs that are hooked up are all orange, so at least that part is functioning, and the display is correctly showing the voltage.

I just can’t see the AP to configure it now that I have reprogrammed it. It worked fine before I loaded my custom code on it.

Check for blocking time-delays or not having a yield() statement.

Thanks - I had forgotten that I had a light sleep routine in the code I used as this test case. I commented out the line that called that function and the AP appears after upload. Thanks!

1 Like

When you finish testing please publish you usermod to repository. It would be nice for people who not that good on programming.
Best regards

I will do that - but I am still fairly new to github. I can probably muddle my way through.

First, I would like to program it to do something more useful than just showing the voltage - this was meant originally for reporting the battery voltage of a lipo connected to the battery connector of the T-Display board.

I might try to incorporate some of the code that is in the other usermods that display the preset, palette, etc.

Yep. Just take a look what people have done with displays and maybe it will be helpful for you. Good luck.

I think that I may have found a bug in the code that is available in the usermods folder for the OLED displays.

I copied the code from one of those examples and adapted it to use the TFT display on my T-display board. But there are a few bits of code that don’t have direct translations to the TFT library…

Here is a code snippet from the example “ssd1306_i2c_oled_u8g2” :

   // Fourth row with palette name
  u8x8.setCursor(2, 3);
  qComma = 0;
  insideQuotes = false;
  printedChars = 0;
  // Looking for palette name in JSON.
  for (size_t i = 0; i < strlen_P(JSON_palette_names); i++) {
    singleJsonSymbol = pgm_read_byte_near(JSON_palette_names + i);
    switch (singleJsonSymbol) {
    case '"':
      insideQuotes = !insideQuotes;
      break;
    case '[':
    case ']':
      break;
    case ',':
      qComma++;
    default:
      if (!insideQuotes || (qComma != knownPalette))
        break;
      u8x8.print(singleJsonSymbol);
      printedChars++;
    }
    if ((qComma > knownMode) || (printedChars > u8x8.getCols() - 2))
      break;
  }

There are a few issues I have:

  1. The u8x8.getCols() command isn’t available in my TFT_eSPI library, but I think that it is simply returning the width of the display in characters. There is a function that lets you state the width in pixels in my library, but the number of characters will vary depending on the font size chosen, so I am just planning to hard code the numbers specifically for this display and the font size I am using.
  2. The palette display ONLY works for me if it is set to the Default palette. Any other palette selection shows nothing on the display. So I started poking around with the code in this section, since I don’t fully understand how this code works. As I understand it, it is just parsing out the string of JSON text to find the full palette name. But the very last line of the code used a comparison to see if either the qcomma value is greated than knownMode or printedChars is greater than the (approximate) width of the display. This seemed odd to me. Since this section is supposed to be looking for the Palette (not the mode), I tried changing this last line to read ‘qcomma > knownPalette’.

Upon uploading this change, it actually worked as expected. So I am just not clear if this is a problem with the T-display that I am solving, or if the OLED displays have this same issue.

My fully modified code is as shown below (with the assumption that the columns count would be 25):

  // Fourth row with palette name
  tft.setCursor(1, 90);
  qComma = 0;
  insideQuotes = false;
  printedChars = 0;
  // Looking for palette name in JSON.
  for (size_t i = 0; i < strlen_P(JSON_palette_names); i++) {
    singleJsonSymbol = pgm_read_byte_near(JSON_palette_names + i);
    switch (singleJsonSymbol) {
    case '"':
      insideQuotes = !insideQuotes;
      break;
    case '[':
    case ']':
      break;
    case ',':
      qComma++;
    default:
      if (!insideQuotes || (qComma != knownPalette))
        break;
      tft.print(singleJsonSymbol);
      printedChars++;
    }
    if ((qComma > knownPalette) || (printedChars > 25 - 2))
      break;
  }