Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

NVIC: Disabling Interrupts on ARM Cortex-M and the Need for a Memory Barrier Instruction

DZone's Guide to

NVIC: Disabling Interrupts on ARM Cortex-M and the Need for a Memory Barrier Instruction

Mastering interrupts is critical to making an embedded application reentrant. The challenge with reentrancy is that things might be implemented in a wrong way and the issue might just show up sporadically. The ARM Cortex interrupt controller is named NVIC (Nested Vectored Interrupt Controller).

· IoT Zone
Free Resource

Cisco IoT makes digital transformation a reality in factories, transportation, and utilities. Learn how to start integrating with Cisco DevNet.

Mastering interrupts is critical to making an embedded application reentrant. The challenge with reentrancy is that things might be implemented in a wrong way and the issue might just show up sporadically (see “EnterCritical() and ExitCritical(): Why Things are Failing Badly”). The ARM Cortex interrupt controller is named NVIC (Nested Vectored Interrupt Controller).

ARM Cortex NVIC Registers

ARM Cortex NVIC Registers

As the ‘nested’ in NVIC indicates, that controller supports nested interrupts which is a good thing from an interrupt latency and flexibility perspective. I can use the NVIC to selectively disable/enable interrupts. If done properly, I don’t have to disable the interrupts system-wide: I can narrow down my interrupt locking to a minimum of interrupts.

The NVIC has the following registers to enable/disable interrupts (one bit for each vector number):

  1. NVIC_ISER: Interrupt Set Enable Register to enable an interrupt source
  2. NVIC_ICER: Interrupt Clear Enable Register to disable an interrupt source
  3. NVIC_ISPR: Interrupt Set Pending Register to raise an interrupt
  4. NVIC_ISCR: Interrupt Clear Pending Register to clear a pending interrupt

The following shows e.g. the bits to enable DMA interrupts on a Freescale KL25Z device:

NVIC ISER

NVIC ISER

To disable an interrupt source, I can do this in the following CMSIS way:

NVIC_DisableIRQ(device_IRQn); // Disable interrupt

with the right IRQ number. However, there is a possible problem with the architecture.


:idea: It is a false thinking that with these modern processors things will be ‘done immediately’: because of the internal pipelining, caching, busses and propagation delays settings will not have an immediate impact. Instead, there might be some delay.

So if an interrupt is just happening before the disable instruction, it might still happen after I have disabled the interrupt:

Interrupt Disabling Delay

Interrupt Disabling Delay (Source: ARM)

That might or might not be a problem for my design. But if I want to create a critical section to prevent that an interrupt is happening that way, I need to add ‘memory barriers’ instructions (see http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dai0321a/BIHEBHFF.html):

  • DSB: Data Synchronization Barrier. Ensures that all explicit data memory transfers before the DSB are completed before any instructions after the DSB is executed.
  • ISB: Instruction Synchronization Barrier. Ensures that the effects of all context altering operations prior to the ISB are recognized by subsequent instructions. This results in a flushing of the instruction pipeline, with the instruction after the ISB being re-fetched.

ARM recommends first to use a DSB, followed by an ISB:

NVIC_DisableIRQ(device_IRQn); // Disable interrupt
__DSB();
__ISB();

Memory barrier instructions are necessary if I don’t want to have a pending interrupt triggered, or if need to access the something in the peripheral space which is related to the interrupt source, e.g. changing the interrupt vector or a peripheral setting which for example would change the vector location. Or in other words where any interrupt activity of that peripheral would be a problem.

Summary

Not thinking through the fact that there are propagation delays in the ARM Cortex M0/M4 architecture can lead to flawed interrupt handling. The nasty thing is that the problem will occur only rarely, and it will be hard to track down. Adding a memory barrier might be the golden bullet to solve your problem too :-).

Happy Interrupting :-)


Cisco is a software company. Surprised? Don’t be. Join DevNet to explore APIs, tools, and techniques that developers are using to add collaboration, IoT, security, network priority, and more!

Topics:
iot ,freescale ,board ,memory

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}