I2C Development Guide_Rev1.3
Revision History
Version |
Date |
Author |
Revision Content |
|---|---|---|---|
Rev1.0 |
2023-09-11 |
TL |
Initial document creation |
Rev1.1 |
2024-03-25 |
SXX |
Changed document name |
Rev1.2 |
24-11-07 |
YMX |
Added common issues section |
Rev1.3 |
26-01-27 |
LJZ |
Added new interfaces |
1 Introduction
This document is designed for engineers using Lierda LTE-EC71X series (EC716 / EC718 / EC718M) modules for OpenCPU secondary development. It systematically introduces the functional features, interface definitions, and usage methods of I2C APIs. The document covers I2C basic concepts, port descriptions, receive/transmit mechanisms, detailed API explanations, and complete code examples to help developers quickly get started and correctly integrate serial communication functions.
The LTE-EC71X series modules support 2 I2C channels. For detailed IO multiplexing references, please refer to the hardware documentation.
2 Basic Concepts
I2C is a multi-master, two-wire, low-speed serial communication bus widely used for communication between microcontrollers and various peripheral devices. It uses two lines: Serial Data Line (SDA) and Serial Clock Line (SCL) for bidirectional transmission.
SCL: Serial Clock Line - clock generated by the master
SDA: Serial Data Line - bidirectional data transmission
I2C Data Frame Structure Diagram:
2.1 Receive/Transmit Mechanism
The I2C in the module is implemented based on I2C hardware controller, not software I2C. Users pass data to DMA through the interface, and DMA is responsible for actual data transmission.
I2C Write (Master Output): Master sends address + register + data, slave replies with ACK
I2C Read (Master Input): Slave actively drives SDA to send data, master replies with ACK/NACK
2.2 Hardware Wiring Instructions
Do not connect SCL/SDA directly to VCC or GND, as this will damage the pins. Pull-up resistors are required, recommended value is 3.3KΩ.
Multiple devices share the bus and are distinguished by device addresses, so there will be no conflicts.
Keep traces as short as possible to reduce interference. For long wiring, it is recommended to increase the pull-up resistor value.
VCC
│
3.3KΩ
│
MODEM_SCL ───┼─── Slave SCL
│
3.3KΩ
│
MODEM_SDA ───┼─── Slave SDA
MODEM_GND ─────── Slave GND
3 API Function Overview
Function |
Description |
|---|---|
|
Initialize I2C bus. |
|
Write data to I2C bus, slave device register address length is 8 bits. |
|
Read data from I2C bus, slave device register address length is 8 bits. |
|
Release I2C bus. |
|
Write data to I2C bus, slave device register address length is 16 bits. |
|
Read data from I2C bus, slave device register address length is 16 bits. |
|
Write data to I2C bus, slave device register address length controlled by parameter, can be 8-bit or 16-bit. |
|
Read data from I2C bus, slave device register address length controlled by parameter, can be 8-bit or 16-bit. |
4 Type Descriptions
4.1 liot_errcode_i2c_e
I2C API execution result error codes.
Definition
typedef enum
{
LIOT_I2C_SUCCESS = LIOT_SUCCESS,
LIOT_I2C_INIT_ERR = 1 | LIOT_I2C_ERRCODE_BASE,
LIOT_I2C_NOT_INIT_ERR,
LIOT_I2C_INVALID_PARAM_ERR,
LIOT_I2C_WRITE_ERR = 5 | LIOT_I2C_ERRCODE_BASE,
LIOT_I2C_READ_ERR,
LIOT_I2C_RELEASE_ERR,
} liot_errcode_i2c_e;
Parameters
LIOT_I2C_SUCCESS: Function executed successfully.
LIOT_I2C_INIT_ERR: Invalid input parameter.
LIOT_I2C_NOT_INIT_ERR: I2C not initialized.
LIOT_I2C_INVALID_PARAM_ERR: Invalid parameter.
LIOT_I2C_WRITE_ERR: Failed to write data to I2C.
LIOT_I2C_READ_ERR: Failed to read data from I2C.
LIOT_I2C_RELEASE_ERR: Failed to release I2C bus.
4.2 liot_i2c_channel_e
I2C channel enumeration.
Definition
typedef enum
{
liot_i2c_1 = 0, // i2c channel 1
liot_i2c_2, // i2c channel 2
liot_i2c_3, // i2c channel 3, not support
} liot_i2c_channel_e;
Parameters
liot_i2c_1: I2C bus number 1, corresponds to I2C0 in pin multiplexing table.
liot_i2c_2: I2C bus number 2, corresponds to I2C1 in pin multiplexing table.
liot_i2c_3: I2C bus number 3, currently not supported by the module.
4.3 liot_i2c_mode_e
I2C working mode enumeration is defined as follows:
Definition
typedef enum
{
LIOT_STANDARD_MODE = 0, // Standard mode (100K)
LIOT_FAST_MODE = 1, // Fast mode (400K)
} liot_i2c_mode_e;
Parameters
I2C only supports two transmission modes: STANDARD and FAST.
LIOT_STANDARD_MODE: Standard mode, transmission speed is 100 kbps.
LIOT_FAST_MODE: Fast mode, transmission speed is 400 kbps.
5 API Function Details
5.1 liot_I2cInit
This function is used to initialize I2C bus.
Declaration
liot_errcode_i2c_e liot_I2cInit(liot_i2c_channel_e i2c_no, liot_i2c_mode_e Mode);
Parameters
i2c_no: [In] I2C bus number.
Mode: [In] I2C working mode.
Return Value
liot_errcode_i2c_e: Execution result code, see 4.1 for reference.
5.2 liot_I2cWrite
This function is used to write data to I2C bus, only for writing data when slave device register address length is 8 bits.
Declaration
liot_errcode_i2c_e liot_I2cWrite(liot_i2c_channel_e i2c_no, uint8_t slave, uint8_t addr, uint8_t *data, uint32_t length);
Parameters
i2c_no: [In] I2C bus number.
slave: [In] I2C slave device address.
addr: [in] I2C slave device register address.
data: [in] Data to be written.
length: [in] Length of data to be written, unit: bytes.
Return Value
liot_errcode_i2c_e: Execution result code, see 4.1 for reference.
5.3 liot_I2cRead
This function is used to read data from I2C bus, only for reading data when slave device register address length is 8 bits.
Declaration
liot_errcode_i2c_e liot_I2cRead(liot_i2c_channel_e i2c_no, uint8_t slave, uint8_t addr, uint8_t *buf, uint32_t length)
Parameters
i2c_no: [In] I2C bus number.
slave: [In] I2C slave device address.
addr: [in] I2C slave device register address.
buf: [out] Data read.
length: [in] Length of data to read, unit: bytes.
Return Value
liot_errcode_i2c_e: Execution result code, see 4.1 for reference.
5.4 liot_I2cRelease
This function is used to release I2C bus. If you need to reinitialize the same I2C bus, you must call this function to release the I2C bus first, then call liot_I2cInit() again for initialization.
Declaration
liot_errcode_i2c_e liot_I2cRelease(liot_i2c_channel_e i2c_no);
Parameters
i2c_no: [In] I2C bus number.
Return Value
liot_errcode_i2c_e: Execution result code, see 4.1 for reference.
5.5 liot_I2cWrite_16bit_addr
This function is used to write data to I2C bus, only for writing data when slave device register address length is 16 bits.
Declaration
liot_errcode_i2c_e liot_I2cWrite_16bit_addr(liot_i2c_channel_e i2c_no, uint8_t slave, uint16_t addr, uint8_t *data, uint32_t length);
Parameters
i2c_no: [In] I2C bus number.
slave: [In] I2C slave device address.
addr: [in] I2C slave device register address.
data: [in] Data to be written.
length: [in] Length of data to be written, unit: bytes.
Return Value
liot_errcode_i2c_e: Execution result code, see 4.1 for reference.
5.6 liot_I2cRead_16bit_addr
This function is used to read data from I2C bus, only for reading data when slave device register address length is 16 bits.
Declaration
liot_errcode_i2c_e liot_I2cRead_16bit_addr(liot_i2c_channel_e i2c_no, uint8_t slave, uint16_t addr, uint8_t *buf, uint32_t length);
Parameters
i2c_no: [In] I2C bus number.
slave: [In] I2C slave device address.
addr: [In] I2C slave device register address.
buf: [Out] Data read.
length: [In] Length of data to read, unit: bytes.
Return Value
liot_errcode_i2c_e: Execution result code, see 4.1 for reference.
5.7 Liot_I2cWriteReg
Write data to I2C bus, slave device register address length controlled by parameter, can be 8-bit or 16-bit.
Declaration
liot_errcode_i2c_e Liot_I2cWriteReg(liot_i2c_channel_e i2c_no, uint8_t devAddr, uint16_t reg, BOOL addr16, const uint8_t *data, uint32_t len);
Parameters
i2c_no: [In] I2C bus number.
devAddr: [In] I2C slave device address.
reg: [In] I2C slave device register address.
addr16: [In] Whether register length is 16-bit. 0: 8-bit, 1: 16-bit.
data: [In] Data to be written.
len: [In] Length of data to write, unit: bytes.
Return Value
liot_errcode_i2c_e: Execution result code, see 4.1 for reference.
5.8 Liot_I2cReadReg
Read data from I2C bus, slave device register address length controlled by parameter, can be 8-bit or 16-bit.
Declaration
liot_errcode_i2c_e Liot_I2cReadReg(liot_i2c_channel_e i2c_no, uint8_t devAddr, uint16_t reg, BOOL addr16, uint8_t *data, uint32_t len);
Parameters
i2c_no: [In] I2C bus number.
devAddr: [In] I2C slave device address.
reg: [In] I2C slave device register address.
addr16: [In] Whether register length is 16-bit. 0: 8-bit, 1: 16-bit.
data: [Out] Data read.
len: [In] Length of data to read, unit: bytes.
Return Value
liot_errcode_i2c_e: Execution result code, see 4.1 for reference.
6 Code Example
The following code is located in examples/demo/src/demo_i2c.c, demonstrating how to initialize multiple I2C ports and perform timed read/write operations for 8-bit and 16-bit registers in a loop.
#include "lierda_app_main.h"
#include "liot_gpio2.h"
#include "liot_i2c.h"
#include "liot_os.h"
#define LIOT_I2C_SCL_BIT 67
#define LIOT_I2C_SCL_FUNC (2)
#define LIOT_I2C_SDA_BIT 66
#define LIOT_I2C_SDA_FUNC (2)
/** @brief 8-bit slave write address */
#define SalveAddr_w_8bit (0x42 >> 1)
/** @brief 8-bit slave read address */
#define SalveAddr_r_8bit (0x43 >> 1)
/** @brief 16-bit slave write address */
#define SalveAddr_w_16bit (0xa0 >> 1)
/** @brief 16-bit slave read address */
#define SalveAddr_r_16bit (0xa1 >> 1)
/** @brief Test mode selection: 1-8bit register address; 0-16bit register address */
#define demo_for_8bit_or_16bit (0)
/**
* @brief I2C function demonstration thread
* @details Initialize I2C interface and perform read-write operations in a loop. Select 8-bit or 16-bit register address mode based on demo_for_8bit_or_16bit
* @param[in] arvg Thread parameters (unused)
*/
void liot_i2c_demo_thread(void *arvg)
{
int i2c_no = 0;
int ret;
int fastmode = 0;
uint8_t read_data = 0;
#if demo_for_8bit_or_16bit
uint8_t data = 0xaa; /**< Data to be written in 8-bit mode */
#else
uint8_t data = 0xab; /**< Data to be written in 16-bit mode */
#endif
liot_rtos_task_sleep_ms(200);
liot_trace("I2C DEMO TEXT !!!");
// Configure I2C pin functions
Liot_SetPinFunc(LIOT_I2C_SCL_BIT, LIOT_I2C_SCL_FUNC);
Liot_SetPinFunc(LIOT_I2C_SDA_BIT, LIOT_I2C_SDA_FUNC);
// Initialize I2C interface
ret = liot_I2cInit(i2c_no, fastmode);
if (ret != LIOT_I2C_SUCCESS)
{
liot_trace("I2C INIT FAILED[%d]", ret);
}
while (1)
{
#if demo_for_8bit_or_16bit
// 8-bit register address mode: read operation
liot_I2cRead(i2c_no, SalveAddr_r_8bit, 0xf0, &read_data, 1);
liot_trace("< read i2c value=0x%x, ret=%d >\n", read_data, ret);
// 8-bit register address mode: write operation
liot_I2cWrite(i2c_no, SalveAddr_w_8bit, 0x55, &data, 1);
liot_trace("< write i2c value=0x%x, ret=%d >\n", data, ret);
#else
// 16-bit register address mode: read operation
ret = liot_I2cRead_16bit_addr(i2c_no, SalveAddr_r_16bit, 0x00ff, &read_data, 1);
liot_trace("< read i2c value=0x%x, ret=%d >\n", read_data, ret);
// 16-bit register address mode: write operation
ret = liot_I2cWrite_16bit_addr(i2c_no, SalveAddr_w_16bit, 0x00ff, &data, 1);
liot_trace("< write i2c value=0x%x, ret=%d >\n", data, ret);
#endif
read_data = 0;
liot_rtos_task_sleep_ms(200); /**< Delay 200ms after each operation */
}
liot_rtos_task_delete(NULL); // kill itself
}
7 Common Issues
7.1 What is the Speed of I2C?
I2C supports 4 speed configurations:
Standard Speed (100kHz)
Fast Speed (400kHz)
Fast+ Speed (1MHz)
High Speed (3.4MHz) (currently not supported)
7.2 I2C Not Working Properly After Deep Sleep Wakeup?
It is recommended to deinitialize I2C before sleep to restore I2C status. After deep sleep wakeup, the code will run again, so there is no need to worry about initialization issues after wakeup.
