From 0e8d14618477de053417fcf7b8c2e72df589cb69 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Tue, 21 Aug 2018 20:28:58 -0400 Subject: [PATCH 1/6] wip --- ports/nrf/common-hal/microcontroller/Pin.c | 67 ++++++++++++++++++++-- ports/nrf/common-hal/microcontroller/Pin.h | 12 ++++ 2 files changed, 74 insertions(+), 5 deletions(-) diff --git a/ports/nrf/common-hal/microcontroller/Pin.c b/ports/nrf/common-hal/microcontroller/Pin.c index 837e813ac0030..1b7ac0d838d7b 100644 --- a/ports/nrf/common-hal/microcontroller/Pin.c +++ b/ports/nrf/common-hal/microcontroller/Pin.c @@ -28,12 +28,69 @@ #include "nrf_gpio.h" #include "py/mphal.h" -bool common_hal_mcu_pin_is_free(const mcu_pin_obj_t *pin) { - return true; -} - void reset_all_pins(void) { - for (uint32_t pin = 0; pin < NUMBER_OF_PINS; ++pin) + for (uint32_t pin = 0; pin < NUMBER_OF_PINS; ++pin) { nrf_gpio_cfg_default(pin); + } + + #ifdef MICROPY_HW_NEOPIXEL + neopixel_in_use = false; + #endif + #ifdef MICROPY_HW_APA102_MOSI + apa102_sck_in_use = false; + apa102_mosi_in_use = false; + #endif + + // After configuring SWD because it may be shared. + #ifdef SPEAKER_ENABLE_PIN + speaker_enable_in_use = false; + // TODO set pin to out and turn off. + #endif +} + +void claim_pin(const mcu_pin_obj_t* pin) { + #ifdef MICROPY_HW_NEOPIXEL + if (pin == MICROPY_HW_NEOPIXEL) { + neopixel_in_use = true; + } + #endif + #ifdef MICROPY_HW_APA102_MOSI + if (pin == MICROPY_HW_APA102_MOSI) { + apa102_mosi_in_use = true; + } + if (pin == MICROPY_HW_APA102_SCK) { + apa102_sck_in_use = true; + } + #endif + + #ifdef SPEAKER_ENABLE_PIN + if (pin == SPEAKER_ENABLE_PIN) { + speaker_enable_in_use = true; + } + #endif } +bool common_hal_mcu_pin_is_free(const mcu_pin_obj_t *pin) { + #ifdef MICROPY_HW_NEOPIXEL + if (pin == MICROPY_HW_NEOPIXEL) { + return !neopixel_in_use; + } + #endif + #ifdef MICROPY_HW_APA102_MOSI + if (pin == MICROPY_HW_APA102_MOSI) { + return !apa102_mosi_in_use; + } + if (pin == MICROPY_HW_APA102_SCK) { + return !apa102_sck_in_use; + } + #endif + + #ifdef SPEAKER_ENABLE_PIN + if (pin == SPEAKER_ENABLE_PIN) { + return !speaker_enable_in_use; + } + #endif + + // TODO check pin enable. + return true; +} diff --git a/ports/nrf/common-hal/microcontroller/Pin.h b/ports/nrf/common-hal/microcontroller/Pin.h index 1694a82493d8a..954d6e51df9b2 100644 --- a/ports/nrf/common-hal/microcontroller/Pin.h +++ b/ports/nrf/common-hal/microcontroller/Pin.h @@ -30,7 +30,19 @@ #include "nrf_pin.h" #include "py/mphal.h" +#ifdef MICROPY_HW_NEOPIXEL +extern bool neopixel_in_use; +#endif +#ifdef MICROPY_HW_APA102_MOSI +extern bool apa102_sck_in_use; +extern bool apa102_mosi_in_use; +#endif + #define mcu_pin_obj_t pin_obj_t void reset_all_pins(void); +// reset_pin takes the pin number instead of the pointer so that objects don't +// need to store a full pointer. +void reset_pin(uint8_t pin); +void claim_pin(const mcu_pin_obj_t* pin); #endif // MICROPY_INCLUDED_NRF_COMMON_HAL_MICROCONTROLLER_PIN_H From 585597a252be431fd4efe11a9120329b233ebba5 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Thu, 30 Aug 2018 21:42:25 -0400 Subject: [PATCH 2/6] pin files rework; implement pin claiming; add more boards --- ports/atmel-samd/boards/gemma_m0/pins.c | 1 + ports/nrf/Makefile | 31 +--- ports/nrf/board_busses.c | 114 +++++++++++++ ports/nrf/board_busses.h | 39 +++++ .../boards/feather_nrf52832/mpconfigboard.h | 10 ++ .../boards/feather_nrf52832/mpconfigboard.mk | 4 +- ports/nrf/boards/feather_nrf52832/pins.c | 46 +++++ ports/nrf/boards/feather_nrf52832/pins.csv | 24 --- .../feather_nrf52840_express/mpconfigboard.h | 34 ++-- .../feather_nrf52840_express/mpconfigboard.mk | 3 +- .../boards/feather_nrf52840_express/pins.c | 41 +++++ .../boards/feather_nrf52840_express/pins.csv | 48 ------ ports/nrf/boards/pca10040/mpconfigboard.h | 4 +- ports/nrf/boards/pca10040/mpconfigboard.mk | 4 +- ports/nrf/boards/pca10040/pins.c | 40 +++++ ports/nrf/boards/pca10040/pins.csv | 31 ---- ports/nrf/boards/pca10056/mpconfigboard.h | 2 +- ports/nrf/boards/pca10056/mpconfigboard.mk | 3 +- ports/nrf/boards/pca10056/pins.c | 129 ++++++++++++++ ports/nrf/boards/pca10056/pins.csv | 48 ------ .../{nrf_pin.h => boards/pca10059/board.c} | 36 ++-- .../6.0.0/pca10056_bootloader_6.0.0_s140.zip | Bin 0 -> 174550 bytes ports/nrf/boards/pca10059/examples/buttons.py | 26 +++ ports/nrf/boards/pca10059/mpconfigboard.h | 32 ++++ ports/nrf/boards/pca10059/mpconfigboard.mk | 17 ++ ports/nrf/boards/pca10059/pins.c | 42 +++++ ports/nrf/common-hal/analogio/AnalogIn.c | 4 +- ports/nrf/common-hal/busio/I2C.c | 6 +- ports/nrf/common-hal/busio/SPI.c | 6 +- ports/nrf/common-hal/busio/UART.c | 2 - ports/nrf/common-hal/digitalio/DigitalInOut.c | 45 ++--- ports/nrf/common-hal/microcontroller/Pin.c | 68 +++++++- ports/nrf/common-hal/microcontroller/Pin.h | 15 +- .../nrf/common-hal/microcontroller/__init__.c | 56 ++++++ .../nrf/common-hal/neopixel_write/__init__.c | 161 ++++++++++++++++++ ports/nrf/common-hal/pulseio/PWMOut.c | 8 +- ports/nrf/nrf52_af.csv | 48 ------ ports/nrf/peripherals/nrf/nrf52832/pins.c | 65 +++++++ ports/nrf/peripherals/nrf/nrf52832/pins.h | 65 +++++++ ports/nrf/peripherals/nrf/nrf52840/pins.c | 78 +++++++++ ports/nrf/peripherals/nrf/nrf52840/pins.h | 81 +++++++++ ports/nrf/peripherals/nrf/pins.h | 69 ++++++++ ports/nrf/supervisor/serial.c | 1 - 43 files changed, 1274 insertions(+), 313 deletions(-) create mode 100644 ports/nrf/board_busses.c create mode 100644 ports/nrf/board_busses.h create mode 100644 ports/nrf/boards/feather_nrf52832/pins.c delete mode 100644 ports/nrf/boards/feather_nrf52832/pins.csv create mode 100644 ports/nrf/boards/feather_nrf52840_express/pins.c delete mode 100644 ports/nrf/boards/feather_nrf52840_express/pins.csv create mode 100644 ports/nrf/boards/pca10040/pins.c delete mode 100644 ports/nrf/boards/pca10040/pins.csv create mode 100644 ports/nrf/boards/pca10056/pins.c delete mode 100644 ports/nrf/boards/pca10056/pins.csv rename ports/nrf/{nrf_pin.h => boards/pca10059/board.c} (71%) create mode 100644 ports/nrf/boards/pca10059/bootloader/6.0.0/pca10056_bootloader_6.0.0_s140.zip create mode 100644 ports/nrf/boards/pca10059/examples/buttons.py create mode 100644 ports/nrf/boards/pca10059/mpconfigboard.h create mode 100644 ports/nrf/boards/pca10059/mpconfigboard.mk create mode 100644 ports/nrf/boards/pca10059/pins.c create mode 100644 ports/nrf/common-hal/neopixel_write/__init__.c delete mode 100644 ports/nrf/nrf52_af.csv create mode 100644 ports/nrf/peripherals/nrf/nrf52832/pins.c create mode 100644 ports/nrf/peripherals/nrf/nrf52832/pins.h create mode 100644 ports/nrf/peripherals/nrf/nrf52840/pins.c create mode 100644 ports/nrf/peripherals/nrf/nrf52840/pins.h create mode 100644 ports/nrf/peripherals/nrf/pins.h diff --git a/ports/atmel-samd/boards/gemma_m0/pins.c b/ports/atmel-samd/boards/gemma_m0/pins.c index 196e438e0b567..c9c7ea555b8bf 100644 --- a/ports/atmel-samd/boards/gemma_m0/pins.c +++ b/ports/atmel-samd/boards/gemma_m0/pins.c @@ -21,6 +21,7 @@ STATIC const mp_rom_map_elem_t board_global_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_APA102_MOSI), MP_ROM_PTR(&pin_PA00) }, { MP_ROM_QSTR(MP_QSTR_APA102_SCK), MP_ROM_PTR(&pin_PA01) }, + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) }, { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }, diff --git a/ports/nrf/Makefile b/ports/nrf/Makefile index f3cc0e35ba19b..3ad97484668bb 100755 --- a/ports/nrf/Makefile +++ b/ports/nrf/Makefile @@ -24,9 +24,6 @@ ifneq ($(SD), ) include drivers/bluetooth/bluetooth_common.mk endif -# qstr definitions (must come before including py.mk) -QSTR_DEFS = qstrdefsport.h $(BUILD)/pins_qstr.h - FROZEN_MPY_DIR = freeze # include py core make definitions @@ -53,6 +50,7 @@ INC += -I./nrfx/drivers/include INC += -I../../lib/mp-readline INC += -I./drivers/bluetooth INC += -I./drivers +INC += -I./peripherals INC += -I../../lib/tinyusb/src INC += -I./usb @@ -105,6 +103,7 @@ SRC_C += \ drivers/bluetooth/ble_drv.c \ drivers/bluetooth/ble_uart.c \ boards/$(BOARD)/board.c \ + boards/$(BOARD)/pins.c \ nrfx/mdk/system_$(MCU_SUB_VARIANT).c \ nrfx/hal/nrf_nvmc.c \ device/$(MCU_VARIANT)/startup_$(MCU_SUB_VARIANT).c \ @@ -119,6 +118,7 @@ SRC_C += \ lib/utils/sys_stdio_mphal.c \ lib/libc/string0.c \ lib/mp-readline/readline.c \ + peripherals/nrf/$(MCU_CHIP)/pins.c \ supervisor/shared/memory.c DRIVERS_SRC_C += $(addprefix modules/,\ @@ -150,6 +150,7 @@ SRC_COMMON_HAL += \ busio/I2C.c \ busio/SPI.c \ busio/UART.c \ + neopixel_write/__init__.c \ pulseio/__init__.c \ pulseio/PulseIn.c \ pulseio/PulseOut.c \ @@ -238,7 +239,6 @@ FROZEN_MPY_PY_FILES := $(shell find -L $(FROZEN_MPY_DIR) -type f -name '*.py') FROZEN_MPY_MPY_FILES := $(addprefix $(BUILD)/,$(FROZEN_MPY_PY_FILES:.py=.mpy)) OBJ += $(PY_O) $(SUPERVISOR_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) -OBJ += $(BUILD)/pins_gen.o OBJ += $(addprefix $(BUILD)/, $(SRC_NRFX:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(DRIVERS_SRC_C:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_COMMON_HAL_EXPANDED:.c=.o)) @@ -333,7 +333,7 @@ dfu-flash: $(BUILD)/dfu-package.zip $(NRFUTIL) --verbose dfu serial --package $^ -p $(SERIAL) -b 115200 --singlebank $(DFU_TOUCH) ## Create DFU package file -dfu-gen: $(BUILD)/dfu-package.zip +dfu-gen: $(BUILD)/dfu-package.zip $(BUILD)/dfu-package.zip: $(BUILD)/$(OUTPUT_FILENAME).hex $(NRFUTIL) dfu genpkg --sd-req 0xFFFE --dev-type 0x0052 --application $^ $(BUILD)/dfu-package.zip @@ -350,29 +350,8 @@ SRC_QSTR += $(SRC_C) $(SRC_SUPERVISOR) $(SRC_MOD) $(DRIVERS_SRC_C) $(SRC_COMMON_ # SRC_QSTR SRC_QSTR_AUTO_DEPS += -# Making OBJ use an order-only depenedency on the generated pins.h file -# has the side effect of making the pins.h file before we actually compile -# any of the objects. The normal dependency generation will deal with the -# case when pins.h is modified. But when it doesn't exist, we don't know -# which source files might need it. -$(OBJ): | $(HEADER_BUILD)/pins.h - -# Use a pattern rule here so that make will only call make-pins.py once to make -# both pins_g.c and pins.h -$(BUILD)/%_gen.c $(HEADER_BUILD)/%.h $(BUILD)/%_qstr.h: boards/$(BOARD)/%.csv $(MAKE_PINS) $(AF_FILE) $(PREFIX_FILE) | $(HEADER_BUILD) - $(ECHO) "Create $@" - $(Q)$(PYTHON) $(MAKE_PINS) --board $(BOARD_PINS) --af $(AF_FILE) --prefix $(PREFIX_FILE) --hdr $(GEN_PINS_HDR) --qstr $(GEN_PINS_QSTR) > $(GEN_PINS_SRC) - -$(BUILD)/pins_gen.o: $(BUILD)/pins_gen.c - $(call compile_c) - -MAKE_PINS = boards/make-pins.py -BOARD_PINS = boards/$(BOARD)/pins.csv AF_FILE = $(MCU_VARIANT)_af.csv PREFIX_FILE = boards/$(MCU_VARIANT)_prefix.c -GEN_PINS_SRC = $(BUILD)/pins_gen.c -GEN_PINS_HDR = $(HEADER_BUILD)/pins.h -GEN_PINS_QSTR = $(BUILD)/pins_qstr.h ifneq ($(FROZEN_DIR),) # To use frozen source modules, put your .py files in a subdirectory (eg scripts/) diff --git a/ports/nrf/board_busses.c b/ports/nrf/board_busses.c new file mode 100644 index 0000000000000..91f0def6d3030 --- /dev/null +++ b/ports/nrf/board_busses.c @@ -0,0 +1,114 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries + * + * 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 "shared-bindings/busio/I2C.h" +#include "shared-bindings/busio/SPI.h" +#include "shared-bindings/busio/UART.h" + +#include "shared-bindings/microcontroller/Pin.h" +#include "supervisor/shared/translate.h" +#include "mpconfigboard.h" +#include "nrf/pins.h" +#include "py/runtime.h" + +#if !defined(DEFAULT_I2C_BUS_SDA) || !defined(DEFAULT_I2C_BUS_SCL) + STATIC mp_obj_t board_i2c(void) { + mp_raise_NotImplementedError(translate("No default I2C bus")); + return NULL; + } +#else + STATIC mp_obj_t i2c_singleton = NULL; + + STATIC mp_obj_t board_i2c(void) { + + if (i2c_singleton == NULL) { + busio_i2c_obj_t *self = m_new_obj(busio_i2c_obj_t); + self->base.type = &busio_i2c_type; + + assert_pin_free(DEFAULT_I2C_BUS_SDA); + assert_pin_free(DEFAULT_I2C_BUS_SCL); + common_hal_busio_i2c_construct(self, DEFAULT_I2C_BUS_SCL, DEFAULT_I2C_BUS_SDA, 400000, 0); + i2c_singleton = (mp_obj_t)self; + } + return i2c_singleton; + + } +#endif +MP_DEFINE_CONST_FUN_OBJ_0(board_i2c_obj, board_i2c); + +#if !defined(DEFAULT_SPI_BUS_SCK) || !defined(DEFAULT_SPI_BUS_MISO) || !defined(DEFAULT_SPI_BUS_MOSI) + STATIC mp_obj_t board_spi(void) { + mp_raise_NotImplementedError(translate("No default SPI bus")); + return NULL; + } +#else + STATIC mp_obj_t spi_singleton = NULL; + + STATIC mp_obj_t board_spi(void) { + + if (spi_singleton == NULL) { + busio_spi_obj_t *self = m_new_obj(busio_spi_obj_t); + self->base.type = &busio_spi_type; + assert_pin_free(DEFAULT_SPI_BUS_SCK); + assert_pin_free(DEFAULT_SPI_BUS_MOSI); + assert_pin_free(DEFAULT_SPI_BUS_MISO); + const mcu_pin_obj_t* clock = MP_OBJ_TO_PTR(DEFAULT_SPI_BUS_SCK); + const mcu_pin_obj_t* mosi = MP_OBJ_TO_PTR(DEFAULT_SPI_BUS_MOSI); + const mcu_pin_obj_t* miso = MP_OBJ_TO_PTR(DEFAULT_SPI_BUS_MISO); + common_hal_busio_spi_construct(self, clock, mosi, miso); + spi_singleton = (mp_obj_t)self; + } + return spi_singleton; + } +#endif +MP_DEFINE_CONST_FUN_OBJ_0(board_spi_obj, board_spi); + +#if !defined(DEFAULT_UART_BUS_RX) || !defined(DEFAULT_UART_BUS_TX) + STATIC mp_obj_t board_uart(void) { + mp_raise_NotImplementedError(translate("No default UART bus")); + return NULL; + } +#else + STATIC mp_obj_t uart_singleton = NULL; + + STATIC mp_obj_t board_uart(void) { + if (uart_singleton == NULL) { + busio_uart_obj_t *self = m_new_obj(busio_uart_obj_t); + self->base.type = &busio_uart_type; + + assert_pin_free(DEFAULT_UART_BUS_RX); + assert_pin_free(DEFAULT_UART_BUS_TX); + + const mcu_pin_obj_t* rx = MP_OBJ_TO_PTR(DEFAULT_UART_BUS_RX); + const mcu_pin_obj_t* tx = MP_OBJ_TO_PTR(DEFAULT_UART_BUS_TX); + + common_hal_busio_uart_construct(self, tx, rx, 9600, 8, PARITY_NONE, 1, 1000, 64); + uart_singleton = (mp_obj_t)self; + } + return uart_singleton; + } +#endif +MP_DEFINE_CONST_FUN_OBJ_0(board_uart_obj, board_uart); diff --git a/ports/nrf/board_busses.h b/ports/nrf/board_busses.h new file mode 100644 index 0000000000000..2a4bfc3d4b64c --- /dev/null +++ b/ports/nrf/board_busses.h @@ -0,0 +1,39 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries + * + * 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_NRF_BOARD_BUSSES_H +#define MICROPY_INCLUDED_NRF_BOARD_BUSSES_H + +void board_i2c(void); +extern mp_obj_fun_builtin_fixed_t board_i2c_obj; + +void board_spi(void); +extern mp_obj_fun_builtin_fixed_t board_spi_obj; + +void board_uart(void); +extern mp_obj_fun_builtin_fixed_t board_uart_obj; + +#endif // MICROPY_INCLUDED_NRF_BOARD_BUSSES_H diff --git a/ports/nrf/boards/feather_nrf52832/mpconfigboard.h b/ports/nrf/boards/feather_nrf52832/mpconfigboard.h index 84afc5e2d7ba9..0da1abfc47c81 100644 --- a/ports/nrf/boards/feather_nrf52832/mpconfigboard.h +++ b/ports/nrf/boards/feather_nrf52832/mpconfigboard.h @@ -34,3 +34,13 @@ #define PORT_HEAP_SIZE (32 * 1024) #define CIRCUITPY_AUTORELOAD_DELAY_MS 500 + +#define DEFAULT_I2C_BUS_SCL (&pin_P0_26) +#define DEFAULT_I2C_BUS_SDA (&pin_P0_25) + +#define DEFAULT_SPI_BUS_SCK (&pin_P0_12) +#define DEFAULT_SPI_BUS_MOSI (&pin_P0_13) +#define DEFAULT_SPI_BUS_MISO (&pin_P0_14) + +#define DEFAULT_UART_BUS_RX (&pin_P0_08) +#define DEFAULT_UART_BUS_TX (&pin_P0_06) diff --git a/ports/nrf/boards/feather_nrf52832/mpconfigboard.mk b/ports/nrf/boards/feather_nrf52832/mpconfigboard.mk index c370b724e71b6..5b1f6e939c854 100644 --- a/ports/nrf/boards/feather_nrf52832/mpconfigboard.mk +++ b/ports/nrf/boards/feather_nrf52832/mpconfigboard.mk @@ -1,6 +1,8 @@ MCU_SERIES = m4 MCU_VARIANT = nrf52 +# Historical: nrf52 means nrf52832 MCU_SUB_VARIANT = nrf52 +MCU_CHIP = nrf52832 SD ?= s132 SOFTDEV_VERSION ?= 2.0.1 @@ -8,4 +10,4 @@ LD_FILE = boards/feather_nrf52832/custom_nrf52832_dfu_app_$(SOFTDEV_VERSION).ld BOOT_FILE = boards/feather_nrf52832/bootloader/feather52_bootloader_$(SOFTDEV_VERSION)_s132_single BOOT_SETTING_ADDR = 0x7F000 -NRF_DEFINES += -DNRF52832_XXAA +NRF_DEFINES += -DNRF52832_XXAA -DNRF52832 diff --git a/ports/nrf/boards/feather_nrf52832/pins.c b/ports/nrf/boards/feather_nrf52832/pins.c new file mode 100644 index 0000000000000..b14b944e8826a --- /dev/null +++ b/ports/nrf/boards/feather_nrf52832/pins.c @@ -0,0 +1,46 @@ +#include "shared-bindings/board/__init__.h" + +#include "board_busses.h" + +STATIC const mp_rom_map_elem_t board_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_P0_02) }, + { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_P0_03) }, + { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_P0_04) }, + { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_P0_05) }, + { MP_ROM_QSTR(MP_QSTR_A4), MP_ROM_PTR(&pin_P0_28) }, + { MP_ROM_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_P0_29) }, + + { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_P0_12) }, + { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_P0_13) }, + { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_P0_14) }, + + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_P0_08) }, + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_P0_06) }, + + { MP_ROM_QSTR(MP_QSTR_DFU), MP_ROM_PTR(&pin_P0_20) }, + + { MP_ROM_QSTR(MP_QSTR_NFC1), MP_ROM_PTR(&pin_P0_09) }, + { MP_ROM_QSTR(MP_QSTR_NFC2), MP_ROM_PTR(&pin_P0_10) }, + + { MP_ROM_QSTR(MP_QSTR_27), MP_ROM_PTR(&pin_P0_27) }, + + { MP_ROM_QSTR(MP_QSTR_D30), MP_ROM_PTR(&pin_P0_30) }, + { MP_ROM_QSTR(MP_QSTR_A6), MP_ROM_PTR(&pin_P0_30) }, + + { MP_ROM_QSTR(MP_QSTR_D31), MP_ROM_PTR(&pin_P0_31) }, + { MP_ROM_QSTR(MP_QSTR_A7), MP_ROM_PTR(&pin_P0_31) }, + + { MP_ROM_QSTR(MP_QSTR_D7), MP_ROM_PTR(&pin_P0_07) }, + { MP_ROM_QSTR(MP_QSTR_D11), MP_ROM_PTR(&pin_P0_11) }, + { MP_ROM_QSTR(MP_QSTR_D15), MP_ROM_PTR(&pin_P0_15) }, + { MP_ROM_QSTR(MP_QSTR_D16), MP_ROM_PTR(&pin_P0_16) }, + + { MP_ROM_QSTR(MP_QSTR_L), MP_ROM_PTR(&pin_P0_17) }, + + { MP_ROM_QSTR(MP_QSTR_LED_BLUE), MP_ROM_PTR(&pin_P0_19) }, + + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_P0_26) }, + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_P0_25) }, +}; + +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/nrf/boards/feather_nrf52832/pins.csv b/ports/nrf/boards/feather_nrf52832/pins.csv deleted file mode 100644 index c041900640ebf..0000000000000 --- a/ports/nrf/boards/feather_nrf52832/pins.csv +++ /dev/null @@ -1,24 +0,0 @@ -A0,P0_02 -A1,P0_03 -A2,P0_04 -A3,P0_05 -TX,P0_06 -RX,P0_08 -NFC1,P0_09 -NFC2,P0_10 -D11,P0_11 -SCK,P0_12 -MOSI,P0_13 -MISO,P0_14 -D15,P0_15 -D16,P0_16 -LED1,P0_17 -LED2,P0_19 -DFU,P0_20 -SDA,P0_25 -SCL,P0_26 -D27,P0_27 -A4,P0_28 -A5,P0_29 -A6,P0_30 -A7,P0_31 diff --git a/ports/nrf/boards/feather_nrf52840_express/mpconfigboard.h b/ports/nrf/boards/feather_nrf52840_express/mpconfigboard.h index ce21e73861bda..81818741d1a52 100644 --- a/ports/nrf/boards/feather_nrf52840_express/mpconfigboard.h +++ b/ports/nrf/boards/feather_nrf52840_express/mpconfigboard.h @@ -29,20 +29,16 @@ #define MICROPY_HW_BOARD_NAME "Adafruit Feather nRF52840 Express" #define MICROPY_HW_MCU_NAME "nRF52840" -#define MICROPY_PY_SYS_PLATFORM "Feather52840" +#define MICROPY_PY_SYS_PLATFORM "Feather52840Express" -// #define MICROPY_HW_NEOPIXEL NRF_GPIO_PIN_MAP(0, 13) +#define MICROPY_HW_NEOPIXEL (&pin_P0_13) -// #define MICROPY_QSPI_DATA0 NRF_GPIO_PIN_MAP(1, 9) -// #define MICROPY_QSPI_DATA1 NRF_GPIO_PIN_MAP(0, 11) -// #define MICROPY_QSPI_DATA2 NRF_GPIO_PIN_MAP(0, 12) -// #define MICROPY_QSPI_DATA3 NRF_GPIO_PIN_MAP(0, 14) -// #define MICROPY_QSPI_SCK NRF_GPIO_PIN_MAP(0, 8) -// #define MICROPY_QSPI_CS NRF_GPIO_PIN_MAP(1, 8) - -// #define MICROPY_HW_UART_RX NRF_GPIO_PIN_MAP(0, 8) -// #define MICROPY_HW_UART_TX NRF_GPIO_PIN_MAP(0, 6) -// #define MICROPY_HW_UART_HWFC (0) +#define MICROPY_QSPI_DATA0 (&pin_P1_09) +#define MICROPY_QSPI_DATA1 (&pin_P0_11) +#define MICROPY_QSPI_DATA2 (&pin_P0_12) +#define MICROPY_QSPI_DATA3 (&pin_P0_14) +#define MICROPY_QSPI_SCK (&pin_P0_08) +#define MICROPY_QSPI_CS (&pin_P1_08) #define CIRCUITPY_AUTORELOAD_DELAY_MS 500 @@ -64,12 +60,12 @@ #define BOARD_HAS_CRYSTAL 1 -#define DEFAULT_I2C_BUS_SCL NRF_GPIO_PIN_MAP(1, 11) -#define DEFAULT_I2C_BUS_SDA NRF_GPIO_PIN_MAP(1, 12) +#define DEFAULT_I2C_BUS_SCL (&pin_P1_11) +#define DEFAULT_I2C_BUS_SDA (&pin_P1_12) -#define DEFAULT_SPI_BUS_SCK NRF_GPIO_PIN_MAP(0, 20) -#define DEFAULT_SPI_BUS_MOSI NRF_GPIO_PIN_MAP(0, 23) -#define DEFAULT_SPI_BUS_MISO NRF_GPIO_PIN_MAP(0, 22) +#define DEFAULT_SPI_BUS_SCK (&pin_P0_20) +#define DEFAULT_SPI_BUS_MOSI (&pin_P0_23) +#define DEFAULT_SPI_BUS_MISO (&pin_P0_22) -#define DEFAULT_UART_BUS_RX NRF_GPIO_PIN_MAP(1, 0) -#define DEFAULT_UART_BUS_TX NRF_GPIO_PIN_MAP(0, 24) +#define DEFAULT_UART_BUS_RX (&pin_P1_0) +#define DEFAULT_UART_BUS_TX (&pin_P0_24) diff --git a/ports/nrf/boards/feather_nrf52840_express/mpconfigboard.mk b/ports/nrf/boards/feather_nrf52840_express/mpconfigboard.mk index 5c4fde4838f0b..caf580ec4d124 100644 --- a/ports/nrf/boards/feather_nrf52840_express/mpconfigboard.mk +++ b/ports/nrf/boards/feather_nrf52840_express/mpconfigboard.mk @@ -1,6 +1,7 @@ MCU_SERIES = m4 MCU_VARIANT = nrf52 MCU_SUB_VARIANT = nrf52840 +MCU_CHIP = nrf52840 SD ?= s140 SOFTDEV_VERSION ?= 6.1.0 @@ -12,4 +13,4 @@ else LD_FILE = boards/adafruit_$(MCU_SUB_VARIANT)_$(SD_LOWER)_v$(firstword $(subst ., ,$(SOFTDEV_VERSION))).ld endif -NRF_DEFINES += -DNRF52840_XXAA +NRF_DEFINES += -DNRF52840_XXAA -DNRF52840 diff --git a/ports/nrf/boards/feather_nrf52840_express/pins.c b/ports/nrf/boards/feather_nrf52840_express/pins.c new file mode 100644 index 0000000000000..0f5eab31d0c76 --- /dev/null +++ b/ports/nrf/boards/feather_nrf52840_express/pins.c @@ -0,0 +1,41 @@ +#include "shared-bindings/board/__init__.h" + +#include "board_busses.h" + +STATIC const mp_rom_map_elem_t board_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_P0_30) }, + { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_P0_28) }, + { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_P0_31) }, + { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_P0_02) }, + { MP_ROM_QSTR(MP_QSTR_A4), MP_ROM_PTR(&pin_P0_29) }, + { MP_ROM_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_P0_03) }, + + { MP_ROM_QSTR(MP_QSTR_AREF), MP_ROM_PTR(&pin_P0_04) }, + { MP_ROM_QSTR(MP_QSTR_VDIV), MP_ROM_PTR(&pin_P0_05) }, + + { MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_P1_13) }, + { MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_P1_14) }, + { MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_P1_15) }, + { MP_ROM_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_P0_27) }, + { MP_ROM_QSTR(MP_QSTR_D11), MP_ROM_PTR(&pin_P0_26) }, + { MP_ROM_QSTR(MP_QSTR_D12), MP_ROM_PTR(&pin_P0_06) }, + { MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_P0_07) }, + { MP_ROM_QSTR(MP_QSTR_L), MP_ROM_PTR(&pin_P0_07) }, + + { MP_ROM_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_P0_13) }, + + { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_P0_20) }, + { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_P0_23) }, + { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_P0_22) }, + + { MP_ROM_QSTR(MP_QSTR_TXD), MP_ROM_PTR(&pin_P0_24) }, + { MP_ROM_QSTR(MP_QSTR_RXD), MP_ROM_PTR(&pin_P1_00) }, + + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_P1_11) }, + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_P1_12) }, + + { MP_ROM_QSTR(MP_QSTR_LED_RED), MP_ROM_PTR(&pin_P1_02) }, + { MP_ROM_QSTR(MP_QSTR_LED_BLUE), MP_ROM_PTR(&pin_P1_10) }, +}; + +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/nrf/boards/feather_nrf52840_express/pins.csv b/ports/nrf/boards/feather_nrf52840_express/pins.csv deleted file mode 100644 index 284370d0602c0..0000000000000 --- a/ports/nrf/boards/feather_nrf52840_express/pins.csv +++ /dev/null @@ -1,48 +0,0 @@ -P0_00,P0_00 -P0_01,P0_01 -P0_02,P0_02 -P0_03,P0_03 -P0_04,P0_04 -P0_05,P0_05 -P0_06,P0_06 -P0_07,P0_07 -P0_08,P0_08 -P0_09,P0_09 -P0_10,P0_10 -P0_11,P0_11 -P0_12,P0_12 -P0_13,P0_13 -P0_14,P0_14 -P0_15,P0_15 -P0_16,P0_16 -P0_17,P0_17 -P0_18,P0_18 -P0_19,P0_19 -P0_20,P0_20 -P0_21,P0_21 -P0_22,P0_22 -P0_23,P0_23 -P0_24,P0_24 -P0_25,P0_25 -P0_26,P0_26 -P0_27,P0_27 -P0_28,P0_28 -P0_29,P0_29 -P0_30,P0_30 -P0_31,P0_31 -P1_00,P1_00 -P1_01,P1_01 -P1_02,P1_02 -P1_03,P1_03 -P1_04,P1_04 -P1_05,P1_05 -P1_06,P1_06 -P1_07,P1_07 -P1_08,P1_08 -P1_09,P1_09 -P1_10,P1_10 -P1_11,P1_11 -P1_12,P1_12 -P1_13,P1_13 -P1_14,P1_14 -P1_15,P1_15 diff --git a/ports/nrf/boards/pca10040/mpconfigboard.h b/ports/nrf/boards/pca10040/mpconfigboard.h index 8fa001dfa1fbd..40035e2cac0ea 100644 --- a/ports/nrf/boards/pca10040/mpconfigboard.h +++ b/ports/nrf/boards/pca10040/mpconfigboard.h @@ -28,8 +28,8 @@ #define MICROPY_HW_MCU_NAME "nRF52832" #define MICROPY_PY_SYS_PLATFORM "nRF52-DK" -#define MICROPY_HW_UART_RX NRF_GPIO_PIN_MAP(0, 8) -#define MICROPY_HW_UART_TX NRF_GPIO_PIN_MAP(0, 6) +#define MICROPY_HW_UART_RX NRF_GPIO_PIN_MAP(0, 11) +#define MICROPY_HW_UART_TX NRF_GPIO_PIN_MAP(0, 12) #define MICROPY_HW_UART_HWFC (0) #define PORT_HEAP_SIZE (32 * 1024) diff --git a/ports/nrf/boards/pca10040/mpconfigboard.mk b/ports/nrf/boards/pca10040/mpconfigboard.mk index 79aa853494972..ad11b4f7c7bc7 100644 --- a/ports/nrf/boards/pca10040/mpconfigboard.mk +++ b/ports/nrf/boards/pca10040/mpconfigboard.mk @@ -1,6 +1,8 @@ MCU_SERIES = m4 MCU_VARIANT = nrf52 +# Historical: nrf52 means nrf52832 MCU_SUB_VARIANT = nrf52 +MCU_CHIP = nrf52832 SD ?= s132 SOFTDEV_VERSION ?= 5.0.0 @@ -10,4 +12,4 @@ else LD_FILE = boards/nrf52832_512k_64k_s132_$(SOFTDEV_VERSION).ld endif -NRF_DEFINES += -DNRF52832_XXAA +NRF_DEFINES += -DNRF52832_XXAA -DNRF52832 diff --git a/ports/nrf/boards/pca10040/pins.c b/ports/nrf/boards/pca10040/pins.c new file mode 100644 index 0000000000000..9671358c9a153 --- /dev/null +++ b/ports/nrf/boards/pca10040/pins.c @@ -0,0 +1,40 @@ +#include "shared-bindings/board/__init__.h" + +#include "board_busses.h" + +STATIC const mp_rom_map_elem_t board_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR_P0_00), MP_ROM_PTR(&pin_P0_00) }, + { MP_ROM_QSTR(MP_QSTR_P0_01), MP_ROM_PTR(&pin_P0_01) }, + { MP_ROM_QSTR(MP_QSTR_P0_02), MP_ROM_PTR(&pin_P0_02) }, + { MP_ROM_QSTR(MP_QSTR_P0_03), MP_ROM_PTR(&pin_P0_03) }, + { MP_ROM_QSTR(MP_QSTR_P0_04), MP_ROM_PTR(&pin_P0_04) }, + { MP_ROM_QSTR(MP_QSTR_P0_05), MP_ROM_PTR(&pin_P0_05) }, + { MP_ROM_QSTR(MP_QSTR_P0_06), MP_ROM_PTR(&pin_P0_06) }, + { MP_ROM_QSTR(MP_QSTR_P0_07), MP_ROM_PTR(&pin_P0_07) }, + { MP_ROM_QSTR(MP_QSTR_P0_08), MP_ROM_PTR(&pin_P0_08) }, + { MP_ROM_QSTR(MP_QSTR_P0_09), MP_ROM_PTR(&pin_P0_09) }, + { MP_ROM_QSTR(MP_QSTR_P0_10), MP_ROM_PTR(&pin_P0_10) }, + { MP_ROM_QSTR(MP_QSTR_P0_11), MP_ROM_PTR(&pin_P0_11) }, + { MP_ROM_QSTR(MP_QSTR_P0_12), MP_ROM_PTR(&pin_P0_12) }, + { MP_ROM_QSTR(MP_QSTR_P0_13), MP_ROM_PTR(&pin_P0_13) }, + { MP_ROM_QSTR(MP_QSTR_P0_14), MP_ROM_PTR(&pin_P0_14) }, + { MP_ROM_QSTR(MP_QSTR_P0_15), MP_ROM_PTR(&pin_P0_15) }, + { MP_ROM_QSTR(MP_QSTR_P0_16), MP_ROM_PTR(&pin_P0_16) }, + { MP_ROM_QSTR(MP_QSTR_P0_17), MP_ROM_PTR(&pin_P0_17) }, + { MP_ROM_QSTR(MP_QSTR_P0_18), MP_ROM_PTR(&pin_P0_18) }, + { MP_ROM_QSTR(MP_QSTR_P0_19), MP_ROM_PTR(&pin_P0_19) }, + { MP_ROM_QSTR(MP_QSTR_P0_20), MP_ROM_PTR(&pin_P0_20) }, + { MP_ROM_QSTR(MP_QSTR_P0_21), MP_ROM_PTR(&pin_P0_21) }, + { MP_ROM_QSTR(MP_QSTR_P0_22), MP_ROM_PTR(&pin_P0_22) }, + { MP_ROM_QSTR(MP_QSTR_P0_23), MP_ROM_PTR(&pin_P0_23) }, + { MP_ROM_QSTR(MP_QSTR_P0_24), MP_ROM_PTR(&pin_P0_24) }, + { MP_ROM_QSTR(MP_QSTR_P0_25), MP_ROM_PTR(&pin_P0_25) }, + { MP_ROM_QSTR(MP_QSTR_P0_26), MP_ROM_PTR(&pin_P0_26) }, + { MP_ROM_QSTR(MP_QSTR_P0_27), MP_ROM_PTR(&pin_P0_27) }, + { MP_ROM_QSTR(MP_QSTR_P0_28), MP_ROM_PTR(&pin_P0_28) }, + { MP_ROM_QSTR(MP_QSTR_P0_29), MP_ROM_PTR(&pin_P0_29) }, + { MP_ROM_QSTR(MP_QSTR_P0_30), MP_ROM_PTR(&pin_P0_30) }, + { MP_ROM_QSTR(MP_QSTR_P0_31), MP_ROM_PTR(&pin_P0_31) }, +}; + +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/nrf/boards/pca10040/pins.csv b/ports/nrf/boards/pca10040/pins.csv deleted file mode 100644 index 2202224461cc7..0000000000000 --- a/ports/nrf/boards/pca10040/pins.csv +++ /dev/null @@ -1,31 +0,0 @@ -P0_01,P0_01 -P0_02,P0_02 -P0_03,P0_03 -P0_04,P0_04 -P0_05,P0_05 -P0_06,P0_06 -P0_07,P0_07 -P0_08,P0_08 -P0_09,P0_09 -P0_10,P0_10 -P0_11,P0_11 -P0_12,P0_12 -P0_13,P0_13 -P0_14,P0_14 -P0_15,P0_15 -P0_16,P0_16 -P0_17,P0_17 -P0_18,P0_18 -P0_19,P0_19 -P0_20,P0_20 -P0_21,P0_21 -P0_22,P0_22 -P0_23,P0_23 -P0_24,P0_24 -P0_25,P0_25 -P0_26,P0_26 -P0_27,P0_27 -P0_28,P0_28 -P0_29,P0_29 -P0_30,P0_30 -P0_31,P0_31 diff --git a/ports/nrf/boards/pca10056/mpconfigboard.h b/ports/nrf/boards/pca10056/mpconfigboard.h index 8195e194790eb..dbd4226631c04 100644 --- a/ports/nrf/boards/pca10056/mpconfigboard.h +++ b/ports/nrf/boards/pca10056/mpconfigboard.h @@ -28,6 +28,7 @@ #define MICROPY_HW_MCU_NAME "nRF52840" #define MICROPY_PY_SYS_PLATFORM "nRF52840-DK" +// See legend on bottom of board #define MICROPY_HW_UART_RX NRF_GPIO_PIN_MAP(0, 8) #define MICROPY_HW_UART_TX NRF_GPIO_PIN_MAP(0, 6) #define MICROPY_HW_UART_HWFC (0) @@ -37,4 +38,3 @@ // Temp (could be removed) 0: usb cdc (default), 1 : hwuart (jlink) #define CFG_HWUART_FOR_SERIAL 0 - diff --git a/ports/nrf/boards/pca10056/mpconfigboard.mk b/ports/nrf/boards/pca10056/mpconfigboard.mk index 5c4fde4838f0b..caf580ec4d124 100644 --- a/ports/nrf/boards/pca10056/mpconfigboard.mk +++ b/ports/nrf/boards/pca10056/mpconfigboard.mk @@ -1,6 +1,7 @@ MCU_SERIES = m4 MCU_VARIANT = nrf52 MCU_SUB_VARIANT = nrf52840 +MCU_CHIP = nrf52840 SD ?= s140 SOFTDEV_VERSION ?= 6.1.0 @@ -12,4 +13,4 @@ else LD_FILE = boards/adafruit_$(MCU_SUB_VARIANT)_$(SD_LOWER)_v$(firstword $(subst ., ,$(SOFTDEV_VERSION))).ld endif -NRF_DEFINES += -DNRF52840_XXAA +NRF_DEFINES += -DNRF52840_XXAA -DNRF52840 diff --git a/ports/nrf/boards/pca10056/pins.c b/ports/nrf/boards/pca10056/pins.c new file mode 100644 index 0000000000000..1c208f89b58a1 --- /dev/null +++ b/ports/nrf/boards/pca10056/pins.c @@ -0,0 +1,129 @@ +#include "shared-bindings/board/__init__.h" + +#include "board_busses.h" + +STATIC const mp_rom_map_elem_t board_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR_P0_00), MP_ROM_PTR(&pin_P0_00) }, + { MP_ROM_QSTR(MP_QSTR_P0_01), MP_ROM_PTR(&pin_P0_01) }, + { MP_ROM_QSTR(MP_QSTR_P0_02), MP_ROM_PTR(&pin_P0_02) }, + + { MP_ROM_QSTR(MP_QSTR_P0_03), MP_ROM_PTR(&pin_P0_03) }, + { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_P0_03) }, + + { MP_ROM_QSTR(MP_QSTR_P0_04), MP_ROM_PTR(&pin_P0_04) }, + { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_P0_04) }, + + { MP_ROM_QSTR(MP_QSTR_P0_05), MP_ROM_PTR(&pin_P0_05) }, + { MP_ROM_QSTR(MP_QSTR_P0_06), MP_ROM_PTR(&pin_P0_06) }, + { MP_ROM_QSTR(MP_QSTR_P0_07), MP_ROM_PTR(&pin_P0_07) }, + { MP_ROM_QSTR(MP_QSTR_P0_08), MP_ROM_PTR(&pin_P0_08) }, + { MP_ROM_QSTR(MP_QSTR_P0_09), MP_ROM_PTR(&pin_P0_09) }, + { MP_ROM_QSTR(MP_QSTR_P0_10), MP_ROM_PTR(&pin_P0_10) }, + + { MP_ROM_QSTR(MP_QSTR_P0_11), MP_ROM_PTR(&pin_P0_11) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON1), MP_ROM_PTR(&pin_P0_11) }, + + { MP_ROM_QSTR(MP_QSTR_P0_12), MP_ROM_PTR(&pin_P0_12) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON2), MP_ROM_PTR(&pin_P0_12) }, + + { MP_ROM_QSTR(MP_QSTR_P0_13), MP_ROM_PTR(&pin_P0_13) }, + { MP_ROM_QSTR(MP_QSTR_L), MP_ROM_PTR(&pin_P0_13) }, + { MP_ROM_QSTR(MP_QSTR_LED1), MP_ROM_PTR(&pin_P0_13) }, + + { MP_ROM_QSTR(MP_QSTR_P0_14), MP_ROM_PTR(&pin_P0_14) }, + { MP_ROM_QSTR(MP_QSTR_LED2), MP_ROM_PTR(&pin_P0_14) }, + + { MP_ROM_QSTR(MP_QSTR_P0_15), MP_ROM_PTR(&pin_P0_15) }, + { MP_ROM_QSTR(MP_QSTR_LED3), MP_ROM_PTR(&pin_P0_15) }, + + { MP_ROM_QSTR(MP_QSTR_P0_16), MP_ROM_PTR(&pin_P0_16) }, + { MP_ROM_QSTR(MP_QSTR_LED4), MP_ROM_PTR(&pin_P0_16) }, + + { MP_ROM_QSTR(MP_QSTR_P0_17), MP_ROM_PTR(&pin_P0_17) }, + + // RESET { MP_ROM_QSTR(MP_QSTR_P0_18), MP_ROM_PTR(&pin_P0_18) }, + + { MP_ROM_QSTR(MP_QSTR_P0_19), MP_ROM_PTR(&pin_P0_19) }, + { MP_ROM_QSTR(MP_QSTR_P0_20), MP_ROM_PTR(&pin_P0_20) }, + { MP_ROM_QSTR(MP_QSTR_P0_21), MP_ROM_PTR(&pin_P0_21) }, + { MP_ROM_QSTR(MP_QSTR_P0_22), MP_ROM_PTR(&pin_P0_22) }, + { MP_ROM_QSTR(MP_QSTR_P0_23), MP_ROM_PTR(&pin_P0_23) }, + + { MP_ROM_QSTR(MP_QSTR_P0_24), MP_ROM_PTR(&pin_P0_24) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON3), MP_ROM_PTR(&pin_P0_24) }, + + { MP_ROM_QSTR(MP_QSTR_P0_25), MP_ROM_PTR(&pin_P0_25) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON4), MP_ROM_PTR(&pin_P0_25) }, + + { MP_ROM_QSTR(MP_QSTR_P0_26), MP_ROM_PTR(&pin_P0_26) }, + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_P0_26) }, + + { MP_ROM_QSTR(MP_QSTR_P0_27), MP_ROM_PTR(&pin_P0_27) }, + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_P0_27) }, + + { MP_ROM_QSTR(MP_QSTR_P0_28), MP_ROM_PTR(&pin_P0_28) }, + { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_P0_28) }, + + { MP_ROM_QSTR(MP_QSTR_P0_29), MP_ROM_PTR(&pin_P0_29) }, + { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_P0_29) }, + + { MP_ROM_QSTR(MP_QSTR_P0_30), MP_ROM_PTR(&pin_P0_30) }, + { MP_ROM_QSTR(MP_QSTR_A4), MP_ROM_PTR(&pin_P0_30) }, + + { MP_ROM_QSTR(MP_QSTR_P0_31), MP_ROM_PTR(&pin_P0_31) }, + { MP_ROM_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_P0_31) }, + + { MP_ROM_QSTR(MP_QSTR_P1_00), MP_ROM_PTR(&pin_P1_00) }, + + { MP_ROM_QSTR(MP_QSTR_P1_01), MP_ROM_PTR(&pin_P1_01) }, + { MP_ROM_QSTR(MP_QSTR_D0), MP_ROM_PTR(&pin_P1_01) }, + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_P1_01) }, + + { MP_ROM_QSTR(MP_QSTR_P1_02), MP_ROM_PTR(&pin_P1_02) }, + { MP_ROM_QSTR(MP_QSTR_D1), MP_ROM_PTR(&pin_P1_02) }, + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_P1_02) }, + + { MP_ROM_QSTR(MP_QSTR_P1_03), MP_ROM_PTR(&pin_P1_03) }, + { MP_ROM_QSTR(MP_QSTR_D2), MP_ROM_PTR(&pin_P1_03) }, + + { MP_ROM_QSTR(MP_QSTR_P1_04), MP_ROM_PTR(&pin_P1_04) }, + { MP_ROM_QSTR(MP_QSTR_D3), MP_ROM_PTR(&pin_P1_04) }, + + { MP_ROM_QSTR(MP_QSTR_P1_05), MP_ROM_PTR(&pin_P1_05) }, + { MP_ROM_QSTR(MP_QSTR_D4), MP_ROM_PTR(&pin_P1_05) }, + + { MP_ROM_QSTR(MP_QSTR_P1_06), MP_ROM_PTR(&pin_P1_06) }, + { MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_P1_06) }, + + { MP_ROM_QSTR(MP_QSTR_P1_07), MP_ROM_PTR(&pin_P1_07) }, + { MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_P1_07) }, + + { MP_ROM_QSTR(MP_QSTR_P1_08), MP_ROM_PTR(&pin_P1_08) }, + { MP_ROM_QSTR(MP_QSTR_D7), MP_ROM_PTR(&pin_P1_08) }, + + { MP_ROM_QSTR(MP_QSTR_P1_09), MP_ROM_PTR(&pin_P1_09) }, + + { MP_ROM_QSTR(MP_QSTR_P1_10), MP_ROM_PTR(&pin_P1_10) }, + { MP_ROM_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_P1_10) }, + + { MP_ROM_QSTR(MP_QSTR_P1_11), MP_ROM_PTR(&pin_P1_11) }, + { MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_P1_11) }, + + { MP_ROM_QSTR(MP_QSTR_P1_12), MP_ROM_PTR(&pin_P1_12) }, + { MP_ROM_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_P1_12) }, + + { MP_ROM_QSTR(MP_QSTR_P1_13), MP_ROM_PTR(&pin_P1_13) }, + { MP_ROM_QSTR(MP_QSTR_D11), MP_ROM_PTR(&pin_P1_13) }, + { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_P1_13) }, + + { MP_ROM_QSTR(MP_QSTR_P1_14), MP_ROM_PTR(&pin_P1_14) }, + { MP_ROM_QSTR(MP_QSTR_D12), MP_ROM_PTR(&pin_P1_14) }, + { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_P1_14) }, + + // Note that there is no LED on D13. + { MP_ROM_QSTR(MP_QSTR_P1_15), MP_ROM_PTR(&pin_P1_15) }, + { MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_P1_15) }, + { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_P1_15) }, +}; + +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/nrf/boards/pca10056/pins.csv b/ports/nrf/boards/pca10056/pins.csv deleted file mode 100644 index 284370d0602c0..0000000000000 --- a/ports/nrf/boards/pca10056/pins.csv +++ /dev/null @@ -1,48 +0,0 @@ -P0_00,P0_00 -P0_01,P0_01 -P0_02,P0_02 -P0_03,P0_03 -P0_04,P0_04 -P0_05,P0_05 -P0_06,P0_06 -P0_07,P0_07 -P0_08,P0_08 -P0_09,P0_09 -P0_10,P0_10 -P0_11,P0_11 -P0_12,P0_12 -P0_13,P0_13 -P0_14,P0_14 -P0_15,P0_15 -P0_16,P0_16 -P0_17,P0_17 -P0_18,P0_18 -P0_19,P0_19 -P0_20,P0_20 -P0_21,P0_21 -P0_22,P0_22 -P0_23,P0_23 -P0_24,P0_24 -P0_25,P0_25 -P0_26,P0_26 -P0_27,P0_27 -P0_28,P0_28 -P0_29,P0_29 -P0_30,P0_30 -P0_31,P0_31 -P1_00,P1_00 -P1_01,P1_01 -P1_02,P1_02 -P1_03,P1_03 -P1_04,P1_04 -P1_05,P1_05 -P1_06,P1_06 -P1_07,P1_07 -P1_08,P1_08 -P1_09,P1_09 -P1_10,P1_10 -P1_11,P1_11 -P1_12,P1_12 -P1_13,P1_13 -P1_14,P1_14 -P1_15,P1_15 diff --git a/ports/nrf/nrf_pin.h b/ports/nrf/boards/pca10059/board.c similarity index 71% rename from ports/nrf/nrf_pin.h rename to ports/nrf/boards/pca10059/board.c index 7a0ebea78d4de..0b667aa9d99ec 100644 --- a/ports/nrf/nrf_pin.h +++ b/ports/nrf/boards/pca10059/board.c @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,20 +24,30 @@ * THE SOFTWARE. */ -#ifndef __MICROPY_INCLUDED_NRF5_PIN_H__ -#define __MICROPY_INCLUDED_NRF5_PIN_H__ +#include +#include +#include "boards/board.h" +#include "nrfx.h" +#include "usb.h" + +void board_init(void) { + + // Clock + NRF_CLOCK->LFCLKSRC = (uint32_t)((CLOCK_LFCLKSRC_SRC_Xtal << CLOCK_LFCLKSRC_SRC_Pos) & CLOCK_LFCLKSRC_SRC_Msk); + NRF_CLOCK->TASKS_LFCLKSTART = 1UL; + + usb_init(); +} + +bool board_requests_safe_mode(void) { + return false; +} + +void reset_board(void) { + +} -#include "py/obj.h" -typedef struct { - mp_obj_base_t base; - qstr name; - uint32_t port : 1; - uint32_t pin : 5; // Some ARM processors use 32 bits/PORT - uint32_t adc_channel : 4; // 0 is no ADC, ADC channel from 1 to 8 -} pin_obj_t; -extern const mp_obj_type_t mcu_pin_type; -#endif // __MICROPY_INCLUDED_NRF5_PIN_H__ diff --git a/ports/nrf/boards/pca10059/bootloader/6.0.0/pca10056_bootloader_6.0.0_s140.zip b/ports/nrf/boards/pca10059/bootloader/6.0.0/pca10056_bootloader_6.0.0_s140.zip new file mode 100644 index 0000000000000000000000000000000000000000..691f4a1ab3cce19e13c954eb71a4d1feff592c27 GIT binary patch literal 174550 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 == 0) mp_raise_ValueError(translate("Pin does not have ADC capabilities")); - nrf_gpio_cfg_default(NRF_GPIO_PIN_MAP(pin->port, pin->pin)); + nrf_gpio_cfg_default(pin->number); self->pin = pin; } @@ -51,7 +51,7 @@ void common_hal_analogio_analogin_deinit(analogio_analogin_obj_t *self) { if (common_hal_analogio_analogin_deinited(self)) return; - nrf_gpio_cfg_default(NRF_GPIO_PIN_MAP(self->pin->port, self->pin->pin)); + nrf_gpio_cfg_default(self->pin->number); self->pin = mp_const_none; } diff --git a/ports/nrf/common-hal/busio/I2C.c b/ports/nrf/common-hal/busio/I2C.c index 7a29da153e664..9390b1fd853fe 100644 --- a/ports/nrf/common-hal/busio/I2C.c +++ b/ports/nrf/common-hal/busio/I2C.c @@ -54,15 +54,15 @@ static uint8_t twi_error_to_mp(const nrfx_err_t err) { } void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, const mcu_pin_obj_t *scl, const mcu_pin_obj_t *sda, uint32_t frequency, uint32_t timeout) { - if (scl->pin == sda->pin) + if (scl->number == sda->number) mp_raise_ValueError(translate("Invalid pins")); const nrfx_twim_t instance = NRFX_TWIM_INSTANCE(INST_NO); self->twim = instance; nrfx_twim_config_t config = NRFX_TWIM_DEFAULT_CONFIG; - config.scl = NRF_GPIO_PIN_MAP(scl->port, scl->pin); - config.sda = NRF_GPIO_PIN_MAP(sda->port, sda->pin); + config.scl = scl->number; + config.sda = sda->number; // change freq. only if it's less than the default 400K if (frequency < 100000) { diff --git a/ports/nrf/common-hal/busio/SPI.c b/ports/nrf/common-hal/busio/SPI.c index 10974c4c5bb43..d4cf1b7ae9c7e 100644 --- a/ports/nrf/common-hal/busio/SPI.c +++ b/ports/nrf/common-hal/busio/SPI.c @@ -77,13 +77,13 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, const mcu_pin_obj_t * nrfx_spim_config_t config = NRFX_SPIM_DEFAULT_CONFIG; config.frequency = NRF_SPIM_FREQ_8M; - config.sck_pin = NRF_GPIO_PIN_MAP(clock->port, clock->pin); + config.sck_pin = clock->number; if (mosi != (mcu_pin_obj_t*)&mp_const_none_obj) - config.mosi_pin = NRF_GPIO_PIN_MAP(mosi->port, mosi->pin); + config.mosi_pin = mosi->number; if (miso != (mcu_pin_obj_t*)&mp_const_none_obj) - config.miso_pin = NRF_GPIO_PIN_MAP(miso->port, miso->pin); + config.miso_pin = miso->number; nrfx_err_t err = nrfx_spim_init(&self->spim, &config, NULL, NULL); diff --git a/ports/nrf/common-hal/busio/UART.c b/ports/nrf/common-hal/busio/UART.c index 765c987b5d2d4..f05949e1524a8 100644 --- a/ports/nrf/common-hal/busio/UART.c +++ b/ports/nrf/common-hal/busio/UART.c @@ -36,8 +36,6 @@ #include "tick.h" -#include "pins.h" - void common_hal_busio_uart_construct(busio_uart_obj_t *self, const mcu_pin_obj_t * tx, const mcu_pin_obj_t * rx, uint32_t baudrate, uint8_t bits, uart_parity_t parity, uint8_t stop, uint32_t timeout, diff --git a/ports/nrf/common-hal/digitalio/DigitalInOut.c b/ports/nrf/common-hal/digitalio/DigitalInOut.c index 4db9e5efa6094..c8ec12c0321b9 100644 --- a/ports/nrf/common-hal/digitalio/DigitalInOut.c +++ b/ports/nrf/common-hal/digitalio/DigitalInOut.c @@ -34,7 +34,7 @@ digitalinout_result_t common_hal_digitalio_digitalinout_construct( digitalio_digitalinout_obj_t *self, const mcu_pin_obj_t *pin) { self->pin = pin; - nrf_gpio_cfg_input(NRF_GPIO_PIN_MAP(pin->port, pin->pin), NRF_GPIO_PIN_NOPULL); + nrf_gpio_cfg_input(pin->number, NRF_GPIO_PIN_NOPULL); return DIGITALINOUT_OK; } @@ -47,66 +47,53 @@ void common_hal_digitalio_digitalinout_deinit(digitalio_digitalinout_obj_t *self if (common_hal_digitalio_digitalinout_deinited(self)) { return; } - - const uint32_t pin = NRF_GPIO_PIN_MAP(self->pin->port, self->pin->pin); - nrf_gpio_cfg_default(pin); + nrf_gpio_cfg_default(self->pin->number); self->pin = mp_const_none; } void common_hal_digitalio_digitalinout_switch_to_input( digitalio_digitalinout_obj_t *self, digitalio_pull_t pull) { - const uint32_t pin = NRF_GPIO_PIN_MAP(self->pin->port, self->pin->pin); - - nrf_gpio_cfg_input(pin, NRF_GPIO_PIN_NOPULL); - + nrf_gpio_cfg_input(self->pin->number, NRF_GPIO_PIN_NOPULL); common_hal_digitalio_digitalinout_set_pull(self, pull); } void common_hal_digitalio_digitalinout_switch_to_output( digitalio_digitalinout_obj_t *self, bool value, digitalio_drive_mode_t drive_mode) { - const uint32_t pin = NRF_GPIO_PIN_MAP(self->pin->port, self->pin->pin); - self->open_drain = (drive_mode == DRIVE_MODE_OPEN_DRAIN); - nrf_gpio_cfg_input(pin, NRF_GPIO_PIN_NOPULL); + nrf_gpio_cfg_input(self->pin->number, NRF_GPIO_PIN_NOPULL); common_hal_digitalio_digitalinout_set_value(self, value); } digitalio_direction_t common_hal_digitalio_digitalinout_get_direction( digitalio_digitalinout_obj_t *self) { - const uint32_t pin = NRF_GPIO_PIN_MAP(self->pin->port, self->pin->pin); - - return (nrf_gpio_pin_dir_get(pin) == NRF_GPIO_PIN_DIR_OUTPUT) ? DIRECTION_OUTPUT : DIRECTION_INPUT; + return (nrf_gpio_pin_dir_get(self->pin->number) == NRF_GPIO_PIN_DIR_OUTPUT) + ? DIRECTION_OUTPUT : DIRECTION_INPUT; } void common_hal_digitalio_digitalinout_set_value( digitalio_digitalinout_obj_t *self, bool value) { - const uint32_t pin = NRF_GPIO_PIN_MAP(self->pin->port, self->pin->pin); - if (value && self->open_drain) { - nrf_gpio_pin_dir_set(pin, NRF_GPIO_PIN_DIR_INPUT); + nrf_gpio_pin_dir_set(self->pin->number, NRF_GPIO_PIN_DIR_INPUT); } else { - nrf_gpio_pin_dir_set(pin, NRF_GPIO_PIN_DIR_OUTPUT); - nrf_gpio_pin_write(pin, value); + nrf_gpio_pin_dir_set(self->pin->number, NRF_GPIO_PIN_DIR_OUTPUT); + nrf_gpio_pin_write(self->pin->number, value); } } bool common_hal_digitalio_digitalinout_get_value( digitalio_digitalinout_obj_t *self) { - const uint32_t pin = NRF_GPIO_PIN_MAP(self->pin->port, self->pin->pin); - const nrf_gpio_pin_dir_t dir = nrf_gpio_pin_dir_get(pin); - - if (dir == NRF_GPIO_PIN_DIR_INPUT) { + if (nrf_gpio_pin_dir_get(self->pin->number) == NRF_GPIO_PIN_DIR_INPUT) { if (self->open_drain) return true; - return nrf_gpio_pin_read(pin); + return nrf_gpio_pin_read(self->pin->number); } - return nrf_gpio_pin_out_read(pin); + return nrf_gpio_pin_out_read(self->pin->number); } void common_hal_digitalio_digitalinout_set_drive_mode( @@ -131,7 +118,6 @@ digitalio_drive_mode_t common_hal_digitalio_digitalinout_get_drive_mode( void common_hal_digitalio_digitalinout_set_pull( digitalio_digitalinout_obj_t *self, digitalio_pull_t pull) { - const uint32_t pin = NRF_GPIO_PIN_MAP(self->pin->port, self->pin->pin); nrf_gpio_pin_pull_t hal_pull = NRF_GPIO_PIN_NOPULL; switch (pull) { @@ -146,12 +132,13 @@ void common_hal_digitalio_digitalinout_set_pull( break; } - nrf_gpio_cfg_input(pin, hal_pull); + nrf_gpio_cfg_input(self->pin->number, hal_pull); } digitalio_pull_t common_hal_digitalio_digitalinout_get_pull( digitalio_digitalinout_obj_t *self) { - uint32_t pin = NRF_GPIO_PIN_MAP(self->pin->port, self->pin->pin); + uint32_t pin = self->pin->number; + // Changes pin to be a relative pin number in port. NRF_GPIO_Type *reg = nrf_gpio_pin_port_decode(&pin); if (nrf_gpio_pin_dir_get(pin) == NRF_GPIO_PIN_DIR_OUTPUT) { @@ -159,7 +146,7 @@ digitalio_pull_t common_hal_digitalio_digitalinout_get_pull( return PULL_NONE; } - switch (reg->PIN_CNF[self->pin->pin] & GPIO_PIN_CNF_PULL_Msk) { + switch (reg->PIN_CNF[pin] & GPIO_PIN_CNF_PULL_Msk) { case NRF_GPIO_PIN_PULLUP: return PULL_UP; diff --git a/ports/nrf/common-hal/microcontroller/Pin.c b/ports/nrf/common-hal/microcontroller/Pin.c index 1b7ac0d838d7b..4d2dea31e1f31 100644 --- a/ports/nrf/common-hal/microcontroller/Pin.c +++ b/ports/nrf/common-hal/microcontroller/Pin.c @@ -24,11 +24,32 @@ * THE SOFTWARE. */ -#include "common-hal/microcontroller/Pin.h" +#include "shared-bindings/microcontroller/Pin.h" + #include "nrf_gpio.h" #include "py/mphal.h" +#include "nrf/pins.h" +#include "supervisor/shared/rgb_led_status.h" + +#ifdef MICROPY_HW_NEOPIXEL +bool neopixel_in_use; +#endif +#ifdef MICROPY_HW_APA102_MOSI +bool apa102_sck_in_use; +bool apa102_mosi_in_use; +#endif +#ifdef SPEAKER_ENABLE_PIN +bool speaker_enable_in_use; +#endif + +// Bit mask of claimed pins on each of up to two ports. nrf52832 has one port; nrf52840 has two. +STATIC bool claimed_pins[2]; + void reset_all_pins(void) { + claimed_pins[0] = 0; + claimed_pins[1] = 0; + for (uint32_t pin = 0; pin < NUMBER_OF_PINS; ++pin) { nrf_gpio_cfg_default(pin); } @@ -48,7 +69,49 @@ void reset_all_pins(void) { #endif } +// Mark pin as free and return it to a quiescent state. +void reset_pin(uint8_t pin) { + // Ignore out-of-bound pin numbers. NUMBER_OF_PINS is from nrf_gpio.h. + if (pin >= NUMBER_OF_PINS) { + return; + } + + // Clear claimed bit. + claimed_pins[nrf_pin_port(pin)] &= ~(1 << nrf_relative_pin_number(pin)); + + #ifdef MICROPY_HW_NEOPIXEL + if (pin == MICROPY_HW_NEOPIXEL->number) { + neopixel_in_use = false; + rgb_led_status_init(); + return; + } + #endif + #ifdef MICROPY_HW_APA102_MOSI + if (pin == MICROPY_HW_APA102_MOSI->number || + pin == MICROPY_HW_APA102_SCK->number) { + apa102_mosi_in_use = apa102_mosi_in_use && pin != MICROPY_HW_APA102_MOSI->number; + apa102_sck_in_use = apa102_sck_in_use && pin != MICROPY_HW_APA102_SCK->number; + if (!apa102_sck_in_use && !apa102_mosi_in_use) { + rgb_led_status_init(); + } + return; + } + #endif + + #ifdef SPEAKER_ENABLE_PIN + if (pin == SPEAKER_ENABLE_PIN->number) { + speaker_enable_in_use = false; + common_hal_digitalio_digitalinout_switch_to_output( + nrf_gpio_pin_dir_set(pin, NRF_GPIO_PIN_DIR_OUTPUT); + nrf_gpio_pin_write(pin, false); + } + #endif +} + void claim_pin(const mcu_pin_obj_t* pin) { + // Set bit in claimed_pins bitmask. + claimed_pins[nrf_pin_port(pin->number)] |= 1 << nrf_relative_pin_number(pin->number); + #ifdef MICROPY_HW_NEOPIXEL if (pin == MICROPY_HW_NEOPIXEL) { neopixel_in_use = true; @@ -91,6 +154,5 @@ bool common_hal_mcu_pin_is_free(const mcu_pin_obj_t *pin) { } #endif - // TODO check pin enable. - return true; + return !(claimed_pins[nrf_pin_port(pin->number)] & (nrf_relative_pin_number(pin->number))); } diff --git a/ports/nrf/common-hal/microcontroller/Pin.h b/ports/nrf/common-hal/microcontroller/Pin.h index 954d6e51df9b2..1e751c714e135 100644 --- a/ports/nrf/common-hal/microcontroller/Pin.h +++ b/ports/nrf/common-hal/microcontroller/Pin.h @@ -27,9 +27,10 @@ #ifndef MICROPY_INCLUDED_NRF_COMMON_HAL_MICROCONTROLLER_PIN_H #define MICROPY_INCLUDED_NRF_COMMON_HAL_MICROCONTROLLER_PIN_H -#include "nrf_pin.h" #include "py/mphal.h" +#include "peripherals/nrf/pins.h" + #ifdef MICROPY_HW_NEOPIXEL extern bool neopixel_in_use; #endif @@ -38,11 +39,21 @@ extern bool apa102_sck_in_use; extern bool apa102_mosi_in_use; #endif -#define mcu_pin_obj_t pin_obj_t void reset_all_pins(void); // reset_pin takes the pin number instead of the pointer so that objects don't // need to store a full pointer. void reset_pin(uint8_t pin); void claim_pin(const mcu_pin_obj_t* pin); +// Lower 5 bits of a pin number are the pin number in a port. +// upper bits (just one bit for current chips) is port number. + +static inline uint8_t nrf_pin_port(uint8_t absolute_pin) { + return absolute_pin >> 5; +} + +static inline uint8_t nrf_relative_pin_number(uint8_t absolute_pin) { + return absolute_pin & 0x1f; +} + #endif // MICROPY_INCLUDED_NRF_COMMON_HAL_MICROCONTROLLER_PIN_H diff --git a/ports/nrf/common-hal/microcontroller/__init__.c b/ports/nrf/common-hal/microcontroller/__init__.c index e88c7413650dc..46fe1e1907aff 100644 --- a/ports/nrf/common-hal/microcontroller/__init__.c +++ b/ports/nrf/common-hal/microcontroller/__init__.c @@ -62,3 +62,59 @@ const mcu_processor_obj_t common_hal_mcu_processor_obj = { .type = &mcu_processor_type, }, }; + + +STATIC const mp_rom_map_elem_t mcu_pin_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR_P0_00), MP_ROM_PTR(&pin_P0_00) }, + { MP_ROM_QSTR(MP_QSTR_P0_01), MP_ROM_PTR(&pin_P0_01) }, + { MP_ROM_QSTR(MP_QSTR_P0_02), MP_ROM_PTR(&pin_P0_02) }, + { MP_ROM_QSTR(MP_QSTR_P0_03), MP_ROM_PTR(&pin_P0_03) }, + { MP_ROM_QSTR(MP_QSTR_P0_04), MP_ROM_PTR(&pin_P0_04) }, + { MP_ROM_QSTR(MP_QSTR_P0_05), MP_ROM_PTR(&pin_P0_05) }, + { MP_ROM_QSTR(MP_QSTR_P0_06), MP_ROM_PTR(&pin_P0_06) }, + { MP_ROM_QSTR(MP_QSTR_P0_07), MP_ROM_PTR(&pin_P0_07) }, + { MP_ROM_QSTR(MP_QSTR_P0_08), MP_ROM_PTR(&pin_P0_08) }, + { MP_ROM_QSTR(MP_QSTR_P0_09), MP_ROM_PTR(&pin_P0_09) }, + { MP_ROM_QSTR(MP_QSTR_P0_10), MP_ROM_PTR(&pin_P0_10) }, + { MP_ROM_QSTR(MP_QSTR_P0_11), MP_ROM_PTR(&pin_P0_11) }, + { MP_ROM_QSTR(MP_QSTR_P0_12), MP_ROM_PTR(&pin_P0_12) }, + { MP_ROM_QSTR(MP_QSTR_P0_13), MP_ROM_PTR(&pin_P0_13) }, + { MP_ROM_QSTR(MP_QSTR_P0_13), MP_ROM_PTR(&pin_P0_13) }, + { MP_ROM_QSTR(MP_QSTR_P0_14), MP_ROM_PTR(&pin_P0_14) }, + { MP_ROM_QSTR(MP_QSTR_P0_15), MP_ROM_PTR(&pin_P0_15) }, + { MP_ROM_QSTR(MP_QSTR_P0_16), MP_ROM_PTR(&pin_P0_16) }, + { MP_ROM_QSTR(MP_QSTR_P0_17), MP_ROM_PTR(&pin_P0_17) }, + { MP_ROM_QSTR(MP_QSTR_P0_18), MP_ROM_PTR(&pin_P0_18) }, + { MP_ROM_QSTR(MP_QSTR_P0_19), MP_ROM_PTR(&pin_P0_19) }, + { MP_ROM_QSTR(MP_QSTR_P0_20), MP_ROM_PTR(&pin_P0_20) }, + { MP_ROM_QSTR(MP_QSTR_P0_21), MP_ROM_PTR(&pin_P0_21) }, + { MP_ROM_QSTR(MP_QSTR_P0_22), MP_ROM_PTR(&pin_P0_22) }, + { MP_ROM_QSTR(MP_QSTR_P0_23), MP_ROM_PTR(&pin_P0_23) }, + { MP_ROM_QSTR(MP_QSTR_P0_24), MP_ROM_PTR(&pin_P0_24) }, + { MP_ROM_QSTR(MP_QSTR_P0_25), MP_ROM_PTR(&pin_P0_25) }, + { MP_ROM_QSTR(MP_QSTR_P0_26), MP_ROM_PTR(&pin_P0_26) }, + { MP_ROM_QSTR(MP_QSTR_P0_27), MP_ROM_PTR(&pin_P0_27) }, + { MP_ROM_QSTR(MP_QSTR_P0_28), MP_ROM_PTR(&pin_P0_28) }, + { MP_ROM_QSTR(MP_QSTR_P0_29), MP_ROM_PTR(&pin_P0_29) }, + { MP_ROM_QSTR(MP_QSTR_P0_30), MP_ROM_PTR(&pin_P0_30) }, + { MP_ROM_QSTR(MP_QSTR_P0_31), MP_ROM_PTR(&pin_P0_31) }, +#ifdef NRF52840 + { MP_ROM_QSTR(MP_QSTR_P1_00), MP_ROM_PTR(&pin_P1_00) }, + { MP_ROM_QSTR(MP_QSTR_P1_01), MP_ROM_PTR(&pin_P1_01) }, + { MP_ROM_QSTR(MP_QSTR_P1_02), MP_ROM_PTR(&pin_P1_02) }, + { MP_ROM_QSTR(MP_QSTR_P1_03), MP_ROM_PTR(&pin_P1_03) }, + { MP_ROM_QSTR(MP_QSTR_P1_04), MP_ROM_PTR(&pin_P1_04) }, + { MP_ROM_QSTR(MP_QSTR_P1_05), MP_ROM_PTR(&pin_P1_05) }, + { MP_ROM_QSTR(MP_QSTR_P1_06), MP_ROM_PTR(&pin_P1_06) }, + { MP_ROM_QSTR(MP_QSTR_P1_07), MP_ROM_PTR(&pin_P1_07) }, + { MP_ROM_QSTR(MP_QSTR_P1_08), MP_ROM_PTR(&pin_P1_08) }, + { MP_ROM_QSTR(MP_QSTR_P1_09), MP_ROM_PTR(&pin_P1_09) }, + { MP_ROM_QSTR(MP_QSTR_P1_10), MP_ROM_PTR(&pin_P1_10) }, + { MP_ROM_QSTR(MP_QSTR_P1_11), MP_ROM_PTR(&pin_P1_11) }, + { MP_ROM_QSTR(MP_QSTR_P1_12), MP_ROM_PTR(&pin_P1_12) }, + { MP_ROM_QSTR(MP_QSTR_P1_13), MP_ROM_PTR(&pin_P1_13) }, + { MP_ROM_QSTR(MP_QSTR_P1_14), MP_ROM_PTR(&pin_P1_14) }, + { MP_ROM_QSTR(MP_QSTR_P1_15), MP_ROM_PTR(&pin_P1_15) }, +#endif +}; +MP_DEFINE_CONST_DICT(mcu_pin_globals, mcu_pin_globals_table); diff --git a/ports/nrf/common-hal/neopixel_write/__init__.c b/ports/nrf/common-hal/neopixel_write/__init__.c new file mode 100644 index 0000000000000..a29e1a136909d --- /dev/null +++ b/ports/nrf/common-hal/neopixel_write/__init__.c @@ -0,0 +1,161 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Scott Shawcroft for Adafruit Industries + * + * 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/mphal.h" + +#include "shared-bindings/neopixel_write/__init__.h" + +#include "tick.h" + +// This magical macro makes sure the delay isn't optimized out and is the +// minimal three instructions. +#define delay_cycles(cycles) \ +{ \ + uint32_t t; \ + asm volatile ( \ + "movs %[t], %[c]\n\t" \ + "loop%=:\n\t" \ + "subs %[t], #1\n\t" \ + "bne.n loop%=" : [t] "=r"(t) : [c] "I" (cycles)); \ + } + +uint64_t next_start_tick_ms = 0; +uint32_t next_start_tick_us = 1000; + +void common_hal_neopixel_write(const digitalio_digitalinout_obj_t* digitalinout, uint8_t *pixels, uint32_t numBytes) { +// TODO: Figure out timing delays on nRF. Turn off cache using ICACHECNF register. +/* + // This is adapted directly from the Adafruit NeoPixel library SAMD21G18A code: + // https://github.com/adafruit/Adafruit_NeoPixel/blob/master/Adafruit_NeoPixel.cpp + uint8_t *ptr, *end, p, bitMask; + uint32_t pinMask; + PortGroup* port; + + // This must be called while interrupts are on in case we're waiting for a + // future ms tick. + wait_until(next_start_tick_ms, next_start_tick_us); + + // Turn off interrupts of any kind during timing-sensitive code. + mp_hal_disable_all_interrupts(); + + + // Make sure the NVM cache is consistently timed. + + NVMCTRL->CTRLB.bit.READMODE = NVMCTRL_CTRLB_READMODE_DETERMINISTIC_Val; + #endif + + uint32_t pin = digitalinout->pin->number; + port = &PORT->Group[GPIO_PORT(pin)]; // Convert GPIO # to port register + pinMask = (1UL << (pin % 32)); // From port_pin_set_output_level ASF code. + ptr = pixels; + end = ptr + numBytes; + p = *ptr++; + bitMask = 0x80; + + volatile uint32_t *set = &(port->OUTSET.reg), + *clr = &(port->OUTCLR.reg); + + for(;;) { + *set = pinMask; + // This is the time where the line is always high regardless of the bit. + // For the SK6812 its 0.3us +- 0.15us + #ifdef SAMD21 + asm("nop; nop;"); + #endif + #ifdef SAMD51 + delay_cycles(3); + #endif + if(p & bitMask) { + // This is the high delay unique to a one bit. + // For the SK6812 its 0.3us + #ifdef SAMD21 + asm("nop; nop; nop; nop; nop; nop; nop;"); + #endif + #ifdef SAMD51 + delay_cycles(11); + #endif + *clr = pinMask; + } else { + *clr = pinMask; + // This is the low delay unique to a zero bit. + // For the SK6812 its 0.3us + #ifdef SAMD21 + asm("nop; nop;"); + #endif + #ifdef SAMD51 + delay_cycles(3); + #endif + } + if((bitMask >>= 1) != 0) { + // This is the delay between bits in a byte and is the 1 code low + // level time from the datasheet. + // For the SK6812 its 0.6us +- 0.15us + #ifdef SAMD21 + asm("nop; nop; nop; nop; nop;"); + #endif + #ifdef SAMD51 + delay_cycles(20); + #endif + } else { + if(ptr >= end) break; + p = *ptr++; + bitMask = 0x80; + // This is the delay between bytes. It's similar to the other branch + // in the if statement except its tuned to account for the time the + // above operations take. + // For the SK6812 its 0.6us +- 0.15us + #ifdef SAMD51 + delay_cycles(15); + #endif + } + } + + #ifdef SAMD21 + // Speed up! (But inconsistent timing.) + NVMCTRL->CTRLB.bit.READMODE = NVMCTRL_CTRLB_READMODE_NO_MISS_PENALTY_Val; + #endif + + #ifdef SAMD51 + // Turn instruction, data, and NVM caches back on. + hri_cmcc_clear_CFG_reg(CMCC, CMCC_CFG_DCDIS | CMCC_CFG_ICDIS); + hri_nvmctrl_clear_CTRLA_CACHEDIS0_bit(NVMCTRL); + hri_nvmctrl_clear_CTRLA_CACHEDIS1_bit(NVMCTRL); + + #endif + + // ticks_ms may be out of date at this point because we stopped the + // interrupt. We'll risk it anyway. + current_tick(&next_start_tick_ms, &next_start_tick_us); + if (next_start_tick_us < 100) { + next_start_tick_ms += 1; + next_start_tick_us = 100 - next_start_tick_us; + } else { + next_start_tick_us -= 100; + } + + // Turn on interrupts after timing-sensitive code. + mp_hal_enable_all_interrupts(); +*/ +} diff --git a/ports/nrf/common-hal/pulseio/PWMOut.c b/ports/nrf/common-hal/pulseio/PWMOut.c index 0f14610924232..c3c51d56698d3 100644 --- a/ports/nrf/common-hal/pulseio/PWMOut.c +++ b/ports/nrf/common-hal/pulseio/PWMOut.c @@ -146,7 +146,7 @@ void common_hal_pulseio_pwmout_construct(pulseio_pwmout_obj_t* self, // check if mapped to PWM channel already for(int i=0; iport, pin->pin)); + int ch = pin2channel(pwm_arr[i], pin->number); if ( ch >= 0 ) { self->pwm = pwm_arr[i]; @@ -163,12 +163,12 @@ void common_hal_pulseio_pwmout_construct(pulseio_pwmout_obj_t* self, if (self->pwm) { - nrf_gpio_cfg_output(NRF_GPIO_PIN_MAP(pin->port, pin->pin)); + nrf_gpio_cfg_output(pin->number); // disable before mapping pin channel self->pwm->ENABLE = 0; - self->pwm->PSEL.OUT[self->channel] = NRF_GPIO_PIN_MAP(pin->port, pin->pin); + self->pwm->PSEL.OUT[self->channel] = pin->number; self->pwm->COUNTERTOP = (PWM_MAX_FREQ/frequency); self->freq = frequency; @@ -203,7 +203,7 @@ void common_hal_pulseio_pwmout_deinit(pulseio_pwmout_obj_t* self) { } } - nrf_gpio_cfg_default(NRF_GPIO_PIN_MAP(self->pin->port, self->pin->pin)); + nrf_gpio_cfg_default(self->pin->number); self->pwm = NULL; self->pin = mp_const_none; diff --git a/ports/nrf/nrf52_af.csv b/ports/nrf/nrf52_af.csv deleted file mode 100644 index 272d9cd09be92..0000000000000 --- a/ports/nrf/nrf52_af.csv +++ /dev/null @@ -1,48 +0,0 @@ -P0_00 -P0_01 -P0_02,AIN0 -P0_03,AIN1 -P0_04,AIN2 -P0_05,AIN3 -P0_06 -P0_07 -P0_08 -P0_09 -P0_10 -P0_11 -P0_12 -P0_13 -P0_14 -P0_15 -P0_16 -P0_17 -P0_18 -P0_19 -P0_20 -P0_21 -P0_22 -P0_23 -P0_24 -P0_25 -P0_26 -P0_27 -P0_28,AIN4 -P0_29,AIN5 -P0_30,AIN6 -P0_31,AIN7 -P1_00 -P1_01 -P1_02 -P1_03 -P1_04 -P1_05 -P1_06 -P1_07 -P1_08 -P1_09 -P1_10 -P1_11 -P1_12 -P1_13 -P1_14 -P1_15 diff --git a/ports/nrf/peripherals/nrf/nrf52832/pins.c b/ports/nrf/peripherals/nrf/nrf52832/pins.c new file mode 100644 index 0000000000000..fdfa766ec8c5f --- /dev/null +++ b/ports/nrf/peripherals/nrf/nrf52832/pins.c @@ -0,0 +1,65 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Dan Halbert for Adafruit Industries + * + * 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. + */ + +// DO NOT include this file directly. Use shared-bindings/microcontroller/Pin.h instead to ensure +// that all necessary includes are already included. + +#include "py/obj.h" +#include "py/mphal.h" +#include "nrf/pins.h" + +const mcu_pin_obj_t pin_P0_00 = PIN(P0_00, 0, 0, 0); +const mcu_pin_obj_t pin_P0_01 = PIN(P0_01, 0, 1, 0); +const mcu_pin_obj_t pin_P0_02 = PIN(P0_02, 0, 2, SAADC_CH_PSELP_PSELP_AnalogInput0); +const mcu_pin_obj_t pin_P0_03 = PIN(P0_03, 0, 3, SAADC_CH_PSELP_PSELP_AnalogInput1); +const mcu_pin_obj_t pin_P0_04 = PIN(P0_04, 0, 4, SAADC_CH_PSELP_PSELP_AnalogInput2); +const mcu_pin_obj_t pin_P0_05 = PIN(P0_05, 0, 5, SAADC_CH_PSELP_PSELP_AnalogInput3); +const mcu_pin_obj_t pin_P0_06 = PIN(P0_06, 0, 6, 0); +const mcu_pin_obj_t pin_P0_07 = PIN(P0_07, 0, 7, 0); +const mcu_pin_obj_t pin_P0_08 = PIN(P0_08, 0, 8, 0); +const mcu_pin_obj_t pin_P0_09 = PIN(P0_09, 0, 9, 0); +const mcu_pin_obj_t pin_P0_10 = PIN(P0_10, 0, 10, 0); +const mcu_pin_obj_t pin_P0_11 = PIN(P0_11, 0, 11, 0); +const mcu_pin_obj_t pin_P0_12 = PIN(P0_12, 0, 12, 0); +const mcu_pin_obj_t pin_P0_13 = PIN(P0_13, 0, 13, 0); +const mcu_pin_obj_t pin_P0_14 = PIN(P0_14, 0, 14, 0); +const mcu_pin_obj_t pin_P0_15 = PIN(P0_15, 0, 15, 0); +const mcu_pin_obj_t pin_P0_16 = PIN(P0_16, 0, 16, 0); +const mcu_pin_obj_t pin_P0_17 = PIN(P0_17, 0, 17, 0); +const mcu_pin_obj_t pin_P0_18 = PIN(P0_18, 0, 18, 0); +const mcu_pin_obj_t pin_P0_19 = PIN(P0_19, 0, 19, 0); +const mcu_pin_obj_t pin_P0_20 = PIN(P0_20, 0, 20, 0); +const mcu_pin_obj_t pin_P0_21 = PIN(P0_21, 0, 21, 0); +const mcu_pin_obj_t pin_P0_22 = PIN(P0_22, 0, 22, 0); +const mcu_pin_obj_t pin_P0_23 = PIN(P0_23, 0, 23, 0); +const mcu_pin_obj_t pin_P0_24 = PIN(P0_24, 0, 24, 0); +const mcu_pin_obj_t pin_P0_25 = PIN(P0_25, 0, 25, 0); +const mcu_pin_obj_t pin_P0_26 = PIN(P0_26, 0, 26, 0); +const mcu_pin_obj_t pin_P0_27 = PIN(P0_27, 0, 27, 0); +const mcu_pin_obj_t pin_P0_28 = PIN(P0_28, 0, 28, SAADC_CH_PSELP_PSELP_AnalogInput4); +const mcu_pin_obj_t pin_P0_29 = PIN(P0_29, 0, 29, SAADC_CH_PSELP_PSELP_AnalogInput5); +const mcu_pin_obj_t pin_P0_30 = PIN(P0_30, 0, 30, SAADC_CH_PSELP_PSELP_AnalogInput6); +const mcu_pin_obj_t pin_P0_31 = PIN(P0_31, 0, 31, SAADC_CH_PSELP_PSELP_AnalogInput7); diff --git a/ports/nrf/peripherals/nrf/nrf52832/pins.h b/ports/nrf/peripherals/nrf/nrf52832/pins.h new file mode 100644 index 0000000000000..0bc039df00d3b --- /dev/null +++ b/ports/nrf/peripherals/nrf/nrf52832/pins.h @@ -0,0 +1,65 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 by Dan Halbert for Adafruit Industries + * + * 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_NRF_PERIPHERALS_NRF52832_PINS_H +#define MICROPY_INCLUDED_NRF_PERIPHERALS_NRF52832_PINS_H + +void reset_pin(uint8_t pin); + +extern const mcu_pin_obj_t pin_P0_00; +extern const mcu_pin_obj_t pin_P0_01; +extern const mcu_pin_obj_t pin_P0_02; +extern const mcu_pin_obj_t pin_P0_03; +extern const mcu_pin_obj_t pin_P0_04; +extern const mcu_pin_obj_t pin_P0_05; +extern const mcu_pin_obj_t pin_P0_06; +extern const mcu_pin_obj_t pin_P0_07; +extern const mcu_pin_obj_t pin_P0_08; +extern const mcu_pin_obj_t pin_P0_09; +extern const mcu_pin_obj_t pin_P0_10; +extern const mcu_pin_obj_t pin_P0_11; +extern const mcu_pin_obj_t pin_P0_12; +extern const mcu_pin_obj_t pin_P0_13; +extern const mcu_pin_obj_t pin_P0_14; +extern const mcu_pin_obj_t pin_P0_15; +extern const mcu_pin_obj_t pin_P0_16; +extern const mcu_pin_obj_t pin_P0_17; +extern const mcu_pin_obj_t pin_P0_18; +extern const mcu_pin_obj_t pin_P0_19; +extern const mcu_pin_obj_t pin_P0_20; +extern const mcu_pin_obj_t pin_P0_21; +extern const mcu_pin_obj_t pin_P0_22; +extern const mcu_pin_obj_t pin_P0_23; +extern const mcu_pin_obj_t pin_P0_24; +extern const mcu_pin_obj_t pin_P0_25; +extern const mcu_pin_obj_t pin_P0_26; +extern const mcu_pin_obj_t pin_P0_27; +extern const mcu_pin_obj_t pin_P0_28; +extern const mcu_pin_obj_t pin_P0_29; +extern const mcu_pin_obj_t pin_P0_30; +extern const mcu_pin_obj_t pin_P0_31; + +#endif // MICROPY_INCLUDED_NRF_PERIPHERALS_NRF52832_PINS_H diff --git a/ports/nrf/peripherals/nrf/nrf52840/pins.c b/ports/nrf/peripherals/nrf/nrf52840/pins.c new file mode 100644 index 0000000000000..b7dc8e65e0598 --- /dev/null +++ b/ports/nrf/peripherals/nrf/nrf52840/pins.c @@ -0,0 +1,78 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Dan Halbert for Adafruit Industries + * + * 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 "py/mphal.h" +#include "nrf/pins.h" + +const mcu_pin_obj_t pin_P0_00 = PIN(P0_00, 0, 0, 0); +const mcu_pin_obj_t pin_P0_01 = PIN(P0_01, 0, 1, 0); +const mcu_pin_obj_t pin_P0_02 = PIN(P0_02, 0, 2, SAADC_CH_PSELP_PSELP_AnalogInput0); +const mcu_pin_obj_t pin_P0_03 = PIN(P0_03, 0, 3, SAADC_CH_PSELP_PSELP_AnalogInput1); +const mcu_pin_obj_t pin_P0_04 = PIN(P0_04, 0, 4, SAADC_CH_PSELP_PSELP_AnalogInput2); +const mcu_pin_obj_t pin_P0_05 = PIN(P0_05, 0, 5, SAADC_CH_PSELP_PSELP_AnalogInput3); +const mcu_pin_obj_t pin_P0_06 = PIN(P0_06, 0, 6, 0); +const mcu_pin_obj_t pin_P0_07 = PIN(P0_07, 0, 7, 0); +const mcu_pin_obj_t pin_P0_08 = PIN(P0_08, 0, 8, 0); +const mcu_pin_obj_t pin_P0_09 = PIN(P0_09, 0, 9, 0); +const mcu_pin_obj_t pin_P0_10 = PIN(P0_10, 0, 10, 0); +const mcu_pin_obj_t pin_P0_11 = PIN(P0_11, 0, 11, 0); +const mcu_pin_obj_t pin_P0_12 = PIN(P0_12, 0, 12, 0); +const mcu_pin_obj_t pin_P0_13 = PIN(P0_13, 0, 13, 0); +const mcu_pin_obj_t pin_P0_14 = PIN(P0_14, 0, 14, 0); +const mcu_pin_obj_t pin_P0_15 = PIN(P0_15, 0, 15, 0); +const mcu_pin_obj_t pin_P0_16 = PIN(P0_16, 0, 16, 0); +const mcu_pin_obj_t pin_P0_17 = PIN(P0_17, 0, 17, 0); +const mcu_pin_obj_t pin_P0_18 = PIN(P0_18, 0, 18, 0); +const mcu_pin_obj_t pin_P0_19 = PIN(P0_19, 0, 19, 0); +const mcu_pin_obj_t pin_P0_20 = PIN(P0_20, 0, 20, 0); +const mcu_pin_obj_t pin_P0_21 = PIN(P0_21, 0, 21, 0); +const mcu_pin_obj_t pin_P0_22 = PIN(P0_22, 0, 22, 0); +const mcu_pin_obj_t pin_P0_23 = PIN(P0_23, 0, 23, 0); +const mcu_pin_obj_t pin_P0_24 = PIN(P0_24, 0, 24, 0); +const mcu_pin_obj_t pin_P0_25 = PIN(P0_25, 0, 25, 0); +const mcu_pin_obj_t pin_P0_26 = PIN(P0_26, 0, 26, 0); +const mcu_pin_obj_t pin_P0_27 = PIN(P0_27, 0, 27, 0); +const mcu_pin_obj_t pin_P0_28 = PIN(P0_28, 0, 28, SAADC_CH_PSELP_PSELP_AnalogInput4); +const mcu_pin_obj_t pin_P0_29 = PIN(P0_29, 0, 29, SAADC_CH_PSELP_PSELP_AnalogInput5); +const mcu_pin_obj_t pin_P0_30 = PIN(P0_30, 0, 30, SAADC_CH_PSELP_PSELP_AnalogInput6); +const mcu_pin_obj_t pin_P0_31 = PIN(P0_31, 0, 31, SAADC_CH_PSELP_PSELP_AnalogInput7); +const mcu_pin_obj_t pin_P1_00 = PIN(P1_00, 1, 0, 0); +const mcu_pin_obj_t pin_P1_01 = PIN(P1_01, 1, 1, 0); +const mcu_pin_obj_t pin_P1_02 = PIN(P1_02, 1, 2, 0); +const mcu_pin_obj_t pin_P1_03 = PIN(P1_03, 1, 3, 0); +const mcu_pin_obj_t pin_P1_04 = PIN(P1_04, 1, 4, 0); +const mcu_pin_obj_t pin_P1_05 = PIN(P1_05, 1, 5, 0); +const mcu_pin_obj_t pin_P1_06 = PIN(P1_06, 1, 6, 0); +const mcu_pin_obj_t pin_P1_07 = PIN(P1_07, 1, 7, 0); +const mcu_pin_obj_t pin_P1_08 = PIN(P1_08, 1, 8, 0); +const mcu_pin_obj_t pin_P1_09 = PIN(P1_09, 1, 9, 0); +const mcu_pin_obj_t pin_P1_10 = PIN(P1_10, 1, 10, 0); +const mcu_pin_obj_t pin_P1_11 = PIN(P1_11, 1, 11, 0); +const mcu_pin_obj_t pin_P1_12 = PIN(P1_12, 1, 12, 0); +const mcu_pin_obj_t pin_P1_13 = PIN(P1_13, 1, 13, 0); +const mcu_pin_obj_t pin_P1_14 = PIN(P1_14, 1, 14, 0); +const mcu_pin_obj_t pin_P1_15 = PIN(P1_15, 1, 15, 0); diff --git a/ports/nrf/peripherals/nrf/nrf52840/pins.h b/ports/nrf/peripherals/nrf/nrf52840/pins.h new file mode 100644 index 0000000000000..80f1d14af3345 --- /dev/null +++ b/ports/nrf/peripherals/nrf/nrf52840/pins.h @@ -0,0 +1,81 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 by Dan Halbert for Adafruit Industries + * + * 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_NRF_PERIPHERALS_NRF52840_PINS_H +#define MICROPY_INCLUDED_NRF_PERIPHERALS_NRF52840_PINS_H + +void reset_pin(uint8_t pin); + +extern const mcu_pin_obj_t pin_P0_00; +extern const mcu_pin_obj_t pin_P0_01; +extern const mcu_pin_obj_t pin_P0_02; +extern const mcu_pin_obj_t pin_P0_03; +extern const mcu_pin_obj_t pin_P0_04; +extern const mcu_pin_obj_t pin_P0_05; +extern const mcu_pin_obj_t pin_P0_06; +extern const mcu_pin_obj_t pin_P0_07; +extern const mcu_pin_obj_t pin_P0_08; +extern const mcu_pin_obj_t pin_P0_09; +extern const mcu_pin_obj_t pin_P0_10; +extern const mcu_pin_obj_t pin_P0_11; +extern const mcu_pin_obj_t pin_P0_12; +extern const mcu_pin_obj_t pin_P0_13; +extern const mcu_pin_obj_t pin_P0_14; +extern const mcu_pin_obj_t pin_P0_15; +extern const mcu_pin_obj_t pin_P0_16; +extern const mcu_pin_obj_t pin_P0_17; +extern const mcu_pin_obj_t pin_P0_18; +extern const mcu_pin_obj_t pin_P0_19; +extern const mcu_pin_obj_t pin_P0_20; +extern const mcu_pin_obj_t pin_P0_21; +extern const mcu_pin_obj_t pin_P0_22; +extern const mcu_pin_obj_t pin_P0_23; +extern const mcu_pin_obj_t pin_P0_24; +extern const mcu_pin_obj_t pin_P0_25; +extern const mcu_pin_obj_t pin_P0_26; +extern const mcu_pin_obj_t pin_P0_27; +extern const mcu_pin_obj_t pin_P0_28; +extern const mcu_pin_obj_t pin_P0_29; +extern const mcu_pin_obj_t pin_P0_30; +extern const mcu_pin_obj_t pin_P0_31; +extern const mcu_pin_obj_t pin_P1_00; +extern const mcu_pin_obj_t pin_P1_01; +extern const mcu_pin_obj_t pin_P1_02; +extern const mcu_pin_obj_t pin_P1_03; +extern const mcu_pin_obj_t pin_P1_04; +extern const mcu_pin_obj_t pin_P1_05; +extern const mcu_pin_obj_t pin_P1_06; +extern const mcu_pin_obj_t pin_P1_07; +extern const mcu_pin_obj_t pin_P1_08; +extern const mcu_pin_obj_t pin_P1_09; +extern const mcu_pin_obj_t pin_P1_10; +extern const mcu_pin_obj_t pin_P1_11; +extern const mcu_pin_obj_t pin_P1_12; +extern const mcu_pin_obj_t pin_P1_13; +extern const mcu_pin_obj_t pin_P1_14; +extern const mcu_pin_obj_t pin_P1_15; + +#endif // MICROPY_INCLUDED_NRF_PERIPHERALS_NRF52840_PINS_H diff --git a/ports/nrf/peripherals/nrf/pins.h b/ports/nrf/peripherals/nrf/pins.h new file mode 100644 index 0000000000000..ca58f5fad09ac --- /dev/null +++ b/ports/nrf/peripherals/nrf/pins.h @@ -0,0 +1,69 @@ +/* + * 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. + */ + +// DO NOT include this file directly. Use shared-bindings/microcontroller/Pin.h instead to ensure +// that all necessary includes are already included. + +#ifndef __MICROPY_INCLUDED_NRF_PERIPHERALS_PINS_H__ +#define __MICROPY_INCLUDED_NRF_PERIPHERALS_PINS_H__ + +#include +#include + +#include "nrf_gpio.h" + +typedef struct { + mp_obj_base_t base; + qstr name; + // These could be squeezed to fewer bits if more fields are needed. + uint8_t number; // port << 5 | pin number in port (0-31): 6 bits needed + uint8_t adc_channel; // 0 is no ADC, ADC channel from 1 to 8: + // 4 bits needed here; 5 bits used in periph registers +} mcu_pin_obj_t; + +extern const mp_obj_type_t mcu_pin_type; + +// Used in device-specific pins.c +#define PIN(p_name, p_port, p_pin, p_adc_channel) \ +{ \ + { &mcu_pin_type }, \ + .name = MP_QSTR_ ## p_name, \ + .number = NRF_GPIO_PIN_MAP(p_port, p_pin), \ + .adc_channel = (p_adc_channel), \ +} + +// Choose based on chip, but not specifically revision (e.g., not NRF52832_XXAA) +#ifdef NRF52832 +#include "nrf52832/pins.h" +#endif + +#ifdef NRF52840 +#include "nrf52840/pins.h" +#endif + +//**************extern const mp_obj_type_t mcu_pin_type; + +#endif // __MICROPY_INCLUDED_NRF_PERIPHERALS_PINS_H__ diff --git a/ports/nrf/supervisor/serial.c b/ports/nrf/supervisor/serial.c index a822dc9936ff2..da7fe07fd3230 100644 --- a/ports/nrf/supervisor/serial.c +++ b/ports/nrf/supervisor/serial.c @@ -30,7 +30,6 @@ #include "ble_uart.h" #else #include "nrf_gpio.h" -#include "nrf_pin.h" #endif #if !defined( NRF52840_XXAA) || ( defined(CFG_HWUART_FOR_SERIAL) && CFG_HWUART_FOR_SERIAL == 1 ) From 9ea809bef73e6862103cd71802803122e97bf80b Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Fri, 31 Aug 2018 17:46:03 -0400 Subject: [PATCH 3/6] add pin claiming to devices --- main.c | 2 +- .../boards/circuitplayground_express/board.c | 4 +-- .../circuitplayground_express_crickit/board.c | 4 +-- .../atmel-samd/common-hal/analogio/AnalogIn.c | 2 +- .../common-hal/analogio/AnalogOut.c | 2 +- .../atmel-samd/common-hal/audiobusio/I2SOut.c | 6 ++-- .../atmel-samd/common-hal/audiobusio/PDMIn.c | 4 +-- .../atmel-samd/common-hal/audioio/AudioOut.c | 4 +-- ports/atmel-samd/common-hal/busio/I2C.c | 16 +++++----- ports/atmel-samd/common-hal/busio/I2C.h | 2 +- ports/atmel-samd/common-hal/busio/SPI.c | 6 ++-- ports/atmel-samd/common-hal/busio/UART.c | 4 +-- .../common-hal/digitalio/DigitalInOut.c | 6 ++-- .../atmel-samd/common-hal/i2cslave/I2CSlave.c | 4 +-- .../common-hal/microcontroller/Pin.c | 30 +++++++++---------- .../common-hal/microcontroller/Pin.h | 4 +-- ports/atmel-samd/common-hal/pulseio/PWMOut.c | 2 +- ports/atmel-samd/common-hal/pulseio/PulseIn.c | 4 ++- .../common-hal/rotaryio/IncrementalEncoder.c | 7 +++-- ports/atmel-samd/common-hal/touchio/TouchIn.c | 2 +- ports/atmel-samd/peripherals | 2 +- ports/nrf/boards/feather_nrf52832/board.c | 4 +-- ports/nrf/common-hal/analogio/AnalogIn.c | 2 ++ ports/nrf/common-hal/analogio/AnalogOut.c | 2 -- ports/nrf/common-hal/busio/I2C.c | 17 ++++++++--- ports/nrf/common-hal/busio/I2C.h | 3 +- ports/nrf/common-hal/busio/SPI.c | 28 ++++++++++++----- ports/nrf/common-hal/busio/SPI.h | 4 ++- ports/nrf/common-hal/digitalio/DigitalInOut.c | 20 +++++++++---- ports/nrf/common-hal/digitalio/DigitalInOut.h | 1 + ports/nrf/common-hal/microcontroller/Pin.c | 23 +++++++------- ports/nrf/common-hal/microcontroller/Pin.h | 4 +-- ports/nrf/peripherals/nrf/nrf52832/pins.h | 2 -- ports/nrf/peripherals/nrf/nrf52840/pins.h | 2 -- ports/nrf/peripherals/nrf/pins.h | 3 ++ supervisor/shared/rgb_led_status.c | 8 ++--- 36 files changed, 140 insertions(+), 100 deletions(-) diff --git a/main.c b/main.c index 61d10bc0865fd..1cb73e58ab375 100755 --- a/main.c +++ b/main.c @@ -451,7 +451,7 @@ void NORETURN __fatal_error(const char *msg) { #ifndef NDEBUG void MP_WEAK __assert_func(const char *file, int line, const char *func, const char *expr) { - printf("Assertion '%s' failed, at file %s:%d\n", expr, file, line); + mp_printf(&mp_plat_print, "Assertion '%s' failed, at file %s:%d\n", expr, file, line); __fatal_error("Assertion failed"); } #endif diff --git a/ports/atmel-samd/boards/circuitplayground_express/board.c b/ports/atmel-samd/boards/circuitplayground_express/board.c index 5c5e9f7faf49e..578963642dda9 100644 --- a/ports/atmel-samd/boards/circuitplayground_express/board.c +++ b/ports/atmel-samd/boards/circuitplayground_express/board.c @@ -48,8 +48,8 @@ bool board_requests_safe_mode(void) { gpio_set_pin_pull_mode(PIN_PA28, GPIO_PULL_DOWN); bool safe_mode = gpio_get_pin_level(PIN_PA14) && gpio_get_pin_level(PIN_PA28); - reset_pin(PIN_PA14); - reset_pin(PIN_PA28); + reset_pin_number(PIN_PA14); + reset_pin_number(PIN_PA28); return safe_mode; } diff --git a/ports/atmel-samd/boards/circuitplayground_express_crickit/board.c b/ports/atmel-samd/boards/circuitplayground_express_crickit/board.c index 5c5e9f7faf49e..578963642dda9 100644 --- a/ports/atmel-samd/boards/circuitplayground_express_crickit/board.c +++ b/ports/atmel-samd/boards/circuitplayground_express_crickit/board.c @@ -48,8 +48,8 @@ bool board_requests_safe_mode(void) { gpio_set_pin_pull_mode(PIN_PA28, GPIO_PULL_DOWN); bool safe_mode = gpio_get_pin_level(PIN_PA14) && gpio_get_pin_level(PIN_PA28); - reset_pin(PIN_PA14); - reset_pin(PIN_PA28); + reset_pin_number(PIN_PA14); + reset_pin_number(PIN_PA28); return safe_mode; } diff --git a/ports/atmel-samd/common-hal/analogio/AnalogIn.c b/ports/atmel-samd/common-hal/analogio/AnalogIn.c index 65ff383628a54..fc11d5d19fe7d 100644 --- a/ports/atmel-samd/common-hal/analogio/AnalogIn.c +++ b/ports/atmel-samd/common-hal/analogio/AnalogIn.c @@ -80,7 +80,7 @@ void common_hal_analogio_analogin_deinit(analogio_analogin_obj_t *self) { if (common_hal_analogio_analogin_deinited(self)) { return; } - reset_pin(self->pin->number); + reset_pin_number(self->pin->number); self->pin = mp_const_none; } diff --git a/ports/atmel-samd/common-hal/analogio/AnalogOut.c b/ports/atmel-samd/common-hal/analogio/AnalogOut.c index 9be8c39360b18..2e42abdd45cf0 100644 --- a/ports/atmel-samd/common-hal/analogio/AnalogOut.c +++ b/ports/atmel-samd/common-hal/analogio/AnalogOut.c @@ -113,7 +113,7 @@ void common_hal_analogio_analogout_deinit(analogio_analogout_obj_t *self) { return; } dac_sync_disable_channel(&self->descriptor, self->channel); - reset_pin(PIN_PA02); + reset_pin_number(PIN_PA02); // Only deinit the DAC on the SAMD51 if both outputs are free. #ifdef SAMD51 if (common_hal_mcu_pin_is_free(&pin_PA02) && common_hal_mcu_pin_is_free(&pin_PA05)) { diff --git a/ports/atmel-samd/common-hal/audiobusio/I2SOut.c b/ports/atmel-samd/common-hal/audiobusio/I2SOut.c index ab3091c3a3f21..af84bb8075d75 100644 --- a/ports/atmel-samd/common-hal/audiobusio/I2SOut.c +++ b/ports/atmel-samd/common-hal/audiobusio/I2SOut.c @@ -212,11 +212,11 @@ void common_hal_audiobusio_i2sout_deinit(audiobusio_i2sout_obj_t* self) { return; } - reset_pin(self->bit_clock->number); + reset_pin_number(self->bit_clock->number); self->bit_clock = mp_const_none; - reset_pin(self->word_select->number); + reset_pin_number(self->word_select->number); self->word_select = mp_const_none; - reset_pin(self->data->number); + reset_pin_number(self->data->number); self->data = mp_const_none; } diff --git a/ports/atmel-samd/common-hal/audiobusio/PDMIn.c b/ports/atmel-samd/common-hal/audiobusio/PDMIn.c index 0adc3fb52b437..e38402ed96201 100644 --- a/ports/atmel-samd/common-hal/audiobusio/PDMIn.c +++ b/ports/atmel-samd/common-hal/audiobusio/PDMIn.c @@ -235,8 +235,8 @@ void common_hal_audiobusio_pdmin_deinit(audiobusio_pdmin_obj_t* self) { disconnect_gclk_from_peripheral(self->gclk, I2S_GCLK_ID_0 + self->clock_unit); disable_clock_generator(self->gclk); - reset_pin(self->clock_pin->number); - reset_pin(self->data_pin->number); + reset_pin_number(self->clock_pin->number); + reset_pin_number(self->data_pin->number); self->clock_pin = mp_const_none; self->data_pin = mp_const_none; } diff --git a/ports/atmel-samd/common-hal/audioio/AudioOut.c b/ports/atmel-samd/common-hal/audioio/AudioOut.c index 7df328a6a81aa..269acabf98f8c 100644 --- a/ports/atmel-samd/common-hal/audioio/AudioOut.c +++ b/ports/atmel-samd/common-hal/audioio/AudioOut.c @@ -248,10 +248,10 @@ void common_hal_audioio_audioout_deinit(audioio_audioout_obj_t* self) { tc_set_enable(tc_insts[self->tc_index], false); - reset_pin(self->left_channel->number); + reset_pin_number(self->left_channel->number); self->left_channel = mp_const_none; #ifdef SAMD51 - reset_pin(self->right_channel->number); + reset_pin_number(self->right_channel->number); self->right_channel = mp_const_none; #endif } diff --git a/ports/atmel-samd/common-hal/busio/I2C.c b/ports/atmel-samd/common-hal/busio/I2C.c index c0643865d63c7..dac15bcc1b5c0 100644 --- a/ports/atmel-samd/common-hal/busio/I2C.c +++ b/ports/atmel-samd/common-hal/busio/I2C.c @@ -96,8 +96,8 @@ void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, common_hal_mcu_delay_us(3); if (!gpio_get_pin_level(sda->number) || !gpio_get_pin_level(scl->number)) { - reset_pin(sda->number); - reset_pin(scl->number); + reset_pin_number(sda->number); + reset_pin_number(scl->number); mp_raise_RuntimeError(translate("SDA or SCL needs a pull up")); } gpio_set_pin_function(sda->number, sda_pinmux); @@ -107,8 +107,8 @@ void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, samd_peripherals_sercom_clock_init(sercom, sercom_index); if (i2c_m_sync_init(&self->i2c_desc, sercom) != ERR_NONE) { - reset_pin(sda->number); - reset_pin(scl->number); + reset_pin_number(sda->number); + reset_pin_number(scl->number); mp_raise_OSError(MP_EIO); } @@ -116,8 +116,8 @@ void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, // Frequency must be set before the I2C device is enabled. if (i2c_m_sync_set_baudrate(&self->i2c_desc, 0, frequency / 1000) != ERR_NONE) { - reset_pin(sda->number); - reset_pin(scl->number); + reset_pin_number(sda->number); + reset_pin_number(scl->number); mp_raise_ValueError(translate("Unsupported baudrate")); } @@ -144,8 +144,8 @@ void common_hal_busio_i2c_deinit(busio_i2c_obj_t *self) { i2c_m_sync_disable(&self->i2c_desc); i2c_m_sync_deinit(&self->i2c_desc); - reset_pin(self->sda_pin); - reset_pin(self->scl_pin); + reset_pin_number(self->sda_pin); + reset_pin_number(self->scl_pin); self->sda_pin = NO_PIN; self->scl_pin = NO_PIN; } diff --git a/ports/atmel-samd/common-hal/busio/I2C.h b/ports/atmel-samd/common-hal/busio/I2C.h index 366c6c469da59..6bec6e8047ad4 100644 --- a/ports/atmel-samd/common-hal/busio/I2C.h +++ b/ports/atmel-samd/common-hal/busio/I2C.h @@ -36,7 +36,7 @@ typedef struct { mp_obj_base_t base; struct i2c_m_sync_desc i2c_desc; - volatile bool has_lock; + bool has_lock; uint8_t scl_pin; uint8_t sda_pin; } busio_i2c_obj_t; diff --git a/ports/atmel-samd/common-hal/busio/SPI.c b/ports/atmel-samd/common-hal/busio/SPI.c index fd7f81cc2fec9..a292f9e3d332f 100644 --- a/ports/atmel-samd/common-hal/busio/SPI.c +++ b/ports/atmel-samd/common-hal/busio/SPI.c @@ -196,9 +196,9 @@ void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { } spi_m_sync_disable(&self->spi_desc); spi_m_sync_deinit(&self->spi_desc); - reset_pin(self->clock_pin); - reset_pin(self->MOSI_pin); - reset_pin(self->MISO_pin); + reset_pin_number(self->clock_pin); + reset_pin_number(self->MOSI_pin); + reset_pin_number(self->MISO_pin); self->clock_pin = NO_PIN; } diff --git a/ports/atmel-samd/common-hal/busio/UART.c b/ports/atmel-samd/common-hal/busio/UART.c index 1be245b4b6f53..a3736e54cbe1e 100644 --- a/ports/atmel-samd/common-hal/busio/UART.c +++ b/ports/atmel-samd/common-hal/busio/UART.c @@ -222,8 +222,8 @@ void common_hal_busio_uart_deinit(busio_uart_obj_t *self) { struct usart_async_descriptor * const usart_desc_p = (struct usart_async_descriptor * const) &self->usart_desc; usart_async_disable(usart_desc_p); usart_async_deinit(usart_desc_p); - reset_pin(self->rx_pin); - reset_pin(self->tx_pin); + reset_pin_number(self->rx_pin); + reset_pin_number(self->tx_pin); self->rx_pin = NO_PIN; self->tx_pin = NO_PIN; } diff --git a/ports/atmel-samd/common-hal/digitalio/DigitalInOut.c b/ports/atmel-samd/common-hal/digitalio/DigitalInOut.c index 7a48ef195e3db..9537d6179e99d 100644 --- a/ports/atmel-samd/common-hal/digitalio/DigitalInOut.c +++ b/ports/atmel-samd/common-hal/digitalio/DigitalInOut.c @@ -40,6 +40,8 @@ digitalinout_result_t common_hal_digitalio_digitalinout_construct( digitalio_digitalinout_obj_t* self, const mcu_pin_obj_t* pin) { claim_pin(pin); self->pin = pin; + self->output = false; + self->open_drain = false; // Must set pull after setting direction. gpio_set_pin_direction(pin->number, GPIO_DIRECTION_IN); @@ -55,7 +57,7 @@ void common_hal_digitalio_digitalinout_deinit(digitalio_digitalinout_obj_t* self if (common_hal_digitalio_digitalinout_deinited(self)) { return; } - reset_pin(self->pin->number); + reset_pin_number(self->pin->number); self->pin = mp_const_none; } @@ -83,7 +85,7 @@ void common_hal_digitalio_digitalinout_switch_to_output( digitalio_direction_t common_hal_digitalio_digitalinout_get_direction( digitalio_digitalinout_obj_t* self) { - return self->output? DIRECTION_OUTPUT : DIRECTION_INPUT; + return self->output ? DIRECTION_OUTPUT : DIRECTION_INPUT; } void common_hal_digitalio_digitalinout_set_value( diff --git a/ports/atmel-samd/common-hal/i2cslave/I2CSlave.c b/ports/atmel-samd/common-hal/i2cslave/I2CSlave.c index f0bbed3d716ae..79c1449e2f6d8 100644 --- a/ports/atmel-samd/common-hal/i2cslave/I2CSlave.c +++ b/ports/atmel-samd/common-hal/i2cslave/I2CSlave.c @@ -105,8 +105,8 @@ void common_hal_i2cslave_i2c_slave_deinit(i2cslave_i2c_slave_obj_t *self) { self->sercom->I2CS.CTRLA.bit.ENABLE = 0; - reset_pin(self->sda_pin); - reset_pin(self->scl_pin); + reset_pin_number(self->sda_pin); + reset_pin_number(self->scl_pin); self->sda_pin = NO_PIN; self->scl_pin = NO_PIN; } diff --git a/ports/atmel-samd/common-hal/microcontroller/Pin.c b/ports/atmel-samd/common-hal/microcontroller/Pin.c index fd063a04cc3cd..0f179a6c1a511 100644 --- a/ports/atmel-samd/common-hal/microcontroller/Pin.c +++ b/ports/atmel-samd/common-hal/microcontroller/Pin.c @@ -91,23 +91,23 @@ void reset_all_pins(void) { #endif } -void reset_pin(uint8_t pin) { - if (pin >= PORT_BITS) { +void reset_pin_number(uint8_t pin_number) { + if (pin_number >= PORT_BITS) { return; } #ifdef MICROPY_HW_NEOPIXEL - if (pin == MICROPY_HW_NEOPIXEL->number) { + if (pin_number == MICROPY_HW_NEOPIXEL->number) { neopixel_in_use = false; rgb_led_status_init(); return; } #endif #ifdef MICROPY_HW_APA102_MOSI - if (pin == MICROPY_HW_APA102_MOSI->number || - pin == MICROPY_HW_APA102_SCK->number) { - apa102_mosi_in_use = apa102_mosi_in_use && pin != MICROPY_HW_APA102_MOSI->number; - apa102_sck_in_use = apa102_sck_in_use && pin != MICROPY_HW_APA102_SCK->number; + if (pin_number == MICROPY_HW_APA102_MOSI->number || + pin_number == MICROPY_HW_APA102_SCK->number) { + apa102_mosi_in_use = apa102_mosi_in_use && pin_number != MICROPY_HW_APA102_MOSI->number; + apa102_sck_in_use = apa102_sck_in_use && pin_number != MICROPY_HW_APA102_SCK->number; if (!apa102_sck_in_use && !apa102_mosi_in_use) { rgb_led_status_init(); } @@ -115,24 +115,24 @@ void reset_pin(uint8_t pin) { } #endif - if (pin == PIN_PA30 + if (pin_number == PIN_PA30 #ifdef SAMD51 ) { - gpio_set_pin_function(pin, GPIO_PIN_FUNCTION_H); + gpio_set_pin_function(pin_number, GPIO_PIN_FUNCTION_H); #endif #ifdef SAMD21 - || pin == PIN_PA31) { - gpio_set_pin_function(pin, GPIO_PIN_FUNCTION_G); + || pin_number == PIN_PA31) { + gpio_set_pin_function(pin_number, GPIO_PIN_FUNCTION_G); #endif } else { - gpio_set_pin_direction(pin, GPIO_DIRECTION_OFF); - gpio_set_pin_function(pin, GPIO_PIN_FUNCTION_OFF); + gpio_set_pin_direction(pin_number, GPIO_DIRECTION_OFF); + gpio_set_pin_function(pin_number, GPIO_PIN_FUNCTION_OFF); } #ifdef SPEAKER_ENABLE_PIN - if (pin == SPEAKER_ENABLE_PIN->number) { + if (pin_number == SPEAKER_ENABLE_PIN->number) { speaker_enable_in_use = false; - gpio_set_pin_function(pin, GPIO_PIN_FUNCTION_OFF); + gpio_set_pin_function(pin_number, GPIO_PIN_FUNCTION_OFF); gpio_set_pin_direction(SPEAKER_ENABLE_PIN->number, GPIO_DIRECTION_OUT); gpio_set_pin_level(SPEAKER_ENABLE_PIN->number, false); } diff --git a/ports/atmel-samd/common-hal/microcontroller/Pin.h b/ports/atmel-samd/common-hal/microcontroller/Pin.h index 18e2d123723d2..dcd80997e25bb 100644 --- a/ports/atmel-samd/common-hal/microcontroller/Pin.h +++ b/ports/atmel-samd/common-hal/microcontroller/Pin.h @@ -40,9 +40,9 @@ extern bool apa102_mosi_in_use; #endif void reset_all_pins(void); -// reset_pin takes the pin number instead of the pointer so that objects don't +// reset_pin_number takes the pin number instead of the pointer so that objects don't // need to store a full pointer. -void reset_pin(uint8_t pin); +void reset_pin_number(uint8_t pin_number); void claim_pin(const mcu_pin_obj_t* pin); #endif // MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_MICROCONTROLLER_PIN_H diff --git a/ports/atmel-samd/common-hal/pulseio/PWMOut.c b/ports/atmel-samd/common-hal/pulseio/PWMOut.c index 4e1b61d787e82..a115a0b7320af 100644 --- a/ports/atmel-samd/common-hal/pulseio/PWMOut.c +++ b/ports/atmel-samd/common-hal/pulseio/PWMOut.c @@ -285,7 +285,7 @@ void common_hal_pulseio_pwmout_deinit(pulseio_pwmout_obj_t* self) { } } } - reset_pin(self->pin->number); + reset_pin_number(self->pin->number); self->pin = mp_const_none; } diff --git a/ports/atmel-samd/common-hal/pulseio/PulseIn.c b/ports/atmel-samd/common-hal/pulseio/PulseIn.c index 3313073c5aade..aaa69a6f86567 100644 --- a/ports/atmel-samd/common-hal/pulseio/PulseIn.c +++ b/ports/atmel-samd/common-hal/pulseio/PulseIn.c @@ -139,6 +139,8 @@ void common_hal_pulseio_pulsein_construct(pulseio_pulsein_obj_t* self, turn_on_cpu_interrupt(self->channel); + claim_pin(pin); + // Set config will enable the EIC. pulsein_set_config(self, true); } @@ -152,7 +154,7 @@ void common_hal_pulseio_pulsein_deinit(pulseio_pulsein_obj_t* self) { return; } turn_off_eic_channel(self->channel); - reset_pin(self->pin); + reset_pin_number(self->pin); self->pin = NO_PIN; } diff --git a/ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c b/ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c index c1ceb410f7514..080cd61b5ee48 100644 --- a/ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c +++ b/ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c @@ -73,6 +73,9 @@ void common_hal_rotaryio_incrementalencoder_construct(rotaryio_incrementalencode ((uint8_t) gpio_get_pin_level(self->pin_a) << 1) | (uint8_t) gpio_get_pin_level(self->pin_b); + claim_pin(pin_a); + claim_pin(pin_b); + turn_on_eic_channel(self->eic_channel_a, EIC_CONFIG_SENSE0_BOTH_Val, EIC_HANDLER_INCREMENTAL_ENCODER); turn_on_eic_channel(self->eic_channel_b, EIC_CONFIG_SENSE0_BOTH_Val, EIC_HANDLER_INCREMENTAL_ENCODER); } @@ -87,9 +90,9 @@ void common_hal_rotaryio_incrementalencoder_deinit(rotaryio_incrementalencoder_o } turn_off_eic_channel(self->eic_channel_a); turn_off_eic_channel(self->eic_channel_b); - reset_pin(self->pin_a); + reset_pin_number(self->pin_a); self->pin_a = NO_PIN; - reset_pin(self->pin_b); + reset_pin_number(self->pin_b); self->pin_b = NO_PIN; } diff --git a/ports/atmel-samd/common-hal/touchio/TouchIn.c b/ports/atmel-samd/common-hal/touchio/TouchIn.c index 7fa61d3dd4360..9fb3a2ea1aa29 100644 --- a/ports/atmel-samd/common-hal/touchio/TouchIn.c +++ b/ports/atmel-samd/common-hal/touchio/TouchIn.c @@ -110,7 +110,7 @@ void common_hal_touchio_touchin_deinit(touchio_touchin_obj_t* self) { } // We leave the clocks running because they may be in use by others. - reset_pin(self->config.pin); + reset_pin_number(self->config.pin); self->config.pin = NO_PIN; } diff --git a/ports/atmel-samd/peripherals b/ports/atmel-samd/peripherals index 156279784cb3d..b099a172dfb63 160000 --- a/ports/atmel-samd/peripherals +++ b/ports/atmel-samd/peripherals @@ -1 +1 @@ -Subproject commit 156279784cb3d22f7f8a8d93b4bb55e2d912a5f8 +Subproject commit b099a172dfb6345a8dac30633df4f6267489c38e diff --git a/ports/nrf/boards/feather_nrf52832/board.c b/ports/nrf/boards/feather_nrf52832/board.c index e0b77437b9a80..dde63b553272d 100644 --- a/ports/nrf/boards/feather_nrf52832/board.c +++ b/ports/nrf/boards/feather_nrf52832/board.c @@ -52,8 +52,8 @@ bool board_requests_safe_mode(void) { // gpio_set_pin_pull_mode(PIN_PA28, GPIO_PULL_DOWN); // bool safe_mode = gpio_get_pin_level(PIN_PA14) && // gpio_get_pin_level(PIN_PA28); -// reset_pin(PIN_PA14); -// reset_pin(PIN_PA28); +// reset_pin_number(PIN_PA14); +// reset_pin_number(PIN_PA28); // return safe_mode; return false; diff --git a/ports/nrf/common-hal/analogio/AnalogIn.c b/ports/nrf/common-hal/analogio/AnalogIn.c index 1ebd5ea1aa760..1e572f7cb9f1a 100644 --- a/ports/nrf/common-hal/analogio/AnalogIn.c +++ b/ports/nrf/common-hal/analogio/AnalogIn.c @@ -40,6 +40,7 @@ void common_hal_analogio_analogin_construct(analogio_analogin_obj_t *self, const nrf_gpio_cfg_default(pin->number); + claim_pin(pin); self->pin = pin; } @@ -53,6 +54,7 @@ void common_hal_analogio_analogin_deinit(analogio_analogin_obj_t *self) { nrf_gpio_cfg_default(self->pin->number); + reset_pin_number(self->pin->number); self->pin = mp_const_none; } diff --git a/ports/nrf/common-hal/analogio/AnalogOut.c b/ports/nrf/common-hal/analogio/AnalogOut.c index 654639b590891..dc0f53740d951 100644 --- a/ports/nrf/common-hal/analogio/AnalogOut.c +++ b/ports/nrf/common-hal/analogio/AnalogOut.c @@ -42,9 +42,7 @@ bool common_hal_analogio_analogout_deinited(analogio_analogout_obj_t *self) { } void common_hal_analogio_analogout_deinit(analogio_analogout_obj_t *self) { - } void common_hal_analogio_analogout_set_value(analogio_analogout_obj_t *self, uint16_t value) { - } diff --git a/ports/nrf/common-hal/busio/I2C.c b/ports/nrf/common-hal/busio/I2C.c index 9390b1fd853fe..8ac76c304aee9 100644 --- a/ports/nrf/common-hal/busio/I2C.c +++ b/ports/nrf/common-hal/busio/I2C.c @@ -71,6 +71,11 @@ void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, const mcu_pin_obj_t * config.frequency = NRF_TWIM_FREQ_250K; } + self->scl_pin_number = scl->number; + self->sda_pin_number = sda->number; + claim_pin(sda); + claim_pin(scl); + nrfx_err_t err = nrfx_twim_init(&self->twim, &config, NULL, NULL); // A soft reset doesn't uninit the driver so we might end up with a invalid state @@ -79,14 +84,15 @@ void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, const mcu_pin_obj_t * err = nrfx_twim_init(&self->twim, &config, NULL, NULL); } - if (err != NRFX_SUCCESS) + if (err != NRFX_SUCCESS) { + common_hal_busio_i2c_deinit(self); mp_raise_OSError(MP_EIO); + } - self->inited = true; } bool common_hal_busio_i2c_deinited(busio_i2c_obj_t *self) { - return !self->inited; + return self->sda_pin_number == NO_PIN; } void common_hal_busio_i2c_deinit(busio_i2c_obj_t *self) { @@ -95,7 +101,10 @@ void common_hal_busio_i2c_deinit(busio_i2c_obj_t *self) { nrfx_twim_uninit(&self->twim); - self->inited = false; + reset_pin_number(self->sda_pin_number); + reset_pin_number(self->scl_pin_number); + self->sda_pin_number = NO_PIN; + self->scl_pin_number = NO_PIN; } // nrfx_twim_tx doesn't support 0-length data so we fall back to the hal API diff --git a/ports/nrf/common-hal/busio/I2C.h b/ports/nrf/common-hal/busio/I2C.h index 331e73062b0d9..a133ff071a9d8 100644 --- a/ports/nrf/common-hal/busio/I2C.h +++ b/ports/nrf/common-hal/busio/I2C.h @@ -34,8 +34,9 @@ typedef struct { mp_obj_base_t base; nrfx_twim_t twim; - bool inited; bool has_lock; + uint8_t scl_pin_number; + uint8_t sda_pin_number; } busio_i2c_obj_t; #endif // MICROPY_INCLUDED_NRF_COMMON_HAL_BUSIO_I2C_H diff --git a/ports/nrf/common-hal/busio/SPI.c b/ports/nrf/common-hal/busio/SPI.c index d4cf1b7ae9c7e..e2d6a0daa10ad 100644 --- a/ports/nrf/common-hal/busio/SPI.c +++ b/ports/nrf/common-hal/busio/SPI.c @@ -78,12 +78,24 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, const mcu_pin_obj_t * config.frequency = NRF_SPIM_FREQ_8M; config.sck_pin = clock->number; + self->clock_pin_number = clock->number; + claim_pin(clock); - if (mosi != (mcu_pin_obj_t*)&mp_const_none_obj) + if (mosi != (mcu_pin_obj_t*)&mp_const_none_obj) { config.mosi_pin = mosi->number; + self->MOSI_pin_number = mosi->number; + claim_pin(mosi); + } else { + self->MOSI_pin_number = NO_PIN; + } - if (miso != (mcu_pin_obj_t*)&mp_const_none_obj) + if (miso != (mcu_pin_obj_t*)&mp_const_none_obj) { config.miso_pin = miso->number; + self->MISO_pin_number = mosi->number; + claim_pin(miso); + } else { + self->MISO_pin_number = NO_PIN; + } nrfx_err_t err = nrfx_spim_init(&self->spim, &config, NULL, NULL); @@ -93,14 +105,14 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, const mcu_pin_obj_t * err = nrfx_spim_init(&self->spim, &config, NULL, NULL); } - if (err != NRFX_SUCCESS) + if (err != NRFX_SUCCESS) { + common_hal_busio_spi_deinit(self); mp_raise_OSError(MP_EIO); - - self->inited = true; + } } bool common_hal_busio_spi_deinited(busio_spi_obj_t *self) { - return !self->inited; + return self->clock_pin_number == NO_PIN; } void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { @@ -109,7 +121,9 @@ void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { nrfx_spim_uninit(&self->spim); - self->inited = false; + reset_pin_number(self->clock_pin_number); + reset_pin_number(self->MOSI_pin_number); + reset_pin_number(self->MISO_pin_number); } bool common_hal_busio_spi_configure(busio_spi_obj_t *self, uint32_t baudrate, uint8_t polarity, uint8_t phase, uint8_t bits) { diff --git a/ports/nrf/common-hal/busio/SPI.h b/ports/nrf/common-hal/busio/SPI.h index c3999ae9446c3..8b637b4a5e061 100644 --- a/ports/nrf/common-hal/busio/SPI.h +++ b/ports/nrf/common-hal/busio/SPI.h @@ -33,8 +33,10 @@ typedef struct { mp_obj_base_t base; nrfx_spim_t spim; - bool inited; bool has_lock; + uint8_t clock_pin_number; + uint8_t MOSI_pin_number; + uint8_t MISO_pin_number; } busio_spi_obj_t; #endif // MICROPY_INCLUDED_NRF_COMMON_HAL_BUSIO_SPI_H diff --git a/ports/nrf/common-hal/digitalio/DigitalInOut.c b/ports/nrf/common-hal/digitalio/DigitalInOut.c index c8ec12c0321b9..b7a1a5001be2c 100644 --- a/ports/nrf/common-hal/digitalio/DigitalInOut.c +++ b/ports/nrf/common-hal/digitalio/DigitalInOut.c @@ -32,7 +32,10 @@ digitalinout_result_t common_hal_digitalio_digitalinout_construct( digitalio_digitalinout_obj_t *self, const mcu_pin_obj_t *pin) { + claim_pin(pin); self->pin = pin; + self->output = false; + self->open_drain = false; nrf_gpio_cfg_input(pin->number, NRF_GPIO_PIN_NOPULL); @@ -49,11 +52,13 @@ void common_hal_digitalio_digitalinout_deinit(digitalio_digitalinout_obj_t *self } nrf_gpio_cfg_default(self->pin->number); + reset_pin_number(self->pin->number); self->pin = mp_const_none; } void common_hal_digitalio_digitalinout_switch_to_input( digitalio_digitalinout_obj_t *self, digitalio_pull_t pull) { + self->output = false; nrf_gpio_cfg_input(self->pin->number, NRF_GPIO_PIN_NOPULL); common_hal_digitalio_digitalinout_set_pull(self, pull); } @@ -61,6 +66,7 @@ void common_hal_digitalio_digitalinout_switch_to_input( void common_hal_digitalio_digitalinout_switch_to_output( digitalio_digitalinout_obj_t *self, bool value, digitalio_drive_mode_t drive_mode) { + self->output = true; self->open_drain = (drive_mode == DRIVE_MODE_OPEN_DRAIN); nrf_gpio_cfg_input(self->pin->number, NRF_GPIO_PIN_NOPULL); @@ -70,8 +76,7 @@ void common_hal_digitalio_digitalinout_switch_to_output( digitalio_direction_t common_hal_digitalio_digitalinout_get_direction( digitalio_digitalinout_obj_t *self) { - return (nrf_gpio_pin_dir_get(self->pin->number) == NRF_GPIO_PIN_DIR_OUTPUT) - ? DIRECTION_OUTPUT : DIRECTION_INPUT; + return self->output ? DIRECTION_OUTPUT : DIRECTION_INPUT; } void common_hal_digitalio_digitalinout_set_value( @@ -87,8 +92,9 @@ void common_hal_digitalio_digitalinout_set_value( bool common_hal_digitalio_digitalinout_get_value( digitalio_digitalinout_obj_t *self) { if (nrf_gpio_pin_dir_get(self->pin->number) == NRF_GPIO_PIN_DIR_INPUT) { - if (self->open_drain) + if (self->open_drain) { return true; + } return nrf_gpio_pin_read(self->pin->number); } @@ -104,14 +110,16 @@ void common_hal_digitalio_digitalinout_set_drive_mode( // True is implemented differently between modes so reset the value to make // sure its correct for the new mode. - if (value) + if (value) { common_hal_digitalio_digitalinout_set_value(self, value); + } } digitalio_drive_mode_t common_hal_digitalio_digitalinout_get_drive_mode( digitalio_digitalinout_obj_t *self) { - if (self->open_drain) + if (self->open_drain) { return DRIVE_MODE_OPEN_DRAIN; + } return DRIVE_MODE_PUSH_PULL; } @@ -141,7 +149,7 @@ digitalio_pull_t common_hal_digitalio_digitalinout_get_pull( // Changes pin to be a relative pin number in port. NRF_GPIO_Type *reg = nrf_gpio_pin_port_decode(&pin); - if (nrf_gpio_pin_dir_get(pin) == NRF_GPIO_PIN_DIR_OUTPUT) { + if (nrf_gpio_pin_dir_get(self->pin->number) == NRF_GPIO_PIN_DIR_OUTPUT) { mp_raise_AttributeError(translate("Cannot get pull while in output mode")); return PULL_NONE; } diff --git a/ports/nrf/common-hal/digitalio/DigitalInOut.h b/ports/nrf/common-hal/digitalio/DigitalInOut.h index ee59eb498018c..afe8a8b42f12e 100644 --- a/ports/nrf/common-hal/digitalio/DigitalInOut.h +++ b/ports/nrf/common-hal/digitalio/DigitalInOut.h @@ -32,6 +32,7 @@ typedef struct { mp_obj_base_t base; const mcu_pin_obj_t *pin; + bool output; bool open_drain; } digitalio_digitalinout_obj_t; diff --git a/ports/nrf/common-hal/microcontroller/Pin.c b/ports/nrf/common-hal/microcontroller/Pin.c index 4d2dea31e1f31..01142fa15a760 100644 --- a/ports/nrf/common-hal/microcontroller/Pin.c +++ b/ports/nrf/common-hal/microcontroller/Pin.c @@ -44,7 +44,7 @@ bool speaker_enable_in_use; #endif // Bit mask of claimed pins on each of up to two ports. nrf52832 has one port; nrf52840 has two. -STATIC bool claimed_pins[2]; +STATIC uint32_t claimed_pins[2]; void reset_all_pins(void) { claimed_pins[0] = 0; @@ -70,17 +70,16 @@ void reset_all_pins(void) { } // Mark pin as free and return it to a quiescent state. -void reset_pin(uint8_t pin) { - // Ignore out-of-bound pin numbers. NUMBER_OF_PINS is from nrf_gpio.h. - if (pin >= NUMBER_OF_PINS) { +void reset_pin_number(uint8_t pin_number) { + if (pin_number == NO_PIN) { return; } // Clear claimed bit. - claimed_pins[nrf_pin_port(pin)] &= ~(1 << nrf_relative_pin_number(pin)); + claimed_pins[nrf_pin_port(pin_number)] &= ~(1 << nrf_relative_pin_number(pin_number)); #ifdef MICROPY_HW_NEOPIXEL - if (pin == MICROPY_HW_NEOPIXEL->number) { + if (pin_number == MICROPY_HW_NEOPIXEL->number) { neopixel_in_use = false; rgb_led_status_init(); return; @@ -89,8 +88,8 @@ void reset_pin(uint8_t pin) { #ifdef MICROPY_HW_APA102_MOSI if (pin == MICROPY_HW_APA102_MOSI->number || pin == MICROPY_HW_APA102_SCK->number) { - apa102_mosi_in_use = apa102_mosi_in_use && pin != MICROPY_HW_APA102_MOSI->number; - apa102_sck_in_use = apa102_sck_in_use && pin != MICROPY_HW_APA102_SCK->number; + apa102_mosi_in_use = apa102_mosi_in_use && pin_number != MICROPY_HW_APA102_MOSI->number; + apa102_sck_in_use = apa102_sck_in_use && pin_number != MICROPY_HW_APA102_SCK->number; if (!apa102_sck_in_use && !apa102_mosi_in_use) { rgb_led_status_init(); } @@ -99,11 +98,11 @@ void reset_pin(uint8_t pin) { #endif #ifdef SPEAKER_ENABLE_PIN - if (pin == SPEAKER_ENABLE_PIN->number) { + if (pin_number == SPEAKER_ENABLE_PIN->number) { speaker_enable_in_use = false; common_hal_digitalio_digitalinout_switch_to_output( - nrf_gpio_pin_dir_set(pin, NRF_GPIO_PIN_DIR_OUTPUT); - nrf_gpio_pin_write(pin, false); + nrf_gpio_pin_dir_set(pin_number, NRF_GPIO_PIN_DIR_OUTPUT); + nrf_gpio_pin_write(pin_number, false); } #endif } @@ -154,5 +153,5 @@ bool common_hal_mcu_pin_is_free(const mcu_pin_obj_t *pin) { } #endif - return !(claimed_pins[nrf_pin_port(pin->number)] & (nrf_relative_pin_number(pin->number))); + return !(claimed_pins[nrf_pin_port(pin->number)] & (1 << nrf_relative_pin_number(pin->number))); } diff --git a/ports/nrf/common-hal/microcontroller/Pin.h b/ports/nrf/common-hal/microcontroller/Pin.h index 1e751c714e135..2cdf440b58df0 100644 --- a/ports/nrf/common-hal/microcontroller/Pin.h +++ b/ports/nrf/common-hal/microcontroller/Pin.h @@ -40,9 +40,9 @@ extern bool apa102_mosi_in_use; #endif void reset_all_pins(void); -// reset_pin takes the pin number instead of the pointer so that objects don't +// reset_pin_number takes the pin number instead of the pointer so that objects don't // need to store a full pointer. -void reset_pin(uint8_t pin); +void reset_pin_number(uint8_t pin); void claim_pin(const mcu_pin_obj_t* pin); // Lower 5 bits of a pin number are the pin number in a port. diff --git a/ports/nrf/peripherals/nrf/nrf52832/pins.h b/ports/nrf/peripherals/nrf/nrf52832/pins.h index 0bc039df00d3b..f8ef85ad09d8b 100644 --- a/ports/nrf/peripherals/nrf/nrf52832/pins.h +++ b/ports/nrf/peripherals/nrf/nrf52832/pins.h @@ -27,8 +27,6 @@ #ifndef MICROPY_INCLUDED_NRF_PERIPHERALS_NRF52832_PINS_H #define MICROPY_INCLUDED_NRF_PERIPHERALS_NRF52832_PINS_H -void reset_pin(uint8_t pin); - extern const mcu_pin_obj_t pin_P0_00; extern const mcu_pin_obj_t pin_P0_01; extern const mcu_pin_obj_t pin_P0_02; diff --git a/ports/nrf/peripherals/nrf/nrf52840/pins.h b/ports/nrf/peripherals/nrf/nrf52840/pins.h index 80f1d14af3345..3ad72ff6327af 100644 --- a/ports/nrf/peripherals/nrf/nrf52840/pins.h +++ b/ports/nrf/peripherals/nrf/nrf52840/pins.h @@ -27,8 +27,6 @@ #ifndef MICROPY_INCLUDED_NRF_PERIPHERALS_NRF52840_PINS_H #define MICROPY_INCLUDED_NRF_PERIPHERALS_NRF52840_PINS_H -void reset_pin(uint8_t pin); - extern const mcu_pin_obj_t pin_P0_00; extern const mcu_pin_obj_t pin_P0_01; extern const mcu_pin_obj_t pin_P0_02; diff --git a/ports/nrf/peripherals/nrf/pins.h b/ports/nrf/peripherals/nrf/pins.h index ca58f5fad09ac..1a87c0d88db35 100644 --- a/ports/nrf/peripherals/nrf/pins.h +++ b/ports/nrf/peripherals/nrf/pins.h @@ -55,6 +55,9 @@ extern const mp_obj_type_t mcu_pin_type; .adc_channel = (p_adc_channel), \ } +// Use illegal pin value to mark unassigned pins. +#define NO_PIN 0xff + // Choose based on chip, but not specifically revision (e.g., not NRF52832_XXAA) #ifdef NRF52832 #include "nrf52832/pins.h" diff --git a/supervisor/shared/rgb_led_status.c b/supervisor/shared/rgb_led_status.c index aea6567982227..186e33ab9b470 100644 --- a/supervisor/shared/rgb_led_status.c +++ b/supervisor/shared/rgb_led_status.c @@ -71,7 +71,7 @@ void rgb_led_status_init() { #else if (!common_hal_busio_spi_deinited(&status_apa102)) { // Don't use spi_deinit because that leads to infinite - // recursion because reset_pin may call + // recursion because reset_pin_number may call // rgb_led_status_init. spi_m_sync_disable(&status_apa102.spi_desc); } @@ -103,11 +103,11 @@ void rgb_led_status_init() { void reset_status_led() { #ifdef MICROPY_HW_NEOPIXEL - reset_pin(MICROPY_HW_NEOPIXEL->number); + reset_pin_number(MICROPY_HW_NEOPIXEL->number); #endif #if defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK) - reset_pin(MICROPY_HW_APA102_MOSI->number); - reset_pin(MICROPY_HW_APA102_SCK->number); + reset_pin_number(MICROPY_HW_APA102_MOSI->number); + reset_pin_number(MICROPY_HW_APA102_SCK->number); #endif } From 4382389e6f7b5f5f05ac1b8f87fd482fdfa12d16 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Sat, 1 Sep 2018 00:29:36 -0400 Subject: [PATCH 4/6] fix typos, remove incorrect pca10059 example; add default buses for pca10056; improve board names for pca boards --- conf.py | 2 +- ports/nrf/boards/feather_nrf52832/pins.c | 2 +- ports/nrf/boards/pca10040/mpconfigboard.h | 5 ++-- ports/nrf/boards/pca10056/mpconfigboard.h | 12 ++++++++- ports/nrf/boards/pca10059/examples/buttons.py | 26 ------------------- ports/nrf/boards/pca10059/mpconfigboard.h | 2 +- .../nrf/common-hal/microcontroller/__init__.c | 1 - ports/nrf/peripherals/nrf/pins.h | 2 -- 8 files changed, 17 insertions(+), 35 deletions(-) delete mode 100644 ports/nrf/boards/pca10059/examples/buttons.py diff --git a/conf.py b/conf.py index 8a7d49a437e30..0f363923f5ab1 100644 --- a/conf.py +++ b/conf.py @@ -115,9 +115,9 @@ "ports/minimal", "ports/nrf/device", "ports/nrf/drivers", - "ports/nrf/hal", "ports/nrf/modules", "ports/nrf/nrfx", + "ports/nrf/peripherals", "ports/nrf/usb", "ports/pic16bit", "ports/qemu-arm", diff --git a/ports/nrf/boards/feather_nrf52832/pins.c b/ports/nrf/boards/feather_nrf52832/pins.c index b14b944e8826a..f4d5023e1ee22 100644 --- a/ports/nrf/boards/feather_nrf52832/pins.c +++ b/ports/nrf/boards/feather_nrf52832/pins.c @@ -22,7 +22,7 @@ STATIC const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_NFC1), MP_ROM_PTR(&pin_P0_09) }, { MP_ROM_QSTR(MP_QSTR_NFC2), MP_ROM_PTR(&pin_P0_10) }, - { MP_ROM_QSTR(MP_QSTR_27), MP_ROM_PTR(&pin_P0_27) }, + { MP_ROM_QSTR(MP_QSTR_D27), MP_ROM_PTR(&pin_P0_27) }, { MP_ROM_QSTR(MP_QSTR_D30), MP_ROM_PTR(&pin_P0_30) }, { MP_ROM_QSTR(MP_QSTR_A6), MP_ROM_PTR(&pin_P0_30) }, diff --git a/ports/nrf/boards/pca10040/mpconfigboard.h b/ports/nrf/boards/pca10040/mpconfigboard.h index 40035e2cac0ea..ebf808ce200c6 100644 --- a/ports/nrf/boards/pca10040/mpconfigboard.h +++ b/ports/nrf/boards/pca10040/mpconfigboard.h @@ -4,6 +4,7 @@ * The MIT License (MIT) * * Copyright (c) 2016 Glenn Ruben Bakke + * Copyright (c) 2018 Dan Halbert for Adafruit Industries * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -28,8 +29,8 @@ #define MICROPY_HW_MCU_NAME "nRF52832" #define MICROPY_PY_SYS_PLATFORM "nRF52-DK" -#define MICROPY_HW_UART_RX NRF_GPIO_PIN_MAP(0, 11) -#define MICROPY_HW_UART_TX NRF_GPIO_PIN_MAP(0, 12) +#define MICROPY_HW_UART_RX NRF_GPIO_PIN_MAP(0, 8) +#define MICROPY_HW_UART_TX NRF_GPIO_PIN_MAP(0, 6) #define MICROPY_HW_UART_HWFC (0) #define PORT_HEAP_SIZE (32 * 1024) diff --git a/ports/nrf/boards/pca10056/mpconfigboard.h b/ports/nrf/boards/pca10056/mpconfigboard.h index dbd4226631c04..de4545d6201eb 100644 --- a/ports/nrf/boards/pca10056/mpconfigboard.h +++ b/ports/nrf/boards/pca10056/mpconfigboard.h @@ -24,7 +24,7 @@ * THE SOFTWARE. */ -#define MICROPY_HW_BOARD_NAME "PCA10056" +#define MICROPY_HW_BOARD_NAME "PCA10056 nRF52840-DK" #define MICROPY_HW_MCU_NAME "nRF52840" #define MICROPY_PY_SYS_PLATFORM "nRF52840-DK" @@ -38,3 +38,13 @@ // Temp (could be removed) 0: usb cdc (default), 1 : hwuart (jlink) #define CFG_HWUART_FOR_SERIAL 0 + +#define DEFAULT_I2C_BUS_SCL (&pin_P0_27) +#define DEFAULT_I2C_BUS_SDA (&pin_P0_26) + +#define DEFAULT_SPI_BUS_SCK (&pin_P1_15) +#define DEFAULT_SPI_BUS_MOSI (&pin_P1_13) +#define DEFAULT_SPI_BUS_MISO (&pin_P1_14) + +#define DEFAULT_UART_BUS_RX (&pin_P1_01) +#define DEFAULT_UART_BUS_TX (&pin_P1_02) diff --git a/ports/nrf/boards/pca10059/examples/buttons.py b/ports/nrf/boards/pca10059/examples/buttons.py deleted file mode 100644 index 1a0c5aabbcaa2..0000000000000 --- a/ports/nrf/boards/pca10059/examples/buttons.py +++ /dev/null @@ -1,26 +0,0 @@ -import board -import digitalio -import gamepad -import time - -pad = gamepad.GamePad( - digitalio.DigitalInOut(board.P0_11), - digitalio.DigitalInOut(board.P0_12), - digitalio.DigitalInOut(board.P0_24), - digitalio.DigitalInOut(board.P0_25), -) - -prev_buttons = 0 - -while True: - buttons = pad.get_pressed() - - if buttons != prev_buttons: - for i in range(0, 4): - bit = (1 << i) - if (buttons & bit) != (prev_buttons & bit): - print('Button %d %s' % (i + 1, 'pressed' if buttons & bit else 'released')) - - prev_buttons = buttons - - time.sleep(0.1) diff --git a/ports/nrf/boards/pca10059/mpconfigboard.h b/ports/nrf/boards/pca10059/mpconfigboard.h index bca61fd0f98d8..b248011ec9e3e 100644 --- a/ports/nrf/boards/pca10059/mpconfigboard.h +++ b/ports/nrf/boards/pca10059/mpconfigboard.h @@ -24,7 +24,7 @@ * THE SOFTWARE. */ -#define MICROPY_HW_BOARD_NAME "PCA10059" +#define MICROPY_HW_BOARD_NAME "PCA10059 nRF52840 Dongle" #define MICROPY_HW_MCU_NAME "nRF52840" #define MICROPY_PY_SYS_PLATFORM "nRF52840-DK" diff --git a/ports/nrf/common-hal/microcontroller/__init__.c b/ports/nrf/common-hal/microcontroller/__init__.c index 46fe1e1907aff..c2e0c5b419141 100644 --- a/ports/nrf/common-hal/microcontroller/__init__.c +++ b/ports/nrf/common-hal/microcontroller/__init__.c @@ -79,7 +79,6 @@ STATIC const mp_rom_map_elem_t mcu_pin_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_P0_11), MP_ROM_PTR(&pin_P0_11) }, { MP_ROM_QSTR(MP_QSTR_P0_12), MP_ROM_PTR(&pin_P0_12) }, { MP_ROM_QSTR(MP_QSTR_P0_13), MP_ROM_PTR(&pin_P0_13) }, - { MP_ROM_QSTR(MP_QSTR_P0_13), MP_ROM_PTR(&pin_P0_13) }, { MP_ROM_QSTR(MP_QSTR_P0_14), MP_ROM_PTR(&pin_P0_14) }, { MP_ROM_QSTR(MP_QSTR_P0_15), MP_ROM_PTR(&pin_P0_15) }, { MP_ROM_QSTR(MP_QSTR_P0_16), MP_ROM_PTR(&pin_P0_16) }, diff --git a/ports/nrf/peripherals/nrf/pins.h b/ports/nrf/peripherals/nrf/pins.h index 1a87c0d88db35..22ca27457af74 100644 --- a/ports/nrf/peripherals/nrf/pins.h +++ b/ports/nrf/peripherals/nrf/pins.h @@ -67,6 +67,4 @@ extern const mp_obj_type_t mcu_pin_type; #include "nrf52840/pins.h" #endif -//**************extern const mp_obj_type_t mcu_pin_type; - #endif // __MICROPY_INCLUDED_NRF_PERIPHERALS_PINS_H__ From b5c03a708572dd1a5f9831109de310a43a1fe9eb Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Tue, 4 Sep 2018 16:43:21 -0400 Subject: [PATCH 5/6] generalize # of ports; remove atmel neopixel code; remove pin name in mc_pin_obj_t --- ports/nrf/common-hal/microcontroller/Pin.c | 7 +- .../nrf/common-hal/neopixel_write/__init__.c | 129 +----------------- ports/nrf/peripherals/nrf/pins.h | 2 - 3 files changed, 5 insertions(+), 133 deletions(-) diff --git a/ports/nrf/common-hal/microcontroller/Pin.c b/ports/nrf/common-hal/microcontroller/Pin.c index 01142fa15a760..7a069eedaa9a6 100644 --- a/ports/nrf/common-hal/microcontroller/Pin.c +++ b/ports/nrf/common-hal/microcontroller/Pin.c @@ -44,11 +44,12 @@ bool speaker_enable_in_use; #endif // Bit mask of claimed pins on each of up to two ports. nrf52832 has one port; nrf52840 has two. -STATIC uint32_t claimed_pins[2]; +STATIC uint32_t claimed_pins[GPIO_COUNT]; void reset_all_pins(void) { - claimed_pins[0] = 0; - claimed_pins[1] = 0; + for (size_t i = 0; i < GPIO_COUNT; i++) { + claimed_pins[i] = 0; + } for (uint32_t pin = 0; pin < NUMBER_OF_PINS; ++pin) { nrf_gpio_cfg_default(pin); diff --git a/ports/nrf/common-hal/neopixel_write/__init__.c b/ports/nrf/common-hal/neopixel_write/__init__.c index a29e1a136909d..3811dddc39c60 100644 --- a/ports/nrf/common-hal/neopixel_write/__init__.c +++ b/ports/nrf/common-hal/neopixel_write/__init__.c @@ -29,133 +29,6 @@ #include "tick.h" -// This magical macro makes sure the delay isn't optimized out and is the -// minimal three instructions. -#define delay_cycles(cycles) \ -{ \ - uint32_t t; \ - asm volatile ( \ - "movs %[t], %[c]\n\t" \ - "loop%=:\n\t" \ - "subs %[t], #1\n\t" \ - "bne.n loop%=" : [t] "=r"(t) : [c] "I" (cycles)); \ - } - -uint64_t next_start_tick_ms = 0; -uint32_t next_start_tick_us = 1000; - void common_hal_neopixel_write(const digitalio_digitalinout_obj_t* digitalinout, uint8_t *pixels, uint32_t numBytes) { -// TODO: Figure out timing delays on nRF. Turn off cache using ICACHECNF register. -/* - // This is adapted directly from the Adafruit NeoPixel library SAMD21G18A code: - // https://github.com/adafruit/Adafruit_NeoPixel/blob/master/Adafruit_NeoPixel.cpp - uint8_t *ptr, *end, p, bitMask; - uint32_t pinMask; - PortGroup* port; - - // This must be called while interrupts are on in case we're waiting for a - // future ms tick. - wait_until(next_start_tick_ms, next_start_tick_us); - - // Turn off interrupts of any kind during timing-sensitive code. - mp_hal_disable_all_interrupts(); - - - // Make sure the NVM cache is consistently timed. - - NVMCTRL->CTRLB.bit.READMODE = NVMCTRL_CTRLB_READMODE_DETERMINISTIC_Val; - #endif - - uint32_t pin = digitalinout->pin->number; - port = &PORT->Group[GPIO_PORT(pin)]; // Convert GPIO # to port register - pinMask = (1UL << (pin % 32)); // From port_pin_set_output_level ASF code. - ptr = pixels; - end = ptr + numBytes; - p = *ptr++; - bitMask = 0x80; - - volatile uint32_t *set = &(port->OUTSET.reg), - *clr = &(port->OUTCLR.reg); - - for(;;) { - *set = pinMask; - // This is the time where the line is always high regardless of the bit. - // For the SK6812 its 0.3us +- 0.15us - #ifdef SAMD21 - asm("nop; nop;"); - #endif - #ifdef SAMD51 - delay_cycles(3); - #endif - if(p & bitMask) { - // This is the high delay unique to a one bit. - // For the SK6812 its 0.3us - #ifdef SAMD21 - asm("nop; nop; nop; nop; nop; nop; nop;"); - #endif - #ifdef SAMD51 - delay_cycles(11); - #endif - *clr = pinMask; - } else { - *clr = pinMask; - // This is the low delay unique to a zero bit. - // For the SK6812 its 0.3us - #ifdef SAMD21 - asm("nop; nop;"); - #endif - #ifdef SAMD51 - delay_cycles(3); - #endif - } - if((bitMask >>= 1) != 0) { - // This is the delay between bits in a byte and is the 1 code low - // level time from the datasheet. - // For the SK6812 its 0.6us +- 0.15us - #ifdef SAMD21 - asm("nop; nop; nop; nop; nop;"); - #endif - #ifdef SAMD51 - delay_cycles(20); - #endif - } else { - if(ptr >= end) break; - p = *ptr++; - bitMask = 0x80; - // This is the delay between bytes. It's similar to the other branch - // in the if statement except its tuned to account for the time the - // above operations take. - // For the SK6812 its 0.6us +- 0.15us - #ifdef SAMD51 - delay_cycles(15); - #endif - } - } - - #ifdef SAMD21 - // Speed up! (But inconsistent timing.) - NVMCTRL->CTRLB.bit.READMODE = NVMCTRL_CTRLB_READMODE_NO_MISS_PENALTY_Val; - #endif - - #ifdef SAMD51 - // Turn instruction, data, and NVM caches back on. - hri_cmcc_clear_CFG_reg(CMCC, CMCC_CFG_DCDIS | CMCC_CFG_ICDIS); - hri_nvmctrl_clear_CTRLA_CACHEDIS0_bit(NVMCTRL); - hri_nvmctrl_clear_CTRLA_CACHEDIS1_bit(NVMCTRL); - - #endif - - // ticks_ms may be out of date at this point because we stopped the - // interrupt. We'll risk it anyway. - current_tick(&next_start_tick_ms, &next_start_tick_us); - if (next_start_tick_us < 100) { - next_start_tick_ms += 1; - next_start_tick_us = 100 - next_start_tick_us; - } else { - next_start_tick_us -= 100; - } - - // Turn on interrupts after timing-sensitive code. - mp_hal_enable_all_interrupts(); -*/ + // stub } diff --git a/ports/nrf/peripherals/nrf/pins.h b/ports/nrf/peripherals/nrf/pins.h index 22ca27457af74..01aa9e956eada 100644 --- a/ports/nrf/peripherals/nrf/pins.h +++ b/ports/nrf/peripherals/nrf/pins.h @@ -37,7 +37,6 @@ typedef struct { mp_obj_base_t base; - qstr name; // These could be squeezed to fewer bits if more fields are needed. uint8_t number; // port << 5 | pin number in port (0-31): 6 bits needed uint8_t adc_channel; // 0 is no ADC, ADC channel from 1 to 8: @@ -50,7 +49,6 @@ extern const mp_obj_type_t mcu_pin_type; #define PIN(p_name, p_port, p_pin, p_adc_channel) \ { \ { &mcu_pin_type }, \ - .name = MP_QSTR_ ## p_name, \ .number = NRF_GPIO_PIN_MAP(p_port, p_pin), \ .adc_channel = (p_adc_channel), \ } From 100603a60b36853cad3d68666a420db19fb11289 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Wed, 5 Sep 2018 17:38:59 -0400 Subject: [PATCH 6/6] neopixel_write merge; alphabetize stuff in Makefile --- ports/nrf/Makefile | 47 +++++++++---------- .../nrf/common-hal/neopixel_write/__init__.c | 12 ++--- 2 files changed, 28 insertions(+), 31 deletions(-) diff --git a/ports/nrf/Makefile b/ports/nrf/Makefile index 75fc1cabdb8b7..d3dc23262dedd 100755 --- a/ports/nrf/Makefile +++ b/ports/nrf/Makefile @@ -95,29 +95,29 @@ SRC_NRFX = $(addprefix nrfx/,\ ) SRC_C += \ - mphalport.c \ - fatfs_port.c \ - tick.c \ background.c \ + fatfs_port.c \ internal_flash.c \ - drivers/bluetooth/ble_drv.c \ - drivers/bluetooth/ble_uart.c \ + mphalport.c \ + tick.c \ boards/$(BOARD)/board.c \ boards/$(BOARD)/pins.c \ - nrfx/mdk/system_$(MCU_SUB_VARIANT).c \ - nrfx/hal/nrf_nvmc.c \ device/$(MCU_VARIANT)/startup_$(MCU_SUB_VARIANT).c \ + drivers/bluetooth/ble_drv.c \ + drivers/bluetooth/ble_uart.c \ + lib/libc/string0.c \ + lib/mp-readline/readline.c \ lib/oofatfs/ff.c \ lib/oofatfs/option/ccsbcs.c \ lib/timeutils/timeutils.c \ lib/utils/buffer_helper.c \ lib/utils/context_manager_helpers.c \ - lib/utils/pyexec.c \ lib/utils/interrupt_char.c \ + lib/utils/pyexec.c \ lib/utils/stdout_helpers.c \ lib/utils/sys_stdio_mphal.c \ - lib/libc/string0.c \ - lib/mp-readline/readline.c \ + nrfx/hal/nrf_nvmc.c \ + nrfx/mdk/system_$(MCU_SUB_VARIANT).c \ peripherals/nrf/$(MCU_CHIP)/pins.c \ supervisor/shared/memory.c @@ -135,30 +135,29 @@ DRIVERS_SRC_C += $(addprefix modules/,\ ) SRC_COMMON_HAL += \ - board/__init__.c \ - digitalio/__init__.c \ - digitalio/DigitalInOut.c \ - microcontroller/__init__.c \ - microcontroller/Pin.c \ - microcontroller/Processor.c \ - neopixel_write/__init__.c \ - os/__init__.c \ - time/__init__.c \ - analogio/__init__.c \ analogio/AnalogIn.c \ analogio/AnalogOut.c \ - busio/__init__.c\ + analogio/__init__.c \ + board/__init__.c \ busio/I2C.c \ busio/SPI.c \ busio/UART.c \ + busio/__init__.c\ + digitalio/DigitalInOut.c \ + digitalio/__init__.c \ + microcontroller/Pin.c \ + microcontroller/Processor.c \ + microcontroller/__init__.c \ neopixel_write/__init__.c \ - pulseio/__init__.c \ + os/__init__.c \ + pulseio/PWMOut.c \ pulseio/PulseIn.c \ pulseio/PulseOut.c \ - pulseio/PWMOut.c \ + pulseio/__init__.c \ storage/__init__.c \ - supervisor/__init__.c \ supervisor/Runtime.c \ + supervisor/__init__.c \ + time/__init__.c \ ifneq ($(SD), ) SRC_COMMON_HAL += \ diff --git a/ports/nrf/common-hal/neopixel_write/__init__.c b/ports/nrf/common-hal/neopixel_write/__init__.c index c84bc4381a321..ef5e8beb17962 100644 --- a/ports/nrf/common-hal/neopixel_write/__init__.c +++ b/ports/nrf/common-hal/neopixel_write/__init__.c @@ -166,7 +166,7 @@ void common_hal_neopixel_write (const digitalio_digitalinout_obj_t* digitalinout // pwm->INTEN |= (PWM_INTEN_SEQEND0_Enabled<pin->port*32 + digitalinout->pin->pin, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL} ); + nrf_pwm_pins_set(pwm, (uint32_t[]) {digitalinout->pin->number, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL} ); // Enable the PWM nrf_pwm_enable(pwm); @@ -205,12 +205,10 @@ void common_hal_neopixel_write (const digitalio_digitalinout_obj_t* digitalinout // the LEDs and if you are not using the EasyDMA feature. __disable_irq(); -#ifdef NRF_P1 - NRF_GPIO_Type* port = ( digitalinout->pin->port ? NRF_P1 : NRF_P0 ); -#else - NRF_GPIO_Type* port = NRF_P0; -#endif - uint32_t pinMask = ( 1UL << digitalinout->pin->pin ); + uint32_t decoded_pin = digitalinout->pin->number; + NRF_GPIO_Type* port = nrf_gpio_pin_port_decode(&decoded_pin); + + uint32_t pinMask = ( 1UL << decoded_pin ); uint32_t CYCLES_X00 = CYCLES_800; uint32_t CYCLES_X00_T1H = CYCLES_800_T1H;