I2C Master

Description

I2C master interface

This resource implements a bit-banged Inter-Integrated Circuit (I2C) master interface, which allows Sensor Controller task code to perform I2C transfers. The interface consists of the following signals:

  • SCL open-drain - Serial clock (controlled by master, stretched by slave)
  • SDA open-drain - Serial data (bi-directional)

External pull-up resistors are required for SCL and SDA. The resistor values must comply with the requirements in the I2C Specification. Typical values are 2.2 kOhm or 10 kOhm, depending on bus load and serial clock frequency.

General features:

  • I2C master, supporting 7-bit address and 8-bit data
  • Configurable serial clock frequency: 400 or 100 kHz
  • Configurable I/O drive strength: 2 mA, 4 mA (default), or 8 mA
  • Clock stretching by I2C slave, with configurable timeout up to 20 ms

It is recommended to use the highest supported clock frequency and minimize periodical I2C communication, since there is significant leakage through the pull-up resistors while SDA and SCL are driven low.

High-Level Procedures for I2C Device Register Access

Use the high-level I2C device procedures to access register-based I2C devices, with 8-bit address and 8/16-bit value. These procedures can be used to operate most sensors with I2C interface:

  • 8-bit register value:
    • i2cDeviceWriteReg8()
    • i2cDeviceReadReg8()
  • 16-bit register value, LSB at specified address, MSB at specified address + 1:
    • i2cDeviceWriteReg16LsbFirst()
    • i2cDeviceReadReg16LsbFirst()
  • 16-bit register value, MSB at specified address, LSB at specified address + 1:
    • i2cDeviceWriteReg16MsbFirst()
    • i2cDeviceReadReg16MsbFirst()

Low-Level Procedures for Basic I2C Operations

Use the low-level I2C procedures to perform operations that are not supported by the high-level procedures, or to optimize complex operations:

  • Conditions:
    • i2cStart()
    • i2cRepeatedStart()
    • i2cStop()
  • Single-byte data transfer:
    • i2cTx()
    • i2cRxAck()
    • i2cRxNack()

I2C Slave 7-Bit Address

The 7-bit I2C slave address must be shifted left by 1 bit, both for high-level and low-level procedures.

It is recommended to create constants for the I2C addresses, with this shift included. These constants can then be used without additional shifting with both high-level and low-level procedures.

Error handling

Error conditions are handled as follows:

  • There are two status bits, which are stored in state.i2cStatus . These bits will be set when errors occur during I2C communication:
    • BV_I2C_STATUS_TIMEOUT - Inidicates that the I2C slave has stretched SCL beyond the configured timeout
    • BV_I2C_STATUS_TX_NACK - Inidicates missing acknowledgment for a transmitted byte
  • If one or more state.i2cStatus bits have been set, any subsequent data transfer operations will be ignored. Start and stop conditions will still be performed.
  • For the high-level procedures (see the example below):
    • It is only necessary to check state.i2cStatus after a sequence of transactions, not after every transaction
    • Software must clear state.i2cStatus manually
  • For the low-level procedures (see the example below):
    • It is only necessary to check state.i2cStatus after each transaction, not after every byte
    • The i2cStart() procedure clears state.i2cStatus

There is no detection of bus arbitration errors.

Examples

High-Level Access: Device Configuration

// Configure and start temperature and humidity measurement
i2cDeviceWriteReg8(HDC_I2C_ADDR, HDC_REG_INT_ENABLE, BV_HDC_INT_ENABLE_TEMP_HIGH);
i2cDeviceWriteReg8(HDC_I2C_ADDR, HDC_REG_CFG_RES_INT_AMM, (BV_HDC_CFG_INT_PIN_DRIVE | BV_HDC_CFG_INT_ACTIVE_LOW) | BV_HDC_CFG_AMM_1_HZ);
i2cDeviceWriteReg8(HDC_I2C_ADDR, HDC_REG_CFG_MEAS, BV_HDC_CFG_MEAS_HUM_TEMP | BV_HDC_CFG_MEAS_TRIG);

// Handle I2C errors, if any ...
if (state.i2cStatus != 0x0000) {
    ... Handle errors ...
    state.i2cStatus = 0x0000;
}

Low-Level Access: Optimized Data Polling

// Accelerometer (I2C address 0x43+W): Write X register address (0x04)
i2cStart();
i2cTx(0x86 | I2C_OP_WRITE);
i2cTx(0x04);

// If successful ...
if (state.i2cStatus == 0x0000) {

    // Accelerometer (I2C address 0x43+R): Read X/Y/Z register values
    i2cRepeatedStart();
    i2cTx(0x86 | I2C_OP_READ);
    i2cRxAck(output.x);
    i2cRxAck(output.y);
    i2cRxNack(output.z);
}
i2cStop();

// Handle I2C errors, if any ...
if (state.i2cStatus != 0x0000) {
    ... Handle errors ...
}

Procedures Overview

Name Brief description
i2cDeviceReadReg16LsbFirst() Reads a 16-bit value, LSB (least significant byte) first, from a register with 8-bit address in an I2C device. More …
i2cDeviceReadReg16MsbFirst() Reads a 16-bit value, MSB (most significant byte) first, from a register with 8-bit address in an I2C device. More …
i2cDeviceReadReg8() Reads an 8-bit value from a register with 8-bit address in an I2C device. More …
i2cDeviceWriteReg16LsbFirst() Writes a 16-bit value, LSB (least significant byte) first, to a register with 8-bit address in an I2C device. More …
i2cDeviceWriteReg16MsbFirst() Writes a 16-bit value, MSB (most significant byte) first, to a register with 8-bit address in an I2C device. More …
i2cDeviceWriteReg8() Writes an 8-bit value to a register with 8-bit address in an I2C device. More …
i2cRepeatedStart() Transmits repeated start condition on the I2C bus. More …
i2cRxAck() Receives with acknowledgment a single byte over I2C. More …
i2cRxNack() Receives without acknowledgment a single byte over I2C. More …
i2cStart() Clears state.i2cStatus and transmits start condition on the I2C bus. More …
i2cStop() Transmits stop condition on the I2C bus. More …
i2cTx() Transmits a single byte over I2C. More …

Constants

Name Description
BV_I2C_STATUS_TIMEOUT Status bit: Clock stretching timeout has occurred
BV_I2C_STATUS_TX_NACK Status bit: Acknowledgment value for the last i2cTx() call (0 = ACK, 1 = NACK)
I2C_BASE_DELAY Protocol base delay, in instruction cycles
I2C_OP_READ Bit 0 of the I2C address byte of an I2C read operation
I2C_OP_WRITE Bit 0 of the I2C address byte of an I2C write operation

Global Variables

Name Description
state.i2cStatus I2C master status

Procedures

i2cDeviceReadReg16LsbFirst

Prototype: i2cDeviceReadReg16LsbFirst(#i2cAddr, regAddr8; value16)

Reads a 16-bit value, LSB (least significant byte) first, from a register with 8-bit address in an I2C device.

This is equivaluent to the following sequence:

  • Start condition ( i2cStart() , status bits not cleared)
  • Transmit I2C address + W ( i2cTx() )
  • Transmit 8-bit register address ( i2cTx() )
  • If successful:
    • Repeated start condition ( i2cRepeatedStart() )
    • Transmit I2C address + R ( i2cTx() )
    • Receive bits [7:0] of 16-bit register value ( i2cRxAck() )
    • Receive bits [15:8] of 16-bit register value ( i2cRxNack() )
  • Stop condition ( i2cStop() )

Parameter value(s)

  • #i2cAddr : I2C slave 7-bit address, shifted left one bit ([7:1] = address, [0] = zero)
  • regAddr8 : Register address

Return value(s)

  • value16 : Register value

i2cDeviceReadReg16MsbFirst

Prototype: i2cDeviceReadReg16MsbFirst(#i2cAddr, regAddr8; value16)

Reads a 16-bit value, MSB (most significant byte) first, from a register with 8-bit address in an I2C device.

This is equivaluent to the following sequence:

  • Start condition ( i2cStart() , status bits not cleared)
  • Transmit I2C address + W ( i2cTx() )
  • Transmit 8-bit register address ( i2cTx() )
  • If successful:
    • Repeated start condition ( i2cRepeatedStart() )
    • Transmit I2C address + R ( i2cTx() )
    • Receive bits [15:8] of 16-bit register value ( i2cRxAck() )
    • Receive bits [7:0] of 16-bit register value ( i2cRxNack() )
  • Stop condition ( i2cStop() )

Parameter value(s)

  • #i2cAddr : I2C slave 7-bit address, shifted left one bit ([7:1] = address, [0] = zero)
  • regAddr8 : Register address

Return value(s)

  • value16 : Register value

i2cDeviceReadReg8

Prototype: i2cDeviceReadReg8(#i2cAddr, regAddr8; value8)

Reads an 8-bit value from a register with 8-bit address in an I2C device.

This is equivaluent to the following sequence:

  • Start condition ( i2cStart() , status bits not cleared)
  • Transmit I2C address + W ( i2cTx() )
  • Transmit 8-bit register address ( i2cTx() )
  • If successful:
    • Repeated start condition ( i2cRepeatedStart() )
    • Transmit I2C address + R ( i2cTx() )
    • Receive 8-bit register value ( i2cRxNack() )
  • Stop condition ( i2cStop() )

Parameter value(s)

  • #i2cAddr : I2C slave 7-bit address, shifted left one bit ([7:1] = address, [0] = zero)
  • regAddr8 : Register address

Return value(s)

  • value8 : Register value

i2cDeviceWriteReg16LsbFirst

Prototype: i2cDeviceWriteReg16LsbFirst(#i2cAddr, regAddr8, value16)

Writes a 16-bit value, LSB (least significant byte) first, to a register with 8-bit address in an I2C device.

This is equivaluent to the following sequence:

  • Start condition ( i2cStart() , status bits not cleared)
  • Transmit I2C address + W ( i2cTx() )
  • Transmit 8-bit register address ( i2cTx() )
  • Transmit bits [7:0] of 16-bit register value ( i2cTx() )
  • Transmit bits [15:8] of 16-bit register value ( i2cTx() )
  • Stop condition ( i2cStop() )

Parameter value(s)

  • #i2cAddr : I2C slave 7-bit address, shifted left one bit ([7:1] = address, [0] = zero)
  • regAddr8 : Register address
  • value16 : Register value

i2cDeviceWriteReg16MsbFirst

Prototype: i2cDeviceWriteReg16MsbFirst(#i2cAddr, regAddr8, value16)

Writes a 16-bit value, MSB (most significant byte) first, to a register with 8-bit address in an I2C device.

This is equivaluent to the following sequence:

  • Start condition ( i2cStart() , status bits not cleared)
  • Transmit I2C address + W ( i2cTx() )
  • Transmit 8-bit register address ( i2cTx() )
  • Transmit bits [15:8] of 16-bit register value ( i2cTx() )
  • Transmit bits [7:0] of 16-bit register value ( i2cTx() )
  • Stop condition ( i2cStop() )

Parameter value(s)

  • #i2cAddr : I2C slave 7-bit address, shifted left one bit ([7:1] = address, [0] = zero)
  • regAddr8 : Register address
  • value16 : Register value

i2cDeviceWriteReg8

Prototype: i2cDeviceWriteReg8(#i2cAddr, regAddr8, value8)

Writes an 8-bit value to a register with 8-bit address in an I2C device.

This is equivaluent to the following sequence:

  • Start condition ( i2cStart() , status bits not cleared)
  • Transmit I2C address + W ( i2cTx() )
  • Transmit 8-bit register address ( i2cTx() )
  • Transmit 8-bit register value ( i2cTx() )
  • Stop condition ( i2cStop() )

Parameter value(s)

  • #i2cAddr : I2C slave 7-bit address, shifted left one bit ([7:1] = address, [0] = zero)
  • regAddr8 : Register address
  • value8 : Register value

i2cRepeatedStart

Prototype: i2cRepeatedStart()

Transmits repeated start condition on the I2C bus.

i2cRxAck

Prototype: i2cRxAck(rxValue)

Receives with acknowledgment a single byte over I2C.

Return value(s)

  • rxValue : The value received

i2cRxNack

Prototype: i2cRxNack(rxValue)

Receives without acknowledgment a single byte over I2C.

Return value(s)

  • rxValue : The value received

i2cStart

Prototype: i2cStart()

Clears state.i2cStatus and transmits start condition on the I2C bus.

i2cStop

Prototype: i2cStop()

Transmits stop condition on the I2C bus.

i2cTx

Prototype: i2cTx(txValue)

Transmits a single byte over I2C. The received acknowledgment value is stored in state.i2cStatus .

Parameter value(s)

  • txValue : The value to be transmitted