Z80 Single Board Computer

Gast #7677690
Lesenswert?

Hallo!

Mein System umfasst die CPU und eine Z80 KIO. Im Moment geht es mir um den Interrupt Mode 2 für die serielle Schnittstelle. Im Polling funktioniert alles einwandfrei und auch die Echo-Funktion im im2 funktioniert. Aber wenn ich simpel einen String in den Sendepuffer schreibe, wird nur das letzte Zeichen übertragen, aber dafür Anzahl Zeichen Mal oft.

Zweites Phänomen. Wenn ich das Umkopieren von Empfangspuffer zu Sendepuffer und das Senden auskommentiere, sehe ich den Tx-Puffer wachsen und nicht den Rx-Puffer wenn ich auf der Konsole was eingebe.

Vermutlich ist der Fehler etwas sehr simples, aber ich komme nicht drauf...

Ich programmiere in C mit sdcc und einem eigenen Startup Skript.

Hat jemand eine Idee was hier die Ursache ist bzw. einen Verbesserungsvorschlag für das Handling?

Danke und LG

Angehängte Dateien:
#7678057
Lesenswert?

Dein Buffer ist komisch.

buf->num_entries++; num_enries? Braucht man nicht. Bei 8 bit ist der vielleicht Multi Thread Safet. Aber auch nicht da. Habe schon compilers gesehen die val = 1, mit clear F und inc F gemacht haben. Weg damit.

bool circbuff_empty(circbuff_t* buf) { return (buf->num_entries == 0); } Head ist gleich Tail dann ist der Buffer leer.

unsigned char head, tail, Das ist nicht gut mach daraus unsigned char *head und unsigned char *tail

Und hier nimmst du dann bool circbuff_write(circbuff_t* buf, unsigned char value) { if (circbuff_full(buf)) return false; *(buf->tail) = value; //buf->num_entries++; //Braucht man net Das musst du dann umschreiben bisschen. buf->tail = (buf->tail++) % CIRCBUFF_SIZE; return true; }

Ach wass, ich lade mein Buffer hoch. Da kannst du dann reinschauen.

Angehängte Dateien:
Gast #7678278
Lesenswert?

Ein Compiler Problem wird es wohl nicht sein. Und auch danke für die Optimierungsvorschläge, aber die beheben das genannte Fehlverhalten auch nicht.

Die Spezialisten haben aber sicher eine Idee. Timing? Mache ich was grundlegend falsch?

Beitrag #7678305 wurde von einem Moderator gelöscht.
#7680458
Lesenswert?

Harald N. schrieb:

Aber wenn ich simpel einen String in den Sendepuffer schreibe, wird nur das letzte Zeichen übertragen, aber dafür Anzahl Zeichen Mal oft.

Hallo Harald, keine Ahnung, ob Dein Problem inzwischen gelöst ist, aber...

circbuff.c

1
    buf->tail = (buf->tail++) % CIRCBUFF_SIZE;

und

1
    buf->head = (buf->head++) % CIRCBUFF_SIZE;

Ausdrücke a la "val = val++" sind grundsätzlich eine schlechte Idee. Mein Änderungsvorschlag ist im Anhang. Der unschöne cast ist drin, damit der Compiler nicht wg Integer Promotion die Modulo-Funktion aufruft. Vielleicht hat ja jemand eine bessere Lösung.

Angehängte Dateien:
Gast #7680464
Lesenswert?

Danke klingt plausibel und werde ich so umsetzen. Mit dem Transmitter Interrupt wird das aber vermutlich nichts zu tun haben. In der Zwischenzeit nutze ich nur noch einen Ringpuffer für den Receiver Interrupt und versende die Daten an der SIO klassisch über Polling und Datenbyte schreiben. Funktioniert soweit.

Rein akademisch macht es mich halt nicht glücklich...

#7680511
Lesenswert?

Leo C. schrieb:

Ausdrücke a la "val = val++" sind grundsätzlich eine schlechte Idee.

In C löst das offiziell undefiniertes Verhalten aus. Da kann also durchaus Blödsinn dabei rauskommen.

Leo C. schrieb:

1
    buf->tail = (unsigned char)(buf->tail + 1) % CIRCBUFF_SIZE;

Man muss die beiden Operationen nicht zwanghaft in eine Zeile stecken. So sieht es übersichtlicher aus:

1
    buf->tail++;
2
    buf->tail %= CIRCBUFF_SIZE;

Man beachte dass die %-Operation je nach Wert von CIRCBUFF_SIZE recht "teuer" sein kann.

#7682396
Lesenswert?

Rolf M. schrieb:

1
buf->tail++;
2
buf->tail %= CIRCBUFF_SIZE;

Man beachte dass die %-Operation je nach Wert von CIRCBUFF_SIZE recht "teuer" sein kann.

Man kann es aber auch gleich einfacher und schneller schreiben.

1
 
2
   buf->tail++;
3
   if (buf->tail == CIRCBUFF_SIZE) buf->tail = 0;

Das ist immer recht schnell, weil es nur einen einfachen Vergleich benötigt.

Gast #7682609
Lesenswert?

Danke für die konstruktiven Beiträge. Der Rest darf woanders herumlästern. Dieses Forum hat sich offensichtlich nicht verändert in den letzten 10 Jahren. Leider sind viele Leute, auf deren Beiträge ich gehofft hatte, offensichtlich nicht mehr hier.

#7682637
Lesenswert?

Falk B. schrieb:

Man kann es aber auch gleich einfacher und schneller schreiben.

buf->tail++; if (buf->tail == CIRCBUFF_SIZE) buf->tail = 0;

Das ist immer recht schnell, weil es nur einen einfachen Vergleich benötigt.

Ja, so in etwa schreibe ich das normalerweise auch. Das hat auch den Vorteil, dass es nicht langsamer ist, wenn die Puffergröße keine Zweierpotenz ist.

Harald K. schrieb:

Harald N. schrieb:

Der Code hat von Anfang an ohne Warnungen kompiliert.

Mit -Wall?

… und -Wextra -pedantic?

#7682669
Lesenswert?

Rolf M. schrieb:

Harald K. schrieb:

Harald N. schrieb:

Der Code hat von Anfang an ohne Warnungen kompiliert.

Mit -Wall?

… und -Wextra -pedantic?

Es geht hier um sdcc, und der hat andere Schalter. Die höchste Warnstufe ist bei ihm aber (imho) schon default.

Im übrigen hat der TO bei dem geposteten Code schon deshalb keine Warnungen bekommen, weil der Compiler mit Error abgebrochen hat.

#7682712
Lesenswert?

Harald N. schrieb:

Ähm der Code wie ich ihn bei Threaderstellung gepostet habe hat ohne Fehler und ohne Warnungen kompiliert.

Frisch ausgepackt:

1
$ sdcc -mz80 -S monitor.c
2
monitor.c:174: error 47: indirections to different types assignment   
3
from type 'const-unsigned-char [16] code'
4
  to type 'const-unsigned-char auto'
5
monitor.c:177: error 22: Array or pointer required for '[]' operation 
6
monitor.c:178: error 22: Array or pointer required for '[]' operation 
7
ernst@waldklause:~/Projekte/HaraldN/src$

Dann lad das Zip von hier nochmal runter und probiers nochmal aus. Ist nur eine Kleinigkeit, weshalb ich vorher auch nichts dazu geschrieben hatte.

Moderator Persönliche Seite #7682745
Lesenswert?

Leo C. schrieb:

monitor.c:174: error 47: indirections to different types assignment

Die Zeile 174 lautet:

1
const unsigned char text = "Hello Zilog Z80";

Da fehlt definitiv ein Sternchen und kann daher zu einem Überschreiber im RAM führen, wenn der Compiler es nicht anmeckert und das durchgehen lässt.

Es muss so heißen:

1
const unsigned char * text = "Hello Zilog Z80";
Gast #7682756
Lesenswert?

Ok stimmt. Da habe ich beim Zippen wohl eine Zwischenversion erwischt. Nur das dieser Fehler halt absolut nichts mit dem Problem oder dem Puffer zu tun hat.

1
const unsigned char* text = "Hello Zilog Z80";

Ich hatte den * vergessen um den String als Char Pointer zu deklarieren.

Natürlich hat der Code dann gebaut:

1
C:\Users\NaHa\Downloads\src>sdcc -mz80 -S monitor.c
2

3
C:\Users\NaHa\Downloads\src>

Und das lauffähige bin wurde dann auf den Flash geschrieben. Ich behaupte mal, dass ich sonst die Fehlerbeschreibung wie bei Threaderöffnung nicht machen könnte.

Gast #7682764
Lesenswert?

Zur Erklärung wie es zu dem Fehler kam: Zuerst hatte ich unsigned char text[]. Da habe ich allerdings im Assembler Code gesehen, dass das höchst ineffizient ist. Hab's zu einem unsigned char* text umgebaut und dabei den * vergessen. Beim kompilieren gemerkt, Stern ergänzt und Fehler somit behoben.

Warum ist das hier eigentlich so, dass man um Sachen herumeiert, die definitiv nichts bzw. nichts mehr mit dem eigentlichen Problem zu tun haben. Ergötzt ihr euch wirklich so sehr daran auf anderen Fehlern so herumzureiten?

Moderator Persönliche Seite #7682779
Lesenswert?

Harald N. schrieb:

Warum ist das hier eigentlich so, dass man um Sachen herumeiert, die definitiv nichts bzw. nichts mehr mit dem eigentlichen Problem zu tun haben.

Es ist nicht einfach, als Leser ein Problem nachzuvollziehen und zu helfen, wenn man selber die Hardware nicht zur Hand hat und deshalb die Möglichkeit des Debuggens nicht gegegeben ist.

Es ist weithin bekannt, dass C-Programme sehr leicht dazu neigen, dass beispielsweise ein Überschreiber im RAM an Codestelle "A" zu einem Problem an einer ganz anderen Codestelle "B" führen kann. Augenscheinlich haben für den Programmierer die Stellen A und Stellen B nicht miteinander zu tun. Da kann ich Dir tausende von Beispielen nennen.

Von daher gibt es bei C-Programmen keine "Sachen", die "definitv nichts mit dem eigentlichen Problem zu tun haben". Das ist ein Trugschluss, den man niemals außer acht lassen darf. Sonst hat man bei der Fehlersuche schon verloren.

Ergötzt ihr euch wirklich so sehr daran auf anderen Fehlern so herumzureiten?

Deine falsche Annahme ("herumeiern") oben führt zwangsweise zu einer falschen Folgerung ("ergötzen") unten. Genau wie ein Fehler im C-Programm "oben" zu einem Problem weiter "unten" führen kann. Witzige Analogie, aber hier zutreffend. Mit "Ergötzen" hat das nichts zu tun, da spielt Dir Deine Phantasie offenbar einen Streich.

Ich stelle aber an dieser Stelle freiwillig meine Hilfe ein. Dafür gescholten zu werden, einen Fehler anzumerken, ist schon ein starkes Stück.

Gast #7682794
Lesenswert?

Akzeptiert. Trotz allem. Lassen wir diese Diskussion.

Ich versuche es jetzt noch einmal mit ganz konkreten Fragen.

Vorrausschicken möchte ich, dass die Hardware funktioniert. Im Polling Modus funktioniert alles einwandfrei. Und auch jetzt, wo Rx über Interrupts und Tx über Polling läuft, funktioniert das Programm einwandfrei. Hatte sogar mcurses (hier aus dem Forum) und damit auch das Beispiel Hexeditor zum Laufen gebracht.

Hat von euch noch nie jemand eine Z80 SIO im IM2 zum Senden benutzt?

Wie kann es sein, dass ein IM2 Rx und IM2 Tx funktioniert solange ich nur ein Echo mache, aber nicht, wenn ich einen String im Programm in den Tx-Puffer schreibe?

Muss man ein besonderes Timing beachten?

Zwar keine Frage, aber ein Nachtrag: Ich habe zuletzt auch wirklich alle Stellen, wo mit dem Puffer handiert wird, mit DI -- EI umschlossen.

Moderator Persönliche Seite #7682808
Lesenswert?

Harald N. schrieb:

Das ging ja nicht gegen dich persönlich.

Naja, die Anmerkungen der anderen waren durchaus näher am Thema dran, nämlich an der Behandlung des Fifos. Da ging es bestimmt nicht um Stellen, die nichts mit dem Thema zu tun haben. Ein Increment auf der rechten Seite und Zuweisung an dieselbe Variable führt unweigerlich zu UB und geht daher in den seltensten Fällen gut.

Harald N. schrieb:

Hatte sogar mcurses (hier aus dem Forum) und damit auch das Beispiel Hexeditor zum Laufen gebracht.

Nur zur Info: Ich bin nicht nur der Autor von MCURSES hier aus dem Forum und des dazu passenden Hexeditors, sondern auch von STECCY, des ZX-Spectrum-Emulators, der natürlich auch den Z80 emuliert. Ich weiß daher im allgemeinen, wovon ich spreche ;-)

