Forum: Mikrocontroller und Digitale Elektronik _delay_ms Faktor 13 zu langsam


von mc (Gast)


Lesenswert?

Hallo,

bin gerade auf einen seltsamen Effekt mit _delay_ms aus der avr/delay.h 
gestossen.

Folgendes Setup:

Atmega8 mit externem 16MHz Crystal. lfuse:w:0x9f:m hfuse:w:0xd9:m.
F_CPU per Makefile auf 16000000 gesetzt.
Es laufen mehrere ISRs und auch usart wird per
1
#define BAUD 38400
2
#define UBRR F_CPU/16/BAUD-1
gesetzt und funktioniert.
Daher wuerde ich davon ausgehen, dass die Settings alle korrekt sind.
Wenn ich testweise auf den langsameren internen Oszillator wechsle, geht 
z.B. usart erwartungsgemaess nicht mehr.

So, nun die _delay_ms()-Funktion: laeuft relativ genau Faktor 13 
langsamer als sie soll, also ein Testsignal mit _delay_ms(38) 
ontime+offtime laeuft ca. mit 1Hz.
Finden konnte ich nichts dazu, hat jemand sowas schonmal gesehen?

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

_delay_ms funktioniert nur korrekt mit eingeschaltetem Optimizer. Stell 
Dein Projekt auf Release um oder schalte die Optmierung ein, also zum 
Beispiel -Os.

von c-hater (Gast)


Lesenswert?

mc schrieb:

> Finden konnte ich nichts dazu, hat jemand sowas schonmal gesehen?

Optimierung ist aus.

von mc (Gast)


Lesenswert?

Ah richtig, das hatte ich vergessen zu erwähnen: -Os wird verwendet.

von c-hater (Gast)


Lesenswert?

mc schrieb:

> Ah richtig, das hatte ich vergessen zu erwähnen: -Os wird verwendet.

Das ist die falsche Optimierung.

von mc (Gast)


Lesenswert?

Und was wäre dann korrekt? -O1 ist identisch.

Hat sich da was mit einem avr-gcc update geändert?
avr-gcc ist bei mir 5.4.0 aus debian testing.
Wenn ich mich recht erinnere, ist das Verhalten recht neu, fast 
identische init code templates + gleiches Makefile habe ich schon Jahre 
verwendet, das hat bisher immer wie gewollt funktioniert.

von Ferger (Gast)


Lesenswert?

c-hater schrieb:
> mc schrieb:
>
>> Ah richtig, das hatte ich vergessen zu erwähnen: -Os wird verwendet.
>
> Das ist die falsche Optimierung.

Das ist Quatsch, wie üblich bei dir.

von Kalter Rechner (Gast)


Lesenswert?

mc schrieb:
> _delay_ms(38)
> ontime+offtime laeuft ca. mit 1Hz.

Um 1 Hz mit ontime+offtime zu erzeugen müsste man _delay_ms(500)
benutzen .....

von mc (Gast)


Lesenswert?

Kalter Rechner schrieb:
> mc schrieb:
>> _delay_ms(38)
>> ontime+offtime laeuft ca. mit 1Hz.
>
> Um 1 Hz mit ontime+offtime zu erzeugen müsste man _delay_ms(500)
> benutzen .....
Ja, stimmt doch? 38x die erwähnte Abweichung um den Faktor 13 ergibt 
knapp 500.

von Oliver S. (oliverso)


Lesenswert?

Mach ein Minimalprogram daraus, und zeig das hier.

Oliver

von Kalter Rechner (Gast)


Lesenswert?

mc schrieb:
> Es laufen mehrere ISRs

... die evtl. eine Menge Arbeit inline erledigen?

Z.B. Zeichenketten in der ISR über UART ausgeben ist tötlich,
aber wir kennen ja dein Programm nicht ....

von Matthias L. (Gast)


Lesenswert?

Die richtige Optimierung ist, kein delay zu verwenden.

von Kalter Rechner (Gast)


Lesenswert?

Matthias L. schrieb:
> Die richtige Optimierung ist, kein delay zu verwenden.

Das hilft auch nichts (mehr) wenn eine ISR die andere jagt.

von mc (Gast)


Lesenswert?

Oliver S. schrieb:
> Mach ein Minimalprogram daraus, und zeig das hier.
>
> Oliver

Gerne, hab das mal minimalisiert. USART-Kram ist noch drinnen weil auch 
ISR.
Ich habe übrigens definitiv eine Abhängigkeit von compiler+lib bei dem 
Effekt. Bin gerade am schauen, wo das genau herkommt, vielleicht 
irgendwelche falsch gezogenen Artefakte.
1
#include <stdlib.h>
2
#include <avr/io.h>
3
#include <inttypes.h>
4
#include <avr/interrupt.h>
5
#include <util/delay.h>
6
#include <stdio.h>
7
#include <util/atomic.h>
8
#include <stdbool.h>
9
10
#define BAUD 38400
11
#define MYUBRR F_CPU/16/BAUD-1
12
13
int usart_putchar_printf(char var, FILE *stream);
14
static FILE mystdout = FDEV_SETUP_STREAM(usart_putchar_printf, NULL, _FDEV_SETUP_WRITE);
15
16
void usart_init( uint16_t ubrr)
17
{
18
    UBRRH = (uint8_t)(ubrr>>8);
19
    UBRRL = (uint8_t)ubrr;
20
    UCSRB = (1<<TXEN);
21
}
22
void usart_putchar(char data)
23
{
24
    while ( !(UCSRA & (_BV(UDRE))) );
25
    UDR = data;^M
26
}
27
28
unsigned char usart_kbhit(void)
29
{
30
    unsigned char b;
31
    b=0;^M
32
    if(UCSRA & (1<<RXC)) b=1;
33
    return b;
34
}
35
void usart_pstr(char *s)
36
{
37
    while (*s) {
38
        usart_putchar(*s);
39
        s++;
40
    }
41
}
42
43
int usart_putchar_printf(char var, FILE *stream)
44
{
45
    if (var == '\n') usart_putchar('\r');
46
    usart_putchar(var);
47
    return 0;
48
}
49
void init( void )
50
{
51
    DDRB |= (1 << PB0) | (1 << PB1) | (1 << PB2) | (1 << PB3) | (1 << PB4) | (1 << PB5);
52
    DDRD |= (1 << PD2) | (1 << PD5);
53
    PORTC |= (1 << PC0) | (1 << PC1) | (1 << PC2) | (1 << PC3) | (1 << PC4) | (1 << PC5);
54
    PORTD |= (1 << PD6) | (1 << PD7);
55
56
    TCCR1A |= (1<<WGM10);
57
    TCCR1A |= (1<<COM1A1) | (1<<COM1B1);
58
    TCCR1B |= (1 << CS10);
59
    TCCR2 |= (0 << CS22) | (0 << CS21) | (1 << CS20);
60
    TIMSK |= (1 << TOIE2);
61
    TCCR0 |=  (1 << CS00);
62
    TIMSK |= 1<<TOIE0;
63
64
    sei();
65
}
66
67
ISR( TIMER2_OVF_vect )
68
{
69
    TCNT2 = 0; // temp avoid opt
70
}
71
72
ISR( TIMER0_OVF_vect )
73
{
74
    TCNT0 = 145;
75
}
76
77
int main(void)
78
{
79
    init();
80
81
    stdout = &mystdout;
82
    usart_init( MYUBRR );
83
84
    _delay_ms(100);
85
    printf("\nfoo\n");
86
    do {
87
        _delay_ms(50);
88
        PORTD &= ~(1 << PD2);
89
        _delay_ms(50);
90
        PORTD |= (1 << PD2);
91
    } while (1);
92
}

Compiled mit:
1
avr-gcc -c -mmcu=atmega8 -I. -DF_CPU=16000000UL -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes -Wundef -Wa,-adhlns=obj/main_test.lst  -std=gnu99 -Wundef -MD -MP -MF .dep/main_test.o.d main_test.c -o obj/main_test.o

von Oliver S. (oliverso)


Lesenswert?

Das muß ein Problem in deiner toolchain sein. Bei mir tut es das 
prinzipiell (avr-gcc 10.1, Windows). Es sind zwar keine 50ms, sondern 
ca. 61ms, weil da die ISRs noch dazwischenfunken, aber ansonsten 
fuktioniert das.

Oliver

von mc (Gast)


Lesenswert?

Oliver S. schrieb:
> Das muß ein Problem in deiner toolchain sein. Bei mir tut es das
> prinzipiell (avr-gcc 10.1, Windows). Es sind zwar keine 50ms, sondern
> ca. 61ms, weil da die ISRs noch dazwischenfunken, aber ansonsten
> fuktioniert das.
>
> Oliver

Vielen Dank für den Test! Sieht wirklich ganz nach build-umgebung aus, 
auf einer neuen VM bekomme ich es (auch debian) nicht reproduziert. In 
diesem Sinne Verzeihung fuer die eigentlich überflüssige Frage, aber da 
denkt man erstmal nicht dran...

von Einer K. (Gast)


Lesenswert?

Oliver S. schrieb:
> Das muß ein Problem in deiner toolchain sein.
Es gibt da noch ein Problem mit der Toolchain.

Wollte das Programm testen und mein 10.2.0 Gcc hats mir um die Ohren 
gehauen.

mc schrieb:
1
static FILE mystdout = FDEV_SETUP_STREAM(usart_putchar_printf, NULL, _FDEV_SETUP_WRITE);
In stdio.h wird die Struktur im C Stil initialisiert.
Das klappt unter C++ nicht.

Abhilfe:
1
  #undef FDEV_SETUP_STREAM
2
  #define FDEV_SETUP_STREAM(p, g, f) { 0, 0, f, 0, 0, p, g, 0 }

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.