Avtor: dr. Simon Vavpotič
2019_279_44
ARMove 32-bitne mikroarhitekture prinašajo v svet mikrokontrolerjev veliko zmogljivost in nešteto novih možnosti uporabe. Kaj so pametni mikrokontrolerji, kaj zmorejo in kako jih uporabljamo?
V prejšnjem delu članka smo se lotili migracije in poenotenja projektov iz Atmel razvojnih okolij v Microchip MPLAB X razvojno okolje, ki je skoraj samoumeven korak, s katerim lahko programsko opremo za vse mikrokontrolerje pod Microchipovim okriljem razvijamo v enotnem razvojnem okolju. Nato smo se lotili še priprave vgrajene programske kode za lastno HID napravo ter aplikacijske programske kode za njeno uporabo z osebnim računalnikom. Spoznali smo tudi pomen Microchip MPLAB Harmony 3 Configuratorja.
Tokrat bomo bomo izdelali HID vmesnik za neposredni dostop do vseh funkcionalnosti SAMV71Q21B mikrokontrolerja in Microsoft Visual Basica. Tako nadaljujemo in zaključujemo odprto temo, ki smo jo začeli v preteklem nadaljevanju.
Ta vsebina je samo za naročnike
Ugnezdena programska oprema
Preizkušanje različnih funkcionalnosti SAMV71Q21B se bomo lotili po preizkušeni metodi, ki jo poznamo že iz nadaljevanja o PIC18, PIC24 in PIC32. V mikrokontroler bomo vgradili enostavno USB HID programsko knjižnico, ki bo omogočala neposredno zajemanje vrednosti pisanje v registre. Tako bomo lahko preizkusili GPIO in druge funkcijske enote, ki ne potrebujejo stalnih hitrih podatkovnih prenosov, preizkusili in nastavili pa bomo lahko tudi različne konfiguracije funkcijskih enot, ne da bi morali za to spreminjati vgrajeno programsko opremo mikrokontrolerja.
Tokrat se bomo lotili programiranja USB vmesnika. Videli bomo, kako dopolnimo pripravljeno objektno programsko kodo, da bo zares uporabna in katere funkcije za podporo komunikaciji preko USB moramo sami implementirati.
Dopolnitev in definicije podatkovnih struktur
Lotimo se torej dopolnjevanja skeletne programske kode, tako da bo povezava preko USB naposled začela delovati. Na mesta, označena z »za narediti« (angl. »TO DO«), moramo dodati svojo programsko kodo, ki bo lahko za vsako sporočilo iz množice obveznih sporočil, s katerimi gostiteljski računalnik vzpostavi in vzdržuje komunikacijo preko USB, pripravila ustrezen odgovor.
Programska knjižnica Harmony je več kot odličen pripomoček, ki nam olajša večino opravil, a kljub temu moramo povedati, kaj pravzaprav želimo prenašati in kako. Pripraviti moramo tudi programske strukture, v katerih bomo hranili stanje aplikacije, oziroma naše naprave. Podpreti moramo naslednje korake: inicializacija, čakanje na nastavitve, izvajanje glavne naloge in stanje hujše komunikacijske napake.
V skeletni kodi (v datoteki app.h) najdemo zgolj stanje inicializacije, ostala pa moramo sprogramirati sami. Mi smo si pri tem pomagali z gotovim primerom za enostavno komunikacijo ATSAMV71 Xplained Ultra razvojne plošče preko USB (glej program 1). Mi smo manjkajoča stanja dodali v obstoječi programski podatkovni tip z naštevanjem, APP_STATES, ki je že v skeletni programski kodi. A poudarimo, da lahko v splošnem stanja aplikacije definiramo tudi z drugimi programskimi strukturami, glej program 1..
Nato smo definirali tudi potrebne dodatne programske strukture za vmesno hrambo podatkov (glej program 2). Kot vidimo, mora aplikacija dejansko hraniti le najbolj osnovne podatke, kot so: ročica logične USB naprave (usbDevHandle), oddajni in sprejemni izravnalnik (receiveDataBuffer in transmitDataBuffer), hitrost prenos (usbSpeed) in še nekaj zastavic, glej program 2.
Dopolnitev programske kode
Podatkovne strukture so pripravljene, a moramo jih še ustvariti. Program 3 prikazuje inicializacijo podatkovnih struktur, ki jo izvedemo v podprogramu APP_Initialize (v datoteki App.c) Gre predvsem za nastavitev začetnih vrednosti, medtem ko bomo kazalce na dinamične strukture (usbDevHandle, txTransferHandle, rxTransferHandle) nastavili s podprogramom APP_Tasks, ki sledi izvajanju APP_Initialize, glej program 3.
Podprogram APP_Tasks je programska implementacija avtomata stanj, ki smo jih predelili v programu 1. Zakaj sploh potrebujemo avtomat stanj? Težko si predstavljamo, da bi SAMV71Q21B mikrokontroler vse naloge, povezane s komunikacijo preko USB, opravljal zaporedno. Potem bi se ne mogel odzivati na sporočila, ki bi prišla v drugačnem vrstnem redu od pričakovanega. Ne verjamete? Predstavljate, si da pomotoma iztaknete kabel USB. Mikrokontroler mora ta izredni dogodek obravnavati ne glede na to, ali morda čaka odziv gostiteljskega računalnika za prenos bloka podatkov. Prav zato je pomembno, da iz programa izločimo vse čakalne zanke, ki bi se ob morebitni neizpolnitvi pogojev vrtele v neskončnost. Eden izmed načinov, da to storimo, je uporaba programskega avtomata stanj v obliki podprograma APP_Tasks, s katero se hkrati izognemo potrebi po nameščanju jedra katerega od večopravilnih operacijskih sistemov, ki sicer na voljo tudi preko Microchip MPLAB Harmony programske knjižnice.
Vendar to še zdaleč ne pomeni, da so večopravilni operacijskih sistemi pri reševanju našega problema za odmet. Če uporabljamo SAMV71Q21B ali zmogljivejši mikrokontroler, si jih vsekakor lahko privoščimo. Res pa je, da bomo morali v tem primeru večopravilnost zagotoviti preko množice programskih niti in komunikacije med njimi. Za enkrat bomo to temo pustili ob strani, saj nas zanima programska rešitev, ki jo lahko vgradimo v vsak PIC, ki podpira komunikacijo preko USB.
Program 4 prikazuje, kako z ukazom USB_DEVICE_Open odpremo komunikacijo preko USB in dobimo ročico gonilnika USB, če klic uspe. Ročico nato uporabimo v ukazu USB_DEVICE_EventHandlerSet, povežemo gonilnik USB z našim podprogramom za obravnavo dogodkov na USB vodilu, APP_USBDeviceEventHandler, glej program 4.
Vendar, pozor! Preden USB gonilnik usmerimo na upravljalnik dogodkov APP_USBDeviceEventHandler, ga moramo vgraditi v programsko datoteko App.c. Ker gre za nekoliko daljši kos programske kode, predlagam, da si ga ogledate kar v programski knjižnici Harmony. Do nje pridete po nalslednji poti: <mapa, kamor ste namestili Harmonijo>appsusbdevicehid_basicfirmwaresrcApp.c.
Upravljalnik dogodkov USB, APP_USBDeviceEventHandler, mora podpreti kar precej možnosti in pri vsaki pravilno nastaviti stanje naše aplikacije, tako da v spremenljivko state vnese eno izmed mogočih stanj (glej program 1). Pri tem je zelo pomembna pravilna obravnava dogodkov, kot so: USB_DEVICE_EVENT_POWER_DETECTED, USB_DEVICE_EVENT_POWER_REMOVED, USB_DEVICE_EVENT_DECONFIGURED in USB_DEVICE_EVENT_CONFIGURED.
S prvim nas gonilnik USB obvešča, da je mikrokontroler zaznal napajalno napetost (5 V) na vodilu USB, kar pomeni, da lahko vklopimo funkcijsko enoto USB in se povežemo z gostiteljskim računalnikom. Slednje storimo s klicem funkcije USB_DEVICE_Attach (appData.usbDevHandle). Ravno obratno moramo storiti ob dogodku USB_DEVICE_EVENT_POWER_REMOVED, ko moramo poklicati funkcijo USB_DEVICE_Detach(appData.usbDevHandle). Omenimo še dogodek USB_DEVICE_EVENT_CONFIGURED, s katerim nas gonilnik obvesti, da je funkcijska enota USB vzpostavila povezavo z gostiteljskim računalnikom. Če vzpostavljamo povezavo z napravo za interakcijo človeka z računalnikom (HID, angl. human interface device), moramo nato nastaviti še upravljalnik dogodkov HID, kar storimo s klicem funkcije USB_DEVICE_HID_EventHandlerSet. Natančno strukturo USB HID upravljalnika dogodkov lahko najdete v datoteko App.c na že omenjeni poti, glede na mapo, v katero ste namestili Harmonijo.
Upravljanje dogodkov HID
Čeprav je HID samo eden izmed podprtih komunikacijskih protokolov, ki delujejo preko USB vodila, je pogosto najenostavnejši za implementacijo prenosa majhnih blokov podatkov. Bistveno je, da programsko podpremo dogodke za nadzor delovanja protokola, poleg teh pa še dogodka: USB_DEVICE_HID_EVENT_REPORT_RECEIVED in USB_DEVICE_HID_EVENT_REPORT_SENT, s katerima prenašamo podatkovne bloke, dolge do največ 64 bajtov. Dolžino USB HID blokov moramo predhodno opredeliti v nastavitvah funkcijske enote USB, jih lahko večinoma izvedemo preko Harmony Configuratorja.
Odgovoriti moramo še vprašanje, kako naša aplikacija ve, da smo uspešno oddali ali sprejeli podatkovni blok. Podatek o tem lahko preberemo iz podatkov dogodka USB_DEVICE_HID_EVENT_REPORT_SENT, oziroma USB_DEVICE_HID_EVENT_REPORT_RECEIVED. Podprogramu za obravnavo vsakega od omenjenih dogodkov ni potrebno storiti drugega, kot da globalno aplikacijsko spremenljivko hidDataReceived, oziroma hidDataTransmitted postavi na vrednost True.
Odziv glavne zanke na dogodke HID
Vrnimo se k funkciji APP_Tasks, ki na najvišjem nivoju upravlja vse naloge, povezane s prenosom podatkov preko vodila USB. Ker smo se odločili za način prenosa HID, smo poleg stanja APP_STATE_INIT dodali še stanji: APP_STATE_WAIT_FOR_CONFIGURATION in APP_STATE_MAIN_TASK. Prvo stanje je namenjeno čakanju na odgovor, ali je povezava z gostiteljskim računalnikom vzpostavljena. Iz tega stanja v naslednjem koraku vselej preidemo v stanje APP_STATE_MAIN_TASK, ki je namenjeno procesiranju USB HID funkcij. Prehod nazaj v stanje APP_STATE_WAIT_FOR_CONFIGURATION je mogoč le v primeru porušitve povezave preko vodila USB. Povejmo še, da je delovanje USB HID vmesnika sorazmerno preprosto, saj podatke prenašamo po blokih dolžine do 64 bajtov. Prejete podatke dobimo v izravnalniku receiveDataBuffer, če pokličemo funkcijo USB_DEVICE_HID_ReportReceive, medtem ko podatke pošiljamo tako, da jih prenesemo v transmitDataBuffer in pokličemo funkcijo USB_DEVICE_HID_ReportSend.
Čeprav vsebina blokov ni vnaprej določena, navadno številko funkcije podamo v prvem bajtu. Funkcije, ki vračajo podatke nato iz izravnalnika receiveDataBuffer preberemo še parametre. Rezultat izvajanja funkcije po potrebi vrnemo preko izravnalnika transmitDataBuffer. Kot vidimo, vsa komunikacija med gostiteljskim računalnikom in mikrokontrolerjem poteka preko preko omenjenih izravnalnikov. Posebna strukturiranost je potrebna predvsem za posebne naprave HID na USB (miška, tipkovnica, …), katerih funkcije znotraj komunikacijskih protokolov so večinoma določene vnaprej, glej program 5.
Zgradbo posredniških podprogramov za branje in pisanje podatkov neposredno v pomnilnike in registre v mikrokontroler vgrajenih funkcijski enot lahko vidimo v programu 1. PC preko sprejemnega izravnalnika USB HID povezave odda kodo ukaza za pisanja (0x1A) ali branje (0x1B), kateri je dodan še 32-bitni naslov registra funkcijske enote. Ukaz za pisanje (PIO_PortWrite(ADR,0xFFFFFFFF,DTA)zahteva tudi novo 32-bitno vrednost registra (DTA), medtem ko ukaz za branje (DTA=PIO_PortRead(ADR)) 32-bitno vrednost, DTA, prenese v izhodni USB izravnalnik in jo preko USB HID vmesnika vrne PCju. Kot zanimivost povejmo še, da moram podporni funkciji PIO_PortWrite, ki je del Harmony 3, kot drugi parameter podati tudi 32-bitno vrednost maske, s katero določimo, na katere bite registra funkcijske enote lahko vrednost DTA spremeni. V našem primeru sestavlja masko 32 enic (0xFFFFFFFF), kar pomeni, da z 32-bitno vrednostjo DTA lahko spremenimo vseh 32 bitov izbranega registra, ki pripada eni od vgrajenih funkcijskih enot.
Kako si pomagamo z Microchip MPLAB Harmony 3 Configuratorjem?
Zdaj, ko poznamo osnovni princip izgradnje lastnega nabora vgrajenih programskih funkciji, do katerih dostopamo preko USB HID vmesnika, poglejmo še, kako bi prebrali vrednost iz analognega vhoda s pomočjo A/D pretvornika v okviru funkcijske enote AFEC (Analog Front End Controller). V resnici to ni težko, saj je dodajanje programskih knjižnic v projekt z Microchip MPLAB Harmony 3 Configuratorjem sorazmerno enostavno, saj slednji samodejno zgradi programsko kodo z osnovnimi nastavitvami, pri čemer lahko izbiramo med tremi načini delovanja: prenosi DMA, prenosi s samodejnim proženjem prekinitev, ali enostavno zajemanje analognih vrednosti iz glavnega programa, kot je prikazano v programu 2, glej program 6.
Vsekakor poudarimo, da je program 2 namenjen predvsem enostavnemu testiranju, saj vsebuje neskončno zanko, s katero čaka na rezultat A/D pretvornika. V praksi bi morali dodati vsaj še psa čuvaja, s katerim bi lahko prekinili izvajanje zanke po izteku največjega dovoljenega določenega časovnega intervala, lahko pa bi namesto tega vstavili števec in dodatni pogoj za prekinitev izvajanja zanke, ko bi števec dosegel največjo dovoljeno vrednost.
Digitalno-analogni pretvornik, DACC
Ko smo že uporabili AFEC, je prav da preverimo še, kako deluje enostavna pretvorba digitalnih vrednosti v analogne. SAMV71Q21B ima vgrajen zmogljiv dvokanalni digitalni pretvornik-krmilnik (angl. digital to analog converter controller) z 12-bitno ločljivostjo, katerega izhoda DAC0 in DAC1 lahko povežemo z izhodnima priključkoma PB13 in PD0. Zanimivo, da sta to edini mogoči preslikavi. Izhoda D/A pretvornika na ATSAMV71 Xplained Ultra razvojni plošči najdemo na vtičnici J504. Za njuno uporabo moramo v Microchip MPLAB Harmony 3 Configuratorju dodati programski knjižnico DACC, omogočiti izhoda DAC0 in DAC1 na izhodnih priključkih in nato s pomočjo programskega generatorja v tem orodju pazljivo dopolniti programsko zagonsko kodo. Če odločimo za enostavni prosto-tekoči način delovanja DACC, lahko nato spreminjamo vrednost analognih izhodov z ukazoma: DACC_DataWrite(DACC_CHANNEL_0,<nova 12-bitna vrednost kanala 0>) in DACC_DataWrite(DACC_CHANNEL_1,<nova 12-bitna vrednost kanala 1>).
Poleg tega načina delovanja lahko izberemo tudi prekinitveni način, za uporabo katerega moramo zgraditi prekinitveni program, katerega naloga je pisanje na DAC0 in DAC1, ko se sproži prekinitev. Pri tem se lahko prekinitev proži sinhrono, po vsaki pretvorbi D/A, lahko pa jo proži tudi zunanja naprava preko posebnega prožilnega vhoda.
PC programska knjižnica in aplikacija
PC aplikacijo lahko sorazmerno enostavno pripravimo v Microsoft Visual Studio okolju, oziroma v enem od programskih jezikov, ki so podprti v tem okolju. Vsekakor lahko uporabimo tudi drugo programsko orodje, kar še posebej velja za razne izpeljanke Linuxa. Kakorkoli, gradnje aplikacije za USB HID komunikacijo PCja z mikrokontrolerjem se v vsakem od okolij lahko lotimo na podoben način. Zato se bomo omejili na Microsoft Visual Studio 2015.NET.
Programiranje v VB.NET
Microsoftovo razvojno okolje Visual Studio in programski jezik Visual Basic 2015.NET ali novejši (v nadaljevanju VB.NET) omogočata razumevanje osnovnih konceptov delovanja mikrokontrolerjev, kot tudi njihovo enostavno uporabo. Most med strojno opremo in programom v VB.NET predstavljata v Windows vgrajeni standardni gonilniki, kot je HID in univerzalna programska knjižnica SAMV71Q21B.NET4.dll, ki jo dobimo na spletnih straneh PC USB Projects.
Zdaj je čas, da se lotimo pisanja prvega programa za SAMV71Q21B mikrokontroler. Na spletni strani https://sites.google.com/site/pcusbprojects/6-downloads so na voljo vse ključne komponente za razvoj aplikacij v okolju Microcoft Visual Studio.NET: ugnezdena programska oprema za SAMV71Q21B (SAMV71Q21B firmware v1.0.HEX), dinamična knjižnica (SAMV71Q21B.NET4.DLL) in primer uporabe. Vse najdemo v datoteki SAMV71Q21B-EXAMPLE.NET4.zip
Najprej moramo v mikrokontroler s pomočjo programatorja prenesti vgrajeno programsko opremo (datoteka HEX). Nato namestimo razvojno okolje Microcoft Visual Studio 2015.NET ali novejše. Sicer lahko namestimo tudi starejše okolje, vendar moramo potem projekt izdelati sami. Pisanje lastnega programa za komunikacijo SAMV71 mikrokontrolerja s PC-jem v okolju .NET sicer začnemo tako, da ustvarimo novo okensko aplikacijo (nov projekt) v Visual Basicu ali Visual C-ju. Nato med reference dodamo dinamično programsko knjižnico SAMV71Q21B.NET4.DLL.
Zdaj se lahko lotimo pisanje kode. Med definicije glavne forme aplikacije dodamoDim PIC As SAMV71Q21B.SVPICAPI = New SAMV71Q21B.SVPICAPI. S tem bomo ustvarili nov objekt, ki zna komunicirati z mikrokontrolerjem preko vodila USB. Naslednji korak je klic ukaza za vzpostavitev komunikacijske povezave z izbranim mikrokontrolerjem: If PIC.Open(DEVICE_VID, DEVICE_PID) < 0 Then Goto Error. Metoda Open zahteva dva vhodna parametra, v katerih podamo ID proizvajalca (DEVICE_ID) in ID proizvoda (DEVICE_PID). Obe vrednosti sta zakodirani v datoteko HEX, oziroma v vgrajeno programsko opremo naprave. V datotekah HEX s prej omenjene spletne strani sta prednastavljeni vrednosti DEVICE_VID=&h4D8 (4D8 hekadecimalno, v nadaljevanju »hex«) in DEVICE_PID=&h3F.
Neposredni dostop do pomnilnika in registrov
Zdaj lahko iz programa v PC neposredno dostopamo do pomnilnika SAMV71Q21B, kar nam bo prišlo še kako prav pri testiranju njegovih številnih funkcionalnosti. Funkciji PIC.MemRead(<32-bitni naslov>) in PIC.MemWrite(<32-bitni naslov>, <32-bitni podatek>) omogočata branje in pisanje v celoten pomnilniški prostor, ki je prosto dostopen. Izjema je pisanje v EEPROM, kjer moramo uporabiti druge funkcije.
Kor primer poglejmo, kako lahko prižgemo in ugasnemo LED0 na razvojni plošči ATSAMV71 Xplained Ultra, ki je dostopna preko priključka PA23.
Prižgemo jo z ukazoma: PIC.MemWrite(&H400E0E00, PIC.MemRead(&H400E0E00) And &HFF7FFFFF), ugasnemo pa z ukazoma PIC.MemWrite(&H400E0E00, PIC.MemRead(&H400E0E00) Or &H800000). Kot vidimo, smo obakrat spremenili samo vrednost bita PA23.
Uporabljamo lahko tudi 12-bitna A/D pretvornika, AFEC0 in AFEC1, ki pretvarjata analogne iz po 11, oziroma 12 analognih kanalov v digitalne. To nam med drugim omogoča enostavno merjenje temperature SAMV71Q21B mikrokontrolerskega čipa (AFEC1, kanal 11 – kanali so sicer označeni od 0 naprej), ki jo lahko prosto izvedemo z ukazom PIC.ReadAnalogInput(<številka AFEC>,<številka analognega kanala>), oziroma PIC.ReadAnalogInput(1,11).
Za branje ostalih analognih kanalov moramo predhodno nastaviti zunanje priključke SAMV71Q21B. Ob tem dodajmo, da ima AFEC1 tudi 11. kanal iz katerega lahko preberemo vrednost temperature procesorskega čipa. 11. kanal je hkrati fiksno povezan s temperaturnim tipalom.
Po koncu dela mikrokontrolerjem, kar je navadno le ob zapiranju aplikacije, prekinemo komunikacijsko povezavo z naslednjim programskim stavkom:
PIC.Close()
Slednjega ne smemo pozabiti uporabiti, še posebej, če naša aplikacija deluje v večnitnem načinu (prednastavljeno), ko dejansko komunikacijo z mikrokontrolerjem izvaja posebna programska nit znotraj programske knjižnice DLL.
Analogne vhode v A/D pretvornika AFEC0 in AFEC1 najdemo na razvojni plošči na priključkih J502, J504 in EXT. Pomembno je, da jih pred uporabo AFECov pripravimo za delovanja in hkrati določimo izhodne priključke mikrokontrolerja, ki bodo delovali kot analogni vhodi. Vsekakor moramo vsakemu od A/D pretvornikov izbrati tudi vir delovnega takta, kar Microchip MPLAB Harmony 3 Configurator stori samodejno, ko v nastavitvah omogočimo kateregakoli od vhodnih kanalov in nastavitve nato s pomočjo programskega generatorja implementiramo v programski kodi.
Poglejmo še, kako nastavimo novo analogno vrednost na obeh kanalih DACC iz PC Windows aplikacije: PIC.DACC(<12-bitna nova vrednost kanala DAC0>,<12-bitna nova vrednost kanala DAC2>). Pri tem obe vrednosti podamo kot 16-bitni celi števili, pri katerih je uporabljenih le spodnjih 12 bitov, kar ustreza ločljivosti D/A pretvornika.
Program dobite v uredništvu revije Svet elektronike, za tiskano vezje pa nam pošljite e-mail in vam ga naredimo na naši PCB parceli za nekaj evrov.
Prihodnjič
Prihodnjič bomo podrobneje analizirali delovanje USB COM vmesnikov po protokolu CDC, za kar nam je tokrat žal zmanjkalo prostora. Podrobneje bomo spoznali tudi implementacijo UART protokolov za serijsko komunikacijo, ki lahko deluje tudi po standardu RS232. Doslej smo se tega problema lotevali zgolj posredno, prihodnjič pa nas bodo zanimale predvsem zmogljivosti UART funkcijski enot. Lotili se bomo tudi strojne podpore za prenos podatkov s protokoli I2C, SPI, QSPI in 2-WIRE.
Uporaba programskega generatorja v Microchip MPLAB Harmony 3 Configuratorju
Marsikateri začetni meni, da je potrebno za pravilno delovanja programa po izvedbi (pre)nastavitev dovoiti Microchip MPLAB Harmnony 3 Configuratorju izvedbno vseh predlaganih sprememb, ki zajemajo tako dopolnitve, kot brisanje programske kode. Vendar ni tako!
Še posebej, ko dodajamo nove funkcionalnosti v obstoječe že skonfigurairane aplikacije, moramo še kako paziti, da dovolimo samo tiste popravke, ki se nanašajo točno na dodano funkcionalnost. Popravke, ki se nanašajo na obstoječe funkcionalnosti (npr. osnovno delovanje USB HID vmesnika, ki je na primer že v celoti zagotovljeno), moramo ignorirati.Program 1: Stanja USB HID vmesnika v vgrajeni programski opremi
<Program 1> typedef enum{ APP_STATE_INIT=0, APP_STATE_WAIT_FOR_CONFIGURATION, APP_STATE_MAIN_TASK, APP_STATE_ERROR } APP_STATES;
Program 2: Glavna programska podatkovna struktura USB HID vmesnika
typedef struct{ USB_DEVICE_HANDLE usbDevHandle; /* Device layer handle returned by device layer open function */ uint8_t * receiveDataBuffer; /* Recieve data buffer */ uint8_t * transmitDataBuffer; /* Transmit data buffer */ APP_STATES state; /* Current state of the application */ bool deviceConfigured; /* Device configured */ USB_DEVICE_HID_TRANSFER_HANDLE txTransferHandle; /* Send report transfer handle*/ USB_DEVICE_HID_TRANSFER_HANDLE rxTransferHandle; /* Receive report transfer handle */ uint8_t configurationValue; /* Configuration value selected by the host*/ USB_SPEED usbSpeed; /* USB speed*/ bool hidDataReceived; /* HID data received flag*/ bool hidDataTransmitted; /* HID data transmitted flag */ uint8_t idleRate; /* USB HID current Idle */ } APP_DATA;
Program 3: Inicializacija podatkovnih struktur USB HID vmesnika
void APP_Initialize ( void ){ appData.state = APP_STATE_INIT; appData.usbDevHandle = USB_DEVICE_HANDLE_INVALID; appData.blinkStatusValid = true; appData.deviceConfigured = false; appData.txTransferHandle = USB_DEVICE_HID_TRANSFER_HANDLE_INVALID; appData.rxTransferHandle = USB_DEVICE_HID_TRANSFER_HANDLE_INVALID; appData.hidDataReceived = false; appData.hidDataTransmitted = true; appData.receiveDataBuffer = &receiveDataBuffer[0]; appData.transmitDataBuffer = &transmitDataBuffer[0]; } Program 4: Inicializacija USB gonilnika USB HID vmesnika case APP_STATE_INIT: appData.usbDevHandle=USB_DEVICE_Open(USB_DEVICE_INDEX_0, DRV_IO_INTENT_READWRITE); /* Open the device layer */ if(appData.usbDevHandle!= USB_DEVICE_HANDLE_INVALID){ USB_DEVICE_EventHandlerSet(appData.usbDevHandle, APP_USBDeviceEventHandler, 0); /* Register a callback with device layer to get event notification */ appData.state = APP_STATE_WAIT_FOR_CONFIGURATION; } break;
Program 5: Izsek iz vgrajene programske kode, s katerim zapisujemo ali beremo iz poljubnih vrat v mikrokontroler vgrajenih funkcijskih enot
… case 0x1A: // write 32-bit word to a microcontroller port adr=ReceiveDataBufferReadDWORD(1); dta=ReceiveDataBufferReadDWORD(5); PIO_PortWrite(adr,0xFFFFFFFF,dta); break; case 0x1B: // read 32-bit word from a microcontroller port adr=ReceiveDataBufferReadDWORD(1); dta=PIO_PortRead(adr); TransmitDataBufferWriteDWORD(1,dta); ToSendDataBuffer[0]=0x1B; SendTransmitBuffer(); break; …
Program 6: Zajem analogne vrednosti z AFEC0 ali AFEC1 v vgrajeni programski kodi in prenos vrednosti v PC preko USB HID vmesnika
… case 0x02: // AFEC0: read analog channel ToSendDataBuffer[0]=0x03; adr=ReceiveDataBufferReadDWORD(1);if(adr>10)adr=10; AFEC0_ConversionStart(); while(!AFEC0_ChannelResultIsReady(adr)){}; // wait for conversion w=AFEC0_ChannelResultGet(adr); TransmitDataBufferWriteWORD(1,w); SendTransmitBuffer(); break; … case 0x03: // get analog input ToSendDataBuffer[0]=0x03; adr=ReceiveDataBufferReadDWORD(1);if(adr>11)adr=11; AFEC1_ConversionStart(); while(!AFEC1_ChannelResultIsReady(adr)){}; // wait for conversion w=AFEC1_ChannelResultGet(adr); TransmitDataBufferWriteWORD(1,w); SendTransmitBuffer(); break; …