Rare error of shared resources in processes with different priorities

This post describes rare errors of shared resources in processing with different priorities.

Shared resources : static variables, MCU functional registers, etc.
Processing : Writing shared resources by processes with different priorities.

Specification

Increment A by +1 each time FUNC() is executed, and set A to zero with INT().

Phenomenon

If an interrupt event occurs at the timing shown below, A should have been set to zero by INT(), but it is not zeroed.
This phenomenon is usually not found in testing, but is often discovered when the product is mass-produced and put on the market.

Mechanism of Occurrence

This occurs when processing is executed with the following processing timing.

1) Write the address of A in r3
2) Write the value x of A in r4
3) Interrupt event occurs, stack for interrupt is saved, INT() starts
4) Write the address of A in r3
5) Write 0 to A
6) Return to Interrupt Stack
7) r4=x+1
8) Write x+1 to A

Countermeasures

Countermeasure 1
This countermeasure can be avoided by changing the interrupt priority as follows. This method is often used for MCU function registers that are often accessed at different priority levels.

static unsigned char A = 0;

void FUNC(void)
{
    unsigned int mask;
    ......
    mask = get_set_ipr(level_max);  // Interrupt priority max Level
    A = A + 1;
    mask = get_set_ipr(mask);       // Interrupt priority original Level
    ......
}

// Interrupt
void INT(void)
{
     ......
     A = 0;
     ......
}

Countermeasure 2
This countermeasure can be avoided by not writing shared resources at different processing timings.
Corrected by Mr. Sébastien Miguet, thanks to Mr. Sébastien Miguet. (2024/7/16)

static unsigned char A = 0;
static unsigned char CLEAR_N1 = 0;
static unsigned char CLEAR_N2 = 0;

void FUNC(void)
{
    ......
    unsigned char CLEAR_N1_CPY = CLEAR_N1;
    if( CLEAR_N1_CPY == CLEAR_N2 )   // Check for occurrence of INT interrupt
    {
        A = A + 1;
    }
    else
    {
        A = 0;
    }
    CLEAR_N2 = CLEAR_N1_CPY;
    ......
}

void INT(void)
{
     ......
     CLEAR_N1 = CLEAR_N1 + 1;
     ......
}
Root cause

This defect is the root cause of the following.

  • Tacit knowledge that is not written in the specification.
  • A culture that values consistency between specifications and code.
  • The fact that more engineers do not know that one code in C is executed by multiple instruction codes.
OSS-ECAL English
error: Content is protected !!