ESP-IDF I2C driver master mode
(左)I2C 16bits IOExpander MCP23017, (右)I2C 8bits IOexpander PCF8574
I2Cdriverの動作確認で、使用しました。
I2C経由で、MCP23017のレジスタを読み込んで、シリアル出力。
<参照>
環境
VScode+platformIO
platform = espressif32
board = my_esp32dev
framework = espidf
※ボードは、esp32devを修正した自作JSONファイル。
I2C driver API関数
I2C driver 初期化API
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
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
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
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.
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
#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);
}