Core#

Introduction#

The core abstraction API provides high-level, device agnostic, control of core peripherals, most notably the ability to execute code in sections with varying levels of interrupt masking.

This module provides support for two types of critical sections, each with different interrupt masking capabilities.

  • CRITICAL section: Inside a critical section, all interrupts are masked (except for core exception handlers).

  • ATOMIC section: Inside an atomic section, interrupts with a priority less than the configurable SL_CORE_BASE_PRIORITY_LEVEL value will be masked.

Compile-time Configuration#

The following #define is used to configure sl_core:

// Enables debug methods to measure the time spent in critical sections.
#define SL_CORE_DEBUG_INTERRUPTS_MASKED_TIMING   0

Macro API#

The core abstraction API has macros to facilitate executing code in ATOMIC and CRITICAL sections.

CORE_DECLARE_IRQ_STATE, CORE_ENTER_ATOMIC() and CORE_EXIT_ATOMIC() can be used together to implement an ATOMIC section.

{
  CORE_DECLARE_IRQ_STATE;           // Storage for saving IRQ state prior to
                                    // atomic section entry.

  CORE_ENTER_ATOMIC();              // Enter atomic section.

  ...
  ... your code goes here ...
  ...

  CORE_EXIT_ATOMIC();               // Exit atomic section, IRQ state is restored.
}

CORE_ATOMIC_SECTION(yourcode) is aconcatenation of all three of the macros above.

{
  CORE_ATOMIC_SECTION(
    ...
    ... your code goes here ...
    ...
  )
}

The following macros implement CRITICAL sections in a similar fashion as described above for ATOMIC sections: CORE_DECLARE_IRQ_STATECORE_ENTER_CRITICAL()CORE_EXIT_CRITICAL()CORE_CRITICAL_SECTION(yourcode)

API Reimplementation#

Most of the functions in the API are implemented as weak functions. This means that it is easy to reimplement when special needs arise. Shown below is a reimplementation of CRITICAL sections suitable if FreeRTOS OS is used:

CORE_irqState_t CORE_EnterCritical(void)
{
  vPortEnterCritical();
  return 0;
}

void CORE_ExitCritical(CORE_irqState_t irqState)
{
  (void)irqState;
  vPortExitCritical();
}

Also note that CORE_Enter/ExitCritical() are not implemented as inline functions. As a result, reimplementations will be possible even when original implementations are inside a linked library.

Some RTOSes must be notified on interrupt handler entry and exit. Macros CORE_INTERRUPT_ENTRY() and CORE_INTERRUPT_EXIT() are suitable placeholders for inserting such code. Insert these macros in all your interrupt handlers and then override the default macro implementations. This is an example if uC/OS is used:

// In emlib_config.h:

#define CORE_INTERRUPT_ENTRY()   OSIntEnter()
#define CORE_INTERRUPT_EXIT()    OSIntExit()

Maximum Interrupt Disabled Time#

The maximum time spent (in cycles) in critical and atomic sections can be measured for performance and interrupt latency analysis. To enable the timings, use the SL_CORE_ENABLE_INTERRUPT_DISABLED_TIMING configuration option. When enabled, the functions CORE_get_max_time_critical_section() and CORE_get_max_time_atomic_section() can be used to get the max timings since startup.

Porting from em_int#

Existing code using INT_Enable() and INT_Disable() must be ported to the sl_core API. While em_int used, a global counter to store the interrupt state, sl_core uses a local variable. Any usage of INT_Disable(), therefore, needs to be replaced with a declaration of the interrupt state variable before entering the critical section.

Since the state variable is in local scope, the critical section exit needs to occur within the scope of the variable. If multiple nested critical sections are used, each needs to have its own state variable in its own scope.

In many cases, completely disabling all interrupts using CRITICAL sections might be more heavy-handed than needed. When porting, consider whether an ATOMIC section can be used to only disable a subset of the interrupts.

Replacing em_int calls with sl_core function calls:

void func(void)
{
  // INT_Disable();
  CORE_DECLARE_IRQ_STATE;
  CORE_ENTER_ATOMIC();
    .
    .
    .
  // INT_Enable();
  CORE_EXIT_ATOMIC();
}

Typedefs#

typedef uint32_t

TYPEDEFS ****************************************.

Functions#

void

PROTOTYPES **********************************.

void

Enable interrupts.

