I have a pretty basic structure that I’m trying to get to scroll without any luck. I’ve confirmed touch is working and the coordinates are registering, but nothing is scrolling. I’ve even resorted to trying chatGPT to get some help, but I’m getting no where. I’m also very new to LVGL…so theres that.
`#include “lcd_display.h”
#include “touch_driver.h”
#include <lvgl.h>
#include <LovyanGFX.hpp>
#include “LGFX_Config.h”
#include <Arduino.h>
#include <Wire.h>
LV_FONT_DECLARE(lv_font_montserrat_20);
LV_FONT_DECLARE(lv_font_montserrat_16);
#define SCREEN_WIDTH 480
#define SCREEN_HEIGHT 320
static lv_disp_draw_buf_t draw_buf;
static lv_color_t buf[SCREEN_WIDTH * 10];
static LGFX tft;
bool lvglReady = false;
void my_disp_flush(lv_disp_drv_t* disp, const lv_area_t* area, lv_color_t* color_p) {
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);
tft.pushPixels((uint16_t *)&color_p->full, w * h, true);
tft.endWrite();
lv_disp_flush_ready(disp);
}
void touch_read(lv_indev_drv_t* indev_drv, lv_indev_data_t* data) {
lgfx::touch_point_t tp;
auto touch = getTouchInstance();
if (touch && touch->getTouchRaw(&tp, 1)) {
data->point.x = tp.x;
data->point.y = SCREEN_HEIGHT - tp.y;
data->state = LV_INDEV_STATE_PR;
Serial.printf("TOUCH: x=%d y=%d => LVGL x=%d y=%d\n",
tp.x, tp.y,
data->point.x, data->point.y);
} else {
data->state = LV_INDEV_STATE_REL;
}
}
void initDisplay() {
Serial.println(“initDisplay() starting…”);
pinMode(27, OUTPUT);
digitalWrite(27, HIGH);
Serial.println(“Backlight turned on”);
tft.init();
tft.setRotation(1);
delay(2000);
Serial.println(“LGFX display initialized”);
if (!initTouch()) {
Serial.println(“Touch initialization failed.”);
return;
}
lgfx::touch_point_t tp;
lgfx::ITouch* touch = getTouchInstance();
if (touch && touch->getTouchRaw(&tp, 1)) {
Serial.printf(“Raw Touch: x=%d y=%d\n”, tp.x, tp.y);
} else {
Serial.println(“No raw touch detected or touch instance is null.”);
}
lv_init();
lv_disp_draw_buf_init(&draw_buf, buf, NULL, sizeof(buf) / sizeof(lv_color_t));
Serial.println(“LVGL draw buffer initialized”);
static lv_disp_drv_t disp_drv;
lv_disp_drv_init(&disp_drv);
disp_drv.hor_res = SCREEN_WIDTH;
disp_drv.ver_res = SCREEN_HEIGHT;
disp_drv.flush_cb = my_disp_flush;
disp_drv.draw_buf = &draw_buf;
lv_disp_drv_register(&disp_drv);
Serial.println(“LVGL display driver registered”);
lv_obj_set_style_bg_color(lv_scr_act(), lv_color_black(), 0);
lv_obj_set_style_bg_opa(lv_scr_act(), LV_OPA_COVER, 0);
static lv_indev_drv_t indev_drv;
lv_indev_drv_init(&indev_drv);
indev_drv.type = LV_INDEV_TYPE_POINTER;
indev_drv.read_cb = touch_read;
lv_indev_drv_register(&indev_drv);
Serial.println(“LVGL touch input registered”);
createStatusScreen();
Serial.println(“Status screen created”);
lvglReady = true;
}
void updateLVGL() {
if (!lvglReady || !lv_scr_act()) return;
lv_timer_handler();
}
static void create_data_pill(lv_obj_t* parent, const char* text, lv_color_t bg_color) {
lv_obj_t* pill = lv_obj_create(parent);
lv_obj_set_width(pill, lv_pct(100));
lv_obj_set_height(pill, LV_SIZE_CONTENT);
lv_obj_set_style_radius(pill, 8, 0);
lv_obj_set_style_bg_color(pill, bg_color, 0);
lv_obj_set_style_bg_opa(pill, LV_OPA_COVER, 0);
lv_obj_set_style_pad_all(pill, 8, 0);
lv_obj_set_style_border_width(pill, 0, 0);
lv_obj_t* label = lv_label_create(pill);
lv_label_set_text(label, text);
lv_label_set_long_mode(label, LV_LABEL_LONG_WRAP);
lv_obj_set_width(label, lv_pct(100));
lv_obj_set_style_text_font(label, &lv_font_montserrat_16, 0);
lv_obj_set_style_text_color(label, lv_color_black(), 0);
lv_obj_align(label, LV_ALIGN_LEFT_MID, 0, 0);
}
void createStatusScreen() {
lv_obj_set_style_bg_color(lv_scr_act(), lv_color_make(0, 0, 0), 0);
lv_obj_set_style_bg_opa(lv_scr_act(), LV_OPA_COVER, 0);
lv_obj_t* scroll = lv_obj_create(lv_scr_act());
lv_obj_clear_flag(scroll, LV_OBJ_FLAG_SCROLLABLE);
lv_obj_set_scroll_dir(scroll, LV_DIR_VER);
lv_obj_set_scrollbar_mode(scroll, LV_SCROLLBAR_MODE_ACTIVE);
lv_obj_set_size(scroll, SCREEN_WIDTH, SCREEN_HEIGHT);
lv_obj_align(scroll, LV_ALIGN_CENTER, 0, 0);
lv_obj_set_flex_flow(scroll, LV_FLEX_FLOW_COLUMN);
lv_obj_set_style_pad_gap(scroll, 8, 0);
lv_obj_set_style_pad_all(scroll, 12, 0);
lv_obj_set_style_bg_color(scroll, lv_color_black(), 0);
lv_obj_t* title = lv_label_create(scroll);
lv_label_set_text(title, “Live Device Data”);
lv_obj_set_style_text_font(title, &lv_font_montserrat_20, 0);
lv_obj_set_style_text_color(title, lv_color_hex(0xFFCC00), 0);
lv_obj_align(title, LV_ALIGN_TOP_MID, 0, 0);
static const char* pill_texts = {
“Connected to The Nut\n192.168.112.210”,
“Standby\n63.46.154.172”,
“Standby\n63.46.154.171, Signal: Excellent”,
“Disabled\nN/A”,
“Disabled\nN/A”,
“Disabled\nN/A”
};
static lv_color_t pill_colors = {
lv_color_hex(0x00FF00),
lv_color_hex(0xCCCC00),
lv_color_hex(0xCCCC00),
lv_color_hex(0xFF0000),
lv_color_hex(0xFF0000),
lv_color_hex(0xFF0000)
};
for (int i = 0; i < 6; i++) {
create_data_pill(scroll, pill_texts[i], pill_colors[i]);
}
lv_obj_t* divider = lv_obj_create(scroll);
lv_obj_set_size(divider, lv_pct(100), 2);
lv_obj_set_style_bg_color(divider, lv_color_hex(0xFFCC00), 0);
lv_obj_set_style_bg_opa(divider, LV_OPA_COVER, 0);
lv_obj_set_style_border_width(divider, 0, 0);
static const char* bottom_labels = { “SpeedFusion:”, “SFC:” };
static const char* bottom_values = {
“conn_to_1144-8C2F-99D0\nRemote: 1144-8C2F-99D0\nType: Device\nSubnets: 169.254.131.0/24, 172.31.93.253/32”,
“Remote: San Jose (SJC)\nType: Cloud”
};
for (int i = 0; i < 2; i++) {
lv_obj_t* label = lv_label_create(scroll);
lv_label_set_text_fmt(label, “%s %s”, bottom_labels[i], bottom_values[i]);
lv_obj_set_style_text_color(label, lv_color_white(), 0);
lv_obj_set_style_text_font(label, &lv_font_montserrat_16, 0);
lv_label_set_long_mode(label, LV_LABEL_LONG_WRAP);
lv_obj_set_width(label, lv_pct(100));
}
lv_obj_t* spacer = lv_obj_create(scroll);
lv_obj_set_height(spacer, 100);
lv_obj_set_width(spacer, lv_pct(100));
lv_obj_clear_flag(spacer, LV_OBJ_FLAG_SCROLLABLE);
lv_obj_set_style_bg_opa(spacer, LV_OPA_TRANSP, 0);
}`