DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Newsletter
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Related

  • Porting Software to ARM: Here’s What We Learned

Trending

  • A Software Factory on Kubernetes: Gemini Builds, jev Decides (Genkit + senro in Go)
  • Building Multi-Rail Payment Failover to Stop Latency Spikes and Double Debits
  • Three Measured Outcomes of Manually Scaling Fleet in Prod
  • The "Just Read the Code" Myth Is Killing Your AI Workflow

Draft This article hasn't been published, so readers can't see it.

In moderation This article is waiting for review, so readers can't see it yet.

Deleted This article has been deleted, so readers can't see it.

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).

By 
Erich Styger
·
Oct. 20, 15 · Tutorial
Post on X (opens in a new tab) Share on LinkedIn (opens in a new tab)
15.7K Views

Join the DZone community Save articles, join the discussion, and download Refcards and Trend Reports with a free account.

Join for free Already a member? Log in

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 :-)


Memory barrier Arm (geography)

Opinions expressed by DZone contributors are their own.

Related

  • Porting Software to ARM: Here’s What We Learned

Partner Resources

×

Comments

Loading comments

The comments didn't load

Please try again in a moment.

Likes

Loading

The next likes didn't load. Please try again.

The likes didn't load

Please try again in a moment.

See who liked this

Log in or join DZone for free to see who liked this article.

Log in Join for free
  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook