Skip to content

Commit b1424e1

Browse files
committed
Add open-drain to digitalio + Resolve some issues with GPIO4 & setting pullup/pulldown
1 parent 7fe51d3 commit b1424e1

File tree

3 files changed

+112
-31
lines changed

3 files changed

+112
-31
lines changed

ports/analog/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,7 @@ CFLAGS += -Wno-error=unused-parameter \
209209
-Wno-error=nested-externs \
210210
-Wno-error=sign-compare \
211211
-Wno-cast-align \
212+
-Wno-sign-compare \
212213

213214
ENTRY = Reset_Handler
214215
LDFLAGS += $(CFLAGS) --entry $(ENTRY) -Wl,-nostdlib -Wl,-T,$(LINKERFILE) -Wl,-Map=$@.map -Wl,-cref -Wl,-gc-sections

ports/analog/common-hal/digitalio/DigitalInOut.c

Lines changed: 109 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,13 @@ digitalinout_result_t common_hal_digitalio_digitalinout_construct(
2828

2929
common_hal_mcu_pin_claim(pin);
3030
self->pin = pin;
31+
self->open_drain = false;
32+
self->vssel = MXC_GPIO_VSSEL_VDDIOH;
3133

3234
mxc_gpio_cfg_t new_gpio_cfg = {
3335
.port = gpio_ports[self->pin->port],
3436
.mask = (self->pin->mask),
35-
.vssel = self->pin->level,
37+
.vssel = self->vssel,
3638
.func = MXC_GPIO_FUNC_IN,
3739
.drvstr = MXC_GPIO_DRVSTR_0,
3840
.pad = MXC_GPIO_PAD_NONE,
@@ -55,6 +57,7 @@ digitalinout_result_t common_hal_digitalio_digitalinout_switch_to_input(
5557
digitalio_digitalinout_obj_t *self, digitalio_pull_t pull) {
5658
mxc_gpio_regs_t *port = gpio_ports[self->pin->port];
5759
uint32_t mask = self->pin->mask;
60+
5861
int err = E_NO_ERROR;
5962

6063
if (self->pin->port == 4) {
@@ -76,21 +79,18 @@ digitalinout_result_t common_hal_digitalio_digitalinout_switch_to_output(
7679
mxc_gpio_regs_t *port = gpio_ports[self->pin->port];
7780
uint32_t mask = self->pin->mask;
7881

82+
self->open_drain = (drive_mode == DRIVE_MODE_OPEN_DRAIN);
83+
84+
// Set GPIO(s) to output mode
7985
if (self->pin->port == 4) {
80-
// Set GPIO(s) to output mode
8186
MXC_MCR->gpio4_ctrl |= GPIO4_OUTEN_MASK(mask);
8287
MXC_MCR->outen &= ~GPIO4_AFEN_MASK(mask);
8388
} else {
8489
MXC_GPIO_RevA_SetAF((mxc_gpio_reva_regs_t *)port, MXC_GPIO_FUNC_OUT, mask);
8590
}
91+
8692
common_hal_digitalio_digitalinout_set_value(self, value);
8793

88-
// todo (low): MSDK Hardware does not support open-drain configuration except
89-
// todo (low): when directly managed by a peripheral such as I2C.
90-
// todo (low): find a way to signal this to any upstream code
91-
if (drive_mode != DRIVE_MODE_PUSH_PULL) {
92-
return DIGITALINOUT_INVALID_DRIVE_MODE;
93-
}
9494
return DIGITALINOUT_OK;
9595
}
9696

@@ -100,6 +100,11 @@ digitalio_direction_t common_hal_digitalio_digitalinout_get_direction(
100100
mxc_gpio_regs_t *port = gpio_ports[self->pin->port];
101101
uint32_t mask = self->pin->mask;
102102

103+
// Open drain must be considered output for CircuitPython API to work properly
104+
if (self->open_drain) {
105+
return DIRECTION_OUTPUT;
106+
}
107+
103108
if (self->pin->port < 4) {
104109
// Check that I/O mode is enabled and we don't have in AND out on at the same time
105110
MP_STATIC_ASSERT(!((port->en0 & mask) && (port->inen & mask) && (port->outen & mask)));
@@ -129,8 +134,30 @@ void common_hal_digitalio_digitalinout_set_value(
129134
mxc_gpio_regs_t *port = gpio_ports[self->pin->port];
130135
uint32_t mask = self->pin->mask;
131136

132-
if (dir == DIRECTION_OUTPUT) {
133-
if (value == true) {
137+
MXC_GPIO_SetVSSEL(port, self->vssel, mask);
138+
139+
if (self->open_drain) {
140+
// Open-drain can be done by setting to input mode, no pullup/pulldown
141+
// when the value is high (no sink current into GPIO)
142+
if (value) {
143+
// set to input, no pull
144+
common_hal_digitalio_digitalinout_switch_to_input(self, PULL_NONE);
145+
}
146+
else {
147+
// can't use common_hal_switch_to_output b/c it calls this function
148+
// set the GPIO to output, low
149+
if (self->pin->port == 4) {
150+
MXC_MCR->gpio4_ctrl |= GPIO4_OUTEN_MASK(mask);
151+
MXC_MCR->outen &= ~GPIO4_AFEN_MASK(mask);
152+
} else {
153+
MXC_GPIO_RevA_SetAF((mxc_gpio_reva_regs_t *)port, MXC_GPIO_FUNC_OUT, mask);
154+
}
155+
MXC_GPIO_OutClr(port, mask);
156+
}
157+
}
158+
159+
else if (dir == DIRECTION_OUTPUT) {
160+
if (value) {
134161
MXC_GPIO_OutSet(port, mask);
135162
} else {
136163
MXC_GPIO_OutClr(port, mask);
@@ -145,6 +172,10 @@ bool common_hal_digitalio_digitalinout_get_value(digitalio_digitalinout_obj_t *s
145172
mxc_gpio_regs_t *port = gpio_ports[self->pin->port];
146173
uint32_t mask = self->pin->mask;
147174

175+
if (self->open_drain) {
176+
return MXC_GPIO_InGet(port, mask) && mask;
177+
}
178+
148179
if (dir == DIRECTION_INPUT) {
149180
if (self->pin->port == 4) {
150181
return (bool)(MXC_MCR->gpio4_ctrl & GPIO4_DATAIN_MASK(mask));
@@ -155,21 +186,29 @@ bool common_hal_digitalio_digitalinout_get_value(digitalio_digitalinout_obj_t *s
155186
}
156187
}
157188

158-
/** FIXME: Implement open-drain by switching to input WITHOUT re-labeling the pin */
159189
digitalinout_result_t common_hal_digitalio_digitalinout_set_drive_mode(
160190
digitalio_digitalinout_obj_t *self, digitalio_drive_mode_t drive_mode) {
161191

162-
if (drive_mode == DRIVE_MODE_OPEN_DRAIN) {
163-
common_hal_digitalio_digitalinout_switch_to_input(self, PULL_NONE);
164-
}
165-
// On MAX32, drive mode is not configurable
166-
// and should always be push-pull unless managed by a peripheral like I2C
192+
// Check what the current value is
193+
bool value = common_hal_digitalio_digitalinout_get_value(self);
194+
self->open_drain = (drive_mode == DRIVE_MODE_OPEN_DRAIN);
195+
196+
// Re-set the value to account for different setting methods for drive types
197+
// Switch to output will both set the output config
198+
// AND set the value for the new drive type
199+
common_hal_digitalio_digitalinout_switch_to_output(self, value, drive_mode);
200+
167201
return DIGITALINOUT_OK;
168202
}
169203

170204
digitalio_drive_mode_t common_hal_digitalio_digitalinout_get_drive_mode(
171205
digitalio_digitalinout_obj_t *self) {
172-
return DRIVE_MODE_PUSH_PULL;
206+
if (self->open_drain) {
207+
return DRIVE_MODE_OPEN_DRAIN;
208+
}
209+
else {
210+
return DRIVE_MODE_PUSH_PULL;
211+
}
173212
}
174213

175214
digitalinout_result_t common_hal_digitalio_digitalinout_set_pull(
@@ -178,11 +217,31 @@ digitalinout_result_t common_hal_digitalio_digitalinout_set_pull(
178217
mxc_gpio_regs_t *port = gpio_ports[self->pin->port];
179218
uint32_t mask = self->pin->mask;
180219

181-
// padctrl registers only work in input mode
220+
// GPIO4 handling
182221
if (self->pin->port == 4) {
183-
MXC_MCR->gpio4_ctrl &= ~(GPIO4_PULLDIS_MASK(mask));
222+
switch(pull) {
223+
case PULL_NONE:
224+
// disable pullup/pulldown
225+
MXC_MCR->gpio4_ctrl |= GPIO4_PULLDIS_MASK(mask);
226+
break;
227+
case PULL_UP:
228+
// enable pullup/pulldown (clear the mask)
229+
// then set output value to 1
230+
MXC_MCR->gpio4_ctrl &= ~(GPIO4_PULLDIS_MASK(mask));
231+
MXC_MCR->gpio4_ctrl |= GPIO4_DATAOUT_MASK(mask);
232+
break;
233+
case PULL_DOWN:
234+
// enable pullup/pulldown (clear the mask)
235+
// then clear output value to 0
236+
MXC_MCR->gpio4_ctrl &= ~(GPIO4_PULLDIS_MASK(mask));
237+
MXC_MCR->gpio4_ctrl &= ~(GPIO4_DATAOUT_MASK(mask));
238+
break;
239+
default:
240+
break;
241+
}
184242
return DIGITALINOUT_OK;
185243
} else {
244+
// padctrl registers only work in input mode
186245
if ((mask & port->en0) & (mask & ~(port->outen))) {
187246
// PULL_NONE, PULL_UP, or PULL_DOWN
188247
switch (pull) {
@@ -193,10 +252,12 @@ digitalinout_result_t common_hal_digitalio_digitalinout_set_pull(
193252
case PULL_UP:
194253
port->padctrl0 |= mask;
195254
port->padctrl1 &= ~(mask);
255+
port->ps &= ~(mask);
196256
break;
197257
case PULL_DOWN:
198-
port->padctrl0 &= ~(mask);
258+
port->padctrl0 &= ~mask;
199259
port->padctrl1 |= mask;
260+
port->ps &= ~mask;
200261
break;
201262
default:
202263
break;
@@ -208,20 +269,37 @@ digitalinout_result_t common_hal_digitalio_digitalinout_set_pull(
208269
}
209270
}
210271

211-
/** FIXME: Account for GPIO4 handling here */
212272
digitalio_pull_t common_hal_digitalio_digitalinout_get_pull(
213273
digitalio_digitalinout_obj_t *self) {
214274

215-
bool pin_padctrl0 = (gpio_ports[self->pin->port]->padctrl0) & (self->pin->mask);
216-
bool pin_padctrl1 = (gpio_ports[self->pin->port]->padctrl1) & (self->pin->mask);
275+
mxc_gpio_regs_t *port = gpio_ports[self->pin->port];
276+
uint32_t mask = self->pin->mask;
217277

218-
if ((pin_padctrl0) && !(pin_padctrl1)) {
219-
return PULL_UP;
220-
} else if (!(pin_padctrl0) && pin_padctrl1) {
221-
return PULL_DOWN;
222-
} else if (!(pin_padctrl0) && !(pin_padctrl1)) {
223-
return PULL_NONE;
224-
} else {
225-
return PULL_NONE;
278+
bool pin_padctrl0 = (port->padctrl0) & (mask);
279+
bool pin_padctrl1 = (port->padctrl1) & (mask);
280+
281+
if (self->pin->port == 4) {
282+
if (MXC_MCR->gpio4_ctrl & GPIO4_PULLDIS_MASK(mask)) {
283+
return PULL_NONE;
284+
}
285+
else {
286+
if (MXC_MCR->gpio4_ctrl & GPIO4_DATAOUT_MASK(mask)) {
287+
return PULL_UP;
288+
}
289+
else {
290+
return PULL_DOWN;
291+
}
292+
}
293+
}
294+
else {
295+
if ((pin_padctrl0) && !(pin_padctrl1)) {
296+
return PULL_UP;
297+
} else if (!(pin_padctrl0) && pin_padctrl1) {
298+
return PULL_DOWN;
299+
} else if (!(pin_padctrl0) && !(pin_padctrl1)) {
300+
return PULL_NONE;
301+
} else {
302+
return PULL_NONE;
303+
}
226304
}
227305
}

ports/analog/common-hal/digitalio/DigitalInOut.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,6 @@
1212
typedef struct {
1313
mp_obj_base_t base;
1414
const mcu_pin_obj_t *pin;
15+
bool open_drain;
16+
mxc_gpio_vssel_t vssel;
1517
} digitalio_digitalinout_obj_t;

0 commit comments

Comments
 (0)