Forum: Mikrocontroller und Digitale Elektronik [STM32] externer Interrupt mit steigender und fallender Flanke


von STM32_Beginner (Gast)


Lesenswert?

Hallo,

laut STM32 Reference Manual ist es möglich den externen Interrupt so zu 
konfigurieren, dass dieser bei steigender und fallender Flanke auslöst. 
Nur wie unterscheide ich in der ISR ob der Interrupt durch die steigende 
bzw. fallende Flanke ausgelöst wurde?
Mein erster Lösungsansatz wäre: Ich überprüfe in der ISR ob der 
entsprechende Portpin auf Low oder High liegt. Wenn der Portpin auf High 
gezogen ist, dann war es eine steigende Flanke. Und wenn der Portpin auf 
Low gezogen ist, dann war es eine fallende Flanke. Kann das so 
funktionieren, oder gibt es vielleicht ein Register das diese 
Information beinhaltet?

Kurz zum Hintergrund: Ich möchte einen Portpin überwachen und bei der 
fallenden Flanke einen Timer starten. Bei der steigenden Flanke soll der 
Timer wieder gestoppt werden und die gemessene Zeit ausgegeben werden. 
Also im Prinzip möchte ich die Zeit zwischen zwei Flanken messen.

von Lasse S. (cowz) Benutzerseite


Lesenswert?

Ich mach das genauso, wie du es vor hast. Eine andere Möglichkeit habe 
ich noch nicht gefunden.

Gruß
Lasse

von (prx) A. K. (prx)


Lesenswert?

STM32_Beginner schrieb:

> Also im Prinzip möchte ich die Zeit zwischen zwei Flanken messen.

Wozu man normalerweise keinen externen Interrupt verwendet, sondern 
Timer Capture. Ist dann taktgenau, während bei der ExtInt Variante die 
variable Latenzzeit mit eingeht.

von STM32_Beginner (Gast)


Lesenswert?

Lasse S. schrieb:
> Ich mach das genauso, wie du es vor hast. Eine andere Möglichkeit habe
> ich noch nicht gefunden.

Danke für den Hinweis, das ist schon mal gut zu wissen. Sollte ich das 
mit dem Capture & Compare nicht hinbekommen, dann werd' ich das so 
lösen.

A. K. schrieb:
> Wozu man normalerweise keinen externen Interrupt verwendet, sondern
> Timer Capture. Ist dann taktgenau, während bei der ExtInt Variante die
> variable Latenzzeit mit eingeht.

So wie ich das im Reference Manual verstanden habe, kann ich den Timer 
Capture so konfigurieren, dass dieser bei der entsprechenden Flanke(z.B: 
steigende Flanke) den Counter Wert in ein Zusatzregister sichert. Wie 
ich damit die Periodendauer eines Signals messen kann ist mir klar, doch 
wie messe ich damit die Pulsbreite eines Signals?

von STM32_Beginner (Gast)


Lesenswert?

Was mir gerade noch eingefallen ist:

Ich konfiguriere den Timer Capture so, dass ich zuerst den Counterstand 
bei der fallenden Flanke bekomme. Und wenn ich diesen dann habe, 
programmiere ich den Timer Capture um, sodass ich den Counterstand bei 
der steigenden Flanke bekomme. Die Differenz der beiden Werte entspricht 
dann der Pulsbreite. Kann das funktionieren?

von (prx) A. K. (prx)


Lesenswert?

Genau so geht das. Der primäre Unterschied zur Version über ExtInt ist 
dabei, dass Latenz/Laufzeit des Interrupts nur noch in die erforderliche 
Mindestdauer des Pulses eingehen, nicht mehr in die Messgenauigkeit.

Alternativ kannst du auch 2 Eingänge des gleichen Timers nutzen, auf 
verschiedene Flanken konfiguriert. Dann muss nur noch durch das den Puls 
beendende Capture-Event ein Interrupt ausgelöst werden.

von STM32_Beginner (Gast)


Lesenswert?

A. K. schrieb:
> Genau so geht das. Der primäre Unterschied zur Version über ExtInt ist
> dabei, dass Latenz/Laufzeit des Interrupts nur noch in die erforderliche
> Mindestdauer des Pulses eingehen, nicht mehr in die Messgenauigkeit.
>
> Alternativ kannst du auch 2 Eingänge des gleichen Timers nutzen, auf
> verschiedene Flanken konfiguriert. Dann muss nur noch durch das den Puls
> beendende Capture-Event ein Interrupt ausgelöst werden.

Vielen Dank für die Hilfestellung & die Erklärung! Ich werd' mich gleich 
mal ransetzen und das ausprobieren.

Danke!

von STM32_Beginner (Gast)


Lesenswert?

Hi,

ich hab mir heute die Capture & Compare Unit des STM32 angesehen. Ich 
hab mich dazu entschlossen den TIM2_CH2 (entspricht Portpin PA.1) als 
Capture Eingang zu verwenden. Dazu gleich eine Frage: Im Datenblatt 
steht, dass PA.1 auch als USART2_RTS dient. Da ich in meiner Software 
auch den USART2 verwende (also nur RX und TX), wollte ich fragen ob ich 
den Portpin PA.1 nun verwenden kann oder nicht?
Meine Konfiguration von TIM2 sieht im Prinzip so aus:

