SIM_INTERFACE(i2c_bus) { int (*start)(conf_object_t *i2c_bus, uint8 address); int (*stop)(conf_object_t *i2c_bus); uint8 (*read_data)(conf_object_t *i2c_bus); void (*write_data)(conf_object_t *i2c_bus, uint8 value); int (*register_device)(conf_object_t *i2c_bus, conf_object_t *device, uint8 address, uint8 mask, i2c_device_flag_t flags); void (*unregister_device)(conf_object_t *i2c_bus, conf_object_t *device, uint8 address, uint8 mask); }; #define I2C_BUS_INTERFACE "i2c_bus"
The i2c_bus
interface is implemented by the I2C
bus. The interface is used by I2C devices to communicate with the
I2C bus.
To connect an I2C device to an I2C bus, first you call
register_device with a 7-bit address and
mask. The address is actually an address pattern. When
there is traffic on the I2C bus (as initiated by a call to the bus
interface start function), the target address is matched
against each registered device by checking if (target_address ^
device_address) & device_mask == 0
. The
flags attribute sets the type of connection. The
alternatives are exclusive
or
shared
. An I2C device connected
exclusive
can not share a transfer with another I2C
device. An I2C device connected shared
supports that
other I2C devices connected shared
to the I2C bus
handles the same transfer. The register_device function
returns 0
on success and -1
on failure.
Use unregister_device to disconnect an I2C device from the I2C bus. To completely remove a device use the same address and mask attributes as when the device was registered. An I2C device can also remove some part of the address match by unregister 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 function with
address as argument. 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.
The start function returns 0
on success and -1
on failure.
An I2C transfer should be terminated by a master I2C device when the bus is
no longer needed. This is done by calling the stop function. This
function always returns 0
.
I2C devices implement the i2c_device
interface. Both
the i2c_device
interface and the
i2c_bus
interface has identical read_data
and write_data functions to transfer data over the
bus. The i2c_device
also has set_state
function, which is used by the I2C bus to set the I2C device
state. The states are I2C_idle
,
I2C_slave_transmit
, and
I2C_slave_receive
. The default state is
I2C_idle
.
Here are the steps for a transfer:
1.
The I2C master device calls start in the
I2C bus with 7-bit address and 1-bit read/write flag.
2.
The I2C bus calls the set_state in the I2C
slave device with I2C_slave_transmit
or
I2C_slave_receive
as argument depending on the 1-bit
read/write flag. The I2C slave accepts the state change by
returning 0.
3.
I2C bus returns 0
to the I2C master if the
start command in 1
was successful. The I2C bus can report
failure for several reasons, there are another ongoing transfer,
can not find any device with the address provided, I2C slave did
not except state change etc.
4.
The I2C master calls the I2C buses
read_data or write_data depending if it
wants to read from or write to the I2C slave. The I2C bus relays the
call to the I2C slave read_data or
write_data function. The I2C slave have no way to report
errors, the I2C master expects the I2C slave to be able to handle
all calls without any problem. The I2C bus can do step 4
several times before terminating the transfer.
5.
The I2C master calls the stop function
when it wants to terminate the transfer. This causes the I2C bus to
call the set_state function in the I2C slave with
I2C_idle
as argument. The transfer is now completed.