Forum: Mikrocontroller und Digitale Elektronik Fragen zu Arduino und Interrupt und direktes Port lesen


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Peter S. (petersieg)


Bewertung
-1 lesenswert
nicht lesenswert
Vorweg: Man spare sich die Arduino ist alles Sch***. Ich nutze es und 
bin zufrieden! Und ich werde nicht mehr wechseln. Entweder es geht damit 
oder eben nicht.

Worum gehts. Ich möchte ein Arduino Uno als IO Gerät (nur lesend hier!) 
an ein 8085 Computer/Bus dran bringen.

Wenn /IOW (IO-write) auf Low geht, soll ein Adress Nibble (4-bit A7..A4) 
und das Datenbyte (geht am UNO an 2 Ports als High+Low Nibble) vom Bus 
gelesen werden.
Wenn das Adress-Nibble passt, soll das Datenbyte weiter verwendet werden 
(hier zum Test serielle Ausgabe).

Was ich bisher probiert hatte:
Einfaches pollen von /IOW ging gar nicht. Die /IOW Impulse müssen wohl 
so kurz gewesen sein, bzw. das Arduino 'Framework' so langsam, das sie 
das gar nicht mitbekommen haben.
Danach hatte ich /IOW auf PIN 2 gelegt und eine Interupt Service Routine 
drauf gelegt, aber dann auch nur einen Trigger definiert und wollte 
Adress-Nibble und Datenbyte in der Loop Routine lesen - Ergebnis war: 
Trigger ging, aber zum Zeitpunkt der Loop Verarbeitung war Adresse bzw. 
Datenbyte schon wieder etwas anderes (8085 System war schon woanders..) 
= also auch zu langsam. Bis hierhin hatte ich auch digitalRead etc. 
verwendet.

Nun möchte ich:
1. Lesen des Adress-Nibble UND Datenbyte in der ISR erledigen
2. Direkte Postzugriffe nutzen, wegen der höheren Geschwindigkeit
3. Die 'Weiterverarbeitung' soll dann nur noch in der Loop Routine 
erfolgen

Leider verursachen diese Bitmanipulationen bei mir 'Kopfschmerzen' ;-)
Quelle: 
http://www.netzmafia.de/skripten/hardware/Arduino/Programmierung/portmanipulation.html
Daher könnte ggf. mal einer der das schon öfter gemacht hat über meinen 
Code mal drüber schauen:
1
// Trigger is /IOW from 8085 - goes to PIN 2 and generated interupt on falling
2
// address nibble A7..A4 goes to PINs A3..A0 on (PortC) at UNO
3
// data byte high nibble is on PINs D11..D8 on (PortB) at UNO
4
// data byte low nibble is on PINs D7..D4 on (PortD) at UNO
5
// way of working:
6
// 1. at /IOW falling, trigger interrupt
7
// 2. read address nibble and combined/complete data byte in isr
8
// 3. if my adress, raise a flag (state=HIGH)
9
// 4. in arduino loop, just check/wait for flag an serial print data byte
10
11
#define MYADR 5
12
13
const byte interruptPin = 2;
14
volatile byte state = LOW;
15
byte data = 0, adr = 0;
16
17
void iow() {
18
  // trigger only if adr nibble = MYADR
19
  adr =  (PINC & B00001111);
20
  data=(((PINB & B00001111) << 4) + ((PIND & B11110000) >> 4)); 
21
  if (adr == MYADR) state = HIGH;
22
}
23
24
void setup() {
25
  DDRC = B11110000; // IO adr at A3-A0
26
  DDRB = B11110000; // Use D11-D8 as high nibble
27
  DDRD = B00001111; // Use D7-D4 as low nibble
28
  PORTC= B00001111; // pullups on
29
  PORTB= B00001111; // pullups on
30
  PORTD= B11110000; // pullups on
31
  Serial.begin(9600);
32
  pinMode(interruptPin, INPUT_PULLUP);
33
  attachInterrupt(digitalPinToInterrupt(interruptPin), iow, FALLING);
34
}
35
36
void loop() {
37
  // wait for IOW = LOW = state = HIGH
38
  while (state);
39
  Serial.print(data,DEC);
40
  state = LOW;
41
}

Bedenken/Zweifel habe ich auch wegen PortD D1+D0 die ja mit der 
seriellen Schnittstelle belegt sind, das ich die nicht durcheinander 
bringe.

Peter

von Rufus Τ. F. (rufus) (Moderator) Benutzerseite


