An I2C (Inter-Integrated Circuit) is a two-wire, bidirectional serial bus that provides a simple, efficient method of data exchange that minimizes the interconnection between devices. This bus is suitable for applications requiring occasional communication over a short distance between many devices. The flexible I2C standard allows you to connect additional devices to the bus for expansion and system development.

The ConnectCore platforms have several I2C interfaces. You can find more information in Hardware reference manuals and I2C.

Digi adds an API to Linux to manage these I2C devices as master. To use this API, include the following header file:

#include <libdigiapix/i2c.h>

You can configure them and communicate with connected devices over the I2C bus.

Request an I2C

You can request an I2C with one of the following functions:

Function Description

i2c_t *ldx_i2c_request(unsigned int i2c_bus)

Requests an I2C by its bus number.

It returns a pointer to i2c_t on success, NULL on error.

i2c_t *ldx_i2c_request_by_alias(char const * const i2c_alias)

Requests an I2C by its alias name. The I2C alias mapping must be defined in the /etc/libdigiapix.conf file under the [I2C] section. See Establish I2C aliases.

It returns a pointer to i2c_t on success, NULL on error.

The requested I2C must be freed once it is not needed anymore. See Free an I2C.

Both functions may fail and return NULL for the following reasons:

  • If the provided bus number or the bus number associated with the given alias cannot be exported.

  • If the API encountered problems allocating memory to initialize the I2C. Your system may have run out of resources.

Request an I2C
[...]
 
/* Request an I2C using its alias */
i2c_t i2c1 = ldx_i2c_request_by_alias("DEFAULT_I2C");
 
/* Request an I2C using bus number */
i2c_t i2c2 = ldx_i2c_request(2);
 
printf("The I2C-%d was requested\n", i2c1->bus);
printf("The I2C-%d was requested\n", i2c2->bus);
 
[...]

Establish I2C aliases

To help you identify the I2Cs of your design, you can assign aliases to your I2C Linux IDs. Map the assigned bus number to a name in the /etc/libdigiapix.conf file:

  1. Add a section called [I2C], if one doesn’t already exist.

  2. Below the section name, add the list of mapped I2Cs following the format:

    <alias> = <i2c_bus>

    Where:

    • <alias> is the human-readable name for the I2C.

    • <i2c_bus> is the I2C bus.

Example I2C section
[I2C]
 
# I2C-1 on I2C board connector.
DEFAULT_I2C_BUS = 0

For example, using the configuration above, you can request an I2C with the API using DEFAULT_I2C_BUS alias. See Request an I2C.

You can get the bus associated to an alias using these functions:

int ldx_i2c_get_bus(const char * const i2c_alias)
For information on including libdigiapix.conf in your Digi Embedded Yocto images, see Define interface aliases.

List available I2C buses

You can determine the list of available I2C buses on the target device with the ldx_i2c_list_available_buses() API function:

int ldx_i2c_list_available_buses(uint8_t **buses)

The function returns the number of available buses for the I2C interface, or -1 if there is an error.

Get I2C bus list
[...]

uint8_t *buses = NULL;
int i, bus_number = 0;

[...]

/* Retrieve the list of available I2C buses */
bus_number = ldx_i2c_list_available_buses(&buses);
if (bus_number > 0) {
    printf("The target has %d I2C available buses:\n", bus_number);
    for (i = 0; i < bus_number; i++) {
        printf(" - I2C-%d\n", buses[i]);
    }
} else {
    printf("The target does not have any I2C bus available\n");
}

[...]

free(buses);

[...]

Free an I2C

You must free a requested I2C when it is no longer required. To do so, set the ldx_i2c_free() function.

int ldx_i2c_free(i2c_t *i2c)
Free a requested I2C
[...]
 
i2c_t *i2c = ...;
 
[...]
 
/* Free I2C once it is not required anymore */
ldx_i2c_free(i2c);
 
[...]

Configure I2C communication

You can configure the I2C behavior to either terminate a communication on time out or to retry accessing an I2C device on acknowledge error. To specify the timeout where the I2C waits for a response from the I2C device, use the following function:

Function Description

int ldx_i2c_set_timeout(i2c_t *i2c, int timeout)

  • Sets the I2C transfer timeout in tenths of milliseconds.

  • It returns EXIT_SUCCESS on success, EXIT_FAILURE otherwise.

The timeout parameter defines the I2C timeout in units of 10ms. If you would like to set timeout to 50 ms, set timeout to 5.

Configure I2C timeout
[...]
 
int timeout = 5; /* 50ms */
 
i2c = ldx_i2c_request(1);
ldx_i2c_set_timeout(i2c, timeout);
 
[...]
 
ldx_i2c_free(i2c);

The retry parameter defines the I2C attempts when acknowledge fails in an I2C communication.

Function Description

int ldx_i2c_set_retries(i2c_t *i2c, int retry)

  • Sets the I2C bus poll retries.

  • It returns EXIT_SUCCESS on success, EXIT_FAILURE otherwise.

Configure I2C retries
[...]
 
int retry = 3;
 
i2c = ldx_i2c_request(1);
ldx_i2c_set_retries(i2c, retry);
 
[...]
 
ldx_i2c_free(i2c);

Communicate with I2C slaves

The API allows three types of communication with other I2C slave devices.

Write data to I2C slave devices

You can send data to other I2C slave devices using the ldx_i2c_write() function:

Function Description

int ldx_i2c_write(i2c_t *i2c, uint8_t i2c_address, uint8_t *buffer, uint16_t length)

  • Sends data to I2C slave devices.

  • The destination I2C slave device is specified with the i2c_address parameter.

  • The data to write is passed in the buffer parameter.

  • The number of bytes to write are specified with the length parameter.

  • It returns EXIT_SUCCESS on success, EXIT_FAILURE otherwise.

Write data to an I2C slave
[...]

#define DATA_SIZE8

[...]

int i = 0;
uint8_t tx_buffer[DATA_SIZE] = {0};
uint8_t i2c_address = 0x55;
 
i2c_t i2c = ...;
/* Fill the buffer with random data */
for (i = 0; i < DATA_SIZE; i++) {
    tx_buffer[i] = rand() % 255;
}
printf("Writing %d bytes to I2C-%d slave %x...\n", DATA_SIZE, i2c->bus, i2c_address);
ldx_i2c_write(i2c, i2c_address, tx_buffer, DATA_SIZE);

[...]

Read data from I2C slave devices

You can receive data from other I2C slave devices using the ldx_i2c_read() function. One of the most common things to do with an I2C interface is read one or more bytes from a specific device slave address.

Function Description

int ldx_i2c_read(i2c_t *i2c, uint8_t i2c_address, uint8_t *buffer, uint16_t length)

  • Receives data from I2C slave devices.

  • The I2C slave device to read data from is specified with the i2c_address parameter.

  • The read data is stored in the buffer parameter.

  • The number of bytes to read are specified with the length parameter.

  • It returns EXIT_SUCCESS on success, EXIT_FAILURE otherwise.

Read data from an I2C slave
[...]

#define DATA_SIZE8

[...]

int i = 0;
uint8_t rx_buffer[DATA_SIZE] = {0};
uint8_t i2c_address = 0x55;
 
i2c_t i2c = ...;
printf("Reading %d bytes from I2C-%d slave %x...\n", DATA_SIZE, i2c->bus, i2c_address);
ldx_i2c_read(i2c, i2c_address, rx_buffer, DATA_SIZE);
for (i = 0; i < DATA_SIZE; i++) {
    printf("rx_data[%d] = 0x%02x\n", i, rx_buffer[i]);
}

[...]

Transfer data to I2C slave devices

You can write and read data simultaneously to and from I2C slave devices in one operation using the ldx_i2c_transfer() function:

Function Description

int ldx_i2c_transfer(i2c_t *i2c, uint8_t i2c_address, uint8_t *buffer_to_write, uint16_t w_length, uint8_t *buffer_to_read, uint16_t r_length)

  • Transfer data with I2C slave devices.

  • The I2C slave device to transfer data with is specified in the i2c_address parameter.

  • The data to write is passed in the buffer_to_write parameter.

  • The number of bytes to write are specified with the w_ length parameter.

  • The data to read is stored in the buffer_to_read parameter.

  • The number of bytes to read are specified with the r_length parameter.

  • It returns EXIT_SUCCESS on success, EXIT_FAILURE otherwise.

Transfer data to an I2C slave
[...]

#define DATA_SIZE8

[...]

int i = 0;
uint8_t tx_buffer[] = {0x23};/* I2C slave specific command or register */
uint8_t rx_buffer[DATA_SIZE] = {0};
uint8_t i2c_address = 0x55;
 
i2c_t i2c = ...;
ldx_i2c_transfer(i2c, i2c_address, tx_buffer, 1, rx_buffer, DATA_SIZE);
 
printf("Read %d bytes from the I2C-%d slave %x...\n", DATA_SIZE, i2c->bus, i2c_address);
 
for (i = 0; i < DATA_SIZE; i++) {
    printf("rx_data[%d] = 0x%02x\n", i, rx_buffer[i]);
}

[...]

I2C example

In this example, I2C writes the page of an external EEPROM memory with random data and then reads the data back to validate it.

You can import the example in Eclipse using the Digi Embeddded Yocto plugin. For more information, see Create a new DEY sample project.  This example is included in Digi Embedded Yocto. Go to GitHub to see the application source code.