eCos Reference Manual
Prev |  | Next

# Chapter 34. Writing a CAN hardware device driver

A CAN driver is nothing more than a named entity that supports the basic I/O functions - read, write, get config, and set config. The device driver uses and manages interrupts from the device. While the interface is generic and device driver independent, the actual driver implementation is completely up to the device driver designer.

That said, the reason for using a device driver is to provide access to a CAN device from application code in as general purpose a fashion as reasonable. Most driver writers are also concerned with making this access as simple as possible while being as efficient as possible.

Like other device drivers the CAN device driver is concerned with the movement of information - the CAN messages. In order to make the most efficient use of system resources, interrupts are used. This will allow other application processing to take place while the data transfers are under way, with interrupts used to indicate when various events have occurred. For example, a CAN device typically generates an interrupt after a CAN message has been sent or a CAN message has been received by a CAN hardware message buffer. It makes sense to allow further application processing while the data is being sent since this can take quite a long time. The interrupt can be used to allow the driver to send a CAN message as soon as the current one is complete, without any active participation by the application code.

The main building blocks for CAN device drivers are found in the include files `<cyg/io/devtab.h>` and `<cyg/io/can.h>`

Like many other device drivers in eCos, CAN device drivers are described by a device table entry, using the cyg_devtab_entry_t type. The entry should be created using the `DEVTAB_ENTRY()` macro.

# How to Write a CAN Hardware Interface Driver

The standard CAN driver supplied with eCos is structured as a hardware independent portion and a hardware dependent interface module. To add support for a new CAN device, the user should be able to use the existing hardware independent portion and just add their own interface driver which handles the details of the actual device. The user should have no need to change the hardware independent portion.

The interfaces used by the CAN driver and CAN implementation modules are contained in the file `<cyg/io/can.h>`.

## DevTab Entry

The interface module contains the devtab entry (or entries if a single module supports more than one interface). This entry should have the form:

    DEVTAB_ENTRY(<<module_name>>,
                 <<device_name>>,
                 0,
                 &can_devio,
                 <<module_init>>,
                 <<module_lookup>>,
                 &<<can_channel>>
                );

Arguments

`module_name`

  The "C" label for this devtab entry

`device_name`

  The "C" string for the device. E.g. `/dev/can0`.

`can_devio`

  The table of I/O functions. This set is defined in the hardware independent CAN driver and should be used.

`module_init`

  The hardware module initialization function.

`module_lookup`

  The device lookup function. This function typically sets up the CAN device for actual use, turning on interrupts, configuring the message buffers, etc.

`can_channel`

  This table (defined below) contains the interface between the interface module and the CAN driver proper.

Example devtab entry for Motorola FlexCAN device driver:

    DEVTAB_ENTRY(flexcan_devtab,
                 CYGDAT_DEVS_CAN_MCF52xx_FLEXCAN0_NAME,
                 0,                     // Does not depend on a lower level interface
                 &cyg_io_can_devio,
                 flexcan_init,
                 flexcan_lookup,        // CAN driver may need initializing
                 &flexcan_can0_chan
        );

## CAN Channel Structure

Each CAN device must have a “CAN channel”. This is a set of data which describes all operations on the device. It also contains buffers, etc. The CAN channel is created by the macro:

    CAN_CHANNEL_USING_INTERRUPTS(l, funs, dev_priv, baud,
                                 out_buf, out_buflen,
                                 in_buf,  in_buflen)

Arguments

`l`

  The "C" label for this structure.

`funs`

  The set of interface functions (see below).

`dev_priv`

  A placeholder for any device specific data for this channel.

`baud`

  The initial baud rate value (cyg_can_baud_rate_t).

`out_buf`

  Pointer to the output buffer

`out_buflen`

  The length of the output buffer.

`in_buf`

  pointer to the input buffer.

`in_buflen`

  The length of the input buffer.

Example CAN channel implementation for Motorola FlexCAN device driver:

    CAN_CHANNEL_USING_INTERRUPTS(
        flexcan_can0_chan,
        flexcan_lowlevel_funs,
        flexcan_can0_info,
        CYG_CAN_BAUD_RATE(CYGNUM_DEVS_CAN_MCF52xx_FLEXCAN0_KBAUD),
        flexcan_can0_txbuf, CYGNUM_DEVS_CAN_MCF52xx_FLEXCAN0_QUEUESIZE_TX,
        flexcan_can0_rxbuf, CYGNUM_DEVS_CAN_MCF52xx_FLEXCAN0_QUEUESIZE_RX
    );

The interface from the hardware independent driver into the hardware interface module is contained in the `funs` table. This is defined by the macro:

## CAN Lowlevel Functions Structure

    CAN_LOWLEVEL_FUNS(l, putmsg, getevent, get_config, set_config, start_xmit, stop_xmit)

Arguments

`l`

  The "C" label for this structure.

`putmsg`

  `bool (*putmsg)(can_channel *priv, cyg_can_message *pmsg, void *pdata)`

  This function sends one CAN message to the interface. It should return `true` if the message is actually consumed. It should return `false` if there is no space in the interface

`getevent`

  `bool (*getevent)(can_channel *priv, cyg_can_event *pevent, void *pdata)`

  This function fetches one event from the interface.

`get_config`

  `Cyg_ErrNo (*get_config)(can_channel *priv, cyg_uint32 key, const void *xbuf, cyg_uint32 *len)`

  This function is used to query the configuration of a CAN channel.

`set_config`

  `Cyg_ErrNo (*set_config)(can_channel *priv, cyg_uint32 key, const void *xbuf, cyg_uint32 *len)`

  This function is used to change configuration of a CAN channel.

`start_xmit`

  `void (*start_xmit)(can_channel *priv)`

  Enable the transmit channel and turn on transmit interrupts.

`stop_xmit`

  `void (*stop_xmit)(can_channel *priv)`

  Disable the transmit channel and turn transmit interrupts off.

Example implementation of low level function structure for Motorola FlexCAN device driver:

    CAN_LOWLEVEL_FUNS(flexcan_lowlevel_funs,
                      flexcan_putmsg,
                      flexcan_getevent,
                      flexcan_get_config,
                      flexcan_set_config,
                      flexcan_start_xmit,
                      flexcan_stop_xmit
         );

## Callbacks

The device interface module can execute functions in the hardware independent driver via `chan->callbacks`. These functions are available:

    void (*can_init)(can_channel *chan)

This function is used to initialize the CAN channel.

    void (*xmt_msg)(can_channel *chan, void *pdata)

This function would be called from an interrupt handler after a transmit interrupt indicating that additional messages may be sent. The upper driver will call the `putmsg` function as appropriate to send more data to the device.

    void (*rcv_event)(can_channel *chan, void *pdata)

This function is used to tell the driver that a message has arrived at the interface or that an event has occurred. This function is typically called from the interrupt handler.

Prev | Home | Next
Configuration | Up | ADC Support