Bewertung
0 lesenswert
nicht lesenswert
Peter S. schrieb:
> void iow() {
>   // trigger only if adr nibble = MYADR
>   adr =  (PINC & B00001111);
>   data=(((PINB & B00001111) << 4) + ((PIND & B11110000) >> 4));
>   if (adr == MYADR) state = HIGH;
> }

Aus Geschwindigkeitsgründen solltest Du auf sämtliche Manipulationen der 
Werte in der ISR verzichten, sondern nur die drei I/O-Ports einlesen und 
die Rohdaten aufheben, um sie in Deiner "loop" o.ä. zu verarbeiten. Die 
Adressauswertung und das Erzeugen Deines "state"-Flags muss ebenfalls 
dort erfolgen.

Warum ist "data" auf zwei Ports (B und D) verteilt? Verdrahte das 
anders, lege alle acht Bits gleich in der richtigen Reihenfolge an einen 
Port dann kannst Du Dir einen kompletten Portzugriff und die Schieberei 
sparen.


Denn es geht hier um Geschwindigkeit. Der 8085 wird mit ein paar MHz 
Takt arbeiten; zwar braucht er mehrere Taktzyklen für einen 
Prozessorbefehl, aber er ist halt doch recht flott, und Du hast nur 
wenige AVR-Prozessortakte Zeit.

