Laboratorul 04. Nuttx - LVGL, timere, butoane

Scopurile laboratorului:

  • Familiarizarea cu o bibliotecă populară pentru aplicații grafice pentru dispozitive embedded - LVGL.
  • Utilizarea de evenimente asincrone generate de timere si butoane.

Prezentarea suportului de laborator

In cadrul laboratorului vom folosi un smartwatch ce are la baza un microcontroller ESP32-S3. Placa vine dotata cu multe componente externe (dupa cum se poate vedea si in imaginea de mai jos), dar astazi vom folosi doar display-ul, un timer hardware si butonul BOOT_BUTTON.

Butoanele sunt denumite in felul urmator, incepand din stanga sus, in sens trigonometric:

  • RESET_BUTTON
  • BOOT_BUTTON
  • DOWN_BUTTON
  • UP_BUTTON

LVGL pe scurt

LVGL (Lightweight Versatile Graphics Library) este o bibliotecă open-source folosita pentru a crea interfete grafice pe dispozitive embedded. Biblioteca functioneaza pe majoritatea microcontrollerelor ce indeplinesc minimul de resurse necesar - 32kB RAM si 128 kB de memorie flash. De asemenea, biblioteca pune la dispozitie si zeci de exemple de layout-uri care pot fi adaptate in functie de use-case, vedeti demo-uri aici.

Utlizarea bibliotecii presupune initializarea de catre aceasta a unui obiect de tip lv_display_t ce reprezinta o interfata catre driver-ul ecranului pe care se va face afisarea. In cadrul laboratorului de astazi, partea de setup este deja implementata si ne vom concentra doar pe cum anume putem folosi API-ul pentru a crea widget-uri (puteti citi mai multe aici).

Pe scurt, o aplicatie standard ce foloseste LVGL va face urmatorii pasi:

  • Initializeaza biblioteca si display-ul (initializarea obiectului de tip lv_display_t, drawbuffere, callback-uri, etc.).
  • Crearea unui thread separat care verifica periodic daca display-ul trebuie updatat.
  • Apelarea functiilor de biblioteca in thread-ul principal pentru a desena pe display. Aceste functii creeaza task-uri ce vor fi procesate pe rand de catre celalalt thread (ceea ce se va face in cadrul laboratorului).

Pentru a afisa pe un ecran, se pleaca de la un lv_obj_t ce reprezinta cel mai simplu obiect care poate fi randat. Acesta are coordonate, un parinte, un stil si optional alte obiecte copil. Impartirea ierarhica a elementelor ce trebuie desenate pe ecran ne permite printre altele sa aplicam transformari simultan asupra mai multor obiecte si sa aliniem widget-uri noi raportat la ce este deja existent pe ecran. Exemplul de cod de mai jos ilustreaza cum putem crea o “scena” noua cu un widget simplu pe care scriem un mesaj.

/* ... */
void lv_hello(void)
{
    /* Cream o scena noua pe care sa desenam si o setam ca fiind scena activa */
    lv_obj_t *screen = lv_obj_create(NULL);
    lv_scr_load(screen);
 
    /* Putem seta culoarea default modificand stilul obiectului */
    lv_obj_set_style_bg_color(lv_screen_active(), lv_color_hex(0x003a57), LV_PART_MAIN);
 
    /* Cream un widget nou de tipul label al carui parinte va fi "screen" */
    lv_obj_t *label = lv_label_create(lv_screen_active());
    lv_label_set_text(label, "Hello world");
 
    /* Putem modifica de asemenea culoarea textului si putem centra obiectul relativ la parinte */
    lv_obj_set_style_text_color(lv_screen_active(), lv_color_hex(0xffffff), LV_PART_MAIN);
    lv_obj_align(label, LV_ALIGN_CENTER, 0, 0);
}
/* ... */

Output:

Biblioteca ne permite astfel sa ne cream mai multe pagini si sa le incarcam dinamic folosind lv_screen_load.

