Controlled Area Network (CAN)#

Hardware Interface#

Defined in namespace hal

#include <libhal/can.hpp>

class can#

Controller Area Network (CAN bus) hardware abstraction interface.

This interface does not provide APIs for CAN message hardware filtering. The hardware implementation for CAN message filter varies wildly across devices and thus a common API is infeasible. So we rely on the concrete classes, the implementations of this interface to provide APIs for setting the CAN filter for the specific hardware. Hardware filtering is a best effort with the resources available. It is often not possible to filter every possible ID in hardware that your application is interested in. Thus, must expect that the CAN message receive buffer.

This interface provides a means to interrupt on every message received. If this behavior is not desirable, consider hal::buffered_can instead.

Subclassed by hal::lpc40::can, hal::mock::can, hal::soft::inert_can, hal::stm32f1::can

Public Types

using id_t = std::uint32_t#

Can message ID type trait.

This was added for backwards API compatibility.

using handler = void(message_t const &p_message)#

Receive handler for can messages.

Public Functions

inline void configure(settings const &p_settings)#

Configure this can bus port to match the settings supplied.

Parameters:

p_settings – - settings to apply to can driver

Throws:

hal::operation_not_supported – - if the settings could not be achieved.

inline void bus_on()#

Transition the CAN device from “bus-off” to “bus-on”.

Can devices have two counters to determine system health. These two counters are the “transmit error counter” and the “receive error counter”. Transmission errors can occur when the device attempts to communicate on the bus and either does not get an acknowledge or sees an unexpected or erroneous signal on the bus during its own transmission. When transmission errors reach 255 counts, the device will go into the “bus-off” state.

In the “bus-off” state, the CAN peripheral can no longer communicate on the bus. Any calls to send() will throw the error hal::operation_not_permitted. If this occurs, this function must be called to re-enable bus communication.

Warning

Calling this function when the device is already in “bus-on” will have no effect. This function is not necessary to call after creating the CAN driver as the driver should already be “bus-on” on creation.

inline void send(message_t const &p_message)#

Send a can message.

Parameters:

p_message – - the message to be sent

Throws:

hal::operation_not_permitted – - if the can device has entered the “bus-off” state. This can happen if a critical fault in the bus has occurred. A call to bus_on() will need to be issued to attempt to talk on the bus again. See bus_on() for more details.

inline void on_receive(hal::callback<handler> p_handler)#

Set the message reception handler.

All messages received before a message handler is installed are dropped.

Parameters:

p_handler – - this handler will be called when a message has been received.

struct message_t#

A standard CAN message.

Public Functions

bool operator<=>(message_t const&) const = default#

Enables default comparison.

Public Members

id_t id#

ID of the message.

std::array<hal::byte, 8> payload = {}#

Message data contents.

uint8_t length = 0#

The number of valid elements in the payload.

Can be between 0 and 8. A length value above 8 should be considered invalid and can be discarded.

bool is_remote_request = false#

Determines if the message is a remote request frame.

If true, then length and payload are ignored.

struct settings#

Generic settings for a can peripheral.

Public Functions

bool operator<=>(settings const&) const = default#

Enables default comparison.

Public Members

hertz baud_rate = 100.0_kHz#

Bus clock rate in hertz.

CAN Bit Quanta Timing Diagram of:

                          | <--- sjw ---> |
    ____    ______    __________    __________
 _/ SYNC \/  PROP  \/   PHASE1   \/   PHASE2   \_
  \______/\________/\____________/\____________/
                                  ^ Sample point
A can bus bit is separated into the segments:

  • Sync Segment (always 1qt): Initial sync transition, the start of a CAN bit.

  • Propagation Delay (1qt … 8qt): Number of time quanta to compensate for signal/propagation delays across the network.

  • Phase Segment 1 (1qt … 8qt): phase segment 1 acts as a buffer that can be lengthened to resynchronize with the bit stream via the synchronization jump width.

  • Phase Segment 2 (1qt … 8qt): Occurs after the sampling point. Phase segment 2. can be shortened to resynchronize with the bit stream via the synchronization jump width.

  • Synchronization jump width (1qt … 4qt): This is the maximum time by which the bit sampling period may be lengthened or shortened during each cycle to adjust for oscillator mismatch between nodes. This value must be smaller than phase_segment1 and phase_segment2.

The exact value of these segments is calculated for you by the can peripheral based on the input clock to the peripheral and the desired baud rate.

A conformant can bus peripheral driver will either choose from tq starting from 25 and reducing it down to 8 or will have pre-configured timing values for each frequency it supports.

Utilities#

Utilities for working with CAN, defined in namespace hal

#include <libhal-util/can.hpp>

group CAN_Utilities

Functions

constexpr auto operator==(can_bus_divider_t const &p_lhs, can_bus_divider_t const &p_rhs)#

Compares two CAN bus settings.

Parameters:
  • p_lhs – CAN bus settings

  • p_rhs – A CAN bus setting to compare against another

Returns:

A boolean if they are the same or not.

inline std::optional<can_bus_divider_t> calculate_can_bus_divider(hertz p_operating_frequency, hertz p_target_baud_rate)#

Calculates the can bus divider values.

Preferred method of calculating the bus divider values for a can bus peripheral or device. The algorithm checks each possible time quanta (tq) width from 25tq to 8tq. The algorithm always checks starting with the greatest time quanta in order to achieve the longest bit width and sync jump value. The aim is to provide the most flexibility in the sync jump value which should help in most topologies.

Parameters:
  • p_operating_frequency – - frequency of the input clock to the can bus bit timing module.

  • p_target_baud_rate – - the baud (bit) rate to set the can bus to.

Returns:

std::optional<can_bus_divider_t> - the resulting dividers for the can bus peripheral. Returns std::nullopt if the target baud rate is not achievable with the provided operating frequency.

struct can_bus_divider_t#
#include <can.hpp>

Generic settings for a can peripheral.

CAN Bit Quanta Timing Diagram of:

                          | <--- sjw ---> |
    ____    ______    __________    __________
 _/ SYNC \/  PROP  \/   PHASE1   \/   PHASE2   \_
  \______/\________/\____________/\____________/
                                  ^ Sample point

Public Members

std::uint8_t clock_divider#

Bus clock rate in hertz.

std::uint8_t propagation_delay#

Propagation Delay (1qt … 8qt)

Propagation time It is used to compensate for signal delays across the network.

std::uint8_t phase_segment1#

Length of Phase Segment 1 (1qt … 8qt)

Determines the bit rate, phase segment 1 acts as a buffer that can be lengthened to resynchronize with the bit stream via the synchronization_jump_width. Includes propagation delay

std::uint8_t phase_segment2#

Length of Phase Segment 2 (1qt … 8qt)

Determines the bit rate and is like phase segment 1 and occurs after the sampling point. Phase segment 2 can be shortened to resynchronize with the bit stream via the synchronization_jump_width.

std::uint8_t synchronization_jump_width#

Synchronization jump width (1qt … 4qt)

This is the maximum time by which the bit sampling period may be lengthened or shortened during each cycle to adjust for oscillator mismatch between nodes.

This value must be smaller than phase_segment1 and phase_segment2

std::uint8_t total_tq#

The total tq of the structure.

Public Static Attributes

static constexpr std::uint8_t sync_segment = 1#

Sync Segment (always 1qt)

Initial sync transition, the start of a CAN bit