Skip to content

feat(chip): add chip ch422g #4

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 11 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,22 @@
# ChangeLog

## v0.0.1 - 2023-09-20
## v0.0.3 - 2024-05-07

### Enhancements:

* Support for various IO expander chips.
* Support to control individual IO in the same way as Arduino
* Support to control multiple IOs at the same time.
* Add support for CH422G from Waveshare (@lboue)
* Update the example to show how to use the CH422G

## v0.0.2 - 2023-10-07

### Bug Fixes:

* Correct library name in `sentence` field of metadata

## v0.0.1 - 2023-09-20

### Enhancements:

* Support for various IO expander chips.
* Support to control individual IO in the same way as Arduino
* Support to control multiple IOs at the same time.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@ ESP32_IO_Expander encapsulates various components from the [Espressif Components
| [TCA95xx (8bit)](https://components.espressif.com/components/espressif/esp_io_expander_tca9554) | 1.0.1 |
| [TCA95xx (16bit)](https://components.espressif.com/components/espressif/esp_io_expander_tca95xx_16bit) | 1.0.0 |
| [HT8574](https://components.espressif.com/components/espressif/esp_io_expander_ht8574) | 1.0.0 |
| CH422G | x |

## Dependencies Version

| **Name** | **Version** |
| ----------------------------------------------------------- | ----------- |
| ESP32_IO_Expander | v0.x.x |
| [arduino-esp32](https://github.com/espressif/arduino-esp32) | >= v2.0.9 |

## How to Use
Expand Down
24 changes: 16 additions & 8 deletions examples/TestFunctions/TestFunctions.ino
Original file line number Diff line number Diff line change
@@ -1,23 +1,31 @@
#include <Arduino.h>
#include <ESP_IOExpander_Library.h>

#define EXAMPLE_I2C_NUM (0)
#define EXAMPLE_I2C_SDA_PIN (8)
#define EXAMPLE_I2C_SCL_PIN (18)

/**
* Create an ESP_IOExpander object, Currently supports:
* - TCA95xx (8bit)
* - TCA95xx (16bit)
* - TCA95xx_8bit
* - TCA95xx_16bit
* - HT8574
* - CH422G
*/
ESP_IOExpander *expander = new ESP_IOExpander_TCA95xx_8bit(EXAMPLE_I2C_NUM, ESP_IO_EXPANDER_I2C_TCA9554_ADDRESS_000, EXAMPLE_I2C_SCL_PIN, EXAMPLE_I2C_SDA_PIN);
#define EXAMPLE_CHIP_NAME TCA95xx_8bit
#define EXAMPLE_I2C_NUM (0)
#define EXAMPLE_I2C_SDA_PIN (8)
#define EXAMPLE_I2C_SCL_PIN (18)

#define _EXAMPLE_CHIP_CLASS(name, ...) ESP_IOExpander_##name(__VA_ARGS__)
#define EXAMPLE_CHIP_CLASS(name, ...) _EXAMPLE_CHIP_CLASS(name, ##__VA_ARGS__)

ESP_IOExpander *expander = NULL;

void setup()
{
Serial.begin(115200);
Serial.println("Test begin");

expander = new EXAMPLE_CHIP_CLASS(EXAMPLE_CHIP_NAME,
(i2c_port_t)EXAMPLE_I2C_NUM, ESP_IO_EXPANDER_I2C_TCA9554_ADDRESS_000,
EXAMPLE_I2C_SCL_PIN, EXAMPLE_I2C_SDA_PIN);
expander->init();
expander->begin();

Expand Down Expand Up @@ -68,5 +76,5 @@ void loop()
Serial.print(", ");
Serial.println(level[3]);

sleep(1);
delay(1000);
}
4 changes: 2 additions & 2 deletions library.properties
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
name=ESP32_IO_Expander
version=0.0.2
version=0.0.3
author=lzw655
maintainer=espressif
sentence=ESP32_IO_Expander is a library designed for driving IO expander chips using ESP32 SoCs
paragraph=Currently support TCA95xx(8bit), TCA95xx(16bit), HT8574
paragraph=Currently support TCA95xx(8bit), TCA95xx(16bit), HT8574, CH422G
category=Other
architectures=esp32
url=https://github.com/esp-arduino-libs/ESP32_IO_Expander
Expand Down
1 change: 1 addition & 0 deletions src/ESP_IOExpander_Library.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,6 @@
#include "chip/TCA95xx_8bit.h"
#include "chip/TCA95xx_16bit.h"
#include "chip/HT8574.h"
#include "chip/CH422G.h"

#endif
178 changes: 178 additions & 0 deletions src/chip/CH422G.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
/*
* SPDX-FileCopyrightText: 2024 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 "CH422G.h"

/* Timeout of each I2C communication */
#define I2C_TIMEOUT_MS (10)

#define IO_COUNT (8)

/* Register address */
#define CH422G_REG_IN (0x26)
#define CH422G_REG_OUT (0x38)

/* Default register value on power-up */
#define DIR_REG_DEFAULT_VAL (0xff)
#define OUT_REG_DEFAULT_VAL (0xdf)

/**
* @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_ch422g_t;

static const char *TAG = "ch422g";

static esp_err_t esp_io_expander_new_i2c_ch422g(i2c_port_t i2c_num, uint32_t i2c_address, esp_io_expander_handle_t *handle);

ESP_IOExpander_CH422G::~ESP_IOExpander_CH422G()
{
if (i2c_need_init) {
i2c_driver_delete(i2c_id);
}
if (handle) {
del();
}
}

void ESP_IOExpander_CH422G::begin(void)
{
CHECK_ERROR_RETURN(esp_io_expander_new_i2c_ch422g(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_ch422g(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_ch422g_t *ch422g = (esp_io_expander_ch422g_t *)calloc(1, sizeof(esp_io_expander_ch422g_t));
ESP_RETURN_ON_FALSE(ch422g, ESP_ERR_NO_MEM, TAG, "Malloc failed");

ch422g->base.config.io_count = IO_COUNT;
ch422g->base.config.flags.dir_out_bit_zero = 1;
ch422g->i2c_num = i2c_num;
ch422g->i2c_address = i2c_address;
ch422g->regs.output = OUT_REG_DEFAULT_VAL;
ch422g->base.read_input_reg = read_input_reg;
ch422g->base.write_output_reg = write_output_reg;
ch422g->base.read_output_reg = read_output_reg;
ch422g->base.write_direction_reg = write_direction_reg;
ch422g->base.read_direction_reg = read_direction_reg;
ch422g->base.del = del;
ch422g->base.reset = reset;

esp_err_t ret = ESP_OK;
/* Reset configuration and register status */
ESP_GOTO_ON_ERROR(reset(&ch422g->base), err, TAG, "Reset failed");

*handle = &ch422g->base;
return ESP_OK;
err:
free(ch422g);
return ret;
}

static esp_err_t read_input_reg(esp_io_expander_handle_t handle, uint32_t *value)
{
esp_io_expander_ch422g_t *ch422g = (esp_io_expander_ch422g_t *)__containerof(handle, esp_io_expander_ch422g_t, base);

uint8_t temp = 0;

ESP_RETURN_ON_ERROR(
i2c_master_read_from_device(ch422g->i2c_num, ch422g->i2c_address, &temp, 1, pdMS_TO_TICKS(I2C_TIMEOUT_MS)),
TAG, "Read input reg failed");

// *INDENT-OFF*
ESP_RETURN_ON_ERROR(
i2c_master_read_from_device(ch422g->i2c_num, CH422G_REG_IN, &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_ch422g_t *ch422g = (esp_io_expander_ch422g_t *)__containerof(handle, esp_io_expander_ch422g_t, base);
value &= 0xff;

uint8_t out_temp = 0x01;
ESP_RETURN_ON_ERROR(
i2c_master_write_to_device(ch422g->i2c_num, ch422g->i2c_address, &out_temp, 1, pdMS_TO_TICKS(I2C_TIMEOUT_MS)),
TAG, "Write output reg failed");

uint8_t data = (uint8_t)value;
ESP_RETURN_ON_ERROR(
i2c_master_write_to_device(ch422g->i2c_num, CH422G_REG_OUT, &data, 1, pdMS_TO_TICKS(I2C_TIMEOUT_MS)),
TAG, "Write output reg failed");
ch422g->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_ch422g_t *ch422g = (esp_io_expander_ch422g_t *)__containerof(handle, esp_io_expander_ch422g_t, base);

*value = ch422g->regs.output;
return ESP_OK;
}

static esp_err_t write_direction_reg(esp_io_expander_handle_t handle, uint32_t value)
{
esp_io_expander_ch422g_t *ch422g = (esp_io_expander_ch422g_t *)__containerof(handle, esp_io_expander_ch422g_t, base);
value &= 0xff;
ch422g->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_ch422g_t *ch422g = (esp_io_expander_ch422g_t *)__containerof(handle, esp_io_expander_ch422g_t, base);

*value = ch422g->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_ch422g_t *ch422g = (esp_io_expander_ch422g_t *)__containerof(handle, esp_io_expander_ch422g_t, base);

free(ch422g);
return ESP_OK;
}
75 changes: 75 additions & 0 deletions src/chip/CH422G.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* SPDX-FileCopyrightText: 2024 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_CH422G: 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_CH422G(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_CH422G(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_CH422G(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_CH422G() override;

/**
* @brief Begin IO expander
*
*/
void begin(void) override;
};

/**
* @brief I2C address of the ch422g
*
* 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 1001000b(0x48).
* Then users can use `ESP_IO_EXPANDER_I2C_CH422G_ADDRESS_000` to init it.
*/
#define ESP_IO_EXPANDER_I2C_CH422G_ADDRESS_000 (0x24)
Loading