Forum: Mikrocontroller und Digitale Elektronik STM32F4 Frequenz messen mit Timer5


von Mach F. (machfax)


Lesenswert?

Hallo

Ich möchte bei einem STM32F407 eine Frequenz bei PA2 messen. Dazu nehme 
ich den Timer5. Mit dem Capture Compare müsste das doch gehen oder was 
mache ich falsch?

TIM_ICInitTypeDef  TIM_ICInitStructure;
  GPIO_InitTypeDef GPIO_InitStructure;
  NVIC_InitTypeDef NVIC_InitStructure;

  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);

  // GPIOB clock enable
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);

  GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_2;
  GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_NOPULL ;
  //GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_UP ;
  GPIO_Init(GPIOA, &GPIO_InitStructure);

  GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_3;
  GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_IN;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_NOPULL ;
  //GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_UP ;
  GPIO_Init(GPIOA, &GPIO_InitStructure);

  // Connect TIM pin to AF2
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_TIM5);

  NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);

  TIM_ICInitStructure.TIM_Channel = TIM_Channel_3;
  TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
  TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
  TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV8;
  TIM_ICInitStructure.TIM_ICFilter = 0x2;

  TIM_PWMIConfig(TIM5, &TIM_ICInitStructure);

  TIM_SelectInputTrigger(TIM5, TIM_TS_TI2FP2);

Oder geht das bei PA2 nicht?
Ich habe einen externen Encoder bei PA2 (Spur A) und PA3 (Spur B) 
angeschlossen, davon möchte ich die Geschwindigkeit messen..
Danke

von m.n. (Gast)


Lesenswert?

Mach Fax schrieb:
> Oder geht das bei PA2 nicht?

Das geht, Du darfst PA2 allerdings nicht als Ausgang konfigurieren!
Ich habe ein Beispiel für T9 an PE5 und ein bißchen Schnickschnack drum 
herum: Beitrag "reziproker Frequenzzähler mit STM32F4Discovery"
Die init_t9() kann man ja auf t5 ändern.

von Mach F. (machfax)


Lesenswert?

Hallo

Ich habe Deine Initialisierung übernommen, jedoch leider immer noch ohne 
Erfolg. Was ist denn daran falsch, ich finde den Fehler einfach nicht:

    GPIO_InitTypeDef GPIO_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);  // Timer5 
aktivieren
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); // PortA 
aktivieren

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    // PA5 und PA6 als capture-input zu T5
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_TIM5);
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource3, GPIO_AF_TIM5);

    NVIC_EnableIRQ(TIM5_IRQn);       // Int-T9 aktivieren
    NVIC_SetPriority(TIM5_IRQn,14);  // sehr hohe Priorität

    TIM5->CCMR1 = TIM_CCMR2_CC3S_0 + TIM_CCMR2_CC3S_1;     // capture 
zuordnung IC1 -> TI1
    TIM5->CCER = TIM_CCER_CC3E;         // capture freigeben

    TIM5->CCMR1 |= TIM_ICPSC_DIV8;      // Vorteiler /8 aktivieren

    TIM5->DIER |= TIM_DIER_CC1IE + TIM_DIER_UIE; // mit interrupts
    TIM5->CR1 |= TIM_CR1_CEN;           // T5 starten


Danke

von holger (Gast)


Lesenswert?

>    RCC_APB2PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);  // Timer5
            ^                      ^
            |                      |

Schau mal GENAU hin.

Das wird noch ein echter Klassiker werden;)

von m.n. (Gast)


Lesenswert?

holger schrieb:
>>    RCC_APB2PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);  // Timer5
>             ^                      ^
>             |                      |
>
> Schau mal GENAU hin.

Meckert da nicht schon der Compiler?
Aber immerhin hast Du einen Blick für diesen Kopierkram :-) Längere 
Quelltexte der STM (u.a.) sind ja fast nicht mehr lesbar, da sich 
gleiche Befehlssequenzen immer wiederholen, sich dann aber doch in nur 
einem Zeichen unterscheiden.

Mach Fax schrieb:
> Ich habe Deine Initialisierung übernommen, jedoch leider immer noch ohne
> Erfolg.

Du hättest auch TIM9 auf PA2+PA3 legen können, um erst einmal einen 
Erfolg zu haben, aber jetzt sollte es bei Dir auch so funktionieren.

von Mach F. (machfax)


Lesenswert?

m.n. schrieb:
> Du hättest auch TIM9 auf PA2+PA3 legen können, um erst einmal einen
> Erfolg zu haben, aber jetzt sollte es bei Dir auch so funktionieren.

Nein kann ich leider nicht, da Timer9 schon benutzt wird, aber Danke 
habe ich am späteren Abend übersehen...
Werde ich ausprobieren und danach ein Feedback geben.

Danke & Gruss

von Mach F. (machfax)


Lesenswert?

Ich habe das jetzt mit dem TimerLib gemacht, jedoch funktioniert da 
immer noch etwas nicht wie gewünscht, sprich es wird kein Interrupt 
ausgelöst bei Flanken auf PA2. Das kann doch nicht so schwierig sein, 
hat niemand eine Lösung dazu?

void EncoderSyncConfig(void)
{
  GPIO_InitTypeDef       GPIO_InitStructure;
  TIM_TimeBaseInitTypeDef    TIM_TimeBaseInitStructure;
  TIM_ICInitTypeDef       TIM_ICInitStructure;
  NVIC_InitTypeDef       NVIC_InitStructure;

  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); // PortA 
aktivieren

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; //GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; //GPIO_PuPd_NOPULL; 
//GPIO_PuPd_UP;
  GPIO_Init(GPIOA, &GPIO_InitStructure);

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; //GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; //GPIO_PuPd_NOPULL; 
//GPIO_PuPd_UP;
  GPIO_Init(GPIOA, &GPIO_InitStructure);

/////////////////////////////////////////

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5,ENABLE);

  GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_TIM5);
  //GPIO_PinAFConfig(GPIOA, GPIO_PinSource3, GPIO_AF_TIM5);

  TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; //Control 
with dead zone.
  TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; 
//Counter direction
  TIM_TimeBaseInitStructure.TIM_Prescaler = 10;// 84-1;   //Timer clock 
= sysclock /(TIM_Prescaler+1) = 2M
  TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
  TIM_TimeBaseInitStructure.TIM_Period = 0xFFFF;
  TIM_TimeBaseInit(TIM5,&TIM_TimeBaseInitStructure);

  TIM_ICInitStructure.TIM_Channel = TIM_Channel_3;
  TIM_ICInitStructure.TIM_ICFilter = 0;
  TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
  TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
  TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; 
//TIM_ICSelection_IndirectTI
  TIM_ICInit(TIM5,&TIM_ICInitStructure);

  NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x05;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);

  NVIC_SetPriority(TIM5_IRQn,14);  // sehr hohe Priorität
  NVIC_EnableIRQ(TIM5_IRQn);       // Int-T9 aktivieren

  TIM_ITConfig(TIM5, TIM_IT_CC3, ENABLE);

  TIM_Cmd(TIM5,ENABLE);
}

von m.n. (Gast)


Lesenswert?

Mach Fax schrieb:
> GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_TIM5);

Dazu fehlt (mindestens) der Init-Aufruf.

von Mach F. (machfax)


Lesenswert?

So, es funktioniert jetzt (Code unten)

Was aber noch nicht geht, ist dass bei einer positiven Flanke auf PA3 
der Timer automatisch wieder auf 0 gestellt wird, jetzt wird der 
Interrupt ausgelöst, ich kann den Capture Wert auslesen in der IRQ 
Routine aber der Timer zählt munter weiter und bei der nächsten 
positiven Flanke habe ich den alten TimerStand plus den neuen im 
Register. Es sollte laut Library mit diesen beiden Zeilen eigentlich den 
Timer bei einer Flanke von extern zurücksetzen, oder was fehlt da noch?

TIM_SelectInputTrigger(TIM5, TIM_TS_ETRF);
TIM_SelectSlaveMode(TIM5, TIM_SlaveMode_Reset);

Danke


void EncoderSyncConfig(void)
{
  GPIO_InitTypeDef       GPIO_InitStructure;
  TIM_TimeBaseInitTypeDef    TIM_TimeBaseInitStructure;
  TIM_ICInitTypeDef       TIM_ICInitStructure;
  NVIC_InitTypeDef       NVIC_InitStructure;

  //Activate PortA
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
  GPIO_Init(GPIOA, &GPIO_InitStructure);

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
  GPIO_Init(GPIOA, &GPIO_InitStructure);

  //Activate the Timer5
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5,ENABLE);

  //connect the Timer5 to the Sync Encoder PINs
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_TIM5);
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource3, GPIO_AF_TIM5);

  //configure the Counter
  TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; 
//without ClockDivision
  TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; 
//Counter direction Up
  TIM_TimeBaseInitStructure.TIM_Prescaler = 1;               //Timer 
clock = sysclock /(TIM_Prescaler+1) = 2M
  TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
  TIM_TimeBaseInitStructure.TIM_Period = 0xFFFFFFFF;
  TIM_TimeBaseInit(TIM5,&TIM_TimeBaseInitStructure);

  TIM_ICInitStructure.TIM_Channel = TIM_Channel_3;
  TIM_ICInitStructure.TIM_ICFilter = 0;
  TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
  TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
  TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; 
//TIM_ICSelection_IndirectTI
  TIM_ICInit(TIM5,&TIM_ICInitStructure);

  //Enable the TIM5 CC3 Interrupt Request
    TIM_ITConfig(TIM5, TIM_IT_CC3, ENABLE);

  //TIM enable counter
    TIM_Cmd(TIM5, ENABLE);

  TIM_SelectInputTrigger(TIM5, TIM_TS_ETRF);
    TIM_SelectSlaveMode(TIM5, TIM_SlaveMode_Reset);
    TIM_SelectMasterSlaveMode(TIM5, TIM_MasterSlaveMode_Enable);
}

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.