Forum: Compiler & IDEs Cortex-M3: delay_ms(), delay_us() ?


von doc (Gast)


Lesenswert?

Hallo Gemeinde,

meine LED blinkt nun mit Hilfe von Millionen von Transtitoren eines 
Cortex-M3 :-)) Einer der aufwändigsten Blinker aller Zeiten :-)

Da stellt sich mir aber eine doofe Anfänger Frage:

Wo finde ich Funktionen wie _delay_ms() und _delay_us() (anlog wie beim 
avr) ?

Oder.. wie programmiere ich sowas halbwegs portabel ?
Ich nehme an, man kann den SysTick benutzen ?

thanks in advance,
doc.

von doc (Gast)


Lesenswert?

p.s. Es handelt sich um einen STM32F103

von (prx) A. K. (prx)


Lesenswert?

Für längere Delays empfiehlt sich der Systick Interrupt.

Für kürzere Delays kann man Systick verwenden, um eine passend 
programmierte Warteschleife zu kalibrieren. Alternativ kann man direkt 
den Systick-Wert nutzen.

von Patrick B. (p51d)


Lesenswert?

also bei avr gcc gibts die angesprochenen Funktionen schon als Header:
1
#define F_CPU   16000000
2
#include     <util/delay.h>
3
4
5
int main(void){
6
7
  _delay_ms(100);      // Delay von 100ms
8
  _delay_us(100);      // Delay von 100us
9
10
return 0;
11
}

oder du baust dir dein Delay selber mittels einem Timer und den 
entsprechenden Interrupts / Flags (je nach Wunsch).
Dann inkrementierst du dir halt eine Variable, jedesmal wenn der Timer 
einen bestimmten Wert erreicht hat (CTC).

von (prx) A. K. (prx)


Lesenswert?

Nur ist ein STM32 kein AVR. Die AVR Versionen hängen von bekannten 
Befehlslaufzeiten ab. Bei komplexeren Prozessoren mit Waitstates, 
Pefetch-Puffern usw. ist das schwer portabel in den Griff zu bekommen.

Wenn man bei solchen Prozessoren mit Delayloops arbeitet, dann sollte 
man die anfangs mit einer bekannter Referenz kalibireren, um nicht von 
unbekannten Laufzeiten abhängig zu sein.

von doc (Gast)


Lesenswert?

@Patrick:
Jo, für den AVR kenn ich das ja..

nützt mir nur nix, weil ich noch keine Bibliothek gefunden habe, wo das 
eingebaut wäre.
Die vom AVR funktioniert natürlich nicht.

@A.K.
Ähmm kannst Du mich in Form von ein bischen Code mal ein wenig auf den 
richtigen Weg schubsen ?

a) für Delays im us-Bereich
b) für Delays im ms-Bereich

Ich möchte die STM StdPeriph_Lib benutzen.

Außer PC9 Toggeln kann ich noch garnix auf Cortex <g>

von Achim (Gast)


Lesenswert?

In der ZIP Datei der StdPeriph_Lib ist ein Examples Verzeichnis 
enthalten, darin gibt es auch ein SysTick Beispiel.

von doc (Gast)


Lesenswert?

p.s. die Delays müssen nicht sonderlich genau sein. Ob delay_us (50) 
50us oder 55us dauert wäre nicht so wichtig.

von doc (Gast)


Lesenswert?

@Achim
Jau, hab ich auch gesehen, aber ist das wirklich so aufwändig ?

von (prx) A. K. (prx)


Lesenswert?

Ein Beispiel für eine kalibrierte Delayloop wäre
1
#define DELAY_OVERHEAD (18 * (1000000000 / F_HCLK)) // Daumenpeilung
2
3
static unsigned delay_ns_per_tick = 1;
4
5
void
6
delay_ns(unsigned ns)
7
{
8
    unsigned t = DELAY_OVERHEAD;
9
    __asm volatile(".balign 8\n"
10
       "1: add %0, %1\n"
11
       "   cmp %0, %2\n"
12
       "   blo 1b" :: "r"(t),"r"(delay_ns_per_tick),"r"(ns));
13
}
wobei ich das eher aus Gewohnheit in Assembler implentiert habe, in C 
ginge das genauso. Die Kalibierung über Systick sieht so aus:
1
    SysTick->LOAD = SYSTICK_MAXCOUNT;
