DCMD_I2C_REGACC

QNX SDP8.0Customizing a BSPConfigurationDeveloper
#include <hw/i2c.h>

#define DCMD_I2C_REGACC             __DIOTF(_DCMD_I2C, 12, i2c_regacc_t)
The arguments to devctl() are:
Argument Value
filedes A file descriptor that you obtained by opening the device.
dcmd DCMD_I2C_REGACC
dev_data_ptr A pointer to a i2c_regacc_t that's followed by additional data
n_bytes sizeof(i2c_regacc_t) + size of additional data
dev_info_ptr NULL

The DCMD_I2C_REGACC command enables client applications to access I2C slave device registers atomically. The atomic property of this command guarantees that another client application won't interrupt the transaction by accessing the I2C bus. This command blocks until the transaction is complete.

Input
  • i2c_regops_t — Register operations(clear, set, toggle) structure:
    typedef struct {
    	uint8_t     clr;        /* 1: clear;  0: no changes */
    	uint8_t     set;        /* 1: set;    0: no changes */
    	uint8_t     toggle;     /* 1: toggle; 0: no changes */
    } i2c_regops_t;
  • i2c_regacc_t — Register access structure:
    typedef struct {
    	i2c_addr_t  slave;      /* slave address */
    	uint32_t    addr;       /* register address, sent out in LSB order */
    	uint32_t    addrlen;    /* address length in byte count */
    	uint32_t    nregs;      /* number of registers to read; also length of receive data in bytes. nregs must be >= 1 */
    	uint32_t    nregops;    /* number of register operations. nregops must be either 0 or equal to nregs */
    	uint32_t    flags;
    	#define  REGACC_RD_STOP  (1 << 0)  /* set stop when reading register value complete */
    	#define  REGACC_RESEND   (1 << 1)  /* need to resend the send commands before register writing */
    	/* followed by nregs recv buffer and then nregops regop structs and then send commands if needed */
    } i2c_regacc_t;
    Use it to read nregs of registers from addr. Then apply nregops of operations (clear, set, toggle). If necessary, write the modified value back to register.
    Note:
    • nregs must be at least 1.
    • nregops must be either 0 or equal to nregs.
      • When nregops == 0, RegAcc is read only.
      • When nregops == nregs, RegAcc is read + modify + write.
This command covers the following cases:
nregops == 0 nregops !== 0
no Sends Recv(s) RegAcc(s)
Sends Send(s)Recv(s) Send(s)RegAcc(s)
DCMD_I2C_REGACC input data structure:
Input data structure of DCMD_I2C_REGACC
Output
  • i2c_regacc_t header structure
  • nregs bytes of initial registers value from addr
