This document specifies I2C hardware IP functionality. This module conforms to the [Comportable guideline for peripheral functionality.]({{< relref “doc/rm/comportability_specification/index.md” >}}) See that document for integration overview within the broader top level system.
1 lowRISC is avoiding the fraught terms master/slave and defaulting to host/target where applicable.
This IP block implements the I2C specification, though with some variation in nomenclature. For the purposes of this document, a “I2C Host” meets the specifications put forth for a “Master” device. Furthermore, a device which meets the specifications put forward for an I2C “Slave” device is here referred to as an “I2C Target” or “I2C Target Device”.
At a high-level, the I2C protocol is a clock-parallel serial protocol, with at least one host issuing transactions to a number of targets on the same bus. Though I2C optionally allows for multiple hosts on the same bus, we do not support this feature at this time.
Every transaction consists of a number of bytes transmitted, either from host-to-target or target-to-host. Each byte is typically followed by a single bit acknowledgement (ACK) from the receiving side. Typically each transaction consists of:
This protocol is generally quite flexible with respect to timing constraints, and slow enough to be managed by a software microcontroller, however such an implementation requires frequent activity on the part of the microcontroller. This IP presents a simple register interface and state-machine to manage the corresponding I/O pins directly using a byte-formatted programming model.
This IP block should be compatible with any target device covered by the I2C specification, operating at speeds up to 1 Mbaud. In order to support any target device, this IP issues addresses in 7-bit encoding whenever possible, as not all target devices may be able to support 10-bit encoding. (It remains the obligation of system designers to ensure that devices which cannot support 10-bit encoding remain in a 7-bit address space.) This IP also supports clock-stretching, should that be required by target devices.
{{< hwcfg “hw/ip/i2c/data/i2c.hjson” >}}
In devices which lack a true open drain buffer functionality, this IP implements a “virtual Open Drain” functionality. The SDA and SCL outputs are assumed to be connected to a tri-state buffer, with independent enable outputs for both signals.
Rather than toggling the buffer inputs, the buffer inputs are continuously asserted low, and instead the buffer enable signals are toggled. The SDA or SCL buffers are enabled for a logical “Low” output on the respective signal, and are disabled for logical “High” outputs. This arrangement allows the the output pins to float high if there is no conflict from external devices, or to be pulled low if there is a conflict (as is required for clock-stretching or--in future revisions-- muli-host functionality).
This arrangement is necessary for FPGA builds.
The I2C hardware interface consists of two external pins, SCL and SDA, whose behavior is described in the I2C specification. These pins are typically controlled by an internal state machine. However, there is a simpler “override” mode, by which these pins can be directly manipulated by software. This override mode is useful for troubleshooting or error-recovery.
To enter override mode, the register field {{< regref OVRD.TXOVRDEN >}} is asserted by software. In this state the output drivers scl_tx_o
and sda_tx_o
are controlled directly by the register fields {{< regref OVRD.SCLVAL >}} and {{< regref OVRD.SDAVAL >}}. When {{< regref OVRD.SCLVAL >}} and {{< regref OVRD.SDAVAL >}} are set high, the virtual open drain configuration will leave the output resistively pulled high, and controllable by remote targets. In this state, with SCL or SDA asserted high, the register fields {{< regref VAL.SCL_RX >}} and {{< regref VAL.SDA_RX >}} can be used to receive inputs (including remote acknowledgments) from target devices.
The state machine-controlled mode allows for higher-speed operation with less frequent software interaction. In this mode, the I2C pins are controlled by the I2C state machine, which in turn is controlled by a sequence of formatting indicators. The formatting indicators indicate:
The I2C reads each format indicator from the head of FMT_FIFO, and processes them in turn. If none of the flags are set for the format indicator, the I2C FSM simply transmits the Format Byte onto the SCL and SDA pins according to the specification, waits for acknowledgement, and then proceeds to the next format indicator. The format flags modulate the behavior as follows.
For standard mode, fast-mode and fast-mode plus, the timing requirements for each transaction are detailed in Table 10 of the I2C specification. In order to claim complete compatibility at each mode, the state machine timings need to be adapted to whether there are Standard-mode, Fast-mode and Fast-mode Plus targets on the bus. Furthermore, depending on the actual capacitance of the bus, even a bus with all Fast-mode Plus capable targets may have to operate at slower speeds than 1Mbaud. For example, the host may need to run at lower frequencies, as discussed in Section 5.2 of the specification, but the computation of the nominal frequency will depend on timing specifications in Table 10, in this case particularly, the limits on tLOW, tHIGH, tr, and tf. Assuming no clock stretching, for a given set of these four parameters the baud rate is then given to be: $$ 1/f_{SCL}=t_{LOW}+t_{HIGH}+t_{r}+t_{f}. $$
Thus in order to ensure compliance with the spec in any particular configuration, software will program the I2C host IP with explicit values for each of the following timing parameters, as defined in Figure 38 of the specification.
The values programmed into the registers {{< regref TIMING0 >}} through {{< regref TIMING4 >}} are to be expressed in units of the bus clock period. Note in order to ensure compliance with the I2C spec, firmware must program these registers with values within the ranges laid out in Table 10 of the specification. These values can be directly computed using DIFs given the desired speed standard, the desired operating frequency, and the actual line capacitance. These timing parameters are then fed directly to the I2C state machine to control the bus timing.
A detailed description of the algorithm for determining these parameters--as well as a couple of concrete examples--are given in the [Programmers Guide section of this document.]({{<relref “#timing-parameter-tuning-algorithm”>}})
A malfunctioning (or otherwise very slow) target device can hold SCL low indefinitely, stalling the bus. For this reason {{< regref TIMEOUT_CTRL >}} provides a clock-stretching timeout mechanism to notify firmware of this sort of condition. If {{< regref TIMEOUT_CTRL.EN >}} is asserted, an interrupt will be asserted when the IP detects that another device (a target or, in possible future revisions, an alternate host) has been holding SCL low for more than {{< regref TIMEOUT_CTRL.VAL >}} clock ticks.
This feature is added as a utility, though it is not required by the I2C specification. However, in some applications it could be used in protocols which build upon I2C. For instance, SMBus applications using this IP could in principle use this to support SMBus timeouts. (Note: This is just an example application of this feature. Other features may also be required for complete SMBus functionality.)
The I2C module has a few interrupts including general data flow interrupts and unexpected event interrupts.
If the RX FIFO exceeds the designated depth of entries, the interrupt rx_watermark
is raised to inform firmware. Firmware can configure the watermark value via the register {{< regref FIFO_CTRL.RXILVL >}}.
Meanwhile it the FMT FIFO level falls below a designated depth of entries the fmt_watermark
interrupt is raised. (Note that this behavior differs from similar interrupts in other modules, such as the UART IP module.) Firmware can configure the watermark value via the register {{< regref FIFO_CTRL.FMTILVL >}}.
If either FIFO receives an additional write request when its FIFO is full, the interrupt fmt_overflow
or rx_overflow
is asserted and the format indicator or character is dropped.
If the module transmits a byte, but receives no ACK signal, the nak
interrupt is usually asserted. In cases where a byte is transmitted and no ACK is expected or required, that byte should be submitted with NAKOK flag also asserted.
When the I2C module is in transmit mode, the scl_interference
or sda_interference
interrupts will be asserted if the IP identifies that some other device (host or target) on the bus is forcing either signal low and interfering with the transmission. If should be noted that the scl_interference
interrupt is not raised in the case when the target device is stretching the clock. (However, it may be raised if the target allows SCL to go high and then pulls SCL down before the end of the current clock cycle.)
A target device should never assert 0 on the SDA lines, and in the absence of multi-host support, the sda_interference
interrupt is raised whenever the host IP detects that another device is pulling SDA low.
On the other hand, it is legal for the a target device to assert SCL low for clock stretching purposes. With clock stretching, the target can delay the start of the following SCL pulse by holding SCL low between clock pulses. However the target device must assert SCL low before the start of the SCL pulse. If SCL is pulled low during an SCL pulse which has already started, this interruption of the SCL pulse will be registered as an exception by the I2C core, which will then assert the scl_interference
interrupt.
{{}} {signal: [ {name: ‘Clock’, wave: ‘p.....|.......|......’}, {name: ‘SCL Host Driver’, wave: ‘0.z..0|.z....0|..z.x.’}, {name: ‘SCL Target Driver’, wave: ‘z.....|0..z...|...0..’}, {name: ‘SCL bus’, wave: ‘0.u..0|...u..0|..u0..’}, {name: ‘scl_interference’, wave: ‘0.....|.......|....1.’}, ], head: {text: ‘SCL pulses: Normal SCL pulse (Cycle 3), SCL pulse with clock strectching (cycle 11), and SCL interference (interrupted SCL pulse)’,tick:1}} {{}}
Though normal clock stretching does not count as SCL interference, if the module detects that a target device has held SCL low and stretched the any given SCL cycle for more than {{< regref TIMEOUT_CTRL.VAL >}} clock ticks this will cause the stretch timeout interrupt to be asserted. This interrupt is suppressed, however, if {{< regref TIMEOUT_CTRL.EN >}} is deasserted low.
{{}} {signal: [ {name: ‘Clock’, wave: ‘p............’}, {name: ‘SCL Host Driver’, wave: ‘0..z.......x.’}, {name: ‘SCL Target Driver’, wave: ‘z0...........’}, {name: ‘SCL bus’, wave: ‘0............’}, {name: ‘TIMEOUT_CNTRL.VAL’, wave: ‘2............’, data: “8”}, {name: ‘SCL timeout counter’, wave: ‘2...22222222x’, data: ‘0 1 2 3 4 5 6 7 8’}, {name: ‘TIMEOUT_CNTRL.EN’, wave: ‘1............’}, {name: ‘scl_timeout’, wave: ‘0..........1.’}, ], head: {text: ‘SCL Timeout Example’,tick:-3}} {{}}
Except for START and STOP symbols, the I2C specification requires that the SDA signal remains constant whenever SCL is high. The sda_unstable
interrupt is asserted if, when receiving data or acknowledgement pulse, the value of the SDA signal does not remain constant over the duration of the SCL pulse.
Transactions are terminated by a STOP signal. The host may send a repeated START signal instead of a STOP, which also terminates the preceeding transaction. In both cases, the trans_complete
interrupt is asserted, in the beginning of a repeated START or at the end of a STOP.
To illustrate the behavior induced by various flags added to the formatting queue, the following figure shows a simplified version of the I2C_Host state machine. In this simplified view, many sequential states have been collapsed into four sub-sequences of states (shown in square brackets):
Within each of these sub-sequences, state transitions depend only on the SDA/SCL inputs or internal timers. Each sub-sequence has a terminal event--generically labeled “[completed]” which prompts the transition to another sequence or state.
However, all transitions which are dependent on formatting flags are shown explicitly in this figure.
After reset, the initialization of the I2C HWIP primarily consists of four steps:
Of the four initialization steps, the timing parameter initialization is the most involved. With so many timing parameters, it is essential to have dedicated device interface functions (DIF's) to determine appropriate values for the 10 timing parameters.
The values of these parameters will depend primarily on three bus details:
Based on the inputs, the timing paramaters may be chosen using the following algorithm:
The physical timing parameters tHD,STA, tSU,STA, tHD.DAT, tSU,DAT, tBUF, and tSTO, tHIGH, and tLOW all have minimum allowed values which depend on the choice of speed mode (standard-mode, fast-mode or fast-mode plus). Using the speed mode input, look up the appropriate minimum value (in ns) for each parameter (i.e. tHD,STA,min, tSU,STA,min, etc)
For each of these eight parameters, obtain an integer minimum by dividing the physical minimum parameter by the clock frequency and rounding up to the next highest integer: $$ \textrm{THIGH_MIN}=\lceil{t_{HIGH,min}/t_{clk}}\rceil $$ $$ \textrm{TLOW_MIN}=\lceil{t_{LOW,min}/t_{clk}}\rceil $$ $$ \textrm{THD_STA_MIN}= \lceil{t_{HD,STA,min}/t_{clk}}\rceil $$ $$ \textrm{TSU_STA_MIN}= \lceil{t_{SU,STA,min}/t_{clk}}\rceil $$ $$ \textrm{THD_DAT_MIN}= \lceil{t_{HD,DAT,min}/t_{clk}}\rceil $$ $$ \textrm{TSU_DAT_MIN}= \lceil{t_{HD,DAT,min}/t_{clk}}\rceil $$ $$ \textrm{T_BUF_MIN}= \lceil{t_{BUF,min}/t_{clk}}\rceil $$ $$ \textrm{T_STO_MIN}= \lceil{t_{STO,min}/t_{clk}}\rceil $$
Input the integer timing parameters, THD_STA_MIN, TSU_STA_MIN, THD_DAT_MIN, TSU_DAT_MIN, T_BUF_MIN and T_STO_MIN into their corresponding registers (TIMING2.THD_STA
, TIMING2.TSU_STA
, TIMING3.THD_DAT
, TIMING3.TSU_DAT
, TIMING4.T_BUF
, TIMING4.T_STO
)
TIMING0.THIGH
and TIMING0.TLOW
will be taken care of in a later step.Take the given values for for tf and tr and convert them to integer counts as well: $$ \textrm{T_R}= \lceil{t_{r}/t_{clk}}\rceil $$ $$ \textrm{T_F}= \lceil{t_{f}/t_{clk}}\rceil $$
Store T_R and T_F in their corresponding registers: TIMING1.T_R
and TIMING1.T_F
.
Based on the input speed mode, look up the maximum permissable SCL frequency (fSCL,max)and calculate the minimum permissable SCL period: $$ t_{SCL,min}= 1/f_{SCL,max} $$
As with each of the other physical parameters convert tSCL,min and, if provided, the tSCL,user to integers, MINPERIOD and USERPERIOD.. $$ MINPERIOD = \lceil{t_{SCL,min}/t_{clk}}\rceil $$ $$ USERPERIOD = \lceil{t_{SCL,user}/t_{clk}}\rceil $$
Let PERIOD=max(MINPERIOD, USERPERIOD).
Each SCL cycle will now be at least PERIOD clock cycles in duration, divided between four segments: T_R, THIGH, T_F, and TLOW.
THIGH is then set to satisfy both constraints in the desired SCL period and in the minimum permissable values for tHIGH: $$ \textrm{TIMING0.THIGH}=\max(\textrm{PERIOD}-\textrm{T_R} - \textrm{TIMING0.TLOW} -\textrm{T_F}, \textrm{THIGH_MIN}) $$
The following tables show a couple of examples for calculating timing register parameters for Fast-mode Plus devices. Both examples assume a desired datarate of 1 Mbaud (the bus maximum) for an SCL period of 1us, and an internal device clock period of 3ns.
Parameter | Spec. Min. (ns) | Reg. Val. | Phys. Val (ns) | Comment |
---|---|---|---|---|
TIMING0.THIGH | 260 | 120 | 360 | Chosen to satisfy SCL Period Minimum |
TIMING0.TLOW | 500 | 167 | 501 | Spec. tLOW Minimum |
TIMING1.T_F | 20ns * (VDD/5.5V) | 7 | 21 | Signal slew-rate should be controlled |
TIMING1.T_R | 0 | 40 | 120 | Based on pull-up resistance, line capacitance |
SCL Period | 1000 | N/A | 1002 | Constraint on THIGH+TLOW+T_R+T_F |
TIMING2.THD_STA | 260 | 87 | 261 | Spec. Minimum |
TIMING2.TSU_STA | 260 | 87 | 261 | Spec. Minimum |
TIMING3.THD_DAT | 0 | 0 | 0 | Spec. Minimum |
TIMING3.TSU_DAT | 260 | 87 | 261 | Spec. Minimum |
TIMING4.T_BUF | 500 | 167 | 501 | Spec. Minimum |
TIMING4.T_STO | 260 | 87 | 161 | Spec. Minimum |
This next example shows how the first SCL timing registers: TIMING0
and TIMING1
are altered in a high-capacitance Fast-mode Plus bus, where the physical value of tr driven to an atypical value of 400ns. As in the previous example the integer register values are determined based on a system clock period, tclk, of 3ns. All other parameters in registers TIMING2
, TIMING3
, TIMING4
are unchanged from the previous example.
Parameter | Spec. Min. (ns) | Reg. Val. | Phys. Val (ns) | Comment |
---|---|---|---|---|
TIMING0.THIGH | 260 | 87 | 261 | Spec. tHIGH Minimum |
TIMING0.TLOW | 500 | 167 | 501 | Spec. tLOW Minimum |
TIMING1.T_F | 20ns * (VDD/5.5V) | 7 | 21 | Signal slew-rate should be controlled |
TIMING1.T_R | 0 | 134 | 402 | Atypicallly high line capacitance |
SCL Period | 1000 | N/A | 395 | Forced longer than minimum by long T_R |
{{< dif_listing “sw/device/lib/dif/dif_i2c.h” >}}
{{<registers “hw/ip/i2c/data/i2c.hjson” >}}