Hi,
ich benutze die coocox ide 1.7.5 um mit dem STM32F4Discovery board zu
basteln,
jetzt bin ich an einem Punkt wo ich gerne feststellen möchte wie lange
ein bestimmer codeabschnitt für die Ausführung braucht.
Ich habe das ganze jetzt einfach mit Timer1 als up counter mit prescaler
1 und period 1 gemacht damit sollte dieser doch mit dem
Systemtakt(168MHz laufen), vor dem zu beobachtendem code den timer
gestartet und nach dem code den counter wert geholt.
Dieser Wert ist aber immer 0.
Das kann nicht richtig sein denn dieser code sollte ausgeführt werden:
der sollte doch schon ein paar systemtakte dauern.
Als ich Timer2 ausprobiert habe, habe ich ihn auch mal auf 1 Sekunde
eingestellt (prescaler = 42000-1; period = 2000-1;) da war timerValue
dann 303... alles sehr komisch. Bei prescaler = 1 und period = 1 war der
Wert dann wieder 0.
Die timer funktionieren wohl (LED mit timer blinken lassen etc.
funktioniert)
Ich habe debug auf RAM gestellt damit nicht immer der flash geschrieben
werden muss.
btw. habe ich die Frage auch schon unter der Rubrik PC Hard- & Software
gestellt, aber da gehört sie wohl nicht so wirklich rein.
Werden die for Schleifen evtl. vom compiler doch wegoptimiert obwohl
Optimierung aus gestellt ist?
Im Wiki steht wie man Takte mit dem SysTick Timer zählt:
http://www.mikrocontroller.net/articles/STM32_f%C3%BCr_Einsteiger#Taktzeitberechnung_und_.C3.9Cberwachung
Zeig doch mal ein vollständiges Beispiel, d.h. ein kompletter
kompilierbarer Code der das bemängelte Verhalten zeigt und so kurz wie
möglich ist. Insbesondere dem Wichtigsten überhaupt, der
Timer-Initialisierung!
Paul schrieb:> Werden die for Schleifen evtl. vom compiler doch wegoptimiert obwohl> Optimierung aus gestellt ist?
Nein, diese Art Schleife wird wohl nie wegoptimiert. Außerdem bewirkt
die Optimierung kleine Wunder, daher sollte man die außer zu
Debug-Zwecken schon auch verwenden...
habs nun auch mit dem CORE_SysTick sachen aus der wiki probiert, der
Wert ist auch 0 und wenn sich DWT_CYCCNT an Speicheradresse 0xE0001004
befindet dann ist es auch 0 :(
Moin Paul,
ich habe momentan leider keinen Beispielcode zur Hand, mit dem ich dir
Zeigen kann wie es geht. Ich glaube aber eine deiner Aussagen ist
falsch.
Paul schrieb:> Ich habe das ganze jetzt einfach mit Timer1 als up counter mit prescaler> 1 und period 1 gemacht damit sollte dieser doch mit dem> Systemtakt(168MHz laufen),
Wenn ich mich recht erinnere laeuft kein Timer der STM32F4 Serie mit 168
MHz. Auch sehe ich keinen Aufruf fuer das SystemInit, welches die
Taktung im System einrichtet (kann aber auch im Startup Code liegen).
Schau dir am Besten mal folgendes Excel Tool an:
http://www.st.com/web/en/catalog/tools/PF257927#
Mit diesem Tool kann Taktung konfigurieren und auch sehen, an welchen
Stellen welcher Takt tatsaechlich anliegt (laut Tool fuer Timer 1
maximal 84 MHz). Auch solltest du ueberpruefen ob im "stm32f4xx.h"
Header die Quarzfrequenz wirklich mit 25 MHz angegeben ist und nicht mit
8 MHz (haeufiger Fehler).
Paul schrieb:> TIM_InitStruct.TIM_Period = 1;
Du lässt den Timer von 0-1 zählen und dann wieder bei 0 starten. Kein
Wunder dass das nicht so ganz klappt.
Michi schrieb:> Zuvor standen auch die (richtigen) DWT register Adressen im wiki.
Oh... Ich hatte den Code dort "korrigiert", weil er hässlich war und im
Text "SysTick" stand, aber die Adressen auf die DWT verwiesen. Habe es
jetzt wieder auf DWT unter Verwendung der CMSIS geändert und im Text
SysTick durch DWT ersetzt. Jetzt müsste es das gleiche tun wie der
Original-Code...
Arne Maximilian R. schrieb:
> Schau dir am Besten mal folgendes Excel Tool an:> http://www.st.com/web/en/catalog/tools/PF257927#
das habe ich benutzt um die Werte für HSE_VALUE (uint32_t)8000000 und
PLL_M 8
einzustellen, die Werte für die Timer stimmten schon überein und laut
dem sheet läuft dann timer 1 mit den 168MHz.
Das Problem ist wohl wirklich die Period. Hab sie auf 100 gesetzt und
schon hatte timerValue einen Wert von 87. Anscheinend hab ich diesen
Paramter nicht wirklich verstanden. Auf was müsste man den denn
einstellen damit wirklich der counter so schnell wie nur eben möglich
läuft und man dann wirklich sagen kann wenn z.B. timerValue = 100 ist
dann hat die Ausführung (100 * 5,9ns) gedauert.
> Ich habe debug auf RAM gestellt damit nicht immer der flash geschrieben> werden muss.
Auch alle anderen Einstellungen gemacht damit die Ausführung aus dem RAM
nicht schiefgeht ?
Laß das Prog doch mal testweise aus dem Flash laufen.
Uwe schrieb:> Auch alle anderen Einstellungen gemacht damit die Ausführung aus dem RAM> nicht schiefgeht ?> Laß das Prog doch mal testweise aus dem Flash laufen.
... was gäbe es denn da sonst noch für Einstellungen?
Mit Debug in RAM in der Projekt configuration wurde alles automatisch
gesetzt, denke die Ausführung funktioniert schon, da nach einem reset
des boards das original (LED blink und accelerometer test) Programm
wieder läuft.
Schätze es ist wohl einfach ein Denkfehler von mir, muss mir die Sache
mit den Timern nochmal vernünftig anschauen. Ich benutz da warscheinlich
etwas falsch.
...habe grad mal etwas ausprobiert...
TIM_Period auf 168 gesetzt.
timerValue war nach der Ausführung der for Schleifen dann 29.
Bedeutet das nun die Ausführung hat : 29 * (1 / (168000000 / 168))s also
29 mikrosekunden gedauert? Oder liege ich da immer noch falsch?
@Paul
Hier ist beschrieben wie man den Clock auf 168MHz einstellt:
http://www.mikrocontroller.net/articles/STM32_CooCox_Installation#Clock_auf_168MHz_einstellen
Wenn man SystemInit(); nicht aufruft wird der STM32F4xx mit dem internen
HSI von 16MHz laufen. CooCox initialisiert den Clock nicht alleine.
Mit RCC_GetClocksFreq() kann man erfahren wie schnell die einzelnen
Teile laufen, vorausgesetzt in der stm32f4xx.h wurde der Wert von
HSE_VALUE korrekt definiert.
Du kannst auch das MCO1 Signal so parametrieren, dass der CPU Takt auf
einem Port-Pin ausgegeben wird und dann messen ob das passt. Bei 168MHz
musst Du den MCO1-Clock noch mindestens durch 4 Teilen, damit das auch
gut messbar ist, somit müsste 42MHz zu messen sein wenn die CPU mit
168MHz läuft.
Markus Müller schrieb:> Hier ist beschrieben wie man den Clock auf 168MHz einstellt:> http://www.mikrocontroller.net/articles/STM32_CooCox_Installation#Clock_auf_168MHz_einstellen
habe ich alles so gemacht, SystemInit(); wird auch im default reset
handler aufgerufen.
Ich gehe davon aus das alles soweit stimmt, ich bin mir halt nur nich
wirklich sicher ob meine Annahme über den TIM_Period Parameter und meine
Rechnung stimmt.
Ansonsten dürfte da sonst kein Fehler mehr drin sein.
Der TIM1 läuft mit 84MHz, weil der Bus APB2 nicht mehr kann und der
Teiler von der CPU Frequenz in SystemInit(); auf DIV 2 eingestellt
wurde. (Wenn der doch mit 168MHz laufen sollte wird der Fehlerhaft
arbeiten.)
TIM_InitStruct.TIM_Prescaler = 1; macht nochmal DIV 2
Somit zählt der Zähler mit 42MHz
Rufe mal RCC_GetClocksFreq(), dann siehst Du die Frequenzen der
einzelnen Busse.
... ich hab mal das excel sheet mit meinen Einstellungen drin angehängt,
die Einstellungen habe ich wie hier :
http://myembeddedtutorial.blogspot.de/2013/06/working-with-stm32f4-timers.html
und hier :
http://blog.stm32f4.eu/development-chain/setting-up-coocox/
beschrieben gemacht.
Das sollte schon stimmen, aber
ich denke ich habe es raus:
gehen wir davon aus das board läuft mit 168 MHz
Timer 1:
TIM_Prescaler = 0;
TIM_Period = 100;
dann ist timerValue nach den for - Schleifen = 68.
Ausführung dauert:
(1 / (168000000 / 100))s * 68
=
0,00000059s * 68 = 0,00004046s = 40,46µs
Paul schrieb:> TIM_Period = 100;
Im Upcounting Mode läuft der Timer immer von 0 bis "TIM_Period" und
fängt dann wieder bei 0 an; du solltest das also schlauerweise auf was
möglichst hohes setzen (max. 2^16-1 bei 16bit-Timern wie dem TIM1) damit
der Timer möglichst weit zählt bevor er wieder bei 0 anfängt! Und eben
dafür sorgen dass er mit 168MHz zählt, damit er alle Core-Takte zählt.
Alternativ kannst du auch einen der 32bit-Timer (wie TIM2) nehmen und
Period auf 2^32-1 setzen, damit du "wirklich" weit zählen kannst (2^16
Takte sind ja jetzt nicht soo viel).
Der Timer 1 kann nicht mit 168MHz zählen, nur mit 84MHz. Siehe hier:
http://www.mikrocontroller.net/wikifiles/3/33/STM32F407.png
Die maximale Frequenz der Timer ist begrenzt durch den jeweiligen Bus
Takt, an dem der Timer angeschlossen ist (APB1/APB2).
Wenn man schneller zählen will muss man die Core eigenen Timer nutzen,
wie z.B. den Systick oder DWT (wie schon oben gezeigt).
Wobei der Systick in der Regel für das erzeugen eines 1ms System-Taktes
genutzt wird und für die Zyklus-Zeitmessung eher nicht missbraucht
werden sollte.
Geht leider nicht anders. Eine Zeitmessung ist mit den TIMx Timer der
Periphere natürlich möglich - jedoch nicht mit 168MHz.
Wenn schon ein Timer, dann am besten den TIM6 oder TIM7 verwenden, denn
die sind nur interne Timer ohne Port Anschluss.
Der TIM1 oder TIM8 sind relativ "Wertvolle" Timer, gedacht für
Motor-Ansteuerungen und daher sollte man diese nicht schon für
Kleinigkeiten "Blockieren".
TIM10 oder TIM11 können auch mit 84MHz zählen, und haben jeweils nur
einen Ausgang. Den könnte man somit gut für internes nutzen.
Dieses Schaubild sollte jeder ausdrucken und sich wo hin hängen oder als
Bildschirm Desktop Hintergrund setzen ;-)
OK, Timer 2, 32 bit, 84MHz, so wie hier :
http://myembeddedtutorial.blogspot.de/2013/06/working-with-stm32f4-timers.html
eingestellt.
TIM_InitStruct.TIM_Prescaler = 0;
TIM_InitStruct.TIM_Period = 0xFFFFFFFF;;
TIM_InitStruct.TIM_ClockDivision = 0;
nach den for -Schleifen ist timerValue = 22130423.
Sieht schon ganz anders aus.
22130423 * 11,9ns = 263352033,7 ns = 263,352ms für die Ausführung.
Das scheint mir der bis jetzt vernünftigste Wert zu sein wenn man sich
die ganzen Rechenoperationen in den verschachtelten for - Schleifen mal
anschaut.
Dann lag das Problem wohl echt daran das der 16 Bit Timer 1 einfach zu
oft übergelaufen ist und die Period einfach zu klein war.
Das mit dem DWT funktioniert leider nicht:
1
// Takt-Zähler - Messen der Anzahl der Befehle des Prozessors:
2
inlinevoidDWT_CycCounterEn(){
3
DWT->CTRL=0x40000001;
4
}
5
inlinevoidDWT_CycCounterDis(){
6
DWT->CTRL=0x40000000;
7
}
8
inlineuint32_tDWT_CycCounterRead(){
9
returnDWT->CYCCNT;
10
}
11
inlinevoidDWT_CycCounterClear(){
12
DWT->CYCCNT=0;
13
}
[cc] C:\CooCox\CoIDE\workspace\LEDtest001\main.c: In function
'DWT_CycCounterEn':
[cc] C:\CooCox\CoIDE\workspace\LEDtest001\main.c:13:3: error:
'DWT' undeclared (first use in this function)
[cc] C:\CooCox\CoIDE\workspace\LEDtest001\main.c:13:3: note: each
undeclared identifier is reported only once for each function it appears
in
[cc] C:\CooCox\CoIDE\workspace\LEDtest001\main.c: In function
'DWT_CycCounterDis':
[cc] C:\CooCox\CoIDE\workspace\LEDtest001\main.c:16:3: error:
'DWT' undeclared (first use in this function)
[cc] C:\CooCox\CoIDE\workspace\LEDtest001\main.c: In function
'DWT_CycCounterRead':
[cc] C:\CooCox\CoIDE\workspace\LEDtest001\main.c:19:10: error:
'DWT' undeclared (first use in this function)
[cc] C:\CooCox\CoIDE\workspace\LEDtest001\main.c: In function
'DWT_CycCounterClear':
[cc] C:\CooCox\CoIDE\workspace\LEDtest001\main.c:22:3: error:
'DWT' undeclared (first use in this function)
Markus Müller schrieb:> #include "core_cm4.h> deklariert, die muss man mit einbinden.
Aber nicht direkt, das klappt nicht... Man muss wie im Artikel die
<stm32f4xx.h> #includen, die #include't die <core_m4.h> interen.
hclk = 168000000
sysclk = 168000000
pclk1 = 0
pclk2 = 0
das sind meine includes :
#include "stm32f4xx.h"
#include "stm32f4xx_gpio.h"
#include "stm32f4xx_rcc.h"
#include "stm32f4xx_tim.h"
und in stm32f4xx.h steht auch #include "core_cm4.h"
aber DWT kennt er trotzdem nicht.
Paul schrieb:> und in stm32f4xx.h steht auch #include "core_cm4.h"> aber DWT kennt er trotzdem nicht.
Scheinbar sind die "DWT"-Sachen in alten Versionen der CMSIS nicht
definiert. Verwende mal die neuste Version, 1.3.0 von ST:
http://www.st.com/web/en/catalog/tools/PF257901
Paul schrieb:> #define DWT_CYCCNT *(volatile uint32_t *)0xE0001004> #define DWT_CONTROL *(volatile uint32_t *)0xE0001000> #define SCB_DEMCR *(volatile uint32_t *)0xE000EDFC
Ganz böser Fehler, wenn schon Macros, dann immer Klammern machen: