Skip to content

Commit ec03f61

Browse files
committed
feat(ch422g): support OCx output
Closes #5
1 parent e5378da commit ec03f61

File tree

6 files changed

+147
-43
lines changed

6 files changed

+147
-43
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# ChangeLog
22

3+
## v0.0.4 - 2024-10-09
4+
5+
### Enhancements:
6+
7+
* feat(ch422g): support OCx output
8+
39
## v0.0.3 - 2024-05-07
410

511
### Enhancements:

examples/TestFunctions/TestFunctions.ino

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,17 @@ void setup()
2929
expander->init();
3030
expander->begin();
3131

32+
/* For CH422G */
33+
/**
34+
* Pin mapping:
35+
*
36+
* | Pin Number | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
37+
* | ------------ | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
38+
* | Function | IO0 | IO1 | IO2 | IO3 | IO4 | IO5 | IO6 | IO7 | OC0 | OC1 | OC2 | OC3 |
39+
*/
40+
// static_cast<ESP_IOExpander_CH422G *>(expander)->enableOC_PushPull();
41+
// static_cast<ESP_IOExpander_CH422G *>(expander)->enableOC_OpenDrain();
42+
3243
Serial.println("Original status:");
3344
expander->printStatus();
3445

library.properties

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name=ESP32_IO_Expander
2-
version=0.0.3
3-
author=lzw655
2+
version=0.0.4
3+
author=espressif
44
maintainer=espressif
55
sentence=ESP32_IO_Expander is a library designed for driving IO expander chips using ESP32 SoCs
66
paragraph=Currently support TCA95xx(8bit), TCA95xx(16bit), HT8574, CH422G

src/chip/CH422G.cpp

Lines changed: 107 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,28 @@
1919
/* Timeout of each I2C communication */
2020
#define I2C_TIMEOUT_MS (10)
2121

22-
#define IO_COUNT (8)
22+
#define IO_COUNT (12)
2323

2424
/* Register address */
25-
#define CH422G_REG_IN (0x26)
26-
#define CH422G_REG_OUT (0x38)
25+
#define CH422G_REG_WR_SET (0x48)
26+
#define CH422G_REG_WR_OC (0x46)
27+
#define CH422G_REG_WR_IO (0x70)
28+
#define CH422G_REG_RD_IO (0x4D)
2729

2830
/* Default register value on power-up */
29-
#define DIR_REG_DEFAULT_VAL (0xff)
30-
#define OUT_REG_DEFAULT_VAL (0xdf)
31+
// *INDENT-OFF*
32+
#define REG_WR_SET_DEFAULT_VAL (0x00UL) // Bit: | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
33+
// |---------|---|---|---------|---|----------|---|---------|
34+
// Value: | [SLEEP] | 0 | 0 | [OD_EN] | 0 | [A_SCAN] | 0 | [IO_OE] |
35+
// |---------|---|---|---------|---|----------|---|---------|
36+
// Default: | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
37+
// *INDENT-OFF*
38+
#define REG_WR_OC_DEFAULT_VAL (0x00UL)
39+
#define REG_WR_IO_DEFAULT_VAL (0x00UL)
40+
#define REG_OUT_DEFAULT_VAL (REG_WR_OC_DEFAULT_VAL << 8 | REG_WR_IO_DEFAULT_VAL)
41+
42+
#define REG_WR_SET_BIT_IO_OE (1 << 0)
43+
#define REG_WR_SET_BIT_OD_EN (1 << 4)
3144

3245
/**
3346
* @brief Device Structure Type
@@ -38,8 +51,9 @@ typedef struct {
3851
i2c_port_t i2c_num;
3952
uint32_t i2c_address;
4053
struct {
41-
uint8_t direction;
42-
uint8_t output;
54+
uint8_t wr_set;
55+
uint8_t wr_oc;
56+
uint8_t wr_io;
4357
} regs;
4458
} esp_io_expander_ch422g_t;
4559

@@ -62,6 +76,32 @@ void ESP_IOExpander_CH422G::begin(void)
6276
CHECK_ERROR_RETURN(esp_io_expander_new_i2c_ch422g(i2c_id, i2c_address, &handle));
6377
}
6478

79+
void ESP_IOExpander_CH422G::enableOC_OpenDrain(void)
80+
{
81+
esp_io_expander_ch422g_t *ch422g = (esp_io_expander_ch422g_t *)__containerof(handle, esp_io_expander_ch422g_t, base);
82+
83+
uint8_t data[2] = {CH422G_REG_WR_SET, (uint8_t)(ch422g->regs.wr_set | REG_WR_SET_BIT_OD_EN)};
84+
85+
// WR-SET
86+
CHECK_ERROR_RETURN(
87+
i2c_master_write_to_device(ch422g->i2c_num, ch422g->i2c_address, data, sizeof(data), pdMS_TO_TICKS(I2C_TIMEOUT_MS))
88+
);
89+
ch422g->regs.wr_set = data[1];
90+
}
91+
92+
void ESP_IOExpander_CH422G::enableOC_PushPull(void)
93+
{
94+
esp_io_expander_ch422g_t *ch422g = (esp_io_expander_ch422g_t *)__containerof(handle, esp_io_expander_ch422g_t, base);
95+
96+
uint8_t data[2] = {CH422G_REG_WR_SET, (uint8_t)(ch422g->regs.wr_set & ~REG_WR_SET_BIT_OD_EN)};
97+
98+
// WR-SET
99+
CHECK_ERROR_RETURN(
100+
i2c_master_write_to_device(ch422g->i2c_num, ch422g->i2c_address, data, sizeof(data), pdMS_TO_TICKS(I2C_TIMEOUT_MS))
101+
);
102+
ch422g->regs.wr_set = data[1];
103+
}
104+
65105
static esp_err_t read_input_reg(esp_io_expander_handle_t handle, uint32_t *value);
66106
static esp_err_t write_output_reg(esp_io_expander_handle_t handle, uint32_t value);
67107
static esp_err_t read_output_reg(esp_io_expander_handle_t handle, uint32_t *value);
@@ -82,7 +122,9 @@ static esp_err_t esp_io_expander_new_i2c_ch422g(i2c_port_t i2c_num, uint32_t i2c
82122
ch422g->base.config.flags.dir_out_bit_zero = 1;
83123
ch422g->i2c_num = i2c_num;
84124
ch422g->i2c_address = i2c_address;
85-
ch422g->regs.output = OUT_REG_DEFAULT_VAL;
125+
ch422g->regs.wr_set = REG_WR_SET_DEFAULT_VAL;
126+
ch422g->regs.wr_oc = REG_WR_OC_DEFAULT_VAL;
127+
ch422g->regs.wr_io = REG_WR_IO_DEFAULT_VAL;
86128
ch422g->base.read_input_reg = read_input_reg;
87129
ch422g->base.write_output_reg = write_output_reg;
88130
ch422g->base.read_output_reg = read_output_reg;
@@ -107,65 +149,99 @@ static esp_err_t read_input_reg(esp_io_expander_handle_t handle, uint32_t *value
107149
esp_io_expander_ch422g_t *ch422g = (esp_io_expander_ch422g_t *)__containerof(handle, esp_io_expander_ch422g_t, base);
108150

109151
uint8_t temp = 0;
152+
uint8_t reg = CH422G_REG_RD_IO;
110153

111154
ESP_RETURN_ON_ERROR(
112-
i2c_master_read_from_device(ch422g->i2c_num, ch422g->i2c_address, &temp, 1, pdMS_TO_TICKS(I2C_TIMEOUT_MS)),
113-
TAG, "Read input reg failed");
114-
115-
// *INDENT-OFF*
116-
ESP_RETURN_ON_ERROR(
117-
i2c_master_read_from_device(ch422g->i2c_num, CH422G_REG_IN, &temp, 1, pdMS_TO_TICKS(I2C_TIMEOUT_MS)),
118-
TAG, "Read input reg failed");
119-
// *INDENT-ON*
155+
i2c_master_write_read_device(ch422g->i2c_num, ch422g->i2c_address, &reg, 1, &temp, 1, pdMS_TO_TICKS(I2C_TIMEOUT_MS)),
156+
TAG, "Read RD-IO reg failed"
157+
);
120158
*value = temp;
159+
121160
return ESP_OK;
122161
}
123162

124163
static esp_err_t write_output_reg(esp_io_expander_handle_t handle, uint32_t value)
125164
{
126165
esp_io_expander_ch422g_t *ch422g = (esp_io_expander_ch422g_t *)__containerof(handle, esp_io_expander_ch422g_t, base);
127-
value &= 0xff;
128166

129-
uint8_t out_temp = 0x01;
130-
ESP_RETURN_ON_ERROR(
131-
i2c_master_write_to_device(ch422g->i2c_num, ch422g->i2c_address, &out_temp, 1, pdMS_TO_TICKS(I2C_TIMEOUT_MS)),
132-
TAG, "Write output reg failed");
167+
uint8_t wr_oc_data = (value & 0xf00) >> 8;
168+
uint8_t wr_io_data = value & 0xff;
169+
uint8_t data[2] = {};
170+
171+
// WR-OC
172+
if (wr_oc_data) {
173+
data[0] = CH422G_REG_WR_OC;
174+
data[1] = wr_oc_data;
175+
ESP_RETURN_ON_ERROR(
176+
i2c_master_write_to_device(ch422g->i2c_num, ch422g->i2c_address, data, sizeof(data), pdMS_TO_TICKS(I2C_TIMEOUT_MS)),
177+
TAG, "Write WR-OC reg failed"
178+
);
179+
ch422g->regs.wr_oc = wr_oc_data;
180+
}
181+
182+
// WR-IO
183+
if (wr_io_data) {
184+
data[0] = CH422G_REG_WR_IO;
185+
data[1] = wr_io_data;
186+
ESP_RETURN_ON_ERROR(
187+
i2c_master_write_to_device(ch422g->i2c_num, ch422g->i2c_address, data, sizeof(data), pdMS_TO_TICKS(I2C_TIMEOUT_MS)),
188+
TAG, "Write WR-IO reg failed"
189+
);
190+
ch422g->regs.wr_io = wr_io_data;
191+
}
133192

134-
uint8_t data = (uint8_t)value;
135-
ESP_RETURN_ON_ERROR(
136-
i2c_master_write_to_device(ch422g->i2c_num, CH422G_REG_OUT, &data, 1, pdMS_TO_TICKS(I2C_TIMEOUT_MS)),
137-
TAG, "Write output reg failed");
138-
ch422g->regs.output = value;
139193
return ESP_OK;
140194
}
141195

142196
static esp_err_t read_output_reg(esp_io_expander_handle_t handle, uint32_t *value)
143197
{
144198
esp_io_expander_ch422g_t *ch422g = (esp_io_expander_ch422g_t *)__containerof(handle, esp_io_expander_ch422g_t, base);
145199

146-
*value = ch422g->regs.output;
200+
*value = ch422g->regs.wr_io | (((uint32_t)ch422g->regs.wr_oc) << 8);
201+
147202
return ESP_OK;
148203
}
149204

150205
static esp_err_t write_direction_reg(esp_io_expander_handle_t handle, uint32_t value)
151206
{
152207
esp_io_expander_ch422g_t *ch422g = (esp_io_expander_ch422g_t *)__containerof(handle, esp_io_expander_ch422g_t, base);
153208
value &= 0xff;
154-
ch422g->regs.direction = value;
209+
210+
uint8_t data[2] = {CH422G_REG_WR_SET, ch422g->regs.wr_set};
211+
212+
if (value > 0) {
213+
data[1] |= REG_WR_SET_BIT_IO_OE;
214+
} else {
215+
data[1] &= ~REG_WR_SET_BIT_IO_OE;
216+
}
217+
218+
// WR-SET
219+
ESP_RETURN_ON_ERROR(
220+
i2c_master_write_to_device(ch422g->i2c_num, ch422g->i2c_address, data, sizeof(data), pdMS_TO_TICKS(I2C_TIMEOUT_MS)),
221+
TAG, "Write WR_SET reg failed"
222+
);
223+
ch422g->regs.wr_set = data[1];
224+
155225
return ESP_OK;
156226
}
157227

228+
#define DIR_OUT_VALUE (0xFFF)
229+
#define DIR_IN_VALUE (0xF00)
230+
158231
static esp_err_t read_direction_reg(esp_io_expander_handle_t handle, uint32_t *value)
159232
{
160233
esp_io_expander_ch422g_t *ch422g = (esp_io_expander_ch422g_t *)__containerof(handle, esp_io_expander_ch422g_t, base);
161234

162-
*value = ch422g->regs.direction;
235+
*value = (ch422g->regs.wr_set & REG_WR_SET_BIT_IO_OE) ? DIR_OUT_VALUE : DIR_IN_VALUE;
236+
163237
return ESP_OK;
164238
}
165239

166240
static esp_err_t reset(esp_io_expander_t *handle)
167241
{
168-
ESP_RETURN_ON_ERROR(write_output_reg(handle, OUT_REG_DEFAULT_VAL), TAG, "Write output reg failed");
242+
ESP_RETURN_ON_ERROR(write_direction_reg(handle, REG_WR_SET_DEFAULT_VAL), TAG, "Write direction reg (WR_SET) failed");
243+
ESP_RETURN_ON_ERROR(write_output_reg(handle, REG_OUT_DEFAULT_VAL), TAG, "Write output reg (WR_OC & WR_IO) failed");
244+
169245
return ESP_OK;
170246
}
171247

@@ -174,5 +250,6 @@ static esp_err_t del(esp_io_expander_t *handle)
174250
esp_io_expander_ch422g_t *ch422g = (esp_io_expander_ch422g_t *)__containerof(handle, esp_io_expander_ch422g_t, base);
175251

176252
free(ch422g);
253+
177254
return ESP_OK;
178255
}

src/chip/CH422G.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,18 @@ class ESP_IOExpander_CH422G: public ESP_IOExpander {
6363
*
6464
*/
6565
void begin(void) override;
66+
67+
/**
68+
* @brief Enable OC0-OC3 output open-drain
69+
*
70+
*/
71+
void enableOC_OpenDrain(void);
72+
73+
/**
74+
* @brief Enable OC0-OC3 output push-pull (default mode when power-on)
75+
*
76+
*/
77+
void enableOC_PushPull(void);
6678
};
6779

