Sunteți pe pagina 1din 99

FACULTATEA DE AUTOMATIC I CALCULATOARE

DEPARTAMENTUL CALCULATOARE

Sistem de monitorizare i comand pentru


vehicule electrice bazat pe microcontroller
LUCRARE DE LICEN

Absolvent: Lucian CRI AN


Coordonator tiinific:

2012

S.L.Dr.Ing Radu DNESCU

VIZAT,
DIRECTOR DEPARTAMENT,
Prof. dr. ing. Rodica
POTOLEA

DECAN,
Prof. dr. ing. Liviu MICLEA

Absolvent: Lucian CRI AN


TITLUL LUCRRII DE LICEN
1. Enunul temei: Problema pe care lucrarea de fa o abordeaz se refer la conducerea
unei maini n mod eficient, avnd ca i constrngeri o destinaie aflat la un anumit
numr de kilometri sau/i o constrngere legat de timpul maxim pn la care se dore te
ajungerea la destinaie. Se va folosi un microcontroller pentru achiziia datelor de la
senzori i trimiterea lor la o tablet cu sistem de operare Android.
2. Coninutul lucrrii: Pagina de prezentare, Declaraie, Introducere, Obiectivele
proiectului, Studiu bibliografic, Analiz i fundamentare teoretic, Proiectare de detaliu
i implementare, Testare i validare, Manual de instalare i utilizare, Concluzii,
Bibliografie, Anexe

3. Locul documentrii: Universitatea Tehnic din Cluj-Napoca, Departamentul


Calculatoare
4. Consultani: S.L. Dr. Ing. Radu Dnescu, A.L. Dr. tefan Breban
5. Data emiterii temei: 1 noiembrie 2011
6. Data predrii: 29 Iunie 2012

Absolvent: _____________________________
Coordonator tiinific: _____________________________

Declaraie

Subsemnatul Lucian CRIAN, student al Facultii de Automatic i Calculatoare,


Universitatea Tehnic din Cluj-Napoca, declar c ideile, analiza, proiectarea,
implementarea, rezultatele i concluziile cuprinse n aceast lucrare de licen constituie
efortul meu propriu, mai puin acele elemente ce nu mi aparin, pe care le indic i
recunosc ca atare.
Declar de asemenea c, dup tiina mea, lucrarea n aceast form este original
i nu a mai fost niciodat prezentat sau depus n alte locuri sau alte instituii dect cele
indicate n mod expres de mine.

Data: 29 Iunie 2012

Absolvent: Lucian CRI AN


Numr matricol: 210842
Semntura:______________________

Cuprins
1. Introducere Contextul proiectului............................................................................1
1.1 Contextul proiectului............................................................................................1
1.2 Domeniul temei de licen....................................................................................1
2. Obiectivele proiectului................................................................................................2
2.1 Msurarea tensiunii pe unt i pe divizorul de tensiune.......................................2
2.1.1 Asigurarea bazei de timp pentru achiziia de date........................................2
2.1.2 Asigurarea voltajului de referin.................................................................2
2.1.3 Ameliorarea variailor consumului de curent...............................................2
2.2 Comunicarea cu tableta........................................................................................3
2.2.1 Protocolul Android Open Accessory............................................................3
2.2.2 Alimentarea tabletei......................................................................................3
2.2.3 Posibilitatea nlocuiri tabletei.......................................................................3
2.3 Asigurarea independenei n comunicare..............................................................3
2.3.1 Trimiterea parametrilor de configuraie ai microcontroller-ului...................4
3. Studiu bibliografic.......................................................................................................5
3.1 Variante alternative de conectare la microcontroller............................................5
3.1.1 Hacking.........................................................................................................5
3.1.2 Bridge ntre USB i serial.............................................................................5
3.1.3 Bridge ntre BlueTooth i serial....................................................................5
3.2 Android Open Accessory Protocol( ADK)...........................................................6
3.2.1 Android@Home............................................................................................6
3.3 Sistem audio-video al mainii conectat la Android..............................................7
3.4 Conducerea eficient a vehiculelor electrice........................................................7
3.5 Roboi autonomi...................................................................................................8
4. Analiz i fundamentare teoretic...............................................................................9
4.1 MPLAB X............................................................................................................9
4.2 Microchip Application Library.............................................................................9
4.3 Componente hardware........................................................................................10
4.3.1 Circuitul de achiziie...................................................................................10
4.3.2 H-Bridge.....................................................................................................10
4.3.3 Motoarele de curent continuu.....................................................................11
4.4 Perifericele microcontroller-ului........................................................................12
4.4.1 Timer...........................................................................................................12
4.4.2 Output Compare..........................................................................................13
4.4.3 Input capture...............................................................................................15
4.4.4 I2C..............................................................................................................16
4.4.5 ADC............................................................................................................17
4.4.6 RTCC..........................................................................................................18
4.4.7 Controller-ul de ntreruperi.........................................................................19
4.5 Protocoale folosite..............................................................................................20
4.5.1 I2C..............................................................................................................20
4.5.2 USB.............................................................................................................22
4.5.2.1 O scurt introducere............................................................................22
4.5.2.2 Tipuri de transfer.................................................................................23
4.5.2.3 Modelul de comunicaie USB.............................................................23
4

4.5.2.4 Descriptorii de USB............................................................................24


4.5.2.5 Procesul de enumerare........................................................................24
4.5.2.6 USB Embedded Host Stack................................................................25
4.5.2.6.1 Target Peripheral List( TPL)......................................................25
4.5.2.6.2 Arhitectura stivei........................................................................26
4.5.2.6.3 Driver-ul client bazat pe evenimente.........................................27
4.5.3 Android Open Accessory Protocol..............................................................27
4.6 Algoritmii propui..............................................................................................28
4.6.1 Conversia din analogic n digital................................................................30
4.6.2 Msurarea turaiei.......................................................................................31
4.6.3 Actualizarea datelor....................................................................................32
4.6.4 Calibrare motoare.......................................................................................33
4.6.5 nlnuirea comenzilor pe USB .................................................................33
5. Proiectare de detaliu i implementare.......................................................................35
5.1 Modulul de DAC................................................................................................36
5.2 Modulul de Input Capture .................................................................................37
5.3 Modulul de PWM...............................................................................................39
5.4 Modulul de ADC ...............................................................................................39
5.5 Modulul de RTCC..............................................................................................40
5.6 Programul principal............................................................................................40
5.6.1 Structura comenziilor..................................................................................41
5.6.2 Trimiterea datelor ctre tablet...................................................................42
5.6.3 Funcia de trimitere a datelor ctre Android...............................................43
5.6.4 Iniializarea comunicaiei pe USB i ADK.................................................43
5.6.5 USBTask()= keep the stack running...........................................................44
5.6.7 Iniializarea plcii de dezvoltare.................................................................44
5.7 Logica general a aplicaiei................................................................................44
6. Testare i validare......................................................................................................46
7. Manual de instalare i utilizare................................................................................49
7.1. Instalare.............................................................................................................49
7.1.1 Instalare hardware.......................................................................................49
7.1.2 Instalare software........................................................................................51
7.2 Manualul utilizatorului.......................................................................................52
8. Concluzii...................................................................................................................53
8.1 Rezumat..............................................................................................................53
8.2 Rezultate obinute...............................................................................................53
8.3 Posibile dezvoltri i mbuntiri ulterioare......................................................54
9. Bibliografie...............................................................................................................56
10. Anexe........................................................................................................................57

1. Introducere Contextul proiectului


1.1 Contextul proiectului
Lucrarea de fa este o component a mainii solare dezoltat n cadrul
Universitii Tehnice din Cluj-Napoca i intitulat Solis.EV. Vehiculul se dorete a fi unul
de tip autonom, a crui propulsie este de tip electric, alimentarea fcndu-se folosind
acumulatori ncrcai de la panouri fotovoltaice.
Pentru preluarea informaiilor de la senzori se folosete un microcontroller, util i
pentru acionarea motoarelor. Afiarea informaiilor i intepretarea lor se face folosind o
tablet care are un sistem de operare de tip Android, n locul panoului central de bord.

1.2 Domeniul temei de licen


Problema pe care lucrarea de fa o abordeaz se refer la conducerea unei ma ini
n mod eficient, avnd ca i constrngeri o destinaie aflat la un anumit numr de
kilometri sau/i o constrngere legat de timpul maxim pn la care se dorete ajungerea
la destinaie. Ca i model de main se va considera una de tip solar, cu alimentare
electric de la acumulatori.
Comparativ cu circuitele analogice, un sistem de comanda si monitorizare bazat
pe microcontroller permite o mai mare flexibilitate, i o adaptare mai bun la modificarea
parametrilor. Pentru senzori i elemente de acionare se va folosi o adresare individual
n locul unei magistrale comune.
n cadrul mainii solare un aspect important l reprezint monitorizarea bateriilor,
deoarece folosirea lor peste limita permis poate produce distrugerea lor. Astfel se va
monitoriza consumul de curent din circuit precum i gradul lor de descrcare.
Cunoaterea acestor parametri permite o estimare a timpului rmas pn la descarcarea
bateriilor, n ritmul de consum actual. Folosind curbele de descrcare se pot indica
diverse moduri de prelungire a duratei de descrcare, n funcie de consumul de curent.
Un alt aspect important l constituie acionarea motoarelor. n urma testelor s-a
constat c circuitele de acionare rspund n mod diferit la stimuli . Din aceast cauz este
necesar ca atunci cnd se conecteaz un set nou de motoare s se fac o calibrare iniial a
lor. n timpul funcionrii se folosete i o bucl de comand nchis, implementat n
software, pentru a reduce diferenele ntre turaii.
Comunicarea cu senzorii, sau cu tableta se face folosind protocoale cum ar fi I2C
respectiv USB. Datele circul n general ntr-o singur direcie de la senzori spre
microcontroller, sau de la acesta spre elementele de acionare i n ambele sensuri pe
USB.

2. Obiectivele proiectului
2.1 Msurarea tensiunii pe unt i pe divizorul de tensiune
Principalul obiectiv al acestei lucrri l constituie monitorizarea descrcrii unor
acumulatori cnd sunt folosii cu un consum variabil. n acest sens s-a folosit un unt de
0.8 astfel nct msurnd cderea de tensiune s se poat afla consumul momentan de
curent. Pentru msurarea lui s-a folosit puntea Wheatstone, datorit necesitii existenei
unei precizii ridicate pentru msurarea unei rezistene de valoare mic.
Principiul prin care se afl intensitatea tiind cderea de tensiune pe unt este de a
folosi legea lui Ohm: U= I* R. Voi folosi un scurt exemplu: la o valoare de tensiune
msurat pe unt de 0.4V i rezistena de 0.8, folosind formula enunat anterior se
ajunge la valoarea intensitii de 0.5A.
Astfel obiectivul principal presupune msurarea n fapt a dou tensiuni: una pe
acumulatori, folosind un divizor i alta pe unt. S-a ales un unt de o valoare mic pentru
a avea un consum minim de curent. Acest fapt face ca tensiunea msurat s nu
depeasc 0.5V. Valoarea msurat pe divizor este de 3 ori mai mare, maximul fiind de
1.5V.
2.1.1 Asigurarea bazei de timp pentru achiziie date
Un alt aspect important n cadrul proiectului este de integrare n timp a celor dou
valori msurate. Pentru aceasta este necesar ca achiziia datelor s se fac la intervale de
timp foarte bine stabilite. Nu este att de important s se i trimit datele cu exact aceiai
constan. Pentru aceasta s-a ales o baz de timp de 1Hz, care este asigurat de circuitul
de RTCC. O variaie n generarea acestei baze de timp va duce n timp la rezultate
eronate.
2.1.2 Asigurarea voltajului de referin
O alt parte esenial a msurrii tensiunilor o constituie meninerea referinei
pentru ADC la o valoare constant. Pentru aceasta se vor folosi regulatorul de tensiune de
pe plac n combinaie cu circuitul de DAC. Convertorul din analogic n digital va folosi
o referin de 1.5V n locul celei e 3.25V folosindu-se mai eficient cei 10 bii ai
rezultatului conversiei din analog i tot odat duce la o precizie ridicat la msurarea mV.
2.1.3 Ameliorarea variailor consumului de curent
Datorit modului de construcie al motoarelor i a faptului c sunt comandate n
PWM apar variaii ale consumului de curent, de frecvena comenzii primite. Acest lucru
se datoreaz rspunsului bobinelor la semnalul dreptunghiular. Pentru atenuarea efectului
s-a folosit un condensator i o mediere a valoriilor msurate folosind software-ul.
Asigurarea unei referine stabile pentru ADC nu este suficient. Baza de timp a
convertorului trebui s fie de asemenea stabil. n acest sens oscilatorul intern al modului
nu poate fi folosit, fiind nerecomandat la msurtori de precizie. Folosirea semnalului de
ceas al perifericelor(care este divizat din oscilatorul principal) este o alternativ mult mai
potrivit.
7

2.2 Comunicarea cu tableta


Datorit capacitii limitate de procesare i de afiare a microcontroller-ului se
impune folosirea unei tablete pentru prelucrea informaiilor, salvarea i afiarea lor n
timp real, utilizatorului uman. Acest lucru ridic cel puin dou probleme: trimitirea
informaiilor la o frecven ridicat i posibilitatea alimentarii tabletei n acelai timp.
2.2.1 Protocolul Android Open Accessory
Este un protocol dezvoltat de Google care folosete USB-ul mpreun cu un
mecanism de hand-shake permind comunicarea ntre un master i un slave. Trebuie avut
n vedere c (momentan) tableta joac rolul de slave. Astfel codul necesar funcionrii
comunicaiei cade n sarcina microcontroller-ului. Un alt dezavantaj ce trebuie avut n
vedere este c doar ultimele versiuni de Android suport acest protocol.
2.2.2 Alimentarea tabletei
Obinerea alimentrii continue a tabletei este necesar deoarece dac se folosete
ca i panou de bord, nu se poate ndeprta n timpul funcionrii pentru a se rencrca.
Folosirea unei surse alternative de alimentare nu este o soluie general, deoarece de cele
mai multe ori, nu exist o muf separat n acest scop.
Avantajul USB este acela c permite transferul datelor la viteze de ordinul MB/s
permind i alimentarea slave-ului n acelai timp. Tensiunea de alimentare este de 5V la
un curent maxim de 250mA, ceea ce n cazul de fa este suficient.
2.2.3 Posibilitatea nlocuiri tabletei
Se dorete folosirea unui protocol care s permit o nlocuire ct mai facil a unei
tablete cu alta de acelai tip sau alt model. Soluiile de tip hacking pe ct sunt de
interesante i de captivante presupun de cele mai multe ori desfacerea carcasei i
cositorirea unor fire.
Folosirea soluiei prezentate n aceast lucrare, presupune doar ndeprtarea
cablului de USB, schimbarea tabletei, ncrcarea pe aceasta a programului Android, apoi
se reconecteaz cablul i se poate relua activitatea.

2.3 Asigurarea independenei n comunicare


Se dorete ca o schimbare fie a dispozitivului slave, fie a celui master s nu
presupun i modificarea protocolului de comunicare. n acest sens s-a ales un protocol
simplu, bazat pe trimiterea de octei. Astfel fiecare mesaj este precedat de un cod de
identificare, urmat apoi de un numr fix de octei care reprezint argumentele.
Octet 1

Octet 2

....

Octet n+1

Cod mesaj

Argument 1

....

Argument n

Tabelul 2.1: Formatul general al unui mesaj


n cazul n care o valoare ocup mai mult de un octet(ca de exemplu valoarea de
8

la ADC care este pe 10 bii) se va trimite pe numrul necesar de octe i, cu aliniere la


dreapta n cadrul grupui de bytes.
2.3.1 Trimiterea parametrilor de configuraie ai microcontroller-ului
Fiecare microcontroller este influenat de hardware n ceea ce privete modul de
reprezentare al rezultatelor i numrul de bii pe ci se reprezint acestea. Astfel este de
preferat ca nainte de a se ncepe trimiterea de mesaje s se trimit configura iile plcii de
dezvoltare. Trebuie avut n vedere c i frecvena plcii poate s fie diferit, precum i
frecvena de lucru pentru periferice.

3. Studiu bibliografic
Materialele folosite pentru realizarea acestei lucrri cuprind: data sheet, reference
manual, aplication note, cri, lucrri de laborator, precum i numeroase pagini de pe
internet. Acestea sunt n marea majoritate n limba englez cu cteva excepii n limba
romn. Datorit noutii tehnologiei ADK, care a fost lansat n primvara anului 2011,
nu se poate vorbi despre o bibliografie de mari dimensiuni.

3.1 Variante alternative de conectare la microcontroller


3.1.1 Hacking
Reprezint varianta cea mai riscant i n acelai timp i cea mai interesant de
comunicare. Aa cum se arat n articolul [1] sunt dou abordri posibile: prima
presupune folosirea unui bridge ntre USB i portul serial, iar a doua i cea mai dificil
presupune gsirea i conectarea la portul serial direct de pe magistrala telefonului.
Principalul avantaj al ultimei metode l constituie costul. Dezavantajul major, l
constituie faptul c fiecare dispozitiv cu Andoid, are pinii de la portul serial situa i n alt
locaie. Accesul la schemele hardware este dificil, i de cele mai multe ori acestea nu sunt
fcute publice deoarece clientul nu are nevoie n mod normal de aceste informaii.
3.1.2 Bridge ntre USB i serial
Folosirea unui bridge ntre serial i USB este prezentat n resursa [2], n acest
articol fiind prezentat modul concret de construire al acestui bridge. Avantajul abordrii
curente i a celei precedente este reprezentat de faptul c pe partea de microcontroller se
folosete comunicarea prin protocolul UART. Acesta este suportat nativ de ctre toate
dispozitivele i de asemenea este un protocol uor de folosit.
Un bridge pentru microcontroller este explicat i n resursa [3], care spre
deosebire de variantele anterioare bazate pe serial necesit i folosirea unei librrii mai
complexe. De asemenea suportul pentru kit-ul de dezvoltare este oferit doar pentru
Arduino, ceea ce limiteaz complexitatea programului ce poate fi ncrcat pe plac.
3.1.3 Bridge ntre BlueTooth i serial
Asupra variantelor wireless m-am oprit cu documentarea doar pe varianta de
Bluetooth, datorit preului mai redus al shield-ului, i a protocolului care este mai
simplu. Pentru aceasta se poate folosi [4], care nu este altceva dect o librrie tot pentru
Arduino. Aceasta accept un numr mare de bridge-uri ntre UART i BlueTooth, att
timp ct se seteaz baud rate-ul pentru comunicaia serial la o valoare prestabilit.
n tutorialul [5] se explic pe larg modul general de conectare ntre device-uri
folosind un bridge de la BlueTooth la serial. Se ofer de asemenea att schemele de
montaj construite n jurul unui Arduino i a unui bridge de la SparkFun, precum i codul
pentru Android i paii necesari dezvoltrii aplicaiei pe microcontroller.

10

3.2 Android Open Accessory Protocol( ADK)


Fiecare telefon sau tablet poate folosi USB-ul mpreun cu protocolul ADB(care
n mod normal este folosit pentru depanare) pentru trimiterea datelor, aa cum este
prezentat n blog-ul [6]. O privire critic asupra ADK se gse te pe blog-ul lui Romfron
[7], unde se combate vehement ADK-ul, fiind considerat ca lipsit de inova ie fa de
ADB, deoarece limiteaz folosirea telefonului/tabletei precum i modele acceptate. ADK
are totui avantajul c permite folosirea( momentan n dezvoltare) n paralel a func ie de
depanare fie printr-un USB secundar sau prin wireless.
Singurele documentaii oficiale referitoare la ADK sunt cele oferite de Google,
unde exist o scurt seciune dedicat [8], n cadrul ghidului pentru Android. Acestei
documentaii i se altur documentaia oferit de ctre Microchip [9]. Ambele
documentaii ns nu sunt destul de detaliate, oferind informaii foarte puine.
ADK folosete momentan telefonul pe post de slave i placa de dezvolatare pe
post de master, USB-ul fiind un protocol asimetric. Decizia aceasta a fost luat, a a cum
se arat n blog-ul oficial [10], deoarece momentan majoritatea telefoanelor nu au modul
master i nici OTG, ci numai slave. De asemenea deoarece majoritatea suport ADB, au
cel puin modul de slave, pentru a se conecta la PC i a realiza depanarea print-un cablu
USB. Din aceast cauz, aa cum se remarc i n blog, este o situa ie inversat, cu susul
n jos: telefonul dei are putere de calcul mai mare acioneaz ca i slave, avnd de
asemenea nevoie i de alimentare.
Pe viitor, aa cum se arat n blog-ul amintit mai sus, [10], se va ncerca s nu se
mai ofere alimentare telefonului i s se suporte distribuirea de coninut audio peste
USB( acest lucru nu este fezabil n varianta de fa , deoarece nu se suport transferul
izocron). n cadrul Google I/O din 2011 [11] s-a lansat ideea chiar ca telefonul s fie host,
ceea ce ar uura foarte mult munca dezvoltatorilor de embedded.
3.2.1 Android@Home
Conceptul a fost prezentat n cadrul Google I/O 2011 [12], ca fiind o extindere
pentru Android Open Accessory Protocol pentru automatizarea unei ntregi locuine.
Dispozitivul Android va trebui s foloseasc Android@Home Framework pentru a putea
comunica cu senzorii folosind Wi-Fi.
Un protocol wireless, care folosete unde radio de 900MHz a fost dezvoltat
pentru conectarea elementelor ce nu pot ngloba capacitiile de Wi-Fi. n acest sens a
fost prezentat un bec bazat pe tehnologia LED i produs mpreun cu Light Science, care
folosete acest protocol proprietar.
Oferta de produse compatibile cu Android@Home este momentan redus. Totui
posibilitatea conectrii la internet ofer accesul la Google Cloud i toate serviciile
asociate lui. Un alt exemplu prezentat a fost nglobarea serviciului Music Beta, care
permite sincronizarea diverselor dispozitive care au Android, prin folosirea unui cont
Google. Toat muzica se va afla salvat n cloud, astfel nct nu va ocupa spaiu pe disc.

11

3.3 Sistem audio-video al mainii conectat la Android


n resursa [13] se exemplific o implementare a protocolului ADK oferit de
Harman, prin sistemul lor de audio-video instalat pe main. Telefonul sau tableta pot fi
comandate de la comenziile de pe ecranul tactil, prin comand vocal, butoanele de pe
volan sau direct din panoul central sistemului audio- video.
Se poate astfel s se trimit un sms sau e-mail folosind comanda vocal, sau s se
redea coninutul unui mesaj primit n boxele mainii. Posibilitatea de a rspunde la
telefon, sau de a apela un numr se poate face tot vocal, sau din butoanele de pe volan.
Reele sociale, cum ar fi Facebook sau Twitter au fost i ele tratate de Harman. Coninutul
text al oricrui post primit poate fi redat de ctre sistemul audio al mainii.
Aplicaiile de navigaie care se gsesc pe telefoane i tablete pot fi folosite pentru
gsirea celei mai apropiate staii de alimentare cu carburani, sau pentru a descoperi
restaurantele din zon. De asemenea pot fi redate i filme, pe panoul sistemului audiovideo sau pe ecrane care pot fi montate n tetiere.
Totui sitemul audio-video oferit de firma Harman nu interfaeaz cu partea de
control al parametrilor mainii(cu excepia volumului n difuzoare, i a coninutului unor
ecrane), fiind mai mult o extindere a ecranului tactil al tabletei. Aici dispozitivul Android
are rolul de gestionar pentru muzic, filme, apleuri i mesaje primite, sau postriile de pe
reelele sociale.

3.4 Conducerea eficient a vehiculelor electrice


