24-BIT PIO für 15 Mark

Ein Nachteil beim Atari ST ist das Fehlen einer parallelen Ein-/ Ausgabeeinheit (kurz PIO), mit der man steuern oder messen kann.

Es gibt bereits diverse Lösungen, die aber allesamt eines gemeinsam haben: sie sind entweder relativ teuer, oder sie blockieren wichtige Anschlüsse (DMA, Rom-Modul, etc.). Auch diese Schaltung blockiert einen Anschluß, nämlich die Centronicsschnittstelle. Aber sie ist billig (ca. 15 DM), und sie ermöglicht es aufgrund des verwendeten Bausteins (eine 8255 PIO von intel). trotzdem einen Drucker anzuschließen.

Das Prinzip der Schaltung

Am Centronicsanschluß befinden sich 10 Leitungen: 8 Datenleitungen und zwei Leitungen, die normalerweise für das Handshaking mit dem Drucker zuständig sind. Die 8255 PIO braucht aber dummerweise 6 Steuerleitungen und 8 Datenleitungen. Nun, die Schaltung benutzt folgenden Trick: Es wird mit den beiden Handshakeleitungen zwischen Daten für die PIO und Steuerdaten, die in einen zusätzlichen 8 Bit-Zwischenspeicher geschrieben werden unterschieden. Da der Baustein weder ein Taktsignal noch ein kompliziertes Timing benötigt, reicht dies aus, um ihn anzusteuern. Ein zweites Problem ist die Stromversorgung, am Centronicsport ist nämlich keinerlei benutzbare Spannung herausgeführt. Aber auch hier gibt es eine einfache Lösung: das Pin 13 des Druckeranschlusses ist nicht belegt. Man kann nun den Atari öffnen und dieses Pin mit +5 V verbinden. Die +5 V sucht man am besten mit einem Voltmeter in der Nähe des Netzteils.

Eine kurze Beschreibung des 8255

24 programmierbare I/O-Anschlüsse (aufgeteilt in 2 Gruppen zu 8 Bit und 2 Gruppen zu 4 Bit, wobei die zwei 4-Bit-Gruppen zu einer 8-Bit-Gruppe zusammengefaßt werden können, um dann drei 8-Bit Gruppen zu bekommen) Möglichkeit, einzelne Bits zu setzen oder zu löschen, Programmierbarkeit des Bausteins in 3 verschiedenen Modi:

Der Baustein hat 2 Adreßleitungen, mit denen man 4 Register adressieren kann. Die Adressen 0 bis 2 werden für die 3 I/O-Ports verwendet, Adresse 3 wird zur Programmierung der PIO verwendet. Wenn das Bit 7 des in dieses Register geschriebenen Werts 1 ist, so werden die Bits 0-6 als Konfigurationsbefehle verstanden: (Modus 0)

Prototyp der PIO

Befehlsnummer: Port 0 Port 1 Port 2, unten Port 2, oben (Hexadezimal) $80 Ausgang Ausgang Ausgang Ausgang ' $81 A A Eingang A $82 A E A A $83 A E E A $88 A A A E $89 A A E E $8A A E A E $8B A E E E $90 E A A A $91 E A E A $92 E E A A $93 E E E A $98 E A A E $99 E A E E $9A E E A E $9B E E E E

Nt das Bit 7 Null, so können einzelne Bits res Ports 3 gesetzt oder gelöscht werden:

Bit 0: 0 bedeutet Bit löschen, 1 = Bit setzen
Bit 1-3: Nummer des Bits von 0 bis 7
Bit 4-6: unbenutzt
Bit 7: muß 0 sein !

Beispiel: Der Wert $D setzt Bit 6.

Schaltplan

Bauteilliste

1 PIO 8255 oder 82C55 (sparsamer)
1 74 LS 32 1 74 LS 374 D-Sub Stecker, 25-polig mit abgewinkelten Anschlüssen - Platine (Layout siehe Zeichnung)

Das Steuerregister wird durch einen 74 LS dargestellt, der 8 D-Flipflops beinhaltet. Es ist folgendermaßen aufgebaut:

Bit 0: /RD8255 ; die Leseleitung für die 8255 PIO, wenn auf Low-Pegel, kann gelesen werden.
Bit 1: /WR8255 ; die Schreibleitung, wenn auf Low-Pegel, kann geschrieben werden.
Bit 2: RESET ; die Resetleitung für die 8255, versetzt die PIO in Einschaltzustand, wenn auf High-Pegel

Die Modi 1 und 2 interessieren hier nicht weiter, es sei nur erwähnt, daß man z.B. zwei Drucker ansteuern (Modus 1) oder eine IEC-Schnittstelle emulieren könnte (Modus 2). Wer weitere Informationen möchte, sei hier auf das Datenblatt von intel verwiesen (Adresse später).

Bit 6: A1; das höherwertige Bit der Registernummer
Bit 7: A0 ; das niederwertige Bit der Registemummer

Ein Lesezugriff auf Register 2 läuft dann so ab:

Die Pinbelegung der Stiftleisten ist auf Zeichnung 2 (dem Bestückungsplan) angegeben. Die drei dick eingezeichneten Lötbrücken müssen vor den ICs eingelötet werden ! Bei der Verwendung von Portleitungen als Eingang müssen diese mit einem Pullup-Widerstand versehen werden, d.h. sie werden über einen 10 Kiloohm-Widerstand mit +5V verbunden. Wird dies nicht gemacht, “rauscht” der Eingang. Bei der Verwendung als Ausgang ist dies nicht nötig.

Die Softwareeinbindung:

Es existiert Steuersoftware für GFA-BASIC und für das Megamax C. Das Prinzip ist bei beiden Programmen gleich, nur das Einbinden ist in C einfacher, da man hier direkt Assemblermnemonics verwenden kann, während man in BASIC Maschinenprogramme entweder nachladen oder in String variablen halten muß.

Zuerst zum GFA-BASIC:

Die Einbindung ist als Unterprogrammsammlung realisiert, die Sie, wenn Sie sie benötigen, hinzuMERGEn müssen.

Die Unterprogramme sind:

Init_all : Initialisiert das MC-Programm und den PIO-Baustein (muß immer vor der ersten Benutzung aufgerufen werden !!!)

Lese_pio(Port%, *Variable %): : Liest aus dem PIO-Register Port% in Variable%.

Schreibe_pio(Port%,Wert%): : Schreibt den angegebenen Wert ins PIO-Register Port%.

Init_drucker: : Schaltet die Centronicsschnittstelle wieder auf Druckerbetrieb um.

(Siehe Listing PIO.LST)

Zum Megamax C:

Die Einbindung wurde als .H File realisiert, d.h., wann immer Sie die PIO in C benötigen, schreiben Sie am Programmanfang

	#include “pio.h” .

Zum Aufruf der PIO-Routinen wird die Funktion ‘pio_access’ verwendet. Als Argument benötigt man den Befehl, die Registernummer und den Wert. Die Funktion liefert bei Leseoperationen einen int Wert zurück.

Initialisieren: pio_access(_INIT,0,0);
schaltet die PIO ein, muß immer vor erster Benutzung aufgerufen werden.

Lesen: x=pio_access(_LESE,2,0);
liest aus Port 2 in Variable x

Schreiben: pio_access(_SCHREIBE, 0,0xAA);
schreibt den Wert $AA in Port 0

Druckerbetrieb: pio_access(_ENDE,0,0);
schaltet auf Druckerbetrieb um.

(Siehe Listing 2+3)

Jörg Falkenberg Jürgen Landler

Literatur:

intel Microsystem Components Hand book Volume II, Seite 5-273 (Adresse: intel, Seidlstraße 27, 8000 München 2)

