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.
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.
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).
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.
@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>
In der ZIP Datei der StdPeriph_Lib ist ein Examples Verzeichnis enthalten, darin gibt es auch ein SysTick Beispiel.
p.s. die Delays müssen nicht sonderlich genau sein. Ob delay_us (50) 50us oder 55us dauert wäre nicht so wichtig.
@Achim Jau, hab ich auch gesehen, aber ist das wirklich so aufwändig ?
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)); |
@Achim, tschuldigung, hatte was verwechselt. Hm.. sieht ja ganz gut aus :-)
@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 ?
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
Hello all, Regarding the delay_us i would recommend to use a timer unit. My 2 ct. Adib.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.