This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Atomic sections of code

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.

Parents
  • NO interrupt should ever enable or disable interrupts

    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.

Reply
  • NO interrupt should ever enable or disable interrupts

    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.

Children