von Matthias (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Manche Dinge löst man besser in Hardware. Die Signale aus einem anderen 
Prozessor auszulesen ist sehr zeitkritisch. Ich denke, mit zwei 
Logikbausteinen hast Du das schneller gelöst, und der Arduino kann dan 
ganz in Ruhe sein Ding machen.

Der 74377 hat ein 8-bit Register, dass den Datenbus für Dich 
zwischenspeichert bis Dein Arduino ihn auslesen kann. Das gleiche kannst 
Du natürlich auch für den Adressbus machen. Jetzt noch einen 4-bit 
Komparator (7485 oder sogar 74688), und Dein Arduino hat Luft zu Atmen.

Sobald der Komparator eine Adresse erkennt, die für Dich interessant 
ist, triggert er die Register, die dann den Status des Datenbusse und 
des Adressbusses speichern. Gleichzeitig löst Du den Interrupt aus. 
Jetzt hat der Arduino Zeit bis zum nächsten Adressevent, die Register 
auszulesen.

Es gibt noch einen anderen Weg: der 8085 hat einen READY Eingang. Wenn 
deine Hardware das verträgt, dann kann Dein Arduino den RAEDY Eingang 
auf 0 legen und ganz in Ruhe den Bus auslesen. Der 8085 wartet geduldig, 
bis der READY Eingang wieder auf 1 ist.

von c-hater (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Peter S. schrieb:

> Vorweg: Man spare sich die Arduino ist alles Sch***. Ich nutze es und
> bin zufrieden!

Nun, der Rest deines Postings spricht ja wohl doch von einer gewissen 
Unzufriedenheit, mindestens ja wohl bezogen auf die konkrete Anwendung. 
;o)

> Und ich werde nicht mehr wechseln. Entweder es geht damit
> oder eben nicht.

Na dann eben nicht.

von Peter S. (petersieg)


Bewertung
0 lesenswert
nicht lesenswert
Der UNO hat keinen ganzen freien Port.
Siehe Link. Im PortD sind D0+D1 belegt durch die serielle Schnittstelle.
Daher muss es wohl dabei bleiben, zwei Nibble zu lesen.

Ich denke ich muss die seriellen Pins und ISR Pin 2 auch noch richtig 
mit DDRD setzen.

Mit vorgeschalteten 7485 und 8255 habe ich schon am laufen. Jetzt möchte 
ich sehen, ob es auch ohne - nur mit einem Arduino geht.

Das mit dem Ready Eingang klingt auch interessant.

Peter

: Bearbeitet durch User
von Rufus Τ. F. (rufus) (Moderator) Benutzerseite


Bewertung
0 lesenswert
nicht lesenswert
Peter S. schrieb:
> Jetzt möchte ich sehen, ob es auch ohne - nur mit einem Arduino geht.

Dann probier' halt aus, Deine drei Werte zu lesen, aber mach' sämtliche 
Manipulationen in der loop.
1
byte dataB;
2
byte dataD;
3
volatile byte isrflag = 0;
4
5
6
void iow() 
7
{
8
  adr = PINC;
9
  dataB = PINB;
10
  dataD = PIND;
11
  isrflag = 1;
12
}
13
14
void loop() 
15
{
16
  // wait for interrupt
17
  while (!isrflag);
18
19
  isrflag = 0;
20
21
  if (adr == MYADR)
22
  {
23
    data = (((dataB & B00001111) << 4) + ((dataD & B11110000) >> 4));
24
 
25
    Serial.print(data,DEC);
26
  }
27
}

Wenn das nicht funktioniert, wirst Du entweder die serielle 
Schnittstelle durch Soft-Serial ersetzen müssen, um PortD als 8-Bit-Port 
nutzen zu können, oder aber die von Mathias angesprochene Ready-Leitung 
verwenden müssen.

(angenommen, sie ist an Pin3 angeschlossen, d.h. PortD.3)

Damit sähe Deine ISR so aus:
1
void iow() 
2
{
3
  // trigger only if adr nibble = MYADR
4
  adr =  (PINC & B00001111);
5
  if (adr != MYADR) 
6
    return;
7
  
8
  // ready aktivieren
9
  PORTD |= B00001000;
10
11
  // daten lesen
12
  data = (((PINB & B00001111) << 4) + ((PIND & B11110000) >> 4)); 
13
  
14
  // ready deaktivieren
15
  PORTD &= ~B00001000;
16
17
  state = HIGH;
18
}

(Ich hab' jetzt keine Ahnung, welche Polarität das Ready-Signal des 8085 
hat; das musst Du notfalls umdrehen).

Durch Vertauschen von Port B und Port D kannst Du das ganze allerdings 
noch etwas flotter bekommen, dann musst Du die Nibbles nicht in Software 
vertauschen und kannst Dir damit die Shift-Operationen sparen:
1
  data = (PINB & B00001111) + (PIND & B11110000);

: Bearbeitet durch Moderator
von Thomas W. (dbstw)


Bewertung
0 lesenswert
nicht lesenswert
Moin, -

ich kenne den 8085 nicht sehr gut, aber der Weg ueber den Ready-Eingang
waere sehr einfach und stabil hinzubekommen. Du merkst Dir den Zugriff
auf das IO-Geraet mit einem Flip-Flop, der vom Arduino zurueckgesetzt
wird.

Die Idee ist nicht von mir (ist mit einer Z80):

https://hackaday.io/project/19000-a-4-4ics-z80-homemade-computer-on-breadboard

https://github.com/SuperFabius/Z80-MBC

Und es gibt auch andere Arduinos als den UNO: Ich benutze einen Mega
fuer solche Aufgaben (5V-kompatibel, viele 8-bit Ports). Und durch
das Konstrukt Wait / Un-Wait hast Du wenig Timing-Probleme (wenn die
8085 lange warten kann).

Liebe Gruesse

Th.

von Peter S. (petersieg)


Bewertung
0 lesenswert
nicht lesenswert
Danke. Schau ich mir an werde mal probieren, was geht.

Peter

von Peter D. (peda)


Bewertung
0 lesenswert
nicht lesenswert
Peter S. schrieb:
> Die /IOW Impulse müssen wohl
> so kurz gewesen sein

Vermutungen helfen da nicht. Das genaue Timing eines IO-Zugriffs kann 
man ganz einfach dem Datenblatt entnehmen. Das enthält alle nötigen 
Timingdiagramme.

Selbst in Assembler und wenn keine Interrupts enabled sind, wird das 
Timing zu sportlich sein für einen AVR.

Für eine ähnliche Anwendung hatte ich mal den 74HC646 benutzt. Eine 
Seite schreibt was rein und die andere Seite kann es später auslesen und 
umgekehrt. Der 74F543 ist auch geeignet.

von W.S. (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Peter S. schrieb:
> Worum gehts. Ich möchte ein Arduino Uno als IO Gerät (nur lesend hier!)
> an ein 8085 Computer/Bus dran bringen.

Dafür hast du das falsche Mittel.

Es hilft auch nicht viel, den Takt des 8085 herunterzuschrauben, denn 
wenn ich mich recht erinnere, sind einige Teile in diesen alten 
Prozessoren dynamisch gemacht, so daß sie das Anhalten des Taktes 
einfach nicht vertragen.

Allenfalls könnte man eventuell mit etwas externer Logik den 8085 dazu 
bringen, Waitzyklen einzulegen, bis der Arduino aus dem Knick gekommen 
ist.

W.S.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.