_delay_ms Faktor 13 zu langsam

Gast #6526656
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?
Gast #6526711
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.
Gast #6526860
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
Gast #6526931
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...
Gast #6527582
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 }

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren