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 timeoutBV_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
- It is only necessary to check
- 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 clearsstate.i2cStatus
- It is only necessary to check
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()
)
- Repeated start condition (
- 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()
)
- Repeated start condition (
- 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()
)
- Repeated start condition (
- 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
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.