void
CORE_ExitCritical(CORE_irqState_t irqState)

Exit a CRITICAL section.

void

Brief interrupt enable/disable sequence to allow handling of pending interrupts.

Enter a CRITICAL section.

void

Disable interrupts.

void

Enable interrupts.

void
CORE_ExitAtomic(CORE_irqState_t irqState)

Exit an ATOMIC section.

void

Brief interrupt enable/disable sequence to allow handling of pending interrupts.

Enter an ATOMIC section.

bool

Check whether the current CPU operation mode is handler mode.

bool

Check if interrupts are disabled.

uint32_t

Returns the max time spent in critical section.

uint32_t

Returns the max time spent in atomic section.

void

Clears the max time spent in atomic section.

void

Clears the max time spent in atomic section.

void

Reset chip routine.

Macros#

#define
CORE_ATOMIC_BASE_PRIORITY_LEVEL 3

DEFINES *************************************.

#define
CORE_DECLARE_IRQ_STATE CORE_irqState_t irqState

MACRO API ***************************************.

#define
CORE_CRITICAL_IRQ_DISABLE ()

CRITICAL style interrupt disable.

#define
CORE_CRITICAL_IRQ_ENABLE ()

CRITICAL style interrupt enable.

#define
CORE_CRITICAL_SECTION (yourcode)

Convenience macro for implementing a CRITICAL section.

#define
CORE_ENTER_CRITICAL ()

Enter CRITICAL section.

#define
CORE_EXIT_CRITICAL ()

Exit CRITICAL section.

#define
CORE_YIELD_CRITICAL ()

CRITICAL style yield.

#define
CORE_ATOMIC_IRQ_DISABLE ()

ATOMIC style interrupt disable.

#define
CORE_ATOMIC_IRQ_ENABLE ()

ATOMIC style interrupt enable.

#define
CORE_ATOMIC_SECTION (yourcode)

Convenience macro for implementing an ATOMIC section.

#define
CORE_ENTER_ATOMIC ()

Enter ATOMIC section.

#define
CORE_EXIT_ATOMIC ()

Exit ATOMIC section.

#define
CORE_YIELD_ATOMIC ()

ATOMIC style yield.

#define
CORE_IRQ_DISABLED ()

Check if IRQ is disabled.

#define
CORE_IN_IRQ_CONTEXT ()

Check if inside an IRQ handler.

#define
CORE_RESET_SYSTEM ()

Typedef Documentation#

CORE_irqState_t#

typedef uint32_t CORE_irqState_t

TYPEDEFS ****************************************.

Storage for PRIMASK or BASEPRI value.


Function Documentation#

CORE_CriticalDisableIrq#

void CORE_CriticalDisableIrq (void )

PROTOTYPES **********************************.

Parameters
TypeDirectionArgument NameDescription
voidN/A

Disable interrupts.

Disable all interrupts by setting PRIMASK. (Fault exception handlers will still be enabled).


CORE_CriticalEnableIrq#

void CORE_CriticalEnableIrq (void )

Enable interrupts.

Parameters
TypeDirectionArgument NameDescription
voidN/A

Enable interrupts by clearing PRIMASK.


CORE_ExitCritical#

void CORE_ExitCritical (CORE_irqState_t irqState)

Exit a CRITICAL section.

Parameters
TypeDirectionArgument NameDescription
CORE_irqState_t[in]irqState

The interrupt priority blocking level to restore to PRIMASK when exiting the CRITICAL section. This value is usually the one returned by a prior call to CORE_EnterCritical().


CORE_YieldCritical#

void CORE_YieldCritical (void )

Brief interrupt enable/disable sequence to allow handling of pending interrupts.

Parameters
TypeDirectionArgument NameDescription
voidN/A

Note

  • Usually used within a CRITICAL section.


CORE_EnterCritical#

CORE_irqState_t CORE_EnterCritical (void )

Enter a CRITICAL section.

Parameters
TypeDirectionArgument NameDescription
voidN/A

When a CRITICAL section is entered, all interrupts (except fault handlers) are disabled.

Returns

  • The value of PRIMASK register prior to the CRITICAL section entry.


CORE_AtomicDisableIrq#

void CORE_AtomicDisableIrq (void )

Disable interrupts.

Parameters
TypeDirectionArgument NameDescription
voidN/A

Disable interrupts with a priority lower or equal to CORE_ATOMIC_BASE_PRIORITY_LEVEL. Sets core BASEPRI register to CORE_ATOMIC_BASE_PRIORITY_LEVEL.

Note


CORE_AtomicEnableIrq#

void CORE_AtomicEnableIrq (void )

Enable interrupts.

Parameters
TypeDirectionArgument NameDescription
voidN/A

Enable interrupts by setting core BASEPRI register to 0.

Note

  • If CORE_ATOMIC_METHOD is CORE_ATOMIC_METHOD_BASEPRI and PRIMASK is set (CPU is inside a CRITICAL section), interrupts will still be disabled after calling this function.

  • If CORE_ATOMIC_METHOD is CORE_ATOMIC_METHOD_PRIMASK, this function is identical to CORE_CriticalEnableIrq().


CORE_ExitAtomic#

void CORE_ExitAtomic (CORE_irqState_t irqState)

Exit an ATOMIC section.

Parameters
TypeDirectionArgument NameDescription
CORE_irqState_t[in]irqState

The interrupt priority blocking level to restore to BASEPRI when exiting the ATOMIC section. This value is usually the one returned by a prior call to CORE_EnterAtomic().

Note

  • If CORE_ATOMIC_METHOD is set to CORE_ATOMIC_METHOD_PRIMASK, this function is identical to CORE_ExitCritical().


CORE_YieldAtomic#

void CORE_YieldAtomic (void )

Brief interrupt enable/disable sequence to allow handling of pending interrupts.

Parameters
TypeDirectionArgument NameDescription
voidN/A

Note

  • Usually used within an ATOMIC section.

  • If CORE_ATOMIC_METHOD is CORE_ATOMIC_METHOD_PRIMASK, this function is identical to CORE_YieldCritical().


CORE_EnterAtomic#

CORE_irqState_t CORE_EnterAtomic (void )

Enter an ATOMIC section.

Parameters
TypeDirectionArgument NameDescription
voidN/A

When an ATOMIC section is entered, interrupts with priority lower or equal to CORE_ATOMIC_BASE_PRIORITY_LEVEL are disabled.

Note

  • If CORE_ATOMIC_METHOD is CORE_ATOMIC_METHOD_PRIMASK, this function is identical to CORE_EnterCritical().

Returns

  • The value of BASEPRI register prior to ATOMIC section entry.


CORE_InIrqContext#

bool CORE_InIrqContext (void )

Check whether the current CPU operation mode is handler mode.

Parameters
TypeDirectionArgument NameDescription
voidN/A

Returns

  • True if the CPU is in handler mode (currently executing an interrupt handler).
    False if the CPU is in thread mode.


CORE_IrqIsDisabled#

bool CORE_IrqIsDisabled (void )

Check if interrupts are disabled.

Parameters
TypeDirectionArgument NameDescription
voidN/A

Returns

  • True if interrupts are disabled.


CORE_get_max_time_critical_section#

uint32_t CORE_get_max_time_critical_section (void )

Returns the max time spent in critical section.

Parameters
TypeDirectionArgument NameDescription
voidN/A

Returns

  • The max time spent in critical section.

Note

  • SL_CORE_DEBUG_INTERRUPTS_MASKED_TIMING must be enabled.


CORE_get_max_time_atomic_section#

uint32_t CORE_get_max_time_atomic_section (void )

Returns the max time spent in atomic section.

Parameters
TypeDirectionArgument NameDescription
voidN/A

Returns

  • The max time spent in atomic section.

Note

  • SL_CORE_DEBUG_INTERRUPTS_MASKED_TIMING must be enabled.


CORE_clear_max_time_critical_section#

void CORE_clear_max_time_critical_section (void )

Clears the max time spent in atomic section.

Parameters
TypeDirectionArgument NameDescription
voidN/A

Note

  • SL_CORE_DEBUG_INTERRUPTS_MASKED_TIMING must be enabled.


CORE_clear_max_time_atomic_section#

void CORE_clear_max_time_atomic_section (void )

Clears the max time spent in atomic section.

Parameters
TypeDirectionArgument NameDescription
voidN/A

Note

  • SL_CORE_DEBUG_INTERRUPTS_MASKED_TIMING must be enabled.


CORE_ResetSystem#

void CORE_ResetSystem (void )

Reset chip routine.

Parameters
TypeDirectionArgument NameDescription
voidN/A