instrukcja - Politechnika Warszawska
Transkrypt
instrukcja - Politechnika Warszawska
Politechnika Warszawska Wydział Elektryczny Laboratorium Programowania urządzeń mikroprocesorowych automatyki elektroenergetycznej Skrypt do ćwiczenia M.35 Implementacja algorytmów zabezpieczeniowych na procesorze DSP – cz.1 (procesor stałoprzecinkowy ADSP 2181). 1 Implementacja algorytmów zabezpieczeniowych na procesorze DSP - cz. 1 /procesor stałoprzecinkowy/ Opracowali: Krzysztof Aniołek Andrzej Bałazy Ryszard Kowalik 1. Cel i zakres ćwiczenia Celem ćwiczenia jest poznanie budowy i działania przykładowego procesora sygnałowego DSP, stałoprzecinkowego oraz sposobu tworzenia i uruchamiania programów, realizujących podstawowe algorytmy zabezpieczeniowe na sterowniku mikroprocesorowym, zbudowanym w oparciu o taki procesor. 2. Wprowadzenie Urządzenia Automatyki Zabezpieczeniowej od kilkunastu lat są konstruowane w oparciu o technikę cyfrową. Ten sposób budowy powoduje, ze urządzenia charakteryzują się cennymi właściwościami, takimi jak: - komunikowanie się z innymi urządzeniami cyfrowymi - pamięć o dużej pojemności - możliwość realizacji złożonych algorytmów w zakresie przetwarzania sygnałów - możliwość łatwego samo-testowania pozwalająca zbadać własną sprawność układu (co jest szczególnie ważne dla zabezpieczeń) - integracja w struktury, które przyczyniają się do znacznego ograniczenia okablowania wtórnego w stacjach elektroenergetycznych - redukcja kosztów sprzętu mikroprocesorowego - duża szybkość działania Wśród wielu procesorów stosowanych obecnie w technice zabezpieczeniowej szczególną rolę zajęły procesory sygnałowe DSP (Digital Signal Procesor). Charakteryzują się one ogromną szybkością działania, przez co często są stosowane w najnowszych zabezpieczeniach czołowych firm. 3. Budowa stanowiska laboratoryjnego 3.1. Opis elementów, z których składa się stanowisko laboratoryjne Do budowy stanowiska laboratoryjnego wykorzystano zestaw szkoleniowy oparty o procesor ADSP 2181 umieszczony na płytce EZ-KIT Lite. Zawiera on, oprócz procesora, układ przetwornika A/C i C/A (kodeka) wraz z układami liniowymi umożliwiającymi wprowadzenie i wyprowadzenie sygnałów analogowych oraz układy konwerterów TTL/RS232 pozwalające na wymianę informacji przez łącze szeregowe z komputerem klasy PC. Do zestawu szkoleniowego ADSP1281 dołączono wymuszalnik, którego zadaniem jest wytworzenie sygnałów analogowych i dwustanowych symulujących obiekt poddawany obserwacji. W tym celu do wejść analogowych modułu DSP podłączono dwukanałowy symulator przebiegów analogowych, wyposażony w generator przebiegu sinusoidalnego o częstotliwości 50Hz z możliwością regulacji amplitudy oraz fazy, a do wejść i wyjść dwustanowych wymuszalnik sygnałów dwustanowych umożliwiający zarówno zadawanie stanu sygnałom dwustanowym za pomoca przełączników jak i obserwację stanu wyjść dwustanowych zestawu ADSP za pomocą diod LED. Źródłem sygnałów analogowych w stanowisku laboratoryjnym może być również generator z możliwością regulowania kształtu i częstotliwości przebiegu analogowego. Wyposażenie stanowiska stanowią również: czterokanałowy oscyloskop pozwalający na obserwacje przebiegów sygnałów analogowych i dwustanowych, zasilacz modułu DPS oraz komputer klasy PC z systemem 2 Windows i oprogramowaniem potrzebnym do pisania, uruchamiania i przesyłania kodu programu z komputera do modułu DSP. Budowa stanowiska laboratoryjnego przedstawiona została na rysunku 1 a jego schemat blokowy na rysunku 2. Moduł z procesorem ADSP2181 zasilany jest napięciem 9V DC dostarczonym z zewnętrznego zasilacza, do modułu ADSP podłączony jest za pomocą interfejsu RS232 komputer PC. Wymiana informacji pomiędzy modułem ADSP a wymuszalnikiem odbywa się za pomocą taśmy 50-pinowej. Wymuszalnik przystosowany jest do połączenia z zewnętrznym generatorem oraz oscyloskopem. Wymuszalnik (układ sterujący) składa się z: symulatora dwustanowych sygnałów wejściowych procesora DSP, układu wizualizującego stany wyjść dwustanowych procesora DSP oraz generatora przebiegu 50Hz wraz z przesuwnikiem fazowym. Sygnały wchodzące na wejścia dwustanowe procesora (FL5..FL8) są generowane poprzez cztery przełączniki podające napięcie +5V. Nad przełącznikami, na przedniej stronie układu wymuszającego znajdują się cztery diody LED, na których odwzorowane są sygnały wyjść dwustanowych (FL1..FL4) procesora. COM RS232 PC Taśma 9V P3 J3 J4 DSP moduł z procesorem DSP oscyloskop czterokanałowy generator off on off on off on off on układ sterujący (wej./wyj. dwustanowe, reg. gen. 50Hz, przes. fazowy) Rysunek 1. Budowa stanowiska laboratoryjnego 3 L1 A G1 C Ampl.; f 0-100kHz Generator fi A Wej. kanał 1 A Wej. kanał 2 C Kodek Ampl. Układ ster. G2 A C 50Hz C Ampl. Łącze szeregowe FL1 FL2 FL3 FL4 R Rdzeń DSP 21xx GND FL5 FL6 FL7 FL8 Wej. kanał 3 Port SPORT0 Procesor DSP /ADSP 2181/ Pamięć RAM 48kB /Program/ Pamięć RAM 32 kB /Dane/ Wej. kanał 4 Oscyloskop 4 kanałowy Port SPORT1 5V Układ sterujący 220Vac Stab. 9V/5V Pamięć EPROM Moduł z procesorem DSP 9V Konwertery TTL/RS232 Łącze RS232 /do komputera PC/ PC Zasilacz Rysunek 2. Schemat blokowy stanowiska laboratoryjnego Analogowe sygnały wejściowe procesora powstają w generatorze przebiegu sinusoidalnego. Regulację kąta i amplitud przebiegów umożliwiają trzy potencjometry obrotowe umieszczone na pokrywie obudowy. Wbudowany generator, nie jest jednak jedynym źródłem sygnałów analogowych. Istnieje także możliwość uzyskania przebiegu analogowego z generatora zewnętrznego. Generator zewnętrzny używany jest w trakcie badań procesora DSP do badania filtrów cyfrowych ze względu na możliwość wytwarzania sygnałów o dużym przedziale częstotliwości. Wybór źródła sygnału (wewnętrzny generator 50Hz lub generator zewnętrzny) odbywa się poprzez przełącznik (L1) znajdujący się z tyłu obudowy. Ostatnim z pięciu elementów stanowiska jest oscyloskop czterokanałowy. Służy on do obserwacji sygnałów analogowych wchodzących oraz wychodzących z wejść oraz wyjść analogowych modułu DSP. 3.2. Opis budowy modułu EZ-KIT Lite Podstawową częścią stanowiska laboratoryjnego jest moduł EZ-KIT Lite. Jego integralną częścią jest procesor ADSP-2181, pełniący najważniejsze funkcje w układzie. Oprócz procesora DSP na płytce modułu umieszczone są: przetwornik A/C i C/A nazywany kodekiem, pamięć EPROM oraz kilka złącz i układów peryferyjnych takich jak wzmacniacze analogowe oraz konwerter TTl/RS232. Poniżej przedstawione są charakterystyczne cechy części składowych modułu. Parametry modułu: Procesor Przetwornik A/C i C/A Wejścia analogowe Wyjścia analogowe Zasilanie - ADSP-2181 KS-133 - częstotliwość pracy 33MHz przy zew. generarze kwarcowym: 16.667 MHz - kodek stereo AD1847 - 2 x 2Vac lub 2 x 20mVac - 2 x 1Vac - od 8 do 10Vdc / 300mA Konstrukcja mechaniczna modułu pokazana jest na rysunku 3, na którym każdemu z elementów przyporządkowano oznaczenia niezbędne do ich identyfikacji. ADSP-2181 33 MIPS DSP AD1847 Stereo Złącze RS-232 Gniazdo EPROM Przyciski Diody sygnalizacyjne Gniazdo zasilania Złącza dodatkowe - U3 - U7 - J3 - U2 - S1, S2 - D1, D2 - J4 - P2,P3 4 Zwory konfiguracyjne Gniazda analogowe - JP1, JP2 - J1, J2 P3 D2 Pin 1 J4 J3 U3 J2 ADSP-2181 Digital Signal Processor P1 J1 U7 AD1847 Stereo Codec U2 JP2 Gniazdo EPROM S1 MIC S2 Pin 1 D1 Pin 1 P2 ADSP-2181 EZ-KIT LITE JP1 RESET INTERRUPT FL1 Rysunek 3. Budowa modułu EZ-KIT Lite Pamięć EPROM (27C010 - 256Kbajtów) jest podłączona do procesora poprzez port Byte DMA, który może adresować do 32M bitów (4Mbajty) pamięci. Jej konfiguracja odbywa się za pomocą pinów JP1. Ustawienie wszystkich parametrów pamięci następuje z chwilą zresetowania układu. Do konwersji A/C i C/A wykorzystuje się 16-to bitowy kodek o nazwie Stereo Audio I/O AD1847 SoundPort Codec (U7), który jest połączony z procesorem DSP za pomocą portu szeregowego SPORT0. Jako wejście sygnału analogowego wykorzystywane jest gniazdo typu jack (J1) 3.5mm. Jako wyjście sygnału analogowego używane jest gniazdo typu jack o oznaczeniu J2. W stanowisku laboratoryjnym sygnały analogowe są wprowadzane i wyprowadzane z modułu przez złącze P3. Do konfiguracji wejść analogowych służy grupa sześciu pinów (JP2). Do komunikacji z komputerem PC służy łącze o standardzie RS232 wyprowadzone na złącze żeńskie (J3). Do zasilania modułu wykorzystuje się zewnętrzny zasilacz o napięciu stałym 9V podłączonym przez złącze (J4) wtyczką cylindryczną jack 5.5mm, w której centralny pin ma biegunowość ujemną (-), natomiast jej część zewnętrzna dodatnią (+). (P1) jest grupą szesnastu pinów, które można użyć do podłączenia procesora z in-circuit emulatorem EZ-ICE (Pin 7 usunięto). Złącza (P2) i (P3) są pięćdziesięcio-pinowymi gniazdami umożliwiającymi dostęp do sygnałów procesora. Można je wykorzystać do wyprowadzania sygnałów na zewnątrz układu, sprawdzania działania lub rozbudowy modułu. Przycisk o nazwie (S1) podaje sygnał Reset dla procesora DSP. Drugi z przycisków o nazwie (S2) przekazuje do procesora DSP sygnał przerwania IRQE. Moduł wyposażony jest standardowo w 2 diody świecące pokazujące stan jego pracy: - (D1) - dioda o kolorze czerwonym pokazuje stan wyjścia o nazwie FL1 (flaga FL1). Istnieje możliwość programowego kontrolowania jej stanu - (D2) - dioda o kolorze zielonym informuje o obecności zasilania modułu. W skład zestawu szkoleniowego, oprócz modułu EZ_KIT Lite, wchodzi także pakiet programów o nazwie "ADSP-2181 Family development software", zawierający komplet narzędzi programowych umożliwiający uruchomienie systemu mikroprocesorowego opartego o procesor ADSP2181. W skład pakietu wchodzą następujące programy: - "Builder System" - umożliwiający zdefiniowanie struktury budowanego systemu - "Asembler" - pozwalający na skompilowanie programu napisanego w mnemonikach procesora ADSP2181, do postaci kodu wynikowego - "Linker" - łączący pliki wynikowe w plik wykonawczy, który można uruchomić w module EZKIT - "Symulator" - umożliwiający wykonanie symulacji działania napisanego programu 5 - "PROM Spliter" generujący kod wykonawczy, który może być zapisane do pamięci EPROM. 3.3. Opis procesora ADSP-2181 3.3.1. Wstęp ADSP-2181 jest mikrokomputerem jednoukładowym ukierunkowanym na przetwarzanie sygnałów cyfrowych, czyli procesorem DSP od angielskiego skrótu "Digital Signal Procesor". Wyprodukowany został w technologii CMOS 0.5µm i wykorzystując zegar 33MHz wykonuje każdą instrukcję w pojedynczym cyklu procesora, tj. w czasie 30ns. Jest produkowany jest w obudowach TQFP i PQFP 128pinowych. (W module EZ-Kit Lite zastosowano procesor z obudowę PQFP.) Struktura blokowa procesora została pokazana na rysunku 4: Łączy ona bazową architekturę rodziny ADSP-21xx, na którą składają się: - trzy jednostki obliczeniowe - dwa generatory adresu danych - generator adresu programu (program sequencer) z dodatkowymi układami peryferyjnymi: - dwoma portami szeregowymi - 16-to bitowym wewnętrznym portem DMA - bajtowym portem DMA - programowalnym timerem - portami wejścia-wyjścia - kontrolerem przerwań oraz - układem sterowania poborem mocy (Power Down) - wewnętrzną pamięcią programu i pamięcią danych Wymienione elementy spełniają w procesorze ADSP2181 następujące funkcje: - trzy jednostki obliczeniowe - jednostki te przetwarzają bezpośrednio 16-to bitowe dane: - ALU - odpowiada za wykonywanie standardowych operacji arytmetycznych i logicznych - MAC multiplier/accumulator - wykonuje w jednym cyklu procesora operacje: mnożenia, mnożenia/dodawania, mnożenia/odejmowania. Wynik obliczeń tych operacji może być nawet 40-to bitowy - SHIFTER - wykonuje logiczne oraz arytmetyczne przesunięcie, normalizację, denormalizację oraz wyprowadza wykładnik potęgi. Shifter może być użyty do sprawnego implementowania obliczeń zmiennoprzecinkowych - dwa generatory adresu danych - elementy te o nazwach DAG1 i DAG2, dostarczają adresy dla równoczesnego pobrania argumentu z pamięci danych oraz z pamięci programu. Każdy układ utrzymuje oraz aktualizuje cztery wskaźniki adresu - generator adresu programu (program sequencer) - układ przy pomocy generatorów adresu danych zapewnia sprawne dostarczenie argumentów operacji do jednostek obliczeniowych. Poza tym inicjuje skoki warunkowe, wywołania podprogramów, oraz powroty z podprogramów w pojedynczym cyklu rozkazowym. Dzięki niemu procesor ADSP-2181 wykonuje np. kod pętli warunkowej bez żadnych sprecyzowanych instrukcji skoku - dwa porty szeregowe - o nazwach SPORT0 i SPORT1 służą do komunikacji z innymi urządzeniami. Umożliwiają uruchomienie mechanizmu buforowania transmisji szeregowej. - 16-to bitowy wewnętrzny port DMA - o nazwie IDMA służy do połączenia procesora DSP z zewnętrznym systemem mikroprocesorowym. Skład się on z 16 sygnałów danych/adresów oraz 5 sygnałów sterujących - bajtowy port DMA (BDMA) - jest dwukierunkowym portem umożliwiającym adresowanie pamięci zewnętrznej RAM oraz ROM do wielkości 4MB. Pozwala to na przechowywanie bardzo dużych bloków danych - programowalny timer - jest układem licznikowym umożliwiającym odliczanie czasu oraz generację przerwań - porty wejścia wyjścia - składa się na nie osiem programowalnych pinów wejścia/wyjścia, trzy piny wyjściowe oraz dwa dodatkowe sygnały dostępne przy alternatywnej konfiguracja SPORT1 - kontroler przerwań - jest układem umożliwiającym sprawowanie nadzoru oraz podjęcie właściwej reakcji na 11 różnych przerwań 6 - układ sterowania poborem mocy (Power Down) - służy do obniżenia poboru mocy procesora w przypadku np. aplikacji o zasilaniu bateryjnym - wewnętrzna pamięć programu i danych. - ten 80 kbajtowy obszar pamięci wewnętrznej (on-chip) skonfigurowanej jako 48kB pamięci RAM programu oraz 32kB pamięci RAM danych umożliwia sprawne wykonywanie programu oraz obliczeń. DATA ADDRESS GENERATORS Generatory Adresu Danych DAG1 DAG2 PROGRAM SEQUENCER POWERDOWN CONTROL PROGRAMOWALNE WE/WY WEWNĘTRZNA PAMIĘĆ FLAGI PAMOIĘĆ PROGRAMU PAMOIĘĆ DANYCH BYTE DMA CONTROLLER ZEWNĘTRZNA SZYNA ADRESÓW SZYNA ADRESÓW PAMIĘCI PROGRAMU SZYNA ADRESÓW PAMIĘCI DANYCH ZEWNĘTRZNA SZYNA DANYCH SZYNA DANYCH PAMIĘCI PROGRAMU SZYNA DANYCH PAMIĘCI DANYCH JEDNOSTKI ARYTMETYCZNE ALU MAC SHIFTER PORTY SZEREGOWE SPORT0 SPORT1 TIMER WEWNĘTRZNY PORT DMA SZYNA DMA Rdzeń budowy rodziny ADSP-2100 Rysunek 4. Budowa wewnętrzna procesora ADSP-2181 Elastyczna struktura oraz obszerny zestaw instrukcji pozwala procesorowi na wykonanie wielu operacji równolegle. W jednym cyklu procesor może w związku z tym np.: - generować nowe adresy programu - pobierać nowe instrukcje - wykonać jedno lub dwa przesłania danych - modyfikować jeden lub dwa wskaźniki adresów danych - wykonać operację obliczeniową. Wykonanie powyższych operacji nie koliduje z pracą innymi czynnościami procesora, który może równocześnie: - otrzymywać oraz transmitować dane poprzez dwa porty szeregowe - otrzymywać i/lub transmitować dane poprzez wewnętrzny port DMA - otrzymywać i/lub transmitować dane poprzez port bajtowy DMA - zmniejszać wartość timera. Rysunek 5 pokazuje budowę procesora ADSP-2181 w sposób bardziej szczegółowy, pozwalający na opisanie mechanizmów wymiany danych między jego elementami. Jak widać wewnętrzna szyna wyniku (R) łączy jednostki obliczeniowe w taki sposób, że wyjście dowolnej jednostki może być wejściem innej dowolnej jednostki w kolejnym cyklu. Dwa generatory adresów danych DAG1 i DAG2 dostarczają adresy niezbędne do równoczesnego pobrania argumentu z pamięci danych oraz z pamięci programu. Każdy układ DAG utrzymuje oraz aktualizuje cztery wskaźniki adresu. Pojedynczy generator adresu danych (DAG) posiada trzy rejestry: - (M) Modify - (I) Index - (L) Length. Każdy z nich zawiera po cztery rejestry 14-to bitowe, które mogą być bezpośrednio czytane bądź zapisywane na szynę DMD. Rejestr I (I0-I3 w generatorze DAG1, I4-I7 w generatorze DAG2) zawiera aktualne adresy pamięci. Rejestr L (L0-L3 w generatorze DAG1, L4-L7 w generatorze DAG2) zawiera długości buforów. Rejestr M (M0-M3 w generatorze DAG1, M4-M7 w generatorze DAG2) zawiera wartość modyfikacji adresu. Generatory adresu umożliwiają dwa typy adresowania: adresowanie liniowe 7 i kołowe. Wartość rejestru L korespondująca z rejestrem I (np. L0 może korespondować z I0) decyduje, który schemat adresowania zostanie użyty. Przy adresowaniu liniowym należy wyłączyć logikę modułu poprzez ustawienie rejestru korespondującego L na wartość „0”. Przy adresowaniu buforu kołowego rejestr L jest ustawiony na długość bufora różną od zera. POWER DOWN CONTROL LOGIC INSTRUCTION REGISTER DAG1 Data Address Generator #1 PROGRAM SRAM 16K x 24 DAG1 Data Address Generator #1 DATA SRAM 16K x 24 BYTE DMA CONTROLLER PROGRAM SEQENCER 2 PROGRAMMABLE I/O 8 3 FLAGS 14 MUX 14 SZYNA PMA 14 ZEWNĘTRZNA SZYNA ADRESU SZYNA DMA 24 24 SZYNA PMD BUS EXCHANGE 16 MUX ZEWNĘTRZNA SZYNA DANYCH SZYNA DMD COMPANDING CIRCUITRY INPUT REGS INPUT REGS INPUT REGS ALU MAC SHIFTER OUTPUT REGS OUTPUT REGS OUTPUT REGS TRANSMIT REG TRANSMIT REG RECEIVE REG RECEIVE REG SERIAL PORT0 SERIAL PORT1 TIMER 16 INTERNAL DMA PORT 4 16 5 5 INTERRUPTS SZYNA R Rysunek 5. Budowa wewnętrzna procesora ADSP-2181 Sprawny transfer danych uzyskuje się, dzięki użyciu pięciu wewnętrznych szyn: - szyny PMA Program Memory Address - szyny PMD Program Memory Data - szyny DMA Data Memory Address - szyny DMD Data Memory Data - szyny R Result. Dwie szyny adresów PMA i DMA tworzą pojedynczą, multipleksowaną, zewnętrzna szynę adresową. Dwie szyny danych PMD i DMD w podobny sposób tworzą pojedyncza, multipleksowaną, zewnętrzna szynę danych. Pamięć programu może przechowywać zarówno instrukcje jak i dane, pozwalając procesorowi ADSP2181 na pobranie dwu argumentów w pojedynczym cyklu: jeden z pamięci programu oraz jeden z pamięci danych. ADSP-2181 może pobierać z pamięci programu w tym samym cyklu argument oraz następną instrukcję. Pamięć programu stanowi przestrzeń o szerokości 24-bitów (trzech bajtów). ADSP2181 ma możliwość adresowania 16K słów wewnętrznej pamięci programu RAM, co pozwala na dysponowanie pamięcią o wielkości 48Kbajty (3bajty x 16 x 1024bajty=48Kbajty). Pamięć danych jest przestrzenią o szeroką 16 bitów, użytą do magazynowania danych oraz rejestrów kontrolnych. ADSP-2181 ma możliwość adresowania 16k słów wewnętrznej pamięci danych lecz dla użytkownika dostępnych jest 16352 słów, ponieważ ponieważ resztę pamięci zajmują 32 zmapowane rejestry. ADSP-2181 posiada 16-to bitowy port (IDMA) łączący szynę PMD z szyną DMD. Jest on wykorzystywany do podłączania układów zewnętrznych. Port IDMA składa się z 16 pinów danych/adresów oraz 5 pinów kontrolnych. Port IDMA umożliwia bezpośredni dostęp do pamięci programu oraz danych RAM. Sygnały pochodzące z nieużywanego portu IDMA są dostępne na złączu P3 modułu EZ-KIT. Dwukierunkowy Port BDMA może bezpośrednio adresować do 4MB zewnętrznej pamięci RAM oraz ROM wykorzystywanej do podręcznego przechowywania programu lub danych. 8 ADSP-2181 zawiera dwa szeregowe porty (SPORT0 i SPORT1). Szeregowy port SPORT0 służy do przesyłania danych i komunikacji z kodekiem. Port SPORT1 służy opcjonalnie do wymiany danych z głównym komputerem, lub może być skonfigurowany jako wejście i wyjście dwustanowe. ADSP-2181 może odpowiadać na 11 źródeł przerwań, sześć zewnętrznych (jedna wyzwalana zboczem, dwie poziomem oraz trzy z możliwością konfigurowania) oraz pięć wewnętrznych generowanych poprzez: - timer - porty szeregowe (SPORTs) - port Byte DMA oraz - układy sterowania poborem mocy - sygnał RESET ADSP-2181 zapewnia 13 uniwersalnych bitów wejścia/wyjścia - flag. Osiem z nich można zaprogramować dowolnie jako wejścia lub wyjścia. Trzy flagi są na stałe skonfigurowane jako wyjścia. Dwie ostatnie flagi, z których jedna jest wejściem a druga wyjściem, są przypisane do portu SPORT1 W procesorze istnieje również programowalny timer generujący przerwania. Jest on zbudowany w oparciu o 16-to bitowy rejestr zliczający (TCOUNT), którego wartość jest zmniejszana po każdych n cyklach procesora, gdzie n jest wartością przechowywaną w 8 bitowym rejestrze (TSCALE). Kiedy wartość rejestru licznika osiąga zero, generowana jest przerwanie, a do rejestru zliczającego wpisywana jest powtórnie wartość z 16-to bitowego rejestru okresu (TPERIOD). 3.3.2. Rejestry Na rysunku 6 pokazano wszystkie rejestry specjalne procesora ADSP-2181. Rejestry te mogą mieć znaczenie bitowe lub mogą przechowywać wartości - liczby. Przykładowo: rejestr AX0 zawiera jeden z operandów jednostki arytmetyczno-logicznej ALU, rejestr I4 przechowuje wartość adresu DAG2. Rejestry bitowe składają się z bitów kontrolnych, pól, lub flag stanu. Na przykład: - rejestr ASTAT zawiera flagi stanu operacji arytmetycznych - bity w rejestrze DWAIT określają opóźnienie cyklu odczytu lub zapisu danych, dla różnych zakresów adresów mapy pamięci - rejestry PMOVLAY i DMOVLAY określają wielkość przestrzeni adresowej dla pamięci danych oraz programu. (Rejestry te mogą być użyte w instrukcjach przesyłania danych.) Niektóre rejestry są dostępne w obszarze pamięci danych. Są to: - System Control Register - DWAIT - timer - port IDMA - port IDMA - SPORT 9 PROGRAM SRAM 16K x 24 PROGRAM SEQENCER DAG2 I0 I1 I2 I3 M0 M1 M2 M3 SSTAT SSTAT IFC CNTR OWRCNTR COUNT STACK 4 x 14 IMASK MSTAT ASTAT STATUS STACK 12 x 25 DAG2 L0 L1 L2 L3 I4 I5 I6 I7 M4 M5 M6 M7 L4 L5 L6 L7 LOOP STACK 4 x 18 PC STACK 16 x 14 BYTE DMA PORT IDMA PORT BTYPE BIAD BEAD BMPAGE BDIR BWCOUNT PMOVLAY DMOVLAY 0x3FFF 0x3FFE DATA SRAM 16K x 24 SYSTEM CONTROL DM WAIT CONTROL IDMAA 14 SZYNA PMA 14 SZYNA DMA 24 SZYNA PMD PX 16 SZYNA DMD AX0 AX1 AY0 AY1 MX0 ALU AR MX1 MY0 MY1 SI MAC AF MR0 MR1 MR2 SE SB SHIFTER MF SR0 RX0 TX0 RX1 TX1 0x3FFA-0x3FF3 0x3FF2-0x3FEF CONTROL REGISTERS CONTROL REGISTERS SR1 SPORT 0 SPORT 1 TIMER FLAGS 0x3FFD 0x3FFC 0x3FFB TPERIOD TCOUNT TSCALE POWERDOWN CONTROL LOGIC PROGRAMMABLE I/O Rysunek 6. Rejestry procesora ADSP-2181 Rejestry te położone są pod adresami pokazanymi w poniższej tabeli. Nazwa rejestru Sys_Crtl_Reg Dm_Wait_Reg Tperiod_Reg Tcount_Reg Tscale_Reg Sport0_Rx_Words1 Sport0_Rx_Words0 Sport0_Tx_Words1 Sport0_Tx_Words0 Prog_Flag_Data BDMA_Word_Count BDMA_Control Adres 0x3fff 0x3ffe 0x3ffd 0x3ffc 0x3ffb 0x3ffa 0x3ff9 0x3ff8 0x3ff7 0x3fe5 0x3fe4 0x3fe3 Nazwa rejestru Sport0_Ctrl_Reg Sport0_Sclkdiv Sport0_Rfsdiv Sport0_Autobuf_Ctrl Sport1_Ctrl_Reg Sport1_Sclkdiv Sport1_Rfsdiv Sport1_Autobuf_Ctrl Prog_Flag_Comp_Sel_Ctrl BDMA_External_Address BDMA_Internal_Address IDMA_Control Adres 0x3ff6 0x3ff5 0x3ff4 0x3ff3 0x3ff2 0x3ff1 0x3ff0 0x3fef 0x3fe6 0x3fe2 0x3fe1 0x3fe0 Pokazane wartości rejestrów są wartościami obowiązującymi po zresetowaniu procesora. 3.3.4. Opis wybranych instrukcji procesora ADSP-2181 Instrukcje języka asemblera procesora ADSP-2181 mają formę prostych wyrażeń matematycznych. Charakteryzują się następującymi cechami użytkowymi: - algebraiczną składnią, która eliminuję potrzebę zapamiętywania mnemoników asemblera. Przykładowo typowa instrukcja dodawania arytmetycznego: przypomina proste równanie AR=AX0+AY0 - kodowaniem instrukcji w postaci pojedynczego, 24 bitowego słowa, wykonywanego w pojedynczym cyklu procesora - kompatybilnością z kodem wynikowym innych członków rodziny ADSP 21xx - obecnością wielu instrukcji warunkowych, wykonywanych w tym samym cyklu maszynowym co reszta instrukcji. (Warunek może być sprawdzony dla instrukcji: skoku, wywołania procedury, powrotu z procedury lub instrukcji arytmetycznych.) 10 - jednoczesnym wykonywaniem instrukcji arytmetycznych, wykorzystujących do dwóch odczytów oraz jednego zapisu w przestrzeni pamięci procesora, podczas pojedynczego cyklu maszynowego. Instrukcje arytmetyczne ALU - dodawanie/dodawanie z przeniesieniem [IF cond ] AR AF = xop + yop C yop+C constant ; yop C yop+C-1 constant ; - odejmowanie/odejmowanie z pożyczką [IF cond ] AR AF = xop - gdzie xop: AX0, AX1, AR, MR0, MR1, MR2, SR0, SR1 yop: AY0, AY1, AF constant: 0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32767, -2, -3, -5, -9, -17, -33, -65, -129, -257, -513, -1025, -2049, -4097, -8193, -1638, -32768 cond: - EQ - równe zero - NE - nie równe zero - LT - mniejsze od zera - GE - większe, równe zero - LE - mniejsze, równe zero - GT - większe od zera - operacje logiczne AND, OR, XOR [IF cond ] AR AF = yop AND OR XOR xop ; - czyszczenie/porównanie [IF cond ] AR AF = PASS Xop Yop constant ; gdzie xop: AX0, AX1, AR, MR0, MR1, MR2, SR0, SR1 yop: AY0, AY1, AF constant: 0, 1, 2, 3, 4, 5, 7, 8, 9, 15, 16, 17, 31, 32, 33, 63, 64, 65, 127,128, 129, 255, 256, 257, 511, 512, 513, 1023, 1024, 1025, 2047, 2048, 2049, 4095, 4096, 4097, 8191, 8192, 8093, 16383, 16384, 16385, 32766, 32767, -1, -2, -3, -4 -5, -6, -8, -9, -10, -16, -17, -18, -32, -33, -34, -64, -65, -66, -128, -129, -130, -256, -257, -258, -512, -513, 514, -1024, -1025, -1026, -2048, -2049, -2050, -4096, -4097, -4098, -8192, -8193, 8194, -16384, -16385, -16386, -32767, -32768. - Increment (zwiększanie o 1) [IF cond ] AR AF = yop+1 - Decrement (zmniejszanie o1) [IF cond ] AR AF = yop-1 gdzie: yop: AY0, AY1, AF Instrukcje arytmetyczne MAC - mnożenie [IF cond ] MR MF = xop * yop xop (SS) (SU) 11 ; (US) (UU) (RND) - mnożenie/dodawanie [IF cond ] MR MF = MR + xop * yop xop (SS) (SU) (US) (UU) (RND) ; = MR - * yop xop (SS) (SU) (US) (UU) (RND) ; - mnożenie/odejmowanie [IF cond ] MR MF xop Instrukcje przesunięcia - przesunięcie arytmetyczne [IF cond ] SR = [SR OR] ASHIFT xop (HI) (LO) ; = [SR OR] LSHIFT xop (HI) (LO) ; - przesunięcie logiczne [IF cond ] SR gdzie: (HI) - przesunięcie do rejestru SR1 (LO) - przesunięcie do rejestru SR0 Instrukcje przesyłania danych - przesył z rejestru do rejestru reg = reg; - przesył danej do rejestru reg = <data>; - przesył danej do rejestru danych dreg= <data>; - przesył z pamięci danych do rejestru (adres bezpośredni) reg = DM(<data>); - przesył z pamięci danych do rejestru danych(adres niebezpośredni) dreg = DM ( I0 I1 I2 I3 , , , , M0 M1 M2 M3 I4 I5 I6 I7 , , , , M4 M5 M6 M7 ); - przesył z pamięci programu do rejestru danych(adres pośredni) dreg = PM ( I4 I5 I6 I7 , M4 M5 M6 M7 ); - przesył z rejestru do pamięci danych (adresowanie bezpośrednie) DM(<addr>) = reg; - przesył z rejestru danych do pamięci danych (adresowanie pośrednie) DM ( I0 I1 I2 I3 , , , , M0 M1 M2 M3 ); = dreg ; 12 I4 I5 I6 I7 , , , M4 M5 M6 M7 - przesył z rejestru danych do pamięci programu (adresowanie pośrednie) DM ( I4 I5 I6 I7 , , , , M4 M5 M6 M7 ); = dreg ; Instrukcje sterujące wykonywaniem programu - instrukcja skoku [IF cond ] JUMP= <addr>; - powrót z podprogramu standardowego [IF cond ] RTS; - powrót z podprogramu obsługi przerwań [IF cond ] RTI; - wprowadzenie procesora w stan zmniejszonego poboru mocy - zmniejszenie szybkości procesora IDLE[(n)]; Instrukcje sterujące bitami procesora - przełączenie wyjścia dwustanowego [IF cond ] TOGGLE RESET SET = FLAG_OUT FL0 FL1 FL2 ; - ustawienie bitów rejestrów MSTAT ENA SEC_REG DIS BIT_REV 4. Opis oprogramowania użytego w stanowisku laboratoryjnym 4.1. Wstęp Elementem niezbędnym do prawidłowego funkcjonowania stanowiska, bez którego sprzęt staje się bezużyteczny, jest oprogramowanie. Umożliwia ono wykonywanie ćwiczenia, testowanie i prezentacja możliwości procesora, a przede wszystkim realizację funkcji zabezpieczeniowych. Całość oprogramowania składa się z trzech programów: Asembler, Host program oraz MathCad, w których funkcjonują stworzone specjalnie dla laboratorium aplikacje użytkowe. Mają one za zadanie: - symulację pracy procesora - komunikację z procesorem - generację współczynników filtru - przetwarzanie współczynników filtru do formatu wymaganego przez asembler procesora - stworzenie środowiska do funkcjonowania programów napisanych dla stanowiska. W celu poprawnego działania programów kompilatora i symulatora niezbędne jest utworzenie w systemie zmiennej o nazwie ADI_DSP oraz odpowiedniej ścieżki dostępu. Oba polecenie w postaci: SET ADI_DSP=C:\ADI_DSP Path c:\ADI_DSP\21XX\BIN zostały wpisane do pliku AUTOEXEC.BAT. 4.2. Asemblacja i linkowanie Po napisaniu programu w postaci źródłowej, czyli w języku asembler procesora ADSP 2181 należy ten program zamienić na postać binarną, możliwą do wykonania przez układ procesora. W tym celu należy poddać program asemblacji oraz linkowaniu. 13 Program źródłowy powinien mieć rozszerzenie: .DSP. Asembler zamienia kod źródłowy programu na postać binarną, w części skompilowaną. Asembler uruchamiany jest komendą asm21 mój_prog -2181 gdzie: mój_prog jest nazwą pliku. Tworzy on plik kodu wynikowego z rozszerzeniem .OBJ. Program Asemblera ma wiele opcji, które można wykorzystać. Pełna lista opcji jest wyświetlana w przypadku podania komendy asm21. Użyteczną opcją jest wykonanie kompilacji z listingiem , co umożliwia parametr „L” np.: asm21 mój_prog -2181 -L Pliki przetworzone przez asembler, można następnie zlinkować, poleceniem ld21 mój_prog -a adsp2181 -e mój_prog Program linkera pozwala na wprowadzenie do kodu powstałego w czasie asemblacji konkretnych adresów zamiennych oraz procedur. Działanie to tworzy plik wykonawczy, możliwy do wykonania przez procesor DSP 2181. Zbiór ten nosi nazwę pliku źródłowego z rozszerzeniem .EXE. Podobnie jak w przypadku asemblera lista dostępnych opcji linkera jest wyświetlana w przypadku podania komendy ld21. Przyspieszenie i ułatwienie powyższych dwu operacji, jest możliwe poprzez stworzenie pliku wsadowego o rozszerzeniu BAT, łączącego wszystkie niezbędne polecenia. Poniżej pokazano zawartość przykładowego liku o nazwie DEMO.BAT. asm21 demo -2181 ld21 demo -a ezkit_lt -e demo -x -g sim2181 -a ezkit_lt -e demo 4.3. Symulator Symulator to program demonstrujący pracę i możliwości procesora DSP. Poprzez prezentację poszczególnych procedur asemblera, zmian zawartości rejestrów i komórek pamięci, pozwala na szybkie zrozumienie zasady działania funkcji i budowy tego procesora. Symulator pozwala na testowanie napisanego programu bez użycia sprzętu. Ten etap pracy pozwala na sprawdzenie prawidłowego działania programu przy wyeliminowaniu ewentualnych błędów sprzętowych. Obsługa symulatora odbywa się tylko i wyłącznie za pomocą myszki. Rysunek 7. Widok okna symulatora Łatwa obsługa rozwijalnego menu skraca czas wyszukiwania potrzebnych komend i danych. Pozwala obserwować zmiany zawartości rejestrów w poszczególnych taktach DSP. Daje możliwość 14 skonfigurowania edytowanych na ekranie elementów, sprawdzenia danego kroku oraz wpisania określonej wartości do rejestru. Dzięki wizualizacji procesów zachodzących w procesorze, które towarzyszą pracy danego programu, użytkownik może śledzić krok po kroku działania DSP i sprawdzić poprawność napisanej aplikacji. Poniżej przedstawiono sposób zastosowania symulatora. Symulator jest uruchamiany komendą : sim2181.exe W celu uruchomienia w symulatorze konkretnego programu należy wpisać komendę, która ułatwi rozpoczęcie pracy: sim2181 -a adsp2181 -e nazwa_programu Aby sprawdzić działanie programu w symulatorze, program ten musi być wcześniej poddany linkowaniu. Menu Register i Memory umożliwiają pokazanie zawartości rejestrów i pamięci, których zawartość zmienia się w trakcie wykonywania poleceń. Kolejne linie programu wykonywane są po naciśnięciu klawisza „F-10”. W menu Execution opcja step”n”Times umożliwia wykonanie programu w dowolnej ilości „n” kroków. Wyjście z symulatora za pomocą opcji „Exit” powoduje zachowanie ostatniego ustawienia ikon. Natomiast wyjście poprzez wybór opcji Quit powoduje anulowanie ostatnio wykonanych zmian. 4.4. Uruchomienie programu wynikowego w środowisku Windows EZ-KIT Lite Monitor jest programem pracującym w środowisku Windows, który służy do komunikacji z modułem procesora ADSP-2181. Program ten przesyła poprzez łącze RS-232 kod skompilowanego programu, który ma zostać uruchomiony. W celu załadowania programu (skompilowanego do postaci wynikowego zbioru o rozszerzeniu EXE) należy wybrać opcję "Loading" oraz podopcję "Download User program and Go" lub nacisnąć "^L". Przed uruchomieniem transferu danych należy wykonać reser modułu. 4.5. Program Mathcad Program Mathcad jest używany do obliczania współczynników filtrów cyfrowych wykorzystywanych w jednym z przykładowych programów. Generuje on współczynniki filtrów dolno i górno przepustowych lub pasmowozaporowych, dowolnego rzędu, o skończonej lub nieskończonej odpowiedzi impulsowej. W celu utworzenia zbioru z współczynnikami odpowiedniego filtru należy uruchomić program MATHCAD oraz wczytać właściwy plik dokonujący obliczeń. W przypadku filtru: - dolnoprzepustowego o skończonej odpowiedzi impulsowej: zbiór wykonujący obliczenia współczynników filtru: FIL_DFIR.MCD zbiór z współczynnikami filtru: WSP_D.DAT - górnoprzepustowego o skończonej odpowiedzi impulsowej: zbiór wykonujący obliczenia współczynników filtru: FIL_GFIR.MCD zbiór z współczynnikami filtru: WSP_G.DAT - pasmowozaporowego o skończonej odpowiedzi impulsowej: zbiór wykonujący obliczenia współczynników filtru: FIL_PFIR.MCD zbiór z współczynnikami filtru: WSP_P.DAT - dolnoprzepustowego o nieskończonej odpowiedzi impulsowej: zbiór wykonujący obliczenia współczynników filtru: FIL_DFII2.MCD zbiory z współczynnikami filtru: WSP_DIA.DAT WSP_DIB.DAT - górnoprzepustowego o nieskończonej odpowiedzi impulsowej: zbiór wykonujący obliczenia współczynników filtru: FIL_GFII2.MCD zbióry z współczynnikami filtru: WSP_GIA.DAT WSP_GIB.DAT - pasmowozaporowego o nieskończonej odpowiedzi impulsowej: zbiór wykonujący obliczenia współczynników filtru: FIL_PFII2.MCD 15 zbióry z współczynnikami filtru: WSP_ZIA.DAT WSP_ZIB.DAT W przypadku filtrów o skończonej odpowiedzi impulsowej, wybór rzędu filtru następuje przez podanie parametru N, a częstotliwość graniczna jest określana przez współczynnik Fg. Dla filtrów o skończonej odpowiedzi impulsowej właściwe wartości współczynników należy obliczyć iteracyjnie zmieniając częstotliwość dopasowywaną filtru o symbolu Fg w taki sposób, aby wyliczany moduł wzmocnienia dla właściwej częstotliwości granicznej o symbolu Fg1 przyjął wartość docelowego wzmocnienia ok. 0.7071. Na rysunku 8 przedstawiono wygląd początku przykładowego pliku wyliczającego współczynniki filtru, otwartego w programie Mathcad z widocznymi charakterystycznymi parametrami: rzędem filtru oraz częstotliwością graniczną. Na rysunku 9 pokazano dalszy fragment tego samego pliku z widoczną wyliczoną wartością wzmocnienia dla częstotliwości granicznej oraz charakterystyką amplitudową filtru. Rysunek 8. Widok okna programu Mathcad Współczynniki filtrów w celu dostosowania do poziomu i formatu użytecznego dla asemblera procesora przed zapisem do zbioru mnoży się, przez 2^15, co powoduje, że zawierają się one w granicach od -32768 do 32768. 16 wyliczana wartość wzmocnienia dla docelowej częstotliwości Rysunek 9. Widok fragmentu pliku weryfikującego współczynniki filtru w programie Mathcad Ponieważ asembler procesora DSP 2181 jest w stanie odczytać z pliku współczynniki w systemie szesnastkowym, niezbędne jest ich przetworzenie do tej postaci, co wykonuje program o nazwie KFIL_DSP.EXE. Wygląd głównego okna tego programu przedstawiono na rysunku 10. W celu dokonania zamiany sposobu zapisu danych należy wskazać zbiór źródłowy a następnie wybrać rodzaj przeliczenia (MCAD>DSP czyli z systemu dziesiętnego na szesnastkowy lub DSP->MCAD czyli z systemu szesnastkowego na dziesiętny). Rysunek 10. Widok okna programu dokonującego konwersji 5. Programy przykładowe Na użytek laboratoryjny, w asemblerze procesora 2181 napisano kilka przykładowych programów realizujących podstawowe funkcje zabezpieczeniowe. Znajdują się one w katalogu c:\adi_dsp\21xx\ezkitl\2181\dsp\ na komputerze stanowiska laboratoryjnego. 5.1. Program szkoleniowy Poniżej przedstawiono prosty program, umożliwiający szybkie poznanie zasady działania procesora i podstawowych jego funkcji. Nosi on nazwę: demo_2d.dsp Program szkoleniowy uruchamiamy w pierwszej kolejności na symulatorze, który umożliwia poznanie poszczególnych procedur asemblera i zapoznanie się z wewnętrzną budową procesora. Program ten nie wykorzystuje pełnych możliwości układu EZKIT LITE, dlatego nie posiada wielu złożonych 17 komend inicjalizujących kodek oraz porty szeregowe, niezbędnych w pracy z rzeczywistym układem. Prostota i przejrzystość programu powoduje, że doskonale nadaje się on do nauki jako program szkoleniowy Pierwsza linia programu zawiera jego nazwę, a kolejne dwa wiersze stanowią deklarację wykorzystywanych zmiennych. Są to zmienna kołowa zajmująca 10 komórek w pamięci danych oraz jednowymiarowa zmienna ogólnego stosowania. W następnych wierszach zdefiniowane są wektory przerwań, które są umieszczane w pamięci programu o adresach od 0x0000H do 0x002FH. Jest ich 11, tyle ile procesor jest w stanie obsłużyć. W pierwszej komórce, od której rozpoczyna się wykonywanie programu, znajduje się rozkaz skoku do etykiety start znajdującej się za wszystkimi wektorami przerwań. Niewykorzystane w programie przerwania wypełnione są instrukcjami RTI gwarantującymi w przypadku wystąpienia takiego przerwania powrót do programu. Adres przerwania IRQE, który generowany jest przyciskiem J3 na module, zawiera rozkaz umieszczenia stałej 000F w pamięci danych. Po deklaracji przerwań znajdują się instrukcje programu, pokazujące działanie funkcji arytmetycznych oraz instrukcji przesyłania danych. Za pomocą instrukcji TOGGLE FL1 trzy wzajemnie zagnieżdżone pętle zmieniają stan na wyjściu dwustanowym, powodując miganie podłączonej do niego diody LED. Po sprawdzeniu i analizie działania programu w symulatorze można przystąpić do pracy w rzeczywistym układzie. .module/ram/abs=0 demo; .var/dm/circ buffer[10]; .var/dm flag; jump start; nop; nop; nop; rti; rti; rti; rti; rti; rti; rti; rti; rti; rti; rti; rti; rti; rti; rti; rti; rti; rti; rti; rti; ax0 = 0x000f; dm(flag) = ax0; rti; rti; rti; rti; rti; rti; rti; rti; rti; rti; rti; rti; rti; rti; rti; rti; rti; rti; rti; rti; rti; rti; start: imask = 0x0010; ax0 = 0; dm(flag) = ax0; ax0 = 3; ay1 = 5; ar = ax0 + ay1; af = ax0 - ay1; nazwa programu deklaracja zmiennej dziesięcio-wymiarowej deklaracja zmiennej ogólnego zastosowania skok ponad wektorem przerwań no-operation -rozkaz pusty „nic nie rób” wypełnienie nieużywanych lokacji przerwań przerwanie IRQE ustawienie flag na wartość różną od zera ładuj do rejestru przerwań wartość 0010 uaktywniając IRQE umieść w rejestrze ax0 wartość 0 zawartość rejestru ax0 do pamięci danych ładuj 3 do rejestru ax0 ładuj 5 do rejestru ay1 dodaj rejestry, sumę umieść w rejestrze wyniku ar odejmij, wynik umieść w feednack rejestrze zobacz w flagach ALU w symulatorze ena m_mode; ustawienie mnożnika dla arytmetyki całkowitej mx0 = 2; ładuj 2 do rejestru mx0 mx1 = 3; ładuj 3 do rejestru mx1 my0 = 2; ładuj 2 do rejestru my0 mr = mx0 * my0 (uu); pomnożyć liczby jako nieoznaczone liczby mr = mr + mx1 * my0 (uu); wykonywać mnożenie i sumowanie Następna sekcja używa pętli przy kołowym (cyklicznym) buforze danych. Można obserwować zmianę częstotliwości świecenia diody w zależności od zmian wartości licznika pętli. 18 i0 = ^buffer; l0 = %buffer; m0 = 1; m1 = 3; again: cntr = 3; do loop_1 until ce; dm(i0, m0) = ar; cntr = 2; do loop_2 until ce; cntr = 10; do loop_3 until ce; ar = ar + ay1; loop_3: dm(i0, m0) = ar; loop_2: dm(i0, m1) = mr1; loop_1: mr1 = ar; toggle fl1; ax0 = dm(flag); none = pass ax0; if ne rts; jump again; ładuj adres wskaźnika z początku adresu z buforu ładuj długość rejestru z długości bufora ładuj adres modyfikacji rejestru do inkrementacji ładuj drugi modyfikator = 3 ładuj licznik pętli (counter-licznik) ustaw pętlę zliczanie upływa gdy ce zapisywać zawartość rejestru do bufora ładuj licznik pętli, stos licznika(cntr) pozwala zagnieżdżać powtarzaj pętlę loop_2, 2 jednostki czasu ładuj licznik pętli na 10 powtarzaj loop_3, 10 jednostek czasu dodaj zawartości ‘ay1’ do ‘ar’ przesuń zawartości z ‘ar’ do ‘mr1’ przełączaj fl1 weź wartość flag z pamięci generuj ALU arytmetyczną flagę jeżeli nie 0, powrót do monitora skocz z powrotem do start z zagnieżdżonej pętli .endmod; 5.2. Przykładowy program W celu zwiększenia przejrzystości wydruków programu, pominięto pewne powtarzające się fragmenty programu. Poniższy program przykładowy jest podstawą do tworzenia dalszych aplikacji pokazujących funkcje zabezpieczeniowe. Spełnia on zadanie edukacyjne, przez wprowadzenie do tworzenia zaawansowanych modułów. Korzysta on w pełni z możliwości procesora i kodeka. Przy korzystaniu z sygnałów analogowych niezbędne było ustawienie łącza SPORT0 oraz kodeka, co spowodowało zwiększenie liczby instrukcji i przez to mniejszą czytelność programu. W początkowej części programu znajdują się deklaracje wykorzystywanych stałych, są to określenia adresów pamięci zajmowanych przez 32 zmapowane rejestry. Zajmują one obszar w pamięci danych od adresu 0x3FE0H do 0x3FFFH. Żmudne wpisywanie linii deklaracji można zastąpić globalnym poleceniem include <..\system.k>; które uwzględnia stałe znajdujące się w pliku o nazwie system.k. W części dotyczącej deklaracji zmiennych, zdefiniowane są trzy bufory kołowe oraz jedna zmienna jednowymiarowa. Dwa zmienne bufory kołowe rx_buf i tx_buf służą do komunikacji i wymiany danych między procesorem a kodekiem poprzez łącze SPORT0. Bufor kołowy o wymiarach tablicy 13-to elementowej wykorzystany jest do sterowania kodeka. Zawarte w nim dane decydują o częstotliwości próbkowania sygnału analogowego, wzmocnieniach kanałów i o rodzajach wykorzystywanych wejść analogowych. Kolejny fragment określa początkowe wartości zmiennych, przypisywane podczas uruchamiania programu. Główną częścią sterującą pracą programu jest część określająca kody wektorów przerwań. Dla sygnału nadrzędnego reset przyporządkowane są cztery pierwsze miejsca komórek pamięci programu 0x0000H, 0x0001H, 0x0002H, 0x0003H, które są czytane w pierwszej kolejności działania programu. W tym programie jest to komenda skoku ponad wektorem przerwań „jump START;” odwołująca się do procedury znajdującej się w dalszej części programu. Kolejne miejsca komórek pamięci programu 0x0004H-0x000FH zarezerwowane są dla nie używanych przerwań IRQ2, IRQL1, IRQL0, wypełnionych instrukcją „rti;”. Kolejne dwa przerwania SPORT0_tx i SPORT0_rx odpowiedzialne są za wysyłanie i odbieranie danych między kodekiem a procesorem przez port SPORT0. Wywołują one skoki do procedur 19 next_cmd i input_samples wykonujące transfer danych. Przerwanie IRQE z zarezerwowanym miejscem w pamięci od 0x0018H do 0x001BH wywoływane jest przyciskiem w układzie EZ-KIT Lite i powoduje skok do procedury Irqe. Kolejne nieużywane przerwania wypełnione są instrukcją „rti;”. Po zdefiniowaniu wektora przerwań rozpoczyna się część programu, w której definiowane są procedury wykorzystane w przerwaniach. Procedura start, do której odwołuje się nadrzędny sygnał reset wykonywana jest jako pierwsza. Można ją podzielić na trzy części: - inicjacja działania portu SPORT0 - konfiguracja pamięci zewnętrznej - ustawienie działania kodeka. Procedura ta zakończona jest instrukcją „IDLE;” wprowadzającą procesor w stan oczekiwania do czasu pojawienia się przerwania. Z punktu widzenia użytkowego najważniejszą w programie jest procedura Input_samples wywołana przerwaniem pojawiającym się po zapisaniu i odczytaniu kompletu danych z kodeka. W procedurze tej próbki z danymi sygnału wejściowego znajdują się w komórkach pamięci (rx_buf+2) oraz (rx_buf+1). Dane, które mają trafić na wyjścia analogowe kodeka powinny zostać zapisane do komórek pamięci (tx_buf+1) oraz (tx_buf+2). W tej procedurze są również umieszczane algorytmy realizujące funkcje zabezpieczeniowe, niepokazane w przykładowym programie. Procedura ta kończy się instrukcją rti powrotu z przerwania. Procedura next_cmd przesyła dane do wyjścia analogowego kodeka. Opisany i przedstawiony poniżej program stanowi podstawę do tworzenia pozostałych aplikacji realizujących funkcje zabezpieczeniowe. Po skompilowaniu wykonuje przepisanie wartości zmierzonych 2 kanałów analogowych na wyjścia analogowe i nie realizuje żadnej funkcji zabezpieczeniowej. Analogowe wejścia i wyjścia można obserwować ma oscyloskopie zmieniając potencjometrami na obudowie układu sterującego amplitudę przebiegu i kąt fazowy. {******************************************************************************} .module/RAM/ABS=0 loopback; {deklaracja } {****************************************************************************** * * Assemble time constants * ******************************************************************************} {Deklaracja stałych} .const IDMA= 0x3fe0; {deklaracja stałej IDMA której obszar 16-to bitowy zarezerwowany jest w komórce pamięci DM o adresie 0x3fe0} .const BDMA_BIAD= 0x3fe1; .const BDMA_BEAD= 0x3fe2; .const BDMA_BDMA_Ctrl= 0x3fe3; .const BDMA_BWCOUNT= 0x3fe4; .const PFDATA= 0x3fe5; .const PFTYPE= 0x3fe6; .const SPORT1_Autobuf= 0x3fef; .const SPORT1_RFSDIV= 0x3ff0; .const SPORT1_SCLKDIV= 0x3ff1; .const SPORT1_Control_Reg= 0x3ff2; .const SPORT0_Autobuf= 0x3ff3; .const SPORT0_RFSDIV= 0x3ff4; .const SPORT0_SCLKDIV= 0x3ff5; .const SPORT0_Control_Reg= 0x3ff6; .const SPORT0_TX_Channels0= 0x3ff7; .const SPORT0_TX_Channels1= 0x3ff8; .const SPORT0_RX_Channels0= 0x3ff9; 20 .const .const .const .const .const .const SPORT0_RX_Channels1= 0x3ffa; TSCALE= 0x3ffb; TCOUNT= 0x3ffc; TPERIOD= 0x3ffd; DM_Wait_Reg= 0x3ffe; System_Control_Reg= 0x3fff; {deklaracje zmiennych i buforów kołowych } .var/dm/ram/circ rx_buf[3]; /* Status + L data + R data */ {deklaracja zmiennej, wektora, tzw. buforu kołowego o rozmiarze 3} .var/dm/ram/circ tx_buf[3]; /* Cmd + L data + R data */ .var/dm/ram/circ init_cmds[13]; .var/dm stat_flag; {deklaracja zmiennej “zwykłej”} {inicjalizacja zdeklarowanych zmiennych i buforów kołowych } .init tx_buf: 0xc000, 0x0000, 0x0000; /* Initially set MCE */ {ustalenie początkowej wartości zmiennej tx_buf na wartości 0c0000H 0c0000H 0c0000H } .init init_cmds: { ustalenie początkowej wartości zmiennej ustawiającej codec patrz } 0xc002, {0000.0010 Left input control reg b7-6: 0=left line 1 ----------------------------------------- 0 1=left aux 1 2=left line 2 3=left line 1 post-mixed loopback b5-4: res b3-0: left input gain x 1.5 dB 2*1.5=3dB } 0xc102, {0000.0010 Right input control reg b7-6: 0=right line 1 ----------------------------------------- 0 1=right aux 1 2=right line 2 3=right line 1 post-mixed loopback b5-4: res b3-0: right input gain x 1.5dB 2*1.5=3dB } 0xc288, {1000.1000 left aux 1 control reg b7 : 1=left aux 1 mute b6-5: res b4-0: gain/atten x 1.5, 08= 0dB, 00= 12dB } 0xc388, {.1000.1000 right aux 1 control reg b7 : 1=right aux 1 mute b6-5: res b4-0: gain/atten x 1.5, 08= 0dB, 00= 12dB } 0xc488, {1000.1000 left aux 2 control reg b7 : 1=left aux 2 mute b6-5: res b4-0: gain/atten x 1.5, 08= 0dB, 00= 12dB } 0xc588, {1000.1000 right aux 2 control reg b7 : 1=right aux 2 mute 21 b6-5: res b4-0: gain/atten x 1.5, 08= 0dB, 00= 12dB } 0xc680, {1000.0000 left DAC control reg b7 : 1=left DAC mute b6 : res b5-0: attenuation x 1.5dB } 0xc780, {1000.0000 right DAC control reg b7 : 1=right DAC mute b6 : res b5-0: attenuation x 1.5dB } 0xc85c, {0101.1100 data format register b7 : res b5-6: 0=8-bit unsigned linear PCM 1=8-bit u-law companded 2=16-bit signed linear PCM-------------------1 3=8-bit A-law companded b4 : 0=mono, 1=stereo-----------------------------1 b0-3: 0= 8. 1= 5.5125 2= 16. 3= 11.025 4= 27.42857 5= 18.9 6= 32. 7= 22.05 8= . 9= 37.8 a= . b= 44.1 c= 48.------------------------------------kHz d= 33.075 e= 9.6 f= 6.615 (b0) : 0=XTAL1 24.576MHz; 1=XTAL2 16.9344MHz } 0xc909, {0000.1001 interface configuration reg b7-4: res b3 : 1=autocalibrate-------------------------1 b2-1: res b0 : 1=playback enabled--------------------1 } 0xca00, {0000.0000 pin control reg b7 : logic state of pin XCTL1 b6 : logic state of pin XCTL0 b5 : master - 1=tri-state CLKOUT slave - x=tri-state CLKOUT b4-0: res } 0xcc40, {0100.0000 miscellaneous information reg b7 : 1=16 slots per frame, 0=32 slots per frame 22 b6 : 1=2-wire system, 0=1-wire system--------------2-wire system b5-0: res } 0xcd00; { 0000.0000 digital mix control reg b7-2: attenuation x 1.5dB b1 : res b0 : 1=digital mix enabled-----------------------------0-disabled } {****************************************************************************** * * Interrupt vector table tablica wektora przerwań * ******************************************************************************} jump start; rti; rti; rti; {00: reset } rti; rti; rti; rti; {04: IRQ2 } rti; rti; rti; rti; {08: IRQL1 } rti; rti; rti; rti; {0c: IRQL0 } ar = dm(stat_flag); {10: SPORT0 tx } ar = pass ar; if eq rti; jump next_cmd; jump input_samples; {14: SPORT1 rx } rti; rti; rti; jump irqe; rti; rti; rti; {18: IRQE } rti; rti; rti; rti; {1c: BDMA } rti; rti; rti; rti; {20: SPORT1 tx or IRQ1 } rti; rti; rti; rti; {24: SPORT1 rx or IRQ0 } rti; rti; rti; rti; {28: timer } rti; rti; rti; rti; {2c: power down } {****************************************************************************** * * ADSP 2181 intialization Inicjalizacja ADSP-2181 * ******************************************************************************} start: i0 = ^rx_buf; {adres zmiennej rx_buf do rejestru i0} l0 = %rx_buf; {długość, wartość zmiennej rx_buf do rejestru l0} i1 = ^tx_buf; l1 = %tx_buf; i3 = ^init_cmds; l3 = %init_cmds; m1 = 1; {================== S E R I A L P O R T #0 S T U F F ==================} {===============konfiguracja portu szeregowego #0========================} ax0 = b#0000001010000111; dm (SPORT0_Autobuf) = ax0; { |||!|-/!/|-/|/|+- receive autobuffering 0=off, 1=on |||!| ! | | +-- transmit autobuffering 0=off, 1=on |||!| ! | +---- | receive m? |||!| ! | | m1 |||!| ! +------- ! receive i? |||!| ! ! i0 |||!| ! ! |||!| +========= | transmit m? |||!| | m1 |||!+------------ ! transmit i? |||! ! i1 |||! ! |||+============= | BIASRND MAC biased rounding control bit ||+-------------- 0 23 |+--------------- | CLKODIS CLKOUT disable control bit +---------------- 0 } ax0 = 0; dm (SPORT0_RFSDIV) = ax0; { RFSDIV = SCLK Hz/RFS Hz - 1 } ax0 = 0; dm (SPORT0_SCLKDIV) = ax0; { SCLK = CLKOUT / (2 (SCLKDIV + 1) } ax0 = b#1000011000001111; dm (SPORT0_Control_Reg) = ax0; { multichannel ||+--/|!||+/+---/ | number of bit per word - 1 ||| |!||| | = 15 ||| |!||| | ||| |!||| | ||| |!||+====== ! 0=right just, 0-fill; 1=right just, signed ||| |!|| ! 2=compand u-law; 3=compand A-law ||| |!|+------- receive framing logic 0=pos, 1=neg ||| |!+-------- transmit data valid logic 0=pos, 1=neg ||| |+========= RFS 0=ext, 1=int ||| +---------- multichannel length 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 } { non-multichannel |||!|||!|||!+---/ | number of bit per word - 1 |||!|||!|||! | = 15 |||!|||!|||! | |||!|||!|||! | |||!|||!|||+===== ! 0=right just, 0-fill; 1=right just, signed |||!|||!||+------ ! 2=compand u-law; 3=compand A-law |||!|||!|+------- receive framing logic 0=pos, 1=neg |||!|||!+-------- transmit framing logic 0=pos, 1=neg |||!|||+========= RFS 0=ext, 1=int |||!||+---------- TFS 0=ext, 1=int |||!|+----------- TFS width 0=FS before data, 1=FS in sync |||!+------------ TFS 0=no, 1=required |||+============= RFS width 0=FS before data, 1=FS in sync ||+-------------- RFS 0=no, 1=required |+--------------- ISCLK 0=ext, 1=int +---------------- multichannel 0=disable, 1=enable } ax0 = b#0000000000000111; dm (SPORT0_TX_Channels0) = ax0; { ^15 00^ transmit word enables: channel # == bit # } ax0 = b#0000000000000111; dm (SPORT0_TX_Channels1) = ax0; { ^31 16^ transmit word enables: channel # == bit # } ax0 = b#0000000000000111; dm (SPORT0_RX_Channels0) = ax0; { ^15 00^ receive word enables: channel # == bit # } ax0 = b#0000000000000111; dm (SPORT0_RX_Channels1) = ax0; { ^31 16^ receive word enables: channel # == bit # } {============== S Y S T E M A N D M E M O R Y S T U F F ==============} ax0 = b#0000111111111111; dm (DM_Wait_Reg) = ax0; { |+-/+-/+-/+-/+-/- ! IOWAIT0 || | ! | ! || | ! | ! || | ! +------ | IOWAIT1 || | ! | || | ! | 24 || | +--------- ! IOWAIT2 || | ! || | ! || +------------ | IOWAIT3 || | || | |+=============== ! DWAIT | ! | ! +---------------- 0 } ax0 = b#0001000000000000; dm (System_Control_Reg) = ax0; { +-/!||+-----/+-/- | program memory wait states | !||| |0 | !||| | | !||+---------- 0 | !|| 0 | !|| 0 | !|| 0 | !|| 0 | !|| 0 | !|| 0 | !|+----------- SPORT1 1=serial port, 0=FI, FO, IRQ0, IRQ1,.. | !+------------ SPORT1 1=enabled, 0=disabled | +============= SPORT0 1=enabled, 0=disabled +---------------- 0 0 0 } ifc = b#00000011111111; { clear pending interrupt } nop; icntl = b#00000; { ||||+- | IRQ0: 0=level, 1=edge |||+-- | 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 } {****************************************************************************** * * ADSP 1847 Codec intialization Inicjalizacja Codeca ADSP-1847 * ******************************************************************************} { clear flag } wyzerowanie flagi ax0 = 1; dm(stat_flag) = ax0; { enable transmit interrupt } umożliwiać transmitować przerwanie imask = b#0001000000; { |||||||||+ | timer ||||||||+- | SPORT1 rec or IRQ0 |||||||+-- | SPORT1 trx or IRQ1 25 ||||||+--- | BDMA |||||+---- | IRQE ||||+----- | SPORT0 rec |||+------ | SPORT0 trx ||+------- | IRQL0 |+-------- | IRQL1 +--------- | IRQ2 } ax0 = dm (i1, m1); { start interrupt } rozpoczęcie(początek) przerwania tx0 = ax0; check_init: ax0 = dm (stat_flag); { wait for entire init } oczekiwanie na kompletny ...... af = pass ax0; { buffer to be sent to } bufor do transmisji do if ne jump check_init; { the codec } kodera ay0 = 2; check_aci1: ax0 = dm (rx_buf); { once initialized, wait for codec } wcześniejsze inicjalizowanie, oczekiwanie na koder ar = ax0 and ay0; { to come out of autocalibration } do wysłania automatycznej kalibracji if eq jump check_aci1; { wait for bit set } oczekiwania na ustawienie bitu check_aci2: ax0 = dm (rx_buf); { wait for bit clear } oczekiwanie na wyzerowany bit ar = ax0 and ay0; if ne jump check_aci2; idle; ay0 = 0xbf3f; { unmute left DAC } .......................... ax0 = dm (init_cmds + 6); ar = ax0 AND ay0; dm (tx_buf) = ar; idle; ax0 = dm (init_cmds + 7); { unmute right DAC } ar = ax0 AND ay0; dm (tx_buf) = ar; idle; ifc = b#00000011111111; { clear any pending interrupt } wyzerowanie jakiś przerwań oczekujących na obsługę nop; imask = b#0000110000; { enable rx0 interrupt } włączenie przerwania rx0 { |||||||||+ | timer ||||||||+- | SPORT1 rec or IRQ0 |||||||+-- | SPORT1 trx or IRQ1 ||||||+--- | BDMA |||||+---- | IRQE ||||+----- | SPORT0 rec |||+------ | SPORT0 trx ||+------- | IRQL0 |+-------- | IRQL1 +--------- | IRQ2 } {------------------------------------------------------------------------------ wait for interrupt and loop forever czekaj na przerwanie i pętle ------------------------------------------------------------------------------} talkthru: idle; jump talkthru; {****************************************************************************** * * Interrupt service routines przerwanie programu użytkowego * 26 ******************************************************************************} {------------------------------------------------------------------------------ receive interrupt used for loopback odbiór przerwania użytego do pętli zwrotnej ------------------------------------------------------------------------------} input_samples: ena sec_reg; { use shadow register bank } użycie cienia banku rejestru mr0 = dm (rx_buf + 1); { loopback inputs to outputs } wejście pętli zwrotnej do wyjścia mr1 = dm (rx_buf + 2); sr = ashift mr0 by -1 (hi); af = pass sr1; sr = ashift mr1 by -1 (hi); {sygnały wejściowe znajdują się odpowiednio w rejestrach “af” “sr1”} {IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII} ar = sr1; dm (tx_buf + 1) = ar; ar = af; dm (tx_buf + 2) = ar; ar = ar + 0x10; rti; {------------------------------------------------------------------------------ transmit interrupt used for Codec initialization przerwanie transmisji użytej do inicjalizacji codec ------------------------------------------------------------------------------} next_cmd: ena sec_reg; ax0 = dm (i3, m1); { fetch next control word and } przynieś następne słowo kontrolne i dm (tx_buf) = ax0; { place in transmit slot 0 } umieść w gnieźdie transmisji ax0 = i3; ay0 = ^init_cmds; ar = ax0 - ay0; if gt rti; { rti if more control words still waiting } rti jeżeli więcej słów nieruchomo czekających ax0 = 0xaf00; { else set done flag and } w przeciwnym wypadku ustaw flage i dm (tx_buf) = ax0; { remove MCE if done initialization } przenieś MCE jeżeli wykonana inicjalizacja ax0 = 0; dm (stat_flag) = ax0; { reset status flag } zeruj status flag rti; irqe: toggle fl1; rti; .endmod; 5.3. Programy demonstracyjne 5.3.1. Program demonstrujący działanie wyjść dwustanowych Działanie wyjść dwustanowych przedstawiono za pomocą prostego programu \TEST_WY\T2\d02.exe Jego uruchomienie powoduje sekwencyjne zapalanie się diod w układzie sterującym. Istnieje programowa możliwość zmiany częstotliwości i sekwencji zapalania się diod. Realizacja tej opcji następuje przez zmianę licznika pętli. .module/ram/abs=0 demo;/* define the program module */ .var/dm/circ buffer[10]; /* declare a circular buffer of length 10 */ 27 .var/dm flag; .var/dm flag1; jump start; nop; nop; nop; rti; rti; rti; rti; rti; rti; rti; rti; rti; rti; rti; rti; rti; rti; rti; rti; rti; rti; rti; rti; ax0 = 0x000f; dm(flag) = ax0; rti; rti; rti; rti; rti; rti; rti; rti; rti; rti; rti; rti; rti; rti; rti; rti; rti; rti; rti; rti; rti; rti; /* general purpose flag */ /* general purpose flag */ /* jump over interrupt vectors */ /* code vectors here upon IRQ2 interrupt */ /* code vectors here upon IRQL1 interrupt */ /* code vectors here upon IRQL0 interrupt */ /* code vectors here upon SPORT0 TX interrupt */ /* code vectors here upon SPORT0 RX interrupt */ /* code vectors here upon IRQE interrupt */ /* set flag to non-zero value */ /* code vectors here upon BDMA interrupt */ /* code vectors here upon SPORT1 TX (IRQ1) interrupt */ /* code vectors here upon SPORT1 RX (IRQ0) interrupt */ /* code vectors here upon TIMER interrupt */ /* code vectors here upon POWER DOWN interrupt */ start: ax0 = dm(0x3fe6); ay0 = 0x000f; ar = ax0 OR ay0; dm(0x3fe6) = ar; ax1 = 0x0000; imask = 0x0010; ax0 = 0; dm(flag) = ax0; dm(flag1) = ax0; ax0 = 3; ay1 = 5; ar = ax0 + ay1; af = ax0 - ay1; /* enable IRQE, interrupt button on EZ-LAB */ /* clear flag */ /* clear flag1 */ /* load a 3 into an ALU X input register */ /* load a 5 into an ALU Y input register */ /* add inputs, store sum in result register */ /* subtract, store result in feednack reg */ /* look at ALU flags in simlator*/ ena m_mode; /* set up multiplier for integer arithmetic */ mx0 = 2; /* load a 2 into a MAC X input register */ mx1 = 3; /* load a 3 into another MAC X input register */ my0 = 2; /* load a 2 into a MAC Y input register */ mr = mx0 * my0 (uu); /* multiply numbers as unsigned numbers */ mr = mr + mx1 * my0 (uu); /* perform multiply and accumulate */ i0 = ^buffer; l0 = %buffer; m0 = 1; m1 = 3; /* load address pointer with start address of buffer */ /* load length register with length og buffer */ /* load address modify register with 1 to increment */ /* load second modifier with a 3 */ again: cntr = 300; /* load loop counter */ do loop_1 until ce; /* set up loop to end when count expires */ dm(i0, m0) = ar; /* store contents of register ar in buffer */ cntr = 20; /* load loop counter, cntr stack allows nesting */ do loop_2 until ce; /* repeat to loop_2, 2 times */ cntr = 1000; /* load loop counter with 10, change to 0x1000 to run on EZ-LAB */ do loop_3 until ce; /* repeat from her to loop_3, 10 times */ ar = ar + ay1; /* add contents of ay1 to ar */ loop_3: dm(i0, m0) = ar; loop_2: dm(i0, m1) = mr1; loop_1: mr1 = ar; /* move contents of ar into mr1 */ toggle fl1; /* toggle flag */ ax0 = dm(flag1); 28 ay0 = 0x0001; ar = ax0 + ay0; ay0 = 0x0003; ar = ar AND ay0; dm(flag1) = ar; se = ar; ax0 = dm(0x3fe5); ay1 = 0xfff0; ar = ax0 AND ay1; si = 0x0001; sr = ASHIFT si (LO); ay0 = sr0; ar = ar OR ay0; dm(0x3fe5)=ar; ax0 = dm(flag); none = pass ax0; if ne rts; jump again; .endmod; /* wartość przesunięcia */ /* maska bitowa */ /* get flag value from memory */ /* generate ALU arithmetic flag */ /* if not 0, return to monitor */ /* go back to start of nesed loops */ 5.3.2. Program demonstrujący działanie wejść dwustanowych Działanie wejść dwustanowych pokazuje program \TEST_WE\T2\d02.exe Załączenie przełącznika na obudowie układu sterującego, powoduje zapalenie się odpowiadającej mu diody. Stosując odpowiednią logikę można stworzyć różne kombinacje testowania wejść i wyjść dwustanowych. .module/ram/abs=0 demo; /* define the program module */ .var/dm/circ buffer[10]; /* declare a circular buffer of length 10 */ .var/dm flag; /* general purpose flag */ .var/dm flag1; /* general purpose flag */ jump start; /* jump over interrupt vectors */ nop; nop; nop; rti; rti; rti; rti; /* code vectors here upon IRQ2 interrupt */ rti; rti; rti; rti; /* code vectors here upon IRQL1 interrupt */ rti; rti; rti; rti; /* code vectors here upon IRQL0 interrupt */ rti; rti; rti; rti; /* code vectors here upon SPORT0 TX interrupt */ rti; rti; rti; rti; /* code vectors here upon SPORT0 RX interrupt */ /* code vectors here upon IRQE interrupt */ ax0 = 0x000f; /* set flag to non-zero value */ dm(flag) = ax0; rti; rti; rti; rti; rti; rti; /* code vectors here upon BDMA interrupt */ rti; rti; rti; rti; /* code vectors here upon SPORT1 TX (IRQ1) interrupt */ rti; rti; rti; rti; /* code vectors here upon SPORT1 RX (IRQ0) interrupt */ rti; rti; rti; rti; /* code vectors here upon TIMER interrupt */ rti; rti; rti; rti; /* code vectors here upon POWER DOWN interrupt */ start: ax0 = dm(0x3fe6); ay0 = 0x000f; ar = ax0 OR ay0; dm(0x3fe6) = ar; ax1 = 0x0000; imask = 0x0010; /* enable IRQE, interrupt button on EZ-LAB */ ax0 = 0; dm(flag) = ax0; /* clear flag */ dm(flag1) = ax0; /* clear flag1 */ ax0 = 3; /* load a 3 into an ALU X input register */ 29 ay1 = 5; ar = ax0 + ay1; af = ax0 - ay1; /* load a 5 into an ALU Y input register */ /* add inputs, store sum in result register */ /* subtract, store result in feednack reg */ /* look at ALU flags in simlator*/ ena m_mode; /* set up multiplier for integer arithmetic */ mx0 = 2; /* load a 2 into a MAC X input register */ mx1 = 3; /* load a 3 into another MAC X input register */ my0 = 2; /* load a 2 into a MAC Y input register */ mr = mx0 * my0 (uu); /* multiply numbers as unsigned numbers */ mr = mr + mx1 * my0 (uu); /* perform multiply and accumulate */ i0 = ^buffer; /* load address pointer with start address of buffer */ l0 = %buffer; /* load length register with length og buffer */ m0 = 1; /* load address modify register with 1 to increment */ m1 = 3; /* load second modifier with a 3 */ again: cntr = 300; /* load loop counter */ do loop_1 until ce; /* set up loop to end when count expires */ dm(i0, m0) = ar; /* store contents of register ar in buffer */ cntr = 20; /* load loop counter, cntr stack allows nesting */ do loop_2 until ce; /* repeat to loop_2, 2 times */ cntr = 1000; /* load loop counter with 10, change to 0x1000 to run on EZ-LAB */ do loop_3 until ce; /* repeat from her to loop_3, 10 times */ ar = ar + ay1; /* add contents of ay1 to ar */ loop_3: dm(i0, m0) = ar; loop_2: dm(i0, m1) = mr1; loop_1: mr1 = ar; /* move contents of ar into mr1 */ ax0 = dm(0x3fe5); ay1 = 0xfff0; ar = ax0 AND ay1; ax0 = ar; /* aktualna wartość 0x3fe5 ze zgaszonymi wyjściami */ ay1 = 0x00f0; ar = ax0 AND ay1; /* aktualny stan wejść */ af = TSTBIT 5 OF AR; if NE JUMP bit5set; JUMP bitclr; bit5set: TOGGLE fl1; bitclr: se = -4; /* wartość przesunięcia */ sr = ASHIFT ar (LO); ay0 = sr0; /* bity wejść przesunięte o 4 w lewo */ ar = ax0 OR ay0; dm(0x3fe5)=ar; ax0 = dm(flag); /* get flag value from memory */ none = pass ax0; /* generate ALU arithmetic flag */ if ne rts; /* if not 0, return to monitor */ jump again; /* go back to start of nesed loops */ .endmod; 5.3.3. Program realizujący algorytm zabezpieczenia nadmiarowego Właściwe funkcje zabezpieczeniowe, uzyskuje się wstawiając w przedstawionym programie przykładowym na początku deklaracje zmiennych, a w procedurze Input_samples część realizującą daną funkcję. Funkcję nadmiarową realizuje program o nazwie: \NAD_PR\nad_pr1.dsp Oblicza on liczbę odebranych próbek, wyliczając na podstawie wartości chwilowych wartość maksymalną. W przypadku, gdy liczba próbek jest większa niż 513, co wskazuje na to, że dokonano porównania próbek i określenia wartości maksymalnej, z czasu większego niż połowa okresu, program dokonuje porównania wartości maksymalnej z zadeklarowaną wartością I_nast. W przypadku gdy wartość nastawiona jest większa od wartości maksymalnej, zostaje zgaszona flaga FL1, w odwrotnym 30 przypadku flaga FL1 zostaje zapalona. Po porównaniu następuje zerowanie liczby próbek oraz określonej wartości maksymalnej. Na rysunku 11 pokazano algorytm działania procedury, a poniżej dwa fragmenty programu zawierające deklaracje wykorzystywanych zmiennych oraz samą procedurę. Rysunek 11. Zaimplementowany algorytm funkcji nadnapięciowej { Deklaracja zmiennych: } .var/dm I_max; {zmienna programowa} 31 .var/dm .var/dm .var/dm .init I_max: .init I_nast: .init licz:: .init I_odp: I_nast; {zmienna zawierająca wartość nastawy} licz; {zmienna programowa -licznik} I_odp; {zmienna zawierająca wartość odpadu} 0; 0x3000; 0; 0x2f00; {Fragment z procedurą realizującą algorytm zabezpieczeniowy } AX0 = dm(I_max); { czytaj wartość } ay0 = mr0; { bieżąca wartość } ar = AX0 - ay0; {porównaj } if GT jump LICZNIK; { jeżeli bufor jest większy od stałej to ... } dm(I_max) = ay0; { przypisanie } LICZNIK: ay0 = dm(licz); { czytaj stan licznika } ar = ay0 + 1; { zwiększ o 1 } ay0 = ar; { zapisz licznik } dm(licz) = ay0; { f = 48kHz na pól okresu przypada 480 próbek = 1e0h } ax1 = ay0; ar = ax1 - 513; { spr.2 licznika który zależy od częstotliwości } if LE jump koniec; ar = dm(I_nast); { czytaj wartość nastawiona } ay0 = dm(I_max); { czytaj wartość maksymalna } ar = ar - ay0; { warunek nadprądowy } if GT jump zgas; ar = ar - ay0; if LE jump zapal; zapal: SET FL1; jump skok; zgas: ar = dm(I_odp); ay0 = dm(I_max); ar = ar - ay0; { warunek odpadu } if GE RESET FL1; skok: ar = 0; dm(licz) = ar; { zerowanie licznika } dm(I_max)= ar; { zerowanie I_max } KONIEC: 5.3.4. Program realizujący algorytm zabezpieczenia niedomiarowego Zabezpieczenie niedomiarowe jest wykonane podobnie jak nadmiarowe. Procedura oblicza liczbę odebranych próbek, wyliczając na podstawie wartości chwilowych wartość maksymalną. W przypadku, gdy liczba próbek jest większa niż 513, co wskazuje na to, że dokonano porównania próbek i określenia wartości maksymalnej, z czasu większego niż połowa okresu, program dokonuje porównania wartości maksymalnej z zadeklarowaną wartością I_nast. W przypadku gdy wartość nastawiona jest mniejsza od wartości maksymalnej, zostaje zgaszona flaga FL1, w odwrotnym przypadku flaga FL1 zostaje zapalona. Po porównaniu następuje zerowanie liczby próbek oraz określonej wartości maksymalnej. Na rysunku 12 pokazano algorytm działania procedury, a poniżej dwa fragmenty programu zawierające deklaracje wykorzystywanych zmiennych oraz samą procedurę. \POD_NAP\pod_nap.dsp. { Deklaracja zmiennych: } .var/dm U_max; {zmienna programowa} .var/dm U_nast; {zmienna zawierająca wartość nastawy} .var/dm licz; {zmienna programowa -licznik} 32 .var/dm .init U_max: .init U_nast: .init licz: .init U_odp: U_odp; 0; 0x3000; 0; 0x3100; {zmienna zawierająca wartość odpadu} {wartość chwilowa maksymalna } {wartość pobudzenia } {wartość początkowa licznika } {wartość odwzbudzenia } {Fragment z procedurą realizującą algorytm zabezpieczeniowy } { zakłada się że próbka znajduje się w mr0 } AX0 = dm(U_max); { czytaj wartość } ay0 = mr0; { bieżąca wartość } ar = AX0 - ay0; {porównaj } if GT jump LICZNIK; { jeżeli bufor jest większy od stałej to ... } dm(U_max) = ay0; { przypisanie } LICZNIK: ay0 = dm(licz); { czytaj stan licznika } ar = ay0 + 1; { zwiększ o 1 } ay0 = ar; { zapisz licznik } dm(licz) = ay0; { f = 48kHz na pół okresu przypada 480 próbek = 1e0h } ax1 = ay0; ar = ax1 - 513; { spr.2 licznika który zależy od częstotliwości } if LE jump koniec; ar = dm(U_odp); { czytaj wartość nastawiona } ay0 = dm(U_max); { czytaj wartość maksymalna } ar = ar - ay0; { warunek podnapieciowy } if LT jump zgas; ar =dm(U_nast) ar = ar - ay0; { warunek podnapieciowy } if GE jump zapal; zapal: SET FL1; jump skok; zgaś: RESET FL1; skok: ar = 0; dm(licz) = ar; { zerowanie licznika } dm(U_max)= ar; { zerowanie U_max } KONIEC: 33 Rysunek 12. Zaimplementowany algorytm funkcji podnapięciowej 34 5.4. Programy realizujące algorytmy filtracyjne Program realizujący algorytm filtracji cyfrowej uzyskuje się wstawiając w przedstawionym programie przykładowym na początku deklaracje zmiennych i nazwę odpowiedniego zbioru zawierającego współczynniki filtru zapisane w formie liczb szesnastkowych oraz w procedurze Input_samples właściwy program realizujący filtrację. Cały program dokonujący filtracji SOI nosi nazwę: \SOI_FIL.DSP a dokonujący filtracji NOI: \NOI_FIL.DSP Przykładowe zbiory zawierające współczynniki filtru noszą rozszerzenia WSP. W części definiującej stałe zdeklarowana jest wieloelementowa stała o nazwie taps, której wartość ustawiana jest zależnie od rzędu stosowanego filtru. Komendy: var coeffsTbl [2] oraz init coeffsTbl: ^fir1_coefs, ^fir1_coefs; deklarują zmienną tablicę dwuelementową ze składnikami fir1_coefs, w których znajdują się współczynniki filtru z przykładowego zbioru o nazwie wsp_d.wsp init fir1_coefs: <wsp_d.wsp>; W buforze kołowym „data” przechowywana jest tablica zpróbkowanych sygnałów wejściowych, której wielkość określa rząd filtru. Ze względu na dużą liczbę współczynników filtru częstotliwość próbkowania wynosi 8kHz. Obliczanie próbek wyjściowych przebiega według wzoru: Ytaps = X1•w1+ X2•w2+ X3•w3+ ....+ Xtaps•wtaps . gdzie: X1, X2, X3 ... Xtaps oznaczają kolejne próbki wejściowe umieszczone w pamięci danych w1, w2, w3 ...wtaps oznaczają kolejne współczynniki filtru typu FIR Linia: fir: cntr=taps-1; ustawia licznik pętli na wartość równą liczbie współczynników, Wiersz mr=0, mx0=dm(i0,m0), my0=pm(i4,m4); definiuje argumenty operacji, a polecenia: do fir1loop until ce; fir1loop: mr=mr+mx0*my0(ss), mx0=dm(i0,m0), my0=pm(i4,m4); obliczają wartości próbki wyjściowej. Próbka wyjściowa jest przepisywana do bufora wyjściowego portu SPORT0, skąd zostaje przesłana do kodeka, trafiając na oba jego kanały cyfrowoanalogowe. Poniżej przedstawiono dwa fragmenty programu zawierające deklaracje wykorzystywanych zmiennych oraz samą procedurę. { Deklaracja zmiennych: } .const taps=16; {rząd filtru - liczba współczynników filtru } .var coeffsTbl [2]; .init coeffsTbl: ^fir1_coefs, ^fir1_coefs; 35 { .var/circ .var/pm/circ .init ^^^^^^^^^^ dummy for talk through } data[taps]; fir1_coefs[taps]; { deklaracja tablicy w pam. progr. z współczynnikami filtru} fir1_coefs: <wsp_d.wsp>; { nazwa pliku z współczynnikami filtru } {Część realizująca algorytm filtracji} sr1 = dm (rx_buf + 1); { get new sample from SPORT0 (from codec) } process_sample: dm(i0,m0)=sr1; { store sample in data buffer (delay line) } fir: cntr=taps-1; {rzad filtru - liczba wspolczynnikow - mnozen} mr=0; {probka wyjsciowa - po filtracji} mx0=dm(i0,m0); {piwrwsza probka wejściowa z pamięci danych - rejestr i0 wskazuje na } {tablicę o nazwie data zawierającą kolejne próbki wejściowe} my0=pm(i4,m4); {współczynniki filtru z pamięci programu - rejestr i4 wskazuje na tablicę o} {nazwie fir1_coefs zawierającą współczynniki filtru zapisane w zbiorze } {wsp_d.wsp} do fir1loop until ce; fir1loop: mr=mr+mx0*my0(ss), mx0=dm(i0,m0), my0=pm(i4,m4); mr=mr+mx0*my0(rnd); if mv sat mr; sr = ashift mr1 by 1 (lo); {pomnożenie wartości próbki wyjściowej przez 2} mr1 = sr0; output: dm (tx_buf + 1) = mr1; { wpisanie próbki wyjściowej do bufora wyjściowego SPORT0} dm (tx_buf + 2) = mr1; { wpisanie próbki wyjściowej do bufora wyjściowego SPORT0} rti; 6. Przebieg ćwiczenia Celem ćwiczenia jest pokazanie działania i budowy kilku prostych programów realizujących podstawowe algorytmy zabezpieczeniowe. Ćwiczenie należy rozpocząć od zapoznania się z działaniem symulatora programowego sim2181.exe na przykładzie programu demonstracyjnego o nazwie demo_2d.dsp. W programie należy zwrócić uwagę na sposób wykonania przez procesor działań arytmetycznych oraz instrukcji pętli. Następnie należy uruchomić na module EZ KIT program demonstrujący działanie wyjścia dwustanowego \TEST_WY\T2\d02.exe. W tym celu należy wykorzystać program ładujący o nazwie EZKITAPP.EXE. Po stwierdzeniu poprawnego działania programu, należy dokonać modyfikacji programu źródłowego tak, aby uzyskać dwukrotne i czterokrotne wydłużenie czasu zapalania i gaśnięcia diody podłączonej do flagi Fl1. Po każdej z modyfikacji należy skompilować zmodyfikowany plik źródłowy i po uzyskaniu programu wynikowego o rozszerzeniu EXE, za pomocą programu EZKITAPP.EXE uruchomić go na module EZ-KIT. W podobny sposób należy zapoznać się z programami demonstrującymi: - działanie wejścia dwustanowego (program \TEST_WE\T2\d02.exe) - algorytm zabezpieczenia nadprądowego \NAD_PR\nad_pr1.dsp - algorytm zabezpieczenia podnapięciowego \POD_NAP\pod_nap.dsp W przypadku dwu ostatnich programów należy sprawdzić wpływ zmiany parametrów o nazwach U_nast, U_odp na progi działania i odpadania sprawdzanych funkcji przekaźnikowych. Następnie należy uruchomić program Mathcad i po wczytaniu odpowiedniego zbioru obliczającego utworzyć zbiór z współczynnikami filtru typu FIR o parametrach podanych przez prowadzącego. Po zamianie współczynników filtru na wartości szesnastkowe za pomocą programu KFIL_DSP.EXE oraz skompilowaniu programu źródłowego o nazwie \TEST_FIL\FIL100.DSP należy za pomocą programu EZKITAPP.EXE uruchomić uzyskany plik wynikowy na module EZ-KIT. Po uruchomieniu programu, należy określić charakterystykę amplitudową i fazową uzyskanego filtru, zmieniając częstotliwość sygnału podawanego z generatora na wejście analogowe modułu i obserwując sygnały wejściowe i wyjściowe na oscyloskopie. 36