Send data to the I2C device

Once you start the I2C driver, it exposes a path under /dev/i2c*. You can use the devctl() command to interface with the I2C driver and can find it's format in hw/i2c.h. The example uses the following sample I2C code to explain the interface: https://gitlab.com/qnx/projects/hardware-component-samples/-/tree/main/common/rpi_i2c

The following example reads a value from a slave device to explain the interface. Start with defining the read data structure in your application:

struct i2c_recv_data_msg_t
{
    i2c_sendrecv_t hdr;
    uint8_t bytes[0];
};

Fill out the i2c_sendrecv_t structure with relevant data:

typedef struct {
    i2c_addr_t          slave;      /* slave address */
    _Uint32t            send_len;   /* length of send data in bytes */
    _Uint32t            recv_len;   /* length of receive data in bytes */
    _Uint32t            stop;       /* set stop when complete? */
} i2c_sendrecv_t;

Fill out the i2c_addr_t structure, which is set up for the slave device:

typedef struct {
    _Uint32t            addr;   /* I2C address */
    _Uint32t            fmt;    /* 7- or 10-bit format */
} i2c_addr_t;

Filling up the data may look like the following:

// Allocate memory for the message
struct i2c_recv_data_msg_t *msg = NULL;
msg = malloc(sizeof(struct i2c_recv_data_msg_t) + MIN_READ_BYTES); // allocate enough memory for both the calling information and received data
if (!msg)
{
    perror("alloc failed");
    return I2C_ERROR_ALLOC_FAILED;
}

// Assign which register
msg->bytes[0] = register_val;

// Assign the I2C device and format of message
msg->hdr.slave.addr = i2c_address;
msg->hdr.slave.fmt = I2C_ADDRFMT_7BIT;
msg->hdr.send_len = 1;
msg->hdr.recv_len = 1;
msg->hdr.stop = 1;

Once you've filled out the data, you can finally send the data to the resource manager using the devctl() command:

int status; // status information about the devctl() call
int err = devctl(smbus_fd[bus_number], DCMD_I2C_SENDRECV, msg, sizeof(*msg) + 1, (&status)); // specify DCMD_I2C_SENDRECV to indicate that we are using the i2c_sendrecv_t data structure

Refer to the smbus_read_data_byte() function in the i2c.c file for more detailed information. You can implement a similar approach for other devctl() DCMDs.

You can find a list of the devctl() commands in the "Resource manager interface" section of the Customizing a BSP guide.

Page updated: