stm32f103 1 us Systick-timer delay

OP #5357941
Lesenswert?

Hallo Zusammen,
ich habe ein stm32f103-board hier (blue-pill, falls das jemand was 
sagt). Dort ist ein 8MHz Quarz drauf. Um einen Sensor vom Typ DHT22 
abfragen zu können, benötige ich unter anderem ein 1uS delay. Nun habe 
ich versucht mir eine Library zu basteln, die mir mithilfe des 
Systick-Timers 2 Delays macht (ms und us). Dabei bin ich grob wie folgt 
vorgegangen:

http://embeddedsystemengineering.blogspot.de/2016/01/arm-cortex-m3-stm32f103-tutorial-system.html

Das ms-delay hat dabei gut funktioniert (noch nicht nachgemessen ob das 
wirklich so genau stimmt). das uS delay funktionierte so gar nicht. Ich 
habe dann angefangen an den Anzahl an Ticks zwischen 2 Interrupts zu 
spielen. Dabei bin ich darauf gestoßen, dass es bis zu einem Wert von 33 
(x 125nS) noch funktioniert, bei 32 nicht mehr. Dies Wären dann ein 
minmales delay von 4,125uS

Kann sich einer das erklären ? Ich werde daraus einfach nicht schlau

die Clock-konfiguration in der main sieht wie folgt aus: (kommt aus 
stm32cubemx so raus)

void SystemClock_Config(void)
{

  RCC_OscInitTypeDef RCC_OscInitStruct;
  RCC_ClkInitTypeDef RCC_ClkInitStruct;

    /**Initializes the CPU, AHB and APB busses clocks
    */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    _Error_Handler(_FILE_, _LINE_);
  }

    /**Initializes the CPU, AHB and APB busses clocks
    */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSE;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != 
HAL_OK)
  {
    _Error_Handler(_FILE_, _LINE_);
  }

    /**Configure the Systick interrupt time
    */
  //HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);

    /**Configure the Systick
    */
  HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);

  /* SysTick_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}


Außerdem habe ich noch die Delay-file angehängt.
So wie ich das sehe läuft der Clock ohne PLL mit dem HSE (Quartz) wenn 
ich mich da nicht vertue

über eine Hilfe wäre ich sehr dankbar

das Programm bleibt einfach in der while-schleife beim delay scheinbar 
hängen
Angehängte Dateien:
Gast #5357995
Lesenswert?

Also den Systick Interrupt alle µs aufzurufen ist schon extrem 
sportlich. Das sind normalerweise 1ms oder 10ms normal. Kurze Delays 
solltest du besser ohne Interrupts machen oder wenn die Zeiten genau 
stimmen müssen über einen speziellen Timer.
OP #5358015
Lesenswert?

also du meinst einen extra timer dafür zu verwenden ? ist der 
systick-timer nicht auch einfach nur ein timer ? ich habe mit dem TIM2 
mal n bisschen rum gespielt(hat auch funktioniert, allerdings habe ich 
nicht getestet, wie weit man runter gehen kann), da ich bei stm32 bisher 
noch nicht viel mit timern gemacht hab.

ein Datenbit ist physikalisch 80uS lang( nachgemessen). ganz genau muss 
es vermutlich nicht sein. ich hatte halt gehofft, dass ich das reltiv 
modular hinbekomme (also am besten als lib die man nur noch einbinden 
kann wenn man sie braucht, der uC soll am ende so variable wie möglich 
für evtl. verschiedene Temperatursensoren, ... verwendbar sein
Angehängte Dateien:
Beitrag #5358054 wurde von einem Moderator gelöscht.
#5358094
Lesenswert?

Ich habe mir vor einiger Zeit mal was gebastelt und es funktioniert 
bisher sehr gut. Hier für den STM32F103:
1
//********************** DWT_Delay_us ********************************
2
#define DWT_Korrekturwert 20 
3
uint32_t DWT_Scale;
4
inline static void DWT_Delay_us(uint32_t microseconds) {
5
  uint32_t DWT_Startwert = DWT->CYCCNT;
6
  uint32_t ticks = (microseconds * DWT_Scale) - DWT_Korrekturwert; 
7
  while ((DWT->CYCCNT - DWT_Startwert) < ticks);     
8
}
9
//********************** DWT_Delay_us ********************************
10

11
int main(void)
12
{
13
   //********************** DWT_Delay_us ********************************
14
  DWT_Scale = (HAL_RCC_GetHCLKFreq() / 1000000);   // Berechnung des "Vorteilers", für Takt pro Microsekunde
15
  CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;  // Initialisierung des DWT
16
  DWT->CYCCNT = 0;                  // Initialisierung des DWT-Counter
17
  DWT->CTRL = ENABLE;                // Initialisierung des DWT-Counter
18
  //********************** DWT_Delay_us ********************************
19

20
while (1)  {
21

22
   DWT_Delay(5);
23
}
24
}
Gast #5358107
Lesenswert?

Hochsprache - und ein Delay von wenigen Systemtakten.

Bei ASM ruft man dann (und nur dann) einfach ein paar
Dummy-Befehle (NOP) auf, und schon ist eine µs vergangen.

Die Compiler sind aber mittlerweile so schlau, dass sie Dummy-
Befehle gar nicht ausführen lassen.

Die DWT-Einheit wird wahrscheinlich auch nur was über Laufzeiten
der vom Compiler für sinnvoll erachteten Befehle erzählen
können...

Inline-Assembler mit ein paar Dummy-Befehlen?
Gast #5358120
Lesenswert?

Jacko schrieb:
> Bei ASM ruft man dann (und nur dann) einfach ein paar
> Dummy-Befehle (NOP) auf, und schon ist eine µs vergangen.

Und woher weisst du wieviele NOPs fuer eine usec gebraucht
werden? Das ist nämlich abhängig von der Clock-Konfiguration,
also unterschiedlich für ein und denselben Controller.

Also ein STM32F103 braucht eben nicht 72 Clock-Zyklen für
eine usec weil er mit 72 Mhz getaktet ist.

Musst du für jeden Konfigurations-Fall getrennt herausmessen.
#5358125
Lesenswert?

Viele Wege führen nach Rom, aber von ASM habe ich keine Ahnung.
Die obige Lösung funktioniert bei mir bisher tadellos.

Ich habe mich natürlich verschrieben.
Das Delay wird natürlich so aufgerufen:
1
DWT_Delay_us(5);

Nachgemessen habe ich indem ich einen Pin getoggelt habe. Die Zeiten 
stimmen ziemlich genau.
Natürlich indem ich direkt das BRR und BSRR-Register beschrieben habe.
Verwendet man die HAL-Funktionen zum Pin toggeln, merkt man auf einmal 
wie langsam die sind.
Gast #5358132
Lesenswert?

>spielen. Dabei bin ich darauf gestoßen, dass es bis zu einem Wert von 33
>(x 125nS) noch funktioniert, bei 32 nicht mehr. Dies Wären dann ein
>minmales delay von 4,125uS

Wundert mich nicht. Der Cortex-M3 Core sichert beim Eintritt in einene 
ISR
(Tailchaining, etc. mal außen vor) alle 32 Register in Hardware auf den 
Stack. Das dürften schon 32 Taktzyklen sein. Bei 8 MHz bzw. 125ns
dauert der Context-Switch für einen IRQ schon 32 x 125ns = 4000ns.
Beim Beenden würde dann prinzipiell nochmal soviel anfallen.
Da könnte dann ggf. das Tailchaining greifen, dass es etwas 
"beschleunigt" wird.
OP #5358426
Lesenswert?

Also den DWT kannte ich bisher noch nicht. Ich werde vielleicht erst mal 
kucken ob ich nicht einen der Timer im Input-Capture verwenden kann 
(wenn man sie schon hat).

Mir stellt sich nur die frage ob der Input-Capture-Mode der richtige 
ist. Ich habe da im Reference-Manual auch noch was von External-Trigger 
gelesen. Das gesamtbild wie dies alles zusammenhängt ist mir noch nicht 
ganz klar. ist der ETR ein extra mode/ eingang oder was soll das ganze.

Ich will mir einen Sensorknoten bauen, der über eine weitere serielle 
Schnittstelle mit anderen Sprechen kann(kleiner Linux-Rechner / andere 
uC). Dafür soll der Knoten mit verschiedenen Sensoren arbeiten können 
(was halt grad da ist). Die Abfrage sollen quasi über seriell von 
anderen Stellen kommen, so nach dem Frage-Antwort-Prinzip(die Abfrage 
des Sensors, muss also nicht in einer Endlosschleife immer wieder 
passieren)

Den DWT kann ich mir ja mal anschauen für was der denn überhaupt da ist
Gast #5358446
Lesenswert?

Matthias schrieb:
>>spielen. Dabei bin ich darauf gestoßen, dass es bis zu einem Wert
> von 33
>>(x 125nS) noch funktioniert, bei 32 nicht mehr. Dies Wären dann ein
>>minmales delay von 4,125uS
>
> Wundert mich nicht. Der Cortex-M3 Core sichert beim Eintritt in einene
> ISR
> (Tailchaining, etc. mal außen vor) alle 32 Register in Hardware auf den
> Stack. Das dürften schon 32 Taktzyklen sein. Bei 8 MHz bzw. 125ns
> dauert der Context-Switch für einen IRQ schon 32 x 125ns = 4000ns.


Bullshit. Lies die Doku.
OP #5358498
Lesenswert?

Ich bin eigentlich eher ein Fan von direktem verwenden der CMSIS. Das 
ist das was mir beim AVR früher immer gefallen hat. es war zwar etwas 
mehr einarbeitung erforderlich, aber dabei hat man das soweit verstanden 
wie die Dinge funktionieren.

Bei st geht es eher in die richtung sich alles generieren zu lassen. In 
letzter Zeit befasse ich mich wieder mehr damit direkt die Register zu 
beschreiben wenn möglich.

Vielleicht muss ich mir echt mal ein template-projekt pro stm32-typ 
basteln, dass nur das nötigste (makefile, startup, cmsis, ...) enthält 
und diese mit libs nach und nach erweitern, bei denen ich dann weiß was 
sie tun (und vor allem dass sie tun)
(Firma: keine) #5358581
Lesenswert?

Roland H. schrieb:
> Also den DWT kannte ich bisher noch nicht. Ich werde vielleicht erst mal
> kucken ob ich nicht einen der Timer im Input-Capture verwenden kann
> (wenn man sie schon hat).
>
> Mir stellt sich nur die frage ob der Input-Capture-Mode der richtige
> ist. Ich habe da im Reference-Manual auch noch was von External-Trigger
> gelesen. Das gesamtbild wie dies alles zusammenhängt ist mir noch nicht
> ganz klar. ist der ETR ein extra mode/ eingang oder was soll das ganze.
>
> Ich will mir einen Sensorknoten bauen, der über eine weitere serielle
> Schnittstelle mit anderen Sprechen kann(kleiner Linux-Rechner / andere
> uC). Dafür soll der Knoten mit verschiedenen Sensoren arbeiten können
> (was halt grad da ist). Die Abfrage sollen quasi über seriell von
> anderen Stellen kommen, so nach dem Frage-Antwort-Prinzip(die Abfrage
> des Sensors, muss also nicht in einer Endlosschleife immer wieder
> passieren)
>
> Den DWT kann ich mir ja mal anschauen für was der denn überhaupt da ist

Hallo,

die DWT (Data Watchpoint and Trace Unit) ist im ARM Cortex Reference 
Manual dokumentiert.

Wie der Name schon impliziert, ist es eigentlich ein Submodul des Cortex 
Kerns, dass zum Debuggen und nicht zum normalen Programmablauf genutzt 
wird. Der Cycle Counter ist dazu da, einen Watchpoint nach einer 
programmierbaren Anzahl von Zyklen nach Auftreten eines Events (z.B. 
schreibenden oder lesenden Zugriffs auf eine definierbare 
Speicherstelle) auszulösen.

Der Cycle Counter ist allerdings der am feinsten granuliebare Timer, den 
der Kern bietet (genauer als auf Einzelzyklenbasis geht's nicht), 
weswegen er auch gerne zu Allen möglichen Anderen Zwecken genutzt wird.

Eines der Dinge, die man bei der Nutzung im Auge behalten muss ist dass 
der Cycle Counter von vielen IDEs und Debuggern genutzt und zuweilen auf 
0 gesetzt wird (um Time Stamp Deltas bilden zu können). Also nicht 
wundern, wenn sich ein Programm, das den DWT Cycle Counter nutzt, unter 
Debuggerkontrolle plötzlich Anders verhält als im Normalbetrieb!
Gast #5358637
Lesenswert?

Ruediger A. schrieb:
> Eines der Dinge, die man bei der Nutzung im Auge behalten muss ist dass
> der Cycle Counter von vielen IDEs und Debuggern genutzt und zuweilen auf
> 0 gesetzt wird

Genau das sollte gelinde gesagt eben niemand tun, so wie es
viele andere ungeschriebene Regeln gibt. Was sollte es auch
für einen triftigen Grund geben gerade diesen Zähler auf Null
zu setzen? Kann mann ihn doch durch einfache Differenzbildung
zum Auswerten für seine "eigenen Zwecke" nutzen.

Auch ein Debugger sollte das schaffen. Der ST-Link z.B. verhält
sich diesbezüglich korrekt, der J-Link (denke ich, gerade nicht
überprüft) auch.
(Firma: keine) #5358714
Lesenswert?

STM Apprentice schrieb:
> Ruediger A. schrieb:
>> Eines der Dinge, die man bei der Nutzung im Auge behalten muss ist dass
>> der Cycle Counter von vielen IDEs und Debuggern genutzt und zuweilen auf
>> 0 gesetzt wird
>
> Genau das sollte gelinde gesagt eben niemand tun, so wie es
> viele andere ungeschriebene Regeln gibt. Was sollte es auch
> für einen triftigen Grund geben gerade diesen Zähler auf Null
> zu setzen? Kann mann ihn doch durch einfache Differenzbildung
> zum Auswerten für seine "eigenen Zwecke" nutzen.
>

Ja, wäre schön, wenn sich Alle daran hielten würden... leider aber hat 
sich auch in "seriösen" Kreisen die Folklore eingebürgert, von 0 aus zum 
Sollwert hochzuzählen, z.B. hier:

http://embeddedb.blogspot.de/2013/10/how-to-count-cycles-on-arm-cortex-m.html
https://stackoverflow.com/questions/36378280/stm32-how-to-enable-dwt-cycle-counter

mglw. auch mit dem Gedanken im Hinterkopf, dass sich damit auch der 
statistisch recht unwahrscheinliche aber mögliche Fall des wraparound 
praktisch elimineren lässt. Ich stimme aber mit Dir darin überein, dass 
sampling on the fly und Deltabildung die bessere Variante ist (zumal die 
Anzahl Zyklen zwischen faktischem Nullsetzen und Anfang des zu 
samplenden Codes auch zwischen Compilern und Optimierungsstufen variabel 
ist und damit das Ergebnis mglw. verfälscht).

> Auch ein Debugger sollte das schaffen. Der ST-Link z.B. verhält
> sich diesbezüglich korrekt, der J-Link (denke ich, gerade nicht
> überprüft) auch.

Ich schrieb von Debuggern, nicht debug probes... Je nach 
"Eigenintelligenz" leiten die probes die Registerzugriffe der Debugger 
mehr oder weniger 1:1 vom Debugger zum Target durch. M.W. nach (könnte 
da aber falsch liegen) hat der ST Link so gut wie keine autarke 
Registersteuerung.
#5358726
Lesenswert?

Ist es denn wirklich notwendig, für irgendwelche simplen µs-Delays 
dermaßen in die "Trickkiste" zu greifen und die Debug-Resourcen 
anzuknabbern?
Der Controller hat ja nun wirklich auch ein paar "normale" Timer, die 
das problemlos leisten können. Da scheint es mir schon zweifelhaft, 
sowas wie die Nutzung des DWTs dafür hier Anfängern quasi als 
"Musterlösung" zu präsentieren...
OP #5358752
Lesenswert?

Thomas E. schrieb:
> Ist es denn wirklich notwendig, für irgendwelche simplen µs-Delays
> dermaßen in die "Trickkiste" zu greifen und die Debug-Resourcen
> anzuknabbern?
> Der Controller hat ja nun wirklich auch ein paar "normale" Timer, die
> das problemlos leisten können. Da scheint es mir schon zweifelhaft,
> sowas wie die Nutzung des DWTs dafür hier Anfängern quasi als
> "Musterlösung" zu präsentieren...
Das wäre auch immer noch die Lösung die ich aktuell im Auge habe. Ich 
habe doch ein paar Timer. Wozu diese also nicht mal benutzen.
#5358875
Lesenswert?

1.
Es scheint mir der DWT-Counter wird vom Debugger gestartet und wenn kein 
Debugger verwendet wird läuft der DWT-Counter garnicht.
Das schließe ich daraus, dass ich den DWT-Counter einmalig von Hand 
anwerfen muss. Sonst funktioniert die DWT_Delay_us-Funktion nur wenn der 
Debugger angeschlossen ist.

2.
Auch erscheint es mir sinnvoll den DWT-Counter nicht zu manipulieren 
(auf 0 setzten), sondern nur zu lesen und das Delay durch 
Differenzbildung zu realisieren.

3.
Interrupts von wenigen Takten machen nur Probleme.

4.
Eine vorgegebene Taktanzahl in einer Schleife zu vertrödeln mag ich aus 
folgenden Gründen nicht:
-Delay ändert sich bei Änderung des uC-Taktes
-Delay ändert sich je nach Optimierungsgrad

Darum verwende ich das DWT-Counter-Dalay solange ich keine bessere 
Lösung kenne:
Ich benutze einen (ansonsten ungenutzten?) geeigneten Counter den ich 
nicht einmal manipuliere, sondern nur lese.
Es werden keine problematischen Interrupts gebraucht und ich muss mir 
keine Gedanken um Optimierungslevel und Taktfrequenz machen. Ich 
"verbaue" mir keinen Timer, den ich vielleicht doch nochmal brauche.
Und es ist mit 2 copy und paste-Aktionen implementiert.


Roland möchte es gerne mit einer anderen Lösung versuchen.
Ich nutze in Zukunft auch gerne eine andere, "bessere" Lösung.

Dazu müssten aber auch Lösungsvorschläge kommen.

Ein: "...das kannst du so nicht machen, weil..."
ist ja gerechtfertigt und auch gewünscht.
Aber dann sollte folgendes kommen:
"... mach es lieber so, weil..."

Und dieses "... mach es lieber so, weil..."
vermisse ich leider immer öfter.

Ich freue mich auf Lösungs/Verbesserungsvorschläge.

Gruß Daniel
#5358899
Lesenswert?

Roland H. schrieb:
> Der Input Capture mode nütz mir aber auch nichts wenn ich nur von
> steigender zu steigender flanke messen kann.

Doch. Man kann ja z.B. die Flanke nach jedem Capture Interrupt toggeln.
Oder eleganter: Den "PWM input mode" nehmen. Im Reference Manual Kapitel 
15.3.6, bzw. 14.3.7.

Wenn auf fallende Flanke getriggert wird, bekommt man im CCR1 der 
Zählerwert für die gesamte Bitlänge, und im CCR2 für die Low-Phase. Die 
High-Phase ist dann die Differenz (CCR1-CCR2).

Die Timerwerte können auch per DMA im RAM abgelegt werden und erst nach 
der kompletten Übertragung ausgewertet werden.
#5359177
Lesenswert?

Daniel B. schrieb:
> Ich benutze einen (ansonsten ungenutzten?) geeigneten Counter den ich
> nicht einmal manipuliere, sondern nur lese.

Eben, das Fragezeichen setzt Du ja schon selbst - ich würde mal 
vorsichtshalber davon ausgehen, daß der Timer evtl. beim Debuggen 
verwendet und u.U. auch vom Debugger gelöscht werden könnte.

Daniel B. schrieb:
> Es werden keine problematischen Interrupts gebraucht und ich muss mir
> keine Gedanken um Optimierungslevel und Taktfrequenz machen.

Muss man bei einem TIMx auch nicht.

Daniel B. schrieb:
> Ich
> "verbaue" mir keinen Timer, den ich vielleicht doch nochmal brauche.
> Und es ist mit 2 copy und paste-Aktionen implementiert.

"Verbaut" ist der Timer ja auch nicht. Die 4 CC-Units kann man ja für 
andere Zwecke benutzen. Meist hat man ja sowieso mindestens einen frei 
durchlaufenden Timer in Benutzung, den man dann für ein µs-Delay einfach 
mitverwendet. Wenn der (16-bit)Timer zufällig eh auf 1 MHz Takt nach 
Prescaler eingestellt ist, ist usDelay dann einfach:
1
void usDelay (uint16_t us)
2
{
3
  uint16_t temp = TIMx->CNT + us;
4
  while((TIMx->CNT - temp) & 0x8000);
5
}

P.S.: wenn ich das richtig sehe, hat Deine Funktion oben übrigens ein 
Problem mit Timer-Überlauf...
#5359422
Lesenswert?

Thomas E. schrieb:
> daß der Timer evtl. beim Debuggen
> verwendet und u.U. auch vom Debugger gelöscht werden könnte.

Kann schon sein. Aber stört das beim debuggen?


Thomas E. schrieb:
> P.S.: wenn ich das richtig sehe, hat Deine Funktion oben übrigens ein
> Problem mit Timer-Überlauf...

Das sehe ich genauso.
Seit zwei Wochen frage ich sekündlich zwei DS18B20 ab und gebe die Werte 
auf ein HD44780.
In beiden Routinen wird das DWT_Delay benutzt wird. Mich wundert auch 
ein wenig, dass ich noch keine einzige Fehlmessung hatte.


Es ist nicht MEINE Lösung.
Es ist nicht mal meine eigene Geistesleistung, den DWT-Counter für sowas 
zu verwenden.

Roland hat nach einer Lösung gesucht und ich habe ihm gesagt, wie es bei 
mir funktioniert.
Wenn er will kann er es verwenden bis er was Besseres gefunden hat.

Ich bin kein Profi, deswegen freue ich mich über jede lehrreiche und 
produktive Diskussion in der die Vor-/Nachteile der unterschiedlichen 
Delays zur Sprache kommen.

Ich probiere dein Timer-Delay auch aus, vielleicht wird es mein neues 
Standard-Delay :-)

Gruß Daniel
Gast #5359448
Lesenswert?

STM Apprentice (Gast) fragte:
> Und woher weisst du wieviele NOPs fuer eine usec gebraucht
> werden? Das ist nämlich abhängig von der Clock-Konfiguration,
> also unterschiedlich für ein und denselben Controller.

1) Der TO hat doch eindeutig 8 MHz geschrieben.
   1 NOP pro Systemtakt - wirst du wohl selber ausrechnen können...

2) Es gibt bedingte Kompilierung, da wird die Prozessor-Taktrate
   bekannt gegeben (davon lebt auch der Standard-Delay-Timer) und
   dann werden die NOPs in 2er-Potenzschritten (oder feiner)
   zugeteilt. Was 1 µs Delay braucht, funktioniert meist auch
   mit 2, aber bestimmt mit 1,4 µs Delay...
   - Genauer wird es bei < 20 MHz auch auf andere Weise nicht,
     wenn noch etwas Zeit für das eigentliche Programm gebraucht
     wird.
Gast #5359491
Lesenswert?

Nimm das und glücklich sein. 1 Mal Init nach SysInit auf dem BPB und es 
läuft, auch mit Debugger
1
#pragma GCC push_options
2
#pragma GCC optimize ("O3")
3
void delayUS_DWT(uint32_t us)
4
{
5
  uint32_t cycles = (SystemCoreClock/1000000L)*us;
6

7
  __disable_irq();
8
  volatile uint32_t start = DWT->CYCCNT;
9
  do  {
10
  } while(DWT->CYCCNT - start < cycles);
11

12
  __enable_irq();
13
}
14
#pragma GCC pop_options
15

16
#pragma GCC push_options
17
#pragma GCC optimize ("O0")
18
uint32_t DWT_Delay_Init(void) {
19
  /* Disable TRC */
20
  CoreDebug->DEMCR &= ~CoreDebug_DEMCR_TRCENA_Msk; // ~0x01000000;
21
  /* Enable TRC */
22
  CoreDebug->DEMCR |=  CoreDebug_DEMCR_TRCENA_Msk; // 0x01000000;
23

24
  /* Disable clock cycle counter */
25
  DWT->CTRL &= ~DWT_CTRL_CYCCNTENA_Msk; //~0x00000001;
26
  /* Enable  clock cycle counter */
27
  DWT->CTRL |=  DWT_CTRL_CYCCNTENA_Msk; //0x00000001;
28

29
  /* Reset the clock cycle counter value */
30
  DWT->CYCCNT = 0;
31

32
     /* 3 NO OPERATION instructions */
33
     __ASM volatile ("NOP");
34
     __ASM volatile ("NOP");
35
     __ASM volatile ("NOP");
36

37
  /* Check if clock cycle counter has started */
38
     if(DWT->CYCCNT)
39
       return 0; /*clock cycle counter started*/
40
     else
41
       return 1; /*clock cycle counter not started*/
42
}
43
#pragma GCC pop_options
Gast #5360741
Lesenswert?

>Matthias schrieb:
>>>spielen. Dabei bin ich darauf gestoßen, dass es bis zu einem Wert
>> von 33
>>>(x 125nS) noch funktioniert, bei 32 nicht mehr. Dies Wären dann ein
>>>minmales delay von 4,125uS
>>
>> Wundert mich nicht. Der Cortex-M3 Core sichert beim Eintritt in einene
>> ISR
>> (Tailchaining, etc. mal außen vor) alle 32 Register in Hardware auf den
>> Stack. Das dürften schon 32 Taktzyklen sein. Bei 8 MHz bzw. 125ns
>> dauert der Context-Switch für einen IRQ schon 32 x 125ns = 4000ns.

