little bat k1.spdns.de / Develop / Hardware / K1-Bus /
Blurb | Basissystem | Busleitungen | Buszyklen | Wait | Reset | I²C-Bus | Maße | Beispiel-I/O-Karte | Beispiel-CPU-Karte | Material

Der K1 Universal-Peripheriebus

Version 1.00

Letzte Änderung: 2014-04-11

English version

Grundsätze

Image of bus connector assignment Der K1-Bus is ein Peripheriebus für Selbstbau-Computer mit beliebigen CPUs, gerne ebenfalls im Selbstbau. Arbeitsspeicher soll darüber nicht angesprochen werden, dieser soll auf der CPU-Platine verbleiben.

Der Bus ist als 16-Bit-Bus gedacht, kann aber auch als reiner 8-Bit-Bus verwendet werden.

Es sind bis zu 16 Peripheriekarten adressierbar. Bei Beschränkung auf einen 8-Bit-Bus sind es noch bis zu 8 Karten. Die Adressierung der Karten erfolgt jeweils mit einer Datenleitung, die auf jeder Karte per Jumper festgelegt wird.

Mechanisch wird ein 40-poliges Flachbandkabel verwendet, wie es für IDE-Festplatten gebräuchlich war und Stecker und Buchsen entsprechend billig sind. Die Signale sind nicht durch Masseleitungen getrennt, deshalb sollte das Flachbandkabel so kurz wie möglich sein. Am besten werden die Buchsen so nah aufeinander folgend aufgepresst, dass man die Karten danach zu einem Paket zusammen schrauben kann.

Elektrisch sollen über den Bus CMOS-Bausteine kommunizieren. Sowohl 'reine' CMOS-Bausteine aus der 74HC-Serie, als auch TTL-kompatible aus der 74HCT-Serie. Bei gemischtem Betrieb werden sich evtl. einige Zeitfenster etwas verschieben. Entscheidend ist, dass die Eingangslast aller angeschlossenen Karten so niedrig ist, dass mit Standard-CMOS-ICs der Bus direkt angesprochen werden kann.

Jede Karte kann ihre Treibersoftware in einem I²C-EEprom bereitstellen. Solche Peripheriekarten können in einem K1-Bus-System ohne Installation von Treibersoftware einsatzbereit sein. Die CPU sucht in der Boot-Phase alle Karten und liest und installiert die Treiber. Diese sind in einem precompilierten Bytecode geschrieben, der sofort übersetzt oder zur Laufzeit interpretiert werden kann. Karten, die nur für ein bestimmtes System gedacht sind, benötigen nicht unbedingt ein I²C-EEprom.

Die höchstmögliche Datenrate beträgt etwa 32 MB/s, erzielbar als 16 Mio. 16-Bit-Transfers pro Sekunde. Ob diese Geschwindigkeit auch nur annähernd erreicht wird, hängt primär von der CPU ab. Eine Z80 CPU erreicht etwa 250 kB/s bei 4 MHz CPU-Takt.

Es gibt nur einen Bus-Master: Die CPU-Platine. Soll DMA eingesetzt werden, muss der DMA-Controller mit auf die CPU-Platine. Ein externer DMA-Controller ist nur sehr aufwändig zu implementieren.

Für einen Datentransfer wird eine Karte zuerst mit /select und der ihr zugeordneten Datenleitung angewählt. Danach gehen alle Datentransfers auf dem Bus zu dieser Karte, bis eine andere Karte angewählt wird.

Jede Karte hat einen eigenen, priorisierbaren und maskierbaren Interrupt. Ein Interrupt wird zunächst über die Sammelleitung /irpt angezeigt. Danach erfragt die CPU mit /rd_irpt die Interruptquelle und sperrt mit /wr_irpt für die Dauer der Interrupt-Behandlung alle Interrupts mit der selben oder niedrigeren Priorität.

Die 6 Adressleitungen A0 bis A5 dienen zur Adressierung der Register in den Peripheriebausteinen. Für 8-Bit-Systeme ist nur eine Unterstützung der 4 ersten Adressleitungen verpflichtend. 8-Bit-CPU-Systeme können recht leicht für volle 16-Bit-Unterstützung ausgebaut werden.

Basissystem

Das absolute Minimalsystem besteht nur aus einer CPU-Karte mit CPU, Boot-Rom und Ram. Ein Microcontroller ist ebenfalls denkbar. Diese Karte sollte zumindest für Testzwecke "stand-alone" lauffähig sein. Dazu kommen typischerweise noch ein Timer-/Counter für die System-Zeitbasis, Debugger-Support wie Reset- und Debug-Taster und eventuell ein serieller Anschluss für ein Terminal oder einen PC, was aber alles auch auf einer Peripheriekarte untergebracht sein kann.

CPU-Karte

• CPU, RAM und ROM oder All-in-one in einem Microcontroller
• Pull-up-Widerstände für: /wait, /reset, /irpt und i2c_data
• Power-on Reset
• Anschluss für Spannungsversorgung

Optional:

• System Timer/Counter
• RS232 für Terminal
• Watchdog-Timer (Interrupt, NMI oder Reset)
• Reset-Taster und Anschluss für externen Taster
• Debug-Taster und Anschluss für externen Taster (Interrupt oder NMI)
• Heart-Beat-LED und Anschluss für externe LED

Netzteilkarte

• Versorgung mit +5V

Optional:

• Power-off Interrupt
• Power-LED und Anschluss für externe LED
• Ein/Aus-Schalter und Anschluss für externen Schalter

Bus-Leitungen

Datenleitungen:
D0 … D15    Daten von und zur Peripheriekarte
A0 … A5 Registeradresse auf der Peripheriekarte
Steuersignale von der CPU an alle Karten:
/select     Karte auswählen
/rd_irpt Interrupt-Status abfragen
/wr_irpt Interrupt-Enable-Masken schreiben
Steuersignale von der CPU zur ausgewählten Karte:
/rd_data    Daten von der Karte lesen
/wr_data Daten zur Karte schreiben
Signal-Sammelleitungen:
/wait       Verlängerung von Buszyklen
/irpt Interrupt
/reset Neustart
I²C-Bus von der CPU zur ausgewählten Karte:
i2c_clk     I²C-Taktleitung
i2c_data I²C-Datenleitung (bidirektional)
Sonstige Leitungen:
GND         4x Gemeinsame Masse für Signale und Stromversorgung
+5V Vcc 4x +5 Volt Stromversorgung

Bus-Zyklen

Es gibt 5 verschiedene Buszyklen, die von der CPU mit 5 einzelnen Steuerleitungen signalisiert werden:
/select (Karte auswählen), /rd_irpt (Interrupt-Status lesen), /wr_irpt (Interrupt-Maske schreiben), /rd_data (Daten lesen) und /wr_data (Daten schreiben).

Bus-Schreibzyklus

wr_data.png

Es gibt drei Bus-Schreibzyklen: /select (Karte auswählen), /wr_irpt (Interruptmaske schreiben) und /wr_data (Daten schreiben). Der Bus-Schreibzyklus besteht, wie der Bus-Lesezyklus, aus 4 Zeitscheiben:

T(Z2S): Vorlaufzeit
T(S2W): "Strobe-to-Wait": Zeitfenster für ein /wait-Signal durch die Peripherie-Karte.
T(D2E): "Data-to-End": Vorlaufzeit für die Lesedaten. Diese umfasst 2 Zeitscheiben und wird von der hinteren Strobeflanke gemessen. Die erste Zeitscheibe überlappt sich mit T(S2W) "Strobe-to-Wait".
T(E2Z): "End-to-Off": Nachlaufzeit für die Registeradresse und Schreibdaten.

Das Strobe-Signal muss jeweils mindestens:
T(ON): 2 Zeitscheiben lang aktiv und
T(OFF): 2 Zeitscheiben lang inaktiv sein.

In der Realität sind die Zeitscheiben nicht gleich lang. Die kürzeste Zeitscheibe im realen Buszyklus einer CPU bestimmt ihren "Vergleichstakt", und die längste Zeitscheibe einer Peripheriekarte bestimmt den CPU-Vergleichstakt, bis zu dem die Karte funktionieren sollte.

/select: Auswählen einer Karte

Auf jeder Karte wird mittels Jumper eine Datenleitung als ihre Adresse eingestellt. Diese wird im /select, /wr_irpt und /rd_irpt-Zyklus zur Adressierung der Karte benutzt.

Der Datenaustausch mit einer Peripheriekarte erfolgt immer in 2 Schritten:
• Auswahl der Karte
• Datentransfer von und zur Karte

