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 message 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.
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.
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.
This table lists the fatal errors generated by Dynamic C.
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.
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.
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:
Register |
Expected Value |
H |
XPC when exception() was called |
L |
Run-time error code |
HL’ |
Address where exception() was called from |
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.
A circular buffer in extended RAM will be filled with the following information for each run-time error that occurs:
The value of SEC_TIMER at the time of the error. This variable contains the number of seconds since 00:00:00 on January 1st 1980 if the real-time clock has been set correctly. This variable is updated by the periodic timer which is enabled by default. Rabbit sets the real-time clock in the factory. When the BIOS starts on boards with batteries, it initializes SEC_TIMER to the value in the real-time clock.
The address where the exception was called from. This can be traced to a particular function using the MAP file generated when a Dynamic C program is compiled.
The exception type. Please see Table 9-1 on page 132 for a list of exception types.
The value of all registers. This includes alternate registers, SP and XPC. This is a global option that is enabled by default.
An 8-byte message. This is a global option that is disabled by default. The default error handler does nothing with this.
A user-definable length of stack dump. This is a global option that is enabled by default.
A one byte checksum of the entry.
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.
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:
A status byte
The number of errors since deployment
The index of the last error
The number of hardware resets since deployment
The number of watchdog time-outs since deployment
The number of software resets since deployment
A checksum byte.
“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.
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 messages in log entries The default error handler makes no use of this feature.
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. |
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