@mmar22
I’ve modified my code based on your suggestions- I see why they make sense. Unfortunately, I’m still getting the same behavior: the screens will change but sometimes I see half of screen1 and half of screen2… See the photos (don’t worry about the color of the screen being off)
The button has a 10k resistor between the pin and the button…
#include <Arduino_GFX_Library.h>
#include <lvgl.h>
//#include <Ds1302.h>
Arduino_DataBus *bus = new Arduino_SWSPI(GFX_NOT_DEFINED, 42, 2, 1, GFX_NOT_DEFINED);
Arduino_ESP32RGBPanel *rgbpanel = new Arduino_ESP32RGBPanel(
40 /* DE */, 39 /* VSYNC */, 38 /* HSYNC */, 41 /* PCLK */,
5 /* R0 */, 45 /* R1 */, 48 /* R2 */, 47 /* R3 */, 21 /* R4 */,
14 /* G0 */, 13 /* G1 */, 12 /* G2 */, 11 /* G3 */, 10 /* G4 */, 9 /* G5 */,
46 /* B0 */, 3 /* B1 */, 8 /* B2 */, 18 /* B3 */, 17 /* B4 */,
1 /* hsync_polarity */, 22 /* hsync_front_porch */, 24 /* hsync_pulse_width */, 6 /* hsync_back_porch */,
1 /* vsync_polarity */, 16 /* vsync_front_porch */, 4 /* vsync_pulse_width */, 10 /* vsync_back_porch */);
Arduino_RGB_Display *gfx = new Arduino_RGB_Display(
480 /* width */, 480 /* height */, rgbpanel, 0 /* rotation */, true /* auto_flush */,
bus, GFX_NOT_DEFINED /* RST */, st7701_type6_init_operations, sizeof(st7701_type6_init_operations));
/* Change to your screen resolution */
static uint32_t screenWidth;
static uint32_t screenHeight;
static uint32_t bufSize;
static lv_disp_draw_buf_t draw_buf;
static lv_color_t *disp_draw_buf;
static lv_disp_drv_t disp_drv;
/* Display flushing */
void my_disp_flush(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p) {
#ifndef DIRECT_MODE
uint32_t w = (area->x2 - area->x1 + 1);
uint32_t h = (area->y2 - area->y1 + 1);
#if (LV_COLOR_16_SWAP != 0)
gfx->draw16bitBeRGBBitmap(area->x1, area->y1, (uint16_t *)&color_p->full, w, h);
#else
gfx->draw16bitRGBBitmap(area->x1, area->y1, (uint16_t *)&color_p->full, w, h);
#endif
#endif // #ifndef DIRECT_MODE
lv_disp_flush_ready(disp);
}
// DS1302 RTC instance
//Ds1302 rtc(15, 16, 17); //RTC module pins
// Button definitions
const int minuteButton = 17;int minuteButtonState = 0; //int prevMinuteState = HIGH;
const int screenButton = 40;int screenButtonState = 0; //int prevScreenState = HIGH;
// Screens
static lv_obj_t *screen1; //gauge
static lv_obj_t *screen2; //clock
static lv_obj_t *screen3; //metrics
// Meters
static lv_obj_t *meter1; //gauge
static lv_obj_t *meter2; //clock
// Metrics Labels
lv_obj_t *labelAFR;
lv_obj_t *labelTPS;
lv_obj_t *labelMAP;
lv_obj_t *labelVOLT;
lv_obj_t *labelCLT;
lv_obj_t *labelRPM;
lv_obj_t *labelBARO;
lv_obj_t *labelAIRCOR;
lv_obj_t *labelWARMCOR;
lv_obj_t *labelBAROCOR;
//Clock hands
lv_meter_indicator_t * indic_min;
lv_meter_indicator_t * indic_hour;
//Clock time values
int minValue = 0;
float hourValue = 0.0;
// Time tracking
unsigned long last_switch_time = 0;
int current_screen = 0;
int twelveHour = 0;
uint32_t looper5;
void create_screens() {
// Screen 1 Gauge
LV_IMG_DECLARE(face);
screen1 = lv_obj_create(NULL); // Create a blank
lv_obj_set_size(screen1, 480, 480);
lv_obj_align(screen1, LV_ALIGN_CENTER, 0, 0);
//Swap gauge faces during nightime?
// Ds1302::DateTime now;
// rtc.getDateTime(&now);
// if (now.hour > 12) {
// 12Hour = now.hour-12;
// if (12Hour > 6) {
// LV_IMG_DECLARE(face);
// } else {
// LV_IMG_DECLARE(faceNight);
// }
// }
lv_obj_set_style_bg_img_src(screen1, &face, LV_PART_MAIN | LV_STATE_DEFAULT);
meter1 = lv_meter_create(screen1); // Create the meter
lv_obj_center(meter1); // Center it on the screen
lv_obj_remove_style(meter1, NULL, LV_PART_MAIN);
lv_obj_remove_style(meter1, NULL, LV_PART_INDICATOR);
lv_obj_set_size(meter1, 480, 480);
LV_IMG_DECLARE(needle);
/*Add AFR scale */
lv_meter_scale_t * scaleAFR = lv_meter_add_scale(meter1);
lv_meter_set_scale_ticks(meter1, scaleAFR, 0, 0, 0, lv_color_black());
lv_meter_set_scale_range(meter1, scaleAFR, 10, 18, 60, 60);
/*Add TPS scale */
lv_meter_scale_t * scaleTPS = lv_meter_add_scale(meter1);
lv_meter_set_scale_ticks(meter1, scaleTPS, 0, 0, 0, lv_color_black());
lv_meter_set_scale_range(meter1, scaleTPS, 0, 100, 60, 330);
/*Add VOLT scale */
lv_meter_scale_t * scaleVOLT = lv_meter_add_scale(meter1);
lv_meter_set_scale_ticks(meter1, scaleVOLT, 0, 0, 0, lv_color_black());
lv_meter_set_scale_range(meter1, scaleVOLT, 9, 15, 60, 240);
/*Add MAP scale */
lv_meter_scale_t * scaleMAP = lv_meter_add_scale(meter1);
lv_meter_set_scale_ticks(meter1, scaleMAP, 0, 0, 0, lv_color_black());
lv_meter_set_scale_range(meter1, scaleMAP, 0, 100, 60, 151);
/* Add AFR needle */
lv_meter_indicator_t * indic1;
indic1 = lv_meter_add_needle_img(meter1, scaleAFR, &needle, 0, 0);
lv_meter_set_indicator_value(meter1, indic1, 14);
/* Add TPS needle */
lv_meter_indicator_t * indic2;
indic2 = lv_meter_add_needle_img(meter1, scaleTPS, &needle, 0, 0);
lv_meter_set_indicator_value(meter1, indic2, 100);
/* Add VOLT needle */
lv_meter_indicator_t * indic3;
indic3 = lv_meter_add_needle_img(meter1, scaleVOLT, &needle, 0, 0);
lv_meter_set_indicator_value(meter1, indic3, 12);
/* Add MAP needle */
lv_meter_indicator_t * indic4;
indic4 = lv_meter_add_needle_img(meter1, scaleMAP, &needle, 0, 0);
lv_meter_set_indicator_value(meter1, indic4, 0);
// Screen 2 Clock
LV_IMG_DECLARE(clockFace);
screen2 = lv_obj_create(NULL); // Create a blank
lv_obj_set_size(screen2, 480, 480);
lv_obj_align(screen2, LV_ALIGN_CENTER, 0, 0);
lv_obj_set_style_bg_img_src(screen2, &clockFace, LV_PART_MAIN | LV_STATE_DEFAULT);
meter2 = lv_meter_create(screen2); // Create the meter
lv_obj_center(meter2); // Center it on the screen
lv_obj_remove_style(meter2, NULL, LV_PART_MAIN);
lv_obj_remove_style(meter2, NULL, LV_PART_INDICATOR);
lv_obj_set_size(meter2, 480, 480);
/*Create a scale for the minutes*/
/*61 ticks in a 360 degrees range (the last and the first line overlaps)*/
lv_meter_scale_t * scale_min = lv_meter_add_scale(meter2);
lv_meter_set_scale_ticks(meter2, scale_min, 0, 0, 0, lv_color_black());
lv_meter_set_scale_range(meter2, scale_min, 0, 60, 360, 270);
/*Create an other scale for the hours. It's only visual and contains only major ticks*/
lv_meter_scale_t * scale_hour = lv_meter_add_scale(meter2);
lv_meter_set_scale_ticks(meter2, scale_hour, 0, 0, 0, lv_color_black());
lv_meter_set_scale_range(meter2, scale_hour, 1, 12, 330, 300); /*[1..12] values in an almost full circle*/
LV_IMG_DECLARE(minute)
LV_IMG_DECLARE(hour)
/*Add a the hands from images*/
indic_min = lv_meter_add_needle_img(meter2, scale_min, &minute, -2, 11);
indic_hour = lv_meter_add_needle_img(meter2, scale_min, &hour, -2, 11);
lv_meter_set_indicator_value(meter2, indic_min, minValue);
lv_meter_set_indicator_value(meter2, indic_hour, hourValue);
/*Create an animation to set the value*/
lv_anim_t a;
lv_anim_init(&a);
lv_anim_set_values(&a, 0, 60);
lv_anim_set_repeat_count(&a, LV_ANIM_REPEAT_INFINITE);
lv_anim_set_time(&a, 2000); /*2 sec for 1 turn of the minute hand (1 hour)*/
lv_anim_set_var(&a, indic_min);
lv_anim_start(&a);
lv_anim_set_var(&a, indic_hour);
lv_anim_set_time(&a, 24000); /*24 sec for 1 turn of the hour hand*/
lv_anim_set_values(&a, 0, 60);
lv_anim_start(&a);
// Screen 3 metrics
screen3 = lv_obj_create(NULL); // Create a blank
lv_obj_set_size(screen3, 480, 480);
lv_obj_align(screen3, LV_ALIGN_CENTER, 0, 0);
lv_obj_set_style_bg_color(screen3,lv_color_black(),LV_PART_MAIN);
}
void setup() {
Serial.begin(115200);
//Serial.setDebugOutput(true);
//while(!Serial);
Serial.println("911 Gauge");
#ifdef GFX_EXTRA_PRE_INIT
GFX_EXTRA_PRE_INIT();
#endif
// Init Display
if (!gfx->begin()) {
Serial.println("gfx->begin() failed!");
}
gfx->fillScreen(RED);
#ifdef GFX_BL
pinMode(GFX_BL, OUTPUT);
digitalWrite(GFX_BL, HIGH);
#endif
lv_init();
screenWidth = gfx->width();
screenHeight = gfx->height();
#ifdef DIRECT_MODE
bufSize = screenWidth * screenHeight;
#else
bufSize = screenWidth * 40;
#endif
#ifdef ESP32
disp_draw_buf = (lv_color_t *)heap_caps_malloc(sizeof(lv_color_t) * bufSize, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
if (!disp_draw_buf) {
// remove MALLOC_CAP_INTERNAL flag try again
disp_draw_buf = (lv_color_t *)heap_caps_malloc(sizeof(lv_color_t) * bufSize, MALLOC_CAP_8BIT);
}
#else
disp_draw_buf = (lv_color_t *)malloc(sizeof(lv_color_t) * bufSize);
#endif
if (!disp_draw_buf) {
Serial.println("LVGL disp_draw_buf allocate failed!");
} else {
lv_disp_draw_buf_init(&draw_buf, disp_draw_buf, NULL, bufSize);
/* Initialize the display */
lv_disp_drv_init(&disp_drv);
/* Change the following line to your display resolution */
disp_drv.hor_res = screenWidth;
disp_drv.ver_res = screenHeight;
disp_drv.flush_cb = my_disp_flush;
disp_drv.draw_buf = &draw_buf;
#ifdef DIRECT_MODE
disp_drv.direct_mode = true;
#endif
lv_disp_drv_register(&disp_drv);
/* Initialize the (dummy) input device driver */
static lv_indev_drv_t indev_drv;
lv_indev_drv_init(&indev_drv);
indev_drv.type = LV_INDEV_TYPE_POINTER;
lv_indev_drv_register(&indev_drv);
// Set up buttons
// pinMode(hourButton, INPUT_PULLUP);
pinMode(minuteButton, INPUT_PULLUP);
pinMode(screenButton, INPUT_PULLUP);
// initialize the RTC
//rtc.init();
// Create the two screens
create_screens();
// Set screen1 as the initial screen
lv_scr_load(screen1);
Serial.println("Setup done");
}
}
void uitasks()
{
// read the buttons
minuteButtonState = digitalRead(minuteButton);
screenButtonState = digitalRead(screenButton);
// Handle minute button presses
if (minuteButtonState == LOW){
//Ds1302::DateTime dt;
//rtc.setDateTime(&dt);
//minValue = dt.minute;
minValue = (minValue + 1) % 60;
hourValue = (hourValue + .084);
Serial.println(hourValue);
if (hourValue > 60.48) {
hourValue = 0;
}
lv_meter_set_indicator_value(meter2, indic_min, minValue);
lv_meter_set_indicator_value(meter2, indic_hour, hourValue);
}
//Change screens
if (screenButtonState == LOW){
delay(200);
if(lv_scr_act() == screen1) lv_scr_load(screen2);
else lv_scr_load(screen1);
Serial.println("Screen Button Pressed");
}
// get the current time
// Ds1302::DateTime now;
// rtc.getDateTime(&now);
// if (now.hour > 12) { //convert 24 hour clock to 12 hour clock
// twelveHour = now.hour-12;
// }
// lv_meter_set_indicator_value(meter2, indic_min, now.minute);
// lv_meter_set_indicator_value(meter2, indic_hour, twelveHour);
}
void loop() {
lv_timer_handler(); /* let the GUI do its work */
delay(5);
looper5++;
if((looper5%10) == 0) uitasks();
// Automatically switch screens every 5 seconds
// if (millis() - last_switch_time > 5000) {
// switch_screens();
// last_switch_time = millis();
// }
#ifdef DIRECT_MODE
#if (LV_COLOR_16_SWAP != 0)
gfx->draw16bitBeRGBBitmap(0, 0, (uint16_t *)disp_draw_buf, screenWidth, screenHeight);
#else
gfx->draw16bitRGBBitmap(0, 0, (uint16_t *)disp_draw_buf, screenWidth, screenHeight);
#endif
#endif // #ifdef DIRECT_MODE
#ifdef CANVAS
gfx->flush();
#endif
}
If I place the below code into uitasks() the screen changes without hanging or stalling like it should… So there’s something wrong with the button press and how LVGL is receiving it?
// Automatically switch screens every 5 seconds - This works flawlessly.
if (millis() - last_switch_time > 5000) {
if(lv_scr_act() == screen1) {
lv_scr_load(screen2);
} else {
lv_scr_load(screen1);
} last_switch_time = millis();
}