cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F101RD: Interrupt preemption not working

jansen
Associate II
Posted on October 03, 2014 at 16:52

System info: 8MHz external clock, 24MHz interrupt system clock.

Interrupt preemption is not working for me no matter the combination of priorities and priority groupings. My goal is to have a high speed timer interrupting every 0.1ms that doesn't get pushed round by other interrupts. Other interrupts include button and switch handlers via EXTIx inputs, UART interrupts for multiple serial inputs, and a couple other slow speed timers.

I'm using priority grouping 1, which gives me two priority groups, 0 & 1. I assume groups with lower priority are of higher preemption priority similar to interrupt priorities. Is this a good assumption?

My high speed timer uses TIM7 and is assigned to priority group 0, sub-priority of 0. This should be highest priority in the highest preemption priority group. All the other interrupts are in preemption priority group 1 with sub-priorities from 1 to 4. The TIM7 interrupt handler toggles a GPIO pin I can watch with an o-scope.

When I put this up on the o-scope and press buttons, I see TIM7 jitter around getting held off while the button handlers do their thing. The TIM7 interrupt is clearly not preempting the button handlers. Note, the button handlers do not disable the other interrupts via primask or basepri.

I feel I'm missing some fundemental setting here. What do I have to do to get preemption to work?

I've tried using SysTick instead of TIM7 and that gets held off, too. I don't see any means to assign SysTick to a priority group, unless the priority field for SysTick works the same as other interrupts.  Can SysTick be in a priority group or is it always in group 0? None of the ARM documentation indicates one way or the other.

Any help would be greatly appreciated! Thank you!

#stm32 #interrupts #preemption
18 REPLIES 18
chen
Associate II
Posted on October 03, 2014 at 17:11

Hi

My understanding is

'Priority Groups' are used when more than 1 IRQ/ISR is assigned to the same IRQ level, it gives the ISRs a defined priority within the same IRQ level.

Since you have so few IRQs, do not use the  group - just stick to the simple IRQ levels.

''

The TIM7 interrupt handler toggles a GPIO pin I can watch with an o-scope.

''

By this you mean that you toggle the IO pin with code?

This will be subject to higher priority ISRs, since this is the highest level the only other higher level is NonMaskable (NMI)

You can make the timer toggle the IO pin by directly (without code) connecting it to the IO pin. It is an Alternate function of the IO pin. There is a limit to which IO pins are attached to which Timers - check the data sheet for you specific part.

''

I don't see any means to assign SysTick to a priority group

''

That is correct. SysTick is a NMI.

(I am not sure what happens when another NMI occurs - there are rules regarding the priority levels for NMI but I do not remember what they are)

It is also a peripheral of the ARM core itself.

That means that it was provided by ARM to ST and is not the same as the other timers eg TIM7 that you are using.

It is a very different timer to the ST ones, you have probably notice how little in the way of things it can do.

Posted on October 03, 2014 at 17:14

Priority Grouping has global scope, you set it once

3. You can change the SysTick IRQ priority by calling the NVIC_SetPriority(SysTick_IRQn,...) just after the SysTick_Config() function call. The NVIC_SetPriority() is defined inside the core_cm3.h file.

void SysTick_Configuration(void)
{
/* Setup SysTick Timer for 1 msec interrupts */
if (SysTick_Config(SystemCoreClock / 1000))
{
/* Capture error */
while (1);
}
/* Set SysTick Priority to 3 - for 2-bit, 2-bit split*/
NVIC_SetPriority(SysTick_IRQn, 0x0C);
}

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
chen
Associate II
Posted on October 03, 2014 at 17:49

clive1 give absolutely correct information.

Take what he says over what I have said. Sorry if I have miss-led you.

jansen
Associate II
Posted on October 03, 2014 at 19:24

Clive, I read you code snip as setting SysTick to priority group 3, sub-priority 0. Is this correct? The higher order bits I think are the grouping.

I've setup the following:

Priority grouping 1: 1-bit for groups, 3-bits for priority

SysTick with priority set to 0 (NVIC_SetPriority(SysTick_IRQn, 0)

--This should be priority group 0, priority 0. The highest possible group and priority.

All other interrupts in priority group 1 with priorities from 1 to 4.

In this configuration, the SysTick interrupt is getting held off by the EXTIx interrupts. If I change SysTick to be in group 1 and the others in 0, SysTick is still pushed around by the EXTIx interrupts. If I change back to use TIM7 instead of SysTick I get the same results.

I'm expecting the handling of SysTick to be unaffected by the EXTIx interrupts. Is this just not possible with this platform? To be sure, I've checked to make sure interrupts are not being disabled somewhere. They're not.

Am I missing another setting somewhere?

Posted on October 03, 2014 at 20:28

Yes

SysTick is a ''System Handler'' so it will behave somewhat differently compared to NVIC sources. You can drive the priority.

I'm not sure how much ''jitter'' you're seeing, or the rate of the timer. Preemption is going to require a context push which might cause some additional deflection when comparing with/without a button push.

You'd want to double check what exactly is programmed into the NVIC grouping settings. You'd also want to make sure to clear the interrupt source early in the handler.

Suggest you post a complete/concise example demonstrating the issue.
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
jansen
Associate II
Posted on October 03, 2014 at 22:10

A background task handler is called from the TIM3 handler and the button handlers. It causes roughly 3.5ms delay to the high speed timer (TIM7 or SysTick) interrupt handler. The high speed timer interrupt is going off every 0.1ms. I use one of TIM7 or SysTick. My debugging lead me to create this build time choice. When I'm not pressing buttons, TIM7 or SysTick work great.

I just read some settings:

AIRCR: FA050600

IP[29]: C0 // TIM3

IP[55]: 00 // TIM7

ISER[0]: 308007C0

ISER[1]: 00B001A0

ISER[2]: 00000000

// Set interrupt priority grouping

NVIC_PriorityGroupConfig( NVIC_PriorityGroup_1 );

#ifdef USE_TIM7

// Enable TIM7 IRQ

NVIC_InitStructure.NVIC_IRQChannel = TIM7_IRQn;

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; // Group

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; // Priority

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

NVIC_Init( &NVIC_InitStructure );

#endif

// Enable TIM2 IRQ - Half Second State timer

NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; // Group

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; // Priority

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

NVIC_Init( &NVIC_InitStructure );

// Enable TIM3 IRQ - Background Task Timer

NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; // Group

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 4; // Priority

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

NVIC_Init( &NVIC_InitStructure );

// Enable UART1 interrupt

NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; // Group

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; // Priority

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

NVIC_Init( &NVIC_InitStructure );

..

.. UARTS 1,3,4,5 used

..

// Enable UART5 interrupt

NVIC_InitStructure.NVIC_IRQChannel = UART5_IRQn;

NVIC_Init( &NVIC_InitStructure );

// Button Interrupts

NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; // Group

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 4; // Priority

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

NVIC_Init( &NVIC_InitStructure );

..

.. // EXTI0 thru EXTI4

..

NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQn;

NVIC_Init(&NVIC_InitStructure);

// Switch interrupts

NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;

NVIC_Init(&NVIC_InitStructure);

NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;

NVIC_Init(&NVIC_InitStructure);

#ifdef USE_TIM7

void TIM7_IRQHandler( void )

{

  TIM_TypeDef *tim7 = TIM7;

  // Clear interrupt

  tim7->SR = 0;

  tickerHandler();

}

#else

void SysTick_Handler(void)

{

  tickerHandler();

}

#endif

void tickerHandler( void )

{

  ticker++;

// Toggles a PWM register TIMx->CCRx

  generate_pattern();

// Toggle test point connected to o-scope

  if( ticker & 1 )

  {

    // Set pin pb2 (tp1)

    GPIOB->BSRR = 0x00000004;

  }

  else

  {

    // Reset pin pb2 (tp1)

    GPIOB->BSRR = 0x00040000;

  }

}

void tickerInit( void )

{

#ifdef USE_TIM7

  TIM_TypeDef *tim7 = TIM7;

  tim7->CR1 = TIM_CR1_URS; // Default disabled.

  tim7->CR2 = 0x0000;

  tim7->DIER = TIM_DIER_UIE;

  tim7->SR = 0x0000;

  tim7->EGR = 0x0000;

  tim7->CNT = 0x0000;

  tim7->PSC = TICKER_PRESCALER - 1;

  tim7->ARR = TICKER_ROLLOVER;

  // Start timer 7

  tim7->CR1 |= TIM_CR1_CEN;

#else // USE_SYSTICK

  SysTick->LOAD = ( 300 & SysTick_LOAD_RELOAD_Msk ) - 1;

  NVIC_SetPriority ( SysTick_IRQn, 0 );

  SysTick->VAL = 0;

  // Enable SysTick IRQ and SysTick Timer with clock source AHB/8

  SysTick->CTRL = SysTick_CTRL_TICKINT_Msk |

                  SysTick_CTRL_ENABLE_Msk;

#endif

  return;

}

// Example button handler code, they are all basically this

void EXTI1_IRQHandler(void)

{

  if( SET == EXTI_GetITStatus( EXTI_Line1 ) )

  {

    Delay(LONG_TIME);

    background_task_handler();

    Delay(

LONG_TIME

);

    EXTI_ClearITPendingBit( EXTI_Line1 );

  }

  buttonHandle( true );

  return;

}

I noticed your comment about clearing interrupt source early and the EXTIx handlers do not... How important is this point?

jansen
Associate II
Posted on October 03, 2014 at 22:27

I just changed to clear interrupt flags first in all the interrupts.  It did not help...

chen
Associate II
Posted on October 06, 2014 at 14:03

Hi

I am not trying to contradict clive1.

I think what you are doing is trying to infer interrupt execution order indirectly by measuring the latency of the ISRs GPIO output.

The important point is that you are not directly looking at the ISR execution order which is what you are asking about.

To test the ISR execution order :

create a static array of short (or int)

create a static count (array index)

In each ISR - at the array index - write a Id number for the ISR

Then increment the array index

Run your code and then examine the array.

This should tell you what order the ISR are executing in.

THAT IS NOT TO SAY THAT THE LATENCY IS NOT AN ISSUE!

I do not understand why you are measuring and getting a latency either?!?

jansen
Associate II
Posted on October 06, 2014 at 17:33

Determinism and latency is my concern, NOT execution order.  I need preemption to work because my high speed timer interrupt needs to preempt the slow button handler multiple times for timing to be correct.  The order of interrupt call is of no consequence as long as the high speed interrupt can run whenever it needs to run regardless of anything else going on on the system, or what context the system is in.