Arduino Questions

Description

What MCU/Processor/Board and compiler are you using?

What do you want to achieve?

  • Learn the library so I can effectively add quality screened UIs to MCU projects\products.

What have you tried so far?

  • Using the stated board and display, I was able to create a project that runs the slider example based from the STM32_TFT_eSPI_Slider example.

Code to reproduce

#include <Arduino.h>
#include <SPI.h>
#include <lvgl.h>
#include <Wire.h>
#include "TouchScreen.h"
#include <Adafruit_HX8357.h>

#define LED_PIN 2
#define YP A2  // must be an analog pin, use "An" notation!
#define XM A1  // must be an analog pin, use "An" notation!
#define YM A5   // can be a digital pin
#define XP A4   // can be a digital pin

#define TS_MINX 240
#define TS_MINY 315
#define TS_MAXX 840
#define TS_MAXY 760

#define TFT_CS   13
#define TFT_DC   12
#define STMPE_CS 32
#define TFT_RST  11
#define TFT_ROTATION 1 // Landscape orientation

//Ticker tick; /* timer for interrupt handler */
Adafruit_HX8357  tft(TFT_CS, TFT_DC, TFT_RST);
static lv_disp_buf_t disp_buf;
static lv_color_t buf[LV_HOR_RES_MAX * 10];

lv_obj_t * slider_label;
int screenWidth = 480;
int screenHeight = 320;

TouchScreen touch = TouchScreen(YM, XP, YP, XM, 300);

/* By Bodmer in https://github.com/Bodmer/TFT_eSPI/issues/581
   faster and more efficient than previous one: */
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.pushColors(&color_p->full, w * h, true);
  tft.writePixels(&color_p->full, w * h, true, true);
  tft.endWrite();

  lv_disp_flush_ready(disp);
}

bool my_touchpad_read(lv_indev_drv_t * indev_driver, lv_indev_data_t * data)
{
    
    int16_t touchX, touchY;
    bool touched = false;
    //bool touched = touch.getXY(touchX, touchY);  //  bool TFT_eTouch<T>::getXY(int16_t& x, int16_t& y)
    
    TSPoint p = touch.getPoint();
    p.x = map(p.x, TS_MINX, TS_MAXX, tft.width(), 0);
    p.y = map(p.y, TS_MINY, TS_MAXY, tft.height(), 0);
    if (p.z > touch.pressureThreshhold) {
        touched = true;
        Serial.print("X = "); Serial.print(p.x);
        Serial.print("\tY = "); Serial.print(p.y);
        Serial.print("\tPressure = "); Serial.println(p.z);      
    }

    touchX = p.x;
    touchY = p.y;
    
    if(!touched)
    {
      return false;
    }

    if(touchX>screenWidth || touchY > screenHeight)
    {
    //   Serial.println("Y or y outside of expected parameters..");
    //   Serial.print("y:");
    //   Serial.print(touchX);
    //   Serial.print(" x:");
    //   Serial.print(touchY);
    }
    else
    {
		
      data->state = touched ? LV_INDEV_STATE_PR : LV_INDEV_STATE_REL; 
  
      /*Save the state and save the pressed coordinate*/
      //if(data->state == LV_INDEV_STATE_PR) touchpad_get_xy(&last_x, &last_y);
     
      /*Set the coordinates (if released use the last pressed coordinates)*/
      data->point.x = touchX;
      data->point.y = touchY;
  
    //   Serial.print("Data x");
    //   Serial.println(touchX);
      
    //   Serial.print("Data y");
    //   Serial.println(touchY);

    }

    return false; /*Return `false` because we are not buffering and no more data to read*/
}

void printEvent(String Event, lv_event_t event)
{
  
  Serial.print(Event);
  Serial.printf(" ");

  switch(event) {
      case LV_EVENT_PRESSED:
          Serial.printf("Pressed\n");
          break;

      case LV_EVENT_SHORT_CLICKED:
          Serial.printf("Short clicked\n");
          break;

      case LV_EVENT_CLICKED:
          Serial.printf("Clicked\n");
          break;

      case LV_EVENT_LONG_PRESSED:
          Serial.printf("Long press\n");
          break;

      case LV_EVENT_LONG_PRESSED_REPEAT:
          Serial.printf("Long press repeat\n");
          break;

      case LV_EVENT_RELEASED:
          Serial.printf("Released\n");
          break;
  }
}

void slider_event_cb(lv_obj_t * slider, lv_event_t event)
{

  //printEvent("Slider", event);

  if(event == LV_EVENT_VALUE_CHANGED) {
      static char buf[4];                                 /* max 3 bytes  for number plus 1 null terminating byte */
      snprintf(buf, 4, "%u", lv_slider_get_value(slider));
      lv_label_set_text(slider_label, buf);               /*Refresh the text*/
	  int16_t value = lv_slider_get_value(slider);
	  value = map(value, 0, 100, 0, 255);
	  //analogWriteFrequency(2000); // Set PMW period to 2000 Hz instead of 1000
	  analogWrite(LED_PIN, value);//8-bit by default
  }
}

void setup() {

    Serial.begin(115200); /* prepare for possible serial debug */
    pinMode(LED_PIN, OUTPUT);
    
    lv_init();

    tft.begin(); /* TFT init */
    tft.setRotation(1);
    
    lv_disp_buf_init(&disp_buf, buf, NULL, LV_HOR_RES_MAX * 10);

    /*Initialize the display*/
    lv_disp_drv_t disp_drv;
    lv_disp_drv_init(&disp_drv);
    disp_drv.hor_res = screenWidth;
    disp_drv.ver_res = screenHeight;
    disp_drv.flush_cb = my_disp_flush;
    disp_drv.buffer = &disp_buf;
    lv_disp_drv_register(&disp_drv);

    lv_indev_drv_t indev_drv;
    lv_indev_drv_init(&indev_drv);             /*Descriptor of a input device driver*/
    indev_drv.type = LV_INDEV_TYPE_POINTER;    /*Touch pad is a pointer-like device*/
    indev_drv.read_cb = my_touchpad_read;      /*Set your driver function*/
    lv_indev_drv_register(&indev_drv);         /*Finally register the driver*/

    //Set the theme..
    // lv_theme_t * th = lv_theme_night_init(210, NULL);     //Set a HUE value and a Font for the Night Theme
    // lv_theme_set_current(th);

    lv_obj_t * scr = lv_cont_create(NULL, NULL);
    lv_disp_load_scr(scr);

    /* Create simple label */
    lv_obj_t *label = lv_label_create(lv_scr_act(), NULL);
    lv_label_set_text(label, "PB6 LED DIMMER");
    lv_obj_align(label, NULL, LV_ALIGN_CENTER, 0, -50);

    /* Create a slider in the center of the display */
    lv_obj_t * slider = lv_slider_create(lv_scr_act(), NULL);
    lv_obj_set_width(slider, screenWidth-75);                        /*Set the width*/
    lv_obj_set_height(slider, 40);
    lv_obj_align(slider, NULL, LV_ALIGN_CENTER, 0, 0);    /*Align to the center of the parent (screen)*/
    lv_obj_set_event_cb(slider, slider_event_cb);         /*Assign an event function*/

    /* Create a label below the slider */
    slider_label = lv_label_create(lv_scr_act(), NULL);
    lv_label_set_text(slider_label, "0");
    lv_obj_set_auto_realign(slider, true);
    lv_obj_align(slider_label, slider, LV_ALIGN_OUT_BOTTOM_MID, 0, 10);
}

void loop() {
  lv_task_handler(); /* let the GUI do its work */
  delay(5);
}

Questions:

I must preface these questions with the following: 1) I’m not a traditionally trained engineer (no college degree in engineering). I’m just a self taught weekend warrior who’s strong with Python and can make my way around a C\C++ Arduino sketch. 2) C/C++ outside of the Arduino IDE or PlatformIO is a bit foreign to me. 3) I suck at math and general graphics related topics (buffer, double buffer, triple buffer, vsync, etc.) I can learn this stuff eventually.

Arduino Questions:

  1. When will the lv_arduino project be updated to v7?
  2. in the lv_arduino (v6) examples, there is a my_touchpad_read function that allows me to get the touched point X/Y from my input device (through indev_drv.read_cb = my_touchpad_read). This worked for me after calibrating my input device. After trying to drop in the v7 library into my project ignoring the lv_arduino library) my touch device no longer works. I notice a lack of (or I just missed it) an equivalent my_touchpad_read function in the lv_examples (v7). Where has this functionality been moved too? How can I make my Arduino project recognize input?
  3. The above code works (slider widget slides from touch input) with the lv_arduino v6. But not when I try to use the standard lvgl v7 library. I can see the slider change styles to a more modern slider when I change to v7. I get no compile errors with v7, I’m just not getting any touch input.

MicroPython Questions:

  1. I see that there is a port to MicroPython. As much as I love Python, I’m concerned that the performance doesn’t compare to C/C++. Is this true? Or can I achieve an equivalent user experience with MicroPython?
  2. Has MP been updated to v7?
  3. Would the MP version work under Adafruit’s CircuitPython? I thought (but could be wrong) that you can use all MP under CP, but not the other way around.

Screenshot and/or video

  • No Screenshots to show

@amirgon Perhaps you can help with the MicroPython questions.

TL;DR Soon. It was waiting for 7.0.1 to be released.

I assume it’s missing because you added 7.0 manually. I’d suggest copying the original implementation from the 6.x project.

The my_touchpad_read function is in my code and I’m using the following in the setup() function to register it:

lv_indev_drv_t indev_drv;
lv_indev_drv_init(&indev_drv);             /*Descriptor of a input device driver*/
indev_drv.type = LV_INDEV_TYPE_POINTER;    /*Touch pad is a pointer-like device*/
indev_drv.read_cb = my_touchpad_read;      /*Set your driver function*/
lv_indev_drv_register(&indev_drv);         /*Finally register the driver*/

The problem is that when I compile the same code with the v6 library, touch functionalities work. When I compile the same exact code with the v7 library, touch functionality disappears.

One thing I haven’t tried yet is using the non-arduino v6 library and see if touch works for me then. If it does, that tells me something in my v6 code has to change to work with v7.

Thanks for this info. Can’t wait to test it out when available.

lvgl Micropython binding is only used as an API to lvgl functions.
There is no functionality implemented in Python. Only native module that bridges Micropython and lvgl C API.
This means that all the heavy-lifting is still done in C: drawing the objects, animation etc.
When you use lvgl with Micropython, the Python code only orchestrates lvgl objects creation and configuration, and event handling. These usually require very little processing power and in most cases you won’t feel the difference in terms of performance and power.

Yes.
It wasn’t merged to main branch yet, but you can use dev-7.0 branch until it does.
Not all example code and drivers were ported to v7 yet, but core lvgl works well.
You can try the online simulator.

In principle, yes.
lvgl is statically linked into Micropython on lv_micropython.
lvgl and its Micropython-binding code can be ported to other forks of Micropython, CircuitPython included.

Some people already ported it to their Micropython fork because they wanted a more up-to-date Micropython version, or some support for a different microcontroller. Others just use our lv_micropython fork.

Regarding CircuitPython, as far as I know, no one bothered doing that porting work yet.
I think CircuitPython has its own graphics library and Adafruit are putting a lot of effort in it, so they have very little motivation integrating some other graphics library other than their own.
It’s all open source with permissive licensing, of course, so if someone decides it’s worth the effort it can be easily done.

I have some notes and hints as to how to port lvgl micropython binding to another Micropython fork.

1 Like

I hope that lv_arduino with version 7.0.1 will be released until end of this week. For now everyone can use pre-release in my github. Unfortunately I’m not able to test STM32 example, because I don’t have any hardware with that CPU at hand.

Thanks, Pablo! I’m pretty busy this week\weekend so hopefully when I’m ready to test it out next week v7 will be released. If not I’ll try the pre-release version.