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

I2C_DRV_STATE_UNINIT

Not initialized (state after reset/startup)

Only I2c_Init()

I2C_DRV_STATE_INIT

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

I2C_CH_STATE_UNINIT

Not initialized.

I2C_CH_STATE_IDLE

Initialized; no transaction in progress.

I2C_CH_STATE_READY

Controller: all data transferred, before STOP or a repeated START. Target: address matched, ready to set up the transfer.

I2C_CH_STATE_BUSY

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
    

See I2c — Requirements (CHI-I2C-MUST-04CHI-I2C-MUST-08).

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) or I2c_StartRxTransaction (read) with the 7-bit deviceAddr; 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_OnAddress with the direction; the integration code then calls I2c_StartTxTransaction / I2c_StartRxTransaction (with I2C_ADDR_UNSPECIFIED) to stage the response. If it does not, the driver transmits the configured default_data (controller read) or accepts and ignores the bytes (controller write).

  • A NACK is reported through I2c_Callout_OnError with I2C_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:

  • InterruptI2c_Init enables the I2C interrupt; I2c_Interrupt services it.

  • PollingI2c_Init disables the interrupt; I2c_PollFunction services 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.