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

Links

Copyright-Bestimmungen: siehe Über diese Seite