2020-03-27 02:59 PM
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
}
Solved! Go to Solution.
2020-03-27 04:06 PM
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
2020-03-27 03:23 PM
> 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.
2020-03-27 04:06 PM
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
2020-03-27 04:46 PM
Thanks for kind explanation.
2020-03-27 04:47 PM
Thanks for showing me my mistake Pavel. I was so focused on interrupt priority couldn't realize about the function.