Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Platform.io example with lvgl + touch + sd + lcd #2

Closed
AllanOricil opened this issue Mar 14, 2024 · 24 comments
Closed

Platform.io example with lvgl + touch + sd + lcd #2

AllanOricil opened this issue Mar 14, 2024 · 24 comments

Comments

@AllanOricil
Copy link
Contributor

I'm looking for a way to fix my problem of not being able to use the SD card when LCD + Touch are working, each using a different SPI bus. Someone on the CYD discord channel told me that your library is the solution.

I'm currently using a library called smartdisplay to initialize the display and lcd. As soon as I init both I can no longer use the SD card. So, with your library I think I can overcome this issue.

Could you help me? Thank you.

@ddxfish
Copy link
Owner

ddxfish commented Mar 14, 2024

Hello @AllanOricil!

I can only tell you what I went through. This Cheap Yellow Display has more SPI devices than buses and none seem to share the same pins. The XPT2046 is on pins that don't seem to have hardware SPI, but SD and TFT are each on separate hardware SPI. I made this library to independently support software SPI on this device without forcing LVGL or TFT_eSPI to handle bitbanging the touchscreen (software SPI). Easier to isolate issues for me when I don't use a package-deal that includes touch and TFT.

That's where my challenges took a different route from yours. I was on Arduino IDE and was trying both LVGL and TFT_eSPI, testing with each back and forth. At some point I decided this device was unusual enough that I had to separate out the touch capabilities from the TFT to isolate issues. I used TFT_eSPI for the display, this for the XPT2046 library, and the most common FAT32 SD library in Arduino IDE. I used all onboard devices simultaneously, I never recall an SD card issue on mine though.

Check the basics like make sure your power supply is plenty. The next thing that comes to mind is that in LVGL, if the touch is set to hardware SPI, it may be trying the other hardware SPI bus, which is really your SD. Sounds like this library could help you isolate issues if you are able to remove touch as an LVGL component. Full integration with LVGL or your graphics lib is best, this was a rudimentary but effective workaround for me.

These devices are weird but so cool. I hope you find your fix. Let me know if I can help any more, I'm not an expert, just an enthusiast.

@AllanOricil
Copy link
Contributor Author

I have no idea where to start to fix my issue, really. I started this project with almost no knowledge of microcontrollers.

Could you tell me if there is a solution?
If yes, could you make a list of what I need to learn to implement it myself?

Thank you @ddxfish

@ddxfish
Copy link
Owner

ddxfish commented Mar 14, 2024

@AllanOricil that make a lot of sense, that's how I started too. Here are some rough ideas.

  1. power supply. This must draw a couple hundred mA of power, so swap your power supply.
  2. Learn what we need to bitbang (which 4 pins on the CYD), and double check your pinout is the same as mine. Pay close attention to pins in your LVGL regarding TFT and touch. Also look for pin numbers used by TF card that may interfere on this device, either through LVGL or other libs.
  3. Config LVGL to not use touch or try to init the touch, and use this library to test if touch and LVGL actually work. I don't know the specifics on this one. You can modify config files, or even customize your libraries.
  4. Start swapping out libraries in your code. Use an alternative to LVGL to see if it can work, which may open up paths.
  5. You mention AI. Try using one of the other mainstream ones to see if it knows it better. Transplant your current AI to another chat via a prompt to see if that helps "unstuck" it.

If there was a direct answer, I'd give it. I'm maybe medium skill level, so nothing special. The main challenge in this board was that normal libraries didn't often work due to the weird pinout. I had to swap them out with others and constantly rework my code to adapt. I think your key is going to be swapping libraries at first.

Just in case it helps, this diagram helped me confirm my pinout a while back for the CYD.
Screenshot 2023-09-27 161321

@ddxfish
Copy link
Owner

ddxfish commented Mar 15, 2024

@AllanOricil I ran LVGL on my esp32 CYD on platform.io and my sd card and it works with this library. I have touch and SD functions in my loop and they both work with TFT enabled.
520 from /hello.txt: Hello, hi from SD card! touchscreen location: 132, 68 521 from /hello.txt: Hello, hi from SD card! touchscreen location: 137, 72 522 from /hello.txt: Hello, hi from SD card! touchscreen location: 141, 78
image

