Low-level I2C peripheral driver. More...

Detailed Description

Low-level I2C peripheral driver.

This interface provides a simple abstraction to use the MCUs I2C peripherals. It provides support for 7-bit and 10-bit addressing and can be used for different kind of register addressing schemes.

Usage

Example for reading a 8-bit register on a device, using a 10-bit device address and 8-bit register addresses and using a RESTART condition (CAUTION: this example does not check any return values...):

// initialize the bus (this is normally done during boot time)
i2c_init(dev);
...
// before accessing the bus, we need to acquire it
i2c_acquire(dev);
// next we write the register address, but create no STOP condition when done
i2c_write_byte(dev, device_addr, reg_addr, (I2C_NOSTOP | I2C_ADDR10));
// and now we read the register value
i2c_read_byte(dev, device_addr, &reg_value, I2C_ADDR10);
// finally we have to release the bus

Example for writing a 16-bit register with 16-bit register addressing and 7-bit device addressing:

// initialize the bus
i2c_init(dev);
...
// first, acquire the shared bus again
i2c_acquire(dev);
// write the 16-bit register address to the device and prevent STOP condition
i2c_write_byte(dev, device_addr, reg_addr, I2C_NOSTOP);
// and write the data after a REPEATED START
i2c_write_bytes(dev, device_addr, reg_data, 2, 0);
// and finally free the bus again

Pull Resistors

The I2C signal lines SDA/SCL need external pull-up resistors which connect the lines to the positive voltage supply Vcc. The I2C driver implementation should enable the pin's internal pull-up resistors. There are however some use cases for which the internal pull resistors are not strong enough and the I2C bus will show faulty behavior. This can for example happen when connecting a logic analyzer which will raise the capacitance of the bus. In this case you should make sure you connect external pull-up resistors to both I2C bus lines.

The minimum and maximum resistances are computed by:

\begin{eqnarray*} R_{min} &=& \frac{V_{DD} - V_{OL(max)}} {I_{OL}}\\ R_{max} &=& \frac{t_r} {(0.8473 \cdot C_b)} \end{eqnarray*}


where:
$ V_{DD} =$ Supply voltage, $ V_{OL(max)} =$ Low level voltage, $ I_{OL} =$ Low level output current, $ t_r =$ Signal rise time, $ C_b =$ Bus capacitance

The pull-up resistors depend on the bus speed. Some typical values are:
Normal mode: 10kΩ
Fast mode: 2kΩ
Fast plus mode: 2kΩ

For more details refer to section 7.1 in:
http://www.nxp.com/documents/user_manual/UM10204.pdf

(Low-) power implications

The I2C interface realizes a transaction-based access scheme to the bus. From a power management perspective, we can leverage this by only powering on the I2C peripheral while it is actually used, that is inside an i2c_acquire() - i2c_release() block.

After initialization, the I2C peripheral should be powered off (e.g. through peripheral clock gating). It should only be powered on once a transaction on the I2C bus starts, namely in the i2c_acquire() function. Once the transaction is finished, the corresponding I2C peripheral should be powered off again in the i2c_release() function.

If the implementation puts the active thread to sleep while a transfer is in progress (e.g. when using DMA), the implementation might need to block certain power states.

Files

file  i2c.h
 Low-level I2C peripheral driver interface definition.
 

Macros

#define I2C_READ   (0x0001)
 Read bit needs to be set when reading.
 
#define I2C_10BIT_MAGIC   (0xF0u)
 Special bit pattern indicating a 10 bit address is used. More...
 

Functions

void i2c_init (i2c_t dev)
 Initialize the given I2C bus. More...
 
int i2c_acquire (i2c_t dev)
 Get mutually exclusive access to the given I2C bus. More...
 
int i2c_release (i2c_t dev)
 Release the given I2C device to be used by others. More...
 
int i2c_read_reg (i2c_t dev, uint16_t addr, uint16_t reg, void *data, uint8_t flags)
 Convenience function for reading one byte from a given register address. More...
 
int i2c_read_regs (i2c_t dev, uint16_t addr, uint16_t reg, void *data, size_t len, uint8_t flags)
 Convenience function for reading several bytes from a given register address. More...
 
int i2c_read_byte (i2c_t dev, uint16_t addr, void *data, uint8_t flags)
 Convenience function for reading one byte from a device. More...
 
int i2c_read_bytes (i2c_t dev, uint16_t addr, void *data, size_t len, uint8_t flags)
 Convenience function for reading bytes from a device. More...
 
int i2c_write_byte (i2c_t dev, uint16_t addr, uint8_t data, uint8_t flags)
 Convenience function for writing a single byte onto the bus. More...
 
int i2c_write_bytes (i2c_t dev, uint16_t addr, const void *data, size_t len, uint8_t flags)
 Convenience function for writing several bytes onto the bus. More...
 
int i2c_write_reg (i2c_t dev, uint16_t addr, uint16_t reg, uint8_t data, uint8_t flags)
 Convenience function for writing one byte to a given register address. More...
 
int i2c_write_regs (i2c_t dev, uint16_t addr, uint16_t reg, const void *data, size_t len, uint8_t flags)
 Convenience function for writing data to a given register address. More...
 
#define I2C_DEV(x)   (x)
 Default I2C device access macro. More...
 
#define I2C_UNDEF   (UINT_MAX)
 Default I2C undefined value.
 
typedef unsigned int i2c_t
 Default i2c_t type definition.
 
enum  i2c_speed_t {
  I2C_SPEED_LOW = 0x01, I2C_SPEED_NORMAL = 100000U, I2C_SPEED_FAST = 400000U, I2C_SPEED_FAST_PLUS = 0x02,
  I2C_SPEED_HIGH = 0x03, I2C_SPEED_LOW = 0x01, I2C_SPEED_NORMAL = TWI_FREQUENCY_FREQUENCY_K100, I2C_SPEED_FAST = TWI_FREQUENCY_FREQUENCY_K400,
  I2C_SPEED_FAST_PLUS = 0x02, I2C_SPEED_HIGH = 0x03, I2C_SPEED_LOW = 0xff, I2C_SPEED_NORMAL = TWIM_FREQUENCY_FREQUENCY_K100,
  I2C_SPEED_FAST = TWIM_FREQUENCY_FREQUENCY_K400, I2C_SPEED_FAST_PLUS = 0xfe, I2C_SPEED_HIGH = 0xfd, I2C_SPEED_LOW = 10000U,
  I2C_SPEED_NORMAL = 100000U, I2C_SPEED_FAST = 400000U, I2C_SPEED_FAST_PLUS = 1000000U, I2C_SPEED_HIGH = 3400000U,
  I2C_SPEED_NORMAL, I2C_SPEED_FAST, I2C_SPEED_LOW = 0, I2C_SPEED_NORMAL,
  I2C_SPEED_FAST, I2C_SPEED_FAST_PLUS, I2C_SPEED_HIGH
}
 Default mapping of I2C bus speed values. More...
 
enum  i2c_flags_t { I2C_ADDR10 = 0x01, I2C_REG16 = 0x02, I2C_NOSTOP = 0x04, I2C_NOSTART = 0x08 }
 I2C transfer flags. More...
 

Macro Definition Documentation

◆ I2C_10BIT_MAGIC

#define I2C_10BIT_MAGIC   (0xF0u)

Special bit pattern indicating a 10 bit address is used.

Should only be used internally in CPU driver implementations, this is not intended to be used by applications.

See also
https://www.i2c-bus.org/addressing/10-bit-addressing/

Definition at line 174 of file i2c.h.

◆ I2C_DEV

#define I2C_DEV (   x)    (x)

Default I2C device access macro.

Todo:
Remove dev_enums.h include once all platforms are ported to the updated periph interface

Definition at line 139 of file i2c.h.

Enumeration Type Documentation

◆ i2c_flags_t

I2C transfer flags.

Enumerator
I2C_ADDR10 

use 10-bit device addressing

I2C_REG16 

use 16-bit register addressing

I2C_NOSTOP 

do not issue a STOP condition after transfer

I2C_NOSTART 

skip START sequence, ignores address field

Definition at line 196 of file i2c.h.

◆ i2c_speed_t

Default mapping of I2C bus speed values.

Enumerator
I2C_SPEED_LOW 

not supported

I2C_SPEED_NORMAL 

normal mode: ~100kbit/s

I2C_SPEED_FAST 

fast mode: ~400kbit/s

I2C_SPEED_FAST_PLUS 

not supported

I2C_SPEED_HIGH 

not supported

I2C_SPEED_LOW 

not supported

I2C_SPEED_NORMAL 

100kbit/s

I2C_SPEED_FAST 

400kbit/s

I2C_SPEED_FAST_PLUS 

not supported

I2C_SPEED_HIGH 

not supported

I2C_SPEED_LOW 

not supported

I2C_SPEED_NORMAL 

100kbit/s

I2C_SPEED_FAST 

400kbit/s

I2C_SPEED_FAST_PLUS 

not supported

I2C_SPEED_HIGH 

not supported

I2C_SPEED_LOW 

