How to properly enable/disable interrupts in ARM Cortex-M?
Point of this post is not how to use NVIC (Nested Vectored Interrupt Controller) in Cortex-M processors but how to disable/enable interrupts properly for your system to avoid strange behaviours in your code.
Let’s assume you have 2 functions, which do some important stuff and they have to make sure that noone interrupts these 2 functions
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
void ImportantFunction1(void) { /* Important function 1 */ /* Do some stuff here which can be interrupted */ /* Disable interrupts */ __disable_irq(); /* Do some stuff here which can not be interrupted */ /* Enable interrupts back */ __enable_irq(); /* Do some stuff here which can be interrupted */ } void ImportantFunction2(void) { /* Important function 2 */ /* Do some stuff here which can be interrupted */ /* Disable interrupts */ __disable_irq(); /* Do some stuff here which can not be interrupted */ /* Enable interrupts back */ __enable_irq(); /* Do some stuff here which can be interrupted */ } |
By calling these 2 functions from some other function, this will just work properly, interrupts will be disabled, important stuff done and interrupts enabled again. But what if you come to a situation, when important function 1 calls important function 2 from section where function 1 should not be interrupted? In case above, important function 2 would enable interrupts back and function 1 would not be safe anymore. Check example below which will fail in order to make clean and safe program:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
void ImportantFunction1(void) { /* Important function 1 */ /* Do some stuff here which can be interrupted */ /* Disable interrupts */ __disable_irq(); /* Do some stuff here which can not be interrupted */ /* Call subfunction */ ImportantFunction2(); /* Do some stuff here which can not be interrupted */ /* Here is a problem, ImportantFunction2() also enables interrupts */ /* This part here is not safe from interrupts anymore and can be interrupted */ /* Enable interrupts back */ __enable_irq(); /* Do some stuff here which can be interrupted */ } void ImportantFunction2(void) { /* Important function 2 */ /* Do some stuff here which can be interrupted */ /* Disable interrupts */ __disable_irq(); /* Do some stuff here which can not be interrupted */ /* Enable interrupts back */ __enable_irq(); /* Do some stuff here which can be interrupted */ } |
To avoid problems like this, the idea is that before you disable interrupts in your function, first check interrupt enabled status in Cortex-M4 PRIMASK register to see if they were enabled or disabled before. Check properly working example where you don’t have to worry about nested function calls with multiple interrupt enable or disable function calls:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
void ImportantFunction1(void) { /* Important function 1 */ uint32_t prim; /* Do some stuff here which can be interrupted */ /* Read PRIMASK register, check interrupt status before you disable them */ /* Returns 0 if they are enabled, or non-zero if disabled */ prim = __get_PRIMASK(); /* Disable interrupts */ __disable_irq(); /* Do some stuff here which can not be interrupted */ /* Call subfunction */ ImportantFunction2(); /* Do some stuff here which can not be interrupted */ /* This part is still interrupt safe because ImportantFunction2 will not enable interrupts */ /* Enable interrupts back */ if (!prim) { __enable_irq(); } /* Do some stuff here which can be interrupted */ } void ImportantFunction2(void) { /* Important function 2 */ uint32_t prim; /* Do some stuff here which can be interrupted */ /* Read PRIMASK register, check interrupt status before you disable them */ /* Returns 0 if they are enabled, or non-zero if disabled */ prim = __get_PRIMASK(); /* Disable interrupts */ __disable_irq(); /* Do some stuff here which can not be interrupted */ /* Enable interrupts back only if they were enabled before we disable it here in this function */ if (!prim) { __enable_irq(); } /* Do some stuff here which can be interrupted */ } |
GENERAL Library
If you are using my TM_GENERAL library for STM32F4xx and its Enable and Disable interrupts function, then you don’t have to worry about everything listed above, because these 2 functions are written in a way to avoid strange behaviour in your system. You can use it everywhere and they will work as expected. Download available below:
Recent comments