Forum: Mikrocontroller und Digitale Elektronik [AVR] _delay_ms() funktioniert nicht mehr (vom Compiler ignoriert?)


von Benedikt W. (whiteshampoo)


Lesenswert?

Hallo liebe µC-Gemeinde,

ich habe ein kleines Problem mit der _delay_ms() Funktion. Ich hab das 
Problem schon etwas nachverfolgt, stehe aber mittlerweile nurnoch mit 
einem großen Fragezeichen über dem Kopf da. Wenn ich nach dem Fehler 
suche finde ich leider nur antworten in denen die Funktion falsch 
verwendet wird oder F_CPU nicht definiert ist.

Mein Problem ist, das mein Compiler scheinbar die _delay_ms() funktion 
nicht richtig behandelt. So kommt exakt die gleiche elf und somit auch 
die gleiche (i)hex datei heraus, egal ob ich z.B. _delay_ms(500) oder 
_delay_ms(1000) schreibe.

Aber erstmal ein paar infos zur Umgebung:

OS: Linux Mint (Auf Arch Linux und/oder anderen PCs ist das gleiche 
Problem)
IDE: Codeblocks 13.12-3
Compiler: avr-gcc 1:4.8-2.1
libc: avr-libc 1:1.8.0-4.1
binutils: binutils-avr 2.23.1-2.1
avr: attiny2313 (ist aber egal welcher)

Ich hab ein Programm mal auf das nötigste heruntergebrochen damit der 
Fehler schneller sehbar ist:
1
#define F_CPU 4000000UL
2
3
#include <avr/io.h>
4
#include <util/delay.h>
5
6
int main(void)
7
{
8
    while(1)
9
    {
10
    asm("nop");
11
    asm("nop");
12
    asm("nop");
13
    _delay_ms(1000);
14
    asm("nop");
15
    asm("nop");
16
    asm("nop");
17
    }
18
19
    return 0;
20
}

Dieses Programm hab ich mit verschiedenen Werten in _delay_ms(x) 
compiliert. 500, 1000, 10000. Alle Werte ergeben folgendes, wenn ich mit 
avr-objdump -d die elf-datei ansehe die compiliert wird.
Die jeweils 3x NOP sollen nur bewirken das man die stelle einfach im 
objdump findet.
1
delay_ms_test.elf:     Dateiformat elf32-avr
2
3
4
Disassembly of section .text:
5
6
00000000 <__vectors>:
7
   0:  12 c0         rjmp  .+36       ; 0x26 <__ctors_end>
8
   2:  17 c0         rjmp  .+46       ; 0x32 <__bad_interrupt>
9
   4:  16 c0         rjmp  .+44       ; 0x32 <__bad_interrupt>
10
   6:  15 c0         rjmp  .+42       ; 0x32 <__bad_interrupt>
11
   8:  14 c0         rjmp  .+40       ; 0x32 <__bad_interrupt>
12
   a:  13 c0         rjmp  .+38       ; 0x32 <__bad_interrupt>
13
   c:  12 c0         rjmp  .+36       ; 0x32 <__bad_interrupt>
14
   e:  11 c0         rjmp  .+34       ; 0x32 <__bad_interrupt>
15
  10:  10 c0         rjmp  .+32       ; 0x32 <__bad_interrupt>
16
  12:  0f c0         rjmp  .+30       ; 0x32 <__bad_interrupt>
17
  14:  0e c0         rjmp  .+28       ; 0x32 <__bad_interrupt>
18
  16:  0d c0         rjmp  .+26       ; 0x32 <__bad_interrupt>
19
  18:  0c c0         rjmp  .+24       ; 0x32 <__bad_interrupt>
20
  1a:  0b c0         rjmp  .+22       ; 0x32 <__bad_interrupt>
21
  1c:  0a c0         rjmp  .+20       ; 0x32 <__bad_interrupt>
22
  1e:  09 c0         rjmp  .+18       ; 0x32 <__bad_interrupt>
23
  20:  08 c0         rjmp  .+16       ; 0x32 <__bad_interrupt>
24
  22:  07 c0         rjmp  .+14       ; 0x32 <__bad_interrupt>
25
  24:  06 c0         rjmp  .+12       ; 0x32 <__bad_interrupt>
26
27
00000026 <__ctors_end>:
28
  26:  11 24         eor  r1, r1