Your code you posted to your issue is also good, or at least looks good. The issue you are having is in the code you didn't post, or less likely, your power supply. Check your flush function to make sure it works without SD and touch for debug, check your pin configs in all libraries you use, and if it fails, swap the smartdisplay driver for TFT_eSPI ILI9341 driver, which I also tested with this setup and it works.

@AllanOricil
Copy link
Contributor Author

@AllanOricil I ran LVGL on my esp32 CYD on platform.io and my sd card and it works with this library. I have touch and SD functions in my loop and they both work with TFT enabled.
520 from /hello.txt: Hello, hi from SD card! touchscreen location: 132, 68 521 from /hello.txt: Hello, hi from SD card! touchscreen location: 137, 72 522 from /hello.txt: Hello, hi from SD card! touchscreen location: 141, 78
image

Your code you posted to your issue is also good, or at least looks good. The issue you are having is in the code you didn't post, or less likely, your power supply. Check your flush function to make sure it works without SD and touch for debug, check your pin configs in all libraries you use, and if it fails, swap the smartdisplay driver for TFT_eSPI ILI9341 driver, which I also tested with this setup and it works.

@ddxfish could you publish this platform.io project to github so that I can flash it into my esp32 and see if it works?

@ddxfish
Copy link
Owner

ddxfish commented Mar 16, 2024

@AllanOricil I'll post the relevant parts of the code. I used TFT_eSPI as the display driver, but earlier versions had smartdisplay driver working fine too without any touch (no, I didn't keep or continue that version after testing it). This uses TFT_eSPI as the driver instead of smartdisplay for the ILI9341, and LVGL as the graphics lib.

This is very bad code, only use it for testing. I should be using LVGL's event handler instead of my own in loop() to bypass event handling. It draws sqaure-like-things on the screen and not circles. It cuts off part of the display. But it prints SD card while using touch and the display at the same time.

platformio.ini

[env:esp32dev]
platform = espressif32
board = esp32dev
framework = arduino
lib_deps = 
  lvgl/LVGL@^7.11.0
  bodmer/TFT_eSPI@^2.3.70
  adafruit/Adafruit SPIFlash
  https://github.com/adafruit/SdFat.git#master
  https://github.com/ddxfish/XPT2046_Bitbang_Arduino_Library/
build_flags = 
  -D LVGL_DISPLAY_WIDTH=320
  -D LVGL_DISPLAY_HEIGHT=240
  -D ILI9341_DRIVER=1  ; Use ILI9341 display driver
  -D TFT_WIDTH=320
  -D TFT_HEIGHT=240
  -D TFT_MISO=19
  -D TFT_MOSI=13
  -D TFT_SCLK=14
  -D TFT_CS=15  ; Adjust your TFT CS pin
  -D TFT_DC=2   ; Adjust your TFT DC pin
  -D TFT_RST=12  ; Adjust if you have a reset pin
  -D TOUCH_CS=33 ; Adjust your Touch CS pin if using TFT_eSPI touch
  -D ENABLE_FAT12_SUPPORT=1
  -I include  ;
monitor_speed = 115200

main.cpp

#include <Arduino.h>
#include <lvgl.h>
#include <TFT_eSPI.h>
#include <FS.h>
#include <SD.h>
#include "SPI.h"
#include "XPT2046_Bitbang.h"

#define SD_CS 5 // Adjust to your SD card CS pin

TFT_eSPI tft = TFT_eSPI(); /* TFT instance */
static lv_disp_buf_t disp_buf;
static lv_color_t buf[LV_HOR_RES_MAX * 10]; /* Declare a buffer for 10 lines */


#define MOSI_PIN 32
#define MISO_PIN 39
#define CLK_PIN  25
#define CS_PIN   33
#define RERUN_CALIBRATE true
XPT2046_Bitbang touchscreen(MOSI_PIN, MISO_PIN, CLK_PIN, CS_PIN);

    /* Display flushing */
void my_disp_flush(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p) {
    Serial.println("Flushing display...");

    uint32_t w = (area->x2 - area->x1 + 1);
    uint32_t h = (area->y2 - area->y1 + 1);

    tft.startWrite();
    tft.setAddrWindow(area->x1, area->y1, w, h);

    // Directly send pixel data to the display
    for(int y = area->y1; y <= area->y2; y++) {
        for(int x = area->x1; x <= area->x2; x++) {
            // Calculate the position within the buffer
            uint32_t buffer_pos = (y - area->y1) * w + (x - area->x1);
            // Extract the color from LVGL's buffer and write to display
            uint16_t color = color_p[buffer_pos].full;
            tft.writeColor(color, 1);
        }
    }

    tft.endWrite();
    lv_disp_flush_ready(disp); // Inform LVGL that flushing is done

    Serial.println("Display flushed.");


}

void setup() {
    Serial.begin(115200);
    while(!Serial); // Wait for serial port to connect. Needed for native USB
    Serial.println("Starting setup...");

    pinMode(21, OUTPUT); // Set pin 21 as an output for the backlight
    digitalWrite(21, HIGH); // Turn on the backlight

    // Initialize the touchscreen
    touchscreen.begin();
    // Check for existing calibration data
    if (!touchscreen.loadCalibration()) {
        Serial.println("Failed to load calibration data from SPIFFS.");
    }
    // Check if we need to re-run calibration
    #if RERUN_CALIBRATE
        Serial.println("Re-running calibration as requested...");
        delay(2000); //wait for user to see serial
        touchscreen.calibrate();
        touchscreen.saveCalibration();
    #endif

    delay(1000);
    Serial.println("Backlight enabled.");

    lv_init();
    Serial.println("LVGL initialized.");

    tft.begin(); /* TFT init */
    Serial.println("TFT initialized.");
    tft.setRotation(1); /* Landscape orientation */
    Serial.println("TFT rotation set.");

    lv_disp_buf_init(&disp_buf, buf, NULL, LV_HOR_RES_MAX * 10);
    lv_disp_drv_t disp_drv;
    lv_disp_drv_init(&disp_drv);
    disp_drv.hor_res = 240;
    disp_drv.ver_res = 320;
    disp_drv.flush_cb = my_disp_flush;
    disp_drv.buffer = &disp_buf;
    lv_disp_drv_register(&disp_drv);
    Serial.println("LVGL display driver registered.");

    // SD Card Initialization
    if(!SD.begin(SD_CS)) {
        Serial.println("Card Mount Failed");
        return;
    }
    Serial.println("SD card initialized.");

    // Format SD card
    if(SD.exists("/hello.txt")) {
        SD.remove("/hello.txt");
        Serial.println("/hello.txt exists. Removing...");
    }

    // Create a new file
    File file = SD.open("/hello.txt", FILE_WRITE);
    if(!file) {
        Serial.println("Failed to open file for writing");
        return;
    }
    file.println("Hello, hi from SD card!");
    file.close();
    Serial.println("Written 'Hello, hi from SD card!' to /hello.txt");

    // Read the file
    file = SD.open("/hello.txt");
    if(!file) {
        Serial.println("Failed to open file for reading");
        return;
    }
    String line;
    while(file.available()){
        line = file.readStringUntil('\n');
        break; // Just read the first line for simplicity
    }
    file.close();
    Serial.println("Read from /hello.txt: " + line);


    // Create a style for the text
    static lv_style_t style_text;
    lv_style_init(&style_text);
    // Set the text color. Example: RGB(255, 0, 0) for red
    lv_style_set_text_color(&style_text, LV_STATE_DEFAULT, LV_COLOR_MAKE(255, 0, 0));


    // Display the text from SD card
    lv_obj_t *label = lv_label_create(lv_scr_act(), NULL);
    
    lv_label_set_text(label, line.c_str());
    lv_obj_align(label, NULL, LV_ALIGN_CENTER, 0, 0);
    Serial.println("Displayed text on screen.");
}
int counter = 0;
unsigned long lastTick = 0;
void loop() {


    static lv_obj_t* circle = nullptr; // Define static to retain the value across loop() calls
    Point touchPoint = touchscreen.getTouch(); // Poll the touch controller

    if (touchPoint.x != 0) { // Valid touch detected
        Serial.println("cirle1");
        //if(circle == nullptr) {
            Serial.println("cirle2");
            // Create the circle on the first valid touch
            circle = lv_obj_create(lv_scr_act(), NULL);
            lv_obj_set_size(circle, 200, 200); // Adjust size for better visibility
            lv_obj_set_style_local_bg_color(circle, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLUE); // Use a contrasting color
        //}
        
        // Move the circle to the touch location on every valid touch
        lv_obj_set_pos(circle, touchPoint.x - 10, touchPoint.y - 10); // Adjust the offset as needed
    }


    Serial.println("touchscreen location: " + String(touchPoint.x) + ", " + String(touchPoint.y));
        // Read the file
    File file = SD.open("/hello.txt");
    if(!file) {
        Serial.println("Failed to open file for reading");
        return;
    }
    String line;
    while(file.available()){
        line = file.readStringUntil('\n');
        break; // Just read the first line for simplicity
    }
    file.close();
    Serial.println("Read from /hello.txt: " + line + " " + String(counter));

    


    lv_task_handler(); /* Handle LVGL tasks */
    delay(10);
    counter +=1;
}

TFT_eSPI User_Setup_Config.h

comment out the first line, uncomment the second line later in the code.

//#include <User_Setup.h>   
#include <User_Setups/Setup42_ILI9341_ESP32.h>    

TFT_eSPI Setup42_ILI9341_ESP32.h

#define TFT_MISO 12  // (leave TFT SDO disconnected if other SPI devices share MISO)
#define TFT_MOSI 13
#define TFT_SCLK 14
#define TFT_CS   15  // Chip select control pin
#define TFT_DC    2  // Data Command control pin
//#define TFT_RST   2  // Reset pin (could connect to RST pin)

SdFatConfig.h

Various compiler errors, just change values here. I had another lib so not sure if this was relevant.

lv_conf.h

This is just the top of the file.

/**
 * @file lv_conf.h
 * Configuration file for v7.10.1
 */

/*
* COPY THIS FILE AS `lv_conf.h` NEXT TO the `lvgl` FOLDER
*/

#if 1 /*Set it to "1" to enable content*/

#ifndef LV_CONF_H
#define LV_CONF_H
/* clang-format off */

#include <stdint.h>

/*====================
  Graphical settings
*====================*/

/* Maximal horizontal and vertical resolution to support by the library.*/
#define LV_HOR_RES_MAX          (320)
#define LV_VER_RES_MAX          (240)

@AllanOricil
Copy link
Contributor Author

@ddxfish my weekend will be fun!
Thank you so much for the example. I will try that and keep you posted.
Have a good weekend!

@ddxfish
Copy link
Owner

ddxfish commented Mar 16, 2024

@AllanOricil good luck! I think you can pull this off. Tell me if you get it working in the end.

@AllanOricil
Copy link
Contributor Author

AllanOricil commented Mar 16, 2024

@ddxfish I made a repo with the code you shared.

https://github.com/AllanOricil/lvgl-lcd-touch-sd-card-test

After building and deploying:

  • A message asking to touch bottom right appears of the screen (probably to calibrate the touch). However there is no time to click on it. Moreover, no circle appeared on the screen to start the touch calibrarion.
  • SD card message appears on serial multiple times. This means it is working.
  • Screen is displaying a blank white screen. Nothing is written in it, like yours.
image

20240316_151425.jpg

Could you take a look and see what I missed?

obs: My TFT seems to be ST7789 and not ILI9341, do I need to change -D ILI9341_DRIVER=1 to - D ST7789_DRIVER=1?

obs: dependencies are tagged, and using a git repo because my platform.io could not find them the way you described. Are we using the same dependencies? could you check if https://github.com/adafruit/Adafruit_SPIFlash.git#4.3.4 equals to adafruit/Adafruit SPIFlash

UPDATE:

I was able to calibrate the touch! But I still cant see anything rendering on the screen.
image

@AllanOricil
Copy link
Contributor Author

I GOT IT! FUCK YEAH!

hehe

@ddxfish
Copy link
Owner

ddxfish commented Mar 16, 2024

@AllanOricil It sounds like you are close. I had a white screen when I had the wrong pin numbers.

ST7789- I didn't know CYD had this variant on displays. TFT_eSPI supports this. Edit your User_Setup.h to point to one of the other drivers in the User_Setups directory. In User_Setup.h you'll find a ton of setups, and that #42 is uncommented, try a different one. Try enabling one of the ST7789 config files, maybe #203. Then edit the file for #203 to match your pins and resolution.

To narrow down issues with driver vs lvgl, add a snippet of code at the start of your setup that inits the TFT_eSPI and draws a circle.

@ddxfish
Copy link
Owner

ddxfish commented Mar 16, 2024

Just saw this. Awesome! I hope the rest goes without speedbumps hehe.

@AllanOricil
Copy link
Contributor Author

@ddxfish Im using the same driver as you. I thought about using ST7789 because I was using this platform.io board in project.
After configuring TFT_eSPI/User_Setup_Select.h and TFT_eSPI/User_Setups/Setup42_ILI9341_ESP32.h pins, I could finally see something on the screen.

