cancel
Showing results for 
Search instead for 
Did you mean: 

Software interrupt on STM32L4

Clonimus74
Senior II
Posted on June 12, 2018 at 10:34

Hi all,

I try to create a software interrupt in STM32L476.

This is the software interrupt enable code

HAL_NVIC_SetPriority(EXTI1_IRQn, 3, 0);

HAL_NVIC_EnableIRQ(EXTI1_IRQn);

LL_EXTI_EnableIT_0_31(LL_EXTI_LINE_1);

LL_EXTI_EnableEvent_0_31(LL_EXTI_LINE_1);

This is the interrupt trigger code

  LL_EXTI_GenerateSWI_0_31(LL_EXTI_LINE_1);

The interrupt is not generated, how come? what am I missing?

The datasheet says the following:

14.3.6 Software interrupt/event selection

Any of the configurable lines can be configured as a software interrupt/event line. The

procedure to generate a software interrupt is as follows:

1. Configure the corresponding mask bit (EXTI_IMR, EXTI_EMR).

2. Set the required bit of the software interrupt register (EXTI_SWIER).

This is exactly what I'm doing. 'normal' interrupts work.

#software-interrupt #stm32l4
1 ACCEPTED SOLUTION

Accepted Solutions
Clonimus74
Senior II
Posted on June 12, 2018 at 12:07

The only thing I found working was the following:

Software interrupt enable code

HAL_NVIC_SetPriority(EXTI1_IRQn, 3, 0);

HAL_NVIC_EnableIRQ(EXTI1_IRQn);

Interrupt trigger code

NVIC->STIR =

EXTI1_IRQn

;

I trigger the software interrupt within another interrupt that has higher preemption, the software interrupt can take a long time so there's a risk of re-entring the IRS while it is still active. Using this method there's no risk of re-entering the software interrupt if it is still ongoing ( LL_EXTI_GenerateSWI_0_31 method was supose to take care of that as well but it doesn't trigger the interrupt), i.e. if the software interrupt is still active NVIC->STIR = EXTI1_IRQn will have no effect.

View solution in original post

6 REPLIES 6
Clonimus74
Senior II
Posted on June 12, 2018 at 12:07

The only thing I found working was the following:

Software interrupt enable code

HAL_NVIC_SetPriority(EXTI1_IRQn, 3, 0);

HAL_NVIC_EnableIRQ(EXTI1_IRQn);

Interrupt trigger code

NVIC->STIR =

EXTI1_IRQn

;

I trigger the software interrupt within another interrupt that has higher preemption, the software interrupt can take a long time so there's a risk of re-entring the IRS while it is still active. Using this method there's no risk of re-entering the software interrupt if it is still ongoing ( LL_EXTI_GenerateSWI_0_31 method was supose to take care of that as well but it doesn't trigger the interrupt), i.e. if the software interrupt is still active NVIC->STIR = EXTI1_IRQn will have no effect.

Posted on June 12, 2018 at 22:49

The following code which attempts to replicate the code snippets from your first code works on L4 DISCO as intended - when pressing the joystick's DOWN direction, the LED in the EXTI1 ISR toggles.

So you either made some mistake in the code you did not show us, or there's some bug in Cube/LL (or both 🙂 )

JW

// (C)2018 wek at efton dot sk// simple extint example// https://community.st.com/0D50X00009XkfHrSAJ// 'L476 DISCO// RED LED on DISCOL4 is PB2// PA5 - JOY_DOWN// pressing JOY_DOWN triggers EXTI1, which in ISR toggles the red LED// default 4MHz MSI clock#include <stdint.h>#include 'stm32l476xx.h'#include 'stm32l476xxx_augment.h'#include 'common.h'// -------- trivial loopdelayvolatile uint32_t __attribute__((section('.ram2'))) delayN;void LoopDelay(uint32_t n) { delayN = n; while(delayN > 0) delayN--;}#define DELAY_CONSTANT 50000// ISRvoid EXTI1_IRQHandler(void) __attribute__((interrupt));void EXTI1_IRQHandler(void) { uint32_t pr; pr = EXTI->PR1 & (1 << 1); EXTI->PR1 = pr; // clear pending interrupts by writing 1 if (pr & (1 << 1)) { // toggle LED if (GPIOB->ODR AND (1 << 2)) { GPIOB->BSRR = (1 << 2) << 16; } else { GPIOB->BSRR = (1 << 2); } }}// -------- mainint main(void) { RCC->AHB2ENR |= 0 | RCC_AHB2ENR_GPIOAEN | RCC_AHB2ENR_GPIOBEN ; GPIOA->PUPDR = (GPIOA->PUPDR & (~GPIO_PUPDR_PUPD5) ) | (0 | (GPIO_PullDown * GPIO_PUPDR_PUPD5_0) // JOY surprisingly switches to +3V! ); ; GPIOA->MODER = (GPIOA->MODER & (~GPIO_MODER_MODER5) ) | (0 | (GPIO_Mode_In * GPIO_MODER_MODER5_0) // PA5 - JOY_DOWN - TIM2_CH1 ); GPIOB->MODER = (GPIOB->MODER & (~GPIO_MODER_MODER2) ) | (0 | (GPIO_Mode_Out * GPIO_MODER_MODER2_0) // PB2-RED LED ); NVIC_SetPriority(EXTI1_IRQn, 3); // Set priority NVIC_EnableIRQ(EXTI1_IRQn); EXTI->IMR1 = 1 << 1; EXTI->EMR1 = 1 << 1; // this is not needed, but we add it to mimic the code in post while(1) { static _Bool down; unsigned i; #define DEBOUNCE_CNT 4000 if (down) { if ((GPIOA->IDR & GPIO_IDR_ID5_Msk) == 0) down = 0; } else { for (i = 0; i < DEBOUNCE_CNT; i++) { if ((GPIOA->IDR & GPIO_IDR_ID5_Msk) == 0) break; } if (i == DEBOUNCE_CNT) { down = 1; EXTI->SWIER1 = 1 << 1; } } }}�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?

Posted on June 13, 2018 at 10:24

 ,

 ,

that is very odd, can't think of a reason why it wouldn't work for me and it does on ,

L4 DISCO.

I use the latest STM32L4 library.

The code I showed you is the one I use, not much beyond that (except that I don't use ,

EXTI1_IRQn I use a define, i.e. ,

♯ define ,SYS_TICK_EVENT_INT_IRQ ,  ,  ,  ,  ,

EXTI1_IRQn

and then ,

HAL_NVIC_EnableIRQ(SYS_TICK_EVENT_INT_IRQ),

But that doesn't change anything...

The only thing I neglected to mention in the OP (but is mentioned in the following comment) it that the trigger of the SWI is done within the SysTick ISR.

Posted on June 13, 2018 at 10:54

I'd read back and check the EXTI registers content after the triggering, and also check in disassembled binary whether the interrupt routine's address is properly inserted into the vector table.

JW

Posted on June 14, 2018 at 12:11

Thanks

Waclawek.Jan

‌, you comment pushed me towards the solution, it was a classic race condition.

The interrupt is triggered within SysTick, which is active before the function that enables the software interrupt.So, since the bit inSWIER1 is set before the interrupt is enabledthe interrupt is not triggered.

So the SWI enable function should look like this:

HAL_NVIC_SetPriority(EXTI1_IRQn, 3, 0);

HAL_NVIC_EnableIRQ(EXTI1_IRQn);

LL_EXTI_EnableIT_0_31(LL_EXTI_LINE_1);

LL_EXTI_EnableEvent_0_31(LL_EXTI_LINE_1);

__disable_interrupt();

EXTI->SWIER1 &= ~

LL_EXTI_LINE_1

;

__enable_interrupt();

And of course add

LL_EXTI_ClearFlag_0_31(

LL_EXTI_LINE_1

);

at the end of the ISR to prevent reentrancy.

Now I come to wonder if the second method (using only NVIC) is not better, since it uses less code, and inherently prevents

reentrancy (without the need to clear any flags within the ISR)

Posted on June 14, 2018 at 12:24

Yes, the requirement to generate a 0-to-1 transition in SWIER1  for the interrupt to be triggered, is an unpleasant (and probably also unnecessary) gotcha...

And, of course, using NVIC directly sounds to be better (I can't see any reason why not), so why not using it, even if it is not the 'designated' method...

JW