blob: 385551578eb28ffa790a1976e6677d0b783da314 [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 George342d9032015-12-29 00:19:23 +0000166int pin_get(uint pin) {
Paul Sokolovskyeb247ea2016-01-08 22:04:00 +0200167 if (pin == 16) {
168 return READ_PERI_REG(RTC_GPIO_IN_DATA) & 1;
169 }
Damien George342d9032015-12-29 00:19:23 +0000170 return GPIO_INPUT_GET(pin);
171}
172
173void pin_set(uint pin, int value) {
Paul Sokolovskyeb247ea2016-01-08 22:04:00 +0200174 if (pin == 16) {
175 int out_en = (pin_mode[pin] == GPIO_MODE_OUTPUT);
176 WRITE_PERI_REG(PAD_XPD_DCDC_CONF, (READ_PERI_REG(PAD_XPD_DCDC_CONF) & 0xffffffbc) | 1);
177 WRITE_PERI_REG(RTC_GPIO_CONF, READ_PERI_REG(RTC_GPIO_CONF) & ~1);
178 WRITE_PERI_REG(RTC_GPIO_ENABLE, (READ_PERI_REG(RTC_GPIO_ENABLE) & ~1) | out_en);
179 WRITE_PERI_REG(RTC_GPIO_OUT, (READ_PERI_REG(RTC_GPIO_OUT) & ~1) | value);
180 return;
181 }
182
Damien Georgecdad2b62015-12-28 17:42:20 +0000183 uint32_t enable = 0;
184 uint32_t disable = 0;
Damien George342d9032015-12-29 00:19:23 +0000185 switch (pin_mode[pin]) {
Damien Georgecdad2b62015-12-28 17:42:20 +0000186 case GPIO_MODE_INPUT:
187 value = -1;
188 disable = 1;
189 break;
190
191 case GPIO_MODE_OUTPUT:
192 enable = 1;
193 break;
194
195 case GPIO_MODE_OPEN_DRAIN:
196 if (value == -1) {
197 return;
198 } else if (value == 0) {
199 enable = 1;
200 } else {
201 value = -1;
202 disable = 1;
203 }
204 break;
205 }
206
207 enable <<= pin;
208 disable <<= pin;
209 if (value == -1) {
210 gpio_output_set(0, 0, enable, disable);
211 } else {
212 gpio_output_set(value << pin, (1 - value) << pin, enable, disable);
213 }
214}
215
Damien George7f9d1d62015-04-09 23:56:15 +0100216STATIC 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 +0000217 pyb_pin_obj_t *self = self_in;
218
219 // pin name
Damien Georgea9a732a2016-04-13 22:38:44 +0100220 mp_printf(print, "Pin(%u)", self->phys_port);
Damien George87c62502015-02-13 22:21:44 +0000221}
222
Damien George8a3e9032016-05-03 13:13:56 +0100223// pin.init(mode, pull=None, *, value)
Damien George87c62502015-02-13 22:21:44 +0000224STATIC 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 +0100225 enum { ARG_mode, ARG_pull, ARG_value };
Damien George87c62502015-02-13 22:21:44 +0000226 static const mp_arg_t allowed_args[] = {
227 { MP_QSTR_mode, MP_ARG_REQUIRED | MP_ARG_INT },
Damien George8a3e9032016-05-03 13:13:56 +0100228 { MP_QSTR_pull, MP_ARG_OBJ, {.u_obj = mp_const_none}},
Damien Georgecdad2b62015-12-28 17:42:20 +0000229 { MP_QSTR_value, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}},
Damien George87c62502015-02-13 22:21:44 +0000230 };
231
232 // parse args
Damien George9df6b3a2016-05-03 12:44:28 +0100233 mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
234 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 +0000235
236 // get io mode
Damien George9df6b3a2016-05-03 12:44:28 +0100237 uint mode = args[ARG_mode].u_int;
Damien George87c62502015-02-13 22:21:44 +0000238
239 // get pull mode
Damien George8a3e9032016-05-03 13:13:56 +0100240 uint pull = GPIO_PULL_NONE;
241 if (args[ARG_pull].u_obj != mp_const_none) {
242 pull = mp_obj_get_int(args[ARG_pull].u_obj);
243 }
Damien Georgecdad2b62015-12-28 17:42:20 +0000244
245 // get initial value
246 int value;
Damien George9df6b3a2016-05-03 12:44:28 +0100247 if (args[ARG_value].u_obj == MP_OBJ_NULL) {
Damien Georgecdad2b62015-12-28 17:42:20 +0000248 value = -1;
249 } else {
Damien George9df6b3a2016-05-03 12:44:28 +0100250 value = mp_obj_is_true(args[ARG_value].u_obj);
Damien Georgecdad2b62015-12-28 17:42:20 +0000251 }
252
253 // save the mode
254 pin_mode[self->phys_port] = mode;
Damien George87c62502015-02-13 22:21:44 +0000255
256 // configure the GPIO as requested
Paul Sokolovskyeb247ea2016-01-08 22:04:00 +0200257 if (self->phys_port == 16) {
Damien George8a15e0b2016-08-10 12:45:40 +1000258 // only pull-down seems to be supported by the hardware, and
259 // we only expose pull-up behaviour in software
260 if (pull != GPIO_PULL_NONE) {
261 nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Pin(16) doesn't support pull"));
262 }
Paul Sokolovskyeb247ea2016-01-08 22:04:00 +0200263 } else {
264 PIN_FUNC_SELECT(self->periph, self->func);
265 #if 0
266 // Removed in SDK 1.1.0
267 if ((pull & GPIO_PULL_DOWN) == 0) {
268 PIN_PULLDWN_DIS(self->periph);
269 }
270 #endif
271 if ((pull & GPIO_PULL_UP) == 0) {
272 PIN_PULLUP_DIS(self->periph);
273 }
274 #if 0
275 if ((pull & GPIO_PULL_DOWN) != 0) {
276 PIN_PULLDWN_EN(self->periph);
277 }
278 #endif
279 if ((pull & GPIO_PULL_UP) != 0) {
280 PIN_PULLUP_EN(self->periph);
281 }
Damien George87c62502015-02-13 22:21:44 +0000282 }
283
Damien George342d9032015-12-29 00:19:23 +0000284 pin_set(self->phys_port, value);
Damien George87c62502015-02-13 22:21:44 +0000285
286 return mp_const_none;
287}
288
289// constructor(id, ...)
Paul Sokolovsky605ff912017-04-11 00:12:20 +0300290mp_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 +0000291 mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true);
292
Damien Georged9d40812016-04-13 22:45:51 +0100293 // get the wanted pin object
Damien George87c62502015-02-13 22:21:44 +0000294 int wanted_pin = mp_obj_get_int(args[0]);
295 pyb_pin_obj_t *pin = NULL;
Damien Georged9d40812016-04-13 22:45:51 +0100296 if (0 <= wanted_pin && wanted_pin < MP_ARRAY_SIZE(pyb_pin_obj)) {
297 pin = (pyb_pin_obj_t*)&pyb_pin_obj[wanted_pin];
Damien George87c62502015-02-13 22:21:44 +0000298 }
Damien Georged9d40812016-04-13 22:45:51 +0100299 if (pin == NULL || pin->base.type == NULL) {
Damien George87c62502015-02-13 22:21:44 +0000300 nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "invalid pin"));
301 }
302
303 if (n_args > 1 || n_kw > 0) {
304 // pin mode given, so configure this GPIO
305 mp_map_t kw_args;
306 mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
307 pyb_pin_obj_init_helper(pin, n_args - 1, args + 1, &kw_args);
308 }
309
310 return (mp_obj_t)pin;
311}
312
Damien Georgecdad2b62015-12-28 17:42:20 +0000313// fast method for getting/setting pin value
Paul Sokolovskyeac22e22017-01-04 16:10:42 +0300314STATIC 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 +0000315 mp_arg_check_num(n_args, n_kw, 0, 1, false);
316 pyb_pin_obj_t *self = self_in;
317 if (n_args == 0) {
318 // get pin
Damien Georgeb203c172016-08-10 12:44:47 +1000319 return MP_OBJ_NEW_SMALL_INT(pin_get(self->phys_port));
Damien Georgecdad2b62015-12-28 17:42:20 +0000320 } else {
321 // set pin
Damien George342d9032015-12-29 00:19:23 +0000322 pin_set(self->phys_port, mp_obj_is_true(args[0]));
Damien Georgecdad2b62015-12-28 17:42:20 +0000323 return mp_const_none;
324 }
325}
326
Damien George87c62502015-02-13 22:21:44 +0000327// pin.init(mode, pull)
328STATIC mp_obj_t pyb_pin_obj_init(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
329 return pyb_pin_obj_init_helper(args[0], n_args - 1, args + 1, kw_args);
330}
331MP_DEFINE_CONST_FUN_OBJ_KW(pyb_pin_init_obj, 1, pyb_pin_obj_init);
332
333// pin.value([value])
334STATIC mp_obj_t pyb_pin_value(mp_uint_t n_args, const mp_obj_t *args) {
Damien Georgecdad2b62015-12-28 17:42:20 +0000335 return pyb_pin_call(args[0], n_args - 1, 0, args + 1);
Damien George87c62502015-02-13 22:21:44 +0000336}
337STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_pin_value_obj, 1, 2, pyb_pin_value);
338
Paul Sokolovskybcf31a32017-04-16 11:14:48 +0300339STATIC mp_obj_t pyb_pin_off(mp_obj_t self_in) {
Damien George87c62502015-02-13 22:21:44 +0000340 pyb_pin_obj_t *self = self_in;
Damien George342d9032015-12-29 00:19:23 +0000341 pin_set(self->phys_port, 0);
Damien George87c62502015-02-13 22:21:44 +0000342 return mp_const_none;
343}
Paul Sokolovskybcf31a32017-04-16 11:14:48 +0300344STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_pin_off_obj, pyb_pin_off);
Damien George87c62502015-02-13 22:21:44 +0000345
Paul Sokolovskybcf31a32017-04-16 11:14:48 +0300346STATIC mp_obj_t pyb_pin_on(mp_obj_t self_in) {
Damien George87c62502015-02-13 22:21:44 +0000347 pyb_pin_obj_t *self = self_in;
Damien George342d9032015-12-29 00:19:23 +0000348 pin_set(self->phys_port, 1);
Damien George87c62502015-02-13 22:21:44 +0000349 return mp_const_none;
350}
Paul Sokolovskybcf31a32017-04-16 11:14:48 +0300351STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_pin_on_obj, pyb_pin_on);
Damien George87c62502015-02-13 22:21:44 +0000352
Damien George9ee46412017-03-16 17:15:34 +1100353// pin.irq(handler=None, trigger=IRQ_FALLING|IRQ_RISING, hard=False)
Damien George8e130fc2016-05-03 13:47:10 +0100354STATIC 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 +1100355 enum { ARG_handler, ARG_trigger, ARG_hard };
Damien George8e130fc2016-05-03 13:47:10 +0100356 static const mp_arg_t allowed_args[] = {
Damien George9ee46412017-03-16 17:15:34 +1100357 { MP_QSTR_handler, MP_ARG_OBJ, {.u_obj = mp_const_none} },
358 { MP_QSTR_trigger, MP_ARG_INT, {.u_int = GPIO_PIN_INTR_POSEDGE | GPIO_PIN_INTR_NEGEDGE} },
359 { MP_QSTR_hard, MP_ARG_BOOL, {.u_bool = false} },
Damien George8e130fc2016-05-03 13:47:10 +0100360 };
361 pyb_pin_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
362 mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
363 mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
364
Damien George674bf1b2016-04-14 11:15:43 +0100365 if (self->phys_port >= 16) {
366 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "pin does not have IRQ capabilities"));
367 }
368
Damien George5d05ff12017-03-21 15:28:31 +1100369 if (n_args > 1 || kw_args->used != 0) {
Damien George674bf1b2016-04-14 11:15:43 +0100370 // configure irq
Damien George8e130fc2016-05-03 13:47:10 +0100371 mp_obj_t handler = args[ARG_handler].u_obj;
Damien George9ee46412017-03-16 17:15:34 +1100372 uint32_t trigger = args[ARG_trigger].u_int;
Damien George674bf1b2016-04-14 11:15:43 +0100373 if (handler == mp_const_none) {
374 handler = MP_OBJ_NULL;
Damien George9ee46412017-03-16 17:15:34 +1100375 trigger = 0;
Damien George674bf1b2016-04-14 11:15:43 +0100376 }
377 ETS_GPIO_INTR_DISABLE();
378 MP_STATE_PORT(pin_irq_handler)[self->phys_port] = handler;
Damien George2507c832017-02-15 17:45:53 +1100379 pin_irq_is_hard[self->phys_port] = args[ARG_hard].u_bool;
Damien George9ee46412017-03-16 17:15:34 +1100380 SET_TRIGGER(self->phys_port, trigger);
Damien George674bf1b2016-04-14 11:15:43 +0100381 GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, 1 << self->phys_port);
382 ETS_GPIO_INTR_ENABLE();
383 }
384
385 // return the irq object
386 return MP_OBJ_FROM_PTR(&pin_irq_obj[self->phys_port]);
387}
Damien George8e130fc2016-05-03 13:47:10 +0100388STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_pin_irq_obj, 1, pyb_pin_irq);
Damien George674bf1b2016-04-14 11:15:43 +0100389
Paul Sokolovsky18b68352017-01-01 19:02:28 +0300390STATIC mp_uint_t pin_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode);
391STATIC mp_uint_t pin_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) {
392 (void)errcode;
393 pyb_pin_obj_t *self = self_in;
394
395 switch (request) {
396 case MP_PIN_READ: {
397 return pin_get(self->phys_port);
398 }
399 case MP_PIN_WRITE: {
400 pin_set(self->phys_port, arg);
401 return 0;
402 }
403 }
404 return -1;
405}
406
Damien George87c62502015-02-13 22:21:44 +0000407STATIC const mp_map_elem_t pyb_pin_locals_dict_table[] = {
408 // instance methods
409 { MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&pyb_pin_init_obj },
410 { MP_OBJ_NEW_QSTR(MP_QSTR_value), (mp_obj_t)&pyb_pin_value_obj },
Paul Sokolovskybcf31a32017-04-16 11:14:48 +0300411 { MP_OBJ_NEW_QSTR(MP_QSTR_off), (mp_obj_t)&pyb_pin_off_obj },
412 { MP_OBJ_NEW_QSTR(MP_QSTR_on), (mp_obj_t)&pyb_pin_on_obj },
Damien George674bf1b2016-04-14 11:15:43 +0100413 { MP_OBJ_NEW_QSTR(MP_QSTR_irq), (mp_obj_t)&pyb_pin_irq_obj },
Damien George87c62502015-02-13 22:21:44 +0000414
415 // class constants
416 { MP_OBJ_NEW_QSTR(MP_QSTR_IN), MP_OBJ_NEW_SMALL_INT(GPIO_MODE_INPUT) },
Damien Georgecdad2b62015-12-28 17:42:20 +0000417 { MP_OBJ_NEW_QSTR(MP_QSTR_OUT), MP_OBJ_NEW_SMALL_INT(GPIO_MODE_OUTPUT) },
418 { MP_OBJ_NEW_QSTR(MP_QSTR_OPEN_DRAIN), MP_OBJ_NEW_SMALL_INT(GPIO_MODE_OPEN_DRAIN) },
Damien George87c62502015-02-13 22:21:44 +0000419 { MP_OBJ_NEW_QSTR(MP_QSTR_PULL_UP), MP_OBJ_NEW_SMALL_INT(GPIO_PULL_UP) },
Josef Gajdusek7d8edef2015-05-26 18:54:55 +0200420 //{ MP_OBJ_NEW_QSTR(MP_QSTR_PULL_DOWN), MP_OBJ_NEW_SMALL_INT(GPIO_PULL_DOWN) },
Damien George674bf1b2016-04-14 11:15:43 +0100421
422 // IRG triggers, can be or'd together
423 { MP_OBJ_NEW_QSTR(MP_QSTR_IRQ_RISING), MP_OBJ_NEW_SMALL_INT(GPIO_PIN_INTR_POSEDGE) },
424 { MP_OBJ_NEW_QSTR(MP_QSTR_IRQ_FALLING), MP_OBJ_NEW_SMALL_INT(GPIO_PIN_INTR_NEGEDGE) },
Damien George87c62502015-02-13 22:21:44 +0000425};
426
427STATIC MP_DEFINE_CONST_DICT(pyb_pin_locals_dict, pyb_pin_locals_dict_table);
428
Paul Sokolovsky18b68352017-01-01 19:02:28 +0300429STATIC const mp_pin_p_t pin_pin_p = {
430 .ioctl = pin_ioctl,
431};
432
Damien George87c62502015-02-13 22:21:44 +0000433const mp_obj_type_t pyb_pin_type = {
434 { &mp_type_type },
435 .name = MP_QSTR_Pin,
436 .print = pyb_pin_print,
Paul Sokolovsky605ff912017-04-11 00:12:20 +0300437 .make_new = mp_pin_make_new,
Damien Georgecdad2b62015-12-28 17:42:20 +0000438 .call = pyb_pin_call,
Paul Sokolovsky18b68352017-01-01 19:02:28 +0300439 .protocol = &pin_pin_p,
Damien George87c62502015-02-13 22:21:44 +0000440 .locals_dict = (mp_obj_t)&pyb_pin_locals_dict,
441};
Damien George674bf1b2016-04-14 11:15:43 +0100442
443/******************************************************************************/
444// Pin IRQ object
445
446STATIC const mp_obj_type_t pin_irq_type;
447
448STATIC const pin_irq_obj_t pin_irq_obj[16] = {
449 {{&pin_irq_type}, 0},
450 {{&pin_irq_type}, 1},
451 {{&pin_irq_type}, 2},
452 {{&pin_irq_type}, 3},
453 {{&pin_irq_type}, 4},
454 {{&pin_irq_type}, 5},
455 {{&pin_irq_type}, 6},
456 {{&pin_irq_type}, 7},
457 {{&pin_irq_type}, 8},
458 {{&pin_irq_type}, 9},
459 {{&pin_irq_type}, 10},
460 {{&pin_irq_type}, 11},
461 {{&pin_irq_type}, 12},
462 {{&pin_irq_type}, 13},
463 {{&pin_irq_type}, 14},
464 {{&pin_irq_type}, 15},
465};
466
467STATIC mp_obj_t pin_irq_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
468 pin_irq_obj_t *self = self_in;
469 mp_arg_check_num(n_args, n_kw, 0, 0, false);
470 pin_intr_handler(1 << self->phys_port);
471 return mp_const_none;
472}
473
474STATIC mp_obj_t pin_irq_trigger(size_t n_args, const mp_obj_t *args) {
475 pin_irq_obj_t *self = args[0];
476 uint32_t orig_trig = GET_TRIGGER(self->phys_port);
477 if (n_args == 2) {
478 // set trigger
479 SET_TRIGGER(self->phys_port, mp_obj_get_int(args[1]));
480 }
481 // return original trigger value
482 return MP_OBJ_NEW_SMALL_INT(orig_trig);
483}
484STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pin_irq_trigger_obj, 1, 2, pin_irq_trigger);
485
486STATIC const mp_rom_map_elem_t pin_irq_locals_dict_table[] = {
487 { MP_ROM_QSTR(MP_QSTR_trigger), MP_ROM_PTR(&pin_irq_trigger_obj) },
488};
489
490STATIC MP_DEFINE_CONST_DICT(pin_irq_locals_dict, pin_irq_locals_dict_table);
491
492STATIC const mp_obj_type_t pin_irq_type = {
493 { &mp_type_type },
494 .name = MP_QSTR_IRQ,
495 .call = pin_irq_call,
496 .locals_dict = (mp_obj_dict_t*)&pin_irq_locals_dict,
497};