I2C(2) — QNX implementation

There is a resource manager interface, for applications to access a master. The resource manager layer registers a device name (usually /dev/i2c0).

Interface between applications and resmgr:  devctl() commands, such as

  • DCMD_I2C_SEND It executes a master send transaction and returns when the transaction is complete.
  • DCMD_I2C_RECV command executes a master receive transaction. It returns when the transaction is complete.
  • DCMD_I2C_SENDRECV command executes a send followed by a receive. This sequence is typically used to read a slave device’s register value. When multiple applications access the same slave device, it is necessary to execute this sequence atomically to prevent register reads from being interrupted.

A typical one-byte write function in an application:

struct send_recv
{
    i2c_send_t hdr;
    uint8_t buf[2];
} i2c_data;
	int error = EOK;

	i2c_data.buf[0] = reg_addr;
	i2c_data.buf[1] = data;
	i2c_data.hdr.len = 2;
	i2c_data.hdr.slave.addr = slave_addr;
	i2c_data.hdr.slave.fmt = I2C_ADDRFMT_7BIT;
	i2c_data.hdr.stop = 1;

	error = devctl(fd, DCMD_I2C_SEND, &i2c_data, sizeof (i2c_data), NULL);

A typical one-byte read function in an application:

struct send_recv
{
    i2c_sendrecv_t hdr;
    uint8_t buf[2];
} i2c_data;

int error = EOK;
int retry, timeout = 10;

i2c_data.buf[0] = reg_addr;
i2c_data.hdr.send_len = 1;
i2c_data.hdr.recv_len = 1;
i2c_data.hdr.slave.addr = dev_addr;
i2c_data.hdr.slave.fmt = I2C_ADDRFMT_7BIT;
i2c_data.hdr.stop = 1;
error = devctl(fd, DCMD_I2C_SENDRECV, &i2c_data, sizeof (i2c_data), NULL);

Interface between resource manager and the hardware driver: a list of functions.

  • upon receiving DCMD_I2C_SEND, resmgr calls h/w function send().
  • upon receiving DCMD_I2C_SENDRECV, resmgr calls .send() first, then .recv() function.

I2C hardware driver implements the list of functions. The implementation is h/w dependent. The description below is an example which is done for a specific I2C controller.

  • .send function
    • send the slave address to the bus via a few out32()s .
    • wait for ACK (could be an interrupt).
    • send the register address to the bus via out32() calls.-— buf[0]
    • wait for ACK (could be interrupt).
    • send each data byte to the bus via out32() calls. — buf[1], buf[2],,
    • wait for ACK (could be interrupt).
  • . recv function
    • send the slave address to the bus: a few out32()s.
    • wait for ACK (could be an interrupt).
    • initiate READ via out32() for each byte requested.
    • wait for the READ done.

More about the implementation

  • The resmgr is single-threaded, and each DCMD is handled in a synchronized way (returns until the requested transaction is complete) . As a result,
    • when multiple applications try to access different I2C slaves, respectively, at the same time, there is no issue — the DCMD commands are taken care of one by one, without being interrupted by others.
    • when multiple applications try to access the same I2C slave at the same time, although the individual command can be done without interruption, there could be race conditions. This needs to be avoided.
  • The existing resmgr and i2c drivers only work in single-thread resmgr environment. If there are multiple threads handling CDMD commands, it will be a total mess..
    • DCMD_I2C_SEND/RECV leads to a send or receive transaction. Although the transaction in the physical level can be considered “atomic”, the implementation in resmgr and h/w driver is not atomic at all: there are quite some lines of code, there are a few calls to out32()s, and most critically, there is no mutex or other protections in either resmgr or driver.
  • If there are multiple masters, a separate instance of the resource manager should be run for each master.
    • the option ‘c’ looks for this purpose: ‘c’ is used to specify the number of threads. once specified, each thread will start a resource manager.
    • in this case, although the arbitration is supported in the physical layer, some synchronization will be needed between different master/resmgr.

Leave a comment