There are several possibilities to protect critical sections of code from being interrupted:
1. Temporarily disabling and enabling interrupts:
void function(void) { EA = 0; // atomic_section... EA = 1; }
Disadvantage: This will change the status of EA if interrupts had not been enabled before.
2. Saving and restoring EA: http://www.keil.com/forum/1080/
bit ea_saved; void function(void) { ea_saved = EA; EA = 0; // atomic_section... EA = ea_saved; }
Disadvantage: if this code can be interrupted between ea_saved=EA and EA=0. If the interrupt service routine decides to disable interrupts, the interrupts will become enabled again when doing EA=ea_saved after the critical section.
3. Using #pragma disable http://www.keil.com/support/man/docs/c51/c51_disable.htm http://www.keil.com/forum/1080/
#pragma disable void function (void) { // atomic_section... }
Advantage: Avoids the above problem because the JBC opcode is used to evaluate the current state of EA and clear EA with the same instruction:
; FUNCTION function (BEGIN) SETB C JBC EA,IS_CLEARED CLR C IS_CLEARED: PUSH PSW // atomic_section... POP PSW MOV EA,C RET ; FUNCTION function (END)
Disadvantage: Can be applied to whole functions only. Requires 1 Byte on the stack.
4. Combination of 2. and 3.
#include <intrins.h> #define ATOMIC_SECTION_BEGIN { ea_saved = 1; if (!(_testbit_(EA))) { ea_saved = 0; } } #define ATOMIC_SECTION_END { EA = ea_saved; } #define INTERRUPTS_DISABLE { EA = 0; ea_saved = 0; } #define INTERRUPTS_ENABLE { EA = 1; ea_saved = 1; } bit ea_saved; void function(void) { ATOMIC_SECTION_BEGIN // atomic_section... ATOMIC_SECTION_END }
This results in
ATOMIC_SECTION_BEGIN SETB ea_saved JBC EA,?C0007?HB CLR ea_saved ?C0007?HB: // atomic_section... ATOMIC_SECTION_END MOV C,ea_saved MOV EA,C
Advantages: Pure source code, no inline assembly. Atomic section can remain inline, no sub-function required. Only one bit for status saving required.
NO interrupt should ever enable or disable interrupts
Erik
You missed the actual issue. The issue is that no normal, re-usable function can safely assume the interrupts were enabled when it was called. A caller further up the tree might have disabled interrupts and expect them to stay off. Or it might be called before the system enabled the interrupts at all.
What you typically want for easiest re-use are macros or inlines not for Interrupt_save_and_disable()/Interrupt_restore(), but rather nestable Interrupt_suspend() and Interrupt_resume(), where
* the first suspend saves the current state and disables interrupts * further suspends increase a nesting count * all but the last resume decrease the nesting count * the final release restores the interrupts to the state saved by the inital suspend
That way any function needing interrupts off for a section of code can surround it with suspend & resume without having to know the whole system architecture.
What is this thread answering?
You missed the actual issue. I did not thr OP: "Disadvantage: if this code can be interrupted between ea_saved=EA and EA=0. If the interrupt service routine decides to disable interrupts,"
can you just imagine the effects of the above?
thr OP:
Erik, when you write a one-line reply to a 100-line posting, your reply only relates to one aspect of one of its paragraphs, you really should leave some indication what you're referring to. Otherwise how was anyone (e.g. me) supposed to know that "no need" referred to that small shred, instead of the whole posting?
Human language creates enough unavoidable misunderstandings --- no need to make it worse by being obscure.
I did not
Which is worse, erik?
a) you missed the point or b) you didn't know that you missed the point.