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.
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 greater 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
Let's consider the following sequence where:
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.