Hi,
ich habe in meinem Labor nun einen neuen PC für meine
Programmierarbeiten. Im Zuge der Installation habe ich mir die neueste
WinAVR-Version vom 5.12.2008 gezogen.
Allerdings habe ich so meine Probleme damit, einen Lauffähigen Code zu
erzeugen. Ohne jetzt ins Detail gehen zu wollen:
Nutzt jemand schon die neue Version und ist damit zufrieden ? Sind
bereits Bugs bekannt ?
Gruß
Andreas
Also bei mir funktioniert die Version einwandfrei. Hab bisher noch keine
Bugs gefunden.
Wenn du uns nicht verrätst, ob es ne Fehlermeldung gibt und welche, dann
kann dir auch nicht geholfen werden.
MfG
Marius
Hi,
bin voller Vezweiflung nun auf die Version WinAVR-20080610
zurückgegangen und siehe da: ES FUNKTIONIERT.
Mit der neuen Version (Dezember 2008) kann ich mein Programm zwar
compilieren (alles "Standard" mit MAKE-File aus meinem Programm-VZ vom
September 2007) und dann mittels Ponyprog auf den Controller beamen aber
es läuft nicht :-( Auf dem LCD erscheinen nur wirre Zeichen - das
Prgramm reagiert überhaupt nicht.
Wenn ich exakt das selbe mit der Oktober-Version von WinAVR mache mit
exakt dem selben MAKE-File läuft alles genauso ab nur dass das LCD das
zeigt was es zeigen soll und mein Programm von Controller ausgeführt
wird.
Was nun ?
Zunächst kann ich mit der Oktober-Version gut leben - nur wie sucht man
einen solchen Fehler ???
Gruß
Andreas
UBoot-Stocki wrote:
> Auf dem LCD erscheinen nur wirre Zeichen - das> Prgramm reagiert überhaupt nicht.
Das deutet auf ein Timingproblem oder sonst einen gemeinen Fehler in der
Software hin (Stacküberlauf, ein fehlendes volatile oder ähnliches). Es
war quasi Zufall dass die Software lief.
Ich sollte vielleicht noch bemerken, dass das Programm seit September
2007 bei mir "produktiv" im einsatz ist. Ich möchte nun einige
Funktionen überarbeiten, da die Benutzung und Menüführung etwas
"unpraktisch" ist.
Diese Programm ist/war übrigens auch die Grundlage für meine
Rolladensteuerung (Beitrag "Komfortable Rolladensteuerung V1.0")
Gruß
Andreas
Wie vermutet: Die LCD Init ist schonmal ziemlich falsch, du verletzt da
sehr viele Timings.
1
PORTD=0x03;// muss 3mal hintereinander gesendet werden zur Initialisierung
2
lcd_enable();
3
PORTD=0x03;
4
lcd_enable();
5
PORTD=0x03;
6
lcd_enable();
7
PORTD=0x02;// 4bit-Modus einstellen
8
lcd_enable();
9
lcd_busy_wait();
10
lcd_send(0x28,1);// 4Bit / 2 Zeilen / 5x8
Schau mal die Init im Datenblatt an, da werden in diesem Codeteil einige
Pausen gefordert.
in void lcd_busy_wait(void)
ist dieser Teil auch nicht ganz nach Datenblatt:
1
uint8_ti=1;
2
3
DDRD=0xF0;
4
PORTD&=~(1<<PD4);// PD4 = RS-Leitung 0
5
PORTD|=(1<<PD6);// PD6 = R/W-Leitung 1
6
PORTD|=(1<<PD5);// enable 1
7
while(i!=0){
8
i=PIND<<4;// liest die ersten 4 BIT ein
9
i=(PIND&(1<<PIND3));// Fragt PD3 auf 1 ab
10
}
11
PORTD&=~(1<<PD5);// enable 0
12
PORTD&=~(1<<PD6);//R/W-Leitung 0
13
DDRD=0xFF;D3));// Fragt PD3 auf 1 ab
Diese Zeile ist sinnlos, da in der nächsten Zeile i überschrieben wird:
i=PIND << 4; // liest die ersten 4 BIT ein
Weiterhin führst du beim Busy Lesen immer noch einen Transfer aus,
obwohl das Datenblatt immer 2 Transfers fordert, damit ein volles Byte
übertragen wird.
Mich wundert es, dass dieser Code bisher lief...
PS: Die busy Abfrage packt man sinnvollerweise vor die Senderoutine,
denn dann kann der µC während das Display beschäftigt ist andere Dinge
erledigen, und wenn das lange genug dauert, dann ist gar keine Wartezeit
erforderlich.
Hi,
zur Initialisierung kann ich jetzt auf die schnelle nichts sagen - muss
ich mir ansehen.
Bei der Routine lcd_busy_wait(void) bin ich ziemlich sicher, dass das so
stimmt. Allein schon aus dem Grund, dass es NUR so funktioniert. Der
Inhalt von "i" in
1
i=PIND<<4;// liest die ersten 4 BIT ein
spielt keine Rolle, da es nur um das Lesen an sich geht. Hier findet
auch das von Dir erwähnte 1. Lesen statt. Die wichtige Zeile ist
1
i=(PIND&(1<<PIND3));// Fragt PD3 auf 1 ab
da hier in der zweiten Operation das BIT gelesen wir. Beachte bitte es
handelt sich hier um den 4-BIT-Modus.
Egal ob nun die Timings stimmen oder nicht - Warum wird der Code
übersetzt mit gcc 5.12.2008 falsch ausgeführt (selbst wenn das LCD nicht
funktioniert müssten doch die Tasten und die damit verbundenen
Funktionen für die Hintergrundbeleuchtung laufen) und mit gcc 6.10.2008
funzt es einwandfrei ???
Das kann nicht an falschen LCD-Timings liegen ?
Wer hat da eine Idee ?
Gruß
Andreas
UBoot-Stocki wrote:
> Allein schon aus dem Grund, dass es NUR so funktioniert.
Das kann an den restlichen Fehlern liegen.
> Der> Inhalt von "i" in>
1
>i=PIND<<4;// liest die ersten 4 BIT ein
2
>
> spielt keine Rolle, da es nur um das Lesen an sich geht.
Das Lesen ist schlicht und einfach sinnlos, da das LCD davon nichts
mitbekommt. Der einzige Nutzen davon ist eine Pause. 1-2 nops erfüllen
den selben Zweck.
> Hier findet auch das von Dir erwähnte 1. Lesen statt.
Nein. Denn dazu müsstest du enable takten, was du aber nicht machst.
> Die wichtige Zeile ist>
1
>i=(PIND&(1<<PIND3));// Fragt PD3 auf 1 ab
2
>
> da hier in der zweiten Operation das BIT gelesen wir. Beachte bitte es> handelt sich hier um den 4-BIT-Modus.
Ja, sag ich doch. Aber um dein Argument, dass es sich um den 2. Transfer
handelt, weiter zu entkräften: Das Busy Bit liegt im oberen Nibble, und
das wird zuerst übertragen.
> Das kann nicht an falschen LCD-Timings liegen ?
Doch. Wenn er z.B. bei der komplett falschen Busy Abfrage hängen bleibt,
dann schon.
Schau dir mal den angehängten Ausschnitt aus dem Datenblatt an, der
sieht "leicht" anders aus als das was dein Code macht.
Wenn ich es recht sehe, funktioniert keine der beiden Versionen wie sie
soll, denn keine passt in den Flash.
Dazu ein Blick ins mapfile wagen (.text+.data ist größer als 8kB)
Bei 0610 waren's nur 8 Byte zu viel, also wurden nicht so viele Daten
falsch initialisiert wie in 1205.
20080610
Der Tipp mit der Optimierungsstufe ist gut. Ich würde es jedoch mit eher
mit "-O0" versuchen.
Folgender Code z.B. läuft nur korrekt mit "-O0" bei jeder anderen
Optimierungsstufe werden die Schleifen wegoptimiert. Logisch, die tun ja
auch nichts ausser den Programmablauf verzögern aber manchmal ist es
jedoch notwendig.
int main() //* Blinker *********
{
int n;
DDRB = 0x08;
while(1)
{
PORTB = (0x001 << PB3);
for (n = 1; n < 3000; n++);
PORTB = 0;
for (n = 1; n < 3000; n++);
}
return 0;
}
Börnie wrote:
> Der Tipp mit der Optimierungsstufe ist gut. Ich würde es jedoch mit eher> mit "-O0" versuchen.
Wenn das Programm mit -O2 bereits nicht in den den µC passt, dann schon
garnicht mit -O0.
Falls es denn -O2 sei soll -- was jedoch m.E. eh nicht empfehlenswert
ist, für AVR abgezeigt ist -Os --, dann sollte man die für avr-gcc 4.x
geboteten Optionen wie -fno-inline-small-functions etc. setzten. Damit
passt's auch rein.
Mit -O0 lässt sich noch nichtmal ein hex-File erzeugen: ld-Fehler weil
.text überläuft.
>Der Tipp mit der Optimierungsstufe ist gut.
Ist er.
>Ich würde es jedoch mit eher mit "-O0" versuchen.
Nur, wenn man unbedingt selbstgezimmerte Verzögerungsschleifen mit
undefinierter Dauer braucht. Wobei, auch die gehen "optimierungssicher"
mit
1
for(volatileintn=0;n<30000;n++);
Für Verzögerungen mit Rechenzeitvernichtung gibt es in der avrlib
entsprechende Funktionen, die nicht "wegoptimiert" werden. Ernsthafte
Programme, die nicht nur eine LED blinken lassen, passen ohne
Größenoptimierung kaum in einen normalen AVR, und bei denen löst man das
Blinken nebenher mit einem Timerinterrupt.
Oliver
Ich habe mir in den letzten Stunden die Unterlagen zu meinem alten
Projekt angesehen. Die Initialisierungs-Routine stammt 1:1 aus dem
Tutorial hier aus dem Forum. Zum Glück habe ich noch einen alten
Ausdruck vom 29.5.2007 gefunden. Heute ist der Code im Tutorial anders!
Ich halte Euch auf dem Laufenden wie es weiter geht ...
Gruß
Andreas
UBoot-Stocki wrote:
> Ich halte Euch auf dem Laufenden wie es weiter geht ...
Die Lösung warum dein Zeug abschmiert steht oben. Lesen musst du aber
schon selber ;-)
|| { echo empty LCD1_eeprom.srec not generated; exit 0; }
16
c:\Programme\WinAVR-20080610\bin\avr-objcopy.exe: --change-section-lma .eeprom=0x00000000 never used
17
18
> Process Exit Code: 0
19
> Time Taken: 00:01
Es ist tatsächlich so, dass die Oktober-Version einen größeren Code
generiert als die in 2007 verwendete (keine Ahnung mehr welche das war
...)
Morgen teste ich die aktuelle ...
Gruß und Danke für die Tipps
Andreas
Hi,
"Warum nicht _delay_ms(25)?"
Wäre doch zu einfach ;-)
Im Ernst: Ich habe das "auf die Schnelle" gemacht. Werde da noch
Anpassungen machen ...
Gruß
Andreas
UBoot-Stocki wrote:
> habe jetzt folgende Initialisierungsroutine:
Sieht gut aus, sollte funktionieren. Zumindest stimmt jetzt alles mit
dem Datenblatt überein. Dieser Code sollte zuverlässig mit allen 44780
kompatiblem LCDs funktionieren.
Hi,
alles klar - Problem gelöst.
Nochmals vielen Dank inbesondere an benedikt und gjlayde aber natürlich
auch an alle Anderen.
Die neue Version läuft, mein Code läuft und es passt alles in den
Controller!
Eine Frage bleibt: Wie sind denn die "Empfohlenen" Optimierungsoptionen
für ein AVR-Projekt in Bezog auf die Codegröße ???
Gruß
andreas
UBoot-Stocki wrote:
> Eine Frage bleibt: Wie sind denn die "Empfohlenen" Optimierungsoptionen> für ein AVR-Projekt in Bezog auf die Codegröße ???
-Os erzeugt fast immer den kleinsten Code, teilweise optimiert er aber
Sachen zu stark (z.B. /16 wird über eine Division gerechnet und nicht
über eine Schiebeoperation. Ein Funktionsaufruf ist Platzmäßig eben
besser als eine Schiebeoperation, wenn die Divisionsroutine sowieso
schon eingebunden ist.) Wenn ausreichen Platz zur Verfügung steht ist
-O2 daher meine Standardwahl.
UBoot-Stocki schrob:
> Eine Frage bleibt: Wie sind denn die "Empfohlenen" Optimierungsoptionen> für ein AVR-Projekt in Bezog auf die Codegröße ???
Auf jeden Fall
1
-Os
Die Laufzeit wird damit nur unmerklich schlechter als mit -O2, während
die Codegröße deutlich abnimmt. Bei -O2 werten teilweise Basic Blocks
kopiert, um Sprünge zu sparen, was aber mächtig Code kostet. Von -O3 ist
generell abzuraten. -O1 wenn man optimieren möchte/muss, aber noch
einigermassen gut debuggen können möchte.
Wertere Optionen die du antesten kannst sind
1
-fno-inline-small-functions
2
-fno-split-wide-types
3
-fno-tree-scev-cprop
Und last not least besteht die Möglichkeit ältere Versionen von avr-gcc
zu versuchen. Ich verwende standardmässig den 3.4.6, der macht in meinen
Projekten rund 10% kleineren Code. Bei deinem Projekt ist die Codegröße
so wie bei 4.3.2, was darauf hindeutet, daß du weitere 10% an Code
sparen kannst, wenn du etwas geschickter codierst.
Benedikt K. schrob:
> -Os erzeugt fast immer den kleinsten Code, teilweise optimiert er aber> Sachen zu stark (z.B. /16 wird über eine Division gerechnet und nicht> über eine Schiebeoperation. Ein Funktionsaufruf ist Platzmäßig eben> besser als eine Schiebeoperation, wenn die Divisionsroutine sowieso> schon eingebunden ist.) Wenn ausreichen Platz zur Verfügung steht ist> -O2 daher meine Standardwahl.
Das dürfte ein bekanntes Problem sein, siehe
http://gcc.gnu.org/ml/gcc/2008-12/msg00329.htmlhttp://gcc.gnu.org/ml/gcc-help/2008-12/msg00232.html
sowie die Antworten darauf.
Hallo,
Dem Thema entsprechend hänge ich mich hier gleich an.
Mit der neuen GCC-Version funktionieren die Stringfunktionen nicht mehr.
Z.B.
uint16_t uword = 12345;
char foo_string[10];
sprintf(foo_string, "%05u", uword);
ausgabe(foo_string);
Die sprintf führt zum Neustart (Reset) des ATmega128.
char foo_string[10];
strcpy(foo_string, "12345");
ausgabe(foo_string);
Nach der strcpy beinhaltet der string sechs byte mit jeweils 0xFF.
Bitte antwortet nur wenn ihr die Funktionen auch tatsächlich in einem
ATmega128 laufen lassen könnt und nicht nur in einem Simulator. Die
angeführten Beispiele laufen z.B. mit WinAVR 20080610 und allen anderen
Vorgängerversionen einwandfrei. Es liegt also nicht am Kode sondern an
der Übersetzung. In wie weit andere Stringfunktionen ebenfalls betroffen
sind kann ich derzeit nicht sagen weil ich wegen Zeitdrucks jetzt mit
der 20080610 Version weiterarbeite und keine Zeit für Experimente habe.
Hier noch der Makeoutput um Fragen bezüglich Meldungen und Einstellungen
gleich vorweg zu beantworten:
-------- begin --------
avr-gcc (WinAVR 20081205) 4.3.2
Copyright (C) 2008 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is
NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.
Size before:
AVR Memory Usage
----------------
Device: atmega128
Program: 9616 bytes (7.3% Full)
(.text + .data + .bootloader)
Data: 993 bytes (24.2% Full)
(.data + .bss + .noinit)
EEPROM: 1 bytes (0.0% Full)
(.eeprom)
Compiling C: E2000_Flughaven.c
avr-gcc -c -mmcu=atmega128 -I. -gdwarf-2 -DF_CPU=7372800UL -O0
-funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall
-Wstrict-prototypes -Wa,-adhlns=./E2000_Flughaven.lst -std=gnu99
-Wundef -MMD -MP -MF .dep/E2000_Flughaven.o.d E2000_Flughaven.c -o
E2000_Flughaven.o
Linking: E2000_Flughaven.elf
avr-gcc -mmcu=atmega128 -I. -gdwarf-2 -DF_CPU=7372800UL -O0
-funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall
-Wstrict-prototypes -Wa,-adhlns=E2000_Flughaven.o -std=gnu99 -Wundef
-MMD -MP -MF .dep/E2000_Flughaven.elf.d E2000_Flughaven.o --output
E2000_Flughaven.elf -Wl,-Map=E2000_Flughaven.map,--cref
-Wl,-u,vfprintf -lprintf_flt -lm
Creating load file for Flash: E2000_Flughaven.hex
avr-objcopy -O ihex -R .eeprom -R .fuse -R .lock E2000_Flughaven.elf
E2000_Flughaven.hex
Creating load file for EEPROM: E2000_Flughaven.eep
avr-objcopy -j .eeprom --set-section-flags=.eeprom="alloc,load" \
--change-section-lma .eeprom=0 --no-change-warnings -O ihex
E2000_Flughaven.elf E2000_Flughaven.eep || exit 0
Creating Extended Listing: E2000_Flughaven.lss
avr-objdump -h -S -z E2000_Flughaven.elf > E2000_Flughaven.lss
Creating Symbol Table: E2000_Flughaven.sym
avr-nm -n E2000_Flughaven.elf > E2000_Flughaven.sym
Size after:
AVR Memory Usage
----------------
Device: atmega128
Program: 9666 bytes (7.4% Full)
(.text + .data + .bootloader)
Data: 999 bytes (24.4% Full)
(.data + .bss + .noinit)
EEPROM: 1 bytes (0.0% Full)
(.eeprom)
srec_cat E2000_Flughaven.hex -Intel -Output E2000_Flughaven.srec
-Motorola -Line_Length 142
-------- end --------
Sorry, ich habe bereits deinstalliert und arbeite wieder mit der
20080610. Das Problem läuft aber nicht davon und nach dem 12.1. nehme
ich mir etwas Zeit und installiere 20081205 erneut.
Du kannst mehrere AVR-Toolchains parallel installieren.
Einfach die Pfadvariable anpassen oder die Tools mal mit absoluten
Pfaden aufrufen wenn man ne andere Version antesten will.
Nein in diesem Projekt wird kein EEProm verwendet. Den EEProm-Bug gabs
auch nur in der Zeit zwischen nach 2006xxxx und 20080610. War ja auch
ich der den schmerzlich bemerkt hat. Der wurde aber dann auch durch
Austausch der Headerdatei umschifft. Ob das nun wieder ein Thema wird
werde ich erst später mir mal ansehen. Heute habe ich nur festgestellt
dass die beiden Stringfunktionen nicht mehr funktionieren.
Hi,
bitte entschuldigt, dass ich den Thread nochmal rauskrame. Ich nutze
ebenfalls die Version "WinAVR 20081205".
Beim Compilieren kommen keine Fehler jedoch zeigt das Programm seltsam
Erscheinungen. Ein Blick in das list-file brachte die "Erleuchtung". Bei
Verwendung einer Optimierungsstufe (-O1..-Os) wird ein "doppelter" ASM
Code erzeugt. Im Simulator funktioniert der Code wie gewollt, nur real
eben nicht.
Hier das Code-Fragment in C:
1
uint8_tmain(void){
2
3
uart0_init();
4
port_init();
5
timer0_init();
6
timer1_init();
7
sei();
8
PORTD=(1<<PD5);
9
10
while(1){// Endlosschleife
11
12
// neue PWM Daten
13
14
if(uart0_rx_is_buffer_empty()==NO){
15
16
uint8_tPWM_value;
17
PORTD^=(1<<PD6);// LED rot toggle
18
PWM_value=uart0_rx_getchar();
19
uart0_tx_putchar(PWM_value);
20
21
if((PWM_value>=0)&&(PWM_value<=100)){
22
OCR1A=PWM_value*0xFF/100;
23
}
24
}
25
26
27
}
28
29
// wird nie erreicht
30
return0;
31
}
Und hier das Resultat im list-file:
Ab Adresse ca beginnt der Inhalt der Endloschleife. Dieser Code ist auch
schon falsch da keinerlei togglen der LED an dieser Stelle erfolgt
(PORTD 0x12 wird nicht zum XOR verknüpfen ausgelesen). Ab e0 wird ein
"doppelter" Code wiederholt. Diesmal beginnt er jedoch korrekt mit dem
LED Toggle.
1
uint8_t main (void) {
2
b2: df 92 push r13
3
b4: ef 92 push r14
4
b6: ff 92 push r15
5
b8: 0f 93 push r16
6
ba: 1f 93 push r17
7
bc: cf 93 push r28
8
be: df 93 push r29
9
10
uart0_init();
11
c0: 26 d0 rcall .+76 ; 0x10e <uart0_init>
12
port_init();
13
c2: cd df rcall .-102 ; 0x5e <port_init>
14
timer0_init();
15
timer1_init();
16
c4: e8 df rcall .-48 ; 0x96 <timer1_init>
17
sei();
18
c6: 78 94 sei
19
PORTD = (1<<PD5);
20
c8: 80 e2 ldi r24, 0x20 ; 32
21
ca: 82 bb out 0x12, r24 ; 18
22
// neue PWM Daten
23
24
if (uart0_rx_is_buffer_empty() == NO){
25
26
uint8_t PWM_value;
27
PORTD ^= (1<<PD6); // LED rot toggle
28
cc: c2 e3 ldi r28, 0x32 ; 50
29
ce: d0 e0 ldi r29, 0x00 ; 0
30
d0: 00 e4 ldi r16, 0x40 ; 64
31
PWM_value = uart0_rx_getchar();
32
uart0_tx_putchar(PWM_value);
33
34
if ( (PWM_value >= 0) && (PWM_value <= 100) ){
35
OCR1A = PWM_value*0xFF/100;
36
d2: dd 24 eor r13, r13
37
d4: da 94 dec r13
38
d6: 0f 2e mov r0, r31
39
d8: fa e4 ldi r31, 0x4A ; 74
40
da: ef 2e mov r14, r31
41
dc: ff 24 eor r15, r15
42
de: f0 2d mov r31, r0
43
44
while(1){ // Endlosschleife
45
46
// neue PWM Daten
47
48
if (uart0_rx_is_buffer_empty() == NO){
49
e0: 4e d0 rcall .+156 ; 0x17e <uart0_rx_is_buffer_empty>
50
e2: 88 23 and r24, r24
51
e4: e9 f7 brne .-6 ; 0xe0 <main+0x2e>
52
53
uint8_t PWM_value;
54
PORTD ^= (1<<PD6); // LED rot toggle
55
e6: 88 81 ld r24, Y
56
e8: 80 27 eor r24, r16
57
ea: 88 83 st Y, r24
58
PWM_value = uart0_rx_getchar();
59
ec: 52 d0 rcall .+164 ; 0x192 <uart0_rx_getchar>
60
ee: 18 2f mov r17, r24
61
uart0_tx_putchar(PWM_value);
62
f0: 71 d0 rcall .+226 ; 0x1d4 <uart0_tx_putchar>
63
64
if ( (PWM_value >= 0) && (PWM_value <= 100) ){
65
f2: 15 36 cpi r17, 0x65 ; 101
66
f4: a8 f7 brcc .-22 ; 0xe0 <main+0x2e>
67
OCR1A = PWM_value*0xFF/100;
68
f6: 1d 9d mul r17, r13
69
f8: c0 01 movw r24, r0
70
fa: 11 24 eor r1, r1
71
fc: 64 e6 ldi r22, 0x64 ; 100
72
fe: 70 e0 ldi r23, 0x00 ; 0
73
100: bd d0 rcall .+378 ; 0x27c <__divmodhi4>
74
102: 86 2f mov r24, r22
75
104: 97 2f mov r25, r23
76
106: f7 01 movw r30, r14
77
108: 91 83 std Z+1, r25 ; 0x01
78
10a: 80 83 st Z, r24
79
10c: e9 cf rjmp .-46 ; 0xe0 <main+0x2e>
Ich werde in den nächsten Tagen mal eine Vorgängerversion testen. Bis
dahin seht dies einfach als Information. Leider fehlt mir im Moment die
Zeit sämtliche Bugreports etc. für diese WinAVR Version zu durchforsten
deswegen kann ich nicht sagen ob dieser Fehler bereits bekannt ist.
MfG
Robert
Du lässt dich zu sehr von den eingestreuten Zitaten über die
C-Statements kirre machen. Statt dessen hättest du mal versuchen sollen,
den erzeugten Code zu untersuchen.
Jenseits von -O0 ist ist durchaus üblich, dass der Compiler den Code
eines Statements in mehrere Codeblöcke zerschnippelt und sie auf sehr
unterschiedliche Stelle verteilt. Diese aber jeweils mit dem gleichen
C-Statement garniert, so dass die gleiche Zeile vom Quellcode mehrfach
auftaucht.
Nach Bugreports zu suchen ist müssig, denn der erzeugte Code ist
korrekt.
> Ab Adresse ca beginnt der Inhalt der Endloschleife.
Nein, die beginnt bei 0xE0. Das Zeug davor intialisiert nur ein paar
Register, die u.U. in den im Kommentar angegebenen Statements verwendet
werden (oder auch garnicht).
> Dieser Code ist auch> schon falsch da keinerlei togglen der LED an dieser Stelle erfolgt
Im Code auch nicht.
> Ab e0 wird ein "doppelter" Code wiederholt.
Nein. Es werden nur ein paar Quellcodezeilen wiederholt. Der Code dazu
ist verschieden.
Apropos: Wenn der gleiche Code im Simulator funktioniert, auf realer
Hardware jedoch nicht, dann kann man das als deutlichen Hinweis auf
Zeitprobleme verstehen. Dem Compiler ist es doch völlig schnuppe ob die
Hardware echt ist oder simulert.
Beispiel:
Die Zeile
PORTD ^= (1<<PD6); // LED rot toggle
besteht insgesamt aus zwei verteilten Codeblöcken, einmal
cc: c2 e3 ldi r28, 0x32 ; 50
ce: d0 e0 ldi r29, 0x00 ; 0
d0: 00 e4 ldi r16, 0x40 ; 64
als Initialisierung vor der Schleife, und dann
e6: 88 81 ld r24, Y
e8: 80 27 eor r24, r16
ea: 88 83 st Y, r24
als toggle Operation in der Schleife.
Man kann nun drüber streiten, ob das wirklich als Optimierung zu
verstehen ist, weil dieser Code summarum langsamer und länger ist als
eine weniger agressiv optimierte Version. Aber korrekt ist es.
Servus,
danke für die ausführliche Erklärung. Du hast natürlich recht, hätte ich
noch genauer hingesehen wärs mir vllt. auch aufgefallen.
Leider bekomm ich mein Programm aber mit dem WinAVR trotzdem nicht zum
laufen. Habe den Code mit dem ICC AVR v7 von Imagecraft übersetzt und
damit läuft es. Dummerweise kann ich auch keinen logischen Fehler
entdecken. Ich verweise nochmal auf mein C Codesegment hier
Beitrag "Re: Probleme win WinAVR 20081205".
Das Programm begibt sich in jedem Durchlauf in die erste If-Verzweigung
obwohl die Bedingung eigentlich nicht erfüllt sein dürfte. Naja, mal
sehen ob ich noch dahinter komme was da falsch läuft.
Grüße und danke nochmals.
Robert K. wrote:
> Das Programm begibt sich in jedem Durchlauf in die erste If-Verzweigung> obwohl die Bedingung eigentlich nicht erfüllt sein dürfte.
Meinst du mit "erste If-Verzweigung" dies?
1
if(uart0_rx_is_buffer_empty()==NO){
uart0_rx_is_buffer_empty liefert also nicht das erwartete Ergebnis. Was
glaubst du soll irgendjemand hier dazu sagen, wenn wir den "Inhalt"
dieser Funktion nicht kennen?
Hi,
ich steig einfach nich dahinter warum der Controller nich das macht was
er soll. Es scheitert schon an dem einfachen LED-toggle. Hab alle UART
Funktionen entfernt, compiliert mit 3 WinAVR Versionen (aus AVR-Studio
4.15 Build 623). Schau mal bitte einer drüber ob er nen Fehler findet,
so langsam neige ich dazu auch privat auf nen anderen Compiler
umzusteigen, mit dem Imagecraft ICC AVR 7 klappts ohne Probleme. Habe
irgendwie die Vermutung das es an den Interrupts liegt.
Die Ausgabe des PWM Signals funzt dagegen wie sie soll auch beim WinAVR
(Frequenz und Tastverhältnis mit Oszi überprüft)
thx and greetz, molch
edit 1: Nur eine Warnung beim compilieren das der Rückgabetyp von main
nicht int ist, denke daran sollte es nich liegen. Sonst keine
Fehlermeldungen.
1
#include<avr/io.h>
2
#include<avr/interrupt.h>
3
#include<stdint.h>
4
5
//#include "uart.h"
6
7
8
//uint8_t *ptr_fed = uart0_rx_buffer;
9
10
uint16_tlife_LED_counter;
11
12
13
voidport_init(void){
14
15
DDRB=(1<<DDB1);
16
PORTB=0x00;
17
DDRC=0x00;
18
PORTC=0x00;
19
DDRD=(1<<DDD6)|(1<<DDD5);
20
PORTD=0x00;
21
22
}
23
24
25
ISR(TIMER1_OVF_vect){
26
27
life_LED_counter++;
28
29
}
30
31
/*
32
void timer0_init(void){
33
34
35
}
36
*/
37
38
voidtimer1_init(void){
39
40
// Set OC1A on Compare Match when upcounting.
41
// Clear OC1A on Compare Match when counting down. PWM inverted at OC1A
volatile uint16_t life_LED_counter;
statt
uint16_t life_LED_counter;
Außerdem musst du in der Main loop darauf achten, dass du den Wert
atomar behandelst.
und vor allem(!) Unter Interruptsperre wieder zurücksetzt.
Da kann der Compiler aber auch nichts für, wenn du fehlerhaften Code
schreibst.
Lesen: http://www.mikrocontroller.net/articles/Interrupt
Variable auf volatile gesetzt, Interrupts für die Zeit der Ausführung
global blockiert für "atomaren" bzw. ungestörten Zugriff. Was genau
meinst du mit Unter Interruptsperre zurücksetzen, der Timeroverflowint.
returnt mit nem reti, das sollte meines Wissen diesen Interrupt wieder
freigeben.
edit: ...und die LED wird zwar einmal angeschalten vor der while
Schleife aber in dieser tut sich nix mehr.
>edit: ...und die LED wird zwar einmal angeschalten vor der while>Schleife aber in dieser tut sich nix mehr.
Selbst bei 16MHz dauert es 8 Sekunden, bis die LED aus geht. Bei 1MHz
sind es mehr als 2 Minuten. Hast du auch lange genug gewartet?
Oliver
@Olli:
Timer1 16Bit, Phase & Frequency correct PWM, TOP-Wert im ICR1 mit 255
initialisiert, Formel laut Datenblatt:
"Genau" das mess ich auch mit dem Oszi für die PWM.
Der Timeroverflow erfolgt dann also etwa aller 500µs = 0,5ms, mit meinem
Zwischenzähler "life_LED_counter" teil ich die Frequenz um den Faktor
2000 nach unten -> 1 Hz -> 0,5s bis ein Zustandswechsel an der LED
erkennbar ist.
Wie kommst du auf 2 Minuten?
Grüße
... heissen. Also nich 1960 KHz sondern 1960 Hz.
Rest des Abschnitts stimmt.
Auf die 2 Minuten kommst du sicherlich wenn du TOP = 65535 setzt, aber
das tu ich hier ja nicht.
Wie lange ist die Edit-Funktion für eigene Beiträge aktiv?
Grüße
Hi,
ich darf verkünden Problem gelöst.
Der Grund ist das verschiedene Interrupthandling der beiden von mir
verwendten Compiler (ICC und GCC). Der WinAVR erstellt ein Tabelle mit
den Interrupt Adressen am Anfang des Listfiles und da sind alle
Interrupte denen keine ISR zugeordnet ist mit der Sprungmarke 0x5c
<__bad_interrupt> gekennzeichnet. An dieser wird dann zum Resetvektor
zurückgesprungen.
Da mein Timer1 Capture Event Int. erlaubt war (
1
TIMSK=(1<<TICIE1)|(1<<TOIE1);
) aber keine zugehörige ISR existierte erfolgte bei jedem Capture Event
ein Reset.
Was mich dennoch stutzig macht ist, dass das PWM-Signal korrekt aussah.
Die Erzeugung der PWM wird ja dann beim TOP-Wert des Timers durch den
Reset unterbrochen und damit eigentlich eine halbe Periode zu früh was
die doppelte Frequenz zur Folge hätte. Kann sein, dass das durch das
Tastverhältnis von 50% und den Phase6 Frequency Correct Mode überhaupt
nicht auffiel, aber das untersuch ich jetz erstmal nich. Jetz seh ich zu
das ich in dem Programm mal weiterkomm.
Grüße und danke an die Helfenden, auch wenn keiner von euch den Fehler
gefunden hat :P joke
Bis zum nächsten Problem, Robert