Skip to content

Commit c118e4b

Browse files
lboueLzw655
authored andcommitted
Added support for CH422G from Waveshare
Add CH422G in ESP_IOExpander_Library.h Closes #3
1 parent 39460b3 commit c118e4b

File tree

3 files changed

+252
-0
lines changed

3 files changed

+252
-0
lines changed

src/ESP_IOExpander_Library.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,6 @@
1212
#include "chip/TCA95xx_8bit.h"
1313
#include "chip/TCA95xx_16bit.h"
1414
#include "chip/HT8574.h"
15+
#include "chip/CH422G.h"
1516

1617
#endif

src/chip/CH422G.cpp

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <inttypes.h>
8+
#include <string.h>
9+
#include <stdlib.h>
10+
11+
#include "driver/i2c.h"
12+
#include "esp_bit_defs.h"
13+
#include "esp_check.h"
14+
#include "esp_log.h"
15+
16+
#include "../private/CheckResult.h"
17+
#include "CH422G.h"
18+
19+
/* Timeout of each I2C communication */
20+
#define I2C_TIMEOUT_MS (10)
21+
22+
#define IO_COUNT (8)
23+
24+
/* Default register value on power-up */
25+
#define DIR_REG_DEFAULT_VAL (0xff)
26+
#define OUT_REG_DEFAULT_VAL (0xdf)
27+
28+
/**
29+
* @brief Device Structure Type
30+
*
31+
*/
32+
typedef struct {
33+
esp_io_expander_t base;
34+
i2c_port_t i2c_num;
35+
uint32_t i2c_address;
36+
struct {
37+
uint8_t direction;
38+
uint8_t output;
39+
} regs;
40+
} esp_io_expander_ch422g_t;
41+
42+
static const char *TAG = "ch422g";
43+
44+
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);
45+
46+
ESP_IOExpander_CH422G::~ESP_IOExpander_CH422G()
47+
{
48+
if (i2c_need_init) {
49+
i2c_driver_delete(i2c_id);
50+
}
51+
if (handle) {
52+
del();
53+
}
54+
}
55+
56+
void ESP_IOExpander_CH422G::begin(void)
57+
{
58+
CHECK_ERROR_RETURN(esp_io_expander_new_i2c_ch422g(i2c_id, i2c_address, &handle));
59+
}
60+
61+
static esp_err_t read_input_reg(esp_io_expander_handle_t handle, uint32_t *value);
62+
static esp_err_t write_output_reg(esp_io_expander_handle_t handle, uint32_t value);
63+
static esp_err_t read_output_reg(esp_io_expander_handle_t handle, uint32_t *value);
64+
static esp_err_t write_direction_reg(esp_io_expander_handle_t handle, uint32_t value);
65+
static esp_err_t read_direction_reg(esp_io_expander_handle_t handle, uint32_t *value);
66+
static esp_err_t reset(esp_io_expander_t *handle);
67+
static esp_err_t del(esp_io_expander_t *handle);
68+
69+
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)
70+
{
71+
ESP_RETURN_ON_FALSE(i2c_num < I2C_NUM_MAX, ESP_ERR_INVALID_ARG, TAG, "Invalid i2c num");
72+
ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "Invalid handle");
73+
74+
esp_io_expander_ch422g_t *ch422g = (esp_io_expander_ch422g_t *)calloc(1, sizeof(esp_io_expander_ch422g_t));
75+
ESP_RETURN_ON_FALSE(ch422g, ESP_ERR_NO_MEM, TAG, "Malloc failed");
76+
77+
ch422g->base.config.io_count = IO_COUNT;
78+
ch422g->base.config.flags.dir_out_bit_zero = 1;
79+
ch422g->i2c_num = i2c_num;
80+
ch422g->i2c_address = i2c_address;
81+
ch422g->regs.output = OUT_REG_DEFAULT_VAL;
82+
ch422g->base.read_input_reg = read_input_reg;
83+
ch422g->base.write_output_reg = write_output_reg;
84+
ch422g->base.read_output_reg = read_output_reg;
85+
ch422g->base.write_direction_reg = write_direction_reg;
86+
ch422g->base.read_direction_reg = read_direction_reg;
87+
ch422g->base.del = del;
88+
ch422g->base.reset = reset;
89+
90+
esp_err_t ret = ESP_OK;
91+
/* Reset configuration and register status */
92+
ESP_GOTO_ON_ERROR(reset(&ch422g->base), err, TAG, "Reset failed");
93+
94+
*handle = &ch422g->base;
95+
return ESP_OK;
96+
err:
97+
free(ch422g);
98+
return ret;
99+
}
100+
101+
#define CH422G_REG_IN 0x26
102+
static esp_err_t read_input_reg(esp_io_expander_handle_t handle, uint32_t *value)
103+
{
104+
esp_io_expander_ch422g_t *ch422g = (esp_io_expander_ch422g_t *)__containerof(handle, esp_io_expander_ch422g_t, base);
105+
106+
uint8_t temp = 0;
107+
108+
ESP_RETURN_ON_ERROR(
109+
i2c_master_read_from_device(ch422g->i2c_num, ch422g->i2c_address, &temp, 1, pdMS_TO_TICKS(I2C_TIMEOUT_MS)),
110+
TAG, "Read input reg failed");
111+
112+
// *INDENT-OFF*
113+
ESP_RETURN_ON_ERROR(
114+
i2c_master_read_from_device(ch422g->i2c_num, CH422G_REG_IN, &temp, 1, pdMS_TO_TICKS(I2C_TIMEOUT_MS)),
115+
TAG, "Read input reg failed");
116+
// *INDENT-ON*
117+
*value = temp;
118+
return ESP_OK;
119+
}
120+
121+
#define CH422G_REG_OUT 0x38
122+
static esp_err_t write_output_reg(esp_io_expander_handle_t handle, uint32_t value)
123+
{
124+
esp_io_expander_ch422g_t *ch422g = (esp_io_expander_ch422g_t *)__containerof(handle, esp_io_expander_ch422g_t, base);
125+
value &= 0xff;
126+
127+
uint8_t out_temp = 0x01;
128+
ESP_RETURN_ON_ERROR(
129+
i2c_master_write_to_device(ch422g->i2c_num, ch422g->i2c_address, &out_temp, 1, pdMS_TO_TICKS(I2C_TIMEOUT_MS)),
130+
TAG, "Write output reg failed");
131+
132+
uint8_t data = (uint8_t)value;
133+
ESP_RETURN_ON_ERROR(
134+
i2c_master_write_to_device(ch422g->i2c_num, CH422G_REG_OUT, &data, 1, pdMS_TO_TICKS(I2C_TIMEOUT_MS)),
135+
TAG, "Write output reg failed");
136+
ch422g->regs.output = value;
137+
return ESP_OK;
138+
}
139+
140+
static esp_err_t read_output_reg(esp_io_expander_handle_t handle, uint32_t *value)
141+
{
142+
esp_io_expander_ch422g_t *ch422g = (esp_io_expander_ch422g_t *)__containerof(handle, esp_io_expander_ch422g_t, base);
143+
144+
*value = ch422g->regs.output;
145+
return ESP_OK;
146+
}
147+
148+
static esp_err_t write_direction_reg(esp_io_expander_handle_t handle, uint32_t value)
149+
{
150+
esp_io_expander_ch422g_t *ch422g = (esp_io_expander_ch422g_t *)__containerof(handle, esp_io_expander_ch422g_t, base);
151+
value &= 0xff;
152+
ch422g->regs.direction = value;
153+
return ESP_OK;
154+
}
155+
156+
static esp_err_t read_direction_reg(esp_io_expander_handle_t handle, uint32_t *value)
157+
{
158+
esp_io_expander_ch422g_t *ch422g = (esp_io_expander_ch422g_t *)__containerof(handle, esp_io_expander_ch422g_t, base);
159+
160+
*value = ch422g->regs.direction;
161+
return ESP_OK;
162+
}
163+
164+
static esp_err_t reset(esp_io_expander_t *handle)
165+
{
166+
ESP_RETURN_ON_ERROR(write_output_reg(handle, OUT_REG_DEFAULT_VAL), TAG, "Write output reg failed");
167+
return ESP_OK;
168+
}
169+
170+
static esp_err_t del(esp_io_expander_t *handle)
171+
{
172+
esp_io_expander_ch422g_t *ch422g = (esp_io_expander_ch422g_t *)__containerof(handle, esp_io_expander_ch422g_t, base);
173+
174+
free(ch422g);
175+
return ESP_OK;
176+
}

src/chip/CH422G.h

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#pragma once
8+
9+
#include <stdint.h>
10+
11+
#include "driver/i2c.h"
12+
#include "esp_err.h"
13+
14+
#include "../ESP_IOExpander.h"
15+
16+
class ESP_IOExpander_CH422G: public ESP_IOExpander {
17+
public:
18+
/**
19+
* @brief Constructor to create ESP_IOExpander object
20+
*
21+
* @note After using this function, call `init()` will initialize I2C bus.
22+
*
23+
* @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.
26+
* @param config Pointer to I2C bus configuration
27+
*/
28+
ESP_IOExpander_CH422G(i2c_port_t id, uint8_t address, const i2c_config_t *config): ESP_IOExpander(id, address, config) { };
29+
30+
/**
31+
* @brief Constructor to create ESP_IOExpander object
32+
*
33+
* @note After using this function, call `init()` will initialize I2C bus.
34+
*
35+
* @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.
38+
* @param scl SCL pin number
39+
* @param sda SDA pin number
40+
*/
41+
ESP_IOExpander_CH422G(i2c_port_t id, uint8_t address, int scl, int sda): ESP_IOExpander(id, address, scl, sda) { };
42+
43+
/**
44+
* @brief Constructor to create ESP_IOExpander object
45+
*
46+
* @note If use this function, should initialize I2C bus before call `init()`.
47+
*
48+
* @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.
51+
*/
52+
ESP_IOExpander_CH422G(i2c_port_t id, uint8_t address): ESP_IOExpander(id, address) { };
53+
54+
/**
55+
* @brief Destructor
56+
*
57+
* @note This function will delete I2C driver if it is initialized by ESP_IOExpander and delete ESP_IOExpander object.
58+
*/
59+
~ESP_IOExpander_CH422G() override;
60+
61+
/**
62+
* @brief Begin IO expander
63+
*
64+
*/
65+
void begin(void) override;
66+
};
67+
68+
/**
69+
* @brief I2C address of the ch422g
70+
*
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.
74+
*/
75+
#define ESP_IO_EXPANDER_I2C_CH422G_ADDRESS_000 (0x24)

0 commit comments

Comments
 (0)