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#
TYPEDEFS ****************************************.
Functions#
PROTOTYPES **********************************.
Enable interrupts.
Exit a CRITICAL section.
Brief interrupt enable/disable sequence to allow handling of pending interrupts.
Enter a CRITICAL section.
Disable interrupts.
Enable interrupts.
Exit an ATOMIC section.
Brief interrupt enable/disable sequence to allow handling of pending interrupts.
Enter an ATOMIC section.
Check whether the current CPU operation mode is handler mode.
Check if interrupts are disabled.
Returns the max time spent in critical section.
Returns the max time spent in atomic section.
Clears the max time spent in atomic section.
Clears the max time spent in atomic section.
Reset chip routine.
Macros#
DEFINES *************************************.
MACRO API ***************************************.
CRITICAL style interrupt disable.
CRITICAL style interrupt enable.
Convenience macro for implementing a CRITICAL section.
Enter CRITICAL section.
Exit CRITICAL section.
CRITICAL style yield.
ATOMIC style interrupt disable.
ATOMIC style interrupt enable.
Convenience macro for implementing an ATOMIC section.
Enter ATOMIC section.
Exit ATOMIC section.
ATOMIC style yield.
Check if IRQ is disabled.
Check if inside an IRQ handler.
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 **********************************.
Type | Direction | Argument Name | Description |
---|---|---|---|
void | N/A |
Disable interrupts.
Disable all interrupts by setting PRIMASK. (Fault exception handlers will still be enabled).
CORE_CriticalEnableIrq#
void CORE_CriticalEnableIrq (void )
Enable interrupts.
Type | Direction | Argument Name | Description |
---|---|---|---|
void | N/A |
Enable interrupts by clearing PRIMASK.
CORE_ExitCritical#
void CORE_ExitCritical (CORE_irqState_t irqState)
Exit a CRITICAL section.
Type | Direction | Argument Name | Description |
---|---|---|---|
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.
Type | Direction | Argument Name | Description |
---|---|---|---|
void | N/A |
Note
Usually used within a CRITICAL section.
CORE_EnterCritical#
CORE_irqState_t CORE_EnterCritical (void )
Enter a CRITICAL section.
Type | Direction | Argument Name | Description |
---|---|---|---|
void | N/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.
Type | Direction | Argument Name | Description |
---|---|---|---|
void | N/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
If CORE_ATOMIC_METHOD is CORE_ATOMIC_METHOD_PRIMASK, this function is identical to CORE_CriticalDisableIrq().
CORE_AtomicEnableIrq#
void CORE_AtomicEnableIrq (void )
Enable interrupts.
Type | Direction | Argument Name | Description |
---|---|---|---|
void | N/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.
Type | Direction | Argument Name | Description |
---|---|---|---|
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.
Type | Direction | Argument Name | Description |
---|---|---|---|
void | N/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.
Type | Direction | Argument Name | Description |
---|---|---|---|
void | N/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.
Type | Direction | Argument Name | Description |
---|---|---|---|
void | N/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.
Type | Direction | Argument Name | Description |
---|---|---|---|
void | N/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.
Type | Direction | Argument Name | Description |
---|---|---|---|
void | N/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.
Type | Direction | Argument Name | Description |
---|---|---|---|
void | N/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.
Type | Direction | Argument Name | Description |
---|---|---|---|
void | N/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.
Type | Direction | Argument Name | Description |
---|---|---|---|
void | N/A |
Note
SL_CORE_DEBUG_INTERRUPTS_MASKED_TIMING must be enabled.
CORE_ResetSystem#
void CORE_ResetSystem (void )
Reset chip routine.
Type | Direction | Argument Name | Description |
---|---|---|---|
void | N/A |