URL
https://opencores.org/ocsvn/openrisc/openrisc/trunk
Subversion Repositories openrisc
[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [io/] [can/] [current/] [doc/] [can.sgml] - Rev 825
Go to most recent revision | Compare with Previous | Blame | View Log
<!-- {{{ Banner -->
<!-- =============================================================== -->
<!-- -->
<!-- can.sgml -->
<!-- -->
<!-- Generic CAN documentation. -->
<!-- -->
<!-- =============================================================== -->
<!-- ####ECOSDOCCOPYRIGHTBEGIN#### -->
<!-- =============================================================== -->
<!-- Copyright (C) 2004 Free Software Foundation, Inc. -->
<!-- This material may be distributed only subject to the terms -->
<!-- and conditions set forth in the Open Publication License, v1.0 -->
<!-- or later (the latest version is presently available at -->
<!-- http://www.opencontent.org/openpub/) -->
<!-- Distribution of the work or derivative of the work in any -->
<!-- standard (paper) book form is prohibited unless prior -->
<!-- permission obtained from the copyright holder -->
<!-- =============================================================== -->
<!-- ####ECOSDOCCOPYRIGHTEND#### -->
<!-- =============================================================== -->
<!-- #####DESCRIPTIONBEGIN#### -->
<!-- -->
<!-- Author(s): Uwe Kindler -->
<!-- Date: 2006/12/04 -->
<!-- -->
<!-- ####DESCRIPTIONEND#### -->
<!-- =============================================================== -->
<!-- }}} -->
<PART id="io-can"><title>CAN Support</title>
<CHAPTER id="io-can-overview">
<TITLE>Overview</TITLE>
<SECTION id="io-can-overview-descr">
<TITLE>Description</TITLE>
<PARA>
The Controller Area Network, CAN, is a multicast shared, differential
serial bus standard especially suited for networking "intelligent"
devices as well as sensors and actuators within a system or sub-system.
The protocol was originally developed in the 1980s by Robert Bosch GmbH
aiming at automotive applications. Nowadays CAN has gained widespread use
and is used in industrial automation as well as in automotive, mobile
machines and in many embedded control applications.
</PARA>
<PARA>
The CAN protocol is defined by the ISO 11898-1 standard. The physical layer
uses differential transmission on a twisted pair wire. CAN uses a
non-destructive bit-wise arbitration to control access to the bus.
</PARA>
<PARA>
There is no explicit address in the messages because in CAN networks there
is no addressing of subscribers or stations, but instead, each message carries
a prioritized identifier. A transmitter sends a message to all CAN nodes
(broadcasting). The identifier may serve as an identification of the contents
of the message and also determines the priority that the message enjoys in
competition for bus access. A node decides on the basis of this identifier
received whether it should process the message or not.
</PARA>
<PARA>
The CAN messages are small (at most eight data bytes) and are protected
by a checksum. Each CAN message consists of an 11 bit message ID, up to 8
bytes of data and, a CRC checksum and a number of control bits. These
short messages ensure a robust transfer of data in electromagnetically
noisy environments. An extended version of the CAN frame supports 29 bit
message identifiers.
</PARA>
<PARA>
Basically there are two different operational modes for CAN receivers -
FullCAN and BasicCAN. The difference between these two modes is the
Object Storage function. The BasicCAN architecture is quite similar to a
simple UART. A BasicCAN device has typically one transmit buffer and two
receive buffers. The CAN chip handles only the transmitting and receiving
of the data (and the error handling) and so most of the manipulation of the
data has to be done by the CPU. The CPU has to request the transmitting or
acknowledge the receiving of the data through the interrupt flags. This will
burden the CPU and take up much of the CPU time.
</PARA>
<PARA>
The FullCAN architecture is more suitable for high-speed performance. It
has its own storage area on chip and works with a number of message buffers
or message boxes. The CAN controller has its own Acceptance Filtering Mask
on chip. It can thus determine which frames are to be received by examining
the identifiers. The CPU in this case will only receive the valid (wanted)
frames and hence improve the performance of the CPU.
</PARA>
<PARA>
You can find more information at the
<ulink url="http://www.can-cia.org/">CAN in Automation</ulink> website.
</PARA>
</SECTION> <!-- "io-can-description" -->
<SECTION id="io-can-ecos-support">
<TITLE>eCos Support for CAN</TITLE>
<PARA>
The eCos CAN subsystem supports the BasicCAN and FullCAN mode. The architecture
and the interface of the eCos CAN driver is quite similar to the eCos serial
driver and supports the same interface.
</PARA>
<PARA>
The eCos CAN support for any given platform is spread over a number of different
packages:
</PARA>
<itemizedlist>
<listitem>
<para>
This package, <varname>CYGPKG_IO_CAN</varname>, exports a generic
device independent CAN I/O API for accessing devices attached to a CAN
network. This API handles issues such as locking between threads. The
package does not contain any hardware-specific code. Instead it will
call into a CAN device driver to handle the hardware device
access. This package also defines the interface that such hardware
drivers should provide.
</para>
</listitem>
<listitem>
<para>
Each CAN device will have its own device driver, which is implemented
as a separate package, for example
<varname>CYGPKG_DEVS_CAN_MCF52xx_FLEXCAN</varname>. For devices that may
be attached to a variety of different boards the device driver will be
generic and a second platform specific package will be used to customize
it to each platform. For devices that are associated with a specific
chipset, only a single package may be present.
</para>
</listitem>
</itemizedlist>
<PARA>
Typically all appropriate packages will be loaded automatically when
you configure eCos for a given platform. If the application does not use
any of the CAN I/O facilities, directly or indirectly, then linker garbage
collection should eliminate all unnecessary code and data. All necessary
initialization should happen automatically. However the exact details may
depend on the platform, so the platform HAL documentation should be
checked for further details.
</PARA>
<PARA>
There is an important exception to this: if the CAN devices are attached
to an expansion connector, such as PCI, then the platform HAL will not
know about these devices. Instead the necessary packages will need to be
added explicitly during configuration.
</PARA>
</SECTION>
</CHAPTER>
<CHAPTER id="io-can-api">
<TITLE>User API</TITLE>
<PARA>
The CAN driver uses the standard eCos I/O API functions. All functions
except <function>cyg_io_lookup()</function> require an I/O "handle".
</PARA>
<PARA>
All functions return a value of the type <type>Cyg_ErrNo</type>.
If an error condition is detected, this value will be negative and the
absolute value indicates the actual error, as specified in
<filename>cyg/error/codes.h</filename>. The only other legal return values
will be <varname>ENOERR</varname>, <varname>-EINTR</varname>,
<varname>-EINVAL</varname> and <varname>-EAGAIN</varname>. All other
function arguments are pointers (references). This allows the drivers
to pass information efficiently, both into and out of the driver. The
most striking example of this is the <parameter>len</parameter> value
passed to the read and write functions. This parameter contains the
desired length of data on input to the function and the actual
transferred length on return.
</PARA>
<PROGRAMLISTING>
// Lookup a CAN device and return its handle
Cyg_ErrNo <FUNCTION><!-- <index></index> -->cyg_io_lookup</function>(
const char <parameter>*name</parameter>,
cyg_io_handle_t <parameter>*handle</parameter> )
</PROGRAMLISTING>
<PARA>
This function maps a CAN device name onto an appropriate handle. If the
named device is not in the system, then the error
<varname>-ENOENT</varname> is returned. If the device is found, then
the handle for the device is returned by way of the handle pointer
<parameter>*handle</parameter>.
</PARA>
<PROGRAMLISTING>
// Send a CAN message
Cyg_ErrNo <FUNCTION><!-- <index></index> -->cyg_io_write</function>(
cyg_io_handle_t <parameter>handle</parameter>,
const void <parameter>*buf</parameter>,
cyg_uint32 <parameter>*len</parameter> )
</PROGRAMLISTING>
<PARA>
This function sends one single CAN message (not a buffer of CAN messages)
to a device. The size of data to send is contained in
<parameter>*len</parameter> and the actual size sent will be returned in
the same place.
</PARA>
<PROGRAMLISTING>
// Read one CAN event from device
Cyg_ErrNo <!-- <index></index> --><function>cyg_io_read</function>(
cyg_io_handle_t <parameter>handle</parameter>,
void <parameter>*buf</parameter>,
cyg_uint32 <parameter>*len</parameter> )
</PROGRAMLISTING>
<PARA>
This function receives one single CAN event from a device. The desired size
of data to receive is contained in <parameter>*len</parameter> and the
actual size obtained will be returned in the same place.
</PARA>
<PARA>
You may notice that the data sent (messages) is different from the
data received (events). An event includes flags that describe the
event, and eventually a received message and a timestamp.
</PARA>
<PROGRAMLISTING>
// Read configuration of a CAN device
Cyg_ErrNo <FUNCTION><!-- <index></index> -->cyg_io_get_config</FUNCTION>(
cyg_io_handle_t <parameter>handle</parameter>,
cyg_uint32 <parameter>key</parameter>,
void *<parameter>buf</parameter>,
cyg_uint32 *<parameter>len</parameter> )
</PROGRAMLISTING>
<PARA>
This function is used to obtain run-time configuration about a
device. The type of information retrieved is specified by the
<parameter>key</parameter>. The data will be returned in the given
buffer. The value of <parameter>*len</parameter> should contain the
amount of data requested, which must be at least as large as the size
appropriate to the selected key. The actual size of data retrieved is
placed in <parameter>*len</parameter>. The appropriate key values
are all listed in the file <filename><cyg/io/config_keys.h></filename>.
</PARA>
<PROGRAMLISTING>
// Change configuration of a CAN device
Cyg_ErrNo <!-- <index></index> --><function>cyg_io_set_config</function>(
cyg_io_handle_t <parameter>handle</parameter>,
cyg_uint32 <parameter>key</parameter>,
const void <parameter>*buf</parameter>,
cyg_uint32 <parameter>*len</parameter> )
</PROGRAMLISTING>
<PARA>
This function is used to manipulate or change the run-time
configuration of a device. The type of information is specified by the
<parameter>key</parameter>. The data will be obtained from the given
buffer. The value of <parameter>*len</parameter> should contain the
amount of data provided, which must match the size appropriate to the
selected key. The appropriate key values are all listed in the file
<filename><cyg/io/config_keys.h></filename>.
</PARA>
</CHAPTER>
<CHAPTER id="io-can-driver-details">
<TITLE>CAN driver details</TITLE>
<PARA>
Allow applications and other packages to access CAN devices.
</PARA>
<SECTION id="io-can-driver-description">
<TITLE>Description</TITLE>
<PARA>
A raw CAN driver is is provided as a standard part of the eCos system.
</PARA>
<PARA>
Use the include file <filename><cyg/io/canio.h></filename> for this driver.
</PARA>
<PARA>
The CAN driver is capable of sending single CAN messages to a device and
receiving single CAN events from a CAN device. Controls are provided to
configure the actual hardware, but there is no manipulation of the data by
this driver.
</PARA>
<PARA>
There may be many instances of this driver in a given system, one for each
CAN channel. Each channel corresponds to a physical device and there will
typically be a device module created for this purpose. The device modules
themselves are configurable, allowing specification of the actual hardware
details.
</PARA>
</SECTION>
<SECTION id="io-can-api-details">
<TITLE>API Details</TITLE>
<SECTION>
<TITLE>cyg_io_write</TITLE>
<PROGRAMLISTING>
cyg_io_write(handle, buf, len)
</PROGRAMLISTING>
<PARA>
To transmit a message an application must fill a <type>cyg_can_message</type>
buffer and call <function>cyg_io_write()</function>.
This function sends one single CAN message (not a buffer of CAN messages)
to a device. The size of data to send is contained in <parameter>*len</parameter>
and the actual size sent will be returned in the same place. A pointer to a
<type>cyg_can_message</type> is contained in <parameter>*buf</parameter>.
The driver maintains a buffer to hold the data. The size of the intermediate
buffer is configurable within the interface module. The data is not modified
at all while it is being buffered. On return, <parameter>*len</parameter>
contains the amount of characters actually consumed - that means
<parameter>*len</parameter> always contains
<function>sizeof(cyg_can_message)</function>.
</PARA>
<PARA>
It is possible to configure the write call to be blocking (default) or
non-blocking. Non-blocking mode requires both the configuration option
<varname>CYGOPT_IO_CAN_SUPPORT_NONBLOCKING</varname> to be enabled, and
the specific device to be set to non-blocking mode for writes
(see <function>cyg_io_set_config()</function>). In blocking mode, the
call will not return until there is space in the buffer and the content
of the CAN message has been consumed. In non-blocking mode, if there is
no space in buffer for the CAN message, <varname>-EAGAIN</varname> is
returned and the caller must try again.
</PARA>
<PARA>
It is possible to configure the write call to be non-blocking with timeout.
None-blocking mode with timeout requires the configuration option
<varname>CYGOPT_IO_CAN_SUPPORT_NONBLOCKING</varname> and
<varname>CYGOPT_IO_CAN_SUPPORT_TIMEOUTS</varname> to be enabled, requires
the eCos kernel package to be included and the specific device to be set
to non-blocking mode for writes (see <function>cyg_io_set_config()
</function>).
In non-blocking mode with timeouts, if there is no space in buffer for the
CAN message, the driver waits a certain amount of time (the timeout time)
for space in the buffer. If there is still no space in buffer after
expiration of the timeout time, <varname>-EINTR</varname> is returned and
the caller must try again.
</PARA>
<PARA>
If a message was successfully sent, the function returns <varname>ENOERR</varname>.
</PARA>
</SECTION>
<SECTION>
<TITLE>CAN Messages</TITLE>
<PARA>
The CAN driver uses <structname>cyg_can_message</structname> structures to
pass messages between the application and the CAN driver. The type
cyg_can_message provides a device independent type of CAN message.
Before calling the write function this message should be setup properly.
</PARA>
<PROGRAMLISTING>
typedef struct can_message
{
cyg_uint32 id;
cyg_uint8 data[8];
cyg_can_id_type ext;
cyg_can_frame_type rtr;
cyg_uint8 dlc;
} cyg_can_message;
</PROGRAMLISTING>
<PARA>
The structure contains the following fields:
</PARA>
<variablelist>
<varlistentry>
<term><type>cyg_uint32</type> <varname>id</varname></term>
<listitem><para>
Message ID. This is the ID to be transmitted with the message, or the
ID received. If the <structfield>ext</structfield> field is set, then
this will contain a 29 bit ID, otherwise it will contain an 11 bit ID.
</para></listitem>
</varlistentry>
<varlistentry>
<term><type>cyg_uint32</type> <varname>data</varname></term>
<listitem><para>
Message data. Only the first <structfield>dlc</structfield> bytes of
data are valid. If the <structfield>rtr</structfield> field is set,
then the contents of this field are ignored.
</para></listitem>
</varlistentry>
<varlistentry>
<term><type>cyg_can_id_type</type> <varname>ext</varname></term>
<listitem><para>
Extended ID. If this field is <varname>CYGNUM_CAN_ID_EXT</varname> then the
<structname>id</structname> field contains a 29 bit extended ID. If it
contains <varname>CYGNUM_CAN_ID_STD</varname> then the ID is 11 bits.
</para></listitem>
</varlistentry>
<varlistentry>
<term><type>cyg_can_frame_type</type> <varname>rtr</varname></term>
<listitem><para>
Remote Transmission Request. If this field contains
<varname>CYGNUM_CAN_FRAME_RTR</varname> then the RTR bit on the message
will be set and the <structfield>data</structfield> field will be ignored.
If the field contains <varname>CYGNUM_CAN_FRAME_DATA</varname> then a
normal data frame will be send.
</para></listitem>
</varlistentry>
<varlistentry>
<term><type>cyg_uint8</type> <varname>dlc</varname></term>
<listitem><para>
The length of the data carried in the message. This can range from
zero to 8. In a message with the <structfield>rtr</structfield> field set,
this indicates the size of data being requested.
</para></listitem>
</varlistentry>
</variablelist>
<PARA>
Example code for sending one single CAN message:
</PARA>
<PROGRAMLISTING>
cyg_can_message tx_msg;
cyg_uint32 len;
Cyg_ErrNo ret;
tx_msg.id = 0x100;
tx_msg.ext = CYGNUM_CAN_ID_EXT;
tx_msg.rtr = CYGNUM_CAN_FRAME_DATA;
tx_msg.dlc = 1;
tx_msg.data[0] = 0xF1;
len = sizeof(tx_msg);
ret = cyg_io_write(hDrvCAN, &tx_msg, &len);
</PROGRAMLISTING>
</SECTION><!-- can-cyg_can_message -->
<SECTION>
<TITLE>cyg_io_read</TITLE>
<PROGRAMLISTING>
cyg_io_read(handle, buf, len)
</PROGRAMLISTING>
<PARA>
To receive a message the application calls <function>cyg_io_read()</function>.
This function receives one single event from a device. The desired size
of data to receive is contained in <parameter>*len</parameter> and the
actual size obtained will be returned in the same place. A pointer to
a <type>cyg_can_event</type> is contained in <parameter>*buf</parameter>.
No manipulation of the data is performed before being transferred.
Again, this buffering is completely configurable. On return,
<parameter>*len</parameter> contains <function>sizeof(cyg_can_event)</function>.
</PARA>
<PARA>
It is possible to configure the read call to be blocking (default) or
non-blocking. Non-blocking mode requires both the configuration option
<varname>CYGOPT_IO_CAN_SUPPORT_NONBLOCKING</varname> to be enabled,
and the specific device to be set to non-blocking mode for reads
(see <function>cyg_io_set_config()</function>). In blocking mode,
the call will not return until one single CAN event has been read.
In non-blocking mode, if there is no CAN event in buffer, the call
returns immediately with <varname>-EAGAIN</varname> and the caller must
try again.
</PARA>
<PARA>
It is possible to configure the read call to be non-blocking with timeout.
None-blocking mode with timeout requires the configuration option
<varname>CYGOPT_IO_CAN_SUPPORT_NONBLOCKING</varname> and
<varname>CYGOPT_IO_CAN_SUPPORT_TIMEOUTS</varname> to be enabled,
requires the eCos kernel package to be included and the specific device
to be set to non-blocking mode for reads (see
<function>cyg_io_set_config()</function>). In non-blocking mode with timeouts,
if there is no CAN event in receive buffer, the driver waits a certain amount
of time (the timeout time) for a CAN event to arrive. If there is still no
CAN event in buffer after expiration of the timeout time, <varname>-EINTR</varname>
is returned and the caller must try again.
</PARA>
<PARA>
If an event was successfully received, the function returns <varname>ENOERR</varname>.
</PARA>
</SECTION><!-- cyg_io_read -->
<SECTION>
<TITLE>CAN Events</TITLE>
<PARA>
The CAN driver uses <structname>cyg_can_event</structname> structures to
pass events from hardware device driver to the generic CAN driver.
A <structname>cyg_can_event</structname> provides a generic device
independent type for handling CAN events that may occur.
</PARA>
<PROGRAMLISTING>
typedef struct cyg_can_event_st
{
cyg_uint32 timestamp;
cyg_can_event_flags_t flags;
cyg_can_message msg;
} cyg_can_event;
</PROGRAMLISTING>
<PARA>
The structure contains the following fields:
</PARA>
<variablelist>
<varlistentry>
<term><type>cyg_uint32</type> <varname>timestamp</varname></term>
<listitem><para>
If the hardware CAN device driver supports timestamps then this field may
contain a timestamp value for an event that occured.
</para></listitem>
</varlistentry>
<varlistentry>
<term><type>cyg_can_event_flags_t</type> <varname>flags</varname></term>
<listitem><para>
Event flags. The <varname>flags</varname> field contains bits that
indicate which kind of events occured. More than one flag can be raised
in a single event.
</para></listitem>
</varlistentry>
<varlistentry>
<term><type>cyg_can_message</type> <varname>msg</varname></term>
<listitem><para>
CAN message. The msg field contains a CAN message if an RX or TX event
occured. If another type of event occured,
the <structfield>data</structfield> field of
the <structfield>msg</structfield> may contain additional event
specific data.
</para></listitem>
</varlistentry>
</variablelist>
<PARA>
The following events are supported and after receiving an event the
application should check the <varname>flags</varname> field against these values:
</PARA>
<PROGRAMLISTING>
CYGNUM_CAN_EVENT_RX 0x00000001 // message received
CYGNUM_CAN_EVENT_TX 0x00000002 // mesage transmitted
CYGNUM_CAN_EVENT_WARNING_RX 0x00000004 // tx error counter (TEC) reached warning level (>96)
CYGNUM_CAN_EVENT_WARNING_TX 0x00000008 // rx error counter (REC) reached warning level (>96)
CYGNUM_CAN_EVENT_ERR_PASSIVE 0x00000010 // CAN "error passive" occured
CYGNUM_CAN_EVENT_BUS_OFF 0x00000020 // CAN "bus off" error occured
CYGNUM_CAN_EVENT_OVERRUN_RX 0x00000040 // overrun in RX queue occured
CYGNUM_CAN_EVENT_OVERRUN_TX 0x00000080 // overrun in TX queue occured
CYGNUM_CAN_EVENT_CAN_ERR 0x00000100 // a CAN bit or frame error occured
CYGNUM_CAN_EVENT_LEAVING_STANDBY 0x00000200 // CAN hardware leaves standby / power down mode or is waked up
CYGNUM_CAN_EVENT_ENTERING_STANDBY 0x00000400 // CAN hardware enters standby / power down mode
CYGNUM_CAN_EVENT_ARBITRATION_LOST 0x00000800 // arbitration lost
CYGNUM_CAN_EVENT_FILTER_ERR 0x00001000 // CAN message filter / acceptance filter error
CYGNUM_CAN_EVENT_PHY_FAULT 0x00002000 // General failure of physical layer detected
CYGNUM_CAN_EVENT_PHY_H 0x00004000 // Fault on CAN-H detected (Low Speed CAN)
CYGNUM_CAN_EVENT_PHY_L 0x00008000 // Fault on CAN-L detected (Low Speed CAN)
CYGNUM_CAN_EVENT_ERR_ACTIVE 0x00010000 // CAN controller now "error active"
CYGNUM_CAN_EVENT_OVERRUN_RX_HW 0x00020000 // CAN controller reports a RX overrun
</PROGRAMLISTING>
<PARA>
Often the flags field will contain only one single set flag. But it is
possible that a number of flags is set and so the flag field should
always be checked by a receiver. Most of the flags are independent
from each other and the receiver has to handle each of them separately.
</PARA>
<PARA>
The internal receive buffers of the CAN device driver are circular
buffers. That means that even if the buffers are completely filled
new messages will be received. In this case the newest message will
always overwrite the oldest message in the receive buffer. If this
happens the
<varname>CYGNUM_CAN_EVENT_OVERRUN_RX</varname> flag will be set for
this new message that caused overwriting of the old one. However if an
overrun occurs in the hardware message buffers of the CAN controller,
the flag <varname>CYGNUM_CAN_EVENT_OVERRUN_RX_HW</varname> is raised
instead.
</PARA>
<PARA>
Example code for receiving one single CAN event:
</PARA>
<PROGRAMLISTING>
cyg_can_event rx_event;
cyg_uint32 len;
Cyg_ErrNo ret;
len = sizeof(rx_event);
ret = cyg_io_read(hDrvCAN, &rx_event, &len);
if (ENOERR == ret)
{
if (rx_event.flags & CYGNUM_CAN_EVENT_RX)
{
// handle RX event
}
if (rx_event.flags & ~CYGNUM_CAN_EVENT_RX)
{
// handle other events
}
}
else if (-EINTR == ret)
{
// handle timeout
}
</PROGRAMLISTING>
</SECTION><!-- can-cyg_can_event -->
<SECTION>
<TITLE>cyg_io_get_config</TITLE>
<PROGRAMLISTING>
cyg_io_get_config(handle, key, buf, len)
</PROGRAMLISTING>
<PARA>
This function is used to obtain run-time configuration about a device.
The type of information retrieved is specified by the <parameter>key</parameter>.
The data will be returned in the given buffer. The value of
<parameter>*len</parameter> should contain the amount of data requested,
which must be at least as large as the size appropriate to the selected
<parameter>key</parameter>. The actual size of data retrieved is placed
in <parameter>*len</parameter>. The appropriate key values are all listed
in the file <filename><cyg/io/config_keys.h></filename>.
</PARA>
<PARA>
The following config keys are currently supported:
</PARA>
<PROGRAMLISTING>
CYG_IO_GET_CONFIG_READ_BLOCKING
CYG_IO_GET_CONFIG_WRITE_BLOCKING
CYG_IO_GET_CONFIG_CAN_INFO
CYG_IO_GET_CONFIG_CAN_BUFFER_INFO
CYG_IO_GET_CONFIG_CAN_MSGBUF_INFO
CYG_IO_GET_CONFIG_CAN_TIMEOUT
CYG_IO_GET_CONFIG_CAN_HDI
CYG_IO_GET_CONFIG_CAN_STATE
</PROGRAMLISTING>
</SECTION><!-- can-cyg-io-get-config -->
<SECTION>
<TITLE>cyg_io_set_config</TITLE>
<PROGRAMLISTING>
cyg_io_set_config(handle, key, buf, len)
</PROGRAMLISTING>
<PARA>
This function is used to manipulate or change the run-time configuration
of a device. The type of information is specified by the <parameter>key</parameter>.
The data will be obtained from the given buffer. The value of
<parameter>*len</parameter> should contain the amount of data provided,
which must match the size appropriate to the selected <parameter>key</parameter>.
The appropriate key values are all listed in the file
<filename><cyg/io/config_keys.h></filename>.
</PARA>
<PARA>
The following config keys are currently supported:
</PARA>
<PROGRAMLISTING>
CYG_IO_SET_CONFIG_READ_BLOCKING
CYG_IO_SET_CONFIG_WRITE_BLOCKING
CYG_IO_SET_CONFIG_CAN_INFO
CYG_IO_SET_CONFIG_CAN_OUTPUT_DRAIN
CYG_IO_SET_CONFIG_CAN_OUTPUT_FLUSH
CYG_IO_SET_CONFIG_CAN_INPUT_FLUSH
CYG_IO_SET_CONFIG_CAN_TIMEOUT
CYG_IO_SET_CONFIG_CAN_MSGBUF
CYG_IO_SET_CONFIG_CAN_MODE
CYG_IO_SET_CONFIG_CAN_ABORT
CYG_IO_SET_CONFIG_CAN_CALLBACK
CYG_IO_SET_CONFIG_CAN_RANGE_FILTER
CYG_IO_SET_CONFIG_CAN_MASK_FILTER
</PROGRAMLISTING>
</SECTION><!-- can-cyg-io-set-config -->
</SECTION><!-- io-can-api-details -->
<SECTION id="io-can-runtime-cfg">
<TITLE>Runtime Configuration</TITLE>
<PARA>
Runtime configuration is achieved by exchanging data structures with the
driver via the <function>cyg_io_set_config()</function> and
<function>cyg_io_get_config()</function> functions.
</PARA>
<SECTION>
<TITLE>Device configuration</TITLE>
<PROGRAMLISTING>
typedef struct cyg_can_info_st {
cyg_can_baud_rate_t baud;
} cyg_can_info_t;
</PROGRAMLISTING>
<PARA>
Device configuration is achieved by by exchanging
<structname>cyg_can_info_t</structname> data structures with the driver
via the <function>cyg_io_set_config()</function> and
<function>cyg_io_get_config()</function> functions using the config keys
<varname>CYG_IO_GET_CONFIG_CAN_INFO</varname> and
<varname>CYG_IO_SET_CONFIG_CAN_INFO</varname>.
The field <structfield>baud</structfield> contains a baud rate selection.
This must be one of the following values:
</PARA>
<PROGRAMLISTING>
CYGNUM_CAN_KBAUD_10
CYGNUM_CAN_KBAUD_20
CYGNUM_CAN_KBAUD_50
CYGNUM_CAN_KBAUD_100
CYGNUM_CAN_KBAUD_125
CYGNUM_CAN_KBAUD_250
CYGNUM_CAN_KBAUD_500
CYGNUM_CAN_KBAUD_800
CYGNUM_CAN_KBAUD_1000
</PROGRAMLISTING>
</SECTION><!-- can-cyg-io-set-config -->
<SECTION>
<TITLE>Timeout configuration</TITLE>
<PROGRAMLISTING>
typedef struct cyg_can_timeout_info_st
{
cyg_uint32 rx_timeout;
cyg_uint32 tx_timeout;
} cyg_can_timeout_info_t;
</PROGRAMLISTING>
<PARA>
Timeout configuration is achieved by by exchanging
<structname>cyg_can_timeout_info_t</structname> data structures with the
driver via the <function>cyg_io_set_config()</function> and
<function>cyg_io_get_config()</function> functions using the config keys
<varname>CYG_IO_SET_CONFIG_CAN_TIMEOUT</varname> and
<varname>CYG_IO_SET_CONFIG_CAN_TIMEOUT</varname>.
</PARA>
<variablelist>
<varlistentry>
<term><type>cyg_uint32</type> <varname>rx_timeout</varname></term>
<listitem><para>
Timeout for <function>cyg_io_read</function> calls.
</para></listitem>
</varlistentry>
<varlistentry>
<term><type>cyg_uint32</type> <varname>tx_timeout</varname></term>
<listitem><para>
Timeout for <function>cyg_io_write</function> calls.
</para></listitem>
</varlistentry>
</variablelist>
<PARA>
Timeout runtime configuration is supported if the configuration options
<varname>CYGOPT_IO_CAN_SUPPORT_NONBLOCKING</varname>
and <varname>CYGOPT_IO_CAN_SUPPORT_TIMEOUTS</varname> are enabled.
</PARA>
</SECTION><!-- can-timeout-config -->
<SECTION>
<TITLE>Reading buffer configuration</TITLE>
<PROGRAMLISTING>
typedef struct cyg_can_buf_info_st
{
cyg_int32 rx_bufsize;
cyg_int32 rx_count;
cyg_int32 tx_bufsize;
cyg_int32 tx_count;
} cyg_can_buf_info_t;
</PROGRAMLISTING>
<PARA>
<varname>CYG_IO_GET_CONFIG_CAN_BUFFER_INFO</varname> - This function
retrieves the current state of the software buffers in the CAN drivers.
For the transmit buffer it returns the the total number of
<type>cyg_can_message</type> objects in buffer and the current number of
<type>cyg_can_message</type> objects occupied in the buffer.
For the receive buffer it returns the total number of
<type>cyg_can_event</type> objects in receive buffer and the current
number of <type>cyg_can_event</type> objects occupied in the buffer.
It does not take into account any buffering such as FIFOs or holding
registers that the CAN hardware device itself may have.
</PARA>
<variablelist>
<varlistentry>
<term><type>cyg_uint32</type> <varname>rx_bufsize</varname></term>
<listitem><para>
Total number of <type>cyg_can_event</type> buffers in receive queue.
</para></listitem>
</varlistentry>
<varlistentry>
<term><type>cyg_uint32</type> <varname>rx_count</varname></term>
<listitem><para>
Current number of <type>cyg_can_event</type> buffers occupied in receive queue.
</para></listitem>
</varlistentry>
<varlistentry>
<term><type>cyg_uint32</type> <varname>tx_bufsize</varname></term>
<listitem><para>
Total number of <type>cyg_can_message</type> buffers in transmit queue.
</para></listitem>
</varlistentry>
<varlistentry>
<term><type>cyg_uint32</type> <varname>rtx_count</varname></term>
<listitem><para>
Current number of <type>cyg_can_message</type> buffers occupied in transmit queue.
</para></listitem>
</varlistentry>
</variablelist>
</SECTION> <!-- can-read-buffer-config -->
<SECTION>
<TITLE>Reading hardware description information</TITLE>
<PROGRAMLISTING>
typedef struct cyg_can_hdi_st
{
cyg_uint8 support_flags;
cyg_uint8 controller_type;
} cyg_can_hdi;
</PROGRAMLISTING>
<PARA>
<varname>CYG_IO_GET_CONFIG_CAN_HDI</varname> - This function retrieves
information about the used hardware. The Hardware Description Interface
provides a method to gather information about the CAN hardware and the
functionality of the driver. For this purpose the structure
<structname>cyg_can_hdi</structname> is defined.
</PARA>
<variablelist>
<varlistentry>
<term><type>cyg_uint8</type> <varname>support_flags</varname></term>
<listitem><para>
Contains information about the capabilities of the used CAN hardware.
</para></listitem>
</varlistentry>
<varlistentry>
<term><type>cyg_uint8</type> <varname>controller_type</varname></term>
<listitem><para>
A number that identifies the CAN controller type.
</para></listitem>
</varlistentry>
</variablelist>
<PARA>
The following flags are available in the field <structfield>support_flags</structfield>:
</PARA>
<PROGRAMLISTING>
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+-------+-------+-------+-------+--------+-------+-------+-------+
|ListenO|Mask F |Range F|timest.|autobaud|FullCAN| Frametype |
</PROGRAMLISTING>
<variablelist>
<varlistentry>
<term><parameter>Frametype</parameter></term>
<listitem><para>
Bit 0 and Bit 1 of the structure describe the possibilities of the CAN
controller. The following values are defined:
<PROGRAMLISTING>
CYGNUM_CAN_HDI_FRAMETYPE_STD // receives only standard frame
CYGNUM_CAN_HDI_FRAMETYPE_EXT_PASSIVE // can receive but not send extended frames
CYGNUM_CAN_HDI_FRAMETYPE_EXT_ACTIVE // can send and receive extended frames
</PROGRAMLISTING>
</para></listitem>
</varlistentry>
<varlistentry>
<term><parameter>FullCAN</parameter></term>
<listitem><para>
If the Bit 2 - <varname>CYGNUM_CAN_HDI_FULLCAN </varname> - is set to one,
the CAN controller supports more than one message buffer.
</para></listitem>
</varlistentry>
<varlistentry>
<term><parameter>autobaud</parameter></term>
<listitem><para>
If Bit 3 - <varname>CYGNUM_CAN_HDI_AUTBAUD</varname> - is set to one then
the CAN driver supports an autobaud feature.
</para></listitem>
</varlistentry>
<varlistentry>
<term><parameter>Timestamp</parameter></term>
<listitem><para>
If Bit 4 - <varname>CYGNUM_CAN_HDI_TIMESTAMP</varname> - is set to one then
the CAN hardware supports timestamps for CAN messages.
</para></listitem>
</varlistentry>
<varlistentry>
<term><parameter>Identifier Range filtering</parameter></term>
<listitem><para>
If Bit 5 - <varname>CYGNUM_CAN_HDI_RANGE_FILTERING</varname> - is set to one
then the CAN hardware supports message filtering based on identifier ranges.
</para></listitem>
</varlistentry>
<varlistentry>
<term><parameter>Identifier Mask filtering</parameter></term>
<listitem><para>
If Bit 6 - <varname>CYGNUM_CAN_HDI_MASK_FILTERING</varname> - is set to one
then the CAN hardware supports message filtering based on identifier masks.
</para></listitem>
</varlistentry>
<varlistentry>
<term><parameter>Listen Only mode</parameter></term>
<listitem><para>
If Bit 7 - <varname>CYGNUM_CAN_HDI_LISTEN_ONLY</varname> - is set to one
then the CAN hardware supports a 'listen-only' mode.
</para></listitem>
</varlistentry>
</variablelist>
</SECTION> <!-- can-read-buffer-config -->
<SECTION>
<TITLE>Reading hardware message buffer configuration</TITLE>
<PROGRAMLISTING>
typedef struct cyg_can_msgbox_info_st
{
cyg_uint16 count; // number of message buffers available for this device
cyg_uint16 free; // number of free message buffers
} cyg_can_msgbuf_info;
</PROGRAMLISTING>
<PARA>
<varname>CYG_IO_GET_CONFIG_CAN_MSGBUF_INFO</varname> - If the CAN hardware supports
more than one message buffer for reception of CAN messages (flag
<varname>CYGNUM_CAN_HDI_FULLCAN</varname> is set while reading hardware description
interface with <varname>CYG_IO_GET_CONFIG_CAN_HDI</varname>) then this function
reads the number of message buffers the CAN hardware supports and the number of
free message buffers.
</PARA>
<variablelist>
<varlistentry>
<term><type>cyg_uint16</type> <varname>count</varname></term>
<listitem><para>
Counts the number of message buffers supported by the device.
</para></listitem>
</varlistentry>
<varlistentry>
<term><type>cyg_uint16</type> <varname>free</varname></term>
<listitem><para>
Contains the number of free message buffers. The free message buffers are
available for setting up remote buffers (<varname>CYG_IO_SET_CONFIG_CAN_REMOTE_BUF</varname>)
and message filters (<varname>CYG_IO_SET_CONFIG_CAN_FILTER_MSG</varname>).
</para></listitem>
</varlistentry>
</variablelist>
</SECTION> <!-- can-read-buffer-config -->
<SECTION>
<TITLE>Reading state of CAN hardware</TITLE>
<PROGRAMLISTING>
typedef enum
{
CYGNUM_CAN_STATE_ACTIVE, // CAN controller active, no errors
CYGNUM_CAN_STATE_STOPPED, // CAN controller in stopped mode
CYGNUM_CAN_STATE_STANDBY, // CAN controller in Sleep mode
CYGNUM_CAN_STATE_BUS_WARN, // CAN controller active, warning level is reached
CYGNUM_CAN_STATE_ERR_PASSIVE, // CAN controller went into error passive mode
CYGNUM_CAN_STATE_BUS_OFF, // CAN controller went into bus off mode
CYGNUM_CAN_STATE_PHY_FAULT, // General failure of physical layer
CYGNUM_CAN_STATE_PHY_H, // Fault on CAN-H detected (Low Speed CAN)
CYGNUM_CAN_STATE_PHY_L, // Fault on CAN-L detected (Low Speed CAN)
} cyg_can_state;
</PROGRAMLISTING>
<PARA>
<varname>CYG_IO_GET_CONFIG_CAN_STATE</varname> - This function retrieves the
present state of the CAN controller. Possible values are defined in the
<type>cyg_can_state</type> enumeration.
</PARA>
</SECTION> <!-- can-read-hw-state -->
<SECTION>
<TITLE>Changing mode of CAN hardware</TITLE>
<PARA>
<varname>CYG_IO_SET_CONFIG_CAN_MODE</varname> - This function changes
the operating mode of the CAN controller. The identifiers for the different
operating modes are defined in the <type>cyg_can_mode</type> enumeration.
</PARA>
<PROGRAMLISTING>
typedef enum
{
CYGNUM_CAN_MODE_STOP, // set controller into stop mode
CYGNUM_CAN_MODE_START, // set controller into operational mode
CYGNUM_CAN_MODE_STANDBY,// set controller into standby / sleep mode
CYGNUM_CAN_MODE_CONFIG, // safe mode to add/delete message buffers
CYGNUM_CAN_MODE_LISTEN_ONLY_ENTER, // set controller into listen only mode.
CYGNUM_CAN_MODE_LISTEN_ONLY_EXIT // set controller out of listen only mode.
} cyg_can_mode;
</PROGRAMLISTING>
<variablelist>
<varlistentry>
<term><type>CYGNUM_CAN_MODE_STOP</type></term>
<listitem><para>
Set controller into stop mode
</para></listitem>
</varlistentry>
<varlistentry>
<term><type>CYGNUM_CAN_MODE_START</type></term>
<listitem><para>
Set controller into operational mode
</para></listitem>
</varlistentry>
<varlistentry>
<term><type>CYGNUM_CAN_MODE_STANDBY</type></term>
<listitem><para>
Set controller into standby / sleep mode.
</para></listitem>
</varlistentry>
<varlistentry>
<term><type>CYGNUM_CAN_MODE_CONFIG</type></term>
<listitem><para>
Set controller into a mode allowing modifying message buffers.
</para></listitem>
</varlistentry>
<varlistentry>
<term><type>CYGNUM_CAN_MODE_LISTEN_ONLY_ENTER</type></term>
<listitem><para> Make controller enter listen-only mode (if
supported by hardware). In such a mode the CAN controller won't
acknowledge the messages it sees on the bus. This mode can help to
perform autobaud at application level if the underlying hardware does
not support it directly. Depending on your CAN transceiver, such a
mode may also be implemented by the transceiver.
</para></listitem>
</varlistentry>
<varlistentry>
<term><type>CYGNUM_CAN_MODE_LISTEN_ONLY_EXIT</type></term>
<listitem><para> Make controller exit of listen-only
mode. The controller will acknowledge all messages it sees on the bus.
</para></listitem>
</varlistentry>
</variablelist>
<PARA>
Before the hardware configuration of the device is changed, that means
if baud rate is changed or the message buffer and filter configuration
is changed, the CAN hardware should be set into stop or config mode
and if configuration is finished, then device should be set back into
operational mode. Before the device is set into standby mode, the
output buffers should be flushed or drained because transmission of a
CAN message may wake up the CAN hardware. If a received message wakes
up the CAN hardware from standby mode then
a <varname>CYGNUM_CAN_EVENT_LEAVING_STANDBY</varname> event will be
inserted into receive message buffer or
the <varname>CYGNUM_CAN_EVENT_LEAVING_STANDBY</varname> flag will be
set for the message that caused wake up of CAN hardware.
</PARA>
<PARA>
You must also check with the CAN controller data sheet if an incoming
message waking up the controller is fully received and processed by
the controller, or if such a wake up message is lost.
</PARA>
</SECTION> <!-- can-mode-cfg -->
<SECTION>
<TITLE>Flush or drain buffers</TITLE>
<PARA>
<varname>CYG_IO_SET_CONFIG_CAN_OUTPUT_DRAIN</varname> - This function
waits for any buffered output to complete. This function only
completes when there is no more data remaining to be sent to the
device.
</PARA>
<PARA>
<varname>CYG_IO_SET_CONFIG_CAN_OUTPUT_FLUSH</varname> - This function
discards any buffered output for the device.
</PARA>
<PARA>
<varname>CYG_IO_SET_CONFIG_CAN_INPUT_FLUSH</varname> - This function
discards any buffered input for the device.
</PARA>
</SECTION>
<SECTION>
<TITLE>Configuring blocking/non-blocking calls</TITLE>
<PARA>
By default all calls to <function>cyg_io_read()</function>
and <function>cyg_io_write()</function> are blocking calls. The config
keys
</PARA>
<PROGRAMLISTING>
CYG_IO_SET_CONFIG_READ_BLOCKING
CYG_IO_SET_CONFIG_WRITE_BLOCKING
</PROGRAMLISTING>
<PARA>
enable switching between blocking and nonblocking calls separatly for
read and write calls. If blocking calls are configured then the
read/write functions return only if a message was stored into TX
buffer or an event was received from RX buffer. If non-blocking calls
are enabled and there is no space in TX buffer or RX buffer is empty
then the function returns immediately
with <varname>-EAGAIN</varname>.
</PARA>
<PARA>
If non-blocking calls are enabled and additionally timeouts are
supported by driver, then the read/write functions wait until timeout
value is expired and then return with <varname>-EINTR</varname>. If
the read/write operation succeeds during the timed wait then the
functions return succesfully with
<varname>ENOERR</varname>.
</PARA>
<PARA>
To query if <function>cyg_io_read()</function>
and <function>cyg_io_write()</function> are blocking or non-blocking
you can use the config keys
</PARA>
<PROGRAMLISTING>
CYG_IO_GET_CONFIG_READ_BLOCKING
CYG_IO_GET_CONFIG_WRITE_BLOCKING
</PROGRAMLISTING>
</SECTION> <!-- can-cfg-unblock -->
<SECTION>
<TITLE>Message buffer management</TITLE>
<PARA>
Full CAN controllers often support more than one message buffer. These
message buffers are often configurable for transmission or reception
of certain CAN messages or as a remote buffers. If a CAN hardware
supports more than one message buffer then it is possible to configure
the CAN hardware to receive only CAN messages with certain identifiers
or to configure hardware support for remote buffers. If message
filtering is done by hardware, the number of received CAN messages
decreases and so also the time for processing received CAN messages
and the memory required for buffering received messages
decreases. This saves valuable memory and processing time.
</PARA>
<PARA>
The eCos CAN driver supports a generic way of adding message filters
or remote buffers. By default the CAN driver is configured for
reception of any kind of CAN standard and extended
frames. Configuration of message buffers is done by
calling <function>cyg_io_set_config()</function> with the config key
</PARA>
<PROGRAMLISTING>
CYG_IO_SET_CONFIG_CAN_MSGBUF
</PROGRAMLISTING>
<PARA>
and by exchanging <type>cyg_can_msgbuf_cfg</type> data structures.
</PARA>
<PROGRAMLISTING>
typedef struct cyg_can_msgbox_cfg_st
{
cyg_can_msgbuf_cfg_id cfg_id; // configuration id
cyg_can_msgbuf_handle handle; // handle to message buffer
cyg_can_message msg; // CAN message - for configuration of buffer
} cyg_can_msgbuf_cfg;
</PROGRAMLISTING>
<variablelist>
<varlistentry>
<term><type>cyg_can_msgbuf_cfg_id</type> <varname>cfg_id</varname></term>
<listitem><para> The <varname>cfg_id</varname> field
contains the configuration ID that tells the driver what to do with a
message buffer.
</para></listitem>
</varlistentry>
<varlistentry>
<term><type>cyg_can_msgbuf_handle</type> <varname>handle</varname></term>
<listitem><para>
Contains a reference to a certain message buffer.
</para></listitem>
</varlistentry>
<varlistentry>
<term><type>cyg_can_message</type> <varname>msg</varname></term>
<listitem><para>
Required for configuration of message buffer parameters.
</para></listitem>
</varlistentry>
</variablelist>
<PARA>
The following configuration identifiers are supported:
</PARA>
<PROGRAMLISTING>
CYGNUM_CAN_MSGBUF_RESET_ALL // clears alle message buffers
CYGNUM_CAN_MSGBUF_RX_FILTER_ALL // cfg driver for reception of all can messages
CYGNUM_CAN_MSGBUF_RX_FILTER_ADD // add single message filter
CYGNUM_CAN_MSGBUF_REMOTE_BUF_ADD // add new remote response buffer
CYGNUM_CAN_MSGBUF_REMOTE_BUF_WRITE // stores data into existing remote buffer
</PROGRAMLISTING>
<variablelist>
<varlistentry>
<term><type>CYGNUM_CAN_MSGBUF_RESET_ALL</type></term>
<listitem><para>
Clears all message buffers - no message will be received and all remote buffers are deleted.
</para></listitem>
</varlistentry>
<varlistentry>
<term><type>CYGNUM_CAN_MSGBUF_RX_FILTER_ALL</type></term>
<listitem><para>
Configure driver for reception of all can messages
</para></listitem>
</varlistentry>
<varlistentry>
<term><type>CYGNUM_CAN_MSGBUF_RX_FILTER_ADD</type></term>
<listitem><para>
Add single message filter.
</para></listitem>
</varlistentry>
<varlistentry>
<term><type>CYGNUM_CAN_MSGBUF_REMOTE_BUF_ADD</type></term>
<listitem><para>
Add new remote response buffer.
</para></listitem>
</varlistentry>
<varlistentry>
<term><type>CYGNUM_CAN_MSGBUF_REMOTE_BUF_WRITE</type></term>
<listitem><para>
Stores data into existing remote buffer (remote buffer handle required).
</para></listitem>
</varlistentry>
</variablelist>
<PARA>
Example code for resetting all message buffers:
</PARA>
<PROGRAMLISTING>
cyg_can_msgbuf_cfg msgbox_cfg;
msgbox_cfg.cfg_id = CYGNUM_CAN_MSGBUF_RESET_ALL;
len = sizeof(msgbox_cfg);
if (ENOERR != cyg_io_set_config(hDrvFlexCAN,
CYG_IO_SET_CONFIG_CAN_MSGBUF,
&msgbox_cfg, &len))
{
// handle configuration error
}
</PROGRAMLISTING>
</SECTION> <!-- can-msgbuf-cfg -->
<SECTION>
<TITLE>Remote frame response buffer configuration</TITLE>
<PARA>
The remote frame is a message frame which is transmitted to request a
data frame. Some CAN hardware generates receive interrupts when a
remote transmission request arrives. Other CAN hardware, i.e. the
Motorola FlexCAN module, does not generate any receive
interrupt. These CAN hardware chips like the FlexCAN module can be
configured to transmit a data frame automatically in response to a
remote frame. In order to support any kind of CAN hardware the eCos CAN
driver provides a generic handling of remote transmission requests.
</PARA>
<PARA>
The transmission of the data frame in response to a remote frame is
completely handled by the CAN driver. If the hardware driver, like
the driver for the FlexCAN module, supports hardware message buffers,
then the response frame is automatically transmitted if a remote
transmission request with a matching ID arrives. If a CAN hardware
does not provide hardware support for sending data frames in response
to a remote frame, then this need to be implemented in software by the
hardware device driver.
</PARA>
<PARA>
It is always possible to add remote response buffers. It does not
matter if the driver is configured for reception of all CAN messages
or if message filtering is used. As long as there are free message
buffers available, it is possible to add remote response buffers.
</PARA>
<PARA>
In order to respond to a remote frame, a remote frame response buffer
need to be initialized before a data frame can be sent in response to
a remote frame. This is achieved by by
exchanging <type>cyg_can_remote_buf</type> data structures with the
driver via the <function>cyg_io_set_config()</function> function using
the config key <varname>CYG_IO_SET_CONFIG_CAN_MSGBUF</varname>. Once
the buffer is initialized, the CAN data can be changed at any time by
the application.
</PARA>
<PROGRAMLISTING>
typedef struct cyg_can_msgbuf_cfg_st
{
cyg_can_msgbuf_cfg_id cfg_id; // configuration id
cyg_can_msgbuf_handle handle; // handle to message buffer
cyg_can_message msg; // CAN message - for configuration of buffer
} cyg_can_remote_buf;
</PROGRAMLISTING>
<variablelist>
<varlistentry>
<term><type>cyg_can_msgbuf_cfg_id</type> <varname>cfg_id</varname></term>
<listitem><para>
The <varname>cfg_id</varname> field contains the configuration ID that tells the driver what to do with
a message buffer (<varname>CYGNUM_CAN_MSGBUF_REMOTE_BUF_ADD</varname> or
<varname>CYGNUM_CAN_MSGBUF_REMOTE_BUF_WRITE</varname>).
</para></listitem>
</varlistentry>
<varlistentry>
<term><type>cyg_can_msgbuf_handle</type> <varname>handle</varname></term>
<listitem><para>
If there is no buffer initialized for this data, the value of the handle field need to be set to
<varname>CYGNUM_CAN_MSGBUF_INIT</varname>. After the call to <function>cyg_io_set_config()</function>
the handle field contains a valid remote buffer handle ( >= 0) or the value
<varname>CYGNUM_CAN_MSGBUF_NA</varname> ( < 0) if no free buffer is available.
</para></listitem>
</varlistentry>
<varlistentry>
<term><type>cyg_can_message</type> <varname>msg</varname></term>
<listitem><para>
The CAN frame that should be transmitted in response to a remote frame.
</para></listitem>
</varlistentry>
</variablelist>
<PARA>
Example code for setting up a remote response buffer:
</PARA>
<PROGRAMLISTING>
cyg_can_remote_buf rtr_buf;
// prepare the remote response buffer
rtr_buf.cfg_id = CYGNUM_CAN_MSGBUF_REMOTE_BUF_ADD;
rtr_buf.handle = CYGNUM_CAN_MSGBUF_INIT;
rtr_buf.msg.id = 0x7FF;
rtr_buf.msg.ext = CYGNUM_CAN_ID_STD;
rtr_buf.msg.rtr = CYGNUM_CAN_FRAME_DATA;
rtr_buf.msg.dlc = 1;
rtr_buf.msg.data[0] = 0xAB;
len = sizeof(rtr_buf);
if (ENOERR != cyg_io_set_config(hDrvFlexCAN,
CYG_IO_SET_CONFIG_CAN_MSGBUF,
&rtr_buf, &len))
{
// handle configuration error
}
if (rtr_buf.handle == CYGNUM_CAN_MSGBUF_NA)
{
// no free message buffer available - handle this problem here
}
// change CAN data for a buffer that is already initialized
rtr_buf.cfg_id = CYGNUM_CAN_MSGBUF_REMOTE_BUF_WRITE;
rtr_buf.msg.data[0] = 0x11;
len = sizeof(rtr_buf);
if (ENOERR != cyg_io_set_config(hDrvFlexCAN,
CYG_IO_SET_CONFIG_CAN_MSGBUF,
&rtr_buf, &len))
{
// handle configuration error
}
</PROGRAMLISTING>
</SECTION> <!-- can-rtrbuf-cfg -->
<SECTION>
<TITLE>Message filter configuration</TITLE>
<PARA>
If message filtering is done by hardware the number of received CAN
messages decreases and so also the time for processing received CAN
messages and the memory required for buffering received messages
decreases. This saves valuable memory and processing time. The eCos
CAN driver supports a generic way of adding message filters. By
default the CAN driver is configured for reception of any kind of CAN
standard and extended frames. As soon as a message filter is added,
the CAN driver will only receive the CAN frames with the identifier of
the CAN filter. By adding a number of message filters it is possible
for the CAN hardware to receive an number of different CAN messages.
</PARA>
<PARA>
Adding message filters is only possible if driver is not configured
for reception of all available CAN messages. If the driver is
configured for reception of all CAN messages then message buffers need
to be reset before adding single message filters.
</PARA>
<PARA>
In order to add a message filter, a message buffer need to be
initialized. This is achieved by
exchanging <type>cyg_can_filter</type> data structures with the driver
via the <function>cyg_io_set_config()</function> function using the
config key <varname>CYG_IO_SET_CONFIG_CAN_MSGBUF</varname>. Once the
buffer is initialized, the CAN hardware can receive messages with the
identifier of the filter.
</PARA>
<PROGRAMLISTING>
typedef struct cyg_can_msgbox_cfg_st
{
cyg_can_msgbuf_cfg_id cfg_id;
cyg_can_msgbuf_handle handle;
cyg_can_message msg;
} cyg_can_filter;
</PROGRAMLISTING>
<variablelist>
<varlistentry>
<term><type>cyg_can_msgbuf_cfg_id</type> <varname>cfg_id</varname></term>
<listitem><para>
The <varname>cfg_id</varname> field contains the configuration ID that tells the driver what to do with
a message buffer.
</para></listitem>
</varlistentry>
<varlistentry>
<term><type>cyg_can_msgbuf_handle</type> <varname>handle</varname></term>
<listitem><para>
After the call to <function>cyg_io_set_config()</function> the handle field contains a valid value
( >= 0) or the value <varname>CYGNUM_CAN_MSGBUF_NA</varname> ( < 0) if no free buffer is available.
</para></listitem>
</varlistentry>
<varlistentry>
<term><type>cyg_can_message</type> <varname>msg</varname></term>
<listitem><para>
The fields <structfield>id</structfield> and <structfield>ext</structfield> of the <structfield>msg</structfield>
configure the type of message to receive by a certain message filter.
</para></listitem>
</varlistentry>
</variablelist>
<PARA>
Before adding message filters the device should be stopped and after
configuration it should be set into operational mode again.
</PARA>
<PARA>
Example code for setting up a message filter:
</PARA>
<PROGRAMLISTING>
cyg_can_msgbuf_cfg msgbox_cfg;
cyg_can_filter rx_filter;
// reset all message buffers
msgbox_cfg.cfg_id = CYGNUM_CAN_MSGBUF_RESET_ALL;
len = sizeof(msgbox_cfg);
if (ENOERR != cyg_io_set_config(hDrvFlexCAN,
CYG_IO_SET_CONFIG_CAN_MSGBUF,
&msgbox_cfg, &len))
{
// handle configuration error
}
// prepare the message filter
rx_filter.cfg_id = CYGNUM_CAN_MSGBUF_RX_FILTER_ADD;
rx_filter.msg.id = 0x800;
rx_filter.msg.ext = CYGNUM_CAN_ID_EXT;
len = sizeof(rx_filter);
if (ENOERR != cyg_io_set_config(hDrvFlexCAN,
CYG_IO_SET_CONFIG_CAN_MSGBUF,
&rx_filter, &len))
{
// handle configuration error;
}
else if (CYGNUM_CAN_MSGBUF_NA == rx_filter.handle)
{
// no free message buffer available - handle this problem here
}
</PROGRAMLISTING>
</SECTION> <!-- can-msgfilt-cfg -->
<SECTION id="can-msgfilt-deact">
<TITLE>Message filter deactivation</TITLE>
<PARA>
After startup of your device the CAN driver is configured for
reception of all available CAN messages. If you change this
configuration by adding single message filters then you can reset this
default state with the configuration ID:
</PARA>
<PROGRAMLISTING>
CYGNUM_CAN_MSGBUF_RX_FILTER_ALL
</PROGRAMLISTING>
<PARA>
This message buffer configuration id will clear all message filters
and remote buffers and prepares the CAN hardware for reception of any
kind of CAN standard and extended frames. It is not necessary to reset
the message buffer configuration before this configuration step is
executed because this should be done by device driver.
</PARA>
<PARA>
Example code for deactivation of message filtering:
</PARA>
<PROGRAMLISTING>
cyg_can_filter rx_filter;
// now setup a RX all configuration
rx_filter.cfg_id = CYGNUM_CAN_MSGBUF_RX_FILTER_ALL;
len = sizeof(rx_filter);
if (ENOERR != cyg_io_set_config(hDrvFlexCAN,
CYG_IO_SET_CONFIG_CAN_MSGBUF,
&rx_filter, &len))
{
CYG_TEST_FAIL_FINISH("Error writing config of /dev/can0");
}
</PROGRAMLISTING>
</SECTION> <!-- can-msgfilt-deact -->
<SECTION id="can-id-range-filter">
<TITLE>Message filtering using identifier ranges</TITLE>
<PARA>
If the low level driver supports it, you can filter messages using
identifier ranges. Such filtering is interesting if it is directly
supported by the CAN controller hardware. Instead of waiting for a
particular message identifier, the application can define one or more
ranges of identifiers. If a received message has an identifier value
(and type) matching a defined identifier range, then the message
passes the filter and is made available to the application.
</PARA>
<PARA>
To add such a filter, use this configuration ID:
</PARA>
<PROGRAMLISTING>
CYG_IO_SET_CONFIG_CAN_RANGE_FILTER
</PROGRAMLISTING>
<PARA>
The buffer argument given to <function>cyg_io_set_config()</function>
must point to an area holding the following structure:
</PARA>
<PROGRAMLISTING>
typedef struct cyg_can_filter_range_cfg_st
{
cyg_can_id_type ext; // type of identifier concerned
cyg_uint32 lower_id_bound; // lower bound identifier (included)
cyg_uint32 upper_id_bound; // upper bound identifier (included)
} cyg_can_filter_range_cfg;
</PROGRAMLISTING>
<variablelist>
<varlistentry>
<term><type>cyg_can_id_type</type> <varname>ext</varname></term>
<listitem><para> Extended ID. If this field
is <varname>CYGNUM_CAN_ID_EXT</varname> then the next two fields contains
29 bit extended ID. If <varname>ext</varname>
contains <varname>CYGNUM_CAN_ID_STD</varname> then the next two fields
represent 11 bits identifiers.
</para></listitem>
</varlistentry>
<varlistentry>
<term><type>cyg_uint32</type> <varname>lower_id_bound</varname></term>
<listitem><para>
Combined with <varname>upper_id_bound</varname> an identifier range is
defined. All messages having an identifier of the type defined by
<varname>ext</varname> and included in the range <varname>lower_id_bound</varname>
to <varname>upper_id_bound</varname> will pass the filter. The identifiers
<varname>lower_id_bound</varname> and <varname>upper_id_bound</varname> are
included in the defined range.
</para></listitem>
</varlistentry>
<varlistentry>
<term><type>cyg_uint32</type> <varname>upper_id_bound</varname></term>
<listitem><para>
Upper identifier value of the defined range.
</para></listitem>
</varlistentry>
</variablelist>
</SECTION> <!-- can-id-range-filter -->
<SECTION id="can-id-mask-filter">
<TITLE>Message filtering using identifier masks</TITLE>
<PARA>
If the low level driver supports it, you can filter messages using
identifier masks. Such filtering is interesting if it is directly
supported by the CAN controller hardware. Instead of waiting for a
particular message identifier, the application can define one or more
pair of identifier and mask. If a received message has an identifier
value (and type) that, for each bit set of the mask, matches the
corresponding bit in the provided identifier, then the message passes
the filter and is made available to the application.
</PARA>
<PARA>
To add such a filter, use this configuration ID:
</PARA>
<PROGRAMLISTING>
CYG_IO_SET_CONFIG_CAN_MASK_FILTER
</PROGRAMLISTING>
<PARA>
The buffer argument given to <function>cyg_io_set_config()</function>
must point to an area holding the following structure:
</PARA>
<PROGRAMLISTING>
typedef struct cyg_can_filter_mask_cfg_st
{
cyg_can_id_type ext; // type of identifier concerned
cyg_uint32 id; // identifier to use for filtering
cyg_uint32 mask; // mask to apply for filtering
} cyg_can_filter_mask_cfg;
</PROGRAMLISTING>
<variablelist>
<varlistentry>
<term><type>cyg_can_id_type</type> <varname>ext</varname></term>
<listitem><para>
Extended ID. If this field is <varname>CYGNUM_CAN_ID_EXT</varname> then the
<structname>id</structname> field contains a 29 bit extended ID. If it
contains <varname>CYGNUM_CAN_ID_STD</varname> then the ID is 11 bits.
</para></listitem>
</varlistentry>
<varlistentry>
<term><type>cyg_uint32</type> <varname>id</varname></term>
<listitem><para>
Message ID. This is the ID to be matched with an incoming message, after
having considered the <varname>mask</varname> field.
</para></listitem>
</varlistentry>
<varlistentry>
<term><type>cyg_uint32</type> <varname>mask</varname></term>
<listitem><para>
Mask value. A message will pass the filter if, for each bit set in
<varname>mask</varname>, the received message ID has its corresponding
bit equals to the corresponding bit in the <varname>id</varname> field.
</para></listitem>
</varlistentry>
</variablelist>
<PARA>
For instance let's suppose that the <varname>id</varname> field is
0x05 (bits 0 and 2 are set) and the <varname>mask</varname> field is
0x07 (bits 0, 1 and 2 are set). If an incoming message has an ID of
0x01: bit 0 matches since bit 0 is set in the mask and both the
incoming message and the <varname>id</varname> field have a similar
value for bit 0. The message ID has its bit 1 set to 0, as
the <varname>id</varname> field and the mask tells the controller to
check this bit: it passes too. However the message ID has its bit 2
unset, while bit 2 of the mask tells the controller to check bit
2. Bit 2 of the identifier isn't set in the <varname>id</varname>
field, hence this example message does not pass the filter.
</PARA>
</SECTION> <!-- can-id-mask-filter -->
<SECTION id="can-event-callback">
<TITLE>Configuring a callback on events</TITLE>
<PARA>
By default application cannot get information about an event arriving
in the RX buffer until it calls
the <function>cyg_io_read()</function>. Usually this leads applications
to use accessory threads to wait for new CAN events.
</PARA>
<PARA>
The CDL option <varname>CYGOPT_IO_CAN_SUPPORT_CALLBACK</varname>
allows application to use a callback on event arrival. It is
configured by passing a <structname>cyg_can_callback_cfg</structname>
data structure to the driver via
the <function>cyg_io_set_config()</function> function using the config
key
<varname>CYG_IO_SET_CONFIG_CAN_CALLBACK</varname>.
</PARA>
<PROGRAMLISTING>
CYG_IO_SET_CONFIG_CAN_CALLBACK
</PROGRAMLISTING>
<PROGRAMLISTING>
typedef void (*cyg_can_event_cb_t)(cyg_uint16, CYG_ADDRWORD);
typedef struct cyg_can_callback_cfg_st
{
cyg_can_event_cb_t callback_func; // callback function
cyg_can_event_flags_t flag_mask; // flags mask
CYG_ADDRWORD data; // data passed to callback
} cyg_can_callback_cfg;
</PROGRAMLISTING>
<variablelist>
<varlistentry>
<term><type>cyg_can_event_cb_t</type> <varname>callback_func</varname></term>
<listitem><para>
Pointer to the callback function. The function will be called from DSR context so
you should be careful to only call API functions that are safe in DSR
context. The first parameter is a combination of event flags for events that have
occurred. Second parameter is a user defined data pointer or value.
</para></listitem>
</varlistentry>
<varlistentry>
<term><type>CYG_ADDRWORD</type> <varname>data</varname></term>
<listitem><para>
Additional user data that will be passed to callback function as a second parameter.
</para></listitem>
</varlistentry>
<varlistentry>
<term><type>cyg_can_event_flags_t</type> <varname>flag_mask</varname></term>
<listitem><para>
Should be set with a combination
of <varname>CYGNUM_CAN_EVENT_*</varname> flags. If one of these
events happens, the callback function will be called, with the
actually event flags passed as a parameter. To disable the callback
function from being called set <varname>flag_mask</varname> to 0. To
set all possible flags use the <varname>CYGNUM_CAN_EVENT_ALL</varname> macro.
</para></listitem>
</varlistentry>
</variablelist>
<PARA>
Instead of using a thread dedicated to reading CAN events, it is
possible, if the CAN controller I/O handle was set in non-blocking
mode for read operations, to have the callback function to read each
event it is waiting for. However the callback function runs in DSR
mode, so it must be carefully written to avoid any blocking call.
</PARA>
<PARA>
If you plan to have the callback function to perform read operations,
be aware that <function>cyg_io_read()</function> retrieves events of
all kinds while the callback function is triggered only on events it
is expecting, as defined by the <varname>flag_mask</varname>
field. The side effect is that the callback function, if it is not
waiting for all events, may see its first parameter (the flag(s)
describing why the callback function is called) different from an
event it get from <function>cyg_io_read()</function>.
</PARA>
<PARA>
For instance, let's suppose the callback function is expecting
only <varname>CYGNUM_CAN_EVENT_RX</varname> events while the bus
activity triggers other kind of events, like
the <varname>CYGNUM_CAN_EVENT_WARNING_RX</varname> event. It is
possible to have in the receive queue a first event of
type <varname>CYGNUM_CAN_EVENT_WARNING_RX</varname> followed by a
second event of type <varname>CYGNUM_CAN_EVENT_RX</varname>. In that
case, the callback function is triggered and have its first parameter
set to <varname>CYGNUM_CAN_EVENT_RX</varname> exactly
when <varname>CYGNUM_CAN_EVENT_RX</varname> occurs, but if the
callback function reads the event queue, it will first get
the <varname>CYGNUM_CAN_EVENT_WARNING_RX</varname> event.
</PARA>
<PARA>
If the callback function is set to process all kind of events and
always call <function>cyg_io_read()</function> to get each event, it
is possible to have a receive queue size of one event.
</PARA>
<PARA>
If the CAN controller does not provide message timestamps of its own,
or if the provided timestamps do not match your needs, the callback
function mechanism can be helpful since it is called from the DSR
processing the hardware related events. The callback function can
manage timestamps in the way that suits you the best however there is
a slight delay between an event related to the CAN bus activity occurs
and the time the callback function runs. If you implement your own
timestamps this way, pay also attention to what gives you the current
time. For instance the granularity
of <function>cyg_current_time()</function> may not be accurate enough,
according to the clock resolution and your needs of accuracy.
</PARA>
</SECTION> <!-- can-event-callback -->
</SECTION>
</CHAPTER>
<CHAPTER id="io-can-configuration">
<TITLE>Configuration</TITLE>
<PARA>
The CAN subsystem has a number of configuration options.
</PARA>
<variablelist>
<varlistentry>
<term><type>cdl_interface CYGINT_IO_CAN_TIMESTAMP</type></term>
<listitem><para>
A hardware device driver that supports timestamps should implement this interface.
</para></listitem>
</varlistentry>
<varlistentry>
<term><type>cdl_option CYGOPT_IO_CAN_SUPPORT_TIMESTAMP</type></term>
<listitem><para>
If the CAN hardware driver supports some kind of timestamps then this option enables
propagation of timestamps to higher layers. This may add some extra code to hardware
drivers.
</para></listitem>
</varlistentry>
<varlistentry>
<term><type>cdl_option CYGOPT_IO_CAN_TX_EVENT_SUPPORT</type></term>
<listitem>
<para> This option enables support for TX
events. If a CAN message is transmitted successfully a TX event will
be inserted into the receive event queue and propagated to higher
layers. If this option is enabled the RX event queue will be filled
faster.
</para></listitem>
</varlistentry>
<varlistentry>
<term><type>cdl_option CYGOPT_IO_CAN_SUPPORT_NONBLOCKING</type></term>
<listitem>
<para>
This option enables extra code in the generic CAN driver which allows
clients to switch read() and write() call semantics from blocking to
non-blocking.
</para></listitem>
</varlistentry>
<varlistentry>
<term><type>cdl_option CYGOPT_IO_CAN_SUPPORT_CALLBACK</type></term>
<listitem>
<para>
This option enables extra code in the generic CAN driver which allows
an application to register a callback for events. The callback function
is called from DSR context so you should be careful to only call API
functions that are safe in DSR context.
</para></listitem>
</varlistentry>
<varlistentry>
<term><type>cdl_option CYGNUM_IO_CAN_DEFAULT_TIMEOUT_READ</type></term>
<listitem><para>
The initial timeout value in clock ticks for <FUNCTION>cyg_io_read()</FUNCTION> calls.
</para></listitem>
</varlistentry>
<varlistentry>
<term><type>cdl_option CYGNUM_IO_CAN_DEFAULT_TIMEOUT_WRITE</type></term>
<listitem><para> The initial timeout value in clock ticks
for <FUNCTION>cyg_io_write()</FUNCTION> calls.
</para></listitem>
</varlistentry>
</variablelist>
</CHAPTER>
<CHAPTER id="io-can-device-drivers">
<TITLE>Writing a CAN hardware device driver</TITLE>
<PARA>
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.
</PARA>
<PARA>
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.
</PARA>
<PARA>
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.
</PARA>
<PARA>
The main building blocks for CAN device drivers are found in the
include files
<filename><cyg/io/devtab.h></filename> and <filename><cyg/io/can.h></filename>
</PARA>
<PARA>
Like many other device drivers in eCos, CAN device drivers are described by a device
table entry, using the <type>cyg_devtab_entry_t</type> type. The entry should be created using
the <varname>DEVTAB_ENTRY()</varname> macro.
</PARA>
<SECTION id="io-can-how-to-write-interface-driver">
<TITLE>How to Write a CAN Hardware Interface Driver</TITLE>
<PARA>
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.
</PARA>
<PARA>
The interfaces used by the CAN driver and CAN implementation modules
are contained in the file <filename><cyg/io/can.h></filename>.
</PARA>
<SECTION>
<title>DevTab Entry</TITLE>
<PARA>
The interface module contains the devtab entry (or entries if a single
module supports more than one interface). This entry should have the
form:
</PARA>
<PROGRAMLISTING>
DEVTAB_ENTRY(<<module_name>>,
<<device_name>>,
0,
&can_devio,
<<module_init>>,
<<module_lookup>>,
&<<can_channel>>
);
</PROGRAMLISTING>
<variablelist>
<title>Arguments</title>
<varlistentry>
<term><parameter>module_name</parameter></term>
<listitem><para>The "C" label for this devtab entry</para></listitem>
</varlistentry>
<varlistentry>
<term><parameter>device_name</parameter></term>
<listitem><para>The "C" string for the
device. E.g. <filename>/dev/can0</filename>.</para></listitem>
</varlistentry>
<varlistentry>
<term><parameter>can_devio</parameter></term>
<listitem><para>The table of I/O functions. This set is defined in
the hardware independent CAN driver and should be used.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><parameter>module_init</parameter></term>
<listitem><para>The hardware module initialization function.</para></listitem>
</varlistentry>
<varlistentry>
<term><parameter>module_lookup</parameter></term>
<listitem><para>The device lookup function. This function
typically sets up the CAN device for actual use, turning on
interrupts, configuring the message buffers, etc.</para></listitem>
</varlistentry>
<varlistentry>
<term><parameter>can_channel</parameter></term>
<listitem><para>This table (defined below) contains the interface
between the interface module and the CAN driver proper.</para></listitem>
</varlistentry>
</variablelist>
<PARA>
Example devtab entry for Motorola FlexCAN device driver:
</PARA>
<PROGRAMLISTING>
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
);
</PROGRAMLISTING>
</SECTION>
<SECTION>
<title>CAN Channel Structure</TITLE>
<PARA>
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:
</PARA>
<PROGRAMLISTING>
CAN_CHANNEL_USING_INTERRUPTS(l, funs, dev_priv, baud,
out_buf, out_buflen,
in_buf, in_buflen)
</PROGRAMLISTING>
<variablelist>
<title>Arguments</title>
<varlistentry>
<term><parameter>l</parameter></term>
<listitem><para>The "C" label for this structure.</para></listitem>
</varlistentry>
<varlistentry>
<term><parameter>funs</parameter></term>
<listitem><para>The set of interface functions (see below).</para></listitem>
</varlistentry>
<varlistentry>
<term><structfield>dev_priv</structfield></term>
<listitem><para>A placeholder for any device specific data for
this channel.</para></listitem>
</varlistentry>
<varlistentry>
<term><structfield>baud</structfield></term>
<listitem><para>The initial baud rate value
(<type>cyg_can_baud_rate_t</type>).</para></listitem>
</varlistentry>
<varlistentry>
<term><structfield>out_buf</structfield></term>
<listitem><para>Pointer to the output buffer</para></listitem>
</varlistentry>
<varlistentry>
<term><structfield>out_buflen</structfield></term>
<listitem><para>The length of the output buffer.</para></listitem>
</varlistentry>
<varlistentry>
<term><structfield>in_buf</structfield></term>
<listitem><para>pointer to the input buffer.</para></listitem>
</varlistentry>
<varlistentry>
<term><structfield>in_buflen</structfield></term>
<listitem><para>The length of the input buffer.</PARA></listitem>
</varlistentry>
</variablelist>
<PARA>
Example CAN channel implementation for Motorola FlexCAN device driver:
</PARA>
<PROGRAMLISTING>
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
);
</PROGRAMLISTING>
<PARA>
The interface from the hardware independent driver into the hardware
interface module is contained in the <structfield>funs</structfield>
table. This is defined by the macro:
</PARA>
</SECTION>
<SECTION>
<TITLE>CAN Lowlevel Functions Structure</TITLE>
<PROGRAMLISTING>
CAN_LOWLEVEL_FUNS(l, putmsg, getevent, get_config, set_config, start_xmit, stop_xmit)
</PROGRAMLISTING>
<variablelist>
<title>Arguments</title>
<varlistentry>
<term><structfield>l</structfield></term>
<listitem><para>The "C" label for this structure.</para></listitem>
</varlistentry>
<varlistentry>
<term><structfield>putmsg</structfield></term>
<listitem>
<para><literal>
bool (*putmsg)(can_channel *priv, cyg_can_message *pmsg, void *pdata)
</literal></para>
<para>
This function sends one CAN message to the interface. It should
return <literal>true</literal> if the message is actually
consumed. It should return <literal>false</literal> if there is
no space in the interface
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><structfield>getevent</structfield></term>
<listitem>
<para><literal>
bool (*getevent)(can_channel *priv, cyg_can_event *pevent, void *pdata)
</literal></para>
<para>
This function fetches one event from the interface.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><structfield>get_config</structfield></term>
<listitem>
<para><literal>
Cyg_ErrNo (*get_config)(can_channel *priv, cyg_uint32 key, const void *xbuf, cyg_uint32 *len)
</literal></para>
<para>
This function is used to query the configuration of a CAN channel.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><structfield>set_config</structfield></term>
<listitem>
<para><literal>
Cyg_ErrNo (*set_config)(can_channel *priv, cyg_uint32 key, const void *xbuf, cyg_uint32 *len)
</literal></para>
<para>
This function is used to change configuration of a CAN channel.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><parameter>start_xmit</parameter></term>
<listitem><para><literal>void (*start_xmit)(can_channel *priv)</literal></para>
<para>
Enable the transmit channel and turn on transmit interrupts.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><parameter>stop_xmit</parameter></term>
<listitem>
<para><literal>void (*stop_xmit)(can_channel *priv)</literal></para>
<para>Disable the transmit channel and turn transmit interrupts off.</PARA>
</listitem>
</varlistentry>
</variablelist>
<PARA>
Example implementation of low level function structure for Motorola FlexCAN
device driver:
</PARA>
<PROGRAMLISTING>
CAN_LOWLEVEL_FUNS(flexcan_lowlevel_funs,
flexcan_putmsg,
flexcan_getevent,
flexcan_get_config,
flexcan_set_config,
flexcan_start_xmit,
flexcan_stop_xmit
);
</PROGRAMLISTING>
</SECTION>
<SECTION>
<TITLE>Callbacks</TITLE>
<PARA>
The device interface module can execute functions in the
hardware independent driver via <literal>chan->callbacks</literal>.
These functions are available:
</PARA>
<PROGRAMLISTING>
void (*can_init)(can_channel *chan)
</PROGRAMLISTING>
<PARA>This function is used to initialize the CAN channel.</PARA>
<PROGRAMLISTING>
cyg_bool (*xmt_msg)(can_channel *chan, void *pdata)
</PROGRAMLISTING>
<PARA>
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 <function>putmsg</function>
function as appropriate to send more data to the
device. <function>xmt_msg()</function> returns <literal>true</literal>
if a message has been provided to the low level
driver, <literal>false</literal> otherwise.
</PARA>
<PROGRAMLISTING>
cyg_bool (*rcv_event)(can_channel *chan, void *pdata)
</PROGRAMLISTING>
<PARA>
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. <function>rcv_event()</function>
returns <literal>true</literal> if an event has been provided by the
low level driver, <literal>false</literal> otherwise.
</PARA>
</SECTION><!-- Callbacks -->
</SECTION><!-- id="io-can-how-to-write-interface-driver" -->
</CHAPTER>
</PART>
Go to most recent revision | Compare with Previous | Blame | View Log