<< Previous | Index | Next >>

7. The Slave Port Driver

The Rabbit 2000 and the Rabbit 3000 have 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.

7.1 Slave Port Driver 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.

7.1.1 Overview

  1. Master writes to the command register after setting the address register and, optionally, the data register. These registers are internal to the slave.

  2. Slave reads the registers that were written by the master.

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

  4. Master reads response and data registers.

  5. Master writes to the slave port status register to clear interrupt line from the slave.

7.1.2 Registers on the Slave

From the point of view of the master, the slave is an I/O device with four register addresses.

Table 7-7. The slave registers that are accessible by the master
Register
Name
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.

Table 7-8. What happens when the master accesses a slave register
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 both the Rabbit 2000 and the Rabbit 3000 acting as a slave are as follows:

Table 7-9. Pin assignments for the Rabbit acting as a slave
Pin
Function
PE7 /SCS chip select (active low to read/write slave port)
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
PA0-PA7 slave port data bus

For more details and read/write signal timing see the Rabbit 2000 Microprocessor User's Manual or the Rabbit 3000 Microprocessor User's Manual.

7.1.3 Polling and Interrupts

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.

7.1.4 Communication Channels

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

7.2 Functions

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

7.3 Examples

The rest of the chapter describes some useful handlers.

7.3.1 Status Handler

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.

7.3.2 Serial Port Handler

Slave_port.lib contains handlers for all four serial ports 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.

7.3.2.1 Commands to the Slave

Table 7-10. Commands that the master can send to the slave
Command
Command Description
1
Transmit byte. Byte value is in data register. Slave responds with 1 if the byte was processed or 0 if it was not.
2
Receive byte. Slave responds with 2 if has put a new received byte into the data return register or 0 if there were no bytes to receive.
3
Combined transmit/receive--a combination of the transmit and receive commands. The response will also be a logical OR of the two command responses.
4
Set baud factor, byte 1 (LSB). The actual baud rate is the baud factor multiplied by 300.
5
Set baud factor, byte 2 (MSB). The actual baud rate is the baud factor multiplied by 300.
6
Set port configuration bits
7
Open port
8
Close port
9
Get errors. Slave responds with 1 if the port is open and can return an error bitfield. The error bits are the same as for the function serAgetErrors() and are put in the data return register by the slave.
10, 11
Returns count of free bytes in the serial port write buffer. The two commands return the LSB and the MSB of the count respectively. The LSB(10) should be read first to latch the count.
12, 13
Returns count of free bytes in the serial port read buffer. The two commands return the LSB and the MSB of the count respectively. The LSB(12) should be read first to latch the count.
14, 15
Returns count of bytes currently in the serial port write buffer. The two commands return the LSB and the MSB of the count respectively. The LSB(14) should be read first to latch the count.
16, 17
Returns count of bytes currently in the serial port write buffer. The two commands return the LSB and the MSB of the count respectively. The LSB(16) should be read first to latch the count.

7.3.2.2 Slave Side of Protocol

To set up the serial port handler to connect serial port A to channel 5 , do the following:


SPsetHandler (5, SPserAhandler, NULL);

7.3.2.3 Master Side of Protocol

The following functions are in Master_serial.lib. They are for a master using a serial port handler on a slave.



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 0x01
SER_OVERRUN_ERROR 0x02

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

7.3.2.4 Sample Program for Master

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));
}
}
}

7.3.3 Byte Stream Handler

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.

7.3.3.1 Slave Side of Stream Channel

To set up the function SPShandler() as the byte stream handler, do the following:


SPsetHandler (10, SPShandler, stream_ptr);

This sets up the stream to use channel 10 on the slave.

A sample program in Section 7.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.

7.3.3.1.1 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();

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();

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();

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();

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

7.3.3.2 Byte Stream Sample Program

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"
#use "sp_stream.lib"
#define STREAM_BUFFER_SIZE 31 main()
{
char buffer[10];
int bytes_read;
SPStream stream; // Circular buffers need 9 bytes for bookkeeping.
char stream_inbuf[STREAM_BUFFER_SIZE + 9];
char stream_outbuf[STREAM_BUFFER_SIZE + 9];
SPStream *stream_ptr; // setup buffers
cbuf_init(stream_inbuf, STREAM_BUFFER_SIZE);
stream.inbuf = stream_inbuf;
cbuf_init(stream_outbuf, STREAM_BUFFER_SIZE);
stream.outbuf = stream_outbuf;
stream_ptr = &stream; SPinit(1); SPsetHandler(0x42, SPShandler, stream_ptr); while(1)
{
bytes_read = SPSread(stream_ptr, buffer, 10, 10);
if(bytes_read)
{
SPSwrite(stream_ptr, buffer, bytes_read);
}
}
}

<< Previous | Index | Next >>
Z-World, Inc.
www.zworld.com
Phone: 1.530.757.3737
Fax: 1.530.757.3792
Rabbit Semiconductor
www.rabbitsemiconductor.com
Phone: 1.530.757.8400
Fax: 1.530.757.8402