@@ -28,11 +28,13 @@ digitalinout_result_t common_hal_digitalio_digitalinout_construct(
28
28
29
29
common_hal_mcu_pin_claim (pin );
30
30
self -> pin = pin ;
31
+ self -> open_drain = false;
32
+ self -> vssel = MXC_GPIO_VSSEL_VDDIOH ;
31
33
32
34
mxc_gpio_cfg_t new_gpio_cfg = {
33
35
.port = gpio_ports [self -> pin -> port ],
34
36
.mask = (self -> pin -> mask ),
35
- .vssel = self -> pin -> level ,
37
+ .vssel = self -> vssel ,
36
38
.func = MXC_GPIO_FUNC_IN ,
37
39
.drvstr = MXC_GPIO_DRVSTR_0 ,
38
40
.pad = MXC_GPIO_PAD_NONE ,
@@ -55,6 +57,7 @@ digitalinout_result_t common_hal_digitalio_digitalinout_switch_to_input(
55
57
digitalio_digitalinout_obj_t * self , digitalio_pull_t pull ) {
56
58
mxc_gpio_regs_t * port = gpio_ports [self -> pin -> port ];
57
59
uint32_t mask = self -> pin -> mask ;
60
+
58
61
int err = E_NO_ERROR ;
59
62
60
63
if (self -> pin -> port == 4 ) {
@@ -76,21 +79,18 @@ digitalinout_result_t common_hal_digitalio_digitalinout_switch_to_output(
76
79
mxc_gpio_regs_t * port = gpio_ports [self -> pin -> port ];
77
80
uint32_t mask = self -> pin -> mask ;
78
81
82
+ self -> open_drain = (drive_mode == DRIVE_MODE_OPEN_DRAIN );
83
+
84
+ // Set GPIO(s) to output mode
79
85
if (self -> pin -> port == 4 ) {
80
- // Set GPIO(s) to output mode
81
86
MXC_MCR -> gpio4_ctrl |= GPIO4_OUTEN_MASK (mask );
82
87
MXC_MCR -> outen &= ~GPIO4_AFEN_MASK (mask );
83
88
} else {
84
89
MXC_GPIO_RevA_SetAF ((mxc_gpio_reva_regs_t * )port , MXC_GPIO_FUNC_OUT , mask );
85
90
}
91
+
86
92
common_hal_digitalio_digitalinout_set_value (self , value );
87
93
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
- }
94
94
return DIGITALINOUT_OK ;
95
95
}
96
96
@@ -100,6 +100,11 @@ digitalio_direction_t common_hal_digitalio_digitalinout_get_direction(
100
100
mxc_gpio_regs_t * port = gpio_ports [self -> pin -> port ];
101
101
uint32_t mask = self -> pin -> mask ;
102
102
103
+ // Open drain must be considered output for CircuitPython API to work properly
104
+ if (self -> open_drain ) {
105
+ return DIRECTION_OUTPUT ;
106
+ }
107
+
103
108
if (self -> pin -> port < 4 ) {
104
109
// Check that I/O mode is enabled and we don't have in AND out on at the same time
105
110
MP_STATIC_ASSERT (!((port -> en0 & mask ) && (port -> inen & mask ) && (port -> outen & mask )));
@@ -129,8 +134,30 @@ void common_hal_digitalio_digitalinout_set_value(
129
134
mxc_gpio_regs_t * port = gpio_ports [self -> pin -> port ];
130
135
uint32_t mask = self -> pin -> mask ;
131
136
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 ) {
134
161
MXC_GPIO_OutSet (port , mask );
135
162
} else {
136
163
MXC_GPIO_OutClr (port , mask );
@@ -145,6 +172,10 @@ bool common_hal_digitalio_digitalinout_get_value(digitalio_digitalinout_obj_t *s
145
172
mxc_gpio_regs_t * port = gpio_ports [self -> pin -> port ];
146
173
uint32_t mask = self -> pin -> mask ;
147
174
175
+ if (self -> open_drain ) {
176
+ return MXC_GPIO_InGet (port , mask ) && mask ;
177
+ }
178
+
148
179
if (dir == DIRECTION_INPUT ) {
149
180
if (self -> pin -> port == 4 ) {
150
181
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
155
186
}
156
187
}
157
188
158
- /** FIXME: Implement open-drain by switching to input WITHOUT re-labeling the pin */
159
189
digitalinout_result_t common_hal_digitalio_digitalinout_set_drive_mode (
160
190
digitalio_digitalinout_obj_t * self , digitalio_drive_mode_t drive_mode ) {
161
191
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
+
167
201
return DIGITALINOUT_OK ;
168
202
}
169
203
170
204
digitalio_drive_mode_t common_hal_digitalio_digitalinout_get_drive_mode (
171
205
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
+ }
173
212
}
174
213
175
214
digitalinout_result_t common_hal_digitalio_digitalinout_set_pull (
@@ -178,11 +217,31 @@ digitalinout_result_t common_hal_digitalio_digitalinout_set_pull(
178
217
mxc_gpio_regs_t * port = gpio_ports [self -> pin -> port ];
179
218
uint32_t mask = self -> pin -> mask ;
180
219
181
- // padctrl registers only work in input mode
220
+ // GPIO4 handling
182
221
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
+ }
184
242
return DIGITALINOUT_OK ;
185
243
} else {
244
+ // padctrl registers only work in input mode
186
245
if ((mask & port -> en0 ) & (mask & ~(port -> outen ))) {
187
246
// PULL_NONE, PULL_UP, or PULL_DOWN
188
247
switch (pull ) {
@@ -193,10 +252,12 @@ digitalinout_result_t common_hal_digitalio_digitalinout_set_pull(
193
252
case PULL_UP :
194
253
port -> padctrl0 |= mask ;
195
254
port -> padctrl1 &= ~(mask );
255
+ port -> ps &= ~(mask );
196
256
break ;
197
257
case PULL_DOWN :
198
- port -> padctrl0 &= ~( mask ) ;
258
+ port -> padctrl0 &= ~mask ;
199
259
port -> padctrl1 |= mask ;
260
+ port -> ps &= ~mask ;
200
261
break ;
201
262
default :
202
263
break ;
@@ -208,20 +269,37 @@ digitalinout_result_t common_hal_digitalio_digitalinout_set_pull(
208
269
}
209
270
}
210
271
211
- /** FIXME: Account for GPIO4 handling here */
212
272
digitalio_pull_t common_hal_digitalio_digitalinout_get_pull (
213
273
digitalio_digitalinout_obj_t * self ) {
214
274
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 ;
217
277
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
+ }
226
304
}
227
305
}
0 commit comments