29
  28:  1f be         out  0x3f, r1  ; 63
30
  2a:  cf ed         ldi  r28, 0xDF  ; 223
31
  2c:  cd bf         out  0x3d, r28  ; 61
32
  2e:  02 d0         rcall  .+4        ; 0x34 <main>
33
  30:  0d c0         rjmp  .+26       ; 0x4c <_exit>
34
35
00000032 <__bad_interrupt>:
36
  32:  e6 cf         rjmp  .-52       ; 0x0 <__vectors>
37
38
00000034 <main>:
39
  34:  00 00         nop
40
  36:  00 00         nop
41
  38:  00 00         nop
42
  3a:  8f ef         ldi  r24, 0xFF  ; 255
43
  3c:  9f e3         ldi  r25, 0x3F  ; 63
44
  3e:  01 97         sbiw  r24, 0x01  ; 1
45
  40:  f1 f7         brne  .-4        ; 0x3e <__SP_L__+0x1>
46
  42:  00 c0         rjmp  .+0        ; 0x44 <__SREG__+0x5>
47
  44:  00 00         nop
48
  46:  00 00         nop
49
  48:  00 00         nop
50
  4a:  f4 cf         rjmp  .-24       ; 0x34 <main>
51
52
0000004c <_exit>:
53
  4c:  f8 94         cli
54
55
0000004e <__stop_program>:
56
  4e:  ff cf         rjmp  .-2        ; 0x4e <__stop_program>

Um zu verhindern das ich irgendwas übersehe habe ich auch schon 
avr-objdump mit -d -x ausgeführt und für die jeweils verschiedenen Werte 
in _delay_ms in dateien geschrieben und mit diff verglichen. KEIN 
Unterschied. Und um zu verhindern das ich die falsche Datei untersuche 
habe ich versucht andere kleine Variablenmanipulationen ins Programm zu 
bringen. Hierbei entstehen durchaus änderungen in der elf-Datei.

Ich will _delay_ms eigentlich gar nicht verwenden, aber um schnell etwas 
zu testen ist es eben nützlich. Nur wenn einem so ein kleines Problem 
einen ganzen Abend aufhält ist das schon lästig.
Letzendlich ist es egal was ich eingebe, das delay ändert sich nicht, 
und so kann natürlich niemand arbeiten.
Was mich besonders stutzig macht ist das _delay_ms() vor wenigen 
Wochen/Monaten von mir ohne Probleme benutzt werden konnte. Also zu doof 
scheine ich auch nicht zu sein.

Ich hoffe das irgendjemand eine Lösung hat.

Danke für Eure Zeit und Lösungen!

: Bearbeitet durch User
von STK500-Besitzer (Gast)


Lesenswert?

Benedikt W. schrieb:
> der _delay_ms() Funktion

Es ist ein Makro - keine Funktion.
Und es wird durch die Compiler-Optimierungseinstellung gerne 
wegoptimiert.

von Benedikt W. (whiteshampoo)


Lesenswert?

Wenn ich dem Compiler sage "Bitte nicht optimieren" jammert _delay_ms 
aber herum das es nicht richtig funktionieren wird. :(

von Bitflüsterer (Gast)


Lesenswert?

Benedikt W. schrieb:
> Wenn ich dem Compiler sage "Bitte nicht optimieren" jammert _delay_ms
> aber herum das es nicht richtig funktionieren wird. :(

Von STK500-Besitzer abgesehen, sagt ja niemand, das Du die Optimierung 
ausschalten sollst.

Das ist doch mal ein "RTFM" wert. 
http://www.groupes.polymtl.ca/inf1995/logiciel/progAvr/avr-libc-user-manual-1.8.0.pdf 
;-)

von Karl H. (kbuchegg)


Lesenswert?

STK500-Besitzer schrieb:
> Benedikt W. schrieb:
>> der _delay_ms() Funktion
>
> Es ist ein Makro - keine Funktion.
> Und es wird durch die Compiler-Optimierungseinstellung gerne
> wegoptimiert.

Hatte ich zuerst auchgedacht, dass es wegoptimiert wurde.
Ist hier aber nicht der Fall, wie der Assembler Output zeigt.

von Bitflüsterer (Gast)


Lesenswert?

Du hast vergessen, nachträglich zu editieren, Karl Heinz. Ich weiss zwar 
nicht, was Du noch ändern solltest, aber Du solltest es. :-)

von Jim M. (turboj)


Lesenswert?

Versuche mal einen Wert kleiner als 60. Da war was mit Integer Überlauf 
in dem _delay_ms Makro.

von Karl H. (kbuchegg)


Lesenswert?

Bitflüsterer schrieb:
> Du hast vergessen, nachträglich zu editieren, Karl Heinz. Ich weiss zwar
> nicht, was Du noch ändern solltest, aber Du solltest es. :-)

Hmm. Zwischen 'auch' und 'gedacht' fehlt ein Leerzeichen.
Könnte ich jetzt noch reineditieren, bin aber im Moment zu faul dazu :-)

von Karl H. (kbuchegg)


Lesenswert?

Jim Meba schrieb:
> Versuche mal einen Wert kleiner als 60. Da war was mit Integer Überlauf
> in dem _delay_ms Makro.

Da müsste er schon eine sehr alte Version haben.
Seit einigen Jahren ist das kein Problem mehr.

von Karl H. (kbuchegg)


Lesenswert?

Karl Heinz schrieb:
> Jim Meba schrieb:
>> Versuche mal einen Wert kleiner als 60. Da war was mit Integer Überlauf
>> in dem _delay_ms Makro.
>
> Da müsste er schon eine sehr alte Version haben.
> Seit einigen Jahren ist das kein Problem mehr.


Aber irgendwas stimmt da nicht
Denn das
1
  3a:  8f ef         ldi  r24, 0xFF  ; 255
2
  3c:  9f e3         ldi  r25, 0x3F  ; 63
3
  3e:  01 97         sbiw  r24, 0x01  ; 1
4
  40:  f1 f7         brne  .-4        ; 0x3e <__SP_L__+0x1>
ergibt bei aller Liebe niemals 1 Sekunde Laufzeit. Da brauch ich gar 
nicht nachrechnen, das geht sich nie aus.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Benedikt W. schrieb:
> Ich hoffe das irgendjemand eine Lösung hat.

 So sieht es bei mir aus:
1
00000034 <main>:
2
    milliseconds can be achieved.
3
 */
4
void
5
_delay_loop_2(uint16_t __count)
6
{
7
  __asm__ volatile (
8
  34:  24 e6         ldi  r18, 0x64  ; 100
9
  36:  30 e0         ldi  r19, 0x00  ; 0
10
11
int main(void)
12
{
13
    while(1)
14
    {
15
    asm("nop");
16
  38:  00 00         nop
17
    asm("nop");
18
  3a:  00 00         nop
19
    asm("nop");
20
  3c:  00 00         nop
21
  3e:  80 e1         ldi  r24, 0x10  ; 16
22
  40:  97 e2         ldi  r25, 0x27  ; 39
23
  42:  f9 01         movw  r30, r18
24
  44:  31 97         sbiw  r30, 0x01  ; 1
25
  46:  f1 f7         brne  .-4        ; 0x44 <__SREG__+0x5>
26
    __ticks = (uint16_t) (__ms * 10.0);
27
    while(__ticks)
28
    {
29
      // wait 1/10 ms
30
      _delay_loop_2(((F_CPU) / 4e3) / 10);
31
      __ticks --;
32
  48:  01 97         sbiw  r24, 0x01  ; 1
33
    __ticks = 1;
34
  else if (__tmp > 65535)
35
  {
36
    //  __ticks = requested delay in 1/10 ms
37
    __ticks = (uint16_t) (__ms * 10.0);
38
    while(__ticks)
39
  4a:  d9 f7         brne  .-10       ; 0x42 <__SREG__+0x3>
40
    _delay_ms(1000);
41
    asm("nop");
42
  4c:  00 00         nop
43
    asm("nop");
44
  4e:  00 00         nop
45
    asm("nop");
46
  50:  00 00         nop
47
  52:  f2 cf         rjmp  .-28       ; 0x38 <main+0x4>
48
49
00000054 <_exit>:
50
  54:  f8 94         cli
51
52
00000056 <__stop_program>:
53
  56:  ff cf         rjmp  .-2        ; 0x56 <__stop_program>
 Bei dir ist _delay irgendwie verschwunden, auch ist Wert fur _delay
 nicht as volatile deklariert, aber so schlau kann doch eigentlich kein
 Compiler sein - oder doch ?
 Versuchs mal mit irgendeiner Variable dahinter.

: Bearbeitet durch User
von Marco S (Gast)


Lesenswert?

Bei mir kommt mit
1
avr-gcc (GCC) 4.8.2-2
1
avr-binutils 2.24-1
1
avr-libc 1.8.0-5
1
avr-gcc -Os -g3 -o main.elf -mmcu=attiny2313 main.c

unter ArchLinux folgendes heraus:
1
  while(1)
2
    {
3
    asm("nop");
4
  46:   00 00           nop
5
    asm("nop");
6
  48:   00 00           nop
7
    asm("nop");
8
  4a:   00 00           nop
9
        #else
10
                //round up by default
11
                __ticks_dc = (uint32_t)(ceil(fabs(__tmp)));
12
        #endif
13
14
        __builtin_avr_delay_cycles(__ticks_dc);
15
  4c:   2f ef           ldi     r18, 0xFF       ; 255
16
  4e:   84 e3           ldi     r24, 0x34       ; 52
17
  50:   9c e0           ldi     r25, 0x0C       ; 12
18
  52:   21 50           subi    r18, 0x01       ; 1
19
  54:   80 40           sbci    r24, 0x00       ; 0
20
  56:   90 40           sbci    r25, 0x00       ; 0
21
  58:   e1 f7           brne    .-8             ; 0x52 <main+0xc>
22
  5a:   00 c0           rjmp    .+0             ; 0x5c <main+0x16>
23
  5c:   00 00           nop
24
    _delay_ms(1000);
25
    asm("nop");
26
  5e:   00 00           nop
27
    asm("nop");
28
  60:   00 00           nop
29
    asm("nop");
30
  62:   00 00           nop

Das liegt mit dem 24bit-Zähler schon eher in der Nähe von 1Sek.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Marc Vesely schrieb:
> So sieht es bei mir aus:

 Ist zwar OT, aber trotzdem eine Frage an den Moderator:
 Du hast mein Beitrag moderiert, ich meine das mit Unterstrich und so,
 machst du das zu Fuss oder kann man autoedit irgendwie abstellen ?

von Karl H. (kbuchegg)


Lesenswert?

Marc Vesely schrieb:
> Marc Vesely schrieb:
>> So sieht es bei mir aus:
>
>  Ist zwar OT, aber trotzdem eine Frage an den Moderator:
>  Du hast mein Beitrag moderiert, ich meine das mit Unterstrich und so,
>  machst du das zu Fuss oder kann man autoedit irgendwie abstellen ?

Wenn du dir angewöhnen würdest, bei Code gleich die Formatierzeichen 
einzufügen ....


Für C-Code am Beginn des Codes [ C ], am Ende des Codes [ /C ] (jeweils 
ohne die Leerzeichen.
Für Assembler Code am Beginn des Codes [ avrasm ], am Ende des Codes [ 
/avrasm ] (wieder ohne die Leerzeichen

... dann bräuchte ich deinen Post nicht editieren.
Mahr als diese Formatierzeichen ergänzen hab ich in deinem Posting nicht 
gemacht.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Marc Vesely schrieb:
> nicht as volatile deklariert, aber so schlau kann doch eigentlich kein
>  Compiler sein - oder doch ?
>  Versuchs mal mit irgendeiner Variable dahinter.

 Vor etwa 10 Jahren zeigte mir jemand ein Schnipsel aus den 60-er
 in FORTRAN. War fur IBMetwas geschrieben. Und zwar wollten die wissen
 wie schnell der IBM eigentlich rechnen kann.
 Also, Variable XYZ durch PI, in eine Schleife, 1000 Durchläufe, Zeit
 gemessen - nicht messbar.
 5000, 100000, 10000000, 1E12 - dasselbe.
 Na, so schnell kann der IBM doch gar nicht sein, dachten die
 Schlaumeier. Bis irgendeiner dahinter kam, dass die Variable ja
 nirgendwo ausgegeben oder benutzt wurde, also hat der compiler das
 Ganze einfach wegoptimiert...

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Karl Heinz schrieb:
> ... dann bräuchte ich deinen Post nicht editieren.
> Mahr als diese Formatierzeichen ergänzen hab ich in deinem Posting nicht
> gemacht.

 Hab mich auch nicht beschwert, nur gefragt. Sorry.
 Wichtige Regeln - erst lesen, dann posten.
 Hurra, ich kann das !!!

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.