6880
/**

test_apps/main/test_ESP_IOExpander.cpp

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
2+
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
@@ -16,27 +16,25 @@
1616

1717
#include "ESP_IOExpander_Library.h"
1818

19-
// Refer to `esp32-hal-gpio.h`
20-
#define INPUT 0x01
21-
#define OUTPUT 0x03
22-
#define LOW 0x0
23-
#define HIGH 0x1
24-
2519
static const char *TAG = "ESP_IOxpander_test";
2620

21+
#define CHIP_NAME TCA95xx_8bit
2722
#define I2C_HOST (I2C_NUM_0)
2823
#define I2C_SDA_PIN (8)
2924
#define I2C_SCL_PIN (18)
3025

31-
TEST_CASE("test ESP IO expander for TCA9554", "[tca9554]")
26+
#define _EXAMPLE_CHIP_CLASS(name, ...) ESP_IOExpander_##name(__VA_ARGS__)
27+
#define EXAMPLE_CHIP_CLASS(name, ...) _EXAMPLE_CHIP_CLASS(name, ##__VA_ARGS__)
28+
29+
TEST_CASE("test ESP IO expander functions", "[io_expander]")
3230
{
3331
ESP_IOExpander *expander = NULL;
3432
const i2c_config_t i2c_config = EXPANDER_I2C_CONFIG_DEFAULT(I2C_SCL_PIN, I2C_SDA_PIN);
3533

3634
ESP_LOGI(TAG, "Test initialization with external I2C");
3735
TEST_ASSERT_EQUAL(i2c_param_config(I2C_HOST, &i2c_config), ESP_OK);
3836
TEST_ASSERT_EQUAL(i2c_driver_install(I2C_HOST, i2c_config.mode, 0, 0, 0), ESP_OK);
39-
expander = new ESP_IOExpander_TCA95xx_8bit(I2C_HOST, ESP_IO_EXPANDER_I2C_TCA9554_ADDRESS_000);
37+
expander = new EXAMPLE_CHIP_CLASS(CHIP_NAME, I2C_HOST, ESP_IO_EXPANDER_I2C_TCA9554_ADDRESS_000);
4038
expander->init();
4139
expander->begin();
4240
expander->reset();
@@ -45,15 +43,15 @@ TEST_CASE("test ESP IO expander for TCA9554", "[tca9554]")
4543
i2c_driver_delete(I2C_HOST);
4644

4745
ESP_LOGI(TAG, "Test initialization with internal I2C (with config)");
48-
expander = new ESP_IOExpander_TCA95xx_8bit(I2C_HOST, ESP_IO_EXPANDER_I2C_TCA9554_ADDRESS_000, &i2c_config);
46+
expander = new EXAMPLE_CHIP_CLASS(CHIP_NAME, I2C_HOST, ESP_IO_EXPANDER_I2C_TCA9554_ADDRESS_000, &i2c_config);
4947
expander->init();
5048
expander->begin();
5149
expander->reset();
5250
expander->del();
5351
delete expander;
5452

5553
ESP_LOGI(TAG, "Test initialization with internal I2C (without config)");
56-
expander = new ESP_IOExpander_TCA95xx_8bit(I2C_HOST, ESP_IO_EXPANDER_I2C_TCA9554_ADDRESS_000, I2C_SCL_PIN, I2C_SDA_PIN);
54+
expander = new EXAMPLE_CHIP_CLASS(CHIP_NAME, I2C_HOST, ESP_IO_EXPANDER_I2C_TCA9554_ADDRESS_000, I2C_SCL_PIN, I2C_SDA_PIN);
5755
expander->init();
5856
expander->begin();
5957
expander->reset();

0 commit comments

Comments
 (0)