Rabat dla członków klubu AVT!

Dodatkowy port PAR i SER

Fotka

Jeden port równoległy i jeden szeregowy to stanowczo za mało. Ciągłe przełączanie wtyczek od drukarki, samplera, modemu i innych urządzeń nie jest ani wygodne, ani bezpieczne. Dodatkowy port PAR+SER (max 8) likwiduje wszelkie niedogodności.
Szybkość transferu dla portu PAR 200-300KB/s.
Dodatkowy port PAR w przeciwieństwie do portu w Amidze ma konfigurowane piny 14-17 co umożliwi mu współpracę ze skanerami itp. Ponadto pin 14 można skonfigurować jako wejście/wyjście lub zasilanie +5V, co umożliwia współpracę z samplerami itp.
Dodatkowy port SER ma bufor FIFO na 16-bajtów, max transfer 691200bd.

Porty będą dostępne w wersji na Zorro II i port Colck A1200. Dzięki układowi GAL do portu zegara można podłączyć 4 dodatkowe porty PAR i 4 SER lub inne urządzenia z zawartym dekoderm adresowym na GAL'u. Przy wykorzystaniu płyty Zorro Elboxu liczba portów wzrośnie czterokrotnie.

Oprócz oprogramowania (drivery) dostepne będa przyklady w asemblerze i Basic'u. Dzięki temu każdy będzie mógł napisać procedury obsługujące port z pominięciem sterowników.

        Wymagania:              port zegara lub port Zorro-2


Karta MultiIO - dodatkowe porty PAR i SER do Amigi
Jak każdy użytkownik Amigi wie, naszą przyjaciółkę (Amiga, z Greckiego zdaje się, oznacza przyjaciółka) standardowo wyposażono w jeden port równoległy i jeden port szeregowy. Tak więc przy podłączaniu drukarki i programatora (np. AVT-996) czy modemu i emulatora AVT-870 napotykamy na problemy. Jedynym wyjściem jest "wachlowanie" wtyczkami . Dodatkowy port Par i Ser zwany dalej kartą MultiIO rozwiąże ten problem. Dzięki zastosowaniu układu GAL do jednego portu Clock A1200 można podłączyć cztery dodatkowe porty równoległe i cztery szeregowe. Gdy w komputerze mamy kartę z Zorro-2 i czterema portami Clock liczbę dodatkowych portów można zwiększyć do 16 PAR i 16 SER. Jeżeli będzie zainteresowanie powstaną porty na sloty Zorro-2. Jeśli zainteresowanie będzie małe powstanie karta na Zorro-2 z czterema portami zegara. Umożliwi to podłączenie w/w portów do Amig z Zorro-2.
Port równoległy może pracować w dwóch trybach:
- jako standardowy port Amigi (na pinie 14 napięcie zasilania +5V)
- jako pełny port ECP/EPP
Wyboru trybu dokonujemy programowo. Port szeregowy może pracować z maksymalną prędkością 691200bd, zawiera 16 bajtowy FIFO oraz zabezpieczenie przed ESD. Bufor FIFO zmniejsza wymagania w stosunku do komputera przy obsłudze dużych prędkości transmisji.

