I have copied a project from internet. The project use a CYD, Cheap Yellow Displays. The model is a ESP32-2432S028 (ESP32-WROM32 with TFT ILI9141 and touchscreen XPT2046. the display working, but the touchscreen does not work for this sketch. Thank for your help
// --------------------------------------------------------------------------------------------------------------------------------------------------
//
// M0NTV Homebrewing
//
// C H E A P Y E L L O W D I S P L A Y
//
// S i 5 3 5 1 V F O
//
// VERSION 2.5
// (February 2nd 2025)
//
// -------------------------------------------------------------------------------------------------------------------------------------------------
//
// This is an adaptation of code created by Pavel Milanes <pavelmc@gmail.com> which draws on work by:
//
// - Linux Kernel (www.kernel.org)
// - Hans Summers libs and demo code (qrp-labs.com)
// - Jason Mildrum's Etherkit libraries for Si5351
// - DK7IH example.
// - Jerry Gaffke integer routines for the bitx20 group
// - Brian Lough (https://www.youtube.com/brianlough) for his code which reassigns CYD pin 27 to CLK (instead of the usual pin 21 which is used for the screen).
// - Adafruit Seesaw Library
//
/***************************************************
Wiring:
Make sure you purchase an ESP32-2432S028R (the 'R' on the end indicates a RESISTIVE touchscreen). You want the resistive one not the capacitive one.
I bought this one: https://www.aliexpress.com/item/1005004502250619.html?spm=a2g0o.order_list.order_list_main.52.25a81c24300W0v
I would STRONGLY ADVISE you check out some of the excellent tutorials on getting started with the CYD (Cheap Yellow Display) at https://randomnerdtutorials.com
Just do a search on the home page for 'CYD'. They also have a great intro to the pinout of the device.
- Plug wire that came with CYD into the JST connector
closest to the Micro SD card slot
- Connect the wire to the adapter as follows:
CYD -> Adapter
------------------------------------------
GND -> - (AKA GND) - Black wire
3.3V -> + (AKA 3V) - Red wire
IO22 -> d (AKA SDA) - Blue wire
IO27 -> c (AKA SCL) - Yellow wire
*******************************************************/
//
// REVISION HISTORY
// ----------------
//
// V.1.0 Original version created.
// V.1.1 Added formatting to frequency display plus display of tuning increment. Tidied up code.
// V.1.2 Added automatic Sideband display (<10 MHz = LSB; >10 MHz = USB).
// V.2.0 Added touch sensitive button to screen GUI to select sideband manually.
// V.2.1 Tidied up colours & added colour-change to sideband indicator (blue = LSB; orange = USB).
// V.2.2 Added facility to select SUPERHET mode with IF offset calculations for LSB and USB.
// V.2.3 Added 100 MHz+ frequencies to be displayed correctly. Converted the SSB indicator into a button for sideband selection. Cleaned up code.
// V.2.4 Added capability to produce LO signal for FM mode.
// V.2.5 Added software tuning buttons to increase and decrease frequency.
/*
SETTING UP THE SOFTWARE
-----------------------
To ensure the best chance of this code running on your machine I advise that you use the SAME versions of libraries as I do.
A library update can very easily BREAK this code!
ESP32 Core - Version 3.0.4 - by Espressif Systems (This is installed in the BOARDS MANAGER section of Arduino IDE)
In the massive list of different ESP32 boards select 'ESP32 Dev Module'. This is what the Cheap Yellow Display identifies as.
You might also need to reduce the upload speed (under TOOLS menu in Arduino IDE) to 460800 to get it to work.
si5351mcu - Version 0.7.1 - Download from https://github.com/pavelmc/Si5351mcu/
Wire - Standard Arduino library (version shouldn't be an issue)
lvgl - Version 9.2.0 - by kisvegabor (installed through Arduino IDE)
tft_eSPI - Version 2.5.43 - by Bodmer (installed through Arduino IDE)
XPT2046_Touchscreen - Version 1.4 - by Paul Stoffregen (installed through Arduino IDE)
Adafruit_seesaw - Version 1.7.9 - by Adafruit (installed through Arduino IDE)
*/
#include "si5351mcu.h"
#include <Wire.h>
#include <lvgl.h>
#include <TFT_eSPI.h>
#include <XPT2046_Touchscreen.h>
#include "Adafruit_seesaw.h"
// Touchscreen pins
#define XPT2046_IRQ 36 // T_IRQ
#define XPT2046_MOSI 32 // T_DIN
#define XPT2046_MISO 39 // T_OUT
#define XPT2046_CLK 25 // T_CLK
#define XPT2046_CS 33 // T_CS
SPIClass touchscreenSPI = SPIClass(VSPI);
XPT2046_Touchscreen touchscreen(XPT2046_CS, XPT2046_IRQ);
#define SCREEN_WIDTH 240
#define SCREEN_HEIGHT 320
// Touchscreen coordinates: (x, y) and pressure (z)
int x, y, z;
#define DRAW_BUF_SIZE (SCREEN_WIDTH * SCREEN_HEIGHT / 10 * (LV_COLOR_DEPTH / 8))
uint32_t draw_buf[DRAW_BUF_SIZE / 4];
// lib instantiation as "Si"
Si5351mcu Si;
//----------------------------------------- SETTING UP THE VFO & BFO ---------------------------------------------------
//
// For USB: This figure is simply the top edge of your crystal sideband filter + an optional 300 Hz offset to attenuate
// the sub 300 Hz frequencies and allow more higher frequencies through the pass band.
//
// For LSB: To avoid sideband inversion the BFO (and LO) are dropped by the filter bandwidth plus a further 300 Hz
// frequency offset (see above). So LSB = top edge of filter - filter B/W - 300 Hz.
//
// For FM: For mixing down a VHF FM RF signal to a seperate demodulator module.
//
//
uint32_t LSB = 13324600; // 2.4 kHz 13.3 MHz (8 Pole) Filter
uint32_t USB = 13327900; // 2.4 kHz 13.3 MHz (8 Pole) Filter
uint32_t FM = 40650000; // To mix 2m band down to a 40 MHz IF.
uint32_t F1 = 7200000; // CLK0 frequency (Display Frequency)
int MODE = 1; // (MODE selection: 1 = LSB; 2 = USB; 3 = FM)
//-----------------------------------------------------------------------------------------------------------------------
String MHz, kHz, Hz;
String freq, comb_str;
char cfreq[9];
// Mix some colours to use
lv_color_t Blue = (lv_color_t)LV_COLOR_MAKE(50, 60, 250);
lv_color_t Green = (lv_color_t)LV_COLOR_MAKE(52, 235, 64);
lv_color_t Orange = (lv_color_t)LV_COLOR_MAKE(252, 134, 15);
lv_color_t Purple = (lv_color_t)LV_COLOR_MAKE(137, 50, 168);
lv_color_t ModeColour;
lv_obj_t * my_rect3;
lv_obj_t * text_label;
lv_obj_t * inc_button;
lv_obj_t * inc_label;
lv_obj_t * SSB_button;
lv_obj_t * SSB_button_label;
const char * ModeLabel;
lv_obj_t * Tune_UP_button;
lv_obj_t * Tune_DOWN_button;
lv_obj_t * Tune_UP_label;
lv_obj_t * Tune_DOWN_label;
bool inc_button_press = 0;
#define SDA 22
#define SCL 27
#define SS_SWITCH 24
#define SEESAW_ADDR 0x36 // Run the M0NTV CYD version of I2C Scanner and include the addresses here.
#define Si5351_ADDR 0x60
//------------------------ SET MODE OF OPERATION -----------------------------------
//
//Uncomment the mode of operation you WANT to use. Only one can be selected at once:
//
//#define SUPERHET // For SSB (LO = RF + IF) and for FM (LO = RF - IF)
//
#define DCR // LO = RF
//----------------------------------------------------------------------------------
Adafruit_seesaw ss;
int32_t encoder_position = 10000000;
int32_t tuning_inc = 1000;
int32_t old_tuning_inc = 1000;
// Get the Touchscreen data
void touchscreen_read(lv_indev_t * indev, lv_indev_data_t * data) {
// Checks if Touchscreen was touched, and prints X, Y and Pressure (Z)
if(touchscreen.tirqTouched() && touchscreen.touched()) {
// Get Touchscreen points
TS_Point p = touchscreen.getPoint();
// Advanced Touchscreen calibration, LEARN MORE » https://RandomNerdTutorials.com/touchscreen-calibration/
float alpha_x, beta_x, alpha_y, beta_y, delta_x, delta_y;
// REPLACE WITH YOUR OWN CALIBRATION VALUES » https://RandomNerdTutorials.com/touchscreen-calibration/
alpha_x = -0.000;
beta_x = 0.089;
delta_x = -32.329;
alpha_y = 0.067;
beta_y = 0.000;
delta_y = -14.482;
x = alpha_y * p.x + beta_y * p.y + delta_y;
// clamp x between 0 and SCREEN_WIDTH - 1
x = max(0, x);
x = min(SCREEN_WIDTH - 1, x);
y = alpha_x * p.x + beta_x * p.y + delta_x;
// clamp y between 0 and SCREEN_HEIGHT - 1
y = max(0, y);
y = min(SCREEN_HEIGHT - 1, y);
// Basic Touchscreen calibration points with map function to the correct width and height
//x = map(p.x, 200, 3700, 1, SCREEN_WIDTH);
//y = map(p.y, 240, 3800, 1, SCREEN_HEIGHT);
z = p.z;
data->state = LV_INDEV_STATE_PRESSED;
// Set the coordinates
data->point.x = x;
data->point.y = y;
}
else {
data->state = LV_INDEV_STATE_RELEASED;
}
}
static void tune_up_event_cb(lv_event_t * e) {
lv_event_code_t tuneupcode = lv_event_get_code(e);
Tune_UP_button = (lv_obj_t*) lv_event_get_target(e);
lv_obj_t * label = (lv_obj_t*) lv_event_get_user_data(e);
if(tuneupcode == LV_EVENT_CLICKED) {
F1 = (F1 + tuning_inc);
display_frequency();
set_frequency();
}
}
static void tune_down_event_cb(lv_event_t * e) {
lv_event_code_t tunedowncode = lv_event_get_code(e);
Tune_DOWN_button = (lv_obj_t*) lv_event_get_target(e);
lv_obj_t * label = (lv_obj_t*) lv_event_get_user_data(e);
if(tunedowncode == LV_EVENT_CLICKED) {
F1 = (F1 - tuning_inc);
display_frequency();
set_frequency();
}
}
static void inc_button_event_cb(lv_event_t * e) {
lv_event_code_t incbuttoncode = lv_event_get_code(e);
inc_button = (lv_obj_t*) lv_event_get_target(e);
lv_obj_t * label = (lv_obj_t*) lv_event_get_user_data(e);
if(incbuttoncode == LV_EVENT_CLICKED) {
inc_button_press = 1;
}
}
static void button_event_cb(lv_event_t * e) {
lv_event_code_t code = lv_event_get_code(e);
SSB_button = (lv_obj_t*) lv_event_get_target(e);
lv_obj_t * label = (lv_obj_t*) lv_event_get_user_data(e);
if(code == LV_EVENT_CLICKED) {
if(MODE == 1){
// If USB is selected ...
MODE = 2;
lv_obj_set_style_bg_color(SSB_button, Orange, 0);
lv_label_set_text(SSB_button_label, "USB");
}
else if(MODE == 2) {
// If FM is selected ...
MODE = 3;
lv_obj_set_style_bg_color(SSB_button, Blue, 0);
lv_label_set_text(SSB_button_label, "FM");
}
else {
// If LSB is selected ...
MODE = 1;
lv_obj_set_style_bg_color(SSB_button, Green, 0);
lv_label_set_text(SSB_button_label, "LSB");
}
}
set_frequency();
}
void lv_create_main_gui(void) {
// Create blue rectangle for tuning frequency
static lv_obj_t * my_rect = lv_obj_create(lv_scr_act());
lv_obj_set_size(my_rect , 180, 50);
lv_obj_set_pos(my_rect , 70, 10);
lv_obj_set_style_bg_color(my_rect , Blue, 0);
// Create a text label for the tuning frequency.
text_label = lv_label_create(lv_screen_active());
lv_obj_set_style_text_color(lv_scr_act(), lv_color_hex(0xffffff), LV_PART_MAIN);
lv_label_set_text(text_label, " ");
lv_obj_align(text_label, LV_ALIGN_CENTER, 0, -85);
// Create a button to set the tuning increment
inc_button = lv_button_create(lv_screen_active());
lv_obj_set_size(inc_button, 50, 50); // Set the button size
lv_obj_set_pos(inc_button , 260, 10);
lv_obj_set_style_bg_color(inc_button, Blue, 0);
// Add a label to the tuning increment button
inc_label = lv_label_create(inc_button);
lv_label_set_text(inc_label, "1K"); // Set the label text
lv_obj_center(inc_label);
lv_obj_add_event_cb(inc_button, inc_button_event_cb, LV_EVENT_ALL, inc_label); // Assign a callback to the button
// Set font type and font size for FREQUENCY label. More information: https://docs.lvgl.io/master/overview/font.html
static lv_style_t style_text_label;
lv_style_init(&style_text_label);
lv_style_set_text_font(&style_text_label, &lv_font_montserrat_26);
lv_obj_add_style(text_label, &style_text_label, 0);
// Set font type and font size for TUNING INCREMENT label.
static lv_style_t style_inc_label;
lv_style_init(&style_inc_label);
lv_style_set_text_font(&style_inc_label, &lv_font_montserrat_14);
lv_obj_add_style(inc_label, &style_inc_label, 0);
// Set font type and font size for LARGE label.
static lv_style_t style_large_label;
lv_style_init(&style_large_label);
lv_style_set_text_font(&style_large_label, &lv_font_montserrat_48);
// Create a button to set the desired MODE
SSB_button = lv_button_create(lv_screen_active());
lv_obj_set_size(SSB_button, 50, 50); // Set the button size
lv_obj_set_pos(SSB_button , 10, 10);
lv_obj_set_style_bg_color(SSB_button, ModeColour, 0);
// Add a label to the MODE button
SSB_button_label = lv_label_create(SSB_button);
lv_label_set_text(SSB_button_label, ModeLabel); // Set the label text
lv_obj_center(SSB_button_label);
lv_obj_add_event_cb(SSB_button, button_event_cb, LV_EVENT_ALL, SSB_button_label); // Assign a callback to the button
// Create a purple button to increment the tuning frequency
Tune_UP_button = lv_button_create(lv_screen_active());
lv_obj_set_size(Tune_UP_button, 100, 100); // Set the button size
lv_obj_set_pos(Tune_UP_button , 208, 130);
lv_obj_set_style_bg_color(Tune_UP_button, Purple, 0);
// Add a label to the tuning frequency increment button
Tune_UP_label = lv_label_create(Tune_UP_button);
lv_obj_add_style(Tune_UP_label, &style_large_label, 0);
lv_label_set_text(Tune_UP_label, "+"); // Set the label text
lv_obj_center(Tune_UP_label);
lv_obj_add_event_cb(Tune_UP_button, tune_up_event_cb, LV_EVENT_ALL, Tune_UP_label); // Assign a callback to the button
// Create a purple button to decrement the tuning frequency
Tune_DOWN_button = lv_button_create(lv_screen_active());
lv_obj_set_size(Tune_DOWN_button, 100, 100); // Set the button size
lv_obj_set_pos(Tune_DOWN_button , 10, 130);
lv_obj_set_style_bg_color(Tune_DOWN_button, Purple, 0);
// Add a label to the tuning frequency decrement button
Tune_DOWN_label = lv_label_create(Tune_DOWN_button);
lv_obj_add_style(Tune_DOWN_label, &style_large_label, 0);
lv_label_set_text(Tune_DOWN_label, "-"); // Set the labels text
lv_obj_center(Tune_DOWN_label);
lv_obj_add_event_cb(Tune_DOWN_button, tune_down_event_cb, LV_EVENT_ALL, Tune_DOWN_label); // Assign a callback to the button
}
void setup() {
Serial.begin(115200);
Wire.begin(SDA, SCL);
ss.begin(SEESAW_ADDR);
// use a pin for the built in encoder switch
ss.pinMode(SS_SWITCH, INPUT_PULLUP);
// get starting position
encoder_position = ss.getEncoderPosition();
delay(10);
ss.setGPIOInterrupts((uint32_t)1 << SS_SWITCH, 1);
ss.enableEncoderInterrupt();
// Start LVGL
lv_init();
// Start the SPI for the touchscreen and init the touchscreen
touchscreenSPI.begin(XPT2046_CLK, XPT2046_MISO, XPT2046_MOSI, XPT2046_CS);
touchscreen.begin(touchscreenSPI);
// Set the Touchscreen rotation in landscape mode
// Note: in some displays, the touchscreen might be upside down, so you might need to set the rotation to 0: touchscreen.setRotation(0);
touchscreen.setRotation(2);
// Create a display object
lv_display_t * disp;
// Initialize the TFT display using the TFT_eSPI library
disp = lv_tft_espi_create(SCREEN_WIDTH, SCREEN_HEIGHT, draw_buf, sizeof(draw_buf));
lv_display_set_rotation(disp, LV_DISPLAY_ROTATION_270);
// Initialize an LVGL input device object (Touchscreen)
lv_indev_t * indev = lv_indev_create();
lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER);
// Set the callback function to read Touchscreen input
lv_indev_set_read_cb(indev, touchscreen_read);
// Draw MODE button in the correct colour & with correct label
if(MODE == 1){
ModeColour = Green; // LSB
ModeLabel = "LSB";
}
else if(MODE == 2){
ModeColour = Orange; // USB
ModeLabel = "USB";
}
else{
ModeColour = Blue; // FM
ModeLabel = "FM";
}
// Function to draw the GUI
lv_create_main_gui();
display_frequency();
// init the Si5351 lib
Si.init(25000000);
// For a different xtal (from the default of 27.00000 Mhz)
// just pass it on the init procedure, just like this
// Si.init(26570000);
// set & apply my calculated correction factor
Si.correction(2018); // was -1997985
// set max power to both outputs
Si.setPower(0, SIOUT_8mA);
Si.setPower(1, SIOUT_8mA);
set_frequency();
// reset the PLLs
Si.reset();
}
void loop() {
lv_task_handler(); // let the GUI do its work
display_tuning_increment();
read_encoder_position();
// don't overwhelm serial port
delay(10);
lv_tick_inc(10);
}
/**************************************/
/* Read the button with debouncing */
/**************************************/
boolean get_button()
{
if (! ss.digitalRead(SS_SWITCH)) {
delay(20);
if (! ss.digitalRead(SS_SWITCH))
{
while (! ss.digitalRead(SS_SWITCH));
return 1;
}
}
return 0;
}
void display_frequency(){
freq = String(F1);
if (F1 >= 100000000){
MHz = freq.substring(0, 3);
kHz = freq.substring(3, 6);
Hz = freq.substring(6, 9);
}
else if (F1 >= 10000000){
MHz = freq.substring(0, 2);
kHz = freq.substring(2, 5);
Hz = freq.substring(5, 8);
}
else {
MHz = freq.substring(0, 1);
kHz = freq.substring(1, 4);
Hz = freq.substring(4, 7);
}
comb_str = MHz + "." + kHz + " " + Hz;
comb_str.toCharArray(cfreq, comb_str.length() + 1);
lv_label_set_text(text_label, cfreq);
}
void set_frequency(){
#ifdef SUPERHET
if (MODE == 1){
// We're on LSB
Si.setFreq(0, LSB + F1);
Si.setFreq(1, LSB);
}
else if (MODE == 2){
// We're on USB
Si.setFreq(0, USB + F1);
Si.setFreq(1, USB);
}
else{
// We're on FM
Si.setFreq(0, F1 - FM);
}
#endif
#ifdef DCR
Si.setFreq(0, F1);
#endif
}
void display_tuning_increment(){
// Button press changes the frequency tuning increment
if (get_button() || (inc_button_press == 1))
{
switch (tuning_inc)
{
case 1:
tuning_inc = 10;
lv_label_set_text(inc_label, "10");
break;
case 10:
tuning_inc = 100;
lv_label_set_text(inc_label, "100");
break;
case 100:
tuning_inc = 1000;
lv_label_set_text(inc_label, "1K");
break;
case 1000:
tuning_inc = 10000;
lv_label_set_text(inc_label, "10K");
break;
case 10000:
tuning_inc = 100000;
lv_label_set_text(inc_label, "100K");
break;
case 100000:
tuning_inc = 1000000;
lv_label_set_text(inc_label, "1M");
break;
case 1000000:
tuning_inc = 1;
lv_label_set_text(inc_label, "1");
break;
}
}
inc_button_press = 0;
}
void read_encoder_position(){
int32_t new_position = ss.getEncoderPosition();
// Has the frequency changed?
if (encoder_position != new_position) {
if (new_position > encoder_position){
F1 = (F1 + tuning_inc);
}
else F1 = (F1 - tuning_inc);
display_frequency();
set_frequency();
encoder_position = new_position; // and save for next round
}
}


