Forum: Mikrocontroller und Digitale Elektronik ATmega128 und sprintf() -> Stürzt ab


von Boxi B. (boxi)


Lesenswert?

N'Abend!

folgedes kleines Programm, um das Problem zu reproduzieren:
1
#include <stdio.h>
2
#include <avr/io.h>
3
#include <avr/pgmspace.h>
4
#include "types.h"
5
6
static int uart_send(char data)
7
{
8
  while (((UCSR1A >> UDRE1) & 1) == 0){}
9
  UDR1 = data;
10
  return 0;
11
}
12
13
void uart_send_string(char *string)
14
{
15
  uint8_t i = 0;
16
  while(string[i] != 0)
17
  {
18
    uart_send(string[i++]);
19
  }
20
}
21
22
UI8 z[100];
23
  
24
int main()
25
{
26
  UBRR1L = 9;
27
  UCSR1B |= (1<<TXEN0);
28
  UCSR1C |= (1<<UCSZ01) | (1<<UCSZ00);
29
30
  sprintf(z, "\ndgartztkuzjuze etaear weeu tatawet rtaf\n\r");
31
  uart_send_string(z);
32
33
  while (1)
34
  {
35
    static UI16 i = 0;
36
37
    sprintf(z, "sdfgd %d etgaga\r", i);
38
    uart_send_string(z);
39
    i++;
40
  }
41
 
42
}


Verhalten: Auf einem ATmega128 läuft das Programm nicht stabil. 
Irgendwann hängt der Controller oder läuft in einen Resetvektor.
In einem Terminal sieht die Ausgabe in etwa so aus:
1
dgartztkuzjuze etaear weeu tatawet rtaf
2
sdfgd 165 etgaga
3
dgartztkuzjuze etaear weeu tatawet rtaf
4
sdfgd 1291 etgagaaga
5
dgartztkuzjuze etaear weeu tatawet rtaf
6
sdfgd 690 etgaga
7
dgartztkuzjuze etaear weeu tatawet rtaf
8
sdfgd 1137 etgaga
9
dgartztkuzjuze etaear weeu tatawet rtaf
10
sdfgd 386 etgaga
11
dgartztkuzjuze etaear weeu tatawet rtaf
12
sdfgd 960 etgagagaga

Ersetzt man den sprintf-Aufruf in der while-Schleife durch
1
sprintf(z, "sdfgd etgaga\r");
tritt das Problem nicht mehr auf

Auch wenn ich
1
uart_send_string(z);
aus der Schleife entferne, besteht das Problem weiterhin.

Da geht also definitiv was beim sprintf() schief und auch nur wenn 
Umwandlungszeichen im Formatstring verwendet werden.

Lasse ich das Programm für einen ATmega2561 oder ATmega32 compilieren 
und laufen, tritt das Problem auch nicht auf.

Kennt jemand dieses Verhalten und hat eine Lösung dafür?

Danke vielmals
Boxi

von Stefan E. (sternst)


Lesenswert?

Boxi Boxitec schrieb:
> Verhalten: Auf einem ATmega128 läuft das Programm nicht stabil.
> Irgendwann hängt der Controller oder läuft in einen Resetvektor.

Was heißt hier "irgendwann"? Dass nach jedem "sdfgd..." wieder ein 
"dgartzt..." kommt, zeigt doch, dass schon beim ersten 
Schleifendurchlauf etwas gewaltig schief läuft.

Die M103C-Fuse ist aber schon aus, oder?

von Boxi B. (boxi)


Lesenswert?

Stefan Ernst schrieb:
> Die M103C-Fuse ist aber schon aus, oder?

Richtich. Hat das was mit dem Problem zu tun?

> Was heißt hier "irgendwann"? Dass nach jedem "sdfgd..." wieder ein
> "dgartzt..." kommt, zeigt doch, dass schon beim ersten
> Schleifendurchlauf etwas gewaltig schief läuft.

irgendwann heißt so ungefähr exakt nach der Anzahl Durchläufen, die da 
stehen: 165, 1291, 690, 1137 ...
Also recht breit gestreut. Und definitiv nicht beim ersten 
Schleifendurchlauf.

Ich weiß, es ist schon spät, aber trotzdem Danke!
Boxi

von Stefan E. (sternst)


Lesenswert?