If an error occurs, the command returns:
EIO
The master send failed. The causes include: bad slave address, bad bus speed, bus is busy.
EFAULT
An error occurred while accessing the data buffer.
EINVAL
Bad message format.
ENOMEM
Insufficient memory.
EPERM
The master is locked by another connection.
A code example of using DCMD_I2C_REGACC that sends commands to the device and reads data from the registers without applying bit modifications:
/* This sample code is accessing device /dev/i2c0.
 * It sends 3 commands to slave device 0x20,
 * then read 1 register value at offset 0x10 from
 * slave device 0x50 then return the value.
 * All the transactions are atomic.
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <devctl.h>
#include <fcntl.h>
#include <hw/i2c.h>

#define REGS_NUM   1
#define CMDS_NUM   3

char        *devname = "/dev/i2c0";
unsigned    bus_speed = 0;

int main(int argc, char *argv[])
{
    int i;
    int fd;
    int status;
    int bytes;

    iov_t       siov[8];
    iov_t       riov[2];

    fd = open(devname, O_RDWR);
    if (fd < 0) {
        fprintf(stderr, "open(%s): %s\n", devname, strerror(errno));
        exit(-1);
    }

    if (bus_speed) {
        if ((status = devctl(fd, DCMD_I2C_SET_BUS_SPEED, &bus_speed, sizeof(bus_speed), NULL))) {
            errno = status;
            perror("devctl(BUS_SPEED)");
            exit(-1);
        }
    }

    i2c_regacc_t regacc = {.slave.addr = 0x50, .slave.fmt = I2C_ADDRFMT_7BIT,
                           .addr = 0x10,
                           .addrlen = 1,
                           .nregs = REGS_NUM,
                           .nregops = 0,
                           .flags = REGACC_RD_STOP  /* Stop after read regs */
                          };

    unsigned char recvbuf[REGS_NUM] = {0};
 
    i2c_send_t cmds[CMDS_NUM] = {{.len = 1, .slave.addr = 0x20, .slave.fmt = I2C_ADDRFMT_7BIT, .stop = 1},
                                 {.len = 2, .slave.addr = 0x20, .slave.fmt = I2C_ADDRFMT_7BIT, .stop = 1},
                                 {.len = 3, .slave.addr = 0x20, .slave.fmt = I2C_ADDRFMT_7BIT, .stop = 1}
                                };
    uint8_t     data0 = 0x01;
    uint8_t     data1[2] = {0x02, 0x03};
    uint8_t     data2[3] = {0x04, 0x05, 0x06};

    /* Header + recvbuf + regpos */
    SETIOV(&siov[0], &regacc, sizeof(regacc));
    SETIOV(&siov[1], &recvbuf, sizeof(recvbuf));

    /* Send commands */
    SETIOV(&siov[2], &cmds[0], sizeof(cmds[0]));
    SETIOV(&siov[3], &data0, sizeof(data0));
    SETIOV(&siov[4], &cmds[1], sizeof(cmds[1]));
    SETIOV(&siov[5], &data1, sizeof(data1));
    SETIOV(&siov[6], &cmds[2], sizeof(cmds[2]));
    SETIOV(&siov[7], &data2, sizeof(data2));

    /* recv header + buf */
    SETIOV(&riov[0], &regacc, sizeof(regacc));
    SETIOV(&riov[1], &recvbuf, sizeof(recvbuf));

    if ((status = devctlv(fd, DCMD_I2C_REGACC, 8, 2, siov, riov, &bytes))) {
        errno = status;
        perror("MASTER_SEND");
        exit(-1);
    }

    for (i = 0; i < bytes; ++i) {
        fprintf(stderr, "recv: 0x%x\n", recvbuf[i]);
    }

    exit(0);
}
A code example of using DCMD_I2C_REGACC that sends commands to the device and reads data from the registers, then applies bit modifications:
/* This sample code is accessing device /dev/i2c0.
 * Firstly sending 3 commands to slave device 0x20,
 * then read 1 register value at offset 0x10 from
 * slave device 0x50 and toggle the bit 2 then
 * write the modified value back to offset 0x10. The
 * original register value is returned.
 * All the transactions are atomic.
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <devctl.h>
#include <fcntl.h>
#include <hw/i2c.h>

#define REGS_NUM   1
#define OPS_NUM    1
#define CMDS_NUM   3

char        *devname = "/dev/i2c0";
unsigned    bus_speed = 0;

int main(int argc, char *argv[])
{
    int i;
    int fd;
    int status;
    int bytes;

    iov_t       siov[9];
    iov_t       riov[2];

    fd = open(devname, O_RDWR);
    if (fd < 0) {
        fprintf(stderr, "open(%s): %s\n", devname, strerror(errno));
        exit(-1);
    }

    if (bus_speed) {
        if ((status = devctl(fd, DCMD_I2C_SET_BUS_SPEED, &bus_speed, sizeof(bus_speed), NULL))) {
            errno = status;
            perror("devctl(BUS_SPEED)");
            exit(-1);
        }
    }

    i2c_regacc_t regacc = {.slave.addr = 0x50, .slave.fmt = I2C_ADDRFMT_7BIT,
                           .addr = 0x10,
                           .addrlen = 1,
                           .nregs = REGS_NUM,
                           .nregops = OPS_NUM,
                           .flags = REGACC_RD_STOP | REGACC_RESEND  /* Stop after read regs and re-send cmds before write regs */
                          };

    unsigned char recvbuf[REGS_NUM] = {0};

    i2c_regops_t regops[OPS_NUM] = {{.clr = 0x00, .set = 0x00, .toggle = 0x04}  /* Toggle bit 2 */
                                };
 
    i2c_send_t cmds[CMDS_NUM] = {{.len = 1, .slave.addr = 0x20, .slave.fmt = I2C_ADDRFMT_7BIT, .stop = 1},
                                 {.len = 2, .slave.addr = 0x20, .slave.fmt = I2C_ADDRFMT_7BIT, .stop = 1},
                                 {.len = 3, .slave.addr = 0x20, .slave.fmt = I2C_ADDRFMT_7BIT, .stop = 1}
                                };
    uint8_t     data0 = 0x01;
    uint8_t     data1[2] = {0x02, 0x03};
    uint8_t     data2[3] = {0x04, 0x05, 0x06};

    /* Header + recvbuf + regpos */
    SETIOV(&siov[0], &regacc, sizeof(regacc));
    SETIOV(&siov[1], &recvbuf, sizeof(recvbuf));
    SETIOV(&siov[2], &regops, sizeof(regops));

    /* Send commands */
    SETIOV(&siov[3], &cmds[0], sizeof(cmds[0]));
    SETIOV(&siov[4], &data0, sizeof(data0));
    SETIOV(&siov[5], &cmds[1], sizeof(cmds[1]));
    SETIOV(&siov[6], &data1, sizeof(data1));
    SETIOV(&siov[7], &cmds[2], sizeof(cmds[2]));
    SETIOV(&siov[8], &data2, sizeof(data2));

    /* recv header + buf */
    SETIOV(&riov[0], &regacc, sizeof(regacc));
    SETIOV(&riov[1], &recvbuf, sizeof(recvbuf));

    if ((status = devctlv(fd, DCMD_I2C_REGACC, 9, 2, siov, riov, &bytes))) {
        errno = status;
        perror("MASTER_SEND");
        exit(-1);
    }

    for (i = 0; i < bytes; ++i) {
        fprintf(stderr, "recv: 0x%x\n", recvbuf[i]);
    }

    exit(0);
}
Page updated: