Prof. Ing. Jiří Tůma, CSc. Signálové procesory firmy Analog Device rodiny ADSP-21xx Signálové procesory se stále častěji objevují tam, kde se dříve používaly jen analogové obvody nebo dokonce nahrazují specializované číslicové počítače. V současné době se tyto obvodové prvky rozdělují na DSP s pevnou řádovou čárkou (Fixed-Point DSP) nebo s pohyblivou řádovou čárkou (Floating-Point DSP). V této příloze bude referováno jen o DSP s pevnou řádovou čárkou rodiny ADSP-21xx a to jen od jednoho výrobce, kterým je americká firma Analog Devices. Přehled úloh, které může DSP řešit, je v tabulce D-I, která je převzata z aplikačních poznámek [1]. V prvém sloupci je typ úlohy (Algorithm), druhý sloupec obsahuje odhad potřebné výkonnosti DSP v MIPS (Million Instruction Per Second) a třetí odhad požadavků na velikost paměti programu (PM) a paměti dat (DM) v počtech slov (word). Tab. D-I Typické úlohy pro použití DSP s odhadem potřebné rychlosti a paměti Algorithm V.32bis or V.32terbo FAX/Modem 20 Voice Music Synthesis Full Duplex Speaker Phone Digital Answering Machine GSM, 13 kbps Compression/Decompression CELP, 4.3 or 7.5 kbps Compression/Decompression MPEG Layer2, 64 kbps Compression MPEG Layer2, 64 kbps Decompression Dolby AC-2, 117 kbps Compression/Decompression
Approximate MIPS Required 16 20 13 8 4 12.5 16 10 13
Approximate RAM Required 16K words PM, 16K words DM 6K words PM, 4K words DM 2K words PM, 2K words DM 5K words PM, 1K word DM 2K words PM, 1K word DM 1.5K words PM, 1.5K words DM 5K words PM, 4K words DM 1K words PM, 8.5K words DM 4K words PM, 8.5K words DM
Architektura rodiny DSP typu ADSP-21xx Přehled jednotlivých typů DSP rodiny ADSP-21xx je v tabulce D-II. Všechny DSP mají společné jádro (21xx Core), které obsahuje 3 výpočetní jednotky (Computional Units), dva generátory adres dat (DAG - Data Address Generator #1 a #2), registr instrukcí a řadič programu (Instruction Register & Program Sequencer). Ke společnému jádru patří také blok výměny dat mezi sběrnicemi (Bus Exchange). Jednotlivé členy rodiny pak charakterizuje rozšíření (Integration). Zmíněné výpočetní jednotky tvoří aritmeticko - logická jednotka (Arithmetic/Logic Unit, tzv. ALU), násobička se střádačem (Multiply/Accumulator, tzv. MAC) a posouvač (Shifter). Tab. D-II Typy DSP rodiny ADSP-21xx Typ Data memory RAM Program Memory RAM Serial Port 0 Serial Port 1 Host Interface Port DMA Port Analog Interface Supply Voltage Instruction Rate (MIPS)
2101
2103
2105
2115
2111
2171
2173
2181
2183
1K 2K + + 5V 20
1K 2K + + 3.3V 10
512 1K + 5V 13.8
512 1K + + 5V 20
1K 2K + + + 5V 20
2K 2K + + + 5V 33
2K 2K + + + 3.3V 20
16K 16K + + + + 5V 33
16K 16K + + + + 3.3V 33
21ms p58 2K 2K + + + + 5V 26
Blokové schéma jádra (Core) rodiny procesorů ADSP 21xx a příslušné rozšíření (Integration) pro typ 2181 je na obr. D-1. 1
Obr. D-1 Architektura rodiny signálových procesorů ADSP 21xx (CORE) a provedení ADSP-2181 (Integration)
2
Formáty čísel s pevnou řádovou čárkou Číselná data mohou být v paměti počítače uložena jako čísla s pecnou řádovou čárkou (fixed point) nebo s pohyblivou řádovou čárkou (floated-point). Základní aritmetické operace signálových procesorů rodiny ADSP-21xx jsou s čísly s pevnou řádovou čárkou. Čísla mohou být zapsána v různých číselných soustavách. Pro počítače je preferována soustava dvojková s ciframi 0 a 1. Informace obsažena v datech se dělí podle jejího množství na • • •
bit (bit), 1 bit obsahuje nemenší možné množství informace (ano/ne, 1/0, zapnuto/vypnuto) bajt (byte), 8 bitů s určitým pořadím slovo (word), dva bajty s určitým pořadím.
V kódu programu se zapisují dvojková čísla tak, že před sérii nul a jedniček (jediných dvou cifer čísla) se zapíši znaky „b#“ nebo „B#“, například: b#1111101100110101 nebo B#1111101100110101 Pro vyčerpavající využití kapacity 4 bitů umožňuje zápis čísel v šestnáctkové soustavě s ciframi 0, 1, 2, …, 9, A, B, …, F. Cifra „A“ má v desítkové soustavě velikost 10 a poslední cifra „F“ velikost 15. U písmenových cifer je povoleno použití také malých písmen (a, b, …, f). Číslo o délce 16 bitů se zapíše 4 výše uvedenými ciframi následujícím způsobem 0xFB35 nebo 0xfb35 nebo h#fb35 nebo H#FB35 Pro používání pouze malých nebo velkých písmen jsou jen estetické důvody. Čísla desítkové soustavy nejsou nijak odlišena a tato čísla mají význam referenční, protože jsou nejběžnější. Signálové procesory rodiny ADSP-21xx pracují s 16bitovými čísly (slovy) s pevnou řádovou čárkou (fixed-point data). Operace s dvojitou přesností nebo s plovoucí řádovou čárkou (floating-point, například 16 bitů exponent a 16 bitů zlomková část) se musí naprogramovat. Číslo ve dvojité přesnosti se 32 bity (double precision) je uloženo ve dvou 16bitových paměťových buňkách, významnější (s větší váhou) bity jsou uloženy v jedné buňce a méně významné bity v druhé buňce. Číslo v pohyblivé řádové čárce je rozděleno na zlomkovou část nebo mantisa F a část exponentu E o základu dvě, tj. binárním základu (v angličtině také radix): ± F * 2 ±E Každá tato část je uložena ve zvláštní buňce. Přesnost čísel odpovídá v pevné řadové čárce odpovídá přesnosti A/D a D/A převodníku, který je rovněž 16bitový. Čísla mohou být bez znaménka (unsigned numbers) nebo se znaménkem (signed numbers). Čísla bez znaménka jsou pouze kladná, zatímco čísla se znaménkem mohou být obou polarit. Čísla se znaménkem jsou v procesorech ADSP 21xx ve formátu, který se nazývá dvojkový doplněk (twos-complement format). Absolutní hodnota čísel bez znaménka může tedy být dvakrát větší než u čísel se znaménkem. Pozice bitů v 16bitovém dvojkovém čísle se značí od 0 do 15, a to zprava doleva, takže jejich váha roste stejně jako v případě čísel desítkové soustavy. Bit 15 je u čísel se znaménkem nazýván znaménkový (Sign Bit) a protože má nejvyšší váhu, rozhoduje o znaménku čísla. Bit 0 je nejméně významný (Least Significant Bit - LSB) a bit 15 nejvíce významný (Most Significant Bit – MSB). Nula na místě znaménkového bitu odpovídá tedy kladným číslům a jednotka záporným číslům. Váha znaménkového bitu u dvojkových doplňků je mocnina o základu –2. Absolutní hodnota záporného čísla se nezíská odstraněním znaménkového bitu. Čísla ukládaná do paměti počítače lze rozdělit na celočíselná (integer) a racionální, která lze zapsat zlomkem, proto zlomková (fractional) 3
U čísel typu integer se znaménkem je desetinná čárka (radix point) umístěna za číslem. Signed Integer Bity Váha
15
14
13
2
1
0
15
14
13
2
2
1
2
20
2
1
0
22
21
20
-(2 )
2
2
…..
●
Další typ čísel je integer bez znaménka. Unsigned Integer Bity
15
14
13
Váha
215
214
213
…..
●
Zlomková čísla (fractional) mají myšlenou binární (radix) čárku uvnitř. Slova binární tečka u dvojkových čísel je použito ve stejném významu jako označení desetinná čárka pro desetinná čísla desítková. Formát zlomkových čísel, tj. počet bitů před binární čárkou a za binární čárkou se označuje dvojicí čísel oddělených tečkou. Signed Fractional (14.2) Bity
15
14
13
Váha
-(213)
212
211
2 22
…..
●
1
0
21
20
1
0
21
20
Unsigned Fractional (14.2) Bity
15
14
13
Váha
213
212
211
2 22
…..
●
Formát není součástí zápisu hodnoty čísla. Rozsah čísel dvou extrémních formátů v desetinné soustavě je znázorněn v následující tabulce. Formát Největší kladná hodnota Největší záporná hodnota Hodnota nejnižšího bitu (0x7FFF) (0x8000) (0x0001) 1.15
0.999969482421875
-1.0
0.000030517578125
16.0
32767
-32768
1.0
Kladná čísla formátu 1.15 jsou tedy vždy menší než 1. Záporná hodnota čísla tohoto formátu je dána součtem hodnoty spodních 15 bitů, která je vždy menší než 1 avšak nejméně 0, a hodnoty bitu s nejvyšší váhou, která je –2, proto dvojkový doplněk. Přepočet na číslo desítkové soustavy se provede nejjednodušeji tak, že váhy a cifry se nahradí jejich desítkovou hodnotou. Jestliže typ číselné soustavy je označen indexem, pak se převod uskuteční výpočtem podle následujícího příkladu: (1,0110)2 = (1*(-2)0 + 0*2-1+ 1*2-2 + 1*2-3+ 0*2-4)10 = (-0,625)10 Sčítat a odčítat lze jen čísla se stejným formátem. Násobená čísla mohou být obě se znaménkem nebo bez znaménka a nebo smíšená. Poloha desetinné čárky ve výsledku se odvodí z poloh desetinných čárek. Výsledek násobení dvou čísel ve formátu M.N a P.Q je (M+P).(N+Q). Násobením dvou 16bitových čísel se obdrží číslo s 32 bity. Součin dvou dvojkově doplňkových čísel má dva znaménkové bity, z nichž jeden je redundantní (navíc), a proto lze výsledek posunout o jeden bit doleva. Násobením dvou 4
16bitových čísel o formátu 1.15 se obdrží číslo s 32 bity ve formátu 2.30. Po posunu o jeden bit doleva se obdrží formát 1.31. Tato operace se provádí ve zlomkovém modu (fractional mode) automaticky V integer mode se tento posun neprovádí, což je užitečné při násobení čísel ve formátu 16.0. V šestnáctkové soustavě se zapisují čísla se znaménkem ve formátu 1.15 ve tvaru, který je demonstrován v následujících příkladech Formát 1.15 0x0001 0x7FFF 0xFFFF 0x8000
Číslo v desítkové soustavě 0.000031 0.999969 -0.000031 -1.000000
Signálový procesor ADSP-2181 Signálový procesor je vyroben 0.5 µm CMOS technologií. Jako obvodová součástka nemůže pracovat samostatně, ale s dalšími podpůrnými obvody, jako jsou například paměti a periferie. Obvodové schéma zapojení je na obr. XXX. Protože tento text není konstrukčním manuálem, nebudou popisovány všechny vývody této součástky, ostatně některé vývody nejsou v diagramu uvedeny. Z označení jsou však zjevné externí adresové a datové sběrnice, sériové porty, přerušovací signály, atd.. Schéma má význam v souvislosti se vstupy a výstupy procesoru, které ovlivňují jeho program a které lze přímo programově ovládat.
5
Obr. D-1 Obvodové schéma zapojení signálového procesoru a dalších podpůrných obvodů Paměť Procesor integruje 80K (K = 1024) bajtů paměti, která je rozdělena na několik částí. Signálový procesor používá modifikovanou harvardskou architekturu, ve které se data ukládají do zvláštní RAM paměti (Data Memory) a program, případně další data, do jiné RAM paměti (Programm Memory). Buňky paměti programu jsou 24bitové a kapacita paměti je 16K. V jedné buňce je jedna 24bitová instrukce. Buňky paměti dat jsou jen 16bitové a jejich počet je také 16K. Adresy buněk paměti jsou šestnáctková čísla v rozsahu od 0x0000 do 0x3FFF. Jak již bylo poznamenáno, do paměti programu lze ukládat také data, což se s výhodou požívá jednotka MAC při výpočtu součtu součinů. Příklad mapy datové a programové paměti v dále popsaném vývojovém systému EZ-KIT Lite je následující: Data Memory (DM) Data memory 32 paměťově mapovaných registrů umístěných v DM
Program Memory (PM)
Adresy 0x3FFF 0x3FE0 0x3FDF
Program Memory 8K Internal (PMOVLAY=0, MMAP=0) nebo 8K External (PMOVLAY=1 nebo 2 MMAP=0)
Internal 8160 words 8K Internal (DMOVLAY=0) nebo 8K External (DMOVLAY=1,2)
0x2000 0x1FFF
Adresy 0x3FFF
0x2000 0x1FFF
8K Internal 0x0000
0x0000
Konfigurace programové paměti je řízena vývodem MMAP (v blokovém schématu není zakreslen) integrovaného obvodu a registrem PMOVLAY. Ve zmíněném vývojovém systému je použito MMAP = 0 ze dvou možných. K dispozici je 16 352 slov (words) datové paměti jestliže DMOVLAY=0. Posledních 32 adres datové paměti obsahuje tzv. paměťově mapované registry. S těmito registry se z hlediska programování přiřazovacích příkazů pracuje jako s ostatními paměťovými buňkami. Kromě paměťově mapovaných registrů obsahuje signálový procesor ještě řadu dalších registrů, z nichž některé jsou nepřístupné zápisu nebo čtení. Jsou to registry výpočetních jednotek (ALU, MAC, Shifter a Bus Exchanger), jednotek generátorů adres (Data Address Generator) a jednotky řadiče programu (Program Sequencer). Tyto registry z hlediska programování přiřazovacích příkazů tvoří skupinu odlišnou od paměťově mapovaných registrů. K signálovému procesoru lze připojit tzv. Byte Memory (bajtovou paměť) přes Byte Memory DMA (BDMA). Adresa o 22 bitech umožňuje adresovat tuto paměť do 4 MB. S bajtovou pamětí se komunikuje (zápis/čtení) přes Byte DMA Port. Tato paměť je rozdělena na 256 stránek po 16 K 8 bitových slov, ale formát slov může být také 16 nebo 24 bitů, popřípadě 8 bitů LSM nebo MSB. K přístupu k datům je třeba znát stránku (BMPAGE), počet čtených slov (BWCOUNT) ze stránky a formát slov (BTYPE). Nejběžněji se Byte Memory používá k zavedení programu (tzv. bootování) signálového procesoru z externí paměti EPROM po resetu nebo po zapnutí napájení. Způsob zavedení (nebo také nezavedení) obsahu Byte Memory do paměti určuje kombinace logických hodnot na vývodech MMAP a BMODE procesoru. Bootovat lze také z paměti Overlay Memory nebo přes IDMA Port z host počítače.
6
DSP je připraven na použití dodatečné externí I/O paměti (I/O Memory) o 2048 paměťových místech pro potřeby paralelních periferií. K signálovému procesoru ADSP-2181 lze připojit externí paměť (OVERLAY MEMORY) složenou ze dvou 8K segmentů paměti programu a ze dvou 8K segmentů paměti dat. Tyto segmenty mohou být swapovány pro horních 8K paměti programu nebo dolních 8K paměti dat. Externí segmenty 8K paměti programu (PMOVLAY=1 nebo 2) jsou mapovány například od adresy PM(0x2000). Sběrnice DSP má pět sběrnicí, dvě sběrnice pro adresy (DMA - Data Memory Address Bus a PMA - Program Memory Address Bus), dvě sběrnice pro data (DMD - Data Memory Data Bus a PMD - Program Memory Data Bus) a pátou sběrnicí pro výstupy výpočetních jednotek (R - BUS), která nepokračuje do rozšiřující části. Datová sběrnice pro paměť dat je 16bitová a pro paměť programu 24bitová. Obě adresové sběrnice jsou 14 bitové, tj. lze adresovat 16K (K = 1024) buněk paměti. Adresové a datové sběrnice lze napojit na externí sběrnici adresovou o velikosti 14 bitů a datovou o velikosti 24 bitů. Výpočetní jednotky Procesor obsahuje tři výpočetní jednotky, které budou podrobně popsány v části popisující programování. K těmto jednotkám lze přiřadit jednotku Bus Exchange. Procesor pracuje s 30 ns instrukčním cyklem (frekvence hodinového kmitočtu je 33 MHz). Každá instrukce je provedena v jednom cyklu. Výpočetní jednotky obsahují několik registrů. Registry jsou většinou 16bitové. Počet bitů odlišný od 16 je vyznačen. Některé registry výpočetních jednotek MAC a Shifter jsou spojeny. Jedná se o registr MR u jednotky MAC a SR u jednotky Shifter. Dílčí části těchto registrů jsou však pro instrukce čtení a zápisu přístupné. Jednotkám ALU, MAC a Shifter přísluší řada příkazů, které budou probrány později. Souhrnně lze uvést, že ALU jednotka provádí operace běžné v jiných procesorech. Hlavní předností signálového procesoru je násobení s výsledkem na 32 bitů a současná akumulace (sčítání nebo odečítání) do 40bitového registru jednotky MAC. Jednotka Shift zjednodušuje bitové posuny obsahu registrů a buněk. Funkci jednotky Bus Exchanger je zprostředkovat výměnu mezi 24bitovou datovou sběrnici paměti programu a 16bitovou datovou sběrnicí paměti dat. Tato výměna probíhá je dvojím způsobem. První způsob spojení umožňuje přenášet data mezi horními 16 bity datové sběrnice paměti programů a datovou sběrnici paměti dat. Druhý způsob v spočívá ve využití 8 bitového registru PX, který může být zaplněn dolními 8 bity z každé datové sběrnice nebo ze kterého lze číst 8 dolních bitů každé sběrnice.
7
ALU AX0
MAC
AX1
AY0
AR
AF
MX0
AY1
8
16 MR2
Shifter 8 SI SR1
MY0
MY1
16
MR1
MR0
MF
BUS EXCHANGE 5
SE
MX1
8 SB
PX
SR0
Všechny registry uvedených výpočetních jednotek mají trojrozměrný stín, což znamená, že kromě primárních registrů jsou také sekundární registry. Následující instrukce přepnou na skupinu sekundárních registrů a zpět. ENA SEC_REG; DIS SEC_REG;
Všechny procesory rodiny ADSP-21xx podporují paralelismus. V jednom cyklu lze současně • generovat příští programovou adresu • připravit (fetch) příští instrukci • provést dva datové přenosy • změnit jeden nebo dva ukazatele adres • provést výpočet Ve stejném cyklu lze také • přijmout nebo vyslat data přes sériový port • přijmout nebo vyslat data přes port host procesoru • přijmout nebo vyslat data přes DMA porty Znalost hardware má význam ve spojitosti s programováním. Další popis bude tedy tyto okruhy vědomostí prolínat. Generátory adres dat DSP má dva generátory (DAG) s označením #1 a #2. V jednom cyklu lze připravit (Fetch) k výpočtu dva operandy (jeden z paměti dat a druhý z paměti programu) a jednu instrukci z paměti programu. Každý DAG udržuje a obnovuje čtyři adresové ukazatele (address pointers) s označením I. Kdykoliv je adresový ukazatel použit k přístupu k datům (tzv. nepřímému adresování) je tento ukazatel modifikován dodatečně (po vykonání operace) obsahem jednoho ze čtyř modifikačních registrů M. Další čtyři registry obsahují informaci o délce L, která může být využita k tzv. cyklickým zásobníkům (buffers). Obsah registrů lze číst nebo do nich zapisovat prostřednictvím datové sběrnice paměti dat. Všechny registry jsou 14bitové, a proto mohou pracovat s adresami až 16K paměti.
8
DAG1 (adresuje pouze DM) možnost reverzování bitů
DAG2 (adresuje PM a DM)
I0 I1 I2 I3
L0 L1 L2 L3
M0 M1 M2 M3
I4 I5 I6 I7
L4 L5 L6 L7
M4 M5 M6 M7
14 bitů
14 bitů
14 bitů
14 bitů
14 bitů
14 bitů
Možnost reverzace pořadí bitů u DAG1 se s výhodou používá k výpočtu FFT, který touto transformací ulehčuje. Protože adresy jsou jen 14 bitové, je při reverzaci zrcadlen obsah bitů podle rozhraní mezi 6. a 7. bitem, dále se vymění 5. a 8. bit až k výměně 0. až 13. bitu. Reverzace se povolí a zakáže následujícími instrukcemi. ENA BIT_REV; DIS BIT_REV;
Řadič programu DSP podporuje podmíněné skoky, volání podprogramů a návraty ze smyček. Interní čítač průchodů smyčkou a speciální odkládací zásobníky (stacks) pro smyčku umožňují jejich programování bez použití skoků. Odkládací zásobníky jsou paměťová místa s několika pozicemi, které jsou přístupné tak, že číst lze jen poslední uložený údaj a zapisovaný údaj se ukládá vždy na vrchol (top) zásobníku. Počet možných pozic se označuje jako hloubka odkládacího zásobníku. K čítači instrukcí patří několik registrů. Některé slouží k řízení přerušovacího systému: IMASK, ICNTL a IFC. Status aritmeticko-logické jednotky (ALU) je v registru ASTAT, status zásobníků (PC STACK, COUNT STACK, STATUS STACK a LOOP STACK) je obsažen v registru SSTAT a módy procesoru jsou v registru MSTAT. Na vrchol 12úrovňového odkládacího zásobníku (STATUS STACK) jsou automaticky přesunuty obsahy registrů IMASK, MSTAT a ASTAT jako součást začátku obsluhy přerušení. Registr CNTR a odkládací zásobník COUNT STACK je použit pro programové smyčky. V registru je počet aktuálních průchodů smyčkou, a proto se před instrukcí smyčky zaplní požadovaným počtem průchodů. Počet současně vykonávaných smyček je až 4. Jestliže je smyčka nedokončena, pak instrukce další smyčky přesune aktuální obsah registru CNTR na vrchol odkládacího zásobníku COUNT STACK s kapacitou čtyř 14bitových čísel. Z vrcholu tohoto zásobníku lze manuálně údaj odebrat instrukcí POP CNTR. Registr OWRCNTR slouží k přepsání počtu aktuálně vykonávaných smyček. Tento registr nelze číst a nesmí být součástí poslední instrukce smyčky. K funkci smyček patří také zásobník LOOPSTACK s hloubkou 4 pozic a šířkou 18 bitů (14 bitů pro konec smyčky a 4 bity pro podmínky jejího ukončení). Je obsluhován automaticky při zahnízdění smyček. Je však možné jeho z vrcholu zásobníku údaj sejmout (POP LOOP). Odkládací zásobník PC STACK je 14bitový a obsahuje 16 pozicí. Do tohoto zásobníku jsou ukládány návratové adresy pro případ přerušení, volání podprogramu nebo při volání smyček. Obsluha odkládacího zásobníku je automatická při přerušení a volání podprogramu. Na vrchol odkládacího zásobníku lze však přesouvat obsahy registrů na jeho vrchol (TOPPCSTACK = reg) nebo jeho poslední vložený obsah odebrat (reg = TOPPCSTACK). Odkládací zásobníky jsou použity při volání podprogramu nebo při použití smyčky.
9
PROGRAM SEQUENCER 18
5
LOOP STACK 4x18
14
ICNTL
PC STACK 16x14
16
IFC
8 SSTAT
14
OWRCNTR CNTR COUNT STACK 4x14
16
8
IMASK
8
MSTAT ASTAT STATUS STACK
Přerušovací systém: DSP má 12 úrovní přerušení od nejvyšší priority, kterou je vstup RESET , až po Timer (časovač) s prioritou nejmenší. Zdroj přerušení RESET nebo připojení napájení (nemaskovatelné) Odpojení napájení (nemaskovatelné) IRQ2 IRQL1 IRQL0 SPORT0 Transmit SPORT0 Receive IRQE BDMA Interrupt Transmit nebo IRQ1 SPORT1 Receive nebo IRQ0 Timer
Adresa vektoru přerušení 0x0000 (Nejvyšší priorita) 0x002C 0x0004 0x0008 0x000C 0x0010 0x0014 0x0018 0x001C 0x0020 0x0024 0028 (Nejnižší priorita)
Čtyři zdroje přerušení jsou externí, a to vývody integrovaného obvodu: IRQ2 , IRQL1 , IRQL0 a IRQE . Dva jsou citlivé na úroveň přerušovacího signálu ( IRQL1 , IRQL0 ) a jeden na jeho hranu ( IRQE ). Další dva externí signály pro přerušení mohou být získány konfigurací SPORT1 na vývody IRQ1 , IRQ0 , FLAG_IN a FLAG_OUT. Vnitřní zdroje přerušení pocházejí od časovače, DMA portu, dvou sériových portů a od kontrolních obvodů napájení. Přerušení s výjimkou resetu a ztrátě napájení jsou interně maskovatelná (lze je zakázat) změnou příslušných bitů registru IMASK. Význam jednotlivých bitů registru jsou zřejmé z následující instrukce
10
IMASK = b#0000000000; { |||||||||+ | ||||||||+- | |||||||+-- | ||||||+--- | |||||+---- | ||||+----- | |||+------ | ||+------- | |+-------- | +--------- | }
timer SPORT1 SPORT1 BDMA IRQE SPORT0 SPORT0 IRQL0 IRQL1 IRQ2
rec or IRQ0 trx or IRQ1 rec trx
Externí přerušovací signály IRQ2 , IRQ0 a IRQ1 lze nastavit na citlivost na hranu (edge-sensitive) signálu nebo na úroveň (level-sensitive) signálu, a to obsahem registru ICNTL. Nastavení typu citlivosti souvisí s řešením hardware zdroje přerušení vně DSP. Při použití citlivosti na úroveň signálu je potřeba po obsluze přerušení zajistit návrat přerušovacího signálu na výchozí úroveň. Vnitřní zdroje přerušení nemají v tomto registru bity pro nastavování citlivosti, protože se chovají jako citlivá na hranu. Zahnízdění (nesting) přerušení lze změnou obsahu 4. bitu tohoto registru povolit nebo zakázat. Význam jednotlivých bitů je zřejmý z demonstračních příkladů. Změnou obsahu IFC registru lze na hranu citlivá přerušení vnutit (bity 8-15) nebo tyto neobsloužené (pending) přerušení vynulovat (bity 0-7). Externím zdrojům přerušení lze toto přerušení vnutit jen pokud jsou citlivé na hranu. Implicitně jsou citlivá na hranu přerušení také od jednotky TIMER a jednotek SPORT. Vnucené přerušení se obslouží jedenkrát. Příklad vynulování přerušení je uveden v následujícím přiřazovacím příkaze: IFC = b#0000000011111111; /------//------/ { |||||||||||||||+ | ||||||||||||||+- | |||||||||||||+-- | ||||||||||||+--- | |||||||||||+---- | ||||||||||+----- | |||||||||+------ | ||||||||+------- | |||||||+-------- | ||||||+--------- | |||||+---------- | ||||+----------- | |||+------------ | ||+------------- | |+-------------- | +--------------- | }
{ vynulování přerušení } vnucení / vynulování timer SPORT1 rec or IRQ0 SPORT1 trx or IRQ1 BDMA IRQE SPORT0 rec SPORT0 trx IRQ2 vynulování přerušení timer vnucení přerušení SPORT1 trx BDMA IRQE SPORT0 rec SPORT0 trx IRQ2 vnucení přerušení
Adresy vstupních procedur ve vektoru přerušení jsou po 4 buňkách od adresy 0x0000. Jestliže lze přerušení obsloužit v těchto 4 buňkách není třeba odskoku (JUMP) do podprogramu. Velkou výhodou pro softwarovou obsluhu přerušení je zdvojení všech vstupních a výstupních registrů výpočetních jednotek. Na začátku obsluhy přerušení se lze prostě přepnout na zmíněné sekundární registry bez úklidu rozpracovaných akcí. Na konci podprogramu obsluhy přerušení je instrukce návratu RTI. Zásobníky uchovávají obsah některých registrů (stav procesoru) během obsluhy přerušení, vykonávaní smyček a vykonávání posdprogramů. STATUS STACK má 12 úrovní, aby bylo možné zahnízdění při přerušení, smyčce a podprogramu 11
Následující instrukce globálně povolí nebo zakáže obsluhu přerušení (včetně výpadku napájení) bez ohledu na obsah registru IMASK. Zákaz obsluhy se nevztahuje na autobuffering sériového portu. ENA INTS; DIS INTS;
Po resetu je obsluha přerušení vždy povolena. Sériové porty DSP obsahuje dva synchronní sériové porty (SPORT0 a SPORT1) pro sériové komunikace. Tyto porty mají následující vlastnosti • • • •
• • • •
jsou obousměrné a mají oddělené zdvojené sekce pro příjem a vysílání mohou použít vnější hodinový kmitočet ke svému řízení nebo generovat svůj vlastní (SCLK) mají nezávislé rámcování (framing) pro příjem a vysílání podporují sériový přenos dat o délce 3 až 16 bitů s kompresi a expansi (companding) podle obou norem, tj. evropské A-law a americko-japonské µ-law v souhlase s doporučením CCITT G.711 (Companding má význam v telekomunikačních aplikacích a umožňuje dosáhnout dynamického rozsahu signálu 64 nebo 72 dB (teoreticky na výstupu 12bitového převodníku, 16 bitů dovolí dynamický rozsah 96 dB) jen s daty o 8 bitech. Tento rozsah se dosáhne převodem signálu blokem s nelineární charakteristikou.) obě části, příjmová a vysílací, generují přerušení při dokončení přenosu dat mohou přijímat a vysílat obsah celého cyklického zásobníku dat, přerušení je generováno po dokončení přenosu SPORT0 má mnoho-kanálový interface pro selektivní příjem a vysílaní, u kterého je bitový tok přepínán časovým dělením SPORT1 může být konfigurován, aby pracoval se dvěma externími přerušeními ( IRQL1 , IRQL0 ) a Flag_In a Flaf_Out signály, přičemž interně generovaný hodinový kmitočet může být použit v této konfiguraci.
Blokové schéma jednoho ze dvou portů SPORTn (n=0 a 1) je na obr. XXXXX. Z hlediska programování jsou důležité pro výstup registry TX1 a TX2 a pro příjem registry RX1 a RX2 a jejich napojení na datovou sběrnici paměti dat. Signály DT a DR představují sériová výstupní a vstupní data. Signál SCLK jsou je signál hodin. Signály TFS a RFS jsou pro synchronizaci rámců dat. Oba sériové porty jsou velmi univerzální a prostřednictvím paměťově mapovaných registrů mohou různě konfigurovány. Sériový port SPORT0 má registry v úseku adres datové paměti 0x3FF3 až 0x3FFA a SPORT1 v úseku adres stejné paměti 0x3FEF až 0x3FF2.
12
16
DMD Bus 16
16
TXn Transmit Data Register
Companding Hardware
RXn Receive Data Register
16
16
Transmit Shift Register
Serial Control
Receive Shift Register
Internal RFS Serial SCLK Clock DR Generator
TFS DT
Obr. D-1 Blokové schéma sériového portu Před prvním použitím musí být sériové porty zkonfigurovány. Konfigurace se týká následujících nastavení • • • •
SPORT ENABLE, přístupnost portu se nastavuje v registru System Control Register DM(0x3FFF) SERIAL CLOCKS, zdroj hodinového kmitočtu (interní/externí) se u portu SPORT0 nastaví v registru SPORT0 Control Register DM(0x3FF6) a u portu SPORT1 v registru SPORT1 Control Register DM(0x3FF2) SCLK FREQUENCY, frekvence taktu pro sériový port je zlomkem hodinové frekvence procesoru, faktor pro dělení SCLKDIV je pro SPORT0 obsahem DM(0x3FF5) a pro SPORT1 obsahem DM(0x3FF1) WORD LENGTH, délka slova může být od 3 do 16 bitů, nastaví se u portu SPORT0 v registru SPORT0 Control Register a u portu SPORT1 v registru SPORT1 Control Register
WORD FRAMING OPTIONS (týká se tzv. framing signálů k identifikaci prvního bitu přenášeného slova, nastaví se u portu SPORT0 v registru SPORT0 Control Register a u portu SPORT1 v registru SPORT1 Control Register). • • • •
FRAME SYNCHRONIZATION, určuje, zda je framing signál potřebný jen u prvního přenášeného slova nebo u každého slova FRAME SYNC SIGNAL SOURCE, zdroj synchronizačního signálu NORMAL AND ALTERNATE FRAMING MODES, týká se způsobu kontroly framing signálu ve vztahu ACTIVE HIFH OR ACTIVE LOW, týká se úrovně, při které je framing signál aktivní
COMPANDING AND DATA FORMAT, nastavení komprese nebo dekomprese a formátu dat, nastaví se u portu SPORT0 v registru SPORT0 Control Register a u portu SPORT1 v registru SPORT1 Control Register. Čtení nebo zápis dat do sériového portu lze naprogramovat tak, že se provádí po jednotlivých slovech nebo v celých blocích. Příklad čtení jednotlivých slov je následující: TX1 = AX0; AYO = RX0;
{obsah AX je vyslán na port SPORT1} {obsah RX0 v SPORT0 je přenesen do AY0}
13
Druhý příkaz je vykonán jako obsluha přerušení, které SPORT0 generuje při přijetí celého slova. Druhý zmíněný způsob programování se týká celých bloků dat a nazývá se Autobuffering. Data jsou přenášena přímo mezi pamětí a registry sérového portu. I když přenos nelze popsat přímo instrukcemi, princip je přibližně ekvivalentní instrukcím dm(I,M) = RX0; TYO = dm(I,M);
{příjem} {vysílání}
Přerušení jsou generována až po přenosu celého bloku. Toto přerušení nelze znepřístupnit jako některá přerušení. Autobuffering užívá cyklických zásobníků a generátoru adres. Konfiguruje se pro SPORT0 v registru SPORT0 Autobuffer Control Register DM(0x3FF3) a pro SPORT1 v registru SPORT1 Autobuffer Control Register DM(0x3FEF). V těchto paměťově mapovaných registrech jsou přiřazeny registry generátorů adres. Sériový port SPORT0 podporuje mnoho-kanálový přenos dat. Jednotlivé kanály jsou ovšem časově dělené, tj. data se vysílají/přijímají postupně. Příslušnost ke kanálu je dána pořadím přenášeného slova v bloku. Kanálů může být celkem 24 nebo 32 a na kterýkoliv z nich se lze selektivně zaměřit a ignorovat ostatní kanály. Mnoho-kanálový přenos se konfiguruje v registru SPORT0 Control Register. Používání sériového portu a jeho konfigurace bude demonstrována na zvláštním příkladu v jiném místě textu. IDMA Port Internal DMA Port je paralelní vstupní a výstupní port, který umožňuje host počítači přímé čtení z paměti signálového procesoru a také přímý zápis do této paměti s výjimkou paměťově mapovaných registrů paměti dat. Přímo připojený host počítač může být například Motorola 68000 nebo Intel 8051 a nebo kterýkoliv DSP z rodiny ADSP-21xx. Přístup do paměti DSP z host počítače je úplně asynchronní a bez asistence ADSP-2181. IDMA Port má 16bitovou adresovou a datovou sběrnici, po které lze vyměňovat data mezi paměti programu nebo dat a host počítačem. Funkce IDMA Portu se řídí 4 vývody, které jsou pro DSP vstupy. Jestliže se data čtou nebo zapisují prostřednictvím IDMA datové sběrnice, pak adresa paměti dat nebo programu je obsažena v registru s názvem IDMA Control Register, který je mapován v paměti dat na adrese DM(0x3FE0). Tato adresa je 14bitová, 15. bit registru určuje zdá výměna dat probíhá mezi paměti dat nebo paměti programu a IDMA datovou sběrnicí. Časovač (Timer) Procesor má rovněž 16bitový časovač (Timer) s tzv. prescalerem k násobnému zvětšení počtu cyklů nad rozsah 16bitového čísla. Vlastní čítač je postupně dekrentovaný registr TCOUNT, který po dosažení nuly generuje přerušení se současným obnovením výchozí hodnoty z registru TPERIOD. Dekrementování je v každém instrukčním cyklu jestliže obsah registru TSCALE (zmíněný prescaler) je nulový. Jestliže je registr TSCALE nenulový, např. n, pak dekrementace se opakuje až po n+1 cyklech procesoru. Zmíněné tři registry časovače, z nichž dva jsou 16bitové a jeden (TSCALE) 8bitový, jsou umístěny (mapovány) v datové paměti. Timer Registers 15 14 13 12 11 10
9
8
7
6
5
4
3
14
2
1
0
Registr
Místo v paměti
TPERIOD
DM(0x3FFD)
TCOUNT
DM(0x3FFC)
0
0
0
0
0
0
0
0
TSCALE
DM(0x3FFB)
Časovač lze zpřístupnit nebo zakázat instrukcemi ENA TIMER; DIS TIMER;
Časovač lze zpřístupnit/zakázat nastavením/nulováním 5. bitu registru MSTAT.
Programování signálového procesoru rodiny ADSP 21xx Programování signálového procesoru se opírá o jazyk, který je označován jako asembler. Tento jazyk je mnohem dokonalejší než běžný asembler počítačů třídy PC. Jeho omezení jej vylučuje z rodiny vyšších programovacích jazyků jako C, Pascal apod.. Jako v asembleru se používají návěští a identifikátory. Snadné je použití přiřazovacích aritmetickologických příkazů se zápisem srovnatelným s jazykem C, dále použití instrukcí skoku a cyklu (smyčky), volání podprogramu nebo návrat z podprogramu a návrat z obsluhy přerušení. Řada instrukcí může být podmíněna. Zmíněná omezení úzce souvisí s architekturou signálového procesoru, proto popis instrukcí se bude opírat o blokové zapojení jednotlivých výpočetních jednotek. Výhodou asembleru je především to, že všechny operace jsou pod kontrolou, a proto je některými programátory oblíben. Kromě asembleru lze pořídit překládač z jazyka C (C Compiler). Překládač čte zdrojový kód v normě ANSI C. Při popisu syntaxe instrukcí je použito konvence, podle které hranaté závorky [ ] značí nepovinnou část instrukce a výběr z alternativ je ve sloupci se závorkami . Zápis programů není citlivý na použití velkých a malých písmen. Komentáře (poznámky) Struktura programu obsahuje část deklarace s různými direktivami pro překlad a část instrukcí. Komentáře se uzavírají mezi závorky { … } nebo /* … */ a mohou přesahovat přes několik řádek. Instrukce Jedna instrukce obsazuje jedno paměťové místo (24 bitů) v paměti programu, tj. její přeložený kód obsadí jednu buňku paměti jako při použití jazyka C. Instrukce se provádí v jednom taktu (cyklu) procesoru odvozeného od hodinové frekvence. Žádná instrukce není rozložena na více taktů jako v případě některých jiných procesorů. Toto pravidlo umožňuje odhadnout rychlost provádění programu na základě sečtení počtu prováděných instrukcí. Instrukce se ukončuje středníkem nebo některé také čárkou. V případě, že se během jednoho taktu vykonává jedna instrukce, pak se ukončuje středníkem, tj. instrukce ; Protože procesor podporuje paralelismus, některé instrukce se mohou vykonávat současně v jednom taktu procesoru, a to jen v určitém pořadí. Tyto instrukce se oddělují čárkami, přičemž poslední instrukce takto sdružených instrukcí je zakončena středníkem, tj.například instrukce1, instrukce 2, instrukce3 ; Takto sdružené instrukce mohou být až tři, z nichž je jedna výpočetní a dvě pro přípravu operandů s využitím generátorů adres DAG1 a DAG2. V dokumentaci se nazývají multifunkční.
15
Identifikátory Pro identifikátory (jména proměnných) nespecifikují příručky žádná výjimečná pravidla. Platí stejné zásady jako u ostatních programovacích jazyků, např. C. Protože se identifikátory nepoužívají v aritmeticko-logických operacích, jsou to jen jména paměťových míst (buněk), které jsou při popisu nahrazena
. Příklad jména proměnné je var_name nebo buffer_name. Další použití identifikátoru je v návěštích (label). Klasické označení pole nebo indexovaná proměnná se v programátorské příručce nepoužívá, tato označení jsou nahrazena označením zásobník (buffer). Jestliže data představují zásobník, pak jeho identifikátor, např. buffer_name, je název první buňky s prvním prvkem zásobníku. Další prvek je umístěn v buňce s názvem zvetšeným o jednotku, tj. pro uvedený příklad buffer_name+1. Třetí prvek zásobníku je uložen v buňce buffer_name+2, atd.. Data Data jsou v popisu instrukcí označována . Při respektování rozsahu čísel daných 16 bity lze data zapsat ve dvojkové, desítkové nebo šestnáctkové soustavě. Při operacích v jednotce ALU je jejich formát 16.0. Jednička může být tedy zapsána těmito ekvivalentními způsoby b#0000000000000001 nebo 1 nebo 0x0001 nebo h#0001 Při operacích v jednotce MAC záleží na módu procesoru. V integer mode jsou předpokládána ve formátu 16.0, zatímco ve fractional mode jsou ve formátu 1.15. Jméno buňky se mění na data předsunutím znaku „^“ nebo „%“. Význam těchto znaků demonstrovaný na příkladu je následující ^buffer_name
označuje adresu buňky, tj. její pořadí od začátku paměti s první buňkou o adrese 0x0000 (znak má v jazyku C význam ukazatele – pointeru)
%buffer_name
označuje délku deklarovaného zásobníku (pole) – viz dále
Tato možnost je používána pro přiřazování hodnot registrům I a L z DAG1 a DAG2. Přiřazovací příkaz Tento příkaz obsahující rovnítko (=) podstatně usnadňuje a zpřehledňuje programování signálového procesoru oproti klasickému asembleru, avšak jeho použití je silně omezeno. Vzájemně lze přiřazovat, tj. přenášet data, jen tehdy, jestliže mezi jejich zdrojem a příjemcem je přímé hardwarové spojení. Možnosti přenosu dat jsou pro následující •
obsah registru lze přenést do jiného registru (oba registry se předpokládají paměťově nemapované) v jednom taktu procesoru
•
data z paměti dat lze číst do všech paměťově nemapovaných registrů a opačně paměť dat lze plnit obsahy těchto registrů v jednom taktu procesoru
•
jen některé registry výpočetních jednotek (ALU, MAC a Shifter) mohou využít generátorů adres pro čtení a zápis (jedná se o registry AX0, AX1, AY0, AY1, AR, MX0, MX1, MY0, MY1, MR0, MR1, MR2, SI, SE, SR0 a SR1), přičemž paměť programu je dostupná jen u DAG2
•
daty lze plnit přímo jen paměťově nemapované registry, paměť lze daty plnit jen prostřednictvím paměťově nemapovaných registrů, tj. ve dvou taktech procesoru.
16
Omezení tedy spočívá v nemožnosti v jednom přiřazovacím příkaze zaplnit některou buňku paměti a nebo uskutečnit přenos přímo mezi buňkami paměti. Tyto operace je třeba uskutečnit například pomocí registrů výpočetních jednotek. S obsahem paměťově mapovaných registrů v paměti dat se pracuje jako s ostatními buňkami paměti. Například zaplnění paměťově mapovaného registru v paměti dat na adrese 0x3FF2 obsahem 0x6B27 se vykoná například prostřednictvím registru AX0 AX0 = 0x6B27; dm(0x3FF2) = AX0;
{naplnění registru AX0 žádaným obsahem} {přepis obsahu registru AX0 do žádané buňky}
Písmena dm označují paměť dat a písmena pm by označovala paměť programu. Přímé a nepřímé adresování paměti Signálový procesor využívá nepřímé adresování pomocí registrů I generátorů adres (Data Address Generators, tzv. DAGs). Tyto registry se nazývají také indexregistry. Rozdíl mezi nepřímým a přímým adresováním lze nejlépe demonstrovat na příkladu. Nechť je deklarován zásobník o 256 buňkách se jménem coefficients v paměti programu. Toto jméno lze považovat rovněž za název paměťových míst této paměti. .var/pm/ram
coefficients[256];
Příkladem přímého adresování je například načtení prvního koeficientu do libovolného registru, který není paměťově mapován, tj. například MX0 MX0 = pm(coefficients);
{příklad přímého adresování}
Načtení druhého koeficientu do registru téhož registru se uskuteční příkazem MX0 = pm(coefficients+1);
{příklad přímého adresování}
Pro příklad použití nepřímého adresování nechť je deklarována jiná proměnná se jménem addr_ptr. .var/dm/ram
addr_ptr;
Jak bylo uvedeno, přímým adresováním lze načíst obsah buňky se jménem addr_ptr do libovolného paměťově nemapovaného registru. Mezi paměťově nemapované registry patří také registry generátoru adres DAG, tj. například registr I3 I3 = dm(addr_ptr);
{příklad přímého adresování}
Jak je v části popisující cyklické zásobníky uvedeno, je třeba, aby byl definován rovněž obsah registru L3 (příslušejícího k I3) a obsah některého z registrů M0 až M3, například M1 L3 = 0; M1 = 0;
Nepřímé adresování paměťových buněk znamená použití adresy obsažené v registru I. Například čtení z paměti dat do registru AX0 se uskuteční instrukcí AX0 = dm(I3);
Cyklické a lineární zásobníky (buffers) Specialitou signálového procesoru jsou cyklické a lineární zásobníky hodnot, které mají hlavní uplatnění ve zpožďovacích linkách. Funkce zásobníků přímo souvisí generátory adres. Hlavní význam obou zásobníků spočívá v automatické modifikaci adresy, jejíž obsah byl čten nebo měněn. Toto umožňuje následující operaci s další buňkou paměti bez opravy ukazatele na její adresu. Pro tyto zásobníky je třeba nastavit nejprve adresu první buňky zásobníku do 17
některého registru I, dále je třeba nastavit délku zásobníku (počet prvků pole) do registru L a také do registru M zadat o kolik se má aktuální adresa modifikovat. Výběr kombinace registrů musí odpovídat jednomu DAG, ale v rámci něj se čísla registrů I, L a M mohou lišit. Nechť adresa první buňky (base address) cyklického registru je B, pak adresa pro příští paměťovou operaci, uložená v registru I, je dána vztahem: příští adresa = (I + M – B) kde „modulo“ znamená zbytek po dělení. Z cyklického zásobníku jsou postupně vybíraná (ukládaná) data a při dosažení konce zásobníku je automaticky pokračováno od jeho počátku znovu. Obsah registru M tedy určuje o kolik buněk dopředu (kladný obsah M) nebo dozadu (záporný obsah M) se má příští paměťová operace posunout. Zvláště důležité je nezapomenout na přiřazení hodnoty délky v registru L se stejným pořadím jako má registr I. Jestliže je L = 0, pak je zásobník lineární, což znamená, ze adresa je podle obsahu M inkrementována nebo dekrementována k hranicím fyzické paměti a funkce programu se zhroutí. Jak je patrné z výčtu direktiv překládače, cyklický zásobník je třeba deklarovat. Například deklarace zásobníku s názvem (jménem) rx_buf pro 3 čísla v datové paměti (dm) paměti RAM (ram) je následujícím způsobem .var/dm/ram/circ
rx_buf[3];
Počáteční přiřazení obsahů vybraných registrů I, L a M je následující I6 = ^rx_buf; L6 = %rx_buf; M7 = 1;
Cyklické zásobníky spolu s instrukcemi pro smyčky jsou zvláště výhodné pro programování zpožďovacích linek, které jsou součástí číslicových filtrů. Každé čtení nebo zápis vede k automatické modifikaci na další buňku bez psaní dalších příkazů. Inicializace proměnných a zásobníků Inicializací se rozumí přiřazení počátečních hodnot. Toto lze vykonat buď přiřazovacím příkazem nebo zvláštní direktivou .INIT. Hodnotu výše deklarované proměnné addr_ptr obsahující adresu konce datové nebo programové paměti lze zajistit direktivou .init addr_ptr: 0x3FFF;
Nulování obsahu zásobníku rx_buf s 3 buňkami je možné provést direktivou .init rx_buf: 0x0000, 0x0000, 0x0000;
nebo také jejich opakováním, což je výhodné pro velké zásobníky .init rx_buf[0]: 0x0000; .init rx_buf[1]: 0x0000, 0x0000;
Výpis obsahu všech 256 buněk zásobníku coefficients by bylo nepraktické. Výhodné v tomto případě je vytvoření textového souboru například se jménem Koeficienty.dat, který obsahuje hodnoty pro zaplnění tohoto zásobníku. Inicializace se pak provede direktivou .init coefficients: ;
18
Zásobník coefficients je deklarován v paměti programu a může být použit například pro výpočet součtu součinů hodnot z tohoto zásobníku se stejně dlouhým zásobníkem v paměti programu. Pro tuto operaci je určena jednotka MAC. Paměť programu však obsahuje buňky se 24 bity, ze kterých lze využít jen horních (více významných) 16 bitů. Textový soubor je proto třeba zaplnit údaji pro všech 24 bitů. Do dolních 8 bitů se proto dosadí nuly. Několik řádků toho souboru s čísly v šestnáctkové soustavě může vypadat takto: … 02E100 010400 FF1600 FD4B00 …
Čísla jsou bez znaků „0x“, poslední dvě nuly odpovídají dolním 8 bitům buněk paměti programu. V případě, že by se plnila paměť dat, pak řádky obsahují jen 4 cifry šestnáctkového čísla. Direktivy pro překlad K ovládání překladu slouží tzv. direktivy, které se odlišují od instrukcí tím, že na řádku začínají tečkou. Direktivy se neprojeví v přeloženém programu jako samostatný kód. Nejpoužívanější direktivy jsou popsány v následující tabulce: Direktivy asembleru .MODULE/qualifier/qualifier … module_name; {první řádek zdrojového textu modulu, kvantifikátory vysvětleny v další tabulce} .PAGE; .CONST constant_name=expresion; {definuje identifikátor symbolické konstanty výrazem, nejběžněji přímo konstantou } .VAR/qualifier/qualifier buffer_name[length], ... ; {deklarace proměnných a zásobníků (polí). U zásobníků je vyznačena délka length } .INIT buffer_name: init_value1, init_value1, ... ; {inicializace deklarovaných proměnných a obsahu zásobníků konkrétními hodnotami} .GLOBAL buffer_name ... ; {Atribut proměnných, zásobníků a portů, na které bude odvoláváno v jiných modulech} .ENTRY program_label ... ; {Atribut návěští, na které bude odvoláváno v jiných modulech} .EXTERNAL external_symbol; {Označuje proměnné, porty a návěští z jiných modulů, na které bude odkazováno. V těchto modulech musí být v modulech, kde jsou deklarovány, atributy .ENTRY (návěští) nebo .GLOBAL (proměnné a porty)} .PORT port_name; {Deklaruje paměťově mapovaný V/V port v RM nebo DM. Symbolické jméno musí být jméno portu deklarované v souboru popisu architektury (ADSP2181.ACH).} .INCLUDE ; {V tomto místě je kód programu rozšířen o obsah textového souboru, používá se pro společné konstanty} .DMSEG dmseg_name; .MACRO macro_name(param1,param2, ...); .ENDMACRO; .LOCAL macro_label, ...; .NEWPAGE; {Vloží přechod na novou stránku v .LST souboru} .PAGELENGTH #lines; { Vloží novou stránku v .LST souboru po lines řádků} .INDENT #columns; {Odsazení o columns sloupců v .LST souboru} .PAGEWIDTH #columns; {Nastavení pravého okraje na columns sloupců} 19
.ENDMOD; {poslední řádek ve zdrojovém textu modulu} Kvantifikátory jednotlivých direktiv jsou následující: .MODULE qualifiers:
RAM, ROM {paměť RAM nebo ROM} ABS=address {absolutní startovací adresa, nepoužívejte se STATIC} SEG=seg_name {absolutní startovací adresa, nepoužívejte se STATIC} STATIC
.VAR qualifiers:
PM, DM {paměť programu nebo dat} RAM, ROM {paměť RAM nebo ROM} ABS=address {umístění v paměti, nepoužívejte se STATIC} CIRC {cyklický zásobník} STATIC
.INIT qualifiers:
constant, constant, ... {konstanty} {jméno textového souboru, který je jakoby vložen na tomto místě} ^other_buffer {adresa jiného zásobníku} %other_buffer {délka jiného zásobníku}
Při psaní kódu programu lze použít také direktivy preprocesoru (Assembler C Preprocessor Directives). Jejich použití dovoluje komponovat zdrojový kód z různých části a podmíněně vykonávat překlad. V textu zdrojového kódu se nejčastěji objevují jen direktivy #define a #include. #define macro_name(param1,…) expresion # undef macro_name #include “filename” #if expression #else #endif #ifdef macro_name # ifndef macro_name #else #endif
Definuje macro Oddefinuje macro Vloží text z jiného zdrojového souboru Podmíněně vloží a překládá v závislosti na logické hodnotě expression pro případ, že předcházející test if expression neuspěje Podmíněně vloží a přeloží, jestliže je macro definováno s #define nebo přepínačem –d Podmíněně vloží a přeloží, jestliže je macro není definováno pro případ, že předcházející #ifdef nebo #ifndef neuspěje
Registry Funkce signálového procesoru je řízená obsahem registrů (Control Registers). Do registrů se rovněž zaznamenává stav procesoru (Status Registers). Registry jsou buď mimo paměť (DM a PM) nebo jsou součástí paměti dat, pro které je určeno 32 buněk s nejvyššími adresami u 16K datové paměti (DM). Některé registry jsou pro čtení a zápis, některé jen pro čtení (read only) nebo jen pro zápis (write only). Registry mimo datovou paměť jsou ASTAT 20
SSTAT (read only) MSTAT ICNTL IMASK IFC (write only) CNTR OWRCNTR (write only) Pokud je to povoleno, pak se s obsahem registrů zachází stejně jako s registry např. jednotky ALU (viz instrukce přesunu dat). Jako součást datové paměti je následujících 24 paměťově mapovaných registrů, které jsou deklarovány jako konstanty s hodnotami adres : Název registru IDMA BDMA_BIAD BDMA_BEAD BDMA_BDMA_Ctrl BDMA_BWCOUNT PFDATA PFTYPE SPORT1_Autobuf SPORT1_RFSDIV SPORT1_SCLKDIV SPORT1_Control_Reg SPORT0_Autobuf SPORT0_RFSDIV SPORT0_SCLKDIV SPORT0_Control_Reg SPORT0_TX_Channels0 SPORT0_TX_Channels1 SPORT0_RX_Channels0 SPORT0_RX_Channels1 TSCALE TCOUNT TPERIOD DM_Wait_Reg System_Control_Reg
Jednotka IDMA Port IDMA Port IDMA Port IDMA Port IDMA Port IDMA Port IDMA Port SPORT1 SPORT1 SPORT1 SPORT1 SPORT0 SPORT0 SPORT0 SPORT0 SPORT0 SPORT0 SPORT0 SPORT0 TIMER TIMER TIMER
Místo v paměti DM(0x3FE0) DM(0x3FE1) DM(0x3FE2) DM(0x3FE3) DM(0x3FE4) DM(0x3FE5) DM(0x3FE6) DM(0x3FEF) DM(0x3FF0) DM(0x3FF1) DM(0x3FF2) DM(0x3FF3) DM(0x3FF4) DM(0x3FF5) DM(0x3FF6) DM(0x3FF7) DM(0x3FF8) DM(0x3FF9) DM(0x3FFa) DM(0x3FFb) DM(0x3FFc) DM(0x3FFd) DM(0x3FFE) DM(0x3FFF)
Obsahy těchto registrů jsou přístupné operacemi čtení a zápisu do paměti, které jsou popsány dále (viz instrukce přesunu dat). Všechny tyto deklarace lze vložit do deklarační části kódu programu pomocí direktivy .INCLUDE z textového souboru, který je součástí software (CONSTANT.K), tj.: .INCLUDE Význam jednotlivých bitů v registrech je zřejmý z demonstračních příkladů, tj. z míst jejich bezprostředního použití. S 8bitovým registrem ASTAT se čtenář setká při popisu instrukcí ALU jednotky. Žádný demonstrační příklad nemanipuluje s bity také 8bitového registru SSTAT, který je určen jen ke čtení, a proto význam jeho bitů je uveden v tomto místě.
21
ASTAT = b#00000000; { |||||||+ | ||||||+- | |||||+-- | ||||+--- | |||+---- | ||+----- | |+------ | +------- | }
AZ AN AV AC AS AQ MV SS
SSTAT = b#01010101; { |||||||+ | ||||||+- | |||||+-- | ||||+--- | |||+---- | ||+----- | |+------ | +------- | }
PC Stack Empty PC Stack Overflow Count Stack Empty Count Stack Overflow Status Stack Empty Status Stack Overflow Loop Stack Empty Loop Stack Overflow
ALU Result Zero ALU Result Negative ALU Overflow ALU Carry ALU X Input Sign ALU Quotient MAC Overflow Shifter Input Sign
read-only
Instrukce výpočetních jednotek DSP rodiny ADSP 21xx Instrukce výpočetní jednotky ALU Jednotka ALU provádí aritmetické a logické operace dvěma vstupními operandy X a Y z množiny přípustných registrů a výsledek ukládá do 16bitového registru AR nebo AF. Operand X může být vybrán z jednoho ze dvou 16bitových registrů AX0 a AX1 jednotky ALU, ale také z jejího výstupního registru AR, popřípadě z registrů MR0, MR1 nebo MR2 jednotky MAC nebo z registrů SR0 a SR1 jednotky Shifter. Operand Y zase může být vybrán jen z registru AY0, AY1 a AF jednotky ALU. Druhý operand může být povolená konstanta typu integer a nebo tzv. přenos (carry-bit). Jsou přípustné operace s jedním operandem. V instrukcích se tedy nepoužívají libovolné identifikátory. Před operaci v ALU je tedy třeba příslušné registry zaplnit daty paměťovými operacemi nebo přesunem z jiného registru. Přehled jednotlivých instrukcí výpočetní jednotky ALU je následující R=X+Y R=X-Y R=Y-X R=-X R=-Y R = X + Y + CI R = X - Y + CI - 1 R = Y - X + CI - 1 R=Y+1 R=Y-1 R = PASS X R = PASS Y R = 0 (PASS 0) R = ABS X R = X AND Y R = X OR Y R = X XOR Y R = NOT X R = NOT Y Poznámka: CI je přenos (carry-bit), PASS znamená přenos s nastavením statusu ALU jednotky (registr ASTAT) Zdrojové registry a registry pro výsledek jsou následující X input port Y input port R output port AX0, AX1 AY0, AY1 AR AR AF AF MR0, MR1, MR2 konstanta SR0, SR1
22
Pro operaci sčítání a odčítání může být druhý operand rovněž určitá hodnota konstanty, a to hodnoty 0, 1, 2, 4, ...(mocniny dvou až do16384), 32767, -2, -3, -5, -9, ...(mocniny dvou + 1 do –19385), -32768. Pro logické operace a operaci PASS může být druhý operand roven také mocnině dvou zmenšené nebo zvětšené o jedničku. ALU Status je obsažen v ASTAT registru, jehož bity jsou nastaveny za následujících podmínek AZ (Zero) AN (Negative) AV (Overflow) AC (Carry) R=0 R<0 přetečení přenos
AS (Sign) znaménko X
AQ (Quotient) quocient
ALU jednotka provádí také dělení, pro které jsou dvě instrukce DIVS Y, X; DIVQ X; kde operandy X a Y jsou v registrech stejných jako pro sčítání a odčítání. Dělení s jednoduchou přesností má dělence o délce 32 bitů a dělitele o délce 16 bitů. Výsledkem 16 cyklů výpočtu je 16bitový podíl (kvocient). Dělení může být se znaménkem nebo bez znaménka s podmínkou, že oba operandy jsou stejného typu. Horní polovina dělence (operand Y), 16 více významných bitů, se umístí do registru AY1 nebo AF a dolní polovina do registru AY0. Dělitel se umísti do libovolného registru přípustného pro operand X. Opakované provádění instrukce DIVQ implementuje sčítání/odečítání s výsledkem uloženým v registru AY0. Dělení se znaménky znamená první vykonání instrukce DIVS pro určení znaménka a pak 15 opakování instrukce DIVQ. Při dělení bez znamének je třeba horní polovinu operandu umístit v registru AF, pak nastavit na nulu bit AQ v registru ASTAT, což indikuje kladné znaménko výsledku. Pak následuje opakování instrukce DIVQ tolikrát, kolik je bitů v kvocientu. Bity kvocientu generované při každé instrukce DIVQ jsou uloženy v bitu AQ registru ASTAT. Výsledný zbytek produkovaný tímto algoritmem nemá platnou hodnotu a musí být korigován. Dělení je složitá operace, pro kterou je vhodné použít výrobcem sestavený podprogram, který bude popsán v jiném místě. Poslední instrukcí jsou operace s jednotlivými bity Y = TSTBIT n z X
operace AND s 1 v bitu n operandu X
Y = SETBIT n z X
operace OR s 1 v bitu n operandu X
Y = CLBIT n z X
operace AND s 0 v bitu n operandu X
Y = TGBIT n z X
operace AND s 0 v bitu n operandu X
Povolené hodnoty pro n jsou 0, 1, …, 15, operand X může být jeden z registrů jako při operaci sčítání a odečítání.
23
PMD BUS
24
DMD BUS
16
Instrukce bez výsledku je 16 (UPPER)
kde ALU je libovolný přiřazovací příkaz s výjimkou DIVS a DIVQ. Tato instrukce dovoluje otestovat bity stavového registru ASTAT bez ovlivnění obsahu registrů AR a AF.
MUX
AX REGISTERS 2 x 16
AY REGISTERS 2 x 16
16
16 MUX
AZ AN AC AV AS AQ
MUX
X
AF REGISTER
Y
ALU
Všechny operace mohou být podmíněny, tj. mohou začínat IF cond instr;
CI
kde cond je některá ze 17 dále popsaných podmínek a instr je některá povolená instrukce.
R 16 16
Blokové schéma jednotky ALU je na obr. D-II. Spojení jednotlivých bloků zdůvodňuje výpočetní operace. Registry s prostorovým stínovým orámováním jsou zdvojeny, jak již bylo zmíněno při popisu obsluhy přerušení.
MUX
AR REGISTER
16
NONE = ,
R - BUS
Obr. D-II Blokový diagram výpočetní jednotky ALU Přehled všech instrukcí je v následující tabulce, ve které cond znamená podmínku a X s Y výše popsané operandy. Přehled „podmínek“ instrukce IF je na konci kapitoly. Y AR CI [IF cond] AF = X + Y + CI ; Sčítání nebo sčítání s přenosem kons tan ta Y = X - Y + CI − 1 ; kons tan ta
Odečítání X-Y nebo odečítání s přenosem
X = Y - X + CI − 1 ; kons tan ta
Odečítání Y-X Y nebo odečítání s přenosem
AND = X OR Y; XOR
AND, OR, XOR
X = PASS Y ; Přiřazení s nastavením registru ASTAT kons tan ta
24
X =−Y ;
Negace
X = NOT Y ; 0
NOT
= ABS X ; =Y+1; =Y–1; = DIVS Y, X ; = DIVQ Y ; TSTBIT n z X SETBIT n z X = ; CLBIT n z X TGBIT n z X NONE
Absolutní hodnota Inkrementováni Y Dekrementování Y Dělení Dělení Operace s bity
= ALU
Instrukce výpočetní jednotky MAC Jednotka MAC provádí aritmetické operace se dvěma vstupními operandy X a Y z určitých registrů a výsledek přičítá k obsahu registru MR. Registr MR je 40bitový a je rozdělen na tři části: 40
32 31
16 15
0
MR2
MR1
MR0
Overflow
Most Significant 16 Bits
Least Significant 16 Bits
Operand X může být vybrán z jednoho ze dvou 16bitových registrů MX0 a MX1 jednotky MAC, ale také z jejich registrů MR0, MR1 nebo MR2, popřípadě z registru AR jednotky ALU. Operand Y zase může být vybrán jen z registru MY0, MY1 a MF jednotky MAC. Výsledek výpočtu je umístěn buď v registru MR nebo v 16bitovém registru MF. Stejně jako jednotka ALU není použit v instrukci libovolný identifikátor. Před operaci s data v MAC je třeba příslušné registry zaplnit vstupními daty. Přehled jednotlivých instrukcí výpočetní jednotky MAC je následující X*Y MR + X * Y MR - X * Y 0
násobení X a Y operandu s uložením výsledku do MR registru násobení X a Y operandu a přičtení výsledku k MR registru násobení X a Y operandu a odečtení výsledku od MR registru nulování MR registru
Všechny výpočty mohou být podmíněné (IF) nějakou podmínkou. Při násobení lze pracovat ve dvou modech, a to fractional mode pro čísla formátu 1.15 nebo v integer mode pro čísla formátu 16.0, tj. bez desetinné čárky. V prvém případě je výsledek ve formátu 1.31 a ve druhém 32.0. Tato vlastnost je výhodná pro softwarové ošetření výpočtů v pevné řádové čárce, ale s dvojnásobnou přesností, při které jsou jedním číslem obsazovány dvě paměťová místa po 16 bitech. Protože v tomto případě jen jedno ze dvou uložených čísel obsahuje znaménkový bit, je třeba při postupném násobení čísel s dvojitou 25
přesností vyznačit typ násobení, tj. zda je se znaménkem (signed) nebo bez (unsigned). Typ násobení se vyznačuje za instrukcí některou z dvojic čísel ( SS), (US), (SU) a (UU). Jestliže se výsledek mezi 15. a 16. bitem pouze zaokrouhlí (round), označí se instrukce (RND). Podobně je to v případě, kdy je výsledek ukládán v 16bitovém registru MF. Zaokrouhlení může být nevychýlené (unbiased) nebo vychýlené (biased). Volba módu zaokrouhlování je dána hodnotou BIASRND bitu, který je 12. bit SPORT0 Autobuffer Control Registru. Formát vstupních dat X input port Y input port signed signed unsigned signed signed unsigned unsigned unsigned PMD BUS
24
DMD BUS
16
Zdrojové registry a registry pro výsledek X input port Y input port R output port MX0, MX1 MY0, MY1 MR (MR2, MR1, MR0) AR MF MF MR0, MR1, MR2 SR0, SR1 Registr MR2 dovoluje při opakovaných výpočtech ve smyčce v MAC průběžné přetečení až 256krát. Na konci výpočtu, kdy se výsledek předává ven z MAC, je však třeba případné přetečení hlídat. Testování přetečení je pomocí bitu MV již dříve zmíněného registru ASTAT, který se při přetečení nastaví na 1. Je výhodnější nastavit jako výsledek buď nejvyšší kladné nebo nejnižší záporné číslo, tj. saturovat, než jen převzít obsahy registrů MR1 a MR0. Tuto funkci zajistí instrukce
16 (UPPER)
MUX
MX REGISTERS 2 x 16
MY REGISTERS 2 x 16
16
16 MUX
MUX
MF REGISTER
X Y MULTIPLIER P
40
32 ADD / SUBSTRACT R1
R2
MUX
MV
MUX
8
16
MR2 REGISTER
IF MV SAT MR;
R0
Blokové schéma výpočetní jednotky MAC je na obr. D-III. Z jejího zapojení lze získat představu o možných registrech, ze kterých lze převzít pro výpočet vstupní data. Zvýrazněné orámování znázorňuje zdvojené registry.
MUX
16
MR1 REGISTER
MR0 REGISTER
M U X
16
Přehled všech instrukcí je v následující tabulce, ve které cond znamená podmínku a X s Y výše popsané operandy.
R - BUS
Obr. D-III Blokový diagram výpočetní jednotky MAC [IF cond]
MR AF
=X*
Y X
Násobení
(SS ) (SU ) (US )
; 26
Y X Y = MR-X * X = MR [(RND)]; =0; IF MV SAT MR; = MR+X *
Násobení/sečítání Násobení/odečítání Přenos MR Nulování Podmíněná saturace obsahu registru MR
Jak bude podrobněji ukázáno dále, lze výpočet součinu se součtem provést současně s naplněním vstupních registrů operandy z cyklických pamětí v paměti programu a dat pro příští opakování výpočtu součinu a součtu. Tato vlastnost a instrukce pro smyčky usnadňuje programování konvoluce signálů m
yk = ∑ bi xk −i i =0
tj. především výpočet signálů na výstupu FIR nebo IIR filtru. Čtení dat a výpočet součinu se součtem může proběhnout v jednom taktu procesoru, proto počet taktů je roven řádu filtru. Tato možnost velmi urychlí výpočet výstupu filtru. Instrukce výpočetní jednotky Shifter Výpočetní jednotka Shifter uskutečňuje posuny bitů v registru SR, který má délku 32 bitů a je rozdělen na dvě části, SR1 a SR0: 31
16 15 SR1
0 SR0
V tomto 32bitovem prostoru je uložen výsledek posunu. Výchozí poloha 16bitového slova (před posunem) souhlasí při HI referenci s obsahem registru SR1 a při LO referenci s obsahem registru SR0. Vstupní slovo pro operaci posunu je obsaženo v 16bitovém registru SI, případně v registrech SR1 nebo SR2 a nebo také v registrech AR, MR0, MR1, MR2. Počet bitů, o který se má posouvat, je uložen v 8bitovém registru SE (shifter exponent). Kladné číslo obsažené v tomto registru znamená posun doleva a záporný doprava. Kromě posunů je jednotka Shift určena také k operacím úpravy bloků číselných dat k výpočtům. Pro tyto účely je použit 5bitový registr SB (shifter block). Oba registry, SB a SE, jsou na sběrnici DMD rozšířeny na 16bitové. Stejně jako jednotka ALU a MAC nelze použit v instrukci libovolný identifikátor. Před operaci s data v Shifter je třeba příslušné registry zaplnit vstupními daty. Jak naznačuje blokové schéma na obr D-IV, některé registry jsou zdvojeny. Operace posunu jsou následující
• aritmetický posun (ASHIFT) (zachová se znaménko čísla a odpovídá násobení nebo dělení mocninou dvou, například při posunu záporného čísla při referenci HI se nejvýznamnější bity registru SR1 plní zleva 1) • logický posun (LSHIFT) (posuny se uskutečňují bez ohledu na znaménkový bit, ze záporného čísla se po posunu vpravo při referenci HI stane kladné číslo) • odvození exponentu (EXP) s uložením výsledku do registru SE (exponent čísla je nula nebo záporné číslo a jeho absolutní hodnota je rovna počtu redundantních bitů; tato operace je přípravou normalizace)
27
• normalizace (NORM) (vyloučení redundantních bitů posunem vlevo, velikost posunu je určena obsahem registru SE) • nastavení nejmenšího exponentu bloku dat (EXPADJ) (nejvyšší exponent z opakovaného testu je uložen v registru SB; jedná se o záporné číslo od 0 do –15, jehož absolutní hodnota se rovná počtu redundantních bitů). Vstupní a výstupní registry jsou následující Shifter input X Shifter output SI SR (SR0, SR1) AR MR0, MR1, MR2 SR0, SR1
Tyto instrukce se užijí pro úlohy
• • • •
odvození exponentu bloku dat okamžité posuny o zadaný počet bitů denormalizace normalizace
Zvláštní případ tzv. rozšířené (eXtended) reference HI, která se značí HIX, je při normalizaci se vstupem z registru AR jednotky ALU. Při této operaci se čte také bit přetečení (overflow) AV a přenosu (carry) AC. DMD BUS
16
SI REGISTER
MUX
SB REGISTER MUX
SS X EXPONENT DETECTOR
COMPARE
I
MUX
R C
HI/LO
8
32
MUX
X SHIFTER ARRAY O
32 OR / PASS
SE REGISTER
16
NEGATE
16
8
From INSTRUCTION
MUX
MUX
SR1 REGISTER
SR0 REGISTER
16
16
16
R - BUS
Obr. D-IV Blokový diagram výpočetní jednotky Shift
28
MUX
Přehled instrukcí posunu je následující [IF cond] SR = [SR OR] ASHIFT X [IF cond] SR = [SR OR] LSHIFT X [IF cond] SE = EXP X
[IF cond] SR = [SR OR] NORM X
(HI ) (LO ) ; (HI ) (LO ) ; (HI ) (LO ) ; (HIX ) (HI ) (LO ) ;
[IF cond] SB = EXPADJ X SR = [SR OR] ASHIFT X BY EXP SR = [SR OR] LSHIFT X BY EXP
Aritmetický posun o počet bitů daný obsahem registru SE Logický posun o počet bitů daný obsahem registru SE Určení exponentu, tj. počtu redundantních bitů v operandu Normalizace, tj. posun o počet redundantních bitů, který je obsažen v registru SE Nastavení největšího exponentu u bloku dat při opakovaných použitích této instrukce Okamžitý aritmetický posun o zadaný počet bitů EXP doleva nebo doprava Okamžitý logický posun o zadaný počet bitů EXP doleva nebo doprava
Výraz <exp>, exponent, označuje 8bitové číslo se znaménkem (signed). Poznámky: Redundantní bity u dvojkových čísel jsou bity vlevo od znaménkového bitu směrem doprava, které mohou být vyloučeny posunem dalších bitů směrem doleva na jejich místo. Posun obsahu registru vlevo o jeden bit znamená násobení dvěma. Velikost posunu doleva v počtu bitu se záporným znaménkem je nazýván exponentem tohoto čísla bez redundantních bitů. Exponent čísla je ve skutečnosti exponent mocniny se základem 2. Číslo bez redundantních bitů vynásobené touto mocninou má za výsledek původní číslo. Normalizace probíhá ve dvou fázích. Nejprve je zjištěn instrukcí EXP počet redundantních bitů a uložen do registru SE. Například pro následující záporné číslo 11110110 11010100
umístěné v registru SR1 se touto instrukcí nastaví obsah registru SE na –3. Ve druhé fázi se instrukcí NORM s referencí HI se odstraní redundantní bity (zbylé bity jsou vyznačeny tučně) s následujícím výsledným obsazením registrů SR1 a SR0. 10110110 10100000 00000000 00000000
Nastavení exponentu bloku dat z 16bitových čísel probíhá tak, že se registr SB nejprve zaplní nejmenším možným číslem číslem –16 a pak se instrukcí EXPADJ testuje obsah registru povoleného v kolonce tabulky s názvem Shifter input X. Jestliže je exponent čísla v tomto registru větší (např. –3), pak se tento exponent do registru přepíše. Jestliže je exponent dalšího testovaného čísla menší (např. –5), pak obsah registru SB zůstane nezměněn. Výsledkem prohledání celého bloku dat je největší zjištěný exponent. Účel operace OR v logických a aritmetických posunech a při normalizaci lze nejlépe vysvětlit na příkladu vynásobení obsahu celého registru MR dvěma, což je aritmetický posun obsahu MR o jeden bit doleva. Nechť regisrt SR0 byl předem vynulován. Nejprve je třeba posunout významnější bity z registru MR1 aritmetickým posunem při referenci HI, tj. posunuté bity se uloží jen do registru SR1. Velikost posunu se zadá buď do registru SE nebo jako konkrétní číslo (v daném příkladě 1) za písmena BY, o které je instrukce posunu doplněna. Výsledek zadaného posunu je obsažen pouze v registru SR1, přičemž 16. bit registru SR1 29
obsahuje 0. Tento obsah registru SR1 je třeba sečíst (operátor OR) s logicky posunutým obsahem registru MR0 při referenci LO, tj. posunuté bity z MR0 jsou uloženy z části v registru SR0, přičemž nejvyšší bit z MR0 se přesune do nejnižšího bitu registru SR1. Výsledek „násobení“ dvěma obsahu registrů MR1 a MR0 je v registrech SR1 a SR0: sr = ashift mr1 by 1 (hi); sr = sr or lshift mr0 by 1 (lo);
Instrukce přesunu dat Důležitou skupinu instrukcí představují přesuny obsahu registrů a paměti mezi sebou navzájem. Možnost vzájemné předávání dat mezi registry a pamětí a ukládání dat do paměti je omezena. Paměťovým buňkám nelze přímo přiřadit žádná data, ale je třeba použít jako prostředníka některý registr. Registry obecně (reg) mají podskupinu datových registrů (dreg). Jen registry dreg mohou využívat generátorů adres. reg I0, I1, I2, I3, I4, I5, I6, I7, M0, M1, M2, M3, M4, M5, M6, M7, L0, L1, L2, L3, L4, L5, L6, L7, TX0, TX1, RX0, RX1, SB, PX, ASTAT, MSTAT, SSTAT (read-only), IMASK, ICNTL, IFC (write-only), CNTR, OWRCNTR (write-only) dreg AX0, AX1, AY0, AY1, AR, MX0, MX1, MY0, MY1, MR0, MR1, MR2, SR0, SR1, SR2
Přehled instrukcí přesunů je následující: reg = reg; reg = ; dreg = ; dreg = DMOVLAY; DMOVLAY = dreg; reg = DM; dreg = IO;
přesun obsahu jednoho registru do jiného registru naplnění registru daty naplnění datového registru daty čtení Overlay Registru zápis do Overlay Registru naplnění obsahem datové paměti na adrese addr naplnění registru daty z vnější paměti, přičemž adresa je této instrukce omezena na rozsah čísel od 0 do 2048 dreg = PM; naplnění registru z adresy Ix datové paměti s modifikací adresy o My (x, y jsou shodná nebo různá čísla od 4 do 7) dreg = DM; naplnění registru z adresy Ix datové paměti s modifikací adresy o My (x, y jsou buď jako u čtení PM od 4 do 7 nebo navíc od 0 do 3) DM = reg; naplnění datové paměti obsahem registru reg DM = DMOVLAY; naplnění datové paměti obsahem Overlay Registru IO = dreg; naplnění vnější paměti obsahem registru dreg, přičemž adresa je této instrukce omezena na rozsah čísel od 0 do 2048 PM = dreg; naplnění programové paměti o adrese Ix s modifikací adresy o My (x, y jsou shodná nebo různá čísla od 4 do 7) DM = dreg; naplnění datové paměti o adrese Ix s modifikací adresy o My z dreg (x, y jsou buď jako u zápisu do PM čísla od 4 do 7 nebo také od 0 do 3) Multifunkční instrukce Jak již bylo v uvedeno, některé instrukce lze sdružovat tak, že jsou provedeny v jednom instrukčním cyklu. Nazývají se multifunkční. V tomto případě se při psaní zdrojového textu programu tyto instrukce ukončují místo středníkem čárkou a až poslední instrukce je ukončena středníkem. Sdružovat do jednoho taktu je možné tyto instrukce
30
Výpočet s přesunem z registru do registru ALU MAC , dreg = dreg; Shift
kde
ALU , MAC , Shift
jsou jakékoliv instrukce příslušné jednotky s výjimkou
podmíněných instrukcí a v případě instrukcí ALU , MAC v registrech AF, MF, což platí i pro další použití těchto instrukcí
nesmí být výsledek uložen
Výpočet s přesunem z paměti do registru ALU DM (Ix , My ) ; MAC , dreg = PM (Ix , My ) Shift
kde x a y je buď kombinace hodnot od 0 do 3 nebo od 4 do 7 (není možná kombinace čísel z obou uvedených skupin u čtení datové paměti (DM) a jen kombinace hodnot od 4 do 7 při čtení z programové paměti (PM) Výpočet s přesunem z registru do paměti do registru DM (Ix , My ) = dreg , PM (Ix , My )
ALU MAC ; Shift
pro kombinace hodnot x a y platí stejná podmínka jako v předchozím případě Čtení z datové a programové paměti
AX0 AX1 MX0 = DM (Ix , My ) , MX1
AY0 AY1 MY0 = PM (Iu , Mv ) ; MY1
kde x a y mohou být jakákoliv čísla od 0 do 3 a u a v jakákoliv čísla od 4 do 7 Čtení z datové a programové paměti
AX0 ALU AX1 MAC , MX0 = DM (Ix , My ) , Shift MX1
AY0 AY1 MY0 = PM (Iu , Mv ) ; MY1
kde x, y, u a v mají stejná omezení jako v předchozím případě. Multifunkční instrukce spolu s vlastnostmi cyklických zásobníků urychlují podstatně výpočet. Řízení běhu programu K řízení běhu programu jsou k dispozici instrukce DO UNTIL, JUMP, CALL, RTS (Return From Subroutine), RTI (Return From Interupt) a IDLE. Instrukce skoku JUMP je buď přímo na adresu dnou návěštím nebo nepřímo na adresu, která je obsažena v indexovém registru DAG2. Stejný způsob adresování je pro instrukci volání podprogramu CALL. Návrat ze sekvence 31
instrukcí podprogramu je instrukcí RTS. Instrukce DO UNTIL slouží k programování smyček. Instrukcí IDLE se uvede DSP do stavu sníženého příkonu až do okamžiku vzniku přerušení. Řada instrukcí může být podmíněná. Tyto instrukce začínají IF s podmínkou. Smyčky DO [UNTIL term] Nejběžnější způsob řízení počtu opakování využívá registru 14bitového CNTR a příznaku CE snížení jeho obsahu na nulu. Při každém opakování úseku programu od instrukce DO loop UNTIL CE;
do návěští loop se automaticky snižuje obsah registru CNTR o 1 až k nule. Protože registr CNTR je dekrementován na konci vybraného úseku programu a CE testováno na jeho začátku, je při nastaveni CNTR na N zajištěno N opakování. Ostatní podmínky term jsou uvedeny v přehledu na konci úseku popisu řídicích instrukcí. Hardware signálového procesoru umožňuje zahnízdit až čtyři smyčky do sebe. Příklad čtyř zahnízděných smyček je následující:
loop4: loop3: loop2: loop1:
CNTL = 80 DO loop1 UNTIL CE; CNTL = 50 DO loop2 UNTIL CE; CNTL = 30 DO loop3 UNTIL CE; CNTL = 10 DO loop4 UNTIL CE; { instrukce } NOP; NOP; NOP; NOP;
Skoky [IF cond] JUMP
(I 4 ) (I 5 ) (I6 ) (I7 )
;
addr
Adresa pro instrukci skoku je dána buď obsahem I registru DAG2 nebo návěštím. Příklady pro omezení návěštím je JUMP fir_start;
a příklad pro I registr JUMP (I5);
Instrukce volání podprogramu [IF cond] CALL
(I 4 ) (I 5 ) (I6 ) (I7 )
;
addr
Adresa pro instrukci volání podprogramu je dána rovněž jako v případě instrukce skoku buď obsahem I registru DAG2 nebo návěštím. Podprogram představuje skupinu instrukcí následujících po návěští. Vykonávání instrukcí této skupiny je ukončeno instrukcí návratu 32
z podprogramu RTS (Return From Subroutine). Data pro vykonání podprogramu se předávají prostřednictvím libovolně vybraných registrů. Instrukce JUMP a CALL podle signálu na vývodech IF FLAG _ IN
JUMP
NOT FLAG _ IN CALL
;
Instrukce skoku nebo volání podprogramu se uskuteční podle logické hodnoty na vývodu (pin) procesoru FLAG_IN
FLAG _ OUT Instrukce SET, RESET a TOGGLE [IF cond] SET FL0 RESET TOGGLE FL1 FL2
[, . . .] ;
FLAG_OUT, FL0 až FL 2 jsou vývody signálového procesoru. Instrukce SET nastavuje hodnotu příslušného vývodu bitu na 1, RESET na 0 a TOGGLE změní hodnotu buď z nuly na 1 nebo opačně. Instrukce návratu z podprogramu [IF cond] RTS ; Instrukce návratu z obsluhy přerušení [IF cond] RTI ; Instrukce RTI (Return From Interrupt Service Routine) ukončuje obsluhu přerušení a umožňuje pokračovat ve vykonávání programu. Instrukce IDLE [(n)]; Samotná instrukce IDLE ; vyvolá zastavení procesoru a čekání na přerušení v režimu sníženého odběru proudu. Po vzniku přerušení je toto přerušení obslouženo a pak se pokračuje instrukcí následující za instrukcí IDLE. Jinou možností použití této instrukce je její rozšíření o n = 16, 32, 64 a 128.Tato instrukce vyvolá snížení taktovací frekvence procesoru faktorem n, tj. rovněž snížený příkon při zachování plné funkceschopnosti. Po vzniku přerušení nenastane reakce v jednom taktu, ale po uplynutí zmíněných n taktů procesoru, kdy je obnovena výchozí taktovací frekvence procesoru. Různé instrukce Prázdná instrukce NOP ; Tato instrukce nevyvolá žádnou akci. Instrukce MODIFY (Ix, My) ; Instrukce modifikuje (přidá) obsah registru My k obsahu registru Ix. Čísla x a y nabývají libovolné kombinace hodnot ze skupiny od 0 do 3 nebo ze skupiny od 4 do 7. Instrukce [ PUSH STS] [, POP CNTR] [, POP PC] [, POP LOOP] ; POP Instrukce složí k ovládání zásobníků, které pracují na principu Last In – First Out. Instrukce PUSH uloží obsahy registru na vrchol zásobníku a instrukce POP sejme uložený údaj z vrcholu zásobníku.
33
[, . . . ] ; SEC _ REG BIT _ REV AV _ LATCH AR _ SAT M _ MODE TIMER G _ MODE INTS Instrukce ENA (enable) zpřístupňuje a DIS (disable) různé módy procesoru. Těmito instrukcemi se ovlivňuje nastavení registru MSTAT: Instrukce ENA DIS
MSTAT = b#1000000; { ||||||+- | |||||+-- | ||||+--- | |||+---- | ||+----- | |+------ | +------- | }
Data register bank select (0=prim, 1=second) FFT bit reverse mode enable (DAG1) ALU overflow latch mode, 1=sticky AR saturation mode, 1=saturate, 0=wrap MAC result, 0=fractional, 1=integer Timer enable GO MODE enable
SEC_REG se týká sekundárních (stínových) registrů procesoru. BIT_REV zpřístupňuje bitově reverzní adresaci DAG1. Mód AV_LATCH způsobí setrvání bitu AV registru ASTAT v indikaci přetečení, i když tato příčina pominula. Mód AV_SAT způsobí saturaci AR registru v případě přetečení na největší kladnou hodnotu 0x7FFF nebo na největší zápornou hodnotu 0x8000. M_MODE umožňuje počítat při výstupu operací v MAC s integer čísly bez posouvání obsahu registru o jeden bit vlevo, tj. v integer mode na rozdíl od fractional mode, při kterém k posunu dochází. TIMER se vztahuje na časovač. G_MODE zpřístupňuje GO mód procesoru, který má význam při přístupu k externí paměti. INTS se vztahuje na přerušovací systém, který lze zakázat nebo povolit. Pro úplnost textu je třeba ještě výčet způsobu ukončení smyčky DO UNTIL a podmínky pro IF. DO cond UNTIL cond EQ NE LT GE LE GT AC NOT AC AV NOT AV MV NOT MV NEG POS CE FOREVER
True if AZ = 1 AZ = 0 AN .XOR. AV = 1 AN .XOR. AV = 0 (AN .XOR. AV) .OR. AZ = 1 (AN .XOR. AV) .OR. AZ = 0 AC ´1 AC = 0 AV = 1 AV = 0 MV = 1 MV = 0 AS = 1 AS = 0 CNTR Counter Expired Always
IF cond cond EQ NE LT GE LE GT AC NOT AC AV NOT AV MV NOT MV NEG POS NOT CE FLAG_IN NOT FLAG_IN
34
True if AZ = 1 AZ = 0 AN .XOR. AV = 1 AN .XOR. AV = 0 (AN .XOR. AV) .OR. AZ = 1 (AN .XOR. AV) .OR. AZ = 0 AC ´1 AC = 0 AV = 1 AV = 0 MV = 1 MV = 0 AS = 1 AS = 0 CNTR Counter Not Expired FI pin = 1 FI pin = 0
Popis programování DST typu ADSP-2181 se snaží čtenáře seznámit se všemi instrukcemi, které jsou zapotřebí k vytvoření vlastního programu. K dokonalému zvládnutí programování je nezbytné prostudovat stovky stránek manuálu a mnoho příkladů.
Matematické programy pro signálové procesory rodiny ADSP 21xx Signálové procesory jsou určeny především pro zpracování signálů. K tomuto účelu je procesor vybaven zvláštními instrukcemi, jejichž přednosti vyniknou právě z následujících příkladů. Filtr prvního řádu Lineární číslicový filtr prvního řádu je má přenosovou funkci v Z-transformaci b + bz −1 . H (z ) = 1 + az −1 Diferenční rovnice příslušná tomuto přenosu, která transformuje vstupní signál x i , i = 0, 1, 2,... a na výstupní signál y i , i = 0, 1, 2,... , je tvaru y k = bx k + bx k −1 − a y k −1 . K opakovanému výpočtu této rovnice je zbytečné použít aparátu cyklických zásobníků. V paměti se pouze deklarují následující proměnné .var/dm .var/dm .var/dm .var/pm .var/pm
in_smpl; past_in_smpl; out_smpl; a_coef; b_coef;
{ { { { {
aktuálně změřený vzorek } minule změřený vzorek } výstupní vzorek } koeficient a } koeficient b }
Po inicializaci je výpočet výstupu filtru včetně přesunu hodnot v jednoduché zpožďovací lince v 11 taktech procesoru následující: sr0 = dm(in_smpl); my0 = pm(b_coef); mr = sr0*my0(ss); mx0 = dm(past_in_smpl); mr = mr+mx0*my0(ss); mx0 = dm(out_smpl); { minulý (nezměněný) výstupní vzorek } my0 = pm(a_coef); mr = mr-mx0*my0(rnd); IF MV SAT MR; dm(out_smpl) = mr1; { nový výstupní vzorek } dm(past_in_smpl) = sr0; { nový minulý vstupní vzorek }
Stejný výpočet lze naprogramovat s použitím cyklického zásobníku pro koeficienty a data. Vstupní parametry výstup filtru jsou v paměti umístěny následujícím způsobem: dm(delayline) = vstupní vzorek x(k) I0 --> delayline:zpož.linka pro x(k),x(k-1),y(k-1) L0 = 3 I4 --> coef: b, b, -a L4 = 3 M0,M4 = 1 I0=^delayline; I4=^coef;
35
cntr = 2 vystupní vzorek y(k) = dm(delayline+2)
Za předpokladu, že registry I0 a I4 nebudou použity jinými částmi programu, lze počet taktů procesoru pro výpočet výstupu filtru snížit na 8. V případě, že před výpočtem výstupu filtru je třeba definovat nově obsahy obou indexregistrů, popřípadě délky cyklických zásobníků, je urychlení algoritmu oproti první verzi programu nepodstatné.
lp:
mr = 0, mx0 = dm(i0,m0), my0 = pm(i4,m4); do lp until ce; mr = mr+mx0*my0 (ss), mx0 = dm(i0,m0), my0 = pm(i4,m4); mr = mr+mx0*my0(rnd); IF MV SAT MR; dm(delayline+2)=mr1; ar = dm(delayline); dm(delayline+1)=ar;
Filtr prvního řádu má technické opodstatnění vzhledem k průběhu frekvenční charakteristiky použít jen v takovém případě, kdy frekvence zlomu je mnohem menší než polovina vzorkovací frekvence. Koeficient b tohoto filtru je velmi malé číslo a koeficient a se blíží k jedničce. Vzhledem k omezené rozlišitelnosti čísel ve formátu 1.15, nemůže být frekvence zlomu neomezeně malá. Praktické využití filtru spočívá v integraci signálu ve frekvenčním pásmu nad několikanásobek (postačuje do 10) frekvence zlomu, a to pro použití s převodníkem, který stejnosměrnou složku signálu neměří a pracuje například až od 20 Hz (jako dále zmíněný codec AD1847), protože na jeho vsup je přiveden napěťový signál přes kondenzátor. Konvoluce signálů – filtr FIR Zvláště výhodná pro výpočet v signálovém procesoru je konvoluce měřeného signálů se signálem konečné délky. Nechť vstupní signál je dán posloupností vzorků x i , i = 0, 1, 2,... a druhý signál je konečná impulsní odezva bi , i = 0, 1, 2,..., m nějaké soustavy nebo přímo tzv. filtru s konečnou odezvou (Finite Impulse Response - FIR) řádu m. Výstupní signál se vypočte podle vzorce m
y k = ∑ bi x k − i i =0
Teoreticky žádní konečné hodnoty koeficientů bi , i = 0, 1, 2,..., m nemohou způsobit nestabilitu filtru. Nebezpečné je pouze přetečení v případě, že filtr má statické zesílení větší než 1 a rozsah vstupních vzorků je ve formátu 1.15 a využívá plný rozsah čísel od –1 do 0.999969. Pro konstantní vzorky na vstupu filtru je výstup filtru po ustálení, které nastane po změně vstupu za m vzorků, jejich násobkem o velikosti
m
∑b i =0
i
. I když je součet koeficientů menší než 1
a navíc pro filtry vyššího řádu také jednotlivé koeficienty jsou v absolutní hodnotě menší než 1, mohou dílčí součty přesahovat v absolutní hodnotě 1. Proto má registr MR část umožňující až 256násobné přetečení. Příkladem filtru prvního řádu, který může způsobit přetečení, je výpočet diference y k = xk − xk −1 , ( b0 = 1, b0 = −1 ) s nulovým statickým zesílením. Dva sousední vzorky mohou vytvářet rozdíl v absolutní hodnotě větší než 1 nehledě na skutečnost, že +1 nelze uložit ve formátu 1.15. V tomto případě se oba koeficienty filtru zmenší na polovinu
36
( b0 = 0.5, b0 = −0.5 ), tj. v paměti se oba koeficienty posunou o 1 bit vpravo. Výstupní vzorky tohoto filtru jsou pak poloviční, což je třeba respektovat. Při programovém řešení konvoluce budou koeficienty konečné impulsní odezvy uloženy v zásobníku se jménem fir_coefs. Jejich počet je m + 1 a je označen identifikátorem taps. Vstupní data, aktuální a zpožděné vzorky, v počtu m + 1 budou uloženy v cyklickém zásobníku, který je označen identifikátorem. Zásobník data je vytvořen (deklarován) v paměti dat a zásobník fir_coefs je vytvořen (deklarován) v paměti programu. Vzorky signálu jsou předpokládány ve formátu 1.15. Jak již bylo uvedeno v jiném místě textu, koeficienty jsou uloženy jako 24bitové údaje, ovšem pro výpočet je použito je horních 16 bitů, tj. jejich formát je také 1.15. Indexové registry, které jsou ve výše uvedeném kódu označeny I0 a I4, se inkrementují o M0 a M4. Zpožďovací linka pro vstupní signál je na úplném začátku programu inicializována instrukcemi: I0=^data;
M0=1;
L0=taps;
První změřený vzorek se uloží do první buňky zásobníku a současně se automaticky generátorem adres modifikuje adresa o jednotku (volbou obsahu modifikačního registru) pro uložení dalšího vzorku, kde bude později (po dosažení konce zásobníku) uložen nejstarší vzorek. To se opakuje až do konce tohoto cyklického zásobníku odkud se přejde opět automaticky na jeho začátek. Celá zpožďovací linka se tedy realizuje jedinou instrukcí. Výstupní signál může být poskytnut pro D/A převod nebo být vstupem pro další konvoluci, tj. může být ukládán do zpožďovací linky. Příklad kódu v asembleru pro výpočtu konvoluce nejprve zajistí přiřazení registrů generátoru adres pro zásobník s koeficienty (stejné registry by mohly být použity pro jiný zásobník). Registr I4 obsahuje adresu první buňky zásobníku koeficientů a registr I0 obsahuje adresu nejstaršího vzorku ve zpožďovací lince. V prvém kroku výpočtu konvoluce se pouze vynuluje registr MR a naplní se obsahy vstupních registrů MX0 a MY0 daty. Tyto tři instrukce se vykonají sdruženě v jednom taktu procesoru a označují se za multifunkční. Dále je třeba připomenout, že vybrané registry obsahují již adresy příštích hodnot pro čtení do vstupních registrů. K opakovaným výpočtům se použije instrukce smyčky po návěští firloop, která zajistí opakování trojice v jednom taktu procesoru vykonaných instrukcí. Součet a součin v MAC jednotce je deklarován jako operace s čísly se znaménky (SS). Průběžné výsledky výpočtů jsou obsaženy v 40bitovém registru. Konečný výsledek je třeba omezit jen na 16 bitů a současně zaokrouhlit poslední bit (RND). Proto není smyčka opakována o počet vzorků impulsní odezvy, ale o jeden méně. Během výpočtu může dvojkové číslo v registru MR „přetéci“ o 8 bitů (256krát), což lze předpokládat na základě obvyklého rozložení koeficientů impulsní odezvy. Pro jistotu je na konci výpočtu po zaokrouhlení proveden test na přetečení a po jeho provedení je případné přetečení opraveno nahrazením výsledku nejvyšší možnou kladnou nebo zápornou hodnotou čísla ve formátu 1.15. ...................... I4=^fir_coefs; M4=1; L4=taps; CNTR=taps-1; MR=0, MX0=DM(I0,M0), MY0=PM(I4,M4); DO firloop UNTIL CE; firloop: MR=MR+MX0*MY0(SS), MX0=DM(I0,M0), MY0=PM(I4,M4); { IF NOT CE JUMP firloop;} MR=MR+MX0*MY0(RND); IF MV SAT MR; ......................
37
Výsledek výpočtu konvoluce je k dispozici v registru MR1. Během výpočtu byly postupně čteny všechny údaje ve zpožďovací lince a v zásobníku koeficientů, tj. obsah registru I4 adresuje první buňku zásobníku s koeficienty a obsah registru I4 adresuje buňku zpožďovací linky s nejstarším vzorkem. Filtr FIR s dvojnásobnou přesností koeficientů Jestliže jsou koeficienty filtru uloženy ve formátu 1.15, pak nejmenší možná nenulová absolutní hodnota koeficientu je 0.000031. Pro filtry s menšími koeficienty, které mohou také ovlivnit výstup filtru, lze výpočet naprogramovat ve dvojnásobné přesnosti uložených koeficientů, tj. ve formátu 1.31. Dvojnásobná přesnost pro vstupní data (změřené vzorky) nechť je z důvodu přesnosti převodu zbytečná. Koeficienty jsou tedy uloženy tak, že jsou rozděleny do dvou buněk, a to nejprve do buňky se 16 významnějšími bity (slovem MSW) a následující buňky s 16 méně významnými bity (slovem LSW). Slovo MSW je se znaménkem (signed) a slovo LSW je bez znaménka (unsigned). Jestliže se obsahy buněk (slova) rozliší indexem „v“ pro vzorky a indexem „k“ pro koeficienty, pak lze násobení zapsat symbolicky jako MSWv*(MSWk + LSWk) = MSWv*MSWk+MSWv*LSWk . Výpočet součtu součinů se rozpadne na dva dílčí výpočty. Nejprve se vypočte součet MSWv*LSWk jako násobení (SU) a výsledek v registru MR se posune o 16 bitů doprava ( tj. co do významu dolů) a k tomuto mezisoučtu se připočte součet MSWv*MSWk jako násobení (SS). Výsledek výpočtu je opět zaokrouhlen na formát 1.15. .MODULE dfir_sub; { Podprogram pro výpočet výstupu FIR filtru s koeficienty ve dvojnásobné přesnosti Vstupní parametry I0 --> Nejstarší vstupní vzorek ve zpožďovací lince L0 = Délka filtru (N) I4 --> druhá buňka (LSW prvního koeficientu) zásobníku koeficientů L4 = 2 * Délka filtru (N) M0,M4 = 1 M5 = 2 M2,M6 = 3 AX0 = Délka filtru - 2 (N-2) CNTR = Délka filtru - 2 (N-2) Výsledek výpočtu MR1,MR0 = součet součinů (podmíněně saturováno na 32 bitů) I0 --> Nejstarší vstupní vzorek ve zpožďovací lince I4 --> druhá buňka (LSW prvního koeficientu) zásobníku koeficientů Změněné registry MX0,MY0,MR Doba výpočtu 2 * (N - 2) + 11 Koeficienty jsou ve dvojnásobné přesnosti ve formátu 1.31 a vzorky v jednoduché přesnosti ve formátu 1.15. } .ENTRY dfir; dfir:
MR=0, MX0=DM(I0,M0), MY0=PM(I4,M5); DO hlloop UNTIL CE; hlloop: MR=MR+MX0*MY0(SU), MX0=DM(I0,M0), MY0=PM(I4,M5); MR=MR+MX0*MY0(SU), MX0=DM(I0,M0), MY0=PM(I4,M4);
38
MR=MR+MX0*MY0(SU), MX0=DM(I0,M0), MY0=PM(I4,M5); CNTR=AX0; MR0=MR1; {posun v registru MR o 16 bitů doprava} MR1=MR2; CNTR=AX0; DO hhloop UNTIL CE; hhloop: MR=MR+MX0*MY0(SS), MX0=DM(I0,M0), MY0=PM(I4,M5); MR=MR+MX0*MY0(SS), MX0=DM(I0,M0), MY0=PM(I4,M6); MR=MR+MX0*MY0(RND); IF MV SAT MR; RTS; .ENDMOD;
Kód je mezi direktivami MODULE a ENDMOD. Hlavička je věnována popisu vstupních a výstupních parametrů a dále je uveden počet cyklů, které dělení vyžaduje. Kód končí instrukcí návratu z podprogramu (RTS). Vstupním bodem je návěští dfir, které je deklarováno jako ENTRY. Program, který tento podprogram volá, musí mít tento vstupní bod deklarován jako EXTERNAL, tj. .EXTERNAL dfir;
Přeložený podprogram je třeba přilinkovat k výslednému kódu programu. Filtr IIR v přímé formě Filtr s nekonečnou odezvou (Infinite Inpulse Response - IIR) řádu n ( n ≥ m ) má Ztransformaci přenosové funkce ve tvaru Y (z ) b0 + b1z −1 + ... + bm z − m H (z ) = = , X (z ) 1 + a1z −1 + ... + an z −n kde a1 , a 2 ,..., a n a b0 , b1 , ..., bm jsou parametry. Parametry jmenovatele nemohou pro stabilitu filtru nabýt libovolné hodnoty. Filtr IIR obsahuje zpětnou vazbu, která může způsobit nestabilitu. Aby byl filtr stabilní, kořeny jmenovatele musí ležet uvnitř jednotkové kružnice se středem v počátku komplexní roviny. Jak již naznačuje název tohoto typu filtrů, odezva filtru na jednotkový impuls trvá nekonečně dlouho. Výše uvedenému přenosu odpovídá v časové oblasti vzorec
y k = b0 xk + b1 x k −1 + ... + bm xk −m − a1 y k −1 − a 2 y k −2 − ... − a n y k −n . Tento tvar vzorce pro programování se označuje přímá forma (direct form). Kromě stability jsou dalším problémem IIR filtrů hodnoty koeficientů, které jsou v absolutní hodnotě větší než 1. Jestliže některý z koeficientů je větší než 1, pak se všechny koeficienty musí o jednotný násobek 1/SF (Scale Factor) zmenšit tak, aby byly zobrazitelné ve formátu 1.15. Velokost zmenšení určuje koeficient s největší absolutní hodnotou. Původní výstup se získá vynásobením výsledku výpočtu hodnotou SF
⎡⎛ b ⎞ ⎤ ⎛a ⎞ ⎛b ⎞ ⎛a ⎞ ⎛a ⎞ ⎛b ⎞ y k = SF ⎢⎜ 0 ⎟ xk + ⎜ 1 ⎟ x k −1 + ... + ⎜ m ⎟ x k −m − ⎜ 1 ⎟ y k −1 − ⎜ 2 ⎟ y k −2 − ... − ⎜ n ⎟ y k −n ⎥ . ⎝ SF ⎠ ⎝ SF ⎠ ⎝ SF ⎠ ⎝ SF ⎠ ⎝ SF ⎠ ⎣⎝ SF ⎠ ⎦ Toto řešení je nevýhodné. Lepší způsob naprogramování přenosu spočívá v jeho rozkladu na kaskádu (sériové zapojení) filtrů IIR druhého řádu. Každý dílčí filtr má přenos ve tvaru
Y (z ) b0 + b1z −1 + b2 z −2 H (z ) = = , X (z ) 1 + a1z −1 + a 2 z −2
39
kde a1 , a 2 a b0 , b1 , b2 jsou parametry. V anglické literatuře se tento filtr nazývá Biquad IIR Filter. Odezva filtru na jednotkový impuls trvá nekonečně dlouho. Výše uvedenému přenosu odpovídá v časové oblasti vzorec
y k = b0 x k + b1 xk −1 + b2 xk −2 − a1 y k −1 − a 2 y k −2 . Kromě stability je dalším problémem IIR filtrů realizovaných v signálových procesorech s pevnou řádovou čárkou zaokrouhlování. Kořeny polynomu jmenovatele příslušející zaokrouhleným hodnotám se mohou posunout do blízkosti meze stability nebo dokonce do nestabilní oblasti a signál na výstupu filtru může kmitat. Signálový diagram filtru je na obr. XXX. Význam zavedení SP k úpravě rozsahu koeficientů vyplývá z následující ho vzorce ⎡⎛ b ⎞ ⎤ ⎛b ⎞ ⎛b ⎞ ⎛a ⎞ ⎛a ⎞ y k = SF ⎢⎜ 0 ⎟ xk + ⎜ 1 ⎟ xk −1 + ⎜⎜ ⎟⎟ xk − − ⎜ 1 ⎟ y k −1 − ⎜ 2 ⎟ y k −2 ⎥ . ⎝ SF ⎠ ⎝ SF ⎠ ⎝ SF ⎠ ⎝ SF ⎠ ⎣⎝ SF ⎠ ⎦ Každý filtr v kaskádě může mít individuální hodnotu SF. Pro stabilitu filtru musí být obecně parametr a1 < 2 a parametr a 2 < 1 . Pro parametr a1 v absolutní hodnotě větší než 1 je výhodné volit SF = 2 . Násobení výsledku součtu dvěma znamená pouze aritmetický posuv o 1 bit doleva. xk
b0*
Σ
yk
SF
-1
z
z-1 b*1
a*1
z-1
z-1 a2*
b2*
Obr. XXXX Signálový diagram filtru nazývaného Biquad IIR Filter Kód pro výpočet výstupu kaskády filtrů druhého řádu (biquad sections) je následující. Část definice konstant určuje počet biquad sections na 3. .MODULE biquad_sub; { Kaskáda filtrů IIR druhého řádu Vstupní parametry SR1 = vstupní vzorek x(k) I0 --> delayline:zpož.linka pro x(k-2),x(k-1),y(k-2),y(k-1) L0 = 0 I1 --> scalelist: scale factors pro každou biquad section L1 = 0 (v případě jediné biquad section) L1 = počet biquad sections I4 --> coefflist: b2,b1,b0,a2,a1, b2,b1,b0,a2,a1, ... L4 = 2.5 * řád filtru --nebo—5 * počet biquad sections M0,M4 = 1 M1 = -3 M2 = 1 (v případě více biquad sections než jedna) M2 = 0 (v případě jediné biquad section) M3 = (1 – délka zpožďovací linky) CNTR = počet biquad sections Výstup filtru SR1 = výstupní vzorek y(k) I0 --> uvnitř zpožďovací linky I1 --> vrchol seznamu scale factors I4 --> vrchol seznamu coefficients Změněné registry
40
} .CONST .CONST
MX0,MX1,MY0,MR,SE,SR Doba výpočtu 8 * počet biquad sections + 4 takty Všechny koeficienty a data jsou ve formátu 1.15. N = 3; N_x_5 = 15;
{ počet biquad sections, příklad: 3 } { počet biquad sections krát 5 }
.VAR/DM delayline[4]; { to je pomocná } .VAR/DM scalelist[N]; { je třeba inicializovat scale factors } .VAR/PM coefflist[N_x_5];{ je třeba inicializovat parametry filtrů } .ENTRY
biquad;
biquad: I0=^delayline; DO sections UNTIL CE; SE=DM(I1,M2); MX0=DM(I0,M0),MY0=PM(I4,M4); {čte x(n-2), b2} MR=MX0*MY0(SS),MX1=DM(I0,M0),MY0=PM(I4,M4); {čte x(n-1), b1} MR=MR+MX1*MY0(SS),MY0=PM(I4,M4); {čte b0} MR=MR+SR1*MY0(SS),MX0=DM(I0,M0),MY0=PM(I4,M4); {čte y(n-2), a2} MR=MR+MX0*MY0(SS),MX0=DM(I0,M1),MY0=PM(I4,M4); {čte y(n-1), a1} DM(I0,M0)=MX1, MR=MR+MX0*MY0(RND); {ukládá x(n-1) jako x(n-2)} sections: DM(I0,M0)=SR1, SR=ASHIFT MR1 (HI); {ukládá x(n) jako x(n-1)} DM(I0,M0)=MX0; DM(I0,M3)=SR1; RTS; .ENDMOD;
Decimace vzorků
Decimace vzorků znamená snížení vzorkovací frekvence f s tak, že se pravidelně jeden nebo více vzorků vynechá. Faktor decimace je v tomto případě celočíselný. Vynechání každého druhého vzorku znamená, že vzorkovací frekvence klesne na polovinu, tj. f s 2 , a faktor decimace je M = 2. Příklad celočíselné decimace je předmětem této kapitoly. Decimací se snižuje vzorkovací frekvence a podle Shannon-Koterlnikova teorému také maximální přípustný frekvenční rozsah signálu. Před decimací je tedy třeba upravit frekvenční spektrum signálu filtrací tak, aby obsahovalo pouze složky s frekvencemi rovnými nejvýše polovině vzorkovací frekvence po decimaci jinak vznikne jev zvaný aliasing. Dolnopropustný filtr s frekvencí zlomu f s (2 M ) pro tuto úpravu spektra signálu se nazývá antialiasingový. Decimace má význam například pro možnost realizace pásmového filtru, jehož propustné pásmo je blízké 0 Hz, tj. horní a dolní frekvence zlomu jsou podstatně menší ve srovnání se vzorkovací frekvencí. Účelem decimace je snížit vzorkovací frekvenci tak, aby byla mnohem menší než horní a dolní frekvence zmíněného pásmového filtru. Na výstupu filtru lze například sledovat efektivní hodnotu signálu. Antialiasingový filtr je nejvhodnější volit typu FIR. Výstupní vzorky tohoto filtru totiž stačí vypočítat jen pro sníženou vzorkovací frekvenci a ne pro každý vzorek jako v případě použití filtru IIR, kdy je třeba znát i minulé výstupní vzorky tohoto typu filtru. Ačkoliv bylo formulováno pravidlo, že nejdříve se musí filtrovat a pak teprve decimovat, zbytečný výpočet vynechávaných vzorků na výstupu filtru FIR toto pořadí při psaní programu obrací. Pro antialiasingový FIR filtr je třeba uložit do paměti programu jeho koeficienty a v paměti dat vytvořit zpožďovací linku pro výchozí vzorky. V případě filtrace decimovaných vzorků je třeba pro tyto vzorky zpožďovací linka rovněž. Na začátku programu je třeba deklarovat příslušné cyklické zásobníky. Inicializace zásobníků je následující 41
I0=^data1; L0=N1; I1=^data2; L1=N2; I4=^fir_coefs; L4=N1;
m0=1;
{ vzorkovací frekvence fs } { vzorkovací frekvence fs/M }
m4=1;
Faktor decimace M bude při inicializaci programu uložen v buňce counter. Data z převodníku nechť jsou uloženy v registru AY0. {________ Část programu opakující se s frekvencí vzorkování fs ________} sample: dm(i0,m0)=ay0; {uložení změřeného vzorku do zpožďovací linky} ay0=dm(counter); ar=ay0-1; {dekrementování čítače vzorků} dm(counter)=ar; if ne rti; {test a návrat jestliže se neopakuje M krát} {________ Část programu opakující se s frekvencí vzorkování fs/M ______} do_fir: ar=M; {reset čítače vzorků na M} dm(counter)=ar; cntr=taps1 - 1; mr=0, mx0=dm(i0,m0), my0=pm(i4,m4); do taploop until ce; {N1-1 taps filtru FIR} taploop: mr=mr+mx0*my0(ss), mx0=dm(i0,m0), my0=pm(i4,m4); mr=mr+mx0*my0(rnd); {poslední taps} if mv sat mr; {saturace výsledku při přetečení} dm(i1,m0)=mr1; {výstupní vzorky do zpožďovací linky} {další výpočty, např. filtrace} rti;
Filtrace spojená se změnou vzorkovací frekvence se nazývá v anglické literatuře multirate filter. Interpolace vzorků
Interpolace vzorků znamená zvýšení jejich vzorkovací frekvence f s tak, že se mezi vzorky vloží jeden nebo více dalších vzorků, což má efekt zvýšení vzorkovací frekvence. Faktor zvýšení je v tomto případě celočíselný. Přidání jednoho vzorku mezi dva sousední vzorky znamená, že se vzorkovací frekvence zvýší na dvojnásobek, tj. 2 f s , a faktor zvýšení je M = 2. Zvyšování vzorkovací frekvence má prakticky význam jen jestliže byla před tím frekvence snížena. V předcházející kapitole byla popsána decimace z důvodu realizace filtru s propustným pásmem blízkým 0 Hz. Nechť je žádoucí výstup tohoto filtru poslat zpět na převodník D/A, který převádí s nedecimovanou frekvencí. V případě zvyšování vzorkovací frekvence problém s aliasingem nevznikne, ale musí se ošetřit jiný jev. Tím jsou velikosti vzorků, které se mezi původní vzorky vkládají. Programátorsky nejjednodušší je buď vložit nulový vzorek nebo M-krát opakovat minulý vzorek. Obě tyto možnosti způsobí vznik složek spektra, které před interpolací ve spektru signálu nebyly. Posloupnost vzorků po takto provedené interpolaci je proto třeba frekvenčně upravit tak, aby se jeho spektrum omezilo na původní spektrum o šířce frekvenčního pásma rovnajícího se polovině původní vzorkovací frekvence, tj. před interpolací. Tento dolnopropustný filtr se nazývá antiimaging filtr. Jeho koeficienty jsou shodné s koeficienty antialiasingového filtru, který byl použit před decimací. Jen v případě, kdy se vkládají nulové vzorky, je třeba výstup filtru M-krát zesílit. Naopak nulové vzorky mají výhodu v tom, že jejich 42
násobení se nemusí vůbec uskutečnit a ukazatel ve zpožďovací lince se může přímo posouvat o počet vzorků M, což M-násobně urychlí výpočet výstupu filtru. Řešení programu pro interpolaci je podobné řešení programu pro decimaci. Jestliže je potřebné výstup filtru na nižší frekvenci než je frekvence vzorkování přivést na D/A převodník (pracuje se stejnou vzorkovací frekvencí jako A/D převodník), pak se zřetězí decimace a interpolace, jak je znázorněno v diagramu na následujícím obrázku. A/D převod
FIR N1
M
FIR N2
FIR N1
M
D/A převod
Výpočty filtrů FIR vysokého řádu „spotřebují“ mnoho taktů procesoru. Z řetězce operací se se stejnou frekvencí opakují výpočty filtru FIR N1 po decimaci a FIR N2. Je nevýhodné oba tyto výpočty kumulovat do obsluhy přerušení z měření stejného vzorku. Protože FIR filtry mají značné zpoždění, které se rovná polovině jejich řádu, je vhodnější výpočet výstupu filtrů FIR N1 a FIR N2 rozprostřít na obsluhu přerušení od změření dvou různých vzorků. Při obsluze přerušení vyvolaného změřením vzorku signálu se „spotřebová“ rovnoměrněji rozložený počet taktů na výpočty. Mnohonásobně opakované decimování vede na problém plánování jednotlivých výpočtů v periodě měření vzorků o délce, která je součinem faktorů jednotlivých decimací. Generováni funkce SIN
Signálový procesor lze použít také k výpočtu funkcí, a to zejména v případě, že je třeba generovat jejich časový průběh. Základní signál ve harmonický, tj. funkce času sinus. Postup je dvojí. Buď lze počítat aproximované hodnoty této funkce nebo ji sestavit například ze vzorků. a) Výpočet z aproximační formule, kterou je polynom 5. stupně (je uveden v komentáři programu). Pro tento případ stačí řešit interval od 0 do π 2 radiánů, protože pomocí vztahů sin (− x ) = − sin (x ) a sin (π − x ) = sin (x ) lze vypočítat hodnoty z 2. až 4.kvadrantu. Program pro výpočet je vytvořen tak, že interval vstupních hodnot x od 0 do 0.5 odpovídá intervalu od 0 do π 2 radiánů. Přesnost aproximace hodnotí následující graf chyba 1,0E-04 1,0E-05 1,0E-06 1,0E-07 0
0,1
0,2
0,3
0,4 x 0,5
.MODULE Sin_Approximation; { Aproximace funkce Y = Sin(x) SIN(x)=3.140625x+0.02026367x2-5.325196x3+0.5446778x4+1.800293x5 Vstupní parametry AX0 = x ve formátu 1.15 v hodnotách 0 až 0.5 pro 0 až pi/2 M3 = 1 L3 = 0 Výsledek výpočtu AR = y ve formátu 1.15 Změněné registry AY0,AF,AR,MY1,MX1,MF,MR,SR,I3 Doba výpočtu
43
25 taktů } .VAR/DM sin_coeff[5]; .INIT sin_coeff : H#3240, H#0053, H#AACC, H#08B7, H#1CCE; .ENTRY sin:
sin; I3=^sin_coeff; {Ukazatel na zásobník koeficientů} AY0=H#4000; AR=AX0, AF=AX0 AND AY0; {Kontrola 2. nebo 4. kvadrantu} IF NE AR=-AX0; {Jestliže ano, negovat vstup} AY0=H#7FFF; AR=AR AND AY0; {Odstranit znaménkový bit} MY1=AR; MF=AR*MY1 (RND), MX1=DM(I3,M3); {MF = x**2} MR=MX1*MY1 (SS), MX1=DM(I3,M3); {MR = C1*x} CNTR=3; DO approx UNTIL CE; MR=MR+MX1*MF (SS); approx: MF=AR*MF (RND), MX1=DM(I3,M3); MR=MR+MX1*MF (SS); SR=ASHIFT MR1 BY 3 (HI); SR=SR OR LSHIFT MR0 BY 3 (LO); {Konverze do 1.15 formátu} AR=PASS SR1; IF LT AR=PASS AY0; {Podle potřeby saturování} AF=PASS AX0; IF LT AR=-AR; {Podle potřeby negování výstupu} RTS; .ENDMOD;
b) Pro generování tónu o určité frekvenci lze také vytvořit jednu periodu vzorků, které jsou postupně vybírány z cyklického zásobníku. Příklad hodnot 32 vzorků jedné periody sinusovky je přiložen. Jestliže bude zvolena vzorkovací frekvence 44,1 kHz, pak opakované vysílání série těchto vzorků vytvoří tón o frekvenci asi 44,1/32 = 1,38 kHz, tj. pípnutí. 0000, 7fff, 0000, 8001,
18f8, 7d89, e708, 8277,
30fb, 7640, cf05, 89c0,
471c, 6a6c, b8e4, 9594,
5a81, 5a81, a57f, a57f,
6a6c, 471c, 9594, b8e4,
7640, 30fb, 89c0, cf05,
7d89, 18f8, 8277, e708
Generování náhodných čísel
Tento generátor vytváří ve frekvenčním rozsahu do poloviny vzorkovací frekvence bílý šum. Jestliže je tento signál zaveden na vstup navržených filtrů, pak frekvenční spektrum výstupního signálu může demonstrovat správnost její funkce. Generátor čísel využívající kongruence podle Applicataions Handbook, Chapter 4 má následující kód: { .var
}
seed_msw, seed_lsw; si=h#1234; dm(seed_lsw)=si; dm(seed_msw)=si;
deklarace dvou proměnných, tzv. random seed inicializace libovolným číslem před prvním voláním podprogramu
getrnd: { návěští podprogramu pro generování 16bitového náhodného čísla } sr1=dm(seed_msw); sr0=dm(seed_lsw); my1=25; { Upper half of a } my0=26125; { Lower half of a } mr=sr0*my1(uu); { a(hi) X x(lo) } mr=mr+sr1*my0(uu); { a(hi) X x(lo) + a(lo) X x(hi) }
44
si=mr1; mr1=mr0; mr2=si; mr0=h#fffe; mr=mr+sr0*my0(uu); sr=ashift mr2 by 15 (hi); sr=sr or lshift mr1 by -1 (hi); sr=sr or lshift mr0 by -1 (lo); dm(seed_msw)=sr1; dm(seed_lsw)=sr0; rts;
{ c=32767, posun doleva o 1 bit } {(above) + a(lo) X x(lo) + c } { posun doprava o 1 bit }
{ výsledek, náhodné číslo v sr1 }
Podprogram pro dělení
Pro dělení je vhodné použít algoritmů, které připravil výrobce signálového procesoru, tj. firma Analog Devices. Dělení bez znaménka je k dispozici v souboru SDIVQ.DSP, jehož výpis následuje: .MODULE Unsigned_SP_Divide; { Dělení bez znaménka, jednoduchá přesnost Vstupní parametry AF = MSW dělence AY0 = LSW dělence AX0 = 16bitový dělitel Výsledek dělení AY0 = 16bitový výsledek Změněné obsahy registrů AY0, AF Doba výpočtu 18 taktů procesoru } .ENTRY sdivq; {Vstupní bod podprogramu} sdivq:
ASTAT=0; DIVQ AX0; DIVQ AX0; DIVQ AX0; DIVQ AX0; DIVQ AX0; DIVQ AX0; RTS; .ENDMOD;
DIVQ DIVQ DIVQ DIVQ DIVQ
AX0; AX0; AX0; AX0; AX0;
DIVQ DIVQ DIVQ DIVQ DIVQ
AX0; AX0; AX0; AX0; AX0;
{Nuluje AQ bit ASTAT} {Vypočte 16 bitů podílu}
Vstupním bodem je návěští sdivq, které je deklarováno jako ENTRY. Program, který tento podprogram volá, musí mít tento vstupní bod deklarován jako EXTERNAL, tj. .EXTERNAL sdivq;
Výše uvedený podprogram počítá jen s operandy bez znaménka. Výsledek je správný jen pro horní polovinu 32bitového dělence (s více významnými 16 bity) menší než dělitel a pro dělitel menší než nebo roven 0x7FFF. Podprogram pro odmocnění
Rovněž pro odmocnění je vhodné použít algoritmů, které připravil výrobce. Tuto operaci zajišťuje podprogram v souboru SQRT.DSP, jehož výpis následuje: .MODULE Square_root;
45
{
}
Odmocnina y = sqrt(x) Vstupní parametry MR1 = MSW operandu X MR0 = LSW operandu Y M3 = 1 L3 = 0 Výsledek výpočtu SR1 = y ve formátu 8.8 bez znaménka (UNSIGNED) Změněné registry AX0,AY0,AY1,AR,MY0,MY1,MX0,MF,MR,SE,SR,I3 Doba výpočtu 75 taktů procesoru (maximum)
.CONST base=H#0D49, sqrt2=H#5A82; .VAR/DM sqrt_coeff[5]; .INIT sqrt_coeff : H#5D1D, H#A9ED, H#46D6, H#DDAA, H#072D; .ENTRY
sqrt;
sqrt:
I3=^sqrt_coeff; {Ukazatel na coeff. buffer} SE=EXP MR1 (HI); {Kontrola nadbytečných bitů} SE=EXP MR0 (LO); AX0=SE, SR=NORM MR1 (HI); {Odstranění nadbytečných bitů} SR=SR OR NORM MR0 (LO); MY0=SR1, AR=PASS SR1; IF EQ RTS; MR=0; MR1=base; {Přiřazení konstant} MF=AR*MY0 (RND), MX0=DM(I3,M3); {MF = x**2} MR=MR+MX0*MY0 (SS), MX0=DM(I3,M3); {MR = base + C1*x} CNTR=4; DO approx UNTIL CE; MR=MR+MX0*MF (SS), MX0=DM(I3,M3); approx: MF=AR*MF (RND); AY0=15; MY0=MR1, AR=AX0+AY0; {SE + 15 = 0?} IF NE JUMP scale; {Ne, vypočti sqrt(s)} SR=ASHIFT MR1 BY -6 (HI); RTS; scale: MR=0; MR1=sqrt2; {Přiřazení 1/sqrt(2)} MY1=MR1, AR=ABS AR; AY0=AR; AR=AY0-1; IF EQ JUMP pwr_ok; CNTR=AR; {Výpočet (1/sqrt(2))^(SE+15)} DO compute UNTIL CE; compute: MR=MR1*MY1 (RND); pwr_ok: IF NEG JUMP frac; AY1=H#0080; {Přiřazení čísla 1 v 9.23 formátu} AY0=0; {Výpočet převrácené hodnoty MR} DIVS AY1, MR1; DIVQ MR1; DIVQ MR1; DIVQ MR1; DIVQ MR1; DIVQ MR1; DIVQ MR1; DIVQ MR1; DIVQ MR1; DIVQ MR1; DIVQ MR1; DIVQ MR1; DIVQ MR1; DIVQ MR1; DIVQ MR1; DIVQ MR1; MX0=AY0;
46
MR=0; MR0=H#2000; MR=MR+MX0*MY0 (US); SR=ASHIFT MR1 BY 2 (HI); SR=SR OR LSHIFT MR0 BY 2 (LO); RTS; frac: MR=MR1*MY0 (RND); SR=ASHIFT MR1 BY -6 (HI); RTS; .ENDMOD;
Vstupní parametry a výsledek je popsán v komentářové části programu. Je třeba zdůraznit, že se odmocňuje 32bitové číslo a výsledek má poloviční počet bitů, tj. 16. Vstupní bot tohoto podprogramu je třeba deklarovat jako v případě dělení direktivou .EXTERNAL sqrt;
V podprogramu je demonstrována deklarace konstant a proměnných typu zásobník s inicializací hodnot. Některé instrukce jsou multifunkční a vykonávají se sduženě v jednom ctaktu procesoru. Výpočet efektivní hodnoty
Při použití signálového procesoru pro vyhodnocování signálů je často třeba určit efektivní hodnotu (RMS Root Mean Square) vstupního nebo filtrovaného signálu. Pro signál zpracovávaný Vzorec pro výpočet RMS je následující N
RMS =
∑x k =1
N
2 k
,
kde N je počet vzorků x k , 1,..., N . Nechť je časový interval pro výpočet RMS úloze signálovému procesoru zadán příkazem z vnějšku, např. z host počítače nebo z PC po sériové lince, tj. okamžik startu a konce měření pro vyhodnocení vzorků signálu. Dále nechť je požadováno připravit k přenosu do host počítače vypočtenou hodnotu RMS až po příkazu ukončit měření. Programátor tedy musí zajistit následující úkony:
• • •
spočítat počet vzorků za dobu měření průběžně kumulovat obnovovat součet čtverců vzorků v průběhu měření nakonec provést výpočet odmocniny a podílu.
Kapacita 16bitového slova je pro počítání malá, protože s tímto slovem a vzorkovací frekvenci např. 44,1 kHz by se měřilo po dobu asi 1 sekundy. To znamená, že čítač vzorků by měl obsadit aspoň dvě paměťové buňky pro kapacitu několika hodin měření. Druhá mocnina (čtverec) vzorků ve formátu 1.15 je vždy kladné číslo ve formátu 1.31, které bude třeba také uchovávat ve dvou slovech. Hodnoty malých vzorků ovlivní jen obsah méně významného slova. Postupné sčítání například tisíců vzorků může ovšem vést ke značnému přetečení výsledku. Kromě zmíněných dvou slov je třeba ukládat informaci o posunech, které budou předcházet přetečení. Posledním problémem je pořadí výpočtu odmocniny a podílu. Algoritmus dělení předpokládá dělenec 16bitové číslo a algoritmus odmocňování pracuje s 32bitovým číslem. Proto bude výhodné nejprve odmocnit čitatele a jmenovatele výše uvedeného zlomku a pak výsledky podělit.
47
Kód pro počítání vzorků může být naprogramován s využitím jednotky MAC v 7 taktech procesoru. Jednička pro inkrementování o nejméně významný bit se získá vynásobením dvou nejmenších nenulových 16bitovách čísel. mr1 = dm(samlple_no_msw); mr0 = dm(samlple_no_lsw); mx0 = 0x0001; mr = mr + mx0*mx0(ss); dm(samlple_no_msw) = mr1; dm(samlple_no_lsw) = mr0; if mv call measurement_init; { pojistka proti přetečení . . . }
Průběžný výpočet součtu čtverců rovněž využívá jednotky MAC. Navíc oproti předchozímu algoritmu je jen testován výsledek a při přetečení jsou vzorek a mezivýsledky v registrech posouvány vpravo o dva bity což je ekvivalentní dělení 4. Číslo 4 se lehce odmocní na výsledek 2. Exponent není udržován pro součet čtverců, ale přímo pro odmocninu. {
}
again:
mr1 = aktuální vzorek pro aktualizaci sumy vzorků před výpočtem nulovat obsahy těchto buněk square_sum_msw buňka s více významným slovem součtu čtverců square_sum_lsw buňka s méně významným slovem součtu čtverců square_sum_exp buňka s exponentem odmocniny součtu čtverců mx0=dm(square_sum_msw); my0=dm(square_sum_lsw); ax0=dm(square_sum_exp);
{ načtení hodnot z paměti }
ax1= mr1;
{ uložení vzorku do pomocného registru }
si = ax1; se = ax0; sr = ashift si (hi); mr1=mx0; mr0= my0; mr = mr+sr1*sr1(ss);
{ { { { {
výchozí vzorek } příprava posunu o exponent odmocniny } aritmetický posun bitů vzorku vpravo } naplnění registru mr } mr + vzorek^2 }
if not mv rts; si = sr = si = sr = mx0=
{ přetečení výsledku ? }
mx0; { ashift si by -2 (hi); { my0; sr or lshift si by -2 (lo); { sr1; my0= sr0; {
ar = ax0 - 1; ax0= ar; jump again; dm(square_sum_msw)=mx0; dm(square_sum_lsw)=my0; dm(square_sum_exp)=ax0;
dělení square_sum_msw 2^2 = 4 } ekviv. posunu vpravo o 2 bity } dělení square_sum_lsw 4 } a ORorování s square_sum_lsw }
{ zmenšení exponentu o jedničku } { opakování výpočtu s novými hodnotami } { uložení hodnot do paměti }
Po skončení výpočtu jsou aktualizovaná data uložena do paměti. Poslední dva rozhodující kroky výpočtu RMS, a to odmocnění a dělení byly již výše popsány. Při volání podprogramů je třeba pečlivě sledovat formáty čísel.
48
Výpočet Radix-2 FFT metodou DIT
Základem k vyhodnocování spekter signálů metodou výpočtu Fourierovy transformace je algoritmus FFT. V teoretické části byl popsán princip řešení algoritmu FFT metodou decimace posloupnosti vzorků (DIT) a metodou decimace obrazu, tj. frekvenčních složek (DIF). V této části bude pouze analyzován postup výpočtu algoritmu publikovaného aplikačním oddělením firmy Analog Devices. Jedná se o algoritmus založený na DIT a je organizován po etapách (STAGES) jak bylo popsáno v teoretické kapitole o FFT. Algoritmus je naprogramován pro 1024bodovou FFT. Vstupní data jsou načtena z datových souborů inputreal.dat a inputimag.dat, nepocházejí tedy z přímého měření A/D převodníkem. Oba soubory mohou obecně obsahovat nenulová čísla charakterizující „dvourozměrný“ signál, ale příklad kódu předpokládá, že imaginární část vstupních dat je nulová, tj. výpočet je určen jen pro 1024 reálných hodnot. Při inicializaci jsou příslušné cyklické zásobníky, inputreal a inputimag, zaplněny z uvedených souborů. Oba zásobníky jsou v paměti dat situovány od adresy 0x1000 a navazují na sebe. V hlavním modulu jsou deklarovány také další dva pomocné cyklické zásobníky, inplacereal a inplaceimag, v paměti dat od adresy 0x0000, také na sebe navazují. Tato oblast je zaplněna po skončení podprogramu scramble (rozhození pořadí) vstupními daty s pořadím, které vzniklo bitovou reverzací adres se vzestupným pořadím viz teorie výpočtu FFT. V této oblasti je rovněž výsledek výpočtu. V hlavním modulu je navíc inicializovaná také oblast paměti inplaceimag, a to nulami. Mocniny faktoru pootočení (twiddle factor) jsou vypočteny předem a do programu jsou načteny jako konstanty o minimálním možném počtu 512. Protože se jedná o komplexní čísla, je do jednoho cyklického zásobníku twid_real uložena reálná část a do druhého cyklického zásobníku twid_imag imaginární část. Tyto hodnoty jsou vloženy ze souborů twid_real.dat a twid_imag.dat. Naposled jsou deklarovány a inicializovány proměnné groups, bflys_per_group, node_space, blk_exponent. Tyto proměnné se vztahují k počtu skupin motýlků (groups) v jednotlivých etapách, počtu motýlků ve skupině (bflys_per_group) a vzdálenosti uzlů motýlků (node_space) ve smyslu popsaném v teoretickém popisu FFT. Poslední proměnná je blokový exponent (blk_exponent), který je mocnitelem základu 2 a určuje měřítko výstupních hodnot. Proměnná padding je jen pro ladění a v ostrém programu může být vynechána. Proměnné groups, bflys_per_group, node_space jsou inicializovány pro použití od druhé etapy výpočtu. Blokový exponent je nastaven na nulu, tj. na počátku je měřítko výsledků 20 = 1. Čísla pro výpočet jsou předpokládána ve formátu 1.15. Hodnoty faktoru pootočení jsou v rozsahu od –1 do +1. Vstupní data jsou však omezena na rozsah od –0,5 do +0,5. Pro větší rozsah by u motýlků v první etapě výpočtu mohlo dojít k přetečení výsledku. V této etapě výpočtu se dva po sobě jdoucí vzorky sčítají a odečítají. Po inicializacích proměnných se výpočet uskutečňuje voláním dvou podprogramů, a to scramble a fft_strt. .MODULE/ABS=4 dit_fft_main; .CONST N = 1024, N_div_2 = 512; {Const. for 1024 points} .VAR/PM/RAM/CIRC twid_real [N_div_2]; .VAR/PM/RAM/CIRC twid_imag [N_div_2], padding [4]; .VAR/DM/RAM/ABS=0 inplacereal [N], inplaceimag [N]; .VAR/DM/RAM/ABS=H#1000 inputreal [N], inputimag [N];
49
.VAR/DM/RAM .INIT .INIT .INIT .INIT .INIT .INIT .INIT .INIT .INIT .INIT
groups, bflys_per_group, node_space, blk_exponent;
twid_real: ; twid_imag: ; inputreal: ; inputimag: ; inplaceimag: ; groups: N_div_2; bflys_per_group: 2; node_space: 2; blk_exponent: 0; padding: 0,0,0,0;
{Zeros after inplaceimag}
.GLOBAL twid_real, twid_imag; .GLOBAL inplacereal, inplaceimag; .GLOBAL inputreal, inputimag; .GLOBAL groups, bflys_per_group, node_space, blk_exponent; .EXTERNAL scramble, fft_strt; SET FL1; CALL scramble; CALL fft_strt; RESET FL1; .ENDMOD;
{rozsvícení červené led diody} {volání podprogramu} {zhasnutí červené led diody}
Návěští scramble, od kterého podprogram začíná je podprogramu je vstupním bodem stejnojmenného modulu. Jedinou funkcí podprogramu je transformovat pořadí dat ze vstupní oblasti paměti dat od adresy 0x0000 na bitově reverzované pořadí v oblasti paměti dat od adresy 0x1000. Toto rozhození dat se týká jen jejich reálné části, protože imaginární část je nulová. Pro případ zpracování obecných dat toto rozhození pořadí musí být doprogramováno také pro imaginární část vstupních dat. V tomto modulu je demonstrováno použití bitové reverzace adres, tj. její zpřístupnění a zakázání. Jak bylo uvedeno, oblast, do které jsou ukládána data se změněným (rozhozeným) pořadím, začíná adresou 0x0000. Počet vstupních dat je 1024, tj. počet bitů jejich adres je jen 10, tj. méně než 14, pro které reverzace bitů generuje adresy s modifikátorem 1 tak, že tyto adresy zrcadlí kolem rozhranní mezi 7. a 6. bitem. Pro 14bitovou adresu je zrcadlení první adresy prvního údaje v zásobníku správné, ale adresa druhého údaje #b00000000000001
→ zrcadlení pořadí bitů→
#b10000000000000
má velikost adresy se zrcadlovým pořadím bitů mimo rozsah adres vstupních dat. Aby reverzace bitů dávala správný výsledek i pro 10bitovou adresu, je třeba modifikátor indexregistru nastavit na hodnotu 214-10, tj 24 = 16 = 0x0010. Bitově reverzovaná druhá adresa je následující: 0x0010 = #b00000000010000 → zrcadlení pořadí bitů → #b00001000000000 = 0x0200. Výsledek této reverzace bitů druhé adresy v desítkové soustavě je roven 512, tj. polovině počtu hodnot. Data s tímto uspořádáním jsou vstupem pro vlastní výpočet FFT algoritmy s motýlkovými signálovými diagramy. .MODULE dit_scramble; {
Vstupní parametry Vstupní data se vzestupným pořadím v zásobníku inputreal Výstupní parametry Rozhozená vstupní data po bitové reverzaci adres inplacereal
50
}
Změněné registry I0,I4,M0,M4,AY1 Změněná oblast paměti inplacereal
.CONST .EXTERNAL .ENTRY
N=1024, mod_value=H#0010; inputreal, inplacereal; scramble;
scramble: I4=^inputreal; I0=^inplacereal; M4=1; M0=mod_value; L4=0; L0=0; CNTR = N; ENA BIT_REV; DO brev UNTIL CE; AY1=DM(I4,M4); brev: DM(I0,M0)=AY1; DIS BIT_REV; RTS; .ENDMOD;
{Inicializace konstant}
{I4-->Data se vzestupným pořadím} {I0-->Data s rozhozeným pořadím } {M0=modifikátor reverzující N bitů}
{Povolení bitově reverzované adresy DAG1} {Čtení vstupních dat se vzestupným pořadím} {Zápis dat do bitově reverzovaných adres} {Disable bit-reverse} {Návrat z podprogramu}
Vlastní výpočet je naprogramován v modulu fft od návěští fft_strt. Pro daný počet vzorků N (= 1024) jsou výpočty rozděleny do log2 N (= 10) etap (STAGES). První a poslední etapa výpočtů je naprogramována zvlášť. V prvé etapě nabývají mocniny faktoru pootočení jen hodnot 0 a 1, a proto odpadá násobení těmito mocninami. Rovněž struktura motýlků je jednoduchá. Také poslední etapa výpočtů se programuje zvlášť. Pro první a poslední etapu výpočtu jsou zavedeny zvláštní konstanty nover2 a nover4 (není použita). V těchto etapách je jen jedna smyčka. Ve smyčce výpočtů v prostředních etapách je vnořena smyčka pro skupiny motýlků a do této smyčky další smyčka pro motýlky jedné skupiny. Po každém výpočtu části motýlkového diagramu ve všech etapách je kontrolován exponent tohoto výsledku instrukcí EXPADJ. V registru SB, který je přednastaven na –2 je tedy zaregistrována případná přítomnost výsledku s exponentem 0 nebo –1. Na konci výpočtu každé etapy je podprogramem bfp_adj z modulu dit_radix_2_bfp_adjust kontrolován obsah registru SB, a v případě, že jeho obsah je větší než –2 (tj. –1 nebo 0), jsou všechny výsledky výpočtů v dané etapě dvakrát nebo čtyřikrát zmenšeny. Tato úprava měřítka mezivýsledků má za cíl zabránit v následující etapě výpočtů, pro kterou jsou tyto mezivýsledky vstupem, vznik přetečení některého mezivýsledku. Velikost posunu po každé etapě se kumuluje v proměnné blk_exponent. Jednotlivé přiřazovací příkazy jsou komentovány a jejich značení odpovídá motýlkovému diagramu z teoretické části. Pro vstupní hodnoty je použito označení x0, y0, x1 a y1, a pro mocniny faktoru pootočení je použito označení C a S. Po výpočtu poslední etapy jsou výsledky uloženy v paměti dat od adresy 0x0000, tj. v zásobnících nazvaných inplacereal a inplaceimag. Reálná a imaginátní část výsledků je uspořádána vzestupně. .MODULE {
fft; Vypočte Radix-2 DIT FFT Vstupní parametry
51
inplacereal = reálná část vstupních dat inplaceimag = nuly (reáná čísla jsou předpokládána) twid_real = Twiddle factor, hodnoty kosinus twid_imag = Twiddle factor, hodnoty sinus groups = N/2 bflys_per_group = 1 node_space = 1 Výstupní parametry inplacereal = reálná část výsledků se vzestupným pořadím inplaceimag = imaginární část výsledků se vzestup. pořadím Změněné registry I0,I1,I2,I3,I4,I5,L0,L1,L2,L3,L4,L5 M0,M1,M2,M3,M4,M5 AX0,AX1,AY0,AY1,AR,AF MX0,MX1,MY0,MY1,MR,SB,SE,SR,SI Změněna paměť inplacereal, inplaceimag, groups, node_space, bflys_per_group, blk_exponent
} .CONST
log2N=10, N=1024, nover2 = 512, nover4 = 256;
.EXTERNAL .EXTERNAL .EXTERNAL .EXTERNAL
twid_real, twid_imag; inplacereal, inplaceimag; groups, bflys_per_group, node_space; bfp_adj;
.ENTRY
fft_strt;
fft_strt: CNTR=log2N - 2; {Initialize stage counter} M0=0; M1=1; L1=0; L2=0; L3=0; L4=%twid_real; L5=%twid_imag; SB= -2;
L6=0;
{------------------STAGE 1-------------------------} i0 = ^inplacereal; i1 = ^inplacereal + 1; i2 = ^inplaceimag; i3 = ^inplaceimag + 1; m2 = 2; cntr = nover2; ax0 = dm(i0,m0); ay1 = dm(i3,m0);
ay0 = dm(i1,m0);
do group_lp until ce; ar=ax0+ay0, ax1=dm(i2,m0); sb=expadj ar, dm(i0,m2)=ar; ar=ax0-ay0; sb=expadj ar; dm(i1,m2)=ar, ar=ax1+ay1; sb=expadj ar, dm(i2,m2)=ar; ar=ax1-ay1, ax0=dm(i0,m0); sb=expadj ar, dm(i3,m2)=ar; ay0=dm(i1,m0); group_lp: ay1=dm(i3,m0); call bfp_adj; {---------------- STAGE 2 to nover2 – 1 -----------} DO stage_loop UNTIL CE; I0=^inplacereal;
{Compute all stages in FFT} {I0 -->x0 in 1st grp of stage}
52
I2=^inplaceimag; SI=DM(groups); SR=ASHIFT SI BY -1(LO); DM(groups)=SR0; CNTR=SR0; M4=SR0; M2=DM(node_space); I1=I0; MODIFY(I1,M2); I3=I2; MODIFY(I3,M2);
{I2 -->y0 in 1st grp of stage} {groups / 2} {groups = groups / 2} {CNTR = group counter} {M4=twiddle factor modifier} {M2=node space modifier} {I1 -->y0 of 1st grp in stage} {I3 -->y1 of 1st grp in stage}
DO group_loop UNTIL CE; I4=^twid_real; {I4 --> C of W0} I5=^twid_imag; {I5 --> (-S) of W0} CNTR=DM(bflys_per_group); {CNTR = butterfly counter} MY0=PM(I4,M4),MX0=DM(I1,M0); {MY0=C,MX0=x1 } MY1=PM(I5,M4),MX1=DM(I3,M0); {MY1=-S,MX1=y1} DO bfly_loop UNTIL CE; MR=MX0*MY1(SS),AX0=DM(I0,M0); {MR=x1(-S),AX0=x0} MR=MR+MX1*MY0(RND),AX1=DM(I2,M0); {MR=(y1(C)+x1(-S)),AX1=y0} AY1=MR1,MR=MX0*MY0(SS); {AY1=y1(C)+x1(-S),MR=x1(C)} MR=MR-MX1*MY1(RND); {MR=x1(C)-y1(-S)} AY0=MR1,AR=AX1-AY1; {AY0=x1(C)-y1(-S),} {AR=y0-[y1(C)+x1(-S)]} SB=EXPADJ AR,DM(I3,M1)=AR; {Check for bit growth,} {y1=y0-[y1(C)+x1(-S)]} AR=AX0-AY0,MX1=DM(I3,M0),MY1=PM(I5,M4); {AR=x0-[x1(C)-y1(-S)],} {MX1=next y1,MY1=next (-S)} SB=EXPADJ AR,DM(I1,M1)=AR; {Check for bit growth,} {x1=x0-[x1(C)-y1(-S)]} AR=AX0+AY0,MX0=DM(I1,M0),MY0=PM(I4,M4); {AR=x0+[x1(C)-y1(-S)],} {MX0=next x1,MY0=next C} SB=EXPADJ AR,DM(I0,M1)=AR; {Check for bit growth,} {x0=x0+[x1(C)-y1(-S)]} AR=AX1+AY1; {AR=y0+[y1(C)+x1(-S)]} bfly_loop: SB=EXPADJ AR,DM(I2,M1)=AR; {Check for bit growth,} {y0=y0+[y1(C)+x1(-S)]} MODIFY(I0,M2); {I0 -->1st x0 in next group} MODIFY(I1,M2); {I1 -->1st x1 in next group} MODIFY(I2,M2); {I2 -->1st y0 in next group} group_loop: MODIFY(I3,M2); {I3 -->1st y1 in next group} CALL bfp_adj; {Compensate for bit growth} SI=DM(bflys_per_group); SR=ASHIFT SI BY 1(LO); DM(node_space)=SR0; {node_space=node_space * 2} stage_loop: DM(bflys_per_group)=SR0; {bflys_per_group= } {bflys_per_group * 2} {-----------------------
LAST STAGE
--------------------------}
i0 =^inplacereal; i1 =^inplacereal + nover2; i2 =^inplaceimag; i3 =^inplaceimag + nover2; cntr = nover2; m2 = dm(node_space); m4 = 1; i4 =^twid_real; i5 =^twid_imag; MY0=PM(I4,M4),MX0=DM(I1,M0);
{MY0=C,MX0=x1 }
53
MY1=PM(I5,M4),MX1=DM(I3,M0); DO bfly_lp UNTIL CE; MR=MX0*MY1(SS),AX0=DM(I0,M0); MR=MR+MX1*MY0(RND),AX1=DM(I2,M0);
{MY1=-S,MX1=y1} {MR=x1(-S),AX0=x0}
{MR=(y1(C)+x1(-S)),AX1=y0} {AY1=y1(C)+x1(-S),MR=x1(C)} {MR=x1(C)-y1(-S)} {AY0=x1(C)-y1(-S),} {AR=y0-[y1(C)+x1(-S)]} SB=EXPADJ AR,DM(I3,M1)=AR; {Check for bit growth,} {y1=y0-[y1(C)+x1(-S)]} AR=AX0-AY0,MX1=DM(I3,M0),MY1=PM(I5,M4); {AR=x0-[x1(C)-y1(-S)],} {MX1=next y1,MY1=next (-S)} SB=EXPADJ AR,DM(I1,M1)=AR; {Check for bit growth,} {x1=x0-[x1(C)-y1(-S)]} AR=AX0+AY0,MX0=DM(I1,M0),MY0=PM(I4,M4); {AR=x0+[x1(C)-y1(-S)],} {MX0=next x1,MY0=next C} SB=EXPADJ AR,DM(I0,M1)=AR; {Check for bit growth,} {x0=x0+[x1(C)-y1(-S)]} AR=AX1+AY1; {AR=y0+[y1(C)+x1(-S)]} bfly_lp: SB=EXPADJ AR,DM(I2,M1)=AR; {Check for bit growth,} call bfp_adj; AY1=MR1,MR=MX0*MY0(SS); MR=MR-MX1*MY1(RND); AY0=MR1,AR=AX1-AY1;
RTS; .ENDMOD;
Podprogram od návěští bfp_adj upravuje výstupní data každé etapy výpočtu podle velikosti blokového exponentu, který je uložen v registru SB. Jestliže blokový exponent má hodnotu –1 nebo 0, pak se výsledky z dané etapy upraví násobením konstantou, jejíž hodnota je ekvivalentní dělení 2 nebo 4, aby do další etapy vstupovaly opět s blokovým exponentem nejvýše –2. Každý posun je zaznamenán přírůstkem obsahu proměnné blk_exponent. Účelem této kontroly je předejít přetečení výsledků. .MODULE dit_radix_2_bfp_adjust; {
}
Vstupní parametry Výsledky v inplacereal a inplaceimag proměnných Výstupní parametry inplacereal a inplaceimag adjusted for bit growth Změněné registry I0,I1,AX0,AY0,AR,MX0,MY0,MR,CNTR Změněná paměť inplacereal, inplaceimag, blk_exponent
.EXTERNAL inplacereal, blk_exponent; .ENTRY bfp_adj; bfp_adj: AY0=CNTR; AR=AY0-1; IF EQ RTS; AY0=-2; AX0=SB; AR=AX0-AY0; IF EQ RTS; I0=^inplacereal; I1=^inplacereal;
{Begin declaration section}
{Check for last stage} {If last stage, return} {Check for SB=-2} {IF SB=-2, no bit growth, return} {I0=read pointer} {I1=write pointer}
54
AY0=-1; MY0=H#4000; {Set MY0 to shift 1 bit right} AR=AX0-AY0,MX0=DM(I0,M1); {Check if SB=-1; Get first sample} IF EQ JUMP strt_shift; {If SB=-1, shift block data 1 bit} AY0=-2; {Set AY0 for block exponent update} MY0=H#2000; {Set MY0 to shift 2 bits right} strt_shift: CNTR=2047; {initialize loop counter} DO shift_loop UNTIL CE; {Shift block of data} MR=MX0*MY0(RND),MX0=DM(I0,M1); {MR=shifted data,MX0=next value} shift_loop:DM(I1,M1)=MR1; {Unshifted data=shifted data} MR=MX0*MY0(RND); {Shift last data word} AY0=DM(blk_exponent); {Update block exponent and} DM(I1,M1)=MR1,AR=AY0-AX0; {store last shifted sample} DM(blk_exponent)=AR; SB = -2; RTS; .ENDMOD;
Popis funkčních vlastností karty EZ-KIT Lite K osvojení programování a vlastností signálového procesoru ADSP-2181 lze pořídit poloprofesionální kartu s několika součástkami. Karta má rozměry 3,5 x 5,5 palce a lze ji položit na stůl vedle počítače. Mimo několika podpůrných součástek (odporů a kondenzátorů) je na kartě signálový procesor ADSP-2181, CODEC AD1847, paměť PROM, obvod ADM232AAR pro transformaci napětí k ovládání sériové linky RS 232 a šestice invertorů v jednom IO. Ke kartě náleží také základní software. Patří k němu překládač asembleru, linker přeložených objektů a spliter pro generování souborů k zápisu do programovatelné paměti PROM. V dodané paměti PROM je monitorovací program. Monitor komunikuje s tzv. host programem v PC. Host program obsahuje několik demonstračních programů na filtraci kompresi řeči, odstranění dozvuku a simulaci tónové volby telefonu a hlavně podporu pro zápis a čtení bloků obou pamětí signálového procesoru a spouštění podprogramů obsažených v programové paměti. Příkon karty je na 8 až 10V 300 mA. Přítomnost napájecího napětí indikuje svit zelené LED diody. Na kartě jsou dvě tlačítka. Jedno je resetovací a druhé inicializuje přerušení na vývodu IRQE . Analogový vstup a výstup se připojuje dvěma stereo jacky, průměr 3,5 mm. Sériový port (RS232) se připojuje na D-Sub konektor s 9 vývody. K volbě analogového typu vstupu je na kartě přepínač (switch) JP2. Lze volit 2V RMS střídavě vázaný vstup nebo 20 mV mikrofonní vstup. Všechny vývody signálového procesoru jsou dostupní na 50vývodovém konektoru na okraji karty. Paměť EPROM je připojena k procesoru přes Byte DMA Port a využívá jen 8 z 24 bitů (D16 až D23) z 24 bitové sběrnice a je určena k zavedení programu do paměti procesoru po resetu nebo připojení napájecího napětí. Ze tří možných kombinací je zvoleno (MMAP = 0 a BMODE = 0), tj. přes Byte DMA Port. Nejprve se zavede 32 prvních slov od adresy PM(0x0000) a pak se spustí program pro načtení. Na kartu lze umístit EPROM s kapacitou od 256K do 8 M bitů. V továrním provedení lze použít obvod 27C512 (64K bajtů) nebo 27C010 (256K). Změnou propojek na JP1 lze použít také větší paměti. Codec AD1847 je připojen prostřednictvím sériového portu SPORT0. Vysokorychlostní spojení umožňuje předávání dat, informací o stavu a řízení. Je možné, aby CODEC byl znepřístupněn. Na rozšířeném konektoru P3 (při okraji karty) je v tomto případě třeba uzemnit vývod CODECDIS . Popisu obvodu bude věnována zvláštní kapitola.
55
Vývody sériového portu SPORT1 jsou použity ke komunikaci s host PC přes RS-232 interface. Data jsou přenášena vývody Flag_IN a Flag_Out. Přijímaná data jsou napojena rovněž na vývod IRQ1 inicializující přerušení, takže DSP nemusí opakovaně žádat (polling) příchod dat na vývod Flag_In. Software DSP emuluje obvod UART a vlastním protokolem spojení komunikuje rychlostí 9600 bitů za vteřinu, pro 8 bitů bez parity a jedním stop bitem. Invertory jsou použity ke resetu při přivedení napětí, stisku resetovacího tlačítka, dva jsou použity k obsluze přerušovacího tlačítka a pátý invertor je použit k napájení červené LED diody. IDMA Port není v EZ-KIT Lite použit. Stereo codec AD1847
Blokové schéma zapojení codecu AD1847 je na obr. XXXX. Dvoukanálový analogový vstup má vstupní rozsah o velikosti 2V efektivní hodnoty harmonického signálu a dvoukanálový výstup má rozsah 1V efektivní hodnoty harmonického signálu. Vstupy jsou střídavě vázány a proto jejich frekvenční rozsah nezačíná měřením stejnosměrného napětí. V případě zvukových karet s tímto typem převodníku je použit analogový hornopropustný filtr prvního řádu s frekvencí zlomu 5 Hz. Podle dokumentace je spodní hranice frekvenčního pásma měření 20 Hz. Typ převodníku je Σ∆ (sigma-delta). K jeho funkci patří vysoce účinná antialiasingová filtrace. V pásmu od 0,45 do 0,6 násobku vzorkovací frekvence je pokles antialiasingového filtru pro vstup a výstup 80 dB. Frekvence vzorkování je volitelná po skocích od 5,5 do 48 kHz. Analogový vstup a výstup obvodu AD1847 má programovatelné zesílení a útlum. Rovněž lze jak analogový tak číslicový signál ze vstupu přivádět přímo po zeslabení na jeho výstup. Parametry převodníku se zadávají zaplněním 13 registrů. Převodníky pracují s číslicovými daty 16bitovými (dvojkovými doplněk), 8bitovými a 8bitovými komprimovanými podle norem A-law nebo µ-law. Nevýhodou codecu je velké dopravní zpoždění převodu. Převod A/D a následně D/A má zpoždění 12 ms. Hodinový kmitočet procesoru je 33 MHz. Ze známé vzorkovací frekvence f s lze vypočítat počet taktů, které procesor může uskutečnit při zpracování změřeného vzorku (viz následující tabulka) za předpokladu, že DSP neprovádí žádné další operace. Pro nejnyšší vzorkovací frekvenci není taktů procesoru mnoho a při programování se musí šetřit s každou instrukcí. fs v kHz počet taktů
5,51 5986
6,62 4989
9,60 11,03 16,00 18,00 22,05 27,43 32,00 33,08 37,80 44,10 48,00 3438 2993 2063 1833 1497 1203 1031 998 873 748 688
56
Obr. XXXX Blokové schéma codecu AD1847 Codec AD1847 má šest 16bitových registrů a 13 osmibitových registrů (jsou adresovány od 0 do 13, přičemž 11 je neplatná). Řídicí informace jsou do codecu posílány v jednom 16bitové slově (Control Word), přičemž prostřednictvím Index Readback Output mohou být přečteny zpět. Informace o stavu jsou z codecu vysílány také v jednom 16 bitovém slově (Status Word). Další čtyři 16bitové registry jsou určeny pro vstupní a výstupní data z /do levého a pravého kanálu. Každí slovo má svůj „slot“ (přihrádku) v časovém dělení sériově přenášených informací. EZ-KIT Lite je navržen pro TSSEL = 0, a proto podle dokumentace codecu je rozdělení slotů následující: Slot 0 1 2 3 4 5
Jméno 16bitového registru Control Word Input Left Playback Data Input Right Playback Data Input StatusWord/Index Readback Output Left Capture Data Output Right Capture Data Output
Pro funkci codecu má zvláštní význam obsah 16bitového Control Word, kterým lze měnit nastavení nejen analogové části A/D a D/A převodníku, ale také například vzorkovací frekvenci. Control Word 15 14 CLOR MCE 7 6 DATA7 DATA6
13 RREQ 5 DATA5
12 rezerva 4 DATA4
11 IA3 3 DATA3
57
10 IA2 2 DATA2
9 IA1 1 DATA1
8 IA0 0 DATA0
• • • • •
CLOR: Clear Overange při HI znamená zruš příznak překročení rozsahu, který je posílán ve Status Word. Při LO zůstane příznak přerušení nezměněn také při zmenšení měřené veličiny pod mezní hodnoty MCE: Mode Change Enable. Musí být nastaven na HI, kdykoliv jsou měněny chráněné řídicí registry. Obsahy registrů Data Format, Miscellaneous Information a ACAL bit v Interface Configuration nemohou být měněny jestliže tento bit není HI RREQ Read Request: Nastavením tohoto bitu na HI se požaduje zpětné čtení obsahu některého z 13 registrů. IA3 až IA0 Index Register Address: Adresy 13 osmibitových registrů DATA7 až DATA0 Index Register Data: Data určena pro 13 osmibitových registrů.
Bezprostředně po resetu je tento registr zaplněn 0xC000. Kontrola obsahu Status Word nabízí následující možnosti: Status Word 15 14 13 12 11 10 9 8 rezerva rezerva RREQ rezerva ID3 ID2 ID1 ID0 7 6 5 4 3 2 1 0 rezerva rezerva ORR1 ORR0 ORL1 ORL0 ACI INIT • RREQ Read Request: Nastavením tohoto bitu na LO odpovídá AD1847 na nastavení tohoto bitu v Control Word • ID3 až ID0: Číslo revize zapojení AD1847 • ORL1 až 0: Úroveň signálu v levém kanálu (0 méně než 1 dB pod max přípustnou hodnotou, 1 méně než 1 dB pod max hodnotou, 2 překročení o méně než 1 dB, překročení o více než 1 dB) • ORR1 až 0: Úroveň signálu v pravém kanálu (0 méně než 1 dB pod maximálně přípustnou hodnotou, 1 méně než 1 dB pod maximální hodnotou, 2 překročení o méně než 1 dB, překročení o více než 1 dB) • ACI Autocalibrate In-Progres: Při HI pokračuje autokalibrace převodníku • INIT: Tento bit indikuje, že synchronizace rámců (frame) bude zastavena a sériová sběrnice bude vypnuta.
Osmibitové registry jsou přístupné nepřímým adresováním prostřednictvím Control Word. Seznam s účinkem jednotlivých registrů následuje. Význam jednotlivých bitů bude komentován v ukázkovém programu.
58
Index 0 1 2 3 4 5 6 7 8 9 10 11 12 13
Jméno 8bitového registru Left Input Control Right Input Control Left Aux #1Input Control Right Aux #1Input Control Left Aux #2Input Control Right Aux #2Input Control Left DAC Control Right DAC Control Data Format Interface Configuration Pin Control Invalid Address Miscellaneous Information Digital Mix Control
Codec AD1847 komunikuje s DSP po sériovém spojení tak, že vysílá a přijímá tři 16bitová slova za jednu vzorkovací periodu. V programu je třeba deklarovat dva cyklické zásobníky po 3 16bitových slovech, a to například tx_buf pro vysílání a rx_buf pro příjem. Codec přijímá z DSP řídicí slovo (Contro Word) a dva číslicové údaje pro D/A převodník levého a pravého stereo kanálu a vysílá informaci o stavu A/D převodníku (Status Word) a dva číslicové údaje z A/D převodníku.
Monitor EZ-KIT Lite Monitor je program v DSP, který se zavede do paměti signálového procesoru z připojené ROM paměti po zapnutí napájení nebo po resetu. Monitor vykonává tyto funkce
• otestuje DSP po resetu nebo připojení napájení • inicializuje codec AD1847 a zajistí nefiltrovaný průchod z A/D do D/A převodníku (talk through) • emuluje obvod UART pro rychlost přenosu 9600 bps • zajistí přenos obsahu paměti programu a dat mezi DSP a PC v obou směrech. Omezení, která způsobuje funkce monitoru, vyplývají z následujících údajů
• monitor obsazuje paměť programu v rozsahu adres 0x3800 až 0x3FFF a paměť dat v rozsahu 0x3E00 až 0xFDF, které jsou pro zaváděný program proto nepoužitelné • zaváděný program musí být napsán jako podprogram, tj. jeho funkce musí končit instrukcí RTS v případě, že je žádoucí používat služeb monitoru i po skončení programu. Pro uživatele je tedy přístupná paměť programu v rozsahu od 0x0000 do 0x37FF a paměť dat v rozsahu od 0x0000 do 0x3DFF. Při psaní programu je třeba dodržovat tyto zásady
• zavedený uživatelský program začíná od adresy paměti programu 0x0000, což se specifikuje direktivou .MODULE/RAM/abs=0 • všechna přerušení jsou před startem zavedeného uživatelského programu maskována (IMASK = 0) proto, aby bylo možné bezpečně provést inicializaci a obnovení funkce přerušovacího systému • uživatelský program musí inicializovat vektor přerušení; je třeba vzít na vědomí, že přerušení IRQ1 je určeno pro komunikaci prostřednictvím RS 232 (na místo obsluhy tohoto přerušení, tj. od 0x0020 do 0x0023, lze umístit prázdné instrukce RTI) 59
Monitor lze ovládat řadou příkazů. Název, přijaté příkazy (received) a vyslaná odpověď (sent) jsou následující (text v hranatých závorkách reprezentuje horní a dolní část 16bitového obsahu buněk paměti) 1. Beep (krátké pípnutí) received: $$$ sent: ok[led count][alive called count][self test hi][selftest lo] [led count] dolních 8 bitů čítače inkrementovaného frekvencí 28800 Hz [alive called count] inkrementovano o 1 po každém volání [self test hi][selftest lo] horní a dolní část registru s výsledkem testu 2. Test správnosti funkce (bez pípnutí) received: $OK sent: ok[led count][alive called count][self test hi][selftest lo] 3. Vyslání (upload) specifikované části paměti dat received: $UD[hi start][lo start][hi len][lo len] sent: [hi][lo] . . . [hi sum][lo sum]$! [hi start] [lo start] adresa první přenášené buňky paměti [hi len][lo len] počet přenášených buněk [hi][lo] přenášená data (opakovaně 16 bitů) [hi sum][lo sum] 16bitový kontrolní součet 4. Vyslání (upload) specifikované části paměti programu received: $UP[hi start][lo start][hi len][lo len] sent: [hi][mi][lo] . . . [hi sum][mi sum] [lo sum]$! [hi start] [lo start] adresa první přenášené buňky paměti [hi len][lo len] počet přenášených buněk [hi][mi][lo] přenášená data (opakovaně 24 bitů) [hi sum][mi sum][lo sum] 32bitový kontrolní součet 5. Příjem (download) specifikované části paměti dat received: $DD[hi start][lo start][hi len][lo len] [hi][lo] . . . sent: ![hi sum][lo sum] 6. Příjem (download) specifikované části paměti programu received: $DP[hi start][lo start][hi len][lo len] [hi][mi][lo] . . . sent: ![hi sum][mi sum] [lo sum] 7. Start zavedeného programu received: $GO[hi address][lo address] sent: ![hi address][lo address] [hi address] [lo address] adresa začátku programu Výpis zdrojového kódu monitoru je součástí software EZ-KIT Lite. Při řešení vlastního software, který má nahradit monitor, je výhodné převzít kód emulující UART.
Postup návrhu uživatelstkého programu Obecný postup vytvoření specializovaného systému v 5 krocích za předpokladu použití všech podpůrných prostředků je znázorněn na diagramu na obr. XXXX. Tento text se však orientuje na školní vývojový systém EZ-KIT Lite bez zvláštní výbavy, a proto některé kroky budou vynechány. 60
Obr. D-V System development diagram Popis architektury systému
Prvním obecným krokem k vytvoření vlastního je definice požadavků a návrh hardwarové struktury. Tento krok nebude podrobně analyzován a okamžitě bude předpokládáno, že je k dispozici EZ-KIT Lite se signálovým procesorem ADSP-2181 spolu se stereo codecem AD1847. Pro překlad vytvořeného kódu je důležitá architektura systému. Soubor popisující architekturu vytvoří program System Builder. Vstupem pro tento program je textový soubor s definicí rozsahu (rozsah absolutních adres paměti programu a paměti dat) a typu pamětí (RAM, ROM), jehož výpis je následující .system demo; .adsp2181; .mmap0; .seg/pm/ram/abs=0/code/data .seg/pm/ram/abs=8192/code/data .seg/dm/ram/abs=0/code/data .seg/dm/ram/abs=8192/code/data .endsys;
int_pm_lo[8192]; int_pm_hi[8192]; int_dm_lo[8192]; int_dm_hi[8160];
Paměť programu je rozdělena na dva 8K segmenty. První je určen k internímu použití, zatímco druhý může být programován buď jako interní nebo také pro externí paměť (podle obsahu registru PMOVLAY). Rovněž paměť dat je rozdělena na dva segmenty. Posledních 32 buněk paměti dat je určeno pro paměťově mapované registry. Výstupem programu System Builder je textový soubor ADSP2181.ACH (System Architecture File), jehož obsah je následující $2181 $ADSP2181 $0000 3FFF paxINT_PM_USER t
61
$0000 3FDF dadINT_DM_USER t $
Tento soubor je potřebný při linkování programu a je k dispozici při použití EZ-KIT Lite v adresáři BIN s překladačem, linkerem a spliterem. Vytvoření zdrojového kódu uživatelského programu
Nejdůležitějším krokem je vytvoření vlastního kódu uživatelského programu. Také zkušený programátor neváhá a použije obvykle nějaký demonstrační program, který postupně přestaví pro jiné funkce. Kód programu lze upravovat v textovém editoru, například NOTEPAD.EXE (Poznámkový blok). Implicitně očekávaná přípona jména programu je .DSP. V tomto případě stačí překládači uvést jako parametr jméno bez přípony. Nechť se programátor rozhodne nazvat svůj program my_prog.dsp. Při tvorbě programu je třeba uvažovat o způsobu využívání programu v tom smyslu, zda bude procovat současně s monitorem nebo nezávisle na něm. Program lze vytvořit tak, že jej lze po odladění naprogramovat do paměti ROM EZ-KIT Lite. V tomto případě se po přivedení napájecího napětí program automaticky zavede (bootuje) a spustí. Jinou možností je, že bude spouštěn pod dohledem monitorovacího programu EZ-KIT Lite. V tomto případě je vytvářený program koncipován jako procedura, která se ukončuje instrukcí rts; Příkaz k ukončení této procedury je třeba nějakým způsobem sdělit. Překlad zdrojového kódu
Dalším krokem je překlad zdrojového programu asemblerem ASM21.EXE. Obecný způsob spuštění asembleru pro zdrojový kód v souboru sourcefile.dsp je asm21 sourcefile
[-switch . . .]
-2181
Přepínače switch programu asm21 jsou následující -c -l -m [depth] -i [depth] -o filename -dident [=literal] -s -2181
Nastavení citlivosti na velká a malá písmena (case sensitivity) Generuje se .LST soubor Expandované macro v .LST souboru Ukáží se obsahy INCLUDE souborů v .LST souboru Přejmenuje výstupní soubor na filename.obj (přednastaveno je sourcefile.obj) Definuje identifikátor pro asemblerovský C preprocesor Vypnuta sématická kontrola multifunkčních instrukcí Užijí se speciální instrukce ADSP-2181
Pro výše uvedený zdrojový kód programu my_prog.dsp lze použít následující spuštění programu asm21 my_program -2181
Během překladu jsou generovány informace o chybách. Popis chyb usnadní jejich opravu. Po úspěšném překladu vznikne soubor my_program.obj. Linkování EXE programu pro DSP
Po bezchybném překladu lze přistoupit k linkování programu. Program pro linkování se nazývá LINKER.DSP. ld21 file1 [file2 . . .] [-switch . . .]
62
nebo ld21 –i file_all [-switch . . .]
Přepínače a parametry programu ld21 jsou následující .ACH soubor (je třeba zadat ADSP2181.ACH) Textový soubor obsahující výčet linkovaných souborů (soubory jsou bez přípony) -e executable Výstupní soubor má jméno executable.exe (přednastaveno 210x.exe -dryrun Spustit linkovaný soubor bez jeho vytvoření -g Generován soubor .SYM obsahující tabulku symbolů -x Generuje se .MAP soubor s paměťovou mapou -user fastlibr Hledání knihovních souborů knihovníkem -dir directory Specifikace adresářů k hledání knihovních podprogramů -p Přiřadí knihovní podprogramy k bootovacím stránkám když budou volány -a archfile -i file_all
Jestliže program my_prog.dsp nepoužívá žádné další moduly, pak ke spuštěni linkeru stačí příkaz asm21 my_program –a adsp2181 –e my_program
Rovněž během linkování jsou generovány informace o chybách. V případě bezchybného linkování je do signálového procesoru ADSP-2181 proveditelný program my_pro.exe. Zavedení EXE souboru do DSP
Po bezchybném linkování lze program spustit. K zavedení programu do paměti DSP lze využít aplikaci EZKITAPP.EXE vytvořenou pro operační systém Windows, která se nazývá EZ-KIT Lite Host Program a která patří rovněž k podpůrným prostředkům EZ-KIT Lite. Aplikace Monitor v PC komunikuje s programem Monitor v DSP prostřednictvím sériového spojení RS 232. Kromě zavedení a spuštění vestavěných demoprogramů pro DSP umožňuje tato aplikace také přečíst (Upload) a zavést (Download) úseky datové a programové paměti DSP. Pro zavedení a spuštění proveditelného programu (přípona EXE) pro DSP je vhodné použít volbu Download and Go.
Obr. D-V Okno aplikace EZ-KIT Lite Host Program
63
Ladění programu (debugging)
Proveditelný program (přípona .EXE) lze ladit simulačním programem SIM2181, který je součástí software EZ-KIT Lite. Ovládání tohoto programu nebude popisováno. Asembler není prostředek, kterým lze vytvářet velmi komplikované programy, a proto má větší význam dokonalé pochopení funkce kódu programu než dodatečné prohlížení registrů a paměti simulačním programem za účelem jeho analýzy. Kromě analogového signálu z D/A převodníku lze funkci programu pozorovat z jediné červené LED diody, kterou lze ovládat vývodem FL1 následujícími instrukcemi [IF cond] SET FL1 ; RESET TOGGLE Jinou možností je komunikace prostřednictvím RS 232, kterou je třeba zvlášť naprogramovat. Funkci signálového procesoru týkající se transformace analogového signálu lze kontrolovat pomocí zvukové karty počítače. Zvukovou kartou lze vygenerovat žádoucí signál a také zaznamenat. Ke generování souboru WAV a k jeho analýze lze použít MATLAB, zvláště jeho toolbox Signal Processing. Generování souboru k naprogramování EPROM
Nahrání programu do PROM je účelné v případě, kdy zavedení prostřednictvím aplikace EZ-KIT Lite Monitor obsluhu zdržuje a DSP je určeno pro vykonávaní pouze jedné specializované činnosti, kterou lze případně měnit volbami prostřednictvím obslužné aplikace v PC. K přípravě souboru k nahrání do EPROM slouží program PROM Spliter. spl21 exe_file promfile –pm [-switch . . .]
nebo spl21 exe_file promfile –dmm [-switch . . .]
nebo spl21 exe_file promfile –loader –2181 [-s] [-i]
Přepínače a parametry programu spl21 jsou následující -pm -dm -s -i -us -us2 -ui -loader –2181
Extrahuje informace o ROM programové paměti Extrahuje informace o ROM datové paměti Formát souboru PROM: Motorola S record (přednastaveno) Formát souboru PROM: Intel Hex record Formát souboru PROM: Motorola S record byte stream Formát souboru PROM: Motorola S2 record byte stream Formát souboru PROM: Intel Hex record byte stream Generuje
Program my_prog.exe se převede programem PROM Spliter na soubor my_PROM.bnm (Motorola S record format) pro nahrání do paměti PROM, která je připojena k DSP a slouží k bootování po zapnutí nebo resetu. asm21 my_program my_PROM.bnm –loader -2181
Jestliže jsou pochybnosti o funkčnosti programu, je výhodné používat simulátoru PROM paměti a teprve nakonec použít programátoru pamětí PROM.
64
Povinná část programu v DSP V této části budou probrány postupně částí programu, které jsou nezbytné při použití codecu AD1847 a spojení s host počítačem s využitím podprogramů v modulu emulujícím UART. Tento popis je úvodem k analýze demo programu FIRDEMO.DSP. Jednotlivé kroky jsou však řazeny tak, že umožňují vytvořit kód, který poběží samostatně bez podpory monitorovacího programu. Definice adres odkazujících na paměťově mapované registry
Jak již bylo uvedeno, část registrů je paměťově mapována v paměti dat. Odkaz na tyto registry může být s použitím adresy ve formě šestnáctkového čísla, což je značně nepřehledné, nebo lépe ve formě definované konstanty nahrazující příslušnou adresu pojmenováním registru ve tvaru řetězce znaků. Souvislost mezi adresami a jmény registrů určují následující direktivy: .const .const .const .const .const .const .const .const .const .const .const .const .const .const .const .const .const .const .const .const .const .const .const .const
IDMA= BDMA_BIAD= BDMA_BEAD= BDMA_BDMA_Ctrl= BDMA_BWCOUNT= PFDATA= PFTYPE= SPORT1_Autobuf= SPORT1_RFSDIV= SPORT1_SCLKDIV= SPORT1_Control_Reg= SPORT0_Autobuf= SPORT0_RFSDIV= SPORT0_SCLKDIV= SPORT0_Control_Reg= SPORT0_TX_Channels0= SPORT0_TX_Channels1= SPORT0_RX_Channels0= SPORT0_RX_Channels1= TSCALE= TCOUNT= TPERIOD= DM_Wait_Reg= System_Control_Reg=
0x3fe0; 0x3fe1; 0x3fe2; 0x3fe3; 0x3fe4; 0x3fe5; 0x3fe6; 0x3fef; 0x3ff0; 0x3ff1; 0x3ff2; 0x3ff3; 0x3ff4; 0x3ff5; 0x3ff6; 0x3ff7; 0x3ff8; 0x3ff9; 0x3ffa; 0x3ffb; 0x3ffc; 0x3ffd; 0x3ffe; 0x3fff;
Deklarace základních proměnných a zásobníků
Úsek deklarací obsahuje část, která souvisí s nastavením codecu AD1847. Protože buse používán Autobuffering je třeba deklarovat dva zásobníky o délce 3 pro vysílání a příjem tx_buf a rx_buf. Parametry určující funkci codecu jsou obsaženy v cyklickém zásobníku init_cmds. Pro inicializaci codecu ještě je použita pomocná proměnná stat_flag. Deklarace jsou následující .var/dm/ram/circ .var/dm/ram/circ .var/dm/ram/circ .var/dm
rx_buf[3]; /* příjem: Status Word + tx_buf[3]; /* vysílání: Control Word + init_cmds[13]; /* zásobník s stat_flag; /* indikace stavu
L data + R data*/ L data + R data*/ AD1847 registrů*/ registrů AD1847*/
Inicializace základních proměnných a zásobníků
Zásobník pro vysílání je inicializován následujícími daty, tj. je vynulováno jak Control Word, tak data pro převodník D/A.
65
.init tx_buf:
0xc0000, 0x0000, 0x0000;
Úsek deklarací obsahuje část, která souvisí s nastavením codecu AD1847. Parametry určující funkci codecu jsou obsaženy v cyklickém zásobníku init_cmds. Jeho deklarace je následující .var/dm/ram/circ
init_cmds[13];
Inicializace hodnot v řídicích registrech codecu může nastavit následující vlastnosti:
• • • • • • • • •
vstupní kanál (line1, line 2, aux 1, popřípadě propojení mezi analogovým vstupem a výstupem) pro levý a pravý kanál zvlášť zesílení (gain/atten) levého a pravého aux 1 kanálu zvlášť, popřípadě úplné ztlumení (mute) zesílení (gain/atten) levého a pravého aux 2 kanálu zvlášť, popřípadě úplné ztlumení (nevstupuje do A/D převodníku, ale mixuje se k výstupu D/A převodníku) zesílení levého a pravého výstupního kanálu (D/A) zvlášť, popřípadě úplné ztlumení (mute) mixování levého a pravého kanálu, zesílení vzájemného propojení formát dat: unsigned nebo signed, mono nebo stereo, kompresi (companding) vzorkovací frekvenci v mezích od 5.5125 kHz do 48 kHz spuštění autokalibrace konfiguraci přenodového kanálu 1 nebo 2 vodiče (wire), počet počet kanálů v jednom bloku 16 nebo 32 (slots per frame). Jednotlivá slova zásobníku init_cmds mají jednotnou strukturu v tom, že
• • • • •
obsah bitů 0-7 se přenáší do řídicích registrů codecu bity 8-11 jsou adresy jednotlivých řídicích registrů bit 13 nastavuje možnost zpětného čtení obsahu řídicích registrů codecu bit 14 je tzv. Mode Change Enabled bit (MCE), který musí být při změně některých registrů nastaven na 1 bit 15 je tzv. Clear Overrange bit (CLOR), který určuje způsob aktualizace indikace překročení rozsahu převodníku ve stavovém slově (Status Word).
Sériový port SPORT0 je v tomto popisu konfigurován k použití režimu Autobuffering a mnoho-kanálového módu. Nastavení codecu a sériového portu musí být kompatibilní. Obsah zásobníku init_cmds se přepíše do registrů codecu AD1847 během jeho inicializace.
66
.init init_cmds: 0xc85b, { 0xc002, { Data format register Left input control reg b7 : res b7-6: 0=line 1, 1=aux 1, b5-6: 0=8-bit unsigned 2=line 2, 3=line 1 linear PCM post-mixed loopback 1=8-bit u-law companded b5-4: res 2=16-bit signed b3-0: left input gain x 1.5 dB linear PCM } 3=8-bit A-law companded 0xc102, { b4 : 0=mono, 1=stereo Right input control reg Sampling frequency in kHz b7-6: 0=line 1, 1=aux 1, b0-3: 0= 8. 2=line 2, 3=line 1 1= 5.5125 post-mixed loopback 2= 16. b5-4: res 3= 11.025 b3-0: right input gain x 1.5 dB 4= 27.42857 } 5= 18.9 0xc288, { 6= 32. left aux 1 control reg 7= 22.05 b7 : 1=left aux 1 mute, 8= . b6-5: res 9= 37.8 b4-0: gain/atten x 1.5, a= . 08= 0dB, 00= 12dB b= 44.1 } c= 48. 0xc388, { d= 33.075 right aux 1 control reg e= 9.6 b7 : 1=right aux 1 mute f= 6.615 b6-5: res (b0) : 0=XTAL1 24.576 MHz; b4-0: gain/atten x 1.5, 1=XTAL2 16.9344 MHz 08= 0dB, 00= 12dB } } 0xc909, { 0xc488, { interface configuration reg left aux 2 control reg b7-4: res b7 : 1=left aux 2 mute b3 : 1=autocalibrate b6-5: res b2-1: res b4-0: gain/atten x 1.5, b0 : 1=playback enabled 08= 0dB, 00= 12dB } } 0xca00, { 0xc588, { pin control reg right aux 2 control reg b7 : logic state of pin XCTL1 b7 : 1=right aux 2 mute b6 : logic state of pin XCTL0 b6-5: res b5 : master – b4-0: gain/atten x 1.5, 1=tri-state CLKOUT 08= 0dB, 00= 12dB slave - x=tri-state CLKOUT } b4-0: res 0xc680, { } left DAC control reg 0xcc40, { b7 : 1=left DAC mute miscellaneous information reg b6 : res b7 : 1=16 slots per frame, b5-0: attenuation x 1.5 dB 0=32 slots per frame } b6 : 1=2-wire system, 0xc780, { 0=1-wire system right DAC control reg b5-0: res b7 : 1=right DAC mute } b6 : res 0xcd00; { b5-0: attenuation x 1.5 dB digital mix control reg } b7-2: attenuation x 1.5 dB b1 : res b0 : 1=digital mix enabled }
67
Vektor přerušení
Vektor přerušení je obecně název pro část programu v asembleru obsahující instrukce skoků na podprogramy (subroutine), které obsluhují nějaké přerušení a které jsou na rozdíl zmíněného skoku situovány v paměti výše. Instrukce skoku jsou totiž umístěny v části paměti začínající adresou 0x0000. Přerušovací systém je hardwarově řešen tak, že při vzniku přerušení předá řízení na instrukci ve zmíněném začátku paměti, což se uskuteční zaplněním příslušných registrů a uložením některých registrů do zásobníku. Pro přehled jsou paměťová míst „namačkána“ za sebou, a proto se na dané místo nevejde více než instrukce skoku. Přerušení se obslouží jen tehdy, jestliže není individuálně maskováno. Signálové procesory rodiny ADSP 21xx však mají buňky, na které se předá řízení programu, odstupňovány po čtyřech. To umožňuje krátký kód (do 3 instrukcí) situovat bezprostředně za buňku, na kterou přerušovací systém „skočí“. Při vzniku přerušení se obecně nejprve ověřuje, zda je individuálně povoleno (obsah registru IMAS) a pak se na vrchol zásobníků jednotky Program Sequencer uloží adresa, od které má program pokračovat po ukončení přerušení. Dále se na vrchol zásobníku uloží obsahy některých registrů (ASTAT, MSTAT a IMASK). Tyto registry jsou naplněny novými hodnotami, které určují, zda zahnízdění přerušení je povoleno nebo není. Po ukončení obsluhy přerušení se uložené obsahy registrů (ASTAT, MSTAT a IMASK) sejmou z vrcholu zásobníku a uloží se zpět na původní místo. Obnovení MSTAT přepne znovu na primární registry. Rovněž se obnoví obsah registru s adresou pro čtení příští instrukce. Příkladem vektoru přerušení v programu, který snímá data z A/D převodníku a komunikuje po sériové lince s host počítačem je následující {*** Interrupt vector table *********************} jump start; rti; rti; rti; {00: rti; rti; rti; rti; {04: rti; rti; rti; rti; {08: rti; rti; rti; rti; {0c: ar = dm(stat_flag); {10: ar = pass ar; if eq rti; jump next_cmd; jump input_samples; rti; rti; rti; {14: jump irqe; rti; rti; rti; {18: rti; rti; rti; rti; {1c: jump irq1isr; rti; rti; rti; {20: rti; rti; rti; rti; {24: jump process_a_bit; rti; rti; rti; {28: rti; rti; rti; rti; {2c: start:
{
reset IRQ2 IRQL1 IRQL0 SPORT0 tx
} } } } }
SPORT1 rx } IRQE } BDMA } SPORT1 tx or IRQ1 } SPORT1 rx or IRQ0 } timer } power down }
vlastní začátek programu s inicializacemi }
Obsluha přerušení
Po resetu nebo zapojení napájení přerušovací systém skočí na buňku s adresou 00 (0x0000). Tato buňka obsahuje skok na vlastní začátek programu s návěštím start, kde začínají různé inicializace. Při přerušení je předáno řízení programu na instrukce v buňkách adresami 00, 04, 08, … až 2C, které jsou v prvém sloupci, přičemž instrukce v dalších sloupcích pomyslné matice ve výše uvedeném výpise slouží pouze k obsluze tohoto přerušení. Jestliže je přerušení neobslouženo, pak se toto paměťové místo zaplní instrukcí návratu z obsluhy přerušení rti. Touto instrukcí jsou zaplněny také další nevyužité buňky. Je třeba připomenout, že při překladu se počet instrukcí a obsažených buněk paměti shoduje.
68
Kromě resetu další využité přerušení je od vysílání (tx) do sériového portu SPORT0. Co se stane, závisí na obsahu buňky paměti se jménem stat_flag. Jestliže je tato pomocná proměnná nulová, pak obsluha přerušení skončí okamžitě, jinak pokračuje instrukcemi od návěští next_cmd, které jsou ukončeny instrukcí návratu z obsluhy přerušení. Z buněk zásobníku init_cmds se postupně pomocí registru I3 (s modifikací m1 = 1) vybírací jejich obsahy, které se umísťují do první buňky zásobníku (obsah je Control Word), což vyvolá v režimu Autobuffering jejich přenos do řídicího registru AD1847, jehož adresa je dána 8. až 11. bitem tohoto slova. Následující část programu rovněž kontroluje, zda je přenos všech slov pro registry AD1847 ukončen. Po dokončení přenosu se pomocná proměnná stat_flag nuluje. next_cmd: ena sec_reg; ax0 = dm (i3, m1); { čtení jednoho slova ze zásobníku init_cmds } dm (tx_buf) = ax0; { a jeho umístění do první buňky tx_buf } ax0 = i3; ay0 = ^init_cmds; ar = ax0 - ay0; if gt rti; { rti jestliže není přenos init_cmds dokončen,} ax0 = 0xaf00; { v případě dokončení inicializace se bit MCE } dm (tx_buf) = ax0; { nuluje, aby se některé registr nemohly měnit} ax0 = 0; dm (stat_flag) = ax0; { nuluje se také proměnná status flag } rti;
Další přerušení je od příjmu (rx) ze sériového portu SPORT0 a vzniká po příjmu nového vzorku z A/D převodníku. Toto přerušení se obslouží programem od návěští input_samples. Obsluha začíná načtením vzorku z A/D a končí jeho vysláním zpět do D/A převodníku. input_samples: ena sec_reg; mr0 = dm(rx_buf + 1); mr1 = dm(rx_buf + 2);
{ přepnutí na sekundární registry } { načtení levého a pravého kanálu }
{ libovolná transformace vstupního signáku } dm(tx_buf + 1) = mr0; dm(tx_buf + 2) = mr1;
{ výstup levého a pravého kanálu }
rti;
Stisk tlačítka INTERUPT na kartě EZ-KIT Lite vyvolá přerušení IRQE. Obsluha tohoto tlačítka pouze změní logickou hodnotu výstupu fl1, tj. irqe:
toggle fl1; rti;
Příchod start bitu při sériové komunikaci způsobí v přerušení IRQ1, které se obsluhuje od návěští irq1isr. , kde je instrukce startu časovače TIMER a samozřejmě instrukce návratu. Poslední přerušení je vyvoláno časovačem TIMER a je obslouženo od návěští v modulu UART. Použití návratu pomocí instrukce rts je dáno výjimkou vázanou na použití instrukce pop sts. irq1isr: pop sts; ena timer; rts;
{ nyní odstartuje timer } { všimněte si rts }
69
Začátek programu
Program v DSP se zavede buď po připojení napájení nebo po stisknutí tlačítka reset. Obsah některých registrů je nedefinován, zbylé se nastaví do výchozího stavu. Z registrů obsahujících stav DSP (Status Registers) se nulují IMASK (všechna přerušení jsou maskována), ASTAT, MSTAT (přepnuto na primární registry, MAC v režimu fractional mode) a IFC. Registr SSTAT je inicializovam 0x55 a registr ICNTL je ve stavu neurčitém. Oba sériové porty SPORT0 a SPORT1) jsou vypnuty, tj. příslušné bity (11. a 12.) registru System Control Register obsahují nuly. Regisry výpočetních jednotek a generárorů adres jsou rovněž v neurčitém stavu. Jenotka MAC je v módu RND (rounding). Inicializace generátorů adres
Přiřazeny jsou obsahy registrů I, L a M, které jsou v programu použity k čtení a zápisu do cyklických zásobníků: i0 l0 i1 l1 i3 l3
= = = = = =
^rx_buf; %rx_buf; ^tx_buf; %tx_buf; ^init_cmds; %init_cmds;
m1 = 1; m0 = 0;
/* /* /* /* /* /*
set set set set set set
i0 l0 i1 l1 i3 l3
= = = = = =
adresa první buňky rx_buf délka rx_buf adresa první buňky tx_buf délka tx_buf adresa první buňky init_cmds délka init_cmds
/* velikost modifikace adres
*/ */ */ */ */ */
*/
Nastavení a inicializace sériového portu SPORT0
Sériový port je konfigurován k použití autobuferingu a mnoho-kanálového režimu funkce, který se opírá o časové dělení do posloupnosti tzv. slotů. K řízení tohoto portu je použit externí zdroj hodinové frekvence a synchronizace bloků (frame sync), tj. tyto signály vstupují do DSP z vnějšku. Autobuffering může být považován za DMA sériového portu, který používá k automatickému přístupu k datům generátorů adres, a to registrů I0, I1 a M1 = 1. Obsah registru I0 je určen k přístupu k zásobníku rx_buf a obsah registru I1 k zásobníku tx_buf. Mnoho-kanálový mód je konfigurován pro 32 kanálů v jednom bloku (frame) a na stejný počet kanálů je konfigurován rovněž codec AD1847. Každé přenášené 16bitové slovo v tomto mnoho-kanálovém spojení s časovým dělením je přiřazeno určitému intervalu (tzv. slot) z 32 po sobě jdoucích intervalů. V tomto kanálu může být přiřazené slovo přenášeno v obou směrech (příjem/vysílání). Každý synchronizační impuls bloku odstartuje přenos tohoto bloku obsahujícího 32 16bitových slov. Tento program konfiguruje SPORT0 k vysílání na kanálech 0, 1, 2, 16, 17, 18 a k příjmu na stejných kanálech. Zbývající kanály jsou ignorovány. Nejprve je třeba nastavit registr SPORT0_Autobuf (v dokumentaci také označovaný SPORT0 Autobuffer Control Register) tak, aby se
• • • •
shodovalo přiřazení generátorů adres zásobníkům pro příjem a vysílání (RMREG=M1, RIREG=I0, TMREG=M1, TIREG=I1), povolil příjem a vysílání v režimu Autobuffering a, povolil CLKOUT pro případné řízení externí paměti zakázal BIASRND (vychýlené zaokrouhlování obsahu registru MR1 z jednotky MAC). ax0 = b#0000001010000111; dm (SPORT0_Autobuf) = ax0; { |||!|-/!/|-/|/|+- autobuffering pro příjem 0=off, 1=on |||!| ! | | +-- autobuffering pro vysílání 0=off, 1=on |||!| ! | +---- | příjem m?
70
}
|||!| ! | |||!| ! +------|||!| ! |||!| +========= |||!| |||!+-----------|||! |||+============= ||+-------------|+--------------+----------------
| ! ! | | ! ! | 0 | 0
m1 příjem i? i0 vysílání m? m1 vysílání i? i1 BIASRND MAC kontr.bit vychýleného zaok r. CLKODIS CLKOUT disable control bit
Dále je třeba nastavit registry SPOTR0_RFSDIV s SPOTR0_SCLKDIV a registr SPOTR0_Control_Reg
• • • • • •
délka slova SLEN= 16 bitů, zarovnání doprava - doplnění nulami nepoužito neinvertovat synchronizaci pro příjem a vysílání INVRFS=0, INVTFS=0 nepovolit interní synchronizaci pro příjem a vysílání IRFS=0, a současně nastavit počet kanálů na 32 ITFS=1 nastavit mnoho-kanálový režim MFD=1 bez interního generátoru hodin v DSP ISCLK=0 povolit mnoho-kanálový mód MCE=1. ax0 = 0; dm (SPORT0_RFSDIV) = ax0; { RFSDIV = SCLK Hz/RFS Hz – 1, užívá externí zdroj pro receive frame sync ( RFS = input ) } ax0 = 0; dm (SPORT0_SCLKDIV) = ax0; { SCLK = CLKOUT / (2 (SCLKDIV + 1), užívá externí zdroj pro hodinovou frekvenci ( SCLK=input ) } ax0 = b#1000011000001111; dm (SPORT0_Control_Reg) = ax0; { multichannel ||+--/|!||+/+---/ | počet bitů na slovo – 1, pro 16bit slovo ||| |!||| | = 15 ||| |!||| | ||| |!||+====== ! 0=right just,0-fill;1=right just,signed ||| |!|| ! 2=compand u-law; 3=compand A-law ||| |!|+------- příjem framing logiky 0=pos, 1=neg ||| |!+-------- logika vysílání platných dat 0=pos, 1=neg ||| |+========= RFS 0=ext, 1=int ||| +---------- počet kanálů 0=24, 1=32 words ||+-------------- | frame sync to occur this number of clock || | cycle before first bit || | |+--------------- ISCLK 0=ext, 1=int +---------------- multichannel 0=disable, 1=enable }
Zpřístupnění kanálů 0, 1 a 2 pro vysílání se zajistí nastavením registru SPORT0_TX_Channels0 a kanálů 16, 17 a 18 nastavením registru SPORT0_TX_Channels1. Stejně je to s kanály pro příjem, které určují registry SPORT0_RX_Channels0 a SPORT0_RX_Channels1. ax0 = b#0000000000000111; { ^15 00^ ax0 = b#0000000000000111; { ^31 16^ ax0 = b#0000000000000111; { ^15 00^
dm (SPORT0_TX_Channels0) = ax0; transmit word enables: channel # == bit #} dm (SPORT0_TX_Channels1) = ax0; transmit word enables: channel # == bit #} dm (SPORT0_RX_Channels0) = ax0; receive word enables: channel # == bit # }
71
ax0 = b#0000000000000111; { ^31 16^
dm (SPORT0_RX_Channels1) = ax0; receive word enables: channel # == bit # }
Nastavení systému a paměti
V nastavení I/O paměti (I/O Memory s 2048 slovy) je pro všechny její částí (adresy 0x000 až 0x1FF, 0x200 až 0x3FF, 0x400 až 0x5FF a 0x600 až 0x7FF) nastaven stejný počet čekacích stavů (IOWAITx = 7) a počet a čekacích stavů pro externí paměť je nula (DWAIT = 0). V registru System_Control_Reg je rovněž nastaven počet čekacích stavů paměti na nulu (PWAIT = 0) a v tomto registru je zpřístupněn sériový kanál SPORT0. Nastavením registru IFC jsou vynulovány neobsloužená přerušení (jedničky v bitech 0-7). ax0 = b#0000111111111111; dm (DM_Wait_Reg) = ax0; { || | | | | -|IOWAIT0 || | | | | | || | | | +-- | || | | | | IOWAIT1 || | | | | || | | +----- | || | | | IOWAIT2 || | | | || | +-------- | || | | IOWAIT3 || | | || +----------- | || | DWAIT || | |+-------------- | +--------------- | } ax0 = b#0001000000000000; dm (System_Control_Reg) = ax0; { +-/!||+-----/+-/- | program memory wait states PWAIT = 0 | !||| | 0 | !||| | | !||+---------- 0 | !|| 0 | !|| 0 | !|| 0 | !|| 0 | !|| 0 | !|| 0 | !|+----------- SPORT1 1=serial, 0=FI, FO, IRQ0, IRQ1, SCLK | !+------------ SPORT1 1=enabled, 0=disabled | +============= SPORT0 1=enabled, 0=disabled +---------------- 0 0 0 } ifc = 0xff; nop;
/* vynulování neobsloužených přerušení */
Rovněž je potřeba definovat obsah registru ICNTL (protože se použije emulace UART, je třeba zajistit citlivost přerušení IRQ1 na hranu) a nastavit GO mód, který má význam jen při používání externí paměti (jsou-li sběrnice blokovány, procesor běží): icntl = b#00010; { ||||+- | IRQ0: 0=level, 1=edge
72
|||+-||+--|+---+-----
| IRQ1: 0=level, 1=edge | IRQ2: 0=level, 1=edge 0 | IRQ nesting: 0=disabled, 1=enabled
} mstat = b#1000000; { ||||||+- | |||||+-- | ||||+--- | |||+---- | ||+----- | |+------ | +------- | }
Data register bank select FFT bit reverse mode (DAG1) ALU overflow latch mode, 1=sticky AR saturation mode, 1=saturate, 0=wrap MAC result, 0=fractional, 1=integer timer enable GO MODE
V případě, že je program je spuštěn monitorem, pak nastavení registrů ICNTL a MSTAT jsou jeho součástí a nemusí být do kódu programu zahrnuta. Inicializace codecu AD1847
Protože přerušení od sériového portu SPORT0 pro vysílání je dosud maskováno, nebylo dosud voláno jeho obsloužení. Před odmaskováním tohoto přerušení je nastaven indikátor ukončení přenosu dat do všech řídicích registrů codecu, proměnná stat_flag, nastavena na 1. ax0 = 1; dm(stat_flag) = ax0;
/* initialize stat_flag to 1
*/
Odmaskování SPORT0 pro vysílání (tx) se zajistí nastavením příslušného bitu: imask = b#0001000000; { |||||||||+ | ||||||||+- | |||||||+-- | ||||||+--- | |||||+---- | ||||+----- | |||+------ | ||+------- | |+-------- | +--------- | }
timer SPORT1 SPORT1 BDMA IRQE SPORT0 SPORT0 IRQL0 IRQL1 IRQ2
rec or IRQ0 trx or IRQ1 rec trx
Následuje přečtení obsahu první buňky cyklického zásobníku tx_buf do registr AX0 a přiřazení obsahu tohoto registru vysílacímu registru sériového portu SPORT0 TX0. Přenos do registru TX0 spustí v režimu Autobuffering přenos obsahu cyklického zásobníku do codecu. Je třeba připomenout, že obsah celého zásobníku byl nulován. ax0 = dm (i1, m1); tx0 = ax0;
/* načtení obsahu první buňky tx_buf do ax0 */ /* zahájení přenosu v režimu Autobuffering */
Přerušení od SPORT tx je generováno až po ukončení přenosu sériovým portem. Tímto okamžikem je zahájena obsluha přerušení která spočívá v postupném načtení obsahu jednotlivých buněk zásobníku init_cmds a jejich přiřazení první buňce cyklického zásobníku tx_buf, což je opět signálem k zahájení přenosu do codecu. Tato první buňka obsahuje řídicí slovo (Control Word), jehož obsah zajistí obsazení příslušného řídicího registru codecu. Přerušení se opakuje tolikrát, až je vyčerpán obsah zásobníku init_cmds.
73
Test konce přenosu řídicích slov testuje následující úsek programu prostřednictvím testování obsahu proměnné stat_flag. check_init: ax0 = dm (stat_flag); af = pass ax0; if ne jump check_init;
/* načtení stat_flag */ /* nastavení příznaků ASTAT, je nula? */ /* jestliže ne, pak opakuj od check_init */
Po ukončení přenosu indikovaném nulovým obsahem stat_flag je třeba ještě počkat na dokončení autokalibrace codecu. Kontrola je dvojí, nejprve je testováno, zda je codec v autokalibračním módu a pak je testováno, zda se autokalibrace dokončila. Stav autokalibrace se pozná podle obsahu stavového slova (Status Word) codecu. ay0 = 2; check_aci1: ax0 = dm (rx_buf); ar = ax0 and ay0; if eq jump check_aci1; check_aci2: ax0 = dm (rx_buf); ar = ax0 and ay0; if ne jump check_aci2; idle;
/* smyčka k testování ACI bitu = 1 ( in autocalibration ) */ /* čtení stavového slova AD1847 */ /* AND 2 se stavovým slovem */ /* jestliže je výsledek různý od 0, pak konec testu ve smyčce */ /* smyčka k testování ACI bitu =0 ( autocalibration complete ) */ /* čekání na nulování bitu */
Jakmile je autokalibrace dokončena, je třeba zrušit umlčení levého a pravého kanálu pro D/A. To se provede změnou obsahu 7. buňky zásobníku (init_cmds +6) logickým AND s konstantou 0xbf3f. ay0 = 0xbf3f; ax0 = dm (init_cmds + 6); ar = ax0 AND ay0; dm (tx_buf) = ar; idle; ax0 = dm (init_cmds + 7); ar = ax0 AND ay0; dm (tx_buf) = ar; idle;
/* zrušit umlčení levého DAC
*/
/* čekání na dokončení přenosu */ /* zrušit umlčení pravého DAC */ /* čekání na dokončení přenosu */
Zakončení inicializační části spočívá ve vynulování neobsloužených přerušení a odmaskování přerušení od IRQE a RX0. ifc = 0xff; /* nop; imask = b#0000110000; { |||||||||+ | ||||||||+- | |||||||+-- | ||||||+--- | |||||+---- | ||||+----- | |||+------ | ||+------- | |+-------- | +--------- | }
vynulování neobsloužených přerušení */ /* odmaskování rx0 a IRQE přerušení */ timer SPORT1 rec or IRQ0 SPORT1 trx or IRQ1 BDMA IRQE SPORT0 rec SPORT0 trx IRQL0 IRQL1 IRQ2
74
Inicializace emulátoru UART
V případě, že DSP komunikuje s host počítačem je třeba tuto komunikaci spustit podprogramy, které přísluší modulu emulujícímu funkci UART. Podrobnosti o způsobu komunikace budou uvedeny v dalších kapitolách. V tomto místě jsou uvedeny jen instrukce pro inicializaci a start: call init_uart; call turn_rx_on;
{ inicializování uart } { spuštění uart }
Uživatelská část programu
Po inicializacích, které jsou společné aplikacím využívajícím možností EZ-KIT Lite může program pokračovat částí, která zpracovává příkazy z host počítače. Každý příkaz je třeba dekódovat a provést nějakou akci spočívající buď ve změně podmínek zpracování signálu při obsluze přerušení od SPOTR0 RX nebo ve výpočtu nějaké charakteristiky signálu. V části popisující matematické programy je uveden příklad na výpočet efektivní hodnoty. Součástí reakce je poslání informace zpět do host počítače. Při programování výpočtů v této části programu je třeba mít na paměti, že tento program běží souběžně s obsluhou přerušení, jmenovitě například od vzorkování signálu. Mezivýpočty při obsluze přerušení mohou probíhat s daty, které se právě rozpracovávají jako reakce na příkaz z host počítače. Jako příklad může být uveden výpočet efektivní hodnoty. Akumulace součtu čtverců vzorků by neměla probíhat souběžně s výpočtem odmocnin a podílu. Tomu lze zabránit testováním nějaké pomocné proměnné, jejíž obsah signalizuje obsluze přerušení, že dílčí část obsluhy má být přeskočena.
Komunikace mezi DSP a host počítačem třídy PC Signálový procesor může pracovat po zavedení programu zcela samostatně. Jednou z jeho funkcí může být filtrace stereo-audio signálu. To znamená snímání 2 kanálů A/D převodníky a výstup prostřednictvím D/A převodníku. Mnohem zajímavější využití DSP spočívá například ve volbě typu filtru, která je zadána z host počítače. Pro tuto funkci musí DSP a PC spolu komunikovat. Jak již bylo uvedeno, ADSP-2181 jako součást EZ-KIT Lite emuluje obvod UART. Emulace obvodu UART v EZ-KIT Lite
Pro sériovou komunikaci probíhá po následujícím spojení. Obvod AD233 pouze transformuje signály 5 V DC na napěťovou úroveň asynchronní sériové linky RS232. Rychlost přenosu je udržována časovačem (TIMER). ADSP2181 Flag_Out
AD233
RS232 RX
ADSP2181 Flag_In
AD233
RS232 TX
Software emulátoru je obsaženo v modulu UART, který je obsažen v textovém souboru UART.DSP. Tento modul je součásti dodávky EZ-KIT Lite. Nastavení podprogramů pro vysílání je nezávislé na nastavení podprogramů pro příjem. Ačkoliv pro vysílání a příjem je použit jeden časovač, příjem a vysílání nemusí být spolu synchronizovány. Časovač (TIMER) je nastaven tak, že za dobu vyslání jednoho bitu vzniknou 3 přerušení, tj. je 3 větší než přenosová rychlost v bitech (Bd). Při přerušení od časovače je startován podprogram s návěštím process_a_bit (návěští musí být uvnitř uživatelského programu deklarováno jako 75
.EXTERNAL). Bit je tedy přijat na vývodu FLAG_IN nebo vyslán na vývodu FLAG_OUT až po 3 přerušeních od časovače. Příjem je rovněž napojen na přerušení z vývodu IRQ1 . V případě, že časovač není přístupný, podprogram pro obsluhu tohoto přerušení časovač odstartuje. V úvodních částech deklarací modulu UART jsou formou konstant (.CONST) zapsány důležité informace o nastavení sériového spojení. Jedná se například o počet bitů zvlášť pro příjem a zvlášť pro vysílání. Modul UART rovněž ovlivňuje frekvenci blikání červené LED diody pro indikaci správného a nesprávného příjmu znaků. Základní podprogramy modulu UART pro příjem a vysílání zajišťují přenos 8 bitů s úvodním start bitem a koncovým stop bitem. Informace o 8 bitech představuje polovinu 16 bitového slova DSP, tj. jeden bajt který je kódem pro jeden znak. Podprogramy pro příjem a vyslání znaku (char) přenášejí pro dané nastavení 8 nejméně významných bitů z 16bitového registru AX0. Celé slovo (int) složené ze dvou bajtů lze tedy přenést ve dvou znacích. Přenos znaků a slov společně s inicializací, zapnutím a vypnutím jsou v modulu UART následující vstupní body: .entry init_uart; reset } .entry stop_uart; .entry out_char_ax1; .entry get_char_ax1; .entry get_char_ax1_to; .entry out_int_ar; .entry get_int_ar_to; .entry turn_rx_on; .entry turn_rx_off; .entry process_a_bit;
{ inicializace sofrwarového UART, vždy po { { { { { { { { {
stop sofrwarového UART } vyslání znaku z registru ax1 } příjem znaku do registru ax1 } příjem znaku do registru ax1 s timeout } vyslání slova z registru ar s timeout } příjem slova do registru ar s timeout } zpřístupnění rx sekce UARTu } znepřístupnění rx sekce UARTu } obsluha přerušení z časovače (TIMER) }
V uživatelské programu je třeba deklarovat externí proměnné z modulu UART. Testováním těchto proměnných, které jsou nastavovány podprogramy UART, lze zjistit příchod znaku nebo ukončení vyslání: .external nového .external příjem .external
flag_tx_ready; slova} flag_rx_no_word; nového slova } flag_rx_ready;
{ indikace připravenosti UART k vyslání { indikace prázdného zásobníku UART pro { indikace, že UART není zaneprázdněn }
Podprogram modulu UART je nastaven tak, že je příjem vypnut (OFF). Ke zpřístupnění musí být použit podprogram turn_rx_on. Použití modulu UART k příjmu znaků prostřednictvím RS 232
Programy pro DSP jsou obvykle koncipovány tak, že běží základní program odstartovaný od adresy 0x0000, přičemž tento program je periodicky přerušován od převodníku A/D, popřípadě od časovače. Funkcí základního programu je po inicializaci obvykle komunikovat s host počítačem. Výhodné je absolutně pasívní postavení DSP oproti host počítači. Tato funkce se zajistí tak, že v určitém místě jeho kódu program „běhá“ ve smyčce a čeká na příchod znaku po RS 232 z host počítače. Tento úsek kódu může být řešen následujícím způsobem:. again:
{ začátek smyčky } ar = dm (flag_rx_no_word); none = pass ar; if ne jump again;
{ { { {
čtení informace o příjmu znaku } nastavení příznaku v ASTAT } jestliže = 1, pak nic nepřišlo } něco se děje }
76
call get_char_ax1_to; if lt jump again; . . . . . . . . . . . . .
{ čtení znaku do ax1 s timeout } { time out překročen }
Pokračování uvedené části programu za posledním podmíněným příkazem skoku, tj. ukončení opakování tohoto úseku programu, znamená, že v registru AX1 se nachází právě přijatý znak. Podle tohoto znaku se může program větvit na různé akce. Po jejich skončení se program vrátí zpět na návěští again a čeká přijetí dalšího znaku. Použití modulu UART k vysílání znaků prostřednictvím RS 232
Typickou úlohou pro aplikace DSP v oblasti měřicí techniky je požadavek host počítač týkající se zpětného zaslání nějaké informace. Může se jednat například o velikost efektivní hodnoty signálu na výstupu frekvenčního filtru. Znak k vyslání je třeba připravit do registru AX1, ze kterého je vysláno jen 8 méně významných bitů. Podprogram označený návěštím SendChar pro vyslání znaku je následující SendChar: call out_char_ax1; wt:
{ vyslání znaku } { čekání na ukončení přenosu }
ar = dm (flag_tx_ready); none = pass ar; if eq jump wt; rts;
Vyslaný znak reprezentuje polovinu obsahu 16bitového registru. Jestliže se jedná o numerický údaj, je vhodné, aby po sběrnici RS 232 byly vysílány jen znaky, které reprezentují například čtyři cifry šestnáctkového čísla. Obsah buňky je proto třeba rozložit na 4 čtveřice bitů a každou z nich překódovat na znaky 0, 1, 2, …,9, A, B, …, F. Podprogramy pro rozklad 16 bitového údaje na 4 šestnáctkové cifry, které jsou zakončeny čárkou (,), jsou v následující tabulce: { Rozklad 16bitového slova na 2 8bitové char a odeslání}
{ Dekodovaní 8bitového char na 2 čtyřbitové hex a odeslání }
SendWord: sr
ConvChar: ay1 = 9; ar = sr1 – ay1; if gt jump Send2Char1; ay1 = 48; { '0' } jump Send2Char2; Send2Char1: ay1 = 55; { 55+10=65 'A' } Send2Char2: ar = sr1 + ay1; ax1 = ar; call SendChar; rts;
= lshift si by -12 (hi);
call ConvChar; sr = lshift si by -8 (hi); { horní 4 bity } ay0 = 0x000f; { maska } ar = sr1 AND ay0; sr1 = ar; call ConvChar; sr = lshift si by -4 (hi); ar = sr1 AND ay0; sr1 = ar; call ConvChar; sr1 = si; { dolní 4 bity } ar = sr1 AND ay0; sr1 = ar; call ConvChar; ar = 44; { poslat čárku } ax1 = ar; call SendChar; rts;
77
Komunikace host počítače s DSP s využitím Visual Basicu
Přiklad řešení bude předveden v jazyku Visual Basic. Komunikace host počítače (PC) se signálovým procesorem může být zcela jednosměrná (tj. bez zpětné vazby potvrzující přijetí zprávy) nebo vlastní protokol může být realizován tak, že příkazy host počítače jsou potvrzovány zpětným vysláním nějakého vhodného znaku, který dovolí indikovat správnost přenosu. Kromě příkazů půjde ve vzájemné komunikaci také o předávání dat. Tato kapitola neřeší žádný speciální protokol, ale pouze uvádí základní příkazy jazyka Visual Basic. V textu bude popsáno, jak řešit úlohu, při které DSP pouze odpovídá na data vysílaná host procesorem. Dále bude předpokládáno, že je vždy znám počet zpětně vyslaných znaků. Ke zjednodušení dekódování znaků v DSP bude předpokládáno, že ze strany PC je vysílán pouze jeden znak , přičemž DSP odpovídá jedním nebo několika znaky v bloku. Poslední znak řetězce vysílaného z DSP je vždy programu v PC znám stejně jako struktura vysílaných dat. K ovládání sériové rozhranní, tj. sériové komunikaci, je v jazyku Visual Basicu (VB) k dispozici ovládací prvek MSComm. Tento ovládací prvek nevyžaduje se zajímat o podrobnosti funkce portu jako v případě signálového procesoru. Programáto vytváří kód, který komunikuje jen s vyrovnávacím zásobníky sériového portu PC pro příjem a vysílání prostřednictvím vlastností Input a Output. Programování začne přetažením ikony komponenty na plochu formuláře, např. Form. Pak je možné začít využívat metod a vlastností tohoto objektu MSComm1. Výhodou VB je událostmi řízené programování, které umožňuje ošetřit všechny události na sériové lince jako je například příchod znaku nebo také změny na Carrier Detect (CD) lince a Request To Send (RTS) lince. Rovněž lze detekovat chyby ve spojení prostřednictvím vlastnosti CommEvent. Před použitím je třeba nastavit některé vlastnosti (Properties) objektu MSComm1, jak je naznačeno v kopii tohoto okna. Vlastnosti CommPort, InputLen a RThreshold jsou programem měněny, jiné lze nastavit jen v tomto okně. Mezi těmito vlastnostmi jsou důležité dostatečně velké zásobníky InBufferSize a OutBufferSize, typ protokolu Handshaking, typ dat InputMode a nastavení parametrů komunikace v Settings. Handshaking je název vlastnosti pro komunikační protokol, který je nastaven na „žádný“. Nastavení InputMode představuje binární data (druhou možnosti je textový string). Nastavení NullDiscard určuje reakci na znak null, tj. Chr$(0), a to zda se má nebo nemá tento znak do vstupního zásobníku portu přenášet. Nastaveni EOFEnable určuje, jestli se má znak konce souboru, tj. Chr$(26), vyvolat událost OnComm nebo ne. Obě nastavení nejsou pro přenos znaků z tabulky ASCII s pořadovým číslem vyšším než 31 důležité. Vysílání cifer (znaky 0, 1, …, 9, A, …, F) šestnáctkových čísel s oddělovači minimálně zdvojnásobí počet vysílaných znaků, ale tyto znaky se nemohou interpretovat jako například konec souboru. 78
Spojení po sériové lince s EZ-KIT Lite pro nastavení DTREnable a RTSEnable na True pracuje. V případě, že je třeba naprogramovat přenos dat mezi DSP a host počítačem bez kódování na znaky šestnáctkového čísla, musí být předpokládáno, že znaky Chr$(0) a Chr$(26) mohou být platná data z měření. Tento způsob přenosu je třeba použít v případě, kdy kódování do šestnáctkových čísel omezuje přenosovou kapacitu spojovacího kanálu mezi PC a DSP na nepřijatelnou mez. Prvým krokem k zahájení sériové komunikace je nastavení čísla portu, na který je DSP připojen, a parametrů spojení. MSComm1.CommPort = 2 MSComm1.Settings = "9600,N,8,1"
V daném případě je otevřen COM2 pro neměnitelnou přenosovou rychlost 9600 Bd, bez kontroly parity a přenos 8 bitů s jedním stop bitem, protože toto nastavení předpokládá emulátor UART v DSP. Zkušení programátoři mohou použít načtení (případně uložení) těchto hodnot z registrů Windows příkazem GetSetting (popřípadě SaveSetting). Vzor řešení naleznou v demonstračním příkladu projektu VBTerm, který je součásti software VB. Port se otevře příkazem MSComm1.PortOpen = True
Podprogram pro vyslání znaku z PC do DSP bude mezi svými parametry obsahovat vysílaný znak a dále, vzhledem k výše popsané komunikaci, také počet znaků, které zpětně vyšle DSP, a také znak ukončující zpětně vyslaný řetězec. Je předpokládáno, že program v PC může opakovaně rychle za sebou žádat vyslání několika znaků. Časově limitující je ovšem komunikační kanál. Stačí porovnat dobu vysílání jednoho znaku (8bitů, 1 start bit a jeden stop bit) a počet instrukcí, které může vykonat PC a DSP. Například emulátor UART v DSP může vyslat teoreticky nejvýše 960 znaků za sekundu, tj. při vyslání jednoho znaků vykoná ADSP2181 více než 34 tisíce taktů. Pro jednoduchost komunikace mezi PC a DSP se nevysílají všechny požadované znaky do DSP okamžitě, ale postupně tak, že se vyčká odpověď DSP jen na jeden vyslaný znak. Proto se znaky požadované k vysílání ukládají do zásobníku, který je tvořen řetězcem znaků strZnakyKVyslani (proměnná typu string). Z tohoto zásobníku se odešle k přenosu do DSP pouze jeden znak, který byl do zásobníku uložen nejdříve, tj. na začátku řetězce. Další znak se vyšle až po přijetí odpovědi z DSP. Tímto zpomalením se zabrání kolizi programu v DSP, který příkaz musí kompletně vyřídit. Před vysláním znaku se nastaví počet znaků, jejichž přijetí do přijímacího zásobníku (receive buffer) vyvolá událost OnComm, která spustí podprogram MSComm1_OnComm(). Dále se nastaví také délka řetězce, který se z tohoto zásobníku příjme do vlastnosti MSComm1.Input. Pochopitelně je třeba do proměnných ve funkci zásobníků ukládat také očekávané kontrolní znaky, řetězec strPoslZnaky, a také počet přijímaných znaků (pole intZasobnik typu integer). Délka fronty znaků k vysílání je obsažena v proměnné intUkazatel typu integer. Public Sub VyslaniZnaku(ByVal ZnakOut As String, _ ’Vysílaný znak ByVal ZnakIn As String, _ ’Posl.očekávaný znak ByVal ZnakInLen As Integer) ’Počet očekáv. znaků Dim i As Integer intZasobnik(intUkazatel) = ZnakInLen strPoslZnaky = strPoslZnaky & ZnakIn strZnakyKVyslani = strZnakyKVyslani & ZnakOut
79
If intUkazatel = 0 Then frmForm.MSComm1.RThreshold = ZnakInLen frmForm.MSComm1.InputLen = ZnakInLen frmForm.MSComm1.Output = ZnakOut strZnakyKVyslani = "" End If
’Sériová linka volná
If intUkazatel < 1023 Then ’Test na přetečení zásobníku intUkazatel = intUkazatel + 1 Else MsgBox "Přetečení zásobníku", vbCritical End If End Sub
Podprogram, který je spuštěn událostí OnComm na sériové lince, vychází ze zmíněného demoprogramu. V kódu je příkaz čtení zásobníku (receive buffer) a ukázka začátku dekódování řetězce 20 znaků ukončených znakem „x“, který je podle příkazu vyslaného do DSP očekáván. Struktura řetězce odpovídá ukázkám podprogramů pro vysílání znaků z DSP, tj.4 znaky šestnáctkové soustavy jsou následovány znakem čárka. Součástí vyřízení události příjmu bloku znaků (MSComm1.CommEvent = comEvReceive) je vyslání dalších znaků do DSP v případě, že příslušný řetězec strZnakyKVyslání není prázdný. Visual Basic nabízí v použití funkce Val velmi snadné dekódování šestnáctkových čísel, například řetězec znaků šestnáctkového čísla se konvertuje na číslo příkazem Val("&H" & strPrvni4Znaky). Mezi události patří také chyby, které se mohou při sériové komunikaci objevit. V příkladu kódu jsou uvedeny jen některé. ' Událost OnComm je použita k dekódování jevů na sériové lince Private Static Sub MSComm1_OnComm() Dim EVMsg$ Dim ERMsg$ Dim strPrvni4Znaky As String Dim strDruhe4Znaly As String Dim strPom As String Dim xxx As Double Dim intLen As Integer Dim Retezec As String Dim PoslZnak As String Dim i As Integer ' Větvení podle druhu události Select Case MSComm1.CommEvent ' Event messages. Case comEvReceive Retezec = StrConv(MSComm1.Input, vbUnicode) intLen = Len(Retezec) PoslZnak = Right(Retezec, 1) If PoslZnak <> Left(strPoslZnaky, 1) Then MsgBox "Chyba přenosu znaků", vbCritical ' Ošetření chyby (např. zavření portu . . . ) End If If (intLen = 21) And (PoslZnak = "x") Then strPrvni4Znaky = Mid(Retezec, 1, 4) strDruhe4Znaly = Mid(Retezec, 6, 4) xxx = Val("&H" & strPrvni4Znaky) / 32767 ' Další příkazy pro dekódování dat . . . . . End If
80
' Další typy bloků očekávaných znaků ' Po přijmu bloku znaků je vyřízená odpověď, tj. očekávaný znak ' a informace o délce bloku jsou ze zásobníku odstraněny intUkazatel = intUkazatel - 1 strPoslZnaky = Right(strPoslZnaky, Len(strPoslZnaky) - 1) For i = 0 To intUkazatel intZasobnik(i) = intZasobnik(i + 1) Next i If (intUkazatel > 0) And MSComm1.PortOpen Then MSComm1.RThreshold = intZasobnik(0) MSComm1.InputLen = intZasobnik(0) MSComm1.Output = Left(strZnakyKVyslani, 1) strZnakyKVyslani = Right(strZnakyKVyslani,_ Len(strZnakyKVyslani) - 1) End If Case comEvSend ' Neošetřuje se! Case comEvCTS EVMsg$ = "Change in CTS Detected" Case comEvDSR EVMsg$ = "Change in DSR Detected" Case comEvCD EVMsg$ = "Change in CD Detected" Case comEvRing EVMsg$ = "The DSP is Ringing" ' Pokračují další typy událostí související se sériovou linkou . . . . . . . . End Select If Len(EVMsg$) Then ' Informace o chybě . . . . . ElseIf Len(ERMsg$) Then ' Informace o chybě . . . . . . ' Display error messages in an alert message box. End If End Sub
Sériový port se uzavře nastavením následující vlastnosti objektu MSComm1 na False MSComm1.PortOpen = False
Otestovat funkčnost spojení mezi PC a DSP je možné pomocí logické hodnoty vlastnosti MSComm1.CTSHolding. If MSComm1.CTSHolding Then ' Spojení je funkční Else ' Spojení není funkční End If
Realizace FIR filtru V této kapitole je předvedeno, jak lze zakomponovat program pro FIR filtraci. Jedná se o demonstrační program, který je součástí dodávaného software. V programu jsou přepínány 4 81
FIR filtry s různými propustnými pásmy a 5 filtr je vlastně přímé propojení vstupu a výstupu. Volba filtru se provádí z host počítače vysláním znaků 0 až 9. Vstup filtru je alternativně z A/D převodníku nebo z interního programového generátoru náhodných čísel. Příjem znaku „Z“ program ukončí a přejde do monitoru EZ-KIT Lite. Každý přijatý znak do DSP z host počítače je zpětně potvrzován vysláním znaku „z“. Filtry jsou navrženy pro následující propustná a nepropustná pásma: Filtr FIR1 FIR2 FIR3 FIR4
Spodní nepropustné pásmo 0 - 269 Hz 0 - 426 Hz 0 - 675 Hz 0 - 1070 Hz
Propustné pásmo 328 - 448 Hz 521 - 710 Hz 825 - 1125 Hz 1308 - 1783 Hz
Horní nepropustné pásmo 547 - 4000 Hz 866 - 4000 Hz 1375 - 4000 Hz 2179 - 4000 Hz
Je předpokládáno, že vzorkovací frekvence A/D a D/A převodníku je 8 kHz. Všechny čtyři filtry byly navrženy pro zvlnění (ripple) v propustném pásmu 0,1 dB a jsou 255 řádu, tj. taps = 256. Jejich impulsní charakteristiky o konečné době trvání jsou znázorněny na obr. XXXX.
Obr. 1. Impulsní charakteristiky filtrů FIR 1 až 4 Deklarace a inicializace proměnných
Deklarace a inicializace je uvedena jen pro proměnné spojené s funkci filtru. Všechny filtry jsou řádu 256 (konstanta taps). . const .var .init {
taps=256; coeffsTbl [5]; coeffsTbl: ^fir1_coefs, ^fir1_coefs, ^fir2_coefs, ^fir3_coefs, ^fir4_coefs; ^^^^^^^^^^ dummy for talk through }
.var/dm/ram/circ .var/dm/ram/circ
rx_buf[3]; tx_buf[3];
/* Status + L data + R data */ /* Cmd + L data + R data */
82
.var/dm/ram/circ init_cmds[13]; .var/dm stat_flag; .var/circ data[taps]; .var which_fir; .var voice_or_noise; .var seed_msw, seed_lsw; .var rndnum; .var/pm/circ .var/pm/circ .var/pm/circ .var/pm/circ .init .init .init .init
fir1_coefs[taps]; fir2_coefs[taps]; fir3_coefs[taps]; fir4_coefs[taps]; fir1_coefs: ; fir2_coefs: ; fir3_coefs: ; fir4_coefs: ;
Základní program
Dosazení počátečních hodnot pro kruhové zásobníky a nulování zpožďovací linky zajišťuje následující část programu, která se vykoná pouze po spuštění. V tomto úseku se definují počáteční hodnoty proměnných, podle kterých se program větví. Proměnná voice_or_noise určuje, zda bude použit pro filtry vstup z A/D převodníku nebo zda se použije generátor náhodných čísel. Proměnná which_fir určuje, který ze tří filtrů bude použit, případně zda bude propojení vstupu a výstupu přímé. i2=^data; m0=1; l2=taps; i4=^fir2_coefs; m4=1; l4=taps; si=0; dm(which_fir)=si; { začíná s vypnutou filtrací } dm(voice_or_noise)=si; { začíná se vstupem z A/D převodníku } si=h#1234; dm(seed_lsw)=si; { inicializace náhodného generátoru } dm(seed_msw)=si; i2=^data;
zero:
cntr=taps; do zero until ce; dm(i2,m0)=0; { nulování zpožďovací linky prodata } { if not ce jump zero;}
Program vykonává permanentně následující příkazy ve smyčce. Ve skutečnosti jen čeká na příchod znaků po sériové lince z host počítače a dosazuje pro filtraci zvolený filtr. again:
{ přišel znak z host počítače ?} ar = dm (CHAR_WAITING_FLAG); none = pass ar; if ne jump again;
{ kbhit () }
{ něco přišlo } i7 = dm (PTR_TO_GET_CHAR); { get int } call (i7); if lt jump again; { time out } ay0 = 48; { '0' } none = ax1 - ay0; if lt jump cmd1; ay0 = 57; { '9' } none = ax1 - ay0; if le jump newfir; { skok na '0'..'9' } cmd1: ay0 = 90; { 'Z' }
83
iSend:
none = ax1 - ay0; if eq rts; { návrat zpět do monitoru. } ar = ax1 + 1; ax1 = ar; i7 = dm (PTR_TO_OUT_CHAR); { vyslání znaku } call (i7);
{ čekání na dokončení přenosu } wt: ar = dm (CHAR_SEND_DONE_FLAG); none = pass ar; if eq jump wt; toggle fl1; jump again; newfir:
{ výchozí volba je vstup A/D převodníku, mikrofónu } ar = pass 0; dm(voice_or_noise) = ar; { 0 – bez filtrace, 1-4 == fir1-4; + 5 pro šum } ay0 = 53; { '5' } none = ax1 - ay0; if lt jump newfir1; ar = pass 1; dm(voice_or_noise) = ar;
ay0 = 5; ar = ax1 - ay0; ax1 = ar; newfir1: ay0 = 48; { '0' } ar = ax1 - ay0; dm(which_fir)=ar;
{ zbytek jako s mikrofonem } { načti číslo aktuálního filtru: 0..4 }
{ set i4 } ay0 = ^coeffsTbl; ar = ar + ay0; i7 = ar; ar = dm (i7, m7); i4 = ar; { pro potvrzení je vyslán zpět znak 'z' } ax1 = 122; { 'z' } jump iSend;
Obsluha přerušení od příjmu nového vzorku
Tento úsek programu se periodicky spouští přerušením od naměření nového vzorku, který se snímá předvolenou vzorkovací frekvenci 8 kHz. input_samples: ena sec_reg;
{ užití sekundárních registrů }
ar=dm(voice_or_noise); ar=pass ar; if eq jump voice_input; noise_input:
84
call getrnd; { generování 16bitového náhodného čísla v sr1 } sr=ashift sr1 by -1 (hi); { zeslabit signál dvakrát } jump process_sample; voice_input: sr1 = dm (rx_buf + 2); { přečíst vzorek z portu SPORT0 (z codec) } process_sample: dm(i0,m0)=sr1; ar=dm(which_fir); none = pass ar; if ne jump fir;
{ store sample in data buffer (delay line) } { decide which filter to do }
nofilt: {sr=ashift sr1 by -1 (hi);} { zeslabit signál dvakrát } mr1=sr1; output: dm (tx_buf + 1) = mr1; { filtrovaný výstup do SPORT (do repro) } dm (tx_buf + 2) = mr1; { filtrovaný výstup do SPORT (do repro) } rti;
Podprogram pro výpočet výstupu FIR filtru
Funkce FIR filtru byla již vysvětlena dříve. fir:
cntr=taps-1; mr=0, mx0=dm(i0,m0), my0=pm(i4,m4); do fir1loop until ce; fir1loop: mr=mr+mx0*my0(ss), mx0=dm(i0,m0), my0=pm(i4,m4); { if not ce jump fir1loop;} mr=mr+mx0*my0(rnd); if mv sat mr; sr = ashift mr1 by 1 (lo); {zesílit filtrovaný signál 2krát } mr1 = sr0; jump output;
Ověření funkce filtru
Z impulsní odezvy lre Fourierovou transformací vypočítat frekvenční charakteristiku filtru. Výsledek výpočtu je na obr. XXXX. K ověření funkce filtru lze použít interní generátor bílého šumu, který je součásti programu pro DSP. Výstup filtru lze připojit na vstup zvukové karty běžného počítače (PC) a aplikací pro záznam zvuku lze zaznamenat výstupní signál codecu do souboru WAV. Vzorkovací frekvenci je třeba volit 8 nebo 11,025 kHz, tj. telefonní nebo rozhlasovou kvalitu. Dále je třeba, aby WAV soubor obsahoval vzorky s 16 bity. Záznam do vzorků s 8 bity by znamenal vysokou úroveň zaokrouhlovacího šumu a zkreslení pozadí spekter. Data z WAVsouboru lze načíst do pracovního prostoru MATLABu. Toolboxem Signal processing je možné vyhodnotit frekvenční spektrum zaznamenaného signálu a tak konfrontovat teorii návrhu filtru s praktickým měřením. Limitující vlastností cocecu zvukové karty je nevyhovující měření složek signálu pod 20 Hz. Toto pásmo je však z hlediska citlivosti lidského sluchu nezajímavé. MATLAD umožňuje rovněž vytvořit libovolný WAV-soubor. Tímto způsobem lze generovat harmonické signály o vhodné frekvenci a přenos filtru testovat klasickým postupem. Měřením amplitudy na výstupu filtru opět přivedeného na vstup zvukové karty. Domácí laboratoř pro programování DSP je tímto vybavením skoro zadarmo.
85
Obr. 2. Teoretická frekvenční charakteristiky filtrů FIR 1 až 4
Obr. 3. Spektrum signálu na výstupu filtrů FIR 1 až 4 se vstupním signálem typu bílý šum
86
Porovnání různých DSP od Analog Device, Texas Instruments & Motorola Signálové procesory s pevnou řádovou čárkou je možné vzájemně porovnat s ohledem na velikost paměti, operační rychlost a možnost přístupu k vyrovnávací paměti periferie. Tab. D-IV Porovnání DSP s pevnou řádovou čárkou podle velikosti paměti a rychlosti operací Výrobce
Analog Devices Motorola
Texas Instruments
DSP Processor
ADSP-2181
DSP56002
TMS320C50
TMS320C53
On-Chip RAM 32K words “Glue-Less” Off-Chip RAM and Yes I/O Interface?
1K word
9.5K words
3.5K words
No
No
No
DSP Instruction Rate
20 MIPS
40 MIPS
40 MIPS
33 MIPS
Tab. D-IV Porovnání DSP podle přístupu k paměti mimo číp a možnosti použití DMA Porovnání možností DSP
ADSP-2181
Přístup k paměti mimo číp DSP
2 přístupy za instrukční 1 přístup za instrukční cyklus, žádný HW cyklus DSP, požadován k dekódování není třeba externí HW pro paměť a I/O
1 přístup zabere 2 instrukční cykly DSP, požadován externí HW pro paměť a I/O
Interface k I/O periferiím
Žádná podpora k přístupu Integrovaná podpora k vyrovnávací paměti I/O paměťového periferie prostoru, žádný HW k dekódování není třeba
Integrovaná podpora I/O paměťového prostoru, požadován externí HW pro paměť a I/O
Přímý přístup k paměti Integrovaná podpora (DMA) DMA
DSP56002
Žádná podpora DMA
TMS320C53
Podporuje externí DMA kontrolér, ale DSP operace jsou suspendovány během DMA přenosu
Literatura [1]
Considerations for Selecting a DSP Processor - Why Buy the ADSP-2181?. Analog Devices Application Note AN-400, Inc., Norwood USA, 4-5/ 1995.
[2]
ADSP-2100 Family User’s Manual,Third Edition. Analog Devices, Inc., Norwood USA, September 1995.
[3]
ADSP-2100 Family, EZ-KIT Lite Reference Manual. Analog Devices, Inc., Norwood USA, September 1995.
[4]
Audio Application of the ADSP Family (IIR Filters). Application Note AN-217, Analog Devices, Inc., Norwood USA.
[5]
Sedláček, M. Zpracování signálů v měřící technice. Vydavatelství ČVUT Praha, 1998.
87
SIGNÁLOVÉ PROCESORY FIRMY ANALOG DEVICES............................................................................ 1
ARCHITEKTURA RODINY DSP TYPU ADSP-21XX ................................................................................................ 1 FORMÁTY ČÍSEL S PEVNOU ŘÁDOVOU ČÁRKOU .................................................................................................... 3 SIGNÁLOVÝ PROCESOR ADSP-2181 .................................................................................................................... 5 Paměť .............................................................................................................................................................. 6 Sběrnice ........................................................................................................................................................... 7 Výpočetní jednotky........................................................................................................................................... 7 Generátory adres dat....................................................................................................................................... 8 Řadič programu............................................................................................................................................... 9 Přerušovací systém:....................................................................................................................................... 10 Sériové porty.................................................................................................................................................. 12 IDMA Port..................................................................................................................................................... 14 Časovač (Timer) ............................................................................................................................................ 14 PROGRAMOVÁNÍ SIGNÁLOVÉHO PROCESORU RODINY ADSP 21XX .................................................................... 15 Komentáře (poznámky).................................................................................................................................. 15 Instrukce ........................................................................................................................................................ 15 Identifikátory ................................................................................................................................................. 16 Data............................................................................................................................................................... 16 Přiřazovací příkaz ......................................................................................................................................... 16 Přímé a nepřímé adresování paměti.............................................................................................................. 17 Cyklické a lineární zásobníky (buffers) ......................................................................................................... 17 Inicializace proměnných a zásobníků............................................................................................................ 18 Direktivy pro překlad .................................................................................................................................... 19 Registry.......................................................................................................................................................... 20 INSTRUKCE VÝPOČETNÍCH JEDNOTEK DSP RODINY ADSP 21XX ....................................................................... 22 Instrukce výpočetní jednotky ALU ................................................................................................................. 22 Instrukce výpočetní jednotky MAC ................................................................................................................ 25 Instrukce výpočetní jednotky Shifter.............................................................................................................. 27 Instrukce přesunu dat .................................................................................................................................... 30 Multifunkční instrukce ................................................................................................................................... 30 Řízení běhu programu ................................................................................................................................... 31 Různé instrukce.............................................................................................................................................. 33 MATEMATICKÉ PROGRAMY PRO SIGNÁLOVÉ PROCESORY RODINY ADSP 21XX ................................................. 35 Filtr prvního řádu.......................................................................................................................................... 35 Konvoluce signálů – filtr FIR ........................................................................................................................ 36 Filtr FIR s dvojnásobnou přesností koeficientů............................................................................................. 38 Filtr IIR v přímé formě .................................................................................................................................. 39 Decimace vzorků ........................................................................................................................................... 41 Interpolace vzorků ......................................................................................................................................... 42 Generováni funkce SIN.................................................................................................................................. 43 Generování náhodných čísel ......................................................................................................................... 44 Podprogram pro dělení ................................................................................................................................. 45 Podprogram pro odmocnění.......................................................................................................................... 45 Výpočet efektivní hodnoty.............................................................................................................................. 47 Výpočet Radix-2 FFT metodou DIT .............................................................................................................. 49 POPIS FUNKČNÍCH VLASTNOSTÍ KARTY EZ-KIT LITE......................................................................................... 55 Stereo codec AD1847 .................................................................................................................................... 56 MONITOR EZ-KIT LITE...................................................................................................................................... 59 POSTUP NÁVRHU UŽIVATELSTKÉHO PROGRAMU ................................................................................................ 60 Popis architektury systému............................................................................................................................ 61 Vytvoření zdrojového kódu uživatelského programu..................................................................................... 62 Překlad zdrojového kódu ............................................................................................................................... 62 Linkování EXE programu pro DSP ............................................................................................................... 62 Zavedení EXE souboru do DSP..................................................................................................................... 63 Ladění programu (debugging)....................................................................................................................... 64 Generování souboru k naprogramování EPROM ......................................................................................... 64 POVINNÁ ČÁST PROGRAMU V DSP ..................................................................................................................... 65 Definice adres odkazujících na paměťově mapované registry ...................................................................... 65 Deklarace základních proměnných a zásobníků............................................................................................ 65 Inicializace základních proměnných a zásobníků.......................................................................................... 65
88
Vektor přerušení ............................................................................................................................................ 68 Obsluha přerušení ......................................................................................................................................... 68 Začátek programu ......................................................................................................................................... 70 Inicializace generátorů adres........................................................................................................................ 70 Nastavení a inicializace sériového portu SPORT0........................................................................................ 70 Nastavení systému a paměti........................................................................................................................... 72 Inicializace codecu AD1847.......................................................................................................................... 73 Inicializace emulátoru UART ........................................................................................................................ 75 Uživatelská část programu ............................................................................................................................ 75 KOMUNIKACE MEZI DSP A HOST POČÍTAČEM TŘÍDY PC .................................................................................... 75 Emulace obvodu UART v EZ-KIT Lite .......................................................................................................... 75 Použití modulu UART k příjmu znaků prostřednictvím RS 232..................................................................... 76 Použití modulu UART k vysílání znaků prostřednictvím RS 232 ................................................................... 77 Komunikace host počítače s DSP s využitím Visual Basicu .......................................................................... 78 REALIZACE FIR FILTRU ...................................................................................................................................... 81 Deklarace a inicializace proměnných ........................................................................................................... 82 Základní program.......................................................................................................................................... 83 Obsluha přerušení od příjmu nového vzorku................................................................................................. 84 Podprogram pro výpočet výstupu FIR filtru.................................................................................................. 85 Ověření funkce filtru...................................................................................................................................... 85 POROVNÁNÍ RŮZNÝCH DSP OD ANALOG DEVICE, TEXAS INSTRUMENTS & MOTOROLA ................................... 87 LITERATURA ...................................................................................................................................................... 87
89