Forum: Mikrocontroller und Digitale Elektronik Atmega, Problem mit I/O redirect


von Micha (Gast)


Lesenswert?

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:
1
#include <stdio.h>
2
3
...
4
5
   FILE usart_output = FDEV_SETUP_STREAM(usart_putchar, NULL, 
6
_FDEV_SETUP_WRITE);
7
//    FILE usart_input = FDEV_SETUP_STREAM(NULL, usart_getchar, 
8
_FDEV_SETUP_READ);
9
    stdout = &usart_output;
10
//    stdin  = &usart_input;
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?

von Stefan (Gast)


Lesenswert?

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.

von Conny G. (conny_g)


Lesenswert?

Vermutungen:
- bist Du sicher, dass die Puffergrößen stimmen / ausreichen
- Nullterminierung gewährleistet?

Ansonsten kann man ohne Source tatsächlich nicht viel sagen.

von Peter D. (peda)


Lesenswert?

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.

von Micha (Gast)


Lesenswert?

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.

von Micha (Gast)


Angehängte Dateien:

Lesenswert?

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.

von katastrophenheinz (Gast)


Lesenswert?

Hier
1
ISR (USART0_RX_vect)
2
{
3
uint8_t c;
4
  c = UDR0;      // get one more char from serial line
5
  serbuffer[serInPointer++] = c;
6
  serInPointer &= (SERBUFSIZE - 1);
7
  buf_usage++;
8
}  // end of ISR
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
1
ISR (USART0_RX_vect)
2
{
3
uint8_t c;
4
  c = UDR0;      // get one more char from serial line
5
         if ( ++buf_usage > SERBUFSIZE ) 
6
         serbuffer[serInPointer] = '*';
7
         else
8
            serbuffer[serInPointer] = c;
9
         serInPointer++;
10
  serInPointer &= (SERBUFSIZE - 1);
11
}  // end of ISR

von Micha (Gast)


Lesenswert?

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.

von katastrophenheinz (Gast)


Lesenswert?

>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

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.