Budowa i zasada działania:
Napięcie zasilania z portu Clock po przejściu przez bezpiecznik polimerowy i odfiltrowaniu w C1...C5, C13 zasila układy na karcie portów. Szyna danych i adresowa z magistrali procesora dostępnej na porcie Clock steruje bezpośrednio układami UART typu 16C550, CIA typu 8520, oraz GAL'em. Na szynie danych złącza Clock dostępne są tylko cztery linie adresowe A2...A5. Sympatyków procesorów 8-bit może zdziwić brak linia adresowych A0, A1. Otóż procesor zastosowany w A1200 jest w pełni 32-bitowy. Przy przesłaniach 8-bit dane są wysyłane-pobierane z linii: dla adresów:
%xxxxxxxxxxx00 - D0...D7
%xxxxxxxxxxx01 - D8...D15
%xxxxxxxxxxx10 - D16...D23
%xxxxxxxxxxx11 - D24...D31
dlatego z procesora nie wyprowadzono linii A0 i A1. Układ UART do pełnej obsługi potrzebuje 3 linii adresowych. Budując odpowiednio dekoder adresowy (przykład na rys. 2 - dekoder znajduje się w szarym polu) można podłączyć dwa UART'y. CIA do pełnej obsługi potrzebuje 4 linii adresowych. W najprostszym wykonaniu można więc podłączyć tylko jeden układ do portu Clock. Jak więc możliwe, że na opisanej w artykule karcie znajdują się dwa układy, a do jednego portu Clock można podłączyć 4 karty? Problem rozwiązuje GAL koordynujący pracę karty. Przed dostępem do układu na jakiejkolwiek karcie trzeba go zaadresować. GAL po wykryciu adresu przeznaczonego dla niego ($d8002d) i niskim stanie na WR wpisuje daną z linii D16...D18 do wewnętrznego rejestru. Odczyt z pod tego adresu spowoduje pojawienie się ostatnio zapisanej tam informacji na wyjściach trójstanowych Q16...Q18. Podczas tych operacji stroby CS_PAR i CS_SER są nieaktywne. Jeśli do portu Clock jest podłączonych więcej kart, każdy z układów GAL zapamięta wysłaną daną w swoim rejestrze. Od tego momentu strob na linii CS_SER lub CS_PAR pojawi się tylko wtedy, gdy wartość wpisana do GAL'a będzie się zgadzała z adresem przypisanym na stałe do GAL'a. Adresy zaprogramowane w GAL'u są następujące:
0 - CIA na pierwszej karcie (strob CS_PAR)
1 - UART na pierwszej karcie (strob CS_SER)
2 - CIA na drugiej karcie (strob CS_PAR)
3 - UART na drugiej karcie (strob CS_SER)
4 - CIA na trzeciej karcie (strob CS_PAR)
5 - UART na trzeciej karcie (strob CS_SER)
6 - CIA na czwartej karcie (strob CS_PAR)
7 - UART na czwartej karcie (strob CS_SER)
W dalszym tekście wartość wpisana do rejestrów układu GAL będzie nazywana SubAdresem. Jak z tego wynika, każda karta ma inaczej zaprogramowanego GAL'a. GAL dostępny w kicie będzie obsługiwał adresy 0 i 1 czyli pierwszą kartę. Aby podłączyć więcej kart trzeba samemu przeprogramować GAL'a. Nie powinno stanowić to problemu, ponieważ w AVT jest dostępny programator GAL'i dla Amigi (AVT-5049). Na stronie www EP oraz na CD EP znajdują się pliki źródłowe i wynikowe GAL'a dla wszystkich czterech kart. Rejestr GAL znajduje się pod adresem $D8002D. Podczas zapisu pod w/w adres pojawia się wysoki poziom logiczny na wyprowadzeniu 22 układu GAL, a co za tym idzie na wejściu Clock GAL'a. Powoduje to przepisanie danych z szyny adresowej do wewnętrznego rejestru typu D umieszczonego w strukturze GAL'a. Wartość rejestru można także odczytać. Podczas odczytu adresu $D8002D pojawia się niski poziom na wyjściu 15 GAL, a co za tym idzie na wejściu OE sterującym buforami trójstanowymi układu GAL. Za sprawą sygnału OE bufory zostaną otwarte i zawartość rejestru GAL'a pojawi się na magistrali adresowej. W danej tej istotne są tylko bity 0...3 pozostałe należy zignorować. Układ GAL generuje jeszcze sygnał zegarowy E oznaczany często jako O2 dla układu 8520. Jak wiadomo sygnał ten jest charakterystyczny dla układów Motoroli, ale niestety nie dostępny na złączu Clock. Da się go jednak odtworzyć na podstawie sygnałów WR i RD. Sygnał E przyjmuje poziom wysoki, gdy któryś ze sygnałów (RD lub WR) przyjmie poziom niski (rys. 3). Taki sposób odtworzenia sygnału E ma tą wadę, że nie jest on generowany, gdy nie komunikujemy się z układem, przez to nie działają poprawnie wewnętrzne timery i nie da się ich wykorzystać. Warto wspomnieć, że pod adresem $D8002D znajduje się jeden z rejestrów układu CIA, a konkretnie rejestr TODHR. Ze względu na to, że na wejście TICK nie jest podany żaden sygnał rejestr ten jest nieaktywny. Po wybraniu tego adresu nie jest generowany strob do układu CIA dzięki czemu odczyt rejestru układu GAL nie jest zakłócony. Bramy układu CIA są połączone do złącza portu równoległego. Spostrzegawczy czytelnicy zauważą, że linie portu PB i trzy linie portu PA są połączone z portem równoległym dokładnie tak jak w Amidze. Dzięki temu łatwo zaadaptować istniejące oprogramowanie tak, aby obsługiwało nowe porty. W tym celu wystarczy zmienić adresy portów. Pozostałe linie połączono z pinami 14...17 portu dzięki czemu możemy pracować w trybach ECP/EPP. Linia PA7 steruje załączaniem napięcia +5V na pinie 14 portu, dzięki czemu będą działały samplery i inne urządzenia wykorzystujące zasilanie z tegoż pinu. Ze względu na swą specyfikę sygnał reset dla układu UART należało zanegować. Niestety nie starczyło wyprowadzeń układu GAL i należało zastosować dodatkowy tranzystor. Z podobnych powodów użyto tranzystora to sterowania linią zgłoszenia przerwania. Dane w standardzie TTL są konwertowane do +/-10V w układzie MAX241E. Układ ten ma budowę podobną do MAX232 tyle, że zawiera więcej konwerterów i wbudowane zabezpieczenie przed ESD.

Montaż i uruchomienie:
Montaż przeprowadzamy w nietypowy sposób. Najpierw wlutowujemy układ US4 który jest wykonany w technologii SMD. Proponuję najpierw przylutować jedną skrajną nóżkę. Po poprawnym ułożeniu układu na polach lutowniczych lutujemy pozostałe wyprowadzenia. Następnie wlutowujemy rezystory, podstawki pod układy, złącze CON1, tranzystory, kondensatory na końcu kwarc i złącza DB. Montażu złącz IDC trzeba poświęcić nieco więcej uwagi. Jest to spowodowane tym, że zdobycie złącz IDC22-2.0 jest beznadziejnie trudne. Posłużymy się więc złączem typu IDC34-2.0, z którego usuniemy po sześć skrajnych wyprowadzeń (rys. 4). Należy zwrócić uwagę na odpowiednie umieszczenie wycięcia uniemożliwiającego odwrotne umieszczenie wtyku w gnieździe. Od taśmy FLAT34 oddzielamy 12 przewodów, dzięki czemu pozostanie ich 22. Zaciskając wtyk od strony karty należy zwrócić uwagę na to, że pierwsze i ostatnie sześć pinów jest pominięte. Pierwszy przewód taśmy jest zaciśnięty na pinie 7 wtyku IDC. Złącze od strony komputera trzeba zacisnąć inaczej. Zaciskamy je tak, aby pin pierwszy był połączony z pierwszą żyłą taśmy, pozostałe 13 pinów złącza odcinamy (rys. 5). W miejscu odcięcia wskazane jest wpuszczenie kropli kleju, aby skleić dolną i górną część wtyku. W przeciwnym razie może się zdarzyć, że wyrwiemy taśmę z wtyku. Jest to spowodowane tym, że w odciętej części znajduje się zatrzask spinający obie części wtyku IDC34-2.0. Taśmę warto wykonać dłuższą. Dzięki temu jeśli będziemy chcieli podłączyć kolejną kartę wystarczy na taśmie zaciskać kolejne wtyki. Pod układy scalone DIL montujemy podstawki. Układ 8520 występuje w obudowie DIL40 i PLCC44. Płytka przystosowana jest do układów DIL. Jeśli posiadamy układ PLCC należy zastosować dodatkową przejściówkę. Po zmontowaniu karty, sprawdzeniu czy nie ma ewentualnych zwarć. Bez układów umieszczonych w podstawkach łączymy kartę z komputerem. Wszelkie operacje typu podłączanie odłączanie karty czy wkładanie wyjmowanie układów z podstawek wykonujemy przy wyłączonym zasilaniu komputera! Po włączeniu zasilania komputer powinien wystartować, a my możemy sprawdzić obecność napięć zasilających na podstawkach pod układy. Jeśli komputer nie startuje, oznacza to, że mamy zwarcie na płytce. W następnej kolejności umieszczamy w podstawce układ GAL i ponownie włączamy zasilanie komputera. Uruchamiamy program "TestGala" Najpierw jest przeprowadzany test automatyczny, jeśli jego wynik będzie pomyślny program można zakończyć. Gdy test wypadnie niepomyślnie program przejdzie do interaktywnego testu ręcznego. Podczas tego testu należy postępować zgodnie z instrukcjami na ekranie

. Gdy GAL funkcjonuje poprawnie można umieścić wszystkie układy w podstawkach. Po uruchomieniu programu "Szukanie" powinniśmy ujrzeć na ekranie adresy pod jakimi są widziane układy PAR i SER
. Jeśli posiadamy cztery złącza Clock na karcie z Zorro2 i w innym gnieździe znajduje się jakaś karta, to program może odnaleźć także układy na dodatkowych kartach. Do portu PAR podłączmy drukarkę. Po załączeniu zasilania komputera i uruchomieniu programu "Drukuj" na drukarce powinien pojawić się tekst próbny. Do gniazda portu SER wkładamy wtyczkę ze zwartymi wyprowadzeniami 2 i 3 po czym uruchamiamy program "Terminal". Na ekranie powinny pojawiać się znaki naciskane na klawiaturze. Po tych zabiegach możemy uznać, że karta jest sprawna. Jeśli nasza Amiga jest umieszczona w "wierzy" do karty mocujemy śledzia u umieszczamy kartę w wolnym miejscu obudowy. Jeśli Amiga jest w standardowej obudowie kartę portów warto umieścić w plastikowej obudowie serii KM. Taśmę można wyprowadzić z tyłu komputera podpiłowując lekko obudowę. Jeżeli posiadamy więcej kart MultiIO, to każdą z nich musimy testować osobno, tak aby podczas testu na wybranym porcie Clock była tylko jedna karta. Jest to spowodowane tym, że z powodu błędu montażowego rejestry układów GAL na różnych kartach mogłyby mieć różną zawartość. Spowodowałoby to pojawienie się fałszywych danych na magistrali. Podczas normalnej pracy sytuacja taka nie może mieć miejsca, ponieważ rejestry wszystkich układów GAL zawierają ten sam subadres.

Oprogramowanie:
Do portu dołączono oprogramowanie zawierające sterownik do portu PAR, SER i program przechwytujący dane wysyłane na urządzenie PRT

. Dzięki temu wydruk można skierować na dodatkowy port PAR. Sterowniki można ustawić na dowolny adres i subadres karty. Wyjaśniam co to jest adres (zwany też bazą lub adresem bazowym) i subadres. Adres karty to adres pod, którym znajduje się port Clock. Standardowo będzie to $d80001. Jeśli jednak w komputerze zainstalowana jest karta z Zorro-2 i czterema portami Clock porty są widziane pod następującymi adresami:
Clock0 - $d80001
Clock1 - $d84001
Clock2 - $d88001
Clock3 - $d8c001
Subadres natomiast to liczba wpisywana do rejestru układu GAL i tak:
SubAdres0 - PAR1
SubAdres1 - SER1
SubAdres2 - PAR2
SubAdres3 - SER2
SubAdres4 - PAR3
SubAdres5 - SER3
SubAdres6 - PAR4
SubAdres7 - SER4

Konfigurowanie sterowników jest dokładnie opisane w guide oprogramowania. Chcę przybliżyć sposób obsługi kart programistom zamierzającym wykorzystać porty w swoich programach. Jak robić to z poziomu systemu nie będę pisał, ponieważ jest to standardowa obsługa sterowników. Opiszę sposób mniej elegancki czyli z pominięciem sterowników. Sposób taki jest właściwie jedynym wyjściem, gdy piszemy program sterujący urządzeniem własnej budowy itp. Aby wpisać daną do rejestru wybranego układu najpierw musimy wpisać daną do rejestru układu GAL. I tu prośba do programistów, dajcie możliwość dowolnego ustalenia przez użytkownika zarówno adresu i subadresu. Na subadres można narzucić ograniczenie polegające na tym, że dla portów PAR subadres musi być parzysty dla SER nieparzysty. Dlaczego piszę o dowolnych adresach? Chodzi o to, że gdy powstanie karta dla Zorro-2 będzie miała zupełnie inne adresy niż port Clock, ale obsługa będzie taka sama! Dzięki temu w przyszłości użytkownik po zainstalowaniu nowej karty i zmianie ustawień będzie mógł podłączyć urządzenie do nowej karty. Ponadto użytkownik może mieć więcej niż jedną kartę MultiIO (max 16) i adres oraz subadres karty może być różny. Obsługa karty jest dość prosta. W przykładzie poniżej przedstawiłem sposób dostępu do pierwszego i trzeciego rejestru układu CIA. Przykład podałem w Basicu ponieważ bardzo łatwo przetłumaczyć go na C, AmigaE czy Asembler.
Poke Baza+%101100,SubAdres : Rem Uaktywnienie GAL'a
Poke Baza+2*4,$00 : Rem Wpis do trzeciego rejestru (PRA wejście)
xx=Peek (Baza+0*4) : Rem Odczyt pierwszego rejestru (odczyt portu PRA)

Wpis do układu GAL wystarczy przeprowadzić tylko raz na początku programu. Warto jednak przed wpisaniem danej zapamiętać stan rejestru GAL'a np.:
gal=Peek(Baza+%101100)
Po zakończeniu operacji na portach przywrócić starą zawartość rejestru GAL'a:
Poke Baza+%101100,gal

Jak łatwo zauważyć gdyby praca programu został przerwana np. przez przerwanie zawartość rejestry GAL mogłaby ulec zmianie. Na szczęście to nie nastąpi ponieważ w procedurze obsługi przerwania zawartość rejestru GAL jest zapamiętana i odtwarzana przy wyjściu z przerwania. Z rejestrem GAL'a kryje się jednak inne niebezpieczeństwo. Wyobraźmy sobie następującą sytuację:
- wpisujemy daną do rejestru GAL np. 0
- działamy na rejestrach układu
- następuje zmiana tasku, w której program wpisuje daną 1 do rejestru GAL
- task się skończył i dalej jest realizowany nasz program
zmiany jakie przeprowadzimy na rejestrach będą niestety dotyczyły innego układu ponieważ w rejestrze GAL jest liczba 1, a nie 0 Aby zabezpieczyć się przed taką sytuacją musimy użyć funkcji Forbid (ExecBase-132) i Permit (ExecBase-138). Przed zapisaniem danej do rejestru GAL wyłączamy multitasking wywołując Forbid, po zakończeniu obsługi rejestrów uruchamiamy multitasking przez Permit. Nie jest to jednak eleganckie rozwiązanie, tracimy atut Amigi jakim jest PRAWDZIWY MULTITASKING, (a nie udawany jak w PC). Ale i na to jest recepta. Jak wiadomo, gdy trwa przerwanie danego poziomu (w wypadku karty MultiIO poziomu 6) nie może ono zostać przerwane przez inne źródło na tym samym poziomie (w tym wypadku inną kartę MultiIO lub drugi układ na danej karcie). Poza tym podczas obsługi stanów wyjątkowych nie są obsługiwane przerwania (ani inne stany wyjątkowe) do póki procesor nie skończy obsługi stanu wyjątkowego. Nie jest więc możliwe, aby podczas obsługi przerwania 6 poziomu czy dowolnego stanu wyjątkowego program główny, inny stan wyjątkowy lub program przerwań zmienił zawartość rejestru SubAdresu układu GAL. Większości Amigowców stan wyjątkowy kojarzy się z czerwoną ramką GURU. Faktycznie większość wektorów stanów wyjątkowych jest skierowana na GURU. Wektory te można jednak zmienić. Wystarczy wektor instrukcji "TRAP #0" skierować na własną procedurę o nazwie np. "Odczyt_IO", natomiast "Trap #1" na "Zapis_IO". W procedurze tej zapamiętamy dawną zawartość rejestru GAL, wpiszemy nową (subadres obsługiwanego portu), odczytamy lub zapiszemy wybrany rejestr, po czym zwrócimy starą zawartość rejestru GAL i wyjdziemy ze stanu wyjątkowego. Manipulacje stanami wyjątkowymi zajmują trochę czasu procesora, ale to i tak mniej niż wywołanie funkcji Forbid Permit. Poza tym systemowa obsługa sterowników działa na przerwaniach, więc program korzystający z przerwań Trap nie będzie wolniejszy od systemowych sterowników. Dużej szybkości transferu nie da się osiągnąć także dlatego, że podczas dostępu do portu Clock wstawiane są takty oczekiwania przez kontroler magistrali. Maksymalną prędkość transmisji przez port równoległy można uzyskać tylko po skorzystaniu ze slotów Zorro-2. Obsługa karty z wykorzystaniem instrukcji Trap mogłoby wyglądać np. tak:

;---------------- Deklaracja stałych -------------
PRB		equ	1*4			;rejestr danych zewnętrznych dla portu danych B
DDRB		equ	3*4			;rejestr kierunku danych portu B

;---------------- Inicjalizacja ------------------
; Procedura "Init" jest wywoływana raz na początku programu
; obsługującego karty MiltiIO.
Init:		Move.l	$80,StaryAdresTrap0	;Zapamiętanie starych wektorów
		Move.l	$84,StaryAdresTrap1
		Lea	Odczyt_IO,a0		;Zapis nowego wektora Trap #0
		Move.l	a0,$80
		Lea	Zapis_IO,a0		; i Trap #1
		Move.l	a0,$84
		Move.l	#$d80001,Baza		;Wpisanie Adresu i SubAdresu
	Move.l	#0,SubAdres		; do zmiennych, najlepiej
						; aby dane to mógł zmienić
						; użytkownik programu np.
						; w ToolTypes ikony lub preferencjach
;----------- Program główny --------------
;Teraz procedura zapisu portu równoległego na MultiIO
; w rejestrze D1 podajemy ofset adresu rejestru portu względem bazy
; w rejestrze D0 umieszczamy daną do zapisu w rejestrze
		Move.w	#DDRB,d1		;Adres (przesunięcie) portu DDRB
		Move.b	#$ff,d0			;dana do wpisania do w/w portu (ustawi port na wyjście)
		Trap	#1			;wywołanie procedury zapisu portu
		Move.w	#PRB,d1			;Adres (przesunięcie) portu DDRB
		Move.b	#$55,d0			;dana do wpisania do w/w portu (zapisze $55 do portu
