Skip to content

Commit efb0968

Browse files
committed
rg_i2c: Added support for MCP23017 extender (#203)
This is untested because I don't have one. All my knowledge comes from reading the datasheet. Maybe I broke all extenders with this new code, in fact...
1 parent 56f3097 commit efb0968

File tree

3 files changed

+55
-56
lines changed

3 files changed

+55
-56
lines changed

components/retro-go/drivers/display/ili9341.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -156,13 +156,13 @@ static void lcd_set_backlight(float percent)
156156

157157
#if defined(RG_GPIO_LCD_BCKL)
158158
#if defined(RG_TARGET_BYTEBOI_REV1)
159-
rg_i2c_gpio_set_direction(RG_GPIO_LCD_BCKL, 0);
159+
rg_i2c_gpio_set_direction(RG_GPIO_LCD_BCKL, RG_GPIO_OUTPUT);
160160
rg_i2c_gpio_set_level(RG_GPIO_LCD_BCKL, percent > 0 ? 0:1);
161161
#else
162162
error_code = ledc_set_fade_time_and_start(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, 0x1FFF * level, 50, 0);
163163
#endif
164164
#elif defined(RG_TARGET_QTPY_GAMER)
165-
rg_i2c_gpio_set_direction(AW_TFT_BACKLIGHT, 0);
165+
rg_i2c_gpio_set_direction(AW_TFT_BACKLIGHT, RG_GPIO_ANALOG_OUTPUT);
166166
rg_i2c_gpio_set_level(AW_TFT_BACKLIGHT, level * 255);
167167
#endif
168168

@@ -237,7 +237,7 @@ static void lcd_init(void)
237237
gpio_set_level(RG_GPIO_LCD_RST, 1);
238238
rg_usleep(10 * 1000);
239239
#elif defined(RG_TARGET_QTPY_GAMER)
240-
rg_i2c_gpio_set_direction(AW_TFT_RESET, 0);
240+
rg_i2c_gpio_set_direction(AW_TFT_RESET, RG_GPIO_OUTPUT);
241241
rg_i2c_gpio_set_level(AW_TFT_RESET, 0);
242242
rg_usleep(100 * 1000);
243243
rg_i2c_gpio_set_level(AW_TFT_RESET, 1);

components/retro-go/rg_i2c.c

Lines changed: 42 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -132,21 +132,31 @@ static uint8_t gpio_extender_address = 0x00;
132132

133133
#if RG_I2C_GPIO_DRIVER == 1 // AW9523
134134

135-
#define AW9523_REG_CHIPID 0x10 ///< Register for hardcode chip ID
136-
#define AW9523_REG_SOFTRESET 0x7F ///< Register for soft resetting
137-
#define AW9523_REG_INPUT0 0x00 ///< Register for reading input values
138-
#define AW9523_REG_OUTPUT0 0x02 ///< Register for writing output values
139-
#define AW9523_REG_CONFIG0 0x04 ///< Register for configuring direction
140-
#define AW9523_REG_INTENABLE0 0x06 ///< Register for enabling interrupt
141-
#define AW9523_REG_GCR 0x11 ///< Register for general configuration
142-
#define AW9523_REG_LEDMODE 0x12 ///< Register for configuring const current
135+
static const uint8_t gpio_input_regs[2] = {0x00, 0x01};
136+
static const uint8_t gpio_output_regs[2] = {0x02, 0x03};
137+
static const uint8_t gpio_direction_regs[2] = {0x04, 0x05};
138+
static const uint8_t gpio_init_sequence[][2] = {
139+
{0x7F, 0x00}, // Software reset (is it really necessary?)
140+
{0x11, 1 << 4}, // Push-Pull mode
141+
};
142+
static const uint8_t gpio_deinit_sequence[][2] = {};
143143

144144
#elif RG_I2C_GPIO_DRIVER == 2 // PCF9539
145145

146-
#define AW9523_REG_INPUT0 0x00 ///< Register for reading input values
147-
#define AW9523_REG_OUTPUT0 0x02 ///< Register for writing output values
148-
#define AW9523_REG_POLARITY0 0x04 ///< Register for polarity inversion of inputs
149-
#define AW9523_REG_CONFIG0 0x06 ///< Register for configuring direction
146+
static const uint8_t gpio_input_regs[2] = {0x00, 0x01};
147+
static const uint8_t gpio_output_regs[2] = {0x02, 0x03};
148+
static const uint8_t gpio_direction_regs[2] = {0x06, 0x07};
149+
static const uint8_t gpio_init_sequence[][2] = {};
150+
static const uint8_t gpio_deinit_sequence[][2] = {};
151+
152+
#elif RG_I2C_GPIO_DRIVER == 3 // MCP23017
153+
154+
// Mappings when IOCON.BANK = 0 (which should be default on power-on)
155+
static const uint8_t gpio_input_regs[2] = {0x12, 0x13};
156+
static const uint8_t gpio_output_regs[2] = {0x14, 0x15};
157+
static const uint8_t gpio_direction_regs[2] = {0x00, 0x01};
158+
static const uint8_t gpio_init_sequence[][2] = {};
159+
static const uint8_t gpio_deinit_sequence[][2] = {};
150160

151161
#endif
152162

@@ -159,69 +169,49 @@ bool rg_i2c_gpio_init(void)
159169
if (!i2c_initialized && !rg_i2c_init())
160170
return false;
161171

162-
#if RG_I2C_GPIO_DRIVER == 1 // AW9523
163-
164172
gpio_extender_address = RG_I2C_GPIO_ADDR;
165-
rg_i2c_write_byte(gpio_extender_address, AW9523_REG_SOFTRESET, 0);
166-
rg_usleep(10 * 1000);
167-
uint8_t id = rg_i2c_read_byte(gpio_extender_address, AW9523_REG_CHIPID);
168-
if (id != 0x23)
169-
{
170-
RG_LOGE("AW9523 invalid ID 0x%x found", id);
171-
return false;
172-
}
173-
rg_i2c_write_byte(gpio_extender_address, AW9523_REG_CONFIG0, 0xFF);
174-
rg_i2c_write_byte(gpio_extender_address, AW9523_REG_CONFIG0 + 1, 0xFF);
175-
rg_i2c_write_byte(gpio_extender_address, AW9523_REG_LEDMODE, 0xFF);
176-
rg_i2c_write_byte(gpio_extender_address, AW9523_REG_LEDMODE + 1, 0xFF);
177-
rg_i2c_write_byte(gpio_extender_address, AW9523_REG_GCR, 1 << 4);
178-
179173
gpio_extender_initialized = true;
180-
return true;
181174

182-
#elif RG_I2C_GPIO_DRIVER == 2 // PCF9539
175+
// Configure extender-specific registers if needed (disable open-drain, interrupts, inversion, etc)
176+
for (size_t i = 0; i < RG_COUNT(gpio_init_sequence); ++i)
177+
rg_i2c_write_byte(gpio_extender_address, gpio_init_sequence[i][0], gpio_init_sequence[i][1]);
183178

184-
gpio_extender_address = RG_I2C_GPIO_ADDR;
185-
rg_i2c_write_byte(gpio_extender_address, AW9523_REG_OUTPUT0, 0xFF);
186-
rg_i2c_write_byte(gpio_extender_address, AW9523_REG_OUTPUT0 + 1, 0xFF);
187-
rg_i2c_write_byte(gpio_extender_address, AW9523_REG_POLARITY0, 0x00);
188-
rg_i2c_write_byte(gpio_extender_address, AW9523_REG_POLARITY0 + 1, 0x00);
189-
rg_i2c_write_byte(gpio_extender_address, AW9523_REG_CONFIG0, 0xFF);
190-
rg_i2c_write_byte(gpio_extender_address, AW9523_REG_CONFIG0 + 1, 0xFF);
179+
// Now set all pins of all ports as inputs and clear output latches
180+
for (size_t i = 0; i < RG_COUNT(gpio_direction_regs); ++i)
181+
rg_i2c_write_byte(gpio_extender_address, gpio_direction_regs[i], 0xFF);
182+
for (size_t i = 0; i < RG_COUNT(gpio_output_regs); ++i)
183+
rg_i2c_write_byte(gpio_extender_address, gpio_output_regs[i], 0x00);
191184

192-
gpio_extender_initialized = true;
193185
return true;
194-
195-
#else
196-
197-
RG_LOGE("Unknown driver type");
198-
return false;
199-
200-
#endif
201186
}
202187

