Skip to content

Commit 6216027

Browse files
authored
Merge pull request #8 from ainyan03/ioexpander_m5unified_0_2_21
Follow the IOExpander_Base API of M5Unified 0.2.21
2 parents f7ed40e + 342f0a1 commit 6216027

3 files changed

Lines changed: 148 additions & 66 deletions

File tree

src/M5StackChan.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,13 +60,13 @@ void M5StackChan_Class::io_expander_init()
6060
if (_io_expander) {
6161
// VM EN
6262
_io_expander->setDirection(0, true); // Output
63-
_io_expander->setPullMode(0, true); // Pull-up
63+
_io_expander->setPullMode(0, PY32IOExpander_Class::pull_up);
6464
setServoPowerEnabled(true);
6565
delay(200);
6666

6767
// RGB
68-
_io_expander->setDirection(13, true); // Output
69-
_io_expander->setPullMode(13, true); // Pull-up
68+
_io_expander->setDirection(13, true); // Output
69+
_io_expander->setPullMode(13, PY32IOExpander_Class::pull_up);
7070
_io_expander->setDriveMode(13, false); // Push-pull
7171
_io_expander->setLedCount(12);
7272
delay(200);

src/drivers/PY32IOExpander/PY32IOExpander.cpp

Lines changed: 87 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -49,19 +49,12 @@ static constexpr uint8_t REG_PWM3_DUTY_H = 0x20;
4949
static constexpr uint8_t REG_PWM4_DUTY_L = 0x21;
5050
static constexpr uint8_t REG_PWM4_DUTY_H = 0x22;
5151

52-
void PY32IOExpander_Class::_writeBit(uint8_t reg_l, uint8_t reg_h, uint8_t pin, bool value)
52+
bool PY32IOExpander_Class::_writeBit(uint8_t reg_l, uint8_t reg_h, uint8_t pin, bool value)
5353
{
5454
if (pin < 8) {
55-
if (value)
56-
bitOn(reg_l, 1 << pin);
57-
else
58-
bitOff(reg_l, 1 << pin);
59-
} else {
60-
if (value)
61-
bitOn(reg_h, 1 << (pin - 8));
62-
else
63-
bitOff(reg_h, 1 << (pin - 8));
55+
return value ? bitOn(reg_l, 1 << pin) : bitOff(reg_l, 1 << pin);
6456
}
57+
return value ? bitOn(reg_h, 1 << (pin - 8)) : bitOff(reg_h, 1 << (pin - 8));
6558
}
6659

6760
bool PY32IOExpander_Class::_readBit(uint8_t reg_l, uint8_t reg_h, uint8_t pin)
@@ -80,95 +73,133 @@ bool PY32IOExpander_Class::begin()
8073
return true;
8174
}
8275

83-
void PY32IOExpander_Class::setDirection(uint8_t pin, bool direction)
76+
bool PY32IOExpander_Class::_setDirection(uint8_t pin, bool direction)
8477
{
8578
// direction: false=input (0), true=output (1)
86-
_writeBit(REG_GPIO_M_L, REG_GPIO_M_H, pin, direction);
79+
if (!_isValidPin(pin)) return false;
80+
return _writeBit(REG_GPIO_M_L, REG_GPIO_M_H, pin, direction);
8781
}
8882

