Skip to content

Commit 5ba1a03

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

File tree

6 files changed

+160
-71
lines changed

6 files changed

+160
-71
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: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
#define EXAMPLE_I2C_NUM (0)
1313
#define EXAMPLE_I2C_SDA_PIN (8)
1414
#define EXAMPLE_I2C_SCL_PIN (18)
15+
#define EXAMPLE_I2C_ADDR (ESP_IO_EXPANDER_I2C_TCA9554_ADDRESS_000) // Modify this value according to the
16+
// hardware address
1517

1618
#define _EXAMPLE_CHIP_CLASS(name, ...) ESP_IOExpander_##name(__VA_ARGS__)
1719
#define EXAMPLE_CHIP_CLASS(name, ...) _EXAMPLE_CHIP_CLASS(name, ##__VA_ARGS__)
@@ -23,12 +25,15 @@ void setup()
2325
Serial.begin(115200);
2426
Serial.println("Test begin");
2527

26-
expander = new EXAMPLE_CHIP_CLASS(EXAMPLE_CHIP_NAME,
27-
(i2c_port_t)EXAMPLE_I2C_NUM, ESP_IO_EXPANDER_I2C_TCA9554_ADDRESS_000,
28-
EXAMPLE_I2C_SCL_PIN, EXAMPLE_I2C_SDA_PIN);
28+
expander = new EXAMPLE_CHIP_CLASS(EXAMPLE_CHIP_NAME, (i2c_port_t)EXAMPLE_I2C_NUM, EXAMPLE_I2C_ADDR,
29+
EXAMPLE_I2C_SCL_PIN, EXAMPLE_I2C_SDA_PIN);
2930
expander->init();
3031
expander->begin();
3132

33+
/* For CH422G */
34+
// static_cast<ESP_IOExpander_CH422G *>(expander)->enableOC_PushPull();
35+
// static_cast<ESP_IOExpander_CH422G *>(expander)->enableOC_OpenDrain();
36+
3237
Serial.println("Original status:");
3338
expander->printStatus();
3439

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: 108 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,29 @@
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)
27-
28-
/* Default register value on power-up */
29-
#define DIR_REG_DEFAULT_VAL (0xff)
30-
#define OUT_REG_DEFAULT_VAL (0xdf)
25+
#define CH422G_REG_WR_SET (0x48 >> 1)
26+
#define CH422G_REG_WR_OC (0x46 >> 1)
27+
#define CH422G_REG_WR_IO (0x70 >> 1)
28+
#define CH422G_REG_RD_IO (0x4D >> 1)
29+
30+
/* Default register value when reset */
31+
// *INDENT-OFF*
32+
#define REG_WR_SET_DEFAULT_VAL (0x01UL) // 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 | 1 |
37+
// *INDENT-OFF*
38+
#define REG_WR_OC_DEFAULT_VAL (0x0FUL)
39+
#define REG_WR_IO_DEFAULT_VAL (0xFFUL)
40+
#define REG_OUT_DEFAULT_VAL ((REG_WR_OC_DEFAULT_VAL << 8) | REG_WR_IO_DEFAULT_VAL)
41+
#define REG_DIR_DEFAULT_VAL (0xFFUL)
42+
43+
#define REG_WR_SET_BIT_IO_OE (1 << 0)
44+
#define REG_WR_SET_BIT_OD_EN (1 << 4)
3145