; równoległego)
		Trap	#1			;wywołanie procedury zapisu portu
;Teraz dla odmiany odczyt portu, podobnie jak przy zapisie
; w D1 umieszczamy ofset adresu portu, wynik odczytu jest zwracany
; w rejestrze D0
		Move.w	#PRB,d1			;Adres (przesunięcie) portu DDRB
		Trap	#0			;Odczyt stanu portu równoległego do rejestru D0

;-------------- Wyjście z programu ----------------
;Przy wyjściu z programu należy odtworzyć poprzednią zawartość wektorów Trap
		Move.l	StaryAdresTrap0,$80	;Odtworzenie wektora Trap #0
		Move.l	StaryAdresTrap1,$84	; i Trap #1
		Rts				;Wyjście z programu
				
;------------ Obsługa stanów wyjątkowych TRAP -------
;Procedura zapisu rejestru na karcie MultiIO
;we:	D0			- dana do zapisu
;	D1			- ofset (przesunięcie) rejestru do zapisu
;	wektor "baza"		- Adres bazowy karty MultiIO
;	wektor "SubAdres"	- Subadres układu na Karcie MultiIO
;wyjście:	--
;zmienia:	--
; 	
Zapis_IO:	Movem.l	a0/d2,-(sp)		;rejestry na stos
		Move.l	baza,a0			;Adres bazy karty IO do A0
		Move.b	%101100(a0),d2		;Zapamiętanie rejestru GAL'a
		Move.b	SubAdres,%101100(a0)	;Zapis rejestru GAL'a
		Move.b	d0,(A0,d1.w) 		;Zapis portu
		Move.b	d2,%101100(a0)		;Odtworzenie rejestru GAL'a
		Movem.l	(sp)+,a0/d2		;rejestry ze stosu
		Rte				;Wyjście ze stanu wyjątkowego TRAP #0

;Procedura odczytu rejestru z karty MultiIO
;wejście:	D1			- ofset (przesunięcie) rejestru do zapisu
;		wektor "baza"		- Adres bazowy karty MultiIO
;		wektor "SubAdres"	- Subadres układu na Karcie MultiIO
;wyjście:	D0			- odczytana dana
;zmienia:	--
; 	
Odczyt_IO:	Movem.l	a0/d2,-(sp)		;rejestry na stos
		Move.l	baza,a0			;Adres bazy karty IO do A0
		Move.b	%101100(a0),d2		;Zapamiętanie rejestru GAL'a
		Move.b	SubAdres,%101100(a0)	;Zapis rejestru GAL'a
		Move.b	(A0,d1.w),d0 		;Odczyt portu
		Move.b	d2,%101100(a0)		;Odtworzenie rejestru GAL'a
		Movem.l	(sp)+,a0/d2		;rejestry ze stosu
		Rte				Wyjście ze stanu wyjątkowego TRAP #1

;--------------- deklaracja zmiennych ----------
StaryAdresTrap0:	dc.l	0		;Tu jest przechowywana stara zawartość
StaryAdresTrap1:	dc.l	0		; wektorów Trap
Baza			dc.l	0		;A tu Adres bazowy i Subadres
SubAdres		dc.l	0
 
Po uruchomieniu powyższego programu z CLI Na port równoległy pierwszej karty MultiIO zostanie wysłana liczba $55 (dziesiętnie 85). Wartość odczytana z portu jest zwracana przez program w postaci błędu. Nr błędu odpowiada liczbie odczytanej z portu równoległego. W naszym przypadku zwracana jest wartość dziesiętna 85 czyli dokładnie to co zapisaliśmy do portu. Gdyby zmodyfikować program główny do postaci:
		Move.w	#DDRB,d1		;Adres (przesunięcie) portu DDRB
		Move.b	#$00,d0			;dana do wpisania do w/w portu
		Trap	#1			;wywołanie procedury zapisu portu
		Move.w	#PRB,d1			;Adres (przesunięcie) portu DDRB
		Trap	#0

Wtedy port pracowałby jako wejście i program zwracałby wartość błędu równą liczbie binarnej reprezentowanej na porcie. Należy pamiętać, aby po odczycie portu instrukcją "Trap #0" nie modyfikować zawartości rejestru D0. System operacyjny po zakończeniu działania programu sprawdza stan rejestru D0. Jeśli jest on różny od zera wartość ta jest traktowana jako błąd i wyświetlana w oknie. Jeśli wartość rejestru D0 jest równa 0 nie pojawia się żaden komunikat. Dlatego każdy program kończący się bezbłędnie przed instrukcją "RTS" ma umieszczoną instrukcję "Moveq #0,D0". Warto wspomnieć jeszcze o kodach 1...19. Nie są to kody błędów. Programy w ten sposób zwracają wynik swoich działań np. procedura sprawdzająca stan przycisku myszy zwraca -5 jeśli przycisk jest zwolniony.

Pozostało jeszcze omówienie rejestrów układów CIA i UART. W układzie 16C450 mamy dostęp do 10 portów (12 rejestrów):

Tablica1:
Adres		|	Nazwa		| Funkcja
------------------------------------------------------------------
Baza+0*4	|	THR/RBR	| bufor nadajnika-odbiornika
Baza+0*4	|	DLL		| mniej znaczący bajt podzielnika
Baza+1*4	|	IER		| rejestr konfiguracji przerwań
Baza+1*4	|	DLM		| bardziej znaczący bajt podzielnika
Baza+2*4	|	FCR/ISR	| rejestr identyfikacji przerwania
Baza+3*4	|	LCR		| rejestr formatu danych
Baza+4*4	|	MCR		| rejestr sygnałów wyjściowych
Baza+5*4	|	LSR		| rejestr stanu transmisji
Baza+6*4	|	MSR		| rejestr sygnałów wejściowych
Baza+7*4	|	SPR		| rejestr dodatkowy do zapisu odczytu
		|			| (nie ma w 8250)
