Skip to content

Commit a426a76

Browse files
committed
Add examples for CH422G
1 parent 5a9d8b4 commit a426a76

File tree

5 files changed

+301
-70
lines changed

5 files changed

+301
-70
lines changed

examples/TestCH422G/TestCH422G.ino

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
/**
2+
* | Supported IO Expanders | CH422G |
3+
* | ------------------------- | ------ |
4+
*
5+
* # CH422G Test Example
6+
*
7+
* The hardware device used in this example is waveshare ESP32-S3-Touch-LCD-4.3B-BOX. To test the simultaneous use of I/O input and OC output, connect DO0 to DI0, and connect DO1 to DI1.
8+
*
9+
* ## How to use
10+
*
11+
* 1. Enable USB CDC.
12+
* 2. Verify and upload the example to your board.
13+
*
14+
* ## Serial Output
15+
*
16+
* ```
17+
* ...
18+
* Test begin
19+
* Set the OC pin to push-pull output mode.
20+
* Set the IO0-7 pin to input mode.
21+
* Set pint 8 and 9 to:0, 1
22+
*
23+
* Read pin 0 and 5 level: 0, 1
24+
*
25+
* Set pint 8 and 9 to:1, 0
26+
*
27+
* Read pin 0 and 5 level: 1, 0
28+
* ...
29+
* ```
30+
*
31+
* ## Troubleshooting
32+
*
33+
* The driver initialization by default sets CH422G's IO0-7 to output high-level mode.
34+
Since the input/output mode of CH422G's IO0-7 must remain consistent, the driver will only set IO0-7 to
35+
input mode when it determines that all pins are configured as input.
36+
Using pinMode and multiPinMode will be invalid. You can only set the pin working mode through enableAllIO_Input, enableAllIO_Output, enableOC_PushPull and enableOC_OpenDrain
37+
*
38+
*/
39+
40+
#include <Arduino.h>
41+
#include <ESP_IOExpander_Library.h>
42+
43+
#define EXAMPLE_I2C_NUM (0)
44+
#define EXAMPLE_I2C_SDA_PIN (8)
45+
#define EXAMPLE_I2C_SCL_PIN (9)
46+
#define EXAMPLE_I2C_ADDR (ESP_IO_EXPANDER_I2C_CH422G_ADDRESS) // Modify this value according to the \
47+
// hardware address
48+
49+
ESP_IOExpander_CH422G *expander = NULL;
50+
51+
void setup() {
52+
Serial.begin(115200);
53+
delay(1000);
54+
Serial.println("Test begin");
55+
56+
expander = new ESP_IOExpander_CH422G((i2c_port_t)EXAMPLE_I2C_NUM, EXAMPLE_I2C_ADDR,
57+
EXAMPLE_I2C_SCL_PIN, EXAMPLE_I2C_SDA_PIN);
58+
expander->init();
59+
expander->begin();
60+
61+
/* For CH422G */
62+
Serial.println("Set the OC pin to push-pull output mode.");
63+
static_cast<ESP_IOExpander_CH422G *>(expander)->enableOC_PushPull();
64+
65+
// Serial.println("Set the OC pin to open_drain output mode.");
66+
// static_cast<ESP_IOExpander_CH422G *>(expander)->enableOC_OpenDrain();
67+
68+
Serial.println("Set the IO0-7 pin to input mode.");
69+
static_cast<ESP_IOExpander_CH422G *>(expander)->enableAllIO_Input();
70+
71+
// Serial.println("Set the IO0-7 pin to output mode.");
72+
//static_cast<ESP_IOExpander_CH422G *>(expander)->enableAllIO_Output();
73+
}
74+
75+
int level[2] = { 0, 0 };
76+
77+
void loop() {
78+
for (int i = 0; i < 100; i++) {
79+
bool toggle = i % 2;
80+
81+
Serial.print("Set pint 8 and 9 to:");
82+
Serial.print(toggle);
83+
Serial.print(", ");
84+
Serial.println(!toggle);
85+
Serial.println();
86+
87+
// Set pin 8 and 9 level
88+
expander->digitalWrite(8, toggle);
89+
expander->digitalWrite(9, !toggle);
90+
delay(1);
91+
92+
// Read pin 0 and 5 level
93+
level[0] = expander->digitalRead(0);
94+
level[1] = expander->digitalRead(5);
95+
96+
Serial.print("Read pin 0 and 5 level: ");
97+
Serial.print(level[0]);
98+
Serial.print(", ");
99+
Serial.println(level[1]);
100+
Serial.println();
101+
102+
delay(1000);
103+
}
104+
}

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