low speed mode: ~10kbit/s

I2C_SPEED_NORMAL 

normal mode: ~100kbit/s

I2C_SPEED_FAST 

fast mode: ~400kbit/s

I2C_SPEED_FAST_PLUS 

fast plus mode: ~1Mbit/s

I2C_SPEED_HIGH 

high speed mode: ~3.4Mbit/s

I2C_SPEED_NORMAL 

normal mode: ~100kbit/s

I2C_SPEED_FAST 

fast mode: ~400kbit/s

I2C_SPEED_LOW 

low speed mode: ~10 kbit/s

I2C_SPEED_NORMAL 

normal mode: ~100 kbit/s

I2C_SPEED_FAST 

fast mode: ~400 kbit/s

I2C_SPEED_FAST_PLUS 

fast plus mode: ~1000 kbit/s

I2C_SPEED_HIGH 

high speed mode: ~3400 kbit/s

Definition at line 181 of file i2c.h.

Function Documentation

◆ i2c_acquire()

int i2c_acquire ( i2c_t  dev)

Get mutually exclusive access to the given I2C bus.

In case the I2C device is busy, this function will block until the bus is free again.

Parameters
[in]devI2C device to access
Returns
0 on success, -1 on error

◆ i2c_init()

void i2c_init ( i2c_t  dev)

Initialize the given I2C bus.

The given I2C device will be initialized with the parameters as specified in the boards periph_conf.h, using the pins and the speed value given there.

The bus MUST not be acquired before initializing it, as this is handled internally by the i2c_init function!

Parameters
[in]devthe device to initialize

◆ i2c_read_byte()

int i2c_read_byte ( i2c_t  dev,
uint16_t  addr,
void *  data,
uint8_t  flags 
)

Convenience function for reading one byte from a device.

Note
This function is using a repeated start sequence for reading from the specified register address.
Precondition
i2c_acquire must be called before accessing the bus
Parameters
[in]devI2C peripheral device
[in]addr7-bit or 10-bit device address (right-aligned)
[out]datamemory location to store received data
[in]flagsoptional flags (see i2c_flags_t)
Returns
0 When success
-EIO When slave device doesn't ACK the byte
-ENXIO When no devices respond on the address sent on the bus
-ETIMEDOUT When timeout occurs before device's response
-EINVAL When an invalid argument is given
-EOPNOTSUPP When MCU driver doesn't support the flag operation
-EAGAIN When a lost bus arbitration occurs

◆ i2c_read_bytes()

int i2c_read_bytes ( i2c_t  dev,
uint16_t  addr,
void *  data,
size_t  len,
uint8_t  flags 
)

Convenience function for reading bytes from a device.

Note
This function is using a repeated start sequence for reading from the specified register address.
Precondition
i2c_acquire must be called before accessing the bus
Parameters
[in]devI2C peripheral device
[in]addr7-bit or 10-bit device address (right-aligned)
[out]datamemory location to store received data
[in]lenthe number of bytes to read into data
[in]flagsoptional flags (see i2c_flags_t)
Returns
0 When success
-EIO When slave device doesn't ACK the byte
-ENXIO When no devices respond on the address sent on the bus
-ETIMEDOUT When timeout occurs before device's response
-EINVAL When an invalid argument is given
-EOPNOTSUPP When MCU driver doesn't support the flag operation
-EAGAIN When a lost bus arbitration occurs

◆ i2c_read_reg()

int i2c_read_reg ( i2c_t  dev,
uint16_t  addr,
uint16_t  reg,
void *  data,
uint8_t  flags 
)

Convenience function for reading one byte from a given register address.

Note
This function is using a repeated start sequence for reading from the specified register address.
Precondition
i2c_acquire must be called before accessing the bus
Parameters
[in]devI2C peripheral device
[in]regregister address to read from (8- or 16-bit, right-aligned)
[in]addr7-bit or 10-bit device address (right-aligned)
[out]datamemory location to store received data
[in]flagsoptional flags (see i2c_flags_t)
Returns
0 When success
-EIO When slave device doesn't ACK the byte
-ENXIO When no devices respond on the address sent on the bus
-ETIMEDOUT When timeout occurs before device's response
-EINVAL When an invalid argument is given
-EOPNOTSUPP When MCU driver doesn't support the flag operation
-EAGAIN When a lost bus arbitration occurs

◆ i2c_read_regs()

int i2c_read_regs ( i2c_t  dev,
uint16_t  addr,
uint16_t  reg,
void *  data,
size_t  len,
uint8_t  flags 
)

Convenience function for reading several bytes from a given register address.

