Forum: Mikrocontroller und Digitale Elektronik Frage/Problem mit Timer STM32F4Discovery


von Markus F. (markus_f79)


Angehängte Dateien:

Lesenswert?

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)
    {
    }
}

von Uwe B. (derexponent)


Lesenswert?

Hi Markus,

nur ein "schnellschuss" aber kann es sein das dein Aufruf :
1
GPIO_ToggleBits(GPIOC, GPIO_Pin_15);
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
GPIOC->ODR ^= GPIO_Pin_15;

Gruss Uwe

von Markus F. (markus_f79)


Lesenswert?

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

von Uwe B. (derexponent)


Lesenswert?

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

von Markus F. (markus_f79)


Lesenswert?

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.

von Uwe B. (derexponent)


Lesenswert?

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

von Markus F. (markus_f79)


Lesenswert?

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.

von Uwe B. (derexponent)


Lesenswert?

hab gerade diese Funktion gemessen :
1
  while(1)
2
  {
3
    GPIOC->ODR ^= GPIO_Pin_15;
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
  TIM_TimeBaseStructure.TIM_Period = 2;
2
  TIM_TimeBaseStructure.TIM_Prescaler = 19;

da kommen bei mir auch nur ca. 350kHz raus
(statt 700kHz) ?!?

versteh ich auch nicht ganz

mit diesen Werten :
1
  TIM_TimeBaseStructure.TIM_Period = 4;
2
  TIM_TimeBaseStructure.TIM_Prescaler = 19;

stimmt die Ausgangsfrq

scheint wohl ein problem mit der Abarbeitung
der ISR zu sein

blöd ! :-)

von blau (Gast)


Lesenswert?

> 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
void TIM3_IRQHandler(void)
2
{
3
TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
4
TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
5
6
  if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)
7
  {
8
    GPIO_ToggleBits(GPIOC, GPIO_Pin_15);
9
  }
10
}

von Uwe B. (derexponent)


Lesenswert?

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
void TIM3_IRQHandler(void)
2
{
3
  TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
4
5
  GPIO_ToggleBits(GPIOC, GPIO_Pin_15);
6
}

damit sind es 700kHz

es darf halt jetzt kein anderer Interrupt
von TIM3 aktiviert werden :-)

Gruss Uwe

von Markus F. (markus_f79)


Lesenswert?

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.

von Fritz (Gast)


Lesenswert?

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!

von Uwe B. (derexponent)


Lesenswert?

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

von Fritz (Gast)


Lesenswert?

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.

von blau (Gast)


Lesenswert?

> 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

von blau (Gast)


Lesenswert?

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.

von Michael Warenberg (Gast)


Lesenswert?

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.

von Uwe B. (derexponent)


Lesenswert?

@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)

von Michael Warenberg (Gast)


Lesenswert?

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)

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
Noch kein Account? Hier anmelden.