Der /select-Zyklus dient zur Auswahl einer Karte für die nachfolgenden Datentransfers mit /rd_data und /wr_data und auf dem I²C-Bus.

Dazu macht die CPU einen Bus-Schreibzugriff mit /select als Steuerleitung.

Im Maskenwort sind alle Bits gesetzt, nur das Bit für die gewünschte Karte ist gelöscht. Das Maskenwort kann auch $FFFF sein, um alle Karten zu deaktivieren. In 8-Bit-Systemen werden nur die unteren 8 Datenleitungen benutzt. Hier sind dann nur 8 Karten adressierbar.

Timing:

Das /select-Signal muss mind. 2 Zeitscheiben lang aktiviert werden. Das Maskenwort muss dabei zwei Zeitscheiben vor und eine Zeitscheibe nach der Datenübernahme-Flanke des Strobesignals gültig sein.

Die Registeradresse A0 - A5 ist ohne Bedeutung. Das Verhalten von /wait ist nicht definiert, d.h. es darf aktiviert werden, die CPU muss es aber nicht beachten.

Die Peripheriekarten sollten ihr Select-Bit mit einem positiv flankengetriggerten Latch, z.B. einem 74HC74 übernehmen.

/wr_irpt: Interrupt-Enablebits schreiben

Die CPU kann mit einem Maskenwort die Interrupts aller Karten individuell ein- und ausschalten.

Dazu legt sie das 16-Bit-Maskenwort auf den Datenbus und macht einen Bus-Schreibzugriff mit /wr_irpt als Steuersignal.

Im Maskenwort gesetzte Bits sperren die Interrupts der jeweiligen Karte, gelöschte Bits erlauben die jeweiligen Interrupts. Das Maskenwort kann auch $FFFF sein, um alle Interrupts zu sperren, oder $0000, um alle Interrupts zuzulassen. In 8-Bit-Systemen werden nur die unteren 8 Datenleitungen benutzt. Hier sind dann nur 8 Karten adressierbar.

Timing:

Das /wr_irpt-Signal muss mindestens 2 Zeitscheiben lang aktiviert werden. Das Maskenwort muss dabei zwei Zeitscheiben vor und eine Zeitscheibe nach der Datenübernahme-Flanke des Strobesignals gültig sein.

Die Registeradresse A0 - A5 ist ohne Bedeutung. Das Verhalten von /wait ist nicht definiert, d.h. es darf aktiviert werden, die CPU muss es aber nicht beachten.

Die Peripheriekarten sollten ihr Interrupt-Enable-Bit mit einem positiv flankengetriggerten Latch, z.B. einem 74HC74 übernehmen.

/wr_data: Reguläre Daten zur Karte senden

Die CPU kann 16-Bit-Daten zur aktuell angewählten Peripheriekarte senden. Dazu macht sie einen Bus-Schreibzugriff mit /wr_data als Steuersignal.

Timing:

Die Adressleitungen mit der Registeradresse müssen mit der fallenden Flanke von /wr_data gültig sein, danach kommt die Reaktionszeit T(S2W) für /wait. Nach 2 Zeitscheiben T(D2E) kommt die Datenübernahme-Flanke des Strobesignals, mit dem die Daten von der Karte übernommen werden sollen. Danach müssen Daten und Registeradresse noch eine weitere Zeitscheibe T(E2Z) gültig bleiben.

Wurde /wait innerhalb der Reaktionszeit T(S2W) aktiviert, muss der Buszyklus so lange eingefroren werden, bis die Peripheriekarte das /wait-Signal wieder löst. Nur die ausgewählte Peripheriekarte darf /wait aktivieren. Wird /wait außerhalb eines Bus-Zyklus aktiviert, so ist das Verhalten unbestimmt; d.h. die CPU könnte es beachten, muss aber nicht.

Bus-Lesezyklus

rd_data.png

Es gibt zwei Bus-Lesezyklen: /rd_irpt (Interruptstatus lesen) und /rd_data (Daten lesen). Ein Bus-Lesezyklus besteht, wie der Bus-Schreibzyklus, aus 4 nominell gleich langen Zeitscheiben:

T(Z2S): Vorlaufzeit
T(S2W): "Strobe-to-Wait": Zeitfenster für ein /wait-Signal durch die Peripherie-Karte.
  Identisch mit T(S2D): "Strobe-to-Data": Zeitfenster bis zur Bereitstellung der Lesedaten.