Note
This function is using a repeated start sequence for reading from the specified register address.
Precondition
i2c_acquire must be called before accessing the bus
Parameters
[in]devI2C peripheral device
[in]regregister address to read from (8- or 16-bit, right-aligned)
[in]addr7-bit or 10-bit device address (right-aligned)
[out]datamemory location to store received data
[in]lenthe number of bytes to read into data
[in]flagsoptional flags (see i2c_flags_t)
Returns
0 When success
-EIO When slave device doesn't ACK the byte
-ENXIO When no devices respond on the address sent on the bus
-ETIMEDOUT When timeout occurs before device's response
-EINVAL When an invalid argument is given
-EOPNOTSUPP When MCU driver doesn't support the flag operation
-EAGAIN When a lost bus arbitration occurs

◆ i2c_release()

int i2c_release ( i2c_t  dev)

Release the given I2C device to be used by others.

Parameters
[in]devI2C device to release
Returns
0 on success, -1 on error

◆ i2c_write_byte()

int i2c_write_byte ( i2c_t  dev,
uint16_t  addr,
uint8_t  data,
uint8_t  flags 
)

Convenience function for writing a single byte onto the bus.

Precondition
i2c_acquire must be called before accessing the bus
Parameters
[in]devI2C peripheral device
[in]addr7-bit or 10-bit device address (right-aligned)
[in]databyte to write to the device
[in]flagsoptional flags (see i2c_flags_t)
Returns
0 When success
-EIO When slave device doesn't ACK the byte
-ENXIO When no devices respond on the address sent on the bus
-ETIMEDOUT When timeout occurs before device's response
-EINVAL When an invalid argument is given
-EOPNOTSUPP When MCU driver doesn't support the flag operation
-EAGAIN When a lost bus arbitration occurs

◆ i2c_write_bytes()

int i2c_write_bytes ( i2c_t  dev,
uint16_t  addr,
const void *  data,
size_t  len,
uint8_t  flags 
)

Convenience function for writing several bytes onto the bus.

Precondition
i2c_acquire must be called before accessing the bus
Parameters
[in]devI2C peripheral device
[in]addr7-bit or 10-bit device address (right-aligned)
[in]dataarray holding the bytes to write to the device
[in]lenthe number of bytes to write
[in]flagsoptional flags (see i2c_flags_t)
Returns
0 When success
-EIO When slave device doesn't ACK the byte
-ENXIO When no devices respond on the address sent on the bus
-ETIMEDOUT When timeout occurs before device's response
-EINVAL When an invalid argument is given
-EOPNOTSUPP When MCU driver doesn't support the flag operation
-EAGAIN When a lost bus arbitration occurs

◆ i2c_write_reg()

int i2c_write_reg ( i2c_t  dev,
uint16_t  addr,
uint16_t  reg,
uint8_t  data,
uint8_t  flags 
)

Convenience function for writing one byte to a given register address.

Note
This function is using a repeated start sequence for writing to the specified register address.
Precondition
i2c_acquire must be called before accessing the bus
Parameters
[in]devI2C peripheral device
[in]regregister address to read from (8- or 16-bit, right-aligned)
[in]addr7-bit or 10-bit device address (right-aligned)
[in]databyte to write
[in]flagsoptional flags (see i2c_flags_t)
Returns
0 When success
-EIO When slave device doesn't ACK the byte
-ENXIO When no devices respond on the address sent on the bus
-ETIMEDOUT When timeout occurs before device's response
-EINVAL When an invalid argument is given
-EOPNOTSUPP When MCU driver doesn't support the flag operation
-EAGAIN When a lost bus arbitration occurs

◆ i2c_write_regs()

int i2c_write_regs ( i2c_t  dev,
uint16_t  addr,
uint16_t  reg,
const void *  data,
size_t  len,
uint8_t  flags 
)

Convenience function for writing data to a given register address.

Note
This function is using a repeated start sequence for writing to the specified register address.
Precondition
i2c_acquire must be called before accessing the bus
Parameters
[in]devI2C peripheral device
[in]regregister address to read from (8- or 16-bit, right-aligned)
[in]addr7-bit or 10-bit device address (right-aligned)
[out]datamemory location to store received data
[in]lenthe number of bytes to write
[in]flagsoptional flags (see i2c_flags_t)
Returns
0 When success
-EIO When slave device doesn't ACK the byte
-ENXIO When no devices respond on the address sent on the bus
-ETIMEDOUT When timeout occurs before device's response
-EINVAL When an invalid argument is given
-EOPNOTSUPP When MCU driver doesn't support the flag operation
-EAGAIN When a lost bus arbitration occurs