------------------------------------------------------------------
Ze względu na to, że układ 16C450 ma trzy linie adresowe można z zaadresować w nim 8 portów. Liczba portów w układzie jest jednak większa, dlatego wprowadzono dodatkową sztuczną linię adresową. Jej funkcję pełni bit 7 w rejestrze LCR. Jeśli bit ten jest ustawiony pod adresem 0 i 1 są dostępne rejestry podzielnika (DLL, DLM), jeśli bit ten jest skasowany pod adresami 0 i 1 są dostępne bufory wejściowy-wyjściowy (THR/RBR) i rejestr kontroli przerwań (IER).
Rejestr RBR - odczytany bajt z linii SIN (RxD). Czy bajt został już skompletowany i czy nie wystąpiły błędy transmisji sprawdzamy w rejestrze stanu LSR.
Rejestr THR - wpisany bajt jest transmitowany szeregowo linią SOUT (TxD), z prędkością określoną rejestrami podzielnika i częstotliwości generatora. Przed wpisem rejestru należy sprawdzić, czy poprzedni bajt został już nadany (rejestr LSR).
Rejestr IER uaktywnia bądź kasuje możliwość generowania przerwań:
b3 1 - przerwanie generowane po zmianie stanu linii CTS, DSR, DCD lub RI
b2 1 - przerwanie generowane w wyniku błędu parzystości, protokołu, przepełniania lub zerwania połączenia
b1 1 - przerwania generowane na skutek opróżnienia rejestru przesuwnego nadajnika
b0 1 - przerwania generowane gdy w buforze odbiornika znajduje się bajt danych
W rejestrze ISR znajduje się informacja o przyczynie przerwania (jeśli zostały włączone odpowiednim ustawieniem rejestru IER). Ustawiony bit 0 informuje o wystąpieniu przerwania. Bity 1 i 2 informują o przyczynie tegoż przerwania, i tak:
Bity poziom przyczyna przerwania
b2=0, b1=0 3 zmiana stanu jednego z sygnałów sterujących CTS, DSR, RI, DCD)
b2=0, b1=1 2 bufor nadajnika pusty
b2=1, b1=0 1 w buforze odbiornika znajduje się znak
b2=1, b1=1 0 stwierdzono błąd parzystości, protokołu, przepełnienie
bufora odbiornika lub zerwanie łączności
Przerwanie kasuje się:
- dla poziomu3 odczytując rejestr MSR
- dla poziomu2 wpisując bajt do THR
- dla poziomu1 odczytując RHR
- dla poziomu0 odczytując rejestr LSR
Rejestrem LCR ustawiamy format danych:
b7		Czwarta sztuczna linia adresowa			0 - udostępnienie rejestrów THR, RHR i IER
			1 - udostępnienie rejestrów DLL i DLM
b6		Przerwanie połączenia:
			1-przerwanie połączenia (Break) przez wymuszenie stanu 0 na wyjściu SOUT
b5...3	Tryb kontroli parzystości:
			000 - brak kontroli
			001 - nieparzystość
			011 - parzystość
			100 - bit zawsze ustawiony na 1
			111 - bit zawsze ustawiony na 0
b2		Liczba bitów stopu:
			0 - 1 bit stopu
			1 - 2 bity stopu
b1..0		Liczba bitów danych:
			00 - 5 bitów
			01 - 6 bitów
			10 - 7 bitów
			11 - 8 bitów
Przez czas w którym bit 6 jest ustawiony wyjście SOUT przyjmuje poziom niski, a zatem na linii TxD pojawia się napięcie +12V. Stan ten należy odróżnić od braku danych kiedy to wyjście SOUT znajduje się w wysokim stanie logicznym. Rejestr MCR steruje liniami wyjściowymi RTD, DTR, OUT1 i OUT2:
b4 - 1 połączenie wyjścia SOUT układu UART z wejściem SIN
b3 - 1 aktywowanie sygnału OUT2
b2 - 1 aktywowanie sygnału OUT1
b1 - 1 aktywowanie sygnału RTS
b0 - 1 aktywowanie sygnału DTR
Łącząc wyjście SOUT z wejściem SIN możemy przetestować funkcjonowanie układu UART. Nadawane znaki pojawiają się w buforze odbiorczym. Ze względy na to, że "zapętlenie" sygnałów przeprowadzone jest wewnątrz układu, nie są testowane konwertery nadawczo-odbiorcze. Wyjścia OUT1 i OUT2 wyprowadzone są na zewnątrz układu, ale nie są do niczego podłączone. Można je wykorzystać w dowolny sposób.
Rejestr LSR informuje w jakim stanie w danym momencie znajduje się część nadawcza i odbiorcza układu UART:b6		0 - w buforze odbiornika albo w rejestrze przesuwnym nadajnika
znajdują się dane1- bufor odbiornika i rejestr przesuwny nadajnika są puste
b5		1- rejestr przesuwny nadajnika jest pustyb4		1 - połączenie zostało przerwane (Break)b3		1 - błąd protokołu (niezgodny format danych lub prędkość transmisji)
b2		1 - błąd parzystości
b1		1 - przepełniony bufor odbiornika
b0		0 - bufor odbiornika pusty
		1 - odebrany bajt spoczywa w buforze odbiornika
W rejestrze MSR można odczytać stan linii wejściowych:
b7		Sygnał DCD jest:	0 - nieaktywny
					1 -aktywny
b6		Sygnał RI jest:	0 - nieaktywny
					1 -aktywny
b5		Sygnał DSR jest:	0 - nieaktywny
					1 -aktywny
b4		Sygnał CTS jest:	0 - nieaktywny
					1 -aktywny