>Bullshit. Lies die Doku.
Wenn Du es schon "besser" weißt, dann hättest Du ja auch gleich die 
korrekten Latenzdaten schreiben können, statt dem Blödsinn.

Dann sind es halt nur 12 Zyklen beim Eintritt und nicht alle 32 Register 
+
nochmal 12 Zyklen beim Verlassen des IRQ Kontext. Macht in Summe 
trotzdem
noch satte 24 Zyklen bzw. 3000ns allein für den Context-Switch.
Dazu kommen noch ein paar Zyklen für den ISR-Code. Damit sollte klar 
sein,
warum er nicht unter die beobachteten 4us kommt.
Gast #6742519
Lesenswert?

Der Thread ist zwar schon alt, trotzdem hole ich das hier nochmal hoch. 
Leider stimmt die Aussage nicht, dass das DWT-Delay mit dem jlink 
problemlos ist. Zumindestens nicht in Verbindung mit Segger Embedded 
Studio.
Beim Initialisieren des DWT wird folgendes gemacht:
1
  /* Enable TRC */
2
  CoreDebug->DEMCR |=  CoreDebug_DEMCR_TRCENA_Msk;
Wenn sich jlink connected kommt das System nicht durcheinander, blöd ist 
nur dass genau dieses Bit vom jlink (oder der Segger IDE) beim 
Deconnecten zurück setzt. Damit hängt das Programm in der nächsten 
Delay-Schleife fest.
Ich habe leider noch nicht rausgekriegt ob und wie man das abschalten 
kann und wäre über einen Tip dankbar.
(Firma: keine) #6742568
Lesenswert?

Naja, wie schon mehrmals hier erwähnt wurde, ist die Nutzung des DWT als 
"normaler" Timer etwas fragwürdig. DWT heißt Data Watchpoint and Trace 
und ist eigentlich ein fürs Debugging dediziertes Modul.

Es läßt sich wirklich jeder Cortex M Timer dafür verwenden, einen 
Zyklengenauen Zähler und Verzögerer zu implementieren. Dazu muß der 
Timer nur als freilaufend konfiguriert und periodisch der Zählerstand 
abgefragt werden. Es muss nicht die DWT sein, die wird im Zusammenhang 
mit aktiven Debuggern mit hoher Wahrscheinlichkeit Probleme bereiten.
Gast #6742592
Lesenswert?

Ruediger A. schrieb:
> Naja, wie schon mehrmals hier erwähnt wurde, ist die Nutzung des DWT als
> "normaler" Timer etwas fragwürdig. DWT heißt Data Watchpoint and Trace
> und ist eigentlich ein fürs Debugging dediziertes Modul.

Das ist mir klar, und darum ging es nicht bei meiner Frage/Feststellung

Ruediger A. schrieb:
> Es läßt sich wirklich jeder Cortex M Timer dafür verwenden

nur leider hat der STM32F103 nicht einen einzigen der 32bit breit ist.
Ja, es gibt sicher andere Lösungen die kompatibler sind. Das brauche ich 
allerdings nicht und wechsele auch nicht ständig die IDE. Also kann ich 
gut damit leben und helfe mir so:
1
void delay_dwt(const uint32_t ticks) 
2
{
3
  uint32_t start = DWT_CYCCNT;
4
  while((DWT_CYCCNT - start) < ticks)
5
    {    
6
    SCB_DEMCR |= 0x01000000;
7
    }
8
}
Gast #6742602
Lesenswert?

temp schrieb:
> und helfe mir so:

Dauernd auf das SCB_DEMCR-Register ballern?

Und dann noch mit Magic Numbers, sodass jeder erst in den
Magic Documents nachschauen muss was du da machst?

Dein Read-Modify-Write braucht ein "paar Taktzyklen" die
das ganze µs-Timen ungenauer machen.
Gast #6742867
Lesenswert?

STM Apprentice schrieb:
> Dauernd auf das SCB_DEMCR-Register ballern?
>
> Und dann noch mit Magic Numbers, sodass jeder erst in den
> Magic Documents nachschauen muss was du da machst?
>
> Dein Read-Modify-Write braucht ein "paar Taktzyklen" die
> das ganze µs-Timen ungenauer machen.

Es schaut hier nur einer rein und das bin ich. Ich habe hier niemanden 
etwas aufdrängeln wollen. Die Entscheidung ob die paar Taktzyklen etwas 
ungenauer machen oder nicht kannst du auch mir überlassen. Also was soll 
dein Genöle? Die die's interessiert werden da raus nehmen können was 
wichtig ist. Ich präsentiere hier auch keine Lib die man ungeprüft in 
ein Arduino Dumpfbacken Projekt kopiert. Also troll dich und mach deinen 
eigenen Kram anstelle hier den Oberlehrer zu spielen.
#6742879
Lesenswert?

