Inter-integrated Circuit (I2C)#

Hardware Interface#

Defined in namespace hal

#include <libhal/i2c.hpp>

class i2c#

Inter-integrated Circuit (I2C) hardware abstract interface.

Also known as Two Wire Interface (TWI) communication protocol. This is a very commonly used protocol for communication with sensors and peripheral devices because it only requires two connections SDA (data signal) and SCL (clock signal). This is possible because the protocol for I2C is addressable.

Some devices can utilize clock stretching as a means to pause the i2c controller until the device is ready to respond. To ensure operations with i2c are deterministic and reliably it is advised to NEVER use a clock stretching device in your application.

Subclassed by hal::bit_bang_i2c, hal::lpc40::i2c, hal::soft::bit_bang_i2c, hal::soft::inert_i2c, hal::soft::minimum_speed_i2c

Public Functions

inline void configure(settings const &p_settings)#

Configure i2c to match the settings supplied.

Parameters:

p_settings – - settings to apply to i2c driver

Throws:

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

inline void transaction(hal::byte p_address, std::span<hal::byte const> p_data_out, std::span<hal::byte> p_data_in)#

perform an i2c transaction with another device on the bus. The type of transaction depends on values of input parameters. This function will block until the entire transfer is finished.

Performing Write, Read and Write-Then-Read transactions depends on which span for data_out and data_in are set to null.

  • For write transactions, pass p_data_in as an empty span std::span<hal::byte>{} and pass a buffer to p_data_out.

  • For read transactions, pass p_data_out as an empty span std::span<hal::byte const>{} and pass a buffer to p_data_in.

  • For write-then-read transactions, pass a buffer for both p_data_in p_data_out.

  • If both p_data_in and p_data_out are empty, simply do nothing and return success.

In the event of arbitration loss, this function will wait for the bus to become free and try again. Arbitration loss means that during the address phase of a transaction 1 or more i2c bus controllers attempted to perform an transaction and one of the i2c bus controllers, that isn’t this one won out.

Parameters:
  • p_address – 7-bit address of the device you want to communicate with. To perform a transaction with a 10-bit address, this parameter must be the address upper byte of the 10-bit address OR’d with 0b1111’0000 (the 10-bit address indicator). The lower byte of the address must be contained in the first byte of the p_data_out span.

  • p_data_out – data to be written to the addressed device. Set to nullptr with length zero in order to skip writing.

  • p_data_in – buffer to store read data from the addressed device. Set to nullptr with length 0 in order to skip reading.

Throws:
  • hal::no_such_device – - indicates that no devices on the bus acknowledge the address in this transaction, which could mean that the device is not connected to the bus, is not powered, not available to respond, broken or many other possible outcomes.

  • hal::io_error – - indicates that the i2c lines were put into an invalid state during the transaction due to interference, misconfiguration, hardware fault, malfunctioning i2c peripheral or possibly something else. This tends to present a hardware issue and is usually not recoverable.

inline void transaction(hal::byte p_address, std::span<hal::byte const> p_data_out, std::span<hal::byte> p_data_in, hal::function_ref<hal::timeout_function> p_timeout)#

perform an i2c transaction with another device on the bus. The type of transaction depends on values of input parameters. This function will block until the entire transfer is finished.

Deprecated:

Prefer to use the i2c API that does not use timeouts. Timeout functions get in the way of an efficient usage of DMA, is a viral performance hit, and is only for the rare situation where a device on the bus may perform clock stretching for which there are few devices that support this. The deprecated attribute is not used yet, as the transition is still ongoing.

Parameters:
  • p_address – 7-bit address of the device you want to communicate with. To perform a transaction with a 10-bit address, this parameter must be the address upper byte of the 10-bit address OR’d with 0b1111’0000 (the 10-bit address indicator). The lower byte of the address must be contained in the first byte of the p_data_out span.

  • p_data_out – data to be written to the addressed device. Set to nullptr with length zero in order to skip writing.

  • p_data_in – buffer to store read data from the addressed device. Set to nullptr with length 0 in order to skip reading.

  • p_timeout – callable which notifies the i2c driver that it has run out of time to perform the transaction and must stop and return control to the caller.

Throws:
  • hal::timed_out – from p_timeout if the transaction exceeds its deadline.

  • hal::no_such_device – - indicates that no devices on the bus acknowledge the address in this transaction, which could mean that the device is not connected to the bus, is not powered, not available to respond, broken or many other possible outcomes.

  • hal::io_error – - indicates that the i2c lines were put into an invalid state during the transaction due to interference, misconfiguration, hardware fault, malfunctioning i2c peripheral or possibly something else. This tends to present a hardware issue and is usually not recoverable.

struct settings#

Generic settings for a standard I2C device.

Public Functions

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

Enables default comparison.

Public Members

hertz clock_rate = 100.0_kHz#

The serial clock rate in hertz.

Utilities#

Utilities for working with I2C, defined in namespace hal

#include <libhal-util/i2c.hpp>

group I2CUtils

Enums

enum class i2c_operation#

Set of I2C transaction operations.

Values:

enumerator write#

Denotes an i2c write operation.

enumerator read#

Denotes an i2c read operation.

Functions

inline void write(i2c &p_i2c, hal::byte p_address, std::span<hal::byte const> p_data_out, timeout auto)#

write data to a target device on the i2c bus with a timeout

Deprecated:

use APIs that do not use timeouts

Deprecated:

Prefer to use the write API that does not require a timeout.

Shorthand for writing i2c.transfer(…) for write only operations

Parameters:
  • p_i2c – - i2c driver

  • p_address – - target address

  • p_data_out – - buffer of bytes to write to the target device

  • auto – - [deprecated don’t use]

inline void write(i2c &p_i2c, hal::byte p_address, std::span<hal::byte const> p_data_out)#

write data to a target device on the i2c bus

Shorthand for writing i2c.transfer(…) for write only operations, but never times out. Can be used for devices that never perform clock stretching.

Parameters:
  • p_i2c – - i2c driver

  • p_address – - target address

  • p_data_out – - buffer of bytes to write to the target device

inline void read(i2c &p_i2c, hal::byte p_address, std::span<hal::byte> p_data_in, timeout auto)#

read bytes from target device on i2c bus

Deprecated:

use APIs that do not use timeouts

Shorthand for writing i2c.transfer(…) for read only operations

Parameters:
  • p_i2c – - i2c driver

  • p_address – - target address

  • p_data_in – - buffer to read bytes into from target device

  • auto – - [deprecated don’t use]

inline void read(i2c &p_i2c, hal::byte p_address, std::span<hal::byte> p_data_in)#

read bytes from target device on i2c bus

Deprecated:

use APIs that do not use timeouts

Shorthand for writing i2c.transfer(…) for read only operations, but never times out. Can be used for devices that never perform clock stretching.

Parameters:
  • p_i2c – - i2c driver

  • p_address – - target address

  • p_data_in – - buffer to read bytes into from target device

template<size_t bytes_to_read>
std::array<hal::byte, bytes_to_read> read(i2c &p_i2c, hal::byte p_address, timeout auto)#

return array of read bytes from target device on i2c bus

Deprecated:

use APIs that do not use timeouts

Eliminates the need to create a buffer and pass it into the read function.

Template Parameters:

bytes_to_read – - number of bytes to read

Parameters:
  • p_i2c – - i2c driver

  • p_address – - target address

  • auto – - [deprecated don’t use]

Returns:

std::array<hal::byte, bytes_to_read> - array of bytes from target device

template<size_t bytes_to_read>
std::array<hal::byte, bytes_to_read> read(i2c &p_i2c, hal::byte p_address)#

return array of read bytes from target device on i2c bus

Eliminates the need to create a buffer and pass it into the read function.

Template Parameters:

bytes_to_read – - number of bytes to read

Parameters:
  • p_i2c – - i2c driver

  • p_address – - target address

Returns:

std::array<hal::byte, bytes_to_read> - array of bytes from target device

inline void write_then_read(i2c &p_i2c, hal::byte p_address, std::span<hal::byte const> p_data_out, std::span<hal::byte> p_data_in, timeout auto)#

write and then read bytes from target device on i2c bus

Deprecated:

use APIs that do not use timeouts

This API simply calls transaction. This API is here for consistency across the other other communication protocols such as SPI and serial.

Parameters:
  • p_i2c – - i2c driver

  • p_address – - target address

  • p_data_out – - buffer of bytes to write to the target device

  • p_data_in – - buffer to read bytes into from target device

  • auto – - amount of time to execute the transaction

template<size_t bytes_to_read>
std::array<hal::byte, bytes_to_read> write_then_read(i2c &p_i2c, hal::byte p_address, std::span<hal::byte const> p_data_out, timeout auto)#

write and then return an array of read bytes from target device on i2c bus

Deprecated:

use APIs that do not use timeouts

Eliminates the need to create a buffer and pass it into the read function.

Template Parameters:

bytes_to_read – - number of bytes to read after write

Parameters:
  • p_i2c – - i2c driver

  • p_address – - target address

  • p_data_out – - buffer of bytes to write to the target device

  • auto – - [deprecated use the APIs without timeout parameters]

Returns:

std::array<hal::byte, bytes_to_read> - array of bytes from target device.

template<size_t bytes_to_read>
std::array<hal::byte, bytes_to_read> write_then_read(i2c &p_i2c, hal::byte p_address, std::span<hal::byte const> p_data_out)#

write and then return an array of read bytes from target device on i2c bus

Eliminates the need to create a buffer and pass it into the read function.

Template Parameters:

bytes_to_read – - number of bytes to read after write

Parameters:
  • p_i2c – - i2c driver

  • p_address – - target address

  • p_data_out – - buffer of bytes to write to the target device

Returns:

std::array<hal::byte, bytes_to_read> -

inline bool probe(i2c &p_i2c, hal::byte p_address)#

probe the i2c bus to see if a device exists

NOTE: that this utilizes the fact that i2c drivers throw std::errc::no_such_device_or_address when a transaction is performed and the device’s address is used on the bus and the device does not respond with an acknowledge.

Parameters:
  • p_i2c – - i2c driver for the i2c bus that the device may exist on

  • p_address – - device to check

Returns:

true - if the device appears on the bus

Returns:

false - if the devices does not appear on the i2c bus

inline hal::byte to_8_bit_address(hal::byte p_address, i2c_operation p_operation) noexcept#

Convert 7-bit i2c address to an 8-bit address.

Parameters:
  • p_address – 7-bit i2c address

  • p_operation – write or read operation

Returns:

hal::byte - 8-bit i2c address