This version is outdated by a newer approved version.DiffThis version (27 Sep 2022 16:30) was approved by Darius B.The Previously approved version (27 Sep 2022 16:13) is available.Diff

This is an old revision of the document!



The no-OS framework provides a common application programming interface to initialize and use an I2C peripheral across various target platforms.

The I2C API documentation is available as Doxygen documentation.

I2C device initialization

The no-OS framework provides a way to create an I2C slave device descriptor starting from user specified initialization parameters (init params). The init params are generic, defined by no-OS and applicable to all platforms. However, a certain platform may require passing extra initialization parameters that are specific to that platform. The extra member of the init params allows the user to pass such specific init params. The extra init params are of the type [platform]_i2c_init_param as defined in [platform]_i2c.h header.

struct [platform]_i2c_init_param slave_xip = {
	.specific_parameter = value,
struct no_os_i2c_init_param slave_ip = {
	.device_id = 1,
	.max_speed_hz = 100000,
	.slave_address = 0x30,
	.platform_ops = &[platform]_i2c_ops,
	.extra = &slave_xip

Creating/removing an I2C slave device descriptor with the above parameters can be achieved with:

int ret;
struct no_os_i2c_desc *slave_desc;
ret = no_os_i2c_init(&slave_desc, &slave_ip);
// ...
// ... i2c transfers
// ...
ret = no_os_i2c_remove(slave_desc);

Such a descriptor is needed for each slave because each slave requires different communication settings (address, speed). When performing transfers, the I2C peripheral is reconfigured with the I2C settings of the particular slave being targeted.

In the above example, the max_speed_hz parameter given is 100 kHz. The no_os_i2c_init() function will choose such an I2C peripheral prescaler so that SCK is guaranteed to be the closest possible value but not greated than 100 kHz, provided a fixed input clock and the range of available prescalers.



To write a sequence of bytes to a slave with a stop bit at the end, use:

uint8_t data[3] = {0xAA, 0xBB, 0xCC};
ret = no_os_i2c_write(slave_desc, data, 3, 1);
if (ret < 0)
	; // take action


To read a sequence of bytes from a slave with a stop bit at the end, use:

uint8_t data[2];
ret = no_os_i2c_read(slave_desc, data, 2, 1);
if (ret < 0)
	; // take action
// data now contains the received bytes

write and read

Let's consider the following sequence where:

  • S - start condition
  • P - stop condition
  • A - acknowledge
  • 0x60 / 0x61 - write / read of slave at address 0x30
  • 0xAA - slave specific command
  • 0xBB 0xCC - slave specific response
S 0x60 A 0xAA A S 0x61 A 0xBB A 0xCC A P

This can be translated into code using no-OS API in the following way:

uint8_t cmd[1] = {0xAA};
ret = no_os_i2c_write(slave_desc, cmd, 1, 0);
if (ret < 0)
	; // take action
uint8_t data[2];
ret = no_os_i2c_read(slave_desc, data, 2, 1);
if (ret < 0)
	; // take action
// here, data contains {0xBB, 0xCC} received from slave

Note that the last parameter of the write and read functions allows the caller to control the generation of the stop condition. Some slaves require that a write to occur and the read to follow without an intermediate stop condition, in which case write operation must have the stop_bit argument zeroed, as in this example. Other slaves require the stop condition be generated between the write and the read operations, so the stop_bit must be 1 for both operations.

resources/no-os/drivers/i2c.1664289023.txt.gz · Last modified: 27 Sep 2022 16:30 by Darius B