# ESP32 I2C積體匯流排電路
:::info
#### 何謂I2C?
##### I2C(Inter-Integrated Circuit),它是一種串列通訊匯流排,使用多主從架構進行晶片與晶片之間的短距離通訊。在通訊的過程中,每個Slave晶片中都會有相對應的7bit的地址讓Master來辨別晶片的身分,是否為通訊目標,並選擇該晶片進行資料傳輸。
:::
## **I2C架構**

###### ESP32 為 Master時,可藉由I2C與其他Slave裝置進行短距離通訊
:::info
### I2C以SDA和SCL兩種訊號來進行資料傳輸
* ### SDA:
#### SDA為I2C之串列資料線(SDA),Master可藉由SDA資料線讀取其他Slave的資料或者是寫入資料到其他Slave晶片中。
* ### SCL:
#### SCL為串列時鐘線,Master藉由SCL提供I2C-Bus時脈訊號。
:::

---
## **ESP32 I2C Driver**
### **ESP32 I2C驅動安裝流程**

### 1. **參數配置**
:::info
#### ESP32在執行I2C匯流排前,需要先配置ESP32 I2C控制器的傳輸環境參數配置,來配置ESP32 I2C以下參數:
1. ##### I2C工作模式
2. ##### 決定哪個GPIO作為SDA訊號線
3. ##### 決定哪個GPIO作為SCL時脈線
4. ##### SCL時脈頻率(最大4MHz)
5. ##### SDA和SCL GPIO需要啟用上拉電阻
6. ##### TX、RX Buffer
:::
#### 把上述資料由Struct結構體數據結構儲存起來
```c!
int i2c_master_port = 0;
i2c_config_t conf = {
.mode = I2C_MODE_MASTER,
.sda_io_num = I2C_MASTER_SDA_IO, // 配置 SDA 的 GPIO
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_io_num = I2C_MASTER_SCL_IO, // 配置 SCL 的 GPIO
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.master.clk_speed = 400000, // 選擇時脈頻率
.clk_flags = 0,
};
```
#### 將上述i2c_config_t結構體作為參數,進行esp32 driver參數配置及初始化
```c!
i2c_param_config(i2c_master_port, &conf);
```
:::info
Paramater
* ##### i2c_master_port: ESP32 I2C控制器編號
* ##### conf: 上述程式之結構體,由I2C各參數所組成
:::
### **2.安裝I2C驅動**
```c!
i2c_driver_install(i2c_master_port, conf.mode, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0);
```
:::info
#### **Paramater**
##### * i2c_master_port: ESP32提供2個I2C控制器,本例子使用第一個控制器,為 0
##### * conf.mode: I2C工作模式,選擇工作於Master模式
##### * I2C_MASTER_RX_BUF_DISABLEI2C_MASTER_TX_BUF_DISABLE無使用,則寫入0
:::
## **ESP32 I2C Write data / Read Date from I2C-Bus**
* ### **Write data**

#### ESP32工作於Master模式,藉由下圖流程,進行n Bytes的資料寫入,寫入至slave address中的特定寄存器
:::info
##### 1.建立cmd為i2c通訊命令Link
##### 2.發起Start訊號
##### 3.寫入8位元資料,其中7位元為slave位址,1位元選擇R/W,等待ACK回應
##### 4.收到ACK後,發送Data,並等待ACK
##### 5.送出結束字元,STOP
##### 6.將上述設定好的流程,開始發送所有資料至I2C-Bus
##### 7.釋放資源,記憶體
:::
* ### **Read Data**

#### ESP32工作於Master模式,藉由下圖流程,進行n Bytes的資料讀取,讀取slave address中的特定寄存器內的資料
:::info
```c!
i2c_master_write_byte(cmd, (ESP_SLAVE_ADDR << 1) | I2C_MASTER_WRITE, ACK_EN);
```
```c!
i2c_master_write_byte(cmd, (ESP_SLAVE_ADDR << 1) | I2C_MASTER_READ, ACK_EN);
```
I2C在Write和Read不同的點在於slave address為固定7bit的位址,我們需要在LSB最低位元選擇(0 OR 1),讓I2C-Bus來辨別這一連串的資料是要用於讀取slave寄存器資料還是用於寫入資料到slave寄存器中,所以要在LSB(最低位元),寫入I2C_MASTER_WRITE(0)或者I2C_MASTER_READ(1)
:::
## **ESP32 I2C Write data / Read Date from I2C-Bus API**
#### 1. 由SENSOR_ADDR讀取n Bytes的資料
```c!
i2c_master_write_read_device(I2C_MASTER_NUM, SENSOR_ADDR, ®_addr, 1, data, len, I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS);
```
#### 2. 向SENSOR_ADDR寫入1 Bytes的資料
```c!
i2c_master_write_to_device(I2C_MASTER_NUM, SENSOR_ADDR, write_buf, sizeof(write_buf), I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS);
```
---
#### 我們可以藉由I2C-Bus上寫入或讀取用來配置Slave寄存器的內容,也可以藉由讀取,來獲取Slave寄存器內的資料。
#### 下一章節,我們將使用I2C-Bus來使用Mpu6050六軸感測器。
---
* ### **Mpu6050六軸感測器實作教學影片**

* [https://www.youtube.com/watch?v=ZGw88J1PExE](https://www.youtube.com/watch?v=ZGw88J1PExE)