Documente Academic
Documente Profesional
Documente Cultură
DEPARTAMENTUL CALCULATOARE
2012
VIZAT,
DIRECTOR DEPARTAMENT,
Prof. dr. ing. Rodica
POTOLEA
DECAN,
Prof. dr. ing. Liviu MICLEA
Absolvent: _____________________________
Coordonator tiinific: _____________________________
Declaraie
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
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
Octet 2
....
Octet n+1
Cod mesaj
Argument 1
....
Argument n
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.
10
11
13
17
20
25
26
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
Numele clasei
Codul clasei
Flash Drive
Mass Storage
0x08
0x06
0x50
Descriere
Productor
Device
cu Google
suport ADK
Model
0x2D00
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
Driver-ul
bazat
pe
dac nu este deja n acest mod va ncerca pornirea acestuia n modul amintit
32
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
33
34
35
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.
37
39
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.
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[].
stare actual
rising edge
IC2
sampleIC2Start
stare urmtoare
sampleIC2Stop
sampleIC3Start
sampleIC2Stop
sampleIC3Start
reseteaz Timerul
pstraz
actual
IC3
IC3
Observaii
starea
IC2
pstraz
actual
starea
IC2
pstraz
actual
starea
IC3
sampleIC3Stop
pstraz
actual
IC3
sampleIC3Stop
IC2
reseteaz Timerul
sampleIC2Start
starea
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
|
|
|
|
|
|
|
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
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
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.
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|
}
#endif
mLedRTCCToggle();
rtcc_1secINTR= TRUE;
45
=
=
=
=
=
=
=
=
=
=
=
0x01,
0x02,
0x03,
0x04,
0x05,
0x06,
0x07,
0x08,
0x09,
0x0A,
0x0B,
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
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
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
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);
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,
usb_host_android_protocol_v1.c::AndroidAppRead_Pv1(void* handle,
BYTE* data, DWORD size). Se folosete o redirectare la:
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
50
6. Testare i validare
53
54
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
Pin Cerebot
JK 07
JK 08
Explicaii
Referina pentru ADC
JJ 09
JJ 07
Motor 1 HB5
JD 01- JD06
Motor 2 HB5
JD 07- JD12
Tablet Android
J17
Motoarele au nevoie de
surs extern de alimentare
Conectare tablet folosind
cablu USB
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
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) ???
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
}
#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
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;
}
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
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;
Success = FALSE;
}
/**
* 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;
Success = FALSE;
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;
}
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);
}
/////
////////////////
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
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
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
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"
//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
}
#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"
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
/**
* 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
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){}
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
PLLFBD = 38;
CLKDIVbits.PLLPOST = 0;
CLKDIVbits.PLLPRE = 0;
OSCTUN = 0;
/*
*
/* M = 60
/* N1 = 2
/* N2 = 2
*/
*/
*/
__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();
//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;
91
received");
}
}
because
size
break;
//
If variable packet
the
92
}
}else{
status
if(errorCode != USB_SUCCESS)
{
//Error
DEBUG_ERROR("Error trying to complete write");
}
}
FALSE))
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;
94
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.
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;
96
configsSendOK= FALSE;
device will be connected
return TRUE;
break;
// if another
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
99