I am making myself a greenhouse controller based of the Waveshare 4.3" ESP32-S3 board and I’m just getting started but having one hell of a time with whatever this scrolling bug is. I can display static stuff all I want but as soon as I go to update live info, in this case temp and humidity from a DHT22 it takes on some type of scrolling effect. I just watch my live temperature and humidity slowly update from top to bottom and cycle back to the top again. I’ve tried limiting the updates to just one container, oversizing the screen, and it feels like just about everything under the sun. I’m using LVGL 8.4 as waveshare suggests. Anybody have some suggestions on where in my code the live updated numbers cause my screen to start scrolling?
#include <Arduino.h>
#include <lvgl.h>
#include <esp_display_panel.hpp>
#include <DHT.h>
#include “config.h”
using namespace esp_panel::board;
#define SCREEN_WIDTH 800
#define SCREEN_HEIGHT 480
#define LABEL_X (SCREEN_WIDTH / 2 - 100) // ~400, rough center
#define LABEL_Y (SCREEN_HEIGHT / 2 - 20) // ~240, rough center
Board *board;
static lv_disp_draw_buf_t draw_buf;
static lv_color_t buf[SCREEN_WIDTH * 20];
DHT dht(DHT22_PIN, DHT22);
static lv_obj_t *screen;
static lv_obj_t *dataLabel;
void myDispFlush(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p) {
int x_start = area->x1;
int y_start = area->y1;
int w = area->x2 - area->x1 + 1;
int h = area->y2 - area->y1 + 1;
size_t pix_count = w * h;
size_t byte_len = pix_count * 2;
uint8_t *rgb565_buf = (uint8_t *)malloc(byte_len);
if (!rgb565_buf) return;
for (size_t i = 0; i < pix_count; i++) {
uint8_t r = (color_p[i].full >> 11) & 0x1F;
uint8_t g = (color_p[i].full >> 5) & 0x3F;
uint8_t b = color_p[i].full & 0x1F;
rgb565_buf[i * 2] = (g << 5) | b;
rgb565_buf[i * 2 + 1] = (r << 3) | (g >> 3);
}
auto lcd = board->getLCD();
lcd->drawBitmap(x_start, y_start, w, h, rgb565_buf);
free(rgb565_buf);
lv_disp_flush_ready(disp);
}
void resetScreen() {
auto lcd = board->getLCD();
uint8_t *clear_buf = (uint8_t *)malloc(SCREEN_WIDTH * SCREEN_HEIGHT * 2);
if (clear_buf) {
for (int i = 0; i < SCREEN_WIDTH * SCREEN_HEIGHT * 2; i += 2) {
clear_buf[i] = 0x1F; // Blue (low byte)
clear_buf[i + 1] = 0x00; // Blue (high byte)
}
lcd->drawBitmap(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, clear_buf);
free(clear_buf);
}
}
void setup() {
board = new Board();
if (!board->begin()) {
while (1) delay(1000);
}
auto backlight = board->getBacklight();
if (backlight) backlight->setBrightness(255);
pinMode(DHT22_PIN, INPUT);
dht.begin();
lv_init();
lv_disp_draw_buf_init(&draw_buf, buf, NULL, SCREEN_WIDTH * 20);
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 = myDispFlush;
disp_drv.draw_buf = &draw_buf;
lv_disp_drv_register(&disp_drv);
lv_disp_set_rotation(NULL, LV_DISP_ROT_NONE);
screen = lv_scr_act();
lv_obj_set_style_bg_color(screen, lv_color_make(0, 0, 255), 0);
lv_obj_set_scrollbar_mode(screen, LV_SCROLLBAR_MODE_OFF);
lv_obj_clear_flag(screen, LV_OBJ_FLAG_SCROLLABLE);
lv_obj_set_scroll_dir(screen, LV_DIR_NONE);
dataLabel = lv_label_create(screen);
lv_label_set_text(dataLabel, “T: --.-°F H: --.-%”);
lv_obj_set_style_text_font(dataLabel, &lv_font_montserrat_28, 0);
lv_obj_set_style_text_color(dataLabel, lv_color_hex(0xFFFFFF), 0);
lv_obj_set_pos(dataLabel, LABEL_X, LABEL_Y);
lv_label_set_long_mode(dataLabel, LV_LABEL_LONG_CLIP);
lv_obj_set_scrollbar_mode(dataLabel, LV_SCROLLBAR_MODE_OFF);
lv_obj_clear_flag(dataLabel, LV_OBJ_FLAG_SCROLLABLE);
lv_obj_set_scroll_dir(dataLabel, LV_DIR_NONE);
resetScreen(); // Initial clear
lv_task_handler(); // Initial render
}
void loop() {
static unsigned long lastUpdate = 0;
unsigned long now = millis();
if (now - lastUpdate >= 2000) {
float tempC = dht.readTemperature();
float humidity = dht.readHumidity();
char displayStr[32];
if (!isnan(tempC) && !isnan(humidity)) {
float tempF = (tempC * 9.0 / 5.0) + 32.0;
snprintf(displayStr, sizeof(displayStr), “T: %.1f°F H: %.1f%%”, tempF, humidity);
} else {
snprintf(displayStr, sizeof(displayStr), “T: --.-°F H: --.-%”);
}
lv_label_set_text(dataLabel, displayStr);
lv_obj_set_pos(dataLabel, LABEL_X, LABEL_Y); // Re-clamp position
lv_refr_now(NULL); // Force render
lastUpdate = now;
}
delay(5);
}