Boxi Boxitec schrieb:
> irgendwann heißt so ungefähr exakt nach der Anzahl Durchläufen, die da
> stehen: 165, 1291, 690, 1137 ...
> Also recht breit gestreut. Und definitiv nicht beim ersten
> Schleifendurchlauf.

Ich verstehe. Das "in etwa" hier
> In einem Terminal sieht die Ausgabe in etwa so aus:
muss also sehr großzügig ausgelegt werden.

von Matthias (Gast)


Lesenswert?

Wenn irgendwas mit printf, sprintf, etc. schief geht, ist es meistens
irgendwas mit den Parametern. Entweder läuft der Stack über, oder
es passt etwas bei der Parameterübergabe nicht (was auch über den Stack 
abgewickelt wird).

Was passiert denn, wenn Du "static UI16 i = 0;" zu "static UI8 i = 0;"
änderst?

Alternativ mal statt "%d" mal "%x" probieren.

Du verwendest wohl den avr-gcc (?) Welche Version ?

von Boxi B. (boxi)


Lesenswert?

Matthias,

auch wenn ich die Schleife verändere wie du es vorschlugst:
1
while (1)
2
{
3
  static UI8 i = 0;
4
5
  sprintf(z, "sdfgd %x etgaga\r", i);
6
  uart_send_string(z);
7
  i++;
8
}

Verhält sich der Controller weiterhin komisch.

Danke
Boxi

von Boxi B. (boxi)


Lesenswert?

Stefan Ernst schrieb:
> Ich verstehe. Das "in etwa" hier
>> In einem Terminal sieht die Ausgabe in etwa so aus:
> muss also sehr großzügig ausgelegt werden.

Stefan,

ja, das "in etwa" sollte die recht unterschiedliche Anzahl von 
Schleifendurchläufen andeuten, bis feststellbar (Reset) was schief 
läuft.

Boxi

von Boxi B. (boxi)


Lesenswert?

Matthias schrieb:
> Du verwendest wohl den avr-gcc (?) Welche Version ?

Ach so ja, ich verwende avr-gcc in der Version von 20100110.

Ich habe ja vor meinem ersten Post gestern Nacht schon jede Menge 
gegoogelt. Andere Leute hatten das Problem auch schon. Leider konnte ich 
dort keine Lösung herauslesen:
http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&p=700064

Boxi

von Oliver (Gast)


Lesenswert?

Mit welcher Taktfrequenz läuft denn der Prozessor?

Oliver

von Klaus W. (mfgkw)


Lesenswert?

Und ist das wirklich das ganze Programm?

von MWS (Gast)


Lesenswert?

Boxi Boxitec schrieb:
>   UCSR1B |= (1<<TXEN0);
Ist nicht der Fehler, aber dennoch korrekturbedürftig.

Nimm doch mal das send_string aus der while raus und schau, ob's dabei 
Reboots gibt. Dann kann man eingrenzen.

von Krapao (Gast)


Lesenswert?

> dgartztkuzjuze etaear weeu tatawet rtaf
> sdfgd 165 etgaga
> dgartztkuzjuze etaear weeu tatawet rtaf

Die dritte Zeile zeigt, dass der AVR sich resettet. Kontrolliere mal die 
RESET-Ursache in dem entsprechenden Kontollregister: Watchdog? Brownout?

Die M103C Fuse wäre ein Kandidat, weil bei gesetzter Fuse der Stack 
nicht zum für Atmega128 übersetzten Programm passt und es bei der 
Rückkehr von der ersten Funktion knallt. Die UART-Funktionen zählen 
eventuell nicht als echter Funktionsaufruf, denn GCC kann die inline 
realisiert haben (je nach Optimierungslevel)

von Boxi B. (boxi)


Lesenswert?

Oliver schrieb:
> Mit welcher Taktfrequenz läuft denn der Prozessor?
>
> Oliver

BINGO, Oliver!