T(D2E): "Data-to-End": Vorlaufzeit für die Lesedaten.
T(E2Z): "End-to-Off": Nachlaufzeit für die Registeradresse und Ausschaltzeit für Lesedaten.

Das Strobe-Signal muss jeweils mindestens:
T(ON): 2 Zeitscheiben lang aktiv und
T(OFF): und 2 Zeitscheiben lang inaktiv sein.

In der Realität sind die Zeitscheiben nicht gleich lang. Die kürzeste Zeitscheibe im realen Buszyklus einer CPU bestimmt ihren "Vergleichstakt", und die längste Zeitscheibe einer Peripheriekarte bestimmt den CPU-Vergleichstakt, bis zu dem die Karte funktionieren sollte.

Die Zeiten sind As seen on the Bus:

Um die erhöhte kapazitative Last auf dem Bus zu berücksichtigen, sollte man zu den normalen Gatterlaufzeiten für alle Bus-Ausgangstreiber ca. 20ns zusätzliche Laufzeit ansetzen; sowohl auf der CPU-Karte als auch auf der Peripheriekarte. (to be determined)

/rd_irpt: Interrupt-Statusbits lesen

Die CPU kann den Interrupt-Status aller Karten einlesen. Dazu macht sie einen Bus-Lesezugriff mit /rd_irpt als Steuersignal.

Hierbei müssen alle Karten ihren Interrupt-Status auf ihrer per Jumper eingestellten Datenleitung ausgeben. Wartende Interrupts werden '0'-aktiv signalisiert. Der Ausgang sollte 3-State sein, d.h. die Karte muss sowohl eine '1' (kein Interrupt) als auch eine '0' (Interrupt) treiben.

Timing:

Die CPU aktiviert /rd_irpt für mindestens 2 Zeitscheiben und liest mit Ende des /rd_irpt-Signals das Datenwort mit den Statusbits aller Karten ein. Die Datenbits müssen spätestens eine Zeitscheibe nach der fallenden Flanke des Strobesignals gültig sein, und spätestens eine Zeitscheibe nach der Datenübernahme-Flanke müssen die Treiber der Karte wieder hochohmig sein. Die Registeradresse A0 - A5 ist ohne Bedeutung.

Das Verhalten von /wait ist nicht definiert, d.h. es darf aktiviert werden, die CPU muss es aber nicht beachten.

Nicht angeschlossene Bits floaten naturgemäß und müssen im Interrupt-Handler der CPU ausmaskiert werden.

/rd_data: Reguläre Daten von der Karte lesen

Die CPU kann 16-Bit-Daten von der angewählten Peripheriekarte empfangen. Dazu macht sie einen Bus-Lesezugriff mit /rd_data als Steuersignal.

Timing:

Die Adressleitungen mit der Registeradresse müssen mit der fallenden Flanke von /rd_data gültig sein. Danach kommt die Reaktionszeit T(S2W) für /wait. Danach muss entweder /wait aktiviert worden sein, oder die Lesedaten auf dem Bus anliegen. Nach einer weiteren Zeitscheibe T(D2E) kommt die Datenübernahme-Flanke des Strobesignals, zu der die Daten von der CPU übernommen werden. Danach sollte die Registeradresse noch eine weitere Zeitscheibe T(E2Z) gültig bleiben. Spätestens mit Ende dieser Zeitscheibe müssen die Treiber der Karte wieder hochohmig sein.

Wurde /wait innerhalb der Reaktionszeit T(S2W) aktiviert, muss der Buszyklus so lange eingefroren werden, bis die Peripheriekarte das /wait-Signal wieder löst. Nur die ausgewählte Peripheriekarte darf /wait aktivieren. Wird /wait außerhalb eines Bus-Zyklus aktiviert, so ist das Verhalten unbestimmt; d.h. die CPU könnte es beachten, muss aber nicht.

/wait: Verlangsamen des Bus-Lese- oder Schreibzyklus

/wait dient dazu, dass Peripheriekarten die Datenübertragung zur CPU abbremsen können, so dass auch langsame Karten mit schnellen CPUs betrieben werden können.

Nur die ausgewählte Peripheriekarte darf /wait aktivieren. Wird /wait außerhalb eines Bus-Zyklus aktiviert, so ist das Verhalten unbestimmt; d.h. die CPU könnte es beachten, muss aber nicht.

/wait kann mit einem Open-Gain-Ausgang angesteuert werden. Zu diesem Zweck wird die /wait-Leitung auf der CPU-Platine mit einem Pullup-Widerstand von ca. 5kΩ nach '1' vorgespannt. Dadurch ist es auch möglich, dass eine Peripheriekarte keine Wartelogik implementiert und /wait gar nicht ansteuert.

/wait sollte aber mit einem 3-State-Ausgang angesteuert werden, den nur die ausgewählte Karte aktivieren darf. Der Vorteil gegenüber einem Open-Drain-Ausgang liegt darin, dass eine aktive Beendigung des /wait-Signals durch einen Treiber, der das Signal auch nach '1' ziehen kann, schneller geht, als wenn die Entladung der Leitungskapazität nur durch einen – relativ hohen – Pullup-Widerstand erfolgt.

Mögliche Betriebsarten für /wait:

• /wait wird nicht benutzt:
Die Karte muss Schreibdaten nach T(D2E) (2 Zeitscheiben) übernehmen können bzw. Lesedaten nach T(S2D) (1 Zeitscheibe) bereitstellen. Die CPU muss also entsprechend langsam bzw. die Peripheriekarte entsprechend schnell sein.

• Betrieb im Sinne von '/wait':
/wait wird durch /rd_data oder /wr_data aktiviert. Diese Karte funktioniert mit allen CPUs, für die sie die Wait-Reaktionszeit T(S2W) (1 Zeitscheibe) einhält.

• Gemischter Betrieb:
Da die Registeradresse mit /rd_data oder /wr_data gültig anliegen muss, kann die Kartenlogik /wait nur für bestimmte Register aktivieren, z.B. wenn ein Statusregister sofort lesbar ist, ein Datenregister aber nicht.

/reset

Die Reset-Leitung ist eine Sammelleitung, die von allen Karten aktiviert werden darf. Sie ist 0-aktiv und muss mit Open-Drain-Ausgängen angesteuert werden. Auf der CPU-Karte wird sie mit einem Pullup-Widerstand von ca. 5kΩ nach '1' vorgespannt.

I²C-Bus

Der K1-Bus beinhaltet einen I²C-Bus. Dieser dient primär dazu, in der Bootphase EEproms mit Treibersoftware auf den Peripheriekarten auszulesen. Er kann aber auch anderweitig benutzt werden, jedoch mit Vorsicht: Der I²C-Bus ist nicht sehr schnell und während der Kommunikation mit einem I²C-Baustein müssen normalerweise sämtliche Interrupts gesperrt werden!

I²C-Bausteine müssen so angeschlossen sein, dass sie nur ansprechbar sind, wenn die Karte angewählt ist.

i2c_bus_timing.png

Der I²C-Bus besteht aus einer Takt- und einer bidirektionalen Datenleitung. Es gibt einen Master, die CPU-Platine, die den Takt erzeugt und alle Transfers initiiert. Alle anderen Geräte am I²C-Bus sind Slaves. Der Master beginnt einen Bustransfer mit der Auswahl des Gesprächspartners, anschließend folgt der Transfer beliebig vieler Datenbytes. Jedes Byte wird mit 8 Bit MSB first übertragen. Danach kommt ein 9. Bit, in dem der Datenempfänger eine Bestätigung (Acknowledge) auf der Datenleitung anzeigt, indem er diese auf 0 zieht. Unter bestimmten Bedingungen wird auch absichtlich mit Not-Acknowledge geantwortet.

Der Bus ist frei (idle), wenn Data und Clock beide 1 sind. Der Master sendet zu Beginn einer Übertragung eine Startbedingung, die darin besteht, dass er die Datenleitung auf 0 zieht, während die Taktleitung 1 bleibt. Danach kommt pro Takt ein Bit, wobei die Datenleitung immer nur geändert werden darf, während die Taktleitung 0 ist. Während die Taktleitung 1 ist, muss die Datenleitung stabil bleiben. Für das Acknowledgement setzt der Sender die Datenleitung auf 1, und der Empfänger zieht sie auf 0, was möglich ist, weil die Datenleitung mit Open Drain-Ausgängen und einem Pullup-Widerstand beschaltet wird. Danach kommt das 2. Byte usw. bis der Master den Datentransfer beendet, indem er eine Stopbedingung generiert, die darin besteht, dass er die Datenleitung von 0 nach 1 wechselt, während die Taktleitung 1 ist.

