i2c_device i2c_master
API Reference Manual  /  4 Model-to-Model Interfaces  / 

i2c_link

Description
SIM_INTERFACE(i2c_link) {
        void (*register_slave_address)(conf_object_t *i2c_link,
                                       conf_object_t *slave,
                                       uint32 address, uint32 mask);
        void (*unregister_slave_address)(conf_object_t *i2c_link,
                                  conf_object_t *slave,
                                  uint32 address, uint32 mask);

        void (*register_bridge)(conf_object_t *i2c_link,
                                conf_object_t *bridge);

        void (*disconnect_device)(conf_object_t *i2c_link,
                                  conf_object_t *device);

        void (*start_request)(conf_object_t *i2c_link, conf_object_t *master,
                              uint32 address);
        void (*read_request)(conf_object_t *i2c_link, conf_object_t *master);
        void (*ack_read_request)(conf_object_t *i2c_link, conf_object_t *master,
                                 i2c_status_t ack);
        void (*write_request)(conf_object_t *i2c_link, conf_object_t *master,
                              uint8 value);

        void (*read_response)(conf_object_t *i2c_link, conf_object_t *slave,
                                 uint8 value);
        void (*ack_read_response)(conf_object_t *i2c_link,
                                  conf_object_t *slave);
        void (*write_response)(conf_object_t *i2c_link, conf_object_t *slave,
                                  i2c_status_t status);
        void (*start_response)(conf_object_t *i2c_link, conf_object_t *slave,
                                  i2c_status_t status);
        void (*stop)(conf_object_t *i2c_link, conf_object_t *master);
};

#define I2C_LINK_INTERFACE "i2c_link"

The i2c_link interface is implemented by the I2C link. The interface is used by I2C devices to communicate with the I2C link.

An I2C device implements either the i2c_slave or the i2c_master interface, or both. You don't need to do anything to connect an I2C master device to a link.

To connect an I2C slave device to an I2C link, call register_slave_address with an address pattern consisting of the address and mask parameters. When there is traffic on the I2C link (as initiated by a call to the link interface start_request function), the target address is matched against each registered device by checking if (target_address ^ device_address) & device_mask == 0; i.e., the bits that are set to 1 in the mask indicates which bits in the address that must match.

There are three different addressing modes defined by this protocol: 7-bit addressing, General call, and 10-bit addressing. 7-bit addressing is by far the most common addressing mode, and at the moment the only one supported by the official i2c_link device. When 7-bit addressing is used, the address fits into the lower 8 bits of the address parameter; in other addressing modes more than 8 bits can be used, but the addressing mode can always be deduced from the lower 8 address bits.

In 7-bit addressing mode, the address of an I2C device is encoded as an even 8-bit number, in the range 0x10 - 0xef. In other words, address ranges 0x00 - 0x0f and 0xf0 - 0xff are reserved for other addressing modes, and the 7-bit address is defined by bits 7 to 1 (little-endian) of the 8-bit encoded address. Bit 0 is reserved as a read/write bit for the start_request function, and should be 0 in both address and 0 in mask, while bits 8 to 31 should be 0 in address and 1 in mask.

It is an error to register two I2C slave devices to the same 7-bit address.

Use disconnect_device to completely disconnect an I2C slave device from the I2C link. If you just intend to disable the I2C functionality of the device (without disconnecting the wire), use unregister_slave_address, and use the same address and mask attributes as when the device was registered. An I2C slave device can also remove some part of the address match by unregistering itself with a different mask.

An I2C transfer is initiated by a master I2C device. The I2C device responding to the transfer is called slave. The master starts a transfer by calling the start_request function with address as argument. In 7-bit addressing mode, the address is the 7-bit address plus a read-write bit (read-write = 0 → slave-receive, read-write = 1 → slave-transmit). The read-write bit is the least significant bit. This means that all odd values sent to start function initiates a transfer where the master is requesting data from the slave.

I2C slave devices implement the i2c_slave interface. The i2c_slave interface and the i2c_link interface have identical start_request, read_request, ack_read_request and write_request functions to transfer data over the link. See the i2c_slave interface for the definitions of these functions.