Das war's, ich könnte mir in den A.... beißen. Ich habe den ATmega128 
außerhalb der Spezifikationen mit 18,432MHz betrieben. Da im Datenblatt 
in der Liste der Baudrateneinstellungen auch je eine Spalte mit fOSC = 
18,432MHz und 20MHz dabei ist, habe ich total verdrängt, das der 
ATmega128 nur bis 16MHz darf.
Manchmal sieht man einfach den Wald vor lauter Bäumen nicht... Obwohl 
dieses eigenartige Verhalten ja förmlich danach geschrien hat, dass das 
Teil nicht in seinen Spezifikationen läuft.
Der ATmega32, den ich vorher verwendet habe, lief mit auch 18,432MHZ, 
obwohl er auch nur 16MHz dürfte. Ohne Probleme -> einfach nur 
zweifelhaftes Glück gehabt. Da sieht man mal wieder, was passieren kann, 
wenn man die Regeln nicht einhält.

Jetzt ist ein 16MHz-Quarz drauf, UBRR1 angepaßt und siehe da, es läuft.

Danke für all eure Gedanken. Für mich gilt: "Again what learned!" ;)
Grüße
Boxi


=======================================================================
Der Vollständigkeit halber noch ein paar Kommentare auf eure Antworten:

> Autor: Klaus Wachtler (mfgkw)
> Und ist das wirklich das ganze Programm?

Ja, das war der relevante Teil, den ich aus meinem eigentlichen Programm 
extrahiert habe, um den Fehler zu reproduzieren.


> Autor: MWS (Gast)
> Boxi Boxitec schrieb:
>>   UCSR1B |= (1<<TXEN0);
> Ist nicht der Fehler, aber dennoch korrekturbedürftig.
>
> Nimm doch mal das send_string aus der while raus und schau, ob's dabei
> Reboots gibt. Dann kann man eingrenzen.

Wie ich schon vorher geschrieben hatte, gabs die Resets auch ohne das 
uart_send_string()


> Autor: Krapao (Gast)
> Die dritte Zeile zeigt, dass der AVR sich resettet. Kontrolliere mal die
> RESET-Ursache in dem entsprechenden Kontollregister: Watchdog? Brownout?

Die Resetursache konnte ich jetzt leider nicht mehr kontrollieren, weil 
ich in meinem Überschwang das 16MHz-Quarz eingelötet habe und den Fehler 
ja jetzt nicht mehr bekomme.
Brown-Out und Watchdog würde ich jetzt mal ausschließen, weil nicht 
aktiviert.
Aber ich gehe mal davon aus, dass es sowas wie "forbidden instruction" 
(gibts das bei den AVRs?) war, weil er in einen Teil des 
Programmspeichers geschickt wurde, der wohl mit 0xFFs gefüllt war.

von Klaus W. (mfgkw)


Lesenswert?

Boxi Boxitec schrieb:
> Ja, das war der relevante Teil, den ich aus meinem eigentlichen Programm
> extrahiert habe, um den Fehler zu reproduzieren.

auch wenn es sich schon erledigt hat:
es hätte ja in dem weggelassenen Teil irgendwo eine ISR provoziert 
werden können, für die keine Routine existiert.
Das hätte auch ein ähnliches Verhalten zeigen können, daher die Frage.

von Boxi B. (boxi)


Lesenswert?

Klaus Wachtler schrieb:
> Boxi Boxitec schrieb:
>> Ja, das war der relevante Teil, den ich aus meinem eigentlichen Programm
>> extrahiert habe, um den Fehler zu reproduzieren.
>
> auch wenn es sich schon erledigt hat:
> es hätte ja in dem weggelassenen Teil irgendwo eine ISR provoziert
> werden können, für die keine Routine existiert.
> Das hätte auch ein ähnliches Verhalten zeigen können, daher die Frage.

Achso, jetzt bin ich dabei. Ja das war das komplette Programm, das für 
den Controller übersetzt wurde. ;)

von robo (Gast)


Lesenswert?

Mich wundert, dass i überhaupt hochzählt und nicht immer Null bleibt.

von MWS (Gast)


Lesenswert?

robo schrieb:
> Mich wundert, dass i überhaupt hochzählt und nicht immer Null bleibt.

Wenn die Variable mit einem Wert deklariert wird, dann wird sie nur 
einmal damit initialisiert, das ist nicht das Gleiche, wie wenn ihr 
innerhalb des Codes etwas zugewiesen wird.

von robo (Gast)


Lesenswert?

ok, verstanden
aber das ist dann aber kein guter Programmstil?

von Boxi B. (boxi)


Lesenswert?

robo schrieb:
> ok, verstanden
> aber das ist dann aber kein guter Programmstil?

PH!!! ;)

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.