<< Previous | Index | Next >>

> ## 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 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.

> ### 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 on page 145 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 | not used
> 255

> ### 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 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 144 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.

> #### 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:

> - 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.

> #### 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.

> ##### 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.

> #### 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

Dynamic C User's Manual | << Previous | Index | Next>> | rabbit.com