cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F4: EXTI: Fails to capture rising edge interrupt sometimes

MSuhe
Associate III

In out project we are making use of EXTI for interfacing a radio (RF) ASIC with STM32F411. Whenever, the radio has some data to be sent host it interrupts the host using the I/O line (drives the line high). This I/O line stays high till data is read by STM32 over SPI.

Now, we have configured this line to be external interrupt line with EXTI. And the functionality works as expected most of the time. But, we do see some scenarios where, EXTI controller does not raise an interrupt even though the I/O line is high.

To overcome this issue, we are monitoring the state of the I/O line to check if it is high and if true, try and read the data from radio over SPI.

A quick check at the state of the EXTI registers whenever this happens shows PR (pending register) set to 0 (no interrupt pending) and IMR (interrupt mask register) set to 0x400, which mean the associated interrupt being enabled.

Is there any reason why the EXTI might fail to capture a rising edge on the I/O line? STM32F4 does not support level sensitive interrupts, otherwise we could have configured the external interrupt as level sensitive.

Please do share your inputs.

15 REPLIES 15

This typically happens if the external device can generate two edges consecutively and you clear the pending register *after* the second edge arrives.

JW

Thanks for your response. As far as i am know,

  • The external device we have generates an edge everytime it has some data for host.
  • And we clear the pending register right at the beginning of the ISR handler before we start reading data from external device.
  • We clear the pending register as a first step, so that EXTI can capture any new triggers/edges generated on the I/O line, while executing the ISR handler.
  • Also, we are not masking the interrupts at all, as edges are not captured if masked. by clearing "interrupt mask register".

Am i missing anything else? Please so share your inputs.

> The external device we have generates an edge everytime it has some data for host.

How often that can be? Is your total interrupt latency, ie. worst-case time from the physical edge to the point where the pending register is cleared, guaranteed to be faster than the closest two edges from the external device?

How do you notify the external device that you've accepted the data? Do you notify after clearing the pending register? Will the external device generate an edge if notification comes after it has more data?

JW

Thanks again for your quick response. Please find some important aspects regarding how/when the external device drives the I/O line and when the I/O line is cleared.

  • From the STM32 side, we have configured the I/O line as input and set the pull-up to PULL-DOWN.
  • Now, whenever the external device has some data it generates a rising edge on the I/O line and leaves the I/O state high as long as the data is not fully read by the host MCU.
  • Now on getting the ISR, we clear the Pending register as a first step. At this point I/O line will still be high.
  • Next MCU reads the data/status from external device over SPI.
  • External device will drive the I/O line low, once all the data is read.
  • Continue with ISR execution.

External device will only generate a second edge only after it is driven low. As the I/O line stays high until all the data is read by host MCU. Now, if there is more data accumulated from the point I/O line goes high to MCU reading it, it is fine. As, MCU will no do a partial read.

Now, with above said external device behaviour and handling from MCU. I don't understand how the host can still miss an edge?

What happens if:

  • Device has 1 set of data and drives I/O line high
  • You get the interrupt, ISR clears pending bit
  • While ISR is reading 1 set of data, device receives a 2nd set of data

Does your ISR always only read 1 set of data and then exit? Or does it check to see if more data is available before exiting? Does it check the state of the I/O line before exiting (i.e. does it keep reading data as long as the I/O line is high)?

MSuhe
Associate III

Thanks Bob for you response. Please find the details as below:

  • Just to be clear, the external device in our project is a radio device with baseband controller.
  • And "data" from the external device read by MCU on getting the ISR, is nothing but the interrupt status registers for different events on the radio like (TX done, RX start, RX done etc...).

Now getting to your queries:

> While ISR is reading 1 set of data, device receives a 2nd set of data

  • Now as i mentioned in my other post, the moment i read all the data "interrupt status registers", external device drives the I/O line low.
  • Your question is perfectly valid, what could happen is after reading all the interrupt status registers from the external device, I/O line is driven low. And while MCU is executing the ISR handler, there are new events and some interrupt flags are set again, causing the external device to drive the line high again. But then this is altogether a new edge right and this should be captured by EXTI?

> does it keep reading data as long as the I/O line is high)?

  • No, we just read the data when the I/O line is high and exit. And do not check for the status of the I/O line. Probably a good thing to do. But, there are other limitations that prevent us from doing this.

> No, we just read the data when the I/O line is high and exit. And do not check for the status of the I/O line. Probably a good thing to do.

It's *necessary* to do so. This is the very root of your problem. There can't be a rising edge, if the signal remains high...

JW

Thanks for your response. Now i have added a check to verify if the I/O line is still high. And if true, attempt reading the data from the external device. This has definitely brought improvements, but has not fully fixed the issue.

Because, till now the workaround what we had for identifying missing edge interrupts and mitigating lock-up was with an API "radio_isr_kick()". This will be called from the FreeRTOS thread. And all "radio_isr_kick()" API does is,

  1. Check if the external I/O line is high.
  2. If yes, execute the external interrupt ISR handler.

And with the help of some flags i still see that, ISR handler gets executed from within "radio_isr_kick()". Which means the I/O line was high and EXTI somehow did not capture the edge.

Can you post the code from your interrupt function? You can remove the radio-specific code and replace it with a "radio stuff here" comment. And how are you "executing" the ISR handler from your kick function - using the EXTI_SWIER register? The status/interrupt output from your radio is not really an edge sensitive interrupt signal, it is a level sensitive signal. It appears that somehow your ISR is somehow exiting with the signal still asserted.