temp schrieb:
> nur leider hat der STM32F103 nicht einen einzigen der 32bit breit ist.

Wenn Du eh die Zeit verwartest, dann reicht ein 16Bit-Timer dicke und 
den höherwertigen Teil erledigt eine profane Zählschleife drumrum.

Abgesehen davon treiben solche elend langen Delays die CPU-Performance 
in den tiefsten Keller, d.h. Dein 32Bit-Bolide wird von jedem 8Bitter um 
Längen geschlagen.

Der Systick Timer des F103 hat immerhin 24Bit.
#6742887
Lesenswert?

temp schrieb:
> Die Entscheidung ob die paar Taktzyklen etwas ungenauer machen oder
> nicht kannst du auch mir überlassen. Also was soll dein Genöle? Die
> die's interessiert werden da raus nehmen können was wichtig ist

Weshalb gleich so pampig?
Der Hinweis auf diese Ungenauigkeit war sicher nicht bös gemeint und 
würde Anfängern, die das nicht sofort durchschauen, ja durchaus helfen.
Gast #6743011
Lesenswert?

900ss D. schrieb:
> Weshalb gleich so pampig?
> Der Hinweis auf diese Ungenauigkeit war sicher nicht bös gemeint und
> würde Anfängern, die das nicht sofort durchschauen, ja durchaus helfen.

