diff --git a/.github/workflows/code_size.yml b/.github/workflows/code_size.yml index de75bfe08f..5d955703b6 100644 --- a/.github/workflows/code_size.yml +++ b/.github/workflows/code_size.yml @@ -28,7 +28,7 @@ jobs: - name: Build run: source tools/ci.sh && ci_code_size_build - name: Compute code size difference - run: tools/metrics.py diff ~/size0 ~/size1 | tee > diff + run: tools/metrics.py diff ~/size0 ~/size1 | tee diff - name: Save PR number if: github.event_name == 'pull_request' env: diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml index e4105e8d43..450805a6bd 100644 --- a/.github/workflows/examples.yml +++ b/.github/workflows/examples.yml @@ -20,6 +20,6 @@ jobs: steps: - uses: actions/checkout@v3 - name: Build - run: make -C examples/embedding + run: make -C examples/embedding -f micropython_embed.mk && make -C examples/embedding - name: Run - run: test "$(./examples/embedding/hello-embed)" = "Hello world of easy embedding!" + run: ./examples/embedding/embed | grep "hello world" diff --git a/CODECONVENTIONS.md b/CODECONVENTIONS.md index 53b202ea37..0bd7a7327a 100644 --- a/CODECONVENTIONS.md +++ b/CODECONVENTIONS.md @@ -65,16 +65,52 @@ changes to the correct style. Without arguments this tool will reformat all source code (and may take some time to run). Otherwise pass as arguments to the tool the files that changed and it will only reformat those. -**Important**: Use only [uncrustify](https://github.com/uncrustify/uncrustify) -v0.71 or v0.72 for MicroPython. Different uncrustify versions produce slightly -different formatting, and the configuration file formats are often incompatible. +uncrustify +========== + +Only [uncrustify](https://github.com/uncrustify/uncrustify) v0.71 or v0.72 can +be used for MicroPython. Different uncrustify versions produce slightly +different formatting, and the configuration file formats are often +incompatible. v0.73 or newer *will not work*. + +Depending on your operating system version, it may be possible to install a pre-compiled +uncrustify version: + +Ubuntu, Debian +-------------- + +Ubuntu versions 21.10 or 22.04LTS, and Debian versions bullseye or bookworm all +include v0.72 so can be installed directly: + +``` +$ apt install uncrustify +``` + +Arch Linux +---------- + +The current Arch uncrustify version is too new. There is an [old Arch package +for v0.72](https://archive.archlinux.org/packages/u/uncrustify/) that can be +installed from the Arch Linux archive ([more +information](https://wiki.archlinux.org/title/Downgrading_packages#Arch_Linux_Archive)). Use +the [IgnorePkg feature](https://wiki.archlinux.org/title/Pacman#Skip_package_from_being_upgraded) +to prevent it re-updating. + +Brew +---- + +This command may work, please raise a new Issue if it doesn't: + +``` +brew install https://github.com/Homebrew/homebrew-core/raw/2b07d8192623365078a8b855a164ebcdf81494a6/Formula/uncrustify.rb +``` Automatic Pre-Commit Hooks ========================== To have code formatting and commit message conventions automatically checked, -a configuration file is provided for the [pre-commit] -(https://pre-commit.com/) tool. +a configuration file is provided for the [pre-commit](https://pre-commit.com/) +tool. First install `pre-commit`, either from your system package manager or via `pip`. When installing `pre-commit` via pip, it is recommended to use a @@ -82,13 +118,17 @@ virtual environment. Other sources, such as Brew are also available, see [the docs](https://pre-commit.com/index.html#install) for details. ``` -$ apt install pre-commit # Ubuntu +$ apt install pre-commit # Ubuntu, Debian $ pacman -Sy python-precommit # Arch Linux $ brew install pre-commit # Brew $ pip install pre-commit # PyPI ``` -Then inside the MicroPython repository, register the git hooks for pre-commit +Next, install [uncrustify (see above)](#uncrustify). Other dependencies are managed by +pre-commit automatically, but uncrustify needs to be installed and available on +the PATH. + +Then, inside the MicroPython repository, register the git hooks for pre-commit by running: ``` @@ -115,7 +155,6 @@ Tips: * To ignore the pre-commit message format check temporarily, start the commit message subject line with "WIP" (for "Work In Progress"). - Python code conventions ======================= diff --git a/docs/esp32/quickref.rst b/docs/esp32/quickref.rst index 03ca97c7a7..f74926c374 100644 --- a/docs/esp32/quickref.rst +++ b/docs/esp32/quickref.rst @@ -68,6 +68,9 @@ by reading the temperature sensor immediately after waking up from sleep. Networking ---------- +WLAN +^^^^ + The :mod:`network` module:: import network @@ -110,6 +113,67 @@ calling ``wlan.config(reconnects=n)``, where n are the number of desired reconne attempts (0 means it won't retry, -1 will restore the default behaviour of trying to reconnect forever). +LAN +^^^ + +To use the wired interfaces one has to specify the pins and mode :: + + import network + + lan = network.LAN(mdc=PIN_MDC, ...) # Set the pin and mode configuration + lan.active(True) # activate the interface + lan.ifconfig() # get the interface's IP/netmask/gw/DNS addresses + + +The keyword arguments for the constructor defining the PHY type and interface are: + +- mdc=pin-object # set the mdc and mdio pins. +- mdio=pin-object +- power=pin-object # set the pin which switches the power of the PHY device. +- phy_type= # Select the PHY device type. Supported devices are PHY_LAN8710, + PHY_LAN8720, PH_IP101, PHY_RTL8201, PHY_DP83848 and PHY_KSZ8041 +- phy_addr=number # The address number of the PHY device. +- ref_clk_mode=mode # Defines, whether the ref_clk at the ESP32 is an input + or output. Suitable values are Pin.IN and Pin.OUT. +- ref_clk=pin-object # defines the Pin used for ref_clk. + +The options ref_clk_mode and ref_clk require at least esp-idf version 4.4. For +earlier esp-idf versions, these parameters must be defined by kconfig board options. + +These are working configurations for LAN interfaces of popular boards:: + + # Olimex ESP32-GATEWAY: power controlled by Pin(5) + # Olimex ESP32 PoE and ESP32-PoE ISO: power controlled by Pin(12) + + lan = network.LAN(mdc=machine.Pin(23), mdio=machine.Pin(18), power=machine.Pin(5), + phy_type=network.PHY_LAN8720, phy_addr=0) + + # or with dynamic ref_clk pin configuration + + lan = network.LAN(mdc=machine.Pin(23), mdio=machine.Pin(18), power=machine.Pin(5), + phy_type=network.PHY_LAN8720, phy_addr=0, + ref_clk=machine.Pin(17), ref_clk_mode=machine.Pin.OUT) + + # Wireless-Tag's WT32-ETH01 + + lan = network.LAN(mdc=machine.Pin(23), mdio=machine.Pin(18), + phy_type=network.PHY_LAN8720, phy_addr=1, power=None) + + # Espressif ESP32-Ethernet-Kit_A_V1.2 + + lan = network.LAN(id=0, mdc=Pin(23), mdio=Pin(18), power=Pin(5), + phy_type=network.PHY_IP101, phy_addr=1) + +A suitable definition of the PHY interface in a sdkconfig.board file is:: + + CONFIG_ETH_PHY_INTERFACE_RMII=y + CONFIG_ETH_RMII_CLK_OUTPUT=y + CONFIG_ETH_RMII_CLK_OUT_GPIO=17 + CONFIG_LWIP_LOCAL_HOSTNAME="ESP32_POE" + +The value assigned to CONFIG_ETH_RMII_CLK_OUT_GPIO may vary depending on the +board's wiring. + Delay and timing ---------------- diff --git a/docs/library/machine.Timer.rst b/docs/library/machine.Timer.rst index 424a49bcba..48c023a11c 100644 --- a/docs/library/machine.Timer.rst +++ b/docs/library/machine.Timer.rst @@ -38,13 +38,16 @@ Constructors Methods ------- -.. method:: Timer.init(*, mode=Timer.PERIODIC, period=-1, callback=None) +.. method:: Timer.init(*, mode=Timer.PERIODIC, freq=-1, period=-1, callback=None) Initialise the timer. Example:: def mycallback(t): pass + # periodic at 1kHz + tim.init(mode=Timer.PERIODIC, freq=1000, callback=mycallback) + # periodic with 100ms period tim.init(period=100, callback=mycallback) @@ -60,6 +63,11 @@ Methods - ``Timer.PERIODIC`` - The timer runs periodically at the configured frequency of the channel. + - ``freq`` - The timer frequency, in units of Hz. The upper bound of + the frequency is dependent on the port. When both the ``freq`` and + ``period`` arguments are given, ``freq`` has a higher priority and + ``period`` is ignored. + - ``period`` - The timer period, in milliseconds. - ``callback`` - The callable to call upon expiration of the timer period. diff --git a/docs/library/rp2.StateMachine.rst b/docs/library/rp2.StateMachine.rst index 7e38ba8b1a..d39194e6ff 100644 --- a/docs/library/rp2.StateMachine.rst +++ b/docs/library/rp2.StateMachine.rst @@ -99,13 +99,17 @@ Methods .. method:: StateMachine.put(value, shift=0) - Push a word onto the state machine's TX FIFO. + Push words onto the state machine's TX FIFO. - If the FIFO is full, it blocks until there is space (i.e. the state machine - pulls a word). + *value* can be an integer, an array of type ``B``, ``H`` or ``I``, or a + `bytearray`. - The value is first shifted left by *shift* bits, i.e. the state machine - receives ``value << shift``. + This method will block until all words have been written to the FIFO. If + the FIFO is, or becomes, full, the method will block until the state machine + pulls enough words to complete the write. + + Each word is first shifted left by *shift* bits, i.e. the state machine + receives ``word << shift``. .. method:: StateMachine.rx_fifo() diff --git a/docs/library/socket.rst b/docs/library/socket.rst index 1d1c23abd1..944e7e631a 100644 --- a/docs/library/socket.rst +++ b/docs/library/socket.rst @@ -29,7 +29,7 @@ returned by `getaddrinfo` function, which must be used to resolve textual addres # You must use getaddrinfo() even for numeric addresses sockaddr = socket.getaddrinfo('127.0.0.1', 80)[0][-1] # Now you can use that address - sock.connect(addr) + sock.connect(sockaddr) Using `getaddrinfo` is the most efficient (both in terms of memory and processing power) and portable way to work with addresses. diff --git a/docs/reference/constrained.rst b/docs/reference/constrained.rst index 8b64fd98fc..2bcf9f7fb7 100644 --- a/docs/reference/constrained.rst +++ b/docs/reference/constrained.rst @@ -392,6 +392,8 @@ Symbol Meaning F float B byte code M module + S string or bytes + A bytearray ====== ================= Each letter represents a single block of memory, a block being 16 bytes. So each diff --git a/docs/rp2/tutorial/pio.rst b/docs/rp2/tutorial/pio.rst index 9981aed832..4e519650ee 100644 --- a/docs/rp2/tutorial/pio.rst +++ b/docs/rp2/tutorial/pio.rst @@ -76,9 +76,10 @@ and state machines. Below is the code for reference. nop() [29] jmp(x_dec, "delay_high") - # Cycles: 1 + 7 + 32 * (30 + 1) = 1000 + # Cycles: 1 + 1 + 6 + 32 * (30 + 1) = 1000 + nop() set(pins, 0) - set(x, 31) [6] + set(x, 31) [5] label("delay_low") nop() [29] jmp(x_dec, "delay_low") @@ -113,6 +114,8 @@ the following: X starts with the value 31 this jump will happen 31 times, so the ``nop() [29]`` runs 32 times in total (note there is also one instruction cycle taken by the ``jmp`` for each of these 32 loops). +- The single ``nop()`` correlates with the cycle used for IRQ raise, and ensures + the same number of cycles are used for LED on and LED off. - ``set(pins, 0)`` will turn the LED off by setting pin 25 low. - Another 32 loops of ``nop() [29]`` and ``jmp(...)`` will execute. - Because ``wrap_target()`` and ``wrap()`` are not specified, their default will diff --git a/docs/zephyr/quickref.rst b/docs/zephyr/quickref.rst index 783621316c..329a9c41c0 100644 --- a/docs/zephyr/quickref.rst +++ b/docs/zephyr/quickref.rst @@ -151,7 +151,7 @@ Use the :ref:`zsensor.Sensor ` class to access sensor data:: accel.measure() # obtain a measurement reading from the accelerometer # each of these prints the value taken by measure() - accel.float(zsensor.ACCEL_X) # print measurement value for accelerometer X-axis sensor channel as float - accel.millis(zsensor.ACCEL_Y) # print measurement value for accelerometer Y-axis sensor channel in millionths - accel.micro(zsensor.ACCEL_Z) # print measurement value for accelerometer Z-axis sensor channel in thousandths - accel.int(zsensor.ACCEL_X) # print measurement integer value only for accelerometer X-axis sensor channel + accel.get_float(zsensor.ACCEL_X) # print measurement value for accelerometer X-axis sensor channel as float + accel.get_millis(zsensor.ACCEL_Y) # print measurement value for accelerometer Y-axis sensor channel in millionths + accel.get_micro(zsensor.ACCEL_Z) # print measurement value for accelerometer Z-axis sensor channel in thousandths + accel.get_int(zsensor.ACCEL_X) # print measurement integer value only for accelerometer X-axis sensor channel diff --git a/drivers/ninaw10/machine_pin_nina.c b/drivers/ninaw10/machine_pin_nina.c new file mode 100644 index 0000000000..23c547b81f --- /dev/null +++ b/drivers/ninaw10/machine_pin_nina.c @@ -0,0 +1,92 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2022 Ibrahim Abdelkader + * + * 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" + +#if defined(MICROPY_PY_NETWORK_NINAW10) && defined(MICROPY_HW_PIN_EXT_COUNT) + +#include "modmachine.h" +#include "machine_pin.h" +#include "nina_wifi_drv.h" + +#define NINA_GPIO_INPUT (0x00) +#define NINA_GPIO_OUTPUT (0x01) +#define NINA_GPIO_INPUT_PULLUP (0x02) + +#define NINA_GPIO_MODE (0x50) +#define NINA_GPIO_READ (0x53) +#define NINA_GPIO_WRITE (0x51) + +static uint8_t pin_map[MICROPY_HW_PIN_EXT_COUNT] = { + 27, // LEDR + 25, // LEDG + 26, // LEDB + 36, // A6 + 35, // A7 +}; + +void machine_pin_ext_init(void) { + nina_init(); +} + +void machine_pin_ext_set(machine_pin_obj_t *self, bool value) { + if (self->id >= 0 && self->id < MICROPY_HW_PIN_EXT_COUNT) { + uint8_t buf[] = {pin_map[self->id], value}; + nina_ioctl(NINA_GPIO_WRITE, sizeof(buf), buf, 0); + } +} + +bool machine_pin_ext_get(machine_pin_obj_t *self) { + bool value = false; + if (self->id >= 0 && self->id < MICROPY_HW_PIN_EXT_COUNT) { + uint8_t buf[] = {pin_map[self->id]}; + nina_ioctl(NINA_GPIO_READ, sizeof(buf), buf, 0); + } + return value; +} + +void machine_pin_ext_config(machine_pin_obj_t *self, int mode, int value) { + if (mode == MACHINE_PIN_MODE_IN) { + mode = NINA_GPIO_INPUT; + self->is_output = false; + } else if (mode == MACHINE_PIN_MODE_OUT) { + mode = NINA_GPIO_OUTPUT; + self->is_output = true; + machine_pin_ext_set(self, value); + } else { + mp_raise_ValueError("only Pin.OUT and Pin.IN are supported for this pin"); + } + if (self->id >= 0 && self->id < MICROPY_HW_PIN_EXT_COUNT) { + uint8_t buf[] = {pin_map[self->id], mode}; + nina_ioctl(NINA_GPIO_MODE, sizeof(buf), buf, 0); + } +} + +#endif // defined(MICROPY_PY_NETWORK_NINAW10) && defined(MICROPY_HW_PIN_EXT_COUNT) diff --git a/examples/embedding/Makefile b/examples/embedding/Makefile index edaa577f57..13bfdf1239 100644 --- a/examples/embedding/Makefile +++ b/examples/embedding/Makefile @@ -1,8 +1,25 @@ -MPTOP = ../.. -CFLAGS += -std=c99 -I. -I$(MPTOP) -DNO_QSTR -LDFLAGS += -L./build +# This file is part of the MicroPython project, http://micropython.org/ +# The MIT License (MIT) +# Copyright (c) 2022-2023 Damien P. George +# +# This is a very simple makefile that demonstrates how to build the embed port. +# All it needs to do is build all *.c files in the micropython_embed directory. +# This makefile would be replaced with your custom build system. -hello-embed: hello-embed.o -lmicropython +EMBED_DIR = micropython_embed +PROG = embed --lmicropython: - $(MAKE) -f $(MPTOP)/examples/embedding/Makefile.upylib MPTOP=$(MPTOP) +CFLAGS += -I. +CFLAGS += -I$(EMBED_DIR) +CFLAGS += -I$(EMBED_DIR)/port +CFLAGS += -Wall -Og + +SRC += main.c +SRC += $(wildcard $(EMBED_DIR)/*/*.c) $(wildcard $(EMBED_DIR)/*/*/*.c) +OBJ += $(SRC:.c=.o) + +$(PROG): $(OBJ) + $(CC) -o $@ $^ + +clean: + /bin/rm -f $(OBJ) $(PROG) diff --git a/examples/embedding/Makefile.upylib b/examples/embedding/Makefile.upylib deleted file mode 100644 index 99ce94b7ad..0000000000 --- a/examples/embedding/Makefile.upylib +++ /dev/null @@ -1,184 +0,0 @@ -MPTOP = ../.. --include mpconfigport.mk -include $(MPTOP)/py/mkenv.mk - -all: lib - -# OS name, for simple autoconfig -UNAME_S := $(shell uname -s) - -# include py core make definitions -include $(MPTOP)/py/py.mk -include $(MPTOP)/extmod/extmod.mk - -INC += -I. -INC += -I.. -INC += -I$(MPTOP) -INC += -I$(MPTOP)/ports/unix -INC += -I$(BUILD) - -# compiler settings -CWARN = -Wall -Werror -CWARN += -Wpointer-arith -Wuninitialized -CFLAGS += $(INC) $(CWARN) -std=gnu99 -DUNIX $(CFLAGS_MOD) $(COPT) $(CFLAGS_EXTRA) - -# Some systems (eg MacOS) need -fno-common so that mp_state_ctx is placed in the BSS. -CFLAGS += -fno-common - -# Debugging/Optimization -ifdef DEBUG -CFLAGS += -g -COPT = -O0 -else -COPT = -Os #-DNDEBUG -# _FORTIFY_SOURCE is a feature in gcc/glibc which is intended to provide extra -# security for detecting buffer overflows. Some distros (Ubuntu at the very least) -# have it enabled by default. -# -# gcc already optimizes some printf calls to call puts and/or putchar. When -# _FORTIFY_SOURCE is enabled and compiling with -O1 or greater, then some -# printf calls will also be optimized to call __printf_chk (in glibc). Any -# printfs which get redirected to __printf_chk are then no longer synchronized -# with printfs that go through mp_printf. -# -# In MicroPython, we don't want to use the runtime library's printf but rather -# go through mp_printf, so that stdout is properly tied into streams, etc. -# This means that we either need to turn off _FORTIFY_SOURCE or provide our -# own implementation of __printf_chk. We've chosen to turn off _FORTIFY_SOURCE. -# It should also be noted that the use of printf in MicroPython is typically -# quite limited anyways (primarily for debug and some error reporting, etc -# in the unix version). -# -# Information about _FORTIFY_SOURCE seems to be rather scarce. The best I could -# find was this: https://securityblog.redhat.com/2014/03/26/fortify-and-you/ -# Original patchset was introduced by -# https://gcc.gnu.org/ml/gcc-patches/2004-09/msg02055.html . -# -# Turning off _FORTIFY_SOURCE is only required when compiling with -O1 or greater -CFLAGS += -U _FORTIFY_SOURCE -endif - -# On OSX, 'gcc' is a symlink to clang unless a real gcc is installed. -# The unix port of MicroPython on OSX must be compiled with clang, -# while cross-compile ports require gcc, so we test here for OSX and -# if necessary override the value of 'CC' set in py/mkenv.mk -ifeq ($(UNAME_S),Darwin) -CC = clang -# Use clang syntax for map file -LDFLAGS_ARCH = -Wl,-map,$@.map -else -# Use gcc syntax for map file -LDFLAGS_ARCH = -Wl,-Map=$@.map,--cref -endif -LDFLAGS += $(LDFLAGS_MOD) $(LDFLAGS_ARCH) -lm $(LDFLAGS_EXTRA) - -ifeq ($(MICROPY_FORCE_32BIT),1) -# Note: you may need to install i386 versions of dependency packages, -# starting with linux-libc-dev:i386 -ifeq ($(MICROPY_PY_FFI),1) -ifeq ($(UNAME_S),Linux) -CFLAGS_MOD += -I/usr/include/i686-linux-gnu -endif -endif -endif - -ifeq ($(MICROPY_USE_READLINE),1) -INC += -I$(MPTOP)/shared/readline -CFLAGS_MOD += -DMICROPY_USE_READLINE=1 -SHARED_SRC_C_EXTRA += readline/readline.c -endif -ifeq ($(MICROPY_USE_READLINE),2) -CFLAGS_MOD += -DMICROPY_USE_READLINE=2 -LDFLAGS_MOD += -lreadline -# the following is needed for BSD -#LDFLAGS_MOD += -ltermcap -endif -ifeq ($(MICROPY_PY_TIME),1) -CFLAGS_MOD += -DMICROPY_PY_TIME=1 -SRC_MOD += modtime.c -endif -ifeq ($(MICROPY_PY_TERMIOS),1) -CFLAGS_MOD += -DMICROPY_PY_TERMIOS=1 -SRC_MOD += modtermios.c -endif -ifeq ($(MICROPY_PY_SOCKET),1) -CFLAGS_MOD += -DMICROPY_PY_SOCKET=1 -SRC_MOD += modsocket.c -endif - -ifeq ($(MICROPY_PY_FFI),1) - -ifeq ($(MICROPY_STANDALONE),1) -LIBFFI_CFLAGS_MOD := -I$(shell ls -1d $(MPTOP)/lib/libffi/build_dir/out/lib/libffi-*/include) - ifeq ($(MICROPY_FORCE_32BIT),1) - LIBFFI_LDFLAGS_MOD = $(MPTOP)/lib/libffi/build_dir/out/lib32/libffi.a - else - LIBFFI_LDFLAGS_MOD = $(MPTOP)/lib/libffi/build_dir/out/lib/libffi.a - endif -else -LIBFFI_CFLAGS_MOD := $(shell pkg-config --cflags libffi) -LIBFFI_LDFLAGS_MOD := $(shell pkg-config --libs libffi) -endif - -ifeq ($(UNAME_S),Linux) -LIBFFI_LDFLAGS_MOD += -ldl -endif - -CFLAGS_MOD += $(LIBFFI_CFLAGS_MOD) -DMICROPY_PY_FFI=1 -LDFLAGS_MOD += $(LIBFFI_LDFLAGS_MOD) -SRC_MOD += modffi.c -endif - -MAIN_C = main.c - -# source files -SRC_C = $(addprefix ports/unix/,\ - $(MAIN_C) \ - gccollect.c \ - unix_mphal.c \ - input.c \ - modmachine.c \ - moduselect.c \ - alloc.c \ - coverage.c \ - fatfs_port.c \ - $(SRC_MOD) \ - ) - -SHARED_SRC_C = $(addprefix shared/,\ - libc/printf.c \ - runtime/gchelper_generic.c \ - timeutils/timeutils.c \ - $(SHARED_SRC_C_EXTRA) \ - ) - -OBJ = $(PY_O) -OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) -OBJ += $(addprefix $(BUILD)/, $(SHARED_SRC_C:.c=.o)) - -# List of sources for qstr extraction -SRC_QSTR += $(SRC_C) $(SHARED_SRC_C) -# Append any auto-generated sources that are needed by sources listed in -# SRC_QSTR -SRC_QSTR_AUTO_DEPS += - -include $(MPTOP)/py/mkrules.mk - -# Value of configure's --host= option (required for cross-compilation). -# Deduce it from CROSS_COMPILE by default, but can be overridden. -ifneq ($(CROSS_COMPILE),) -CROSS_COMPILE_HOST = --host=$(patsubst %-,%,$(CROSS_COMPILE)) -else -CROSS_COMPILE_HOST = -endif - -deplibs: libffi - -# install-exec-recursive & install-data-am targets are used to avoid building -# docs and depending on makeinfo -libffi: - cd $(MPTOP)/lib/libffi; git clean -d -x -f - cd $(MPTOP)/lib/libffi; ./autogen.sh - mkdir -p $(MPTOP)/lib/libffi/build_dir; cd $(MPTOP)/lib/libffi/build_dir; \ - ../configure $(CROSS_COMPILE_HOST) --prefix=$$PWD/out CC="$(CC)" CXX="$(CXX)" LD="$(LD)"; \ - make install-exec-recursive; make -C include install-data-am diff --git a/examples/embedding/README.md b/examples/embedding/README.md index 0dfc52e1dc..e3683acdc2 100644 --- a/examples/embedding/README.md +++ b/examples/embedding/README.md @@ -1,67 +1,37 @@ Example of embedding MicroPython in a standalone C application ============================================================== -This directory contains a (very simple!) example of how to embed a MicroPython -in an existing C application. - -A C application is represented by the file `hello-embed.c`. It executes a simple -Python statement which prints to the standard output. +This directory contains a simple example of how to embed MicroPython in an +existing C application. +A C application is represented here by the file `main.c`. It executes two +simple Python scripts which print things to the standard output. Building the example -------------------- -Building the example is as simple as running: +First build the embed port using: - make + $ make -f micropython_embed.mk -It's worth to trace what's happening behind the scenes though: +This will generate the `micropython_embed` directory which is a self-contained +copy of MicroPython suitable for embedding. The .c files in this directory need +to be compiled into your project, in whatever way your project can do that. The +example here uses make and a provided `Makefile`. -1. As a first step, a MicroPython library is built. This is handled by a -separate makefile, `Makefile.upylib`. It is more or less complex, but the -good news is that you won't need to change anything in it, just use it -as is, the main `Makefile` shows how. What may require editing though is -a MicroPython configuration file. MicroPython is highly configurable, so -you would need to build a library suiting your application well, while -not bloating its size. Check the options in the file `mpconfigport.h`. -Included is a copy of the "minimal" Unix port, which should be a good start -for minimal embedding. For the list of all available options, see -`py/mpconfig.h`. +To build the example project, based on `main.c`, use: -2. Once the MicroPython library is built, your application is compiled -and linked it. The main Makefile is very simple and shows that the changes -you would need to do to your application's `Makefile` (or other build -configuration) are also simple: + $ make -a) You would need to use C99 standard (you're using this 15+ years old -standard already, not a 25+ years old one, right?). - -b) You need to provide a path to MicroPython's top-level dir, for includes. - -c) You need to include `-DNO_QSTR` compile-time flag. - -d) Otherwise, just link with the MicroPython library produced in step 1. +That will create an exacutable called `embed` which you can run: + $ ./embed Out of tree build ----------------- This example is set up to work out of the box, being part of the MicroPython -tree. Your application of course will be outside of its tree, but the -only thing you need to do is to pass `MPTOP` variable pointing to -MicroPython directory to both Makefiles (in this example, the main Makefile -automatically passes it to `Makefile.upylib`; in your own Makefile, don't forget -to use a suitable value). - -A practical way to embed MicroPython in your application is to include it -as a git submodule. Suppose you included it as `libs/micropython`. Then in -your main Makefile you would have something like: - -~~~ -MPTOP = libs/micropython - -my_app: $(MY_OBJS) -lmicropython - --lmicropython: - $(MAKE) -f $(MPTOP)/examples/embedding/Makefile.upylib MPTOP=$(MPTOP) -~~~ +tree. Your application will be outside of this tree, but the only thing you +need to do for that is to change `MICROPYTHON_TOP` (found in `micropython_embed.mk`) +to point to the location of the MicroPython repository. The MicroPython +repository may, for example, be a git submodule in your project. diff --git a/examples/embedding/hello-embed.c b/examples/embedding/hello-embed.c deleted file mode 100644 index 0b778986b3..0000000000 --- a/examples/embedding/hello-embed.c +++ /dev/null @@ -1,76 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2016 Paul Sokolovsky - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include -#include -#include - -#include "py/builtin.h" -#include "py/compile.h" -#include "py/runtime.h" -#include "py/gc.h" -#include "py/stackctrl.h" - -static char heap[16384]; - -mp_obj_t execute_from_str(const char *str) { - nlr_buf_t nlr; - if (nlr_push(&nlr) == 0) { - qstr src_name = 1/*MP_QSTR_*/; - mp_lexer_t *lex = mp_lexer_new_from_str_len(src_name, str, strlen(str), false); - mp_parse_tree_t pt = mp_parse(lex, MP_PARSE_FILE_INPUT); - mp_obj_t module_fun = mp_compile(&pt, src_name, false); - mp_call_function_0(module_fun); - nlr_pop(); - return 0; - } else { - // uncaught exception - return (mp_obj_t)nlr.ret_val; - } -} - -int main() { - // Initialized stack limit - mp_stack_set_limit(40000 * (sizeof(void *) / 4)); - // Initialize heap - gc_init(heap, heap + sizeof(heap)); - // Initialize interpreter - mp_init(); - - const char str[] = "print('Hello world of easy embedding!')"; - if (execute_from_str(str)) { - printf("Error\n"); - } -} - -uint mp_import_stat(const char *path) { - return MP_IMPORT_STAT_NO_EXIST; -} - -void nlr_jump_fail(void *val) { - printf("FATAL: uncaught NLR %p\n", val); - exit(1); -} diff --git a/examples/embedding/main.c b/examples/embedding/main.c new file mode 100644 index 0000000000..ee673fc93a --- /dev/null +++ b/examples/embedding/main.c @@ -0,0 +1,44 @@ +/* This file is part of the MicroPython project, http://micropython.org/ + * The MIT License (MIT) + * Copyright (c) 2022-2023 Damien P. George + */ + +#include "port/micropython_embed.h" + +// This is example 1 script, which will be compiled and executed. +static const char *example_1 = + "print('hello world!', list(x + 1 for x in range(10)), end='eol\\n')"; + +// This is example 2 script, which will be compiled and executed. +static const char *example_2 = + "for i in range(10):\n" + " print('iter {:08}'.format(i))\n" + "\n" + "try:\n" + " 1//0\n" + "except Exception as er:\n" + " print('caught exception', repr(er))\n" + "\n" + "import gc\n" + "print('run GC collect')\n" + "gc.collect()\n" + "\n" + "print('finish')\n" + ; + +// This array is the MicroPython GC heap. +static char heap[8 * 1024]; + +int main() { + // Initialise MicroPython. + mp_embed_init(&heap[0], sizeof(heap)); + + // Run the example scripts (they will be compiled first). + mp_embed_exec_str(example_1); + mp_embed_exec_str(example_2); + + // Deinitialise MicroPython. + mp_embed_deinit(); + + return 0; +} diff --git a/examples/embedding/micropython_embed.mk b/examples/embedding/micropython_embed.mk new file mode 100644 index 0000000000..5db5415927 --- /dev/null +++ b/examples/embedding/micropython_embed.mk @@ -0,0 +1,9 @@ +# This file is part of the MicroPython project, http://micropython.org/ +# The MIT License (MIT) +# Copyright (c) 2022-2023 Damien P. George + +# Set the location of the top of the MicroPython repository. +MICROPYTHON_TOP = ../.. + +# Include the main makefile fragment to build the MicroPython component. +include $(MICROPYTHON_TOP)/ports/embed/embed.mk diff --git a/examples/embedding/mpconfigport.h b/examples/embedding/mpconfigport.h index 89c180b2a8..ed34a5d766 100644 --- a/examples/embedding/mpconfigport.h +++ b/examples/embedding/mpconfigport.h @@ -1 +1,15 @@ -#include "mpconfigport_minimal.h" +/* This file is part of the MicroPython project, http://micropython.org/ + * The MIT License (MIT) + * Copyright (c) 2022-2023 Damien P. George + */ + +// Include common MicroPython embed configuration. +#include + +// Use the minimal starting configuration (disables all optional features). +#define MICROPY_CONFIG_ROM_LEVEL (MICROPY_CONFIG_ROM_LEVEL_MINIMUM) + +// MicroPython configuration. +#define MICROPY_ENABLE_COMPILER (1) +#define MICROPY_ENABLE_GC (1) +#define MICROPY_PY_GC (1) diff --git a/examples/embedding/mpconfigport_minimal.h b/examples/embedding/mpconfigport_minimal.h deleted file mode 100644 index 02089c1a62..0000000000 --- a/examples/embedding/mpconfigport_minimal.h +++ /dev/null @@ -1,122 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2015 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. - */ - -// options to control how MicroPython is built - -#define MICROPY_ALLOC_PATH_MAX (PATH_MAX) -#define MICROPY_ENABLE_GC (1) -#define MICROPY_ENABLE_FINALISER (0) -#define MICROPY_STACK_CHECK (0) -#define MICROPY_COMP_CONST (0) -#define MICROPY_MEM_STATS (0) -#define MICROPY_DEBUG_PRINTERS (0) -#define MICROPY_READER_POSIX (1) -#define MICROPY_KBD_EXCEPTION (1) -#define MICROPY_HELPER_REPL (1) -#define MICROPY_HELPER_LEXER_UNIX (1) -#define MICROPY_ENABLE_SOURCE_LINE (0) -#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_TERSE) -#define MICROPY_WARNINGS (0) -#define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (0) -#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_NONE) -#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_NONE) -#define MICROPY_STREAMS_NON_BLOCK (0) -#define MICROPY_OPT_COMPUTED_GOTO (0) -#define MICROPY_CAN_OVERRIDE_BUILTINS (0) -#define MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG (0) -#define MICROPY_CPYTHON_COMPAT (0) -#define MICROPY_PY_BUILTINS_BYTEARRAY (0) -#define MICROPY_PY_BUILTINS_MEMORYVIEW (0) -#define MICROPY_PY_BUILTINS_COMPILE (0) -#define MICROPY_PY_BUILTINS_ENUMERATE (0) -#define MICROPY_PY_BUILTINS_FILTER (0) -#define MICROPY_PY_BUILTINS_FROZENSET (0) -#define MICROPY_PY_BUILTINS_REVERSED (0) -#define MICROPY_PY_BUILTINS_SET (0) -#define MICROPY_PY_BUILTINS_SLICE (0) -#define MICROPY_PY_BUILTINS_STR_UNICODE (0) -#define MICROPY_PY_BUILTINS_PROPERTY (0) -#define MICROPY_PY_BUILTINS_MIN_MAX (0) -#define MICROPY_PY___FILE__ (0) -#define MICROPY_PY_MICROPYTHON_MEM_INFO (0) -#define MICROPY_PY_GC (0) -#define MICROPY_PY_GC_COLLECT_RETVAL (0) -#define MICROPY_PY_ARRAY (0) -#define MICROPY_PY_COLLECTIONS (0) -#define MICROPY_PY_MATH (0) -#define MICROPY_PY_CMATH (0) -#define MICROPY_PY_IO (0) -#define MICROPY_PY_STRUCT (0) -#define MICROPY_PY_SYS (1) -#define MICROPY_PY_SYS_EXIT (0) -#define MICROPY_PY_SYS_PLATFORM "linux" -#define MICROPY_PY_SYS_MAXSIZE (0) -#define MICROPY_PY_SYS_PATH_DEFAULT ".frozen" -#define MICROPY_PY_SYS_STDFILES (0) -#define MICROPY_PY_CMATH (0) -#define MICROPY_PY_UCTYPES (0) -#define MICROPY_PY_UZLIB (0) -#define MICROPY_PY_UJSON (0) -#define MICROPY_PY_UOS (1) -#define MICROPY_PY_URE (0) -#define MICROPY_PY_UHEAPQ (0) -#define MICROPY_PY_UHASHLIB (0) -#define MICROPY_PY_UBINASCII (0) - -////////////////////////////////////////// -// Do not change anything beyond this line -////////////////////////////////////////// - -#if !(defined(MICROPY_GCREGS_SETJMP) || defined(__x86_64__) || defined(__i386__) || defined(__thumb2__) || defined(__thumb__) || defined(__arm__)) -// Fall back to setjmp() implementation for discovery of GC pointers in registers. -#define MICROPY_GCREGS_SETJMP (1) -#endif - -// type definitions for the specific machine - -#ifdef __LP64__ -typedef long mp_int_t; // must be pointer size -typedef unsigned long mp_uint_t; // must be pointer size -#else -// These are definitions for machines where sizeof(int) == sizeof(void*), -// regardless for actual size. -typedef int mp_int_t; // must be pointer size -typedef unsigned int mp_uint_t; // must be pointer size -#endif - -// Cannot include , as it may lead to symbol name clashes -#if _FILE_OFFSET_BITS == 64 && !defined(__LP64__) -typedef long long mp_off_t; -#else -typedef long mp_off_t; -#endif - -// We need to provide a declaration/definition of alloca() -#ifdef __FreeBSD__ -#include -#else -#include -#endif diff --git a/examples/rp2/pio_1hz.py b/examples/rp2/pio_1hz.py index c18aa22fc0..4b6fe95bbd 100644 --- a/examples/rp2/pio_1hz.py +++ b/examples/rp2/pio_1hz.py @@ -16,9 +16,10 @@ def blink_1hz(): nop() [29] jmp(x_dec, "delay_high") - # Cycles: 1 + 7 + 32 * (30 + 1) = 1000 + # Cycles: 1 + 1 + 6 + 32 * (30 + 1) = 1000 + nop() set(pins, 0) - set(x, 31) [6] + set(x, 31) [5] label("delay_low") nop() [29] jmp(x_dec, "delay_low") diff --git a/extmod/axtls-include/axtls_os_port.h b/extmod/axtls-include/axtls_os_port.h index ef2683acfc..057642f974 100644 --- a/extmod/axtls-include/axtls_os_port.h +++ b/extmod/axtls-include/axtls_os_port.h @@ -26,7 +26,11 @@ #ifndef AXTLS_OS_PORT_H #define AXTLS_OS_PORT_H +#ifndef __ets__ +#include +#endif #include +#include #include "py/stream.h" #include "lib/crypto-algorithms/sha256.h" diff --git a/lib/re1.5/charclass.c b/lib/re1.5/charclass.c index 7f6388c93d..2553b40530 100644 --- a/lib/re1.5/charclass.c +++ b/lib/re1.5/charclass.c @@ -6,7 +6,15 @@ int _re1_5_classmatch(const char *pc, const char *sp) int is_positive = (pc[-1] == Class); int cnt = *pc++; while (cnt--) { - if (*sp >= *pc && *sp <= pc[1]) return is_positive; + if (*pc == RE15_CLASS_NAMED_CLASS_INDICATOR) { + if (_re1_5_namedclassmatch(pc + 1, sp)) { + return is_positive; + } + } else { + if (*sp >= *pc && *sp <= pc[1]) { + return is_positive; + } + } pc += 2; } return !is_positive; diff --git a/lib/re1.5/compilecode.c b/lib/re1.5/compilecode.c index add4f6ac20..513a155970 100644 --- a/lib/re1.5/compilecode.c +++ b/lib/re1.5/compilecode.c @@ -4,6 +4,9 @@ #include "re1.5.h" +// Matches: DSWdsw +#define MATCH_NAMED_CLASS_CHAR(c) (((c) | 0x20) == 'd' || ((c) | 0x24) == 'w') + #define INSERT_CODE(at, num, pc) \ ((code ? memmove(code + at + num, code + at, pc - at) : 0), pc += num) #define REL(at, to) (to - at - 2) @@ -31,7 +34,7 @@ static const char *_compilecode(const char *re, ByteProg *prog, int sizecode) case '\\': re++; if (!*re) return NULL; // Trailing backslash - if ((*re | 0x20) == 'd' || (*re | 0x20) == 's' || (*re | 0x20) == 'w') { + if (MATCH_NAMED_CLASS_CHAR(*re)) { term = PC; EMIT(PC++, NamedClass); EMIT(PC++, *re); @@ -63,14 +66,21 @@ static const char *_compilecode(const char *re, ByteProg *prog, int sizecode) PC++; // Skip # of pair byte prog->len++; for (cnt = 0; *re != ']'; re++, cnt++) { - if (*re == '\\') { + char c = *re; + if (c == '\\') { ++re; + c = *re; + if (MATCH_NAMED_CLASS_CHAR(c)) { + c = RE15_CLASS_NAMED_CLASS_INDICATOR; + goto emit_char_pair; + } } - if (!*re) return NULL; - EMIT(PC++, *re); + if (!c) return NULL; if (re[1] == '-' && re[2] != ']') { re += 2; } + emit_char_pair: + EMIT(PC++, c); EMIT(PC++, *re); } EMIT_CHECKED(term + 1, cnt); diff --git a/lib/re1.5/re1.5.h b/lib/re1.5/re1.5.h index 81f43ed7f5..b1ec01cbc5 100644 --- a/lib/re1.5/re1.5.h +++ b/lib/re1.5/re1.5.h @@ -138,6 +138,7 @@ struct Subject { #define NON_ANCHORED_PREFIX 5 #define HANDLE_ANCHORED(bytecode, is_anchored) ((is_anchored) ? (bytecode) + NON_ANCHORED_PREFIX : (bytecode)) +#define RE15_CLASS_NAMED_CLASS_INDICATOR 0 int re1_5_backtrack(ByteProg*, Subject*, const char**, int, int); int re1_5_pikevm(ByteProg*, Subject*, const char**, int, int); diff --git a/ports/cc3200/application.mk b/ports/cc3200/application.mk index 428367d66a..97e113b040 100644 --- a/ports/cc3200/application.mk +++ b/ports/cc3200/application.mk @@ -162,7 +162,7 @@ APP_STM_SRC_C = $(addprefix ports/stm32/,\ OBJ = $(PY_O) $(addprefix $(BUILD)/, $(APP_FATFS_SRC_C:.c=.o) $(APP_RTOS_SRC_C:.c=.o) $(APP_FTP_SRC_C:.c=.o) $(APP_HAL_SRC_C:.c=.o) $(APP_MISC_SRC_C:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(APP_MODS_SRC_C:.c=.o) $(APP_CC3100_SRC_C:.c=.o) $(APP_SL_SRC_C:.c=.o) $(APP_TELNET_SRC_C:.c=.o) $(APP_UTIL_SRC_C:.c=.o) $(APP_UTIL_SRC_S:.s=.o)) OBJ += $(addprefix $(BUILD)/, $(APP_MAIN_SRC_C:.c=.o) $(APP_SHARED_SRC_C:.c=.o) $(APP_LIB_SRC_C:.c=.o) $(APP_STM_SRC_C:.c=.o)) -OBJ += $(BUILD)/shared/runtime/gchelper_m3.o +OBJ += $(BUILD)/shared/runtime/gchelper_thumb2.o OBJ += $(BUILD)/pins.o # List of sources for qstr extraction diff --git a/ports/embed/README.md b/ports/embed/README.md new file mode 100644 index 0000000000..556cfc749d --- /dev/null +++ b/ports/embed/README.md @@ -0,0 +1,18 @@ +MicroPython embed port +====================== + +This is a port of MicroPython that outputs a set of .c and .h files for embedding +into a wider project. This port essentially targets the C language, instead of a +particular hardware architecture or platform. + +To use this port in a project there are three main steps: + +1. Provide configuration for the project via an `mpconfigport.h` file. + +2. Build this embed port against that configuration, using the provided `embed.mk`. + The output is a set of self-contained source files for building MicroPython. + These files can be placed outside this repository. + +3. Build the project. This requires compiling all .c files from the above step. + +See `examples/embedding` for an example. diff --git a/ports/embed/embed.mk b/ports/embed/embed.mk new file mode 100644 index 0000000000..7fb344d704 --- /dev/null +++ b/ports/embed/embed.mk @@ -0,0 +1,65 @@ +# This file is part of the MicroPython project, http://micropython.org/ +# The MIT License (MIT) +# Copyright (c) 2022-2023 Damien P. George +# +# This file is intended to be included by a Makefile in a custom project. + +# Set the build output directory for the generated files. +BUILD = build-embed + +# Include the core environment definitions; this will set $(TOP). +include $(MICROPYTHON_TOP)/py/mkenv.mk + +# Include py core make definitions. +include $(TOP)/py/py.mk + +# Set the location of the MicroPython embed port. +MICROPYTHON_EMBED_PORT = $(MICROPYTHON_TOP)/ports/embed + +# Set default makefile-level MicroPython feature configurations. +MICROPY_ROM_TEXT_COMPRESSION ?= 0 + +# Set CFLAGS for the MicroPython build. +CFLAGS += -I. -I$(TOP) -I$(BUILD) -I$(MICROPYTHON_EMBED_PORT) +CFLAGS += -Wall -Werror -std=c99 + +# Define the required generated header files. +GENHDR_OUTPUT = $(addprefix $(BUILD)/genhdr/, \ + moduledefs.h \ + mpversion.h \ + qstrdefs.generated.h \ + root_pointers.h \ + ) + +# Define the top-level target, the generated output files. +.PHONY: all +all: micropython-embed-package + +clean: clean-micropython-embed-package + +.PHONY: clean-micropython-embed-package +clean-micropython-embed-package: + $(RM) -rf $(PACKAGE_DIR) + +PACKAGE_DIR ?= micropython_embed +PACKAGE_DIR_LIST = $(addprefix $(PACKAGE_DIR)/,py extmod shared/runtime genhdr port) + +.PHONY: micropython-embed-package +micropython-embed-package: $(GENHDR_OUTPUT) + $(ECHO) "Generate micropython_embed output:" + $(Q)$(RM) -rf $(PACKAGE_DIR_LIST) + $(Q)$(MKDIR) -p $(PACKAGE_DIR_LIST) + $(ECHO) "- py" + $(Q)$(CP) $(TOP)/py/*.[ch] $(PACKAGE_DIR)/py + $(ECHO) "- extmod" + $(Q)$(CP) $(TOP)/extmod/moduplatform.h $(PACKAGE_DIR)/extmod + $(ECHO) "- shared" + $(Q)$(CP) $(TOP)/shared/runtime/gchelper.h $(PACKAGE_DIR)/shared/runtime + $(Q)$(CP) $(TOP)/shared/runtime/gchelper_generic.c $(PACKAGE_DIR)/shared/runtime + $(ECHO) "- genhdr" + $(Q)$(CP) $(GENHDR_OUTPUT) $(PACKAGE_DIR)/genhdr + $(ECHO) "- port" + $(Q)$(CP) $(MICROPYTHON_EMBED_PORT)/port/*.[ch] $(PACKAGE_DIR)/port + +# Include remaining core make rules. +include $(TOP)/py/mkrules.mk diff --git a/ports/embed/port/embed_util.c b/ports/embed/port/embed_util.c new file mode 100644 index 0000000000..a3850f3c0f --- /dev/null +++ b/ports/embed/port/embed_util.c @@ -0,0 +1,106 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2022-2023 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include "py/compile.h" +#include "py/gc.h" +#include "py/persistentcode.h" +#include "py/runtime.h" +#include "py/stackctrl.h" +#include "shared/runtime/gchelper.h" +#include "port/micropython_embed.h" + +// Initialise the runtime. +void mp_embed_init(void *gc_heap, size_t gc_heap_size) { + mp_stack_ctrl_init(); + gc_init(gc_heap, (uint8_t *)gc_heap + gc_heap_size); + mp_init(); +} + +#if MICROPY_ENABLE_COMPILER +// Compile and execute the given source script (Python text). +void mp_embed_exec_str(const char *src) { + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + // Compile, parse and execute the given string. + mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0); + qstr source_name = lex->source_name; + mp_parse_tree_t parse_tree = mp_parse(lex, MP_PARSE_FILE_INPUT); + mp_obj_t module_fun = mp_compile(&parse_tree, source_name, true); + mp_call_function_0(module_fun); + nlr_pop(); + } else { + // Uncaught exception: print it out. + mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val); + } +} +#endif + +#if MICROPY_PERSISTENT_CODE_LOAD +void mp_embed_exec_mpy(const uint8_t *mpy, size_t len) { + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + // Execute the given .mpy data. + mp_module_context_t *ctx = m_new_obj(mp_module_context_t); + ctx->module.globals = mp_globals_get(); + mp_compiled_module_t cm = mp_raw_code_load_mem(mpy, len, ctx); + mp_obj_t f = mp_make_function_from_raw_code(cm.rc, ctx, MP_OBJ_NULL); + mp_call_function_0(f); + nlr_pop(); + } else { + // Uncaught exception: print it out. + mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val); + } +} +#endif + +// Deinitialise the runtime. +void mp_embed_deinit(void) { + mp_deinit(); +} + +#if MICROPY_ENABLE_GC +// Run a garbage collection cycle. +void gc_collect(void) { + gc_collect_start(); + gc_helper_collect_regs_and_stack(); + gc_collect_end(); +} +#endif + +// Called if an exception is raised outside all C exception-catching handlers. +void nlr_jump_fail(void *val) { + for (;;) { + } +} + +#ifndef NDEBUG +// Used when debugging is enabled. +void __assert_func(const char *file, int line, const char *func, const char *expr) { + for (;;) { + } +} +#endif diff --git a/ports/embed/port/micropython_embed.h b/ports/embed/port/micropython_embed.h new file mode 100644 index 0000000000..bf55d9b2b4 --- /dev/null +++ b/ports/embed/port/micropython_embed.h @@ -0,0 +1,41 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2022-2023 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_MICROPYTHON_EMBED_H +#define MICROPY_INCLUDED_MICROPYTHON_EMBED_H + +#include +#include + +void mp_embed_init(void *gc_heap, size_t gc_heap_size); +void mp_embed_deinit(void); + +// Only available if MICROPY_ENABLE_COMPILER is enabled. +void mp_embed_exec_str(const char *src); + +// Only available if MICROPY_PERSISTENT_CODE_LOAD is enabled. +void mp_embed_exec_mpy(const uint8_t *mpy, size_t len); + +#endif // MICROPY_INCLUDED_MICROPYTHON_EMBED_H diff --git a/ports/embed/port/mpconfigport_common.h b/ports/embed/port/mpconfigport_common.h new file mode 100644 index 0000000000..69216a7582 --- /dev/null +++ b/ports/embed/port/mpconfigport_common.h @@ -0,0 +1,38 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2022-2023 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 + +// Type definitions for the specific machine + +typedef intptr_t mp_int_t; // must be pointer size +typedef uintptr_t mp_uint_t; // must be pointer size +typedef long mp_off_t; + +// Need to provide a declaration/definition of alloca() +#include + +#define MICROPY_MPHALPORT_H "port/mphalport.h" diff --git a/ports/embed/port/mphalport.c b/ports/embed/port/mphalport.c new file mode 100644 index 0000000000..8e76a8e22e --- /dev/null +++ b/ports/embed/port/mphalport.c @@ -0,0 +1,33 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2022-2023 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include "py/mphal.h" + +// Send string of given length to stdout, converting \n to \r\n. +void mp_hal_stdout_tx_strn_cooked(const char *str, size_t len) { + printf("%.*s", (int)len, str); +} diff --git a/ports/embed/port/mphalport.h b/ports/embed/port/mphalport.h new file mode 100644 index 0000000000..49928e154d --- /dev/null +++ b/ports/embed/port/mphalport.h @@ -0,0 +1,2 @@ +// Define so there's no dependency on extmod/virtpin.h +#define mp_hal_pin_obj_t diff --git a/ports/esp32/boards/GENERIC_UNICORE/board.json b/ports/esp32/boards/GENERIC_UNICORE/board.json new file mode 100644 index 0000000000..8fed71a018 --- /dev/null +++ b/ports/esp32/boards/GENERIC_UNICORE/board.json @@ -0,0 +1,19 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [ + "BLE", + "WiFi" + ], + "id": "esp32-unicore", + "images": [ + "generic_unicore.jpg" + ], + "mcu": "esp32", + "product": "ESP32 Unicore", + "thumbnail": "", + "url": "https://www.espressif.com/en/products/modules", + "vendor": "Espressif" +} diff --git a/ports/esp32/boards/GENERIC_UNICORE/board.md b/ports/esp32/boards/GENERIC_UNICORE/board.md new file mode 100644 index 0000000000..b41c167498 --- /dev/null +++ b/ports/esp32/boards/GENERIC_UNICORE/board.md @@ -0,0 +1 @@ +The following files are daily firmware for single-core ESP32-based boards without external SPIRAM. diff --git a/ports/esp32/boards/GENERIC_UNICORE/mpconfigboard.cmake b/ports/esp32/boards/GENERIC_UNICORE/mpconfigboard.cmake new file mode 100644 index 0000000000..2f34688c8c --- /dev/null +++ b/ports/esp32/boards/GENERIC_UNICORE/mpconfigboard.cmake @@ -0,0 +1,5 @@ +set(SDKCONFIG_DEFAULTS + boards/sdkconfig.base + boards/sdkconfig.ble + boards/GENERIC_UNICORE/sdkconfig.board +) diff --git a/ports/esp32/boards/GENERIC_UNICORE/mpconfigboard.h b/ports/esp32/boards/GENERIC_UNICORE/mpconfigboard.h new file mode 100644 index 0000000000..5d0624b9c3 --- /dev/null +++ b/ports/esp32/boards/GENERIC_UNICORE/mpconfigboard.h @@ -0,0 +1,2 @@ +#define MICROPY_HW_BOARD_NAME "ESP32 Unicore module" +#define MICROPY_HW_MCU_NAME "ESP32-UNICORE" diff --git a/ports/esp32/boards/GENERIC_UNICORE/sdkconfig.board b/ports/esp32/boards/GENERIC_UNICORE/sdkconfig.board new file mode 100644 index 0000000000..f0b0b5e03d --- /dev/null +++ b/ports/esp32/boards/GENERIC_UNICORE/sdkconfig.board @@ -0,0 +1 @@ +CONFIG_FREERTOS_UNICORE=y diff --git a/ports/esp32/boards/OLIMEX_ESP32_POE/board.json b/ports/esp32/boards/OLIMEX_ESP32_POE/board.json new file mode 100644 index 0000000000..84b6680d59 --- /dev/null +++ b/ports/esp32/boards/OLIMEX_ESP32_POE/board.json @@ -0,0 +1,23 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [ + "BLE", + "WiFi", + "MicroSD", + "Battery Charging", + "Ethernet", + "PoE", + "Breadboard friendly" + ], + "images": [ + "ESP32-POE-ISO-1.jpg" + ], + "mcu": "esp32", + "product": "Olimex ESP32 POE", + "thumbnail": "", + "url": "https://www.olimex.com/", + "vendor": "OLIMEX" +} diff --git a/ports/esp32/boards/OLIMEX_ESP32_POE/board.md b/ports/esp32/boards/OLIMEX_ESP32_POE/board.md new file mode 100644 index 0000000000..1e2dbb744a --- /dev/null +++ b/ports/esp32/boards/OLIMEX_ESP32_POE/board.md @@ -0,0 +1,4 @@ +The following files are daily firmware for Olimex ESP32 boards with Ethernet. +They match the boards ESP32 ETH-PoE, ESP32 ETH-PoE-ISO and ESP32 Gateway. + +This firmware is compiled using ESP-IDF v4.x. diff --git a/ports/esp32/boards/OLIMEX_ESP32_POE/mpconfigboard.cmake b/ports/esp32/boards/OLIMEX_ESP32_POE/mpconfigboard.cmake new file mode 100644 index 0000000000..c460b07d5e --- /dev/null +++ b/ports/esp32/boards/OLIMEX_ESP32_POE/mpconfigboard.cmake @@ -0,0 +1,5 @@ +set(SDKCONFIG_DEFAULTS + boards/sdkconfig.base + boards/sdkconfig.ble + boards/OLIMEX_ESP32_POE/sdkconfig.board +) diff --git a/ports/esp32/boards/OLIMEX_ESP32_POE/mpconfigboard.h b/ports/esp32/boards/OLIMEX_ESP32_POE/mpconfigboard.h new file mode 100644 index 0000000000..c8458e35fa --- /dev/null +++ b/ports/esp32/boards/OLIMEX_ESP32_POE/mpconfigboard.h @@ -0,0 +1,2 @@ +#define MICROPY_HW_BOARD_NAME "Olimex ESP32 ETH" +#define MICROPY_HW_MCU_NAME "ESP32" diff --git a/ports/esp32/boards/OLIMEX_ESP32_POE/sdkconfig.board b/ports/esp32/boards/OLIMEX_ESP32_POE/sdkconfig.board new file mode 100644 index 0000000000..15ffbf3a67 --- /dev/null +++ b/ports/esp32/boards/OLIMEX_ESP32_POE/sdkconfig.board @@ -0,0 +1,4 @@ +CONFIG_ETH_PHY_INTERFACE_RMII=y +CONFIG_ETH_RMII_CLK_OUTPUT=y +CONFIG_ETH_RMII_CLK_OUT_GPIO=17 +CONFIG_LWIP_LOCAL_HOSTNAME="ESP32_POE" diff --git a/ports/esp32/machine_hw_spi.c b/ports/esp32/machine_hw_spi.c index 35ecc397b3..36f8d3f069 100644 --- a/ports/esp32/machine_hw_spi.c +++ b/ports/esp32/machine_hw_spi.c @@ -533,6 +533,14 @@ mp_obj_t machine_hw_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_ return MP_OBJ_FROM_PTR(self); } +spi_host_device_t machine_hw_spi_get_host(mp_obj_t in) { + if (mp_obj_get_type(in) != &machine_spi_type) { + mp_raise_ValueError(MP_ERROR_TEXT("expecting a SPI object")); + } + machine_hw_spi_obj_t *self = (machine_hw_spi_obj_t *)in; + return self->host; +} + STATIC const mp_machine_spi_p_t machine_hw_spi_p = { .init = machine_hw_spi_init, .deinit = machine_hw_spi_deinit, diff --git a/ports/esp32/machine_sdcard.c b/ports/esp32/machine_sdcard.c index 801a26f378..5b495f8494 100644 --- a/ports/esp32/machine_sdcard.c +++ b/ports/esp32/machine_sdcard.c @@ -211,7 +211,7 @@ STATIC mp_obj_t machine_sdcard_make_new(const mp_obj_type_t *type, size_t n_args .gpio_cs = GPIO_NUM_34, .gpio_cd = SDSPI_SLOT_NO_CD, .gpio_wp = SDSPI_SLOT_NO_WP, - .dma_channel = 2 + .dma_channel = SPI_DMA_CH_AUTO }, SDSPI_SLOT_CONFIG_DEFAULT() }; diff --git a/ports/esp32/modnetwork.c b/ports/esp32/modnetwork.c index 7429274c15..3f56fcfae2 100644 --- a/ports/esp32/modnetwork.c +++ b/ports/esp32/modnetwork.c @@ -229,7 +229,7 @@ STATIC const mp_rom_map_elem_t mp_module_network_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_WLAN), MP_ROM_PTR(&get_wlan_obj) }, #endif - #if (ESP_IDF_VERSION_MAJOR == 4) && (ESP_IDF_VERSION_MINOR >= 1) && (CONFIG_IDF_TARGET_ESP32) + #if MICROPY_PY_NETWORK_LAN { MP_ROM_QSTR(MP_QSTR_LAN), MP_ROM_PTR(&get_lan_obj) }, #endif { MP_ROM_QSTR(MP_QSTR_PPP), MP_ROM_PTR(&ppp_make_new_obj) }, @@ -260,7 +260,8 @@ STATIC const mp_rom_map_elem_t mp_module_network_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_AUTH_MAX), MP_ROM_INT(WIFI_AUTH_MAX) }, #endif - #if (ESP_IDF_VERSION_MAJOR == 4) && (ESP_IDF_VERSION_MINOR >= 1) && (CONFIG_IDF_TARGET_ESP32) + #if MICROPY_PY_NETWORK_LAN + { MP_ROM_QSTR(MP_QSTR_PHY_LAN8710), MP_ROM_INT(PHY_LAN8710) }, { MP_ROM_QSTR(MP_QSTR_PHY_LAN8720), MP_ROM_INT(PHY_LAN8720) }, { MP_ROM_QSTR(MP_QSTR_PHY_IP101), MP_ROM_INT(PHY_IP101) }, { MP_ROM_QSTR(MP_QSTR_PHY_RTL8201), MP_ROM_INT(PHY_RTL8201) }, @@ -269,6 +270,20 @@ STATIC const mp_rom_map_elem_t mp_module_network_globals_table[] = { // PHY_KSZ8041 is new in ESP-IDF v4.3 { MP_ROM_QSTR(MP_QSTR_PHY_KSZ8041), MP_ROM_INT(PHY_KSZ8041) }, #endif + #if ESP_IDF_VERSION_MINOR >= 4 + // PHY_KSZ8081 is new in ESP-IDF v4.4 + { MP_ROM_QSTR(MP_QSTR_PHY_KSZ8081), MP_ROM_INT(PHY_KSZ8081) }, + #endif + + #if CONFIG_ETH_SPI_ETHERNET_KSZ8851SNL + { MP_ROM_QSTR(MP_QSTR_PHY_KSZ8851SNL), MP_ROM_INT(PHY_KSZ8851SNL) }, + #endif + #if CONFIG_ETH_SPI_ETHERNET_DM9051 + { MP_ROM_QSTR(MP_QSTR_PHY_DM9051), MP_ROM_INT(PHY_DM9051) }, + #endif + #if CONFIG_ETH_SPI_ETHERNET_W5500 + { MP_ROM_QSTR(MP_QSTR_PHY_W5500), MP_ROM_INT(PHY_W5500) }, + #endif { MP_ROM_QSTR(MP_QSTR_ETH_INITIALIZED), MP_ROM_INT(ETH_INITIALIZED)}, { MP_ROM_QSTR(MP_QSTR_ETH_STARTED), MP_ROM_INT(ETH_STARTED)}, diff --git a/ports/esp32/modnetwork.h b/ports/esp32/modnetwork.h index 7bcfa0e6fc..d90679fa8a 100644 --- a/ports/esp32/modnetwork.h +++ b/ports/esp32/modnetwork.h @@ -28,7 +28,8 @@ #include "esp_event.h" -enum { PHY_LAN8720, PHY_IP101, PHY_RTL8201, PHY_DP83848, PHY_KSZ8041 }; +enum { PHY_LAN8710, PHY_LAN8720, PHY_IP101, PHY_RTL8201, PHY_DP83848, PHY_KSZ8041, PHY_KSZ8081, PHY_KSZ8851SNL = 100, PHY_DM9051, PHY_W5500 }; +#define IS_SPI_PHY(NUM) (NUM >= 100) enum { ETH_INITIALIZED, ETH_STARTED, ETH_STOPPED, ETH_CONNECTED, ETH_DISCONNECTED, ETH_GOT_IP }; // Cases similar to ESP8266 user_interface.h diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h index d8822980b7..38468cf9cf 100644 --- a/ports/esp32/mpconfigport.h +++ b/ports/esp32/mpconfigport.h @@ -217,3 +217,21 @@ typedef long mp_off_t; #endif void boardctrl_startup(void); + +#ifndef MICROPY_PY_NETWORK_LAN +#if (ESP_IDF_VERSION_MAJOR == 4) && (ESP_IDF_VERSION_MINOR >= 1) && (CONFIG_IDF_TARGET_ESP32 || (CONFIG_ETH_USE_SPI_ETHERNET && (CONFIG_ETH_SPI_ETHERNET_KSZ8851SNL || CONFIG_ETH_SPI_ETHERNET_DM9051 || CONFIG_ETH_SPI_ETHERNET_W5500))) +#define MICROPY_PY_NETWORK_LAN (1) +#else +#define MICROPY_PY_NETWORK_LAN (0) +#endif +#endif + +#if MICROPY_PY_NETWORK_LAN && CONFIG_ETH_USE_SPI_ETHERNET +#ifndef MICROPY_PY_NETWORK_LAN_SPI_CLOCK_SPEED_MZ +#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C2 +#define MICROPY_PY_NETWORK_LAN_SPI_CLOCK_SPEED_MZ (12) +#else +#define MICROPY_PY_NETWORK_LAN_SPI_CLOCK_SPEED_MZ (36) +#endif +#endif +#endif diff --git a/ports/esp32/mphalport.h b/ports/esp32/mphalport.h index c838bd2284..672fa306f5 100644 --- a/ports/esp32/mphalport.h +++ b/ports/esp32/mphalport.h @@ -35,6 +35,8 @@ #include "freertos/FreeRTOS.h" #include "freertos/task.h" +#include "driver/spi_master.h" + #define MICROPY_PLATFORM_VERSION "IDF" IDF_VER // The core that the MicroPython task(s) are pinned to. @@ -42,7 +44,9 @@ // and avoid the Wifi/BLE timing problems on the same core. // Best effort here to remain backwards compatible in rare version edge cases... // See https://github.com/micropython/micropython/issues/5489 for history -#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0) +#if CONFIG_FREERTOS_UNICORE +#define MP_TASK_COREID (0) +#elif ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0) #define MP_TASK_COREID (1) #else #define MP_TASK_COREID (0) @@ -111,4 +115,6 @@ static inline void mp_hal_pin_write(mp_hal_pin_obj_t pin, int v) { gpio_set_level(pin, v); } +spi_host_device_t machine_hw_spi_get_host(mp_obj_t in); + #endif // INCLUDED_MPHALPORT_H diff --git a/ports/esp32/network_lan.c b/ports/esp32/network_lan.c index c57d7815d7..d4d630e345 100644 --- a/ports/esp32/network_lan.c +++ b/ports/esp32/network_lan.c @@ -33,13 +33,16 @@ #include "esp_idf_version.h" // LAN only for ESP32 (not ESP32S2) and only for ESP-IDF v4.1 and higher -#if (ESP_IDF_VERSION_MAJOR == 4) && (ESP_IDF_VERSION_MINOR >= 1) && (CONFIG_IDF_TARGET_ESP32) +#if MICROPY_PY_NETWORK_LAN #include "esp_eth.h" #include "esp_eth_mac.h" #include "esp_event.h" #include "esp_log.h" #include "esp_netif.h" +#if CONFIG_ETH_USE_SPI_ETHERNET +#include "driver/spi_master.h" +#endif #include "modnetwork.h" @@ -48,9 +51,11 @@ typedef struct _lan_if_obj_t { int if_id; // MUST BE FIRST to match wlan_if_obj_t bool initialized; bool active; - uint8_t mdc_pin; - uint8_t mdio_pin; + int8_t mdc_pin; + int8_t mdio_pin; int8_t phy_power_pin; + int8_t phy_cs_pin; + int8_t phy_int_pin; uint8_t phy_addr; uint8_t phy_type; esp_eth_phy_t *phy; @@ -97,14 +102,23 @@ STATIC mp_obj_t get_lan(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ar return MP_OBJ_FROM_PTR(&lan_obj); } - enum { ARG_id, ARG_mdc, ARG_mdio, ARG_power, ARG_phy_addr, ARG_phy_type }; + enum { ARG_id, ARG_mdc, ARG_mdio, ARG_power, ARG_phy_addr, ARG_phy_type, + ARG_spi, ARG_cs, ARG_int, ARG_ref_clk_mode, ARG_ref_clk }; static const mp_arg_t allowed_args[] = { { MP_QSTR_id, MP_ARG_OBJ, {.u_obj = mp_const_none} }, - { MP_QSTR_mdc, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_mdio, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_mdc, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_mdio, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, { MP_QSTR_power, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, { MP_QSTR_phy_addr, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT }, { MP_QSTR_phy_type, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_spi, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_cs, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_int, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + #if ESP_IDF_VERSION_MINOR >= 4 + // Dynamic ref_clk configuration available at v4.4 + { MP_QSTR_ref_clk_mode, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_ref_clk, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + #endif }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; @@ -116,36 +130,99 @@ STATIC mp_obj_t get_lan(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ar } } - self->mdc_pin = machine_pin_get_id(args[ARG_mdc].u_obj); - self->mdio_pin = machine_pin_get_id(args[ARG_mdio].u_obj); - self->phy_power_pin = args[ARG_power].u_obj == mp_const_none ? -1 : machine_pin_get_id(args[ARG_power].u_obj); + #define GET_PIN(XXX) args[XXX].u_obj == mp_const_none ? -1 : machine_pin_get_id(args[XXX].u_obj); + + self->mdc_pin = GET_PIN(ARG_mdc); + self->mdio_pin = GET_PIN(ARG_mdio); + self->phy_power_pin = GET_PIN(ARG_power); + self->phy_cs_pin = GET_PIN(ARG_cs); + self->phy_int_pin = GET_PIN(ARG_int); if (args[ARG_phy_addr].u_int < 0x00 || args[ARG_phy_addr].u_int > 0x1f) { mp_raise_ValueError(MP_ERROR_TEXT("invalid phy address")); } self->phy_addr = args[ARG_phy_addr].u_int; - if (args[ARG_phy_type].u_int != PHY_LAN8720 && + if (args[ARG_phy_type].u_int != PHY_LAN8710 && + args[ARG_phy_type].u_int != PHY_LAN8720 && args[ARG_phy_type].u_int != PHY_IP101 && args[ARG_phy_type].u_int != PHY_RTL8201 && #if ESP_IDF_VERSION_MINOR >= 3 // KSZ8041 is new in ESP-IDF v4.3 args[ARG_phy_type].u_int != PHY_KSZ8041 && #endif + #if ESP_IDF_VERSION_MINOR >= 4 // KSZ8081 is new in ESP-IDF v4.4 + args[ARG_phy_type].u_int != PHY_KSZ8081 && + #endif + #if CONFIG_ETH_USE_SPI_ETHERNET + #if CONFIG_ETH_SPI_ETHERNET_KSZ8851SNL + args[ARG_phy_type].u_int != PHY_KSZ8851SNL && + #endif + #if CONFIG_ETH_SPI_ETHERNET_DM9051 + args[ARG_phy_type].u_int != PHY_DM9051 && + #endif + #if CONFIG_ETH_SPI_ETHERNET_W5500 + args[ARG_phy_type].u_int != PHY_W5500 && + #endif + #endif args[ARG_phy_type].u_int != PHY_DP83848) { mp_raise_ValueError(MP_ERROR_TEXT("invalid phy type")); } eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG(); - mac_config.smi_mdc_gpio_num = self->mdc_pin; - mac_config.smi_mdio_gpio_num = self->mdio_pin; - esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&mac_config); + esp_eth_mac_t *mac = NULL; + + // Dynamic ref_clk configuration available at v4.4 + #if ESP_IDF_VERSION_MINOR >= 4 + if (args[ARG_ref_clk_mode].u_int != -1) { + // Map the GPIO_MODE constants to EMAC_CLK constants. + mac_config.clock_config.rmii.clock_mode = + args[ARG_ref_clk_mode].u_int == GPIO_MODE_INPUT ? EMAC_CLK_EXT_IN : EMAC_CLK_OUT; + } + if (args[ARG_ref_clk].u_obj != mp_const_none) { + mac_config.clock_config.rmii.clock_gpio = machine_pin_get_id(args[ARG_ref_clk].u_obj); + } + #endif eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG(); phy_config.phy_addr = self->phy_addr; phy_config.reset_gpio_num = self->phy_power_pin; self->phy = NULL; + #if CONFIG_ETH_USE_SPI_ETHERNET + spi_device_handle_t spi_handle = NULL; + if (IS_SPI_PHY(args[ARG_phy_type].u_int)) { + spi_device_interface_config_t devcfg = { + .mode = 0, + .clock_speed_hz = MICROPY_PY_NETWORK_LAN_SPI_CLOCK_SPEED_MZ * 1000 * 1000, + .queue_size = 20, + .spics_io_num = self->phy_cs_pin, + }; + switch (args[ARG_phy_type].u_int) { + #if CONFIG_ETH_SPI_ETHERNET_DM9051 + case PHY_DM9051: { + devcfg.command_bits = 1; + devcfg.address_bits = 7; + break; + } + #endif + #if CONFIG_ETH_SPI_ETHERNET_W5500 + case PHY_W5500: { + devcfg.command_bits = 16; + devcfg.address_bits = 8; + break; + } + #endif + } + spi_host_device_t host = machine_hw_spi_get_host(args[ARG_spi].u_obj); + if (spi_bus_add_device(host, &devcfg, &spi_handle) != ESP_OK) { + mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("spi_bus_add_device failed")); + } + } + #endif + switch (args[ARG_phy_type].u_int) { + #if CONFIG_IDF_TARGET_ESP32 + case PHY_LAN8710: case PHY_LAN8720: self->phy = esp_eth_phy_new_lan8720(&phy_config); break; @@ -158,15 +235,59 @@ STATIC mp_obj_t get_lan(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ar case PHY_DP83848: self->phy = esp_eth_phy_new_dp83848(&phy_config); break; + #if ESP_IDF_VERSION_MINOR >= 3 // KSZ8041 is new in ESP-IDF v4.3 case PHY_KSZ8041: - #if ESP_IDF_VERSION_MINOR >= 3 // KSZ8041 is new in ESP-IDF v4.3 self->phy = esp_eth_phy_new_ksz8041(&phy_config); break; - #endif - default: - mp_raise_ValueError(MP_ERROR_TEXT("unknown phy")); + #endif + #if ESP_IDF_VERSION_MINOR >= 4 // KSZ8081 is new in ESP-IDF v4.4 + case PHY_KSZ8081: + self->phy = esp_eth_phy_new_ksz8081(&phy_config); + break; + #endif + #endif + #if CONFIG_ETH_USE_SPI_ETHERNET + #if CONFIG_ETH_SPI_ETHERNET_KSZ8851SNL + case PHY_KSZ8851SNL: { + eth_ksz8851snl_config_t chip_config = ETH_KSZ8851SNL_DEFAULT_CONFIG(spi_handle); + chip_config.int_gpio_num = self->phy_int_pin; + mac = esp_eth_mac_new_ksz8851snl(&chip_config, &mac_config); + self->phy = esp_eth_phy_new_ksz8851snl(&phy_config); + break; + } + #endif + #if CONFIG_ETH_SPI_ETHERNET_DM9051 + case PHY_DM9051: { + eth_dm9051_config_t chip_config = ETH_DM9051_DEFAULT_CONFIG(spi_handle); + chip_config.int_gpio_num = self->phy_int_pin; + mac = esp_eth_mac_new_dm9051(&chip_config, &mac_config); + self->phy = esp_eth_phy_new_dm9051(&phy_config); + break; + } + #endif + #if CONFIG_ETH_SPI_ETHERNET_W5500 + case PHY_W5500: { + eth_w5500_config_t chip_config = ETH_W5500_DEFAULT_CONFIG(spi_handle); + chip_config.int_gpio_num = self->phy_int_pin; + mac = esp_eth_mac_new_w5500(&chip_config, &mac_config); + self->phy = esp_eth_phy_new_w5500(&phy_config); + break; + } + #endif + #endif } + #if CONFIG_IDF_TARGET_ESP32 + if (!IS_SPI_PHY(args[ARG_phy_type].u_int)) { + if (self->mdc_pin == -1 || self->mdio_pin == -1) { + mp_raise_ValueError(MP_ERROR_TEXT("mdc and mdio must be specified")); + } + mac_config.smi_mdc_gpio_num = self->mdc_pin; + mac_config.smi_mdio_gpio_num = self->mdio_pin; + mac = esp_eth_mac_new_esp32(&mac_config); + } + #endif + if (esp_netif_init() != ESP_OK) { mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("esp_netif_init failed")); } @@ -261,7 +382,12 @@ STATIC mp_obj_t lan_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs if (bufinfo.len != 6) { mp_raise_ValueError(MP_ERROR_TEXT("invalid buffer length")); } - esp_eth_ioctl(self->eth_handle, ETH_CMD_S_MAC_ADDR, bufinfo.buf); + if ( + (esp_eth_ioctl(self->eth_handle, ETH_CMD_S_MAC_ADDR, bufinfo.buf) != ESP_OK) || + (esp_netif_set_mac(self->eth_netif, bufinfo.buf) != ESP_OK) + ) { + mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("failed setting MAC address")); + } break; } default: diff --git a/ports/esp32/network_wlan.c b/ports/esp32/network_wlan.c index f0b458e6dd..e4b34b2204 100644 --- a/ports/esp32/network_wlan.c +++ b/ports/esp32/network_wlan.c @@ -35,6 +35,7 @@ #include "py/objlist.h" #include "py/runtime.h" +#include "py/mphal.h" #include "modnetwork.h" #include "esp_wifi.h" @@ -210,6 +211,12 @@ STATIC mp_obj_t network_wlan_active(size_t n_args, const mp_obj_t *args) { wifi_started = true; } } + // This delay is a band-aid patch for issues #8289, #8792 and #9236, + // allowing the esp data structures to settle. It looks like some + // kind of race condition, which is not yet found. But at least + // this small delay seems not hurt much, since wlan.active() is + // usually not called in a time critical part of the code. + mp_hal_delay_ms(1); } return (mode & bit) ? mp_const_true : mp_const_false; diff --git a/ports/esp8266/README.md b/ports/esp8266/README.md index b54d8958d7..1e0cae2139 100644 --- a/ports/esp8266/README.md +++ b/ports/esp8266/README.md @@ -1,10 +1,9 @@ MicroPython port to ESP8266 =========================== -This is an experimental port of MicroPython for the WiFi modules based -on Espressif ESP8266 chip. - -WARNING: The port is experimental and many APIs are subject to change. +This is a port of MicroPython to the Espressif ESP8266 WiFi microcontroller. +MicroPython runs on this chip without any underlying operating system, using +the ESP8266 NONOS SDK. Supported features include: - REPL (Python prompt) over UART0. diff --git a/ports/esp8266/modnetwork.c b/ports/esp8266/modnetwork.c index ec62528a08..29bdd3a1b7 100644 --- a/ports/esp8266/modnetwork.c +++ b/ports/esp8266/modnetwork.c @@ -410,6 +410,11 @@ STATIC mp_obj_t esp_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs wifi_set_phy_mode(mp_obj_get_int(kwargs->table[i].value)); break; } + case MP_QSTR_txpower: { + int8_t power = mp_obj_get_float(kwargs->table[i].value) * 4; + system_phy_set_max_tpw(power); + break; + } default: goto unknown; } diff --git a/ports/mimxrt/Makefile b/ports/mimxrt/Makefile index e08f2ad602..18e91639ef 100644 --- a/ports/mimxrt/Makefile +++ b/ports/mimxrt/Makefile @@ -262,7 +262,7 @@ SRC_SS = \ $(MCU_DIR)/gcc/startup_$(MCU_SERIES)$(MCU_CORE).S \ hal/resethandler_MIMXRT10xx.S -SRC_S += shared/runtime/gchelper_m3.s \ +SRC_S += shared/runtime/gchelper_thumb2.s \ # ============================================================================= # QSTR Sources diff --git a/ports/mimxrt/mpconfigport.h b/ports/mimxrt/mpconfigport.h index 911fd41b46..224714b071 100644 --- a/ports/mimxrt/mpconfigport.h +++ b/ports/mimxrt/mpconfigport.h @@ -37,7 +37,11 @@ uint32_t trng_random_u32(void); #define MICROPY_CONFIG_ROM_LEVEL (MICROPY_CONFIG_ROM_LEVEL_FULL_FEATURES) // Memory allocation policies +#if MICROPY_HW_SDRAM_AVAIL +#define MICROPY_GC_STACK_ENTRY_TYPE uint32_t +#else #define MICROPY_GC_STACK_ENTRY_TYPE uint16_t +#endif #define MICROPY_ALLOC_PARSE_CHUNK_INIT (32) #define MICROPY_ALLOC_PATH_MAX (256) diff --git a/ports/nrf/mpconfigport.h b/ports/nrf/mpconfigport.h index 27dbd3b584..629ba5e946 100644 --- a/ports/nrf/mpconfigport.h +++ b/ports/nrf/mpconfigport.h @@ -277,6 +277,11 @@ typedef int mp_int_t; // must be pointer size typedef unsigned int mp_uint_t; // must be pointer size typedef long mp_off_t; +#if MICROPY_HW_ENABLE_RNG +#define MICROPY_PY_URANDOM_SEED_INIT_FUNC (rng_generate_random_word()) +long unsigned int rng_generate_random_word(void); +#endif + #if BOARD_SPECIFIC_MODULES #include "boardmodules.h" #endif // BOARD_SPECIFIC_MODULES diff --git a/ports/qemu-arm/Makefile b/ports/qemu-arm/Makefile index 7ae7955cf4..40b3062ae4 100644 --- a/ports/qemu-arm/Makefile +++ b/ports/qemu-arm/Makefile @@ -17,7 +17,7 @@ ifeq ($(BOARD),netduino2) CFLAGS += -mthumb -mcpu=cortex-m3 -mfloat-abi=soft CFLAGS += -DQEMU_SOC_STM32 LDSCRIPT = stm32.ld -SRC_BOARD_O = shared/runtime/gchelper_native.o shared/runtime/gchelper_m3.o +SRC_BOARD_O = shared/runtime/gchelper_native.o shared/runtime/gchelper_thumb2.o MPY_CROSS_FLAGS += -march=armv7m endif @@ -26,7 +26,7 @@ CFLAGS += -mthumb -mcpu=cortex-m0 -mfloat-abi=soft CFLAGS += -DQEMU_SOC_NRF51 LDSCRIPT = nrf51.ld QEMU_EXTRA = -global nrf51-soc.flash-size=1048576 -global nrf51-soc.sram-size=262144 -SRC_BOARD_O = shared/runtime/gchelper_native.o shared/runtime/gchelper_m0.o +SRC_BOARD_O = shared/runtime/gchelper_native.o shared/runtime/gchelper_thumb1.o MPY_CROSS_FLAGS += -march=armv7m endif @@ -34,7 +34,7 @@ ifeq ($(BOARD),mps2-an385) CFLAGS += -mthumb -mcpu=cortex-m3 -mfloat-abi=soft CFLAGS += -DQEMU_SOC_MPS2 LDSCRIPT = mps2.ld -SRC_BOARD_O = shared/runtime/gchelper_native.o shared/runtime/gchelper_m3.o +SRC_BOARD_O = shared/runtime/gchelper_native.o shared/runtime/gchelper_thumb2.o MPY_CROSS_FLAGS += -march=armv7m endif diff --git a/ports/renesas-ra/Makefile b/ports/renesas-ra/Makefile index b02379b472..17ec58ae0b 100644 --- a/ports/renesas-ra/Makefile +++ b/ports/renesas-ra/Makefile @@ -335,7 +335,7 @@ SRC_O += \ $(SYSTEM_FILE) SRC_O += \ - shared/runtime/gchelper_m3.o + shared/runtime/gchelper_thumb2.o HAL_SRC_C += $(addprefix $(HAL_DIR)/ra/board/$(BOARD_LOW)/,\ board_init.c \ diff --git a/ports/rp2/CMakeLists.txt b/ports/rp2/CMakeLists.txt index 15264bf8ad..357125e734 100644 --- a/ports/rp2/CMakeLists.txt +++ b/ports/rp2/CMakeLists.txt @@ -87,7 +87,7 @@ set(MICROPY_SOURCE_LIB ${MICROPY_DIR}/shared/netutils/netutils.c ${MICROPY_DIR}/shared/netutils/trace.c ${MICROPY_DIR}/shared/readline/readline.c - ${MICROPY_DIR}/shared/runtime/gchelper_m0.s + ${MICROPY_DIR}/shared/runtime/gchelper_thumb1.s ${MICROPY_DIR}/shared/runtime/gchelper_native.c ${MICROPY_DIR}/shared/runtime/interrupt_char.c ${MICROPY_DIR}/shared/runtime/mpirq.c @@ -131,6 +131,7 @@ set(MICROPY_SOURCE_PORT usbd.c msc_disk.c mbedtls/mbedtls_port.c + ${CMAKE_BINARY_DIR}/pins_${MICROPY_BOARD}.c ) set(MICROPY_SOURCE_QSTR @@ -153,6 +154,7 @@ set(MICROPY_SOURCE_QSTR ${PROJECT_SOURCE_DIR}/modutime.c ${PROJECT_SOURCE_DIR}/rp2_flash.c ${PROJECT_SOURCE_DIR}/rp2_pio.c + ${CMAKE_BINARY_DIR}/pins_${MICROPY_BOARD}.c ) set(PICO_SDK_COMPONENTS @@ -257,6 +259,10 @@ if (MICROPY_PY_NETWORK_CYW43) ) endif() + list(APPEND MICROPY_SOURCE_PORT + machine_pin_cyw43.c + ) + list(APPEND MICROPY_SOURCE_EXTMOD ${MICROPY_DIR}/extmod/network_cyw43.c ) @@ -281,6 +287,7 @@ if (MICROPY_PY_NETWORK_NINAW10) ${MICROPY_DIR}/drivers/ninaw10/nina_bt_hci.c ${MICROPY_DIR}/drivers/ninaw10/nina_wifi_drv.c ${MICROPY_DIR}/drivers/ninaw10/nina_wifi_bsp.c + ${MICROPY_DIR}/drivers/ninaw10/machine_pin_nina.c ) list(APPEND MICROPY_SOURCE_EXTMOD @@ -435,3 +442,37 @@ endforeach() # Include the main MicroPython cmake rules. include(${MICROPY_DIR}/py/mkrules.cmake) + +set(MICROPY_BOARDS_DIR "${MICROPY_PORT_DIR}/boards") +set(GEN_PINS_AF_CSV "${MICROPY_BOARDS_DIR}/rp2_af.csv") +set(GEN_PINS_PREFIX "${MICROPY_BOARDS_DIR}/rp2_prefix.c") +set(GEN_PINS_MKPINS "${MICROPY_BOARDS_DIR}/make-pins.py") +set(GEN_PINS_SRC "${CMAKE_BINARY_DIR}/pins_${MICROPY_BOARD}.c") +set(GEN_PINS_HDR "${MICROPY_GENHDR_DIR}/pins.h") +set(GEN_PINS_QSTR "${CMAKE_BINARY_DIR}/pins_qstr.h") +set(GEN_PINS_AF_CONST "${MICROPY_GENHDR_DIR}/pins_af_const.h") +set(GEN_PINS_AF_PY "${CMAKE_BINARY_DIR}/pins_af.py") + +if(EXISTS "${MICROPY_BOARDS_DIR}/${MICROPY_BOARD}/pins.csv") + set(GEN_PINS_BOARD_CSV "${MICROPY_BOARDS_DIR}/${MICROPY_BOARD}/pins.csv") + set(GEN_PINS_CSV_ARG --board "${GEN_PINS_BOARD_CSV}") +endif() + +target_sources(${MICROPY_TARGET} PRIVATE + ${GEN_PINS_HDR} +) + +# Generate pins +add_custom_command( + OUTPUT ${GEN_PINS_HDR} ${GEN_PINS_SRC} ${GEN_PINS_QSTR} + COMMAND ${Python3_EXECUTABLE} ${GEN_PINS_MKPINS} ${GEN_PINS_CSV_ARG} --af ${GEN_PINS_AF_CSV} --prefix ${GEN_PINS_PREFIX} + --hdr ${GEN_PINS_HDR} --qstr ${GEN_PINS_QSTR} --af-const ${GEN_PINS_AF_CONST} --af-py ${GEN_PINS_AF_PY} > ${GEN_PINS_SRC} + DEPENDS + ${GEN_PINS_AF_CSV} + ${GEN_PINS_BOARD_CSV} + ${GEN_PINS_MKPINS} + ${GEN_PINS_PREFIX} + ${MICROPY_MPVERSION} + VERBATIM + COMMAND_EXPAND_LISTS +) diff --git a/ports/rp2/boards/ADAFRUIT_FEATHER_RP2040/pins.csv b/ports/rp2/boards/ADAFRUIT_FEATHER_RP2040/pins.csv new file mode 100644 index 0000000000..ee6fd99fee --- /dev/null +++ b/ports/rp2/boards/ADAFRUIT_FEATHER_RP2040/pins.csv @@ -0,0 +1 @@ +LED,GPIO13 diff --git a/ports/rp2/boards/ADAFRUIT_ITSYBITSY_RP2040/pins.csv b/ports/rp2/boards/ADAFRUIT_ITSYBITSY_RP2040/pins.csv new file mode 100644 index 0000000000..1b7e7c3c73 --- /dev/null +++ b/ports/rp2/boards/ADAFRUIT_ITSYBITSY_RP2040/pins.csv @@ -0,0 +1 @@ +LED,GPIO11 diff --git a/ports/rp2/boards/ARDUINO_NANO_RP2040_CONNECT/mpconfigboard.h b/ports/rp2/boards/ARDUINO_NANO_RP2040_CONNECT/mpconfigboard.h index 1818b56a68..6498cbf560 100644 --- a/ports/rp2/boards/ARDUINO_NANO_RP2040_CONNECT/mpconfigboard.h +++ b/ports/rp2/boards/ARDUINO_NANO_RP2040_CONNECT/mpconfigboard.h @@ -13,6 +13,9 @@ // Disable internal error numbers. #define MICROPY_USE_INTERNAL_ERRNO (0) +// Enable externally controlled pins. +#define MICROPY_HW_PIN_EXT_COUNT (5) + // Enable USB Mass Storage with FatFS filesystem. #define MICROPY_HW_USB_MSC (1) #define MICROPY_HW_USB_VID (0x2341) diff --git a/ports/rp2/boards/ARDUINO_NANO_RP2040_CONNECT/pins.csv b/ports/rp2/boards/ARDUINO_NANO_RP2040_CONNECT/pins.csv new file mode 100644 index 0000000000..b398c8ec94 --- /dev/null +++ b/ports/rp2/boards/ARDUINO_NANO_RP2040_CONNECT/pins.csv @@ -0,0 +1,26 @@ +TX,GPIO0 +RX,GPIO1 +D2,GPIO25 +D3,GPIO15 +D4,GPIO16 +D5,GPIO17 +D6,GPIO18 +D7,GPIO19 +D8,GPIO20 +D9,GPIO21 +D10,GPIO5 +D11,GPIO7 +D12,GPIO4 +D13,GPIO6 +LED,GPIO6 +A0,GPIO26 +A1,GPIO27 +A2,GPIO28 +A3,GPIO29 +A4,GPIO12 +A5,GPIO13 +LEDR,EXT_GPIO0 +LEDG,EXT_GPIO1 +LEDB,EXT_GPIO2 +A6,EXT_GPIO3 +A7,EXT_GPIO4 diff --git a/ports/rp2/boards/GARATRONIC_PYBSTICK26_RP2040/pins.csv b/ports/rp2/boards/GARATRONIC_PYBSTICK26_RP2040/pins.csv new file mode 100644 index 0000000000..6b3bedc0e1 --- /dev/null +++ b/ports/rp2/boards/GARATRONIC_PYBSTICK26_RP2040/pins.csv @@ -0,0 +1 @@ +LED,GPIO23 diff --git a/ports/rp2/boards/NULLBITS_BIT_C_PRO/README.md b/ports/rp2/boards/NULLBITS_BIT_C_PRO/README.md new file mode 100644 index 0000000000..0849108413 --- /dev/null +++ b/ports/rp2/boards/NULLBITS_BIT_C_PRO/README.md @@ -0,0 +1,17 @@ +# nullbits Bit-C PRO + +The nullbits Bit-C PRO Board is based on the Raspberry Pi RP2040, and comes in the Arduino Pro Micro footprint. + + +## Board-specific modules + +The `board` module contains definitions for the onboard RGB LED. + +Example: + +```python +>>> import board +>>> board.led_red.on() +>>> board.led_green.on() +>>> board.led_blue.on() +``` diff --git a/ports/rp2/boards/NULLBITS_BIT_C_PRO/board.json b/ports/rp2/boards/NULLBITS_BIT_C_PRO/board.json new file mode 100644 index 0000000000..2aff0580d8 --- /dev/null +++ b/ports/rp2/boards/NULLBITS_BIT_C_PRO/board.json @@ -0,0 +1,20 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [ + "Breadboard Friendly", + "RGB LED", + "USB-C", + "SPI Flash" + ], + "images": [ + "nullbits_bit_c_pro.jpg" + ], + "mcu": "rp2040", + "product": "Bit-C PRO", + "thumbnail": "", + "url": "https://nullbits.co/bit-c-pro", + "vendor": "nullbits" +} diff --git a/ports/rp2/boards/NULLBITS_BIT_C_PRO/board.py b/ports/rp2/boards/NULLBITS_BIT_C_PRO/board.py new file mode 100644 index 0000000000..9ee8cc806f --- /dev/null +++ b/ports/rp2/boards/NULLBITS_BIT_C_PRO/board.py @@ -0,0 +1,7 @@ +from machine import Pin, Signal + +led_red = Signal("LED_RED", Pin.OUT, invert=True, value=0) +led_green = Signal("LED_GREEN", Pin.OUT, invert=True, value=0) +led_blue = Signal("LED_BLUE", Pin.OUT, invert=True, value=0) + +del Pin diff --git a/ports/rp2/boards/NULLBITS_BIT_C_PRO/manifest.py b/ports/rp2/boards/NULLBITS_BIT_C_PRO/manifest.py new file mode 100644 index 0000000000..3a6af47a16 --- /dev/null +++ b/ports/rp2/boards/NULLBITS_BIT_C_PRO/manifest.py @@ -0,0 +1,2 @@ +include("$(PORT_DIR)/boards/manifest.py") +module("board.py") diff --git a/ports/rp2/boards/NULLBITS_BIT_C_PRO/mpconfigboard.cmake b/ports/rp2/boards/NULLBITS_BIT_C_PRO/mpconfigboard.cmake new file mode 100644 index 0000000000..050ca347be --- /dev/null +++ b/ports/rp2/boards/NULLBITS_BIT_C_PRO/mpconfigboard.cmake @@ -0,0 +1,10 @@ +# cmake file for nullbits Bit-C PRO + +# The Bit-C PRO is not yet in upstream pico-sdk, so define it here +# See also: https://github.com/raspberrypi/pico-sdk/tree/master/src/boards/include/boards +list(APPEND PICO_BOARD_HEADER_DIRS ${MICROPY_BOARD_DIR}) + +set(PICO_BOARD "nullbits_bit_c_pro") + +# Freeze board.py +set(MICROPY_FROZEN_MANIFEST ${MICROPY_BOARD_DIR}/manifest.py) diff --git a/ports/rp2/boards/NULLBITS_BIT_C_PRO/mpconfigboard.h b/ports/rp2/boards/NULLBITS_BIT_C_PRO/mpconfigboard.h new file mode 100644 index 0000000000..e28c379fa7 --- /dev/null +++ b/ports/rp2/boards/NULLBITS_BIT_C_PRO/mpconfigboard.h @@ -0,0 +1,9 @@ +// https://nullbits.co/bit-c-pro + +#define MICROPY_HW_BOARD_NAME "nullbits Bit-C PRO" +#define MICROPY_HW_FLASH_STORAGE_BYTES (PICO_FLASH_SIZE_BYTES - (1 * 512 * 1024)) // 512K reserved + +// RGB LED, active low +// Red LED 16 +// Green LED 17 +// Blue LED 18 diff --git a/ports/rp2/boards/NULLBITS_BIT_C_PRO/nullbits_bit_c_pro.h b/ports/rp2/boards/NULLBITS_BIT_C_PRO/nullbits_bit_c_pro.h new file mode 100644 index 0000000000..2e8b03a430 --- /dev/null +++ b/ports/rp2/boards/NULLBITS_BIT_C_PRO/nullbits_bit_c_pro.h @@ -0,0 +1,96 @@ +// Board definition for the nullbits Bit-C PRO + +#ifndef _BOARDS_NULLBITS_BIT_C_PRO_H +#define _BOARDS_NULLBITS_BIT_C_PRO_H + +// For board detection +#define NULLBITS_BIT_C_PRO + +// On some samples, the xosc can take longer to stabilize than is usual +#ifndef PICO_XOSC_STARTUP_DELAY_MULTIPLIER +#define PICO_XOSC_STARTUP_DELAY_MULTIPLIER 64 +#endif + +// --- BOARD SPECIFIC --- +#define BIT_C_PRO_LED_R_PIN 16 +#define BIT_C_PRO_LED_G_PIN 17 +#define BIT_C_PRO_LED_B_PIN 18 + +// ------------- UART -------------// +#ifndef PICO_DEFAULT_UART +#define PICO_DEFAULT_UART 0 +#endif + +#ifndef PICO_DEFAULT_UART_TX_PIN +#define PICO_DEFAULT_UART_TX_PIN 0 +#endif + +#ifndef PICO_DEFAULT_UART_RX_PIN +#define PICO_DEFAULT_UART_RX_PIN 1 +#endif + +// --- LED --- +// Set the default LED to the Bit-C PRO's B led +#ifndef PICO_DEFAULT_LED_PIN +#define PICO_DEFAULT_LED_PIN BIT_C_PRO_LED_B_PIN +#endif + +#ifndef PICO_DEFAULT_LED_PIN_INVERTED +#define PICO_DEFAULT_LED_PIN_INVERTED 1 +#endif +// no PICO_DEFAULT_WS2812_PIN + +// ------------- I2C -------------// +#ifndef PICO_DEFAULT_I2C +#define PICO_DEFAULT_I2C 0 +#endif + +#ifndef PICO_DEFAULT_I2C_SDA_PIN +#define PICO_DEFAULT_I2C_SDA_PIN 2 +#endif + +#ifndef PICO_DEFAULT_I2C_SCL_PIN +#define PICO_DEFAULT_I2C_SCL_PIN 3 +#endif + +// ------------- SPI -------------// +#ifndef PICO_DEFAULT_SPI +#define PICO_DEFAULT_SPI 0 +#endif + +#ifndef PICO_DEFAULT_SPI_TX_PIN +#define PICO_DEFAULT_SPI_TX_PIN 23 +#endif + +#ifndef PICO_DEFAULT_SPI_RX_PIN +#define PICO_DEFAULT_SPI_RX_PIN 20 +#endif + +#ifndef PICO_DEFAULT_SPI_SCK_PIN +#define PICO_DEFAULT_SPI_SCK_PIN 22 +#endif + +#ifndef PICO_DEFAULT_SPI_CSN_PIN +#define PICO_DEFAULT_SPI_CSN_PIN 21 +#endif + +// ------------- FLASH -------------// + +// Best performance/compatibility with selected flash +#define PICO_BOOT_STAGE2_CHOOSE_W25X10CL 1 + +#ifndef PICO_FLASH_SPI_CLKDIV +#define PICO_FLASH_SPI_CLKDIV 2 +#endif + +// Bit-C PRO has 4MB SPI flash +#ifndef PICO_FLASH_SIZE_BYTES +#define PICO_FLASH_SIZE_BYTES (4 * 1024 * 1024) +#endif + +// All boards have B1+ RP2040 +#ifndef PICO_RP2040_B0_SUPPORTED +#define PICO_RP2040_B0_SUPPORTED 0 +#endif + +#endif diff --git a/ports/rp2/boards/NULLBITS_BIT_C_PRO/pins.csv b/ports/rp2/boards/NULLBITS_BIT_C_PRO/pins.csv new file mode 100644 index 0000000000..1274effaef --- /dev/null +++ b/ports/rp2/boards/NULLBITS_BIT_C_PRO/pins.csv @@ -0,0 +1,4 @@ +LED,GPIO16 +LED_RED,GPIO16 +LED_GREEN,GPIO17 +LED_BLUE,GPIO18 diff --git a/ports/rp2/boards/PICO/pins.csv b/ports/rp2/boards/PICO/pins.csv new file mode 100644 index 0000000000..16e3340264 --- /dev/null +++ b/ports/rp2/boards/PICO/pins.csv @@ -0,0 +1,28 @@ +GP0,GPIO0 +GP1,GPIO1 +GP2,GPIO2 +GP3,GPIO3 +GP4,GPIO4 +GP5,GPIO5 +GP6,GPIO6 +GP7,GPIO7 +GP8,GPIO8 +GP9,GPIO9 +GP10,GPIO10 +GP11,GPIO11 +GP12,GPIO12 +GP13,GPIO13 +GP14,GPIO14 +GP15,GPIO15 +GP16,GPIO16 +GP17,GPIO17 +GP18,GPIO18 +GP19,GPIO19 +GP20,GPIO20 +GP21,GPIO21 +GP22,GPIO22 +GP25,GPIO25 +GP26,GPIO26 +GP27,GPIO27 +GP28,GPIO28 +LED,GPIO25 diff --git a/ports/rp2/boards/PICO_W/mpconfigboard.h b/ports/rp2/boards/PICO_W/mpconfigboard.h index 43a9fbafa7..227e7e3ff4 100644 --- a/ports/rp2/boards/PICO_W/mpconfigboard.h +++ b/ports/rp2/boards/PICO_W/mpconfigboard.h @@ -17,9 +17,6 @@ // Debug level (0-4) 1=warning, 2=info, 3=debug, 4=verbose // #define MODUSSL_MBEDTLS_DEBUG_LEVEL 1 -#define MICROPY_HW_PIN_CYW43_COUNT CYW43_WL_GPIO_COUNT -#ifdef CYW43_WL_GPIO_LED_PIN -#define MICROPY_HW_PIN_CYW43_LED_PIN_NUM CYW43_WL_GPIO_LED_PIN -#endif +#define MICROPY_HW_PIN_EXT_COUNT CYW43_WL_GPIO_COUNT #define MICROPY_HW_PIN_RESERVED(i) ((i) == CYW43_PIN_WL_HOST_WAKE || (i) == CYW43_PIN_WL_REG_ON) diff --git a/ports/rp2/boards/PICO_W/pins.csv b/ports/rp2/boards/PICO_W/pins.csv new file mode 100644 index 0000000000..8debb6326e --- /dev/null +++ b/ports/rp2/boards/PICO_W/pins.csv @@ -0,0 +1,30 @@ +GP0,GPIO0 +GP1,GPIO1 +GP2,GPIO2 +GP3,GPIO3 +GP4,GPIO4 +GP5,GPIO5 +GP6,GPIO6 +GP7,GPIO7 +GP8,GPIO8 +GP9,GPIO9 +GP10,GPIO10 +GP11,GPIO11 +GP12,GPIO12 +GP13,GPIO13 +GP14,GPIO14 +GP15,GPIO15 +GP16,GPIO16 +GP17,GPIO17 +GP18,GPIO18 +GP19,GPIO19 +GP20,GPIO20 +GP21,GPIO21 +GP22,GPIO22 +GP26,GPIO26 +GP27,GPIO27 +GP28,GPIO28 +WL_GPIO0,EXT_GPIO0 +WL_GPIO1,EXT_GPIO1 +WL_GPIO2,EXT_GPIO2 +LED,EXT_GPIO0 diff --git a/ports/rp2/boards/PIMORONI_PICOLIPO_16MB/pins.csv b/ports/rp2/boards/PIMORONI_PICOLIPO_16MB/pins.csv new file mode 100644 index 0000000000..e75354485d --- /dev/null +++ b/ports/rp2/boards/PIMORONI_PICOLIPO_16MB/pins.csv @@ -0,0 +1 @@ +LED,GPIO25 diff --git a/ports/rp2/boards/PIMORONI_PICOLIPO_4MB/pins.csv b/ports/rp2/boards/PIMORONI_PICOLIPO_4MB/pins.csv new file mode 100644 index 0000000000..e75354485d --- /dev/null +++ b/ports/rp2/boards/PIMORONI_PICOLIPO_4MB/pins.csv @@ -0,0 +1 @@ +LED,GPIO25 diff --git a/ports/rp2/boards/PIMORONI_TINY2040/pins.csv b/ports/rp2/boards/PIMORONI_TINY2040/pins.csv new file mode 100644 index 0000000000..e4add1b0be --- /dev/null +++ b/ports/rp2/boards/PIMORONI_TINY2040/pins.csv @@ -0,0 +1 @@ +LED,GPIO19 diff --git a/ports/rp2/boards/SPARKFUN_THINGPLUS/pins.csv b/ports/rp2/boards/SPARKFUN_THINGPLUS/pins.csv new file mode 100644 index 0000000000..e75354485d --- /dev/null +++ b/ports/rp2/boards/SPARKFUN_THINGPLUS/pins.csv @@ -0,0 +1 @@ +LED,GPIO25 diff --git a/ports/rp2/boards/W5100S_EVB_PICO/pins.csv b/ports/rp2/boards/W5100S_EVB_PICO/pins.csv new file mode 100644 index 0000000000..e75354485d --- /dev/null +++ b/ports/rp2/boards/W5100S_EVB_PICO/pins.csv @@ -0,0 +1 @@ +LED,GPIO25 diff --git a/ports/rp2/boards/W5500_EVB_PICO/pins.csv b/ports/rp2/boards/W5500_EVB_PICO/pins.csv new file mode 100644 index 0000000000..e75354485d --- /dev/null +++ b/ports/rp2/boards/W5500_EVB_PICO/pins.csv @@ -0,0 +1 @@ +LED,GPIO25 diff --git a/ports/rp2/boards/WEACTSTUDIO/pins.csv b/ports/rp2/boards/WEACTSTUDIO/pins.csv new file mode 100644 index 0000000000..e75354485d --- /dev/null +++ b/ports/rp2/boards/WEACTSTUDIO/pins.csv @@ -0,0 +1 @@ +LED,GPIO25 diff --git a/ports/rp2/boards/make-pins.py b/ports/rp2/boards/make-pins.py new file mode 100755 index 0000000000..55e7ebe01f --- /dev/null +++ b/ports/rp2/boards/make-pins.py @@ -0,0 +1,428 @@ +#!/usr/bin/env python +"""Creates the pin file for the RP2.""" + +from __future__ import print_function + +import argparse +import sys +import csv +import re + +SUPPORTED_FN = { + "SPI": ["TX", "RX", "SCK", "CS"], + "UART": ["TX", "RX", "CTS", "RTS"], + "I2C": ["SCL", "SDA"], + "PWM": ["A", "B"], + "SIO": [""], + "PIO0": [""], + "PIO1": [""], + "GPCK": ["GPIN0", "GPOUT0", "GPIN1", "GPOUT1", "GPOUT2", "GPOUT3"], + "USB": ["OVCUR_DET", "VBUS_DET", "VBUS_EN"], +} + + +def parse_pin(name_str): + """Parses a string and returns a pin number.""" + if len(name_str) < 2: + raise ValueError("Expecting pin name to be at least 2 charcters.") + if not name_str.startswith("GPIO") and not name_str.startswith("EXT_GPIO"): + raise ValueError("Expecting pin name to start with EXT_/GPIO") + return int(re.findall(r"\d+$", name_str)[0]) + + +def split_name_num(name_num): + num = None + for num_idx in range(len(name_num) - 1, -1, -1): + if not name_num[num_idx].isdigit(): + name = name_num[0 : num_idx + 1] + num_str = name_num[num_idx + 1 :] + if len(num_str) > 0: + num = int(num_str) + break + if name == "PIO": + name += str(num) + return name, num + + +class AlternateFunction(object): + """Holds the information associated with a pins alternate function.""" + + def __init__(self, idx, af_str): + self.idx = idx + self.af_str = af_str + + self.func = "" + self.fn_num = None + self.pin_type = "" + self.supported = False + + af_words = af_str.split("_", 1) + self.func, self.fn_num = split_name_num(af_words[0]) + if len(af_words) > 1: + self.pin_type = af_words[1] + if self.func in SUPPORTED_FN: + pin_types = SUPPORTED_FN[self.func] + if self.pin_type in pin_types: + self.supported = True + + def is_supported(self): + return self.supported + + def ptr(self): + """Returns the numbered function (i.e. USART6) for this AF.""" + if self.fn_num is None: + return self.func + return "{:s}{:d}".format(self.func, self.fn_num) + + def mux_name(self): + return "AF{:d}_{:s}".format(self.idx, self.ptr()) + + def print(self): + """Prints the C representation of this AF.""" + if self.supported: + print(" AF", end="") + else: + print(" //", end="") + fn_num = self.fn_num + if fn_num is None: + fn_num = 0 + print("({:d}, {:4s}, {:d}), // {:s}".format(self.idx, self.func, fn_num, self.af_str)) + + def qstr_list(self): + return [self.mux_name()] + + +class Pin(object): + """Holds the information associated with a pin.""" + + def __init__(self, pin, is_ext=False): + self.pin = pin + self.alt_fn = [] + self.alt_fn_count = 0 + self.is_board = False + self.is_ext = is_ext + + def cpu_pin_name(self): + return "{:s}GPIO{:d}".format("EXT_" if self.is_ext else "", self.pin) + + def is_board_pin(self): + return self.is_board + + def set_is_board_pin(self): + self.is_board = True + + def parse_af(self, af_idx, af_strs_in): + if len(af_strs_in) == 0: + return + # If there is a slash, then the slash separates 2 aliases for the + # same alternate function. + af_strs = af_strs_in.split("/") + for af_str in af_strs: + alt_fn = AlternateFunction(af_idx, af_str) + self.alt_fn.append(alt_fn) + if alt_fn.is_supported(): + self.alt_fn_count += 1 + + def alt_fn_name(self, null_if_0=False): + if null_if_0 and self.alt_fn_count == 0: + return "NULL" + return "pin_{:s}_af".format(self.cpu_pin_name()) + + def print(self): + if self.is_ext: + print("#if (MICROPY_HW_PIN_EXT_COUNT > {:d})".format(self.pin)) + + if self.alt_fn_count == 0: + print("// ", end="") + print("const machine_pin_af_obj_t {:s}[] = {{".format(self.alt_fn_name())) + for alt_fn in self.alt_fn: + alt_fn.print() + if self.alt_fn_count == 0: + print("// ", end="") + print("};") + print("") + print( + "{:s}machine_pin_obj_t pin_{:s} = PIN({:d}, {:s}, {:d}, {:d}, {:s});".format( + "" if self.is_ext else "const ", + self.cpu_pin_name(), + self.pin, + self.cpu_pin_name(), + self.is_ext, + self.alt_fn_count, + self.alt_fn_name(null_if_0=True), + ) + ) + if self.is_ext: + print("#endif") + print("") + + def print_header(self, hdr_file): + n = self.cpu_pin_name() + hdr_file.write( + "extern{:s}machine_pin_obj_t pin_{:s};\n".format(" " if self.is_ext else " const ", n) + ) + if self.alt_fn_count > 0: + hdr_file.write("extern const machine_pin_af_obj_t pin_{:s}_af[];\n".format(n)) + + def qstr_list(self): + result = [] + for alt_fn in self.alt_fn: + if alt_fn.is_supported(): + result += alt_fn.qstr_list() + return result + + +class NamedPin(object): + def __init__(self, name, pin): + self._name = name + self._pin = pin + + def pin(self): + return self._pin + + def name(self): + return self._name + + +class Pins(object): + def __init__(self): + self.cpu_pins = [] # list of NamedPin objects + self.board_pins = [] # list of NamedPin objects + self.ext_pins = [] # list of NamedPin objects + for i in range(0, 10): + self.ext_pins.append(NamedPin("EXT_GPIO{:d}".format(i), Pin(i, True))) + + def find_pin(self, pin_name): + for pin in self.cpu_pins: + if pin.name() == pin_name: + return pin.pin() + + for pin in self.ext_pins: + if pin.name() == pin_name: + return pin.pin() + + def parse_af_file(self, filename, pinname_col, af_col): + with open(filename, "r") as csvfile: + rows = csv.reader(csvfile) + for row in rows: + try: + pin_num = parse_pin(row[pinname_col]) + except Exception as e: + # import traceback; traceback.print_exc() + continue + pin = Pin(pin_num) + for af_idx in range(af_col, len(row)): + if af_idx >= af_col: + pin.parse_af(af_idx, row[af_idx]) + self.cpu_pins.append(NamedPin(pin.cpu_pin_name(), pin)) + + def parse_board_file(self, filename): + with open(filename, "r") as csvfile: + rows = csv.reader(csvfile) + for row in rows: + if len(row) == 0 or row[0].startswith("#"): + # Skip empty lines, and lines starting with "#" + continue + if len(row) != 2: + raise ValueError("Expecting two entries in a row") + + cpu_pin_name = row[1] + try: + pin_num = parse_pin(cpu_pin_name) + except: + # import traceback; traceback.print_exc() + continue + pin = self.find_pin(cpu_pin_name) + if pin: + pin.set_is_board_pin() + if row[0]: # Only add board pins that have a name + self.board_pins.append(NamedPin(row[0], pin)) + + def print_table(self, label, named_pins): + print("") + print("const machine_pin_obj_t *machine_pin_{:s}_pins[] = {{".format(label)) + for pin in named_pins: + if not pin.pin().is_ext: + print(" &pin_{},".format(pin.name())) + print("};") + print("") + + def print_named(self, label, named_pins): + print("") + print( + "STATIC const mp_rom_map_elem_t pin_{:s}_pins_locals_dict_table[] = {{".format(label) + ) + for named_pin in named_pins: + pin = named_pin.pin() + if pin.is_ext: + print(" #if (MICROPY_HW_PIN_EXT_COUNT > {:d})".format(pin.pin)) + print( + " {{ MP_ROM_QSTR(MP_QSTR_{:s}), MP_ROM_PTR(&pin_{:s}) }},".format( + named_pin.name(), pin.cpu_pin_name() + ) + ) + if pin.is_ext: + print(" #endif") + + print("};") + print( + "MP_DEFINE_CONST_DICT(pin_{:s}_pins_locals_dict, pin_{:s}_pins_locals_dict_table);".format( + label, label + ) + ) + print("") + + def print(self): + for pin in self.cpu_pins: + pin.pin().print() + + for pin in self.ext_pins: + if pin.pin().is_ext: + pin.pin().print() + + self.print_table("cpu", self.cpu_pins) + self.print_named("cpu", self.cpu_pins + self.ext_pins) + self.print_named("board", self.board_pins) + + def print_header(self, hdr_filename, obj_decls): + with open(hdr_filename, "wt") as hdr_file: + if obj_decls: + for named_pin in self.cpu_pins: + pin = named_pin.pin() + pin.print_header(hdr_file) + for named_pin in self.board_pins: + pin = named_pin.pin() + if pin.is_ext: + pin.print_header(hdr_file) + # provide #define's mapping board to cpu name + for named_pin in self.board_pins: + if named_pin.pin().is_board_pin(): + hdr_file.write( + "#define pin_{:s} pin_{:s}\n".format( + named_pin.name(), named_pin.pin().cpu_pin_name() + ) + ) + + def print_qstr(self, qstr_filename): + with open(qstr_filename, "wt") as qstr_file: + qstr_set = set([]) + for named_pin in self.cpu_pins: + pin = named_pin.pin() + if pin.is_board_pin(): + qstr_set |= set(pin.qstr_list()) + qstr_set |= set([named_pin.name()]) + for named_pin in self.board_pins: + qstr_set |= set([named_pin.name()]) + for qstr in sorted(qstr_set): + print("Q({})".format(qstr), file=qstr_file) + + def print_af_hdr(self, af_const_filename): + with open(af_const_filename, "wt") as af_const_file: + af_hdr_set = set([]) + mux_name_width = 0 + for named_pin in self.cpu_pins: + pin = named_pin.pin() + if pin.is_board_pin(): + for af in pin.alt_fn: + if af.is_supported(): + mux_name = af.mux_name() + af_hdr_set |= set([mux_name]) + if len(mux_name) > mux_name_width: + mux_name_width = len(mux_name) + for mux_name in sorted(af_hdr_set): + key = "MP_OBJ_NEW_QSTR(MP_QSTR_{}),".format(mux_name) + val = "MP_OBJ_NEW_SMALL_INT(GPIO_{})".format(mux_name) + print(" { %-*s %s }," % (mux_name_width + 26, key, val), file=af_const_file) + + def print_af_py(self, af_py_filename): + with open(af_py_filename, "wt") as af_py_file: + print("PINS_AF = (", file=af_py_file) + for named_pin in self.board_pins: + print(" ('%s', " % named_pin.name(), end="", file=af_py_file) + for af in named_pin.pin().alt_fn: + if af.is_supported(): + print("(%d, '%s'), " % (af.idx, af.af_str), end="", file=af_py_file) + print("),", file=af_py_file) + print(")", file=af_py_file) + + +def main(): + parser = argparse.ArgumentParser( + prog="make-pins.py", + usage="%(prog)s [options] [command]", + description="Generate board specific pin file", + ) + parser.add_argument( + "-a", + "--af", + dest="af_filename", + help="Specifies the alternate function file for the chip", + default="rp2_af.csv", + ) + parser.add_argument( + "--af-const", + dest="af_const_filename", + help="Specifies header file for alternate function constants.", + default="build/pins_af_const.h", + ) + parser.add_argument( + "--af-py", + dest="af_py_filename", + help="Specifies the filename for the python alternate function mappings.", + default="build/pins_af.py", + ) + parser.add_argument( + "-b", + "--board", + dest="board_filename", + help="Specifies the board file", + ) + parser.add_argument( + "-p", + "--prefix", + dest="prefix_filename", + help="Specifies beginning portion of generated pins file", + default="rp2_prefix.c", + ) + parser.add_argument( + "-q", + "--qstr", + dest="qstr_filename", + help="Specifies name of generated qstr header file", + default="build/pins_qstr.h", + ) + parser.add_argument( + "-r", + "--hdr", + dest="hdr_filename", + help="Specifies name of generated pin header file", + default="build/pins.h", + ) + args = parser.parse_args(sys.argv[1:]) + + pins = Pins() + + print("// This file was automatically generated by make-pins.py") + print("//") + if args.af_filename: + print("// --af {:s}".format(args.af_filename)) + pins.parse_af_file(args.af_filename, 0, 1) + + if args.board_filename: + print("// --board {:s}".format(args.board_filename)) + pins.parse_board_file(args.board_filename) + + if args.prefix_filename: + print("// --prefix {:s}".format(args.prefix_filename)) + print("") + with open(args.prefix_filename, "r") as prefix_file: + print(prefix_file.read()) + pins.print() + pins.print_header(args.hdr_filename, True) + pins.print_qstr(args.qstr_filename) + pins.print_af_hdr(args.af_const_filename) + pins.print_af_py(args.af_py_filename) + + +if __name__ == "__main__": + main() diff --git a/ports/rp2/boards/rp2_af.csv b/ports/rp2/boards/rp2_af.csv new file mode 100644 index 0000000000..454f7ed2d1 --- /dev/null +++ b/ports/rp2/boards/rp2_af.csv @@ -0,0 +1,31 @@ +Pin,AF1,AF2,AF3,AF4,AF5,AF6,AF7,AF8,AF9 +GPIO0,SPI0_RX,UART0_TX,I2C0_SDA,PWM0_A,SIO,PIO0,PIO1,,USB_OVCUR_DET +GPIO1,SPI0_CS,UART0_RX,I2C0_SCL,PWM0_B,SIO,PIO0,PIO1,,USB_VBUS_DET +GPIO2,SPI0_SCK,UART0_CTS,I2C1_SDA,PWM1_A,SIO,PIO0,PIO1,,USB_VBUS_EN +GPIO3,SPI0_TX,UART0_RTS,I2C1_SCL,PWM1_B,SIO,PIO0,PIO1,,USB_OVCUR_DET +GPIO4,SPI0_RX,UART1_TX,I2C0_SDA,PWM2_A,SIO,PIO0,PIO1,,USB_VBUS_DET +GPIO5,SPI0_CS,UART1_RX,I2C0_SCL,PWM2_B,SIO,PIO0,PIO1,,USB_VBUS_EN +GPIO6,SPI0_SCK,UART1_CTS,I2C1_SDA,PWM3_A,SIO,PIO0,PIO1,,USB_OVCUR_DET +GPIO7,SPI0_TX,UART1_RTS,I2C1_SCL,PWM3_B,SIO,PIO0,PIO1,,USB_VBUS_DET +GPIO8,SPI1_RX,UART1_TX,I2C0_SDA,PWM4_A,SIO,PIO0,PIO1,,USB_VBUS_EN +GPIO9,SPI1_CS,UART1_RX,I2C0_SCL,PWM4_B,SIO,PIO0,PIO1,,USB_OVCUR_DET +GPIO10,SPI1_SCK,UART1_CTS,I2C1_SDA,PWM5_A,SIO,PIO0,PIO1,,USB_VBUS_DET +GPIO11,SPI1_TX,UART1_RTS,I2C1_SCL,PWM5_B,SIO,PIO0,PIO1,,USB_VBUS_EN +GPIO12,SPI1_RX,UART0_TX,I2C0_SDA,PWM6_A,SIO,PIO0,PIO1,,USB_OVCUR_DET +GPIO13,SPI1_CS,UART0_RX,I2C0_SCL,PWM6_B,SIO,PIO0,PIO1,,USB_VBUS_DET +GPIO14,SPI1_SCK,UART0_CTS,I2C1_SDA,PWM7_A,SIO,PIO0,PIO1,,USB_VBUS_EN +GPIO15,SPI1_TX,UART0_RTS,I2C1_SCL,PWM7_B,SIO,PIO0,PIO1,,USB_OVCUR_DET +GPIO16,SPI0_RX,UART0_TX,I2C0_SDA,PWM0_A,SIO,PIO0,PIO1,,USB_VBUS_DET +GPIO17,SPI0_CS,UART0_RX,I2C0_SCL,PWM0_B,SIO,PIO0,PIO1,,USB_VBUS_EN +GPIO18,SPI0_SCK,UART0_CTS,I2C1_SDA,PWM1_A,SIO,PIO0,PIO1,,USB_OVCUR_DET +GPIO19,SPI0_TX,UART0_RTS,I2C1_SCL,PWM1_B,SIO,PIO0,PIO1,,USB_VBUS_DET +GPIO20,SPI0_RX,UART1_TX,I2C0_SDA,PWM2_A,SIO,PIO0,PIO1,GPCK_GPIN0,USB_VBUS_EN +GPIO21,SPI0_CS,UART1_RX,I2C0_SCL,PWM2_B,SIO,PIO0,PIO1,GPCK_GPOUT0,USB_OVCUR_DET +GPIO22,SPI0_SCK,UART1_CTS,I2C1_SDA,PWM3_A,SIO,PIO0,PIO1,GPCK_GPIN1,USB_VBUS_DET +GPIO23,SPI0_TX,UART1_RTS,I2C1_SCL,PWM3_B,SIO,PIO0,PIO1,GPCK_GPOUT1,USB_VBUS_EN +GPIO24,SPI1_RX,UART1_TX,I2C0_SDA,PWM4_A,SIO,PIO0,PIO1,GPCK_GPOUT2,USB_OVCUR_DET +GPIO25,SPI1_CS,UART1_RX,I2C0_SCL,PWM4_B,SIO,PIO0,PIO1,GPCK_GPOUT3,USB_VBUS_DET +GPIO26,SPI1_SCK,UART1_CTS,I2C1_SDA,PWM5_A,SIO,PIO0,PIO1,,USB_VBUS_EN +GPIO27,SPI1_TX,UART1_RTS,I2C1_SCL,PWM5_B,SIO,PIO0,PIO1,,USB_OVCUR_DET +GPIO28,SPI1_RX,UART0_TX,I2C0_SDA,PWM6_A,SIO,PIO0,PIO1,,USB_VBUS_DET +GPIO29,SPI1_CS,UART0_RX,I2C0_SCL,PWM6_B,SIO,PIO0,PIO1,,USB_VBUS_EN diff --git a/ports/rp2/boards/rp2_prefix.c b/ports/rp2/boards/rp2_prefix.c new file mode 100644 index 0000000000..50f2852a8a --- /dev/null +++ b/ports/rp2/boards/rp2_prefix.c @@ -0,0 +1,36 @@ +#include +#include "py/obj.h" +#include "py/mphal.h" +#include "machine_pin.h" + +#define AF(af_idx, af_fn, af_unit) \ + { \ + .base = { &machine_pin_af_type }, \ + .name = MP_QSTR_##af_fn, \ + .idx = (af_idx), \ + .fn = GPIO_FUNC_##af_fn, \ + .unit = (af_unit), \ + } + +#if MICROPY_HW_PIN_EXT_COUNT +#define PIN(_id, _name, _is_ext, _af_num, _af_list) \ + { \ + .base = { &machine_pin_type }, \ + .name = MP_QSTR_##_name, \ + .id = (uint8_t)(_id), \ + .is_ext = (_is_ext), \ + .is_output = false, \ + .last_output_value = 0, \ + .af_num = (_af_num), \ + .af = (_af_list), \ + } +#else +#define PIN(_id, _name, _is_ext, _af_num, _af_list) \ + { \ + .base = { &machine_pin_type }, \ + .name = MP_QSTR_##_name, \ + .id = (uint8_t)(_id), \ + .af_num = (_af_num), \ + .af = (_af_list), \ + } +#endif diff --git a/ports/rp2/machine_pin.c b/ports/rp2/machine_pin.c index 9abcf064e7..71eda316da 100644 --- a/ports/rp2/machine_pin.c +++ b/ports/rp2/machine_pin.c @@ -31,6 +31,7 @@ #include "py/mphal.h" #include "shared/runtime/mpirq.h" #include "modmachine.h" +#include "machine_pin.h" #include "extmod/virtpin.h" #include "hardware/irq.h" @@ -38,11 +39,6 @@ #include "hardware/structs/iobank0.h" #include "hardware/structs/padsbank0.h" -#define GPIO_MODE_IN (0) -#define GPIO_MODE_OUT (1) -#define GPIO_MODE_OPEN_DRAIN (2) -#define GPIO_MODE_ALT (3) - // These can be or'd together. #define GPIO_PULL_UP (1) #define GPIO_PULL_DOWN (2) @@ -62,15 +58,25 @@ #define MICROPY_HW_PIN_RESERVED(i) (0) #endif -typedef struct _machine_pin_obj_t { - mp_obj_base_t base; - uint8_t id; - #if MICROPY_HW_PIN_CYW43_COUNT - bool is_cyw43; - bool is_output; - bool last_output_value; - #endif -} machine_pin_obj_t; +MP_DEFINE_CONST_OBJ_TYPE( + machine_pin_af_type, + MP_QSTR_PinAF, + MP_TYPE_FLAG_NONE + ); + +MP_DEFINE_CONST_OBJ_TYPE( + pin_cpu_pins_obj_type, + MP_QSTR_cpu, + MP_TYPE_FLAG_NONE, + locals_dict, &pin_cpu_pins_locals_dict + ); + +MP_DEFINE_CONST_OBJ_TYPE( + pin_board_pins_obj_type, + MP_QSTR_board, + MP_TYPE_FLAG_NONE, + locals_dict, &pin_board_pins_locals_dict + ); typedef struct _machine_pin_irq_obj_t { mp_irq_obj_t base; @@ -79,92 +85,17 @@ typedef struct _machine_pin_irq_obj_t { } machine_pin_irq_obj_t; STATIC const mp_irq_methods_t machine_pin_irq_methods; - -STATIC const machine_pin_obj_t machine_pin_obj[NUM_BANK0_GPIOS] = { - {{&machine_pin_type}, 0}, - {{&machine_pin_type}, 1}, - {{&machine_pin_type}, 2}, - {{&machine_pin_type}, 3}, - {{&machine_pin_type}, 4}, - {{&machine_pin_type}, 5}, - {{&machine_pin_type}, 6}, - {{&machine_pin_type}, 7}, - {{&machine_pin_type}, 8}, - {{&machine_pin_type}, 9}, - {{&machine_pin_type}, 10}, - {{&machine_pin_type}, 11}, - {{&machine_pin_type}, 12}, - {{&machine_pin_type}, 13}, - {{&machine_pin_type}, 14}, - {{&machine_pin_type}, 15}, - {{&machine_pin_type}, 16}, - {{&machine_pin_type}, 17}, - {{&machine_pin_type}, 18}, - {{&machine_pin_type}, 19}, - {{&machine_pin_type}, 20}, - {{&machine_pin_type}, 21}, - {{&machine_pin_type}, 22}, - {{&machine_pin_type}, 23}, - {{&machine_pin_type}, 24}, - {{&machine_pin_type}, 25}, - {{&machine_pin_type}, 26}, - {{&machine_pin_type}, 27}, - {{&machine_pin_type}, 28}, - {{&machine_pin_type}, 29}, -}; - -#if MICROPY_HW_PIN_CYW43_COUNT -#include "lib/cyw43-driver/src/cyw43.h" -#define CYW43_PIN_NAME_PREFIX "WL_GPIO" -STATIC machine_pin_obj_t cyw43_pin_obj[MICROPY_HW_PIN_CYW43_COUNT]; -#endif - -#define LED_PIN_NAME "LED" - -#ifndef MICROPY_HW_PIN_ENABLE_LED_PIN -#if defined(MICROPY_HW_PIN_CYW43_LED_PIN_NUM) || defined(PICO_DEFAULT_LED_PIN) -#define MICROPY_HW_PIN_ENABLE_LED_PIN 1 -#endif -#endif - -#ifdef MICROPY_HW_PIN_ENABLE_LED_PIN -#ifdef MICROPY_HW_PIN_CYW43_LED_PIN_NUM -STATIC machine_pin_obj_t *led_pin_obj = &cyw43_pin_obj[MICROPY_HW_PIN_CYW43_LED_PIN_NUM]; -#elif defined(MICROPY_HW_PIN_LED_PIN_NUM) -STATIC machine_pin_obj_t *led_pin_obj = &machine_pin_obj[MICROPY_HW_PIN_LED_PIN_NUM]; -#elif defined(PICO_DEFAULT_LED_PIN) -STATIC const machine_pin_obj_t *led_pin_obj = &machine_pin_obj[PICO_DEFAULT_LED_PIN]; -#else -#error MICROPY_HW_PIN_ENABLE_LED_PIN defined but there is no LED pin -#endif -#endif +extern const machine_pin_obj_t *machine_pin_cpu_pins[NUM_BANK0_GPIOS]; // Mask with "1" indicating that the corresponding pin is in simulated open-drain mode. uint32_t machine_pin_open_drain_mask; -#if MICROPY_HW_PIN_CYW43_COUNT -STATIC inline bool is_cyw43_pin(__unused const machine_pin_obj_t *self) { - return self->is_cyw43; +#if MICROPY_HW_PIN_EXT_COUNT +STATIC inline bool is_ext_pin(__unused const machine_pin_obj_t *self) { + return self->is_ext; } #else -#define is_cyw43_pin(x) false -#endif - -#if MICROPY_HW_PIN_CYW43_COUNT -STATIC inline void update_cyw43_value(__unused machine_pin_obj_t *self, bool value) { - if (value != self->last_output_value || !self->is_output) { - cyw43_gpio_set(&cyw43_state, self->id, value); - } - self->last_output_value = value; -} -#endif - -#if MICROPY_HW_PIN_CYW43_COUNT -STATIC inline bool get_cyw43_value(__unused machine_pin_obj_t *self) { - bool value = false; - cyw43_gpio_get(&cyw43_state, self->id, &value); - return value; -} +#define is_ext_pin(x) false #endif STATIC void gpio_irq(void) { @@ -191,12 +122,8 @@ void machine_pin_init(void) { memset(MP_STATE_PORT(machine_pin_irq_obj), 0, sizeof(MP_STATE_PORT(machine_pin_irq_obj))); irq_add_shared_handler(IO_IRQ_BANK0, gpio_irq, PICO_SHARED_IRQ_HANDLER_DEFAULT_ORDER_PRIORITY); irq_set_enabled(IO_IRQ_BANK0, true); - #if MICROPY_HW_PIN_CYW43_COUNT - for (uint i = 0; i < count_of(cyw43_pin_obj); i++) { - cyw43_pin_obj[i].id = i; - cyw43_pin_obj[i].base.type = &machine_pin_type; - cyw43_pin_obj[i].is_cyw43 = true; - } + #if MICROPY_HW_PIN_EXT_COUNT + machine_pin_ext_init(); #endif } @@ -210,11 +137,40 @@ void machine_pin_deinit(void) { irq_remove_handler(IO_IRQ_BANK0, gpio_irq); } +const machine_pin_obj_t *machine_pin_find_named(const mp_obj_dict_t *named_pins, mp_obj_t name) { + const mp_map_t *named_map = &named_pins->map; + mp_map_elem_t *named_elem = mp_map_lookup((mp_map_t *)named_map, name, MP_MAP_LOOKUP); + if (named_elem != NULL && named_elem->value != NULL) { + return MP_OBJ_TO_PTR(named_elem->value); + } + return NULL; +} + +const machine_pin_af_obj_t *machine_pin_find_alt(const machine_pin_obj_t *pin, uint8_t fn) { + const machine_pin_af_obj_t *af = pin->af; + for (mp_uint_t i = 0; i < pin->af_num; i++, af++) { + if (af->fn == fn) { + return af; + } + } + return NULL; +} + +const machine_pin_af_obj_t *machine_pin_find_alt_by_index(const machine_pin_obj_t *pin, mp_uint_t af_idx) { + const machine_pin_af_obj_t *af = pin->af; + for (mp_uint_t i = 0; i < pin->af_num; i++, af++) { + if (af->idx == af_idx) { + return af; + } + } + return NULL; +} + STATIC void machine_pin_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { machine_pin_obj_t *self = self_in; uint funcsel = GPIO_GET_FUNCSEL(self->id); qstr mode_qst; - if (!is_cyw43_pin(self)) { + if (!is_ext_pin(self)) { if (funcsel == GPIO_FUNC_SIO) { if (GPIO_IS_OPEN_DRAIN(self->id)) { mode_qst = MP_QSTR_OPEN_DRAIN; @@ -226,7 +182,7 @@ STATIC void machine_pin_print(const mp_print_t *print, mp_obj_t self_in, mp_prin } else { mode_qst = MP_QSTR_ALT; } - mp_printf(print, "Pin(%u, mode=%q", self->id, mode_qst); + mp_printf(print, "Pin(%q, mode=%q", self->name, mode_qst); bool pull_up = false; if (GPIO_IS_PULL_UP(self->id)) { mp_printf(print, ", pull=%q", MP_QSTR_PULL_UP); @@ -240,12 +196,17 @@ STATIC void machine_pin_print(const mp_print_t *print, mp_obj_t self_in, mp_prin } } if (funcsel != GPIO_FUNC_SIO) { - mp_printf(print, ", alt=%u", funcsel); + const machine_pin_af_obj_t *af = machine_pin_find_alt_by_index(self, funcsel); + if (af == NULL) { + mp_printf(print, ", alt=%u", funcsel); + } else { + mp_printf(print, ", alt=%q", af->name); + } } } else { - #if MICROPY_HW_PIN_CYW43_COUNT - mode_qst = self->is_output ? MP_QSTR_OUT : MP_QSTR_IN; - mp_printf(print, "Pin(%s%u, mode=%q", CYW43_PIN_NAME_PREFIX, self->id, mode_qst); + #if MICROPY_HW_PIN_EXT_COUNT + mode_qst = (self->is_output) ? MP_QSTR_OUT : MP_QSTR_IN; + mp_printf(print, "Pin(%q, mode=%q", self->name, mode_qst); #endif } mp_printf(print, ")"); @@ -261,155 +222,102 @@ static const mp_arg_t allowed_args[] = { {MP_QSTR_alt, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = GPIO_FUNC_SIO}}, }; -#if MICROPY_HW_PIN_CYW43_COUNT -// pin.init(mode, pull=None, *, value=None, alt=FUNC_SIO) -STATIC mp_obj_t machine_pin_cyw43_obj_init_helper(machine_pin_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - if (args[ARG_pull].u_obj != mp_const_none) { - int pull = mp_obj_get_int(args[ARG_pull].u_obj); - if (pull) { - mp_raise_ValueError("Pulls are not supported for this pin"); - } - } - - if (args[ARG_alt].u_int != GPIO_FUNC_SIO) { - mp_raise_ValueError("Alternate functions are not supported for this pin"); - } - - int value = -1; - if (args[ARG_value].u_obj != mp_const_none) { - value = mp_obj_is_true(args[ARG_value].u_obj); - } - - if (args[ARG_mode].u_obj != mp_const_none) { - mp_int_t mode = mp_obj_get_int(args[ARG_mode].u_obj); - if (mode == GPIO_MODE_IN) { - if (self->is_output) { - // todo need to disable output - } - self->is_output = false; - } else if (mode == GPIO_MODE_OUT) { - if (!self->is_output) { - // todo need to enable output - // for now we just set the value - if (value == -1) { - value = self->last_output_value; - } - self->last_output_value = !self->last_output_value; // defeat shortcircuit - update_cyw43_value(self, value); - self->is_output = true; - } - } else { - mp_raise_ValueError("only Pin.OUT and Pin.IN are supported for this pin"); - } - } - - if (value != -1) { - if (self->is_output) { - update_cyw43_value(self, value); - } else { - // figure if you pass a value to IN it should still remember it (this is what regular GPIO does) - self->last_output_value = value; - } - } - - return mp_const_none; -} -#endif - STATIC mp_obj_t machine_pin_obj_init_helper(const machine_pin_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { // parse args mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - // set initial value (do this before configuring mode/pull) + if (is_ext_pin(self) && args[ARG_pull].u_obj != mp_const_none) { + mp_raise_ValueError("pulls are not supported for external pins"); + } + + if (is_ext_pin(self) && args[ARG_alt].u_int != GPIO_FUNC_SIO) { + mp_raise_ValueError("alternate functions are not supported for external pins"); + } + + // get initial value of pin (only valid for OUT and OPEN_DRAIN modes) + int value = -1; if (args[ARG_value].u_obj != mp_const_none) { - gpio_put(self->id, mp_obj_is_true(args[ARG_value].u_obj)); + value = mp_obj_is_true(args[ARG_value].u_obj); } // configure mode if (args[ARG_mode].u_obj != mp_const_none) { mp_int_t mode = mp_obj_get_int(args[ARG_mode].u_obj); - if (mode == GPIO_MODE_IN) { + if (is_ext_pin(self)) { + #if MICROPY_HW_PIN_EXT_COUNT + // The regular Pins are const, but the external pins are mutable. + machine_pin_obj_t *mutable_self = (machine_pin_obj_t *)self; + machine_pin_ext_config(mutable_self, mode, value); + #endif + } else if (mode == MACHINE_PIN_MODE_IN) { mp_hal_pin_input(self->id); - } else if (mode == GPIO_MODE_OUT) { + } else if (mode == MACHINE_PIN_MODE_OUT) { + if (value != -1) { + // set initial output value before configuring mode + gpio_put(self->id, value); + } mp_hal_pin_output(self->id); - } else if (mode == GPIO_MODE_OPEN_DRAIN) { - mp_hal_pin_open_drain(self->id); + } else if (mode == MACHINE_PIN_MODE_OPEN_DRAIN) { + mp_hal_pin_open_drain_with_value(self->id, value == -1 ? 1 : value); } else { - // Alternate function. - gpio_set_function(self->id, args[ARG_alt].u_int); + // Configure alternate function. + mp_uint_t af = args[ARG_alt].u_int; + if (machine_pin_find_alt(self, af) == NULL) { + mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("invalid pin af: %d"), af); + } + gpio_set_function(self->id, af); machine_pin_open_drain_mask &= ~(1 << self->id); } } - // configure pull (unconditionally because None means no-pull) - uint32_t pull = 0; - if (args[ARG_pull].u_obj != mp_const_none) { - pull = mp_obj_get_int(args[ARG_pull].u_obj); + if (!is_ext_pin(self)) { + // Configure pull (unconditionally because None means no-pull). + uint32_t pull = 0; + if (args[ARG_pull].u_obj != mp_const_none) { + pull = mp_obj_get_int(args[ARG_pull].u_obj); + } + gpio_set_pulls(self->id, pull & GPIO_PULL_UP, pull & GPIO_PULL_DOWN); } - gpio_set_pulls(self->id, pull & GPIO_PULL_UP, pull & GPIO_PULL_DOWN); return mp_const_none; } // constructor(id, ...) mp_obj_t mp_pin_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true); - - const machine_pin_obj_t *self = NULL; + if (mp_obj_is_str(args[0])) { const char *name = mp_obj_str_get_str(args[0]); - #if MICROPY_HW_PIN_ENABLE_LED_PIN - if (!strcmp(name, LED_PIN_NAME)) { - self = led_pin_obj; - } - #endif - #if MICROPY_HW_PIN_CYW43_COUNT - static_assert(MICROPY_HW_PIN_CYW43_COUNT < 10, ""); // makes parsing name easy! - if (!self && !strncmp(name, CYW43_PIN_NAME_PREFIX, strlen(CYW43_PIN_NAME_PREFIX)) && strlen(name) == strlen(CYW43_PIN_NAME_PREFIX) + 1) { - int num = name[strlen(CYW43_PIN_NAME_PREFIX)] - '0'; - if (num < MICROPY_HW_PIN_CYW43_COUNT) { - self = &cyw43_pin_obj[num]; - } - } - #endif + // Try to find the pin in the board pins first. + self = machine_pin_find_named(&pin_board_pins_locals_dict, args[0]); if (!self) { - mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("Unknown named pin \"%s\""), name); + // If not found, try to find the pin in the cpu pins which include + // CPU and and externally controlled pins (if any). + self = machine_pin_find_named(&pin_cpu_pins_locals_dict, args[0]); + } + if (!self) { + mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("unknown named pin \"%s\""), name); + } + } else if (mp_obj_is_int(args[0])) { + // get the wanted pin object + int wanted_pin = mp_obj_get_int(args[0]); + if (0 <= wanted_pin && wanted_pin < MP_ARRAY_SIZE(machine_pin_cpu_pins)) { + self = machine_pin_cpu_pins[wanted_pin]; } } if (!self) { - // get the wanted pin object - int wanted_pin = mp_obj_get_int(args[0]); - if (!(0 <= wanted_pin && wanted_pin < MP_ARRAY_SIZE(machine_pin_obj))) { - mp_raise_ValueError("invalid pin"); - } - self = &machine_pin_obj[wanted_pin]; + mp_raise_ValueError("invalid pin"); } - // note we have different init args based on the type of pin. so Pin("LED", Pin.OUT) may not always make sense - if (!is_cyw43_pin(self)) { - if (n_args > 1 || n_kw > 0) { - // pin mode given, so configure this GPIO - mp_map_t kw_args; - mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); - machine_pin_obj_init_helper(self, n_args - 1, args + 1, &kw_args); - } - return MP_OBJ_FROM_PTR(self); - } - #if MICROPY_HW_PIN_CYW43_COUNT + if (n_args > 1 || n_kw > 0) { // pin mode given, so configure this GPIO mp_map_t kw_args; mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); - // The regular Pins are const, but the CYW43 pins are mutable. - machine_pin_obj_t *mutable_self = (machine_pin_obj_t *)self; - machine_pin_cyw43_obj_init_helper(mutable_self, n_args - 1, args + 1, &kw_args); + machine_pin_obj_init_helper(self, n_args - 1, args + 1, &kw_args); } return MP_OBJ_FROM_PTR(self); - #endif } // fast method for getting/setting pin value @@ -418,39 +326,33 @@ STATIC mp_obj_t machine_pin_call(mp_obj_t self_in, size_t n_args, size_t n_kw, c machine_pin_obj_t *self = self_in; if (n_args == 0) { // get pin - if (!is_cyw43_pin(self)) { + if (is_ext_pin(self)) { + #if MICROPY_HW_PIN_EXT_COUNT + return MP_OBJ_NEW_SMALL_INT(machine_pin_ext_get(self)); + #endif + } else { return MP_OBJ_NEW_SMALL_INT(gpio_get(self->id)); } - #if MICROPY_HW_PIN_CYW43_COUNT - return MP_OBJ_NEW_SMALL_INT(get_cyw43_value(self)); - #endif } else { // set pin bool value = mp_obj_is_true(args[0]); - if (!is_cyw43_pin(self)) { - if (GPIO_IS_OPEN_DRAIN(self->id)) { - MP_STATIC_ASSERT(GPIO_IN == 0 && GPIO_OUT == 1); - gpio_set_dir(self->id, 1 - value); - } else { - gpio_put(self->id, value); - } - return mp_const_none; + if (is_ext_pin(self)) { + #if MICROPY_HW_PIN_EXT_COUNT + machine_pin_ext_set(self, value); + #endif + } else if (GPIO_IS_OPEN_DRAIN(self->id)) { + MP_STATIC_ASSERT(GPIO_IN == 0 && GPIO_OUT == 1); + gpio_set_dir(self->id, 1 - value); + } else { + gpio_put(self->id, value); } - #if MICROPY_HW_PIN_CYW43_COUNT - update_cyw43_value(self, value); - #endif } return mp_const_none; } // pin.init(mode, pull) STATIC mp_obj_t machine_pin_obj_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { - if (!is_cyw43_pin(args[0])) { - return machine_pin_obj_init_helper(args[0], n_args - 1, args + 1, kw_args); - } - #if MICROPY_HW_PIN_CYW43_COUNT - return machine_pin_cyw43_obj_init_helper(args[0], n_args - 1, args + 1, kw_args); - #endif + return machine_pin_obj_init_helper(args[0], n_args - 1, args + 1, kw_args); } MP_DEFINE_CONST_FUN_OBJ_KW(machine_pin_init_obj, 1, machine_pin_obj_init); @@ -463,36 +365,32 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_pin_value_obj, 1, 2, machine_ // pin.low() STATIC mp_obj_t machine_pin_low(mp_obj_t self_in) { machine_pin_obj_t *self = MP_OBJ_TO_PTR(self_in); - if (!is_cyw43_pin(self)) { - if (GPIO_IS_OPEN_DRAIN(self->id)) { - gpio_set_dir(self->id, GPIO_OUT); - } else { - gpio_clr_mask(1u << self->id); - } - return mp_const_none; + if (is_ext_pin(self)) { + #if MICROPY_HW_PIN_EXT_COUNT + machine_pin_ext_set(self, 0); + #endif + } else if (GPIO_IS_OPEN_DRAIN(self->id)) { + gpio_set_dir(self->id, GPIO_OUT); + } else { + gpio_clr_mask(1u << self->id); } - #if MICROPY_HW_PIN_CYW43_COUNT - update_cyw43_value(self, 0); return mp_const_none; - #endif } STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_pin_low_obj, machine_pin_low); // pin.high() STATIC mp_obj_t machine_pin_high(mp_obj_t self_in) { machine_pin_obj_t *self = MP_OBJ_TO_PTR(self_in); - if (!is_cyw43_pin(self)) { - if (GPIO_IS_OPEN_DRAIN(self->id)) { - gpio_set_dir(self->id, GPIO_IN); - } else { - gpio_set_mask(1u << self->id); - } - return mp_const_none; + if (is_ext_pin(self)) { + #if MICROPY_HW_PIN_EXT_COUNT + machine_pin_ext_set(self, 1); + #endif + } else if (GPIO_IS_OPEN_DRAIN(self->id)) { + gpio_set_dir(self->id, GPIO_IN); + } else { + gpio_set_mask(1u << self->id); } - #if MICROPY_HW_PIN_CYW43_COUNT - update_cyw43_value(self, 1); return mp_const_none; - #endif } STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_pin_high_obj, machine_pin_high); @@ -500,22 +398,20 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_pin_high_obj, machine_pin_high); // pin.toggle() STATIC mp_obj_t machine_pin_toggle(mp_obj_t self_in) { machine_pin_obj_t *self = MP_OBJ_TO_PTR(self_in); - if (!is_cyw43_pin(self)) { - if (GPIO_IS_OPEN_DRAIN(self->id)) { - if (GPIO_IS_OUT(self->id)) { - gpio_set_dir(self->id, GPIO_IN); - } else { - gpio_set_dir(self->id, GPIO_OUT); - } + if (is_ext_pin(self)) { + #if MICROPY_HW_PIN_EXT_COUNT + machine_pin_ext_set(self, self->last_output_value ^ 1); + #endif + } else if (GPIO_IS_OPEN_DRAIN(self->id)) { + if (GPIO_IS_OUT(self->id)) { + gpio_set_dir(self->id, GPIO_IN); } else { - gpio_xor_mask(1u << self->id); + gpio_set_dir(self->id, GPIO_OUT); } - return mp_const_none; + } else { + gpio_xor_mask(1u << self->id); } - #if MICROPY_HW_PIN_CYW43_COUNT - update_cyw43_value(self, self->last_output_value ^ 1); return mp_const_none; - #endif } STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_pin_toggle_obj, machine_pin_toggle); @@ -528,7 +424,7 @@ STATIC machine_pin_irq_obj_t *machine_pin_get_irq(mp_hal_pin_obj_t pin) { irq = m_new_obj(machine_pin_irq_obj_t); irq->base.base.type = &mp_irq_type; irq->base.methods = (mp_irq_methods_t *)&machine_pin_irq_methods; - irq->base.parent = MP_OBJ_FROM_PTR(&machine_pin_obj[pin]); + irq->base.parent = MP_OBJ_FROM_PTR(machine_pin_cpu_pins[pin]); irq->base.handler = mp_const_none; irq->base.ishard = false; MP_STATE_PORT(machine_pin_irq_obj[pin]) = irq; @@ -563,7 +459,7 @@ STATIC mp_obj_t machine_pin_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_ { MP_QSTR_hard, MP_ARG_BOOL, {.u_bool = false} }, }; machine_pin_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - if (is_cyw43_pin(self)) { + if (is_ext_pin(self)) { mp_raise_ValueError(MP_ERROR_TEXT("expecting a regular GPIO Pin")); } @@ -594,15 +490,30 @@ STATIC const mp_rom_map_elem_t machine_pin_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_toggle), MP_ROM_PTR(&machine_pin_toggle_obj) }, { MP_ROM_QSTR(MP_QSTR_irq), MP_ROM_PTR(&machine_pin_irq_obj) }, + // class attributes + { MP_ROM_QSTR(MP_QSTR_board), MP_ROM_PTR(&pin_board_pins_obj_type) }, + { MP_ROM_QSTR(MP_QSTR_cpu), MP_ROM_PTR(&pin_cpu_pins_obj_type) }, + // class constants - { MP_ROM_QSTR(MP_QSTR_IN), MP_ROM_INT(GPIO_MODE_IN) }, - { MP_ROM_QSTR(MP_QSTR_OUT), MP_ROM_INT(GPIO_MODE_OUT) }, - { MP_ROM_QSTR(MP_QSTR_OPEN_DRAIN), MP_ROM_INT(GPIO_MODE_OPEN_DRAIN) }, - { MP_ROM_QSTR(MP_QSTR_ALT), MP_ROM_INT(GPIO_MODE_ALT) }, + { MP_ROM_QSTR(MP_QSTR_IN), MP_ROM_INT(MACHINE_PIN_MODE_IN) }, + { MP_ROM_QSTR(MP_QSTR_OUT), MP_ROM_INT(MACHINE_PIN_MODE_OUT) }, + { MP_ROM_QSTR(MP_QSTR_OPEN_DRAIN), MP_ROM_INT(MACHINE_PIN_MODE_OPEN_DRAIN) }, + { MP_ROM_QSTR(MP_QSTR_ALT), MP_ROM_INT(MACHINE_PIN_MODE_ALT) }, { MP_ROM_QSTR(MP_QSTR_PULL_UP), MP_ROM_INT(GPIO_PULL_UP) }, { MP_ROM_QSTR(MP_QSTR_PULL_DOWN), MP_ROM_INT(GPIO_PULL_DOWN) }, { MP_ROM_QSTR(MP_QSTR_IRQ_RISING), MP_ROM_INT(GPIO_IRQ_EDGE_RISE) }, { MP_ROM_QSTR(MP_QSTR_IRQ_FALLING), MP_ROM_INT(GPIO_IRQ_EDGE_FALL) }, + + // Pins alternate functions + { MP_ROM_QSTR(MP_QSTR_ALT_SPI), MP_ROM_INT(GPIO_FUNC_SPI) }, + { MP_ROM_QSTR(MP_QSTR_ALT_UART), MP_ROM_INT(GPIO_FUNC_UART) }, + { MP_ROM_QSTR(MP_QSTR_ALT_I2C), MP_ROM_INT(GPIO_FUNC_I2C) }, + { MP_ROM_QSTR(MP_QSTR_ALT_PWM), MP_ROM_INT(GPIO_FUNC_PWM) }, + { MP_ROM_QSTR(MP_QSTR_ALT_SIO), MP_ROM_INT(GPIO_FUNC_SIO) }, + { MP_ROM_QSTR(MP_QSTR_ALT_PIO0), MP_ROM_INT(GPIO_FUNC_PIO0) }, + { MP_ROM_QSTR(MP_QSTR_ALT_PIO1), MP_ROM_INT(GPIO_FUNC_PIO1) }, + { MP_ROM_QSTR(MP_QSTR_ALT_GPCK), MP_ROM_INT(GPIO_FUNC_GPCK) }, + { MP_ROM_QSTR(MP_QSTR_ALT_USB), MP_ROM_INT(GPIO_FUNC_USB) }, }; STATIC MP_DEFINE_CONST_DICT(machine_pin_locals_dict, machine_pin_locals_dict_table); @@ -610,31 +521,28 @@ STATIC mp_uint_t pin_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, i (void)errcode; machine_pin_obj_t *self = self_in; - if (!is_cyw43_pin(self)) { - switch (request) { - case MP_PIN_READ: { - return gpio_get(self->id); - } - case MP_PIN_WRITE: { - gpio_put(self->id, arg); - return 0; - } - } - return -1; - } - - #if MICROPY_HW_PIN_CYW43_COUNT switch (request) { case MP_PIN_READ: { - return get_cyw43_value(self); + if (is_ext_pin(self)) { + #if MICROPY_HW_PIN_EXT_COUNT + return machine_pin_ext_get(self); + #endif + } else { + return gpio_get(self->id); + } } case MP_PIN_WRITE: { - update_cyw43_value(self, arg); + if (is_ext_pin(self)) { + #if MICROPY_HW_PIN_EXT_COUNT + machine_pin_ext_set(self, arg); + #endif + } else { + gpio_put(self->id, arg); + } return 0; } } return -1; - #endif } STATIC const mp_pin_p_t pin_pin_p = { @@ -683,7 +591,7 @@ mp_hal_pin_obj_t mp_hal_get_pin_obj(mp_obj_t obj) { mp_raise_ValueError(MP_ERROR_TEXT("expecting a Pin")); } machine_pin_obj_t *pin = MP_OBJ_TO_PTR(obj); - if (is_cyw43_pin(pin)) { + if (is_ext_pin(pin)) { mp_raise_ValueError(MP_ERROR_TEXT("expecting a regular GPIO Pin")); } return pin->id; diff --git a/ports/rp2/machine_pin.h b/ports/rp2/machine_pin.h new file mode 100644 index 0000000000..c10dc4f9e8 --- /dev/null +++ b/ports/rp2/machine_pin.h @@ -0,0 +1,82 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2022 Ibrahim Abdelkader + * + * 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_RP2_MACHINE_PIN_H +#define MICROPY_INCLUDED_RP2_MACHINE_PIN_H + +#include +#include "py/obj.h" +#include "py/mphal.h" + +enum { + MACHINE_PIN_MODE_IN = 0, + MACHINE_PIN_MODE_OUT = 1, + MACHINE_PIN_MODE_OPEN_DRAIN = 2, + MACHINE_PIN_MODE_ALT = 3 +}; + +typedef struct _machine_pin_af_obj_t { + mp_obj_base_t base; + qstr name; + uint8_t idx : 4; + uint8_t fn : 4; + uint8_t unit : 8; +} machine_pin_af_obj_t; + +typedef struct _machine_pin_obj_t { + mp_obj_base_t base; + qstr name; + uint8_t id : 5; + #if MICROPY_HW_PIN_EXT_COUNT + uint8_t is_ext : 1; + uint8_t is_output : 1; + uint8_t last_output_value : 1; + #endif + uint8_t af_num : 4; + const machine_pin_af_obj_t *af; +} machine_pin_obj_t; + +extern const mp_obj_type_t machine_pin_type; +extern const mp_obj_type_t machine_pin_af_type; + +// Include all of the individual pin objects +#include "genhdr/pins.h" + +extern const mp_obj_type_t pin_cpu_pins_obj_type; +extern const mp_obj_dict_t pin_cpu_pins_locals_dict; + +extern const mp_obj_type_t pin_board_pins_obj_type; +extern const mp_obj_dict_t pin_board_pins_locals_dict; + +void machine_pin_ext_init(void); +void machine_pin_ext_set(machine_pin_obj_t *self, bool value); +bool machine_pin_ext_get(machine_pin_obj_t *self); +void machine_pin_ext_config(machine_pin_obj_t *self, int mode, int value); + +const machine_pin_obj_t *machine_pin_find_named(const mp_obj_dict_t *named_pins, mp_obj_t name); +const machine_pin_af_obj_t *machine_pin_find_alt(const machine_pin_obj_t *pin, uint8_t fn); +const machine_pin_af_obj_t *machine_pin_find_alt_by_index(const machine_pin_obj_t *pin, mp_uint_t af_idx); + +#endif // MICROPY_INCLUDED_RP2_MACHINE_PIN_H diff --git a/ports/rp2/machine_pin_cyw43.c b/ports/rp2/machine_pin_cyw43.c new file mode 100644 index 0000000000..c09561461f --- /dev/null +++ b/ports/rp2/machine_pin_cyw43.c @@ -0,0 +1,86 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016-2022 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/runtime.h" +#include "py/mphal.h" + +#if defined(MICROPY_PY_NETWORK_CYW43) && defined(MICROPY_HW_PIN_EXT_COUNT) + +#include "modmachine.h" +#include "machine_pin.h" +#include "lib/cyw43-driver/src/cyw43.h" + +void machine_pin_ext_init(void) { +} + +void machine_pin_ext_set(machine_pin_obj_t *self, bool value) { + if (value != self->last_output_value || !self->is_output) { + cyw43_gpio_set(&cyw43_state, self->id, value); + } + self->last_output_value = value; +} + +bool machine_pin_ext_get(machine_pin_obj_t *self) { + bool value = false; + cyw43_gpio_get(&cyw43_state, self->id, &value); + return value; +} + +void machine_pin_ext_config(machine_pin_obj_t *self, int mode, int value) { + if (mode == MACHINE_PIN_MODE_IN) { + if (self->is_output) { + // TODO need to disable output + } + self->is_output = false; + } else if (mode == MACHINE_PIN_MODE_OUT) { + if (!self->is_output) { + // TODO need to enable output + // for now we just set the value + if (value == -1) { + value = self->last_output_value; + } + self->last_output_value = !self->last_output_value; // defeat shortcircuit + machine_pin_ext_set(self, value); + self->is_output = true; + } + } else { + mp_raise_ValueError("only Pin.OUT and Pin.IN are supported for this pin"); + } + + if (value != -1) { + if (self->is_output) { + machine_pin_ext_set(self, value); + } else { + // figure if you pass a value to IN it should still remember it (this is what regular GPIO does) + self->last_output_value = value; + } + } +} + +#endif // defined(MICROPY_PY_NETWORK_CYW43) && defined(MICROPY_HW_PIN_EXT_COUNT) diff --git a/ports/rp2/machine_pwm.c b/ports/rp2/machine_pwm.c index 41dc3ab476..0c840eca94 100644 --- a/ports/rp2/machine_pwm.c +++ b/ports/rp2/machine_pwm.c @@ -100,11 +100,33 @@ STATIC void mp_machine_pwm_deinit(machine_pwm_obj_t *self) { pwm_set_enabled(self->slice, false); } -STATIC mp_obj_t mp_machine_pwm_freq_get(machine_pwm_obj_t *self) { +// Returns: floor((16*F + offset) / div16) +// Avoids overflow in the numerator that would occur if +// 16*F + offset > 2**32 +// F + offset/16 > 2**28 = 268435456 (approximately, due to flooring) +uint32_t get_slice_hz(uint32_t offset, uint32_t div16) { uint32_t source_hz = clock_get_hz(clk_sys); + if (source_hz + offset / 16 > 268000000) { + return (16 * (uint64_t)source_hz + offset) / div16; + } else { + return (16 * source_hz + offset) / div16; + } +} + +// Returns 16*F / denom, rounded. +uint32_t get_slice_hz_round(uint32_t div16) { + return get_slice_hz(div16 / 2, div16); +} + +// Returns ceil(16*F / denom). +uint32_t get_slice_hz_ceil(uint32_t div16) { + return get_slice_hz(div16 - 1, div16); +} + +STATIC mp_obj_t mp_machine_pwm_freq_get(machine_pwm_obj_t *self) { uint32_t div16 = pwm_hw->slice[self->slice].div; uint32_t top = pwm_hw->slice[self->slice].top; - uint32_t pwm_freq = 16 * source_hz / div16 / (top + 1); + uint32_t pwm_freq = get_slice_hz_round(div16 * (top + 1)); return MP_OBJ_NEW_SMALL_INT(pwm_freq); } @@ -113,30 +135,36 @@ STATIC void mp_machine_pwm_freq_set(machine_pwm_obj_t *self, mp_int_t freq) { // Maximum "top" is set at 65534 to be able to achieve 100% duty with 65535. #define TOP_MAX 65534 uint32_t source_hz = clock_get_hz(clk_sys); - uint32_t div16_top = 16 * source_hz / freq; - uint32_t top = 1; - for (;;) { - // Try a few small prime factors to get close to the desired frequency. - if (div16_top >= 16 * 5 && div16_top % 5 == 0 && top * 5 <= TOP_MAX) { - div16_top /= 5; - top *= 5; - } else if (div16_top >= 16 * 3 && div16_top % 3 == 0 && top * 3 <= TOP_MAX) { - div16_top /= 3; - top *= 3; - } else if (div16_top >= 16 * 2 && top * 2 <= TOP_MAX) { - div16_top /= 2; - top *= 2; - } else { - break; - } + uint32_t div16; + uint32_t top; + + if ((source_hz + freq / 2) / freq < TOP_MAX) { + // If possible (based on the formula for TOP below), use a DIV of 1. + // This also prevents overflow in the DIV calculation. + div16 = 16; + + // Same as get_slice_hz_round() below but canceling the 16s + // to avoid overflow for high freq. + top = (source_hz + freq / 2) / freq - 1; + } else { + // Otherwise, choose the smallest possible DIV for maximum + // duty cycle resolution. + // Constraint: 16*F/(div16*freq) < TOP_MAX + // So: + div16 = get_slice_hz_ceil(TOP_MAX * freq); + + // Set TOP as accurately as possible using rounding. + top = get_slice_hz_round(div16 * freq) - 1; } - if (div16_top < 16) { + + + if (div16 < 16) { mp_raise_ValueError(MP_ERROR_TEXT("freq too large")); - } else if (div16_top >= 256 * 16) { + } else if (div16 >= 256 * 16) { mp_raise_ValueError(MP_ERROR_TEXT("freq too small")); } - pwm_hw->slice[self->slice].div = div16_top; - pwm_hw->slice[self->slice].top = top - 1; + pwm_hw->slice[self->slice].div = div16; + pwm_hw->slice[self->slice].top = top; if (self->duty_type == DUTY_U16) { mp_machine_pwm_duty_set_u16(self, self->duty); } else if (self->duty_type == DUTY_NS) { @@ -148,12 +176,17 @@ STATIC mp_obj_t mp_machine_pwm_duty_get_u16(machine_pwm_obj_t *self) { uint32_t top = pwm_hw->slice[self->slice].top; uint32_t cc = pwm_hw->slice[self->slice].cc; cc = (cc >> (self->channel ? PWM_CH0_CC_B_LSB : PWM_CH0_CC_A_LSB)) & 0xffff; - return MP_OBJ_NEW_SMALL_INT(cc * 65535 / (top + 1)); + + // Use rounding (instead of flooring) here to give as accurate an + // estimate as possible. + return MP_OBJ_NEW_SMALL_INT((cc * 65535 + (top + 1) / 2) / (top + 1)); } STATIC void mp_machine_pwm_duty_set_u16(machine_pwm_obj_t *self, mp_int_t duty_u16) { uint32_t top = pwm_hw->slice[self->slice].top; - uint32_t cc = duty_u16 * (top + 1) / 65535; + + // Use rounding here to set it as accurately as possible. + uint32_t cc = (duty_u16 * (top + 1) + 65535 / 2) / 65535; pwm_set_chan_level(self->slice, self->channel, cc); pwm_set_enabled(self->slice, true); self->duty = duty_u16; @@ -161,17 +194,15 @@ STATIC void mp_machine_pwm_duty_set_u16(machine_pwm_obj_t *self, mp_int_t duty_u } STATIC mp_obj_t mp_machine_pwm_duty_get_ns(machine_pwm_obj_t *self) { - uint32_t source_hz = clock_get_hz(clk_sys); - uint32_t slice_hz = 16 * source_hz / pwm_hw->slice[self->slice].div; + uint32_t slice_hz = get_slice_hz_round(pwm_hw->slice[self->slice].div); uint32_t cc = pwm_hw->slice[self->slice].cc; cc = (cc >> (self->channel ? PWM_CH0_CC_B_LSB : PWM_CH0_CC_A_LSB)) & 0xffff; - return MP_OBJ_NEW_SMALL_INT((uint64_t)cc * 1000000000ULL / slice_hz); + return MP_OBJ_NEW_SMALL_INT(((uint64_t)cc * 1000000000ULL + slice_hz / 2) / slice_hz); } STATIC void mp_machine_pwm_duty_set_ns(machine_pwm_obj_t *self, mp_int_t duty_ns) { - uint32_t source_hz = clock_get_hz(clk_sys); - uint32_t slice_hz = 16 * source_hz / pwm_hw->slice[self->slice].div; - uint32_t cc = (uint64_t)duty_ns * slice_hz / 1000000000ULL; + uint32_t slice_hz = get_slice_hz_round(pwm_hw->slice[self->slice].div); + uint32_t cc = ((uint64_t)duty_ns * slice_hz + 500000000ULL) / 1000000000ULL; if (cc > 65535) { mp_raise_ValueError(MP_ERROR_TEXT("duty larger than period")); } diff --git a/ports/rp2/main.c b/ports/rp2/main.c index fdcdd90d4c..c5b5037491 100644 --- a/ports/rp2/main.c +++ b/ports/rp2/main.c @@ -234,7 +234,7 @@ void gc_collect(void) { } void nlr_jump_fail(void *val) { - printf("FATAL: uncaught exception %p\n", val); + mp_printf(&mp_plat_print, "FATAL: uncaught exception %p\n", val); mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(val)); for (;;) { __breakpoint(); diff --git a/ports/rp2/mphalport.h b/ports/rp2/mphalport.h index 73a503f5a9..8b4a5b6093 100644 --- a/ports/rp2/mphalport.h +++ b/ports/rp2/mphalport.h @@ -91,22 +91,31 @@ static inline unsigned int mp_hal_pin_name(mp_hal_pin_obj_t pin) { } static inline void mp_hal_pin_input(mp_hal_pin_obj_t pin) { - gpio_set_function(pin, GPIO_FUNC_SIO); gpio_set_dir(pin, GPIO_IN); machine_pin_open_drain_mask &= ~(1 << pin); + gpio_set_function(pin, GPIO_FUNC_SIO); } static inline void mp_hal_pin_output(mp_hal_pin_obj_t pin) { - gpio_set_function(pin, GPIO_FUNC_SIO); gpio_set_dir(pin, GPIO_OUT); machine_pin_open_drain_mask &= ~(1 << pin); + gpio_set_function(pin, GPIO_FUNC_SIO); +} + +static inline void mp_hal_pin_open_drain_with_value(mp_hal_pin_obj_t pin, int v) { + if (v) { + gpio_set_dir(pin, GPIO_IN); + gpio_put(pin, 0); + } else { + gpio_put(pin, 0); + gpio_set_dir(pin, GPIO_OUT); + } + machine_pin_open_drain_mask |= 1 << pin; + gpio_set_function(pin, GPIO_FUNC_SIO); } static inline void mp_hal_pin_open_drain(mp_hal_pin_obj_t pin) { - gpio_set_function(pin, GPIO_FUNC_SIO); - gpio_set_dir(pin, GPIO_IN); - gpio_put(pin, 0); - machine_pin_open_drain_mask |= 1 << pin; + mp_hal_pin_open_drain_with_value(pin, 1); } static inline void mp_hal_pin_config(mp_hal_pin_obj_t pin, uint32_t mode, uint32_t pull, uint32_t alt) { diff --git a/ports/rp2/rp2_flash.c b/ports/rp2/rp2_flash.c index 0a94b6cc90..26ec41949e 100644 --- a/ports/rp2/rp2_flash.c +++ b/ports/rp2/rp2_flash.c @@ -120,6 +120,11 @@ STATIC mp_obj_t rp2_flash_readblocks(size_t n_args, const mp_obj_t *args) { offset += mp_obj_get_int(args[3]); } memcpy(bufinfo.buf, (void *)(XIP_BASE + self->flash_base + offset), bufinfo.len); + // MICROPY_EVENT_POLL_HOOK_FAST is called here to avoid a fail in registering + // USB at boot time, if the board is busy loading files or scanning the file + // system. MICROPY_EVENT_POLL_HOOK_FAST calls tud_task(). As the alternative + // tud_task() should be called in the USB IRQ. See discussion in PR #10423. + MICROPY_EVENT_POLL_HOOK_FAST; return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(rp2_flash_readblocks_obj, 3, 4, rp2_flash_readblocks); @@ -134,7 +139,7 @@ STATIC mp_obj_t rp2_flash_writeblocks(size_t n_args, const mp_obj_t *args) { mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION(); flash_range_erase(self->flash_base + offset, bufinfo.len); MICROPY_END_ATOMIC_SECTION(atomic_state); - MICROPY_EVENT_POLL_HOOK + MICROPY_EVENT_POLL_HOOK_FAST; // TODO check return value } else { offset += mp_obj_get_int(args[3]); @@ -143,7 +148,7 @@ STATIC mp_obj_t rp2_flash_writeblocks(size_t n_args, const mp_obj_t *args) { mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION(); flash_range_program(self->flash_base + offset, bufinfo.buf, bufinfo.len); MICROPY_END_ATOMIC_SECTION(atomic_state); - MICROPY_EVENT_POLL_HOOK + MICROPY_EVENT_POLL_HOOK_FAST; // TODO check return value return mp_const_none; } diff --git a/ports/samd/mcu/samd21/mpconfigmcu.mk b/ports/samd/mcu/samd21/mpconfigmcu.mk index 90112759b9..ddd3e8b410 100644 --- a/ports/samd/mcu/samd21/mpconfigmcu.mk +++ b/ports/samd/mcu/samd21/mpconfigmcu.mk @@ -2,7 +2,7 @@ CFLAGS_MCU += -mtune=cortex-m0plus -mcpu=cortex-m0plus -msoft-float MPY_CROSS_MCU_ARCH = armv6m -SRC_S += shared/runtime/gchelper_m0.s +SRC_S += shared/runtime/gchelper_thumb1.s LIBM_SRC_C += $(addprefix lib/libm/,\ acoshf.c \ diff --git a/ports/samd/mcu/samd51/mpconfigmcu.mk b/ports/samd/mcu/samd51/mpconfigmcu.mk index e79dbc3aa6..8596f59821 100644 --- a/ports/samd/mcu/samd51/mpconfigmcu.mk +++ b/ports/samd/mcu/samd51/mpconfigmcu.mk @@ -6,7 +6,7 @@ MICROPY_VFS_LFS2 ?= 1 MICROPY_VFS_FAT ?= 1 FROZEN_MANIFEST ?= mcu/$(MCU_SERIES_LOWER)/manifest.py -SRC_S += shared/runtime/gchelper_m3.s +SRC_S += shared/runtime/gchelper_thumb2.s SRC_C += \ fatfs_port.c \ diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index 418562f7cb..d57e72a6c5 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -362,18 +362,18 @@ ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),f0 g0 l0)) CSUPEROPT = -Os # save some code space SRC_O += \ resethandler_m0.o \ - shared/runtime/gchelper_m0.o + shared/runtime/gchelper_thumb1.o else ifeq ($(MCU_SERIES),l1) CFLAGS += -DUSE_HAL_DRIVER SRC_O += \ resethandler_m3.o \ - shared/runtime/gchelper_m3.o + shared/runtime/gchelper_thumb2.o else SRC_O += \ system_stm32.o \ resethandler.o \ - shared/runtime/gchelper_m3.o + shared/runtime/gchelper_thumb2.o endif endif @@ -546,7 +546,7 @@ define RUN_DFU $(ECHO) "Writing $(1) to the board" $(if $(filter $(USE_PYDFU),1),\ $(Q)$(PYTHON) $(PYDFU) --vid $(BOOTLOADER_DFU_USB_VID) --pid $(BOOTLOADER_DFU_USB_PID) -u $(1), - $(Q)$(DFU_UTIL) -a 0 -d $(BOOTLOADER_DFU_USB_VID):$(BOOTLOADER_DFU_USB_PID) -D $(1)) + $(Q)$(DFU_UTIL) -a 0 -d $(BOOTLOADER_DFU_USB_VID):$(BOOTLOADER_DFU_USB_PID) -D $(1) -s :leave) endef define RUN_STLINK diff --git a/ports/stm32/boards/ARDUINO_PORTENTA_H7/stm32h747.ld b/ports/stm32/boards/ARDUINO_PORTENTA_H7/stm32h747.ld index 650756a19f..7a973289cb 100644 --- a/ports/stm32/boards/ARDUINO_PORTENTA_H7/stm32h747.ld +++ b/ports/stm32/boards/ARDUINO_PORTENTA_H7/stm32h747.ld @@ -44,15 +44,12 @@ _micropy_hw_internal_flash_storage_ram_cache_end = ORIGIN(DTCM) + LENGTH(DTCM); _micropy_hw_internal_flash_storage_start = ORIGIN(FLASH_FS); _micropy_hw_internal_flash_storage_end = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS); +REGION_ALIAS("FLASH_COMMON", FLASH_TEXT); + /* define output sections */ SECTIONS { - .isr_vector : - { - . = ALIGN(4); - KEEP(*(.isr_vector)) - . = ALIGN(4); - } >FLASH_TEXT + INCLUDE common_isr.ld .text : { @@ -65,6 +62,6 @@ SECTIONS _etext = .; } >FLASH_TEXT - INCLUDE common_extratext_data_in_flash_text.ld + INCLUDE common_extratext_data_in_flash.ld INCLUDE common_bss_heap_stack.ld } diff --git a/ports/stm32/boards/PYBD_SF2/f722_qspi.ld b/ports/stm32/boards/PYBD_SF2/f722_qspi.ld index c9199b341b..85145b22a3 100644 --- a/ports/stm32/boards/PYBD_SF2/f722_qspi.ld +++ b/ports/stm32/boards/PYBD_SF2/f722_qspi.ld @@ -42,6 +42,8 @@ _heap_end = _sstack; ENTRY(Reset_Handler) +REGION_ALIAS("FLASH_COMMON", FLASH_APP); + /* Define output sections */ SECTIONS { @@ -56,22 +58,8 @@ SECTIONS . = ALIGN(4); } >FLASH_EXT - .isr_vector : - { - . = ALIGN(4); - KEEP(*(.isr_vector)) - . = ALIGN(4); - } >FLASH_APP - - .text : - { - . = ALIGN(4); - *(.text*) - *(.rodata*) - . = ALIGN(4); - _etext = .; - } >FLASH_APP - - INCLUDE common_extratext_data_in_flash_app.ld + INCLUDE common_isr.ld + INCLUDE common_text.ld + INCLUDE common_extratext_data_in_flash.ld INCLUDE common_bss_heap_stack.ld } diff --git a/ports/stm32/boards/PYBD_SF6/f767.ld b/ports/stm32/boards/PYBD_SF6/f767.ld index 5866f0b5cc..cbe74696e8 100644 --- a/ports/stm32/boards/PYBD_SF6/f767.ld +++ b/ports/stm32/boards/PYBD_SF6/f767.ld @@ -41,15 +41,12 @@ _heap_end = _sstack; ENTRY(Reset_Handler) +REGION_ALIAS("FLASH_COMMON", FLASH_APP); + /* Define output sections */ SECTIONS { - .isr_vector : - { - . = ALIGN(4); - KEEP(*(.isr_vector)) - . = ALIGN(4); - } >FLASH_APP + INCLUDE common_isr.ld .text : { @@ -62,6 +59,6 @@ SECTIONS _etext = .; } >FLASH_APP - INCLUDE common_extratext_data_in_flash_app.ld + INCLUDE common_extratext_data_in_flash.ld INCLUDE common_bss_heap_stack.ld } diff --git a/ports/stm32/boards/STM32F769DISC/f769_qspi.ld b/ports/stm32/boards/STM32F769DISC/f769_qspi.ld index b6957a3213..b6515b0666 100644 --- a/ports/stm32/boards/STM32F769DISC/f769_qspi.ld +++ b/ports/stm32/boards/STM32F769DISC/f769_qspi.ld @@ -40,6 +40,8 @@ _heap_end = _sstack; ENTRY(Reset_Handler) +REGION_ALIAS("FLASH_COMMON", FLASH_APP); + SECTIONS { /* Define the code that goes in QSPI flash */ @@ -50,24 +52,8 @@ SECTIONS . = ALIGN(4); } >FLASH_QSPI - /* The startup code goes first into main flash */ - .isr_vector : - { - . = ALIGN(4); - KEEP(*(.isr_vector)) - . = ALIGN(4); - } >FLASH_APP - - /* The program code and other data goes into flash */ - .text : - { - . = ALIGN(4); - *(.text*) - *(.rodata*) - . = ALIGN(4); - _etext = .; - } >FLASH_APP - - INCLUDE common_extratext_data_in_flash_app.ld + INCLUDE common_isr.ld + INCLUDE common_text.ld + INCLUDE common_extratext_data_in_flash.ld INCLUDE common_bss_heap_stack.ld } diff --git a/ports/stm32/boards/common_basic.ld b/ports/stm32/boards/common_basic.ld index dbda1b8b68..9916a4c254 100644 --- a/ports/stm32/boards/common_basic.ld +++ b/ports/stm32/boards/common_basic.ld @@ -12,31 +12,13 @@ ENTRY(Reset_Handler) +REGION_ALIAS("FLASH_COMMON", FLASH); + /* define output sections */ SECTIONS { - /* The startup code goes first into FLASH */ - .isr_vector : - { - . = ALIGN(4); - KEEP(*(.isr_vector)) /* Startup code */ - - . = ALIGN(4); - } >FLASH - - /* The program code and other data goes into FLASH */ - .text : - { - . = ALIGN(4); - *(.text*) /* .text* sections (code) */ - *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ - /* *(.glue_7) */ /* glue arm to thumb code */ - /* *(.glue_7t) */ /* glue thumb to arm code */ - - . = ALIGN(4); - _etext = .; /* define a global symbol at end of code */ - } >FLASH - + INCLUDE common_isr.ld + INCLUDE common_text.ld INCLUDE common_extratext_data_in_flash.ld INCLUDE common_bss_heap_stack.ld } diff --git a/ports/stm32/boards/common_bl.ld b/ports/stm32/boards/common_bl.ld index 21d809a3d2..b17fe98743 100644 --- a/ports/stm32/boards/common_bl.ld +++ b/ports/stm32/boards/common_bl.ld @@ -12,31 +12,13 @@ ENTRY(Reset_Handler) +REGION_ALIAS("FLASH_COMMON", FLASH_APP); + /* define output sections */ SECTIONS { - /* The startup code goes first into FLASH */ - .isr_vector : - { - . = ALIGN(4); - KEEP(*(.isr_vector)) /* Startup code */ - - . = ALIGN(4); - } >FLASH_APP - - /* The program code and other data goes into FLASH */ - .text : - { - . = ALIGN(4); - *(.text*) /* .text* sections (code) */ - *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ - /* *(.glue_7) */ /* glue arm to thumb code */ - /* *(.glue_7t) */ /* glue thumb to arm code */ - - . = ALIGN(4); - _etext = .; /* define a global symbol at end of code */ - } >FLASH_APP - - INCLUDE common_extratext_data_in_flash_app.ld + INCLUDE common_isr.ld + INCLUDE common_text.ld + INCLUDE common_extratext_data_in_flash.ld INCLUDE common_bss_heap_stack.ld } diff --git a/ports/stm32/boards/common_blifs.ld b/ports/stm32/boards/common_blifs.ld index 5517a2d09c..51969e1f90 100644 --- a/ports/stm32/boards/common_blifs.ld +++ b/ports/stm32/boards/common_blifs.ld @@ -12,31 +12,13 @@ ENTRY(Reset_Handler) +REGION_ALIAS("FLASH_COMMON", FLASH_TEXT); + /* define output sections */ SECTIONS { - /* The startup code goes first into FLASH */ - .isr_vector : - { - . = ALIGN(4); - KEEP(*(.isr_vector)) /* Startup code */ - - . = ALIGN(4); - } >FLASH_TEXT - - /* The program code and other data goes into FLASH */ - .text : - { - . = ALIGN(4); - *(.text*) /* .text* sections (code) */ - *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ - /* *(.glue_7) */ /* glue arm to thumb code */ - /* *(.glue_7t) */ /* glue thumb to arm code */ - - . = ALIGN(4); - _etext = .; /* define a global symbol at end of code */ - } >FLASH_TEXT - - INCLUDE common_extratext_data_in_flash_text.ld + INCLUDE common_isr.ld + INCLUDE common_text.ld + INCLUDE common_extratext_data_in_flash.ld INCLUDE common_bss_heap_stack.ld } diff --git a/ports/stm32/boards/common_extratext_data_in_flash.ld b/ports/stm32/boards/common_extratext_data_in_flash.ld index eb9b86f49d..db4306641b 100644 --- a/ports/stm32/boards/common_extratext_data_in_flash.ld +++ b/ports/stm32/boards/common_extratext_data_in_flash.ld @@ -6,7 +6,7 @@ __exidx_start = .; *(.ARM.exidx*) __exidx_end = .; -} >FLASH +} >FLASH_COMMON /* Used by the start-up code to initialise data */ _sidata = LOADADDR(.data); @@ -19,4 +19,4 @@ _sidata = LOADADDR(.data); *(.data*) . = ALIGN(4); _edata = .; -} >RAM AT> FLASH +} >RAM AT> FLASH_COMMON diff --git a/ports/stm32/boards/common_extratext_data_in_flash_app.ld b/ports/stm32/boards/common_extratext_data_in_flash_app.ld deleted file mode 100644 index aba6bf57c8..0000000000 --- a/ports/stm32/boards/common_extratext_data_in_flash_app.ld +++ /dev/null @@ -1,22 +0,0 @@ -/* This linker script fragment is intended to be included in SECTIONS. */ - -/* For C++ exception handling */ -.ARM : -{ - __exidx_start = .; - *(.ARM.exidx*) - __exidx_end = .; -} >FLASH_APP - -/* Used by the start-up code to initialise data */ -_sidata = LOADADDR(.data); - -/* Initialised data section, start-up code will copy it from flash to RAM */ -.data : -{ - . = ALIGN(4); - _sdata = .; - *(.data*) - . = ALIGN(4); - _edata = .; -} >RAM AT> FLASH_APP diff --git a/ports/stm32/boards/common_extratext_data_in_flash_text.ld b/ports/stm32/boards/common_extratext_data_in_flash_text.ld deleted file mode 100644 index 5a29e47307..0000000000 --- a/ports/stm32/boards/common_extratext_data_in_flash_text.ld +++ /dev/null @@ -1,22 +0,0 @@ -/* This linker script fragment is intended to be included in SECTIONS. */ - -/* For C++ exception handling */ -.ARM : -{ - __exidx_start = .; - *(.ARM.exidx*) - __exidx_end = .; -} >FLASH_TEXT - -/* Used by the start-up code to initialise data */ -_sidata = LOADADDR(.data); - -/* Initialised data section, start-up code will copy it from flash to RAM */ -.data : -{ - . = ALIGN(4); - _sdata = .; - *(.data*) - . = ALIGN(4); - _edata = .; -} >RAM AT> FLASH_TEXT diff --git a/ports/stm32/boards/common_ifs.ld b/ports/stm32/boards/common_ifs.ld index 733ca12f67..1876e41561 100644 --- a/ports/stm32/boards/common_ifs.ld +++ b/ports/stm32/boards/common_ifs.ld @@ -13,6 +13,8 @@ ENTRY(Reset_Handler) +REGION_ALIAS("FLASH_COMMON", FLASH_TEXT); + /* define output sections */ SECTIONS { @@ -41,19 +43,7 @@ SECTIONS . = ALIGN(4); } >FLASH_ISR - /* The program code and other data goes into FLASH */ - .text : - { - . = ALIGN(4); - *(.text*) /* .text* sections (code) */ - *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ - /* *(.glue_7) */ /* glue arm to thumb code */ - /* *(.glue_7t) */ /* glue thumb to arm code */ - - . = ALIGN(4); - _etext = .; /* define a global symbol at end of code */ - } >FLASH_TEXT - - INCLUDE common_extratext_data_in_flash_text.ld + INCLUDE common_text.ld + INCLUDE common_extratext_data_in_flash.ld INCLUDE common_bss_heap_stack.ld } diff --git a/ports/stm32/boards/common_isr.ld b/ports/stm32/boards/common_isr.ld new file mode 100644 index 0000000000..0f9b8bcaad --- /dev/null +++ b/ports/stm32/boards/common_isr.ld @@ -0,0 +1,9 @@ +/* This linker script fragment is intended to be included in SECTIONS. */ + +/* The startup code goes first into FLASH */ +.isr_vector : +{ + . = ALIGN(4); + KEEP(*(.isr_vector)) /* Startup code */ + . = ALIGN(4); +} >FLASH_COMMON diff --git a/ports/stm32/boards/common_text.ld b/ports/stm32/boards/common_text.ld new file mode 100644 index 0000000000..16eea43bae --- /dev/null +++ b/ports/stm32/boards/common_text.ld @@ -0,0 +1,14 @@ +/* This linker script fragment is intended to be included in SECTIONS. */ + +/* The program code and other data goes into FLASH */ +.text : +{ + . = ALIGN(4); + *(.text*) /* .text* sections (code) */ + *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ +/* *(.glue_7) */ /* glue arm to thumb code */ +/* *(.glue_7t) */ /* glue thumb to arm code */ + + . = ALIGN(4); + _etext = .; /* define a global symbol at end of code */ +} >FLASH_COMMON diff --git a/ports/teensy/Makefile b/ports/teensy/Makefile index 89e5cbce9d..70331c5dc7 100644 --- a/ports/teensy/Makefile +++ b/ports/teensy/Makefile @@ -169,7 +169,7 @@ OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(STM_SRC_C:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_TEENSY:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SHARED_SRC_C:.c=.o)) -OBJ += $(BUILD)/shared/runtime/gchelper_m3.o +OBJ += $(BUILD)/shared/runtime/gchelper_thumb2.o OBJ += $(GEN_PINS_SRC:.c=.o) all: hex diff --git a/ports/unix/Makefile b/ports/unix/Makefile index cd18a6ed1e..8e9094b40c 100644 --- a/ports/unix/Makefile +++ b/ports/unix/Makefile @@ -294,7 +294,7 @@ $(TOP)/lib/libffi/configure: $(TOP)/lib/libffi/autogen.sh # docs and depending on makeinfo $(BUILD)/lib/libffi/include/ffi.h: $(TOP)/lib/libffi/configure mkdir -p $(BUILD)/lib/libffi; cd $(BUILD)/lib/libffi; \ - $(abspath $(TOP))/lib/libffi/configure $(CROSS_COMPILE_HOST) --prefix=$$PWD/out --disable-structs CC="$(CC)" CXX="$(CXX)" LD="$(LD)" CFLAGS="-Os -fomit-frame-pointer -fstrict-aliasing -ffast-math -fno-exceptions"; \ + $(abspath $(TOP))/lib/libffi/configure $(CROSS_COMPILE_HOST) --prefix=$$PWD/out --disable-shared --disable-structs CC="$(CC)" CXX="$(CXX)" LD="$(LD)" CFLAGS="-Os -fomit-frame-pointer -fstrict-aliasing -ffast-math -fno-exceptions"; \ $(MAKE) install-exec-recursive; $(MAKE) -C include install-data-am PREFIX = /usr/local diff --git a/ports/unix/main.c b/ports/unix/main.c index 7920db02f2..d6ae1e611b 100644 --- a/ports/unix/main.c +++ b/ports/unix/main.c @@ -699,6 +699,7 @@ MP_NOINLINE int main_(int argc, char **argv) { char *basedir = realpath(argv[a], pathbuf); if (basedir == NULL) { mp_printf(&mp_stderr_print, "%s: can't open file '%s': [Errno %d] %s\n", argv[0], argv[a], errno, strerror(errno)); + free(pathbuf); // CPython exits with 2 in such case ret = 2; break; diff --git a/py/gc.c b/py/gc.c index 22cfdae998..f11c34aefe 100644 --- a/py/gc.c +++ b/py/gc.c @@ -1058,8 +1058,7 @@ void gc_dump_alloc_table(void) { } // print header for new line of blocks // (the cast to uint32_t is for 16-bit ports) - // mp_printf(&mp_plat_print, "\n%05x: ", (uint)(PTR_FROM_BLOCK(area, bl) & (uint32_t)0xfffff)); - mp_printf(&mp_plat_print, "\n%05x: ", (uint)((bl * BYTES_PER_BLOCK) & (uint32_t)0xfffff)); + mp_printf(&mp_plat_print, "\n%08x: ", (uint)(bl * BYTES_PER_BLOCK)); } int c = ' '; switch (ATB_GET_KIND(area, bl)) { diff --git a/py/lexer.c b/py/lexer.c index 39e9662f63..e7d0e81440 100644 --- a/py/lexer.c +++ b/py/lexer.c @@ -356,6 +356,9 @@ STATIC void parse_string_literal(mp_lexer_t *lex, bool is_raw, bool is_fstring) vstr_add_byte(&lex->vstr, '{'); next_char(lex); } else { + // wrap each argument in (), e.g. + // f"{a,b,}, {c}" --> "{}".format((a,b), (c),) + vstr_add_byte(&lex->fstring_args, '('); // remember the start of this argument (if we need it for f'{a=}'). size_t i = lex->fstring_args.len; // extract characters inside the { until we reach the @@ -382,7 +385,9 @@ STATIC void parse_string_literal(mp_lexer_t *lex, bool is_raw, bool is_fstring) // remove the trailing '=' lex->fstring_args.len--; } - // comma-separate args + // close the paren-wrapped arg to .format(). + vstr_add_byte(&lex->fstring_args, ')'); + // comma-separate args to .format(). vstr_add_byte(&lex->fstring_args, ','); } vstr_add_byte(&lex->vstr, '{'); diff --git a/py/map.c b/py/map.c index 7a6f2233e6..c18df5a9f3 100644 --- a/py/map.c +++ b/py/map.c @@ -221,6 +221,7 @@ mp_map_elem_t *MICROPY_WRAP_MP_MAP_LOOKUP(mp_map_lookup)(mp_map_t * map, mp_obj_ } mp_map_elem_t *elem = map->table + map->used++; elem->key = index; + elem->value = MP_OBJ_NULL; if (!mp_obj_is_qstr(index)) { map->all_keys_are_qstrs = 0; } diff --git a/py/mkrules.cmake b/py/mkrules.cmake index b29986585a..38bad80fdb 100644 --- a/py/mkrules.cmake +++ b/py/mkrules.cmake @@ -205,7 +205,7 @@ if(MICROPY_FROZEN_MANIFEST) add_custom_command( OUTPUT ${MICROPY_FROZEN_CONTENT} - COMMAND ${Python3_EXECUTABLE} ${MICROPY_DIR}/tools/makemanifest.py -o ${MICROPY_FROZEN_CONTENT} -v "MPY_DIR=${MICROPY_DIR}" -v "MPY_LIB_DIR=${MICROPY_LIB_DIR}" -v "PORT_DIR=${MICROPY_PORT_DIR}" -v "BOARD_DIR=${MICROPY_BOARD_DIR}" -b "${CMAKE_BINARY_DIR}" -f${MICROPY_CROSS_FLAGS} ${MICROPY_FROZEN_MANIFEST} + COMMAND ${Python3_EXECUTABLE} ${MICROPY_DIR}/tools/makemanifest.py -o ${MICROPY_FROZEN_CONTENT} -v "MPY_DIR=${MICROPY_DIR}" -v "MPY_LIB_DIR=${MICROPY_LIB_DIR}" -v "PORT_DIR=${MICROPY_PORT_DIR}" -v "BOARD_DIR=${MICROPY_BOARD_DIR}" -b "${CMAKE_BINARY_DIR}" -f${MICROPY_CROSS_FLAGS} --mpy-tool-flags=${MICROPY_MPY_TOOL_FLAGS} ${MICROPY_FROZEN_MANIFEST} DEPENDS MICROPY_FORCE_BUILD ${MICROPY_QSTRDEFS_GENERATED} ${MICROPY_ROOT_POINTERS} diff --git a/py/obj.h b/py/obj.h index cb9a6cc459..8a0a256708 100644 --- a/py/obj.h +++ b/py/obj.h @@ -313,12 +313,12 @@ typedef union _mp_rom_obj_t { // Cast mp_obj_t to object pointer #ifndef MP_OBJ_TO_PTR -#define MP_OBJ_TO_PTR(o) ((void *)o) +#define MP_OBJ_TO_PTR(o) ((void *)(o)) #endif // Cast object pointer to mp_obj_t #ifndef MP_OBJ_FROM_PTR -#define MP_OBJ_FROM_PTR(p) ((mp_obj_t)p) +#define MP_OBJ_FROM_PTR(p) ((mp_obj_t)(p)) #endif // Macros to create objects that are stored in ROM. diff --git a/py/objarray.c b/py/objarray.c index c660705389..0d9411d7c4 100644 --- a/py/objarray.c +++ b/py/objarray.c @@ -53,6 +53,7 @@ #if MICROPY_PY_BUILTINS_MEMORYVIEW #define TYPECODE_MASK (0x7f) #define memview_offset free +#define memview_offset_max ((1LL << MP_OBJ_ARRAY_FREE_SIZE_BITS) - 1) #else // make (& TYPECODE_MASK) a null operation if memorview not enabled #define TYPECODE_MASK (~(size_t)0) @@ -522,6 +523,9 @@ STATIC mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value assert(sz > 0); #if MICROPY_PY_BUILTINS_MEMORYVIEW if (o->base.type == &mp_type_memoryview) { + if (slice.start > memview_offset_max) { + mp_raise_msg(&mp_type_OverflowError, MP_ERROR_TEXT("memoryview offset too large")); + } res = m_new_obj(mp_obj_array_t); *res = *o; res->memview_offset += slice.start; diff --git a/py/objarray.h b/py/objarray.h index 48a26c3fb3..4a0e8a983f 100644 --- a/py/objarray.h +++ b/py/objarray.h @@ -32,6 +32,9 @@ // Used only for memoryview types, set in "typecode" to indicate a writable memoryview #define MP_OBJ_ARRAY_TYPECODE_FLAG_RW (0x80) +// Bit size used for mp_obj_array_t.free member. +#define MP_OBJ_ARRAY_FREE_SIZE_BITS (8 * sizeof(size_t) - 8) + // This structure is used for all of bytearray, array.array, memoryview // objects. Note that memoryview has different meaning for some fields, // see comment at the beginning of objarray.c. @@ -44,7 +47,7 @@ typedef struct _mp_obj_array_t { // parent object. (Union is not used to not go into a complication of // union-of-bitfields with different toolchains). See comments in // objarray.c. - size_t free : (8 * sizeof(size_t) - 8); + size_t free : MP_OBJ_ARRAY_FREE_SIZE_BITS; size_t len; // in elements void *items; } mp_obj_array_t; diff --git a/py/objint_mpz.c b/py/objint_mpz.c index 2811bcf2aa..e9545149f8 100644 --- a/py/objint_mpz.c +++ b/py/objint_mpz.c @@ -296,8 +296,7 @@ mp_obj_t mp_obj_int_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_i mpz_pow_inpl(&res->mpz, zlhs, zrhs); break; - default: { - assert(op == MP_BINARY_OP_DIVMOD); + case MP_BINARY_OP_DIVMOD: { if (mpz_is_zero(zrhs)) { goto zero_division_error; } @@ -306,6 +305,9 @@ mp_obj_t mp_obj_int_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_i mp_obj_t tuple[2] = {MP_OBJ_FROM_PTR(quo), MP_OBJ_FROM_PTR(res)}; return mp_obj_new_tuple(2, tuple); } + + default: + return MP_OBJ_NULL; // op not supported } return MP_OBJ_FROM_PTR(res); diff --git a/shared/runtime/gchelper_generic.c b/shared/runtime/gchelper_generic.c index dcd35f9c7e..272e37056a 100644 --- a/shared/runtime/gchelper_generic.c +++ b/shared/runtime/gchelper_generic.c @@ -98,7 +98,7 @@ STATIC void gc_helper_get_regs(gc_helper_regs_t arr) { #elif defined(__thumb2__) || defined(__thumb__) || defined(__arm__) -// Fallback implementation, prefer gchelper_m0.s or gchelper_m3.s +// Fallback implementation, prefer gchelper_thumb1.s or gchelper_thumb2.s STATIC void gc_helper_get_regs(gc_helper_regs_t arr) { register long r4 asm ("r4"); diff --git a/shared/runtime/gchelper_m0.s b/shared/runtime/gchelper_thumb1.s similarity index 94% rename from shared/runtime/gchelper_m0.s rename to shared/runtime/gchelper_thumb1.s index db0d9738d1..a316c4fb36 100644 --- a/shared/runtime/gchelper_m0.s +++ b/shared/runtime/gchelper_thumb1.s @@ -25,7 +25,6 @@ */ .syntax unified - .cpu cortex-m0 .thumb .section .text @@ -34,6 +33,9 @@ .global gc_helper_get_regs_and_sp .type gc_helper_get_regs_and_sp, %function +@ This function will compile on processors like Cortex M0 that don't support +@ newer Thumb-2 instructions. + @ uint gc_helper_get_regs_and_sp(r0=uint regs[10]) gc_helper_get_regs_and_sp: @ store registers into given array diff --git a/shared/runtime/gchelper_m3.s b/shared/runtime/gchelper_thumb2.s similarity index 96% rename from shared/runtime/gchelper_m3.s rename to shared/runtime/gchelper_thumb2.s index 5220fa0883..bbc98459ec 100644 --- a/shared/runtime/gchelper_m3.s +++ b/shared/runtime/gchelper_thumb2.s @@ -25,7 +25,6 @@ */ .syntax unified - .cpu cortex-m3 .thumb .section .text @@ -34,6 +33,8 @@ .global gc_helper_get_regs_and_sp .type gc_helper_get_regs_and_sp, %function +@ This function requires Thumb-2 instruction support, e.g. Cortex M3/M4. + @ uint gc_helper_get_regs_and_sp(r0=uint regs[10]) gc_helper_get_regs_and_sp: @ store registers into given array diff --git a/shared/runtime/mpirq.c b/shared/runtime/mpirq.c index f9a85ebbd6..acd727403b 100644 --- a/shared/runtime/mpirq.c +++ b/shared/runtime/mpirq.c @@ -81,8 +81,8 @@ void mp_irq_handler(mp_irq_obj_t *self) { // Uncaught exception; disable the callback so that it doesn't run again self->methods->trigger(self->parent, 0); self->handler = mp_const_none; - printf("Uncaught exception in IRQ callback handler\n"); - mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val)); + mp_printf(MICROPY_ERROR_PRINTER, "Uncaught exception in IRQ callback handler\n"); + mp_obj_print_exception(MICROPY_ERROR_PRINTER, MP_OBJ_FROM_PTR(nlr.ret_val)); } gc_unlock(); mp_sched_unlock(); diff --git a/shared/runtime/pyexec.c b/shared/runtime/pyexec.c index 2c9f1e80ff..b6e7d8fe68 100644 --- a/shared/runtime/pyexec.c +++ b/shared/runtime/pyexec.c @@ -154,12 +154,12 @@ STATIC int parse_compile_execute(const void *source, mp_parse_input_kind_t input // display debugging info if wanted if ((exec_flags & EXEC_FLAG_ALLOW_DEBUGGING) && repl_display_debugging_info) { mp_uint_t ticks = mp_hal_ticks_ms() - start; // TODO implement a function that does this properly - printf("took " UINT_FMT " ms\n", ticks); + mp_printf(&mp_plat_print, "took " UINT_FMT " ms\n", ticks); // qstr info { size_t n_pool, n_qstr, n_str_data_bytes, n_total_bytes; qstr_pool_info(&n_pool, &n_qstr, &n_str_data_bytes, &n_total_bytes); - printf("qstr:\n n_pool=%u\n n_qstr=%u\n " + mp_printf(&mp_plat_print, "qstr:\n n_pool=%u\n n_qstr=%u\n " "n_str_data_bytes=%u\n n_total_bytes=%u\n", (unsigned)n_pool, (unsigned)n_qstr, (unsigned)n_str_data_bytes, (unsigned)n_total_bytes); } @@ -713,7 +713,7 @@ int pyexec_frozen_module(const char *name) { #endif default: - printf("could not find module '%s'\n", name); + mp_printf(MICROPY_ERROR_PRINTER, "could not find module '%s'\n", name); return false; } } diff --git a/tests/basics/int_big_error.py b/tests/basics/int_big_error.py index 79809aef11..1793cf3253 100644 --- a/tests/basics/int_big_error.py +++ b/tests/basics/int_big_error.py @@ -7,6 +7,16 @@ try: except ValueError: print("ValueError") +try: + i @ 0 +except TypeError: + print("TypeError") + +try: + i @= 0 +except TypeError: + print("TypeError") + try: len(i) except TypeError: diff --git a/tests/basics/memoryview_slice_size.py b/tests/basics/memoryview_slice_size.py new file mode 100644 index 0000000000..c56514d21f --- /dev/null +++ b/tests/basics/memoryview_slice_size.py @@ -0,0 +1,27 @@ +# test memoryview slicing beyond the limit of what memoryview can internally index + +try: + from sys import maxsize + from uctypes import bytearray_at + + memoryview +except: + print("SKIP") + raise SystemExit + +if maxsize <= 0xFFFF_FFFF: + slice_max = 0xFF_FFFF +else: + slice_max = 0xFF_FFFF_FFFF_FFFF + +buf = bytearray_at(0, slice_max + 2) +mv = memoryview(buf) + +# this should work +print(mv[slice_max : slice_max + 1]) + +# this should overflow the internal index for memoryview slicing +try: + print(mv[slice_max + 1 : slice_max + 2]) +except OverflowError: + print("OverflowError") diff --git a/tests/basics/memoryview_slice_size.py.exp b/tests/basics/memoryview_slice_size.py.exp new file mode 100644 index 0000000000..34baadd35e --- /dev/null +++ b/tests/basics/memoryview_slice_size.py.exp @@ -0,0 +1,2 @@ + +OverflowError diff --git a/tests/basics/string_fstring.py b/tests/basics/string_fstring.py index 7e8a97fd30..8907a5c478 100644 --- a/tests/basics/string_fstring.py +++ b/tests/basics/string_fstring.py @@ -56,3 +56,8 @@ try: except (ValueError, SyntaxError): # MicroPython incorrectly raises ValueError here. print('SyntaxError') + +# Allow literal tuples +print(f"a {1,} b") +print(f"a {x,y,} b") +print(f"a {x,1} b") diff --git a/tests/basics/string_fstring_debug.py b/tests/basics/string_fstring_debug.py index 76a448ca06..95abd4d6d0 100644 --- a/tests/basics/string_fstring_debug.py +++ b/tests/basics/string_fstring_debug.py @@ -21,3 +21,7 @@ print(f"a {x=:08x} b {y} c") print(f'a {f() + g("foo") + h()=} b') print(f'a {f() + g("foo") + h()=:08x} b') + +print(f"a {1,=} b") +print(f"a {x,y,=} b") +print(f"a {x,1=} b") diff --git a/tests/basics/string_fstring_debug.py.exp b/tests/basics/string_fstring_debug.py.exp index 563030f400..f0309e1c98 100644 --- a/tests/basics/string_fstring_debug.py.exp +++ b/tests/basics/string_fstring_debug.py.exp @@ -4,3 +4,6 @@ a x=1 b 2 c a x=00000001 b 2 c a f() + g("foo") + h()=15 b a f() + g("foo") + h()=0000000f b +a 1,=(1,) b +a x,y,=(1, 2) b +a x,1=(1, 1) b diff --git a/tests/extmod/ure_namedclass.py b/tests/extmod/ure_namedclass.py index 00d58ad98a..4afc09dc0a 100644 --- a/tests/extmod/ure_namedclass.py +++ b/tests/extmod/ure_namedclass.py @@ -15,7 +15,7 @@ def print_groups(match): try: i = 0 while True: - print(m.group(i)) + print(match.group(i)) i += 1 except IndexError: pass @@ -32,3 +32,8 @@ print_groups(m) m = re.match(r"(([0-9]*)([a-z]*)\d*)", "1234hello567") print_groups(m) + +# named class within a class set +print_groups(re.match("([^\s]+)\s*([^\s]+)", "1 23")) +print_groups(re.match("([\s\d]+)([\W]+)", "1 2-+=")) +print_groups(re.match("([\W]+)([^\W]+)([^\S]+)([^\D]+)", " a_1 23")) diff --git a/tools/pyboard.py b/tools/pyboard.py index 55c00fbca1..d0e67d1f31 100755 --- a/tools/pyboard.py +++ b/tools/pyboard.py @@ -67,10 +67,13 @@ Or: """ +import ast +import os +import struct import sys import time -import os -import ast + +from collections import namedtuple try: stdout = sys.stdout.buffer @@ -86,7 +89,15 @@ def stdout_write_bytes(b): class PyboardError(Exception): - pass + def convert(self, info): + if len(self.args) >= 3: + if b"OSError" in self.args[2] and b"ENOENT" in self.args[2]: + return OSError(errno.ENOENT, info) + + return self + + +listdir_result = namedtuple("dir_result", ["name", "st_mode", "st_ino", "st_size"]) class TelnetToSerial: @@ -275,7 +286,15 @@ class Pyboard: delayed = False for attempt in range(wait + 1): try: - self.serial = serial.Serial(device, **serial_kwargs) + if os.name == "nt": + # Windows does not set DTR or RTS by default + self.serial = serial.Serial(**serial_kwargs) + self.serial.dtr = True + self.serial.rts = False + self.serial.port = device + self.serial.open() + else: + self.serial = serial.Serial(device, **serial_kwargs) break except (OSError, IOError): # Py2 and Py3 have different errors if wait == 0: @@ -379,7 +398,7 @@ class Pyboard: def raw_paste_write(self, command_bytes): # Read initial header, with window size. data = self.serial.read(2) - window_size = data[0] | data[1] << 8 + window_size = struct.unpack("