blob: febbc15878d4f7c3b16bf0b0780b3c6d74776b9e [file] [log] [blame]
Damien George87c62502015-02-13 22:21:44 +00001/*
2 * This file is part of the Micro Python project, http://micropython.org/
3 *
4 * The MIT License (MIT)
5 *
6 * Copyright (c) 2013, 2014, 2015 Damien P. George
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to deal
10 * in the Software without restriction, including without limitation the rights
11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 * copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 * THE SOFTWARE.
25 */
26
27#include <stdio.h>
28#include <stdint.h>
29#include <string.h>
30
Damien George674bf1b2016-04-14 11:15:43 +010031#include "etshal.h"
Damien George87c62502015-02-13 22:21:44 +000032#include "c_types.h"
33#include "user_interface.h"
34#include "gpio.h"
35
36#include "py/nlr.h"
37#include "py/runtime.h"
Damien George674bf1b2016-04-14 11:15:43 +010038#include "py/gc.h"
Damien George68e222a2016-05-26 15:42:27 +010039#include "py/mphal.h"
Paul Sokolovsky18b68352017-01-01 19:02:28 +030040#include "extmod/virtpin.h"
Paul Sokolovsky8bc3fc22016-11-06 01:30:19 +030041#include "modmachine.h"
Damien George674bf1b2016-04-14 11:15:43 +010042
43#define GET_TRIGGER(phys_port) \
44 GPIO_PIN_INT_TYPE_GET(GPIO_REG_READ(GPIO_PIN_ADDR(phys_port)))
45#define SET_TRIGGER(phys_port, trig) \
46 (GPIO_REG_WRITE(GPIO_PIN_ADDR(phys_port), \
47 (GPIO_REG_READ(GPIO_PIN_ADDR(phys_port)) & ~GPIO_PIN_INT_TYPE_MASK) \
48 | GPIO_PIN_INT_TYPE_SET(trig))) \
Damien George87c62502015-02-13 22:21:44 +000049
50#define GPIO_MODE_INPUT (0)
51#define GPIO_MODE_OUTPUT (1)
Damien Georgecdad2b62015-12-28 17:42:20 +000052#define GPIO_MODE_OPEN_DRAIN (2) // synthesised
Damien George87c62502015-02-13 22:21:44 +000053#define GPIO_PULL_NONE (0)
54#define GPIO_PULL_UP (1)
Josef Gajdusek7d8edef2015-05-26 18:54:55 +020055// Removed in SDK 1.1.0
56//#define GPIO_PULL_DOWN (2)
Damien George87c62502015-02-13 22:21:44 +000057
Damien George674bf1b2016-04-14 11:15:43 +010058typedef struct _pin_irq_obj_t {
59 mp_obj_base_t base;
60 uint16_t phys_port;
61} pin_irq_obj_t;
62
Damien Georgea2d5d842016-04-22 10:04:12 +010063const pyb_pin_obj_t pyb_pin_obj[16 + 1] = {
Damien Georgea9a732a2016-04-13 22:38:44 +010064 {{&pyb_pin_type}, 0, FUNC_GPIO0, PERIPHS_IO_MUX_GPIO0_U},
65 {{&pyb_pin_type}, 1, FUNC_GPIO1, PERIPHS_IO_MUX_U0TXD_U},
66 {{&pyb_pin_type}, 2, FUNC_GPIO2, PERIPHS_IO_MUX_GPIO2_U},
67 {{&pyb_pin_type}, 3, FUNC_GPIO3, PERIPHS_IO_MUX_U0RXD_U},
68 {{&pyb_pin_type}, 4, FUNC_GPIO4, PERIPHS_IO_MUX_GPIO4_U},
69 {{&pyb_pin_type}, 5, FUNC_GPIO5, PERIPHS_IO_MUX_GPIO5_U},
Damien Georged9d40812016-04-13 22:45:51 +010070 {{NULL}, 0, 0, 0},
71 {{NULL}, 0, 0, 0},
72 {{NULL}, 0, 0, 0},
Damien Georgea9a732a2016-04-13 22:38:44 +010073 {{&pyb_pin_type}, 9, FUNC_GPIO9, PERIPHS_IO_MUX_SD_DATA2_U},
74 {{&pyb_pin_type}, 10, FUNC_GPIO10, PERIPHS_IO_MUX_SD_DATA3_U},
Damien Georged9d40812016-04-13 22:45:51 +010075 {{NULL}, 0, 0, 0},
Damien Georgea9a732a2016-04-13 22:38:44 +010076 {{&pyb_pin_type}, 12, FUNC_GPIO12, PERIPHS_IO_MUX_MTDI_U},
77 {{&pyb_pin_type}, 13, FUNC_GPIO13, PERIPHS_IO_MUX_MTCK_U},
78 {{&pyb_pin_type}, 14, FUNC_GPIO14, PERIPHS_IO_MUX_MTMS_U},
79 {{&pyb_pin_type}, 15, FUNC_GPIO15, PERIPHS_IO_MUX_MTDO_U},
Paul Sokolovskyeb247ea2016-01-08 22:04:00 +020080 // GPIO16 is special, belongs to different register set, and
81 // otherwise handled specially.
Damien Georgea9a732a2016-04-13 22:38:44 +010082 {{&pyb_pin_type}, 16, -1, -1},
Damien George87c62502015-02-13 22:21:44 +000083};
84
Paul Sokolovskyeb247ea2016-01-08 22:04:00 +020085STATIC uint8_t pin_mode[16 + 1];
Damien Georgecdad2b62015-12-28 17:42:20 +000086
Damien George674bf1b2016-04-14 11:15:43 +010087// forward declaration
88STATIC const pin_irq_obj_t pin_irq_obj[16];
89
Damien George2507c832017-02-15 17:45:53 +110090// whether the irq is hard or soft
91STATIC bool pin_irq_is_hard[16];
92
Damien George674bf1b2016-04-14 11:15:43 +010093void pin_init0(void) {
94 ETS_GPIO_INTR_DISABLE();
95 ETS_GPIO_INTR_ATTACH(pin_intr_handler_iram, NULL);
96 // disable all interrupts
97 memset(&MP_STATE_PORT(pin_irq_handler)[0], 0, 16 * sizeof(mp_obj_t));
Damien Georgeb16c3542017-03-21 15:13:15 +110098 memset(pin_irq_is_hard, 0, sizeof(pin_irq_is_hard));
Damien George674bf1b2016-04-14 11:15:43 +010099 for (int p = 0; p < 16; ++p) {
100 GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, 1 << p);
101 SET_TRIGGER(p, 0);
102 }
103 ETS_GPIO_INTR_ENABLE();
104}
105
106void pin_intr_handler(uint32_t status) {
Damien George1b7d6722017-02-15 17:45:36 +1100107 mp_sched_lock();
Damien George674bf1b2016-04-14 11:15:43 +0100108 gc_lock();
109 status &= 0xffff;
110 for (int p = 0; status; ++p, status >>= 1) {
111 if (status & 1) {
112 mp_obj_t handler = MP_STATE_PORT(pin_irq_handler)[p];
113 if (handler != MP_OBJ_NULL) {
Damien George2507c832017-02-15 17:45:53 +1100114 if (pin_irq_is_hard[p]) {
115 mp_call_function_1_protected(handler, MP_OBJ_FROM_PTR(&pyb_pin_obj[p]));
116 } else {
117 mp_sched_schedule(handler, MP_OBJ_FROM_PTR(&pyb_pin_obj[p]));
118 }
Damien George674bf1b2016-04-14 11:15:43 +0100119 }
120 }
121 }
122 gc_unlock();
Damien George1b7d6722017-02-15 17:45:36 +1100123 mp_sched_unlock();
Damien George674bf1b2016-04-14 11:15:43 +0100124}
125
Damien George7059c8c2016-02-11 11:41:58 +0000126pyb_pin_obj_t *mp_obj_get_pin_obj(mp_obj_t pin_in) {
Damien George342d9032015-12-29 00:19:23 +0000127 if (mp_obj_get_type(pin_in) != &pyb_pin_type) {
128 nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "expecting a pin"));
129 }
130 pyb_pin_obj_t *self = pin_in;
Damien George7059c8c2016-02-11 11:41:58 +0000131 return self;
132}
133
134uint mp_obj_get_pin(mp_obj_t pin_in) {
135 return mp_obj_get_pin_obj(pin_in)->phys_port;
Damien George342d9032015-12-29 00:19:23 +0000136}
137
Damien George68e222a2016-05-26 15:42:27 +0100138void mp_hal_pin_input(mp_hal_pin_obj_t pin_id) {
139 pin_mode[pin_id] = GPIO_MODE_INPUT;
140 if (pin_id == 16) {
141 WRITE_PERI_REG(PAD_XPD_DCDC_CONF, (READ_PERI_REG(PAD_XPD_DCDC_CONF) & 0xffffffbc) | 1);
142 WRITE_PERI_REG(RTC_GPIO_CONF, READ_PERI_REG(RTC_GPIO_CONF) & ~1);
143 WRITE_PERI_REG(RTC_GPIO_ENABLE, (READ_PERI_REG(RTC_GPIO_ENABLE) & ~1)); // input
144 } else {
145 const pyb_pin_obj_t *self = &pyb_pin_obj[pin_id];
146 PIN_FUNC_SELECT(self->periph, self->func);
147 PIN_PULLUP_DIS(self->periph);
148 gpio_output_set(0, 0, 0, 1 << self->phys_port);
149 }
150}
151
152void mp_hal_pin_output(mp_hal_pin_obj_t pin_id) {
153 pin_mode[pin_id] = GPIO_MODE_OUTPUT;
154 if (pin_id == 16) {
155 WRITE_PERI_REG(PAD_XPD_DCDC_CONF, (READ_PERI_REG(PAD_XPD_DCDC_CONF) & 0xffffffbc) | 1);
156 WRITE_PERI_REG(RTC_GPIO_CONF, READ_PERI_REG(RTC_GPIO_CONF) & ~1);
157 WRITE_PERI_REG(RTC_GPIO_ENABLE, (READ_PERI_REG(RTC_GPIO_ENABLE) & ~1) | 1); // output
158 } else {
159 const pyb_pin_obj_t *self = &pyb_pin_obj[pin_id];
160 PIN_FUNC_SELECT(self->periph, self->func);
161 PIN_PULLUP_DIS(self->periph);
162 gpio_output_set(0, 0, 1 << self->phys_port, 0);
163 }
164}
165
Damien George46b849a2017-06-22 16:39:09 +1000166void mp_hal_pin_open_drain(mp_hal_pin_obj_t pin_id) {
167 const pyb_pin_obj_t *pin = &pyb_pin_obj[pin_id];
168
169 if (pin->phys_port == 16) {
170 // configure GPIO16 as input with output register holding 0
171 WRITE_PERI_REG(PAD_XPD_DCDC_CONF, (READ_PERI_REG(PAD_XPD_DCDC_CONF) & 0xffffffbc) | 1);
172 WRITE_PERI_REG(RTC_GPIO_CONF, READ_PERI_REG(RTC_GPIO_CONF) & ~1);
173 WRITE_PERI_REG(RTC_GPIO_ENABLE, (READ_PERI_REG(RTC_GPIO_ENABLE) & ~1)); // input
174 WRITE_PERI_REG(RTC_GPIO_OUT, (READ_PERI_REG(RTC_GPIO_OUT) & ~1)); // out=0
175 return;
176 }
177
178 ETS_GPIO_INTR_DISABLE();
179 PIN_FUNC_SELECT(pin->periph, pin->func);
180 GPIO_REG_WRITE(GPIO_PIN_ADDR(GPIO_ID_PIN(pin->phys_port)),
181 GPIO_REG_READ(GPIO_PIN_ADDR(GPIO_ID_PIN(pin->phys_port)))
182 | GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_ENABLE)); // open drain
183 GPIO_REG_WRITE(GPIO_ENABLE_ADDRESS,
184 GPIO_REG_READ(GPIO_ENABLE_ADDRESS) | (1 << pin->phys_port));
185 ETS_GPIO_INTR_ENABLE();
186}
187
Damien George342d9032015-12-29 00:19:23 +0000188int pin_get(uint pin) {
Paul Sokolovskyeb247ea2016-01-08 22:04:00 +0200189 if (pin == 16) {
190 return READ_PERI_REG(RTC_GPIO_IN_DATA) & 1;
191 }
Damien George342d9032015-12-29 00:19:23 +0000192 return GPIO_INPUT_GET(pin);
193}
194
195void pin_set(uint pin, int value) {
Paul Sokolovskyeb247ea2016-01-08 22:04:00 +0200196 if (pin == 16) {
197 int out_en = (pin_mode[pin] == GPIO_MODE_OUTPUT);
198 WRITE_PERI_REG(PAD_XPD_DCDC_CONF, (READ_PERI_REG(PAD_XPD_DCDC_CONF) & 0xffffffbc) | 1);
199 WRITE_PERI_REG(RTC_GPIO_CONF, READ_PERI_REG(RTC_GPIO_CONF) & ~1);
200 WRITE_PERI_REG(RTC_GPIO_ENABLE, (READ_PERI_REG(RTC_GPIO_ENABLE) & ~1) | out_en);
201 WRITE_PERI_REG(RTC_GPIO_OUT, (READ_PERI_REG(RTC_GPIO_OUT) & ~1) | value);
202 return;
203 }
204
Damien Georgecdad2b62015-12-28 17:42:20 +0000205 uint32_t enable = 0;
206 uint32_t disable = 0;
Damien George342d9032015-12-29 00:19:23 +0000207 switch (pin_mode[pin]) {
Damien Georgecdad2b62015-12-28 17:42:20 +0000208 case GPIO_MODE_INPUT:
209 value = -1;
210 disable = 1;
211 break;
212
213 case GPIO_MODE_OUTPUT:
214 enable = 1;
215 break;
216
217 case GPIO_MODE_OPEN_DRAIN:
218 if (value == -1) {
219 return;
220 } else if (value == 0) {
221 enable = 1;
222 } else {
223 value = -1;
224 disable = 1;
225 }
226 break;
227 }
228
229 enable <<= pin;
230 disable <<= pin;
231 if (value == -1) {
232 gpio_output_set(0, 0, enable, disable);
233 } else {
234 gpio_output_set(value << pin, (1 - value) << pin, enable, disable);
235 }
236}
237
Damien George7f9d1d62015-04-09 23:56:15 +0100238STATIC void pyb_pin_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
Damien George87c62502015-02-13 22:21:44 +0000239 pyb_pin_obj_t *self = self_in;
240
241 // pin name
Damien Georgea9a732a2016-04-13 22:38:44 +0100242 mp_printf(print, "Pin(%u)", self->phys_port);
Damien George87c62502015-02-13 22:21:44 +0000243}
244
Damien George8a3e9032016-05-03 13:13:56 +0100245// pin.init(mode, pull=None, *, value)
Damien George87c62502015-02-13 22:21:44 +0000246STATIC mp_obj_t pyb_pin_obj_init_helper(pyb_pin_obj_t *self, mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
Damien George9df6b3a2016-05-03 12:44:28 +0100247 enum { ARG_mode, ARG_pull, ARG_value };
Damien George87c62502015-02-13 22:21:44 +0000248 static const mp_arg_t allowed_args[] = {
249 { MP_QSTR_mode, MP_ARG_REQUIRED | MP_ARG_INT },
Damien George8a3e9032016-05-03 13:13:56 +0100250 { MP_QSTR_pull, MP_ARG_OBJ, {.u_obj = mp_const_none}},
Damien Georgecdad2b62015-12-28 17:42:20 +0000251 { MP_QSTR_value, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}},
Damien George87c62502015-02-13 22:21:44 +0000252 };
253
254 // parse args
Damien George9df6b3a2016-05-03 12:44:28 +0100255 mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
256 mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
Damien George87c62502015-02-13 22:21:44 +0000257
258 // get io mode
Damien George9df6b3a2016-05-03 12:44:28 +0100259 uint mode = args[ARG_mode].u_int;
Damien George87c62502015-02-13 22:21:44 +0000260
261 // get pull mode
Damien George8a3e9032016-05-03 13:13:56 +0100262 uint pull = GPIO_PULL_NONE;
263 if (args[ARG_pull].u_obj != mp_const_none) {
264 pull = mp_obj_get_int(args[ARG_pull].u_obj);
265 }
Damien Georgecdad2b62015-12-28 17:42:20 +0000266
267 // get initial value
268 int value;
Damien George9df6b3a2016-05-03 12:44:28 +0100269 if (args[ARG_value].u_obj == MP_OBJ_NULL) {
Damien Georgecdad2b62015-12-28 17:42:20 +0000270 value = -1;
271 } else {
Damien George9df6b3a2016-05-03 12:44:28 +0100272 value = mp_obj_is_true(args[ARG_value].u_obj);
Damien Georgecdad2b62015-12-28 17:42:20 +0000273 }
274
275 // save the mode
276 pin_mode[self->phys_port] = mode;
Damien George87c62502015-02-13 22:21:44 +0000277
278 // configure the GPIO as requested
Paul Sokolovskyeb247ea2016-01-08 22:04:00 +0200279 if (self->phys_port == 16) {
Damien George8a15e0b2016-08-10 12:45:40 +1000280 // only pull-down seems to be supported by the hardware, and
281 // we only expose pull-up behaviour in software
282 if (pull != GPIO_PULL_NONE) {
283 nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Pin(16) doesn't support pull"));
284 }
Paul Sokolovskyeb247ea2016-01-08 22:04:00 +0200285 } else {
286 PIN_FUNC_SELECT(self->periph, self->func);
287 #if 0
288 // Removed in SDK 1.1.0
289 if ((pull & GPIO_PULL_DOWN) == 0) {
290 PIN_PULLDWN_DIS(self->periph);
291 }
292 #endif
293 if ((pull & GPIO_PULL_UP) == 0) {
294 PIN_PULLUP_DIS(self->periph);
295 }
296 #if 0
297 if ((pull & GPIO_PULL_DOWN) != 0) {
298 PIN_PULLDWN_EN(self->periph);
299 }
300 #endif
301 if ((pull & GPIO_PULL_UP) != 0) {
302 PIN_PULLUP_EN(self->periph);
303 }
Damien George87c62502015-02-13 22:21:44 +0000304 }
305
Damien George342d9032015-12-29 00:19:23 +0000306 pin_set(self->phys_port, value);
Damien George87c62502015-02-13 22:21:44 +0000307
308 return mp_const_none;
309}
310
311// constructor(id, ...)
Paul Sokolovsky605ff912017-04-11 00:12:20 +0300312mp_obj_t mp_pin_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
Damien George87c62502015-02-13 22:21:44 +0000313 mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true);
314
Damien Georged9d40812016-04-13 22:45:51 +0100315 // get the wanted pin object
Damien George87c62502015-02-13 22:21:44 +0000316 int wanted_pin = mp_obj_get_int(args[0]);
317 pyb_pin_obj_t *pin = NULL;
Damien Georged9d40812016-04-13 22:45:51 +0100318 if (0 <= wanted_pin && wanted_pin < MP_ARRAY_SIZE(pyb_pin_obj)) {
319 pin = (pyb_pin_obj_t*)&pyb_pin_obj[wanted_pin];
Damien George87c62502015-02-13 22:21:44 +0000320 }
Damien Georged9d40812016-04-13 22:45:51 +0100321 if (pin == NULL || pin->base.type == NULL) {
Damien George87c62502015-02-13 22:21:44 +0000322 nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "invalid pin"));
323 }
324
325 if (n_args > 1 || n_kw > 0) {
326 // pin mode given, so configure this GPIO
327 mp_map_t kw_args;
328 mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
329 pyb_pin_obj_init_helper(pin, n_args - 1, args + 1, &kw_args);
330 }
331
332 return (mp_obj_t)pin;
333}
334
Damien Georgecdad2b62015-12-28 17:42:20 +0000335// fast method for getting/setting pin value
Paul Sokolovskyeac22e22017-01-04 16:10:42 +0300336STATIC mp_obj_t pyb_pin_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
Damien Georgecdad2b62015-12-28 17:42:20 +0000337 mp_arg_check_num(n_args, n_kw, 0, 1, false);
338 pyb_pin_obj_t *self = self_in;
339 if (n_args == 0) {
340 // get pin
Damien Georgeb203c172016-08-10 12:44:47 +1000341 return MP_OBJ_NEW_SMALL_INT(pin_get(self->phys_port));
Damien Georgecdad2b62015-12-28 17:42:20 +0000342 } else {
343 // set pin
Damien George342d9032015-12-29 00:19:23 +0000344 pin_set(self->phys_port, mp_obj_is_true(args[0]));
Damien Georgecdad2b62015-12-28 17:42:20 +0000345 return mp_const_none;
346 }
347}
348
Damien George87c62502015-02-13 22:21:44 +0000349// pin.init(mode, pull)
350STATIC mp_obj_t pyb_pin_obj_init(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
351 return pyb_pin_obj_init_helper(args[0], n_args - 1, args + 1, kw_args);
352}
353MP_DEFINE_CONST_FUN_OBJ_KW(pyb_pin_init_obj, 1, pyb_pin_obj_init);
354
355// pin.value([value])
356STATIC mp_obj_t pyb_pin_value(mp_uint_t n_args, const mp_obj_t *args) {
Damien Georgecdad2b62015-12-28 17:42:20 +0000357 return pyb_pin_call(args[0], n_args - 1, 0, args + 1);
Damien George87c62502015-02-13 22:21:44 +0000358}
359STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_pin_value_obj, 1, 2, pyb_pin_value);
360
Paul Sokolovskybcf31a32017-04-16 11:14:48 +0300361STATIC mp_obj_t pyb_pin_off(mp_obj_t self_in) {
Damien George87c62502015-02-13 22:21:44 +0000362 pyb_pin_obj_t *self = self_in;
Damien George342d9032015-12-29 00:19:23 +0000363 pin_set(self->phys_port, 0);
Damien George87c62502015-02-13 22:21:44 +0000364 return mp_const_none;
365}
Paul Sokolovskybcf31a32017-04-16 11:14:48 +0300366STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_pin_off_obj, pyb_pin_off);
Damien George87c62502015-02-13 22:21:44 +0000367
Paul Sokolovskybcf31a32017-04-16 11:14:48 +0300368STATIC mp_obj_t pyb_pin_on(mp_obj_t self_in) {
Damien George87c62502015-02-13 22:21:44 +0000369 pyb_pin_obj_t *self = self_in;
Damien George342d9032015-12-29 00:19:23 +0000370 pin_set(self->phys_port, 1);
Damien George87c62502015-02-13 22:21:44 +0000371 return mp_const_none;
372}
Paul Sokolovskybcf31a32017-04-16 11:14:48 +0300373STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_pin_on_obj, pyb_pin_on);
Damien George87c62502015-02-13 22:21:44 +0000374
Damien George9ee46412017-03-16 17:15:34 +1100375// pin.irq(handler=None, trigger=IRQ_FALLING|IRQ_RISING, hard=False)
Damien George8e130fc2016-05-03 13:47:10 +0100376STATIC mp_obj_t pyb_pin_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
Damien George9ee46412017-03-16 17:15:34 +1100377 enum { ARG_handler, ARG_trigger, ARG_hard };
Damien George8e130fc2016-05-03 13:47:10 +0100378 static const mp_arg_t allowed_args[] = {
Damien George9ee46412017-03-16 17:15:34 +1100379 { MP_QSTR_handler, MP_ARG_OBJ, {.u_obj = mp_const_none} },
380 { MP_QSTR_trigger, MP_ARG_INT, {.u_int = GPIO_PIN_INTR_POSEDGE | GPIO_PIN_INTR_NEGEDGE} },
381 { MP_QSTR_hard, MP_ARG_BOOL, {.u_bool = false} },
Damien George8e130fc2016-05-03 13:47:10 +0100382 };
383 pyb_pin_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
384 mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
385 mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
386
Damien George674bf1b2016-04-14 11:15:43 +0100387 if (self->phys_port >= 16) {
388 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "pin does not have IRQ capabilities"));
389 }
390
Damien George5d05ff12017-03-21 15:28:31 +1100391 if (n_args > 1 || kw_args->used != 0) {
Damien George674bf1b2016-04-14 11:15:43 +0100392 // configure irq
Damien George8e130fc2016-05-03 13:47:10 +0100393 mp_obj_t handler = args[ARG_handler].u_obj;
Damien George9ee46412017-03-16 17:15:34 +1100394 uint32_t trigger = args[ARG_trigger].u_int;
Damien George674bf1b2016-04-14 11:15:43 +0100395 if (handler == mp_const_none) {
396 handler = MP_OBJ_NULL;
Damien George9ee46412017-03-16 17:15:34 +1100397 trigger = 0;
Damien George674bf1b2016-04-14 11:15:43 +0100398 }
399 ETS_GPIO_INTR_DISABLE();
400 MP_STATE_PORT(pin_irq_handler)[self->phys_port] = handler;
Damien George2507c832017-02-15 17:45:53 +1100401 pin_irq_is_hard[self->phys_port] = args[ARG_hard].u_bool;
Damien George9ee46412017-03-16 17:15:34 +1100402 SET_TRIGGER(self->phys_port, trigger);
Damien George674bf1b2016-04-14 11:15:43 +0100403 GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, 1 << self->phys_port);
404 ETS_GPIO_INTR_ENABLE();
405 }
406
407 // return the irq object
408 return MP_OBJ_FROM_PTR(&pin_irq_obj[self->phys_port]);
409}
Damien George8e130fc2016-05-03 13:47:10 +0100410STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_pin_irq_obj, 1, pyb_pin_irq);
Damien George674bf1b2016-04-14 11:15:43 +0100411
Paul Sokolovsky18b68352017-01-01 19:02:28 +0300412STATIC mp_uint_t pin_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode);
413STATIC mp_uint_t pin_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) {
414 (void)errcode;
415 pyb_pin_obj_t *self = self_in;
416
417 switch (request) {
418 case MP_PIN_READ: {
419 return pin_get(self->phys_port);
420 }
421 case MP_PIN_WRITE: {
422 pin_set(self->phys_port, arg);
423 return 0;
424 }
425 }
426 return -1;
427}
428
Damien George87c62502015-02-13 22:21:44 +0000429STATIC const mp_map_elem_t pyb_pin_locals_dict_table[] = {
430 // instance methods
431 { MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&pyb_pin_init_obj },
432 { MP_OBJ_NEW_QSTR(MP_QSTR_value), (mp_obj_t)&pyb_pin_value_obj },
Paul Sokolovskybcf31a32017-04-16 11:14:48 +0300433 { MP_OBJ_NEW_QSTR(MP_QSTR_off), (mp_obj_t)&pyb_pin_off_obj },
434 { MP_OBJ_NEW_QSTR(MP_QSTR_on), (mp_obj_t)&pyb_pin_on_obj },
Damien George674bf1b2016-04-14 11:15:43 +0100435 { MP_OBJ_NEW_QSTR(MP_QSTR_irq), (mp_obj_t)&pyb_pin_irq_obj },
Damien George87c62502015-02-13 22:21:44 +0000436
437 // class constants
438 { MP_OBJ_NEW_QSTR(MP_QSTR_IN), MP_OBJ_NEW_SMALL_INT(GPIO_MODE_INPUT) },
Damien Georgecdad2b62015-12-28 17:42:20 +0000439 { MP_OBJ_NEW_QSTR(MP_QSTR_OUT), MP_OBJ_NEW_SMALL_INT(GPIO_MODE_OUTPUT) },
440 { MP_OBJ_NEW_QSTR(MP_QSTR_OPEN_DRAIN), MP_OBJ_NEW_SMALL_INT(GPIO_MODE_OPEN_DRAIN) },
Damien George87c62502015-02-13 22:21:44 +0000441 { MP_OBJ_NEW_QSTR(MP_QSTR_PULL_UP), MP_OBJ_NEW_SMALL_INT(GPIO_PULL_UP) },
Josef Gajdusek7d8edef2015-05-26 18:54:55 +0200442 //{ MP_OBJ_NEW_QSTR(MP_QSTR_PULL_DOWN), MP_OBJ_NEW_SMALL_INT(GPIO_PULL_DOWN) },
Damien George674bf1b2016-04-14 11:15:43 +0100443
444 // IRG triggers, can be or'd together
445 { MP_OBJ_NEW_QSTR(MP_QSTR_IRQ_RISING), MP_OBJ_NEW_SMALL_INT(GPIO_PIN_INTR_POSEDGE) },
446 { MP_OBJ_NEW_QSTR(MP_QSTR_IRQ_FALLING), MP_OBJ_NEW_SMALL_INT(GPIO_PIN_INTR_NEGEDGE) },
Damien George87c62502015-02-13 22:21:44 +0000447};
448
449STATIC MP_DEFINE_CONST_DICT(pyb_pin_locals_dict, pyb_pin_locals_dict_table);
450
Paul Sokolovsky18b68352017-01-01 19:02:28 +0300451STATIC const mp_pin_p_t pin_pin_p = {
452 .ioctl = pin_ioctl,
453};
454
Damien George87c62502015-02-13 22:21:44 +0000455const mp_obj_type_t pyb_pin_type = {
456 { &mp_type_type },
457 .name = MP_QSTR_Pin,
458 .print = pyb_pin_print,
Paul Sokolovsky605ff912017-04-11 00:12:20 +0300459 .make_new = mp_pin_make_new,
Damien Georgecdad2b62015-12-28 17:42:20 +0000460 .call = pyb_pin_call,
Paul Sokolovsky18b68352017-01-01 19:02:28 +0300461 .protocol = &pin_pin_p,
Damien George87c62502015-02-13 22:21:44 +0000462 .locals_dict = (mp_obj_t)&pyb_pin_locals_dict,
463};
Damien George674bf1b2016-04-14 11:15:43 +0100464
465/******************************************************************************/
466// Pin IRQ object
467
468STATIC const mp_obj_type_t pin_irq_type;
469
470STATIC const pin_irq_obj_t pin_irq_obj[16] = {
471 {{&pin_irq_type}, 0},
472 {{&pin_irq_type}, 1},
473 {{&pin_irq_type}, 2},
474 {{&pin_irq_type}, 3},
475 {{&pin_irq_type}, 4},
476 {{&pin_irq_type}, 5},
477 {{&pin_irq_type}, 6},
478 {{&pin_irq_type}, 7},
479 {{&pin_irq_type}, 8},
480 {{&pin_irq_type}, 9},
481 {{&pin_irq_type}, 10},
482 {{&pin_irq_type}, 11},
483 {{&pin_irq_type}, 12},
484 {{&pin_irq_type}, 13},
485 {{&pin_irq_type}, 14},
486 {{&pin_irq_type}, 15},
487};
488
489STATIC mp_obj_t pin_irq_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
490 pin_irq_obj_t *self = self_in;
491 mp_arg_check_num(n_args, n_kw, 0, 0, false);
492 pin_intr_handler(1 << self->phys_port);
493 return mp_const_none;
494}
495
496STATIC mp_obj_t pin_irq_trigger(size_t n_args, const mp_obj_t *args) {
497 pin_irq_obj_t *self = args[0];
498 uint32_t orig_trig = GET_TRIGGER(self->phys_port);
499 if (n_args == 2) {
500 // set trigger
501 SET_TRIGGER(self->phys_port, mp_obj_get_int(args[1]));
502 }
503 // return original trigger value
504 return MP_OBJ_NEW_SMALL_INT(orig_trig);
505}
506STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pin_irq_trigger_obj, 1, 2, pin_irq_trigger);
507
508STATIC const mp_rom_map_elem_t pin_irq_locals_dict_table[] = {
509 { MP_ROM_QSTR(MP_QSTR_trigger), MP_ROM_PTR(&pin_irq_trigger_obj) },
510};
511
512STATIC MP_DEFINE_CONST_DICT(pin_irq_locals_dict, pin_irq_locals_dict_table);
513
514STATIC const mp_obj_type_t pin_irq_type = {
515 { &mp_type_type },
516 .name = MP_QSTR_IRQ,
517 .call = pin_irq_call,
518 .locals_dict = (mp_obj_dict_t*)&pin_irq_locals_dict,
519};