Forum: Compiler & IDEs Problem mit UART Library von Peter Fleury


von Micha (Gast)


Lesenswert?

ich hab die Tage eine Experimental-Schaltung zusammengebastelt, um 
zunächst die Anbindung Atmega <--> PC für sich zu testen, in 
Vorbereitung für ein eigenes, komplexeres Projekt. Ich teste immer gern 
alle Aspekte zunächst separat.
Die Schaltung besteht im wesentlichen aus einem mit 18,432 MHz 
getakteten Atmega 644P und einem Pegelwandler MAX3232, letzterer 
entsprechend Datenblatt mit 100nF Kondensatoren beschaltet.
Verbindung zum Terminal ohne Hardwarehandshake als 
Drei-Leiter-Verbindung TxD, RxD über Kreuz, sowie Ground mit Ground. 
Konfiguration an beiden Enden 9600,8N1, am Terminal ohne 
Software-Flow-Control eingestellt.

Ich verwende die C Bibliothek von Peter Fleury. Soweit ich bisher 
recherchiert habe ist das die meist-verwendete Bibliothek für diesen 
Zweck(?)
Bisher sind meine Tests ausschliesslich auf dem Beispielcode von Peter 
Fleury für das Hauptprogramm basiert.
Die Übertragungsrichtung Atmega --> Terminal klappt von Anfang an 
problemlos, also sowas wie uart_puts("bla bla"\r\n); geht.

Solange die interrupt-basierte Abfrage des UART-Ports im Hintergrund vor 
sich hinwerkelt, läuft auch alles stabil.
Aber sobald in der Hautpschleife des Peter-Fleury Beispiel main 
Programms uart_getc() mit hoher Frequenz ausgeführt wird führt der 
Atmega nach paar Tastendrücken am Terminal ein Reboot aus. Hab in jene 
Schleife mal ein _delay_ms(5) eingebaut - und sofort läuft alles stabil. 
Ich hab mich die letzten Tage fast zu Tode gegoogelt auf der Suche nach 
Hinweisen zu diesem Problem.

Kann es sein dass die Funktion uart_getc() aus der Peter-Fleury 
irgendwas unsauberes mit den Ringpuffer-Pointern macht wenn sie (schnell 
getakteter Atmega und langsame Baud-Rate) viel öfter in Aktion tritt als 
der UART-Recieve-Interrupt?

von Noname (Gast)


Lesenswert?

An sich ist alles möglich. Aber der Code von Peter ist schon relativ oft 
verwendet worden und falls das öfter passiert, wäre es hier im Forum zu 
finden. Such doch mal.
Um aber konkret auf Dein Problem einzugehen, wäre es gut zu wissen, 
welchen Code Du genau verwendet hast. Es gibt nämlich verschiedene 
Versionen davon und ein paar Leute haben den Code noch variiert. Poste 
bitte mal einen Link genau auf den Beitrag wo Du den Code her hast.

von Noname (Gast)


Lesenswert?

Es wäre auch wichtig Deinen Code dazu zu sehen.
Ich kann mir aber auf Anhieb nicht vorstellen, das ein wildgewordener 
Zeiger in den UART Funktionen von Peter das Problem ist.

von Micha (Gast)


Lesenswert?

na von dorten:
http://homepage.hispeed.ch/peterfleury/avr-software.html

Im code des test-Hauptprogramms, im unteren Teil, in der Endlosschleife

for(;;)
{

...

}

crasht das Programm nach paar Tastendrücken am Terminal, wenn ich es so 
lasse wie es ist. Wenn ich entweder das uart_getc() auskommentiere oder 
einen Delay einfüge läuft alles stabil - im ersten Fall natürlich 
funktionslos ohne Eingabe.

Mein persönlicher Verdacht: da spielen 2 Faktoren eine Rolle:
1. verwenden die meisten Anwender sowieso nur die Datenrichtung Atmega 
--> PC
2. verwenden die meisten wahrscheinlich höhere Datenraten als 9600.

Ich vermute das Problem besteht wenn uart_getc() häufiger auftritt als 
die ISR, die Daten in den Ringpuffer tut...

von Stefan E. (sternst)


Lesenswert?

Micha schrieb:
> na von dorten:
> http://homepage.hispeed.ch/peterfleury/avr-software.html

Welcher Code genau? Poste ihn doch einfach, statt irgendwelcher 
Verweise.

Micha schrieb:
> Ich vermute das Problem besteht wenn uart_getc() häufiger auftritt als
> die ISR, die Daten in den Ringpuffer tut...

