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.

The function returns a pointer to can_if_t on success, or NULL on error.

can_if_t *ldx_can_request(
		unsigned int can_iface);

Requests a CAN interface by its index.

The function returns a pointer to can_if_t on success, or 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 do not 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.

The function returns EXIT_SUCCESS on success, or EXIT_FAILURE on failure.

Free a requested CAN
can_if_t *can = ...;

/* [...] */

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.

The function returns CAN_ERR_NONE on success, or an error code on error.

Modify the bitrate
#define BITRATE  125000

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.

The function returns CAN_ERR_NONE on success, or an error code on 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
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.

The function returns CAN_ERR_NONE on success, or an error code or error.

Modify the control mode
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
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.

The function returns CAN_ERR_NONE on success, or an 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
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, and EXIT_FAILURE otherwise.

Initialize the CAN interface
#define BITRATE...

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, or an error code on error.

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, or an error code on error.

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

int ldx_can_restart(can_if_t *cif);

Restart the specified CAN interface.

Manage CAN interface
can_if_t *can_if = ...

/* [...] */

ldx_can_start(can_if);

/* [...] */

ldx_can_stop(can_if);

/* [...] */

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.

The function returns EXIT_SUCCESS on success, or EXIT_FAILURE otherwise.

Send CAN frames
can_if_t *can_if = ...

/* Fill the fields of the frame */
frame.can_id = ...
frame.len = ...
frame.data = ...

/* [...] */

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

The function returns EXIT_SUCCESS on success, EXIT_FAILURE otherwise.

Receive CAN frames
static void can_rx_callback(struct canfd_frame *frame, struct timeval *tv)
{
	printf("CAN frame received\n");
}

/* [...] */

int main (void)
{
	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
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.

The function returns the id of the provided frame.

CAN frame operations
can_if_t *can_if = ...
struct canfd_frame frame;

/* [...] */

/* 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
static void can_error_callback(int error, void *data)
{
	printf("The following error occurs in the CAN %s", ldx_can_strerror(error));
}

/* [...] */

int main (void)
{
	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:

# ifconfig canX down