[ Prev ] [ Index ] [ Next ]

5_struct i2c msg

Created Thursday 19 January 2017

The primary interface with I2C devices, within a Linux context, is through the use of i2C_msg data structures.

// Defines for struct i2c_msg - flags field
#define I2C_M_RD 0x0001 /* read data, from slave to master */
#define I2C_M_TEN 0x0010 /* this is a ten bit chip address */
#define I2C_M_RECV_LEN 0x0400 /* length will be first received byte */
#define I2C_M_NO_RD_ACK 0x0800 /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_IGNORE_NAK 0x1000 /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_REV_DIR_ADDR 0x2000 /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_NOSTART 0x4000 /* if I2C_FUNC_NOSTART */
#define I2C_M_STOP 0x8000 /* if I2C_FUNC_PROTOCOL_MANGLING */

struct i2c_msg {

__u16 addr; /* slave address */
__u16 flags; /* see above for flag definitions */
__u16 len; /* msg length */
__u8 *buf; /* pointer to msg data */
};
(Defined in uapi/linux/i2c.h)

This data structure provides for the definition of the device address,
if it's a transmit or receive, pointer to data to send/receive, and size of data.


Another common data structure is struct i2c_rdwr_ioctl_data

This is the structure as used in the I2C_RDWR ioctl call
struct i2c_rdwr_ioctl_data {

struct i2c_msg __user *msgs; /* pointers to i2c_msgs */
__u32 nmsgs; /* number of i2c_msgs */
};
(Defined in linux/i2c-dev.h)
This structure points to the array of i2c_msg to process and defines the number of i2c_msg in the array.

Usage:
If the program is to write one byte (example - the index byte), followed by
reading one byte, two struct i2c_msg data structures will be needed.
One for the write, and another for the read. These two data structures should be declared as an array of two i2c_msg data structures. They will be processed in the order they appear in the array.

i2c_msg Example:
Interracting with DS3231, I2C address 0x68, read the Hours register (index 2)
To perform this exercise, we need to write the single byte, 0x02, followed with the reading of a single byte, using the I2C address 0x68.

// file: ds3231.cpp
#include <stdio.h> // printf()
#include <sys/types.h> // open()
#include <sys/stat.h> // open()
#include <fcntl.h> // open()
#include <sys/ioctl.h> // ioctl()
#include <errno.h> // errno
#include <string.h> // strerror()
#include <unistd.h> // close()
#include <linux/i2c-dev.h> // struct i2c_msg
#include <linux/i2c.h> // struct i2c_rdwr_ioctl_data
int main(int argc, char * argv[])
{

struct i2c_msg ds3231msg[2]; // declare our two i2c_msg array
unsigned char ucIndex = 2;
unsigned char ucData = 0;
// Load up transmit msg
ds3231msg[0].addr = 0x68;
ds3231msg[0].flags = 0;
ds3231msg[0].len = sizeof(ucIndex);
ds3231msg[0].buf = &ucIndex;
// Load up receive msg
ds3231msg[1].addr = 0x68;
ds3231msg[1].flags = I2C_M_RD;
ds3231msg[1].len = sizeof(ucData);
ds3231msg[1].buf = &ucData;
// Load up i2c_rdwr_ioctl_data
struct i2c_rdwr_ioctl_data i2c_data; // declare our i2c_rdwr_ioctl_data structure
i2c_data.msgs = ds3231msg;
i2c_data.nmsgs = 2;

// Open file descriptor to I2C bus
int fd = open("/dev/i2c-1",O_RDWR);
if(fd<0) {
printf("Failed to open i2c-1.");
return -1;
}
// With our file descriptor, perform I2C message transfers
int result = ioctl(fd,I2C_RDWR,&i2c_data);
if(result < 0)
{
printf("ioctl error: %s\n", strerror(errno));
return -1;
}
// We have read a data byte from index 2... Display it
printf("Index 2: 0x%02X\n",ucData);
close(fd);

return 0;
}


Home Page