不可屏蔽中断 Non-maskable interrupts (NMIs)
embOS performs atomic operations by disabling interrupts.
However, a non-maskable interrupt (NMI) cannot be disabled,
meaning it can interrupt these atomic operations.
Therefore, NMIs should be used with great care and
may under no circumstances call any embOS routines.
低优先级中断 Low priority interrupts < Normal interrupts >
May call embOS API functions
Latencies caused by embOS
高优先级中断 High priority interrupts < Fast interrupts >
May not call embOS API functions
Why can a high priority ISR not use the OS API ?
embOS disables low priority interrupts when embOS data structures are modified. During this time high priority ISR are enabled. If they would call an embOS function, which also modifies embOS data, the embOS data structures would be corrupted.
No Latencies caused by embOS (Zero latency)
embOS does never disable high priority interrupts.
This means that high priority interrupts can interrupt the operating system at any time,
even in critical situations such as the modification of linked lists and double linked list.
There is a way to still use OS functions from high priority interrupts indirectly:
High priority interrupt triggers a low priority interrupt usually by setting an interrupt request flag.
That low priority interrupt may now call OS functions.
May not call embOS API functions :
embOS disables low prio interrupts when embOS data structures are modified.
embOS does never disable high priority interrupts.
During this time high prio ISR are enabled, if they would call an embOS function,
which also modifies embOS data, the embOS data structures would be corrupt.
----------------------------------------------------------------------------------------------------------------------------
针对低优先级中断 Low priority interrupts < Normal interrupts >
OS_DI() Disables interrupts. Does not change the interrupt disable counter.
OS_EI() Unconditionally enables Interrupt.
OS_IncDI() Increments the interrupt disable counter (OS_DICnt) and disables interrupts.
OS_DecRI() Decrements the counter and enables interrupts if the counter reaches 0.
OS_RestoreI() Restores the status of the interrupt flag, based on the interrupt disable counter.
#define OS_IncDI() { OS_ASSERT_DICnt(); OS_DI(); OS_DICnt++; } #define OS_DecRI() { OS_ASSERT_DICnt(); if (--OS_DICnt==0) OS_EI(); } #define OS_RestoreI() { OS_ASSERT_DICnt(); if (OS_DICnt==0) OS_EI(); }
如何禁止高优先级中断 High priority interrupts < Fast interrupts > ?
Disables interrupts. This intrinsic function can only be used in privileged mode.
For other devices, it disables interrupt requests (irq) and fast interrupt requests (fiq).
void _ _enable_interrupt(void);
Enables interrupts. This intrinsic function can only be used in privileged mode.
For Cortex-M devices, it resets the execution priority level to default by clearing the priority mask bit, PRIMASK.
For other devices, it enables interrupt requests (irq) and fast interrupt requests (fiq).
----------------------------------------------------------------------------------------------------------------------------
void _ _disable_fiq(void); Disables fast interrupt requests (fiq).
void _ _disable_fiq(void);
This intrinsic function can only be used in privileged mode and
is not available for Cortex-M devices.
Interrupt handling with vectored interrupt controller -- for Cortex-M devices.
OS_ARM_EnableISR(int ISRIndex) < NVIC_EnableIRQ() >
used to enable interrupt acceptance of a specific interrupt source in a vectored interrupt controller.
Note that the ISRIndex counts from 0 for the first entry in the vector table.
The first peripheral index therefore has the ISRIndex 16,
because the first peripheral interrupt vector is located after the 16 generic vectors in the vector table.
This differs from index values used with CMSIS.
OS_ARM_DisableISR() < NVIC_DisableIRQ() >
used to disable interrupt acceptance of a specific interrupt source in a vectored interrupt controller which is not of the VIC type.
OS_ARM_ISRSetPrio (int ISRIndex, int Prio) < NVIC_SetPriority() >
used to set or modify the priority of a specific interrupt source by programming the interrupt controller.
The priority value is independent from the chip specific preemption levels.
Any value between 0 and 255 can be used, were 255 always is the lowest priority and 0 is the highest priority.
The function can be called to set the priority for all interrupt sources, regardless embOS is used in the specified interrupt handler.
Note that interrupt handler running on priorities from 127 or higher must not call any embOS function.
----------------------------------------------------------------------------------------------------------------------------
OS_CallISR() Interrupt entry function. -- Nestable interrupts disabled.
OS_CallISR() can be used as entry function in an embOS interrupt handler,
when the corresponding interrupt should not be interrupted by another embOS interrupt.
OS_CallISR() sets the interrupt priority of the CPU to the user definable fast interrupt priority level,
thus locking any other embOS interrupt. <Normal Interrupt>
Fast interrupts are not disabled.
OS_EnterInterrupt() Informs embOS that interrupt code is executing. -- Nestable interrupts disabled.
(1) disables task switches
(2) keeps interrupts in internal routines disabled. <Normal Interrupt - 任何优先级的中断 >
(3) Fast interrupts are not disabled.
OS_LeaveInterrupt() Informs embOS that the end of the interrupt routine has been reached;
executes task switching within ISR.
If the interrupt has caused a task switch, it will be executed
(unless the program which was interrupted was in a critical region).
----------------------------------------------------------------------------------------------------------------------------
OS_CallNestableISR() Interrupt entry function supporting nestable interrupts. -- Nestable interrupts enabled.
OS_CallNestableISR() can be used as entry function in an embOS interrupt handler,
when interruption by higher prioritized embOS interrupts should be allowed.
OS_CallNestableISR() does not alter the interrupt priority of the CPU,
thus keeping all interrupts with higher priority enabled. < 高于当前中断优先级的中断 >
Fast interrupts are not disabled.
__interrupt void ISR_Timer(void) { OS_EnterInterrupt(); OS_SignalEvent(1,&Task);/* Any functionality could be here */ OS_LeaveInterrupt(); }
OS_EnterNestableInterrupt() Informs embOS that interrupt code is executing and reenables interrupts.
(1) Re-enables interrupts and increments the embOS internal critical region counter, thus disabling further task switches.
(2) implemented as a macro and offers the same functionality as OS_EnterInterrupt() in combination with OS_DecRI()
(3) Fast interrupts are not disabled.
OS_LeaveNestableInterrupt() Informs embOS that the end of the interrupt routine has been reached;
executes task switching within ISR.
(1) disables interrupts right before ending the interrupt routine again, thus restores the default condition
(2) then decrements the embOS internal critical region count,
thus re-enabling task switches if the counter has reached zero again.
(3) implemented as a macro and offers the same functionality as OS_LeaveInterrupt() in combination with OS_IncDI()
static void _Systick(void) { OS_EnterNestableInterrupt(); // Inform embOS that interrupt code is running OS_HandleTick(); // May be interrupted by higher priority interrupts OS_LeaveNestableInterrupt(); // Inform embOS that interrupt handler is left }
----------------------------------------------------------------------------------------------------------------------------
embOS for Cortex M3 / M4 and M4F
----------------------------------------------------------------------------------------------------------------------------
Interrupt-stack switching
Since Cortex M core based controllers have two separate stack pointers,
and embOS runs the user application on the process stack, ( PSP )
there is no need for explicit stacks witching in an interrupt routine which runs on the main stack. ( MSP )
The routines OS_EnterIntStack() and OS_LeaveIntStack() are supplied for
source code compatibility to other processors only and have no functionality.
Fast interrupts
with Instead of disabling interrupts when embOS does atomic operations,
the interrupt level of the CPU is set to 128.
Therefore all interrupt priorities higher than 128 can still be processed.
Please note, that lower priority numbers define a higher priority.
All interrupts with priority level from 0 to 127 are never disabled.
These interrupts are named Fast interrupts.
You must not execute any embOS function from within a fast interrupt function.
Interrupt priorities
(1) Any interrupt handler using embOS API functions has to run with interrupt priorities from 128 to 255.
These embOS interrupt handlers have to start with OS_EnterInterrupt() or OS_EnterNestableInterrupt()
and have to end with OS_LeaveInterrupt() or OS_LeaveNestableInterrupt().
These embOS interrupt handlers do not calling any embOS API function are allowed,
but must not reenable interrupts! < to reenable it, call OS_EnterNestableInterrupt() >
(2) Any Fast interrupt (running at priorities from 0 to 127)
These interrupt handlers must not call any embOS API function.
Even OS_EnterInterrupt() and OS_LeaveInterrupt() must not be called.
Priority of the embOS scheduler < PendSV_Handler() --> OS_Exception() >
The embOS scheduler runs on the lowest interrupt priority.
The scheduler may be preempted by any other interrupt with higher preemption priority level.
The application interrupts shall run on higher preemption levels to ensure short reaction time.
Priority of the embOS system timer < SysTick_Handler() --> OS_Systick() >
The embOS system timer runs on the second lowest preemption level.
Thus, the embOS timer may preempt the scheduler.
Application interrupts which require fast reaction should run on a higher preemption priority level.
Priority of embOS software timers
The embOS software timer callback functions are called from the scheduler
and run on the schedulers preemption priority level which is the lowest interrupt priority level.
To ensure short reaction time of other interrupts,
other interrupts should run on a higher preemption priority level
and the software timer callback functions should be as short as possible.
Priority of application interrupts
Application interrupts using embOS functions may run on any priority level between 255 to 128.
However, interrupts, which require fast reaction should run on higher priority levels
than the embOS scheduler and the embOS system timer to allow preemption of theses interrupt handlers.
(1) require fastest reaction should run on a higher preemption priority level than 128 ( 0..7 )
(2) require fast reaction should run on a higher preemption priority level than Priority of the embOS system timer. ( 8..13 )
(3) require short reaction should run on a higher preemption priority level than Priority of the embOS scheduler. ( 8..14 )
the embOS scheduler : 15 < PendSV_Handler() --> OS_Exception() >
the embOS system timer : 14 < SysTick_Handler() --> OS_Systick() >
the application short interrupt : 14..8
the application fast interrupt : 13..8
the application fastest interrupt : 7..0