3246
/**
3347
* @brief Device Structure Type
@@ -38,14 +52,22 @@ typedef struct {
3852
i2c_port_t i2c_num;
3953
uint32_t i2c_address;
4054
struct {
41-
uint8_t direction;
42-
uint8_t output;
55+
uint8_t wr_set;
56+
uint8_t wr_oc;
57+
uint8_t wr_io;
4358
} regs;
4459
} esp_io_expander_ch422g_t;
4560

4661
static const char *TAG = "ch422g";
4762

4863
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);
64+
static esp_err_t read_input_reg(esp_io_expander_handle_t handle, uint32_t *value);
65+
static esp_err_t write_output_reg(esp_io_expander_handle_t handle, uint32_t value);
66+
static esp_err_t read_output_reg(esp_io_expander_handle_t handle, uint32_t *value);
67+
static esp_err_t write_direction_reg(esp_io_expander_handle_t handle, uint32_t value);
68+
static esp_err_t read_direction_reg(esp_io_expander_handle_t handle, uint32_t *value);
69+
static esp_err_t reset(esp_io_expander_t *handle);
70+
static esp_err_t del(esp_io_expander_t *handle);
4971

5072
ESP_IOExpander_CH422G::~ESP_IOExpander_CH422G()
5173
{
@@ -62,13 +84,29 @@ void ESP_IOExpander_CH422G::begin(void)
6284
CHECK_ERROR_RETURN(esp_io_expander_new_i2c_ch422g(i2c_id, i2c_address, &handle));
6385
}
6486

65-
static esp_err_t read_input_reg(esp_io_expander_handle_t handle, uint32_t *value);
66-
static esp_err_t write_output_reg(esp_io_expander_handle_t handle, uint32_t value);
67-
static esp_err_t read_output_reg(esp_io_expander_handle_t handle, uint32_t *value);
68-
static esp_err_t write_direction_reg(esp_io_expander_handle_t handle, uint32_t value);
69-
static esp_err_t read_direction_reg(esp_io_expander_handle_t handle, uint32_t *value);
70-
static esp_err_t reset(esp_io_expander_t *handle);
71-
static esp_err_t del(esp_io_expander_t *handle);
87+
void ESP_IOExpander_CH422G::enableOC_OpenDrain(void)
88+
{
89+
esp_io_expander_ch422g_t *ch422g = (esp_io_expander_ch422g_t *)__containerof(handle, esp_io_expander_ch422g_t, base);
90+
uint8_t data = (uint8_t)(ch422g->regs.wr_set | REG_WR_SET_BIT_OD_EN);
91+
92+
// WR-SET
93+
CHECK_ERROR_RETURN(
94+
i2c_master_write_to_device(ch422g->i2c_num, CH422G_REG_WR_SET, &data, sizeof(data), pdMS_TO_TICKS(I2C_TIMEOUT_MS))
95+
);
96+
ch422g->regs.wr_set = data;
97+
}
98+
99+
void ESP_IOExpander_CH422G::enableOC_PushPull(void)
100+
{
101+
esp_io_expander_ch422g_t *ch422g = (esp_io_expander_ch422g_t *)__containerof(handle, esp_io_expander_ch422g_t, base);
102+
uint8_t data = (uint8_t)(ch422g->regs.wr_set & ~REG_WR_SET_BIT_OD_EN);
103+
104+
// WR-SET
105+
CHECK_ERROR_RETURN(
106+
i2c_master_write_to_device(ch422g->i2c_num, CH422G_REG_WR_SET, &data, sizeof(data), pdMS_TO_TICKS(I2C_TIMEOUT_MS))
107+
);
108+
ch422g->regs.wr_set = data;
109+
}
72110

73111
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)
74112
{
@@ -82,7 +120,9 @@ static esp_err_t esp_io_expander_new_i2c_ch422g(i2c_port_t i2c_num, uint32_t i2c
82120
ch422g->base.config.flags.dir_out_bit_zero = 1;
83121
ch422g->i2c_num = i2c_num;
84122
ch422g->i2c_address = i2c_address;
85-
ch422g->regs.output = OUT_REG_DEFAULT_VAL;
123+
ch422g->regs.wr_set = REG_WR_SET_DEFAULT_VAL;
124+
ch422g->regs.wr_oc = REG_WR_OC_DEFAULT_VAL;
125+
ch422g->regs.wr_io = REG_WR_IO_DEFAULT_VAL;
86126
ch422g->base.read_input_reg = read_input_reg;
87127
ch422g->base.write_output_reg = write_output_reg;
88128
ch422g->base.read_output_reg = read_output_reg;
@@ -105,67 +145,93 @@ static esp_err_t esp_io_expander_new_i2c_ch422g(i2c_port_t i2c_num, uint32_t i2c
105145
static esp_err_t read_input_reg(esp_io_expander_handle_t handle, uint32_t *value)
106146
{
107147
esp_io_expander_ch422g_t *ch422g = (esp_io_expander_ch422g_t *)__containerof(handle, esp_io_expander_ch422g_t, base);
108-
109148
uint8_t temp = 0;
110149

111150
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*
151+
i2c_master_read_from_device(ch422g->i2c_num, CH422G_REG_RD_IO, &temp, 1, pdMS_TO_TICKS(I2C_TIMEOUT_MS)),
152+
TAG, "Read RD-IO reg failed"
153+
);
120154
*value = temp;
155+
121156
return ESP_OK;
122157
}
123158

124159
static esp_err_t write_output_reg(esp_io_expander_handle_t handle, uint32_t value)
125160
{
126161
esp_io_expander_ch422g_t *ch422g = (esp_io_expander_ch422g_t *)__containerof(handle, esp_io_expander_ch422g_t, base);
127-
value &= 0xff;
128162

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");
163+
uint8_t wr_oc_data = (value & 0xF00) >> 8;
164+
uint8_t wr_io_data = value & 0xFF;
165+
166+
// WR-OC
167+
if (wr_oc_data) {
168+
ESP_RETURN_ON_ERROR(
169+
i2c_master_write_to_device(ch422g->i2c_num, CH422G_REG_WR_OC, &wr_oc_data, sizeof(wr_oc_data), pdMS_TO_TICKS(I2C_TIMEOUT_MS)),
170+
TAG, "Write WR-OC reg failed"
171+
);
172+
ch422g->regs.wr_oc = wr_oc_data;
173+
}
174+
175+
// WR-IO
176+
if (wr_io_data) {
177+
ESP_RETURN_ON_ERROR(
178+
i2c_master_write_to_device(ch422g->i2c_num, CH422G_REG_WR_IO, &wr_io_data, sizeof(wr_io_data), pdMS_TO_TICKS(I2C_TIMEOUT_MS)),
179+
TAG, "Write WR-IO reg failed"
180+
);
181+
ch422g->regs.wr_io = wr_io_data;
182+
}
133183

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;
139184
return ESP_OK;
140185
}
141186

142187
static esp_err_t read_output_reg(esp_io_expander_handle_t handle, uint32_t *value)
143188
{
144189
esp_io_expander_ch422g_t *ch422g = (esp_io_expander_ch422g_t *)__containerof(handle, esp_io_expander_ch422g_t, base);
145190

146-
*value = ch422g->regs.output;
191+
*value = ch422g->regs.wr_io | (((uint32_t)ch422g->regs.wr_oc) << 8);
192+
147193
return ESP_OK;
148194
}
149195

150196
static esp_err_t write_direction_reg(esp_io_expander_handle_t handle, uint32_t value)
151197
{
152198
esp_io_expander_ch422g_t *ch422g = (esp_io_expander_ch422g_t *)__containerof(handle, esp_io_expander_ch422g_t, base);
153-
value &= 0xff;
154-
ch422g->regs.direction = value;
199+
uint8_t data = ch422g->regs.wr_set;
200+
201+
value &= 0xFF;
202+
if (value > 0) {
203+
data |= REG_WR_SET_BIT_IO_OE;
204+
} else {
205+
data &= ~REG_WR_SET_BIT_IO_OE;
206+
}
207+
208+
// WR-SET
209+
ESP_RETURN_ON_ERROR(
210+
i2c_master_write_to_device(ch422g->i2c_num, CH422G_REG_WR_SET, &data, sizeof(data), pdMS_TO_TICKS(I2C_TIMEOUT_MS)),
211+
TAG, "Write WR_SET reg failed"
212+
);
213+
ch422g->regs.wr_set = data;
214+
155215
return ESP_OK;
156216
}
157217

218+
#define DIR_OUT_VALUE (0xFFF)
219+
#define DIR_IN_VALUE (0xF00)
220+
158221
static esp_err_t read_direction_reg(esp_io_expander_handle_t handle, uint32_t *value)
159222
{
160223
esp_io_expander_ch422g_t *ch422g = (esp_io_expander_ch422g_t *)__containerof(handle, esp_io_expander_ch422g_t, base);
161224

162-
*value = ch422g->regs.direction;
225+
*value = (ch422g->regs.wr_set & REG_WR_SET_BIT_IO_OE) ? DIR_OUT_VALUE : DIR_IN_VALUE;
226+
163227
return ESP_OK;
164228
}
165229

166230
static esp_err_t reset(esp_io_expander_t *handle)
167231
{
168-
ESP_RETURN_ON_ERROR(write_output_reg(handle, OUT_REG_DEFAULT_VAL), TAG, "Write output reg failed");
232+
ESP_RETURN_ON_ERROR(write_direction_reg(handle, REG_DIR_DEFAULT_VAL), TAG, "Write direction reg (WR_SET) failed");
233+
ESP_RETURN_ON_ERROR(write_output_reg(handle, REG_OUT_DEFAULT_VAL), TAG, "Write output reg (WR_OC & WR_IO) failed");
234+
169235
return ESP_OK;
170236
}
171237

@@ -174,5 +240,6 @@ static esp_err_t del(esp_io_expander_t *handle)
174240
esp_io_expander_ch422g_t *ch422g = (esp_io_expander_ch422g_t *)__containerof(handle, esp_io_expander_ch422g_t, base);
175241

176242
free(ch422g);
243+
177244
return ESP_OK;
178245
}

src/chip/CH422G.h

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,13 @@
1313

1414
#include "../ESP_IOExpander.h"
1515

16+
/**
17+
* Pin mapping:
18+
*
19+
* | Pin Number | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
20+
* | ------------ | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
21+
* | Function | IO0 | IO1 | IO2 | IO3 | IO4 | IO5 | IO6 | IO7 | OC0 | OC1 | OC2 | OC3 |
22+
*/
1623
class ESP_IOExpander_CH422G: public ESP_IOExpander {
1724
public:
1825
/**
@@ -21,35 +28,32 @@ class ESP_IOExpander_CH422G: public ESP_IOExpander {
2128
* @note After using this function, call `init()` will initialize I2C bus.
2229
*
2330
* @param id I2C port number
24-
* @param address I2C device address. Should be like `ESP_IO_EXPANDER_I2C_*`.
25-
* Can be found in the header file of each IO expander.h.
31+
* @param address I2C device address. Just to keep the same with other IO expanders, but it is ignored.
2632
* @param config Pointer to I2C bus configuration
2733
*/
28-
ESP_IOExpander_CH422G(i2c_port_t id, uint8_t address, const i2c_config_t *config): ESP_IOExpander(id, address, config) { };
34+
ESP_IOExpander_CH422G(i2c_port_t id, uint8_t address, const i2c_config_t *config): ESP_IOExpander(id, 0xFF, config) { };
2935

3036
/**
3137
* @brief Constructor to create ESP_IOExpander object
3238
*
3339
* @note After using this function, call `init()` will initialize I2C bus.
3440
*
3541
* @param id I2C port number
36-
* @param address I2C device address. Should be like `ESP_IO_EXPANDER_I2C_*`.
37-
* Can be found in the header file of each IO expander.h.
42+
* @param address I2C device address. Just to keep the same with other IO expanders, but it is ignored.
3843
* @param scl SCL pin number
3944
* @param sda SDA pin number
4045
*/
41-
ESP_IOExpander_CH422G(i2c_port_t id, uint8_t address, int scl, int sda): ESP_IOExpander(id, address, scl, sda) { };
46+
ESP_IOExpander_CH422G(i2c_port_t id, uint8_t address, int scl, int sda): ESP_IOExpander(id, 0xFF, scl, sda) { };
4247

4348
/**
4449
* @brief Constructor to create ESP_IOExpander object
4550
*
4651
* @note If use this function, should initialize I2C bus before call `init()`.
4752
*
4853
* @param id I2C port number
49-
* @param address I2C device address. Should be like `ESP_IO_EXPANDER_I2C_*`.
50-
* Can be found in the header file of each IO expander.h.
54+
* @param address I2C device address. Just to keep the same with other IO expanders, but it is ignored.
5155
*/
52-
ESP_IOExpander_CH422G(i2c_port_t id, uint8_t address): ESP_IOExpander(id, address) { };
56+
ESP_IOExpander_CH422G(i2c_port_t id, uint8_t address): ESP_IOExpander(id, 0xFF) { };
5357

5458
/**
5559
* @brief Destructor
@@ -63,13 +67,22 @@ class ESP_IOExpander_CH422G: public ESP_IOExpander {
6367
*
6468
*/
6569
void begin(void) override;
70+
71+
/**
72+
* @brief Enable OC0-OC3 output open-drain
73+
*
74+
*/
75+
void enableOC_OpenDrain(void);
76+
77+
/**
78+
* @brief Enable OC0-OC3 output push-pull (default mode when power-on)
79+
*
80+
*/
81+
void enableOC_PushPull(void);
6682
};
6783

6884
/**
69-
* @brief I2C address of the ch422g
85+
* @brief I2C address of the ch422g. Just to keep the same with other IO expanders, but it is ignored.
7086
*
71-
* And the 7-bit slave address is the most important data for users.
72-
* For example, if a chip's A0,A1,A2 are connected to GND, it's 7-bit slave address is 1001000b(0x48).
73-
* Then users can use `ESP_IO_EXPANDER_I2C_CH422G_ADDRESS_000` to init it.
7487
*/
75-
#define ESP_IO_EXPANDER_I2C_CH422G_ADDRESS_000 (0x24)
88+
#define ESP_IO_EXPANDER_I2C_CH422G_ADDRESS (0x24)

0 commit comments

Comments
 (0)