b3		1 -stwierdzono zmianą poziomu sygnału DCD
b2		1 -stwierdzono zmianą poziomu sygnału RI
b1		1 -stwierdzono zmianą poziomu sygnału DSR
b0		1 -stwierdzono zmianą poziomu sygnału CTS
Bity 0...3 zawierają informację o ewentualnej zmianie stanu danej linii od ostatniego odczytu rejestru. Po odczycie rejestru bity 0...3 są kasowane.
Rejestr SPR zachowuje się jak komórka pamięci. Można w nim przechowywać dowolną liczbę 8-bit/ Ustawienia rejestru w żaden sposób nie wpływają na pracę układu UART.
Rejestry DLL i DML dzielą sygnał zegarowy tak, aby uzyskać wymaganą prędkość transmisji. Aby uzyskać prędkość transmisji równą 2400bd należy do rejestrów DML i DLL wpisać odpowiednio: 1 (w hex $01) i 31 (w hex $21). Wynika to ze wzoru:
DL=Fclk/16/(Baud+1)
DLM=DL/256
DLL=DL-DLM
gdzie:
Baud - żądana prędkość transmisji
Fclk - częstotliwość generatora (w przykładzie 11059200Hz)
UART 16C550 ma dodatkowo 16 bitowy bufor odbiorczy FIFO. Buforem sterują dodatkowe bity rejestry FCR i ISR.

Poniżej znajduje się prosty program wysyłający znaki z klawiatury na port RS z prędkością 4800bd, format ramki 8N1.

SPARE=$D80001
RTC=$D80001 		: Rem Adres bazowy GAL'a
RTC=RTC+%101100 	: Rem Adres zapisu rejestru Gal'a
'        |  |
'        |  \---- Adr2
'        \------- Adr5

RHR=0*4			;Rem Definicja rejestrów UART'a
THR=0*4
IER=1*4
ISR=2*4
FCR=2*4
LCR=3*4
MCR=4*4
LSR=5*4
MSR=6*4
SPR=7*4
DLL=0*4
DLM=1*4


SPARE=$D80001		:Rem Wybór adresu i subadresu
SUB=1

Poke RTC,SUB 		: Rem Wybór portu Ser na karcie

'------- Programowy Reset UART'a --------- 
Poke SPARE+LCR,0
Poke SPARE+IER,0
Poke SPARE+ISR,1
Poke SPARE+MCR,0
Poke SPARE+LSR,0
Poke SPARE+MSR,0
Poke SPARE+SPR,$FF

'-------- Inicjalizacja UART'a --------- 
Poke SPARE+LCR,$80 	: Rem Wybór rejestrów szybkości w miejsce RHR(THR) i IER
Poke SPARE+DLM,$0 	: Rem  Szybkość 4800 - Starszy
Poke SPARE+DLL,$90 	: Rem Szybkość 4800 - Młodszy
Poke SPARE+LCR,%11 	: Rem liczba bitów, parzystość, ustawienie RHR(THR) i IER w miejsce DLL i DLM
Poke SPARE+IER,0 	: Rem   Przerwania wyłączone

Poke SPARE+MCR,%11 : Rem ustawienie linii RTS i DTR


Cls : Print 		: Rem Czyszczenie ekranu i opuszczenie o jedną linię w dół
Do
   '----------- To emuluje terminal, naciskane znaki zostaną wysłane po RS -----
   K$=Inkey$ 				:Rem Jeśli naciśnięto klawisz
   If K$<>""
      If Btst(6,ST)=True 		:Rem i jeśli bufor nadawczy pusty
         Poke SPARE+THR,Asc(K$) 	:Rem to wyślij znak do bufora nadawczego
      End If
   End If
   Exit If K$=Chr$(27)
Loop 


Poniższa procedura w pętli głównej wyświetlałaby znaki przychodzące po RS na ekranie:
ST=Peek(SPARE+LSR) : Rem Czyta status
If Btst(0,ST)=True : Rem Jeśli bufor odbiorczy pełny to wyświetla znak
   Print Chr$(Peek(SPARE+RHR)); 	:Rem Odczyt bufora odbiorczego kasuje znacznik
