Forum: Compiler & IDEs Seltsames AVR Studio / WinAVR Verhalten


von André W. (sefiroth)


Lesenswert?

Hi,

ich habe hier ein Problem zum Haare raufen und finde einfach nicht ruas 
was mit meinem AVR Studio / WinAVR los ist.

Ich habe WinAVR und AVR Studio schon neu installiert und auch die 
Updates für AVR Studio installiert.

Ich möchte ein Programm schreiben, dass einfach nur eine LED mittels PWM 
ansteuert - wobei der PWM Wert aus einem ADC-Signal berechnet wird.

Aber das Verhalten von AVr Studio ist völlig unnochvollziehbar.
Z.B.: Die LED sollte gleichmäßig leuchten, flackert aber. Der PWM-Wert 
wurde in der main vor der while(1) { ... } Schleife festgelegt - die LED 
müsste eigentlich gleichmäig leuchten, da dass Hauptprogramm das OCR1A 
Register gar nicht anfasst. Zur Fehlereingrenzung, habe ich dann mal den 
ganzen Inhalt der While(1)-Schleife (nicht die Schleife selbst!) 
auskommentiert und siehe da: LED leuchtet gleichmäßig. Ok, dann also 
schritt für schritt wieder Programmteile einkommentiert um den Fehler zu 
einzugrenzen - aaber: nachdem ich alles wieder einkommentiert hatte 
(also das exakt gleiche Programm wie beim Flackern) leuchtet die LED 
gleichmäßig.

Und zig weiterer solch verrückter Sachen. Teilweise hatte ich ne 
if-Abfrage mit drin, die bei gedrückter Taste den LED-PWM Wert z.B. mit 
100 überschrieben sollte. Solange das drin war ging überhaupt nichts 
mehr. Nachdem ich den Einzeiler wieder gelöscht hatte gings immer noch 
nicht. Dann habe ich ne andere Optimierungsstufe gewählt und plötzlich 
gings wieder. Bis zum nächsten Vorfall dieser Art (z.B. eine Variable 
nicht mehr durch 5, sondern durch 10 zu teilen). Und im Simulator läuft 
das auch ganz normal da durch und berechnet auch völlig korrekte Werte.

Bitte sagt mir, dass schon wer solch ein seltsames Verhalten beoabachten 
und beheben konnte. Ich stehe echt vor einem Rätsel... Die Übertragung 
in den Flash Speicher kanns ja eigentlich auch nicht sein - die wird ja 
danach verifiziert... Nutze da den ISP Anschluss meines STK500.

Für jede Hilfe wäre ich echt dankbar, sonst fall ich vom 
Programmierglauben ab...

von André W. (sefiroth)


Lesenswert?

Ach so, hier vielleicht mal mein Hauptprogramm:
1
// H A U P T P R O G R A M M
2
// -------------------------
3
4
int main (void)
5
{
6
  // IOs konfigurieren
7
  // -----------------
8
  // -> PWM Ausgänge:
9
  DDRB |= _BV(PB1) | _BV(PB2) | _BV(PB3);
10
  
11
  // -> SET PWM Treiber -> Ausgang
12
  DDRB |= _BV(PB0);
13
14
  // -> Taster als Eingänge (mit Pull-Up)
15
  DDRD &= ~( _BV(PD2) | _BV(PD5) );
16
  PORTD |= _BV(PD2) | _BV(PD5);
17
18
  // -> Versorgung TV-Signal-Platine  
19
  DDRD |= _BV(PD6);
20
  ENABLE_SIG_SUPPLY();    // aktivieren
21
22
23
  // ADC initialisieren
24
  init_ADC();
25
26
27
  // PWM Signale initalisieren
28
  init_PWM_1A();
29
  init_PWM_1B();
30
  init_PWM_2();
31
32
  
33
  // Lokale Variablen  
34
  // ----------------
35
  // -> Farbsignal-Buffer
36
  uint8_t red, green, blue;
37
38
39
  ENABLE_LED_DRIVER();
40
41
42
  red = green = blue = 0;
43
44
  uint16_t res_red = 0;
45
  uint16_t res_green = 0;
46
  uint16_t res_blue = 0;
47
48
  uint16_t oldr = 0;
49
  uint16_t oldg = 0;
50
  uint16_t oldb = 0;
51
52
  while(1)
53
  {
54
    // --- Rot ---
55
    
56
    res_red = oldr;  
57
    res_red += adc_convert(0,40);
58
    res_red += oldr;
59
    res_red += adc_convert(0,40);
60
    res_red += oldr;
61
    res_red += adc_convert(0,40);
62
    res_red /= 6;
63
64
    oldr = res_red;    
65
66
    if (res_red < 160) 
67
    {
68
      res_red = 0;
69
    }
70
    else if (res_red > 400)
71
    {
72
      res_red = 255;
73
    }
74
    else
75
    {
76
      res_red = (res_red - 160) * 255 / 240;
77
    }
78
    
79
    
80
    // --- Grün ---
81
      
82
    res_green = oldg;
83
    res_green += adc_convert(1,40);
84
    res_green += oldg;
85
    res_green += adc_convert(1,40);
86
    res_green += oldg;
87
    res_green += adc_convert(1,40);
88
    res_green /= 6;
89
    oldg = res_green;
90
91
    if (res_green < 200) 
92
    {
93
      res_green = 0;
94
    }
95
    else if (res_green > 400)
96
    {
97
      res_green = 255;
98
    }
99
    else
100
    {
101
      res_green = (res_green - 200) * 255 / 200;
102
    }
103
    
104
        
105
106
    // --- Blau ---
107
108
    res_blue = oldb;
109
    res_blue += adc_convert(2,50);
110
    res_blue += oldb;
111
    res_blue += adc_convert(2,50);
112
    res_blue += oldb;
113
    res_blue += adc_convert(2,50);
114
    res_blue /= 6;
115
116
    oldb = res_blue;
117
    
118
    if (res_blue < 230) 
119
    {
120
      res_blue = 0;
121
    }
122
    else if (res_blue > 410)
123
    {
124
      res_blue = 255;
125
    }
126
    else
127
    {
128
      res_blue = (res_blue - 230) * 255 / 180;
129
    }    
130
131
132
    red = pwm_adjust(red,res_red);
133
    green = pwm_adjust(green,res_green);
134
    blue = pwm_adjust(blue,res_blue);
135
136
137
    set_PWM_1A( red / 2 );
138
    set_PWM_1B( green / 2 );
139
    set_PWM_2( blue / 2 );
140
  
141
  }
142
143
}

Es liest zyklisch drei ADC Kanäle ein ("adc_convert(x,40)" bildet 
Mittelwert aus je 40 Messungen) limitiert und glättet die Werte und 
rechnet sie in 8-Bit PWM Werte um.

Das Krasse ist halt, dass es einwandfrei funktioniert und dann ändere 
ich eine Zahl im programm und plötzlich ist tote Hose...

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Welchen µC hast du und wie ist der SRAM Verbrauch?

Vielleicht geht deinem µC zur Laufzeit der Speicher aus und du 
beobachtest die Effekte eines Stackoverflow, der dir Variablen zerhaut.

avr-size ist dein erster Freund ;-)
http://www.mikrocontroller.net/articles/AVR-GCC#Tipps_.26_Tricks

von André W. (sefiroth)


Angehängte Dateien:

Lesenswert?

Es ist ein ATmega8. AVR Studio sagt mir, ich würde 2128 bytes 
verbrauchen (avr-size gibt mir die selbe Zahl aus):

Ausgabe von AVR Studio:
1
AVR Memory Usage
2
----------------
3
Device: atmega8
4
5
Program:    2128 bytes (26.0% Full)
6
(.text + .data + .bootloader)
7
8
Data:          0 bytes (0.0% Full)
9
(.data + .bss + .noinit)
10
11
12
Build succeeded with 0 Warnings...