203188
bool rg_i2c_gpio_deinit(void)
204189
{
205-
gpio_extender_initialized = false;
206-
gpio_extender_address = 0;
190+
if (gpio_extender_initialized)
191+
{
192+
for (size_t i = 0; i < RG_COUNT(gpio_deinit_sequence); ++i)
193+
rg_i2c_write_byte(gpio_extender_address, gpio_deinit_sequence[i][0], gpio_deinit_sequence[i][1]);
194+
// Should we reset all pins to be high impedance?
195+
gpio_extender_initialized = false;
196+
}
207197
return true;
208198
}
209199

210-
bool rg_i2c_gpio_set_direction(int pin, int mode)
200+
bool rg_i2c_gpio_set_direction(int pin, rg_gpio_mode_t mode)
211201
{
212-
uint8_t reg = AW9523_REG_CONFIG0 + (pin >> 3), mask = 1 << (pin & 7);
202+
uint8_t reg = gpio_direction_regs[(pin >> 3) & 1], mask = 1 << (pin & 7);
213203
uint8_t val = rg_i2c_read_byte(gpio_extender_address, reg);
214204
return rg_i2c_write_byte(gpio_extender_address, reg, mode ? (val | mask) : (val & ~mask));
215205
}
216206

217207
uint8_t rg_i2c_gpio_read_port(int port)
218208
{
219-
return rg_i2c_read_byte(gpio_extender_address, AW9523_REG_INPUT0 + port);
209+
return rg_i2c_read_byte(gpio_extender_address, gpio_input_regs[port & 1]);
220210
}
221211