n lucrarea [14] se trateaz modul n care pot fi satisfcute cerin ele clientului
innd cont de resursele mainii. Abordarea adoptat n acest articol este ierarhic, i
cuprinde 4 module.
Fiecare modul constituie o intrare pentru cel de nivel superior, astfel nct se
transmit o colecie de soluii stagiului urmtor, acesta combinnd fiecare soluie primit
cu cea proprie, pentru a obine tot o colecie de soluii. Un optim local unui nivel poate s
nu fac parte i din soluia global, de aceea se trimit un set de soluii.
Soluia unui singur drum optimal, din punct de vedere al clientului, implic
satisfacerea constrngerilor de timp i de consum energetic. La acestea se pot aduga
costuri de rencrcare, timpi mori n care se face alimentarea, numrul de astfel de opriri
i alte criterii.
Primul nivel tratat este cel al componentelor mainii, cu rol asupra confortului
clientului sau asupra posibilitii efective de locomoie. La acest nivel strategiile sunt
foarte simple, i sunt constituite n mare din compararea unor threshold-uri.
La nivelul urmtor, cel al cltoriei se iau n considerare punctele de alimentare i
destinaiile, i modul n care se poate ajunge ct mai eficient la ele. Aici pentru elaborarea
strategiilor se folosesc grafuri.
Nivelul cltoriei este format dintr-o serie de rute, i puncte de sta ionare/parcare
reprezentate de destinaii intermediare sau finale. Pentru conectarea rutelor se folose te
programarea dinamic, sau gsirea unui optim local.
Ultimul nivel este cel de asigurare a mobilitii, n care un client nu este legat n
mod direct de un anumit mijloc de transport; poate folosi i mijloace de transport n
comun, sau pe anumite poriuni poate s cltoreasc alturi de un cunoscut. n acest scop
12

se folosesc algoritmi din teoria jocului.


Concluzia acestei lucrri este c nu doar costul unei cltorii poate fi mbuntit,
dar chiar i timpul total poate fi mult mbuntit n paralel. Pentru sus inerea acestei
afirmaii s-a dezvoltat un cadru matematic prin care se studiaz complexitatea
algoritmilor, i spaiu computaional al soluiilor. Este necesar s se renun e la anumite
variante n stagii ct mai incipiente, deoarece dac nu spaiul solu iilor poate ajunge la
ordinul miilor, iar analiza lor va consuma foarte mult timp. De asemenea alegerea unei
medii, n locul unui optim global poate s satisfac de cele mai multe ori cerinele
clientului.

3.5 Roboi autonomi


n cartea [15] se prezint tipurile de roboi autonomi, mobilitatea lor, senzori i
percepia mediului, localizarea i planificarea cltoriei.
Un robot care are 3 roi are avantajul stabilitii i de asemenea nu are nevoie de
suspensie, deoarece un plan este determinat de 3 puncte i astfel fiecare roat are contact
permanent cu solul. O alt condiie necesar este ca centrul de greutate s se gseasc n
interiorul triunghiului format de cele 3 roi.
Pentru control direciei, puntea din fa se acioneaz independent, iar n spate se
poate folosi o roat sferic sau una pivotant. Schimbarea direciei se face prin rotirea n
jurul centrului de greutate, blocnd o roat i cealalt fiind acionat n sensul dorit. n
locul blocrii se poate folosi acionarea n sens invers, ceea ce duce ca robotul s roteasc
la punct fix. Dificultatea controlului const n faptul c turaiile celor dou roi motoare
trebuie s fie identice pentru o deplasare n linie dreapt. Folosirea unei roi sferice sau a
uneia pivotante n spate nu influeneaz n mod semnificativ manevrabilitatea robotului.
Pentru atingerea destinaiei se poate folosi o planificare fie n bucl deschis, fie
n bucl nchis. Prima abordare presupune divizarea traseului n mai multe segmente de
tipul liniilor sau arcelor de cerc. Aceast tehnic nu ia n calcul modificriile neprevzute
n configuraia mediului, i de asemenea viteza de deplasare are fluctuaii mari datorit
neregularitiilor ce apar n compunerea drumului ales.
Folosirea unei bucle nchise, prin analiza feed back-ului primit de la diver i
senzori, constituie o abordare mai realist i uor adaptabil la schimbriile de mediu.
Tehnica de baz const n alegerea unor puncte intermediare, care urmeaz s fie vizitate.

13

4. Analiz i fundamentare teoretic


4.1 MPLAB X
Mediul de dezvoltare MPLAB X v.1.10, asigur dezvoltarea facil a aplicaiilor
pentru microcontroller-ele Microchip. Are funcii de programare a acestora folosind un
cablu USB sau un programator, de citire a coninutului memoriei i de execu ie a unui
program pas-cu-pas.
Testarea aplicaiilor, n lipsa unei plci de dezvoltare, se poate face folosind
simulatorul, care poate emula orice microcontroller suportat de mediul de dezvoltare. Are
dezavantajul de a afia registrele n mod list, ordonate dup adres sau dup nume, n
locul unei grupri dup perifericul de care aparin.
Dezvoltarea programelor se poate face, folosind fie limbajul de asamblare fie C.
Prin folosirea directive pentru compilare, se permite introducerea de cod scris n alt
limbaj dect cel ales de utilizator la crearea proiectului. Se ofer suport pentru limbajul
de asamblare prin ASM iar prin C18/C30/C32 respectiv HI-TECH PICC/PICC-18 se
ofer suport pentru C. Varietatea mare de compilatoare se explic prin multitudinea de
arhitecturi suportate: de 8, 24 i 32 de bii precum i procesoare digitale de semnal.
Pe lng compilatoarele necesare, pentru rularea IDE-ului este nevoie i de
instalarea unui JRE. n cazul n care este instalat i versiunea 8 de MPLAB este nevoie
de un driver switch pentru conectarea la placa de dezvoltare. Switch-ul are rolul de a
ncrca driver-ul corespunztor folosiri USB ca i programator pentru microcontroller;
att versiunea 8 ct i versiunea X au driver propriu.
Mediul de programare fiind dezvoltat plecnd de la NetBeans ofer un grad ridicat
de modularitate printr-un set de plug-in-uri. Unul foarte util este DMCI care permite
vizualizarea diverselor tipuri de variabile, afiarea unui vector pe grafic sau modificarea
unor valori folosind sliders sau butoane de tip on/off pentru booleans.

4.2 Microchip Application Library


Cuprinde o serie de librrii scrise n C pentru folosirea perifericelor de pe plac, a
cror programare este mai dificil. Se ofer acces la stivele de TCP/IP, USB, Wireless,
ecrane tactile, SD card i sisteme de fiiere. Aceste librri pot fi folosite individual sau
pot fi combinate n cazul n care aplicaia este mai complicat.
Librria Android Accessory Framework, folosete i librria de USB pentru a
oferi un API facil dezvoltrii aplicaiilor de tip ADK. Generarea fiierelor de configuraie
pentru driver-ul de USB se poate face folosind programul USB Config, prin configurarea
pas-cu-pas a fiecrei opiuni asociate comunicaiei seriale.
Librriile necesare pot fi incluse n proiectul curent n dou moduri: prin
adugarea locaiei la include path ca i cale absolut, sau prin copierea lor n proiectul
curent i referirea folosind calea relativ. Metoda a doua asigur nu doar portabilitate, dar
mpiedic modificarea voluntar sau nu a fiierelor originale din librrie. Compilatorul
folosete include path pentru a cuta dependenele proiectului, cum ar fi fiierele din
librriile standard.
14

4.3 Componente hardware


4.3.1 Circuitul de achiziie
Circuitul de achiziie este prezentat n figura 4.1, n continuare fiind prezentate
componentele constructive. Schema a fost realizat folosind: falstad.com/circuit/, un
applet n Java, de tip drag-and-drop.
Acumulatorii sunt de tip rencrcabil, cu o tensiune la borne de 1.2V i o
capacitate de 2450mAh. n locul acumulatorilor se pot folosi baterii obinuite de 1.5V.
Cei 4 acumulatori sunt legai n serie, oferind astfel 4.8V, capacitatea rmnnd la
valoarea de 2450mAh.
Circuitul de msur al voltajului la borne este format din 4 rezistene de 1K n
serie, cu scopul de a forma un divizor de tensiune. Rezistenele pot fi de orice valoare, ct
timp sunt de valori egale. Dac sunt de valori diferite tensiunea pe o rezisten va trebui
calculat folosind proporiile aritmetice. n cazul folosiri a 4 rezistene, cderea de
tensiune pe o rezisten este de 4 ori mai mic dect n tot circuitul serie. n cazul de fa
s-a ales valoarea de 1K pentru a se reduce consumul de curent n circuit.

Figura 4.1: Circuitul de achiziie


Condensatorul este de tip electrolitic i are o capacitate de 4.7mF, iar cele dou
motoare sunt reprezentate pe schem ca i dou rezistene de 100 , aflate n partea
dreapt. Asupra rolului condensatorului voi reveni ntr-un capitol viitor, iar motoarele vor
fi prezentate n continuare.
4.3.2 H-Bridge
Circuitul are rolul de a schimba direcia motorului, fr a fi necesar modificarea
montajului. Pentru aceasta se folosesc patru tranzistori grupai n dou perechi: Q1/Q3 i
15

Q2/Q4, comandai prin semnalele A, respectiv B.


Dac A are valoarea '1', iar B are valoarea '0', motorul se va roti n sensul acelor
de ceasornic, iar dac A este '0' i B este '1', se va roti n sensul opus acelor de ceasornic.
Pentru a se opri motorul, ambele semnale de control trebuie s fie la valoarea '0'. Dac
ambele semnale sunt '1', comportamentul va fi nedefinit.
n figura 4.2 este prezentat un Pmod ce ndeplinete funcia descris mai sus, i
schema general a circuitului de H bridge, folosit pentru exemplificarea func ionrii.
Aa cum se poate observa circuitul de alimentare este separat de comand, astfel nct
motoarele pot fi acionate la tensiuni i cureni mari.

Figura 4.2: PMod HB5(n partea stng) i schema general a H


bridge(n dreapta)

4.3.3 Motoarele de curent continuu


Motoarele sunt de tip Igarashi IG22, cu o cutie de viteze ncorporat, ce are un
raport de 1:19, funcionnd ca un reductor cu raport fix. Modelul de fa se poate
alimenta la tensiuni de maxim 6V, curent continuu, iar consumul de curent are valoarea
maxim de 125mA. n figura 4.3 este prezentat o privire de ansamblu asupra motorului,
o vedere din spate a encoder-ului i ieirea n defazaj a celor doi senzori Hall.
n partea din spate a fiecrui motor se afl un encoder, bazat pe efect Hall, care
msoar gradul de rotaie. Scopul acestui circuit este s determine turaia motorului,
folosind doi senzori magnetici dispui la o anumit distan unul fa de cellalt.
Magnetul folosit este unul obinuit, de tip Nord-Sud. Cei doi senzori ofer la ieire
semnalele A i B, defazate cu 900, i cu un factor de umplere de 50%, aa cum se vede n
16

partea dreapt jos.


Trebuie avut n vedere c senzorii msoar direct turaia rotorului, astfel valoarea
obinut este de 19 ori mai mare dect ieirea din reductor, care acioneaz roile.
Senzorul Hall poate fi folosit chiar dac motorul nu este alimentat. Valoarea gradului de
rotaie este una relativ la momentul nceperii msurrii. Folosirea unei codificri Gray
asociate acestui encoder ar fi permis cunoaterea n orice moment al gradului de rotaie.

Figura 4.3: Motorul de curent continuu i encoder-ul

4.4 Perifericele microcontroller-ului


n sectiuniile urmtoare sunt prezentate perifericele folosite n cadrul proiectului.
Termenul de PB se refer la semnalul de ceas al perifericelor, iar SOSC la oscilatorul
secundar. Ceasul general al sistemului, SYSCLK , este divizat pentru a se ob ine PB.
Notaia 'x' din denumirea registrelor sau pinilor se refer la registrul/pinul asociat unei
anumite instane a perifericului, ca de exemplu dac x este 1 n TxCK este pinul
semnalului de ceas extern pentru Timer 1.
4.4.1 Timer
Am folosit ca i principal surs de informare Reference Manual [16]. Acest
model de chip are un numar de 5 timere de 16 bii(T1- T5). Pentru a se obine un timer de
32 de bii se pot asocia T2 cu T3 sau T4 cu T5.

17

Figura 4.4: Timer 1


Se folosete termenul de Type A pentru cele care pot fi folosite doar ca i 16 bii,
respectiv Type B pentru cele care pot fi folosite i ca 32 bii. n cazul B se folosesc
notaiile de TimerX i TimerY, primul fiind considerat master(ex emplu Timer 2) iar al
doilea fiind considerat slave(exemplu T3). Masterul stabilete perioada i setriile de
baz, registrele lui Y sunt folosite doar pentru setarea ntreruperilor.
Pot fi identificate mai multe moduri de operare:
Modul sincron care este asemntor pentru tipul A i B presupune folosirea
Peripheral Bus Clock (PB) i eventual a unui prescaler.
Modul sincron cu ceas extern presupune folosirea unui pin(TxCK) unde este
furnizat un ceas extern. Acesta este sincronizat cu ceasul sistemului.
Modul gated presupune folosirea unui semnal extern care valideaz numrarea.
Modul asincron. Acesta este singurul mod care apare doar la tipul A, spre
deosebire de modurile de mai sus care apar la ambele tipuri. Se poate folosi ca i
sursa T1CK sau oscilatorul secundar (SOSC). Se ofer mecanisme de sincronizare
ntre PB clock i ceasul extern.
Fiecare timer are propria ntrerupere, a crei prioritate/subprioritate poate fi setat
individual. Poate avea surse multiple cum ar fi atingerea valorii din PR sau, dac se
folosete n modul gated, de un falling edge pe gate.
4.4.2 Output Compare
Principala surs de informare privind PWM a constituit-o Reference Manual[17].
Poate fi folosit doar cu Timer 2 sau cu Timer 3. Se pot folosi un numr de maxim
5 canale. n privina registrelor necesare, numrul acestora este mic:
OCxCON, folosit pentru configurarea modulului
18

OCxR i OCxRS folosite pentru compararea cu valori de 16 bii sau de 32 de bii


dac se folosete i registrul secundar(OCxRS).
Din punctul de vedere al modurilor de funcionare se pot distinge:
modul Single compare, a crui ieire poate fi folosit pentru a avea high, low sau
toggle, la potrivirea valorii din timer cu cea din output compare(OcxR).
Modul Dual compare, folosete ambele registre pentru comparare. De exmplu la
atingerea valorii din primul registru va trece n starea low, apoi la atingerea valorii
din registrul al doilea va trece n high.
Modul PWM. Perioada se stabilete prin setarea timer-ului, iar factorul de umplere
prin setarea OcxR. OcxRS are aici rol de buffer, i se transfer n OcxR la
overflow-ul timer-ului.

Figura 4.5: Funcionarea OC


PWM poate fi folosit cu scopul de convertor digital-analogic. Modificnd factorul
de umplere se modific i ieirea. La frecvene mari, de ordinul kHz, un factor de
umplere de x%, va face ca ieirea s fie perceput ca fiind x% din valoarea maxim. n
exemplul din figura 4.6 la un factor de umplere de 50%, ieirea este msurat ca fiind 5V,
jumtate din cei 10V, ct reprezint valoarea high a semnalului dreptunghiular.
Fiecare canal are asociat o ntrerupere, astfel se pot seta individual prioritiile i
subprioritiile.

Figura 4.6: PWM ca i regulator de tensiune


19

4.4.3 Input capture


Este folosit pentru a se efectua msurtori ale frecvenei sau ale duratei unui
impuls, aa cum se arat n Reference Manual [18].

Figura 4.7: Modulul de input capture


Modulul are dou registre: unul pentru configurare ICxCON i unul de tip buffer
ICxBuf. Prin intermediul acestui registru buffer poate fi citit stiva(FIFO). Dac stiva
conine 4 valori atunci sunt necesare 4 citiri din ICxBUF. Stiva are un numr maxim de 4
cuvinte. Se poate folosi ca i baz de timp Timer 2, Timer 3 sau ambele pentru o baz de
timp de 32 de bii.
Se poate folosi n urmtoarele moduri:
simple capture, mod n care se alege modul de rising/falling, iar ntreruperea va fi
generat dup numrul de evenimente specificat n ICxCON.
prescaled capture, mod n care se va genera un eveniment tot la al 4-lea sau 16lea eveniment.
Modul edge detect va detecta att tranziiile high-low ct i low-high . Modul
interrupt-only se folosete pentru modul sleep i idle.
Modulul are dou ntreruperi: ICxIF, care apare dup numrul dorit de
evenimente i ICxIE care apare n urma unei erori cum ar fi faptul ca nu se citete din
FIFO i apare over run.

20

Figura 4.8: Modul general de folosire al IC i Timer


n figura 4.8, este prezentat conceptual funcionarea modului. Modul de folosire
este de single capture, i evenimentele de interes sunt cele de tipul rising edge, marcate
cu verde pe figur. Registrul se va incrementa cu frecvena ceasului folosit ca i baz
pentru msurtoare. Dac apare un eveniment se genereaz o ntrerupere, se salveaz
valoarea, apoi registrul se va reiniializa.
4.4.4 I2C

Cele mai importante caracteristici ale modulului sunt urmtoarele:


logic separat pentru partea de slave/master
posibilitatea de a lucra att cu adrese 7 bit ct i de 10 bit
posibilitatea arbitrri n sisteme de tip multimaster
poate lucra la frecvene de 100KHz, 400KHz sau 1MHz.

Registrele care controleaz modulul de I2C sunt prezentate n [19] i sunt


urmtoarele:
I2CxCON, este registrul care va controla funcionarea I2C
I2CxSTAT, conine o serie de flags
I2CxADD, este registrul ce conine adresa n cazul n care funcioneaz ca i slave
I2CxMSK, este un registru de masc pentru adres, astfel nct s poat s
rspund la mai multe adrese
I2CxBRG, folosit pentru baud rate
I2CxTRN, aici se vor pune datele care se doresc trimise
I2CxRCV, aici se vor depunde datele primite
ntreruperile asociate cu acest modul sunt difereniate pentru modul de folosire
master, slave sau sunt comune(bus collision), sursele n fiecare caz fiind multiple. Pentru
recepionarea datelor se folosete principiul de double buffer. Prima dat datele sunt
deplasate folosind I2CxRSR iar apoi odat terminat operaia(dup primirea a 8 bii) se
mut datele n I2CxRCV. Dac vechea valoare nu a fost citit din acest registru se va
semnaliza prin flagul I2xCOV, iar valoarea nou se va pierde.
Funcia de reload automat pentru Baud Rate Generator are sens n contextul
arbitrrii, pentru a determina o nou ncercare de obinere a magistralei. BRG se va
decrementa ct timp SCL este low, iar apoi va ncerca s aduc SCL n starea high.
Pierderea arbitrrii poate s apar la Start, Repeated Start, trimitere de date, adres, sau la
Stop; i se va semnaliza prin setarea flag-ului de BCL.
In continuare voi prezenta unele particulariti pentru modulul de I2C n modul
21

master. La iniializarea unui Start trebuie s se atepte terminarea lui, altfel se va


semnaliza o coliziune pe bus. Pentru a se verifica dac bus-ul este idle(SCL este high) se
mai poate verifica flagul de Stop. Pentru o abordare bazat pe ntreruperi este necesar
construirea unui state machine deoarece, ntreruperea pentru modul master poate fi
activat de mai multe surse.
4.4.5 ADC

Figura 4.9: Modulu ADC


Registrele folosite pentru programarea modului sunt urmtoarele:
AD1CON1, AD1CON2, AD1CON3, folosite pentru configurare
AD1CHS, folosit la selectarea pinilor ce vor fi conectai la SHA, prin cele dou
multiplexoare
AD1PCFG, este folosit pentru configurarea pinilor ca i digital sau analogic
AD1CSSL, este folosit pentru alegerea piniilor ce vor fi folosii la scanare
ADC1BUF0- ADC1BUFF, constituie stiva unde vor fi depuse rezultatele

Pentru a se folosi un pin ca i intrare analogic mai nti se va marca ca i pin de


intrare folosind registrul TRIS, apoi se va seta ca i analogic folosind AD1PCFG.
Rezultatul conversie este de 10 bii, dar poate fi citit ca i un numr pe 16 sau pe 32 de
bii att n format ntreg ct i n format fracional, cu semn sau fr. Numerele negative
nu se obin n urma citiri unei valori negative, ci datorit faptului c sunt n prima
jumtate a intervalului, n mijlocul intervalului fiind valoarea 0.
22

Setarea modului de conversie poate fi realizat n 4 feluri i anume: manual prin


setarea bitului de sample; prin folosirea Timer2 i/sau Timer3; printr-o ntrerupere
extern; sau n mod auto. Modul auto va seta la finalul conversie bitul de sample, ceea ce
va duce la nceperea unei noi eantionri.
Se poate specifica numrul de conversii dup care se va genera o ntrerupere, acest
numr fiind de maxim 16 sau 8 n funcie de Buffer Fill Mode. Rezultatele vor fi salvate
n stiv ncepnd cu BUF0 i continund pn la maxim BUFF. Prin folosirea dual buffer
stiva este mprit n dou zone: primele 8 BUF0- BUF7 i ultimele BUF8- BUFF. Astfel
mai nti se scrie n prima zona, se genereaz ntrerupere, apoi se trece la a doua zon, i
se genereaz ntrerupere, apoi rezultatele conversiei vor fi depuse din nou n prima zon.
Generarea ntreruperii se face dup scrierea numrului indicat de valori, valoarea maxim
n acest mod fiind de 8. Mai nti se va scrie n buffer-ul 0, apoi n 1,2 n prima zon;
respectiv 8, 9, 10 pentru zona a doua. Astfel se permite o operaie de citire dintr-o zon,
n timp ce se scriu rezultatele n alt zon, fr riscul de suprascriere a valorilor.

Figura 4.10: Funcionarea S/H


Perioada convertorului se numete TAD i este dat fie de un oscilator intern, fie de
semnalul de ceas al perifericelor. Convertorul este unul de tipul sample and hold, fiind
prezentat n figura 4.9 ca o zon punctat cu denumirea S/H. Funcionarea este prezentat
n figura 4.10, valoarea analogic avnd culoarea gri, punctele de eantionare fiind
prezentate cu linii punctate, i valoarea digitizat avnd culoarea roie pe grafic. Prima
dat se face o ncrcare a condenstatorului, urmat de decuplarea ntreruptorului. Dup
perioada de eantionare, urmeaz perioada de hold n care se face conversia valorii din
condensator. Perioada de sample poate fi modificat de la 1 la 127 T AD , dar perioada de
conversie este fixat la 12 TAD.
n sectiunia 17.5 din [20] se prezint modul de calcul al TAD i pentru a se obine o
frecventa de eantionare de 1000ksps.
4.4.6 RTCC
RTCC este un circuit ce asigur pstrarea datei n format BCD, facilitnd astfel
interpretarea ct mai rapid a datei fr a mai fi nevoie de prelucrri ulterioare. Se ofer
posibilitatea de ntrerupere i toggle de output la intervale de o secund, un minut, o or
i alte intervale mai mari. n mod intern perioada de lucru este de o jumtate de secund,
dar pentru citire rezoluia este la o secund.
n ceea ce privete alarma ea poate fi setat ntr-un interval de la o jumtate de
secund pn la un an i poate fi repetat de un numr de maxim 255 de ori. Dac se
folosete opiunea de Chime se va repeta la nesfrit, detectnd atingerea numrului de 0
23

repetri contorul se va reiniializa.


Accesul la registrele pentru timp i pentru alarm se face doar dac bitul
RTCSYNC, respectiv ALRMSYNC este zero. Acest interval de timp este de 32 de
perioade de ceas, o citire sau o scriere n afara acestui interval producnd efecte
nedefinite.

Figura 4.11: Incrementarea secundelor


n figura 4.11 se prezint modul n care se incrementeaz registrul secundelor.
Dup 32768 de perioade de ceas are loc incrementarea registrului.
n cazul n care se observ c referina nu are exact 32 768Hz se poate ajusta cu
formula: (32 768- Frecven msurat)*60= Eroare. Acest valoare poate avea att valori
pozitive ct i negative. Modulul va face coreciile necesare o dat la 1 minut, prin
modificarea secundelor.
Pentru alarm se va seta data i timpul primei declanri, apoi se alege cnd(dup
o secund, o zi, un an) se va declana i de cte ori se va repeta alarma la intervalul
specificat. Data primei alarme este comparat cu o masc. De exemplu, dac se alege un
interval de un minut nu se vor lua n considerare secundele pentru a se stabili perioada de
declanare. La incrementarea registrului minutelor vom avea o alarm. n cazul extrem,
de repetare la un interval de o secund, setarea datei primei alarme este inutil.
Configuraia mti n acest caz face ca prima alarm s apar dup o secund de la
setarea bitului de enable. Pentru nelegerea acestui modul recomand urmrirea [21]i
[22].
4.4.7 Controller-ul de ntreruperi
Acest microcontroller are un numr de 46 vectori de ntrerupere i un numr de 58
de IRQ( surse de ntrerupere, inclusiv cele 5 externe). Att n modul single ct i n modul
multi- vector se pot folosi registre de tip shadow(secondary register set).
Modul single vector : este modul default, n care va intra dup reset. Se va folosi
aceiai adres indiferent de vectorul care a generat-o.
Modul multi vector : fiecare vector are asociat o adres unic calculat folosind o
adres de baz i un deplasament.
ntreruperile pot avea prioritate ntre 1(minim) i 7(maxim). Prioritatea 0 se
folosete pentru a inhiba ntreruperea. Controller-ul de ntreruperi va servi o ntrerupere
de ordin superior, chiar dac exist una de ordin inferior n execuie . Aceiai ordonare i
regul de servire apare i n cazul folosirii subprioritiilor ce au valori ntre 0(minim) i
3(maxim). Pe lng aceste reguli pentru ordonare se folosete i ordinea natural, unde 0
este maxim i vectorul 45 este minim. La intrarea n ISR (Interrupt service routine) este
obligatoriu s se marcheze sursa care a generat ntreruperea pentru a evita ntreruperi de
tip recursiv.
24

Registrele shadow(al doilea set de registre GPR) aduc o cretere a


performanei deoarece nu mai este nevoie s se fac salvri de context pe stiv. Acestea
sunt valabile pentru single vector, iar n multi vector sunt valabile doar pentru
ntreruperile de nivel mai ridicat.
Tehnica TEMPORAL PROXIMITY INTERRUPT COALESCING, presupune
folosirea unei cozi unde se pun ntreruperile, de grad egal sau mai mic cu un prag dat, i
care vor fi apoi servite nlnuit. Se folosete un timer, care este declan at de apari ia
primei ntreruperi ce respect condiia de grad. Odat ajuns la zero, se vor procesa
nlnuit toate acele ntreruperi care au respectat condiia de a intra n coada de ateptare.
Pentru aceasta este nevoie s se ncarce pragul dorit n TPC i valoarea de unde se va
decrementa n IPTMR( valoare pe 32 bii). Acest timer folosete direct SYSCLK, fr
prescaler.
Se pot folosi de asemenea i pn la 5 intreruperi externe, care pot fi pe front
cresctor sau descrector, i dou ntreruperi de tip soft, a cror declanare poate fi fcut
exclusiv prin cod. Pentru nelegerea ntreruperilor recomand [23].

4.5 Protocoale folosite


4.5.1 I2C
Este un protocol de tipul master slave. Se folosesc dou linii pentru comunicare:
una pentru date(SDA), i alta pentru semnalul de ceas(SCL). Ambele linii sunt de tipul
open-drain, pentru a se putea modifica valoarea liniei din orice punct. Pe linia de SDA se
pot ncrca datele fie de ctre master, fie de ctre slave; dar linia de SCL este permanent
controlat de master, slave-ul putnd doar s prelungeasc timpul n care se gsete n
starea '0'.

Figura 4.12: Magistrala I2C


Liniile au valoarea default '1', datorit rezistenelor de pull-up Rp, care sunt
conectate la Vdd, aa cum se poate vedea n figura 4.1 2. Pentru modificarea valorii la '0'
se va conecta linia dorit la GND, fie din master, fie din slave.
Pentru a se modifica valoarea linie SDA, linia de SCL trebuie s fie n poziia low.
Singurele exceptii de la aceast regul sunt condiiile de start i stop, n care datele trec
din high n low i invers, dei linia semnalului de ceas are valoarea '1', aa cum se arat i
n figura 4.13.

25

Figura 4.13: Start, schimbare date, stop


Datele transmise pe magistral au 8 bii n dimensiune, urmate apoi de bit de
confirmare. n figura 4.14 se prezint schema general de transfer pe magistrala I2C.
Repetarea startului apare pentru a nu se pierde arbitrarea atunci cnd se dorete s se
transfere mai mult de 1 byte spre un dispozitiv.

Figura 4.14: Formatul general de transfer al datelor


Magistralele cu mai mult de un master au nevoie de arbitrare. n figura 4.15 s-a
presupus c sunt conectate 2 astfel de dispozitive. Ambele verific linia de SCL i
ncearc pornirea unui transfer, i implicit obinerea magistralei. Deoarece ambele au
putut da startul, vor continua s pun datele n paralel, pn cnd Data1 este '1', ns SDA
este '0', ceea ce nseamn c primul a pierdut magistrala, i astfel renun s mai pun
date pe I2C.

26

Figura 4.15: Arbitrarea a dou masters


Un mecanism similar celui de arbitrare apare i la semnalul de ceas i se nume te
'clock streching'. Dac slave-ul mai are nevoie de timp pentru procesare va menine linia
de clock la valoarea '0', exemplificat n figura 4.14, pentru a putea face procesriile
necesare.
Protocolul I2C presupune trimiterea mai nti a adresei slave-ului de la care se
dorete recepionarea/trimiterea datelor, nsoit de un bit de read/write, iar la final de
ACK. n octeii urmtori se gsesc datele de la slave spre master, sau n sens invers. Cel
care este destinatarul datelor trebuie s confirme transferul prin ACK. Asupra tipurilor de
transfer voi reveni n capitolele urmtoare unde vor fi i exemplificate pentru DAC.
4.5.2 USB
Pentru aceast prezentare general a protocolului am folosit [24] i [25], precum
i unele constatri experimentale.
4.5.2.1 O scurt introducere
Diferenele ntre funcionalitiile portului USB de pe placa de dezvoltare i cel de
pe un PC sunt minime. Diferenele majore sunt urmtoarele: ofer suport doar pentru
anumite clase sau dispozitive, poate suporta doar anumite tipuri de transfer, nu suport
hub-uri, cantitatea de curent oferit este limitat.
Permite conectarea diverselor periferice la calculator prin folosirea unui cablu
unic. ntr-un sistem coninnd o magistral USB, perifericele se pot conecta n serie sau
ntr-o topologie sub form de stea pe mai multe nivele. Un avantaj important l reprezint
conectarea de tip plug-and-play care nu necesit desfacerea carcasei sau repornirea
sistemului.
Portul USB detecteaz adugarea unui nou periferic i determin n mod automat
resursele necesare acestuia, inclusiv driver-ul software, rata de transfer i consumul de
curent. Perifericele se pot afla la o distan de pn la 5 m unele fa de altele sau fa de
un distribuitor(hub).
n configuraia de fa oferit de Microchip nu se poate folosi distribuitor. Din
aceast cauz topologiile de tip stea nu pot fi implementate. De asemenea dei din punct
27

de vedere al USB Host Stack se permite conectarea mai multor dispozitive in serie, placa
de dezvoltare asigur un singur port de USB i astfel se poate conecta practic un singur
periferic la un moment dat.
Fiecare funcie(periferic) conine informaii de configuraie care descriu
posibilitile sale i resursele necesare. Aceste informaii sunt transmise calculatorului
gazd ca rspuns la o tranzacie de control. naintea utilizrii unei funcii, aceasta trebuie
configurat de calculatorul gazd. Aceast configurare presupune alocarea unei limi de
band n cadrul magistralei USB i selectarea opiunilor specifice de configuraie.
4.5.2.2 Tipuri de transfer
Arhitectura USB permite patru tipuri de transferuri de date: de control, de
ntrerupere, de date voluminoase i izocrone.
Transferurile de control se utilizeaz de driver-ele calculatorului gazd pentru
configurarea dispozitivelor care sunt ataate la sistem.
Transferurile de ntrerupere se utilizeaz pentru date care trebuie transmise cu
o ntrziere limitat. Transferul acestor date poate fi solicitat de un dispozitiv n orice
moment, iar rata de transfer pe magistral nu poate fi mai redus dect cea specificat de
dispozitiv. Tastatura sau mouse-ul pot folosi acest tip de transfer pentru notificarea
apsrii unei taste, respectiv pentru trimiterea noilor coordonate ale cursorului.
Transferurile de date voluminoase (bulk) se utilizeaz cu periferice cum sunt
memorii de mas, imprimante sau scanere. Aceste date sunt secveniale, i de dimensiuni
mari. Fiabilitatea transferurilor este asigurat la nivel hardware prin utilizarea unui cod
detector de erori i reluarea unui transfer cu erori de un anumit numr de ori. Rata de
transfer poate varia n funcie de alte activiti de pe magistral.
Transferurile izocrone se utilizeaz pentru datele care trebuie furnizate cu o
anumit rat de transfer constant i a cror sincronizare trebuie garantat. Un exemplu ar
fi streaming-ul audio sau video, unde o eroare la transmiterea unui pachet duce la
anularea retransmisiei i continuarea cu urmtorul din secvena de transfer.
n cazul aplicaiei dezvoltate se folosesc cu precdere transferuri de control i de
ntrerupere, existnd suport i pentru bulk; transferurile izocrone nu sunt suportate.
4.5.2.3 Modelul de comunicaie USB
Protocolul USB este de tip asimetric, i folosete adresarea pentru identificarea
dispozitivelor conectate. Spre deosebire de I2C magistrala nu este de tipul multimaster.
Magistrala USB are 4 fire: VBUS i GND sunt folosite pentru alimentarea dispozitivelor
iar D+ i D- se folosesc pentru transferul ntr-o singur direcie la un moment dat al
datelor.
Comunicarea ntre host i periferic se face folosind fluxuri de comunicaie numite
pipes, pentru realizarea legturii la nivel de end point-uri. End point-ul este folosit alturi
de adresa device-ului pentru identificare. El este necesar deoarece la o adresa(la un
dispozitiv) pot exista mai multe tipuri de transferuri fiecare fiind asociat cu un end point.
Punctele terminale pot fi de intare sau de ieire, iar cel cu numr 0 este default fiind
folosit pentru configurare.
Exist dou moduri de comunicaie printr-o conduct(pipe): ir sau mesaj. n
modul ir, datele nu au o structur definit de specificaiile USB. Datele sunt transferate
secvenial i au o direcie predefinit, de intrare sau de ieire. Conductele de tip ir permit
28

transferuri de ntrerupere, bulk sau izocrone. n modul mesaj, datele au o anumit


structur definit de specificaiile USB. Coninutul datelor transferate printr-o conduct
de tip mesaj este interpretat de controller-ul USB. Aceste conducte sunt controlate de
calculatorul gazd i permit doar transferuri de control, n ambele direcii, fiind folosite
pentru configurarea dispozitivelor.
Punctele terminale conin buffere de intrare sau de ieire prin intermediul crora
se realizeaz comunicaia ntre calculatorul gazd i dispozitivul USB. De exemplu, dac
programul rulat pe calculatorul gazd transmite un pachet adresat unui anumit dispozitiv
USB, acest pachet va fi depus n bufferul unui punct terminal de ieire al dispozitivului.
Ulterior, controller-ul dispozitivului va citi din buffer pachetul recepionat. Dac
dispozitivul trebuie s transmit date la calculatorul gazd, nu poate depune datele direct
pe magistral, deoarece toate tranzaciile sunt iniiate de master. Dispozitivul va depune
datele n buffer-ul unui punct terminal de intrare, iar aceste date vor fi transferate la
cererea calculatorului printr-un pachet de intrare. Noiunile de intrare/ieire sunt relative
la host. Master-ul a fost denumit alternativ calculator sau host. Pentru slave s-a folosit
denumirea de dispozitiv.
4.5.2.4 Descriptorii de USB
Ierarhia de descriptori are ca rdcin la nivelul superior descriptorul de
dispozitiv. La nivelul urmtor se afl descriptorii de configuraie; exist cte un asemenea
descriptor pentru fiecare configuraie a dispozitivului. Pentru fiecare configuraie pot
exista unul sau mai muli descriptori de interfa, n funcie de numrul de interfee ale
configuraiei respective. n sfrit, pentru fiecare punct terminal al fiecrei interfee exist
cte un descriptor al punctului terminal.
Descriptorul de dispozitiv este folosit pentru a oferi informaii generale despre
dispozitiv: clasa/subclasa producator ID/produs ID, revizia de USB. Descriptorul de
configuraie este folosit pentru a primi informaii legate de tipul alimentrii: proprii sau
prin bus-ul de USB. n cazul n care un dispozitiv are asociate mai multe astfel de
dispozitive, la un moment dat poate fi activat doar unul. Un numr oarecare de puncte
terminale pot fi grupate logic ntr-un descriptor de interfa; care este folosit in cadrul
dispozitivelor multifuncionale. La un moment dat pot fi activate mai mul i asemenea
descriptori. Conine informaii legate de numrul de puncte terminale i tipul de
clas/subclas. Descriptori de end-point sunt folosii pentru a se stabili direcia, timp ul de
acces, laimea de band, adresa dispozitivului. Un alt descriptor opional dar care este
implementat in USB Host Stack este cel de ir de caractere( string) folosit pentru a se
obine informaii in plain text legate de capabilitiile dispozitivului.
4.5.2.5 Procesul de enumerare
Atunci cnd un dispozitiv este conectat/deconectat la magistrala USB,
calculatorul gazd execut un proces numit enumerare pentru a determina modificrile
aprute n configuraia sistemului USB. La conectarea unui dispozitiv USB la magistral,
se execut urmtoarele operaii:
1. Calculatorul gazd folosind o rezisten determin conectarea unui nou
dispozitiv.
2. Calculatorul gazd ateapt un timp de cel puin 100ms pentru ca tensiunea de
29

alimentare a dispozitivului s devin stabil, dup care transmite o comand de validare


i de resetare a portului. Folosind msurarea tensiunii pe liniile de date, se determin
prezena rezistenelor de pull-up/pull-down, i astfel se determin viteza dispozitivului:
vitez ridicat(480 Mbii/s) sau viteza normal (12 Mbii/s).
3. Dup terminarea procedurii de resetare, portul este validat. Dispozitivul se afl
acum n starea implicit i poate absorbi un curent de maxim 100 mA de pe linia VBUS a
magistralei. Dispozitivul va rspunde la tranzacii cu adresa implicit zero.
4. Calculatorul gazd solicit descriptorul de dispozitiv, iar dispozitivul transmite
acest descriptor prin intermediul conductei implicite.
5. Calculatorul gazd asigneaz o adres unic dispozitivului.
6. Calculatorul gazd solicit descriptorii de configuraie, iar dispozitivul
transmite calculatorului gazd aceti descriptori.
7. Pe baza informaiilor de configuraie, calculatorul gazd asigneaz o anumit
configuraie dispozitivului. Dispozitivul se afl acum n starea configurat i toate
punctele terminale ale acestei configuraii sunt configurate conform caracteristicilor
specificate n descriptorii acestora.
Dispozitivul este pregtit pentru utilizare i poate absorbi de pe linia VBUS a
magistralei curentul specificat pentru configuraia selectat.
Atunci cnd dispozitivul USB este deconectat de la un port USB, calculatorul
gazd dezactiveaz portul respectiv i actualizeaz informaiile sale despre topologia
magistralei.
4.5.2.6 USB Embedded Host Stack
n Application note [26] se face o scurt introducere a modului de funcionare a
USB host adaptat pentru embedded. Articolul [27] vine ca i o completare a articolului
precedent, insistndu-se mai mult pe partea de programare, cu multe exemple de cod.
4.5.2.6.1 Target Peripheral List( TPL)

Conine o descriere a dispozitivelor ce pot fi suportate de host fie pe baz de clas


i de protocol (ca de exemplu tabelul 4.1 ) sau de VID-PID (ca de exemplu tabelul 4.2).
n cazul microcontroller-ului, spre deosebire de PC, TPL rmne fix, putndu-se suporta
doar dispozitivele declarate iniial.
Descriere

Numele clasei

Codul clasei

Codul subclasei Protocol

Flash Drive

Mass Storage

0x08

0x06

0x50

Tabelul 4.1: Exemplu de TPL pentru Clas, Subclas i Protocol

Descriere

Productor

Device
cu Google
suport ADK

Model

VID(vector ID) PID(product ID)

Telefon/ tablet 0x18D1

0x2D00

Tabelul 4.2: Exemplu de TPL pentru VID, PID


30

4.5.2.6.2 Arhitectura stivei

Este format din dou pri: maina de stri(pentru enumerarea dispozitivelor) i


handler-ul de ntreruperi(pentru procese critice).

Figura 4.16: Maina de stri


n figura 4.16 se prezint schema general pentru state machine. Iniializarea are
rolul de a pregti controller-ul USB, i se realizeaz o singur dat dup reset, trecnduse apoi n starea detached, n care se ateapt conectarea dispozitivelor. Un dispozitiv
ataat trece din starea atached n starea de primire a unei adrese dac respect condi iile
electrice specifice. Starea configured presupune pregtirea end point-urilor pentru a se
realiza transferul bidirecional, printr-un apel al handler-ului de iniializare specific
dispozitivului, folosind intrrile din TPL i Client Driver Table. La deconectare se trece
din starea running n starea detached.
Stiva de firmware este o structur de tip ierarhic. Aplicaia( codul utilizatorului)
reprezint ultimul nivel, USB Client Driver este folosit pentru iniializarea dispozitivului
31

descoperit, iar USB Host Layer este librria care faciliteaz accesul la resursele hardware
i ofer funcionalitatea de baz pentru modul: identificare, enumerare, managementul de
drivere. Pot exista mai multe USB Client Driver dac se dorete oferirea suportului
pentru un numr mai mare de dispozitive.
O organizare pe layers se folosete i pentru handler-ul de ntrerupere, avnd trei
nivele: electric, mesaje USB i mesaje Android(ultimul nivel). Fiecare nivel trateaz
evenimentele specifice, iar la ntlnirea unuia necunoscut se face o trimitere spre nivelele
superioare pentru analiz.
4.5.2.6.3 Driver-ul client bazat pe evenimente

Aplicaia principal are rolul de a apela


