Runtime Errors

Error and Fault handling.

Overview

Run-time errors are primarily handled by module RuntimeErrors.

There are two types of run-time problems that are caught and reported:

  • Errors: checks inserted by the Astrobe compiler, using the SVC system exception to signal a problem;
  • Faults: checks done by the MCU hardware, using the dedicated system exceptions to signal a problem.

Errors are always caught synchronously to the execution of the program, Faults can be synchronous or asynchronous. Errors include array index out of bounds, division by zero, Faults include Bus Faults or Usage Faults.

Module RuntimeErrors installs a handler for the SVC exception as well as all hardware fault exceptions at initialisation.

Together with the SVC instruction, the Astrobe compiler also inserts the corresponding line number of the source code, so the error messages can include a direct reference to the faulty line in the program text, together with the absolute code address in memory. For Fault exceptions, we only have the code address available to track down the exact location of the problem.

Separation of Error Handling and Output

Since a control program must be able to run unattended, that is, without any human operator present, possibly even without a terminal attached, RuntimeErrors does not do any error message output. Rather, the error exception handler collect a defined set of data in a data structure, which is then available for a user-installable error handler.

That handler can then log the error and its data, acquire more information, such as a stack trace or the contents of the registers as stacked by the error exception, print the data, or even attempt to recover from the error, eg. by resetting the offending process, or the MCU. Module RuntimeErrorsOut provides a compatible handler that prints out the error information, including a stack trace and the stacked registers’ contents, and then halts, for development and debugging purposes.

Also, printing error messages on a serial terminal takes a lot of time. If autonomous problem recovery is the primary goal, in order to keep the control program running, no time should be wasted with output.

Module Stacktrace provides the tools to create a stack trace and read the stacked registers contents.

Error Data

The data collected by the Error and Fault handlers include:

  • MCU core;
  • Error or Fault code;
  • error type
  • absolute code address in memory;
  • source code line number, if available;
  • base address of the exception stack frame;
  • EXC_RETURN value.

This data is meant to be minimal, with a three-fold purpose:

  • allow error analysis of log entry data;
  • allow autonomous error recovery;
  • allow further analysis by development tools, such as stack traces.

With the RP2350, when the FPU is enabled and used, the stack frame contains an additional 18 word stack context for the lower half of the FPU registers. And when using both Secure and Non-secure code, there can be additional contexts. In total there are four different possible stack frame layouts. We neglect the Non-secure realm for now, so we only have to deal with two possible stack frame schemes.

Terminology

  • Each exception creates a stack frame.
  • Each stack frame contains one or more contexts:
    • state context: the standard 8x 32-bit words
    • additional state context: 10x 32 bit words, used for Non-secure exceptions
    • FP context: 18x 32-bit words, used for FPU registers
    • additional FP context: 16x 32-bit words, used for Non-secure exceptions

Core Separation

Since a run-time problem can occur in either core at the same time, RuntimeErrors maintains error data structures for each core, and the program code is re-entrant (thread safe).

See Also

Updated: 2025-04-30