# HG changeset patch # User asl # Date 1166298681 0 # Node ID 1e57c4599705ee252f2c2ae0ec575567f1da08ce # Parent 32bc0bce49a02721c0dbf00371ebffcf1f2db4e4 * doc/can.sgml: CAN driver SGML documentation added. diff --git a/packages/io/can/current/ChangeLog b/packages/io/can/current/ChangeLog --- a/packages/io/can/current/ChangeLog +++ b/packages/io/can/current/ChangeLog @@ -1,3 +1,7 @@ +2006-12-13 Uwe Kindler + + * doc/can.sgml: CAN driver SGML documentation added. + 2006-08-25 Gary Thomas * cdl/io_can.cdl: Set parent for more intuitive ConfigTool layout. diff --git a/packages/io/can/current/doc/can.sgml b/packages/io/can/current/doc/can.sgml new file mode 100644 --- /dev/null +++ b/packages/io/can/current/doc/can.sgml @@ -0,0 +1,1902 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +CAN Support + + +Overview + +
+Description + + +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. + + + +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. + + + +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. + + + +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. + + + +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. + + + +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. + + + +You can find more information at the +CAN in Automation website. + + +
+ +
+eCos Support for CAN + + +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. + + + +The eCos CAN support for any given platform is spread over a number of different +packages: + + + + + + +This package, CYGPKG_IO_CAN, 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. + + + + +Each CAN device will have its own device driver, which is implemented +as a separate package, for example +CYGPKG_DEVS_CAN_MCF52xx_FLEXCAN. 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. + + + + + +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. + + + +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. + +
+
+ + +User API + + +The CAN driver uses the standard eCos I/O API functions. All functions +except cyg_io_lookup() require an I/O "handle". + + + +All functions return a value of the type Cyg_ErrNo. +If an error condition is detected, this value will be negative and the +absolute value indicates the actual error, as specified in +cyg/error/codes.h. The only other legal return values +will be ENOERR, -EINTR and +-EAGAIN. 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 +len 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. + + + +// Lookup a CAN device and return its handle +Cyg_ErrNo cyg_io_lookup( + const char *name, + cyg_io_handle_t *handle ) + + + +This function maps a CAN device name onto an appropriate handle. If the +named device is not in the system, then the error +-ENOENT is returned. If the device is found, then +the handle for the device is returned by way of the handle pointer +*handle. + + + +// Send a CAN message +Cyg_ErrNo cyg_io_write( + cyg_io_handle_t handle, + const void *buf, + cyg_uint32 *len ) + + + +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 +*len and the actual size sent will be returned in +the same place. + + + +// Read one CAN event from device +Cyg_ErrNo cyg_io_read( + cyg_io_handle_t handle, + void *buf, + cyg_uint32 *len ) + + + +This function receives one single CAN event from a device. The desired size +of data to receive is contained in *len and the +actual size obtained will be returned in the same place. + + + +// Read configuration of a CAN device +Cyg_ErrNo cyg_io_get_config( + cyg_io_handle_t handle, + cyg_uint32 key, + void *buf, + cyg_uint32 *len ) + + + +This function is used to obtain run-time configuration about a +device. The type of information retrieved is specified by the +key. The data will be returned in the given +buffer. The value of *len 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 *len. The appropriate key values +are all listed in the file <cyg/io/config_keys.h>. + + + +// Change configuration of a CAN device +Cyg_ErrNo cyg_io_set_config( + cyg_io_handle_t handle, + cyg_uint32 key, + const void *buf, + cyg_uint32 *len ) + + + +This function is used to manipulate or change the run-time +configuration of a device. The type of information is specified by the +key. The data will be obtained from the given +buffer. The value of *len 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 +<cyg/io/config_keys.h>. + + + + +CAN driver details + + +Allow applications and other packages to access CAN devices. + + +
+Description + + +A raw CAN driver is is provided as a standard part of the eCos system. + + + +Use the include file <cyg/io/canio.h> for this driver. + + + +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. + + + +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. + +
+ +
+API Details + +
+cyg_io_write + + +cyg_io_write(handle, buf, len) + + + +To transmit a message an application must fill a cyg_can_message +buffer and call cyg_io_write(). +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 *len +and the actual size sent will be returned in the same place. A pointer to a +cyg_can_message is contained in *buf. +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, *len +contains the amount of characters actually consumed - that means +*len always contains +sizeof(cyg_can_message). + + + +It is possible to configure the write call to be blocking (default) or +non-blocking. Non-blocking mode requires both the configuration option +CYGOPT_IO_CAN_SUPPORT_NONBLOCKING to be enabled, and +the specific device to be set to non-blocking mode for writes +(see cyg_io_set_config()). 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, -EAGAIN is +returned and the caller must try again. + + + +It is possible to configure the write call to be non-blocking with timeout. +None-blocking mode with timeout requires the configuration option +CYGOPT_IO_CAN_SUPPORT_NONBLOCKING and +CYGOPT_IO_CAN_SUPPORT_TIMEOUTS 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 cyg_io_set_config() +). +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, -EINTR is returned and +the caller must try again. + + + +If a message was sucessfully sent, the function returns ENOERR. + +
+ +
+CAN Messages + + +The CAN driver uses cyg_can_message 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. + + + +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; + + + +The structure contains the following fields: + + + + + cyg_uint32 id + +Message ID. This is the ID to be transmitted with the message, or the +ID received. If the ext field is set, then +this will contain a 29 bit ID, otherwise it will contain an 11 bit ID. + + + + cyg_uint32 data + +Message data. Only the first dlc bytes of +data are valid. If the rtr field is set, +then the contents of this field are ignored. + + + + cyg_can_id_type ext + +Extended ID. If this field is CYGNUM_CAN_ID_EXT then the +id field contains a 29 bit extended ID. If it +contains CYGNUM_CAN_ID_STD then the ID is 11 bits. + + + + cyg_can_frame_type rtr + +Remote Transmission Request. If this field contains +CYGNUM_CAN_FRAME_RTR then the RTR bit on the message +will be set and the data field will be ignored. +If the field contains CYGNUM_CAN_FRAME_DATA then a +normal data frame will be send. + + + + cyg_uint8 dlc + +The length of the data carried in the message. This can range from +zero to 8. In a message with the rtr field set, +this indicates the size of data being requested. + + + + + +Example code for sending one single CAN message: + + + +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); + +
+ +
+cyg_io_read + + +cyg_io_read(handle, buf, len) + + + +To receive a message the application calls cyg_can_recv(). +This function receives one single event from a device. The desired size +of data to receive is contained in *len and the +actual size obtained will be returned in the same place. A pointer to +a cyg_can_event is contained in *buf. +No manipulation of the data is performed before being transferred. +Again, this buffering is completely configurable. On return, +*len contains sizeof(cyg_can_event). + + + +It is possible to configure the read call to be blocking (default) or +non-blocking. Non-blocking mode requires both the configuration option +CYGOPT_IO_CAN_SUPPORT_NONBLOCKING to be enabled, +and the specific device to be set to non-blocking mode for reads +(see cyg_io_set_config()). 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 -EAGAIN and the caller must +try again. + + + +It is possible to configure the write call to be non-blocking with timeout. +None-blocking mode with timeout requires the configuration option +CYGOPT_IO_CAN_SUPPORT_NONBLOCKING and +CYGOPT_IO_CAN_SUPPORT_TIMEOUTS 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 +cyg_io_set_config()). 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, -EINTR +is returned and the caller must try again. + + + +If a event was sucessfully received, the function returns ENOERR. + +
+ + +
+CAN Events + + +The CAN driver uses cyg_can_event structures to +pass events from hardware device driver to the generic CAN driver. +A cyg_can_event provides a generic device +independent type for handling CAN events that may occur. + + + +typedef struct cyg_can_event_st +{ + cyg_uint32 timestamp; + cyg_can_message msg; + cyg_uint16 flags; +} cyg_can_event; + + + +The structure contains the following fields: + + + + + cyg_uint32 timestamp + +If the hardware CAN device driver supports timestamps then this field may +contain a timestamp value for an event that occured. + + + + cyg_can_message msg + +CAN message. The msg field contains a CAN message if an RX or TX event +occured. If another type of event occured, +the data field of +the msg may contain additional event +specific data. + + + + cyg_uint16 flags + +Event flags. The flags field contains 16 bits that +indicate which kind of events occured. + + + + + +The following events are supported and after receiving an event the +application should check the flag field against these values: + + + +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; + + + +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 CYGNUM_CAN_EVENT_RX +is set then also the CYGNUM_CAN_EVENT_OVERRUN_RX +may be set if the received message caused an RX overrun. + + + +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 +CYGNUM_CAN_EVENT_OVERRUN_RX flag will be set for this +new message that caused overwriting of the old one. The +CYGNUM_CAN_EVENT_OVERRUN_RX flag will be set also if +a overrun occures in hardware message buffers of the CAN device. + + + +Example code for receiving one single CAN event: + + + +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 +} + +
+ + +
+cyg_io_get_config + + +cyg_io_get_config(handle, key, buf, len) + + + +This function is used to obtain run-time configuration about a device. +The type of information retrieved is specified by the key. +The data will be returned in the given buffer. The value of +*len 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 *len. The appropriate key values are all listed +in the file <cyg/io/config_keys.h>. + + + +The following config keys are currently supported: + + + +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 + +
+ +
+cyg_io_set_config + + +cyg_io_set_config(handle, key, buf, len) + + + +This function is used to manipulate or change the run-time configuration +of a device. The type of information is specified by the key. +The data will be obtained from the given buffer. The value of +*len 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 +<cyg/io/config_keys.h>. + + + +The following config keys are currently supported: + + + +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 + +
+
+ +
+Runtime Configuration + + +Runtime configuration is achieved by exchanging data structures with the +driver via the cyg_io_set_config() and +cyg_io_get_config() functions. + + +
+Device configuration + + +typedef struct cyg_can_info_st { + cyg_can_baud_rate_t baud; +} cyg_can_info_t; + + + +Device configuration is achieved by by exchanging +cyg_can_info_t data structures with the driver +via the cyg_io_set_config() and +cyg_io_get_config() functions using the config keys +CYG_IO_GET_CONFIG_CAN_INFO and +CYG_IO_SET_CONFIG_CAN_INFO. +The field baud contains a baud rate selection. +This must be one of the following values: + + + +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 + +
+ +
+Timeout configuration + + +typedef struct cyg_can_timeout_info_st +{ + cyg_uint32 rx_timeout; + cyg_uint32 tx_timeout; +} cyg_can_timeout_info_t; + + + +Timeout configuration is achieved by by exchanging +cyg_can_timeout_info_t data structures with the +driver via the cyg_io_set_config() and +cyg_io_get_config() functions using the config keys +CYG_IO_SET_CONFIG_CAN_TIMEOUT and +CYG_IO_SET_CONFIG_CAN_TIMEOUT. + + + + + cyg_uint32 rx_timeout + +Timeout for cyg_io_read calls. + + + + cyg_uint32 tx_timeout + +Timeout for cyg_io_write calls. + + + + + +Timeout runtime configuration is supported if the configuration options +CYGOPT_IO_CAN_SUPPORT_NONBLOCKING +and CYGOPT_IO_CAN_SUPPORT_TIMEOUTS are enabled. + +
+ +
+Reading buffer configuration + + +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; + + + +CYG_IO_GET_CONFIG_CAN_BUFFER_INFO - 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 +cyg_can_message objects in buffer and the current number of +cyg_can_message objects occupied in the buffer. +For the receive buffer it returns the total number of +cyg_can_event objects in receive buffer and the current +number of cyg_can_event 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. + + + + + cyg_uint32 rx_bufsize + +Total number of cyg_can_event buffers in receive queue. + + + + cyg_uint32 rx_count + +Current number of cyg_can_event buffers occupied in receive queue. + + + + cyg_uint32 tx_bufsize + +Total number of cyg_can_message buffers in transmit queue. + + + + cyg_uint32 rtx_count + +Current number of cyg_can_message buffers occupied in transmit queue. + + + +
+ + +
+Reading hardware description information + + +typedef struct cyg_can_hdi_st +{ + cyg_uint8 support_flags; + cyg_uint8 controller_type; +} cyg_can_hdi; + + + +CYG_IO_GET_CONFIG_CAN_HDI - 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 +cyg_can_hdi is defined. + + + + + cyg_uint8 support_flags + +Contains information about the capabilities of the used CAN hardware. + + + + cyg_uint8 controller_type + +A number that identifies the CAN controller type. + + + + + +The following flags are available in the field support_flags: + + + +| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | ++-------+-------+-------+-------+-------+-------+-------+-------+ +| res | res | res |timest.|SW-Filt|FullCAN| Frametype | + + + + + Frametype + +Bit 0 and Bit 1 of the structure describe the possibilities of the CAN +controller. The following values are defined: + +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 + + + + + FullCAN + +If the Bit 2 - CYGNUM_CAN_HDI_FULLCAN - is set to one, +the CAN controller supports more than one message buffer. + + + + SW-Filter + +If Bit 3 - CYGNUM_CAN_HDI_FILT_SW - is set to one then +the CAN driver supports some kind of software message filtering. + + + + Timestamp + +If Bit 4 - CYGNUM_CAN_HDI_TIMESTAMP - is set to one then +the CAN hardware supports timestamps for CAN messages + + + +
+ +
+Reading hardware message buffer configuration + +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; + + + +CYG_IO_GET_CONFIG_CAN_MSGBUF_INFO - If the CAN hardware supports +more than one message buffer for reception of CAN messages (flag +CYGNUM_CAN_HDI_FULLCAN is set while reading hardware description +interface with CYG_IO_GET_CONFIG_CAN_HDI) then this function +reads the number of message buffers the CAN hardware supports and the number of +free message buffers. + + + + + cyg_uint8 count + +Counts the number of message buffers supported by the device. + + + + cyg_uint8 free + +Contains the number of free message buffers. The free message buffers are +available for setting up remote buffers (CYG_IO_SET_CONFIG_CAN_REMOTE_BUF) +and message filters (CYG_IO_SET_CONFIG_CAN_FILTER_MSG). + + + +
+ +
+Reading state of CAN hardware + + +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; + + + +CYG_IO_GET_CONFIG_CAN_STATE - This function retrieves the +present state of the CAN controller. Possible values are defined in the +cyg_can_state enumeration. + +
+ + +
+Changing mode of CAN hardware + + +CYG_IO_SET_CONFIG_CAN_MODE - This function changes +the operating mode of the CAN controller. The identifiers for the different +operating modes are defined in the cyg_can_mode enumeration. + + + +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; + + + + + 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. + + + + + +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 CYGNUM_CAN_EVENT_LEAVING_STANDBY event will be +inserted into receive message buffer or +the CYGNUM_CAN_EVENT_LEAVING_STANDBY flag will be +set for the message that caused wake up of CAN hardware. + +
+ +
+Flush or drain buffers + + +CYG_IO_SET_CONFIG_CAN_OUTPUT_DRAIN - 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. + + + +CYG_IO_SET_CONFIG_CAN_OUTPUT_FLUSH - This function +discards any buffered output for the device. + + + +CYG_IO_SET_CONFIG_CAN_INPUT_FLUSH - This function +discards any buffered input for the device. + +
+ +
+Configuring blocking/non-blocking calls + +By default all calls to cyg_io_read() +and cyg_io_write() are blocking calls. The config +keys + + + +CYG_IO_SET_CONFIG_READ_BLOCKING +CYG_IO_SET_CONFIG_WRITE_BLOCKING + + + +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 -EAGAIN. + + + +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 -EINTR. If +the read/write operation succeeds during the timed wait then the +functions return succesfully with +ENOERR. + + + +To query if cyg_io_read() +and cyg_io_write() are blocking or non-blocking +you can use the config keys + + + +CYG_IO_GET_CONFIG_READ_BLOCKING +CYG_IO_GET_CONFIG_WRITE_BLOCKING + +
+ +
+Message buffer management + + +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. + + + +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 cyg_io_set_config() with the config key + + + +CYG_IO_SET_CONFIG_CAN_MSGBUF + + + +and by exchanging cyg_can_msgbuf_cfg data structures. + + + +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; + + + + cyg_can_msgbuf_cfg_id cfg_id + The cfg_id field +contains the configuration ID that tells the driver what to do with a +message buffer. + + + + cyg_can_msgbuf_handle handle + +Contains a reference to a certain message buffer. + + + + cyg_can_message msg + +Required for configuration of message buffer parameters. + + + + + +The following configuration identifiers are supported: + + + +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 + + + + + CYGNUM_CAN_MSGBUF_RESET_ALL + +Clears alle message buffers - no message will be received and all remote buffers are deleted. + + + + CYGNUM_CAN_MSGBUF_RX_FILTER_ALL + +Configure 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 (remote buffer handle required). + + + + + +Example code for resetting all message buffers: + + + +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 +} + +
+ + +
+Remote frame response buffer configuration + + +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. + + + +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. + + + +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. + + + +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 cyg_can_remote_buf data structures with the +driver via the cyg_io_set_config() function using +the config key CYG_IO_SET_CONFIG_CAN_MSGBUF. Once +the buffer is initialized, the CAN data can be changed at any time by +the application. + + + +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; + + + + cyg_can_msgbuf_cfg_id cfg_id + +The cfg_id field contains the configuration ID that tells the driver what to do with +a message buffer (CYGNUM_CAN_MSGBUF_REMOTE_BUF_ADD or +CYGNUM_CAN_MSGBUF_REMOTE_BUF_WRITE). + + + + cyg_can_msgbuf_handle handle + +If there is no buffer initialized for this data, the value of the handle field need to be set to +CYGNUM_CAN_MSGBUF_INIT. After the call to cyg_io_set_config() +the handle field contains a valid remote buffer handle ( >= 0) or the value +CYGNUM_CAN_MSGBUF_NA ( < 0) if no free buffer is available. + + + + cyg_can_message msg + +The CAN frame that should be transmitted in response to a remote frame. + + + + + +Example code for setting up a remote response buffer: + + + +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 +} + +
+ + +
+Message filter configuration + + +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. + + + +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. + + + +In order to add a message filter, a message buffer need to be +initialized. This is achieved by +exchanging cyg_can_filter data structures with the driver +via the cyg_io_set_config() function using the +config key CYG_IO_SET_CONFIG_CAN_MSGBUF. Once the +buffer is initialized, the CAN hardware can receive messages with the +identifier of the filter. + + + +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; + + + + + cyg_can_msgbuf_cfg_id cfg_id + +The cfg_id field contains the configuration ID that tells the driver what to do with +a message buffer. + + + + cyg_can_msgbuf_handle handle + +After the call to cyg_io_set_config() the handle field contains a valid value +( >= 0) or the value CYGNUM_CAN_MSGBUF_NA ( < 0) if no free buffer is available. + + + + cyg_can_message msg + +The fields id and ext of the msg +configure the type of message to receive by a certain message filter. + + + + + +Before adding message filters the device should be stopped and after +configuration it should be set into operational mode again. + + + +Example code for setting up a message filter: + + + +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 +} + +
+ + +
+Message filter deactivation + + +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: + + + +CYGNUM_CAN_MSGBUF_RX_FILTER_ALL + + + +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. + + + +Example code for deactivation of message filtering: + + + +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"); +} + +
+
+
+ + +Configuration + + +The CAN subsystem has a number of configuration options. + + + + + cdl_interface CYGINT_IO_CAN_TIMESTAMP + +A hardware device driver that supports timestamps should implement this interface. + + + + cdl_option CYGOPT_IO_CAN_SUPPORT_TIMESTAMP + +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. + + + + cdl_option CYGOPT_IO_CAN_TX_EVENT_SUPPORT + + 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. + + + + cdl_option CYGOPT_IO_CAN_SUPPORT_NONBLOCKING + + +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. + + + + cdl_option CYGNUM_IO_CAN_DEFAULT_TIMEOUT_READ + +The initial timeout value in clock ticks for cyg_io_read() calls. + + + + cdl_option CYGNUM_IO_CAN_DEFAULT_TIMEOUT_WRITE + The initial timeout value in clock ticks +for cyg_io_write() calls. + + + + + + + +Writing a CAN hardware device driver + + +A CAN driver is nothing more than a named entity that supports the +basic I/O functions - read, write, get config, and set config. The +device driver uses and manages interrupts from the device. While the +interface is generic and device driver independent, the actual driver +implementation is completely up to the device driver designer. + + + +That said, the reason for using a device driver is to provide access +to a CAN device from application code in as general purpose a fashion +as reasonable. Most driver writers are also concerned with making this +access as simple as possible while being as efficient as possible. + + + +Like other device drivers the CAN device driver is concerned with the +movement of information - the CAN messages. In order to make the most +efficient use of system resources, interrupts are used. This will +allow other application processing to take place while the data +transfers are under way, with interrupts used to indicate when various +events have occurred. For example, a CAN device typically generates an +interrupt after a CAN message has been sent or a CAN message has been +received by a CAN hardware message buffer. It makes sense to allow +further application processing while the data is being sent since this +can take quite a long time. The interrupt can be used to allow the +driver to send a CAN message as soon as the current one is complete, +without any active participation by the application code. + + + +The main building blocks for CAN device drivers are found in the +include files +<cyg/io/devtab.h> and <cyg/io/can.h> + + + +Like many other device drivers in eCos, CAN device drivers are described by a device +table entry, using the cyg_devtab_entry_t type. The entry should be created using +the DEVTAB_ENTRY() macro. + + + +
+How to Write a CAN Hardware Interface Driver + + +The standard CAN driver supplied with eCos is structured as a hardware +independent portion and a hardware dependent interface module. To add +support for a new CAN device, the user should be able to use the +existing hardware independent portion and just add their own interface +driver which handles the details of the actual device. The user should +have no need to change the hardware independent portion. + + + +The interfaces used by the CAN driver and CAN implementation modules +are contained in the file <cyg/io/can.h>. + + +
+DevTab Entry + + +The interface module contains the devtab entry (or entries if a single +module supports more than one interface). This entry should have the +form: + + + +DEVTAB_ENTRY(<<module_name>>, + <<device_name>>, + 0, + &can_devio, + <<module_init>>, + <<module_lookup>>, + &<<can_channel>> + ); + + + +Arguments + + module_name + The "C" label for this devtab entry + + + device_name + The "C" string for the + device. E.g. /dev/can0. + + + can_devio + The table of I/O functions. This set is defined in + the hardware independent CAN driver and should be used. + + + + module_init + The hardware module initialization function. + + + module_lookup + The device lookup function. This function + typically sets up the CAN device for actual use, turning on + interrupts, configuring the message buffers, etc. + + + can_channel + This table (defined below) contains the interface + between the interface module and the CAN driver proper. + + + + +Example devtab entry for Motorola FlexCAN device driver: + + + +DEVTAB_ENTRY(flexcan_devtab, + CYGDAT_DEVS_CAN_MCF52xx_FLEXCAN0_NAME, + 0, // Does not depend on a lower level interface + &cyg_io_can_devio, + flexcan_init, + flexcan_lookup, // CAN driver may need initializing + &flexcan_can0_chan + ); + +
+ + +
+CAN Channel Structure + + +Each CAN device must have a “CAN channel”. +This is a set of data which describes all operations on the device. +It also contains buffers, etc. The CAN channel is created by the macro: + + + +CAN_CHANNEL_USING_INTERRUPTS(l, funs, dev_priv, baud, + out_buf, out_buflen, + in_buf, in_buflen) + + + + Arguments + + l + The "C" label for this structure. + + + funs + The set of interface functions (see below). + + + dev_priv + A placeholder for any device specific data for + this channel. + + + baud + The initial baud rate value + (cyg_can_baud_rate_t). + + + out_buf + Pointer to the output buffer + + + out_buflen + The length of the output buffer. + + + in_buf + pointer to the input buffer. + + + in_buflen + The length of the input buffer. + + + + +Example CAN channel implementation for Motorola FlexCAN device driver: + + + +CAN_CHANNEL_USING_INTERRUPTS( + flexcan_can0_chan, + flexcan_lowlevel_funs, + flexcan_can0_info, + CYG_CAN_BAUD_RATE(CYGNUM_DEVS_CAN_MCF52xx_FLEXCAN0_KBAUD), + flexcan_can0_txbuf, CYGNUM_DEVS_CAN_MCF52xx_FLEXCAN0_QUEUESIZE_TX, + flexcan_can0_rxbuf, CYGNUM_DEVS_CAN_MCF52xx_FLEXCAN0_QUEUESIZE_RX +); + + + +The interface from the hardware independent driver into the hardware +interface module is contained in the funs +table. This is defined by the macro: + +
+ +
+CAN Lowlevel Functions Structure + + +CAN_LOWLEVEL_FUNS(l, putmsg, getevent, get_config, set_config, start_xmit, stop_xmit) + + + + Arguments + + l + The "C" label for this structure. + + + putmsg + + + bool (*putmsg)(can_channel *priv, cyg_can_message *pmsg, void *pdata) + + + This function sends one CAN message to the interface. It should + return true if the message is actually + consumed. It should return false if there is + no space in the interface + + + + + getevent + + + bool (*getevent)(can_channel *priv, cyg_can_event *pevent, void *pdata) + + + This function fetches one event from the interface. + + + + + get_config + + + Cyg_ErrNo (*get_config)(can_channel *priv, cyg_uint32 key, const void *xbuf, cyg_uint32 *len) + + + This function is used to query the configuration of a CAN channel. + + + + + set_config + + + Cyg_ErrNo (*set_config)(can_channel *priv, cyg_uint32 key, const void *xbuf, cyg_uint32 *len) + + + This function is used to change configuration of a CAN channel. + + + + + start_xmit + void (*start_xmit)(can_channel *priv) + + Enable the transmit channel and turn on transmit interrupts. + + + + + stop_xmit + + void (*stop_xmit)(can_channel *priv) + Disable the transmit channel and turn transmit interrupts off. + + + + + +Example implementation of low level function structure for Motorola FlexCAN +device driver: + + + +CAN_LOWLEVEL_FUNS(flexcan_lowlevel_funs, + flexcan_putmsg, + flexcan_getevent, + flexcan_get_config, + flexcan_set_config, + flexcan_start_xmit, + flexcan_stop_xmit + ); + +
+ +
+Callbacks + + +The device interface module can execute functions in the +hardware independent driver via chan->callbacks. +These functions are available: + + + +void (*can_init)(can_channel *chan) + + +This function is used to initialize the CAN channel. + + +void (*xmt_msg)(can_channel *chan, void *pdata) + + + +This function would be called from an interrupt handler after a +transmit interrupt indicating that additional messages may be +sent. The upper driver will call the putmsg +function as appropriate to send more data to the device. + + + +void (*rcv_event)(can_channel *chan, void *pdata) + + + +This function is used to tell the driver that a message has arrived +at the interface or that an event has occurred. This function is typically +called from the interrupt handler. + +
+ +
+
+ +