Snapshot of JC3636W518EN kit before demo folder cleanup

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
patriandClaude Opus 5.5 committed 2026-10-22 23:56:18 +02:00
commit 9ee85bfd86
1862 files changed
+668877

No files matched your search

@@ -0,0 +1,164 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <inttypes.h>
#include <string.h>
#include <stdlib.h>
#include "driver/i2c.h"
#include "esp_bit_defs.h"
#include "esp_check.h"
#include "esp_log.h"
#include "../private/CheckResult.h"
#include "HT8574.h"
/* Timeout of each I2C communication */
#define I2C_TIMEOUT_MS (10)
#define IO_COUNT (8)
/* Default register value on power-up */
#define DIR_REG_DEFAULT_VAL (0xff)
#define OUT_REG_DEFAULT_VAL (0xff)
/**
* @brief Device Structure Type
*
*/
typedef struct {
esp_io_expander_t base;
i2c_port_t i2c_num;
uint32_t i2c_address;
struct {
uint8_t direction;
uint8_t output;
} regs;
} esp_io_expander_ht8574_t;
static const char *TAG = "ht8574";
static esp_err_t esp_io_expander_new_i2c_ht8574(i2c_port_t i2c_num, uint32_t i2c_address, esp_io_expander_handle_t *handle);
ESP_IOExpander_HT8574::~ESP_IOExpander_HT8574()
{
if (i2c_need_init) {
i2c_driver_delete(i2c_id);
}
if (handle) {
del();
}
}
void ESP_IOExpander_HT8574::begin(void)
{
CHECK_ERROR_RETURN(esp_io_expander_new_i2c_ht8574(i2c_id, i2c_address, &handle));
}
static esp_err_t read_input_reg(esp_io_expander_handle_t handle, uint32_t *value);
static esp_err_t write_output_reg(esp_io_expander_handle_t handle, uint32_t value);
static esp_err_t read_output_reg(esp_io_expander_handle_t handle, uint32_t *value);
static esp_err_t write_direction_reg(esp_io_expander_handle_t handle, uint32_t value);
static esp_err_t read_direction_reg(esp_io_expander_handle_t handle, uint32_t *value);
static esp_err_t reset(esp_io_expander_t *handle);
static esp_err_t del(esp_io_expander_t *handle);
static esp_err_t esp_io_expander_new_i2c_ht8574(i2c_port_t i2c_num, uint32_t i2c_address, esp_io_expander_handle_t *handle)
{
ESP_RETURN_ON_FALSE(i2c_num < I2C_NUM_MAX, ESP_ERR_INVALID_ARG, TAG, "Invalid i2c num");
ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "Invalid handle");
esp_io_expander_ht8574_t *ht8574 = (esp_io_expander_ht8574_t *)calloc(1, sizeof(esp_io_expander_ht8574_t));
ESP_RETURN_ON_FALSE(ht8574, ESP_ERR_NO_MEM, TAG, "Malloc failed");
ht8574->base.config.io_count = IO_COUNT;
ht8574->base.config.flags.dir_out_bit_zero = 1;
ht8574->i2c_num = i2c_num;
ht8574->i2c_address = i2c_address;
ht8574->regs.output = OUT_REG_DEFAULT_VAL;
ht8574->base.read_input_reg = read_input_reg;
ht8574->base.write_output_reg = write_output_reg;
ht8574->base.read_output_reg = read_output_reg;
ht8574->base.write_direction_reg = write_direction_reg;
ht8574->base.read_direction_reg = read_direction_reg;
ht8574->base.del = del;
ht8574->base.reset = reset;
esp_err_t ret = ESP_OK;
/* Reset configuration and register status */
ESP_GOTO_ON_ERROR(reset(&ht8574->base), err, TAG, "Reset failed");
*handle = &ht8574->base;
return ESP_OK;
err:
free(ht8574);
return ret;
}
static esp_err_t read_input_reg(esp_io_expander_handle_t handle, uint32_t *value)
{
esp_io_expander_ht8574_t *ht8574 = (esp_io_expander_ht8574_t *)__containerof(handle, esp_io_expander_ht8574_t, base);
uint8_t temp = 0;
// *INDENT-OFF*
ESP_RETURN_ON_ERROR(
i2c_master_read_from_device(ht8574->i2c_num, ht8574->i2c_address, &temp, 1, pdMS_TO_TICKS(I2C_TIMEOUT_MS)),
TAG, "Read input reg failed");
// *INDENT-ON*
*value = temp;
return ESP_OK;
}
static esp_err_t write_output_reg(esp_io_expander_handle_t handle, uint32_t value)
{
esp_io_expander_ht8574_t *ht8574 = (esp_io_expander_ht8574_t *)__containerof(handle, esp_io_expander_ht8574_t, base);
value &= 0xff;
uint8_t data = (uint8_t)value;
ESP_RETURN_ON_ERROR(
i2c_master_write_to_device(ht8574->i2c_num, ht8574->i2c_address, &data, 1, pdMS_TO_TICKS(I2C_TIMEOUT_MS)),
TAG, "Write output reg failed");
ht8574->regs.output = value;
return ESP_OK;
}
static esp_err_t read_output_reg(esp_io_expander_handle_t handle, uint32_t *value)
{
esp_io_expander_ht8574_t *ht8574 = (esp_io_expander_ht8574_t *)__containerof(handle, esp_io_expander_ht8574_t, base);
*value = ht8574->regs.output;
return ESP_OK;
}
static esp_err_t write_direction_reg(esp_io_expander_handle_t handle, uint32_t value)
{
esp_io_expander_ht8574_t *ht8574 = (esp_io_expander_ht8574_t *)__containerof(handle, esp_io_expander_ht8574_t, base);
value &= 0xff;
ht8574->regs.direction = value;
return ESP_OK;
}
static esp_err_t read_direction_reg(esp_io_expander_handle_t handle, uint32_t *value)
{
esp_io_expander_ht8574_t *ht8574 = (esp_io_expander_ht8574_t *)__containerof(handle, esp_io_expander_ht8574_t, base);
*value = ht8574->regs.direction;
return ESP_OK;
}
static esp_err_t reset(esp_io_expander_t *handle)
{
ESP_RETURN_ON_ERROR(write_output_reg(handle, OUT_REG_DEFAULT_VAL), TAG, "Write output reg failed");
return ESP_OK;
}
static esp_err_t del(esp_io_expander_t *handle)
{
esp_io_expander_ht8574_t *ht8574 = (esp_io_expander_ht8574_t *)__containerof(handle, esp_io_expander_ht8574_t, base);
free(ht8574);
return ESP_OK;
}
@@ -0,0 +1,89 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include "driver/i2c.h"
#include "esp_err.h"
#include "../ESP_IOExpander.h"
class ESP_IOExpander_HT8574: public ESP_IOExpander {
public:
/**
* @brief Constructor to create ESP_IOExpander object
*
* @note After using this function, call `init()` will initialize I2C bus.
*
* @param id I2C port number
* @param address I2C device address. Should be like `ESP_IO_EXPANDER_I2C_*`.
* Can be found in the header file of each IO expander.h.
* @param config Pointer to I2C bus configuration
*/
ESP_IOExpander_HT8574(i2c_port_t id, uint8_t address, const i2c_config_t *config): ESP_IOExpander(id, address, config) { };
/**
* @brief Constructor to create ESP_IOExpander object
*
* @note After using this function, call `init()` will initialize I2C bus.
*
* @param id I2C port number
* @param address I2C device address. Should be like `ESP_IO_EXPANDER_I2C_*`.
* Can be found in the header file of each IO expander.h.
* @param scl SCL pin number
* @param sda SDA pin number
*/
ESP_IOExpander_HT8574(i2c_port_t id, uint8_t address, int scl, int sda): ESP_IOExpander(id, address, scl, sda) { };
/**
* @brief Constructor to create ESP_IOExpander object
*
* @note If use this function, should initialize I2C bus before call `init()`.
*
* @param id I2C port number
* @param address I2C device address. Should be like `ESP_IO_EXPANDER_I2C_*`.
* Can be found in the header file of each IO expander.h.
*/
ESP_IOExpander_HT8574(i2c_port_t id, uint8_t address): ESP_IOExpander(id, address) { };
/**
* @brief Destructor
*
* @note This function will delete I2C driver if it is initialized by ESP_IOExpander and delete ESP_IOExpander object.
*/
~ESP_IOExpander_HT8574() override;
/**
* @brief Begin IO expander
*
*/
void begin(void) override;
};
/**
* @brief I2C address of the ht8574
*
* The 8-bit address format is as follows:
*
* (Slave Address)
* ┌─────────────────┷─────────────────┐
* ┌─────┐─────┐─────┐─────┐─────┐─────┐─────┐─────┐
* | 0 | 1 | 1 | 1 | A2 | A1 | A0 | R/W |
* └─────┘─────┘─────┘─────┘─────┘─────┘─────┘─────┘
* └────────┯────────┘ └─────┯──────┘
* (Fixed) (Hareware Selectable)
*
* And the 7-bit slave address is the most important data for users.
* For example, if a chip's A0,A1,A2 are connected to GND, it's 7-bit slave address is 0111000b(0x38).
* Then users can use `ESP_IO_EXPANDER_I2C_HT8574_ADDRESS_000` to init it.
*/
#define ESP_IO_EXPANDER_I2C_HT8574_ADDRESS_000 (0x38)
#define ESP_IO_EXPANDER_I2C_HT8574_ADDRESS_001 (0x29)
#define ESP_IO_EXPANDER_I2C_HT8574_ADDRESS_010 (0x2A)
#define ESP_IO_EXPANDER_I2C_HT8574_ADDRESS_011 (0x2B)
#define ESP_IO_EXPANDER_I2C_HT8574_ADDRESS_100 (0x2C)
@@ -0,0 +1,175 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <inttypes.h>
#include <string.h>
#include <stdlib.h>
#include "driver/i2c.h"
#include "esp_bit_defs.h"
#include "esp_check.h"
#include "esp_log.h"
#include "../private/CheckResult.h"
#include "TCA95xx_16bit.h"
/* Timeout of each I2C communication */
#define I2C_TIMEOUT_MS (10)
#define IO_COUNT (16)
/* Register address */
#define INPUT_REG_ADDR (0x00)
#define OUTPUT_REG_ADDR (0x02)
#define DIRECTION_REG_ADDR (0x06)
/* Default register value on power-up */
#define DIR_REG_DEFAULT_VAL (0xffff)
#define OUT_REG_DEFAULT_VAL (0xffff)
/**
* @brief Device Structure Type
*
*/
typedef struct {
esp_io_expander_t base;
i2c_port_t i2c_num;
uint32_t i2c_address;
struct {
uint8_t direction;
uint8_t output;
} regs;
} esp_io_expander_tca95xx_16bit_t;
static const char *TAG = "tca95xx_16bit";
ESP_IOExpander_TCA95xx_16bit::~ESP_IOExpander_TCA95xx_16bit()
{
if (i2c_need_init) {
i2c_driver_delete(i2c_id);
}
if (handle) {
del();
}
}
static esp_err_t esp_io_expander_new_i2c_tca95xx_16bit(i2c_port_t i2c_num, uint32_t i2c_address, esp_io_expander_handle_t *handle);
void ESP_IOExpander_TCA95xx_16bit::begin(void)
{
CHECK_ERROR_RETURN(esp_io_expander_new_i2c_tca95xx_16bit(i2c_id, i2c_address, &handle));
}
static esp_err_t read_input_reg(esp_io_expander_handle_t handle, uint32_t *value);
static esp_err_t write_output_reg(esp_io_expander_handle_t handle, uint32_t value);
static esp_err_t read_output_reg(esp_io_expander_handle_t handle, uint32_t *value);
static esp_err_t write_direction_reg(esp_io_expander_handle_t handle, uint32_t value);
static esp_err_t read_direction_reg(esp_io_expander_handle_t handle, uint32_t *value);
static esp_err_t reset(esp_io_expander_t *handle);
static esp_err_t del(esp_io_expander_t *handle);
static esp_err_t esp_io_expander_new_i2c_tca95xx_16bit(i2c_port_t i2c_num, uint32_t i2c_address, esp_io_expander_handle_t *handle)
{
ESP_RETURN_ON_FALSE(i2c_num < I2C_NUM_MAX, ESP_ERR_INVALID_ARG, TAG, "Invalid i2c num");
ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "Invalid handle");
esp_io_expander_tca95xx_16bit_t *tca = (esp_io_expander_tca95xx_16bit_t *)calloc(1, sizeof(esp_io_expander_tca95xx_16bit_t));
ESP_RETURN_ON_FALSE(tca, ESP_ERR_NO_MEM, TAG, "Malloc failed");
tca->base.config.io_count = IO_COUNT;
tca->base.config.flags.dir_out_bit_zero = 1;
tca->i2c_num = i2c_num;
tca->i2c_address = i2c_address;
tca->base.read_input_reg = read_input_reg;
tca->base.write_output_reg = write_output_reg;
tca->base.read_output_reg = read_output_reg;
tca->base.write_direction_reg = write_direction_reg;
tca->base.read_direction_reg = read_direction_reg;
tca->base.del = del;
tca->base.reset = reset;
esp_err_t ret = ESP_OK;
/* Reset configuration and register status */
ESP_GOTO_ON_ERROR(reset(&tca->base), err, TAG, "Reset failed");
*handle = &tca->base;
return ESP_OK;
err:
free(tca);
return ret;
}
static esp_err_t read_input_reg(esp_io_expander_handle_t handle, uint32_t *value)
{
esp_io_expander_tca95xx_16bit_t *tca = (esp_io_expander_tca95xx_16bit_t *)__containerof(handle, esp_io_expander_tca95xx_16bit_t, base);
uint8_t temp[2] = {0, 0};
uint8_t reg = INPUT_REG_ADDR;
// *INDENT-OFF*
ESP_RETURN_ON_ERROR(
i2c_master_write_read_device(tca->i2c_num, tca->i2c_address, &reg, 1, (uint8_t*)&temp, 2, pdMS_TO_TICKS(I2C_TIMEOUT_MS)),
TAG, "Read input reg failed");
// *INDENT-ON*
*value = (((uint32_t)temp[0]) << 8) | (temp[1]);
return ESP_OK;
}
static esp_err_t write_output_reg(esp_io_expander_handle_t handle, uint32_t value)
{
esp_io_expander_tca95xx_16bit_t *tca = (esp_io_expander_tca95xx_16bit_t *)__containerof(handle, esp_io_expander_tca95xx_16bit_t, base);
value &= 0xffff;
uint8_t data[] = {OUTPUT_REG_ADDR, (uint8_t)(value >> 8), (uint8_t)(value & 0xff)};
ESP_RETURN_ON_ERROR(
i2c_master_write_to_device(tca->i2c_num, tca->i2c_address, data, sizeof(data), pdMS_TO_TICKS(I2C_TIMEOUT_MS)),
TAG, "Write output reg failed");
tca->regs.output = value;
return ESP_OK;
}
static esp_err_t read_output_reg(esp_io_expander_handle_t handle, uint32_t *value)
{
esp_io_expander_tca95xx_16bit_t *tca = (esp_io_expander_tca95xx_16bit_t *)__containerof(handle, esp_io_expander_tca95xx_16bit_t, base);
*value = tca->regs.output;
return ESP_OK;
}
static esp_err_t write_direction_reg(esp_io_expander_handle_t handle, uint32_t value)
{
esp_io_expander_tca95xx_16bit_t *tca = (esp_io_expander_tca95xx_16bit_t *)__containerof(handle, esp_io_expander_tca95xx_16bit_t, base);
value &= 0xffff;
uint8_t data[] = {DIRECTION_REG_ADDR, (uint8_t)(value >> 8), (uint8_t)(value & 0xff)};
ESP_RETURN_ON_ERROR(
i2c_master_write_to_device(tca->i2c_num, tca->i2c_address, data, sizeof(data), pdMS_TO_TICKS(I2C_TIMEOUT_MS)),
TAG, "Write direction reg failed");
tca->regs.direction = value;
return ESP_OK;
}
static esp_err_t read_direction_reg(esp_io_expander_handle_t handle, uint32_t *value)
{
esp_io_expander_tca95xx_16bit_t *tca = (esp_io_expander_tca95xx_16bit_t *)__containerof(handle, esp_io_expander_tca95xx_16bit_t, base);
*value = tca->regs.direction;
return ESP_OK;
}
static esp_err_t reset(esp_io_expander_t *handle)
{
ESP_RETURN_ON_ERROR(write_direction_reg(handle, DIR_REG_DEFAULT_VAL), TAG, "Write dir reg failed");
ESP_RETURN_ON_ERROR(write_output_reg(handle, OUT_REG_DEFAULT_VAL), TAG, "Write output reg failed");
return ESP_OK;
}
static esp_err_t del(esp_io_expander_t *handle)
{
esp_io_expander_tca95xx_16bit_t *tca = (esp_io_expander_tca95xx_16bit_t *)__containerof(handle, esp_io_expander_tca95xx_16bit_t, base);
free(tca);
return ESP_OK;
}
@@ -0,0 +1,108 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include "driver/i2c.h"
#include "esp_err.h"
#include "../ESP_IOExpander.h"
class ESP_IOExpander_TCA95xx_16bit: public ESP_IOExpander {
public:
/**
* @brief Constructor to create ESP_IOExpander object
*
* @note After using this function, call `init()` will initialize I2C bus.
*
* @param id I2C port number
* @param address I2C device address. Should be like `ESP_IO_EXPANDER_I2C_*`.
* Can be found in the header file of each IO expander.h.
* @param config Pointer to I2C bus configuration
*/
ESP_IOExpander_TCA95xx_16bit(i2c_port_t id, uint8_t address, const i2c_config_t *config): ESP_IOExpander(id, address, config) { };
/**
* @brief Constructor to create ESP_IOExpander object
*
* @note After using this function, call `init()` will initialize I2C bus.
*
* @param id I2C port number
* @param address I2C device address. Should be like `ESP_IO_EXPANDER_I2C_*`.
* Can be found in the header file of each IO expander.h.
* @param scl SCL pin number
* @param sda SDA pin number
*/
ESP_IOExpander_TCA95xx_16bit(i2c_port_t id, uint8_t address, int scl, int sda): ESP_IOExpander(id, address, scl, sda) { };
/**
* @brief Constructor to create ESP_IOExpander object
*
* @note If use this function, should initialize I2C bus before call `init()`.
*
* @param id I2C port number
* @param address I2C device address. Should be like `ESP_IO_EXPANDER_I2C_*`.
* Can be found in the header file of each IO expander.h.
*/
ESP_IOExpander_TCA95xx_16bit(i2c_port_t id, uint8_t address): ESP_IOExpander(id, address) { };
/**
* @brief Destructor
*
* @note This function will delete I2C driver if it is initialized by ESP_IOExpander and delete ESP_IOExpander object.
*/
~ESP_IOExpander_TCA95xx_16bit() override;
/**
* @brief Begin IO expander
*
*/
void begin(void) override;
};
/**
* @brief I2C address of the TCA9539 or TCA9555
*
* The 8-bit address format for the TCA9539 is as follows:
*
* (Slave Address)
* ┌─────────────────┷─────────────────┐
* ┌─────┐─────┐─────┐─────┐─────┐─────┐─────┐─────┐
* | 1 | 1 | 1 | 0 | 1 | A1 | A0 | R/W |
* └─────┘─────┘─────┘─────┘─────┘─────┘─────┘─────┘
* └────────┯──────────────┘ └──┯──┘
* (Fixed) (Hareware Selectable)
*
* The 8-bit address format for the TCA9555 is as follows:
*
* (Slave Address)
* ┌─────────────────┷─────────────────┐
* ┌─────┐─────┐─────┐─────┐─────┐─────┐─────┐─────┐
* | 0 | 1 | 0 | 0 | A2 | A1 | A0 | R/W |
* └─────┘─────┘─────┘─────┘─────┘─────┘─────┘─────┘
* └────────┯────────┘ └─────┯──────┘
* (Fixed) (Hareware Selectable)
*
* And the 7-bit slave address is the most important data for users.
* For example, if a TCA9555 chip's A0,A1,A2 are connected to GND, it's 7-bit slave address is 0b0100000.
* Then users can use `ESP_IO_EXPANDER_I2C_TCA9555_ADDRESS_000` to init it.
*/
enum esp_io_expander_tca_95xx_16bit_address {
ESP_IO_EXPANDER_I2C_TCA9539_ADDRESS_00 = 0b1110100,
ESP_IO_EXPANDER_I2C_TCA9539_ADDRESS_01 = 0b1110101,
ESP_IO_EXPANDER_I2C_TCA9539_ADDRESS_10 = 0b1110110,
ESP_IO_EXPANDER_I2C_TCA9539_ADDRESS_11 = 0b1110111,
ESP_IO_EXPANDER_I2C_TCA9555_ADDRESS_000 = 0b0100000,
ESP_IO_EXPANDER_I2C_TCA9555_ADDRESS_001 = 0b0100001,
ESP_IO_EXPANDER_I2C_TCA9555_ADDRESS_010 = 0b0100010,
ESP_IO_EXPANDER_I2C_TCA9555_ADDRESS_011 = 0b0100011,
ESP_IO_EXPANDER_I2C_TCA9555_ADDRESS_100 = 0b0100000,
ESP_IO_EXPANDER_I2C_TCA9555_ADDRESS_101 = 0b0100101,
ESP_IO_EXPANDER_I2C_TCA9555_ADDRESS_110 = 0b0100110,
ESP_IO_EXPANDER_I2C_TCA9555_ADDRESS_111 = 0b0100111,
};
@@ -0,0 +1,175 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <inttypes.h>
#include <string.h>
#include <stdlib.h>
#include "driver/i2c.h"
#include "esp_bit_defs.h"
#include "esp_check.h"
#include "esp_log.h"
#include "../private/CheckResult.h"
#include "TCA95xx_8bit.h"
/* Timeout of each I2C communication */
#define I2C_TIMEOUT_MS (10)
#define IO_COUNT (8)
/* Register address */
#define INPUT_REG_ADDR (0x00)
#define OUTPUT_REG_ADDR (0x01)
#define DIRECTION_REG_ADDR (0x03)
/* Default register value on power-up */
#define DIR_REG_DEFAULT_VAL (0xff)
#define OUT_REG_DEFAULT_VAL (0xff)
/**
* @brief Device Structure Type
*
*/
typedef struct {
esp_io_expander_t base;
i2c_port_t i2c_num;
uint32_t i2c_address;
struct {
uint8_t direction;
uint8_t output;
} regs;
} esp_io_expander_tca95xx_8bit_t;
static const char *TAG = "tca95xx_8bit";
static esp_err_t esp_io_expander_new_i2c_tca95xx_8bit(i2c_port_t i2c_num, uint32_t i2c_address, esp_io_expander_handle_t *handle);
ESP_IOExpander_TCA95xx_8bit::~ESP_IOExpander_TCA95xx_8bit()
{
if (i2c_need_init) {
i2c_driver_delete(i2c_id);
}
if (handle) {
del();
}
}
void ESP_IOExpander_TCA95xx_8bit::begin(void)
{
CHECK_ERROR_RETURN(esp_io_expander_new_i2c_tca95xx_8bit(i2c_id, i2c_address, &handle));
}
static esp_err_t read_input_reg(esp_io_expander_handle_t handle, uint32_t *value);
static esp_err_t write_output_reg(esp_io_expander_handle_t handle, uint32_t value);
static esp_err_t read_output_reg(esp_io_expander_handle_t handle, uint32_t *value);
static esp_err_t write_direction_reg(esp_io_expander_handle_t handle, uint32_t value);
static esp_err_t read_direction_reg(esp_io_expander_handle_t handle, uint32_t *value);
static esp_err_t reset(esp_io_expander_t *handle);
static esp_err_t del(esp_io_expander_t *handle);
static esp_err_t esp_io_expander_new_i2c_tca95xx_8bit(i2c_port_t i2c_num, uint32_t i2c_address, esp_io_expander_handle_t *handle)
{
ESP_RETURN_ON_FALSE(i2c_num < I2C_NUM_MAX, ESP_ERR_INVALID_ARG, TAG, "Invalid i2c num");
ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "Invalid handle");
esp_io_expander_tca95xx_8bit_t *tca = (esp_io_expander_tca95xx_8bit_t *)calloc(1, sizeof(esp_io_expander_tca95xx_8bit_t));
ESP_RETURN_ON_FALSE(tca, ESP_ERR_NO_MEM, TAG, "Malloc failed");
tca->base.config.io_count = IO_COUNT;
tca->base.config.flags.dir_out_bit_zero = 1;
tca->i2c_num = i2c_num;
tca->i2c_address = i2c_address;
tca->base.read_input_reg = read_input_reg;
tca->base.write_output_reg = write_output_reg;
tca->base.read_output_reg = read_output_reg;
tca->base.write_direction_reg = write_direction_reg;
tca->base.read_direction_reg = read_direction_reg;
tca->base.del = del;
tca->base.reset = reset;
esp_err_t ret = ESP_OK;
/* Reset configuration and register status */
ESP_GOTO_ON_ERROR(reset(&tca->base), err, TAG, "Reset failed");
*handle = &tca->base;
return ESP_OK;
err:
free(tca);
return ret;
}
static esp_err_t read_input_reg(esp_io_expander_handle_t handle, uint32_t *value)
{
esp_io_expander_tca95xx_8bit_t *tca = (esp_io_expander_tca95xx_8bit_t *)__containerof(handle, esp_io_expander_tca95xx_8bit_t, base);
uint8_t temp = 0;
uint8_t reg = INPUT_REG_ADDR;
// *INDENT-OFF*
ESP_RETURN_ON_ERROR(
i2c_master_write_read_device(tca->i2c_num, tca->i2c_address, &reg, 1, &temp, 1, pdMS_TO_TICKS(I2C_TIMEOUT_MS)),
TAG, "Read input reg failed");
// *INDENT-ON*
*value = temp;
return ESP_OK;
}
static esp_err_t write_output_reg(esp_io_expander_handle_t handle, uint32_t value)
{
esp_io_expander_tca95xx_8bit_t *tca = (esp_io_expander_tca95xx_8bit_t *)__containerof(handle, esp_io_expander_tca95xx_8bit_t, base);
value &= 0xff;
uint8_t data[] = {OUTPUT_REG_ADDR, (uint8_t)value};
ESP_RETURN_ON_ERROR(
i2c_master_write_to_device(tca->i2c_num, tca->i2c_address, data, sizeof(data), pdMS_TO_TICKS(I2C_TIMEOUT_MS)),
TAG, "Write output reg failed");
tca->regs.output = value;
return ESP_OK;
}
static esp_err_t read_output_reg(esp_io_expander_handle_t handle, uint32_t *value)
{
esp_io_expander_tca95xx_8bit_t *tca = (esp_io_expander_tca95xx_8bit_t *)__containerof(handle, esp_io_expander_tca95xx_8bit_t, base);
*value = tca->regs.output;
return ESP_OK;
}
static esp_err_t write_direction_reg(esp_io_expander_handle_t handle, uint32_t value)
{
esp_io_expander_tca95xx_8bit_t *tca = (esp_io_expander_tca95xx_8bit_t *)__containerof(handle, esp_io_expander_tca95xx_8bit_t, base);
value &= 0xff;
uint8_t data[] = {DIRECTION_REG_ADDR, (uint8_t)value};
ESP_RETURN_ON_ERROR(
i2c_master_write_to_device(tca->i2c_num, tca->i2c_address, data, sizeof(data), pdMS_TO_TICKS(I2C_TIMEOUT_MS)),
TAG, "Write direction reg failed");
tca->regs.direction = value;
return ESP_OK;
}
static esp_err_t read_direction_reg(esp_io_expander_handle_t handle, uint32_t *value)
{
esp_io_expander_tca95xx_8bit_t *tca = (esp_io_expander_tca95xx_8bit_t *)__containerof(handle, esp_io_expander_tca95xx_8bit_t, base);
*value = tca->regs.direction;
return ESP_OK;
}
static esp_err_t reset(esp_io_expander_t *handle)
{
ESP_RETURN_ON_ERROR(write_direction_reg(handle, DIR_REG_DEFAULT_VAL), TAG, "Write dir reg failed");
ESP_RETURN_ON_ERROR(write_output_reg(handle, OUT_REG_DEFAULT_VAL), TAG, "Write output reg failed");
return ESP_OK;
}
static esp_err_t del(esp_io_expander_t *handle)
{
esp_io_expander_tca95xx_8bit_t *tca = (esp_io_expander_tca95xx_8bit_t *)__containerof(handle, esp_io_expander_tca95xx_8bit_t, base);
free(tca);
return ESP_OK;
}
@@ -0,0 +1,119 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include "driver/i2c.h"
#include "esp_err.h"
#include "../ESP_IOExpander.h"
class ESP_IOExpander_TCA95xx_8bit: public ESP_IOExpander {
public:
/**
* @brief Constructor to create ESP_IOExpander object
*
* @note After using this function, call `init()` will initialize I2C bus.
*
* @param id I2C port number
* @param address I2C device address. Should be like `ESP_IO_EXPANDER_I2C_*`.
* Can be found in the header file of each IO expander.h.
* @param config Pointer to I2C bus configuration
*/
ESP_IOExpander_TCA95xx_8bit(i2c_port_t id, uint8_t address, const i2c_config_t *config): ESP_IOExpander(id, address, config) { };
/**
* @brief Constructor to create ESP_IOExpander object
*
* @note After using this function, call `init()` will initialize I2C bus.
*
* @param id I2C port number
* @param address I2C device address. Should be like `ESP_IO_EXPANDER_I2C_*`.
* Can be found in the header file of each IO expander.h.
* @param scl SCL pin number
* @param sda SDA pin number
*/
ESP_IOExpander_TCA95xx_8bit(i2c_port_t id, uint8_t address, int scl, int sda): ESP_IOExpander(id, address, scl, sda) { };
/**
* @brief Constructor to create ESP_IOExpander object
*
* @note If use this function, should initialize I2C bus before call `init()`.
*
* @param id I2C port number
* @param address I2C device address. Should be like `ESP_IO_EXPANDER_I2C_*`.
* Can be found in the header file of each IO expander.h.
*/
ESP_IOExpander_TCA95xx_8bit(i2c_port_t id, uint8_t address): ESP_IOExpander(id, address) { };
/**
* @brief Destructor
*
* @note This function will delete I2C driver if it is initialized by ESP_IOExpander and delete ESP_IOExpander object.
*/
~ESP_IOExpander_TCA95xx_8bit() override;
/**
* @brief Begin IO expander
*
*/
void begin(void) override;
};
/**
* @brief I2C address of the TCA9554
*
* The 8-bit address format is as follows:
*
* (Slave Address)
* ┌─────────────────┷─────────────────┐
* ┌─────┐─────┐─────┐─────┐─────┐─────┐─────┐─────┐
* | 0 | 1 | 0 | 0 | A2 | A1 | A0 | R/W |
* └─────┘─────┘─────┘─────┘─────┘─────┘─────┘─────┘
* └────────┯────────┘ └─────┯──────┘
* (Fixed) (Hareware Selectable)
*
* And the 7-bit slave address is the most important data for users.
* For example, if a chip's A0,A1,A2 are connected to GND, it's 7-bit slave address is 0100000b(0x20).
* Then users can use `ESP_IO_EXPANDER_I2C_TCA9554_ADDRESS_000` to init it.
*/
#define ESP_IO_EXPANDER_I2C_TCA9554_ADDRESS_000 (0x20)
#define ESP_IO_EXPANDER_I2C_TCA9554_ADDRESS_001 (0x21)
#define ESP_IO_EXPANDER_I2C_TCA9554_ADDRESS_010 (0x22)
#define ESP_IO_EXPANDER_I2C_TCA9554_ADDRESS_011 (0x23)
#define ESP_IO_EXPANDER_I2C_TCA9554_ADDRESS_100 (0x24)
#define ESP_IO_EXPANDER_I2C_TCA9554_ADDRESS_101 (0x25)
#define ESP_IO_EXPANDER_I2C_TCA9554_ADDRESS_110 (0x26)
#define ESP_IO_EXPANDER_I2C_TCA9554_ADDRESS_111 (0x27)
/**
* @brief I2C address of the TCA9554A
*
* The 8-bit address format is as follows:
*
* (Slave Address)
* ┌─────────────────┷─────────────────┐
* ┌─────┐─────┐─────┐─────┐─────┐─────┐─────┐─────┐
* | 0 | 1 | 1 | 1 | A2 | A1 | A0 | R/W |
* └─────┘─────┘─────┘─────┘─────┘─────┘─────┘─────┘
* └────────┯────────┘ └─────┯──────┘
* (Fixed) (Hareware Selectable)
*
* And the 7-bit slave address is the most important data for users.
* For example, if a chip's A0,A1,A2 are connected to GND, it's 7-bit slave address is 0111000b(0x38).
* Then users can use `ESP_IO_EXPANDER_I2C_TCA9554A_ADDRESS_000` to init it.
*/
#define ESP_IO_EXPANDER_I2C_TCA9554A_ADDRESS_000 (0x38)
#define ESP_IO_EXPANDER_I2C_TCA9554A_ADDRESS_001 (0x39)
#define ESP_IO_EXPANDER_I2C_TCA9554A_ADDRESS_010 (0x3A)
#define ESP_IO_EXPANDER_I2C_TCA9554A_ADDRESS_011 (0x3B)
#define ESP_IO_EXPANDER_I2C_TCA9554A_ADDRESS_100 (0x3C)
#define ESP_IO_EXPANDER_I2C_TCA9554A_ADDRESS_101 (0x3D)
#define ESP_IO_EXPANDER_I2C_TCA9554A_ADDRESS_110 (0x3E)
#define ESP_IO_EXPANDER_I2C_TCA9554A_ADDRESS_111 (0x3F)