Ist der Master der Empfänger des letzten Bytes, so erzeugt er im 9. Takt ein Not-Acknowledge und sendet danach die Stopbedingung. Danach kann der Slave/Sender in den Stromsparmodus schalten, nach einem Ack geht sie idR. mit dem nächsten Byte weiter.

Wurden Daten in ein EEprom gespeichert, so ist es eine Zeit lang mit der Programmierung seiner EEpromzellen beschäftigt. In dieser Zeit ist es nicht ansprechbar und antwortet nicht, wenn es angesprochen wird, generiert also auch kein Acknowledge auf der Datenleitung. Daran kann man dann feststellen, wann es wieder ansprechbar ist. (sic!)

Das I²C-Protokoll ist für einen Takt von 100kHz und 400kHz spezifiziert, wobei am K1-Bus nur 400kHz-fähige Devices angeschlossen werden sollen. Der übliche Pullup-Widerstand für die Datenleitung bei 400kHz ist 2kΩ.

System Boot: Auslesen der I²C-EEproms

In der Bootphase liest die CPU die Kartentreiber aus den I²C-EEproms aller Karten aus. Dazu wählt sie die Karte mit einem /select-Buszyklus aus und versucht dann ein EEprom mit der Adresse %1010.0001 zu lesen. Dies ist die Adresse für 24C02..16-EEproms, 24C65-EEproms oder 24C128/256-EEproms, wenn deren Adresspins E0, E1 und E2 auf 0 gelegt sind, mit implizitem Lese-Befehl in Bit 0. Adresspin E2 des EEproms sollte mit dem Ausgang des /select-Latches (dem 74HC74) verbunden sein, so dass von allen EEproms am I²C-Bus nur das der ausgewählten Karte tatsächlich ausgewählt wird. Alle anderen haben an ihrem Adresspin E2 eine '1' und würden sich nur durch die Adresse %1010.1001 angesprochen fühlen. Einige der 'dicken' EEproms haben leider keine (beschalteten) Ex-Eingänge mehr, hier muss man das i2c_clock-Signal zum EEprom unterbrechen, wenn die Karte nicht angewählt ist.

Das EEprom enthält allgemeine Daten zur Karte, so z.B. ihren Namen und eine grundsätzliche Klassifizierung. Danach folgen Blöcke precompilierten Bytecodes, der entweder in der Bootphase übersetzt oder später zur Laufzeit interpretiert wird.

Der Aufbau des EEproms und der Bytecode werden in i2c-eeprom.pdf beschrieben.

Abmessungen der Peripheriekarten

Board_Dimensions.png

Obige Zeichnung ist ein Vorschlag für die Abmessung für ganze und halbe Europakarten-Platinen. Die halbe Europaplatine ist nur 79mm breit, um 2mm Schnittbreite beim Teilen einer ganzen Platine zu berücksichtigen.

Die Karten werden vorzugsweise liegend eingebaut. Dann kann man ganze und halbe Platinen mischen. In den Ecken sind Durchgangslöcher für M3-Schrauben oder Distanzbolzen. Der Lochdurchmesser reicht auch für zöllige Grobgewindeschrauben. Um die Löcher herum ist eine 10mm durchmessende Fläche, in der keine Bauteile und Leiterbahnen erlaubt sind. Die Löcher müssen potentialfrei bleiben und dürfen z.B. auch nicht mit Masse verbunden sein, um Masseschleifen zu verhindern. Sie dürfen jedoch mit der Abschirmung von externen Anschlüssen verbunden sein. Die Platinen sollen mit M3-Distanzbolzen oder durchgehenden M3-Schrauben und Distanzhülsen verschraubt werden.

Die bevorzugte Fläche für Jumper und interne Anschlüsse ist links auf der Platine.

Der K1-Busstecker ist so zu platzieren, dass er mittig auf der 79mm breiten halben Platine sitzt und am Platinenrand bündig abschließt. Die rückseitigen Anschlüsse sollen ebenfalls bündig abschließen.

Schaltungsbeispiel für eine Peripheriekarte

Example_IO.png Das Schaltbild zeigt den grundsätzlichen Aufbau der Ansteuerung auf einer Peripheriekarte.

Das große IC mit der Bezeichnung I/O ist das, worum es geht. Wenn man sich hier die Anschlüsse anschaut, sieht man, dass man viele ICs direkt 1:1 anschließen kann.

Mit dem Adress-Selektor wird eine der angebotenen Datenleitungen eingestellt. Es genügt wahrscheinlich fast immer, nur 4 zufällig bestimmte Leitungen im Jumperfeld anzubieten. Diese Datenleitung wird auf die beiden Dateneingänge der '74er Flip-Flops geführt und ist an den Ausgang für /rd_irpt angeschlossen.

Das obere Flip-Flop (1/2 74HC74) speichert den Zustand der Datenleitung, wenn ein /select-Zyklus ausgeführt wird. Sein Ausgang reflektiert den /select-Status der Karte.

Das andere Flip-Flop (1/2 74HC74) speichert den Zustand der Datenleitung, wenn ein /wr_irpt-Zyklus ausgeführt wird. Sein Ausgang reflektiert den Interrupt-Enable-Status für die Karte.

/rd_irpt schaltet einfach einen 3-State-Treiber auf 'unsere' Datenleitung durch. Man kann ein 74HC125 nehmen, das 4 einzeln ansteuerbare 3-State-Treiber enhält.

Da /irpt eine Sammelleitung ist und nur mit Open-Drain-Treibern auf '0' gezogen werden darf, wird hier ein kleiner Trick angewandt, um einen weiteren Treiber aus dem 74HC125 verwenden zu können. Das OR-Gatter kann ggf. aus einem Widerstand und einer Diode improvisiert werden, wenn es nicht noch irgendwo anfällt.

Ganz unten ist das Treiber-EEprom gezeigt, das einfach 1:1 an den I2C-Bus angeschlossen wird. Den Adresseingang E2, der quasi als Chip-Enable dient, bekommt es wie das I/O-IC vom /select-Status der Karte.

Schaltungsbeispiel für eine Z80 CPU-Karte

Ein Beispiel für eine CPU-Karte mit einer MC68008 und SRAM findet sich in ../K1-Bus 68008 CPU board with SRAM/.

Minimalsystem

Example_CPU.png

Obige Schaltung zeigt ein minimales Z80-System, zu dem die Ansteuerlogik für den K1-Bus hinzugefügt wurde.

Das Minimalsystem besteht nur aus CPU, Ram, Eprom, Takt, Reset-Logik und der Dekodierung von A15 für Adressierung von Ram und Eprom; ohne einen Timer-Interrupt oder eine PIO oder SIO.

Erweiterung für den K1-Bus

Der Anschluss für den K1-Bus besteht im absoluten Minimum nur aus einem IC, dem 3-zu-8-Dekoder 74HC138, und drei Pullup-Widerständen für die Sammelleitungen /wait, /irpt und /reset. Die Daten- und Adressleitungen sind nicht gepuffert. Diese CPU-Karte unterstützt nur einen 8-Bit-Bus und 4 Registeradressleitungen. D8-D15, A4 und A5 des K1-Bus bleiben einfach unbeschaltet.

Zur Durchschaltung des 74HC138 dienen /iorq, /m1 und A7. /m1 darf nicht aktiviert sein, um den normalen I/O-Zugriff von einem Interrupt-Acknowledge-Zyklus unterscheiden zu können, und A7 wird decodiert, um eventuell noch andere Peripheriebausteine auf der CPU-Platine ansprechen zu können.

Die 8 möglichen Ausgangsleitungen werden durch die 3 Adressbits A4 bis A6 ausgewählt. Eigentlich wäre /rd statt A4 ganz sinnvoll, da aber /iorq und /rd von der Z80 für die gleiche Zeit aktiviert werden, besteht die Gefahr von Glitches auf den Ausgängen, wenn /iorq die Ausgänge des 74HC138 schon aktiviert, bevor der gewünschte Ausgang (u.A. mittels /rd) richtig ausgewählt ist. Mit der Verwendung von 3 Adressbits kann das nicht passieren, weil die Adressen von der Z80 vor /iorq angelegt werden. Allerdings kann jetzt ein fehlerhafter OUT-Befehl zu einer Buskollission führen.

Erweiterung für den I²C-Bus

