Laboratorul 02. I2C - Haptics, Accelerometru, Giroscop

În laboratorul de astăzi veți învăța cum să interactionați cu diferite periferice prin I2C și cum datele de la hardware sunt transmise utilizatorului prin diferite niveluri de redirectare. Vom explora atât noțiuni low-level cât și aspecte mai high-level (arhitectura software a driver-elor in NuttX) construite peste.

Un modul de kernel (sau un device driver) este o bucată specializată de cod care este compilată și adăugată la kernel-ul sistemului de operare. În acest mod, sistemul de operare are posibilitatea de a interacționa cu diferite periferice - în absența driverelor, un kernel nu ar putea accesa lumea exterioară CPU-ului. De exemplu, dacă ne dorim ca sistemul nostru să poată transfera date prin controller-ul de I2C, avem nevoie de un driver pentru I2C care să programeze aceste tranzacții de transfer de date. Analog, dacă ne dorim să interacționăm cu un senzor, avem nevoie de un device driver care știe să programeze acel senzor.

Aproximativ 80% din codul unui sistem de operare este format din codul pentru drivere.

Din punct de vedere al user-ului, driverele pot să fie expuse în două moduri:

  • char device driver - în Linux sunt folosite pentru mouse și tastatură, de exemplu, iar în NuttX pentru senzori, printre altele. Pe scurt, dispozitive cu rată mică de transfer de date, care functionează la nivel de caracter (byte).
  • block device driver - folosite pentru hdd-uri, sdd-uri, device-uri care au nevoie să transfere date la nivel de blocuri (4KB de obicei).

I2C

I2C (Inter-Integrated Circuit) este un protocol de comunicație serială dezvoltat de Philips (acum NXP) în anii ’80, folosit pe scară largă pentru a conecta microcontrolere cu senzori, memorii, afișaje și alte periferice. Este foarte popular în proiecte embedded datorită simplității și numărului redus de pini necesari.

I2C este un protocol care functioneaza sub paradigma master-slave prin care un “master” (de obicei microcontroller-ul, in cazul nostru ESP32S3-ul) citeste sau scrie date de pe un device denumit “slave” (cele mai comune device-uri de acest fel in lumea embedded fiind senzorii).

Astfel, magistrala (bus-ul) este definita din doua linii de comunicatie:

  • SDA (Serial Data) - folosita pentru transmisia datelor.
  • SCL (Serial Clock) - folosita pentru propagarea ceasului dupa care se face esantionarea datelor.

Transmisia datelor se face in mod bidirectional (master → slave in cazul operatiei de write si slave → master in caz de read), insa nu este full-duplex - doar un singur device poate sa detina controlul SDA-ului in orice moment de timp. SCL-ul este intotdeauna generat de master-ul comunicatiei si este propagat catre toate dispozitivele de tip slave.

Fiecare dispozitiv slave este identificat printr-o adresa pe 7 biti la care se adauga un bit pentru R/W. Astfel:

  • pentru operatiile de write, master-ul pune pe magistrala si datele de transmis, iar slave-ul este in modul de “listening”.
  • pentru operatiile de read, dupa transmisia adresei si a bit-ului de R/W, slave-ul preia controlul SDA-ului, iar master-ul intra in modul de “listening” pentru a receptiona datele.

DRV2605L - driver haptic

DRV2605L este un driver haptic proiectat cu scopul de a controla motoare de vibratie care in final sa poata oferi feedback utilizatorului prin vibratii. Avantajul acestui device este ca, desi poate fi programat sa genereze vibratii constante, vine cu o biblioteca interna de efecte haptice, fara a fi nevoie ca user-ul sa creeze trenul de vibrații manual.

In cadrul NuttX, arhitectura software prin care o aplicatie interactioneaza cu senzorul DRV2605L presupune mai multe niveluri de redirectare:

Codul este impartit in doua componente, upper half driver si lower half driver. Deoarece majoritatea codului unui driver poate fi refolosit, a fost introdus upper half driver pentru a oferi un API uniformizat si standardizat pentru toate device-urile. Componenta care este particulara fiecarui device si se ocupa de accesul efectiv la hardware este driver-ul lower half, neaccesibil user-ului in mod direct. Acesta este invocat de catre driver-ul upper half printr-un API intern.

LSM6DSL - accelerometru si giroscop

LSM6DSL este un senzor 3D care combina in acelasi dispozitiv un accelerometru si un giroscop. Desi pe sistemul nostru este conectat prin I2C, acesta poate comunica si prin SPI.

  • accelerometrul detecteaza schimbarile de viteza si poate determina inclinarea dispozitivului (desi nu este atat de precis fara folosirea giroscopului). Dispozitivul masoara acceleratia in m/s², insa in NuttX datele obtinute sunt exprimate in mg (mili-g), unde 1g este echivalent cu acceleratia gravitationala (9.81 m/s²).
  • giroscopul masoara cat de repede se roteste dispozitivul in jurul propriilor axe folosind dps (degrees per second), iar in NuttX datele obtinute de la senzor sunt exprimate in mdps (mili-dps).

Spre deosebire de DRV2605L, arhitectura software este mai simpla in cazul acestui device, sistemul de operare oferind doar un singur nivel de redirectare:

Apelurile de sistem sunt interceptate de catre driver-ul dispozitivului prin char device-ul expus in /dev/lsm6dsl, iar mai apoi comenzile de read/write sunt trimise direct device-ului hardware, fara a mai exista o componenta intermediara uniforma pentru toate device-urile. Acest API este imprumutat din Linux si este considerat “obsolete” in NuttX, doar device-urile “legacy” utilizand aceasta abordare.

Exerciții

Pentru a putea rula exercitiile, este nevoie să compilați NuttX folosind hacktorwatch:iot, la care va trebui sa activati manual cateva config-uri folosindu-va de sistemul de build (make menuconfig). Astfel, veti activa atat compilarea codului de driver si initializarea efectiva a hardware-ului, cat veti si incarca pe placa aplicatii de demo pe care le puteti rula.

Ca sa folositi senzorul de haptics, aveti nevoie de urmatoarele config-uri:

  • CONFIG_FF_DRV2605L
  • CONFIG_DRV2605L_TS2200_LIBRARY_A
  • CONFIG_EXAMPLES_DRV2605L

Atentie la dependintele lui CONFIG_FF_DRV2605L. In cadrul acestui exercitiu de set-up va trebui sa determinati care sunt acele dependinte si sa le activati mai intai pe acelea.

Pentru a valida ca ati configurat NuttX corect, este suficient un simplu restart de ceas. Codul de initializare din cadrul sistemului de operare realizeaza o calibrare a senzorului de haptics la boot time, iar ceasul va vibra.

Cele doua config-uri de mai jos va vor oferi access la accelerometru si giroscop:

  • CONFIG_SENSORS_LSM6DSL
  • CONFIG_EXAMPLES_LSM6DSL_READER

La fel ca in cazul device-ului de haptics, atentie la dependintele acestor config-uri.

1. Pentru a va acomoda cu API-ul pe care NuttX il ofera pentru a interactiona cu cele doua device-uri, in cadrul acestui exercitiu va trebui sa inspectati codul si sa rulati aplicatiile de demo disponibile in repository-ul nuttx-apps.

  1. nuttx-apps/examples/drv2605l/ initializeaza device-ul cu anumite efecte de vibrare (upload_rom_effect, upload_constant_effect). Apelarea acestora se face ulterior, “on demand”, prin play_effect.
  2. nuttx-apps/examples/lsm6dsl_reader afiseaza la consola o data la doua secunde datele obtinute de la accelerometru si giroscop. Observati modul de interactiune cu senzorul: acesta este expus printr-o intrare in /dev/ care va trebui folosita in cadrul apelului de sistem open, iar mai apoi folosim apeluri de ioctl pentru a interactiona cu hardware-ul.
  3. Cautati definitiile pentru structurile de date folosite in ambele aplicatii.

Toate fișierele de tip header le puteți găsi în nuttx/include/nuttx/. Puteți căuta recursiv din linia de comandă folosind grep -r <string>.

2. In cadrul acestui exercitiu, vrem ca ceasul sa ne ofere informatii (prin vibrare) atunci cand viram stanga, respectiv dreapta.

  1. Folosindu-ne de lsm6dsl_reader vom citi datele oferite de accelerometru si vom determina directia de mers.
  2. Daca ceasul este nemiscat sau merge inainte nu va oferi niciun fel de feedback utilizatorului.
  3. drv2605l are o biblioteca interna de efecte de vibrare pe care o puteti consulta aici, la pagina 63. Alegeti doua efecte din acest tabel si incarcati-le pe ceas.
  4. In functie de directia de mers, vom rula in mod constant unul dintre cele doua efecte pana cand ceasul va reveni in stare initiala (ceasul este nemiscat sau sau se misca doar inainte).

Hint: pentru a opri un efect, trebuie sa scrieti o functie care realizeaza inversul lui play_effect. Parametrul care ne intereseaza si trebuie modificat este play.value (trebuie sa fie setat pe 0 - disabled).

Hint: pentru a putea face polling mai des pe senzor si sa obtineti date mai accurate este nevoie sa folositi usleep.

3. (Bonus) La exercitiul anterior, intensitatea de vibrare era absoluta (on/off). Ne dorim sa avem un mecanism mai complex prin care sa folosim vibrare graduala in functie de nivelul acceleratiei - cu cat acceleratia este mai mare, cu atat vibratia va fi mai puternica.

Resurse

si/iot2025/lab02.txt · Last modified: 2025/08/11 12:53 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