1e41f4b71Sopenharmony_ci# I3C
2e41f4b71Sopenharmony_ci
3e41f4b71Sopenharmony_ci## Introduction
4e41f4b71Sopenharmony_ci
5e41f4b71Sopenharmony_ci### Function
6e41f4b71Sopenharmony_ci
7e41f4b71Sopenharmony_ciImproved Inter-Integrated Circuit (I3C) is a simple and cost-efficient two-wire bidirectional synchronous serial bus protocol developed by the Mobile Industry Processor Interface (MIPI) Alliance.
8e41f4b71Sopenharmony_ci
9e41f4b71Sopenharmony_ciI3C is a two-wire bidirectional serial bus, optimized for multiple sensor target devices and controlled by only one I3C controller at a time. It is backward compatible with Inter-Integrated circuit (I2C) target devices, but features higher speed and lower power consumption. Moreover, I3C supports in-band interrupts (IBIs), hot-joins of target devices, and controller switchover. The IBIs over the serial bus eliminates the need for an extra interrupt line to complete interrupts in I2C. I2C devices, I3C target devices, and the I3C secondary controller can co-exist on the same I3C bus.
10e41f4b71Sopenharmony_ci
11e41f4b71Sopenharmony_ciThe I3C module provides a set of common APIs for I3C transfer, including:
12e41f4b71Sopenharmony_ci- Opening and closing an I3C controller
13e41f4b71Sopenharmony_ci- Obtaining and setting I3C controller parameters
14e41f4b71Sopenharmony_ci- Performing custom I3C message transfer by using a message array
15e41f4b71Sopenharmony_ci- Requesting and releasing an IBI
16e41f4b71Sopenharmony_ci
17e41f4b71Sopenharmony_ci### Basic Concepts
18e41f4b71Sopenharmony_ci
19e41f4b71Sopenharmony_ci- IBI
20e41f4b71Sopenharmony_ci
21e41f4b71Sopenharmony_ci  When there is no start signal on the serial clock (SCL) line, the I3C target device can pull down the serial data (SDA) line to make the controller send an SCL start signal, which initiates an IBI request. If multiple target devices send interrupt requests at the same time, the I3C controller arbitrates the requests based on the target device addresses. The request with a lower address is responded first.
22e41f4b71Sopenharmony_ci
23e41f4b71Sopenharmony_ci- Dynamic Address Assignment (DAA)
24e41f4b71Sopenharmony_ci
25e41f4b71Sopenharmony_ci  The I3C controller can dynamically allocate addresses to target devices to avoid address conflicts. Before addresses are allocated, each I3C device connected to a I3C bus must be uniquely identified in either of the following ways:
26e41f4b71Sopenharmony_ci    1) The device has an I2C compliant static address that can be used by the host.
27e41f4b71Sopenharmony_ci    2) The device has a 48-bit temporary ID. The host must use a 48-bit temporary ID unless the device has a static IP address. 
28e41f4b71Sopenharmony_ci
29e41f4b71Sopenharmony_ci- Common Command Code (CCC)
30e41f4b71Sopenharmony_ci
31e41f4b71Sopenharmony_ci  All I3C devices support CCC. The CCC can be sent to a specific I3C target device or all I3C target devices.
32e41f4b71Sopenharmony_ci
33e41f4b71Sopenharmony_ci- Bus Characteristic Register (BCR)
34e41f4b71Sopenharmony_ci
35e41f4b71Sopenharmony_ci  Each I3C device connected to an I3C bus has a read-only BCR, which describes the I3C compliant device's role and capabilities for use in DAA and CCC.
36e41f4b71Sopenharmony_ci
37e41f4b71Sopenharmony_ci- Device Characteristic Register (DCR)
38e41f4b71Sopenharmony_ci
39e41f4b71Sopenharmony_ci  Each I3C device connected to an I3C bus has a read-only DCR, which describes the I3C compliant device type (such as accelerometers, gyroscope, and others) for use in DAA and DCC.
40e41f4b71Sopenharmony_ci
41e41f4b71Sopenharmony_ci### Working Principles
42e41f4b71Sopenharmony_ci
43e41f4b71Sopenharmony_ciIn the Hardware Driver Foundation (HDF), the I3C module uses the unified service mode for API adaptation. In this mode, a service is used as the I3C manager to handle external access requests in a unified manner. The unified service mode applies when the system has multiple device objects of the same type, for example, when there are more than 10  I3C controllers. If the independent service mode is used in this case, more device nodes need to be configured and more memory resources will be consumed.
44e41f4b71Sopenharmony_ci
45e41f4b71Sopenharmony_ciCompared with I2C, I3C features higher speed and lower power consumption, supports IBIs, hot-joins of target devices, and controller switchover. I3C is also backward compatible with I2C target devices. Multiple devices, such as I2C target device, I3C target device, and I3C secondary controller, can be connected to an I3C bus. However, the I3C bus must have only one controller.
46e41f4b71Sopenharmony_ci
47e41f4b71Sopenharmony_ci**Figure 1** I3C physical connection
48e41f4b71Sopenharmony_ci
49e41f4b71Sopenharmony_ci![](figures/I3C_physical_connection.png "I3C_physical_connection")
50e41f4b71Sopenharmony_ci
51e41f4b71Sopenharmony_ci### Constraints
52e41f4b71Sopenharmony_ci
53e41f4b71Sopenharmony_ciThe I3C module supports only the kernel (LiteOS-A) for mini and small systems and cannot be used in user mode.
54e41f4b71Sopenharmony_ci
55e41f4b71Sopenharmony_ci## Usage Guidelines
56e41f4b71Sopenharmony_ci
57e41f4b71Sopenharmony_ci### When to Use
58e41f4b71Sopenharmony_ci
59e41f4b71Sopenharmony_ciI3C can connect to one or more I3C or I2C target devices. It is used to:
60e41f4b71Sopenharmony_ci
61e41f4b71Sopenharmony_ci- Communicate with sensors, such as gyroscopes, barometers, and image sensors that support the I3C protocol.
62e41f4b71Sopenharmony_ci- Communicate with devices with other ports (such as UART serial ports) through software or hardware protocols.
63e41f4b71Sopenharmony_ci
64e41f4b71Sopenharmony_ci### Available APIs
65e41f4b71Sopenharmony_ci
66e41f4b71Sopenharmony_ciThe following table describes the APIs provided by the I3C module. For more information about the APIs, see **//drivers/hdf_core/framework/include/platform/i3c_if.h**.
67e41f4b71Sopenharmony_ci
68e41f4b71Sopenharmony_ci**Table 1** I3C driver APIs
69e41f4b71Sopenharmony_ci
70e41f4b71Sopenharmony_ci| API       | Description         |
71e41f4b71Sopenharmony_ci| ------------- | ----------------- |
72e41f4b71Sopenharmony_ci| DevHandle I3cOpen(int16_t number)       | Opens an I3C controller.    |
73e41f4b71Sopenharmony_ci| void I3cClose(DevHandle handle)      | Closes an I3C controller.    |
74e41f4b71Sopenharmony_ci| int32_t I3cTransfer(DevHandle handle, struct I3cMsg \*msg, int16_t count, enum TransMode mode)   | Performs custom transfer.       |
75e41f4b71Sopenharmony_ci| int32_t I3cSetConfig(DevHandle handle, struct I3cConfig \*config)  | Sets the I3C controller.    |
76e41f4b71Sopenharmony_ci| int32_t I3cGetConfig(DevHandle handle, struct I3cConfig \*config)  | Obtains I3C controller configuration.|
77e41f4b71Sopenharmony_ci| int32_t I3cRequestIbi(DevHandle handle, uint16_t addr, I3cIbiFunc func, uint32_t payload) | Requests an IBI.     |
78e41f4b71Sopenharmony_ci| int32_t I3cFreeIbi(DevHandle handle, uint16_t addr)    | Releases an IBI.     |
79e41f4b71Sopenharmony_ci
80e41f4b71Sopenharmony_ci>![](../public_sys-resources/icon-note.gif) **NOTE**
81e41f4b71Sopenharmony_ci>
82e41f4b71Sopenharmony_ci>All APIs described in this document can be called only in kernel mode.
83e41f4b71Sopenharmony_ci
84e41f4b71Sopenharmony_ci### How to Develop
85e41f4b71Sopenharmony_ci
86e41f4b71Sopenharmony_ciThe following figure illustrates how to use the I3C APIs.
87e41f4b71Sopenharmony_ci
88e41f4b71Sopenharmony_ci**Figure 2** Process of using I3C driver APIs
89e41f4b71Sopenharmony_ci
90e41f4b71Sopenharmony_ci![](figures/using-I3C-process.png)
91e41f4b71Sopenharmony_ci
92e41f4b71Sopenharmony_ci#### Opening an I3C Controller
93e41f4b71Sopenharmony_ci
94e41f4b71Sopenharmony_ciBefore I3C communication, call **I3cOpen()** to open an I3C controller.
95e41f4b71Sopenharmony_ci```c
96e41f4b71Sopenharmony_ciDevHandle I3cOpen(int16_t number);
97e41f4b71Sopenharmony_ci```
98e41f4b71Sopenharmony_ci
99e41f4b71Sopenharmony_ci**Table 2** Description of I3cOpen
100e41f4b71Sopenharmony_ci
101e41f4b71Sopenharmony_ci| Name      | Description           |
102e41f4b71Sopenharmony_ci| ---------- | ------------------- |
103e41f4b71Sopenharmony_ci| number     | I3C controller number.        |
104e41f4b71Sopenharmony_ci| **Return Value**| **Description**     |
105e41f4b71Sopenharmony_ci| NULL       | The operation fails.  |
106e41f4b71Sopenharmony_ci| Controller handle| The operation is successful. The handle of the I3C controller opened is returned.|
107e41f4b71Sopenharmony_ci
108e41f4b71Sopenharmony_ciExample: Open I3C controller 1 of the eight I3C controllers numbered from 0 to 7 in the system.
109e41f4b71Sopenharmony_ci
110e41f4b71Sopenharmony_ci```c
111e41f4b71Sopenharmony_ciDevHandle i3cHandle = NULL; /* I3C controller handle. /
112e41f4b71Sopenharmony_ci
113e41f4b71Sopenharmony_ci/* Open I3C controller 1. */
114e41f4b71Sopenharmony_cii3cHandle = I3cOpen(1);
115e41f4b71Sopenharmony_ciif (i3cHandle == NULL) {
116e41f4b71Sopenharmony_ci    HDF_LOGE("I3cOpen: failed\n");
117e41f4b71Sopenharmony_ci    return;
118e41f4b71Sopenharmony_ci}
119e41f4b71Sopenharmony_ci```
120e41f4b71Sopenharmony_ci
121e41f4b71Sopenharmony_ci#### Obtaining the I3C Controller Configuration
122e41f4b71Sopenharmony_ci
123e41f4b71Sopenharmony_ci```c
124e41f4b71Sopenharmony_ciint32_t I3cGetConfig(DevHandle handle, struct I3cConfig *config);
125e41f4b71Sopenharmony_ci```
126e41f4b71Sopenharmony_ci
127e41f4b71Sopenharmony_ci**Table 3** Description of I3cGetConfig
128e41f4b71Sopenharmony_ci
129e41f4b71Sopenharmony_ci| Name      | Description      |
130e41f4b71Sopenharmony_ci| ---------- | -------------- |
131e41f4b71Sopenharmony_ci| handle     | I3C controller handle. |
132e41f4b71Sopenharmony_ci| config     | Pointer to the I3C controller configuration. |
133e41f4b71Sopenharmony_ci| **Return Value**| **Description**|
134e41f4b71Sopenharmony_ci| 0          | The operation is successful.      |
135e41f4b71Sopenharmony_ci| Negative value      | The operation fails.      |
136e41f4b71Sopenharmony_ci
137e41f4b71Sopenharmony_ciThe following is an example of obtaining the I3C controller configuration:
138e41f4b71Sopenharmony_ci
139e41f4b71Sopenharmony_ci```c
140e41f4b71Sopenharmony_cistruct I3cConfig config;
141e41f4b71Sopenharmony_ci
142e41f4b71Sopenharmony_ciret = I3cGetConfig(i3cHandle, &config);
143e41f4b71Sopenharmony_ciif (ret != HDF_SUCCESS) {
144e41f4b71Sopenharmony_ci    HDF_LOGE("%s: Get config fail!", __func__);
145e41f4b71Sopenharmony_ci    return HDF_FAILURE;
146e41f4b71Sopenharmony_ci}
147e41f4b71Sopenharmony_ci```
148e41f4b71Sopenharmony_ci
149e41f4b71Sopenharmony_ci#### Setting an I3C Controller
150e41f4b71Sopenharmony_ci
151e41f4b71Sopenharmony_ci```c
152e41f4b71Sopenharmony_ciint32_t I3cSetConfig(DevHandle handle, struct I3cConfig *config);
153e41f4b71Sopenharmony_ci```
154e41f4b71Sopenharmony_ci
155e41f4b71Sopenharmony_ci**Table 4** Description of I3cSetConfig
156e41f4b71Sopenharmony_ci
157e41f4b71Sopenharmony_ci| Name      | Description      |
158e41f4b71Sopenharmony_ci| ---------- | -------------- |
159e41f4b71Sopenharmony_ci| handle     | I3C controller handle. |
160e41f4b71Sopenharmony_ci| config     | Pointer to the I3C controller configuration. |
161e41f4b71Sopenharmony_ci| **Return Value**| **Description**|
162e41f4b71Sopenharmony_ci| 0          | The operation is successful.      |
163e41f4b71Sopenharmony_ci| Negative value      | The operation fails.      |
164e41f4b71Sopenharmony_ci
165e41f4b71Sopenharmony_ciThe following is an example of setting an I3C controller:
166e41f4b71Sopenharmony_ci
167e41f4b71Sopenharmony_ci```c
168e41f4b71Sopenharmony_cistruct I3cConfig config;
169e41f4b71Sopenharmony_ci
170e41f4b71Sopenharmony_ciconfig->busMode = I3C_BUS_HDR_MODE;
171e41f4b71Sopenharmony_ciconfig->curMaster = NULL;
172e41f4b71Sopenharmony_ciret = I3cSetConfig(i3cHandle, &config);
173e41f4b71Sopenharmony_ciif (ret != HDF_SUCCESS) {
174e41f4b71Sopenharmony_ci    HDF_LOGE("%s: Set config fail!", __func__);
175e41f4b71Sopenharmony_ci    return HDF_FAILURE;
176e41f4b71Sopenharmony_ci}
177e41f4b71Sopenharmony_ci```
178e41f4b71Sopenharmony_ci
179e41f4b71Sopenharmony_ci#### Performing I3C Communication
180e41f4b71Sopenharmony_ci
181e41f4b71Sopenharmony_ciCall **I3cTransfer()** to transfer messages.
182e41f4b71Sopenharmony_ci```c
183e41f4b71Sopenharmony_ciint32_t I3cTransfer(DevHandle handle, struct I3cMsg *msgs, int16_t count, enum TransMode mode);
184e41f4b71Sopenharmony_ci```
185e41f4b71Sopenharmony_ci
186e41f4b71Sopenharmony_ci**Table 5** Description of I3cTransfer
187e41f4b71Sopenharmony_ci
188e41f4b71Sopenharmony_ci| Name      | Description                                    |
189e41f4b71Sopenharmony_ci| ---------- | -------------------------------------------- |
190e41f4b71Sopenharmony_ci| handle     | I3C controller handle.                               |
191e41f4b71Sopenharmony_ci| msgs       | Pointer to the message array of the data to transfer.                  |
192e41f4b71Sopenharmony_ci| count      | Length of the message array.                                |
193e41f4b71Sopenharmony_ci| mode       | Transmission mode. The value **0** indicates I2C mode, **1** indicates I3C mode, and **2** indicates CCC transmission.|
194e41f4b71Sopenharmony_ci| **Return Value**| **Description**                              |
195e41f4b71Sopenharmony_ci| Positive integer    | The operation is successful. The number of message structures that are successfully transmitted is returned.                    |
196e41f4b71Sopenharmony_ci| Negative value      | The operation fails.                                    |
197e41f4b71Sopenharmony_ci
198e41f4b71Sopenharmony_ciThe I3C messages are of the I3cMsg type. Each message structure indicates a read or write operation. A message array can be used to perform multiple read or write operations.
199e41f4b71Sopenharmony_ci
200e41f4b71Sopenharmony_ci```c
201e41f4b71Sopenharmony_ciint32_t ret;
202e41f4b71Sopenharmony_ciuint8_t wbuff[2] = { 0x12, 0x13 };
203e41f4b71Sopenharmony_ciuint8_t rbuff[2] = { 0 };
204e41f4b71Sopenharmony_cistruct I3cMsg msgs[2];  /* Custom message array for transfer. */
205e41f4b71Sopenharmony_cimsgs[0].buf = wbuff;    /* Data to write. */
206e41f4b71Sopenharmony_cimsgs[0].len = 2;        /* Length of the data to write. */
207e41f4b71Sopenharmony_cimsgs[0].addr = 0x3F;    /* Address of the device to which the data is written. */
208e41f4b71Sopenharmony_cimsgs[0].flags = 0;      /* Transfer flag. A write operation is performed by default. */
209e41f4b71Sopenharmony_cimsgs[1].buf = rbuff;    /* Data to read. */
210e41f4b71Sopenharmony_cimsgs[1].len = 2;        /* Length of the data to read. */
211e41f4b71Sopenharmony_cimsgs[1].addr = 0x3F;    /* Address of the device from which the data is read. */
212e41f4b71Sopenharmony_cimsgs[1].flags = I3C_FLAG_READ /* I3C_FLAG_READ is set. */
213e41f4b71Sopenharmony_ci/* Transfer two messages in I2C mode. */
214e41f4b71Sopenharmony_ciret = I3cTransfer(i3cHandle, msgs, 2, I2C_MODE);
215e41f4b71Sopenharmony_ciif (ret != 2) {
216e41f4b71Sopenharmony_ci    HDF_LOGE("I3cTransfer: failed, ret %d\n", ret);
217e41f4b71Sopenharmony_ci    return;
218e41f4b71Sopenharmony_ci}
219e41f4b71Sopenharmony_ci```
220e41f4b71Sopenharmony_ci
221e41f4b71Sopenharmony_ci>![](./public_sys-resources/icon-caution.gif) **Caution**<br>
222e41f4b71Sopenharmony_ci>-   The device address in the **I3cMsg** structure does not contain the read/write flag bit. The read/write information is passed by the read/write control bit in **flags**.
223e41f4b71Sopenharmony_ci>-   The I3C controller determines the maximum number of messages to transfer at a time and the maximum length of each message.
224e41f4b71Sopenharmony_ci>-   Using **I3cTransfer()** may cause the system to sleep. Do not call it in the interrupt context.
225e41f4b71Sopenharmony_ci
226e41f4b71Sopenharmony_ci#### Requesting an IBI
227e41f4b71Sopenharmony_ci
228e41f4b71Sopenharmony_ci```c
229e41f4b71Sopenharmony_ciint32_t I3cRequestIbi(DevHandle handle, uint16_t addr, I3cIbiFunc func, uint32_t payload);
230e41f4b71Sopenharmony_ci```
231e41f4b71Sopenharmony_ci
232e41f4b71Sopenharmony_ci**Table 6** Description of I3cRequestIbi
233e41f4b71Sopenharmony_ci
234e41f4b71Sopenharmony_ci| Name      | Description      |
235e41f4b71Sopenharmony_ci| ---------- | -------------- |
236e41f4b71Sopenharmony_ci| handle     | I3C controller handle. |
237e41f4b71Sopenharmony_ci| addr       | I3C device address.   |
238e41f4b71Sopenharmony_ci| func       | Callback used to return the IBI.   |
239e41f4b71Sopenharmony_ci| payload    | IBI payload.   |
240e41f4b71Sopenharmony_ci| **Return Value**| **Description**|
241e41f4b71Sopenharmony_ci| 0          | The operation is successful.      |
242e41f4b71Sopenharmony_ci| Negative value      | The operation fails.      |
243e41f4b71Sopenharmony_ci
244e41f4b71Sopenharmony_ciThe following is an example:
245e41f4b71Sopenharmony_ci
246e41f4b71Sopenharmony_ci```c
247e41f4b71Sopenharmony_cistatic int32_t TestI3cIbiFunc(DevHandle handle, uint16_t addr, struct I3cIbiData data)
248e41f4b71Sopenharmony_ci{
249e41f4b71Sopenharmony_ci    (void)handle;
250e41f4b71Sopenharmony_ci    (void)addr;
251e41f4b71Sopenharmony_ci    HDF_LOGD("%s: %.16s", __func__, (char *)data.buf);
252e41f4b71Sopenharmony_ci
253e41f4b71Sopenharmony_ci    return 0;
254e41f4b71Sopenharmony_ci}
255e41f4b71Sopenharmony_ci
256e41f4b71Sopenharmony_ciint32_t I3cTestRequestIbi(void)
257e41f4b71Sopenharmony_ci{
258e41f4b71Sopenharmony_ci    DevHandle i3cHandle = NULL;
259e41f4b71Sopenharmony_ci    int32_t ret;
260e41f4b71Sopenharmony_ci
261e41f4b71Sopenharmony_ci    /* Open the I3C controller. */
262e41f4b71Sopenharmony_ci    i3cHandle = I3cOpen(1);
263e41f4b71Sopenharmony_ci    if (i3cHandle == NULL) {
264e41f4b71Sopenharmony_ci        HDF_LOGE("I3cOpen: failed\n");
265e41f4b71Sopenharmony_ci    return;
266e41f4b71Sopenharmony_ci}
267e41f4b71Sopenharmony_ci    ret = I3cRequestIbi(i3cHandle, 0x3F, TestI3cIbiFunc, 16);
268e41f4b71Sopenharmony_ci    if (ret != 0) {
269e41f4b71Sopenharmony_ci        HDF_LOGE("%s: Request IBI failed!", __func__);
270e41f4b71Sopenharmony_ci        return -1;
271e41f4b71Sopenharmony_ci    }
272e41f4b71Sopenharmony_ci
273e41f4b71Sopenharmony_ci    I3cClose(i3cHandle);
274e41f4b71Sopenharmony_ci    HDF_LOGD("%s: Done", __func__);
275e41f4b71Sopenharmony_ci
276e41f4b71Sopenharmony_ci    return 0;
277e41f4b71Sopenharmony_ci}
278e41f4b71Sopenharmony_ci```
279e41f4b71Sopenharmony_ci
280e41f4b71Sopenharmony_ci#### Releasing an IBI
281e41f4b71Sopenharmony_ci
282e41f4b71Sopenharmony_ci```c
283e41f4b71Sopenharmony_ciint32_t I3cFreeIbi(DevHandle handle, uint16_t addr);
284e41f4b71Sopenharmony_ci```
285e41f4b71Sopenharmony_ci
286e41f4b71Sopenharmony_ci**Table 7** Description of I3cFreeIbi
287e41f4b71Sopenharmony_ci
288e41f4b71Sopenharmony_ci| Name      | Description      |
289e41f4b71Sopenharmony_ci| ---------- | -------------- |
290e41f4b71Sopenharmony_ci| handle     | I3C controller handle. |
291e41f4b71Sopenharmony_ci| addr       | I3C device address.   |
292e41f4b71Sopenharmony_ci| **Return Value**| **Description**|
293e41f4b71Sopenharmony_ci| 0          | The operation is successful.      |
294e41f4b71Sopenharmony_ci| Negative value      | The operation fails.      |
295e41f4b71Sopenharmony_ci
296e41f4b71Sopenharmony_ciThe following is an example:
297e41f4b71Sopenharmony_ci
298e41f4b71Sopenharmony_ci```c
299e41f4b71Sopenharmony_ciI3cFreeIbi(i3cHandle, 0x3F); /* Release an IBI. */
300e41f4b71Sopenharmony_ci```
301e41f4b71Sopenharmony_ci
302e41f4b71Sopenharmony_ci#### Closing an I3C Controller
303e41f4b71Sopenharmony_ci
304e41f4b71Sopenharmony_ciCall **I3cClose()** to close the I3C controller after the communication is complete.
305e41f4b71Sopenharmony_ci```c
306e41f4b71Sopenharmony_civoid I3cClose(DevHandle handle); 
307e41f4b71Sopenharmony_ci```
308e41f4b71Sopenharmony_ci
309e41f4b71Sopenharmony_ci**Table 8** Description of I3cClose
310e41f4b71Sopenharmony_ci
311e41f4b71Sopenharmony_ci| Name      | Description      |
312e41f4b71Sopenharmony_ci| ---------- | -------------- |
313e41f4b71Sopenharmony_ci| handle     | I3C controller handle. |
314e41f4b71Sopenharmony_ci
315e41f4b71Sopenharmony_ciThe following is an example:
316e41f4b71Sopenharmony_ci
317e41f4b71Sopenharmony_ci```c
318e41f4b71Sopenharmony_ciI3cClose(i3cHandle); /* Close the I3C controller. */
319e41f4b71Sopenharmony_ci```
320e41f4b71Sopenharmony_ci
321e41f4b71Sopenharmony_ci## Example
322e41f4b71Sopenharmony_ci
323e41f4b71Sopenharmony_ciThe following example presents how to use I3C APIs to manage an I3C device on a Hi3516D V300 development board. <br>The basic hardware information is as follows:
324e41f4b71Sopenharmony_ci
325e41f4b71Sopenharmony_ci-   SoC: Hi3516D V300
326e41f4b71Sopenharmony_ci
327e41f4b71Sopenharmony_ci-   Virtual I3C device: The I3C address is 0x3f, and the register bit width is 1 byte.
328e41f4b71Sopenharmony_ci
329e41f4b71Sopenharmony_ci-   The virtual I3C device is connected to I3C controllers 18 and 19.
330e41f4b71Sopenharmony_ci
331e41f4b71Sopenharmony_ciPerform simple I3C transfer to test whether the I3C channels are normal.
332e41f4b71Sopenharmony_ci
333e41f4b71Sopenharmony_ciThe sample code is as follows:
334e41f4b71Sopenharmony_ci
335e41f4b71Sopenharmony_ci```c
336e41f4b71Sopenharmony_ci#include "i3c_if.h"          /* Header file for I3C standard APIs */
337e41f4b71Sopenharmony_ci#include "hdf_log.h"         /* Header file for log APIs */
338e41f4b71Sopenharmony_ci##include "osal_io.h"        /* Header file for I/O read and write APIs */
339e41f4b71Sopenharmony_ci#include "osal_time.h"       /* Header file for delay and sleep APIs */
340e41f4b71Sopenharmony_ci
341e41f4b71Sopenharmony_ci/* Define a device structure to hold information. */
342e41f4b71Sopenharmony_cistruct TestI3cDevice {
343e41f4b71Sopenharmony_ci    uint16_t busNum;              /* I3C bus number */ 
344e41f4b71Sopenharmony_ci    uint16_t addr;                /* I3C device address */ 
345e41f4b71Sopenharmony_ci    uint16_t regLen;              /* Register bit width */
346e41f4b71Sopenharmony_ci    DevHandle i3cHandle;          /* I3C controller handle */ 
347e41f4b71Sopenharmony_ci};
348e41f4b71Sopenharmony_ci
349e41f4b71Sopenharmony_ci/* Use I3cTransfer() to encapsulate a register read/write helper function. Use flag to indicate a read or write operation. */
350e41f4b71Sopenharmony_cistatic int TestI3cReadWrite(struct TestI3cDevice *testDevice, unsigned int regAddr,
351e41f4b71Sopenharmony_ci    unsigned char *regData, unsigned int dataLen, uint8_t flag)
352e41f4b71Sopenharmony_ci{
353e41f4b71Sopenharmony_ci    int index = 0;
354e41f4b71Sopenharmony_ci    unsigned char regBuf[4] = {0};
355e41f4b71Sopenharmony_ci    struct I3cMsg msgs[2] = {0};
356e41f4b71Sopenharmony_ci
357e41f4b71Sopenharmony_ci    /* Perform length adaptation for the single- or dual-byte register. */
358e41f4b71Sopenharmony_ci    if (testDevice->regLen == 1) { 
359e41f4b71Sopenharmony_ci        regBuf[index++] = regAddr & 0xFF;
360e41f4b71Sopenharmony_ci    } else {
361e41f4b71Sopenharmony_ci        regBuf[index++] = (regAddr >> 8) & 0xFF;
362e41f4b71Sopenharmony_ci        regBuf[index++] = regAddr & 0xFF;
363e41f4b71Sopenharmony_ci    }
364e41f4b71Sopenharmony_ci
365e41f4b71Sopenharmony_ci    /* Fill in the I3cMsg message structure. */
366e41f4b71Sopenharmony_ci    msgs[0].addr = testDevice->addr;
367e41f4b71Sopenharmony_ci    msgs[0].flags = 0; /* The flag 0 indicates a write operation. */
368e41f4b71Sopenharmony_ci    msgs[0].len = testDevice->regLen;
369e41f4b71Sopenharmony_ci    msgs[0].buf = regBuf;
370e41f4b71Sopenharmony_ci
371e41f4b71Sopenharmony_ci    msgs[1].addr = testDevice->addr;
372e41f4b71Sopenharmony_ci    msgs[1].flags = (flag == 1) ? I3C_FLAG_READ : 0; /* Add the read flag. */
373e41f4b71Sopenharmony_ci    msgs[1].len = dataLen;
374e41f4b71Sopenharmony_ci    msgs[1].buf = regData;
375e41f4b71Sopenharmony_ci
376e41f4b71Sopenharmony_ci    if (I3cTransfer(testDevice->i3cHandle, msgs, 2, I2C_MODE) != 2) {
377e41f4b71Sopenharmony_ci        HDF_LOGE("%s: i3c read err", __func__);
378e41f4b71Sopenharmony_ci        return HDF_FAILURE;
379e41f4b71Sopenharmony_ci    }
380e41f4b71Sopenharmony_ci    return HDF_SUCCESS;
381e41f4b71Sopenharmony_ci}
382e41f4b71Sopenharmony_ci
383e41f4b71Sopenharmony_ci/* Read data from the register. */
384e41f4b71Sopenharmony_cistatic inline int TestI3cReadReg(struct TestI3cDevice *testDevice, unsigned int regAddr,
385e41f4b71Sopenharmony_ci    unsigned char *regData, unsigned int dataLen)
386e41f4b71Sopenharmony_ci{
387e41f4b71Sopenharmony_ci    return TestI3cReadWrite(testDevice, regAddr, regData, dataLen, 1);
388e41f4b71Sopenharmony_ci}
389e41f4b71Sopenharmony_ci
390e41f4b71Sopenharmony_ci/* Write data to the register. */
391e41f4b71Sopenharmony_cistatic inline int TestI3cWriteReg(struct TestI3cDevice *testDevice, unsigned int regAddr,
392e41f4b71Sopenharmony_ci    unsigned char *regData, unsigned int dataLen)
393e41f4b71Sopenharmony_ci{
394e41f4b71Sopenharmony_ci    return TestI3cReadWrite(testDevice, regAddr, regData, dataLen, 0);
395e41f4b71Sopenharmony_ci}
396e41f4b71Sopenharmony_ci
397e41f4b71Sopenharmony_ci/* Main entry of I3C routines. */
398e41f4b71Sopenharmony_cistatic int32_t TestCaseI3c(void)
399e41f4b71Sopenharmony_ci{
400e41f4b71Sopenharmony_ci    int32_t i;
401e41f4b71Sopenharmony_ci    int32_t ret;
402e41f4b71Sopenharmony_ci    unsigned char bufWrite[7] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xA, 0xB, 0xC };
403e41f4b71Sopenharmony_ci    unsigned char bufRead[7] = {0};
404e41f4b71Sopenharmony_ci    static struct TestI3cDevice testDevice;
405e41f4b71Sopenharmony_ci
406e41f4b71Sopenharmony_ci    /* Initialize device information. */
407e41f4b71Sopenharmony_ci    testDevice.busNum = 18;
408e41f4b71Sopenharmony_ci    testDevice.addr = 0x3F;
409e41f4b71Sopenharmony_ci    testDevice.regLen = 1;
410e41f4b71Sopenharmony_ci    testDevice.i3cHandle = NULL;
411e41f4b71Sopenharmony_ci
412e41f4b71Sopenharmony_ci    /* Open an I3C controller. */
413e41f4b71Sopenharmony_ci    testDevice.i3cHandle = I3cOpen(testDevice.busNum);
414e41f4b71Sopenharmony_ci    if (testDevice.i3cHandle == NULL) {
415e41f4b71Sopenharmony_ci        HDF_LOGE("%s: Open I3c:%u fail!", __func__, testDevice.busNum);
416e41f4b71Sopenharmony_ci        return -1;
417e41f4b71Sopenharmony_ci    }
418e41f4b71Sopenharmony_ci
419e41f4b71Sopenharmony_ci    /* Write 7-byte data continuously to the device whose address is 0x3F. */
420e41f4b71Sopenharmony_ci    ret = TestI3cWriteReg(&testDevice, 0x3F, bufWrite, 7);
421e41f4b71Sopenharmony_ci    if (ret != HDF_SUCCESS) {
422e41f4b71Sopenharmony_ci        HDF_LOGE("%s: test i3c write reg fail!:%d", __func__, ret);
423e41f4b71Sopenharmony_ci        I3cClose(testDevice.i3cHandle);
424e41f4b71Sopenharmony_ci        return -1;
425e41f4b71Sopenharmony_ci    }
426e41f4b71Sopenharmony_ci    OsalMSleep(10);
427e41f4b71Sopenharmony_ci
428e41f4b71Sopenharmony_ci    /* Read 7-byte data continuously from the device whose address is 0x3F. */
429e41f4b71Sopenharmony_ci    ret = TestI3cReadReg(&testDevice, 0x3F, bufRead, 7);
430e41f4b71Sopenharmony_ci    if (ret != HDF_SUCCESS) {
431e41f4b71Sopenharmony_ci        HDF_LOGE("%s: test i3c read reg fail!:%d", __func__, ret);
432e41f4b71Sopenharmony_ci        I3cClose(testDevice.i3cHandle);
433e41f4b71Sopenharmony_ci        return -1;
434e41f4b71Sopenharmony_ci    }
435e41f4b71Sopenharmony_ci    HDF_LOGI("%s: test i3c write&read reg success!", __func__);
436e41f4b71Sopenharmony_ci
437e41f4b71Sopenharmony_ci    /* Close the I3C controller. */
438e41f4b71Sopenharmony_ci    I3cClose(testDevice.i3cHandle);
439e41f4b71Sopenharmony_ci
440e41f4b71Sopenharmony_ci    return 0;
441e41f4b71Sopenharmony_ci}
442e41f4b71Sopenharmony_ci```
443