This shows you the differences between two versions of the page.
si:laboratoare:04 [2024/10/27 17:33] radu_ioan.pascale fix entry point config name |
— (current) | ||
---|---|---|---|
Line 1: | Line 1: | ||
- | ===== Laboratorul 04. Nuttx - LVGL, timere, butoane ===== | ||
- | |||
- | Scopurile laboratorului: | ||
- | |||
- | * Familiarizarea cu o bibliotecă populară pentru aplicații grafice pentru dispozitive embedded - [[https://lvgl.io/|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**. Placuta 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''. | ||
- | |||
- | [[https://github.com/radupascale/smartwatch-licenta|{{ si:laboratoare:pcb2_no_bg.png?500 }}]] | ||
- | |||
- | 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 [[https://lvgl.io/demos|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 [[https://docs.lvgl.io/master/intro/basics.html|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. | ||
- | |||
- | <code C> | ||
- | /* ... */ | ||
- | 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); | ||
- | } | ||
- | /* ... */ | ||
- | </code> | ||
- | |||
- | Output: | ||
- | [[https://docs.lvgl.io/master/examples.html#a-very-simple-hello-world-label|{{ si:laboratoare:hello_lvgl.png }}]] | ||
- | |||
- | 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: | ||
- | - Timer-ul este configurat ca la generarea unui semnal sa apeleze din thread-ul principal functia de callback pentru tratarea semnalelor. | ||
- | - 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 [[https://github.com/radupascale/hectorwatch-nuttx|link]] si urmati instructiunile din README pentru a clona repository-ul cu suportul pentru laborator si pentru a instala toolchain-ul pentru **ESP32-S3**. | ||
- | |||
- | <note important> | ||
- | Cititi cu atentie instructiunile legate de procesul de //flashuire// al ceasului. | ||
- | </note> | ||
- | |||
- | **1.** Config: | ||
- | * Pentru a incepe sa lucrati la laborator selectati si compilati cu configuratia ''lab04si'': | ||
- | |||
- | <note tip>''./tools/configure.sh -l ./boards/custom-boards/esp32s3-hectorwatch/configs/lab04si''.</note> | ||
- | |||
- | * 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 [[https://docs.lvgl.io/master/API/widgets/label/lv_label.html#_CPPv421lv_label_set_text_fmtP8lv_obj_tPKcz|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. | ||
- | |||
- | <note info> | ||
- | 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. | ||
- | </note> | ||
- | |||
- | **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 ==== | ||
- | * [[https://nuttx.apache.org/docs/latest/faq/index.html#how-to-start-directly-my-application-instead-starting-nsh|How to start directly my application instead starting NSH]] | ||
- | * [[https://docs.lvgl.io/master/intro/basics.html|LVGL Basics]] | ||
- | * [[https://docs.lvgl.io/8.3/porting/timer-handler.html|Timer Handler LVGL]] | ||
- | * [[https://docs.lvgl.io/8.3/widgets/core/label.html|Labels in LVGL]] | ||
- | * [[https://nuttx.apache.org/docs/latest/reference/user/07_signals.html|NuttX Signal Interface]] | ||
- | * [[https://nuttx.apache.org/docs/latest/components/drivers/character/timers/timer.html|Timer Driver in NuttX]] | ||