Documente Academic
Documente Profesional
Documente Cultură
DEPARTAMENTUL CALCULATOARE
LUCRARE DE LICEN
2012
VIZAT,
DECAN, DIRECTOR DEPARTAMENT,
Prof. dr. ing. Liviu MICLEA Prof. dr. ing. Rodica
POTOLEA
4. Consultani: S.L. Dr. Ing. Radu Dnescu, A.L. Dr. tefan Breban
Absolvent: _____________________________
3
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
4.5.2.2 Tipuri de transfer.................................................................................23
4.5.2.3 Modelul de comunicaie USB.............................................................23
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
5
1. Introducere Contextul proiectului
6
2. Obiectivele proiectului
9
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.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 situai 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.
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 gsete pe blog-ul lui Romfron
[7], unde se combate vehement ADK-ul, fiind considerat ca lipsit de inovaie 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 funcie 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, aa 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 situaie 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 audio-
video 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.
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 execuie 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.
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 funcionrii.
Aa cum se poate observa circuitul de alimentare este separat de comand, astfel nct
motoarele pot fi acionate la tensiuni i cureni mari.
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.
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(exemplu 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.
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.
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].
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 16-
lea 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.
4.4.5 ADC
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.
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.
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'.
25
Figura 4.13: Start, schimbare date, stop
26
Figura 4.15: Arbitrarea a dou masters
4.5.2 USB
Pentru aceast prezentare general a protocolului am folosit [24] i [25], precum
i unele constatri experimentale.
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).
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, trecndu-
se 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 condiiile
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.
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 Length Data(optio
nal)
Get USB_Dir_out| 51 0 0 2 Get
protocol USB_type_Vend protocol
(5110) or| USB_Device
Send USB_Dir_out| 52 0 0... 5 String Send a
strings USB_type_Vend dimension string
(5210) or| USB_Device
Strart USB_Dir_out| 53 0 0 0 Send Null
(5310) USB_type_Vend
or| USB_Device
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 aplicaia 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.
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
35
4.6.2 Msurarea turaiei
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 obinut micarea de
rotaie, se poate reduce factorul de umplere cu cteva procente, fr a se constata oprirea
motorului.
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 octei 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.
39
5. Proiectare de detaliu i implementare
42
stare actual rising edge stare urmtoare Observaii
IC2 sampleIC2Stop reseteaz Timerul
sampleIC2Start pstraz starea
IC3
actual
preia valoarea din
IC3 sampleIC3Start
Timer i l reseteaz
sampleIC2Stop
pstraz starea
IC2
actual
pstraz starea
IC2
sampleIC3Start actual
IC3 sampleIC3Stop reseteaz Timerul
pstraz starea
IC3
actual
sampleIC3Stop
preia valoarea din
IC2 sampleIC2Start
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 | MotorsDirectionConfigPins();
2 | MotorSpeedPWMConfigPins();
3 | setMotorsDirection(1);
4 | PWM_PRReg_FREQ= getPR_For_PWM(PWM_desired_freq, 1);
5 | OpenTimerForMotors(MotorConfigs, PWM_PRReg_FREQ);
6 | OpenOCMotor1(Motor1Configs, 0,0);//PWM motor 1
7 | OpenOCMotor2(Motor2Configs, 0,0);//PWM motor 2
Pinii de output ai modului de PWM trebuie marcai ca fiind de ieire.n funcia de
mai sus se seteaz doar frecvena bazei de timp, factorul de umplere pentru motoare fiind
fixat la zero.
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 | SetInputCapture1(GetFreqMotor1());
6 | SetInputCapture2(GetFreqMotor2());
7 | SetVoltageBatt(GetChannel4Batt());
8 | SetVoltageSunt(GetChannel8Sunt());
9 | mLedRTCCToggle();
10| rtcc_1secINTR= TRUE;
11| }
12| #endif
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 flag-
ului 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.
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 = 0x01,
4 | COMMAND_getConfig_Fuses_PWM = 0x02,
5 | COMMAND_getConfig_InputCapture = 0x03,
6 | COMMAND_getValue_InputCapture = 0x04,
7 | COMMAND_getValue_Voltage = 0x05,
8 | COMMAND_setValue_PWM = 0x06,
9 | COMMAND_shutDown = 0x07,
10| COMMAND_initialPWMConfig = 0x08,
11| COMMAND_finishedPWMConfig = 0x09,
12| COMMAND_getConfig_MotorsID = 0x0A,
13| COMMAND_setDirectionMotor = 0x0B,
14| COMMAND_APP_CONNECT = 0xFE,
15| COMMAND_APP_DISCONNECT = 0xFF
16|} ACCESSORY_DEMO_COMMANDS;
, iar lungimiile sunt fixe:
1 | #define Command_getValue_Voltage_Size 4
7
8
9
10 ID motor 1 ID motor 2
11 Dir motors
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);
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;
50
6. Testare i validare
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 citete timerul apoi acesta se
reiniializeaz. Curbele obiute sunt relativ line, iar abaterea astfel calculat este de 2.25e-
6, ceea ce reprezint o perioad de 1.0000655 secunde pentru RTCC.
51
Figura 6.3: Analiza folosind osciloscopul
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.
54
Figura 7.1: Schema general de montaj
55
n tabelul 7.2 se prezint modul de conectare al perifericelor la plac.
Pin PMod(periferic) Pin Cerebot Explicaii
DAC GND( Negru) JK 07
Referina pentru ADC
DAC Referin( Rou) JK 08
GND circuit msur(Negru) JJ 02
Voltaj unt(Rou) JJ 09 Circuitul extern de msur
Voltaj divizor baterii(Alb) JJ 07
Motor 1 HB5 JD 01- JD06 Motoarele au nevoie de
Motor 2 HB5 JD 07- JD12 surs extern de alimentare
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.
58
Figura 8.1: Valoare RTCC msurat n condiii normale
n figura 8.1 se prezint comportarea circuitului de RTCC n condiii 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.
60
folosi(n cazul n care se poate alege ntre dou module similare), diverse frecvene 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/#/android-
serial/4548697508.
[2] "Android G1 Serial to USB Cable", http://www.instructables.com/id/Android-G1-
Serial-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-development-
kit/.
[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://android-
developers.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, ediia 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
//#define RUN_AT_48MHZ
//#define RUN_AT_24MHZ
#define RUN_AT_60MHZ
#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
#define CaptureMotor2PortEnable mPORTCSetPinsDigitalIn(1<<
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 OpenTimer2
#define TimerForICConfigs T2_ON | T2_SOURCE_INT|
T2_PS_1_32
#define TimerForICSetPriority mT2SetIntPriority
#define TimerForICSetSubPriority mT2SetIntSubPriority
#define TimerForICINTEnable mT2IntEnable
#define TimerValueReg TMR2
#endif
#endif
Anexa 3.
/*
* File: InputCap.c
* Description: Contains the code to sample two channels
*/
#include <plib.h>
#include "InputCap.h"
#include "../HardwareProfile.h"
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
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;
}
#endif
/**
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 Constants
#define DAC_I2C_BUS I2C1
#define DAC_ADDRESS 0x60 // 0b1100000 MPC4725
DAC
#define dutyCicleMaxDAC 0x0FFF
/**
* 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 - If successful
FALSE - 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.
**********************************************************************
*******/
if(I2CStart(DAC_I2C_BUS) != I2C_SUCCESS)
{
DBPRINTF("Error: Bus collision during transfer Start\n");
return FALSE;
}
}
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 - Data was sent successfully
FALSE - A bus collision occured
Example:
<code>
TransmitOneByte(0xAA);
</code>
Remarks:
This is a blocking routine that waits for the transmission to
complete.
**********************************************************************
*******/
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.
**********************************************************************
*******/
/**
* 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;
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
#if defined(ADC1)
#define CloseADC CloseADC10
#define SetChannelADC SetChanADC10
#define OpenConfigADC OpenADC10
#define ConfigureINTADC ConfigIntADC10
#define INTConfigADC ADC_INT_ON| INTLevelADC|
ADC_INT_SUB_PRI_2
#define EnableADC EnableADC10
#define ADCVecor _ADC_VECTOR
#define ADCClearINTFlag mAD1ClearIntFlag
#define ReadADCActiveBuffer ReadActiveBufferADC10
#define ReadADCStack ReadADC10
#endif
#endif
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);
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)
#if defined(Timer3ForOutputCompare)
#define OpenTimerForMotors OpenTimer3
#define MotorConfigs T3_ON | T3_SOURCE_INT|
T3_PS_1_1
#endif
#endif
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);
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);}
Anexa 11.
/*
* File: rtcc_1secINTR.h
* Description: The code for the RTCC, for test it is used an onboard
LED
*/
#include <plib.h>
#include "rtcc_1secINTR.h"
#include "GenericTypeDefs.h"
#include "HardwareProfile.h"
#include "mainDef.h"
#include "InputCap.h"
//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
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());
mLedRTCCToggle();
rtcc_1secINTR= TRUE;
}
#endif
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 "ADCsetUp.h"
#include "InputCap.h"
#include "PWMMotors.h"
#include "DAC.h"
#include "rtcc_1secINTR.h"
#include "InputCap.h"
82
}MotorChangeDirectionStates;
/**
* 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.
/
************************************************************************
*******
************************************************************************
*******/
// 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"
#else
#error Cannot define configuration bits.
#endif
#elif defined(__C32__)
void _general_exception_handler(unsigned cause, unsigned status)
{
unsigned long address = _CP0_GET_EPC();
DEBUG_ERROR("exception");
while(1){}
}
#endif
//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;
/
************************************************************************
****
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;
#if defined(__PIC32MX__)
InitPIC32();
#endif
87
#if defined(__dsPIC33EP512MU810__) || defined (__PIC24EP512GU810__)
PLLFBD = 38; /* M = 60 */
CLKDIVbits.PLLPOST = 0; /* N1 = 2 */
CLKDIVbits.PLLPRE = 0; /* N2 = 2 */
OSCTUN = 0;
__builtin_write_OSCCONH(0x03);
__builtin_write_OSCCONL(0x01);
while (OSCCONbits.COSC != 0x3);
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();
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;
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");
break;
}
}
// And move the pointer to the next packet (this works
because
// all command packets are 2 bytes. If variable packet
size
// 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
if(errorCode != USB_SUCCESS)
{
//Error
DEBUG_ERROR("Error trying to complete write");
}
}
}
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;
}
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. Return FALSE if the
event
wasn't handled.
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. Return FALSE if the
event
wasn't handled.
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 EVENT_VBUS_RELEASE_POWER:
case EVENT_HUB_ATTACH:
case EVENT_UNSUPPORTED_DEVICE:
case EVENT_CANNOT_ENUMERATE:
case EVENT_CLIENT_INIT_ERROR:
case EVENT_OUT_OF_MEMORY:
case EVENT_UNSPECIFIED_ERROR: // This should never be
generated.
case EVENT_DETACH: // USB cable has been
detached (data: BYTE, address of device)
case EVENT_ANDROID_DETACH:
device_attached = FALSE;
96
configsSendOK= FALSE; // if another
device will be connected
return TRUE;
break;
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
// INTEnableSystemMultiVectoredInt();
// will be set later
// 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)
};
99