CA82

uniwersalny sterownik mikroprocesorowy


charakterystyka i informacje ogólne
książki / dokumentacja (literatura)
ulotki i broszurki MIK (literatura)
skany artykułów z prasy (literatura)
programator EPROM (aplikacje)
dwupunktowy termometr (aplikacje)
licznik-timer Z80-CTC i dioda RGB (aplikacje)
Direct Memory Loader - ładowarka do pamięci (akcesoria)
próbnik stanów logicznych MIK03C (akcesoria)
zdalnie sterowana klawiatura (akcesoria)
przegląd procedur systemowych (programowanie)
interfejs RS-232 z układem Z80-SIO/0
hex2wav - ładowanie programów do CA80 z plików audio
sterownik mikroprocesorowy CA82

☘☘☘☘☘☘☘☘☘☘☘☘☘☘

-- ♠ --


CA82 w pigułce

System CA82 to jakby minimalistyczna wersja CA80, przeznaczona jak łatwo zgadnąć do zastosowań wbudowanych. Płytka bazowa zawiera tylko jeden układ 8255 (adres 0xE0) i jest on przeznaczony dla użytkownika. Pamięć podzielona na dwa banki: 0x0000 (32kB ROM), 0x8000 (32kB RAM), domyślne krosy na płytce zapewniają pracę układów odpowiednio EPROM 2732/64 oraz SRAM 6116/M48Z02. Procesor taktowany jest zegarem 4MHz, przerwania NMI zgłaszane z zespołu liczników mają częstotliwość 400Hz. Płytka drukowana (tu w wersji przed odświeżeniem i testowym uruchomieniem):



Detalicznie informacje o CA82 znajdują się w tomiku MIK11, rodział `4.0 Uniwersalny sterownik mikroprocesrorowy`, z nich pozwolę sobie zacytować schemat ideowy, ponieważ to w tym miejscu najważniejsze. Do kompletu szczerze polecam lekturę rozdziału `4.0 Istotne błedy w dokumentacji CA80` tomiku MIK09, niestety opis CA82 z MIK11 nie jest pozbawiony drobnych pomyłek.





Płytka sterownika nieco doczyszczona, odświeżone podstawki - no niestety, dostało się bidzie od życia i po latkach ponad dwudziestu jest przy nim co robić. Dolutowany komplet kondensatorów blokujących zasilanie, wymiana kilku rezystorów (były wartości od czapki no i jeden ukruszony). W okolicach kwarcu bałam się coś dłubać, oscylator wystartował na 8MHz a cherlawe druciki na spodzie płytki skutecznie odstraszały przed ewentualnymi poprawkami. Kątowe złącze igłowe (to od 8255) oczyściłam z glutków z cyny i można na nim bezpiecznie zapinać kabelki do płytki stykowej. Po drugiej stronie PCB jest wyprowadzona szyna systemowa, dałam tam grzebyk, ale prosty, ponieważ kątowej listwy chwilowo u mnie brak. Odnośnie kostek - mamy oryginalnego Zilog-a, a PIO jest od Mitsubishi. Pamięć 2kB to D4460 od NEC, czyli klimaty `eighties` zapewnione.



Po raz kolejny w pełnej krasie ukazuje swą przydatność genialny emulator pamięci EPROM AVT-270, jak kitów-składaków nie lubię tak ten jest naprawdę super. Dodatkowo wespół z przelotką USB/LPT zapewnia mi na Linux ładowanie plików binarnych zwykłym konsolowym poleceniem cp. Tu mamy emulator wpięty w podstawkę U9, domyślnie ustawia się na emulację 2764 więc tak naprawdę po włączeniu zasilania nic nie musżę już robić, zabawka jest gotowa do pracy.



No i oczywiście smoke-test odrobinę ogarniętego gracika, program bez szału ale szkoda mi było czasu tracić na coś bardziej fikuśniego, skoro nie byłam pewna, czy systemik w ogóle ruszy. No, nie powiem, atrakcje też były, ale natury kontaktowej, elektromechanicznej. Po prostu po tylu latach styki w podstawkach niezbyt chciały kontaktować, pomogło wyjęcie wszystkich kostek i ponownie włożenie, sterownik finalnie zadziałał. Program testowy inicjuje dedykowany użytkownikowi układ 8255, wszystkie porty ustawiając na OUT. W pętli głównej inkrementuje wartość na porcie PA, co daje serie szybkich impulsów. W procedurze obsługi przerwania NMI wywoływanej dla odmiany co 2.5 ms (400Hz czyli inaczej niż w CA80 gdzie jest 500Hz / 2ms) mamy inkrementacje portu PB. Przemycenie wartości przez zmienną w RAM oraz obsługa NMI (wykorzystanie stosu w tle) pozwala `dotknać` pamięci RAM. Obserwacja działania malca na dwóch próbnikach logicznych od HP - impulsy są, co mnie nie ukrywam całkowicie na chwilę obecną zadowala.

.cr	Z80
		.tf	test.bin,BIN
		.lf	test.lst
BVAR	.eq		$8000
		.or 	$0000		
        ; na fochy coniektorych CPU
		nop
		nop
		nop
		nop
        ; inicjalizacja 8255, wszystko OUT
		ld A,$80
		out ($E0+3),A
		xor A
		out ($E0+0),A
		out ($E0+1),A
		; impulsy numer jeden, na port PA
main:	
		inc A
		out ($E0+0),A
        jp main

        ; impulsy numer 2, w NMI, na port PB
		.no $66
		push AF
		push HL
		ld HL,BVAR
		ld A,(HL)
		inc A
		ld (HL),A
		out ($E0+1),A
		pop HL
		pop AF
		retn

Na koniec pierwszego odcinka krótki filmik z działającym sterownikiem CA82 w roli głównej.



Małe, a cieszy...

CA82 - aplikacje - DLR1414

Taki oto ciekawy złom przytrafił mi sie ponad rok temu na elektroniczej targowicy, także i rok czekał grzecznie na swoje pięć minut w mediach.



Pomijając inne ciekawe kostki, z płyty owej najistotniejsze są teraz cudne wyświetlacze matrycowe DLR1414, których specyfikację wskazuję linkiem: Wyświetlacz diodowy LED 4-znakowy 7 x 5. Wyswietlacze te to już relikt przeszłości więc tym bardziej komponują się z CA82. Plan chytry jest taki, aby je podłaczyć do portów 8255 i choćby zgrubnie oprogramować. Oczywiście najpierw konieczna jest ekstrakcja znalezisk ze zdobycznej płyty, pomocną okazała się lutownica hot-air, choć stres był, nie ukrywam to moduly przetrwały operację bez szwanku, uff.



Wstępnie podrutowana instalacja testowa i uruchomienie modulków tylko na zasilaniu. W dokumentacji lojalnie uprzedzają, że matryca ledowa po załączeniu zasilania jest w `random state`, no i właśnie to widzimy. Objawiła się przypadkowa jak to się kolokwialnie mawia kaszanka, ale potwierdzająca, że układom nie stała się krzywda podczas wylutowywania.



