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 |
---|---|
|
Returns a can_if_t pointer based on the interface name. The function returns a pointer to |
|
Requests a CAN interface by its index. The function returns a pointer to |
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 |
---|---|
|
Free a CAN interface. The function returns |
[...]
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 |
---|---|
|
Initialize the selected CAN interface with the selected bitrate. The function returns |
#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 |
---|---|
|
Initialize the selected CAN interface with the selected control mode mask. The function returns |
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 |
---|---|
|
Set the timeout to restart the communication on error on ms. The function returns |
[...]
/* 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 timing options for the CAN interface with the following function:
Function | Description |
---|---|
|
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. The function returns |
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 |
---|---|
|
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 |
---|---|
|
Initialize the selected can interface with the given configuration in cfg. It returns |
#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 |
---|---|
|
In the
The function returns |
|
In the
The function returns |
|
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 |
---|---|
|
Start the CAN interface for communication. |
|
Stop the specified CAN interface. |
|
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 |
---|---|
|
Send a frame through the CAN interface. The function returns |
[...]
/* 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.
Function | Description |
---|---|
|
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. |
|
Unregister the reception callback (cb). The function returns |
[...]
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 frame operations
You can use the following operations to get additional information from the CAN frame:
Function | Description |
---|---|
|
Check whether the provided frame has extended id. It returns True on extended id, False otherwise. |
|
Get the id of the provided frame. The function 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 |
---|---|
|
Register a handle to be executed with every error. |
|
Unregister the error handle. |
|
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 examples are included in Digi Embedded Yocto. Go to GitHub to see the source code.
The APIX CAN application configures the CAN interface, so you must make sure the CAN network device is stopped before running the application:
|