2
    SysTick->VAL  = 0;
3
    SysTick->CTRL = 1<<SYSTICK_CLKSOURCE | 1<<SYSTICK_ENABLE; // use core clock (HCLK)
4
    __DSB();
5
    unsigned t1 = SysTick->VAL;
6
    delay_ns(1000 + DELAY_OVERHEAD);
7
    unsigned t2 = SysTick->VAL;
8
    __asm volatile (""::"r"(t2)); // GCC-spezifische Vorsichtsmassnahme
9
    delay_ns_per_tick = 1000000 / (F_HCLK / (t1 - t2));

von doc (Gast)


Lesenswert?

@Achim, tschuldigung, hatte was verwechselt.
Hm.. sieht ja ganz gut aus :-)

von doc (Gast)


Lesenswert?

@A.K.
wow.. DANKESCHÖN erstmal.

Ich verstehe zwar noch nicht viel davon, aber das sieht klasse aus :-)
Wie würde ich für den Fall des Falles Interrupts enablen/disablen ?

von Selso (Gast)


Lesenswert?

Sorry I don't speak german, but the topic is interesting even it is old 
this is the only one I found that talks about short delay on cortex.

I wanted u delay based on the systick.
I am coding with ST HAL for the STM32F3xx
I did not understand the asm code above, so I wrote my own solution that 
I share here :
1
typedef struct __libclk_systickInfo
2
{
3
  unsigned long ulRes_ns ; //!< cpt resolution
4
  unsigned long ulMax_ns ; //!< delay max appliable NS
5
} LIBCLK_SYSTICKINFO;
6
7
static LIBCLK_SYSTICKINFO g_systickInfo = {0};
8
9
void libclk_dlyInit( void )
10
{
11
  // Compute the max appliable
12
13
  /*
14
   * Compute troncate to int but this does not matter, we'll                         
15
           compensate later "SystemCoreClock "
16
   */
17
  g_systickInfo.ulRes_ns = (1000000000/SystemCoreClock);
18
19
  /*
20
   * Delay on a full counwtown result in impossible thresold detection : we give 100 us margin to CPU (@72MHz) 
21
   */
22
  g_systickInfo.ulMax_ns = ((SysTick->LOAD ) *  
23
        g_systickInfo.ulRes_ns)  - 100000 ;
24
25
}
26
27
void libclk_delayNs( unsigned long dlyNs )
28
{
29
  // add 1 count to compensate division truncation
30
  unsigned long dly_cnt = dlyNs / g_systickInfo.ulRes_ns  + 1;
31
  // systick execute a countdown
32
  unsigned long dly_val =  0;
33
  unsigned long systick_val = SysTick->VAL;
34
35
  // deactivate assert when benchmarking
36
  assert( g_systickInfo.ulRes_ns && g_systickInfo.ulMax_ns);
37
  assert( dly_cnt <=  g_systickInfo.ulMax_ns);
38
39
  if( systick_val >= dly_cnt )
40
  {
41
    dly_val = systick_val - dly_cnt;
42
    // wait underflow with 1 countdown detection
43
    while( (SysTick->VAL > dly_val) && (SysTick->VAL < systick_val) ){};
44
  }
45
  else
46
  {
47
    dly_val = SysTick->LOAD - ( dly_cnt - systick_val ) ;
48
    // wait underflow
49
    while(SysTick->VAL < systick_val);
50
    // wait target underflowed
51
    while( SysTick->VAL > dly_val ) {};
52
  }
53
}

I just did test in debug mode with a gcc toolchain, the minimum I could 
do was 1,35 us. I bet the result is better when optimising but my target 
was to have us delays.
It would be better if this code was written in disassembly as the 
compilation option would not influence the result, but I am not used to 
assembly code.
Regards.

: Bearbeitet durch Moderator
von Adib (Gast)


Lesenswert?

Hello all,

Regarding the delay_us i would recommend to use a timer unit.

My 2 ct.

Adib.

von aSma>> (Gast)


Lesenswert?


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.