I2C master devices implement the i2c_master interface, which has the functions start_response, read_response, ack_read_response and write_response in common with the i2c_link interface. The only difference in definition is that the I2C_status_bus_busy value is not allowed for the status parameter of start_response in the i2c_link interface, while it is allowed in the i2c_master interface. The definitions of these functions can be found in the documentation of the i2c_master interface.

Here are the steps for a transfer:

  1. The I2C master device calls start_request in the I2C link with 7-bit address and 1-bit read/write flag.
  2. The I2C link calls start_request in the I2C slave device, forwarding the address given by the master. If there is no slave device on the given address, or if the link is busy with another connection, the I2C link instead terminates the connection by calling start_response in the master device with I2C_status_noack or I2C_status_bus_busy as status code.
  3. The I2C slave device calls start_response in the I2C link, with either I2C_status_success or I2C_status_noack as status code.
  4. The I2C link calls start_response in the I2C master device. This terminates the transfer if the status wasn't I2C_status_success.
  5. The I2C master calls the read_request or write_request function in the I2C link, depending on the read/write bit given in the start_request message. The I2C link relays the call to the I2C slave read_request or write_request function. The slave responds with a call to read_response or write_response, which the link relays to the I2C master device. If it's a read transfer, the master calls the ack_read_request function in the I2C link, which is relayed to the slave. The slave responds with a call to the ack_read_response in the I2C link, which is relayed to the master. This step can be repeated any number of times.
  6. The I2C master ends the transfer either by calling start_request again (possibly with a different slave address), or by calling stop in the I2C link. The link will respond by calling stop in the slave device (if it wasn't a repeated start with the same device as slave), and if it was a start command, relay it to the slave device as in step 2 above. Before a master device is allowed to call start_request or stop, it must wait for any pending read_response or write_response call from a slave device. In a read transfer, the last call to the function ack_read_request should pass I2C_status_noack in the ack parameter.

In total, an I2C link can be in nine different states:

  1. Idle, waiting for start_request call from any master device
  2. Waiting for a start_response call from the slave device (write mode)
  3. Waiting for a write_request (or stop or repeated start_request) call from the current master device
  4. Waiting for a write_response call from the slave device
  5. Waiting for start_response call from the slave device (read mode)
  6. Waiting for a read_request (or stop or repeated start_request) call from the current master device
  7. Waiting for a read_response call from the slave device
  8. Waiting for an ack_read_request call from the current master device
  9. Waiting for an ack_read_response call from the slave device

During a transfer, the actual data is delivered by the write_request and read_response function calls. The data is always delivered one byte at a time.

There are two addressing modes apart from the 7-bit addressing mode described above:

Note that a single call to register_slave_address may only register addresses from one addressing mode; it is an error to supply an address pattern that matches addresses from different addressing modes.

During write operations, ACK bits are sent in the status parameter of the write_response functions. During read operations, the master device sends the ACK bit with the ack_read_request function after the read_response function has been called by the slave. The slave should respond with a call to the ack_read_response function, which is relayed to the master. The value of the ACK bit controls which functions that are allowed as the next operation by the master device: If the ACK bit is 0 (i.e., I2C_status_success), the next operation must be a read_request, while ACK = 1 (I2C_status_noack) means that the next operation must be stop or a repeated start_request. It is an error to violate this rule: If the master device's software attempts to issue a STOP or START condition after a read with ACK=0, the master device should catch the error and log a spec_violation message.

The register_bridge function is used to register a device that implements the i2c_bridge interface. The I2C link device will use the i2c_bridge interface to keep the I2C bridge device updated with which slave addresses on the link that have something registered on them; this is mainly useful when implementing a bridge between i2c links. For more information, see the documentation on the i2c_bridge interface.

The disconnect_device function completely disconnects a device (slave, master, bridge or any combination thereof) from the link. The link checks which i2c interfaces the device implements, and cleanly removes all its references to the device. This mainly has following effects:

Hence, disconnect_device an I2C device which has had any kind of interaction with an I2C link, must always use disconnect_device when disconnecting.

Execution Context
Cell Context for all methods.

i2c_device i2c_master