Documentation: Improve "High Performance, Zero Latency Interrupts"
* Documentation/guides/zerolatencyinterrupts.rst: Add paragraph that defines jitter. Fix a few minor typos. Fix incorrect reStructuredText formatting for bulletpoints (they were being rendered like 2nd level bulletpoints). * Documentation/guides/index.rst: Add zerolatencyinterrupts.rst to the TOC, which I forgot to do in PR # 9302.
This commit is contained in:
parent
ab02bdc626
commit
33bf661413
|
@ -16,3 +16,4 @@ Guides
|
|||
pysimcoder.rst
|
||||
customboards.rst
|
||||
customapps.rst
|
||||
zerolatencyinterrupts.rst
|
||||
|
|
|
@ -8,19 +8,27 @@ Generic Interrupt Handling
|
|||
NuttX includes a generic interrupt handling subsystem that makes it
|
||||
convenient to deal with interrupts using only IRQ numbers. In order to
|
||||
integrate with this generic interrupt handling system, the platform
|
||||
specific code is expected to collect all thread state into an container,
|
||||
specific code is expected to collect all thread state into a container,
|
||||
``struct xcptcontext``. This container represents the full state of the
|
||||
thread and can be saved, restored, and exchanged as a *unit of thread*.
|
||||
|
||||
While this state saving has many useful benefits, it does require
|
||||
processing time. It was reported to me that this state saving required
|
||||
about two microseconds on an STM32F4Discovery board. That added
|
||||
interrupt latency might be an issue in some circumstance.
|
||||
interrupt latency might be an issue in some circumstances.
|
||||
|
||||
**Terminology:** The concepts discussed in this Wiki are not unique to
|
||||
NuttX. Other RTOS have similar concepts but will use different
|
||||
In addition, critical sections that are required in various places
|
||||
throughout the RTOS can pause interrupt handling momentarily. This
|
||||
increases the latency for those interrupts which become pending during a
|
||||
critical section. As this is likely to occur for some instances of an
|
||||
interrupt and not others, the interrupt latency varies from time to time
|
||||
(experiences *jitter*). Like the added latency discussed above, that
|
||||
jitter might be an issue in some circumstances.
|
||||
|
||||
**Terminology:** The concepts discussed in this guide are not unique to
|
||||
NuttX. Other RTOSes have similar concepts but will use different
|
||||
terminology. The `Nucleus <https://www.embedded.com/design/operating-systems/4461604/Interrupts-in-the-Nucleus-SE-RTOS>`_
|
||||
RTOS, for example use the terms *Native* and *Managed* interrupts.
|
||||
RTOS, for example, uses the terms *Native* and *Managed* interrupts.
|
||||
|
||||
Bypassing the Generic Interrupt Handling
|
||||
========================================
|
||||
|
@ -53,24 +61,23 @@ when the ``CONFIG_ARCH_RAMVECTORS`` option is enabled.
|
|||
|
||||
So what is the downside? There are two:
|
||||
|
||||
- Your custom interrupt handler will not have collected its state
|
||||
into the ``struct xcptcontext`` container. Therefore, it cannot
|
||||
communicate with operating system. Your custom interrupt handler
|
||||
has been taken "out of the game" and can no longer work with the
|
||||
system.
|
||||
* Your custom interrupt handler will not have collected its state into
|
||||
the ``struct xcptcontext`` container. Therefore, it cannot communicate
|
||||
with operating system. Your custom interrupt handler has been taken
|
||||
"out of the game" and can no longer work with the system.
|
||||
|
||||
- If your custom interrupt is truly going to be *high performance*
|
||||
then you will also have to support nested interrupts! The custom
|
||||
interrupt must have a high priority and must be able interrupt the
|
||||
generic interrupt handling logic. Otherwise, it will be
|
||||
occasionally delayed when there is a collision between your custom
|
||||
interrupt and other, lower priority interrupts.
|
||||
* If your custom interrupt is truly going to be *high performance* then
|
||||
you will also have to support nested interrupts! The custom interrupt
|
||||
must have a high priority and must be able interrupt the generic
|
||||
interrupt handling logic. Otherwise, it will be occasionally delayed
|
||||
when there is a collision between your custom interrupt and other,
|
||||
lower priority interrupts.
|
||||
|
||||
Getting Back into the Game
|
||||
==========================
|
||||
|
||||
As mentioned, the custom interrupt handler can not use most of the
|
||||
service of the OS since it has not created a ``struct xcptcontext``
|
||||
As mentioned, the custom interrupt handler cannot use most of the
|
||||
services of the OS since it has not created a ``struct xcptcontext``
|
||||
container. So it needs a mechanism to "get back into the game" when it
|
||||
needs to interact with the operating system to, for example, post a
|
||||
semaphore, signal a thread, or send a message.
|
||||
|
@ -78,16 +85,15 @@ semaphore, signal a thread, or send a message.
|
|||
The ARM Cortex-M family supports a special way to do this using the
|
||||
*PendSV* interrupt:
|
||||
|
||||
- The custom logic would connect with the *PendSV* interrupt using
|
||||
the standard ``irq_attach()`` interface.
|
||||
* The custom logic would connect with the *PendSV* interrupt using the
|
||||
standard ``irq_attach()`` interface.
|
||||
|
||||
- In the custom interrupt handler, it would schedule the *PendSV*
|
||||
interrupt when it needs to communicate with the OS.
|
||||
* In the custom interrupt handler, it would schedule the *PendSV*
|
||||
interrupt when it needs to communicate with the OS.
|
||||
|
||||
- The *PendSV* interrupt is dispatched through generic interrupt
|
||||
system so when the attached *PendSV* interrupt is handled, it
|
||||
will be in a context where it can perform any necessary OS
|
||||
interactions.
|
||||
* The *PendSV* interrupt is dispatched through the generic interrupt
|
||||
system so when the attached *PendSV* interrupt is handled, it will be
|
||||
in a context where it can perform any necessary OS interactions.
|
||||
|
||||
With the ARMv7_M architecture, the *PendSV* interrupt can be generated
|
||||
with:
|
||||
|
@ -118,27 +124,26 @@ interrupt interrupt handler.
|
|||
Modifications may be required to the generic interrupt handling logic
|
||||
to accomplish. A few points need to be made here:
|
||||
|
||||
- The MCU should support interrupt prioritization so that the custom
|
||||
interrupt can be scheduled with a higher priority.
|
||||
* The MCU should support interrupt prioritization so that the custom
|
||||
interrupt can be scheduled with a higher priority.
|
||||
|
||||
- The generic interrupt handlers currently disable interrupts during
|
||||
interrupts. Instead, they must be able to keep the custom
|
||||
interrupt enabled throughout interrupt process but still prevent
|
||||
re-entrancy by other standard interrupts (This can be done by
|
||||
setting an interrupt base priority level in the Cortex-M family).
|
||||
* The generic interrupt handlers currently disable interrupts during
|
||||
interrupts. Instead, they must be able to keep the custom interrupt
|
||||
enabled throughout interrupt process but still prevent re-entrancy by
|
||||
other standard interrupts (This can be done by setting an interrupt
|
||||
base priority level in the Cortex-M family).
|
||||
|
||||
- The custom interrupt handler can now interrupt the generic
|
||||
interrupt handler at any place. Is the logic safe in all cases to
|
||||
be interrupted? Sometimes interrupt handlers place the MCU in
|
||||
momentarily perverse states while registers are being
|
||||
manipulated. Make sure that it is safe to take interrupts at any
|
||||
time (or else keep the interrupts disabled in the critical
|
||||
times).
|
||||
* The custom interrupt handler can now interrupt the generic interrupt
|
||||
handler at any place. Is the logic safe in all cases to be
|
||||
interrupted? Sometimes interrupt handlers place the MCU in momentarily
|
||||
perverse states while registers are being manipulated. Make sure that
|
||||
it is safe to take interrupts at any time (or else keep the interrupts
|
||||
disabled in the critical times).
|
||||
|
||||
- Will the custom interrupt handler have all of the resources it
|
||||
needs in place when it occurs? Will it have a valid stack
|
||||
pointer? (In the Cortex-M implementation, for example, the MSP
|
||||
may not be valid when the custom interrupt handler is entered).
|
||||
* Will the custom interrupt handler have all of the resources it needs
|
||||
in place when it occurs? Will it have a valid stack pointer? (In the
|
||||
Cortex-M implementation, for example, the MSP may not be valid when
|
||||
the custom interrupt handler is entered).
|
||||
|
||||
Some of these issues are complex and so you should expect some
|
||||
complexity in getting the nested interrupt handler to work.
|
||||
|
@ -201,14 +206,13 @@ priority interrupts.
|
|||
Dependencies
|
||||
------------
|
||||
|
||||
- ``CONFIG_ARCH_HAVE_IRQPRIO``. Support for prioritized interrupt
|
||||
support must be enabled.
|
||||
* ``CONFIG_ARCH_HAVE_IRQPRIO``. Support for prioritized interrupt
|
||||
support must be enabled.
|
||||
|
||||
- Floating Point Registers. If used with a Cortex-M4 that supports
|
||||
hardware floating point, you cannot use hardware floating point
|
||||
in the high priority interrupt handler UNLESS you use the common
|
||||
vector logic that supports saving of floating point registers on
|
||||
all interrupts.
|
||||
* Floating Point Registers. If used with a Cortex-M4 that supports
|
||||
hardware floating point, you cannot use hardware floating point in the
|
||||
high priority interrupt handler UNLESS you use the common vector logic
|
||||
that supports saving of floating point registers on all interrupts.
|
||||
|
||||
Configuring High Priority Interrupts
|
||||
------------------------------------
|
||||
|
@ -220,14 +224,13 @@ First, You need to change the address in the vector table so that the
|
|||
high priority interrupt vectors to your special C interrupt handler.
|
||||
There are two ways to do this:
|
||||
|
||||
- If you select ``CONFIG_ARCH_RAMVECTORS``, then vectors will be
|
||||
kept in RAM and the system will support the interface: ``int
|
||||
up_ramvec_attach(int irq, up_vector_t vector)``. That interface
|
||||
can be used to attach your C interrupt handler to the vector at
|
||||
run time.
|
||||
* If you select ``CONFIG_ARCH_RAMVECTORS``, then vectors will be kept in
|
||||
RAM and the system will support the interface: ``int
|
||||
up_ramvec_attach(int irq, up_vector_t vector)``. That interface can be
|
||||
used to attach your C interrupt handler to the vector at run time.
|
||||
|
||||
- Alternatively, you could keep your vectors in FLASH but in order
|
||||
to this, you would have to develop your own custom vector table.
|
||||
* Alternatively, you could keep your vectors in FLASH but in order to
|
||||
this, you would have to develop your own custom vector table.
|
||||
|
||||
Second, you need to set the priority of your interrupt to *NVIC* to
|
||||
``NVIC_SYSH_HIGH_PRIORITY`` using the standard interface:
|
||||
|
@ -238,12 +241,11 @@ Example Code
|
|||
|
||||
You can find an example that tests the high priority, nested interrupts in the NuttX source:
|
||||
|
||||
- nuttx/boards/arm/stm32/viewtool-stm32f107/README.txt. Description
|
||||
of the configuration
|
||||
* nuttx/boards/arm/stm32/viewtool-stm32f107/README.txt. Description of
|
||||
the configuration
|
||||
|
||||
- nuttx/boards/arm/stm32/viewtool-stm32f107/highpri. Test
|
||||
configuration
|
||||
* nuttx/boards/arm/stm32/viewtool-stm32f107/highpri. Test configuration
|
||||
|
||||
- nuttx/boards/arm/stm32/viewtool-stm32f107/src/stm32_highpri. Test
|
||||
driver.
|
||||
* nuttx/boards/arm/stm32/viewtool-stm32f107/src/stm32_highpri. Test
|
||||
driver.
|
||||
|
||||
|
|
Loading…
Reference in New Issue