From 733094aead6e84b42da54655b2b0a5d0dbd1a503 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Wed, 20 Jan 2021 16:47:18 -0800 Subject: [PATCH] Add initial RP2040 support The RP2040 is new microcontroller from Raspberry Pi that features two Cortex M0s and eight PIO state machines that are good for crunching lots of data. It has 264k RAM and a built in UF2 bootloader too. Datasheet: https://pico.raspberrypi.org/files/rp2040_datasheet.pdf --- .github/workflows/build.yml | 2 + .gitmodules | 5 +- Makefile | 1 + conf.py | 1 + docs/supported_ports.rst | 3 +- lib/tinyusb | 2 +- ports/raspberrypi/.gitignore | 1 + ports/raspberrypi/Makefile | 273 ++++++++ ports/raspberrypi/README.rst | 18 + ports/raspberrypi/background.c | 44 ++ ports/raspberrypi/background.h | 32 + .../bindings/rp2pio/StateMachine.c | 449 ++++++++++++++ .../bindings/rp2pio/StateMachine.h | 71 +++ ports/raspberrypi/bindings/rp2pio/__init__.c | 45 ++ .../boards/adafruit_feather_rp2040/board.c | 44 ++ .../adafruit_feather_rp2040/mpconfigboard.h | 14 + .../adafruit_feather_rp2040/mpconfigboard.mk | 10 + .../boards/adafruit_feather_rp2040/pins.c | 36 ++ .../boards/raspberry_pi_pico/board.c | 38 ++ .../boards/raspberry_pi_pico/mpconfigboard.h | 15 + .../boards/raspberry_pi_pico/mpconfigboard.mk | 10 + .../boards/raspberry_pi_pico/pins.c | 38 ++ .../bs2_default_padded_checksummed.S | 20 + .../common-hal/analogio/AnalogIn.c | 73 +++ .../common-hal/analogio/AnalogIn.h | 41 ++ .../common-hal/analogio/AnalogOut.c | 48 ++ .../common-hal/analogio/AnalogOut.h | 36 ++ .../common-hal/analogio/__init__.c | 1 + ports/raspberrypi/common-hal/board/__init__.c | 34 + ports/raspberrypi/common-hal/busio/I2C.c | 175 ++++++ ports/raspberrypi/common-hal/busio/I2C.h | 47 ++ ports/raspberrypi/common-hal/busio/OneWire.h | 33 + ports/raspberrypi/common-hal/busio/SPI.c | 294 +++++++++ ports/raspberrypi/common-hal/busio/SPI.h | 52 ++ ports/raspberrypi/common-hal/busio/UART.c | 403 ++++++++++++ ports/raspberrypi/common-hal/busio/UART.h | 47 ++ ports/raspberrypi/common-hal/busio/__init__.c | 1 + .../common-hal/digitalio/DigitalInOut.c | 157 +++++ .../common-hal/digitalio/DigitalInOut.h | 40 ++ .../common-hal/digitalio/__init__.c | 1 + .../common-hal/displayio/ParallelBus.c | 68 ++ .../common-hal/displayio/ParallelBus.h | 36 ++ .../common-hal/microcontroller/Pin.c | 190 ++++++ .../common-hal/microcontroller/Pin.h | 53 ++ .../common-hal/microcontroller/Processor.c | 66 ++ .../common-hal/microcontroller/Processor.h | 39 ++ .../common-hal/microcontroller/__init__.c | 148 +++++ .../common-hal/microcontroller/__init__.h | 36 ++ .../common-hal/neopixel_write/__init__.c | 95 +++ ports/raspberrypi/common-hal/os/__init__.c | 62 ++ ports/raspberrypi/common-hal/pwmio/PWMOut.c | 216 +++++++ ports/raspberrypi/common-hal/pwmio/PWMOut.h | 47 ++ ports/raspberrypi/common-hal/pwmio/__init__.c | 1 + .../common-hal/rp2pio/StateMachine.c | 586 ++++++++++++++++++ .../common-hal/rp2pio/StateMachine.h | 68 ++ .../raspberrypi/common-hal/rp2pio/__init__.c | 1 + .../common-hal/supervisor/Runtime.c | 37 ++ .../common-hal/supervisor/Runtime.h | 37 ++ .../common-hal/supervisor/__init__.c | 40 ++ ports/raspberrypi/fatfs_port.c | 48 ++ ports/raspberrypi/link.ld | 251 ++++++++ ports/raspberrypi/mpconfigport.h | 46 ++ ports/raspberrypi/mpconfigport.mk | 44 ++ ports/raspberrypi/mphalport.c | 57 ++ ports/raspberrypi/mphalport.h | 50 ++ ports/raspberrypi/peripherals/pins.c | 67 ++ ports/raspberrypi/peripherals/pins.h | 71 +++ ports/raspberrypi/qstrdefsport.h | 1 + ports/raspberrypi/sdk | 1 + .../sdk_config/pico/config_autogen.h | 19 + ports/raspberrypi/sdk_config/pico/version.h | 19 + ports/raspberrypi/supervisor/internal_flash.c | 131 ++++ ports/raspberrypi/supervisor/internal_flash.h | 38 ++ .../supervisor/internal_flash_root_pointers.h | 31 + ports/raspberrypi/supervisor/port.c | 200 ++++++ ports/raspberrypi/supervisor/rp2_cpu.s | 35 ++ ports/raspberrypi/supervisor/usb.c | 38 ++ py/circuitpy_defns.mk | 4 + py/circuitpy_mpconfig.h | 29 +- py/circuitpy_mpconfig.mk | 8 +- shared-bindings/microcontroller/__init__.h | 7 + shared-module/sdcardio/SDCard.c | 4 +- supervisor/shared/filesystem.c | 2 + supervisor/shared/safe_mode.c | 2 + supervisor/shared/workflow.c | 4 +- tools/build_board_info.py | 2 + tools/build_memory_info.py | 4 +- 87 files changed, 5676 insertions(+), 18 deletions(-) create mode 100644 ports/raspberrypi/.gitignore create mode 100644 ports/raspberrypi/Makefile create mode 100644 ports/raspberrypi/README.rst create mode 100644 ports/raspberrypi/background.c create mode 100644 ports/raspberrypi/background.h create mode 100644 ports/raspberrypi/bindings/rp2pio/StateMachine.c create mode 100644 ports/raspberrypi/bindings/rp2pio/StateMachine.h create mode 100644 ports/raspberrypi/bindings/rp2pio/__init__.c create mode 100644 ports/raspberrypi/boards/adafruit_feather_rp2040/board.c create mode 100644 ports/raspberrypi/boards/adafruit_feather_rp2040/mpconfigboard.h create mode 100644 ports/raspberrypi/boards/adafruit_feather_rp2040/mpconfigboard.mk create mode 100644 ports/raspberrypi/boards/adafruit_feather_rp2040/pins.c create mode 100644 ports/raspberrypi/boards/raspberry_pi_pico/board.c create mode 100644 ports/raspberrypi/boards/raspberry_pi_pico/mpconfigboard.h create mode 100644 ports/raspberrypi/boards/raspberry_pi_pico/mpconfigboard.mk create mode 100644 ports/raspberrypi/boards/raspberry_pi_pico/pins.c create mode 100644 ports/raspberrypi/bs2_default_padded_checksummed.S create mode 100644 ports/raspberrypi/common-hal/analogio/AnalogIn.c create mode 100644 ports/raspberrypi/common-hal/analogio/AnalogIn.h create mode 100644 ports/raspberrypi/common-hal/analogio/AnalogOut.c create mode 100644 ports/raspberrypi/common-hal/analogio/AnalogOut.h create mode 100644 ports/raspberrypi/common-hal/analogio/__init__.c create mode 100644 ports/raspberrypi/common-hal/board/__init__.c create mode 100644 ports/raspberrypi/common-hal/busio/I2C.c create mode 100644 ports/raspberrypi/common-hal/busio/I2C.h create mode 100644 ports/raspberrypi/common-hal/busio/OneWire.h create mode 100644 ports/raspberrypi/common-hal/busio/SPI.c create mode 100644 ports/raspberrypi/common-hal/busio/SPI.h create mode 100644 ports/raspberrypi/common-hal/busio/UART.c create mode 100644 ports/raspberrypi/common-hal/busio/UART.h create mode 100644 ports/raspberrypi/common-hal/busio/__init__.c create mode 100644 ports/raspberrypi/common-hal/digitalio/DigitalInOut.c create mode 100644 ports/raspberrypi/common-hal/digitalio/DigitalInOut.h create mode 100644 ports/raspberrypi/common-hal/digitalio/__init__.c create mode 100644 ports/raspberrypi/common-hal/displayio/ParallelBus.c create mode 100644 ports/raspberrypi/common-hal/displayio/ParallelBus.h create mode 100644 ports/raspberrypi/common-hal/microcontroller/Pin.c create mode 100644 ports/raspberrypi/common-hal/microcontroller/Pin.h create mode 100644 ports/raspberrypi/common-hal/microcontroller/Processor.c create mode 100644 ports/raspberrypi/common-hal/microcontroller/Processor.h create mode 100644 ports/raspberrypi/common-hal/microcontroller/__init__.c create mode 100644 ports/raspberrypi/common-hal/microcontroller/__init__.h create mode 100644 ports/raspberrypi/common-hal/neopixel_write/__init__.c create mode 100644 ports/raspberrypi/common-hal/os/__init__.c create mode 100644 ports/raspberrypi/common-hal/pwmio/PWMOut.c create mode 100644 ports/raspberrypi/common-hal/pwmio/PWMOut.h create mode 100644 ports/raspberrypi/common-hal/pwmio/__init__.c create mode 100644 ports/raspberrypi/common-hal/rp2pio/StateMachine.c create mode 100644 ports/raspberrypi/common-hal/rp2pio/StateMachine.h create mode 100644 ports/raspberrypi/common-hal/rp2pio/__init__.c create mode 100755 ports/raspberrypi/common-hal/supervisor/Runtime.c create mode 100755 ports/raspberrypi/common-hal/supervisor/Runtime.h create mode 100755 ports/raspberrypi/common-hal/supervisor/__init__.c create mode 100644 ports/raspberrypi/fatfs_port.c create mode 100644 ports/raspberrypi/link.ld create mode 100644 ports/raspberrypi/mpconfigport.h create mode 100644 ports/raspberrypi/mpconfigport.mk create mode 100644 ports/raspberrypi/mphalport.c create mode 100644 ports/raspberrypi/mphalport.h create mode 100644 ports/raspberrypi/peripherals/pins.c create mode 100644 ports/raspberrypi/peripherals/pins.h create mode 100644 ports/raspberrypi/qstrdefsport.h create mode 160000 ports/raspberrypi/sdk create mode 100644 ports/raspberrypi/sdk_config/pico/config_autogen.h create mode 100644 ports/raspberrypi/sdk_config/pico/version.h create mode 100644 ports/raspberrypi/supervisor/internal_flash.c create mode 100644 ports/raspberrypi/supervisor/internal_flash.h create mode 100644 ports/raspberrypi/supervisor/internal_flash_root_pointers.h create mode 100644 ports/raspberrypi/supervisor/port.c create mode 100755 ports/raspberrypi/supervisor/rp2_cpu.s create mode 100644 ports/raspberrypi/supervisor/usb.c diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index fd4840830e..abde2da0bb 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -177,6 +177,7 @@ jobs: - "8086_commander" - "ADM_B_NRF52840_1" - "TG-Watch" + - "adafruit_feather_rp2040" - "aloriumtech_evo_m51" - "aramcon_badge_2019" - "arduino_mkr1300" @@ -294,6 +295,7 @@ jobs: - "pyruler" - "qtpy_m0" - "qtpy_m0_haxpress" + - "raspberry_pi_pico" - "raytac_mdbt50q-db-40" - "robohatmm1_m4" - "sam32" diff --git a/.gitmodules b/.gitmodules index f4080de1b2..66fcf186fa 100644 --- a/.gitmodules +++ b/.gitmodules @@ -75,7 +75,7 @@ url = https://github.com/adafruit/nrfx.git [submodule "lib/tinyusb"] path = lib/tinyusb - url = https://github.com/hathach/tinyusb.git + url = https://github.com/tannewt/tinyusb.git branch = master fetchRecurseSubmodules = false [submodule "tools/huffman"] @@ -171,3 +171,6 @@ [submodule "frozen/Adafruit_CircuitPython_LC709203F"] path = frozen/Adafruit_CircuitPython_LC709203F url = https://github.com/adafruit/Adafruit_CircuitPython_LC709203F +[submodule "ports/raspberrypi/sdk"] + path = ports/raspberrypi/sdk + url = https://github.com/raspberrypi/pico-sdk.git diff --git a/Makefile b/Makefile index adb206d7bc..845997beb2 100644 --- a/Makefile +++ b/Makefile @@ -255,6 +255,7 @@ stubs: @$(PYTHON) tools/extract_pyi.py shared-bindings/ $(STUBDIR) @$(PYTHON) tools/extract_pyi.py extmod/ulab/code/ $(STUBDIR)/ulab @$(PYTHON) tools/extract_pyi.py ports/atmel-samd/bindings $(STUBDIR) + @$(PYTHON) tools/extract_pyi.py ports/raspberrypi/bindings $(STUBDIR) @$(PYTHON) setup.py -q sdist .PHONY: check-stubs diff --git a/conf.py b/conf.py index c2d3d37eed..0a163e7d3c 100644 --- a/conf.py +++ b/conf.py @@ -189,6 +189,7 @@ exclude_patterns = ["**/build*", "ports/nrf/nrfx", "ports/nrf/peripherals", "ports/nrf/usb", + "ports/raspberrypi/sdk", "ports/stm/st_driver", "ports/stm/packages", "ports/stm/peripherals", diff --git a/docs/supported_ports.rst b/docs/supported_ports.rst index e74067e28f..b83ef12d35 100644 --- a/docs/supported_ports.rst +++ b/docs/supported_ports.rst @@ -13,8 +13,9 @@ is limited. ../ports/atmel-samd/README ../ports/cxd56/README + ../ports/esp32s2/README ../ports/litex/README ../ports/mimxrt10xx/README ../ports/nrf/README + ../ports/raspberrypi/README ../ports/stm/README - ../ports/esp32s2/README diff --git a/lib/tinyusb b/lib/tinyusb index cfcffe94ce..b68e4e9d70 160000 --- a/lib/tinyusb +++ b/lib/tinyusb @@ -1 +1 @@ -Subproject commit cfcffe94ce62f5ef1fb5aef4641924d64dc4b1c0 +Subproject commit b68e4e9d70ddef442c4d95412414c4221eef59eb diff --git a/ports/raspberrypi/.gitignore b/ports/raspberrypi/.gitignore new file mode 100644 index 0000000000..414487d53e --- /dev/null +++ b/ports/raspberrypi/.gitignore @@ -0,0 +1 @@ +build-*/ diff --git a/ports/raspberrypi/Makefile b/ports/raspberrypi/Makefile new file mode 100644 index 0000000000..69bd592c20 --- /dev/null +++ b/ports/raspberrypi/Makefile @@ -0,0 +1,273 @@ +# This file is part of the MicroPython project, http://micropython.org/ +# +# The MIT License (MIT) +# +# SPDX-FileCopyrightText: Copyright (c) 2019 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. + +# Select the board to build for. +ifeq ($(BOARD),) + $(error You must provide a BOARD parameter) +else + ifeq ($(wildcard boards/$(BOARD)/.),) + $(error Invalid BOARD specified) + endif +endif + +# If the build directory is not given, make it reflect the board name. +BUILD ?= build-$(BOARD) + +include ../../py/mkenv.mk +# Board-specific +include boards/$(BOARD)/mpconfigboard.mk +# Port-specific +include mpconfigport.mk +# CircuitPython-specific +include $(TOP)/py/circuitpy_mpconfig.mk + +# qstr definitions (must come before including py.mk) +QSTR_DEFS = qstrdefsport.h + +# include py core make definitions +include $(TOP)/py/py.mk + +include $(TOP)/supervisor/supervisor.mk + +# Include make rules and variables common across CircuitPython builds. +include $(TOP)/py/circuitpy_defns.mk + +CROSS_COMPILE = arm-none-eabi- + +HAL_DIR=hal/$(MCU_SERIES) + +INC += -I. \ + -I../.. \ + -I../lib/mp-readline \ + -I../lib/timeutils \ + -Iboards/$(BOARD) \ + -Iboards/ \ + -isystem sdk/ \ + -isystem sdk/src/common/pico_base/include/ \ + -isystem sdk/src/common/pico_binary_info/include/ \ + -isystem sdk/src/common/pico_stdlib/include/ \ + -isystem sdk/src/common/pico_sync/include/ \ + -isystem sdk/src/common/pico_time/include/ \ + -isystem sdk/src/common/pico_util/include/ \ + -isystem sdk/src/rp2040/hardware_regs/include/ \ + -isystem sdk/src/rp2040/hardware_structs/include/ \ + -isystem sdk/src/rp2_common/hardware_adc/include/ \ + -isystem sdk/src/rp2_common/hardware_base/include/ \ + -isystem sdk/src/rp2_common/hardware_claim/include/ \ + -isystem sdk/src/rp2_common/hardware_clocks/include/ \ + -isystem sdk/src/rp2_common/hardware_dma/include/ \ + -isystem sdk/src/rp2_common/hardware_flash/include/ \ + -isystem sdk/src/rp2_common/hardware_gpio/include/ \ + -isystem sdk/src/rp2_common/hardware_irq/include/ \ + -isystem sdk/src/rp2_common/hardware_i2c/include/ \ + -isystem sdk/src/rp2_common/hardware_pio/include/ \ + -isystem sdk/src/rp2_common/hardware_pll/include/ \ + -isystem sdk/src/rp2_common/hardware_resets/include/ \ + -isystem sdk/src/rp2_common/hardware_spi/include/ \ + -isystem sdk/src/rp2_common/hardware_sync/include/ \ + -isystem sdk/src/rp2_common/hardware_timer/include/ \ + -isystem sdk/src/rp2_common/hardware_uart/include/ \ + -isystem sdk/src/rp2_common/hardware_watchdog/include/ \ + -isystem sdk/src/rp2_common/hardware_xosc/include/ \ + -isystem sdk/src/rp2_common/pico_multicore/include/ \ + -isystem sdk/src/rp2_common/pico_fix/rp2040_usb_device_enumeration/include/ \ + -isystem sdk/src/rp2_common/pico_stdio/include/ \ + -isystem sdk/src/rp2_common/pico_printf/include/ \ + -isystem sdk/src/rp2_common/pico_float/include/ \ + -isystem sdk/src/rp2_common/pico_platform/include/ \ + -isystem sdk/src/rp2_common/pico_runtime/printf/include/ \ + -isystem sdk/src/rp2_common/pico_bootrom/include/ \ + -Isdk_config \ + -I../../lib/tinyusb/src \ + -I../../supervisor/shared/usb \ + -I$(BUILD) + +# Pico specific configuration +CFLAGS += -DPICO_ON_DEVICE=1 -DPICO_NO_BINARY_INFO=0 -DPICO_TIME_DEFAULT_ALARM_POOL_DISABLED=1 -DPICO_DIVIDER_CALL_IDIV0=0 -DPICO_DIVIDER_CALL_LDIV0=0 -DPICO_DIVIDER_HARDWARE=1 -DPICO_DOUBLE_ROM=1 -DPICO_FLOAT_ROM=1 -DPICO_MULTICORE=1 -DPICO_BITS_IN_RAM=0 -DPICO_DIVIDER_IN_RAM=0 -DPICO_DOUBLE_PROPAGATE_NANS=0 -DPICO_DOUBLE_IN_RAM=0 -DPICO_MEM_IN_RAM=0 -DPICO_FLOAT_IN_RAM=0 -DPICO_FLOAT_PROPAGATE_NANS=1 -DPICO_NO_FLASH=0 -DPICO_COPY_TO_RAM=0 -DPICO_DISABLE_SHARED_IRQ_HANDLERS=0 +OPTIMIZATION_FLAGS ?= -O3 +# TinyUSB defines +CFLAGS += -DTUD_OPT_RP2040_USB_DEVICE_ENUMERATION_FIX=1 -DCFG_TUSB_MCU=OPT_MCU_RP2040 -DCFG_TUD_MIDI_RX_BUFSIZE=128 -DCFG_TUD_CDC_RX_BUFSIZE=256 -DCFG_TUD_MIDI_TX_BUFSIZE=128 -DCFG_TUD_CDC_TX_BUFSIZE=256 -DCFG_TUD_MSC_BUFSIZE=1024 + +# option to override default optimization level, set in boards/$(BOARD)/mpconfigboard.mk +CFLAGS += $(OPTIMIZATION_FLAGS) + +#Debugging/Optimization +ifeq ($(DEBUG), 1) + CFLAGS += -ggdb3 -Og + # No LTO because we may place some functions in RAM instead of flash. +else + CFLAGS += -DNDEBUG + + # No LTO because we may place some functions in RAM instead of flash. + + ifdef CFLAGS_BOARD + CFLAGS += $(CFLAGS_BOARD) + endif +endif + +DISABLE_WARNINGS = -Wno-unused-function -Wno-unused-variable -Wno-strict-overflow -Wno-cast-align -Wno-strict-prototypes -Wno-nested-externs -Wno-double-promotion -Wno-sign-compare + +CFLAGS += $(INC) -Wall -Werror -std=gnu11 -nostdlib -fshort-enums $(BASE_CFLAGS) $(CFLAGS_MOD) $(COPT) $(DISABLE_WARNINGS) + +CFLAGS += \ + -march=armv6-m \ + -mthumb \ + -mabi=aapcs-linux \ + -mcpu=cortex-m0plus \ + -msoft-float \ + -mfloat-abi=soft + +PICO_LDFLAGS = --specs=nosys.specs -Wl,--wrap=__aeabi_ldiv0 -Wl,--wrap=__aeabi_idiv0 -Wl,--wrap=__aeabi_lmul -Wl,--wrap=__clzsi2 -Wl,--wrap=__clzdi2 -Wl,--wrap=__ctzsi2 -Wl,--wrap=__ctzdi2 -Wl,--wrap=__popcountsi2 -Wl,--wrap=__popcountdi2 -Wl,--wrap=__clz -Wl,--wrap=__clzl -Wl,--wrap=__clzll -Wl,--wrap=__aeabi_idiv -Wl,--wrap=__aeabi_idivmod -Wl,--wrap=__aeabi_ldivmod -Wl,--wrap=__aeabi_uidiv -Wl,--wrap=__aeabi_uidivmod -Wl,--wrap=__aeabi_uldivmod -Wl,--wrap=__aeabi_dadd -Wl,--wrap=__aeabi_ddiv -Wl,--wrap=__aeabi_dmul -Wl,--wrap=__aeabi_drsub -Wl,--wrap=__aeabi_dsub -Wl,--wrap=__aeabi_cdcmpeq -Wl,--wrap=__aeabi_cdrcmple -Wl,--wrap=__aeabi_cdcmple -Wl,--wrap=__aeabi_dcmpeq -Wl,--wrap=__aeabi_dcmplt -Wl,--wrap=__aeabi_dcmple -Wl,--wrap=__aeabi_dcmpge -Wl,--wrap=__aeabi_dcmpgt -Wl,--wrap=__aeabi_dcmpun -Wl,--wrap=__aeabi_i2d -Wl,--wrap=__aeabi_l2d -Wl,--wrap=__aeabi_ui2d -Wl,--wrap=__aeabi_ul2d -Wl,--wrap=__aeabi_d2iz -Wl,--wrap=__aeabi_d2lz -Wl,--wrap=__aeabi_d2uiz -Wl,--wrap=__aeabi_d2ulz -Wl,--wrap=__aeabi_d2f -Wl,--wrap=sqrt -Wl,--wrap=cos -Wl,--wrap=sin -Wl,--wrap=tan -Wl,--wrap=atan2 -Wl,--wrap=exp -Wl,--wrap=log -Wl,--wrap=ldexp -Wl,--wrap=copysign -Wl,--wrap=trunc -Wl,--wrap=floor -Wl,--wrap=ceil -Wl,--wrap=round -Wl,--wrap=sincos -Wl,--wrap=asin -Wl,--wrap=acos -Wl,--wrap=atan -Wl,--wrap=sinh -Wl,--wrap=cosh -Wl,--wrap=tanh -Wl,--wrap=asinh -Wl,--wrap=acosh -Wl,--wrap=atanh -Wl,--wrap=exp2 -Wl,--wrap=log2 -Wl,--wrap=exp10 -Wl,--wrap=log10 -Wl,--wrap=pow -Wl,--wrap=powint -Wl,--wrap=hypot -Wl,--wrap=cbrt -Wl,--wrap=fmod -Wl,--wrap=drem -Wl,--wrap=remainder -Wl,--wrap=remquo -Wl,--wrap=expm1 -Wl,--wrap=log1p -Wl,--wrap=fma -Wl,--wrap=__aeabi_fadd -Wl,--wrap=__aeabi_fdiv -Wl,--wrap=__aeabi_fmul -Wl,--wrap=__aeabi_frsub -Wl,--wrap=__aeabi_fsub -Wl,--wrap=__aeabi_cfcmpeq -Wl,--wrap=__aeabi_cfrcmple -Wl,--wrap=__aeabi_cfcmple -Wl,--wrap=__aeabi_fcmpeq -Wl,--wrap=__aeabi_fcmplt -Wl,--wrap=__aeabi_fcmple -Wl,--wrap=__aeabi_fcmpge -Wl,--wrap=__aeabi_fcmpgt -Wl,--wrap=__aeabi_fcmpun -Wl,--wrap=__aeabi_i2f -Wl,--wrap=__aeabi_l2f -Wl,--wrap=__aeabi_ui2f -Wl,--wrap=__aeabi_ul2f -Wl,--wrap=__aeabi_f2iz -Wl,--wrap=__aeabi_f2lz -Wl,--wrap=__aeabi_f2uiz -Wl,--wrap=__aeabi_f2ulz -Wl,--wrap=__aeabi_f2d -Wl,--wrap=sqrtf -Wl,--wrap=cosf -Wl,--wrap=sinf -Wl,--wrap=tanf -Wl,--wrap=atan2f -Wl,--wrap=expf -Wl,--wrap=logf -Wl,--wrap=ldexpf -Wl,--wrap=copysignf -Wl,--wrap=truncf -Wl,--wrap=floorf -Wl,--wrap=ceilf -Wl,--wrap=roundf -Wl,--wrap=sincosf -Wl,--wrap=asinf -Wl,--wrap=acosf -Wl,--wrap=atanf -Wl,--wrap=sinhf -Wl,--wrap=coshf -Wl,--wrap=tanhf -Wl,--wrap=asinhf -Wl,--wrap=acoshf -Wl,--wrap=atanhf -Wl,--wrap=exp2f -Wl,--wrap=log2f -Wl,--wrap=exp10f -Wl,--wrap=log10f -Wl,--wrap=powf -Wl,--wrap=powintf -Wl,--wrap=hypotf -Wl,--wrap=cbrtf -Wl,--wrap=fmodf -Wl,--wrap=dremf -Wl,--wrap=remainderf -Wl,--wrap=remquof -Wl,--wrap=expm1f -Wl,--wrap=log1pf -Wl,--wrap=fmaf -Wl,--wrap=memcpy -Wl,--wrap=memset -Wl,--wrap=__aeabi_memcpy -Wl,--wrap=__aeabi_memset -Wl,--wrap=__aeabi_memcpy4 -Wl,--wrap=__aeabi_memset4 -Wl,--wrap=__aeabi_memcpy8 -Wl,--wrap=__aeabi_memset8 + +LDFLAGS = $(CFLAGS) $(PICO_LDFLAGS) -Wl,-T,link.ld -Wl,-Map=$@.map -Wl,-cref -Wl,--gc-sections + +# Use toolchain libm if we're not using our own. +ifndef INTERNAL_LIBM +LIBS += -lm +endif + +LDFLAGS += -mthumb -mcpu=cortex-m0plus + +SRC_SDK := \ + src/common/pico_sync/critical_section.c \ + src/common/pico_sync/lock_core.c \ + src/common/pico_sync/mutex.c \ + src/common/pico_time/time.c \ + src/common/pico_util/pheap.c \ + src/rp2_common/hardware_adc/adc.c \ + src/rp2_common/hardware_claim/claim.c \ + src/rp2_common/hardware_clocks/clocks.c \ + src/rp2_common/hardware_dma/dma.c \ + src/rp2_common/hardware_flash/flash.c \ + src/rp2_common/hardware_gpio/gpio.c \ + src/rp2_common/hardware_i2c/i2c.c \ + src/rp2_common/hardware_irq/irq.c \ + src/rp2_common/hardware_pio/pio.c \ + src/rp2_common/hardware_pll/pll.c \ + src/rp2_common/hardware_spi/spi.c \ + src/rp2_common/hardware_sync/sync.c \ + src/rp2_common/hardware_timer/timer.c \ + src/rp2_common/hardware_uart/uart.c \ + src/rp2_common/hardware_watchdog/watchdog.c \ + src/rp2_common/hardware_xosc/xosc.c \ + src/rp2_common/pico_bootrom/bootrom.c \ + src/rp2_common/pico_double/double_init_rom.c \ + src/rp2_common/pico_fix/rp2040_usb_device_enumeration/rp2040_usb_device_enumeration.c \ + src/rp2_common/pico_float/float_init_rom.c \ + src/rp2_common/pico_float/float_math.c \ + src/rp2_common/pico_multicore/multicore.c \ + src/rp2_common/pico_platform/platform.c \ + src/rp2_common/pico_printf/printf.c \ + src/rp2_common/pico_runtime/runtime.c \ + src/rp2_common/pico_stdio/stdio.c \ + +SRC_SDK := $(addprefix sdk/, $(SRC_SDK)) + +SRC_C += \ + boards/$(BOARD)/board.c \ + boards/$(BOARD)/pins.c \ + bindings/rp2pio/StateMachine.c \ + bindings/rp2pio/__init__.c \ + common-hal/rp2pio/StateMachine.c \ + common-hal/rp2pio/__init__.c \ + background.c \ + peripherals/pins.c \ + fatfs_port.c \ + lib/libc/string0.c \ + lib/mp-readline/readline.c \ + lib/oofatfs/ff.c \ + lib/oofatfs/option/ccsbcs.c \ + lib/timeutils/timeutils.c \ + lib/tinyusb/src/portable/raspberrypi/rp2040/dcd_rp2040.c \ + lib/tinyusb/src/portable/raspberrypi/rp2040/rp2040_usb.c \ + lib/utils/buffer_helper.c \ + lib/utils/context_manager_helpers.c \ + lib/utils/interrupt_char.c \ + lib/utils/pyexec.c \ + lib/utils/stdout_helpers.c \ + lib/utils/sys_stdio_mphal.c \ + mphalport.c \ + supervisor/shared/memory.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_EXPANDED = $(addprefix shared-bindings/, $(SRC_SHARED_MODULE)) \ + $(addprefix shared-module/, $(SRC_SHARED_MODULE)) \ + $(addprefix shared-module/, $(SRC_SHARED_MODULE_INTERNAL)) + +# There may be duplicates between SRC_COMMON_HAL_EXPANDED and SRC_SHARED_MODULE_EXPANDED, +# because a few modules have files both in common-hal/ and shared-modules/. +# Doing a $(sort ...) removes duplicates as part of sorting. +SRC_COMMON_HAL_SHARED_MODULE_EXPANDED = $(sort $(SRC_COMMON_HAL_EXPANDED) $(SRC_SHARED_MODULE_EXPANDED)) + +SRC_S = supervisor/$(CHIP_FAMILY)_cpu.s +SRC_S_UPPER = bs2_default_padded_checksummed.S \ + sdk/src/rp2_common/hardware_divider/divider.S \ + sdk/src/rp2_common/hardware_irq/irq_handler_chain.S \ + sdk/src/rp2_common/pico_bit_ops/bit_ops_aeabi.S \ + sdk/src/rp2_common/pico_double/double_aeabi.S \ + sdk/src/rp2_common/pico_double/double_v1_rom_shim.S \ + sdk/src/rp2_common/pico_divider/divider.S \ + sdk/src/rp2_common/pico_float/float_aeabi.S \ + sdk/src/rp2_common/pico_float/float_v1_rom_shim.S \ + sdk/src/rp2_common/pico_int64_ops/pico_int64_ops_aeabi.S \ + sdk/src/rp2_common/pico_mem_ops/mem_ops_aeabi.S \ + sdk/src/rp2_common/pico_standard_link/crt0.S \ + +OBJ = $(PY_O) $(SUPERVISOR_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) +OBJ += $(addprefix $(BUILD)/, $(SRC_SDK:.c=.o)) +OBJ += $(addprefix $(BUILD)/, $(SRC_COMMON_HAL_SHARED_MODULE_EXPANDED:.c=.o)) +ifeq ($(INTERNAL_LIBM),1) +OBJ += $(addprefix $(BUILD)/, $(SRC_LIBM:.c=.o)) +endif +OBJ += $(addprefix $(BUILD)/, $(SRC_S:.s=.o)) +OBJ += $(addprefix $(BUILD)/, $(SRC_S_UPPER:.S=.o)) +OBJ += $(addprefix $(BUILD)/, $(SRC_MOD:.c=.o)) + + +SRC_QSTR += $(SRC_C) $(SRC_SUPERVISOR) $(SRC_COMMON_HAL_EXPANDED) $(SRC_SHARED_MODULE_EXPANDED) + +all: $(BUILD)/firmware.uf2 + +$(BUILD)/firmware.elf: $(OBJ) link.ld + $(STEPECHO) "LINK $@" + $(Q)$(CC) -o $@ $(LDFLAGS) $(OBJ) + $(Q)$(SIZE) $@ | $(PYTHON3) $(TOP)/tools/build_memory_info.py link.ld + +$(BUILD)/firmware.bin: $(BUILD)/firmware.elf + $(STEPECHO) "Create $@" + $(Q)$(OBJCOPY) -O binary $^ $@ + +$(BUILD)/firmware.uf2: $(BUILD)/firmware.bin + $(STEPECHO) "Create $@" + $(Q)$(PYTHON3) $(TOP)/tools/uf2/utils/uf2conv.py -f 0xe48bff56 -b 0x10000000 -c -o $@ $^ + +include $(TOP)/py/mkrules.mk + +# Print out the value of a make variable. +# https://stackoverflow.com/questions/16467718/how-to-print-out-a-variable-in-makefile +print-%: + @echo $* = $($*) diff --git a/ports/raspberrypi/README.rst b/ports/raspberrypi/README.rst new file mode 100644 index 0000000000..d6ad9b3335 --- /dev/null +++ b/ports/raspberrypi/README.rst @@ -0,0 +1,18 @@ +RP2040 +================== + +This port supports many development boards that utilize RP2040 chips. See +https://circuitpython.org/downloads for all supported boards. + + +Building +-------- + +For build instructions see this guide: https://learn.adafruit.com/building-circuitpython/ + + +Port Specific modules +--------------------- + +.. toctree:: + ../../shared-bindings/rp2pio/index diff --git a/ports/raspberrypi/background.c b/ports/raspberrypi/background.c new file mode 100644 index 0000000000..c85b83b41e --- /dev/null +++ b/ports/raspberrypi/background.c @@ -0,0 +1,44 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 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 "background.h" + +#include "supervisor/filesystem.h" +#include "supervisor/shared/tick.h" +#include "supervisor/usb.h" + +#include "py/runtime.h" +#include "shared-module/network/__init__.h" +#include "supervisor/shared/stack.h" +#include "supervisor/port.h" + +#if CIRCUITPY_DISPLAYIO +#include "shared-module/displayio/__init__.h" +#endif + +void port_start_background_task(void) {} +void port_finish_background_task(void) {} + +void port_background_task(void) {} diff --git a/ports/raspberrypi/background.h b/ports/raspberrypi/background.h new file mode 100644 index 0000000000..c8e23e2a57 --- /dev/null +++ b/ports/raspberrypi/background.h @@ -0,0 +1,32 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 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_RASPBERRYPI_BACKGROUND_H +#define MICROPY_INCLUDED_RASPBERRYPI_BACKGROUND_H + +#include + +#endif // MICROPY_INCLUDED_RASPBERRYPI_BACKGROUND_H diff --git a/ports/raspberrypi/bindings/rp2pio/StateMachine.c b/ports/raspberrypi/bindings/rp2pio/StateMachine.c new file mode 100644 index 0000000000..f472583ff1 --- /dev/null +++ b/ports/raspberrypi/bindings/rp2pio/StateMachine.c @@ -0,0 +1,449 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 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 contains all of the Python API definitions for the +// rp2pio.StateMachine class. + +#include + +#include "shared-bindings/microcontroller/Pin.h" +#include "bindings/rp2pio/StateMachine.h" +#include "shared-bindings/util.h" + +#include "lib/utils/buffer_helper.h" +#include "lib/utils/context_manager_helpers.h" +#include "lib/utils/interrupt_char.h" +#include "py/mperrno.h" +#include "py/objproperty.h" +#include "py/runtime.h" +#include "supervisor/shared/translate.h" + + +//| class StateMachine: +//| """A single PIO StateMachine +//| +//| The programmable I/O peripheral on the RP2 series of microcontrollers is +//| unique. It is a collection of generic state machines that can be +//| used for a variety of protocols. State machines may be independent or +//| coordinated. Program memory and IRQs are shared between the state machines +//| in a particular PIO instance. They are independent otherwise. +//| +//| This class is designed to facilitate sharing of PIO resources. By default, +//| it is assumed that the state machine is used on it's own and can be placed +//| in either PIO. State machines with the same program will be placed in the +//| same PIO if possible. To ensure multiple state machines share a PIO use +//| the ``colocate`` kwarg during construction and create them one after another.""" +//| +//| def __init__(self, +//| program: ReadableBuffer, +//| frequency: int, +//| *, +//| init: Optional[ReadableBuffer] = None, +//| first_out_pin: Optional[microcontroller.Pin] = None, +//| out_pin_count: int = 1, +//| first_in_pin: Optional[microcontroller.Pin] = None, +//| in_pin_count: int = 1, +//| first_set_pin: Optional[microcontroller.Pin] = None, +//| set_pin_count: int = 1, +//| first_sideset_pin: Optional[microcontroller.Pin] = None, +//| sideset_pin_count: int = 1, +//| exclusive_pin_use: bool = True, +//| auto_pull: bool = False, +//| pull_threshold : int = 32, +//| out_shift_right : bool = True, +//| auto_push: bool = False, +//| push_threshold : int = 32, +//| in_shift_right : bool = True) -> None: +// //| colocate: Union[int, StateMachine, None] = None +//| +//| """Construct a StateMachine object on the given pins with the given program. +//| +//| :param ReadableBuffer program: the program to run with the state machine +//| :param int frequency: the target clock frequency of the state machine. Actual may be less. +//| :param ReadableBuffer init: a program to run once at start up. This is run after program +//| is started so instructions may be intermingled +//| :param ~microcontroller.Pin first_out_pin: the first pin to use with the OUT instruction +//| :param int out_pin_count: the count of consecutive pins to use with OUT starting at first_out_pin +//| :param ~microcontroller.Pin first_in_pin: the first pin to use with the IN instruction +//| :param int in_pin_count: the count of consecutive pins to use with IN starting at first_in_pin +//| :param ~microcontroller.Pin first_set_pin: the first pin to use with the SET instruction +//| :param int set_pin_count: the count of consecutive pins to use with SET starting at first_set_pin +//| :param ~microcontroller.Pin first_sideset_pin: the first pin to use with a side set +//| :param int sideset_pin_count: the count of consecutive pins to use with a side set starting at first_sideset_pin +//| :param bool exclusive_pin_use: When True, do not share any pins with other state machines. Pins are never shared with other peripherals +//| :param bool auto_pull: When True, automatically load data from the tx FIFO into the +//| output shift register (OSR) when an OUT instruction shifts more than pull_threshold bits +//| :param int pull_threshold: Number of bits to shift before loading a new value into the OSR from the tx FIFO +//| :param bool out_shift_right: When True, data is shifted out the right side (LSB) of the +//| OSR. It is shifted out the left (MSB) otherwise. NOTE! This impacts data alignment +//| when the number of bytes is not a power of two (1, 2 or 4 bytes). +//| :param bool auto_push: When True, automatically save data from input shift register +//| (ISR) into the rx FIFO when an IN instruction shifts more than push_threshold bits +//| :param int push_threshold: Number of bits to shift before saving the ISR value to the RX FIFO +//| :param bool in_shift_right: When True, data is shifted into the right side (LSB) of the +//| ISR. It is shifted into the left (MSB) otherwise. NOTE! This impacts data alignment +//| when the number of bytes is not a power of two (1, 2 or 4 bytes).""" +//| ... +//| + +STATIC mp_obj_t rp2pio_statemachine_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + rp2pio_statemachine_obj_t *self = m_new_obj(rp2pio_statemachine_obj_t); + self->base.type = &rp2pio_statemachine_type; + enum { ARG_program, ARG_frequency, ARG_init, + ARG_first_out_pin, ARG_out_pin_count, + ARG_first_in_pin, ARG_in_pin_count, + ARG_first_set_pin, ARG_set_pin_count, + ARG_first_sideset_pin, ARG_sideset_pin_count, + ARG_exclusive_pin_use, + ARG_auto_pull, ARG_pull_threshold, ARG_out_shift_right, + ARG_auto_push, ARG_push_threshold, ARG_in_shift_right}; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_program, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_frequency, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_init, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_first_out_pin, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_out_pin_count, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, + { MP_QSTR_first_in_pin, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_in_pin_count, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, + { MP_QSTR_first_set_pin, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_set_pin_count, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, + { MP_QSTR_first_sideset_pin, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_sideset_pin_count, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, + { MP_QSTR_exclusive_pin_use, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} }, + { MP_QSTR_auto_pull, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + { MP_QSTR_pull_threshold, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 32} }, + { MP_QSTR_out_shift_right, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} }, + { MP_QSTR_auto_push, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + { MP_QSTR_push_threshold, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 32} }, + { MP_QSTR_in_shift_right, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[ARG_program].u_obj, &bufinfo, MP_BUFFER_READ); + + mp_buffer_info_t init_bufinfo; + init_bufinfo.len = 0; + mp_get_buffer(args[ARG_init].u_obj, &init_bufinfo, MP_BUFFER_READ); + + // We don't validate pin in use here because we may be ok sharing them within a PIO. + mcu_pin_obj_t *first_out_pin = validate_obj_is_pin_or_none(args[ARG_first_out_pin].u_obj); + if (args[ARG_out_pin_count].u_int < 1) { + mp_raise_ValueError(translate("Pin count must be at least 1")); + } + mcu_pin_obj_t *first_in_pin = validate_obj_is_pin_or_none(args[ARG_first_in_pin].u_obj); + if (args[ARG_in_pin_count].u_int < 1) { + mp_raise_ValueError(translate("Pin count must be at least 1")); + } + mcu_pin_obj_t *first_set_pin = validate_obj_is_pin_or_none(args[ARG_first_set_pin].u_obj); + if (args[ARG_set_pin_count].u_int < 1) { + mp_raise_ValueError(translate("Pin count must be at least 1")); + } + if (args[ARG_set_pin_count].u_int > 5) { + mp_raise_ValueError(translate("Set pin count must be between 1 and 5")); + } + mcu_pin_obj_t *first_sideset_pin = validate_obj_is_pin_or_none(args[ARG_first_sideset_pin].u_obj); + if (args[ARG_sideset_pin_count].u_int < 1) { + mp_raise_ValueError(translate("Pin count must be at least 1")); + } + if (args[ARG_sideset_pin_count].u_int > 5) { + mp_raise_ValueError(translate("Side set pin count must be between 1 and 5")); + } + + mp_int_t pull_threshold = args[ARG_pull_threshold].u_int; + mp_int_t push_threshold = args[ARG_push_threshold].u_int; + if (pull_threshold < 1 || pull_threshold > 32) { + mp_raise_ValueError(translate("pull_threshold must be between 1 and 32")); + } + if (push_threshold < 1 || push_threshold > 32) { + mp_raise_ValueError(translate("push_threshold must be between 1 and 32")); + } + + if (bufinfo.len < 2) { + mp_raise_ValueError(translate("Program must contain at least one 16-bit instruction.")); + } + if (bufinfo.len % 2 != 0) { + mp_raise_ValueError(translate("Program size invalid")); + } + if (bufinfo.len > 32) { + mp_raise_ValueError(translate("Program too large")); + } + + if (init_bufinfo.len % 2 != 0) { + mp_raise_ValueError(translate("Init program size invalid")); + } + + common_hal_rp2pio_statemachine_construct(self, + bufinfo.buf, bufinfo.len / 2, + args[ARG_frequency].u_int, + init_bufinfo.buf, init_bufinfo.len / 2, + first_out_pin, args[ARG_out_pin_count].u_int, + first_in_pin, args[ARG_in_pin_count].u_int, + first_set_pin, args[ARG_set_pin_count].u_int, + first_sideset_pin, args[ARG_sideset_pin_count].u_int, + args[ARG_exclusive_pin_use].u_bool, + args[ARG_auto_pull].u_bool, pull_threshold, args[ARG_out_shift_right].u_bool, + args[ARG_auto_push].u_bool, push_threshold, args[ARG_in_shift_right].u_bool); + return MP_OBJ_FROM_PTR(self); +} + +//| def deinit(self) -> None: +//| """Turn off the state machine and release it's resources.""" +//| ... +//| +STATIC mp_obj_t rp2pio_statemachine_obj_deinit(mp_obj_t self_in) { + rp2pio_statemachine_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_rp2pio_statemachine_deinit(self); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(rp2pio_statemachine_deinit_obj, rp2pio_statemachine_obj_deinit); + +//| def __enter__(self) -> SPI: +//| """No-op used by Context Managers. +//| Provided by context manager helper.""" +//| ... +//| + +//| def __exit__(self) -> None: +//| """Automatically deinitializes the hardware when exiting a context. See +//| :ref:`lifetime-and-contextmanagers` for more info.""" +//| ... +//| +STATIC mp_obj_t rp2pio_statemachine_obj___exit__(size_t n_args, const mp_obj_t *args) { + (void)n_args; + common_hal_rp2pio_statemachine_deinit(args[0]); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(rp2pio_statemachine_obj___exit___obj, 4, 4, rp2pio_statemachine_obj___exit__); + + +STATIC void check_for_deinit(rp2pio_statemachine_obj_t *self) { + if (common_hal_rp2pio_statemachine_deinited(self)) { + raise_deinited_error(); + } +} + +// // | def restart(self, *other_state_machines) -> None: +// // | """Restarts this state machine and any others given. They must share +// // | an underlying PIO. An exception will be raised otherwise.""" +// // | ... +// // | + +//| def write(self, buffer: ReadableBuffer, *, start: int = 0, end: Optional[int] = None) -> None: +//| """Write the data contained in ``buffer`` to the state machine. If the buffer is empty, nothing happens. +//| +//| :param ~_typing.ReadableBuffer buffer: Write out the data in this buffer +//| :param int start: Start of the slice of ``buffer`` to write out: ``buffer[start:end]`` +//| :param int end: End of the slice; this index is not included. Defaults to ``len(buffer)``""" +//| ... +//| + +STATIC mp_obj_t rp2pio_statemachine_write(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_buffer, ARG_start, ARG_end }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} }, + }; + rp2pio_statemachine_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + check_for_deinit(self); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_READ); + int32_t start = args[ARG_start].u_int; + size_t length = bufinfo.len; + normalize_buffer_bounds(&start, args[ARG_end].u_int, &length); + + if (length == 0) { + return mp_const_none; + } + + bool ok = common_hal_rp2pio_statemachine_write(self, ((uint8_t*)bufinfo.buf) + start, length); + if (mp_hal_is_interrupted()) { + return mp_const_none; + } + if (!ok) { + mp_raise_OSError(MP_EIO); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(rp2pio_statemachine_write_obj, 2, rp2pio_statemachine_write); + + +// // | def readinto(self, buffer: WriteableBuffer, *, start: int = 0, end: Optional[int] = None) -> None: +// // | """Read into ``buffer``. If the number of bytes to read is 0, nothing happens. +// // | +// // | :param ~_typing.WriteableBuffer buffer: Read data into this buffer +// // | :param int start: Start of the slice of ``buffer`` to read into: ``buffer[start:end]`` +// // | :param int end: End of the slice; this index is not included. Defaults to ``len(buffer)`` +// // | :param int write_value: Value to write while reading. (Usually ignored.)""" +// // | ... +// // | + +// STATIC mp_obj_t rp2pio_statemachine_readinto(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { +// enum { ARG_buffer, ARG_start, ARG_end, ARG_write_value }; +// static const mp_arg_t allowed_args[] = { +// { MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, +// { MP_QSTR_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, +// { MP_QSTR_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} }, +// { MP_QSTR_write_value,MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, +// }; +// rp2pio_statemachine_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); +// check_for_deinit(self); +// check_lock(self); +// mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; +// mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + +// mp_buffer_info_t bufinfo; +// mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_WRITE); +// int32_t start = args[ARG_start].u_int; +// size_t length = bufinfo.len; +// normalize_buffer_bounds(&start, args[ARG_end].u_int, &length); + +// if (length == 0) { +// return mp_const_none; +// } + +// bool ok = common_hal_rp2pio_statemachine_read(self, ((uint8_t*)bufinfo.buf) + start, length, args[ARG_write_value].u_int); +// if (!ok) { +// mp_raise_OSError(MP_EIO); +// } +// return mp_const_none; +// } +// MP_DEFINE_CONST_FUN_OBJ_KW(rp2pio_statemachine_readinto_obj, 2, rp2pio_statemachine_readinto); + +// //| def write_readinto(self, buffer_out: ReadableBuffer, buffer_in: WriteableBuffer, *, out_start: int = 0, out_end: Optional[int] = None, in_start: int = 0, in_end: Optional[int] = None) -> None: +// //| """Write out the data in ``buffer_out`` while simultaneously reading data into ``buffer_in``. +// //| The SPI object must be locked. +// //| The lengths of the slices defined by ``buffer_out[out_start:out_end]`` and ``buffer_in[in_start:in_end]`` +// //| must be equal. +// //| If buffer slice lengths are both 0, nothing happens. +// //| +// //| :param ~_typing.ReadableBuffer buffer_out: Write out the data in this buffer +// //| :param ~_typing.WriteableBuffer buffer_in: Read data into this buffer +// //| :param int out_start: Start of the slice of buffer_out to write out: ``buffer_out[out_start:out_end]`` +// //| :param int out_end: End of the slice; this index is not included. Defaults to ``len(buffer_out)`` +// //| :param int in_start: Start of the slice of ``buffer_in`` to read into: ``buffer_in[in_start:in_end]`` +// //| :param int in_end: End of the slice; this index is not included. Defaults to ``len(buffer_in)``""" +// //| ... +// //| + +// STATIC mp_obj_t rp2pio_statemachine_write_readinto(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { +// enum { ARG_buffer_out, ARG_buffer_in, ARG_out_start, ARG_out_end, ARG_in_start, ARG_in_end }; +// static const mp_arg_t allowed_args[] = { +// { MP_QSTR_buffer_out, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, +// { MP_QSTR_buffer_in, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, +// { MP_QSTR_out_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, +// { MP_QSTR_out_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} }, +// { MP_QSTR_in_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, +// { MP_QSTR_in_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} }, +// }; +// rp2pio_statemachine_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); +// check_for_deinit(self); +// check_lock(self); +// mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; +// mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + +// mp_buffer_info_t buf_out_info; +// mp_get_buffer_raise(args[ARG_buffer_out].u_obj, &buf_out_info, MP_BUFFER_READ); +// int32_t out_start = args[ARG_out_start].u_int; +// size_t out_length = buf_out_info.len; +// normalize_buffer_bounds(&out_start, args[ARG_out_end].u_int, &out_length); + +// mp_buffer_info_t buf_in_info; +// mp_get_buffer_raise(args[ARG_buffer_in].u_obj, &buf_in_info, MP_BUFFER_WRITE); +// int32_t in_start = args[ARG_in_start].u_int; +// size_t in_length = buf_in_info.len; +// normalize_buffer_bounds(&in_start, args[ARG_in_end].u_int, &in_length); + +// if (out_length != in_length) { +// mp_raise_ValueError(translate("buffer slices must be of equal length")); +// } + +// if (out_length == 0) { +// return mp_const_none; +// } + +// bool ok = common_hal_rp2pio_statemachine_transfer(self, +// ((uint8_t*)buf_out_info.buf) + out_start, +// ((uint8_t*)buf_in_info.buf) + in_start, +// out_length); +// if (!ok) { +// mp_raise_OSError(MP_EIO); +// } +// return mp_const_none; +// } +// MP_DEFINE_CONST_FUN_OBJ_KW(rp2pio_statemachine_write_readinto_obj, 2, rp2pio_statemachine_write_readinto); + +//| frequency: int +//| """The actual state machine frequency. This may not match the frequency requested +//| due to internal limitations.""" +//| + +STATIC mp_obj_t rp2pio_statemachine_obj_get_frequency(mp_obj_t self_in) { + rp2pio_statemachine_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return MP_OBJ_NEW_SMALL_INT(common_hal_rp2pio_statemachine_get_frequency(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(rp2pio_statemachine_get_frequency_obj, rp2pio_statemachine_obj_get_frequency); + +const mp_obj_property_t rp2pio_statemachine_frequency_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&rp2pio_statemachine_get_frequency_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +STATIC const mp_rom_map_elem_t rp2pio_statemachine_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&rp2pio_statemachine_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&rp2pio_statemachine_obj___exit___obj) }, + +// { MP_ROM_QSTR(MP_QSTR_restart), MP_ROM_PTR(&rp2pio_statemachine_configure_obj) }, + +// { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&rp2pio_statemachine_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&rp2pio_statemachine_write_obj) }, +// { MP_ROM_QSTR(MP_QSTR_write_readinto), MP_ROM_PTR(&rp2pio_statemachine_write_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_frequency), MP_ROM_PTR(&rp2pio_statemachine_frequency_obj) } +}; +STATIC MP_DEFINE_CONST_DICT(rp2pio_statemachine_locals_dict, rp2pio_statemachine_locals_dict_table); + +const mp_obj_type_t rp2pio_statemachine_type = { + { &mp_type_type }, + .name = MP_QSTR_StateMachine, + .make_new = rp2pio_statemachine_make_new, + .locals_dict = (mp_obj_dict_t*)&rp2pio_statemachine_locals_dict, +}; + +rp2pio_statemachine_obj_t *validate_obj_is_statemachine(mp_obj_t obj) { + if (!MP_OBJ_IS_TYPE(obj, &rp2pio_statemachine_type)) { + mp_raise_TypeError_varg(translate("Expected a %q"), rp2pio_statemachine_type.name); + } + return MP_OBJ_TO_PTR(obj); +} diff --git a/ports/raspberrypi/bindings/rp2pio/StateMachine.h b/ports/raspberrypi/bindings/rp2pio/StateMachine.h new file mode 100644 index 0000000000..5ff20a75bf --- /dev/null +++ b/ports/raspberrypi/bindings/rp2pio/StateMachine.h @@ -0,0 +1,71 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 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_RASPBERRYPI_BINDINGS_RP2PIO_STATEMACHINE_H +#define MICROPY_INCLUDED_RASPBERRYPI_BINDINGS_RP2PIO_STATEMACHINE_H + +#include "py/obj.h" + +#include "common-hal/microcontroller/Pin.h" +#include "common-hal/rp2pio/StateMachine.h" + +// Type object used in Python. Should be shared between ports. +extern const mp_obj_type_t rp2pio_statemachine_type; + +// Construct an underlying SPI object. +extern void common_hal_rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self, + const uint16_t* program, size_t program_len, + size_t frequency, + const uint16_t* init, size_t init_len, + const mcu_pin_obj_t * first_out_pin, uint8_t out_pin_count, + const mcu_pin_obj_t * first_in_pin, uint8_t in_pin_count, + const mcu_pin_obj_t * first_set_pin, uint8_t set_pin_count, + const mcu_pin_obj_t * first_sideset_pin, uint8_t sideset_pin_count, + bool exclusive_pin_use, + bool auto_pull, uint8_t pull_threshold, bool out_shift_right, + bool auto_push, uint8_t push_threshold, bool in_shift_right); + +extern void common_hal_rp2pio_statemachine_deinit(rp2pio_statemachine_obj_t *self); +extern bool common_hal_rp2pio_statemachine_deinited(rp2pio_statemachine_obj_t *self); + +// Writes out the given data. +extern bool common_hal_rp2pio_statemachine_write(rp2pio_statemachine_obj_t *self, const uint8_t *data, size_t len); + +// // Reads in len bytes while outputting zeroes. +// extern bool common_hal_rp2pio_statemachine_read(rp2pio_statemachine_obj_t *self, uint8_t *data, size_t len, uint8_t write_value); + +// // Reads and write len bytes simultaneously. +// extern bool common_hal_rp2pio_statemachine_transfer(rp2pio_statemachine_obj_t *self, +// const uint8_t *data_out, size_t out_len, +// uint8_t *data_in, size_t in_len); + +// Return actual SPI bus frequency. +uint32_t common_hal_rp2pio_statemachine_get_frequency(rp2pio_statemachine_obj_t* self); + +// This is used by the supervisor to claim SPI devices indefinitely. +// extern void common_hal_rp2pio_statemachine_never_reset(rp2pio_statemachine_obj_t *self); + +#endif // MICROPY_INCLUDED_RASPBERRYPI_BINDINGS_RP2PIO_STATEMACHINE_H diff --git a/ports/raspberrypi/bindings/rp2pio/__init__.c b/ports/raspberrypi/bindings/rp2pio/__init__.c new file mode 100644 index 0000000000..dd5808cd5e --- /dev/null +++ b/ports/raspberrypi/bindings/rp2pio/__init__.c @@ -0,0 +1,45 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 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/obj.h" +#include "py/runtime.h" + +#include "bindings/rp2pio/StateMachine.h" + +//| """Hardware interface to RP2 series' programmable IO (PIO) peripheral.""" +//| + +STATIC const mp_rom_map_elem_t rp2pio_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_rp2pio) }, + { MP_ROM_QSTR(MP_QSTR_StateMachine), MP_ROM_PTR(&rp2pio_statemachine_type) }, +}; + +STATIC MP_DEFINE_CONST_DICT(rp2pio_module_globals, rp2pio_module_globals_table); + +const mp_obj_module_t rp2pio_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&rp2pio_module_globals, +}; diff --git a/ports/raspberrypi/boards/adafruit_feather_rp2040/board.c b/ports/raspberrypi/boards/adafruit_feather_rp2040/board.c new file mode 100644 index 0000000000..8686f6d0c2 --- /dev/null +++ b/ports/raspberrypi/boards/adafruit_feather_rp2040/board.c @@ -0,0 +1,44 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 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/board.h" + +#include "shared-bindings/microcontroller/Pin.h" +#include "src/rp2_common/hardware_gpio/include/hardware/gpio.h" + +void board_init(void) { + common_hal_never_reset_pin(&pin_GPIO17); + gpio_init(17); + gpio_set_dir(17, GPIO_OUT); + gpio_put(17, true); +} + +bool board_requests_safe_mode(void) { + return false; +} + +void reset_board(void) { +} diff --git a/ports/raspberrypi/boards/adafruit_feather_rp2040/mpconfigboard.h b/ports/raspberrypi/boards/adafruit_feather_rp2040/mpconfigboard.h new file mode 100644 index 0000000000..6a2d063d79 --- /dev/null +++ b/ports/raspberrypi/boards/adafruit_feather_rp2040/mpconfigboard.h @@ -0,0 +1,14 @@ +#define MICROPY_HW_BOARD_NAME "Adafruit Feather RP2040" +#define MICROPY_HW_MCU_NAME "rp2040" + +#define MICROPY_HW_NEOPIXEL (&pin_GPIO16) + +#define DEFAULT_I2C_BUS_SCL (&pin_GPIO3) +#define DEFAULT_I2C_BUS_SDA (&pin_GPIO2) + +#define DEFAULT_SPI_BUS_SCK (&pin_GPIO18) +#define DEFAULT_SPI_BUS_MOSI (&pin_GPIO19) +#define DEFAULT_SPI_BUS_MISO (&pin_GPIO20) + +// #define DEFAULT_UART_BUS_RX (&pin_PA11) +// #define DEFAULT_UART_BUS_TX (&pin_PA10) diff --git a/ports/raspberrypi/boards/adafruit_feather_rp2040/mpconfigboard.mk b/ports/raspberrypi/boards/adafruit_feather_rp2040/mpconfigboard.mk new file mode 100644 index 0000000000..97b3cd9495 --- /dev/null +++ b/ports/raspberrypi/boards/adafruit_feather_rp2040/mpconfigboard.mk @@ -0,0 +1,10 @@ +USB_VID = 0x239A +USB_PID = 0x80F2 +USB_PRODUCT = "Feather RP2040" +USB_MANUFACTURER = "Adafruit" + +CHIP_VARIANT = RP2040 +CHIP_FAMILY = rp2 + +INTERNAL_FLASH_FILESYSTEM = 1 + diff --git a/ports/raspberrypi/boards/adafruit_feather_rp2040/pins.c b/ports/raspberrypi/boards/adafruit_feather_rp2040/pins.c new file mode 100644 index 0000000000..1617ac865e --- /dev/null +++ b/ports/raspberrypi/boards/adafruit_feather_rp2040/pins.c @@ -0,0 +1,36 @@ +#include "shared-bindings/board/__init__.h" + +STATIC const mp_rom_map_elem_t board_global_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_GPIO26) }, + { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_GPIO27) }, + { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO28) }, + { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_GPIO29) }, + { MP_ROM_QSTR(MP_QSTR_D24), MP_ROM_PTR(&pin_GPIO24) }, + { MP_ROM_QSTR(MP_QSTR_D25), MP_ROM_PTR(&pin_GPIO25) }, + { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO19) }, + { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_D0), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_D1), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_D4), MP_ROM_PTR(&pin_GPIO4) }, + + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_D11), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_D12), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_GPIO13) }, + + { MP_ROM_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_NEOPIXEL_POWER), MP_ROM_PTR(&pin_GPIO17) }, + + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, + { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) }, + // { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_global_dict_table); diff --git a/ports/raspberrypi/boards/raspberry_pi_pico/board.c b/ports/raspberrypi/boards/raspberry_pi_pico/board.c new file mode 100644 index 0000000000..80ec5de32b --- /dev/null +++ b/ports/raspberrypi/boards/raspberry_pi_pico/board.c @@ -0,0 +1,38 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 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/board.h" + +void board_init(void) +{ +} + +bool board_requests_safe_mode(void) { + return false; +} + +void reset_board(void) { +} diff --git a/ports/raspberrypi/boards/raspberry_pi_pico/mpconfigboard.h b/ports/raspberrypi/boards/raspberry_pi_pico/mpconfigboard.h new file mode 100644 index 0000000000..4b0a220287 --- /dev/null +++ b/ports/raspberrypi/boards/raspberry_pi_pico/mpconfigboard.h @@ -0,0 +1,15 @@ +// LEDs +// #define MICROPY_HW_LED_STATUS (&pin_PA17) + +#define MICROPY_HW_BOARD_NAME "Raspberry Pi Pico" +#define MICROPY_HW_MCU_NAME "rp2040" + +// #define DEFAULT_I2C_BUS_SCL (&pin_PA23) +// #define DEFAULT_I2C_BUS_SDA (&pin_PA22) + +// #define DEFAULT_SPI_BUS_SCK (&pin_PB11) +// #define DEFAULT_SPI_BUS_MOSI (&pin_PB10) +// #define DEFAULT_SPI_BUS_MISO (&pin_PA12) + +// #define DEFAULT_UART_BUS_RX (&pin_PA11) +// #define DEFAULT_UART_BUS_TX (&pin_PA10) diff --git a/ports/raspberrypi/boards/raspberry_pi_pico/mpconfigboard.mk b/ports/raspberrypi/boards/raspberry_pi_pico/mpconfigboard.mk new file mode 100644 index 0000000000..11b06449c8 --- /dev/null +++ b/ports/raspberrypi/boards/raspberry_pi_pico/mpconfigboard.mk @@ -0,0 +1,10 @@ +USB_VID = 0x239A +USB_PID = 0x80F4 +USB_PRODUCT = "Pico" +USB_MANUFACTURER = "Raspberry Pi" + +CHIP_VARIANT = RP2040 +CHIP_FAMILY = rp2 + +INTERNAL_FLASH_FILESYSTEM = 1 + diff --git a/ports/raspberrypi/boards/raspberry_pi_pico/pins.c b/ports/raspberrypi/boards/raspberry_pi_pico/pins.c new file mode 100644 index 0000000000..38ec75c4ad --- /dev/null +++ b/ports/raspberrypi/boards/raspberry_pi_pico/pins.c @@ -0,0 +1,38 @@ +#include "shared-bindings/board/__init__.h" + +STATIC const mp_rom_map_elem_t board_global_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_GP0), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_GP1), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_GP2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_GP3), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_GP4), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_GP5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_GP6), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_GP7), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_GP8), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_GP9), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_GP10), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_GP11), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_GP12), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_GP13), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_GP14), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_GP16), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_GP17), MP_ROM_PTR(&pin_GPIO17) }, + { MP_ROM_QSTR(MP_QSTR_GP18), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_GP19), MP_ROM_PTR(&pin_GPIO19) }, + { MP_ROM_QSTR(MP_QSTR_GP20), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_GP21), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_GP22), MP_ROM_PTR(&pin_GPIO22) }, + { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_GPIO25) }, + { MP_ROM_QSTR(MP_QSTR_GP25), MP_ROM_PTR(&pin_GPIO25) }, + { MP_ROM_QSTR(MP_QSTR_GP26_A0), MP_ROM_PTR(&pin_GPIO26) }, + { MP_ROM_QSTR(MP_QSTR_GP26), MP_ROM_PTR(&pin_GPIO26) }, + { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_GPIO26) }, + { MP_ROM_QSTR(MP_QSTR_GP27_A1), MP_ROM_PTR(&pin_GPIO27) }, + { MP_ROM_QSTR(MP_QSTR_GP27), MP_ROM_PTR(&pin_GPIO27) }, + { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_GPIO27) }, + { MP_ROM_QSTR(MP_QSTR_GP28_A2), MP_ROM_PTR(&pin_GPIO28) }, + { MP_ROM_QSTR(MP_QSTR_GP28), MP_ROM_PTR(&pin_GPIO28) }, + { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO28) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_global_dict_table); diff --git a/ports/raspberrypi/bs2_default_padded_checksummed.S b/ports/raspberrypi/bs2_default_padded_checksummed.S new file mode 100644 index 0000000000..d77f4867c6 --- /dev/null +++ b/ports/raspberrypi/bs2_default_padded_checksummed.S @@ -0,0 +1,20 @@ +// Padded and checksummed version of: /Users/graham/dev/mu/pico_sdk/cmake-build-debug-mu/src/rp2_common/boot_stage2/bs2_default.bin + +.section .boot2, "a" + +.byte 0x00, 0xb5, 0x2f, 0x4b, 0x21, 0x20, 0x58, 0x60, 0x98, 0x68, 0x02, 0x21, 0x88, 0x43, 0x98, 0x60 +.byte 0xd8, 0x60, 0x18, 0x61, 0x58, 0x61, 0x2b, 0x4b, 0x00, 0x21, 0x99, 0x60, 0x02, 0x21, 0x59, 0x61 +.byte 0x01, 0x21, 0xf0, 0x22, 0x99, 0x50, 0x28, 0x49, 0x19, 0x60, 0x01, 0x21, 0x99, 0x60, 0x35, 0x20 +.byte 0x00, 0xf0, 0x3e, 0xf8, 0x02, 0x22, 0x90, 0x42, 0x14, 0xd0, 0x06, 0x21, 0x19, 0x66, 0x00, 0xf0 +.byte 0x2e, 0xf8, 0x19, 0x6e, 0x01, 0x21, 0x19, 0x66, 0x00, 0x20, 0x18, 0x66, 0x1a, 0x66, 0x00, 0xf0 +.byte 0x26, 0xf8, 0x19, 0x6e, 0x19, 0x6e, 0x19, 0x6e, 0x05, 0x20, 0x00, 0xf0, 0x29, 0xf8, 0x01, 0x21 +.byte 0x08, 0x42, 0xf9, 0xd1, 0x00, 0x21, 0x99, 0x60, 0x18, 0x49, 0x19, 0x60, 0x00, 0x21, 0x59, 0x60 +.byte 0x17, 0x49, 0x18, 0x48, 0x01, 0x60, 0x01, 0x21, 0x99, 0x60, 0xeb, 0x21, 0x19, 0x66, 0xa0, 0x21 +.byte 0x19, 0x66, 0x00, 0xf0, 0x0c, 0xf8, 0x00, 0x21, 0x99, 0x60, 0x13, 0x49, 0x11, 0x48, 0x01, 0x60 +.byte 0x01, 0x21, 0x99, 0x60, 0x01, 0xbc, 0x00, 0x28, 0x00, 0xd1, 0x10, 0x48, 0x00, 0x47, 0x03, 0xb5 +.byte 0x99, 0x6a, 0x04, 0x20, 0x01, 0x42, 0xfb, 0xd0, 0x01, 0x20, 0x01, 0x42, 0xf8, 0xd1, 0x03, 0xbd +.byte 0x02, 0xb5, 0x18, 0x66, 0x18, 0x66, 0xff, 0xf7, 0xf2, 0xff, 0x18, 0x6e, 0x18, 0x6e, 0x02, 0xbd +.byte 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x07, 0x00, 0x00, 0x03, 0x5f, 0x00 +.byte 0x21, 0x22, 0x00, 0x00, 0xf4, 0x00, 0x00, 0x18, 0x22, 0x20, 0x00, 0xa0, 0x01, 0x01, 0x00, 0x10 +.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x27, 0x2a, 0x60 diff --git a/ports/raspberrypi/common-hal/analogio/AnalogIn.c b/ports/raspberrypi/common-hal/analogio/AnalogIn.c new file mode 100644 index 0000000000..c51a749295 --- /dev/null +++ b/ports/raspberrypi/common-hal/analogio/AnalogIn.c @@ -0,0 +1,73 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 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 "py/runtime.h" +#include "supervisor/shared/translate.h" + +#include "src/rp2_common/hardware_adc/include/hardware/adc.h" + +#define ADC_FIRST_PIN_NUMBER 26 +#define ADC_PIN_COUNT 4 + +void common_hal_analogio_analogin_construct(analogio_analogin_obj_t *self, const mcu_pin_obj_t *pin) { + if (pin->number < ADC_FIRST_PIN_NUMBER || pin->number > ADC_FIRST_PIN_NUMBER + ADC_PIN_COUNT) { + mp_raise_ValueError(translate("Pin does not have ADC capabilities")); + } + + adc_init(); + + adc_gpio_init(pin->number); + + claim_pin(pin); + self->pin = pin; +} + +bool common_hal_analogio_analogin_deinited(analogio_analogin_obj_t *self) { + return self->pin == NULL; +} + +void common_hal_analogio_analogin_deinit(analogio_analogin_obj_t *self) { + if (common_hal_analogio_analogin_deinited(self)) { + return; + } + + reset_pin_number(self->pin->number); + self->pin = NULL; +} + +uint16_t common_hal_analogio_analogin_get_value(analogio_analogin_obj_t *self) { + adc_select_input(self->pin->number - ADC_FIRST_PIN_NUMBER); + uint16_t value = adc_read(); + + // Map value to from 12 to 16 bits + return (value << 4); +} + +float common_hal_analogio_analogin_get_reference_voltage(analogio_analogin_obj_t *self) { + // The nominal VCC voltage + return 3.3f; +} diff --git a/ports/raspberrypi/common-hal/analogio/AnalogIn.h b/ports/raspberrypi/common-hal/analogio/AnalogIn.h new file mode 100644 index 0000000000..ee9976e348 --- /dev/null +++ b/ports/raspberrypi/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) 2021 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_RASPBERRYPI_COMMON_HAL_ANALOGIO_ANALOGIN_H +#define MICROPY_INCLUDED_RASPBERRYPI_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_init(void); + +#endif // MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_ANALOGIO_ANALOGIN_H diff --git a/ports/raspberrypi/common-hal/analogio/AnalogOut.c b/ports/raspberrypi/common-hal/analogio/AnalogOut.c new file mode 100644 index 0000000000..adafa15d5c --- /dev/null +++ b/ports/raspberrypi/common-hal/analogio/AnalogOut.c @@ -0,0 +1,48 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Dan Halbert for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "shared-bindings/analogio/AnalogOut.h" + +#include +#include + +#include "py/mperrno.h" +#include "py/runtime.h" +#include "supervisor/shared/translate.h" + +void common_hal_analogio_analogout_construct(analogio_analogout_obj_t* self, const mcu_pin_obj_t *pin) { + mp_raise_RuntimeError(translate("AnalogOut functionality not supported")); +} + +bool common_hal_analogio_analogout_deinited(analogio_analogout_obj_t *self) { + return true; +} + +void common_hal_analogio_analogout_deinit(analogio_analogout_obj_t *self) { +} + +void common_hal_analogio_analogout_set_value(analogio_analogout_obj_t *self, uint16_t value) { +} diff --git a/ports/raspberrypi/common-hal/analogio/AnalogOut.h b/ports/raspberrypi/common-hal/analogio/AnalogOut.h new file mode 100644 index 0000000000..7c7a61aa2d --- /dev/null +++ b/ports/raspberrypi/common-hal/analogio/AnalogOut.h @@ -0,0 +1,36 @@ +/* + * 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_RASPBERRYPI_COMMON_HAL_ANALOGIO_ANALOGOUT_H +#define MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_ANALOGIO_ANALOGOUT_H + +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; +} analogio_analogout_obj_t; + +#endif // MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_ANALOGIO_ANALOGOUT_H diff --git a/ports/raspberrypi/common-hal/analogio/__init__.c b/ports/raspberrypi/common-hal/analogio/__init__.c new file mode 100644 index 0000000000..eea58c77d6 --- /dev/null +++ b/ports/raspberrypi/common-hal/analogio/__init__.c @@ -0,0 +1 @@ +// No analogio module functions. diff --git a/ports/raspberrypi/common-hal/board/__init__.c b/ports/raspberrypi/common-hal/board/__init__.c new file mode 100644 index 0000000000..3c7f30df22 --- /dev/null +++ b/ports/raspberrypi/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) 2021 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/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/raspberrypi/common-hal/busio/I2C.c b/ports/raspberrypi/common-hal/busio/I2C.c new file mode 100644 index 0000000000..fa49e375e2 --- /dev/null +++ b/ports/raspberrypi/common-hal/busio/I2C.c @@ -0,0 +1,175 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Scott Shawcroft for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "shared-bindings/busio/I2C.h" +#include "py/mperrno.h" +#include "py/runtime.h" + +#include "shared-bindings/microcontroller/__init__.h" +#include "supervisor/shared/translate.h" + +#include "src/rp2_common/hardware_gpio/include/hardware/gpio.h" + +// Synopsys DW_apb_i2c (v2.01) IP + +#define NO_PIN 0xff + +STATIC bool never_reset_i2c[2]; +STATIC i2c_inst_t* i2c[2] = {i2c0, i2c1}; + +void reset_i2c(void) { + for (size_t i = 0; i < 2; i++) { + if (never_reset_i2c[i]) { + continue; + } + + i2c_deinit(i2c[i]); + } +} + +void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, + const mcu_pin_obj_t* scl, const mcu_pin_obj_t* sda, uint32_t frequency, uint32_t timeout) { + self->peripheral = NULL; + // I2C pins have a regular pattern. SCL is always odd and SDA is even. They match up in pairs + // so we can divide by two to get the instance. This pattern repeats. + if (scl->number % 2 == 1 && sda->number % 2 == 0 && scl->number / 2 == sda->number / 2) { + size_t instance = (scl->number / 2) % 2; + self->peripheral = i2c[instance]; + } + if (self->peripheral == NULL) { + mp_raise_ValueError(translate("Invalid pins")); + } + if ((i2c_get_hw(self->peripheral)->enable & I2C_IC_ENABLE_ENABLE_BITS) != 0) { + mp_raise_ValueError(translate("I2C peripheral in use")); + } + if (frequency > 1000000) { + mp_raise_ValueError(translate("Unsupported baudrate")); + } + +#if CIRCUITPY_REQUIRE_I2C_PULLUPS + // Test that the pins are in a high state. (Hopefully indicating they are pulled up.) + gpio_set_function(sda->number, GPIO_FUNC_SIO); + gpio_set_function(scl->number, GPIO_FUNC_SIO); + gpio_set_dir(sda->number, GPIO_IN); + gpio_set_dir(scl->number, GPIO_IN); + + gpio_set_pulls(sda->number, false, true); + gpio_set_pulls(scl->number, false, true); + + common_hal_mcu_delay_us(10); + + gpio_set_pulls(sda->number, false, false); + gpio_set_pulls(scl->number, false, false); + + // We must pull up within 3us to achieve 400khz. + common_hal_mcu_delay_us(3); + + if (!gpio_get(sda->number) || !gpio_get(scl->number)) { + reset_pin_number(sda->number); + reset_pin_number(scl->number); + mp_raise_RuntimeError(translate("SDA or SCL needs a pull up")); + } +#endif + + gpio_set_function(sda->number, GPIO_FUNC_I2C); + gpio_set_function(scl->number, GPIO_FUNC_I2C); + + self->baudrate = i2c_init(self->peripheral, frequency); + + self->sda_pin = sda->number; + self->scl_pin = scl->number; + claim_pin(sda); + claim_pin(scl); +} + +bool common_hal_busio_i2c_deinited(busio_i2c_obj_t *self) { + return self->sda_pin == NO_PIN; +} + +void common_hal_busio_i2c_deinit(busio_i2c_obj_t *self) { + if (common_hal_busio_i2c_deinited(self)) { + return; + } + never_reset_i2c[i2c_hw_index(self->peripheral)] = false; + + i2c_deinit(self->peripheral); + + reset_pin_number(self->sda_pin); + reset_pin_number(self->scl_pin); + self->sda_pin = NO_PIN; + self->scl_pin = NO_PIN; +} + +bool common_hal_busio_i2c_probe(busio_i2c_obj_t *self, uint8_t addr) { + uint8_t fake_read = 0; + return i2c_read_blocking(self->peripheral, addr, &fake_read, 1, false) != PICO_ERROR_GENERIC; +} + +bool common_hal_busio_i2c_try_lock(busio_i2c_obj_t *self) { + bool grabbed_lock = false; + if (!self->has_lock) { + grabbed_lock = true; + self->has_lock = true; + } + 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 transmit_stop_bit) { + int result = i2c_write_blocking(self->peripheral, addr, data, len, !transmit_stop_bit); + if (result == len) { + return 0; + } else if (result == PICO_ERROR_GENERIC) { + return MP_ENODEV; + } + return MP_EIO; +} + +uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, + uint8_t *data, size_t len) { + int result = i2c_read_blocking(self->peripheral, addr, data, len, false); + if (result == len) { + return 0; + } else if (result == PICO_ERROR_GENERIC) { + return MP_ENODEV; + } + return MP_EIO; +} + +void common_hal_busio_i2c_never_reset(busio_i2c_obj_t *self) { + never_reset_i2c[i2c_hw_index(self->peripheral)] = true; + + never_reset_pin_number(self->scl_pin); + never_reset_pin_number(self->sda_pin); +} diff --git a/ports/raspberrypi/common-hal/busio/I2C.h b/ports/raspberrypi/common-hal/busio/I2C.h new file mode 100644 index 0000000000..d09f29e54c --- /dev/null +++ b/ports/raspberrypi/common-hal/busio/I2C.h @@ -0,0 +1,47 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 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_RASPBERRYPI_COMMON_HAL_BUSIO_I2C_H +#define MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_BUSIO_I2C_H + +#include "common-hal/microcontroller/Pin.h" + +#include "py/obj.h" + +#include "src/rp2_common/hardware_i2c/include/hardware/i2c.h" + +typedef struct { + mp_obj_base_t base; + i2c_inst_t * peripheral; + bool has_lock; + uint baudrate; + uint8_t scl_pin; + uint8_t sda_pin; +} busio_i2c_obj_t; + +void reset_i2c(void); + +#endif // MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_BUSIO_I2C_H diff --git a/ports/raspberrypi/common-hal/busio/OneWire.h b/ports/raspberrypi/common-hal/busio/OneWire.h new file mode 100644 index 0000000000..e27723ab2c --- /dev/null +++ b/ports/raspberrypi/common-hal/busio/OneWire.h @@ -0,0 +1,33 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 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_RASPBERRYPI_COMMON_HAL_BUSIO_ONEWIRE_H +#define MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_BUSIO_ONEWIRE_H + +// Use bitbangio. +#include "shared-module/busio/OneWire.h" + +#endif // MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_BUSIO_ONEWIRE_H diff --git a/ports/raspberrypi/common-hal/busio/SPI.c b/ports/raspberrypi/common-hal/busio/SPI.c new file mode 100644 index 0000000000..b157ae3eb0 --- /dev/null +++ b/ports/raspberrypi/common-hal/busio/SPI.c @@ -0,0 +1,294 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Scott Shawcroft for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "shared-bindings/busio/SPI.h" + +#include "lib/utils/interrupt_char.h" +#include "py/mperrno.h" +#include "py/runtime.h" + +#include "supervisor/board.h" +#include "common-hal/microcontroller/Pin.h" +#include "supervisor/shared/rgb_led_status.h" +#include "shared-bindings/microcontroller/Pin.h" + +#include "src/rp2_common/hardware_dma/include/hardware/dma.h" +#include "src/rp2_common/hardware_gpio/include/hardware/gpio.h" + +#define NO_INSTANCE 0xff + +STATIC bool never_reset_spi[2]; +STATIC spi_inst_t* spi[2] = {spi0, spi1}; + +void reset_spi(void) { + for (size_t i = 0; i < 2; i++) { + if (never_reset_spi[i]) { + continue; + } + + spi_deinit(spi[i]); + } +} + +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) { + size_t instance_index = NO_INSTANCE; + if (clock->number % 4 == 2) { + instance_index = (clock->number / 8) % 2; + } + if (mosi != NULL) { + // Make sure the set MOSI matches the clock settings. + if (mosi->number % 4 != 3 || + (mosi->number / 8) % 2 != instance_index) { + instance_index = NO_INSTANCE; + } + } + if (miso != NULL) { + // Make sure the set MOSI matches the clock settings. + if (miso->number % 4 != 0 || + (miso->number / 8) % 2 != instance_index) { + instance_index = NO_INSTANCE; + } + } + + // TODO: Check to see if we're sharing the SPI with a native APA102. + + if (instance_index > 1) { + mp_raise_ValueError(translate("Invalid pins")); + } + + if (instance_index == 0) { + self->peripheral = spi0; + } else if (instance_index == 1) { + self->peripheral = spi1; + } + + if ((spi_get_hw(self->peripheral)->cr1 & SPI_SSPCR1_SSE_BITS) != 0) { + mp_raise_ValueError(translate("SPI peripheral in use")); + } + + spi_init(self->peripheral, 250000); + + gpio_set_function(clock->number, GPIO_FUNC_SPI); + claim_pin(clock); + self->clock = clock; + + self->MOSI = mosi; + if (mosi != NULL) { + gpio_set_function(mosi->number, GPIO_FUNC_SPI); + claim_pin(mosi); + } + + self->MISO = miso; + if (miso != NULL) { + gpio_set_function(miso->number, GPIO_FUNC_SPI); + claim_pin(miso); + } +} + +void common_hal_busio_spi_never_reset(busio_spi_obj_t *self) { + never_reset_spi[spi_get_index(self->peripheral)] = true; + + common_hal_never_reset_pin(self->clock); + common_hal_never_reset_pin(self->MOSI); + common_hal_never_reset_pin(self->MISO); +} + +bool common_hal_busio_spi_deinited(busio_spi_obj_t *self) { + return self->clock == NULL; +} + +void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { + if (common_hal_busio_spi_deinited(self)) { + return; + } + never_reset_spi[spi_get_index(self->peripheral)] = false; + spi_deinit(self->peripheral); + + common_hal_reset_pin(self->clock); + common_hal_reset_pin(self->MOSI); + common_hal_reset_pin(self->MISO); + self->clock = NULL; +} + +bool common_hal_busio_spi_configure(busio_spi_obj_t *self, + uint32_t baudrate, uint8_t polarity, uint8_t phase, uint8_t bits) { + if (baudrate == self->target_frequency && + polarity == self->polarity && + phase == self->phase && + bits == self->bits) { + return true; + } + + spi_set_format(self->peripheral, bits, polarity, phase, SPI_MSB_FIRST); + + self->polarity = polarity; + self->phase = phase; + self->bits = bits; + self->target_frequency = baudrate; + self->real_frequency = spi_set_baudrate(self->peripheral, baudrate); + + return true; +} + +bool common_hal_busio_spi_try_lock(busio_spi_obj_t *self) { + bool grabbed_lock = false; + if (!self->has_lock) { + grabbed_lock = true; + self->has_lock = true; + } + 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; +} + +static bool _transfer(busio_spi_obj_t *self, + const uint8_t *data_out, size_t out_len, + uint8_t *data_in, size_t in_len) { + // Use DMA for large transfers if channels are available + const size_t dma_min_size_threshold = 32; + int chan_tx = -1; + int chan_rx = -1; + size_t len = MAX(out_len, in_len); + if (len >= dma_min_size_threshold) { + // Use two DMA channels to service the two FIFOs + chan_tx = dma_claim_unused_channel(false); + chan_rx = dma_claim_unused_channel(false); + } + bool use_dma = chan_rx >= 0 && chan_tx >= 0; + if (use_dma) { + dma_channel_config c = dma_channel_get_default_config(chan_tx); + channel_config_set_transfer_data_size(&c, DMA_SIZE_8); + channel_config_set_dreq(&c, spi_get_index(self->peripheral) ? DREQ_SPI1_TX : DREQ_SPI0_TX); + channel_config_set_read_increment(&c, out_len == len); + channel_config_set_write_increment(&c, false); + dma_channel_configure(chan_tx, &c, + &spi_get_hw(self->peripheral)->dr, + data_out, + len, + false); + + c = dma_channel_get_default_config(chan_rx); + channel_config_set_transfer_data_size(&c, DMA_SIZE_8); + channel_config_set_dreq(&c, spi_get_index(self->peripheral) ? DREQ_SPI1_RX : DREQ_SPI0_RX); + channel_config_set_read_increment(&c, false); + channel_config_set_write_increment(&c, in_len == len); + dma_channel_configure(chan_rx, &c, + data_in, + &spi_get_hw(self->peripheral)->dr, + len, + false); + + dma_start_channel_mask((1u << chan_rx) | (1u << chan_tx)); + while (dma_channel_is_busy(chan_rx) || dma_channel_is_busy(chan_tx)) { + // TODO: We should idle here until we get a DMA interrupt or something else. + RUN_BACKGROUND_TASKS; + if (mp_hal_is_interrupted()) { + if (dma_channel_is_busy(chan_rx)) { + dma_channel_abort(chan_rx); + } + if (dma_channel_is_busy(chan_tx)) { + dma_channel_abort(chan_tx); + } + break; + } + } + } + + // If we have claimed only one channel successfully, we should release immediately. This also + // releases the DMA after use_dma has been done. + if (chan_rx >= 0) { + dma_channel_unclaim(chan_rx); + } + if (chan_tx >= 0) { + dma_channel_unclaim(chan_tx); + } + + if (!use_dma && !mp_hal_is_interrupted()) { + // Use software for small transfers, or if couldn't claim two DMA channels + // Never have more transfers in flight than will fit into the RX FIFO, + // else FIFO will overflow if this code is heavily interrupted. + const size_t fifo_depth = 8; + size_t rx_remaining = len; + size_t tx_remaining = len; + + while (!mp_hal_is_interrupted() && (rx_remaining || tx_remaining)) { + if (tx_remaining && spi_is_writable(self->peripheral) && rx_remaining - tx_remaining < fifo_depth) { + spi_get_hw(self->peripheral)->dr = (uint32_t) *data_out; + // Increment only if the buffer is the transfer length. It's 1 otherwise. + if (out_len == len) { + data_out++; + } + --tx_remaining; + } + if (rx_remaining && spi_is_readable(self->peripheral)) { + *data_in = (uint8_t) spi_get_hw(self->peripheral)->dr; + // Increment only if the buffer is the transfer length. It's 1 otherwise. + if (in_len == len) { + data_in++; + } + --rx_remaining; + } + RUN_BACKGROUND_TASKS; + } + } + return true; +} + +bool common_hal_busio_spi_write(busio_spi_obj_t *self, + const uint8_t *data, size_t len) { + uint32_t data_in; + return _transfer(self, data, len, (uint8_t*) &data_in, MIN(len, 4)); +} + +bool common_hal_busio_spi_read(busio_spi_obj_t *self, + uint8_t *data, size_t len, uint8_t write_value) { + uint32_t data_out = write_value << 24 | write_value << 16 | write_value << 8 | write_value; + return _transfer(self, (const uint8_t*) &data_out, MIN(4, len), data, len); +} + +bool common_hal_busio_spi_transfer(busio_spi_obj_t *self, const uint8_t *data_out, uint8_t *data_in, size_t len) { + return _transfer(self, data_out, len, data_in, len); +} + +uint32_t common_hal_busio_spi_get_frequency(busio_spi_obj_t* self) { + return self->real_frequency; +} + +uint8_t common_hal_busio_spi_get_phase(busio_spi_obj_t* self) { + return self->phase; +} + +uint8_t common_hal_busio_spi_get_polarity(busio_spi_obj_t* self) { + return self->polarity; +} diff --git a/ports/raspberrypi/common-hal/busio/SPI.h b/ports/raspberrypi/common-hal/busio/SPI.h new file mode 100644 index 0000000000..981db46d41 --- /dev/null +++ b/ports/raspberrypi/common-hal/busio/SPI.h @@ -0,0 +1,52 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 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_RASPBERRYPI_COMMON_HAL_BUSIO_SPI_H +#define MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_BUSIO_SPI_H + +#include "common-hal/microcontroller/Pin.h" + +#include "py/obj.h" + +#include "src/rp2_common/hardware_spi/include/hardware/spi.h" + +typedef struct { + mp_obj_base_t base; + spi_inst_t * peripheral; + bool has_lock; + const mcu_pin_obj_t* clock; + const mcu_pin_obj_t* MOSI; + const mcu_pin_obj_t* MISO; + uint32_t target_frequency; + int32_t real_frequency; + uint8_t polarity; + uint8_t phase; + uint8_t bits; +} busio_spi_obj_t; + +void reset_spi(void); + +#endif // MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_BUSIO_SPI_H diff --git a/ports/raspberrypi/common-hal/busio/UART.c b/ports/raspberrypi/common-hal/busio/UART.c new file mode 100644 index 0000000000..71da6cadd5 --- /dev/null +++ b/ports/raspberrypi/common-hal/busio/UART.c @@ -0,0 +1,403 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Scott Shawcroft for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "shared-bindings/microcontroller/__init__.h" +#include "shared-bindings/busio/UART.h" + +#include "mpconfigport.h" +#include "lib/utils/interrupt_char.h" +#include "py/gc.h" +#include "py/mperrno.h" +#include "py/runtime.h" +#include "py/stream.h" +#include "supervisor/shared/translate.h" +#include "supervisor/shared/tick.h" + +#define UART_DEBUG(...) (void)0 +// #define UART_DEBUG(...) mp_printf(&mp_plat_print __VA_OPT__(,) __VA_ARGS__) + +// Do-nothing callback needed so that usart_async code will enable rx interrupts. +// See comment below re usart_async_register_callback() +// static void usart_async_rxc_callback(const struct usart_async_descriptor *const descr) { +// // Nothing needs to be done by us. +// } + +#define NO_PIN 0xff + +void common_hal_busio_uart_construct(busio_uart_obj_t *self, + const mcu_pin_obj_t * tx, const mcu_pin_obj_t * rx, + const mcu_pin_obj_t * rts, const mcu_pin_obj_t * cts, + const mcu_pin_obj_t * rs485_dir, bool rs485_invert, + uint32_t baudrate, uint8_t bits, busio_uart_parity_t parity, uint8_t stop, + mp_float_t timeout, uint16_t receiver_buffer_size, byte* receiver_buffer, + bool sigint_enabled) { + +// Sercom* sercom = NULL; +// uint8_t sercom_index = 255; // Unset index +// uint32_t rx_pinmux = 0; +// uint8_t rx_pad = 255; // Unset pad +// uint32_t tx_pinmux = 0; +// uint8_t tx_pad = 255; // Unset pad + +// if ((rts != NULL) || (cts != NULL) || (rs485_dir != NULL) || (rs485_invert)) { +// mp_raise_ValueError(translate("RTS/CTS/RS485 Not yet supported on this device")); +// } + +// if (bits > 8) { +// mp_raise_NotImplementedError(translate("bytes > 8 bits not supported")); +// } + +// bool have_tx = tx != NULL; +// bool have_rx = rx != NULL; +// if (!have_tx && !have_rx) { +// mp_raise_ValueError(translate("tx and rx cannot both be None")); +// } + +// self->baudrate = baudrate; +// self->character_bits = bits; +// self->timeout_ms = timeout * 1000; + +// // This assignment is only here because the usart_async routines take a *const argument. +// struct usart_async_descriptor * const usart_desc_p = (struct usart_async_descriptor * const) &self->usart_desc; + +// for (int i = 0; i < NUM_SERCOMS_PER_PIN; i++) { +// Sercom* potential_sercom = NULL; +// if (have_tx) { +// sercom_index = tx->sercom[i].index; +// if (sercom_index >= SERCOM_INST_NUM) { +// continue; +// } +// potential_sercom = sercom_insts[sercom_index]; +// #ifdef SAMD21 +// if (potential_sercom->USART.CTRLA.bit.ENABLE != 0 || +// !(tx->sercom[i].pad == 0 || +// tx->sercom[i].pad == 2)) { +// continue; +// } +// #endif +// #ifdef SAM_D5X_E5X +// if (potential_sercom->USART.CTRLA.bit.ENABLE != 0 || +// !(tx->sercom[i].pad == 0)) { +// continue; +// } +// #endif +// tx_pinmux = PINMUX(tx->number, (i == 0) ? MUX_C : MUX_D); +// tx_pad = tx->sercom[i].pad; +// if (rx == NULL) { +// sercom = potential_sercom; +// break; +// } +// } +// for (int j = 0; j < NUM_SERCOMS_PER_PIN; j++) { +// if (((!have_tx && rx->sercom[j].index < SERCOM_INST_NUM && +// sercom_insts[rx->sercom[j].index]->USART.CTRLA.bit.ENABLE == 0) || +// sercom_index == rx->sercom[j].index) && +// rx->sercom[j].pad != tx_pad) { +// rx_pinmux = PINMUX(rx->number, (j == 0) ? MUX_C : MUX_D); +// rx_pad = rx->sercom[j].pad; +// sercom = sercom_insts[rx->sercom[j].index]; +// sercom_index = rx->sercom[j].index; +// break; +// } +// } +// if (sercom != NULL) { +// break; +// } +// } +// if (sercom == NULL) { +// mp_raise_ValueError(translate("Invalid pins")); +// } +// if (!have_tx) { +// tx_pad = 0; +// if (rx_pad == 0) { +// tx_pad = 2; +// } +// } +// if (!have_rx) { +// rx_pad = (tx_pad + 1) % 4; +// } + +// // Set up clocks on SERCOM. +// samd_peripherals_sercom_clock_init(sercom, sercom_index); + +// if (rx && receiver_buffer_size > 0) { +// self->buffer_length = receiver_buffer_size; +// // Initially allocate the UART's buffer in the long-lived part of the +// // heap. UARTs are generally long-lived objects, but the "make long- +// // lived" machinery is incapable of moving internal pointers like +// // self->buffer, so do it manually. (However, as long as internal +// // pointers like this are NOT moved, allocating the buffer +// // in the long-lived pool is not strictly necessary) +// self->buffer = (uint8_t *) gc_alloc(self->buffer_length * sizeof(uint8_t), false, true); +// if (self->buffer == NULL) { +// common_hal_busio_uart_deinit(self); +// mp_raise_msg_varg(&mp_type_MemoryError, translate("Failed to allocate RX buffer of %d bytes"), self->buffer_length * sizeof(uint8_t)); +// } +// } else { +// self->buffer_length = 0; +// self->buffer = NULL; +// } + +// if (usart_async_init(usart_desc_p, sercom, self->buffer, self->buffer_length, NULL) != ERR_NONE) { +// mp_raise_ValueError(translate("Could not initialize UART")); +// } + +// // usart_async_init() sets a number of defaults based on a prototypical SERCOM +// // which don't necessarily match what we need. After calling it, set the values +// // specific to this instantiation of UART. + +// // Set pads computed for this SERCOM. +// // TXPO: +// // 0x0: TX pad 0; no RTS/CTS +// // 0x1: TX pad 2; no RTS/CTS +// // 0x2: TX pad 0; RTS: pad 2, CTS: pad 3 (not used by us right now) +// // So divide by 2 to map pad to value. +// // RXPO: +// // 0x0: RX pad 0 +// // 0x1: RX pad 1 +// // 0x2: RX pad 2 +// // 0x3: RX pad 3 + +// // Doing a group mask and set of the registers saves 60 bytes over setting the bitfields individually. + +// sercom->USART.CTRLA.reg &= ~(SERCOM_USART_CTRLA_TXPO_Msk | +// SERCOM_USART_CTRLA_RXPO_Msk | +// SERCOM_USART_CTRLA_FORM_Msk); +// sercom->USART.CTRLA.reg |= SERCOM_USART_CTRLA_TXPO(tx_pad / 2) | +// SERCOM_USART_CTRLA_RXPO(rx_pad) | +// (parity == BUSIO_UART_PARITY_NONE ? 0 : SERCOM_USART_CTRLA_FORM(1)); + +// // Enable tx and/or rx based on whether the pins were specified. +// // CHSIZE is 0 for 8 bits, 5, 6, 7 for 5, 6, 7 bits. 1 for 9 bits, but we don't support that. +// sercom->USART.CTRLB.reg &= ~(SERCOM_USART_CTRLB_TXEN | +// SERCOM_USART_CTRLB_RXEN | +// SERCOM_USART_CTRLB_PMODE | +// SERCOM_USART_CTRLB_SBMODE | +// SERCOM_USART_CTRLB_CHSIZE_Msk); +// sercom->USART.CTRLB.reg |= (have_tx ? SERCOM_USART_CTRLB_TXEN : 0) | +// (have_rx ? SERCOM_USART_CTRLB_RXEN : 0) | +// (parity == BUSIO_UART_PARITY_ODD ? SERCOM_USART_CTRLB_PMODE : 0) | +// (stop > 1 ? SERCOM_USART_CTRLB_SBMODE : 0) | +// SERCOM_USART_CTRLB_CHSIZE(bits % 8); + +// // Set baud rate +// common_hal_busio_uart_set_baudrate(self, baudrate); + +// // Turn on rx interrupt handling. The UART async driver has its own set of internal callbacks, +// // which are set up by uart_async_init(). These in turn can call user-specified callbacks. +// // In fact, the actual interrupts are not enabled unless we set up a user-specified callback. +// // This is confusing. It's explained in the Atmel START User Guide -> Implementation Description -> +// // Different read function behavior in some asynchronous drivers. As of this writing: +// // http://start.atmel.com/static/help/index.html?GUID-79201A5A-226F-4FBB-B0B8-AB0BE0554836 +// // Look at the ASFv4 code example for async USART. +// usart_async_register_callback(usart_desc_p, USART_ASYNC_RXC_CB, usart_async_rxc_callback); + + +// if (have_tx) { +// gpio_set_pin_direction(tx->number, GPIO_DIRECTION_OUT); +// gpio_set_pin_pull_mode(tx->number, GPIO_PULL_OFF); +// gpio_set_pin_function(tx->number, tx_pinmux); +// self->tx_pin = tx->number; +// claim_pin(tx); +// } else { +// self->tx_pin = NO_PIN; +// } + +// if (have_rx) { +// gpio_set_pin_direction(rx->number, GPIO_DIRECTION_IN); +// gpio_set_pin_pull_mode(rx->number, GPIO_PULL_OFF); +// gpio_set_pin_function(rx->number, rx_pinmux); +// self->rx_pin = rx->number; +// claim_pin(rx); +// } else { +// self->rx_pin = NO_PIN; +// } + +// usart_async_enable(usart_desc_p); +} + +bool common_hal_busio_uart_deinited(busio_uart_obj_t *self) { + return self->rx_pin == NO_PIN && self->tx_pin == NO_PIN; +} + +void common_hal_busio_uart_deinit(busio_uart_obj_t *self) { + if (common_hal_busio_uart_deinited(self)) { + return; + } + // This assignment is only here because the usart_async routines take a *const argument. + // struct usart_async_descriptor * const usart_desc_p = (struct usart_async_descriptor * const) &self->usart_desc; + // usart_async_disable(usart_desc_p); + // usart_async_deinit(usart_desc_p); + reset_pin_number(self->rx_pin); + reset_pin_number(self->tx_pin); + self->rx_pin = NO_PIN; + self->tx_pin = NO_PIN; +} + +// Read characters. +size_t common_hal_busio_uart_read(busio_uart_obj_t *self, uint8_t *data, size_t len, int *errcode) { + if (self->rx_pin == NO_PIN) { + mp_raise_ValueError(translate("No RX pin")); + } + + // This assignment is only here because the usart_async routines take a *const argument. + // struct usart_async_descriptor * const usart_desc_p = (struct usart_async_descriptor * const) &self->usart_desc; + + if (len == 0) { + // Nothing to read. + return 0; + } + + // struct io_descriptor *io; + // usart_async_get_io_descriptor(usart_desc_p, &io); + + size_t total_read = 0; + // uint64_t start_ticks = supervisor_ticks_ms64(); + + // // Busy-wait until timeout or until we've read enough chars. + // while (supervisor_ticks_ms64() - start_ticks <= self->timeout_ms) { + // // Read as many chars as we can right now, up to len. + // size_t num_read = io_read(io, data, len); + + // // Advance pointer in data buffer, and decrease how many chars left to read. + // data += num_read; + // len -= num_read; + // total_read += num_read; + // if (len == 0) { + // // Don't need to read any more: data buf is full. + // break; + // } + // if (num_read > 0) { + // // Reset the timeout on every character read. + // start_ticks = supervisor_ticks_ms64(); + // } + // RUN_BACKGROUND_TASKS; + // // Allow user to break out of a timeout with a KeyboardInterrupt. + // if (mp_hal_is_interrupted()) { + // break; + // } + // // If we are zero timeout, make sure we don't loop again (in the event + // // we read in under 1ms) + // if (self->timeout_ms == 0) { + // break; + // } + // } + + // if (total_read == 0) { + // *errcode = EAGAIN; + // return MP_STREAM_ERROR; + // } + + return total_read; +} + +// Write characters. +size_t common_hal_busio_uart_write(busio_uart_obj_t *self, const uint8_t *data, size_t len, int *errcode) { + if (self->tx_pin == NO_PIN) { + mp_raise_ValueError(translate("No TX pin")); + } + + // This assignment is only here because the usart_async routines take a *const argument. + // struct usart_async_descriptor * const usart_desc_p = (struct usart_async_descriptor * const) &self->usart_desc; + + // struct io_descriptor *io; + // usart_async_get_io_descriptor(usart_desc_p, &io); + + // // Start writing characters. This is non-blocking and will + // // return immediately after setting up the write. + // if (io_write(io, data, len) < 0) { + // *errcode = MP_EAGAIN; + // return MP_STREAM_ERROR; + // } + + // // Busy-wait until all characters transmitted. + // struct usart_async_status async_status; + // while (true) { + // usart_async_get_status(usart_desc_p, &async_status); + // if (async_status.txcnt >= len) { + // break; + // } + // RUN_BACKGROUND_TASKS; + // } + + return len; +} + +uint32_t common_hal_busio_uart_get_baudrate(busio_uart_obj_t *self) { + return self->baudrate; +} + +void common_hal_busio_uart_set_baudrate(busio_uart_obj_t *self, uint32_t baudrate) { + // This assignment is only here because the usart_async routines take a *const argument. + // struct usart_async_descriptor * const usart_desc_p = (struct usart_async_descriptor * const) &self->usart_desc; + // usart_async_set_baud_rate(usart_desc_p, + // // Samples and ARITHMETIC vs FRACTIONAL must correspond to USART_SAMPR in + // // hpl_sercom_config.h. + // _usart_async_calculate_baud_rate(baudrate, // e.g. 9600 baud + // PROTOTYPE_SERCOM_USART_ASYNC_CLOCK_FREQUENCY, + // 16, // samples + // USART_BAUDRATE_ASYNCH_ARITHMETIC, + // 0 // fraction - not used for ARITHMETIC + // )); + self->baudrate = baudrate; +} + +mp_float_t common_hal_busio_uart_get_timeout(busio_uart_obj_t *self) { + return (mp_float_t) (self->timeout_ms / 1000.0f); +} + +void common_hal_busio_uart_set_timeout(busio_uart_obj_t *self, mp_float_t timeout) { + self->timeout_ms = timeout * 1000; +} + +uint32_t common_hal_busio_uart_rx_characters_available(busio_uart_obj_t *self) { + // This assignment is only here because the usart_async routines take a *const argument. + // struct usart_async_descriptor * const usart_desc_p = (struct usart_async_descriptor * const) &self->usart_desc; + // struct usart_async_status async_status; + // usart_async_get_status(usart_desc_p, &async_status); + // return async_status.rxcnt; + return 0; +} + +void common_hal_busio_uart_clear_rx_buffer(busio_uart_obj_t *self) { + // This assignment is only here because the usart_async routines take a *const argument. + // struct usart_async_descriptor * const usart_desc_p = (struct usart_async_descriptor * const) &self->usart_desc; + // usart_async_flush_rx_buffer(usart_desc_p); + +} + +// True if there are no characters still to be written. +bool common_hal_busio_uart_ready_to_tx(busio_uart_obj_t *self) { + if (self->tx_pin == NO_PIN) { + return false; + } + return false; + // // This assignment is only here because the usart_async routines take a *const argument. + // struct usart_async_descriptor * const usart_desc_p = (struct usart_async_descriptor * const) &self->usart_desc; + // struct usart_async_status async_status; + // usart_async_get_status(usart_desc_p, &async_status); + // return !(async_status.flags & USART_ASYNC_STATUS_BUSY); +} diff --git a/ports/raspberrypi/common-hal/busio/UART.h b/ports/raspberrypi/common-hal/busio/UART.h new file mode 100644 index 0000000000..43ed9bee01 --- /dev/null +++ b/ports/raspberrypi/common-hal/busio/UART.h @@ -0,0 +1,47 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 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_RASPBERRYPI_COMMON_HAL_BUSIO_UART_H +#define MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_BUSIO_UART_H + +#include "common-hal/microcontroller/Pin.h" + +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; + // struct usart_async_descriptor usart_desc; + uint8_t rx_pin; + uint8_t tx_pin; + uint8_t character_bits; + bool rx_error; + uint32_t baudrate; + uint32_t timeout_ms; + uint32_t buffer_length; + uint8_t* buffer; +} busio_uart_obj_t; + +#endif // MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_BUSIO_UART_H diff --git a/ports/raspberrypi/common-hal/busio/__init__.c b/ports/raspberrypi/common-hal/busio/__init__.c new file mode 100644 index 0000000000..41761b6743 --- /dev/null +++ b/ports/raspberrypi/common-hal/busio/__init__.c @@ -0,0 +1 @@ +// No busio module functions. diff --git a/ports/raspberrypi/common-hal/digitalio/DigitalInOut.c b/ports/raspberrypi/common-hal/digitalio/DigitalInOut.c new file mode 100644 index 0000000000..06f0cfdd27 --- /dev/null +++ b/ports/raspberrypi/common-hal/digitalio/DigitalInOut.c @@ -0,0 +1,157 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 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 "common-hal/microcontroller/Pin.h" +#include "shared-bindings/digitalio/DigitalInOut.h" +#include "supervisor/shared/translate.h" + +#include "src/rp2_common/hardware_gpio/include/hardware/gpio.h" + +digitalinout_result_t common_hal_digitalio_digitalinout_construct( + digitalio_digitalinout_obj_t* self, const mcu_pin_obj_t* pin) { + claim_pin(pin); + self->pin = pin; + self->output = false; + self->open_drain = false; + + gpio_init(pin->number); + return DIGITALINOUT_OK; +} + +void common_hal_digitalio_digitalinout_never_reset( + digitalio_digitalinout_obj_t *self) { + never_reset_pin_number(self->pin->number); +} + +bool common_hal_digitalio_digitalinout_deinited(digitalio_digitalinout_obj_t* self) { + return self->pin == NULL; +} + +void common_hal_digitalio_digitalinout_deinit(digitalio_digitalinout_obj_t* self) { + if (common_hal_digitalio_digitalinout_deinited(self)) { + return; + } + reset_pin_number(self->pin->number); + self->pin = NULL; +} + +void common_hal_digitalio_digitalinout_switch_to_input( + digitalio_digitalinout_obj_t* self, digitalio_pull_t pull) { + self->output = false; + // This also sets direction to input. + common_hal_digitalio_digitalinout_set_pull(self, pull); +} + +digitalinout_result_t common_hal_digitalio_digitalinout_switch_to_output( + digitalio_digitalinout_obj_t* self, bool value, + digitalio_drive_mode_t drive_mode) { + const uint8_t pin = self->pin->number; + gpio_set_dir(pin, GPIO_OUT); + // Turn on "strong" pin driving (more current available). See DRVSTR doc in datasheet. + // hri_port_set_PINCFG_DRVSTR_bit(PORT, (enum gpio_port)GPIO_PORT(pin), GPIO_PIN(pin)); + + self->output = true; + common_hal_digitalio_digitalinout_set_drive_mode(self, drive_mode); + common_hal_digitalio_digitalinout_set_value(self, value); + return DIGITALINOUT_OK; +} + +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) { + const uint8_t pin = self->pin->number; + if (self->open_drain) { + gpio_set_dir(pin, value ? GPIO_IN : GPIO_OUT); + } else { + gpio_put(pin, value); + } +} + +bool common_hal_digitalio_digitalinout_get_value( + digitalio_digitalinout_obj_t* self) { + return gpio_get(self->pin->number); +} + +digitalinout_result_t common_hal_digitalio_digitalinout_set_drive_mode( + digitalio_digitalinout_obj_t* self, + digitalio_drive_mode_t drive_mode) { + const uint8_t pin = self->pin->number; + bool value = common_hal_digitalio_digitalinout_get_value(self); + self->open_drain = drive_mode == DRIVE_MODE_OPEN_DRAIN; + if (self->open_drain) { + gpio_put(pin, false); + } + // True is implemented differently between modes so reset the value to make + // sure it's correct for the new mode. + if (value) { + common_hal_digitalio_digitalinout_set_value(self, value); + } + return DIGITALINOUT_OK; +} + +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, digitalio_pull_t pull) { + const uint8_t pin = self->pin->number; + gpio_set_pulls(pin, pull == PULL_UP, pull == PULL_DOWN); + gpio_set_dir(pin, GPIO_IN); +} + +digitalio_pull_t common_hal_digitalio_digitalinout_get_pull( + digitalio_digitalinout_obj_t* self) { + // uint32_t pin = self->pin->number; + // if (self->output) { + // mp_raise_AttributeError(translate("Cannot get pull while in output mode")); + // return PULL_NONE; + // } else { + // if (hri_port_get_PINCFG_PULLEN_bit(PORT, GPIO_PORT(pin), GPIO_PIN(pin)) == 0) { + // return PULL_NONE; + // } if (hri_port_get_OUT_reg(PORT, GPIO_PORT(pin), 1U << GPIO_PIN(pin)) > 0) { + // return PULL_UP; + // } else { + // return PULL_DOWN; + // } + // } + return PULL_NONE; +} diff --git a/ports/raspberrypi/common-hal/digitalio/DigitalInOut.h b/ports/raspberrypi/common-hal/digitalio/DigitalInOut.h new file mode 100644 index 0000000000..8b14bbad8f --- /dev/null +++ b/ports/raspberrypi/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) 2020 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_RASPBERRYPI_COMMON_HAL_DIGITALIO_DIGITALINOUT_H +#define MICROPY_INCLUDED_RASPBERRYPI_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_RASPBERRYPI_COMMON_HAL_DIGITALIO_DIGITALINOUT_H diff --git a/ports/raspberrypi/common-hal/digitalio/__init__.c b/ports/raspberrypi/common-hal/digitalio/__init__.c new file mode 100644 index 0000000000..20fad45959 --- /dev/null +++ b/ports/raspberrypi/common-hal/digitalio/__init__.c @@ -0,0 +1 @@ +// No digitalio module functions. diff --git a/ports/raspberrypi/common-hal/displayio/ParallelBus.c b/ports/raspberrypi/common-hal/displayio/ParallelBus.c new file mode 100644 index 0000000000..57b2ffc36b --- /dev/null +++ b/ports/raspberrypi/common-hal/displayio/ParallelBus.c @@ -0,0 +1,68 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Scott Shawcroft for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "shared-bindings/displayio/ParallelBus.h" + +#include + +#include "common-hal/microcontroller/Pin.h" +#include "py/runtime.h" +#include "shared-bindings/digitalio/DigitalInOut.h" +#include "shared-bindings/microcontroller/__init__.h" + +void common_hal_displayio_parallelbus_construct(displayio_parallelbus_obj_t* self, + const mcu_pin_obj_t* data0, const mcu_pin_obj_t* command, const mcu_pin_obj_t* chip_select, + const mcu_pin_obj_t* write, const mcu_pin_obj_t* read, const mcu_pin_obj_t* reset) { + + mp_raise_NotImplementedError(translate("ParallelBus not yet supported")); + // TODO: Implement with PIO and DMA. +} + +void common_hal_displayio_parallelbus_deinit(displayio_parallelbus_obj_t* self) { + +} + +bool common_hal_displayio_parallelbus_reset(mp_obj_t obj) { + return false; +} + +bool common_hal_displayio_parallelbus_bus_free(mp_obj_t obj) { + return false; +} + +bool common_hal_displayio_parallelbus_begin_transaction(mp_obj_t obj) { + + return false; +} + +void common_hal_displayio_parallelbus_send(mp_obj_t obj, display_byte_type_t byte_type, + display_chip_select_behavior_t chip_select, const uint8_t *data, uint32_t data_length) { + +} + +void common_hal_displayio_parallelbus_end_transaction(mp_obj_t obj) { + +} diff --git a/ports/raspberrypi/common-hal/displayio/ParallelBus.h b/ports/raspberrypi/common-hal/displayio/ParallelBus.h new file mode 100644 index 0000000000..45989d9900 --- /dev/null +++ b/ports/raspberrypi/common-hal/displayio/ParallelBus.h @@ -0,0 +1,36 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 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_RASPBERRYPI_COMMON_HAL_DISPLAYIO_PARALLELBUS_H +#define MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_DISPLAYIO_PARALLELBUS_H + +#include "common-hal/digitalio/DigitalInOut.h" + +typedef struct { + mp_obj_base_t base; +} displayio_parallelbus_obj_t; + +#endif // MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_DISPLAYIO_PARALLELBUS_H diff --git a/ports/raspberrypi/common-hal/microcontroller/Pin.c b/ports/raspberrypi/common-hal/microcontroller/Pin.c new file mode 100644 index 0000000000..90c3274067 --- /dev/null +++ b/ports/raspberrypi/common-hal/microcontroller/Pin.c @@ -0,0 +1,190 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 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/runtime.h" + +#include "shared-bindings/microcontroller/Pin.h" + +#include "supervisor/shared/rgb_led_status.h" + +#include "src/rp2_common/hardware_gpio/include/hardware/gpio.h" + +#ifdef MICROPY_HW_NEOPIXEL +bool neopixel_in_use; +#endif +#ifdef MICROPY_HW_APA102_MOSI +bool apa102_sck_in_use; +bool apa102_mosi_in_use; +#endif +#ifdef SPEAKER_ENABLE_PIN +bool speaker_enable_in_use; +#endif + +STATIC uint32_t never_reset_pins; + +void reset_all_pins(void) { + for (size_t i = 0; i < 30; i++) { + if ((never_reset_pins & (1 << i)) != 0) { + continue; + } + reset_pin_number(i); + } +} + +void never_reset_pin_number(uint8_t pin_number) { + if (pin_number >= 32) { + return; + } + + never_reset_pins |= 1 << pin_number; +} + +void reset_pin_number(uint8_t pin_number) { + if (pin_number >= 32 +#if TUD_OPT_RP2040_USB_DEVICE_ENUMERATION_FIX + // Pin 15 is used for Errata so we don't mess with it. + || pin_number == 15 +#endif + ) { + return; + } + + never_reset_pins &= ~(1 << pin_number); + + // We are very aggressive in shutting down the pad fully. Both pulls are + // disabled and both buffers are as well. + gpio_init(pin_number); + hw_clear_bits(&padsbank0_hw->io[pin_number], PADS_BANK0_GPIO0_IE_BITS | + PADS_BANK0_GPIO0_PUE_BITS | + PADS_BANK0_GPIO0_PDE_BITS); + hw_set_bits(&padsbank0_hw->io[pin_number], PADS_BANK0_GPIO0_OD_BITS); + + #ifdef MICROPY_HW_NEOPIXEL + if (pin_number == MICROPY_HW_NEOPIXEL->number) { + neopixel_in_use = false; + rgb_led_status_init(); + return; + } + #endif + #ifdef MICROPY_HW_APA102_MOSI + if (pin_number == MICROPY_HW_APA102_MOSI->number || + pin_number == MICROPY_HW_APA102_SCK->number) { + apa102_mosi_in_use = apa102_mosi_in_use && pin_number != MICROPY_HW_APA102_MOSI->number; + apa102_sck_in_use = apa102_sck_in_use && pin_number != MICROPY_HW_APA102_SCK->number; + if (!apa102_sck_in_use && !apa102_mosi_in_use) { + rgb_led_status_init(); + } + return; + } + #endif + + #ifdef SPEAKER_ENABLE_PIN + if (pin_number == SPEAKER_ENABLE_PIN->number) { + speaker_enable_in_use = false; + } + #endif +} + +void common_hal_never_reset_pin(const mcu_pin_obj_t* pin) { + never_reset_pin_number(pin->number); +} + +void common_hal_reset_pin(const mcu_pin_obj_t* pin) { + reset_pin_number(pin->number); +} + +void claim_pin(const mcu_pin_obj_t* pin) { + #ifdef MICROPY_HW_NEOPIXEL + if (pin == MICROPY_HW_NEOPIXEL) { + neopixel_in_use = true; + } + #endif + #ifdef MICROPY_HW_APA102_MOSI + if (pin == MICROPY_HW_APA102_MOSI) { + apa102_mosi_in_use = true; + } + if (pin == MICROPY_HW_APA102_SCK) { + apa102_sck_in_use = true; + } + #endif + + #ifdef SPEAKER_ENABLE_PIN + if (pin == SPEAKER_ENABLE_PIN) { + speaker_enable_in_use = true; + } + #endif +} + +bool pin_number_is_free(uint8_t pin_number) { + if (pin_number >= 30) { + return false; + } +#if TUD_OPT_RP2040_USB_DEVICE_ENUMERATION_FIX + // Pin 15 is used for Errata so we don't mess with it. + if (pin_number == 15) { + return true; + } +#endif + uint32_t pad_state = padsbank0_hw->io[pin_number]; + return (pad_state & PADS_BANK0_GPIO0_IE_BITS) == 0 && + (pad_state & PADS_BANK0_GPIO0_OD_BITS) != 0; +} + +bool common_hal_mcu_pin_is_free(const mcu_pin_obj_t* pin) { + #ifdef MICROPY_HW_NEOPIXEL + if (pin == MICROPY_HW_NEOPIXEL) { + return !neopixel_in_use; + } + #endif + #ifdef MICROPY_HW_APA102_MOSI + if (pin == MICROPY_HW_APA102_MOSI) { + return !apa102_mosi_in_use; + } + if (pin == MICROPY_HW_APA102_SCK) { + return !apa102_sck_in_use; + } + #endif + + #ifdef SPEAKER_ENABLE_PIN + if (pin == SPEAKER_ENABLE_PIN) { + return !speaker_enable_in_use; + } + #endif + + return pin_number_is_free(pin->number); +} + +uint8_t common_hal_mcu_pin_number(const mcu_pin_obj_t* pin) { + return pin->number; +} + +void common_hal_mcu_pin_claim(const mcu_pin_obj_t* pin) { + return claim_pin(pin); +} + +void common_hal_mcu_pin_reset_number(uint8_t pin_no) { + reset_pin_number(pin_no); +} diff --git a/ports/raspberrypi/common-hal/microcontroller/Pin.h b/ports/raspberrypi/common-hal/microcontroller/Pin.h new file mode 100644 index 0000000000..07c3211850 --- /dev/null +++ b/ports/raspberrypi/common-hal/microcontroller/Pin.h @@ -0,0 +1,53 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 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_RASPBERRYPI_COMMON_HAL_MICROCONTROLLER_PIN_H +#define MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_MICROCONTROLLER_PIN_H + +#include +#include + +#include + +#include "peripherals/pins.h" + +#ifdef MICROPY_HW_NEOPIXEL +extern bool neopixel_in_use; +#endif +#ifdef MICROPY_HW_APA102_MOSI +extern bool apa102_sck_in_use; +extern bool apa102_mosi_in_use; +#endif + +void reset_all_pins(void); +// reset_pin_number takes the pin number instead of the pointer so that objects don't +// need to store a full pointer. +void reset_pin_number(uint8_t pin_number); +void never_reset_pin_number(uint8_t pin_number); +void claim_pin(const mcu_pin_obj_t* pin); +bool pin_number_is_free(uint8_t pin_number); + +#endif // MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_MICROCONTROLLER_PIN_H diff --git a/ports/raspberrypi/common-hal/microcontroller/Processor.c b/ports/raspberrypi/common-hal/microcontroller/Processor.c new file mode 100644 index 0000000000..0ad3a51e28 --- /dev/null +++ b/ports/raspberrypi/common-hal/microcontroller/Processor.c @@ -0,0 +1,66 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 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/mphal.h" +#include "common-hal/microcontroller/Processor.h" +#include "shared-bindings/microcontroller/ResetReason.h" + +#include "src/rp2_common/hardware_adc/include/hardware/adc.h" +#include "src/rp2_common/hardware_clocks/include/hardware/clocks.h" + +float common_hal_mcu_processor_get_temperature(void) { + adc_init(); + adc_set_temp_sensor_enabled(true); + adc_select_input(4); + uint16_t value = adc_read(); + adc_set_temp_sensor_enabled(false); + float voltage = value * 3.3 / (1 << 12); + // TODO: turn the ADC back off + return 27 - (voltage - 0.706) / 0.001721; +} + +float common_hal_mcu_processor_get_voltage(void) { + return 3.3f; +} + +uint32_t common_hal_mcu_processor_get_frequency(void) { + return clock_get_hz(clk_sys); +} + +void common_hal_mcu_processor_get_uid(uint8_t raw_id[]) { + // TODO: get the unique id from the flash. The chip itself doesn't have one. + // for (int i=0; i<4; i++) { + // for (int k=0; k<4; k++) { + // raw_id[4 * i + k] = (*(id_addresses[i]) >> k * 8) & 0xff; + // } + // } +} + +mcu_reset_reason_t common_hal_mcu_processor_get_reset_reason(void) { + return RESET_REASON_UNKNOWN; +} diff --git a/ports/raspberrypi/common-hal/microcontroller/Processor.h b/ports/raspberrypi/common-hal/microcontroller/Processor.h new file mode 100644 index 0000000000..b7c86e8506 --- /dev/null +++ b/ports/raspberrypi/common-hal/microcontroller/Processor.h @@ -0,0 +1,39 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 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_RASPBERRYPI_COMMON_HAL_MICROCONTROLLER_PROCESSOR_H +#define MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_MICROCONTROLLER_PROCESSOR_H + +#define COMMON_HAL_MCU_PROCESSOR_UID_LENGTH 16 + +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; + // Stores no state currently. +} mcu_processor_obj_t; + +#endif // MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_MICROCONTROLLER_PROCESSOR_H diff --git a/ports/raspberrypi/common-hal/microcontroller/__init__.c b/ports/raspberrypi/common-hal/microcontroller/__init__.c new file mode 100644 index 0000000000..e454ffa1b7 --- /dev/null +++ b/ports/raspberrypi/common-hal/microcontroller/__init__.c @@ -0,0 +1,148 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 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 "py/obj.h" +#include "py/runtime.h" + +#include "common-hal/microcontroller/__init__.h" +#if CIRCUITPY_NVM +#include "shared-bindings/nvm/ByteArray.h" +#endif +#include "shared-bindings/microcontroller/__init__.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/microcontroller/Processor.h" +#include "supervisor/shared/safe_mode.h" +#include "supervisor/shared/translate.h" + +#include "src/rp2040/hardware_structs/include/hardware/structs/sio.h" +#include "src/rp2_common/hardware_sync/include/hardware/sync.h" + +void common_hal_mcu_delay_us(uint32_t delay) { + mp_hal_delay_us(delay); +} + +volatile uint32_t nesting_count = 0; +void common_hal_mcu_disable_interrupts(void) { + // We don't use save_and_disable_interrupts() from the sdk because we don't want to worry about PRIMASK. + // This is what we do on the SAMD21 via CMSIS. + asm volatile ("cpsid i" : : : "memory"); + __dmb(); + nesting_count++; +} + +void common_hal_mcu_enable_interrupts(void) { + if (nesting_count == 0) { + // reset_into_safe_mode(LOCKING_ERROR); + } + nesting_count--; + if (nesting_count > 0) { + return; + } + __dmb(); + asm volatile ("cpsie i" : : : "memory"); +} + +void common_hal_mcu_on_next_reset(mcu_runmode_t runmode) { + if (runmode == RUNMODE_BOOTLOADER) { + } else { + } + if (runmode == RUNMODE_SAFE_MODE) { + safe_mode_on_next_reset(PROGRAMMATIC_SAFE_MODE); + } +} + +void common_hal_mcu_reset(void) { +} + +// The singleton microcontroller.Processor object, bound to microcontroller.cpu +// It currently only has properties, and no state. +static const mcu_processor_obj_t processor0 = { + .base = { + .type = &mcu_processor_type, + }, +}; + +static const mcu_processor_obj_t processor1 = { + .base = { + .type = &mcu_processor_type, + }, +}; + +const mp_rom_obj_tuple_t common_hal_mcu_processor_obj = { + {&mp_type_tuple}, + CIRCUITPY_PROCESSOR_COUNT, + { + MP_ROM_PTR(&processor0), + MP_ROM_PTR(&processor1) + } +}; + +#if CIRCUITPY_NVM && CIRCUITPY_INTERNAL_NVM_SIZE > 0 +// The singleton nvm.ByteArray object. +const nvm_bytearray_obj_t common_hal_mcu_nvm_obj = { + .base = { + .type = &nvm_bytearray_type, + }, + .len = CIRCUITPY_INTERNAL_NVM_SIZE, + .start_address = (uint8_t*) (CIRCUITPY_INTERNAL_NVM_START_ADDR) +}; +#endif + +// This maps MCU pin names to pin objects. +const mp_rom_map_elem_t mcu_pin_global_dict_table[TOTAL_GPIO_COUNT] = { + { MP_ROM_QSTR(MP_QSTR_GPIO0), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_GPIO1), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_GPIO2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_GPIO3), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_GPIO4), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_GPIO5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_GPIO6), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_GPIO7), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_GPIO8), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_GPIO9), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_GPIO10), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_GPIO11), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_GPIO12), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_GPIO13), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_GPIO14), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_GPIO15), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_GPIO16), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_GPIO17), MP_ROM_PTR(&pin_GPIO17) }, + { MP_ROM_QSTR(MP_QSTR_GPIO18), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_GPIO19), MP_ROM_PTR(&pin_GPIO19) }, + { MP_ROM_QSTR(MP_QSTR_GPIO20), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_GPIO21), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_GPIO22), MP_ROM_PTR(&pin_GPIO22) }, + { MP_ROM_QSTR(MP_QSTR_GPIO23), MP_ROM_PTR(&pin_GPIO23) }, + { MP_ROM_QSTR(MP_QSTR_GPIO24), MP_ROM_PTR(&pin_GPIO24) }, + { MP_ROM_QSTR(MP_QSTR_GPIO25), MP_ROM_PTR(&pin_GPIO25) }, + { MP_ROM_QSTR(MP_QSTR_GPIO26), MP_ROM_PTR(&pin_GPIO26) }, + { MP_ROM_QSTR(MP_QSTR_GPIO27), MP_ROM_PTR(&pin_GPIO27) }, + { MP_ROM_QSTR(MP_QSTR_GPIO28), MP_ROM_PTR(&pin_GPIO28) }, + { MP_ROM_QSTR(MP_QSTR_GPIO29), MP_ROM_PTR(&pin_GPIO29) }, +}; +MP_DEFINE_CONST_DICT(mcu_pin_globals, mcu_pin_global_dict_table); diff --git a/ports/raspberrypi/common-hal/microcontroller/__init__.h b/ports/raspberrypi/common-hal/microcontroller/__init__.h new file mode 100644 index 0000000000..cc509b6b12 --- /dev/null +++ b/ports/raspberrypi/common-hal/microcontroller/__init__.h @@ -0,0 +1,36 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 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_RASPBERRYPI_COMMON_HAL_MICROCONTROLLER___INIT___H +#define MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_MICROCONTROLLER___INIT___H + +#include "src/rp2040/hardware_regs/include/hardware/platform_defs.h" + +#define TOTAL_GPIO_COUNT NUM_BANK0_GPIOS + +extern const mp_rom_map_elem_t mcu_pin_global_dict_table[TOTAL_GPIO_COUNT]; + +#endif // MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_MICROCONTROLLER___INIT___H diff --git a/ports/raspberrypi/common-hal/neopixel_write/__init__.c b/ports/raspberrypi/common-hal/neopixel_write/__init__.c new file mode 100644 index 0000000000..10462b5a33 --- /dev/null +++ b/ports/raspberrypi/common-hal/neopixel_write/__init__.c @@ -0,0 +1,95 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Scott Shawcroft for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "shared-bindings/neopixel_write/__init__.h" + +#include "bindings/rp2pio/StateMachine.h" +#include "common-hal/rp2pio/StateMachine.h" +#include "shared-bindings/microcontroller/__init__.h" + +#include "supervisor/port.h" + +uint64_t next_start_raw_ticks = 0; + +// NeoPixels are 800khz bit streams. Zeroes are 1/3 duty cycle (~416ns) and ones +// are 2/3 duty cycle (~833ns). Each of the instructions below take 1/3 duty +// cycle. The first two instructions always run while only one of the two final +// instructions run per bit. We start with the low period because it can be +// longer than 1/3 period while waiting for more data. +const uint16_t neopixel_program[] = { +// bitloop: +// out x 1 side 0 [1]; Side-set still takes place before instruction stalls + 0x6121, +// jmp !x do_zero side 1 [1]; Branch on the bit we shifted out after 1/3 duty delay. Positive pulse + 0x1123, +// do_one: +// jmp bitloop side 1 [1]; Continue driving high, for a long pulse + 0x1100, +// do_zero: +// nop side 0 [1]; Or drive low, for a short pulse + 0xa142 +}; + +const uint16_t init_program[] = { + 0xe081 +}; + +void common_hal_neopixel_write(const digitalio_digitalinout_obj_t* digitalinout, uint8_t *pixels, uint32_t num_bytes) { + // Set everything up. + rp2pio_statemachine_obj_t state_machine; + + // TODO: Cache the state machine after we create it once. We'll need a way to + // change the pins then though. + uint8_t pin_number = digitalinout->pin->number; + bool ok = rp2pio_statemachine_construct(&state_machine, + neopixel_program, sizeof(neopixel_program) / sizeof(neopixel_program[0]), + 800000 * 6, // 800 khz * 6 cycles per bit + init_program, 1, + NULL, 1, + NULL, 1, + digitalinout->pin, 1, + digitalinout->pin, 1, + 1 << pin_number, true, false, + true, 8, false, // TX, auto pull every 8 bits. shift left to output msb first + false, 32, true, // RX setting we don't use + false); // claim pins + if (!ok) { + // Do nothing. Maybe bitbang? + return; + } + + // Wait to make sure we don't append onto the last transmission. This should only be a tick or + // two. + while (port_get_raw_ticks(NULL) < next_start_raw_ticks) {} + + common_hal_rp2pio_statemachine_write(&state_machine, pixels, num_bytes); + + // Use a private deinit of the state machine that doesn't reset the pin. + rp2pio_statemachine_deinit(&state_machine, true); + gpio_init(digitalinout->pin->number); + // Update the next start. + next_start_raw_ticks = port_get_raw_ticks(NULL) + 1; +} diff --git a/ports/raspberrypi/common-hal/os/__init__.c b/ports/raspberrypi/common-hal/os/__init__.c new file mode 100644 index 0000000000..dcbd06e937 --- /dev/null +++ b/ports/raspberrypi/common-hal/os/__init__.c @@ -0,0 +1,62 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 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" + + +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, "rp2040"); +STATIC const MP_DEFINE_STR_OBJ(os_uname_info_nodename_obj, "rp2040"); +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) { + return false; +} diff --git a/ports/raspberrypi/common-hal/pwmio/PWMOut.c b/ports/raspberrypi/common-hal/pwmio/PWMOut.c new file mode 100644 index 0000000000..567ec5ef54 --- /dev/null +++ b/ports/raspberrypi/common-hal/pwmio/PWMOut.c @@ -0,0 +1,216 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 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/runtime.h" +#include "common-hal/pwmio/PWMOut.h" +#include "shared-bindings/pwmio/PWMOut.h" +#include "shared-bindings/microcontroller/Processor.h" + +#include "supervisor/shared/translate.h" + +#include "src/rp2040/hardware_regs/include/hardware/platform_defs.h" +#include "src/rp2_common/hardware_clocks/include/hardware/clocks.h" +#include "src/rp2_common/hardware_gpio/include/hardware/gpio.h" +#include "src/rp2_common/hardware_pwm/include/hardware/pwm.h" + +uint32_t target_slice_frequencies[NUM_PWM_SLICES]; +uint32_t slice_fixed_frequency; + +#define CHANNELS_PER_SLICE 2 +static uint32_t channel_use; +static uint32_t never_reset_channel; + +static uint32_t _mask(uint8_t slice, uint8_t channel) { + return 1 << (slice * CHANNELS_PER_SLICE + channel); +} + +void common_hal_pwmio_pwmout_never_reset(pwmio_pwmout_obj_t *self) { + never_reset_channel |= _mask(self->slice, self->channel); + + never_reset_pin_number(self->pin->number); +} + +void common_hal_pwmio_pwmout_reset_ok(pwmio_pwmout_obj_t *self) { + never_reset_channel &= ~_mask(self->slice, self->channel); +} + +void pwmout_reset(void) { + // Reset all slices + for (size_t slice = 0; slice < NUM_PWM_SLICES; slice++) { + bool reset = true; + for (size_t channel = 0; channel < CHANNELS_PER_SLICE; channel++) { + uint32_t channel_use_mask = _mask(slice, channel); + if ((never_reset_channel & channel_use_mask) != 0) { + reset = false; + continue; + } + channel_use &= ~channel_use_mask; + } + if (!reset) { + continue; + } + pwm_set_enabled(slice, false); + target_slice_frequencies[slice] = 0; + slice_fixed_frequency &= ~(1 << slice); + } +} + +pwmout_result_t common_hal_pwmio_pwmout_construct(pwmio_pwmout_obj_t* self, + const mcu_pin_obj_t* pin, + uint16_t duty, + uint32_t frequency, + bool variable_frequency) { + self->pin = pin; + self->variable_frequency = variable_frequency; + self->duty_cycle = duty; + + if (frequency == 0 || frequency > (common_hal_mcu_processor_get_frequency() / 2)) { + return PWMOUT_INVALID_FREQUENCY; + } + + uint8_t slice = pwm_gpio_to_slice_num(pin->number); + uint8_t channel = pwm_gpio_to_channel(pin->number); + uint32_t channel_use_mask = _mask(slice, channel); + + // Check the channel first. + if ((channel_use & channel_use_mask) != 0) { + return PWMOUT_ALL_TIMERS_ON_PIN_IN_USE; + } + // Now check if the slice is in use and if we can share with it. + if (target_slice_frequencies[slice] > 0) { + // If we want to change frequency then we can't share. + if (variable_frequency) { + return PWMOUT_ALL_TIMERS_ON_PIN_IN_USE; + } + // If the other user wants to change frequency then we can't share either. + if ((slice_fixed_frequency & (1 << slice)) != 0) { + return PWMOUT_ALL_TIMERS_ON_PIN_IN_USE; + } + // If we're both fixed frequency but we don't match target frequencies then we can't share. + if (target_slice_frequencies[slice] != frequency) { + return PWMOUT_ALL_TIMERS_ON_PIN_IN_USE; + } + } + self->slice = slice; + self->channel = channel; + channel_use |= channel_use_mask; + if (!variable_frequency) { + slice_fixed_frequency |= 1 << slice; + } + + if (target_slice_frequencies[slice] != frequency) { + // Reset the counter and compare values. + pwm_hw->slice[slice].ctr = PWM_CH0_CTR_RESET; + common_hal_pwmio_pwmout_set_duty_cycle(self, duty); + common_hal_pwmio_pwmout_set_frequency(self, frequency); + pwm_set_enabled(slice, true); + } else { + common_hal_pwmio_pwmout_set_duty_cycle(self, duty); + } + + // Connect to the pad last to avoid any glitches from changing settings. + gpio_set_function(pin->number, GPIO_FUNC_PWM); + + return PWMOUT_OK; +} + +bool common_hal_pwmio_pwmout_deinited(pwmio_pwmout_obj_t* self) { + return self->pin == NULL; +} + +void common_hal_pwmio_pwmout_deinit(pwmio_pwmout_obj_t* self) { + if (common_hal_pwmio_pwmout_deinited(self)) { + return; + } + uint32_t channel_mask = _mask(self->slice, self->channel); + channel_use &= ~channel_mask; + never_reset_channel &= ~channel_mask; + uint32_t slice_mask = ((1 << CHANNELS_PER_SLICE) - 1) << (self->slice * CHANNELS_PER_SLICE + self->channel); + if ((channel_use & slice_mask) == 0) { + target_slice_frequencies[self->slice] = 0; + slice_fixed_frequency &= ~(1 << self->slice); + pwm_set_enabled(self->slice, false); + } + + reset_pin_number(self->pin->number); + self->pin = NULL; +} + +extern void common_hal_pwmio_pwmout_set_duty_cycle(pwmio_pwmout_obj_t* self, uint16_t duty) { + self->duty_cycle = duty; + uint16_t actual_duty = duty * self->top / ((1 << 16) - 1); + pwm_set_chan_level(self->slice, self->channel, actual_duty); +} + +uint16_t common_hal_pwmio_pwmout_get_duty_cycle(pwmio_pwmout_obj_t* self) { + return self->duty_cycle; +} + +void common_hal_pwmio_pwmout_set_frequency(pwmio_pwmout_obj_t* self, uint32_t frequency) { + if (frequency == 0 || frequency > (common_hal_mcu_processor_get_frequency() / 2)) { + mp_raise_ValueError(translate("Invalid PWM frequency")); + } + + target_slice_frequencies[self->slice] = frequency; + + // For low frequencies use the divider to give us full resolution duty_cycle. + if (frequency < (common_hal_mcu_processor_get_frequency() / (1 << 16))) { + // Compute the divisor. It's an 8 bit integer and 4 bit fraction. Therefore, + // we compute everything * 16 for the fractional part. + // This is 1 << 12 because 4 bits are the * 16. + uint64_t frequency16 = ((uint64_t) clock_get_hz(clk_sys)) / (1 << 12); + uint64_t div16 = frequency16 / frequency; + // Round the divisor to try and get closest to the target frequency. We could + // also always round up and use TOP to get us closer. We may not need that though. + if (frequency16 % frequency >= frequency / 2) { + div16 += 1; + } + if (div16 >= (1 << 12)) { + div16 = (1 << 12) - 1; + } + self->actual_frequency = frequency16 / div16; + self->top = 1 << 16; + pwm_set_clkdiv_int_frac(self->slice, div16 / 16, div16 % 16); + pwm_set_wrap(self->slice, self->top - 1); + } else { + uint32_t top = common_hal_mcu_processor_get_frequency() / frequency; + self->actual_frequency = common_hal_mcu_processor_get_frequency() / top; + self->top = top; + pwm_set_clkdiv_int_frac(self->slice, 1, 0); + pwm_set_wrap(self->slice, self->top - 1); + } + common_hal_pwmio_pwmout_set_duty_cycle(self, self->duty_cycle); +} + +uint32_t common_hal_pwmio_pwmout_get_frequency(pwmio_pwmout_obj_t* self) { + return self->actual_frequency; +} + +bool common_hal_pwmio_pwmout_get_variable_frequency(pwmio_pwmout_obj_t* self) { + return self->variable_frequency; +} diff --git a/ports/raspberrypi/common-hal/pwmio/PWMOut.h b/ports/raspberrypi/common-hal/pwmio/PWMOut.h new file mode 100644 index 0000000000..50f84777b5 --- /dev/null +++ b/ports/raspberrypi/common-hal/pwmio/PWMOut.h @@ -0,0 +1,47 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 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_PWMIO_PWMOUT_H +#define MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_PWMIO_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; + uint8_t slice; + uint8_t channel; + bool variable_frequency; + uint16_t duty_cycle; + uint32_t actual_frequency; + uint32_t top; +} pwmio_pwmout_obj_t; + +void pwmout_reset(void); + +#endif // MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_PWMIO_PWMOUT_H diff --git a/ports/raspberrypi/common-hal/pwmio/__init__.c b/ports/raspberrypi/common-hal/pwmio/__init__.c new file mode 100644 index 0000000000..9e551a1072 --- /dev/null +++ b/ports/raspberrypi/common-hal/pwmio/__init__.c @@ -0,0 +1 @@ +// No pwmio module functions. diff --git a/ports/raspberrypi/common-hal/rp2pio/StateMachine.c b/ports/raspberrypi/common-hal/rp2pio/StateMachine.c new file mode 100644 index 0000000000..d613771a4f --- /dev/null +++ b/ports/raspberrypi/common-hal/rp2pio/StateMachine.c @@ -0,0 +1,586 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 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 "bindings/rp2pio/StateMachine.h" + +#include "common-hal/microcontroller/__init__.h" +#include "shared-bindings/microcontroller/Pin.h" + +#include "src/rp2040/hardware_regs/include/hardware/platform_defs.h" +#include "src/rp2_common/hardware_clocks/include/hardware/clocks.h" +#include "src/rp2_common/hardware_dma/include/hardware/dma.h" +#include "src/rp2_common/hardware_pio/include/hardware/pio_instructions.h" +#include "src/rp2040/hardware_structs/include/hardware/structs/iobank0.h" + +#include "lib/utils/interrupt_char.h" +#include "py/obj.h" +#include "py/objproperty.h" +#include "py/runtime.h" + +// Count how many state machines are using each pin. +STATIC uint8_t _pin_reference_count[TOTAL_GPIO_COUNT]; +STATIC uint32_t _current_program_id[NUM_PIOS][NUM_PIO_STATE_MACHINES]; +STATIC uint8_t _current_program_offset[NUM_PIOS][NUM_PIO_STATE_MACHINES]; +STATIC uint8_t _current_program_len[NUM_PIOS][NUM_PIO_STATE_MACHINES]; +STATIC bool _never_reset[NUM_PIOS][NUM_PIO_STATE_MACHINES]; + +STATIC uint32_t _current_pins[NUM_PIOS]; +STATIC uint32_t _current_sm_pins[NUM_PIOS][NUM_PIO_STATE_MACHINES]; + +STATIC PIO pio_instances[2] = {pio0, pio1}; + +void _reset_statemachine(PIO pio, uint8_t sm, bool leave_pins) { + uint8_t pio_index = pio_get_index(pio); + pio_sm_unclaim(pio, sm); + uint32_t program_id = _current_program_id[pio_index][sm]; + if (program_id == 0) { + return; + } + _current_program_id[pio_index][sm] = 0; + bool program_in_use = false; + for (size_t i = 0; i < NUM_PIO_STATE_MACHINES; i++) { + if (_current_program_id[pio_index][i] == program_id) { + program_in_use = true; + break; + } + } + if (!program_in_use) { + uint8_t offset = _current_program_offset[pio_index][sm]; + pio_program_t program_struct = { + .length = _current_program_len[pio_index][sm] + }; + pio_remove_program(pio, &program_struct, offset); + } + + uint32_t pins = _current_sm_pins[pio_index][sm]; + for (size_t pin_number = 0; pin_number < TOTAL_GPIO_COUNT; pin_number++) { + if ((pins & (1 << pin_number)) == 0) { + continue; + } + _pin_reference_count[pin_number]--; + if (_pin_reference_count[pin_number] == 0) { + if (!leave_pins) { + reset_pin_number(pin_number); + } + _current_pins[pio_index] &= ~(1 << pin_number); + } + } + _current_sm_pins[pio_index][sm] = 0; +} + +void reset_rp2pio_statemachine(void) { + for (size_t i = 0; i < NUM_PIOS; i++) { + PIO pio = pio_instances[i]; + for (size_t j = 0; j < NUM_PIO_STATE_MACHINES; j++) { + if (_never_reset[i][j]) { + continue; + } + _reset_statemachine(pio, j, false); + } + } +} + +STATIC uint32_t _check_pins_free(const mcu_pin_obj_t * first_pin, uint8_t pin_count, bool exclusive_pin_use) { + uint32_t pins_we_use = 0; + if (first_pin != NULL) { + for (size_t i = 0; i < pin_count; i++) { + uint8_t pin_number = first_pin->number + i; + if (pin_number >= TOTAL_GPIO_COUNT) { + mp_raise_ValueError(translate("Pin count too large")); + } + const mcu_pin_obj_t * pin = mcu_pin_global_dict_table[pin_number].value; + if (exclusive_pin_use || _pin_reference_count[pin_number] == 0) { + assert_pin_free(pin); + } + pins_we_use |= 1 << pin_number; + } + } + return pins_we_use; +} + + +bool rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self, + const uint16_t* program, size_t program_len, + size_t frequency, + const uint16_t* init, size_t init_len, + const mcu_pin_obj_t * first_out_pin, uint8_t out_pin_count, + const mcu_pin_obj_t * first_in_pin, uint8_t in_pin_count, + const mcu_pin_obj_t * first_set_pin, uint8_t set_pin_count, + const mcu_pin_obj_t * first_sideset_pin, uint8_t sideset_pin_count, + uint32_t pins_we_use, bool tx_fifo, bool rx_fifo, + bool auto_pull, uint8_t pull_threshold, bool out_shift_right, + bool auto_push, uint8_t push_threshold, bool in_shift_right, + bool claim_pins) { + // Create a program id that isn't the pointer so we can store it without storing the original object. + uint32_t program_id = ~((uint32_t) program); + + // Next, find a PIO and state machine to use. + size_t pio_index = NUM_PIOS; + uint8_t program_offset = 32; + pio_program_t program_struct = { + .instructions = (uint16_t*) program, + .length = program_len, + .origin = 0 + }; + for (size_t i = 0; i < NUM_PIOS; i++) { + PIO pio = pio_instances[i]; + uint8_t free_count = 0; + for (size_t j = 0; j < NUM_PIO_STATE_MACHINES; j++) { + if (_current_program_id[i][j] == program_id && + _current_program_len[i][j] == program_len) { + program_offset = _current_program_offset[i][j]; + } + int temp_claim = pio_claim_unused_sm(pio, false); + if (temp_claim >= 0) { + pio_sm_unclaim(pio, temp_claim); + free_count++; + } + } + if (free_count > 0 && (program_offset < 32 || pio_can_add_program(pio, &program_struct))) { + pio_index = i; + if (program_offset < 32) { + break; + } + } + // Reset program offset if we weren't able to find a free state machine + // on that PIO. (We would have broken the loop otherwise.) + program_offset = 32; + } + + int state_machine = -1; + if (pio_index < NUM_PIOS) { + PIO pio = pio_instances[pio_index]; + for (size_t i = 0; i < NUM_PIOS; i++) { + if (i == pio_index) { + continue; + } + if ((_current_pins[i] & pins_we_use) != 0) { + // Pin in use by another PIO already. + return false; + } + } + state_machine = pio_claim_unused_sm(pio, false); + } + if (pio_index == NUM_PIOS || state_machine < 0 || state_machine >= NUM_PIO_STATE_MACHINES) { + return false; + } + + self->pio = pio_instances[pio_index]; + self->state_machine = state_machine; + if (program_offset == 32) { + program_offset = pio_add_program(self->pio, &program_struct); + } + _current_program_id[pio_index][state_machine] = program_id; + _current_program_len[pio_index][state_machine] = program_len; + _current_program_offset[pio_index][state_machine] = program_offset; + _current_sm_pins[pio_index][state_machine] = pins_we_use; + _current_pins[pio_index] |= pins_we_use; + + for (size_t pin_number = 0; pin_number < TOTAL_GPIO_COUNT; pin_number++) { + if ((pins_we_use & (1 << pin_number)) == 0) { + continue; + } + _pin_reference_count[pin_number]++; + const mcu_pin_obj_t * pin = mcu_pin_global_dict_table[pin_number].value; + // Also claim the pin at the top level when we're the first to grab it. + if (_pin_reference_count[pin_number] == 1) { + if (claim_pins) { + claim_pin(pin); + } + pio_gpio_init(self->pio, pin_number); + } + } + + pio_sm_config c = {0, 0, 0}; + + if (frequency == 0) { + frequency = clock_get_hz(clk_sys); + } + uint64_t frequency256 = ((uint64_t) clock_get_hz(clk_sys)) * 256; + uint64_t div256 = frequency256 / frequency; + if (frequency256 % div256 > 0) { + div256 += 1; + } + self->actual_frequency = frequency256 / div256; + sm_config_set_clkdiv_int_frac(&c, div256 / 256, div256 % 256); + + if (first_out_pin != NULL) { + sm_config_set_out_pins(&c, first_out_pin->number, out_pin_count); + } + if (first_in_pin != NULL) { + sm_config_set_in_pins(&c, first_in_pin->number); + } + if (first_set_pin != NULL) { + sm_config_set_set_pins(&c, first_set_pin->number, set_pin_count); + } + if (first_sideset_pin != NULL) { + sm_config_set_sideset(&c, sideset_pin_count, false /* optional */, false /* pin direction */); + sm_config_set_sideset_pins(&c, first_sideset_pin->number); + } + sm_config_set_wrap(&c, program_offset, program_offset + program_len - 1); + sm_config_set_in_shift(&c, in_shift_right, auto_push, push_threshold); + sm_config_set_out_shift(&c, out_shift_right, auto_pull, pull_threshold); + + enum pio_fifo_join join = PIO_FIFO_JOIN_NONE; + if (!rx_fifo) { + join = PIO_FIFO_JOIN_TX; + } else if (!tx_fifo) { + join = PIO_FIFO_JOIN_RX; + } + if (rx_fifo) { + self->rx_dreq = pio_get_dreq(self->pio, self->state_machine, false); + } + if (tx_fifo) { + self->tx_dreq = pio_get_dreq(self->pio, self->state_machine, true); + } + self->in = rx_fifo; + self->out = tx_fifo; + self->out_shift_right = out_shift_right; + self->in_shift_right = in_shift_right; + + sm_config_set_fifo_join(&c, join); + + pio_sm_init(self->pio, self->state_machine, program_offset, &c); + pio_sm_set_enabled(self->pio, self->state_machine, true); + for (size_t i = 0; i < init_len; i++) { + pio_sm_exec(self->pio, self->state_machine, init[i]); + } + return true; +} + +void common_hal_rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self, + const uint16_t* program, size_t program_len, + size_t frequency, + const uint16_t* init, size_t init_len, + const mcu_pin_obj_t * first_out_pin, uint8_t out_pin_count, + const mcu_pin_obj_t * first_in_pin, uint8_t in_pin_count, + const mcu_pin_obj_t * first_set_pin, uint8_t set_pin_count, + const mcu_pin_obj_t * first_sideset_pin, uint8_t sideset_pin_count, + bool exclusive_pin_use, + bool auto_pull, uint8_t pull_threshold, bool out_shift_right, + bool auto_push, uint8_t push_threshold, bool in_shift_right) { + + // First, check that all pins are free OR already in use by any PIO if exclusive_pin_use is false. + uint32_t pins_we_use = 0; + pins_we_use |= _check_pins_free(first_out_pin, out_pin_count, exclusive_pin_use); + pins_we_use |= _check_pins_free(first_in_pin, in_pin_count, exclusive_pin_use); + pins_we_use |= _check_pins_free(first_set_pin, set_pin_count, exclusive_pin_use); + pins_we_use |= _check_pins_free(first_sideset_pin, sideset_pin_count, exclusive_pin_use); + + // Look through the program to see what we reference and make sure it was provided. + bool tx_fifo = false; + bool rx_fifo = false; + bool in_loaded = false; // can be loaded in other ways besides the fifo + bool out_loaded = false; + bool in_used = false; + bool out_used = false; + for (size_t i = 0; i < program_len; i++) { + uint16_t full_instruction = program[i]; + uint16_t instruction = full_instruction & 0xe000; + if (instruction == 0x8000) { + if ((full_instruction & 0xe080) == pio_instr_bits_push) { + rx_fifo = true; + in_loaded = true; + } else { // pull otherwise. + tx_fifo = true; + out_loaded = true; + } + } + if (instruction == pio_instr_bits_jmp) { + uint16_t condition = (full_instruction & 0x00e0) >> 5; + if (condition == 0x6) { // GPIO + mp_raise_NotImplementedError_varg(translate("Instruction %d jumps on pin"), i); + } + } + if (instruction == pio_instr_bits_wait) { + uint16_t wait_source = (full_instruction & 0x0060) >> 5; + uint16_t wait_index = full_instruction & 0x001f; + if (wait_source == 0 && (pins_we_use & (1 << wait_index)) == 0) { // GPIO + mp_raise_ValueError_varg(translate("Instruction %d uses extra pin"), i); + } + if (wait_source == 1) { // Input pin + if (first_in_pin == NULL) { + mp_raise_ValueError_varg(translate("Missing first_in_pin. Instruction %d waits based on pin"), i); + } + if (wait_index > in_pin_count) { + mp_raise_ValueError_varg(translate("Instruction %d waits on input outside of count"), i); + } + } + } + if (instruction == pio_instr_bits_in) { + uint16_t source = (full_instruction & 0x00e0) >> 5; + uint16_t bit_count = full_instruction & 0x001f; + if (source == 0) { + if (first_in_pin == NULL) { + mp_raise_ValueError_varg(translate("Missing first_in_pin. Instruction %d shifts in from pin(s)"), i); + } + if (bit_count > in_pin_count) { + mp_raise_ValueError_varg(translate("Instruction %d shifts in more bits than pin count"), i); + } + } + if (auto_push) { + in_loaded = true; + rx_fifo = true; + } + in_used = true; + } + if (instruction == pio_instr_bits_out) { + uint16_t bit_count = full_instruction & 0x001f; + uint16_t destination = (full_instruction & 0x00e0) >> 5; + // Check for pins or pindirs destination. + if (destination == 0x0 || destination == 0x4) { + if (first_out_pin == NULL) { + mp_raise_ValueError_varg(translate("Missing first_out_pin. Instruction %d shifts out to pin(s)"), i); + } + if (bit_count > out_pin_count) { + mp_raise_ValueError_varg(translate("Instruction %d shifts out more bits than pin count"), i); + } + } + if (auto_pull) { + out_loaded = true; + tx_fifo = true; + } + out_used = true; + } + if (instruction == pio_instr_bits_set) { + uint16_t destination = (full_instruction & 0x00e0) >> 5; + // Check for pins or pindirs destination. + if ((destination == 0x00 || destination == 0x4) && first_set_pin == NULL) { + mp_raise_ValueError_varg(translate("Missing first_set_pin. Instruction %d sets pin(s)"), i); + } + } + if (instruction == pio_instr_bits_mov) { + uint16_t source = full_instruction & 0x0007; + uint16_t destination = (full_instruction & 0x00e0) >> 5; + // Check for pins or pindirs destination. + if (destination == 0x0 && first_out_pin == NULL) { + mp_raise_ValueError_varg(translate("Missing first_out_pin. Instruction %d writes pin(s)"), i); + } + if (source == 0x0 && first_in_pin == NULL) { + mp_raise_ValueError_varg(translate("Missing first_in_pin. Instruction %d reads pin(s)"), i); + } + if (destination == 0x6) { + in_loaded = true; + } else if (destination == 0x7) { + out_loaded = true; + } + } + } + + if (!in_loaded && in_used) { + mp_raise_ValueError_varg(translate("Program does IN without loading ISR")); + } + if (!out_loaded && out_used) { + mp_raise_ValueError_varg(translate("Program does OUT without loading OSR")); + } + + if (in_pin_count > 8 || out_pin_count > 8) { + mp_raise_NotImplementedError(translate("Only IN/OUT of up to 8 supported")); + } + + bool ok = rp2pio_statemachine_construct(self, + program, program_len, + frequency, + init, init_len, + first_out_pin, out_pin_count, + first_in_pin, in_pin_count, + first_set_pin, set_pin_count, + first_sideset_pin, sideset_pin_count, + pins_we_use, tx_fifo, rx_fifo, + auto_pull, pull_threshold, out_shift_right, + auto_push, push_threshold, in_shift_right, + true /* claim pins */); + if (!ok) { + mp_raise_RuntimeError(translate("All state machines in use")); + } +} + +uint32_t common_hal_rp2pio_statemachine_get_frequency(rp2pio_statemachine_obj_t* self) { + return self->actual_frequency; +} + +void rp2pio_statemachine_deinit(rp2pio_statemachine_obj_t *self, bool leave_pins) { + uint8_t sm = self->state_machine; + uint8_t pio_index = pio_get_index(self->pio); + _never_reset[pio_index][sm] = false; + _reset_statemachine(self->pio, sm, leave_pins); + self->state_machine = NUM_PIO_STATE_MACHINES; +} + +void common_hal_rp2pio_statemachine_deinit(rp2pio_statemachine_obj_t *self) { + rp2pio_statemachine_deinit(self, false); +} + +void common_hal_rp2pio_statemachine_never_reset(rp2pio_statemachine_obj_t *self) { + uint8_t sm = self->state_machine; + uint8_t pio_index = pio_get_index(self->pio); + _never_reset[pio_index][sm] = true; + // TODO: never reset all the pins +} + +bool common_hal_rp2pio_statemachine_deinited(rp2pio_statemachine_obj_t *self) { + return self->state_machine == NUM_PIO_STATE_MACHINES; +} + +static bool _transfer(rp2pio_statemachine_obj_t *self, + const uint8_t *data_out, size_t out_len, + uint8_t *data_in, size_t in_len) { + // This implementation is based on SPI but varies because the tx and rx buffers + // may be different lengths and occur at different times or speeds. + + // Use DMA for large transfers if channels are available + const size_t dma_min_size_threshold = 32; + int chan_tx = -1; + int chan_rx = -1; + size_t len = MAX(out_len, in_len); + bool tx = data_out != NULL; + bool rx = data_in != NULL; + if (len >= dma_min_size_threshold) { + // Use DMA channels to service the two FIFOs + if (tx) { + chan_tx = dma_claim_unused_channel(false); + } + if (rx) { + chan_rx = dma_claim_unused_channel(false); + } + } + volatile uint8_t* tx_destination = NULL; + const volatile uint8_t* rx_source = NULL; + if (tx) { + tx_destination = (volatile uint8_t*) &self->pio->txf[self->state_machine]; + if (!self->out_shift_right) { + tx_destination += 3; + } + } + if (rx) { + rx_source = (const volatile uint8_t*) &self->pio->rxf[self->state_machine]; + if (!self->in_shift_right) { + rx_source += 3; + } + } + bool use_dma = (!rx || chan_rx >= 0) && (!tx || chan_tx >= 0); + if (use_dma) { + dma_channel_config c; + uint32_t channel_mask = 0; + if (tx) { + c = dma_channel_get_default_config(chan_tx); + channel_config_set_transfer_data_size(&c, DMA_SIZE_8); + channel_config_set_dreq(&c, self->tx_dreq); + channel_config_set_read_increment(&c, true); + channel_config_set_write_increment(&c, false); + dma_channel_configure(chan_tx, &c, + tx_destination, + data_out, + len, + false); + channel_mask |= 1u << chan_tx; + } + if (rx) { + c = dma_channel_get_default_config(chan_rx); + channel_config_set_transfer_data_size(&c, DMA_SIZE_8); + channel_config_set_dreq(&c, self->rx_dreq); + channel_config_set_read_increment(&c, false); + channel_config_set_write_increment(&c, true); + dma_channel_configure(chan_rx, &c, + data_in, + rx_source, + len, + false); + channel_mask |= 1u << chan_rx; + } + + dma_start_channel_mask(channel_mask); + while ((rx && dma_channel_is_busy(chan_rx)) || + (tx && dma_channel_is_busy(chan_tx))) { + // TODO: We should idle here until we get a DMA interrupt or something else. + RUN_BACKGROUND_TASKS; + if (mp_hal_is_interrupted()) { + if (rx && dma_channel_is_busy(chan_rx)) { + dma_channel_abort(chan_rx); + } + if (tx && dma_channel_is_busy(chan_tx)) { + dma_channel_abort(chan_tx); + } + break; + } + } + // Clear the stall bit so we can detect when the state machine is done transmitting. + self->pio->fdebug = PIO_FDEBUG_TXSTALL_BITS; + } + + // If we have claimed only one channel successfully, we should release immediately. This also + // releases the DMA after use_dma has been done. + if (chan_rx >= 0) { + dma_channel_unclaim(chan_rx); + } + if (chan_tx >= 0) { + dma_channel_unclaim(chan_tx); + } + + if (!use_dma && !mp_hal_is_interrupted()) { + // Use software for small transfers, or if couldn't claim two DMA channels + size_t rx_remaining = in_len; + size_t tx_remaining = out_len; + + while (rx_remaining || tx_remaining) { + if (tx_remaining && !pio_sm_is_tx_fifo_full(self->pio, self->state_machine)) { + *tx_destination = *data_out; + data_out++; + --tx_remaining; + } + if (rx_remaining && !pio_sm_is_rx_fifo_empty(self->pio, self->state_machine)) { + *data_in = (uint8_t) *rx_source; + data_in++; + --rx_remaining; + } + RUN_BACKGROUND_TASKS; + if (mp_hal_is_interrupted()) { + break; + } + } + // Clear the stall bit so we can detect when the state machine is done transmitting. + self->pio->fdebug = PIO_FDEBUG_TXSTALL_BITS; + } + // Wait for the state machine to finish transmitting the data we've queued + // up. + if (tx) { + while (!pio_sm_is_tx_fifo_empty(self->pio, self->state_machine) || + (self->pio->fdebug & PIO_FDEBUG_TXSTALL_BITS) == 0) { + RUN_BACKGROUND_TASKS; + } + } + return true; +} + +// Writes out the given data. +bool common_hal_rp2pio_statemachine_write(rp2pio_statemachine_obj_t *self, + const uint8_t *data, size_t len) { + if (!self->out) { + mp_raise_RuntimeError(translate("No out in program")); + } + return _transfer(self, data, len, NULL, 0); +} + diff --git a/ports/raspberrypi/common-hal/rp2pio/StateMachine.h b/ports/raspberrypi/common-hal/rp2pio/StateMachine.h new file mode 100644 index 0000000000..6b70b6b5b5 --- /dev/null +++ b/ports/raspberrypi/common-hal/rp2pio/StateMachine.h @@ -0,0 +1,68 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 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_RASPBERRYPI_COMMON_HAL_RP2PIO_STATEMACHINE_H +#define MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_RP2PIO_STATEMACHINE_H + +#include "py/obj.h" + +#include "src/rp2_common/hardware_pio/include/hardware/pio.h" + +typedef struct { + mp_obj_base_t base; + uint32_t pins; // Bitmask of what pins this state machine uses. + int state_machine; + PIO pio; + bool in; + bool out; + uint tx_dreq; + uint rx_dreq; + bool out_shift_right; + bool in_shift_right; + uint32_t actual_frequency; +} rp2pio_statemachine_obj_t; + +void reset_rp2pio_statemachine(void); + +// Minimal internal version that only fails on pin error (not in use) or full PIO. +bool rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self, + const uint16_t* program, size_t program_len, + size_t frequency, + const uint16_t* init, size_t init_len, + const mcu_pin_obj_t * first_out_pin, uint8_t out_pin_count, + const mcu_pin_obj_t * first_in_pin, uint8_t in_pin_count, + const mcu_pin_obj_t * first_set_pin, uint8_t set_pin_count, + const mcu_pin_obj_t * first_sideset_pin, uint8_t sideset_pin_count, + uint32_t pins_we_use, bool tx_fifo, bool rx_fifo, + bool auto_pull, uint8_t pull_threshold, bool out_shift_right, + bool auto_push, uint8_t push_threshold, bool in_shift_right, + bool claim_pins); + +void rp2pio_statemachine_deinit(rp2pio_statemachine_obj_t *self, bool leave_pins); + +extern const mp_obj_type_t rp2pio_statemachine_type; + +#endif // MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_RP2PIO_STATEMACHINE_H diff --git a/ports/raspberrypi/common-hal/rp2pio/__init__.c b/ports/raspberrypi/common-hal/rp2pio/__init__.c new file mode 100644 index 0000000000..21699dfa36 --- /dev/null +++ b/ports/raspberrypi/common-hal/rp2pio/__init__.c @@ -0,0 +1 @@ +// Nothing yet. diff --git a/ports/raspberrypi/common-hal/supervisor/Runtime.c b/ports/raspberrypi/common-hal/supervisor/Runtime.c new file mode 100755 index 0000000000..6be38f216a --- /dev/null +++ b/ports/raspberrypi/common-hal/supervisor/Runtime.c @@ -0,0 +1,37 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Michael Schroeder + * + * 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 "shared-bindings/supervisor/Runtime.h" +#include "supervisor/serial.h" + +bool common_hal_get_serial_connected(void) { + return (bool) serial_connected(); +} + +bool common_hal_get_serial_bytes_available(void) { + return (bool) serial_bytes_available(); +} diff --git a/ports/raspberrypi/common-hal/supervisor/Runtime.h b/ports/raspberrypi/common-hal/supervisor/Runtime.h new file mode 100755 index 0000000000..45db489bda --- /dev/null +++ b/ports/raspberrypi/common-hal/supervisor/Runtime.h @@ -0,0 +1,37 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Michael Schroeder + * + * 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_RASPBERRYPI_COMMON_HAL_SUPERVISOR_RUNTIME_H +#define MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_SUPERVISOR_RUNTIME_H + +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; + // Stores no state currently. +} super_runtime_obj_t; + +#endif // MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_SUPERVISOR_RUNTIME_H diff --git a/ports/raspberrypi/common-hal/supervisor/__init__.c b/ports/raspberrypi/common-hal/supervisor/__init__.c new file mode 100755 index 0000000000..6dca35fb5a --- /dev/null +++ b/ports/raspberrypi/common-hal/supervisor/__init__.c @@ -0,0 +1,40 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Michael Schroeder + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + +#include "py/obj.h" + +#include "shared-bindings/supervisor/__init__.h" +#include "shared-bindings/supervisor/Runtime.h" + + +// The singleton supervisor.Runtime object, bound to supervisor.runtime +// It currently only has properties, and no state. +const super_runtime_obj_t common_hal_supervisor_runtime_obj = { + .base = { + .type = &supervisor_runtime_type, + }, +}; diff --git a/ports/raspberrypi/fatfs_port.c b/ports/raspberrypi/fatfs_port.c new file mode 100644 index 0000000000..c65a73a428 --- /dev/null +++ b/ports/raspberrypi/fatfs_port.c @@ -0,0 +1,48 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * SPDX-FileCopyrightText: 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 "py/mphal.h" +#include "py/runtime.h" +#include "lib/oofatfs/ff.h" /* FatFs lower layer API */ +#include "lib/oofatfs/diskio.h" /* FatFs lower layer API */ +#include "lib/timeutils/timeutils.h" + +#if CIRCUITPY_RTC +#include "shared-bindings/rtc/RTC.h" +#endif + +DWORD get_fattime(void) { +#if CIRCUITPY_RTC + timeutils_struct_time_t tm; + common_hal_rtc_get_time(&tm); + return ((tm.tm_year - 1980) << 25) | (tm.tm_mon << 21) | (tm.tm_mday << 16) | + (tm.tm_hour << 11) | (tm.tm_min << 5) | (tm.tm_sec >> 1); +#else + return ((2016 - 1980) << 25) | ((9) << 21) | ((1) << 16) | ((16) << 11) | ((43) << 5) | (35 / 2); +#endif + + +} diff --git a/ports/raspberrypi/link.ld b/ports/raspberrypi/link.ld new file mode 100644 index 0000000000..dcf5c9a37a --- /dev/null +++ b/ports/raspberrypi/link.ld @@ -0,0 +1,251 @@ +/* Based on GCC ARM embedded samples. + Defines the following symbols for use by code: + __exidx_start + __exidx_end + __etext + __data_start__ + __preinit_array_start + __preinit_array_end + __init_array_start + __init_array_end + __fini_array_start + __fini_array_end + __data_end__ + __bss_start__ + __bss_end__ + __end__ + end + __HeapLimit + __StackLimit + __StackTop + __stack (== StackTop) +*/ + +MEMORY +{ + FLASH_FIRMWARE (rx) : ORIGIN = 0x10000000, LENGTH = 1024k + RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 256k + SCRATCH_X (rwx) : ORIGIN = 0x20040000, LENGTH = 4k + SCRATCH_Y (rwx) : ORIGIN = 0x20041000, LENGTH = 4k +} + +ENTRY(_entry_point) + +SECTIONS +{ + /* Second stage bootloader is prepended to the image. It must be 256 bytes big + and checksummed. It is usually built by the boot_stage2 target + in the Pico SDK + */ + + .flash_begin : { + __flash_binary_start = .; + } > FLASH_FIRMWARE + + .boot2 : { + __boot2_start__ = .; + KEEP (*(.boot2)) + __boot2_end__ = .; + } > FLASH_FIRMWARE + + ASSERT(__boot2_end__ - __boot2_start__ == 256, + "ERROR: Pico second stage bootloader must be 256 bytes in size") + + /* The second stage will always enter the image at the start of .text. + The debugger will use the ELF entry point, which is the _entry_point + symbol if present, otherwise defaults to start of .text. + This can be used to transfer control back to the bootrom on debugger + launches only, to perform proper flash setup. + */ + + .text : { + __reset_start = .; + KEEP (*(.reset)) + . = ALIGN(256); + __reset_end = .; + ASSERT(__reset_end - __reset_start == 256, "ERROR: reset section should only be 256 bytes"); + KEEP (*(.vectors)) + /* TODO revisit this now memset/memcpy/float in ROM */ + /* bit of a hack right now to exclude all floating point and time critical (e.g. memset, memcpy) code from + * FLASH ... we will include any thing excluded here in .data below by default */ + *(.init) + *(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .text*) + *(.fini) + /* Pull all c'tors into .text */ + *crtbegin.o(.ctors) + *crtbegin?.o(.ctors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) + *(SORT(.ctors.*)) + *(.ctors) + /* Followed by destructors */ + *crtbegin.o(.dtors) + *crtbegin?.o(.dtors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) + *(SORT(.dtors.*)) + *(.dtors) + + *(.eh_frame*) + . = ALIGN(4); + } > FLASH_FIRMWARE + + .rodata : { + *(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .rodata*) + . = ALIGN(4); + *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.flashdata*))) + . = ALIGN(4); + } > FLASH_FIRMWARE + + .ARM.extab : + { + *(.ARM.extab* .gnu.linkonce.armextab.*) + } > FLASH_FIRMWARE + + __exidx_start = .; + .ARM.exidx : + { + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + } > FLASH_FIRMWARE + __exidx_end = .; + + /* Machine inspectable binary information */ + . = ALIGN(4); + __binary_info_start = .; + .binary_info : + { + KEEP(*(.binary_info.keep.*)) + *(.binary_info.*) + } > FLASH_FIRMWARE + __binary_info_end = .; + . = ALIGN(4); + + /* End of .text-like segments */ + __etext = .; + + .ram_vector_table (COPY): { + *(.ram_vector_table) + } > RAM + + .data : { + __data_start__ = .; + *(vtable) + + *(.time_critical*) + + /* remaining .text and .rodata; i.e. stuff we exclude above because we want it in RAM */ + *(.text*) + . = ALIGN(4); + *(.rodata*) + . = ALIGN(4); + + *(.data*) + + . = ALIGN(4); + *(.after_data.*) + . = ALIGN(4); + /* preinit data */ + PROVIDE_HIDDEN (__mutex_array_start = .); + KEEP(*(SORT(.mutex_array.*))) + KEEP(*(.mutex_array)) + PROVIDE_HIDDEN (__mutex_array_end = .); + + . = ALIGN(4); + /* preinit data */ + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP(*(SORT(.preinit_array.*))) + KEEP(*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + + . = ALIGN(4); + /* init data */ + PROVIDE_HIDDEN (__init_array_start = .); + KEEP(*(SORT(.init_array.*))) + KEEP(*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + + . = ALIGN(4); + /* finit data */ + PROVIDE_HIDDEN (__fini_array_start = .); + *(SORT(.fini_array.*)) + *(.fini_array) + PROVIDE_HIDDEN (__fini_array_end = .); + + *(.jcr) + . = ALIGN(4); + /* All data end */ + __data_end__ = .; + } > RAM AT> FLASH_FIRMWARE + + .uninitialized_data (COPY): { + . = ALIGN(4); + *(.uninitialized_data*) + } > RAM + + /* Start and end symbols must be word-aligned */ + .scratch_x : { + __scratch_x_start__ = .; + *(.scratch_x.*) + . = ALIGN(4); + __scratch_x_end__ = .; + } > SCRATCH_X AT > FLASH_FIRMWARE + __scratch_x_source__ = LOADADDR(.scratch_x); + + .scratch_y : { + __scratch_y_start__ = .; + *(.scratch_y.*) + . = ALIGN(4); + __scratch_y_end__ = .; + } > SCRATCH_Y AT > FLASH_FIRMWARE + __scratch_y_source__ = LOADADDR(.scratch_y); + + .bss : { + . = ALIGN(4); + __bss_start__ = .; + *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.bss*))) + *(COMMON) + . = ALIGN(4); + __bss_end__ = .; + } > RAM + + .heap (COPY): + { + __end__ = .; + end = __end__; + *(.heap*) + __HeapLimit = .; + } > RAM + + /* .stack*_dummy section doesn't contains any symbols. It is only + * used for linker to calculate size of stack sections, and assign + * values to stack symbols later + * + * stack1 section may be empty/missing if platform_launch_core1 is not used */ + + /* by default we put core 0 stack at the end of scratch Y, so that if core 1 + * stack is not used then all of SCRATCH_X is free. + */ + .stack1_dummy (COPY): + { + *(.stack1*) + } > SCRATCH_X + .stack_dummy (COPY): + { + *(.stack*) + } > SCRATCH_Y + + .flash_end : { + __flash_binary_end = .; + } > FLASH_FIRMWARE + + /* stack limit is poorly named, but historically is maximum heap ptr */ + __StackLimit = ORIGIN(RAM) + LENGTH(RAM); + __StackOneTop = ORIGIN(SCRATCH_X) + LENGTH(SCRATCH_X); + __StackTop = ORIGIN(SCRATCH_Y) + LENGTH(SCRATCH_Y); + __StackOneBottom = __StackOneTop - SIZEOF(.stack1_dummy); + __StackBottom = __StackTop - SIZEOF(.stack_dummy); + PROVIDE(__stack = __StackTop); + + /* Check if data + heap + stack exceeds RAM limit */ + ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed") + /* todo assert on extra code */ +} + diff --git a/ports/raspberrypi/mpconfigport.h b/ports/raspberrypi/mpconfigport.h new file mode 100644 index 0000000000..3fdc8febbf --- /dev/null +++ b/ports/raspberrypi/mpconfigport.h @@ -0,0 +1,46 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 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 __INCLUDED_MPCONFIGPORT_H +#define __INCLUDED_MPCONFIGPORT_H + +#define MICROPY_PY_UJSON (1) + +#define CIRCUITPY_INTERNAL_NVM_SIZE 0 + +#define CIRCUITPY_DEFAULT_STACK_SIZE (24*1024) + +#define MICROPY_USE_INTERNAL_PRINTF (1) + +#define CIRCUITPY_PROCESSOR_COUNT (2) + +// This also includes mpconfigboard.h. +#include "py/circuitpy_mpconfig.h" + +#define MICROPY_PORT_ROOT_POINTERS \ + CIRCUITPY_COMMON_ROOT_POINTERS; + +#endif // __INCLUDED_MPCONFIGPORT_H diff --git a/ports/raspberrypi/mpconfigport.mk b/ports/raspberrypi/mpconfigport.mk new file mode 100644 index 0000000000..a6211be73d --- /dev/null +++ b/ports/raspberrypi/mpconfigport.mk @@ -0,0 +1,44 @@ +# 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. + +ifeq ($(LONGINT_IMPL),NONE) +MPY_TOOL_LONGINT_IMPL = -mlongint-impl=none +endif + +ifeq ($(LONGINT_IMPL),MPZ) +MPY_TOOL_LONGINT_IMPL = -mlongint-impl=mpz +endif + +ifeq ($(LONGINT_IMPL),LONGLONG) +MPY_TOOL_LONGINT_IMPL = -mlongint-impl=longlong +endif + +ifndef CIRCUITPY_RP2PIO +CIRCUITPY_RP2PIO = 1 +else +CIRCUITPY_NEOPIXEL_WRITE = 0 +endif + +CIRCUITPY_FULL_BUILD = 1 +CIRCUITPY_PWMIO = 1 + +# Things that need to be implemented. +CIRCUITPY_AUDIOBUSIO = 0 # Use PIO interally for I2S +CIRCUITPY_AUDIOMP3 = 0 +CIRCUITPY_COUNTIO = 0 # Use PWM interally +CIRCUITPY_FREQUENCYIO = 0 # Use PWM interally +CIRCUITPY_I2CPERIPHERAL = 0 +CIRCUITPY_NVM = 0 +CIRCUITPY_PULSEIO = 0 # Use PIO interally +CIRCUITPY_ROTARYIO = 0 # Use PIO interally +CIRCUITPY_RTC = 0 + +# Things that are unsupported by the hardware. +CIRCUITPY_AUDIOIO = 0 + +INTERNAL_LIBM = 1 + +USB_SERIAL_NUMBER_LENGTH = 32 + +USB_NUM_EP = 8 diff --git a/ports/raspberrypi/mphalport.c b/ports/raspberrypi/mphalport.c new file mode 100644 index 0000000000..89b597bc74 --- /dev/null +++ b/ports/raspberrypi/mphalport.c @@ -0,0 +1,57 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 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 "lib/mp-readline/readline.h" +#include "lib/utils/interrupt_char.h" +#include "py/mphal.h" +#include "py/mpstate.h" +#include "py/runtime.h" +#include "py/smallint.h" +#include "shared-bindings/microcontroller/__init__.h" +#include "shared-bindings/time/__init__.h" +#include "supervisor/shared/autoreload.h" + +#include "mpconfigboard.h" +#include "mphalport.h" +#include "supervisor/shared/tick.h" + +#include "src/rp2_common/hardware_timer/include/hardware/timer.h" + +extern uint32_t common_hal_mcu_processor_get_frequency(void); + +void mp_hal_delay_us(mp_uint_t delay) { + busy_wait_us_32(delay); +} + +void mp_hal_disable_all_interrupts(void) { + common_hal_mcu_disable_interrupts(); +} + +void mp_hal_enable_all_interrupts(void) { + common_hal_mcu_enable_interrupts(); +} diff --git a/ports/raspberrypi/mphalport.h b/ports/raspberrypi/mphalport.h new file mode 100644 index 0000000000..8d2d7d51a2 --- /dev/null +++ b/ports/raspberrypi/mphalport.h @@ -0,0 +1,50 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 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_RASPBERRYPI_MPHALPORT_H +#define MICROPY_INCLUDED_RASPBERRYPI_MPHALPORT_H + +#include "py/obj.h" + +#include "lib/oofatfs/ff.h" + +#include "supervisor/shared/tick.h" + +// Global millisecond tick count (driven by SysTick interrupt). +#define mp_hal_ticks_ms() ((mp_uint_t) supervisor_ticks_ms32()) + +// Number of bytes in receive buffer +extern volatile uint8_t usb_rx_count; +extern volatile bool mp_cdc_enabled; + +int receive_usb(void); + +void mp_hal_set_interrupt_char(int c); + +void mp_hal_disable_all_interrupts(void); +void mp_hal_enable_all_interrupts(void); + +#endif // MICROPY_INCLUDED_RASPBERRYPI_MPHALPORT_H diff --git a/ports/raspberrypi/peripherals/pins.c b/ports/raspberrypi/peripherals/pins.c new file mode 100644 index 0000000000..a2a7b85bd3 --- /dev/null +++ b/ports/raspberrypi/peripherals/pins.c @@ -0,0 +1,67 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 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 "pins.h" + +#include "shared-bindings/microcontroller/Pin.h" + +// This macro is used to simplify pin definition in boards//pins.c +#define PIN(p_number) \ +const mcu_pin_obj_t pin_GPIO## p_number = { \ + { &mcu_pin_type }, \ + .number = p_number \ +} + +PIN(0); +PIN(1); +PIN(2); +PIN(3); +PIN(4); +PIN(5); +PIN(6); +PIN(7); +PIN(8); +PIN(9); +PIN(10); +PIN(11); +PIN(12); +PIN(13); +PIN(14); +PIN(15); +PIN(16); +PIN(17); +PIN(18); +PIN(19); +PIN(20); +PIN(21); +PIN(22); +PIN(23); +PIN(24); +PIN(25); +PIN(26); +PIN(27); +PIN(28); +PIN(29); diff --git a/ports/raspberrypi/peripherals/pins.h b/ports/raspberrypi/peripherals/pins.h new file mode 100644 index 0000000000..99ab9cfe48 --- /dev/null +++ b/ports/raspberrypi/peripherals/pins.h @@ -0,0 +1,71 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 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. + */ + +// DO NOT include this file directly. Use shared-bindings/microcontroller/Pin.h instead to ensure +// that all necessary includes are already included. + +#ifndef MICROPY_INCLUDED_RASPBERRYPI_PERIPHERALS_PINS_H +#define MICROPY_INCLUDED_RASPBERRYPI_PERIPHERALS_PINS_H + +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; + uint8_t number; +} mcu_pin_obj_t; + +extern const mcu_pin_obj_t pin_GPIO0; +extern const mcu_pin_obj_t pin_GPIO1; +extern const mcu_pin_obj_t pin_GPIO2; +extern const mcu_pin_obj_t pin_GPIO3; +extern const mcu_pin_obj_t pin_GPIO4; +extern const mcu_pin_obj_t pin_GPIO5; +extern const mcu_pin_obj_t pin_GPIO6; +extern const mcu_pin_obj_t pin_GPIO7; +extern const mcu_pin_obj_t pin_GPIO8; +extern const mcu_pin_obj_t pin_GPIO9; +extern const mcu_pin_obj_t pin_GPIO10; +extern const mcu_pin_obj_t pin_GPIO11; +extern const mcu_pin_obj_t pin_GPIO12; +extern const mcu_pin_obj_t pin_GPIO13; +extern const mcu_pin_obj_t pin_GPIO14; +extern const mcu_pin_obj_t pin_GPIO15; +extern const mcu_pin_obj_t pin_GPIO16; +extern const mcu_pin_obj_t pin_GPIO17; +extern const mcu_pin_obj_t pin_GPIO18; +extern const mcu_pin_obj_t pin_GPIO19; +extern const mcu_pin_obj_t pin_GPIO20; +extern const mcu_pin_obj_t pin_GPIO21; +extern const mcu_pin_obj_t pin_GPIO22; +extern const mcu_pin_obj_t pin_GPIO23; +extern const mcu_pin_obj_t pin_GPIO24; +extern const mcu_pin_obj_t pin_GPIO25; +extern const mcu_pin_obj_t pin_GPIO26; +extern const mcu_pin_obj_t pin_GPIO27; +extern const mcu_pin_obj_t pin_GPIO28; +extern const mcu_pin_obj_t pin_GPIO29; + +#endif // MICROPY_INCLUDED_RASPBERRYPI_PERIPHERALS_PINS_H diff --git a/ports/raspberrypi/qstrdefsport.h b/ports/raspberrypi/qstrdefsport.h new file mode 100644 index 0000000000..3ba897069b --- /dev/null +++ b/ports/raspberrypi/qstrdefsport.h @@ -0,0 +1 @@ +// qstrs specific to this port diff --git a/ports/raspberrypi/sdk b/ports/raspberrypi/sdk new file mode 160000 index 0000000000..26653ea81e --- /dev/null +++ b/ports/raspberrypi/sdk @@ -0,0 +1 @@ +Subproject commit 26653ea81e340cacee55025d110c3e014a252a87 diff --git a/ports/raspberrypi/sdk_config/pico/config_autogen.h b/ports/raspberrypi/sdk_config/pico/config_autogen.h new file mode 100644 index 0000000000..688f367c34 --- /dev/null +++ b/ports/raspberrypi/sdk_config/pico/config_autogen.h @@ -0,0 +1,19 @@ +#pragma once + +#define PICO_IE_26_29_UNCHANGED_ON_RESET (0) +#define PICO_USE_STACK_GUARDS (0) +#define PICO_ENTER_USB_BOOT_ON_EXIT (0) +#define PICO_USE_OPTIMISTIC_SBRK (0) +#define PICO_NO_HARDWARE (0) +#define PICO_ON_DEVICE (1) +#define PICO_USE_CRT_PRINTF (0) +#define PICO_NO_PRINTF (0) +#define PICO_FLOAT_SUPPORT_ROM_V1 (1) +#define PICO_DOUBLE_SUPPORT_ROM_V1 (1) +#define PICO_STDIO_UART (0) +#define PICO_STDIO_USB (0) +#define PICO_STDIO_SEMIHOSTING (0) +#define PICO_STDIO_IGNORE_NESTED_STDOUT (0) +#define PICO_PRINTF_PICO (0) +#define PICO_PRINTF_NONE (0) +#define PICO_PRINTF_ALWAYS_INCLUDED (1) diff --git a/ports/raspberrypi/sdk_config/pico/version.h b/ports/raspberrypi/sdk_config/pico/version.h new file mode 100644 index 0000000000..3a1e1a3d27 --- /dev/null +++ b/ports/raspberrypi/sdk_config/pico/version.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +// ---------------------------------------------------------- +// THIS FILE IS (NOT) AUTOGENERATED; EDIT when updating sdk/ +// ---------------------------------------------------------- + +#ifndef _PICO_VERSION_H +#define _PICO_VERSION_H + +#define PICO_SDK_VERSION_MAJOR 1 +#define PICO_SDK_VERSION_MINOR 0 +#define PICO_SDK_VERSION_REVISION 0 +#define PICO_SDK_VERSION_STRING "1.0.0" + +#endif diff --git a/ports/raspberrypi/supervisor/internal_flash.c b/ports/raspberrypi/supervisor/internal_flash.c new file mode 100644 index 0000000000..d333830de9 --- /dev/null +++ b/ports/raspberrypi/supervisor/internal_flash.c @@ -0,0 +1,131 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 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/internal_flash.h" + +#include +#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 "shared-bindings/microcontroller/__init__.h" + +#include "supervisor/usb.h" + +#include "src/rp2040/hardware_structs/include/hardware/structs/sio.h" +#include "src/rp2_common/hardware_flash/include/hardware/flash.h" +#include "src/common/pico_binary_info/include/pico/binary_info.h" + +#define RESERVED_FLASH 1 * 1024 * 1024 + +// TODO: Parameterize flash size based on the configured flash. +#define TOTAL_FLASH_SIZE 2 * 1024 * 1024 + +// TODO: Split the caching out of supervisor/shared/external_flash so we can use it. +#define SECTOR_SIZE 4096 +#define NO_CACHE 0xffffffff +STATIC uint8_t _cache[SECTOR_SIZE]; +STATIC uint32_t _cache_lba = NO_CACHE; + +void supervisor_flash_init(void) { + bi_decl_if_func_used(bi_block_device( + BINARY_INFO_MAKE_TAG('C', 'P'), + "CircuitPython", + RESERVED_FLASH, + TOTAL_FLASH_SIZE - RESERVED_FLASH, + NULL, + BINARY_INFO_BLOCK_DEV_FLAG_READ | + BINARY_INFO_BLOCK_DEV_FLAG_WRITE | + BINARY_INFO_BLOCK_DEV_FLAG_PT_UNKNOWN)); +} + +uint32_t supervisor_flash_get_block_size(void) { + return FILESYSTEM_BLOCK_SIZE; +} + +uint32_t supervisor_flash_get_block_count(void) { + return (TOTAL_FLASH_SIZE - RESERVED_FLASH) / FILESYSTEM_BLOCK_SIZE; +} + +void port_internal_flash_flush(void) { + if (_cache_lba == NO_CACHE) { + return; + } + common_hal_mcu_disable_interrupts(); + flash_range_erase(RESERVED_FLASH + _cache_lba, SECTOR_SIZE); + flash_range_program(RESERVED_FLASH + _cache_lba, _cache, SECTOR_SIZE); + common_hal_mcu_enable_interrupts(); + _cache_lba = NO_CACHE; +} + +mp_uint_t supervisor_flash_read_blocks(uint8_t *dest, uint32_t block, uint32_t num_blocks) { + memcpy(dest, + (void*)(XIP_BASE + RESERVED_FLASH + block * FILESYSTEM_BLOCK_SIZE), + num_blocks * FILESYSTEM_BLOCK_SIZE); + return 0; +} + +mp_uint_t supervisor_flash_write_blocks(const uint8_t *src, uint32_t lba, uint32_t num_blocks) { + uint32_t blocks_per_sector = SECTOR_SIZE / FILESYSTEM_BLOCK_SIZE; + uint32_t block = 0; + while (block < num_blocks) { + uint32_t block_address = lba + block; + uint32_t sector_offset = block_address / blocks_per_sector * SECTOR_SIZE; + uint8_t block_offset = block_address % blocks_per_sector; + + if (_cache_lba != block_address) { + memcpy(_cache, + (void*)(XIP_BASE + RESERVED_FLASH + sector_offset), + SECTOR_SIZE); + _cache_lba = sector_offset; + } + for (uint8_t b = block_offset; b < blocks_per_sector; b++) { + // Stop copying after the last block. + if (block >= num_blocks) { + break; + } + memcpy(_cache + b * FILESYSTEM_BLOCK_SIZE, + src + block * FILESYSTEM_BLOCK_SIZE, + FILESYSTEM_BLOCK_SIZE); + block++; + } + // Make sure we don't have an interrupt while we do flash operations. + common_hal_mcu_disable_interrupts(); + flash_range_erase(RESERVED_FLASH + sector_offset, SECTOR_SIZE); + flash_range_program(RESERVED_FLASH + sector_offset, _cache, SECTOR_SIZE); + common_hal_mcu_enable_interrupts(); + } + + return 0; // success +} + +void supervisor_flash_release_cache(void) { +} diff --git a/ports/raspberrypi/supervisor/internal_flash.h b/ports/raspberrypi/supervisor/internal_flash.h new file mode 100644 index 0000000000..0dc9f15458 --- /dev/null +++ b/ports/raspberrypi/supervisor/internal_flash.h @@ -0,0 +1,38 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 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_RASPBERRYPI_INTERNAL_FLASH_H +#define MICROPY_INCLUDED_RASPBERRYPI_INTERNAL_FLASH_H + +#include + +#include "mpconfigport.h" + +// #define INTERNAL_FLASH_PART1_NUM_BLOCKS (CIRCUITPY_INTERNAL_FLASH_FILESYSTEM_SIZE / FILESYSTEM_BLOCK_SIZE) + +// #define INTERNAL_FLASH_SYSTICK_MASK (0x1ff) // 512ms +// #define INTERNAL_FLASH_IDLE_TICK(tick) (((tick) & INTERNAL_FLASH_SYSTICK_MASK) == 2) + +#endif // MICROPY_INCLUDED_RASPBERRYPI_INTERNAL_FLASH_H diff --git a/ports/raspberrypi/supervisor/internal_flash_root_pointers.h b/ports/raspberrypi/supervisor/internal_flash_root_pointers.h new file mode 100644 index 0000000000..419a4c9435 --- /dev/null +++ b/ports/raspberrypi/supervisor/internal_flash_root_pointers.h @@ -0,0 +1,31 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 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_RASPBERRYPI_INTERNAL_FLASH_ROOT_POINTERS_H +#define MICROPY_INCLUDED_RASPBERRYPI_INTERNAL_FLASH_ROOT_POINTERS_H + +#define FLASH_ROOT_POINTERS + +#endif // MICROPY_INCLUDED_RASPBERRYPI_INTERNAL_FLASH_ROOT_POINTERS_H diff --git a/ports/raspberrypi/supervisor/port.c b/ports/raspberrypi/supervisor/port.c new file mode 100644 index 0000000000..b2f73c7b4c --- /dev/null +++ b/ports/raspberrypi/supervisor/port.c @@ -0,0 +1,200 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 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 "supervisor/board.h" +#include "supervisor/port.h" + +#include "bindings/rp2pio/StateMachine.h" +#include "genhdr/mpversion.h" +#include "shared-bindings/busio/I2C.h" +#include "shared-bindings/busio/SPI.h" +#include "shared-bindings/microcontroller/__init__.h" +#include "shared-bindings/rtc/__init__.h" +#include "shared-bindings/pwmio/PWMOut.h" + +#include "supervisor/shared/safe_mode.h" +#include "supervisor/shared/stack.h" +#include "supervisor/shared/tick.h" + +#include "src/rp2040/hardware_structs/include/hardware/structs/watchdog.h" +#include "src/rp2_common/hardware_gpio/include/hardware/gpio.h" +#include "src/rp2_common/hardware_uart/include/hardware/uart.h" +#include "src/rp2_common/hardware_sync/include/hardware/sync.h" +#include "src/rp2_common/hardware_timer/include/hardware/timer.h" +#include "src/common/pico_time/include/pico/time.h" +#include "src/common/pico_binary_info/include/pico/binary_info.h" + +#include "tusb.h" + + +extern volatile bool mp_msc_enabled; + +STATIC void _tick_callback(uint alarm_num); + +STATIC void _binary_info(void) { + // Binary info readable with `picotool`. + bi_decl(bi_program_name("CircuitPython")); + bi_decl(bi_program_version_string(MICROPY_GIT_TAG)); + bi_decl(bi_program_build_date_string(MICROPY_BUILD_DATE)); + bi_decl(bi_program_url("https://circuitpython.org")); + + bi_decl(bi_program_build_attribute("BOARD=" CIRCUITPY_BOARD_ID)); + // TODO: Add build attribute for debug builds. Needs newer CircuitPython with CIRCUITPY_DEBUG. +} + +safe_mode_t port_init(void) { + _binary_info(); + // Set brown out. + + // Reset everything into a known state before board_init. + reset_port(); + + // For the tick. + hardware_alarm_claim(0); + hardware_alarm_set_callback(0, _tick_callback); + + // Check brownout. + + if (board_requests_safe_mode()) { + return USER_SAFE_MODE; + } + + return NO_SAFE_MODE; +} + +void reset_port(void) { + #if CIRCUITPY_BUSIO + reset_i2c(); + reset_spi(); + #endif + + #if CIRCUITPY_RP2PIO + reset_rp2pio_statemachine(); + #endif + + #if CIRCUITPY_PWMIO + pwmout_reset(); + #endif + + reset_all_pins(); +} + +void reset_to_bootloader(void) { + // reset(); + while (true) {} +} + +void reset_cpu(void) { + // reset(); + while (true) {} +} + +bool port_has_fixed_stack(void) { + return false; +} + +// From the linker script +extern uint32_t __HeapLimit; +extern uint32_t __StackTop; +uint32_t *port_stack_get_limit(void) { + return &__HeapLimit; +} + +uint32_t *port_stack_get_top(void) { + return &__StackTop; +} + +uint32_t *port_heap_get_bottom(void) { + return port_stack_get_limit(); +} + +uint32_t *port_heap_get_top(void) { + return port_stack_get_top(); +} + +void port_set_saved_word(uint32_t value) { + // NOTE: This doesn't survive pressing the reset button (aka toggling RUN). + watchdog_hw->scratch[0] = value; +} + +uint32_t port_get_saved_word(void) { + return watchdog_hw->scratch[0]; +} + +uint64_t port_get_raw_ticks(uint8_t* subticks) { + uint64_t microseconds = time_us_64(); + return 1024 * (microseconds / 1000000) + (microseconds % 1000000) / 977; +} + +STATIC void _tick_callback(uint alarm_num) { + supervisor_tick(); + hardware_alarm_set_target(0, delayed_by_us(get_absolute_time(), 977)); +} + +// Enable 1/1024 second tick. +void port_enable_tick(void) { + hardware_alarm_set_target(0, delayed_by_us(get_absolute_time(), 977)); +} + +// Disable 1/1024 second tick. +void port_disable_tick(void) { + // hardware_alarm_cancel(0); +} + +// This is called by sleep, we ignore it when our ticks are enabled because +// they'll wake us up earlier. If we don't, we'll mess up ticks by overwriting +// the next RTC wake up time. +void port_interrupt_after_ticks(uint32_t ticks) { +} + +void port_idle_until_interrupt(void) { + common_hal_mcu_disable_interrupts(); + if (!tud_task_event_ready()) { +// asm volatile ("dsb 0xF":::"memory"); +// __wfi(); + } + common_hal_mcu_enable_interrupts(); +} + +/** + * \brief Default interrupt handler for unused IRQs. + */ +__attribute__((used)) void HardFault_Handler(void) +{ +#ifdef ENABLE_MICRO_TRACE_BUFFER + // Turn off the micro trace buffer so we don't fill it up in the infinite + // loop below. + REG_MTB_MASTER = 0x00000000 + 6; +#endif + + reset_into_safe_mode(HARD_CRASH); + while (true) { + asm("nop;"); + } +} diff --git a/ports/raspberrypi/supervisor/rp2_cpu.s b/ports/raspberrypi/supervisor/rp2_cpu.s new file mode 100755 index 0000000000..741bb21358 --- /dev/null +++ b/ports/raspberrypi/supervisor/rp2_cpu.s @@ -0,0 +1,35 @@ +.syntax unified +.cpu cortex-m0 +.thumb +.text +.align 2 + +@ uint cpu_get_regs_and_sp(r0=uint regs[10]) +.global cpu_get_regs_and_sp +.thumb +.thumb_func +.type cpu_get_regs_and_sp, %function +cpu_get_regs_and_sp: +@ store registers into given array +str r4, [r0, #0] +str r5, [r0, #4] +str r6, [r0, #8] +str r7, [r0, #12] +push {r1} +mov r1, r8 +str r1, [r0, #16] +mov r1, r9 +str r1, [r0, #20] +mov r1, r10 +str r1, [r0, #24] +mov r1, r11 +str r1, [r0, #28] +mov r1, r12 +str r1, [r0, #32] +mov r1, r13 +str r1, [r0, #36] +pop {r1} + +@ return the sp +mov r0, sp +bx lr diff --git a/ports/raspberrypi/supervisor/usb.c b/ports/raspberrypi/supervisor/usb.c new file mode 100644 index 0000000000..db2c298f5d --- /dev/null +++ b/ports/raspberrypi/supervisor/usb.c @@ -0,0 +1,38 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 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 "lib/tinyusb/src/device/usbd.h" +#include "supervisor/background_callback.h" +#include "supervisor/usb.h" +#include "src/rp2_common/pico_platform/include/pico/platform.h" +#include "src/rp2040/hardware_regs/include/hardware/regs/intctrl.h" + +void init_usb_hardware(void) { +} + +void __isr __used isr_usbctrl(void) { + usb_irq_handler(); +} diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index 21bd5b9658..3ce7c01173 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -51,6 +51,7 @@ BASE_CFLAGS = \ -DCIRCUITPY_SOFTWARE_SAFE_MODE=0x0ADABEEF \ -DCIRCUITPY_CANARY_WORD=0xADAF00 \ -DCIRCUITPY_SAFE_RESTART_WORD=0xDEADBEEF \ + -DCIRCUITPY_BOARD_ID="\"$(BOARD)\"" \ --param max-inline-insns-single=500 # Use these flags to debug build times and header includes. @@ -234,6 +235,9 @@ endif ifeq ($(CIRCUITPY_RANDOM),1) SRC_PATTERNS += random/% endif +ifeq ($(CIRCUITPY_RP2PIO),1) +SRC_PATTERNS += rp2pio/% +endif ifeq ($(CIRCUITPY_ROTARYIO),1) SRC_PATTERNS += rotaryio/% endif diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index a3411b7adb..b0bca0f250 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -228,7 +228,7 @@ typedef long mp_off_t; #endif #ifndef MICROPY_PY_REVERSE_SPECIAL_METHODS -#define MICROPY_PY_REVERSE_SPECIAL_METHODS (CIRCUITPY_FULL_BUILD) +#define MICROPY_PY_REVERSE_SPECIAL_METHODS (CIRCUITPY_ULAB || CIRCUITPY_FULL_BUILD) #endif #if INTERNAL_FLASH_FILESYSTEM == 0 && QSPI_FLASH_FILESYSTEM == 0 && SPI_FLASH_FILESYSTEM == 0 && !DISABLE_FILESYSTEM @@ -581,13 +581,6 @@ extern const struct _mp_obj_module_t pwmio_module; #define PWMIO_MODULE #endif -#if CIRCUITPY_RGBMATRIX -extern const struct _mp_obj_module_t rgbmatrix_module; -#define RGBMATRIX_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_rgbmatrix),(mp_obj_t)&rgbmatrix_module }, -#else -#define RGBMATRIX_MODULE -#endif - #if CIRCUITPY_RANDOM extern const struct _mp_obj_module_t random_module; #define RANDOM_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_random), (mp_obj_t)&random_module }, @@ -595,6 +588,20 @@ extern const struct _mp_obj_module_t random_module; #define RANDOM_MODULE #endif +#if CIRCUITPY_RP2PIO +extern const struct _mp_obj_module_t rp2pio_module; +#define RP2PIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_rp2pio),(mp_obj_t)&rp2pio_module }, +#else +#define RP2PIO_MODULE +#endif + +#if CIRCUITPY_RGBMATRIX +extern const struct _mp_obj_module_t rgbmatrix_module; +#define RGBMATRIX_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_rgbmatrix),(mp_obj_t)&rgbmatrix_module }, +#else +#define RGBMATRIX_MODULE +#endif + #if CIRCUITPY_ROTARYIO extern const struct _mp_obj_module_t rotaryio_module; #define ROTARYIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_rotaryio), (mp_obj_t)&rotaryio_module }, @@ -849,6 +856,7 @@ extern const struct _mp_obj_module_t msgpack_module; PULSEIO_MODULE \ PWMIO_MODULE \ RANDOM_MODULE \ + RP2PIO_MODULE \ RE_MODULE \ RGBMATRIX_MODULE \ ROTARYIO_MODULE \ @@ -928,12 +936,15 @@ void supervisor_run_background_tasks_if_tick(void); #define CIRCUITPY_PYSTACK_SIZE 1536 #endif - // Wait this long imediately after startup to see if we are connected to USB. #ifndef CIRCUITPY_USB_CONNECTED_SLEEP_DELAY #define CIRCUITPY_USB_CONNECTED_SLEEP_DELAY 5 #endif +#ifndef CIRCUITPY_PROCESSOR_COUNT +#define CIRCUITPY_PROCESSOR_COUNT (1) +#endif + #define CIRCUITPY_BOOT_OUTPUT_FILE "/boot_out.txt" #define CIRCUITPY_VERBOSE_BLE 0 diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk index d0145a90f3..9c9b17f4b7 100644 --- a/py/circuitpy_mpconfig.mk +++ b/py/circuitpy_mpconfig.mk @@ -198,12 +198,18 @@ CFLAGS += -DCIRCUITPY_PULSEIO=$(CIRCUITPY_PULSEIO) # For now we tie PWMIO to PULSEIO so they always both exist. In CircuitPython 7 # we can enable and disable them separately once PWMOut is removed from `pulseio`. -CIRCUITPY_PWMIO = $(CIRCUITPY_PULSEIO) +CIRCUITPY_PWMIO ?= $(CIRCUITPY_PULSEIO) CFLAGS += -DCIRCUITPY_PWMIO=$(CIRCUITPY_PWMIO) CIRCUITPY_RANDOM ?= 1 CFLAGS += -DCIRCUITPY_RANDOM=$(CIRCUITPY_RANDOM) +# CIRCUITPY_RP2PIO is handled in the raspberrypi tree. +# Only for rp2 chips. +# Assume not a rp2 build. +CIRCUITPY_RP2PIO ?= 0 +CFLAGS += -DCIRCUITPY_RP2PIO=$(CIRCUITPY_RP2PIO) + CIRCUITPY_RGBMATRIX ?= 0 CFLAGS += -DCIRCUITPY_RGBMATRIX=$(CIRCUITPY_RGBMATRIX) diff --git a/shared-bindings/microcontroller/__init__.h b/shared-bindings/microcontroller/__init__.h index 0dafc74c72..39d3e718b4 100644 --- a/shared-bindings/microcontroller/__init__.h +++ b/shared-bindings/microcontroller/__init__.h @@ -29,6 +29,7 @@ #include "py/obj.h" #include "py/mpconfig.h" +#include "py/objtuple.h" #include "common-hal/microcontroller/Processor.h" #include "shared-bindings/microcontroller/ResetReason.h" @@ -44,7 +45,13 @@ extern void common_hal_mcu_reset(void); extern const mp_obj_dict_t mcu_pin_globals; +#if CIRCUITPY_PROCESSOR_COUNT == 1 extern const mcu_processor_obj_t common_hal_mcu_processor_obj; +#elif CIRCUITPY_PROCESSOR_COUNT > 1 +extern const mp_rom_obj_tuple_t common_hal_mcu_processor_obj; +#else +#error "Invalid processor count" +#endif #if CIRCUITPY_INTERNAL_NVM_SIZE > 0 diff --git a/shared-module/sdcardio/SDCard.c b/shared-module/sdcardio/SDCard.c index 9e861279d3..1712f58ee4 100644 --- a/shared-module/sdcardio/SDCard.c +++ b/shared-module/sdcardio/SDCard.c @@ -375,7 +375,7 @@ int common_hal_sdcardio_sdcard_readblocks(sdcardio_sdcard_obj_t *self, uint32_t return r; } -int _write(sdcardio_sdcard_obj_t *self, uint8_t token, void *buf, size_t size) { +STATIC int _write(sdcardio_sdcard_obj_t *self, uint8_t token, void *buf, size_t size) { wait_for_ready(self); uint8_t cmd[2]; @@ -420,7 +420,7 @@ int _write(sdcardio_sdcard_obj_t *self, uint8_t token, void *buf, size_t size) { return 0; } -int writeblocks(sdcardio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *buf) { +STATIC int writeblocks(sdcardio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *buf) { common_hal_sdcardio_check_for_deinit(self); uint32_t nblocks = buf->len / 512; if (nblocks == 1) { diff --git a/supervisor/shared/filesystem.c b/supervisor/shared/filesystem.c index 618dc796b8..09b30b6bad 100644 --- a/supervisor/shared/filesystem.c +++ b/supervisor/shared/filesystem.c @@ -79,6 +79,8 @@ static void make_sample_code_file(FATFS *fatfs) { f_open(fatfs, &fs, "/code.py", FA_WRITE | FA_CREATE_ALWAYS); f_write(&fs, buffer, sizeof(buffer) - 1, &char_written); f_close(&fs); + #else + make_empty_file(fatfs, "/code.py"); #endif } diff --git a/supervisor/shared/safe_mode.c b/supervisor/shared/safe_mode.c index 9032e40451..f8e871f975 100644 --- a/supervisor/shared/safe_mode.c +++ b/supervisor/shared/safe_mode.c @@ -28,7 +28,9 @@ #include "mphalport.h" +#if defined(MICROPY_HW_LED_STATUS) #include "shared-bindings/digitalio/DigitalInOut.h" +#endif #include "shared-bindings/microcontroller/Processor.h" #include "shared-bindings/microcontroller/ResetReason.h" diff --git a/supervisor/shared/workflow.c b/supervisor/shared/workflow.c index 4986c09570..9aac7c4d05 100644 --- a/supervisor/shared/workflow.c +++ b/supervisor/shared/workflow.c @@ -36,7 +36,9 @@ void supervisor_workflow_reset(void) { // Not that some chips don't notice when USB is unplugged after first being plugged in, // so this is not perfect, but tud_suspended() check helps. bool supervisor_workflow_connecting(void) { - return tud_connected() && !tud_suspended(); + return true; + // TODO: Use the below once we've updated TinyUSB for the RP2040. + // return tud_connected() && !tud_suspended(); } // Return true if host has completed connection to us (such as USB enumeration). diff --git a/tools/build_board_info.py b/tools/build_board_info.py index ce9d45fe2f..7b556ee5d2 100644 --- a/tools/build_board_info.py +++ b/tools/build_board_info.py @@ -26,6 +26,7 @@ SUPPORTED_PORTS = [ "litex", "mimxrt10xx", "nrf", + "raspberrypi", "stm", ] @@ -47,6 +48,7 @@ extension_by_port = { "mimxrt10xx": HEX_UF2, "litex": DFU, "esp32s2": BIN_UF2, + "raspberrypi": UF2, } # Per board overrides diff --git a/tools/build_memory_info.py b/tools/build_memory_info.py index 26697b9740..89aedf0f40 100644 --- a/tools/build_memory_info.py +++ b/tools/build_memory_info.py @@ -9,10 +9,10 @@ import re import sys # Handle size constants with K or M suffixes (allowed in .ld but not in Python). -K_PATTERN = re.compile(r'([0-9]+)K') +K_PATTERN = re.compile(r'([0-9]+)[kK]') K_REPLACE = r'(\1*1024)' -M_PATTERN = re.compile(r'([0-9]+)M') +M_PATTERN = re.compile(r'([0-9]+)[mM]') M_REPLACE = r'(\1*1024*1024)' print()