mirror of
https://github.com/apache/nuttx.git
synced 2026-08-02 12:49:00 +00:00
* This completes task list in https://github.com/apache/nuttx/issues/11127. * This preserves selected content from cwiki and moves it to new docs. * Most pages are simple copy-paste with a simple RST formatting updates, with minor updates. * Content update / reorganization will follow later on when needed. * Files added (or updated title from cwiki -> current docs): * Documentation/implementation: * index. * cancellation_points. * Asynchronous vs. Synchronous Context Switches -> context_switches.rst. * ARMv7-M Hardfaults, SVCALL, and Debuggers -> hardfatuls.rst. * chip.h FAQ -> chip_h.rst. * Debug Output (SYSLOG) Issues -> syslog.rst. * Detaching File Descriptors -> file_descriptors.rst. * device_nodes.rst. * Dynamic Clocking -> power_management.rst. * ENOTTY ioctl() Return Value -> ioctl.rst. * memory_configurations.rst. * kernel_modules_vs_shared_libraries.rst. * NAKing USB OUT/IN Tokens -> usb.rst. * naming_arch_mcu_board_interfaces.rst. * naming_os_internals.rst. * nuttx_tasking.rst. * oneshot_timers_and_cpu_load.rst. * nuttx_initialization_sequence.rst. * short_time_delays.rst. * Signal Handler Tour -> signal_handlers.rst. * smp.rst. * syslog.rst. * Task Exit Sequence -> nuttx_tasking.rst. * tasks_vs_threads.rst. * tls.rst. * tickless_os.rst. * Why Can't Kernel Threads Have pthreads -> kernel_threads_vs_pthreads.rst. * Documentation/components/filesystem: * smartfs.rst. Signed-off-by: Tomasz 'CeDeROM' CEDRO <tomek@cedro.info>
144 lines
6.6 KiB
ReStructuredText
144 lines
6.6 KiB
ReStructuredText
.. _hardfaults:
|
|
|
|
==========
|
|
Hardfaults
|
|
==========
|
|
|
|
ARMv7
|
|
=====
|
|
|
|
Cortex-M3 and Cortex-M4
|
|
-----------------------
|
|
|
|
The most popular CPUs in current MCU designs are the Cortex-M3 (ARMv7-M) and
|
|
the Cortex-M4 (ARMv7E-M). Handling of these two architectures is almost
|
|
identical in NuttX (unless hardware floating point is enabled).
|
|
|
|
SVCALL
|
|
------
|
|
|
|
NuttX uses the SVCALL software interrupt in order to perform certain steps
|
|
in the context switching for the Cortex-M3 and Cortext-M4.
|
|
This sequence of logic appears in several places:
|
|
|
|
* Create a short critical section by disabling exceptions,
|
|
* Perform some set-up,
|
|
* Initiate the software exception / SVCALL, and
|
|
* When the software exception processing returns, re-enable exceptions.
|
|
|
|
.. note:: There is a technical difference between interrupts and exceptions.
|
|
In this section the term exception will be used. It is probably
|
|
more accurate since interrupts are really exceptions that result
|
|
from device interrupt lines. Furthermore, when we refer to
|
|
exceptions in this section, we are referring specifically to
|
|
ARMv7-M configurable exceptions.
|
|
|
|
Disabling Interrupts via the PRIMASK register
|
|
---------------------------------------------
|
|
|
|
The ARMv7-M architecture supports a register called the ``PRIMASK`` register.
|
|
The ``PRIMASK`` register contains a single valid bit. If that bit is set to
|
|
one, then exceptions are disabled. If that bit is zero, exceptions are enabled.
|
|
More correctly, when this bit is set to one, it prevents the activation of all
|
|
exceptions with configurable priority.
|
|
|
|
The original NuttX implementation used this ``PRIMASK`` register to enable
|
|
and disable exceptions. Things now get interesting in the sequence of logic
|
|
listed above because the ``PRIMASK`` bit also disables the SVCALL exception!
|
|
So, instead of taking the ``SVCALL`` exception vector, the Cortex-M3/4
|
|
generates a hardfault exception (see ARM.com's discussion of
|
|
`Activation Levels <https://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0337g/Chdbdfjf.html>`_).
|
|
|
|
These hardfaults are not really a problem. The design of the NuttX hardfault
|
|
handler expects these exceptions and does the right thing.
|
|
However, the occurrence of hardfaults may come as a surprise to many people
|
|
and especially to some debuggers.
|
|
|
|
Hardfaults and Debuggers
|
|
------------------------
|
|
|
|
These hardfaults only become a technical issue when dealing with a debugger.
|
|
What does the debugger do when the hardfault occurs?
|
|
|
|
We need to back off and think about some system philosophy here.
|
|
The deep philosophical question here is: Who is in charge of system integrity?
|
|
The debugger or the RTOS?
|
|
|
|
If you are running a primitive NoOS program (like the famous blinky test
|
|
program), then you are running a barebones system and you need
|
|
all of the help you can get. So having the debugger make decisions about what
|
|
is the proper behavior of the blinky program and what is not is a good
|
|
thing for you.
|
|
|
|
But if you are using an advanced RTOS, then the RTOS will want to take
|
|
responsibility of the health of your system and now there is the possibility
|
|
of inconsistencies between the decisions that the RTOS makes and the decisions
|
|
that your debugger makes this hardfault handling is a perfect example here.
|
|
|
|
In NuttX, the hardfaults are controlled by the RTOS, but some debuggers will
|
|
break when the hardfault occurs and make debugging impossible.
|
|
|
|
Some people might take issue with this. Breaking on hardfault can make
|
|
debugging easier, since the break happens in the throwing context and you have
|
|
a hope of obtaining a backtrace and debugging the throwing side callstack.
|
|
However, I would suggest that putting a break point on ``up_assert()`` would
|
|
accomplish the same thing without being so intrusive.
|
|
|
|
How did the debugger know that the hardfault occurred? It knew because of
|
|
settings in the "ARM's Debug Exception and Monitor Control Register" or
|
|
``DEMCR``. Proper settings of the ``DEMCR`` register will allow debugger
|
|
to get break exceptions when a hardfault occrs.
|
|
So one workaround is to just reconfigure the ``DEMCR`` register so that break
|
|
exceptions are no longer generated when hardfaults occur.
|
|
|
|
Here is an example of such logic for the LPC43xx MCU.
|
|
Decoupling the hardfault from the break exception in this way does not work
|
|
with all debuggers, however. Presumably because some debuggers re-enable break
|
|
exceptions on hardfaults.
|
|
|
|
Disabling Interrupts via the BASEPRI register
|
|
---------------------------------------------
|
|
|
|
The ARMv7-M architecture supports another way to disable exceptions using
|
|
a register called the ``BASEPRI`` register. ARMv7-M exceptions are prioritized.
|
|
Each exception can be assigned an 8-bit priority. If the ``BASEPRI`` register
|
|
is set to a non-zero priority value, then it will filter exceptions in this sense:
|
|
|
|
* Exceptions with priority lower than or equal to the ``BASEPRI`` register
|
|
will be disabled.
|
|
* Exceptions with priority higher than the ``BASEPRI`` register will still
|
|
be enabled.
|
|
|
|
Normally this interrupt prioritization is used to support nested interrupt
|
|
handling, but it can also be used for disabling of all exceptions
|
|
if configured properly.
|
|
|
|
.. note:: In the ARMv7-M, higher values correspond to lower priority.
|
|
This can be really confusing!
|
|
|
|
NuttX supports a configuration option called ``CONFIG_ARMV7M_USEBASEPRI``.
|
|
If this option is selected, then the exception prioritization and control
|
|
logic will be configured to use the ``BASEPRI`` register instead of the
|
|
``PRIMASK`` register to disable exceptions.
|
|
This configuration includes the following changes in the behavior:
|
|
|
|
* Normal interrupts and exceptions are restricted to the range
|
|
``{ lowest priority ... (highest priority - 1) }``.
|
|
* The priority of the ``SVCALL`` exception is set to highest priority.
|
|
* When exceptions are enabled, the ``BASEPRI`` register is set to zero,
|
|
enabling exceptions of all priorities.
|
|
* When exceptions are disabled, the ``BASEPRI`` register is set to
|
|
``(highest priority - 1)``, disabling all exceptions except for the
|
|
``SVCALL`` exception.
|
|
|
|
In this way, the ``SVCALL`` exception remains enabled when exceptions
|
|
are disabled and no hardfault occurs.
|
|
|
|
.. note:: The above is inaccurate on several counts. It was simplified
|
|
to make the discussion sane. Not only do higher values correspond
|
|
to lower priorities, but the increment between consecutive 8-bit
|
|
priority values is probably not one. The supported maximum and
|
|
minimum priority values (as well as the step in each priority value)
|
|
may be different for each MCU. To handle this, these values are
|
|
exported in NuttX for each ARMv7-M architecture by header files at
|
|
``nuttx/arch/arm/include/<chip>/chip.h``.
|