constant layer-ul de la nivelul cel mai sczut:
USB host(sgeat #2). La terminarea unei
activiti pe USB se va apela(#3) n client
driver, iar dac este suportat, se va apela mai
apoi aplicaia(#4). Apelurile, folosind structuri,
trimit i informaii legate de surs i parametrii.
Astfel tranziiile de la nivelele superioare, apar
ca urmare a evenimentelor de pe USB, fiecare
nivel avnd un state machine.
Layer-ul Host este influenat i de
evenimetele ce apar pe magistral cum ar fi
conectarea sau deconectarea unui dispozitiv.
Apelul #2 are rolul de a permite tranziiile ntre
sub-striile de la adresare sau configurare.
Se poate implementa driver-ul client i
folosind polling. Diferena ntre cele dou
metode apare la modul n care se face tranziia
ntre stri, marcat prin folosirea de while loops
( polling) sau de ntreruperi i call backs( event
Figura 4.17:
based). Varianta cu ntreruperi este mai
evenimente
eficient. Exemple de call back sunt apelurile
#3 i #4.

Driver-ul

bazat

pe

4.5.3 Android Open Accessory Protocol


Un USB host(accesoriul) va trebui s implementeze urmtorii pai:

ateapt i detecteaz conectarea device-ului cu Android

verific dac acest device suport modul accesoriu

dac nu este deja n acest mod va ncerca pornirea acestuia n modul amintit
32

stabilete comunicarea cu device-ul folosind protocolul amintit n subtitlu

Accesoriul verific la fiecare conectare a unui slave ca vendor ID device-ului s


fie 0x18D1, i ID de produs s fie 0x2D00(ADK) sau 0x2D01(ADK i ADB). Dac nu
se primesc aceste rspunsuri, microcontroller-ul va ncerca pornirea dispozitivului n mod
accesoriu: trimite o comand de tip 51, de obinere a protocolului, iar device-ul va
rspunde cu un numr nenul dac are implementat ADK.
Folosind comanda 52 se vor trimite pe rnd descrierile ctre accesoriu. Apoi se va
trimite device-ului comanda 53 pentru a porni n modul accesoriu. Dup trimiterea
comenzii 53, USB-ul de pe device se va reporni ceea ce duce la un nou proces de
enumerare. De aceast dat vendor ID i product ID trebuie s fie cele corecte, n caz
contrar, sau la orice eroare aprut pe parcurs, nseamn c device-ul nu cunoate
protocolul cerut. Pentru mai multe detalii legate de structura acestor mesaje standard
poate fi consultat seciunea 5.9. Comenzi USB din [25].
Command Request Type

Request Value

Index

Get
protocol
(5110)

USB_Dir_out|
USB_type_Vend
or| USB_Device

51

Send
strings
(5210)

USB_Dir_out|
USB_type_Vend
or| USB_Device

52

0... 5

Strart
(5310)

USB_Dir_out|
USB_type_Vend
or| USB_Device

53

Length
2

Data(optio
nal)
Get
protocol

String
Send
dimension string
0

Send Null

Tabelul 4.3: Comenzi de iniializare ADK


Dac ID-ul de productor este 0x2D00, atunci este o singur interfa cu dou
endpoint-uri bulk, unul pentru intrare i altul pentru ieire. Dac primim ID 0x2D01,
atunci sunt dou interfee(ADK i ADB) fiecare cu cte dou bulk endpoints. n tabelul
4.3 sunt prezentate schematic etapele protocolului, numerele fiind n baza zece. Valorile
lui index pentru comanda 52 n ordine cresctoare sunt: productor, model, descriere,
versiune, URI, i numr serial. URI se folosete pentru a se descrca aplica ia din Google
Play n cazul n care nu este instalat pe telefon/tablet. Comenziile 52 i 53 nu se
folosesc dac device-ul se afl deja n modul accesoriu.

4.6 Algoritmii propui


ntregul sistem poate fi privit ca i un sistem distribuit, deoarece fiecare modul i
execut funcionalitatea independent de restul.

33

Figura 4.18: Structura logic a aplicaiei


n figura 4.18 este prezentat schema general a aplicaiei. Codul de culori ofer o
mai bun grupare vizual a componentelor. Perifericele productoare/consumatoare de
date sunt colorate cu albastru, iar zonele partajate sunt de culoarea orange. Memoriile
partajate pot fi privite ca i buffere, cu mai multe periferice care scriu i care citesc din
aceste zone. Circuitele de USB i RTCC sunt colorate cu verde respectiv rou deoarece
ndeplinesc funcionaliti speciale. RTCC se folosete pentru a controla procesul de
actualizare a zonei comune vzut de USB, copierea datelor fcndu-se de la dreapta la
stnga(sgeata de pe desen). Modulul USB este cel care comunic mai departe cu tableta.
Direcia sgeilor arat modul de deplasare al datelor, fr a se insista pe tipul sau numele
datelor care circul.
Datele care intr n ADC sunt de tip analogic, iar cele care intr, respectiv ies din
IC i din PWM sunt de tip digital, de tip semnal dreptunghiular. RTCC este alimentat de o
sinusoid de 32768Hz.

34

4.6.1 Conversia din analogic n digital

Figura 4.19: Schema general de conversie


n figura 4.19 se prezint schema general de conversie din analogic n digital.
Primul pas presupune eantionarea i conversia efectiv a celor dou tensiuni(canal 1 si
canal 2). n funcie de ce zon folosim pentru salvare se va salva n zona 0 sau n 1.
Valoriile pentru i sunt de la 0 la 7, iar pentru j sunt de la 8 la 15. Att i, ct i j se vor
incrementa, iar dup ce au ajuns la 7 respectiv 15 se genereaz o ntrerupere i se
reiniializeaz. n ntrerupere are loc citirea celor 8 valori din buffere, n func ie de zona
de lucru i medierea lor. Eantionarea celor dou tensiuni se face n mod alternativ.
De exemplu, considerm c zona de lucru este 0. Se face conversia primei tensiuni
i salvarea n buffer-ul 0, iar a doua tensiune se salveaz n bufferul 1. Se va continua cu
salvarea canalului 1 n buffer-ul 2, i a canalului 2 n buffer-ul 3. Dup ce s-a scris i n
bufferul 7 se genereaz ntreruperea. n ntrerupere se ine seama de zona curent de lucru
i de alternana cu care se salveaz cele dou canale.

35

4.6.2 Msurarea turaiei

Figura 4.20: Msurare frecven puls


n figura 4.20 se prezint modul general n care se msoar frecvena unui semnal
dreptunghiular. Ct timp nu apare un front cresctor se incrementeaz un timer. La
apariia unui eveniment se genereaz o ntrerupere. n ntrerupere se verific dac a fost
primul astfel de eveniment. n caz afirmativ se reiniializeaz timer-ul. La al doilea
eveniment mai nti se va salva valoarea ceasului, apoi acesta se va reini ializa. Al treilea
eveniment este considerat din nou ca fiind primul, aciunea algoritmului fiind similar.

Figura 4.21: Modul de folosire al dou module de IC i un Timer


n figura 4.21 se prezint cazul n care se msoar dou frecvene folosind un
singur timer. Culoarea albastr reprezint primul canal, iar culoarea verde reprezint al
36

doilea canal. n acest caz mai nti se analizeaz primul canal n ateptarea a dou fronturi
de interes(F1 i F2). n acest timp orice eveniment pe al doilea canal este ignorat. Dup
msurarea perioadei primului canal(T canal 1) acesta se ignor i se urmrete apariia a
dou fronturi pe canalul 2. Ciclul apoi se reia cu primul canal. Pentru msurarea perioadei
pe oricare canal se consider algoritmul prezentat n prima parte a seciunii.n mod
similar, cazul de fa poate fi extins la orice numr de canale, cre terea numrului ducnd
la scderea ratei cu care se actualizeaz informaiile legate de frecvena lor.
4.6.3 Actualizarea datelor
Actualizarea datelor apare n figura 4.18 ca i un transfer ntre dou zone partajate.
Actualizarea repezint o copiere a datelor din zona din partea dreapt n zona din partea
stng.

Figura 4.22: Cele dou moduri de actualizare a datelor


n figura 4.22 sunt prezentate cele dou regimuri de funcionare a mecanismului
de actualizare: normal i calibrarea motoarelor. n modul de funcionare normal se face o
copiere a datelor la o frecven de 1Hz. Aceast frecven poate fi obinut folosind un
circuit extern, un timer intern sau circuitul de RTCC. Circuitul de RTCC are avantajul c
nu este folosit de alt component sau de ctre program.
n cazul n care se dorete o calibrare a motoarelor valoriile msurate vor fi
transferate imediat ce au fost calculate. Pentru aceasta la fiecare modificare a factorului
de umplere al PWM are loc un rspuns care cuprinde tensiuniile i frecvenele msurate.

37

4.6.4 Calibrare motoare


Procedura de calibrare presupune
folosirea factorului de umplere al PWM
care comand viteza motoarelor. Factorul
de umplere va lua valoarea initial 100%,
i va continua s scad att timp ct turaia
motorului este diferit de zero. n cazul n
care s-a ajuns la 0, motorul se consider
oprit, i factorul de umplere se seteaz la
zero. Procedura este evideniat n figura
4.23 i trebuie repetat pentru fiecare
motor n parte.
Calibrarea are rolul de a stabili
intervalul de valori pentru PWM care
produce rotirea motorului. Ca i rezultat se
elimin zonele cu factor de umplere mic, n
care motorul are turaie 0.
n locul decrementrii factorului deFigura 4.23: Calibrare motor
umplere se poate porni de la valoarea zero,
i apoi s se incrementeze ct timp turaia este zero. Aceast variant a algoritmului
produce un prag al factorului de umplere mai mare dect varianta care presupune
decrementarea. Explicaia const n faptul c pentru a se pune iniial n micare bobina
rotorului este nevoie de un impuls de tensiune mai mare. Odat ob inut mi carea de
rotaie, se poate reduce factorul de umplere cu cteva procente, fr a se constata oprirea
motorului.
4.6.5 nlnuirea comenzilor pe USB
n figura 4.24 se prezint modul n care poate fi crescut performana
transferurilor pe USB prin nlnuirea comezilor. Fiecare comand este identificat
printr-un cod unic urmat de un numr cunoscut de argumente. n exemplul urmtor s-a
considerat transmisia unui numr de 3 comenzi pe magistrala serial, fiecare comand
fiind de dimensiune variabil. Fiecare dreptunghi are dimeunea de 1 octet. Se folose te
un vector unde vor fi copiate comenziile, lungimea fiind egal cu suma dimensiunilor
comenzilor n cazul maxim de nlnuire.n cazul extrem numr maxim de nln uiri este
egal cu numrul de comenzi de ieire pe magistrala serial. Numrul poate fi redus dac
existena unor comenzi de ieire este exclusiv. Pointer-ul se folosete pentru a indica
locaia urmtoare unde se poate copia informaia.
La primul pas se copiaz prima comand i se incrementeaz poziia pointerului cu
3, reprezentnd numrul de octei mutai. Aciuni similare se execut i pentru
urmtoarele dou comenzi, pointer-ul indicnd la final locaia de dup argumentul
comenzii 3. Operaia poate fi extins pn la copierea unui numr de 1023 de octe i, dac
se folsete modul bulk. Principalul avantaj al nlnuirii l constituie faptul c printr-un
singur transfer de USB se vor transmite mai multe date. Un dezavantaj minor este
reprezentat de logica de decodificare a mesajului, care presupune mprirea acestuia n
38

tokens(comenzi) n funcie de codul aflat pe primul octet i manipularea individual a


fiecrei comenzi.
Pentru a se trimite i date care nu constituie comenzi, sau a cror lungime este
variabil, trebuie ca informaiile s fie mpachetate. n acest sens, se va folosi un cod de
mesaj special, pentru a codifica informaiile care nu constituie comenzi. Pe urmtorul
octet se va specifica numrul de bytes al mesajului, iar n urmtorii octe i se vor copia
datele efective. n acest caz pentru a se putea descifra mesajul este nevoie s se citeasc
primi doi octei, primul este folosit pentru a marca un mesaj special, iar urmtorul pentru
a specifica numrul de argumente componente.
O alt abordare pentru mesajele speciale presupune ncadrarea datelor ntre un cod
special i un marcator de final(asemntor \n n C). Pentru a se include marcatorul de
sfrit n corpul mesajului se va adopta o tehnic similar caracterelor escape din C.
Lipsa marcatorului de final va permite citirea ntregului buffer de intrare al USB, ceea ce
poate duce la pierderea comenziilor care nu vor mai fi interpretate.
Pentru introducerea mesajelor de dimensiune variabil, prima abordare este mai
sigur i mai uor de implementat.

Figura 4.24: nlnuirea comenziilor pe USB

39

5. Proiectare de detaliu i implementare

Figura 5.1: Schema general a aplicaiei


n figura 5.1 se prezint schema general a aplicaiei. Microcontroller-ul(uC) este
prezentat ca o component separat, cu rol n controlul traficului informaiei. Sgeiile
indic direciile de circulaie ale datelor. Senzorii i elementele de acionare sunt
prezentate ca i componente separate, dar o parte sunt uniti din interiorul uC, divizarea
fiind fcut astfel doar pentru a evidenia rolul lor diferit n sistem.
n figura 5.2 se prezint structura aplicaiei din punct de vedere al depenenelor de
componte hardware i software. Aplicaia de fa are ca i baz un exemplu oferit de
Microchip, n care se folosete tableta pentru a controla 4 LED-uri, a citi 2 butoane i un
poteniometru de pe plac. Codul de culori s-a folosit pentru a eviden ia zonele care au
presupus dezvoltare, sau care au avut nevoie doar de documentare i testare.
n partea superioar a imaginii sunt prezenate cu orange fiierele create pentru
realizarea funcionalitilor propuse. Divizarea pe fiiere are rolul de a permite o grupare
a algoritmilor folosii pentru ndeplinirea unui task. Fiierul mainDef.h conine o serie de
variabile externe, vizibile din mai multe fiiere, precum i ncapsularea accesului pentru
datele folosite de mai multe module prin folosirea de macro-uri. Pentru ndeplinirea unei
funcionaliti se folote perechea de fiiere .h i.c. n fiierul header sunt redefinii
regitrii folosii(pentru o denumire uniform) i parametrii de configurare. n fiierul
surs se gsete codul efectiv. Main.c este fiierul principal, i folosete funcionaliti
din restul modulelor. Conine iniializriile modulelor i bucla principal.
Android Accessory Framework i USB Stack sunt cele dou librrii care
realizeaz comunicarea pe protocolul Andoid Open Accessory. Aplicaia folosete cele
40

dou librrii amintite, mpreun cu Microchip Peripheral Library(MPL), care este folosit
pentru accesul la modulele de baz ale microcontroller-ului. MPL folosete cod scris n
ASM sau n C. Toate librriile au fost folosite ca atare, fiind nevoie doar integrarea lor n
proiect i testarea funcionalitilor.
Folosirea modulelor a presupus analiza modului de operare i a interdependenelor
existente, pentru a se folosi ct mai eficient un numr minim de astfel de componente.
Partea de hardware a presupus design-ul folosind unelte cum ar fi falstad.com/circuit,
prototipizarea pe breadboard i mprimarea efectiv a montajului pe o plac.

Figura 5.2:Dependenele aplicaiei

5.1 Modulul de DAC


Acest modul are o adres fix 0x60, pinii de A0- A2 find lipii la GND. Acest
modul este un convertor pe 12 bii asigurnd astfel un interval de 4096 de valori. Ie irea
este proporional cu intrarea, din aceast cauz este sensibil la valoarea intrrii.
S-au implementat funciile de scriere n registru i n EEROM precum i de citire
a registrului i a memoriei. Memoria nevolatil poate fi folosit pentru a se programa o
singur dat modulul, pentru ca apoi acesta s pstreze valoriile i dup o repornire a
sistemului.
Semnturile celor dou funcii de scriere void writeDACRegister(unsigned int
DACValue,
unsigned
short
PowerDownOption)
i
respectiv
a
void
41

writeDACRegisterAndEEPROM(unsigned
int
DACValue,
unsigned
int
PowerDownOption) sunt identice, prima valoare fiind un numr ntre 0- 4095, iar cea dea
doua valoare reprezint opiunea de power down, pentru a se obine high impedance dac
se dorete. Implementarea acestor metode urmrete Reference Manual-ul de la
productor.
Funcia de citire din DAC nu este folosit, semntura ei fiind BOOL
readDACRegisterANDEEPROM (BYTE i2cbyte[]), i returneaz un boolean pentru a
semnaliza dac operaia s-a executat sau nu cu succes, iar rezultatul este depus n
i2cbyte[].

Figura 5.3: Scrierea n registre, fr salvare n EEPROM


n figura 5.3 se prezint modul n care se poate scrie n registrele circuitului de
DAC, fr salvarea n EEPROM. n primul octet se precizeaz adresa dispozitivului,
mpreun cu tipul operaiei, n acest caz este una de scriere. n octetul al doilea i al
treilea se prezint valoriile care trebuie ncrcate n registre, de interes fiind DAC
Register, care va reprezenta valoarea ieirii; tipul operaiei se specific prin Fast Mode
Command. Fiecare byte se va confirma(Ack) de ctre DAC. Pentru a se salva n
EEPROM, n locul bitului de stop se repet coninutul octeiilor 2 i 3 de pe figur.

5.2 Modulul de Input Capture


S-a ales folosirea Timer 2 ca i baz de timp pe 16 bii, cu un prescaler de 16, i a
ntreruperilor de la canalul 2, respectiv 3 de la Input Capture. Am ales folosirea unei
abordri de tip state machine state pentru a se permite msurarea ct mai exact a dou
frecvene folosind un singur timer.
Se definesc macro-urile pentru prima surs sampleIC2Start i sampleIC2Stop ,
respectiv sampleIC3Start i sampleIC3Stop, pentru a doua surs de frecven i se
folosete o variabil care va trece prin cele 4 stri. Ca i exemplificare se folosete tabelul
5.1, abordarea fiind similar cu cea propus n seciunea 4.6.2.
Pentru msurarea lui IC2, variabila va lua mai nti valoarea sampleIC2Start,
odat cu primul rising edge; la urmtorul eveniment pe IC2 va trece n sampleIC2Stop. n
timpul n care variabila a avut una din cele dou valori enumerate mai sus, orice
eveniment de pe IC3 va fi pur i simplu ignorat. n sampleIC2Stop, doar un eveniment pe
IC3 va determina tranziia n sampleIC3Start, evoluia fiind similar pentru IC3.
Detecia opririi unuia dintre motoare se face folosind detectarea condiiei de
overflow de la baza de timp, caz n care se verific dac variabila este sampleIC2Start
sau sampleIC3Start , pentru a se determina sursa. Se va trece apoi la canalul urmtor n
starea de start, pentru a se evita blocarea algoritmului.
42

stare actual

rising edge
IC2

sampleIC2Start

stare urmtoare
sampleIC2Stop

sampleIC3Start

sampleIC2Stop

sampleIC3Start

reseteaz Timerul
pstraz
actual

IC3
IC3

Observaii
starea

preia valoarea din


Timer i l reseteaz

IC2

pstraz
actual

starea

IC2

pstraz
actual

starea

IC3

sampleIC3Stop

pstraz
actual

IC3
sampleIC3Stop
IC2

reseteaz Timerul

sampleIC2Start

starea

preia valoarea din


Timer i l reseteaz

Tabelul 5.1: Evoluia strilor pentru implementarea input capture


n continuare voi prezenta codul pentru ISR de input capture pentru primul canal:

1 | #if CaptureMotor1INTLevel == IC_INT_PRIOR_4


2 |
void __ISR(CaptureMotor1INTVector, ipl4)
InputCapture2Routine(void){
3 |
INTClearFlag(INT_IC2);
4 |
bufferTemp= CaptureMotor1ReadCapture()& 0xFFFF;
5 |
if(sampleICx== sampleIC2Start){
6 |
TimerValueReg= 0; // reset the timer
7 |
sampleICx= sampleIC2Stop; // go to next state
8 |
}else
9 |
if(sampleICx== sampleIC2Stop){
10|
val1IC2= bufferTemp; TimerValueReg= 0; sampleICx=
11|
sampleIC3Start;}
12|
if(CaptureMotor1ControlReg.ICOV)
13|
val1IC2= InCapOVFL;
14|
}
15| #endif

, i codul pentru ISR a timer-ului:

1 |
void __ISR(_TIMER_2_VECTOR, ipl1) Timer2Routine(void){
2 |
INTClearFlag(INT_T2);
3 |
if((sampleICx== sampleIC2Start) ||(sampleICx==
sampleIC2Stop)){
4 |
sampleICx= sampleIC3Start; val1IC2= TimerOVFLInCap;
5 |
}else
6 |
if((sampleICx== sampleIC3Start) ||(sampleICx==
sampleIC3Stop)){
7 |
sampleICx= sampleIC2Start; val1IC3= TimerOVFLInCap;
8 |
}
9 |
}

43

5.3 Modulul de PWM


n cadrul acestui modul, spre deosebire de celelalte, nu sunt alte funcii dect cea
de set up, nefiind necesare ntreruperi, totul fiind controlat de hardware.
Codul pentru funcia de set-up este urmtorul:
1
2
3
4
5
6
7

|
|
|
|
|
|
|

MotorsDirectionConfigPins();
MotorSpeedPWMConfigPins();
setMotorsDirection(1);
PWM_PRReg_FREQ= getPR_For_PWM(PWM_desired_freq, 1);
OpenTimerForMotors(MotorConfigs, PWM_PRReg_FREQ);
OpenOCMotor1(Motor1Configs, 0,0);//PWM motor 1
OpenOCMotor2(Motor2Configs, 0,0);//PWM motor 2

Pinii de output ai modului de PWM trebuie marcai ca fiind de ie ire.n func ia de


mai sus se seteaz doar frecvena bazei de timp, factorul de umplere pentru motoare fiind
fixat la zero.

5.4 Modulul de ADC


Active buffer

Index
0
1
2

3
4
5
6
7
8
9
10

11
12
13
14
15

Valoare
channel4mas1
channel8mas1
channel4mas2
channel8mas2
channel4mas3
channel8mas3
channel4mas4
channel8mas4
channel4mas1
channel8mas1
channel4mas2
channel8mas2
channel4mas3
channel8mas3
channel4mas4
channel8mas4

Tabelul 5.2: Folosirea buffer-elor de la ADC


n figura 5.2 se prezint modul n care sunt folosite cele 15 buffere pentru
eantionarea alternativ a dou canale. Ordinea se salvare a celor dou canale eantionate
44

este alternativ. La un moment dat se poate lucra cu o singur zon, fiind disponibile fie
registrele 0- 7, fie 8- 15. n ntrerupere se citesc cele 4 valori pentru fiecare canal din
zona activ, valoarea canalului fiind media lor. Modulul nu se poate folosi n cazul de
fa la valoarea maxim, deoarece produce blocarea restului perifericelor, chiar dac are o
prioritate mai mic dect restul.

5.5 Modulul de RTCC


n continuare se prezint o parte a void setUpRTCC_1secINT(), care realizeaz
configurarea
modulului
i
codul
handler-ului
de
ntrerupere
void
__ISR(_RTCC_VECTOR, ipl7SRS) RtccIsr(void).
1|
2|
3|
4|
5|
6|

RtccInit();
while(RtccGetClkStat()!= RTCC_CLK_ON);
RtccChimeEnable();
RtccSetAlarmRptCount(255);
RtccSetAlarmRpt(RTCC_RPT_SEC);
RtccAlarmEnable();

n acest cod are loc o iniializare a modului de RTCC, urmat prin while-ul care
testeaz dac este conectat oscilatorul extern. Urmtoarele 4 instruciuni sunt folosite
pentru a seta alarm i repetarea ei nedefinit( funcia de chime).
1
2
3
4

|
|
|
|

5
6
7
8

|
|
|
|

9 |
10|
11|
12|

#if RTCCLevel== INT_PRIORITY_LEVEL_7


void __ISR(_RTCC_VECTOR, ipl7SRS) RtccIsr(void)
{
INTClearFlag(INT_RTCC);
SetInputCapture1(GetFreqMotor1());
SetInputCapture2(GetFreqMotor2());
SetVoltageBatt(GetChannel4Batt());
SetVoltageSunt(GetChannel8Sunt());

}
#endif

mLedRTCCToggle();
rtcc_1secINTR= TRUE;

Handler-ul de ntrerupere al RTCC este cel care controleaz schimbul de date de


la i spre USB. Acest lucru se realizeaz prin cele 4 apeluri de macro i marcarea flagului rtcc_1secINTR cu TRUE. Variabila boolean se folosete n bucla principal din
main pentru ncrcarea efectiv a datelor pe magistral. Pentru a se obine o frecven
mai mare va trebui modificat repetarea alarmei la RTCC_RPT_HALF_SEC, ceea ce va
dubla frecvena de trimitere a datelor. Toggle-ul LED-ului are scop de verificare vizual.

5.6 Programul principal


n continuare voi prezenta programul principal prin evidenierea zonelor
importante pentru nelegerea algoritmului. Buciile de cod pot s fie diferite fa de cele
din codul aplicaiei, deoarece unele linii de cod au fost nlturate pentru a se putea
urmrii mai uor logica aplicaiei.

45

5.6.1 Structura comenziilor


Comenziile sunt definite folosind o enumerare, n locul unor typedef/macro pentru
o grupare vizual mai eficient.
1 |typedef enum _ACCESSORY_DEMO_COMMANDS
2 |{
3 |
COMMAND_getConfig_ADC
4 |
COMMAND_getConfig_Fuses_PWM
5 |
COMMAND_getConfig_InputCapture
6 |
COMMAND_getValue_InputCapture
7 |
COMMAND_getValue_Voltage
8 |
COMMAND_setValue_PWM
9 |
COMMAND_shutDown
10|
COMMAND_initialPWMConfig
11|
COMMAND_finishedPWMConfig
12|
COMMAND_getConfig_MotorsID
13|
COMMAND_setDirectionMotor
14|
COMMAND_APP_CONNECT
= 0xFE,
15|
COMMAND_APP_DISCONNECT
= 0xFF
16|} ACCESSORY_DEMO_COMMANDS;

=
=
=
=
=
=
=
=
=
=
=

0x01,
0x02,
0x03,
0x04,
0x05,
0x06,
0x07,
0x08,
0x09,
0x0A,
0x0B,

, iar lungimiile sunt fixe:

1 | #define Command_getValue_Voltage_Size

Coman Arg 1
d

Arg 2

Arg 3

Arg 4

ADC Size

[Vref]

{Vref}

Freq proc

FPLLMU FPLLDI
L
V

IC presc

IC size

HFreq IC 1 LFreq IC 1 HFreq IC 2 LFreq IC 2

HU unt

LU unt

HU battery

LU battery

HDuty

LDuty

HDuty

LDuty

motor 1

motor 1

motor 2

10

ID motor 1

ID motor 2

11

Dir motors

Arg 5

Arg 6

Arg 7

Arg 8

FPLLODI FPBDIV OC size Freq OC OC presc


V

Event size

motor

7
8
9

254
255
Tabelul 5.3: Comenziile trimise ntre tablet i uC
n tabelul 5.3 se prezint structura comenziilor. O parte a acestor comenzi sunt de
tipul flag, i nu au argumente, contnd doar ID lor, cum ar fi 7,8,9. Pentru parametrii care
ocup mai mult de un octet s-a folosit HArg respectiv LArg pentru partea superioar
46

respectiv inferioar a argumentului. Comenziile au structur i lungime fix.


Pachetele de intrare i de ieire nu sunt altceva dect un ir de bytes, lucru
evideniat prin codul care urmeaz:
1| typedef struct __attribute__((packed))
2| {
3|
BYTE command;
4|
BYTE data[MAX_COMMAND_DATA_Size];
5| }ACCESSORY_APP_PACKET outgoing_packet;;

Structura precedent poate fi folosit ca atare sau se poate considera c este


format dintr-un vector de bytes, aa cum se folosete n codul urmtor:
1 |
errorCode = AndroidAppRead(device_handle, (BYTE*)&command_packet,
(DWORD)sizeof(command_packet));
2 |switch(command_packet->command)
3 |
{
4 |
case
COMMAND_setValue_PWM:
5 |
commandSize= Command_setValue_PWM_Size+ 1;
6 |
if(initialPWMconfig== TRUE){
7 |
rtcc_1secINTR= TRUE;
8 |
SetInputCapture1(GetFreqMotor1());
9 |
SetInputCapture2(GetFreqMotor2());
10|
SetVoltageBatt(GetChannel4Batt());
11|
SetVoltageSunt(GetChannel8Sunt());
12|
}
13|
break;
14|
case COMMAND_initialPWMConfig:
15|
break;
16|
case COMMAND_finishedPWMConfig:
17|
break;
18|
case COMMAND_setDirectionMotor:
19|
break;
20|
case COMMAND_shutDown:
21|
break;
22|
case COMMAND_APP_DISCONNECT:
23|
break;
24|
default:
//Error, unknown command
25|
DEBUG_ERROR("Error: unknown command received");
26|
break;
27|
}
n timpul citiri cu AndroidAppRead, pe magistrala USB pot exista mai multe

comenzi nlnuite. Prin verificarea primului octet, care indic lungimea primei comenzi,
se determin numrul de bytes rmai pentru procesare i adresa din cadrul vectorului de
unde se va continua procesarea.
1| size-= commandSize;
2| relativeAddressInCommandPacket+= commandSize;
3| if(size!= 0)
4|
memcpy(command_packet,&read_buffer[relativeAddress],size);

5.6.2 Trimiterea datelor ctre tablet


n cazul n care se trimit mesaje la vitez maxim, fr a folosi ntrzierea de o
secund se produce nclzirea tabletei. Pentru a se limita numrul de mesaje trimise n
47

bucla principal din main se verific dac a trecut o secund de la ultima transmisie:
1| if(rtcc_1secINTR== FALSE)
2|
continue;

Se verific dac sunt i alte operaii de scriere n ateptare, iar n caz negativ se va
putea trimite mesajul dorit. Pentru a crete eficiena n coada de mesaje pot fi puse mai
multe mesaje, fiecare de dimensiune definit.
1| if(writeInProgress == FALSE){
2|
outgoing_packet.command = COMMAND_getValue_InputCapture;
3|
outgoing_packet.data[0]= ....

4|
memcpy(&write_buffer[adresaWrite],
(BYTE*)&outgoing_packet,
Command_getValue_InputCapture_Size+ 1);
5|
adresaWrite+= Command_getValue_InputCapture_Size+ 1;
6| }

n final are loc i scrierea propriuzis, precum i marcarea faptului c a avut loc o
scriere(writeInProgress ):
1| if(writeInProgress== FALSE){
2|
rtcc_1secINTR= FALSE;
3|
writeInProgress= TRUE;
4|
errorCode
adresaWrite);
5| }

AndroidAppWrite(device_handle,

write_buffer,

5.6.3 Funcia de trimitere a datelor ctre Android


n continuare se va prezenta modul n care se trimit datele ctre tableta Android,
fiind evideniate i fiierele n care sunt definite funciile respective, pentru a se putea
urmrii nivelurile multiple de redirectri care apar ca urmare a existenei layer-urilor.

usb_host_android.c:: AndroidAppRead(void* handle, BYTE* data, DWORD


size) . Se face o parcurgere a numrului de dispozitive Android i fiecare va fi
notificat. Parametrul handle reprezint informaia primit la conectara
dispozitivului, iar data este un buffer unde va fi depozitat informaia. Dac la
acest nivel se face verificarea de device la nivel de Android, la urmtorul nivel de
redirectare se va face verificarea de adresa, RX/TX busy, stare:

usb_host_android_protocol_v1.c::AndroidAppRead_Pv1(void* handle,
BYTE* data, DWORD size). Se folosete o redirectare la:

usb_host.c::BYTE USBHostRead( BYTE deviceAddress, BYTE


endpoint, BYTE *pData, DWORD size ), unde se va verifica la
nivel de tip de endpoint i starea ultimului transfer. Se va face o
nou redirectare la o metod din acelai fiier
void
_USB_InitRead(
USB_ENDPOINT_INFO
*pEndpoint, BYTE *pData, WORD size ) care va face
ncrcarea efectiv a registrelor cu valorile necesare.

5.6.4 Iniializarea comunicaiei pe USB i ADK


Se folosesc funciile: USBHostInit(unsigned long flag) i AndroidAppStart
(&myDeviceInfo), pentru realizarea iniializriilor necesare.n cadrul primei funcii se
folosete structura usbDeviceInfo pentru a se vedea dac exist sau trebuie alocat
48

Endpoint-ul 0, singurul care se folosete momentan n aplicaie. Are loc i o iniializare a


variabilelor folosite pentru meninerea adreselor i starea endpoint-ului curent, precum i
iniializarea stivei de evenimente.
n cadrul celei de-a doua funcii se iniializeaz structuriile:
ANDROID_ACCESSORY_INFORMATION, care conine informaii legate de
productor, model, descriere; ANDROID_DEVICE_DATA care conine informaii legate
de driver, protocol, stare, adrese; ANDROID_PROTOCOL_V1_DEVICE_DATA se
iniializeaz cu informaii legate de adresa device-ului, starea acestuia, numrul endpointului de intrare i de ieire, precum i starea liniilor RX i TX.
5.6.5 USBTask()= keep the stack running
Cuprinde dou apeluri de funcii: USBHostTask() i AndroidTask(). Prima funcie
are rolul de a asigura procesarea ultimului eveniment din stiv, i de a notifica aplicaia.
Funcia void AndroidTasks( void) verific dac dispozitivul conectat suport
modul accesoriu. Se folosete AndroidTasks_Pv1() pentru a itera peste numrul de
dispozitive conectate, verificnd la fiecare descrierea i dac poate ntra n modul
accesoriu. n caz afirmativ se apeleaz funcia de call back din fiierul principal
USB_ApplicaionEventHandler , folosit pentru a seta flag-uri care marcheaz
descoperirea unui nou dispozitiv.
5.6.7 Iniializarea plcii de dezvoltare
Funcia initPIC() are rolul de a iniializa platforma de dezvoltare s funcioneze la
o frecven de 60MHz. n fiierul HARDWARE_PROFILE_PIC32MX460F512L.h se
definesc parametrii de funcionare cum ar fi frecvena de baz a sistemului, frecven a
pentru periferice, i o serie de flag-uri pentru a semnala perifericele folosite de aplicaie.

5.7 Logica general a aplicaiei


Folosind ca i suport explicaiile din capitolele anterioare n continuare se va
prezenta logica de ansamblu a aplicaiei. Se va folosi pseudocod pentru exemplificare:
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10|
11|
12|
13|
14|
15|
16|

iniializare_module();
activare_intreruperi();
while(1){
USBTasks();
if(device_attached == FALSE) continue;
if(readyToRead == TRUE)AndroidAppRead();
AndroidAppIsReadComplete();
while(size > 0)proceseaz_comenzi();
readyToRead= True;
if(connected_to_app == FALSE)continue;
if(configsSendOK== FALSE)send_configs();
if(writeInProgress== TRUE )
AndroidAppIsWriteComplete() ;
if(rtcc_1secINTR== FALSE)continue;
if(writeInProgress== FALSE)AndroidAppWrite();
}

Aplicaia este format din dou pri: iniializarea modulelor folosite i bucla
49

principal care ruleaz la infinit.


n partea de iniializare se configureaz fiecare modul i se activeaz global
ntreruperile.
Fiecare iteraie a buclei va apela USBTask pentru a menine funcionarea stivei
USB. n cazul n care nu este ataat niciun dispozitiv pe magistral se continu cu itera ia
urmtoare. Spre deosebire de linia 5, n linia 10 se verific dac s-a primit mesajul de
conectare de la aplicaia Android. i n acest caz se continu cu iteraia urmtoare n caz
negativ.
Mecanismul de citire este prezentat n liniile 6 i 7, iar cel de scriere n liniile 13 i
15. Mecanismul de citire verific la fiecare pas dac ultima operaie de citire s-a executat
cu succes, ns pentru write se folote un flag, verificarea fiind fcut doar dac a avut loc
o scriere precedent. n cazul n care s-a citit cel puin o comand n linia 8 se va procesa
irul de octei primit, iar n rndul urmtor se marcheaz terminarea procesrii, ceea ce
permite citirea unei noi valori.
Fiecare dispozitiv conectat pe magistral va primi informaiile legate de
configuraia microcontroller-ului: dimensiunea registrelor, frecvenele folosite, procedeu
evideniat n linia 11.
Pentru a nu se produce o ncrcare a magistralei cu informaii despre tura ii i
tensiuni, se folosete o ntrziere de minim o secund fa de ultimul transfer. La
frecvene mari ale transferului dinspre microcontroller spre Android s-a constat o cre tere
a temperaturii tabletei, i performane mai sczute.
Un mecanism care nu a fost prezentat n pseudocod este cel de schimbare a
direciei motoarelor. Se folosete mecanismul din linia 14 pentru a verifica c a trecut cel
puin o secund ntre oprirea motoarelor i schimbarea direc iei, cu scopul de a proteja
puntea H de scurt-circuit. Orice instruciune aflat dup linia 14 va fi executat o dat la
o secund.

50

6. Testare i validare

Figura 6.1: Functionarea cu o surs rcire


Verificarea RTCC s-a fcut folosind DMCI, un plug-in pentru NetBeans, folosind
ca i baz de timp un timer pe 32 de bii, alimentat direct de la ceasul sistemului la
80MHz. n ntreruperea de la RTCC o dat la o secund se cite te timerul apoi acesta se
reiniializeaz. Curbele obiute sunt relativ line, iar abaterea astfel calculat este de 2.25e6, ceea ce reprezint o perioad de 1.0000655 secunde pentru RTCC.

Figura 6.2: Funcionarea cu o surs de cldur


n figurile 6.1 i 6.2 se prezint graficele pentru funcionarea extrem: alturi de o
surs de cldur sau folosind un ventilator ndreptat spre oscilator.
n figura 6.3 s-a analizat oscilatorul circuitului de timp real, model LF
XTAL002995, al firmei IQD, dup ce a fost adugat un condensator de 220pF, in paralel
celui exstent, C15 de pe plac. S-a obinut o frecven apropiat de 32 768Hz.
51

Figura 6.3: Analiza folosind osciloscopul


Alturi de analiza circuitului de RTCC s-au studiat i diferenele ntre valoarea
afiat pe tablet i msurat folosind osciloscopul, pentru divizorul de tensiune(figura
6.4) i pentru unt(figura 6.5), diferenele fiind nesemnificative.

Figura 6.4: Valoarea msurat pe osciloscop(stnga) i 4* tensiunea msurat de


plac(dreapta); pentru divizorul de tensiune
n figura 6.5 cu galben se prezint tensiunea pe unt dup filtrarea folosind
condensatorul iar cu rou se prezint semnalul dac nu se folosete filtrare. Frecven a
vrfurilor de consum este identic cu cea de la acionarea motoarelor cu semnalul
dreptunghiular al PWM.
52

Figura 6.5: Valoarea msurat pe unt folosind osciloscopul(stnga) i tableta(dreapta)


Ieirea circuitului DAC a fost analizat folosind osciloscopul, fr a se obine
diferene notabile ntre valoarea dorit i cea msurat. De asemenea forma este una
liniar, fr fluctuaii, potrivit astfel pentru a fi folosit ca i referin.

Figura 6.6: Ieirea circuitului de DAC

53

7. Manual de instalare i utilizare


7.1. Instalare
n continuare se vor explica modul n care se realizeaz montajul cablat asociat
microcontroller-ului i paii necesari instalrii aplicaiei.
7.1.1 Instalare hardware
Pentru a se putea realiza montajul sunt necesare: o plac de tip Cerebot32MX4, 4
rezistene, 1 condensator, dou motoare, suporturile necesare i cabluri pentru conectic.
Placa de tip Cerebot32MX4, poate fi schimbat uor cu alt tip de plac, de la
Digilent care are microcontroller de tip PIC 32MX, fiind necesare doar mici modificri,
care pot fi uor descoperite prin compararea celor dou Reference Manual. n continuare
se va prezenta montajul.
Schema circuitului de msurare a fost prezentat n figura 4.1. Ea cuprinde 4
rezistene de 1 K, legate n serie, i avnd rol de divizor de tensiune. Condensatorul are
rol de netezire a fluctuaiilor de tensiune, i are valoarea de 4700 F, fiind produs de
SAMXON. untul este unul improvizat, cu 4 borne, cte dou pentru plus respectiv minus
i are o rezisten de 0.8 msurat cu puntea Wheatstone.
Deoarece acumulatorii actuali sunt de capacitate mic se recomand alimentarea
plcii prin alt circuit. Poate fi folosit n acest sens cablul USB folosit la programare sau o
surs de la Digilent( care se conecteaz la 220V) sau 4 baterii de 1.5V. Pentru alimentarea
plcii se vor folosi tensiuni cuprinse ntre 3.6V- 5V DC, iar consumul de curent este ntre
250mA i 300mA.
n figura 7.1 se prezint schema general de montaj. Nu se insist exact pe pinii
unde se conecteaz perifericele, fiind evideniat doar portul. Pentru a afla pozi ia pinilor
se va folosi tabelul 7.2. Firele de alimentare folosesc conven ia: rou la Vcc i negru la
GND. n cazul conectrii circuitului de msur la plac se folosesc 3 fire: negru, alb i
rou. Pe aceast schem se folosesc alte culori pentru a se deosebi de circuitul de
alimentare. Culoarea albastr folosit la conectarea motoarelor i pentru USB are rolul de
a arta c este vorba despre o grupare de fire, respectiv despre o magistral.
Tensiunea generat de DAC se conecteaz la ADC ca i referin extern prin
dou fire: rou i negru. Oscilatorul cu quartz, modelul LF XTAL002995 al firmei IQD,
din poziia X2 este reprezentat n zona central folosind o imagine default. Pentru
funcionarea corect are nevoie de lipirea n paralel cu C15 a unui condensator de 220 pF.
n tabelul 7.1 se prezint poziia jumper-ilor care influeneaz n mod direct
aplicaia. Restul jumper-ilor pot fi n orice poziie, i nu vor influena funcionarea
normal. Se pot folosi n paralel cablul de programare/depanare conectat la PC i la J11 i
o alimentare de la o surs extern pentru plac.

54

Figura 7.1: Schema general de montaj

Jumper

Poziie

J10

Explicaii
Ieirea de la DAC

J12

External power

Alimentare de la o surs
extern prin J13, J14 sau J18

J16

VBUSON

Alimentare USB

JP5

Conectat

Detectare supra-cureni pe
USB
Selecie ntre alimentarea
J17 i J15(micro USB, pe
verso-ul plcii)

JP6

Host

JPA- JPK

3.3V

Alimentare
3.25V

Poziie default

Nu influeneaz aplicaia

Restul

periferice

la

Tabelul 7.1: Poziie jumpers


55

n tabelul 7.2 se prezint modul de conectare al perifericelor la plac.


Pin PMod(periferic)

Pin Cerebot

DAC GND( Negru)

JK 07

DAC Referin( Rou)

JK 08

Explicaii
Referina pentru ADC

GND circuit msur(Negru) JJ 02


Voltaj unt(Rou)

JJ 09

Voltaj divizor baterii(Alb)

JJ 07

Motor 1 HB5

JD 01- JD06

Motor 2 HB5

JD 07- JD12

Tablet Android

J17

Circuitul extern de msur

Motoarele au nevoie de
surs extern de alimentare
Conectare tablet folosind
cablu USB

Tabelul 7.2: Legarea pinilor de la Cerebot la pinii perifericelor.


7.1.2 Instalare software
Pentru a se putea rula aplicaia de fa este nevoie s fie instalat MPLAB X v1.10
sau o variant mai nou; instalarea Microchip Application Library nefiind necesar. Ca i
sitem de operare am folosit Windows 7, pe 64 de bii. Librria de PIC C folosit are
versiunea 2.02.
Folosind opiunea de Package care poate fi gsit printr-un click dreapta pe proiect
se va obine o copie portabil a proiectului. Structura de directoare dup dezarhivare
difer de o structur clasic de proiect, deoarece toate dependenele sunt copiate local.
Pentru a se programa mucrocontroller-ul se vor executa paii:
1. Se va dezarhiva codul surs. Fie C:\Folder Test\Android App calea unde s-a
realizat dezarhivarea. n folderul Andoid App se va gsi directorul scr care conine
aplicaia i toate dependenele.
2. Se va importa codul surs aflat n C:\Folder Test\Android App\src\Android
Accessories\Basic Communication Demo [RMK] v2\Firmware
3. Folosind click dreapta pe proiect i Properties se va verifica c n partea dreapt
n zona Configuration tipul Device -ului este PIC32MX460F512L(figura 7.2,
marcajul #1). Se va verifica ca la Compiler Toolchains s fie selectat un C32(#2).
n partea stng la Categories se verific c PIC32MX460F512L_PIM este
activ(nconjurat cu [ i ])(#3). n caz contrar n partea de jos la Manage
configurations(#4) se va putea activa(#5).
4. Se vor salva modificrile prin Ok (#6).
5. Se va programa microcontroller-ul folosind opiunea Make and program device
main project.
Un prim indiciu asupra succesului programrii l constituie aprinderea lui LED2 la
un interval de 1 secund.
56

Figura 7.2: Proprietiile proiectului


n figura 7.3 se prezint buid path; cile analizate pentru include sunt fie locale,
obinute n urma dezarhivrii codului i aflate n C:\Folder Test\Android App ; sau sunt
fiiere aflate n sursele compilatorului C:\Program Files (x86)\Microchip\mplabc32.

Figura 7.3: Structura de directoare analizat pentru include

7.2 Manualul utilizatorului


Utilizatorul va trebui s acioneze ntreruptorul SW1( pentru a permite alimentarea
microcontroller-ului) i s conecteze tableta folosind USB-ul.
57

8. Concluzii
Aceast rubric cuprinde 3 categorii, i anume: un rezumat, rezultatele
experimentale obinute i posibile dezvoltri/ mbuntiri.

8.1 Rezumat
Sistemul de fa are principalele atribuii de a monitoriza consumul de curent din
circuit i de aciona motoarele. Interaciunea cu utilizatorul se face printr-o tablet,
folosind USB i protocolul Android Open Accessory.
Se folosesc dou canale analogice pentru msurarea tensiunii de pe unt i de pe
divizorul de tensiune. untul fiind de valoare cunoscut se va transforma cderea de
tensiune n curent. Ca i voltaj de referin se folosete ieirea circuitului de DAC, care
este fixat la 1.5V.
Frecvenele minime ale motoarelor ce pot fi msurate au valoarea de 30Hz. Se
msoar turaiile efective, nainte de reductorul de 1:19. La turaii mai mici dect limita
inferioar se constat oprirea motorului deoarece corespunde unui factor de umplere al
PWM sub pragul minim de funcionare.
Pentru calcularea consumului total n circuit se folosete un circuit de RTCC
pentru a salva o dat la o secund valoriile msurate care apoi vor fi trimise pe USB i
nsumate pe tablet. Principalele date care sosesc de la tablet sunt cele referitoare la
factorul de umplere pentru PWM.
Pentru a se asigura independena i portabilitatea, naintea conectrii unui
dispozitiv pe USB se trimit parametrii microcontroller-ului: dimensiunea registrelor care
conin rezultatele i frecveele de lucru pentru ceasul sistem i cel al perifericelor precum
i factorii de divizare pentru semnalele de ceas folosite de periferice.

8.2 Rezultate obinute

58

Figura 8.1: Valoare RTCC msurat n condiii normale


n figura 8.1 se prezint comportarea circuitului de RTCC n condi ii normale,
msurat folosind oscilatorul principal de 80MHz. Tehnica de msurare folosit a fost
descris n capitolul 6, i se bazeaz pe acurateea cristalui principal de pe plac. Abaterea
frecvenei msurat n acest nod este de 2.25ppm, valoare care se ncadreaz n limita
recomandat de productor de 20ppm. Cu toate acestea valoriile obtinute pentru
intervalul de o secund sunt n jurul valorii de 1.0000655sec. Frecvena diferit a
oscilatorului secundar este confirmat de figura 6.3 unde valoarea msurat este de
32.89KHz. Funcionarea n prezena unei surse de cldur(figura 6.1) sau de rcire(6. 2)
produce efecte vizibile n ceea ce privete frecvena de funcionare, aa cum specific i
productorul. Aspectul uniform al graficelor, precum i eroarea mai mic de 10e-6,
recomand folosirea RTCC ca i baz de timp pentru msur.
Diferenele ntre valoriile de tensiune msurate pe microcontroller-ul i osciloscop
sunt mai mici de ordinul 0,001, lucru vizibil n figurile 6.4, i 6.5. Pot s apar unele
diferene momentane mai mari, n special la valoarea de pe unt, care aa cum se observ
n imaginea 6.5 prezint mici fluctuaii. Pentru calibrare s-a folosit msurarea unei
tensiuni stabile(ieirea de la DAC) folosind ADC de pe plac; n acest caz erorile au fost
sub pragul de 0.001. Nu se recomand folosirea depanrii pentru a citi valoarea msurat,
deoarece fiecare pas de depanare produce o fluctuaie semnificativ n consumul de
curent. Pentru verificare se poate folosi trimierea valorii pe UART.
Funcia de calibrare a motoarelor obine diferene ntre cele dou turaii ale
motoarelor de 6Hz, ceea ce reprezint o abatere de 3% ntre motoare. O cauz posibil o
reprezint diferenele ntre cele dou puni H, care nu reuesc s produc ieiri identice
chiar dac comenziile sunt identice( au fost conectate acelai PWM). Pentru compensare,
se folosete o bucl nchis de reglaj implementat n software-ul de pe tablet. Motorul
care are turaie mai mare va fi ncetinit pentru a ajunge la turaia celui lent.
Pentru testare s-a folosit un singur microcontroller i o singur tablet, precum i
un singur circuit de msur. Posibilitatea portrii codului pentru placa de dezvoltare a fost
testat folosind un alt PC i urmrind paii din seciunea 7.1.2.

8.3 Posibile dezvoltri i mbuntiri ulterioare


O prim dezvoltare ar putea fi introducerea unui RTOS. Acest lucru aduce cu sine
59

o serie de probleme cum ar fi faptul c stiva de Android/USB trebuie adaptat pentru


mediul multi-tasking. Aceast problem este tratat n Integrating Microchip Libraries
with a Real-Time Operating System, un application note oferit de Microchip. Avantajele
evidente sunt: o mai mare modularitate a codului i evidenierea mult mai clar a
dependenelor ntre module prin folosirea cozilor, sau a semafoarelor. n acest sens s-a
instalat pe plac FreeRTOS, i s-au rulat unele aplicaii de test, fr a instala i librria de
USB.
O alt dezvoltare legat tot de sistemele de operare o constituie instalarea unei
versiuni de Linux. Acest lucru face posibil folosirea unui numr mare de programe
scrise n C pentru Linux i destinate iniial pentru PC, s fie folosite i aici. Instalarea
unui kernel clasic de Linux pe configuraia actual este aproape imposibil, n principal
datorit memoriei limitate, aa cum se arat pe forumul [28], dar o versiune minimal de
Linux, adaptat pentru embedded, ar putea fi instalat.
Folosirea codului scris n asamblare constituie ntotdeauna o mbuntire, ns
pentru aceasta este necesar o analiz amnunit a codului, pentru a identifica zonele
care merit mbuntite. Se poate folosi n acest sens Legea lui Amdahl.
Ca i o alt mbuntire, o analiz mai amnunit a codului ar putea duce la o
reducere a dimensiunii unor variabile, sau la eliminarea altora. De asemenea cmpurile
structurilor pot fi specificate de ce dimensiune s fie, mpiedicnd astfel s se mai fac
alinierea.
O alt mbuntire o constituie folosirea zonelor critice. n aplicaie, n
configuraia de fa, nu se folosesc zone critice pentru a se accesa variabilele importante
pentru aplicaie. Singurul mecanism de protecie fiind folosirea nivelelor multiple de
prioriti pentru ntreruperi, cu nivelul cel mai ridicat pentru RTCC. Cel mai simplu mod
de implementare a zonelor critice l constituie dezactivarea general a ntreruperilor la
intrarea n ISR i reactivarea lor la ieirea din handler.
Pentru a se reduce consumul de curent se poate folosi microcontroller-ul n modul
de sleep, atunci cnd nu sunt date de procesat. Pentru aceasta, ar trebui diminuat de
asemena i frecvena cu care se intr n ntreruperile fiecrui modul, s fie ct mai
apropiat de 10 Hz, pentru a se realiza 10 msurtori ntre dou transferuri pe magistrala
de USB.
Funciile a cror durat de execuie este mare, pot fi mpr ite ntre mai multe stri
i la fiecare apel s se fac doar un pas din algoritm. Astfel se reduce durata apelului
funciei dar crete complexitatea n ceea ce privete n elegerea codului i mentenana lui.
Pentru a se mbunii i mai mult timpul general de execuie i main loop-ul poate fi
divizat n stri i vor fi apelate anumite funcii doar dac a fost un eveniment.
Ca i o mbuntire a codului, se poate schimba vizibilitatea variabilelor i se pot
semnala cele accesibile din mai multe surse cu volatile. De asemnea se pot folosi mult
mai intens pointeri. Respectarea unui standard industrial cum ar fi MISRA sau chiar
ANSI C ar fi binevenit.
Pentru creterea modularitii n anamblu se poate folosi un ecran tactil, care s ne
permit realizarea configuraiilor plcii. Astfel se poate selecta numrul de motoare din
sistem, dac se dorete conectarea la acelai Output Compare, ce resurse hardware se vor
60

folosi(n cazul n care se poate alege ntre dou module similare), diverse frecven e de
lucru. Acest lucru ar duce la o adaptare mult mai bun la cerine, i o configurare rapid
pentru un numr mare de aplicaii.

61

Bibliografie
[1]
"Android
Serial
Port",
http://www.progsrp.moonfruit.com/#/androidserial/4548697508.
[2] "Android G1 Serial to USB Cable", http://www.instructables.com/id/Android-G1Serial-Cable/.
[3] "Microbridge", http://code.google.com/p/microbridge/.
[4] "Amarino", 2009, http://www.amarino-toolkit.net/index.php/docs.html.
[5] "Tutorial: Android to Microcontroller via Bluetooth", 2011,
http://www.ryandebenham.com/?cat=14.
[6] "The Android Debug Bridge (ADB)", 2011,
http://www.androidauthority.com/about-android-debug-bridge-adb-21510/.
[7] "A closer look at Googles open accessory development kit", 2011,
www.romfont.com/2011/05/11/a-closer-look-at-googles-open-accessory-developmentkit/.
[8] "Android Open Accessory Development Kit", 2011,
http://developer.android.com/guide/topics/usb/adk.html.
[9] "Microchip's Accessory Framework for Android(tm)", Microchip, 2011.
[10] "A Bright Idea: Android Open Accessories", 2011, http://androiddevelopers.blogspot.com/2011/05/bright-idea-android-open-accessories.html.
[11] "Google I/O 2011: Android Open Accessory API and Development Kit (ADK)",
2011, http://www.youtube.com/watch?v=s7szcpXf2rE.
[12] "Google I/O 2011: Keynote Day One ", 2011, http://www.youtube.com/watch?
feature=player_embedded&v=OxzucwjFEEs#!.
[13] "Harman to bring Android integration to cars... finally", 2011,
www.autoblog.com/2011/07/15/harman-to-bring-android-integration-to-cars-finally/.
[14] Nicklas Hochy, Kevin Zemmery, Bernd Wertherand Roland Y. Siegwart ,"Electric
Vehicle Travel OptimizationCustomer Satisfaction Despite ResourceConstraints",
IEEE 2012 Intelligent Vehicles Symposium, Alcal de Henares, 2012.
[15] Roland Siegwart, Illah R. Nourbakhsh ,"Introduction to Autonomous Mobile
Robots", MIT Press, Cambridge, 1st edition, 2004.
[16] "Timers", Microchip, 2011.
[17] "Output Compare", Microchip, 2011.
[18] "Input Capture", Microchip, 2011.
[19] "Inter-Integrated Circuit (I2C)", Microchip, 2011.
[20] "10-bit Analog-to-Digital Converter (ADC)", Microchip, 2011.
[21] "Oscillators Reference Manual", Microchip, 2011.
[22] "Real-Time Clock and Calendar (RTCC)", Microchip, 2011.
[23] "Interrupts Reference Manual", Microchip, 2011.
[24] Zoltan Francisc Baruch ,"Sisteme de I/E", Editura Albastr, Cluj-Napoca, edi ia 1,
2000.
[25] Baruch Zoltan Francisc ,"INTERFAA USB", UTCN, Cluj-Napoca, Lucrare de
laborator.
[26] "USB OTG and Embedded Host", Microchip, 2008.
[27] "USB Embedded Host Stack Programmer's Guide", Microchip, 2008.
[28] "PIC32 Linux / eCos Challenge", 2011,
http://www.microchip.com/forums/m293237.aspx.
62

Anexa 1.
/*
* File:
HardwareProfile - PIC32MX460F512L PIM.h
* Description: Used to specify board settings
*/
#ifndef HARDWARE_PROFILE_PIC32MX460F512L_PIM_H
#define HARDWARE_PROFILE_PIC32MX460F512L_PIM_H
/**
Board
definition
***********************************************/
// These defintions will tell the main() function which board is
// currently selected. This will allow the application to add
// the correct configuration bits as wells use the correct
//
initialization functions for the board.
These defitions are
only
// required in the stack provided demos. They are not required in
// final application design.
#define DEMO_BOARD PIC32MX460F512L_PIM
#define EXPLORER_16
//#define RUN_AT_48MHZ
//#define RUN_AT_24MHZ
#define RUN_AT_60MHZ
// Various clock values
#if defined(RUN_AT_48MHZ)
#define GetSystemClock()
#define GetPeripheralClock()
#define GetInstructionClock()
#elif defined(RUN_AT_24MHZ)
#define GetSystemClock()
#define GetPeripheralClock()
#define GetInstructionClock()
#elif defined(RUN_AT_60MHZ)
#define GetSystemClock()
#define GetPeripheralClock()
divided down
#define GetInstructionClock()
#else
#error Choose a speed
#endif

48000000UL
48000000UL
(GetSystemClock() / 2) ???
24000000UL
24000000UL
(GetSystemClock() / 2) ???
60000000UL
60000000UL

// Will be

(GetSystemClock() / 2) ???

#define DEMO_BOARD_NAME_STRING "PIC32MX460F512L PIM"


/** Hardware use, the values aren't used in
****************/
#define InputCaptureChannel2
#define InputCaptureChannel3
3
#define ADC1
1
#define OutputCompare2
2
#define OutputCompare3
3
#define Timer2ForInputCapture
2
#define Timer3ForOutputCompare 3
#define RTCC1sec
1
#define I2CChannel1ForDAC
1
/**
Interrupts
***********************************************/

practice

level

63

#define
#define
#define
#define
#define

CaptureMotor1INTLevel
IC_INT_PRIOR_4
CaptureMotor2INTLevel
IC_INT_PRIOR_4
TimerForICINTLevel
T1_INT_PRIOR_1
INTLevelADC
ADC_INT_PRI_3
RTCCLevel
INT_PRIORITY_LEVEL_7
/**
I/O
pin
definitions
********************************************/
#define INPUT_PIN 1
#define OUTPUT_PIN 0
#endif

//HARDWARE_PROFILE_PIC32MX460F512L_PIM_H

Anexa 2.
/*
* File:
InputCap.h
* Description: Define public function; redefine used registers
*
* Created on March 6, 2012, 9:54 PM
*/
#include "HardwareProfile.h"
#ifndef InputCap_H
#define InputCap_H
#define sampleIC2Start 1
#define sampleIC2Stop
2
#define sampleIC3Start 3
#define sampleIC3Stop
4
#define TimerOVFLInCap 1
#define InCapOVFL
2
// - Capture Every rise edge
// - Enable capture interrupts
// - Use Timer 2 source
// - Interrupt on every edge of interest
#define ICsettings IC_EVERY_RISE_EDGE | IC_INT_1CAPTURE |
IC_TIMER2_SRC | IC_FEDGE_RISE | IC_ON
/**
* Will prepare the Input Capture for channel 2 and 3, using as the
time base Timer 2
* We use a prescaler for Timer 2, in order to get small
frequencies, around 30HZ
* We will use interrupts asociated with the input capture and the
timer
*/
void setUpInputCap();
#ifdef InputCaptureChannel2
#define CaptureMotor1PortEnable
mPORTDSetPinsDigitalIn(1<<
9);
// IC2 for the first motor
#define OpenCaptureMotor1
OpenCapture2
#define SetPriorityICMotor1
SetPriorityIntIC2
#define EnableINTICMotor1
EnableIntIC2
#define CaptureMotor1INTVector
_INPUT_CAPTURE_2_VECTOR
#define CaptureMotor1INTBit
INT_IC2
#define CaptureMotor1ReadCapture
mIC2ReadCapture
#define CaptureMotor1ControlReg
IC2CONbits
#endif
#if defined(InputCaptureChannel3)

64

1);

#define CaptureMotor2PortEnable
mPORTCSetPinsDigitalIn(1<<
// and IC3 for the second motor
#define OpenCaptureMotor2
OpenCapture3
#define SetPriorityICMotor2
SetPriorityIntIC3
#define EnableINTICMotor2
EnableIntIC3
#define CaptureMotor2INTVector
_INPUT_CAPTURE_3_VECTOR
#define CaptureMotor2INTBit
INT_IC3
#define CaptureMotor2ReadCapture
mIC3ReadCapture
#define CaptureMotor2ControlReg
IC3CONbits

#endif
#if defined(Timer2ForInputCapture)
#define OpenTimerForIC
#define TimerForICConfigs
T2_PS_1_32
#define TimerForICSetPriority
#define TimerForICSetSubPriority
#define TimerForICINTEnable
#define TimerValueReg
#endif
#endif

OpenTimer2
T2_ON | T2_SOURCE_INT|
mT2SetIntPriority
mT2SetIntSubPriority
mT2IntEnable
TMR2

Anexa 3.
/*
* File: InputCap.c
* Description: Contains the code to sample two channels
*/
#include <plib.h>
#include "InputCap.h"
#include "../HardwareProfile.h"
unsigned int bufferTemp;
/*@see main.c*/
extern unsigned int val1IC2;
extern unsigned int val1IC3;
extern BYTE nrImpulsuriIC2;
extern BYTE nrImpulsuriIC3;
extern BYTE nrEvents1, nrEvents2;
BYTE sampleICx= sampleIC2Start;
void setUpInputCap(){
CaptureMotor1PortEnable;
CaptureMotor2PortEnable;
// Enable Input Capture Module 2
OpenCaptureMotor1(ICsettings);
SetPriorityICMotor1(CaptureMotor1INTLevel | IC_INT_SUB_PRIOR_3); //
Priority 4
EnableINTICMotor1;
// Enable Input Capture Module 3
OpenCaptureMotor2(ICsettings);
SetPriorityICMotor2(CaptureMotor1INTLevel | IC_INT_SUB_PRIOR_2); //
Priority 4
EnableINTICMotor2;

65

// We use timer 2 for measuring the input capture


OpenTimerForIC(TimerForICConfigs, 0xFFFF); // we use a prescaler of
32 to get freq over 30Hz
TimerForICSetPriority(TimerForICINTLevel); // will have a freq of
3.75Mhz for a Periph clock of 60Mhz and T= 266.7 ns
TimerForICSetSubPriority(2);
TimerForICINTEnable(TRUE);
}
/**
* We use a state machine to figure out if it is time to read the value
or not
*/
#if CaptureMotor1INTLevel == IC_INT_PRIOR_4
void __ISR(CaptureMotor1INTVector, ipl4) InputCapture2Routine(void){
INTClearFlag(INT_IC2);
bufferTemp= CaptureMotor1ReadCapture()& 0xFFFF;
nrImpulsuriIC2++;
// will count no mather in what
state we are
if(sampleICx== sampleIC2Start){
TimerValueReg= 0; // reset the timer
sampleICx= sampleIC2Stop; // go to next state
}else
if(sampleICx== sampleIC2Stop){
val1IC2= bufferTemp;
TimerValueReg= 0; // reset the timer
sampleICx= sampleIC3Start; // go to next state
}
if(CaptureMotor1ControlReg.ICOV)
val1IC2= InCapOVFL;

}
#endif
/**
* We use a state machine to figure out if it is time to read the value
or not
*/
#if CaptureMotor2INTLevel == IC_INT_PRIOR_4
void __ISR(CaptureMotor2INTVector, ipl4) InputCapture3Routine(void){
INTClearFlag(CaptureMotor2INTBit);
bufferTemp= CaptureMotor2ReadCapture()& 0xFFFF;
nrImpulsuriIC3++;
// will count no mather in what
state we are

}
#endif
/**

if(sampleICx== sampleIC3Start){
TimerValueReg= 0; // reset the timer
sampleICx= sampleIC3Stop; // go to next state
}else
if(sampleICx== sampleIC3Stop){
val1IC3= bufferTemp;
TimerValueReg= 0; // reset the timer
sampleICx= sampleIC2Start; // go to next state
}
if(CaptureMotor2ControlReg.ICOV)
val1IC3= InCapOVFL;

66

* if I have overflow this means we don't have input on IC2 or IC3


*/
#if TimerForICINTLevel == T1_INT_PRIOR_1
void __ISR(_TIMER_2_VECTOR, ipl1) Timer2Routine(void){
INTClearFlag(INT_T2);
if((sampleICx== sampleIC2Start) ||(sampleICx== sampleIC2Stop)){
sampleICx= sampleIC3Start;
val1IC2= TimerOVFLInCap;
}else
if((sampleICx== sampleIC3Start) ||(sampleICx==
sampleIC3Stop)){
sampleICx= sampleIC2Start;
val1IC3= TimerOVFLInCap;
}
}
#endif

Anexa 4.
/*
* File:
DAC.h
* Author: elcano
* Description: Defines the settings used by the DAC; enumerate the
public functions
* Created on March 6, 2012, 10:03 PM
*/
#ifndef DAC_H
#define DAC_H
// Clock Constants
#define I2C_CLOCK_FREQ
400000 //The I2C on the board
support a medium speed (100K or 400K bps),

DAC

// DAC Constants
#define DAC_I2C_BUS
#define DAC_ADDRESS

I2C1
0x60

#define dutyCicleMaxDAC

0x0FFF

// 0b1100000 MPC4725

/**
* Writes the DAC register, but don't write the EEPROM
* It doesn't need the reead command to verify the RDY bit, because
we don't use EEPROM
*
* @param DACValue A 12 bit value [0- 4095] or [0x0000- 0x0FFF]
* @param PowerDownOption In general we use 0x0 for normal use
*/
void writeDACRegister(unsigned int DACValue, unsigned short
PowerDownOption);
/**
* I recomand to use a read command and verify the RDY bit
* See the previous description for the param
* @param DACValue
* @param PowerDownOption
*/
void writeDACRegisterAndEEPROM(unsigned int DACValue, unsigned int
PowerDownOption);

67

/**
* NEED REWORK, IT DOWSN'T WORK PROPERLY
* Read the setting[1 byte], content of the DAC Register[2 byte],
and then the content of the EEPROM [2 byte]
* @param i2cbyte
* @return
*/
BOOL readDACRegisterANDEEPROM(BYTE i2cbyte[5]);
/**
* Will set the DAC to the desired value
* @param valReg should be a value betwen 0 and 4095. At 4095 is
3.25V the output(the value of the board)
*/
void setUpDAC(unsigned short valReg);
#endif

Anexa 5.
/*
* File:
DAC.c
* Author: elcano
* Descriptor: The code for the DAC
* Created on March 6, 2012, 10:03 PM
*/
#include <plib.h>
#include "DAC.h"
#include "HardwareProfile.h"
//
************************************************************************
****
//
************************************************************************
****
// Local Support Routines
//
************************************************************************
****
//
************************************************************************
****
/
************************************************************************
*******
Function:
BOOL StartTransfer( BOOL restart )
Summary:
Starts (or restarts) a transfer to/from the EEPROM.
Description:
This routine starts (or restarts) a transfer to/from the EEPROM,
waiting (in
a blocking loop) until the start (or re-start) condition has
completed.

68

Precondition:
The I2C module must have been initialized.
Parameters:
restart - If FALSE, send a "Start" condition
- If TRUE, send a "Restart" condition
Returns:
TRUE
FALSE

- If successful
- If a collision occured during Start signaling

Example:
<code>
StartTransfer(FALSE);
</code>
Remarks:
This is a blocking routine that waits for the bus to be idle and the
Start
(or Restart) signal to complete.
**********************************************************************
*******/
BOOL StartTransfer( BOOL restart )
{
I2C_STATUS status;
// Send the Start (or Restart) signal
if(restart)
{
I2CRepeatStart(DAC_I2C_BUS);
}
else
{
// Wait for the bus to be idle, then start the transfer
while( !I2CBusIsIdle(DAC_I2C_BUS) );

if(I2CStart(DAC_I2C_BUS) != I2C_SUCCESS)
{
DBPRINTF("Error: Bus collision during transfer Start\n");
return FALSE;
}

// Wait for the signal to complete


do
{
status = I2CGetStatus(DAC_I2C_BUS);
} while ( !(status & I2C_START) );
}

return TRUE;

/
************************************************************************

69

*******
Function:
BOOL TransmitOneByte( BYTE data )
Summary:
This transmits one byte to the EEPROM.
Description:
This transmits one byte to the EEPROM, and reports errors for any
bus
collisions.
Precondition:
The transfer must have been previously started.
Parameters:
data
- Data byte to transmit
Returns:
TRUE
FALSE

- Data was sent successfully


- A bus collision occured

Example:
<code>
TransmitOneByte(0xAA);
</code>
Remarks:
This is a blocking routine that waits for the transmission to
complete.
**********************************************************************
*******/
BOOL TransmitOneByte( BYTE data )
{
// Wait for the transmitter to be ready
while(!I2CTransmitterIsReady(DAC_I2C_BUS));
// Transmit the byte
if(I2CSendByte(DAC_I2C_BUS, data) == I2C_MASTER_BUS_COLLISION)
{
DBPRINTF("Error: I2C Master Bus Collision\n");
return FALSE;
}
// Wait for the transmission to finish
while(!I2CTransmissionHasCompleted(DAC_I2C_BUS));
return TRUE;
}
/
************************************************************************
*******
Function:
void StopTransfer( void )

70

Summary:
Stops a transfer to/from the EEPROM.
Description:
This routine Stops a transfer to/from the EEPROM, waiting (in a
blocking loop) until the Stop condition has completed.
Precondition:
The I2C module must have been initialized & a transfer started.
Parameters:
None.
Returns:
None.
Example:
<code>
StopTransfer();
</code>
Remarks:
This is a blocking routine that waits for the Stop signal to
complete.
**********************************************************************
*******/
void StopTransfer( void )
{
I2C_STATUS status;
// Send the Stop signal
I2CStop(DAC_I2C_BUS);
// Wait for the signal to complete
do
{
status = I2CGetStatus(DAC_I2C_BUS);
} while ( !(status & I2C_STOP) );
}
/**
* Writes the DAC register, but don't write the EEPROM
* It doesn't need the reead command to verify the RDY bit, because we
don't use EEPROM
*
* @param DACValue A 12 bit value [0- 4095] or [0x0000- 0x0FFF]
* @param PowerDownOption In general we use 0x0 for normal use
*/
void
writeDACRegister(unsigned
int
DACValue,
unsigned
short
PowerDownOption){
BYTE
i2cData[10];
I2C_7_BIT_ADDRESS
SlaveAddress;
int
Index;
int
DataSz;

71

BOOL

Success = TRUE;

// Initialize the data buffer


I2C_FORMAT_7_BIT_ADDRESS(SlaveAddress, DAC_ADDRESS, I2C_WRITE);
i2cData[0] = SlaveAddress.byte;
i2cData[1] = 0x40| (PowerDownOption& ((1<< 1)| (1<< 2)));
// C2, C1, C0= 010 WriteDAC Register, and PD1, PD0= 00 for normal mode
of power down
i2cData[2] = (DACValue& 0x0FF0)>> 4;
// DAC output high byte
i2cData[3] = (DACValue& 0x000F)<< 4;
// DAC output low
byte (12 bits in total)
DataSz = 4;
// Start the transfer to write data to the EEPROM
if( !StartTransfer(FALSE) )
{
while(1);
}
// Transmit all data
Index = 0;
while( Success && (Index < DataSz) )
{
// Transmit a byte
if (TransmitOneByte(i2cData[Index]))
{
// Advance to the next byte
Index++;
// Verify that the byte was acknowledged
if(!I2CByteWasAcknowledged(DAC_I2C_BUS))
{
DBPRINTF("Error: Sent byte was not acknowledged\n");
Success = FALSE;
}
}
else
{

Success = FALSE;

// End the transfer (hang here if an error occured)


StopTransfer();
if(!Success)
{
while(1);
}

}
/**
* I recomand to use a read command and verify the RDY bit
* See the previous description for the param
* @param DACValue
* @param PowerDownOption
*/
void writeDACRegisterAndEEPROM(unsigned int DACValue, unsigned
PowerDownOption){

int

72

BYTE
I2C_7_BIT_ADDRESS
int
int
BOOL

i2cData[10];
SlaveAddress;
Index;
DataSz;
Success = TRUE;

// Initialize the data buffer


I2C_FORMAT_7_BIT_ADDRESS(SlaveAddress, DAC_ADDRESS, I2C_WRITE);
i2cData[0] = SlaveAddress.byte;
i2cData[1] = 0x60| (PowerDownOption& ((1<< 1)| (1<< 2)));
// C2, C1, C0= 011 WriteDAC Register and EEPROM; and PD1, PD0= 00 for
normal mode of power down
i2cData[2] = (DACValue& 0x0FF0)>> 4;
// DAC output high byte
i2cData[3] = (DACValue& 0x000F)<< 4;
// DAC output low
byte (12 bits in total)
i2cData[4] = 0x60| (PowerDownOption& ((1<< 1)| (1<< 2)));
// C2, C1, C0= 011 WriteDAC Register and EEPROM; and PD1, PD0= 00 for
normal mode of power down
i2cData[5] = (DACValue& 0x0FF0)>> 4;
// DAC output high byte
i2cData[6] = (DACValue& 0x000F)<< 4;
// DAC output low
byte (12 bits in total)
DataSz = 7;
// Start the transfer to write data to the EEPROM
if( !StartTransfer(FALSE) )
{
while(1);
}
// Transmit all data
Index = 0;
while( Success && (Index < DataSz) )
{
// Transmit a byte
if (TransmitOneByte(i2cData[Index]))
{
// Advance to the next byte
Index++;
// Verify that the byte was acknowledged
if(!I2CByteWasAcknowledged(DAC_I2C_BUS))
{
DBPRINTF("Error: Sent byte was not acknowledged\n");
Success = FALSE;
}
}
else
{

Success = FALSE;

// End the transfer (hang here if an error occured)


StopTransfer();
if(!Success)
{
while(1);

73

}
}
BOOL readDACRegisterANDEEPROM(BYTE i2cbyte[5]){
BYTE
i2cData[10];
I2C_7_BIT_ADDRESS
SlaveAddress;
int
Index;
int
DataSz;
BOOL
Success = TRUE;
// Initialize the data buffer
I2C_FORMAT_7_BIT_ADDRESS(SlaveAddress, DAC_ADDRESS, I2C_READ);
i2cData[0] = SlaveAddress.byte;
DataSz = 1;
// Start the transfer to read the EEPROM.
if( !StartTransfer(FALSE) )
{
while(1);
}
// Address the EEPROM.
Index = 0;
while( Success & (Index < DataSz) )
{
// Transmit a byte
if (TransmitOneByte(i2cData[Index]))
{
// Advance to the next byte
Index++;
}
else
{
Success = FALSE;
}

// Verify that the byte was acknowledged


if(!I2CByteWasAcknowledged(DAC_I2C_BUS))
{
DBPRINTF("Error: Sent byte was not acknowledged\n");
Success = FALSE;
}

// Read the DAC register


Index = 0;
while( Success & (Index < 5) )
{
if(I2CReceiverEnable(DAC_I2C_BUS, TRUE) == I2C_RECEIVE_OVERFLOW)
{
DBPRINTF("Error: I2C Receive Overflow\n");
Success = FALSE;
}
else
{
while(!I2CReceivedDataIsAvailable(DAC_I2C_BUS));

74

i2cbyte[Index] = I2CGetByte(DAC_I2C_BUS);
I2CAcknowledgeByte(DAC_I2C_BUS, TRUE);
Index++;
}
}
// End the transfer (stop here if an error occured)
StopTransfer();
if(!Success)
{
while(1);
}

if((i2cbyte[0]& (0x80)== 1))


return TRUE;
else
return FALSE;

void setUpDAC(unsigned short valReg){


UINT32
actualClock;
// Initialize debug messages (when supported)
DBINIT();
#if defined(I2CChannel1ForDAC)
// Set the I2C baudrate
actualClock = I2CSetFrequency(DAC_I2C_BUS, GetPeripheralClock(),
I2C_CLOCK_FREQ);
if ( abs(actualClock-I2C_CLOCK_FREQ) > I2C_CLOCK_FREQ/10 )
{
DBPRINTF("Error: I2C1 clock frequency (%u) error exceeds 10%
%.\n", (unsigned)actualClock);
}

/////

// Enable the I2C bus


I2CEnable(DAC_I2C_BUS, TRUE);
////////////////////////////////////////////////////////////////

////////////////
Testarea
functiilor ///////////////////////////////
////////////////////////////////////////////////////////////////
/////
writeDACRegisterAndEEPROM(valReg, 0); //1.5V
I2CEnable(DAC_I2C_BUS, FALSE); // and now we will disable it
#endif
}

Anexa 6.
/*
* File:
ADCsetUp.h
* Author: elcano
* Description: Defines the parameters used by the ADC; redefines the
used registers; enumerate the public functions

75

* Created on March 6, 2012, 8:46 PM


*/
#include "HardwareProfile.h"
#ifndef ADCsetUp_H
#define ADCsetUp_H
// define setup parameters for OpenADC10
// Turn module on |
in idle mode
| ouput in integer
| trigger mode auto | enable autosample
#define PARAM1 ADC_MODULE_ON | ADC_IDLE_CONTINUE| ADC_FORMAT_INTG |
ADC_CLK_AUTO | ADC_AUTO_SAMPLING_ON
// ADC ref external
| disable offset test
| enable
scan mode | perform 8 samples whith average
| use dual buffers | do
not use alternate mode
#define PARAM2
ADC_VREF_EXT_EXT | ADC_OFFSET_CAL_DISABLE |
ADC_SCAN_ON
| ADC_SAMPLES_PER_INT_8 | ADC_ALT_BUF_ON
|
ADC_ALT_INPUT_OFF
//
use ADC PB clock | set sample time | maxim= 127
(ADCS+ 1)*2
#define
PARAM3
ADC_CONV_CLK_PB|
ADC_SAMPLE_TIME_12|
ADC_CONV_CLK_32Tcy
// Scan #1
|
Scan #2
#define PARAM4
ENABLE_AN4_ANA| ENABLE_AN8_ANA
//
Skip all but Analog 4| Analog 8
#define PARAM5
SKIP_SCAN_AN0| SKIP_SCAN_AN1| SKIP_SCAN_AN2|
SKIP_SCAN_AN3| \
SKIP_SCAN_AN5| SKIP_SCAN_AN6| SKIP_SCAN_AN7| \
SKIP_SCAN_AN9| SKIP_SCAN_AN10| SKIP_SCAN_AN11|
SKIP_SCAN_AN12| SKIP_SCAN_AN13| SKIP_SCAN_AN14| SKIP_SCAN_AN15
/************************************
Methods
signature
******************************************************/
/**
* Will prepare the ADC to work with interrupts
* Will use double buffers and will make 4 samples for each channel,
and will save the average
* Will use the internal counter for sampling
* Auto convert and auto sampling: in this mode will sample and
convert for the desired time and then will restart the process
*/
void setUpADC();
#if defined(ADC1)
#define CloseADC
#define SetChannelADC
#define OpenConfigADC
#define ConfigureINTADC
#define INTConfigADC
ADC_INT_SUB_PRI_2
#define EnableADC
#define ADCVecor
#define ADCClearINTFlag
#define ReadADCActiveBuffer
#define ReadADCStack
#endif
#endif

CloseADC10
SetChanADC10
OpenADC10
ConfigIntADC10
ADC_INT_ON| INTLevelADC|
EnableADC10
_ADC_VECTOR
mAD1ClearIntFlag
ReadActiveBufferADC10
ReadADC10

76

Anexa 7.
/*
* File:
ADCsetUp.c
* Description: The code for the ADC
*/
#include "ADCsetUp.h"
#include "HardwareProfile - PIC32MX460F512L PIM.h"
#include <plib.h>
/**
* The method used to configure the ADC
*/
/*@see main.c for declaration*/
extern volatile unsigned int channel4, channel8;
unsigned int channel4mas1, channel4mas2, channel4mas3, channel4mas4;
unsigned int channel8mas1, channel8mas2, channel8mas3, channel8mas4;
void setUpADC(){
CloseADC();{
// ensure the ADC is off before setting the
configuration
// we use only MUX A, and AN1 as external ground
SetChannelADC( ADC_CH0_NEG_SAMPLEA_AN1 );
OpenConfigADC( PARAM1, PARAM2, PARAM3, PARAM4, PARAM5 ); //
configure ADC using parameter define above
ConfigureINTADC(INTConfigADC);
}EnableADC(); // Enable the ADC
}
/**
* The interrupt handler for ADC, we use a level 3 for interrupt
*/
#if INTLevelADC == ADC_INT_PRI_3
void __ISR(ADCVecor, ipl3) ADCHandler(void){
ADCClearINTFlag();
unsigned int
offset = 8 * ((~ReadADCActiveBuffer() &
0x01)); // determine which buffer is idle and create an offset
// GND
Prima sonda
Scan #1
Scan #2
Scan #3
Scan #4
//#define PARAM4
ENABLE_AN1_ANA | ENABLE_AN3_ANA|
ENABLE_AN8_ANA| ENABLE_AN9_ANA| ENABLE_AN14_ANA| ENABLE_AN15_ANA
channel4mas1= ReadADCStack(offset);
channel8mas1= ReadADCStack(offset+ 1);
channel4mas2= ReadADCStack(offset+ 2);
channel8mas2= ReadADCStack(offset+ 3);
channel4mas3= ReadADCStack(offset+ 4);
channel8mas3= ReadADCStack(offset+ 5);
channel4mas4= ReadADCStack(offset+ 6);
channel8mas4= ReadADCStack(offset+ 7);
channel4mas4)>> 2;
channel8mas4)>> 2;
}
#endif

channel4= (channel4mas1+ channel4mas2+ channel4mas3+


channel8= (channel8mas1+ channel8mas2+ channel8mas3+

Anexa 8.
/*
* File:

PWMMotors.h

77

* Author: elcano
* Description: Enumerate the public function; redefines the used
registers
* Created on March 6, 2012, 9:13 PM
*/
#include "HardwareProfile.h"
#ifndef PWMMotors_H
#define PWMMotors_H
#define PWM_desired_freq 5000 // 5KHzs
/**
* It uses Timer 3 as time base and Output compare 2& 3 as PWM.
* Here we don't use interrupts, everything is done in hardware
*/
void setUpPWM();
/**
* A small function used to calculate the value witch will be save
in a register, based on the values of desired frequency, the prescaler,
and the peripheral clock
* @param desiredFreq
* @param prescaler
* @return
*/
unsigned int getPR_For_PWM(unsigned int desiredFreq, unsigned int
prescaler);
/**
* Used to set the direction of the motors
* Will set the direction in opossite, because the motors are monted
back to back
* @param direction 0 or 1
* @pre before the enable signal should be stopped(the PWM output)
*/
void setMotorsDirection(BYTE direction);
#define SetDutyMotor1 SetDCOC2PWM
#define SetDutyMotor2 SetDCOC3PWM
#if defined(OutputCompare3)
#if defined(OutputCompare3)
#define Motor1DirectionPin 6
#define Motor2DirectionPin 7
#define Motor1SpeedPWMPin
1
#define Motor2SpeedPWMPin
2
#define MotorsDirectionPort LATD
#define mPortMotorsDirectionSetDigitalOut(x)
mPORTDSetPinsDigitalOut(x) // here is the same port for direction and
for speed(PWM)
#define mPortMotorsSpeedPWMSetDirectionOut(x)
mPORTDSetPinsDigitalOut(x)
#define
MotorsDirectionConfigPins()
mPortMotorsDirectionSetDigitalOut((1<<
Motor1DirectionPin)|(1<<
Motor2DirectionPin)) // direction for motors
#define
MotorSpeedPWMConfigPins()
mPortMotorsSpeedPWMSetDirectionOut((1<<
Motor1SpeedPWMPin)|
(1<<
Motor2SpeedPWMPin)) // speed of the motors //_RD1| _RD2 (PWM output)
#define OpenOCMotor1
#define Motor1Configs

OpenOC2
OC_ON | OC_TIMER_MODE16 |

78

OC_TIMER3_SRC | OC_PWM_FAULT_PIN_DISABLE
#define OpenOCMotor2
OpenOC3
#define Motor2Configs
OC_ON | OC_TIMER_MODE16 |
OC_TIMER3_SRC | OC_PWM_FAULT_PIN_DISABLE
#endif
#endif
#if defined(Timer3ForOutputCompare)
#define OpenTimerForMotors
#define MotorConfigs
T3_PS_1_1
#endif
#endif

OpenTimer3
T3_ON | T3_SOURCE_INT|

Anexa 9.
/*
* File:
PWMMotors.c
* Description: The code for the PWM, in this case only the setUp
function
*/
#include <plib.h>
#include "PWMMotors.h"
#include "HardwareProfile.h"
unsigned int PWM_PRReg_FREQ, duty;
/*
* First we will set up the pins then the timer and the output compare
*/
void setUpPWM(){
MotorsDirectionConfigPins(); // direction for motors
MotorSpeedPWMConfigPins(); // speed of the motors //_RD1| _RD2 (PWM
output)
setMotorsDirection(1);
PWM_PRReg_FREQ= getPR_For_PWM(PWM_desired_freq, 1);
OpenTimerForMotors(MotorConfigs, PWM_PRReg_FREQ); // 16bit Sysnc
mode, pentru o frecventa de
OpenOCMotor1(Motor1Configs, 0,0);//PWM motor 1
OpenOCMotor2(Motor2Configs, 0,0);//PWM motor 2
}
unsigned int getPR_For_PWM(unsigned int desiredFreq, unsigned int
prescaler){
return GetPeripheralClock()/(prescaler* desiredFreq);
};
inline
__attribute__((always_inline))
void
setMotorsDirection(BYTE
direction){
MotorsDirectionPort&= 0xFFFF^ ((1<< Motor1DirectionPin)|(1<<
Motor2DirectionPin));
MotorsDirectionPort|= ((direction& 1)<< Motor1DirectionPin)| ((1<<
Motor2DirectionPin)^((direction& 1)<< Motor2DirectionPin));
}

Anexa 10.
/*
* File:
rtcc_1secINTR.h
* Author: elcano
* Description: Enumerate the public function; because it is only a

79

RTCC, we don't redefine the registers, only some macros.


* Created on March 26, 2012, 7:42 PM
*/
#include "HardwareProfile.h"
#ifndef rtcc_1secINTR_H
#define rtcc_1secINTR_H
/**
* Will set the internal RTCC to a frequency of 1Hz interrupt
generation
* We don't use date and time because here it is useless
* We use internal interrupt
*/
void setUpRTCC_1secINT();
#ifdef RTCC1sec
#define LEDRTCCTest

BIT_11
#define
mSetLedRTCCOutDir()
{mPORTBSetPinsDigitalOut(LEDRTCCTest);}
#define mLedRTCCOn()
{mPORTBSetBits(LEDRTCCTest);}
#define mLedRTCCOff()
{mPORTBClearBits(LEDRTCCTest);}
#define mLedRTCCToggle()
{mPORTBToggleBits(LEDRTCCTest);}
#define RTCC_IntrruptDisable() {RtccAlarmDisable();}
{INTEnable(INT_RTCC, INT_DISABLED);}
#define RTCC_InterruptEnable() {RtccAlarmEnable();}
{INTEnable(INT_RTCC, INT_ENABLED);} // it is call by default
SetUpRtcc_1secINTR
#endif
#endif

//
//
in

Anexa 11.
/*
* File:
rtcc_1secINTR.h
* Description: The code for the RTCC, for test it is used an onboard
LED
*/
#include
#include
#include
#include
#include
#include

<plib.h>
"rtcc_1secINTR.h"
"GenericTypeDefs.h"
"HardwareProfile.h"
"mainDef.h"
"InputCap.h"

extern BOOL rtcc_1secINTR;


void setUpRTCC_1secINT(){
mSetLedRTCCOutDir();
the frequency
mLedRTCCOff();

// only to see on a PIN

//RtccSetCalibration(-12);
// if we need
calibration, could be set when the RTCC is turned off
RtccInit();
// init the RTCC
while(RtccGetClkStat()!= RTCC_CLK_ON); // wait for the SOSC to

80

be actually running and RTCC to have its clock source


// could wait here at
most 32ms
// set time and date (not necesary if we use only to generate 1
second interrupt)
// RtccOpen(0x17040000, 0x08100604, 0);// time is MSb: hour,
min, sec, rsvd. date is MSb: year, mon, mday, wday.
// please note that the
rsvd field has to be 0 in the time field!
RtccChimeEnable();
// rollover of the alarm when
it is decremented to 0, it jumps to 0xFF
RtccSetAlarmRptCount(255);
// if we use "chime" we could
use here any number and stilwe wil get uninterrupted repeats
RtccSetAlarmRpt(RTCC_RPT_SEC);
//
one
alarm
every
second
// set the alarm (not necesary if we use only to generate 1
second interrupt)
// RtccSetAlarmTimeDate(0x17045000, 0x08100604);
RtccAlarmEnable();
// enable the alarm
INTSetVectorPriority(INT_RTCC_VECTOR, RTCCLevel);
// set the RTCC priority in the INT controller
INTSetVectorSubPriority(INT_RTCC_VECTOR,
INT_SUB_PRIORITY_LEVEL_1);
// set the RTCC sub-priority in the
INT controller
INTEnable(INT_RTCC,
INT_ENABLED);
// enable the RTCC event interrupts in the INT controller.
mLedRTCCOn();
}
/**
* Interrupt handler with Second register set
*/
#if RTCCLevel== INT_PRIORITY_LEVEL_7
void __ISR(_RTCC_VECTOR, ipl7SRS) RtccIsr(void)
{
// once we get in the RTCC ISR we have to clear the RTCC int
flag
INTClearFlag(INT_RTCC);
// will copy the values from interrupt(like IC, ADC) to the
variables whitch will be send over USB
// we don't verify if the values changes, we only asure that
we have a 1 second freq
SetInputCapture1(GetFreqMotor1());
SetInputCapture2(GetFreqMotor2());
SetVoltageBatt(GetChannel4Batt());
SetVoltageSunt(GetChannel8Sunt());
SetNrEventsMotor1(GetNrImpulsuri1());
SetNrEventsMotor2(GetNrImpulsuri2());

}
#endif

mLedRTCCToggle();
rtcc_1secINTR= TRUE;

81

Anexa 12.
/*
* File:
mainDef.h
* Author: elcano
* Description: Enumerate the variables used by several modules; defines
some macros used by several source files; defines the command size
* Created on March 11, 2012, 10:23 PM
*/
#ifndef mainDef_H
#define mainDef_H
#include
#include
#include
#include
#include
#include

"ADCsetUp.h"
"InputCap.h"
"PWMMotors.h"
"DAC.h"
"rtcc_1secINTR.h"
"InputCap.h"

// will be declared in the main file


extern volatile unsigned int val1IC2;
extern volatile unsigned int val1IC3;
extern volatile BYTE nrImpulsuriIC2;
extern volatile BYTE nrImpulsuriIC3;
extern volatile BYTE nrEvents1, nrEvents2;
extern volatile unsigned int inputCapture1;
extern volatile unsigned int inputCapture2;
extern volatile unsigned int voltageSunt;
extern volatile unsigned int voltageBatt;
extern volatile unsigned int channel4;
extern volatile unsigned int channel8;
//#define DEBUG_MODE
#define Command_getConfig_ADC_Size
command ID(name), only the data
#define Command_getConfig_Fuses_PWM_Size
#define Command_getConfig_InputCapture_Size
#define Command_getValue_Voltage_Size
#define Command_getValue_InputCapture_Size
#define Command_setValue_PWM_Size
#define Command_shutDown_Size
#define COMMAND_initialPWMConfig_Size
#define COMMAND_finishedPWMConfig_Size
#define Command_App_Disconnect_Size
#define Command_App_Connect_Size
#define COMMAND_getConfig_MotorsID_Size
#define COMMAND_setDirectionMotor_Size
#define MAX_COMMAND_DATA_Size
command ID only the data

1
3 // whitout the
8
3
4
6
4
0
0
0
0
0
2
1

8 // whitout the

#define DAC_1dot5V
1890 // the value
witch should be put in DAC register to have Vout= 1.5V at Vin= 3.25V
typedef enum _MotorChangeDirectionStates{
IDLE=
1,
//IDLE= Changed
NeedToChange=
2,
ChangeNow=
3,

82

}MotorChangeDirectionStates;
// some
#define
#define
#define
#define
#define
#define

getters for values calculated in interrupts


GetFreqMotor1() val1IC2
GetFreqMotor2() val1IC3
GetChannel8Sunt() channel8
GetChannel4Batt() channel4
GetNrImpulsuri1() nrImpulsuriIC2
GetNrImpulsuri2() nrImpulsuriIC3

// some setters, for variables whitch will be send over USB


#define SetInputCapture1(value) {inputCapture1= value;}
#define SetInputCapture2(value) {inputCapture2= value;}
#define SetVoltageSunt(value)
{voltageSunt= value;}
#define SetVoltageBatt(value)
{voltageBatt= value;}
#define SetNrEventsMotor1(value){nrEvents1= value; value= 0;} //
read and after we make a reset
#define SetNrEventsMotor2(value){nrEvents2= value; value= 0;} //
read and after we make a reset
// some
#define
#define
#define
#define
#define
#define

getters, used to send


GetInputCapture1()
GetInputCapture2()
GetVoltageSunt()
GetVoltageBatt()
GetNrEventsMotor1()
GetNrEventsMotor2()

values on the USB


inputCapture1
inputCapture2
voltageSunt
voltageBatt
nrEvents1
nrEvents2

/**
* Will send the configuration to Android, using the commands of the
type: COMMAND_getConfig_xxxx
* Precondition: The USB must be set up before
* Postcondition: None, it have no side efects
*/
void sendConfigToAndroid();
#endif

Anexa 13.
/
************************************************************************
*******
USB Android Accessory basic demo with accessory in host mode
The code for the application;
************************************************************************
*******/
// Include files
#include <stdio.h>
#include "USB/usb.h"
#include "USB/usb_host_android.h"
#include "Compiler.h"
#include "HardwareProfile.h"

83

#include "mainDef.h"
// If a maximum current rating hasn't been defined, then define 500mA by
default
#ifndef MAX_ALLOWED_CURRENT
#define MAX_ALLOWED_CURRENT
(500)
// Maximum
power we can supply in mA
#endif
// Define a debug error printing
#define DEBUG_ERROR(a)
Nop(); Nop(); Nop();
// Configuration bits for the device.
Please refer to the device
datasheet for each device
//
to determine the correct configuration bit settings
#ifdef __C30__
#if defined(__PIC24FJ256GB110__)
_CONFIG2(FNOSC_PRIPLL & POSCMOD_HS & PLL_96MHZ_ON & PLLDIV_DIV2)
// Primary HS OSC with PLL, USBPLL /2
_CONFIG1(JTAGEN_OFF & FWDTEN_OFF & ICS_PGx2)
// JTAG off,
watchdog timer off
#elif defined(__PIC24FJ64GB004__)
_CONFIG1(WDTPS_PS1 & FWPSA_PR32 & WINDIS_OFF & FWDTEN_OFF &
ICS_PGx1 & GWRP_OFF & GCP_OFF & JTAGEN_OFF)
_CONFIG2(POSCMOD_HS & I2C1SEL_PRI & IOL1WAY_OFF & OSCIOFNC_ON &
FCKSM_CSDCMD & FNOSC_PRIPLL & PLL96MHZ_ON & PLLDIV_DIV2 & IESO_ON)
_CONFIG3(WPFP_WPFP0 & SOSCSEL_SOSC & WUTSEL_LEG & WPDIS_WPDIS &
WPCFG_WPCFGDIS & WPEND_WPENDMEM)
_CONFIG4(DSWDTPS_DSWDTPS3 & DSWDTOSC_LPRC & RTCOSC_SOSC &
DSBOREN_OFF & DSWDTEN_OFF)
#elif defined(__PIC24FJ256GB106__)
_CONFIG1( JTAGEN_OFF & GCP_OFF & GWRP_OFF & COE_OFF & FWDTEN_OFF
& ICS_PGx2)
_CONFIG2( 0xF7FF & IESO_OFF & FCKSM_CSDCMD & OSCIOFNC_OFF &
POSCMOD_HS & FNOSC_PRIPLL & PLLDIV_DIV3 & IOL1WAY_ON)
#elif defined(__PIC24FJ256DA210__) || defined(__PIC24FJ256GB210__)
_CONFIG1(FWDTEN_OFF & ICS_PGx2 & GWRP_OFF & GCP_OFF &
JTAGEN_OFF)
_CONFIG2(POSCMOD_HS & IOL1WAY_ON & OSCIOFNC_ON & FCKSM_CSDCMD &
FNOSC_PRIPLL & PLL96MHZ_ON & PLLDIV_DIV2 & IESO_OFF)
#elif defined(IOIO)
_CONFIG1(FWDTEN_OFF & ICS_PGx2 & GWRP_OFF & GCP_OFF &
JTAGEN_OFF)
_CONFIG2(POSCMOD_NONE & IOL1WAY_ON & OSCIOFNC_ON & FCKSM_CSDCMD
& FNOSC_FRCPLL & PLL96MHZ_ON & PLLDIV_NODIV & IESO_OFF)
#elif defined(__dsPIC33EP512MU810__) || defined(PIC24EP512GU810_PIM)
_FOSCSEL(FNOSC_FRC);
_FOSC(FCKSM_CSECMD & OSCIOFNC_OFF & POSCMD_XT);
_FWDT(FWDTEN_OFF);
#endif
#elif defined( __PIC32MX__ )
#pragma config UPLLEN
= ON
// USB PLL Enabled
#pragma config FPLLMUL = MUL_15
// PLL Multiplier
#pragma config UPLLIDIV = DIV_2
// USB PLL Input Divider
#pragma config FPLLIDIV = DIV_2
// PLL Input Divider
#pragma config FPLLODIV = DIV_1
// PLL Output Divider
#pragma config FPBDIV
= DIV_1
// Peripheral Clock divisor

84

#pragma config FWDTEN


=
#pragma config WDTPS
=
//#pragma config FCKSM
Safe Clock Monitor
#pragma config OSCIOFNC =
#pragma config POSCMOD =
"clock"*/
#pragma config IESO
Switch-over
#pragma config FSOSCEN
Oscillator Enable for RTCC */
#pragma config FNOSC
=
#pragma config CP
=
#pragma config BWP
=
#pragma config PWP
Protect
#pragma config ICESEL
Select
#pragma config DEBUG
Enable

OFF
PS1
= CSDCMD

// Watchdog Timer
// Watchdog Timer Postscale
// Clock Switching & Fail

OFF
EC

// CLKO Enable
/** ANDROID: WE use Discera

= OFF
= ON
PRIPLL
OFF
OFF
= OFF
= ICS_PGx2
= ON

// Internal/External
/** ANDROID: Secondary
// Oscillator Selection
// Code Protect
// Boot Flash Write Protect
// Program Flash Write
// ICE/ICD Comm Channel
// Background Debugger

#else
#error Cannot define configuration bits.
#endif
// C30 and C32 Exception Handlers
// If your code gets here, you either tried to read or write
// a NULL pointer, or your application overflowed the stack
// by having too many local variables or parameters declared.
#if defined(__C30__)
void _ISR __attribute__((__no_auto_psv__)) _AddressError(void)
{
DEBUG_ERROR("Address error");
while(1){}
}
void _ISR __attribute__((__no_auto_psv__)) _StackError(void)
{
DEBUG_ERROR("Stack error");
while(1){}
}
#elif defined(__C32__)
void _general_exception_handler(unsigned cause, unsigned status)
{
unsigned long address = _CP0_GET_EPC();

}
#endif

DEBUG_ERROR("exception");
while(1){}

//Definitions of the various application commnands that can be sent


typedef enum _ACCESSORY_DEMO_COMMANDS
{
COMMAND_getConfig_ADC
= 0x01,
COMMAND_getConfig_Fuses_PWM
= 0x02,
COMMAND_getConfig_InputCapture
= 0x03,

85

COMMAND_getValue_InputCapture
= 0x04,
COMMAND_getValue_Voltage
= 0x05,
COMMAND_setValue_PWM
= 0x06,
COMMAND_shutDown
= 0x07,
COMMAND_initialPWMConfig
= 0x08, // used to calculate the
lower limit for PWM at the desired freq
COMMAND_finishedPWMConfig
= 0x09,
COMMAND_getConfig_MotorsID
= 0x0A,
COMMAND_setDirectionMotor
= 0x0B,
COMMAND_APP_CONNECT
= 0xFE,
COMMAND_APP_DISCONNECT
= 0xFF
} ACCESSORY_DEMO_COMMANDS;
//Creation of the data packet that is going to be sent. In this example
// there is just a command code and a one byte data.
typedef struct __attribute__((packed))
{
BYTE command;
BYTE data[MAX_COMMAND_DATA_Size];
}ACCESSORY_APP_PACKET;
//Local prototypes
#if defined(__C32__)
static void InitPIC32(void);
#endif
//local variables
static BYTE read_buffer[64];
static BYTE write_buffer[64];
static BYTE adresaWrite= 0; // pointer to the next location where will
be put the command
static ACCESSORY_APP_PACKET outgoing_packet;
static void* device_handle = NULL;
static BOOL device_attached = FALSE;
static char manufacturer[] = "Microchip Technology Inc.";
static char model[] = "Basic Accessory Demo";
static char description[] = DEMO_BOARD_NAME_STRING;
static char version[] = "2.0";
static char uri[] = "http://www.microchip.com/android";
static char serial[] = "N/A";
volatile unsigned int channel4, channel8;
volatile unsigned int val1IC2, val1IC3;
volatile unsigned int inputCapture1= 0xFFFF, inputCapture2= 0xFFFF;
volatile unsigned int voltageSunt= 0xFF, voltageBatt= 0xFF;
volatile BYTE nrImpulsuriIC2= 0;
volatile BYTE nrImpulsuriIC3= 0;
volatile BYTE nrEvents1=0, nrEvents2= 0;
BOOL rtcc_1secINTR= FALSE;
BOOL configsSendOK= FALSE;
// if we could send the configs setting,
will be reset when the device is disconnected
BOOL initialPWMconfig= FALSE; // if it is true will ignore the 1 second
rate transmit, and will transmit when it have the data
MotorChangeDirectionStates needToChangeMotorDirection= IDLE;
BYTE desiredDirectionForMotors;
ANDROID_ACCESSORY_INFORMATION myDeviceInfo =
{
manufacturer,

86

sizeof(manufacturer),
model,
sizeof(model),
description,
sizeof(description),
version,
sizeof(version),
uri,
sizeof(uri),
serial,
sizeof(serial)
};
/
************************************************************************
****
Function:
int main(void)
Summary:
main function
Description:
main function
Precondition:
None
Parameters:
None
Return Values:
int - exit code for main function
Remarks:
None
**********************************************************************
*****/
int main(void)
{
DWORD size = 0;
BYTE commandSize = 0x00;
// because our commands have different
sizes
BOOL readyToRead = TRUE;
BOOL writeInProgress = FALSE;
BYTE errorCode;
BYTE relativeAddressInCommandPacket= 0;
ACCESSORY_APP_PACKET* command_packet = NULL;
BOOL connected_to_app = FALSE;
BOOL need_to_disconnect_from_app = FALSE;
#if defined(__PIC32MX__)
InitPIC32();
#endif

87

#if defined(__dsPIC33EP512MU810__) || defined (__PIC24EP512GU810__)


//
//
//
//
//
//

Configure the device PLL to obtain 60 MIPS operation. The crystal


frequency is 8MHz. Divide 8MHz by 2, multiply by 60 and divide by
2. This results in Fosc of 120MHz. The CPU clock frequency is
Fcy = Fosc/2 = 60MHz. Wait for the Primary PLL to lock and then
configure the auxilliary PLL to provide 48MHz needed for USB
Operation.

PLLFBD = 38;
CLKDIVbits.PLLPOST = 0;
CLKDIVbits.PLLPRE = 0;
OSCTUN = 0;
/*
*

/* M = 60
/* N1 = 2
/* N2 = 2

*/
*/
*/

Initiate Clock Switch to Primary


Oscillator with PLL (NOSC= 0x3)*/

__builtin_write_OSCCONH(0x03);
__builtin_write_OSCCONL(0x01);
while (OSCCONbits.COSC != 0x3);
//
//
//
//
//
//

Configuring the auxiliary PLL, since the primary


oscillator provides the source clock to the auxiliary
PLL, the auxiliary oscillator is disabled. Note that
the AUX PLL is enabled. The input 8MHz clock is divided
by 2, multiplied by 24 and then divided by 2. Wait till
the AUX PLL locks.

ACLKCON3 = 0x24C1;
ACLKDIV3 = 0x7;
ACLKCON3bits.ENAPLL = 1;
while(ACLKCON3bits.APLLCK != 1);
TRISBbits.TRISB5 = 0;
LATBbits.LATB5 = 1;
#endif
// initialization
setUpInputCap();
//setUpDAC(DAC_1dot5V); // should be call only once because it
writes the value in EEPROM whitch isn't affected by a reset
setUpPWM();
setUpADC();
setUpRTCC_1secINT();
INTEnableSystemMultiVectoredInt();
INTEnableInterrupts();
USBInitialize(0);
AndroidAppStart(&myDeviceInfo);
while(1)
{
//Keep the USB stack running
USBTasks();
//If the device isn't attached yet,

88

if(device_attached == FALSE)
{
need_to_disconnect_from_app = FALSE;
connected_to_app = FALSE;
size = 0;
//Continue to the top of the while loop to start the check
over again.

continue;

}
//If the accessory is ready, then this is where we run all of
the demo code
if(readyToRead == TRUE)
{
errorCode = AndroidAppRead(device_handle,
(BYTE*)&read_buffer, (DWORD)sizeof(read_buffer));
//If the device is attached, then lets wait for a command
from the application
if( errorCode != USB_SUCCESS)
{
//Error
DEBUG_ERROR("Error trying to start read");
}
else
{
readyToRead = FALSE;
}
}
size = 0;
relativeAddressInCommandPacket= 0;
if(AndroidAppIsReadComplete(device_handle, &errorCode, &size) ==
TRUE)

{
//We've received a command over the USB from the Android

device.

if(errorCode == USB_SUCCESS)
{
//Maybe process the data here.
Maybe process it
somewhere else.
command_packet = (ACCESSORY_APP_PACKET*)&read_buffer[0];
//readyToRead= TRUE; will be set after the message it is
bean digest, the size is zero
}
else
{
//Error
DEBUG_ERROR("Error trying to complete read request");
}
}
while(size > 0)
{
if(connected_to_app == FALSE)
{

89

if(command_packet->command == COMMAND_APP_CONNECT)
{
connected_to_app = TRUE;
need_to_disconnect_from_app = FALSE;
commandSize= Command_App_Connect_Size+ 1;
//size-= Command_App_Connect_Size+ 1;// recalculate
the size, using the relative size of the command
//relativeAddressInCommandPacket+=
Command_App_Connect_Size+ 1;
}
}
else
{
if(configsSendOK== TRUE)
switch(command_packet->command)
{
case COMMAND_setValue_PWM:
if(sizeof(command_packet-> data)>=
Command_setValue_PWM_Size){
// could be more than one
command
SetDutyMotor1 ((command_packet->
data[0]<< 8)| command_packet-> data[1]); // we make a 16 bit from two 8
bit
SetDutyMotor2 ((command_packet->
data[2]<< 8)| command_packet-> data[3]);
commandSize = Command_setValue_PWM_Size+
1;
if(initialPWMconfig== TRUE){
rtcc_1secINTR= TRUE; // will force
to transmit the data faster
SetInputCapture1(GetFreqMotor1());
SetInputCapture2(GetFreqMotor2());
SetVoltageBatt(GetChannel4Batt());
SetVoltageSunt(GetChannel8Sunt());
}
//size-= Command_setValue_PWM_Size+ 1;
//relativeAddressInCommandPacket+=
Command_setValue_PWM_Size+ 1;
}
break;
case COMMAND_initialPWMConfig:
if(sizeof(command_packet-> data)>=
COMMAND_initialPWMConfig_Size){
// could be more than one
command
commandSize=
COMMAND_initialPWMConfig_Size+ 1;
initialPWMconfig= TRUE;
RTCC_IntrruptDisable (); // we will
generate manual the sampling rate
setUpDAC(DAC_1dot5V);
// here it is a
good place to initialize also the DAC to be sure it is ok the voltage
reference
}
break;
case COMMAND_finishedPWMConfig:
if(sizeof(command_packet-> data)>=

90

COMMAND_finishedPWMConfig_Size){
command
COMMAND_finishedPWMConfig_Size+ 1;

// could be more than one


commandSize=
initialPWMconfig= FALSE; // we are

finished with the "burst" mode

RTCC_InterruptEnable(); // the sampling


rate will be generate in auto mode at 1Hz
}
break;
case COMMAND_setDirectionMotor:
if(sizeof(command_packet-> data)>=
COMMAND_setDirectionMotor_Size){
// could be more than one
command
commandSize=
COMMAND_setDirectionMotor_Size+ 1;
SetDutyMotor1(0); // before we stop the
PWMs, and then, after a second we change the sign
SetDutyMotor2(0);
desiredDirectionForMotors =
command_packet->data[0];
needToChangeMotorDirection =
NeedToChange;
}
break;
case COMMAND_shutDown:
if(sizeof(command_packet-> data)>=
Command_shutDown_Size){
/**
* ANDROID:
* The code to shut down the system
* For now we will shut down both motors
*/
SetDutyMotor1(0);
SetDutyMotor2(0);
commandSize= Command_shutDown_Size+ 1;
//size-= Command_shutDown_Size+ 1;
//relativeAddressInCommandPacket+=
Command_shutDown_Size+ 1;
}
break;
case COMMAND_APP_DISCONNECT:
if(sizeof(command_packet-> data)>=
Command_App_Disconnect_Size){
need_to_disconnect_from_app = TRUE;
commandSize=
Command_App_Disconnect_Size+ 1;
//size-= Command_App_Disconnect_Size+ 1;
//relativeAddressInCommandPacket+=
Command_App_Disconnect_Size+ 1;
}
break;
default:
//Error, unknown command
DEBUG_ERROR("Error: unknown command

91

received");
}
}
because

// And move the pointer to the next packet (this works


//

size

break;

//

all command packets are 2 bytes.

If variable packet

then need to handle moving the pointer by the size of

the

// command type that arrived.


size-= commandSize;
relativeAddressInCommandPacket+= commandSize;
if(size!= 0)
memcpy(command_packet,
&read_buffer[relativeAddressInCommandPacket], size);
if(need_to_disconnect_from_app == TRUE)
{
break;
}
}
if(size == 0)
{
readyToRead = TRUE;
}
if(connected_to_app == FALSE)
{
//If the app hasn't told us to start sending data, let's not
do anything else.
continue;
}
// WE TRY TO SEND THE CONFIGS
// At first run we move in the buffer the configs(a local one);
here will be put the local buffer contain in the output buffer
// At second run we will verify if have been send with succes
the infos, and if so we will set a flag
// Because the flag eill be set only at the second pass, the
program counter won't go further, because of the continue statement
adresaWrite= 0;
if(configsSendOK== FALSE){
// If there is a write already in progress, we need to
check its status
if( writeInProgress == TRUE )
{
if(AndroidAppIsWriteComplete(device_handle, &errorCode,
&size) == TRUE)
{
writeInProgress = FALSE;
if(errorCode != USB_SUCCESS)
{
//Error
DEBUG_ERROR("Error trying to complete write");
}else
configsSendOK= TRUE;

92

}
}else{

sendConfigToAndroid(); // we will prepare the output


buffer whir all the configs
writeInProgress= TRUE;
errorCode = AndroidAppWrite(device_handle, write_buffer,
adresaWrite);
if( errorCode != USB_SUCCESS )
{
DEBUG_ERROR("Error trying to send button update");
}
}
}
if(configsSendOK== FALSE)
continue;
// if we are here after all the continue statemant maybe we have
smth to send, we will use a local buffer

status

// If there is a write already in progress, we need to check its

if( writeInProgress == TRUE )


{
if(AndroidAppIsWriteComplete(device_handle, &errorCode,
&size) == TRUE)
{
writeInProgress = FALSE;
if(need_to_disconnect_from_app == TRUE)
{
connected_to_app = FALSE;
need_to_disconnect_from_app = FALSE;
}

if(errorCode != USB_SUCCESS)
{
//Error
DEBUG_ERROR("Error trying to complete write");
}

}
FALSE))

if((need_to_disconnect_from_app == TRUE) && (writeInProgress ==


{

outgoing_packet.command = COMMAND_APP_DISCONNECT;
//outgoing_packet.data = 0;
writeInProgress = TRUE;

errorCode = AndroidAppWrite(device_handle,
(BYTE*)&outgoing_packet, Command_App_Disconnect_Size+ 1);
if( errorCode != USB_SUCCESS )
{
DEBUG_ERROR("Error trying to send button update");
}
}else
// it isn't the time to send smth, we will wait a little
more

93

if(rtcc_1secINTR== FALSE)
continue;
if(needToChangeMotorDirection== ChangeNow){
setMotorsDirection(desiredDirectionForMotors);
needToChangeMotorDirection= IDLE; // do not change the order
of the two ifs
}
if(needToChangeMotorDirection== NeedToChange){
needToChangeMotorDirection= ChangeNow; // we will wait
minimum 1 sec
}
// If we need up update the inputCapture on the Android device
and we aren't
// already busy in a write, then we can send the new button
data.
// if((inputCapNeedUpdate == TRUE)&& (writeInProgress== FALSE))
if(writeInProgress == FALSE)
{
outgoing_packet.command = COMMAND_getValue_InputCapture;
outgoing_packet.data[0]= GetInputCapture1() >> 8;
//
we send the first value, followed by the second one
outgoing_packet.data[1]= GetInputCapture1() & 0x00FF;
outgoing_packet.data[2]= GetInputCapture2() >> 8;
outgoing_packet.data[3]= GetInputCapture2() & 0x00FF;
outgoing_packet.data[4]= GetNrEventsMotor1()& 0x00FF;
outgoing_packet.data[5]= GetNrEventsMotor2()& 0x00FF;
memcpy(&write_buffer[adresaWrite], (BYTE*)&outgoing_packet,
Command_getValue_InputCapture_Size+ 1);
adresaWrite+= Command_getValue_InputCapture_Size+ 1;
}

// writeInProgress = TRUE;

//If we need up update the pot status on the Android device and
we aren't
// already busy in a write, then we can send the new pot data.
if(writeInProgress == FALSE)
{
outgoing_packet.command = COMMAND_getValue_Voltage;
outgoing_packet.data[0]= GetVoltageSunt()
>> 8;
outgoing_packet.data[1]= GetVoltageSunt()
& 0x00FF;
outgoing_packet.data[2]= GetVoltageBatt()
>> 8;
outgoing_packet.data[3]= GetVoltageBatt()
& 0x00FF;
memcpy(&write_buffer[adresaWrite], (BYTE*)&outgoing_packet,
Command_getValue_Voltage_Size+ 1);
adresaWrite+= Command_getValue_Voltage_Size+ 1;
}

// writeInProgress = TRUE;

// at the end we try to write smth, could be locked by the need


of deconect from the app
if(writeInProgress== FALSE){
rtcc_1secINTR= FALSE;
// will be set by the RTCC
writeInProgress= TRUE;

94

errorCode = AndroidAppWrite(device_handle, write_buffer,


adresaWrite);
if( errorCode != USB_SUCCESS )
{
DEBUG_ERROR("Error trying to send pot update");
}
}
} //while(1) main loop
}
/
************************************************************************
****
Function:
BOOL USB_ApplicationDataEventHandler( BYTE address, USB_EVENT event,
void *data, DWORD size )
Summary:
Handles USB data application events
Description:
Handles USB data application events
Precondition:
None
Parameters:
BYTE address - address of the device causing the event
USB_EVENT event - the event that has occurred
void* data - data associated with the event
DWORD size - the size of the data in the data field
Return Values:
BOOL - Return TRUE of the event was processed.
event
wasn't handled.

Return FALSE if the

Remarks:
None
**********************************************************************
*****/
BOOL USB_ApplicationDataEventHandler( BYTE address, USB_EVENT event,
void *data, DWORD size )
{
return FALSE;
}
/
************************************************************************
****
Function:
BOOL USB_ApplicationEventHandler( BYTE address, USB_EVENT event,
void *data, DWORD size )
Summary:
Handles USB application events

95

Description:
Handles USB application events
Precondition:
None
Parameters:
BYTE address - address of the device causing the event
USB_EVENT event - the event that has occurred
void* data - data associated with the event
DWORD size - the size of the data in the data field
Return Values:
BOOL - Return TRUE of the event was processed.
event
wasn't handled.

Return FALSE if the

Remarks:
None
**********************************************************************
*****/
BOOL USB_ApplicationEventHandler( BYTE address, USB_EVENT event, void
*data, DWORD size )
{
switch( event )
{
case EVENT_VBUS_REQUEST_POWER:
// The data pointer points to a byte that represents the
amount of power
// requested in mA, divided by two. If the device wants too
much power,
// we reject it.
if (((USB_VBUS_POWER_EVENT_DATA*)data)->current <=
(MAX_ALLOWED_CURRENT / 2))
{
return TRUE;
}
else
{
DEBUG_ERROR( "\r\n***** USB Error - device requires too
much current *****\r\n" );
}
break;
case
case
case
case
case
case

EVENT_VBUS_RELEASE_POWER:
EVENT_HUB_ATTACH:
EVENT_UNSUPPORTED_DEVICE:
EVENT_CANNOT_ENUMERATE:
EVENT_CLIENT_INIT_ERROR:
EVENT_OUT_OF_MEMORY:
case EVENT_UNSPECIFIED_ERROR:

generated.
case EVENT_DETACH:
detached (data: BYTE, address of device)
case EVENT_ANDROID_DETACH:
device_attached = FALSE;

// This should never be


// USB cable has been

96

configsSendOK= FALSE;
device will be connected
return TRUE;
break;

// if another

// Android Specific events


case EVENT_ANDROID_ATTACH:
device_attached = TRUE;
device_handle = data;
return TRUE;
default :
break;
}
return FALSE;
}
/
************************************************************************
****
Function:
void InitPIC32(void)
Summary:
Initialize the PIC32 core to the correct modes and clock speeds
Also enables multi vector interrupt
Description:
Initialize the PIC32 core to the correct modes and clock speeds
Precondition:
Only runs on PIC32
Parameters:
None
Return Values:
None
Remarks:
None
**********************************************************************
*****/
#if defined(__PIC32MX__)
static void InitPIC32(void)
{
int value;
#if defined(RUN_AT_60MHZ)
// Use OSCCON default
#else
OSCCONCLR = 0x38000000; //PLLODIV
#if defined(RUN_AT_48MHZ)
OSCCONSET = 0x08000000; //PLLODIV /2
#elif defined(RUN_AT_24MHZ)
OSCCONSET = 0x10000000; //PLLODIV /4

97

#else
#error Cannot set OSCCON
#endif
#endif
value = SYSTEMConfigWaitStatesAndPB( GetSystemClock() );
// Enable the cache for the best performance
CheKseg0CacheOn();
// INTEnableSystemMultiVectoredInt();
// will be set later
/*ANDROID: We let JTAG enable for debugging
*
*/
//DDPCONbits.JTAGEN = 0;
value = OSCCON;
while (!(value & 0x00000020))
{
value = OSCCON;
// Wait for PLL lock to stabilize
}
// INTEnableInterrupts();
// will be set later

}
#endif

/**
* Will send the configuration to Android, using the commands of the
type: COMMAND_getConfig_xxxx
* Precondition: The USB must be set up before
* Postcondition: None, it have no side efects
* Return: Will return true if all the configs were send with succes,
and false if not
*/
void sendConfigToAndroid(){
BYTE sizeWhitoutIDCmd;
BYTE index= 0; // folosit pentru parcurgerea tabloului de configs
BYTE nrOfTry= 1; // se va incerca de 1 ori sa se trimita
configurarile
BOOL allFlags= FALSE; // will be an AND of the flagsOkTransmit[]
BYTE configs[4][MAX_COMMAND_DATA_Size+ 2]={ //Size+ 1 for the ID and
another one for the size
{COMMAND_getConfig_ADC, Command_getConfig_ADC_Size,
10, (1<< 5)| ((5>> 8)& 0x1F), 5, 0, 0, 0, 0, 0},
// ID, dim
data, ADCsize, Vref intreg & Vref fractional parte dominanta, Vref
fractional
{COMMAND_getConfig_Fuses_PWM, Command_getConfig_Fuses_PWM_Size,
80, 15, 2, 1, 1, 16, PWM_desired_freq/100, 1},
// ID, dim
data, Freq a cristalului de pe placa* 100KHz, FPLLMUL, FPLLDIV,
FPLLODIV, FPBDIV, OutComp reg size, OutComp freq *100Hz, T3_PS_1_1
{COMMAND_getConfig_InputCapture, Command_getConfig_InputCapture_Size,
32, 16, 8, 0, 0, 0, 0, 0},
// ID, dim data, Prescaler

98

T2_PS_1_16, dim in biti a rezultatului, dim in bits of the number of


events
{COMMAND_getConfig_MotorsID, COMMAND_getConfig_MotorsID_Size,
1, 2, 0, 0, 0, 0, 0, 0}
// ID, id motor 1(with IC2 and OC2),
id motor 2(with IC3 and OC3)
};
while((nrOfTry)> 0&& (allFlags== FALSE)){
nrOfTry-- ;
allFlags= TRUE; // if remain true it means that all configs have
been send with success
// we have to send 3 configs arrays, whitch means 3 commands
with data
// at every step we send the command+ data then we try to see if
there was completed the last write on Android
for(index= 0; index< 4; index++){
sizeWhitoutIDCmd= configs[index][1];
outgoing_packet.command = configs[index][0];
memcpy(outgoing_packet.data, &configs[index][2],
sizeWhitoutIDCmd);
memcpy(&write_buffer[adresaWrite], (BYTE*)&outgoing_packet,
sizeWhitoutIDCmd+ 1);
adresaWrite+= sizeWhitoutIDCmd+ 1;
}
}
}

99

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