SoC
  • Home
  • Arm
  • Arm Cortex M0/M0+
  • Arm Cortex M4
  • Arm Cortex M3
  • Contact
Reading: Changing Interrupt Priority on Cortex-M Microcontrollers
SUBSCRIBE
SoCSoC
Font ResizerAa
  • Home
  • Arm
  • Arm Cortex M0/M0+
  • Arm Cortex M4
Search
  • Home
  • Arm
  • Arm Cortex M0/M0+
  • Arm Cortex M4
Have an existing account? Sign In
Follow US
  • Looking for Something?
  • Privacy Policy
  • About Us
  • Sitemap
  • Contact Us
© S-O-C.ORG, All Rights Reserved.
Arm

Changing Interrupt Priority on Cortex-M Microcontrollers

Holly Lindsey
Last updated: October 5, 2023 9:55 am
Holly Lindsey 6 Min Read
Share
SHARE

Cortex-M microcontrollers allow developers to assign different priority levels to interrupts. This allows high priority interrupts to preempt lower priority ones. Changing the priority of interrupts dynamically at runtime can help optimize interrupt response and overall system performance.

Contents
Interrupt Priority LevelsSetting Interrupt PrioritiesReading Interrupt PrioritiesChanging Interrupt Priorities DynamicallyUse CasesImportant ConsiderationsMaintaining Forward ProgressNVIC Priority GroupingExample Priority Grouping ConfigurationsCoding Best PracticesConclusion

Interrupt Priority Levels

On Cortex-M processors, interrupts can have 256 priority levels from 0 (highest priority) to 255 (lowest priority). The NVIC (Nested Vectored Interrupt Controller) handles prioritization and dispatching of interrupts based on their priority level.

Higher priority interrupts can interrupt lower priority ones. This allows time critical functions to take precedence over less important background tasks. For example, a timer interrupt used to implement an RTOS would have very high priority to ensure task scheduling is always responsive.

Setting Interrupt Priorities

Interrupt priority is configured statically at compile time by setting the Priority field in the Interrupt Number Definition section of the startup file. For example: /* Interrupt Priorities */ #define WWDG_IRQ_PRIO 0 #define PVD_IRQ_PRIO 1 #define RTC_IRQ_PRIO 2

This sets the priority of the RTC interrupt to 2, PVD to 1, and WWDG to 0 (highest priority). The application can still change priorities dynamically at runtime if needed.

Reading Interrupt Priorities

To read the current priority of an interrupt, use the NVIC_GetPriority() function. It takes the interrupt number as a parameter and returns the 8-bit priority value (0-255). uint32_t priority; priority = NVIC_GetPriority(RTC_IRQn);

This reads back the current priority value assigned to the RTC interrupt.

Changing Interrupt Priorities Dynamically

The NVIC_SetPriority() function can be used to change the priority of an interrupt at runtime. This takes the interrupt number and 8-bit priority value as parameters. NVIC_SetPriority(RTC_IRQn, 10);

This sets the priority of the RTC interrupt to 10 dynamically at runtime. Higher priority interrupts can still preempt this interrupt.

Use Cases

Some common use cases for dynamically changing interrupt priorities include:

  • Increasing the priority of a time critical interrupt temporarily during a critical code section to prevent disruption.
  • Lowering the priority of a bandwidth consuming interrupt temporarily to allow higher priority transfers to complete.
  • Boosting the priority of an interrupt from a communication peripheral to minimize latency.
  • Implementing a dynamic interrupt priority scheme in an RTOS or hybrid RTOS system.

Important Considerations

There are some important factors to keep in mind when changing interrupt priorities dynamically:

  • Do not lower the priority of an interrupt you are currently servicing below the current executing priority level. This could cause deadlock.
  • Avoid boosting multiple interrupt priorities above the SysTick priority. This could impact RTOS timing.
  • Only modify interrupt priorities from privileged thread mode, not handler mode.
  • Ensure interrupt priority changes are atomic and thread safe.
  • For Cortex-M parts without priority grouping (M0+/M1), avoid priority inversion which could cause deadlocks.

Maintaining Forward Progress

When changing priorities dynamically, the developer must ensure that all higher priority interrupts can eventually complete so lower priority ones can resume normal operation. Techniques to ensure system forward progress include:

  • Limiting long running interrupts – Long interrupts at any priority level can block lower priority ones indefinitely. Keep ISRs short with most work done at thread level.
  • Avoiding nested interrupts – Supporting nested interrupts requires carefully managing priority levels and stack usage.
  • Allowing lower priority interrupts periodically – Occasionally drop the priority of long running interrupts to allow others to run.
  • Checking for pending interrupts – Check NVIC_GetPendingIRQ() periodically and handle pending lower priority IRQs.

NVIC Priority Grouping

Cortex-M3 and M4 processors support priority grouping, which divides the 8-bit priority field into a group priority and subpriority. The NVIC_SetPriorityGrouping() API configures how the bits are split between group and subpriority: void NVIC_SetPriorityGrouping(uint32_t PriorityGroup);

When priority grouping is used, the group priority determines the overall preemption level while the subpriority differentiates between interrupts with the same group priority level. This can help prevent priority inversion issues.

Example Priority Grouping Configurations

  • No grouping – All 8 bits used for subpriority. (0xFF)
  • Binary point between bit 7 and 6 – Bit 7 is group priority, bits 6-0 are subpriority. (0x80)
  • Binary point between bit 5 and 4 – Bits 7-5 are group priority, bits 4-0 are subpriority. (0xA0)

The developer should carefully choose a priority grouping scheme that makes optimal use of the priority levels for the application’s use case.

Coding Best Practices

Here are some recommended coding best practices when working with interrupt priorities on Cortex-M:

  • Initialize all interrupt priorities properly at startup even if they are changed later.
  • Utilize priority grouping features to prevent priority inversion.
  • Minimize the use of higher priority and nested interrupts when possible.
  • Keep ISRs short and move processing to threads.
  • Ensure interrupt priority changes are thread safe.
  • Do not call NVIC priority APIs from interrupt handlers.
  • Analyze worst case interrupt latency from simulation.
  • Ensure system tick has a priority lower than application tasks.

Conclusion

Dynamically changing interrupt priorities can optimize responsiveness and throughput in Cortex-M systems. However, priority levels interactions can be complex so caution must be taken. Usage of priority grouping, avoidance of nested interrupts, deterministic context switch timings, and proper application design is needed to build robust systems that leverage dynamic priority levels effectively.

Newsletter Form (#3)

More ARM insights right in your inbox

 


Share This Article
Facebook Twitter Email Copy Link Print
Previous Article Mapping External RAM Correctly with Scatter Load Files on ARM Cortex-M
Next Article Preventing Interrupt Nesting on Cortex-M using BASEPRI
Leave a comment Leave a comment

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

2k Followers Like
3k Followers Follow
10.1k Followers Pin
- Sponsored-
Ad image

You Might Also Like

Measuring interrupt latency on Arm Cortex-M processors

Interrupt latency is an important performance metric for real-time embedded…

7 Min Read

What is the specification of STM32F407G?

The STM32F407G is a high-performance microcontroller from STMicroelectronics based on…

7 Min Read

Tradeoffs Between Clock Frequency and Timing Closure in Arm Cortex M1

The Arm Cortex M1 processor is designed to provide high…

9 Min Read

How does one do integer (signed or unsigned) division on ARM?

Integer division on ARM processors is done using the SDIV…

10 Min Read
SoCSoC
  • Looking for Something?
  • Privacy Policy
  • About Us
  • Sitemap
  • Contact Us
Welcome Back!

Sign in to your account