Concepts
Informative
The model behind the I2C driver: its driver- and channel-level state machines, the transfer model in controller and target mode, and how events are handled. Non-binding; the normative rules live in I2c — Requirements.
State machine
The driver has a driver-wide state and, within the initialized state, a per-channel state. A channel is statically configured as a controller or a target; the two roles move through the same channel states with different triggers.
Driver state
stateDiagram-v2
[*] --> I2C_DRV_STATE_UNINIT : Reset
I2C_DRV_STATE_UNINIT --> I2C_DRV_STATE_INIT : I2c_Init()
I2C_DRV_STATE_INIT --> I2C_DRV_STATE_UNINIT : I2c_DeInit()
Driver state |
Meaning |
API calls accepted |
|---|---|---|
|
Not initialized (state after reset/startup) |
Only |
|
Initialized; service APIs are accepted |
All |
Channel state
Each channel moves through four states (I2c_ChannelStateType). I2c_Init leaves every channel
in IDLE; I2c_DeInit returns the driver (and its channels) to I2C_DRV_STATE_UNINIT.
Channel state |
Meaning |
|---|---|
|
Not initialized. |
|
Initialized; no transaction in progress. |
|
Controller: all data transferred, before STOP or a repeated START. Target: address matched, ready to set up the transfer. |
|
A transaction is ongoing. |
Controller mode — the integration code starts a transaction; the driver drives it to completion:
stateDiagram-v2
direction LR
[*] --> I2C_CH_STATE_IDLE : I2c_Init()
I2C_CH_STATE_IDLE --> I2C_CH_STATE_BUSY : I2c_StartTxTransaction() / I2c_StartRxTransaction()
I2C_CH_STATE_BUSY --> I2C_CH_STATE_READY : transfer complete
I2C_CH_STATE_READY --> I2C_CH_STATE_BUSY : repeated START (new transaction)
I2C_CH_STATE_READY --> I2C_CH_STATE_IDLE : STOP
I2C_CH_STATE_BUSY --> I2C_CH_STATE_IDLE : error
Target mode — an addressed transaction from the bus drives the channel:
stateDiagram-v2
direction LR
[*] --> I2C_CH_STATE_IDLE : I2c_Init()
I2C_CH_STATE_IDLE --> I2C_CH_STATE_READY : address match
I2C_CH_STATE_READY --> I2C_CH_STATE_BUSY : return from I2c_Callout_OnAddress
I2C_CH_STATE_BUSY --> I2C_CH_STATE_IDLE : transfer complete or error
Transfer model
A transfer has a direction (I2c_DirectionType): I2C_DIR_CONTROLLER_WRITE or
I2C_DIR_CONTROLLER_READ — always named from the controller’s point of view.
Controller mode. The integration code calls
I2c_StartTxTransaction(write) orI2c_StartRxTransaction(read) with the 7-bitdeviceAddr; the driver issues START, the address, and the data, then STOP — or a repeated START if a new transaction is started from within the completion callout before STOP.Target mode. On an address match the driver reports
I2c_Callout_OnAddresswith the direction; the integration code then callsI2c_StartTxTransaction/I2c_StartRxTransaction(withI2C_ADDR_UNSPECIFIED) to stage the response. If it does not, the driver transmits the configureddefault_data(controller read) or accepts and ignores the bytes (controller write).A NACK is reported through
I2c_Callout_OnErrorwithI2C_ERR_NACK_RECEIVED; bus and arbitration failures are runtime errors (see Errors).
The data buffer passed to a transaction MUST stay valid until the matching completion callout
(I2c_Callout_OnTransmission / I2c_Callout_OnReception) fires.
Event handling: interrupt or polling
For each channel, event handling is configured as either interrupt or polling:
Interrupt —
I2c_Initenables the I2C interrupt;I2c_Interruptservices it.Polling —
I2c_Initdisables the interrupt;I2c_PollFunctionservices the events.
Either way the same callouts are invoked: I2c_Callout_OnReception,
I2c_Callout_OnTransmission, I2c_Callout_OnError, and (target mode) I2c_Callout_OnAddress.
Controller transaction sequence
The informative view of a controller transfer (CHI-I2C-MUST-07, CHI-I2C-MUST-13, CHI-I2C-MUST-14):
sequenceDiagram
participant INTEG as Integration code
participant DRV as I2cDrv
participant HW as I2C HW
INTEG->>DRV: I2c_StartTxTransaction(ch, addr, data, len)
activate DRV
DRV->>HW: START + address (channel now BUSY)
DRV-->>INTEG: E_OK
deactivate DRV
HW->>DRV: I2c_Interrupt (byte transferred)
activate DRV
alt NACK on address or data
DRV->>INTEG: I2c_Callout_OnError(ch, I2C_ERR_NACK_RECEIVED)
else transfer complete
DRV->>INTEG: I2c_Callout_OnTransmission(ch, len)
end
Note over INTEG,HW: integration code then sends STOP, or a repeated START for a new transaction
deactivate DRV
Target transaction sequence
The informative view of a target transfer (CHI-I2C-MUST-08, CHI-I2C-MUST-15, CHI-I2C-MUST-16):
sequenceDiagram
participant INTEG as Integration code
participant DRV as I2cDrv
participant HW as I2C HW
HW->>DRV: I2c_Interrupt (address match)
activate DRV
DRV->>INTEG: I2c_Callout_OnAddress(ch, direction)
INTEG->>DRV: I2c_StartTxTransaction or I2c_StartRxTransaction (ch, I2C_ADDR_UNSPECIFIED)
DRV->>HW: transfer bytes (channel BUSY)
alt controller read (target transmits)
DRV->>INTEG: I2c_Callout_OnTransmission(ch, len)
else controller write (target receives)
DRV->>INTEG: I2c_Callout_OnReception(ch, len)
end
deactivate DRV
Key terms
For I2C glossary terms — controller/target node, 7-bit address, direction, repeated START, ACK/NACK, default data — see the glossary in the appendix.