Es ging mir nicht darum Delays zu implementieren, sondern darum auf die 
Problematik mit dem SCB_DEMCR, jlink und der Segger IDE hinzuweisen.

Peter D. schrieb:
> Dein 32Bit-Bolide wird von jedem 8Bitter um
> Längen geschlagen.

Na dann werde ich wohl auf 8Bitter umstellen wenn die den Vorteil haben 
bei einem 1000µs Delay in 100µs fertig zu sein...

Peter D. schrieb:
> Der Systick Timer des F103 hat immerhin 24Bit.

Der wird aber in der Regel immer verwendet und läuft auch nicht durch.

Peter D. schrieb:
> Wenn Du eh die Zeit verwartest, dann reicht ein 16Bit-Timer dicke und
> den höherwertigen Teil erledigt eine profane Zählschleife drumrum.

Ich kniee ehrfürchtig vor dem Meister nieder für diesen Tip. Auf diese 
Idee wäre außer dir sicher niemand gekommen.

Den freilaufenden 32bit DWT verwende ich als einzigen 32bit Zähler im 
stm32f103 auch für andere Zwecke, ein 16bit Register ist hier kein 
Ersatz.
Alle anderen Cortexe die ich verwende haben wenigstens einen 32bit 
Timer, da verwende ich den. Also was sollen die Belehrungen? Es gibt 
immer viele Lösungen für ein Problem, ich drängle niemanden meine auf 
erwarte aber, dass das umgekehrt auch keiner Macht.

900ss D. schrieb:
> Weshalb gleich so pampig?
> Der Hinweis auf diese Ungenauigkeit war sicher nicht bös gemeint und
> würde Anfängern, die das nicht sofort durchschauen, ja durchaus helfen.

Weil ich Oberlehrer nicht ausstehen kann. Anfänger, die nicht mal raffen 
dass ein paar Befehle in einer Schleife die Ausführung verlängern 
sollten stricken oder häkeln. Diese Arroganz an dieser Stelle erlaube 
ich mir.
#6743460
Lesenswert?

temp schrieb:
> Peter D. schrieb:
>> Der Systick Timer des F103 hat immerhin 24Bit.
>
> Der wird aber in der Regel immer verwendet und läuft auch nicht durch.

Meistens steht ein krummer Wert im reload-Register, deshalb muss man den 
"Überlauf" extra behandeln. Oder bedeutet "läuft nicht durch" noch was 
schlimmeres?

Und vielen Dank für den Tipp mit dem Debugger!
Gast #6743508
Lesenswert?

Peter D. schrieb:
> Und das sagt ausgerechnet der Oberlehrer vom Dienst.
> Ich wußte nicht, daß Du nen uralten Thread ausgräbst, nur um andere zu
> beleidigen. Dann hätte ich mir meinen Beitrag natürlich verkniffen.
> Belehre bitte andere.

Nein, die Belehrung bei dir ist mehr als angebracht. Lies meinen ersten 
Beitrag und du wirst merken, dass es überhaupt nicht um Delay-Schleifen 
ging, sondern um die Manipulation des DEMCR Registers durch jlink beim 
Deconnecten.
Nicht mehr und nicht weniger. Alles andere kam erst durch die 
versammelte Delayexpertenexpertiese.

Und dann kommen solche Trollos wie du daher und wollen erklären wie man 
Delays programmiert. Und nein, ich belehre dich nicht wie du das machst. 
Du kannst machen was du willst. Aber hör bitte auf anderen deinen 
Programmierstil aufzuschwatzen.

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