src/chip/CH422G.cpp

Lines changed: 135 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,30 @@
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] | [OD_EN] | [A_SCAN] | [IO_OE] |
35+
// | --- | --- | --- | --- | ------- | ------- | -------- | ------- |
36+
// Default: | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
37+
38+
// *INDENT-OFF*
39+
#define REG_WR_OC_DEFAULT_VAL (0x0FUL)
40+
#define REG_WR_IO_DEFAULT_VAL (0xFFUL)
41+
#define REG_OUT_DEFAULT_VAL ((REG_WR_OC_DEFAULT_VAL << 8) | REG_WR_IO_DEFAULT_VAL)
42+
#define REG_DIR_DEFAULT_VAL (0xFFFUL)
43+
44+
#define REG_WR_SET_BIT_IO_OE (1 << 0)
45+
#define REG_WR_SET_BIT_OD_EN (1 << 2)
3146

3247
/**
3348
* @brief Device Structure Type
@@ -38,14 +53,22 @@ typedef struct {
3853
i2c_port_t i2c_num;
3954
uint32_t i2c_address;
4055
struct {
41-
uint8_t direction;
42-
uint8_t output;
56+
uint8_t wr_set;
57+
uint8_t wr_oc;
58+
uint8_t wr_io;
4359
} regs;
4460
} esp_io_expander_ch422g_t;
4561

4662
static const char *TAG = "ch422g";
4763

4864
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);
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);
4972

5073
ESP_IOExpander_CH422G::~ESP_IOExpander_CH422G()
5174
{
@@ -62,13 +85,55 @@ void ESP_IOExpander_CH422G::begin(void)
6285
CHECK_ERROR_RETURN(esp_io_expander_new_i2c_ch422g(i2c_id, i2c_address, &handle));
6386
}
6487

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);
88+
void ESP_IOExpander_CH422G::enableOC_OpenDrain(void)
89+
{
90+
esp_io_expander_ch422g_t *ch422g = (esp_io_expander_ch422g_t *)__containerof(handle, esp_io_expander_ch422g_t, base);
91+
uint8_t data = (uint8_t)(ch422g->regs.wr_set | REG_WR_SET_BIT_OD_EN);
92+
93+
// WR-SET
94+
CHECK_ERROR_RETURN(
95+
i2c_master_write_to_device(ch422g->i2c_num, CH422G_REG_WR_SET, &data, sizeof(data), pdMS_TO_TICKS(I2C_TIMEOUT_MS))
96+
);
97+
ch422g->regs.wr_set = data;
98+
}
99+
100+
void ESP_IOExpander_CH422G::enableOC_PushPull(void)
101+
{
102+
esp_io_expander_ch422g_t *ch422g = (esp_io_expander_ch422g_t *)__containerof(handle, esp_io_expander_ch422g_t, base);
103+
uint8_t data = (uint8_t)(ch422g->regs.wr_set & ~REG_WR_SET_BIT_OD_EN);
104+
105+
// WR-SET
106+
CHECK_ERROR_RETURN(
107+
i2c_master_write_to_device(ch422g->i2c_num, CH422G_REG_WR_SET, &data, sizeof(data), pdMS_TO_TICKS(I2C_TIMEOUT_MS))
108+
);
109+
ch422g->regs.wr_set = data;
110+
}
111+
112+
void ESP_IOExpander_CH422G::enableAllIO_Input(void)
113+
{
114+
esp_io_expander_ch422g_t *ch422g = (esp_io_expander_ch422g_t *)__containerof(handle, esp_io_expander_ch422g_t, base);
115+
uint8_t data = (uint8_t)(ch422g->regs.wr_set & ~REG_WR_SET_BIT_IO_OE);
116+
117+
// WR-SET
118+
CHECK_ERROR_RETURN(
119+
i2c_master_write_to_device(ch422g->i2c_num, CH422G_REG_WR_SET, &data, sizeof(data), pdMS_TO_TICKS(I2C_TIMEOUT_MS))
120+
);
121+
ch422g->regs.wr_set = data;
122+
// Delay 1ms to wait for the IO expander to switch to input mode
123+
vTaskDelay(pdMS_TO_TICKS(2));
124+
}
125+
126+
void ESP_IOExpander_CH422G::enableAllIO_Output(void)
127+
{
128+
esp_io_expander_ch422g_t *ch422g = (esp_io_expander_ch422g_t *)__containerof(handle, esp_io_expander_ch422g_t, base);
129+
uint8_t data = (uint8_t)(ch422g->regs.wr_set | REG_WR_SET_BIT_IO_OE);
130+
131+
// WR-SET
132+
CHECK_ERROR_RETURN(
133+
i2c_master_write_to_device(ch422g->i2c_num, CH422G_REG_WR_SET, &data, sizeof(data), pdMS_TO_TICKS(I2C_TIMEOUT_MS))
134+
);
135+
ch422g->regs.wr_set = data;
136+
}
72137

73138
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)
74139
{
@@ -79,10 +144,11 @@ static esp_err_t esp_io_expander_new_i2c_ch422g(i2c_port_t i2c_num, uint32_t i2c
79144
ESP_RETURN_ON_FALSE(ch422g, ESP_ERR_NO_MEM, TAG, "Malloc failed");
80145

81146
ch422g->base.config.io_count = IO_COUNT;
82-
ch422g->base.config.flags.dir_out_bit_zero = 1;
83147
ch422g->i2c_num = i2c_num;
84148
ch422g->i2c_address = i2c_address;
85-
ch422g->regs.output = OUT_REG_DEFAULT_VAL;
149+
ch422g->regs.wr_set = REG_WR_SET_DEFAULT_VAL;
150+
ch422g->regs.wr_oc = REG_WR_OC_DEFAULT_VAL;
151+
ch422g->regs.wr_io = REG_WR_IO_DEFAULT_VAL;
86152
ch422g->base.read_input_reg = read_input_reg;
87153
ch422g->base.write_output_reg = write_output_reg;
88154
ch422g->base.read_output_reg = read_output_reg;
@@ -105,67 +171,93 @@ static esp_err_t esp_io_expander_new_i2c_ch422g(i2c_port_t i2c_num, uint32_t i2c
105171
static esp_err_t read_input_reg(esp_io_expander_handle_t handle, uint32_t *value)
106172
{
107173
esp_io_expander_ch422g_t *ch422g = (esp_io_expander_ch422g_t *)__containerof(handle, esp_io_expander_ch422g_t, base);
108-
109174
uint8_t temp = 0;
110175

111176
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*
177+
i2c_master_read_from_device(ch422g->i2c_num, CH422G_REG_RD_IO, &temp, 1, pdMS_TO_TICKS(I2C_TIMEOUT_MS)),
178+
TAG, "Read RD-IO reg failed"
179+
);
120180
*value = temp;
181+
121182
return ESP_OK;
122183
}
123184

124185
static esp_err_t write_output_reg(esp_io_expander_handle_t handle, uint32_t value)
125186
{
126187
esp_io_expander_ch422g_t *ch422g = (esp_io_expander_ch422g_t *)__containerof(handle, esp_io_expander_ch422g_t, base);
127-
value &= 0xff;
128188

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");
189+
uint8_t wr_oc_data = (value & 0xF00) >> 8;
190+
uint8_t wr_io_data = value & 0xFF;
191+
192+
// WR-OC
193+
if (wr_oc_data) {
194+
ESP_RETURN_ON_ERROR(
195+
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)),
196+
TAG, "Write WR-OC reg failed"
197+
);
198+
ch422g->regs.wr_oc = wr_oc_data;
199+
}
200+
201+
// WR-IO
202+
if (wr_io_data) {
203+
ESP_RETURN_ON_ERROR(
204+
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)),
205+
TAG, "Write WR-IO reg failed"
206+
);
207+
ch422g->regs.wr_io = wr_io_data;
208+
}
133209

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;
139210
return ESP_OK;
140211
}
141212

142213
static esp_err_t read_output_reg(esp_io_expander_handle_t handle, uint32_t *value)
143214
{
144215
esp_io_expander_ch422g_t *ch422g = (esp_io_expander_ch422g_t *)__containerof(handle, esp_io_expander_ch422g_t, base);
145216

146-
*value = ch422g->regs.output;
217+
*value = ch422g->regs.wr_io | (((uint32_t)ch422g->regs.wr_oc) << 8);
218+
147219
return ESP_OK;
148220
}
149221

150222
static esp_err_t write_direction_reg(esp_io_expander_handle_t handle, uint32_t value)
151223
{
152224
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;
225+
uint8_t data = ch422g->regs.wr_set;
226+
227+
value &= 0xFF;
228+
if (value != 0) {
229+
data |= REG_WR_SET_BIT_IO_OE;
230+
} else {
231+
data &= ~REG_WR_SET_BIT_IO_OE;
232+
}
233+
234+
// WR-SET
235+
ESP_RETURN_ON_ERROR(
236+
i2c_master_write_to_device(ch422g->i2c_num, CH422G_REG_WR_SET, &data, sizeof(data), pdMS_TO_TICKS(I2C_TIMEOUT_MS)),
237+
TAG, "Write WR_SET reg failed"
238+
);
239+
ch422g->regs.wr_set = data;
240+
155241
return ESP_OK;
156242
}
157243

244+
#define DIR_OUT_VALUE (0xFFF)
245+
#define DIR_IN_VALUE (0xF00)
246+
158247
static esp_err_t read_direction_reg(esp_io_expander_handle_t handle, uint32_t *value)
159248
{
160249
esp_io_expander_ch422g_t *ch422g = (esp_io_expander_ch422g_t *)__containerof(handle, esp_io_expander_ch422g_t, base);
161250

162-
*value = ch422g->regs.direction;
251+
*value = (ch422g->regs.wr_set & REG_WR_SET_BIT_IO_OE) ? DIR_OUT_VALUE : DIR_IN_VALUE;
252+
163253
return ESP_OK;
164254
}
165255

166256
static esp_err_t reset(esp_io_expander_t *handle)
167257
{
168-
ESP_RETURN_ON_ERROR(write_output_reg(handle, OUT_REG_DEFAULT_VAL), TAG, "Write output reg failed");
258+
ESP_RETURN_ON_ERROR(write_direction_reg(handle, REG_DIR_DEFAULT_VAL), TAG, "Write direction reg (WR_SET) failed");
259+
ESP_RETURN_ON_ERROR(write_output_reg(handle, REG_OUT_DEFAULT_VAL), TAG, "Write output reg (WR_OC & WR_IO) failed");
260+
169261
return ESP_OK;
170262
}
171263

@@ -174,5 +266,6 @@ static esp_err_t del(esp_io_expander_t *handle)
174266
esp_io_expander_ch422g_t *ch422g = (esp_io_expander_ch422g_t *)__containerof(handle, esp_io_expander_ch422g_t, base);
175267

176268
free(ch422g);
269+
177270
return ESP_OK;
178271
}

0 commit comments

Comments
 (0)