89-
void PY32IOExpander_Class::enablePull(uint8_t pin, bool enablePull)
83+
bool PY32IOExpander_Class::_setPullMode(uint8_t pin, gpio_pull_t mode)
9084
{
91-
if (enablePull) {
92-
// Enable Pull Up by default if neither is set
93-
bool pu = _readBit(REG_GPIO_PU_L, REG_GPIO_PU_H, pin);
94-
bool pd = _readBit(REG_GPIO_PD_L, REG_GPIO_PD_H, pin);
95-
if (!pu && !pd) {
96-
_writeBit(REG_GPIO_PU_L, REG_GPIO_PU_H, pin, true);
85+
if (!_isValidPin(pin)) return false;
86+
switch (mode) {
87+
case pull_none: {
88+
bool pu_ok = _writeBit(REG_GPIO_PU_L, REG_GPIO_PU_H, pin, false);
89+
bool pd_ok = _writeBit(REG_GPIO_PD_L, REG_GPIO_PD_H, pin, false);
90+
return pu_ok && pd_ok;
9791
}
98-
// If one is already set, leave it.
99-
} else {
100-
// Disable both
101-
_writeBit(REG_GPIO_PU_L, REG_GPIO_PU_H, pin, false);
102-
_writeBit(REG_GPIO_PD_L, REG_GPIO_PD_H, pin, false);
103-
}
104-
}
105-
106-
void PY32IOExpander_Class::setPullMode(uint8_t pin, bool mode)
107-
{
108-
// mode: false=down, true=up
109-
if (mode) {
110-
// Pull Up
111-
_writeBit(REG_GPIO_PD_L, REG_GPIO_PD_H, pin, false);
112-
_writeBit(REG_GPIO_PU_L, REG_GPIO_PU_H, pin, true);
113-
} else {
114-
// Pull Down
115-
_writeBit(REG_GPIO_PU_L, REG_GPIO_PU_H, pin, false);
116-
_writeBit(REG_GPIO_PD_L, REG_GPIO_PD_H, pin, true);
92+
case pull_up: {
93+
bool pd_ok = _writeBit(REG_GPIO_PD_L, REG_GPIO_PD_H, pin, false);
94+
bool pu_ok = _writeBit(REG_GPIO_PU_L, REG_GPIO_PU_H, pin, true);
95+
return pd_ok && pu_ok;
96+
}
97+
case pull_down: {
98+
bool pu_ok = _writeBit(REG_GPIO_PU_L, REG_GPIO_PU_H, pin, false);
99+
bool pd_ok = _writeBit(REG_GPIO_PD_L, REG_GPIO_PD_H, pin, true);
100+
return pu_ok && pd_ok;
101+
}
102+
default:
103+
return false;
117104
}
118105
}
119106

120107
void PY32IOExpander_Class::setDriveMode(uint8_t pin, bool openDrain)
121108
{
122109
// openDrain: false=push-pull (0), true=open-drain (1)
110+
if (!_isValidPin(pin)) return;
123111
_writeBit(REG_GPIO_DRV_L, REG_GPIO_DRV_H, pin, openDrain);
124112
}
125113

126-
void PY32IOExpander_Class::setHighImpedance(uint8_t pin, bool enable)
114+
bool PY32IOExpander_Class::_setHighImpedance(uint8_t pin, bool enable)
127115
{
128-
if (enable) {
129-
// Input mode
130-
setDirection(pin, false);
131-
// Disable pulls
132-
enablePull(pin, false);
133-
}
116+
if (!_isValidPin(pin)) return false;
117+
if (!enable) return true;
118+
// Input mode with the pulls disabled
119+
bool dir_ok = _setDirection(pin, false);
120+
bool pull_ok = _setPullMode(pin, pull_none);
121+
return dir_ok && pull_ok;
134122
}
135123

136124
bool PY32IOExpander_Class::getWriteValue(uint8_t pin)
137125
{
126+
if (!_isValidPin(pin)) return false;
138127
return _readBit(REG_GPIO_O_L, REG_GPIO_O_H, pin);
139128
}
140129

141-
void PY32IOExpander_Class::digitalWrite(uint8_t pin, bool level)
130+
bool PY32IOExpander_Class::_digitalWrite(uint8_t pin, bool level)
142131
{
143-
_writeBit(REG_GPIO_O_L, REG_GPIO_O_H, pin, level);
132+
if (!_isValidPin(pin)) return false;
133+
return _writeBit(REG_GPIO_O_L, REG_GPIO_O_H, pin, level);
144134
}
145135

146136
bool PY32IOExpander_Class::digitalRead(uint8_t pin)
147137
{
138+
if (!_isValidPin(pin)) return false;
148139
return _readBit(REG_GPIO_I_L, REG_GPIO_I_H, pin);
149140
}
150141

151-
void PY32IOExpander_Class::resetIrq()
142+
bool PY32IOExpander_Class::_resetIrq()
152143
{
153144
// Clear all interrupts by writing 1s to IS registers
154-
writeRegister8(REG_GPIO_IS_L, 0xFF);
155-
writeRegister8(REG_GPIO_IS_H, 0xFF); // Only bits 0-5 used for high byte (pins 8-13)
145+
bool l_ok = writeRegister8(REG_GPIO_IS_L, 0xFF);
146+
bool h_ok = writeRegister8(REG_GPIO_IS_H, 0xFF); // Only bits 0-5 used for high byte (pins 8-13)
147+
return l_ok && h_ok;
156148
}
157149

158-
void PY32IOExpander_Class::disableIrq()
150+
bool PY32IOExpander_Class::_disableIrq()
159151
{
160152
// Disable all interrupts
161-
writeRegister8(REG_GPIO_IE_L, 0x00);
162-
writeRegister8(REG_GPIO_IE_H, 0x00);
153+
bool l_ok = writeRegister8(REG_GPIO_IE_L, 0x00);
154+
bool h_ok = writeRegister8(REG_GPIO_IE_H, 0x00);
155+
return l_ok && h_ok;
163156
}
164157

165-
void PY32IOExpander_Class::enableIrq()
158+
bool PY32IOExpander_Class::_enableIrq()
166159
{
167160
// Enable all interrupts
168-
writeRegister8(REG_GPIO_IE_L, 0xFF);
169-
writeRegister8(REG_GPIO_IE_H, 0x3F); // Pins 8-13
161+
bool l_ok = writeRegister8(REG_GPIO_IE_L, 0xFF);
162+
bool h_ok = writeRegister8(REG_GPIO_IE_H, 0x3F); // Pins 8-13
163+
return l_ok && h_ok;
170164
}
171165

166+
void PY32IOExpander_Class::enablePull(uint8_t pin, bool enablePull)
167+
{
168+
if (!_isValidPin(pin)) return;
169+
if (enablePull) {
170+
// Enable Pull Up by default if neither is set
171+
bool pu = _readBit(REG_GPIO_PU_L, REG_GPIO_PU_H, pin);
172+
bool pd = _readBit(REG_GPIO_PD_L, REG_GPIO_PD_H, pin);
173+
if (!pu && !pd) {
174+
_setPullMode(pin, pull_up);
175+
}
176+
// If one is already set, leave it.
177+
} else {
178+
_setPullMode(pin, pull_none);
179+
}
180+
}
181+
182+
#if PY32IOEXPANDER_STATUS_API
183+
bool PY32IOExpander_Class::setDirection(uint8_t pin, bool direction) { return _setDirection(pin, direction); }
184+
bool PY32IOExpander_Class::setPullMode(uint8_t pin, gpio_pull_t mode) { return _setPullMode(pin, mode); }
185+
bool PY32IOExpander_Class::setPullMode(uint8_t pin, bool mode) { return _setPullMode(pin, mode ? pull_up : pull_down); }
186+
bool PY32IOExpander_Class::setHighImpedance(uint8_t pin, bool enable) { return _setHighImpedance(pin, enable); }
187+
bool PY32IOExpander_Class::digitalWrite(uint8_t pin, bool level) { return _digitalWrite(pin, level); }
188+
bool PY32IOExpander_Class::resetIrq() { return _resetIrq(); }
189+
bool PY32IOExpander_Class::disableIrq() { return _disableIrq(); }
190+
bool PY32IOExpander_Class::enableIrq() { return _enableIrq(); }
191+
#else
192+
void PY32IOExpander_Class::setDirection(uint8_t pin, bool direction) { _setDirection(pin, direction); }
193+
// mode: false=down, true=up
194+
void PY32IOExpander_Class::setPullMode(uint8_t pin, bool mode) { _setPullMode(pin, mode ? pull_up : pull_down); }
195+
bool PY32IOExpander_Class::setPullMode(uint8_t pin, gpio_pull_t mode) { return _setPullMode(pin, mode); }
196+
void PY32IOExpander_Class::setHighImpedance(uint8_t pin, bool enable) { _setHighImpedance(pin, enable); }
197+
void PY32IOExpander_Class::digitalWrite(uint8_t pin, bool level) { _digitalWrite(pin, level); }
198+
void PY32IOExpander_Class::resetIrq() { _resetIrq(); }
199+
void PY32IOExpander_Class::disableIrq() { _disableIrq(); }
200+
void PY32IOExpander_Class::enableIrq() { _enableIrq(); }
201+
#endif
202+
172203
uint16_t PY32IOExpander_Class::readDeviceUID()
173204
{
174205
uint8_t l = readRegister8(REG_UID_L);

src/drivers/PY32IOExpander/PY32IOExpander.hpp

Lines changed: 58 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,26 @@
88

99
#include <M5Unified.hpp>
1010

11+
// M5Unified 0.2.21 changed the IOExpander_Base virtuals: they report the write
12+
// status as bool, setPullMode takes gpio_pull_t and enablePull was removed.
13+
#if defined(M5UNIFIED_VERSION_MAJOR) && \
14+
((M5UNIFIED_VERSION_MAJOR > 0) || (M5UNIFIED_VERSION_MINOR > 2) || \
15+
(M5UNIFIED_VERSION_MINOR == 2 && M5UNIFIED_VERSION_PATCH >= 21))
16+
#define PY32IOEXPANDER_STATUS_API 1
17+
#else
18+
#define PY32IOEXPANDER_STATUS_API 0
19+
#endif
20+
1121
namespace m5 {
1222
class PY32IOExpander_Class : public IOExpander_Base {
1323
public:
1424
static constexpr std::uint8_t DEFAULT_ADDRESS = 0x6F;
1525

26+
#if !PY32IOEXPANDER_STATUS_API
27+
// Same names and values as IOExpander_Base::gpio_pull_t in M5Unified 0.2.21+
28+
enum gpio_pull_t : std::uint8_t { pull_none = 0, pull_up = 1, pull_down = 2 };
29+
#endif
30+
1631
PY32IOExpander_Class(std::uint8_t i2c_addr = DEFAULT_ADDRESS, std::uint32_t freq = 100000,
1732
m5::I2C_Class* i2c = &m5::In_I2C)
1833
: IOExpander_Base(i2c_addr, freq, i2c)
@@ -23,29 +38,55 @@ class PY32IOExpander_Class : public IOExpander_Base {
2338

2439
// IOExpander_Base overrides
2540
// false input, true output
41+
// Return true when every register access was acknowledged.
42+
#if PY32IOEXPANDER_STATUS_API
43+
bool setDirection(uint8_t pin, bool direction) override;
44+
45+
bool setPullMode(uint8_t pin, gpio_pull_t mode) override;
46+
47+
// false down, true up (kept for callers written against the old API)
48+
bool setPullMode(uint8_t pin, bool mode);
49+
50+
// Kept for callers written against the old API: true enables the pull-up unless a pull
51+
// is already set, false disables both pulls.
52+
void enablePull(uint8_t pin, bool enablePull);
53+
54+
bool setHighImpedance(uint8_t pin, bool enable) override;
55+
56+
bool digitalWrite(uint8_t pin, bool level) override;
57+
58+
bool resetIrq() override;
59+
60+
bool disableIrq() override;
61+
62+
bool enableIrq() override;
63+
#else
2664
void setDirection(uint8_t pin, bool direction) override;
2765

2866
void enablePull(uint8_t pin, bool enablePull) override;
2967

3068
// false down, true up
3169
void setPullMode(uint8_t pin, bool mode) override;
3270

33-
// false push-pull, true open-drain
34-
void setDriveMode(uint8_t pin, bool openDrain);
71+
bool setPullMode(uint8_t pin, gpio_pull_t mode);
3572

3673
void setHighImpedance(uint8_t pin, bool enable) override;
3774

38-
bool getWriteValue(uint8_t pin) override;
39-
4075
void digitalWrite(uint8_t pin, bool level) override;
4176

42-
bool digitalRead(uint8_t pin) override;
43-
4477
void resetIrq() override;
4578

4679
void disableIrq() override;
4780

4881
void enableIrq() override;
82+
#endif
83+
84+
// false push-pull, true open-drain
85+
void setDriveMode(uint8_t pin, bool openDrain);
86+
87+
bool getWriteValue(uint8_t pin) override;
88+
89+
bool digitalRead(uint8_t pin) override;
4990

5091
// Extended functionality
5192
uint16_t readDeviceUID();
@@ -69,7 +110,17 @@ class PY32IOExpander_Class : public IOExpander_Base {
69110
void refreshLeds();
70111

71112
private:
72-
void _writeBit(uint8_t reg_l, uint8_t reg_h, uint8_t pin, bool value);
113+
// Version independent implementation; the overrides above wrap these.
114+
bool _setDirection(uint8_t pin, bool direction);
115+
bool _setPullMode(uint8_t pin, gpio_pull_t mode);
116+
bool _setHighImpedance(uint8_t pin, bool enable);
117+
bool _digitalWrite(uint8_t pin, bool level);
118+
bool _resetIrq();
119+
bool _disableIrq();
120+
bool _enableIrq();
121+
122+
static bool _isValidPin(uint8_t pin) { return pin < 14; }
123+
bool _writeBit(uint8_t reg_l, uint8_t reg_h, uint8_t pin, bool value);
73124
bool _readBit(uint8_t reg_l, uint8_t reg_h, uint8_t pin);
74125
};
75126
} // namespace m5

0 commit comments

Comments
 (0)