Mercurial > ecos
changeset 2335:1e57c4599705
* doc/can.sgml: CAN driver SGML documentation added.
| author | asl |
|---|---|
| date | Sat, 16 Dec 2006 19:51:21 +0000 |
| parents | 32bc0bce49a0 |
| children | e7f4d7e429ce |
| files | packages/io/can/current/ChangeLog packages/io/can/current/doc/can.sgml |
| diffstat | 2 files changed, 1906 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- a/packages/io/can/current/ChangeLog +++ b/packages/io/can/current/ChangeLog @@ -1,3 +1,7 @@ +2006-12-13 Uwe Kindler <uwe_kindler@web.de> + + * doc/can.sgml: CAN driver SGML documentation added. + 2006-08-25 Gary Thomas <gary@mlbassoc.com> * cdl/io_can.cdl: Set parent for more intuitive ConfigTool layout.
new file mode 100644 --- /dev/null +++ b/packages/io/can/current/doc/can.sgml @@ -0,0 +1,1902 @@ +<!-- {{{ Banner --> + +<!-- =============================================================== --> +<!-- --> +<!-- can.sgml --> +<!-- --> +<!-- Generic CAN documentation. --> +<!-- --> +<!-- =============================================================== --> +<!-- ####COPYRIGHTBEGIN#### --> +<!-- --> +<!-- =============================================================== --> +<!-- Copyright (C) 2004 eCosCentric Limited --> +<!-- 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 --> +<!-- =============================================================== --> +<!-- --> +<!-- ####COPYRIGHTEND#### --> +<!-- =============================================================== --> +<!-- #####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 inderface 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> 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> + +<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 sucessfully 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_can_recv()</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 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 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 a event was sucessfully 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_message msg; + cyg_uint16 flags; +} 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_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> + <varlistentry> + <term><type>cyg_uint16</type> <varname>flags</varname></term> + <listitem><para> +Event flags. The <varname>flags</varname> field contains 16 bits that +indicate which kind of events occured. + </para></listitem> + </varlistentry> +</variablelist> + +<PARA> +The following events are supported and after receiving an event the +application should check the flag field against these values: +</PARA> + +<PROGRAMLISTING> +typedef enum +{ + CYGNUM_CAN_EVENT_RX = 0x0001, // message received + CYGNUM_CAN_EVENT_TX = 0x0002, // message transmitted + CYGNUM_CAN_EVENT_WARNING_RX = 0x0004, // (TEC) reached warning level (>96) + CYGNUM_CAN_EVENT_WARNING_TX = 0x0008, // (REC) reached warning level (>96) + CYGNUM_CAN_EVENT_ERR_PASSIVE = 0x0010, // CAN "error passive" occured + CYGNUM_CAN_EVENT_BUS_OFF = 0x0020, // CAN "bus off" error occured + CYGNUM_CAN_EVENT_OVERRUN_RX = 0x0040, // overrun in RX queue or hardware + CYGNUM_CAN_EVENT_OVERRUN_TX = 0x0080, // overrun in TX queue occured + CYGNUM_CAN_EVENT_CAN_ERR = 0x0100, // a CAN bit or frame error occured + CYGNUM_CAN_EVENT_LEAVING_STANDBY = 0x0200, // CAN hardware leaves standby + CYGNUM_CAN_EVENT_ENTERING_STANDBY = 0x0400, // CAN hardware enters standby + CYGNUM_CAN_EVENT_ARBITRATION_LOST = 0x0800, // arbitration lost + CYGNUM_CAN_EVENT_DEVICE_CHANGED = 0x1000, // device changed event + CYGNUM_CAN_EVENT_PHY_FAULT = 0x2000, // General failure of physical layer + CYGNUM_CAN_EVENT_PHY_H = 0x4000, // Fault on CAN-H (Low Speed CAN) + CYGNUM_CAN_EVENT_PHY_L = 0x8000, // Fault on CAN-L (Low Speed CAN) +} cyg_can_event_flags; +</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. I.e. if the <varname>CYGNUM_CAN_EVENT_RX</varname> +is set then also the <varname>CYGNUM_CAN_EVENT_OVERRUN_RX</varname> +may be set if the received message caused an RX overrun. +</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 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. The +<varname>CYGNUM_CAN_EVENT_OVERRUN_RX</varname> flag will be set also if +a overrun occures in hardware message buffers of the CAN device. +</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 +</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 | ++-------+-------+-------+-------+-------+-------+-------+-------+ +| res | res | res |timest.|SW-Filt|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>SW-Filter</parameter></term> + <listitem><para> +If Bit 3 - <varname>CYGNUM_CAN_HDI_FILT_SW</varname> - is set to one then +the CAN driver supports some kind of software message filtering. + </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> +</variablelist> +</SECTION> <!-- can-read-buffer-config --> + +<SECTION> +<TITLE>Reading hardware message buffer configuration</TITLE> +<PROGRAMLISTING> +typedef struct cyg_can_msgbox_info_st +{ + cyg_uint8 count; // number of message buffers available for this device + cyg_uint8 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_uint8</type> <varname>count</varname></term> + <listitem><para> +Counts the number of message buffers supported by the device. + </para></listitem> + </varlistentry> + <varlistentry> + <term><type>cyg_uint8</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 +} 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> +</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 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> +</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 a 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 the 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 alle 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-cfg --> +</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 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> +void (*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. +</PARA> + +<PROGRAMLISTING> +void (*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. +</PARA> +</SECTION><!-- Callbacks --> + +</SECTION><!-- id="io-can-how-to-write-interface-driver" --> +</CHAPTER> + +</PART>
