A CAN (Controller Area Network) is an standard bus designed to allow microcontrollers and devices to communicate with each other in applications without a host computer. It is a message-based protocol used in automotion but it is also used in many other scenarios.
The ConnectCore platforms have several CAN interfaces. You can find more information in Hardware reference manuals and Controller Area Network (CAN).
Digi adds an API to Linux to manage these CAN buses. To use this API, include the following header file:
#include <libdigiapix/can.h>
With this API, you can configure and communicate with other CAN devices connected to the bus.
Request a CAN
You can request a CAN with one of the following functions:
Function | Description |
---|---|
can_if_t *ldx_can_request_by_name(const char * const can_iface) |
Returns a can_if_t pointer based on the interface name. It returns a pointer to can_if_t on success, NULL on error. |
can_if_t *ldx_can_request(unsigned int can_iface); |
Requests a CAN interface by its index. It returns a pointer to can_if_t on success, NULL on error. |
The requested CAN must be freed once it is no longer needed. See Free a CAN. |
Both functions may fail and return NULL for the following reasons:
-
The provided CAN interfaces don´t exist in the system.
-
The API encountered problems allocating memory to initialize the CAN. Your system may have run out of resources.
Once you have requested the CAN, you can receive and send frames
[...]
/* Request a CAN using its name */
can_if_t *can_if_0 = ldx_can_request_by_name("can0");
/* Request a CAN using its index *can1*/
can_if_t *can_if_1 = ldx_can_request(1);
printf("The CAN 0 name is %s\n", can_if_0->name);
printf("The CAN 1 name is %s\n", can_if_1->name);
[...]
Free a CAN
You must free a requested can when it is no longer required. To do so, use the ldx_can_free function.
Function | Description |
---|---|
int ldx_can_free(can_if_t *cif) |
Free a CAN interface. It returns EXIT_SUCCESS on success, EXIT_FAILURE otherwise. |
[...]
can_if_t *can = ...;
[...]
/* Free CAN once it is no longer required */
ldx_can_free(can);
[...]
Configure the CAN interface
You can configure several aspects of a CAN interface, including the bitrate, control mode, and bit timing:
Configure the CAN bitrate
You can manage and change the bitrate of the CAN interface with the following function.
Function | Description |
---|---|
int ldx_can_set_bitrate(can_if_t *cif, uint32_t bitrate) |
Initialize the selected CAN interface with the selected bitrate. It returns CAN_ERR_NONE on success, the error code or error. |
#define BITRATE 125000
[...]
/* Request a CAN interface */
can_if_t *can_if =...
ldx_can_set_bitrate(can_if, BITRATE);
printf("The current bitrate for %s is d\n", can_if->name, BITRATE);
[...]
Configure the CAN control mode
You can manage and change the control mode of the CAN interface with the following function.
Function | Description |
---|---|
int ldx_can_set_ctrlmode(can_if_t *cif, struct can_ctrlmode *cm) |
Initialize the selected CAN interface with the selected control mode mask. It returns CAN_ERR_NONE on success, the error code or error. |
The mask accepts the following values:
-
CAN_CTRLMODE_LOOPBACK
-
CAN_CTRLMODE_LISTENONLY
-
CAN_CTRLMODE_3_SAMPLES
-
CAN_CTRLMODE_ONE_SHOT
-
CAN_CTRLMODE_BERR_REPORTING
[...]
/* Request a CAN interface */
can_if_t *can_if =...
can_ctrlmode cm;
/* The CAN interface is configured with these two settings */
cm.mask = CAN_CTRLMODE_ONE_SHOT | CAN_CTRLMODE_BERR_REPORTING;
/* But we only enable this one */
cm.flags = CAN_CTRLMODE_BERR_REPORTING;
ldx_can_set_ctrlmode(can_if, &cm);
printf("The current flags for %s interface are %s\n", can_if->name, can_if->cfg->cm->flags);
[...]
Configure the CAN restart
You can manage and change the restart time of the CAN interface with the following function:
Function | Description |
---|---|
int ldx_can_set_restart_ms(can_if_t *cif, uint32_t restart_ms) |
Set the timeout to restart the communication on error on ms. It returns CAN_ERR_NONE on success, the error code or error. |
[...]
/* Request a CAN interface */
can_if_t *can_if =...
/* The CAN interface is configured with 1000 ms (1s) to restart on error */
ldx_can_set_restart_ms(can_if, 1000);
printf("The current restart time for %s interface is %d\n", can_if->name, can_if->cfg->restart_ms);
[...]
Configure the CAN bit timming
You can manage and change the timming options for the CAN interface with the following function:
Function | Description |
---|---|
int ldx_can_set_bit_timing(can_if_t *cif, struct can_bittiming *bt) |
This function sets the bit timing configuration of the specified can interface. Normally, this is not required as the can driver computes the proper bit timing information for the selected bitrate. It returns CAN_ERR_NONE on success, the error code on error. |
The bittiming struct has the following parameters:
-
bitrate: bitrate in bits/second
-
sample_point: Sample point in one-tenth of a percent
-
tq: Time quanta (TQ) in nanoseconds
-
prop_seg: Propagation segment in TQs
-
phase_seg1: Phase buffer segment 1 in TQs
-
phase_seg2: Phase buffer segment 2 in TQs
-
sjw: Synchronization jump width in TQs
-
brp: bitrate prescaler
You can adjust the parameters of your CAN communication with these parameters:
[...]
/* Request a CAN interface */
can_if_t *can_if =...
struct can_bittiming bt;
/* Fill the fields with the desired values */
bt.bitrate = ...
bt.sample_point = ...
[...]
ldx_can_set_bit_timing(can_if, &bt);
[...]
You can also initialize the CAN interface without providing a cfg struct.
Function | Description |
---|---|
void ldx_can_set_defconfig(can_if_cfg_t *cfg) |
Initialize the selected cfg struct with a default configuration. |
Because this function sets a default configuration, you do not need to provide any configuration values other than bitrate. |
Once the configuration struct is ready you can use the following function to initialize the interface:
Function | Description |
---|---|
int ldx_can_init(can_if_t *cif, can_if_cfg_t *cfg) |
Initialize the selected can interface with the given configuration in cfg. It returns EXIT_SUCCESS on success, EXIT_FAILURE otherwise. |
#define BITRATE...
[...]
/* Request a CAN interface */
can_if_t *can_if =...
struct can_if_cfg_t cfg;
/* Set a default configuration and init the CAN interface */
ldx_can_set_defconfig(&cfg);
ldx_can_set_bitrate(can_if, BITRATE);
ldx_can_init(can_if, &cfg);
[...]
Get CAN statistics
Once the CAN interface is running you can get statistics about the use of the interface with the following functions:
Function | Description |
---|---|
int ldx_can_get_state(can_if_t *cif, enum can_state *state) |
In the state variable you can find the state of the interface The available CAN states are:
The function returns CAN_ERR_NONE on success, error code otherwise |
int ldx_can_get_dev_stats(can_if_t *cif, struct can_device_stats *cds) |
In the cds variable you can find the stats of the interface The available can stats are:
The function returns CAN_ERR_NONE on success, error code otherwise |
int ldx_can_get_bit_error_counter(can_if_t *cif, struct can_berr_counter *bc) |
Retrieve the bit error counter for the reception and transmission. |
[...]
/* Request a CAN interface */
can_if_t *can_if = ...
enum can_state state;
struct can_device_stats stats;
struct can_berr_counter bc;
[...]
ldx_can_get_dev_stats(can_if, &stats);
ldx_can_get_state(can_if, &state);
ldx_can_get_bit_error_counter(can_if, &bc);
printf("The current state of CAN%s is %d\n", can_if->name, state);
printf("The current stat of bus_error is of CAN%s is %Lu\n", can_if->name, stats.bus_error);
printf("These are the fails in the bus %s in rx:%d tx:%d\n", can_if->name, bc.rxerr, bc.txerr);
[...]
Manage CAN interface
You must open the CAN interface before using it for communication. Use the following functions to manage and control the interface:
Function | Description |
---|---|
int ldx_can_start(can_if_t *cif) |
Start the CAN interface for communication. |
int ldx_can_stop(can_if_t *cif) |
Stop the specified CAN interface. |
ldx_can_restart(can_if_t *cif) |
Restart the specified CAN interface. |
[...]
/* Request a CAN interface */
can_if_t *can_if = ...
[...]
/* Start the CAN interface */
ldx_can_start(can_if);
[...]
/* Stop the CAN interface */
ldx_can_stop(can_if);
[...]
/* Restart the CAN interface */
ldx_can_restart(can_if);
Send CAN frames
Once the CAN interface is configured and opened, you can send CAN frames through it. However, you must build a frame before sending it. To do so, use struct canfd_frame with the following values:
Field | Description |
---|---|
canid_t can_id |
32 bit CAN_ID + EFF/RTR/ERR flags. |
__u8 len |
Frame payload length in byte. |
__u8 flags |
Additional flags for CAN FD. |
__u8 data |
Data to transfer. |
When the struct is filled, send it through the CAN interface with the following function:
Function | Description |
---|---|
int ldx_can_tx_frame(can_if_t *cif, struct canfd_frame *frame) |
Send a frame through the CAN interface. It returns EXIT_SUCCESS on success, EXIT_FAILURE otherwise. |
[...]
/* Request a CAN interface */
can_if_t *can_if = ...
/* Fill the fields of the frame */
frame.can_id = ...
frame.len = ...
frame.data = ...
[...]
/* Send the frame */
ldx_can_tx_frame(can_if, &frame)
Receive CAN frame
To receive frames, use the following function to register a callback that will be executed each time a frame is received. In order to do that, you can use the following function:
Function | Description |
---|---|
int ldx_can_register_rx_handler(can_if_t *cif, const ldx_can_rx_cb_t cb, struct can_filter *filters, int nfilters) |
Register a callback (cb) for the reception. The system executes a callback every time a frame is received in the CAN interface. It returns CAN_ERR_NONE on success, the error code or error. |
int ldx_can_unregister_rx_handler(can_if_t *cif, const ldx_can_rx_cb_t cb) |
Unregister the reception callback (cb). It returns EXIT_SUCCESS on success, EXIT_FAILURE otherwise. |
[...]
struct canfd_frame frame;
static void can_rx_callback(struct canfd_frame *frame, struct timeval *tv)
{
printf("CAN frame received\n");
}
[...]
/* Request a CAN interface */
can_if_t *can_if = ...
struct can_filter deffilter = {
.can_id = 0,
.can_mask = 0,
};
[...]
ldx_can_register_rx_handler(can_if, can_rx_callback, &deffilter, 1);
CAN frames operations
You can use the following operations to get additional information from the CAN frame:
Function | Description |
---|---|
static inline bool ldx_can_is_extid_frame(struct canfd_frame *frame) |
Check whether the provided frame has extended id. It returns True on extended id, False otherwise. |
static inline uint32_t ldx_can_get_id(struct canfd_frame *frame) |
Get the id of the provided frame. It returns the id of the provided frame. |
[...]
struct canfd_frame frame;
[...]
/* Request a CAN interface */
can_if_t *can_if = ...
[...]
/* After receiving some frames you can verify some params */
printf("The frame has %s id", ldx_can_is_extid_frame(&frame) ? "extended":"standard");
printf("The frame has the following id %d", ldx_can_get_id(&frame));
CAN error operations
Detect errors using the following functions:
Function | Description |
---|---|
int ldx_can_register_error_handler(can_if_t *cif, const ldx_can_error_cb_t cb) |
Register a handle to be executed with every error. |
int ldx_can_unregister_error_handler(can_if_t *cif, const ldx_can_error_cb_t cb) |
Unregister the error handle. |
char * ldx_can_strerror(int error) |
It returns a string describing the error. |
[...]
struct canfd_frame frame;
static void can_error_callback(int error, void *data)
{
printf("The following error occurs in the CAN %s", ldx_can_strerror(error));
}
[...]
/* Request a CAN interface */
can_if_t *can_if = ...
[...]
ldx_can_register_error_handler(can_if, can_error_callback);
[...]
ldx_can_unregister_error_handler(can_if, can_error_callback);
[...]
CAN example
In these examples you can see how to send and receive frames using the APIx.
In the apix-can-send-example you can configure the can frame with different parameters and send the frame using the CAN interface.
In the apix-can-recv-example you can configure the reception mask and listen to incoming frames in the CAN interface.
You can import these examples in Eclipse using the Digi Embedded Yocto plugin. For more information, see Create a new DEY sample project. These example are included in Digi Embedded Yocto. Go to GitHub to see the application source code.