Dass das uart_getc der Fleury-Lib nicht blockierend arbeitet, und also 
auch so was wie "kein Zeichen verfügbar" zurück geben kann, hast du aber 
bedacht, oder?

von Karl H. (kbuchegg)


Lesenswert?

Micha schrieb:

> Im code des test-Hauptprogramms, im unteren Teil, in der Endlosschleife
>
> for(;;)
> {
>
> ...
>
> }
>
> crasht das Programm nach paar Tastendrücken am Terminal,

Du verwendest den Code ohne irgendwelche Änderungen? Richtig?

> Mein persönlicher Verdacht: da spielen 2 Faktoren eine Rolle:
> 1. verwenden die meisten Anwender sowieso nur die Datenrichtung Atmega
> --> PC
> 2. verwenden die meisten wahrscheinlich höhere Datenraten als 9600.

Antwort auf beide Vermutungen:
Spielt alles keine Rolle. Deswegen darf der Code nicht crashen.

Solange du händisch am Terminal tippst, kannst du tun was du willst, 
diesen Code darfst du nicht zum Crashen bringen. So schnell kannst du 
nicht tippen.

von Noname (Gast)


Lesenswert?

>na von dorten:
Was heisst "na"? Nur weil Du eine Quelle gefunden hast, heisst, das ja 
nicht, das es die einzige ist. ;-) Ich z.B. hab meine Variante hier 
aus dem Forum. Such mal hier im Forum nach Peter Fleury. Da findest Du 
noch weitere Varianten.

Ich habe mal nachgeguckt, aber in der getc routine kann aus meiner Sicht 
nichts crashen, egal wie häufig man die aufruft. Wenn kein Zeichen da 
ist, ist halt keins da und wenn doch wird der Index UART_RxTail nur in 
getc verändert.

Deine Vermutung muss deswegen nicht falsch sein, aber hat es doch nötig 
durch Informationen erhärtet zu werden.

von Micha (Gast)


Lesenswert?

ja ich weiss, so ein Problem ist immer irgendwie ne komplexe Mischung 
aus möglichen Hard- und Software- Ursachen. Ich hab leider vorläufig 
nicht das Equipment (Speicher-Oszi, Logik-Analyzer) um Hardware-Probleme 
zuverlässig einzukreisen.

Ich hänge mal unten den aktuellen Stand meines Experimental-Codes an. 
Startpunkt für das Hauptprogramm war test_uart.c aus dem Archiv direkt 
von Peter Fleury's Webpage. Strings vom Atmega zum Terminal hat von 
Anfang an gut geklappt.

Hab zunächst mal die PROGMEM Sachen rausgetan um eine mögliche Ursache 
zu eliminieren. Ohne Erfolg. Dann hab ich verschiedenes ausprobiert. Mit 
dem Code wie angehängt resettet der Atmega jeweils nach ca. 2 bis 10 
Tastaturanschlägen auf dem Terminal. Wenn ich die Zeile mit 
*uart_getc()* auskommentiere läuft der Atmega stabil durch. Wenn ich ein 
*_delay_ms(5)* in die Hauptschleife einfüge läuft es ebenfalls stabil, 
dann bekomme ich sogar die Zeichen wieder aufs Terminal ge-echot. Läuft 
stundenlang, ohne Zeichen-Verlust.

Ich hab die Zeile mit dem delay mit >>> <<< markiert, das ist 
selbstverständlich nicht Teil des eigentlich verwendeten Quelltexts:
1
/*************************************************************************
2
3
Title:    example program for the Interrupt controlled UART library
4
5
Author:   Peter Fleury <pfleury@gmx.ch>   http://jump.to/fleury
6
7
File:     $Id: test_uart.c,v 1.4 2005/07/10 11:46:30 Peter Exp $
8
9
Software: AVR-GCC 3.3
10
11
Hardware: any AVR with built-in UART, tested on AT90S8515 at 4 Mhz
12
13
14
15
DESCRIPTION:
16
17
          This example shows how to use the UART library uart.c
18
19
20
21
*************************************************************************/
22
23
24
25
/* define CPU frequency in Mhz here if not defined in Makefile */
26
27
#ifndef F_CPU
28
29
#define F_CPU 18432000    // do NOT append UL to this number
30
31
#endif
32
33
34
35
#include <stdlib.h>
36
37
#include <avr/io.h>
38
39
#include <avr/interrupt.h>
40
41
// #include <avr/signal.h>
42
43
#include <avr/pgmspace.h>
44
45
#include <util/delay.h>
46
47
48
49
#include "uart.h"
50
51
52
53
54
55
56
57
/* 9600 baud */
58
59
#define UART_BAUD_RATE      9600      
60
61
62
63
64
65
int main(void)
66
67
{
68
69
  // set unused ports to OUTPUT mode
70
71
  DDRA = 0b11111111;
72
73
  DDRC = 0b11111111; 
74
75
  DDRD |= 0b11111100;
76
77
  DDRB = 0b11111111;
78
79
    unsigned int c;
80
81
    char buffer[7];
82
83
    int  num;
84
85
86
87
    
88
89
    /*
90
91
     *  Initialize UART library, pass baudrate and AVR cpu clock
92
93
     *  with the macro 
94
95
     *  UART_BAUD_SELECT() (normal speed mode )
96
97
     *  or 
98
99
     *  UART_BAUD_SELECT_DOUBLE_SPEED() ( double speed mode)
100
101
     */
102
103
    uart_init( UART_BAUD_SELECT(UART_BAUD_RATE,F_CPU) ); 
104
105
    
106
107
    /*
108
109
     * now enable interrupt, since UART library is interrupt controlled
110
111
     */
112
113
    sei();
114
115
    
116
117
    /*
118
119
     *  Transmit string to UART
120
121
     *  The string is buffered by the uart library in a circular buffer
122
123
     *  and one character at a time is transmitted to the UART using interrupts.
124
125
     *  uart_puts() blocks if it can not write the whole string to the circular 
126
127
     *  buffer
128
129
     */
130
131
    uart_puts("COMMODORE BASIC V2\r\n");
132
133
    
134
135
    /*
136
137
     * Transmit string from program memory to UART
138
139
     */
140
141
    uart_puts("39387 BASIC BYTES FREE.\r\n");
142
143
    
144
145
        
146
147
    /* 
148
149
     * Use standard avr-libc functions to convert numbers into string
150
151
     * before transmitting via UART
152
153
     */     
154
155
    for (num=0;num<=1000;num++) {
156
157
    itoa( num, buffer, 10);   // convert integer into string (decimal format)        
158
159
    uart_puts("next number is ");
160
161
    uart_puts(buffer);        // and transmit string to UART
162
163
    uart_puts("\r\n");
164
165
  }  
166
167
    
168
169
    /*
170
171
     * Transmit single character to UART
172
173
     */
174
175
    // uart_putc('\r');
176
177
    uart_puts("\r\n");
178
179
    for(;;)
180
181
    {
182
183
        /*
184
185
         * Get received character from ringbuffer
186
187
         * uart_getc() returns in the lower byte the received character and 
188
189
         * in the higher byte (bitmask) the last receive error
190
191
         * UART_NO_DATA is returned when no data is available.
192
193
         *
194
195
         */
196
197
>>>  _delay_ms(10);    <<<
198
199
        c = uart_getc();
200
201
        if ( c & UART_NO_DATA )
202
203
        {
204
205
            /* 
206
207
             * no data available from UART 
208
209
             */
210
211
        }
212
213
        else
214
215
        {
216
217
            /*
218
219
             * new data available from UART
220
221
             * check for Frame or Overrun error
222
223
             */
224
225
            if ( c & UART_FRAME_ERROR )
226
227
            {
228
229
                /* Framing Error detected, i.e no stop bit detected */
230
231
                uart_puts("UART Frame Error: ");
232
233
            }
234
235
            else if ( c & UART_OVERRUN_ERROR )
236
237
            {
238
239
                /* 
240
241
                 * Overrun, a character already present in the UART UDR register was 
242
243
                 * not read by the interrupt handler before the next character arrived,
244
245
                 * one or more received characters have been dropped
246
247
                 */
248
249
                uart_puts("UART Overrun Error: ");
250
251
            }
252
253
            else if ( c & UART_BUFFER_OVERFLOW )
254
255
            {
256
257
                /* 
258
259
                 * We are not reading the receive buffer fast enough,
260
261
                 * one or more received character have been dropped 
262
263
                 */
264
265
                uart_puts("Buffer overflow error: ");
266
267
            }
268
269
      else uart_putc( (unsigned char)c );
270
271
        }
272
273
    }
274
275
}

von Noname (Gast)


Lesenswert?

Ich denke, das es sich um eine Hardwareproblem handelt?

Bei welcher Spannung läuft Dein Prozessor und der Max?
Hast Du Abblockkkondensatoren am Prozessor?

von Noname (Gast)


Lesenswert?

Wie versorgst Du die Schaltung? Strombegrenzung mal hochgedreht?

von Micha (Gast)


