cancel
Showing results for 
Search instead for 
Did you mean: 

STM32H7B3I - Receiving an unknown interrupt on the EXT9_5 after clearing the interrupts on all lines 5 - 9.

Garnett.Robert
Senior III

Hi,

I have the following code: which clears the WXTI9_5 interrupts, enables the EXTI9_5 interrrupts and provides an interrupt handler for these.

void clearAll_EXTI9_5_IRQ(void)
{
	__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_5);
	__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_6);
	__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_7);
	__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_8);
	__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_9);
}
 ...
  clearAll_EXTI9_5_IRQ();
  HAL_NVIC_EnableIRQ(EXTI9_5_IRQn);
 
/**
  * @brief This function handles EXTI line[9:5] interrupts.
  * GPIO_PIN_5 is the WiFi Ready status
  */
uint16_t flagInt;
void EXTI9_5_IRQHandler(void)
{
	BaseType_t xHigherPriorityTaskWoken = pdFALSE;
	flagInt = 0;
 
  if (__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_5) != 0x00U)
  {
  	/* DataReady Pin Rising */
  	__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_5);
  	wiFiRdyState = true;
  	xSemaphoreGiveFromISR(wiFiReadySemHandle, &xHigherPriorityTaskWoken);
  	portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
  	return;
  }
 
  if(__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_8) != 0x00U)
  {
		__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_8); /* SD Card detect */
  	return;
  }
 
  if(__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_6) != 0x00U)
  {
		__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_6); /* NIU */
  	return;
  }
 
  if(__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_7) != 0x00U)
  {
		__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_7); /* NIU */
  	return;
  }
 
  if(__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_9) != 0x00U)
  {
		__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_9); /* NIU */
  	return;
  }
 
  /* What interrupt is this? */
  flagInt = 1;
}

I am using the line 5 interrupt on a rising edge and that works fine.

However before I initiate a SPI transaction which results in Line 5 asserting on completion, I get an interrupt which does not match any of the lines and I end up at line 58 i.e. flagInt = 1;

This is in spite of the fact that I clear all of the interrupts for EXTI9_5 and I have checked that there are no other active pins floating that could cause this. I also checked that I only enabled the EXTI9_5 once.

I have seen another question similar to this and putting __DSB()'s before the returns was the fix, but I do not seem to be missing genuine interrupts in the 5 - 9 range I just get the extra one at the start.

I would like to nail it down because rogue interrupts can cause nastiness to occur in complex projects.

Any ideas?

Regards

Rob

13 REPLIES 13

> clearAll_EXTI9_5_IRQ();

> HAL_NVIC_EnableIRQ(EXTI9_5_IRQn);

If there were pending interrupts in EXTI before you called clearAll_EXTI9_5_IRQ(), there may be an interrupt thrown immediately after the enable. Reason is, that it takes time until changes in EXTI pending register propagate to NVIC.

Unfortunately, there is probably no universally good solution. I tried to tackle this on an 'F4, clearing first the interrupt source (here EXTI, I experimented with TIM, but there is no difference in this regard) then interrupt pending in NVIC, but I found out that due to the undocumented internal timing if I did this quickly enough, the interrupt in EXTI "reappeared" after a few cycles. You may need to perform a similar experiment for your 'H7 (which is inifinitely more complex than 'F4) and ascertain, what influences might make one particular such assesment void (e.g. changing APB divider).

JW

S.Ma
Principal

Check the pin level in the interrupt, disable the interrupt once happening, and use a timer delayed interrupt to reenable them after some programmable ignore time. Maybe the EXTI needs optional filtering like timer input captures.....

Garnett.Robert
Senior III

Hi,

I put an operating system vTaskDelay between the clearing and enabling AND a CPU time delay loop and I still get an interrupt that doesn't match the input pins 5 to 9.

HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_5);
	clearAll_EXTI9_5_IRQ();
	vTaskDelay(2);
        timeDelay_usec(100);
        HAL_NVIC_EnableIRQ(EXTI9_5_IRQn);

Still got the unidentifiable interrupt! 

I did think about a timer using a digital filter, but I've run out of timers for this project. But in any event the interrupt that is occurring doesn't match any of the external interrupt pins I'm using; the data ready from the WiFi module and the SD Card switch. Which one of the two would I put the timer on?

What is generating this interrupt; it's not one of my two pins.

I would like an answer from ST, they designed the chip surely they should be able to advise.

If there is a problem with the silicon then fess up, at least I would know what I'm facing.

In fact given the size of the interrupt space for the H7 why not have a separate interrupt for each of the 16 external interrupt pins? This business of having to work out "which pin was that" is an unnecessary delay in processing interrupts.

It's ridiculous!

Best regards

Rob

S.Ma
Principal

Test by clearing the PR bit at the very end of tge interrupt.

Outside the ISR, you have to clear also the NVIC pending bit, as I did in the post linked above.

0693W00000KdIVGQA3.png 

> I would like an answer from ST,

Then ask them. This is a primarily user-driven forum, with casual ST presence.

> why not have a separate interrupt for each of the 16 external interrupt pins?

I'm sure ST will gladly produce an mcu as per your specifications, given enough incentives (expressed usually in M$s). Otherwise, it's a tradeoff between capabilities and silicon real estate (= unit cost).

JW

Hi JW,

Rogue Interrupt

To save time, (I'm getting on a bit), I assumed that the code in the HAL GPIO External interrupt handler was sufficient to clear ALL of the necessary register bits. When I first detected this odd interrupt I had read the extract of the manual you posted, but it didn't mention time delays between clearing the flag and the flag being cleared. I initially thought that maybe there was another input that was floating and causing the interrupt to occur so that clearing put the interrupt into an Active state, but the only other interrupt in that group than had an active input was the SD card insertion pin. I disabled this pin so that it wasn't configured as an interrupt.

You said in your reply above:

If there were pending interrupts in EXTI before you called clearAll_EXTI9_5_IRQ(), there may be an interrupt thrown immediately after the enable. Reason is, that it takes time until changes in EXTI pending register propagate to NVIC.

I read the STM32 Gotchas article and thought that if the problem were bus times delays they wouldn't be more than a ten or so microseconds.

I did take all this on-board (pardon the pun) and put an operating system time delay of 2 ticks = 2 ms and a loop delay of 100us between the clear interrupts and the enable interrupts thinking this would be plenty of time for the EXTI pending register to propagate to the NVIC, but it didn't fix the problem. So I'm unclear what the problem is and what options I have to fix the issue. It almost seems like the NVIC reset data gets off at the wrong bus stop.

Its an intriguing problem; I will make a small project and do some experiments as you suggested.

Ask ST:

If you mean ask them on the Support Portal, I have tried this many times and have been almost universally disappointed. In most cases I haven't had any reply and the support ticket was cancelled. In one case I couldn't get Cube to generate Keil projects. I raised a support ticket and they did reply, they then shifted the problem the forum where we unsuccessfully tried to sort the problem out and ST spent a lot of effort on it. In that case I don't think it was an ST Problem I'm pretty sure it was a problem with my PC. I have had a lot more luck with the forum. I am not criticizing ST here. I'm only a hobbyist who will only ever purchase 0.00...001% of the chips ST make so I am always going to be down the list when it comes to free support. I don't have a problem with this, so I use the forum. I have posted quite a few questions lately and an ST employee has answered them within a day or two, and they have been very helpful.

Separate Interrupts:

Surely I'm allowed to have a little whinge about their processors. I really do think that they are excellent processors, love the ADC's, love the memory layout, MPU, love the Random Number Gen, floating point and doubles etc etc. Also like the Eco-System and TouchGFX. I used to use Keil uVision. It's very robust, very fast and has excellent compilers, but the interface is is a bit old and tired. CubeMX IDE whilst a bit slow, has much better features than uVision such as the Build Analyzer, excellent data transfer features, really good break-point features etc, etc, etc.

Any way I will take your advice about experimenting.

Thanks for your help

Rob

Pavel A.
Evangelist III

@Garnett.Robert (Community Member)

As Jan and others wrote, H7 is complicated. There can be delayed/buffered writes that require explicit flush (DSB) and even this not always is enough, requires a read-back or even worse.

IMHO your experiment with added delays is not 100% convincing.

To avoid wasting time IMHO you only need to check that unknown cases in shared EXTI hander go away in "short" time : there are no more than N handler calls in a row, before a good handler call.

Your diligence is a good thing but here you're chasing a known chupacabra.

> I assumed that the code in the HAL GPIO External interrupt handler was sufficient to clear ALL of the necessary register bits

It is, but only if you are executing the ISR. But from non-interrupt context, you have to explicitly clear also the NVIC pending bit (see NVIC_ICPRx register). This is what I quoted above: if the interrupt kicks in, it clears this bit in hardware; but if it's not the interrupt context, you have to do it yourself.

So the procedure is:

  • clear the interrupt source (by writing to EXTI pending register)
  • wait - this is the tricky part
  • clear the NVIC pending bit (by writing to NVIC_ICPRx, for which CMSIS provides the NVIC_ClearPendingIRQ() function)
  • here wait shouldn't be necessary, but I am not entirely sure
  • enable the interrupt in NVIC

JW

Garnett.Robert
Senior III

Hi

I think? I've figured it out.

For an interrupt from say a DMA controller when a transmission is complete or there is an exception (error) the interrupt is raised in the NVIC and when the interrupt gets serviced the interrupt handler sorts out which interrupts were triggered at the peripheral level, executes handler functions if defined, then clears the peripheral interrupts. When the interrupt request function is returned by some magic the NVIC pending/active reg's clear and no more interrupts until the peripheral says so.

The multi-input interrupts on return however do NOT appear clear the interrupts in the NVIC reg's. So that on returning from the interrupt you get some more unsolicited interrupts.

What you seem to have to do is check all the multi-input interrupt flags and then after doing your stuff, execute a 

NVIC_ClearPendingIRQ(EXTI9_5_IRQn)

statement.

Viz:

#define CHK_LINE_IRQ_5 0 /* NIU */
#define CHK_LINE_IRQ_6 0 /* NIU */
#define CHK_LINE_IRQ_7 0 /* NIU */
#define CHK_LINE_IRQ_8 1 /* uSDCardInserted */
#define CHK_LINE_IRQ_9 1 /* Test interrupt connected to PH9 (output mode) */
 
/**
  * @brief This function handles EXTI line[9:5] interrupts.
  */
void EXTI9_5_IRQHandler(void)
{
 
#if(CHK_LINE_IRQ_5 == 1)
  if (__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_5) != 0x00U)
  {
  	/* DataReady Pin Rising */
  	__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_5);
  }
#endif
 
#if(CHK_LINE_IRQ_6 == 1)
  if(__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_6) != 0x00U)
  {
		__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_6); /* SD Card detect */
  }
#endif
 
#if(CHK_LINE_IRQ_7 == 1)
  if(__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_7) != 0x00U)
  {
		__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_7); /* NIU */
  }
#endif
 
#if(CHK_LINE_IRQ_8 == 1)
  if(__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_8) != 0x00U)
  {
		__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_8); /* NIU */
  }
#endif
 
#if(CHK_LINE_IRQ_9 == 1)
  if(__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_9) != 0x00U)
  {
		__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_9); /* NIU */
  }
#endif
  /* Clear NVIC Interrupts for these lines */
  NVIC_ClearPendingIRQ(EXTI9_5_IRQn);
}

This seems to do the trick.

I made a little project to test all of this and have attached it. I used PH9 as an output into PI9 which is the interrupt pin available on the connector. You can set PH9 high or skip setting it by changing the value of userFlag in main.c with the deburgler. This tests the case for no interrupt and one interrupt respectively.

Anyway chew it over and see whether I'm on the right track.

Best regards

Rob