delay us: Wie reparieren?

#3313519
Lesenswert?

Hab hier nen SAM3X8E mit f_cpu = 84MHz. Bei 1000us messe ich auf dem 
Oszi aber um die 1920us (nicht Faktor 2) am Port.

das hier steht in cycle_counter.h (ich benutze gcc):
1
void portable_delay_cycles(unsigned long n);
2

3
#if (defined __GNUC__)
4
#  define cpu_ms_2_cy(ms, f_cpu)  \
5
  (((uint64_t)(ms) * (f_cpu) + (uint64_t)(57e2-1ul)) / (uint64_t)57e2)
6
#  define cpu_us_2_cy(us, f_cpu)  \
7
  (((uint64_t)(us) * (f_cpu) + (uint64_t)(57e5-1ul)) / (uint64_t)57e5)
8

9

10
#elif (defined __ICCARM__)
11
#  define cpu_ms_2_cy(ms, f_cpu)  \
12
  (((uint64_t)(ms) * (f_cpu) + (uint64_t)(14e3-1ul)) / (uint64_t)14e3)
13
#  define cpu_us_2_cy(us, f_cpu)  \
14
  (((uint64_t)(us) * (f_cpu) + (uint64_t)(14e6-1ul)) / (uint64_t)14e6)
15
#endif
16

17
#define delay_cycles               portable_delay_cycles
18

19
#define cpu_delay_ms(delay, f_cpu) delay_cycles(cpu_ms_2_cy(delay, f_cpu))
20
#define cpu_delay_us(delay, f_cpu) delay_cycles(cpu_us_2_cy(delay, f_cpu))


Die Datei ist aus dem Atmel Framework. Scheinbar gehört der Code aber zu 
einem anderen uC. Wie kann ich die Berechnungen korrigieren damit ich
cpu_delay_us(delay, f_cpu)
vernünftig benutzen kann?
Und was hat's mit den unterschiedlichen Anhängseln für gcc und IAR auf 
sich?
Gast #3315153
Lesenswert?

Laeuft der Systick Timer? Dann haengt Dich an den ran. Etwa wie in 
Nut/Os
1
void NutMicroDelay(uint32_t us)
2
{
3
    int32_t start_ticks;
4
    int32_t current_ticks, summed_ticks=0;
5
    int32_t end_ticks;
6

7
    start_ticks = SysTick->VAL;
8
    end_ticks = (us * (SysTick->LOAD +1))/SYS_TICK_FREQ;
9
/* Systick counts backwards! */
10
    while (summed_ticks < end_ticks)
11
    {
12
        current_ticks = SysTick->VAL;
13
        summed_ticks += start_ticks - current_ticks ;
14
        if (current_ticks > start_ticks)
15
            summed_ticks += (SysTick->LOAD +1);
16
        start_ticks = current_ticks;
17
    }
#3315998
Lesenswert?

>Laeuft der Systick Timer? Dann haengt Dich an den ran.

Ja, das hab ich auch schon überlegt.
Das freundlicherweise mitgelieferte mdelay() liefert Mllisekunden, ich 
hab die Timer samt ISR aber bis jetzt immer zu umgehen versucht ;-) 
Wobei der System-Timer wohl einfacher ist. Ich werd's in den nächsten 
Tagen angehen.

Danke.
#3316062
Lesenswert?

Uwe Bonnes schrieb:
> void NutMicroDelay(uint32_t us)
> ...

Das ist ja ganz schön viel Holz.
Es geht auch deutlich einfacher.

Hier ein Delay mit Timer auf dem AVR:
1
void delay( int16_t d )          // d = 0 ... 32000 ticks
2
{
3
  d += TCNT1;
4
  while( (TCNT1 - d) & 0x8000 ); // until positive
5
}

Der Trick dabei ist, daß es überlauffest ist (Differenzen stimmen 
immer).

Bei 32Bit wird der Überlauf zwar seltener sein, muß aber trotzdem 
berücksichtigt werden.

Uwe Bonnes schrieb:
> end_ticks = (us * (SysTick->LOAD +1))/SYS_TICK_FREQ;

Erfordert aber zwingend einen MC mit Divisionsbefehl, sonst kommt da 
noch massig Delay hinzu.
Gast #3316928
Lesenswert?

Peter Dannegger schrieb:
> Das ist ja ganz schön viel Holz.
> Es geht auch deutlich einfacher.
>
> Hier ein Delay mit Timer auf dem AVR:void delay( int16_t d )          //
> d = 0 ... 32000 ticks
> {
>   d += TCNT1;
>   while( (TCNT1 - d) & 0x8000 ); // until positive
> }
>
> Der Trick dabei ist, daß es überlauffest ist (Differenzen stimmen
> immer).
>

Peter, der SysTick Timer beim Cortex dient meist Zeitbasis und laeuft 
daher sowieso. Ausserdem ist er bei allen Cortex Type vorhanden, 
waehrend die anderen Timer herstellerspezifisch sind. Allerdings zaehlt 
der Systick im Betrieb als Zeitbasis halt nur von 0 bis x und nicht bis 
zum Ueberlauf, daher die komplexere Arithmetik.

> Bei 32Bit wird der Überlauf zwar seltener sein, muß aber trotzdem
> berücksichtigt werden.
>
> Uwe Bonnes schrieb:
>> end_ticks = (us * (SysTick->LOAD +1))/SYS_TICK_FREQ;
>
> Erfordert aber zwingend einen MC mit Divisionsbefehl, sonst kommt da
> noch massig Delay hinzu.

Irgendwo hatte ich (SysTick->LOAD +1))/SYS_TICK_FREQ auch schon mal 
waehrend des Startups berechnet und dann in NutMicroDelay nur noch 
multipliziert. Der Code ist aber irgendwie nicht im Repsoitory 
angekommen. Danke fuer die Codereview!

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