9. Run-Time Errors

Compiled code generated by Dynamic C calls an exception handling routine for run-time errors. The exception handler supplied with Dynamic C prints internally defined error messages to a Windows mes­sage box when run-time errors are detected during a debugging session. When software runs stand-alone (disconnected from Dynamic C), such a run-time error will cause a watchdog timeout and reset. Run-time error logging is available for Rabbit-based target systems with battery-backed RAM.

9.1 Run-Time Error Handling

When a run-time error occurs, a call is made to exception(). The run-time error type is passed to exception(), which then pushes various parameters on the stack, and calls the installed error handler. The default error handler places information on the stack, disables interrupts, and enters an endless loop by calling the _xexit function in the BIOS. Dynamic C notices this and halts execution, reporting a run-time error to the user.

9.1.1  Error Code Ranges

The table below shows the range of error codes used by Dynamic C and the range available for a custom error handler to use. Table 9-1 is valid prior to Dynamic C version 9.30. Starting with DC 9.30, the file errmsg.ini located in the root directory of Dynamic C can be edited to add descriptions for user-defined run-time errors that will be displayed by Dynamic C should the error occur.

For example, if the following entry is made in errmsg.ini:

// My custom errors
800=My own run-time error message

Calling “exit(-800)” in an application or library will cause Dynamic C to report “My own run-time error message” in a message box.

Please see Section 9.2 for information on replacing the default error handler with a custom one.

9.1.2  Fatal Error Codes

This table lists the fatal errors generated by Dynamic C.

 

Table 9-1.  Dynamic C Fatal Errors

Error Type

Meaning

127 - 227

not used

228

Pointer store out of bounds

229

Array index out of bounds

230 - 233

not used

234

Domain error (for example, acos(2))

235

Range error (for example, tan(pi/2))

236

Floating point overflow

237

Long divide by zero

238

Long modulus, modulus zero

239

not used

240

Integer divide by zero

241

Unexpected interrupt

242

not used

243

Codata structure corrupted

244

Virtual watchdog timeout

245

XMEM allocation failed (xalloc call)

246

Stack allocation failed

247

Stack deallocation failed

248

not used

249

Xmem allocation initialization failed

250

No virtual watchdog timers available

251

No valid MAC address for board

252

Invalid cofunction instance

253

Socket passed as auto variable while running µC/OS-II

254 - 255

not used

9.2 User-Defined Error Handler

Dynamic C allows replacement of the default error handler with a custom error handler. This is needed to add run-time error handling that would require treatment not supported by the default handler.

A custom error handler can also be used to change how existing run-time errors are handled. For example, the floating-point math libraries included with Dynamic C are written to allow for execution to continue after a domain or range error, but the default error handler halts with a run-time error if that state occurs. If continued execution is desired (the function in question would return a value of INF or whatever value is appropriate), then a simple error handler could be written to pass execution back to the program when a domain or range error occurs, and pass any other run-time errors to Dynamic C.

9.2.1  Replacing the Default Handler

To tell the BIOS to use a custom error handler, call this function:

void defineErrorHandler(void *errfcn)

This function sets the BIOS function pointer for run-time errors to the one passed to it.

When a run-time error occurs, exception() pushes onto the stack the information detailed in the table below.

Table 9-2.  Stack Setup for Run-time Errors

Address

Data at address

SP+0

Return address for error handler

SP+2

Error code

SP+4

Additional data (user-defined)

SP+6

XPC when exception() was called (upper byte)

SP+8

Address where exception() was called from

.

Then exception() calls the installed error handler. If the error handler passes the run-time error to Dynamic C (i.e. it is a fatal error and the system needs to be halted or reset), then registers must be loaded appropriately before calling the _xexit function.

Dynamic C expects the following values to be loaded:

 

Table 9-3.  Register Contents Loaded by Error Handler Before Passing the Error to Dynamic C

Register

Expected Value

H

XPC when exception() was called

L

Run-time error code

HL’

Address where exception() was called from

9.3 Run-Time Error Logging

Error logging is available as a BIOS enhancement for storing run-time exception history. It can be useful diagnosing problems in deployed Rabbit targets. To support error logging, the target must have battery-backed RAM.

Error logging is no longer supported as of Dynamic C 10.40.

9.3.1  Error Log Buffer

A circular buffer in extended RAM will be filled with the following information for each run-time error that occurs:

The size of the error log buffer is determined by the number of entries, the size of an entry, and the header information at the beginning of the buffer. The number of entries is determined by the macro ERRLOG_NUM_ENTRIES (default is 78). The size of each entry is dependent on the settings of the global options for stack dump, register dump and error message. The default size of the buffer is about 4K in extended RAM.

9.3.2  Initialization and Defaults

An initialization of the error log occurs when the BIOS is compiled, when cloning takes place or when the BIOS is loaded via the Rabbit Field Utility (RFU). By default, error logging is disabled.

The error log buffer contains header information as well as an entry for each run-time error. A debug start-up will zero out this header structure, but the run-time error entries can still be examined from Dynamic C using the static information in flash. The header is at the start of the error log buffer and contains:

“Deployment” is defined as the first power up without the programming cable attached. Reprogramming the board using the programming cable, the RFU, or a RabbitLink board and starting the program again without the programming cable attached is a new deployment.

9.3.3  Configuration Macros

These macros are defined in Lib\..\BIOSLIB\errlogconfig.lib. Define these macros in your project to use them. For instructions on how to do that, see the “Defines Tab” on page 290.

ENABLE_ERROR_LOGGING

Default: 0. Disables error logging. Changing this to “1” enables error logging.

ERRLOG_USE_REG_DUMP

Default: 1. Include a register dump in log entries. Changing this to zero excludes the register dump in log entries.

ERRLOG_STACKDUMP_SIZE

Default: 16. Include a stack dump of size ERRLOG_STACKDUMP_SIZE in log entries. Changing this to zero excludes the stack dump in log entries.

ERRLOG_NUM_ENTRIES

Default: 78. This is the number of entries allowed in the log buffer.

ERRLOG_USE_MESSAGE

Default: 0. Exclude error messages from log entries. Changing this to “1” includes 8 byte error mes­sages in log entries The default error handler makes no use of this feature.

9.3.4  Error Logging Functions

The run-time error logging API consists of the following functions:

errlogGetHeaderInfo

Reads error log header and formats output.

errlogGetNthEntry

Loads errLogEntry structure with the Nth entry from the error log buffer. errLogEntry is a pre-allocated global structure.

errlogGetMessage

Returns a NULL-terminated string containing the 8 byte error message in errLogEntry.

errlogFormatEntry

Returns a NULL-terminated string containing basic information in errLogEntry.

errlogFormatRegDump

Returns a NULL-terminated string containing the register dump in errLogEntry.

errlogFormatStackDump

Returns a NULL-terminated string containing the stack dump in errLogEntry.

errlogReadHeader

Reads error log header into the structure errlogInfo.

ResetErrorLog

Resets the exception and restart type counts in the error log buffer header.

9.3.5  Examples of Error Log Use

To try error logging, follow the instructions at the top of the sample programs:

samples\ErrorHandling\Generate_runtime_errors.c

and

samples\ErrorHandling\Display_errorlog.c