I am experimenting with the STM32f4
discovery and i tried to use a delay (based on SYSTICK
) in an EXTI_IRQ
handler but i figured out that while the EXTI
handler is triggered the the systick
handler doesn't trigger , here's my code :
extern volatile int del ;
void EXTI0_IRQHandler(void) {
if (EXTI_GetITStatus(EXTI_Line0) != RESET ) {
/* Do your stuff when PD0 is changed */
del=1000 ;
while(del)
{
//do something
}
/* Clear interrupt flag */
EXTI_ClearITPendingBit(EXTI_Line0);
}
}
And the systick handler :
void SysTick_Handler(void)
{
if (del--)
;
}
So how can i solve this problem .
-
\$\begingroup\$ on most CPUs, interrupts have an order of precedence. A higher precedence interrupt will mask a lower precedence interrupt while the higher precedence interrupt is being handled. \$\endgroup\$user3629249– user36292492016年03月25日 19:54:34 +00:00Commented Mar 25, 2016 at 19:54
2 Answers 2
You can, if your processor allows it (it should, since I believe all of that series are Cortex M4 based), set the Systick Interrupt to a higher priority than the other interrupts and then find out if you can make your compiler/processor not turn off interrupts globally while processing an interrupt.
That is, if you want to have delays in your interrupts.
Hint: You shouldn't want that.
Interrupts are meant to run efficiently and quickly to handle important events that are critical. If something needs a delay beyond a couple of ASM("__volatile__ NOP\n NOP\n NOP\n")
's, it's probably not something you want in your interrupt.
If you have a "heavy task" that gets triggered by an interrupt it's much neater to write:
uint32_t taskFlags; // semafore register, can also be any other data type that fits your flags (1ul --> uint32_t or larger!)
#define HANDLE_MY_INTERRUPT_STUFF (1ul<<0) // Define a flag for interrupt things.
void main(void) {
while(1) {
if(taskFlags & HANDLE_MY_INTERRUPT_STUFF) { // Check the flag
// Do your interrupt stuff
// Allowed to have many delays and other weird stuff
taskFlags &= ~HANDLE_MY_INTERRUPT_STUFF; // Clear the flag.
}
}
}
InterruptHandler(void) {
taskFlags |= HANDLE_MY_INTERRUPT_STUFF; // set the flag
}
And now suddenly all that heavy processing gets done in the main loop, where it can be interrupted and all and won't harm any other time-critical things. But only triggered by the interrupt source, through the flags.
Although through the flags you will of course risk a slight variable delay in execution, it's always a balancing act.
Late addition:
Between processor types the delay will usually be between 4 and 40 clock cycles + average other interrupt code execution, so at a couple MHz using a 10ms delay will usually already marginalise that delay and its variation.)
-
\$\begingroup\$ but what if it's the case when you need to denounce a button ( the case of interruption triggered with push button ) with a delay i know i can make delay with a for loop but it's a bad solution . \$\endgroup\$starter– starter2016年03月24日 01:21:33 +00:00Commented Mar 24, 2016 at 1:21
-
1\$\begingroup\$ @starter see the second part. Anything you do inside the interrupt can be done in the main with a flag. It's that simple. \$\endgroup\$Asmyldof– Asmyldof2016年03月24日 01:58:47 +00:00Commented Mar 24, 2016 at 1:58
-
\$\begingroup\$ thank you that was helpful , i was over complicating life . \$\endgroup\$starter– starter2016年03月24日 07:28:39 +00:00Commented Mar 24, 2016 at 7:28
This is the simplest solution to do:
extern __IO uint32_t TimmingDelay;
void Delay(__IO uint32_t time)
{
TimmingDelay = time;
while(TimmingDelay != 0);
}
This is in stm32f4xx_it.c:
void SysTick_Handler(void)
{
if(TimmingDelay != 0)
{
TimmingDelay --;
}
}
In main don't forget to add this line:
SysTick_Config(SystemCoreClock/1000000);
and then use Delay("AddDelayHere"); and spam all over your code.
-
1\$\begingroup\$ This isn't guaranteed to solve the interrupt conflict \$\endgroup\$Asmyldof– Asmyldof2016年03月24日 00:40:17 +00:00Commented Mar 24, 2016 at 0:40