Im Anhang nochmal die Ausgaben von avr-size und avr-nm (wobei ich mit 
avr-nm nicht viel anfangen kann ^_^)

Aber ich führe ja doch keine unendlich komplizierten Float 
Rechenoperationen durch. Wenn der Controller nicht ein paar 
Integer-Variablen aufsummieren und durch ne Ganzzahl dividieren kann, 
muss doch was im Busch sein...

Ich trau mich kaum zu fragen, aber könnte der Controller gestorben sein? 
Wäre das erste Mal, dass mir das passiert aber möglich ist alles. Aber 
sind die bei mir aufgetretenen Symptome ein sicheres Zeichen für nen 
defekten Controller?

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Ähm, ist deine adc_convert()-Funktion auch volatile deklariert?

Nicht dass der Compiler meint, drei Aufrufe mit gleichen konstanten 
Parametern können wir optimieren. (Und die Optimierung fällt weg wenn 
ein anderer Parameter ausprobiert wird...).

// Prototyp z.B.
volatile uint16_t adc_convert(uint8_t, uint8_t);

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Sorry die Deklaration hilft nicht.

Wenn
1
#include <avr/io.h>
2
#include <inttypes.h>        // Interger
3
4
uint16_t adc(uint8_t a, uint8_t b)
5
{
6
   return a+b;
7
}
8
9
int main (void)
10
{
11
  uint16_t red, oldr;
12
13
  red = 0;
14
15
  oldr = red;
16
  red  = adc(1,40); // wird real durchgeführt und Ergebnis kommt in Puffer
17
  red += oldr;
18
  red += adc(1,40); // gepuffertes Ergebnis adc(1,40) wird benutzt
19
  red += oldr;
20
  red += adc(1,40); // gepuffertes Ergebnis adc(1,40) wird benutzt
21
  red += oldr;
22
  red /= 6;
23
24
  return red;
25
}

mit Optimierung -O1 übersetzt wird, wird nur der erste adc() aufruf 
ausgeführt. Die anderen Aufrufe nutzen ein Zwischenergebnis.

Ich kann das durch ein volatile im Funktionsprototyl nicht ändern. Und 
wie man dem Compiler an der Stelle das Optimieren abgewöhnt, weiss ich 
nicht.

Wenn die Rückgabe von adc() einen volatile Wert beinhaltet oder 
innerhalb adc ein volatile Wert bearbeitet wird, erfolgt keine 
Pufferung.
1
#include <avr/io.h>
2
#include <inttypes.h>        // Interger
3
4
volatile uint8_t va;
5
6
uint16_t adc(uint8_t a, uint8_t b)
7
{
8
   va = a;
9
   return a+b;
10
}
11
12
int main (void)
13
{
14
  uint16_t red, oldr;
15
16
  red = 0;
17
18
  oldr = red;
19
  red  = adc(1,40); // wird real durchgeführt
20
  red += oldr;
21
  red += adc(1,40); // wird real durchgeführt
22
  red += oldr;
23
  red += adc(1,40); // wird real durchgeführt
24
  red += oldr;
25
  red /= 6;
26
27
  return red;
28
}

von André W. (sefiroth)


Lesenswert?

Das ist ja abgefahren, dass er die Funktion nur einmal aufruft ohne zu 
wissen was darin passiert... Aber es funktioniert ja auch bei -O0 (also 
ohne Optimierung) nicht :-(

Zudem - wenn er da immer den gleichen Wert als Funktionsrückgabe nehmen 
würde (und sei es auch 65000), dürfte sich das Programm ja dennoch nicht 
aufhängen. Egal welcher Wert z.B. in "res_red" am Ende der 
adc-Wandlungen steht, die nachfolgende Limitierung sorgt ja dafür, dass 
immer ein gültiges Ergebnis für die PWM Generierung geschickt wird.

Aber volatile Deklarationen habe ich nirgends verwendet. Dachte das wäre 
nur notwendig, wenn ich globale Variablen in Interrupts ansprechen will. 
die ADC-Funktionen liegen extern in einer adc.c und adc.h die ich mit 
ins Programm eingebunden habe.

von Kai G. (runtimeterror)


Lesenswert?

>Ich trau mich kaum zu fragen, aber könnte der Controller gestorben sein?

Ich würd's zumindest versuchen auszuschließen - einfach mal 'nen 
frischen Kandidaten auf den elektrischen Stuhl setzen. Dauert 2 Minuten 
und spart u.U. mehrere Stunden Fehlersuche im Code.

Gruß

Kai

von Karl H. (kbuchegg)


Lesenswert?

André Wippich wrote:
> Das ist ja abgefahren, dass er die Funktion nur einmal aufruft ohne zu
> wissen was darin passiert...

Der springende Punkt ist:
Der Compiler weiss was in dieser Funktion passiert.
Und die Datenflussanalyse hat ergeben, dass diese Funktion
bei gleichen Argumenten auch immer das gleiche Ergebnis liefern
wird.

Deshalb kann der Compiler diese Optimierung machen.

von André W. (sefiroth)


Lesenswert?

Kai Giebeler wrote:
> Ich würd's zumindest versuchen auszuschließen - einfach mal 'nen
> frischen Kandidaten auf den elektrischen Stuhl setzen. Dauert 2 Minuten
> und spart u.U. mehrere Stunden Fehlersuche im Code.

Leider ist es die SMD-Variante und SMD-Auslöten war noch nie so meine 
Stärke. Zumindest nicht mit dem Werkzeug hier zu Hause. Könnte höchstens 
mit nem heissen Lötkolben Pin für Pin hochhebeln, beten dass die 
Leiterbahnen auf der Paltine bleiben und dann nen Ersatz reinlöten. Und 
die Arbeit wollte ich mir eigentlich nur machen wenn es auch sinnvoll 
ist.

Karl heinz Buchegger wrote:
>Der springende Punkt ist:
>Der Compiler weiss was in dieser Funktion passiert.
>Und die Datenflussanalyse hat ergeben, dass diese Funktion
>bei gleichen Argumenten auch immer das gleiche Ergebnis liefern
>wird.
>
>Deshalb kann der Compiler diese Optimierung machen.

Naja, aber in der Funktion werdenja die ADC Register eingelesen, deren 
Inhalte sich abhängig von äußeren Einflüssen ständig ändern können. Dann 
wäre es doch sehr schwach, wenn der Compiler eine Funktion wegoptimiert, 
in der mit Registern gearbeitet wird. Bei ner Funktion, die einfach nur 
die Summe aus zwei Variablen bildet wäre das ja was ganz anderes.


Aber als Fazit glaube ich langsam echt, dass der ATmega8 einen Schaden 
hat.  Er läuft mit einem externen 16MHz Quarz, d.h. eine ISP Frequenz 
von 1.845 MHz (STK500-Einstellung) sollte kein Problem sein. Das 
Programmieren des Flash funktioniert, aber beim Verifizieren hängt sich 
der Programmer auf, bzw. meldet dass ein Fehler beim Ausführen des 
Kommandos aufgetreten ist. Das macht mich schonmal sehr stutzig. Hatte 
es vorher nicht bemerkt, weil ich immer mit 57,6kHz habe Programmieren 
lassen und dabei alle Programmierschritte einwandfrei durchlaufen 
wurden.

Außerdem: Ich habe eine (ohne Optimierung) laufende Programmversion 
aufgebläht, indem ich einfach ein paar Funktionen mit eingefügt habe, 
die das Programm aber nicht verwendet. War dann bei 5366 Bytes (65,5% 
voll) Speicherbelegung und ohne dass sich am Programmablauf etwas 
geändert hat, funktionierte nichts mehr...

Vielleicht löte ich den ATmega8 morgen wirklich mal aus. Das wird ein 
Spaß :-(

von Simon K. (simon) Benutzerseite


Lesenswert?

André Wippich wrote:
> Aber als Fazit glaube ich langsam echt, dass der ATmega8 einen Schaden
> hat.  Er läuft mit einem externen 16MHz Quarz, d.h. eine ISP Frequenz
> von 1.845 MHz (STK500-Einstellung) sollte kein Problem sein.

Kann auch an zu langen ISP Kabeln liegen...

von André W. (sefiroth)


Lesenswert?

Simon K. wrote:
> Kann auch an zu langen ISP Kabeln liegen...

Das Kabel ist 6cm lang, das sollte kurz genug sein ;-)

von Philipp B. (philipp_burch)


Lesenswert?

Ausserhalb des Safe-Operating-Area (16MHz erst ab 4.xV)?

von André W. (sefiroth)


Lesenswert?

Leider auch nicht. Das ganze läuft mit 5V.

Es ist echt der erste Atmel der solch unerklärliches Verhalten zeigt und 
ich habe schon mit zig ATmega8, AT90CAN128 und einigen anderen Typen von 
Atmel gearbeitet. Und dann natürlich auch schon mit den kleinen 
Standardproblemen zu tun gehabt. Meist kann man den Fehler ja schnell 
eingrenzen und dann auch beheben:

- Spannungsversorgung geht in die Strombegrenzung
--> Kurzschluss auf der Platine

- ISP-Programmer bekommt keine Verbindung
--> ISP-Frequenz zu hoch
--> Reset-,SCK-, MISO- oder MOSI-Leitung ist unterbrochen (z.B. kalte 
Lötstelle)
--> Fuse-Bit Fehler (z.B. falsche Taktquelle eingestellt)

- Seltsames Programmverhalten
--> Mist programmiert (auskommentieren bis die Fehlerpassage entdeckt 
wurde)

Aber nichts davon lässt sich auf mein Problem anwenden :-(

von André W. (sefiroth)


Lesenswert?

Ich schätze der ATmega8 ist wirklich hinüber... Ich habe mal meine 
Bastelkiste durchwühlt und noch einen 16 MHz Quarz und einen DIL28 
ATmega8 gefunden. Damit konnte ich mein Programm direkt auf dem STK500 
ausprobieren und dort liefen einwandfrei auch die Versionen, die bei der 
der SMD ATmega8 in meiner Schaltung den Dienst versagt.

D.h. also Lötkolben raus und ab dafür... Weiß noch nicht wann ich das 
mache - bin grad ziemlich verschnupft und da ist fummeliges SMD-Entlöten 
nicht grad der beste Freizeitvertreib. Aber ich werde die Ergebnisse 
hier posten.

Ach ja, als kleine Zusatzinfo: Das "Verify FLASH" von AVRStudio 
funktionierte auch beim eingesteckten ATmega8 nicht bei Frequenzen über 
115kHz - die Programmierung ("Program FLASH") schon. Das kann also nicht 
dem (wahrscheinlich) defekten ATmega8 zugeschoben werden. Vielleicht ein 
Bug von AVR Studio (nutze AVR Studio 4.13.571 Service Pack 2)...

von Kai G. (runtimeterror)


Lesenswert?

Frohes Neues, viel Glück, viel Spaß und gute Besserung ;)

von André W. (sefiroth)


Lesenswert?

Danke :-)

Ich habe mich gestern drangesetzt, den alten ATmega8 ausgelötet und 
einen neuen eingelötet (was für eine Fummelarbeit stöhn). Jetzt 
funktioniert alles, wie es soll. Liegt zwar noch ein gutes Stück 
Programmierarbeit vor mir, aber solange der AVR das macht, was ich 
programmiert habe, sehe ich da keine Schwierigkeiten
1
FAZIT: DER ATMEGA8 WAR KAPUTT !!!

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.