The Rabbit family of microprocessors has hardware for a slave port, allowing a master controller to read and write certain internal registers on the Rabbit. The library, Slaveport.lib, implements a complete master/slave protocol for the Rabbit slave port. Sample libraries, Master_serial.lib and Sp_stream.lib provide serial port and stream-based communication handlers using the slave port protocol.
Given the variety of embedded system implementations, the protocol for the slave port driver was designed to make the software for the master controller as simple as possible. Each interaction between the master and the slave is initiated by the master. The master has complete control over when data transfers occur and can expect single, immediate responses from the slave.
Master writes to the command register after setting the address register and, optionally, the data register. These registers are internal to the slave.
Slave reads the registers that were written by the master.
Slave writes to command response register after optionally setting the data register. This also causes the SLAVEATTN line on the Rabbit slave to be pulled low.
Master reads response and data registers.
Master writes to the slave port status register to clear interrupt line from the slave.
From the point of view of the master, the slave is an I/O device with four register addresses.
|
Register |
Internal Address of Register |
Address of Register From Master’s Perspective |
Register Use |
|
SPD0R |
0x20 |
0 |
Command and response register |
|
SPD1R |
0x21 |
1 |
Address register |
|
SPD2R |
0x22 |
2 |
Optional data register |
|
SPSR |
0x23 |
3 |
Slave port status register. In this protocol the only bit used is for checking the command response register. Bit 3 is set if the slave has written to SPD0R. It is cleared when the master writes to SPSR, which also deasserts the SLAVEATTN line. |
Accessing the same address (0, 1 or 2) uses two different registers, depending on whether the access was a read or a write. In other words, when writing to address 0, the master accesses a different location than when the it reads address 0.
|
Register Address |
Read |
Write |
|
0 |
Gets command response from slave |
Sends command to slave, triggers slave response |
|
1 |
Not used |
Sets channel address to send command to |
|
2 |
Gets returned data from slave |
Sets data byte to send to slave |
|
3 |
Gets slave port status (see below) |
Clears slave response bit (see below) |
The status port is a bit field showing which slave port registers have been updated. For the purposes of this protocol. Only bit 3 needs to be examined. After sending a command, the master can check bit 3, which is set when the slave writes to the response register. At this point the response and returned data are valid and should be read before sending a new command. Performing a dummy write to the status register will clear this bit, so that it can be set by the next response.
Pin assignments for the Rabbit acting as a slave are as follows:
|
Rabbit 4000 Pins Rabbit 5000 Pins |
Function |
|
PA0-PA7 |
Slave port data bus, bidirectional |
|
PB6 |
/SCS Slave Chip Select (active low to read/write slave port) |
|
PE7 |
/SCS Alternate Slave Chip Select |
|
PB2 |
/SWR Slave Write (assert for write cycle) |
|
PB3 |
/SRD Slave Read (assert for read cycle) |
|
PB4 |
SA0 low address bit for slave port registers |
|
PB5 |
SA1 high address bit for slave registers |
|
PB7 |
/SLVATTN asserted by slave when it responds to a command; cleared by master write to status register |
For more details and read/write signal timing see the microprocessor user’s manual for your Rabbit chip.
Both the slave and the master can use interrupt or polling for the slave. The parameter passed to SPinit() determines which one is used. In interrupt mode, the developer can indicate whether the handler functions for the channels are interruptible or non-interruptible.
The Rabbit slave has 256 configurable channels available for communication. The developer must provide a handler function for each channel that is used. Some basic handlers are available in the library Slave_Port.lib. These handlers will be discussed later in this chapter.
When the slave port driver is initialized, a callback table of handler functions is set up. Handler functions are added to the callback table by SPsetHandler().
Slave_port.lib provides the following functions:.
int SPinit ( int mode );
Description
This function initializes the slave port driver. It sets up the callback tables for the different channels. The slave port driver can be run in either polling mode where SPtick() must be called periodically, or in interrupt mode where an ISR is triggered every time the master sends a command. There are two version of interrupt mode. In the first, interrupts are reenabled while the handler function is executing. In the other, the handler function will execute at the same interrupt priority as the driver ISR.
Parameters
mode
0: For polling
1: For interrupt driven (interruptible handler functions)
2: For interrupt driven (non-interruptible handler functions)
Return value
1: Success
0: Failure
Library
SLAVE_PORT.LIB
int SPsetHandler ( char address, int (*handler)(), void *handler_params );
Description
This function sets up a handler function to process incoming commands from the master for a particular slave port address.
Parameters
address
The 8-bit slave port address of the channel that corresponds to the handler function.
handler
Pointer to the handler function. This function must have a particular form, which is described by the function description for MyHandler() shown below. Setting this parameter to NULL unloads the current handler.
handler_params
Pointer that will be saved and passed to the handler function each time it is called. This allows the handler function to be parameterized for multiple cases.
Return value
1: Success, the handler was set.
0: Failure.
Library
SLAVE_PORT.LIB
int MyHandler ( char command, char data_in, void *params );
Description
This function is a developer-supplied function and can have any valid Dynamic C name. Its purpose is to handle incoming commands from a master to one of the 256 channels on the slave port. A handler function must be supplied for every channel that is being used on the slave port.
Parameters
command
This is the received command byte.
data_in
The optional data byte
params
The optional parameters pointer.
Return value
This function must return an integer. The low byte must contains the response code and the high byte contains the returned data, if there is any.
Library
This is a developer-supplied function.
void SPtick ( void );
Description
This function must be called periodically when the slave port is used in polling mode.
Library
SLAVE_PORT.LIB
void SPclose( void );
Description
This function disables the slave port driver and unloads the ISR if one was used.
Library
SLAVE_PORT.LIB
The rest of the chapter describes some useful handlers.
SPstatusHandler(), available in Slave_port.lib, is an example of a simple handler to report the status of the slave. To set up the function as a handler on slave port address 12, do the following:
SPsetHandler (12, SPstatusHandler, &status_char);
Sending any command to this handler will cause it to respond with a 1 in the response register and the current value of status_char in the data return register.
Slave_port.lib contains handlers for all serial ports A, B, C and D on the slave. Master_serial.lib contains code for a master using the slave’s serial port handler. This library illustrates the general case of implementing the master side of the master/slave protocol.
To set up the serial port handler to connect serial port A to channel 5 , do the following:
SPsetHandler (5, SPserAhandler, NULL);
The following functions are in Master_serial.lib. They are for a master using a serial port handler on a slave.
|
cof_MSgetc() |
MSopen() |
int cof_MSgetc( char address );
Description
Yields to other tasks until a byte is received from the serial port on the slave.
Parameters
address
Slave channel address of the serial handler.
Return value
Value of the received character on success.
-1: Failure.
Library
MASTER_SERIAL.LIB
void cof_MSputc( char address, char ch );
Description
Sends a character to the serial port. Yields until character is sent.
Parameters
address
Slave channel address of serial handler.
ch
Character to send.
Return value
0: Success, character was sent.
-1: Failure, character was not sent.
Library
MASTER_SERIAL.LIB
int cof_MSread( char address, char *buffer, int length, unsigned long timeout );
Description
Reads bytes from the serial port on the slave into the provided buffer. Waits until at least one character has been read. Returns after buffer is full, or timeout has expired between reading bytes. Yields to other tasks while waiting for data.
Parameters
address
Slave channel address of serial handler.
buffer
Buffer to store received bytes.
length
Size of buffer.
timeout
Time to wait between bytes before giving up on receiving anymore.
Return value
>0: Bytes read.
-1: Failure.
Library
MASTER_SERIAL.LIB
int cof_MSwrite( char address, char *data, int length );
Description
Transmits an array of bytes from the serial port on the slave. Yields to other tasks while waiting for write buffer to clear.
Parameters
address
Slave channel address of serial handler.
data
Array to be transmitted.
length
Size of array.
Return value
Number of bytes actually written or -1 if error.
Library
MASTER_SERIAL.LIB
int MSclose( char address );
Description
Closes a serial port on the slave.
Parameters
address
Slave channel address of serial handler.
Return value
0: Success.
-1: Failure.
Library
MASTER_SERIAL.LIB
int MSgetc( char address );
Description
Receives a character from the serial port.
Parameters
address
Slave channel address of serial handler.
Return value
Value of received character.
-1: No character available.
Library
MASTER_SERIAL.LIB
int MSgetError( char address );
Description
Gets bitfield with any current error from the specified serial port on the slave. Error codes are:
SER_PARITY_ERROR
SER_OVERRUN_ERROR
Parameters
address
Slave channel address of serial handler.
Return value
Number of bytes free: Success.
-1: Failure.
Library
MASTER_SERIAL.LIB
int MSinit( int io_bank );
Description
Sets up the connection to the slave.
Parameters
io_bank
The I/O bank and chip select pin number for the slave device. This is a number from 0 to 7 inclusive.
Return value
1: Success.
Library
MASTER_SERIAL.LIB
int MSopen( char address, unsigned long baud );
Description
Opens a serial port on the slave, given that there is a serial handler at the specified address on the slave.
Parameters
address
Slave channel address of serial handler.
baud
Baud rate for the serial port on the slave.
Return value
1: Baud rate used matches the argument.
0: Different baud rate is being used.
-1: Slave port comm error occurred.
Library
MASTER_SERIAL.LIB
int MSputc( char address, char ch );
Description
Transmits a single character through the serial port.
Parameters
address
Slave channel address of serial handler.
ch
Character to send.
Return value
1: Character sent.
0: Transmit buffer is full or locked.
Library
MASTER_SERIAL.LIB
int MSrdFree( char address );
Description
Gets the number of bytes available in the specified serial port read buffer on the slave.
Parameters
address
Slave channel address of serial handler.
Return value
Number of bytes free: Success.
-1: Failure.
Library
MASTER_SERIAL.LIB
int MSsendCommand( char address, char command, char data, char *data_returned, unsigned long timeout );
Description
Sends a single command to the slave and gets a response. This function also serves as a general example of how to implement the master side of the slave protocol.
Parameters
address
Slave channel address to send command to.
command
Command to be sent to the slave (see Section 8.3.2.1).
data
Data byte to be sent to the slave.
data_returned
Address of variable to place data returned by the slave.
timeout
Time to wait before giving up on slave response.
Return Value
³0: Response code.
-1: Timeout occured before response.
-2: Nothing at that address (response = 0xff).
Library
MASTER_SERIAL.LIB
int MSread( char address, char *buffer, int size, unsigned long timeout );
Description
Receives bytes from the serial port on the slave.
Parameters
address
Slave channel address of serial handler.
buffer
Array to put received data into.
size
Size of array (max bytes to be read).
timeout
Time to wait between characters before giving up on receiving any more.
Return value
The number of bytes read into the buffer (behaves like serXread()).
Library
MASTER_SERIAL.LIB
int MSwrFree( char address );
Description
Gets the number of bytes available in the specified serial port write buffer on the slave.
Parameters
address
Slave channel address of serial handler.
Return value
Number of bytes free: Success.
-1: Failure.
Library
MASTER_SERIAL.LIB
int MSwrite( char address, char *data, int length );
Description
Sends an array of bytes out the serial port on the slave (behaves like serXwrite()).
Parameters
address
Slave channel address of serial handler.
data
Array of bytes to send.
length
Size of array.
Return value
Number of bytes actually sent.
Library
MASTER_SERIAL.LIB
This sample program, /Samples/SlavePort/master_demo.c, treats the slave like a serial port.
#use "master_serial.lib"
#define SP_CHANNEL 0x42
char* const test_str = "Hello There";
main(){
char buffer[100];
int read_length;
MSinit(0);
// comment this line out if talking to a stream handler
printf("open returned:0x%x\n", MSopen(SP_CHANNEL, 9600));
while(1)
{
costate
{
wfd{cof_MSwrite(SP_CHANNEL, test_str, strlen(test_str));}
wfd{cof_MSwrite(SP_CHANNEL, test_str, strlen(test_str));}
}
costate
{
wfd{ read_length = cof_MSread(SP_CHANNEL, buffer, 99, 10); }
if(read_length > 0)
{
buffer[read_length] = 0; //null terminator
printf("Read:%s\n", buffer);
}
else if(read_length < 0)
{
printf("Got read error: %d\n", read_length);
}
printf("wrfree = %d\n", MSwrFree(SP_CHANNEL));
}
}
}
The library, SP_STREAM.LIB, implements a byte stream over the slave port. If the master is a Rabbit, the functions in MASTER_SERIAL.LIB can be used to access the stream as though it came from a serial port on the slave.
To set up the function SPShandler() as the byte stream handler, do the following:
SPsetHandler (10, SPShandler, stream_ptr);
This function sets up the stream to use channel 10 on the slave.
A sample program in Section 8.3.3.2 shows how to set up and initialize the circular buffers. An internal data structure, SPStream, keeps track of the buffers and a pointer to it is passed to SPsetHandler() and some of the auxiliary functions that supports the byte stream handler. This is also shown in the sample program.
Functions
These are the auxiliary functions that support the stream handler function, SPShandler().
void cbuf_init( char *circularBuffer, int dataSize );
Description
This function initializes a circular buffer.
Parameters
circularBuffer
The circular buffer to initialize.
dataSize
Size available to data. The size must be 9 bytes more than the number of bytes needed for data. This is for internal book-keeping.
Library
RS232.LIB
int cof_SPSread( SPStream *stream, void *data, int length, unsigned long tmout );
Description
Reads length bytes from the slave port input buffer or until tmout milliseconds transpires between bytes after the first byte is read. It will yield to other tasks while waiting for data. This function is non-reentrant.
Parameters
stream
Pointer to the stream state structure.
data
Structure to read from slave port buffer.
length
Number of bytes to read.
tmout
Maximum wait in milliseconds for any byte from previous one.
Return value
The number of bytes read from the buffer.
Library
SP_STREAM.LIB
int cof_SPSwrite( SPStream *stream, void *data, int length );
Description
Transmits length bytes to slave port output buffer.This function is non-reentrant.
Parameters
stream
Pointer to the stream state structure.
data
Structure to write to slave port buffer.
length
Number of bytes to write.
Return value
The number of bytes successfully written to slave port.
Library
SP_STREAM.LIB
void SPSinit( void );
Description
Initializes the circular buffers used by the stream handler.
Library
SP_STREAM.LIB
int SPSread( SPStream *stream, void *data, int length, unsigned long tmout );
Description
Reads length bytes from the slave port input buffer or until tmout milliseconds transpires between bytes. If no data is available when this function is called, it will return immediately. This function will call SPtick() if the slave port is in polling mode.
This function is non-reentrant.
Parameters
stream
Pointer to the stream state structure.
data
Buffer to read received data into.
length
Maximum number of bytes to read.
tmout
Time to wait between received bytes before returning.
Return value
Number of bytes read into the data buffer
Library
SP_STREAM.LIB
int SPSwrite( SPSream *stream, void *data, int length );
Description
This function transmits length bytes to slave port output buffer. If the slave port is in polling mode, this function will call SPtick() while waiting for the output buffer to empty. This function is non-reentrant.
Parameters
stream
Pointer to the stream state structure.
data
Bytes to write to stream.
length
Size of write buffer.
Return value
Number of bytes written into the data buffer.
Library
SP_STREAM.LIB
int SPSwrFree( void );
Description
Returns number of free bytes in the stream write buffer.
Return value
Space available in the stream write buffer.
Library
SP_STREAM.LIB
int SPSrdFree( void );
Description
Returns the number of free bytes in the stream read buffer.
Return value
Space available in the stream read buffer.
Library
SP_STREAM.LIB
int SPSwrUsed( void );
Description
Returns the number of bytes currently in the stream write buffer.
Return value
Number of bytes currently in the stream write buffer.
Library
SP_STREAM.LIB
int SPSrdUsed( void );
Description
Returns the number of bytes currently in the stream read buffer.
Return value
Number of bytes currently in the stream read buffer.
Library
SP_STREAM.LIB
This program, /Samples/SlavePort/Slave_Demo.c, runs on a slave and implements a byte stream over the slave port.
|
#class auto #use "slave_port.lib" #define STREAM_BUFFER_SIZE 31 main() SPStream stream; // Circular buffers need 9 bytes for bookkeeping. SPStream *stream_ptr; // setup buffers stream_ptr = &stream; SPinit(1); SPsetHandler(0x42, SPShandler, stream_ptr); while(1) |