Využití AD a DA převodníků
Digitální zvukový procesor Seminární práce z programování a informatiky
Vypracoval: Vladimír Burian V Jihlavě dne 23. 1. 2008
Obsah OBSAH....................................................................................................................................................2 ZADÁNÍ A SPECIFIKACE..................................................................................................................3 POPIS KONEČNÉHO ZAŘÍZENÍ......................................................................................................3 POPIS HARDWARU ............................................................................................................................5 ŘÍDÍCÍ A VÝPOČETNÍ JEDNOTKA...................................................................................................................6 MODUL UŽIVATELSKÉHO ROZHRANÍ.............................................................................................................7 POPIS SOFTWARU PRO MIKROPOČÍTAČ...................................................................................7 STRUKTURA PROGRAMU (PROJEKTU)............................................................................................................7 EFEKTY..................................................................................................................................................9 ZÁVĚR..................................................................................................................................................10 ZDROJOVÉ KÓDY.............................................................................................................................11 MAIN.ASM............................................................................................................................................11 EFFECT_ECHO.ASM................................................................................................................................17 COM_ACCESS.ASM...............................................................................................................................21 SCHÉMATA.........................................................................................................................................23
-2-
Zadání a specifikace Prvotním cílem pro mě bylo navrhnout, zkonstruovat a zprovoznit přenosné programovatelné zařízení zpracovávající zvuk – přesněji zařízení, které by bylo schopné v reálném čase efektovat zvuk zejména elektronických hudebních nástrojů, např. kytary. Mělo by být obsaženo několik základních efektů, především těch, jejichž podstatou, či rovnou výsadou je relativně delší zpoždění – takové efekty nejsou náročné na numerické výpočty a lze jich těžko dosáhnout čistě analogovou cestou. Samozřejmostí je požadavek na jednoduché ale účinné uživatelské rozhraní. Zařízení si neklade nárok konkurovat i těm levnějším, masově vyráběným multiefektům, ale mělo by být s přimhouřeným okem v praxi použitelné. Hlavním cílem samotného zařízení tedy není pouze konečný, na začátku velmi nejistý výsledek, ale také cesta k němu. V každém případě tedy bude sloužit ke vzdělání. S tím souvisí další požadavek: Zařízení (přinejmenším některé jeho části) by mělo mít univerzálnější charakter, možnost rozšíření, připojení dalších periferií a nabídnout možnost osvojení si práce s nimi. Případně i posloužit jako zajímavý základ pro úlohy jiného charakteru.
Popis konečného zařízení Zvuk prochází zařízením následujícím způsobem: vstup
+ +
výstup
Efekt
Obr.1: blokové schéma analogové cesty signálu Ihned za vstupem je signál zesílen na potřebnou úroveň nastavenou uživatelem tak, aby byl co nejlépe využit rozsah A/D a D/A převodníků a přitom nedocházelo ke zkreslení – přebuzení převodníků. Toto nastavení velmi ovlivňuje výslednou kvalitu zvuku a odstup nežádoucích složek signálu vznikajících při převodu. Následně se signál rozděluje do dvou větví. V horní, čisté větvi je neefektovaný signál přiveden k dalšímu zesilovači (prakticky pouze na potenciometr), který určuje jeho úroveň ve výsledném signálu. Druhá větev se stará o efektovaný signál. Když opomeneme směšovač a následující dolní propust, signál vstoupí do „efektu“ – digitální části přístroje. Následně je „vyčištěn“ další dolní propustí, ze které pokračuje jednak na zesilovač (potenciometr) určující jeho podíl ve výstupu a pak přes jiný zesilovač (potenciometr) zpět na začátek, kde je (již efektovaný
-3-
signál) přimíchán do signálu teprve vstupujícího do „efektu“. Posledně popsaná část tedy zajišťuje zpětnou vazbu „efektu“, která v praxi slouží k nastavení např. délky ozvěny. Nakonec jsou oba signály – efektovaný a čistý – smíchány a dále už je pouze řízena celková úroveň výstupního signálu. Na blokovém schématu není zakreslen výkonový výstupní zesilovač.
Obr.2: nákres zadního panelu přístroje
Obr.3: pohled na vrchní stranu přístroje Funkce potenciometrů: - P1 – zesílení vstupního signálu - P2 – úroveň čistého signálu - P3 – úroveň efektovaného signálu - P4 – zpětná vazba - P5 – hlasitost Funkce tlačítek: -
TL1 – menu zpět TL2 – menu vpřed TL3 – plus TL4 – mínus TL5 – nahoru TL6 – dolu
menu typu rozcestí
menu typu nastavení Obr.4: příklad struktury programu -4-
Rozhraní pro komunikaci programu s uživatelem zahrnuje grafický display, 6 tlačítek a 6 LED diod. Diody slouží primárně k indikaci úrovně signálu se kterým „efekt“ pracuje – což je důležité pro již zmíněné, správné nastavení zesílení vstupního signálu. Z obr.4 je patné velmi jednoduché, účelné uspořádání nabídek. Základem pro vše je menu, které obsahuje nadpis a jednotlivé položky na zvláštních řádcích. Právě vybraná položka je vlevo indikována šipkou a pro její posun složí tlačítka TL5 a TL6. Položka v rozcestí má funkci jakéhosi odkazu na další menu – rozcestí tedy reaguje také na TL1 a TL2. Pokud se ale dostaneme na menu typu nastavení, znamená to, že zároveň běží jemu odpovídající „efekt“ (programový modul) – položky v tomto případě představují jednotlivé volitelné vlastnosti. Pro jejich změnu slouží TL3 a TL4. TL1 způsobí vypnutí efektu a skok zpět. Implementovány jsou v současné době pouze dva efekty: echo a flanger. Základní vlastnosti: - vzorkovací frekvence: 27 027 – 29 585 Hz - rozlišení: 12-bitové, mono - filtry: mezní frekvence 5 kHz; Butterworthovy 4. řádu, - vstupní citlivost: 160 mV – 1,76 V - napájení: min. 11 V (ideálně). max. 35 V
Popis hardwaru Vzhledem k požadavku univerzálnosti i kvůli snadnějšímu zprovoznění a odhalování chyb (důvodem je také postupný vznik celku) je zařízení rozděleno do několika samostatných, ucelených modulů (vše je patrno z přiložených schémat): -
řídící a výpočetní jednotka modul uživatelského rozhraní modul A/D a D/A převodníků („zvuková karta“) modul zesilovačů a zpětné vazby výkonový sluchátkový zesilovač zdroj stabilizovaného napětí
Výkonnost a složitost (jak hardwaru, tak softwaru) se odvíjí od použitého mikropočítače. Dnešní trh nabízí mnoho jednočipových mikropočítačů lišících se počtem I/O pinů, počtem vestavěných obvodů, velikostí pamětí, výpočtovými schopnostmi, rychlostí či rovnou předurčeností k použití v určitých oblastech a tento sortiment se velmi rychle rozšiřuje. Takováto rozmanitost s sebou nese rozličné architektury mikroprocesorů, instrukční sady, různé vývojové nástroje i programátory k samotnému přenesení kódu do mikropočítače. Vyznat se tak v nabídce a přecházet mezi kategoriemi mikropočítačů není úplně snadné. Protože mám zkušenosti zejména s 8-mi bitovými mikropočítači (spíše mikrokontroléry) firmy Microchip, vybral jsem jejich PIC16F874A, přestože by se našli mnohem a mnohem vhodnější, třeba přímo z řad DPS (digitálních signálových procesorů), které jsou navrženy pro zpracování signálu obecně.
-5-
Řídící a výpočetní jednotka Některé základní vlastnosti PIC16F874A: - frekvence 20 MHz – 5 MIPS (milionů operací za vteřinu) - architektura RISC (redukovaná instrukční sada) – pouze 35 instrukcí - zásobník na 8 návratových adres - 4 k words (14 bit) Flash program memory (100 000 cyklů) – 4096 instrukcí - 192 B SRAM - 128 B EEPROM (1 000 000 cyklů) - 33 vstupů/výstupů - 3x časovač/čítač - SSP (synchronní sériový port) a I2C - UART (univerzální synchronní asynchronní přijímač a vysílač) - 8-kanálový 10-bitový A/D převodník - 2x PWM (pulzně-šířková modulace) modul Ostatní moduly jsou k hlavní řídící jednotce připojeny dvěma typy synchronních sběrnic: 1, sériovou sběrnicí SPI – poměrně velmi rychlá a jednoduchá sběrnice využívající 4 signály: data do a z periferie a hodinový signál (společné pro všechny) a adresní signál (jedinečný pro každé zařízení), který určuje, s čím chceme komunikovat (tzv. hardwarová adresace). Tímto odpadá potřeba „zdlouhavého“ odesílání adresy požadované periferie při každém spojení. 2, paralelní sběrnicí – 8 datových vodičů, 2 hodinové signály (pro čtení a pro zápis) a opět pro každé zařízení jedinečný adresní vodič. Sériová sběrnice umožňuje adresovat 16 zařízení (0 – 15), přičemž první 3 pozice jsou rezervovány pro 3 EEPROM (k uložení např. znakové sady, struktury menu, uvítací bitmapy apod.) Adresní bity jsou negovány – log.0 … aktivní. Paralelní sběrnice umožňuje adresovat 8 zařízení (0 – 7). Adresní bity zde nejsou negované. Na tuto sběrnici je napevno připojeno 2x32 KB SRAM, které obsadily prví 3 pozice. Adresa 0 má funkci zapsání nižšího bytu adresy pro SRAM (názorně: na datové vodiče pošleme nižší byte adresy pro SRAM a poté !!!změníme!!! adresu paralelní periferie na 0, což vyvolá na odpovídajícím vodiči vzestupnou hranu a adresa pro SRAM je uložena). Adresa 2 odpovídá zapsání vyššího bytu adresy pro SRAM. Adresa 3 už přímo odpovídá samotné SRAM a následně je již možno psát či číst na předtím určené místo. Další podrobnosti jsou patrné ze schématu. V této konstrukci není nejsou na sběrnici připojena žádná další zařízení. Pozn.: SRAM paměti byly získány ze stařičké základní desky PC Deska také obsahuje převodník z TTL logiky na linku rs232, což je sériový (COM) port počítače. Po této lince je možno přeprogramovat mikropočítač bez nutnosti hardwarového programátoru, či ho využít k testování apod. Převádí se pouze základní signály RXD a TXD, avšak na převodníku je volný další pár, který by šel požít např. k hardwarovému řízení komunikace. Na mikropočítači záměrně zůstaly nepoužity piny RC0 až RC3 (PWM výstupy a vstupy pro čítače) a celý PORTA (piny RA0 – RA5; analogové vstupy).
-6-
Modul uživatelského rozhraní Funkce z hlediska uživatele již byla popsána s části „Popis konečného zařízení“. Jako display je použit monochromatický grafický display 48x84 bodů z mobilního telefonu Nokia 5110. Jedná se o display firmy Goldentek s řadičem PCD8544. Display je vnitřně rozdělen na 6 řádků – každý elementární sloupec (8 bodů) v řádku odpovídá zapsanému bytu. Kromě dříve uvedených 6-ti tlačítek je možno připojit k tomuto modulu další 2 tlačítka/přepínače (např. nožní spínač pro zapínání a vypínání efektů apod.).
Popis softwaru pro mikropočítač Použitý mikropočítač klade na zařízení velká omezení, o to kvalitnější a úspornější musí být program pro něj. Zásadním měřítkem je dosažená vzorkovací frekvence. Abychom pokryli slyšitelné pásmo 20 – 20 000 Hz, potřebovali bychom vzorkovací frekvenci minimálně 40 kHz. Na první pohled by se zdálo, že 5 MIPS je postačujících. To by ale znamenalo zpracovat jeden vzorek signálu ve 125 instrukcích, aniž by mikropočítač dělal cokoli jiného. Bylo by možné této hodnoty dosáhnout ale uživatelské rozhraní jsem nehodlal opomenout. Všech 35 instrukcí mikropočítače pokryje opravdu velmi základní úkony a uvědomíme-li si, že je 8-bitový, vyvstává mnoho problémů. Za nejsložitější aritmetické operace se dá považovat sčítání a odčítání. Při každé operaci s daty také musí být jedno z čísel umístěno napřed do pracovního registru, tzv. WREG značený W. Sečtení dvou 8-bitových čísel uložených v RAM a zapsání výsledku do RAM na místo třetí tak v ideálním případě zabere 3 instrukce. Obdobná operace s 16-bitovými čísly vyžaduje minimálně 8 instrukcí a přitom není ošetřeno přetečení. Další nepříjemností je rozdělení programové i datové paměti na banky. To znamená, že nemůžeme jednoduše pracovat s jakýmkoli bytem v RAM nebo odskočit v programu ihned na jakékoli místo. Tomu musí předcházet nastavení správné banky v registrech. Pro úplné pochopení je nezbytné přečtení alespoň části katalogového listu mikropočítače. V praxi se mi podařilo přiblížit se vzorkovací frekvenci 30 kHz včetně obsloužení uživatele a stupnice znázorňující úroveň signálu. Každé zkrácení programu byť o jednu jedinou instrukci je znatelným úspěchem. Zrychlení by přineslo použití interního A/D převodníku a PWM jako výstupu, avšak za cenu snížení hloubky na 10 bitů. Program je psán přímo v assembleru s použitím volně dostupného vývojového nástroje MPLAB od Microchipu.
Struktura programu (projektu) Projekt obsahuje tyto soubory: - Main.asm – hlavní část programu - Init.asm – inicializace mikropočítače - Routines.asm – čekací rutiny - Hardware_routines.asm – základní rutiny pro SPI, pro práci s RAM a EEPROM … - COM_access.asm – komunikace mikropočítače s PC po rs232 - Math.asm – násobení a dělelní - Display_modul.asm – základní obsluha displeje, výpis čísel, znaků a řetězců, bitmapy, … - Effect_Echo.asm – programový modul „Echo“ - Effect_Flanger.asm – programový modul „Flanger“ - DSP_Header.inc – konstanty a definice -7-
- Math_macros.inc – základní operace s 16-bitovými čísly - 16f874a.lkr – soubor pro linker s rozložením programové paměti Program lze logicky rozdělit do tří oddílů: Většinu tvoří podprogramy na té nejnižší úrovni pro komunikaci s hardwarem nebo s PC, pro výstup na displej, matematické operace, odměřování času apod. Programové moduly – dělají právě to, co se od celého zařízení očekává především. Každý musí mít minimálně 5 podprogramů: -
Inicializace a start modulu Zastavení modulu Reakce na změnu vlastnosti v menu Rutinní podprogram (je volán při každém průchodu hlavní nekonečnou smyčkou) Podprogram při přerušení (u efektu je to zpracování jednoho vzorku signálu)
Tyto podprogramy musí být zapsány v tabulkách uvnitř „Main.asm“. Pokud by ale existence nějakého z těchto podprogramů nebyla potřebná, lze do tabulky rovnou zapsat RETURN. No a pokud chceme mít k tomuto modulu přístup jako uživatelé skrze rozhraní, musíme pro něj vytvořit menu strukturu, navázat ji na ostatní menu a celek poté zapsat do externí EEPROM. Při „spouštění“ programového modulu je ještě před vlastním voláním podprogramu pro start volán podprogram pro změnu vlastnosti postupně pro každou položku – vytvoření vnitřních implicitních údajů na základě implicitních údajů předaných z postupně menu. Přidávání a odebírání programových modulů by tak nemělo vyžadovat nějak hluboké zásahy do ostatního programového kódu, nicméně částečně vyžaduje jeho znalost. Ve středu všeho je program „Main.asm“, který se stará především o komunikaci s uživatelem. Stará se o chod menu a spravuje programové moduly (zde jsou to efekty, ale mohlo by jít i o cokoli jiného). Podrobnější funkce by snad měla být patrná z jeho komentářů. Reprezentace jednotlivých menu mají takovouto strukturu: 1B 2B xB 1B
-
číslo podprogramu offset předchozí struktury v ROM string nadpisu počet položek této struktury
xB - string 1.položky 4B - Nastavení vlastností 1. položky xB - string 2.položky 4B - Nastavení vlastností 2. položky ... --------------------------------------Vlastnosti položky z menu typu nastavení: 1B – ItemVal - počáteční hodnota 1B – ItemStep - krok při změně 1B – ItemMin - minimum 1B – ItemMax - maximum Vlastnosti položky z menu typu rozcestí: 2B - Offset dalšího menu 2B - nepoužito
-8-
Hlavní menu z obr.4 vypadá v ROM následovně: 0550: 0558: 0560: 0568: 0570: 0578: 0580:
00 20 45 08 72 6F 73
00 4D 63 20 00 6D 00
00 45 68 46 51 20 A9
09 4E 6F 6C 00 61 00
4D 55 00 61 00 63 00
41 03 35 6E 0B 63
49 05 00 67 20 65
4E 20 00 65 43 73
....MAIN .MENU.. Echo.... . Flange r.Q... C om acces s....
Menu typu nastavení pro efekt „Echo“: 0580: 0588: 0590: 0598: 05A0:
01 FF 04 45 43 48 4F 01 0E 44 65 6C 61 79 3A 20 20 20 30 6D 73 32 01 C8
CB 20 20 01
... .ECHO.. Delay: 0ms... .
Nadpis „ECHO“, jediná položka „ Delay: 0ms“, s výchozí hodnotou 50, měnitelná po kroku 1 v intervalu od 1 do 200.
Pozn.: Data jsou skutečným výpisem z EEPROM a je tudíž také patrné provázání obou menu přes offsety.
Efekty Důležité je, že převodníky jsou připojeny přes sériovou sběrnici a SRAM přes paralelní. Díky tomu se může obojí komunikace provádět zároveň. Oba efekty pracují s RAM jako s nekonečným kruhovým zásobníkem. Každý vzorek v tomto zásobníku obsazuje dva byty. Každý efekt si uchovává aktuální pozici (samozřejmě vždy dělitelnou 2), na kterou zapisuje právě přečtený vzorek. „Delay“ poté udává o kolik bytů zpět se nachází požadovaný zpožděný vzorek („Delay“ je opět dělitelné 2). Spouštění efektové smyčky (podprogramu) je řízeno přerušením. Důležité je, aby pro hlavní smyčku zbylo alespoň 7 cyklů bez přerušení – tolik cyklů je potřeba, aby mohla pracovat sériová komunikace. V jiném případě program určitě zamrzne. Echo je nejjednodušší efekt, pouze vytváří konstantní zpoždění. Může posloužit jako základ pro další efekty pracující se zpožděním. Flanger mění lineárně zpoždění signálu v úzkém intervalu (např. 0–5 ms) a změna má periodu v jednotkách sekund. Sám osobě míchá zpožděný a původní signál ve zvoleném poměru. Součtem oněch dvou signálů vzniká nový signál, kde jsou některé frekvence potlačeny a některé naopak posíleny, a díky změně zpoždění se mění i tyto frekvence. Výsledkem je zvuk přirovnávaný ke zvuku stíhačky. Změnou poměru míchání se mění „ostrost“ efektu.
-9-
Závěr Touto seminární prací jsem zdaleka nepokryl možnosti vytvořeného zařízení. Co se efektů týče, napadlo by mě ještě např. vibrato, zkreslení zvuku podle převodní tabulky uložené v RAM, implementace jednoduchého FIR filtru apod. Hardware je dále připraven na stereo rozšíření pouze propojením několik míst, tuto možnost jsem ale ani nestihl vyzkoušel. Také jsem chtěl zkusit zprovoznit slot na SD/MMC karty (podporují SPI režim), ani na to nedošlo. Před dalšími pokusy bych ale prvně přeci jenom přešel na jiný mikropočítač, konkrétně na PIC18F452. Tento o řadu vyšší mikropočítač nabízí 75 instrukcí, nemá programovou část rozdělenou do bank, RAM prostor je daleko větší a nejen na všechny řídící registry lze přistupovat okamžitě, disponuje 10 MIPS, vnitřní hardwarovou násobičku (násobí dvě bytová čísla v jednom cyklu !) atd. A především je s PIC16F874A pinově kompatibilní. Tento se jako DSP opravdu používá a jeho vnitřní struktura je pro to uzpůsobena daleko lépe. (mikroprocesor jsem již koupil, bohužel jsem si ale nenašel čas přepsat pro něj program) Nápadů na vylepšení je stále dost a dost. Přesto si myslím, že je za čím se ohlédnout, i když toto téma nevypadá nějak atraktivně a mnoho lidí asi výsledek nezaujme. Rozhodně alespoň mě ale práce přinesla mnoho nových poznatků a vědomostí. Jak stavba probíhala (a že to nebylo vždy tak veselé) si můžete prohlédnout a poslechnout na přiloženém CD. Zde také najdete datasheety některých obvodů, veškerá schémata atd.
- 10 -
Zdrojové kódy Pozn.: nejsou kompletní, ale obsahují důležité poznámky; vynechávky označeny (…)
Main.asm ;================================================================= ;================================================================= ;--------------------- Hlavní programový kód --------------------;================================================================= ; Obsluha uživatele - spravuje se menu, reaguje se na tlačítka... ; Obsluha přerušení a správa podprogramů jednotlivých efektů ;----------------------------------------------------------------; Definice ;----------------------------------------------------------------#include "p16f874A.inc" __config _BODEN_OFF & _CP_OFF & _PWRTE_ON & _WDT_OFF & _HS_OSC & _DEBUG_OFF & _CPD_OFF & _LVP_OFF #include "DSP_Header.inc" EXTERN EXTERN
COM_BOOT INITIALIZATION
EXTERN EXTERN EXTERN EXTERN EXTERN EXTERN
WAIT_x100ms INIT_DSP, CLEAR_DSP, STARTUP_SCREEN GOTO_XY, CoordX, CoordY WRITE_DEC, MAKE_BCD, BCDNum WRITE_CHAR_FAST, WRITE_STRING, WRITE_CAPTION VUMeter
EXTERN EXTERN
ROM_READ_PREPARE, Adr SPI_IO
EXTERN EXTERN
ECHO_START, ECHO_CHANGE, ECHO_LOOP FLANGER_START, FLANGER_CHANGE, FLANGER_LOOP, FLANGER_ROUTINE
GLOBAL GLOBAL
INTERRUPT_END, EFFECT_LOOP_START IntDelay, ItemVal, MenuItemNum
GLOBAL GLOBAL GLOBAL
SPIReceive, SPIRecBuf ITEM_WRITE_1, ITEM_WRITE_2 CHANGE_LEDS
;----------------------------------------------------------------; Proměnné potřebné při obsluze přerušení ;----------------------------------------------------------------Inter_var UDATA ; Záloha důležitých registrů WregBuf res 1 StatusBuf res 1 PCLATHBuf res 1 SPICSBuf res 1 ; Podle další proměnné se nastavuje interval dalšího přerušení ; Přerušení nastává, pokud časovač TMR0 přeteče přes 255 ; "IntDelay" je počáteční hodnota TMR0 ; Počet cyklů mezi přerušeními = 256 - "IntDelay" + 5 IntDelay res 1 ; Proměnné využité při kritické sériové komunikaci SPIReceive res 1 SPIRecBuf res 1
- 11 -
;----------------------------------------------------------------; Proměnné k obsluze tlačítek ;----------------------------------------------------------------Buttons_var UDATA BtnNew res 1 ; Nový stav tlačítek BtnOld res 1 ; Starý stav tlačítek BtnClick res 1 ; Tlačítka, které byla stisknuta BtnCount res 1 ; Počítadlo pro automatické opakování stisku BtnTmrInit res 1 ; Počáteční hodnota pro časovač autorepeateru ; v podstatě není nutné; umožňuje změnu ; rychlosti automatického opakování ;----------------------------------------------------------------; Proměnné potřebné pro chod menu ;----------------------------------------------------------------Menu_var UDATA MenuAdr res 2 ; ROM adresa současné menu struktury MenuOffset res 2 ; Offset předchozí struktury MenuSubPrg res 1 ; Číslo podprogramu náležící k současnému menu MenuItems res 1 ; Počet položek v menu MenuItemNum res 1 ; Číslo právě vybrané položky (od 0) MenuTemp res 1 ; Pouze vnitřní proměnná ItemMax res 1 ; Maximální hodnota právě vybrané položky ItemMin res 1 ; Minimální hodnota právě ... ItemStep res 1 ; Změna (krok) hodnoty právě ... ItemVal res 1 ; Aktuální hodnota právě ... Backlight res 1 ; Podsvícení displeje (0-nesvítí; 1-svítí) ; Proměnné "Item..." se týkají pouze právě vybrané položky. ; Obdobné údaje těch ostatních jsou uloženy za sebou v zásobníku ; ležícím od adresy 0xA0 a přistupuje se k nim skrze ukazatel ;================================================================= ;================================================================= ;---------------------- Prvopočátek programu --------------------;================================================================= RESET CODE 0x0000 pagesel INITIALIZATION CALL INITIALIZATION CALL COM_BOOT GOTO PROGRAM ; Provede se nezbytná počáteční inicializace mikropočítače ; Dále je vyvolán pokus o navázání spojení po rs232 lince ; Poté program pokračuje na adrese "PROGRAM" ;================================================================= ;####################### OBSLUHA PŘERUŠENÍ ####################### ;================================================================= ; Obsloužení interruptu (bez návratu z efektové smyčky) ; trvá max. 30 cyklů ; min. 28 cyklů ; Vektor přerušení INTERRUPT CODE 0x0004 MOVWF WregBuf
; Uložení pracovního registru W
BCF MOVF MOVWF
INTCON,TMR0IF IntDelay,W TMR0
; Nastavení dalšího přerušení
MOVF MOVWF MOVF MOVWF
STATUS,W StatusBuf SPI_CS,W SPICSBuf
; Záloha další kritických registrů
BTFSC GOTO MOVF
SPIReceive,0 INTERRUPT_L1 SSPBUF,W
; Případné dokončení kritické SPI ; komunikace ; Odeslání 1 bytu trvá 8 cyklů ->
- 12 -
MOVWF BSF
SPIRecBuf SPIReceive,0
INTERRUPT_L1 MOVF PCLATH,W MOVWF PCLATHBuf CLRF PCLATH MOVF ADDWF
MenuSubPrg,W PCL,F
GOTO GOTO GOTO GOTO
INTERRUPT_END ECHO_LOOP FLANGER_LOOP INTERRUPT_END
; pokud jsme těsně před přerušením ; začali komunikovat, zde již bude ; komunikace dokončena ; Skok do odpovídající efektové smyčky
; Tabulka efektových smyček !!!!!!!!!!
; Volá se po dokončení efektové smyčky INTERRUPT_END MOVF PCLATHBuf,W ; Obnovení kritických registrů MOVWF PCLATH MOVF SPICSBuf,W MOVWF SPI_CS MOVF StatusBuf,W MOVWF STATUS MOVF WregBuf,W RETFIE ; Návrat z přerušení ;================================================================= ;------------- Inicializace hlavní programové smyčky ------------;================================================================= MAIN CODE 0x0030 PROGRAM BSF SPIReceive,0 ; Inicializace displeje CALL INIT_DSP CLRF BSF CLRF CALL
Backlight Backlight,0 VUMeter CHANGE_LEDS
; Nastavení a rozsvícení podsvětlení
CALL MOVLW CALL
STARTUP_SCREEN .15 WAIT_x100ms
; Ukázaní úvodní bitmapy na 1500ms
CLRF MOVLW MOVWF MOVLW MOVWF GOTO
MenuSubPrg h'05' MenuAdr h'50' MenuAdr+1 MENU_PREPARE
; Načtení prvotní menu struktury ; (MAIN MENU) z ROM na adrese 0x0550 ; MENU_PREPARE na závěr skočí do ; nekonečné smyčky MAIN_MENU
;================================================================= ;-------------------- Hlavní nekonečná smyčka -------------------;================================================================= MAIN_MENU CALL SUBPRG_ROUTINE ; Zavolá rutinní podprogram efektu CALL READ_BUTTONS ; Přečte stav tlačítek ; Další část reaguje na stisk tlačítek (v podstatě události) BTFSC BtnClick,BTN_F1 ; TL1 - v menu o krok zpět GOTO MENU_BACKWARD MOVF BTFSC GOTO
MenuItems,F STATUS,Z MAIN_MENU
; Pokud menu nemá žádné položky, ; opaku smyčku, jinak jdi dál
BTFSC
BtnClick,BTN_DOWN
; Posun po položkách v menu
- 13 -
CALL BTFSC CALL
MENU_DOWN BtnClick,BTN_UP MENU_UP
MOVF BTFSC GOTO BTFSC CALL BTFSC CALL GOTO
MenuSubPrg,F STATUS,Z MAIN_MENU_L1 BtnNew,BTN_LEFT BTN_LEFT_PRESS BtnNew,BTN_RIGHT BTN_RIGHT_PRESS MAIN_MENU
MAIN_MENU_L1 BTFSC BtnClick,BTN_F2 GOTO MENU_FORWARD GOTO MAIN_MENU ; Opakování smyčky MAIN_MENU
; ; ; ;
Na tlačítka "plus" a "mínus" reaguje pouze pokud je číslo podprogramu větší než 0 (pokud běží efekt)
; Pokud je pouze v nabídce, reaguje ; na TL2
;================================================================= ;------------------------- Příprava menu ------------------------;================================================================= ; Každá menu struktura je v ROM reprezentována následovně: ; --------------------------------------; 1B - číslo podprogramu ; 2B - offset předchozí struktury v ROM ; xB - string nadpisu ; 1B - počet položek této struktury ; ; ; ; ; ; ; ; ; ; ; ; ; ;
xB - string 1.položky 4B - Nastavení vlastností 1. položky xB - string 2.položky 4B - Nastavení vlastností 2. položky ... --------------------------------------Vlastnosti položky z menu nastavení: 1B - ItemVal 1B - ItemStep 1B - ItemMin 1B - ItemMax Vlastnosti položky z rozcestí 2B - Offset další struktury 2B - ---
; Načte takovouto strukturu uloženou na adrese "MenuAdr" ; a samozřejmě aktualizuje všechny proměnné "Menu_var". ; Kromě toho také zavolá postupně pro každou položku podprogram ; pro přepočet vnitřních údajů efektu – inicializace hodnot MENU_PREPARE (...) ; MENU PREPARE končí skokem do hlavní smyčky MENU_BACKWARD MENU_JUMP ; Načte menu určené offsetem v "MenuOffset" ; Pokud "MenuOffset" nezměníme, znamená to zpět. (...) MENU_FORWARD ; Načte následující menu (...)
- 14 -
;================================================================= ;-------------- Rutiny pro práci s položkami v menu -------------;================================================================= MENU_DOWN ; Způsobí vybrání nižší položky včetně zavolání ostatní důležitých ; podprogramů s tím souvisejících (...) MENU_UP ; Obdobně způsobí vybrání vyšší položky (...) ;================================================================= ITEM_WRITE_1 ; Vypíše na displej hodnotu položky beze změny (...) ITEM_WRITE_2 ; Vypíše na displej hodnotu položky jako číslo "ItemVal"*10^-1 ; Jednotky oddělí od desítek a stovek desetinou čárkou (...) ;================================================================= MENU_ITEM_CH ; Na displeji označí aktuální položku a do proměnných "Item..." ; načte její vlastnosti (...) MENU_ITEM_UNCH ; Na displeji odznačí aktuální položku a její proměnné uloží ; zpět do zásobníku (...) MENU_ITEM_POINT ; Nastaví ukazatel na data položky "MenuItemNum" v zásobníku (...) ;================================================================= ;----------- Čtení tlačítek a některé jejich události -----------;================================================================= READ_BUTTONS ; Zaktualizuje BtnOld, BtnNew a BtnClick (...) ; Následující podprogramy reagují na stisk (držení) tlačítek ; "plus" a "mínus" a odpovídajícím způsobem mění hodnotu "ItemVal" ; právě vybrané položky (vlastnosti). BTN_LEFT_PRESS (...) BTN_RIGHT_PRESS (...) BTN_LEFT_RIGHT_REPEAT (...)
- 15 -
;================================================================= ;############ SPRÁVA PODPROGRAMŮ JEDNOTLIVÝCH EFEKTŮ ############# ;================================================================= ; Zde jsou části kódu spravující 4 z 5 podprogramů potřebných pro ; každý efekt. Tyto podprogramy jsou pro: ; - start (inicializace) efektové smyčky ; - konec (zastavení) efektové smyčky ; - aktualizace (přepočet) vnitřních údajů efektu ; - provedení rutinních záležitostí (např. obsluha VU metru) ; Poslední, 5. podprogram (samotná efektová smyčka) je v části ; obsluhující přerušení SUBPRG_START ; Skočí do startovacího (inicializačního) podprogramu efektu pageselw SUBPRG_START_TABLE MOVLW SUBPRG_START_TABLE ADDWF MenuSubPrg,W BTFSC STATUS,C INCF PCLATH,F MOVWF PCL SUBPRG_START_TABLE ;Tabulka startovacích podprogramů RETURN GOTO ECHO_START GOTO FLANGER_START RETURN SUBPRG_STOP ; Skočí do ukončovacího podprogramu ; Většinou efekty nevyžadují odlišný přístup a lze použít ; základní podprogram EFFECT_LOOP_STOP pageselw SUBPRG_STOP_TABLE MOVLW SUBPRG_STOP_TABLE ADDWF MenuSubPrg,W BTFSC STATUS,C INCF PCLATH,F MOVWF PCL SUBPRG_STOP_TABLE ; Tabulka ukončovacích podprogramů RETURN GOTO EFFECT_LOOP_STOP GOTO EFFECT_LOOP_STOP RETURN ITEM_CHANGE ; Je voláno při změně hodnoty položky v menu typu nastavení. ; Nastaví na displeji souřadnici řádku této položky a následně ; skočí do podprogramu odpovídajícího efektu, který přepočte své ; interní údaje. MOVF MenuItemNum,W ADDLW .2 MOVWF CoordY pageselw ITEM_CHANGE_TABLE MOVLW ITEM_CHANGE_TABLE ADDWF MenuSubPrg,W BTFSC STATUS,C INCF PCLATH,F MOVWF PCL ITEM_CHANGE_TABLE ; Tabulka podprogramů pro aktualizaci RETURN ; interních údajů GOTO ECHO_CHANGE GOTO FLANGER_CHANGE RETURN SUBPRG_ROUTINE ; Skočí do podprogramu s rutinami odpovídajícího efektu pageselw SUBPRG_ROUTINE_TABLE MOVLW SUBPRG_ROUTINE_TABLE ADDWF MenuSubPrg,W
- 16 -
BTFSC STATUS,C INCF PCLATH,F MOVWF PCL SUBPRG_ROUTINE_TABLE ; Tabulka podprogramů s rutinami RETURN RETURN GOTO FLANGER_ROUTINE RETURN ;================================================================= ;------------ Elementární spuštění, zastavení efektu ------------;================================================================= EFFECT_LOOP_START ; Povolí přerušení od TMR0 CLRF TMR0 BCF INTCON,TMR0IF BSF INTCON,GIE RETURN EFFECT_LOOP_STOP ; Zakáže přerušení od TMR0 a zhasne VU metr BCF INTCON,GIE CLRF VUMeter CALL CHANGE_LEDS RETURN ;================================================================= ;---------------------------- Ostatní ---------------------------;================================================================= CHANGE_LEDS ; Podle proměnných "VUMeter" a "Backlight" rozsvítí/zhasne ; LED diody a podsvícení. ; Bity 2..7 proměnné "VUMeter" odpovídají jednotlivým LED. SET_SPI_ADR LED_ADR MOVF VUMeter,W ANDLW b'11111100' IORWF Backlight,W CALL SPI_IO NULL_SPI_ADR RETURN END
Effect_Echo.asm ;================================================================= ;-------------------------- EFEKT ECHO --------------------------;================================================================= #include "p16f874a.inc" #include "DSP_Header.inc" EXTERN EXTERN EXTERN EXTERN EXTERN EXTERN
INTERRUPT_END EFFECT_LOOP_START RAM_CLEAR MUL, MulByte, MulWord, MulAns ITEM_WRITE_1 IntDelay, ItemVal
; Podprogramy určené k zapsání do tabulek hlavního programu GLOBAL ECHO_START, ECHO_CHANGE, ECHO_LOOP Effect_var Pos Delay
UDATA_OVR res 2 ; Adresa aktuální pozice v RAM res 2 ; O kolik bytů před aktuální pozicí
- 17 -
; se nachází chtěný zpožděný vzorek SampleIn SampleOut SAdr
res 2 res 2 res 2
; vzorek čtený z ADC, poté zapisovaný do RAM ; vzorek čtený z RAM, poté zapisovaný na DAC ; pomocná proměnná
Count
res 1
; pomocná proměnná
;================================================================= ECHO CODE ECHO_START ; Inicializace a start echa CALL RAM_CLEAR CLRF Pos CLRF Pos+1 MOVLW .92 MOVWF IntDelay CALL EFFECT_LOOP_START RETURN
; Vyčištění RAM ; Nastavení nulové adresy ; Nystavení přerušení ; na 29 585 Hz ; Zapnutí přerušení
ECHO_CHANGE ; Reaguje na změnu vlastnosti (zpoždění - jeho jediná vlastnost) MOVLW CHAR8 ; novou hodnotu vypíše na displej CALL ITEM_WRITE_1 MOVF MOVWF MOVLW MOVWF MOVLW MOVWF CALL MOVF MOVWF MOVF MOVWF RETURN
ItemVal,W MulByte .2 MulWord .80 MulWord+1 MUL MulAns,W Delay MulAns+1,W Delay+1
; Vnitřní proměnná "Delay" ; je rovna "ItemVal" * 592
;================================================================= ECHO_LOOP ; 123 cyklů ; Zpracování jednoho vzorku ; Přečte vzorek z ADC a zapíše ho na aktuální pozici v RAM. ; Z RAM přečte dřívější vzorek a zapíšeho na DAC. ; Pozn.: instrukce odsazené více vpravo jsou součástí paralelní ; komunikace s RAM ;----------------------------------------------------------------; I. část - čtení z ADC a RAM + částečně zápis do RAM MOVF IORLW ANDLW MOVWF MOVLW MOVWF
SPI_CS,W h'0F' ADC_ADR SPI_CS b'00000001' SSPBUF
;-------------------; SAdr = Pos - Delay ; Adresa, ze které se čte zpožděný signál MOVF SUBWF MOVWF
Delay,W Pos,W SAdr
MOVF SUBWF MOVWF
Delay+1,W Pos+1,W SAdr+1
- 18 -
BTFSS STATUS,C DECF SAdr,F ;(8) NOP ;(9) ;-------------------MOVF BSF MOVLW MOVWF
SSPBUF,W SSPCON,SSPM0 b'10100000' SSPBUF
;-------------------; čtení "SampleOut" z RAM CLRF PPI_CS MOVF MOVWF INCF MOVF MOVWF INCF
SAdr+1,W PPI_DAT PPI_CS,F SAdr,W PPI_DAT PPI_CS,F
BSF MOVLW MOVWF BCF
STATUS,RP0 b'11111111' TRISD STATUS,RP0
BCF MOVFW MOVWF BSF
PPI_OE PPI_DAT SampleOut PPI_OE
BSF CLRF BCF
STATUS,RP0 TRISD STATUS,RP0
;(18)
; čtení "SampleOut+1" CLRF PPI_CS INCF MOVWF
SAdr+1,W PPI_DAT
MOVLW MOVWF
h'02' PPI_CS
BSF MOVLW MOVWF BCF
STATUS,RP0 b'11111111' TRISD STATUS,RP0
BCF MOVFW MOVWF BSF
PPI_OE PPI_DAT SampleOut+1 PPI_OE ;(31)
BSF STATUS,RP0 CLRF TRISD BCF STATUS,RP0 ;-------------------MOVF SSPBUF,W ANDLW b'00001111' MOVWF SampleIn MOVLW b'00000000' MOVWF SSPBUF ;--------------------
;(34)
; zápis "SampleIn" - pozn. již bylo přečteno z ADC CLRF PPI_CS
- 19 -
MOVF MOVWF INCF
Pos+1,W PPI_DAT PPI_CS,F
MOVF MOVWF INCF
Pos,W PPI_DAT PPI_CS,F
MOVF SampleIn,W MOVWF PPI_DAT BCF PPI_WE BSF PPI_WE SPI_WAIT ;-------------------MOVF SSPBUF,W MOVWF SampleIn+1 INCF SPI_CS,F
;(11) ; Počká na dokončení SPI komunikace
;-----------------------------------------------------------------; II. část - zápis do DAC a RAM BCF MOVFW IORLW MOVWF
SSPCON,SSPM0 SampleOut b'10110000' SSPBUF
;-------------------; zápis "SampleIn+1" CLRF PPI_CS INCF MOVWF
Pos+1,W PPI_DAT
MOVLW MOVWF
h'02' PPI_CS
MOVF SampleIn+1,W MOVWF PPI_DAT BCF PPI_WE BSF PPI_WE ;(9) ;-------------------MOVF MOVF MOVWF
SSPBUF,W SampleOut+1,W SSPBUF
;-------------------; Pos := Pos + 2 ; Posun adresy ukazující do RAM na následující pozici MOVLW h'02' ADDWF Pos+1,F BTFSC STATUS,Z INCF Pos,1 ;-------------------NOP NOP NOP NOP NOP ;-------------------MOVF
SSPBUF,W
;----------------------------------------------------------------; III. část - případné dodatečné výpočty a návrat GOTO end
INTERRUPT_END
- 20 -
COM_access.asm ;================================================================= ;-------- Komunikace mezi mikropočítačem a PC přes rs232 --------;================================================================= #include "p16f874a.inc" #include "DSP_Header.inc" EXTERN EXTERN GLOBAL
SPI_IO WAIT_x10ms COM_SYNC, COM_ACCESS, COM_BOOT
Temp UDATA_OVR COM_Command res 1 COM_Dat res 1 CBLOCK Length:0x01 Count:0x01 Check:0x01 Buf:0x42 ENDC
0x20
;================================================================= RECEIVE_NEXT_BYTE MACRO ; Čeká na další byte, pokud nepřijde včas (určeno v podprogramu ; COM_ACCESS_RNB), vyvolá TIMEOUT, jinak vrátí přijatý byte ; skrz WREG. (...) ;================================================================= COM_INTERFACE CODE COM_SYNC ; Pokus o synchronizaci mikropočítače a PC. ; Vyšle znak "B". Pokud před vypršením timeoutu přijme od PC ; znak "Y", odpoví znakem "O" a nastaví STATUS,Z na 1. ; Pokud vyprší timeout nebo přijme jiný znak než "Y", nastaví ; STATUS,Z na 0. ; Poté se vrátí. (...) ;================================================================= COM_BOOT ; Vyvolá pokus o navázání spojení - "COM_SYNC". ; V případě úspěchu přejde do módu naslouchání, jinak se vrátí. (...) COM_ACCESS ; Naslouchá počítači a interpretuje jeho příkazy. ; Na první byte četá neomezeně, další se musí vejít do timeoutu. ; První byte - číslo příkazu ; Druhý byte - parametr příkazu ; Pokud je příkaz neplatný, odpoví znakem "E". Jinak příkaz ; interpretuje, což končí odpovědí: ; "O" - zdárné dokončení ; "L" - vypršel timeout (vymaže se fronta) ; "E" - v případě nějaké chyby (všechny chyby nejsou ošetřeny) ; Dále se celý postu opakuje ; Výjimkou je příkaz TERMINATE - odpoví "T" a program se vrátí ; ze stavu naslouchání (...)
- 21 -
COM_ACCESS_TABLE GOTO COM_ACCESS_TERMINATE GOTO COM_ACCESS_SPI_CS GOTO COM_ACCESS_SPI_WRITE GOTO COM_ACCESS_SPI_READ GOTO FLASH_WRITE GOTO FLASH_READ GOTO COM_ACCESS_RESTART
; ; ; ; ;
Tabulka příkazů Ukončení naslouchání Adresuje SPI zařízení Odešle po SPI byte Přijme po SPI byte
; Skočí na úplný začátek ; programu, ale nevymaže např. ; zásobník návratových adres.
FLASH_WRITE ; Slouží k nahrání programu do mikropočítače po rs232. ; Paramert je počet WORDů k zapsání (max. 32 words). ; 1. přečte počáteční adresu zápisu programu (word) ; 2. přečte odpovídající počet WORDů nového programu ; 3. přečte kontrolní součet (byte) a zkontroluje ho ; 4. v kladném případě začne zapisovat do programové paměti ; POZOR programovat lze vždy jen čtveřici zarovnaných WORDů (...) FLASH_READ ; Slouží ke čtení programové paměti po rs232 ; Paramert je počet WORDů k přečtení (max. 255 words). ; 1. přečte počáteční adresu (word) ; 2. přečte kontrolní součet adresy (byte) a zkontroluje ho ; 3. odešle odpovídající počet WORDů programové paměti ; 4. odešle kontrolní součet předtím odeslaných WORDů (...) ;Pozn.: WORD má tvar ["nižší byte""vyšší byte"] ;Pozn.: Kontrolní součet - je v podstatě součet všech bytů, ; ze kterého je v jeho 256-kovém zápisu dělán ciferný ; součet tak dlouho, dokud číslo nemá pouze jednu cifru. ; př.: 0x0286 -> 0x88 ; př.: 0xFFFF -> 0x01FE -> 0xFF ; př.: 0x12F861 -> 0x016B -> 0x6C ;================================================================= (...) (...) (...) ;================================================================= COM_ACCESS_RNB ; TimeOut [ms] = (256 - "xxx") * 0.4096 BCF STATUS,RP1 CLRF TMR1L MOVLW .243 ; "xxx" MOVWF TMR1H BCF PIR1,TMR1IF BTFSS GOTO BSF RETURN BTFSS GOTO BCF RETURN
;Receive Next Byte
PIR1,RCIF $+0x03 STATUS,Z PIR1,TMR1IF $-0x05 STATUS,Z
END
- 22 -
Schémata
- 23 -
- 24 -
- 25 -
- 26 -