STM32 using hardware interrupt flags without ISR - Page 1
Forum section: electronics / general

author: syntax333
author_rank: Regular Contributor
timestamp: March 09, 2020, 11:37:35 am
content: Hi, I was wondering if you can use only hardware interrupt flags without defining ISR. For example uC goes to sleep in certain FSM state. I want to wake the uC up by pressing external push button. For this I don't need to do something inside ISR so it would be empty. I just need to check the interrupt flag, if it is external interrupt(EXTI) then go to next state if not keep sleeping.Can I enable interrupts without defining ISR?Once, I didn't defined ISR for Systick timer which resulted uC to halt after 1ms and wait indefinitely. Is this default behavior for other interrupt sources?Thank you.

author: SiliconWizard
author_rank: Super Contributor
timestamp: March 09, 2020, 03:10:05 pm
content: You can use interrupt flags without enabling interrupts, certainly.But as long as you enable a specific interrupt, the corresponding ISR will get called. I don't really see a way around this.For your specific case - which is waking up due to an interrupt - I think you may have a way around this.You can define wakeup sources separate from interrupts. Think you have to use a 'wake from event' mode to put the MCU to sleep instead of 'wake from interrupt'. The external pins that would work as wakeup sources may be limited to specific wake pins depending on your exact MCU - look that up.Of course if that's too limited, you can still use a 'wake from interrupt' mode, enable the corresponding interrupt and just implement an empty ISR - that won't cost you that much.

author: ajb
author_rank: Super Contributor
timestamp: March 09, 2020, 03:59:31 pm
content: Quote from: SiliconWizard on March 09, 2020, 03:10:05 pmIn most ARM MCUs there's a multi-step process to calling an ISR:- Some sort of event happens that causes an interrupt flag to be set in the peripheral. At this stage, the interrupt flag is basically just another status flag in the peripheral.- If the interrupt corresponding to the flag is enabled in the peripheral, the peripheral will raise an interrupt request to the interrupt controller. Most peripherals have only one IRQ line but many possible interrupt sources, so you can enable only the interrupts you actually want to act on. For example, in a timer you might want an interrupt on overflow, but not compare match.- If the peripheral's interrupt line is enabled in the interrupt controller, only then will the NVIC execute the ISR as required by the ISR's priority and the current execution priority.Generally you don't need to enable a peripheral interrupt in order to allow the interrupt flag to be set (though this is peripheral dependent), so if you just need the flag to be set/cleared then you may not need to do anything else. Even if you do need to enable the interrupt in the peripheral, you don't necessarily need to enable it in the NVIC. You'll still get the IRQ, but it will never be scheduled for execution. Of course if you need other interrupt sources on the same peripheral to be handled via an ISR, then you DO need to enable the IRQ in the NVIC, and you'll just need to check what caused the interrupt in the ISR and clear any flags that you don't want to handle.

author: ataradov
author_rank: Super Contributor
timestamp: March 09, 2020, 05:02:19 pm
content: Yes, it is totally fine. I do that all the time. Interrupt flags are typically set whether you enable actual interrupt sources or not.But even if peripheral is strangely designed and you actually need to enable interrupt for the flags to be set (I have never see such peripherals), you can still enable the interrupt in the peripheral and don't enable it in the NVIC. So interrupt will never fire, but peripheral has no way of knowing it, so it will operate exactly the same way as if interrupts are fully enabled..Same with SysTick. There is a flag and a separate enable bit. The flag can be polled without interrupt handler being called. Again, this is a pretty typical way to use SysTick for blocking delays.

author: emece67
author_rank: Frequent Contributor
timestamp: March 09, 2020, 05:43:00 pm
content: .

author: bugnate
author_rank: Regular Contributor
timestamp: March 10, 2020, 06:31:04 pm
content: Can confirm, I have done this. WFE can do what you want but may or may not take some extra steps. I don't know your chip, but from a F10X series reference manual (RM0008):QuoteThat said, there isn't a whole lot of benefit to doing it this way as opposed to an empty/masked ISR as others have said. WFE typically has slightly better wake-up latency (because you don't jump). I suppose there might be some wake-up scenarios from Stop mode that require it. If what you have is a super loop and an EXTI is your only wake-up source, then yeah I guess this would be the most elegant, but not a big deal unless the latency was critical.

author: syntax333
author_rank: Regular Contributor
timestamp: March 11, 2020, 04:23:05 pm
content: Thank you for your responses I understand WFE "function" of STM32 now and use it the way as suggested.However, I got another question. As I understand from reference manual only way to wake up from WFE is trigger of external interrupt. What if I wanted to wake up from timer interrupt? Is it the same way as WFE?

author: ataradov
author_rank: Super Contributor
timestamp: March 11, 2020, 04:34:19 pm
content: What specific device you are using?There are two instructions for sleep in ARM cores. WFI is instruction that waits for any interrupt. It is directly tied to the NVIC, so it should always work.WFE waits on a system-level event. An "event" man be anything system designer decides it to be.In most cases you want to use WFI for sleep, unless specific system implements some special sleep modes.

author: syntax333
author_rank: Regular Contributor
timestamp: March 11, 2020, 05:03:25 pm
content: I am using STM32F4 Discovery board which has STM32F407VG.

author: ataradov
author_rank: Super Contributor
timestamp: March 11, 2020, 05:12:28 pm
content: This device operates in a vert typical way:QuoteSo in this case they decided to route the output of the EXTI to the event input. But the regular interrupts work too.Ans again, just use WFI. This use of WFE is really an abuse and not what it was designed for.

author: syntax333
author_rank: Regular Contributor
timestamp: March 11, 2020, 06:12:46 pm
content: Another question:How can a ISR be empty? For example I have a Finite State Machine that goes into sleep in one of its states with WFI and a timer is set to count 1 second. After 1 second when STM32 wakes up it will go immediately to ISR and want me to clear the interrupt flag right? If I clear the interrupt flag I cannot check the flag in my main FSM loop to switch state? or Is interrupt flag and pending bit to leave ISR is totally different thing.pseudo code example:Code:void main{while(1){state1{LED_TOGGLE;switch_state2;reset_start_timer;}state2{_WFI;if(Timer_Interrupt_Flag_Set){switch_state1}}}}void timer_ISR{Timer_Interrupt_Flag_Set = 0; //Clear interrupt flag so it won't go into ISR again}

author: ajb
author_rank: Super Contributor
timestamp: March 11, 2020, 06:30:22 pm
content: There are a couple of options. If the timer interrupt is the only one that's active, then after the WFI instruction you know that the timer interrupt was triggered without having to check the flag.If you really want to check the timer flag itself, then in the ISR you can disable to timer interrupt in the NVIC or by clearing the interrupt enable flag for that interrupt in the peripheral (check the datasheet to be sure this won't also clear the flag). That will leave the flag set but will prevent the ISR from running continuously.The simplest solution, though, is probably be to clear the peripheral flag and set your own flag in the ISR. Be sure to label the flag variable as volatile since it will need to be shared between two threads of execution.

author: Siwastaja
author_rank: Super Contributor
timestamp: March 15, 2020, 07:52:19 am
content: One option is to reconsider and using interrupts after all; and move the FSM into the interrupt handler(s); if you currently do something that takes a long time, take it out from the FSM first because you usually don't want to spend a lot of time in the interrupts.But this way, you can run the state machine with minimum latency, and in parallel with whatever application code you have in mind.One way to do this very efficiently is to divide each state into its own (interrupt handler) function, then do the state changes by modifying the (RAM-relocated) vector table inside those handler functions.An example with a timer interrupt driven FSM; you can of course use different interrupt sources as well.Code:#define VECTORS 0x0000FC00UL#define SET_TIM3_VECTOR(v) do{*((volatile uint32_t*)(VECTORS+0x00B4)) = (uint32_t)(v);}while(0)void init(){SET_TIM3_VECTOR(inthandler0); // initial state// Make TIM3 generate periodic interruptsRCC->APB1LENR |= 1UL<<1;TIM3->CR1 = 1UL<<3 /* one pulse mode */ | 1UL<<2 /*only over/underflow generates update int*/;TIM3->DIER |= 1UL; // Update interruptTIM3->PSC = 20-1; // Set the prescaler to generate 0.1us ticks.NVIC_SetPriority(TIM3_IRQn, 4);NVIC_EnableIRQ(TIM3_IRQn);}static inline void set_timer(uint16_t tenth_us){TIM3->ARR = tenth_us-1;TIM3->CR1 = 1UL<<3 /* one pulse mode */ | 1UL<<2 /*only over/underflow generates update int*/ | 1UL /* enable*/;}static void inthandler0(){TIM3->SR = 0UL;do_something;set_timer(delay_to_the_next_interrupt);// next state:if(something)SET_TIM3_VECTOR(inthandler1);elseSET_TIM3_VECTOR(inthandler2);}static void inthandler1(){...}