drvTip810 - CAN Bus Driver

TEWS Tip810 Driver for EPICS
Version 2.6

Andrew Johnson <anj@aps.anl.gov>


1. Introduction

This document describes the software interface to the TEWS TIP810 Industry-Pack Module for vxWorks, written as part of an EPICS interface to the CANbus for the Gemini and UKIRT telescopes. This software is an IPAC Module Driver and uses the services of the drvIpac Industry Pack Driver to interface to the IPAC Carrier Board - see the accompanying document drvIpac - Industry Pack Driver for details of this driver software. The device support routines provided for use with EPICS are described in the document devCan - CAN Bus Device Support which briefly covers the use of the various record types supported.

The following routines provided by this driver are described in detail below:


2. Tip810 Driver Usage

The software provides an interface to higher level software which, other than device initialisation, is not specific to the TIP810 but could be used with a CANbus driver for a different hardware interface. The interface to the higher level software is provided in two header files: canBus.h contains all of the generic CANbus definitions and declarations, while drvTip810.h incorporates the additional declarations and definitions which are specific to the TIP810 module (and also #includes canBus.h and the vxWorks ANSI header file types.h). The routines which are specific to the TIP810 or meant for use from the vxWorks shell are described individually in this section, while the generic CANbus interface routines are described in section 3 below.

The TEWS TIP810 IP module contains a Philips pca82c200 stand-alone CAN-controller chip which performs all of the CANbus interfacing functions. The interface to this chip is defined in a separate header file pca82c200.h which declares the register interface structure and the bit-patterns for the various chip registers.

The driver uses an interrupt service routine with a different interrupt vector for each TIP810 module it controls, starting with vector 0x60 and increasing by one each time.

The driver can be built for use in a native vxWorks (i.e. non-EPICS) application. To do this, the drvTip810.c file should be compiled with the -DNO_EPICS switch to disable the EPICS-specific code.


t810Create

Registers a new TIP810 device with the driver. In EPICS, this is registered as an iocsh command.

int t810Create (char *pbusName, ushort_t card, ushort_t slot,
                ushort_t irqNum, uint_t busRate);

Parameters

char *pbusName
String which comprises a unique identifier for this particular CAN Bus. This must be a static string which should not be changed while the driver is loaded and running (vxWorks shell string literals have this property). While t810Create enforces no restrictions on the characters which may be used in the name, if the canIoParse routine is used the name should contain alphanumeric characters only.
ushort_t card, ushort_t slot
Ipac Driver carrier and slot numbers which identify the IPAC module, for use with drvIpac.
ushort_t irqNum
Interrupt vector number. Previous versions of the driver automatically allocated vectors numbers starring at 0x60, but these should really be set by the user, hence the addition of this parameter.
uint_t busRate
CAN bus rate in Kbits/sec. This parameter can have one of the values given in the following table. Other rates will require modifications to the driver source code. The Kvaser standard uses different bit timings which are not compatible with those used by Tews and so require special bit-rate entries.
busRate CANbus bit rate
5 5 Kbits/sec
10 10 Kbits/sec
20 20 Kbits/sec
50 50 Kbits/sec
100 100 Kbits/sec
125 125 Kbits/sec
250 250 Kbits/sec
500 500 Kbits/sec
1000 1000 Kbits/sec
1600 1600 Kbits/sec
-125 Kvaser 125 Kbits/sec
-250 Kvaser 250 Kbits/sec
-500 Kvaser 500 Kbits/sec
-1000 Kvaser 1000 Kbits/sec

Description

This routine will usually be called from the vxWorks (EPICS) start-up script. It is used to inform the driver about each TIP810 module which it is to control, providing information on how to find the module (the IPAC carrier and slot numbers) and what CANbus bit rate is to be used. Each module is given a name which is matched during calls to the canOpen routine to identify the particular module again.

The code checks that the given name and card/slot numbers are unique and point to a real Tews Tip810 module, then it creates a new device table and initialises it and some of the chip registers. At this stage the device is not activated but held in the reset state.

Returns

Symbol/Value Meaning
0 OK
S_t810_badBusRate Bus Rate not supported
S_t810_duplicateDevice another TIP810 already using given name and/or IPAC address
(drvIpac) errors returned by ipmValidate
(vxWorks) errno from malloc, semBCreate, or semMCreate

Example


t810Shutdown

Reboot hook routine, resets all devices to stop interrupts.

int t810Shutdown(int startType);

Parameters

int startType
This parameter is not used by the routine but is required to allow it to be used as a vxWorks reboot hook routine, when it differentiates between a cold and a warm restart.

Description

When t810Initialise is run, this routine will be connected up to the vxWorks reboot hook to reset the CAN controller chips on all known TIP810 modules when the system is rebooted. It can also be called by applications programs to turn off all the module drivers in the event of a catastrophic failure, but it may be necessary to reboot the system to re-enable them afterwards.

Returns

Symbol/Value Meaning
0 OK
S_t810_badDevice Bad or corrupted internal device table found


t810Initialise

Initialise driver and all registered hardware.

int t810Initialise(void);

Parameters

void
None.

Description

Under EPICS this routine is called during iocInit, which must occur after all canCreate calls in the start-up script. It creates a message queue to hold received messages and starts a task named canRecvTask to distribute them to the routines that have asked to be informed about them. Finally it completes the initialisation of the CAN controller chip and interrupt vector registers for all known TIP810 devices and starts them running.

Returns

Symbol/Value Meaning
0 OK
(vxWorks) errno from intConnect


t810Report

Display report giving status of all TEWS Tip810 devices. In EPICS, this is registered as an iocsh command.

int t810Report(int interest);

Parameters

int interest
Interest level, indicating how much detail is required and what information to show.

Description

Outputs (to stdout) a list of all the Tip810 devices created, their IP carrier & slot numbers and the bus name string. For interest=1 it adds message and error statistics; for interest=2 it lists all CAN IDs for which a call-back has been registered; for interest=3 the status of the CAN controller chip is given.

Returns

Symbol/Value Meaning
0 OK
S_t810_badDevice Bad or corrupted internal device table found

Examples


canTest

Test routine, sends a single test message to the named CANbus.

int canTest (char *pbusName, ushort_t identifier, ushort_t rtr,
             uchar_t length, char *data);

Parameters

char *pbusName
Device name to identify the particular T810 device to use.
ushort_t identifier
The CANbus message identifier to send.
ushort_t rtr
0 for a normal CAN message, non-zero to send a Remote Transmission Request packet.
uchar_t length
Number of bytes in the data field for this CANbus message type.
char *data
Pointer to the data to be sent. Ignored for RTR packets.

Description

This routine is provided as a diagnostic, to allow the system developer to generate CANbus messages and RTR packets from the vxWorks shell. It should not be used from within an application. It makes use of the canOpen and canWrite routines, and responds to errors reported by those routines by printing a message and returning -1.

Returns

Symbol/Value Meaning
0 OK
-1 ERROR

Example


3. Routines for CANbus Applications

canOpen

Return device pointer for given CAN bus name.

int canOpen(char *busName, void **pcanBusID);

Parameters

char *busName
Device name to identify the particular Tip810 device to use.
void **pcanBusID
Pointer to a void* location to hold the device identifier.

Description

Searches through the list of registered Tip810 devices for one which matches the name given, and returns a device identifier for it. This identifier is a required parameter for all of the remaining can driver routines. String searching in this manner is not particularly fast if several devices have been registered so this routine is intended to be used mainly when an application starts up. It may be used as often as desired however - there is no associated canClose routine.

Returns

Symbol/Value Meaning
0 OK
S_can_noDevice No matching device name found.

Example


canIoParse

Parse a CAN address string into a canIo_t structure

int canIoParse(char *canString, canIo_t *pcanIo);

Parameters

const char *canString
Address string to be converted.
canIo_t *pcanIo
Pointer to a structure which will be used to return the converted address information.

Description

canIoParse is used by the EPICS device support routines to convert record hardware addresses, but can be used by any application with similar requirements. It is intended to provide a standard way of converting the parameters which are needed to specify a portion of a particular CANbus message type from an ASCII string to their binary representation as a structure. The canIo_t structure is defined as a typedef in the canBus.h header as follows:

The address string passed to this routine consists of a series of elements, some of which are optional.

The first element is the bus name, which should consist of alphanumeric characters only. The name is terminated immediately before the first "/" or ":" character in the string, and after omitting any leading white-space the characters forming the bus name are copied to a newly allocated buffer, the address of which is placed in pcanIo->busName.

An oblique stroke ("/") after the bus name introduces an optional timeout element, which is an integer number of milli-seconds to wait for a response for this particular type of message. This is converted into vxWorks system clock ticks and placed in pcanIo->timeout. If no timeout element is included, the timeout is set to WAIT_FOREVER (-1).

The CANbus message identifier is preceded by a colon (":"), and must result in one of the legal CANbus identifiers in the range 0 through 2047 (with holes). The identifier itself can be specified as a single number, or in several parts separated by plus signs, which are all summed. The numbers here can be given in any of the standard 'C' formats as converted by strtol, so negative, hex or octal numbers may be used as desired.

If the identifier is followed by a decimal point ("."), the following element is an optional byte offset into the CANbus message. The offset is an unsigned short integer (using strtoul again for the conversion), although to remain within the limits of the message buffer it should be restricted to a maximum value of seven. The converted value is placed in pcanIo->offset, which defaults to zero if no offset is given.

The final element is a general-purpose parameter, introduced by a space or tab character. The value is first converted to a signed long using strtol which is placed in pcanIo->parameter. A pointer to any remaining characters is placed in pcanIo->paramStr.

If the string is successfully converted without errors, canIoParse will also call canOpen to initialise the pcanIo->canBusID bus identifier.

Returns

Symbol/Value Meaning
0 OK
S_can_badAddress illegal input string or NULL input parameters
S_can_noDevice No matching device name found
(vxWorks) errno from malloc

Example


canWrite

Writes a message to the given CANbus

int canWrite (void *canBusID, canMessage_t *pmessage, int timeout);

Parameters

void *canBusID
CANbus device identifier, obtained from canOpen
canMessage_t *pmessage
The message to be transmitted.
int timeout
Delay in vxWorks system clock ticks, indicating how long to wait for exclusive access to the TIP810 hardware.

Description

This routine is called to transmit a message on a particular CANbus. The canMessage_t type is defined as the following structure in canBus.h:

When called, canWrite obtains exclusive access to the TIP810 transmission buffer, converts the message into the correct form for the interface chip and copies it to the hardware registers. Finally it sends a Transmit Message command to the chip. The exclusive access semaphore will be released by the Interrupt Service Routine when it receives a notification from the chip that the message has been transmitted successfully.

Returns

Symbol/Value Meaning
0 OK
S_t810_badDevice canBusID not valid
S_can_badMessage invalid field in the message buffer
S_t810_transmitterBusy system fault somewhere
(vxWorks) errno from semTake

Example


canMessage

Register CAN message call-back

int canMessage(void *canBusID, ushort_t identifier,
               canMsgCallback_t *pcallback, void *pprivate);

Parameters

void *canBusID
CANbus device identifier, obtained from canOpen
ushort_t identifier
The CAN message identifier for which call-backs are required.
canMsgCallback_t *pcallback
The address of the routine to be called whenever matching messages are received.
void *pprivate
A parameter which is passed to the call-back routine to help it identify its context.

Description

This routine is used to add a call-back routine for a particular CAN message identifier on the given CANbus. Call-backs can be registered for any CAN message identifier, and there can be more than one call-back using the same ID - all routines are called in turn when a message with the relevant identifier is received. The call-back routine must not change the message at all, and should copy any information it needs from the message buffer before returning. The call-back used to be executed from vxWorks' Interrupt Context, thus there were restrictions in what vxWorks routines the call-back could use (see the vxWorks User Guide for details of these), however from release 2-1 a high priority task is used instead. Processing should still be kept to a minimum though as this task is run at a high priority. The call-back routine should be of type canMsgCallback_t:

void callback(void *pprivate, const canMessage_t *pmessage);

The same pprivate value supplied when the call-back was registered with canMessage is passed to the call-back routine with each message to allow it to identify its context.

Returns

Symbol/Value Meaning
0 OK
S_can_badMessage bad identifier or NULL call-back routine
S_can_badDevice bad device pointer
(vxWorks) errno from malloc

Example


canMsgDelete

Delete CAN message call-back

int canMsgDelete(void *canBusID, ushort_t identifier,
               canMsgCallback_t *pcallback, void *pprivate);

Parameters

void *canBusID
CANbus device identifier, obtained from canOpen
ushort_t identifier
The CAN message identifier for which call-backs were registered.
canMsgCallback_t *pcallback
The address of the routine being called whenever matching messages were received.
void *pprivate
The parameter passed to the call-back routine to help it identify its context.

Description

This routine is used to remove a call-back routine already registerd for a particular CAN message identifier on the given CANbus.

Exactly the same parameters given when the call-back was registered with canMessage must be passed to canMsgDelete for it to be successfully deleted.

Returns

Symbol/Value Meaning
0 OK
S_can_badMessage bad identifier or NULL call-back routine
S_can_noMessage no matching call-back routine
S_can_badDevice bad device pointer

Example

To delete the call-back registered in the previous canMessage example:


canSignal

Register CAN error signal call-back

int canSignal(void *canBusID, canSigCallback_t *pcallback,
              void *pprivate);

Parameters

void *canBusID
CANbus device identifier, obtained from canOpen
canSigCallback_t *pcallback
The address of the routine to be called whenever there is a change in the bus status.
void *pprivate
A parameter which is passed to the call-back routine to help it identify its context.

Description

This routine is used to add a new call-back routine for CANbus error reports from the given CANbus. There can be any number of error call-backs on each device, and all are called in turn when the controller chip reports a Bus Error or Bus Off event. The call-back routine is called from vxWorks' Interrupt Context (Note this has not changed in release 2-1), thus there are restrictions in which vxWorks routines can be used (see vxWorks User Guide for details of these), and processing should be kept to an absolute minimum. The call-back routine should be of type canSigCallback_t:

void callback(void *pprivate, ushort_t status);

The pprivate value supplied to canSignal is passed to the call-back routine with the error status to allow it to identify its context. Status values will be one of

these being pre-processor macros defined in the header file. If the chip goes to the Bus Off state, the driver will attempt to restart it, thus a Bus Ok signal should follow almost immediately.

Returns

Symbol/Value Meaning
0 OK
S_can_badDevice bad device identifier
(vxWorks) errno from malloc

Example


canBusReset

Reset CAN chip and message and error counters

int canBusReset(char *busName);

Parameters

char *busName
Device name to identify the particular Tip810 device to be reset.

Description

Resets the pca82c200 chip identified by the given busName, and clears all the counters associated with this device. This may clear some bus-related errors. All registered callbacks will remain active as before, although the chip may miss some incoming messages while resetting. This routine may also be used to restart an interface after a call to canBusStop.

Returns

Symbol/Value Meaning
0 OK
S_can_noDevice No matching device name found.

Example


canBusStop

Stop CAN interface

int canBusStop(char *busName);

Parameters

char *busName
Device name to identify the particular Tip810 device to be stopped.

Description

Holds the pca82c200 chip identified by the given busName in the reset state, which prevents it from sending or receiving messages, or from sending message acknowledgements to other nodes. The interface can be reactiviated using either canBusRestart or canBusReset.

Returns

Symbol/Value Meaning
0 OK
S_can_noDevice No matching device name found.

Example


canBusRestart

Restart a stopped CAN interface

int canBusReset(char *busName);

Parameters

char *busName
Device name identifying the Tip810 device to be restarted.

Description

Restarts the pca82c200 chip identified by the given busName after it has been stopped by a call to canBusStop. All registered callbacks will remain active as before and the message and error counters will continue to increment from their previous values.

Returns

Symbol/Value Meaning
0 OK
S_can_noDevice No matching device name found.

Example


canRead

Send Remote Transmission Request and wait for reply.

int canRead(void *canBusID, canMessage_t *pmessage, int timeout);

Parameters

void *canBusID
CANbus device identifier, obtained from canOpen
canMessage_t *pmessage
Message buffer to be used, with identifier and length fields set.
int timeout
Delay in vxWorks system clock ticks, indicating how long to wait for a response, including the delay in canWrite to obtain exclusive access to the transmit buffer. This value is not an absolute delay but is used internally for three separate sequential semaphore time-outs, thus there could be a total delay of over twice this period but the routine could still succeed.

Description

Sends a CANbus Remote Transmission Request and waits for a reply on the same message identifier, returning the message received in the given buffer. On entry the message buffer must be initialised with the CANbus message identifier and length of the expected reply in the relevant fields.

The canRead routine can be used along with canWrite to create simple CANbus interface applications without the need to use the message call-back system. This will work in situations where the vxWorks system is the only device on the CANbus which initiates message traffic and there are no long delays in responses to RTRs. More complex applications which need to receive unsolicited messages will need to use the canMessage call-back functions; these can be used at the same time as canRead. Although the routine is safe to use in multi-tasking situations, the action of sending an RTR and waiting for a returned message will only be performed for one task at a time on each bus.

Returns

Symbol/Value Meaning
0 OK
S_t810_badDevice bad bus ID
S_can_badMessage bad message Identifier or length
(vxWorks) errno from semTake

Example


Andrew Johnson <anj@aps.anl.gov>