mikrocontroller.net

Forum: Compiler & IDEs Seltsames AVR Studio / WinAVR Verhalten


Autor: André Wippich (sefiroth)
Datum:

Bewertung
0 lesenswert
nicht 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...

Autor: André Wippich (sefiroth)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ach so, hier vielleicht mal mein Hauptprogramm:
// H A U P T P R O G R A M M
// -------------------------

int main (void)
{
  // IOs konfigurieren
  // -----------------
  // -> PWM Ausgänge:
  DDRB |= _BV(PB1) | _BV(PB2) | _BV(PB3);
  
  // -> SET PWM Treiber -> Ausgang
  DDRB |= _BV(PB0);

  // -> Taster als Eingänge (mit Pull-Up)
  DDRD &= ~( _BV(PD2) | _BV(PD5) );
  PORTD |= _BV(PD2) | _BV(PD5);

  // -> Versorgung TV-Signal-Platine  
  DDRD |= _BV(PD6);
  ENABLE_SIG_SUPPLY();    // aktivieren


  // ADC initialisieren
  init_ADC();


  // PWM Signale initalisieren
  init_PWM_1A();
  init_PWM_1B();
  init_PWM_2();

  
  // Lokale Variablen  
  // ----------------
  // -> Farbsignal-Buffer
  uint8_t red, green, blue;


  ENABLE_LED_DRIVER();


  red = green = blue = 0;

  uint16_t res_red = 0;
  uint16_t res_green = 0;
  uint16_t res_blue = 0;

  uint16_t oldr = 0;
  uint16_t oldg = 0;
  uint16_t oldb = 0;

  while(1)
  {
    // --- Rot ---
    
    res_red = oldr;  
    res_red += adc_convert(0,40);
    res_red += oldr;
    res_red += adc_convert(0,40);
    res_red += oldr;
    res_red += adc_convert(0,40);
    res_red /= 6;

    oldr = res_red;    

    if (res_red < 160) 
    {
      res_red = 0;
    }
    else if (res_red > 400)
    {
      res_red = 255;
    }
    else
    {
      res_red = (res_red - 160) * 255 / 240;
    }
    
    
    // --- Grün ---
      
    res_green = oldg;
    res_green += adc_convert(1,40);
    res_green += oldg;
    res_green += adc_convert(1,40);
    res_green += oldg;
    res_green += adc_convert(1,40);
    res_green /= 6;
    oldg = res_green;

    if (res_green < 200) 
    {
      res_green = 0;
    }
    else if (res_green > 400)
    {
      res_green = 255;
    }
    else
    {
      res_green = (res_green - 200) * 255 / 200;
    }
    
        

    // --- Blau ---

    res_blue = oldb;
    res_blue += adc_convert(2,50);
    res_blue += oldb;
    res_blue += adc_convert(2,50);
    res_blue += oldb;
    res_blue += adc_convert(2,50);
    res_blue /= 6;

    oldb = res_blue;
    
    if (res_blue < 230) 
    {
      res_blue = 0;
    }
    else if (res_blue > 410)
    {
      res_blue = 255;
    }
    else
    {
      res_blue = (res_blue - 230) * 255 / 180;
    }    


    red = pwm_adjust(red,res_red);
    green = pwm_adjust(green,res_green);
    blue = pwm_adjust(blue,res_blue);


    set_PWM_1A( red / 2 );
    set_PWM_1B( green / 2 );
    set_PWM_2( blue / 2 );
  
  }

}

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...

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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#Ti...

Autor: André Wippich (sefiroth)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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:
AVR Memory Usage
----------------
Device: atmega8

Program:    2128 bytes (26.0% Full)
(.text + .data + .bootloader)

Data:          0 bytes (0.0% Full)
(.data + .bss + .noinit)


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?

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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);

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sorry die Deklaration hilft nicht.

Wenn
#include <avr/io.h>
#include <inttypes.h>        // Interger

uint16_t adc(uint8_t a, uint8_t b)
{
   return a+b;
}

int main (void)
{
  uint16_t red, oldr;

  red = 0;

  oldr = red;
  red  = adc(1,40); // wird real durchgeführt und Ergebnis kommt in Puffer
  red += oldr;
  red += adc(1,40); // gepuffertes Ergebnis adc(1,40) wird benutzt
  red += oldr;
  red += adc(1,40); // gepuffertes Ergebnis adc(1,40) wird benutzt
  red += oldr;
  red /= 6;

  return red;
}

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.

#include <avr/io.h>
#include <inttypes.h>        // Interger

volatile uint8_t va;

uint16_t adc(uint8_t a, uint8_t b)
{
   va = a;
   return a+b;
}

int main (void)
{
  uint16_t red, oldr;

  red = 0;

  oldr = red;
  red  = adc(1,40); // wird real durchgeführt
  red += oldr;
  red += adc(1,40); // wird real durchgeführt
  red += oldr;
  red += adc(1,40); // wird real durchgeführt
  red += oldr;
  red /= 6;

  return red;
}

Autor: André Wippich (sefiroth)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Kai G. (runtimeterror)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: André Wippich (sefiroth)
Datum:

Bewertung
0 lesenswert
nicht 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ß :-(

Autor: Simon K. (simon) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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...

Autor: André Wippich (sefiroth)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Simon K. wrote:
> Kann auch an zu langen ISP Kabeln liegen...

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

Autor: Philipp Burch (philipp_burch)
Datum:

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

Autor: André Wippich (sefiroth)
Datum:

Bewertung
0 lesenswert
nicht 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 :-(

Autor: André Wippich (sefiroth)
Datum:

Bewertung
0 lesenswert
nicht 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)...

Autor: Kai G. (runtimeterror)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Frohes Neues, viel Glück, viel Spaß und gute Besserung ;)

Autor: André Wippich (sefiroth)
Datum:

Bewertung
0 lesenswert
nicht 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
FAZIT: DER ATMEGA8 WAR KAPUTT !!!

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.