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.
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.
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.
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.
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
#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);
}
/***********************************************
* 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);
}