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...
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...
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
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?
Ä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);
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 | }
|
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.
>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
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.
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ß :-(
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...
Simon K. wrote:
> Kann auch an zu langen ISP Kabeln liegen...
Das Kabel ist 6cm lang, das sollte kurz genug sein ;-)
Ausserhalb des Safe-Operating-Area (16MHz erst ab 4.xV)?
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 :-(
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)...
Frohes Neues, viel Glück, viel Spaß und gute Besserung ;)
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.