wykład
Transkrypt
wykład
Podstawy techniki mikroprocesorowej dla elektroenergetyków Multipleksacja Zwielokrotnienie czasowe Demultipleksacja Dane kanału 1 0 0 1 1 0 1 0 0 Dane kanałów szczelina szczelina szczelina czasowa czasowa czasowa 1 2 3 Dane kanału 2 1 1 0 1 1 0 0 0 001101001101100010010010 1 1 0 1 1 0 0 0 Dane kanału 2 Dane kanału 3 1 0 0 1 0 0 1 0 kierunek transmisji 1 0 0 1 0 0 1 0 Dane kanału 3 0 0 1 1 0 1 0 0 Dane kanału 1 U10 U11 U2 U1 RD 5 WR 36 A0 9 A1 8 RESET 35 CS 8255 6 D0 D1 D2 D3 D4 D5 D6 D7 PA0 PA1 PA2 PA3 PA4 PA5 PA6 PA7 RD WR A0 A1 RESET CS PB0 PB1 PB2 PB3 PB4 PB5 PB6 PB7 PC0 PC1 PC2 PC3 PC4 PC5 PC6 PC7 8255 R.Kowalik 4 3 2 1 40 39 38 37 1 2 3 4 5 6 7 8 1K 16 15 14 13 12 11 10 9 18 19 20 21 22 23 24 25 14 15 16 17 13 12 11 10 U12 U13 U14 S1 S2 S3 S4 S5 S6 S7 S8 16 15 14 13 12 11 10 9 34 33 32 31 30 29 28 27 U15 U16 U17 VCC LED LED LED LED LED LED LED VCC U2 10K 1 2 3 4 5 6 7 8 D0 D1 D2 D3 D4 D5 D6 D7 LED Informacje Wykładowca: dr inż. Ryszard Kowalik Tel. wew. PW: 5608 Email: [email protected] Konsultacje: GM-213 Literatura: 1. TIETZE U., SCHENK CH.: Układy półprzewodnikowe, Warszawa, WNT, 1996 2. Pełka R.: Mikrokontrolery architektura, programowanie, zastosowania, Warszawa, WKŁ, 1999 3. Daca W.: Mikrokontrolery od układów 8 do 32-bitowych, ZNI MIKOM. Warszawa 2000 4. GAŁKA P., GAŁKA P.: Podstawy programowania mikrokontrolerów 8051, Warszawa, ZNI “MIKOM”, 1995 5. Z.Czaja: Materiały do wykładu Mikrokontrolery i mikrosystemy 2003, Politechnika Gdańska, 2003 www.pg.gda.pl/~zbczaja/mk.html 2 Spis tematów INFORMACJE ................................................................................................................................................................. 2 SPIS TEMATÓW ............................................................................................................................................................. 3 WSTĘP .............................................................................................................................................................................. 6 1. ALGEBRA BOOLE'A ................................................................................................................................................. 8 1.1. PODSTAWOWE FUNKCJE LOGICZNE ........................................................................................................................ 9 1.2. INNE FUNKCJE LOGICZNE ..................................................................................................................................... 10 2. OPIS FUNKCJI LOGICZNYCH – UKŁADY KOMBINACYJNE....................................................................... 11 3. REALIZACJA UKŁADOWA FUNKCJI LOGICZNYCH .................................................................................... 13 3.1. REALIZACJA UKŁADOWA FUNKCJI LOGICZNYCH - PRZEGLĄD WŁAŚCIWOŚCI ........................................................ 17 4. UKŁADY LOGICZNE WYKORZYSTYWANE W TECHNICE MIKROPROCESOROWEJ ........................ 20 4.1. BRAMKI O WYJŚCIACH Z OTWARTYM KOLEKTOREM ............................................................................................ 20 4.2. BRAMKI O WYJŚCIACH TRÓJSTANOWYCH ............................................................................................................ 20 4.3. PROSTE UKŁADY KOMBINACYJNE ........................................................................................................................ 21 4.3.1. Proste układy kombinacyjne – dekoder 1 z n ........................................................................................... 22 4.3.2. Proste układy kombinacyjne – demultiplekser ......................................................................................... 22 4.3.3. Proste układy kombinacyjne – multiplekser ............................................................................................. 23 4.3.4. Proste układy kombinacyjne – dekoder priorytetowy............................................................................... 24 4.4. PROSTE UKŁADY SEKWENCYJNE.......................................................................................................................... 25 4.4.1. Przerzutniki FLIP-FLOP.......................................................................................................................... 25 4.4.1. Proste układy sekwencyjne – przerzutnik FLIP-FLOP............................................................................. 25 4.4.2. Proste układy sekwencyjne – przerzutnik RS-kluczowany........................................................................ 26 4.4.3. Proste układy sekwencyjne – przerzutnik D-kluczowany ......................................................................... 26 4.4.4. Proste układy sekwencyjne – przerzutnik wyzwalany impulsem............................................................... 27 4.4.5. Przerzutniki wyzwalane zboczem (single-edge-triggered flip flops)......................................................... 28 4.4.6. Liczniki dwójkowe .................................................................................................................................... 30 4.4.7. Asynchroniczne Liczniki dwójkowe .......................................................................................................... 31 4.4.8. Synchroniczne Liczniki dwójkowe ............................................................................................................ 32 4.4.9. Rejestry przesuwające .............................................................................................................................. 34 4.4.10. Rejestr przesuwający z wpisem równoległym......................................................................................... 35 4.5. PAMIĘCI............................................................................................................................................................... 36 4.5.1. Pamięci statyczne RAM ............................................................................................................................ 37 4.5.1. Pamięci statyczne RAM – parametry dynamiczne.................................................................................... 39 4.5.2. Pamięci dynamiczne RAM........................................................................................................................ 41 4.5.3. Pamięci dynamiczne RAM – układ sterowania (kontroler) ...................................................................... 43 4.5.4. Pamięci dwubramowe RAM ..................................................................................................................... 44 4.5.5. Pamięci RAM jako rejestr przesuwający.................................................................................................. 46 4.5.6. Pamięci FIFO........................................................................................................................................... 47 4.5.7. Pamięci stałe (ROM) ................................................................................................................................ 49 4.5.8. Pamięci ROM programowane maską....................................................................................................... 49 4.5.9. Pamięci programowane w sposób trwały (PROM) .................................................................................. 49 4.5.9. Pamięci stałe - PROM.............................................................................................................................. 50 4.5.10. Pamięci stałe kasowane promieniami UV - EPROM ............................................................................. 51 4.5.11. Pamięci stałe kasowane elektrycznie - EEPROM .................................................................................. 54 4.5.12. Pamięć błyskowa - FLASH..................................................................................................................... 55 4.5.13. Układy logiki programowalnej – PLD ................................................................................................... 61 4.6. UKŁADY WSPÓŁPRACY Z WEJŚCIAMI ORAZ WYJŚCIAMI BINARNYMI ..................................................................... 71 4.7. UKŁAD WSPÓŁPRACY Z WYŚWIETLACZEM 7 SEGMENTOWYM LED ..................................................................... 76 4.8. UKŁAD WSPÓŁPRACY Z KLAWIATURĄ.................................................................................................................. 79 4.9. UKŁAD WSPÓŁPRACY Z WYŚWIETLACZEM LCD .................................................................................................. 81 4.10. PRZETWORNIKI ANALOGOWO-CYFROWE ............................................................................................................ 86 4.10.1. Konwersja analogowo-cyfrowa – przetwornik SAR ............................................................................... 88 4.10.2. Konwersja analogowo-cyfrowa – przetwornik SS.................................................................................. 89 3 4.10.3. Konwersja analogowo-cyfrowa – przetwornik SigmaDelta (Σ∆)........................................................... 90 4.10.4. Błędy konwersji w przetwornikach A/C.................................................................................................. 94 4.11. UKŁADY PRÓBKUJĄCO-PAMIĘTAJĄCE (S/H) ...................................................................................................... 96 4.12. UKŁADY KLUCZY I MULTIPLEKSERÓW ANALOGOWYCH ..................................................................................... 99 4.13. UKŁADY PRZETWORNIKÓW C/A ...................................................................................................................... 104 5. BUDOWA I ZASADA DZIAŁANIA MIKROKONTROLERÓW O ARCH. STANDARDOWEJ .................. 107 5.1. STANDARDOWA ARCHITEKTURA MIKROKONTROLERA ....................................................................................... 109 5.2. UKŁAD WYKONAWCZY ...................................................................................................................................... 111 5.2.1. Jednostka ALU ....................................................................................................................................... 111 5.2.2. Rejestry................................................................................................................................................... 113 5.3. Tryby adresowania argumentów ............................................................................................................... 115 5.3.1. Formaty instrukcji .................................................................................................................................. 116 5.3.2. Podstawowe tryby adresowania ............................................................................................................. 118 5.3.3. Przykładowa lista instrukcji - mikrokontroler 80C51 ............................................................................ 124 5.4. UKŁAD STEROWANIA ......................................................................................................................................... 125 5.4.1. Układ oscylatora .................................................................................................................................... 125 5.4.2. Układ resetu ........................................................................................................................................... 129 5.4.3. Cykl wykonania rozkazu ......................................................................................................................... 131 5.4.4. Przerwania i sytuacje wyjątkowe ........................................................................................................... 135 5.4.5. Tryby redukcji mocy mikrokontrolera .................................................................................................... 140 5.5. ARCHITEKTURA SYSTEMU PAMIĘCI MIKROPROCESORA...................................................................................... 141 5.5.2. Segmentacja pamięci.............................................................................................................................. 146 5.5.3. Stos ......................................................................................................................................................... 147 6. DODATKOWE BLOKI FUNKCJONALNE MIKROKONTROLERÓW......................................................... 149 6.1. PORTY WEJŚCIA WYJŚCIA................................................................................................................................... 149 6.2. UKŁADY LICZNIKOWE/CZASOWE ....................................................................................................................... 153 6.2. UKŁADY LICZNIKOWE/CZASOWE – CD. (80C51) ................................................................................................ 159 6.3. UKŁADY NADZORUJĄCE – UKŁAD WATCHDOG .................................................................................................. 159 6.4. SPECJALIZOWANE UKŁADY KOMUNIKACJI SZEREGOWEJ .................................................................................... 161 6.4.1. Interfejs UART........................................................................................................................................ 162 6.4.2. Interfejs SPI............................................................................................................................................ 172 6.4.3. Interfejs I2C............................................................................................................................................ 177 6.4.4. Interfejs CAN.......................................................................................................................................... 180 6.4.5. Interfejs USB .......................................................................................................................................... 180 7. WSPÓŁPRACA Z UKŁADAMI ZEWNĘTRZNYMI .......................................................................................... 182 7.1. STEROWANIE SZYNAMI ...................................................................................................................................... 184 7.2. WSTRZYMANIE DOSTĘPU DO SZYNY .................................................................................................................. 186 7.3. PRZYŁĄCZENIE ZEWNĘTRZNYCH PAMIĘCI RAM/ROM/EPROM....................................................................... 188 7.4. WSPÓŁPRACA Z PAMIĘCIAMI EEPROM I BŁYSKOWYMI .................................................................................... 192 7.5. PRZYŁĄCZANIE PAMIĘCI EEPROM Z DOSTĘPEM SZEREGOWYM ....................................................................... 193 7.6. WSPÓŁPRACA Z PAMIĘCIAMI BŁYSKOWYMI ....................................................................................................... 196 7.7. BEZPOŚREDNI DOSTĘP DO PAMIĘCI .................................................................................................................... 202 8. MIKROKONTROLERY DSP................................................................................................................................. 203 8.1. STAŁOPRZECINKOWE DSP NA PRZYKŁADZIE ADSP 2181................................................................................. 203 8.2. ZMIENNOPRZECINKOWE DSP NA PRZYKŁADZIE ADSP-21061 SHARC ............................................................ 209 9. PROGRAMOWANIE MIKROKONTROLERÓW .............................................................................................. 212 9.1. PROGRAMOWANIE W JĘZYKU ASEMBLERA......................................................................................................... 212 9.1.1. Asemblery i makroasemblery ................................................................................................................. 214 9.1.2. Przykłady Makroasemblerów ................................................................................................................. 218 9.1.3. Przykłady programów asemblera........................................................................................................... 220 9.2. PROGRAMOWANIE W JĘZYKU C ......................................................................................................................... 223 9.2.1. Kompilatory języka C ............................................................................................................................. 223 9.2.2. Przykłady programów w języku C – przykład 1...................................................................................... 224 9.2.3. Przykłady programów w języku C – przykład 2...................................................................................... 225 9.2.4. Przykłady programów w języku C – przykład 3...................................................................................... 227 4 9.2.5. Przykłady programów w języku C – przykład 4...................................................................................... 229 9.3. NARZĘDZIA WSPOMAGAJĄCE URUCHAMIANIE SYSTEMÓW MIKROPROCE-SOROWYCH ........................................ 231 9.3.1. Monitory i programy śledzące................................................................................................................ 231 9.3.2. Symulatory.............................................................................................................................................. 233 9.3.3. Zintegrowane programy wspomagające uruchamianie ......................................................................... 236 10. LITERATURA........................................................................................................................................................ 238 11. DOKUMENTACJA STEROWNIKA DSM-51 WYK. W LABORATORIUM ................................................ 239 5 Wstęp Poniżej przedstawiono schemat blokowy oraz ideowy układu mikroprocesorowego, który będzie przez Państwa wykorzystywany w zajęciach laboratoryjnych w semestrze letnim. 6 Jak widać, aby przeanalizować działanie tego układu nie wystarczy poznanie jedynie zasady działania mikroprocesora, trzeba także znać działanie innych układów, które z nim współpracują. Z tego względu, naukę techniki mikroprocesorowej należy rozpocząć od przypomnienia podstawowych wiadomości z zakresu algebry, elektroniki i techniki cyfrowej. Te dziedziny wiedzy legły u postaw działania układów mikroprocesorowych. 1. 1.1. 1.2. 2. 3. 4. ALGEBRA BOOLE’A Podstawowe funkcje logiczne Inne funkcje logiczne OPIS FUNKCJI LOGICZNYCH – UKŁADY KOMBINACYJNE REALIZACJA UKŁADOWA FUNKCJI LOGICZNYCH UKŁADY LOGICZNE WYKORZYSTYWANE W TECHNICE MIKROPROCESOROWEJ 7 1. Algebra BOOLE'A Budowa układów cyfrowych opiera się na idei wielokrotnego stosowania niewielkiej liczby podstawowych rodzajów układów logicznych. Sposób połączenia tych układów można uzyskać za pomocą algebry Boole’a zwanej też algebrą łączeń. W przeciwieństwie do zmiennej w zwykłej algebrze zmienna logiczna może przyjmować dwie wartości dyskretne: - zero logiczne - jedynkę logiczną Rozróżniamy trzy podstawowe działania na zmiennych logicznych: - iloczyn (koniunkcja) y = x1 ∩ x2 = x1 ∗ x2 = x1 x2 - suma (dysjunkcja) y = x1 ∪ x2 = x1 + x2 - negacja y=x Dla tych działań obowiązuje szereg praw: - prawo przemienności: y = x1 ∗ x2 = x2 ∗ x1 y = x1 + x2 = x2 + x1 - prawo łączności: y = x1 ∗ ( x2 ∗ x3 ) = ( x1 ∗ x2 ) ∗ x3 y = x1 + ( x2 + x3 ) = ( x1 + x2 ) + x3 - prawo rozdzielczości: y = x1 ∗ ( x2 + x3 ) = x1 ∗ x2 + x1 ∗ x3 y = x1 + x2 ∗ x3 = ( x1 + x2 ) ∗ ( x1 + x3 ) - prawo pochłaniania: y = x1 ∗ ( x1 + x2 ) = x1 y = x1 + x1 ∗ x2 = x1 - prawo tautologii: y = x∗ x = x y = x+x= x - własności negacji: y = x∗ x = 0 y = x + x =1 - () podwojona negacja: y= x =x - prawo De’Morgana: y = x1 ∗ x2 = x1 + x2 y = x1 + x2 = x1 ∗ x2 - szereg praw dla działań z 0 i 1: y = x ∗1 = x y = x+0= x y = x∗0 = 0 y = x +1 = 1 8 y = 0 =1 y =1= 0 Zauważmy, że w przedstawionych prawdach obowiązuje zasada dualności, mówiąca o tym, że jeżeli w którejś z tożsamości zamienimy znaki “ ∗ ” na ”+” a “0” na “1”, to również otrzymamy tożsamość. 1.1. Podstawowe funkcje logiczne Bardzo często przy opisywaniu funkcji logicznych będziemy korzystać z tzw. “tablicy prawdy”. Tablica 1.1 Tablica prawdy funkcji AND X1 0 0 1 1 y = 1 wtedy i tylko wtedy, gdy x1 = 1 i x2 = 1 X2 0 1 0 1 Y 0 0 0 1 X2 0 1 0 1 Y 1 1 1 0 Tablica 1.2 Tablica prawdy funkcji OR X1 0 0 1 1 y = 1 wtedy, gdy x1 = 1 lub x2 = 1 Przejdźmy do prezentacji fizycznej wspomnianych funkcji. Ze względu na to, że zmienne logiczne przyjmują jedynie dwa stany pracy pod uwagę można brać tylko urządzenia o podobnych właściwościach. Urządzeniami takimi są np. zestyki. W tej reprezentacji funkcji logicznej OR odpowiada obwód przedstawiony na rysunku 1.1 (równoległe połączenie zestyków), natomiast funkcji AND połączenie szeregowe zestyków (rysunek 1.2). x1 x2 Rysunek 1.1. Realizacja funkcji OR na zestykach x1 x2 Rysunek 1.2. Realizacja funkcji AND na zestykach Prawo tautologii przybierze w tej reprezentacji następującą postać: x1 x2 x Rysunek 1.3. Przedstawienie prawa tautologii Innym sposobem reprezentacji zmiennych logicznych mogą być poziomy napięć elektrycznych. Jeżeli wyróżnimy dwa poziomy: 9 - H – wysoki, L – niski i przypiszemy im stany logiczne w następujący sposób H=1 i L=0, to otrzymamy logikę dodatnią. Przy przyporządkowaniu odwrotnym tzn.: - H – wysoki, L – niski, ale wartość stanów H=0 i L=1, otrzymamy logikę ujemną. Przy takiej reprezentacji podstawowe funkcje logiczne można realizować za pomocą odpowiednich układów elektronicznych posiadających jedno lub wiele wejść oraz jedno wyjście (rysunek 1.4). x1 x2 y F(x) xn Rysunek 1.4. Układ elektryczny realizujący funkcję logiczną Ponieważ istnieje wiele rozwiązań układowych wspomnianego układu, dla uproszczenia wprowadzono symbole oznaczające funkcję logiczną realizowana przez układ, a nie mówiące nic o jego budowie wewnętrznej. x1 x2 x1 & y=x1+x2 x2 y=x1+x2 x2 x1 x1 x1 >1 y=x1+x2 x2 y=x1+x2 x2 y=x1+x2 x2 x1 x2 x1 1 x1 y=x y=x x2 y=x1+x2 x1 y=x x2 Rysunek 1.5. Symbole podstawowych funkcji logicznych Zauważmy, że pomimo pewnej realizacji układowej opis wejść i wyjść układu pozostał zgodny z opisem logicznym i nie odzwierciedla poziomów napięć występujących w układach. 1.2. Inne funkcje logiczne Poprzednio pokazano, że dowolną funkcję logiczna można przedstawić za pomocą odpowiedniej kombinacji funkcji OR, AND i NOT. Istnieją jednak funkcje złożone, które w technice występują na tyle często, że nadano im własne nazwy. Funkcjami tymi są: - funkcja równoważności, przyjmuje wartość y = 1 wówczas, gdy obie zmienne wejściowe są sobie równe: y = EQUIV ( x1 , x2 ) = x1 x2 + x1 x2 - funkcja nierównoważności, jest negacją równoważności; y = 1 gdy zmienne wejściowe są różne. y = ANTIV ( x1 , x2 ) = x1 x2 + x1 x2 Z tablicy prawdy wynika jeszcze inna interpretacja funkcji nierównoważności; funkcja ta jest zgodna z funkcja OR dla wszystkich wartości z wyjątkiem przypadku, gdy wszystkie zmienne wejściowe są równe jeden. Dlatego nosi ona nazwę EXCLUSIVE OR (EXOR) lub sumy modulo 2 (MOD 2) y = EXOR( x1 , x2 ) = x1 x2 + x1 x2 Zgodnie z tym funkcję równoważności można nazwać funkcją EXCLUSIVE NOR (EXNOR) y = EXNOR ( x1 , x2 ) = x1 x2 + x1 x2 10 2. Opis funkcji logicznych – układy kombinacyjne Zwykle opis funkcji logicznej podany jest w postaci wspomnianej tablicy prawdy. W celu znalezienia funkcji logicznej spełniającej daną tablicę prawdy należy: - w tablicy prawdy wyszukać wiersze, których wartość zmiennej wyjściowej wynosi “1” - dla każdego z wierszy utworzyć iloczyn tworzących go zmiennych wejściowych w ten sposób, - że jeżeli wartość danej zmiennej wynosi “1”, to piszemy “ xi ”, jeżeli “0” piszemy xi . poszukiwaną funkcję otrzymujemy tworząc sumę wszystkich znalezionych iloczynów. Przykład: Tablica 2.1. Przykład tablicy prawdy Wiersz x1 x2 x3 y 1 0 0 0 0 2 0 0 1 0 3 0 1 0 1 4 0 1 1 0 5 1 0 0 1 6 1 0 1 0 7 1 1 0 1 8 1 1 1 0 W wierszach 3,5,7 jest y = 1 . Najpierw musimy więc utworzyć iloczyn dla tych wierszy: - wiersz 3 I 3 = x1 x2 x3 - wiersz 5 I 5 = x1 x2 x3 - wiersz 7 I 7 = x1 x2 x3 poszukiwana funkcja jest sumą iloczynów: y = I3 + I5 + I7 y = x1 x 2 x3 + x1 x 2 x3 + x1 x 2 x3 Po znalezieniu funkcji przystępujemy do jej uproszczenia stosując podane wcześniej prawa algebry Boole’a. y = x1 x 2 x3 + x1 x 2 x3 + x1 x 2 x3 = x1 x 2 + x1 ( x 2 + x 2 ) x3 = ( x1 x 2 + x1 ) x3 = ( x1 + x 2 )( x1 + x1 ) x3 [ ] y = ( x1 + x 2 ) x3 Jeżeli w tablicy prawdy zmienna wyjściowa częściej przybiera wartość “1” wygodniej jest wstępnie zanegować tablicę, a następnie po znalezieniu funkcji opisującej poddać ją negacji. Innym sposobem znalezienia funkcji opisującej jest zastosowanie tzw. tablicy Karnaugha. Tworzy się ją następująco: - wartości zmiennych wejściowych wpisuje się na brzegach tablicy w taki sposób, aby przy przejściu do kolejnej kratki wartość zmieniała się co najwyżej na jednej pozycji - w kratki wpisuje się wartość zmiennej wyjściowej dla wartości zmiennych wejściowych znajdujących się na brzegach - dla każdej kratki zawierającej wartość “1” tworzymy iloczyn zmiennych wejściowych wg przykładu - sumujemy otrzymane iloczyny otrzymując szukaną funkcję (Jeżeli w kwadracie lub prostokącie o parzystej liczbie kratek są same jedynki, iloczyn całej grupy można otrzymać bezpośrednio, uwzględniając tylko zmienne wejściowe, dla wszystkich kratek grupy mają stałą wartość.) Przykład: 11 Tablica tablicy Karnaugha Karnaugha Tablica 2.2. 1.4. Przykład Przykład tablicy x1 x2 0 0 0 1 1 1 1 0 x3 0 1 0 1 1 1 0 0 0 0 Szukana funkcja to: x1 x3 + x2 x3 = ( x1 + x 2 ) x3 12 3. Realizacja układowa funkcji logicznych W dotychczasowych rozwiązaniach zajmowaliśmy się elementami logicznymi nie troszcząc się o ich budowę wewnętrzną. Ma to swoje uzasadnienie w technice, bowiem współczesne układy scalone mają zaznaczone jedynie zaciski zasilania oraz wejść i wyjść. Do realizacji poszczególnych podstawowych funkcji logicznych istnieje wiele technik układowych, które różnią się między sobą: - poborem mocy - ∆P - poziomami “L” i “H” - czasem propagacji - t - obciążalnością wyjścia (Termin obciążalność wyjścia bramki określa, ile wejść bramek tej samej rodziny można dołączyć do jednego wyjścia bez zmniejszania jej odporności na zakłócenia.) W ciągu kilkudziesięciu lat historii układów logicznych mieliśmy do czynienia z wieloma technikami układowymi, z których duża część nie jest już stosowana. Do technologii, które odeszły w zapomnienie możemy zaliczyć: - układy RTL – (resistor transistor logic) - ∆P = 5mW t = 25ns - układy DTL – (diode transistor logic) - ∆P = 180mW t = 175ns - układy TTL – (transistor transistor logic) - ∆P = 10mW t = 10ns - układy ECL – (emitter coupled logic) - ∆P = 25mW t = 2ns Obecnie używane technologie to: - TTL-LS – (coraz mniej) - ∆P = 2mW t = 10ns - HC, HCT, ACT – (high speed cmos) - ∆P = 0,3µW / kHz t = 10ns Wyjaśnijmy zasadę działania przykładowych bramek z obu grup, zaczynając od TTL i TTL LS. +5V +5V R1 4k +5V R2 1,6k R4 130 T4 T1 D T2 U1 T3 U2 Uwy R3 1k Rysunek 3.1. Standardowa bramka NAND TTL W standardowej bramce TTL przedstawionej na rysunku 3.1, jeżeli wszystkie wejścia są w stanie ”H”, prąd płynie przez rezystancję R1 i złącze baza-kolektor tranzystora wejściowego spolaryzowane jest w kierunku przewodzenia do bazy tranzystora T2, powodując jego przewodzenie. Jeżeli na jedno z wejść doprowadzimy niskie napięcie, odpowiednie złącze bazaemiter zaczyna przewodzić i przejmuje prąd bazy T2. powoduje to zatkanie tranzystora T2 i przejście wyjścia do stanu “H”. Wzmacniacz w układzie TTL składa się z tranzystora sterującego T2 i przeciwsobnego wzmacniacza wyjściowego. Gdy tranzystor T2 przewodzi, przewodzi również T3, a T4 jest zatkany. Na wyjściu jest poziom “L”, a tranzystor T3 może przyjmować duże prądy, pochodzące np. z dołączonych wejść bramek (w stanie “L” prąd wypływa z wejść). Gdy tranzystor 13 T2 jest zatkany , zatkany jest również T3. W tym przypadku T4 przewodzi i daje poziom “H” na wyjściu. Tranzystor T4 pracujący jako wtórnik emiterowy może teraz dostarczać dużego prądu wyjściowego i dzięki temu szybko ładować pojemności obciążenia. Standardowe układy TTL tego rodzaju , jak pokazane na rysunku 3.1, są obecnie spotykane rzadko z powodu dużego czasu propagacji wywołanego nasyceniem tranzystorów. Nasyceniu można zapobiec przez dołączenie diody Schottky’ego równolegle do złącza kolektor-baza (rysunek 3.2). dzięki napięciowemu sprzężeniu zwrotnemu przy przewodzeniu tranzystora uniemożliwia ona spadek napięcia kolektoremiter poniżej wartości ok. 0,3V. C C B B E E Rysunek 3.2.Tranzystor z diodą Schottky’ego przeciwdziałającą nasyceniu i jego symbol graficzny Bramka TTL zbudowana z takich “tranzystorów Schottky'ego" (bramka TTL-S) jest przedstawiona na rys. 3.3. Jest to uproszczony schemat bramki TTL-S małej mocy, tzw. bramki TTL-LS (Iow power Schottky). Z porównania ze standardową bramką TTL z rys. 3.1 widać, że ma ona rezystancje kolektorowe pięć razy większe, dzięki czemu pobór mocy jest pięć razy mniejszy i wynosi tylko 2 mW. Mimo to czas propagacji bramki nie jest większy i wynosi 10 ns. Wejściowy zespół diod jest zbudowany tak, jak w układzie DTL, z oddzielnych diod. Dioda D (rys. 3.1) w stopniu wyjściowym, służąca do przesunięcia potencjału, została tu zastąpiona układem Darlingtona T3. + 5V 20kΩ + 5V 8kΩ + 5V Pstr = 2mW 120Ω t p = 10ns T3 D1 T1 U1 U2 D2 3kΩ T2 U wy Rysunek 3.3. Bramka NAND TTL LS (74LS00) Charakterystykę przejściową inwertera TTL-S małej mocy przedstawiono na rys. 3.4. Nietrudno zauważyć, że poziom przełączania wynosi ok. 1,1 V. Charakterystyczne dla układów TTL tolerancje są tu zachowane z dużym zapasem. Przy najwyższym dopuszczalnym poziomie L na wejściu, równym 0,8 V, na wyjściu musi być poziom H wynoszący co najmniej 2,4 V. Przy najniższym poziomie H na wejściu, równym 2,0 V, poziom L na wyjściu może wynosić najwyżej 0,4 V. 14 4,8 U wy [V ] 3,2 2,4 1,6 0,8 0 0,4 0,8 1,2 2,0 1,6 U we [V ] 2,8 Rysunek 3.4. Charakterystyka przejściowa bramki TTL LS (Zakreskowane granice tolerancji) Bramki CMOS są rodziną układów logicznych odznaczającą się szczególnie niskim poborem mocy. Układ inwertera pokazany jest na rysunku 3.5. USS G D T2 typu P Uwe S S G typu N T1 D Uwy Rysunek 3.5. Inwerter CMOS Zwraca uwagę fakt, że układ ten składa się wyłącznie z tranzystorów polowych MOS z kanałem wzbogaconym. Źródło tranzystora z kanałem typu n jest połączone z masą, a tranzystora typu p – z napięciem zasilania USS. Oba tranzystory pracują więc w układzie ze wspólnym źródłem i wzmacniają napięcie wejściowe, odwracając jego fazę. Każdy z tranzystorów stanowi równocześnie rezystancję obciążenia drugiego tranzystora. Napięcie progowe obu tranzystorów wynosi około 1,5V. Dlatego też przy napięciu zasilania równym 5V przynajmniej jeden z tranzystorów przewodzi. Jeżeli przyjmiemy UWE = 0, przewodzi tranzystor T2 z kanałem typu p, a tranzystor T1 z kanałem typu n jest zatkany. Napięcie wyjściowe jest równe USS. Dla UWE = USS tranzystor T2 jest zatkany, a T1 przewodzi. Napięcie wyjściowe jest równe zeru. Nietrudno zauważyć, że w stanie ustalonym przez układ nie płynie żaden prąd. Niewielki prąd płynie tylko podczas przełączania. Poziomy logiczne zależą od wybranego napięcia zasilania. Dopuszczalny zakres napięcia zasilania układów CMOS jest bardzo duży. Dla układów z bramką krzemową wynosi od 3 do 6V, a dla układów z bramką metalową od 3 nawet do 15V jak pokazano na rysunku 3.6. 15 5 Uss Uwy [V ] 4 3 2 I ss 1 0 1 2 4 Uwe [V ] 5 3 Rysunek 3.6. Charakterystyki przejściowe bramki CMOS przy napięciu 5V Tablica 3.1. USS = 5V Układ standardowy Układ szybki Typ 74C04 74HC04 Moc strat 0,3µW/kHz 0,5µW/kHz Czas propagacji 90ns 10ns Prąd pobierany przez bramkę CMOS ma trzy składowe: 1. Gdy napięcie wejściowe jest stałe i równe zeru lub Uss, płynie bardzo mały prąd upływu bramek rzędu kilku mikroamperów. 2. Gdy sygnał wejściowy zmienia stan, przez oba tranzystory przepływa prąd przewodzenia. 3. Największy wpływ ma jednak przeładowywanie pojemności tranzystora CT. Przy ładowaniu jest magazynowana energia — CTUgS; równocześnie taka sama energia jest przekształcana w tranzystorze na ciepło. Przy rozładowaniu energia zmagazynowana w kondensatorze jest również przetwarzana, na ciepło. W cyklu L-H-L przetworzona zostaje energia W=- CTC/js. Wynika stąd moc strat Pdiss = W/ 1 = W-f= CTUlsf. Ze względu na fakt, że straty wywołane przez prąd przewodzenia są również proporcjonalne do częstotliwości, można je uwzględnić, definiując pojemność mocy strat. Jest ona nieco większa od pojemności CT samego tranzystora. Potencjał rozwartego wejścia układu CMOS jest nieokreślony. Dlatego też wejścia układów CMOS muszą być połączone z masą lub napięciem Uss. Jest to zalecane także w przypadku nieużywanych bramek, gdyż w przeciwnym razie na ich wejściach może ustalić się taki potencjał wejściowy, przy którym przez oba tranzystory popłynie prąd przewodzenia, co pociągnie za sobą wzrost strat. Elektrody bramek tranzystorów polowych z izolowaną bramką są bardzo wrażliwe na ładunki statyczne. W celu uniknięcia uszkodzeń wejścia układów scalonych MOS są zabezpieczone diodami w sposób pokazany na rys. 3.7. Mimo to należy zachować ostrożność. Diody zabezpieczające powodują również dalsze ograniczenie, które należy uwzględnić przy stosowaniu bramek CMOS. U SS U SS D4 R1 D2 D1 D3 U SS T2 T1 U wy Rysunek 3.7. Zabezpieczenie bramek CMOS od wpływu ładunków statycznych 16 Wskutek izolacji złączowej obu tranzystorów polowych T1 i T2, między zaciskami napięcia zasilania powstaje pasożytniczy tyrystor, jak to pokazano na rys. 3.8. Rysunek 3.8. Pasożytniczy tyrystor w bramce CMOS W normalnych warunkach tyrystor ten nie wpływa na pracę układu, ponieważ tranzystory T3 i T4 są zatkane, a ich prądy zerowe płyną przez rezystancję R2 lub R3. Jeżeli jednak jedna z działających jako dodatkowe emitery diod zabezpieczających zostanie spolaryzowana w kierunku przewodzenia, może to spowodować włączenie tyrystora T3, T4. Oba tranzystory przechodzą wtedy w stan przewodzenia i powodują zwarcie napięcia zasilania. Występujące przy tym prądy o dużej wartości powodują zniszczenie układu scalonego. Dla uniknięcia tego zjawiska, zwanego zatrzaskiwaniem, napięcie wejściowe nie powinno być niższe od potencjału masy, ani wyższe od napięcia zasilania. Jeżeli nie da się tego wykluczyć, należy przynajmniej ograniczyć prąd płynący przez diody zabezpieczające do wartości wynoszącej w zależności od technologii od 1 do 100mA. Wystarcza do tego najczęściej zwykła rezystancja szeregowa. Załączanie pasożytniczego tyrystora również nastąpić po podaniu na wyjście napięcia przekraczającego zakres napięć zasilania. 3.1. Realizacja układowa funkcji logicznych - przegląd właściwości W tablicy 3.2 przedstawiono przegląd najczęściej używanych rodzin układów cyfrowych. Podane dane techniczne odnoszą się do pojedynczej bramki. Nietrudno zauważyć, że każda technika realizacyjna istnieje w różnych wykonaniach, różniących się od siebie poborem mocy i czasem propagacji bramek. Wskaźnikiem jakości rodziny układów logicznych jest iloczyn czasu propagacji i strat mocy bramki (wskaźnik energetyczny). Mówi on, czy bramka oprócz małych strat mocy ma również mały czas propagacji. Można więc zauważyć, że nowsze rodziny, jak 74AS, 74ALS, 74F, 10H100 i 100.100 mają bardzo mały wskaźnik energetyczny. Jest to spowodowane zastosowaniem izolacji dielektrycznej i związaną z tym mniejszą wartością pojemności obciążających elementy przy przełączaniu, niż ma to miejsce w przypadku starszych rodzin z izolacją złączową.. Dużym postępem technologicznym są również układy CMOS z bramką krzemową. Przy takich samych właściwościach, są one dziesięć razy szybsze od typów z bramką metalową. Większość rodzin układów cyfrowych oferowanych przez różnych producentów jest oznaczana symbolami różniącymi się tylko częścią literową umieszczoną na początku symbolu. Moc pobierana przez elementy z różnych rodzin układów cyfrowych jest bardzo różna. Z wykresu na rys. 3.9 widać, że układy CMOS są bardzo korzystne przy małych częstotliwościach. Powyżej l MHz różnice mocy strat między układami TTL-S małej mocy i układami CMOS są niewielkie. Godnym podkreślenia jest fakt, że w tym zakresie częstotliwości rośnie również pobór mocy przez układy TTL. Przyczyną tego jest prąd płynący przez przeciwsobny stopień wyjściowy podczas każdego procesu przełączania, powodujący znaczne zwiększenie poboru mocy przy większych częstotliwościach. 17 Tablica 3.2. Przegląd najbardziej rozpowszechnionych rodzin układów TTL, ECL i CMOS Wady tej nie mają układy ECL. Dlatego też przy częstotliwościach powyżej 30 MHz układy ECL odznaczają się samymi zaletami z wyjątkiem ich wysokiej ceny. Rysunek 3.9. Zależność mocy strat od częstotliwości pracy układu 18 Warunkiem wstępnym prawidłowej pracy cyfrowych układów scalonych jest poprawne doprowadzenie napięć zasilających. Wszystkie rodziny układów cyfrowych wytwarzają przy przełączaniu impulsy prądowe w przewodach doprowadzających prąd zasilania. Ponieważ wszystkie sygnały mają za punkt odniesienia potencjał masy, jest wymagane wykonywanie we wszystkich układach scalonych połączeń masy o małej rezystancji i indukcyjności. Na płytce drukowanej warunek ten można spełnić najlepiej przez wykonanie masy w postaci siatki. Przy częstotliwościach powyżej 50 MHz należy raczej wykonać masę w postaci metalizacji całej jednej strony płytki. Aby impulsy prądowe powstające przy przełączaniu nie zakłócały zasilania, musi być ono doprowadzone do układów scalonych w sposób niskorezystancyjny i bezindukcyjny. Jeśli masa jest dobra, zakłócenia impulsowe mogą być odfiltrowane kondensatorami blokującymi. Stosuje się do tego kondensatory ceramiczne o pojemności 10... 100 nF. Nie nadają się do tego celu kondensatory elektrolityczne, ze względu na złe właściwości przy wielkich częstotliwościach. Przeciętnie jeden kondensator powinien przypadać na 2... 5 układów scalonych. 19 4. Układy logiczne wykorzystywane w technice mikroprocesorowej 4.1. Bramki o wyjściach z otwartym kolektorem Niekiedy występuje problem logicznego połączenia wyjść dużej liczby bramek. Przy np. dwudziestu wyjściach byłaby potrzebna do tego bramka o dwudziestu wejściach, do których musiałoby prowadzić dwadzieścia oddzielnych przewodów. Kłopotu tego można uniknąć, stosując bramkę z otwartym kolektorem. Jej stopień wyjściowy stanowi tranzystor npn którego emiter jest połączony z masą. Takie wyjścia można w odróżnieniu od stosowanych zazwyczaj przeciwsobnych stopni wyjściowych – bez obaw łączyć równolegle i zaopatrzyć we wspólny rezystor kolektorowy (rysunek 4.1).Potencjał wyjścia przyjmuje stan „H” tylko wówczas, gdy wszystkie wyjścia są w stanie „H”. W logice dodatniej otrzymamy więc funkcję AND. Jednakże wiadomo, że wyjście przechodzi w stan „L” wówczas, gdy jedno lub więcej wyjść ma stan „L”. W logice ujemnej otrzymamy więc funkcję OR. Ponieważ funkcja logiczna została zrealizowana przez zewnętrzne połączenia galwaniczne, mówimy wówczas o iloczynie galwanicznym lub sumie galwanicznej. Ponieważ wyjścia bramek mają małą rezystancję tylko w stanie „L”, można je nazwać również wyjściami z aktywnym stanem niskim. Symbol bramki z otwartym kolektorem przedstawia rysunek 4.2. za pomocą wyjść z otwartym kolektorem możemy też zrealizować funkcję OR, stosując iloczyn galwaniczny dla zmiennych zanegowanych. Zgodnie z prawem de Morgana mamy: y1 + y2 + ... + yn = y1 * y2 * ... * yn + Rc B1 B2 Bn Uwy Rysunek 4.1. Łączenie wyjść bramek z otwartym kolektorem x1 y x2 Rysunek 4.2. Symbol bramki z otwartym kolektorem Wadą układów z otwartym kolektorem jest wolniejsze narastanie napięcia wyjściowego niż w przypadku elementów z wyjściem przeciwsobnym, ponieważ przełączane pojemności mogą się naładować tylko przez rezystancję Rc. 4.2. Bramki o wyjściach trójstanowych Istnieje jeszcze jeden ważny przykład zastosowania, w którym równoległe połączenie wyjść bramek prowadzi do uproszczenia układu: jest to przypadek, gdy jedna z wielu bramek ma decydować o stanie linii sygnałowej w tzw. Magistrali. Zadanie to można rozwiązać przy użyciu bramek z otwartym kolektorem ustawiając w wysoko-impedancyjny stan „H” wszystkie wyjścia z wyjątkiem jednego. Zasadniczej wady tego rozwiązania, małej szybkości narastania napięcia 20 wyjściowego, można w tym specyficznym zastosowaniu uniknąć, stosując zamiast bramek z otwartym kolektorem tzw. bramki z wyjściem trójstanowym. Jest to typowe wyjście przeciwsobne z tym, że za pomocą dodatkowego sygnału sterującego można je przełączyć w stan tzw. wysokiej impedancji. Stan ten nosi również nazwę stanu Z. Zasadę realizacji takiego układu przedstawiono na rysunku 4.3, na rysunku widać też jego symbol graficzny. + 5V EN & T2 y & X EN X EN 1 T1 y Rysunek 4.3. Inwerter z wyjściem trójstanowym i jego symbol graficzny Jeśli sygnał zezwolenia EN=1, układ działa jak zwykły inwerter: dla x=1 mamy z1=0 i z2=1, tzn. T1 jest zatkany, a T2przewodzi. Jeżeli jednak zmienna sterująca EN=0, to z1=z2=0 i oba tranzystory wyjściowe są zatkane. Jest to stan wysokiej impedancji Z. 4.3. Proste układy kombinacyjne Przez pojęcie układu kombinacyjnego rozumie się układ cyfrowy nie zawierający pamięci. Zmienne wyjściowe są określone jednoznacznie przez zmienne wejściowe. Stanowi to kryterium odróżniające układy kombinacyjne od układów sekwencyjnych, w których zmienne wyjściowe zależą dodatkowo od stanu układu, czyli od jego przeszłości. W układach kombinacyjnych zmienne wyjściowe można przyporządkować zmiennym wejściowym za pomocą tabel prawdy lub funkcji logicznych. Do realizacji technicznej układów kombinacyjnych można stosować pamięci stałe ROM (read only memory), w których zapisuje się tabele prawdy. Zmienne wejściowe są wówczas adresami. Druga możliwość polega na użyciu bramek lub ukladów logiki programowalnej PLD (programmable logic devices), za pomocą których realizuje się funkcje logiczne. W dalszym ciągu zajmiemy się kilkoma prostymi układami. Układy kombinacyjne są często stosowane do przeliczeń i przekodowywania liczb. Aby te liczby móc przedstawić za pomocą zmiennych logicznych, należy je przekształcić w ciąg informacji dwuwartościowych (binarnych). Jedna taka pozycja binarna nosi nazwę bitu. Specjalnym przypadkiem binarnego przedstawienia liczb jest kod dwójkowy, w którym poszczególne pozycje są uszeregowane według rosnących potęg liczby 2. Cyfra 1 jest wtedy identyfikowana z logiczną jedynką, a cyfra 0 - z zerem logicznym. Zmienną logiczną przypisaną poszczególnym pozycjom będziemy oznaczać małymi literami, a całą liczbę - wielką literą. Npozycyjna liczba ma więc w kodzie dwójkowym postać XN = xN-12N-1 + xN-2 2N-2 + ... + x121 + x020 Należy oczywiście zawsze rozróżniać, czy chcemy przeprowadzić działanie arytmetyczne na cyfrach, czy też zrealizować funkcję zmiennych logicznych. Różnicę tę wyjaśnimy jeszcze raz na przykładzie. Załóżmy, że chcemy dokonać obliczeń odpowiadających wyrażeniu 1 + 1. Jeżeli znak „+" potraktujemy jako rozkaz dodawania w systemie dziesiętnym, otrzymamy zależność: 1+1=2 21 Natomiast dodawanie w systemie dwójkowym daje: 1 + 1 = 10B (czytaj: jeden zero). Jeżeli znak „+" potraktujemy jako sumę zmiennych logicznych, otrzymamy: 1+1=1 4.3.1. Proste układy kombinacyjne – dekoder 1 z n Dekoder 1 z n jest układem o n wyjściach i log2 n wejściach. Wyjścia y1 są ponumerowane od 0 do (n - 1). Wyjście jest w stanie jeden wtedy, kiedy wprowadzona liczba dwójkowa A jest równa numerowi tego wyjścia. W poniższej tablicy przedstawiono tablicę prawdy dekodera 1 z 4. Zmienne a0 i a1 przedstawiają liczbę A w kodzie dwójkowym. Można z niej bezpośrednio odczytać postać normalną sumy dla funkcji konwersji kodu. Odpowiednią realizację przedstawiono na rysunku 4.4. 1 a0 a1 A 0 1 2 3 a1 0 0 1 1 1 a0 0 1 0 1 y3 0 0 0 1 & y0 & y1 & y2 & y3 y2 0 0 1 0 y1 0 1 0 0 y0 1 0 0 0 Rysunek 4.4. Realizacja funkcji dekodera Przy realizacji scalonej w postaci układu monolitycznego, zamiast bramki AND używa się często bramki NAND. Zmienne wyjściowe są więc najczęściej zanegowane. Tablica 4.1. Najczęściej używane typy dekoderów 1 z n Typy układów scalonych: dziesięciowyjściowe TTL 74LS42 CMOS 4028 4.3.2. Proste układy kombinacyjne – demultiplekser Za pomocą demultipleksera można doprowadzać informację wejściową do różnych wyjść. Stanowi on rozszerzenie dekodera 1 z n. Zaadresowane wyjście nie przechodzi do stanu jeden, lecz przyjmuje wartość zmiennej wejściowej d. Na rysunku 4.5 pokazano zasadę jego pracy, posługując się bramkami logicznymi. Jeżeli x = const. = 1, demultiplekser pracuje jako dekoder 1 z n. Najczęściej używane typy demultiplekserów zebrano w tablicy poniżej. 22 a0 a1 1 1 d A 0 1 2 3 a1 0 0 1 1 a0 0 1 0 1 y3 0 0 0 d & y0 & y1 & y2 & y3 y2 0 0 d 0 y1 0 d 0 0 y0 1 0 0 0 Rysunek 4.5. Realizacja funkcji demultipleksera Tablica 4.2. Najczęściej używane typy demultiplekserów Typy układów scalonych: 16 wyjściowe 8 wyjściowe TTL 74LS154 74LS138 CMOS 5414 74HC138 4.3.3. Proste układy kombinacyjne – multiplekser Układ działający odwrotnie do demultipleksera nazywa się multiplekserem. Wykorzystując schemat ideowy z rys. 4.5 można go zrealizować przez zamianę wyjścia z wejściem. Powstaje wówczas układ przedstawiony na rys. 4.6. Na tej podstawie można w bardzo prosty sposób wytłumaczyć jego działanie: dekoder 1 z n wybiera to z n wejść, którego numer jest zgodny z wprowadzoną liczbą, i łączy je z wyjściem. Na rysunku 4.6. przedstawiono także odpowiednią realizację multipleksera za pomocą bramek logicznych. Rysunek 4.6. Zasada działania multipleksera i jego układ logiczny W technice CMOS multiplekser można zrealizować zarówno za pomocą bramek, jak i kluczy analogowych (bramek transmisyjnych – transmission gates). Jak widać z porównania rys. 4.5 i 4.6, 23 multiplekser zbudowany przy zastosowaniu kluczy analogowych staje się identyczny z demultiplekserem. W tym przypadku układ nosi nazwę analogowego multipleksera / demultipleksera. Rysunek 4.7. Multiplekser z bramkami z otwartym kolektorem Rysunek 4.8. Multiplekser z bramkami trójstanowymi Potrzebną w multiplekserach funkcję OR można zrealizować w postaci sumy galwanicznej, np. wykorzystując bramki z otwartym kolektorem (rys. 4.7). Ponieważ w logice dodatniej otrzymuje się w tym przypadku funkcję AND, należy - tak jak na rys. 4.1 - przejść na sygnały zanegowane. Jeżeli chcemy uniknąć wady związanej z otwartym kolektorem, tzn. wzrostu czasu propagacji tpLH, możemy połączyć równolegle wyjścia bramek trójstanowych, z których zawsze tylko jedna jest włączona. To rozwiązanie przedstawiono na rys. 4.8. Możliwości realizacji funkcji OR przedstawione na rys. 4.7 i 4.8 nie są stosowane w scalonych rnultiplekserach. Mają one jednak znaczenie wówczas, gdy źródła sygnałów wejściowych multipleksera są rozmieszczone w różnych miejscach. Najczęściej używane typy multiplekserów zestawiono w tabl. 4.3. Tablica 4.3. Scalone multipleksery. CMOS analogowy oznacza multiplekser/demultiplekser z bramkami transmisyjnymi 4.3.4. Proste układy kombinacyjne – dekoder priorytetowy Do zamiany kodu 1 z n na kod dwójkowy można zastosować dekoder priorytetowy. Na jego wyjściach pojawia się liczba dwójkowa odpowiadająca najwyższemu numerowi wejścia, na którym jest jedynka. Wartość zmiennych wejściowych o niższych numerach nie jest istotna. Nazwa dekoder priorytetowy wzięła się stąd, że za pomocą tego układu można zdekodować nie tylko kod 1 z n, lecz także kod, w którym jedynki występują we wszystkich pozycjach położonych niżej. Tablica prawdy kodera priorytetowego jest przedstawiona tablicy 4.4. 24 Tablica 4.4. Tablica prawdy kodera priorytetowego J 0 ! 7 3 4 5 6 7 8 9 x9 0 0 0 0 0 0 0 0 0 1 X8 0 0 0 0 0 0 0 D 1 x X6 0 0 0 0 0 0 0 1 x x X6 0 0 0 0 0 0 1 x x x X5 0 0 0 0 0 1 x x x x X4 0 0 0 0 1 x x x x x X3 0 0 0 1 x x x x x x X2 0 0 1 x x x x x x x X1 0 1 x x x x x x x x y1 0 0 0 0 0 0 0 0 1 1 y1 0 0 0 0 1 1 1 1 0 0 y1 0 0 1 1 0 0 1 1 0 0 yo 0 1 0 1 0 1 0 1 0 1 Tablica 4.5. Najczęściej używane dekodery priorytetowe Typy układów scalonych: Kod 1 z 10 Kod 1 z 8 z możliwością rozszerzenia TTL SN 74147 SN74148 CMOS 5414 MC 14532 4.4. Proste układy sekwencyjne Przez pojęcie układu .sekwencyjnego rozumie się taki układ elementów cyfrowych służący do realizacji zależności logicznych, który może zapamiętywać poszczególne stany zmiennych. W odróżnieniu od układów kombinacyjnych zmienne wyjściowe y zależą więc nie tylko od zmiennych wejściowych x, lecz dodatkowo od przeszłości, która jest reprezentowana przez stan przerzutników (wewnętrzny stan układu). 4.4.1. Przerzutniki FLIP-FLOP Jeżeli dwie bramki NOR połączymy w sposób pokazany na rys. 4.9, to otrzymamy przerzutnik (FLIP-FLOP). Ma on dwa dopełniające się wyjścia Q i Q oraz dwa wejścia S (set) i R (reset). Jeżeli na wejścia podamy S = 1 i R = 0, otrzymamy: Q = S + Q =1+ Q = 0 , Q = R + Q = 0 + 0 = 1 Oba wyjścia przyjmują więc rzeczywiście stany dopełniające się. Rysunek 4.9. Przerzutnik RS zbudowany z bramek NOR i jego tablica praejść 4.4.1. Proste układy sekwencyjne – przerzutnik FLIP-FLOP W analogiczny sposób dla R = 1 i S = 0 otrzymamy odwrotny stan wyjść. Jeżeli R = S = 0, zostaje zachowany poprzedni stan wyjść. Na tym właśnie polega zastosowanie przerzutnika RS jako elementu pamięci. Dla R = S = 1 oba wyjścia są równocześnie równe zeru, jeżeli jednak w następnej chwili R i S staną się równocześnie równe zeru, stan wyjść jest nieokreślony. Dlatego stan wejść R = S = 1 jest w zasadzie niedozwolony. Zestawienie stanów przerzutnika zamieszczono w tablicy przejść na rys. 4.9. 25 Rysunek 4.10. Przerzutnik RS zbudowany z bramek NAND i jego tablica przejść Równanie logiczne nie ulega zmianie, jeżeli zanegujemy wszystkie zmienne i zamienimy między sobą operacje (+) i (*). Jeżeli zasadę tę zastosujemy w tym przypadku, otrzymamy przerzutnik RS zbudowany z bramek NAND (rys. 4.10) o takiej samej tablicy przejść, jak podana na rys. 4.9. Należy jednak pamiętać, że teraz mamy do czynienia ze zmiennymi wejściowymi S i R . Jego tablicę przejść dla zmiennych wejściowych R i S przedstawia rys. 4.10. 4.4.2. Proste układy sekwencyjne – przerzutnik RS-kluczowany Często jest potrzebny przerzutnik RS, który reaguje na stan wejść tylko w określonym czasie. Czas ten ma określać dodatkowa zmienna taktująca C. Na rysunku 4.11 przedstawiono taki kluczowany przerzutnik RS (clocked RS flip flop). Dla C = 0 mamy R = S = 1. W tym przypadku przerzutnik pamięta poprzedni stan. Dla C = 1 mamy R=R' i S=S', czyli przerzutnik zachowuje się jak normalny przerzutnik RS. Rysunek 4.11. Przerzutnik RS kluczowany 4.4.3. Proste układy sekwencyjne – przerzutnik D-kluczowany W dalszej kolejności zbadamy, jak w przerzutniku z rys. 4.11 można zapamiętać wartość zmiennej logicznej D. Stwierdziliśmy, że Q = S, jeśli na wejścia podamy dopełniające się stany i jeśli C = 1. Aby zapamiętać wartość zmiennej D, należy tylko spełnić warunek S = D i R = D. Do tego służy inwertor B5 na rys. 4.12. W powstałej w ten sposób komórce pamięci mamy Q = D tak długo, jak długo sygnał zegarowy C = 1. Wynika to również z tablicy przejść pokazanej na rys. 4.12. Ze względu na tę właściwość taka kluczowana komórka pamięci nosi nazwę przerzutnika D typu „zatrzask" (data latch). Rysunek 4.12. Przerzutnik D typu „zatrzask” i jego tablica przejść 26 Jeżeli C = 0, aktualny w danej chwili stan wyjść zostaje zapamiętany. Nietrudno zauważyć, że bramka NAND B4 na rys. 4.12 dla C = 1 jest inwertorem zmiennej D. Umożliwia to zaoszczędzenie inwertora B5 i prowadzi do praktycznej realizacji przerzutnika D przedstawionej na rys. 4.13. Na tym rysunku przedstawiono także jego symbol graficzny. Rysunek 4.13. Realizacja praktyczna przerzutnika D typu „zatrzask” i jego symbol graficzny Tablica 4.6. Najczęściej używane przerzutniki D typu „zatrzask” Typy układów scalonych: Zatrzask TTL 74L575 CMOS 4042 4.4.4. Proste układy sekwencyjne – przerzutnik wyzwalany impulsem Do wielu zastosowań, jak np. liczniki i rejestry przesuwające, przerzutniki proste nie nadają się. W tych zastosowaniach są potrzebne przerzutniki zapamiętujące stany wejściowe i przekazujące je na wyjścia dopiero po ponownym zablokowaniu wejść. Składają się one z dwu przerzutników prostych: przerzutnika głównego (master) na wejściu i przerzutnika pomocniczego (slave) na wyjściu. Na rysunku 4.14 pokazano przerzutnik wyzwalany impulsem (two-edge triggered flip-flop) typu master-slave zbudowany z dwu kluczowanych przerzutników RS z rys. 10.5. Oba przerzutniki są blokowane na przemian sygnałem zegarowym C. Do inwersji sygnału zegarowego służy bramka B15. Gdy sygnał zegara C = 1, informacja wejściowa jest wczytywana do przerzutnika głównego. Stan wyjść nie ulega zmianie, gdyż przerzutnik pomocniczy jest zablokowany. Rysunek 4.14. Przerzutnik RS master-slave 27 Rysunek 4.14. Przerzutnik RS master-slave Gdy impuls zegara zmieni swój stan na C = 0, przerzutnik główny zostaje zablokowany i w ten sposób zostaje „zamrożona" informacja, która była na wejściu bezpośrednio przed ujemnym zboczem impulsu zegara. Równocześnie zostaje odblokowany przerzutnik pomocniczy i tym samym stan przerzutnika głównego zostaje przekazany na wyjście. Przesyłanie danych następuje więc przy ujemnym zboczu sygnału zegara, nie ma jednak takiego stanu zegara, przy którym dane wejściowe oddziaływałyby bezpośrednio na wyjście, jak to ma miejsce w przerzutnikach prostych (transparent flip flnps). Kombinacja zmiennych wyjściowych R=S=1 prowadzi do nieokreślonego zachowania się przerzutnika, ponieważ wejścia S 1 i R 1 w części głównej równocześnie zmieniają się z 00 na 11 przy przejściu zegara do stanu C = 0. 4.4.5. Przerzutniki wyzwalane zboczem (single-edge-triggered flip flops) Przerzutniki złożone można realizować również łącząc szeregowo dwa przerzutniki D typu „zatrzask" (rys. 10.8) i sterując je dopełniającymi się sygnałami zegarowymi. Otrzymuje się wtedy układ przedstawiony na rys. 10.16. Jeżeli zegar jest w stanie C = 0, przerzutnik główny śledzi sygnał wejściowy i Q1 = D. W tym czasie przerzutnik pomocniczy pamięta poprzedni stan. Gdy zegar zmienia swój stan na 1, istniejąca w tym momencie informacja D zostaje zamrożona w przerzutniku głównym i przeniesiona do przerzutnika pomocniczego, a tym samym na wyjście Q. Informacja istniejąca na wejściu D w chwili pojawienia się dodatniego zbocza impulsu zegarowego zostaje więc natychmiast przeniesiona na wyjście Q. W pozostałym czasie stan wejścia D nie odgrywa roli, co widać również na rys. 4.16. W przerzutniku z rys. 4.15wartość wczytana pojawia się na wyjściu natychmiast, a nie dopiero przy ujemnym zboczu impulsu zegarowego. Rysunek 4.15. Przerzutnik D wyzwalany zboczem Stanowi to zaletę, ponieważ dla utworzenia nowych sygnałów D mamy do dyspozycji cały czas trwania okresu zegara. 28 Rysunek 4.16. Przebiegi czasowe sygnałów wejściowych i wyjściowych w przerzutniku D wyzwalanym zboczem Rysunek 4.17. Symbol graficzny przerzutnika D wyzwalanego zboczem Symbol graficzny przerzutnika D wyzwalanego zboczem przedstawiono na rys. 4.17. Tablica 4.7. Najczęściej używane przerzutniki D wyzwalane zboczem Typy układów scalonych: TTL CMOS Przerzutnik wyzwalany 74L74 4013 zboczem Przerzutniki D wyzwalane zboczem mogą pracować również jako przerzutniki T (toggle). Należy w tym celu zrealizować zależność D = Q , jak to pokazano na rys. 4.18. W chwili wystąpienia dodatniego zbocza impulsu zegarowego stan wyjścia zmienia się na przeciwny. Przedstawiono to na rys. 4.19. W przypadku zastosowania przerzutników D typu „zatrzask", zamiast dzielenia częstotliwości w czasie, gdy C = 1, otrzymalibyśmy generację drgań, ponieważ ze względu na nie zablokowane przejście sygnału, po upływie czasu opóźnienia następowałoby odwrócenie jego fazy. Rysunek 4.18. Przerzutnik D wyzwalany zboczem jako dzielnik częstotliwości Rysunek 4.19. Przebiegi czasowe w dzielniku częstotliwości Odwracanie fazy można uzależnić również od zmiennej sterującej, łącząc zgodnie z wyborem wyjście Q lub Q z wejściem D przez multiplekser. Multiplekser jest sterowany z wejścia T, jak pokazano na rys. 4.20. Rysunek 4.20. Budowa przerzutnika T i jego symbol graficzny Jeszcze bardziej uniwersalne przerzutniki można otrzymać przez stworzenie dodatkowej możliwości synchronicznego wprowadzania danych. W tym celu należy wykorzystać multiplekser o dodatkowym - poza wejściem D - wejściu, które jest wybierane za pomocą wejścia wpisującego L (load) w sposób przedstawiony na rys. 4.21. Dla L = 1 mamy y = D, a w następnym takcie Q = D. Dla L = 0 układ pracuje dokładnie tak, jak układ na rys. 4.20. Symbol oraz tablicę przejść tego przerzutnika przedstawiono na rys. 4.22. 29 Rysunek 4.21. Przerzutniki wielofunkcyjne Rysunek 4.22. Symbol graficzny i tablica przejść przerzutnika wielofunkcyjnego 4.4.6. Liczniki dwójkowe Ważną grupę układów sekwencyjnych stanowią liczniki. Licznikiem może być każdy układ, w którym w pewnym zakresie istnieje jednoznaczne przyporządkowanie liczbie wprowadzonych impulsów stanu zmiennych wyjściowych. Ponieważ każda zmienna wyjściowa może przyjmować tylko dwie wartości, w przypadku n wyjść istnieje 2n możliwych kombinacji (często wykorzystuje się jednak tylko część możliwych kombinacji). Wybór kombinacji, która ma odpowiadać danej liczbie, jest w zasadzie obojętny. Celowe jest jednak dobranie takiego sposobu przedstawienia liczb, który umożliwia łatwe ich dekodowanie. Najprostsze układy otrzymuje się w przypadku naturalnego kodu dwójkowego. Na rysunku 4.23 przedstawiono odpowiednie przyporządkowanie liczbie impulsów wejściowych Z wartości zmiennych wyjściowych zi dla 4-bitowego licznika dwójkowego. Jeżeli czytamy tę tablicę od góry do dołu, możemy zauważyć dwie prawidłowości: - zmienna wyjściowa zi zmienia swoją wartość wtedy, kiedy najbliższa zmienna zi-1 przechodzi z 1 na 0; - zmienna wyjściowa zi zmienia zawsze swoją wartość wtedy, kiedy wszystkie niższe zmienne zi-1 ... z0 mają wartość 1 i pojawi się nowy impuls zliczany. Prawidłowości te można odczytać również z wykresu czasowego przedstawionego na rys. 4.24. Pierwsza prawidłowość prowadzi do realizacji licznika asynchronicznego, a druga - licznika synchronicznego. 30 Rysunek 4.23. Tablica stanów licznika dwójkowego Rysunek 4.24. Przebiegi czasowe na wyjściach licznika dwójkowego liczącego w przód Niekiedy są potrzebne liczniki, których stan po każdym impulsie zliczanym zmniejsza się o jeden. Prawidłowości charakteryzujące taki licznik liczący w tył (odejmujący - down counter) można również dostrzec w tablicy na rys. 4.23, czytając ją od dołu do góry: - w liczniku odejmującym zmienna wyjściowa zi zmienia swą wartość zawsze wtedy, kiedy najbliższa niższa zmienna zi-1 przechodzi z 0 na 1; - w liczniku odejmującym zmienna wyjściowa zi zmienia swą wartość zawsze wtedy, kiedy wszystkie niższe zmienne zi-1 ... z0 mają wartość 0 i pojawi się nowy impuls zliczany. 4.4.7. Asynchroniczne Liczniki dwójkowe Asynchroniczny licznik dwójkowy można zrealizować, tworząc łańcuch przerzutników i łącząc wejście zegarowe C każdego przerzutnika z wyjściem Q poprzedniego, jak to pokazano na rys. 4.25. Można np. zastosować przerzutniki wyzwalane dodatnim zboczem impulsu zegarowego, czyli np. przerzutniki D wyzwalane zboczem. Jeżeli połączymy je tak, jak na rys. 4.25, otrzymamy licznik odejmujący. Aby zrealizować zliczanie w przód, należy dokonać inwersji sygnału 31 zegarowego. W tym celu wejście zegarowe łączymy po prostu z wyjściem Q poprzedniego przerzutnika. Z0 CLK C1 Q Q Z1 C1 Q Q Z2 C1 Q Z3 C1 Q Q Q Rysunek 4.25. Asynchroniczny licznik dwójkowy Każdy licznik jest równocześnie dzielnikiem częstotliwości. Częstotliwość na wyjściu przerzutnika Po jest równa połowie częstotliwości impulsów zliczanych. Na wyjściu P1 występuje jedna czwarta częstotliwości wejściowej, na wyjściu P2 jedna ósma, itd. Ta właściwość dzielenia częstotliwości jest dobrze widoczna na rys. 4.25. Typy scalonych asynchronicznych liczników dwójkowych przedstawiono w tabl. 10.2. Tablica 4.8. Najczęściej używane asynchroniczne liczniki dwójkowe TTL 74L93 74LS93 Typy układów scalonych: Licznik 4 bitowy Licznik 8 bitowy Licznik 24 bitowy CMOS 4521 4.4.8. Synchroniczne Liczniki dwójkowe Cechą liczników asynchronicznych jest to, że zliczane impulsy są podawane tylko na wejście zegarowe pierwszego przerzutnika, podczas gdy pozostałe przerzutniki są sterowane w sposób pośredni. W następstwie tego sygnał wejściowy dociera do ostatniego przerzutnika dopiero wówczas, gdy przerzucą wszystkie poprzednie przerzutniki. Stany kolejnych wyjść z0 do zn zmieniają się z opóźnieniem równym czasowi przerzutu. W przypadku długiego łańcucha przerzutników i dużej częstotliwości liczenia może się zdarzyć, że zn zmienia się dopiero po pojawieniu się następnego impulsu zliczanego. Dlatego po ostatnim impulsie należy odczekać czas opóźnienia całego łańcucha przerzutników, a dopiero potem odczytywać stan licznika. Jeżeli jest potrzebny odczyt stanu licznika w trakcie liczenia, to okres impulsów zliczanych nie może być krótszy od czasu opóźnienia łańcucha przerzutników tworzących licznik. Wad tych nie mają liczniki synchroniczne. Rysunek 4.26. Synchroniczny licznik dwójkowy Charakteryzują się one tym, że zliczane impulsy są podawane równocześnie na wszystkie wejścia zegarowe C. Aby każdy impuls zegarowy nie przerzucał wszystkich przerzutników, stosuje się sterowane przerzutniki T (rys. 4.20), które zmieniają stan tylko wówczas, gdy zmienna sterująca T= 1. Zgodnie z tabl. z rys. 4.23 warunek przerzutu brzmi: przerzutnik wchodzący w skład licznika dwójkowego może zmienić stan tylko wtedy, kiedy wszystkie przerzutniki poprzednie są w stanie 32 jeden. Aby to zrealizować, należy zapewnić warunki T0 = 1, Tl = z0, T2 = z0zl i T3 = z0zlz2. Na rysunku 4.26 można zauważyć służące do tego celu bramki AND. Scalone liczniki synchroniczne mają jeszcze kilka innych wejść i wyjść, których działanie i zastosowanie wyjaśnimy dokładniej na podstawie rys. 4.27. Rysunek 4.27. Praktyczna realizacja scalonego licznika synchronicznego Wejście zerujące CLR umożliwia wyzerowanie całego licznika. (Z = 0). Wejście wpisujące LOAD umożliwia wpisanie do licznika dowolnej liczby Z = D. Wejścia C1 są asynchroniczne, natomiast wejścia wpisujące mogą być zarówno synchroniczne, jak i asynchroniczne. Liczniki wieloczłonowe można realizować przez kaskadowe połączenie większej liczby członów, np. czteropozycyjnych. Człony łączy się ze sobą przez wyjścia przeniesienia szeregowego RCO (ripple carry output) i wejścia zezwolenia T (enable T) ENT, za pomocą których można zablokować cały człon licznika i wyjście przeniesienia. Na wyjściu przeniesienia sygnał 1 pojawi się wówczas, gdy licznik osiągnie stan 1111, i wszystkie człony poprzedzające dadzą również przeniesienie 1. W tym celu w każdym członie należy zrealizować funkcję: RCO = ENT z0zlz2z3. W celu kaskadowego połączenia członów licznika należy tylko połączyć wejście ENT jednego członu z wyjściem RCO najbliższego członu poprzedzającego. W celu kaskadowego połączenia członów licznika należy tylko połączyć wejście ENT jednego członu z wyjściem RCO najbliższego członu poprzedzającego. Rysunek 4.28. Kaskadowe łączenie członów licznika synchronicznego 33 Tablica 4.9. Wybrane scalone synchroniczne liczniki dwójkowe Kaskadowa realizacja funkcji AND powoduje jednak sumowanie się czasów propagacji. W licznikach wieloczłonowych powoduje to zmniejszenie maksymalnej osiągalnej częstotliwości liczenia. W tym przypadku jest bardziej korzystne tworzenie wymaganej funkcji AND równolegle w każdym członie licznika. W tym celu opuszcza się najniższy człon licznika przy szeregowym łączeniu RCO-ENT i steruje blokadę wyższych członów równolegle, przez wejście zezwolenia P (enable P) ENP. W ten sposób równoległą realizację funkcji AND można przeprowadzić bez udziału zewnętrznych bramek, jak to pokazano na rys. 4.28. 4.4.9. Rejestry przesuwające Rejestry przesuwające to łańcuchy zbudowane z przerzutników, które umożliwiają przesuwanie informacji podanej na wejście o jeden przerzutnik w każdym takcie zegara. Po przejściu przez cały łańcuch informacja jest dostępna na wyjściu z opóźnieniem, ale w niezmienionej postaci. Zasada pracy rejestru przesuwającego jest przedstawiona na rys. 4.29. Pierwszy impuls zegarowy powoduje wczytanie informacji D1 podanej na wejście do przerzutnika P1. Drugi impuls zegarowy powoduje przekazanie jej do przerzutnika P2; równocześnie do przerzutnika P1 zostaje wczytana nowa informacja. Tablica 4.10 ilustruje działanie takiego układu na przykładzie rejestru przesuwającego o długości czterech bitów. Można zauważyć, że po czterech taktach rejestr przesuwający zostaje wypełniony wprowadzanymi danymi. Są one do dyspozycji w postaci równoległej na wyjściach czterech przerzutników Q1... Q4 lub można je otrzymać w następnych taktach w postaci szeregowej na wyjściu Q4. Rysunek 4.29. Najprostsza realizacja 4-bitowego rejestru przesuwającego Rysunek 4.29. Najprostsza realizacja 4-bitowego rejestru przesuwającego 34 Tablica 4.10. Tablica stanów 4-bitowego rejestru przesuwającego Jako przerzutniki nadają się do tego celu wszystkie typy przerzutników złożonych. Przerzutniki proste nie nadają się, ponieważ w chwili pojawienia się jedynki na wejściu zegarowym informacja podana na wejście przebiegłaby natychmiast aż do ostatniego przerzutnika. 4.4.10. Rejestr przesuwający z wpisem równoległym Jeżeli do każdego wejścia D dołączymy multiplekser, jak to pokazano na rys. 4.30, to za pomocą wejścia LOAD można przełączyć układ na wpisywanie równoległe. W następnym takcie dane d1 ... d4 zostają wpisane równolegle i pojawiają się na wyjściach Q1... Q4. Umożliwia to nie tylko przejście z postaci szeregowej na równoległą, lecz także z postaci równoległej na szeregową. Rysunek 4.30. Rejestr przesuwający z równoległym wejściem wpisującym Rejestr przesuwający z wejściami do wpisywania równoległego może pracować również jako rejestr dwukierunkowy. W tym celu należy połączyć każde wejście do wpisywania równoległego z sąsiednim wyjściem po prawej stronie. Wtedy dla LOAD = 1 otrzymuje się przesuwanie danych od prawej strony do lewej. Przykłady scalonych rejestrów przesuwających przedstawiono w tabl. 4.11. Tablica 4.11. Wybrane scalone rejestry przesuwające 35 4.5. Pamięci Wśród pamięci półprzewodnikowych można wyróżnić dwie podstawowe grupy: pamięci typu tablicowego oraz pamięci typu funkcyjnego . Na rysunku 4.31 przedstawiono klasyfikację najczęściej używanych rodzajów pamięci. Rysunek 4.31. Rodzaje pamięci półprzewodnikowych W pamięciach typu tablicowego podaje się adres mieszczący się w zakresie Długość słowa adresu wynosi, zależnie od rodzaju pamięci, N = 5 ...22. Pod każdym z 2N adresów można zapamiętać dane. Długość słowa danych wynosi m=l...l6 bitów. Na rysunku 4.32 pokazano przykład pamięci o N = 3 bitach adresu i m = 2 bitach danych. Rysunek 4.32. Układ tablicy Pojemność pamięci P = m * n jest podawana w bitach, a przy długościach słowa danych 8 lub 16 bitów - również w bajtach, jako P/8. Użycie większej liczby elementów pamięci umożliwia dowolne rozszerzenie tak przestrzeni adresowej, jak też długości słowa. W ten sposób można zapamiętywać dowolne tablice, jak np. tablice prawdy, programy komputerowe lub ciągi danych pomiarowych. W pamięciach typu funkcyjnego zapamiętuje się nie tablice, lecz funkcje logiczne. Każdą zmienną tablicy prawdy można przedstawić w postaci funkcji logicznej. Funkcja logiczna zmiennej d0 na rys. 4.32 ma następującą postać normalną sumy: 36 d 0 = a 2 a1 a 0 d 00 + a 2 a1 a0 d10 + ... + a 2 a1 a 0 d 70 Jeżeli d0 nie wykazuje żadnych prawidłowości, a więc zera i jedynki są rozłożone zgodnie z zasadami statystyki, otrzymujemy n/2, a więc w tym przypadku 4 nie znikające iloczyny. Tego rodzaju zależności występują np. przy zapamiętywaniu programów. W tym przypadku realizacja funkcji logicznej jest bardziej pracochłonna niż zapamiętanie jej w tablicy. Rysunek 4.32. Układ tablicy Jeżeli jednak punktem wyjścia jest tablica prawdy, z powodu występujących często prawidłowości istnieją daleko idące możliwości uproszczenia funkcji logicznej. Przypadek ten ma miejsce np. wtedy, kiedy w tablicy występuje bardzo mało jedynek. Jeżeli np. funkcja d0 jest równa tylko d70 = l, potrzebny jest tylko jeden iloczyn d0 = a2a1a0. Inny przypadek występuje wtedy, kiedy funkcja logiczna daje się uprościć za pomocą twierdzeń algebry Boole'a. Jeżeli np. na rys. 4.32 d0=a1, otrzymuje się bardzo prostą funkcję, chociaż zawiera ona 4 jedynki. W takich przypadkach zastosowanie pamięci typu funkcyjnego prowadzi do bardziej korzystnych rozwiązań niż zastosowanie pamięci typu tablicowego. Pamięci typu tablicowego można podzielić na pamięci RAM i ROM. RAM jest ogólnym oznaczeniem pamięci, w których przy normalnej pracy istnieje możliwość zapisywania i odczytywania informacji. Skrót RAM oznacza dosłownie „Random Access Memory", czyli „pamięć o swobodnym dostępie". Oznacza to, że w każdej chwili istnieje dostęp do każdego słowa danych, w przeciwieństwie do pamięci o dostępie szeregowym, w których wpisane słowo danych może zostać odczytane lub zmienione tylko w ściśle określonej chwili. Pamięci o dostępie szeregowym nie mają obecnie większego znaczenia. Dlatego też nazwa RAM stanowi ogólne określenie pamięci z zapisem i odczytem. Jest ona o tyle myląca, że pamięci ROM również umożliwiają swobodny dostęp do każdego słowa danych. ROM jest skrótem angielskiej nazwy „Read-Only Memory", czyli „pamięć tylko odczytywana". Nazwa ta obejmuje pamięci scalone zachowujące dane nawet wówczas, gdy pracują bez żadnego napięcia zasilania, w tym również bez pomocniczych baterii. Jak sama nazwa wskazuje przy normalnej pracy dane z tych pamięci mogą być tylko odczytywane. Proces zapisu danych odbywa się na ogól w specjalnych urządzeniach i nosi nazwę programowania. Przedstawione na rys. 4.31 rodzaje pamięci ROM różnią się sposobem programowania; zostanie to dokładniej opisane w następnych punktach. 4.5.1. Pamięci statyczne RAM RAM jest pamięcią, w której można po podaniu adresu zapisać dane i pod tym adresem ponownie je odczytać (tzw. dostęp swobodny). Ze względów technologicznych komórki pamięci nie są ułożone liniowo, lecz stanowią kwadratową matrycę. W celu wybrania określonej komórki pamięci adres A jest dekodowany przez dekoder kolumn i wierszy, jak to pokazano na rys. 4.33. Oprócz wejść adresowych pamięć RAM ma jeszcze wejście danych DI (data input), wyjście danych DO (data output), wejście sygnału zapis/odczyt R/ W (read/write) i wejście sygnału wyboru 37 (selekcji) układu CS (chip selecf) lub sygnału zezwolenia dla układu CE (chip enable). Wejścia CS i CE umożliwiają pracę w systemie multipleksowym większej liczby pamięci połączonych ze wspólną linią danych (praca z wykorzystaniem magistrali). Jeżeli CS = O, wyjście danych DO znajduje się w stanie wysokiej impedancji i nie ma wpływu na linię danych. W celu umożliwienia tego rodzaju przełączania wyjście danych jest zrealizowane przeważnie jako wyjście z otwartym kolektorem lub wyjście trójstanowe. W czasie zapisu (R/W = 0) dodatkowa funkcja logiczna powoduje ustawienie bramki wyjściowej również w stan wysokiej impedancji. Dzięki temu istnieje możliwość połączenia DI z DO i prowadzenie w ten sposób transmisji danych w obu kierunkach za pomocą tej samej linii (magistrala dwukierunkowa). Inna funkcja logiczna zapobiega przełączeniu w stan zapisu (we = 1), gdy CS = 0. Dzięki temu unika się omyłkowego zapisu przed wybraniem odpowiedniego układu pamięci. Rysunek 4.33. Budowa wewnętrzna pamięci RAM. Przykład pamięci o pojemności 16 bitów Rysunek 4.34. Logiczny schemat zastępczy komórki pamięci Funkcje te są pokazane na rys. 4.33. Wewnątrz układu do każdej komórki pamięci są doprowadzone linie di, do i we (write enable), jak to schematycznie przedstawiono na rys. 4.34. Dane mogą zostać wpisane do komórki pamięci tylko wówczas, gdy jest spełniony warunek adresu xj = yj = l i oprócz tego we = l. Tę funkcję realizuje bramka B1 Zawartość komórki pamięci może być podana na wyjście również tylko wtedy, kiedy jest spełniony warunek adresu. Tę funkcję realizuje bramka B2. Ma ona wyjście z otwartym kolektorem. Jeżeli komórka nie jest zaadresowana, tranzystor wyjściowy jest zablokowany. Wyjścia wszystkich komórek pamięci są połączone wewnątrz układu, 38 tworząc iloczyn galwaniczny i za pomocą pokazanej na rys. 4.33 bramki trójstanowej są dołączone do wyjścia pamięci DO. Jeśli nie zostanie odłączone napięcie zasilania, zawartość pamięci jest zachowana tak długo, aż zostanie zmieniona nowym poleceniem zapisu. Takie pamięci noszą nazwę pamięci statycznych, w odróżnieniu od pamięci dynamicznych, których zawartość musi być stale odświeżana, aby nie uległa zatarciu. Symbol graficzny pamięci RAM przedstawia rys. 4.35. Na symbolu widać N wejść adresowych, które są dekodowane przez dekoder adresu tak, by można było wybrać dokładnie tę komórkę pamięci (z 2N komórek), która odpowiada podanemu adresowi. Przełączanie z zapisu na odczyt R/IV jest aktywne tylko wtedy, kiedy sygnał zezwolenia dla układu (chip enable) CE = l lub CE = 0. Wtedy przy RfW = l wyjście trójstanowe jest aktywne, a przy R/W = O w stanie wysokiej impedancji. Dlatego też istnieje możliwość wewnętrznego połączenia wejścia i wyjścia danych w elemencie pamięci. Powstaje wówczas dwukierunkowy port danych, którego kierunek transmisji jest określany za pomocą sygnału R/W. Rysunek 4.35. Symbol graficzny pamięci RAM Często pod jednym adresem jest pamiętany nie pojedynczy bit, ale całe m-pozycyjne słowo. Pamiętanie całych słów można przedstawić jako przestrzenne rozszerzenie schematu blokowego z rys. 4.33. Dodatkowe bity leżą wówczas na następnych poziomach pamięci jeden nad drugim; ich linie sterujące x, y, i we są połączone równolegle, a linie danych tworzą słowo wejściowe lub wyjściowe. 4.5.1. Pamięci statyczne RAM – parametry dynamiczne W celu zapewnienia niezawodnej pracy pamięci powinny być spełnione pewne warunki. Na rysunku 4.36 przedstawiono wykresy czasowe sygnałów w trakcie zapisu. Dla uniknięcia wpisania danych do niewłaściwej komórki, polecenie zapisu można podać dopiero pewien czas po adresie. Czas ten nosi nazwę czasu ustalania na wejściu adresowym tAS (adress setup time). Czas trwania sygnalu zapisu nie może spaść poniżej wartości twp (write pulse width). 39 Rysunek 4.36. Przebiegi czasowe cyklu zapisu Dane zostają wpisane na końcu sygnału zapisu. Muszą one być aktualne, tj. stabilne dla poprzedzającego określonego minimalnego odstępu czasu. Czas ten jest oznaczany symbolem tDW, (data valid to end ofwrite). W wielu pamięciach dane lub adresy muszą zostać przetrzymane jeszcze przez pewien czas tH po zakończeniu impulsu zapisu (hold time). Jak widać na rys. 4.36, zapisywanie wymaga czasu: Nosi on nazwę czasu cyklu zapisu (write cycle time). Cykl odczytu jest przedstawiony na rys. 4.37. Po podaniu adresu należy odczekać czas tAA, aż dane będą dostępne na wyjściu. Czas ten nosi nazwę czasu dostępu od wejścia adresowego (adress access time) lub po prostu czasu dostępu. Rysunek 4.37. Przebieg czasowy cyklu odczytu W tablicy 4.12 podano zestawienie najczęściej używanych pamięci stat. RAM w tech. bipolarnej i MOS. 40 Tablica 4.12. Przykłady pamięci statycznych RAM 4.5.2. Pamięci dynamiczne RAM Ponieważ w pamięci chcielibyśmy pomieścić możliwie dużo komórek, należy je realizować możliwie w prosty sposób. Z reguły komórka pamięci składa się tylko z kilku tranzystorów; w statycznych pamięciach RAM CMOS typowa komórka składa się z 6 tranzystorów. W najprostszym przypadku rezygnuje się nawet z przerzutnika, zastępując go kondensatorem, który jest wybierany za pomocą tranzystora MOS. W ten sposób można zbudować komórkę pamięci zawierającą tylko l tranzystor. Informacja jest wówczas pamiętana w postaci ładunku, ale niestety pozostaje zachowana tylko przez krótki czas. Dlatego też kondensator pamiętający wymaga regularnego doładowywania (co ok. 2... 8 ms). Operację tę nazywamy odświeżaniem (refresh), a pamięć nosi nazwę pamięci dynamicznej RAM. Mimo tej wady pamięci dynamiczne mają wiele zalet: na tej samej powierzchni półprzewodnika, przy tym samym poborze prądu i tych samych kosztach umożliwiają uzyskanie w przybliżeniu czterokrotnie większej pojemności pamięci. W celu 41 zmniejszenia liczby wyprowadzeń w pamięciach dynamicznych adres jest wprowadzany w dwu krokach oraz zostaje przejściowo zapamiętany w układzie scalonym. Odpowiedni schemat blokowy jest przedstawiony na rys. 4.38. W pierwszym kroku sygnał bramkowania adresu wiersza RAS (rów adress strobe) powoduje wpisanie bitów adresu a0...a1 do rejestru adresu wiersza (rów adress latch), a w drugim kroku sygnal bramkowania adresu kolumny CAS (column adress strobe) wpisanie bitów adresu a8...a15 do rejestru adresu kolumny (column adress latch). Rysunek 4.38. Dekodowanie adresu w pamięci dynamicznej 1 Mbit Umożliwia to umieszczenie pamięci 1-megabitowej w obudowie 18-wyprowadzeniowej. W tablicy 4.13 umieszczono zestawienie najczęściej używanych typów takich pamięci. Tablica 4.13. Przykłady pamięci dynamicznych RAM 42 4.5.3. Pamięci dynamiczne RAM – układ sterowania (kontroler) Pamięci dynamiczne RAM wymagają współpracy dodatkowych układów. Przy normalnym dostępie do pamięci adres musi być wpisany do pamięci w dwu następujących po sobie krokach. W celu uniknięcia utraty danych jest wymagane wywołanie wszystkich adresów wierszy co najmniej raz w ciągu 8 ms. Jeżeli zawartość pamięci nie jest czytana cyklicznie, są konieczne dodatkowe układy, które powodują adresowanie cykliczne między normalnymi cyklami dostępu do pamięci. Układy te noszą nazwę kontrolerów pamięci dynamicznych RAM (dynamie RAM controller). Schemat blokowy takiego układu, jest pokazany na rys. 4.39. W normalnym cyklu dostępu do pamięci podany z zewnątrz adres zostaje zapamiętany w rejestrze adresu wiersza i kolumny, jeśli sygnal bramkowania adresu AS (adress strobe) jest równy l i wskazuje, że adres jest aktualny. Równocześnie układ sterowania przebiegu inicjuje cykl dostępu do pamięci. Powoduje to najpierw podanie adresu wiersza a0...a9 do pamięci za pomocą multipleksera. Następnie sygnał bramkowania adresu wiersza RAS przyjmuje wartość l i powoduje przekazanie adresu do pamięci. Potem zostaje podany adres kolumny a10...a19 i za pomocą sygnału bramkowania adresu kolumny CAS zostaje wczytany również do pamięci. Odpowiedni przebieg czasowy pokazano na rys. 4.40. Rysunek 4.39. Schemat blokowy kontrolera pamięci dynamicznej RAM 1Mbit Po wprowadzeniu adresu sygnał bramkowania adresu musi pozostać tak długo w stanie l, aż zakończy się przesyłanie danych. Następny cykl dostępu do pamięci nie może zacząć się natychmiast, lecz dopiero po upływie czasu wstępnego ładowania (precharge time), który jest tego samego rzędu, co czas dostępu. W czasie odświeżania należy co 8 ms wywołać 512 niższych adresów. Przy czasie cyklu odświeżania (refresh cycle time) równym 300 ns potrzeba na to w sumie ok. 150 µs. Dyspozycyjność pamięci zmniejsza się wskutek tego tylko o mniej niż 2%. Rysunek 4.40. Przebieg czasowy wprowadzania adresu do pamięci dynamicznej RAM 43 Istnieją trzy różne metody podziału czasowego cyklu odświeżania: - Odświeżanie z przerwaniem cyklu pracy (burst refresh). Przy tym rodzaju odświeżania po każdych 8 ms normalnej pracy następuje jej przerwanie i odświeżenie wszystkich komórek pamięci. W wielu jednak przypadkach zablokowanie pamięci na 150 us może zakłócać jej prace; - Odświeżanie z wykradaniem cykli (cycle stealing). Dla uniknięcia niekorzystnego blokowania pamięci proces odświeżania można równomiernie rozłożyć na okres 8 ms: jeżeli stan licznika odświeżania będziemy co 15 us zwiększać o l po 512x15us≈8 ms, nastąpi aktywizacja wszystkich adresów wierszy, tak jak jest to wymagane. Przy tym rodzaju odświeżania procesor jest zatrzymywany co 15 us na jeden cykl i jest wykonywany krok odświeżania. W czasie cyklu odświeżania stan licznika odświeżania jest podawany przez multiplekser do pamięci, a sygnał RAS przejściowo jest ustawiany w stan 1. Na zakończenie stan licznika zostaje zwiększony o jeden. W czasie cyklu odświeżania użytkownik pamięci jest wstrzymywany sygnałem oczekiwania (wait). Biegnący proces jest wskutek tego zatrzymywany co 15 us na 0,3 us, a więc przebiega o 2% wolniej; - Odświeżanie o minimalnych stratach czasu (transparent refresh lub hidden refresh). Metoda ta polega również na realizacji cyklu odświeżania co 15 µs. Układ sterowania odświeżania (refresh controller) jest jednak synchronizowany tak, że nie następuje wstrzymywanie dostępu do pamięci, lecz odświeżanie odbywa się dokładnie wtedy, kiedy użytkownik i tak nie korzysta z pamięci. Nie występuje wtedy strata czasu. Jeżeli nie można całkowicie wykluczyć nakładania się na siebie dostępu do pamięci z zewnątrz i cyklu odświeżania, można zastosować dekoder priorytetowy (arbiter). Żądanie dostępu z zewnątrz zostaje potwierdzone sygnałem oczekiwania trwającym do zakończenia trwającego cyklu odświeżania, po czym następuje jego realizacja. Tablica 4.14. Typy układów scalonych pamięci DRAM 1M: SN74ACT4503 DP8421A 74F1764 673104 DP8430 AM29C668 74F1762 DP8840 DP8441 pamięci DRAM 4M: pamięci DRAM 16M: pamięci DRAM64M: CMOS CMOS TTL TTL CMOS CMOS TTL CMOS CMOS Texas Instr. National Philips AMD National AMD Philips National National 4.5.4. Pamięci dwubramowe RAM Pamięci dwubramowe (dudport RAM) to specjalne pamięci RAM, które umożliwiają dwu niezależnym procesom dostęp do wspólnych danych. Umożliwia to wymianę danych między obydwoma procesami. W tym celu pamięć dwubramowa musi mieć dwa oddzielne zestawy linii adresowych, danych i sterujących, jak to pokazano na rys. 4.41. Zasady tej nie można zrealizować bez ograniczeń, ponieważ nie jest możliwy równoczesny wpis z obu bram do tej samej komórki pamięci. A1 R/W1 D1 A2 Pamięć dwubramowa Brama 1 R/W2 D2 Brama 2 Rysunek 4.41. Wyprowadzenia zewnętrzne pamięci dwubramowej 44 WRITE1 A1 Dekoder adresu1 WRITE2 Matryca pamięci D1 Dekoder A2 adresu2 D2 4.42. Budowa pamięci z możliwością odczytu podczas zapisu W przypadku pamięci z możliwością odczytu w trakcie zapisu (read while write) problem ten ominięto w ten sposób, że jedna brama służy tylko do zapisu, a druga - tylko do odczytu. Na rysunku 4.42 widać, że pamięci te mają dwa oddzielne dekodery adresu, które umożliwiają równoczesny zapis pod jednym adresem i odczyt spod drugiego. Jeżeli chcemy czytać i zapisywać na obu bramach pamięci dwubramowej, konflikt dostępów można rozwiązać w ogólny sposób tylko przez uniemożliwienie równoczesnego dostępu do pamięci. Można do tego zastosować normalną pamięć RAM, jak to pokazano na rys. 4.43, której linie adresowe, danych i sterujące są przyporządkowane wywołanej bramie za pomocą multipleksera. Rysunek 4.43. Pamięć dwubramowa z wykorzystaniem standardowej pamięci RAM W wielu przypadkach oba procesy można tak ze sobą zsynchronizować, że równoczesny dostęp do pamięci zostaje wykluczony. Jeżeli nie jest to możliwe, można zastosować dekoder priorytetowy, który w przypadku nakładania się dostępów do pamięci wstrzymuje przejściowo jeden z procesów sygnałem oczekiwania. Wybrane typy scalonych pamięci dwubramowych podane są w tablicy 4.15. Ich pojemność jest jednak ograniczona. Przy realizacji dużych pamięci dwubramowych celowe jest zastosowanie normalnych pamięci RAM i kontrolera pamięci dwubramowej. W tym wypadku szczególnie przydatny jest kontroler 74 LS 764 firmy Valvo, wspomagający pracę pamięci dynamicznych RAM jako pamięci dwubramowych. 45 Tablica 4.15. Przykłady pamięci dwubramowych (CMOS) 4.5.5. Pamięci RAM jako rejestr przesuwający Pamięci RAM mogą pracować jako rejestry przesuwające, jeśli adresy są przeliczane cyklicznie. Służy do tego licznik na rys. 4.44. Pod każdym adresem najpierw są wyprowadzane zapamiętane dane, a następnie wczytywane nowe dane. Przebiegi czasowe są przedstawione na rys. 4.45. Rysunek 4.44. Praca pamięci RAM jako rejestru przesuwającego Rysunek 4.45. Przebiegi czasowe w rejestrze przesuwającym z pamięcią RAM Stan licznika zwiększa się przy dodatnim zboczu impulsu zegara. Ponieważ sygnał CLK jest używany również jako sygnał R/W, zatem przy dodatnim zboczu impulsu zegarowego odbywa się odczytywanie zawartości pamięci, a przy ujemnym – zapamiętanie jej w przerzutniku wyjściowym. W czasie gdy sygnał zegarowy CLK = O do komórki pamięci, z której właśnie nastąpił odczyt, wpisuje się nowe dane. Minimalny okres impulsów zegarowych jest tu krótszy od sumy czasów cyklu odczytu i zapisu, ponieważ adres pozostaje stały. Okres ten jest równy czasowi zmodyfikowanego cyklu odczytu-zapisu (read modify write cycle time). Różnica w stosunku do normalnego rejestru przesuwającego polega na tym, że tu nie są przesuwane dane, ale tylko adresy, które stanowią wskaźniki dla nieruchomych danych. Korzyściami wynikającymi z tej metody są: możliwość stosowania normalnych pamięci RAM, które mają o wiele większe pojemności, niż konwencjonalne rejestry przesuwające, a dla częstotliwości zegara większej niż 64 kHz, możliwość stosowania pamięci dynamicznych RAM bez dodatkowych układów odświeżania. 46 4.5.6. Pamięci FIFO Pamięć FIFO jest odmianą rejestru przesuwającego. Podobnie jak w rejestrze, w pamięci FIFO dane ukazują się na wyjściu w tej samej kolejności, w jakiej zostały wprowadzone: słowo wpisane jako pierwsze (flrst in) zostaje również jako pierwsze wyprowadzone (first out). W przypadku pamięci FIFO proces ten - inaczej niż w rejestrze przesuwającym - może przebiegać w pełni asynchronicznie, to znaczy takt wyprowadzenia jest niezależny od taktu wprowadzenia. Dlatego też pamięci FIFO są używane do sprzęgania systemów asynchronicznych. Zasada działania pamięci FIFO jest podobna do tworzenia się kolejki: dane nie przesuwają się od wejścia do wyjścia w takt kolejnych impulsów zegarowych, lecz czekają w pamięci tak długo, aż wszystkie wprowadzone wcześniej dane zostaną wyprowadzone. Jest to schematycznie pokazane na rys. 4.46. Rysunek 4.46. Poglądowe przedstawienie zasady działania pamięci FIFO W pamięciach FIFO pierwszej generacji dane były rzeczywiście przesuwane przez łańcuch rejestrów zgodnie ze schematem pokazanym na rys. 4.46. Wprowadzane dane przechodzą do najniższego wolnego miejsca pamięci i stamtąd przesuwają się do wyjścia w takt impulsów wyprowadzających. Wadą tej metody jest duży czas przelotu (fall-trough time). Uwidacznia się on w szczególnie nieprzyjemny sposób w przypadku, gdy pamięć FIFO jest pusta, ponieważ wtedy dane, zanim pojawią się na wyjściu, muszą przejść przez wszystkie rejestry. Dlatego nawet małe pamięci FIFO mają czas przelotu rzędu wielu mikrosekund. Dalszymi wadami są rozbudowany układ logiczny i duża liczba operacji przesuwania, pozostająca w sprzeczności z oszczędną pod względem poboru prądu techniką CMOS. Dlatego też w pamięciach FIFO drugiej generacji nie przesuwa się już danych, a tylko dwa wskaźniki, podające adres wejścia lub wyjścia pamięci RAM. Widać to na rys. 4.47. Wskaźnik wejścia wskazuje pierwszy wolny adres AI, a adres wyjścia ostatni zajęty adres AO. Rysunek 4.47. Pamięć pierścieniowa FIFO 47 Rysunek 4.48. Realizacja pamięci FIFOz wykorzystaniem pamięci z odczytem podczas zapisu Przy wprowadzaniu i wyprowadzaniu danych oba wskaźniki zmieniają położenie. Odstęp obu wskaźników AI - AO podaje stan wypełnienia pamięci. Jeżeli mamy AI - AO = Amax, pamięć FIFO jest pełna. Nie można wtedy niczego wpisywać, gdyż nastąpiłoby skasowanie danych, które nie były jeszcze czytane. Jeżeli AI = AO pamięć FIFO jest pusta. Wtedy nie wolno czytać żadnych danych, gdyż grozi to przeczytaniem starych danych po raz drugi. Przepełnienia lub opróżnienia pamięci można uniknąć tylko wówczas, gdy średnie szybkości transmisji danych przy odczycie i zapisie są równe. W tym celu należy nadzorować wypełnienie pamięci i próbować tak wpływać na źródło i ujście danych, by pamięć była wypełniona w połowie. Pamięć FIFO może wtedy przejmować krótkotrwałe zamiany szybkości, jeżeli tylko ma wystarczająco dużą pojemność. Budowę pamięci FIFO przedstawia rys. 4.48. Jej struktura zbliżona jest do rejestru przes. wyk. pamięć RAM. Na pamięci nadają się tu szczególnie dobrze pamięci z możliwością odczytu podczas zapisu, ponieważ mają możliwość wpisywania i czytania asynchronicznego. Zgodnie z tą zasadą pracują nowsze pamięci FIFO. Przy realizacji dużych pamięci FIFO jest celowe wykorzystanie standardowych pamięci RAM, ponieważ osiąga się wtedy najwyższy stopień scalenia. W tym celu pamięć z odczytem podczas zapisu z rys. 4.48 zastępuje się pamięcią dwubramową zrealizowaną z wykorzystaniem standardowych pamięci RAM. Wynikający stąd układ jest przedstawiony na rys. 4.49. Rysunek 4.49. Relizacja pamięci FIFO z wykorzystaniem standardowych pamięci RAM Ponieważ w przypadku normalnej pamięci RAM nie można równocześnie prowadzić zapisu i odczytu, operacje te należy wykonać kolejno. Koordynację przejmuje arbiter wchodzący w skład układu sterowania. Jeżeli zapis ma być wykonany w czasie, gdy trwa jeszcze odczyt, najpierw kończy się cykl odczytu, a zapis zostaje opóźniony.Wykonywany jest zawsze ten cykl, który został wywołany wcześniej. Jeżeli takty zapisu i odczytu zbiegną się, arbiter podejmuje decyzję przypadkową. Wskutek możliwego czasu oczekiwania, w niekorzystnym przypadku czas dostępu może się podwoić. Układ sterujący potrzebny do pracy pamięci RAM jako FIFO jest dostępny w postaci układu scalonego zwanego kontrolerem RAM-FIFO. 48 Tablica 4.16. Przykłady pamięci FIFO 4.5.7. Pamięci stałe (ROM) Pamięci ROM to pamięci typu tablicowego, które normalnie są tylko odczytywane. Z tego też względu nadają się do pamiętania tablic i programów. Ich zaletą jest, że zawartość pamięci zostaje zachowana po odłączeniu napięcia zasilającego. Wadę pamięci ROM stanowi to, że wpisywanie tablicy jest znacznie bardziej pracochłonne niż w przypadku pamięci RAM. Odmiany pamięci ROM przedstawione na rys. 4.31 (MROM, PROM, EPROM, EEPROM) różnią się procedurą zapisu. 4.5.8. Pamięci ROM programowane maską W pamięciach ROM programowanych maską (MROM) zawartość pamięci zostaje określona przez producenta w ostatnim etapie produkcji za pomocą specjalnie do tego celu przygotowanej maski metalizacji. Metoda ta jest opłacalna jedynie przy długich seriach produkcyjnych (od ok. 10 000 sztuk), a wykonanie układu scalonego trwa przeważnie kilka miesięcy. 4.5.9. Pamięci programowane w sposób trwały (PROM) Skrót PROM (programmable ROM) oznacza pamięć, której zawartość jest programowana przez użytkownika. Elementami umożliwiającymi programowanie takich pamięci są bezpieczniki, realizowane w układach scalonych w postaci bardzo cienkich, metalizowanych mostków. Oprócz tego są stosowane również diody, które po przeciążeniu w kierunku zaporowym przechodzą w stan zwarcia. Najnowszymi elementami umożliwiającymi programowanie pamięci PROM są specjalne tranzystory MOS, mające dodatkową, izolowaną (tzw. swobodną) bramkę (floating gate). W procesie programowania pojemność tej bramki zostaje naładowana, co powoduje przesunięcie napięcia progowego tranzystora MOS. Ze względu na fakt, że swobodna bramka jest ze wszystkich stron izolowana za pomocą warstwy SiO2, można zagwarantować 10-letni czas zachowania ładunku. 49 4.5.9. Pamięci stałe - PROM Budowę wewnętrzną pamięci PROM omówimy na przykładzie z rys. 4.50. Ze względów technologicznych poszczególne komórki pamięci nie są ułożone liniowo, lecz stanowią kwadratową matrycę. Adresowanie określonej komórki pamięci odbywa się przez podanie logicznej jedynki na odpowiednią linię wiersza i kolumny. Rysunek 4.50. Budowa wewnętrzna pamięci PROM. Przykład pamięci 16 bitów W tym celu należy odpowiednio zdekodować wektor adresu A — (a0...an) podany z zewnątrz. Do tego służą dekodery kolumn i wierszy. Pracują one jako dekodery l z n.Wybrana komórka pamięci jest aktywowana przez bramkę AND w punkcie przecięcia wybranych linii kolumn i wierszy. Sygnał wyjściowy D otrzymuje się jako sumę logiczną (OR) wyjść wszystkich komórek pamięci. Aby uniknąć użycia bramki o 2n wejściach, stosuje się sumę galwaniczną (wired OR). W przypadku wyjść z otwartym kolektorem można ją zrealizować poprzez iloczyn galwaniczny (wired AND) zanegowanych sygnałów. W stanie pierwotnym każda zaadresowana komórka pamięci daje sygnał wyjściowy D=1. W celu zaprogramowania zera przepala się bezpiecznik na wyjściu żądanej komórki. W tym celu wybiera się adres odpowiedniej komórki i tym samym powoduje przewodzenie tranzystora wyjściowego bramki NAND. Następnie wymusza się w linii odczytu silny impuls prądowy, który jest tak duży, że powoduje przepalenie bezpiecznika na wyjściu bramki NAND. Należy przy tym dokładnie przestrzegać podanego przez producenta kształtu impulsu. Dlatego też do tego celu używa się specjalnych programatorów, które można dopasować do różnych typów pamięci. W pamięci PROM pod jednym adresem jest pamiętany z reguły nie jeden bit, ale całe słowo 4- lub 8-bitowe. Dlatego pamięci te mają odpowiednią liczbę wyjść danych. Pojemność pamięci np. l k x 8 bitów oznacza, że pamięć zawiera 1024 słowa 8-bitowe. Zawartość pamięci podaje się w postaci tablicy programu. Na rysunku 4.51 podano przykładowo tablicę dla pamięci PROM 32 x 8 bitów. Symbol graficzny pamięci PROM odpowiada symbolowi pamięci RAM z tą różnicą, że wejście przełączające z zapisu na odczyt jest tu wejściem programującym. W tablicy 4.17 zebrano kilka najczęściej używanych typów pamięci PROM wykonanych w różnych technologiach. 50 Wejścia Wyjścia A4 A3 A2 A1 A0 D7 D6 D5 D4 D3 D2 D1 D0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 1 1 ... ... 1 1 1 1 0 1 1 1 1 1 ... ... Rysunek 4.51. Przykład pamięci PROM o pojemności 32 słowa 8 bitowe Tablica 4.17. Przykłady pamięci PROM 4.5.10. Pamięci stałe kasowane promieniami UV - EPROM Nazwa EPROM (erasable PROM) oznacza pamięć stałą, którą użytkownik może nie tylko zaprogramować, lecz także może skasować jej zawartość światłem ultrafioletowym. Elementami pamiętającymi są wyłącznie tranzystory MOS z dodatkową izolowaną bramką (floating gate). Przy programowaniu ładuje się bramkę (tak jak w przypadku niektórych pamięci PROM) i wskutek tego przesuwa napięcie progowe tranzystora MOS. W przypadku pamięci EPROM istnieje dodatkowa możliwość skasowania jej zawartości przez naświetlanie promieniowaniem ultrafioletowym w ciągu ok. 20 min. Aby to umożliwić, w obudowie nad strukturą znajduje się okienko wykonane ze szkła kwarcowego. 51 Ze względu na dość skomplikowaną konstrukcję obudowy, pamięci EPROM są droższe od wykonanych tą samą technologią pamięci PROM bez okna. Z tego też względu przy projektowaniu urządzeń stosowanie pamięci EPROM jest uzasadnione, ale przy produkcji seryjnej należy przejść na elementy PROM. Pamięci EPROM programuje się słowami, więc przy typowej organizacji 8bitowej bajtami. W starszych typach pamięci (np. 2716, 2k x 8 bitów) programowanie było stosunkowo proste. Należało tylko doprowadzić napięcie programujące UPP = 25 V, żądany adres i wzór bitów, a potem podać polecenie programowania o czasie trwania 50 ms. Na tym programowanie można było zakończyć, lub też powtórzyć operację pod innym adresem i z nowym wzorem bitów. Programowanie całej pamięci EPROM o pojemności 2 kilobajtów trwało więc ok. 2 minut. Programowanie pamięci 128 kB musiałoby więc zająć prawie 2 godziny. Ponieważ tej niedogodności nie można uniknąć, dla większych pamięci EPROM należało zmodyfikować technologię produkcji i algorytmy programowania. U podstaw wszystkich szybkich algorytmów programowania leży spostrzeżenie, że większość bajtów pamięci EPROM daje się zaprogramować w czasie znacznie krótszym niż 50 ms. Ponieważ jednak istnieją także „wolne" bajty, czasu programowania nie daje się generalnie skrócić. Stosuje się przy tym raczej zmienny czas trwania impulsów programujących. Stosowany obecnie „szybki" lub „inteligentny" algorytm programowania przedstawiono na rys. 4.52. Najpierw podaje się napięcie programujące Upp = 12,5 V i podwyższa napięcia zasilania do Ucc = 6 V. Wyższe napięcie zasilania z jednej strony przyśpiesza proces programowania, bo tranzystory mają wówczas mniejszą rezystancję, a z drugiej strony stwarza możliwość weryfikacji układu w warunkach „najgorszego przypadku" (worst case). Potem podaje się adres A = O i odpowiednie dane. Teraz następuje procedura programowania danego bajtu. W tym celu zeruje się pomocniczy licznik (n = 0) i podaje polecenie programowania o czasie trwania l ms. Po zwiększeniu stanu licznika odczytuje się zawartość pamięci, aby sprawdzić czy programowanie zakończyło się sukcesem. Jeżeli nie, podaje się następne rozkazy programowania, aż do 24. Jeżeli nawet wtedy dany bajt nie zostanie zaprogramowany, program uznaje, że element pamięci jest uszkodzony. Normalnie potrzeba tylko kilka impulsów programujących. Nie jest wtedy jednak pewne, czy do izolowanej bramki został wprowadzony wystarczająco duży ładunek, który utrzyma się przez następne 10 lat. Aby to zapewnić, operację ładowania wykonuje się jeszcze trzykrotnie. Do tego celu służy operacja „doprogramowywania" o czasie trwania 3n * lms. W ten sposób został zaprogramowany pierwszy bajt i procedurę można powtórzyć pod następnym adresem, z nowymi danymi. Na końcu programowania następuje przełączenie do trybu czytania i jeszcze jedna weryfikacja całej zawartości pamięci. Dzięki zastosowaniu szybkiego algorytmu programowania czas programowania pamięci EPROM o pojemności l Mb skraca się z ok. 2 godzin do poniżej 10 minut. Przez zmniejszenie czasu trwania impulsu programującego do 100 us można w przypadku niektórych pamięci EPROM osiągnąć nawet czasy poniżej l minuty. 52 Rysunek 4.52. Szybki algorytm programowania pamięci EPROM W tablicy 4.18 podano zestawienie częściej używanych typów pamięci EPROM. Tablica 4.18. Przykłady pamięci EPROM 53 4.5.11. Pamięci stałe kasowane elektrycznie - EEPROM Nazwa EEPROM (electrically erasable PROM) oznacza pamięć PROM, której zawartość -w przeciwieństwie do pamięci EPROM -można kasować elektrycnie. W nowszych typach takich pamięci w strukturze układu scalona jest także przetwornica (konwerter) wytwarzająca napięcie programujące i układ czasowy (timer) do ustalania długości impulsu programującego. W celu zaprogramowania bajtu wystarczy tylko podać adres i dane. Jeżeli podamy potem polecenie zapisu i zainicjujemy operację programowania, EEPROM zapamiętuje wewnętrznie adres i dane, po czym natychmiast zwalnia linie adresowe i linie danych. Dalszy ciąg operacji programowania przebiega autonomicznie w strukturze układu scalonego. Najpierw jest kasowany stary bajt, a następnie programowany nowy. Operacja ta jest wewnętrznie nadzorowana w celu zapewnienia, że zaprogramowany ładunek jest wystarczająco duży. Czas trwania programowania wynosi l... 10 ms, a więc jest tego samego rzędu, jak w pamięciach EPROM. W niektórych pamięciach EEPROM w jednej operacji programowania można zapisać nie tylko pojedynczy bajt, lecz całą „stronę" mieszczącą 16... 64 bajty. W tym celu należy wpisać programowaną stronę do wewnętrznej pamięci RAM i podać polecenie programowania. W ten sposób osiąga się efektywny czas programowania jednego bajtu równy 30 us. Ta prostota operacji wpisywania i kasowania nie daje jednak możliwości wykorzystywania pamięci EEPROM jako pamięci RAM, ponieważ liczba cykli zapisu jest ograniczona. Jednego bajtu nie wolno zapisać więcej niż l04... 106 razy (w zależności od typu układu scalonego). Przy czasie programowania równym l ms już po 10 s można osiągnąć granicę trwałości bajtu lub strony, jeżeli programowanie odbywałoby się w sposób ciągły. Z tego powodu w niektórych typach układów łączy się pamięci EEPROM i RAM. Zawartość pamięci przenosi się do pamięci EEPROM tylko w przypadku zaniku napięcia zasilania. Dzięki temu przy normalnej pracy osiąga się krótki cykl zapisu, nie związany ze zjawiskami zużywania się pamięci. Rozwiązanie pośrednie między pamięciami EPROM a EEPROM stanowią pamięci EEPROM kasowane równolegle (Flash). Można je kasować elektrycznie tak, jak pamięci EEPROM, ale nie bajt po bajcie, lecz całą pamięć za jednym razem. Stąd też wzięła się nazwa tych układów: EEPROM typu „flash". Ich kasowanie jest o wiele prostsze niż pamięci EPROM; wymaga podania tylko jednego impulsu kasującego trwającego kilka sekund. Nie ma więc potrzeby wyjmowania elementu z układu i wkładania go na ok. 20 minut do kasownika. Technologia produkcji tych elementów nie jest wcale bardziej złożona od technologii elementów EPROM i umożliwia uzyskanie odpowiednio dużych gęstości upakowania, a także niskiej ceny. Aby niepotrzebnie nie podrażać produkcji, w pamięciach EEPROM typu „flash" z rodziny 28 rezygnuje się z przetwornicy (konwertera) napięcia programującego i układu czasowego (timera) do ustalania długości impulsu programującego, występujących w typowych pamięciach EEPROM. Dlatego też programuje si je tak samo, jak pamięci EPROM. Porównanie różnych odmian pamięci ROM z pamięciami RAM pod kątem możliwości zapisu i odczytu jest przedstawione w tablicy 4.19. Tablica 4.19. Porównanie pamięci RAM i ROM pod względem możliwości zapisu i odczytu 54 Widoczna jest wyższość pamięci RAM pod względem szybkości zapisu i odczytu, przy czym operacje zapisu i odczytu mogą być powtarzane dowolnie często. W przypadku wszystkich odmian pamięci ROM istnieje mniej lub więcej ograniczeń związanych z zapisem. Za to wszystkie pamięci ROM zachowują swoją zawartość bez konieczności zasilania. W przypadku pamięci RAM własność tę można uzyskać dołączając do układu baterię podtrzymującą. Pobór prądu wielu pamięci RAM CMOS - jak to widać w tablicy 4.12 – jest mniejszy niż samowyładowanie baterii. Dlatego też i tutaj w przypadku zastosowania odpowiednich baterii można zagwarantować 10-letni okres zachowania danych. Tablica 4.20. Przykłady pamięci EEPROM 4.5.12. Pamięć błyskowa - FLASH Pamięć błyskowa (FLASH) jest również pamięcią programowaną i kasowaną elektrycznie. Koszt jej produkcji jest niższy niż układu EEPROM. W porównaniu z pamięcią EEPROM cechuje się ona szybszymi czasami programowania i kasowania. Najczęściej pamięć ta składa się z sektorów, na których mogą być wykonywane odpowiednie operacje, posiada własną listę komend automatyzujących programowanie i kasowanie pamięci. Szczególną zaletą pamięci błyskowych (FLASH) w stosunku do pamięci EEPROM jest krótki czas kasowania i zapisu. Do programowania i kasowania pamięci błyskowych potrzebne jest podwyższone napięcie 11,5 - 13,5V, które w zależności od typu układu może być podawane z zewnątrz lub wytwarzane przez wbudowaną przetwornicę. Pamięci FLASH przyjmują oprócz danych polecenia, które umożliwiają realizację różnych rodzajów operacji. Ten typ pamięci zostanie przedstawiony na przykładzie popularnej pamięci typu 29F010 firmy AMD (Advanced Micro 55 Devices) o organizacji 128k x 8 bitów. Na rys. 4.53 pokazano symbol logiczny pamięci wraz z opisem linii. Rysunek 4.53. Symbol logiczny pamięci Am29F010 Pamięć Am29F010 jest 1Mbit, 5V pamięcią FLASH zorganizowaną jako 131072 bajtów. Produkowana jest w 32-pinowych obudowach typu PLCC ,TSOP i PDIP. Zaprojektowano ją z możliwością programowania w systemie ze standardowym 5V zasilaniem. Ponadto może być programowana za pomocą standardowego programatora do pamięci EPROM. Pamięć ta posiada następujące właściwości: − pojedyncze zasilanie, 5V +-10% dla czytania, zapisu i operacji kasowania programu, − maksymalny czas dostępu 45ns, − niskie zużycie energii, maksymalnie 30mA na odczyt i 50mA na programowanie oraz czyszczenie, mniej niż 25µA podczas trybu standby, − elastyczna architektura oparta na sektorach, 8 zunifikowanych sektorów, wszystkie kombinacje sektorów mogą być czyszczone, − możliwość wymazania całego chipu, − ochrona sektorów przed zapisem, − wsparcie sprzętowe dla zablokowania i odblokowania programowania i czyszczenia dla wszystkich kombinacji sektorów, − wbudowany algorytm czyszczenia automatycznie przeprogramuje i czyści chip lub wszystkie kombinacje wybranych sektorów, − wbudowany algorytm programowania automatycznie programujący i sprawdzający dane z zadanego adresu, − minimum 100000 gwarantowanych cykli programowania i czyszczenia, − programowe metody detekcji końca cyklu programowania i czyszczenia. Pamięć posiada wbudowany algorytm programowania (wewnętrzny algorytm, który automatycznie weryfikuje szerokość i czas trwania impulsów programowania). Zawiera ona także wbudowany algorytm czyszczenia. Podczas czyszczenia urządzenie automatycznie kontroluje czas i szerokość sygnałów oraz weryfikuje właściwe komórki docelowe. System nadrzędny może wykrywać zakończenia operacji czyszczenia/programowania poprzez czytanie bitów statusu: DQ7 (DATA#Polling) i DQ6 (toggle). Po zakończeniu cyklu programowania/czyszczenia pamięć jest gotowa do czytania z niej danych lub oczekuje na następną komendę. Sektorowa architektura pamięci pozwala na czyszczenie, czy ponowne programowanie wybranych sektorów pamięci bez wpływu na pozostałe sektory. Sprzętowa ochrona danych wykrywa niski poziom napięcia zasilania i wstrzymuje proces zapisywania podczas zmiany napięcia. Pamięć można przełączyć w tryb standby, w celu znacznej redukcji pobieranej mocy. Na rys. 4.54 przedstawiono schemat blokowy pamięci Am29F010. 56 Rysunek 4.54. Schemat blokowy pamięci Am29F010 Jak widać, składa się ona z wielu bloków, z których część służy do obsługi procesu zapisu do pamięci (blok Cell Matrix), są nimi generatory napięć PGM Voltage Generator i Erase Voltage Generator. Pracą całego układu zarządza blok State Control / Command Register. Komórki pamięci są wybierane za pomocą układu dekodera adresu. Sterowanie przepływem danych odbywa się za pośrednictwem dwukierunkowego bufora i rejestru zatrzaskującego oraz bloku Chip Enable / Output Enable Logic. Rejestr komend (Command Register) składa się z zatrzasków, które przechowują komendy z adresami i danymi potrzebnymi do wykonania komendy. Zawartość rejestru służy jako wejścia dla „wewnętrznej maszyny stanu”. Wyjścia maszyny stanu dyktują funkcje urządzenia. Funkcje te (operacje na szynie danych) wykonywane przez układ sterownia pamięci Flash przedstawiono w tablicy 4.21. Tablica 4.21. Operacje na szynie danych pamięci Am29F010 Aby odczytać dane z pamięci system musi zapewnić niski stan linii CE# i OE#. Linia CE# kontroluje odczyt. Linia OE# steruje buforem wyjściowym. Sygnał na linii WE# powinien być na poziomie VIH. Żadna komenda nie jest wymagana w tym trybie. Jest on trybem domyślnym po włączeniu napięcia zasilania. Zatem mk może podawać na linie adresowe A0 – A16 adresy danych, które chce otrzymać na liniach danych DQ0 – DQ7. Urządzenie pozostaje dostępne do odczytu dopóki nie zmieni się zawartość rejestru komend. Aby zapisać komendę lub sekwencję komend (które zawierają dane programujące czy czyszczące wybrane sektory pamięci), system musi zapewnić następujące stany: na liniach WE# i CE# stan niski VIL oraz na linii OE# stan wysoki VIH. Operacja czyszczenia może skasować jeden sektor, wiele sektorów lub całe urządzenie. 57 Tablica adresów sektorów wskazuje na adres w przestrzeni jaką każdy sektor zajmuje. „Adres sektora” to bity adresu potrzebne aby jednoznacznie zidentyfikować sektor (patrz tablica 4.22). Tablica 4.22. Tablica adresów sektorów pamięci Am29F010 Podczas operacji czyszczenia lub programowania system może sprawdzić status operacji przez czytanie bitów statusu DQ7-DQ0. Pamięć posiada tryb autoselect, który umożliwia identyfikację urządzenia oraz producenta, a także weryfikację chronionych sektorów przez kody identyfikacyjne podane na DQ7-DQ0. Ten tryb jest niezbędny dla urządzeń programujących, aby mogły wykorzystać odpowiedni algorytm programujący. Ten tryb może być także wykorzystany w systemie przez rejestr komend. Pamięć można wprowadzić w tryb autoselect wydając odpowiednią komendę (tablica 4.23). Zapis adresu i danej rozkazu lub całej sekwencji rozkazowej do rejestru rozkazów inicjuje wykonanie operacji. Poprawne sekwencje rozkazowe przedstawia tabela rozkazów (tablica 4.23). Tablica 4.23. Formaty poleceń sterowania pamięcią Am29F010 Zapis niepoprawnych wartości adresu i danych lub zapis sekwencji w nieodpowiedniej kolejności przestawia pamięć w tryb odczytu danych. Adres jest "zatrzaskiwany" w momencie pojawienia się opadającego zbocza na linii WE# lub CE#, w zależności od tego, które z tych zdarzeń wystąpi jako ostatnie. 58 Rozkaz AUTOSELECT umożliwia uzyskanie dostępu do kodów producenta i pamięci, a także pozwala na ustalenie, czy dany sektor jest chroniony. Na sekwencję rozkazową składa się rozkaz AUTOSELECT poprzedzony zapisem 2 cykli odblokowujących. Następnie pamięć wchodzi w tryb autoselect i możliwy jest odczyt spod każdego adresu dowolną ilość razy bez inicjowania kolejnej sekwencji rozkazowej. Cykl odczytu spod adresu XX00h zwraca kod producenta, a spod adresu XX01h kod urządzenia. Cykl odczytu zawierający adres sektora (SA) i adres 02h zwraca 01h jeśli ten sektor jest chroniony, a 00h w przeciwnym wypadku. W celu wyjścia z trybu autoselect do pamięci trzeba przesłać rozkaz RESET. Programowanie pamięci składa się z 4 cykli szyny (rozkaz PROGARM). Na sekwencję rozkazową składa się rozkaz ustawiający tryb programowania poprzedzony zapisem 2 cykli odblokowujących. Dane i adres są wysyłane w następnej kolejności. Operacja ta inicjuje wykonanie wbudowanego algorytmu programowania. System programujący nie musi dostarczać dodatkowych sygnałów sterujących czy t aktujących. Urządzenie samo generuje wewnętrzne impulsy programujące i weryfikuje poprawność zaprogramowania komórki. Kiedy wbudowany algorytm programowania zakończy działanie urządzenie wraca do trybu odczytu danych i zwalniany jest przerzutnik "zatrzaskujący" adresy. System nadrzędny może ustalić status operacji programowania na podstawie stanu linii DQ6 i DQ7. Wszystkie rozkazy wysyłane do urządzenia podczas wykonywania wbudowanego algorytmu programowania są ignorowane. Programowanie może odbywać się w dowolnej kolejności i może przekraczać granice sektorów. Sekwencja kasowania pamięci składa się 6 cykli szyny. W jej skład wchodzi rozkaz ustawienia (set-up) poprzedzony zapisem 2 cykli odblokowujących. Po nich następują kolejne 2 cykle odblokowujące zapis i rozkaz kasowania, który uruchamia wbudowany algorytm kasowania. Wszystkie rozkazy wysyłane do urządzenia podczas wykonywania wbudowany algorytm kasowania są ignorowane. Kiedy ten algorytm zakończy działanie urządzenie wraca do trybu odczytu danych i zwalniany jest przerzutnik "zatrzaskujący" adresy. Na rozkaz kasowanie sektora również składa się 6 cykli szyny. Pierwszym jest rozkaz ustawienia (set-up) poprzedzony zapisem 2 cykli odblokowujących. W następnej kolejności wysyłane są 2 dodatkowe cykle odblokowujące. Potem zapisywane są: adres sektora do kasowania oraz rozkaz kasowania. Po zapisie sekwencji rozkazowej rozpoczyna się 50µs przerwy. W trakcie tej przerwy mogą zostać przesłane dodatkowe adresy i rozkazy kasowania sektorów. Załadowanie bufora kasowania sektorów może się odbyć w dowolnej kolejności. Dowolna może być także liczba sektorów przeznaczonych do skasowania. Odstęp czasu między tymi dodatkowymi cyklami, w których przesyłane są informacje o dodatkowych sektorach do skasowania musi być mniejszy niż 50µs. Jakikolwiek rozkaz wysłany podczas 50µs przerwy przestawia urządzenie w tryb odczytu. System musi ponownie wysłać sekwencje rozkazową oraz adresy dodatkowych sektorów i rozkazy. System może nadzorować stan linii DQ3 w celu sprawdzenia, czy minął czas przerwy. Przerwa zaczyna się od narastającego zbocza ostatniego impulsu w sekwencji rozkazowej na linii WE#. Wszystkie rozkazy wysyłane do urządzenia podczas kasowania sektora są ignorowane. Kiedy wbudowany algorytm kasowania zakończy działanie urządzenie wraca do trybu odczytu danych i zwalniany jest przerzutnik "zatrzaskujący" adresy. System nadrzędny może ustalić status operacji programowania przy wykorzystaniu linii DQ6 i DQ7. Stan operacji zapisu można sprawdzić wykorzystując linie: DQ3, DQ5, DQ6 i DQ7. Za pomocą pinów DQ7 i DQ6 można sprawdzić, czy operacja programowania lub kasowania została zakończona (tablica 4.24). 59 Tablica 4.24. Status operacji zapisu Na poniższym rysunku pokazano przebiegi czasowe operacji odczytu danej z pamięci. Rysunek 4.55. Przebieg czasowy operacji odczytu z pamięci Am29F010 Na poniższym rysunku pokazano przebiegi czasowe operacji zapisu danej do pamięci. Rysunek 4.56. Przebieg czasowy operacji programowania pamięci Am29F010 Na poniższym rysunku pokazano przebiegi czasowe operacji kasowania pamięci. 60 Rysunek 4.57. Przebieg czasowy operacji kasowania pamięci Am29F010 4.5.13. Układy logiki programowalnej – PLD Układy logiki programowalnej (programmable logic demces, PLD) służą do pamiętania funkcji logicznych. Znane są trzy rodzaje takich układów: PLA, PAL i LCA. Różnią się one możliwościami programowania. Najprościej programuje się układy PAL (programmable array logie), dlatego cieszą się one dużą popularnością i występują w wielu odmianach. Programowalne matryce logiczne PLA (programmable logie array) są bardziej uniwersalne, ale ich programowanie jest bardziej skomplikowane, dlatego nie odgrywają obecnie większej roli. Nowymi elementami są układy LCA (logie celi array), które umożliwiają programowanie nie tylko funkcji logicznych, lecz także pól połączeń między różnymi blokami logicznymi. Dzięki temu mogą one zastępować zwykłe matryce bramek i można je nazwać matrycami logicznymi programowalnymi przez użytkownika. a b c d a b 1 d & a*b*d & Vcc a b 0 d > 1 a b c d a*b*d a b c d a+b+d & a*b*d a b c d > 1 a+b+d > 1 a+b+d Rysunek 4.58. Uproszczony sposób przedstawiania funkcji AND i OR. Jeśli przy realizacji funkcji logicznej skorzystamy z normalnej postaci sumy, musimy najpierw utworzyć wymagane iloczyny logiczne zmiennych wejściowych, a potem sumy logiczne tych iloczynów. Aby przedstawić układ w sposób przejrzysty, stosuje się skrócony zapis pokazany na rys. 4.58. (Krzyżyki wskazują, które z wyjść są dołączone. Wejście nie dołączone nie ma wpływu na stan układu, gdyż w przypadku funkcji AND jest równoważne stanowi 1, a w przypadku funkcji OR stanowi 0.) 61 Zmienne wejściowe i ich negacje wraz z krzyżującymi się z nimi wejściami bramek AND tworzą matrycę, w której można zaprogramować wszystkie potrzebne iloczyny. Aby otrzymać potrzebne sumy logiczne, w odpowiedniej drugiej matrycy można zrealizować połączenia między wyjściami bramek AND i bramkami OR. Na jedną zmienną wyjściową jest potrzebna przy tym tylko jedna bramka OR. W przypadku układów PLA (rys. 4.59 u góry) użytkownik ma możliwość programowania obu matryc. W układzie PAL (rys. 4.59 u dołu) matryca OR jest narzucona przez producenta; tutaj można programować tylko matrycę AND. Rysunek 4.59. Układ PLD Rysunek 4.60. Układ PLD Za pamięć funkcyjną można również uważać pamięć PROM. Jeżeli dekoder adresu interpretuje się jako matrycę iloczynów logicznych (AND), uzyskuje się wówczas układ pokazany na rys. 4.60. Dla każdego adresu tylko jeden iloczyn logiczny ma wartość “jeden", i to właśnie ten, który odpowiada podanemu adresowi. Mamy tu więc n = 2N iloczynów logicznych, podczas gdy układy PLA i PAL mają ich znacznie mniej. To, czy przynależna wartość funkcji jest równa l czy 0, ustala się przez 62 zaprogramowanie matrycy OR. Pamięci PROM przewidziane do realizacji funkcji logicznych są oznaczane skrótem PLE (programmable logie element). Różnice między tymi elementami wyjaśnimy na przykładzie funkcji logicznych z rys. 4.61. W tym celu usuniemy wszystkie połączenia, które dla rozważanych funkcji nie są potrzebne. Rysunek 4.61. Przykład tablicy prawdy, jej funkcje i ich realizacja za pomocą układów PLA, PAL i PROM Nietrudno zauważyć, że zawartość pamięci PROM stanowi odwzorowanie tablicy prawdy, podczas gdy układy PLA i PAL reprezentują funkcje logiczne. W pamięci PROM można zapamiętać dowolną tablicę prawdy, podczas gdy w układzie PLA lub PAL dysponujemy tylko ograniczoną ilością iloczynów i sum logicznych. Z tego też względu nie mamy tu możliwości realizacji dowolnych tablic prawdy, lecz tylko te, które prowadzą do prostych funkcji logicznych. Aby efektywnie wykorzystać układy PAL, musimy maksymalnie uprościć funkcje logiczne, korzystając z algebry Boole'a, a w razie potrzeby za pomocą prawa de Morgana przekształcić iloczyny na sumy logiczne. Dzisiaj nie robi się już tego ręcznie, lecz korzysta ze specjalnych programów wspomagających projektowanie, pracujących na każdym komputerze osobistym. Układy PAL Układy PAL (programmable array logie) są najważniejszym przedstawicielem rodziny układów logiki programowalnej (PLD). Dostępne są w wielu różnych odmianach, ale wszystkie oparte na zasadzie pokazanej na rys. 4.58. Różnice polegają na odmiennych wykonaniach sum logicznych na wyjściu. Najczęściej używane układy PAL są przedstawione na rys. 4.62. Typ H (z wyjściem prostym - high, H) to typ podstawowy. Typ L ma wyjście zanegowane (Iow, L). Typ S (sharing) ma strukturę zbliżoną do układu PLA. Ma możliwość częściowego programowania matrycy OR: dwie sąsiadujące ze sobą sumy logiczne można w dowolny sposób łączyć z wyjściami współpracujących iloczynów. Dzięki temu można tworzyć funkcje, dla których w innym przypadku zabrakło by sum logicznych. W wielu układach PAL wyjście można wykorzystać również jako wejście lub też zaprogramować końcówkę dwukierunkową (WE/WY). 63 Rysunek 4.62. Układy wyjściowe struktur PAL Do tego celu służy bramka trójstanowa na wyjściu, której samo wejście zezwolenia (enable) stanowi już funkcję logiczną. Ważną dziedziną zastosowań elementów PAL są układy sekwencyjne. Aby nie były potrzebne żadne dodatkowe elementy, w strukturze PAL scala się również rejestry (R). Rejestry te mają wspólne wyprowadzenie wejść zegarowych, umożliwiające budowę synchronicznych układów sekwencyjnych. Sygnały wyjściowe są przeważnie podawane wewnątrz układu z powrotem do matrycy AND, dzięki czemu zaoszczędza się na zewnętrznych liniach sprzęgających i niepotrzebnie nie zajmuje wejść. Jeżeli do każdego zastosowania chcielibyśmy użyć optymalnego układu PAL, potrzebowalibyśmy - jak widać na rys. 4.62wielu różnorodnych typów. Aby zredukować liczbę typów, na rynek wprowadza się coraz więcej układów PAL z programowalną strukturą wyjść. Tego rodzaju makrokomórka V (variable) jest przedstawiona na rys. 4.62. Jej jądrem jest multiplekser, umożliwiający wybór jednego z czterech trybów pracy. Wyboru dokonuje się przez zaprogramowanie bitów konfiguracyjnych f0 f1. W tablicy 4.25 zestawiono tryby pracy układu. Tablica 4.25. Tryby pracy programowalnej makrokomórki 64 Bit f0 określa, czy wyjście ma być proste, czy zanegowane. Bit f1 przełącza układ z pracy asynchronicznej na synchroniczną i odwrotnie. Równocześnie drugi multiplekser przełącza sprzężenie z wyjścia na rejestr. Widać stąd, że za pomocą tego jednego typu można zrealizować funkcje większości układów PAL. Układy logiczne CPLD na przykładzie rodziny układów XC9500 firmy Xilinx Układy logiczne CPLD zostaną przedstawione na przykładzie rodziny układów XC9500 firmy Xilinx. Są one programowalne i testowalne w docelowym mse. Rodzina ta charakteryzuje się następującymi właściwościami: − duża szybkość działania (5ns opóźnienia pomiędzy pinami, fCNT do 125 MHz), − duża gęstość upakowania (od 36 do 288 makrokomórek z 800 do 6,400 użytecznymi bramkami), − układy programowalne w systemie o napięciu zasilania 5V (możliwość wykonania 10000 cykli programowania/kasowania), − układy składają się z „elastycznych” bloków funkcyjnych (odpowiadających układom GAL typu 36V18), 90 linii product terms sterujących pojedynczymi lub wszystkimi 18 makrokomórkami wewnątrz bloku funkcyjnego, − posiadają interfejs standardu IEEE 1149.1 (JTAG), − zapewniają programowalny tryb redukcji mocy dla każdej komórki, − wyjścia układów przewodzą prąd do 24mA, − piny wejściowo-wyjściowe mogą być ustawione na standard 3,3V lub 5V. Tablica 4.26. Rodzina układów XC9500 Rysunek 4.63. Architektura układów rodziny XC9500 65 Na potrzeby programowania i testowania układów w systemie rozszerzono listę instrukcji sterujących interfejsem JTAG. Zatem interfejs ten pozwala nie tylko na testowanie zgodnie ze standardem IEEE 1149.1, ale również i programowanie układów zamontowanych już w systemie. Możliwość przeprowadzania wielokrotnej liczby cykli programowania/kasowania zapewnia dużą swobodę w zmienianiu wewnętrznej konfiguracji układów, czy uaktualnianiu zawartych w nich projektów. Dodatkowo zapewniono kontrolę szybkości narastania napięć wyjściowych oraz umożliwiono programowe uziemienie pinów w celu lepszej redukcji szumów. Urządzenia wejścia/wyjścia mogą być konfigurowane dla napięć 3,3V oraz 5V. Wszystkie wyjścia przewodzą prąd do 24mA. Każdy układ XC9500 jest podsystemem zawierającym bloki funkcyjne (FB – Function Block) i bloki wejścia/wyjścia (IOB – I/O Block), które są łączone między sobą za pomocą matrycy przełączającej (FastCONNECT switch matrix) (rys. 4.63). Bloki IOB buforują sygnały wejściowe i wyjściowe z układu oraz zapewniają odpowiednie parametry elektryczne zacisków. Każdy blok funkcyjny FB daje możliwość zaprogramowania 36 wejść i 18 wyjść. Matryca przełączająca łączy wszystkie wyjścia bloku FB z wejściami innego bloku FB. Dla każdego bloku FB wyjścia w liczbie od 12 do 18 (w zależności od liczby wyprowadzeń obudowy) skojarzone z sygnałami output enable sterują bezpośrednio blokami IOB. Każdy blok funkcyjny, jak przedstawiono na rys. 4.64, składa się z 18 niezależnych makrokomórek, z których każda może realizować funkcję kombinacyjną bądź rejestrową. Do bloku funkcyjnego doprowadzony jest sygnał zegara oraz sygnały set/reset. Blok funkcyjny poprzez generację stanów na 18 wyjściach steruje matrycą przełączającą. Wyjścia te wraz z sygnałami output enable sterują blokami IOB. Rysunek 4.64. Blok funkcyjny (FB) układów rodziny XC9500 Do programowalnej matrycy iloczynów logicznych dochodzą 72 sygnały (36 normalnych sygnałów i 36 ich negacji). Sygnały te są przez nią łączone do 90 linii product term dochodzących do 18 makrokomórek. Dla każdego bloku FB możliwe jest zrealizowanie połączeń (ścieżek) z wyjść makrokomórek do matrycy iloczynów logicznych, bez potrzeby wyprowadzania ich poza dany blok FB. Ścieżki te wykorzystywane są do tworzenia bardzo szybkich liczników oraz układów stanów, gdzie wszystkie rejestry stanu są wewnątrz tego samego bloku FB. Każda makrokomórka w bloku FB układu XC9500 może być indywidualnie skonfigurowana tak, aby realizować funkcje kombinacyjne lub rejestrowe. Rys. 4.65 przedstawia makrokomórkę i towarzysząca jej strukturę logiczną bloku FB. Pięciu linii product terms bezpośrednio wyprowadzonych z matrycy iloczynów logicznych można użyć jako podstawowych wejść danych (do bramek OR i XOR). Pozwalają one na implementację funkcji kombinacyjnej lub mogą posłużyć jako wejścia sterujące włączając w to sygnały zegara, set/reset i 66 output enable. Blok PTA (Product Term Allocator), zawarty w każdej makrokomórce, służy do wyboru sposobu użycia tych pięciu linii. Rysunek 4.65. Makrokomórka bloku FB układów XC9500 Rejestr makrokomórki może być skonfigurowany jako przerzutnik D lub T, lub też może być przeznaczony do operacji kombinacyjnych. Każdy rejestr wyposażony jest w dwie asynchroniczne operacje ustawiania (set) i zerowania (reset). Podczas włączania zasilania wszystkie wykorzystywane rejestry są inicjalizowane do stanu zdefiniowanego przez użytkownika (w przypadku braku specyfikacji domyślnie ustawiane jest 0). Wszystkie globalne sygnały takie jak sygnały zegara, set/reset oraz output enable są dostępne dla każdej makrokomórki. Sygnał zegarowy dochodzący do rejestru makrokomórki może być jednym z trzech globalnych sygnałów zegara lub sygnałem zegara pochodzącym z linii product term, co przedstawiono na rys. 4.66. Dodatkowo istnieje możliwość wyboru aktywnego zbocza sygnału zegarowego. Poprzez wejście GSR możliwe jest ustawienie rejestru użytkownika do zdefiniowanego przez niego stanu. Blok PTA makrokomórki steruje wykorzystaniem pięciu bezpośrednich linii product terms dochodzących do niej. Np. wszystkie pięć linii może być dołączonych do bramki OR, jak pokazano na rys. 4.67. Blok PTA może dokonywać zmian wewnątrz FB i przydzielać makrokomórce dodatkowe linie, oprócz pięciu podstawowych dochodzących już do niej. 67 Rysunek 4.66. Sposób wyboru sygnałów zegarowych set/reset w makrokomórce bloku FB układów rodziny XC9500 Rysunek 4.67. Wykorzystanie bezpośrednich linii product terms w makrokomórce Każda makrokomórka wymagająca dodatkowej linii product term może skorzystać z niewykorzystanej linii innej makrokomórki wewnątrz bloku FB. Pojedyncza makrokomórka może użyć 15 linii product terms, przy czym należy uwzględnić dodatkowe opóźnienia sygnałów na dodanych liniach, wynikające z wydłużenia się ich drogi wewnątrz bloku FB (rys. 4.68). Elastyczność ta wynika z budowy bloku PTA pokazanej na rys. 4.69. Rysunek 4.68. Blok PTA z 15 liniami product terms 68 Rysunek 4.69. Schemat logiczny bloku PTA Rysunek 4.70. Schemat logiczny matrycy przełączającej (Fast CONNECT Switch Matrix) Matryca przełączająca dostarcza sygnały z bloków IOB i FB do wejść bloków FB (rys. 4.70). Wszystkie wyjścia bloków FB i wejścia/wyjścia bloków IOB są podawane na tę matrycę. Za pomocą matrycy użytkownik wybiera sygnały, które mają dochodzić do danego bloku FB. Dodatkowo realizuje ona iloczyn logiczny na drucie co zwiększa funkcjonalność całego układu. 69 Rysunek 4.71. Schemat logiczny bloku IOB wraz z układami sterujacymi sygnałami ouput enable Bloki wejścia/wyjścia IOB stanowią interfejs pomiędzy wewnętrzną logiką, a pinami wejścia/wyjścia układu. Każdy blok zawiera bufor wejściowy, sterownik wyjściowy, multiplekser wyboru output enable oraz programowalne uziemienie (rys. 4.71). Bufor wejściowy jest kompatybilny ze standardami 5V CMOS, 5V TTL i poziomami sygnału 3,3V. Bufor wejściowy używa wewnętrznego 5V źródła zasilania (VCCINT) w celu zapewnienia stałych progów wejścia i eliminacji wahań napięcia VCCIO. Sygnał output enable może być generowany w następujący sposób, jako: sygnał product term z makrokomórki, dowolny sygnał zegara globalnego, zawsze „1” lub zawsze „0”. Rezystory są de aktywowane podczas normalnych operacji. Sterownik wyjściowy jest zdolny do przewodzenia prądu 24mA. Wszystkie sterowniki wyjściowe w układzie mogą być skonfigurowane dla poziomu 5V lub poziomu 3,3V przez połączenie wyjściowego pinu zasilania (VCCIO) do 5V lub do źródła zasilania 3,3V. Rys. 4.72 pokazuje jak układ XC9500 może być zasilany tylko napięciem 5V lub napięciem 5V i 3,3V. Rysunek 4.72. Sposoby zasilania układu rodziny XC9500: a) jedno źródło zasilania 5V, b) dwa źródła zasilania 5V i 3,3V Programowanie i testowanie układów rodziny XC9500 jest realizowane za pomocą interfejsu standardu IEEE 1149.1 (JTAG). Interfejs ten posiada następującą listę instrukcji: EXTES, 70 SAMPLE/PRELOAD, BYPASS, USER-CODE, INTEST, IDCODE, HIGHZ. Dodatkowo na potrzeby programowania układów w systemie (ISP) dodano 5 instrukcji: ISPEN, FERASE, FPGM, FVFY, ISPEX. Stanowią one rozszerzenie zestawu instrukcji 1149.1. Zgodnie ze specyfikacją standardu IEEE 1149.1 piny TMS i TCK układu interfejsu JTAG są podwieszone poprzez rezystory pull-up do zasilania. Układy XC9500 zawierają zaawansowane sposoby ochrony danych, które całkowicie zabezpieczają program przed nieautoryzowanym czytaniem lub pomyłkowym skasowaniem, czy przeprogramowaniem. Użytkownik może ustawić odpowiednie bity w celu ochrony kodu programu zawartego w układzie przed jego przeczytaniem. Skasowanie w całości programu jest jedynym sposobem na wyzerowanie bitów zabezpieczających, tym samym na odblokowanie odczytu z układu. Wszystkie układy XC9500 oferują możliwość ustawienia trybu niskiego poboru mocy dla każdej makrokomórki z osobna lub dla wszystkich jednocześnie. Zatem ważne dla danej aplikacji części układu mogą pozostać w standardowym trybie poboru mocy, podczas gdy pozostałe mogą zostać zaprogramowane na operacje przy niskim poborze mocy. W czasie włączania zasilania (power-up time) układy XC9500 są w stanie uśpienia dopóki napięcie zasilające VCCINT nie osiągnie bezpiecznego poziomu (około 3,8 V). Do tego czasu wszystkie piny układu oraz interfejsu JTAG są wyłączone i podwieszone do zasilania za pomocą rezystorów pull-up. Kiedy napięcie zasilania osiągnie bezpieczny poziom wszystkie rejestry użytkownika są inicjalizowane (typowo w czasie 100µs dla 9536 - 95144, 200µs dla 95216, 300µs dla 95288) po czym układ jest gotowy do pracy. 4.6. Układy współpracy z wejściami oraz wyjściami binarnymi Układami bardzo często spotykanymi w urządzeniach mikroprocesorowych są układy wejść i wyjść binarnych. Prosty układ wejścia binarnego ma formę ośmiobitowej bramy trójstanowej podłączanej do systemu np. w sposób pokazany na rysunku 4.73. U1 2 3 4 5 6 7 8 9 CS WE 19 1 A0 A1 A2 A3 A4 A5 A6 A7 E DIR B0 B1 B2 B3 B4 B5 B6 B7 18 17 16 15 14 13 12 11 S1 S2 S3 S4 S5 S6 S7 S8 VCC 16 15 14 13 12 11 10 9 D0 D1 D2 D3 D4 D5 D6 D7 U2 10K 1 2 3 4 5 6 7 8 74HC245 Rysunek 4.73. Schemat prostego układu 8 wejść binarnych Wejścia trójstanowe są otwierane sygnałem CSWE (pochodzącym z procesora oraz dekodera adresów), podłączonym do wejścia zanegowanego E. Kierunek przesyłania danych wyznacza wejście DIR, do którego podłączono 0 logiczne, co powoduje, że dane są wysyłane z portu B do portu A. Osiem 71 rezystorów umieszczonych po stronie sygnałów obiektowych, wymusza stan 0 logicznego na każdym z bitów portu. Stan ten w przypadku zamknięcia któregokolwiek z zestyków zmienia się na 1 logiczną. Prosty układ wyjścia dwustanowego ma formę ośmiobitowego zatrzasku podłączanego do systemu np. w sposób pokazany na rysunku 4.74. U10 U11 U2 U1 D0 D1 D2 D3 D4 D5 D6 D7 9 8 7 6 5 4 3 2 CS WY 11 1 8D 7D 6D 5D 4D 3D 2D 1D 8Q 7Q 6Q 5Q 4Q 3Q 2Q 1Q 12 13 14 15 16 17 18 19 1 2 3 4 5 6 7 8 16 15 14 13 12 11 10 9 1K CLK OC 74HC574 U12 U13 U14 U15 U16 U17 LED LED VCC LED LED LED LED LED LED Rysunek 4.74. Schemat prostego układu 8 wyjść binarnych Przerzutniki wyjściowe układu są zapisywane sygnałem CSWY (pochodzącym z procesora oraz dekodera adresów), podłączonym do wejścia CLK dokonującego wpisu. Wyjścia Q0-Q7 są na stałe otwarte przez połączenie wejścia sterującego OC z 0 logicznym (sygnał GND). Osiem rezystorów po stronie wyjść ogranicza prąd płynący przez diody LED będące elementami sygnalizacyj-nymi umieszczonymi po stronie sygnałów obiektowych. Ośmiobitowy rejestr zatrzaskujący 74HC/HCT574, wykorzystany w przedstawionym na rysunku 4.74. układzie wyjść binarnych, ma następujące cechy: - trójstanowe nieodwracające wyjścia, pozwalające na stosowanie układu w systemach magistralowych, - 8-bitowy rejestr składający się z przerzutników typu D wyzwalanych zboczem narastającym sygnału CP, - każdemu przerzutnikowi przyporządkowana jest linia wejściowa i wyjściowa, - wszystkie przerzutniki mają wspólny sygnał zegara CP (clock) oraz sygnał sterowania trójstanowymi buforami wyjściowymi OE. Gdy na linii CP pojawi się zbocze narastające, to stan sygnałów na liniach wejściowych układu (DO - D7) zostaje zapamiętany w rejestrze. Kiedy sygnał OE jest w stanie wysokim, wyjścia układu (QO - Q7) są w stanie wysokiej irnpedancji. Stan niski na linii OE spowoduje wystawienie zawartości rejestru na linie wyjściowe. Linia OE nie wpływa na zawartość rejestrów układu. Na rys. 4.75 pokazano wyprowadzenia końcówek układu oraz jego schemat funkcjonalny. 72 Rysunek 4.75. Schemat wyprowadzeń oraz schemat funkcjonalny układu 74HC574 Rysunek 4.76. Schemat logiczny układu 74HC574 Bardziej skomplikowany układ programowanej bramy wejścia/wyjścia został pokazany na rysunku 4.77. Wykorzystuje on popularny układ 8255A PIO (ang. programmable input-output) zawierający trzy ośmiobitowe bramy o programowalnym kierunku przepływu danych. Do portu A zaprogramowanego jako wyjścia binarne podłączono szeregowo osiem diod LED oraz rezystorów ograniczających prąd wspomnianych diod. Do portu B zaprogramowanego jako wejścia binarne podłączono osiem rezystorów, wymuszających stan 0 logicznego na każdym z bitów portu. Stan ten w przypadku zamknięcia któregokolwiek z zestyków S1S8 zmienia się na 1 logiczną. Na rysunku 4.78 przedstawiono w uproszczeniu wewnętrzną strukturę tego układu 8255. Układ steruje 24 liniami wejścia/wyjścia podzielonymi na dwie sekcje (grupy) A i B zawierające po 12 linii. Interfejs może sterować dowolnymi układami cyfrowymi TTL lub CMOS i bezpośrednio współpracować z większością mikrokontrolerów. 73 U10 U11 U2 U1 5 RD WR 36 9 A0 8 A1 RESET 35 CS 8255 6 D0 D1 D2 D3 D4 D5 D6 D7 PA0 PA1 PA2 PA3 PA4 PA5 PA6 PA7 RD WR A0 A1 RESET CS PB0 PB1 PB2 PB3 PB4 PB5 PB6 PB7 PC0 PC1 PC2 PC3 PC4 PC5 PC6 PC7 4 3 2 1 40 39 38 37 1 2 3 4 5 6 7 8 16 15 14 13 12 11 10 9 18 19 20 21 22 23 24 25 14 15 16 17 13 12 11 10 U12 U13 U14 S1 S2 S3 S4 S5 S6 S7 S8 16 15 14 13 12 11 10 9 34 33 32 31 30 29 28 27 U15 U16 U17 VCC LED LED LED LED LED LED LED VCC U2 10K 1 2 3 4 5 6 7 8 D0 D1 D2 D3 D4 D5 D6 D7 1K LED 8255 Rysunek 4.77. Schemat modułu wejść/wyjść binarnych wykorzystującego układ 8255 Rysunek 4.78. Schemat wewnętrzny układu 8255 Grupa linii A składa się z 8-bitowego portu A oraz czterech bardziej znaczących bitów portu C (PC7-4), natomiast grupa B obejmuje 8-bitowy port B i cztery mniej znaczące bity portu C (PC3-0). Układ jest wybierany sygnałem CS i zawiera cztery rejestry adresowane bitami Al i AO. Przyporządkowanie adresów rejestrom wewnętrznym oraz funkcje rejestrów podano w tablicy 4.4. 74 Tablica 4.27. Wewnętrzne rejestry układu 8255A PIO Adres Al A0 0 0 0 1 l 0 1 1 Rejestr Port A Port B Port C Sterujący Funkcja Rejestr danych portu A Rejestr danych portu B Rejestr danych portu C Rejestr konfiguracji portów A, B, C Po sygnale RESET wszystkie linie interfejsu są zdefiniowane jako wejścia. Rysunek 4.79. Funkcje bitów w rejestrze sterującym układu 8255 Użytkownik może zmienić kierunek przepływu danych w bramie, wpisując odpowiednie słowo sterujące do jej rejestru sterującego. Funkcje poszczególnych bitów w rejestrze sterującym przedstawiono na rysunku 4.79. Słowo wpisywane pod adres AlA0 = 11 zostanie zinterpretowane jako słowo definicji kierunków transmisji tylko wtedy, gdy najbardziej znaczący bit jest ustawiony (D7 = l). Jak wynika z rysunku 4.79, układ umożliwia niezależne definiowanie kierunków transmisji w porcie A i B oraz w każdej z połówek portu C. Ponadto dla każdego z portów definiuje się tryb pracy, określający sposób współpracy z urządzeniem zewnętrznym sterowanym przez ten port. Port A może pracować w trybach 0, l i 2, natomiast port B w trybach 0 i l. Poszczególne tryby różnią się sposobem wykorzystania linii portu C do synchronizacji transmisji między interfejsem a urządzeniem zewnętrznym. Jeśli słowo sterujące wpisywane pod adres A1A0 = 11 ma zero na pozycji najbardziej znaczącego bitu (D7 = 0), wówczas jego znaczenie jest inne. Jest ono mianowicie używane do ustawiania bądź zerowania poszczególnych bitów portu PC, zgodnie z opisem podanym na rysunku 4.80. Dla przykładu, wpis słowa 0xxx0010 spowoduje wyzerowanie bitu PCI, natomiast wpis słowa 0xxx1011 ustawi bit PC5. Możliwość manipulowania poszczególnymi bitami portu C rozszerza zakres stosowania interfejsu 8255A, który, jak widać, nadaje się nie tylko do realizacji transmisji równoległej, ale również do sterowania pojedynczymi liniami (diodami LED, przekaźnikami itp.). Oczywiście, przyłączając do portu C urządzenia zewnętrzne należy zadbać, by nie przekroczyć maksymalnych obciążalności wyjść w stanie niskim i wysokim. 75 Rysunek 4.80. Przykładowa konfiguracja portu A układu 8255 w trybach 1 i 2 4.7. Układ współpracy z wyświetlaczem 7 segmentowym LED Układem spotykanym w starszych urządzeniach mikroprocesorowych jest zestaw wyświetlaczy siedmiosegmentowych pozwalający użytkownikowi na wizualizację komunikatów pochodzących z urządzenia. Wyświetlacz 7-segmcntowy sterowany jest poprzez 2 bufory - porty wyjściowe podłączone do szyny. Bufor wyboru wskaźnika (U23 – CSDS=FF30H) - dane wpisane do tego bufora określają, który wskaźnik ma być w danym momencie aktywny. Stosowane są tzw. Kody l z 8, czyli każdy bit decyduje indywidualnie o świeceniu konkretnego wskaźnika. Typowo wybrany będzie faktycznie tylko l z 7 wskaźników. Ustawienie l na poszczególnym bicie powoduje świecenie odpowiedniego wskaźnika. Bit 0 decyduje o świeceniu wskaźnika l, bit l decyduje o świeceniu wskaźnika 2 itd. Bit 6 decyduje o świeceniu diod świecących, które zostały podłączone jako wskaźnik 7 Tablica 4.28. Bufor wskaźnika wyboru 76 Rysunek 4.81. Schemat przykładowego układu wyświetlacza siedmiosegmentowego 77 Bufor danych wskaźnika (U22 – CSDB=FF38H) – bajt umieszczony w tym buforze określa, które segmenty wyświetlacza będą zapalone w wybranym wskaźniku. Jedynka umieszczona na konkretnym bicie powoduje świecenie odpowiedniego segmentu lub diody świecącej, zgodnie z opisem. Rysunek 4.82. Bufor danych wskaźnika Przykład przedstawia proste sterowanie wyświetlaczem 7-segmentowym. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 0096 FF30 FF38 0009 005B 0000: 02 01 00 0100: 0100: 0100: 90 FF 30 0103: 74 09 0105: F0 0106: 90 FF 38 0109: 74 5B 010B: F0 010C: C2 96 010E: 80 FE SEG_ON EQU P1.6 ;bit. włączenia wyświetl. 7-segm. ;Pełne adresy urządzeń we/wy systemu DSM-51 F_CSDS EQU 0FF30H ;bufor wyboru wskaźnika F_CSDB EQU 0FF38H ;bufor danych wskaźnika ;Stałe używane w programie DISPLAY EQU 00001001B ;wybrane wskaźniki – 1 i 4 COD EQU 01011011B ;wybrane segmenty LJMP START ORG 100H ;przesunięcie kodu instrukcji do adresu 100H START: MOV DPTR,#F_CSDS ;adres bufora wyboru wskaźnika MOV A,#DISPLAY MOVX @DPTR,A ;wpisz wybrane wskaźniki MOV DPTR,#F_CSDB ;adres bufora danych wskaźnika MOV A,#COD MOVX @DPTR,A ;wpisz wybrane segmenty CLR SEG_ON ;włącz wyświetlacz 7-segmentowy SJMP $ W przykładzie przedstawiony jest sposób zapisu danych do portów podłączonych do szyny mikrokontrolera. Zapis danych do tych portów polega na podaniu przez mikrokontroler odpowiedniego adresu na szynę adresową i sygnału WR (porty wyjściowe umieszczone są w obszarze pamięci danych. Oznacza to, że do zapisania potrzebny jest sygnał WR). Po podaniu odpowiedniego adresu do portu dotrze sygnał CS wytworzony w dekoderze adresów. Sygnał ten, wraz z sygnałem WR, jest rozkazem dla portu wyjściowego, aby wysterował zapisał do zatrzasku dane wystawione na szynę przez procesor. W ten sposób po wystawieniu sygnału WR, mikrokontroler może zapisać dane do portu wyjściowego. Służy do tego rozkaz MOVX. Literka X w nazwie rozkazu, dla odróżnienia od rozkazu MOV, oznacza, że chodzi o zewnętrzną (eXternal) przestrzeń adresową danych. Rozkaz MOVX @DPTR,A zapisuje pod adres zawarty w rejestrze DPTR bajt z akumulatora. Rejestr DPTR jest rejestrem 16-bitowym (jest to jedyny rejestr 16-bitowy w mikrokontrolerze 8051 poza licznikiem rozkazów PC). W rzeczywistości są to dwa rejestry 8-bitowe (DPL, DPH) umieszczone w obszarze rejestrów specjalnych SFR, które mikrokontroler 8051 potrafi użyć razem jako rejestr 16-bitowy. Przed rozkazem MOVX umieszczono w rejestrze DPTR adres bufora, do którego należy przesłać dane. Dzięki temu rozkaz MOVX wystawia na szynę adresową pełny adres potrzebnego bufora. Po uruchomieniu programu można zaobserwować, że świecą wskaźniki wybrane stałą DISPLAY, natomiast segmenty wybrane stałą COD. Dokonując zmian w tych stałych można decydować, które wskaźniki i które segmenty mają świecić. 78 W przykładzie w stałej DISPLAY umieszczono dwie jedynki, co powoduję że świecą dwa wskaźniki - 1 i 4. Po wpisaniu danych do buforów sterujących wyświetlaczem należy jeszcze wyzerować linię szóstą w porcie Pl mikrokontrolera. Linia ta, ustawiona na l, blokuje tranzystor T18 i w rezultacie wyświetlanie na całym wyświetlaczu 7-segmentowym. Jest ona doprowadzona do wyświetlacza po to, aby po włączeniu zasilania nie była wyświetlana na wyświetlaczu przypadkowa zawartość buforów - port mikrokontrolera jest automatycznie ustawiany na wartość l. Może ona też być wykorzystana przy sekwencyjnej obsłudze wyświetlacza do jego wygaszania w czasie zmiany wyświetlanego wskaźnika. 4.8. Układ współpracy z klawiaturą Ważnym elementem w systemie mikroprocesorowym jest zestaw klawiszy pozwalający użytkownikowi na bezpośrednie wprowadzanie danych. Zwykle układ klawiszy ma formę klawiatury podłączanej do systemu np. w sposób pokazany na poniższym rysunku. Obsługa klawiatury z rysunku 4.83 jest wykonywana w sposób programowy, to znaczy sprawdzanie, czy został wciśnięty jakiś przycisk oraz dekodowanie jego współrzędnych w matrycy (numeru wiersza i kolumny) odbywa się przy użyciu algorytmu skanowania (przeglądania) klawiatury. W bardziej skomplikowanych zespołach klawiatur alternatywnie stosuje się sygnalizację wciśnięcia przycisku przez linie przerwań oraz sprzętowe dekodowanie wciśniętego przycisku. SW9 SW1 R1 L0 SW2 SW10 SW3 SW11 R2 L1 R5 SW12 L3 SW5 R6 SW13 R7 L4 SW6 L0 L1 L2 L3 L4 L5 L6 L7 R4 L2 SW4 U9 R3 L5 8x10 k SW7 SW15 + 5V SW16 D1 D2 D3 D4 D5 D6 D7 D8 Q1 Q2 Q3 Q4 Q5 Q6 Q7 Q8 18 17 16 15 14 13 12 11 D0 D1 D2 D3 D4 D5 D6 D7 D [0..7] E1 E2 74541 RD CSKB L6 SW8 2 3 4 5 6 7 8 9 1 19 R8 SW14 L0 L1 L2 L3 L4 L5 L6 L7 3 4 1 L7 2 6 U8A 74125 5 U8B 74125 A1 A0 A [0..15] Rysunek 4.83. Schemat układu klawiatury wyk. w urządzeniu dydaktycznym DSM-51 Odczytywanie danych z tych portów polega na podaniu przez mikrokontroler odpowiedniego adresu na szynę adresową i sygnału RD (porty wejściowe umieszczone są w obszarze pamięci danych. Znaczy to, że do odczytania potrzebny jest sygnał RD). Po podaniu odpowiedniego adresu do portu dotrze sygnał CS wytworzony w dekoderze adresów. Sygnał ten, wraz z sygnałem RD, jest rozkazem dla portu wejściowego, aby wysterował szynę danych zgodnie z danymi, które są na jego wejściu. W ten sposób po wystawieniu sygnału RD, mikrokontroler może odczytać dane z portu wejściowego. Do przeprowadzenia tej operacji służą, tak jak w przypadku portów wyjściowych, rozkazy MOVX. Można oczywiście stosować zarówno adresowanie pełne, korzystając z rejestru DPTR, jak i adresowanie 8bitowe - rejestry R0 i Rl. W systemie DSM-51 najprostszym urządzeniem wejściowym jest klawiatura matrycowa. Jest ona podłączona jako dwa porty wejściowe pod kolejnymi adresami: CSKBO i CSKB l. Pod każdym z nich można odczytać stan ośmiu klawiszy. Wybór odczytywanego zestawu klawiszy jest dokonywany liniami adresowymi A0 i A l (stan 0 na linii uaktywnia związany z nią zestaw kla- 79 wiszy). Jeśli port P2 zawiera starszą część adresu urządzeń wejść/wyjść, to do odczytania stanu klawiatury można posłużyć się rozkazami podającymi na szynę tylko młodszą część adresu. Odczytanie wartości spod adresu 21H (A l = O, AO = 1) daje stan pierwszego zestawu ośmiu klawiszy. Drugi zestaw jest odczytywany spod adresu 22H (A l = l, AO = 0). Przyporządkowanie poszczególnych klawiszy bitom danych odczytanych spod adresu 21H lub 22H jest przedstawione w tabeli. Tablica 4.29. Porty wejściowe klawiatury matrycowej Przykład przedstawia proste odwzorowanie stanu klawiszy [0],...[7] na wyświetlaczu 7-segmentowym. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 0096 0055 0021 0038 0000: 02 01 00 0100: 0100: 0100: 79 30 0102: 74 55 0104: F3 0105: 79 38 0107: 78 21 0109: C2 96 010B: 010B: E2 010C: F4 010D: F3 010E: 80 FB SEG_ON EQU P1.6 ;włączenie wyświetlacza 7-segmentowego ;Stałe używane w programie DISPLAY EQU 01010101B ;wskaźniki - 1,3,5,7 CSKB0 EQU 021H ;bufor wyboru wskaźnika CSDB EQU 038H ;bufor danych wskaźnika LJMP START ORG 100H ;przesunięcie kodu instrukcji do adresu 100H START: ;pusta linia w programie źrdłowym MOV R1,#CSDS ;adres wyboru wskaźnika MOV A,#DISPLAY MOVX @R1,A ;wpisz wybrane wskaźniki MOV R1,#CSDB ;adres danych wskaźnika MOV R0,#CSKB0 ;adres klawiszy 0..7 CLR SEG_ON ;włącz wyświetlacz 7-segm LOOP: ;przepisuj stan klawiszy na wyświetlacz 7-segm. MOVX A,@R0 ;odczytanie klawiszy, bit = 0 – klawisz naciśnięty CPL A ;zmiana 0<->1 MOVX @R1,A ;włączenie segm. odpowiadających wciśniętym klawiszom SJMP LOOP Stan na wyświetlaczu jest wyświetlany statycznie, jednocześnie na kilku wskaźnikach. O tym, na których, decyduje stała DISPLAY. W przykładzie można odczytać naraz stan ośmiu klawiszy. Wybierając adres CSKBO wczytywany jest stan klawiszy - klawiszowi [0] odpowiada bit 0 w odczytanym bajcie, - klawiszowi [1] odpowiada bit l itd. Jeżeli klawisz jest zwolniony, to odpowiada mu bit o wartości - l, jeśli jest naciśnięty, bit = 0. Negując ten bajt i wysyłając go na wyświetlacz 7-segmentowy otrzymano zależność świecenia segmentu o numerze odpowiadającym numerowi naciśniętego klawisza. Oznacza to, że: - klawiszowi [0] odpowiada segment a, - klawiszowi [1] odpowiada segment b itd. 80 Na rysunku poniżej pokazano inne rozwiązanie układu klawiatury matrycowej, wykorzystujące układ 8255. Rysunek 4.84. Uproszczony schemat połączenia klawiatury matrycowej 7 x 4 z mikrokontrolerem x51 przez programowalny układ PIO Przed rozpoczęciem skanowania klawiatury należy, odpowiednio skonfigurować układ 8255, to znaczy zdefiniować odpowiednie kierunki transmisji w portach. Następnie dekodowanie stanu klawiatury przebiega według następującego schematu: - Mikrokontroler ustawia stan "0" na linii kolumny numer 0, sterowanej z wyjścia PBO układu 8255. - Program odczytuje port PCL i sprawdza, czy na jednym z wejść jest stan "0". Jeśli tak jest, to wykryto wciśnięcie przycisku na skrzyżowaniu kolumny 0 i wiersza, na którym odczytane zostało "0". - Mikrokontroler generuje stan "0" na kolejnej linii kolumn i wykonuje sprawdzenie stanu linii wierszy. Procedura powtarza się, aż sprawdzona zostanie cała klawiatura albo nastąpi wykrycie stanu wciśnięcia jakiegokolwiek przycisku. - Po zdekodowaniu klawiatury program przystępuje do obsługi przez wywołanie procedury przypisanej do danego klawisza. 4.9. Układ współpracy z wyświetlaczem LCD Ważnym elementem w systemie mikroprocesorowym jest wyświetlacz LCD pozwalający użytkownikowi na wizualizację komunikatów pochodzących z urządzenia. W wyświetlaczach LCD tych każdy znak zdefiniowany jest na polu 5x7 punktów, co pozwala na wyświetlanie dowolnych znaków (cyfr, liter) w pełni zrozumiałych dla człowieka. Ze względu na znacznie większą ilość danych niż w wyświetlaczu 7-segmentowym oraz na bardziej złożone sterowanie, wyświetlacze LCD są standardowo wyposażone w specjalizowane procesory, które zarządzają wyświetlaniem. Takie procesory nazywane są sterownikami wyświetlacza. Typowym ich przedstawicielem jest układ firmy Hitachi HD 44780. Do takiego sterownika mikrokontroler wysyła tylko dane (które mają być wyświetlane) i instrukcje (w jaki sposób mają być wyświetlane). Natomiast sposób zamiany danych na punkty, które mają świecić, czy przebiegi sterujące wyświetlaniem, to już zadanie sterownika. 81 + 5V D [0..7] R1 10 k + 5V R2 470 U10 2 3 1 KONTRAST A0 A1 4 5 6 VCC VO GND RS R/W E D0 D1 D2 D3 D4 D5 D6 D7 17 16 15 10 11 12 13 14 D0 D1 D2 D3 D4 D5 D6 D7 LM16A21 A [0..15] LCD Rysunek 4.85. układ sterownika wyświetlacza LCD Z tego względu wyświetlacz LCD (naprawdę układ interfejsu sterownika HD44780) zajmuje w przestrzeni adresowej cztery kolejne komórki pamięci. W urządzeniu DSM-51 wykorzystywanym w laboratorium, są to adresy począwszy od 80H (FF80H). Każdy z tych adresów pełni specyficzną rolę: - 80H - zapis instrukcji, - 81H - zapis danych, - 82H - odczyt stanu, - 83H - odczyt danych. Po wysłaniu do sterownika wyświetlacza LCD kolejnej instrukcji bądź kolejnych danych, sterownik musi wykonać otrzymane polecenie, tzn. wykonać instrukcję bądź umieścić dane pod odpowiednim adresem. Na wykonanie tych operacji sterownik potrzebuje określonego czasu. W tym czasie sterownik jest zajęty i nie przyjmuje kolejnych poleceń. Jedynym wyjątkiem jest możliwość odczytania stanu. Przed wydaniem kolejnego polecenia należy sprawdzić, czy sterownik jest gotów do jego przyjęcia. Jest to możliwe przez odczytanie stanu wyświetlacza, czyli odczyt spod adresu 82H. Siódmy bit stanu jest to flaga Busy (flaga zajętości). Jeżeli flaga ta jest równa l, to sterownik jest zajęty i będzie głuchy na nasze polecenia. Jeżeli flaga Busy równa się 0, to można wysłać do sterownika kolejne polecenie. Sterownik wyświetlacza ma wyprowadzone następujące sygnały sterujące: Tablica 4.30. Sygnały sterujące wyświetlacza LCD W zależności od ich stanu można dokonywać wpisu lub odczytywania danych zgodnie z poniższą tabelą. Tablica 4.31. Dozwolone stany sygnałów sterujących 82 Do sterownika można wysłać wiele różnych rozkazów pokazanych w poniższej tabeli wpisując je pod adres rejestru sterującego. Tablica 4.32. Rozkazy dla sterownika LCD Pamięć sterownika składa się z dwu części pozwalających na: - pamiętanie znaków pokazywanych na wyświetlaczu – obszar DD_RAM Tablica 4.33. Pozycja Linia 1 Linia 2 - 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 00 01 02 03 04 05 06 07 08 0A 0B 0C 0D 0E 0F 10 40 41 42 43 44 45 46 47 48 4A 4B 4C 4D 4E 4F 50 pamiętanie definicji kroju graficznego znaków wyświetlacza – obszar CG_RAM. Na każdy znak przeznaczonych jest 8 bajtów w pamięci CG_RAM odpowiednio 0H...7H, 8H...0FH, ...38H...3FH. Przykładowo pamięć znaku M wygląda następująco: 83 Rysunek 4.86. Definicja kroju graficznego znaków wyświetlacza Definicje znaków w obszarze pamięci CG_RAM sterownika przedstawiono poniżej w postaci tabeli. Tablica 4.34. Definicje znaków pamięci CG_RAM sterownika wyświetlacza LCD 84 Przykład l ilustruje sposób wprowadzania kolejnych danych na wyświetlacz. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 0080 0081 0082 LCDWC EQU LCDWDEQU LCDRC EQU 0000: 02 01 00 0100: 0100: 0100: 79 82 0102: 78 80 0104: 74 01 0106: F2 0107: 0107: E3 0108: 20 E7 FC 80H 81H 82H LJMP START ORG 100H ;adres wpisywania rozkazów do wyświetlacza LCD ;adres wpisywania danych do wyświetlacza LCD ;adres odczytu stanu wyświetlacza LCD ;pusta linia w programie źrdłowym ;przesunięcie kodu instrukcji do adresu 100H ;pusta linia w programie źrdłowym START: MOV MOV MOV MOVX R1,#LCDRC R0,#LCDWC A,#1 @R0,A ;adres odczytu stanu wyświetlacza LCD ;adres wpisywania danych do wyświetlacza LCD ;rozkaz CLR dla wyświetlacza LCD ;wpis rozkazu CLR do wyświetlacza LCD BUSY: MOVX A,@R1 JB ACC.7,BUSY 85 ;odczyt stanu wyświetlacza ;oczekiwanie na bit BUSY=0 16 17 18 19 20 010B: 78 81 010D: 74 4B 010F: F2 0110: 80 FE MOV MOV MOVX SJMP R0,#LCDWD A,#4BH @R0,A $ ;adres wpisywania danych do wyświetlacza LCD ;kod znaku “K” ;wpis kodu znaku do wyświetlacza LCD Jako pierwszy do wyświetlacza (pod adres rejestru sterującego LCDWC=FF80H) zostaje wysłany rozkaz CLR, który kasuje wszystkie znaki pokazywane na wyświetlaczu. Przed wysłaniem kolejnej danej procesor sprawdza, czy sterownik wyświetlacza wykonał poprzednią instrukcję. Sprawdzenie jest wykonywane w pętli BUSY. W pętli tej procesor czyta stan wyświetlacza (z adresu rejestru stanu LCDRC=FF82H), aż do momentu, kiedy bit nr 7 w odczytywanej danej, czyli flaga zajętości (BUSY) będzie równa 0. Wtedy wysyłany jest następny znak. Ale tym razem pod adres rejestru danych LCDWD=FF80H. Po wprowadzeniu 16-tu znaków kursor znika z wyświetlacza i kolejne znaki pozornie nie są wpisywane na wyświetlacz. Jednak gdy wprowadzonych zostanie ponad 40 znaków, kursor ponownie pojawia się na wyświetlaczu - tym razem w dolnej linii. Takie zachowanie wynika z tego, że wyświetlacz LCD wyposażony jest w uniwersalny sterownik LCD. Jego uniwersalność polega na tym, że bez względu na to, jakim wyświetlaczem steruje (2 linie po 16 znaków, 2x20, 2x40, l x80), jest to zawsze ten sam sterownik, który pamięta 80 znaków (l linia x 80 znaków bądź 2 linie x 40 znaków). Tak więc wysłane na wyświetlacz znaki nie zginęły, a jedynie nie można było ich wszystkich naraz wyświetlić. 4.10. Przetworniki analogowo-cyfrowe Przetworniki analogowo-cyfrowe stosowane w układach mikroprocesorowych wykorzystują najczęściej kilka spośród wielu znanych metod przetwarzania napięcia na odpowiadającą mu miarę liczbową: - metodę sukcesywnej aproksymacji SAR (ang. successive approximation), - metodę jednozboczowego ładowania pojemności SS (ang. single-slope A/D), - metodę nadpróbkowania (ang. oversampling). Częściej stosowana jest metoda SAR, która nie wymaga dołączania do mikrokontrolera zewnętrznych elementów dyskretnych i jest łatwiejsza przy programowaniu obsługi przetwornika. Zaletą metody SAR jest ponadto stosunkowo krótki czas konwersji, równy zwykle od 10 do 16 cykli zegara w przypadku konwerterów 8-bitowych. (Czas konwersji to czas upływający pomiędzy momentem podania na wejściu przetwornika sygnału inicjującego konwersję a momentem ustalenia się na wyjściu przetwornika wyniku liczbowego konwersji). Realizacja przetworników SAR o większej rozdzielczości napotyka jednak trudności, dlatego (praktyce rozdzielczość przetworników SAR wbudowywanych do mikrokontrolerów nie przekracza 10 bitów a zewnętrznych 16 bitów. Metoda SS wymaga z kolei stosowania dołączanego z zewnątrz kondensatora, co jest jej oczywistą wadą. Zapewnia jednak stosunkowo prostą realizację przetworników o większej rozdzielczości, na przykład 12- lub nawet 16-bitowej. Czas przetwarzania jest jednak dłuższy niż w przypadku metody SAR. Przetworniki z nadpróbkowaniem (sigma-delta) są urządzeniami mającymi największą rozdzielczość wynoszącą nawet 24bity, przy czym ich czas przetwarzania nie jest zwykle mniejszy niż kilka mikrosekund. W celu zwiększenia liczby wejściowych kanałów analogowych bardzo często przetworniki współpracują z układami multiplekserów lub kluczy analogowych. W celu zwiększenia dokładności konwersji, wejścia analogowe wykorzystują układy próbkująco-pamiętające (ang. sample&hold – S/H). Realizacja przetworników A/C na przykładzie metody równoległej Na rysunku 4.87 pokazano realizację przetwornika równoległego dla liczb trzybitowych. Liczba trzybitowa umożliwia reprezentację ośmiu różnych liczb z zerem włącznie. Przetwornik wymaga wiec zastosowania siedmiu komparatorów. 86 Rysunek 4.87. Równoległy przetwornik A/C Siedem różniących się o stałą wartość napięć odniesienia wytwarza się za pomocą dzielnika napięcia. Jeżeli podamy napięcie wejściowe mieszczące się przykładowo w zakresie 5/2...7/2 ULSB, to na wyjściu komparatorów l ...3 otrzymamy l, a na wyjściu komparatorów 4... 7 - 0. Potrzebny jest teraz układ logiczny, który przetworzy te stany komparatorów na liczbę 3. Na rysunku 4.88 przedstawiliśmy związek miedzy stanami komparatorów a odpowiadającymi im liczbami dwójkowymi. Przekształcenie to można zrealizować za pomocą dekodera priorytetowego. Rysunek 4.88. Stany zmiennych w równoległym przetworniku A/C w zależności od napięcia wejściowego Dekodera priorytetowego nie można jednak dołączyć bezpośrednio do wyjść komparatorów. Jeżeli bowiem napięcie wejściowe nie jest stałe, to w kodzie dwójkowym mogą przejściowo wystąpić błędne wartości liczb. Weźmy dla przykładu przejście z trzech na cztery, czyli w kodzie dwójkowym z 011 na 100. Jeżeli z powodu krótszych czasów propagacji najwyższa pozycja zmieni się wcześniej od pozostałych dwu, to przejściowo pojawi się liczba 111, czyli 7. Odpowiada to 87 błędowi równemu połowie zakresu pomiarowego. Ponieważ wynik przetwarzania A/C jest z reguły przechowywany w pamięci, istnieje pewne prawdopodobieństwo zapamiętania tej całkowicie błędnej wartości. Pomocą może tu być np. zapobieganie zmianom napięcia wejściowego w czasie pomiaru za pomocą układu próbkująco-pamiętającego (S/H). Wpływa to jednak na osiągalną częstotliwość napięcia wejściowego, ponieważ układ próbkująco-pamiętający wymaga określonego czasu akwizycji. Poza tym nie gwarantuje to, że stany wyjść komparatorów nie ulegną zmianie, ponieważ szybkie układy próbkująco-pamiętające mają duży dryft. Problemów tych można jednak uniknąć, jeśli zamiast wartości analogowej (przed komparatorami), zapamięta się wartość cyfrową (za komparatorami). Do tego celu służą przerzutniki D wyzwalane zboczem za każdym komparatorem na rys. 4.87. Dzięki nim, przez cały okres przebiegu taktującego dekoder priorytetowy otrzymuje ustalony sygnał wejściowy. Opisana wyżej możliwość zastosowania cyfrowego układu próbkująco-pamiętającego jest zaletą metody równoległej, decydującą o dużej szybkości przetwarzania A/C. Dla częstotliwości powyżej kilku MHz bowiem, nawet przy dużym nakładzie środków, nie można zrealizować analogowych układów próbkująco-pamiętających o wymaganej dokładności. 4.10.1. Konwersja analogowo-cyfrowa – przetwornik SAR Przetwornik SAR składa się z układu próbkująco-pamiętającego (ang. sample&hold – S/H), komparatora, rejestru aproksymacyjnego i układu sterowania realizującego algorytm SAR (rysunek 4.88). W rzeczywistych układach stosuje się zazwyczaj kilka (ba nawet kilkanaście) kanałów przetwarzania A/C, multiplekser kanałów, źródło napięcia odniesienia i niekiedy oddzielny układ zasilania części analogowej w celu wyeliminowania zakłóceń. Rysunek 4.88. Uproszczony schematprzetwornika A/C pracującego na zasadziesukcesywnej aproksymacji Cykl konwersji w układzie SAR zaczyna się od pobrania próbki mierzonego napięcia wejściowego i zapamiętania jej w pojemności C. Rejestr aproksymacyjny jest zazwyczaj inicjowany w taki sposób, że ma ustawiony najbardziej znaczący bit, a pozostałe bity wyzerowane. Zawartość rejestru reprezentuje zatem napięcie równe połowie maksymalnego napięcia (zakresu pomiarowego). Wartość ta jest zamieniana przez przetwornik C/A na napięcie i porównywana z napięciem mierzonym. W zależności od wyniku równania układ sterowania pozostawia najbardziej znaczący bit rejestru niezmieniony albo go neguje. Pierwszy przypadek ma miejsce wtedy, gdy napięcie mierzone jest większe od połowy napięcia maksymalnego, drugi natomiast - gdy jest mniejsze. Po określeniu wartości najbardziej znaczącego bitu rejestru aproksymacyjnego układ SAR ustawia w rejestrze kolejny bit i powtarza opisaną wyżej procedurę. 88 Przy n-bitowym rejestrze aproksymacyjnym, układ określa jego ostateczną zawartość po n cyklach zegara (lub 2n cyklach zegara, jeśli jeden cykl aproksymacji jest wykonywany w czasie dwóch cykli zegara). Opisana metoda jest niekiedy określana w literaturze jako poszukiwanie dwudzielne lub binarne (ang. binary search). Ograniczenie dokładności konwersji napięcia wynika przede wszystkim z błędów wnoszonych przez analogową pętlę sprzężenia zwrotnego. Tablica 4.35. Przykłady układów przetworników analogowo-cyfrowych typu SAR 4.10.2. Konwersja analogowo-cyfrowa – przetwornik SS Rysunek 4.89. Budowa przetwornika A/C opartego na zasadzie jednozboczowego ładowania zewnętrznej pojemności Początkowa część toru przetwornika SS ma podobną budowę jak w przetworniku SAR - zawiera układ próbkująco-pamiętający i komparator (rysunek 4.89). Dodatkowo stosuje się zewnętrzną pojemność C ładowaną przez źródło prądowe. Cykl pomiaru napięcia wejściowego zaczyna się od rozładowania pojemności C1 przez zwarcie jej do masy. Jednocześnie układ próbkująco-pamiętający pobiera próbkę mierzonego napięcia i zapamiętuje ją w pojemności C (w prostych układach nie stosuje się układu sample&hold i napięcie mierzone jest ciągle podawane na wejście komparatora). 89 Różnica tych zawartości jest miarą czasu ładowania pojemności C1 i pozwala łatwo obliczyć napięcie wejściowe, jeśli tylko znana jest wielkość prądu I oraz okres zegara wzorcowego. Uzyskanie dużej rozdzielczości pomiaru wymaga stosowania małego prądu I, czyli długiego czasu ładowania. Właściwa konwersja zaczyna się w chwili włączenia źródła prądowego, które ładuje pojemność C1. W tym momencie licznik zaczyna zliczać impulsy generatora wzorcowego. Rosnące napięcie na pojemności C1, jest porównywane z mierzonym napięciem przez komparator, a po zrównaniu się z nim następuje zatrzymanie licznika. W praktyce realizacja układu jest nieco inna, mianowicie licznik pracuje bez przerwy, natomiast jego zawartość jest odczytywana w chwili startu ładowania pojemności i w chwili zrównania się napięć na wejściu komparatora. Z tego względu czas przetwarzania w metodzie SS jest w związku z tym długi (rzędu milisekund), podczas gdy przetworniki SAR wykonują przetwarzanie w czasie rzędu mikrosekund. Mimo długiego czasu konwersji przetworniki SS są stosowane, jeśli potrzebna jest duża rozdzielczość pomiaru. Przetwornik tego typu jest wbudowany na przykład w mikrokontrolerze 68HC705JP7 (Motorola) i zapewnia rozdzielczość 12-bitową. 4.10.3. Konwersja analogowo-cyfrowa – przetwornik SigmaDelta (Σ Σ∆) Jedną z podstawowych zalet techniki sigma-delta jest to, że może ona wykorzystywać filtrację cyfrową, a około 90% obszaru struktury półprzewodnikowej obwodu scalonego jest czysto cyfrowe. Dzięki temu dostępne są teraz przetworniki sigma-delta o dużej rozdzielczości (np. 24 bitowe), dobrych charakterystykach szumowych i cenie porównywalnej z innymi typami przetworników. Przetworniki sigma-delta charakteryzują się wszystkimi tymi zaletami, które wynikają ze stosowania technik cyfrowych, czyli dużej niezawodności, lepszej stabilności i wyższej funkcjonalności. Ponadto, ze względu na wykorzystywanie podczas konwersji sigma-delta głównie technik cyfrowych, możliwe jest zintegrowanie tego przetwornika z urządzeniem DSP na tej samej strukturze półprzewodnikowej. Zmniejsza to liczbę niezbędnych obwodów scalonych systemu redukując koszt, a co najważniejsze poprawia niezawodność systemu. Przetworniki SAR oraz z całkowaniem wykorzystują identyczną zasadę próbkowania - częstotliwość próbkowania znajduje się w pobliżu granicy Nyquista, co wymaga stosowania dobrego filtru antyaliasingowego (filtru dolnoprzepustowego ograniczającego częstotliwość maksymalną sygnału podawanego na przetwornik A/C, pozwalającego na spełnienie warunku: (Fpr > 2fmax sygnału)). Dobre parametry tych przetworników osiągane są dzięki dobieraniu podzespołów i procesowi wyrównywania laserowego. Natomiast przetwornik A/C typu sigma-delta wykorzystuje konwersję o niskiej rozdzielczości (kwantyzator jednobitowy), lecz stosowana w nim szybkość próbkowania wielokrotnie przewyższa częstotliwość Nyquista. Po procesie próbkowania, już w dziedzinie cyfrowej, następuje zgęszczenie informacji (decymacja), co prowadzi do obniżenia częstotliwości wyjściowej i wzrostu dokładności. Rysunek 4.90. Próbkowanie z częstotliwością czterokrotnie przewyższającą granicę Nyquista Załóżmy próbkowanie przebiegu wejściowego z częstotliwością czterokrotnie przewyższająca granicę Nyquista (Fpr=FS > 2fmax sygnału) i zbadajmy rezultat tej czynności (rysunek 4.90). 90 Z rysunku wynika, że wymagania na filtr antyaliasingowy znacznie się uprościły. Odnośny obszar, w którym wymagana jest płaska odpowiedź impulsowa jest węższy, a nachylenie charakterystyki filtru może być bardziej łagodne. W związku z tym sam filtr staje się o wiele łatwiejszy do zaprojektowania. Rysunek 4.91. Redukcja mocy szumów podczas nadpróbkowania Próbkowanie przy wyższej częstotliwości, nazywane nadpróbkowaniem, ma jeszcze jedną istotną zaletę. Podczas procesu kwantyzacji wynikająca z niego moc szumu rozkłada się równomiernie na całe widmo. Zatem stosując przetworniki A/C sigma-delta otrzymujemy taką samą całkowitą moc szumu, która jest jednak rozłożona w szerszym paśmie częstotliwościowym. Dzięki temu moc szumu z interesującego nas zakresu, mającego wpływ na szum końcowy (od -fm do + fm), jest niższa, co pokazano na rysunku 4.91. Stosowana w przetwornikach A/C jednobitowa kwantyzacja sigma-delta wykorzystuje rozwinięcie metody znanej już w technice i nazywanej modulacją delta. Modulacja ta opiera się o kwantyzację różnicy między wartościami kolejnych próbek, a nie wartości absolutnej próbki sygnału wejściowego (rysunek 4.92). 91 Modulacja Demodulacja Rysunek 4.92. Modulacja/demodulacja typu delta Modulacja sigma-delta osiągnięta jest przez przesuniecie drugiego układu całkującego z demodulatora do stopnia wejściowego modulatora (rysunek 4.93). Modulator Demodulator Rysunek 4.93. Zmodyfikowana modulacje/demodulacja typu delta Całkowanie jest funkcją liniową i może być wykonane bez naruszenia prawidłowego funkcjonowania systemu. Co więcej, dwa układy całkujące mogą być połączone w jeden zgodnie z rysunkiem 4.94. 92 Modulator Demodulator Rysunek 4.94. Modulacja sigma-delta w połączeniu z całkowaniem Nazwa sigma-delta pochodzi od węzła sumującego (sigma) po którym umieszczony jest modulator delta (całkowanie i jednobitowy kwantyzator). Właściwości szumowe takiego kodera zależą od częstotliwości. Sprzężenie zwrotne pełni tu rolę filtru dolnoprzepustowego dla sygnału wejściowego oraz filtru górno przepustowego dla szumów wprowadzanych przez kwantyzator. Ta właściwość kształtowania szumów dobrze nadaje się do cyfrowych zastosowań audio. Schemat blokowy przetwornika A/C sigma-delta pokazano na rysunku 4.95. Rysunek 4.95. Przetwornik A/C typu sigma-delta Jednobitowe dane przesyłane są do filtru decymacyjnego (układu redukcji przepływu informacji), który uśrednia wartości w dziedzinie cyfrowej oraz wytwarza wyjście n-bitowe o niższej częstotliwości (rysunek 4.96). Rysunek 4.96. Zasada działania cyfrowego filtru decymacyjnego 93 Tablica 4.36. Przykłady układów przetworników analogowo-cyfrowych typu Σ∆ 4.10.4. Błędy konwersji w przetwornikach A/C Błędy statyczne Przy przetwarzaniu wielkości analogowej na liczbę o skończonej liczbie bitów ze względu na ograniczoną rozdzielczość powstaje błąd systematyczny, który nosi nazwę błędu kwantyzacji (rozdzielczości). Zgodnie z rys. 4.97 wynosi on ± ULSB/2 tzn. jest równy połowie zmiany napięcia wejściowego, która wywołuje zmianę najniższej pozycji liczby. Jeżeli otrzymany ciąg liczb przetworzymy za pomocą przetwornika C/A z powrotem na napięcie, błąd kwantyzacji ujawni się w postaci szumu, którego wartość skuteczna wynosi: Przy pełnym wysterowaniu przebiegiem sinusoidalnym w przypadku N-bitowego przetwornika wartość skuteczna napięcia sygnału: Otrzymujemy stąd stosunek sygnału do szumu: Oprócz systematycznego błędu kwantyzacji występują większe lub mniejsze błędy pochodzenia układowego. Jeżeli w idealnej charakterystyce przetwarzania na rys. 4.98 połączymy środki schodków, to otrzymamy prostą o nachyleniu l , przechodzącą przez początek układów współrzędnych. W rzeczywistym przetworniku A/C prosta ta nie przechodzi przez 0 (błąd zera), a jej nachylenie odbiega od jedności (błąd wzmocnienia). 94 Błąd wzmocnienia wywołuje stałą dla zakresu wysterowania odchyłkę względną wielkości wyjściowej od wartości zadanej, natomiast błąd zera - stałą odchyłkę bezwzględną. Rysunek 4.97. Powstanie szumu kwantyzacji.Napiecie Uwr(L) otrzymuje się z przetworzenia C/A liczby L występującej na wyjściu przetwornika A/C Rysunek 4.98. Charakterystyka przetwarzania przetwornika A/C z błędem liniowości Oba te błędy można z reguły skorygować przez regulację zera i wartości odpowiadającej pełnemu zakresowi. Pozostają wtedy tylko odchyłki wywołane niestałością (dryftem) i nieliniowością. Nieliniowość wykraczająca poza systematyczny błąd kwantyzacji powstaje zawsze wówczas, gdy schodki nie są jednakowo szerokie. W celu określenia błędu liniowości należy najpierw dokonać regulacji zera oraz wzmocnienia i określić maksymalną odchyłkę napięcia wejściowego od idealnej prostej. Wartość ta, po odjęciu systematycznego błędu kwantyzacji f/LSB/2, stanowi całkowity błąd liniowości. Podaje się go zazwyczaj w postaci ułamka jednostki podstawowej równej najmniej znaczącemu bitowi. W przykładzie z rys. 4.97 wynosi on ± ULSB/2. Inną miarą liniowości jest różniczkowy błąd liniowości. Mówi on, o ile szerokość poszczególnych schodków różni się od wartości zadanej 1LSB. Jeżeli błąd ten jest większy od LSB, to występuje „przeskakiwanie" niektórych cyfr (ang. missing code). Przy jeszcze większych odchyłkach liczba L może nawet maleć przy wzroście napięcia wejściowego (błąd monotoniczności). Błędy dynamiczne Można wyróżnić dwie dziedziny zastosowań przetworników A/C: jedną z nich są woltomierze cyfrowe, a drugą - przetwarzanie sygnałów. W woltomierzach cyfrowych zakłada się, że w czasie przetwarzania napięcie wejściowe ma wartość stałą, natomiast przy przetwarzaniu sygnału napięcie wejściowe stale się zmienia. Z tego napięcia zmiennego, w celu poddania go obróbce cyfrowej, pobiera się w równych odstępach czasu próbki za pomocą układu próbkująco-pamiętającego. Przetwornik A/C przetwarza te próbki na liczby. Powstający ciąg liczb {L} reprezentuje ciągły sygnał wejściowy bez utraty informacji tylko wówczas, gdy jest spełnione twierdzenie o próbkowaniu. Zgodnie z tym częstotliwość próbkowania fp musi być wiec co najmniej dwa razy większa od maksymalnej częstotliwości sygnału fmax. Wynika stąd wymaganie, by czas przetwarzania przetwornika A/C i czas akwizycji układu próbkująco-pamiętającego były razem mniejsze niż l/(2fmax). Aby móc zrealizować to wymaganie przy założonym nakładzie kosztów, ogranicza się szerokość pasma sygnału do koniecznej wartości. W tym celu na wejście włącza się najczęściej filtr dolnoprzepustowy. Do oceny dokładności należy rozważać wspólnie właściwości przetwornika A/C i układu próbkująco-pamiętającego. Nie ma np. sensu współpraca dwunastobitowego przetwornika A/C z układem próbkująco-pamiętającym, który w będącym do dyspozycji czasie nie osiąga wartości ustalonej z dokładnością do 1/4096 « 0,025% zakresu wysterowania. 95 Inny błąd dynamiczny jest spowodowany niepewnością chwili pobrania próbki (niestałością apertury). Czas opóźnienia apertury td układu próbkująco-pamiętającego powoduje pobranie próbki z opóźnieniem. Gdy czas opóźnienia apertury jest stały, każda próbka jest opóźniona o ten sam czas. Dzięki temu jest zapewnione próbkowanie w równych odstępach czasu. Jeżeli jednak czas opóźnienia -jak na rys. 4.99 - zmienia się o wartość niestałości (drżenie) apertury ∆fd, to powstaje błąd pomiaru, który jest równy zmianie napięcia ∆U. Rysunek 4.99. Wpływ niestałości (drżenia) apertury W celu obliczenia maksymalnego błędu ∆U załóżmy, że sygnał wejściowy jest przebiegiem sinusoidalnym o maksymalnej przewidzianej częstotliwości fmax. Największe nachylenie występuje przy przejściu przez zero Otrzymujemy stąd błąd amplitudy: Jeżeli ma on być mniejszy od jednostki podstawowej ULSB przetwornika A/C, to otrzymuje się warunek na niestałość apertury Przy wielkich częstotliwościach sygnału warunek ten jest bardzo trudno spełnić, jak to widać na następującym przykładzie liczbowym: Dla przetwornika ośmiobitowego ULSB/Umax = 1/255. Jeżeli maksymalna częstotliwość sygnału wynosi 10 MHz, to niestałość apertury powinna być mniejsza niż 125 ps. 4.11. Układy próbkująco-pamiętające (S/H) Ważną grupą układów współpracujących z przetwornikami analogowo-cyfrowymi są układy próbkującopamiętające (ang. sample&hold – S/H). Podstawowe pojęcia Napięcie wyjściowe układu próbkująco-pamiętającego (ang. sample&hold circuit) w stanie włączenia powinno śledzić napięcie wejściowe. W tym stanie układ ten zachowuje się więc jak przełącznik analogowy. W stanie wyłączenia napięcie wyjściowe nie powinno jednak spaść do zera, lecz powinno być równe napięciu w chwili wyłączania. Ze względu na te właściwości układy próbkująco-pamiętające noszą również nazwę układów śledząco-pamiętających (ang. track&hold circuits). 96 Rysunek 4.100. Podstawowy układ próbkująco-pamiętający Zasadniczy schemat układu próbkująco-pamiętającego jest przedstawiony na rys. 4.100. Głównym elementem układu jest kondensator pamiętający C. Gdy klucz K jest zamknięty, wówczas kondensator jest ładowany do napięcia wejściowego. Aby nie powodowało to obciążenia źródła napięcia wejściowego, stosuje się układ dopasowujący impedancję. Na rysunku 4.100 zrealizowano go za pomocą wtórnika napięciowego WO1. Musi on dostarczać dużych prądów wyjściowych, umożliwiających szybkie przeładowanie kondensatora pamiętającego. Jeżeli klucz K jest otwarty, to napięcie na kondensatorze C powinno jak najdłużej pozostać bez zmian. Dlatego za kondensatorem jest włączony wtórnik napięciowy separujący obciążenie. Oprócz tego przełącznik musi mieć dużą rezystancję w stanie wyłączenia, a kondensator - izolację wysokiej jakości. Porównanie zmian napięcia na kondensatorze w idealnym układzie i w rzeczywistym ukł. próbkująco-pamiętającym przedstawiono na rys. 4.101. Rysunek 4.101. Definicje parametrów układu próbkująco-pamiętającego. Przykładowo podano dane typowe układu LF 398 z kondensatorem pamiętającym 1nF. Czas trwania fazy śledzenia musi być co najmniej równy czasowi akwizycji Po zamknięciu klucza K napięcie wyjściowe nie osiąga natychmiast wartości napięcia wejściowego, lecz narasta z szybkością określoną przez maksymalną szybkość zmian sygnału na wyjściu (ang. slew rate). Ogranicza ją przede wszystkim maksymalny prąd wejściowego wtórnika napięciowego. Potem następuje stan nieustalony, którego czas trwania zależy od tłumienia wprowadzanego przez wtórnik i od rezystancji klucza w stanie włączenia. Jako czas akwizycji tA (ang. acąuisition time) definiuje się czas, który upływa od chwili pojawienia się sygnału zamykającego klucz do chwili, kiedy napięcie wyjściowe osiągnie wartość równą napięciu wejściowemu z zadaną dokładnością. Jeżeli stopień naładowania kondensatora pamiętającego zależy wyłącznie od rezystancji klucza w stanie włączenia RON, to czas aktywacji można obliczyć na podstawie przebiegu ładowania układu RC i wymaganej dokładności ustalania. Otrzymuje się wtedy: Na początku fazy pamiętania od chwili pojawienia się sygnału otwierającego klucz do chwili jego otwarcia upływa pewien czas. Czas ten nosi nazwę czasu opóźnienia apertury td (ang. aperture delay). Przeważnie 97 nie ma on stałej wartości, lecz ulega wahaniom, często zależnym od wartości napięcia wejściowego. Wahania te noszą nazwę niestałości (drżenia) apertury atd (ang. aperture jitter). Po upływie tego czasu napięcie wyjściowe najczęściej nie ma jeszcze stałej, zapamiętanej wartości, lecz następuje niewielki skok napięcia zwany piedestałem (ang. hold step), z następującym po nim stanem nieustalonym. Bierze się on stąd, że przy wyłączaniu pewien niewielki ładunek jest przekazywany przez pojemność klucza CK z obwodu sygnału sterującego do kondensatora pamiętającego C. Występujący przy tym skok napięcia wynosi gdzie ∆Us jest amplitudą sygnału sterującego. Zakłócenie to jest więc tym mniejsze, im większą wybierzemy wartość C. Kolejnym parametrem układu jest przenik (ang. feedthrough). Wynika on stąd, że mimo otwartego klucza napięcie wejściowe oddziałuje na wyjście. Zjawisko to jest wywołane głównie przez pojemnościowy dzielnik napięcia, utworzony z pojemności otwartego klucza i kondensatora pamiętającego. Najważniejszym parametrem w stanie pamiętania jest spadek napięcia na kondensatorze pamiętającym, zwany zwisem (ang. droop). Zależy on głównie od prądu wejściowego wtórnika wyjściowego oraz prądu upływu klucza. Przy prądzie rozładowania IL otrzymuje się: W celu minimalizacji prądu rozładowania, jako WO2 stosuje się wzmacniacz z wejściem na tranzystorach polowych. Nietrudno zauważyć, że wszystkie parametry w stanie pamiętania są tym lepsze, im większa jest wartość C, natomiast przy śledzeniu C powinno być jak najmniejsze. Dlatego też - w zależności od zastosowania - musimy się zdecydować na kompromis. W dotychczasowych rozważaniach zakładaliśmy, że kondensator pamiętający ma idealne właściwości. Istnieją kondensatory o praktycznie pomijalnie małym prądzie wyładowania samoistnego. Mimo to w stanie pamiętania może wystąpić zmiana napięcia wywołana magazynowaniem ładunku w dielektryku. Zjawisko to wyjaśnia schemat zastępczy kondensatora pokazany na rys. 4.102. Kondensator C1 reprezentuje ładunek zmagazynowany w dielektryku. Przy skokowej zmianie napięcia ładunek ten początkowo nie ulega zmianie; przeładowanie następuje dopiero z upływem czasu. Jeżeli okres próbkowania jest krótki, to potrzebny do tego ładunek jest pobierany z kondensatora C podczas fazy pamiętania. Przy skoku napięcia o wartość U otrzymuje się wskutek tego dodatkową zmianę napięcia: Rysunek 4.102. Schemat zastępczy kondensatora (parametry podane na rys. dotyczą kondensatora 1µF z dielektrykiem mylarowym) Przy parametrach takich, jak podane na rys. 4.102, stanowi to 0,6%. Stosunek C1/C zależy od rodzaju dielektryka. Dobre właściwości pod tym względem mają teflon, polistyren i polipropylen, natomiast właściwości poliwęglanu, mylaru i większości dielektryków ceramicznych nie są dobre. Tablica 4.37. Typowe dane scalonych układów próbkująco-pamiętających 98 4.12. Układy kluczy i multiplekserów analogowych Inną ważną grupą układów współpracujących z przetwornikami analogowo-cyfrowymi są układy kluczy analogowych oraz multiplekserów analogowych pozwalającw na doprowadzenie do przetwornika analogowo-cyfrowego większej liczby sygnałów analogowych. Klucz (przełącznik) analogowy powinien włączać i wyłączać ciągły sygnał wejściowy. Jeżeli jest włączony, to napięcie wyjściowe powinno być z możliwie dużą dokładnością równe napięciu wejściowemu; jeżeli jest wyłączony powinno być równe zeru. Najważniejsze właściwości przełącznika analogowego charakteryzują następujące parametry: - rezystancja w stanie włączenia; - rezystancja w stanie wyłączenia; - zakres napięć analogowych; - czasy przełączeń. Układy kluczy Istnieją różne układy pracy kluczy, spełniające stawiane im zadania. Pokazano je na rys. 4.103. Rysunek 4.103. Klucze: a) szeregowy, b) równoległy, c) szregowo-równoległy Na rysunku 4.103a przedstawiono klucz szeregowy. Jeśli jest on zamknięty, to Uwy = Uwe. Jeśli klucz zostanie otwarty, to napięcie wyjściowe staje się równe zeru. Dzieje się tak jednak tylko przy braku obciążenia. Przy obciążeniu pojemnościowym ze względu na skończoną wartość rezystancji wyjściowej 99 Rwy = R napięcie spada wolno do zera. Wady tej nie ma klucz równoległy pokazany na rys. 4.103b. Za to w stanie włączenia, a więc przy otwartym zestyku, ma on skończoną rezystancję wyjściową Rwy = R. Klucz szeregowo-równoległy z rys. 4.103c łączy zalety obu poprzednich układów. W obu stanach ma małą rezystancję wyjściową. Rezystancja w stanie włączenia jest niewielka, a w stanie wyłączenia duża. Zwarte w stanie wyłączenia wyjście może jednak stanowić przeszkodę. Jest tak np. wtedy, kiedy napięcie wyjściowe chcemy zapamiętać na kondensatorze, jak w układach próbkująco-pamiętających omówionych w poprzednim punkcie. Możemy wówczas dodać jeszcze jeden zestyk K3, jak na rys. 4.104. Rysunek 4.104. Klucz szeregowy o zwiększonym tłumieniu Rysunek 4.105. Analogowy multiplekser/demultiplekser Gdy klucz jest otwarty, wówczas sygnał wejściowy sprzężony pojemnościowo przez K1 jest zwierany przez zestyk K2; wyjście jednak - ze względu na K3 - jest w stanie wysokiej impedancji. Układ ten zachowuje się więc na zewnątrz tak jak klucz szeregowy z rys. 4.103a; charakteryzuje się jednak znacznie lepszym tłumieniem dla wielkich częstotliwości. Układ o większej liczbie wejść przedstawiono na rys. 4.105. Z czterech zestyków jest zawsze zamknięty tylko jeden, wskutek czego napięcie wyjściowe jest równe odpowiedniemu napięciu wejściowemu. Dlatego układ ten nosi również nazwę multipleksera analogowego. Jeśli układ odwrócimy, zachowując tylko jedno wejście, to otrzymamy demultiplekser analogowy. Klucze elektroniczne Do realizacji kluczy stosuje się tranzystory polowe, diody lub tranzystory bipolarne. Mają one różne właściwości, ale ogólnie schemat układu, w którym te elementy grają rolę kluczy, jest zawsze taki sam. Przedstawiono go na rys. 4.106. Rysunek 4.106. Układ sterowania klucza Sygnały sterujące, najczęściej zgodne ze standardem TTL, są wzmacniane przez bramkę mocy (bufor). Za nią znajduje się układ dopasowania poziomu (tzw. translator), wytwarzający napięcia potrzebne do otwierania i zamykania klucza. Tranzystor polowy jako klucz Tranzystor polowy przy małych napięciach dren-źródło zachowuje się tak jak rezystor, którego wartość można zmieniać o kilka rzędów wartości za pomocą napięcia bramka-źródło UGS; może więc pracować jako klucz. Na rysunku 4.107 pokazano tranzystor polowy pracujący w układzie klucza szeregowego. Jeżeli napięcie sterujące UST będzie co najmniej o napięcie odcięcia UP mniejsze od najniższego ujemnego napięcia 100 wejściowego, to tranzystor polowy nie będzie przewodził i napięcie wyjściowe będzie równe zeru. Żeby tranzystor mógł przewodzić, napięcie UGS powinno być równe zeru. Warunek ten nie jest łatwy do spełnienia, ponieważ potencjał źródła nie jest ustalony. Układ umożliwiający spełnienie tego warunku przedstawiono na rys. 4.108. Rysunek 4.107. Klucz z tranzystorem polowym Rysunek 4.108. Uproszczenie sterowania klucza Jeżeli w tym układzie UST będzie większe niż najwyższe dodatnie napięcie wejściowe, to dioda nie przewodzi i mamy zgodnie z życzeniem UGS = 0. Przy wystarczająco ujemnym napięciu sterującym dioda przewodzi i tranzystor jest zatkany. W tym stanie pracy prąd ze źródła napięcia wejściowego płynie przez rezystor R1 do obwodu sterowania. W normalnych warunkach nie stanowi to przeszkody, ponieważ napięcie wejściowe jest i tak równe zeru.Trudności mogą wystąpić wówczas, gdy napięcie wejściowe jest podawane przez kondensator sprzęgający, ponieważ w fazie nieprzewodzenia jest on ładowany napięciem ujemnym. Problemy te nie występują, gdy jako klucz zastosujemy tranzystor MOS-FET. Tranzystor MOSFET z kanałem typu n można wprowadzić w stan przewodzenia przez podanie napięcia sterującego większego od najwyższego dodatniego napięcia wejściowego, nie obawiając się, że popłynie prąd bramka-kanał. 101 Można więc zrezygnować z diody D i rezystora Rt. Aby zwiększyć zakres dopuszczalnych napięć wejściowych, zamiast pojedynczego tranzystora MOS należy zastosować klucz CMOS, składający się z dwu komplementarnych tranzystorów MOSFET połączonych równolegle, jak na rys. 4.109. Aby klucz przewodził, na bramkę tranzystora T1 z kanałem n podajemy napięcie U+, a bramkę tranzystora T2 z kanałem p łączymy z masą. Rysunek 4.109. Klucz szeregowy Rysunek 4.110. Zależność rezystancji od napięcia wejściowego CMOS dla Usr=USTON=U+=5V Przy średnich napięciach wejściowych Uwe oba tranzystory MOSFET przewodzą. Jeżeli napięcie wejściowe wzrośnie, to zmniejsza się UGS1. Wskutek tego rezystancja tranzystora T1 wzrasta. Nie stanowi to jednak przeszkody, ponieważ równocześnie rośnie moduł UGS2, wskutek czego rezystancja T2 maleje. Przedstawiono to na rys. 4.110, z którego wynika, że napięcie wejściowe może przyjąć każdą wartość miedzy 0 i U+. W przypadku standardowych kluczy CMOS napięcie wejściowe nie może przekroczyć tego zakresu, ponieważ wskutek tzw. zatrzaśnięcia się (ang. latch up) klucz może ulec zniszczeniu. W tym bowiem przypadku zaczyna przewodzić dioda kanał-podłoże, dostarczając nośników ładunku do podłoża. Mogą one spowodować włączenie pasożytniczego tyrystora, który zwiera napięcie zasilania. Jeżeli nie możemy zagwarantować bezpiecznego zakresu napięć wejściowych, to należy dołączyć szeregowo rezystor ograniczający prąd do l mA. Prąd ten jest z reguły mniejszy od prądu włączania tyrystora. Ze względu na te trudności większość scalonych kluczy CMOS jest wyposażona w dodatkowe układy zabezpieczające lub ma izolację dielektryczną. Podłoże nie jest wówczas izolowane za pomocą złącza pn, lecz za pomocą warstwy tlenku. Dlatego w elementach CMOS z izolacją dielektryczną nie występuje zjawisko zatrzaskiwania. W tablicy 4.38 przedstawiono parametry najczęściej używanych kluczy CMOS i multiplekserów. Układy z serii 74HC są normalnymi bramkami CMOS o bardzo niskiej cenie. Mogą się jednak zatrzaskiwać i mają ograniczony zakres dopuszczalnych napięć wejściowych. Pozostałe układy mają izolację dielektryczną i ich stosowanie nie nastręcza kłopotów. Wymienieni producenci oferują ponadto wiele innych typów kluczy, z których przykładowo wymieniono tylko kilka. Typowe prądy upływu kluczy w temperaturze pokojowej wynoszą 0,1... l nA. Podwajają się one przy wzroście temperatury o 10° i mogą wzrosnąć nawet do 100 nA. Tablica 4.38. Przykłady kluczy analogowych CMOS 102 103 Tablica 4.39. Przykłady analogowych multiplekserów CMOS 4.13. Układy przetworników C/A Przetworniki analogowo-cyfrowe (A/C, ang. analog to digital converter, ADC) umożliwiają przedstawienie napięcia analogowego w postaci liczby L gdzie ULSB jest napięciem odpowiadającym najmniej znaczącemu bitowi (ang. least significant bit, LSB), czyli napięciem odpowiadającym L = l. W celu przekształcenia odwrotnego: liczby na napięcie, stosuje się przetworniki cyfrowo-analogowe (C/A, ang. digital to analog converter, DAC). Ich napięcie wyjściowe jest proporcjonalne do wprowadzonej liczby zgodnie z zależnością Zadaniem przetwornika C/A jest przetworzenie liczby na napięcie. Można wyróżnić trzy różniące się zasadniczo metody przetwarzania: - równoległą; - wagową; - zliczania. Metody te przedstawiono poglądowo na rys. 4.111. W metodzie równoległej (rys. 4.111a) dzielnik napięcia dostarcza wszystkich możliwych napięć, a dekoder l z n powoduje zamknięcie tego klucza, któremu odpowiada żądane napięcie wyjściowe. 104 W metodzie wagowej (rys. 4.111 b) każdemu bitowi jest przyporządkowany jeden klucz. Napięcie wyjściowe jest sumowane za pomocą rezystorów o odpowiednich wagach. Metoda zliczania (rys. 4.111c) wymaga zastosowania tylko jednego klucza, który jest okresowo otwierany i zamykany. Impulsy prądu powodują ładowanie się kondensatora do napięcia proporcjonalnego do liczby zamknięć klucza lub współczynnika wypełnienia (szerokości) impulsu. Rysunek 4.111. Metoda przetwarzania cyfrowo-analogowego: a) metoda równoległa, b) metoda wagowa, c) metoda zliczania Porównanie tych trzech metod wskazuje, że metoda równoległa wymaga Lmax kluczy, metoda wagowa log2Lmax kluczy, a metoda zliczania - tylko jednego klucza. Ze względu na dużą liczbę kluczy metoda równoległa jest stosowana rzadko. Coraz większe znaczenie zdobywa metoda zliczania, ponieważ modulator szerokości impulsów jest układem cyfrowym dającym się łatwo scalić. Jeżeli układ pracuje z częstotliwością znacznie większą od wymaganej częstotliwości próbkowania (z tzw. próbkowaniem nadmiarowym, oversampling), upraszcza się dzięki temu wymagany filtr dolnoprzepustowy. Największe znaczenie mają przetworniki C/A pracujące według metody wagowej. Klucze są realizowane dwoma sposobami: w układach CMOS są stosowane bramki transmisyjne, a w układach bipolarnych stosuje się przełączanie prądów o stałej wartości za pomocą diod lub wzmacniaczy różnicowych. Sumowanie ważonych prądów Prosty układ przetwarzający liczbę dwójkową na proporcjonalne do niej napięcie jest przedstawiony na rys. 4.112. Rezystancje są dobrane tak, że przy zamkniętym kluczu płynie prąd odpowiadający wadze danej pozycji. Klucze muszą być zamknięte zawsze wówczas, gdy na danej pozycji występuje jedynka logiczna. Dzięki objęciu wzmacniacza operacyjnego ujemnym sprzężeniem zwrotnym za pomocą rezystancji RF, wejście odwracające jest zawsze na potencjale równym zeru. Rysunek 4.112. Zasada działania przetwornika A/C 105 Prądy składowe są więc sumowane, nie wpływając na siebie wzajemnie. Gdy zamknięty jest klucz sterowany sygnałem 0, wówczas napięcie wyjściowe wynosi W ogólnym przypadku mamy: Wynika stąd: 106 5. Budowa i zasada działania mikrokontrolerów o arch. standardowej Uproszczony schemat mikrokontrolera przedstawiony na rysunku 5.1 ilustruje jego najważniejsze zespoły funkcjonalne. Są one skupione wokół jednostki centralnej (CPU), która realizuje ciąg operacji (program) zapisany w pamięci programu. Rysunek 5.1. Uproszczony schemat funkcjonalny mikrokontrolera Przykład programu realizowanego przez CPU: 00001111 00000111 00000000 01111000 00000000 01111000 00011000 01100011 00001111 01111110 Program może mieć za zadanie przetworzenie danych zapisanych wcześniej w pamięci danych i/lub współpracę z urządzeniami przyłączonymi z zewnątrz przez linie wejścia/wyjścia. Dane i program są reprezentowane w postaci cyfrowej jako ciągi słów dwójkowych (binarnych) i przesyłane między jednostką centralną a pamięciami danych i programu przez wewnętrzną szynę danych. Jeśli przez n oznaczymy liczbę linii danych tej szyny, to mikrokontroler nazywamy n-bitowym, jest on bowiem zdolny do wykonywania operacji na liczbach n-bitowych. Większość dostępnych mikrokontrolerów operuje na danych o wielkości będącej wielokrotnością bajtu, czyli ośmiu bitów, zatem n = 8k, ( k = l, 2, ...). Liczba linii adresowych, którymi jednostka centralna adresuje pamięć danych i programu, jest oznaczona przez m. Linie te tworzą wewnętrzną szynę adresową. Przez wielkość przestrzeni adresowej wewnętrznej pamięci mikrokontrolera rozumie się liczbę wszystkich możliwych adresów równą 2m. Dla przykładu, jeśli m = 16, to przestrzeń adresowa ma wielkość 64 kilosłów 8bitowych lub w skrócie 64 k (lk = 1024). W większości prostych mikrokontrolerów szyna adresowa 107 jest jednokierunkowa, ponieważ jedynym źródłem adresów jest jednostka centralna. Szyna danych jest natomiast dwukierunkowa i umożliwia zarówno odczyt, jak i zapis danych przez CPU. Jednostka centralna jest synchronicznym układem sekwencyjnym. W teorii układów cyfrowych przez układ synchroniczny rozumie się układ, w którym zmiany stanów wewnętrznych, a w konsekwencji również sygnałów wyjściowych, zachodzą w chwilach czasu określonych przez sygnał synchronizujący. Najczęściej jest on okresowy i pochodzi z generatora nazywanego zegarem (ang. clock). Częstotliwość impulsów zegarowych jest stabilizowana przez przyłączany z zewnątrz rezonator kwarcowy. Termin „sekwencyjny" odnosi się natomiast do układów cyfrowych, których stan w kolejnym cyklu zegara zależy nie tylko od sygnałów wejściowych, ale również od stanu w poprzednim cyklu zegara. Początkowy stan jednostki centralnej, któremu odpowiada ściśle określony adres początkowy pamięci programu, jest wymuszany przy użyciu sygnału RESET. Może on być generowany przez operatora ręcznie przez wciśnięcie odpowiedniego przycisku, wytwarzany programowo, pochodzić z innego systemu cyfrowego lub być wynikiem włączenia zasilania (ang. power-on). Budowa i działanie układów wejścia/wyjścia oraz układów peryferyjnych są zróżnicowane w zależności od konkretnego typu mikrokontrolera. Najprostsze mikrokontrolery są wyposażone jedynie w zespoły linii wejścia/wyjścia z wewnętrznym buforowaniem, nazywane portami (ang. ports). Budowa i działanie układów wejścia/wyjścia oraz układów peryferyjnych są zróżnicowane w zależności od konkretnego typu mikrokontrolera. Najprostsze mikrokontrolery są wyposażone jedynie w zespoły linii wejścia/wyjścia z wewnętrznym buforowaniem, nazywane portami (ang. ports). Każdy port zawiera zwykle osiem linii i służy do równoległej transmisji bajtów danych. Stosuje się też linie do szeregowej transmisji danych (ang. serial port) pracujące w asynchronicznym trybie UART (ang. universal asynchronous receiver-transmitter) lub zdolne do pracy w trybie synchronicznym bądź asynchronicznym, nazywanym USART (ang. universal synchronous-asynchronous receiver--transmitter). Bardziej rozbudowane mikrokontrolery zawierają ponadto wbudowane układy przetworników analogowo-cyfrowych (A/C, ang. ADC - analog-to-digital converter) i rzadziej również przetworników cyfrowo-analogowych (C/A, ang. DAĆ - digital-to-analog converter). Ze strony cyfrowej mają one zwykle rozdzielczość ośmiu bitów, w bardziej zaawansowanych mikrokontrolerach spotyka się natomiast przetworniki 10-, a nawet 12-bitowe. Do układów peryferyjnych zalicza się również liczniki, nazywane niekiedy w literaturze polskiej „tajmerami" (ang. timers). W zależności od sposobu zaprogramowania mogą one zliczać impulsy zegara i służyć do wyznaczania ściśle określonych odstępów czasu lub liczyć impulsy doprowadzone z zewnątrz. Ze względu na ścisłe powiązanie liczników z algorytmami sterowania w czasie rzeczywistym są one często nazywane układami czasowymi. Najczęściej spotyka się liczniki o długości 16 bitów. Podana wyżej krótka lista typowych układów wejścia/wyjścia i układów peryferyjnych nie wyczerpuje bogactwa ich odmian spotykanych w konkretnych typach mikrokontrolerów. Niektóre z nich wykorzystują specyficzne interfejsy, np. SPI lub I2C, używane jako standard przemysłowy w elektronice powszechnego użytku (Philips). Na tle zarysowanej wstępnie wewnętrznej budowy mikrokontrolera można określić zasadnicze różnice i podobieństwa między mikrokontrolerem i mikroprocesorem. Standardowy mikroprocesor składa się z jednostki centralnej i szczątkowej pamięci danych w postaci zbioru rejestrów. Większość nowoczesnych mikroprocesorów zawiera również generator zegara. Mikroprocesory nie mają natomiast wbudowanej pamięci programu i układów we/wy ani układów peryferyjnych. 108 Mikrokontroler może być zatem uważany w pierwszym przybliżeniu za mikroprocesor z wbudowanymi dodatkowo układami pamięci i układami do komunikacji z otoczeniem. Ważna różnica dotyczy ponadto zbioru operacji realizowanych przez CPU, nazywanego listą instrukcji (ang. instruction set). W przypadku mikroprocesorów lista instrukcji jest zaprojektowana pod kątem ułatwienia obliczeń numerycznych i transmisji danych, natomiast mikrokontrolery mają rozbudowane grupy instrukcji do obsługi urządzeń peryferyjnych. Jednostka centralna mikrokontrolera (a także mikroprocesora) składa się z dwóch podstawowych zespołów funkcjonalnych, nazywanych układem sterowania i układem wykonawczym, powiązanych ze sobą w sposób pokazany na rysunku 5.2. Zadaniem układu sterowania (CU, ang. contro! unit) jest koordynacja pracy poszczególnych zespołów funkcjonalnych mikrokontrolera w trakcie wykonywania programu. Układ ten otwiera bądź zamyka przepływ danych między zespołami przyłączonymi do szyny danych oraz generuje sygnały sterujące pracą zespołów funkcjonalnych. Rysunek 5.2. Struktura jednostki centralnej mikrokontrolera (mikroprocesora) Blok wykonawczy (EU, ang. execution unit) realizuje natomiast operacje określone przez sygnały sterujące. Operacje mogą dotyczyć zarówno danych, jak i adresów. Decyzje o przebiegu każdej kolejnej operacji blok sterowania podejmuje na podstawie zakodowanych rozkazów przesyłanych przez szynę danych oraz sygnałów stanu generowanych przez układ wykonawczy. Sygnały sterujące są przesyłane przez dwukierunkową szynę sygnałów sterowania, nazywaną w skrócie szyną sterowania. Łączy ona układ sterowania z wszystkimi pozostałymi zespołami funkcjonalnymi mikrokontrolera. Na uproszczonych schematach blokowych mikrokontrolerów i mikroprocesorów szynę sterowania często pomija się, by poprawić czytelność rysunku 5.1. Standardowa architektura mikrokontrolera Rozważmy standardowy mikrokontroler przedstawiony na rysunku 5.3. Jego struktura bywa nazywana jednoszynową, ponieważ wszystkie bloki wewnętrzne mikrokontrolera są połączone przez wspólną szynę danych. Szyna ta łączy się z zewnętrzną szyną danych przez bufor, który spełnia dwa zadania. Zapewnia odpowiednie parametry elektryczne sygnałów na wyprowadzeniach obudowy mikrokontrolera, w tym odpowiednią obciążalność wyjść oraz umożliwia czasowe odłączenie mikrokontrolera od zewnętrznej szyny danych. W tym celu bufor jest wyposażony w wyjścia trójstanowe (ang. three-state out-puts). W trzecim stanie, charakteryzującym się wysoką impedancją, wyjścia bufora mogą być traktowane jako rozwarte. 109 Rysunek 5.3. Budowa wewnętrzna standardowego mikrokontrolera W dużych systemach cyfrowych, w których do zewnętrznej szyny danych jest przyłączonych wiele różnych układów cyfrowych (np. kilka mikrokontrolerów lub mikroproce-sorów), zablokowanie buforów w wybranych układach pozwala uniknąć kolizji na szynie. Kolizja taka mogłaby powstać, gdyby linie szyny danych były sterowane jednocześnie przez kilka różnych układów. Zazwyczaj liczba linii zewnętrznej szyny danych jest taka sama, jak liczba linii wewnętrznej szyny danych. Niekiedy stosuje się multipleksowanie szyny danych. W mikrokontrolerach tego rodzaju (np. 80C51) liczba linii zewnętrznej szyny danych jest mniejsza i do prawidłowego połączenia obu szyn niezbędny jest multiplekser. Przesłanie n-bitowej liczby przebiega wtedy w dwóch lub w większej liczbie kroków. Transmisja danych jest wówczas wolniejsza, ale za to obudowa mikrokontrolera ma mniejszą liczbę wyprowadzeń. Z tego powodu często stosuje się również multipleksowanie szyny danych z częścią linii szyny adresowej. Rysunek 5.4. Budowa wewnętrzna mikrokontrolera z multipleksowaną szyną Szyna adresowa mikrokontrolera z rys. 5.4 została przedstawiona w dużym uproszczeniu. Pominięto na nim wewnętrzną szynę adresową, służącą do adresowania wewnętrznych pamięci. Mechanizm generowania adresów wew. i zew. jest podobny. Pochodzą one z rejestru adresowego i dotyczą danych albo zakodowanych rozkazów umieszczonych w pamięci programu. Liczba linii wewnętrznej i zew. szyny danych zależy od typu mikrokontrolera. W najprostszych układach z 110 niewielką pamięcią wew. stosuje się 8-bitowe adresy danych (256 bajtów) i 12-bitowe adresy rozkazów (4 kB pamięci programu). Zewnętrzna szyna adresowa ma natomiast 16 linii i umożliwia zaadresowanie 64 kB pamięci zewnętrznej. Najbardziej rozbudowane układy, a zwłaszcza procesory typu embedded, wykorzystują dłuższe adresy, nawet 32-bitowe. 5.2. Układ wykonawczy Układ wykonawczy prostego mikrokontrolera ostał pokazany na rysunku 5.5 Rysunek 5.5. Budowa wewnętrzna standardowego mikrokontrolera Składa się on z następujących elementów: - jednostki arytmetyczno-logicznej ALU (ang. arithmetic-logic unit), akumulatora A (ang. accumulator), - rejestru przejściowego, nazywanego też tymczasowym (ang. temporaryregister), - rejestru wskaźników, określanego też jako rejestr warunków, flag lub rejestr stanu (ang. status flags). 5.2.1. Jednostka ALU Zadaniem jednostki arytmetyczno-logicznej jest wykonywanie operacji arytmetycznych (np. dodawania) i logicznych (np. sumy logicznej) na argumentach zawartych w akumulatorze i rejestrze przejściowym. Repertuar operacji realizowanych przez ALU jest określony przez listę instrukcji konkretnego typu mikrokontrolera. Proste typy mikrokontrolerów wykonują bardziej złożone zadania w sposób programowy, np. mnożenie jest realizowane przez sekwencję operacji dodawania. Na wyjściu ALU znajduje się szybki rejestr przesuwający (ang. barrel shifter), który realizuje operacje przesunięcia wyniku operacji ALU o jeden bit w prawo (\v stronę najmniej znaczącego bitu) oraz o jeden bit w lewo (w stronę najbardziej znaczącego bitu). Możliwa jest też transmisja wyniku bez przesunięcia. W realizowanych przez mikrokontroler algorytmach bardzo często oprócz wyników produkowanych przez ALU istotne są także ich pewne szczególne konsekwencje, jak np. wynik równy zeru, przeniesienie z najbardziej znaczącego bitu, znak wyniku itp. Informacje te są pamiętane w rejestrze wskaźników. Specjalne instrukcje pozwalają testować stan poszczególnych bitów tego rejestru i wykonywać na tej podstawie rozgałęzienia w programie. Są też instrukcje, które uwzględniają ustawiony wcześniej stan bitu przeniesienia jako trzeci argument. W ten sposób można np. zrealizować dodawanie z przeniesieniem, w którym oprócz zawartości akumulatora i rejestru przejściowego uczestniczy bit przeniesienia w rejestrze wskaźników. Zilustrowano to na rysunku 5.6, który przedstawia strukturę rejestru 111 wskaźników przykładowego mikrokontrolera (80C51 XA), wykorzystanie słowa wskaźników do sterowania rozgałęzieniem programu oraz realizację dodawania z przeniesieniem. Rysunek 5.6. a) rejestr wskaźników przykładowego mikrokontrolera (80C51 XA), b) przykład wykorzystania bitu Z do organizacji pętli w programie, c) przykład dodawania z uwzględnieniem bitu przeniesienia C Bit przeniesienia C (ang. carry) pełni podwójną rolę: służy do pamiętania przeniesienia z najbardziej znaczącego bitu przy operacjach arytme-tycznych oraz do zapamiętania bitu opuszczającego rejestr przesuwający. W niektórych typach mikroprocesorów bywa oznaczany symbolem CY. Jeśli bit C jest ustawiony (C = 1), to znaczy że przeniesienie wystąpiło. W przykładzie z rysunku 5.6c bit C został użyty w operacji dodawania dwóch 8-bitowych liczb z uwzględnieniem przeniesienia. Założono, że przed wykonaniem dodawania C = l. W wyniku podanego w przykładzie dodawania nowa wartość bitu C jest także równa l. W procesorze 80C51 rejestr wskaźników nosi nazwę PSW. Jego zawartość jak wspomniano opisuje cechy wyniku ostatnio wykonywanej operacji. bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0 C AC F0 RS1 RS0 OV P Słowo stanu PSW Rysunek 5.7. Rejestr PSW Znaczenie poszczególnych bitów jest następujące: Bit nadmiaru V (ang. overflow) służy do detekcji błędu określenia znaku wyniku w operacjach arytmetycznych na liczbach ze znakiem zapisanych w kodzie uzupełnień do dwóch (U2). Bit ten jest ustawiany, gdy operacja arytmetyczna powoduje przeniesienie na pozycję znaku. W niektórych typach mikrokontrolerów jest oznaczany symbolem O lub OV. Nadmiar ma miejsce, gdy bit V jest ustawiony (V = 1). Bit znaku N (ang. negative) jest określony przez najbardziej znaczący bit wyniku. Ustawiony bit N (N = 1) oznacza wynik ujemny. Niektórzy producenci mikrokontrolerów oznaczają ten bit symbolem S (ang. sign). Bit przeniesienia pomocniczego AC (ang. auxiliary carry), nazywany też bitem przeniesienia połówkowego i oznaczany symbolem H (ang. half carry), jest pomocny przy wykonywaniu operacji arytmetycznych na liczbach zapisanych w kodzie BCD (ang. binary coded decimal). Ustawiony bit 112 AC (AC = 1) oznacza, że w wyniku wykonania operacji wystąpiło przeniesienie z mniej znaczącej czwórki (tetrady) bitów, czyli z bitu b3 na bit b4, przy numeracji bitów od zera. Korzystając z bitu AC można dokonać korekcji wyniku operacji arytmetycznej na liczbach zapisanych w kodzie BCD. Bit zera Z (ang. zero] jest ustawiany (Z = 1), jeżeli wynikiem operacji jest zero. W przeciwnym przypadku bit ten ma wartość równą zeru. W przykładzie z rysunku 2.4,b bit Z został użyty do sterowania pętlą w programie. Początkowa wartość zapisana w akumulatorze jest równa 10. Po każdym wykonaniu treści pętli, reprezentowanej w tym przykładzie przez pewną operację X, następuje zmniejszenie zawartości akumulatora o jeden. Przy dziesiątym obiegu pętli odejmowanie jedynki od zawartości akumulatora da wynik równy zero i bit Z zostanie ustawiony. Instrukcja skoku warunkowego reprezentowana przez zapis w polu o kształcie rombu spowoduje wtedy zakończenie pętli i przejście do dalszego fragmentu programu. Niektóre typy mikrokontrolerów mogą oprócz wymienionych bitów zawierać w rejestrze wskaźników inne, dodatkowe bity. Jednym z nich jest bit parzystości P (ang. parity), który jest ustawiany, jeżeli wynik operacji zawiera parzystą liczbę jedynek. Parzystości P nie należy mylić z parzystością wyniku w sensie arytmetycznym - w tym znaczeniu parzystość liczby dwójkowej zależy bowiem wyłącznie od stanu najmniej znaczącego bitu tej liczby. Zasady, według których bity wskaźników są ustawiane i zerowane, muszą być precyzyjnie zdefiniowane w opisie listy rozkazów mikrokontrolera. Opis ten powinien ponadto określać wpływ stanu poszczególnych wskaźników na przebieg realizacji rozkazu. Układy wykonawcze mikrokontrolerów mogą być bardziej rozbudowane niż układ omówiony tu jako standardowy. Niektóre zawierają na przykład kilka mogących pracować równolegle jednostek arytmetyczno-logicznych. Jedna z nich, oznaczana jako FPU (ang. floatingpoint unii), jest zazwyczaj przeznaczona do wykonywania operacji na liczbach zmiennoprzecinkowych, czyli zapisanych w postaci mantysy i wykładnika. Struktura tego typu znacznie przyspiesza wykonywanie programu, ale poważnie komplikuje sterowanie szynami. 5.2.2. Rejestry Operacje wykonywane przez ALU wymagają dostarczenia na wejście jednego lub dwóch argumentów, nazywanych też operandami. ALU z trzema lub większą liczbą wejść praktycznie nie są stosowane. Przykładem operacji jednoargumentowej może być instrukcja zmiany znaku liczby na przeciwny. Liczbę tę wpisuje się do akumulatora. Po wykonaniu operacji do akumulatora trafia wynik w postaci liczby o zmienionym znaku i pierwotna zawartość akumulatora ulega zniszczeniu. Rysunek 5.8. Budowa wewnętrzna standardowego mikrokontrolera W przypadku operacji dwuargumentowych, na przykład dodawania, jeden z argumentów jest umieszczany w akumulatorze, a drugi w rejestrze przejściowym. Wynik dodawania również jest umieszczany w akumulatorze. Oczywiście, z uwagi na jednoszynową strukturę procesora, czynności 113 te muszą być wykonane kolejno, w odpowiednich odstępach czasu. Z funkcjonalnego punktu widzenia akumulator różni się od rejestru przejściowego tym, że jego zawartość może być odczytana i wysłana do innego rejestru lub do pamięci, natomiast zawartości rejestru przejściowego nie da się wyprowadzić na szynę. Na rysunku 5.8 cechę tę zaznaczono przez dwukierunkowe połączenie akumulatora z szyną danych i jednokierunkowe połączenie rejestru przejściowego. Konieczność umieszczania argumentów w akumulatorze i rejestrze przejściowym (dla operacji dwuargumentowych) bądź w samym akumulatorze (dla operacji jednoargumentowych) wymaga częstych operacji przesłań danych z udziałem akumulatora. Ponieważ, jak zobaczymy dalej, transmisje między akumulatorem a pamięcią danych są relatywnie wolne, wymagają bowiem przygotowania i wysłania adresu pamięci, do przechowywania wartości roboczych zmiennych używa się szybszego sposobu. Polega on na wykorzystaniu rejestrów roboczych, nazywanych rejestrami ogólnego przeznaczenia (ang. general purpose registers) lub w skrócie po prostu rejestrami. Zbiór rejestrów ma w rzeczywistości strukturę niewielkiej pamięci, jednak dostęp nie wymaga podawania adresu. Zamiast adresu w zapisie programu używa się nazw symbolicznych rejestrów, np. A, B, C itd. lub R0, Rl, R2 ... . Nazwy przypisane rejestrom roboczym, jak również ich liczba zależą od konkretnego typu mikrokontrolera. Typowe mikrokontrolery zawierają od kilku do kilkudziesięciu rejestrów. W dwójkowym kodzie programu nazwy rejestrów mogą być zatem zapisane przy użyciu tylko kilku bitów. Kod programu jest w związku z tym krótszy, a jego wykonanie szybsze niż w przypadku adresowania argumentów w pamięci. Przykładowa struktura zbioru rejestrów procesora 8051 została pokazana na rysunku 5.9. R0 R0 R0 R0 R1 R1 R1 R1 R2 R2 R2 R2 R3 R3 R3 R3 R4 R4 R4 R4 R5 R5 R5 R5 R6 R6 R6 R6 R7 R7 R7 R7 Bank 3 Bank 2 Bank 1 Bank 0 Rys. 5.9. Struktura rejestrów ogólnego przeznaczenia procesora 8051 Rejestry RO – R7 są powielone jako cztery zestawy nazywane bankami (ang. Banked registers). Można w nich przechowywać bajty. Podczas wykonywania programu w danym momencie dostępny jest tylko jeden bank. Programista może przełączać aktywny bank przy użyciu odpowiednich rozkazów. Mechanizm ten wprowadzono po to, by uzyskać efekt nazywany szybkim, kontekstowym przełączaniem rejestrów. Polega on na tym, że ten sam program (lub podprogram) może pracować na różnych zestawach danych w zależności od aktywnego banku rejestrów. Kolejną, ważną właściwością opisywanego zbioru rejestrów jest możliwość adresowania poszczególnych bitów w rejestrach. Dla przykładu zapis R0.7 oznacza bit b7 w rejestrze R0. Wyboru banku w procesorze 8051 dokonuje się przez zmianę wartości 2 bitów RS0 oraz RS1 znajdujących się w słowie stanu – PSW. Bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0 C AC F0 RS1 RS0 OV P Rysunek 5.10. Słowo stanu PSW Rysunek 5.11, pokazuje przykładowy podział rejestrów na grupy o różnych własnościach funkcjonalnych w innym procesorze - 80C51 XA. Część rejestrów, oznaczona symbolami R4 - R15, to rejestry globalne, a więc dostępne w dowolnym miejscu programu. Rejestry R8 - R15 są 16bitowe, przechowują zatem dwubajtowe słowa. Rejestry R4 - R7 mogą być natomiast używane 114 zarówno do przechowywania słów 16-bitowych, jak i pojedynczych bajtów. Na przykład R4H oznacza bardziej znaczący bajt rejestru R4, natomiast R4L - mniej znaczący bajt tego rejestru. Rysunek 5.11. Struktura rejestrów ogólnego przeznaczenia w mikrokontrolerze 80C51XA Rejestry RO - R3 są powielone jako cztery zestawy nazywane bankami (ang. banked registers). Można w nich również przechowywać albo bajty, albo słowa. Podczas wykonywania programu w danym momencie dostępny jest tylko jeden bank. Programista może przełączać aktywny bank przy użyciu odpowiednich rozkazów. Mechanizm ten wprowadzono po to, by uzyskać efekt nazywany szybkim, kontekstowym przełączaniem rejestrów. Polega on na tym, że ten sam program (lub podprogram) może pracować na różnych zestawach danych w zależności od aktywnego banku rejestrów. Dodatkową cechą zestawu rejestrów w mikrokontrolerze 80C51 XA jest możliwość łączenia niektórych z nich w pary o długości 32 bitów. Dotyczy to par rejestrów (R0, Rl), (R2, R3), (R4, R5) i (R6, R7). Kolejną, ważną właściwością opisywanego zbioru rejestrów jest możliwość adresowania poszczególnych bitów w rejestrach. Dla przykładu zapis R0.7 oznacza bit b7 w rejestrze R0. Rejestry R0 - R7 są implementowane we wszystkich odmianach mikrokontrolera 80C51 XA, natomiast rejestry R8 - R15 są dostępne tylko w niektórych odmianach tego układu. Oprócz zróżnicowania rejestrów wynikającego z ich długości, możliwości łączenia w pary i podziału na banki, rejestry różnią się od siebie pod jeszcze innym, ważnym kątem. Niektóre rozkazy mogą mianowicie współpracować tylko ze ściśle określonymi rejestrami. Wśród rejestrów występuje więc pewna specjalizacja pod względem przeznaczenia. Obok rejestrów ogólnego przeznaczenia mikrokontrolery zawierają dwie inne grupy rejestrów. Pierwsza z nich to rejestry specjalne (SFR, ang. special function registers), związane z układami wejścia/wyjścia, układami peryferyjnymi oraz systemem sterowania zasilaniem,. W przypadku procesora 8051 to między innymi: rejestr konfiguracji portu P1, rejestr konfiguracji układu licznika/timera T0, rejestr konfiguracji portu szeregowego UART. Drugą stanowią rejestry związane z pracą układu sterowania. Należą do nich w przypadku procesora 8051 między innymi: rejestr rozkazów IR (ang. instruction register), licznik programu IP (ang. program counter, instruction pointer) oraz niektóre z rejestrów specjalnych takie jak: wskaźnik stosu SP, kontroler przerwań (ang. interrupt controller) 5.3. Tryby adresowania argumentów 115 Program dwójkowy zapisany w pamięci składa się z ciągu zakodowanych instrukcji. Przez instrukcję rozumie się opis elementarnej operacji należącej do zbioru opisanego przez listę instrukcji. Każdy typ mikrokontrolera ma własną, zdefiniowaną przez producenta listę instrukcji, która szczegółowo opisuje sposób wykonania poszczególnych instrukcji. Lista instrukcji jest zatem rodzajem katalogu dostępnych operacji, których używa się przy pisaniu programów. Lista instrukcji wraz z opisem zachodzących między nimi współzależności oraz zbiorem reguł dotyczących składni zapisu programu tworzy opis języka programowania nazywanego językiem asemblera (ang. assembly language) lub w skrócie po prostu asemblerem. W teorii języków programowania asembler określa się jako język maszynowy (ang. machinę language), ponieważ instrukcje programu odpowiadają elementarnym operacjom realizowanym przez procesor. Języki programowania oparte na zbiorze instrukcji zbliżonym do listy instrukcji procesora nazywa się językami niskiego poziomu (ang. low-level language). 5.3.1. Formaty instrukcji Programista piszący program w języku asemblera posługuje się symbolicznym zapisem instrukcji. W zapisie takim polecenie: „dodaj do zawartości akumulatora liczbę szesnastkową 3CH i umieść wynik w akumulatorze" ma postać: ADD A,#3CH lub binarnie: 00100100,00111100, 24H,3CH Symbol ADD oznacza rodzaj operacji i jest nazywany skrótem mnemotechnicznym (mnemonikiem) lub nazwą symboliczną instrukcji. Podana instrukcja ma dwa argumenty. Pierwszy z nich wskazuje na akumulator (A), drugi natomiast jest liczbą szesnastkową o wartości 3C. Litera H występująca po wartości liczby wskazuje, że jest ona podana w kodzie szesnastkowym, natomiast znak # (ang. hash) służy do wskazania, że argument jest liczbową wartością dodajnika, a nie jego adresem w pamięci. Przy pisaniu programów dla różnych typów mikrokontrolerów pewną trudność sprawia to, że nazwy symboliczne instrukcji, rejestrów, a także sposoby definiowania kodów liczbowych i znaczenia argumentów są różne. Podany przykład symbolicznego zapisu instrukcji dodawania dotyczy asemblera procesorów rodziny MCS 51 (Intel) i jest stosowany powszechnie przez wielu innych producentów mikrokontrolerów. Inne oznaczenia symboliczne i reguły składni stosuje przede wszystkim Motorola oraz niektórzy producenci japońscy. Innym sposobem przedstawienia instrukcji jest jej opis funkcjonalny, który pokazuje, w jaki sposób przebiega wykonanie operacji. Funkcjonalny opis podanej wcześniej instrukcji dodawania ma postać: (A) <- (A) + #3CH W zapisie tym nawiasy okrągłe są użyte do wskazania zawartości obiektu, w tym przypadku akumulatora A. Sam symbol A pozbawiony nawiasów oznaczałby symboliczny adres akumulatora, natomiast zapis (A) oznacza liczbową zawartość akumulatora. Symbol strzałki opisuje natomiast przesłanie, w tym przypadku wyniku dodawania do akumulatora, którego nowa zawartość staje się równa sumie arytmetycznej poprzedniej zawartości akumulatora i liczby 3CH. Naturalnie, w wyniku wykonania powyższej operacji poprzednia zawartość akumulatora (dodąjna) zostanie zniszczona. Program będący ciągiem zapisanych symbolicznie instrukcji, nazywany programem źródłowym, tworzy się przy użyciu edytora i zapisuje zwykle na dysku komputerowym w postaci pliku ASCII. Program źródłowy nie może być bezpośrednio wykonywany przez mikrokontroler. Wcześniej należy go przetłumaczyć na postać dwójkową, dołączyć ewentualnie programy biblioteczne i załadować do pamięci mikrokontrolera. Operacje te, nazywane odpowiednio kompilacją, łączeniem (lub konsolidacją) oraz ładowaniem, są szczegółowo przedstawione w rozdziale 6. 116 Program dwójkowy, który można załadować do pamięci i wykonać, jest nazywany programem wynikowym. Składa się z ciągu zakodowanych dwójkowo instrukcji odpowiadających kolejnym instrukcjom programu źródłowego. Obraz analizowanej wcześniej instrukcji ADD wyglądałby w pamięci w sposób pokazany na rysunku 5.12. Rysunek 5.12. Fragment pamięci programu zawierający instrukcję ADD A,#3CH. Zapisany w pamięci przykładowy rozkaz ADD zajmuje dwa kolejne bajty o adresach oznaczonych przez: x i x + 1. Pierwszy bajt (o mniejszym adresie) zawiera kod operacji równy 00100100. Informuje on kontroler nie tylko o tym, że należy wykonać dodawanie, ale także o sposobie dostępu do dodajnika. W rozważanym przykładzie kod operacji określa, że dodajnik jest zapisany jako jednobajtowa liczba w drugim bajcie rozkazu. Natomiast w opisywanym mikrokontrolerze dodąjna musi być zawsze umieszczona w akumulatorze, dlatego wskazywanie jej lokalizacji jest zbędne. Zbędne jest też specyfikowanie miejsca, do którego należy wysłać obliczoną sumę, ponieważ jak wynika z podanego wcześniej opisu funkcjonalnego, znajdzie się ona w akumulatorze. Podany przykład pokazuje, że instrukcja może być opisana trzema różnymi sposobami: symbolicznie, funkcjonalnie oraz jako dwójkowa reprezentacja w pamięci. W taki właśnie sposób instrukcje definiuje lista instrukcji, która jest podstawowym i najbardziej wyczerpującym dokumentem pomocnym przy tworzeniu programów w języku asemblera. Większość współczesnych mikrokontrolerów wykorzystuje instrukcje o zróżnicowanej długości. W prostych układach 8-bitowych zajmują one zwykle od jednego do trzech bajtów pamięci, w bardziej skomplikowanych mikrokontrolerach 32-bitowych spotyka się natomiast instrukcje zajmujące nawet do ośmiu bajtów. Podstawowa reguła formatowania dwójkowego kodu instrukcji wymaga, by w pamięci najpierw był umieszczony kod operacji, a dopiero po nim argumenty (dane lub adresy). Warianty formatów instrukcji prostego mikrokontrolera 8-bitowego przedstawiono na rysunku 5.13, na którym podano również przykład różnych formatów dwójkowych tej samej instrukcji ORL mikrokontrolera 80C51 (ang. logical-OR), wykonującej operację sumy logicznej dwóch 8-bitowych argumentów. Na rysunku 25.13a pokazano typowe formaty rozkazów 1-, 2- i 3-bajtowych w prostych mikrokontrolerach 8-bitowych. Najkrótszy format l-bajtowy jest stosowany wówczas, gdy instrukcja nie wymaga żadnych argumentów lub gdy mogą być one zwarte w akumulatorze bądź rejestrach. 117 Rysunek 5.13. a) warianty formatów instrukcji w prostym mikrokontrolerze 8-bitowym, b) postać instrukcji sumy logicznej ORL mikrokontrolera 80C51 w różnych formatach Drugi i trzeci bajt kodu instrukcji służy wtedy do bezpośr. zapisu 16-bitowego argumentu, 16bitowego adresu operanda albo do zapisu 8-bitowego adr. jednego z argumentów i bezpośredniego zapisu drugiego argumentu. Przykład z rysunku 5.13b pokazuje natomiast, jak w praktyce korzysta się ze zróżnicowanych formatów instrukcji. Widać z niego, że bajt kodu operacji, który jest w każdym z trzech wariantów pierwszym bajtem kodu instrukcji, ma wartość zależną od użytego formatu. W podanym przykładzie dla instrukcji ORL mikrokontrolera 80C51 tylko bardziej znacząca tetrada kodu operacji jest w każdym formacie taka sama (0100). Pozostałe cztery bity służą do identyfikacji użytego formatu i ewentualnie rejestrów uczestniczących w operacji. Liczba różnych formatów instrukcji jest znacznie większa w przypadku mikrokontrolerów 16- i 32-bitowych. Mamy wówczas do czynienia z licznymi kombinacjami specyfikacji argumentów, a ta sama podstawowa instrukcja może być użyta w programie na wiele różnych sposobów, w zależności od tego, gdzie są umieszczone argumenty. Niełatwe zadanie biegłego posługiwania się licznymi odmianami instrukcji jest podstawą przy pisaniu efektywnych programów, to znaczy zajmujących mało pamięci i wykonywanych możliwie szybko. Z pojęciem formatu instrukcji wiąże się jeszcze jedna ważna sprawa dotycząca terminologii. Chodzi mianowicie o rozróżnienie pojęć instrukcja i rozkaz. W niektórych pracach pojęcia te są używane zamiennie, co może prowadzić do nieporozumień. - Przez rozkaz będziemy rozumieć rodzaj operacji opisanej przez określoną instrukcję. - Kod operacji zapisany w pierwszym bajcie instrukcji będziemy w związku z tym nazywać kodem rozkazowym lub w skrócie rozkazem. - Instrukcja będzie natomiast oznaczać pojęcie szersze, czyli rozkaz wraz ze specyfikacją argumentów, na których operacja ma być wykonana. Dla przykładu, w tym rozumieniu obu terminów ADD oznacza symboliczny zapis rozkazu dodawania, a zapis ADD A,#7H oznacza instrukcję o treści: dodaj liczbę 07H do zawartości akumulator i umieść wynik w akumulatorze. 5.3.2. Podstawowe tryby adresowania Przez tryb adresowania rozumie się sposób wskazywania na argumenty wykorzystywane w trakcie wykonania instrukcji. Im bogatszy jest repertuar trybów adresowania realizowanych przez dany typ mikrokontrolera, tym bardziej efektywny jest proces programowania pozwalający na zwięzły zapis algorytmów. Standardowe mikrokontrolery 8- i 16-bitowe realizują zazwyczaj kilka bądź kilkanaście różnych sposobów adresowania argumentów operacji, ustępując procesorom stosowanym w dużych komputerach stacjonarnych. Ciągły rozwój techniki mikroprocesorowej 118 powoduje stale wzbogacanie repertuaru sposobów adresowania i nowoczesne procesory do aplikacji typu embedded używają już podobnego arsenału adresowego co procesory stosowane w dużych komputerach. Do najważniejszych trybów adresowania można zaliczyć adresowanie: - implikowane, zwane też wewnętrznym lub rejestrowym (ang. implied, inherent, register), - natychmiastowe (ang. immediate), - bezpośrednie (ang. direct), - pośrednie (ang. indirect), - indeksowe (ang. indexed), - względne (ang. relative). Adresowanie implikowane Adresowanie implikowane dotyczy jednobajtowych instrukcji, dla których zarówno operand (bądź operandy) jak i miejsce przeznaczenia wyniku są określone przez słowo rozkazowe. Ten tryb adresowania jest używany wyłącznie w odniesieniu do wewnętrznych rejestrów mikroprocesora, w tym przede wszystkim w odniesieniu do akumulatora (lub akumulatorów, jeśli mikrokontroler zawiera ich większą liczbę). Dwójkowy kod instrukcji nie zawiera więc ani argumentów, ani adresów i składa się wyłącznie z kodu rozkazu. Wskazanie na argumenty jest niejako „ukryte" wewnątrz kodu rozkazu, skąd bierze się nazwa tego trybu adresowania. Rysunek 5.14 ilustruje implikowany tryb adresowania dla przytoczonego już wcześniej rozkazu ADD. Rysunek 5.14. Ilustracja implikowanego trybu adresowania na przykładzie rozkazu dodawania ADD w mikrokontrolerze 80C51 Ze względu na krótki format instrukcji i brak konieczności adresowania argumentów w pamięci, instrukcje wykorzystujące tryb implikowany przy adresowaniu argumentów są bardzo efektywne w użyciu. Należy je w związku z tym stosować, jeśli jest to tylko możliwe. Ograniczenia w wykorzystaniu tego trybu wynikają głównie z dostępnej liczby rejestrów. W skomplikowanych algorytmach używających wielu zmiennych nie można zmieścić wszystkich danych i zmiennych roboczych w rejestrach, dlatego korzy-nie z innych trybów adresowania jest nieuniknione. Niemniej jednak należy próbować . rozmieścić zmienne w rejestrach i pamięci, by te, do których algorytm odwołuje się najczęściej, znalazły się w rejestrach, a inne, rzadziej używane - w pamięci. Adresowanie natychmiastowe Adresowanie natychmiastowe ma miejsce wtedy, gdy operand jest podany w jawnej postaci w kodzie instrukcji. Naturalnie, by móc skorzystać z tego trybu, programista musi znać wartość argumentu w trakcie pisania programu. Tryb natychmiastowy może być zatem używany wyłącznie w odniesieniu do stałych, nie ma natomiast zastosowania w przypadku zmiennych. W przykładzie z rysunku 5.15 pokazującym zastosowanie natych-miastowego trybu adresowania, użyto 8-bitowej stałej natych-miastowej, takiej bowiem długości dodajnika wymaga 8-bitowa jednostka ALU rozważanego mikrokontrolera. W przypadku innych rozkazów tego mikrokon-trolera, a także mikrokontrolerów 16- i 32-bitowych, można stosować dane natychmiastowe o większej długości. 119 Rysunek 5.15. Ilustracja natychmiastowego trybu adresowania na przykładzie rozkazu dodawania ADD w mikrokontrolerze 80C51 W pamięci programu zajmują one wtedy dwa lub więcej kolejnych bajtów następujących po kodzie rozkazu. W większości typów mikrokontrolerów wielobajtowe argumenty natychmiastowe są zapisywane w kodzie instrukcji zaczynając od najbardziej znaczącego bajtu, tzn. bajt ten jest umieszczony jako pierwszy po kodzie rozkazu. Instrukcje wykorzystujące natychmiastowy tryb adresowania zajmują, oczywiście, więcej miejsca w pamięci i wykonują się wolniej niż instrukcje zapisane w trybie implikowanym. Adresowanie bezpośrednie Adresowanie bezpośrednie odnosi się do instrukcji wielobajtowych, w których po kodzie rozkazu następuje adres argumentu umieszczonego w pamięci danych. Niektóre typy mikrokontrolerów dopuszczają adresowanie tą metodą tylko ograniczonego fragmentu pamięci danych. la przykładu, w mikrokontrolerze 80C51 można w ten sposób adresować wewnętrzny obszar pamięci o adresach od 0 do 255, natomiast w układzie 16-bitowym typu 80C51 XA początkowy l kB pamięci danych. Mikrokontrolery 8-bitowe produkowane przez firmę Motorola posługują się rozszerzonym adresowaniem bezpośrednim (ang. extended mode) i umożliwiają adresowanie 64 kB pamięci. W nowoczesnych mikrokontrolerach 16- i 32-bitowych adresowanie bezpośrednie jest najczęściej kombinowane z bardziej zaawansowanymi metodami dostępu, opartymi na segmentacji pamięci. W przykładzie z rysunku 5.16a pokazano działanie rozkazu dodawania ADD w mikrokontrolerze x51. Natomiast na rysunku 5.16b przedstawiono schemat funkcjonalny bezpośredniego adresowania rozszerzonego w procesorze 68HC05 (Motorola). Przy okazji warto prześledzić różnice w zapisie symbolicznym, dwójkowym i funkcjonalnym instrukcji, stosowanym przez obie firmy. W symbolicznym zapisie Motoroli pominięto symbol akumulatora, który w tym przypadku jest domyślnym miejscem ulokowania dodajnej i wyniku. W zapisie funkcjonalnym użyto natomiast symbolu (M), który oznacza zawartość komórki pamięci o podanym adresie bezpośrednim (M od ang. memory). 120 Rysunek 5.16. Bezpośrednie adresowanie pamięci: a) rozkaz ADD z krótkim adresem –x51, b) rozkaz ADD z rozszerzonym trybem adresowania 16 bitowego – 68HC05 Adresowanie indeksowe Adresowanie indeksowe nie jest stosowane we wszystkich mikrokontrolerach (na przykład x51 nie realizuje tego trybu). Polega na obliczaniu adresu przez sumowanie zawartości specjalnie przeznaczonego do indeksowania rejestru, nazywanego rejestrem indeksowym, z adresem bezpośrednim, zapisanym w instrukcji. Obliczony w ten sposób fizyczny adres pamięci bywa nazywany adresem efektywnym (rys. 5.17). Adresowanie indeksowe jest szczególnie użyteczne przy operowaniu na blokach danych, czyli ciągach bajtów bądź słów zapisanych w kolejnych komórkach pamięci. Umieszczając w instrukcji adres początku bloku danych można uzyskać wygodny dostęp do kolejnych bajtów danych przez samą tylko zmianę zawartości rejestru indeksowego. Rysunek 5.17. Adresowanie indeksowe Adres efektywny jest sumą dwóch składników, zatem rola, jaką te składniki spełniają, jest czysto umowna. W niektórych mikrokontrolerach adres początku bloku danych jest umieszczony w 121 rejestrze indeksowym, a składnik określający przesunięcie (ang. offset, displacement) adresowanego bajtu względem początku bloku jest umieszczony w instrukcji. Ten wariant adresowania indeksowego jest nazywany adresowaniem bazowym, a rejestr indeksowy - rejestrem bazowym. Często też stosuje się krótki, 8-bitowy adres zapisany w drugim bajcie dwubajtowej instrukcji. W niektórych typach mikrokontrolerów przesunięcie adresu względem adresu bazowego jest traktowane jako liczba ze znakiem zapisana w kodzie U2, co umożliwia dostęp zarówno do komórek o adresach większych, jak i mniejszych od adresu bazowego. Odmianą adresowania indeksowego jest adresowanie postindeksowe, polegające na obliczaniu adresu efektywnego jako sumy zawartości rejestru indeksowego z zawartością komórki pamięci adresowanej przez adres bezpośredni instrukcji. Metodę takiego obliczania adresu pokazano na rysunku 5.18. Rysunek 5.18. Adresowanie postindeksowe Jeżeli jednocześnie mikrokontroler umożliwia również podstawowy tryb adresowania indeksowego, to jest ono dla rozróżnienia nazywane adresowaniem proindeksowym. Długość rejestru indeksowego oraz adresu bazowego i adresu pośredniego jest różna dla różnych typów mikrokontrolerów. Różne są też zestawy instrukcji, które mogą korzystać z tego trybu adresowania. Ponadto niektóre mikrokontrolery zawierają więcej niż jeden rejestr indeksowy. Z tego powodu na rysunkach 25.17 i 5.18 podano jedynie ogólny schemat ilustrujący adresowanie indeksowe, nie zaś jak wcześniej, ilustrację dotyczącą konkretnej instrukcji wybranego mikrokontrolera. Adresowanie pośrednie Adresowanie pośrednie ma miejsce, gdy część adresowa instrukcji wskazuje na komórkę pamięci (lub pierwszą z kilku sąsiednich komórek) zawierającą adres efektywny. Sytuację taką przedstawiono na rysunku 5.19. Odmianą adresowania pośredniego jest adresowanie zawartością rejestrów (ang. pointer addressing), w którym adres efektywny jest zawarty w rejestrze lub w parze rejestrów mikrokontrolera. W tym przypadku identyfikacja tych rejestrów odbywa się na podstawie słowa rozkazowego. Zazwyczaj nic wszystkie rejestry mikrokontrolera mogą być użyte do przechowywania adresów pośrednich, lecz tylko niektóre z nich. 122 Rysunek 5.19. Adresowanie pośrednie Adresowanie względne Adresowanie względne służy do adresowania pamięci względem adresu aktualnie wykonywanej instrukcji w pamięci programu. Adres ten jest przechowywany w specjalnie do tego celu przeznaczonym rejestrze, nazywanym licznikiem programu (PC, ang. program counter), licznikiem rozkazów lub wskaźnikiem instrukcji (1P, ang. instruction pointer), przedstawionym wcześniej. Instrukcja wykorzystująca względny tryb adresowania zawiera jedno- lub kilkubajtowe przesunięcie nazywane adresem względnym (ang. relative address). Adres efektywny jest obliczany. jako suma zawartości licznika programu i adresu względnego, w sposób przedstawiony na rysunku 5.20. Jednobajtowe przesunięcie zapisane jako liczba ze znakiem w kodzie U2 umożliwia dostęp do komórek pamięci położonych w obszarze [-128, +127] bajtów względem instrukcji używającej tego trybu adresowania. Odpowiednio większy zakres dostępu zapewniają instrukcje z wielobajtowym przesunięciem. Rysunek 5.20. Adresowanie względne Tryb ten jest używany przede wszystkim w instrukcjach skoków i umożliwia tworzenie programów relokowalnych, to znaczy takich, które mogą być prawidłowo wykonywane niezależnie od fizycznego adresu obszaru pamięci, w którym zostały umieszczone. Dodatkową korzyścią ze stosowania adresowania względnego jest skrócenie kodu instrukcji skoków, które zamiast pełnego adresu bezpośredniego zawierają jedynie krótkie, zwykle jednobajtowe przesunięcie (adres względny). Innym, ciekawym zastosowaniem względnego trybu adresowania jest pisanie programów, które w czasie wykonywania modyfikują swój własny kod. Właściwość ta może być użyta na przykład przy programowaniu algorytmów z dziedziny metod sztucznej inteligencji. Niezbędne jest jednak przy tym duże doświadczenie w programowaniu w języku asemblera, ponieważ błędnie napisany program tego typu może łatwo doprowadzić do zniszczenia zawartości pamięci i nieprzewidzianych 123 reakcji całego systemu. Naturalnie, programy zdolne do modyfikowania własnego kodu muszą być zapisane w pamięci typu RAM. Przedstawione tryby adresowania są typowymi, najczęściej stosowanymi sposobami dostępu do argumentów. W niektórych mikrokontrolerach spotyka się dalsze ich odmiany, powstające najczęściej w wyniku kombinacji omówionych trybów podstawowych. Nowoczesne mikrokontrolery, przystosowane do operowania dużymi przestrzeniami adresowymi, wykorzystują podział pamięci na mniejsze fragmenty nazywane segmentami. Segmentacja wiąże się ściśle z metodami dostępu do argumentów i wymaga stosowania trybów adresowania o odpowiednio zmodyfikowanym działaniu. Są one jednak zawsze oparte na omówionych wcześniej elementarnych zasadach generowania adresów. 5.3.3. Przykładowa lista instrukcji - mikrokontroler 80C51 W celu pokazania zastosowania różnych trybów adresowania oraz możliwości jednostki ALU poniżej zaprezentowano listę instrukcji procesora 80C51. Rysunek 5.21. Lista instrukcji procesora 80C51 124 Rysunek 5.22. Lista instrukcji procesora 80C51 – cd. Rysunek 5.23. Lista instrukcji procesora 80C51 – cd. 5.4. Układ sterowania Przedstawiony w zarysie układ sterowania mikrokontrolera jest fragmentem większego zespołu funkcjonalnego, nazywanego podsystemem sterowania. Oprócz samego układu sterowania obejmuje on następujące elementy: − układ oscylatora − układ resetu − rejestr rozkazów IR (ang. instruction register), − dekoder rozkazów, − licznik programu IP (ang. program counter, instruction pointer). Do podsystemu sterowania należą ponadto niektóre rejestry specjalne SFR, wskaźnik stosu SP (ang. stack pointer), kontrolery szyn, układy transmisyjne oraz kontroler przerwań (ang. interrupt controller). 5.4.1. Układ oscylatora W mikrokontrolerze (mk) można wyróżnić dwa źródła sygnału zegarowego: − sygnał zegarowy generowany „wewnątrz” mk (wewnętrzny układ RC), − sygnał zegarowy generowany z wykorzystaniem zewnętrznych elementów. Każdy mk posiada dedykowane dwie końcówki służące wyłącznie do podłączenia zewnętrznych elementów wykorzystywanych do generacji (stabilizacji) sygnału zegarowego. Jedna z nich jest wejściem (najczęściej oznaczana OSC1 lub XTAL1), druga wyjściem (OSC2 lub XTAL2) wewnętrznego układu generatora. Można do nich podłączyć oscylator kwarcowy, ceramiczny, układ RC lub podać na końcówkę wejściową zewnętrzny sygnał prostokątny. W przypadku mikrokontrolera 80c51 układ oscylatora jest bardzo prosty, ponieważ możliwa jest praca jedynie z zewnętrznym rezonatorem kwarcowym lub z podaniem zew sygnału prostokątnego na wejście XTAL1. 125 Rysunek 5.24. Połączenia zewnętrzne układu oscylatora 80c51 Tablica 5.1. Parametry układu oscylatora 80c51 Poniżej przedstawiono schematy układów połączeń zewnętrznych oraz wewnętrznych oscylatora 80C51. Rysunek 5.25. Połączenia wewnętrzne układu oscylatora mikrokontrolera 80C51 – schemat ideowy Rysunek 5.26. Połączenia wewnętrzne układu oscylatora mikrokontrolera 80C51 – schemat dokładny 126 Mikrokontroler PIC16F873 ma więcej możliwości generacji sygnału zegarowego. Umożliwia wykorzystanie: - rezonatora kwarcowego/ceramicznego (rys. 5.27a), - rezonatora RC (najtańszy ale najgorsze parametry generowanego przebiegu) (rys. 5.27b), - zewnętrznego sygnału prostokątnego podanego na wejście OSC1 (rys. 5.27c), - wewnętrznego rezonatora RC (rys. 5.27d). Ponadto możemy wyróżnić następujące tryby pracy oscylatorów kwarcowych/ceramicznych: - LP – generowanie niskich częstotliwości dla zapewnienia min. poboru mocy (ang. Low Power Crystal), - XT – generowanie średnich częstotliwości (ang. Crystal/Resonator), - HS – generowanie wysokich częstotliwości (ang. Hight Speed Crystal/Resonator). Producenci zawierają w dokumentacji mk tabele wartości kondensatorów dla poszczególnych trybów pracy oscylatora/rezonatora. Dla mikrokontrolera PIC16F873 zostały one przedstawione poniżej na rysunku 5.27. Dla przykładu w tablicy 5.2 podano wartości kondensatorów C1 i C2 dla wszystkich możliwych trybów pracy oscylatora kwarcowego tego mikrokontrolera. Rysunek 5.27. Sposoby generowania sygnału zegarowego Tablica 5.2. Wartości kondensatorów w zależności od trybu pracy oscylatora kwarcowego Metodę generacji sygnału zegarowego jak i tryb pracy oscylatora wybiera się na etapie programowania mk, czyli podczas wprowadzania kodu programu do jego pamięci FLASH. Służą do tego dwa bity zawarte w rejestrze konfiguracyjnym (rys. 5.28). Rejestr ten znajduje się w pamięci FLASH pod adresem 2007H i jest dostępny (można do niego pisać i z niego czytać) wyłącznie w trybie programowania wykorzystując w tym celu programator i dołączone do niego oprogramowanie np. MPLAB. Rejestr konfiguracyjny jest 14-bitowy. Na rys. 2.15 pokazano jego 127 fragment związany z omawianymi zagadnieniami. Układ pracy oscylatora mk musi być zgodny z tym, co zostało zaprogramowane. W przeciwnym razie mk nie będzie działał! Rysunek 5.28. Fragmenty rejestru konfiguracyjnego mk PIC16F873 Ponieważ od mk wymaga się niezawodności niektóre z nich wyposażone są w specjalne generatory zapewniające ciągłą, bezawaryjną generację sygnału zegarowego oraz jego filtrację, np. mk ST72215G. Ponadto cechą charakterystyczną współczesnych mk są rozbudowane układy generacji i dystrybucji sygnałów zegarowych. Potrzeba ta wynika z dużej ilości pracujących autonomicznie modułów we/wy wymagających różnych sygnałów zegarowych. Same procesory rdzeniowe często są wyposażone w 2 generatory zegarowe, jeden o częstotliwości zapewniającej maksymalną szybkość pracy i drugi pozwalający na pracę z częstotliwością 32,768 kHz, np. Rabbit2000 Na rys. 5.29. pokazano układ dystrybucji sygnałów zegarowych mk DS87C530. Dostarcza on sygnał zegarowy do jednostki centralnej oraz urządzeń peryferyjnych. Składa się z programowalnego preskalera i układu dostarczającego sygnał do zewnętrznych urządzeń. Preskaler pozwala na ustawienie odpowiedniej częstotliwości sygnału zegarowego, co w przypadku jej zmniejszenia, powoduje zmniejszenie pobieranej przez mk mocy (moc pobierana przez układy CMOS jest proporcjonalna do ich częstotliwości pracy). CD1 CD0 SWB XTOFF ALEOFF DME1 DME0 1/65536 z zewnętrznego oscylatora f osc 1/4, 1/64, 1/1024 f wewnętrzny oscylator RING f cpu ring 2-4MHz układ wyboru Rysunek 5.29. Układ oscylatora mikrokontrolera DS87C530 W układzie występuje dodatkowy oscylator zwany Ring, którego cechami charakterystycznymi są: bardzo szybkie wejście w stan generacji oraz niestabilna praca. Oscylator ten pozwala na szybkie (w ciągu kilku mikrosekund) podjęcie pracy przez mikrokontroler, w odróżnieniu od normalnego układu oscylatora, który do stabilnej pracy wymaga czasu 65536 okresów oscylacji. 128 5.4.2. Układ resetu Sygnał RESET służy do inicjalizacji pracy mk, czyli wprowadzenia go w stan początkowy. Inicjalizacja polega najczęściej na wyzerowaniu licznika rozkazów, ustawienia go na początek wykonywania programu. Urządzenia we/wy i rejestry sterujące są ustawiane w tryb standardowy (spoczynku). Uniwersalne końcówki we/wy są ustawione jako wejścia o wysokiej impedancji, aby minimalnie wpływać na otoczenie mk (w dokumentacji każdego mk znajduje się informacja o stanie wszystkich rejestrów i portów po resecie mk). Dla niektórych mk po resecie może być czytany rejestr stanu określający tryb pracy mk, stany (poziomy) sygnałów na niektórych końcówkach, a następnie czytany adres początku programu znajdujący się w obszarze obsługi resetu. Dla mk o architekturze harwardzkiej po resecie wykonywana jest instrukcja najczęściej spod adresu 00h (np. 80C51, AT90S8515, PIC16F873, COP880). Natomiast dla mk bazujących na architekturze Von-Neumanna adres ten znajduje się zazwyczaj na końcu obszaru adresowania pamięci, gdyż początkowe adresy najczęściej przypisane są urządzeniom we/wy i pamięci RAM (np. ST72215G – po resecie wykonywana jest instrukcja spod adresu FFFEH-FFFFH). Możemy wyróżnić następujące źródła resetu: − reset po włączeniu zasilania, − reset wywołany zewnętrznym sygnałem RESET, − reset programowy wywołany przez ustawienie odpowiedniego bitu, − reset wywołany przez układ watchdog, − reset wywołany przez układy nadzorujące poprawność pracy mk (np. od układu wykrywającego spadek napięcia zasilania LVD (ang. Low Voltage Detector) w ST72215G, − BOR (ang. Brown-out Reset) w PIC16F873). Każdy mk posiada dedykowaną końcówkę (pin) do której przypisany jest zewnętrzny sygnał resetu. Sygnał ten umożliwia asynchroniczny reset mk.. Najczęściej jest on aktywny poziomem niskim (z wyjątkiem mk 80C51). Najprostszy, często stosowany układ resetu przedstawiono na rys. 5.30. Zapewnia on niski poziom sygnału pojawiający się bezpośrednio po włączeniu zasilania i trwający przez określony czas. Jest to układ RC, zatem czas trwania resetu zależy od stałej czasowej RC. Na rys. 5.31 pokazano układ resetu procesora 80C51. VCC u(t) Mikrokontroler R u(t) RESET stan C t Praca Reset t Rysunek 5.30. Najczęściej spotykany - najprostszy układ resetu mikrokontrolera 129 VCC C u(t) u(t) Mikrokontroler 80C51 RST stan R C=10uF R=8.2K t Praca Reset t Rysunek 5.31. Najprostszy układ resetu mikrokontrolera 80C51 Na rysunku 5.32 pokazano reakcję mikrokontrolera 80C51 na zewnętrzny sygnał resetu. Rysunek 5.32. Reakcja układu mikrokontrolera z rodziny 80C51 na zewnętrzny sygnał reset Obecnie mk posiadają rozbudowane układy resetu, które poza resetem mk również monitorują poprawność pracy systemu i reagują na sytuacje awaryjne. Na rys. 5.33 pokazano taki układ. Rysunek 5.33. Układ resetu mk PIC16F873 130 Reset po włączeniu zasilania jest generowany przez specjalny blok (VDD ang. Rise Detect), w przypadku wykrycia przez niego narastającego zbocza sygnału zasilającego. Dzięki temu układ z rys. 5.31 jest zbędny. Sygnał resetu może być również wywołany przez bloki nadzorujące poprawność pracy mk takie jak BOR, czy LVD. BOR sprawdza napięcie zasilające. Jeżeli spadnie ono poniżej VBOR i jego spadek trwać będzie przynajmniej przez TBOR to układ wysyła sygnał resetu. Działanie układu LVD jest bardziej złożone. Można powiedzieć, iż spełnia on funkcje detektora narastania napięcia zasilania jak i układu BOR. Na rys. 5.34 pokazano na przebiegach działanie takiego układu. Rysunek 5.34. Przebiegi sygnałów VDD i RESET dla układu LVD mk ST72215G Układ generuje sygnał resetu dopóki VDD podczas narastania nie osiągnie założonego napięcia VIT+ oraz gdy to napięcie spadnie poniżej VIT- podczas opadania. Kolejnym źródłem resetu jest układ watchdog. Generuje on sygnał resetu, gdy nastąpi zawieszenie programu w mk. Układy resetu posiadają również dodatkowe układy wydłużające sygnał reset (rys. 5.35). Ma to zapewnić pracę mk z już ustalonym napięciem zasilania i ustalonym sygnałem z oscylatora. W PIC16F873 licznik PWRT, z własnym wewnętrznym oscylatorem RC, wydłuża sygnał resetu o TPWRT=72ms, a licznik OST o dodatkowe 1024 cykle sygnału z oscylatora kwarcowego (TOSC), oczywiście o ile są włączone. Dla mk DS87C530 wydłużenie sygnału resetu spowodowane czasem oczekiwania na stabilną pracę głównego oscylatora jest stałe i wynosi 65536. Rysunek 5.35. Przebiegi sygnałów w układzie resetu mk PIC16F873 Do konfiguracji układu resetu są przeznaczone specjalne rejestry. Znajduje się w nich również informacja o przyczynie resetu, np. czy reset nastąpił sygnałem zewnętrznym, czy po włączeniu zasilania, czy też został wywołany przez układ watchdog. (Przykładowe nazwy rejestrów zawierających wspomniane informacje w przypadku mikrokontrolera DS87C530 są następujące WDCON - D8H, EIE - E8H, EXIF – 91H, PCON – 87H.) 5.4.3. Cykl wykonania rozkazu Po wykonaniu cyklu resetu, mk zaczyna wykonywać instrukcje programu zapisane w pamięci programu. 131 Mikrokontroler o prostej strukturze wykonuje instrukcje programu w dwóch fazach: - pobranie kodu rozkazu z pamięci programu do rejestru rozkazów IR (ang. fetch), - wykonanie odpowiedniej sekwencji mikrooperacji zgodnie z sygnałami generowanymi przez układ sterowania (ang. execution). Etap pobrania kodu rozkazu jest zunifikowany dla wszystkich rodzajów instrukcji, ponieważ dwójkowy format instrukcji przewiduje, że kod rozkazu jest zawsze zapisany w pierwszym bajcie. Faza ta składa się z następujących czynności: - podanie zawartości licznika programu IP przez rejestr adresowy na szynę adresową, - wygenerowanie przez układ sterowania sygnału odczytu pamięci programu i doprowadzenie go do pamięci przez szynę sterowania, - przesłanie kodu rozkazu z wyjść pamięci przez szynę danych do rejestru rozkazów I R, - zwiększenie zawartości licznika programu IP o jeden (inkrementacja IP). Przepływ informacji podczas fazy pobierania kodu rozkazu ilustruje rysunek 5.36. Rysunek 5.36. Przepływ sygnałów podczas fazy pobrania rozkazu Faza wykonania instrukcji przebiega różnie w zależności od konkretnej operacji. Pierwszym etapem jest jednak zawsze dekodowanie rozkazu realizowane przez dekoder wykonany jako układ kombinacyjny. Na podstawie zdekodowanego stanu rejestru rozkazów układ sterowania generuje właściwą sekwencję sygnałów sterujących. Sekwencja ta jest uzależniona głównie od liczby odwołań do pamięci (wewnętrznej lub zewnętrznej), potrzebnych do wykonania instrukcji. Rozważmy wykonanie przykładowych instrukcji różniących się zastosowanym formatem zapisu oraz trybem adresowania. Załóżmy przy tym dla uproszczenia, że szyna danych jest 8-bitowa, natomiast szyna adresów ma 16 bitów. Typową instrukcją o formacie jednobajtowym jest operacja przesłania zawartości rejestru Ri do akumulatora A, której zapis funkcjonalny przedstawiamy jako: (A) <- (Ri). Instrukcja ta nie wymaga odwołań do pamięci (wewnętrznej ani zewnętrznej), a jej wykonanie ilustruje rysunek 5.37. 132 Rysunek 5.37. Wykonanie instrukcji przesłania zawartości rejestru RI do akumulatora Bardziej skomplikowany przebieg ma operacja przesłania zawartości akumulatora do komórki pamięci adresowanej w sposób pośredni, przez złożenie (konkatenację) zawartości rejestrów RO i RI. Operację tę możemy oznaczyć jako M(RO, RI) <- (A). Wykonanie tej instrukcji pokazano na rysunku 5.38, na którym dodatkowo podano przebiegi czasowe sygnałów związanych z wykonaniem instrukcji. Ponieważ rozważana instrukcja ma format jednobajtowy (adres pośredni mieści się w rejestrach), do jej wykonania potrzebny jest jednokrotny dostęp do pamięci programu (cykl fetch) i jednokrotny dostęp do pamięci danych. Rysunek 5.38. Faza wykonania instrukcji M(R0,R1)<-(A).a) przepływ danych, b)przebiegi czasowe w fazie pobrania i wykonania instrukcji Znaczenie parametrów określających czasy trwania impulsów z. rysunku 5.38b jest następujące (według oznaczeń firmy Intel): - tr - czas trwania impulsu odczytu z pamięci, - tar - czas wyprzedzenia ustalonego stanu szyny adresowej względem impulsu odczytu, - tdr - czas wyprzedzenia ustalonego stanu szyny danych względem końca impulsu odczytu, - thr - czas utrzymywania stanu szyny danych po zakończeniu impulsu odczytu, - tw - czas trwania impulsu zapisu do pamięci, - taw - czas wyprzedzenia ustalonego stanu szyny adresowej względem impulsu zapisu danych do pamięci, - tdw - czas wyprzedzenia stabilnego stanu szyny danych względem impulsu zapisu do pamięci, thw - czas utrzymania stanu szyny danych po zakończeniu impulsu zapisu. Wartości tych parametrów (nominalne i minimalne) zależą od szybkości mikrokontrolerów, czyli od maksymalnej częstotliwości zegara oraz od czasu dostępu do pamięci. Mają one znaczenie wtedy, gdy wykorzystywana jest zewnętrzna pamięć danych i programu. Przy współpracy z pamięciami wewnętrznymi instrukcje tego typu są wykonywane z maksymalną szybkością, w ciągu zaledwie jednego cyklu zegara. Wykonanie instrukcji wielobajtowych przebiega w bardziej skomplikowany sposób. Przykładem takiej instrukcji może być operacja: (A) <- (A) + #dana, oznaczająca dodanie do akumulatora natychmiastowego argumentu zapisanego w pamięci programu. Jeśli dla uproszczenia przyjmiemy, że akumulator i stała natychmiastowa są 8-bitowe, to instrukcja wymaga dwukrotnego dostępu do pamięci programu w celu pobrania rozkazu i argumentu. Czynności układu sterowania 133 podczas pobierania instrukcji z pamięci i jej wykonania mogą być zapisane symbolicznie w następujący sposób: (IR) <M(PC) ;pobranie słowa rozkazowego (PC) <(PC)+1 ;inkrementacja licznika programu B(ALU) <M(PC) ;pobranie argumentu #dana (PC) <(PC)+1 ;inkrementacja licznika programu (A) <ALU+ ;wykonanie dodawania gdzie B(ALU) oznacza zawartość rejestru przejściowego ALU (bufora), natomiast ALU+ oznacza stan wyjść ALU przy wysterowaniu jednostki arytmetyczno-logicznej w sposób odpowiadający operacji dodawania. Jako przykład instrukcji trzybajtowej rozważmy operację: (A) <- (A) + M(adres), gdzie symbol adres oznacza dwubajtowy adres bezpośredni. Instrukcja ta wymaga trzykrotnego dostępu do pamięci, zgodnie z zapisem symbolicznym: (IR) <M(PC) ;pobranie słowa rozkazowego (PC) <(PC)+1 ;inkrementacja licznika programu (RAH) <M(PC) ;załadowanie bardziej znaczącego bajtu adresu (PC) <(PC)+1 ;inkrementacja licznika programu (RAL) <M(PC) ;załadowanie mniej znaczącego bajtu adresu (PC) <(PC)+1 ;inkrementacja licznika programu B(ALU) <M(RA) ;załadowanie dodajnika do rejestru przejściowego (A) <ALU+ ;wykonanie dodawania Symbole RAL i RAH oznaczają odpowiednio mniej i bardziej znaczący bajt 16-bitowcgo rejestru adresowego RA, przy czym założono, że drugi bajt kodu instrukcji zawiera bardziej znaczący bajt adresu. W nowoczesnych mikrokontrolerach transmisja z/do pamięci (również zewnętrznych) może się odbywać nie tylko bajtami, ale również słowami, a niekiedy nawet podwójnymi słowami. Przedstawiony powyżej cykl pracy układu sterowania jest wtedy prostszy, faza wykonania wymaga bowiem tylko jednego dostępu do nieci programu. Czas wykonywania instrukcji przyjęto określać podając liczbę cykli maszynowych potrzebnych do jej realizacji. Przez cykl maszynowy rozumie się sekwencję cykli zegara potrzebnych do realizacji pojedynczego odwołania do pamięci lub układu wejścia/wyjścia. Cykl instrukcyjny (nazywany niekiedy cyklem rozkazowym) składa się z kilku kolejno następujących cykli maszynowych. Zwykle tworzy on sekwencję następujących cykli maszynowych: - cykl pobrania rozkazu, - cykl (bądź cykle) pobrania argumentów, - cykl zapisu wyniku. Pojęcie cyklu maszynowego stopniowo wychodzi jednak z użycia. Powodem jest to, że standardową architekturę mikrokontrolera w swojej czystej, podstawowej postaci stosuje się coraz rzadziej. Współczesne procesory wykorzystują bardziej zaawansowane warianty architektoniczne, które umożliwiają jednoczesne wykonywanie faz instrukcji, nawet ciągu kolejnych instrukcji. Czas wykonania instrukcji jest w tej sytuacji określany przez liczbę cykli zegara. Wykonanie większości stawowych instrukcji zajmuje tylko jeden cykl zegara. Cykl maszynowy mikrokontrolera 8051 składa się z sześciu stanów oznaczonych S1 do S6. Każdy ze stanów trwa dwa okresy sygnału taktującego, oznaczonych jako fazy P1 i P2. Wynika z tego, że czas trwania cyklu maszynowego wynosi 12 taktów zegara, co dla częstotliwości rezonatora równej 12MHz daje czas 1us. Czas wykonywania instrukcji wynosi jeden, dwa lub cztery cykle maszynowe, w zależności od instrukcji. Na rysunku 5.39 przedstawiono cztery różne cykle rozkazowe dla czterech różnych instrukcji. 134 Przebieg a) przedstawia cykl rozkazowy instrukcji jednobajtowej wykonywanej w pojedynczym cyklu maszynowym, przebieg b) przedstawia przypadek wykonywania instrukcji dwubajtowej wykonywanej w pojedynczym cyklu maszynowym, przebieg c) obrazuje wykonanie instrukcji jednobajtowej wykonywanej w ciągu dwóch cykli maszynowych. Rysunek 5.39. Cykle rozkazowe dla różnych instrukcji W związku z multipleksowaniem szyny adresowej A0-A7 i szyny danych, mikrokontroler musi generować dodatkowy sygnał sterujący zewnętrznym buforem zatrzaskowym - tym sygnałem jest ALE. Sygnał ten jest generowany podczas pobierania każdego słowa rozkazu dwukrotnie w każdym cyklu maszynowym. Wyjątek stanowi rozkaz MOVX (oraz MOVC przy dostępie do zewnętrznej pamięci programu) realizujący dostęp do pamięci zewnętrznej. Instrukcja ta jest jednobajtowa, wykonywana w dwóch cyklach maszynowych. W pierwszym cyklu następuje odczyt kodu instrukcji (pierwszy sygnał ALE) oraz ustawienie adresu żądanej komórki pamięci (drugi sygnał ALE). W drugim cyklu maszynowym następuje odczyt/zapis szyny danych - nie może wówczas wystąpić sygnał ALE, gdyż zniszczyłby on wcześniej ustawiony adres komórki pamięci 5.4.4. Przerwania i sytuacje wyjątkowe Dotychczasowe milczące założenie, że mikrokontroler pracuje w pełni autonomicznie i jedynym czynnikiem określającym jego pracę jest program zapisany w pamięci, nie jest zazwyczaj spełnione w praktyce. Mikrokontroler współpracuje z rozmaitymi urządzeniami zewnętrznymi, które w określonych sytuacjach wymagają obsługi ze strony mikrokontrolera. W systemach pracujących w czasie rzeczywistym (ang. real-time) często definiuje się maksymalny dopuszczalny czas oczekiwania urządzenia na obsługę. Zapewnienie odpowiednio szybkiej reakcji mikrokontrolera na żądania obsługi zgłaszane przez urządzenia zewnętrzne wymaga wprowadzenia mechanizmu przerywania programu wykonywanego przez mikrokontroler. Na sygnał przerwania pochodzący z urządzenia zewnętrznego mikrokontroler przerywa aktualnie wykonywany program i przechodzi do procedury obsługi przerwania. Po jej zakończeniu mikrokontroler powinien powrócić do poprzednio 135 realizowanych czynności. Właściwa praca systemu wymaga zatem, by przed wystąpieniem do obsługi przerwania zapamiętać stan mikrokontrolera oraz adres instrukcji, od której należy wznowić program po zakończeniu obsługi przerwania. Oprócz przerwań wywoływanych przez urządzenia zewnętrzne, mikrokontrolery obsługują w podobnym trybie nadzwyczajne sytuacje zaistniałe w wyniku realizacji programu lub wynikłe ze specyficznych warunków pracy bloków funkcjonalnych układu. Generalnie przerwania dzieli się zwykle na cztery kategorie zdarzeń: - sytuacje wyjątkowe (ang. exception interrupts), - maskowalne przerwania sprzętowe (ang. event interrupts), - przerwania programowe (ang. software interrupts), - pułapki (ang. traps). Do sytuacji wyjątkowych zalicza się zdarzenia o największym znaczeniu dla poprawnego działania systemu, których obsługi nie można odłożyć na później. Jest tak na przykład w przypadku wystąpienia operacji dzielenia przez zero (ang. divide-byzero exception) lub żądania obsługi przez urządzenie zewnętrzne przyłączone do wejścia przerwań niemaskowalnych NMI (ang. non-maskable interrupt). Zgłoszenia pochodzące z tego wejścia nie mogą być zablokowane (zamaskowane) w sposób programowy, skąd bierze się nazwa przerwań tego typu. Sytuacje wyjątkowe są obsługiwane przez mikro-kontroler niezwłocznie po skompletowaniu aktualnie realizowanego cyklu rozkazowego, niezależnie od priorytetu, który ma wykonywany program. Przerwania maskowalne są generowane przez urządzenia peryferyjne, zarówno wbudowane w scalony układ mikrokontrolera, jak i przyłączone do niego z zewnątrz. Mogą być blokowane (maskowane) programowo przez ustawienie specjalnego bitu (bądź bitów) nazywanego maską przerwań. Bit lub bity maski są zwykle umieszczone w rejestrze wskaźników lub w wydzielonym rejestrze specjalnym SFR. Zgłoszenia przerwań tego typu mogą pochodzić na przykład od układu transmisji UART, liczników lub urządzeń zewnętrznych. Większość współczesnych mikrokontrolerów umożliwia nadawanie określonym źródłom przerwań priorytetów, według których ustalana jest kolejność obsługi przerwań. Przerwania programowe w rozbudowanych mikrokontrolerach również wykorzystują system priorytetowej obsługi. Są wywoływane przez umieszczenie w programie rozkazu przerwania, a więc wynikają z intencji programisty, a nie z nieprzewidywalnych, często losowych zdarzeń zachodzących w otoczeniu mikrokontrolera. W zaawansowanych metodach programowania przerwania programowe są wykorzystywane do manipulowania priorytetem fragmentów kodu programu. Pułapki, podobnie jak przerwania programowe, są rezultatem umieszczenia w programie odpowiedniego rozkazu, w tym przypadku rozkazu TRAP. Od przerwań programowych różnią się przeznaczeniem. Najczęściej są używane do śledzenia wykonywania programu w fazie jego testowania. Program nadzorujący śledzenie definiuje w wybranych punktach testowanego programu punkty zatrzymań (ang. breakpoints) i wstawia w te miejsca rozkazy generowania pułapek. Procedura obsługi przerwania (pułapki) polega w tym przypadku najczęściej na wyprowadzeniu zawartości rejestrów i wybranych obszarów pamięci. Pułapki są też przydatne jako wygodny mechanizm wywoływania procedur globalnych, dostępnych w całym programie, oraz do tworzenia oprogramowania, które może pracować w dwóch trybach: systemowym i użytkownika. Można wyróżnić następujące systemy przerwań: - system przerwań z programowym przeglądaniem urządzeń, - system przerwań z automatyczną detekcją źródła przerwania - system przerwań wektoryzowany. Przykładowy system przerwań z programowym przeglądaniem urządzeń pokazano na rys. 5.40. 136 Rysunek 5.40. Schemat układu przerwań mk PIC16F873 Każde urządzenie wewnętrzne jest wyposażone w przerzutnik służący do zapamiętania stanu urządzenia – zawiera flagę przerwania (np. INTF – flaga przerwania zewnętrznego). Żądanie przerwania powoduje ustawienie przerzutnika, czyli tej flagi. Każdemu przerwaniu może być przypisana maska (np. INTE). Gdy jest ona ustawiona i nastąpi zgłoszenie przerwania - ustawienie flagi przerwania, to do jednostki centralnej jest przekazywany sygnał przerwania, o ile globalna maska przerwań (GIE) jest ustawiona. W tym systemie jednostka centralna nie zna źródła (przyczyny) przerwania. Najczęściej obsługa wszystkich przerwań jest pod jednym wspólnym adresem (np. 04h). Zatem jednostka centralna musi programowo przejrzeć (przepytać) wszystkie urządzenia tak, jak przy programowym testowaniu stanu urządzeń, z tą różnicą, iż wykonuje ona tę czynność tylko w trakcie obsługi przerwania. Również i tutaj kolejność priorytetu przerwań zależy od przyjętej kolejności odpytywania. W tym systemie przerwań flagi poszczególnych przerwań nie są kasowane sprzętowo przy wejściu w obsługę przerwań, zatem należy je kasować programowo w trakcie ich obsługi. Zaletą tego systemu przerwań jest prostota struktury sprzętowej potrzebnej do jego realizacji. Jego główną wadą jest długi czas potrzebny na identyfikację źródła przerwania. Tablica 5.3. Zestawienie wektorów przerwań mk AT89C52 Najbardziej zaawansowanym i często stosowanym w mk jest system przerwań wektoryzowanych. W systemie tym na sygnał potwierdzenia przyjęcia przerwania przez to urządzenie, które zgłosiło przerwanie, podaje na szynę danych kod identyfikacyjny, który jest traktowany jako numer elementu w wektorze przerwań. Zatem każdemu przerwaniu przypisany jest adres obsługi przerwania w pamięci programu (np. tablica 5.3). 137 W przedstawionym przykładzie występuje 6 różnych źródeł przerwań: - PT0, PT1 – przerwania od licznika T0 lub od licznika T1 - PS – przerwanie od portu szeregowy - PX0, PX1 - przerwanie od zewnętrznych wejść INT0 lub INT1 - TF2, TXF2 – przerwanie od dodatkowych układów występujących w wersji AT89C52. Przerwania te mogą zostać odblokowane poprzez ustawienie bitu o wartości 1 w odpowiadającym temu przerwaniu bicie sterującym znajdującym się w rejestrze specjalnym sterującym systemem przerwań. W rejestrze tym znajduje się również bit EA włączający globalnie cały system przerwań (patrz rysunek). Rejestr IE: Adres: A8H EA - - ES ET1 EX1 ET0 EX0 Rysunek 5.41. Rejestr IE W tym systemie każdemu przerwaniu jest przypisany na stałe priorytet. Jeżeli pojawi się w tym samym czasie kilka przerwań to najpierw obsługiwane jest to o najwyższym priorytecie, a następnie według ważności priorytetów kolejne przerwania. Często przerwanie o wyższym priorytecie może przerwać obsługę przerwania o niższym (nigdy nie odwrotnie). Istnieje również możliwość zmiany kolejności priorytetów. Służy do tego celu rejestr poziomu priorytetów, np. rejestr IP dla 80C51: Rejestr IP: Adres: B8H - - PT2 PS PT1 PX1 PT0 PX0 Rysunek 5.42. Rejestr IP Gdzie: - PT0, PT1 – liczniki/timery 0 oraz 1 - PS - port szeregowy - PX0, PX1 - przerwanie zewnętrzne z wejścia INT0 lub INT1 Ustawienie w rejestrze IP znacznika dla danego źródła przerwania powoduje, że przerwanie to osiąga wyższy priorytet od przerwań, dla których znaczniki mają stan 0. Natomiast wzajemna relacja pomiędzy źródłami przerwań, których znaczniki mają ten sam stan, nie ulega zmianie. Zatem do obsługi przerwań przeważnie używane są trzy rejestry: rejestr z flagami przerwań, z maskami poszczególnych przerwań i maską globalną oraz rejestr poziomu priorytetów. W tym systemie flagi przerwań są zerowane sprzętowo przez obsługę przerwań. W mk 80C51 w przypadku jeżeli równocześnie wystąpi więcej przerwań niż jedno o takim samym priorytecie, są one obsługiwane w następującej kolejności: IE0, TF0, IE1, TF1, RI oraz TI. 138 Rysunek 5.43. Rejestr IE mk 80C51 Rysunek 5.44. Rejestr IP mk 80C51 139 Rysunek 5.45. System kontroli wejść mk 80C51 5.4.5. Tryby redukcji mocy mikrokontrolera Wszystkie współczesne mikrokontrolery mogą w czasie pracy wykonywać działania z normalną szybkością lub też mogą znajdować się w jednym z kilku stanów charakteryzujących się obniżonym poborem mocy. Właściwość ta jest szczególnie ważna, gdy mikrokontroler jest zasilany z baterii i musi pracować w czasie wielomiesięcznych, a nawet wieloletnich sesji, na przykład podczas misji kosmicznych. W stanie uśpienia (ang. sleep mode, idle mode) wykonywanie programu jest zatrzymane, pracuje natomiast zegar i niektóre urządzenia peryferyjne. Pobór mocy jest przy tym mniejszy od nominalnego około 2-10 razy. Wyprowadzenie mikrokontrolera ze stanu uśpienia następuje po sygnale RESET, zewnętrznym sygnale przerwania lub gdy wystąpi błąd adresu DMA albo też błąd identyfikacji źródła przerwania. Drugi ze stanów obniżonego poboru mocy jest nazywany stanem czuwania (ang. stand-by mode, power-down mode). W stanie tym zegar jest wyłączony, a mikrokontroler pobiera minimalną moc potrzebną do podtrzymania zawartości wewnętrznej pamięci i rejestrów. Zazwyczaj prąd potrzebny do tego celu nie przekracza kilkudziesięciu mikroamperów. Wyprowadzenie mikrokontrolera ze stanu czuwania odbywa się na sygnał przerwania zewnętrznego lub na sygnał RESET. Kolejnym sposobem redukcji poboru mocy jest zastosowanie dwóch oscylatorów. Jeden pracuje z maksymalną częstotliwością – główny oscylator – (np. 10MHz lub 40MHz), drugi z częstotliwością niską np. 32,768 kHz. Przejście z wysokiej do niskiej częstotliwości powoduje spadek pobieranej mocy o około trzy rzędy. Np. Rabbit 2000. Innym sposobem jest dzielenie podstawowego sygnału zegara przed przekazaniem do dalszych układów mikrokontrolera. Tego typu rozwiązanie zastosowane zostało w np. DS87C530. Sieć dystrybucji sygnałów zegarowych umożliwia również odłączanie od sygnału zegarowego jc, jak i urządzeń peryferyjnych lub wręcz wstrzymanie pracy oscylatora. Stąd mk może znaleźć się w następujących specjalnych trybach pracy: - tryb pełnej aktywności (RUN), - tryb, w którym nie pracuje procesor, a pracują wszystkie urządzenia peryferyjne (WAIT lub SLEEP) – inaczej tryb uśpienia, 140 - tryb, w którym nie pracuje procesor, a pracują niektóre urządzenia peryferyjne (układ przerwań, porty równoległe, przetworniki A/C zasilane zewnętrznym sygnałem zegarowym), tryb pełnego wstrzymania (zamrożenia) pracy mk – zatrzymany układ oscylatora, zatem żadne urządzenie nie pracuje, stan rejestrów i pamięci RAM jest „zamrożony” (STOP lub HALT). Rysunek 5.46. Fragment schematu blokowego mk Rabbit 2000 Mikroprocesor 80C51 nie używa bardzo rozbudowanych metod redukcji mocy. Pozwala na wprowadzenie w stan HALT oraz IDLE. Od sterowania trybem pracy wykorzystuje się jeden z rejestrów specjalnych o nazwie PCON. Rysunek 5.47. Rejestr PCON mk 80C51 W trybie IDLE działają wszystkie układy peryferyjne co pozwala mikrokontrolerowi na wyjście z tego stanu w przypadku przyjęcia przerwania. W trybie HALT układy peryferyjne są również wyłączone, a wprowadzenie mikrokontrolera w tryb normalnej pracy wiąże się z podaniem sygnału reset. 5.5. Architektura systemu pamięci mikroprocesora Architektura podsystemu pamięci ma duży wpływ na projektowanie i programowanie systemów cyfrowych z mikrokontrolerami. Ze względu na to, że część pamięci mieści się wewnątrz scalonego układu mikrokontrolera, a część jest dołączana z zewnątrz, budowa i działanie tego 141 podsystemu jest na ogół bardziej skomplikowane niż w przypadku konwencjonalnych systemów mikroprocesorowych. W zależności od typu, mikrokontroler może być wyposażony w kilka rodzajów wbudowanej pamięci wewnętrznej. Ze względu na technologię wykonania pamięci jak już wspomniano we wcześniejszym rozdziale dzieli się na sześć podstawowych odmian: - pamięć RAM (ang. random access memory) - może być zarówno odczytywana, jak i zapisywana przez CPU. Zawartość pamięci jest podtrzymywana tak długo, jak długo jest włączone zasilanie układu. Rozróżnia się statyczne i dynamiczne pamięci RAM. W mikrokontrolerach stosuje się również wbudowane statyczne pamięci RAM z podtrzymywaniem bateryjnym (ang. battery backed-up static RAM). Pamięci dynamiczne są zwykle używane jako zewnętrzne pamięci RAM. - Pamięć ROM (ang. read-only memory) może być tylko odczytywana. Zawartość pamięci jest określona na stałe podczas procesu produkcji. Pamięci tego typu są używane jako wewnętrzna pamięć programu do przechowywania kodu firmowego oprogramowania dostarczanego wraz z mikrokontrolerem (ang. firmware). Oprogramowanie to zawiera najczęściej procedury diagnostyczne oraz program do ładowania, uruchamiania i nadzorowania programów użytkownika, zwany monitorem. Rozróżnia się pamięci OTP (ang. one time programmable), EPROM (ang. erasable programmable ROM), EEPROM (ang. electrically erasable PROM), FLASH (ang. bulk erasable non-volatile memory). Pamięć EPROM (ang. erasable programmable ROM) służy do przechowywania programów i danych użytkownika. Zawartość pamięci może być zmieniana przez skasowanie poprzedniej zawartości i wpisanie nowej. Operacja ta wymaga zwykle wyjęcia układu z podstawki. Kasowanie przeprowadza się naświetlając pamięć promieniami ultrafioletowymi, natomiast programowanie odbywa się w sterowanym przez komputer programatorze, przy użyciu napięcia o wartości równej kilkanaście woltów. Liczba cykli kasowania-programowania jest ograniczona. Podobnie jak pamięć ROM, pamięć EPROM jest nieulotna, to znaczy po wyłączeniu zasilania zachowuje swoją zawartość. Pamięć jednokrotnie programowalna OTP (ang. one time programmable) ma budowę identyczną jak EPROM, ale proces programowania można wykonać tylko jeden raz. W odróżnieniu od pamięci EPROM, których obudowy są wyposażone w okno z kwarcu umożliwiające kasowanie w ultrafiolecie, pamięci OTP nie mają takiego okienka, nie mogą być więc kasowane. Ściślej biorąc, zawartość zaprogramowanej pamięci OTP można modyfikować, ale tylko przez zmianę jedynek na zera. Zaprogramowane wcześniej zera nie mogą być już przeprogramowane na jedynki. Pamięć EEPROM (ang. electrically erasable PROM) może być przeprogramowana elektrycznie, bez potrzeby kasowania ultrafioletem. Jest pamięcią nieulotna, stosowaną do przechowywania programów i danych. Wadą pamięci tego typu jest długi czas zapisu wynoszący zwykle od kilkuset nanosekund do około l milisekundy. Liczba cykli zapisu-kasowania jest ograniczona i wynosi typowo 10 000. Pamięć błyskowa FLASH (ang. bulk erasable non-volatile memory) ma cechy podobne do pamięci EEPROM. Jest nieulotna i może być przeprogramowana elektrycznie. W porównaniu z pamięcią EEPROM jest szybsza i zapewnia zwykle większą liczbę cykli zapisu-kasowania. Jest stosowana jako pamięć wewnętrzna lub zewnętrzna w nowoczesnych mikrokontrolerach. Ważną zaletą pamięci błyskowej jest możliwość szybkiego kasowania wybranych sektorów pamięci lub całej jej zawartości. Ten sam podstawowy typ mikrokontrolera jest zazwyczaj produkowany w wielu odmianach różniących się między innymi rodzajami i pojemnością wbudowanych pamięci. Niektóre bardziej popularne typy mikrokontrolerów są dostępne nawet w kilkudziesięciu różnych wersjach. W tablicy 142 5.4 przedstawiono dla przykładu zestawienie pojemności wbudowanej pamięci w podstawowych odmianach mikrokontrolerów rodziny 8051. Symbolem SRAM oznaczono statyczną pamięć RAM (ang. static RAM) używaną jako szybka, wewnętrzna pamięć danych. Tablica 5.4. Wybrane wersje mikrokontrolerów x51 Niektóre odmiany tego mikrokontrolera zawierają ponadto wydzielony, specjalizowany układ TPU (ang. timing processor unii) do operacji w czasie rzeczywistym. Jest on wyposażony we własną pamięć RAM o pojemności 2 kB. Wybierając typ mikrokontrolera do konkretnej aplikacji należy pamiętać, że wielkość wewnętrznej pamięci ma wpływ nie tylko na koszt układu, ale również na pobór mocy. Nie należy zatem stosować niepotrzebnie zbyt dużej, niewykorzystywanej w praktyce pamięci, zwłaszcza w układach zasilanych bateryjnie.5.5.1. Mapy pamięci mikroprocesorów Dla projektanta systemu, a także dla programisty piszącego oprogramowanie użytkowe mikrokontrolera ważny jest nie tylko rozmiar i rodzaj pamięci wewnętrznej oraz zewnętrznej, ale także rozmieszczenie poszczególnych pamięci w przestrzeni adresowej jednostki centralnej. Rozmieszczenie to opisuje się najczęściej w wygodnej postaci graficznej nazywanej mapą pamięci (ang. memory map). Oprócz adresów obszarów RAM, ROM i innych rodzajów pamięci mapa pamięci podaje także usytuowanie rejestrów uniwersalnych, adresów procedur obsługi przerwań, rejestrów specjalnych (SFR) oraz rejestrów układów wejścia/wyjścia. Kompletna, poprawnie zbudowana mapa pamięci powinna jednoznacznie określać adresy wszystkich obiektów dostępnych dla jednostki CPU i realizowanych przez nią programów. Najprostszą strukturę mają mapy pamięci w systemach z jednolitą przestrzenią adresową, w których wszystkie pamięci, rejestry i układy wejścia/wyjścia są umieszczone w jednej, wspólnej przestrzeni adresowej. Koncepcja jednolitej przestrzeni adresowej ma ważne odniesienie do architektury mikrokontrolera. Zakłada ona mianowicie, że podział przestrzeni adresowej na pamięć programu, pamięć danych oraz obszar wejścia/wyjścia jest czysto umowny i zależy wyłącznie od rozmieszczenia tych elementów w obszarze adresowym podczas projektowania systemu. Architektura tego rodzaju jest nazywana architekturą Von-Neumanna, od nazwiska wybitnego matematyka amerykańskiego (pochodzenia węgierskiego), który pierwszy podał teoretyczne 143 podstawy budowy komputerów. Komputer (procesor) Von-Neumanna ma jedną szynę danych wspólną dla danych i programu, a podział obszaru pamięci na dane i program jest umowny. Mikrokontroler z rysunku 5.3 ma właśnie taką architekturę, choć zaznaczono na nim oddzielne bloki pamięci danych i programu. Rozdziału tego dokonano jednak wyłącznie dla pokazania typowej organizacji (czyli implementacji) mikrokontrolera, natomiast na poziomie opisu architektury, czyli sposobu funkcjonowania procesora, obie pamięci mogą być używane zamiennie, jeśli są tylko odpowiedniego rodzaju (RAM, ROM itp.). Na rysunku 5.48 przedstawiono w uproszczeniu typową mapę pamięci mikro-kontrolera z jednolitą przestrzenią adresową. Pominięto na nim wartości adresów przypisanych początkom każdego z cząstkowych obszarów przestrzeni adresowej oraz przyjęto przykładowe usytuowanie tych obszarów, które dla konkretnych typów mikrokontrolerów może być nieco inne. Liczba znaków szesnastkowych (tetrad bitów) użyta do opisu adresów zależy oczywiście od liczby bitów szyny adresowej mikrokontrolera. Rysunek 5.48. Przykładowa struktura mapy pamięci mikrokontrolera z jednolitą przestrzenią adresową Pierwsze 256 bajtów przestrzeni adresowej ma szczególnie ważne znaczenie, dostęp bowiem do tego fragmentu pamięci może się odbywać przy użyciu krótkich, 8-bitowych adresów bezpośrednich. W obszarze tym umieszcza się zatem najczęściej używane obiekty, a więc rejestry uniwersalne, podręczną pamięć danych i stos, o którym więcej nieco później. Usytuowanie pozostałych elementów w wewnętrznym obszarze adresów nic jest już tak krytyczne. Zewnętrzna przestrzeń adresowa jest wykorzystywana opcjonalnie, jeśli w konkretnej aplikacji wewnętrzna pamięć ma niewystarczającą pojemność lub gdy w fazie uruchamiania systemu łatwiej jest modyfikować programy i dane ulokowane poza mikrokontrolerem. Zazwyczaj nawet wtedy pewna część zewnętrznej przestrzeni adresowej pozostaje nie wykorzystana. Planując mapę pamięci należy pamiętać, że dostęp do pamięci wewnętrznej jest szybszy niż do pamięci zewnętrznej. Często używane procedury i dane należy zatem, jeśli to tylko możliwe, lokować wewnątrz układu mikrokontrolera. 144 Architektura Von-Neumanna z jednolitą przestrzenią adresową wyróżnia się pro-i przejrzystością. Programowanie jest ułatwione, dostęp bowiem do danych, programu i urządzeń wejścia/wyjścia odbywa się przy użyciu zunifikowanych rozkazów wykorzystujących te same tryby adresowania. Architekturę tego typu najszerzej stosuje w prostych mikrokontrolerach firma Motorola. Niestety, elegancka struktura procesora Von-Neumanna ma również wady. Najważniejszą jest powolna realizacja cyklu rozkazowego, co wynika z wykorzystywania wspólnej szyny do pobierania rozkazów i danych. Z tego powodu większość współczesnych mikrokontrolerów wykorzystuje bardziej złożoną architekturę, nazywaną architekturą harwardzką (ang. Harvard architecture). Opiera się ona na użyciu dwóch oddzielnych szyn dla danych i rozkazów, dzięki czemu w trakcie pobierania argumentów wykonywanej właśnie instrukcji można równocześnie zacząć pobieranie następnego słowa rozkazowego (ang. pre-fetch). W procesorach tego typu obszary adresowe pamięci danych i programu, a także pamięci wewnętrznej i zewnętrznej nie są już jednolite, jak pokazano na rysunku 5.49. Rysunek 5.49. Uproszczona przykładowa mapa pamięci mikrokontrolera o architekturze harwardzkiej Zróżnicowane obszary adresowe dla pamięci danych i programu oraz pamięci wewnętrznej i zewnętrznej pociągają za sobą niejednoznaczność adresów. W przykładowej mapie z rysunku 2.22 jednostka centralna „widzi" pod adresem 0...00H cztery różne obiekty: wewnętrzną pamięć programu, zewnętrzną pamięć programu oraz zewnętrzną i wewnętrzną pamięć danych. By uniknąć tych niejednoznaczności konieczne staje się zatem stosowanie innych rodzajów rozkazów przy dostępie do poszczególnych obszarów pamięci, albo zróżnicowanych trybów adresowania. Prześledźmy to na przykładzie odwołań do pamięci danych. Załóżmy, że chcemy pobrać do akumulatora zawartość komórki o adresie 00H z wewnętrznej pamięci danych. W typowym mikrokontrolerze instrukcja realizująca takie przesłanie ma postać: MOV A,00H przy czym mnemonik (kod mnemotechniczny) zapisany jako MOV jest skrótem od angielskiego słowa move (przesuń, przemieść). Użyto bezpośredniego adresu 8-bitowego. Jeżeli natomiast chcemy wykonać takie przesłanie, ale z komórki zewnętrznej pamięci danych o adresie 00H, należy najpierw do rejestru R0 wpisać liczbę 00H, a następnie zastosować instrukcję: MOVX A,@R0 Symbol @ (czyt. at) oznacza tu adresowanie pośrednie zawartością rejestru RO. Jak widać, zastosowano rozkaz o innym mnemoniku (MOVX - MOVe eXternal) oraz inny tryb adresowania. Jeszcze innych odmian rozkazu MOV i innych trybów adresowania należałoby użyć przy dostępie do pamięci programu. 145 Przytoczony przykład pokazuje, że architektura harwardzka znacznie komplikuje programowanie mikrokontrolera, wymaga bowiem operowania rozmaitymi odmianami rozkazów i trybów adresowania. 5.5.2. Segmentacja pamięci Innego rodzaju problemy powstają wtedy, gdy chcemy, by mikrokontroler miał dużą przestrzeń adresową. Używany przez nas dotąd mechanizm adresowania, nazywany adresowaniem liniowym, staje się bowiem nieefektywny. Przy adresowaniu liniowym adres podany w instrukcji jest kompletnym, fizycznym adresem komórki pamięci. Jego długość wynika zatem z rozmiaru przestrzeni adresowej. Na przykład dla przestrzeni równej 64 k adres ma 16 bitów, natomiast dla przestrzeni 1M potrzebny jest już adres 20-bitowy. Bardzo duże przestrzenie adresowe wymagają więc długich adresów liniowych. Kod instrukcji i czas jej wykonania stają się zatem dłuższe. Ponadto we współczesnych systemach mikroprocesorowych bardzo ważna jest ochrona (protekcja) pamięci przed niepowołanym dostępem. Dotyczy to zwłaszcza systemów wielozadaniowych, które dopuszczają równoczesne rezydowanie w pamięci i współbieżne wykonywanie wielu zadań (programów). Z potrzebą protekcji mamy również do czynienia w systemach jednozadaniowych. W tym przypadku istotna jest ochrona obszaru programu, danych i stosu przed wzajemną interferencją. Wymienione problemy rozwiązuje segmentacja pamięci, która polega na podziale obszaru pamięci na mniejsze fragmenty nazywane segmentami. Długość segmentu zależy od typu mikrokontrolera, ale najczęściej stosuje się segmenty o długości 64 k. W najprostszej wersji segmentacji liczba i usytuowanie segmentów w przestrzeni adresowej są stałe. W pełnej wersji system ten pozwala natomiast swobodnie definiować położenie segmentów przy użyciu rejestrów segmentów (ang. segment registers), które podają adresy początków segmentów (adresy bazowe). W praktyce najczęściej wymaga się, by segment zaczynał się od adresu podzielnego przez 2k (k = 1,2,...). Jeśli przyjmiemy ; = 4, początki segmentów będą przypadać przy adresach podzielnych przez 16, to znaczy że końcowe cztery bity adresów początków segmentów będą zawsze zerami. Dzięki temu zamiast pamiętać cały adres początku segmentu, można pominąć mniej znaczące cztery bity. Adres efektywny przy segmentacji pamięci oblicza się zawsze jako sumę dwóch składników: przesuniętej o k bitów w lewo zawartości odpowiedniego rejestru segmentu i adresu wewnątrz segmentu, nazywanego przesunięciem (ang. offset, displacement). Jeśli teraz przyjmiemy, że określone grupy instrukcji współpracują tylko z określonym segmentem, np. tylko z segmentem kodu programu (ang. code segment) lub tylko z segmentem danych (ang. data segment), to w części adresowej instrukcji wystarczy podawać tylko przesunięcie. Jednocześnie mamy zatem rozwiązany problem protekcji i długości adresów. Ilustrację segmentacji pamięci podano na rysunku 5.50. 146 Rysunek 5.50. Obliczanie adresu efektywnego w systemie z segmentacją pamięci Dodatkową korzyścią z segmentacji jest możliwość łatwej realizacji pamięci wirtualnej (ang. virtual memory). Koncepcja ta polega na tym, że w danej chwili w rzeczywistej (fizycznej) pamięci przebywa tylko część programu i danych, natomiast reszta jest ulokowana na innym nośniku (np. w pamięci dyskowej). W zależności od potrzeb, do pamięci fizycznej sprowadzane są kolejne porcje kodu i danych, stwarzając wirtualne wrażenie dysponowania dużą pamięcią fizyczną. Podział pamięci na mniejsze fragmenty jest niezbędny, by móc tę koncepcję zrealizować w praktyce. Oprócz segmentacji stosuje się w tym celu podział pamięci na strony (ang. paging). Zagadnienie pamięci wirtualnej i stronicowania dotyczy rozbudowanych mikrokontrolerów z procesorami klasy embedded. Jego szersze omówienie można znaleźć w pracach dotyczących systemów operacyjnych i architektury mikroprocesorów. 5.5.3. Stos Wszystkie stosowane obecnie w mikrokontrolerach rodzaje pamięci półprzewodnikowych umożliwiaj ą bezpośredni dostęp do komórki o podanym adresie. W pewnych przypadkach wygodna jest jednak inna organizacja dostępu, nazywana stosem. Przypomnijmy, że pojęcie stosu pojawiło się już wcześniej, przy omawianiu rejestrów mikrokontrolera. Wyróżniono tam rejestr SP, który przechowuje adres szczytu stosu, w sposób pokazany na rysunku 5.51. Rysunek 5.51. Stos: a) operacja zapisu, b)operacja odczytu Obszar stosu jest fragmentem pamięci RAM, zapisywanym i odczytywanym zgodnie z algorytmem LIFO (ang. Lasl-In First-Out). Przy zapisie kolejne bajty są umieszczane w komórkach o kolejnych adresach, podobnie jak warstwy na stosie. Zawartość rejestru SP pokazuje adres szczytu stosu i po każdym zapisie jest zwiększana o jeden. Przy odczycie informacje są „zdejmowane" ze stosu w odwrotnej kolejności, przy czym odczyt każdego bajtu powoduje zmniejszenie zawartości rejestru SP o jeden. Korzystając ze standardowych rozkazów zapisu i odczytu ze stosu (oznaczanych zwykle odpowiednio przez PUSH i POP), nie można ominąć tej kolejności i dostać się do wnętrza stosu. W trakcie wykonywania programu stos „pulsuje'', to znaczy jego obszar wzrasta lub maleje. Rysunek 5.51 i podany wyżej komentarz dotyczą stosu, który rozbudowuje się w stronę wzrastających adresów. Konwencję tę stosuje większość producentów mikrokontrolerów, można jednak spotkać i takie typy, w których stos rozbudowuje się w stronę malejących adresów. Kierunek rozbudowywania się stosu jest ważny o tyle, że programista powinien zadbać, by stos miał dostatecznie dużo miejsca w pamięci RAM i nic spowodował zniszczenia danych lub sytuacji wyjątkowej. Po sygnale RESET przyjmowana jest ustalona wartość wskaźnika stosu (różna dla 147 różnych typów mikrokontrolerów). Programista może ją zmienić wpisując do rejestru SP inną wartość. Stos jest wykorzystywany w trzech sytuacjach: - do zapamiętywania stanu CPU przed przejściem do obsługi przerwań, - do zapamiętywania adresu powrotu z podprogramów i procedur obsługi przerwań, - do chwilowego zapamiętywania (chronienia) zawartości rejestrów i zmiennych w programie użytkownika. Jeśli programista korzysta ze stosu, powinien zbilansować liczbę operacji zapisu i od-w każdej procedurze, w przeciwnym przypadku nastąpi zaburzenie mechanizmu automatycznego zapamiętywania i odtwarzania adresów powrotu oraz stanu jednostki centralnej. 148 6. Dodatkowe bloki funkcjonalne mikrokontrolerów Lista bloków funkcjonalnych mikrokontrolerów przedstawiona w poprzednich rozdziałach została ograniczona tylko do tych zespołów, które są niezbędne do autonomicznej prac CPU. Pominięto natomiast wszystkie inne, najczęściej opcjonalne bloki, zapewniając współpracę z otoczeniem. Należą do nich: - zespoły wejść i wyjść cyfrowych (porty), - przetworniki analogowo-cyfrowe i cyfrowo-analogowe, - bloki sterowania szynami i współpracą z pamięciami zewnętrznymi, - liczniki, układy czasowe, modulatory szerokości impulsów itp., - zespoły obsługi przerwań, - specjalizowane bloki transmisji danych w postaci szeregowej i równoległej. 6.1. Porty wejścia wyjścia Do równoległej transmisji danych cyfrowych służą w mikrokontrolerach zespoły linii wejścia/wyjścia nazywane portami równoległymi (ang. parallel ports lub I/O ports). W przeważającej liczbie przypadków porty zawierają po 8 linii, mogą zatem transmitować dane bajtami. Liczba portów i ich wyprowadzeń (ang. pins) jest ograniczona przez liczbę wyprowadzeń obudowy mikrokontrolera. Wyróżnia się trzy rodzaje linii portów: dwukierunkowe (ang. quasibidirectional), z otwartym obwodem drenu tranzystora (ang. open drain), o zwiększonej obciążalności (ang. push-pull output). Najbardziej uniwersalne są linie dwukierunkowe, które mogą służyć zarówno jako wejście, jak i wyjście sygnału bez potrzeby rekonfiguracji portu, to znaczy bez programowego przełączania buforów. Jest to możliwe dzięki temu, że przy stanie wysokim na wyjściu, linia zewnętrzna jest sterowana małym prądem, umożliwiając urządzeniu zewnętrznemu na wprowadzenie końcówki w stan niski, wpływając na kierunek transmisji. Natomiast jeśli wyjście jest w stanie niskim, jest sterowane w taki sposób, że może przyjąć duży prąd z obwodów zewnętrznych. Właściwość tę uzyskuje się stosując do sterowania linii trzy tranzystory w konfiguracji pokazanej na rysunku 6.1. Tranzystor T2 jest włączany, gdy mikrokontroler ustawia na wyjściu stan wysoki. Na nieobciążonym wyjściu jest wówczas stan logiczny “l”. Tranzystor T3 jest włączany wtedy, gdy mikrokontroler wyprowadził na linię stan wysoki, a obciążone wyprowadzenie również znajduje się w stanie wysokim. Zapewnia to odpowiedni prąd wyjściowy w stanie wysokim. Obciążalność wyjścia w stanie wysokim pozwala na sterowanie przynajmniej kilkoma wejściami TTL. Jeśli na linii ustawionej przez mikrokontroler w stan ,,1" został wymuszony z zewnątrz stan niski, tranzystor T3 wyłącza się, natomiast tranzystor T2 pozostaje włączony. Rysunek 6.1. Układ dwukierunkowej linii portu Układ wymuszający z zewnątrz stan "0" musi w związku z tym przyjąć odpowiednio duży prąd. Tranzystor Tl jest wykorzystywany do przyspieszenia przełączania linii przy przejściu z ,,0" na 149 ,,1" . Tranzystor ten jest włączany na krótki czas (zwykle dwa okresy zegara) i skraca czas narastania napięcia na wyjściu. Przedstawiona konfiguracja dwukierunkowej linii portu, aczkolwiek prosta w realizacji, ma istotne wady. Najważniejszą z nich jest mały prąd wyjściowy, toteż linia ma ograniczone zdolności sterowania układami przyłączonymi z zewnątrz. W szczególności nie nadaje się do bezpośredniego sterowania baz tranzystorów n-p-n używanych powszechnie do zwiększania prądu wyjściowego układów. Innym rodzajem układów wyjściowych są układy z otwartym obwodem drenu, które są obciążane z zewnątrz, zazwyczaj przez rezystory przyłączone do napięcia zasilania - Vcc. Zaletą takich linii jest możliwość realizacji poza mikrokontrolerem funkcji "zwartego iloczynu" przez połączenie dwóch lub większej liczby wyjść. Strukturę układu sterującego linią z otwartym obwodem drenu przedst. na rys. 6.2. Rysunek 6.2. Linia z otwartym obwodem drenu Jeśli mikrokontroler musi sterować układami zewnętrznymi bezpośrednio, wymagana jest zwiększona obciążalność wyjść portów, czyli większy prąd wyjściowy w stanie wysokim na wyjściu. Najprostszą konfigurację wyjścia o takich właściwościach pokazano na rysunku 6.3. Przedstawione odmiany sposobów sterowania linii portów są stosowane w mikrokontrolerach w różny sposób. Dla przykładu, mikrokontrolery z rodziny x5l są wyposażone w cztery porty oznaczone symbolami PO, Pl, P2 i P3. Wszystkie porty są dwukierunkowe, wyposażone w rejestr zatrzaskowy danych wyjściowych i bufor danych wejściowych. Port PO, którego linie są sterowane układami o strukturze przedstawionej na rysunku 6.4, nie ma wewnętrznego obciążenia obwodu drenu tranzystora wyjściowego. Tranzystor FET umieszczony w tym obwodzie jest włączony tylko wtedy, gdy na wyjściu linii mikrokontroler ustawił stan "l". W rezultacie wyjście zachowuje się jak układ z otartym obwodem drenu. Rysunek 6.3. Linia o zwiększonym prądzie wyjściowym 150 Rysunek 6.4. Praktyczna realizacja układu sterowania linią portu o zwiększonej obciążalności (port P0 w mikrokontrolerze x51) Zapis" l" do przerzutnika zatrzaskowego powoduj e wyłączenie obu tranzystorów i linia może pracować jako wejście o dużej impedancji. W omawianym przykładzie wyjścia PO i P2 oraz wejście PO są używane do współpracy z zewnętrznymi pamięciami. Port PO wyprowadza mniej znaczący bajt adresu, multipleksowany z danymi, które mogą przepływać w dwóch kierunkach. Port P2 wyprowadza bardziej znaczący bajt adresu, jeśli potrzebne są adresy 16-bitowe, lub służy jako port wejścia/wyjścia. Linie portu P3 spełniają podwójne funkcje. Mogą służyć do równoległej transmisji danych, ale alternatywnie mogą być też wykorzystywane jako wejścia zgłoszeń przerwań, linie układu transmisji szeregowej, linie strobu zapisu i odczytu zewnętrznej pamięci oraz linie wejściowych impulsów napełniających liczniki wbudowane do mikrokontrolera. Alternatywne funkcje tych linii są dostępne tylko wtedy, gdy do rejestru zatrzaskowego zostały wpisane stany" l ". Rysunek 6.5. Linia portu z wewnętrznym obciążeniem (port P1 mikrokontrolera x51) W przeciwnym przypadku stan linii jest niski, niezależnie od sterowania z zewnątrz. Rejestry zatrzaskowe portów składają się z przerzutników typu D, które zatrzaskują stan na wewnętrznej szynie danych. Stan rejestrów może być odczytywany, jeśli CPU wyśle sygnał odczytu rejestru. Mikrokontroler ma zatem dwie możliwości odczytu portu: 1) rejestru zatrzaskowego oraz 2) stanu wyprowadzenia sterowanego z zewnątrz jako wejście. Fakt ten często utrudnia zrozumienie działania portów przez początkujących programistów, którzy nie rozróżniają obu operacji. W istocie odczyt rejestru jest tylko "przypomnieniem" sobie przez program wartości, którą sam tam wcześniej zapisał, natomiast odczyt stanu końcówek jest rzeczywistą operacją odczytu danych z portu mikrokontrolera traktowanego jako wejście. Obie operacje są wykonywane przez różne instrukcje, które należy właściwie stosować, w zależności od tego czy pożądany jest odczyt rejestru, czy też 151 stanu linii. Rysunek 6.6. Linia portu ze sterowanym obciążeniem (port P2 mikrokontrolera x51) Porty P0 i P2, ze względu na to, że w omawianym mikrokontrolerze służą również do przesyłania adresów i danych przy współpracy z pamięciami zewnętrznymi, są wyposażone w odpowiednie linie sterujące przełączaniem źródła informacji. Przełączanie to odbywa się przy użyciu multiplekserów doprowadzających sygnał na bramkę tranzystora wyjściowego linii. Rysunek 6.7. Linia portu z alternatywną funkcją (port P3 mikrokontrolera x51) W rozważanym przypadku mikrokontrolerów rodziny x5l linie portów Pl, P2 i P3 mogą sterować trzema wejściami TTL LS. Porty traktowane jako wejścia mogą być sterowane przez wyjścia z otwartym kolektorem lub drenem, ale przełączanie linii ze stanu ,,0" do ,,1" jest relatywnie wolne. Na rysunku 6.8 pokazano układ ilustrujący sterowanie linii portu przez obwód tranzystora TN z otwartym drenem. Pojemność pasożytnicza obciążająca wejście jest równa typowo około 100 pF. 152 Rysunek 6.8. Warunki sterowania linii portu przez tranzystor z otwartym drenem Dynamiczna analiza procesów przełączania linii portów ma znaczenie w systemach sterowania w czasie rzeczywistym, kiedy często wymaga się, aby czasy przełączania nie przekraczały zadanych wartości krytycznych. Niekiedy ważna jest również stromość zboczy sygnału. Parametry te są podawane w katalogach jako wartości maksymalne i typowe. Niektóre mikrokontrolery są wyposażone w specjalne, szybkie układy wejścia/wyjścia, dla których czas przełączania, zarówno ze stanu ,,0" do stanu "l ", jak i odwrotnie jest bardzo krótki i wynosi kilkaset nanosekund. W przypadku standardowych mikrokontrolerów czas przełączania może być o rząd wielkości dłuższy. Rysunek 6.9. Przełączenie linii portu mikrokontrolera x51 ze stanu „0” do stanu”1” Na rysunku 6.9 przedstawiono typowy przebieg przełączania linii portu ze stanu niskiego do wysokiego odniesiony do układu z rysunku 6.8. W obszarze oznaczonym literą A pojemność obciążenia jest ładowana tylko przez tranzystor T2. Po upływie około 5 us napięcie na wyprowadzeniu osiąga wartość 2V. W obszarze B włącza się tranzystor T3 i szybkość ładowania wzrasta około l0-krotnie. Mimo to napięcie wyjściowe osiąga wartość zbliżoną do V cc dopiero po około 10 us. Podany przykład wskazuje, że od chwili wysłania do portu danych do chwili ustalenia się na wyprowadzeniach odpowiednich napięć może upłynąć nawet kilkadziesiąt cykli zegara. 6.2. Układy licznikowe/czasowe Współpraca mikrokontrolera z otoczeniem w czasie rzeczywistym wymaga odliczania czasu lub generowania złożonych sekwencji binarnych. Jest to realizowane przez specjalizowane bloki nazywane licznikami (ang. counters) lub układami czasowymi (ang. timers) z dokładnością oscylatora kwarcowego mk. Liczba liczników stosowanych w mk i ich długość wyrażona w bitach, różnią się dla konkretnych typów mk. Większość mk ma przynajmniej dwa liczniki 16- bitowe, każdy mk posiada choćby jeden licznik 8-bitowy. Najprostszą strukturę takiego układu pokazano na rys. 6.10. Składa się on z rejestru o określonej długości i niezaznaczonych na rys. rejestru zawierającego np. bity przepełnienia, ustawiające tryb pracy, bit startu zliczania licznika itd. Rejestr przesuwny zliczający liczbę zmian poziomów doprowadzonych do niego sygnałów jest dostępny z poziomu programu użytkownika, jako rejestr (dla liczników 8-bitowych) lub para rejestrów (dla liczników 16- bitowych) o określonych adresach w obszarze pamięci danych. 153 Rysunek 6.10. Schematyczna budowa układu czasowego Z rys. 6.10 widać, że najprostsze układy czasowe mogą pracować w dwóch podstawowych konfiguracjach: − jako właściwe układy czasowe (timers) – Są wtedy taktowane wewnętrznym sygnałem zegarowym przeznaczonym do taktowania jednostki centralnej. Timery wykorzystywane są w programie użytkownika jako wzorce czasu. W celu generowania wzorców czasu o różnej długości wewnętrzny sygnał zegarowy, przed doprowadzeniem do układu czasowego, przechodzi przez programowalny dzielnik częstotliwości. − jako liczniki (counters) – Są one wtedy taktowane zewnętrznymi sygnałami doprowadzanymi poprzez linie wejściowe portów i wykorzystywane w programie użytkownika np. jako liczniki zmian poziomów sygnałów zewnętrznych Kolejna właściwość liczników to sposób zliczania impulsów. Liczniki mogą zliczać impulsy w górę, tzn. inkrementować lub w dół czyli dekrementować. W praktyce mk są wyposażone w bardziej rozbudowane układy licznikowe. Liczniki te są używane zazwyczaj do realizacji następujących funkcji: − określenia (mierzenia) odstępów czasu między zdarzeniami zachodzącymi na zewnątrz mk, sygnalizowanymi przez impulsy elektryczne doprowadzone do mk. Funkcja ta bywa nazywana rejestracją zdarzeń (ang. input event capture), − generowania impulsów (sekwencji impulsów) w odstępach czasu o zaprogramowanej wartości (ang. output compare) lub przebiegu okresowego o zadanej częstotliwości, − generowania sygnałów impulsowych o określonym czasie trwania lub sygnałów okresowych o zadanym współczynniku wypełnienia (PWM – ang. puls width modulation), − sterowania szybkością transmisji w portach szeregowych, zarówno w trybie synchronicznym, jak i asynchronicznym (ang. baud rate generator), − realizacji zadań licznika nadzorcy – watchdoga, omówionych w następnym rozdziale. Podstawową konfigurację licznika jako rejestratora zdarzeń pokazano na rys. 6.11. Rysunek 6.11. Licznik w konfiguracji rejestratora zdarzeń 154 Jego zadaniem jest określenie czasu wys-tąpienia zdarzenia zewnętrznego sygnalizowanego przez impuls elektryczny podany na wejście. Czas ten jest mierzony w sposób względny, tzn. w stosu-nku do chwili zezwolenia na rozpoczęcie zliczenia w liczniku. Przed uruchomieniem zliczania program zeruje licznik i określa zbocze sygnału zewnętrznego, które ma spowodować rejestrację zdarzenia. Po wystąpieniu tego zbocza zawartość licznika jest przepisywana do rejestru zatrzaskowego rejestratora. Układ może równocześnie wygenerować przerwanie informujące jc o zarejestrowaniu zdarzenia, jeśli wcześniej ustawiono zezwolenie przerwania. W tym układzie odczyt rejestru zatrzaskowego musi nastąpić przed wystąpieniem kolejnego zdarzenia, ponieważ pracujący cały czas licznik przy następnym sygnale zewnętrznym zmieni zawartość rejestru zatrzaskowego. Rejestrując czas wystąpienia kolejnych zboczy można łatwo określić częstotliwość sygnału okresowego lub szerokość impulsów. W pierwszym przypadku rejestruje się dwa następujące po sobie zbocza o tej samej polaryzacji, natomiast w drugim – dwa zbocza o różnej polaryzacji. Szczególne zastosowanie tej konfiguracji polega na generowaniu impulsów o programowalnym czasie opóźnienia w stosunku do zewnętrznych impulsów odniesienia. W tym przypadku układ pracuje w mieszanym trybie rejestrator – generator. Po zarejestrowaniu zdarzenia licznik odmierza zaprogramowaną liczbę impulsów i generuje sygnał wyjściowy. W konfiguracji programowanego generatora impulsów licznik pracuje zgodnie z zasadą pokazaną na rys. 6.12. Jc wpisuje do rejestru komparatora liczbę określającą chwilę wygenerowania impulsu, po czym uruchamia licznik. Po upływie zaprogramowanej liczby cykli zegara, komparator wykrywa zrównanie się zawartości licznika i rejestru, po czym generuje sygnał wyjściowy. Jednocześnie licznik może wysyłać do jc przerwanie, o ile zostało odblokowane. Większość liczników/ generatorów wytwarza impulsy o zadanej polaryzacji. Ponadto po wygenerowaniu impulsu przez układ licznika jc może zlecić nowy cykl generacji z innym początkowym ustawieniem rejestru komparatora. Rysunek 6.12. Licznik w układzie programowalnego generatora impulsów W ten sposób mk jest w stanie generować przebieg o dowolnie ustalanych czasach trwania kolejnych impulsów. Wadą przedstawionej prostej konfiguracji generatora jest to, że przy generacji kolejnych impulsów powstaje błąd wynikający z czasu działania jc (zwykle dwa okresy sygnału zegarowego), ponieważ jc musi po każdej operacji wpisywać nową zawartość do rejestru komparatora. W celu wyeliminowania tej wady stosuje się ulepszone układy liczników z podwójnymi rejestrami i komparatorami, nazywane licznikami z buforowaniem (ang. buffered output compares). W tych układach aktualnie zaprogramowana wartość opóźnienia jest przechowywana w rejestrze jednego z kanałów, natomiast wartość kolejnego opóźnienia w rejestrze drugiego kanału (rys. 6.13). Blok licznika autonomicznie steruje układem selekcji kanału. W najprostszym przypadku kanały pracują naprzemiennie. Należy pamiętać aby nie wpisywać danych do rejestru aktualnie pracującego kanału. 155 Rysunek 6.13. Licznik w układzie programowalnego generatora impulsów z podwójnym kanałem W konfiguracji PWM licznik pracuje jako generator fali prostokątnej o programowanym współczynniku wypełnienia. Układ ten pokazano na rys. 6.14. Zasada jego pracy jest następująca. Jeśli zawartość licznika osiągnie zaprogramowaną liczbę NT określającą okres impulsów, komparator ustawia przerzutnik wyjściowy. Sygnał przepełnienia licznika określa zatem początek okresu generowanego przebiegu. W czasie zliczania kolejnych impulsów zegara zawartość licznika jest porównywana z zawartością rejestru szerokości impulsów, a po zrównaniu się z nią generowany jest sygnał „=”, który zeruje przerzutnik wyjściowy. Tym samym impuls wytwarzany przez PWM kończy się. Rozdzielczość wyjściowa układu PWM jest określona przez częstotliwość sygnału zegara i długość słowa licznika. Rejestr sterujący PWM zawiera dodatkowo wydzielone bity, które pozwalają na wyjściu uzyskać sygnał stały na poziomie „0” lub „1”. Jako przykład prostego układu licznikowego można przedstawić 8-bitowy licznik TIMER0 mk PIC16F873. Rysunek 6.14. Licznik w trybie PWM W konfiguracji PWM licznik pracuje jako generator fali prostokątnej o programowanym współczynniku wypełnienia. Układ ten pokazano na rys. 6.14. Zasada jego pracy jest następująca. Jeśli zawartość licznika osiągnie zaprogramowaną liczbę NT określającą okres impulsów, komparator ustawia przerzutnik wyjściowy. Sygnał przepełnienia licznika określa zatem początek okresu generowanego przebiegu. W czasie zliczania kolejnych impulsów zegara zawartość licznika jest porównywana z zawartością rejestru szerokości impulsów, a po zrównaniu się z nią generowany jest sygnał „=”, który zeruje przerzutnik wyjściowy. Tym samym impuls wytwarzany przez PWM kończy się. W przypadku mk 80c51 blok liczników/timerów składa się z 2 układów 16 bitowych, których działanie jest uzależnione od konfiguracji zapisanej w rejestrach TCON oraz TMOD przedstawionych rysunku 6.15 i 6.16. Mogą one pracować zarówno jako Timery (liczą impulsy z rezonatora kwarcowego podzielone przez 12), jak i jako liczniki (liczą impulsy podłączone do linii wejściowej mikrokontrolera). Naliczanie odbywa się 156 na liczbach 16-bitowych, znaczy to, że maksymalna wartość wynosi 65536. Przepełnienie w liczniku, tzn. przejście ze stanu FFFFH do 0000H, jest sygnalizowane odpowiednią flagą. W tym momencie może być również zgłaszane przerwanie do mikrokontrolera, co jest przedstawione w lekcji 12. Stan początkowy liczników może być dowolnie ustawiany tak, aby zakończenie zliczania (ustawienie flagi bądź przerwanie) oznaczało odliczenie zadanego czasu. Timery w mikrokontrolerze 8051 mogą pracować w czterech różnych trybach. Będą one przedstawione na przykładzie pracy timera jako licznika impulsów zewnętrznych. Timer może liczyć impulsy zewnętrzne podłączone do linii procesora: Timer0 z linii P3.4 zwanej też T0, Timer1 z linii P3.5 zwanej też T1. Wszystkie rejestry związane z timerami są położone w obszarze rejestrów specjalnych. Należą do nich: TL0 - młodsza część Timera0 (8 bitów) TH0 - starsza część Timera0 (8 bitów) TL1 - młodsza część Timera1 (8 bitów) TH1 - starsza część Timera1 (8 bitów) TMOD - ustawia tryby pracy timerów 0 i l (Cztery młodsze bity rejestru TMOD ustawiają tryb pracy Timera0, natomiast 4 starsze w sposób analogiczny ustawiają Timer 1.) TCON - 4 bity z tego rejestru sterują pracą timerów. Rysunek 6.15. Rejestr TMOD mk 80c51 Rysunek 6.16. Rejestr TCON mk 80c51 W rejestrze TMOD: - Bit C / T decyduje o pracy jako timer lub jako licznik. Stan 0 powoduje zliczanie impulsów wewnętrznego zegara mikrokontrolera (rezonator kwarcowy /l2), natomiast stan l impulsów zewnętrznych z wejścia Tx. - Bit GATE decyduje o sposobie kontrolowania pracy timera. Przy ustawieniu 0, start/stop timera odbywa się przez ustawienie bitu TRx (z rejestru TCON). Przy ustawieniu l dodatkowo o pracy timera decyduje stan linii INTx. - Dwa bity Ml, M0 ustawiają odpowiedni tryb pracy timera - 0...3. W rejestrze TCON znajdują się po 2 bity sterujące dla każdego timera: - TRx: l - start timera, 0 - zatrzymanie timera. - TFx flaga przepełnienia - ustawiona automatycznie na 1 w momencie przekroczenia zakresu timera. Jak wspomniano wyżej, ustawienie bitu GATE w rejestrze TMOD powoduje, że praca timera jest dodatkowo kontrolowana przez linię INTx. Poniżej przedstawiono schematy blokowe ilustrujące poszczególne konfigurację pracy liczników/timerów mikrokontrolera 80C51. 157 Rysunek 6.17. Układ TIMERA0 w przypadku pracy w modzie 0 i 1 W trybie 0 timer pracuje jako rejestr 13-bitowy, tzn. TL1 traktowany jest jako rejestr 5-bitowy. Rejestr ten jest w rzeczywistości nadal rejestrem 8-bitowym i cały jest zwiększany, ale przeniesienie z rejestru TLI do rejestru THl jest generowane przy przepełnieniu młodszych 5 bitów rejestru TLI. Tak skonfigurowany timer może liczyć do wartości 8192. W trybie l timer pracuje jako pełny rejestr 16-bitowy. W tym trybie ustawienie flagi TF1 następuje przy doliczeniu do wartości 65536. Rysunek 6.18. Układ TIMERA0 w przypadku pracy w modzie 2 W trybie 2 timer pracuje jako rejestr 8-bitowy. Wykorzystany jest do tego TLI. W momencie przekroczenia jego zakresu (256) następuje ustawienie flagi TF1 i jednoczesne załadowanie rejestru TLI zawartością rejestru THl. Wpisując do rejestru THl odpowiednią wartość, na przykład 256-10, można uzyskać ustawienie flagi TF1 co 10 impulsów wejściowych. 158 6.2. Układy licznikowe/czasowe – cd. (80c51) Rysunek 6.19. Układ TIMERA0 w przypadku pracy w modzie 3 W trybie 3 Timerl jest zatrzymywany, natomiast Timer0 pracuje jako dwa niezależne liczniki 8-bitowe. Licznik TL0 sterowany jest przez te same bity, tak jak cały Timer0 w innych trybach. Natomiast licznik TH0 może pracować tylko jako timer i jest sterowany bitem TR1 oraz ustawia flagę TF1. Timerl może w tym momencie pracować w innym, dowolnym trybie, ale nie będzie można go zatrzymać i nie ustawi on flagi TF l. 6.3. Układy nadzorujące – układ watchdog Do układów nadzorujących poprawność pracy mk można zaliczyć: - autonomiczne liczniki watchdog (licznik nadzorcy), - monitory sygnału zegarowego, - układy detekcji zaniku i powrotu napięć zasilających, - układy detekcji przyczyn awarii systemowych. Część z tych układów została już przedstawiona przy omawianiu układu oscylatora i dystrybucji sygnału zegarowego oraz układu resetu. Najczęściej stosowanym układem nadzorującym pracę mk jest licznik watchdog. Poprawnie pracujący mk charakteryzuje się pewną sygnaturą częstotliwościową lub czasową zawierającą się w ściśle określonych granicach. Wynika to z zasady pisania oprogramowania na mk (rys 6.20). Rysunek 6.20. Struktura programu użytkownika w mk 159 Program użytkownika, po części inicjalizacyjnej, jest wykonywany w niekończącej się pętli od czasu do czasu przerywanej przez obsługę przerwań. Program ten jest jedynym programem jaki znajduje się w mk – w przeciwieństwie do komputerów PC, gdzie program użytkownika jest uruchamiany przez pracujący na okrągło system operacyjny. W mk nie ma systemu operacyjnego. Zatem mk wykonuje tylko to co napiszemy. Stąd aby mk działał prawidłowo nasz program musi pracować w nieskończonej pętli. Pętla ta jest wykonywana z określoną częstotliwością możliwą do obliczenia przez programistę (znamy częstotliwość oscylatora, z dokumentacji wiemy ile cykli zegarowych potrzebuje każda instrukcja i oczywiście wiemy ile jest tych instrukcji w pętli). Jeżeli w jakimś momencie pętla ta zawiesi się (np. błąd w programie) lub będzie wykonywana zdecydowanie wolniej niż powinna (np. nieprawidłowa praca urządzeń peryferyjnych) jest to równoważne z wykryciem sytuacji alarmowej. Układem, który to wykrywa jest autonomiczny licznik watchdog. Gdy wykryje on tę sytuację wysyła sygnał reset zerujący mk oraz ustawia odpowiednie bity w rejestrze przechowującym informację o przyczynach wyzerowania procesora. Zasada jego działania jest następująca: Układ ten jest licznikiem zasilanym sygnałem z własnego oscylatora RC (np. dla PIC16F873 i AT90S8515) lub oscylatora kwarcowego (rys. 6.21). Jeśli nastąpi jego przepełnienie to wysyła on sygnał reset. Czyli trzeba ten licznik co jakiś czas zerować. Służą do tego specjalne instrukcje np. CLRWDT dla PIC16F873, które należy umieścić w nieskończonej pętli programu (lub inaczej – głównej pętli programu). Czyli jak program pracuje prawidłowo to rozkaz zerujący watchdog jest wykonywany cyklicznie z założoną częstotliwością. Natomiast gdy program się zawiesi to instrukcja ta nie zostanie wykonana na czas i licznik watchdoga przepełni się wywołując reset mk. Rysunek 6.21. Układ watchdog mk ST72215G W przypadku mk ST72215G należy cyklicznie wpisywać do rejestru CR watchdoga bajt o wartości od FFH do C0h w zależności od tego ile zliczeń 12288 impulsów zegara założyliśmy. Licznik zlicza w dół (dekrementuje). Bit WDGA służy do włączenia/wyłączenia watchdoga. Natomiast wyzerowanie bitu T6 generuje sygnał resetu. Bit ten można również programowo wyzerować wywołując w ten sposób reset programowy. Po uruchomieniu (inicjalizacji) mk, analiza śladu programu (np. stosu, zawartości rejestrów, itp.) oraz znajomość przyczyny zerowania daje podstawy do tworzenia programów auto-korekcyjnych, które po wykryciu błędu oprogramowania sygnalizują i zapamiętują numer błędu i mogą dokonywać blokady odpowiedniego fragmentu kodu zabezpieczając system przed ciągłym blokowaniem się w sytuacjach alarmowych. W przypadku mk DS87530 schemat układu watchdog przedstawia rysunek 6.22. 160 Rysunek 6.22. Konfiguracja rejestru sterującego układem WDOG w mk DS87530 6.4. Specjalizowane układy komunikacji szeregowej Sterowniki komunikacji szeregowej służą do wymiany informacji pomiędzy mk, a jego otoczeniem. Przesyłanie danych odbywa się w sposób szeregowy. Zasadę działania tych układów pokazano na rys. 6.23. Rysunek 6.23. Schematyczna budowa sterownika komunikacji szeregowej Urządzenie to umożliwia wysyłanie zawartości określonego rejestru, tzw. Bufora nadajnika, w postaci szeregowej poprzez określone wyprowadzenia portu. Oznacza to, że na wyjściu linii portu pojawia się ciąg binarny odpowiadający zawartości wysyłanego rejestru (funkcja nadajnika – transmiter). W funkcji odbiornika (ang. receiver) sterownik komunikacji szeregowej potrafi przetworzyć ciąg binarny doprowadzony do wejścia określonej linii portu na zawartość rejestru, zwanego buforem odbiornika. Bufory nadajnika i odbiornika są dostępne z poziomu programu użytkownika. Wyróżnia się dwa rodzaje transmisji szeregowej: − asynchroniczną, − synchroniczną. 161 Dane przesyłane asynchronicznie nie są związane z żadnym sygnałem synchronizującym, w szczególności nie towarzyszy im sygnał zegara. Transmisja przebiega zwykle bajtami przesyłanymi w postaci ciągów bitów. Oprócz ośmiu bitów danych przesyła się dodatkowo bit startu oraz opcjonalnie bit parzystości do detekcji błędów i bit stopu. Pomiędzy nadajnikiem, a odbiornikami musi być ustalona częstotliwość przesyłania danych. Przy transmisji synchronicznej równolegle z ciągiem bitów danych przesyła się sygnał synchronizujący (zegarowy), który określa chwile, w których stan linii danych odpowiada ważnym wartościom kolejnych bitów. Po każdym bajcie może być dodatkowo przesłany bit parzystości. Sterownik komunikacji szeregowej (w skrócie: port szeregowy) nazywa się dwukierunkowym (dupleksowym), jeśli może równocześnie odbierać i nadawać dane. Jest to możliwe, gdy jest wyposażony w dwie oddzielne linie do nadawania i do odbioru. Można wyróżnić między innymi następujące interfejsy szeregowe stosowane w mk: − UART (ang. Universal Asynchronous Receiver/Transmitter), − SPI (ang. Serial Peripherial Interface), ISP (In-System Programmable) − I2C (ang. Inter-Integrated Circuit), − CAN (ang. Cotroller Area Network), − USB (ang. Universal Serial Bus). 6.4.1. Interfejs UART Interfejs ten przewidziany jest zazwyczaj do zapewnienia łączności mk z komputerem PC lub innym mk. Mk posiadają często rozbudowane układy UART posiadające własne generatory sygnałów odniesienia, bufory, dekodery kodów sterujących, mogące pracować w trybie dwukierunkowym z protokołem potwierdzeń sprzętowych (Xon/Xoff). W praktyce jednak nie spotyka się tak często zewnętrznych układów scalonych wyposażonych w ten system interfejsowy. Nie może więc on być traktowany jako platforma rozszerzenia mse, lecz jedynie jako interfejs dedykowany budowie specjalizowanego łącza, np. do komunikacji z komputerem PC. Port szeregowy UART kontaktuje się ze światem zewnętrznym za pomocą dwóch wyprowadzeń: wejścia odbiornika (oznaczanego najczęściej RxD) i wyjścia odbiornika (TxD). Interfejs UART jest interfejsem asynchronicznym, najczęściej posiada swój własny generator taktujący. Rysunek 6.24. Format danych dla standardu UART Format danych w tym standardzie pokazano na rys. 6.24. Jak widać, transmisja zaczyna się od bitu startu, po którym następuje osiem bitów danej (czasami dziewięć, gdzie dziewiąty bit jest najczęściej bitem parzystości) i jednego bitu stopu (w skrócie: 8N1). Jako przykład takiego urządzenia przedstawiono urządzenie UART mikrokontrolera 80C51 (rys. 6.25). Do rejestru SBUF użytkownik wpisuje dane przeznaczone do wysłania wyjściem TxD i odczytuje z niego dane, które przyszły wejściem RxD. Fizycznie są to dwa rejestry pod wspólną nazwą, ponieważ operacja zapisu dotyczy innego rejestru niż operacja czytania. Zapis danej do rej. SBUF automatycznie uruchamia procedurę wysyłania danej przez interfejs. 162 Rysunek 6.25. Schematyczna budowa urządzenia UART mk 80C51 Rejestr SCON służy do sterowania pracą interfejsu oraz zawiera informację o jego stanie. Jego postać jest następująca: Rysunek 6.26. Rejestr SCON SM0, SM1 – wybór trybu pracy: 0 0 tryb 0 – rejestr przesuwny (8 bitów), fosc/12, 0 1 tryb 1 – UART (8 bitów), częstotliwość zmienna, 1 0 tryb 2 – UART (9 bitów), fosc/64 lub fosc/32, 1 1 tryb 3 – UART (9 bitów), częstotliwość zmienna. SM2 - maskowanie odbioru znaku: tryb 0 – powinno być SM2 = 0, tryb 1 – przy SM2 = 1 znacznik przerwania RI nie jest uaktywniany przy braku bitu stopu w odbieranym słowie, tryb 2 i 3 – przy SM2 = 1 znacznik przerwania RI nie jest uaktywniany jeżyli 9-ty bit odbieranego słowa jest równy 0; w tych trybach znacznik ten jest wykorzystywany przy komunikacji wieloprocesorowej. REN - znacznik uaktywnienia odbiornika: 0 odbiór zablokowany, 1 odbiór dozwolony. TB8 - znacznik używany w transmisji dziewięciobitowej: tryb 0 i 1 – nie używany, tryb 2 i 3 – dziewiąty bit w nadawanym słowie. RB8 - znacznik używany w transmisji dziewięciobitowej: tryb 0 – nie używany, tryb 1 – gdy SM2, do RB8 jest wpisywany bit stopu odbieranego słowa, tryb 2 i 3 – do RB8 jest wpisywany dziewiąty bit odbieranego słowa. TI - znacznik przerwania nadajnika. Ustawiany w stan 1 przez mikrokontroler tylnym zboczem 9tego bitu wysyłanego słowa w trybie 0 lub przednim zboczem bitu stopu w pozostałych trybach. Może być zerowany tylko programowo. RI - znacznik przerwania odbiornika. Ustawiany w stan 1 przez mikrokontroler tylnym zboczem 9tego bitu przyjmowanego słowa w trybie 0 lub w połowie bitu stopu w pozostałych trybach z wyjątkiem gdy w trybach 2 i 3 bit SM2 = 1, a dziewiąty bit odbieranego słowa jest równy 0. 163 Jednym z elementów konfiguracji urządzenia UART jest ustawienie prędkości transmisji. Dla trybu 1 i 3 interfejs taktuje się za pomocą liczników mk. W celu uzyskania jednej ze standardowych prędkości transmisji np. 9600 bitów na sekundę niezbędne jest zastosowanie oscylatora np. o częstotliwości 11,059MHz. „Okrągłe” częstotliwości pożądane w układach pomiarowych np. 12MHz nie zapewniają prawidłowej prędkości transmisji, która jest obarczona błędem. Gdy błąd ten nie jest duży (poniżej jednego procenta), to nie wpływa on na poprawność wymiany danych. Rysunek 6.27. Serial Port, Mode 0 164 Rysunek 6.28. Przebiegi czasowe sygnałów dla portu w trybie, Mode 0 Rysunek 6.29. Serial Port, Mode 1 165 Rysunek 6.30. Przebiegi czasowe sygnałów dla portu w trybie, Mode 1 Rysunek 6.31. Serial Port, Mode 2 166 Rysunek 6.32. Przebiegi czasowe sygnałów dla portu w trybie, Mode 2 Rysunek 6.33. Serial Port, Mode 3 167 Rysunek 6.34. Przebiegi czasowe sygnałów dla portu w trybie, Mode 3 Drugim przykładem jest interfejs UART mk AT90S8515. Umożliwia on transmisję szeregową asynchroniczną z pełnym dupleksem. Posiada następujące cechy : − full duplex (posiada oddzielne rejestry do odbioru i nadawania), − można ustawić wiele prędkości transmisji, − wysyłanie/odbieranie 8 lub 9 bitów danej, − zapewnia filtrację szumów, − ma detekcje błędu kolizji i błędu ramki, − zapewnia detekcję błędu nieprawidłowego startu, − generuje 3 oddzielne przerwania (Tx zakończone, Tx rejestr danej pusty, Rx zakończone). Układ ten składa się z trzech oddzielnych bloków: układu do nadawania danej (nadajnika), układu do odbioru danej (odbiornika) oraz generatora taktującego. W układzie nadajnika (rys. 6.35) transmisja jest inicjowana przez wpis danej do rejestru danej układu UART (rej. UDR). Rysunek 6.35. Schemat blokowy układu nadajnika UART w mk AT90S8515 Dana jest transferowana z rej. UDR do rejestru przesuwnego gdy : 168 − Nowa dana została wpisana do rej. UDR po tym jak wysłany został ostatni bit danej poprzedniej. Rejestr przesuwny jest ładowany natychmiast. − Nowa dana została wpisana do rej. UDR zanim zakończono wysyłanie poprzedniej. Rejestr przesuwny jest ładowany dopiero po wysłaniu bitu stopu danej poprzedniej. Przesłanie danej z rej. UDR do rejestru przesuwnego powoduje ustawienie flagi UDRE w rejestrze statusowym USR. Flaga ta sygnalizuje gotowość przyjęcia następnej danej do nadawania. Zaraz po załadowaniu rejestru przesuwnego czyszczony jest jego najmłodszy bit (bit startu), a bit 9-ty lub 10ty jest ustawiany (bit stopu). W przypadku wysyłania danej dziewięciobitowej (patrz bit CHR9 w rejestrze sterującym UCR), 9-ty bit danej jest przepisywany na 9-ty bit rejestru przesuwnego. Z prędkością ustawianą za pomocą rej. UBRR, następuje przesyłanie bitów, rozpoczynając od bitu startu, następnie od bitu LSB, kończąc na bicie stopu. Bity są wystawiane na pin TxD. Po wysłaniu bitu stopu, następuje przesłanie nowej danej z rej. UDR do rejestru przesuwnego (o ile nowa dana została tam wpisana w czasie transmisji). Podczas przesyłania ustawiana jest flaga UDRE.W przypadku braku nowej danej, bit UDRE pozostaje ustawiony, aż do momentu wpisania danej do rej. UDR. Jeśli nie ma już danych do przesłania, a bit stopu pozostaje na TxD przez czas potrzebny na przesłanie 1 bitu, ustawiana jest flaga TxC w rej. USR. Bit TXEN w rej. UCR włącza tryb nadawania UART. Jeśli jest wyczyszczony, pin PD1 może być użyty jako końcówka ogólnego przeznaczenia. Jeśli jest ustawiony, pin PD1 będzie ustawiony jako wyjście i to niezależnie od stanu rejestru kierunku danych portu D. Drugim układem w interfejsie UART jest odbiornik, którego schemat blokowy pokazano na rys. 6.36. Rysunek 6.36. Schemat blokowy układu odbiornika UART w mk AT90S8515 Układ odbioru próbkuje sygnał wejściowy (RxD) z częstotliwością 16 * BAUD, gdzie BAUD – częstotliwość układu taktującego. Gdy linia jest w stanie spoczynkowym, pojedyncza próbka o stanie „0” jest interpretowana jako zbocze opadające bitu startu i rozpoczyna się procedura sprawdzająca. Testuje ona, czy rzeczywiście stan „0” na linii jest bitem startu czy też zakłóceniem, i w tym drugim przypadku ignoruje zbocze. Jeśli bit startu jest stwierdzony poprawnie (3 próbki z rzędu to „0”), następuje odczyt kolejnych bitów danej, rozpoczynając od LSB. Każdy bit próbkowany jest 3 razy i jako prawdziwa wartość interpretowana jest ta, która pojawia się w przynajmniej 2 próbkach. Pozwala to na eliminację zakłóceń. Kiedy do odbiornika trafia bit stopu, przechodzi on procedurę sprawdzenia poprawności i jeśli z 3 próbek 2 lub 3 są zerami, ustawiana 169 jest flaga FE (błąd ramki). Przed odczytaniem rej. UDR należy więc zawsze sprawdzać stan flagi FE. Niezależnie od ewentualnego błędu ramki, dana jest przesyłana do rej. UDR i ustawiana jest flaga RxC. W rzeczywistości rej. UDR nie jest jednym rejestrem, lecz dwoma oddzielnymi dla wysyłania i odbioru. W przypadku zapisu do rej. UDR dana jest wpisywana do rejestru wysłania, a w przypadku odczytu podstawiana jest zawartość rejestru odbioru. Jeśli ustawiony jest tryb odbioru danej 9–bitowej (patrz bit CHR9 w rej. UCR), bit RXB8 w rej. UCR jest ładowany wartością 9-tego bitu danej odebranej. Jeśli po odebraniu danej stwierdzi się brak pobrania z rej. UDR danej poprzedniej, ustawiana jest flaga kolizji OR w rej. UCR. Oznacza ona, że ostatnio odbierana dana nie mogła zostać przesłana do rej. UDR i została utracona. Flaga OR jest czyszczona przy odczycie prawidłowej danej z rej. UDR. Przed odczytem rej. UDR należy więc zawsze sprawdzić flagę OR. Kiedy bit RXEN w rej. UCR jest wyczyszczony, odbiornik jest wyłączony. Pin PD0 może być użyty jako linia portu równoległego. Gdy RXEN = „1” do linii PD0 podłączone jest wejście odbiornika, co oznacza, że staje się on pinem wejściowym, niezależnie od ustawień w rejestrze kierunku pinów DDRD portu D. Kiedy ustawiony jest bit CHR9 w rej. UCR, dane odbierane i nadawane mają długość 9 bitów plus bit startu i stopu. 9-ty bit danej do nadania należy wpisać pod bit TXB8 w rej. UCR, a odebrany 9-ty bit danej znajduje się w RXB8 rej. UCR. Wpis bitu do TXB8 musi nastąpić wcześniej niż wpis reszty danej do rej. UDR, co rozpoczyna transmisję. Do sterowania układem UART mk AT90S8515 wykorzystuje się cztery rejestry: − Danej, rej. UDR (dana odbierana lub nadawana), − Statusowy, rej. USR (flagi błędów, zakończenie transmisji, etc.), − Sterowania, rej. UCR (włączenie przerwań, włączenie / wyłączenie UART), − Prędkości, rej. UBRR (BAUD = fck / ( 16 ( UBRR+1 ) )). Rejestr statusowy – rej. USR o adresie $0B ( $2B ) posiada następujące flagi: − 7 : RXC – Odbiór zakończony. Gdy flaga jest ustawiona, odebrana dana została przesłana do rej. UDR. Flaga ta jest ustawiana niezależnie od błędów transmisji. W przypadku włączenia przerwania ( RXCIE w rej. UCR), ustawienie RXC oznacza wywołanie obsługi przerwania zakończenia odbioru. RXC czyszczona jest przez odczyt rej. UDR. Obsługa przerwania zakończonego odbioru musi odczytać rej. UDR i wyczyścić flagę RXC. − 6 : TXC – Nadawanie zakończone. Zakończono nadawanie bitu stopu, a w rej. UDR nie ma nowej danej. Flaga ta jest użyteczna w trybie half-duplex, kiedy urządzenie po nadaniu danych musi zwolnić linię i ustawić się w tryb odbioru. Jeśli ustawiona jest flaga TXCIE w rej. UCR, wykona się obsługa przerwania zakończonego nadawania. TXC czyści się wtedy automatycznie. W przypadku wyłączonego przerwania TXC można wyczyścić poprzez wpisanie logicznej „1”. − 5 : UDRE – Rejestr danej pusty. Flaga ta ustawia się przy przesłaniu danej z rej. UDR do rejestru przesuwnego celem nadania i oznacza, że do rej. UDR można wpisać kolejną daną. − 4 : FE – Błąd ramki. Ustawia się gdy zamiast bitu stopu stwierdza się „0”. Czyści się automatycznie po prawidłowym odbiorze bitu stopu. 3 : OR – Błąd kolizji. Ustawia się, gdy nie można przesłać odebranej danej do rej. UDR, ponieważ nie odczytano z tego rejestru danej poprzedniej. Zeruje się przy prawidłowym przepisaniu danej do rej. UDR. − 2..0 : – Zarezerwowane. Do sterowania pracą portu UART wykorzystuje się rej. UCR spod adresu $0A ( $2A ). Znaczenie bitów jest następujące: 170 Rysunek 6.37. Znaczenie bitów rejestru UCR − 7 : RXCIE – Włączenie przerwania zakończonego odbioru. Gdy flaga jest ustawiona, ustawienie flagi RXC w rej. USR powoduje wywołanie obsługi przerwania (oczywiście przy odblokowanej globalnej masce przerwań). − 6 : TXCIE – Włączenie przerwania zakończonego nadawania. Gdy flaga jest ustawiona, ustawienie flagi TXC w rej. USR powoduje wywołanie obsługi przerwania (oczywiście przy odblokowanej globalnej masce przerwań). − 5 : UDRIE – Włączenie przerwania „rejestr danej pusty”. Gdy flaga jest ustawiona, ustawienie flagi UDRE w rej. USR powoduje wywołanie obsługi przerwania (oczywiście przy odblokowanej globalnej masce przerwań). − 4 : RXEN – Bit ten włącza tryb odbioru (gdy RXEN=”1”). Gdy RXEN=”0” flagi TXC, OR i FE nie mogą mieć wartości „1”. Jeśli flagi te są ustawione, wyłączenie RXEN nie powoduje ich czyszczenia. − 3 : TXEN – Bit ten włącza tryb nadawania (gdy TXEN=”1”). Wyłączenie tego bitu w czasie transmisji ma efekt dopiero po zakończeniu nadawania zarówno aktualnej danej, jak i ewentualnie następnej już wpisanej do rej. UDR. − 2 : CHR9 – Włączenie trybu transmisji danej 9–bitowej. Patrz opis bitów RXB8 i TXB8. Dziewiąty bit może być użyty jako dodatkowy bit stopu lub do kontroli parzystości. − 1 : RXB8 – Dziewiąty bit odebranej danej. Czyta się go, jeśli bit CHR9 jest ustawiony. − 0 : TXB8 – Dziewiąty bit danej do nadania. Należy go modyfikować, jeśli dana przesłana ma być 9–bitowa (czyli gdy CHR9=”1”). Ostatnim układem interfejsu UART jest generator taktujący. Jest on dzielnikiem częstotliwości, który generuje sygnał zegarowy o częstotliwości BAUD = fck / ( 16 ( UBRR+1 ) ), gdzie: rej UBRR jest rejestrem prędkości interfejsu UART (rejestr o adresie $09 ($29)), a fck częstotliwością oscylatora kwarcowego. Przykładowe prędkości transmisji dla czterech częstotliwości oscylatora przedstawiono w tablicy 6.1. Zawiera ona wartości jakie należy wpisać do rej UBRR, aby uzyskać daną prędkość transmisji. Dodatkowo umieszczono w niej procentowy błąd rzeczywistej prędkości transmisji w stosunku do standardowej. Zaleca się stosować takie prędkości transmisji, aby ten błąd był mniejszy niż 1 %. Tablica 6.1. Przykładowe prędkości transmisji układu UART i odpowiadające im wartości rej. UBRR Jak wspomniano, interfejs UART przeważnie służy do komunikacji mk z komputerem PC. Odbywa się to najczęściej za pomocą standardu RS232. Sposób realizacji sprzętowej standardu RS232C pokazano na rys. 4.38. 171 Rysunek 6.38. Realizacja sprzętowa standardu RS232C Zadaniem układu ADM232 jest konwersja sygnałów między poziomem TTL na wyprowadzeniach mk, a poziomem sygnału +/- 12V wykorzystywanym podczas transmisji łączem RS232C. Łącze to wymaga co najmniej trzech przewodów: linii nadajnika, odbiornika oraz linii odniesienia, czyli tzw. masy. Jest to zatem łącze asymetryczne. Umożliwia ono komunikację ze sobą tylko dwóch jednostek przy zastosowaniu transmisji full duplex. 6.4.2. Interfejs SPI Interfejs SPI służy do dwukierunkowej (full-duplex), synchronicznej, szeregowej transmisji danych pomiędzy mk, a zewnętrznymi układami peryferyjnymi, np. przetwornikami A/C i C/A, szeregowymi pamięciami EEPROM, innymi mk, układami scalonymi z regulowanymi cyfrowo potencjometrami, dekadami pojemnościowymi, itd. Jest interfejsem trójżyłowym: składa się z dwóch linii synchronicznie przesyłających dane w przeciwnych kierunkach i linii z sygnałem zegarowym synchronizującym ten transfer. Rysunek 6.39. Przykład połączenia interfejsu ISP pomiędzy układem master i slave Na rys. 6.39 pokazano sposób połączenia interfejsu SPI pomiędzy układem nadrzędnym (master) i układem podrzędnym (ang. slave), gdzie pin MISO jest wejściem danych, pin MOSI wyjściem danych, a pin SCK wyjściem zegara dla układu master i wejściem zegara dla układu slave. Z rysunku widać, że protokół transmisji (w najprostszej postaci) wymaga dwóch rejestrów przesuwnych (ang. shift register) połączonych w licznik pierścieniowy (wejście jest połączone z wyjściem). Transmisja jest synchroniczna - jeden z układów dostarcza sygnału zegara, odseparowanego od sygnału danych, zgodnie ze zboczami zegara taktującego. Układ generujący sygnał zegara jest określony jako nadrzędny, bez względu na to czy dane są przez niego nadawane czy odbierane. Wszystkie pozostałe układy na magistrali są określone jako podrzędne. Sygnały danych i zegara są przesyłane oddzielnymi jednokierunkowymi liniami. Sygnał zegara nie jest ciągły, nadawany jest jedynie w czasie trwania transmisji. Umożliwia to odbiór poszczególnych bitów danych bez konieczności testowania bitów startu i stopu, charakterystycznego dla transmisji asynchronicznej. Kiedy układ nadrzędny nadaje dane na linii MOSI do układu podrzędnego, to układ podrzędny odpowiada, wysyłając do układu nadrzędnego dane na linii MISO. Implikuje to 172 dwukierunkową transmisję z jednoczesnym wysyłaniem i odbieraniem danych, synchronizowanym tym samym sygnałem zegarowym, przez oba układy. Zatem bajt transmitowany jest od razu zastępowany bajtem odbieranym. Dzięki temu nie ma „pustych” transmisji: raz aby wysłać bajt, drugi aby go odebrać. Do wysłania bajtu i jego odebrania wystarczy osiem impulsów zegarowych na linii SCK. W interfejsie tym dane są wpisywane (odbierane) do rejestru szeregowego jednym zboczem zegarowym, a przesuwane (wyprowadzane na zewnątrz – nadawane) drugim. Zwiększa to czas podtrzymania danych odbiornika do ½TCLK - td, gdzie TCLK - okres zegara, td - opóźnienie magistrali. Zatem wypełnienie sygnału zegarowego wynosi około ½. Najczęściej szybkość transmisji nie przekracza 1-2 Mbit/s. Wymiana danych za pomocą interfejsu SPI mk pracującego w trybie master pomiędzy mk, a zewnętrznym urządzeniem peryferyjnym generalnie przebiega według następującej procedury: − najpierw należy odpowiednio skonfigurować interfejs SPI mk: tryb master, poprawnie skonfigurowane piny interfejsu (pin SCK ma być wyjściem), ustawić częstotliwość sygnału zegarowego, urządzenie peryferyjne musi być uaktywnione (przygotowane na odbiór danych) – najczęściej służy do tego dodatkowa linia mk podłączona do wejścia CS (ang. Chip Select ) urządzenia peryferyjnego, − aby rozpocząć transmisję ustawia się odpowiedni bit w rejestrze sterującym SPI lub wpisuje się daną do rejestru przesuwnego, − po czym czeka się na zakończenie transmisji, testując flagę informującą o zakończeniu transmisji lub czeka się na przerwanie od układu SPI, o ile jest odblokowane, − na zakończenie z rejestru przesuwnego można odczytać daną odebraną. Interfejs SPI mk można skonfigurować do pracy w trybie slave. W tym przypadku procedura postępowania jest następująca: − najpierw należy odpowiednio skonfigurować interfejs SPI mk: tryb slave, poprawnie skonfigurowane piny interfejsu (pin SCK ma być wejściem), − następnie wpisuje się daną, którą chcemy wysłać do rejestru przesuwnego, − ustawia się odpowiedni bit w rejestrze sterującym SPI uruchamiającym interfejs, − urządzenie peryferyjne musi być aktywne i pracować w trybie master, − po czym czeka się na zakończenie transmisji, które wywołuje przerwanie, o ile jest odblokowane, − na zakończenie z rejestru przesuwnego można odczytać daną odebraną. W trybie slave metoda odpytywania flagi zakończenia transmisji jest nieefektywna, ponieważ transmisja z układu peryferyjnego może nastąpić w dowolnej chwili nieznanej mk. Zatem musi on w pętli głównej programu ciągle odpytywać tę flagę, co niepotrzebnie zajmuje czas procesora. Stąd wiele układów SPI posiada dodatkowy sygnał wejściowy (pin SS), który pozwala na wymuszenie trybu slave interfejsu SPI mk przez urządzenie peryferyjne. Podsumowując, właściwości układu SPI z punktu widzenia interfejsu mogą być opisane przy pomocy 3 funkcji interfejsowych: − Talker (nadajnik) – wprowadzenie danej do rejestru szeregowego, przesuwanie i wysyłanie danej z rejestru szeregowego. − Listener (odbiornik) - wczytanie danej odbieranej z rejestru szeregowego po zebraniu całego słowa − Repeater (pośredniczenie w transmisji) - dane wejściowe są wpisywane do rejestru szeregowego z linii wejściowej, przesuwane i od razu wysyłane na linię wyjściową. − Maksymalna konfiguracja zawiera z reguły wszystkie trzy wymienione funkcje, ale w praktyce spotyka się najczęściej dwie pierwsze. Aby transmisja pomiędzy mk, a urządzeniem peryferyjnym przebiegała prawidłowo muszą być spełnione następujące warunki: − zachowanie jednakowej długość danej (najczęściej 8 bitów lub wielokrotność tej liczby), − taka sama kolejność wysyłania bitów (najczęściej od MSB do LSB, niektóre mk mają 173 − możliwość programowej zmiany tej kolejności), − zgodna polaryzacja i faza sygnału zegarowego. Częstotliwość sygnału zegarowego nie jest istotna, ponieważ dane są synchronizowane tym sygnałem i są aktywowane (wpisywane lub wyprowadzane z rejestru szeregowego) wyłącznie przez zbocza tego sygnału. Zatem prędkość transmisji możemy zmienić nawet w trakcie przesyłania danych. Można również wstrzymać transmisję w dowolnej chwili, aby następnie ją dalej kontynuować. Właściwość ta jest szczególnie przydatna, w przypadku przesyłania danych 8nbitowych, gdzie n – liczna naturalna, za pomocą interfejsu SPI mk, który wyłącznie może przesyłać dane 8-bitowe. Po wysłaniu 8 bitów następuje przerwa – zatrzymanie transmisji, w czasie której do interfejsu jest wprowadzana/czytana kolejna dana 8-bitowa, po tej przerwie ponownie uruchamia się interfejs, itd. Polaryzacja i faza sygnału zegarowego muszą być zgodne zarówno dla układu master, jak i układów slave, aby transmisja pomiędzy nimi przebiegała prawidłowo. Polaryzacja sygnału zegarowego jest określona przez wartość logiczną sygnału zegara w stanie spoczynkowym (poza czasem transmisji): − CPOL=0 – sygnał zegara w stanie spoczynku jest w stanie niskim „Lo”, − CPOL=1 – sygnał zegara w stanie spoczynku jest w stanie wysokim „Hi”. Faza sygnału zegarowego definiuje zależność pomiędzy zboczami sygnału zegarowego, a momentami próbkowania danych wejściowych; przesuwania zawartości rejestru (wysłania danych wyjściowych): − CPHA=0 – pierwsze zbocze sygnału zegarowego próbkuje dane wejściowe, drugie zbocze przesuwa dane w rejestrze – wyprowadza je z rejestru (dane są próbkowane, a następnie przesuwane i wysyłane), − CPHA=1 – pierwsze zbocze sygnału zegarowego przesuwa dane w rejestrze – wyprowadza je z rejestru, drugie zbocze próbkuje dane wejściowe (dane są przesuwane i wysyłane, a następnie próbkowane i wpisywane do rejestru). Stąd można wyróżnić cztery warianty pracy interfejsu SPI (strobowania/przesuwania informacji): (1): CPHA=0 i CPOL=0, (2): CPHA=0 i CPOL=1, (3): CPHA=1 i CPOL=0, (4): CPHA=1 i CPOL=1. Najczęściej spotyka się pierwszy wariant, lecz pozostałe również są stosowane, dlatego we współczesnych mk istnieje możliwość programowego ustawienia polaryzacji i fazy sygnału zegarowego. Na rys. 6.40 przedstawiono (1) i (2) wariant pracy interfejsu SPI, dla sygnału zegarowego o fazie CPHA=0, natomiast na rys.6.41 warianty (3) i (4) dla sygnału zegarowego o fazie CPHA=1. Jako przykład interfejsu SPI wybrano układ z mk ST72215G, którego schemat blokowy pokazano na rys. 6.42. Rysunek 6.40. Przebiegi czasowe interfejsu SPI dla sygnału zegarowego o CPHA = 0 174 Rysunek 6.41. Przebiegi czasowe interfejsu SPI dla sygnału zegarowego o CPHA = 1 Rysunek 6.42. Schemat blokowy układu interfejsu SPI mk ST72215G Z tym układem stowarzyszone są trzy rejestry: − rejestr kontrolny, rej. CR, − rejestr statusu, rej. SR, − rejestr danych, rej. DR. Rejestr danych DR służy do wpisywania danej, która ma zostać wysłana i do odczytu odebranej danej. Rejestr statusu SR zawiera trzy flagi: SPIF – informacja o zakończeniu transferu danej z rej. DR, WCOL – bit kolizji ustawiany, gdy w trakcie wysyłania danej, wprowadzono nową daną do rej. DR, MODF – jest ustawiany sprzętowo, gdy na linii SS pojawi się stan niski w trakcie pracy układu jako master. Bity te są zerowane programowo. Pierwsza i trzecia flaga mogą wywołać przerwanie, jeśli bit SPIE w rej. CR jest ustawiony. Rejestr sterujący CR służy do konfigurowania interfejsu i sterowania jego pracą. Znaczenie bitów jest następujące: SPIE – maska przerwania od interfejsu SPI, 175 SPE – podłączenie urządzenia do pinów portu równoległego, zerowany przez niski poziom sygnału na linii SS w trybie master, SPR2, SPR1, SPR0 – określają częstotliwość sygnału taktującego interfejs w trybie master, MSTR – ustawienie tego bitu wybiera tryb master (w przeciwnym przypadku układ jest w trybie slave), zerowany przez niski poziom sygnału na linii SS, CPOL – wybór polaryzacji sygnału zegarowego, CPOL=0 lub CPOL=1, CPHA – wybór fazy próbkowania, CPHA=0 lub CPHA=1. Aby skonfigurować interfejs w trybie master należy wykonać następujące kroki: − ustawić bity SPR1,SPR0 w rej. CR w celu wyboru prędkości transmisji, − ustawić CPOL i CPHA w rej. CR aby wybrać właściwy wariant strobowania danych, − na linii SS musimy zapewnić stan wysoki w czasie całej transmisji, − bity MSTR i SPE muszą być ustawione. Transmisja zaczyna się, gdy wpiszemy bajt do rej. DR. Jest on równolegle ładowany do rejestru szeregowego i następnie szeregowo wyprowadzany począwszy od najstarszego bitu. Gdy transfer jest kompletny, bit SPIF jest ustawiany sprzętowo i jeśli bit SPIE w rej. CR jest ustawiony oraz bit I w rejestrze kontrolnym przerwań CCR został wyzerowany, to następuje generacja przerwania. Kiedy ustawiany jest bit SPIF, to następuje jednoczesne przepisanie zawartości rejestru szeregowego do bufora. Bit ten jest zerowany poprzez odczyt/zapis rej. SR lub odczyt z rej. DR. Do rej. DR można wprowadzić kolejną daną wyłącznie w przypadku, gdy bit SPIF=0. Dla trybu slave konieczne są następujące czynności: − urządzenie peryferyjne musi być w tym samym trybie co mk (właściwie ustawiona CPOLi CPHA), − na linii SS musimy zapewnić stan niski w czasie całej transmisji, − należy wyzerować bit MSTR i ustawić bit SPE. Transmisja zaczyna się, gdy urządzenie peryferyjne zaczyna generować sygnał zegarowy. Układ slave (mk) w takt tych impulsów wysyła z rejestru szeregowego bajt od MSB do LSB i jednocześnie kompletuje daną odbieraną. Dalej procedura przebiega według uprzedniej procedury. Generalnie za pomocą interfejsu SPI można utworzyć dwie konfiguracje magistralowe: − system z pojedynczym układem master (ang. single master system), − system z wieloma układami master (ang. multimaster system). Najczęściej spotykanym i najprostszym w konfiguracji jest pierwszy system, którego przykładową konfigurację pokazano na rys. 6.43. Rysunek 6.43. System z pojedynczym układem master oparty na interfejsie SPI Układ master wybiera poszczególny układ slave korzystając z czterech linii portu równoległego. Dane urządzenie slave jest wybrane, gdy na jego wejściu SS pojawi się stan niski. W czasie transmisji, w celu uniknięcia kolizji na liniach interfejsu, tylko jeden układ slave może być aktywny. 176 6.4.3. Interfejs I2C Standard ten został opracowany przez firmę Philips. Jest stosowany w urządzeniach powszechnego użytku, zwłaszcza audio-video, telekomunikacji i systemach elektroniki przemysłowej. Transmisja danych odbywa się szeregowo, w dwóch kierunkach, przy użyciu dwóch linii. Jedną z nich SCL (serial clock line) przesyła się impulsy zegarowe synchronizujące transmisję, natomiast drugą SDA (serial data line) transmituje się w dwóch kierunkach dane. W transmisji interfejsem I2C uczestniczy układ nadrzędny (master) oraz jeden lub więcej układów podrzędnych (slave). Transmisja bloku danych jest inicjowana wówczas, gdy stan linii SDA zmieni się z wysokiego na niski, podczas gdy linia zegarowa SCL znajduje się w stanie wysokim. Sytuacja taka jest nazywana warunkiem startowym (Start). Koniec transmisji ma miejsce wtedy, gdy linia SDA zmieni stan z niskiego na wysoki, podczas gdy linia zegara jest w stanie wysokim. Jest to warunek nazywany Stop. Stan linii danych może być zmieniany wówczas, gdy linia zegarowa znajduje się w stanie niskim. Od chwili wystąpienia warunku Start do chwili odległej o określony odstęp czasu od wystąpienia warunku Stop szyna jest zajęta. Informacje są przesyłane bajtami, w postaci szeregowej, przy czym jako pierwszy wysyłany jest najbardziej znaczący bit. Po przesłaniu danych wysyłany jest sygnał potwierdzenia oznaczony symbolem A lub ACK (acknowledge). Dziewiąty impuls zegara towarzyszący potwierdzeniu jest generowany przez układ master. Na ten sygnał urządzenie nadające musi zwolnić linię SDA, wprowadzając swoje wyjście SDA w stan wysoki lub w stan wysokiej impedancji, natomiast odbiornik potwierdza odbiór sygnałem SDA=0. Liczba bajtów przesłanych w jednej sesji, to jest między stanem Start i Stop, jest nieograniczona. Wysłanie bitu potwierdzenia przez odbiornik po odebraniu każdego bajtu danych jest obligatoryjne. Jeśli potwierdzenie nie zostaje wysłane, linia SDA musi znaleźć się w stanie wysokim lub w stanie wysokiej impedancji, by umożliwić układowi master wygenerowanie warunku Stop i zakończenie transmisji. Brak potwierdzenia może nastąpić na przykład wtedy, gdy odbiornik pracuje w czasie rzeczywistym i jest zajęty obsługa jakiegoś pilnego zadania. Jeśli odbiornikiem jest układ master, to po odebraniu ostatniego bajtu w sekwencji nie wysyła sygnału potwierdzenia NA (not acknowledge). Układ slave musi wtedy zwolnić linię SDA, by umożliwić układowi master wygenerowanie warunku Stop kończącego transmisję. Na rys. 6.44 przedstawiono kompletny cykl transmisji w formacie standardu I2C. Po wygenerowaniu warunku Start układ master wysyła na szynę adres układu slave, z którym chce współpracować. Adres składa się z siedmiu bitów, po którym następuje ósmy bit R/W określający kierunek transmisji. Jeśli R/W=0, dane będą przesyłane z układu master do układu slave, natomiast gdy R/W=1, kierunek transmisji będzie odwrotny. Rysunek 6.44. Protokół transmisji szeregowej standardu I2C 177 Początkowa sekwencja bitów przesyłanych w trakcie każdej sesji, złożona z bitu Startu, adresu urządzenia slave i bitu kierunku jest nazywana blokiem Start. Dalsza część transmisji polega na przesyłaniu kolejnych bajtów danych, zgodnie z protokołem pokazanym na rys. 6.44. Ostatnią fazą sesji jest wysłanie przez układ master warunku Stop. Pełna sesja składa się zatem z bloku Start, przynajmniej jednego cyklu przesłania bajtu danych i bitu Stop. Jeśli układ master zamierza w jednej sesji wysyłać informacje w kilku blokach do tego samego lub do różnych urządzeń, może nie kończyć sesji warunkiem Stop, lecz po przesłaniu bloku danych powtórzyć warunek Start z tym samym lub nowym adresem urządzenia slave. Przemysłowa norma magistrali I2C zakłada możliwość taktowania transmisji sygnałem zegarowym SCL o częstotliwości od 0 do 100kHz. Wymaga się przy tym, by stan niski impulsów zegarowych trwał przynajmniej 4,7µs, natomiast stan wysoki był nie krótszy niż 4 µs. W razie potrzeby układ slave może spowolnić transmisję, utrzymując linię zegara SCL w stanie niskim po odebraniu bajtu danych od mk. Stan taki jest nazywany stanem oczekiwania i oznaczany symbolem WAIT. Realizacja stanów oczekiwania na magistrali wymaga, by układ master przed wysłaniem kolejnego bajtu przełączył linię SCL w stan wysoki lub w stan wysokiej impedancji, po czym odczytał stan na SCL. Układy współpracujące z magistralą I2C muszą być wyposażone w wyjścia z otwartym drenem dla linii SCL i SDA. Każda z tych linii jest połączona ze źródłem napięcia zasilającego UCC przez rezystor 10kΩ. Do jednego układu master można przyłączyć dowolną liczbę układów slave, jednak pod warunkiem, że pojemność połączeń nie przekroczy maksymalnej wartości równej 400pF. Schemat połączeń przedstawiono na rys. 6.45. Rysunek 6.45. Połączenie urządzeń z magistralą I2C Jako przykład układu interfejsu I2C przytoczono układ MSSP (Master Synchronous Serial Port) mk PIC16F873, który może pracować jako interfejs SPI oraz interfejs I2C. Układ ten w pełni implementuje wszystkie funkcje master i slave interfejsu I2C. Zapewnia on sprzętową realizację przerwań na pojawienie się sekwencji Start i Stop. Umożliwia adresowanie 7-mio i 10-bitowe oraz może pracować przy dwóch prędkościach 100kHz i 400kHz. Do obsługi interfejsu wykorzystuje się sześć rejestrów: − rejestr sterujący SSPCON (SSP Contorl Register), − rejestr sterujący drugi SSPCON2 (SSP Contorl Register2), − rejestr statusowy SSPSTAT (SSP Status Register), − bufor odbioru/wysyłania danej SSPBUF (Serial Receive/Transmit Buffer), − rejestr przesuwny SSPSR (SSP Shift Register) –bezpośrednio nie dostępny, − rejestr adresu SSPADD (SSP Address Register). Rej. SSPCON służy do kontroli pracy interfejsu. Pozwala na wybór jednego z czterech trybów pracy interfejsu: − tryb slave (adres 7-bitowy), − tryb slave (adres 10-bitowy), 178 − tryb master, prędkość transmisji jest równa fOSC/(4 * (adres SSPADD+1)), − tryby firmware (aby zapewnić kompatybilność z innymi produktami średniej klasy). Przed podłączeniem interfejsu I2C do portu mk, właściwe piny muszą być skonfigurowane jako wejścia. Linii SCL i SDA muszą być poprzez zewnętrzne rezystory podwieszone do napięcia zasilania. Schemat blokowy układu MSSP pracującego jako interfejs I2C w trybie slave pokazano na rys. 6.46, a w trybie master na rys. 6.47. Rysunek 6.46. Schemat blokowy układu MSSP pracującego jako interfejs I2C Rysunek 6.47. Schemat blokowy układu MSSP pracującego jako interfejs I2C w trybie master Przedstawione układy w sposób sprzętowy w pełni realizują protokół interfejsu I2C zarówno dla trybu slave, jak i trybu master. 179 6.4.4. Interfejs CAN Interfejs CAN stosuje się głównie w motoryzacji, w lotnictwie, a także w sterownikach przemysłowych. Założenia projektowe CAN koncentrują się na trzech właściwościach systemu transmisyjnego: − szybkości przesyłania danych łączem szeregowym, − odporności transmisji na zakłócenia elektromagnetyczne, − możliwości dzielenia wspólnych danych przez rozproszone mk realizujące cząstkowe funkcje sterowania. Szyna CAN jest asynchroniczną szyną transmisji szeregowej z tylko jedną linią transmisyjną. Ma strukturę otwartą, tzn. może być rozszerzana o nowe węzły (odbiorniki/nadajniki), oraz liniową, czyli nie zawiera pętli. Minimalna konfiguracja CAN składa się z dwóch węzłów. Liczba węzłów w trakcie pracy szyny może się zmieniać bez wpływu na działanie szyny. Właściwość ta oznacza możliwość dynamicznego konfigurowania węzłów, na przykład wyłączenia węzłów, które w wyniku działania procedur diagnostycznych zostały uznane za niesprawne. Poszczególne węzły są przyłączone do szyny na zasadzie funkcji „zwarty iloczyn” (ang. wired- AND). Przy braku sterowania szyna znajduje się w stanie nazywanym recesywnym R (ang. recessive), któremu odpowiada stan logiczny „1”. Stan ten może być zmieniony na stan logiczny „0”, jeśli choć jeden węzeł wymusi na szynie poziom dominujący D (dominant). Najpopularniejszy sposób sprzętowej realizacji szyny jest użycie pary skręconych przewodów oznaczonych symbolami CAN_H i CAN_L. Linie te przyłącza się do węzłów bezpośrednio lub za pośrednictwem buforów/nadajników/odbiorników. Po obu stronach linii dołącza się rezystory. Maksymalna szybkość transmisji szyną CAN wynosi 1Mbps przy długości linii nie przekraczającej 40m. Im dłuższa linia tym prędkość transmisji mniejsza, np. dla długości przewodów 1km prędkość transmisji wynosi już 40kbps. Dane przesyłane szyną są transmitowane metodą NRZ (ang. Non Return to Zero). Adresy odbiorników (identyfikatory) są przesyłane jako integralna część przekazu. Ponieważ interfejs składa się wyłącznie z jednej linii konieczny jest arbitraż szyny. Wykonuje się go metodą CSMA/CD z opcją NDA (ang. carrier sense multiple access / collision detection with nondestructive arbitration). Specyfika standardu CAN przewiduje 11-bitowe identyfikatory, czyli umożliwia współpracę 2048 węzłów. Najnowsza specyfikacja 2.0B (extended CAN) posiada identyfikator 29-bitowy, co daję teoretycznie możliwość adresowania 536 milionów współpracujących ze sobą urządzeń. 6.4.5. Interfejs USB Interfejs ten został opracowany jako uniwersalny interfejs szeregowy wbudowany w architekturę komputerów PC. Jego przeznaczeniem jest współpraca komputerów z urządzeniami: przemysłowymi, urządzeniami powszechnego użytku oraz integracja z sieciami telekomunikacyjnymi. Prędkość transferu danych wynosi 1,5 lub 12 Mbit/s dla standardu USB 1.1, natomiast dla standardu USB 2.0 jest ona równa 480 Mbit/s. Przyjęto następującą topologię systemu z interfejsem USB, jeden host (komputer zarządzający) połączony z pierwszym Hubem, do którego można podłączyć na zasadzie drzewa kolejne Huby lub urządzenia. Taka topologia zapewnia możliwość współpracy różnych urządzeń poprzez wyspecjalizowane Huby, które z kolei współpracują ze sobą tworząc jednolity system, wygodny do użycia przez końcowego użytkownika dzięki : − prostemu i znormalizowanemu okablowaniu, − izolacji elektrycznej, − samoidentyfikacji urządzeń, − automatycznej konfiguracji ich sterowników, − automatycznej rejestracji w systemie, − niskich kosztów sprzętu i okablowania. 180 Podstawowym elementem systemu są Huby. Hub posiada port do połączenia z hostem (Upstream Port) oraz do siedmiu portów do podłączenia urządzeń lub innych Hubów (Downstream Port), z których każdy może być indywidualnie konfigurowany i kontrolowany poprzez komputer host. Huby składają się z dwóch części: − Hub Controller, − Hub Repeater. Hub Repeater jest protokołem kontrolującym połączenie pomiędzy Upsteam Port i Downstream Port. Dostarcza on rejestr służący do komunikacji z hostem. Wszystkie elementy systemu połączone są magistralą składającą się z czterech linii: − Vbus, przewód zasilania +5[V] − D+, przewód symetrycznej skrętki sygnałowej − D-, przewód symetrycznej skrętki sygnałowej − GND, przewód masy zasilania. Typowym kablem sygnałowym jest skrętka ekranowana o impedancji charakterystycznej 90+-15[%] i maksymalnej długości 5m. Maksymalne opóźnienie sygnału między punktami końcowymi, tzn. hostem i urządzeniem musi być mniejsze od 70ns. Do transmisji danych interfejsem USB wykorzystuje się kodowanie danych NRZI (ang. Non- Return to Zero Invert on ones). Kodowanie to polega na braku zmiany poziomu dla jedynki logicznej i zmianie poziomu dla zera logicznego. Komunikacja między urządzeniami przebiega w następujący sposób: urządzenie fizyczne zostaje zidentyfikowane przez oprogramowanie typu klient, zai4nstalowane na komputerze (host). Następnie zostaje zainicjowane połączenie pomiędzy urządzeniem a hostem, umożliwiające przesyłanie komunikatów i danych. Dane odebrane z urządzenia zostają sformatowane zgodnie z wymaganiami protokołu USB i przekazane do hosta dzięki współpracy oprogramowania systemu USB, oprogramowania hosta oraz współpracującego sprzętu. Przykładem mk wyposażonego w interfejs USB może być mk CY7C68013 firmy Cypress, którego schemat blokowy przedstawiono na rys. 6.48. Rysunek 6.48. Schemat blokowy mk CY7C68013 firmy Cypress z interfejsem USB 2.0 Mk ten zbudowany jest na bazie dwóch rdzeni 8051. Pierwszy stanowi jednostkę centralną całego mk, drugi został użyty do obsługi interfejsu USB. Dodatkowo mk posiada interfejs I2C oraz układy do współpracy ze standardowymi magistralami równoległymi. 181 7. Współpraca z układami zewnętrznymi Urządzenia zewnętrzne w tym przede wszystkim pamięć zewnętrzną stosuje się w dwóch podstawowych przypadkach: - kiedy pojemność pamięci wewnętrznej danych i/lub programu jest niewystarczająca i - gdy w fazie badań prototypu urządzenia wygodniej jest korzystać z programów i danych zapisanych w wymiennych pamięciach RAM/EPROM/EEPROM. - kiedy mikrokontroler nie dysponuje wystarczającą liczbą lub odpowiednim rodzajem układu peruferyjnego (np. sterownikiem wyświetlacza LCD) Przy projektowaniu układu interfejsu pamięci lub innych układów zewnętrznych, podstawowe znaczenie dla poprawnej ich pracy ma przebieg cyklu szyny adresów, danych i sygnałów sterujących, pokazujący relacje między tymi sygnałami. Większość mikrokontrolerów realizuje kilka wariantów cyklu szyny. W układzie 8xC196 (Intel), który posłuży nam dalej do ilustracji zagadnień dotyczących współpracy z pamięciami zewnętrznymi, podstawowym rodzajem cyklu szyny jest cykl z multipleksowaniem adresów i danych, przy czym adresy są 16-bitowe. W innych trybach adresy mogą być j przesyłane w dwóch 8-bitowych porcjach lub w dynamicznie zmienianym trybie 8- i 16-bitowym. Dodatkowo, w każdym z tych trybów możliwe jest stosowanie różnych rodzajów synchronizacji zapisu i odczytu pamięci. W standardowym trybie pracy zewnętrzna pamięć jest adresowana pełnym, w tym przypadku 16-bitowym adresem przesyłanym liniami AD[15 : 0]. Dane są transmitowane i samymi liniami, niezbędne jest zatem multipleksowanie szyn. Zazwyczaj do przesyłania adresów i danych wykorzystuje się wydzielone porty wejścia/wyjścia, które w systemach pozbawionych zewnętrznych układów pamięci służą do komunikacji z otoczeniem. Na rysunku 7.1 przedstawiono wyidealizowany przebieg cyklu szyny. Sygnał ALE powoduje zatrzaśnięcie adresów w przyłączanym z zewnątrz zatrzaskowym (na przykład typu 74AC373). By uniknąć nieporozumień i nie mylić adresów na szynie z adresem wpisanym do rejestru, zatrzaśnięty adres będzie oznaczony symbolem MD[15 : 0]. Przy odczycie dane wyprowadzone z pamięci muszą ustabilizować przed pojawieniem się aktywnego, dodatniego zbocza sygnału odczytu RD . Przy zapisie natomiast dane muszą być na wyjściach MD odpowiednio wcześniej przed pojawieniem się aktywnego, dodatniego zbocza sygnału zapisu WR . Przy transmisjach 16-bitowych wykorzystuje się dodatkowo sygnał sterujący BHE (bus high enable) , który uaktywnia pamięć przechowującą bardziej znaczące bajty danych. Rysunek 7.1. Poglądowa ilustracja cyklu szyny Jeśli MAO = 0, to aktywna jest pamięć przechowująca mniej znaczące bajty danych. W ten sposób mikrokontroler może wykonywać transmisje 16-bitowych słów umieszczonych w komórkach pamięci o parzystych adresach (MAO = 0, BHE = l), tylko bardziej znaczących bajtów 182 zlokalizowanych pod adresami nieparzystymi (MAO = l, i = 0) lub oddzielnie mniej i bardziej znaczących bajtów (MAO = 0, BHE = 0). Jeśli pracujemy z pamięcią tylko do odczytu, wtedy dekodowanie stanów BHE i MAO nie jest potrzebne. Jeśli zajdzie taka potrzeba, mikrokontroler sam odrzuci niepotrzebną część odczytanych danych. Sygnały biorące udział w transmisji są generowane synchronicznie z impulsami wewnętrznego zegara, a dokładniej z przebiegiem na wyprowadzeniu CLKOUT, który jest ściśle związany z przebiegiem na wyprowadzeniu oscylatora XT ALI. Cykl szyny nie zawierający dodatkowych opóźnień, nazywanych stanami oczekiwania (ang. wait states) trwa w omawianym procesorze dwa okresy zegara. Pierwsze ujemne zbocze CLKOUT generuje sygnał ALE i wyprowadza na szynę adres. Następujące po nim zbocze dodatnie likwiduje sygnał ALE. Kolejne ujemne zbocze CLKOUT powoduje pojawienie się sygnału RD lub WR. Ostatnie w cyklu ujemne zbocze zegara przy odczycie zatrzaskuje dane z szyny w wewnętrznym rejestrze danych mikrokontrolera, natomiast przy zapisie oznacza, że na szynie są ważne dane. Przedstawiony powyżej cykl szyny odnosi się do współpracy z dostatecznie szybkimi pamięciami zewnętrznymi (lub innymi urządzeniami), które są w stanie spełnić wymagane relacje czasowe między sygnałami. Jeśli pamięć jest zbyt wolna, do cyklu szyny wstawiane są stany oczekiwania. Każdy taki stan trwa przez dwa okresy zegara. W mikrokontrolerach, które są zbudowane jako układy statyczne, liczba wprowadzanych stanów oczekiwania może być dowolnie duża, natomiast w mikrokontrolerach zawierających układy dynamiczne liczba ta jest ograniczona. Żądanie dodania! do cyklu szyny stanów oczekiwania układy współpracujące z mikrokontrolerem sygnalizują podając sygnał READY. Różnorodność trybów pracy szyny wymaga wprowadzenia mechanizmu, dzięki któremu mikrokontroler mógłby jednoznacznie określić konfigurację zewnętrznego podsystemu pamięci. W przypadku mikrokontrolera 8xC196 służy do tego rejestr konfiguracji CCR (ang. chip configuration register), umieszczony w komórce o adresie 2018H w wewnętrznej lub zewnętrznej pamięci, w zależności od stanu na wejściu EA (rysunek 7.2). Dwa bardziej znaczące bity LOCO i LOC1 określają rodzaj protekcji pamięci. Może ona oznaczać na przykład zakaz zapisu (EPROM) lub zakaz odczytu (ROM/EPROM) przez nieupoważnione programy. Stan LOCO = LOC1 = 1 oznacza, że pamięć nie jest objęta protekcją. Kolejne dwa bity IRCO i IRC l oznaczają górny limit liczby stanów oczekiwania. Rysunek 7.2. Rejestr konfiguracji pamięci w systemie z mikroprocesorem 8xC196 Kombinacja dwóch zer oznacza, że dozwolony jest maksymalnie jeden stan oczekiwania, natomiast dwie jedynki pozwalają wprowadzić dowolną liczbę stanów oczekiwania. Następne trzy bity definiują sposób sterowania szyną, który dokładniej zostanie opisany w dalszej części rozdziału. 183 Ostatni, najmniej znaczący bit określa, czy pamięć może być wyłączana (zezwolenie lub blokada trybu power-down). Zawartość rejestru jest pierwszym bajtem pobieranym z pamięci po sygnale RESET i nie może być zmieniana w trakcie pracy systemu. 7.1. Sterowanie szynami W zależności od ustawienia rejestru CCR procesor może generować kilka różnych rodzajów sygnałów sterujących szynami, przy czym wyprowadzenia ALE, WR i BHE spełniają podwójne funkcje. Dzięki temu mikrokontroler jest przystosowany do współpracy z podsystemami pamięci o różnych konfiguracjach bez potrzeby używania dodatkowych układów zewnętrznych do wypracowania sygnałów sterujących. Na rysunku 7.3a,b przedstawiono uproszczony diagram przebiegu sygnałów w czasie standardowego cyklu szyny. Sygnał ALE pojawia się wraz z adresami i opada po ich ustabilizowaniu wyznaczając moment zatrzaśnięcia adresów w rejestrze zatrzaskowym, Operacja zapisu następuje po pojawieniu się na szynie danych, w chwili określonej przez sygnał WR. Jeśli stosuje się transmisję 16-bitową dodatkowo wykorzystywany jest sygnał BHE. Za jego pomocą można również uzyskać sygnały WRH i WRL do sterowania zapisem odpowiednio tylko bardziej lub mniej znaczących bajtów. . Sposób generowania sygnałów WRH i WRL przedstawiono na rysunku 7.3c. Rysunek 7.3. Standardowy cykl szyny: a) w konfiguracji 16-bitowej, b) w konfiguracji 8-bitowej oraz sposób generowania sygnałów WRH i WRL Stosowanie zewnętrznych układów do generowania sygnałów WRH i WRL może nie być potrzebne dzięki trybowi pracy ze strobowanym zapisem (ang. write strobe mode). Tryb ten jest wybierany, jeśli bit 2 rejestru CCR jest wyzerowany. Przy transmisjach 16-bitowych sygnały WRL i WRH są generowane wówczas na wyprowadzeniach WR i BHE, przy czym gnał WRL pojawia się przy zapisach bajtów do komórek o adresach parzystych oraz przy zapisach słów 16-bitowych. Sygnał WRH jest generowany przy zapisach bajtów do komórek o adresach nieparzystych i przy zapisach słów 16-bitowych. Postać cyklu szyny w tym trybie pracy mikrokontrolera przedstawiono na rysunku 7.4. 184 Rysunek 7.4. Cykl szyny w trybie zapisu ze strobem: a) transmisje 16-bitowe, b) transmisje 8-bitowe Jeśli bit 3 w rejestrze CCR jest wyzerowany, mikrokontroler pracuje w trybie ze strobowaniem ważnego adresu (ang. address valid strobe mode). Przebiegi sygnałów w czasie cyklu szyny wykonywanego w tym trybie przedstawiono na rysunku 7.5. Sygnał ADV, który pojawia się po ustabilizowaniu adresów zastępuje używany wcześniej sygnał ALE. Aktywny stan ADV trwa aż do końca cyklu szyny, dzięki czemu sygnał ten można wykorzystać do sterowania wejściami wyboru pamięci CS (ang. chip select). Rysunek 7.5. Cykl szyny w trybie ze strobem ważnego adresu: a) transmisje 16-bitowe, b)transmisje 8bitowe Możliwa jest również kombinacja obu tych trybów, czyli praca ze strobem ważnego adresu i strobem zapisu. Postać cyklu szyny dla transmisji 16- i 8-bitowych w tym trybie przedstawiono na rysunku 7.6. Rysunek 7.6. Cykl szyny z oddzielnym sygnałem strobu ważnych adresów i strobem zapisu: a) transmisje 16-bitowe, b) transmisje 8-bitowe 185 Jak wynika z przedstawionego dotąd opisu cyklu szyny w omawianym mikrokontrolerze, może on pracować z dwoma szerokościami szyny danych: 16-bitową i 8-bitową. Konfiguracja szerokości szyny może odbywać się w trakcie pracy mikrokontrolera i być zmieniana. Tryb 16-bitowy oznacza przesyłanie 16-bitowych adresów i 16-bitowych danych ze wspólną, multipleksowaną szynę, natomiast tryb 8-bitowy oznacza przesyłanie 6-bitowych adresów i 8-bitowych danych, przy czym multipleksowane jest mniej znaczące 8 bitów szyny adresowej. Tryb 8-bitowy jest zatem identyczny jak w prostych 8-bitowych mikrokontrolerach, na przykład należących do rodziny x51. Podczas cykli 16-bitowych porty 3 i 4 przesyłają dane i adresy, przy czym sygnał ALE jest używany do zatrzaskiwania adresów. W trybie 8-bitowym multipleksowane jest tylko 8 mniej znaczących bitów adresu, natomiast 8 bardziej znaczących bitów ma ważne wartości w czasie trwania całego cyklu szyny. Rysunek 7.7. Dwa warianty konfiguracji szyny mikrokontrolera: a) szyna 16-bitowa z multipleksowaniem adresów i danych i b) szyna 8-bitowa z multipleksowaniem mniej znaczącego bajtu Szerokość szyny może być zmieniana co cykl szyny, jeśli tylko bit l w rejestrze CCR zostanie ustawiony podczas operacji RESET. W czasie pracy szerokość szyny jest zmieniana dynamicznie przy użyciu sygnału doprowadzonego do wejścia BUSWIDTH. Jeśli na wejściu jest stan wysoki, szyna ma szerokość 16-bitów, natomiast w przeciwnym przypadku szyna pracuje w trybie 8bitowym. Jeśli w rejestrze CCR bit l jest wyzerowany, sygnał BUSWIDTH nie je wykorzystywany. System dynamicznych zmian szerokości szyny daje pożyteczne w praktyce możliwości. Na przykład instrukcje mogą być pobierane z pamięci programu w trybie 16-bitowym, natomiast dane w trybie 8-bitowym. Dzięki temu nie trzeba stosować danych dwóch 8-bitowych pamięci RAM, jeżeli pojemność jednej pamięci jest wystarczająca. Konfigurację tego typu uzyskuje się przez połączenie wejścia BUSWIDTH mikrokontrolera z wejściem CS pamięci i sterowanie ich wspólnym sygnałem. Korzystając z trybu 8-bitowego do pobierania kodów instrukcji z pamięci programu należy pamiętać, że mikrokontroler nie jest wówczas w stanie pracować z pełną wydajnością. W szczególności, kolejka instrukcji w potoku może być w pewnych okolicznościach nie wypełniana. 7.2. Wstrzymanie dostępu do szyny W rozbudowanych systemach cyfrowych, w których wspólna szyna łączy większą liczbę rozproszonych mikrokontrolerów lub innych urządzeń wyposażonych we własne sterowniki szyny, często zachodzi potrzeba blokowania dostępu mikrokontrolera do szyny po to, by inne urządzenie mogło przejąć sterowanie i wykonać transmisję. Do tego celu służy mechanizm wstrzymywania dostępu do szyny (ang. hold). Do obsługi wstrzymań w omawianym mikrokontrolerze 8xC 196 (Intel) używa się trzech sygnałów: HOLD, HLDA i BREQ. Urządzenie, które chce przejąć kontrolę szyną, wysyła żądanie dostępu do szyny. Sygnał ten, podany na wejście HOLD mikrokontrolera wywołuje sekwencję czynności przedstawionych na diagramie z rysunku 7.8. 186 Rysunek 7.8. Przebiegi sygnałów na szynie po zewnętrznym zgłoszeniu żądania wstrzymania dostępu do szyny przez mikrokontroler W odpowiedzi na sygnał HOLD mikrokontroler wysyła potwierdzenie zwolnienia szyny w postaci sygnału HLDA (ang. hold acknowledge). Po wykorzystaniu szyny przez urządzenie zgłaszające żądanie dostępu sygnał HOLD zostaje zdjęty. Mikrokontroler zdejmuje wówczas sygnał HLDA i przejmuje z powrotem kontrolę nad szyną. W czasie wstrzymania dostępu do szyny mikrokontroler może realizować program, nie może jednak korzystać z szyny zewnętrznej. Jeśli powstanie taka potrzeba, mikrokontroler generuje sygnał BREQ, który wskazuje urządzeniom zewnętrznym, by niepotrzebnie nie przetrzymywały dostępu do szyny. Sygnał BREQ jest zdejmowany razem z sygnałem HLDA. W czasie trwania wstrzymania wyjścia danych, adresów, RD, WR, BHE i 1NST i nieokreślone stany, natomiast wyjście ALU znajduje się w stanie niskim, przy czym możliwa jest realizacja funkcji „zwartego lub" i połączenia linii ALE z różnych sterowników szyny. W niektórych mikrokontrolerach wyprowadzenia sygnałów HOLD, HLDA i BREQ są niezależne, w innych natomiast sygnały te są przekazywane przez wybrane linie portów wejścia/wyjścia i wykorzystywane tylko w razie potrzeby. Na rysunku 7.9 przedstawiono dwa warianty reakcji mikrokontrolera na sygnał wstrzymania. Efektywne przekazywanie dostępu do szyny przez różne urządzenia wymaga by maksymalny czas między zgłoszeniem HOLD a potwierdzeniem udostępnienia szyny HLDA był krótki. Czas ten jest nazywany opóźnieniem reakcji na wstrzymanie (ang. hold lattency), a jego wielkość zależy od rodzaju cyklu szyny wykonywanego przez mikrokontroler podczas nadejścia zgłoszenia HOLD. 187 Rysunek 7.9. Obsługa asynchronicznego sygnału wstrzymania HOLD: a) zgłoszonego z wyprzedzeniem w stosunku do dodatniego zbocza zegara, b) zgłoszonego asynchronicznie Badanie stanu wejścia HOLD jest przeprowadzane przy najbliższym dodatnim zboczu zegara, jeśli tylko zgłoszenie wstrzymania wyprzedza to zbocze o minimalny odstęp czasu oznaczany symbole THVCH Jeśli czas wyprzedzenia HOLD nie jest zachowany, zgłoszenie zostanie rozpoznane dopiero przy następnym zboczu zegara (rysunek 7.9b). To samo dotyczy wyjścia ze stanu wstrzymania: jeśli sygnał HOLD zostanie zdjęty z odpowiednim wyprzedzeniem w stosunku do najbliższego dodatniego zbocza zegara, wyjście ze stanu wstrzymania i nastąpi razem z tym zboczem, a ściślej biorąc po upływie niewielkiego odstępu czasu THVCH . Większość mikrokontrolerów ma możliwość blokowania żądań wstrzymań. Opcja ta jest potrzebna na przykład wtedy, gdy mikrokontroler musi wykonać serię odwołań do pamięci zewnętrznej w czasie rzeczywistym, bez opóźnień wywołanych wstrzymaniami. Bit zezwolenia na wstrzymania HLDEN (ang. hold enable) umieszczony w jednym z rejestrów specjalnych SFR mikrokontrolera może być ustawiany i zerowany podczas wykonywania programu. Jeśli jednostka centralna zablokuje wstrzymania (HLDEN = 0), a mikrokontroler znajduje się właśnie w stanie wstrzymania, przywrócenie dostępu do szyny nastąpi dopiero po zakończeniu bieżącego cyklu wstrzymania. 7.3. Przyłączenie zewnętrznych pamięci RAM/ROM/EPROM Zewnętrzne pamięci RAM / ROM / EPROM mogą być przyłączane do mikrokontrolerów na wiele różnych sposobów. Na rysunku 7.10 pokazano najprostszą konfigurację, w której mikrokontroler współpracuje z jednym zewnętrznym układem ROM / EPROM w trybie 8-bitowym. 188 Rysunek 7.10. Połączenie mikrokontrolera z jednym układem zewnętrznej pamięci ROM/EPROM w trybie przesłań 8-bitowych Do sterowania wejściem wyboru układu pamięci CS wykorzystano sygnał ADV. W rejestrze konfiguracji pamięci CCR bit numer l jest wyzerowany, co powoduje, że system pracuje w trybie przesłań 8-bitowych. Do zatrzaskiwania mniej znaczącego bajtu. użyto rejestru typu 373, strobowanego sygnałem ADV. W przypadku nowoczesnych pamięci ROM / EPROM jest on najczęściej niepotrzebny, ponieważ pamięć ma wbudowany rejestr zatrzaskowy adresu. Jeśli w systemie potrzebne są dwie pamięci, jedna typu RAM, a druga nieulotna, można zastosować konfigurację przedstawioną na rysunku 7.11. W układzie tym pamięć ROM/EPROM jest umieszczona w dolnej połowie przestrzeni adresowej, natomiast pamięć RAM w górnej połowie. Jeszcze inaczej można zorganizować pamięć w trybie 16-bitowym, z pamięcią stałą. Konfigurację połączeń pokazano na rysunku 7.12. Rysunek 7.11. Połączenie mikrokontrolera z pamięcią ROM/EPROM i pamięcią RAM 189 Rysunek 7.12. Połączenie mikrokontrolera z dwoma pamięciami w trybie 16-bitowym Najbardziej pełna konfiguracja podsystemu zewnętrznej pamięci jest przedstawiona na rysunku 7.13, na którym pokazano wariant z dynamicznie zmienianą szerokością szyny. Pamięci stałe przechowują kod programu, natomiast dane są umieszczone w pamięci RAM. Należy zwrócić uwagę, że sygnał CS wyboru pamięci RAM jest jednocześnie używany do sterowania wejściem BUSWIDTH i wymuszenia 8bitowego trybu pracy na szynie. Rysunek 7.13. Połączenie pamięci w konfiguracji z dynamicznym wyborem szerokości szyny Przedstawione powyżej proste warianty realizacji połączeń mikrokontrolera z pamięciami zewnętrznymi wykorzystują bezpośrednie sterowanie sygnałami wyboru układów pamięci CS z wyjścia ADV lub najbardziej znaczącym bitem adresu. W praktyce, zwłaszcza gdy w systemie znajduje się wiele układów pamięci, takie rozwiązanie jest niewystarczające, nie pozwala bowiem lokować pamięci o różnych pojemnościach w wybranych miejscach przestrzeni adresowej. Znacznie wygodniejsze w użyciu są wówczas mikrokontrolery wyposażone we wbudowany dekoder adresów i wyprowadzenia kilku lub nawet kilkunastu zdekodowanych sygnałów CS. Oprócz tego niektóre mikrokontrolery mają dodatkowe wyjście wyboru pamięci, w której zapisano oprogramowanie inicjujące pracę systemu (CSBOOT). Stosując na przykład mikrokontroler 68HC16 można zewnętrzne pamięci przyłączyć w sposób przedstawiony na rysunku 7.14. 190 Rysunek 7.14. Sterowanie pamięciami przez mikrokontroler wyposażony w wyjścia selekcji CS Pamięć RAM została przyłączona do linii ośmiu bardziej znaczących bitów szyny danych. Przy zapisie dane pojawiają się również na mniej znaczących bitach, ale nie ma to wpływu na pracę pamięci ROM, która jest wówczas nieaktywna. Warto zauważyć, że 16-bitowa pamięć ROM jest sterowana adresami ADDR[16 : l], to znaczy bit ADDR1 szyny jest połączony z wejściem adresowym ADDR0 pamięci. Zapewnia to prawidłową pracę przy odczycie słowami 16-bitowymi. Pamięć RAM jest wybierana sygnałem CSO mikrokontrolera, natomiast pamięć stała uaktywnia się po wystąpieniu sygnału CSBOOT. Na rysunku 7.15 przedstawiono natomiast sposób połączenia dwóch 8-bitowych pamięci pracujących wspólnie jako układ 16-bitowy. Dodatkowo pokazano połączenie z pamięcią 16-bitową typu ROM. Wyborem układów RAM sterują sygnały CSO i CS1, przy czym CSO wybiera pamięć przechowującą bardziej znaczące bajty danych, natomiast CS1 wybiera pamięć zawierającą mniej znaczące bajty. Wejścia strobu odczytu i zapisu obydwu układów są połączone z wyjściem R / W mikrokontrolera. Zaletą przedstawionego rozwiązania jest brak jakichkolwiek zewnętrznych układów. Nie jest potrzebne stosowanie ani rejestrów zatrzaskowych, ani najprostszych nawet dekoderów adresów. Uproszczenia te wynikają po części stąd, że przykładowy mikrokontroler użyty do ilustracji struktur bloków pamięci na rysunkach 7.14 i 7.15 ma rozdzielone szyny adresów i danych, a po części z wykorzystania sygnałów wyboru układów (CS). 191 Rysunek 7.15. Konfiguracja 16-bitowej pamięci złożonej z dwóch układów 8-bitowych Odmianą konfiguracji z rysunku 7.15 jest wariant połączeń przedstawiony na rysunku 7.16. Tu również dwie 8-bitowe pamięci RAM tworzą razem jeden blok pamięci 16-bitowej, ale zastosowano układy z oddzielnymi wejściami strobu odczytu OE i zapisu WE. Są one uzyskiwane z odpowiednich wyjść CS mikrokontrolera. Wejścia wyboru układów RAM są połączone z masą, toteż obydwa układy są zawsze gotowe do pracy. Rysunek 7.16. Blok 16-bitowej pamięci RAM złożonej z dwóch układów 8-bitowych sterowanych oddzielnymi sygnałami zapisu i odczytu Przytoczone przykłady połączeń mikrokontrolerów z pamięciami zewnętrznymi nie wyczerpują bogactwa możliwych wariantów budowy podsystemu pamięci RAM/ROM/EPROM. W szczególności, jeśli w systemie wykorzystywane są zewnętrzne dynamiczne pamięci RAM (DRAM), niezbędne jest zapewnienie odświeżania ich zawartości. Pamięci tego typu są wyposażone w wejścia RAS (ang. rów address strobe) l i CAS (ang. column address strobe). Odświeżanie polega na okresowym odczycie komórek pamięci przy odpowiednim wysterowaniu wejść RAS i CAS. Okres, w którym pamięć musi być odświeżana, jest rzędu milisekundy. Zadanie to realizuje się dwoma sposobami: - z wykorzystaniem układów sterowania odświeżaniem wbudowanych do mikrokontrolera (np. H8 Hitachi, i960 Intel, Y8000 NEC), - przy użyciu zewnętrznego kontrolera pamięci DRAM. Użycie wbudowanego kontrolera pamięci DRAM jest wygodniejsze, jednak tylko nieliczne mikrokontrolery 8- i 16-bitowe są wyposażone w taki układ (por. p. 2.4). W rozbudowanych systemach ze skomplikowaną mapą pamięci często zachodzi też potrzeba użycia zewnętrznych dekoderów adresowych. Dotyczy to zwłaszcza systemów z mikrokontrolerami, które nie mają wyjść CS. Dekodery adresowe buduje się z prostych układów kombinacyjnych, na przykład ze scalonych dekoderów z wyjściem w kodzie ,.1 z 8" - uklad 74HCT138, albo przy użyciu programowanych układów PLD. 7.4. Współpraca z pamięciami EEPROM i błyskowymi Pamięci nieulotne EEPROM i błyskowe są coraz częściej stosowane w systemach mikroprocesorowych ze względu na możliwość programowania ich zawartości w układzie, pracują (ang. in-circuit programming). Jeśli pamięci te są zaprogramowane poza systemem i używane wyłącznie jako ROM, mogą współpracować z mikrokontrolerami w taki sam sposób jak pamięci ROM/EPROM. W szczególności, można je przyłączać do mikrokontrolera zgodnie z zasadami 192 podanymi w p.7.3, w konfiguracjach opisanych na rysunkach 7.10-7.16. Inaczej wygląda współpraca mikrokontrolera z pamięciami błyskowymi i EEPROM w następujących przypadkach: 1) gdy pamięć błyskowa lub EEPROM ma być nie tylko odczytywana, ale również programowana w układzie, w którym pracuje, 2) gdy pamięć jest wyposażona w szeregowe wejście i wyjście danych. Analizę tych przypadków rozpoczniemy od omówienia współpracy mikrokontrolerów: tanimi pamięciami EEPROM o niewielkich pojemnościach wyposażonych w szeregowe wejścia i wyjścia. 7.5. Przyłączanie pamięci EEPROM z dostępem szeregowym Pamięci EEPROM z szeregowym wejściem i wyjściem danych są stosowane w miniaturowych kontrolerach, w których ważny jest koszt wykonania układu, jego gabaryty, masa pobór mocy. Pojemności pamięci tego typu nie przekraczają zwykle kilku kilobajtów, nadają się zatem do wykorzystania w systemach z niezbyt skomplikowanym oprogramowaniem. Ich zaletą, oprócz niskiej ceny i małych rozmiarów obudowy, jest standardowe cię zasilania równe zwykle +5V. Produkowane są również pamięci zasilane napięciem +3V. Podobnie jak pamięci EEPROM z wejściami i wyjściami równoległymi, układy pracujące w trybie szeregowym mają zwykle wbudowaną przetwornicę napięcia i nie wymagają do programowania i kasowania zewnętrznego napięcia programującego. W praktyce spotyka się dwie podstawowe odmiany pamięci EEPROM z szeregowym wejściem i wyjściem danych: - układy pracujące z niestandardowym protokołem wymiany danych, - układy I2C EEPROM, w których zastosowano protokół komunikacji szeregowej opracowany przez firmę Philips. Przykładem pamięci EEPROM z dostępem szeregowym jest rodzina układów 93x6 produkowana między innymi przez takie firmy, jak National, Catalyst, SGS Thomson rochip. Protokół wymiany informacji nie jest zgodny z żadnym międzynarodowym standardem, wszystkie pamięci tej rodziny wykorzystuj ą jednak identyczny zbiór poleceń dwójkowych potrzebnych do kasowania, programowania i odczytu ich zawartości. Są dostępne w odmianach o pojemności l kb (128 x 8), 2 kb (256 x 8) oraz 4 kb (512 x 8). Zasadniczą wadą tych układów, jak również innych rodzajów pamięci EEPROM, jest długi czas zapisu informacji, wynoszący w przypadku układów z. serii 93x6 około 4 ms. Do sterowania pamięci EEPROM z szeregowym dostępem stosuje się powszechnie dwie różne metody: − sterowanie przy użyciu linii portów wejścia/wyjścia mikrokontrolera oraz − sterowanie przez interfejs komunikacji szeregowej. Na rysunku 7.17 pokazano przykładową konfigurację połączenia pamięci EEPRCto typu 93C56 z prostym mikrokontrolerem 8-bitowym typu 68HC705 (Motorola). 193 Rysunek 7.17. Przykładowe połączenie pamięci EEPROM z szeregowym dostępem do mikrokontrolera przy użyciu linii portu wejścia/wyjścia mikrokontrolera Pamięć jest połączona z mikrokontrolerem przez 4 linie portu PA. Spełniają one następując funkcje: PAO - CS (ang. chip select), linia wyboru układu pamięci, PA1 - SK (ang. serial clock), sygnał szeregowo przesyłanych impulsów synchronizujących (zegarowych), PA2 - DI (ang. serial data input), szeregowe wejście danych, PAS - DO (ang. serial data output), szeregowe wyjście danych. Procesor steruje pamięcią wysyłając do niej polecenia złożone z 3 bitów kodu polecenia, 8 bitów adresu i ewentualnie 16 bitów danych. Formaty i znaczenie poszczególnych poleceń podano w tablicy 7. l. Tablica 7.1. Formaty i funkcje poleceń sterowania pamięcią EEPROM W układzie z rysunku 7.17 operacje zapisu, odczytu i kasowania pamięci EEPROM są wykonywane przez odpowiednie procedury programowe. Tryb taki bywa nazywany obsługą przez programowe przeglądanie (ang. polling). Przykładowy algorytm odczytu danych z pamięci w opisanej wcześniej konfiguracji przedstawiono na rysunku 7.18. Założono przy tym dodatkowo, że pamięć może przesyłać dane w trybie 16-bitowym, tak jak określa to tablica 7.1, oraz w trybie 8-bitowym. Wybór trybu odbywa się przez odpowiednie ustawienie dodatkowego wejścia ORG/NC (nie pokazanego na rysunku 7.17). Jeśli wejście to jest połączone z masą układu, pamięć pracuje w trybie 8-bitowym, natomiast jeśli na wejściu jest stan wysoki - przesłania odbywają się słowami 16-bitowymi. Po odpowiednim skonfigurowaniu portów mikrokontrolera polegającym w tym przypadku na zdefiniowaniu kierunku transmisji w porcie PA, program wysyła polecenie WDS zabezpieczające pamięć przed przypadkowym skasowaniem. Następnie w pętli odczytywane są kolejne słowa (lub bajty dla trybu 8-bitowego). 194 Rysunek 7.18 Algorytm odczytu z pamięci EEPROM o dostępie szeregowym Licznik przesłań N jest ustawiony przed wywołaniem procedury i zawiera liczbę słów (bajtów), które procedura ma odczytać z pamięci oraz adres bufora w wewnętrznej pamięci mikrokontrolera, w której zapisywane są odczytane dane. Przy każdym obiegu pętli wartość licznika jest zmniejszana o 1. Jednocześnie inkrementowany jest adres pamięci. Wygodniejszą metodą współpracy z pamięciami EEPROM o dostępie szeregowym jest wykorzystanie portu transmisji szeregowej mikrokontrolera (UART, USART, SP itp.). Przykład połączenia mikrokontrolera z pamięcią EEPROM przez port SPI pokazano na rysunku 7.19. 195 Rysunek 7.19. Współpraca mikrokontrolera z pamięcią EEPROM o dostępie szeregowym przez port transmisji szeregowej SPI (Motorola) Port szeregowy, jak jest to wyjaśnione szczegółowo w dalszej części rozdziału, może pracować w dwóch podstawowych trybach: z zablokowanymi przerwaniami oraz z włączonym systemem przerwań. W pierwszym przypadku program przegląda stan rejestrów portu i kolejno wysyła lub odczytuje dane. Tryb ten jest zatem podobny do opisanego wcześniej wariantu z wykorzystaniem portu wejścia/wyjścia. Korzyścią z zastosowania portu jest to, że konwersja równoległo-szeregowa i szeregowo-równoległa danych odbywa się teraz nie programowo, ale sprzętowo. W trybie z przerwaniami program może realizować inne zadania, podczas gdy trwa transmisja. Jednostka centralna jest angażowana tylko po skompletowaniu danych w buforze portu szeregowym przy odbiorze po opróżnieniu bufora przy wysyłaniu danych. Powiadomienie CPU o zakończeniu transmisji bajtu odbywa się za pomocą mechanizmu przerwań. Źródłem przerwań jest w tym przypadku wewnętrzny układ portu szeregowego mikrokontrolera. Oczywiście przed rozpoczęciem transmisji należy odpowiednio skonfigurować port szeregowy. Sposób konfiguracji oraz funkcje poszczególnych linii portu SPI (SCK, MOSI, MISO) omówione w jednym z następnych punktów. 7.6. Współpraca z pamięciami błyskowymi Jeśli pominąć wejście zezwolenia na zapis (ang. write-enable), pamięci błyskowe można traktować tak jak zwykłą pamięć EPROM. Z funkcjonalnego punktu widzenia rzeczywista różnica między oboma rodzajami pamięci polega zatem wyłącznie na tym, że pamięć błyskową można kasować i programować w sposób elektryczny. Jeśli chcemy korzystać z zaprogramowanej wcześniej pamięci FLASH i tylko odczytywać jej zawartość, można posłużyć się konfiguracjami z rysunków 7.10 7.16. Zastosowane tam pamięci ROM/EPROM o pojemności 32 kB można zastąpić na przykład pamięcią błyskową 28F256 o identycznej organizacji wewnętrznej. Pamięci błyskowe, podobnie jak omówione wcześniej proste pamięci ERPROM z dostępem szeregowym przyjmują oprócz danych polecenia, które umożliwiają realizację różnych rodzajów operacji. Przykład poleceń dla popularnej pamięci typu 29F010 ced Micro Devices) o organizacji 128 k x 8 podano w tablicy 7.2. 196 Tablica 7.2. Formaty poleceń sterowania pamięcią błyskową 29F010 (AMD) Znaczenie symboli użytych w tablicy 7.2 jest następujące: RA - adres komórki pamięci do odczytu, PA- adres komórki pamięci do zaprogramowania, określony w chwili wystąpienia opadającego zbocza na wejściu WE pamięci, SA. - adres sektora do skasowania, RD - zawartość komórki pamięci o adresie RA, PD - zawartość komórki pamięci o adresie PA. Pamięć typu 29F010 jest podzielona na sektory, przy czym kasowanie można przeprowadzać tylko dla wybranego sektora albo dla całej pamięci. Polecenie Read/R oznacza wprowadzenie pamięci w tryb Read/Reset i umożliwia odczyt danych. Polecenie AUTO odczytuje typ układu i kod producenta zapisany w pamięci, rozkaz Byte zapisuje dane do pamięci, natomiast polecenia Erase i Sector kasują odpowiednio całą pamięć lub sektor (fragment pamięci o wielkości zależnej od jej wewnętrznej organizacji). Różne warianty połączeń pamięci błyskowej z mikrokontrolerem zostaną prześledzone na przykładzie mikrokontrolera 80C51XA G3 (Philips). Procesor ten jest wytwarzany w kilku odmianach z różnymi rodzajami wbudowanej pamięci RAM/ROM/0l Ma 20-bitową szynę zewnętrznych adresów i może współpracować z pamięciami o pojemności do l MB. Na rysunku 7.20 przedstawiono najprostszą konfigurację połączeń z pamięcią błyskową przy założeniu, że nie jest potrzebna dodatkowa, zewnętrzna pamięć W konfiguracji tej oprogramowanie do ładowania programu z pamięci błyskowej jest zapisane w wewnętrznej pamięci EPROM/OTP mikrokontrolera. Również inicjację systemu wykonuje program w wewnętrznej pamięci stałej procesora (ang. bootfrom ROM). Wymuszenie startu programu z wewnętrznej pamięci następuje przez podanie stanu wysokiego na wejście EA (ang. external access). Po uruchomieniu wewnętrznego programu następuje odwołanie do zewnętrznej pamięci błyskowej. Rysunek 7.20. Połączenie pamięci błyskowej typu 29F010(AMD) o organizacji 128k x8 z mk80C51 XA (Philips) 197 Zanim to jednak nastąpi, procesor musi zablokować wejście WAIT przez wpis odpowiedniego bitu do rejestru BCR (ang. bus configuration register). W wyniku tego CPU nie będzie otrzymywać sygnałów żądania wstawienia do cyklu szyny stanów oczekiwania. W tym przypadku stany oczekiwania nie są potrzebne, ponieważ program jest przed wykonaniem przepisywany do wewnętrznej pamięci mikrokontrolera. Program ładujący (ang. loader) jest zapisany również wewnątrz mikrokontrolera. Inicjacja ładowania może nastąpić na sygnał z zewnątrz, doprowadzony na przykład przez UART. Zaletą przedstawionej konfiguracji jest jej prostota i brak potrzeby stosowania dodatkowych układów zewnętrznych. Ma ona jednak także wady. Najważniejszą jest to, że adresy procedur obsługi przerwań (wektor przerwań) w procesorze XA są przechowywane w obszarze adresów 0-120H wewnętrznej pamięci ROM, nie mogą być więc zmieniane. Programy zapisane w pamięci błyskowej muszą być dopasowane do tych adresów, to znaczy muszą zawierać procedury obsługi w odpowiednich miejscach. Ponadto początkowy adres startu aplikacji jest sztywno określony. Inną wadą jest marnowanie początkowego obszaru 32 kB w pamięci FLASH, jeśli jest ona umieszczona w mapie adresowej począwszy od adresu 0000H, ponieważ w obszarze tym znajduje się wewnętrzna pamięć ROM mikrokontrolera. Wadą jest też wyższa cena mikrokontrolera XA z wbudowaną pamięcią OTP w porównaniu z wersją bez pamięci stałej (ang. ROM-less) oraz kłopotliwa emulacja programów, ponieważ nie są one umieszczone począwszy od 0000H. Sygnał PSEN (ang. program store enable) jest strobem odczytu zewnętrznej pamięci programu. Na rysunku 7.21 przedstawiono inny wariant połączenia mikrokontrolera 80C51 z zewnętrzną pamięcią błyskową. Zastosowano mikrokontroler bez wewnętrznej pamięci ROM. Program inicjujący pracę systemu (ang. boot program) jest umieszczony w zewnętrznej pamięci stałej o pojemności 4 kB. W pamięci błyskowej przechowywany jest program aplikacji sterującej pracą systemu. Program aplikacji jest umieszczony w obszarze adresowym zaczynającym się od adresu 0000H. Rysunek 7.21. Połączenie mk 80XC51 XA z pamięcią błyskową i zewnętrzną pamięcią ROM zawierającą program inicjujący Program ładujący zapisano w zewnętrznej pamięci ROM ulokowanej w obszarze położonym powyżej obszaru FLASH, od adresu 20000H. Po wystąpieniu sygnału RESET, lub po włączeniu zasilania, system ładuje program aplikacji z pamięci błyskowej, ponieważ wejście EA jest utrzymywane w stanie niskim. Jeśli mikrokontroler otrzyma polecenie ponownego załadowania aplikacji z pamięci FLASH, na przykład sygnałem z konsoli operatorskiej przyłączonej przez port UART, wykonywana aplikacja generuje skok do programu ładującego w zewnętrznej pamięci ROM. Po załadowaniu nowej 198 aplikacji niezbędne jest wydanie programowego sygnału RESET w celu wznowienia pracy aplikacji. Zamiast układu ROM typu 82HS321 wykorzystanego w systemie z rysunku 7.21. możliwe jest, oczywiście, użycie innej pamięci, na przykład EPROM typu 27Cxx. Jeśli w systemie potrzebna jest większa pamięć FLASH, zamiast pojedynczej pamięci 29F010 stosuje się kilka takich układów lub jeden układ o większej pojemności. Wejście zezwolenia CE pamięci należy wówczas połączyć nie z linią A17, jak pokazano na rysi 7.21, ale z linią A19. Organizacja mapy pamięci omawianego przykładowego systemu wymaga, by zapis do komórek pamięci FLASH w obszarze adresów od 0000H do 01FFH w przypadku mikrokontrolera XA G3 i w obszarze adresów od 0000H do 03FFH w przypadku mikrokontrolera XA S3 był wykonywany przy użyciu instrukcji odwołań do pamięci zewnętrznej. Na liście instrukcji omawianego mikrokontrolera, instrukcja ta ma oznaczenie mnę mnemoniczne MOVX. Jeśli zamiast instrukcji MOVX w programie zostanie użyta instrukcja MOV stosowana przy przesłaniach wewnętrznych, program odwoła się do wewnętrznej pamięci mikrokontrolera. Konfiguracja połączeń mikrokontrolera XA z zewnętrzną pamięcią błyskową pokazana na rysunku 7.21 ma ważne zalety: - system jest elastyczny; można stosować dodatkowe pamięci i swobodnie organizować mapę pamięci, - wektor przerwań jest zapisany w pamięci błyskowej i może być łatwo modyfikowany; pozwala to na dopasowanie adresów przerwań do programu aplikacji w pamięci, a nie odwrotnie, jak wymagała tego konfiguracja z rysunku 7.20, - mikrokontroler XA bez wewnętrznej pamięci ROM jest tańszy niż wersja z pamięcią ROM/OTP, - ładowanie aplikacji zaczyna się zawsze od adresu 0000H, - możliwa jest prosta emulacja w trakcie wykonywania aplikacji zapisanych w pamięci błyskowej. Do wad przedstawionej powyżej konfiguracji należy natomiast zaliczyć konieczność stosowania zewnętrznej pamięci stałej (ROM/EPROM), kłopotliwe pierwsze uruchomienie systemu z pustą pamięcią błyskową oraz większe gabaryty i pobór mocy systemu. W opisanych dwóch wariantach połączeń mikrokontrolera z zewnętrzną pamięcią błyskową założono, że w systemie nie jest potrzebna zewnętrzna pamięć RAM. Jeśli zachodzi konieczność użycia takiej pamięci, należy zastosować połączenie mikrokontrolera z pamięciami według schematu z rysunku 7.22. Z zewnątrz dołączona jest pamięć danych SRAM o pojemności 8 kB, którą w razie potrzeby można powiększyć. Wewnętrzna pamięć EPROM/OTP w mikrokontrolerze jest w tej konfiguracji zbyteczna, wykorzystuje się więc tanią wersję mikrokontrolera (ROM-less). Po sygnale RESET lub po włączeniu zasilania uruchamiany jest program inicjujący, zapisany w pamięci błyskowej, ponieważ wejście EA znajduje się w stanie niskim. W pamięci tej umieszczony jest również program ładujący. Pamięć RAM jest „widziana" przez mikrokontroler podwójnie, zarówno w obszarze pamięci programu i danych, i jest umieszczona począwszy od adresu 20000H. Jeśli potrzebna jest zmiana (przeładowanie) zawartości pamięci błyskowej, program ładujący jest kopiowany do pamięci RAM i wykonywany. Po zmianie programu zapisanego w pamięci błyskowej należy, tak jak poprzednio, ponownie uruchomić program inicjujący (ang. re-boot), ale odbywa się to teraz z wykorzystaniem kodu nowego programu aplikacji i polega po prostu na wykonaniu instrukcji RESET (programowy sygnał RESET). Podobnie jak we wcześniej omawianej konfiguracji, jeśli potrzebne jest zastosowanie pamięci błyskowej lub SRAM o większej pojemności, można łatwo dodać kolejne układy, a wejścia wyboru układów CE sterować sygnałem A19 zamiast A17. 199 Rysunek 7.22. Współpraca mk 80C51 XA z zewnętrzną pamięcią błyskową i zewnętrzną pamięcią RAM Obszar pamięci RAM zostaje wówczas przesunięty do obszaru zaczynającego się od adresu 80000H. Tak samo jak w poprzednio omawianej konfiguracji, zapis do komórek pamięci błyskowej o adresach z przedziału OOOOH - 01FFH (XA G3) lub OOOOH - 03FFH (XAS3) jest możliwy tylko przy użyciu instrukcji MOVX. Zaletą metody współpracy z rysunku 7.22 jest prostota układu, niski koszt (mikrokontroler bez pamięci ROM), łatwość modyfikacji wektora przerwań w pamięci FLASH, ładowanie programów od adresu 0000H i prosta emulacja aplikacji. Wadą jest natomiast to, że pamięć RAM nie jest umieszczona od adresu 0000H, dlatego nie nadaje się do organizacji stosu. Podobnie jak we wcześniej omawianym wariancie kłopotliwe jest też pierwsze uruchomienie systemu Dostęp do pamięci FLASH przyłączonej do mikrokontrolera na jeden z wymienionych wyżej sposobów realizuje się łatwo przy użyciu odpowiednich procedur zapisanych w języku asemblera lub C. Do zapisu bajtu pod wskazany adres służy funkcja o następującej postaci (Philips): 200 Funkcja ZAPIS realizuje cykl zapisu zgodnie z formatem polecenia Byte w tablicy 7.2. Składa się z trzech cykli WR, cyklu zapisu danej do pamięci oraz sprawdzenia poprawności zapisu. Po wykonaniu procedury zwracana jest wartość 0, gdy programowanie zostało wykonane poprawnie, i wartość l, gdy wystąpił błąd. Kasowanie zawartości całej pamięci realizuje natomiast następująca procedura: 201 Z powyższych przykładów widać, że o ile kasowanie pamięci błyskowej przebiega sprawnie i wymaga jednego wywołania podanej wyżej procedury, o tyle programowanie jest bardziej czasochłonne, ponieważ po zapisie każdej danej należy wykonać sprawdzenie prawności zapisu. W przypadku kasowania sprawdzenie to jest wykonywane tylko raz po zakończeniu procedury kasowania całej pamięci. Mimo tej komplikacji oraz często bardziej złożonego połączenia pamięci błyskowych z mikrokontrolerem niż w przy-pamięci ROM/EPROM, pamięci błyskowe są coraz szerzej stosowane w systemach zawierających mikrokontrolery. Największą łatwość konfigurowania systemów z zewnętrznymi pamięciami, w tym również typu FLASH, zapewniają mikrokontrolery wyposażone w wyjścia wyboru układów współpracujących (CS). Na rysunku 7.23 przedstawiono przykład systemu z zewnętrzną pamięcią błyskową o organizacji 64k x 16 oraz z dwiema pamięciami SRAM o organizacji 32 k x 8. W systemie pracuje mikrokontroler z rodziny 60HC16 wyposażony w wyjście CSBOOT do aktywacji pamięci zawierającej program inicjujący oraz wyjścia CS do współpracy z pamięciami. Rysunek 7.23. Konfiguracja połączeń zewnętrznych pamięci SRAM i FLASH z mk 68HC16 wyposażonym w wyjścia wyboru CS W pamięci błyskowej umieszczony jest program inicjujący oraz dane. Odczyt i zapis przebiega słowami 16-bitowymi (wejście A0 pamięci jest połączone z linią adresową ADDR1). Dwie pamięci SRAM przechowują odpowiednio bardziej i mniej znaczącej bajty danych. Pierwsza z nich współpracuje z liniami danych DANE[15 : 8], a druga] z liniami DANE[7 : 0]. Wyborem obu pamięci sterują linie CS1 i CS2. Konfiguracja taka jest znacznie bardziej przejrzysta i prostsza przy programowaniu niż podane wcześniej konfiguracje połączeń dla mikrokontrolera XA. Wynika to przede wszystkim z możliwości użycia linii wyboru układów. 7.7. Bezpośredni dostęp do pamięci Bezpośredni dostęp do pamięci - DMA (ang. direct memory access) polega na wymianie informacji między pamięciami i urządzeniami zewnętrznymi bez udziału jednostki centralnej. Do realizacji trybu przesłań DMA wykorzystuje się mechanizm wstrzymań. Transmisja DMA jest obsługiwana przez specjalizowane zespoły funkcjonalne nazywane kontrolerami DMA lub w skrócie - DMAC (ang. DMA controller). Bloki DMAC mogą być wbudowane do mikrokontrolerów lub przyłączane z zewnątrz. 202 8. Mikrokontrolery DSP W układach mikroprocesorowych stosowanych obecnie szczególną rolę zajęły procesory sygnałowe DSP (ang. Digital Signal Processor). Są to układy zaprojektowane do obróbki w czasie rzeczywistym sygnałów cyfrowych. Najczęściej używaną funkcją procesorów DSP jest umiejętność wykonywania operacji mnożenia w jednym cyklu rozkazowym, jest to możliwe dzięki zastosowaniu sprzętowego układu mnożącego. Kolejną cechą procesorów DSP jest umiejętność kilkukrotnego dostępu do pamięci w jednym cyklu rozkazowym. Umożliwia to procesorowi ładowanie instrukcji równolegle z pobieraniem argumentów i/lub składowaniem w pamięci wyników poprzednich operacji. Trzecią funkcją używaną dla przyspieszenia operacji arytmetycznych w procesorach DSP jest specjalny układ generujący adresy. W chwili gdy zostaną odpowiednio skonfigurowane jego rejestry, rozpoczyna on pracę „w tle” (bez używania głównej magistrali), przygotowując adres wymagany do pobrania parametrów równolegle z wykonywaniem operacji arytmetycznej. Ponieważ wiele algorytmów DSP wykorzystuje wielokrotne, powtarzające się obliczenia, większość procesorów DSP umożliwia specjalne, efektywniejsze wykonywanie pętli. Pozwala to programiście na zaimplementowanie następnej pętli bez wykonywania dodatkowych cykli rozkazowych dla sprawdzenia i zmiany stanu licznika pętli lub utworzenia rozgałęzienia do początku istniejącej pętli. Tak wyposażone procesory, charakteryzują się ogromną szybkością działania i dużą mocą obliczeniową. 8.1. Stałoprzecinkowe DSP na przykładzie ADSP 2181 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 um. Wykorzystując zegar 33MHz wykonuje każdą instrukcję w pojedynczym cyklu procesora, tj. w czasie 30ns. Jest produkowany jest w obudowach TQFP i PQFP 128-pinowych. (W module EZ-Kit Lite zastosowano procesor z obudowę PQFP.)Struktura blokowa procesora została pokazana na rysunku 8.1. DATA ADDRESS GENERATORS Generatory Adresu Danych DAG1 DAG2 PROGRAM SEQUENCER POWERDOWN CONTROL PROGRAMOWALNE WE/WY WEWNĘTRZNA PAMIĘĆ FLAGI PAMOIĘĆ PAMOIĘĆ PROGRAMU 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 8.1. Budowa wewnętrzna procesora ADSP-2181 ADSP-2181 łączy bazową architekturę rodziny ADSP-21xx, na którą składają się: 203 - 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ę, denormali-zację 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ń - 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 (onchip) skonfigurowanej jako 48kB pamięci RAM programu oraz 32kB pamięci RAM danych umożliwia sprawne wykonywanie programu oraz obliczeń. 204 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 operacje 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 8.2.pokazuje budowę procesora ADSP-2181 w sposób bardziej szczegółowy, pozwalający na opisanie mechanizmów wymiany danych między jego elementami. 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 16 4 5 5 INTERRUPTS SZYNA R Rysunek 8.2. Budowa wewnętrzna procesora ADSP-2181 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) 205 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 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. 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ą, zew. szynę danych. Pamięć programu może przechowywać zarówno instrukcje jak i dane, pozwalając procesorowi ADSP-2181 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). ADSP-2181 ma możliwość adresowania 16K słów wewnętrznej pamięci programu RAM, co pozwala na dysponowanie pamięcią o wielkości 48Kbajty (3bajty • 16K=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 kontrolnych pinów. 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. ADSP-2181 zawiera dwa szeregowe porty (SPORT0 i SPORT1). Szeregowy port SPORT0 służy do przesyłania danych i komunikacji z innymi urządzeniami mającymi łącza szeregowe synchroniczne lub asynchroniczne. 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 206 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). Na rysunku 8.3 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 Rejestry te położone są pod adresami pokazanymi w poniższej tabeli. Tablica 8.1. Położenie rejestrów procesora ADSP 2181 Nazwa rejestru Adres Nazwa rejestru Sys_Crtl_Reg 0x3fff Sport0_Ctrl_Reg Dm_Wait_Reg 0x3ffe Sport0_Sclkdiv Tperiod_Reg 0x3ffd Sport0_Rfsdiv Tcount_Reg 0x3ffc Sport0_Autobuf_Ctrl Tscale_Reg 0x3ffb Sport1_Ctrl_Reg Sport0_Rx_Words1 0x3ffa Sport1_Sclkdiv Sport0_Rx_Words0 0x3ff9 Sport1_Rfsdiv Sport0_Tx_Words1 0x3ff8 Sport1_Autobuf_Ctrl Sport0_Tx_Words0 0x3ff7 Prog_Flag_Comp_Sel_Ctrl Prog_Flag_Data 0x3fe5 BDMA_External_Address BDMA_Word_Count 0x3fe4 BDMA_Internal_Address BDMA_Control 0x3fe3 IDMA_Control Pokazane wartości rejestrów są wartościami obowiązującymi po resecie procesora. 207 Adres 0x3ff6 0x3ff5 0x3ff4 0x3ff3 0x3ff2 0x3ff1 0x3ff0 0x3fef 0x3fe6 0x3fe2 0x3fe1 0x3fe0 Rysunek 8.3. Rejestry procesora ADSP-2181 208 8.2. Zmiennoprzecinkowe DSP na przykładzie ADSP-21061 SHARC Procesor ADSP-21061 SHARC – Super Harvard Architecture Computer – jest nowoczesnym 32-bitowm mikrokomputerem jednoukładowym specjalizowanym do przetwarzania sygnałów cyfrowych (Digital Signal Processor). Może być wykorzystywany do przetwarzania mowy, dźwięku, grafiki czy obrazu. Został on zaprojektowany i wykonany w oparciu o nowoczesny rdzeń zmiennoprzecinkowy i uzupełniony dwuportową pamięcią SRAM oraz obsługą zintegrowanej magistrali I/O. Dzięki zawartej w strukturze procesora pamięci „cache” oraz specjalnej architekturze, możliwe jest wykonywanie wszystkich instrukcji w pojedynczym cyklu. Architektura Super Harvard jaką wykorzystano do budowy procesora ADSP-21061 charakteryzuje się rozdzieleniem pamięci programu i pamięci danych, co umożliwia równoczesne pobieranie instrukcji i operandów, a w efekcie przyspiesza pracę procesora. Do poprawnej pracy takiego układu wymagane są cztery niezależne magistrale: adresowa pamięci programu PMA Bus (24-bit), danych pamięci programu PMD Bus (48-bit), adresowa pamięci danych DMA Bus (32-bit) oraz danych pamięci danych DMD Bus (40-bit). Procesor taktowany jest zewnętrznym sygnałem zegarowym o częstotliwości 40 MHz, co przy zastosowaniu opisywanej wyżej architektury oraz umieszczonych w rdzeniu procesora trzech niezależnych, pracujących równolegle jednostkach liczących, pozwala osiągnąć szybkość przetwarzania 40 MIPS oraz szybkości obliczeń: średnio 80 MFLOPS i maksymalnie 120 MFLOPS. Czas wykonywania jednej instrukcji wynosi 25 ns. Procesor posiada 1 Mbit wewnętrznej pamięci SRAM oraz 32Ksłów pamięci „cache”, dwa porty szeregowe synchroniczne mogące przesyłać dane z prędkością 40 Mbit/s oraz zewnętrzną szynę danych i szynę sterującą, pozwalające na równoległą pracę sześciu procesorów z dostępem do zewnętrznej pamięci danych lub do wewnętrznej pamięci każdego ze współpracujących procesorów. Procesor oferuje dwa tryby pracy ograniczające pobór mocy: idle oraz idle16. W trybie idle procesor oczekuje przez nieograniczony czas, ze zmniejszonym poborem mocy, na przyjście niemaskowanego przerwania natomiast w trybie idle16 dodatkowo jest spowalniany wewnętrzny zegar procesora do 1/16 częstotliwości podstawowej co jeszcze bardziej ogranicza pobór energii. W trybie idle16 przerwania są obsługiwane 16 razy wolniej. Budowa wewnętrzna procesora Struktura wewnętrzna procesora zawiera: - trzy niezależne jednostki obliczeniowe, pracujące równo-legle, wykonujące operacje zmiennoprzecinkowe na danych 32-bitowych pojedynczej prec-yzji lub 40-bitowych rozszerzo-nej precyzji, są to: ALU, multiplier i shifter; - zbiór rejestrów wymiany danych (Data Register File); - dwa generatory adresu (DAG1, DAG2); - sekwenser programu z pamięcią podręczną (Program Sequencer) ; - timer; - dwuportową pamięć SRAM (Dual-Ported SRAM); - dodatkowy port do komunikacji z zewnętrzną pamięcią i peryferiami (External Port); - interfejs współpracy z innymi procesorami (Multiprocessor Interface); - sterownik kanałów DMA (DMA Controller); - dwa porty szeregowe (Serial Ports); - port testujący (JTAG). 209 INSTRUCTION TIMER CACHE 32 x 48-Bit BLOCK 0 BLOCK 1 Dual-Ported SRAM AAAAA Core Processor AAAAAAA JTAG 7 Test & Emulation DAG 1 8 x 4 x 32 PROCESSOR PORT PROGRAM DAG 2 8 x 4 x 24 SEQUENCER I/O PORT AAAAAAA AA A IOD 48 PM Address Bus (PMA) 24 External Port IOA 17 PMA 32 EPA DM Address Bus (DMA) 32 DMA MULTIPROCESSOR PM Data Bus (PMD) Bus INTERFACE 48 PMD Connec t DM Data Bus (DMD) (PX) 48 EPD DMD 32/40 HOST INTERFACE A BARREL SHIFTER IOA 16 x 40-Bit EPA DATA REGISTER FILE IOD EPD DMD PMD A AA A MULTIPLIER DMA 4 CONTROLLER IOP REGISTERS ALU 6 SERIAL PORTS (2) 6 I/O Processor Rysunek 8.4. Schemat blokowy procesora Jednostka ALU (ang. Arithmetic/Logic Unit) jest odpowiedzialna za wykonywanie standardowych operacji arytmetycznych i logicznych. Multiplier wykonuje w jednym cyklu procesora operacje: mnożenia, mnożenia/dodawania, mnożenia/odejmowania. Shifter wykonuje arytmetyczne przesunięcie, normalizację, denormalizację, wyprowadzanie wykładnika potęgi oraz operacje na bitach: ustawianie, zerowanie, zmianę stanu, testowanie. Zbiór rejestrów wymiany danych jest zestawem rejestrów, przy pomocy których odbywa się wymiana danych między jednostkami obliczeniowymi i szynami danych. Generatory adresów dostarczają adresy niezbędne do równoczesnego pobrania instrukcji z pamięci programu oraz argumentu z pamięci danych. Generatory adresu umożliwiają adresowanie liniowe i kołowe. Sekwenser programu przy pomocy generatora adresów zapewnia sprawne dostarczanie argumentów operacji do jednostek obliczeniowych. Sekwenser inicjuje skoki warunkowe, wywołanie podprogramów oraz powroty w pojedynczym cyklu. Dzięki niemu możliwe jest wykonywanie pętli bez sprecyzowanych instrukcji skoku. Sekwenser jest wykorzystywany także w czasie obsługi przerwań oraz trybu bezczynności (idle). Pamięć podręczna “cache” ma rozmiar 32 Ksłów i sekwenser korzysta z niej w przypadku operacji powtarzających się. Takie zachowanie powoduje, że układ nie musi pobierać kolejnych instrukcji z pamięci programu lecz możne je pobrać z szybszej pamięci podręcznej. Programowalny timer dostarcza cyklicznych przerwań, rejestr licznika jest automatycznie przeładowywany po każdym zakończeniu liczenia. 210 Dwuportowa pamięć SRAM o pojemności 1Mbit jest skonfigurowana w dwa bloki po 0,5Mbit z możliwością niezależnego dostępu przez rdzeń procesora, sterownik I/O lub sterownik DMA. Dwuportowa organizacja pamięci i oddzielne magistrale wewnętrzne pozwalają na dwa transfery danych z rdzenia oraz jeden z układu I/O w jednym cyklu procesora. Zastosowanie w procesorze dodatkowego portu do komunikacji z pamięcią zewnętrzną i peryferiami umożliwia zaadresowanie do 4-giga słów pamięci zewnętrznej. Port ten integruje wewnętrzne magistrale adresowe i danych w jedną 32-bitową magistralę adresową oraz jedną 48bitową magistralę danych. Interfejs współpracy z innymi procesorami umożliwia połączenie ze sobą do sześciu procesorów mogących równolegle wykonywać operacje (możliwość ta może być wykorzystana przy skomplikowanych algorytmach). Wszystkie połączone ze sobą jednostki mają możliwość dostępu do jednej wspólnej pamięci zewnętrznej oraz swoich pamięci wewnętrznych. Wymiana danych między procesorami może odbywać się z prędkością do 240 Mbit/s. Sterownik DMA umożliwia bezpośredni transfer danych bez zaangażowania procesora. Sterownik pracuje niezależnie i niewidocznie dla rdzenia procesora gdy ten w tym czasie wykonuje program. Kanały DMA pośredniczą w transferze między pamięcią wewnętrzną i zewnętrzną oraz peryferiami, a także między pamięcią wewnętrzną i portami szeregowymi. Do komunikacji z innymi układami procesor może wykorzystywać dwa synchroniczne porty szeregowe. Taktowanie procesora z pełną prędkością pozwala na przesyłanie danych przez porty szeregowe z szybkością do 40 Mbit/s. Niezależne funkcje odbioru i wysyłania pozwalają na bardzo elastyczne użytkowanie portów szeregowych. Mogą one również automatycznie przesyłać dane do i z- pamięci zewnętrznej przez kanał DMA. Możliwe jest synchronizowanie portów za pomocą sygnałów generowanych przez procesor lub sygnały zewnętrznie. 211 9. Programowanie mikrokontrolerów W odróżnieniu od programowania komputerów do zadań związanych z przetwarzaniem i archiwizacją danych (obliczenia numeryczne, bazy danych, edycja tekstów itp.), programowanie sterowników z wbudowanymi mikrokontrolerami jest znacznie ściślej związane z architekturą samego procesora i jego sprzętowego otoczenia. W ostatnich latach nastąpił w tej dziedzinie znaczny postęp. Język asemblera, aczkolwiek wciąż niezbędny w wielu zastosowaniach, jest stopniowo wypierany przez języki C/C++. Do programowania mikrokontrolerów zaczęto też używać języka Java opracowanego przez Sun ticrosystems do tworzenia przenośnych aplikacji. Dużym ułatwieniem dla programistów mikrokontrolerów jest popularyzacja językówów C i C++. Kompilatory tych języków są dziś dostępne dla praktycznie wszystkich produkowanych typów mikrokontrolerów. Mimo znacznego postępu w zakresie optymalizacji kodu programu produkowanego przez kompilatory C/C++, języki te wciąż są mniej efektywne od asemblerów. Jeśli zatem warunki pracy systemu w czasie rzeczywistym narzucają szczególnie krytyczne wymagania wobec szybkości działania programu, język asemblera jest niezastąpiony. Połączenie zalet programowania w języku asemblera z korzyściami, jakie daje język wysokiego poziomu jest możliwe przy zastosowaniu mieszanych technik programowania, w których newralgiczne fragmenty programu projektuje się w języku asemblera, a pozostałą część programu w języku C/C++. W niniejszym rozdziale przedstawiono zarys problemów związanych z wykorzystaniem obu tych języków, przy czym założono, że Czytelnik zna podstawy programowania w języku C/C++. Ponieważ, jak powiedziano wcześniej, o programowaniu mikrokontrolerów nie można mówić w oderwaniu od ich architektury, w podanych dalej przykładach posłużono się głównie architekturą popularnej rodziny układów x51. 9.1. Programowanie w języku asemblera Programowanie w języku asemblera stosuje się w trzech przypadkach: 1) gdy tworzona aplikacja jest bardzo prosta i zapis w języku asemblera nie sprawia kłopotu, 2) gdy nie dysponujemy kompilatorem C/C++ lub jego koszt byłby niewspółmierny do skali projektu i 3) gdy wymagania wobec szybkości działania programu i minimalizacji zajmowanej pamięci są szczególnie ostre. Do zalet programowania w języku asemblera należy zaliczyć: 1) możliwość pełnego panowania nad zasobami systemu; programista ma nieograniczony dostęp do wszystkich bloków na poziomie rejestrów i pojedynczych bitów; żadna z funkcji systemu nie jest ukryta; w szczególności możliwe jest dowolne, nawet nietypowe oddziaływanie na obszar stosu i mechanizm przerwań, 2) swobodne dysponowanie obszarem pamięci, 3) efektywny program wynikowy; szybszy i zajmujący na ogół znacznie mniej pamięci niż równoważny program zapisany w języku wysokiego poziomu, 4) możliwość swobodnego wyboru formatu danych i precyzji obliczeń; programista może samodzielnie definiować wielobajtowe struktury danych do obliczeń o praktycznie dowolnej dokładności, 5) możliwość dopasowania algorytmu do indywidualnych cech architektury mik kontrolera oraz optymalizacji programu wynikowego. Niestety, zastosowanie asemblera ma też i wady. Programowanie jest żmudne i zajmuje więcej czasu niż przy użyciu języków wysokiego poziomu. Program jest zatem droższy, trudniejszy do modyfikowania, bardziej podatny na błędy i mniej czytelny, nawet jeśli zastosowano obszerne komentarze. Projektowanie oprogramowania w języku asemblera przebiega według schematu przedstawionego na rysunku 9.1. 212 Rysunek 9.1. Cykl projektowania oprogramowania w języku asemblera W większości przypadków wykorzystuje się w tym celu komputer PC. Programy edytora, asemblera, program łącząco-ładujący (ang. linking-\-loader) i śledzący (debuger) są instalowane w PC albo jako oddzielne aplikacje DOS, lub Unix, albo też jako zintegrowane środowisko projektowe IDE (ang. inte\grated development emironment). Do edycji programów źródłowych zapisanych w plikach tekstowych ASCII można użyć dowolnego, prostego edytora dostarczanego na przykład wraz z systemami operacyjnymi. Otrzymany w wyniku edycji program źródłowy jest poddawany tłumaczeniu (czyli translacji lub asemblacji). W rezultacie powstają dwa nowe pliki dyskowe: 1) Program wynikowy (ang. objęci code), który jest zapisany w postaci dwójkowej, nie nadaje się jednak jeszcze do załadowania do pamięci mikrokontrolera i wykonania. Program wynikowy zapisany w pliku OBJ jest przemieszczalny (relokowalny - ang. relocatable code), to znaczy może być przypisany do ustalonego później obszaru adresowego pamięci. 2) Plik tekstowy z raportem translacji i wydrukiem programu źródłowego z towarzyszącym mu kodem wynikowym (zazwyczaj w postaci szesnastkowej). Raport z translacji (ang. listing fiie) podaje ponadto numery i adresy kolejnych linii (instrukcji) programu, adresy zadeklarowanych zmiennych, zestawienie użytych nazw symbolicznych oraz ewentualnie komunikaty o błędach. Pliki źródłowy, wynikowy i listing mogą mieć dowolne nazwy i rozszerzenia, najczęściej jednak nadaje się im tę samą nazwę (np. PROJEKT1) i standardowe rozszerzenia: ASM plik z tekstem programu źródłowego, OBJ plik z programem wynikowym, LST plik zawierający raport z translacji wraz z wydrukiem programu. 213 Po uzyskaniu programu wynikowego wolnego od błędów translacji następuje faza łączenia programu (konsolidacji). W fazie tej wykonuje się połączenie modułów wynikowych (jeśli program został zapisany w kilku plikach OBJ), dołączenie modułów bibliotecznych (jeśli zostały użyte w programie) oraz uzgodnienie adresów modułów. •W rezultacie na dysku komputera PC powstaje zapis nie przemieszczalnego programu dwójkowego (ang. non-relocatable code), który można załadować do pamięci systemu [mikroprocesorowego i uruchomić. Format dyskowego pliku z programem ładowalnym zależy od typu procesora i użytego środowiska IDE. Jednym z najszerzej rozpowszechnionych formatów jest format HEX opracowany przez firmę Intel. Plik z rozszerzeniem |HEX przechowuje kody instrukcji i dane (stałe) w postaci ciągu rekordów zapisanych |w kodzie ASCII. Każdy z rekordów ma stały format: :llaaaatt[dd....]cc przy czym znaczenie użytych symboli jest następujące: : znak dwukropka, identyfikator początku każdego nowego rekordu, ll długość pola danych (dd. . . .) wyrażona w bajtach, aaaa 16-bitowy adres miejsca pamięci, do którego mają być załadowane dane zapisane w rekordzie, tt kod typu rekordu: 00 oznacza rekord danych, 01 oznacza rekord terminalny (kończący plik HEX), dd ciąg bajtów danych, cc suma kontrolna obliczana jako różnica: OOH - (suma wszystkich bajtów rekordu) mod 256. W asemblerach firmy Motorola stosuje się jednocześnie z formatem HEX własny firmowy format S (ang. S-record file). Budowa rekordu S jest podobna do budowy kodu HEX, jednak kolejność pól jest nieco inna. Najpierw podawany jest dwuznakowy typ rekordu złożony ze znaku S i cyfry 0-9, potem dwuznakowa liczba oznaczająca liczbę par bajtów w całym rekordzie z wyłączeniem pola typu i długości, dalej 4-, 6- li 8-znakowy adres pamięci, w-znakowe pole danych lub kodu programu i wreszcie dv znakowa suma kontrolna. Rekord typu SO jest nagłówkiem zaczynającym plik S. Po stawowym typem rekordu danych lub programu jest typ Sl, natomiast rekord typu S9 kończy plik rekordów. Podczas ładowania programu z pliku HEX (lub S) do pamięci systemu wykonywane jest rozpakowanie kolejnych rekordów, sprawdzenie sumy kontrolnej oraz przesłanie pola danych pod wskazany adres. Po załadowaniu program jest gotowy do uruchomienia, Testowanie programu jest wykonywane pod nadzorem programu śledzącego. W początkowej fazie korzysta się przy tym z trybu pracy krokowej lub z systemu pułapek (punktów zatrzymań) ulokowanych w zadanych miejscach programu. Śledzenie pracy programu polega na sprawdzaniu zawartości rejestrów i wybranych komórek pamięci w kolejnych fazach wykonywania programu. Jeśli zawartości te zmieniają się zgodnie z założeniami projektowymi, a przyłączone do systemu urządzenia peryferyjne pracują również zgodnie z oczekiwaniami, uruchamianie programu jest zakończone. Ważnymi aspektem etapu testowania aplikacji jest określenie zbioru warunków testowych (danych wejściowych i sygnałów z urządzeń zewnętrznych), które wyczerpują przestrzeń stanów sterowania systemu. 9.1.1. Asemblery i makroasemblery Wyróżnia się dwa rodzaje programów tłumaczących programy źródłowe zapisane w języku asemblera: proste asemblery oraz makroasemblery. Obydwa rodzaje programów łumaczących mają wspólne cechy w zakresie podstawowych funkcji związanych z translacją: generują kod programu wynikowego i produkują raport z przebiegu translacji. Sterowanie przebiegiem translacji w przypadku prostych asemblerów pracujących w środowisku DOS odbywa się przez podanie parametrów (przełączników). W ten sposób określa się na przykład czy ma być generowany raport (L), czy też nie 214 (-L). W przypadku asemblerów pracujących w graficznym środowisku IDE parametry te ustala siej w zbiorze opcji asemblera, stosując system list dialogowych Windows. Oprócz znakowego zapisu kolejnych instrukcji programu, plik źródłowy zawiera komentarze oraz dyrektywy asemblera, które same nie zostają przetłumaczone na kod wynikowy, ale mają wpływ na proces tłumaczenia. Poniżej podano podstawowe dyrektywy stosowane w większości asemblerów oraz przykłady ich użycia: PARAMETR1 EQU 23H Dyrektywa equ (ang. equate) definiuje stałą o zadanej nazwie (w powyższym przykładzie parametr1) i nadaje jej wyspecyfikowaną wartość (23H). Należy wyraźnie zaznaczyć, że definicja stałej nie oznacza rezerwacji pamięci, zatem obiekt zdefiniowany dyrektywą EQU istnieje tylko podczas translacji i znika po jej zakończeniu. Stała zdefiniowana dyrektywą EQU może być używana bez ograniczeń, poczynając od miejsca, w którym została zdefiniowana. Jeśli na przykład w programie zostanie zapisana instrukcja: MOV A,#PARAMETR1 to asembler przetłumaczy ją jako MOV A,#23H, czyli zastąpi symboliczną nazwę PARAMETR1 przez nadaną jej wcześniej wartość 23H. Podobnie, definicja stałej o postaci: Adres_bazowy_PIO EQU 50FFH spowoduje, że po napotkaniu instrukcji ładowania rejestru MOV DPTR,#Adres_bazowy_PIO asembler wygeneruje kod odpowiadający instrukcji: MOV DPTR,#50FFH. Stałe mogą być definiowane, przy użyciu wszystkich zapisów liczbowych dopuszczanych przez asembler, a więc zwykle w postaci dziesiętnej, szesnastkowej i dwójkowej. Ponadto większość asemblerów dopuszcza w definicji stałej użycie prostych wyrażeń. Dla przykładu zapis: Rejestr_CTRL EQU Adres_bazowy_PIO+3 poprzedzony podaną wcześniej definicją stałej o nazwie Adres bazowy PIO spowoduje zdefiniowanie stałej o nazwie Rejestr_CTRL i nadanie jej wartości 5102H. Używanie stałych symbolicznych zamiast stałych liczbowych jest zalecane jako • jedna z podstawowych reguł programowania w języku asemblera. Odpowiednio dobrane nazwy radykalnie poprawiają czytelność programu, a ponadto w razie konieczności zmiany stałej wystarczy zmodyfikować jedną linię programu (i oczywiście powtórnie wykonać asemblację), zamiast modyfikować wszystkie instrukcje, w których użyto stałej liczbowej. Do deklarowania zmiennych używa się dyrektyw DB (ang. defme bytes) oraz DW (ang. defme words). Niefortunne użycie słowa defme w terminologii angielskiej nie powinno wywołać mylnego przekonania, że chodzi tu o podobną definicję, jak w przypadku stałych. Dyrektywy DB i DW faktycznie rezerwują miejsce w pamięci danych, powstają zatem obiekty, które będą istniały w czasie wykonywania programu. Deklaracje zmiennych mogą być użyte tylko do rezerwacji miejsca w pamięci dla zmiennych o podanych nazwach symbolicznych albo jednocześnie do nadania im określonych wartości początkowych. Przykładowy zapis: X1: DB 3FH,21,0FH Y1: DW 3FFFH rezerwuje trzybajtową zmienną xi i nadaje kolejnym bajtom wartości dziesiętne 63, 21 i 15 oraz zmienną Y o rozmiarze słowa i wartości początkowej 3FFFH. Większość asemblerów dopuszcza ponadto deklarowanie łańcuchów znakowych. Na przykład deklaracja NAPIS DB "to jest napis" deklaruje łańcuch o nazwie NAPIS i treści TO JEST NAPIS. Jednym z zadań programisty piszącego program w języku asemblera jest zaplanowanie rozmieszczenia poszczególnych fragmentów programu w pamięci. W zależności od rodzaju asemblera służą do tego różne dyrektywy. Najczęściej spotykana jest dyrektywą ORG (ang. 215 originate), która wskazuje asemblerowi, że następujące po niej instrukcje programu (lub dane zadeklarowane dyrektywami DB bądź DW) mają być umieszczone w kolejnych komórkach pamięci od wskazanego adresu. Przykładowy zapis: ORG 200H START: CLR A spowoduje, że kod instrukcji CLR A opatrzonej etykietą START zostanie umieszczony\ w komórce o adresie 2000H, natomiast sekwencja: ORG 0EFH DB 1AH zainicjuje komórkę (rejestr) o adresie EFH, wpisując do niej wartość 1AH. Większość asemblerów dopuszcza ponadto inne sposoby definiowania obszarów adresowych danych i programu. Dla przykładu zapis CSEG AT 1OOOH oznacza, że program (ang. code segment) następujący po tej dyrektywie będzie lokowany począwszy od adresu 1000H, natomiast zapis TABLICA DATA 3000H deklaruje wektor o nazwie TABLICA umieszczony począwszy od adresu 3000H. Możliwe jest też definiowanie segmentów danych w pamięci wewnętrznej (DSEG) i zewnętrznej (XSEG), obszarów adresowanych bitowo (BSEG) i obszarów relokowalnych (RSEG). Jeśli program jest zapisany modularnie, w kilku plikach OBJ, udostępnianiem procedur sterują dyrektywy: PUBLIC EXTERN. Ostatnią linią programu źródłowego powinna być dyrektywa END. Operatory, wyrażenia, stałe W zapisie programu źródłowego dozwolone jest używanie prostych operatorów, wyrażeń i stałych. Zbiór operatorów i symbole używane do ich oznaczania są różne dla różnych asemblerów. Przykładem typowej symboliki operatorów jest notacja stosowana w asemblerach firmy Motorola, w których dopuszcza się użycie następujących operacji: * mnożenie / dzielenie + dodawanie odejmowanie < przesunięcie w lewo > przesunięcie w prawo % reszta z dzielenia & iloczyn logiczny | suma logiczna ^ suma modulo 2 Korzystanie z operatorów jest dozwolone przy zapisie dowolnych argumentów, zarówno danych, jak i adresów. Dla przykładu instrukcje: JMP PROC1+5 MOV A,#Dana S. ICH spowodują odpowiednio skok do adresu PROC1+3 oraz załadowanie do akumulatora liczby będącej iloczynem logicznym stałej „Dana” oraz stałej ICH. Specjalnym przypadkiem operatorów jest symbol „$" (oraz w niektórych asemblerach równoważny mu symbol gwiazdki „*"), który oznacza aktualną zawartość licznika programu. Instrukcje o postaci: JMP $ JMP $-5 oznaczają zatem odpowiednio: „skocz na siebie" (w tym przypadku jest to nieskończona pętla) oraz „skocz o 5 bajtów wstecz". 216 Każdy z asemblerów wykorzystuje domyślną podstawę zapisu stałych. W przypadku asemblerów firmy Motorola i niektórych asemblerów firmy Intel (np. dla procesorów x86) jako domyślny jest przyjmowany zapis szesnastkowy, dlatego liczba 15 bez żadnych dodatkowych symboli oznacza wartość 15H, czyli 21 w kodzie dziesiętnym. W innych asemblerach, na przykład x51, domyślny jest zapis dziesiętny. Zmianę domyślnej pod stawy zapisu stałych umożliwia system przedrostków (ang. prefix) oraz przyrostków i (ang. suffix). Pisanie programów w językach różnych asemblerów utrudnia to, że stosuje się w nich różne symbole przedrostków i przyrostków. W notacji firmy Intel przyrostki dla liczb dwójkowych, ósemkowych, dziesiętnych i szesnastkowych mają odpowiednio 1 symbole B, O (lub Q), D oraz H, natomiast w notacji firmy Motorola są oznaczane symbolami Q, O, T i H. Asemblacja warunkowa i procesor makrodefinicji Opisane wcześniej dyrektywy są słowami zarezerwowanymi i nic muszą być poprzedzone w programie żadnym znakiem specjalnym pełniącym rolę wyróżnika dyrektywy. Pozostałe dyrektywy wyróżnia się natomiast znakiem „S". Wśród dyrektyw tego typu znajdują się między innymi dyrektywy sterujące postacią raportu z translacji oraz warunkowym tłumaczeniem fragmentów programu. Warunkowe tłumaczenie programu polega na możliwości zdefiniowania sekcji programu źródłowego, które będą tłumaczone na kod wynikowy tylko wtedy, gdy jest spełniony określony warunek zadany w postaci wyrażenia boolowskiego. Sekcja taka ma postać: Dzięki translacji warunkowej można tworzyć uniwersalne programy źródłowe, które w zależności od sposobu zdefiniowania zmiennych sterujących warunkami będą miały różną postać wynikową. Do zapisu warunków używa się meta-zmiennych, operatorów i stałych. Meta-zmienne są definiowane przy użyciu dyrektywy SET. Dla przykładu zapis:! $ SET (VAR1, VAR2 = 3, VAR3) definiuje zmienne o nazwach VAR1, VAR2 i VAR3. Początkowa wartość zmiennej VAR2 jest równa 3, natomiast zmienne VAR1 i VAR3 przyjmą domyślne wartości OFFFFH. Dyrektywa RESET zeruje zmienne. Na przykład zapis: $ RESET (VARl, VAR2) spowoduje wyzerowanie zmiennych VAR1 i VAR2. Wyrażenie boolowskie złożone z metazmiennych, operatorów i stałych jest spełnione (prawdziwe), jeśli jego wartość jest różna od zera. W przeciwnym przypadku wyrażenie jest fałszywe. Zasadniczą cechą, która wyróżnia makroasemblery od prostych asemblerów jest wbudowany preprocesor makrodefinicji i makrowywołań. Początek makrodefinicji oznacza dyrektywa MACRO, natomiast koniec - dyrektywa ENDM. Dla przykładu, sekwencja o postaci: DODAJ MACRO PAR1, PAR2 MOV A,#PAR1 217 ADD A,#PAR2 ENDM jest makrodefinicją o nazwie DODAJ, która dodaje do siebie parametry PAR1 i PAR2, przy czym wynik jest umieszczony w akumulatorze. Jeśli po powyższej makrodefinicji w pro gramie nastąpi makrowywołanie, na przykład w postaci linii: DODAJ 20H, 7 to preprocesor makro zastąpi ją tekstem źródłowym: MOV A,#20H ADD A,#7 Należy zwrócić uwagę, że obsługa makrowywołań przez preprocesor odbywa się na poziomie kodu programu źródłowego. Zatem mimo pewnego podobieństwa mechanizmu makrowywołań do mechanizmu wywołań podprogramów (procedur) efekt obu tych technik programowania jest inny. Podprogram rezyduje w programie wynikowym tylko w jednym egzemplarzu, a każde jego wywołanie powoduje zapamiętanie adresu powrotu na stosie, skok do podprogramu, wykonanie jego treści i powrót do zapamiętanego adresu. W przypadku każdego makrowywołania w programie wynikowym pojawia się nowa kopia przetłumaczonej na kod wynikowy makrodefinicji, z uwzględnieniem aktualnych parametrów makrowywołania. Skok i zapamiętanie adresu powrotu nie jest więc konieczne, dzięki czemu makrowywołanie wykonuje się szybciej od równoważnego podprogramu. Wadą makrowywołań jest natomiast większa zajętość pamięci, ponieważ każde makrowywołanie generuje w programie wynikowym kopię kodu makrodefinicji. Używanie makrodefinicji i makrowywołań jest zalecane, ponieważ poprawia czytelność programu. Należy je stosować przede wszystkim w przypadku krótkich sekwencji instrukcji, powtarzanych w programie z różnymi argumentami oraz w sytuacjach, gdy szybkość działania programu jest istotna. W przypadku długich, często wywoływanych procedur lepiej stosować jest podprogramy, zwłaszcza gdy system ma niewielką pamięć. Szczególnym przykładem akcji preprocesora makro, jest obsługa dyrektywy REPT, która ; służy do powielania ciągu instrukcji. Przykładowy zapis: REPT 3 INC DPTR ENDM spowoduje, że w programie źródłowym preprocesor wstawi trzykrotnie powieloną instrukcję inkrementacji rejestru wskaźnika danych DPTR: INC DPTR INC DPTR INC DPTR W praktycznie implementowanych preprocesorach makro spotyka się ponadto dodatkowe funkcje, umożliwiające między innymi zagnieżdżanie się makrodefinicji oraz bardziej wszechstronne sposoby przekazywania parametrów. 9.1.2. Przykłady Makroasemblerów Większość dostępnych asemblerów i makroasemblerów wykonuje tłumaczenie programu źródłowego w dwóch przebiegach (ang. two-pass assembly), co oznacza że program jest analizowany dwukrotnie. W pierwszym przebiegu tłumaczone są instrukcje, które nie zawierają argumentów symbolicznych (stałych i zmiennych symbolicznych oraz etykiet). Równocześnie ascmblcr buduje tablicę symboli (ang. symbol table), w której notuje s wszystkie napotkane definicje symboli i ich wartości. Po zakończeniu pierwszego przebiegu następuje drugi przebieg, polegający na uzupełnieniu wartości argumentów symbolicznych w programie wynikowym. W podanym poniżej przykładzie przedstawiono wydruk raportu translacji uzyskany w wyniku tłumaczenia prostego programu testującego. Wydruk raportu z translacji popularnego makroasemblera A51 (Keil), przeznaczonego dla mikrokontrolerów rodziny x51 pokazuje rys. 9.2. 218 Rysunek 9.2. Wydruk raportu makroasemblera A51 W podanym niżej przykładzie program o nazwie TRANS wysyła ciąg znaków ASCII przez port szeregowy UART. Ciąg jest zdefiniowany przy użyciu dyrektywy DB i oznaczony symboliczną nazwą KOM. Koniec łańcucha znaków tworzącego tekst określa znak terminalny, którym w podanym przykładzie jest znak EOT (04H). W celu zilustrowania działania dyrektyw PUBLIC i EXTRN założono, że procedura SEND realizująca wysyłanie pojedynczego bajtu przez port UART jest zdefiniowana w innym module wynikowym programu. Wydruk raportu translacji omawianego programu ma następującą postać: Treść pliku źródłowego zawierającego procedurę transmisji zaczyna się od dyrektywy NAME, która nadaje modułowi wynikowemu nazwę TRANS wykorzystywaną później w procesie łączenia modułów. Stała RATĘ oznacza szybkość transmisji w porcie UARTJ i jest określona na podstawie częstotliwości zegara, zgodnie z danymi katalogowymi mikrokontrolera x51. Kolejna dyrektywa EXTRN wskazuje makroasemblerowi, że procedura SEND wywoływana w treści modułu jest zdefiniowana w innym module i należy ją dołączyć później. Adres początkowy START modułu TRANS jest udostępniany na zewnątrz j przy użyciu dyrektywy PUBLIC, zatem z procedury transmisji mogą korzystać inne moduły wynikowe, oczywiście pod warunkiem, że zawierają odpowiednią dyrektywę EXTRN. Program jest przetłumaczony jako moduł relokowalny, ponieważ zastosowano dyrektywę RS EG. Właściwy program zaczyna się od ustawienia trybu pracy portu UART i uruchomienia licznika T1 użytego do taktowania transmisji. Następnie pobierane są kolejne bajty komunikatu tekstowego z pola danych o nazwie KOM i wysyłane przez port UART przy użyciu zewnętrznej procedury SEND. Po wysłaniu każdego znaku następuje sprawdzenie, czy wysłany znak jest znakiem terminalnym. Jeśli tak, procedura kończy się (RET), natomiast w przeciwnym przypadku następuje skok do etykiety NEXT i wysłanie kolejnego znaku. Należy zwrócić uwagę, że pobieranie kolejnych znaków jest wykonywane przy użyciu rozkazu MOVC, który w mikrokontrolerach x51 umożliwia dostęp do pamięci programu. Adres bajtu jest obliczany jako suma zawartości akumulatora (w podanym przykładzie zawsze zero) oraz rejestru wskaźnika DPTR, który po wysłaniu każdego znaku jest inkrementowany rozkazem INC . 219 Aby program działał poprawnie, zewnętrzna procedura SEND nic może zmieniać zawartości akumulatora i rejestru DPTR. W liniach, w których występują odwołania do procedury SEND (linia 14) i pola danych KOM (linia 17), asembler podał dodatkowy symbol F, oznaczający, że część adresowa instrukcji jest wyrażeniem relokowalnym i musi być uzupełniona w fazie łączenia modułów. Tymczasowo część adresowa tych instrukcji jest wypełniona zerami. 9.1.3. Przykłady programów asemblera Weźmy pod uwagę układ sterowania wyświetlaczami 7-segmentowymi, którego uproszczony schemat przedstawiono na rysunku 9.3. Zastosowano w nim mikrokontroler x51 sprzężony z programowanym układem wejścia /wyjścia PIO oraz, sześć identycznych wyświetlaczy. Załóżmy, że dekoder adresowy narysowany w postaci zamkniętego bloku generuje sygnał CS wybierający układ PIO, jeśli na szynie adresowej mikrokontrolera pojawi się adres 800xH. Rejestr PA układu 8255 ma wówczas adres 8000H, rejestr PI3 – adres 8001H, rejestr PC - adres 8002H, natomiast rejestr kontrolny - adres 8003H. System sterowania zastosowany w układzie z rysunku 9.3 jest systemem dynamicznym, ponieważ w danej chwili aktywny jest tylko jeden wyświetlacz. Wyświetlanie informacji na kilku wyświetlaczach wymaga więc ich okresowego pobudzania przez mikrokontroler. Dane dla wyświetlaczy są przesyłane przez port PB ustawiony jako wyjście. Rysunek 9.3. Uproszczony schemat układu sterowania wyświetlaczami 7-segmentowymi Port A nie jest wykorzystywany, natomiast bardziej znaczące cztery bity portu PC służą do wyboru wyświetlacza, na którym ma się pojawić informacja wysłana przez port PB. Porty PCH i PB powinny być zatem ustawione jako wyjścia pracujące w trybie 0, natomiast konfiguracja portów PA i PCL jest nieistotna. Cykl wyświetlania informacji przebiega w następujący sposób: 1) Mikrokontroler wysyła 7-segmentowy kod cyfry do portu PB. Przyporządkowanie poszczególnych segmentów pozycjom bitów kodu pokazano na rysunku 9.3. Dla przykładu, aby wyświetlić cyfrę „4" należy wysłać kod 0110011 OB -= 66H. Wysłany kod pojawia się na wejściach informacyjnych 220 wszystkich wyświetlaczy, jednak na razie żaden z nich nie zapala się, gdyż żaden z kluczy prądowych nie jest otwarty. 2) Na linie PC4-6 należy podać kombinację zer i jedynek odpowiadającą numerowi wyświetlacza, na którym ma się pojawić cyfra. Linia PC7 powinna być w stanie wysokim. Dla przykładu, by wybrać wyświetlacz drugi z lewej, do portu PCH należy wysłać kombinację 1001B. Wyświetlacz nadal nie jest zapalony, ale dekoder l 74LS145 jest już wstępnie zaadresowany. Na wszystkich sześciu wykorzystywanych wyjściach dekodera jest stan wysoki, ponieważ wejście D znajduje się w stanie wysokim. 3) Należy spowodować wyzwolenie układu monostabilnego 74LS123 przez podanie na wejście A stanu niskiego z wyjścia PC8. Układ monostabilny wyprodukuje wówczas ujemny impuls na wyjściu zanegowanym, który włączy wybrany wyświetlacz. W podanym przypadku, aby spowodować wyzwolenie układu monostabilnego, do portu PCH należy wpisać kombinację 0001B. Czas trwania impulsu, czyli czas włączenia wyświetlacza jest określony przez stałą czasową obwodu RC przyłączonego do układu 74LS123. Po upływie tego czasu cyfra na wybranym wyświetlaczu zgaśnie i mikrokontroler powinien powtórzyć sekwencję czynności 1) - 3). Jeśli chcemy wyświetlać cyfry na kilku wyświetlaczach, powyższa sekwencja powinna być powtórzona kolejno dla wszystkich używanych wyświetlaczy. Wadą przedstawionego tu dynamicznego sposobu wyświetlania jest konieczność stałego zaangażowania CPU, natomiast zaletą - możliwość programowego regulowania jaskrawości świecenia poszczególnych wyświetlaczy. Jasność ta zależy od częstotliwości pobudzania wyświetlaczy w pętli programowej. Program, który wyświetla cyfrę „4" na drugim od lewej strony wyświetlaczu z rysunku 9.3, ma następującą postać: Odblokowanie przerwań z portu UART jest w powyższym przykładzie potrzebne po to, by system mógł mieć kontakt z systemem uruchomieniowym opartym na komputerze PC, połączonym z 221 mikrokontrolerem przez interfejs RS-232C. Oczywiście, zamiast programowego opóźnienia wprowadzanego przez procedurę CZEKAJ można zastosować wbudowany licznik. Jeśli obsługa przepełnienia licznika będzie się odbywać w trybie przerwań, jednostka centralna między kolejnymi pobudzeniami wyświetlacza może realizować inne zadania. Rozważmy teraz blok prostego programowanego generatora przebiegów analogowych z mikrokontrolerem x51 i 8-bitowym przetwornikiem cyfrowo-analogowym przedstawiony na rysunku 9.4. Rysunek 9.4. Uproszczony schemat programowanego generatora przebiegów elektrycznych Na rysunku pominięto źródła napięć odniesienia przetwornika C/A oraz bufory sygnałów wyjściowych mikrokontrolera. Przetwornik ma wewnętrzny rejestr danych, który jest zapisywany, jeśli wejście CS jest w stanie niskim, a na linii WR pojawi się strob zapisu. Wpis liczby OOH do rejestru przetwornika powoduje, że na jego wyjściu UX pojawia się napięcie o wartości 0V, natomiast wpis liczby FFH generuje napięcie +5V. Napięcie wyjściowe UX jest podawane na wejście X analogowego multipleksera MUX z ośmioma wyjściami ponumerowanymi od O do 7. Wyborem wyjścia multipleksera steruje 3-bitowa liczba wpisana z szyny danych do wewnętrznego rejestru multipleksera. Wpis liczby OOH wybiera wyjście numer O, natomiast wpis liczby 07H wybiera wyjście nr 7. Załóżmy, że zadanie projektowe polega na napisaniu programu dla generatora fali prostokątnej o zadanych wartościach napięć w stanie wysokim i niskim oraz o zadanych czasach trwania stanu wysokiego i niskiego. Dla ustalenia uwagi przyjmijmy, że napięcie w stanie wysokim UH ma wynosić 4V, natomiast napięcie w stanie niskim UL ma być równe 2V. Załóżmy też, że stan niski ma trwać dwa razy krócej niż stan wysoki, a czas trwania stanu wysokiego ma być zdefiniowany jako parametr projektowanej procedury. Niech ponadto sygnał CS1 z dekodera odpowiada adresowi 800CH, natomiast sygnał CS2 - adresowi 800DH. Generowane napięcie ma się pojawić na wyjściu numer 5. Program, który realizuje powyższe zadanie ma postać: 222 Podobnie jak we wcześniejszym przykładzie, zamiast opóźnień programowych można wykorzystać przerwania z licznika. Należy zauważyć, że użycie opóźnień programowych może prowadzić do znacznych błędów określenia czasów trwania stanu niskiego i wysokiego na wyjściu, ponieważ do opóźnień wnoszonych przez procedurę delay dodają się opóźnienia związane z wywołaniem procedury i powrotem z niej oraz opóźnienia związane z wykonaniem instrukcji przygotowujących każdy kolejny cykl w sekcji start. Dokonując prostych modyfikacji podanego wyżej programu można uzyskać generację przebiegów o innym kształcie, na przykład trójkątnym, trapezowym itp. 9.2. Programowanie w języku C Tworzenie programu w języku C przebiega według tego samego schematu, co cykl projektowy programu w języku asemblera przedstawiony na rysunku 9.1. Pliki źródłowe programu (oznaczone zwykle rozszerzeniem C) są tłumaczone na postać wynikową przez translatory nazywane kompilatorami (ang. compilers). 9.2.1. Kompilatory języka C Większość dostępnych kompilatorów języka C dla mikrokontrolerów jest opracowywana przez specjalistyczne firmy zajmujące się oprogramowaniem wspomagającym projektowanie systemów z mikrokontroleraini. Do najbardziej znanych firm działających w tej dziedzinie należą: Archimedes, Tasking, Ceibo, Hi-Tech, Frankłin, Keil, Ashling i IAR. Kompilatory języka C opracowywane przez wymienione wyżej firmy są zwykle niezgodne ze sobą, co wynika także z wciąż niedostatecznej standaryzacji samego języka C. Najczęściej stosowanym standardem jest standard ANSI C, jednak w praktyce kod źródłowy akceptowany przez kompilator określonej firmy może wymagać modyfikacji przed skompilowaniem przy użyciu kompilatora ANSI C innej firmy. Kompilatory C dla mikrokontrolerów są przeważnie dostarczane jako kompilatory skrośne (ang. 223 cross-compilers). Oznacza to, że kompilator pracuje na innej platformie (zwykle PC) i produkuje kod wynikowy dla mikrokontrolera określonego typu. Typowe kompilatory języka C dla mikrokontrolerów mają następujące cechy: - implementacja wszystkich typów ANSI C: unsigned, short, long, char, inl,floal, double oraz pointer, a także typów związanych z architekturą mikrokontrolerów: bit, sbit,sfr, - implementacja struktur, unii oraz typów tablicowych i wyliczeniowych, - deklaracje funkcji współużywalnych, rekurencyjnych i funkcji przerwań, - implementacja różnych modeli pamięci (liny, smali, compact, medium, large, banked) z podziałem na obszary danych (data), programu (code), obszaru pierwszych 256 bajtów pamięci (idata) oraz obszaru pamięci zewnętrznej (xdata), - dostęp do obszarów adresowanych bitowo, rejestrów SFR i rejestrów ogólnego przeznaczenia, - implementacja wskaźników o długości zależnej od typu pamięci (np. l-bajtowe w obszarze data i 2-bajtowe w obszarze xdata), - funkcje optymalizacji kodu wynikowego przez optymalizację skoków, eliminację zdublowanych fragmentów kodu i niepotrzebnych rozgałęzień, optymalizację operacji zmiennoprzecinkowych itp. Niektóre z wymienionych cech powodują, że programowanie mikrokontrolerów w języku C wymaga specjalistycznych umiejętności i przebiega w odmienny sposób niż w przypadku programowania komputerów. Najważniejsze różnice można streścić w postaci następujących spostrzeżeń: 1) Zapisanie algorytmu pracy mikrokontrolera w języku C wymaga tak samo dobrej znajomości architektury mikrokontrolera, jak przy posługiwaniu się językiem asemblera (chyba że przedmiotem projektu jest fragment programu nie związany ze sprzętem, a tylko z przetwarzaniem danych). Większość autorytatywnych publikacji z tej dziedziny postuluje opanowanie asemblera jako niezbędną umiejętność przed przystąpieniem do pisania programów w języku C. 2) Programy dla mikrokontrolerów zapisane w języku C „wyglądają" nieco inaczej niż typowe programy komputerowe. W mniejszym stopniu korzysta się ze skomplikowanych konstrukcji strukturalnych, a w większym z prostych operacji przypisań. Dotyczy to zwłaszcza programów intensywnie współpracujących ze sprzętem na j poziomie rejestrów i poszczególnych bitów. Uwaga 2) pociąga za sobą w konsekwencji to, że program źródłowy w języku C ma często prawie tak samo dużo linii, jak program źródłowy w języku asemblera. Kod wynikowy wyprodukowany przez dobry kompilator jest natomiast zwykle od kilku do kilkunastu razy dłuższy od kodu wynikowego asemblera. W tym świetle o popularności języka C w programowaniu mikrokontrolerów decyduje głównie sprawa kosztów. Duży program zapisany w języku C może być nawet kilkukrotnie tańszy niż program w języku asemblera, a czas jego projektowania, testowania i dokumentowania jest znacznie krótszy niż cykl projektowania programu w języku asemblera. 9.2.2. Przykłady programów w języku C – przykład 1 Obsługa wyświetlaczy 7-SEGMENTOWYCH Rozważmy program sterowania wyświetlaczem 7-segmentowym w układzie z rysunku 9.3, realizujący to samo zadanie co program podany w p. 9. l .3: 224 Powyższy program różni się nieco od programu z p. 9.1.3, gdyż funkcja czekaj wykorzystuje licznik T0 mikrokontrolera x51. Na początku programu dołączono biblioteczny nagłówek reg51.h z definicjami rejestrów i bitów kontrolno-sterujących mikrokontrolera. Program zajmuje 29 linii, natomiast program w języku asemblera z p. 6.1.3 nieco więcej, bo 33 linie (razem z komentarzami). Jeśliby w programie zapisanym w języku C zrezygnować z obsługi licznika i wykorzystać opóźnienie programowe, liczba i linii programu źródłowego wyniosłaby 16. Pogram byłby zatem o połowę krótszy niż wersja zapisana w asemblerze. Porównanie wielkości kodu wynikowego wypada natomiast zdecydowanie na korzyść asemblera. Program wynikowy zajmuje bowiem odpowiednio 40 bajtów (asembler) i 116 bajtów (C). W przedstawionym powyżej programie założono, że mikrokontroler pracuje z oscylatorem o częstotliwości 11,0592 MHz, typowej dla tych układów, jeśli chce się łatwo uzyskać standardowe szybkości transmisji w porcie UART. Wewnętrzna częstotliwość sygnału zegara doprowadzonego do licznika jest wówczas równa 11,0592 MHz/ /12 - 921,6 kHz, a okres zegara wynosi 1,085 p.s. Aby uzyskać opóźnienie 20 ms trzeba zatem zliczyć 20000 / 1,085 = 18433 impulsów zegara. Ponieważ licznik liczy od zaprogramowanej wartości x do chwili przepełnienia, czyli osiągnięcia stanu FFFFH = I = 65535D, zatem wartość x programująca licznik powinna być równa 65535 - 18433 = = 47102 - B7FDII. W programie przyjęto przybliżoną wartość równą B800H. 9.2.3. Przykłady programów w języku C – przykład 2 Programowany generator funkcyjny z przetwornikiem C/A Rozważmy teraz program generacji przebiegu prostokątnego o zadanych parametrach, równoważny programowi z p. 9. l .3. W języku C ma on następującą postać: 225 W powyższym przykładzie, podobnie jak w poprzednim, do odmierzania czasu wykorzystano licznik T0, pracujący w konfiguracji 16-bitowej. Program generuje falę prostokątną o napięciu UH = 4 V i UL = 2 V, przy czym czas trwania stanu wysokiego wynosi 80ms, natomiast czas trwania stanu niskiego równa się 40ms. Mimo bardziej elastycznej procedury odmierzania czasu program źródłowy w języku C jest krótszy od programu w języku asemblera. Kod wynikowy jest jednak blisko 3-krotnie dłuższy (asembler 38 bajtów, C - 112 bajtów). Podany wyżej program można łatwo zmodyfikować w celu realizacji programowanego generatora funkcyjnego o dowolnym przebiegu. Dla przykładu, program generatora przebiegu piłokształtnego z dobieranym czasem trwania kroku narastania impulsów oraz z ustalaną programowo wartością napięcia maksymalnego może mieć następującą postać: 226 Przebieg piłokształtny jest generowany na wyjściu WY0 układu z rysunku 9.3. W rzeczywistości narastające zbocze przebiegu jest krzywą schodkową, przy czym czas trwania każdej kolejnej wartości napięcia wynosi 10 ms (TLH), natomiast skok napięcia wynosi 5V/256 = 19,5 mV. Zastosowanie pętli for przy generowaniu kolejnych napięć powoduje, że napięcie o wartości 0V pojawia się na czas krótszy niż l ms. Można to łatwo zmienić, zastępując pętlę for pętlą while z inkrementacją zmiennej licz na końcu pętli. 9.2.4. Przykłady programów w języku C – przykład 3 Obsługa klawiatury matrycowej Najprostszym zespołem wykorzystywanym w systemach mikrokontrolerów do wprowadzania danych i poleceń sterujących są klawiatury zorganizowane w postaci matryc (macierzy) przycisków. Na rysunku 9.5 przedstawiono prostą klawiaturę złożoną z 28 przycisków ułożonych w matrycy z siedmioma kolumnami i czterema wierszami. Pominięto dodatkowe bufory i rezystory, które są zwykle stosowane w celu zapewnienia odpowiednich parametrów elektrycznych sygnałów przy współpracy z układem P1O. Rysunek 9.5. Uproszczony schemat klawiatury matrycowej 7x4 z mikrokontrolerem x51 przez programowany układ PIO Obsługa klawiatury z rysunku 9.5 jest wykonywana w sposób programowy, to znaczy sprawdzanie, czy został wciśnięty jakiś przycisk oraz dekodowanie jego współrzędnych w matrycy (numeru wiersza i kolumny) odbywa się przy użyciu algorytmu skanowania (przeglądania) klawiatury. W bardziej skomplikowanych zespołach klawiatur alternatywnie stosuje się sygnalizację wciśnięcia przycisku przez linie przerwań oraz sprzętowe dekodowanie wciśniętego przycisku. 227 W układzie przedstawionym na rysunku 9.5 dekodowanie stanu klawiatury przebiega według następującego schematu: 1) Mikrokontroler ustawia stan „O" na linii kolumny numer O, sterowanej z wyjścia PBO układu PIO. Wcześniej należy, oczywiście, odpowiednio skonfigurować układ PIO, to znaczy zdefiniować odpowiednie kierunki transmisji w portach. 2) Program odczytuje port PCL i sprawdza, czy na jednym z wejść jest stan „O". Jeśli tak jest, to wykryto wciśnięcie przycisku na skrzyżowaniu kolumny O i wiersza, na którym odczytane zostało „O". 3) Mikrokontroler generuje stan „O" na kolejnej linii kolumn i wykonuje sprawdzenie stanu linii wierszy. Procedura powtarza się, aż sprawdzona zostanie cała klawiatura albo nastąpi wykrycie stanu wciśnięcia jakiegokolwiek przycisku. 4) Po zdekodowaniu klawiatury program przystępuje do obsługi przez wywołanie procedury przypisanej do danego klawisza. Przedstawiony poniżej program obsługi klawiatury z rysunku 9.5 sprawdza całą macierz, niezależnie od tego, czy w trakcie sprawdzania wykryto stan wciśnięcia któregoś z przycisków, czy też nie. Sprawdzanie odbywa się od lewej kolumny do prawej i od dolnego wiersza do górnego. Jeśli równocześnie wciśnięty został więcej niż jeden przycisk, program zwróci kod klawisza położonego w kolumnie położonej bliżej prawej strony matrycy i w wierszu znajdującym się bliżej jej dołu. 228 Funkcja dekoduj zwraca kod wciśniętego klawisza. Jeśli żaden klawisz nic został wciśnięty, zwracana jest liczba 0xff, natomiast jeśli wciśnięto klawisz Kxy, wartość funkcji dekoduj na czterech bardziej znaczących bitach podaje numer kolumny (0 - 6) w naturalnym kodzie dwójkowym, a na mniej znaczących czterech bitach - numer wiersza w kodzie „l z 4". Wywołanie funkcji obsługi klawiszy zrealizowano przy użyciu instrukcji switch. Ten fragment programu można również zapisać, korzystając z tablicy wskaźników do funkcji obsługi. Przedstawiony powyżej prosty program obsługi klawiatury matrycowej ma pewne niedoskonałości. Mianowicie, klawiatury realizowane w postaci matryc z mechanicznymi stykami wytwarzają przy zwieraniu zakłócenia impulsowe, w wyniku czego przez pewien niedługi czas stan linii wierszy może być nieustalony. W stosowanych w praktyce programach obsługi klawiatur tego typu nieprawidłowemu zdekodowaniu klawiatury zapobiega się przez kilkakrotne (na przykład 3-krotne) odczytanie stanu wiersza. Jeśli przynajmniej dwa odczyty świadczą o wciśnięciu klawisza, program przystępuje do jego obsługi, natomiast w przeciwnym przypadku stan klawisza uznaje się za nieokreślony. Drugą wadą przedstawionego programu jest brak reakcji systemu na zwieranie klawiszy w czasie gdy mikrokontroler jest zajęty obsługą poprzednio wciśniętego klawisza. Można temu zaradzić, stosując dodatkową linię doprowadzającą do mikrokontrolera sygnał przerwania w przypadku wciśnięcia któregokolwiek klawisza. Praca z przerwaniami ma dodatkowo tę zaletę, że przy braku zgłoszeń z klawiatury procesor może realizować inne zadania zamiast bezproduktywnie skanować klawiaturę. Przykład obsługi przerwań w programie zapisanym w języku C przedstawiono w następnym punkcie. 9.2.5. Przykłady programów w języku C – przykład 4 Transmisja przez port szeregowy 229 W systemach z mikrokontrolerami stosuje się najczęściej transmisję asynchroniczną, ze standardową szybkością określoną przez odpowiednio zaprogramowany licznik. Szybkość ta w prostych mikrokontrolerach jest zazwyczaj niewielka, dlatego obsługa transmisji w trybie programowym powodowałaby bardzo nieefektywne wykorzystanie czasu CPU. Dlatego zamiast obsługi programowej w praktyce korzysta się z systemu przerwań, zgodnie z regułami podanymi w p. 5.4.4. W podanym niżej przykładzie mikrokontroler odbiera ciąg bajtów z portu szeregowego pracującego jako 8-bitowy układ UART. Szybkość transmisji jest określona przez impulsy produkowane przez licznik T1. Odebrane bajty są wysyłane w postaci równoległej do portu P1 w prosty sposób - bez synchronizacji transmisji między mikrokontrolerem a odbiornikiem i z powiadamianiem odbiornika o gotowości bajtu do odbioru przez wysłanie dodatniego impulsu na wyjściu P2.0. Program realizujący tak zdefiniowane zadanie ma następujący zapis w języku C: Zapis interrupt 4 w nagłówku definicji funkcji przekaz oznacza, że funkcja ta będzie wywoływana, jeśli wystąpi przerwanie numer 4. W mikrokontrolerach rodziny x51 przerwanie to jest przypisane portowi UART. Kompilator po natrafieniu na taki zapis spowoduje, że adres funkcji przekaz zostanie zapisany pod adresem odpowiadającym wektorowi przerwań o numerze 4 (licząc od zera). Zgodnie z ogólnymi zasadami obsługi przerwań opisanymi w p. 5.4.4 funkcja obsługi przerwań powinna być napisana w taki sposób, by nie zmieniała wartości rejestrów używanych przez program, którego wykonanie jest przerywane. Można to zrealizować przy użyciu stosu, ale w mikrokontrolerach z rejestrami podzielonymi na banki prościej jest wykorzystać w funkcji obsługi inny bank rejestrów niż ten, na którym operuje program główny. W podanym przykładzie zapis using 2 oznacza, że funkcja przekaz będzie wykorzystywać bank rejestrów o numerze 2. Dla ścisłości trzeba dodać, że w podanym wyżej programie przedstawiono tylko sam mechanizm inicjacji portu UART i sposób programowania w systemie przerwań. Po wykonaniu inicjacji portu UART program główny wchodzi w nieskończoną pętlę, toteż korzyść z pracy w systemie przerwań nie jest widoczna. Jeśli jednak zamiast pętli while(1) w funkcji main zapisze się program realizujący inne zadania, wtedy korzyść z zastosowania systemu przerwań stanic się oczywista. 230 9.3. Narzędzia wspomagające uruchamianie systemów mikroprocesorowych Uruchamianie prototypowych systemów z mikrokontrolcrami jest na ogól trudniejsze od uruchamiania konwencjonalnych systemów mikroprocesorowych, budowanych głównie do przetwarzania danych. Wynika to z dwóch podstawowych przyczyn: 1) Mikrokontrolery mają wiele wbudowanych bloków funkcjonalnych (pamięci i układów peryferyjnych), do których dostęp w czasie pracy systemu jest utrudniony lub niemożliwy. Traktowanie mikrokontrolera jako „czarnej skrzynki" nie wystarcza jednak do szczegółowego przeanalizowania pracy systemu. Potrzebne są specjalistyczne narzędzia i metody do śledzenia stanu mikrokontrolera i jego otoczenia, a w szczególności do badania stanu rejestrów SFR. 2) Sterowniki z wbudowanymi mikrokontrolerami są przeznaczone do pracy w czasie rzeczywistym. Testowanie systemu w czasie rzeczywistym, we współpracy z rzeczywistym otoczeniem, bez naruszania relacji czasowych sygnałów, wymaga narzędzi diagnostycznych, które nie zakłócają pracy systemu. Mimo tych różnic, do uruchamiania systemów z mikroprocesorami i mikrokontrolerami stosuje się podobne metody i narzędzia, opracowane i udoskonalane w ciągu blisko 30-letniej ewolucji techniki mikroprocesorowej. Przedstawione powyżej trudności pokonuje się przy użyciu ulepszonych metod śledzenia systemów w czasie rzeczywistym, z wykorzystaniem wbudowanych do mikrokontrolerów bloków zapewniających pracę ze śledzeniem w tle (ang. background debugging modę) oraz specjalizowanych interfejsów diagnostycznych (JTAG). Narzędzia wspomagające projektowanie i uruchamianie dzieli się na kilka podstawowych kategorii: - monitory programowe (ang. monitors), - programy śledzące (ang. debuggers), - symulatory (ang. simulators), - analizatory stanów logicznych (ang. logie analyzers), - emulatory sprzętowe (ICH, ang. in-circuit emulators), - zintegrowane systemy projektowo-diagnostyczne (IDE, ang. integrated deve-lopment environment), - analizatory szybkości pracy systemu (ang. performance analysis tools), - programatory wbudowanych i zewnętrznych pamięci OTP / EPROM / EEPROM / FLASH (ang. memory programmers). Do narzędzi wspomagających projektowanie zalicza się też omówione wcześniej asemblery, kompilatory i programy łącząco-ładujące. Systemy uruchomieniowe produkuje się albo jako autonomiczne systemy z wbudowanym mikrokomputerem, albo w postaci kart, interfejsów, przystawek i oprogramowania do instalacji w typowych komputerach PC. 9.3.1. Monitory i programy śledzące Monitory i programy śledzące (debugery) są najprostszymi, najtańszymi i jednocześnie najszerzej stosowanymi narzędziami wspomagającymi uruchamianie systemów z mikrokontrolerami. Podstawowa różnica między monitorami i programami śledzącymi polega na tym, że monitory są instalowane w pamięci nieulotnej (wewnętrznej lub zewnętrznej) systemu zawierającego mikrokontroler, natomiast debugery pracują w przyłączonych do systemu komputerach (zwykle klasy PC). Z tego powodu monitory nazywa się również rezydującymi debugerami (ang. resident debuggers). Często stosuje się rozwiązanie mieszane, w którym część programu debugera rezyduje w pamięci na płycie prototypowej (ang. evaluation board), a pozostała część programu jest umieszczona w pamięci komputera PC. W takiej konfiguracji program rezydujący służy przede wszystkim do realizacji komunikacji z komputerem PC (zwykle przez port UART - RS232) i ładowania testowanych programów, natomiast komputer PC wykonuje właściwe funkcje związane ze śledzeniem pracy programu (rysunek 9.6). 231 Rysunek 9.6. Prosty system uruchomieniowy z płytą prototypową i komputerem PC Zestaw funkcji monitora-debugera zależy od jego typu, producenta i rodzaju zastosowanego mikrokontrolera. Większość debugerów zapewnia realizację podstawowego zbioru operacji, przy użyciu których można załadować program z pliku HEX lub S do pamięci, uruchomić go, śledzić w kilku różnych trybach, obserwować i modyfikować zawartości pamięci i rejestrów (w tym SFR), a także wykonywać proste zmiany w programie bez potrzeby ponownej asemblacji (lub rekompilacji). Debugery pracujące w systemie DOS są sterowane przy użyciu poleceń podawanych przez operatora, zwykle w postaci jednoliterowych symboli z opcjonalnymi parametrami. Programy śledzące przeznaczone dla graficznego środowiska Windows są natomiast sterowane typową metodą interaktywną (mysz, listy dialogowe, menu), a wyniki pojawiają się w odpowiednich oknach. Poniżej podano zbiór typowych poleceń debugera. W nawiasach prostokątnych umieszczono opcjonalne parametry sterujące. D [adres] [, l bajtów] - (ang. display, dump) wyprowadza i wyświetla na konsoli zawartość n = 1_bajtów kolejnych komórek pamięci począwszy od adresu adres. Jeśli liczba bajtów nie jest podana, wyświetlana jest zawartość domyślnej liczby komórek. Jeśli natomiast nie podano adresu, wyświetlany jest obszar zaczynający się od aktualnej zawartości licznika adresów. Po uruchomieniu debugera licznik wskazuje zwykle na początek pamięci (najczęściej 0). Poniższy przykładowy wydruk ilustruje typowy format stosowany przy wyświetlaniu zawartości pamięci: w lewej kolumnie podane są adresy, następnie w 16 kolumnach zawartości komórek pamięci w kodzie szesnastkowym i w końcowych kolumnach równoważna informacja w kodzie ASCII. Kody, którym nie odpowiadają dające się wydrukować znaki ASCII są reprezentowane przez znak kropki. Rysunek.9.7. Fragment monitora Siemens x166 wyprowadzony w trybie HEX-dump adres [, nowa_zawartość] - (ang. memory) wyświetla zawartość komórki pamięci o adresie adres i ewentualnie wpisuje do niej nową zawartość. R [nazwa_rejestru] - (ang. register) wyświetla zawartość wskazanego rejestru lub wszystkich rejestrów (jeśli nie podano nazwy konkretnego rejestru). Operator może podać nowe zawartości rejestrów. L [adres, ] nazwa-pliku - (ang. load) ładuje plik dwójkowy (np. w formacie HEX) do pamięci systemu poczynając od adresu adres. B [iista_adresów] - (ang. breakpoint) wstawia punkt zatrzymania przy adresie odpowiadającym aktualnej zawartości licznika programu lub w punktach określonych przez listę adresów. G [adres] - (ang. go) uruchamia program od aktualnego adresu w liczniku programu lub od adresu wskazanego jako parametr. Jeśli nie zdefiniowano punktów zatrzymań, program wykonuje się w całości. M 232 S [liczba_instrukcji] - (ang. step) wykonuje pojedynczą instrukcję programu lub ciąg instrukcji o zadanej długości. Debugery są ponadto najczęściej wyposażone w prosty asembler (ang. in-line as-sembler) i deasembler (ang. disassembler), które są wywoływane poleceniami A i u: A [adres] - (ang. assemble) po podaniu tego polecenia operator może wpisywać z konsoli program źródłowy. Kolejne instrukcje są tłumaczone na bieżąco i umieszczane w kolejnych komórkach pamięci, zaczynając od aktualnej zawartości licznika programu lub od podanego adresu. W najprostszych asemblerach typu in-line nie można używać nazw symbolicznych, a więc w szczególności etykiet. Adresy skoków są podawane w postaci liczbowej, co znacznie utrudnia pisanie większych fragmentów programu. u [adres] [, liczba_instrukcji] - (ang. unassemble) deasembluje podaną lub domyślną liczbę instrukcji zaczynając od adresu adres lub od aktualnej zawartości licznika programu. Adres początkowy musi odpowiadać pierwszemu bajtowi instrukcji, w przeciwnym przypadku deasembler zinterpretuje zawartość pamięci w nieprawidłowy sposób. Przykład takiej sytuacji ilustruje podane niżej zestawienie prawidłowego i nieprawidłowego użycia polecenia u deasemblera x86: Rysunek 9.8. Prawidłowe i nieprawidłowe użycie polecenia deasemblera x86 Wywołanie U 123 jest prawidłowe, ponieważ w bieżącym segmencie programu (CS = 1F6E) komórka pamięci o adresie 0123H zawiera pierwszy bajt (kod operacji) instrukcji jnz. Wywołanie u 122 jest natomiast nieprawidłowe, ponieważ pod rym adresem znajduje się ostatni bajt (argument) poprzedniej instrukcji. Deasembler próbuje zinterpretować go jako kod operacji xor, co prowadzi w konsekwencji do błędnej interpretacji kolejnych instrukcji. Ponowna synchronizacja adresów następuje dopiero przy rozkazie MOV DX,CX. Zaletą prostych monitorów i debugerów jest łatwość obsługi i niska cena. Podstawową wadą jest fakt, że narzędzia te nie pozwalają na prześledzenie pracy systemu w czasie rzeczywistym i w warunkach identycznych jak te, które będą miały miejsce w gotowej aplikacji. Monitor zainstalowany w systemie prototypowym zajmuje część jego zasobów (pamięć, port szeregowy i linię przerwań), dlatego aplikacje korzystające z tych zasobów muszą być w fazie testowania zmodyfikowane i śledzone w niepełnym zakresie realizowanych funkcji. 9.3.2. Symulatory Symulator jest programem umożliwiającym prześledzenie programu dla mikrokontrolera przy użyciu procesora innego typu (zwykle x86 na platformie Windows/PC). Program symulatora naśladuje zachowanie się mikrokontrolera, pozwala śledzić stan rejestrów, zawartość pamięci, a nawet symulować przerwania i proste układy peryferyjne. Zaletą takiego rozwiązania jest to, że badania oprogramowania można zacząć zanim jeszcze powstanie prototyp sprzętowy. Wadą symulatorów jest brak możliwości przetestowania współpracy mikrokontrolera z otoczeniem w rzeczywistych warunkach. Mimo to symulatory są często stosowane we wstępnej fazie projektowania oprogramowania, ponieważ pozwalają wykryć wiele błędów nie związanych ze współpracą mikrokontrolera z otoczeniem sprzętowym. Na rysunku 9.9 przedstawiono okno definiowania parametrów urządzeń zewnętrznych przykładowego symulatora mikrokontrolerów x51, 251 i 8x93. 233 Rysunek 9.9. Okno do definiowania parametrów urządzeń zewnętrznych w symulatorze Compass/251USB Emulatory sprzętowe Emulatory sprzętowe są najlepszymi i jednocześnie najdroższymi narzędziami do uruchamiania systemów z mikroprocesorami lub mikrokontrolerami. Zasada ich pracy polega na zastąpieniu mikrokontrolera w uruchamianym urządzeniu przez sondę zakończoną adapterem dopasowanym do podstawki mikrokontrolera. Układy emulatora, częściowo wbudowane do samego adaptera, a częściowo przyłączone przez sondę, pracują tak samo jak wyjęty z podstawki mikrokontroler, ale oprócz tego zapewniają śledzenie pracy systemu w czasie rzeczywistym. Dobrze zaprojektowane emulatory naśladują mikrokontrolery w najdrobniejszych szczegółach, z zachowaniem relacji czasowych między wszystkimi sygnałami wejściowymi i wyjściowymi. Najczęściej emulator jest połączony z zewnętrznym komputerem (np. klasy PC), który umożliwia wygodne śledzenie badanego prototypu. Klasyczny emulator jest zbudowany w sposób przedstawiony na rysunku 9.10. Rysunek 9.10. Poglądowy schemat budowy typowego emulatora sprzętowego Emulator przypomina kompletny mikrokomputer, gdyż oprócz jednostki centralnej zawiera pamięci i układy wejścia/wyjścia. Emulatory mają następujące cechy: - mogą w trakcie pracy zamieniać między sobą zasoby testowanego systemu i odpowiadające im zasoby emulatora; technikę tę nazywa się mapowaniem zasobów (ang. mapping), 234 - testowanie programu w czasie rzeczywistym jest możliwe nawet bez przyłączonego systemu prototypowego, - podobnie jak w przypadku debugerów, program jest wykonywany w trybie ciągłym, krokowo lub ze zdefiniowanymi uprzednio punktami zatrzymań, - zapewniona jest pełna obserwacja i możliwość modyfikacji zawartości rejestrów i pamięci, często również w czasie rzeczywistym, - śledzenie wykonywania programu ułatwiają wbudowane analizatory stanów logicznych rejestrujące sekwencje stanów w wybranych punktach systemu. Emulatory o zaawansowanej architekturze mają takie same możliwości, przy czym funkcje śledzenia w czasie rzeczywistym są bardziej rozbudowane i dotyczą praktycznie wszystkich parametrów testowanego systemu. Emulatory tego typu wykorzystują bloki pamięci RAM wyposażone w podwójne sterowanie, a więc w dwie niezależne szyny adresów i danych (ang. dualport RAM). Dzięki temu procesor emulatora i przyłączona do niego stacja robocza mogą pracować równocześnie, mając dostęp do wspólnych zasobów (rysunek 9.11). W emulatorze nie jest zatem potrzebny monitor zapisany w pamięci ROM, gdyż komunikacja stacji z emulatorem odbywa się bez udziału procesora wbudowanego do emulatora. O ile w przypadku układu z rysunku 9.10 każde polecenie emulacyjne wysyłane z komputera nadzorującego przerywało pracę procesora emulującego (NM1), o tyle w układzie z rysunku 9.11 przerwania są potrzebne tylko w przypadku niektórych operacji (na przykład wymuszenia przejścia do określonego adresu w programie). Rysunek 9.11. Budowa emulatora wyposażonego w blok pamięci RAM z podwójnym dostępem Emulatory są zazwyczaj budowane z wykorzystaniem mikrokontrolera tego samego typu, jaki zastosowano w systemie testowanym. Z zewnątrz przyłączane są dodatkowe, niekiedy bardzo skomplikowane układy, umożliwiające rejestrację stanu mikrokontrolera w czasie rzeczywistym. W przypadku mikrokontrolerów niektórych typów budowa emulatora jest ułatwiona, oprócz bowiem wersji rynkowej układów producenci dostarczają także wersje przeznaczone specjalnie do emulacji (ang. bond out version). Mają one obudowy z większą liczbą wyprowadzeń, przez które wyprowadza się na zewnątrz sygnały z wewnętrznej szyny danych i adresów. W przypadku mikrokontrolerów, które są trudne do emulacji, a nie mają wersji bond out, stosuje się niekiedy funkcjonalnie równoważne mikrokontrolery zbudowane przy użyciu programowanych struktur logicznych. Metoda nie nadaje się jednak do użycia w przypadku najbardziej zaawansowanych mikrokontrolerów o skomplikowanej budowie wewnętrznej. Drugim pod względem trudności zadaniem przy projektowaniu emulatorów jest opracowanie układów realizujących mapowanie zasobów. Technika mapowania zastosowana do pamięci umożliwia elastyczne przełączanie zasobów testowanego systemu i emulatora lub komputera sterującego. We wstępnej fazie projektu, programy mogą być dzięki temu uruchamiane w pamięci komputera, a dopiero potem wraz z pojawieniem się prototypu projektowanego urządzenia są przenoszone do jego własnej pamięci. W fazach pośrednich możliwe jest wykonywanie części 235 programu w pamięci komputera, a innych fragmentów oprogramowania - w pamięci badanego systemu. Mapowaniem zasobów zarządza specjalizowany kontroler współpracujący z pamięcią emulacyjną (rysunek 9.12). W zależności od sposobu zaprogramowania (skonfigurowania) kontrolera system korzysta albo z zasobów komputera sterującego, albo z rzeczywistych zasobów testowanego systemu. Rysunek 9.12. Realizacja mapowania obszarów pamięci w emulatorze sprzętowym Do emulatorów sprzętowych zalicza się również oddzielną grupę narzędzi nazywanych emulatorami pamięci ROM (EPROM). Są one znacznie prostsze w budowie od emulatorów mikrokontrolerów, choć pracują na podobnej zasadzie. Sonda z adapterem emulatora ROM zastępuje pamięć stałą i naśladuje jej działanie. Dane odczytywane przez szynę pamięci ROM pochodzą jednak z pamięci RAM emulatora, dlatego mogą być łatwo modyfikowane w fazie testowania systemu, bez potrzeby programowania kolejnych układów ROM (FPROM). Dzięki temu czas tworzenia projektu jest znacznie krótszy. Wysoki koszt opracowania emulatorów dla coraz bardziej skomplikowanych mikrokontrolerów spowodował, że coraz więcej czołowych producentów mikrokontrolerów wyposaża je w dodatkowe bloki funkcjonalne ułatwiające śledzenie pracy w czasie rzeczywistym. Układy te mogą pracować w trybie śledzenia w tle (HMD - ang. background modę debugging), a sygnały potrzebne do śledzenia są przesyłane przy użyciu dodatkowych wyprowadzeń, nie wpływając na pracę mikrokontrolera. Interfejs diagnostyczny mikrokontrolerów i mikroprocesorów jest najczęściej zgodny ze standardem JTAG. W system BMD są wyposażone między innymi wszystkie nowe procesory firm Intel i Motorola, poczynając od Pentium, PowerPC i ColdFire. Dla niektórych typów procesorów tryb BMD lub równoważne mu tryby pracy testowej nie są dostępne. Dotyczy to zwłaszcza procesorów z oprogramowaniem fabrycznym zapisanym w wewnętrznej pamięci ROM, które jest w ten sposób chronione przed skopiowaniem lub rozkodowaniem. W rzeczywistości jednak nawet układy do zastosowań specjalnych z zabezpieczonym odczytem wewnętrznej pamięci programu mogą pracować w trybie diagnostycznym, jest to bowiem niezbędne w fazie testów fabrycznych. Sposób uruchomienia trybu testowego w takich przypadkach jest otoczony tajemnicą firmową i nie jest udostępniany nawet producentom narzędzi wspomagających projektowanie i testowanie systemów. 9.3.3. Zintegrowane programy wspomagające uruchamianie Poszczególne programy narzędziowe do śledzenia, symulacji i emulacji są najczęściej dostarczane w postaci pakietów tworzących kompletne środowisko programowe do projektowania i testowania aplikacji mikrokontrolerów. Typowy pakiet tego typu (IDE) zawiera asembler, debuger, kompilator języka C, program łącząco-ładujący, program zarządzania plikami projektów (ang. project manager, librarian) oraz opcjonalnie symulator, program do emulacji i analizator szybkości pracy systemu. Pakiety IDE są najczęściej implementowane w środowisku Windows/PC i sprzedawane w rozmaitych opcjach. Ich cena zależy głównie od typu mikrokontrolera, jakości kompilatora języka C oraz zestawu funkcji do testowania systemów prototypowych w czasie rzeczywistym. 236 Przykładem środowiska IDE dla popularnych mikrokontrolerów 8- i 16-bitowych firm Intel i Motorola jest PathFinder, opracowany przez irlandzką firmę Ashling. PathFinder jest w znacznej mierze systemem otwartym, może bowiem współpracować w szerokim zakresie z oprogramowaniem i sprzętem innych firm produkujących narzędzia IDE. W szczególności można w nim wykorzystać kompilatory C dostarczane przez IAR, Keil, Tasking/BSO, HiwarelArchimedes, Hi-Tech, Cosmic, Byte Craft, Intel i Introl. Może też współpracować z emulatorami sprzętowymi i programatorami pamięci. Jeśli testowany system jest przyłączony do komputera nadzorującego przy użyciu złącza szeregowego RS-232, pakiet PathFinder zapewnia szybkość transmisji równą 115 kbps, dlatego ładowanie nawet dużych programów przebiega sprawnie. Zaletą systemu są też praktycznie nieograniczone rozmiary tablic symboli dla uruchamianych programów. Jedna z dodatkowych funkcji pozwala przeprowadzić analizę szybkości wykonywania poszczególnych rodzajów operacji przez badany program (rysunek 9.13). Rysunek 9.13. Raport z przebiegu analizy szybkości działania poszczególnych rodzajów operacji w testowanym programie Dla większości popularnych typów mikrokontrolerów dostępne są kompletne zestawy do prac projektowo-uruchomieniowych (ang. development kits). W skład takich zestawów wchodzi płyta prototypowa z mikrokontrolerem, zewnętrznymi pamięciami oraz z podstawowymi urządzeniami peryferyjnymi, takimi jak klawiatury matrycowe, wyświetlacze i porty RS-232. W zestawie jest również oprogramowanie (najczęściej IDF) oraz podstawowa dokumentacja techniczna. Jest to wystarczająca podstawa do wstępnych prac projektowych lub do tworzenia niezbyt skomplikowanych aplikacji. Dla biur projektowych zajmujących się profesjonalnie budową bardziej złożonych systemów oferowane są o wiele droższe zestawy MDS (ang. microprocessorlmicrocontroller development system) wyposażone w emulator sprzętowy i kompilator języka C wraz z obszernymi bibliotekami. 237 10. Literatura 1. TIETZE U., SCHENK CH.: Układy półprzewodnikowe, Warszawa, WNT, 1996 2. Pełka R.: Mikrokontrolery architektura, programowanie, zastosowania, Warszawa, WKŁ, 1999 3. GAŁKA P., GAŁKA P.: Podstawy programowania mikrokontrolerów 8051, Warszawa, ZNI “MIKOM”, 1995 4. Z.Czaja: Materiały do wykładu Mikrokontrolery i mikrosystemy 2003, Politechnika Gdańska, 2003 238 11. Dokumentacja sterownika DSM-51 wyk. w laboratorium Rysunek 11.1. Schemat blokowy 239 Rysunek 11.2. Schemat jednostki centralnej 240 Rysunek 11.3. Schemat układu zasilania oraz resetu i wdog 241 Rysunek 11.4. Schemat układu łączy szeregowych RS232 242 Rysunek 11.5. Schemat układów przetwornika A/C i C/A 243 Rysunek 11.6. Schemat układu wyświetlacza 7-segmentowego i klawiatury sekwencyjnej 244 Rysunek 11.7. Schemat układu klawiatury matrycowej 245 Rysunek 11.8. Schemat układu buforów szyny danych, adresowej i sygnałów sterujących 246 Rysunek 11.9. Schemat układu łączówek sterownika 247