mikrocontroller.net

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


Autor: STM32_Beginner (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Lasse S. (cowz) Benutzerseite
Datum:

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

Gruß
Lasse

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: STM32_Beginner (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: STM32_Beginner (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: STM32_Beginner (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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!

Autor: STM32_Beginner (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: STM32_Beginner (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Der alternate function clock für den TIM2 wird natürlich auch aktiviert

Autor: Markus Müller (mmvisual)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sowas hast Du drin?
  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);

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: STM32_Beginner (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:
  RCC->APB2ENR |= RCC_APB2ENR_IOPAEN; //GPIOA clock enable 
  
  RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; //TIM2 clock enable

  GPIOA->CRL = GPIOA->CRL & ~(0x000000F0) | (0x00000080);//configure PA.1 as input with pullup/pulldown

  TIM2->CCMR1 |= TIM_CCMR1_CC2S_0; //IC2 is mapped on TI2
  TIM2->CCMR1 |= (TIM_CCMR1_IC2F_0 | TIM_CCMR1_IC2F_1); //program input capture filter; N = 8

  TIM2->CCER |= TIM_CCER_CC2P; //capture is done on the rising edge
  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.
  
  TIM2->CCER |= TIM_CCER_CC2E; //capture counter value
  TIM2->DIER |= TIM_DIER_CC2IE; //capture interrupt enable

  NVIC->ISER[0] |= (1<<28); //TIM2 interrupt enable
  NVIC->IP[28] = 0x20; //TIM2 interrupt priority = 2
  TIM2->CR1 |= TIM_CR1_CEN; //set TIM2 runbit 

Und hier noch die ISR:
volatile uint8_t dummy = 0; 

void TIM2_IRQHandler(void){
  if (TIM2->SR & 0x00000004) { //TIM2 capture&compare interrupt? 
    dummy = 1;  
  }
  TIM2->SR &= ~(0x00000004); //clear interrupt flag 
}

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht 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."

Autor: STM32_Beginner (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dein Tipp war goldrichtig, jetzt funktioniert's! Besten Dank!

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.