Closed AllanOricil closed 6 months ago
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.
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
@AllanOricil that make a lot of sense, that's how I started too. Here are some rough ideas.
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.
@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
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 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
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?
@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.
[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
#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;
}
comment out the first line, uncomment the second line later in the code.
//#include <User_Setup.h>
#include <User_Setups/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)
Various compiler errors, just change values here. I had another lib so not sure if this was relevant.
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)
@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!
@AllanOricil good luck! I think you can pull this off. Tell me if you get it working in the end.
@ddxfish I made a repo with the code you shared.
https://github.com/AllanOricil/lvgl-lcd-touch-sd-card-test
After building and deploying:
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.
I GOT IT! FUCK YEAH!
hehe
@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.
Just saw this. Awesome! I hope the rest goes without speedbumps hehe.
@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.
@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?
Fixed my problem.
Published your example and gave you all credits.
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!
@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 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 :/
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.
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.
@ddxfish I'm trying to make it work with lvgl 8.3.11 but it is behaving very weird.
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.Updated the example to use lvgl 8.3.11
https://github.com/AllanOricil/esp32-lvgl-lcd-touch-sd-card/tree/lvgl_8
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.
@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 ;
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.