-) GPIOA clock enable
-) configure PA.1 as input with pullup
-) CC2 channel is configured as input, IC2 is mapped on TI2.
-) capture is done on the rising edge
-) no prescaler, capture is done each time an edge is detected on the 
capture input
-) enable capture
-) capture interrupt enable
-) TIM2 interrupt enable(NVIC)
-) TIM2 priority = 2
-) set TIM2 counter enable

Das Problem ist, dass der uC nie in die ISR springt. Hab ich bei der 
TIM2 Konfiguration vielleicht etwas wichtiges übersehen, oder könnte es 
etwas mit dem Portpin PA.1 zu tun haben?

Bei Bedarf poste ich auch gerne den Code der Initialisierungsroutine.

von STM32_Beginner (Gast)


Lesenswert?

Der alternate function clock für den TIM2 wird natürlich auch aktiviert

von Markus M. (Firma: EleLa - www.elela.de) (mmvisual)


Lesenswert?

Sowas hast Du drin?
1
  NVIC_InitTypeDef NVIC_InitStructure;
2
  /* Enable the TIM2 global Interrupt */
3
  NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
4
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
5
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
6
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
7
  NVIC_Init(&NVIC_InitStructure);

von (prx) A. K. (prx)


Lesenswert?

STM32_Beginner schrieb:

> steht, dass PA.1 auch als USART2_RTS dient. Da ich in meiner Software
> auch den USART2 verwende (also nur RX und TX), wollte ich fragen ob ich
> den Portpin PA.1 nun verwenden kann oder nicht?

Ja, RTS kann man da drauf mappen, muss man aber nicht. Aber 
vorsorglich Errata-Sheet lesen, ob da irgendwas drüber drin steht.

> -) GPIOA clock enable

Timer auch?

> Bei Bedarf poste ich auch gerne den Code der Initialisierungsroutine.

Mach ma.

von STM32_Beginner (Gast)


Lesenswert?

Markus Müller schrieb:
> NVIC_InitTypeDef NVIC_InitStructure;
>   /* Enable the TIM2 global Interrupt */
>   NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
>   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
>   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
>   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
>   NVIC_Init(&NVIC_InitStructure);

Von der ST Library hab ich leider nicht soviel Ahnung, ich hab die 
bisher nicht genutzt.

A. K. schrieb:
> Ja, RTS kann man da drauf mappen, muss man aber nicht. Aber
> vorsorglich Errata-Sheet lesen, ob da irgendwas drüber drin steht.

Als ich gestern im Errata-Sheet gestöbert hab, ist mir nichts 
aufgefallen. Aber es war schon spät, ich werd mir das daher heute 
nochmal in Ruhe ansehen.

A. K. schrieb:
> Mach ma.

Anbei mein Sourcecode zur Initialisierung von TIM2:
1
  RCC->APB2ENR |= RCC_APB2ENR_IOPAEN; //GPIOA clock enable 
2
  
3
  RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; //TIM2 clock enable
4
5
  GPIOA->CRL = GPIOA->CRL & ~(0x000000F0) | (0x00000080);//configure PA.1 as input with pullup/pulldown
6
7
  TIM2->CCMR1 |= TIM_CCMR1_CC2S_0; //IC2 is mapped on TI2
8
  TIM2->CCMR1 |= (TIM_CCMR1_IC2F_0 | TIM_CCMR1_IC2F_1); //program input capture filter; N = 8
9
10
  TIM2->CCER |= TIM_CCER_CC2P; //capture is done on the rising edge
11
  TIM2->CCMR1 &= ~(TIM_CCMR1_IC2PSC_0 | TIM_CCMR1_IC2PSC_1); //no prescaler, capture is done each time an edge is detected on the capture input.
12
  
13
  TIM2->CCER |= TIM_CCER_CC2E; //capture counter value
14
  TIM2->DIER |= TIM_DIER_CC2IE; //capture interrupt enable
15
16
  NVIC->ISER[0] |= (1<<28); //TIM2 interrupt enable
17
  NVIC->IP[28] = 0x20; //TIM2 interrupt priority = 2
18
  TIM2->CR1 |= TIM_CR1_CEN; //set TIM2 runbit

Und hier noch die ISR:
1
volatile uint8_t dummy = 0; 
2
3
void TIM2_IRQHandler(void){
4
  if (TIM2->SR & 0x00000004) { //TIM2 capture&compare interrupt? 
5
    dummy = 1;  
6
  }
7
  TIM2->SR &= ~(0x00000004); //clear interrupt flag 
8
}

von (prx) A. K. (prx)


Lesenswert?

TIM2->ARR setzen. Beispielsweise auf 0xFFFF. Obacht, wenn man ARR 
schreibt, dann schreibt man in ein Pufferregister, das erst bei einem 
Update-Event wirklich greift. Es kann nötig sein, dieses Event manuell 
auszulösen (UG bit in the TIMx_EGR).

"In upcounting mode, the counter counts from 0 to the auto-reload value 
(content of the TIMx_ARR register), then restarts from 0 and generates a 
counter overflow event."

"The counter is blocked while the auto-reload value is null."

von STM32_Beginner (Gast)


Lesenswert?

Dein Tipp war goldrichtig, jetzt funktioniert's! Besten Dank!

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.