Îmbunătățirea proiectării sistemelor embedded prin utilizarea unei abordări hardware agnostice: Implementarea driverului

by gabi

Articolul prezintă modul de implementare a unui driver hardware agnostic în cadrul unui proiect. O abordare de tip “plug and play” poate fi benefică proiectanților de software embedded sau firmware indiferent de nivelul lor de experiență. Pentru a analiza funcțiile de bază implementate în driver împreună cu structura software a unui sistem embedded, citiți articolul “Îmbunătățirea proiectării sistemelor embedded prin utilizarea unei abordări hardware agnostice: Noțiuni de bază.”

Introducere

Proiectanții care lucrează cu sisteme embedded sunt nevoiți, de cele mai multe ori, să programeze driverul și, prin urmare, firmware-ul, pentru a se asigura că senzorii selectați își îndeplinesc funcțiile de bază dorite. Acest lucru presupune un consum destul de mare de timp. O soluție la această problemă este aceea de a combina hardware-ul cu software-ul și firmware-ul pentru a permite o abordare de tip “plug and play” pentru selectarea senzorilor și integrarea sistemului. Pe lângă faptul că se simplifică integrarea senzorilor, un driver agnostic din punct de vedere hardware oferă avantajul unei soluții gata de utilizare, care poate fi pusă în aplicare în proiectele viitoare. Acest articol va folosi, ca exemplu, un senzor IMU (unitate de măsurare inerțială), dar abordarea este scalabilă la alți senzori și componente. Driverul este configurat utilizând limbajul de programare C și testat cu un microcontroler generic.

Implementarea driverului

Toate imaginile la care se face referire sunt în anexă, unde cititorul poate găsi codul.

  • adis16500_rd_error_flag

Implementarea acestei funcții este disponibilă în figura 10 din anexă. Aceasta citește indicatorii de eroare conținuți în registrul ADIS16500_REG_DIAG_STAT care, în absența unei erori, are toți biții setați la 0. Există 10 erori posibile, astfel încât funcția va returna o structură numită ADIS16500_ERROR_FLAGS care conține 10 câmpuri booleene, fiecare câmp reprezentând o eroare specifică. Funcția citește, pur și simplu, registrul ADIS16500_REG_ DIAG_STAT și verifică biții acestuia cu anumite măști de eroare, iar ori de câte ori se găsește un bit setat la valoarea logică 1, câmpul respectiv din structură va fi setat la “true” (adevărat).

  • adis16500_rd_temp

Funcția de citire a temperaturii urmează aceeași abordare implementată în cazul accelerației și giroscopului (detaliată în articolul introductiv publicat în ediția trecută). Valoarea citită va fi exprimată în °C. Valoarea binară este conținută într-un registru de 16-biți, ADIS16500_REG_TEMP_OUT. După aceea, va avea loc conversia binară în complement față de doi. Odată ce valoarea în complement față de doi a fost obținută, aceasta va fi înmulțită cu factorul de scalare a temperaturii, care este exprimat în °C/LSB, obținându-se valoarea finală în °C, gata să fie înregistrată în pointerul transmis ca dată de intrare. Implementarea funcției este disponibilă la figura 9 din anexă.

  • adis16500_get_ts_usec

Această funcție este utilizată pentru a obține marca temporală (timestamp) a unității IMU în μs. Abordarea este exact aceeași ca pentru funcția adis16500_rd_temp. Implementarea este prezentată în figura 9 din anexă.

  • adis16500_rd_data_cntr

Procedura citește numărul de date care au fost transmise. Aceasta se face prin simpla citire a unui registru numit ADIS16500_REG_DATA_CNTR. Atunci când registrul atinge valoarea maximă, acesta repornește de la 0. Modul în care a fost implementată funcția este prezentat în figura 9 din anexă.

  • adis16500_wr_acc_calib

Este vorba despre funcția care trebuie invocată dacă proiectantul dorește să efectueze o calibrare personalizată a offsetului. În acest fel, se poate adăuga un offset la valoarea citită din regiștrii de date de ieșire, astfel încât valorile de calibrare x, y, z vor fi adăugate la datele de accelerație x, y, z. Intrarea funcției este un pointer către o structură de tip ADIS16500_XL_OUT. Această structură, din urmă, conține câmpuri de tip real (valori zecimale) x, y și z. Aici, scopul funcției este de a trece de la o valoare flotantă la o valoare în complement față de doi și apoi de la o valoare în complement față de doi la o valoare binară. Toți pașii sunt prezentați în figura 11 din anexă. În acest moment, valoarea binară trebuie să fie scrisă în regiștrii de bias, astfel încât, de exemplu, pentru axa x sunt de scris doi regiștri: ADIS16500_REG_X_ACCEL_BIAS_L pentru cei mai puțin semnificativi 16 biți și ADIS16500_REG_X_ACCEL_BIAS_H pentru cei mai semnificativi 16 biți. Același lucru este valabil și pentru axele y și z, în funcție de regiștrii lor de bias. Pentru a verifica dacă această procedură face lucrurile corecte, senzorul IMU a fost plasat cu axa z îndreptată spre cer, perpendicular pe sol. În această condiție, valorile accelerației sunt aproape 0 pentru axa x și axa y și aproape -9,81 m/s2 (-g) pentru axa z. Invocând funcția de calibrare și oferindu-i o structură de calibrare cu câmpurile x, y și z, toate egale cu -9,81 m/s2, se citește x = -9,81; y = -9,81; z = 0, deci funcția de compensare a calibrării funcționează.

  • adis16500_wr_gyro_calib

Funcția de calibrare a offsetului pentru giroscop urmează exact aceeași procedură ca și funcția pentru accelerație. Desigur, aceasta se realizează în conformitate cu fișa tehnică și cu regiștrii de bias ai giroscopului.

Articolul este axat pe driverul senzorului IMU, dar structura software/firmware va fi aceeași pentru fiecare tip de senzor. Prin urmare, pentru a generaliza implementarea la toți senzorii, se poate spune că singura diferență o constituie protocolul de comunicație (SPI, I2C, UART etc.) care “leagă” microcontrolerul de senzor. Modul în care este inițializat senzorul este în continuare valid, deoarece faza de inițializare înregistrează funcțiile de transmisie și recepție prin protocolul de comunicație.

Cum să includeți și să utilizați driverul într-un proiect

Figura 1. Structura unui fișier de proiect. (Sursă imagine: Analog Devices)

În afară de directivele simple privind conexiunile hardware dintre senzor și microcontroler (MCU), există și instrucțiuni privind includerea driverului din punct de vedere software și firmware.

Nu există o abordare unică în ceea ce privește organizarea driverelor pentru senzori. Abordarea propusă este prezentată în figura 1. Există un director numit userlib care conține toate driverele pentru senzori. În acest exemplu, există doar drivere pentru senzorii IMU, dar procedura va fi similară dacă proiectul include mai mulți senzori. În interiorul userlib există două foldere, “include” și “src”. Folderul “include” conține fișierul header al driverului, în exemplul nostru va fi adis16500.h, în timp ce în “src” se află fișierul sursă, sau adis16500.c. În interiorul userlib există și un fișier makefile, care specifică directivele de includere, după cum se poate vedea în Figura 2.

Figura 2. Un fișier userlib makefile. (Sursă imagine: Analog Devices)

Figura 3 prezintă fișierul makefile principal. Acesta este localizat la nivelul aplicației, lângă main.c. Acest fișier makefile include user.mk așa cum a fost indicat în linia subliniată cu roșu din figura 3 (linia 115 din cod).

Datorită fișierului makefile (.mk), proiectantul poate include interfața driverului la nivelul aplicației, în main.c de exemplu, și poate invoca toate funcțiile publice ale driverului senzorului. În acest fel, va exista o legătură între nivelul aplicației și nivelul driverului senzorului. Stratul aplicație este cel care cunoaște interfața driverului senzorului (adis16500.h). Din acest motiv, legătura dintre stratul de control al senzorului și stratul de control al perifericelor va avea loc la nivelul aplicației prin procedura de inițializare deja discutată. În cazul specific al senzorului IMU, transmițătorul, funcția SPI a receptorului și funcția de întârziere a sistemului vor fi definite în fișierul main.c, ca în figura 2 din anexă.

Figura 3. Un fișier principal makefile. (Sursă imagine: Analog Devices)

Aici, cele trei funcții urmează exact prototipurile din fișierul header al driverului sau cele prezentate în partea de sus a figurii 3 din anexă. În interiorul acestor trei funcții se află funcțiile oferite de stratul de driver periferic, precum spiSelect, spiSend, spiReceive, spiUnselect, și chThdSleepMicroseconds. Din aceste motive, funcțiile de receptor SPI, de emițător și de întârziere a sistemului reprezintă legătura dintre stratul de drivere periferice și stratul de drivere de senzori, acestea fiind funcțiile care vor fi atribuite structurii de inițializare, ca în figura 2 din anexă. Doar atât este necesar pentru a include driverul într-un proiect.

Pentru a obține datele de ieșire de la senzor, proiectantul poate utiliza funcțiile explicate în secțiunile adis16500_rd_acc și adis16500_rd_gyro. Nu există o abordare unică pentru citirea senzorului, dar un exemplu este oferit în figura 4.

Figura 4. Un exemplu de citire a datelor de ieșire ale senzorului. (Sursă imagine: Analog Devices)

În acest exemplu, există o buclă infinită în main.c în care o variabilă statică booleană numită _adis16500_data_ready este întotdeauna verificată. Această variabilă este legată de o funcție “callback” și va comuta la TRUE atunci când pinul DR devine “high”, ceea ce înseamnă că noile date sunt gata. În această condiție, funcția principală va invoca funcțiile adis16500_rd_acc și adis16500_rd_gyro. Prin rularea senzorului IMU la viteză maximă, proiectantul va putea achiziționa date cu o rată a datelor de ieșire (ODR) egală cu 2 kHz.

Concluzie

Articolul descrie funcționalitățile driverului pe lângă abordarea hardware agnostică care facilitează integrarea senzorilor. Un driver agnostic din punct de vedere hardware oferă avantajul unei soluții gata de utilizare care va putea fi pusă în aplicare la viitoarele proiecte.

Autor: Giacomo Paterniani,
Field Applications Engineer,
Analog Devices

Despre autor
Giacomo Paterniani a obținut o diplomă în inginerie biomedicală la Universitatea din Bologna. Și-a finalizat masteratul în inginerie electronică la Universitatea din Modena și Reggio Emilia. După absolvire, a petrecut un an ca cercetător la Universitatea din Modena și Reggio Emilia. În aprilie 2022, s-a alăturat programului pentru absolvenți al Analog Devices în calitate de inginer absolvent de aplicații de teren. În aprilie 2023, a devenit FAE.

Analog Devices

 


Vizitați https://ez.analog.com

 

S-ar putea să vă placă și

Adaugă un comentariu