i2c_bus_drawing_1.jpg Der I²C-Bus kann, so wie oben dargestellt, mit einigen passiven Bauteilen und einem IC 74HC367 gebaut werden. Der 74HC367 enthält sechs 3-State-Treiber, die in Gruppen von 2 und 4 Treibern aktivierbar sind. Die CPU greift hier auf den I²C-Bus immer lesend zu, auch wenn sie ein Bit senden will. A1 liefert das Sendebit, A0 steuert die Taktleitung. Eingelesen wird in D0. Die Skizze rechts zeigt die Schaltung, die hier improvisiert wird.

Treiber 1 und 4 und Treiber 2 und 5 des 74HC367 bilden jeweils ein transparentes Latch, die Diode und der Parallelwiderstand machen den Ausgang von Treiber 5 zu einem Open-Drain-Ausgang mit Pullup-Widerstand.

Die Schaltung mit dem 74HC367 ist nicht wirklich schön, aber die einzige die mir einfiel, um mit nur einem IC auszukommen. Wenn man auf der CPU-Platine sowieso eine PIO oder SIO hat, sollte man versuchen, 2 universelle Portbits dafür herzunehmen. Dann kostet der I²C-Bus kein einziges IC extra.

Erweiterung für 16-Bit-Bus

Die folgende Erweiterung ermöglicht der Z80 die Verwendung von 16-Bit-Peripherie. Mit zwei 74HC574 8-fach Datenlatches werden die Daten für die obere Bushälfte zwischengespeichert. Ein Latch ist in Richtung CPU ➔ Bus und eins ist in Richtung Bus ➔ CPU angeschlossen. Statt der '574er kann man auch '374er und viele andere 8-Bit-Datenlatches verwenden.

Example_CPU_16Bit.png

Zum Schreiben eines 16-Bit-Wertes wird zuerst das obere Byte in das Ausgangslatch geschrieben. Dazu wird eine der freien dekodierten Leitungen des 74HC138 benutzt. Dieses Latch gibt seinen Inhalt auf den Bus wenn A4 = 0 ist. Anders lässt sich nicht erreichen, dass die Daten beim nachfolgenden 8-Bit-Schreibzugriff mit der nötigen Vor- und Nachlaufzeit ausgegeben werden.
Anm.: A4 wird für Eingang 'C' des 3-zu-8 Decoders verwendet, und alle Schreibsteuerleitungen sind an Ausgang 0 bis 3 angeschlossen, so dass sie bei C = 0 erfolgen.

Beim Lesen vom Bus mit /rd_data wird immer auch das obere Datenbyte in das Leselatch gelesen. Nachdem die CPU das untere Byte normal gelesen hat, befindet sich das obere Byte im Latch. Das kann danach ausgelesen werden, wozu die zweite freie Leitung des 74HC138 verwendet wird.

Verzichtet wird in dieser Schaltung darauf, das obere Byte auch bei /rd_irpt zu lesen. Das bedeutet, dass man zwar 16-Bit-Peripherie an diese CPU-Platine anschließen kann, bei der Anzahl der Erweiterungskarten aber auf 8 beschränkt bleibt. Um 16 Karten ansprechen zu können, müsste man /rd_irpt und /rd_data mit AND verknüpfen. ( /clk = /rd_data OR /rd_irpt <=> clk = rd_data AND rd_irpt )

Material

Name Letzte Änderung Länge 
2416.pdf 2008-03-25 18:58 132399 
24256.pdf 2008-03-25 18:58 110699 
2465.pdf 2008-11-03 21:38 213511 
Board_Dimensions.odg 2009-01-23 13:51 15055 
bus_lines.odg 2008-12-17 15:07 15725 
Example_CPU.odg 2009-01-23 14:09 18142 
Example_CPU_16Bit.odg 2009-01-23 14:09 19042 
Example_IO.odg 2009-01-23 14:09 17233 
i2c-eeprom.html 2019-12-18 12:31 141021 
i2c-eeprom.pdf 2014-04-11 22:09 282250 
i2c-eeprom.rtf 2014-04-11 22:02 115222 
i2c_bus_drawing_1.jpg
size: 271 × 220
2008-12-21 11:12 12980 
i2c_bus_drawing_2.jpg
size: 517 × 392
2008-12-21 11:11 43915 
i2c_bus_timing.odg 2009-01-23 14:10 11968 
K1-Bus.lbr 2014-08-21 17:26 428656 
Reset.odg 2009-01-23 14:10 13538 

powered by vipsi - your friendly VIP Script Interpreter

Valid HTML Valid CSS