#7682827
Lesenswert?

Harald N. schrieb:

Hat von euch noch nie jemand eine Z80 SIO im IM2 zum Senden benutzt?

Doch, aber das ist fast 40 Jahre her. Damals gings allerdings um HDLC-Protokolle...

Bei den Retrobasteleien der letzten Jahre habe ich tatsächlich nichts mit Z80-SIO gefunden. Trotzdem wird sich Dein Problem wohl lösen lassen. Ich kann am Wochenende nochmal reinschauen, wenn ich wieder zu Hause bin.

#7685069
Lesenswert?

Harald N. schrieb:

Mein System umfasst die CPU und eine Z80 KIO.

Harald N. schrieb:

Hat von euch noch nie jemand eine Z80 SIO im IM2 zum Senden benutzt?

Die KIO ist ja nun offensichtlich etwas mehr als nur eine SIO: https://www.zilog.com/docs/z80/ps0118.pdf Die KIO gab es vor 40 Jahren noch nicht.

Funktioniert denn dein System mit anderen Interruptquellen?

Harald N. schrieb:

Aber wenn ich simpel einen String in den Sendepuffer schreibe, wird nur das letzte Zeichen übertragen, aber dafür Anzahl Zeichen Mal oft.

Dann funktioniert offenbar der Zeichenzähler, aber der Lesezeiger steht immer auf dem letzten Zeichen.

Ich würde zum Debuggen die funktionierende Polling-Funktion nehmen und in einem Debugspeicher den Zustand vom Lesezeiger ablegen. Den Debugspeicher könnte man sich dann per Tastendruck/Kommando/zeitgesteuert ausgeben lassen um zu schauen, was mit dem Lesezeiger so angestellt wird.

#7688113
Lesenswert?

Hallo, es hat leider etwas länger gedauert. Statt mit Z80 KIO (habe ich nicht), habe ich das Ganze mit Toshiba TMPZ84C015 getestet. Ein Chip, der neben einer Z80 CPU noch CTC, PIO, SIO und etwas Kleinkram enthält. Den gleichen Quarz habe ich auch nicht, und meiner (18,432MHz) lässt sich mit dem CTC nicht auf die üblichen Bitraten teilen. Also läuft die CTC bei mir im Counter-Mode mit extra Takt. F_CPU, BAUD und KIO oder nicht, können/sollten im Makefile eingestellt werden.

Das wichtigste bei der SIO im interrupt-Modus: Der Tx-(Transmit Buffer Empty) Interrupt kommt (nur), wenn das Senderegister leer wird, nicht wenn es leer ist. Wenn der Interrupt kommt, und der circbuf/FIFO auch leer ist, muß man den Interrupt mit dem "Reset TxINT Pending" Kommando quittieren. Den Zustand muß man sich merken, und das nächste Zeichen direkt an die SIO schicken, statt in den FIFO zu schreiben.

Im angeängten Zip-File ist noch eine Version mit meinen eigenen FIFO-Routinen. Tatsächlich hatte ich damit zuerst getestet. Die Routinen kommen ohne Zähler aus, und haben deshalb keine Variable, die von beiden Seiten geschrieben wird. Das reduziert mögliche race conditions.

Das Programm muß mit einem halbwegs aktuellen sdcc übersetzt werden, da es sich an einigen Stellen auf Parameterübergabe in Registern verlässt.

Angehängte Dateien:
Gast #7688140
Lesenswert?

Hallo Leo!

Vielen Dank für deinen Input und dass du deine Zeit geopfert hast. Alleine deine Erklärung macht Sinn und deren Nichtbeachtung führt zu dem Fehlerbild, dass ich beschrieben habe. Mein Code ist natürlich schon lange nicht mehr der den ich hier gepostet habe, aber ich werde trotzdem meine Routinen anpassen und es versuchen.

Gast #7688302
Lesenswert?

Edit:

Ich habe den Code gerade in meinen aktuellen Code eingeflechtet. Da ich mittlerweile bereits die getchar und putchar Routinen implementiert hatte, damit ich printf aus der Standardbibliothek benutzen kann, erweiterte ich mein Programm nur um die (in der Zwischenzeit auskommentierte) Tx-ISR-Routine und habe die putchar nach deinem Vorbild geändert.

Und siehe da es funkktionert. Das Prinzip des Tx-Interrupts hatte ich schon verstanden, aber offensichtlich komplett falsch umgesetzt. Vielen Dank nochmal Leo!!!

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren