cancel
Showing results for 
Search instead for 
Did you mean: 

STM32 NVIC lower priority Interrupt doesn't work again after being preempted by the interrupt with the higher priority.

ABuyu.1
Associate II

Hello,

I am using stm32f4 discovery. I wrote 2 interrupts to blink LEDs in different speeds to write an example for NVIC. I have 1 question that I wonder about and 2 issues I couldn't solve. Here is the situation :

All interrupts work well seperately. Also lower interrupt works well after higher interrupt is done if it isn't broken due to issue 2.

Question 1: Is NVIC grouping works local or global? If it works global then it might mess up all the configurations that was set before the last one. (My code uses only groupconfig(3) so this isn't the reason of the issues I am getting. I just asked to be sure about it)

Question 2: Isn't interrupt with the lower priority supposed to return where it left after the interrupt with the higher priority is triggered while interrupt with the lower priority working.

Issue 1: Both interrupts work well when they are seperately executed. Also when interrupt with the higher priority triggered while the lower priority interrupt working, It stops and go to handle higher priority interrupt. But it doesn't return back to the where it left the line of interrupt with the lower priority and finish it.

Issue 2: Interrupt with the lower priority stops working after the issue 1. It never works again till I reset the mcu or reload the code which is simply doing the same.

#include "stm32f4xx.h"                  // Device header
 
//Breadboard button PB1
//Button PA0
//LED PD12,PD13,PD14,PD15
 
void SystickDelayms(int n);
 
int priority = 0;
 
int main(void)
{
	__disable_irq();  // Disable Interrupts
	
	// Discovery Board Push Button Configurations
	RCC->AHB1ENR |= 0x1; // Enable Clock PA
	GPIOA->MODER |= 0x0; // Configure PA0 as input
	
	// Breadboard Push Button Configuration
	RCC->AHB1ENR |= 0x2; // Enable Clock PB
	GPIOB->MODER  |= 0x00; // Configure PB1 as input
	GPIOB->PUPDR |= 0x4;   // Enable internal pull up resistor for PB1
	
	// LED Configurations
	RCC->AHB1ENR |= 0x8; // Enable Clock PD
	GPIOD->MODER |= (1 << 24) | (1 << 26) | (1 << 28) | (1 << 30); // Configure PD12 as output
	GPIOD->ODR = 0x0000;
	
	// Interrupt Configurations for PA0 Push Button
	RCC->APB2ENR |= (1 << 14); // Enable SYSCFG Clock for Interrupts
	// Set PA0 as external interrupt by making first byte of EXTICR[0] 0.
	SYSCFG->EXTICR[0] |=  0x0; 
	EXTI->IMR  |= 0x1;				 // Unmask the PA0 Interrupt
	EXTI->FTSR |= 0x1;         // Set PA0 interrupt as falling edge triggered
	
	NVIC_SetPriorityGrouping(3); // STM32 Default 2. It can be set up to 4
  NVIC_SetPriority(EXTI0_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 0x2, 0x0));
	// NVIC SetPriority Writes Group Priority, Preempt Group Bits and Subpriority Bits
	//NVIC_SetPriority(EXTI0_IRQn, 0x3); 
	//NVIC->IP[EXTI0_IRQn] = 0x30;
	priority = NVIC_GetPriority(EXTI0_IRQn); // Gets Preempt priority
	NVIC_EnableIRQ(EXTI0_IRQn); // Enable EXTI0 Interrupt
	
	// Interrupt Configurations for PB1 Push Button
	RCC->APB2ENR |= (1 << 14); // Enable SYSCFG Clock for Interrupts
	// Set PB1 as external interrupt by making second byte of EXTICR[0] 1.
	SYSCFG->EXTICR[0] |= 0x10;
	EXTI->IMR |= 0x2;			// == 0x2 Unmask the PB1 Interrupt
	EXTI->FTSR |= 0x2;					// Set PB1 Interrupt as falling edge triggered
	
	NVIC_SetPriorityGrouping(3);
	NVIC_SetPriority(EXTI1_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 0x3, 0x0));
	//NVIC_SetPriority(EXTI1_IRQn, 0x2);
	//NVIC->IP[EXTI0_IRQn] = 0x20;
	priority = NVIC_GetPriority(EXTI1_IRQn);
	NVIC_EnableIRQ(EXTI1_IRQn);
	
	__enable_irq();  // Enable Interrupts
	
	while(1)
	{
		
	}
}
 
