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
:
Bearbeitet durch User
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.
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
Da müssen aber nur die Bitlängen gemessen werden, das geht mit Timer Capture oder einem frei laufenden Timer und bei Pegelwechsel liest man den Zählerstand und bildet die Differenz.
Beitrag #5358054 wurde vom Autor gelöscht.
temp schrieb: > Also den Systick Interrupt alle µs aufzurufen ist schon extrem > sportlich. Jawoll, das ist grob gesprochen Mist. Ist doch alles da, man braucht nur danach suchen: https://www.mikrocontroller.net/articles/STM32_f%C3%BCr_Einsteiger#Taktzeitberechnung_und_.C3.9Cberwachung Gibt es auch beim STM32F103.
Ich müsste also einen timer im Input Capture-Mode verwenden, der bei jedem flankenwechsel die zeit misst. allerdings müsste ich dann zu jeder messung wissen ob 1 oder 0
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 | }
|
:
Bearbeitet durch User
Daniel B. schrieb: > Hier für den STM32F103: Man muss in DWT_Delay_us (...) noch die Interrupts global disablen sonst gibts manchmal pöhse Delay-Verschiebungen.
Danke für den Tipp, werde ich noch einbauen. Bisher hatte ich immer Glück :-)
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?
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.
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.
:
Bearbeitet durch User
>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.
Daniel B. schrieb: > Verwendet man die HAL-Funktionen zum Pin toggeln ... ... dann braucht man auch keine delay_us-Funktion mehr. SCNR
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
:
Bearbeitet durch User
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.
Die ARM kehren bei hoher Interruptlast nicht mehr zum Main zurück, das Main stoppt quasi. Im Unterschied zu den 8051 oder AVR, wo nach jedem RETI mindestens ein Befehl des Main ausgeführt wird.
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)
:
Bearbeitet durch User
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!
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.
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.
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...
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.
Der Input Capture mode nütz mir aber auch nichts wenn ich nur von steigender zu steigender flanke messen kann. Das entsprechende kapitel/register hab ich im Reference-Manual leider noch nicht gefunden
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
:
Bearbeitet durch User
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.
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...
:
Bearbeitet durch User
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
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.
Jacko schrieb: > Der TO hat doch eindeutig 8 MHz geschrieben. ...und das es um einen STM32F103 geht, per PLL macht der da bis 72 MHz raus. Timer mit 1us einrichten, Interrupt nach 40 us auslösen. Zum Sensor lesen bei Pegelwechsel den us Timer lesen.
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
|
>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.
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.
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.
:
Bearbeitet durch User
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 | }
|
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.
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.
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.
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.
:
Bearbeitet durch User
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.
temp schrieb: > Weil ich Oberlehrer nicht ausstehen kann. 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.
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!
:
Bearbeitet durch User
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.
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.