Hello all.
My hardware setup is an ESP32 with a 320x240 serial TFT that has a ILI9341 chip. I use the TFT_eSPI library to drive the TFT display.
The IDE I am using is Platformio with the LV_arduino v3.0.1 library.
I am initializing and reading the GPIO pins associated with the hardware buttons using the Arduino pinmode and digitalread functions. And this is in the lv_port_indev.c file.
The problem is that the Arduino functions don’t seem to work. The GPIO pins are not being initialized. So a button clicked event is never invoked.
I can initialize the read the GPIO pins fine if the code is in the main.c file. The GUI is a simple a screen with two buttons. I want to associate the hardware buttons with the GUI screen buttons, so that when I press a hardware button, the GUI button will depress.
Here is the main.c file:
#include <lvgl.h>
#include <Ticker.h>
#include <TFT_eSPI.h>
TFT_eSPI tft = TFT_eSPI(); /* TFT instance */
static lv_disp_buf_t disp_buf;
static lv_color_t buf[LV_HOR_RES_MAX * 10];
lv_disp_drv_t disp_drv;
lv_indev_drv_t indev_drv;
lv_obj_t *btn1;
lv_obj_t *btn2;
lv_obj_t *screenMain;
lv_obj_t *label;
static void event_handler_btn(lv_obj_t * obj, lv_event_t event) {
if (event == LV_EVENT_PRESSED) {
if (obj == btn1) {
lv_label_set_text(label, "Button1");
printf("Button1 clicked\n");
}
else if (obj == btn2) {
lv_label_set_text(label, "Button2");
}
}
}
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);
uint32_t wh = w * h;
tft.startWrite();
tft.setAddrWindow(area->x1, area->y1, w, h);
while (wh--) tft.pushColor(color_p++->full);
tft.endWrite();
lv_disp_flush_ready(disp);
}
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
tft.begin();
tft.setRotation(0);
analogReadResolution(10);
lv_init();
lv_disp_buf_init(&disp_buf, buf, NULL, LV_HOR_RES_MAX * 10);
/*Initialize the display*/
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);
/*Create screen objects*/
screenMain = lv_obj_create(NULL, NULL);
label = lv_label_create(screenMain, NULL);
lv_label_set_long_mode(label, LV_LABEL_LONG_BREAK);
lv_label_set_text(label, "Press a button");
lv_label_set_align(label, LV_LABEL_ALIGN_CENTER);
lv_obj_set_size(label, 240, 40);
lv_obj_set_pos(label, 0, 15);
btn1 = lv_btn_create(screenMain, NULL);
lv_obj_set_event_cb(btn1, event_handler_btn);
lv_obj_set_width(btn1, 90);
lv_obj_set_height(btn1, 32);
//lv_obj_set_pos(btn1, 32, 100);
lv_obj_set_pos(btn1, 15, 100);
lv_obj_t * label1 = lv_label_create(btn1, NULL);
lv_label_set_text(label1, "Hello");
btn2 = lv_btn_create(screenMain, NULL);
lv_obj_set_event_cb(btn2, event_handler_btn);
lv_obj_set_width(btn2, 90);
lv_obj_set_height(btn2, 32);
//lv_obj_set_pos(btn2, 142, 100);
lv_obj_set_pos(btn2, 125, 100);
lv_obj_t * label2 = lv_label_create(btn2, NULL);
lv_label_set_text(label2, "Goodbye");
lv_scr_load(screenMain);
}
void loop() {
// put your main code here, to run repeatedly:
lv_task_handler(); /* let the GUI do its work */
}
Here is the lv_port_indev.c file:
/**
* @file lv_port_indev.c
*
*/
/*Copy this file as "lv_port_indev.c" and set this value to "1" to enable content*/
#if 1
/*********************
* INCLUDES
*********************/
#include "lv_port_indev.h"
/*********************
* DEFINES
*********************/
#define HIGH 1
#define LOW 0
#define INPUT 1
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static void touchpad_init(void);
static void touchpad_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
static bool touchpad_is_pressed(void);
static void touchpad_get_xy(lv_coord_t * x, lv_coord_t * y);
static void mouse_init(void);
static void mouse_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
static bool mouse_is_pressed(void);
static void mouse_get_xy(lv_coord_t * x, lv_coord_t * y);
static void keypad_init(void);
static void keypad_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
static uint32_t keypad_get_key(void);
static void encoder_init(void);
//static bool encoder_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
static void encoder_handler(void);
static void button_init(void);
static void button_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
static int8_t button_get_pressed_id(void);
static bool button_is_pressed(uint8_t id);
/**********************
* STATIC VARIABLES
**********************/
lv_indev_t * indev_touchpad;
lv_indev_t * indev_mouse;
lv_indev_t * indev_keypad;
lv_indev_t * indev_encoder;
lv_indev_t * indev_button;
lv_obj_t *label3;
const int button1 = 36; // the number of the pushbutton pin
int buttonState = 0; // variable for reading the pushbutton status
const int button2 = 34; // the number of the second pushbutton pin
static int32_t encoder_diff;
static lv_indev_state_t encoder_state;
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_port_indev_init(void)
{
/**
* Here you will find example implementation of input devices supported by LittelvGL:
* - Touchpad
* - Mouse (with cursor support)
* - Keypad (supports GUI usage only with key)
* - Encoder (supports GUI usage only with: left, right, push)
* - Button (external buttons to press points on the screen)
*
* The `..._read()` function are only examples.
* You should shape them according to your hardware
*/
static lv_indev_drv_t indev_drv;
/*------------------
* Touchpad
* -----------------*/
/*Initialize your touchpad if you have*/
touchpad_init();
/*Register a touchpad input device*/
lv_indev_drv_init(&indev_drv);
indev_drv.type = LV_INDEV_TYPE_POINTER;
indev_drv.read_cb = touchpad_read;
indev_touchpad = lv_indev_drv_register(&indev_drv);
/*------------------
* Mouse
* -----------------*/
/*Initialize your touchpad if you have*/
mouse_init();
/*Register a mouse input device*/
lv_indev_drv_init(&indev_drv);
indev_drv.type = LV_INDEV_TYPE_POINTER;
indev_drv.read_cb = mouse_read;
indev_mouse = lv_indev_drv_register(&indev_drv);
/*Set cursor. For simplicity set a HOME symbol now.*/
lv_obj_t * mouse_cursor = lv_img_create(lv_disp_get_scr_act(NULL), NULL);
lv_img_set_src(mouse_cursor, LV_SYMBOL_HOME);
lv_indev_set_cursor(indev_mouse, mouse_cursor);
/*------------------
* Keypad
* -----------------*/
/*Initialize your keypad or keyboard if you have*/
keypad_init();
/*Register a keypad input device*/
lv_indev_drv_init(&indev_drv);
indev_drv.type = LV_INDEV_TYPE_KEYPAD;
indev_drv.read_cb = keypad_read;
indev_keypad = lv_indev_drv_register(&indev_drv);
/*Later you should create group(s) with `lv_group_t * group = lv_group_create()`,
*add objects to the group with `lv_group_add_obj(group, obj)`
*and assign this input device to group to navigate in it:
*`lv_indev_set_group(indev_keypad, group);`*/
// my stuff
label3 = lv_label_create(lv_scr_act(), NULL);
/*------------------
* Encoder
* -----------------*/
/*Initialize your encoder if you have*/
encoder_init();
/*Register a encoder input device*/
lv_indev_drv_init(&indev_drv);
indev_drv.type = LV_INDEV_TYPE_ENCODER;
//indev_drv.read_cb = encoder_read;
indev_encoder = lv_indev_drv_register(&indev_drv);
/*Later you should create group(s) with `lv_group_t * group = lv_group_create()`,
*add objects to the group with `lv_group_add_obj(group, obj)`
*and assign this input device to group to navigate in it:
*`lv_indev_set_group(indev_encoder, group);`*/
/*------------------
* Button
* -----------------*/
/*Initialize your button if you have*/
button_init();
/*Register a button input device*/
lv_indev_drv_init(&indev_drv);
indev_drv.type = LV_INDEV_TYPE_BUTTON;
indev_drv.read_cb = button_read;
indev_button = lv_indev_drv_register(&indev_drv);
/*Assign buttons to points on the screen*/
static const lv_point_t btn_points[2] = {
{15, 100}, /*Button 0 -> x:10; y:10*/
{125, 100}, /*Button 1 -> x:40; y:100*/
};
lv_indev_set_button_points(indev_button, btn_points);
}
/**********************
* STATIC FUNCTIONS
**********************/
/*------------------
* Touchpad
* -----------------*/
/*Initialize your touchpad*/
static void touchpad_init(void)
{
/*Your code comes here*/
}
/*Will be called by the library to read the touchpad*/
static void touchpad_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
{
static lv_coord_t last_x = 0;
static lv_coord_t last_y = 0;
/*Save the pressed coordinates and the state*/
if(touchpad_is_pressed()) {
touchpad_get_xy(&last_x, &last_y);
data->state = LV_INDEV_STATE_PR;
} else {
data->state = LV_INDEV_STATE_REL;
}
/*Set the last pressed coordinates*/
data->point.x = last_x;
data->point.y = last_y;
}
/*Return true is the touchpad is pressed*/
static bool touchpad_is_pressed(void)
{
/*Your code comes here*/
return false;
}
/*Get the x and y coordinates if the touchpad is pressed*/
static void touchpad_get_xy(lv_coord_t * x, lv_coord_t * y)
{
/*Your code comes here*/
(*x) = 0;
(*y) = 0;
}
/*------------------
* Mouse
* -----------------*/
/*Initialize your mouse*/
static void mouse_init(void)
{
/*Your code comes here*/
}
/*Will be called by the library to read the mouse*/
static void mouse_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
{
/*Get the current x and y coordinates*/
mouse_get_xy(&data->point.x, &data->point.y);
/*Get whether the mouse button is pressed or released*/
if(mouse_is_pressed()) {
data->state = LV_INDEV_STATE_PR;
} else {
data->state = LV_INDEV_STATE_REL;
}
}
/*Return true is the mouse button is pressed*/
static bool mouse_is_pressed(void)
{
/*Your code comes here*/
return false;
}
/*Get the x and y coordinates if the mouse is pressed*/
static void mouse_get_xy(lv_coord_t * x, lv_coord_t * y)
{
/*Your code comes here*/
(*x) = 0;
(*y) = 0;
}
/*------------------
* Keypad
* -----------------*/
/*Initialize your keypad*/
static void keypad_init(void)
{
/*Your code comes here*/
}
/*Will be called by the library to read the mouse*/
static void keypad_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
{
static uint32_t last_key = 0;
/*Get the current x and y coordinates*/
mouse_get_xy(&data->point.x, &data->point.y);
/*Get whether the a key is pressed and save the pressed key*/
uint32_t act_key = keypad_get_key();
if(act_key != 0) {
data->state = LV_INDEV_STATE_PR;
/*Translate the keys to LVGL control characters according to your key definitions*/
switch(act_key) {
case 1:
act_key = LV_KEY_NEXT;
break;
case 2:
act_key = LV_KEY_PREV;
break;
case 3:
act_key = LV_KEY_LEFT;
break;
case 4:
act_key = LV_KEY_RIGHT;
break;
case 5:
act_key = LV_KEY_ENTER;
break;
}
last_key = act_key;
} else {
data->state = LV_INDEV_STATE_REL;
}
data->key = last_key;
}
/*Get the currently being pressed key. 0 if no key is pressed*/
static uint32_t keypad_get_key(void)
{
/*Your code comes here*/
return 0;
}
/*------------------
* Encoder
* -----------------*/
/*Initialize your keypad*/
static void encoder_init(void)
{
/*Your code comes here*/
}
/*Will be called by the library to read the encoder*/
static void encoder_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
{
data->enc_diff = encoder_diff;
data->state = encoder_state;
}
/*Call this function in an interrupt to process encoder events (turn, press)*/
static void encoder_handler(void)
{
/*Your code comes here*/
encoder_diff += 0;
encoder_state = LV_INDEV_STATE_REL;
}
/*------------------
* Button
* -----------------*/
/*Initialize your buttons*/
static void button_init(void)
{
/*Your code comes here*/
// initialize the btn1 pin as an input:
pinMode(button1, INPUT);
// initialize the btn2 pin as an input:
pinMode(button2, INPUT);
}
/*Will be called by the library to read the button*/
static void button_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
{
static uint8_t last_btn = 0;
/*Get the pressed button's ID*/
int8_t btn_act = button_get_pressed_id();
if(btn_act >= 0) {
data->state = LV_INDEV_STATE_PR;
last_btn = btn_act;
} else {
data->state = LV_INDEV_STATE_REL;
}
}
/*Get ID (0, 1, 2 ..) of the pressed button*/
static int8_t button_get_pressed_id(void)
{
uint8_t i;
/*Check to buttons see which is being pressed (assume there are 2 buttons)*/
for(i = 0; i < 2; i++) {
/*Return the pressed button's ID*/
if(button_is_pressed(i)) {
return i;
}
}
/*No button pressed*/
return -1;
}
/*Test if `id` button is pressed or not*/
static bool button_is_pressed(uint8_t id)
{
/*Your code comes here*/
// read the state of the pushbutton value:
if(id == 0)
buttonState = digitalRead(button1);
if(id == 1)
buttonState = digitalRead(button2);
// check if the pushbutton is pressed. If it is, the buttonState is HIGH:
if (buttonState == LOW) {
// turn LED on:
return true;
} else {
return false;
}
}
#else /*Enable this file at the top*/
/*This dummy typedef exists purely to silence -Wpedantic.*/
typedef int keep_pedantic_happy;
#endif
Here is the trace output. The button event never happens when I press the hardware button.
— Miniterm on COM3 9600,8,N,1 —
— Quit: Ctrl+C | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H —
Trace: lv_init started (lv_obj.c #125 lv_init())
Info: lv_init ready (lv_obj.c #163 lv_init())
Trace: Screen create started (lv_obj.c #205 lv_obj_create())
Info: Object create ready (lv_obj.c #392 lv_obj_create())
Trace: Screen create started (lv_obj.c #205 lv_obj_create())
Info: Object create ready (lv_obj.c #392 lv_obj_create())
Trace: Screen create started (lv_obj.c #205 lv_obj_create())
Info: Object create ready (lv_obj.c #392 lv_obj_create())
Trace: Screen create started (lv_obj.c #205 lv_obj_create())
Info: Object create ready (lv_obj.c #392 lv_obj_create())
Trace: label create started (lv_label.c #79 lv_label_create())
Trace: Object create started (lv_obj.c #237 lv_obj_create())
Info: Object create ready (lv_obj.c #392 lv_obj_create())
Info: label created (lv_label.c #167 lv_label_create())
Trace: button create started (lv_btn.c #61 lv_btn_create())
Trace: container create started (lv_cont.c #70 lv_cont_create())
Trace: Object create started (lv_obj.c #237 lv_obj_create())
Info: Object create ready (lv_obj.c #392 lv_obj_create())
Info: container created (lv_cont.c #118 lv_cont_create())
Info: button created (lv_btn.c #106 lv_btn_create())
Trace: label create started (lv_label.c #79 lv_label_create())
Trace: Object create started (lv_obj.c #237 lv_obj_create())
Info: Object create ready (lv_obj.c #392 lv_obj_create())
Info: label created (lv_label.c #167 lv_label_create())
Trace: button create started (lv_btn.c #61 lv_btn_create())
Trace: container create started (lv_cont.c #70 lv_cont_create())
Trace: Object create started (lv_obj.c #237 lv_obj_create())
Info: Object create ready (lv_obj.c #392 lv_obj_create())
Info: container created (lv_cont.c #118 lv_cont_create())
Info: button created (lv_btn.c #106 lv_btn_create())
Trace: label create started (lv_label.c #79 lv_label_create())
Trace: Object create started (lv_obj.c #237 lv_obj_create())
Info: Object create ready (lv_obj.c #392 lv_obj_create())
Info: label created (lv_label.c #167 lv_label_create())
Trace: lv_task_handler started (lv_task.c #74 lv_task_handler())
Trace: lv_refr_task: started (lv_refr.c #177 _lv_disp_refr_task())
Trace: lv_refr_task: ready (lv_refr.c #309 _lv_disp_refr_task())
Trace: lv_task_handler ready (lv_task.c #192 lv_task_handler())
Trace: lv_task_handler started (lv_task.c #74 lv_task_handler())
Trace: lv_task_handler ready (lv_task.c #192 lv_task_handler())
Trace: lv_task_handler started (lv_task.c #74 lv_task_handler())
Trace: lv_task_handler ready (lv_task.c #192 lv_task_handler())
Trace: lv_task_handler started (lv_task.c #74 lv_task_handler())
Trace: lv_task_handler ready (lv_task.c #192 lv_task_handler())
Trace: lv_task_handler started (lv_task.c #74 lv_task_handler())
Trace: lv_task_handler ready (lv_task.c #192 lv_task_handler())
Trace: lv_task_handler started (lv_task.c #74 lv_task_handler())
Trace: lv_task_handler ready (lv_task.c #192 lv_task_handler())
Trace: lv_task_handler started (lv_task.c #74 lv_task_handler())
Trace: lv_task_handler ready (lv_task.c #192 lv_task_handler())
Trace: lv_task_handler started (lv_task.c #74 lv_task_handler())
Trace: lv_task_handler ready (lv_task.c #192 lv_task_handler())
Trace: lv_task_handler started (lv_task.c #74 lv_task_handler())
Trace: lv_task_handler ready (lv_task.c #192 lv_task_handler())
Trace: lv_task_handler started (lv_task.c #74 lv_task_handler())
Trace: lv_task_handler ready (lv_task.c #192 lv_task_handler())
Trace: lv_task_handler started (lv_task.c #74 lv_task_handler())
Trace: lv_task_handler ready (lv_task.c #192 lv_task_handler())
Trace: lv_task_handler started (lv_task.c #74 lv_task_handler())
Trace: lv_task_handler ready (lv_task.c #192 lv_task_handler())
Trace: lv_task_handler started (lv_task.c #74 lv_task_handler())
Trace: lv_task_handler ready (lv_task.c #192 lv_task_handler())
Trace: lv_task_handler started (lv_task.c #74 lv_task_handler())
Trace: lv_task_handler ready (lv_task.c #192 lv_task_handler())
Trace: lv_task_handler started (lv_task.c #74 lv_task_handler())
Trace: lv_task_handler ready (lv_task.c #192 lv_task_handler())
Trace: lv_task_handler started (lv_task.c #74 lv_task_handler())
Trace: lv_task_handler ready (lv_task.c #192 lv_task_handler())
What am I doing wrong.
The GUI is created just fine.