Na podstawie dokumentacji do DLR1414 powstał taki schemat - to zalecany sposób rozszerzenia pola odczytowego. Adresy A0 oraz A1 są wspólne dla wszystkich modułów, sygnał zapistu /WR generowany jest w dekoderze 1/8 na bazie układu 74138. W ten sposób dostajemy adresowany pięcioma liniami zestaw dwudziestu pól odczytowych. Linie danych wyswietlaczy (uwaga na żarcik - jeno siedem sztuk, D0..D6) zapięte do portu PA układu 8255, linie adresowe do kolejnych wyjść portu PB, tam też pozytywne wejście zezwalające E3 dekodera, pracujące w roli sygnału zapisującego dane do modułów. Zauważamy, że sygnał na linii PB.5 pracuje w logice dodatniej - stan H wpisuje dane do wyświetlaczy, co wynika z tabeli prawdy dekodera `138, no tak.



Teraz czas na pracę własną z klawiaturą - kompletny programik testowy widzimy poniżej.

.cr	Z80
		.tf	dlr1414-1.bin,BIN
		.lf	dlr1414-1.lst

PA_8255	.eq	$E0
PB_8255	.eq	$E1
PC_8255	.eq	$E2
CT_8255	.eq	$E3

		.or 	$0000		
		nop
		nop
		nop
		nop
		jp	main

		; NMI
		.no $66
		retn

main
		call pioInit
loop:

		ld HL, msg1
		call dlr1414putStr
		call delay
		ld HL, msg2
		call dlr1414putStr
		call delay
		ld HL, msg3
		call dlr1414putStr
		call delay
        jp      loop


msg1:	.az 'to jest test        '
msg2:	.az 'zdobycznych modulkow'
msg3:	.az '  DLR1414 na CA82   '

delay:
		push BC
		ld B,200
.del1
		halt
		halt
		djnz .del1
		pop BC
		ret

;---------------------------------------

pioInit:
		ld A,$80
		out (CT_8255),A
		xor A
		out (PA_8255),A
		out (PB_8255),A
		ret

;---------------------------------------

		; HL - ptr napis 
dlr1414putStr:
		ld B,20			; 20 znaków, 5 x DR1414

.puts:
		ld A,(HL)		; *ptr
		cp 	$00
		jp	Z,.putsEnd
		out (PA_8255),A		
		ld A,B
		dec A
		or A,0x20		; sygnał write, PB.4
		out (PB_8255),A	; __/--
		ld A,B
		out (PB_8255),A   ;       --\__
		inc HL			; ptr++
		djnz .puts
.putsEnd
		ret

Detali tłumaczyć chyba nie musze, ale dwa słowa wyjasnienia odnośnie procedurki dlr1414putStr jednak się należą. Jeżeli popatrzeć na schemat ideowy i w sumie fizyczną realizację układu - adresy najmłodszych pól odczytowych są po prawej stronie, kolejne adresy znaczków to kolejne idąc w lewo cześci wyświetlacza. Napis w pamięci (tabela bajtów, string) również zaczyna się od zerowego elementu, kolejne znaki to kolejne, wzrastające adresy i stąd konieczność odwrócenia kolejnosci wybierania danych wzgledem wyboru pól oczytowych. Adres napisu do wyświetlenia podajemy via rejestr HL, na wyświetlacz idzie maksymalnie 20 znaków, chyba że napis zakończy się wcześniej znakiem 0x00 (NULL), oczywiste jest, że operaujemy zestawem znaków ASCII wyszczególnionym w dokumentacji kostki DLR, a jak widać - wystarcza on w zupełnosci do podstawowych zastosowań.



Filmik z działającym programem testowym mamy poniżej, nie jest to jakieś wielkie halo, ale skutecznie poświadcza, że mały CA82 jest całkowiecie sprawny i można go zaganiać do coraz to ciekawszych aplikacji.



(nieśmiertelny) termometr z zegarkiem - programowanie w C

Celem poniższego ćwiczenia jest sprawdzenie, jakby tu zaprogramować system CA82 w języku C, dodatkowy warunek to minimalne wykorzystanie wstawek assemblerowych. Oczywiście spreparowanie klasycznego `hello world` na wyświetlaczach byłoby nudne, stąd tytułowy, dyżurny termometr z zegarkiem. Temat też w sumie oklepany, ale daje się relatywnie szybko zrealizować i jednoczesnie pozwala dotknąć wszelkich aspektów wykorzystania pakietu SDCC w kontekście komputerka CA82.
Nie ukrywam, poszłam nieco na łatwiznę i cześć elektroniczna do złudzenia przypomina układ znany z dwupunktowego termometru do dużego (jak to brzmi) CA80. Mała zmiana to wykorzystanie przetwornika 10-bitowego TLC1549 oraz źródełka napięcia odniesienia MCP1541 w kwocie 4.096V. Schemat ideowy instalacji testowej widzimy poniżej:



Realizacja oczywiście na płytce stykowej, bożkom celtyckim dziękować należy, że takie pająki w ogóle pracują:



No i zabieramy się za oprogramowanie zabawki. Tak, miało nie być wstawek asseblerowych, ale niestety bez podstawienia zmodyfikowanego kodu rozruchowego niewiele nam zadziała, już tłumaczę. Urządzonko ma oprócz mierzenia temperatury realizować także najprostszy z możliwych zegar czasu rzeczywistego. Skoro do procesora mamy doprowadzony sygnał przerwań NMI o częstotliwości 400Hz to należy go wykorzystać, właśnie do napędu procedury odliczającej czas. Porcedury obsługi przerwań (handlery) IRQ umiemy już w SDCC tworzyć, było pisane na Forum uG wielokrotnie - słowo kluczowe __interrupt zapewnia nam zastapienie rozkazu RET/C9 rozkazem RETI/ED4D (tak!, opcode ma 2 bajty) i wszystko gra. Fizyczną lokalizacją handlera nie musimy się zamartwiać - przecież jej adres umieszczamy w tabeli wektorów przerwań, więc może być (prawie) gdziekolwiek. Z przerwaniem niemaskowalnym NMI jest deko gorzej. Oczywiście SDCC w łaskawości swej dostarcza słowo kluczowe __critical, które wespół z __interrupt wymuszą wyjście z procedury obsługi rozkazem RETN/ED45 ale co z lokalizacją kodu handlera? Ano nic, martw się sama! Procesor Z80 skonstruowany jest tak, że obsługa NMI oznacza wywołanie pod adres 0x0066, to fakt ogólnie znany. No i właśnie dlatego trzeba nieco podrasować kod rozruchowy, aby pod tym właśnie adresem był skok do etykiety opiewającej na naszą własną, pracowicie przygotowaną procedurkę, wystarczy zwykły skok bezwarunkowy JP/C3. Kod rzeczonej procedury napiszemy już w czystym C. Cytat z pliku crt0ca82.s:

    .module crt0
    .globl	_main
    .globl 	_NMI_handler
	.area	_HEADER (ABS)
	; Reset vector
	.org 	0x0000       
init:
	; Stack at the top of memory.
	ld	sp,#0xFFFF       
    ; Initialise global variables
    call    gsinit
	call	_main
1$: jp      1$  
    ; ( !!!! )
	.org 0x0066
	jp _NMI_handler
	; i tak dalej ...

I tu póki co żegnamy się z assemblerem, obsługa NMI - czyli odliczanie czasu - zrealizowana jest w C, o przykładowo tak:


unsigned char hours = 0;
unsigned char minutes = 0;
unsigned char seconds = 0;
unsigned char tenths = 0;
unsigned char nmiCntr = 0;

void updateClock(void) {
	tenths++;
	if ( tenths == 10 ) {
		tenths = 0;
		seconds++;
		if ( seconds == 60 ) {
			seconds = 0;
			minutes++;
			if ( minutes == 60 ) {
				minutes = 0;
				hours++;
				if ( hours == 24 ) {
					hours = 0;
				}
			}
		}
	}
}

void NMI_handler(void) __interrupt __critical {    
	nmiCntr++;
	if ( nmiCntr == 40 ) {
		nmiCntr = 0;
		updateClock(); // co 100 ms.
	}	
}

Zauważmy, że nazwa procedury obsługi NMI_handler musi odpowiadać tej, którą zadeklarowaliśmy w pliku crt0ca82.s dyrektywą .globl - inaczej linker nam się rozpłacze podczas sklejania fragmentów aplikacji w całość.
Kolejna sprawa to obsługa tych fajnych wyświetlaczyków DLR1414, technicznie sprowadza się to do operacji na portach I/O procesora Z80. O tym też było pisane na Forum uG, tu w formie cytatu - deklaracje portów dla 8255 użytkownika, funkcja pisząca po wyświetlaczach, no i oczywiście konfiguracja kostki we-wy:

__sfr __at 0xE0 USER8255_PA;
__sfr __at 0xE1 USER8255_PB;
__sfr __at 0xE2 USER8255_PC;
__sfr __at 0xE3 USER8255_CTRL;

void dlr1414putStr( char *pS ) {
	char *p = pS;
	int n = 19;
	while ( *p && (n >= 0) ) {
		USER8255_PA = *p;
		USER8255_PB	= n;
		USER8255_PB	= 0x20 + n;
		USER8255_PB	= n;
		p++;
		--n;
    }
}

void main( void ) {
    //...
    // ustawienia portu uzytkownika
	USER8255_CTRL = 0x88; // PC74-in, reszta-out
	USER8255_PA = 0x00;
	USER8255_PB = 0x00;
	USER8255_PC = 0x01; //  /CS=1, CLK=0    
    //...
}

Do pełni szczęścia brakuje nam tylko odpytywania przetwornika ADC o aktualny (tak po prawdzie - ostatnio wykonany) pomiar:
unsigned short getTLC1549( void ) {
	unsigned short out = 0;
	unsigned char n;
	USER8255_PC = 0;	// CLK=0, /CS=0
	for ( n = 0; n < 10; n++ ) {
		out = out << 1;
		out = out | ( USER8255_PC & 0x80 ? 1 : 0 );
		USER8255_PC = 2; // CLK=1, /CS=0
		USER8255_PC = 0; // CLK=0, /CS=0
	}
	USER8255_PC = 1;	// CLK=0, /CS=1	
	return out;
}

Pozostała część kodu to już zwykła-niezwykła rzeźba w C, walka z zaokrągleniami, fochami funkcji sprintf() /naprawdę dzięki bardzo za brak obsługi formatowania floatów :(/ czyli tak zwana proza życia. Cały kod źródłowy zegarko-termometru znajduje się tu: ca82/ca82_nmi_termoclock

Termometr przez ostatnie dni nieco ewoluował, stąd i zawartość wyświetlacza jest różna i zależna od zaawansowania prac i poziomu mojej furii, proszę oto stan bardzo pośredni:





Po drobnych perypetiach z uśrednianiem wyników i rezygnacją ze zmuszania MCP9700 o dokładności ±2°C do aptekarskich wyczynów z dziesiątymi częściami stopnia, stanęło na takiej jak niżej postaci wyświetlacza:





Wniosek z opowiastki, poparty migającymi dowodami rzeczowymi nasuwa się taki, że w SDCC da się oprogramować sytemik CA82 i można to zrobić z minimalnym udziałem niskopoziomowych asseblerowych atrakcji. Fakt, że nasza aplikacja startuje od 0x0000 (czyli że ma dla siebie cały obszar ROM) w sumie ułatwia sprawę, nie musimy szukać kompromisów i dopasowywać się do realiów systemu - to my te realia właśnie definiujemy. I jest to (tak myślę) całkiem ciekawe doświadczenie.


c.d.n.


#slowanawiatr, listopad/~ 2019

Natasza Biecek 2004-2019/~, e-mail