Runtime configuration is achieved by exchanging data structures with the
driver via the cyg_io_set_config()
and
cyg_io_get_config()
functions.
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 |
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
.
rx_timeout
Timeout for cyg_io_read
calls.
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.
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.
rx_bufsize
Total number of cyg_can_event buffers in receive queue.
rx_count
Current number of cyg_can_event buffers occupied in receive queue.
tx_bufsize
Total number of cyg_can_message buffers in transmit queue.
rtx_count
Current number of cyg_can_message buffers occupied in transmit queue.
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.
support_flags
Contains information about the capabilities of the used CAN hardware.
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 | +-------+-------+-------+-------+--------+-------+-------+-------+ |ListenO|Mask F |Range F|timest.|autobaud|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.
autobaud
If Bit 3 - CYGNUM_CAN_HDI_AUTBAUD
- is set to one then
the CAN driver supports an autobaud feature.
Timestamp
If Bit 4 - CYGNUM_CAN_HDI_TIMESTAMP
- is set to one then
the CAN hardware supports timestamps for CAN messages.
Identifier Range filtering
If Bit 5 - CYGNUM_CAN_HDI_RANGE_FILTERING
- is set to one
then the CAN hardware supports message filtering based on identifier ranges.
Identifier Mask filtering
If Bit 6 - CYGNUM_CAN_HDI_MASK_FILTERING
- is set to one
then the CAN hardware supports message filtering based on identifier masks.
Listen Only mode
If Bit 7 - CYGNUM_CAN_HDI_LISTEN_ONLY
- is set to one
then the CAN hardware supports a 'listen-only' mode.
typedef struct cyg_can_msgbox_info_st { cyg_uint16 count; // number of message buffers available for this device cyg_uint16 free; // number of free message buffers } cyg_can_msgbuf_info; |
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.
count
Counts the number of message buffers supported by the device.
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
).
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.
typedef struct cyg_can_err_count_info_st { cyg_uint8 rx_err_count; cyg_uint8 tx_err_count; } cyg_can_err_count_info; |
Each CAN node maintains two error counters: the Transmit Error Counter (TEC)
and the Receive Error Counter (REC). There are several rules governing how
these counters are incremented and/or decremented.
CYG_IO_GET_CONFIG_CAN_ERR_COUNTERS
retrieves the present
value of both error counters (TEC and REC).
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 CYGNUM_CAN_MODE_CONFIG, // safe mode to add/delete message buffers CYGNUM_CAN_MODE_LISTEN_ONLY_ENTER, // set controller into listen only mode. CYGNUM_CAN_MODE_LISTEN_ONLY_EXIT // set controller out of listen only mode. } cyg_can_mode; |
Set controller into stop mode
Set controller into operational mode
Set controller into standby / sleep mode.
Set controller into a mode allowing modifying message buffers.
Make controller enter listen-only mode (if supported by hardware). In such a mode the CAN controller won't acknowledge the messages it sees on the bus. This mode can help to perform autobaud at application level if the underlying hardware does not support it directly. Depending on your CAN transceiver, such a mode may also be implemented by the transceiver.
Make controller exit of listen-only mode. The controller will acknowledge all messages it sees on the bus.
Before the hardware configuration of the device is changed, that means
if baud rate is changed or the message buffer and filter configuration
is changed, the CAN hardware should be set into stop or config mode
and if configuration is finished, then device should be set back into
operational mode. Before the device is set into standby mode, the
output buffers should be flushed or drained because transmission of a
CAN message may wake up the CAN hardware. If a received message wakes
up the CAN hardware from standby mode then
a 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.
You must also check with the CAN controller data sheet if an incoming message waking up the controller is fully received and processed by the controller, or if such a wake up message is lost.
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.
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 an event was received from RX buffer. If non-blocking calls
are enabled and there is no space in TX buffer or RX buffer is empty
then the function returns immediately
with -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 |
Full CAN controllers often support more than one message buffer. These message buffers are often configurable for transmission or reception of certain CAN messages or as a remote buffers. If a CAN hardware supports more than one message buffer then it is possible to configure the CAN hardware to receive only CAN messages with certain identifiers or to configure hardware support for remote buffers. If message filtering is done by hardware, the number of received CAN messages decreases and so also the time for processing received CAN messages and the memory required for buffering received messages decreases. This saves valuable memory and processing time.
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; |
cfg_id
The cfg_id
field
contains the configuration ID that tells the driver what to do with a
message buffer.
handle
Contains a reference to a certain message buffer.
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 |
Clears all message buffers - no message will be received and all remote buffers are deleted.
Configure driver for reception of all can messages
Add single message filter.
Add new remote response buffer.
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 } |
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; |
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
).
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.
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 } |
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; |
cfg_id
The cfg_id
field contains the configuration ID that tells the driver what to do with
a message buffer.
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.
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 } |
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"); } |
If the low level driver supports it, you can filter messages using identifier ranges. Such filtering is interesting if it is directly supported by the CAN controller hardware. Instead of waiting for a particular message identifier, the application can define one or more ranges of identifiers. If a received message has an identifier value (and type) matching a defined identifier range, then the message passes the filter and is made available to the application.
To add such a filter, use this configuration ID:
CYG_IO_SET_CONFIG_CAN_RANGE_FILTER |
The buffer argument given to cyg_io_set_config()
must point to an area holding the following structure:
typedef struct cyg_can_filter_range_cfg_st { cyg_can_id_type ext; // type of identifier concerned cyg_uint32 lower_id_bound; // lower bound identifier (included) cyg_uint32 upper_id_bound; // upper bound identifier (included) } cyg_can_filter_range_cfg; |
ext
Extended ID. If this field
is CYGNUM_CAN_ID_EXT
then the next two fields contains
29 bit extended ID. If ext
contains CYGNUM_CAN_ID_STD
then the next two fields
represent 11 bits identifiers.
lower_id_bound
Combined with upper_id_bound
an identifier range is
defined. All messages having an identifier of the type defined by
ext
and included in the range lower_id_bound
to upper_id_bound
will pass the filter. The identifiers
lower_id_bound
and upper_id_bound
are
included in the defined range.
upper_id_bound
Upper identifier value of the defined range.
If no free buffers or filters are available, -ENOSPC
is
returned.
If the low level driver supports it, you can filter messages using identifier masks. Such filtering is interesting if it is directly supported by the CAN controller hardware. Instead of waiting for a particular message identifier, the application can define one or more pair of identifier and mask. If a received message has an identifier value (and type) that, for each bit set of the mask, matches the corresponding bit in the provided identifier, then the message passes the filter and is made available to the application.
To add such a filter, use this configuration ID:
CYG_IO_SET_CONFIG_CAN_MASK_FILTER |
The buffer argument given to cyg_io_set_config()
must point to an area holding the following structure:
typedef struct cyg_can_filter_mask_cfg_st { cyg_can_id_type ext; // type of identifier concerned cyg_uint32 id; // identifier to use for filtering cyg_uint32 mask; // mask to apply for filtering } cyg_can_filter_mask_cfg; |
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.
id
Message ID. This is the ID to be matched with an incoming message, after
having considered the mask
field.
mask
Mask value. A message will pass the filter if, for each bit set in
mask
, the received message ID has its corresponding
bit equals to the corresponding bit in the id
field.
For instance let's suppose that the id
field is
0x05 (bits 0 and 2 are set) and the mask
field is
0x07 (bits 0, 1 and 2 are set). If an incoming message has an ID of
0x01: bit 0 matches since bit 0 is set in the mask and both the
incoming message and the id
field have a similar
value for bit 0. The message ID has its bit 1 set to 0, as
the id
field and the mask tells the controller to
check this bit: it passes too. However the message ID has its bit 2
unset, while bit 2 of the mask tells the controller to check bit
2. Bit 2 of the identifier isn't set in the id
field, hence this example message does not pass the filter.
If no free buffers or filters are available, -ENOSPC
is
returned.
By default application cannot get information about an event arriving
in the RX buffer until it calls
the cyg_io_read()
. Usually this leads applications
to use accessory threads to wait for new CAN events.
The CDL option CYGOPT_IO_CAN_SUPPORT_CALLBACK
allows application to use a callback on event arrival. It is
configured by passing a cyg_can_callback_cfg
data structure to the driver via
the cyg_io_set_config()
function using the config
key
CYG_IO_SET_CONFIG_CAN_CALLBACK
.
CYG_IO_SET_CONFIG_CAN_CALLBACK |
typedef void (*cyg_can_event_cb_t)(cyg_uint16, CYG_ADDRWORD); typedef struct cyg_can_callback_cfg_st { cyg_can_event_cb_t callback_func; // callback function cyg_can_event_flags_t flag_mask; // flags mask CYG_ADDRWORD data; // data passed to callback } cyg_can_callback_cfg; |
callback_func
Pointer to the callback function. The function will be called from DSR context so you should be careful to only call API functions that are safe in DSR context. The first parameter is a combination of event flags for events that have occurred. Second parameter is a user defined data pointer or value.
data
Additional user data that will be passed to callback function as a second parameter.
flag_mask
Should be set with a combination
of CYGNUM_CAN_EVENT_*
flags. If one of these
events happens, the callback function will be called, with the
actually event flags passed as a parameter. To disable the callback
function from being called set flag_mask
to 0. To
set all possible flags use the CYGNUM_CAN_EVENT_ALL
macro.
Instead of using a thread dedicated to reading CAN events, it is possible, if the CAN controller I/O handle was set in non-blocking mode for read operations, to have the callback function to read each event it is waiting for. However the callback function runs in DSR mode, so it must be carefully written to avoid any blocking call.
If you plan to have the callback function to perform read operations,
be aware that cyg_io_read()
retrieves events of
all kinds while the callback function is triggered only on events it
is expecting, as defined by the flag_mask
field. The side effect is that the callback function, if it is not
waiting for all events, may see its first parameter (the flag(s)
describing why the callback function is called) different from an
event it get from cyg_io_read()
.
For instance, let's suppose the callback function is expecting
only CYGNUM_CAN_EVENT_RX
events while the bus
activity triggers other kind of events, like
the CYGNUM_CAN_EVENT_WARNING_RX
event. It is
possible to have in the receive queue a first event of
type CYGNUM_CAN_EVENT_WARNING_RX
followed by a
second event of type CYGNUM_CAN_EVENT_RX
. In that
case, the callback function is triggered and have its first parameter
set to CYGNUM_CAN_EVENT_RX
exactly
when CYGNUM_CAN_EVENT_RX
occurs, but if the
callback function reads the event queue, it will first get
the CYGNUM_CAN_EVENT_WARNING_RX
event.
If the callback function is set to process all kind of events and
always call cyg_io_read()
to get each event, it
is possible to have a receive queue size of one event.
If the CAN controller does not provide message timestamps of its own,
or if the provided timestamps do not match your needs, the callback
function mechanism can be helpful since it is called from the DSR
processing the hardware related events. The callback function can
manage timestamps in the way that suits you the best however there is
a slight delay between an event related to the CAN bus activity occurs
and the time the callback function runs. If you implement your own
timestamps this way, pay also attention to what gives you the current
time. For instance the granularity
of cyg_current_time()
may not be accurate enough,
according to the clock resolution and your needs of accuracy.