ESP32学習 platformIo+ESPIDF "I2C master"通信

# ESP-IDF I2C driver　master mode
![IMG_4436.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3693934/f92c5ae3-0346-1972-e0ce-11f7fad704a5.jpeg)
(左）I2C 16bits IOExpander MCP23017, （右）I2C 8bits IOexpander PCF8574
I2Cdriverの動作確認で、使用しました。
![MCP23017初期値.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3693934/4d5d82d7-ca2e-b155-dbe1-30c8332007ec.png)
I2C経由で、MCP23017のレジスタを読み込んで、シリアル出力。



<参照>

https://docs.espressif.com/projects/esp-idf/en/v5.1/esp32/api-reference/peripherals/i2c.html

:::note 
環境
VScode＋platformIO
platform = espressif32
board = my_esp32dev
framework = espidf
※ボードは、esp32devを修正した自作JSONファイル。
:::

# I2C driver API関数
# I2C driver 初期化API

:::note
esp_err_t **i2c_param_config**(i2c_port_t i2c_num, const i2c_config_t *i2c_conf)
**Configure an I2C bus with the given configuration.**

Parameters
i2c_num – I2C port to configure
i2c_conf – Pointer to the I2C configuration

Returns
ESP_OK Success
ESP_ERR_INVALID_ARG Parameter error
:::

# I2C driver ドライバーインストールAPI
:::note
esp_err_t **i2c_driver_install**(i2c_port_t i2c_num, i2c_mode_t mode,
size_t slv_rx_buf_len, size_t slv_tx_buf_len, int intr_alloc_flags)
**Install an I2C driver.**

Parameters 
i2c_num – I2C port number
mode – I2C mode (either master or slave).
slv_rx_buf_len – Receiving buffer size. Only slave mode will use this value, it is ignored in master mode.
slv_tx_buf_len – Sending buffer size. Only slave mode will use this value, it is ignored in master mode.
intr_alloc_flags – Flags used to allocate the interrupt. One or multiple (ORred) ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info.

Returns 
ESP_OK Success
ESP_ERR_INVALID_ARG Parameter error
ESP_FAIL Driver installation error
:::

# I2C master 書き込みAPI
:::note
esp_err_t **i2c_master_write_to_device**(i2c_port_t i2c_num, uint8_t device_address, const uint8_t *write_buffer, size_t write_size, TickType_t ticks_to_wait)
**Perform a write to a device connected to a particular I2C port. This function is a wrapper to i2c_master_start(), i2c_master_write(), i2c_master_read(), etc… It shall only be called in I2C master mode.**

Parameters
i2c_num – I2C port number to perform the transfer on
device_address – I2C device’s 7-bit address
write_buffer – Bytes to send on the bus
write_size – Size, in bytes, of the write buffer
ticks_to_wait – Maximum ticks to wait before issuing a timeout.

Returns
ESP_OK Success
ESP_ERR_INVALID_ARG Parameter error
ESP_FAIL Sending command error, slave hasn’t ACK the transfer.
ESP_ERR_INVALID_STATE I2C driver not installed or not in master mode.
ESP_ERR_TIMEOUT Operation timeout because the bus is busy.
:::

# I2C driver リスタート読み出しAPI
:::note
esp_err_t **i2c_master_write_read_device**(i2c_port_t i2c_num, uint8_t device_address, const uint8_t *write_buffer, size_t write_size, uint8_t *read_buffer, size_t read_size, TickType_t ticks_to_wait)

**Perform a write followed by a read to a device on the I2C bus. A repeated start signal is used between the write and read, thus, the bus is not released until the two transactions are finished. This function is a wrapper to i2c_master_start(), i2c_master_write(), i2c_master_read(), etc… It shall only be called in I2C master mode.**

Parameters
i2c_num – I2C port number to perform the transfer on
device_address – I2C device’s 7-bit address
write_buffer – Bytes to send on the bus
write_size – Size, in bytes, of the write buffer
read_buffer – Buffer to store the bytes received on the bus
read_size – Size, in bytes, of the read buffer
ticks_to_wait – Maximum ticks to wait before issuing a timeout.

Returns
ESP_OK Success
ESP_ERR_INVALID_ARG Parameter error
ESP_FAIL Sending command error, slave hasn’t ACK the transfer.
ESP_ERR_INVALID_STATE I2C driver not installed or not in master mode.
ESP_ERR_TIMEOUT Operation timeout because the bus is busy.
:::


```kconfig.projbuild
menu "Example Configuration"

    config I2C_MASTER_SCL
        int "SCL_GPIO_Num"
        range 0 39
        default 19
        help 
            GPIO number for I2C Master clock line.

    config I2C_MASTER_SDA
        int "SDA_GPIO_Num"
        range 0 39
        default 18
        help
            GPIO number for I2C Master data line.

    config GPIO_OUTPUT_0
        int "GPIO output pin 0"
        range 0 39
        default 32
        help
            GPIO pin number to be used as GPIO_OUTPUT_IO_0.

    config GPIO_OUTPUT_1
        int "GPIO output pin 1"
        range 0 39
        default 33
        help
            GPIO pin number to be used as GPIO_OUTPUT_IO_1.

    config GPIO_INPUT_0
        int "GPIO input pin 0"
        range 0 39
        default 34
        help
            GPIO pin number to be used as GPIO_INPUT_IO_0.

    config GPIO_INPUT_1
        int "GPIO input pin 1"
        range 0 39
        default 35
        help
            GPIO pin number to be used as GPIO_INPUT_IO_1.

endmenu
```

```CPP:main.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/spi_master.h"
#include "driver/gpio.h"
#include "driver/i2c.h"
#include "sdkconfig.h"
#include "esp_log.h"

static const char *TAG = "i2c_simple-example";

#define PCF8574_ADDRESS             0x25
#define MCP23017_ADDRESS            0x26
#define I2C_MASTER_SCL_IO           CONFIG_I2C_MASTER_SCL
#define I2C_MASTER_SDA_IO           CONFIG_I2C_MASTER_SDA
#define I2C_MASTER_NUM              0
#define I2C_MASTER_FREQ_HZ          400000
#define I2C_MASTER_TX_BUF_DISABLE   0
#define I2C_MASTER_RX_BUF_DISABLE   0
#define I2C_MASTER_TIMEOUT_MS       1000


void mcp23017_init(uint8_t _add);
void mcp23017_write(uint8_t add, uint8_t reg, uint8_t data);
uint8_t mcp23017_read(uint8_t add, uint8_t reg);

/**
 * @brief i2c master initialization
 */
static esp_err_t i2c_master_init(void)
{
    int i2c_master_port = I2C_MASTER_NUM;

    i2c_config_t conf = 
    {
        .mode = I2C_MODE_MASTER,
        .sda_io_num = I2C_MASTER_SDA_IO,
        .scl_io_num = I2C_MASTER_SCL_IO,
        .sda_pullup_en = GPIO_PULLUP_ENABLE,
        .scl_pullup_en = GPIO_PULLUP_ENABLE,
        .master.clk_speed = I2C_MASTER_FREQ_HZ,
    };

    i2c_param_config(i2c_master_port, &conf);

    return i2c_driver_install(i2c_master_port, conf.mode, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE,0);

}



void app_main()
{
    int ret;
    uint8_t txBuf[2];
    uint8_t data[2];

    //I2C0 initialize
    ESP_ERROR_CHECK(i2c_master_init());
    //i2cDevice MCP23017 initialize
    mcp23017_init(MCP23017_ADDRESS);
    for(int i=0; i<=0x0A; i++)
    {        
        i2c_master_write_read_device(I2C_MASTER_NUM,MCP23017_ADDRESS, &i, 1, data, 1, I2C_MASTER_TIMEOUT_MS/portTICK_PERIOD_MS);
        printf("[%02X]:%X\n", i,data[0]);
    }

    for(int i=0x10; i<=0x1A; i++)
    {        
        i2c_master_write_read_device(I2C_MASTER_NUM,MCP23017_ADDRESS, &i, 1, data, 1, I2C_MASTER_TIMEOUT_MS/portTICK_PERIOD_MS);
        printf("[%02X]:%X\n", i,data[0]);
    }

    //LED点滅
    while(1)
    {
        uint8_t write_buf = 0x55;
        ret = i2c_master_write_to_device(I2C_MASTER_NUM, PCF8574_ADDRESS, &write_buf, sizeof(write_buf), 
                                            I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS);
        mcp23017_write(MCP23017_ADDRESS,0x0A,0xAA);
        mcp23017_write(MCP23017_ADDRESS,0x1A,0xAA);
        vTaskDelay(500/portTICK_PERIOD_MS);

        write_buf = 0xAA;
        ret = i2c_master_write_to_device(I2C_MASTER_NUM, PCF8574_ADDRESS, &write_buf, sizeof(write_buf), 
                                            I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS);
        mcp23017_write(MCP23017_ADDRESS,0x0A,0x55);
        mcp23017_write(MCP23017_ADDRESS,0x1A,0x55);
        vTaskDelay(500/portTICK_PERIOD_MS);
    }
}


/// @brief MCP23017 16bits IOexpander initializing
/// @param add I2C slave address
void mcp23017_init(uint8_t add)
{
    uint8_t write_buf[2] = {0x05,0xA8};
    uint8_t readbuf;

    //Control Register(0x05) Check @BANK = 1
    i2c_master_write_read_device(I2C_MASTER_NUM, MCP23017_ADDRESS,
                &write_buf,1,&readbuf,1,I2C_MASTER_TIMEOUT_MS/ portTICK_PERIOD_MS);
    
    if(readbuf!=0xA8)
    {//BANK == 0
        printf("[05]:%X\n",readbuf);
        write_buf[0]=0x0A;
        write_buf[1]=0xA8;

        i2c_master_write_to_device(I2C_MASTER_NUM, MCP23017_ADDRESS, &write_buf, sizeof(write_buf), 
                                            I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS);
    }

    //PORTA IO direction
    write_buf[0]=0x00;
    write_buf[1]=0x00;
    i2c_master_write_to_device(I2C_MASTER_NUM, MCP23017_ADDRESS, &write_buf, sizeof(write_buf), 
                                            I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS);
    //PORTB IO direction
    write_buf[0]=0x10;
    write_buf[1]=0x00;
    i2c_master_write_to_device(I2C_MASTER_NUM, MCP23017_ADDRESS, &write_buf, sizeof(write_buf), 
                                            I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS);
}

/// @brief MCP23017 I2C 16bits IOexpander Write the register
/// @param add i2c Slave address
/// @param reg mcp23017 regster address
/// @param data writing data
void mcp23017_write(uint8_t add, uint8_t reg, uint8_t data)
{
    uint8_t write_buf[2];
    write_buf[0]=reg;
    write_buf[1]=data;
    i2c_master_write_to_device(I2C_MASTER_NUM, MCP23017_ADDRESS, &write_buf, sizeof(write_buf), 
                                            I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS);
}
```

![IMG_4437.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3693934/6eca09a5-865b-2d5e-2d2c-f31689717eb6.jpeg)