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:
Nathan Hartman 2023-05-18 17:57:02 -04:00 committed by Xiang Xiao
parent ab02bdc626
commit 33bf661413
2 changed files with 67 additions and 64 deletions

View File

@ -16,3 +16,4 @@ Guides
pysimcoder.rst pysimcoder.rst
customboards.rst customboards.rst
customapps.rst customapps.rst
zerolatencyinterrupts.rst

View File

@ -8,19 +8,27 @@ Generic Interrupt Handling
NuttX includes a generic interrupt handling subsystem that makes it NuttX includes a generic interrupt handling subsystem that makes it
convenient to deal with interrupts using only IRQ numbers. In order to convenient to deal with interrupts using only IRQ numbers. In order to
integrate with this generic interrupt handling system, the platform 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 ``struct xcptcontext``. This container represents the full state of the
thread and can be saved, restored, and exchanged as a *unit of thread*. thread and can be saved, restored, and exchanged as a *unit of thread*.
While this state saving has many useful benefits, it does require While this state saving has many useful benefits, it does require
processing time. It was reported to me that this state saving required processing time. It was reported to me that this state saving required
about two microseconds on an STM32F4Discovery board. That added 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 In addition, critical sections that are required in various places
NuttX. Other RTOS have similar concepts but will use different 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>`_ 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 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: So what is the downside? There are two:
- Your custom interrupt handler will not have collected its state * Your custom interrupt handler will not have collected its state into
into the ``struct xcptcontext`` container. Therefore, it cannot the ``struct xcptcontext`` container. Therefore, it cannot communicate
communicate with operating system. Your custom interrupt handler with operating system. Your custom interrupt handler has been taken
has been taken "out of the game" and can no longer work with the "out of the game" and can no longer work with the system.
system.
- If your custom interrupt is truly going to be *high performance* * If your custom interrupt is truly going to be *high performance* then
then you will also have to support nested interrupts! The custom you will also have to support nested interrupts! The custom interrupt
interrupt must have a high priority and must be able interrupt the must have a high priority and must be able interrupt the generic
generic interrupt handling logic. Otherwise, it will be interrupt handling logic. Otherwise, it will be occasionally delayed
occasionally delayed when there is a collision between your custom when there is a collision between your custom interrupt and other,
interrupt and other, lower priority interrupts. lower priority interrupts.
Getting Back into the Game Getting Back into the Game
========================== ==========================
As mentioned, the custom interrupt handler can not use most of the As mentioned, the custom interrupt handler cannot use most of the
service of the OS since it has not created a ``struct xcptcontext`` 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 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 needs to interact with the operating system to, for example, post a
semaphore, signal a thread, or send a message. 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 The ARM Cortex-M family supports a special way to do this using the
*PendSV* interrupt: *PendSV* interrupt:
- The custom logic would connect with the *PendSV* interrupt using * The custom logic would connect with the *PendSV* interrupt using the
the standard ``irq_attach()`` interface. standard ``irq_attach()`` interface.
- In the custom interrupt handler, it would schedule the *PendSV* * In the custom interrupt handler, it would schedule the *PendSV*
interrupt when it needs to communicate with the OS. interrupt when it needs to communicate with the OS.
- The *PendSV* interrupt is dispatched through generic interrupt * The *PendSV* interrupt is dispatched through the generic interrupt
system so when the attached *PendSV* interrupt is handled, it system so when the attached *PendSV* interrupt is handled, it will be
will be in a context where it can perform any necessary OS in a context where it can perform any necessary OS interactions.
interactions.
With the ARMv7_M architecture, the *PendSV* interrupt can be generated With the ARMv7_M architecture, the *PendSV* interrupt can be generated
with: with:
@ -118,27 +124,26 @@ interrupt interrupt handler.
Modifications may be required to the generic interrupt handling logic Modifications may be required to the generic interrupt handling logic
to accomplish. A few points need to be made here: to accomplish. A few points need to be made here:
- The MCU should support interrupt prioritization so that the custom * The MCU should support interrupt prioritization so that the custom
interrupt can be scheduled with a higher priority. interrupt can be scheduled with a higher priority.
- The generic interrupt handlers currently disable interrupts during * The generic interrupt handlers currently disable interrupts during
interrupts. Instead, they must be able to keep the custom interrupts. Instead, they must be able to keep the custom interrupt
interrupt enabled throughout interrupt process but still prevent enabled throughout interrupt process but still prevent re-entrancy by
re-entrancy by other standard interrupts (This can be done by other standard interrupts (This can be done by setting an interrupt
setting an interrupt base priority level in the Cortex-M family). base priority level in the Cortex-M family).
- The custom interrupt handler can now interrupt the generic * The custom interrupt handler can now interrupt the generic interrupt
interrupt handler at any place. Is the logic safe in all cases to handler at any place. Is the logic safe in all cases to be
be interrupted? Sometimes interrupt handlers place the MCU in interrupted? Sometimes interrupt handlers place the MCU in momentarily
momentarily perverse states while registers are being perverse states while registers are being manipulated. Make sure that
manipulated. Make sure that it is safe to take interrupts at any it is safe to take interrupts at any time (or else keep the interrupts
time (or else keep the interrupts disabled in the critical disabled in the critical times).
times).
- Will the custom interrupt handler have all of the resources it * Will the custom interrupt handler have all of the resources it needs
needs in place when it occurs? Will it have a valid stack in place when it occurs? Will it have a valid stack pointer? (In the
pointer? (In the Cortex-M implementation, for example, the MSP Cortex-M implementation, for example, the MSP may not be valid when
may not be valid when the custom interrupt handler is entered). the custom interrupt handler is entered).
Some of these issues are complex and so you should expect some Some of these issues are complex and so you should expect some
complexity in getting the nested interrupt handler to work. complexity in getting the nested interrupt handler to work.
@ -201,14 +206,13 @@ priority interrupts.
Dependencies Dependencies
------------ ------------
- ``CONFIG_ARCH_HAVE_IRQPRIO``. Support for prioritized interrupt * ``CONFIG_ARCH_HAVE_IRQPRIO``. Support for prioritized interrupt
support must be enabled. support must be enabled.
- Floating Point Registers. If used with a Cortex-M4 that supports * Floating Point Registers. If used with a Cortex-M4 that supports
hardware floating point, you cannot use hardware floating point hardware floating point, you cannot use hardware floating point in the
in the high priority interrupt handler UNLESS you use the common high priority interrupt handler UNLESS you use the common vector logic
vector logic that supports saving of floating point registers on that supports saving of floating point registers on all interrupts.
all interrupts.
Configuring High Priority 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. high priority interrupt vectors to your special C interrupt handler.
There are two ways to do this: There are two ways to do this:
- If you select ``CONFIG_ARCH_RAMVECTORS``, then vectors will be * If you select ``CONFIG_ARCH_RAMVECTORS``, then vectors will be kept in
kept in RAM and the system will support the interface: ``int RAM and the system will support the interface: ``int
up_ramvec_attach(int irq, up_vector_t vector)``. That interface up_ramvec_attach(int irq, up_vector_t vector)``. That interface can be
can be used to attach your C interrupt handler to the vector at used to attach your C interrupt handler to the vector at run time.
run time.
- Alternatively, you could keep your vectors in FLASH but in order * Alternatively, you could keep your vectors in FLASH but in order to
to this, you would have to develop your own custom vector table. this, you would have to develop your own custom vector table.
Second, you need to set the priority of your interrupt to *NVIC* to Second, you need to set the priority of your interrupt to *NVIC* to
``NVIC_SYSH_HIGH_PRIORITY`` using the standard interface: ``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: 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 * nuttx/boards/arm/stm32/viewtool-stm32f107/README.txt. Description of
of the configuration the configuration
- nuttx/boards/arm/stm32/viewtool-stm32f107/highpri. Test * nuttx/boards/arm/stm32/viewtool-stm32f107/highpri. Test configuration
configuration
- nuttx/boards/arm/stm32/viewtool-stm32f107/src/stm32_highpri. Test * nuttx/boards/arm/stm32/viewtool-stm32f107/src/stm32_highpri. Test
driver. driver.