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
Hallo Harald,
kann Dir bei Deinem Problem leider nicht direkt weiterhelfen, vermute
aber, dass Dein Beitrag im Compiler-Unterforum besser aufgehoben wäre:
https://www.mikrocontroller.net/forum/gcc
Im Betreff würde ich das genaue Problem noch kurz umreißen, damit der
Leser vorab weiß, worum es genau geht.
VG und viel Erfolg, Z80 Ahoi :)
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.
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?
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.
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...
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:
Hans-jürgen H. schrieb:> buf->tail = (buf->tail++) % CIRCBUFF_SIZE;>> bringt doch das gleiche Ergebnis wie:>> buf->tail = (buf->tail) % CIRCBUFF_SIZE;
Das erste Beispiel ist unzweifelhaft falsch, das zweite ist unsinnig
(falls sich nicht irgendwer darum kümmert irgendwo zu inkrementieren).
Rolf M. schrieb:> buf->tail++;> 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.
…oder gleich einen 2^n großen Buffer verwenden…
Aus dem notwendigen INC und AND macht der Compiler einen viertel-Opcode,
bei geringerer Optimierung vielleicht einen Halben. ;-)
Ja klingt ja alles sehr interessant. Warum der IM2 Transmit nicht
funktioniert weiß ich noch immer nicht. Der Buffer funktioniert
jedenfalls. Mittlerweile ist I2C und SPI implementiert.
Hans-jürgen H. schrieb:> buf->tail = (buf->tail++) % CIRCBUFF_SIZE;>> bringt doch das gleiche Ergebnis wie:>> buf->tail = (buf->tail) % CIRCBUFF_SIZE;
Das mag bei dir der Fall sein, aber allgemein gilt das nicht. Wie
gesagt: Das verhalten der ersten Zeile ist undefiniert.
Harald N. schrieb:> Warum der IM2 Transmit nicht> funktioniert weiß ich noch immer nicht.
Tja so ist das bei der Fehlersuche. Zunächst bereinigt man alle
offensichtlichen Fehler und natürlich alles wovor der Compiler warnt.
Dann, erst dann, kümmert man sich um den Rest.
Wer redet von Compiler Warnungen? Der Code hat von Anfang an ohne
Warnungen kompiliert... Aber für mich ist das Problem vorerst erledigt
da anders gelöst.
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.
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?
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.
Leo C. schrieb:> monitor.c:174: error 47: indirections to different types assignment
Die Zeile 174 lautet:
1
constunsignedchartext="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:
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
constunsignedchar*text="Hello Zilog Z80";
Ich hatte den * vergessen um den String als Char Pointer zu deklarieren.
Natürlich hat der Code dann gebaut:
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.
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?
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.
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.
Frank M. schrieb:>> Ich stelle aber an dieser Stelle freiwillig meine Hilfe ein. Dafür> gescholten zu werden, einen Fehler anzumerken, ist schon ein starkes> Stück.
Das ging ja nicht gegen dich persönlich. Aber wie gesagt, das Forum hat
sich nicht verändert.
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 ;-)
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.
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.
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.
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.
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!!!
Manfred P. schrieb:> Und nun hat sich's aus-ge-zettet, gerade die Tage gelesen.
Hallo Manfred,
auch schon aufgewacht???
Und wie immer: Auch dein angefügter Beitrag ist inhaltlich falsch, aber
da kann du nix dafür.
Beitrag "Re: Das Ende des Z80"