Utilizarea de evenimente asincrone pentru timere si butoane in NuttX

Suportul de laborator este configurat astfel incat device-urile atat pentru butoane, cat si pentru timer sa fie inregistrate in /dev/buttons si /dev/timer0. Interactiunea cu ele este similara cu ce s-a discutat in cadrul laboratorului 2 la senzorul de lumina. Se apeleaza open pentru a obtine un file descriptor catre device, iar folosind ioctl putem configura alti parametrii cum ar fi frecventa de generare a intreruperilor timer-ului.

Pe langa aceste configurari de baza, in cadrul scheletului de laborator puteti gasi codul necesar pentru tratarea evenimentelor asincrone generate de timer/buton in doua modalitati diferite. Pe scurt:

  1. Timer-ul este configurat ca la generarea unui semnal sa apeleze din thread-ul principal functia de callback pentru tratarea semnalelor.
  2. Pe de alta parte, un task separat trateaza evenimentele generate de apasarea butonului. Task-ul se afla in majoritatea timpului in starea de Waiting datorita apelului functiei sigwaitinfo.

Exerciții

0. Setup:

  • Accesati urmatorul link si urmati instructiunile din README pentru a clona repository-ul cu suportul pentru laborator si pentru a instala toolchain-ul pentru ESP32-S3.

Cititi cu atentie instructiunile legate de procesul de flashuire al ceasului.

In cazul in care aveti erori legate de versiunea de esptool pe masina virtuala, incercati sa creati un environment nou de python:

python3 -mvenv .venv
source .venv/bin/activate
pip install esptool

1. Config:

  • Pentru a incepe sa lucrati la laborator selectati si compilati cu configuratia lab04si:

./tools/configure.sh -l ./boards/custom-boards/esp32s3-hectorwatch/configs/lab04si.

  • Rulati aplicatia lab04si din NSH.
  • Ne dorim sa configuram aplicatia astfel incat sa nu fie nevoie sa ne conectam cu picocom pentru a rula aplicatia lab04si de fiecare data cand o sa modificam ce se afiseaza pe ecran. Pentru asta, e nevoie sa facem urmatoarele modificari in menuconfig:
    • CONFIG_INIT_ENTRYPOINT = “lab04si_main”
    • CONFIG_BOARD_LATE_INITIALIZE = y
    • In NSH_LIBRARY —→ Have architecture-specific initialization = n

2. Updatarea continutului afisat de LVGL:

  • Accesati directorul nuttx-apps/examples/lab04si si urmați TODO-urile marcate cu (2) în schelet.
  • Adăugați o nouă etichetă aliniata sub prima care să afișeze timpul în formatul minute:secunde cu valoarea implicită 00:00.
    • Puteți folosi fie sprintf într-un buffer, fie să formatați direct cu lv_label_set_text_fmt()).
    • Pentru aliniere, puteti folosi lv_align_obj_to.

3. Utilizarea timerelor hardware în NuttX

  • Urmați TODO-urile marcate cu (3) din schelet.
  • Timer0 este deja configurat (urmariti funcția setup_timers apelată la începutul execuției programului pentru detalii). Ne dorim să realizăm următoarele lucruri:
    • să contorizăm secundele în handler-ul timer-ului.
    • să actualizăm ecranul cu numărul de minute/secunde *numărate de timer* in bucla principala.

Timer-ul este configurat să genereze evenimente o dată pe secundă; puteți modifica acest comportament schimbând valoarea lui `TIMER_INTERVAL` în scheletul de cod.

BONUS. Gestionarea inputului de la utilizator:

  • Urmați TODO-urile marcate cu (BONUS) din schelet.
  • Modificați codul astfel încât inițial timer-ul să fie oprit.
  • Ne dorim ca apăsarea butonului BOOT (stanga jos, vezi mai sus) să oprească/pornească timer-ul.

Resurse

si/laboratoare/04.txt · Last modified: 2024/10/29 19:54 by radu_ioan.pascale
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0