diff options
| author | Glenn Ruben Bakke <glennbakke@gmail.com> | 2017-10-04 21:46:48 +0200 |
|---|---|---|
| committer | Glenn Ruben Bakke <glennbakke@gmail.com> | 2017-10-04 21:46:48 +0200 |
| commit | 44e2cb415f0b571e36b9d08def533c018fa99f1f (patch) | |
| tree | 92bcc0f49b7612d3ffb366688deefe225abc9b5c /ports/nrf/modules/machine | |
| parent | bcab2ba0a80297100919366add6bada140c6ed75 (diff) | |
ports/nrf: Moving nrf51/52 port to new ports directory
Diffstat (limited to 'ports/nrf/modules/machine')
22 files changed, 3464 insertions, 0 deletions
diff --git a/ports/nrf/modules/machine/adc.c b/ports/nrf/modules/machine/adc.c new file mode 100644 index 000000000..61cb6f7b4 --- /dev/null +++ b/ports/nrf/modules/machine/adc.c @@ -0,0 +1,144 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include <stdio.h> +#include <string.h> + +#include "py/nlr.h" +#include "py/runtime.h" +#include "py/mphal.h" +#include "adc.h" +#include "hal_adc.h" + +#if MICROPY_PY_MACHINE_ADC + +typedef struct _machine_adc_obj_t { + mp_obj_base_t base; + ADC_HandleTypeDef *adc; +} machine_adc_obj_t; + +ADC_HandleTypeDef ADCHandle0 = {.config.channel = 0}; +ADC_HandleTypeDef ADCHandle1 = {.config.channel = 1}; +ADC_HandleTypeDef ADCHandle2 = {.config.channel = 2}; +ADC_HandleTypeDef ADCHandle3 = {.config.channel = 3}; +ADC_HandleTypeDef ADCHandle4 = {.config.channel = 4}; +ADC_HandleTypeDef ADCHandle5 = {.config.channel = 5}; +ADC_HandleTypeDef ADCHandle6 = {.config.channel = 6}; +ADC_HandleTypeDef ADCHandle7 = {.config.channel = 7}; + +STATIC const machine_adc_obj_t machine_adc_obj[] = { + {{&machine_adc_type}, &ADCHandle0}, + {{&machine_adc_type}, &ADCHandle1}, + {{&machine_adc_type}, &ADCHandle2}, + {{&machine_adc_type}, &ADCHandle3}, + {{&machine_adc_type}, &ADCHandle4}, + {{&machine_adc_type}, &ADCHandle5}, + {{&machine_adc_type}, &ADCHandle6}, + {{&machine_adc_type}, &ADCHandle7}, +}; + +STATIC int adc_find(mp_obj_t id) { + // given an integer id + int adc_id = mp_obj_get_int(id); + + int adc_idx = adc_id; + + if (adc_idx >= 0 && adc_idx <= MP_ARRAY_SIZE(machine_adc_obj) + && machine_adc_obj[adc_idx].adc != NULL) { + return adc_idx; + } + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "ADC(%d) does not exist", adc_id)); +} + + +/// \method __str__() +/// Return a string describing the ADC object. +STATIC void machine_adc_print(const mp_print_t *print, mp_obj_t o, mp_print_kind_t kind) { + machine_adc_obj_t *self = o; + + (void)self; + + mp_printf(print, "ADC()"); +} + +/******************************************************************************/ +/* MicroPython bindings for machine API */ + +// for make_new +enum { + ARG_NEW_PIN, +}; + +STATIC mp_obj_t machine_adc_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + static const mp_arg_t allowed_args[] = { + { ARG_NEW_PIN, MP_ARG_OBJ, {.u_obj = MP_OBJ_NEW_SMALL_INT(-1) } }, + }; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + int adc_id = adc_find(args[ARG_NEW_PIN].u_obj); + const machine_adc_obj_t *self = &machine_adc_obj[adc_id]; + + return MP_OBJ_FROM_PTR(self); +} + +/// \method value() +/// Read adc level. +mp_obj_t machine_adc_value(mp_obj_t self_in) { + machine_adc_obj_t *self = self_in; + return MP_OBJ_NEW_SMALL_INT(hal_adc_channel_value(&self->adc->config)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_machine_adc_value_obj, machine_adc_value); + +/// \method battery_level() +/// Get battery level in percentage. +mp_obj_t machine_adc_battery_level(void) { + return MP_OBJ_NEW_SMALL_INT(hal_adc_battery_level()); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_machine_adc_battery_level_obj, machine_adc_battery_level); + +STATIC const mp_rom_map_elem_t machine_adc_locals_dict_table[] = { + // instance methods + { MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&mp_machine_adc_value_obj) }, + + // class methods + { MP_ROM_QSTR(MP_QSTR_battery_level), MP_ROM_PTR(&mp_machine_adc_battery_level_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(machine_adc_locals_dict, machine_adc_locals_dict_table); + +const mp_obj_type_t machine_adc_type = { + { &mp_type_type }, + .name = MP_QSTR_ADC, + .make_new = machine_adc_make_new, + .locals_dict = (mp_obj_dict_t*)&machine_adc_locals_dict, + .print = machine_adc_print, +}; + +#endif // MICROPY_PY_MACHINE_ADC diff --git a/ports/nrf/modules/machine/adc.h b/ports/nrf/modules/machine/adc.h new file mode 100644 index 000000000..a8ff56fbb --- /dev/null +++ b/ports/nrf/modules/machine/adc.h @@ -0,0 +1,34 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef ADC_H__ +#define ADC_H__ + +#include "hal_adc.h" + +extern const mp_obj_type_t machine_adc_type; + +#endif // ADC_H__ diff --git a/ports/nrf/modules/machine/i2c.c b/ports/nrf/modules/machine/i2c.c new file mode 100644 index 000000000..943599816 --- /dev/null +++ b/ports/nrf/modules/machine/i2c.c @@ -0,0 +1,163 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include <stdio.h> +#include <string.h> + +#include "py/nlr.h" +#include "py/runtime.h" +#include "py/mphal.h" +#include "extmod/machine_i2c.h" +#include "i2c.h" +#include "hal_twi.h" + +#if MICROPY_PY_MACHINE_I2C + +STATIC const mp_obj_type_t machine_hard_i2c_type; + +typedef struct _machine_hard_i2c_obj_t { + mp_obj_base_t base; + TWI_HandleTypeDef *i2c; +} machine_hard_i2c_obj_t; + +TWI_HandleTypeDef I2CHandle0 = {.instance = NULL, .init.id = 0}; +TWI_HandleTypeDef I2CHandle1 = {.instance = NULL, .init.id = 1}; + +STATIC const machine_hard_i2c_obj_t machine_hard_i2c_obj[] = { + {{&machine_hard_i2c_type}, &I2CHandle0}, + {{&machine_hard_i2c_type}, &I2CHandle1}, +}; + +void i2c_init0(void) { + // reset the I2C handles + memset(&I2CHandle0, 0, sizeof(TWI_HandleTypeDef)); + I2CHandle0.instance = TWI_BASE(0); + memset(&I2CHandle1, 0, sizeof(TWI_HandleTypeDef)); + I2CHandle0.instance = TWI_BASE(1); +} + +STATIC int i2c_find(mp_obj_t id) { + // given an integer id + int i2c_id = mp_obj_get_int(id); + if (i2c_id >= 0 && i2c_id <= MP_ARRAY_SIZE(machine_hard_i2c_obj) + && machine_hard_i2c_obj[i2c_id].i2c != NULL) { + return i2c_id; + } + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "I2C(%d) does not exist", i2c_id)); +} + +STATIC void machine_hard_i2c_print(const mp_print_t *print, mp_obj_t o, mp_print_kind_t kind) { + machine_hard_i2c_obj_t *self = o; + mp_printf(print, "I2C(%u, scl=(port=%u, pin=%u), sda=(port=%u, pin=%u))", + self->i2c->init.id, + self->i2c->init.scl_pin->port, + self->i2c->init.scl_pin->pin, + self->i2c->init.sda_pin->port, + self->i2c->init.sda_pin->pin); +} + +/******************************************************************************/ +/* MicroPython bindings for machine API */ + +// for make_new +enum { + ARG_NEW_id, + ARG_NEW_scl, + ARG_NEW_sda, + ARG_NEW_freq, + ARG_NEW_timeout, +}; + +mp_obj_t machine_hard_i2c_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + static const mp_arg_t allowed_args[] = { + { ARG_NEW_id, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { ARG_NEW_scl, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { ARG_NEW_sda, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + }; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // get static peripheral object + int i2c_id = i2c_find(args[ARG_NEW_id].u_obj); + const machine_hard_i2c_obj_t *self = &machine_hard_i2c_obj[i2c_id]; + + if (args[ARG_NEW_scl].u_obj != MP_OBJ_NULL) { + self->i2c->init.scl_pin = args[ARG_NEW_scl].u_obj; + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "I2C SCL Pin not set")); + } + + if (args[ARG_NEW_sda].u_obj != MP_OBJ_NULL) { + self->i2c->init.sda_pin = args[ARG_NEW_sda].u_obj; + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "I2C SDA Pin not set")); + } + + self->i2c->init.freq = HAL_TWI_FREQ_100_Kbps; + + hal_twi_master_init(self->i2c->instance, &self->i2c->init); + + return MP_OBJ_FROM_PTR(self); +} + +#include <stdio.h> + +int machine_hard_i2c_readfrom(mp_obj_base_t *self_in, uint16_t addr, uint8_t *dest, size_t len, bool stop) { + machine_hard_i2c_obj_t *self = (machine_hard_i2c_obj_t *)self_in; + + hal_twi_master_rx(self->i2c->instance, addr, len, dest, stop); + + return 0; +} + +int machine_hard_i2c_writeto(mp_obj_base_t *self_in, uint16_t addr, const uint8_t *src, size_t len, bool stop) { + machine_hard_i2c_obj_t *self = (machine_hard_i2c_obj_t *)self_in; + + hal_twi_master_tx(self->i2c->instance, addr, len, src, stop); + + return 0; +} + +STATIC const mp_machine_i2c_p_t machine_hard_i2c_p = { + .readfrom = machine_hard_i2c_readfrom, + .writeto = machine_hard_i2c_writeto, +}; + +STATIC const mp_obj_type_t machine_hard_i2c_type = { + { &mp_type_type }, + .name = MP_QSTR_I2C, + .print = machine_hard_i2c_print, + .make_new = machine_hard_i2c_make_new, + .protocol = &machine_hard_i2c_p, + .locals_dict = (mp_obj_dict_t*)&mp_machine_soft_i2c_locals_dict, +}; + +#endif // MICROPY_PY_MACHINE_I2C diff --git a/ports/nrf/modules/machine/i2c.h b/ports/nrf/modules/machine/i2c.h new file mode 100644 index 000000000..cd8d4507c --- /dev/null +++ b/ports/nrf/modules/machine/i2c.h @@ -0,0 +1,36 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef I2C_H__ +#define I2C_H__ + +#include "hal_twi.h" + +extern const mp_obj_type_t machine_i2c_type; + +void i2c_init0(void); + +#endif // I2C_H__ diff --git a/ports/nrf/modules/machine/led.c b/ports/nrf/modules/machine/led.c new file mode 100644 index 000000000..3eec949e9 --- /dev/null +++ b/ports/nrf/modules/machine/led.c @@ -0,0 +1,159 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2016 Damien P. George + * Copyright (c) 2015 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/runtime.h" + +#include "mphalport.h" +#include "led.h" +#include "mpconfigboard.h" + +#if MICROPY_HW_HAS_LED + +#define LED_OFF(led) {(MICROPY_HW_LED_PULLUP) ? hal_gpio_pin_set(0, led) : hal_gpio_pin_clear(0, led); } +#define LED_ON(led) {(MICROPY_HW_LED_PULLUP) ? hal_gpio_pin_clear(0, led) : hal_gpio_pin_set(0, led); } + +typedef struct _pyb_led_obj_t { + mp_obj_base_t base; + mp_uint_t led_id; + mp_uint_t hw_pin; + uint8_t hw_pin_port; +} pyb_led_obj_t; + +STATIC const pyb_led_obj_t pyb_led_obj[] = { +#if MICROPY_HW_LED_TRICOLOR + {{&pyb_led_type}, PYB_LED_RED, MICROPY_HW_LED_RED}, + {{&pyb_led_type}, PYB_LED_GREEN, MICROPY_HW_LED_GREEN}, + {{&pyb_led_type}, PYB_LED_BLUE, MICROPY_HW_LED_BLUE}, +#elif (MICROPY_HW_LED_COUNT == 1) + {{&pyb_led_type}, PYB_LED1, MICROPY_HW_LED1}, +#elif (MICROPY_HW_LED_COUNT == 2) + {{&pyb_led_type}, PYB_LED1, MICROPY_HW_LED1}, + {{&pyb_led_type}, PYB_LED2, MICROPY_HW_LED2}, +#else + {{&pyb_led_type}, PYB_LED1, MICROPY_HW_LED1}, + {{&pyb_led_type}, PYB_LED2, MICROPY_HW_LED2}, + {{&pyb_led_type}, PYB_LED3, MICROPY_HW_LED3}, + {{&pyb_led_type}, PYB_LED4, MICROPY_HW_LED4}, +#endif +}; + +#define NUM_LEDS MP_ARRAY_SIZE(pyb_led_obj) + +void led_init(void) { + for (uint8_t i = 0; i < NUM_LEDS; i++) { + LED_OFF(pyb_led_obj[i].hw_pin); + hal_gpio_cfg_pin(0, pyb_led_obj[i].hw_pin, HAL_GPIO_MODE_OUTPUT, HAL_GPIO_PULL_DISABLED); + } +} + +void led_state(pyb_led_obj_t * led_obj, int state) { + if (state == 1) { + LED_ON(led_obj->hw_pin); + } else { + LED_OFF(led_obj->hw_pin); + } +} + +void led_toggle(pyb_led_obj_t * led_obj) { + hal_gpio_pin_toggle(0, led_obj->hw_pin); +} + + + +/******************************************************************************/ +/* MicroPython bindings */ + +void led_obj_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + pyb_led_obj_t *self = self_in; + mp_printf(print, "LED(%lu)", self->led_id); +} + +/// \classmethod \constructor(id) +/// Create an LED object associated with the given LED: +/// +/// - `id` is the LED number, 1-4. +STATIC mp_obj_t led_obj_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + // check arguments + mp_arg_check_num(n_args, n_kw, 1, 1, false); + + // get led number + mp_int_t led_id = mp_obj_get_int(args[0]); + + // check led number + if (!(1 <= led_id && led_id <= NUM_LEDS)) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "LED(%d) does not exist", led_id)); + } + + // return static led object + return (mp_obj_t)&pyb_led_obj[led_id - 1]; +} + +/// \method on() +/// Turn the LED on. +mp_obj_t led_obj_on(mp_obj_t self_in) { + pyb_led_obj_t *self = self_in; + led_state(self, 1); + return mp_const_none; +} + +/// \method off() +/// Turn the LED off. +mp_obj_t led_obj_off(mp_obj_t self_in) { + pyb_led_obj_t *self = self_in; + led_state(self, 0); + return mp_const_none; +} + +/// \method toggle() +/// Toggle the LED between on and off. +mp_obj_t led_obj_toggle(mp_obj_t self_in) { + pyb_led_obj_t *self = self_in; + led_toggle(self); + return mp_const_none; +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_1(led_obj_on_obj, led_obj_on); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(led_obj_off_obj, led_obj_off); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(led_obj_toggle_obj, led_obj_toggle); + +STATIC const mp_rom_map_elem_t led_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_on), MP_ROM_PTR(&led_obj_on_obj) }, + { MP_ROM_QSTR(MP_QSTR_off), MP_ROM_PTR(&led_obj_off_obj) }, + { MP_ROM_QSTR(MP_QSTR_toggle), MP_ROM_PTR(&led_obj_toggle_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(led_locals_dict, led_locals_dict_table); + +const mp_obj_type_t pyb_led_type = { + { &mp_type_type }, + .name = MP_QSTR_LED, + .print = led_obj_print, + .make_new = led_obj_make_new, + .locals_dict = (mp_obj_dict_t*)&led_locals_dict, +}; + +#endif // MICROPY_HW_HAS_LED diff --git a/ports/nrf/modules/machine/led.h b/ports/nrf/modules/machine/led.h new file mode 100644 index 000000000..c9e20ce4c --- /dev/null +++ b/ports/nrf/modules/machine/led.h @@ -0,0 +1,53 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2015 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef LED_H +#define LED_H + +typedef enum { +#if MICROPY_HW_LED_TRICOLOR + PYB_LED_RED = 1, + PYB_LED_GREEN = 2, + PYB_LED_BLUE = 3 +#elif (MICROPY_HW_LED_COUNT == 1) + PYB_LED1 = 1, +#elif (MICROPY_HW_LED_COUNT == 2) + PYB_LED1 = 1, + PYB_LED2 = 2, +#else + PYB_LED1 = 1, + PYB_LED2 = 2, + PYB_LED3 = 3, + PYB_LED4 = 4 +#endif +} pyb_led_t; + +void led_init(void); + +extern const mp_obj_type_t pyb_led_type; + +#endif // LED_H diff --git a/ports/nrf/modules/machine/modmachine.c b/ports/nrf/modules/machine/modmachine.c new file mode 100644 index 000000000..ad536a37d --- /dev/null +++ b/ports/nrf/modules/machine/modmachine.c @@ -0,0 +1,244 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2015 Damien P. George + * Copyright (c) 2016 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include <stdio.h> + +#include "modmachine.h" +#include "py/gc.h" +#include "py/runtime.h" +#include "py/mphal.h" +#include "extmod/machine_mem.h" +#include "extmod/machine_pulse.h" +#include "extmod/machine_i2c.h" +#include "lib/utils/pyexec.h" +#include "lib/oofatfs/ff.h" +#include "lib/oofatfs/diskio.h" +#include "gccollect.h" +#include "pin.h" +#include "uart.h" +#include "spi.h" +#include "i2c.h" +#include "timer.h" +#if MICROPY_PY_MACHINE_HW_PWM +#include "pwm.h" +#endif +#if MICROPY_PY_MACHINE_ADC +#include "adc.h" +#endif +#if MICROPY_PY_MACHINE_TEMP +#include "temp.h" +#endif +#if MICROPY_PY_MACHINE_RTC +#include "rtc.h" +#endif + +#define PYB_RESET_HARD (0) +#define PYB_RESET_WDT (1) +#define PYB_RESET_SOFT (2) +#define PYB_RESET_LOCKUP (3) +#define PYB_RESET_POWER_ON (16) +#define PYB_RESET_LPCOMP (17) +#define PYB_RESET_DIF (18) +#define PYB_RESET_NFC (19) + +STATIC uint32_t reset_cause; + +void machine_init(void) { + uint32_t state = NRF_POWER->RESETREAS; + if (state & POWER_RESETREAS_RESETPIN_Msk) { + reset_cause = PYB_RESET_HARD; + } else if (state & POWER_RESETREAS_DOG_Msk) { + reset_cause = PYB_RESET_WDT; + } else if (state & POWER_RESETREAS_SREQ_Msk) { + reset_cause = PYB_RESET_SOFT; + } else if (state & POWER_RESETREAS_LOCKUP_Msk) { + reset_cause = PYB_RESET_LOCKUP; + } else if (state & POWER_RESETREAS_OFF_Msk) { + reset_cause = PYB_RESET_POWER_ON; + } else if (state & POWER_RESETREAS_LPCOMP_Msk) { + reset_cause = PYB_RESET_LPCOMP; + } else if (state & POWER_RESETREAS_DIF_Msk) { + reset_cause = PYB_RESET_DIF; +#if NRF52 + } else if (state & POWER_RESETREAS_NFC_Msk) { + reset_cause = PYB_RESET_NFC; +#endif + } + + // clear reset reason + NRF_POWER->RESETREAS = (1 << reset_cause); +} + +// machine.info([dump_alloc_table]) +// Print out lots of information about the board. +STATIC mp_obj_t machine_info(mp_uint_t n_args, const mp_obj_t *args) { + // to print info about memory + { + printf("_etext=%p\n", &_etext); + printf("_sidata=%p\n", &_sidata); + printf("_sdata=%p\n", &_sdata); + printf("_edata=%p\n", &_edata); + printf("_sbss=%p\n", &_sbss); + printf("_ebss=%p\n", &_ebss); + printf("_estack=%p\n", &_estack); + printf("_ram_start=%p\n", &_ram_start); + printf("_heap_start=%p\n", &_heap_start); + printf("_heap_end=%p\n", &_heap_end); + printf("_ram_end=%p\n", &_ram_end); + } + + // qstr info + { + mp_uint_t n_pool, n_qstr, n_str_data_bytes, n_total_bytes; + qstr_pool_info(&n_pool, &n_qstr, &n_str_data_bytes, &n_total_bytes); + printf("qstr:\n n_pool=" UINT_FMT "\n n_qstr=" UINT_FMT "\n n_str_data_bytes=" UINT_FMT "\n n_total_bytes=" UINT_FMT "\n", n_pool, n_qstr, n_str_data_bytes, n_total_bytes); + } + + // GC info + { + gc_info_t info; + gc_info(&info); + printf("GC:\n"); + printf(" " UINT_FMT " total\n", info.total); + printf(" " UINT_FMT " : " UINT_FMT "\n", info.used, info.free); + printf(" 1=" UINT_FMT " 2=" UINT_FMT " m=" UINT_FMT "\n", info.num_1block, info.num_2block, info.max_block); + } + + if (n_args == 1) { + // arg given means dump gc allocation table + gc_dump_alloc_table(); + } + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_info_obj, 0, 1, machine_info); + +// Resets the pyboard in a manner similar to pushing the external RESET button. +STATIC mp_obj_t machine_reset(void) { + NVIC_SystemReset(); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_0(machine_reset_obj, machine_reset); + +STATIC mp_obj_t machine_soft_reset(void) { + pyexec_system_exit = PYEXEC_FORCED_EXIT; + nlr_raise(mp_obj_new_exception(&mp_type_SystemExit)); +} +MP_DEFINE_CONST_FUN_OBJ_0(machine_soft_reset_obj, machine_soft_reset); + +STATIC mp_obj_t machine_sleep(void) { + __WFE(); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_0(machine_sleep_obj, machine_sleep); + +STATIC mp_obj_t machine_deepsleep(void) { + __WFI(); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_0(machine_deepsleep_obj, machine_deepsleep); + +STATIC mp_obj_t machine_reset_cause(void) { + return MP_OBJ_NEW_SMALL_INT(reset_cause); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_reset_cause_obj, machine_reset_cause); + +STATIC mp_obj_t machine_enable_irq(void) { +#ifndef BLUETOOTH_SD + __enable_irq(); +#else + +#endif + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_0(machine_enable_irq_obj, machine_enable_irq); + +// Resets the pyboard in a manner similar to pushing the external RESET button. +STATIC mp_obj_t machine_disable_irq(void) { +#ifndef BLUETOOTH_SD + __disable_irq(); +#else + +#endif + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_0(machine_disable_irq_obj, machine_disable_irq); + +STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_umachine) }, + { MP_ROM_QSTR(MP_QSTR_info), MP_ROM_PTR(&machine_info_obj) }, + { MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&machine_reset_obj) }, + { MP_ROM_QSTR(MP_QSTR_soft_reset), MP_ROM_PTR(&machine_soft_reset_obj) }, + { MP_ROM_QSTR(MP_QSTR_enable_irq), MP_ROM_PTR(&machine_enable_irq_obj) }, + { MP_ROM_QSTR(MP_QSTR_disable_irq), MP_ROM_PTR(&machine_disable_irq_obj) }, +#if MICROPY_HW_ENABLE_RNG + { MP_ROM_QSTR(MP_QSTR_rng), MP_ROM_PTR(&pyb_rng_get_obj) }, +#endif + { MP_ROM_QSTR(MP_QSTR_sleep), MP_ROM_PTR(&machine_sleep_obj) }, + { MP_ROM_QSTR(MP_QSTR_deepsleep), MP_ROM_PTR(&machine_deepsleep_obj) }, + { MP_ROM_QSTR(MP_QSTR_reset_cause), MP_ROM_PTR(&machine_reset_cause_obj) }, + { MP_ROM_QSTR(MP_QSTR_Pin), MP_ROM_PTR(&pin_type) }, + { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&machine_hard_uart_type) }, +#if MICROPY_PY_MACHINE_HW_SPI + { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&machine_hard_spi_type) }, +#endif +#if MICROPY_PY_MACHINE_I2C + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&machine_i2c_type) }, +#endif +#if MICROPY_PY_MACHINE_ADC + { MP_ROM_QSTR(MP_QSTR_ADC), MP_ROM_PTR(&machine_adc_type) }, +#endif +#if MICROPY_PY_MACHINE_RTC + { MP_ROM_QSTR(MP_QSTR_RTC), MP_ROM_PTR(&machine_rtc_type) }, +#endif +#if MICROPY_PY_MACHINE_TIMER + { MP_ROM_QSTR(MP_QSTR_Timer), MP_ROM_PTR(&machine_timer_type) }, +#endif +#if MICROPY_PY_MACHINE_HW_PWM + { MP_ROM_QSTR(MP_QSTR_PWM), MP_ROM_PTR(&machine_hard_pwm_type) }, +#endif +#if MICROPY_PY_MACHINE_TEMP + { MP_ROM_QSTR(MP_QSTR_Temp), MP_ROM_PTR(&machine_temp_type) }, +#endif + { MP_ROM_QSTR(MP_QSTR_HARD_RESET), MP_ROM_INT(PYB_RESET_HARD) }, + { MP_ROM_QSTR(MP_QSTR_WDT_RESET), MP_ROM_INT(PYB_RESET_WDT) }, + { MP_ROM_QSTR(MP_QSTR_SOFT_RESET), MP_ROM_INT(PYB_RESET_SOFT) }, + { MP_ROM_QSTR(MP_QSTR_LOCKUP_RESET), MP_ROM_INT(PYB_RESET_LOCKUP) }, + { MP_ROM_QSTR(MP_QSTR_PWRON_RESET), MP_ROM_INT(PYB_RESET_POWER_ON) }, + { MP_ROM_QSTR(MP_QSTR_LPCOMP_RESET), MP_ROM_INT(PYB_RESET_LPCOMP) }, + { MP_ROM_QSTR(MP_QSTR_DEBUG_IF_RESET), MP_ROM_INT(PYB_RESET_DIF) }, +#if NRF52 + { MP_ROM_QSTR(MP_QSTR_NFC_RESET), MP_ROM_INT(PYB_RESET_NFC) }, +#endif +}; + +STATIC MP_DEFINE_CONST_DICT(machine_module_globals, machine_module_globals_table); + +const mp_obj_module_t machine_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&machine_module_globals, +}; + diff --git a/ports/nrf/modules/machine/modmachine.h b/ports/nrf/modules/machine/modmachine.h new file mode 100644 index 000000000..76b4ad724 --- /dev/null +++ b/ports/nrf/modules/machine/modmachine.h @@ -0,0 +1,42 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2015 Damien P. George + * Copyright (c) 2016 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef __MICROPY_INCLUDED_NRF5_MODMACHINE_H__ +#define __MICROPY_INCLUDED_NRF5_MODMACHINE_H__ + +#include "py/mpstate.h" +#include "py/nlr.h" +#include "py/obj.h" + +void machine_init(void); + +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(machine_info_obj); +MP_DECLARE_CONST_FUN_OBJ_0(machine_reset_obj); +MP_DECLARE_CONST_FUN_OBJ_0(machine_sleep_obj); +MP_DECLARE_CONST_FUN_OBJ_0(machine_deepsleep_obj); + +#endif // __MICROPY_INCLUDED_NRF5_MODMACHINE_H__ diff --git a/ports/nrf/modules/machine/pin.c b/ports/nrf/modules/machine/pin.c new file mode 100644 index 000000000..62160d785 --- /dev/null +++ b/ports/nrf/modules/machine/pin.c @@ -0,0 +1,695 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2016 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + +#include <stdio.h> +#include <stdint.h> +#include <string.h> + +#include "py/nlr.h" +#include "py/runtime.h" +#include "py/mphal.h" +#include "pin.h" + +/// \moduleref pyb +/// \class Pin - control I/O pins +/// +/// A pin is the basic object to control I/O pins. It has methods to set +/// the mode of the pin (input, output, etc) and methods to get and set the +/// digital logic level. For analog control of a pin, see the ADC class. +/// +/// Usage Model: +/// +/// All Board Pins are predefined as pyb.Pin.board.Name +/// +/// x1_pin = pyb.Pin.board.X1 +/// +/// g = pyb.Pin(pyb.Pin.board.X1, pyb.Pin.IN) +/// +/// CPU pins which correspond to the board pins are available +/// as `pyb.cpu.Name`. For the CPU pins, the names are the port letter +/// followed by the pin number. On the PYBv1.0, `pyb.Pin.board.X1` and +/// `pyb.Pin.cpu.B6` are the same pin. +/// +/// You can also use strings: +/// +/// g = pyb.Pin('X1', pyb.Pin.OUT_PP) +/// +/// Users can add their own names: +/// +/// MyMapperDict = { 'LeftMotorDir' : pyb.Pin.cpu.C12 } +/// pyb.Pin.dict(MyMapperDict) +/// g = pyb.Pin("LeftMotorDir", pyb.Pin.OUT_OD) +/// +/// and can query mappings +/// +/// pin = pyb.Pin("LeftMotorDir") +/// +/// Users can also add their own mapping function: +/// +/// def MyMapper(pin_name): +/// if pin_name == "LeftMotorDir": +/// return pyb.Pin.cpu.A0 +/// +/// pyb.Pin.mapper(MyMapper) +/// +/// So, if you were to call: `pyb.Pin("LeftMotorDir", pyb.Pin.OUT_PP)` +/// then `"LeftMotorDir"` is passed directly to the mapper function. +/// +/// To summarise, the following order determines how things get mapped into +/// an ordinal pin number: +/// +/// 1. Directly specify a pin object +/// 2. User supplied mapping function +/// 3. User supplied mapping (object must be usable as a dictionary key) +/// 4. Supply a string which matches a board pin +/// 5. Supply a string which matches a CPU port/pin +/// +/// You can set `pyb.Pin.debug(True)` to get some debug information about +/// how a particular object gets mapped to a pin. + +// Pin class variables +STATIC bool pin_class_debug; + +// Forward declare function +void gpio_irq_event_callback(hal_gpio_event_channel_t channel); + +void pin_init0(void) { + MP_STATE_PORT(pin_class_mapper) = mp_const_none; + MP_STATE_PORT(pin_class_map_dict) = mp_const_none; + pin_class_debug = false; + + hal_gpio_register_callback(gpio_irq_event_callback); +} + +// C API used to convert a user-supplied pin name into an ordinal pin number. +const pin_obj_t *pin_find(mp_obj_t user_obj) { + const pin_obj_t *pin_obj; + + // If a pin was provided, then use it + if (MP_OBJ_IS_TYPE(user_obj, &pin_type)) { + pin_obj = user_obj; + if (pin_class_debug) { + printf("Pin map passed pin "); + mp_obj_print((mp_obj_t)pin_obj, PRINT_STR); + printf("\n"); + } + return pin_obj; + } + + if (MP_STATE_PORT(pin_class_mapper) != mp_const_none) { + pin_obj = mp_call_function_1(MP_STATE_PORT(pin_class_mapper), user_obj); + if (pin_obj != mp_const_none) { + if (!MP_OBJ_IS_TYPE(pin_obj, &pin_type)) { + mp_raise_ValueError("Pin.mapper didn't return a Pin object"); + } + if (pin_class_debug) { + printf("Pin.mapper maps "); + mp_obj_print(user_obj, PRINT_REPR); + printf(" to "); + mp_obj_print((mp_obj_t)pin_obj, PRINT_STR); + printf("\n"); + } + return pin_obj; + } + // The pin mapping function returned mp_const_none, fall through to + // other lookup methods. + } + + if (MP_STATE_PORT(pin_class_map_dict) != mp_const_none) { + mp_map_t *pin_map_map = mp_obj_dict_get_map(MP_STATE_PORT(pin_class_map_dict)); + mp_map_elem_t *elem = mp_map_lookup(pin_map_map, user_obj, MP_MAP_LOOKUP); + if (elem != NULL && elem->value != NULL) { + pin_obj = elem->value; + if (pin_class_debug) { + printf("Pin.map_dict maps "); + mp_obj_print(user_obj, PRINT_REPR); + printf(" to "); + mp_obj_print((mp_obj_t)pin_obj, PRINT_STR); + printf("\n"); + } + return pin_obj; + } + } + + // See if the pin name matches a board pin + pin_obj = pin_find_named_pin(&pin_board_pins_locals_dict, user_obj); + if (pin_obj) { + if (pin_class_debug) { + printf("Pin.board maps "); + mp_obj_print(user_obj, PRINT_REPR); + printf(" to "); + mp_obj_print((mp_obj_t)pin_obj, PRINT_STR); + printf("\n"); + } + return pin_obj; + } + + // See if the pin name matches a cpu pin + pin_obj = pin_find_named_pin(&pin_cpu_pins_locals_dict, user_obj); + if (pin_obj) { + if (pin_class_debug) { + printf("Pin.cpu maps "); + mp_obj_print(user_obj, PRINT_REPR); + printf(" to "); + mp_obj_print((mp_obj_t)pin_obj, PRINT_STR); + printf("\n"); + } + return pin_obj; + } + + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "pin '%s' not a valid pin identifier", mp_obj_str_get_str(user_obj))); +} + +/// \method __str__() +/// Return a string describing the pin object. +STATIC void pin_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + pin_obj_t *self = self_in; + + // pin name + mp_printf(print, "Pin(Pin.cpu.%q, mode=Pin.", self->name); + mp_printf(print, "port=0x%x, ", self->port); + mp_printf(print, "pin=0x%x, ", self->pin); + mp_printf(print, "pin_mask=0x%x,", self->pin_mask); +/* + uint32_t mode = pin_get_mode(self); + + if (mode == GPIO_MODE_ANALOG) { + // analog + mp_print_str(print, "ANALOG)"); + + } else { + // IO mode + bool af = false; + qstr mode_qst; + if (mode == GPIO_MODE_INPUT) { + mode_qst = MP_QSTR_IN; + } else if (mode == GPIO_MODE_OUTPUT_PP) { + mode_qst = MP_QSTR_OUT; + } else if (mode == GPIO_MODE_OUTPUT_OD) { + mode_qst = MP_QSTR_OPEN_DRAIN; + } else { + af = true; + if (mode == GPIO_MODE_AF_PP) { + mode_qst = MP_QSTR_ALT; + } else { + mode_qst = MP_QSTR_ALT_OPEN_DRAIN; + } + } + mp_print_str(print, qstr_str(mode_qst)); + // pull mode + qstr pull_qst = MP_QSTR_NULL; + uint32_t pull = pin_get_pull(self); + if (pull == GPIO_PULLUP) { + pull_qst = MP_QSTR_PULL_UP; + } else if (pull == GPIO_PULLDOWN) { + pull_qst = MP_QSTR_PULL_DOWN; + } + if (pull_qst != MP_QSTR_NULL) { + mp_printf(print, ", pull=Pin.%q", pull_qst); + } + // AF mode + if (af) { + mp_uint_t af_idx = pin_get_af(self); + const pin_af_obj_t *af_obj = pin_find_af_by_index(self, af_idx); + if (af_obj == NULL) { + mp_printf(print, ", af=%d)", af_idx); + } else { + mp_printf(print, ", af=Pin.%q)", af_obj->name); + } + } else { +*/ + mp_print_str(print, ")"); + /* } + }*/ + +} + +STATIC mp_obj_t pin_obj_init_helper(const pin_obj_t *pin, mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kw_args); + +/// \classmethod \constructor(id, ...) +/// Create a new Pin object associated with the id. If additional arguments are given, +/// they are used to initialise the pin. See `init`. +STATIC mp_obj_t pin_make_new(const mp_obj_type_t *type, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true); + + // Run an argument through the mapper and return the result. + const pin_obj_t *pin = pin_find(args[0]); + + if (n_args > 1 || n_kw > 0) { + // pin mode given, so configure this GPIO + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); + pin_obj_init_helper(pin, n_args - 1, args + 1, &kw_args); + } + + return (mp_obj_t)pin; +} + +// fast method for getting/setting pin value +STATIC mp_obj_t pin_call(mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 0, 1, false); + pin_obj_t *self = self_in; + if (n_args == 0) { + // get pin + return MP_OBJ_NEW_SMALL_INT(mp_hal_pin_read(self)); + } else { + // set pin + mp_hal_pin_write(self, mp_obj_is_true(args[0])); + return mp_const_none; + } +} + +STATIC mp_obj_t pin_off(mp_obj_t self_in) { + pin_obj_t *self = self_in; + mp_hal_pin_low(self); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_off_obj, pin_off); + +STATIC mp_obj_t pin_on(mp_obj_t self_in) { + pin_obj_t *self = self_in; + mp_hal_pin_high(self); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_on_obj, pin_on); + +/// \classmethod mapper([fun]) +/// Get or set the pin mapper function. +STATIC mp_obj_t pin_mapper(mp_uint_t n_args, const mp_obj_t *args) { + if (n_args > 1) { + MP_STATE_PORT(pin_class_mapper) = args[1]; + return mp_const_none; + } + return MP_STATE_PORT(pin_class_mapper); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pin_mapper_fun_obj, 1, 2, pin_mapper); +STATIC MP_DEFINE_CONST_CLASSMETHOD_OBJ(pin_mapper_obj, (mp_obj_t)&pin_mapper_fun_obj); + +/// \classmethod dict([dict]) +/// Get or set the pin mapper dictionary. +STATIC mp_obj_t pin_map_dict(mp_uint_t n_args, const mp_obj_t *args) { + if (n_args > 1) { + MP_STATE_PORT(pin_class_map_dict) = args[1]; + return mp_const_none; + } + return MP_STATE_PORT(pin_class_map_dict); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pin_map_dict_fun_obj, 1, 2, pin_map_dict); +STATIC MP_DEFINE_CONST_CLASSMETHOD_OBJ(pin_map_dict_obj, (mp_obj_t)&pin_map_dict_fun_obj); + +/// \classmethod af_list() +/// Returns an array of alternate functions available for this pin. +STATIC mp_obj_t pin_af_list(mp_obj_t self_in) { + pin_obj_t *self = self_in; + mp_obj_t result = mp_obj_new_list(0, NULL); + + const pin_af_obj_t *af = self->af; + for (mp_uint_t i = 0; i < self->num_af; i++, af++) { + mp_obj_list_append(result, (mp_obj_t)af); + } + return result; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_af_list_obj, pin_af_list); + +/// \classmethod debug([state]) +/// Get or set the debugging state (`True` or `False` for on or off). +STATIC mp_obj_t pin_debug(mp_uint_t n_args, const mp_obj_t *args) { + if (n_args > 1) { + pin_class_debug = mp_obj_is_true(args[1]); + return mp_const_none; + } + return mp_obj_new_bool(pin_class_debug); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pin_debug_fun_obj, 1, 2, pin_debug); +STATIC MP_DEFINE_CONST_CLASSMETHOD_OBJ(pin_debug_obj, (mp_obj_t)&pin_debug_fun_obj); + +// init(mode, pull=None, af=-1, *, value, alt) +STATIC mp_obj_t pin_obj_init_helper(const pin_obj_t *self, mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + static const mp_arg_t allowed_args[] = { + { MP_QSTR_mode, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_pull, MP_ARG_OBJ, {.u_obj = mp_const_none}}, + { MP_QSTR_af, MP_ARG_INT, {.u_int = -1}}, // legacy + { MP_QSTR_value, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}}, + { MP_QSTR_alt, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1}}, + }; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // get pull mode + uint pull = HAL_GPIO_PULL_DISABLED; + if (args[1].u_obj != mp_const_none) { + pull = mp_obj_get_int(args[1].u_obj); + } + + // if given, set the pin value before initialising to prevent glitches + if (args[3].u_obj != MP_OBJ_NULL) { + mp_hal_pin_write(self, mp_obj_is_true(args[3].u_obj)); + } + + // get io mode + uint mode = args[0].u_int; + if (mode == HAL_GPIO_MODE_OUTPUT || mode == HAL_GPIO_MODE_INPUT) { + hal_gpio_cfg_pin(self->port, self->pin, mode, pull); + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "invalid pin mode: %d", mode)); + } + + return mp_const_none; +} + +STATIC mp_obj_t pin_obj_init(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { + return pin_obj_init_helper(args[0], n_args - 1, args + 1, kw_args); +} +MP_DEFINE_CONST_FUN_OBJ_KW(pin_init_obj, 1, pin_obj_init); + +/// \method value([value]) +/// Get or set the digital logic level of the pin: +/// +/// - With no argument, return 0 or 1 depending on the logic level of the pin. +/// - With `value` given, set the logic level of the pin. `value` can be +/// anything that converts to a boolean. If it converts to `True`, the pin +/// is set high, otherwise it is set low. +STATIC mp_obj_t pin_value(mp_uint_t n_args, const mp_obj_t *args) { + return pin_call(args[0], n_args - 1, 0, args + 1); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pin_value_obj, 1, 2, pin_value); + +/// \method low() +/// Set the pin to a low logic level. +STATIC mp_obj_t pin_low(mp_obj_t self_in) { + pin_obj_t *self = self_in; + mp_hal_pin_low(self); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_low_obj, pin_low); + +/// \method high() +/// Set the pin to a high logic level. +STATIC mp_obj_t pin_high(mp_obj_t self_in) { + pin_obj_t *self = self_in; + mp_hal_pin_high(self); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_high_obj, pin_high); + +/// \method name() +/// Get the pin name. +STATIC mp_obj_t pin_name(mp_obj_t self_in) { + pin_obj_t *self = self_in; + return MP_OBJ_NEW_QSTR(self->name); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_name_obj, pin_name); + +/// \method names() +/// Returns the cpu and board names for this pin. +STATIC mp_obj_t pin_names(mp_obj_t self_in) { + pin_obj_t *self = self_in; + mp_obj_t result = mp_obj_new_list(0, NULL); + mp_obj_list_append(result, MP_OBJ_NEW_QSTR(self->name)); + + mp_map_t *map = mp_obj_dict_get_map((mp_obj_t)&pin_board_pins_locals_dict); + mp_map_elem_t *elem = map->table; + + for (mp_uint_t i = 0; i < map->used; i++, elem++) { + if (elem->value == self) { + mp_obj_list_append(result, elem->key); + } + } + return result; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_names_obj, pin_names); + +/// \method port() +/// Get the pin port. +STATIC mp_obj_t pin_port(mp_obj_t self_in) { + pin_obj_t *self = self_in; + return MP_OBJ_NEW_SMALL_INT(self->port); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_port_obj, pin_port); + +/// \method pin() +/// Get the pin number. +STATIC mp_obj_t pin_pin(mp_obj_t self_in) { + pin_obj_t *self = self_in; + return MP_OBJ_NEW_SMALL_INT(self->pin); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_pin_obj, pin_pin); + +/// \method gpio() +/// Returns the base address of the GPIO block associated with this pin. +STATIC mp_obj_t pin_gpio(mp_obj_t self_in) { + pin_obj_t *self = self_in; + return MP_OBJ_NEW_SMALL_INT((mp_int_t)self->gpio); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_gpio_obj, pin_gpio); + +/// \method mode() +/// Returns the currently configured mode of the pin. The integer returned +/// will match one of the allowed constants for the mode argument to the init +/// function. +STATIC mp_obj_t pin_mode(mp_obj_t self_in) { + return mp_const_none; // TODO: MP_OBJ_NEW_SMALL_INT(pin_get_mode(self_in)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_mode_obj, pin_mode); + +/// \method pull() +/// Returns the currently configured pull of the pin. The integer returned +/// will match one of the allowed constants for the pull argument to the init +/// function. +STATIC mp_obj_t pin_pull(mp_obj_t self_in) { + return mp_const_none; // TODO: MP_OBJ_NEW_SMALL_INT(pin_get_pull(self_in)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_pull_obj, pin_pull); + +/// \method af() +/// Returns the currently configured alternate-function of the pin. The +/// integer returned will match one of the allowed constants for the af +/// argument to the init function. +STATIC mp_obj_t pin_af(mp_obj_t self_in) { + return mp_const_none; // TODO: MP_OBJ_NEW_SMALL_INT(pin_get_af(self_in)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_af_obj, pin_af); + +STATIC mp_obj_t pin_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + static const mp_arg_t allowed_args[] = { + { MP_QSTR_handler, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_trigger, MP_ARG_INT, {.u_int = HAL_GPIO_POLARITY_EVENT_TOGGLE} }, + { MP_QSTR_wake, MP_ARG_BOOL, {.u_bool = false} }, + }; + pin_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + (void)self; + + // return the irq object + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pin_irq_obj, 1, pin_irq); + + +STATIC const mp_rom_map_elem_t pin_locals_dict_table[] = { + // instance methods + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&pin_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&pin_value_obj) }, + { MP_ROM_QSTR(MP_QSTR_off), MP_ROM_PTR(&pin_off_obj) }, + { MP_ROM_QSTR(MP_QSTR_on), MP_ROM_PTR(&pin_on_obj) }, + { MP_ROM_QSTR(MP_QSTR_low), MP_ROM_PTR(&pin_low_obj) }, + { MP_ROM_QSTR(MP_QSTR_high), MP_ROM_PTR(&pin_high_obj) }, + { MP_ROM_QSTR(MP_QSTR_name), MP_ROM_PTR(&pin_name_obj) }, + { MP_ROM_QSTR(MP_QSTR_names), MP_ROM_PTR(&pin_names_obj) }, + { MP_ROM_QSTR(MP_QSTR_af_list), MP_ROM_PTR(&pin_af_list_obj) }, + { MP_ROM_QSTR(MP_QSTR_port), MP_ROM_PTR(&pin_port_obj) }, + { MP_ROM_QSTR(MP_QSTR_pin), MP_ROM_PTR(&pin_pin_obj) }, + { MP_ROM_QSTR(MP_QSTR_gpio), MP_ROM_PTR(&pin_gpio_obj) }, + { MP_ROM_QSTR(MP_QSTR_mode), MP_ROM_PTR(&pin_mode_obj) }, + { MP_ROM_QSTR(MP_QSTR_pull), MP_ROM_PTR(&pin_pull_obj) }, + { MP_ROM_QSTR(MP_QSTR_af), MP_ROM_PTR(&pin_af_obj) }, + { MP_ROM_QSTR(MP_QSTR_irq), MP_ROM_PTR(&pin_irq_obj) }, + + // class methods + { MP_ROM_QSTR(MP_QSTR_mapper), MP_ROM_PTR(&pin_mapper_obj) }, + { MP_ROM_QSTR(MP_QSTR_dict), MP_ROM_PTR(&pin_map_dict_obj) }, + { MP_ROM_QSTR(MP_QSTR_debug), MP_ROM_PTR(&pin_debug_obj) }, + + // class attributes + { MP_ROM_QSTR(MP_QSTR_board), MP_ROM_PTR(&pin_board_pins_obj_type) }, + { MP_ROM_QSTR(MP_QSTR_cpu), MP_ROM_PTR(&pin_cpu_pins_obj_type) }, + + // class constants + { MP_ROM_QSTR(MP_QSTR_IN), MP_ROM_INT(HAL_GPIO_MODE_INPUT) }, + { MP_ROM_QSTR(MP_QSTR_OUT), MP_ROM_INT(HAL_GPIO_MODE_OUTPUT) }, +/* + { MP_ROM_QSTR(MP_QSTR_OPEN_DRAIN), MP_ROM_INT(GPIO_MODE_OUTPUT_OD) }, + { MP_ROM_QSTR(MP_QSTR_ALT), MP_ROM_INT(GPIO_MODE_AF_PP) }, + { MP_ROM_QSTR(MP_QSTR_ALT_OPEN_DRAIN), MP_ROM_INT(GPIO_MODE_AF_OD) }, + { MP_ROM_QSTR(MP_QSTR_ANALOG), MP_ROM_INT(GPIO_MODE_ANALOG) }, +*/ + { MP_ROM_QSTR(MP_QSTR_PULL_DISABLED), MP_ROM_INT(HAL_GPIO_PULL_DISABLED) }, + { MP_ROM_QSTR(MP_QSTR_PULL_UP), MP_ROM_INT(HAL_GPIO_PULL_UP) }, + { MP_ROM_QSTR(MP_QSTR_PULL_DOWN), MP_ROM_INT(HAL_GPIO_PULL_DOWN) }, + + // IRQ triggers, can be or'd together + { MP_ROM_QSTR(MP_QSTR_IRQ_RISING), MP_ROM_INT(HAL_GPIO_POLARITY_EVENT_LOW_TO_HIGH) }, + { MP_ROM_QSTR(MP_QSTR_IRQ_FALLING), MP_ROM_INT(HAL_GPIO_POLARITY_EVENT_HIGH_TO_LOW) }, +/* + // legacy class constants + { MP_ROM_QSTR(MP_QSTR_OUT_PP), MP_ROM_INT(GPIO_MODE_OUTPUT_PP) }, + { MP_ROM_QSTR(MP_QSTR_OUT_OD), MP_ROM_INT(GPIO_MODE_OUTPUT_OD) }, + { MP_ROM_QSTR(MP_QSTR_AF_PP), MP_ROM_INT(GPIO_MODE_AF_PP) }, + { MP_ROM_QSTR(MP_QSTR_AF_OD), MP_ROM_INT(GPIO_MODE_AF_OD) }, + { MP_ROM_QSTR(MP_QSTR_PULL_NONE), MP_ROM_INT(GPIO_NOPULL) }, +*/ +#include "genhdr/pins_af_const.h" +}; + +STATIC MP_DEFINE_CONST_DICT(pin_locals_dict, pin_locals_dict_table); + +const mp_obj_type_t pin_type = { + { &mp_type_type }, + .name = MP_QSTR_Pin, + .print = pin_print, + .make_new = pin_make_new, + .call = pin_call, + .locals_dict = (mp_obj_dict_t*)&pin_locals_dict, +}; + +/// \moduleref pyb +/// \class PinAF - Pin Alternate Functions +/// +/// A Pin represents a physical pin on the microcprocessor. Each pin +/// can have a variety of functions (GPIO, I2C SDA, etc). Each PinAF +/// object represents a particular function for a pin. +/// +/// Usage Model: +/// +/// x3 = pyb.Pin.board.X3 +/// x3_af = x3.af_list() +/// +/// x3_af will now contain an array of PinAF objects which are availble on +/// pin X3. +/// +/// For the pyboard, x3_af would contain: +/// [Pin.AF1_TIM2, Pin.AF2_TIM5, Pin.AF3_TIM9, Pin.AF7_USART2] +/// +/// Normally, each peripheral would configure the af automatically, but sometimes +/// the same function is available on multiple pins, and having more control +/// is desired. +/// +/// To configure X3 to expose TIM2_CH3, you could use: +/// pin = pyb.Pin(pyb.Pin.board.X3, mode=pyb.Pin.AF_PP, af=pyb.Pin.AF1_TIM2) +/// or: +/// pin = pyb.Pin(pyb.Pin.board.X3, mode=pyb.Pin.AF_PP, af=1) + +/// \method __str__() +/// Return a string describing the alternate function. +STATIC void pin_af_obj_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + pin_af_obj_t *self = self_in; + mp_printf(print, "Pin.%q", self->name); +} + +/// \method index() +/// Return the alternate function index. +STATIC mp_obj_t pin_af_index(mp_obj_t self_in) { + pin_af_obj_t *af = self_in; + return MP_OBJ_NEW_SMALL_INT(af->idx); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_af_index_obj, pin_af_index); + +/// \method name() +/// Return the name of the alternate function. +STATIC mp_obj_t pin_af_name(mp_obj_t self_in) { + pin_af_obj_t *af = self_in; + return MP_OBJ_NEW_QSTR(af->name); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_af_name_obj, pin_af_name); + +/// \method reg() +/// Return the base register associated with the peripheral assigned to this +/// alternate function. +STATIC mp_obj_t pin_af_reg(mp_obj_t self_in) { + pin_af_obj_t *af = self_in; + return MP_OBJ_NEW_SMALL_INT((mp_uint_t)af->reg); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_af_reg_obj, pin_af_reg); + +STATIC const mp_rom_map_elem_t pin_af_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_index), MP_ROM_PTR(&pin_af_index_obj) }, + { MP_ROM_QSTR(MP_QSTR_name), MP_ROM_PTR(&pin_af_name_obj) }, + { MP_ROM_QSTR(MP_QSTR_reg), MP_ROM_PTR(&pin_af_reg_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(pin_af_locals_dict, pin_af_locals_dict_table); + +const mp_obj_type_t pin_af_type = { + { &mp_type_type }, + .name = MP_QSTR_PinAF, + .print = pin_af_obj_print, + .locals_dict = (mp_obj_dict_t*)&pin_af_locals_dict, +}; + +/******************************************************************************/ +// Pin IRQ object + +void gpio_irq_event_callback(hal_gpio_event_channel_t channel) { + // printf("### gpio irq received on channel %d\n", (uint16_t)channel); +} + +typedef struct _pin_irq_obj_t { + mp_obj_base_t base; + pin_obj_t pin; +} pin_irq_obj_t; + +// STATIC const mp_obj_type_t pin_irq_type; + +/*STATIC mp_obj_t pin_irq_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + pin_irq_obj_t *self = self_in; + (void)self; + return mp_const_none; +}*/ + +/*STATIC mp_obj_t pin_irq_trigger(size_t n_args, const mp_obj_t *args) { + pin_irq_obj_t *self = args[0]; + (void)self; + return mp_const_none; +}*/ +// STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pin_irq_trigger_obj, 1, 2, pin_irq_trigger); + +// STATIC const mp_rom_map_elem_t pin_irq_locals_dict_table[] = { +// { MP_ROM_QSTR(MP_QSTR_trigger), MP_ROM_PTR(&pin_irq_trigger_obj) }, +// }; + +// STATIC MP_DEFINE_CONST_DICT(pin_irq_locals_dict, pin_irq_locals_dict_table); + +/*STATIC const mp_obj_type_t pin_irq_type = { + { &mp_type_type }, + .name = MP_QSTR_IRQ, + .call = pin_irq_call, + .locals_dict = (mp_obj_dict_t*)&pin_irq_locals_dict, +};*/ diff --git a/ports/nrf/modules/machine/pin.h b/ports/nrf/modules/machine/pin.h new file mode 100644 index 000000000..1935a0d26 --- /dev/null +++ b/ports/nrf/modules/machine/pin.h @@ -0,0 +1,102 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef __MICROPY_INCLUDED_NRF5_PIN_H__ +#define __MICROPY_INCLUDED_NRF5_PIN_H__ + +// This file requires pin_defs_xxx.h (which has port specific enums and +// defines, so we include it here. It should never be included directly + +#include MICROPY_PIN_DEFS_PORT_H +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; + qstr name; + uint8_t idx; + uint8_t fn; + uint8_t unit; + uint8_t type; + + union { + void *reg; + + PIN_DEFS_PORT_AF_UNION + }; +} pin_af_obj_t; + +typedef struct { + mp_obj_base_t base; + qstr name; + uint32_t port : 4; + uint32_t pin : 5; // Some ARM processors use 32 bits/PORT + uint32_t num_af : 4; + uint32_t adc_channel : 5; // Some ARM processors use 32 bits/PORT + uint32_t adc_num : 3; // 1 bit per ADC + uint32_t pin_mask; + pin_gpio_t *gpio; + const pin_af_obj_t *af; + uint32_t pull; +} pin_obj_t; + +extern const mp_obj_type_t pin_type; +extern const mp_obj_type_t pin_af_type; + +typedef struct { + const char *name; + const pin_obj_t *pin; +} pin_named_pin_t; + +extern const pin_named_pin_t pin_board_pins[]; +extern const pin_named_pin_t pin_cpu_pins[]; + +//extern pin_map_obj_t pin_map_obj; + +typedef struct { + mp_obj_base_t base; + qstr name; + const pin_named_pin_t *named_pins; +} pin_named_pins_obj_t; + +extern const mp_obj_type_t pin_board_pins_obj_type; +extern const mp_obj_type_t pin_cpu_pins_obj_type; + +extern const mp_obj_dict_t pin_cpu_pins_locals_dict; +extern const mp_obj_dict_t pin_board_pins_locals_dict; + +MP_DECLARE_CONST_FUN_OBJ_KW(pin_init_obj); + +void pin_init0(void); +uint32_t pin_get_mode(const pin_obj_t *pin); +uint32_t pin_get_pull(const pin_obj_t *pin); +uint32_t pin_get_af(const pin_obj_t *pin); +const pin_obj_t *pin_find(mp_obj_t user_obj); +const pin_obj_t *pin_find_named_pin(const mp_obj_dict_t *named_pins, mp_obj_t name); +const pin_af_obj_t *pin_find_af(const pin_obj_t *pin, uint8_t fn, uint8_t unit); +const pin_af_obj_t *pin_find_af_by_index(const pin_obj_t *pin, mp_uint_t af_idx); +const pin_af_obj_t *pin_find_af_by_name(const pin_obj_t *pin, const char *name); + +#endif // __MICROPY_INCLUDED_NRF5_PIN_H__ diff --git a/ports/nrf/modules/machine/pwm.c b/ports/nrf/modules/machine/pwm.c new file mode 100644 index 000000000..eaba96606 --- /dev/null +++ b/ports/nrf/modules/machine/pwm.c @@ -0,0 +1,332 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include <stdio.h> +#include <string.h> + +#include "py/nlr.h" +#include "py/runtime.h" +#include "py/mphal.h" + +#if MICROPY_PY_MACHINE_HW_PWM + +#include "pin.h" +#include "genhdr/pins.h" +#include "pwm.h" + +#if NRF52 +// Use PWM hardware. +#include "hal_pwm.h" +#endif + +#ifdef MICROPY_HW_PWM0_NAME +PWM_HandleTypeDef PWMHandle0 = {.instance = NULL}; +#endif + +STATIC const pyb_pwm_obj_t machine_pwm_obj[] = { + #ifdef MICROPY_HW_PWM0_NAME + {{&machine_hard_pwm_type}, &PWMHandle0}, + #else + {{&machine_hard_pwm_type}, NULL}, + #endif +}; + +void pwm_init0(void) { + // reset the PWM handles + #ifdef MICROPY_HW_PWM0_NAME + memset(&PWMHandle0, 0, sizeof(PWM_HandleTypeDef)); + PWMHandle0.instance = PWM0; + #endif +} + +STATIC int pwm_find(mp_obj_t id) { + if (MP_OBJ_IS_STR(id)) { + // given a string id + const char *port = mp_obj_str_get_str(id); + if (0) { + #ifdef MICROPY_HW_PWM0_NAME + } else if (strcmp(port, MICROPY_HW_PWM0_NAME) == 0) { + return 1; + #endif + } + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "PWM(%s) does not exist", port)); + } else { + // given an integer id + int pwm_id = mp_obj_get_int(id); + if (pwm_id >= 0 && pwm_id <= MP_ARRAY_SIZE(machine_pwm_obj) + && machine_pwm_obj[pwm_id].pwm != NULL) { + return pwm_id; + } + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "PWM(%d) does not exist", pwm_id)); + } +} + +void pwm_init(PWM_HandleTypeDef *pwm) { + // start pwm + hal_pwm_start(pwm->instance); +} + +void pwm_deinit(PWM_HandleTypeDef *pwm) { + // stop pwm + hal_pwm_stop(pwm->instance); +} + +STATIC void pwm_print(const mp_print_t *print, PWM_HandleTypeDef *pwm, bool legacy) { + uint pwm_num = 0; // default to PWM0 + mp_printf(print, "PWM(%u)", pwm_num); +} + +/******************************************************************************/ +/* MicroPython bindings for machine API */ + +// for make_new +enum { + ARG_NEW_id, + ARG_NEW_pin, + ARG_NEW_freq, + ARG_NEW_period, + ARG_NEW_duty, + ARG_NEW_pulse_width, + ARG_NEW_mode +}; + +// for init +enum { + ARG_INIT_pin +}; + +// for freq +enum { + ARG_FREQ_freq +}; + +STATIC mp_obj_t machine_hard_pwm_make_new(mp_arg_val_t *args); +STATIC void machine_hard_pwm_init(mp_obj_t self, mp_arg_val_t *args); +STATIC void machine_hard_pwm_deinit(mp_obj_t self); +STATIC mp_obj_t machine_hard_pwm_freq(mp_obj_t self, mp_arg_val_t *args); + +/* common code for both soft and hard implementations *************************/ + +STATIC mp_obj_t machine_pwm_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + static const mp_arg_t allowed_args[] = { + { MP_QSTR_id, MP_ARG_OBJ, {.u_obj = MP_OBJ_NEW_SMALL_INT(-1)} }, + { MP_QSTR_pin, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_freq, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_period, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_duty, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_pulse_width, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_mode, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + }; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + if (args[ARG_NEW_id].u_obj == MP_OBJ_NEW_SMALL_INT(-1)) { + // TODO: implement soft PWM + // return machine_soft_pwm_make_new(args); + return mp_const_none; + } else { + // hardware peripheral id given + return machine_hard_pwm_make_new(args); + } +} + +STATIC mp_obj_t machine_pwm_init(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + static const mp_arg_t allowed_args[] = { + { MP_QSTR_pin, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} } + }; + + // parse args + mp_obj_t self = pos_args[0]; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // dispatch to specific implementation + if (mp_obj_get_type(self) == &machine_hard_pwm_type) { + machine_hard_pwm_init(self, args); + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_pwm_init_obj, 1, machine_pwm_init); + +STATIC mp_obj_t machine_pwm_deinit(mp_obj_t self) { + // dispatch to specific implementation + if (mp_obj_get_type(self) == &machine_hard_pwm_type) { + machine_hard_pwm_deinit(self); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_pwm_deinit_obj, machine_pwm_deinit); + +STATIC mp_obj_t machine_pwm_freq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + static const mp_arg_t allowed_args[] = { + { MP_QSTR_freq, MP_ARG_INT, {.u_int = -1} }, + }; + + mp_obj_t self = pos_args[0]; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + if (mp_obj_get_type(self) == &machine_hard_pwm_type) { + machine_hard_pwm_freq(self, args); + } else { + // soft pwm + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mp_machine_pwm_freq_obj, 1, machine_pwm_freq); + +STATIC mp_obj_t machine_pwm_period(size_t n_args, const mp_obj_t *args) { + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_pwm_period_obj, 1, 2, machine_pwm_period); + +STATIC mp_obj_t machine_pwm_duty(size_t n_args, const mp_obj_t *args) { + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_pwm_duty_obj, 1, 2, machine_pwm_duty); + +STATIC const mp_rom_map_elem_t machine_pwm_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_pwm_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&machine_pwm_deinit_obj) }, + + { MP_ROM_QSTR(MP_QSTR_freq), MP_ROM_PTR(&mp_machine_pwm_freq_obj) }, + { MP_ROM_QSTR(MP_QSTR_period), MP_ROM_PTR(&mp_machine_pwm_period_obj) }, + { MP_ROM_QSTR(MP_QSTR_duty), MP_ROM_PTR(&mp_machine_pwm_duty_obj) }, + + { MP_ROM_QSTR(MP_QSTR_FREQ_16MHZ), MP_ROM_INT(HAL_PWM_FREQ_16Mhz) }, + { MP_ROM_QSTR(MP_QSTR_FREQ_8MHZ), MP_ROM_INT(HAL_PWM_FREQ_8Mhz) }, + { MP_ROM_QSTR(MP_QSTR_FREQ_4MHZ), MP_ROM_INT(HAL_PWM_FREQ_4Mhz) }, + { MP_ROM_QSTR(MP_QSTR_FREQ_2MHZ), MP_ROM_INT(HAL_PWM_FREQ_2Mhz) }, + { MP_ROM_QSTR(MP_QSTR_FREQ_1MHZ), MP_ROM_INT(HAL_PWM_FREQ_1Mhz) }, + { MP_ROM_QSTR(MP_QSTR_FREQ_500KHZ), MP_ROM_INT(HAL_PWM_FREQ_500khz) }, + { MP_ROM_QSTR(MP_QSTR_FREQ_250KHZ), MP_ROM_INT(HAL_PWM_FREQ_250khz) }, + { MP_ROM_QSTR(MP_QSTR_FREQ_125KHZ), MP_ROM_INT(HAL_PWM_FREQ_125khz) }, + + { MP_ROM_QSTR(MP_QSTR_MODE_LOW_HIGH), MP_ROM_INT(HAL_PWM_MODE_LOW_HIGH) }, + { MP_ROM_QSTR(MP_QSTR_MODE_HIGH_LOW), MP_ROM_INT(HAL_PWM_MODE_HIGH_LOW) }, +}; + +STATIC MP_DEFINE_CONST_DICT(machine_pwm_locals_dict, machine_pwm_locals_dict_table); + +/* code for hard implementation ***********************************************/ + +STATIC const machine_hard_pwm_obj_t machine_hard_pwm_obj[] = { + {{&machine_hard_pwm_type}, &machine_pwm_obj[0]}, +}; + +STATIC void machine_hard_pwm_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + machine_hard_pwm_obj_t *self = self_in; + pwm_print(print, self->pyb->pwm, false); +} + +STATIC mp_obj_t machine_hard_pwm_make_new(mp_arg_val_t *args) { + // get static peripheral object + int pwm_id = pwm_find(args[ARG_NEW_id].u_obj); + const machine_hard_pwm_obj_t *self = &machine_hard_pwm_obj[pwm_id]; + + // check if PWM pin is set + if (args[ARG_NEW_pin].u_obj != MP_OBJ_NULL) { + pin_obj_t *pin_obj = args[ARG_NEW_pin].u_obj; + self->pyb->pwm->init.pwm_pin = pin_obj->pin; + } else { + // TODO: raise exception. + } + + if (args[ARG_NEW_freq].u_obj != MP_OBJ_NULL) { + self->pyb->pwm->init.freq = mp_obj_get_int(args[ARG_NEW_freq].u_obj); + } else { + self->pyb->pwm->init.freq = 50; // 50 Hz by default. + } + + if (args[ARG_NEW_period].u_obj != MP_OBJ_NULL) { + self->pyb->pwm->init.period = mp_obj_get_int(args[ARG_NEW_period].u_obj); + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "PWM period has to be within 16000 frequence cycles", self->pyb->pwm->init.period)); + } + + if (args[ARG_NEW_duty].u_obj != MP_OBJ_NULL) { + self->pyb->pwm->init.duty = mp_obj_get_int(args[ARG_NEW_duty].u_obj); + } else { + self->pyb->pwm->init.duty = 50; // 50% by default. + } + + if (args[ARG_NEW_pulse_width].u_obj != MP_OBJ_NULL) { + self->pyb->pwm->init.pulse_width = mp_obj_get_int(args[ARG_NEW_pulse_width].u_obj); + } else { + self->pyb->pwm->init.pulse_width = 0; + } + + if (args[ARG_NEW_mode].u_obj != MP_OBJ_NULL) { + self->pyb->pwm->init.mode = mp_obj_get_int(args[ARG_NEW_mode].u_obj); + } else { + self->pyb->pwm->init.mode = HAL_PWM_MODE_HIGH_LOW; + } + + hal_pwm_init(self->pyb->pwm->instance, &self->pyb->pwm->init); + + return MP_OBJ_FROM_PTR(self); +} + +STATIC void machine_hard_pwm_init(mp_obj_t self_in, mp_arg_val_t *args) { + machine_hard_pwm_obj_t *self = self_in; + pwm_init(self->pyb->pwm); +} + +STATIC void machine_hard_pwm_deinit(mp_obj_t self_in) { + machine_hard_pwm_obj_t *self = self_in; + pwm_deinit(self->pyb->pwm); +} + +STATIC mp_obj_t machine_hard_pwm_freq(mp_obj_t self_in, mp_arg_val_t *args) { + machine_hard_pwm_obj_t *self = self_in; + + if (args[ARG_FREQ_freq].u_int != -1) { + self->pyb->pwm->init.freq = args[ARG_FREQ_freq].u_int; + hal_pwm_init(self->pyb->pwm->instance, &self->pyb->pwm->init); + } else { + return MP_OBJ_NEW_SMALL_INT(self->pyb->pwm->init.freq); + } + + return mp_const_none; +} + + +const mp_obj_type_t machine_hard_pwm_type = { + { &mp_type_type }, + .name = MP_QSTR_PWM, + .print = machine_hard_pwm_print, + .make_new = machine_pwm_make_new, + .locals_dict = (mp_obj_dict_t*)&machine_pwm_locals_dict, +}; + +#endif // MICROPY_PY_MACHINE_HW_PWM diff --git a/ports/nrf/modules/machine/pwm.h b/ports/nrf/modules/machine/pwm.h new file mode 100644 index 000000000..85184bae0 --- /dev/null +++ b/ports/nrf/modules/machine/pwm.h @@ -0,0 +1,41 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "hal_pwm.h" + +typedef struct _pyb_pwm_obj_t { + mp_obj_base_t base; + PWM_HandleTypeDef *pwm; +} pyb_pwm_obj_t; + +typedef struct _machine_hard_pwm_obj_t { + mp_obj_base_t base; + const pyb_pwm_obj_t *pyb; +} machine_hard_pwm_obj_t; + +void pwm_init0(void); + +extern const mp_obj_type_t machine_hard_pwm_type; diff --git a/ports/nrf/modules/machine/rtc.c b/ports/nrf/modules/machine/rtc.c new file mode 100644 index 000000000..cbf9e6211 --- /dev/null +++ b/ports/nrf/modules/machine/rtc.c @@ -0,0 +1,178 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include <stdio.h> +#include <string.h> + +#include "py/nlr.h" +#include "py/runtime.h" +#include "py/mphal.h" +#include "rtc.h" +#include "hal_rtc.h" + +#if MICROPY_PY_MACHINE_RTC + +typedef struct _machine_rtc_obj_t { + mp_obj_base_t base; + hal_rtc_conf_t * p_config; + mp_obj_t callback; + mp_int_t period; + mp_int_t mode; +} machine_rtc_obj_t; + +static hal_rtc_conf_t rtc_config0 = {.id = 0}; +static hal_rtc_conf_t rtc_config1 = {.id = 1}; +#if NRF52 +static hal_rtc_conf_t rtc_config2 = {.id = 2}; +#endif + +STATIC machine_rtc_obj_t machine_rtc_obj[] = { + {{&machine_rtc_type}, &rtc_config0}, + {{&machine_rtc_type}, &rtc_config1}, +#if NRF52 + {{&machine_rtc_type}, &rtc_config2}, +#endif +}; + +STATIC void hal_interrupt_handle(uint8_t id) { + machine_rtc_obj_t * self = &machine_rtc_obj[id];; + + mp_call_function_1(self->callback, self); + + if (self != NULL) { + hal_rtc_stop(id); + if (self->mode == 1) { + hal_rtc_start(id); + } + } +} + +void rtc_init0(void) { + hal_rtc_callback_set(hal_interrupt_handle); +} + +STATIC int rtc_find(mp_obj_t id) { + // given an integer id + int rtc_id = mp_obj_get_int(id); + if (rtc_id >= 0 && rtc_id <= MP_ARRAY_SIZE(machine_rtc_obj) + && machine_rtc_obj[rtc_id].p_config != NULL) { + return rtc_id; + } + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "RTC(%d) does not exist", rtc_id)); +} + +STATIC void rtc_print(const mp_print_t *print, mp_obj_t o, mp_print_kind_t kind) { + machine_rtc_obj_t *self = o; + mp_printf(print, "RTC(%u)", self->p_config->id); +} + +/******************************************************************************/ +/* MicroPython bindings for machine API */ + +STATIC mp_obj_t machine_rtc_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + static const mp_arg_t allowed_args[] = { + { MP_QSTR_id, MP_ARG_OBJ, {.u_obj = MP_OBJ_NEW_SMALL_INT(-1)} }, + { MP_QSTR_period, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1000} }, + { MP_QSTR_mode, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, + { MP_QSTR_callback, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + }; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // get static peripheral object + int rtc_id = rtc_find(args[0].u_obj); + + // unconst machine object in order to set a callback. + machine_rtc_obj_t * self = (machine_rtc_obj_t *)&machine_rtc_obj[rtc_id]; + + self->p_config->period = args[1].u_int; + + self->mode = args[2].u_int; + + if (args[3].u_obj != mp_const_none) { + self->callback = args[3].u_obj; + } + +#ifdef NRF51 + self->p_config->irq_priority = 3; +#else + self->p_config->irq_priority = 6; +#endif + + hal_rtc_init(self->p_config); + + return MP_OBJ_FROM_PTR(self); +} + +/// \method start(period) +/// Start the RTC timer. Timeout occurs after number of periods +/// in the configured frequency has been reached. +/// +STATIC mp_obj_t machine_rtc_start(mp_obj_t self_in) { + machine_rtc_obj_t * self = MP_OBJ_TO_PTR(self_in); + + hal_rtc_start(self->p_config->id); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_rtc_start_obj, machine_rtc_start); + +/// \method stop() +/// Stop the RTC timer. +/// +STATIC mp_obj_t machine_rtc_stop(mp_obj_t self_in) { + machine_rtc_obj_t * self = MP_OBJ_TO_PTR(self_in); + + hal_rtc_stop(self->p_config->id); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_rtc_stop_obj, machine_rtc_stop); + + +STATIC const mp_rom_map_elem_t machine_rtc_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_start), MP_ROM_PTR(&machine_rtc_start_obj) }, + { MP_ROM_QSTR(MP_QSTR_stop), MP_ROM_PTR(&machine_rtc_stop_obj) }, + + // constants + { MP_ROM_QSTR(MP_QSTR_ONESHOT), MP_ROM_INT(0) }, + { MP_ROM_QSTR(MP_QSTR_PERIODIC), MP_ROM_INT(1) }, +}; + +STATIC MP_DEFINE_CONST_DICT(machine_rtc_locals_dict, machine_rtc_locals_dict_table); + +const mp_obj_type_t machine_rtc_type = { + { &mp_type_type }, + .name = MP_QSTR_RTC, + .print = rtc_print, + .make_new = machine_rtc_make_new, + .locals_dict = (mp_obj_dict_t*)&machine_rtc_locals_dict +}; + +#endif // MICROPY_PY_MACHINE_RTC diff --git a/ports/nrf/modules/machine/rtc.h b/ports/nrf/modules/machine/rtc.h new file mode 100644 index 000000000..6bf6efa6a --- /dev/null +++ b/ports/nrf/modules/machine/rtc.h @@ -0,0 +1,36 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef RTC_H__ +#define RTC_H__ + +#include "hal_rtc.h" + +extern const mp_obj_type_t machine_rtc_type; + +void rtc_init0(void); + +#endif // RTC_H__ diff --git a/ports/nrf/modules/machine/spi.c b/ports/nrf/modules/machine/spi.c new file mode 100644 index 000000000..0a82f1db5 --- /dev/null +++ b/ports/nrf/modules/machine/spi.c @@ -0,0 +1,377 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2016 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include <stdio.h> +#include <string.h> + +#include "py/nlr.h" +#include "py/runtime.h" +#include "py/mphal.h" +#include "extmod/machine_spi.h" +#include "pin.h" +#include "genhdr/pins.h" +#include "spi.h" +#include "hal_spi.h" + +#if MICROPY_PY_MACHINE_HW_SPI + +/// \moduleref pyb +/// \class SPI - a master-driven serial protocol +/// +/// SPI is a serial protocol that is driven by a master. At the physical level +/// there are 3 lines: SCK, MOSI, MISO. +/// +/// See usage model of I2C; SPI is very similar. Main difference is +/// parameters to init the SPI bus: +/// +/// from pyb import SPI +/// spi = SPI(1, SPI.MASTER, baudrate=600000, polarity=1, phase=0, crc=0x7) +/// +/// Only required parameter is mode, SPI.MASTER or SPI.SLAVE. Polarity can be +/// 0 or 1, and is the level the idle clock line sits at. Phase can be 0 or 1 +/// to sample data on the first or second clock edge respectively. Crc can be +/// None for no CRC, or a polynomial specifier. +/// +/// Additional method for SPI: +/// +/// data = spi.send_recv(b'1234') # send 4 bytes and receive 4 bytes +/// buf = bytearray(4) +/// spi.send_recv(b'1234', buf) # send 4 bytes and receive 4 into buf +/// spi.send_recv(buf, buf) # send/recv 4 bytes from/to buf + +SPI_HandleTypeDef SPIHandle0 = {.instance = NULL}; +SPI_HandleTypeDef SPIHandle1 = {.instance = NULL}; +#if NRF52 +SPI_HandleTypeDef SPIHandle2 = {.instance = NULL}; +#if NRF52840_XXAA +SPI_HandleTypeDef SPIHandle3 = {.instance = NULL}; // 32 Mbs master only +#endif // NRF52840_XXAA +#endif // NRF52 + +STATIC const machine_hard_spi_obj_t machine_hard_spi_obj[] = { + {{&machine_hard_spi_type}, &SPIHandle0}, + {{&machine_hard_spi_type}, &SPIHandle1}, +#if NRF52 + {{&machine_hard_spi_type}, &SPIHandle2}, +#if NRF52840_XXAA + {{&machine_hard_spi_type}, &SPIHandle3}, +#endif // NRF52840_XXAA +#endif // NRF52 + +}; + +void spi_init0(void) { + // reset the SPI handles + memset(&SPIHandle0, 0, sizeof(SPI_HandleTypeDef)); + SPIHandle0.instance = SPI_BASE(0); + memset(&SPIHandle1, 0, sizeof(SPI_HandleTypeDef)); + SPIHandle1.instance = SPI_BASE(1); +#if NRF52 + memset(&SPIHandle2, 0, sizeof(SPI_HandleTypeDef)); + SPIHandle2.instance = SPI_BASE(2); +#if NRF52840_XXAA + memset(&SPIHandle3, 0, sizeof(SPI_HandleTypeDef)); + SPIHandle3.instance = SPI_BASE(3); +#endif // NRF52840_XXAA +#endif // NRF52 +} + +STATIC int spi_find(mp_obj_t id) { + if (MP_OBJ_IS_STR(id)) { + // given a string id + const char *port = mp_obj_str_get_str(id); + if (0) { + #ifdef MICROPY_HW_SPI0_NAME + } else if (strcmp(port, MICROPY_HW_SPI0_NAME) == 0) { + return 1; + #endif + } + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "SPI(%s) does not exist", port)); + } else { + // given an integer id + int spi_id = mp_obj_get_int(id); + if (spi_id >= 0 && spi_id <= MP_ARRAY_SIZE(machine_hard_spi_obj) + && machine_hard_spi_obj[spi_id].spi != NULL) { + return spi_id; + } + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "SPI(%d) does not exist", spi_id)); + } +} + +void spi_init(SPI_HandleTypeDef *spi, bool enable_nss_pin) { +} + +void spi_deinit(SPI_HandleTypeDef *spi) { +} + +STATIC void spi_transfer(const machine_hard_spi_obj_t * self, size_t len, const void * src, void * dest) { + hal_spi_master_tx_rx(self->spi->instance, len, src, dest); +} + +STATIC void spi_print(const mp_print_t *print, SPI_HandleTypeDef *spi, bool legacy) { + uint spi_num = 0; // default to SPI1 + mp_printf(print, "SPI(%u)", spi_num); +} + +/******************************************************************************/ +/* MicroPython bindings for machine API */ + +// for make_new +enum { + ARG_NEW_id, + ARG_NEW_baudrate, + ARG_NEW_polarity, + ARG_NEW_phase, + ARG_NEW_bits, + ARG_NEW_firstbit, + ARG_NEW_sck, + ARG_NEW_mosi, + ARG_NEW_miso +}; + +// for init +enum { + ARG_INIT_baudrate, + ARG_INIT_polarity, + ARG_INIT_phase, + ARG_INIT_bits, + ARG_INIT_firstbit +}; + +STATIC mp_obj_t machine_hard_spi_make_new(mp_arg_val_t *args); +STATIC void machine_hard_spi_init(mp_obj_t self, mp_arg_val_t *args); +STATIC void machine_hard_spi_deinit(mp_obj_t self); + +/* common code for both soft and hard implementations *************************/ + +STATIC mp_obj_t machine_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + static const mp_arg_t allowed_args[] = { + { MP_QSTR_id, MP_ARG_OBJ, {.u_obj = MP_OBJ_NEW_SMALL_INT(-1)} }, + { MP_QSTR_baudrate, MP_ARG_INT, {.u_int = 500000} }, + { MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_phase, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} }, + { MP_QSTR_firstbit, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0 /* SPI_FIRSTBIT_MSB */} }, + { MP_QSTR_sck, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_mosi, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_miso, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + }; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + if (args[ARG_NEW_id].u_obj == MP_OBJ_NEW_SMALL_INT(-1)) { + // TODO: implement soft SPI + // return machine_soft_spi_make_new(args); + return mp_const_none; + } else { + // hardware peripheral id given + return machine_hard_spi_make_new(args); + } +} + +STATIC mp_obj_t machine_spi_init(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + static const mp_arg_t allowed_args[] = { + { MP_QSTR_baudrate, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_phase, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_firstbit, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, + }; + + // parse args + mp_obj_t self = pos_args[0]; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // dispatch to specific implementation + if (mp_obj_get_type(self) == &machine_hard_spi_type) { + machine_hard_spi_init(self, args); + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_spi_init_obj, 1, machine_spi_init); + +STATIC mp_obj_t machine_spi_deinit(mp_obj_t self) { + // dispatch to specific implementation + if (mp_obj_get_type(self) == &machine_hard_spi_type) { + machine_hard_spi_deinit(self); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_spi_deinit_obj, machine_spi_deinit); + +STATIC const mp_rom_map_elem_t machine_spi_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_spi_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&machine_spi_deinit_obj) }, + + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_machine_spi_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_machine_spi_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_machine_spi_write_obj) }, + { MP_ROM_QSTR(MP_QSTR_write_readinto), MP_ROM_PTR(&mp_machine_spi_write_readinto_obj) }, + + { MP_ROM_QSTR(MP_QSTR_MSB), MP_ROM_INT(HAL_SPI_MSB_FIRST) }, // SPI_FIRSTBIT_MSB + { MP_ROM_QSTR(MP_QSTR_LSB), MP_ROM_INT(HAL_SPI_LSB_FIRST) }, // SPI_FIRSTBIT_LSB +}; + +STATIC MP_DEFINE_CONST_DICT(machine_spi_locals_dict, machine_spi_locals_dict_table); + +/* code for hard implementation ***********************************************/ + +STATIC void machine_hard_spi_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + machine_hard_spi_obj_t *self = self_in; + spi_print(print, self->spi, false); +} + +STATIC mp_obj_t machine_hard_spi_make_new(mp_arg_val_t *args) { + // get static peripheral object + int spi_id = spi_find(args[ARG_NEW_id].u_obj); + const machine_hard_spi_obj_t *self = &machine_hard_spi_obj[spi_id]; + + // here we would check the sck/mosi/miso pins and configure them + if (args[ARG_NEW_sck].u_obj != MP_OBJ_NULL + && args[ARG_NEW_mosi].u_obj != MP_OBJ_NULL + && args[ARG_NEW_miso].u_obj != MP_OBJ_NULL) { + + self->spi->init.clk_pin = args[ARG_NEW_sck].u_obj; + self->spi->init.mosi_pin = args[ARG_NEW_mosi].u_obj; + self->spi->init.miso_pin = args[ARG_NEW_miso].u_obj; + } else { + self->spi->init.clk_pin = &MICROPY_HW_SPI0_SCK; + self->spi->init.mosi_pin = &MICROPY_HW_SPI0_MOSI; + self->spi->init.miso_pin = &MICROPY_HW_SPI0_MISO; + } + + int baudrate = args[ARG_NEW_baudrate].u_int; + + if (baudrate <= 125000) { + self->spi->init.freq = HAL_SPI_FREQ_125_Kbps; + } else if (baudrate <= 250000) { + self->spi->init.freq = HAL_SPI_FREQ_250_Kbps; + } else if (baudrate <= 500000) { + self->spi->init.freq = HAL_SPI_FREQ_500_Kbps; + } else if (baudrate <= 1000000) { + self->spi->init.freq = HAL_SPI_FREQ_1_Mbps; + } else if (baudrate <= 2000000) { + self->spi->init.freq = HAL_SPI_FREQ_2_Mbps; + } else if (baudrate <= 4000000) { + self->spi->init.freq = HAL_SPI_FREQ_4_Mbps; + } else if (baudrate <= 8000000) { + self->spi->init.freq = HAL_SPI_FREQ_8_Mbps; +#if NRF52840_XXAA + } else if (baudrate <= 16000000) { + self->spi->init.freq = HAL_SPI_FREQ_16_Mbps; + } else if (baudrate <= 32000000) { + self->spi->init.freq = HAL_SPI_FREQ_32_Mbps; +#endif + } else { // Default + self->spi->init.freq = HAL_SPI_FREQ_1_Mbps; + } +#ifdef NRF51 + self->spi->init.irq_priority = 3; +#else + self->spi->init.irq_priority = 6; +#endif + self->spi->init.mode = HAL_SPI_MODE_CPOL0_CPHA0; + self->spi->init.firstbit = (args[ARG_NEW_firstbit].u_int == 0) ? HAL_SPI_MSB_FIRST : HAL_SPI_LSB_FIRST;; + hal_spi_master_init(self->spi->instance, &self->spi->init); + + return MP_OBJ_FROM_PTR(self); +} + +STATIC void machine_hard_spi_init(mp_obj_t self_in, mp_arg_val_t *args) { +} + +STATIC void machine_hard_spi_deinit(mp_obj_t self_in) { + machine_hard_spi_obj_t *self = self_in; + spi_deinit(self->spi); +} + +STATIC void machine_hard_spi_transfer(mp_obj_base_t *self_in, size_t len, const uint8_t *src, uint8_t *dest) { + machine_hard_spi_obj_t *self = (machine_hard_spi_obj_t*)self_in; + spi_transfer(self, len, src, dest); +} + + +STATIC mp_obj_t mp_machine_spi_read(size_t n_args, const mp_obj_t *args) { + vstr_t vstr; + vstr_init_len(&vstr, mp_obj_get_int(args[1])); + memset(vstr.buf, n_args == 3 ? mp_obj_get_int(args[2]) : 0, vstr.len); + spi_transfer(args[0], vstr.len, vstr.buf, vstr.buf); + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_spi_read_obj, 2, 3, mp_machine_spi_read); + +STATIC mp_obj_t mp_machine_spi_readinto(size_t n_args, const mp_obj_t *args) { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_WRITE); + memset(bufinfo.buf, n_args == 3 ? mp_obj_get_int(args[2]) : 0, bufinfo.len); + spi_transfer(args[0], bufinfo.len, bufinfo.buf, bufinfo.buf); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_spi_readinto_obj, 2, 3, mp_machine_spi_readinto); + +STATIC mp_obj_t mp_machine_spi_write(mp_obj_t self, mp_obj_t wr_buf) { + mp_buffer_info_t src; + mp_get_buffer_raise(wr_buf, &src, MP_BUFFER_READ); + spi_transfer(self, src.len, (const uint8_t*)src.buf, NULL); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(mp_machine_spi_write_obj, mp_machine_spi_write); + +STATIC mp_obj_t mp_machine_spi_write_readinto(mp_obj_t self, mp_obj_t wr_buf, mp_obj_t rd_buf) { + mp_buffer_info_t src; + mp_get_buffer_raise(wr_buf, &src, MP_BUFFER_READ); + mp_buffer_info_t dest; + mp_get_buffer_raise(rd_buf, &dest, MP_BUFFER_WRITE); + if (src.len != dest.len) { + mp_raise_ValueError("buffers must be the same length"); + } + spi_transfer(self, src.len, src.buf, dest.buf); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_3(mp_machine_spi_write_readinto_obj, mp_machine_spi_write_readinto); + + +STATIC const mp_machine_spi_p_t machine_hard_spi_p = { + .transfer = machine_hard_spi_transfer, +}; + +const mp_obj_type_t machine_hard_spi_type = { + { &mp_type_type }, + .name = MP_QSTR_SPI, + .print = machine_hard_spi_print, + .make_new = machine_spi_make_new, + .protocol = &machine_hard_spi_p, + .locals_dict = (mp_obj_dict_t*)&machine_spi_locals_dict, +}; + +#endif // MICROPY_PY_MACHINE_HW_SPI diff --git a/ports/nrf/modules/machine/spi.h b/ports/nrf/modules/machine/spi.h new file mode 100644 index 000000000..71053fc27 --- /dev/null +++ b/ports/nrf/modules/machine/spi.h @@ -0,0 +1,38 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2016 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "py/obj.h" + +#include "hal_spi.h" + +typedef struct _machine_hard_spi_obj_t { + mp_obj_base_t base; + SPI_HandleTypeDef *spi; +} machine_hard_spi_obj_t; + +extern const mp_obj_type_t machine_hard_spi_type; + +void spi_init0(void); diff --git a/ports/nrf/modules/machine/temp.c b/ports/nrf/modules/machine/temp.c new file mode 100644 index 000000000..9f1840c6e --- /dev/null +++ b/ports/nrf/modules/machine/temp.c @@ -0,0 +1,96 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Bander F. Ajba + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include <stdio.h> +#include <string.h> + +#include "py/nlr.h" +#include "py/runtime.h" +#include "py/mphal.h" +#include "temp.h" +#include "hal_temp.h" + +#if MICROPY_PY_MACHINE_TEMP + +typedef struct _machine_temp_obj_t { + mp_obj_base_t base; +} machine_temp_obj_t; + +/// \method __str__() +/// Return a string describing the Temp object. +STATIC void machine_temp_print(const mp_print_t *print, mp_obj_t o, mp_print_kind_t kind) { + machine_temp_obj_t *self = o; + + (void)self; + + mp_printf(print, "Temp"); +} + +/******************************************************************************/ +/* MicroPython bindings for machine API */ + +STATIC mp_obj_t machine_temp_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + static const mp_arg_t allowed_args[] = { + { }, + }; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + machine_temp_obj_t *self = m_new_obj(machine_temp_obj_t); + + self->base.type = &machine_temp_type; + + return MP_OBJ_FROM_PTR(self); +} + +/// \method read() +/// Get temperature. +STATIC mp_obj_t machine_temp_read(mp_uint_t n_args, const mp_obj_t *args) { + + return MP_OBJ_NEW_SMALL_INT(hal_temp_read()); +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_temp_read_obj, 0, 1, machine_temp_read); + +STATIC const mp_rom_map_elem_t machine_temp_locals_dict_table[] = { + // instance methods + // class methods + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_machine_temp_read_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(machine_temp_locals_dict, machine_temp_locals_dict_table); + +const mp_obj_type_t machine_temp_type = { + { &mp_type_type }, + .name = MP_QSTR_Temp, + .make_new = machine_temp_make_new, + .locals_dict = (mp_obj_dict_t*)&machine_temp_locals_dict, + .print = machine_temp_print, +}; + +#endif // MICROPY_PY_MACHINE_TEMP diff --git a/ports/nrf/modules/machine/temp.h b/ports/nrf/modules/machine/temp.h new file mode 100644 index 000000000..e8f751bdf --- /dev/null +++ b/ports/nrf/modules/machine/temp.h @@ -0,0 +1,34 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Bander F. Ajba + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef TEMP_H__ +#define TEMP_H__ + +extern const mp_obj_type_t machine_temp_type; + +int32_t temp_read(void); + +#endif // TEMP_H__ diff --git a/ports/nrf/modules/machine/timer.c b/ports/nrf/modules/machine/timer.c new file mode 100644 index 000000000..c8eb2ef30 --- /dev/null +++ b/ports/nrf/modules/machine/timer.c @@ -0,0 +1,194 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include <stdio.h> +#include <string.h> + +#include "py/nlr.h" +#include "py/runtime.h" +#include "py/mphal.h" +#include "timer.h" +#include "hal_timer.h" + +#if MICROPY_PY_MACHINE_TIMER + +typedef struct _machine_timer_obj_t { + mp_obj_base_t base; + hal_timer_conf_t * p_config; + mp_obj_t callback; + mp_int_t period; + mp_int_t mode; +} machine_timer_obj_t; + +static hal_timer_conf_t timer_config0 = {.id = 0}; +static hal_timer_conf_t timer_config1 = {.id = 1}; +static hal_timer_conf_t timer_config2 = {.id = 2}; + +#if NRF52 +static hal_timer_conf_t timer_config3 = {.id = 3}; +static hal_timer_conf_t timer_config4 = {.id = 4}; +#endif + +STATIC machine_timer_obj_t machine_timer_obj[] = { + {{&machine_timer_type}, &timer_config0}, + {{&machine_timer_type}, &timer_config1}, + {{&machine_timer_type}, &timer_config2}, +#if NRF52 + {{&machine_timer_type}, &timer_config3}, + {{&machine_timer_type}, &timer_config4}, +#endif +}; + +STATIC void hal_interrupt_handle(uint8_t id) { + machine_timer_obj_t * self = &machine_timer_obj[id]; + + mp_call_function_1(self->callback, self); + + if (self != NULL) { + hal_timer_stop(id); + if (self->mode == 1) { + hal_timer_start(id); + } + } +} + +void timer_init0(void) { + hal_timer_callback_set(hal_interrupt_handle); +} + +STATIC int timer_find(mp_obj_t id) { + // given an integer id + int timer_id = mp_obj_get_int(id); + if (timer_id >= 0 && timer_id < MP_ARRAY_SIZE(machine_timer_obj) + && machine_timer_obj[timer_id].p_config != NULL) { + return timer_id; + } + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "Timer(%d) does not exist", timer_id)); +} + +STATIC void timer_print(const mp_print_t *print, mp_obj_t o, mp_print_kind_t kind) { + machine_timer_obj_t *self = o; + mp_printf(print, "Timer(%u)", self->p_config->id); +} + +/******************************************************************************/ +/* MicroPython bindings for machine API */ + +STATIC mp_obj_t machine_timer_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + static const mp_arg_t allowed_args[] = { + { MP_QSTR_id, MP_ARG_OBJ, {.u_obj = MP_OBJ_NEW_SMALL_INT(-1)} }, + { MP_QSTR_period, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1000} }, + { MP_QSTR_mode, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, + { MP_QSTR_callback, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + }; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // get static peripheral object + int timer_id = timer_find(args[0].u_obj); + +#if BLUETOOTH_SD + if (timer_id == 0) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "Timer(%d) reserved by Bluetooth LE stack.", timer_id)); + } +#endif + +#if MICROPY_PY_MACHINE_SOFT_PWM + if (timer_id == 1) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "Timer(%d) reserved by ticker driver.", timer_id)); + } +#endif + + machine_timer_obj_t *self = &machine_timer_obj[timer_id]; + + self->p_config->period = args[1].u_int; + + self->mode = args[2].u_int; + + if (args[3].u_obj != mp_const_none) { + self->callback = args[3].u_obj; + } + +#ifdef NRF51 + self->p_config->irq_priority = 3; +#else + self->p_config->irq_priority = 6; +#endif + + hal_timer_init(self->p_config); + + return MP_OBJ_FROM_PTR(self); +} + +/// \method start(period) +/// Start the timer. +/// +STATIC mp_obj_t machine_timer_start(mp_obj_t self_in) { + machine_timer_obj_t * self = MP_OBJ_TO_PTR(self_in); + + hal_timer_start(self->p_config->id); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_timer_start_obj, machine_timer_start); + +/// \method stop() +/// Stop the timer. +/// +STATIC mp_obj_t machine_timer_stop(mp_obj_t self_in) { + machine_timer_obj_t * self = MP_OBJ_TO_PTR(self_in); + + hal_timer_stop(self->p_config->id); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_timer_stop_obj, machine_timer_stop); + +STATIC const mp_rom_map_elem_t machine_timer_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_start), MP_ROM_PTR(&machine_timer_start_obj) }, + { MP_ROM_QSTR(MP_QSTR_stop), MP_ROM_PTR(&machine_timer_stop_obj) }, + + // constants + { MP_ROM_QSTR(MP_QSTR_ONESHOT), MP_ROM_INT(0) }, + { MP_ROM_QSTR(MP_QSTR_PERIODIC), MP_ROM_INT(1) }, +}; + +STATIC MP_DEFINE_CONST_DICT(machine_timer_locals_dict, machine_timer_locals_dict_table); + +const mp_obj_type_t machine_timer_type = { + { &mp_type_type }, + .name = MP_QSTR_Timer, + .print = timer_print, + .make_new = machine_timer_make_new, + .locals_dict = (mp_obj_dict_t*)&machine_timer_locals_dict +}; + +#endif // MICROPY_PY_MACHINE_TIMER diff --git a/ports/nrf/modules/machine/timer.h b/ports/nrf/modules/machine/timer.h new file mode 100644 index 000000000..2989dc69b --- /dev/null +++ b/ports/nrf/modules/machine/timer.h @@ -0,0 +1,36 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef TIMER_H__ +#define TIMER_H__ + +#include "hal_timer.h" + +extern const mp_obj_type_t machine_timer_type; + +void timer_init0(void); + +#endif // TIMER_H__ diff --git a/ports/nrf/modules/machine/uart.c b/ports/nrf/modules/machine/uart.c new file mode 100644 index 000000000..b99afef62 --- /dev/null +++ b/ports/nrf/modules/machine/uart.c @@ -0,0 +1,382 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2015 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include <stdbool.h> +#include <string.h> +#include <stdarg.h> + +#include "py/nlr.h" +#include "py/runtime.h" +#include "py/stream.h" +#include "py/mperrno.h" +#include "py/mphal.h" +#include "pin.h" +#include "genhdr/pins.h" + +#include "uart.h" +#include "mpconfigboard.h" +#include "nrf.h" +#include "mphalport.h" +#include "hal_uart.h" + +typedef struct _machine_hard_uart_obj_t { + mp_obj_base_t base; + UART_HandleTypeDef * uart; + byte char_width; // 0 for 7,8 bit chars, 1 for 9 bit chars +} machine_hard_uart_obj_t; + +UART_HandleTypeDef UARTHandle0 = {.p_instance = NULL, .init.id = 0}; +#if NRF52840_XXAA +UART_HandleTypeDef UARTHandle1 = {.p_instance = NULL, .init.id = 1}; +#endif + +STATIC machine_hard_uart_obj_t machine_hard_uart_obj[] = { + {{&machine_hard_uart_type}, &UARTHandle0}, +#if NRF52840_XXAA + {{&machine_hard_uart_type}, &UARTHandle1}, +#endif +}; + +void uart_init0(void) { + // reset the UART handles + memset(&UARTHandle0, 0, sizeof(UART_HandleTypeDef)); + UARTHandle0.p_instance = UART_BASE(0); +#if NRF52840_XXAA + memset(&UARTHandle1, 0, sizeof(UART_HandleTypeDef)); + UARTHandle0.p_instance = UART_BASE(1); +#endif +} + +STATIC int uart_find(mp_obj_t id) { + // given an integer id + int uart_id = mp_obj_get_int(id); + if (uart_id >= 0 && uart_id <= MP_ARRAY_SIZE(machine_hard_uart_obj) + && machine_hard_uart_obj[uart_id].uart != NULL) { + return uart_id; + } + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "UART(%d) does not exist", uart_id)); +} + +void uart_irq_handler(mp_uint_t uart_id) { + +} + +bool uart_rx_any(machine_hard_uart_obj_t *uart_obj) { + // TODO: uart will block for now. + return true; +} + +int uart_rx_char(machine_hard_uart_obj_t * self) { + uint8_t ch; + hal_uart_char_read(self->uart->p_instance, &ch); + return (int)ch; +} + +STATIC hal_uart_error_t uart_tx_char(machine_hard_uart_obj_t * self, int c) { + return hal_uart_char_write(self->uart->p_instance, (char)c); +} + + +void uart_tx_strn(machine_hard_uart_obj_t *uart_obj, const char *str, uint len) { + for (const char *top = str + len; str < top; str++) { + uart_tx_char(uart_obj, *str); + } +} + +void uart_tx_strn_cooked(machine_hard_uart_obj_t *uart_obj, const char *str, uint len) { + for (const char *top = str + len; str < top; str++) { + if (*str == '\n') { + uart_tx_char(uart_obj, '\r'); + } + uart_tx_char(uart_obj, *str); + } +} + +/******************************************************************************/ +/* MicroPython bindings */ + +STATIC void machine_hard_uart_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { +} + + + +/// \method init(baudrate, bits=8, parity=None, stop=1, *, timeout=1000, timeout_char=0, read_buf_len=64) +/// +/// Initialise the UART bus with the given parameters: +/// - `id`is bus id. +/// - `baudrate` is the clock rate. +/// - `bits` is the number of bits per byte, 7, 8 or 9. +/// - `parity` is the parity, `None`, 0 (even) or 1 (odd). +/// - `stop` is the number of stop bits, 1 or 2. +/// - `timeout` is the timeout in milliseconds to wait for the first character. +/// - `timeout_char` is the timeout in milliseconds to wait between characters. +/// - `read_buf_len` is the character length of the read buffer (0 to disable). +STATIC mp_obj_t machine_hard_uart_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + static const mp_arg_t allowed_args[] = { + { MP_QSTR_id, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_baudrate, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 9600} }, + { MP_QSTR_bits, MP_ARG_INT, {.u_int = 8} }, + { MP_QSTR_parity, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_stop, MP_ARG_INT, {.u_int = 1} }, + { MP_QSTR_flow, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1000} }, + { MP_QSTR_timeout_char, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_read_buf_len, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 64} }, + }; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // get static peripheral object + int uart_id = uart_find(args[0].u_obj); + machine_hard_uart_obj_t * self = &machine_hard_uart_obj[uart_id]; + + hal_uart_init_t * init = &self->uart->init; + + // flow control + init->flow_control = args[5].u_int; + +#if MICROPY_HW_UART1_HWFC + init->flow_control = true; +#else + init->flow_control = false; +#endif + init->use_parity = false; +#if (BLUETOOTH_SD == 100) + init->irq_priority = 3; +#else + init->irq_priority = 6; +#endif + + switch (args[1].u_int) { + case 1200: + init->baud_rate = HAL_UART_BAUD_1K2; + break; + case 2400: + init->baud_rate = HAL_UART_BAUD_2K4; + break; + case 4800: + init->baud_rate = HAL_UART_BAUD_4K8; + break; + case 9600: + init->baud_rate = HAL_UART_BAUD_9K6; + break; + case 14400: + init->baud_rate = HAL_UART_BAUD_14K4; + break; + case 19200: + init->baud_rate = HAL_UART_BAUD_19K2; + break; + case 28800: + init->baud_rate = HAL_UART_BAUD_28K8; + break; + case 38400: + init->baud_rate = HAL_UART_BAUD_38K4; + break; + case 57600: + init->baud_rate = HAL_UART_BAUD_57K6; + break; + case 76800: + init->baud_rate = HAL_UART_BAUD_76K8; + break; + case 115200: + init->baud_rate = HAL_UART_BAUD_115K2; + break; + case 230400: + init->baud_rate = HAL_UART_BAUD_230K4; + break; + case 250000: + init->baud_rate = HAL_UART_BAUD_250K0; + break; + case 500000: + init->baud_rate = HAL_UART_BAUD_500K0; + break; + case 1000000: + init->baud_rate = HAL_UART_BAUD_1M0; + break; + default: + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "UART baudrate not supported, %ul", init->baud_rate)); + break; + } + + init->rx_pin = &MICROPY_HW_UART1_RX; + init->tx_pin = &MICROPY_HW_UART1_TX; + +#if MICROPY_HW_UART1_HWFC + init->rts_pin = &MICROPY_HW_UART1_RTS; + init->cts_pin = &MICROPY_HW_UART1_CTS; +#endif + + hal_uart_init(self->uart->p_instance, init); + + return MP_OBJ_FROM_PTR(self); +} + +/// \method writechar(char) +/// Write a single character on the bus. `char` is an integer to write. +/// Return value: `None`. +STATIC mp_obj_t machine_hard_uart_writechar(mp_obj_t self_in, mp_obj_t char_in) { + machine_hard_uart_obj_t *self = self_in; + + // get the character to write (might be 9 bits) + uint16_t data = mp_obj_get_int(char_in); + + hal_uart_error_t err = 0; + for (int i = 0; i < 2; i++) { + err = uart_tx_char(self, (int)(&data)[i]); + } + + HAL_StatusTypeDef status = self->uart->p_instance->EVENTS_ERROR; + + if (err != HAL_UART_ERROR_NONE) { + mp_hal_raise(status); + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(machine_hard_uart_writechar_obj, machine_hard_uart_writechar); + +/// \method readchar() +/// Receive a single character on the bus. +/// Return value: The character read, as an integer. Returns -1 on timeout. +STATIC mp_obj_t machine_hard_uart_readchar(mp_obj_t self_in) { + machine_hard_uart_obj_t *self = self_in; + return MP_OBJ_NEW_SMALL_INT(uart_rx_char(self)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_hard_uart_readchar_obj, machine_hard_uart_readchar); + +// uart.sendbreak() +STATIC mp_obj_t machine_hard_uart_sendbreak(mp_obj_t self_in) { + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_hard_uart_sendbreak_obj, machine_hard_uart_sendbreak); + +STATIC const mp_rom_map_elem_t machine_hard_uart_locals_dict_table[] = { + // instance methods + /// \method read([nbytes]) + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, + /// \method readline() + { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) }, + /// \method readinto(buf[, nbytes]) + { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, + /// \method writechar(buf) + { MP_ROM_QSTR(MP_QSTR_writechar), MP_ROM_PTR(&machine_hard_uart_writechar_obj) }, + { MP_ROM_QSTR(MP_QSTR_readchar), MP_ROM_PTR(&machine_hard_uart_readchar_obj) }, + { MP_ROM_QSTR(MP_QSTR_sendbreak), MP_ROM_PTR(&machine_hard_uart_sendbreak_obj) }, + + // class constants +/* + { MP_ROM_QSTR(MP_QSTR_RTS), MP_ROM_INT(UART_HWCONTROL_RTS) }, + { MP_ROM_QSTR(MP_QSTR_CTS), MP_ROM_INT(UART_HWCONTROL_CTS) }, +*/ +}; + +STATIC MP_DEFINE_CONST_DICT(machine_hard_uart_locals_dict, machine_hard_uart_locals_dict_table); + +STATIC mp_uint_t machine_hard_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, int *errcode) { + machine_hard_uart_obj_t *self = self_in; + byte *buf = buf_in; + + // check that size is a multiple of character width + if (size & self->char_width) { + *errcode = MP_EIO; + return MP_STREAM_ERROR; + } + + // convert byte size to char size + size >>= self->char_width; + + // make sure we want at least 1 char + if (size == 0) { + return 0; + } + + // read the data + byte * orig_buf = buf; + for (;;) { + int data = uart_rx_char(self); + + *buf++ = data; + + if (--size == 0) { + // return number of bytes read + return buf - orig_buf; + } + } +} + +STATIC mp_uint_t machine_hard_uart_write(mp_obj_t self_in, const void *buf_in, mp_uint_t size, int *errcode) { + machine_hard_uart_obj_t *self = self_in; + const byte *buf = buf_in; + + // check that size is a multiple of character width + if (size & self->char_width) { + *errcode = MP_EIO; + return MP_STREAM_ERROR; + } + + hal_uart_error_t err = 0; + for (int i = 0; i < size; i++) { + err = uart_tx_char(self, (int)((uint8_t *)buf)[i]); + } + + if (err == HAL_UART_ERROR_NONE) { + // return number of bytes written + return size; + } else { + *errcode = mp_hal_status_to_errno_table[err]; + return MP_STREAM_ERROR; + } +} + +STATIC mp_uint_t machine_hard_uart_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) { + machine_hard_uart_obj_t *self = self_in; + (void)self; + return MP_STREAM_ERROR; +} + +STATIC const mp_stream_p_t uart_stream_p = { + .read = machine_hard_uart_read, + .write = machine_hard_uart_write, + .ioctl = machine_hard_uart_ioctl, + .is_text = false, +}; + +const mp_obj_type_t machine_hard_uart_type = { + { &mp_type_type }, + .name = MP_QSTR_UART, + .print = machine_hard_uart_print, + .make_new = machine_hard_uart_make_new, + .getiter = mp_identity_getiter, + .iternext = mp_stream_unbuffered_iter, + .protocol = &uart_stream_p, + .locals_dict = (mp_obj_dict_t*)&machine_hard_uart_locals_dict, +}; + diff --git a/ports/nrf/modules/machine/uart.h b/ports/nrf/modules/machine/uart.h new file mode 100644 index 000000000..a4453eadf --- /dev/null +++ b/ports/nrf/modules/machine/uart.h @@ -0,0 +1,48 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2015 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef UART_H__ +#define UART_H__ + +typedef enum { + PYB_UART_NONE = 0, + PYB_UART_1 = 1, +} pyb_uart_t; + +typedef struct _machine_hard_uart_obj_t machine_hard_uart_obj_t; +extern const mp_obj_type_t machine_hard_uart_type; + +void uart_init0(void); +void uart_deinit(void); +void uart_irq_handler(mp_uint_t uart_id); + +bool uart_rx_any(machine_hard_uart_obj_t * uart_obj); +int uart_rx_char(machine_hard_uart_obj_t * uart_obj); +void uart_tx_strn(machine_hard_uart_obj_t * uart_obj, const char *str, uint len); +void uart_tx_strn_cooked(machine_hard_uart_obj_t *uart_obj, const char *str, uint len); + +#endif |