Lesenswert?

mag ich überhaupt nicht ausschliessen dass es ein Hardware-Problem ist. 
Ich hab zwei Varianten ausprobiert:

1) Mit 4,5V (Pack aus drei AA Batterien).

2) Mit einem käuflich erworbenen 5V Netzteil, in dem Fall hab ich einen 
100uF Elko zwischen Netzteil und Schaltung. Ohne den Elko geht 
garnichts, da gibts jede Menge Fehler bzw Resets, mit dem Elko geht 
Senden stabil, und empfangen mit _delay auch.

Aus praktischer Sicht hab ich das Problem ja inzwischen gelöst, ein 5us 
Delay reicht (im Listing waren es 10 us), würde mich aber trotzdem 
interessieren wo das Problem liegt.

Der Maxim MAX3232 den ich verwende braucht laut Datenblatt "nur" 100nF 
Kondensatoren um die Pegelwandlung von 0..5V auf -12..+12V hinzuzaubern. 
Ist das womöglich fauler Zauber? Sollte ich mir doch dringend einen 
Speicheroszi bzw. einen Logikananlyzer besorgen? Fragen über Fragen...

von Noname (Gast)


Lesenswert?

Also bei dem MAX3232 habe ich im Datenblatt andere Angaben zu den 
Kondensatoren gefunden. Nicht alles 100nf sondern 47nF und 330nF resp. 
100nF und 470nF. Siehe Seite 7, Bild 4.

Das

>Ohne den Elko geht
>garnichts, da gibts jede Menge Fehler bzw Resets, mit dem Elko geht
>Senden stabil, und empfangen mit _delay auch.

deutet auch darauf hin, das Du Probleme mit der Stromversorgung hast.
Nachdem Du die Kondensatoren am Max korrigiert hast, könntest Du da auch 
mal mit anderen Kondensatoren spielen.
Was ist das für ein Netzteil? Schaltregler, Linearregler oder nur Trafo 
mit Gleichrichter?

von dunno.. (Gast)


Lesenswert?

so messgeräte sind auf jeden fall nicht verkehrt..

neben dem 100µF elko hast du natürlich auch noch die obligatorischen 
100nF kerkos zum abblocken an den vcc/gnd pins des µC?

von Noname (Gast)


Lesenswert?

>Aus praktischer Sicht hab ich das Problem ja inzwischen gelöst...

ist jedenfalls ein Irrtum. Die Software ist OK und wird durch ein Delay 
in keiner Weise verbessert. Du beseitigst nicht die Ursache sondern die 
Symptome.
Das Delay deutet übrigens auch auf Probleme mit der Stromversorgung und 
zwar in Bezug auf den Max. Denn das Delay bedeutet das der Wandler mehr 
Zeit hat, nach einer Belastung auf Sollausgangsspannung zu kommen.

von Noname (Gast)


Lesenswert?

>neben dem 100µF elko hast du natürlich auch noch die obligatorischen
>100nF kerkos zum abblocken an den vcc/gnd pins des µC?

Ja. Genau. Das habe ich Dich ja auch gefragt, aber Du hast darauf nicht 
geantwortet.

von Micha (Gast)


Lesenswert?

war nicht böse gemeint, ist nur verwirrend wenn alle "Noname" heissen.

Ja, ich hab nen 100nF am Prozessor. Aber ich muss mir wohl wirklich 
dringend entsprechende Messtechnik zulegen. Ideal sind ja immer alles 
Rechteck-Impulse. Aber was ich inzwischen so auf diversen Websiten zum 
Thema Digitaltechnik und Signale gesehen hab macht mich schon 
nachdenklich...
Ich war seit langen ein "Softie" der sich nur mit Programmierung 
beschäftigt hat, in der Hardware Welt der Atmels bin ich erst seit rel. 
kurzer Zeit unterwegs.

von dunno.. (Gast)


Lesenswert?

da es ja wirklich nen HW problem zu sein scheint, poste doch mal nen 
schaltplan/layout?

von Noname (Gast)


Lesenswert?

>war nicht böse gemeint, ist nur verwirrend wenn alle "Noname" heissen.

Verstehe ich nicht. Worauf beziehst Du Dich?
Ich bin immer derselbe Noname. Alle anderen sind billige Kopien. :-)

Was ist jetzt mit dem Max und den Kondensatoren? Was mit dem Netzteil?

von Uwe (de0508)


Lesenswert?

Hallo Micha,

bitte mache auch noch ein paar Bilder.

Ist auch Port A == AVCC, AGND nach Datenblatt, AP beschaltet ?

Siehe: www.atmel.com/dyn/resources/prod_documents/doc8011.pdf

2.3.10

von Micha (Gast)


Lesenswert?

das Datenblatt des Herstellers MAXIM das mir bisher vorlag gibt für die 
Beschaltung des MAX3232 durchgängig 100nF an. Das oben zitierte 
Datenblatt ist von Texas Instruments, gibt tatsächlich teils andere 
Werte vor. Ich glaub inzwischen die Chip-Hersteller sind teils noch viel 
schlampiger als Du und Ich...

von Noname (Gast)


Lesenswert?

Mein Fehler. Hab ich nicht daran gedacht.

Hast Du den wirklich von MAXIM-Dallas? Schau mal auf den Chip welches 
Logo zu sehen ist.

Die Hersteller sind aber durchaus nicht schlampig. Obwohl die Chips 
gleich heissen, brauchen sie, je nach Hersteller unterschiedliche 
Kondensatoren. Das ist schon ok so.

Trotzdem hast Du meiner Ansicht nach ein Problem mit der 
Stromversorgung. Also auf jeden Fall noch 100nF parallel zu dem Elko am 
Netzteil. Falls es nicht geht, anderes Netzteil probieren.

Was für ein Netzteil ist das denn jetzt? Hast immer noch nicht 
geantwortet und ich werde nicht nochmal fragen.

von Micha (Gast)


Lesenswert?

der MAX3232 den ich verwende (bei reichelt gekauft) trägt tatsächlich 
das Logo von Maxim.

Die Stromversorgung hab ich bei komputer.de gekauft, ist so ein Teil:
http://www.komputer.de/zen/index.php?main_page=product_info&cPath=22&products_id=127
Wie schon gesagt, geht nur stabil mit einem 100uF Kondensator dahinter.

von Noname (Gast)


Lesenswert?

>der MAX3232 den ich verwende (bei reichelt gekauft) trägt tatsächlich
>das Logo von Maxim.
OK.

Hm. Das "Netzteil". Wie versorgst Du es? Über USB oder über die 
Hohlsteckerbuchse? Falls USB, dann könnte es sein, das sich Dein Host 
streng an die USB-Spec. hält und Dich nur wenig Strom ziehen lässt, vor 
allem wenn es auf enumerationsanforderungen nicht reagiert. Offen gesagt 
ist das Ding aus meiner Sicht sowieso Murks. Es gibt weder ein 
Datenblatt noch funktioniert die auf der Platine angegebene Website. Da 
sind noch so Halbleiter zu sehen, die sicher auch nicht für umsonst 
arbeiten (soll heissen ohne Spannungsabfall).

Nimm lieber was richtiges. Das Ganze zeigt mit jedem bekannt werdenden 
Detail immer weiter in Richtung Probleme mit der Stromversorgung.

Was hast Du für Messgeräte und alternative Stromversorgungen (ausser 
Batterie).

von Noname (Gast)


Lesenswert?

>Wie schon gesagt, geht nur stabil mit einem 100uF Kondensator dahinter.
Nein. Es geht nicht stabil, da die UART-Kommunikation abbricht.
Denke Dir das nicht so zurecht, das es "fast" passt und nur noch das 
Delay fehlt.

von Micha (Gast)


Lesenswert?

ich hab hier ehrlich gesagt ein massives Verständnisproblem: Die 
Kommunikation zwischen RS232 und Atmel wird über Interrupt-Routinen 
abgewickelt, die die ganze Zeit aktiv sind.
Wenn ich uart_getc() garnicht einbinde (oder mittels delay) in größeren 
Zeitabständen, dann kann ich wie verrückt auf der Tastatur des 
angeschlossenen Terminals herumtippen - ohne dass der Atmel in ein Reset 
gerät. Kann auch beliebig Strings zur RS232 ausgeben mittels uart_puts() 
zu Kontrollzwecken.

Erst wenn ich uart_getc() in schneller Folge ausführen lasse gibt es 
nach paar Tastendrücken ein Reset. Aber uart_getc() macht doch nichts 
mit der Hardware direkt sondern guckt nur in den Ringpuffer ob Zeichen 
da sind. Hab ich einen Denkfehler? Nach meinem Verständnis deutet das 
auf einen Konflikt zwischen Interrupt-Routine und uart_getc() hin?

Was Stromversorgung angeht hab ich bisher nichts "ordentliches". Über 
Tips wär ich dankbar. Ist ein sog. "Labornetzteil" sinnvoll für solche 
Versuche auf Breadboard-Basis?

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.