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
[...]
 
/* 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.

Free a requested CAN
[...]
 
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.

Modify the bitrate
#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

Modify the control mode
[...]
/* 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.

Modify the control mode
[...]
 
/* 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:

Modify the bittiming
[...]
/* 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.

Initialize the CAN interface
#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:

  • CAN_STATE_ERROR_ACTIVE

  • CAN_STATE_ERROR_WARNING

  • CAN_STATE_ERROR_PASSIVE

  • CAN_STATE_BUS_OFF

  • CAN_STATE_STOPPED

  • CAN_STATE_SLEEPING

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:

  • bus_error /* Bus errors */

  • error_warning /* Changes to error warning state */

  • error_passive /* Changes to error passive state */

  • bus_off /* Changes to bus off state */

  • arbitration_lost /* Arbitration lost errors */

  • restarts /* CAN controller re-starts */

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.

Get CAN statistics
[...]
/* 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.

Manage 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.

Send CAN frames
[...]
/* 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.

Receive CAN frames
[...]
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.

CAN frame operations
[...]
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.

Error handle operations
[...]
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.