void EXTI0_IRQHandler(void)
{
	EXTI->PR |= 0x1;
	
	GPIOD->ODR ^= (1 << 12) | (1 << 14) | (1 << 13) | (1 << 15); // EXOR, means not for 12,13,14,15
	SystickDelayms(200);
	GPIOD->ODR ^= (1 << 12) | (1 << 14) | (1 << 13) | (1 << 15);
	SystickDelayms(200);
	GPIOD->ODR ^= (1 << 12) | (1 << 14) | (1 << 13) | (1 << 15);
	SystickDelayms(200);
	GPIOD->ODR ^= (1 << 12) | (1 << 14) | (1 << 13) | (1 << 15);
	SystickDelayms(200);
	GPIOD->ODR ^= (1 << 12) | (1 << 14) | (1 << 13) | (1 << 15);
	SystickDelayms(200);
	GPIOD->ODR ^= (1 << 12) | (1 << 14) | (1 << 13) | (1 << 15);
	SystickDelayms(200);
	GPIOD->ODR ^= (1 << 12) | (1 << 14) | (1 << 13) | (1 << 15);
	SystickDelayms(200);
	GPIOD->ODR ^= (1 << 12) | (1 << 14) | (1 << 13) | (1 << 15);
	SystickDelayms(200);
	GPIOD->ODR ^= (1 << 12) | (1 << 14) | (1 << 13) | (1 << 15);
	SystickDelayms(200);
	GPIOD->ODR ^= (1 << 12) | (1 << 14) | (1 << 13) | (1 << 15);
	
	//EXTI->PR |= 0x1; // Clear the Pending Register before leaving the interrupt by setting it to 1
}
 
void EXTI1_IRQHandler(void)
{
	EXTI->PR |= 0x2; // I tried to change this to 0x3 to solve the problem. It didn't work
	
	GPIOD->ODR ^= (1 << 12) | (1 << 14) | (1 << 13) | (1 << 15); // EXOR, means not for 12,13,14,15
	SystickDelayms(1000);
	GPIOD->ODR ^= (1 << 12) | (1 << 14) | (1 << 13) | (1 << 15);
	SystickDelayms(1000);
	GPIOD->ODR ^= (1 << 12) | (1 << 14) | (1 << 13) | (1 << 15);
	SystickDelayms(1000);
	GPIOD->ODR ^= (1 << 12) | (1 << 14) | (1 << 13) | (1 << 15);
	SystickDelayms(1000);
	GPIOD->ODR ^= (1 << 12) | (1 << 14) | (1 << 13) | (1 << 15);
	SystickDelayms(1000);
	GPIOD->ODR ^= (1 << 12) | (1 << 14) | (1 << 13) | (1 << 15);
	SystickDelayms(1000);
	GPIOD->ODR ^= (1 << 12) | (1 << 14) | (1 << 13) | (1 << 15);
	SystickDelayms(1000);
	GPIOD->ODR ^= (1 << 12) | (1 << 14) | (1 << 13) | (1 << 15);
	SystickDelayms(1000);
	GPIOD->ODR ^= (1 << 12) | (1 << 14) | (1 << 13) | (1 << 15);
	SystickDelayms(1000);
	GPIOD->ODR ^= (1 << 12) | (1 << 14) | (1 << 13) | (1 << 15);
 
	//EXTI->PR |= 0x2; // Clear the Pending Register before leaving the interrupt by setting it to 2
}
 
void SystickDelayms(int n)
{
	SysTick->LOAD = 16000 ; // Reload with number of clocks per milisecond
	SysTick->VAL  = 0;      // Clear current value register
	SysTick->CTRL = 0x5;    // Enable Systick
	
	for(int i = 0; i < n; i++)
	{
		// Wait until the COUNT Flag set
		while((SysTick->CTRL & 0x10000) == 0)
		{}
		// i++ when the COUNT flag set
	}
	SysTick->CTRL = 0; // Disable Systick
}

1 ACCEPTED SOLUTION

Accepted Solutions
Pavel A.
Evangelist III

In addition to the previous reply:

> Question 2: Isn't interrupt with the lower priority supposed to return where it left after the interrupt with the higher priority is triggered

Yes, sure. If a higher priority interrupt hits when SystickDelayms is in loop (lines 129-130) it will reenter SystickDelayms and leave it with SysTick->CTRL = 0; (line 133).

Now it returns to the low prio handler and hangs there.

-- pa

View solution in original post

4 REPLIES 4
TDK
Guru

> Question 1: Is NVIC grouping works local or global? If it works global then it will mess up all the configurations that was set before the last one.

NVIC is a global setting. You can open the function and see it modifies registers. You should set this prior to setting any interrupt priorities, and then leave it alone.

> Question 2: Isn't interrupt with the lower priority supposed to return where it left after the interrupt with the higher priority is triggered while interrupt with the lower priority working.

If a higher priority interrupt preempts a lower priority interrupt, execution will return to the lower priority interrupt after the higher priority interrupt is finished executing.

If you feel a post has answered your question, please click "Accept as Solution".
Pavel A.
Evangelist III

In addition to the previous reply:

> Question 2: Isn't interrupt with the lower priority supposed to return where it left after the interrupt with the higher priority is triggered

Yes, sure. If a higher priority interrupt hits when SystickDelayms is in loop (lines 129-130) it will reenter SystickDelayms and leave it with SysTick->CTRL = 0; (line 133).

Now it returns to the low prio handler and hangs there.

-- pa

Thanks for kind explanation.

Thanks for showing me my mistake Pavel. I was so focused on interrupt priority couldn't realize about the function.