Skip to main content
Visitor II
January 2, 2008
Question

critical section example

  • January 2, 2008
  • 2 replies
  • 2657 views
Posted on January 02, 2008 at 13:54

critical section example

    This topic has been closed for replies.

    2 replies

    togradyAuthor
    Visitor II
    May 17, 2011
    Posted on May 17, 2011 at 12:20

    Hi,

    I have implemented buffered uarts using interupts on the STM32. Can anyone provide a ''critical section'' example to disable interupts when getting data in or out of my circular buffers. I've used the code below in the past with other processors but I'm not sure how to implement the macros DISABLE_INTERRUPTS and ENABLE_INTERRUPTS on the STM32.

    Code:

    void EnterCriticalSection( void )

    {

    DISABLE_INTERRUPTS();

    CriticalSectionNesting++;

    }

    void ExitCriticalSection( void )

    {

    if ((--CriticalSectionNesting) == 0)

    ENABLE_INTERRUPTS();

    }

    Thanks

    Trevor

    Graduate II
    February 28, 2025

    14 years later, about time someone answered this? Here's what I've come up with:

     

     

    #include <assert.h>
    //cmsis_compiler includes cmsis_gnu or cmsis_armcc as applicable,
    //which is where the `__` functions are defined.
    #include <cmsis_compiler.h>
    
    
    
    //Support calling CRITICAL_enter() multiple times before calling CRITICAL_exit(), as
    //sometimes happens when you call functions within your critical sections that themselves
    //enter critical sections. Generally this is a sign of problem, because critical sections
    //should be kept short and simple, but is supported just in case there's a worthy use case.
    uint8_t gNestingLevel = 0;
    //Remember whether interrupts were on or not at the time we disable them.
    bool gInterruptsWereEnabled;
    
    
    void CRITICAL_enter(void)
    {
     assert(gNestingLevel < 100); //don't be silly
    
     if(gNestingLevel == 0)
     {
     gInterruptsWereEnabled = (__get_PRIMASK() == 0);
     __disable_irq(); //we only need to disable interrupts at the top nesting level
     }
     gNestingLevel++;
    }
    
    void CRITICAL_exit(void)
    {
     assert(gNestingLevel > 0); //don't exit before entering
    
     //if we've reached the top nesting level, and interrupts were enabled, re-enable them
     if(--gNestingLevel == 0 && gInterruptsWereEnabled)
     __enable_irq();
    }

     

     
    The DISABLE_INTERRUPTS and ENABLE_INTERRUPTS bits are just the __disable_irq() and __enable_irq() calls, but I've also stored whether they were enabled in the first place so we can restore the correct state.

    Visitor II
    February 28, 2025

    If you use RTOS - critical section support is there (e.g. using semaphores).
    Even you would not know how to mark a critical section: it is a semaphore which is set to block if "somebody" (another thread/task) enters this piece of code as well. When the owner has done, it releases the semaphore.
    So, other threads/tasks have to check this semaphore and block if it is already allocated/in use.

    Enabling and disabling INTs might sound "logical" but it is not good practice: you disable also SYSTICK and any other timer or peripheral which is not related to your critical section. If you want to use "preemptive" multi-tasking - disabling all global INTs, including the timer and time based scheduling - is not a nice approach.

    Critical Section means: you want to avoid that two parallel processes (tasks/threads) use the same piece of code, which is potentially using a peripheral (e.g. UART) which can be used just once at a time. I one code runs a bit, another code kicks in - it can mess up on the "not-sharable" resource. So, you need to encapsulate this code in a critical section.

    In general it looks like this:

    if (xSemaphoreTake(xSemaphoreSPI2, portMAX_DELAY) == pdTRUE)
    {
     //OK: SPI2 was free - I own it now - exclusivly
     //... do something with it
     //all parties using this code cannot intercept each other = critical section
    
     xSemaphoreGive(xSemaphoreSPI2);
     //if all done, relaese the semaphore
    }

     

    Visitor II
    May 17, 2011
    Posted on May 17, 2011 at 12:20

    Your code looks like it was ripped from Freertos, why not just have a look at the cortexm3 port.

    Cheers

    sjo