This is an old revision of the document!


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.

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 rulam manual 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.1730121629.txt.gz · Last modified: 2024/10/28 15:20 by dan.tudose
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