From 60a23f0fb65bebe91ab8b6da4a32ed0b012e9313 Mon Sep 17 00:00:00 2001 From: microbuilder Date: Thu, 21 Dec 2017 13:49:14 +0100 Subject: [PATCH 01/20] nRF52 update with internal file system support --- .gitmodules | 3 + lib/nrfutil | 1 + ports/nrf/Makefile | 131 +++++--- ports/nrf/boards/board.h | 47 +++ ports/nrf/boards/common.ld | 9 +- ports/nrf/boards/feather52/README.md | 130 ++++++-- ports/nrf/boards/feather52/board.c | 122 ++++++++ .../nrf/boards/feather52/bootloader/README.md | 9 + .../custom_nrf52832_dfu_app_2.0.1.ld | 26 +- .../custom_nrf52832_dfu_app_5.0.0.ld | 18 +- ports/nrf/boards/feather52/examples/blinky.py | 12 + .../nrf/boards/feather52/examples/i2c_scan.py | 20 ++ .../nrf/boards/feather52/examples/pulseio.py | 25 ++ ports/nrf/boards/feather52/mpconfigboard.h | 19 +- ports/nrf/boards/feather52/mpconfigboard.mk | 2 +- ports/nrf/boards/feather52/pins.c | 124 ++++++++ ports/nrf/boards/feather52/pins.csv | 40 +-- ports/nrf/boards/feather52/pins.h | 28 ++ ports/nrf/boards/make-pins.py | 8 +- ports/nrf/boards/microbit/mpconfigboard.h | 2 +- ports/nrf/boards/nrf52_prefix.c | 2 +- ports/nrf/common-hal/analogio/AnalogIn.c | 118 +++++++ ports/nrf/common-hal/analogio/AnalogIn.h | 41 +++ ports/nrf/common-hal/analogio/AnalogOut.c | 76 +++++ ports/nrf/common-hal/analogio/AnalogOut.h | 42 +++ ports/nrf/common-hal/analogio/__init__.c | 1 + ports/nrf/common-hal/board/__init__.c | 34 ++ ports/nrf/common-hal/busio/I2C.c | 207 ++++++++++++ ports/nrf/common-hal/busio/I2C.h | 42 +++ ports/nrf/common-hal/busio/SPI.c | 162 ++++++++++ ports/nrf/common-hal/busio/SPI.h | 42 +++ ports/nrf/common-hal/busio/__init__.c | 1 + ports/nrf/common-hal/digitalio/DigitalInOut.c | 169 ++++++++++ ports/nrf/common-hal/digitalio/DigitalInOut.h | 40 +++ ports/nrf/common-hal/digitalio/__init__.c | 1 + ports/nrf/common-hal/microcontroller/Pin.c | 75 +++++ ports/nrf/common-hal/microcontroller/Pin.h | 40 +++ .../common-hal/microcontroller/Processor.c | 37 +++ .../common-hal/microcontroller/Processor.h | 37 +++ .../nrf/common-hal/microcontroller/__init__.c | 51 +++ ports/nrf/common-hal/os/__init__.c | 88 ++++++ ports/nrf/common-hal/pulseio/PWMOut.c | 240 ++++++++++++++ ports/nrf/common-hal/pulseio/PWMOut.h | 47 +++ ports/nrf/common-hal/pulseio/PulseIn.c | 295 ++++++++++++++++++ ports/nrf/common-hal/pulseio/PulseIn.h | 49 +++ ports/nrf/common-hal/pulseio/PulseOut.c | 206 ++++++++++++ ports/nrf/common-hal/pulseio/PulseOut.h | 42 +++ ports/nrf/common-hal/pulseio/__init__.c | 1 + ports/nrf/common-hal/storage/__init__.c | 39 +++ ports/nrf/common-hal/time/__init__.c | 38 +++ ports/nrf/device/nrf52/startup_nrf52832.c | 2 + ports/nrf/device/nrf52/startup_nrf52840.c | 2 + .../drivers/bluetooth/download_ble_stack.sh | 24 +- ports/nrf/fifo.c | 267 ++++++++++++++++ ports/nrf/fifo.h | 148 +++++++++ ports/nrf/hal/hal_gpio.h | 34 +- ports/nrf/hal/hal_uart.c | 53 +++- ports/nrf/hal/hal_uart.h | 1 + ports/nrf/internal_flash.c | 208 ++++++++++++ ports/nrf/internal_flash.h | 61 ++++ ports/nrf/main.c | 265 ---------------- ports/nrf/modules/machine/pin.c | 4 +- ports/nrf/modules/machine/pin.h | 28 +- ports/nrf/modules/machine/pwm.c | 3 +- ports/nrf/modules/machine/spi.c | 3 +- ports/nrf/modules/machine/uart.c | 13 +- ports/nrf/modules/uos/moduos.c | 174 ----------- ports/nrf/mpconfigport.h | 76 +++-- ports/nrf/mpconfigport.mk | 4 + ports/nrf/mphalport.c | 7 + ports/nrf/mphalport.h | 5 + ports/nrf/supervisor/filesystem.c | 88 ++++++ ports/nrf/supervisor/port.c | 79 +++++ ports/nrf/supervisor/serial.c | 59 ++++ supervisor/port.h | 4 + 75 files changed, 4035 insertions(+), 616 deletions(-) create mode 160000 lib/nrfutil create mode 100644 ports/nrf/boards/board.h create mode 100644 ports/nrf/boards/feather52/board.c create mode 100644 ports/nrf/boards/feather52/bootloader/README.md create mode 100644 ports/nrf/boards/feather52/examples/blinky.py create mode 100644 ports/nrf/boards/feather52/examples/i2c_scan.py create mode 100644 ports/nrf/boards/feather52/examples/pulseio.py create mode 100644 ports/nrf/boards/feather52/pins.c create mode 100644 ports/nrf/boards/feather52/pins.h create mode 100644 ports/nrf/common-hal/analogio/AnalogIn.c create mode 100644 ports/nrf/common-hal/analogio/AnalogIn.h create mode 100644 ports/nrf/common-hal/analogio/AnalogOut.c create mode 100644 ports/nrf/common-hal/analogio/AnalogOut.h create mode 100644 ports/nrf/common-hal/analogio/__init__.c create mode 100644 ports/nrf/common-hal/board/__init__.c create mode 100644 ports/nrf/common-hal/busio/I2C.c create mode 100644 ports/nrf/common-hal/busio/I2C.h create mode 100644 ports/nrf/common-hal/busio/SPI.c create mode 100644 ports/nrf/common-hal/busio/SPI.h create mode 100644 ports/nrf/common-hal/busio/__init__.c create mode 100644 ports/nrf/common-hal/digitalio/DigitalInOut.c create mode 100644 ports/nrf/common-hal/digitalio/DigitalInOut.h create mode 100644 ports/nrf/common-hal/digitalio/__init__.c create mode 100644 ports/nrf/common-hal/microcontroller/Pin.c create mode 100644 ports/nrf/common-hal/microcontroller/Pin.h create mode 100644 ports/nrf/common-hal/microcontroller/Processor.c create mode 100644 ports/nrf/common-hal/microcontroller/Processor.h create mode 100644 ports/nrf/common-hal/microcontroller/__init__.c create mode 100644 ports/nrf/common-hal/os/__init__.c create mode 100644 ports/nrf/common-hal/pulseio/PWMOut.c create mode 100644 ports/nrf/common-hal/pulseio/PWMOut.h create mode 100644 ports/nrf/common-hal/pulseio/PulseIn.c create mode 100644 ports/nrf/common-hal/pulseio/PulseIn.h create mode 100644 ports/nrf/common-hal/pulseio/PulseOut.c create mode 100644 ports/nrf/common-hal/pulseio/PulseOut.h create mode 100644 ports/nrf/common-hal/pulseio/__init__.c create mode 100644 ports/nrf/common-hal/storage/__init__.c create mode 100644 ports/nrf/common-hal/time/__init__.c create mode 100644 ports/nrf/fifo.c create mode 100644 ports/nrf/fifo.h create mode 100644 ports/nrf/internal_flash.c create mode 100644 ports/nrf/internal_flash.h delete mode 100644 ports/nrf/main.c delete mode 100644 ports/nrf/modules/uos/moduos.c create mode 100644 ports/nrf/mpconfigport.mk create mode 100644 ports/nrf/supervisor/filesystem.c create mode 100644 ports/nrf/supervisor/port.c create mode 100644 ports/nrf/supervisor/serial.c diff --git a/.gitmodules b/.gitmodules index 4861053fe9b65..fbb74f013e129 100644 --- a/.gitmodules +++ b/.gitmodules @@ -40,3 +40,6 @@ [submodule "tools/usb_descriptor"] path = tools/usb_descriptor url = https://github.com/adafruit/usb_descriptor.git +[submodule "lib/nrfutil"] + path = lib/nrfutil + url = https://github.com/adafruit/nRF52_nrfutil diff --git a/lib/nrfutil b/lib/nrfutil new file mode 160000 index 0000000000000..07b43832ee53a --- /dev/null +++ b/lib/nrfutil @@ -0,0 +1 @@ +Subproject commit 07b43832ee53a4a248c30f5a3014e2632d8aeb88 diff --git a/ports/nrf/Makefile b/ports/nrf/Makefile index 8db3508e4758c..3ae298962197f 100644 --- a/ports/nrf/Makefile +++ b/ports/nrf/Makefile @@ -1,6 +1,6 @@ # Select the board to build for: if not given on the command line, -# then default to pca10040. -BOARD ?= pca10040 +# then default to feather52. +BOARD ?= feather52 ifeq ($(wildcard boards/$(BOARD)/.),) $(error Invalid BOARD specified) endif @@ -11,33 +11,38 @@ SD_LOWER = $(shell echo $(SD) | tr '[:upper:]' '[:lower:]') # TODO: Verify that it is a valid target. - ifeq ($(SD), ) # If the build directory is not given, make it reflect the board name. BUILD ?= build-$(BOARD) include ../../py/mkenv.mk include boards/$(BOARD)/mpconfigboard.mk + -include mpconfigport.mk + +INC += -Idrivers/bluetooth/s132_$(MCU_VARIANT)_$(SOFTDEV_VERSION)/s132_$(MCU_VARIANT)_$(SOFTDEV_VERSION)_API/include +INC += -Idrivers/bluetooth/s132_$(MCU_VARIANT)_$(SOFTDEV_VERSION)/s132_$(MCU_VARIANT)_$(SOFTDEV_VERSION)_API/include/$(MCU_VARIANT) + else # If the build directory is not given, make it reflect the board name. BUILD ?= build-$(BOARD)-$(SD_LOWER) include ../../py/mkenv.mk include boards/$(BOARD)/mpconfigboard_$(SD_LOWER).mk + -include mpconfigport.mk include drivers/bluetooth/bluetooth_common.mk endif + # qstr definitions (must come before including py.mk) -QSTR_DEFS = qstrdefsport.h $(BUILD)/pins_qstr.h +QSTR_DEFS = qstrdefsport.h FROZEN_MPY_DIR = freeze # include py core make definitions include ../../py/py.mk +include $(TOP)/supervisor/supervisor.mk FATFS_DIR = lib/oofatfs -MPY_CROSS = ../../mpy-cross/mpy-cross -MPY_TOOL = ../../tools/mpy-tool.py CROSS_COMPILE = arm-none-eabi- @@ -105,22 +110,12 @@ LIBS += -L $(dir $(LIBC_FILE_NAME)) -lc LIBS += -L $(dir $(LIBGCC_FILE_NAME)) -lgcc endif -SRC_LIB = $(addprefix lib/,\ - libc/string0.c \ - mp-readline/readline.c \ - utils/pyexec.c \ - timeutils/timeutils.c \ - oofatfs/ff.c \ - oofatfs/option/unicode.c \ - ) - SRC_HAL = $(addprefix hal/,\ hal_uart.c \ hal_uarte.c \ hal_spi.c \ hal_spie.c \ hal_time.c \ - hal_rtc.c \ hal_timer.c \ hal_twi.c \ hal_adc.c \ @@ -136,17 +131,31 @@ SRC_HAL += $(addprefix hal/,\ ) endif + SRC_C += \ - main.c \ mphalport.c \ help.c \ - gccollect.c \ pin_named_pins.c \ fatfs_port.c \ + fifo.c \ drivers/softpwm.c \ drivers/ticker.c \ drivers/bluetooth/ble_drv.c \ drivers/bluetooth/ble_uart.c \ + boards/$(BOARD)/board.c \ + boards/$(BOARD)/pins.c \ + device/$(MCU_VARIANT)/system_$(MCU_SUB_VARIANT).c \ + device/$(MCU_VARIANT)/startup_$(MCU_SUB_VARIANT).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/libc/string0.c \ + lib/mp-readline/readline.c \ + internal_flash.c \ + DRIVERS_SRC_C += $(addprefix modules/,\ machine/modmachine.c \ @@ -156,11 +165,9 @@ DRIVERS_SRC_C += $(addprefix modules/,\ machine/adc.c \ machine/pin.c \ machine/timer.c \ - machine/rtc.c \ machine/pwm.c \ machine/led.c \ machine/temp.c \ - uos/moduos.c \ utime/modutime.c \ pyb/modpyb.c \ ubluepy/modubluepy.c \ @@ -179,18 +186,72 @@ DRIVERS_SRC_C += $(addprefix modules/,\ random/modrandom.c \ ) -SRC_C += \ - device/$(MCU_VARIANT)/system_$(MCU_SUB_VARIANT).c \ - device/$(MCU_VARIANT)/startup_$(MCU_SUB_VARIANT).c \ + +SRC_COMMON_HAL += \ + board/__init__.c \ + digitalio/__init__.c \ + digitalio/DigitalInOut.c \ + microcontroller/__init__.c \ + microcontroller/Pin.c \ + microcontroller/Processor.c \ + os/__init__.c \ + time/__init__.c \ + analogio/__init__.c \ + analogio/AnalogIn.c \ + analogio/AnalogOut.c \ + busio/__init__.c\ + busio/I2C.c \ + busio/SPI.c \ + pulseio/__init__.c \ + pulseio/PulseIn.c \ + pulseio/PulseOut.c \ + pulseio/PWMOut.c \ + storage/__init__.c \ + +# These don't have corresponding files in each port but are still located in +# shared-bindings to make it clear what the contents of the modules are. +SRC_BINDINGS_ENUMS = \ + digitalio/Direction.c \ + digitalio/DriveMode.c \ + digitalio/Pull.c \ + help.c \ + math/__init__.c \ + supervisor/__init__.c \ + util.c + +SRC_COMMON_HAL_EXPANDED = $(addprefix shared-bindings/, $(SRC_COMMON_HAL)) \ + $(addprefix shared-bindings/, $(SRC_BINDINGS_ENUMS)) \ + $(addprefix common-hal/, $(SRC_COMMON_HAL)) + +SRC_SHARED_MODULE = \ + os/__init__.c \ + random/__init__.c \ + storage/__init__.c \ + +# bitbangio/__init__.c \ + bitbangio/I2C.c \ + bitbangio/OneWire.c \ + bitbangio/SPI.c \ + busio/OneWire.c \ + gamepad/__init__.c \ + gamepad/GamePad.c \ + struct/__init__.c \ + uheap/__init__.c \ + ustack/__init__.c + +#SRC_SHARED_MODULE_EXPANDED = $(addprefix shared-bindings/, $(SRC_SHARED_MODULE)) \ + $(addprefix shared-module/, $(SRC_SHARED_MODULE)) + +SRC_SHARED_MODULE_EXPANDED = $(addprefix shared-module/, $(SRC_SHARED_MODULE)) 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) $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) -OBJ += $(addprefix $(BUILD)/, $(SRC_LIB:.c=.o)) +OBJ += $(PY_O) $(SUPERVISOR_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_HAL:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(DRIVERS_SRC_C:.c=.o)) -OBJ += $(BUILD)/pins_gen.o +OBJ += $(addprefix $(BUILD)/, $(SRC_COMMON_HAL_EXPANDED:.c=.o)) +OBJ += $(addprefix $(BUILD)/, $(SRC_SHARED_MODULE_EXPANDED:.c=.o)) $(BUILD)/$(FATFS_DIR)/ff.o: COPT += -Os $(filter $(PY_BUILD)/../extmod/vfs_fat_%.o, $(PY_O)): COPT += -Os @@ -241,11 +302,11 @@ endif $(BUILD)/$(OUTPUT_FILENAME).elf: $(OBJ) $(ECHO) "LINK $@" - $(Q)$(CC) $(LDFLAGS) -o $@ $(OBJ) $(LIBS) + $(Q)$(CC) $(LDFLAGS) -o $@ $(OBJ) -Wl,--start-group $(LIBS) -Wl,--end-group $(Q)$(SIZE) $@ # List of sources for qstr extraction -SRC_QSTR += $(SRC_C) $(SRC_MOD) $(SRC_LIB) $(DRIVERS_SRC_C) +SRC_QSTR += $(SRC_C) $(SRC_SUPERVISOR) $(SRC_MOD) $(DRIVERS_SRC_C) $(SRC_COMMON_HAL_EXPANDED) $(SRC_SHARED_MODULE_EXPANDED) # Append any auto-generated sources that are needed by sources listed in # SRC_QSTR @@ -256,16 +317,16 @@ SRC_QSTR_AUTO_DEPS += # 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 +#$(OBJ): | $(HEADER_BUILD)/pins.h # Use a pattern rule here so that make will only call make-pins.py once to make # both pins_$(BOARD).c and pins.h -$(BUILD)/%_$(BOARD).c $(HEADER_BUILD)/%.h $(HEADER_BUILD)/%_af_const.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) --af-const $(GEN_PINS_AF_CONST) --af-py $(GEN_PINS_AF_PY) > $(GEN_PINS_SRC) +#$(BUILD)/%_$(BOARD).c $(HEADER_BUILD)/%.h $(HEADER_BUILD)/%_af_const.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) --af-const $(GEN_PINS_AF_CONST) --af-py $(GEN_PINS_AF_PY) > $(GEN_PINS_SRC) -$(BUILD)/pins_gen.o: $(BUILD)/pins_gen.c - $(call compile_c) +#$(BUILD)/pins_gen.o: $(BUILD)/pins_gen.c +# $(call compile_c) MAKE_PINS = boards/make-pins.py BOARD_PINS = boards/$(BOARD)/pins.csv @@ -290,4 +351,4 @@ CFLAGS += -DMICROPY_QSTR_EXTRA_POOL=mp_qstr_frozen_const_pool CFLAGS += -DMICROPY_MODULE_FROZEN_MPY endif -include ../../py/mkrules.mk +include $(TOP)/py/mkrules.mk diff --git a/ports/nrf/boards/board.h b/ports/nrf/boards/board.h new file mode 100644 index 0000000000000..fecc0fb5761e5 --- /dev/null +++ b/ports/nrf/boards/board.h @@ -0,0 +1,47 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * 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 + * 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. + */ + +// This file defines board specific functions. + +#ifndef MICROPY_INCLUDED_NRF_BOARDS_BOARD_H +#define MICROPY_INCLUDED_NRF_BOARDS_BOARD_H + +#include + +extern volatile uint32_t ticks_ms; + +// Initializes board related state once on start up. +void board_init(void); + +// Returns true if the user initiates safe mode in a board specific way. +// Also add BOARD_USER_SAFE_MODE in mpconfigboard.h to explain the board specific +// way. +bool board_requests_safe_mode(void); + +// Reset the state of off MCU components such as neopixels. +void reset_board(void); + +#endif // MICROPY_INCLUDED_NRF_BOARDS_BOARD_H diff --git a/ports/nrf/boards/common.ld b/ports/nrf/boards/common.ld index c6e4952b454d0..df81aae5833e7 100644 --- a/ports/nrf/boards/common.ld +++ b/ports/nrf/boards/common.ld @@ -1,3 +1,7 @@ +/* Flash region for File System */ +__fatfs_flash_start_addr = ORIGIN(FLASH_FATFS); +__fatfs_flash_length = LENGTH(FLASH_FATFS); + /* define output sections */ SECTIONS { @@ -75,8 +79,8 @@ SECTIONS .heap : { . = ALIGN(4); - PROVIDE ( end = . ); - PROVIDE ( _end = . ); + PROVIDE ( end = . ); + PROVIDE ( _end = . ); _heap_start = .; /* define a global symbol at heap start */ . = . + _minimum_heap_size; } >RAM @@ -101,3 +105,4 @@ SECTIONS .ARM.attributes 0 : { *(.ARM.attributes) } } + diff --git a/ports/nrf/boards/feather52/README.md b/ports/nrf/boards/feather52/README.md index e05d8995330cc..2a28206246023 100644 --- a/ports/nrf/boards/feather52/README.md +++ b/ports/nrf/boards/feather52/README.md @@ -1,6 +1,10 @@ # Setup -Before you can build, you will need to run the following commands once: +## Installing CircuitPython submodules + +Before you can build, you will need to run the following commands once, which +will install the submodules that are part of the CircuitPython ecosystem, and +build the `mpy-cross` tool: ``` $ cd circuitpython @@ -8,7 +12,7 @@ $ git submodule update --init $ make -C mpy-cross ``` -You then need to download the SD and Nordic SDK files: +You then need to download the SD and Nordic SDK files via: > This script relies on `wget`, which must be available from the command line. @@ -17,47 +21,50 @@ $ cd ports/nrf $ ./drivers/bluetooth/download_ble_stack.sh ``` +## Installing `nrfutil` + +The Adafruit Bluefruit nRF52 Feather ships with a serial and OTA BLE bootloader +that can be used to flash firmware images over a simple serial connection, +using the on-board USB serial converter. + +If you haven't installed this command-line tool yet, go to the `/libs/nrfutil` +folder (where nrfutil 0.5.2 is installed as a sub-module) and run the following +commands: + +> If you get a 'sudo: pip: command not found' error running 'sudo pip install', +you can install pip via 'sudo easy_install pip' + +``` +$ cd ../../libs/nrfutil +$ sudo pip install -r requirements.txt +$ sudo python setup.py install +``` + # Building and flashing firmware images -## Building CircuitPython +## Building CircuitPython binaries #### REPL over UART (default settings) To build a CircuitPython binary with default settings for the `feather52` target enter: +> **NOTE:** `BOARD=feather52` is the default option and isn't stricly required. + ``` $ make BOARD=feather52 V=1 ``` -#### REPL over BLE UART (AKA `NUS`) +#### REPL over BLE support -To build a CircuitPython binary with REPL over BLE UART, edit -`bluetooth_conf.h` with the following values (under -`#elif (BLUETOOTH_SD == 132)`): - -``` -#define MICROPY_PY_BLE (1) -#define MICROPY_PY_BLE_NUS (1) -#define BLUETOOTH_WEBBLUETOOTH_REPL (1) -``` - -Then build the CircuitPython binary, including `SD=s132` -to enable BLE support in the build process: +To build a CircuitPython binary with BLE support (S132) include `SD=s132` +as part of the build process: ``` $ make BOARD=feather52 V=1 SD=s132 ``` -## Flashing with `nrfutil` - -The Adafruit Bluefruit nRF52 Feather ships with a serial and OTA BLE bootloader -that can be used to flash firmware images over a simple serial connection, -using the on-board USB serial converter. - -These commands assume that you have already installed `nrfutil`, as described -in the [learning guide](https://learn.adafruit.com/bluefruit-nrf52-feather-learning-guide/arduino-bsp-setup) -for the Arduino variant of the board. +## Flashing binaries with `nrfutil` ### 1. **Update bootloader** to single-bank version @@ -88,7 +95,7 @@ To enable BLE5 support and the latest S132 release, flash the v5.0.0 bootloader $ make BOARD=feather52 SERIAL=/dev/tty.SLAB_USBtoUART SOFTDEV_VERSION=5.0.0 boot-flash ``` -### 2. Generate a CircuitPython DFU .zip package and flash it over serial +### 2. Generate and flash a CircuitPython DFU .zip package over serial The following command will package and flash the CircuitPython binary using the appropriate bootloader mentionned above. @@ -102,9 +109,76 @@ image, as described earlier in this readme. $ make BOARD=feather52 SERIAL=/dev/tty.SLAB_USBtoUART dfu-gen dfu-flash ``` -If you built your CircuitPython binary with **BLE UART** support you will -need to add the `SD=s132` flag as shown below: +If you built your CircuitPython binary with **BLE** support you will need to +add the `SD=s132` flag as shown below: ``` $ make BOARD=feather52 SERIAL=/dev/tty.SLAB_USBtoUART SD=s132 dfu-gen dfu-flash ``` + +## Working with CircuitPython + +### Running local files with `ampy` + +[ampy](https://learn.adafruit.com/micropython-basics-load-files-and-run-code/install-ampy) +is a command-line tool that can be used with the nRF52 Feather to transfer +local python files to the nRF52 for execution, rather than having to enter +the REPL manually, enter paste mode, and paste the code yourself. + +> **IMPORTANT**: You must have `ampy` version **1.0.3** or higher to use `ampy` + with the nRF52. The bootloader on the nRF52 requires a delay between the + HW reset, and the moment when the command sequance is sent to enter raw + mode. This required `-d/--delay` flag was added in release 1.0.3. + + +Save the following file as `test.py`: + +``` +import board +import digitalio +import time + +led = digitalio.DigitalInOut(board.LED2) +led.direction = digitalio.Direction.OUTPUT + +while True: + led.value = True + time.sleep(0.5) + led.value = False + time.sleep(0.5) +``` + +Then run the saved file via ampy, updating the serial port as required: + +``` +$ ampy -p /dev/tty.SLAB_USBtoUART -d 1.5 run test.py +``` + +This should give you blinky at 1 Hz on LED2 (the blue LED on the nRF52 Feather). + +### Uploading files and libraries with `ampy` + +To upload Python files or pre-compiled CircuitPython libraries to the `lib` folder, +run the following commands: + +> In this example **i2c_device.py** is used, which is part of + [Adafruit_CircuitPython_BusDevice](https://github.com/adafruit/Adafruit_CircuitPython_BusDevice) + +``` +$ ampy -p /dev/tty.SLAB_USBtoUART -d 1.5 put i2c_device.py lib/i2c_device.py +``` + +To verify that the file was uploaded correctly, you can check the contents of +the `lib` folder with: + +``` +$ ampy -p /dev/tty.SLAB_USBtoUART -d 1.5 ls /lib +i2c_device.py +``` + +### Suggested libraries + +The following libraries should be installed as a minimum on most new boards: + +- [Adafruit_CircuitPython_BusDevice](https://github.com/adafruit/Adafruit_CircuitPython_BusDevice) +- [Adafruit_CircuitPython_Register](https://github.com/adafruit/Adafruit_CircuitPython_Register/tree/master) diff --git a/ports/nrf/boards/feather52/board.c b/ports/nrf/boards/feather52/board.c new file mode 100644 index 0000000000000..0f4cf4e3059e2 --- /dev/null +++ b/ports/nrf/boards/feather52/board.c @@ -0,0 +1,122 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * 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 + * 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 +#include + +#include "nrf.h" + +#include "boards/board.h" + +#if 0 +#include "common-hal/microcontroller/Pin.h" +#include "hal/include/hal_gpio.h" +#include "shared-bindings/digitalio/DigitalInOut.h" +#include "shared-bindings/neopixel_write/__init__.h" +#endif + +// Must match temp register in bootloader +#define BOOTLOADER_VERSION_REGISTER NRF_TIMER2->CC[0] +uint32_t bootloaderVersion = 0; + +volatile uint32_t ticks_ms = 0; + +#define HAL_LFCLK_FREQ (32768UL) +#define HAL_RTC_FREQ (1024UL) +#define HAL_RTC_COUNTER_PRESCALER ((HAL_LFCLK_FREQ/HAL_RTC_FREQ)-1) + +/* Maximum RTC ticks */ +#define portNRF_RTC_MAXTICKS ((1U<<24)-1U) + +void board_init(void) +{ + // Retrieve bootloader version + bootloaderVersion = BOOTLOADER_VERSION_REGISTER; + + // 32Khz XTAL + NRF_CLOCK->LFCLKSRC = (uint32_t)((CLOCK_LFCLKSRC_SRC_Xtal << CLOCK_LFCLKSRC_SRC_Pos) & CLOCK_LFCLKSRC_SRC_Msk); + NRF_CLOCK->TASKS_LFCLKSTART = 1UL; + + // Set up RTC1 as tick timer + NVIC_DisableIRQ(RTC1_IRQn); + NRF_RTC1->EVTENCLR = RTC_EVTEN_COMPARE0_Msk; + NRF_RTC1->INTENCLR = RTC_INTENSET_COMPARE0_Msk; + NRF_RTC1->TASKS_STOP = 1; + NRF_RTC1->TASKS_CLEAR = 1; + + ticks_ms = 0; + + NRF_RTC1->PRESCALER = HAL_RTC_COUNTER_PRESCALER; + NRF_RTC1->INTENSET = RTC_INTENSET_TICK_Msk; + NRF_RTC1->TASKS_START = 1; + NRF_RTC1->EVTENSET = RTC_EVTEN_OVRFLW_Msk; + NVIC_SetPriority(RTC1_IRQn, 0xf); // lowest priority + NVIC_EnableIRQ(RTC1_IRQn); +} + +void RTC1_IRQHandler(void) +{ + // Clear event + NRF_RTC1->EVENTS_TICK = 0; + volatile uint32_t dummy = NRF_RTC1->EVENTS_TICK; + (void) dummy; + + // Tick correction + uint32_t systick_counter = NRF_RTC1->COUNTER; + uint32_t diff = (systick_counter - ticks_ms) & portNRF_RTC_MAXTICKS; + ticks_ms += diff; +} + +// Check the status of the two buttons on CircuitPlayground Express. If both are +// pressed, then boot into user safe mode. +bool board_requests_safe_mode(void) { +// gpio_set_pin_function(PIN_PA14, GPIO_PIN_FUNCTION_OFF); +// gpio_set_pin_direction(PIN_PA14, GPIO_DIRECTION_IN); +// gpio_set_pin_pull_mode(PIN_PA14, GPIO_PULL_DOWN); +// +// gpio_set_pin_function(PIN_PA28, GPIO_PIN_FUNCTION_OFF); +// gpio_set_pin_direction(PIN_PA28, GPIO_DIRECTION_IN); +// 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); +// return safe_mode; + + return false; +} + +void reset_board(void) { +// uint8_t empty[30]; +// memset(empty, 0, 30); +// digitalio_digitalinout_obj_t neopixel_pin; +// common_hal_digitalio_digitalinout_construct(&neopixel_pin, &pin_PB23); +// common_hal_digitalio_digitalinout_switch_to_output(&neopixel_pin, false, +// DRIVE_MODE_PUSH_PULL); +// common_hal_neopixel_write(&neopixel_pin, empty, 30); +// common_hal_digitalio_digitalinout_deinit(&neopixel_pin); +} + diff --git a/ports/nrf/boards/feather52/bootloader/README.md b/ports/nrf/boards/feather52/bootloader/README.md new file mode 100644 index 0000000000000..434859085951e --- /dev/null +++ b/ports/nrf/boards/feather52/bootloader/README.md @@ -0,0 +1,9 @@ +# Adafruit nRF52 Feather Single-Bank Bootloader + +These files contain an implementation of a single-bank bootloader, +which doubles the amount of flash memory available to applications +at the expense of safe over the air updates. + +Two versions are present, based on release **2.0.1** and **5.0.0** +of the Nordic S132 SoftDevice. The SoftDevice is included as poart +of the bootloader binary. diff --git a/ports/nrf/boards/feather52/custom_nrf52832_dfu_app_2.0.1.ld b/ports/nrf/boards/feather52/custom_nrf52832_dfu_app_2.0.1.ld index 824b6becfebfc..183822f92a81c 100644 --- a/ports/nrf/boards/feather52/custom_nrf52832_dfu_app_2.0.1.ld +++ b/ports/nrf/boards/feather52/custom_nrf52832_dfu_app_2.0.1.ld @@ -5,10 +5,15 @@ ------------------------------------------------------------------------ START ADDR END ADDR SIZE DESCRIPTION ---------- ---------- ------- ----------------------------------------- - 0x00074000..0x00080000 ( 48KB) Serial + OTA Bootloader - 0x0006D000..0x00073FFF ( 28KB) Private Config Data (Bonding, Keys, etc.) - 0x00055000..0x0006CFFF ( 96KB) User Filesystem - 0x0001C000..0x00054FFF (228KB) Application Code + 0x0007F000..0x0007FFFF ( 4KB) Bootloader Settings + 0x0007E000..0x0007EFFF ( 4KB) Master Boot Record Params + 0x00074000..0x0007DFFF ( 40KB) Serial + OTA Bootloader + + 0x00073000..0x00073FFF ( 4KB ) Private Config Data (Bonding, Keys, etc.) + 0x00072000..0x00072FFF ( 4KB ) User NVM data + 0x00059000..0x00071FFF (100KB) User Filesystem + + 0x0001C000..0x00058FFF (244KB) Application Code 0x00001000..0x0001BFFF (108KB) SoftDevice 0x00000000..0x00000FFF (4KB) Master Boot Record */ @@ -16,15 +21,16 @@ /* Specify the memory areas (S132 2.0.1) */ MEMORY { - FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x080000 /* entire flash, 512 KiB */ - FLASH_ISR (rx) : ORIGIN = 0x0001c000, LENGTH = 0x001000 /* sector 0, 4 KiB */ - FLASH_TEXT (rx) : ORIGIN = 0x0001d000, LENGTH = 0x038000 /* APP - ISR, 224 KiB */ - RAM (xrw) : ORIGIN = 0x200039c0, LENGTH = 0x0c640 /* 49.5 KiB, give 8KiB headroom for softdevice */ + FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x080000 /* entire flash, 512 KiB */ + FLASH_ISR (rx) : ORIGIN = 0x0001c000, LENGTH = 0x001000 /* sector 0, 4 KiB */ + FLASH_TEXT (rx) : ORIGIN = 0x0001d000, LENGTH = 0x03C000 /* APP - ISR, 240 KiB */ + FLASH_FATFS (r) : ORIGIN = 0x00059000, LENGTH = 0x019000 /* File system 100KB KB */ + RAM (xrw) : ORIGIN = 0x200039c0, LENGTH = 0x0c640 /* 49.5 KiB, give 8KiB headroom for softdevice */ } /* produce a link error if there is not this amount of RAM for these sections */ _minimum_stack_size = 2K; -_minimum_heap_size = 16K; +_minimum_heap_size = 0 /*16K Circuit Python use static variable for HEAP */; /* top end of the stack */ @@ -35,4 +41,4 @@ _estack = ORIGIN(RAM) + LENGTH(RAM); _ram_end = ORIGIN(RAM) + LENGTH(RAM); _heap_end = 0x20007000; /* tunable */ -INCLUDE "boards/common.ld" \ No newline at end of file +INCLUDE "boards/common.ld" diff --git a/ports/nrf/boards/feather52/custom_nrf52832_dfu_app_5.0.0.ld b/ports/nrf/boards/feather52/custom_nrf52832_dfu_app_5.0.0.ld index e7a09303b9e70..f9209bf3d1884 100644 --- a/ports/nrf/boards/feather52/custom_nrf52832_dfu_app_5.0.0.ld +++ b/ports/nrf/boards/feather52/custom_nrf52832_dfu_app_5.0.0.ld @@ -5,10 +5,15 @@ ------------------------------------------------------------------------ START ADDR END ADDR SIZE DESCRIPTION ---------- ---------- ------- ----------------------------------------- - 0x00074000..0x00080000 ( 48KB) Serial + OTA Bootloader - 0x0006D000..0x00073FFF ( 28KB) Private Config Data (Bonding, Keys, etc.) - 0x00055000..0x0006CFFF ( 96KB) User Filesystem - 0x00023000..0x00054FFF (200KB) Application Code + 0x0007F000..0x0007FFFF ( 4KB) Bootloader Settings + 0x0007E000..0x0007EFFF ( 4KB) Master Boot Record Params + 0x00074000..0x0007DFFF ( 40KB) Serial + OTA Bootloader + + 0x00073000..0x00073FFF ( 4KB ) Private Config Data (Bonding, Keys, etc.) + 0x00072000..0x00072FFF ( 4KB ) User NVM data + 0x00059000..0x00071FFF ( 100KB) User Filesystem + + 0x00023000..0x00058FFF (216KB) Application Code 0x00001000..0x00022FFF (136KB) SoftDevice 0x00000000..0x00000FFF (4KB) Master Boot Record */ @@ -18,13 +23,14 @@ MEMORY { FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x080000 /* entire flash, 512 KiB */ FLASH_ISR (rx) : ORIGIN = 0x00023000, LENGTH = 0x001000 /* sector 0, 4 KiB */ - FLASH_TEXT (rx) : ORIGIN = 0x00024000, LENGTH = 0x030FFF /* APP - ISR, 200 KiB */ + FLASH_TEXT (rx) : ORIGIN = 0x00024000, LENGTH = 0x036000 /* APP - ISR, 216 KiB */ + FLASH_FATFS (r) : ORIGIN = 0x00059000, LENGTH = 0x019000 /* File system 100KB KB */ RAM (xrw) : ORIGIN = 0x200039c0, LENGTH = 0x0c640 /* 49.5 KiB, give 8KiB headroom for softdevice */ } /* produce a link error if there is not this amount of RAM for these sections */ _minimum_stack_size = 2K; -_minimum_heap_size = 16K; +_minimum_heap_size = 0 /*16K Circuit Python use static variable for HEAP */; /* top end of the stack */ diff --git a/ports/nrf/boards/feather52/examples/blinky.py b/ports/nrf/boards/feather52/examples/blinky.py new file mode 100644 index 0000000000000..29cca26d04038 --- /dev/null +++ b/ports/nrf/boards/feather52/examples/blinky.py @@ -0,0 +1,12 @@ +import board +import digitalio +import time + +led = digitalio.DigitalInOut(board.LED2) +led.direction = digitalio.Direction.OUTPUT + +while True: + led.value = True + time.sleep(0.5) + led.value = False + time.sleep(0.5) diff --git a/ports/nrf/boards/feather52/examples/i2c_scan.py b/ports/nrf/boards/feather52/examples/i2c_scan.py new file mode 100644 index 0000000000000..8e3ef557d136b --- /dev/null +++ b/ports/nrf/boards/feather52/examples/i2c_scan.py @@ -0,0 +1,20 @@ +import board +import busio + +i2c = busio.I2C(board.SCL, board.SDA) +count = 0 + +# Wait for I2C lock +while not i2c.try_lock(): + pass + +# Scan for devices on the I2C bus +print("Scanning I2C bus") +for x in i2c.scan(): + print(hex(x)) + count += 1 + +print("%d device(s) found on I2C bus" % count) + +# Release the I2C bus +i2c.unlock() diff --git a/ports/nrf/boards/feather52/examples/pulseio.py b/ports/nrf/boards/feather52/examples/pulseio.py new file mode 100644 index 0000000000000..cdbe16addd065 --- /dev/null +++ b/ports/nrf/boards/feather52/examples/pulseio.py @@ -0,0 +1,25 @@ +import time +from board import * +from pulseio import * + +# Setup BLUE and RED LEDs as PWM output (default frequency is 500 Hz) +ledb = PWMOut(LED2) +ledr = PWMOut(LED1) + +# Set the BLUE LED to have a duty cycle of 5000 (out of 65535, so ~7.5%) +ledb.duty_cycle = 5000 + +# Setup pin A0 as a standard PWM out @ 50% to test on the oscilloscope. +# You should see a 50% duty cycle waveform at ~500Hz on the scope when you +# connect a probe to pin A0 +a0 = PWMOut(A0) +a0.duty_cycle = int(65535/2) + +# Constantly pulse the RED LED +while True: + for i in range(100): + ledr.duty_cycle = int(i / 100 * 65535) + time.sleep(0.01) + for i in range(100, -1, -1): + ledr.duty_cycle = int(i / 100 * 65535) + time.sleep(0.01) diff --git a/ports/nrf/boards/feather52/mpconfigboard.h b/ports/nrf/boards/feather52/mpconfigboard.h index fca9274b797c8..555cffde4134f 100644 --- a/ports/nrf/boards/feather52/mpconfigboard.h +++ b/ports/nrf/boards/feather52/mpconfigboard.h @@ -24,8 +24,6 @@ * THE SOFTWARE. */ -#define PCA10040 - #define MICROPY_HW_BOARD_NAME "Bluefruit nRF52 Feather" #define MICROPY_HW_MCU_NAME "NRF52832" #define MICROPY_PY_SYS_PLATFORM "nrf52" @@ -33,7 +31,7 @@ #define MICROPY_PY_MACHINE_HW_PWM (1) #define MICROPY_PY_MACHINE_HW_SPI (1) #define MICROPY_PY_MACHINE_TIMER (1) -#define MICROPY_PY_MACHINE_RTC (1) +#define MICROPY_PY_MACHINE_RTC (0) #define MICROPY_PY_MACHINE_I2C (1) #define MICROPY_PY_MACHINE_ADC (1) #define MICROPY_PY_MACHINE_TEMP (1) @@ -59,18 +57,23 @@ #define MICROPY_HW_LED2 (19) // LED2 // UART config -#define MICROPY_HW_UART1_RX (pin_A8) -#define MICROPY_HW_UART1_TX (pin_A6) +#define MICROPY_HW_UART1_RX (pin_PA08) +#define MICROPY_HW_UART1_TX (pin_PA06) #define MICROPY_HW_UART1_HWFC (0) // SPI0 config #define MICROPY_HW_SPI0_NAME "SPI0" -#define MICROPY_HW_SPI0_SCK (pin_A12) // (Arduino D13) -#define MICROPY_HW_SPI0_MOSI (pin_A13) // (Arduino D11) -#define MICROPY_HW_SPI0_MISO (pin_A14) // (Arduino D12) +#define MICROPY_HW_SPI0_SCK (pin_PA12) // (Arduino D13) +#define MICROPY_HW_SPI0_MOSI (pin_PA13) // (Arduino D11) +#define MICROPY_HW_SPI0_MISO (pin_PA14) // (Arduino D12) #define MICROPY_HW_PWM0_NAME "PWM0" #define MICROPY_HW_PWM1_NAME "PWM1" #define MICROPY_HW_PWM2_NAME "PWM2" #define HELP_TEXT_BOARD_LED "1,2" + + + +#define PORT_HEAP_SIZE (32*1024) +#define CIRCUITPY_AUTORELOAD_DELAY_MS 500 diff --git a/ports/nrf/boards/feather52/mpconfigboard.mk b/ports/nrf/boards/feather52/mpconfigboard.mk index 30f64ca43c8a7..089189e9f59ba 100644 --- a/ports/nrf/boards/feather52/mpconfigboard.mk +++ b/ports/nrf/boards/feather52/mpconfigboard.mk @@ -8,7 +8,7 @@ BOOTLOADER_PKG = boards/feather52/bootloader/feather52_bootloader_$(SOFTDEV_VERS NRF_DEFINES += -DNRF52832_XXAA - +CFLAGS += -DADAFRUIT_FEATHER52 check_defined = \ $(strip $(foreach 1,$1, \ diff --git a/ports/nrf/boards/feather52/pins.c b/ports/nrf/boards/feather52/pins.c new file mode 100644 index 0000000000000..e8c006802fccf --- /dev/null +++ b/ports/nrf/boards/feather52/pins.c @@ -0,0 +1,124 @@ +// This file was automatically generated by make-pins.py +// +// --af nrf52_af.csv +// --board boards/feather52/pins.csv +// --prefix boards/nrf52_prefix.c + +// nrf52_prefix.c becomes the initial portion of the generated pins file. + +#include + +#include "py/obj.h" +#include "py/mphal.h" +#include "pin.h" + +#define AF(af_idx, af_fn, af_unit, af_type, af_ptr) \ +{ \ + { &pin_af_type }, \ + .name = MP_QSTR_AF ## af_idx ## _ ## af_fn ## af_unit, \ + .idx = (af_idx), \ + .fn = AF_FN_ ## af_fn, \ + .unit = (af_unit), \ + .type = AF_PIN_TYPE_ ## af_fn ## _ ## af_type, \ + .af_fn = (af_ptr) \ +} + +#define PIN(p_port, p_pin, p_af, p_adc_channel) \ +{ \ + { &mcu_pin_type }, \ + .name = MP_QSTR_ ## p_port ## p_pin, \ + .port = PORT_ ## p_port, \ + .pin = (p_pin), \ + .num_af = (sizeof(p_af) / sizeof(pin_af_obj_t)), \ + /*.pin_mask = (1 << p_pin), */\ + .af = p_af, \ + .adc_channel = p_adc_channel,\ +} + +#define NO_ADC 0 + +const pin_obj_t pin_PA02 = PIN(A, 2, NULL, SAADC_CH_PSELP_PSELP_AnalogInput0); +const pin_obj_t pin_PA03 = PIN(A, 3, NULL, SAADC_CH_PSELP_PSELP_AnalogInput1); +const pin_obj_t pin_PA04 = PIN(A, 4, NULL, SAADC_CH_PSELP_PSELP_AnalogInput2); +const pin_obj_t pin_PA05 = PIN(A, 5, NULL, SAADC_CH_PSELP_PSELP_AnalogInput3); +const pin_obj_t pin_PA06 = PIN(A, 6, NULL, NO_ADC); +const pin_obj_t pin_PA07 = PIN(A, 7, NULL, NO_ADC); +const pin_obj_t pin_PA08 = PIN(A, 8, NULL, NO_ADC); +const pin_obj_t pin_PA09 = PIN(A, 9, NULL, NO_ADC); +const pin_obj_t pin_PA10 = PIN(A, 10, NULL, NO_ADC); +const pin_obj_t pin_PA11 = PIN(A, 11, NULL, NO_ADC); +const pin_obj_t pin_PA12 = PIN(A, 12, NULL, NO_ADC); +const pin_obj_t pin_PA13 = PIN(A, 13, NULL, NO_ADC); +const pin_obj_t pin_PA14 = PIN(A, 14, NULL, NO_ADC); +const pin_obj_t pin_PA15 = PIN(A, 15, NULL, NO_ADC); +const pin_obj_t pin_PA16 = PIN(A, 16, NULL, NO_ADC); +const pin_obj_t pin_PA17 = PIN(A, 17, NULL, NO_ADC); + +const pin_obj_t pin_PA19 = PIN(A, 19, NULL, NO_ADC); +const pin_obj_t pin_PA20 = PIN(A, 20, NULL, NO_ADC); + +const pin_obj_t pin_PA25 = PIN(A, 25, NULL, NO_ADC); +const pin_obj_t pin_PA26 = PIN(A, 26, NULL, NO_ADC); +const pin_obj_t pin_PA27 = PIN(A, 27, NULL, NO_ADC); +const pin_obj_t pin_PA28 = PIN(A, 28, NULL, SAADC_CH_PSELP_PSELP_AnalogInput4); +const pin_obj_t pin_PA29 = PIN(A, 29, NULL, SAADC_CH_PSELP_PSELP_AnalogInput5); +const pin_obj_t pin_PA30 = PIN(A, 30, NULL, SAADC_CH_PSELP_PSELP_AnalogInput6); +const pin_obj_t pin_PA31 = PIN(A, 31, NULL, SAADC_CH_PSELP_PSELP_AnalogInput7); + +STATIC const mp_rom_map_elem_t mcu_pin_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR_PA02), MP_ROM_PTR(&pin_PA02) }, + { MP_ROM_QSTR(MP_QSTR_PA03), MP_ROM_PTR(&pin_PA03) }, + { MP_ROM_QSTR(MP_QSTR_PA04), MP_ROM_PTR(&pin_PA04) }, + { MP_ROM_QSTR(MP_QSTR_PA05), MP_ROM_PTR(&pin_PA05) }, + { MP_ROM_QSTR(MP_QSTR_PA06), MP_ROM_PTR(&pin_PA06) }, + { MP_ROM_QSTR(MP_QSTR_PA07), MP_ROM_PTR(&pin_PA07) }, + { MP_ROM_QSTR(MP_QSTR_PA08), MP_ROM_PTR(&pin_PA08) }, + { MP_ROM_QSTR(MP_QSTR_PA09), MP_ROM_PTR(&pin_PA09) }, + { MP_ROM_QSTR(MP_QSTR_PA10), MP_ROM_PTR(&pin_PA10) }, + { MP_ROM_QSTR(MP_QSTR_PA11), MP_ROM_PTR(&pin_PA11) }, + { MP_ROM_QSTR(MP_QSTR_PA12), MP_ROM_PTR(&pin_PA12) }, + { MP_ROM_QSTR(MP_QSTR_PA13), MP_ROM_PTR(&pin_PA13) }, + { MP_ROM_QSTR(MP_QSTR_PA14), MP_ROM_PTR(&pin_PA14) }, + { MP_ROM_QSTR(MP_QSTR_PA15), MP_ROM_PTR(&pin_PA15) }, + { MP_ROM_QSTR(MP_QSTR_PA16), MP_ROM_PTR(&pin_PA16) }, + { MP_ROM_QSTR(MP_QSTR_PA17), MP_ROM_PTR(&pin_PA17) }, + { MP_ROM_QSTR(MP_QSTR_PA19), MP_ROM_PTR(&pin_PA19) }, + { MP_ROM_QSTR(MP_QSTR_PA20), MP_ROM_PTR(&pin_PA20) }, + { MP_ROM_QSTR(MP_QSTR_PA25), MP_ROM_PTR(&pin_PA25) }, + { MP_ROM_QSTR(MP_QSTR_PA26), MP_ROM_PTR(&pin_PA26) }, + { MP_ROM_QSTR(MP_QSTR_PA27), MP_ROM_PTR(&pin_PA27) }, + { MP_ROM_QSTR(MP_QSTR_PA28), MP_ROM_PTR(&pin_PA28) }, + { MP_ROM_QSTR(MP_QSTR_PA29), MP_ROM_PTR(&pin_PA29) }, + { MP_ROM_QSTR(MP_QSTR_PA30), MP_ROM_PTR(&pin_PA30) }, + { MP_ROM_QSTR(MP_QSTR_PA31), MP_ROM_PTR(&pin_PA31) }, +}; +MP_DEFINE_CONST_DICT(mcu_pin_globals, mcu_pin_globals_table); + +STATIC const mp_rom_map_elem_t board_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR_A0 ), MP_ROM_PTR(&pin_PA02) }, + { MP_ROM_QSTR(MP_QSTR_A1 ), MP_ROM_PTR(&pin_PA03) }, + { MP_ROM_QSTR(MP_QSTR_A2 ), MP_ROM_PTR(&pin_PA04) }, + { MP_ROM_QSTR(MP_QSTR_A3 ), MP_ROM_PTR(&pin_PA05) }, + { MP_ROM_QSTR(MP_QSTR_TX ), MP_ROM_PTR(&pin_PA06) }, + { MP_ROM_QSTR(MP_QSTR_A7 ), MP_ROM_PTR(&pin_PA07) }, + { MP_ROM_QSTR(MP_QSTR_RX ), MP_ROM_PTR(&pin_PA08) }, + { MP_ROM_QSTR(MP_QSTR_NFC1 ), MP_ROM_PTR(&pin_PA09) }, + { MP_ROM_QSTR(MP_QSTR_NFC2 ), MP_ROM_PTR(&pin_PA10) }, + { MP_ROM_QSTR(MP_QSTR_D11 ), MP_ROM_PTR(&pin_PA11) }, + { MP_ROM_QSTR(MP_QSTR_SCK ), MP_ROM_PTR(&pin_PA12) }, + { MP_ROM_QSTR(MP_QSTR_MOSI ), MP_ROM_PTR(&pin_PA13) }, + { MP_ROM_QSTR(MP_QSTR_MISO ), MP_ROM_PTR(&pin_PA14) }, + { MP_ROM_QSTR(MP_QSTR_D15 ), MP_ROM_PTR(&pin_PA15) }, + { MP_ROM_QSTR(MP_QSTR_D16 ), MP_ROM_PTR(&pin_PA16) }, + { MP_ROM_QSTR(MP_QSTR_LED1 ), MP_ROM_PTR(&pin_PA17) }, + { MP_ROM_QSTR(MP_QSTR_LED2 ), MP_ROM_PTR(&pin_PA19) }, + { MP_ROM_QSTR(MP_QSTR_DFU ), MP_ROM_PTR(&pin_PA20) }, + { MP_ROM_QSTR(MP_QSTR_SDA ), MP_ROM_PTR(&pin_PA25) }, + { MP_ROM_QSTR(MP_QSTR_SCL ), MP_ROM_PTR(&pin_PA26) }, + { MP_ROM_QSTR(MP_QSTR_D27 ), MP_ROM_PTR(&pin_PA27) }, + { MP_ROM_QSTR(MP_QSTR_A4 ), MP_ROM_PTR(&pin_PA28) }, + { MP_ROM_QSTR(MP_QSTR_A5 ), MP_ROM_PTR(&pin_PA29) }, + { MP_ROM_QSTR(MP_QSTR_A6 ), MP_ROM_PTR(&pin_PA30) }, + { MP_ROM_QSTR(MP_QSTR_A7 ), MP_ROM_PTR(&pin_PA31) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/nrf/boards/feather52/pins.csv b/ports/nrf/boards/feather52/pins.csv index b7017602a75f7..8997ec559ac88 100644 --- a/ports/nrf/boards/feather52/pins.csv +++ b/ports/nrf/boards/feather52/pins.csv @@ -1,25 +1,25 @@ -PA2,PA2,ADC0_IN0 -PA3,PA3,ADC0_IN1 -PA4,PA4,ADC0_IN2 -PA5,PA5,ADC0_IN3 -UART_TX,PA6 +A0,PA2,ADC0_IN0 +A1,PA3,ADC0_IN1 +A2,PA4,ADC0_IN2 +A3,PA5,ADC0_IN3 +TX,PA6 PA7,PA7 -UART_RX,PA8 +RX,PA8 NFC1,PA9 NFC2,PA10 -PA11,PA11 -SPI_SCK,PA12 -SPI_MOSI,PA13 -SPI_MISO,PA14 -PA15,PA15 -PA16,PA16 +D11,PA11 +SCK,PA12 +MOSI,PA13 +MISO,PA14 +D15,PA15 +D16,PA16 LED1,PA17 LED2,PA19 -PA20,PA20 -I2C_SDA,PA25 -I2C_SCL,PA26 -PA27,PA27 -PA28,PA28,ADC0_IN4 -PA29,PA29,ADC0_IN5 -PA30,PA30,ADC0_IN6 -PA31,PA31,ADC0_IN7 +DFU,PA20 +SDA,PA25 +SCL,PA26 +D27,PA27 +A4,PA28,ADC0_IN4 +A5,PA29,ADC0_IN5 +A6,PA30,ADC0_IN6 +A7,PA31,ADC0_IN7 diff --git a/ports/nrf/boards/feather52/pins.h b/ports/nrf/boards/feather52/pins.h new file mode 100644 index 0000000000000..6ad86fa285500 --- /dev/null +++ b/ports/nrf/boards/feather52/pins.h @@ -0,0 +1,28 @@ +extern const pin_obj_t pin_PA02; +extern const pin_obj_t pin_PA03; +extern const pin_obj_t pin_PA04; +extern const pin_obj_t pin_PA05; +extern const pin_obj_t pin_PA06; +extern const pin_obj_t pin_PA07; +extern const pin_obj_t pin_PA08; +extern const pin_obj_t pin_PA09; +extern const pin_obj_t pin_PA10; +extern const pin_obj_t pin_PA11; +extern const pin_obj_t pin_PA12; +extern const pin_obj_t pin_PA13; +extern const pin_obj_t pin_PA14; +extern const pin_obj_t pin_PA15; +extern const pin_obj_t pin_PA16; +extern const pin_obj_t pin_PA17; +extern const pin_obj_t pin_PA19; +extern const pin_obj_t pin_PA20; +extern const pin_obj_t pin_PA25; +extern const pin_obj_t pin_PA26; +extern const pin_obj_t pin_PA27; +extern const pin_obj_t pin_PA28; +extern const pin_obj_t pin_PA29; +extern const pin_obj_t pin_PA30; +extern const pin_obj_t pin_PA31; +extern const pin_obj_t * const pin_PAdc1[]; +extern const pin_obj_t * const pin_PAdc2[]; +extern const pin_obj_t * const pin_PAdc3[]; diff --git a/ports/nrf/boards/make-pins.py b/ports/nrf/boards/make-pins.py index 733bd8c33cda3..1edd2f99a9d61 100644 --- a/ports/nrf/boards/make-pins.py +++ b/ports/nrf/boards/make-pins.py @@ -233,22 +233,22 @@ def parse_board_file(self, filename): self.board_pins.append(NamedPin(row[0], pin)) def print_named(self, label, named_pins): - print('STATIC const mp_rom_map_elem_t pin_{:s}_pins_locals_dict_table[] = {{'.format(label)) + print('STATIC const mp_rom_map_elem_t {:s}_table[] = {{'.format(label)) for named_pin in named_pins: pin = named_pin.pin() if pin.is_board_pin(): print(' {{ MP_ROM_QSTR(MP_QSTR_{:s}), MP_ROM_PTR(&pin_{:s}) }},'.format(named_pin.name(), pin.cpu_pin_name())) print('};') - print('MP_DEFINE_CONST_DICT(pin_{:s}_pins_locals_dict, pin_{:s}_pins_locals_dict_table);'.format(label, label)); + print('MP_DEFINE_CONST_DICT({:s}, {:s}_table);'.format(label, label)); def print(self): for named_pin in self.cpu_pins: pin = named_pin.pin() if pin.is_board_pin(): pin.print() - self.print_named('cpu', self.cpu_pins) + self.print_named('mcu_pin_globals', self.cpu_pins) print('') - self.print_named('board', self.board_pins) + self.print_named('board_module_globals', self.board_pins) def print_adc(self, adc_num): print(''); diff --git a/ports/nrf/boards/microbit/mpconfigboard.h b/ports/nrf/boards/microbit/mpconfigboard.h index 6dc8b0597f054..61c24d642d4dc 100644 --- a/ports/nrf/boards/microbit/mpconfigboard.h +++ b/ports/nrf/boards/microbit/mpconfigboard.h @@ -35,7 +35,7 @@ #define MICROPY_PY_MACHINE_HW_SPI (1) #define MICROPY_PY_MACHINE_TIMER (1) #define MICROPY_PY_MACHINE_RTC (1) -#define MICROPY_PY_MACHINE_I2C (1) +#define MICROPY_PY_MACHINE_I2C (0) #define MICROPY_PY_MACHINE_ADC (1) #define MICROPY_PY_MACHINE_TEMP (1) diff --git a/ports/nrf/boards/nrf52_prefix.c b/ports/nrf/boards/nrf52_prefix.c index 89e5df5b105e8..f408bdcf458db 100644 --- a/ports/nrf/boards/nrf52_prefix.c +++ b/ports/nrf/boards/nrf52_prefix.c @@ -19,7 +19,7 @@ #define PIN(p_port, p_pin, p_af, p_adc_num, p_adc_channel) \ { \ - { &pin_type }, \ + { &mcu_pin_type }, \ .name = MP_QSTR_ ## p_port ## p_pin, \ .port = PORT_ ## p_port, \ .pin = (p_pin), \ diff --git a/ports/nrf/common-hal/analogio/AnalogIn.c b/ports/nrf/common-hal/analogio/AnalogIn.c new file mode 100644 index 0000000000000..9923e62f5b2a4 --- /dev/null +++ b/ports/nrf/common-hal/analogio/AnalogIn.c @@ -0,0 +1,118 @@ +/* + * 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 "common-hal/analogio/AnalogIn.h" + +#include + +#include "py/gc.h" +#include "py/nlr.h" +#include "py/runtime.h" +#include "py/binary.h" +#include "py/mphal.h" +#include "shared-bindings/analogio/AnalogIn.h" +#include "nrf.h" + +void common_hal_analogio_analogin_construct(analogio_analogin_obj_t* self, const mcu_pin_obj_t *pin) { + if (!pin->adc_channel) { + // No ADC function on that pin + mp_raise_ValueError("Pin does not have ADC capabilities"); + } + + hal_gpio_cfg_pin(pin->port, pin->pin, HAL_GPIO_MODE_INPUT, HAL_GPIO_PULL_DISABLED); + self->pin = pin; +} + +bool common_hal_analogio_analogin_deinited(analogio_analogin_obj_t *self) { + return self->pin == mp_const_none; +} + +void common_hal_analogio_analogin_deinit(analogio_analogin_obj_t *self) { + if (common_hal_analogio_analogin_deinited(self)) { + return; + } + reset_pin(self->pin->pin); + self->pin = mp_const_none; +} + +void analogin_reset() { +} + +uint16_t common_hal_analogio_analogin_get_value(analogio_analogin_obj_t *self) { + // Something else might have used the ADC in a different way, + // so we completely re-initialize it. + + int16_t value; + + NRF_SAADC->RESOLUTION = SAADC_RESOLUTION_VAL_14bit; + NRF_SAADC->ENABLE = 1; + + for (int i = 0; i < 8; i++) { + NRF_SAADC->CH[i].PSELN = SAADC_CH_PSELP_PSELP_NC; + NRF_SAADC->CH[i].PSELP = SAADC_CH_PSELP_PSELP_NC; + } + + NRF_SAADC->CH[0].CONFIG = ((SAADC_CH_CONFIG_RESP_Bypass << SAADC_CH_CONFIG_RESP_Pos) & SAADC_CH_CONFIG_RESP_Msk) + | ((SAADC_CH_CONFIG_RESP_Bypass << SAADC_CH_CONFIG_RESN_Pos) & SAADC_CH_CONFIG_RESN_Msk) + | ((SAADC_CH_CONFIG_GAIN_Gain1_6 << SAADC_CH_CONFIG_GAIN_Pos) & SAADC_CH_CONFIG_GAIN_Msk) + | ((SAADC_CH_CONFIG_REFSEL_Internal << SAADC_CH_CONFIG_REFSEL_Pos) & SAADC_CH_CONFIG_REFSEL_Msk) + | ((SAADC_CH_CONFIG_TACQ_3us << SAADC_CH_CONFIG_TACQ_Pos) & SAADC_CH_CONFIG_TACQ_Msk) + | ((SAADC_CH_CONFIG_MODE_SE << SAADC_CH_CONFIG_MODE_Pos) & SAADC_CH_CONFIG_MODE_Msk); + NRF_SAADC->CH[0].PSELN = self->pin->adc_channel; + NRF_SAADC->CH[0].PSELP = self->pin->adc_channel; + + + NRF_SAADC->RESULT.PTR = (uint32_t)&value; + NRF_SAADC->RESULT.MAXCNT = 1; + + NRF_SAADC->TASKS_START = 0x01UL; + + while (!NRF_SAADC->EVENTS_STARTED); + NRF_SAADC->EVENTS_STARTED = 0x00UL; + + NRF_SAADC->TASKS_SAMPLE = 0x01UL; + + while (!NRF_SAADC->EVENTS_END); + NRF_SAADC->EVENTS_END = 0x00UL; + + NRF_SAADC->TASKS_STOP = 0x01UL; + + while (!NRF_SAADC->EVENTS_STOPPED); + NRF_SAADC->EVENTS_STOPPED = 0x00UL; + + if (value < 0) { + value = 0; + } + + NRF_SAADC->ENABLE = 0; + + // Map value to from 14 to 16 bits + return (value << 2); +} + +float common_hal_analogio_analogin_get_reference_voltage(analogio_analogin_obj_t *self) { + return 3.3f; +} diff --git a/ports/nrf/common-hal/analogio/AnalogIn.h b/ports/nrf/common-hal/analogio/AnalogIn.h new file mode 100644 index 0000000000000..95f599e7115d2 --- /dev/null +++ b/ports/nrf/common-hal/analogio/AnalogIn.h @@ -0,0 +1,41 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Scott Shawcroft + * + * 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_COMMON_HAL_ANALOGIO_ANALOGIN_H +#define MICROPY_INCLUDED_NRF_COMMON_HAL_ANALOGIO_ANALOGIN_H + +#include "common-hal/microcontroller/Pin.h" + +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; + const mcu_pin_obj_t * pin; +} analogio_analogin_obj_t; + +void analogin_reset(void); + +#endif // MICROPY_INCLUDED_NRF_COMMON_HAL_ANALOGIO_ANALOGIN_H diff --git a/ports/nrf/common-hal/analogio/AnalogOut.c b/ports/nrf/common-hal/analogio/AnalogOut.c new file mode 100644 index 0000000000000..87cb82ffc334a --- /dev/null +++ b/ports/nrf/common-hal/analogio/AnalogOut.c @@ -0,0 +1,76 @@ +/* + * 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. + */ + +#include +#include + +#include "py/mperrno.h" +#include "py/runtime.h" + +#include "shared-bindings/analogio/AnalogOut.h" + + +void common_hal_analogio_analogout_construct(analogio_analogout_obj_t* self, const mcu_pin_obj_t *pin) { +// if (pin->pin != PIN_PA02) { +// mp_raise_ValueError("AnalogOut not supported on given pin"); +// return; +// } +// struct dac_config config_dac; +// dac_get_config_defaults(&config_dac); +// config_dac.reference = DAC_REFERENCE_AVCC; +// enum status_code status = dac_init(&self->dac_instance, DAC, &config_dac); +// if (status != STATUS_OK) { +// mp_raise_OSError(MP_EIO); +// return; +// } +// claim_pin(pin); +// +// struct dac_chan_config config_analogout_chan; +// dac_chan_get_config_defaults(&config_analogout_chan); +// dac_chan_set_config(&self->dac_instance, DAC_CHANNEL_0, &config_analogout_chan); +// dac_chan_enable(&self->dac_instance, DAC_CHANNEL_0); +// +// dac_enable(&self->dac_instance); +} + +bool common_hal_analogio_analogout_deinited(analogio_analogout_obj_t *self) { + return self->deinited; +} + +void common_hal_analogio_analogout_deinit(analogio_analogout_obj_t *self) { +// if (common_hal_analogio_analogout_deinited(self)) { +// return; +// } +// dac_disable(&self->dac_instance); +// dac_chan_disable(&self->dac_instance, DAC_CHANNEL_0); +// reset_pin(PIN_PA02); +// self->deinited = true; +} + +void common_hal_analogio_analogout_set_value(analogio_analogout_obj_t *self, uint16_t value) { + // Input is 16 bit but we only support 10 bit so we shift the input. +// dac_chan_write(&self->dac_instance, DAC_CHANNEL_0, value >> 6); +} diff --git a/ports/nrf/common-hal/analogio/AnalogOut.h b/ports/nrf/common-hal/analogio/AnalogOut.h new file mode 100644 index 0000000000000..d47412b40edb3 --- /dev/null +++ b/ports/nrf/common-hal/analogio/AnalogOut.h @@ -0,0 +1,42 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Scott Shawcroft + * + * 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_COMMON_HAL_ANALOGIO_ANALOGOUT_H +#define MICROPY_INCLUDED_NRF_COMMON_HAL_ANALOGIO_ANALOGOUT_H + +#include "common-hal/microcontroller/Pin.h" + +//#include "asf/sam0/drivers/dac/dac.h" + +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; +// struct dac_module dac_instance; + bool deinited; +} analogio_analogout_obj_t; + +#endif // MICROPY_INCLUDED_NRF_COMMON_HAL_ANALOGIO_ANALOGOUT_H diff --git a/ports/nrf/common-hal/analogio/__init__.c b/ports/nrf/common-hal/analogio/__init__.c new file mode 100644 index 0000000000000..eea58c77d6315 --- /dev/null +++ b/ports/nrf/common-hal/analogio/__init__.c @@ -0,0 +1 @@ +// No analogio module functions. diff --git a/ports/nrf/common-hal/board/__init__.c b/ports/nrf/common-hal/board/__init__.c new file mode 100644 index 0000000000000..634760335e4f0 --- /dev/null +++ b/ports/nrf/common-hal/board/__init__.c @@ -0,0 +1,34 @@ +/* + * 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. + */ + +#include + +#include "py/runtime.h" +#include "py/mphal.h" +#include "common-hal/microcontroller/Pin.h" + +// Pins aren't actually defined here. They are in the board specific directory +// such as boards/arduino_zero/pins.c. diff --git a/ports/nrf/common-hal/busio/I2C.c b/ports/nrf/common-hal/busio/I2C.c new file mode 100644 index 0000000000000..07b067a2cb1b3 --- /dev/null +++ b/ports/nrf/common-hal/busio/I2C.c @@ -0,0 +1,207 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Sandeep Mistry All right reserved. + * Copyright (c) 2017 hathach + * + * 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 "py/mperrno.h" +#include "py/runtime.h" + +#include "pins.h" +#include "nrf.h" + +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) { + if (scl->pin == sda->pin) { + mp_raise_ValueError("Invalid pins"); + } + + NRF_GPIO->PIN_CNF[scl->pin] = ((uint32_t)GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos) + | ((uint32_t)GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos) + | ((uint32_t)GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos) + | ((uint32_t)GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos) + | ((uint32_t)GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos); + + NRF_GPIO->PIN_CNF[sda->pin] = ((uint32_t)GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos) + | ((uint32_t)GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos) + | ((uint32_t)GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos) + | ((uint32_t)GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos) + | ((uint32_t)GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos); + + // 1 for I2C, 0 for SPI + self->twi = NRF_TWIM1; + + if ( frequency < 100000 ) { + self->twi->FREQUENCY = TWIM_FREQUENCY_FREQUENCY_K100; + }else if ( frequency < 250000 ) { + self->twi->FREQUENCY = TWIM_FREQUENCY_FREQUENCY_K250; + }else { + self->twi->FREQUENCY = TWIM_FREQUENCY_FREQUENCY_K400; + } + + self->twi->ENABLE = (TWIM_ENABLE_ENABLE_Enabled << TWIM_ENABLE_ENABLE_Pos); + + self->twi->PSEL.SCL = scl->pin; + self->twi->PSEL.SDA = sda->pin; + +} + +bool common_hal_busio_i2c_deinited(busio_i2c_obj_t *self) { + return self->twi->ENABLE == 0; +} + +void common_hal_busio_i2c_deinit(busio_i2c_obj_t *self) { + if (common_hal_busio_i2c_deinited(self)) { + return; + } + + uint8_t scl_pin = self->twi->PSEL.SCL; + uint8_t sda_pin = self->twi->PSEL.SDA; + + self->twi->ENABLE = (TWIM_ENABLE_ENABLE_Disabled << TWIM_ENABLE_ENABLE_Pos); + self->twi->PSEL.SCL = (TWIM_PSEL_SCL_CONNECT_Disconnected << TWIM_PSEL_SCL_CONNECT_Pos); + self->twi->PSEL.SDA = (TWIM_PSEL_SDA_CONNECT_Disconnected << TWIM_PSEL_SDA_CONNECT_Pos); + + reset_pin(scl_pin); + reset_pin(sda_pin); +} + +bool common_hal_busio_i2c_probe(busio_i2c_obj_t *self, uint8_t addr) { + // Write no data when just probing + return 0 == common_hal_busio_i2c_write(self, addr, NULL, 0, true); +} + +bool common_hal_busio_i2c_try_lock(busio_i2c_obj_t *self) { + bool grabbed_lock = false; +// CRITICAL_SECTION_ENTER() + if (!self->has_lock) { + grabbed_lock = true; + self->has_lock = true; + } +// CRITICAL_SECTION_LEAVE(); + return grabbed_lock; +} + +bool common_hal_busio_i2c_has_lock(busio_i2c_obj_t *self) { + return self->has_lock; +} + +void common_hal_busio_i2c_unlock(busio_i2c_obj_t *self) { + self->has_lock = false; +} + +uint8_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len, bool stopBit) { + NRF_TWIM_Type* twi = self->twi; + + twi->ADDRESS = addr; + twi->TASKS_RESUME = 1; + + twi->TXD.PTR = (uint32_t) data; + twi->TXD.MAXCNT = len; + + twi->TASKS_STARTTX = 1; + + // Wait for TX started + while(!twi->EVENTS_TXSTARTED && !twi->EVENTS_ERROR) {} + twi->EVENTS_TXSTARTED = 0; + + // Wait for TX complete + if ( len ) + { + while(!twi->EVENTS_LASTTX && !twi->EVENTS_ERROR) {} + twi->EVENTS_LASTTX = 0x0UL; + } + + if (stopBit || twi->EVENTS_ERROR) + { + twi->TASKS_STOP = 0x1UL; + while(!twi->EVENTS_STOPPED); + twi->EVENTS_STOPPED = 0x0UL; + } + else + { + twi->TASKS_SUSPEND = 0x1UL; + while(!twi->EVENTS_SUSPENDED); + twi->EVENTS_SUSPENDED = 0x0UL; + } + + if (twi->EVENTS_ERROR) + { + twi->EVENTS_ERROR = 0x0UL; + uint32_t error = twi->ERRORSRC; + twi->ERRORSRC = error; + + return error; + } + + return 0; +} + +uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *data, size_t len) { + NRF_TWIM_Type* twi = self->twi; + + if(len == 0) return 0; + bool stopBit = true; // should be a parameter + + twi->ADDRESS = addr; + twi->TASKS_RESUME = 0x1UL; + + twi->RXD.PTR = (uint32_t) data; + twi->RXD.MAXCNT = len; + + twi->TASKS_STARTRX = 0x1UL; + + while(!twi->EVENTS_RXSTARTED && !twi->EVENTS_ERROR); + twi->EVENTS_RXSTARTED = 0x0UL; + + while(!twi->EVENTS_LASTRX && !twi->EVENTS_ERROR); + twi->EVENTS_LASTRX = 0x0UL; + + if (stopBit || twi->EVENTS_ERROR) + { + twi->TASKS_STOP = 0x1UL; + while(!twi->EVENTS_STOPPED); + twi->EVENTS_STOPPED = 0x0UL; + } + else + { + twi->TASKS_SUSPEND = 0x1UL; + while(!twi->EVENTS_SUSPENDED); + twi->EVENTS_SUSPENDED = 0x0UL; + } + + if (twi->EVENTS_ERROR) + { + twi->EVENTS_ERROR = 0x0UL; + uint32_t error = twi->ERRORSRC; + twi->ERRORSRC = error; + + return error; + } + + // number of byte read +// (void) _p_twim->RXD.AMOUNT; + + return 0; +} diff --git a/ports/nrf/common-hal/busio/I2C.h b/ports/nrf/common-hal/busio/I2C.h new file mode 100644 index 0000000000000..899b9d5aa9480 --- /dev/null +++ b/ports/nrf/common-hal/busio/I2C.h @@ -0,0 +1,42 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Scott Shawcroft + * + * 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_COMMON_HAL_BUSIO_I2C_H +#define MICROPY_INCLUDED_NRF_COMMON_HAL_BUSIO_I2C_H + +#include "common-hal/microcontroller/Pin.h" + +//#include "hal/include/hal_i2c_m_sync.h" + +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; + volatile bool has_lock; + NRF_TWIM_Type* twi; +} 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 new file mode 100644 index 0000000000000..3d8fa7ad33d88 --- /dev/null +++ b/ports/nrf/common-hal/busio/SPI.c @@ -0,0 +1,162 @@ +/* + * SPI Master library for nRF5x. + * Copyright (c) 2015 Arduino LLC + * Copyright (c) 2016 Sandeep Mistry All right reserved. + * Copyright (c) 2017 hathach + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +#include "shared-bindings/busio/SPI.h" +#include "py/mperrno.h" +#include "py/runtime.h" + +#include "nrf.h" +#include "pins.h" + +// Convert frequency to clock-speed-dependent value. Return 0 if out of range. +static uint32_t baudrate_to_reg(const uint32_t baudrate) { + uint32_t value; + + if (baudrate <= 125000) { + value = SPI_FREQUENCY_FREQUENCY_K125; + } else if (baudrate <= 250000) { + value = SPI_FREQUENCY_FREQUENCY_K250; + } else if (baudrate <= 500000) { + value = SPI_FREQUENCY_FREQUENCY_K500; + } else if (baudrate <= 1000000) { + value = SPI_FREQUENCY_FREQUENCY_M1; + } else if (baudrate <= 2000000) { + value = SPI_FREQUENCY_FREQUENCY_M2; + } else if (baudrate <= 4000000) { + value = SPI_FREQUENCY_FREQUENCY_M4; + } else { + value = SPI_FREQUENCY_FREQUENCY_M8; + } + + return value; +} + +void common_hal_busio_spi_construct(busio_spi_obj_t *self, const mcu_pin_obj_t * clock, const mcu_pin_obj_t * mosi, const mcu_pin_obj_t * miso) { + + // 1 for I2C, 0 for SPI + self->spi = NRF_SPI0; + + self->spi->PSELSCK = clock->pin; + self->spi->PSELMOSI = mosi->pin; + self->spi->PSELMISO = miso->pin; +} + +bool common_hal_busio_spi_deinited(busio_spi_obj_t *self) { + return self->spi == NULL; +} + +void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { + if (common_hal_busio_spi_deinited(self)) { + return; + } + + self->spi->PSELSCK = SPI_PSEL_SCK_PSELSCK_Disconnected; + self->spi->PSELMOSI = SPI_PSEL_MOSI_PSELMOSI_Disconnected; + self->spi->PSELMISO = SPI_PSEL_MISO_PSELMISO_Disconnected; + +// reset_pin(self->clock_pin); +// reset_pin(self->MOSI_pin); +// reset_pin(self->MISO_pin); + + self->spi = NULL; +} + +bool common_hal_busio_spi_configure(busio_spi_obj_t *self, uint32_t baudrate, uint8_t polarity, uint8_t phase, uint8_t bits) { + // nrf52 does not support 16 bit + if ( bits != 8 ) return false; + + self->spi->ENABLE = (SPI_ENABLE_ENABLE_Disabled << SPI_ENABLE_ENABLE_Pos); + + uint32_t config = (SPI_CONFIG_ORDER_MsbFirst << SPI_CONFIG_ORDER_Pos); + + config |= ((polarity ? SPI_CONFIG_CPOL_ActiveLow : SPI_CONFIG_CPOL_ActiveHigh) << SPI_CONFIG_CPOL_Pos); + config |= ((phase ? SPI_CONFIG_CPHA_Trailing : SPI_CONFIG_CPHA_Leading ) << SPI_CONFIG_CPHA_Pos); + + self->spi->CONFIG = config; + self->spi->FREQUENCY = baudrate_to_reg(baudrate); + + self->spi->ENABLE = (SPI_ENABLE_ENABLE_Enabled << SPI_ENABLE_ENABLE_Pos); + + return true; +} + +bool common_hal_busio_spi_try_lock(busio_spi_obj_t *self) { + bool grabbed_lock = false; +// CRITICAL_SECTION_ENTER() +// if (!self->has_lock) { + grabbed_lock = true; + self->has_lock = true; +// } +// CRITICAL_SECTION_LEAVE(); + return grabbed_lock; +} + +bool common_hal_busio_spi_has_lock(busio_spi_obj_t *self) { + return self->has_lock; +} + +void common_hal_busio_spi_unlock(busio_spi_obj_t *self) { + self->has_lock = false; +} + +bool common_hal_busio_spi_write(busio_spi_obj_t *self, const uint8_t *data, size_t len) { + if (len == 0) { + return true; + } + + while (len) + { + self->spi->TXD = *data; + + while(!self->spi->EVENTS_READY); + + (void) self->spi->RXD; + data++; + len--; + + self->spi->EVENTS_READY = 0x0UL; + } + + return true; +} + +bool common_hal_busio_spi_read(busio_spi_obj_t *self, uint8_t *data, size_t len, uint8_t write_value) { + if (len == 0) { + return true; + } + + while (len) + { + self->spi->TXD = write_value; + + while(!self->spi->EVENTS_READY); + + *data = self->spi->RXD; + + data++; + len--; + + self->spi->EVENTS_READY = 0x0UL; + } + + return true; +} diff --git a/ports/nrf/common-hal/busio/SPI.h b/ports/nrf/common-hal/busio/SPI.h new file mode 100644 index 0000000000000..1de74a9f29967 --- /dev/null +++ b/ports/nrf/common-hal/busio/SPI.h @@ -0,0 +1,42 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Scott Shawcroft + * + * 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_COMMON_HAL_BUSIO_SPI_H +#define MICROPY_INCLUDED_NRF_COMMON_HAL_BUSIO_SPI_H + +#include "common-hal/microcontroller/Pin.h" + +//#include "hal/include/hal_spi_m_sync.h" + +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; + NRF_SPI_Type *spi; + bool has_lock; +} busio_spi_obj_t; + +#endif // MICROPY_INCLUDED_NRF_COMMON_HAL_BUSIO_SPI_H diff --git a/ports/nrf/common-hal/busio/__init__.c b/ports/nrf/common-hal/busio/__init__.c new file mode 100644 index 0000000000000..41761b6743aea --- /dev/null +++ b/ports/nrf/common-hal/busio/__init__.c @@ -0,0 +1 @@ +// No busio module functions. diff --git a/ports/nrf/common-hal/digitalio/DigitalInOut.c b/ports/nrf/common-hal/digitalio/DigitalInOut.c new file mode 100644 index 0000000000000..a183faaa784ea --- /dev/null +++ b/ports/nrf/common-hal/digitalio/DigitalInOut.c @@ -0,0 +1,169 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * 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 + * 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 +#include + +#include "py/runtime.h" +#include "py/mphal.h" + +#include "hal/hal_gpio.h" + +#include "common-hal/microcontroller/Pin.h" +#include "shared-bindings/digitalio/DigitalInOut.h" + +digitalinout_result_t common_hal_digitalio_digitalinout_construct( + digitalio_digitalinout_obj_t* self, const mcu_pin_obj_t* pin) { + self->pin = pin; + hal_gpio_cfg_pin(pin->port, pin->pin, HAL_GPIO_MODE_INPUT, HAL_GPIO_PULL_DISABLED); + return DIGITALINOUT_OK; +} + +bool common_hal_digitalio_digitalinout_deinited(digitalio_digitalinout_obj_t* self) { + return self->pin == mp_const_none; +} + +void common_hal_digitalio_digitalinout_deinit(digitalio_digitalinout_obj_t* self) { + if (common_hal_digitalio_digitalinout_deinited(self)) { + return; + } + reset_pin(self->pin->pin); + self->pin = mp_const_none; +} + +void common_hal_digitalio_digitalinout_switch_to_input( + digitalio_digitalinout_obj_t* self, enum digitalio_pull_t pull) { + self->output = false; + + hal_gpio_cfg_pin(self->pin->port, self->pin->pin, HAL_GPIO_MODE_INPUT, HAL_GPIO_PULL_DISABLED); + common_hal_digitalio_digitalinout_set_pull(self, pull); +} + +void common_hal_digitalio_digitalinout_switch_to_output( + digitalio_digitalinout_obj_t* self, bool value, + enum digitalio_drive_mode_t drive_mode) { + const uint8_t pin = self->pin->pin; + + self->output = true; + self->open_drain = (drive_mode == DRIVE_MODE_OPEN_DRAIN); + + hal_gpio_cfg_pin(self->pin->port, pin, HAL_GPIO_MODE_OUTPUT, HAL_GPIO_PULL_DISABLED); + common_hal_digitalio_digitalinout_set_value(self, value); +} + +enum digitalio_direction_t common_hal_digitalio_digitalinout_get_direction( + digitalio_digitalinout_obj_t* self) { + return self->output? DIRECTION_OUTPUT : DIRECTION_INPUT; +} + +void common_hal_digitalio_digitalinout_set_value( + digitalio_digitalinout_obj_t* self, bool value) { + if (value) { + if (self->open_drain) { + hal_gpio_dir_set(self->pin->port, self->pin->pin, HAL_GPIO_MODE_INPUT); + } else { + hal_gpio_pin_set(self->pin->port, self->pin->pin); + hal_gpio_dir_set(self->pin->port, self->pin->pin, HAL_GPIO_MODE_OUTPUT); + } + } else { + hal_gpio_pin_clear(self->pin->port, self->pin->pin); + hal_gpio_dir_set(self->pin->port, self->pin->pin, HAL_GPIO_MODE_OUTPUT); + } +} + +bool common_hal_digitalio_digitalinout_get_value( + digitalio_digitalinout_obj_t* self) { + const uint8_t pin = self->pin->pin; + if (!self->output) { + return hal_gpio_pin_read(self->pin); + } else { + if (self->open_drain && hal_gpio_dir_get(self->pin->port, self->pin->pin) == HAL_GPIO_MODE_INPUT) { + return true; + } else { + return (GPIO_BASE(self->pin->port)->OUT >> pin) & 1; + } + } +} + +void common_hal_digitalio_digitalinout_set_drive_mode( + digitalio_digitalinout_obj_t* self, + enum digitalio_drive_mode_t drive_mode) { + bool value = common_hal_digitalio_digitalinout_get_value(self); + self->open_drain = drive_mode == DRIVE_MODE_OPEN_DRAIN; + // True is implemented differently between modes so reset the value to make + // sure its correct for the new mode. + if (value) { + common_hal_digitalio_digitalinout_set_value(self, value); + } +} + +enum digitalio_drive_mode_t common_hal_digitalio_digitalinout_get_drive_mode( + digitalio_digitalinout_obj_t* self) { + if (self->open_drain) { + return DRIVE_MODE_OPEN_DRAIN; + } else { + return DRIVE_MODE_PUSH_PULL; + } +} + +void common_hal_digitalio_digitalinout_set_pull( + digitalio_digitalinout_obj_t* self, enum digitalio_pull_t pull) { + hal_gpio_pull_t asf_pull = HAL_GPIO_PULL_DISABLED; + switch (pull) { + case PULL_UP: + asf_pull = HAL_GPIO_PULL_UP; + break; + case PULL_DOWN: + asf_pull = HAL_GPIO_PULL_DOWN; + break; + case PULL_NONE: + default: + break; + } + hal_gpio_pull_set(self->pin->port, self->pin->pin, asf_pull); +} + +enum digitalio_pull_t common_hal_digitalio_digitalinout_get_pull( + digitalio_digitalinout_obj_t* self) { + uint32_t pin = self->pin->pin; + if (self->output) { + mp_raise_AttributeError("Cannot get pull while in output mode"); + return PULL_NONE; + } else { + hal_gpio_pull_t pull = hal_gpio_pull_get(self->pin->port, pin); + + switch(pull) + { + case HAL_GPIO_PULL_UP: + return PULL_UP; + + case HAL_GPIO_PULL_DOWN: + return PULL_DOWN; + + default: return PULL_NONE; + } + } +} diff --git a/ports/nrf/common-hal/digitalio/DigitalInOut.h b/ports/nrf/common-hal/digitalio/DigitalInOut.h new file mode 100644 index 0000000000000..8089d8bacc733 --- /dev/null +++ b/ports/nrf/common-hal/digitalio/DigitalInOut.h @@ -0,0 +1,40 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * 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 + * 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_COMMON_HAL_DIGITALIO_DIGITALINOUT_H +#define MICROPY_INCLUDED_NRF_COMMON_HAL_DIGITALIO_DIGITALINOUT_H + +#include "common-hal/microcontroller/Pin.h" +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; + const mcu_pin_obj_t * pin; + bool output; + bool open_drain; +} digitalio_digitalinout_obj_t; + +#endif // MICROPY_INCLUDED_NRF_COMMON_HAL_DIGITALIO_DIGITALINOUT_H diff --git a/ports/nrf/common-hal/digitalio/__init__.c b/ports/nrf/common-hal/digitalio/__init__.c new file mode 100644 index 0000000000000..20fad459593ac --- /dev/null +++ b/ports/nrf/common-hal/digitalio/__init__.c @@ -0,0 +1 @@ +// No digitalio module functions. diff --git a/ports/nrf/common-hal/microcontroller/Pin.c b/ports/nrf/common-hal/microcontroller/Pin.c new file mode 100644 index 0000000000000..ee07ff09aaf45 --- /dev/null +++ b/ports/nrf/common-hal/microcontroller/Pin.c @@ -0,0 +1,75 @@ +/* + * 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 "common-hal/microcontroller/Pin.h" +#include "shared-bindings/microcontroller/Pin.h" + +#include "py/mphal.h" + +#if 0 + +extern volatile bool adc_in_use; + +bool common_hal_mcu_pin_is_free(const mcu_pin_obj_t* pin) { + if (pin == &pin_TOUT) { + return !adc_in_use; + } + if (pin->gpio_number == NO_GPIO || pin->gpio_number == SPECIAL_CASE) { + return false; + } + return (READ_PERI_REG(pin->peripheral) & + (PERIPHS_IO_MUX_FUNC<gpio_number)) == 0 && + (READ_PERI_REG(pin->peripheral) & PERIPHS_IO_MUX_PULLUP) == 0; +} + +void reset_pins(void) { + for (int i = 0; i < 17; i++) { + // 5 is RXD, 6 is TXD + if ((i > 4 && i < 13) || i == 12) { + continue; + } + uint32_t peripheral = PERIPHS_IO_MUX + i * 4; + PIN_FUNC_SELECT(peripheral, 0); + PIN_PULLUP_DIS(peripheral); + // Disable the pin. + gpio_output_set(0x0, 0x0, 0x0, 1 << i); + } +} +#endif + +bool common_hal_mcu_pin_is_free(const mcu_pin_obj_t* pin) { + return true; +} + +void reset_all_pins(void) { +} + +void reset_pin(uint8_t pin) { + +} + + diff --git a/ports/nrf/common-hal/microcontroller/Pin.h b/ports/nrf/common-hal/microcontroller/Pin.h new file mode 100644 index 0000000000000..d7994bc0ce9db --- /dev/null +++ b/ports/nrf/common-hal/microcontroller/Pin.h @@ -0,0 +1,40 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Scott Shawcroft + * + * 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_COMMON_HAL_MICROCONTROLLER_PIN_H +#define MICROPY_INCLUDED_NRF_COMMON_HAL_MICROCONTROLLER_PIN_H + +#include "py/mphal.h" +#include "modules/machine/pin.h" + +//typedef pin_obj_t mcu_pin_obj_t; +#define mcu_pin_obj_t pin_obj_t +void reset_all_pins(void); +void reset_pin(uint8_t pin); +//void claim_pin(const mcu_pin_obj_t* pin); + + +#endif // MICROPY_INCLUDED_NRF_COMMON_HAL_MICROCONTROLLER_PIN_H diff --git a/ports/nrf/common-hal/microcontroller/Processor.c b/ports/nrf/common-hal/microcontroller/Processor.c new file mode 100644 index 0000000000000..4e74a49091d2b --- /dev/null +++ b/ports/nrf/common-hal/microcontroller/Processor.c @@ -0,0 +1,37 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 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 "common-hal/microcontroller/Processor.h" + +// TODO port common_hal_mcu_processor +float common_hal_mcu_processor_get_temperature(void) { + return 0; +} + +uint32_t common_hal_mcu_processor_get_frequency(void) { + return 64000000ul; +} + diff --git a/ports/nrf/common-hal/microcontroller/Processor.h b/ports/nrf/common-hal/microcontroller/Processor.h new file mode 100644 index 0000000000000..00d95ad4f86d2 --- /dev/null +++ b/ports/nrf/common-hal/microcontroller/Processor.h @@ -0,0 +1,37 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 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_COMMON_HAL_MICROCONTROLLER_PROCESSOR_H +#define MICROPY_INCLUDED_NRF_COMMON_HAL_MICROCONTROLLER_PROCESSOR_H + +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; + // Stores no state currently. +} mcu_processor_obj_t; + +#endif // MICROPY_INCLUDED_NRF_COMMON_HAL_MICROCONTROLLER_PROCESSOR_H diff --git a/ports/nrf/common-hal/microcontroller/__init__.c b/ports/nrf/common-hal/microcontroller/__init__.c new file mode 100644 index 0000000000000..ddf0d252cef5c --- /dev/null +++ b/ports/nrf/common-hal/microcontroller/__init__.c @@ -0,0 +1,51 @@ +/* + * 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 "common-hal/microcontroller/Pin.h" +#include "common-hal/microcontroller/Processor.h" + +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/microcontroller/Processor.h" + +// TODO porting common_hal_mcu +void common_hal_mcu_delay_us(uint32_t delay) { +// os_delay_us(delay); +} + +void common_hal_mcu_disable_interrupts() { +} + +void common_hal_mcu_enable_interrupts() { +} + +// The singleton microcontroller.Processor object, returned by microcontroller.cpu +// It currently only has properties, and no state. +mcu_processor_obj_t common_hal_mcu_processor_obj = { + .base = { + .type = &mcu_processor_type, + }, +}; + diff --git a/ports/nrf/common-hal/os/__init__.c b/ports/nrf/common-hal/os/__init__.c new file mode 100644 index 0000000000000..0e6d63347c94c --- /dev/null +++ b/ports/nrf/common-hal/os/__init__.c @@ -0,0 +1,88 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * 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 + * 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 "genhdr/mpversion.h" +#include "py/mpconfig.h" +#include "py/objstr.h" +#include "py/objtuple.h" +#include "py/qstr.h" + +#include "nrf_sdm.h" +#include "nrf_soc.h" + +STATIC const qstr os_uname_info_fields[] = { + MP_QSTR_sysname, MP_QSTR_nodename, + MP_QSTR_release, MP_QSTR_version, MP_QSTR_machine +}; +STATIC const MP_DEFINE_STR_OBJ(os_uname_info_sysname_obj, "nrf52"); +STATIC const MP_DEFINE_STR_OBJ(os_uname_info_nodename_obj, "nrf52"); + +STATIC const MP_DEFINE_STR_OBJ(os_uname_info_release_obj, MICROPY_VERSION_STRING); +STATIC const MP_DEFINE_STR_OBJ(os_uname_info_version_obj, MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE); +STATIC const MP_DEFINE_STR_OBJ(os_uname_info_machine_obj, MICROPY_HW_BOARD_NAME " with " MICROPY_HW_MCU_NAME); + + +STATIC MP_DEFINE_ATTRTUPLE( + os_uname_info_obj, + os_uname_info_fields, + 5, + (mp_obj_t)&os_uname_info_sysname_obj, + (mp_obj_t)&os_uname_info_nodename_obj, + (mp_obj_t)&os_uname_info_release_obj, + (mp_obj_t)&os_uname_info_version_obj, + (mp_obj_t)&os_uname_info_machine_obj +); + +mp_obj_t common_hal_os_uname(void) { + return (mp_obj_t)&os_uname_info_obj; +} + +bool common_hal_os_urandom(uint8_t* buffer, uint32_t length) { + uint8_t sd_en = 0; + (void) sd_softdevice_is_enabled(&sd_en); + + if ( sd_en ) + { + return NRF_SUCCESS == sd_rand_application_vector_get(buffer,length); + }else + { + // SoftDevice is not enabled. + NRF_RNG->EVENTS_VALRDY = 0; + NRF_RNG->TASKS_START = 1; + + for (uint32_t i = 0; i < length; i++) { + while (NRF_RNG->EVENTS_VALRDY == 0) { + ; + } + NRF_RNG->EVENTS_VALRDY = 0; + buffer[i] = (uint8_t) NRF_RNG->VALUE; + } + + NRF_RNG->TASKS_STOP = 1; + } + + return true; +} diff --git a/ports/nrf/common-hal/pulseio/PWMOut.c b/ports/nrf/common-hal/pulseio/PWMOut.c new file mode 100644 index 0000000000000..ea9ba3f0e2ece --- /dev/null +++ b/ports/nrf/common-hal/pulseio/PWMOut.c @@ -0,0 +1,240 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries + * Copyright (c) 2016 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. + */ + +#include +#include "nrf.h" + +#include "py/runtime.h" +#include "common-hal/pulseio/PWMOut.h" +#include "shared-bindings/pulseio/PWMOut.h" + +#define PWM_MAX_MODULE 3 +#define PWM_MAX_CHANNEL 4 + +#define PWM_MAX_FREQ (16000000) + +NRF_PWM_Type* const pwm_arr[PWM_MAX_MODULE] = { NRF_PWM0, NRF_PWM1, NRF_PWM2 }; + +uint16_t _seq0[PWM_MAX_MODULE][PWM_MAX_CHANNEL]; + + +static int pin2channel(NRF_PWM_Type* pwm, uint8_t pin) +{ + for(int i=0; i < PWM_MAX_CHANNEL; i++) + { + if ( pwm->PSEL.OUT[i] == ((uint32_t)pin) ) return i; + } + + return -1; +} + +static int find_free_channel(NRF_PWM_Type* pwm) +{ + for(int i=0; i < PWM_MAX_CHANNEL; i++) + { + if (pwm->PSEL.OUT[i] == 0xFFFFFFFFUL) + { + return i; + } + } + + return -1; +} + +static bool pwm_is_unused(NRF_PWM_Type* pwm) +{ + for(int i=0; i < PWM_MAX_CHANNEL; i++) + { + if (pwm->PSEL.OUT[i] != 0xFFFFFFFFUL) + { + return false; + } + } + + return true; +} + +static void find_new_pwm(pulseio_pwmout_obj_t* self) +{ + // First find unused PWM module + for(int i=0; ipwm = pwm_arr[i]; + self->channel = 0; + return; + } + } + + // Find available channel in a using PWM + for(int i=0; i= 0 ) + { + self->pwm = pwm_arr[i]; + self->channel = (uint8_t) ch; + return; + } + } +} + +void pwmout_reset(void) +{ + for(int i=0; iMODE = PWM_MODE_UPDOWN_Up; + pwm->DECODER = PWM_DECODER_LOAD_Individual; + pwm->LOOP = 0; + pwm->PRESCALER = PWM_PRESCALER_PRESCALER_DIV_1; // default is 500 hz + pwm->COUNTERTOP = (PWM_MAX_FREQ/500); // default is 500 hz + + pwm->SEQ[0].PTR = (uint32_t) _seq0[i]; + pwm->SEQ[0].CNT = PWM_MAX_CHANNEL; // default mode is Individual --> count must be 4 + pwm->SEQ[0].REFRESH = 0; + pwm->SEQ[0].ENDDELAY = 0; + + pwm->SEQ[1].PTR = 0; + pwm->SEQ[1].CNT = 0; + pwm->SEQ[1].REFRESH = 0; + pwm->SEQ[1].ENDDELAY = 0; + + for(int ch =0; ch < PWM_MAX_CHANNEL; ch++) + { + _seq0[i][ch] = (1UL << 15); // polarity = 0 + } + } +} + +void common_hal_pulseio_pwmout_construct(pulseio_pwmout_obj_t* self, + const mcu_pin_obj_t* pin, + uint16_t duty, + uint32_t frequency, + bool variable_frequency) { + self->pwm = NULL; + self->pin = pin; + + // check if mapped to PWM channel already + for(int i=0; ipin); + if ( ch >= 0 ) + { + self->pwm = pwm_arr[i]; + self->channel = (uint8_t) ch; + break; + } + } + + // Haven't mapped before + if ( !self->pwm ) + { + find_new_pwm(self); + } + + if (self->pwm) + { + hal_gpio_cfg_pin(pin->port, pin->pin, HAL_GPIO_MODE_OUTPUT, HAL_GPIO_PULL_DISABLED); + + // disable before mapping pin channel + self->pwm->ENABLE = 0; + + self->pwm->PSEL.OUT[self->channel] = pin->pin; + + self->pwm->COUNTERTOP = (PWM_MAX_FREQ/frequency); + self->freq = frequency; + self->variable_freq = variable_frequency; + + self->pwm->ENABLE = 1; + + common_hal_pulseio_pwmout_set_duty_cycle(self, duty); + } +} + +bool common_hal_pulseio_pwmout_deinited(pulseio_pwmout_obj_t* self) { + return self->pwm == NULL; +} + +void common_hal_pulseio_pwmout_deinit(pulseio_pwmout_obj_t* self) { + if (common_hal_pulseio_pwmout_deinited(self)) { + return; + } + + self->pwm->ENABLE = 0; + + self->pwm->PSEL.OUT[self->channel] = 0xFFFFFFFFUL; + + // re-enable PWM module if there is other active channel + for(int i=0; i < PWM_MAX_CHANNEL; i++) + { + if (self->pwm->PSEL.OUT[i] != 0xFFFFFFFFUL) + { + self->pwm->ENABLE = 1; + break; + } + } + + hal_gpio_cfg_pin(self->pin->port, self->pin->pin, HAL_GPIO_MODE_INPUT, HAL_GPIO_PULL_DISABLED); + + self->pwm = NULL; + self->pin = mp_const_none; +} + +void common_hal_pulseio_pwmout_set_duty_cycle(pulseio_pwmout_obj_t* self, uint16_t duty) { + self->duty = duty; + + uint16_t* p_value = ((uint16_t*)self->pwm->SEQ[0].PTR) + self->channel; + *p_value = ((duty * self->pwm->COUNTERTOP) / 0xFFFF) | (1 << 15); + + self->pwm->TASKS_SEQSTART[0] = 1; +} + +uint16_t common_hal_pulseio_pwmout_get_duty_cycle(pulseio_pwmout_obj_t* self) { + return self->duty; +} + +void common_hal_pulseio_pwmout_set_frequency(pulseio_pwmout_obj_t* self, uint32_t frequency) { + if (frequency == 0 || frequency > 16000000) { + mp_raise_ValueError("Invalid PWM frequency"); + } + + self->freq = frequency; + self->pwm->COUNTERTOP = (PWM_MAX_FREQ/frequency); + self->pwm->TASKS_SEQSTART[0] = 1; +} + +uint32_t common_hal_pulseio_pwmout_get_frequency(pulseio_pwmout_obj_t* self) { + return self->freq; +} + +bool common_hal_pulseio_pwmout_get_variable_frequency(pulseio_pwmout_obj_t* self) { + return self->variable_freq; +} + diff --git a/ports/nrf/common-hal/pulseio/PWMOut.h b/ports/nrf/common-hal/pulseio/PWMOut.h new file mode 100644 index 0000000000000..ddb7192a88a3d --- /dev/null +++ b/ports/nrf/common-hal/pulseio/PWMOut.h @@ -0,0 +1,47 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * 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 + * 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_ATMEL_SAMD_COMMON_HAL_PULSEIO_PWMOUT_H +#define MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_PULSEIO_PWMOUT_H + +#include "common-hal/microcontroller/Pin.h" + +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; + const mcu_pin_obj_t *pin; + NRF_PWM_Type* pwm; + + uint8_t channel; + bool variable_freq; + uint16_t duty; + uint32_t freq; +} pulseio_pwmout_obj_t; + +void pwmout_reset(void); + +#endif // MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_PULSEIO_PWMOUT_H diff --git a/ports/nrf/common-hal/pulseio/PulseIn.c b/ports/nrf/common-hal/pulseio/PulseIn.c new file mode 100644 index 0000000000000..19e7dbba3665c --- /dev/null +++ b/ports/nrf/common-hal/pulseio/PulseIn.c @@ -0,0 +1,295 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * 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 + * 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 "common-hal/pulseio/PulseIn.h" + +#include + +//#include "asf/common2/services/delay/delay.h" +//#include "asf/sam0/drivers/extint/extint.h" +//#include "asf/sam0/drivers/extint/extint_callback.h" +//#include "asf/sam0/drivers/port/port.h" + +#include "mpconfigport.h" +#include "py/gc.h" +#include "py/runtime.h" +//#include "samd21_pins.h" +#include "shared-bindings/microcontroller/__init__.h" +#include "shared-bindings/pulseio/PulseIn.h" + +//#include "tick.h" + +void pulsein_reset(void) { + +} + +void common_hal_pulseio_pulsein_construct(pulseio_pulsein_obj_t* self, const mcu_pin_obj_t* pin, uint16_t maxlen, bool idle_state) { + +} + +bool common_hal_pulseio_pulsein_deinited(pulseio_pulsein_obj_t* self) { + return 1; +} + +void common_hal_pulseio_pulsein_deinit(pulseio_pulsein_obj_t* self) { + +} + +void common_hal_pulseio_pulsein_pause(pulseio_pulsein_obj_t* self) { + +} + +void common_hal_pulseio_pulsein_resume(pulseio_pulsein_obj_t* self, uint16_t trigger_duration) { + +} + +void common_hal_pulseio_pulsein_clear(pulseio_pulsein_obj_t* self) { + +} + +uint16_t common_hal_pulseio_pulsein_popleft(pulseio_pulsein_obj_t* self) { + return 0; +} + +uint16_t common_hal_pulseio_pulsein_get_maxlen(pulseio_pulsein_obj_t* self) { + return 0xadaf; +} + +uint16_t common_hal_pulseio_pulsein_get_len(pulseio_pulsein_obj_t* self) { + return 0xadaf; +} + +uint16_t common_hal_pulseio_pulsein_get_item(pulseio_pulsein_obj_t* self, int16_t index) { + return 0xadaf; +} + + +#if 0 + +static pulseio_pulsein_obj_t *active_pulseins[EIC_NUMBER_OF_INTERRUPTS]; +static uint64_t last_ms[EIC_NUMBER_OF_INTERRUPTS]; +static uint16_t last_us[EIC_NUMBER_OF_INTERRUPTS]; + +void pulsein_reset(void) { + for (int i = 0; i < EIC_NUMBER_OF_INTERRUPTS; i++) { + if (active_pulseins[i] != NULL) { + extint_chan_disable_callback(i, EXTINT_CALLBACK_TYPE_DETECT); + } + active_pulseins[i] = NULL; + last_ms[i] = 0; + last_us[i] = 0; + } +} + +static void pulsein_set_config(pulseio_pulsein_obj_t* self, bool first_edge) { + struct extint_chan_conf config; + extint_chan_get_config_defaults(&config); + config.gpio_pin = self->pin; + config.gpio_pin_pull = EXTINT_PULL_NONE; + config.filter_input_signal = true; + + if (!first_edge) { + config.detection_criteria = EXTINT_DETECT_BOTH; + } else if (self->idle_state) { + config.detection_criteria = EXTINT_DETECT_FALLING; + } else { + config.detection_criteria = EXTINT_DETECT_RISING; + } + extint_chan_disable_callback(self->channel, EXTINT_CALLBACK_TYPE_DETECT); + extint_chan_set_config(self->channel, &config); + // Clear any interrupts that may have triggered without notifying the CPU. + EIC->INTFLAG.reg |= (1UL << self->channel); + extint_chan_enable_callback(self->channel, EXTINT_CALLBACK_TYPE_DETECT); +} + +static void pulsein_callback(void) { + // Grab the current time first. + uint16_t current_us = tc_get_count_value(&ms_timer); + // Add the overflow flag to account for tick interrupts that are blocked by + // this interrupt. + uint64_t current_ms = ticks_ms + TC5->COUNT16.INTFLAG.bit.OVF; + pulseio_pulsein_obj_t* self = active_pulseins[extint_get_current_channel()]; + current_us = current_us * 1000 / self->ticks_per_ms; + if (self->first_edge) { + self->first_edge = false; + pulsein_set_config(self, false); + } else { + uint32_t ms_diff = current_ms - last_ms[self->channel]; + uint16_t us_diff = current_us - last_us[self->channel]; + uint32_t total_diff = us_diff; + if (last_us[self->channel] > current_us) { + total_diff = 1000 + current_us - last_us[self->channel]; + if (ms_diff > 1) { + total_diff += (ms_diff - 1) * 1000; + } + } else { + total_diff += ms_diff * 1000; + } + uint16_t duration = 0xffff; + if (total_diff < duration) { + duration = total_diff; + } + + uint16_t i = (self->start + self->len) % self->maxlen; + self->buffer[i] = duration; + if (self->len < self->maxlen) { + self->len++; + } else { + self->start++; + } + } + last_ms[self->channel] = current_ms; + last_us[self->channel] = current_us; +} + +void common_hal_pulseio_pulsein_construct(pulseio_pulsein_obj_t* self, + const mcu_pin_obj_t* pin, uint16_t maxlen, bool idle_state) { + if (!pin->has_extint) { + mp_raise_RuntimeError("No hardware support on pin"); + } + // TODO(tannewt): Switch to checking actual extint peripheral state when other + // classes use extints. + if (active_pulseins[pin->extint_channel] != NULL) { + mp_raise_RuntimeError("EXTINT channel already in use"); + } + + self->buffer = (uint16_t *) gc_alloc(maxlen * sizeof(uint16_t), false); + if (self->buffer == NULL) { + mp_raise_msg_varg(&mp_type_MemoryError, "Failed to allocate RX buffer of %d bytes", maxlen * sizeof(uint16_t)); + } + self->channel = pin->extint_channel; + self->pin = pin->pin; + self->maxlen = maxlen; + self->idle_state = idle_state; + self->start = 0; + self->len = 0; + self->first_edge = true; + self->ticks_per_ms = (system_cpu_clock_get_hz() / 1000 - 1); + + active_pulseins[pin->extint_channel] = self; + + pulsein_set_config(self, true); + extint_register_callback( + pulsein_callback, + self->channel, + EXTINT_CALLBACK_TYPE_DETECT); + extint_chan_enable_callback(self->channel, EXTINT_CALLBACK_TYPE_DETECT); +} + +bool common_hal_pulseio_pulsein_deinited(pulseio_pulsein_obj_t* self) { + return self->pin == NO_PIN; +} + +void common_hal_pulseio_pulsein_deinit(pulseio_pulsein_obj_t* self) { + if (common_hal_pulseio_pulsein_deinited(self)) { + return; + } + extint_chan_disable_callback(self->channel, EXTINT_CALLBACK_TYPE_DETECT); + active_pulseins[self->channel] = NULL; + reset_pin(self->pin); + self->pin = NO_PIN; +} + +void common_hal_pulseio_pulsein_pause(pulseio_pulsein_obj_t* self) { + extint_chan_disable_callback(self->channel, EXTINT_CALLBACK_TYPE_DETECT); +} + +void common_hal_pulseio_pulsein_resume(pulseio_pulsein_obj_t* self, + uint16_t trigger_duration) { + // Send the trigger pulse. + if (trigger_duration > 0) { + struct port_config pin_conf; + port_get_config_defaults(&pin_conf); + + pin_conf.direction = PORT_PIN_DIR_OUTPUT; + pin_conf.input_pull = PORT_PIN_PULL_NONE; + port_pin_set_config(self->pin, &pin_conf); + + // TODO(tannewt): delay_us isn't exactly correct so we adjust the value + // here before calling it. Find out why its not exact and fix it instead + // of hacking around it here. + uint32_t adjusted_duration = trigger_duration; + adjusted_duration *= 4; + adjusted_duration /= 5; + + common_hal_mcu_disable_interrupts(); + port_pin_set_output_level(self->pin, !self->idle_state); + common_hal_mcu_delay_us(adjusted_duration); + port_pin_set_output_level(self->pin, self->idle_state); + common_hal_mcu_enable_interrupts(); + } + + // Reconfigure the pin and make sure its set to detect the first edge. + last_ms[self->channel] = 0; + last_us[self->channel] = 0; + self->first_edge = true; + pulsein_set_config(self, true); +} + +void common_hal_pulseio_pulsein_clear(pulseio_pulsein_obj_t* self) { + common_hal_mcu_disable_interrupts(); + self->start = 0; + self->len = 0; + common_hal_mcu_enable_interrupts(); +} + +uint16_t common_hal_pulseio_pulsein_popleft(pulseio_pulsein_obj_t* self) { + if (self->len == 0) { + mp_raise_IndexError("pop from an empty PulseIn"); + } + common_hal_mcu_disable_interrupts(); + uint16_t value = self->buffer[self->start]; + self->start = (self->start + 1) % self->maxlen; + self->len--; + common_hal_mcu_enable_interrupts(); + + return value; +} + +uint16_t common_hal_pulseio_pulsein_get_maxlen(pulseio_pulsein_obj_t* self) { + return self->maxlen; +} + +uint16_t common_hal_pulseio_pulsein_get_len(pulseio_pulsein_obj_t* self) { + return self->len; +} + +uint16_t common_hal_pulseio_pulsein_get_item(pulseio_pulsein_obj_t* self, + int16_t index) { + common_hal_mcu_disable_interrupts(); + if (index < 0) { + index += self->len; + } + if (index < 0 || index >= self->len) { + common_hal_mcu_enable_interrupts(); + mp_raise_IndexError("index out of range"); + } + uint16_t value = self->buffer[(self->start + index) % self->maxlen]; + common_hal_mcu_enable_interrupts(); + return value; +} + +#endif diff --git a/ports/nrf/common-hal/pulseio/PulseIn.h b/ports/nrf/common-hal/pulseio/PulseIn.h new file mode 100644 index 0000000000000..f577a61311bc8 --- /dev/null +++ b/ports/nrf/common-hal/pulseio/PulseIn.h @@ -0,0 +1,49 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * 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 + * 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_ATMEL_SAMD_COMMON_HAL_PULSEIO_PULSEIN_H +#define MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_PULSEIO_PULSEIN_H + +#include "common-hal/microcontroller/Pin.h" + +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; + uint8_t channel; + uint8_t pin; + uint16_t* buffer; + uint16_t maxlen; + bool idle_state; + volatile uint16_t start; + volatile uint16_t len; + volatile bool first_edge; + uint16_t ticks_per_ms; +} pulseio_pulsein_obj_t; + +void pulsein_reset(void); + +#endif // MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_PULSEIO_PULSEIN_H diff --git a/ports/nrf/common-hal/pulseio/PulseOut.c b/ports/nrf/common-hal/pulseio/PulseOut.c new file mode 100644 index 0000000000000..b6ddeca445b09 --- /dev/null +++ b/ports/nrf/common-hal/pulseio/PulseOut.c @@ -0,0 +1,206 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 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. + */ + +#include "common-hal/pulseio/PulseOut.h" + +#include + +//#include "asf/sam0/drivers/tc/tc_interrupt.h" +//#include "asf/sam0/drivers/port/port.h" + +#include "mpconfigport.h" +#include "py/gc.h" +#include "py/runtime.h" +//#include "samd21_pins.h" +#include "shared-bindings/pulseio/PulseOut.h" + +//void pulse_finish(struct tc_module *const module) { +// +//} + +void pulseout_reset() { + +} + +void common_hal_pulseio_pulseout_construct(pulseio_pulseout_obj_t* self, const pulseio_pwmout_obj_t* carrier) { + +} + +bool common_hal_pulseio_pulseout_deinited(pulseio_pulseout_obj_t* self) { + return 1; +} + +void common_hal_pulseio_pulseout_deinit(pulseio_pulseout_obj_t* self) { + +} + +void common_hal_pulseio_pulseout_send(pulseio_pulseout_obj_t* self, uint16_t* pulses, uint16_t length) { + +} + +#if 0 +// This timer is shared amongst all PulseOut objects under the assumption that +// the code is single threaded. Its stored in MICROPY_PORT_ROOT_POINTERS so it +// doesn't get garbage collected. +static uint8_t refcount = 0; + +static __IO PORT_PINCFG_Type *active_pincfg = NULL; +static uint16_t *pulse_buffer = NULL; +static volatile uint16_t pulse_index = 0; +static uint16_t pulse_length; +static volatile uint32_t current_compare = 0; + +static void turn_on(__IO PORT_PINCFG_Type * pincfg) { + pincfg->reg = PORT_PINCFG_PMUXEN; +} + +static void turn_off(__IO PORT_PINCFG_Type * pincfg) { + pincfg->reg = PORT_PINCFG_RESETVALUE; +} + +void pulse_finish(struct tc_module *const module) { + pulse_index++; + + if (active_pincfg == NULL) { + return; + } + // Always turn it off. + turn_off(active_pincfg); + if (pulse_index >= pulse_length) { + return; + } + current_compare = (current_compare + pulse_buffer[pulse_index] * 3 / 4) & 0xffff; + tc_set_compare_value(MP_STATE_VM(pulseout_tc_instance), TC_COMPARE_CAPTURE_CHANNEL_0, current_compare); + if (pulse_index % 2 == 0) { + turn_on(active_pincfg); + } +} + +void pulseout_reset() { + refcount = 0; + MP_STATE_VM(pulseout_tc_instance) = NULL; + active_pincfg = NULL; +} + +void common_hal_pulseio_pulseout_construct(pulseio_pulseout_obj_t* self, + const pulseio_pwmout_obj_t* carrier) { + if (refcount == 0) { + // Find a spare timer. + Tc *t = NULL; + Tc *tcs[TC_INST_NUM] = TC_INSTS; + for (uint8_t i = TC_INST_NUM; i > 0; i--) { + if (tcs[i - 1]->COUNT16.CTRLA.bit.ENABLE == 0) { + t = tcs[i - 1]; + break; + } + } + if (t == NULL) { + mp_raise_RuntimeError("All timers in use"); + } + MP_STATE_VM(pulseout_tc_instance) = gc_alloc(sizeof(struct tc_module), false); + if (t == NULL) { + mp_raise_msg(&mp_type_MemoryError, ""); + } + + struct tc_config config_tc; + tc_get_config_defaults(&config_tc); + + config_tc.counter_size = TC_COUNTER_SIZE_16BIT; + config_tc.clock_prescaler = TC_CTRLA_PRESCALER_DIV64; + config_tc.wave_generation = TC_WAVE_GENERATION_NORMAL_FREQ; + + tc_init(MP_STATE_VM(pulseout_tc_instance), t, &config_tc); + tc_register_callback(MP_STATE_VM(pulseout_tc_instance), pulse_finish, TC_CALLBACK_CC_CHANNEL0); + tc_enable(MP_STATE_VM(pulseout_tc_instance)); + tc_stop_counter(MP_STATE_VM(pulseout_tc_instance)); + } + refcount++; + + self->pin = carrier->pin->pin; + + PortGroup *const port_base = port_get_group_from_gpio_pin(self->pin); + self->pincfg = &port_base->PINCFG[self->pin % 32]; + + // Set the port to output a zero. + port_base->OUTCLR.reg = 1 << (self->pin % 32); + port_base->DIRSET.reg = 1 << (self->pin % 32); + + // Turn off the pinmux which should connect the port output. + turn_off(self->pincfg); +} + +bool common_hal_pulseio_pulseout_deinited(pulseio_pulseout_obj_t* self) { + return self->pin == NO_PIN; +} + +void common_hal_pulseio_pulseout_deinit(pulseio_pulseout_obj_t* self) { + if (common_hal_pulseio_pulseout_deinited(self)) { + return; + } + PortGroup *const port_base = port_get_group_from_gpio_pin(self->pin); + port_base->DIRCLR.reg = 1 << (self->pin % 32); + + turn_on(self->pincfg); + + refcount--; + if (refcount == 0) { + tc_reset(MP_STATE_VM(pulseout_tc_instance)); + gc_free(MP_STATE_VM(pulseout_tc_instance)); + MP_STATE_VM(pulseout_tc_instance) = NULL; + } + self->pin = NO_PIN; +} + +void common_hal_pulseio_pulseout_send(pulseio_pulseout_obj_t* self, uint16_t* pulses, uint16_t length) { + if (active_pincfg != NULL) { + mp_raise_RuntimeError("Another send is already active"); + } + active_pincfg = self->pincfg; + pulse_buffer = pulses; + pulse_index = 0; + pulse_length = length; + + current_compare = pulses[0] * 3 / 4; + tc_set_compare_value(MP_STATE_VM(pulseout_tc_instance), TC_COMPARE_CAPTURE_CHANNEL_0, current_compare); + + tc_enable_callback(MP_STATE_VM(pulseout_tc_instance), TC_CALLBACK_CC_CHANNEL0); + turn_on(active_pincfg); + tc_start_counter(MP_STATE_VM(pulseout_tc_instance)); + + while(pulse_index < length) { + // Do other things while we wait. The interrupts will handle sending the + // signal. + #ifdef MICROPY_VM_HOOK_LOOP + MICROPY_VM_HOOK_LOOP + #endif + } + + tc_stop_counter(MP_STATE_VM(pulseout_tc_instance)); + tc_disable_callback(MP_STATE_VM(pulseout_tc_instance), TC_CALLBACK_CC_CHANNEL0); + active_pincfg = NULL; +} +#endif + diff --git a/ports/nrf/common-hal/pulseio/PulseOut.h b/ports/nrf/common-hal/pulseio/PulseOut.h new file mode 100644 index 0000000000000..8ade95cd6d767 --- /dev/null +++ b/ports/nrf/common-hal/pulseio/PulseOut.h @@ -0,0 +1,42 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * 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 + * 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_ATMEL_SAMD_COMMON_HAL_PULSEIO_PULSEOUT_H +#define MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_PULSEIO_PULSEOUT_H + +#include "common-hal/microcontroller/Pin.h" + +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; +// __IO PORT_PINCFG_Type *pincfg; + uint8_t pin; +} pulseio_pulseout_obj_t; + +void pulseout_reset(void); + +#endif // MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_PULSEIO_PULSEOUT_H diff --git a/ports/nrf/common-hal/pulseio/__init__.c b/ports/nrf/common-hal/pulseio/__init__.c new file mode 100644 index 0000000000000..2bee925bc77fb --- /dev/null +++ b/ports/nrf/common-hal/pulseio/__init__.c @@ -0,0 +1 @@ +// No pulseio module functions. diff --git a/ports/nrf/common-hal/storage/__init__.c b/ports/nrf/common-hal/storage/__init__.c new file mode 100644 index 0000000000000..9d94d39690ba5 --- /dev/null +++ b/ports/nrf/common-hal/storage/__init__.c @@ -0,0 +1,39 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * 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 + * 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 + +#include "py/mperrno.h" +#include "py/runtime.h" +#include "shared-bindings/storage/__init__.h" + +extern volatile bool mp_msc_enabled; + +void common_hal_storage_remount(const char* mount_path, bool readonly) { + if (strcmp(mount_path, "/") != 0) { + mp_raise_OSError(MP_EINVAL); + } +} diff --git a/ports/nrf/common-hal/time/__init__.c b/ports/nrf/common-hal/time/__init__.c new file mode 100644 index 0000000000000..dc29e2d6d5457 --- /dev/null +++ b/ports/nrf/common-hal/time/__init__.c @@ -0,0 +1,38 @@ +/* + * 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/time/__init__.h" +#include "boards/board.h" + +inline uint64_t common_hal_time_monotonic() { + return ticks_ms; +} + +void common_hal_time_delay_ms(uint32_t delay) { + mp_hal_delay_ms(delay); +} diff --git a/ports/nrf/device/nrf52/startup_nrf52832.c b/ports/nrf/device/nrf52/startup_nrf52832.c index b36ac0d971b23..614b8c2d32276 100644 --- a/ports/nrf/device/nrf52/startup_nrf52832.c +++ b/ports/nrf/device/nrf52/startup_nrf52832.c @@ -35,6 +35,8 @@ extern uint32_t _ebss; typedef void (*func)(void); +#define _start main + extern void _start(void) __attribute__((noreturn)); extern void SystemInit(void); diff --git a/ports/nrf/device/nrf52/startup_nrf52840.c b/ports/nrf/device/nrf52/startup_nrf52840.c index 998696c08ea32..30634a1b540c3 100644 --- a/ports/nrf/device/nrf52/startup_nrf52840.c +++ b/ports/nrf/device/nrf52/startup_nrf52840.c @@ -35,6 +35,8 @@ extern uint32_t _ebss; typedef void (*func)(void); +#define _start main + extern void _start(void) __attribute__((noreturn)); extern void SystemInit(void); diff --git a/ports/nrf/drivers/bluetooth/download_ble_stack.sh b/ports/nrf/drivers/bluetooth/download_ble_stack.sh index 537742605b4ac..ab85c42af7e2d 100755 --- a/ports/nrf/drivers/bluetooth/download_ble_stack.sh +++ b/ports/nrf/drivers/bluetooth/download_ble_stack.sh @@ -52,15 +52,33 @@ function download_s132_nrf52_3_0_0 cd - } +function download_s132_nrf52_5_0_0 +{ + echo "" + echo "####################################" + echo "### Downloading s132_nrf52_5.0.0 ###" + echo "####################################" + echo "" + + mkdir -p $1/s132_nrf52_5.0.0 + cd $1/s132_nrf52_5.0.0 + + wget http://www.nordicsemi.com/eng/nordic/download_resource/58987/11/7198220/116068 + mv 116068 temp.zip + unzip -u temp.zip + rm temp.zip + cd - +} SCRIPT_DIR="$(cd -P "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -if [ $# -eq 0 ]; then +if [ $# -eq 0 ]; then echo "No Bluetooth LE stack defined, downloading all." download_s110_nrf51_8_0_0 ${SCRIPT_DIR} download_s132_nrf52_2_0_1 ${SCRIPT_DIR} download_s132_nrf52_3_0_0 ${SCRIPT_DIR} -else + download_s132_nrf52_5_0_0 ${SCRIPT_DIR} +else case $1 in "s110_nrf51" ) download_s110_nrf51_8_0_0 ${SCRIPT_DIR} ;; @@ -68,6 +86,8 @@ else download_s132_nrf52_2_0_1 ${SCRIPT_DIR} ;; "s132_nrf52_3_0_0" ) download_s132_nrf52_3_0_0 ${SCRIPT_DIR} ;; + "s132_nrf52_5_0_0" ) + download_s132_nrf52_5_0_0 ${SCRIPT_DIR} ;; esac fi diff --git a/ports/nrf/fifo.c b/ports/nrf/fifo.c new file mode 100644 index 0000000000000..7e8f989c30e96 --- /dev/null +++ b/ports/nrf/fifo.c @@ -0,0 +1,267 @@ +/******************************************************************************/ +/*! + @file fifo.c + @author hathach (tinyusb.org) + + @section DESCRIPTION + + Light-weight FIFO buffer with basic mutex support + + @section LICENSE + + Software License Agreement (BSD License) + + Copyright (c) 2012, K. Townsend (microBuilder.eu) + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holders nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/******************************************************************************/ + +#include "fifo.h" + +/*------------------------------------------------------------------*/ +/* + *------------------------------------------------------------------*/ +#if CFG_FIFO_MUTEX + +#define mutex_lock_if_needed(_ff) if (_ff->mutex) fifo_mutex_lock(_ff->mutex) +#define mutex_unlock_if_needed(_ff) if (_ff->mutex) fifo_mutex_unlock(_ff->mutex) + +#else + +#define mutex_lock_if_needed(_ff) +#define mutex_unlock_if_needed(_ff) + +#endif + +static inline uint16_t min16_of(uint16_t x, uint16_t y) +{ + return (x < y) ? x : y; +} + +static inline bool fifo_initalized(fifo_t* f) +{ + return (f->buffer != NULL) && (f->depth > 0) && (f->item_size > 0); +} + + +/******************************************************************************/ +/*! + @brief Read one byte out of the RX buffer. + + This function will return the byte located at the array index of the + read pointer, and then increment the read pointer index. If the read + pointer exceeds the maximum buffer size, it will roll over to zero. + + @param[in] f + Pointer to the FIFO buffer to manipulate + @param[in] p_buffer + Pointer to the place holder for data read from the buffer + + @returns TRUE if the queue is not empty +*/ +/******************************************************************************/ +bool fifo_read(fifo_t* f, void * p_buffer) +{ + if( !fifo_initalized(f) ) return false; + if( fifo_empty(f) ) return false; + + mutex_lock_if_needed(f); + + memcpy(p_buffer, + f->buffer + (f->rd_idx * f->item_size), + f->item_size); + f->rd_idx = (f->rd_idx + 1) % f->depth; + f->count--; + + mutex_unlock_if_needed(f); + + return true; +} + +/******************************************************************************/ +/*! + @brief This function will read n elements into the array index specified by + the write pointer and increment the write index. If the write index + exceeds the max buffer size, then it will roll over to zero. + + @param[in] f + Pointer to the FIFO buffer to manipulate + @param[in] p_data + The pointer to data location + @param[in] count + Number of element that buffer can afford + + @returns number of bytes read from the FIFO +*/ +/******************************************************************************/ +uint16_t fifo_read_n (fifo_t* f, void * p_buffer, uint16_t count) +{ + if( !fifo_initalized(f) ) return false; + if( fifo_empty(f) ) return false; + + /* Limit up to fifo's count */ + count = min16_of(count, f->count); + if( count == 0 ) return 0; + + mutex_lock_if_needed(f); + + /* Could copy up to 2 portions marked as 'x' if queue is wrapped around + * case 1: ....RxxxxW....... + * case 2: xxxxxW....Rxxxxxx + */ +// uint16_t index2upper = min16_of(count, f->count-f->rd_idx); + + uint8_t* p_buf = (uint8_t*) p_buffer; + uint16_t len = 0; + while( (len < count) && fifo_read(f, p_buf) ) + { + len++; + p_buf += f->item_size; + } + + mutex_unlock_if_needed(f); + + return len; +} + +/******************************************************************************/ +/*! + @brief Reads one item without removing it from the FIFO + + @param[in] f + Pointer to the FIFO buffer to manipulate + @param[in] position + Position to read from in the FIFO buffer + @param[in] p_buffer + Pointer to the place holder for data read from the buffer + + @returns TRUE if the queue is not empty +*/ +/******************************************************************************/ +bool fifo_peek_at(fifo_t* f, uint16_t position, void * p_buffer) +{ + if ( !fifo_initalized(f) ) return false; + if ( position >= f->count ) return false; + + // rd_idx is position=0 + uint16_t index = (f->rd_idx + position) % f->depth; + memcpy(p_buffer, + f->buffer + (index * f->item_size), + f->item_size); + + return true; +} + +/******************************************************************************/ +/*! + @brief Write one element into the RX buffer. + + This function will write one element into the array index specified by + the write pointer and increment the write index. If the write index + exceeds the max buffer size, then it will roll over to zero. + + @param[in] f + Pointer to the FIFO buffer to manipulate + @param[in] p_data + The byte to add to the FIFO + + @returns TRUE if the data was written to the FIFO (overwrittable + FIFO will always return TRUE) +*/ +/******************************************************************************/ +bool fifo_write(fifo_t* f, void const * p_data) +{ + if ( !fifo_initalized(f) ) return false; + if ( fifo_full(f) && !f->overwritable ) return false; + + mutex_lock_if_needed(f); + + memcpy( f->buffer + (f->wr_idx * f->item_size), + p_data, + f->item_size); + + f->wr_idx = (f->wr_idx + 1) % f->depth; + + if (fifo_full(f)) + { + f->rd_idx = f->wr_idx; // keep the full state (rd == wr && len = size) + } + else + { + f->count++; + } + + mutex_unlock_if_needed(f); + + return true; +} + +/******************************************************************************/ +/*! + @brief This function will write n elements into the array index specified by + the write pointer and increment the write index. If the write index + exceeds the max buffer size, then it will roll over to zero. + + @param[in] f + Pointer to the FIFO buffer to manipulate + @param[in] p_data + The pointer to data to add to the FIFO + @param[in] count + Number of element + @return Number of written elements +*/ +/******************************************************************************/ +uint16_t fifo_write_n(fifo_t* f, void const * p_data, uint16_t count) +{ + if ( count == 0 ) return 0; + + uint8_t* p_buf = (uint8_t*) p_data; + + uint16_t len = 0; + while( (len < count) && fifo_write(f, p_buf) ) + { + len++; + p_buf += f->item_size; + } + + return len; +} + +/******************************************************************************/ +/*! + @brief Clear the fifo read and write pointers and set length to zero + + @param[in] f + Pointer to the FIFO buffer to manipulate +*/ +/******************************************************************************/ +void fifo_clear(fifo_t *f) +{ + mutex_lock_if_needed(f); + + f->rd_idx = f->wr_idx = f->count = 0; + + mutex_unlock_if_needed(f); +} diff --git a/ports/nrf/fifo.h b/ports/nrf/fifo.h new file mode 100644 index 0000000000000..7b3afba7a2dcd --- /dev/null +++ b/ports/nrf/fifo.h @@ -0,0 +1,148 @@ +/******************************************************************************/ +/*! + @file fifo.h + @author hathach (tinyusb.org) + + @section LICENSE + + Software License Agreement (BSD License) + + Copyright (c) 2012, K. Townsend (microBuilder.eu) + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holders nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/******************************************************************************/ +#ifndef __FIFO_H__ +#define __FIFO_H__ + +#define CFG_FIFO_MUTEX 1 + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if CFG_FIFO_MUTEX + +#include "nrf52.h" + +#define fifo_mutex_t IRQn_Type + +#define fifo_mutex_lock(m) NVIC_DisableIRQ(m) +#define fifo_mutex_unlock(m) NVIC_EnableIRQ(m) + +/* Internal use only */ +#define _mutex_declare(m) .mutex = m + +#else + +#define _mutex_declare(m) + +#endif + +typedef struct _fifo_t +{ + uint8_t* const buffer ; ///< buffer pointer + uint16_t const depth ; ///< max items + uint16_t const item_size ; ///< size of each item + volatile uint16_t count ; ///< number of items in queue + volatile uint16_t wr_idx ; ///< write pointer + volatile uint16_t rd_idx ; ///< read pointer + bool const overwritable; + +#if CFG_FIFO_MUTEX + fifo_mutex_t const mutex; +#endif + +} fifo_t; + +/** + * Macro to declare a fifo + * @param name : name of the fifo + * @param depth : max number of items + * @param type : data type of item + * @param overwritable : whether fifo should be overwrite when full + * @param mutex : mutex object + */ +#define FIFO_DEF(_name, _depth, _type, _overwritable, _mutex)\ + _type _name##_buffer[_depth];\ + fifo_t _name##_fifo = {\ + .buffer = (uint8_t*) _name##_buffer,\ + .depth = _depth,\ + .item_size = sizeof(_type),\ + .overwritable = _overwritable,\ + _mutex_declare(_mutex)\ + };\ + fifo_t* _name = &_name##_fifo + + +void fifo_clear (fifo_t *f); + +bool fifo_write (fifo_t* f, void const * p_data); +uint16_t fifo_write_n (fifo_t* f, void const * p_data, uint16_t count); + +bool fifo_read (fifo_t* f, void * p_buffer); +uint16_t fifo_read_n (fifo_t* f, void * p_buffer, uint16_t count); + +bool fifo_peek_at (fifo_t* f, uint16_t position, void * p_buffer); +static inline bool fifo_peek(fifo_t* f, void * p_buffer) +{ + return fifo_peek_at(f, 0, p_buffer); +} + + +static inline bool fifo_empty(fifo_t* f) +{ + return (f->count == 0); +} + +static inline bool fifo_full(fifo_t* f) +{ + return (f->count == f->depth); +} + +static inline uint16_t fifo_count(fifo_t* f) +{ + return f->count; +} + +static inline uint16_t fifo_remaining(fifo_t* f) +{ + return f->depth - f->count; +} + +static inline uint16_t fifo_depth(fifo_t* f) +{ + return f->depth; +} + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ports/nrf/hal/hal_gpio.h b/ports/nrf/hal/hal_gpio.h index afd03d0dce514..5a86b25444aa0 100644 --- a/ports/nrf/hal/hal_gpio.h +++ b/ports/nrf/hal/hal_gpio.h @@ -45,8 +45,8 @@ #define GPIO_BASE(x) ((NRF_GPIO_Type *)POINTERS[x]) -#define hal_gpio_pin_high(p) (((NRF_GPIO_Type *)(GPIO_BASE((p)->port)))->OUTSET = (p)->pin_mask) -#define hal_gpio_pin_low(p) (((NRF_GPIO_Type *)(GPIO_BASE((p)->port)))->OUTCLR = (p)->pin_mask) +#define hal_gpio_pin_high(p) (((NRF_GPIO_Type *)(GPIO_BASE((p)->port)))->OUTSET = (1 << (p)->pin) ) +#define hal_gpio_pin_low(p) (((NRF_GPIO_Type *)(GPIO_BASE((p)->port)))->OUTCLR = (1 << (p)->pin) ) #define hal_gpio_pin_read(p) (((NRF_GPIO_Type *)(GPIO_BASE((p)->port)))->IN >> ((p)->pin) & 1) typedef enum { @@ -74,6 +74,28 @@ static inline void hal_gpio_cfg_pin(uint8_t port, uint32_t pin_number, hal_gpio_ | mode; } +static inline void hal_gpio_dir_set(uint8_t port, uint32_t pin, hal_gpio_mode_t mode) +{ + GPIO_BASE(port)->PIN_CNF[pin] &= ~GPIO_PIN_CNF_DIR_Msk; + GPIO_BASE(port)->PIN_CNF[pin] |= mode; +} + +static inline hal_gpio_mode_t hal_gpio_dir_get(uint8_t port, uint32_t pin) +{ + return GPIO_BASE(port)->PIN_CNF[pin] & GPIO_PIN_CNF_DIR_Msk; +} + +static inline void hal_gpio_pull_set(uint8_t port, uint32_t pin, hal_gpio_pull_t pull) +{ + GPIO_BASE(port)->PIN_CNF[pin] &= ~GPIO_PIN_CNF_PULL_Msk; + GPIO_BASE(port)->PIN_CNF[pin] |= pull; +} + +static inline hal_gpio_pull_t hal_gpio_pull_get(uint8_t port, uint32_t pin) +{ + return GPIO_BASE(port)->PIN_CNF[pin] & GPIO_PIN_CNF_PULL_Msk; +} + static inline void hal_gpio_out_set(uint8_t port, uint32_t pin_mask) { GPIO_BASE(port)->OUTSET = pin_mask; } @@ -90,6 +112,14 @@ static inline void hal_gpio_pin_clear(uint8_t port, uint32_t pin) { GPIO_BASE(port)->OUTCLR = (1 << pin); } +static inline void hal_gpio_pin_set_value(uint8_t port, uint32_t pin, uint8_t value) { + if (value) { + hal_gpio_pin_set(port, pin); + }else { + hal_gpio_pin_clear(port, pin); + } +} + static inline void hal_gpio_pin_toggle(uint8_t port, uint32_t pin) { uint32_t pin_mask = (1 << pin); uint32_t pins_state = NRF_GPIO->OUT; diff --git a/ports/nrf/hal/hal_uart.c b/ports/nrf/hal/hal_uart.c index 39590272b53ea..642ab0d920c6e 100644 --- a/ports/nrf/hal/hal_uart.c +++ b/ports/nrf/hal/hal_uart.c @@ -30,9 +30,12 @@ #include "nrf.h" #include "mphalport.h" #include "hal_uart.h" +#include "fifo.h" #ifdef HAL_UART_MODULE_ENABLED +FIFO_DEF(_ff_uart, 128, uint8_t, true, UARTE0_UART0_IRQn); + uint32_t hal_uart_baudrate_lookup[] = { UART_BAUDRATE_BAUDRATE_Baud1200, ///< 1200 baud. UART_BAUDRATE_BAUDRATE_Baud2400, ///< 2400 baud. @@ -66,15 +69,21 @@ hal_uart_error_t hal_uart_char_write(NRF_UART_Type * p_instance, uint8_t ch) { } hal_uart_error_t hal_uart_char_read(NRF_UART_Type * p_instance, uint8_t * ch) { - p_instance->ERRORSRC = 0; - while (p_instance->EVENTS_RXDRDY != 1) { - // Wait for RXD data. - } - - p_instance->EVENTS_RXDRDY = 0; - *ch = p_instance->RXD; - - return p_instance->ERRORSRC; +// p_instance->ERRORSRC = 0; +// while (p_instance->EVENTS_RXDRDY != 1) { +// // Wait for RXD data. +// } +// +// p_instance->EVENTS_RXDRDY = 0; +// *ch = p_instance->RXD; +// +// return p_instance->ERRORSRC; + + while ( !fifo_read(_ff_uart, ch) ) { + // wait for fifo data + } + + return HAL_UART_ERROR_NONE; } hal_uart_error_t hal_uart_buffer_write(NRF_UART_Type * p_instance, uint8_t * p_buffer, uint32_t num_of_bytes, uart_complete_cb cb) { @@ -106,6 +115,11 @@ hal_uart_error_t hal_uart_buffer_read(NRF_UART_Type * p_instance, uint8_t * p_bu return err; } +int hal_uart_available(NRF_UART_Type * p_instance) +{ + return fifo_count(_ff_uart); +} + void hal_uart_init(NRF_UART_Type * p_instance, hal_uart_init_t const * p_uart_init) { hal_gpio_cfg_pin(p_uart_init->tx_pin->port, p_uart_init->tx_pin->pin, HAL_GPIO_MODE_OUTPUT, HAL_GPIO_PULL_DISABLED); hal_gpio_cfg_pin(p_uart_init->tx_pin->port, p_uart_init->rx_pin->pin, HAL_GPIO_MODE_INPUT, HAL_GPIO_PULL_DISABLED); @@ -141,6 +155,27 @@ void hal_uart_init(NRF_UART_Type * p_instance, hal_uart_init_t const * p_uart_in p_instance->EVENTS_RXDRDY = 0; p_instance->TASKS_STARTTX = 1; p_instance->TASKS_STARTRX = 1; + + // Adafruit IRQ + fifo + fifo_clear(_ff_uart); + p_instance->INTENSET = UART_INTENSET_RXDRDY_Msk; + NVIC_ClearPendingIRQ(p_uart_init->irq_num); + NVIC_SetPriority(p_uart_init->irq_num, p_uart_init->irq_priority); + NVIC_EnableIRQ(p_uart_init->irq_num); +} + + +void UARTE0_UART0_IRQHandler(void) +{ + NRF_UART_Type * p_instance = NRF_UART0; + + if (p_instance->EVENTS_RXDRDY) + { + uint8_t ch = (uint8_t) p_instance->RXD; + fifo_write(_ff_uart, &ch); + + p_instance->EVENTS_RXDRDY = 0x0UL; + } } #endif // HAL_UART_MODULE_ENABLED diff --git a/ports/nrf/hal/hal_uart.h b/ports/nrf/hal/hal_uart.h index ca0110c3e48a4..76c09b335f408 100644 --- a/ports/nrf/hal/hal_uart.h +++ b/ports/nrf/hal/hal_uart.h @@ -121,5 +121,6 @@ void hal_uart_init(NRF_UART_Type * p_instance, hal_uart_init_t const * p_uart_in hal_uart_error_t hal_uart_char_write(NRF_UART_Type * p_instance, uint8_t ch); hal_uart_error_t hal_uart_char_read(NRF_UART_Type * p_instance, uint8_t * ch); +int hal_uart_available(NRF_UART_Type * p_instance); #endif // HAL_UART_H__ diff --git a/ports/nrf/internal_flash.c b/ports/nrf/internal_flash.c new file mode 100644 index 0000000000000..4a1faad564e17 --- /dev/null +++ b/ports/nrf/internal_flash.c @@ -0,0 +1,208 @@ +/* + * 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. + */ +#include "internal_flash.h" + +#include +#include + +#include "extmod/vfs.h" +#include "extmod/vfs_fat.h" +#include "py/mphal.h" +#include "py/obj.h" +#include "py/runtime.h" +#include "lib/oofatfs/ff.h" +#include "supervisor/shared/rgb_led_status.h" + +#include "nrf.h" +#include "nrf_soc.h" + +// defined in linker +extern uint32_t __fatfs_flash_start_addr[]; +extern uint32_t __fatfs_flash_length[]; + +void internal_flash_init(void) { + // Activity LED for flash writes. + #ifdef MICROPY_HW_LED_MSC + struct port_config pin_conf; + port_get_config_defaults(&pin_conf); + + pin_conf.direction = PORT_PIN_DIR_OUTPUT; + port_pin_set_config(MICROPY_HW_LED_MSC, &pin_conf); + port_pin_set_output_level(MICROPY_HW_LED_MSC, false); + #endif + + #ifdef SAMD51 + hri_mclk_set_AHBMASK_NVMCTRL_bit(MCLK); + #endif + #ifdef SAMD21 + _pm_enable_bus_clock(PM_BUS_APBB, NVMCTRL); + #endif +// flash_init(&internal_flash_desc, NVMCTRL); +} + +uint32_t internal_flash_get_block_size(void) { + return FILESYSTEM_BLOCK_SIZE; +} + +uint32_t internal_flash_get_block_count(void) { + return ((uint32_t) __fatfs_flash_length) / FILESYSTEM_BLOCK_SIZE ; +} + +void internal_flash_flush(void) { +} + +void flash_flush(void) { + internal_flash_flush(); +} + +static uint32_t convert_block_to_flash_addr(uint32_t block) { + return ((uint32_t)__fatfs_flash_start_addr) + block * FILESYSTEM_BLOCK_SIZE; +} + +bool internal_flash_write_block(const uint8_t *src, uint32_t block) { +#ifdef MICROPY_HW_LED_MSC + port_pin_set_output_level(MICROPY_HW_LED_MSC, true); +#endif + temp_status_color(ACTIVE_WRITE); + // non-MBR block, copy to cache + + uint32_t dest = convert_block_to_flash_addr(block); + + uint32_t pagenum = dest / FLASH_PAGE_SIZE; + uint8_t* flash_align = (uint8_t*) (pagenum*FLASH_PAGE_SIZE); + + // Read back current page to update only 512 portion + __ALIGN(4) uint8_t buf[FLASH_PAGE_SIZE]; + memcpy(buf, flash_align, FLASH_PAGE_SIZE); + memcpy(buf + (dest%FLASH_PAGE_SIZE), src, FILESYSTEM_BLOCK_SIZE); + + if (NRF_SUCCESS != sd_flash_page_erase(pagenum)) { + return false; + } + + if (NRF_SUCCESS != sd_flash_write((uint32_t*) flash_align, (uint32_t*) buf, FLASH_PAGE_SIZE/4)) { + return false; + } + + clear_temp_status(); +#ifdef MICROPY_HW_LED_MSC + port_pin_set_output_level(MICROPY_HW_LED_MSC, false); +#endif + return true; +} + +mp_uint_t internal_flash_read_blocks(uint8_t *dest, uint32_t block, uint32_t num_blocks) { + uint32_t src = convert_block_to_flash_addr(block); + memcpy(dest, (uint8_t*) src, FILESYSTEM_BLOCK_SIZE*num_blocks); + return 0; // success +} + +mp_uint_t internal_flash_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t num_blocks) { + for (size_t i = 0; i < num_blocks; i++) { + if (!internal_flash_write_block(src + i * FILESYSTEM_BLOCK_SIZE, block_num + i)) { + return 1; // error + } + } + return 0; // success +} + +/******************************************************************************/ +// MicroPython bindings +// +// Expose the flash as an object with the block protocol. + +// there is a singleton Flash object +STATIC const mp_obj_base_t internal_flash_obj = {&internal_flash_type}; + +STATIC mp_obj_t internal_flash_obj_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + // check arguments + mp_arg_check_num(n_args, n_kw, 0, 0, false); + + // return singleton object + return (mp_obj_t)&internal_flash_obj; +} + +STATIC mp_obj_t internal_flash_obj_readblocks(mp_obj_t self, mp_obj_t block_num, mp_obj_t buf) { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_WRITE); + mp_uint_t ret = internal_flash_read_blocks(bufinfo.buf, mp_obj_get_int(block_num), bufinfo.len / FILESYSTEM_BLOCK_SIZE); + return MP_OBJ_NEW_SMALL_INT(ret); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(internal_flash_obj_readblocks_obj, internal_flash_obj_readblocks); + +STATIC mp_obj_t internal_flash_obj_writeblocks(mp_obj_t self, mp_obj_t block_num, mp_obj_t buf) { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_READ); + mp_uint_t ret = internal_flash_write_blocks(bufinfo.buf, mp_obj_get_int(block_num), bufinfo.len / FILESYSTEM_BLOCK_SIZE); + return MP_OBJ_NEW_SMALL_INT(ret); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(internal_flash_obj_writeblocks_obj, internal_flash_obj_writeblocks); + +STATIC mp_obj_t internal_flash_obj_ioctl(mp_obj_t self, mp_obj_t cmd_in, mp_obj_t arg_in) { + mp_int_t cmd = mp_obj_get_int(cmd_in); + switch (cmd) { + case BP_IOCTL_INIT: internal_flash_init(); return MP_OBJ_NEW_SMALL_INT(0); + case BP_IOCTL_DEINIT: internal_flash_flush(); return MP_OBJ_NEW_SMALL_INT(0); // TODO properly + case BP_IOCTL_SYNC: internal_flash_flush(); return MP_OBJ_NEW_SMALL_INT(0); + case BP_IOCTL_SEC_COUNT: return MP_OBJ_NEW_SMALL_INT(internal_flash_get_block_count()); + case BP_IOCTL_SEC_SIZE: return MP_OBJ_NEW_SMALL_INT(internal_flash_get_block_size()); + default: return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(internal_flash_obj_ioctl_obj, internal_flash_obj_ioctl); + +STATIC const mp_rom_map_elem_t internal_flash_obj_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_readblocks), MP_ROM_PTR(&internal_flash_obj_readblocks_obj) }, + { MP_ROM_QSTR(MP_QSTR_writeblocks), MP_ROM_PTR(&internal_flash_obj_writeblocks_obj) }, + { MP_ROM_QSTR(MP_QSTR_ioctl), MP_ROM_PTR(&internal_flash_obj_ioctl_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(internal_flash_obj_locals_dict, internal_flash_obj_locals_dict_table); + +const mp_obj_type_t internal_flash_type = { + { &mp_type_type }, + .name = MP_QSTR_InternalFlash, + .make_new = internal_flash_obj_make_new, + .locals_dict = (mp_obj_t)&internal_flash_obj_locals_dict, +}; + +void flash_init_vfs(fs_user_mount_t *vfs) { + vfs->base.type = &mp_fat_vfs_type; + vfs->flags |= FSUSER_NATIVE | FSUSER_HAVE_IOCTL; + vfs->fatfs.drv = vfs; + +// vfs->fatfs.part = 1; // flash filesystem lives on first partition + vfs->readblocks[0] = (mp_obj_t)&internal_flash_obj_readblocks_obj; + vfs->readblocks[1] = (mp_obj_t)&internal_flash_obj; + vfs->readblocks[2] = (mp_obj_t)internal_flash_read_blocks; // native version + + vfs->writeblocks[0] = (mp_obj_t)&internal_flash_obj_writeblocks_obj; + vfs->writeblocks[1] = (mp_obj_t)&internal_flash_obj; + vfs->writeblocks[2] = (mp_obj_t)internal_flash_write_blocks; // native version + + vfs->u.ioctl[0] = (mp_obj_t)&internal_flash_obj_ioctl_obj; + vfs->u.ioctl[1] = (mp_obj_t)&internal_flash_obj; +} diff --git a/ports/nrf/internal_flash.h b/ports/nrf/internal_flash.h new file mode 100644 index 0000000000000..db41065fe5faf --- /dev/null +++ b/ports/nrf/internal_flash.h @@ -0,0 +1,61 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_ATMEL_SAMD_INTERNAL_FLASH_H +#define MICROPY_INCLUDED_ATMEL_SAMD_INTERNAL_FLASH_H + +#include +#include + +#include "mpconfigport.h" + +#define FLASH_ROOT_POINTERS + +#define FLASH_PAGE_SIZE 0x1000 +#define CIRCUITPY_INTERNAL_NVM_SIZE 0 + +#define INTERNAL_FLASH_SYSTICK_MASK (0x1ff) // 512ms +#define INTERNAL_FLASH_IDLE_TICK(tick) (((tick) & INTERNAL_FLASH_SYSTICK_MASK) == 2) + +void internal_flash_init(void); +uint32_t internal_flash_get_block_size(void); +uint32_t internal_flash_get_block_count(void); +void internal_flash_irq_handler(void); +void internal_flash_flush(void); +bool internal_flash_read_block(uint8_t *dest, uint32_t block); +bool internal_flash_write_block(const uint8_t *src, uint32_t block); + +// these return 0 on success, non-zero on error +mp_uint_t internal_flash_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_blocks); +mp_uint_t internal_flash_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t num_blocks); + +extern const struct _mp_obj_type_t internal_flash_type; + +struct _fs_user_mount_t; + +void flash_init_vfs(struct _fs_user_mount_t *vfs); +void flash_flush(void); + +#endif // MICROPY_INCLUDED_ATMEL_SAMD_INTERNAL_FLASH_H diff --git a/ports/nrf/main.c b/ports/nrf/main.c deleted file mode 100644 index 92f578cda1fab..0000000000000 --- a/ports/nrf/main.c +++ /dev/null @@ -1,265 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2013, 2014 Damien P. George - * Copyright (c) 2015 Glenn Ruben Bakke - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include -#include -#include - -#include "py/nlr.h" -#include "py/mperrno.h" -#include "py/lexer.h" -#include "py/parse.h" -#include "py/obj.h" -#include "py/runtime.h" -#include "py/stackctrl.h" -#include "py/gc.h" -#include "py/compile.h" -#include "lib/utils/pyexec.h" -#include "readline.h" -#include "gccollect.h" -#include "modmachine.h" -#include "modmusic.h" -#include "led.h" -#include "uart.h" -#include "nrf.h" -#include "pin.h" -#include "spi.h" -#include "i2c.h" -#include "rtc.h" -#if MICROPY_PY_MACHINE_HW_PWM -#include "pwm.h" -#endif -#include "timer.h" - -#if (MICROPY_PY_BLE_NUS) -#include "ble_uart.h" -#endif - -void do_str(const char *src, mp_parse_input_kind_t input_kind) { - mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0); - if (lex == NULL) { - printf("MemoryError: lexer could not allocate memory\n"); - return; - } - - nlr_buf_t nlr; - if (nlr_push(&nlr) == 0) { - qstr source_name = lex->source_name; - mp_parse_tree_t pn = mp_parse(lex, input_kind); - mp_obj_t module_fun = mp_compile(&pn, source_name, MP_EMIT_OPT_NONE, true); - mp_call_function_0(module_fun); - nlr_pop(); - } else { - // uncaught exception - mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val); - } -} - -extern uint32_t _heap_start; -extern uint32_t _heap_end; - -int main(int argc, char **argv) { - -soft_reset: - mp_stack_set_top(&_ram_end); - - // Stack limit should be less than real stack size, so we have a chance - // to recover from limit hit. (Limit is measured in bytes.) - mp_stack_set_limit((char*)&_ram_end - (char*)&_heap_end - 400); - - machine_init(); - - gc_init(&_heap_start, &_heap_end); - - mp_init(); - mp_obj_list_init(mp_sys_path, 0); - mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR_)); // current dir (or base dir of the script) - mp_obj_list_init(mp_sys_argv, 0); - - pyb_set_repl_info(MP_OBJ_NEW_SMALL_INT(0)); - - readline_init0(); - -#if MICROPY_PY_MACHINE_HW_SPI - spi_init0(); -#endif - -#if MICROPY_PY_MACHINE_I2C - i2c_init0(); -#endif - -#if MICROPY_PY_MACHINE_HW_PWM - pwm_init0(); -#endif - -#if MICROPY_PY_MACHINE_RTC - rtc_init0(); -#endif - -#if MICROPY_PY_MACHINE_TIMER - timer_init0(); -#endif - - uart_init0(); - -#if (MICROPY_PY_BLE_NUS == 0) - { - mp_obj_t args[2] = { - MP_OBJ_NEW_SMALL_INT(0), - MP_OBJ_NEW_SMALL_INT(115200), - }; - MP_STATE_PORT(pyb_stdio_uart) = machine_hard_uart_type.make_new((mp_obj_t)&machine_hard_uart_type, MP_ARRAY_SIZE(args), 0, args); - } -#endif - -pin_init0(); - -#if MICROPY_HW_HAS_SDCARD - // if an SD card is present then mount it on /sd/ - if (sdcard_is_present()) { - // create vfs object - fs_user_mount_t *vfs = m_new_obj_maybe(fs_user_mount_t); - if (vfs == NULL) { - goto no_mem_for_sd; - } - vfs->str = "/sd"; - vfs->len = 3; - vfs->flags = FSUSER_FREE_OBJ; - sdcard_init_vfs(vfs); - - // put the sd device in slot 1 (it will be unused at this point) - MP_STATE_PORT(fs_user_mount)[1] = vfs; - - FRESULT res = f_mount(&vfs->fatfs, vfs->str, 1); - if (res != FR_OK) { - printf("PYB: can't mount SD card\n"); - MP_STATE_PORT(fs_user_mount)[1] = NULL; - m_del_obj(fs_user_mount_t, vfs); - } else { - // TODO these should go before the /flash entries in the path - mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_sd)); - mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_sd_slash_lib)); - - // use SD card as current directory - f_chdrive("/sd"); - } - no_mem_for_sd:; - } -#endif - -#if (MICROPY_HW_HAS_LED) - led_init(); - - do_str("import pyb\r\n" \ - "pyb.LED(1).on()", - MP_PARSE_FILE_INPUT); -#endif - - // Main script is finished, so now go into REPL mode. - // The REPL mode can change, or it can request a soft reset. - int ret_code = 0; - -#if MICROPY_PY_BLE_NUS - ble_uart_init0(); - while (!ble_uart_enabled()) { - ; - } -#endif - - for (;;) { - if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) { - if (pyexec_raw_repl() != 0) { - break; - } - } else { - ret_code = pyexec_friendly_repl(); - if (ret_code != 0) { - break; - } - } - } - - mp_deinit(); - - if (ret_code == PYEXEC_FORCED_EXIT) { - NVIC_SystemReset(); - } else { - goto soft_reset; - } - - return 0; -} - -#if !MICROPY_VFS -mp_lexer_t *mp_lexer_new_from_file(const char *filename) { - mp_raise_OSError(MP_ENOENT); -} - -mp_import_stat_t mp_import_stat(const char *path) { - return MP_IMPORT_STAT_NO_EXIST; -} - -STATIC mp_obj_t mp_builtin_open(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { - mp_raise_OSError(MP_EPERM); -} -MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open); -#endif - -void HardFault_Handler(void) -{ -#if NRF52 - static volatile uint32_t reg; - static volatile uint32_t reg2; - static volatile uint32_t bfar; - reg = SCB->HFSR; - reg2 = SCB->CFSR; - bfar = SCB->BFAR; - for (int i = 0; i < 0; i++) - { - (void)reg; - (void)reg2; - (void)bfar; - } -#endif -} - -void NORETURN __fatal_error(const char *msg) { - while (1); -} - -void nlr_jump_fail(void *val) { - printf("FATAL: uncaught exception %p\n", val); - mp_obj_print_exception(&mp_plat_print, (mp_obj_t)val); - __fatal_error(""); -} - -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); - __fatal_error("Assertion failed"); -} - -void _start(void) {main(0, NULL);} diff --git a/ports/nrf/modules/machine/pin.c b/ports/nrf/modules/machine/pin.c index 62160d785ff1f..d7306a4991b06 100644 --- a/ports/nrf/modules/machine/pin.c +++ b/ports/nrf/modules/machine/pin.c @@ -194,7 +194,7 @@ STATIC void pin_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t mp_printf(print, "Pin(Pin.cpu.%q, mode=Pin.", self->name); mp_printf(print, "port=0x%x, ", self->port); mp_printf(print, "pin=0x%x, ", self->pin); - mp_printf(print, "pin_mask=0x%x,", self->pin_mask); +// mp_printf(print, "pin_mask=0x%x,", self->pin_mask); /* uint32_t mode = pin_get_mode(self); @@ -567,7 +567,7 @@ STATIC const mp_rom_map_elem_t pin_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_AF_OD), MP_ROM_INT(GPIO_MODE_AF_OD) }, { MP_ROM_QSTR(MP_QSTR_PULL_NONE), MP_ROM_INT(GPIO_NOPULL) }, */ -#include "genhdr/pins_af_const.h" +//#include "genhdr/pins_af_const.h" }; STATIC MP_DEFINE_CONST_DICT(pin_locals_dict, pin_locals_dict_table); diff --git a/ports/nrf/modules/machine/pin.h b/ports/nrf/modules/machine/pin.h index 1935a0d2634c4..117fb72896e7c 100644 --- a/ports/nrf/modules/machine/pin.h +++ b/ports/nrf/modules/machine/pin.h @@ -51,17 +51,21 @@ typedef struct { typedef struct { mp_obj_base_t base; qstr name; - uint32_t port : 4; - uint32_t pin : 5; // Some ARM processors use 32 bits/PORT - uint32_t num_af : 4; - uint32_t adc_channel : 5; // Some ARM processors use 32 bits/PORT - uint32_t adc_num : 3; // 1 bit per ADC - uint32_t pin_mask; + + uint32_t port : 1; + uint32_t pin : 5; // Some ARM processors use 32 bits/PORT + uint32_t num_af : 4; + uint32_t adc_channel : 4; // 0 is no ADC, ADC channel from 1 to 8 + +// uint32_t pin_mask; pin_gpio_t *gpio; const pin_af_obj_t *af; uint32_t pull; } pin_obj_t; +// Adafruit +extern const mp_obj_type_t mcu_pin_type; + extern const mp_obj_type_t pin_type; extern const mp_obj_type_t pin_af_type; @@ -84,8 +88,16 @@ typedef struct { extern const mp_obj_type_t pin_board_pins_obj_type; extern const mp_obj_type_t pin_cpu_pins_obj_type; -extern const mp_obj_dict_t pin_cpu_pins_locals_dict; -extern const mp_obj_dict_t pin_board_pins_locals_dict; +//extern const mp_obj_dict_t pin_cpu_pins_locals_dict; +//extern const mp_obj_dict_t pin_board_pins_locals_dict; + +// Adafruit modification for CircuitPython board module +extern const mp_obj_dict_t mcu_pin_globals; +extern const mp_obj_dict_t board_module_globals; + +#define pin_cpu_pins_locals_dict mcu_pin_globals +#define pin_board_pins_locals_dict board_module_globals + MP_DECLARE_CONST_FUN_OBJ_KW(pin_init_obj); diff --git a/ports/nrf/modules/machine/pwm.c b/ports/nrf/modules/machine/pwm.c index eaba96606f3ac..6a98677af1872 100644 --- a/ports/nrf/modules/machine/pwm.c +++ b/ports/nrf/modules/machine/pwm.c @@ -34,7 +34,8 @@ #if MICROPY_PY_MACHINE_HW_PWM #include "pin.h" -#include "genhdr/pins.h" +//#include "genhdr/pins.h" +#include "pins.h" #include "pwm.h" #if NRF52 diff --git a/ports/nrf/modules/machine/spi.c b/ports/nrf/modules/machine/spi.c index 0a82f1db52d50..5c097fd7657f2 100644 --- a/ports/nrf/modules/machine/spi.c +++ b/ports/nrf/modules/machine/spi.c @@ -33,7 +33,8 @@ #include "py/mphal.h" #include "extmod/machine_spi.h" #include "pin.h" -#include "genhdr/pins.h" +//#include "genhdr/pins.h" +#include "pins.h" #include "spi.h" #include "hal_spi.h" diff --git a/ports/nrf/modules/machine/uart.c b/ports/nrf/modules/machine/uart.c index b99afef6223d1..26b9ae7d360c1 100644 --- a/ports/nrf/modules/machine/uart.c +++ b/ports/nrf/modules/machine/uart.c @@ -35,7 +35,8 @@ #include "py/mperrno.h" #include "py/mphal.h" #include "pin.h" -#include "genhdr/pins.h" +//#include "genhdr/pins.h" +#include "pins.h" #include "uart.h" #include "mpconfigboard.h" @@ -65,6 +66,8 @@ void uart_init0(void) { // reset the UART handles memset(&UARTHandle0, 0, sizeof(UART_HandleTypeDef)); UARTHandle0.p_instance = UART_BASE(0); + UARTHandle0.init.irq_num = UARTE0_UART0_IRQn; + #if NRF52840_XXAA memset(&UARTHandle1, 0, sizeof(UART_HandleTypeDef)); UARTHandle0.p_instance = UART_BASE(1); @@ -82,13 +85,13 @@ STATIC int uart_find(mp_obj_t id) { "UART(%d) does not exist", uart_id)); } -void uart_irq_handler(mp_uint_t uart_id) { - -} +//void uart_irq_handler(mp_uint_t uart_id) { +// +//} bool uart_rx_any(machine_hard_uart_obj_t *uart_obj) { // TODO: uart will block for now. - return true; + return hal_uart_available(uart_obj->uart->p_instance) > 0; } int uart_rx_char(machine_hard_uart_obj_t * self) { diff --git a/ports/nrf/modules/uos/moduos.c b/ports/nrf/modules/uos/moduos.c deleted file mode 100644 index 21ea2cde677d6..0000000000000 --- a/ports/nrf/modules/uos/moduos.c +++ /dev/null @@ -1,174 +0,0 @@ -/* - * 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. - */ - -#include -#include - -#include "py/mpstate.h" -#include "py/runtime.h" -#include "py/objtuple.h" -#include "py/objstr.h" -#include "lib/oofatfs/ff.h" -#include "lib/oofatfs/diskio.h" -#include "extmod/vfs.h" -#include "extmod/vfs_fat.h" -#include "genhdr/mpversion.h" -//#include "timeutils.h" -//#include "rng.h" -#include "uart.h" -//#include "portmodules.h" - -/// \module os - basic "operating system" services -/// -/// The `os` module contains functions for filesystem access and `urandom`. -/// -/// The filesystem has `/` as the root directory, and the available physical -/// drives are accessible from here. They are currently: -/// -/// /flash -- the internal flash filesystem -/// /sd -- the SD card (if it exists) -/// -/// On boot up, the current directory is `/flash` if no SD card is inserted, -/// otherwise it is `/sd`. - -STATIC const qstr os_uname_info_fields[] = { - MP_QSTR_sysname, MP_QSTR_nodename, - MP_QSTR_release, MP_QSTR_version, MP_QSTR_machine -}; -STATIC const MP_DEFINE_STR_OBJ(os_uname_info_sysname_obj, "pyboard"); -STATIC const MP_DEFINE_STR_OBJ(os_uname_info_nodename_obj, "pyboard"); -STATIC const MP_DEFINE_STR_OBJ(os_uname_info_release_obj, MICROPY_VERSION_STRING); -STATIC const MP_DEFINE_STR_OBJ(os_uname_info_version_obj, MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE); -STATIC const MP_DEFINE_STR_OBJ(os_uname_info_machine_obj, MICROPY_HW_BOARD_NAME " with " MICROPY_HW_MCU_NAME); -STATIC MP_DEFINE_ATTRTUPLE( - os_uname_info_obj, - os_uname_info_fields, - 5, - (mp_obj_t)&os_uname_info_sysname_obj, - (mp_obj_t)&os_uname_info_nodename_obj, - (mp_obj_t)&os_uname_info_release_obj, - (mp_obj_t)&os_uname_info_version_obj, - (mp_obj_t)&os_uname_info_machine_obj -); - -STATIC mp_obj_t os_uname(void) { - return (mp_obj_t)&os_uname_info_obj; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_0(os_uname_obj, os_uname); - -#if MICROPY_VFS -/// \function sync() -/// Sync all filesystems. -STATIC mp_obj_t os_sync(void) { - for (mp_vfs_mount_t *vfs = MP_STATE_VM(vfs_mount_table); vfs != NULL; vfs = vfs->next) { - // this assumes that vfs->obj is fs_user_mount_t with block device functions - disk_ioctl(MP_OBJ_TO_PTR(vfs->obj), CTRL_SYNC, NULL); - } - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_0(mod_os_sync_obj, os_sync); -#endif - -#if MICROPY_HW_ENABLE_RNG -/// \function urandom(n) -/// Return a bytes object with n random bytes, generated by the hardware -/// random number generator. -STATIC mp_obj_t os_urandom(mp_obj_t num) { - mp_int_t n = mp_obj_get_int(num); - vstr_t vstr; - vstr_init_len(&vstr, n); - for (int i = 0; i < n; i++) { - vstr.buf[i] = rng_get(); - } - return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_urandom_obj, os_urandom); -#endif - -// Get or set the UART object that the REPL is repeated on. -// TODO should accept any object with read/write methods. -STATIC mp_obj_t os_dupterm(mp_uint_t n_args, const mp_obj_t *args) { - if (n_args == 0) { - if (MP_STATE_PORT(pyb_stdio_uart) == NULL) { - return mp_const_none; - } else { - return MP_STATE_PORT(pyb_stdio_uart); - } - } else { - if (args[0] == mp_const_none) { - MP_STATE_PORT(pyb_stdio_uart) = NULL; - } else if (mp_obj_get_type(args[0]) == &machine_hard_uart_type) { - MP_STATE_PORT(pyb_stdio_uart) = args[0]; - } else { - mp_raise_ValueError("need a UART object"); - } - return mp_const_none; - } -} -MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_os_dupterm_obj, 0, 1, os_dupterm); - -STATIC const mp_rom_map_elem_t os_module_globals_table[] = { - { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uos) }, - - { MP_ROM_QSTR(MP_QSTR_uname), MP_ROM_PTR(&os_uname_obj) }, - -#if MICROPY_VFS - { MP_ROM_QSTR(MP_QSTR_chdir), MP_ROM_PTR(&mp_vfs_chdir_obj) }, - { MP_ROM_QSTR(MP_QSTR_getcwd), MP_ROM_PTR(&mp_vfs_getcwd_obj) }, - { MP_ROM_QSTR(MP_QSTR_listdir), MP_ROM_PTR(&mp_vfs_listdir_obj) }, - { MP_ROM_QSTR(MP_QSTR_mkdir), MP_ROM_PTR(&mp_vfs_mkdir_obj) }, - { MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&mp_vfs_remove_obj) }, - { MP_ROM_QSTR(MP_QSTR_rename), MP_ROM_PTR(&mp_vfs_rename_obj) }, - { MP_ROM_QSTR(MP_QSTR_rmdir), MP_ROM_PTR(&mp_vfs_rmdir_obj) }, - { MP_ROM_QSTR(MP_QSTR_stat), MP_ROM_PTR(&mp_vfs_stat_obj) }, - { MP_ROM_QSTR(MP_QSTR_statvfs), MP_ROM_PTR(&mp_vfs_statvfs_obj) }, - { MP_ROM_QSTR(MP_QSTR_unlink), MP_ROM_PTR(&mp_vfs_remove_obj) }, // unlink aliases to remove - - { MP_ROM_QSTR(MP_QSTR_sync), MP_ROM_PTR(&mod_os_sync_obj) }, -#endif - - /// \constant sep - separation character used in paths - { MP_ROM_QSTR(MP_QSTR_sep), MP_ROM_QSTR(MP_QSTR__slash_) }, - -#if MICROPY_HW_ENABLE_RNG - { MP_ROM_QSTR(MP_QSTR_urandom), MP_ROM_PTR(&os_urandom_obj) }, -#endif - - // these are MicroPython extensions - { MP_ROM_QSTR(MP_QSTR_dupterm), MP_ROM_PTR(&mod_os_dupterm_obj) }, -#if MICROPY_VFS - { MP_ROM_QSTR(MP_QSTR_mount), MP_ROM_PTR(&mp_vfs_mount_obj) }, - { MP_ROM_QSTR(MP_QSTR_umount), MP_ROM_PTR(&mp_vfs_umount_obj) }, - { MP_ROM_QSTR(MP_QSTR_VfsFat), MP_ROM_PTR(&mp_fat_vfs_type) }, -#endif -}; - -STATIC MP_DEFINE_CONST_DICT(os_module_globals, os_module_globals_table); - -const mp_obj_module_t mp_module_uos = { - .base = { &mp_type_module }, - .globals = (mp_obj_dict_t*)&os_module_globals, -}; diff --git a/ports/nrf/mpconfigport.h b/ports/nrf/mpconfigport.h index 46ad669119db5..98ac14c3efb21 100644 --- a/ports/nrf/mpconfigport.h +++ b/ports/nrf/mpconfigport.h @@ -30,12 +30,8 @@ #include // options to control how MicroPython is built -#ifndef MICROPY_VFS -#define MICROPY_VFS (1) -#endif -#define MICROPY_VFS_FAT (MICROPY_VFS) #define MICROPY_ALLOC_PATH_MAX (512) -#define MICROPY_PERSISTENT_CODE_LOAD (0) +#define MICROPY_PERSISTENT_CODE_LOAD (1) #define MICROPY_EMIT_THUMB (0) #define MICROPY_EMIT_INLINE_THUMB (0) #define MICROPY_COMP_MODULE_CONST (0) @@ -48,6 +44,7 @@ #define MICROPY_REPL_EMACS_KEYS (0) #define MICROPY_REPL_AUTO_INDENT (1) #define MICROPY_ENABLE_SOURCE_LINE (0) +//CP UPDATE: See mpconfigport.h for LONGINT implementation #define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ) #if NRF51 #define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_NONE) @@ -64,7 +61,15 @@ #define MICROPY_FATFS_LFN_CODE_PAGE (437) /* 1=SFN/ANSI 437=LFN/U.S.(OEM) */ #define MICROPY_FATFS_USE_LABEL (1) #define MICROPY_FATFS_RPATH (2) -#define MICROPY_FATFS_MULTI_PARTITION (1) +#define MICROPY_FATFS_MULTI_PARTITION (0) +#define MICROPY_FATFS_NUM_PERSISTENT (1) + +//#define MICROPY_FATFS_MAX_SS (4096) + +#define FILESYSTEM_BLOCK_SIZE 512 + +#define MICROPY_VFS (1) +#define MICROPY_VFS_FAT (MICROPY_VFS) // TODO these should be generic, not bound to fatfs #define mp_type_fileio fatfs_type_fileio @@ -82,7 +87,7 @@ #define MICROPY_CAN_OVERRIDE_BUILTINS (1) #define MICROPY_USE_INTERNAL_ERRNO (1) #define MICROPY_PY_FUNCTION_ATTRS (1) -#define MICROPY_PY_BUILTINS_STR_UNICODE (0) +#define MICROPY_PY_BUILTINS_STR_UNICODE (1) #define MICROPY_PY_BUILTINS_STR_CENTER (0) #define MICROPY_PY_BUILTINS_STR_PARTITION (0) #define MICROPY_PY_BUILTINS_STR_SPLITLINES (0) @@ -203,19 +208,27 @@ typedef unsigned int mp_uint_t; // must be pointer size typedef long mp_off_t; // extra built in modules to add to the list of known ones + +extern const struct _mp_obj_module_t microcontroller_module; +extern const struct _mp_obj_module_t analogio_module; +extern const struct _mp_obj_module_t digitalio_module; +extern const struct _mp_obj_module_t pulseio_module; +extern const struct _mp_obj_module_t busio_module; +extern const struct _mp_obj_module_t board_module; +extern const struct _mp_obj_module_t os_module; +extern const struct _mp_obj_module_t random_module; +extern const struct _mp_obj_module_t storage_module; +extern const struct _mp_obj_module_t time_module; +extern const struct _mp_obj_module_t supervisor_module; + extern const struct _mp_obj_module_t pyb_module; extern const struct _mp_obj_module_t machine_module; extern const struct _mp_obj_module_t mp_module_utime; -extern const struct _mp_obj_module_t mp_module_uos; extern const struct _mp_obj_module_t mp_module_ubluepy; extern const struct _mp_obj_module_t music_module; extern const struct _mp_obj_module_t random_module; -#if MICROPY_PY_UBLUEPY -#define UBLUEPY_MODULE { MP_ROM_QSTR(MP_QSTR_ubluepy), MP_ROM_PTR(&mp_module_ubluepy) }, -#else -#define UBLUEPY_MODULE -#endif +extern const struct _mp_obj_module_t ble_module; #if MICROPY_PY_MUSIC #define MUSIC_MODULE { MP_ROM_QSTR(MP_QSTR_music), MP_ROM_PTR(&music_module) }, @@ -229,7 +242,11 @@ extern const struct _mp_obj_module_t random_module; #define RANDOM_MODULE #endif -#if BLUETOOTH_SD +#if MICROPY_PY_UBLUEPY +#define UBLUEPY_MODULE { MP_ROM_QSTR(MP_QSTR_ubluepy), MP_ROM_PTR(&mp_module_ubluepy) }, +#else +#define UBLUEPY_MODULE +#endif #if MICROPY_PY_BLE extern const struct _mp_obj_module_t ble_module; @@ -239,32 +256,28 @@ extern const struct _mp_obj_module_t ble_module; #endif #define MICROPY_PORT_BUILTIN_MODULES \ + { MP_OBJ_NEW_QSTR(MP_QSTR_board), (mp_obj_t)&board_module }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_busio), (mp_obj_t)&busio_module }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_analogio), (mp_obj_t)&analogio_module }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_digitalio), (mp_obj_t)&digitalio_module }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_pulseio), (mp_obj_t)&pulseio_module }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_microcontroller), (mp_obj_t)µcontroller_module }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_os), (mp_obj_t)&os_module }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_random), (mp_obj_t)&random_module }, \ + /*{ MP_OBJ_NEW_QSTR(MP_QSTR_storage), (mp_obj_t)&storage_module },*/\ { MP_ROM_QSTR(MP_QSTR_pyb), MP_ROM_PTR(&pyb_module) }, \ { MP_ROM_QSTR(MP_QSTR_machine), MP_ROM_PTR(&machine_module) }, \ { MP_ROM_QSTR(MP_QSTR_utime), MP_ROM_PTR(&mp_module_utime) }, \ - { MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&mp_module_utime) }, \ - { MP_ROM_QSTR(MP_QSTR_uos), MP_ROM_PTR(&mp_module_uos) }, \ - BLE_MODULE \ - MUSIC_MODULE \ - UBLUEPY_MODULE \ - RANDOM_MODULE \ - - -#else -extern const struct _mp_obj_module_t ble_module; -#define MICROPY_PORT_BUILTIN_MODULES \ - { MP_ROM_QSTR(MP_QSTR_pyb), MP_ROM_PTR(&pyb_module) }, \ - { MP_ROM_QSTR(MP_QSTR_machine), MP_ROM_PTR(&machine_module) }, \ - { MP_ROM_QSTR(MP_QSTR_utime), MP_ROM_PTR(&mp_module_utime) }, \ - { MP_ROM_QSTR(MP_QSTR_uos), MP_ROM_PTR(&mp_module_uos) }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_supervisor), (mp_obj_t)&supervisor_module }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_time), (mp_obj_t)&time_module }, \ MUSIC_MODULE \ RANDOM_MODULE \ + /*BLE_MODULE \ + UBLUEPY_MODULE \*/ -#endif // BLUETOOTH_SD #define MICROPY_PORT_BUILTIN_MODULE_WEAK_LINKS \ - { MP_ROM_QSTR(MP_QSTR_os), MP_ROM_PTR(&mp_module_uos) }, \ { MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&mp_module_utime) }, \ // extra built in names to add to the global namespace @@ -308,5 +321,6 @@ extern const struct _mp_obj_module_t ble_module; #include #define MICROPY_PIN_DEFS_PORT_H "pin_defs_nrf5.h" +#define CIRCUITPY_BOOT_OUTPUT_FILE "/boot_out.txt" #endif diff --git a/ports/nrf/mpconfigport.mk b/ports/nrf/mpconfigport.mk new file mode 100644 index 0000000000000..dc29a92cf5915 --- /dev/null +++ b/ports/nrf/mpconfigport.mk @@ -0,0 +1,4 @@ +# Define an equivalent for MICROPY_LONGINT_IMPL, to pass to $(MPY-TOOL) in py/mkrules.mk +# $(MPY-TOOL) needs to know what kind of longint to use (if any) to freeze long integers. +# This should correspond to the MICROPY_LONGINT_IMPL definition in mpconfigport.h. +MPY_TOOL_LONGINT_IMPL = -mlongint-impl=mpz diff --git a/ports/nrf/mphalport.c b/ports/nrf/mphalport.c index 1abd4b186a707..f6e7748279e85 100644 --- a/ports/nrf/mphalport.c +++ b/ports/nrf/mphalport.c @@ -32,6 +32,8 @@ #include "py/mperrno.h" #include "uart.h" +FIL* boot_output_file; + // this table converts from HAL_StatusTypeDef to POSIX errno const byte mp_hal_status_to_errno_table[4] = { [HAL_OK] = 0, @@ -59,6 +61,11 @@ int mp_hal_stdin_rx_chr(void) { return 0; } +bool mp_hal_stdin_any(void) +{ + return uart_rx_any(MP_STATE_PORT(pyb_stdio_uart)); +} + void mp_hal_stdout_tx_strn(const char *str, mp_uint_t len) { if (MP_STATE_PORT(pyb_stdio_uart) != NULL) { uart_tx_strn(MP_STATE_PORT(pyb_stdio_uart), str, len); diff --git a/ports/nrf/mphalport.h b/ports/nrf/mphalport.h index 4e4e117033873..3334fd7fe96a7 100644 --- a/ports/nrf/mphalport.h +++ b/ports/nrf/mphalport.h @@ -32,6 +32,8 @@ #include "pin.h" #include "hal_gpio.h" +#include "lib/oofatfs/ff.h" + typedef enum { HAL_OK = 0x00, @@ -40,6 +42,8 @@ typedef enum HAL_TIMEOUT = 0x03 } HAL_StatusTypeDef; +extern FIL* boot_output_file; + static inline uint32_t hal_tick_fake(void) { return 0; } @@ -53,6 +57,7 @@ void mp_hal_set_interrupt_char(int c); // -1 to disable int mp_hal_stdin_rx_chr(void); void mp_hal_stdout_tx_str(const char *str); +bool mp_hal_stdin_any(void); #define mp_hal_pin_obj_t const pin_obj_t* #define mp_hal_get_pin_obj(o) pin_find(o) diff --git a/ports/nrf/supervisor/filesystem.c b/ports/nrf/supervisor/filesystem.c new file mode 100644 index 0000000000000..5d622725b448c --- /dev/null +++ b/ports/nrf/supervisor/filesystem.c @@ -0,0 +1,88 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * 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 + * 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 "extmod/vfs_fat.h" +#include "lib/oofatfs/ff.h" +#include "lib/oofatfs/diskio.h" + +#include "py/mpstate.h" + +#include "internal_flash.h" + +fs_user_mount_t fs_user_mount_flash; +mp_vfs_mount_t mp_vfs_mount_flash; + + +void filesystem_init(bool create_allowed) { + // init the vfs object + fs_user_mount_t *vfs_fat = &fs_user_mount_flash; + vfs_fat->flags = 0; + flash_init_vfs(vfs_fat); + + // try to mount the flash + FRESULT res = f_mount(&vfs_fat->fatfs); + + if (res == FR_NO_FILESYSTEM && create_allowed) { + // no filesystem so create a fresh one + uint8_t working_buf[_MAX_SS]; + res = f_mkfs(&vfs_fat->fatfs, FM_FAT | FM_SFD, 4096, working_buf, sizeof(working_buf)); + // Flush the new file system to make sure its repaired immediately. + flash_flush(); + if (res != FR_OK) { + return; + } + + // set label + f_setlabel(&vfs_fat->fatfs, "CIRCUITPY"); + flash_flush(); + + // create lib folder + f_mkdir(&vfs_fat->fatfs, "/lib"); + } else if (res != FR_OK) { + return; + } + mp_vfs_mount_t *vfs = &mp_vfs_mount_flash; + vfs->str = "/"; + vfs->len = 1; + vfs->obj = MP_OBJ_FROM_PTR(vfs_fat); + vfs->next = NULL; + MP_STATE_VM(vfs_mount_table) = vfs; + + // The current directory is used as the boot up directory. + // It is set to the internal flash filesystem by default. + MP_STATE_PORT(vfs_cur) = vfs; +} + +void filesystem_flush(void) { + flash_flush(); +} + +void filesystem_writable_by_python(bool writable) { +} + +bool filesystem_present(void) { + return true; +} diff --git a/ports/nrf/supervisor/port.c b/ports/nrf/supervisor/port.c new file mode 100644 index 0000000000000..4ac9c08e018bd --- /dev/null +++ b/ports/nrf/supervisor/port.c @@ -0,0 +1,79 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * 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 + * 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 +#include "supervisor/port.h" +#include "boards/board.h" + +#include "common-hal/microcontroller/Pin.h" +#include "common-hal/pulseio/PWMOut.h" + +safe_mode_t port_init(void) { + board_init(); + +#if 0 + // Configure millisecond timer initialization. + tick_init(); + + #ifdef CIRCUITPY_CANARY_WORD + // Run in safe mode if the canary is corrupt. + if (_ezero != CIRCUITPY_CANARY_WORD) { + return HARD_CRASH; + } + #endif + + if (board_requests_safe_mode()) { + return USER_SAFE_MODE; + } +#endif + + return NO_SAFE_MODE; +} + +void reset_port(void) { + pwmout_reset(); + reset_all_pins(); +} + + +void HardFault_Handler(void) +{ +#if NRF52 +// static volatile uint32_t reg; +// static volatile uint32_t reg2; +// static volatile uint32_t bfar; +// reg = SCB->HFSR; +// reg2 = SCB->CFSR; +// bfar = SCB->BFAR; +// for (int i = 0; i < 0; i++) +// { +// (void)reg; +// (void)reg2; +// (void)bfar; +// } +#endif +} + diff --git a/ports/nrf/supervisor/serial.c b/ports/nrf/supervisor/serial.c new file mode 100644 index 0000000000000..0b844fa01814f --- /dev/null +++ b/ports/nrf/supervisor/serial.c @@ -0,0 +1,59 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * 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 + * 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 "supervisor/serial.h" + +#include "py/obj.h" +#include "py/runtime.h" +#include "mphalport.h" +#include "uart.h" + +void serial_init(void) { + uart_init0(); + + mp_obj_t args[2] = { + MP_OBJ_NEW_SMALL_INT(0), + MP_OBJ_NEW_SMALL_INT(115200), + }; + MP_STATE_PORT(pyb_stdio_uart) = machine_hard_uart_type.make_new((mp_obj_t)&machine_hard_uart_type, MP_ARRAY_SIZE(args), 0, args); +} + +bool serial_connected(void) { + return true; +} + +char serial_read(void) { + return (char) mp_hal_stdin_rx_chr(); +} + +bool serial_bytes_available(void) { + return mp_hal_stdin_any(); +} + +void serial_write(const char* text) { + mp_hal_stdout_tx_str(text); +} + diff --git a/supervisor/port.h b/supervisor/port.h index 2f7bc64448bca..f30d87b47b47c 100644 --- a/supervisor/port.h +++ b/supervisor/port.h @@ -57,4 +57,8 @@ void reset_port(void); // Reset the rest of the board. void reset_board(void); +#ifdef NRF52_SERIES +void HardFault_Handler(void); +#endif + #endif // MICROPY_INCLUDED_SUPERVISOR_PORT_H From 99dd0a61ff478718d540760f63f8e2c59839bde0 Mon Sep 17 00:00:00 2001 From: microbuilder Date: Fri, 22 Dec 2017 11:29:39 +0100 Subject: [PATCH 02/20] Spaces to tabs --- ports/nrf/Makefile | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/ports/nrf/Makefile b/ports/nrf/Makefile index 3ae298962197f..4b91548aa7e55 100644 --- a/ports/nrf/Makefile +++ b/ports/nrf/Makefile @@ -17,10 +17,10 @@ ifeq ($(SD), ) include ../../py/mkenv.mk include boards/$(BOARD)/mpconfigboard.mk -include mpconfigport.mk - -INC += -Idrivers/bluetooth/s132_$(MCU_VARIANT)_$(SOFTDEV_VERSION)/s132_$(MCU_VARIANT)_$(SOFTDEV_VERSION)_API/include -INC += -Idrivers/bluetooth/s132_$(MCU_VARIANT)_$(SOFTDEV_VERSION)/s132_$(MCU_VARIANT)_$(SOFTDEV_VERSION)_API/include/$(MCU_VARIANT) - + +INC += -Idrivers/bluetooth/s132_$(MCU_VARIANT)_$(SOFTDEV_VERSION)/s132_$(MCU_VARIANT)_$(SOFTDEV_VERSION)_API/include +INC += -Idrivers/bluetooth/s132_$(MCU_VARIANT)_$(SOFTDEV_VERSION)/s132_$(MCU_VARIANT)_$(SOFTDEV_VERSION)_API/include/$(MCU_VARIANT) + else # If the build directory is not given, make it reflect the board name. BUILD ?= build-$(BOARD)-$(SD_LOWER) @@ -137,25 +137,25 @@ SRC_C += \ help.c \ pin_named_pins.c \ fatfs_port.c \ - fifo.c \ + fifo.c \ drivers/softpwm.c \ drivers/ticker.c \ drivers/bluetooth/ble_drv.c \ drivers/bluetooth/ble_uart.c \ - boards/$(BOARD)/board.c \ - boards/$(BOARD)/pins.c \ + boards/$(BOARD)/board.c \ + boards/$(BOARD)/pins.c \ device/$(MCU_VARIANT)/system_$(MCU_SUB_VARIANT).c \ device/$(MCU_VARIANT)/startup_$(MCU_SUB_VARIANT).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/timeutils/timeutils.c \ + lib/utils/buffer_helper.c \ + lib/utils/context_manager_helpers.c \ + lib/utils/pyexec.c \ lib/libc/string0.c \ lib/mp-readline/readline.c \ - internal_flash.c \ - + internal_flash.c \ + DRIVERS_SRC_C += $(addprefix modules/,\ machine/modmachine.c \ @@ -186,27 +186,27 @@ DRIVERS_SRC_C += $(addprefix modules/,\ random/modrandom.c \ ) - + SRC_COMMON_HAL += \ - board/__init__.c \ + board/__init__.c \ digitalio/__init__.c \ digitalio/DigitalInOut.c \ microcontroller/__init__.c \ microcontroller/Pin.c \ microcontroller/Processor.c \ os/__init__.c \ - time/__init__.c \ + time/__init__.c \ analogio/__init__.c \ analogio/AnalogIn.c \ analogio/AnalogOut.c \ busio/__init__.c\ busio/I2C.c \ busio/SPI.c \ - pulseio/__init__.c \ + pulseio/__init__.c \ pulseio/PulseIn.c \ pulseio/PulseOut.c \ - pulseio/PWMOut.c \ - storage/__init__.c \ + pulseio/PWMOut.c \ + storage/__init__.c \ # These don't have corresponding files in each port but are still located in # shared-bindings to make it clear what the contents of the modules are. From c868b66f5bdfb11db58edb62747e5d8beac3c91e Mon Sep 17 00:00:00 2001 From: microbuilder Date: Fri, 22 Dec 2017 11:33:17 +0100 Subject: [PATCH 03/20] Minor typo removed in path --- ports/nrf/boards/feather52/README.md | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/ports/nrf/boards/feather52/README.md b/ports/nrf/boards/feather52/README.md index 2a28206246023..d5e00262256a5 100644 --- a/ports/nrf/boards/feather52/README.md +++ b/ports/nrf/boards/feather52/README.md @@ -35,7 +35,7 @@ commands: you can install pip via 'sudo easy_install pip' ``` -$ cd ../../libs/nrfutil +$ cd ../../lib/nrfutil $ sudo pip install -r requirements.txt $ sudo python setup.py install ``` @@ -55,15 +55,6 @@ To build a CircuitPython binary with default settings for the $ make BOARD=feather52 V=1 ``` -#### REPL over BLE support - -To build a CircuitPython binary with BLE support (S132) include `SD=s132` -as part of the build process: - -``` -$ make BOARD=feather52 V=1 SD=s132 -``` - ## Flashing binaries with `nrfutil` ### 1. **Update bootloader** to single-bank version From 393bc9bce92f6d595187711e5c3639e65bc9e304 Mon Sep 17 00:00:00 2001 From: microbuilder Date: Fri, 22 Dec 2017 11:39:40 +0100 Subject: [PATCH 04/20] Removed leftover code snippet --- ports/nrf/boards/feather52/board.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/ports/nrf/boards/feather52/board.c b/ports/nrf/boards/feather52/board.c index 0f4cf4e3059e2..c550e906145d9 100644 --- a/ports/nrf/boards/feather52/board.c +++ b/ports/nrf/boards/feather52/board.c @@ -31,13 +31,6 @@ #include "boards/board.h" -#if 0 -#include "common-hal/microcontroller/Pin.h" -#include "hal/include/hal_gpio.h" -#include "shared-bindings/digitalio/DigitalInOut.h" -#include "shared-bindings/neopixel_write/__init__.h" -#endif - // Must match temp register in bootloader #define BOOTLOADER_VERSION_REGISTER NRF_TIMER2->CC[0] uint32_t bootloaderVersion = 0; @@ -119,4 +112,3 @@ void reset_board(void) { // common_hal_neopixel_write(&neopixel_pin, empty, 30); // common_hal_digitalio_digitalinout_deinit(&neopixel_pin); } - From a3289c3c2f36e2919f94b82f3a3221eab8d67ab1 Mon Sep 17 00:00:00 2001 From: microbuilder Date: Fri, 22 Dec 2017 11:42:33 +0100 Subject: [PATCH 05/20] Added D13 for standard LED examples --- ports/nrf/boards/feather52/pins.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/nrf/boards/feather52/pins.c b/ports/nrf/boards/feather52/pins.c index e8c006802fccf..d718276493f8c 100644 --- a/ports/nrf/boards/feather52/pins.c +++ b/ports/nrf/boards/feather52/pins.c @@ -120,5 +120,6 @@ STATIC const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_A5 ), MP_ROM_PTR(&pin_PA29) }, { MP_ROM_QSTR(MP_QSTR_A6 ), MP_ROM_PTR(&pin_PA30) }, { MP_ROM_QSTR(MP_QSTR_A7 ), MP_ROM_PTR(&pin_PA31) }, + { MP_ROM_QSTR(MP_QSTR_D13 ), MP_ROM_PTR(&pin_PA17) }, // LED for stdrd exmpl }; MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); From ace872bf113c099cdb162eb1016106ea705317d5 Mon Sep 17 00:00:00 2001 From: microbuilder Date: Fri, 22 Dec 2017 11:45:51 +0100 Subject: [PATCH 06/20] Added 'mp_raise_NotImplementedError(NULL)' --- ports/nrf/common-hal/pulseio/PulseIn.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/nrf/common-hal/pulseio/PulseIn.c b/ports/nrf/common-hal/pulseio/PulseIn.c index 19e7dbba3665c..c343bffac6870 100644 --- a/ports/nrf/common-hal/pulseio/PulseIn.c +++ b/ports/nrf/common-hal/pulseio/PulseIn.c @@ -47,7 +47,7 @@ void pulsein_reset(void) { } void common_hal_pulseio_pulsein_construct(pulseio_pulsein_obj_t* self, const mcu_pin_obj_t* pin, uint16_t maxlen, bool idle_state) { - + mp_raise_NotImplementedError(NULL); } bool common_hal_pulseio_pulsein_deinited(pulseio_pulsein_obj_t* self) { From b9e229f739e78d35898cede74d604cf01a5f9487 Mon Sep 17 00:00:00 2001 From: microbuilder Date: Fri, 22 Dec 2017 11:47:15 +0100 Subject: [PATCH 07/20] Removed old code snippets --- ports/nrf/common-hal/pulseio/PulseIn.c | 208 ------------------------- 1 file changed, 208 deletions(-) diff --git a/ports/nrf/common-hal/pulseio/PulseIn.c b/ports/nrf/common-hal/pulseio/PulseIn.c index c343bffac6870..a6f1bf10d6d70 100644 --- a/ports/nrf/common-hal/pulseio/PulseIn.c +++ b/ports/nrf/common-hal/pulseio/PulseIn.c @@ -85,211 +85,3 @@ uint16_t common_hal_pulseio_pulsein_get_len(pulseio_pulsein_obj_t* self) { uint16_t common_hal_pulseio_pulsein_get_item(pulseio_pulsein_obj_t* self, int16_t index) { return 0xadaf; } - - -#if 0 - -static pulseio_pulsein_obj_t *active_pulseins[EIC_NUMBER_OF_INTERRUPTS]; -static uint64_t last_ms[EIC_NUMBER_OF_INTERRUPTS]; -static uint16_t last_us[EIC_NUMBER_OF_INTERRUPTS]; - -void pulsein_reset(void) { - for (int i = 0; i < EIC_NUMBER_OF_INTERRUPTS; i++) { - if (active_pulseins[i] != NULL) { - extint_chan_disable_callback(i, EXTINT_CALLBACK_TYPE_DETECT); - } - active_pulseins[i] = NULL; - last_ms[i] = 0; - last_us[i] = 0; - } -} - -static void pulsein_set_config(pulseio_pulsein_obj_t* self, bool first_edge) { - struct extint_chan_conf config; - extint_chan_get_config_defaults(&config); - config.gpio_pin = self->pin; - config.gpio_pin_pull = EXTINT_PULL_NONE; - config.filter_input_signal = true; - - if (!first_edge) { - config.detection_criteria = EXTINT_DETECT_BOTH; - } else if (self->idle_state) { - config.detection_criteria = EXTINT_DETECT_FALLING; - } else { - config.detection_criteria = EXTINT_DETECT_RISING; - } - extint_chan_disable_callback(self->channel, EXTINT_CALLBACK_TYPE_DETECT); - extint_chan_set_config(self->channel, &config); - // Clear any interrupts that may have triggered without notifying the CPU. - EIC->INTFLAG.reg |= (1UL << self->channel); - extint_chan_enable_callback(self->channel, EXTINT_CALLBACK_TYPE_DETECT); -} - -static void pulsein_callback(void) { - // Grab the current time first. - uint16_t current_us = tc_get_count_value(&ms_timer); - // Add the overflow flag to account for tick interrupts that are blocked by - // this interrupt. - uint64_t current_ms = ticks_ms + TC5->COUNT16.INTFLAG.bit.OVF; - pulseio_pulsein_obj_t* self = active_pulseins[extint_get_current_channel()]; - current_us = current_us * 1000 / self->ticks_per_ms; - if (self->first_edge) { - self->first_edge = false; - pulsein_set_config(self, false); - } else { - uint32_t ms_diff = current_ms - last_ms[self->channel]; - uint16_t us_diff = current_us - last_us[self->channel]; - uint32_t total_diff = us_diff; - if (last_us[self->channel] > current_us) { - total_diff = 1000 + current_us - last_us[self->channel]; - if (ms_diff > 1) { - total_diff += (ms_diff - 1) * 1000; - } - } else { - total_diff += ms_diff * 1000; - } - uint16_t duration = 0xffff; - if (total_diff < duration) { - duration = total_diff; - } - - uint16_t i = (self->start + self->len) % self->maxlen; - self->buffer[i] = duration; - if (self->len < self->maxlen) { - self->len++; - } else { - self->start++; - } - } - last_ms[self->channel] = current_ms; - last_us[self->channel] = current_us; -} - -void common_hal_pulseio_pulsein_construct(pulseio_pulsein_obj_t* self, - const mcu_pin_obj_t* pin, uint16_t maxlen, bool idle_state) { - if (!pin->has_extint) { - mp_raise_RuntimeError("No hardware support on pin"); - } - // TODO(tannewt): Switch to checking actual extint peripheral state when other - // classes use extints. - if (active_pulseins[pin->extint_channel] != NULL) { - mp_raise_RuntimeError("EXTINT channel already in use"); - } - - self->buffer = (uint16_t *) gc_alloc(maxlen * sizeof(uint16_t), false); - if (self->buffer == NULL) { - mp_raise_msg_varg(&mp_type_MemoryError, "Failed to allocate RX buffer of %d bytes", maxlen * sizeof(uint16_t)); - } - self->channel = pin->extint_channel; - self->pin = pin->pin; - self->maxlen = maxlen; - self->idle_state = idle_state; - self->start = 0; - self->len = 0; - self->first_edge = true; - self->ticks_per_ms = (system_cpu_clock_get_hz() / 1000 - 1); - - active_pulseins[pin->extint_channel] = self; - - pulsein_set_config(self, true); - extint_register_callback( - pulsein_callback, - self->channel, - EXTINT_CALLBACK_TYPE_DETECT); - extint_chan_enable_callback(self->channel, EXTINT_CALLBACK_TYPE_DETECT); -} - -bool common_hal_pulseio_pulsein_deinited(pulseio_pulsein_obj_t* self) { - return self->pin == NO_PIN; -} - -void common_hal_pulseio_pulsein_deinit(pulseio_pulsein_obj_t* self) { - if (common_hal_pulseio_pulsein_deinited(self)) { - return; - } - extint_chan_disable_callback(self->channel, EXTINT_CALLBACK_TYPE_DETECT); - active_pulseins[self->channel] = NULL; - reset_pin(self->pin); - self->pin = NO_PIN; -} - -void common_hal_pulseio_pulsein_pause(pulseio_pulsein_obj_t* self) { - extint_chan_disable_callback(self->channel, EXTINT_CALLBACK_TYPE_DETECT); -} - -void common_hal_pulseio_pulsein_resume(pulseio_pulsein_obj_t* self, - uint16_t trigger_duration) { - // Send the trigger pulse. - if (trigger_duration > 0) { - struct port_config pin_conf; - port_get_config_defaults(&pin_conf); - - pin_conf.direction = PORT_PIN_DIR_OUTPUT; - pin_conf.input_pull = PORT_PIN_PULL_NONE; - port_pin_set_config(self->pin, &pin_conf); - - // TODO(tannewt): delay_us isn't exactly correct so we adjust the value - // here before calling it. Find out why its not exact and fix it instead - // of hacking around it here. - uint32_t adjusted_duration = trigger_duration; - adjusted_duration *= 4; - adjusted_duration /= 5; - - common_hal_mcu_disable_interrupts(); - port_pin_set_output_level(self->pin, !self->idle_state); - common_hal_mcu_delay_us(adjusted_duration); - port_pin_set_output_level(self->pin, self->idle_state); - common_hal_mcu_enable_interrupts(); - } - - // Reconfigure the pin and make sure its set to detect the first edge. - last_ms[self->channel] = 0; - last_us[self->channel] = 0; - self->first_edge = true; - pulsein_set_config(self, true); -} - -void common_hal_pulseio_pulsein_clear(pulseio_pulsein_obj_t* self) { - common_hal_mcu_disable_interrupts(); - self->start = 0; - self->len = 0; - common_hal_mcu_enable_interrupts(); -} - -uint16_t common_hal_pulseio_pulsein_popleft(pulseio_pulsein_obj_t* self) { - if (self->len == 0) { - mp_raise_IndexError("pop from an empty PulseIn"); - } - common_hal_mcu_disable_interrupts(); - uint16_t value = self->buffer[self->start]; - self->start = (self->start + 1) % self->maxlen; - self->len--; - common_hal_mcu_enable_interrupts(); - - return value; -} - -uint16_t common_hal_pulseio_pulsein_get_maxlen(pulseio_pulsein_obj_t* self) { - return self->maxlen; -} - -uint16_t common_hal_pulseio_pulsein_get_len(pulseio_pulsein_obj_t* self) { - return self->len; -} - -uint16_t common_hal_pulseio_pulsein_get_item(pulseio_pulsein_obj_t* self, - int16_t index) { - common_hal_mcu_disable_interrupts(); - if (index < 0) { - index += self->len; - } - if (index < 0 || index >= self->len) { - common_hal_mcu_enable_interrupts(); - mp_raise_IndexError("index out of range"); - } - uint16_t value = self->buffer[(self->start + index) % self->maxlen]; - common_hal_mcu_enable_interrupts(); - return value; -} - -#endif From ad7cd0399d4b692891c1ad82e7753721dfc4d8db Mon Sep 17 00:00:00 2001 From: microbuilder Date: Fri, 22 Dec 2017 11:48:07 +0100 Subject: [PATCH 08/20] Added 'mp_raise_NotImplementedError(NULL)' --- ports/nrf/common-hal/pulseio/PulseOut.c | 146 +----------------------- 1 file changed, 1 insertion(+), 145 deletions(-) diff --git a/ports/nrf/common-hal/pulseio/PulseOut.c b/ports/nrf/common-hal/pulseio/PulseOut.c index b6ddeca445b09..dbeaf6b07a4b8 100644 --- a/ports/nrf/common-hal/pulseio/PulseOut.c +++ b/ports/nrf/common-hal/pulseio/PulseOut.c @@ -46,7 +46,7 @@ void pulseout_reset() { } void common_hal_pulseio_pulseout_construct(pulseio_pulseout_obj_t* self, const pulseio_pwmout_obj_t* carrier) { - + mp_raise_NotImplementedError(NULL); } bool common_hal_pulseio_pulseout_deinited(pulseio_pulseout_obj_t* self) { @@ -60,147 +60,3 @@ void common_hal_pulseio_pulseout_deinit(pulseio_pulseout_obj_t* self) { void common_hal_pulseio_pulseout_send(pulseio_pulseout_obj_t* self, uint16_t* pulses, uint16_t length) { } - -#if 0 -// This timer is shared amongst all PulseOut objects under the assumption that -// the code is single threaded. Its stored in MICROPY_PORT_ROOT_POINTERS so it -// doesn't get garbage collected. -static uint8_t refcount = 0; - -static __IO PORT_PINCFG_Type *active_pincfg = NULL; -static uint16_t *pulse_buffer = NULL; -static volatile uint16_t pulse_index = 0; -static uint16_t pulse_length; -static volatile uint32_t current_compare = 0; - -static void turn_on(__IO PORT_PINCFG_Type * pincfg) { - pincfg->reg = PORT_PINCFG_PMUXEN; -} - -static void turn_off(__IO PORT_PINCFG_Type * pincfg) { - pincfg->reg = PORT_PINCFG_RESETVALUE; -} - -void pulse_finish(struct tc_module *const module) { - pulse_index++; - - if (active_pincfg == NULL) { - return; - } - // Always turn it off. - turn_off(active_pincfg); - if (pulse_index >= pulse_length) { - return; - } - current_compare = (current_compare + pulse_buffer[pulse_index] * 3 / 4) & 0xffff; - tc_set_compare_value(MP_STATE_VM(pulseout_tc_instance), TC_COMPARE_CAPTURE_CHANNEL_0, current_compare); - if (pulse_index % 2 == 0) { - turn_on(active_pincfg); - } -} - -void pulseout_reset() { - refcount = 0; - MP_STATE_VM(pulseout_tc_instance) = NULL; - active_pincfg = NULL; -} - -void common_hal_pulseio_pulseout_construct(pulseio_pulseout_obj_t* self, - const pulseio_pwmout_obj_t* carrier) { - if (refcount == 0) { - // Find a spare timer. - Tc *t = NULL; - Tc *tcs[TC_INST_NUM] = TC_INSTS; - for (uint8_t i = TC_INST_NUM; i > 0; i--) { - if (tcs[i - 1]->COUNT16.CTRLA.bit.ENABLE == 0) { - t = tcs[i - 1]; - break; - } - } - if (t == NULL) { - mp_raise_RuntimeError("All timers in use"); - } - MP_STATE_VM(pulseout_tc_instance) = gc_alloc(sizeof(struct tc_module), false); - if (t == NULL) { - mp_raise_msg(&mp_type_MemoryError, ""); - } - - struct tc_config config_tc; - tc_get_config_defaults(&config_tc); - - config_tc.counter_size = TC_COUNTER_SIZE_16BIT; - config_tc.clock_prescaler = TC_CTRLA_PRESCALER_DIV64; - config_tc.wave_generation = TC_WAVE_GENERATION_NORMAL_FREQ; - - tc_init(MP_STATE_VM(pulseout_tc_instance), t, &config_tc); - tc_register_callback(MP_STATE_VM(pulseout_tc_instance), pulse_finish, TC_CALLBACK_CC_CHANNEL0); - tc_enable(MP_STATE_VM(pulseout_tc_instance)); - tc_stop_counter(MP_STATE_VM(pulseout_tc_instance)); - } - refcount++; - - self->pin = carrier->pin->pin; - - PortGroup *const port_base = port_get_group_from_gpio_pin(self->pin); - self->pincfg = &port_base->PINCFG[self->pin % 32]; - - // Set the port to output a zero. - port_base->OUTCLR.reg = 1 << (self->pin % 32); - port_base->DIRSET.reg = 1 << (self->pin % 32); - - // Turn off the pinmux which should connect the port output. - turn_off(self->pincfg); -} - -bool common_hal_pulseio_pulseout_deinited(pulseio_pulseout_obj_t* self) { - return self->pin == NO_PIN; -} - -void common_hal_pulseio_pulseout_deinit(pulseio_pulseout_obj_t* self) { - if (common_hal_pulseio_pulseout_deinited(self)) { - return; - } - PortGroup *const port_base = port_get_group_from_gpio_pin(self->pin); - port_base->DIRCLR.reg = 1 << (self->pin % 32); - - turn_on(self->pincfg); - - refcount--; - if (refcount == 0) { - tc_reset(MP_STATE_VM(pulseout_tc_instance)); - gc_free(MP_STATE_VM(pulseout_tc_instance)); - MP_STATE_VM(pulseout_tc_instance) = NULL; - } - self->pin = NO_PIN; -} - -void common_hal_pulseio_pulseout_send(pulseio_pulseout_obj_t* self, uint16_t* pulses, uint16_t length) { - if (active_pincfg != NULL) { - mp_raise_RuntimeError("Another send is already active"); - } - active_pincfg = self->pincfg; - pulse_buffer = pulses; - pulse_index = 0; - pulse_length = length; - - current_compare = pulses[0] * 3 / 4; - tc_set_compare_value(MP_STATE_VM(pulseout_tc_instance), TC_COMPARE_CAPTURE_CHANNEL_0, current_compare); - - tc_enable_callback(MP_STATE_VM(pulseout_tc_instance), TC_CALLBACK_CC_CHANNEL0); - turn_on(active_pincfg); - tc_start_counter(MP_STATE_VM(pulseout_tc_instance)); - - while(pulse_index < length) { - // Do other things while we wait. The interrupts will handle sending the - // signal. - #ifdef MICROPY_VM_HOOK_LOOP - MICROPY_VM_HOOK_LOOP - #endif - } - - tc_stop_counter(MP_STATE_VM(pulseout_tc_instance)); - tc_disable_callback(MP_STATE_VM(pulseout_tc_instance), TC_CALLBACK_CC_CHANNEL0); - active_pincfg = NULL; -} -#endif - From de72f7fabbbd863073e836f3a1c54080c343017a Mon Sep 17 00:00:00 2001 From: Kevin Townsend Date: Fri, 22 Dec 2017 12:00:34 +0100 Subject: [PATCH 09/20] Delete feather52_bootloader_2.0.1_s132_single.zip --- .../feather52_bootloader_2.0.1_s132_single.zip | Bin 131785 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 ports/nrf/boards/feather52/bootloader/feather52_bootloader_2.0.1_s132_single.zip diff --git a/ports/nrf/boards/feather52/bootloader/feather52_bootloader_2.0.1_s132_single.zip b/ports/nrf/boards/feather52/bootloader/feather52_bootloader_2.0.1_s132_single.zip deleted file mode 100644 index 14e3bf7d68e3d58b9c06f6877c6eddcabb25064b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 131785 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