222212
bool rg_i2c_gpio_write_port(int port, uint8_t value)
223213
{
224-
return rg_i2c_write_byte(gpio_extender_address, AW9523_REG_OUTPUT0 + port, value);
214+
return rg_i2c_write_byte(gpio_extender_address, gpio_output_regs[port & 1], value);
225215
}
226216

227217
int rg_i2c_gpio_get_level(int pin)
@@ -231,7 +221,7 @@ int rg_i2c_gpio_get_level(int pin)
231221

232222
bool rg_i2c_gpio_set_level(int pin, int level)
233223
{
234-
uint8_t reg = AW9523_REG_OUTPUT0 + (pin >> 3), mask = 1 << (pin & 7);
224+
uint8_t reg = gpio_output_regs[(pin >> 3) & 1], mask = 1 << (pin & 7);
235225
uint8_t val = rg_i2c_read_byte(gpio_extender_address, reg);
236226
return rg_i2c_write_byte(gpio_extender_address, reg, level ? (val | mask) : (val & ~mask));
237227
}

components/retro-go/rg_i2c.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,19 @@ bool rg_i2c_write(uint8_t addr, int reg, const void *write_data, size_t write_le
1111
uint8_t rg_i2c_read_byte(uint8_t addr, uint8_t reg);
1212
bool rg_i2c_write_byte(uint8_t addr, uint8_t reg, uint8_t value);
1313

14+
1415
// GPIO extender
16+
typedef enum
17+
{
18+
RG_GPIO_INPUT = 1,
19+
RG_GPIO_OUTPUT = 0,
20+
RG_GPIO_ANALOG_INPUT = 1, // No supported chip yet
21+
RG_GPIO_ANALOG_OUTPUT = 0, // Not yet implemented for AW9523
22+
} rg_gpio_mode_t;
23+
1524
bool rg_i2c_gpio_init(void);
1625
bool rg_i2c_gpio_deinit(void);
17-
bool rg_i2c_gpio_set_direction(int pin, int mode);
26+
bool rg_i2c_gpio_set_direction(int pin, rg_gpio_mode_t mode);
1827
int rg_i2c_gpio_get_level(int pin);
1928
bool rg_i2c_gpio_set_level(int pin, int level);
2029
uint8_t rg_i2c_gpio_read_port(int port);

0 commit comments

Comments
 (0)