ich bin grad dabei, in C (AVR Studio 6.1) ein Projektchen auf einem
Atmega 1284P zu schnitzen.
Der Atmel soll einen Datenstrom von einer ser. Schnittstelle
entgegennehmen, genau gesagt Intel-Hexfile Daten. Dabei erfolgt Annahme
der Zeichen per Interrupt. Solange ich für Ausgaben zur RS232 nur eine
simple Zeichenausgabe verwende, klappt alles. Allerdings hab ich mir aus
einem Beispielcode eine Technik abgeschaut, die mir vielversprechend
erscheint - I/O Redirect:
was mir die komfortable Möglichkeit gibt, Zeichenketten, Zahlen usw. per
printf zur ser. Schnittstelle auszugeben.
Sobald ich allerdings prinf verwende, geschehen merkwürdige Dinge, die
Zeiger des Input-Buffers spielen verrückt, der Atmel resettet. Wenn ich
auf das I/O redirect verzichte, funktioniert alles.
Ist eventuell die <stdio.h> nicht die richtige, gibt es da eine
spezielle Version für Atmega?
Der avr-gcc verwendet automatisch für alle Libraries eine spezielle
Version für den AVR. Daran kann es nicht liegen.
Ohne den Rest des Quelltextes zu sehen, kann ich nicht mehr dazu sagen.
Vermutungen:
- bist Du sicher, dass die Puffergrößen stimmen / ausreichen
- Nullterminierung gewährleistet?
Ansonsten kann man ohne Source tatsächlich nicht viel sagen.
Und aus den 2 Zeilen sollen wir nun auf das gesamte Programm schließen?
Laß den Quatsch.
Poste ein compilierbares Programm, was nicht funktioniert und eins, was
funktioniert. Als Dateianhang.
Ihr habt natürlich recht, für das Finden der Fehlerursache müsste man
den ganzen Quelltext posten. Aber darum ging es mir eigentlich auch
garnicht, das möchte ich niemandem zumuten, längere Quelltexte für mich
durchzusehen. Ich hatte tatsächlich nur (etwas zu wortreich) fragen
wollen, ob das die "richtige" stdio.h Bibliothek war, die ich da
eingebunden habe.
Inzwischen konnte ich das Problem etwas weiter einkreisen -
wahrscheinlich ist es die Hardware und nicht die Software, die hier
Probleme macht. Es handelt sich um einen Breadboard-Aufbau. Hab das
Programm inzwischen Stück für Stück vereinfacht, auf fast schon
elementares Test-Minimum. Der Atmel macht sporadisch immer mal Unfug
bzw. rebootet gelegentlich. Muss wohl mal das Oszi ausgraben und an der
Stromversorgung messen, ggf. alles neu zusammenstecken...
Trotzdem vielen Dank, die Aussage dass diese stdio.h beim AVR-GCC die
richtige ist war für mich ein Lerneffekt.
Sorry wenn ich das Thema noch mal hochhole, aber nach paar Tagen
rumgemurkse zweifel ich so langsam an meinen geistigen Fähigkeiten.
Ich hab den Testcode inzwischen immer weiter vereinfacht, um dem Problem
auf die Spur zu kommen, aber ich bekomme es nicht hin. Auch ohne das I/O
redirect verhält sich mein Testaufbau komisch. Hab den zusammengekürzten
Testcode mal angehängt, der macht jetzt nichts weiter mehr als Zeichen
von der ser. Schnittstelle entgegennehmen, und Zeichen wieder
auszugeben.
Ist von der Schaltung momentan nur noch der 1284P, der mit 18,432 MHz
ext. Quarz läuft (Fuses: FF D9 FF) sowie der MAX für die serielle
Schnittstelle. Hab den Bradboardaufbau auch schon mal komplett
auseinandergerupft und wieder neu aufgebaut.
Das Problem: wenn ich vom Terminalprogramm größere Datenmengen
übertrage, klappt es nur stabil, wenn ich die Datenmenge auf ca 120
Zeichen pro Sekunde limitiere. Wenn ich einen größeren Wert einstelle,
oder die Limitierung abschalte kommt nur noch Datensalat, gelegentlich
resettet der Atmel dann sogar. Eigentlich sollte der das bei ca. 18MHz
mit links hinbekommen? Bin mit meinem Latein völlig am Ende.
Als Anhang der Testcode, soweit vereinfacht wie es nur geht.
ist noch ein Fehler drin: Du guckst nämlich nicht drauf, ob dein
Ringpuffer überläuft. D.h. buf_usage kann ohne Fehler größer als
SERBUFSIZE werden. Dann überschreibst du den Anfang des Ringbuffers und
gibst dementsprechend Schrott aus. Dieser Überlauf kann auftreten, da du
ja für ein empfangenes '\r' zwei Zeichen ausgibst, '\r' und '\n'. D.h.
nach 1024 empfangenen '\r' mit max. Übertragungsrate hast du den
Ringbuffer-Überlauf.
Zum verifizieren, ob dieser Fall auftritt: Schreib ein spezielles
Zeichen in den Ringbuffer, wenn buf_usage. > 1024. Z.b so
vielen Dank katastrophenheinz für den Hinweis - auf jeden Fall stimmt
es dass mein Code nicht gegen Pufferüberlauf abgesichert ist. Trotzdem
denke ich dass die Input/Output Bilanz stimmt, da der Input per
Interrupt angenommen wird und der Output immer genau soviele Zeichen
"abholt" wie hereinkommen.
Inzwischen hab ich einen Fehler in dem oben geposteten Code entdeckt:
muss ja in C die Variablen serInPointer, serRdPointer und buf_usage am
Anfang auf 0 initialisieren! Bin halt Basic-geschädigt ;) Nachdem ich
das gemacht habe laufen die Testruns deutlich stabiler.
Allerdings hab ich ermittelt, dass bei dieser Art der Programmierung bei
ca. 240 Zeichen pro Sekunde eine Art Stabilitätsgrenze liegt. Eventuell
ist es einfach ne gute Idee den Atmel beim Einlesen von Intel Hex Files
nicht jedes Zeichen zum Terminal zu "echoen" sondern bloß einen Punkt
pro Zeile. Ich glaub der Output blockt zuviel Zeit.
Die serielle Verbindung ist momentan eine minimale 3-Draht Verbindung
TxD, RxD, GND. Weder Hardware- noch Software-Handshake.
>Trotzdem denke ich dass die Input/Output Bilanz stimmt
Nein, bau mal meine Änderung ein, du wirst sehen, irgendwann hast du *
in deiner Ausgabe.
>da der Input per>Interrupt angenommen wird und der Output immer genau soviele Zeichen>"abholt" wie hereinkommen.
Das schon, du sendest jedoch mehr Zeichen zurück als ankommen.
Wenn nun also ausreichend viele '\r' ankommen, läuft dein
Eingangsringpuffer langsam voll, weil der Interrupt zwar immer schön
weiter füllt, du aber mit dem Abholen via uart_getchar() nicht
hinterherkommst, denn du musst ja für ein empfangenes '\r' zwei Zeichen
rausschreiben und das tust du, indem du aktiv wartest. Schneller Senden
als Empfangen kannst du auch nicht, also dauert das Senden einfach
länger, weil die Anzahl der zu sendenden Zeichen größer ist als die der
empfangenen Zeichen.
Drei Lösungsvorschläge:
- Nicht mehr Zeichen senden als du empfängst. Wenn du dein Prg zum
Empfang von iHex-Dateien verwenden willst, dann sende z.B. nur ein
Zeichen am Ende jeder Zeile zurück
- Beim Senden an den AVR ab und zu mal ne Pause einlegen ( So macht das
beispielsweise mein Terminalprogramm )
- Handshake implementieren: Xon/Xoff oder Hardware ist egal.
Gruss, Heinz