← ST-Computer 03 / 1988

24-BIT PIO für 15 Mark

Hardware

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:

  • Normale Ein-/Ausgabe (0)
  • Impulsgesteuerte Ein-/Ausgabe (1)
  • Bidirektionaler Bus (2)

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:

  • /RD8255 auf 0, /WR8255 auf 1, RESET auf 0 , Al auf 1 und A0 auf 0 setzen.
  • dieses Steuerwort schreiben
  • Centronics als Eingang programmieren
  • /CE8255 auf 0 setzen (=PIO anwählen)
  • Wert lesen und merken
  • /CE8255 auf 1 setzen (=PIO deselektieren)
  • Centronics wieder Ausgang

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); }