Hallo zusammen, ich habe ein Problem mit den Timereinstellungen eines STM32F4Discovery Boards und hoffe es kann mir hier jemand weiterhelfen. Timer 3 toggled bei jedem Timerevent PortC Pin15 welcher mit einem 10k Widerstand auf Masse liegt. Die Frequenz am Pin messe ich mit einem Oszi. Systemtakt = 168MHz. Habe ich mir an MCO1 ausgeben lassen. -> Passt. HSE Frequenz: 8MHz AHB Prescaler: 1 APB1 Prescaler: 4 APB2 Prescaler: 2 Nun mein Problem: bei gewissen Werten von "Period" und "Prescaler" stimmt die Frequenz mit dem erwarteten Wert zusammen bei einigen dann nicht mehr. Woran liegt das?? z.B.: Period = 2; Prescaler = 83; Frequenz am Pin = 166,7kHz -> passt wie erwartet Period=2; Prescaler = 20; Frequenz: 700kHz -> gemessen wurden aber nur 350kHz -> falsche Frequenz Period=2; Prescaler = 30; Frequenz: 466,6kHz -> gemessen: 466,6kHz -> passt auch Period=4; Prescaler = 18; Frequenz: 442kHz -> gemessen: 442kHz -> passt auch Period=4; Prescaler = 14; Frequenz: 560kHz -> gemessen: 381/535kHz -> falsch (Oszibild ist hier verzerrt) Bei Period=4 ist ein Prescaler=15 der letzte Wert wo die Frequenz noch stimmt. Alle Werte darunter ergeben falsche Frquenzwerte. Ich probier jetzt schon sehr lange damit rum und komme einfach nicht dahinter wo das Problem liegt. Hoffentlich kann mir einer der ARM Spezialisten weiterhelfen. Anbei noch der Quellcode und eine Excel-Datei welche ich zum Kontrollrechnen verwende: Vielen Dank schon mal Markus void TIM3_IRQHandler(void) { if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) { TIM_ClearITPendingBit(TIM3, TIM_IT_Update); GPIO_ToggleBits(GPIOC, GPIO_Pin_15); } } void INTTIM_Config(void) { NVIC_InitTypeDef NVIC_InitStructure; /* Enable the TIM3 gloabal Interrupt */ NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); /* TIM3 clock enable */ RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); /* Time base configuration */ TIM_TimeBaseStructure.TIM_Period = 15-1; // 1 MHz down to 1 KHz (1 ms) TIM_TimeBaseStructure.TIM_Prescaler = 5-1; // 84 MHz Clock down to 1 MHz (adjust per your clock) TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); /* TIM IT enable */ TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE); /* TIM3 enable counter */ TIM_Cmd(TIM3, ENABLE); } int main(void) { SystemInit(); SystemCoreClockUpdate(); /* GPIOD Periph clock enable */ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE); RCC_ClocksTypeDef oClock; RCC_GetClocksFreq(&oClock); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_Init(GPIOC, &GPIO_InitStructure); INTTIM_Config(); while(1) { } }
Hi Markus, nur ein "schnellschuss" aber kann es sein das dein Aufruf :
1 | |
zu lange dauert und deswegen die höheren Frequenzen nicht stimmen ? probier mal das hier (ob das schneller ist...das ist der Aufruf direkt)
1 | |
Gruss Uwe
Hallo Uwe, nein hat leider nix geholfen. Ich hab auch mal versucht in einer Endlosschleife (also alles ohne Timer) einfach einen PIN zu togglen. Hier komme ich auf eine max. Frequenz von ca. 1MHz. Das kann eigentlich auch schon nicht stimmen, oder?? Blöde Frage: kann das mit der ST-Link Frequenz zu tun haben über welchen ich Debug und Flashe. Diese Frequenz ist mit 1MHz eingestellt. Als IDE verwende ich CooCox CoIDE. lg, markus
du hast aber nicht den Debugger laufen oder ? 1MHz kommt mir sehr wenig vor hängt noch was anderes an dem Pin PC15 ? komisch ist, das manche Frequenzen stimmen und andere nicht... lass mal den Widerstand weg und häng das Scope direkt an den Pin Gruss Uwe
nein debugger läuft nicht. hab auch mal die brücken zwischen dem ST-Link und dem eigentlich STM32F4 Chip entfernt und so das program im flash gestartet bringt auch nichts. Widerstand ist weg und hat auch nichts gebracht.... lg, m.
ich kann hier jetzt leider nichts ausprobieren werd aber heut abend (wenn das problem bis dahin nicht schon gelöst ist) mal bei meinem Discovery nachmessen...was der max GPIO speed ist kann es an deinem Oszi liegen ? zeigt es die Frq direkt an oder misst du die Periode selbst aus ? Gruss Uwe
also, so wie ich das datenblatt verstanden habe sollten max. 84MHz GPIO Speed möglich sein. am Oszi liegt es nicht. hab die Frequenz natürlich ermitteln lassen, aber auch durch "abzählen" am Oszibild überprüft.
hab gerade diese Funktion gemessen :
1 | |
2 | |
3 | |
4 | |
da messe ich mit meinem alten Röhren Oszi : T = ca. 133ns f = ca. 7,5 MHz und mit dem Timer hab ichs auch ausprobiert (und deinem Code)
1 | |
2 | |
da kommen bei mir auch nur ca. 350kHz raus (statt 700kHz) ?!? versteh ich auch nicht ganz mit diesen Werten :
1 | |
2 | |
stimmt die Ausgangsfrq scheint wohl ein problem mit der Abarbeitung der ISR zu sein blöd ! :-)
Gast
#3140498
> void TIM3_IRQHandler(void) > { > if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) > { > TIM_ClearITPendingBit(TIM3, TIM_IT_Update); > GPIO_ToggleBits(GPIOC, GPIO_Pin_15); > } > } Änder das mal in:
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
das kann nicht gehen, wenn das "TIM_IT_Update" Bit gelöscht ist, wird die IF-Abfrage darunter immer scheitern aber komplett ohne "IF" funktionierts :
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
damit sind es 700kHz es darf halt jetzt kein anderer Interrupt von TIM3 aktiviert werden :-) Gruss Uwe
uwe, danke erst mal für deine hilfe. bin froh das du die gleichen werte gemessen hast und es dir auch nicht erklären kann. ich versteh auch deine 7,5Mhz nicht. Das ist ja eigentlich auch viel zu wenig, oder?? und beim Timer ist nach wie vor die frage wo da die obergrenze liegt. darf ich vielleicht einen timer nicht für so hohe frquenzen nehmen?? und die If-Abfrage ausbauen ist eigentlich nur ein schlechter "workaround" für die 700khz. oder wie denkst du?? lg, m.
Gast
#3140628
Markus F. schrieb: > ich versteh auch deine 7,5Mhz nicht. Das ist ja eigentlich auch viel zu > wenig, oder?? Wenn du dir nur deine C-Befehle ansiehst ist das so gut wie sinnlos. Du mußt dir in Assembler window ansehen was der Compiler an Assemblerbefehlen daraus gemacht hat. Dann wirst du auch den Einfluß von C-Optimierungseinstellungen beobachten könne!
wegen der 7,5MHz bin ich mir nicht sicher, müsste man mal mit Optimierung auf "speed" probieren wieviel das bringt ich weis ja nicht was du machen willst, einen Pin kann ein Timer auch direkt ansteuern (siehe PWM-Mode ...ohne Interrupt und manuellem setzen) damit müsste es deutlich schneller gehen und wegen der Geschwindigkeit...die Timer1 und 8 werden ja sogar mit 168MHz angefahren ich bin da jetzt auch überfragt warum die IF-Abfrage so lange dauert ich kämpfe zur zeit mit einem ähnlichen Problem, ich will per DMA ein Byte an den GPIOs ausgeben und vom einschalten bis zum erscheinen der Werte an den Pins vergehen 20us !! k.A. warum das so lange dauert vlt meldet sich hier noch jemand zu deinem Problem und klärt das ganze Gruss
Gast
#3140648
Uwe B. schrieb: > ich will per DMA ein Byte an den GPIOs ausgeben > und vom einschalten bis zum erscheinen der Werte an den Pins > vergehen 20us !! k.A. warum das so lange dauert Etwas genauer beschreiben was du tust! Einschalten = Aufruf der Initialisierungsroutine? Wie hast du die 20us gemessen? Die Library Funktionen sind recht langsam. Wichtig auch: !!!!!!!!! Sicherstellen, dass deine CPU wirklich mit 168MHz läuft. Bin da auch einmal in einer Sackgasse gewesen.
Gast
#3140660
> das kann nicht gehen, > wenn das "TIM_IT_Update" Bit gelöscht ist, > wird die IF-Abfrage darunter immer scheitern Hoppla - das stimmt allerdings. Da hab ich geschlafen
Gast
#3140664
Meine Idee zielte darauf sicherzustellen, dass das Interruptflag auch wirklich gelöscht ist wenn die Intzerruptroutine verlassen wird. Es gab da schonmal Probleme, wenn das Flag erst am Ende der Routine gelöscht wird.
Gast
#3140991
Markus F. schrieb: > uwe, > danke erst mal für deine hilfe. > > bin froh das du die gleichen werte gemessen hast und es dir auch nicht > erklären kann. > ich versteh auch deine 7,5Mhz nicht. Das ist ja eigentlich auch viel zu > wenig, oder?? > > und beim Timer ist nach wie vor die frage wo da die obergrenze liegt. > darf ich vielleicht einen timer nicht für so hohe frquenzen nehmen?? > und die If-Abfrage ausbauen ist eigentlich nur ein schlechter > "workaround" für die 700khz. oder wie denkst du?? > > lg, m. Bei 168MHz entspricht 7,5MHz einer Periodendauer von 22 CPU-Zyklen. Wenn man nun den entsprechenden Assembler-Code anschaut, stellt man fest, dass eine ganze Reihe von Assemberbefehlen aus dieser Schleife erzeugt werden. Bedingte Sprungbefehle mit Sprung benötigen beim Cortex-M4 bis zu 5 Zyklen(2+3 zum Aufladen der Pipeline), Load/Store jeweils 2, der Rest im Wesentlichen 1. Bei mir wird folgender Code erzeugt: while(1) { GPIOC->ODR ^= GPIO_Pin_15; toggle: mov.w r3, #2048 ; 0x800 (1) movt r3, #16386 ; 0x4002 (1) mov.w r2, #2048 ; 0x800 (1) movt r2, #16386 ; 0x4002 (1) ldr r2, [r2, #20] (2) eor.w r2, r2, #32768 ; 0x8000 (1) str r2, [r3, #20] (2) } b.n <toggle> (2 mit Sprungvorhersage) Wie man sieht ein Schleifendurchlauf hat genau 11 Zyklen, was einer Frequenz von 7,5MHz ziemlich genau entspricht, da pro Periode die Schleife ja 2 mal also in 22 Zyklen durchlaufen wird. Bei einer Interrupt-Routine müssen zusätzlich noch eine ganze Reihe Register auf den Stack gesichtert und beim Verlassen zurückgeladen werden, somit denke ich, dass 500khz (ca. 150 Zyklen pro Routinenaufruf) durchaus realistisch sind. Müsste man mal genau nachzählen. Auch wenn man beim STM32F4 mit 168MHZ scheinbar unglaublich viel Rechenleistung zur Verfügung hat, muss man in ISR-Routinen sehr aufpassen, will man keine Interrupts verpassen.
@Michael Warenberg, >Wie man sieht ein Schleifendurchlauf hat genau 11 Zyklen, was einer >Frequenz von 7,5MHz ziemlich genau entspricht, da pro Periode die >Schleife ja 2 mal also in 22 Zyklen durchlaufen wird. deine Rechnung klingt plausbibel... hier würde eine RISC-CPU (ATMEga) mit ihren 1Cyclus Befehlen vlt. Ihre Vorteile ausspielen (ich bleib aber beim STM :-) @Fritz, >Etwas genauer beschreiben was du tust! >Einschalten = Aufruf der Initialisierungsroutine? >Wie hast du die 20us gemessen? das wird zu Offtopic...ich werd (wenn ich nicht weiterkomme) einen neuen Thread aufmachen >Die Library Funktionen sind recht langsam. Full ACK !! hier hat schon mal jemand die Delays der STM-Funktionen der GPIOs nachgemessen...(auch interresant für den TE) http://joe-c.de/pages/posts/einstieg_mikrocontroller_stm32f103_101.php (ganz nach unten scrollen)
Gast
#3141016
Uwe B. schrieb: > @Michael Warenberg, > >>Wie man sieht ein Schleifendurchlauf hat genau 11 Zyklen, was einer >>Frequenz von 7,5MHz ziemlich genau entspricht, da pro Periode die >>Schleife ja 2 mal also in 22 Zyklen durchlaufen wird. > > deine Rechnung klingt plausbibel... > hier würde eine RISC-CPU (ATMEga) mit ihren > 1Cyclus Befehlen vlt. Ihre Vorteile ausspielen > (ich bleib aber beim STM :-) Kommt halt auf die Anwendung an. Der STM32 spielt halt beim Verarbeiten größerer Datenmengen seine Vorteile aus, während z.B. ein AVR bei einfachen (IO) Aufgeben bei Stromverbrauch und Einfachheit punkten kann. Man sollte sich halt nicht von den 168MHz allzu sehr blenden lassen, da ein Cortex-M4 dafür auch eine 3-stufige Pipeline und bis zu 5 Waitstates beim (Flash-) Speicherzugriff hat. Auch beim STM32F4 kommt man bei zeitkritischen ISR möglicherweise nicht um Assembler herum. Wenn man auf einem 32-Bit System Aufgaben implementiert, wofür auch 8 bit völlig ausreichend wären, ist der Overhead dadurch gar nicht so gering. > hier hat schon mal jemand die Delays der STM-Funktionen > der GPIOs nachgemessen...(auch interresant für den TE) > > http://joe-c.de/pages/posts/einstieg_mikrocontroll... > > (ganz nach unten scrollen)
Antwort schreiben
Bitte melde dich an, um einen Beitrag zu schreiben.