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?
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.
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.
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...
…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.
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.
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.
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.
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?
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.
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.
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 ;-)
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.
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.
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.
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!!!