0,00 €

V košarici ni izdelkov.

0,00 €

V košarici ni izdelkov.

More
    DomovRevijaProgramiranjeHarmonija razvoja in programiranja (9)

    Harmonija razvoja in programiranja (9)

    Svet elektronike colorAvtor: dr. Simon Vavpotič
    2017_257_28

    Microchip Harmony je zagotovo najpomembnejši programski okvir za vse, ki se navdušujemo nad mikrokontrolerji in digitalnimi procesorji podjetja Microchip. Je tudi pomemben vgradni del razvojnega okolja MPLAB X IDE, ki nekajkrat pohitri in poenostavi delo programerjev.

    Slika 1: Snemalnik zvoka na kartico SD

    V preteklem nadaljevanju smo spoznali delo z datotekami v datotečnih sistemih FAT in MCFS, ki ju podpira Harmony. Izdelali smo tudi preprost snemalnik zvoka, ki pa žal pri višjih hitrostih zajemanja odpove. Opazimo namreč, da bi potrebovali še dodatni mikrokontroler za zajem in začasno hrambo zvoka, medtem ko poteka shranjevanje že zajetih vzorcev v datoteko. Uporabili smo tudi PIC32MZ EC Starter kit, ki je namenjen zgolj eksperimentiranju. Za praktično uporabo so potrebne namenske rešitve. Tokrat se bomo lotili nekoliko zahtevnejše implementacije z dvema mikrokontrolerjema.

    Kako začeti?

    Spopadli se bomo s problemom nepretrganega zajemanja zvoka in njegovega shranjevanja na kartico SD. V preteklem nadaljevanju smo videli, kako lahko problem rešimo z enim mikrokontrolerjem. Tokrat nam bo pomembnejša kakovost vzorčenja.

    Snemalnik zvoka bomo izdelali s pomočjo dveh mikrokontrolerjev PIC32MX (PIC32MX270F256B in PIC32MX250F128B), od katerih bo eden prevzel nalogo digitalizatorja zvoka in njegovega prenosa preko povezave SPI, drugi pa bo skrbel za zapisovanje zvoka na kartico SD. Podobno je zasnovana večina digitalnih predvajalnikov in snemalnikov zvoka, le da uporablja za zajem ali predvajanje namenski mikrokontroler, ki zvok tudi kodira ali dekodira v krajši zapis ali iz krajšega zapisa (npr. MP3). Zato mu pravimo tudi kodek (koder-dekoder). V našem primeru zvok samo zajamemo in shranimo.

    PIC32MX250F128B uporablja A/D pretvornik in vmesnik SPI. Preko povezave SPI z visoko bitno hitrostjo (1 Mb/s) prenaša podatke »bratu«, PIC32MX270F256B, ki skrbi za prenos digitaliziranega zvoka na kartico SD. Pri slednjem uporabimo oba vmesnika SPI, enega za kartico SD, drugega pa za med-mikrokontrolersko komunikacijo. Pri tem mimogrede rešimo tudi primer komunikacije med dvema PIC32 preko zaporednega vmesnika SPI, ki se zdi eden izmed težjih, če sklepamo po objavah na spletnih raznih spletnih forumih. V resnici je pomembna pri programiranju predvsem natančnost in doslednost ter poznavanje nekaj osnovnih trikov.

    Dobro je, na primer vedeti, da s programatorjem PICkit3 ne moremo preveriti pravilnosti prenosa podatkov preko povezave SPI v smeri proti razhroščevanemu mikrokontrolerju. Pri branju iz registra SPI1BUF (prvi vmesnik SPI) ali SPI2BUF (drugi vmesnik SPI) bomo med razhroščevanjem vselej prebrali vrednost 0, ker kaže, da prihaja do nehotenega dvojnega branja. Med normalnim delovanjem sicer branje vrne pravo vrednost. Vsekakor si z vedenjem omenjenega lahko prihranimo marsikateri siv las.

    Za praktično uporabo je sicer SPI sila enostaven. Če izvedemo pravilne nastavitve registrov SPIxCON (x = št. enote SPI), SPIxCON2, SPIxBRG in resetiramo statusni register SPIxSTART z vpisom vrednosti 0x40, lahko preko registra SPIxBUF hkrati prenašamo podatke v obe smeri. Namesto tega lahko uporabimo tudi knjižnico Harmony. Vendar, ne pozabimo na »požiranje« vhodnih podatkov pri razhroščevanju. Za naš primer smo si privoščili kar neposredno programiranje registrov, saj gre za aplikacijo, kjer ne želimo veliko odvečne programske kode, saj prenašamo podatke v realnem času. Morda je prav, povemo še to, da smo Harmony sicer s pridom uporabili za osnovne nastavitve vrat: PORTA in PORTB ter preslikave vhodov in izhodov vmesnikov SPI (enota PPS), saj je delo v grafiki veliko prijetnejše od ročnega preračunavanja vrednosti posameznih registrov. Hkrati pri tem ničesar ne izgubimo pri hitrosti delovanja, saj se nastavitve izvedejo le na začetku delovanja.

    Zajem zvoka

    Dobro! Rešili smo problem komunikacije SPI med dvema PIC32. Sedaj potrebujemo še zajem zvoka, A/D pretvorbo in shranjevanje na kartico SD. Prvo nalogo lahko rešimo brez Harmony, ob predpostavki, da smo že poprej nastavili vrata PORTA in PORTB ter preslikave vrat enot SPI in A/D pretvornika.

    Tudi tokrat smo signal v A/D pretvornik pripeljali iz ojačevalnika radia, osmislili pa smo si še Vellemanov komplet PMK136’1 za 11 €, ki že vključuje mikrofona in predojačevalnika (stereo).

    A/D pretvornik PIC32MX270F256B ima vgrajen medpomnilnik, za začasno shranjevanje do šestnajst vzorcev. Vendar je njegova uporaba pogojena z načinom delovanja in hitrostjo zajemanja. Mi smo si problem poenostavili in smo zajemali vzorce le iz enega registra medpomnilnika v glavni pomnilnik (RAM) PIC32MX270F256B, ki je predstavljal veliko zajetnejši medpomnilnik.

    Protokol gospodar-suženj preko SPI

    Slika 2: Sestava snemalnika zvoka na kartico SD

    Protokol za komunikacijo preko SPI si je bilo potrebno preprosto izmisliti. Hkrati ima PIC32MX250F128B le 32 kB glavnega pomnilnika, od katerega lahko za medpomnilnik uporabimo največ kakih 30 kB. Tako ostane veliko kombinaciji pri naslavljanju neizkoriščenih. Uporabimo jih lahko kot krmilne kode s katerimi gospodar SPI bere podatke iz sužnja.

    Ste že uganili, kateri od PIC32MX je gospodar? Seveda, PIC32MX270F256B, ki upravlja prenos podatkov na kartico SPI! Naloga gospodarja je, da krmili prenos podatkov in preko kontrolnih kod sporoča, katere naslove iz medpomnilnika želi prebrati, oziroma katero od naslednjih funkcij želi izvesti: branje podatka iz naslova v medpomnilniku (koda ukaza je kar naslov med 0 in 0xFFF5), test (koda 0xFFFF), beri zaporedno lokacijo (koda 0xFFFE), branje vrednosti kazalca za zapis podatkov v medpomnilnik sužnja (koda 0xFFFD), branje vrednosti kazalca za branje podatkov iz medpomnilnika sužnja (koda 0xFFFC), branje števca podatkov v medpomnilniku (koda 0xFFF7), ponastavitev kazalcev za zapis in branje podatkov ter števca shranjenih podatkov na 0, ponovni zagon vmesnika SPI sužnja (koda 0xFFF8), … Skratka, najpomembnejši ukaz je 0xFFFE, s katerim gospodar izvaja zaporedno branje podatkov iz medpomnilnika. Pri tem se kazalec na lokacijo medpomnilnika za branje samodejno povečuje.

    Povratna komunikacija vrača vrednosti iz AD-pretvornika, ki je nastavljen tako, da pri 16-bitni vrednosti izkoriščenih samo zgornjih 10 bitov. PIC32MX250F128B vrača status izravnalnika za zvok preko posebne linije, BUF_EMPTY, ki pove, kdaj je mogoče branje naslednjega bloka podatkov. Vrednost 0 pove, da je branje mogoče, vrednost 1 pa, da ni mogoče brati, ker ni dovolj podatkov. Gospodar mora počakati na naslednji blok podatkov, oziroma da BUF_EMPTY dobi vrednost 0.

    Izvajanje pravkar omenjenega protokola je preprosto. Ko ima gospodar čas, bere podatke iz medpomnilnika sužnja hitreje kot jih ta zapisuje ter jih shranjuje na kartico SD.

    Priklop bralnika kartic SD

    Kartic SD vsekakor ne želimo spajkati v tiskano vezje. Zato potrebujemo ustrezno ohišje, v katero lahko vstavimo ali iz njega odstranimo kartico. Potrebni sta tudi napetostna in tokovna prilagoditev. V trgovini Microchip Direct lahko kupimo že izdelano vmesniško ploščico, iz katere vodi množica signalov. A k sreči potrebujemo le: SCK, SDI, SDO, CS, WD in CD. Prvi štirje omogočajo komunikacijo, medtem ko WD in CD povesta, ali je na kartico SD dovoljeno pisati in ali je kartica SD vstavljena v ohišje.

    Od komunikacijskih signalov je CS namenjen aktivaciji komunikacije, podatki pa se prenašajo serijsko preko signalnih linij SDO (izhodni podatki v kartico SD) in SDI (vhodni podatki iz kartice SD). Signal SCK je urin signal, ki ga mora zagotoviti PIC32. Kar za slednjega res ni problem, saj ima vgrajeni kar dve enoti SPI.

    Zdaj pa zares! Tu si izdatno pomagamo s Harmony in priloženimi primeri, kar se vsekakor splača, saj je pravilen zapis podatkov na kartico SD pomemben zaradi zagotavljanja združljivosti z operacijskimi sistemi osebnih računalnikov, tablic in pametnih mobilnih telefonov. Uporabimo tako gonilnika za SPI in kartico SD, kakor tudi sistemsko storitev za podporo delovanju operacijskega sistema. Več o tem lahko preberete v preteklem nadaljevanju.

    Nepretrgano vzorčenje zvoka

    Če ne želimo snemati razsekanega zvoka, skoraj ni druge možnosti, kot da uporabimo večopravilnost v realnem času; kar z drugimi besedami pomeni, da uporabimo dva mikrokontrolerja. Zvok vzorčimo s prvim mikrokontrolerjem, ki zajeta vzorce pakira v datoteko, ki ima primerno obliko za zapis, drugi pa skrbi za zapisovanje tako zbranih podatkov na kartico SD. Program v prvem mikrokontrolerju shranjuje vzorce v veliki in sprejema ukaze od glavnega mikrokontrolerja, ki skrbi za shranjevanje zvoka na kartico SD in izvaja druge krmilne funkcije. Denimo, preverja stanje mikro stikal, s katerimi upravljamo napravo.

    Realizacija programske kode je v obeh mikrokontrolerjih je koračna. Le tako lahko brez pravega večnitnega operacijskega sistema zagotovimo tudi dovolj večopravilnosti za poganjanje vseh nalog, ki so potrebne za zapis podatkov na kartico SD. Čeprav se morda slednje zdi preprosto, temu ni čisto tako. Ko velikost datoteke naraste na več kot 20 MB, je potrebno za postavitev datotečnega kazalca na konec datoteke kar nekaj dragocenega časa, ki je potreben za prenos zvoka.

    Zakaj pa ne bi imeli datoteke med zapisovanjem ves čas odprte? To je sicer mogoče, vendar bomo v tem primeru lahko izgubili vso vsebino, ki je še v medpomnilniku. Če nam je vseeno, se lahko periodičnemu odpiranju in zapiranju datoteke odpovemo.

    Slika 3: Električna shema snemalnika zvoka

    V vsakem primeru PIC32MX270F256B, ki tiktaka s 40 MHz, za zapisovanje v datoteko porabi kar nekaj časa. Takrat PIC32MX250F128B vzorce zvoka shranjuje v medpomnilnik. Čeprav se zdi, da bi problem lahko uspešno rešili tudi z enim mikrokontrolerjem, se dva izkažeta bistveno bolje. En mikrokontroler ne more izvajati dveh nalog v realnem času, marveč mora pri vsaki prekinitvi preklopiti kontekst delovanje. Pri zapisu na kartico SD pa je pomembno, da se cikel zapisovanja izvede dovolj hitro. Zato lahko med slednjim izgubimo nekaj zvočnih vzorcev, kar je za uho neprijetno, saj zvok »preskakuje«.

    Edina rešitev je uporaba dveh mikrokontrolerjev. Vendar je to lažje, kot če bi na vrat na nos poskušali razviti vsemogočno programsko kodo, ki bi se ognila presežkom porabe časa, ki jih zahteva uporaba knjižnice Harmony. Pa tudi v tem primeru ni zagotovila, da bi uspeli uskladiti zajem vzorcev in pisanje blokov podatkov na kartico SD. Tudi osebni računalnik uporablja za obdelavo zvoka ločen mikrokontroler, ki je del zvočnega podsistema, včasih pa je bil na posebni zvočni kartici…

    Algoritma

    Protokol gospodar-suženj smo že omenili. Zato je prav, da nekoliko pogledamo še celotno »sliko« programske kode. Programje v grobem sestavljata dva algoritma, po eden za vsak mikrokontroler. Obema je skupna začetna inicializacija, ki se izvede bolj ali manj samodejno. Potem, ko v grafičnem programerskem vmesniku naklikamo želene opcije, programski generator Harmony izdela skupek datotek z nastavitvami in zagonsko programsko kodo. Za nas sta najpomembnejši sta app.h in app.c. V prvi so definirani osnovni koraki programa, v drugi pa njihovo izvajanje. Pri mikrokontrolerju za zajem zvoka sta koraka samo dva: inicializacija in delovanje (glej Protokol gospodar-suženj preko SPI). Korak delovanja smo zaradi hitrosti delovanja rešili kot neskončno zanko, ki se zahvaljujoč enostavni uporabi enote SPI, izogne vsem programskim presežkom Harmony.

    Pri drugem mikrokontrolerju je potrebnih bistveno več korakov, saj želimo odpornost na odpovedi strojne in programske opreme. Tu se Harmony ne želimo izogniti. Pravzaprav postane pomemben zaveznik, ki omogoča hitro pot do rešitve. Po inicializaciji sledi odpiranje pogona, odpiranje nove datoteke in zapis 44-bajtne glave datoteke snd.wav, v katero zapišemo osnovne podatke o hitrosti vzorčenja, številu zvokovnih kanalov in številu bitov na kanal (koraki: APP_STATE_INIT, APP_INITIAL_DISK, APP_INITIAL_OPEN_FILE, APP_WRITE_TO_FILE). Zdaj lahko začne preko povezava SPI zajemati blok podatkov iz prvega mikrokontrolerja, če je na voljo (korak APP_STATE_READING). Podatki so zaradi lažje obdelave razdeljeni na bloke po 512 bajtov. Obveščanje o razpoložljivosti naslednjega bloka podatkov poteka preko že omenjene signalne linije BUF_EMPTY.

    Ko je blok podatkov prebran, se PIC32MX270F256B loti njegovega zapisovanja na kartico SD (koraki: APP_STATE_OPEN_FILE, APP_STATE_WRITING, APP_STATE_CLOSE), ki poteka skoraj v celoti pod nadzorom Harmony. Osrednji korak je APP_STATE_WRITING, kjer z ukazom SYS_FS_FileWrite zapišemo na kartico SD po en blok podatkov. Programer mora kot parameter ukaza podati ročico datoteka, kazalec na blok podatkov in dolžino bloka. Koraka APP_STATE_OPEN_FILE in APP_STATE_CLOSE sta v uporabi le občasno, saj želimo preprečiti, da bi datoteka ob neželenem izpadu napajanja ostala, ali drugem izrednem dogodku odprta in bi se s tem shranjena vsebina do ukaza SYS_FS_FileClose izgubila. Povrnili bi jo lahko samo, če bi s katerim od programskih orodij za osebne računalnike popravili vsebino na kartici SD.

    V praksi

    Zvok zajemamo analogno. Zato je zelo pomembno, kako ga pripeljemo do A/D pretvornika. Pomembna je tudi stabilna napajalna napetost za PIC32MX250F128B in predvsem dobra masa.

    Pojdimo po vrsti, od izvora zvoka od kartice SD: Mikrofonski ojačevalnik je zelo občutljiv na motnje napajanja zato ga je smiselno napajati ločeno, ali pa filtrirati njegovo vhodno napetost in s tem preprečiti motnje iz digitalnega dela vezja. Po drugi strani, porabi mikrofonski del zelo malo energije in se lahko več dni napaja iz treh baterij. Mikrokontrolerja sta precej bolj požrešna in »pokurita« 4 baterije že v enem dnevu. Vendar ju brez težav napajamo tudi iz vtičnice USB.

    Slika 4: Algoritma gospodarja in sužnja

    Tako smo že pri vzorčenju zvoka. Hitrost okoli 8000 vzorcev na sekundo se ne zdi pretirano, vendar moramo upoštevati, da imamo pri PIC32MX na voljo sorazmerno majhne glavne pomnilnike. Zato se napolnita že v nekaj sekundah. Zato mora shranjevanje na kartico SD ves čas delovati brezhibno, sicer je posnetek nezvezen. Pomembni sta tudi brezhibno delovanje in usklajenost delovanja vmesnikov SPI pri obeh mikrokontrolerjih. O tem smo že veliko povedali. Dodajmo le to, da v praksi povezava SPI dobro deluje in se nad njeno zanesljivostjo ne moremo pritoževati.

    Ostane še shranjevanje v datoteko na kartici SD. Tu utegnemo imeti težave ne zaradi druge povezave SPI, temveč je pomembno katere operacije izvajamo poleg zapisovanja podatkov. V tem pogledu je pomembna tudi velikost bloka podatkov, ki ga zapišemo na enkrat. Premajhen blok podatkov pomeni preveč presežnih operacij, ki onemogočajo dovolj visoko hitrost pisanja podatkov (vsaj okoli 20 kB/s). V praksi je 512 bajtov ravno pravšnja velikost.

    Obenem ne moremo brez varnostnega shranjevanja (občasnega odpiranja in zapiranja datoteke). Vendar se pri ukazu SYS_FS_FileOpen z vklopljeno opcijo dodaj (append) implicitno sproži tudi potratna funkcija za pomik datotečnega kazalca, SYS_FS_FileSeek, ki lahko povzroči celo prekinitev toka podatkov, če je datoteka velika nekaj 100 MB. Optimalna nastavitev je eno shranjevanje na 1000 blokov, kar omogoča, da se podatkovni tok ne prekine, hkrati pa ne izgubimo več kot kako minuto posnetka.

    Za konec povejmo še, da prikazano prototipno vezje ni imelo vgrajene tipke za začetek in konec snemanja. Zato je prekinitev snemanja pomenil kar izvlek kartice SD, kar pa ni najboljše, saj na tak način zanesljivo izgubimo del posnetka. Kljub temu je dodati tipko enostavno. Potrebujemo le mikrostikalo, na pa tudi upora, saj ima PIC32 opciji upora na napajanje (pull-up) ali na maso (pull-down) že vgrajeni in ju lahko nastavimo preko začetnih nastavitev. Malenkostno moramo spremeniti tudi program, da med pogoji za prekinitev snemanja upošteva tudi stanje mikrostikala, oziroma tipke.

    Prihodnjič

    PIC32 lahko deluje tudi kot gostitelj naprav USB, spletni spojnik (HUB), ali pa kot večpredstavna periferna enota, denimo mikrofon USB. Tokrat nam je zmanjkalo prostora, vendar se teh vprašanj zanesljivo lotimo prihodnjič.Harmonija razvoja in programiranja (8)
    Harmonija razvoja in programiranja (7)
    Harmonija razvoja in programiranja (6)
    Harmonija razvoja in programiranja (5)
    Harmonija razvoja in programiranja (4)
    Harmonija razvoja in programiranja (3)
    Harmonija razvoja in programiranja (2)
    Harmonija razvoja in programiranja (1)