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 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> **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 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> **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