:Rem  w rejestrze statusu (LSR)
End If
Układ CIA ma 16 rejestrów, z czego w naszej karcie dostęp mamy do 15 rejestrów. W praktyce wykorzystujemy 5 rejestrów. Jest to spowodowane złym funkcjonowaniem timerów spowodowane odtwarzaniem sygnału E. Wszystkie funkcje układu CIA wykorzystamy dopiero, gdy będzie on zamontowany na karcie Zorro-2. Funkcje rejestru CIA są następujące:
Tablica2:
Adres		| Nazwa	|	Funkcja
-----------------------------------------------------------------------
Baza+0*4	| PRA		| rejestr danych zewnętrznych dla portu danych A
Baza+1*4	| PRB		| rejestr danych zewnętrznych dla portu danych B
Baza+2*4	| DDRA	| rejestr kierunku danych portu A
Baza+3*4	| DDRB	| rejestr kierunku danych portu B
Baza+4*4	| TALO	| młodszy bajt zegara A
Baza+5*4	| TAHI	| starszy bajt zegara A
Baza+6*4	| TBLO	| młodszy bajt zegara B
Baza+7*4	| TBHI	| starszy bajt zegara B
Baza+8*4	| TODLO	| młodszy bajt licznika TOD
Baza+9*4	| TODMID	| środkowy bajt licznika TOD
Baza+10*4	| TODHI	| starszy bajt licznika TOD
Baza+11*4	| TODHR	| nie używany
|		| (pod tym adresem znajduje się rejestr GAL'a)
Baza+12*4	| SDR		| rejestr danych szeregowych
Baza+13*4	| ICR		| rejestr kontroli przerwań
Baza+14*4	| CRA		| rejestr kontrolny A
Baza+15*4	| CRB		| rejestr kontrolny B
-----------------------------------------------------------------------
Rejestr DDRB ustala kierunek linii portu Parallel. Wpisanie jedynki na bit 0 rejestru DDRB spowoduje, że pin 2 portu parallel będzie linią wyjściową. Wpisanie 0 spowoduje, że pin 2 portu będzie linią wejściową. Bit 1 ustala kierunek linii 3 portu, bit 2 linii 4, itd. do bitu 7 odpowiedzialnego za pin 9. Wpisanie liczby 255 ($ff) ustawi linie 2...9 jako wyjściowe, liczba 0 ustawi linie jako wejściowe.
Rejestr PRB służy do odczytu danych z linii 2...9 portu parallel, gdy port pracuje jako wejście, lub zapisu stanu na liniach 2..9 portu, gdy pracuje jako wyjście. Warto omówić przypadek, gdy część linii będzie ustawione jako wejścia, a część jako wyjścia. Wpiszmy i uruchommy program:
Baza=$d80001 	: Rem Adres karty portów
Subadres=0 		: Rem Subadres portu na karcie
PRA=Baza+0*4 	: Rem Przypisanie adresów rejestrów układu CIA i GAL
PRB=Baza+1*4
DDRA=Baza+2*4
DDRB=Baza+3*4
GAL=Baza+%101100
Poke GAL,Subadres : Rem Uaktywnienie jednej z kart portów
Poke DDRB,$F0 	  : Rem Ustawienie bitów 0...3 portu jako wejście,
		  : Rem bitów 4...7 jako wyjście
Poke PRB,%10101010 : Rem Zapisanie danych na port
Print "Stan portu ";Bin$(Peek(PRA)) : Rem Odczytanie i wyświetlenie stanu portu
na ekranie użyjmy (zakładam, że do portu nie jest nic podłączone, a w szczególności drukarka lub inne urządzenie z dwukierunkowym interfejsem):
Stan portu %10101111
Jak można wywnioskować dane daje się zapisać tylko na te linie portu PRB, na których w rejestrze DDRB znajdują się jedynki. Zapis do linii ustawionych jako wejścia zostaje zignorowany. To jest największa różnica portu 8520 w stosunku do portów pseudo-dwukierunkowych. Działanie portu 8520 jest takie samo jak portów w procesorach serii AVR. Warto jeszcze wspomnieć, że każdy zapis lub odczyt rejestru PRB powoduje pojawienie się ujemnego impulsu, o czasie trwania około 200ns, na linii 1 portu parallel. Dzięki temu po wpisaniu danej do PRB automatycznie jest generowany strob informujący drukarkę o tym, że dane na porcie są ustalone. Gdyby port pracował jako wejściowy, strob poinformuje urządzenie nadające, że dane zostały przyjęte i można wysłać kolejną daną.
Rejestry TALO,TAHI, ABLO, TBHI, TODLO,TODMID, TODHI, SDR, CRA i CRB obsługują timery, zegar czasu rzeczywistego i rejestr szeregowy względu na sposób generowania sygnału E nie mogą zostać wykorzystane.
Dość nietypowo obsługuje się rejestr kontroli przerwań ICR. Wpisu jąć liczbę z ustawionym bitem 7 spowodujemy, że wszystkie przerzutniki sterujące zgłoszeniem przerwań przyporządkowane ustawionym bitom 0...6 zostaną ustawione. Jeśli bit 7 byłby wyzerowany wszystkie przerzutniki przyporządkowane ustawionym bitom 0...6 zostałyby skasowane. Najłatwiej zrozumieć to na przykładzie:
ICR=d*4
Poke Baza+ICR,%10010011
ustawi przerzutniki sterujące przerwaniami przyłączone do bitów 0, 1 i 4, natomiast:
Poke Baza+ICR,%00001101
skasuje przerzutniki przyłączone do bitów 0, 2 i 3.
W rejestrze tym interesuje nas bit 4, którym można ustawić lub zamaskować przerwania generowane przez linię ACK (pin 10) portu równoległego. Pozostałe bity odpowiadają za włączenie przerwań od timera A, B, zegara TOD i rejestru szeregowego, które nie będą generować przerwań z powodu nietypowego generowania sygnału E. Rejestr ICR przy odczycie informuje o źródle przerwania. Ustawienie bitu 7 informuje, że wystąpiło jakieś przerwanie, natomiast bity 0...6 informują, który z układów wewnętrznych (timer A, B, rejestr przesuwny, alarm TOD) je wygenerował. W naszym przypadku źródłem przerwań może być tylko linia FLAG (linia ACK portu równoległego). Należy pamiętać, że po odczycie zawartość rejestru ICR jest automatycznie kasowana, a co za tym idzie linia przerwania przechodzi do stanu nieaktywnego.
Więcej szczegółów dotyczących obsługi układu CIA i UART można znaleźć w kodach źródłowych dostępnych razem ze sterownikiem.

Jeśli czytelnicy będą mieli problemy w zdobyciu złącz FC 2.00mm, taśmy FLAT 1.00mm, układów CIA 8520 czy brak możliwości zaprogramowania GAL'a, mogą o pomoc zwrócić się do Sławomira Skrzyńskiego. Sławomir Skrzyński AVT, slawomir.skrzynski@ep.com.pl

Pliki do pobrania
Spakowany artykuł
programy
Schemat i rysunek płytki

Urządzenie jest już gotowe, ale nie są jeszcze napisane sterowniki. Osoby które podjęły by się tego zadania proszę o kontakt info@r-mik.com.pl , warunki do uzgodnienia.

UWAGA!
O pojawieniu się urządzenia w sprzedaży zadecyduje liczba chętnych. Jeśli deklarujesz chęć nabycia urządzenia wypełnij i wyślij formularz

Portem od 01.11.2001 zainteresowało się Licznik odwiedzin osób.