ATARI ST Intern, Data Becker

	,	PIO.LST
	'	Treibersoftware für 24-Bit PIO mit 8255
	'	Software (c)1987 Jürgen Landler
	'	Hardware (c)1987 Jörg Falkenberg
	'
	@Init_all
	Print Hex$(Bef%)
	@Schreibe_pio (3, &H89)
	Repeat
		@Lese_pio(2,*1%)
		Print At(1,2);I%'
		@Schreibe_pio(0,0)
		@ Schreibe_pio(1,0)
		Pause 5
		@Schreibe_pio(0,255)
		@Schreibe_pio(1,255)
		Pause 5
	Until Inkey$="s"
	@Init_drucker
	End
	'
	' Liest MC-Unterprogramme ein
	'
	Procedure	Init_all
		Local A$,I%
		Restore Pio_code
		Bef$=""
		Do
			Read A$
			Exit If. A$="-1"
			Bef$=Bef$+Mki$(Val("&H"+A$))
		Loop
		Bef%=Varptr(Bef$)
		@Init_pio	! Druckerport initialisieren
	Return
 '
 ' Schaltet den Druckerport auf Ausgang, und 8255 auf Standby
 '
	Procedure Init_pio
		Void Xbios(38,L:(Bef%+&HA0))
	Return
	'
	' schaltet Centronics wieder auf Druckerbetrieb um
	'
	Procedure Init_drucker
		Void Xbios(38,L:(Bef%+&H60))
	Return
	'
	' schreibt Wert_ in Register Reg
	'
	Procedure Schreibe_pio(Reg_%,Wert_%)
		Dpoke Bef%,Wert_%
		Dpoke Bef%+2,Reg_%
		Void Xbios (38, L: (Bef %+&HEA) )
	Return
	'
	' liest aus Reg_ in durch Wohin_ adressierte Variable
	'
	Procedure Lese_pio(Reg_%,Wohin_%)
		Dpoke Bef%+2,Reg_%
		Void Xbios(38,L:(Bef%+4))
		*Wohin_%=Dpeek(Bef%)
	Return
	'
	' MC-Unterprogramme
	'
	Pio_code:
 Data 0000,0000,40C2,46FC,2700,08F9,0000,00FF 
 Data FA05,41F9,00FF,8800,323A,FFE8,7008,E219 
 Data E211,E210,E511,E210,6100,00A0,10BC,0007 
 Data 1010,0240,007F,1140,0002,10BC,000F,08B9 
 Data 0000,00FF,FA01,1039,00FF,8800,08F9,0000 
 Data 00FF,FA01,43FA,FFAA,3280, 6134,46C2,4E75
 Data 40C2,343C,2700,41F9,00FF,8800,08B9,0000 
 Data 00FF,FA05,08B9,0000,00FF,FA01,6112,10BC 
 Data 000E,1010,0000,0020,1140,0002,46C2,4E75 
 Data 10BC,0007,1010,0000,0080,1140,0002,4E75 
 Data 40C2,46FC,2700,41F9,00FF,8800,08F9,0000 
 Data 00FF,FA05,08F9,0000,00FF,FA01,61D2,70FF
 Data 6108,70C3,6104,46C2,4E75,10BC,000F,1140 
 Data 0002,10BC,000E,1010,0000,0020,1140,0002 
 Data 0200,00DF,1140,0002,4E75,40C2,46FC,2700 
 Data 08F9,0000,00FF,FA05,41F9,00FF,8800,323A 
 Data FF02,7004,E219,E211,E210,E511,E210,61BA 
 Data 10BC,000F,117A,FEEB,0002,08B9,0000,00FF 
 Data FA01,08F9,0000,00FF,FA01,46C2,4E75
 Data -1

PIO.H

#define _LESE 1 
#define _SCHREIBE 2 
#define _INIT 3 
#define _ENDE 4

int pio_access(befehl,port,wert) 
int befehl,port,wert;
{
	int zurueck; 
	long oldstack; 
	oldstack=Super(0L); 
	switch(befehl)
	{
	case _LESE:
		asm 
		{
			move.w SR,D2
			move.w #0x2700,SR	;	Interrupts aus
			bset #0,0xfffa05
			lea 0xff8800,A0	;	Basisadresse des Soundchips (AY) 
			move.w port(A6),D1	;	Register, Read
			moveq #8,D0	;	/WR8255 auf High, /RD8255 auf Low 
			ror.b #1,D1	;	Portadresse in Bit
			roxr.b #1,D1	;	6 und 7 schieben
			roxr.b #1,D0 
			roxl.b #2, D1 
			roxr.b #1,D0
			bsr stout	;	Steuerwort schreiben
			move.b #7,(A0)	;	AY Eingang
			move.b (A0),D0	;	Register 15 als Eingang
			andi.w #127,D0	;	programmieren
			move.b D0,2(A0)
			move.b #15,(A0)	;	Daten lesen
			bclr #0,0xfffa01 
			move.b 0xff8800, zurueck(A6)
			bset #0,0xfffa01
			bsr ayaus	;	Reg. 15 wieder Ausgang
			move.w D2,SR	;	Interrupts wieder an
			bra lese_ende

		stout:
			move.b #15,(A0)	;	Daten in AY-Register
			move.b D0,2(A0)	;	15 schreiben
			move.b #14,(A0)	;	und mit Strobe-Impuls
			move.b (A0),D0	;	in Steuerregister (LS 374)
			ori.b #0x20,D0	;	übertragen
			move.b D0,2(A0)
			andi.b #0xdf,D0
			move.b D0,2(A0)
			rts

		ayaus:
			move.b #7,(A0)	;	Port 15 auf
			move.b (A0),D0	;	Ausgang umschalten
			ori.b #128,D0 
			move.b D0,2(A0) 
			rts

		lese_ende:
		}
	break;

	case _SCHREIBE: 
		asm 
		{
			move.w SR, D2 
			move.w #0x2700, SR 
			bset #0,0xfffa05 
			lea 0xff8800,A0
			move.w port(A6),D1	;	Port Nummer
			moveq #4,D0	;	/WR8255=Low, /RD8255=High 
			ror.b #1,D1	;	siehe oben
			roxr.b #1,D1 
			roxr.b #1,D0 
			roxl.b #2,D1 
			roxr.b #1,D0 
			bsr stout
			move.b #15,(A0)	;	Daten in Register
			move.b wert+1(A6),2(A0) ; 15 schreiben
			bclr #0,0xfffa01	; /CE8255 auf low...
			bset #0,0xfffa01	; ...und wieder high
			move.w D2,SR
		}
		break;

	case _ENDE: 
		asm 
		{
			move.w SR,D2 
			move.w #0x2700,D2 
			lea 0xff8800,A0
			bclr #0,0xfffa05	;	Busy wieder Eingang
			bclr #0,0xfffa01 
			bsr ayaus
			move.b #14,(A0)	;	Strobe auf High
			move.b (A0),D0
			ori.b #0x20,D0
			move.b D0,2(A0)
			move.w D2,SR
		}
		break;

	case _INIT: 
		asm 
		{
			move.w SR,D2 
			move.w #0x2700,SR 
			lea 0xff8800,A0
			bset #0,0xfffa05	;	Busy jetzt Ausgang
			bset #0,0xfffa01	;	und gleich High setzen
			bsr ayaus
			moveq #0xff,D0	;	8255 Reset geben
			bsr stout
			moveq #-0x3D,D0	;	RESET wieder low
			bsr stout 
			move.w D2, SR
		}
		break;
	}
	Super(oldstack); 
	return(zurueck);
}

PIO.C

/***********************************************
*	Treibersoftware für 24-Bit PIO mit 8255    *
*	Software (c) 1987 Jürgen Landler	         *
*	Hardware (c) 1987 Jörg Falkenberg          *
************************************************ /

#include <osbind.h> 
#include "pio.h"

main ()
{
	int a=1; 
	int b=255; 
	int c=0xaa; 
	int i;

	puts("\033E Ausgabetest:\n\n"); 
	pio_access(_INIT,0,0);
	/* zuerst Reset *./
	pio_access(_SCHREIBE,3,0x80);
	/* alle Ports Ausgang */
	do 
	{
		pio_access(_SCHREIBE,0,a); 
		a=(a<<1); a=( (a&0x100) >> 8 | a ) &0xff;
		/* Bit um eins nach links rotieren */ 
		pio_access(_SCHREIBE,1,b); 
		b^=0xff;
		/* alle Bits in Port B invertieren */ 
		pio_access(_SCHREIBE,2,c); 
		c^=0xff;
		/* auch hier alle Bits invertieren */ 
		for (i=0;i++<35;Vsync());
		/* 1/2 Sekunde warten */
	} while(!Cconis ()); /* bis Taste gedrückt wird */ 
	pio_access(_ENDE,0,0);

}


Aus: ST-Computer 03 / 1988, Seite 26

Links

Copyright-Bestimmungen: siehe Über diese Seite