@AllanOricil
Copy link
Contributor Author

AllanOricil commented Mar 16, 2024

@ddxfish

I'm still having a small problem. The rotation isn't working, and tft can't see part of the screen. Look. Do you have a guess of what I missed?

20240316_162921.mp4

@AllanOricil
Copy link
Contributor Author

Fixed my problem.

20240316_165909.jpg

@AllanOricil
Copy link
Contributor Author

Published your example and gave you all credits.

image

Now, because github index all its pages, when people reach the same dead end while developing their projects, at least, they will have a source which can help them to continue.

Thank you so much!

@ddxfish
Copy link
Owner

ddxfish commented Mar 16, 2024

@AllanOricil I'm glad it helped. I'll close this issue. I might use LVGL for my next project too. Good luck with your project!

@ddxfish ddxfish closed this as completed Mar 16, 2024
@AllanOricil
Copy link
Contributor Author

@ddxfish the touch works, but lvgl does not react to it. Look at my latest changes:

https://github.com/AllanOricil/esp32-lvgl-lcd-touch-sd-card

the touch callback isn't called :/

@AllanOricil
Copy link
Contributor Author

finally fixed it. In lvgl 7 we have to call lv_tick_inc to notify lvgl to process its events. Pushed code with the changes.

WhatsApp.Video.2024-03-16.at.21.33.16.mp4

@ddxfish
Copy link
Owner

ddxfish commented Mar 17, 2024

Nice work on that one! I've been working on a better demo on the way to my next LVGL project, but it might take me a bit longer. It'll have all of these, RBG LED, photo sensor, and maybe a speaker demo too. I'll reference your code to see how to fix that rotation.

I was playing with lv_tick at one point and will probably use that so I can use the internal event handler. So much cleaner.

@AllanOricil
Copy link
Contributor Author

@ddxfish I'm trying to make it work with lvgl 8.3.11 but it is behaving very weird.

  • Blue and Red are inverted.
  • Button understands clicks (its animation get stuck on clicked state), however its callback is only called when I click on a different part of the screen. Then the clicked state is released, and the button goes back to its initial state.
  • I had to call ts_tick_inc, like I did for v7, in order to make lvgl process touch events, even though it is not required by lvgl v8. No idea why I had to do it.

@AllanOricil
Copy link
Contributor Author

Updated the example to use lvgl 8.3.11

https://github.com/AllanOricil/esp32-lvgl-lcd-touch-sd-card/tree/lvgl_8

@ddxfish
Copy link
Owner

ddxfish commented Mar 17, 2024

I am making a local wikireader from my CYD using LVGL. I'll use v8 too, it has a better event handler. I'll post both the project base code and the final.

I feel like we need a repo for CYD community for example code.

@AllanOricil
Copy link
Contributor Author

@ddxfish after migrating to lvgl 8.3.11 in my project, I had to disable #define LV_COLOR_16_SWAP 0 in lv_conf.h and also redefine colors. In platformio.ini, I moved away from User_Setup.h declaring all macros as build variables.

build_flags =
    -Ofast
    -Wall
    -D WIFI_SSID=$WIFI_SSID
    -D WIFI_PASSWORD=$WIFI_PASSWORD
    -D USER_SETUP_LOADED=1
    -D TFT_RGB_ORDER=TFT_RGB
    -D LVGL_DISPLAY_WIDTH=320
    -D LVGL_DISPLAY_HEIGHT=240
    -D ILI9341_DRIVER=1
    -D LCD_WIDTH=320
    -D LCD_HEIGHT=240
    -D TFT_WIDTH=320
    -D TFT_HEIGHT=240
    -D TFT_MISO=19
    -D TFT_MOSI=13
    -D TFT_SCLK=14
    -D TFT_CS=15
    -D TFT_DC=2
    -D TFT_RST=12
    -D TFT_BCKL=21
    -D SPI_FREQUENCY=40000000
    -D SPI_READ_FREQUENCY=16000000
    -D SMOOTH_FONT=1
    -D TOUCH_MOSI=32
    -D TOUCH_MISO=39
    -D TOUCH_CLK=25
    -D TOUCH_CS=33
    -D TF_CS=5
    -D ENABLE_FAT12_SUPPORT=1
    -D LV_CONF_PATH="${PROJECT_DIR}/lv_conf.h"
    -I include  ;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants