| Jackrabbit (BL1800 Series) User's Manual |
![]()
4. Software Reference
4.1 More About Dynamic C
Dynamic C has been in use worldwide since 1989. Dynamic C is specially designed for programming embedded systems. Dynamic C features quick compile and interactive debugging in the real environment. A complete reference to Dynamic C is contained in the Dynamic C Reference Manual.
Dynamic C for RabbitTM processors uses the standard Rabbit programming interface. This is a 10-pin connector that connects to the Rabbit serial port A. It is possible to reset and cold-boot a Rabbit processor via the programming port. No software needs to be present in the target system. More details are available in the Rabbit 2000 Microprocessor User's Manual.
Dynamic C cold-boots the target system and compiles the BIOS. The BIOS is a basic program of a few thousand bytes in length that provides the debugging and communication facilities that Dynamic C needs. Once the BIOS has been compiled, the user can compile his own program and test it. If the BIOS fails because of a crash, a new cold boot and BIOS compile can be done at any time.
Each type of Rabbit microprocessor system can have a different BIOS, or the BIOS program can be customized by using #define options. The Jackrabbit board is supplied with several different BIOS, one for using flash memory to hold the program, and one to use RAM memory to hold the program. RAM memory is useful for holding a program while debugging is being done because it is more flexible than flash memory.
Dynamic C does not use include files, rather it has libraries which are used for the same purpose, that is, to supply function prototypes to programs before they are compiled. Libraries are much easier to use compared to include files.
Dynamic C supports assembly language, either as separate programs or as fragments embedded in C programs. Interrupt routines may be written in Dynamic C or in assembly language.
4.1.1 Operating System Framework
Dynamic C does not include an operating system in the usual sense of a complex software system that is resident in memory. The user has complete control of what is loaded as a part of his program, other than those routines that support loading and debugging and which are inactive at embedded run time. However, certain routines are very basic and normally should always be present and active.
- Periodic interrupt routine. This interrupt routine is driven by the Rabbit periodic interrupt facility, and when enabled creates an interrupt every 16 ticks of the 32.768 kHz oscillator, or every 488 µs. This routine drives three long global variables that keep track of the time: SEC_TIMER, MS_TIMER, and TICK_TIMER that respectively count seconds, milliseconds, and 488 µs ticks. These variables are needed by virtually all functions that measure time. The SEC_TIMER is set to seconds elapsed since 1 Jan 1980, and thus also keeps track of the time and date. The periodic interrupt routine must be disabled when the microprocessor enters sleepy mode and the processor clock is operating at 32.768 kHz. The interrupt routine cannot complete at this slow speed before the next tick of the periodic interrupt. In this situation, the hardware real-time clock can be read directly to provide the time.
- Watchdog support routines. Although the Rabbit watchdog can be disabled, this is not recommended since the watchdog is an essential facility for recovering from crashes. Very few systems are crash-free in real life.
4.2 I/O Drivers
The Jackrabbit board contains four high-power digital output channels, two D/A converter output channels, and one A/D converter input channel. These I/O channels can be accessed using the functions found in the JRIO.LIB library.
4.2.1 Initialization
The function jrioInit() must be called before any other function from the JRIO.LIB library. This function initializes the digital outputs and sets up the driver for the analog input/outputs. The digital outputs correspond to the Rabbit processor's port E bits 0-3, and the analog I/O uses timer B; bits 1, 2, and 4 of port D; and bits 6 and 7 of port E.
The function void jrioInit() initializes the I/O drivers for Jackrabbit. In particular, it sets up parallel port D bits 1, 2, and 4 for analog output, port E bits 0-3 for digital output, and starts up the pulse-width modulation routines for the A/D and D/A channels. Note that these routines can consume up to 20% of the CPU's processing power; the routines use timer B and the B1 and B2 match registers.
4.2.2 Digital Output
The Jackrabbit board contains four high-power digital output drivers, HV0-HV3, on header J4. These can be turned on and off with the following functions from the library JRIO.LIB.
HV0, HV1, and HV2 are open-collector sinking outputs, and are able to sink up to 1 A (200 mA for the BL1810 and BL1820) from a 30 V source connected to the K line on header J4. HV3 is a sourcing output that is able to source up to 500 mA (100 mA for the BL1810 and BL1820) from a 30 V source connected to the K line.
void digOut(int channel, int value)
- sets the state of a digital output bit.
- jrioInit must be called first.
- channel is the output channel number (0-3 on the Jackrabbit).
- value is the output value (0 or 1).
void digOn(int channel)
- sets the state of a digital output bit to on (1).
- jrioInit must be called first.
- channel is the output channel number (0-3 on the Jackrabbit).
void digOff(int channel)
- sets the state of a digital output bit to off (0).
- jrioInit must be called first.
- channel is the output channel number (0-3 on the Jackrabbit).
NOTE See the sample program JRIOTEST.C for an example of using the digital output functions. 4.2.3 Analog Output
The two analog output channels on the Jackrabbit (DA0 and DA1 on header J5) are controlled by a pulse-width modulation (PWM) driver. This requires the use of some fraction of the CPU cycles when the driver is running (up to 20% when both D/A channels are used). A voltage is selected by giving a value from 0 to 1024 to the driver, corresponding roughly to 0.1 V to 3.5 V on DA0. Because of the PWM interrupt frequency, the PWM driver can provide a continuous range of voltage output in the range from 0.1 V to 3.0 V for DA0, and 0.6 V to 3.6 V for DA1. These ranges can be specified with the constants PWM_MIN, PWM_MAX0, and PWM_MAX1. In other words, setting channel DA0 to the value PWM_MIN will output 0.1 V, and setting it to PWM_MAX0 will output 3.0 V. Similarly, setting DA1 to PWM_MIN will output 0.6 V, and setting it to PWM_MAX1 will output 3.6 V. Values below PWM_MIN will be rounded down to 0, and values above PWM_MAX0 (PWM_MAX1 for DA1) will be rounded up to 1024.
The output channels can also be set in an "always on" or "always off" mode, which does not require CPU cycles. The "always on" mode is set by requesting an output value of 1024, and will provide about 3.4 V on channel DA0, and 3.6 V on DA1. The "always off" mode is selected by asking for a value of 0, and provides an output of around 0.1 V on DA0 and 0.0 V on DA1.
See Table 5 below for a summary of the possible analog output voltages corresponding to values given in the anaOut function.
Table 5. Typical Analog Output Voltages Corresponding
to Values in anaOut FunctionThe output value is set using the following function.
void anaOut(int channel, int value)
- sets the state of an analog output channel.
- jrioInit must be called first.
- channel is the output channel number (0 or 1 on the Jackrabbit).
- value is an integer from 0-1024 that corresponds to an output voltage as shown in Table 5.
NOTE See the sample program JRIOTEST.C for examples of using the anaOut function. Effect of Interrupts on Analog I/O
The stability of the voltage output (and hence the voltage input determination as well) depends on the ability of the driver to respond quickly to interrupt requests. Dynamic C debugging, use of the printf function, or any serial communications can disrupt the pulse-width modulation utilized by the driver and cause fluctuations in the voltage outputs. Avoid using serial communications or printf statements during portions of your program where the voltage must remain steady. Also be aware that debugging and running Dynamic C in polling mode will cause fluctuations. Finally, be certain to disable the PWM drivers by setting the output values to 0 or 1024 when you are done using them to free up the CPU.
Calibration of Values to Voltages
The analog output channels on the Jackrabbit board can be more accurately calibrated for each individual Jackrabbit board in the following manner (calibration of DA0 is assumed in this example, calibration of DA1 would proceed similarly):
- Set desired channel output to PWM_MIN.
- Measure voltage Vmin on DA0.
- Set desired channel output to PWM_MAX0.
- Measure voltage Vmax on DA0.
- A linear relation between input value and voltage can now be calculated:
4.2.4 Analog Input
The analog input channel on the Jackrabbit (AD0 on header J5) works by varying analog output channel DA0 until its voltage matches the input voltage on AD0. DA0 obviously cannot be used while an input voltage is being measured, although channel DA0 is still available. The value returned corresponds to the value that DA0 required to match the input voltage (you would call anaOut(0,value) for DA0 to provide that same voltage). If the value returned is negative, then the function considers the value suspect for some reason (most likely a failure of the DA0 voltage to settle quickly). The value can be taken as is, or another measurement can be done.
void anaIn(int channel, int *value)
- Analog input for the Jackrabbit analog input channel (AD0).
- jrioInit must be called first.
- channel is the input channel number (0 only on the Jackrabbit).
An integer between 0 and 1024 will be returned in value, corresponding to a voltage obtained if output channel DA0 was set to that value. If a value is found, but the voltage has not appeared to fully settle, the value will be negative (but equal in magnitude to the found voltage) to allow remeasurement if desired.
NOTE See sample program JRIOTEST.C for an example of the use of anaIn. Two versions of the analog input function are available: the standard function, listed above, that does not return until the measurement has been made, and a cofunction version that can be called from within a costatement. This cofunction version allows other tasks to be performed while the voltage match is being made. The voltage measurement will take ten calls of the cofunction version to make a measurement.
void cof_anaIn(int channel, int *value)
- The parameters are identical to those described above for anaIn.
NOTE See sample program JRIO_COF.C for an example of the use of cof_anaIn. 4.3 RS-232 Serial Communication Drivers
The interface to the Rabbit serial library, RS232.LIB, is designed to provide users with a set of functions that send and receive entire blocks of data without yielding to other tasks, a set of single user cofunctions that send and receive data but yield to other tasks, and a set of circular buffer functions.
The naming convention is serXfn:
- ser - serial
- X - the port being used: A, B, C, or D
- fn - the function being implemented
For example, serBgetc() is the serial port B function getc(), which returns a character.
The Rabbit serial functions are listed in the following groups.
- Open and Close Functions
- Non-Cofunction Blocking Input Functions
- Non-Cofunction Blocking Output Functions
- Single-User Cofunction Input Functions
- Single-User Cofunction Output Functions
- Circular Buffer Functions
4.3.1 Open and Close Functions
The open and close functions enable and disable serial communication over the specified port.
int serXopen (long baud);
- Currently only 8N1 transmission (8 data bits, no parity, 1 stop bit) is supported. The open function sets up the interrupt service routine vector.
Parameters
- baud--desired baud rate in bits per second
Return Value
- 1--The baud rate set on the Rabbit is the same as the input baud rate.
- 0--The baud rate set on the rabbit does not match the input baud rate.
int serXclose ( );
- Disables the serial port interrupt service routine.
Parameters
- None.
Return Value
- 1
4.3.2 Non-Cofunction Blocking Input Functions
These are simple functions that do not use Dynamic C costatements. If no input data are available when called, they return immediately with appropriate status information in their return value. Once they begin to receive characters, they do not yield to other tasks until they complete their operation or until a character-to-character timeout period elapses.
int serXgetc ( );
- Gets a single character. Always returns immediately, either with the next available input byte, or with -1 if none is available.
Parameters
- None
Return Value
- An integer with return character in the low byte. No character is represented by a return of -1.
int serXread (void *data, int length, unsigned long tmout);
- Reads a block of characters. Returns the number of bytes read from an input serial stream. The stream is considered to be ended when all length bytes have been read or when the timeout period elapses waiting for data to appear in the input buffer.
Parameters
- data--Destination data structure. The user must ensure data is allocated for at least length bytes.
- length--The number of bytes to read.
- tmout--The number of milliseconds to wait for receipt of each byte before timing out.
Return Value
- The number of bytes read into data until timed out or until all length bytes have been read.
4.3.3 Non-Cofunction Blocking Output Functions
These are simple functions that do not use Dynamic C costatements. They immediately begin to perform their task, not yielding to other tasks until all characters have been written.
int serXputc (char c);
- Writes a character to the serial port.
Parameters
- c--Character to write
Return Value
- 1 for success, 0 if the character could not be written to the port.
int serXputs (char *s);
- Calls serXwrite (s, strlen (s)).
Parameters
- s--Null-terminated character string source to write to the serial port.
Return Value
- The number of characters written.
int serXwrite (void *data, int length);
- Writes a block of length bytes to the serial port.
Parameters
- data--Destination data structure. The user must ensure data is allocated for at least length bytes.
- length--The number of bytes to read.
Return Value
- The number of bytes written to the serial port.
4.3.4 Single-User Cofunction Input Functions
These are Dynamic C cofunctions. If the input buffer they use is locked or becomes full during the course of their operation, they yield to other tasks, but do not return to execute the next statement within their own costatement block until they have completed their operation.
scofunc int cof_serXgetc ( );
- Reads a single character from the serial port, yielding when not successful, and only returning when a character is successfully read.
Parameters
- None
Return Value
- An integer with the character read in the low byte.
scofunc int cof_serXgets(char *s, int length, unsigned long tmout);
- Reads a null-terminated string, completes its execution when a carriage return is read, length number of characters are read, or the character to character timeout period elapses after the first character is read. It yields to other tasks while the input buffer is locked or becomes empty during its execution, and only returns control to the following statement in its own costatement block when it completes.
Parameters
- data--Destination data structure. The user must ensure data is allocated for at least length bytes.
- length--The number of bytes to read.
- tmout--The number of milliseconds to wait for each character after the first character is read.
Return Value
- 1--CR or length bytes read into s.
- 0--Function times out before reading CR or length bytes.
scofunc int cof_serXread(void *data, int length, unsigned long tmout);
- Reads a block of characters, completes its execution when length number of characters are read, or the character-to-character timeout period elapses after the first character is read. It yields to other tasks while the input buffer is locked or becomes empty during its execution and only returns control to the following statement in its own costatement block when it completes.
Parameters
- data--Destination data structure. The user must ensure data is allocated for at least length bytes.
- length--The number of bytes to read.
- tmout--The number of milliseconds to wait for each character after the first.
Return Value
- The number of bytes read.
4.3.5 Single-User Cofunction Output Functions
These are Dynamic C cofunctions. If the output buffer they use is locked or becomes empty during the course of their operation, they yield to other tasks, but do not return to execute the next statement within their own costatement block until they have completed their operation.
scofunc void cof_serXputc (char c);
- Writes a single character to the serial port, yielding to other tasks when unsuccessful, and returning only when the character is successfully written.
Parameters
- c--Character to write to the serial port.
Return Value
- None
scofunc void cof_serXputs(char *s);
- Writes a null-terminated character string to the serial port, yielding to other tasks when unsuccessful or whenever the buffer is full, returning only when the string is successfully written.
Parameters
- s--Null-terminated character string written to the serial port.
Return Value
- None
scofunc void cof_serXwrite (void *data, int length);
- Writes a block of characters to the serial port, yielding to other tasks when unsuccessful or whenever the buffer is full, returning only when all the data is successfully written.
Parameters
- data--Source data structure to write to the serial port.
- length--Number of characters in data to write.
Return Value
- None
4.3.6 Circular Buffer Functions
These functions act on or report status of the circular transmit/receive buffers.
Macro definitions are used to establish the buffer sizes:
- xINBUFSIZE--read buffer size, where x is A, B, C, or D
- xOUTBUFSIZE--write buffer size where x is A, B, C, or D
The user must define each buffer size for each port being used to be a power of 2 minus 1 with a macro. The size of 2^n - 1 enables masking for fast rollover calculations. If no value or an illegal value is defined, a default size of 31 will be used and a compiler warning will be given. When using cofunctions, smaller buffer sizes can yield more frequently to other tasks, but have the risk of a large input data stream overrunning the buffer and losing data if the other task executes for too long relative to the baud rate.
int serXpeek ( );
- Returns the first character in the receive buffer, if any are available, without removing it from the buffer.
Parameters
- None
Return Value
- An integer with return character in the low byte. No character is represented by a return of -1.
void serXrdFlush ( );
- Flushes the serial port receive buffer.
Parameters
- None
Return Value
- None
void serXwrFlush ( );
- Flushes the serial port transmit buffer.
Parameters
- None
Return Value
- None
int serXrdFree ( );
- Calculates the free space in the serial port receive buffer.
Parameters
- None
Return Value
- The number of characters the serial port receive buffer can accept before becoming full.
int serXwrFree ( );
- Calculates the free space in the serial port transmit buffer.
Parameters
- None
Return Value
- The number of characters the serial port transmit buffer can accept before becoming full.
int serXrdUsed ( );
- Calculates the number of characters ready to read from the serial port receive buffer.
Parameters
- None
Return Value
- The number of characters currently in the serial port receive buffer.
4.4 RS-485 Serial Communication Drivers
The JR485.LIB library in the Dynamic C LIB/JRABLIB directory contains three RS-485 drivers for use with the Jackrabbit. These drivers are used with the drivers for Serial Port D in the RS232.LIB library because serDopen uses PC0 (TXD) and PC1 (RXD), which are connected to pin 4 and pin 1 of the SP483EN RS-485 chip at U6. This chip is half duplex, requiring pin 3 (Data Enable) to be high for pins 6 and 7 to act as outputs, and low for those pins to act as inputs.
Parallel Ports D and E on the Rabbit 2000 are double-buffered to provide precisely timed updating of the output pins. Each port is divided into an upper and a lower nibble. All bits of each nibble must be updated simultaneously. Each nibble may be updated constantly at a rate of perclk/2 or on a match of a selected timer (Timer A1, B1, or B2).
The bits used to select the update rate for each nibble are left random at power-up. If a mode other than perclk/2 is selected, the bits of a particular port will not update on a simple writing to the port's data register. In particular, PD5, the RS-485 transmitter control, will not set the RS-485 transmitter enable unless the upper nibble of Port D is configured properly.
The JR485Init function in Dynamic C release 6.16 has provision to disable the special clocking features associated with the high nibble of Port D. This effectively disables digital-to-analog (D/A) converter output channel DA1, the low-resolution D/A converter channel, which also uses PD4. Channel DA0 has its PWM output clocked separately with the low nibble, and so is not affected. Because the analog-to-digital converter uses D/A channel DA0, analog-to-digital conversion is not affected.
There are three RS-485 serial drivers.
Jr485Init()
- Sets up parallel port D pins for RS-485 use.
Jr485Tx()
- Sets pin 3 (DE) of the SP483EN chip high to disable Rx and enable Tx.
Jr485Rx()
- Resets pin 3 (DE) of the SP483EN chip low to disable Tx and enable Rx.
The following sample program illustrates the use of the RS-485 serial drivers. The sample program shows a byte being trasmitted, and then the RS-485 transceiver waits for a reply.
#define DINBUFSIZE 15
#define DOUTBUFSIZE 15
void main( void ){
int nEcho,nReply;
char cChar;
Jr485Init (); // Init RS485 Control (PD5)
serDopen ( 9600 ); // Open Serial Port D
for (;;) { // Forever
for (cChar='a';cChar<='z';++cChar){
// Send Alphabet
Jr485Tx (); // Enable RS485 Transmitter
serDputc ( cChar ); // Send Byte
while ((nEcho = serDgetc ()) == -1);
// Wait for Echo
Jr485Rx (); // Disable RS485 Transmitter
while ((nReply = serDgetc ()) == -1);
// Wait for Reply
printf ( "%02x -> %02x\n",nEcho,nReply );
}
}
}
| Z-World http://www.zworld.com Voice: (530) 757-3737 FAX: (530) 753-5141 sales@zworld.com |