LVGL v9.3 using PlatformIO barebones example (and do I need TFT_eSPI)

Description

I’m using a Teensy 4.1 with an Adafruit 2.8" display - the ILI9431 one with the resistive analog touch.

What do you want to achieve?

A barebones implementation of display and touch.

What have you tried so far?

I have TFT_eSPI up and running on my board/display but my first question is: do I still need TFT_eSPI for 9.x?

In the LVGL documentation there is now mention of a built in ILI9341 driver but this requires two ‘platform-dependent functions’ which sounds like it is probably intended for display developers rather than app developers?

The second question: is there a barebones example of a PlatformIO project? One that uses the ILI9341 analog touch would be great, but I’d settle for anything that compiles and draws something on my display! I can get LVGL to do the former in PlatformIO (with many, many warnings), but not the latter - I suspect I’m missing a crucial step.

There seems to be plenty of 8.x out there but not so much 9.x - and the LVGL PlatformIO documentation page is a little light - as in it just says ‘TODO’.

It would appear my google-fu is not strong at this time.

Many thanks

It would seem my typing is not strong either - title should be ‘9.2’…

Here you can see what is part of high level support. lvgl/src/drivers/display/ili9341/lv_ili9341.c at master · lvgl/lvgl · GitHub

But this isnt low level hw support.

1 Like

Thank you Marian. I have made progress - it would seem you do need the TFT_eSPI library but it gets created and initialised by LVGL.

For future explorers, here is roughly how I did it:

  1. Add TFT_eSPI and lvgl liraries to your project via PlatformIO library manager
  2. Copy lv_conf.h to a src dir (in my case include)
  3. Update platformio.ini for TFT_eSPI pins and lv_conf.h location:
[env:teensy41]
platform = teensy
board = teensy41
framework = arduino
lib_deps = 
	bodmer/TFT_eSPI@^2.5.43
	lvgl/lvgl@^9.2.2
	adafruit/Adafruit TouchScreen@^1.1.5
build_flags = 
	-D USER_SETUP_LOADED=1
	-D ILI9341_DRIVER=1
	-D TFT_WIDTH=240
	-D TFT_HEIGHT=320
	-D TFT_MISO=12
	-D TFT_MOSI=11
	-D TFT_SCLK=13
	-D TFT_CS=10
	-D TFT_DC=9
	-D TFT_RST=-1
	-D TOUCH_CS=-1
	-D LOAD_GLCD=1
	-D SPI_FREQUENCY=80000000
	-D LV_CONF_PATH="${PROJECT_DIR}/include/lv_conf.h"
  1. In lv_conf.h update the following to 1:
    4.1 #define LV_USE_TFT_ESPI 1
    4.2 #define LV_USE_ILI9341 1

Edit: I’m not convinced I’m using the inbuilt ILI9341 driver as I can set it back to zero with no ill effect. So I guess my first question still stands…

I cannot find any documentation on LV_USE_TFT_ESPI so just looked at the source code for a clue. It does not implement an SPI touch controller but that is not a problem for me as the Adafruit display uses analog pins.

  1. Your main.cpp should look something like this (I’m currently just playing, so this will likely get refactored into separate files):
/*
 */
#include <Arduino.h>
#include <lvgl.h>
#include <TouchScreen.h>

#define DRAW_BUF_SIZE (TFT_WIDTH * TFT_HEIGHT / 10 * (LV_COLOR_DEPTH/8))
//For the Adafruit TouchScreen.h
const uint8_t TOUCHSCREEN_XP = A6;  // Y+ must be an analog pin, use "An" notation!
const uint8_t TOUCHSCREEN_YP = A9;  // X- must be an analog pin, use "An" notation!
const uint8_t TOUCHSCREEN_XM = A8;  // Y- can be a digital pin
const uint8_t TOUCHSCREEN_YM = A7;  // X+ can be a digital pin
// For better pressure precision, we need to know the resistance
// between X+ and X- Use any multimeter to read it
// For the one we're using, it's 300 ohms across the X plate
const uint16_t TOUCHSCREEN_OHMS = 300;
/**
 * These four members define the active area (boundaries) of 
 * the touchscreen.
 * We swap these values around with rotate or flipX, flipY
 * @TODO store and read these from EEPROM
 */
uint16_t tsRight = 915;
uint16_t tsTop = 115;
uint16_t tsBottom = 915;
uint16_t tsLeft = 105;



uint32_t draw_buf[DRAW_BUF_SIZE / 4];

TouchScreen ts = TouchScreen(TOUCHSCREEN_XP, TOUCHSCREEN_YP, TOUCHSCREEN_XM, TOUCHSCREEN_YM, TOUCHSCREEN_OHMS);


// 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)
	//   // a point object holds x y and z coordinates
	TSPoint p = ts.getPoint();
    
	//   // we have some minimum pressure we consider 'valid'
	//   // pressure of 0 means no pressing!
	if (p.z > ts.pressureThreshhold) {
    	data->state = LV_INDEV_STATE_PRESSED;
		// Set the coordinates
		data->point.x = max(1, map(p.x, tsLeft, tsRight, 1, TFT_WIDTH));
		data->point.y = max(1, map(p.y, tsTop, tsBottom, 1, TFT_HEIGHT));
		Serial.printf("Touch X: %i, Y: %i \n", data->point.x, data->point.y);
    } else {
	    data->state = LV_INDEV_STATE_RELEASED;
	}
}

void setup() {
  Serial.begin(115200);
  lv_init();

  /* Set a tick source so that LVGL will know how much time elapsed. */
  lv_tick_set_cb((lv_tick_get_cb_t)millis);

  /* Create a display using the inbuilt LVGL support for TFT_eSPI*/
  lv_display_t *disp = lv_tft_espi_create(TFT_WIDTH, TFT_HEIGHT, draw_buf, sizeof(draw_buf));

  lv_display_set_rotation(disp, LV_DISPLAY_ROTATION_90);
  
  // 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);

  /* Create a simple label. */
  lv_obj_t *label = lv_label_create( lv_scr_act() );
  lv_label_set_text( label, "Hello Teensy, I'm LVGL v9!" );
  lv_obj_align( label, LV_ALIGN_CENTER, 0, 0 );

}

 void loop(void) {
	lv_task_handler();
}

Note: I’m using Adafruit’s Touchscreen for the analog touch interface and I’m pretty sure I have to add more LVGL stuff to the loop() :slight_smile:

This seems to work so far but any comments on whether I am doing it ‘right’ would be very welcome.