diff --git a/.gitmodules b/.gitmodules
index 5c2363610..35aef82d3 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,7 +1,6 @@
[submodule "lib/axtls"]
path = lib/axtls
- url = https://github.com/pfalcon/axtls
- branch = micropython
+ url = https://github.com/micropython/axtls.git
[submodule "lib/libffi"]
path = lib/libffi
url = https://github.com/atgreen/libffi
diff --git a/LICENSE b/LICENSE
index 7f39931ba..5b5c37f7d 100644
--- a/LICENSE
+++ b/LICENSE
@@ -38,10 +38,6 @@ used during the build process and is not part of the compiled source code.
/cc3000 (BSD-3-clause)
/cc3100 (BSD-3-clause)
/wiznet5k (BSD-3-clause)
- /extmod
- /crypto-algorithms (NONE)
- /re15 (BSD-3-clause)
- /uzlib (Zlib)
/lib
/asf4 (Apache-2.0)
/axtls (BSD-3-clause)
@@ -52,6 +48,7 @@ used during the build process and is not part of the compiled source code.
/berkeley-db-1xx (BSD-4-clause)
/btstack (See btstack/LICENSE)
/cmsis (BSD-3-clause)
+ /crypto-algorithms (NONE)
/libhydrogen (ISC)
/littlefs (BSD-3-clause)
/lwip (BSD-3-clause)
@@ -60,9 +57,11 @@ used during the build process and is not part of the compiled source code.
/nxp_driver (BSD-3-Clause)
/oofatfs (BSD-1-clause)
/pico-sdk (BSD-3-clause)
+ /re15 (BSD-3-clause)
/stm32lib (BSD-3-clause)
/tinytest (BSD-3-clause)
/tinyusb (MIT)
+ /uzlib (Zlib)
/logo (uses OFL-1.1)
/ports
/cc3200
diff --git a/docs/conf.py b/docs/conf.py
index 239934bfa..1a3c18a4f 100755
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -74,7 +74,7 @@ copyright = '- The MicroPython Documentation is Copyright © 2014-2021, Damien P
#
# We don't follow "The short X.Y version" vs "The full version, including alpha/beta/rc tags"
# breakdown, so use the same version identifier for both to avoid confusion.
-version = release = '1.16'
+version = release = '1.17'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
diff --git a/docs/develop/library.rst b/docs/develop/library.rst
index bebddcc8a..47ea2dc8d 100644
--- a/docs/develop/library.rst
+++ b/docs/develop/library.rst
@@ -34,7 +34,7 @@ An example is the ``gc`` module discussed in :ref:`memorymanagement`.
>>> gc.enable()
>>>
-MicroPython has several other builtin standard/core modules like ``io``, ``uarray`` etc.
+MicroPython has several other builtin standard/core modules like ``io``, ``array`` etc.
Adding a new core module involves several modifications.
First, create the ``C`` file in the ``py/`` directory. In this example we are adding a
diff --git a/docs/develop/porting.rst b/docs/develop/porting.rst
index 59dd57000..549227d76 100644
--- a/docs/develop/porting.rst
+++ b/docs/develop/porting.rst
@@ -42,8 +42,8 @@ The basic MicroPython firmware is implemented in the main port file, e.g ``main.
#include "py/gc.h"
#include "py/mperrno.h"
#include "py/stackctrl.h"
- #include "lib/utils/gchelper.h"
- #include "lib/utils/pyexec.h"
+ #include "shared/runtime/gchelper.h"
+ #include "shared/runtime/pyexec.h"
// Allocate memory for the MicroPython GC heap.
static char heap[4096];
@@ -106,10 +106,10 @@ We also need a Makefile at this point for the port:
SRC_C = \
main.c \
mphalport.c \
- lib/mp-readline/readline.c \
- lib/utils/gchelper_generic.c \
- lib/utils/pyexec.c \
- lib/utils/stdout_helpers.c \
+ shared/readline/readline.c \
+ shared/runtime/gchelper_generic.c \
+ shared/runtime/pyexec.c \
+ shared/runtime/stdout_helpers.c \
# Define the required object files.
OBJ = $(PY_CORE_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o))
@@ -245,8 +245,8 @@ That should give a MicroPython REPL. You can then run commands like:
.. code-block:: bash
MicroPython v1.13 on 2021-01-01; example-board with unknown-cpu
- >>> import usys
- >>> usys.implementation
+ >>> import sys
+ >>> sys.implementation
('micropython', (1, 13, 0))
>>>
diff --git a/docs/esp32/quickref.rst b/docs/esp32/quickref.rst
index 77c7027c4..3153ebd57 100644
--- a/docs/esp32/quickref.rst
+++ b/docs/esp32/quickref.rst
@@ -98,7 +98,7 @@ A useful function for connecting to your local WiFi network is::
pass
print('network config:', wlan.ifconfig())
-Once the network is established the :mod:`socket ` module can be used
+Once the network is established the :mod:`socket ` module can be used
to create and use TCP/UDP sockets as usual, and the ``urequests`` module for
convenient HTTP requests.
@@ -113,7 +113,7 @@ to reconnect forever).
Delay and timing
----------------
-Use the :mod:`time ` module::
+Use the :mod:`time
+
+ Quick reference for UNIX and Windows
+ command-line reference
+
+
+ Quick reference for the Zephyr port
+ snippets of useful code and a tutorial
+
diff --git a/docs/wipy/general.rst b/docs/wipy/general.rst
index b1109c495..7f24435db 100644
--- a/docs/wipy/general.rst
+++ b/docs/wipy/general.rst
@@ -296,8 +296,8 @@ and put it in '/flash/cert/'. Then do::
ss = ssl.wrap_socket(s, cert_reqs=ssl.CERT_REQUIRED, ca_certs='/flash/cert/ca.pem')
ss.connect(socket.getaddrinfo('cloud.blynk.cc', 8441)[0][-1])
-Incompatibilities in uhashlib module
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Incompatibilities in hashlib module
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Due to hardware implementation details of the WiPy, data must be buffered before being
digested, which would make it impossible to calculate the hash of big blocks of data that
@@ -310,7 +310,7 @@ initial one) is a multiple of 4 bytes.** The last chunk may be of any length.
Example::
- hash = uhashlib.sha1('abcd1234', 1001) # length of the initial piece is multiple of 4 bytes
+ hash = hashlib.sha1('abcd1234', 1001) # length of the initial piece is multiple of 4 bytes
hash.update('1234') # also multiple of 4 bytes
...
hash.update('12345') # last chunk may be of any length
@@ -366,7 +366,7 @@ Adhoc VFS-like support
~~~~~~~~~~~~~~~~~~~~~~
WiPy doesn't implement full MicroPython VFS support, instead following
-functions are defined in ``uos`` module:
+functions are defined in ``os`` module:
.. function:: mount(block_device, mount_point, \*, readonly=False)
diff --git a/docs/wipy/quickref.rst b/docs/wipy/quickref.rst
index a22ea45b5..f9ea3d501 100644
--- a/docs/wipy/quickref.rst
+++ b/docs/wipy/quickref.rst
@@ -107,8 +107,8 @@ See :ref:`machine.SPI `. ::
from machine import SPI
- # configure the SPI master @ 2MHz
- spi = SPI(0, SPI.MASTER, baudrate=200000, polarity=0, phase=0)
+ # configure the SPI controller @ 2MHz
+ spi = SPI(0, SPI.CONTROLLER, baudrate=2_000_000, polarity=0, phase=0)
spi.write('hello')
spi.read(5) # receive 5 bytes on the bus
rbuf = bytearray(5)
@@ -122,11 +122,11 @@ See :ref:`machine.I2C `. ::
from machine import I2C
# configure the I2C bus
i2c = I2C(baudrate=100000)
- i2c.scan() # returns list of slave addresses
- i2c.writeto(0x42, 'hello') # send 5 bytes to slave with address 0x42
- i2c.readfrom(0x42, 5) # receive 5 bytes from slave
- i2c.readfrom_mem(0x42, 0x10, 2) # read 2 bytes from slave 0x42, slave memory 0x10
- i2c.writeto_mem(0x42, 0x10, 'xy') # write 2 bytes to slave 0x42, slave memory 0x10
+ i2c.scan() # returns list of peripheral addresses
+ i2c.writeto(0x42, 'hello') # send 5 bytes to peripheral with address 0x42
+ i2c.readfrom(0x42, 5) # receive 5 bytes from peripheral
+ i2c.readfrom_mem(0x42, 0x10, 2) # read 2 bytes from peripheral 0x42, peripheral memory 0x10
+ i2c.writeto_mem(0x42, 0x10, 'xy') # write 2 bytes to peripheral 0x42, peripheral memory 0x10
Watchdog timer (WDT)
--------------------
diff --git a/docs/zephyr/general.rst b/docs/zephyr/general.rst
new file mode 100644
index 000000000..362f03ada
--- /dev/null
+++ b/docs/zephyr/general.rst
@@ -0,0 +1,22 @@
+.. _zephyr_general:
+
+General information about the Zephyr port
+=========================================
+
+The Zephyr Project is a Linux Foundation hosted Collaboration Project. It’s an open
+source collaborative effort uniting developers and users in building a
+small, scalable, real-time operating system (RTOS) optimized for resource-constrained
+devices, across multiple architectures.
+
+Multitude of boards
+-------------------
+
+There is a multitude of modules and boards from different sources that are supported
+by the Zephyr OS. All boards supported by Zephyr (with standard level of features
+support, like UART console) should work with MicroPython (but not all were tested).
+The FRDM-K64f board is taken as a reference board for the port for this documentation.
+If you have another board, please make sure you have a datasheet, schematics and other
+reference materials for your board handy to look up various aspects of your board
+functioning.
+
+For a full list of Zephyr supported boards click `here (external link) `_
diff --git a/docs/zephyr/quickref.rst b/docs/zephyr/quickref.rst
new file mode 100644
index 000000000..783621316
--- /dev/null
+++ b/docs/zephyr/quickref.rst
@@ -0,0 +1,157 @@
+.. _zephyr_quickref:
+
+Quick reference for the Zephyr port
+===================================
+
+Below is a quick reference for the Zephyr port. If it is your first time working with this port please consider reading the following sections first:
+
+.. toctree::
+ :maxdepth: 1
+
+ general.rst
+ tutorial/index.rst
+
+Running MicroPython
+-------------------
+
+See the corresponding section of the tutorial: :ref:`intro`.
+
+Delay and timing
+----------------
+
+Use the :mod:`time ` module::
+
+ import time
+
+ time.sleep(1) # sleep for 1 second
+ time.sleep_ms(500) # sleep for 500 milliseconds
+ time.sleep_us(10) # sleep for 10 microseconds
+ start = time.ticks_ms() # get millisecond counter
+ delta = time.ticks_diff(time.ticks_ms(), start) # compute time difference
+
+Pins and GPIO
+-------------
+
+Use the :ref:`machine.Pin ` class::
+
+ from machine import Pin
+
+ pin = Pin(("GPIO_1", 21), Pin.IN) # create input pin on GPIO1
+ print(pin) # print pin port and number
+
+ pin.init(Pin.OUT, Pin.PULL_UP, value=1) # reinitialize pin
+
+ pin.value(1) # set pin to high
+ pin.value(0) # set pin to low
+
+ pin.on() # set pin to high
+ pin.off() # set pin to low
+
+ pin = Pin(("GPIO_1", 21), Pin.IN) # create input pin on GPIO1
+
+ pin = Pin(("GPIO_1", 21), Pin.OUT, value=1) # set pin high on creation
+
+ pin = Pin(("GPIO_1", 21), Pin.IN, Pin.PULL_UP) # enable internal pull-up resistor
+
+ switch = Pin(("GPIO_2", 6), Pin.IN) # create input pin for a switch
+ switch.irq(lambda t: print("SW2 changed")) # enable an interrupt when switch state is changed
+
+Hardware I2C bus
+----------------
+
+Hardware I2C is accessed via the :ref:`machine.I2C ` class::
+
+ from machine import I2C
+
+ i2c = I2C("I2C_0") # construct an i2c bus
+ print(i2c) # print device name
+
+ i2c.scan() # scan the device for available I2C slaves
+
+ i2c.readfrom(0x1D, 4) # read 4 bytes from slave 0x1D
+ i2c.readfrom_mem(0x1D, 0x0D, 1) # read 1 byte from slave 0x1D at slave memory 0x0D
+
+ i2c.writeto(0x1D, b'abcd') # write to slave with address 0x1D
+ i2c.writeto_mem(0x1D, 0x0D, b'ab') # write to slave 0x1D at slave memory 0x0D
+
+ buf = bytearray(8) # create buffer of size 8
+ i2c.writeto(0x1D, b'abcd') # write buf to slave 0x1D
+
+Hardware SPI bus
+----------------
+
+Hardware SPI is accessed via the :ref:`machine.SPI ` class::
+
+ from machine import SPI
+
+ spi = SPI("SPI_0") # construct a spi bus with default configuration
+ spi.init(baudrate=100000, polarity=0, phase=0, bits=8, firstbit=SPI.MSB) # set configuration
+
+ # equivalently, construct spi bus and set configuration at the same time
+ spi = SPI("SPI_0", baudrate=100000, polarity=0, phase=0, bits=8, firstbit=SPI.MSB)
+ print(spi) # print device name and bus configuration
+
+ spi.read(4) # read 4 bytes on MISO
+ spi.read(4, write=0xF) # read 4 bytes while writing 0xF on MOSI
+
+ buf = bytearray(8) # create a buffer of size 8
+ spi.readinto(buf) # read into the buffer (reads number of bytes equal to the buffer size)
+ spi.readinto(buf, 0xF) # read into the buffer while writing 0xF on MOSI
+
+ spi.write(b'abcd') # write 4 bytes on MOSI
+
+ buf = bytearray(4) # create buffer of size 8
+ spi.write_readinto(b'abcd', buf) # write to MOSI and read from MISO into the buffer
+ spi.write_readinto(buf, buf) # write buf to MOSI and read back into the buf
+
+Disk Access
+-----------
+
+Use the :ref:`zephyr.DiskAccess ` class to support filesystem::
+
+ import os
+ from zephyr import DiskAccess
+
+ block_dev = DiskAccess('SDHC') # create a block device object for an SD card
+ os.VfsFat.mkfs(block_dev) # create FAT filesystem object using the disk storage block
+ os.mount(block_dev, '/sd') # mount the filesystem at the SD card subdirectory
+
+ # with the filesystem mounted, files can be manipulated as normal
+ with open('/sd/hello.txt','w') as f: # open a new file in the directory
+ f.write('Hello world') # write to the file
+ print(open('/sd/hello.txt').read()) # print contents of the file
+
+Flash Area
+----------
+
+Use the :ref:`zephyr.FlashArea ` class to support filesystem::
+
+ import os
+ from zephyr import FlashArea
+
+ block_dev = FlashArea(4, 4096) # creates a block device object in the frdm-k64f flash scratch partition
+ os.VfsLfs2.mkfs(block_dev) # create filesystem in lfs2 format using the flash block device
+ os.mount(block_dev, '/flash') # mount the filesystem at the flash subdirectory
+
+ # with the filesystem mounted, files can be manipulated as normal
+ with open('/flash/hello.txt','w') as f: # open a new file in the directory
+ f.write('Hello world') # write to the file
+ print(open('/flash/hello.txt').read()) # print contents of the file
+
+Sensor
+------
+
+Use the :ref:`zsensor.Sensor ` class to access sensor data::
+
+ import zsensor
+ from zsensor import Sensor
+
+ accel = Sensor("FXOX8700") # create sensor object for the accelerometer
+
+ 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
diff --git a/docs/zephyr/tutorial/index.rst b/docs/zephyr/tutorial/index.rst
new file mode 100644
index 000000000..218156b3b
--- /dev/null
+++ b/docs/zephyr/tutorial/index.rst
@@ -0,0 +1,16 @@
+.. _zephyr_tutorial:
+
+MicroPython tutorial for the Zephyr port
+========================================
+
+This tutorial is intended to get you started with the Zephyr port.
+
+.. toctree::
+ :maxdepth: 1
+ :numbered:
+
+ intro.rst
+ repl.rst
+ storage.rst
+ pins.rst
+
diff --git a/docs/zephyr/tutorial/intro.rst b/docs/zephyr/tutorial/intro.rst
new file mode 100644
index 000000000..ffdbea8b3
--- /dev/null
+++ b/docs/zephyr/tutorial/intro.rst
@@ -0,0 +1,30 @@
+.. _intro_zephyr:
+
+Getting started with MicroPython on the Zephyr port
+===================================================
+
+Let’s get started!
+
+Requirements
+------------
+
+To use the MicroPython Zephyr port, you will need a Zephyr supported board (for a list of acceptable
+boards see :ref:`zephyr_general`).
+
+Powering up
+-----------
+
+If your board has a USB connector on it then most likely it is powered
+through this when connected to your PC. Otherwise you will need to power
+it directly. Please refer to the documentation for your board for
+further details.
+
+Getting and deploying the firmware
+----------------------------------
+
+The first step you will need to do is either clone the `MicroPython repository `_
+or download it from the `MicroPython downloads page `_. If you are an end user of MicroPython,
+it is recommended to start with the stable firmware builds. If you would like to work on development, you may follow the daily
+builds on git.
+
+Next, follow the Zephyr port readme document (``ports/zephyr/README.md``) to build and run the application on your board.
diff --git a/docs/zephyr/tutorial/pins.rst b/docs/zephyr/tutorial/pins.rst
new file mode 100644
index 000000000..8e1d6602a
--- /dev/null
+++ b/docs/zephyr/tutorial/pins.rst
@@ -0,0 +1,46 @@
+.. _pins_zephyr:
+
+GPIO Pins
+=========
+
+Use :ref:`machine.Pin ` to control I/O pins.
+
+For Zephyr, pins are initialized using a tuple of port and pin number ``(\"GPIO_x\", pin#)``
+for the ``id`` value. For example to initialize a pin for the red LED on a FRDM-k64 board::
+
+ LED = Pin(("GPIO_1", 22), Pin.OUT)
+
+Reference your board's datasheet or Zephyr documentation for pin numbers, see below for more examples.
+
+.. list-table:: Pin Formatting
+ :header-rows: 1
+
+ * - Board
+ - Pin
+ - Format
+ * - frdm_k64f
+ - Red LED = PTB22
+ - ("GPIO_1", 22)
+ * - 96b_carbon
+ - LED1 = PD2
+ - ("GPIOD", 2)
+ * - mimxrt685_evk_cm33
+ - Green LED = PIO0_14
+ - ("GPIO0", 14)
+
+Interrupts
+----------
+
+The Zephyr port also supports interrupt handling for Pins using `machine.Pin.irq() `.
+To respond to Pin change IRQs run::
+
+ from machine import Pin
+
+ SW2 = Pin(("GPIO_2", 6), Pin.IN) # create Pin object for switch 2
+ SW3 = Pin(("GPIO_0", 4), Pin.IN) # create Pin object for switch 3
+
+ SW2.irq(lambda t: print("SW2 changed")) # print message when SW2 state is changed (triggers change IRQ)
+ SW3.irq(lambda t: print("SW3 changed")) # print message when SW3 state is changed (triggers change IRQ)
+
+ while True: # wait
+ pass
diff --git a/docs/zephyr/tutorial/repl.rst b/docs/zephyr/tutorial/repl.rst
new file mode 100644
index 000000000..a7e8955d0
--- /dev/null
+++ b/docs/zephyr/tutorial/repl.rst
@@ -0,0 +1,75 @@
+Getting a MicroPython REPL prompt
+=================================
+
+REPL stands for Read Evaluate Print Loop, and is the name given to the
+interactive MicroPython prompt that you can access on your board through
+Zephyr. It is recommended to use REPL to test out your code and run commands.
+
+REPL over the serial port
+-------------------------
+
+The REPL is available on a UART serial peripheral specified for the board by
+the ``zephyr,console`` devicetree node. The baudrate of the REPL is 115200.
+If your board has a USB-serial convertor on it then you should be able to access
+the REPL directly from your PC.
+
+To access the prompt over USB-serial you will need to use a terminal emulator
+program. For a Linux or Mac machine, open a terminal and run::
+
+ screen /dev/ttyACM0 115200
+
+You can also try ``picocom`` or ``minicom`` instead of screen. You may have to use
+``/dev/ttyACM1`` or a higher number for ``ttyACM``. Additional permissions
+may be necessary to access this device (eg group ``uucp`` or ``dialout``, or use sudo).
+For Windows, get a terminal software, such as puTTY and connect via a serial session
+using the proper COM port.
+
+Using the REPL
+--------------
+
+With your serial program open (PuTTY, screen, picocom, etc) you may see a
+blank screen with a flashing cursor. Press Enter (or reset the board) and
+you should be presented with the following text::
+
+ *** Booting Zephyr OS build v2.6.0-rc1-416-g3056c5ec30ad ***
+ MicroPython v2.6.0-rc1-416-g3056c5ec30 on 2021-06-24; zephyr-frdm_k64f with mk64f12
+ Type "help()" for more information.
+ >>>
+
+Now you can try running MicroPython code directly on your board.
+
+Anything you type at the prompt, indicated by ``>>>``, will be executed after you press
+the Enter key. If there is an error with the text that you enter then an error
+message is printed.
+
+Start by typing the following at the prompt to make sure it is working::
+
+ >>> print("hello world!")
+ hello world!
+
+If you already know some python you can now try some basic commands here. For
+example::
+
+ >>> 1 + 2
+ 3
+ >>> 1 / 2
+ 0.5
+ >>> 3 * 'Zephyr'
+ ZephyrZephyrZephyr
+
+If your board has an LED, you can blink it using the following code::
+
+ >>>import time
+ >>>from machine import Pin
+
+ >>>LED = Pin(("GPIO_1", 21), Pin.OUT)
+ >>>while True:
+ ... LED.value(1)
+ ... time.sleep(0.5)
+ ... LED.value(0)
+ ... time.sleep(0.5)
+
+The above code uses an LED location for a FRDM-K64F board (port B, pin 21;
+following Zephyr conventions ports are identified by "GPIO_x", where *x*
+starts from 0). You will need to adjust it for another board using the board's
+reference materials.
diff --git a/docs/zephyr/tutorial/storage.rst b/docs/zephyr/tutorial/storage.rst
new file mode 100644
index 000000000..12bd0d0d3
--- /dev/null
+++ b/docs/zephyr/tutorial/storage.rst
@@ -0,0 +1,56 @@
+.. _storage_zephyr:
+
+Filesystems and Storage
+=======================
+
+Storage modules support virtual filesystem with FAT and littlefs formats, backed by either
+Zephyr DiskAccess or FlashArea (flash map) APIs depending on which the board supports.
+
+See `os Filesystem Mounting `_.
+
+Disk Access
+-----------
+
+The :ref:`zephyr.DiskAccess ` class can be used to access storage devices, such as SD cards.
+This class uses `Zephyr Disk Access API `_ and
+implements the `os.AbstractBlockDev` protocol.
+
+For use with SD card controllers, SD cards must be present at boot & not removed; they will
+be auto detected and initialized by filesystem at boot. Use the disk driver interface and a
+file system to access SD cards via disk access (see below).
+
+Example usage of FatFS with an SD card on the mimxrt1050_evk board::
+
+ import os
+ from zephyr import DiskAccess
+ bdev = zephyr.DiskAccess('SDHC') # create block device object using DiskAccess
+ os.VfsFat.mkfs(bdev) # create FAT filesystem object using the disk storage block
+ os.mount(bdev, '/sd') # mount the filesystem at the SD card subdirectory
+ with open('/sd/hello.txt','w') as f: # open a new file in the directory
+ f.write('Hello world') # write to the file
+ print(open('/sd/hello.txt').read()) # print contents of the file
+
+
+Flash Area
+----------
+
+The :ref:`zephyr.FlashArea ` class can be used to implement a low-level storage system or
+customize filesystem configurations. To store persistent data on the device, using a higher-level filesystem
+API is recommended (see below).
+
+This class uses `Zephyr Flash map API `_ and
+implements the `os.AbstractBlockDev` protocol.
+
+Example usage with the internal flash on the reel_board or the rv32m1_vega_ri5cy board::
+
+ import os
+ from zephyr import FlashArea
+ bdev = FlashArea(FlashArea.STORAGE, 4096) # create block device object using FlashArea
+ os.VfsLfs2.mkfs(bdev) # create Little filesystem object using the flash area block
+ os.mount(bdev, '/flash') # mount the filesystem at the flash storage subdirectory
+ with open('/flash/hello.txt','w') as f: # open a new file in the directory
+ f.write('Hello world') # write to the file
+ print(open('/flash/hello.txt').read()) # print contents of the file
+
+For boards such as the frdm_k64f in which the MicroPython application spills into the default flash storage
+partition, use the scratch partition by replacing ``FlashArea.STORAGE`` with the integer value 4.
diff --git a/drivers/cyw43/cyw43.h b/drivers/cyw43/cyw43.h
index d7f08cb5d..7d3e30f5d 100644
--- a/drivers/cyw43/cyw43.h
+++ b/drivers/cyw43/cyw43.h
@@ -28,7 +28,7 @@
#include "lwip/netif.h"
#include "lwip/dhcp.h"
-#include "lib/netutils/dhcpserver.h"
+#include "shared/netutils/dhcpserver.h"
#include "drivers/cyw43/cyw43_ll.h"
// For trace_flags
diff --git a/drivers/cyw43/cyw43_ctrl.c b/drivers/cyw43/cyw43_ctrl.c
index aaa266b0d..203bc812a 100644
--- a/drivers/cyw43/cyw43_ctrl.c
+++ b/drivers/cyw43/cyw43_ctrl.c
@@ -27,6 +27,7 @@
#include
#include
+#include "py/mperrno.h"
#include "py/mphal.h"
#include "drivers/cyw43/cyw43.h"
#include "pendsv.h"
@@ -52,6 +53,9 @@
#define WIFI_JOIN_STATE_KEYED (0x0800)
#define WIFI_JOIN_STATE_ALL (0x0e01)
+#define CYW43_STA_IS_ACTIVE(self) (((self)->itf_state >> CYW43_ITF_STA) & 1)
+#define CYW43_AP_IS_ACTIVE(self) (((self)->itf_state >> CYW43_ITF_AP) & 1)
+
cyw43_t cyw43_state;
void (*cyw43_poll)(void);
uint32_t cyw43_sleep;
@@ -102,28 +106,25 @@ void cyw43_init(cyw43_t *self) {
}
void cyw43_deinit(cyw43_t *self) {
+ if (cyw43_poll == NULL) {
+ return;
+ }
+
CYW_ENTER
- cyw43_ll_bus_sleep(&self->cyw43_ll, true);
- cyw43_delay_ms(2);
+ // Stop the TCP/IP network interfaces.
cyw43_tcpip_deinit(self, 0);
cyw43_tcpip_deinit(self, 1);
- self->itf_state = 0;
-
- // Disable async polling
+ // Turn off the SDIO bus.
+ #if USE_SDIOIT
sdio_enable_irq(false);
- cyw43_poll = NULL;
-
- #ifdef pyb_pin_WL_RFSW_VDD
- // Turn the RF-switch off
- mp_hal_pin_low(pyb_pin_WL_RFSW_VDD);
#endif
-
- // Power down the WL chip and the SDIO bus
- mp_hal_pin_low(pyb_pin_WL_REG_ON);
sdio_deinit();
+ // Power off the WLAN chip and make sure all state is reset.
+ cyw43_init(self);
+
CYW_EXIT
}
@@ -478,7 +479,7 @@ void cyw43_wifi_set_up(cyw43_t *self, int itf, bool up) {
int cyw43_wifi_scan(cyw43_t *self, cyw43_wifi_scan_options_t *opts, void *env, int (*result_cb)(void*, const cyw43_ev_scan_result_t*)) {
if (self->itf_state == 0) {
- return -1;
+ return -MP_EPERM;
}
cyw43_ensure_up(self);
@@ -521,6 +522,10 @@ int cyw43_wifi_link_status(cyw43_t *self, int itf) {
// WiFi STA
int cyw43_wifi_join(cyw43_t *self, size_t ssid_len, const uint8_t *ssid, size_t key_len, const uint8_t *key, uint32_t auth_type, const uint8_t *bssid, uint32_t channel) {
+ if (!CYW43_STA_IS_ACTIVE(self)) {
+ return -MP_EPERM;
+ }
+
int ret = cyw43_ensure_up(self);
if (ret) {
return ret;
diff --git a/drivers/cyw43/cyw43_lwip.c b/drivers/cyw43/cyw43_lwip.c
index f3ca59e3a..16ae60237 100644
--- a/drivers/cyw43/cyw43_lwip.c
+++ b/drivers/cyw43/cyw43_lwip.c
@@ -28,7 +28,7 @@
#include
#include "py/mphal.h"
-#include "lib/netutils/netutils.h"
+#include "shared/netutils/netutils.h"
#include "lwip/etharp.h"
#include "lwip/dns.h"
#include "lwip/apps/mdns.h"
diff --git a/drivers/neopixel/manifest.py b/drivers/neopixel/manifest.py
new file mode 100644
index 000000000..27f610adc
--- /dev/null
+++ b/drivers/neopixel/manifest.py
@@ -0,0 +1,5 @@
+freeze(
+ ".",
+ "neopixel.py",
+ opt=3,
+)
diff --git a/drivers/neopixel/neopixel.py b/drivers/neopixel/neopixel.py
new file mode 100644
index 000000000..0032d3618
--- /dev/null
+++ b/drivers/neopixel/neopixel.py
@@ -0,0 +1,46 @@
+# NeoPixel driver for MicroPython
+# MIT license; Copyright (c) 2016 Damien P. George, 2021 Jim Mussared
+
+from machine import bitstream
+
+
+class NeoPixel:
+ # G R B W
+ ORDER = (1, 0, 2, 3)
+
+ def __init__(self, pin, n, bpp=3, timing=1):
+ self.pin = pin
+ self.n = n
+ self.bpp = bpp
+ self.buf = bytearray(n * bpp)
+ self.pin.init(pin.OUT)
+ # Timing arg can either be 1 for 800kHz or 0 for 400kHz,
+ # or a user-specified timing ns tuple (high_0, low_0, high_1, low_1).
+ self.timing = (
+ ((400, 850, 800, 450) if timing else (800, 1700, 1600, 900))
+ if isinstance(timing, int)
+ else timing
+ )
+
+ def __len__(self):
+ return self.n
+
+ def __setitem__(self, i, v):
+ offset = i * self.bpp
+ for i in range(self.bpp):
+ self.buf[offset + self.ORDER[i]] = v[i]
+
+ def __getitem__(self, i):
+ offset = i * self.bpp
+ return tuple(self.buf[offset + self.ORDER[i]] for i in range(self.bpp))
+
+ def fill(self, v):
+ b = self.buf
+ for i in range(self.bpp):
+ c = v[i]
+ for j in range(self.ORDER[i], len(self.buf), self.bpp):
+ b[j] = c
+
+ def write(self):
+ # BITSTREAM_TYPE_HIGH_LOW = 0
+ bitstream(self.pin, 0, self.timing, self.buf)
diff --git a/examples/embedding/Makefile.upylib b/examples/embedding/Makefile.upylib
index 00def493d..14260a719 100644
--- a/examples/embedding/Makefile.upylib
+++ b/examples/embedding/Makefile.upylib
@@ -82,9 +82,9 @@ endif
endif
ifeq ($(MICROPY_USE_READLINE),1)
-INC += -I$(MPTOP)/lib/mp-readline
+INC += -I$(MPTOP)/shared/readline
CFLAGS_MOD += -DMICROPY_USE_READLINE=1
-LIB_SRC_C_EXTRA += mp-readline/readline.c
+SHARED_SRC_C_EXTRA += readline/readline.c
endif
ifeq ($(MICROPY_USE_READLINE),2)
CFLAGS_MOD += -DMICROPY_USE_READLINE=2
@@ -145,19 +145,19 @@ SRC_C = $(addprefix ports/unix/,\
$(SRC_MOD) \
)
-LIB_SRC_C = $(addprefix lib/,\
- $(LIB_SRC_C_EXTRA) \
- utils/printf.c \
- utils/gchelper_generic.c \
+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)/, $(LIB_SRC_C:.c=.o))
+OBJ += $(addprefix $(BUILD)/, $(SHARED_SRC_C:.c=.o))
# List of sources for qstr extraction
-SRC_QSTR += $(SRC_C) $(LIB_SRC_C)
+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 +=
diff --git a/extmod/axtls-include/axtls_os_port.h b/extmod/axtls-include/axtls_os_port.h
new file mode 100644
index 000000000..ef2683acf
--- /dev/null
+++ b/extmod/axtls-include/axtls_os_port.h
@@ -0,0 +1,55 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 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 AXTLS_OS_PORT_H
+#define AXTLS_OS_PORT_H
+
+#include
+#include "py/stream.h"
+#include "lib/crypto-algorithms/sha256.h"
+
+#define SSL_CTX_MUTEX_INIT(mutex)
+#define SSL_CTX_MUTEX_DESTROY(mutex)
+#define SSL_CTX_LOCK(mutex)
+#define SSL_CTX_UNLOCK(mutex)
+
+#define SOCKET_READ(s, buf, size) mp_stream_posix_read((void *)s, buf, size)
+#define SOCKET_WRITE(s, buf, size) mp_stream_posix_write((void *)s, buf, size)
+#define SOCKET_CLOSE(A) UNUSED
+#define SOCKET_ERRNO() errno
+
+#define SHA256_CTX CRYAL_SHA256_CTX
+#define SHA256_Init(ctx) sha256_init(ctx)
+#define SHA256_Update(ctx, buf, size) sha256_update(ctx, buf, size)
+#define SHA256_Final(hash, ctx) sha256_final(ctx, hash)
+
+#define TTY_FLUSH()
+
+#ifdef WDEV_HWRNG
+// For esp8266 port: use the hardware RNG.
+#define PLATFORM_RNG_U8() (*WDEV_HWRNG)
+#endif
+
+#endif // AXTLS_OS_PORT_H
diff --git a/extmod/btstack/btstack.mk b/extmod/btstack/btstack.mk
index e65ceb04a..7ecc23000 100644
--- a/extmod/btstack/btstack.mk
+++ b/extmod/btstack/btstack.mk
@@ -67,7 +67,7 @@ endif
LIB_SRC_C += $(SRC_BTSTACK)
# Suppress some warnings.
-BTSTACK_WARNING_CFLAGS = -Wno-old-style-definition -Wno-unused-variable -Wno-unused-parameter # -Wimplicit-fallthrough=0
+BTSTACK_WARNING_CFLAGS = -Wno-old-style-definition -Wno-unused-variable -Wno-unused-parameter -Wno-implicit-fallthrough
ifneq ($(CC),clang)
BTSTACK_WARNING_CFLAGS += -Wno-format
endif
diff --git a/extmod/btstack/modbluetooth_btstack.c b/extmod/btstack/modbluetooth_btstack.c
index 9c8887803..4e81e21fe 100644
--- a/extmod/btstack/modbluetooth_btstack.c
+++ b/extmod/btstack/modbluetooth_btstack.c
@@ -1085,11 +1085,14 @@ int mp_bluetooth_gatts_read(uint16_t value_handle, uint8_t **value, size_t *valu
return mp_bluetooth_gatts_db_read(MP_STATE_PORT(bluetooth_btstack_root_pointers)->gatts_db, value_handle, value, value_len);
}
-int mp_bluetooth_gatts_write(uint16_t value_handle, const uint8_t *value, size_t value_len) {
+int mp_bluetooth_gatts_write(uint16_t value_handle, const uint8_t *value, size_t value_len, bool send_update) {
DEBUG_printf("mp_bluetooth_gatts_write\n");
if (!mp_bluetooth_is_active()) {
return ERRNO_BLUETOOTH_NOT_ACTIVE;
}
+ if (send_update) {
+ return MP_EOPNOTSUPP;
+ }
return mp_bluetooth_gatts_db_write(MP_STATE_PORT(bluetooth_btstack_root_pointers)->gatts_db, value_handle, value, value_len);
}
diff --git a/extmod/extmod.cmake b/extmod/extmod.cmake
index a54047519..c6b45b0d3 100644
--- a/extmod/extmod.cmake
+++ b/extmod/extmod.cmake
@@ -4,8 +4,9 @@ set(MICROPY_EXTMOD_DIR "${MICROPY_DIR}/extmod")
set(MICROPY_OOFATFS_DIR "${MICROPY_DIR}/lib/oofatfs")
set(MICROPY_SOURCE_EXTMOD
- ${MICROPY_DIR}/lib/embed/abort_.c
- ${MICROPY_DIR}/lib/utils/printf.c
+ ${MICROPY_DIR}/shared/libc/abort_.c
+ ${MICROPY_DIR}/shared/libc/printf.c
+ ${MICROPY_EXTMOD_DIR}/machine_bitstream.c
${MICROPY_EXTMOD_DIR}/machine_i2c.c
${MICROPY_EXTMOD_DIR}/machine_mem.c
${MICROPY_EXTMOD_DIR}/machine_pulse.c
diff --git a/extmod/extmod.mk b/extmod/extmod.mk
index b000b058d..ff24a549a 100644
--- a/extmod/extmod.mk
+++ b/extmod/extmod.mk
@@ -153,7 +153,7 @@ LWIP_DIR = lib/lwip/src
INC += -I$(TOP)/$(LWIP_DIR)/include
CFLAGS_MOD += -DMICROPY_PY_LWIP=1
$(BUILD)/$(LWIP_DIR)/core/ipv4/dhcp.o: CFLAGS_MOD += -Wno-address
-SRC_MOD += extmod/modlwip.c lib/netutils/netutils.c
+SRC_MOD += extmod/modlwip.c shared/netutils/netutils.c
SRC_MOD += $(addprefix $(LWIP_DIR)/,\
apps/mdns/mdns.c \
core/def.c \
diff --git a/extmod/machine_bitstream.c b/extmod/machine_bitstream.c
new file mode 100644
index 000000000..30f1ff1ea
--- /dev/null
+++ b/extmod/machine_bitstream.c
@@ -0,0 +1,65 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Jim Mussared
+ * Copyright (c) 2021 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/runtime.h"
+#include "py/mphal.h"
+#include "extmod/machine_bitstream.h"
+
+#if MICROPY_PY_MACHINE_BITSTREAM
+
+// Timing is a 4-tuple of (high_time_0, low_time_0, high_time_1, low_time_1)
+// suitable for driving WS2812.
+#define MICROPY_MACHINE_BITSTREAM_TYPE_HIGH_LOW (0)
+
+// machine.bitstream(pin, encoding, (timing), bytes)
+STATIC mp_obj_t machine_bitstream_(size_t n_args, const mp_obj_t *args) {
+ mp_hal_pin_obj_t pin = mp_hal_get_pin_obj(args[0]);
+ int encoding = mp_obj_get_int(args[1]);
+
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(args[3], &bufinfo, MP_BUFFER_READ);
+
+ switch (encoding) {
+ case MICROPY_MACHINE_BITSTREAM_TYPE_HIGH_LOW: {
+ uint32_t timing_ns[4];
+ mp_obj_t *timing;
+ mp_obj_get_array_fixed_n(args[2], 4, &timing);
+ for (size_t i = 0; i < 4; ++i) {
+ timing_ns[i] = mp_obj_get_int(timing[i]);
+ }
+ machine_bitstream_high_low(pin, timing_ns, bufinfo.buf, bufinfo.len);
+ break;
+ }
+ default:
+ mp_raise_ValueError(MP_ERROR_TEXT("encoding"));
+ }
+
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_bitstream_obj, 4, 4, machine_bitstream_);
+
+#endif // MICROPY_PY_MACHINE_BITSTREAM
diff --git a/extmod/machine_bitstream.h b/extmod/machine_bitstream.h
new file mode 100644
index 000000000..2e759aedd
--- /dev/null
+++ b/extmod/machine_bitstream.h
@@ -0,0 +1,37 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Jim Mussared
+ * Copyright (c) 2021 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_EXTMOD_MACHINE_BITSTREAM_H
+#define MICROPY_INCLUDED_EXTMOD_MACHINE_BITSTREAM_H
+
+#include "py/obj.h"
+#include "py/mphal.h"
+
+void machine_bitstream_high_low(mp_hal_pin_obj_t pin, uint32_t *timing_ns, const uint8_t *buf, size_t len);
+
+MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(machine_bitstream_obj);
+
+#endif // MICROPY_INCLUDED_EXTMOD_MACHINE_BITSTREAM_H
diff --git a/extmod/modbluetooth.c b/extmod/modbluetooth.c
index e379a8c6a..cb153f70e 100644
--- a/extmod/modbluetooth.c
+++ b/extmod/modbluetooth.c
@@ -717,15 +717,17 @@ STATIC mp_obj_t bluetooth_ble_gatts_read(mp_obj_t self_in, mp_obj_t value_handle
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(bluetooth_ble_gatts_read_obj, bluetooth_ble_gatts_read);
-STATIC mp_obj_t bluetooth_ble_gatts_write(mp_obj_t self_in, mp_obj_t value_handle_in, mp_obj_t data) {
- (void)self_in;
+STATIC mp_obj_t bluetooth_ble_gatts_write(size_t n_args, const mp_obj_t *args) {
mp_buffer_info_t bufinfo = {0};
- mp_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ);
- int err = mp_bluetooth_gatts_write(mp_obj_get_int(value_handle_in), bufinfo.buf, bufinfo.len);
- bluetooth_handle_errno(err);
+ mp_get_buffer_raise(args[2], &bufinfo, MP_BUFFER_READ);
+ bool send_update = false;
+ if (n_args > 3) {
+ send_update = mp_obj_is_true(args[3]);
+ }
+ bluetooth_handle_errno(mp_bluetooth_gatts_write(mp_obj_get_int(args[1]), bufinfo.buf, bufinfo.len, send_update));
return MP_OBJ_NEW_SMALL_INT(bufinfo.len);
}
-STATIC MP_DEFINE_CONST_FUN_OBJ_3(bluetooth_ble_gatts_write_obj, bluetooth_ble_gatts_write);
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_ble_gatts_write_obj, 3, 4, bluetooth_ble_gatts_write);
STATIC mp_obj_t bluetooth_ble_gatts_notify(size_t n_args, const mp_obj_t *args) {
mp_int_t conn_handle = mp_obj_get_int(args[1]);
@@ -842,7 +844,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(bluetooth_ble_gattc_exchange_mtu_obj, bluetooth
STATIC mp_obj_t bluetooth_ble_l2cap_listen(mp_obj_t self_in, mp_obj_t psm_in, mp_obj_t mtu_in) {
(void)self_in;
mp_int_t psm = mp_obj_get_int(psm_in);
- mp_int_t mtu = mp_obj_get_int(mtu_in);
+ mp_int_t mtu = MAX(32, MIN(UINT16_MAX, mp_obj_get_int(mtu_in)));
return bluetooth_handle_errno(mp_bluetooth_l2cap_listen(psm, mtu));
}
STATIC MP_DEFINE_CONST_FUN_OBJ_3(bluetooth_ble_l2cap_listen_obj, bluetooth_ble_l2cap_listen);
@@ -850,7 +852,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_3(bluetooth_ble_l2cap_listen_obj, bluetooth_ble_l
STATIC mp_obj_t bluetooth_ble_l2cap_connect(size_t n_args, const mp_obj_t *args) {
mp_int_t conn_handle = mp_obj_get_int(args[1]);
mp_int_t psm = mp_obj_get_int(args[2]);
- mp_int_t mtu = mp_obj_get_int(args[3]);
+ mp_int_t mtu = MAX(32, MIN(UINT16_MAX, mp_obj_get_int(args[3])));
return bluetooth_handle_errno(mp_bluetooth_l2cap_connect(conn_handle, psm, mtu));
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_ble_l2cap_connect_obj, 4, 4, bluetooth_ble_l2cap_connect);
diff --git a/extmod/modbluetooth.h b/extmod/modbluetooth.h
index d126ad6c1..43519e594 100644
--- a/extmod/modbluetooth.h
+++ b/extmod/modbluetooth.h
@@ -334,8 +334,8 @@ int mp_bluetooth_gatts_register_service_end(void);
// Read the value from the local gatts db (likely this has been written by a central).
int mp_bluetooth_gatts_read(uint16_t value_handle, uint8_t **value, size_t *value_len);
-// Write a value to the local gatts db (ready to be queried by a central).
-int mp_bluetooth_gatts_write(uint16_t value_handle, const uint8_t *value, size_t value_len);
+// Write a value to the local gatts db (ready to be queried by a central). Optionally send notifications/indications.
+int mp_bluetooth_gatts_write(uint16_t value_handle, const uint8_t *value, size_t value_len, bool send_update);
// Notify the central that it should do a read.
int mp_bluetooth_gatts_notify(uint16_t conn_handle, uint16_t value_handle);
// Notify the central, including a data payload. (Note: does not set the gatts db value).
diff --git a/extmod/modframebuf.c b/extmod/modframebuf.c
index 18b170078..454624dda 100644
--- a/extmod/modframebuf.c
+++ b/extmod/modframebuf.c
@@ -491,6 +491,10 @@ STATIC mp_obj_t framebuf_blit(size_t n_args, const mp_obj_t *args) {
if (n_args > 4) {
key = mp_obj_get_int(args[4]);
}
+ mp_obj_framebuf_t *palette = NULL;
+ if (n_args > 5 && args[5] != mp_const_none) {
+ palette = MP_OBJ_TO_PTR(mp_obj_cast_to_native_base(args[5], MP_OBJ_FROM_PTR(&mp_type_framebuf)));
+ }
if (
(x >= self->width) ||
@@ -514,6 +518,9 @@ STATIC mp_obj_t framebuf_blit(size_t n_args, const mp_obj_t *args) {
int cx1 = x1;
for (int cx0 = x0; cx0 < x0end; ++cx0) {
uint32_t col = getpixel(source, cx1, y1);
+ if (palette) {
+ col = getpixel(palette, col, 0);
+ }
if (col != (uint32_t)key) {
setpixel(self, cx0, y0, col);
}
@@ -523,7 +530,7 @@ STATIC mp_obj_t framebuf_blit(size_t n_args, const mp_obj_t *args) {
}
return mp_const_none;
}
-STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(framebuf_blit_obj, 4, 5, framebuf_blit);
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(framebuf_blit_obj, 4, 6, framebuf_blit);
STATIC mp_obj_t framebuf_scroll(mp_obj_t self_in, mp_obj_t xstep_in, mp_obj_t ystep_in) {
mp_obj_framebuf_t *self = MP_OBJ_TO_PTR(self_in);
diff --git a/extmod/modlwip.c b/extmod/modlwip.c
index 1d557a6a8..8811742d6 100644
--- a/extmod/modlwip.c
+++ b/extmod/modlwip.c
@@ -35,7 +35,7 @@
#include "py/mperrno.h"
#include "py/mphal.h"
-#include "lib/netutils/netutils.h"
+#include "shared/netutils/netutils.h"
#include "lwip/init.h"
#include "lwip/tcp.h"
@@ -1502,16 +1502,16 @@ STATIC mp_uint_t lwip_socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_
return 0;
}
- // Deregister callback (pcb.tcp is set to NULL below so must deregister now)
- tcp_arg(socket->pcb.tcp, NULL);
- tcp_err(socket->pcb.tcp, NULL);
- tcp_recv(socket->pcb.tcp, NULL);
-
// Free any incoming buffers or connections that are stored
lwip_socket_free_incoming(socket);
switch (socket->type) {
case MOD_NETWORK_SOCK_STREAM: {
+ // Deregister callback (pcb.tcp is set to NULL below so must deregister now)
+ tcp_arg(socket->pcb.tcp, NULL);
+ tcp_err(socket->pcb.tcp, NULL);
+ tcp_recv(socket->pcb.tcp, NULL);
+
if (socket->pcb.tcp->state != LISTEN) {
// Schedule a callback to abort the connection if it's not cleanly closed after
// the given timeout. The callback must be set before calling tcp_close since
@@ -1525,10 +1525,12 @@ STATIC mp_uint_t lwip_socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_
break;
}
case MOD_NETWORK_SOCK_DGRAM:
+ udp_recv(socket->pcb.udp, NULL, NULL);
udp_remove(socket->pcb.udp);
break;
#if MICROPY_PY_LWIP_SOCK_RAW
case MOD_NETWORK_SOCK_RAW:
+ raw_recv(socket->pcb.raw, NULL, NULL);
raw_remove(socket->pcb.raw);
break;
#endif
diff --git a/extmod/modubinascii.c b/extmod/modubinascii.c
index 9e4f86fbd..fab7717c4 100644
--- a/extmod/modubinascii.c
+++ b/extmod/modubinascii.c
@@ -218,7 +218,7 @@ STATIC mp_obj_t mod_binascii_b2a_base64(mp_obj_t data) {
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_binascii_b2a_base64_obj, mod_binascii_b2a_base64);
#if MICROPY_PY_UBINASCII_CRC32
-#include "uzlib/tinf.h"
+#include "lib/uzlib/tinf.h"
STATIC mp_obj_t mod_binascii_crc32(size_t n_args, const mp_obj_t *args) {
mp_buffer_info_t bufinfo;
diff --git a/extmod/moduhashlib.c b/extmod/moduhashlib.c
index b170de9e5..e97e8cb75 100644
--- a/extmod/moduhashlib.c
+++ b/extmod/moduhashlib.c
@@ -40,7 +40,7 @@
#if MICROPY_SSL_MBEDTLS
#include "mbedtls/sha256.h"
#else
-#include "crypto-algorithms/sha256.h"
+#include "lib/crypto-algorithms/sha256.h"
#endif
#endif
@@ -115,7 +115,7 @@ STATIC mp_obj_t uhashlib_sha256_digest(mp_obj_t self_in) {
#else
-#include "crypto-algorithms/sha256.c"
+#include "lib/crypto-algorithms/sha256.c"
STATIC mp_obj_t uhashlib_sha256_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, 0, 1, false);
diff --git a/extmod/modujson.c b/extmod/modujson.c
index 8dff67358..e5bfb0d96 100644
--- a/extmod/modujson.c
+++ b/extmod/modujson.c
@@ -34,6 +34,62 @@
#if MICROPY_PY_UJSON
+#if MICROPY_PY_UJSON_SEPARATORS
+
+enum {
+ DUMP_MODE_TO_STRING = 1,
+ DUMP_MODE_TO_STREAM = 2,
+};
+
+STATIC mp_obj_t mod_ujson_dump_helper(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args, unsigned int mode) {
+ enum { ARG_separators };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_separators, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
+ };
+
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - mode, pos_args + mode, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_print_ext_t print_ext;
+
+ if (args[ARG_separators].u_obj == mp_const_none) {
+ print_ext.item_separator = ", ";
+ print_ext.key_separator = ": ";
+ } else {
+ mp_obj_t *items;
+ mp_obj_get_array_fixed_n(args[ARG_separators].u_obj, 2, &items);
+ print_ext.item_separator = mp_obj_str_get_str(items[0]);
+ print_ext.key_separator = mp_obj_str_get_str(items[1]);
+ }
+
+ if (mode == DUMP_MODE_TO_STRING) {
+ // dumps(obj)
+ vstr_t vstr;
+ vstr_init_print(&vstr, 8, &print_ext.base);
+ mp_obj_print_helper(&print_ext.base, pos_args[0], PRINT_JSON);
+ return mp_obj_new_str_from_vstr(&mp_type_str, &vstr);
+ } else {
+ // dump(obj, stream)
+ print_ext.base.data = MP_OBJ_TO_PTR(pos_args[1]);
+ print_ext.base.print_strn = mp_stream_write_adaptor;
+ mp_get_stream_raise(pos_args[1], MP_STREAM_OP_WRITE);
+ mp_obj_print_helper(&print_ext.base, pos_args[0], PRINT_JSON);
+ return mp_const_none;
+ }
+}
+
+STATIC mp_obj_t mod_ujson_dump(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ return mod_ujson_dump_helper(n_args, pos_args, kw_args, DUMP_MODE_TO_STREAM);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_ujson_dump_obj, 2, mod_ujson_dump);
+
+STATIC mp_obj_t mod_ujson_dumps(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ return mod_ujson_dump_helper(n_args, pos_args, kw_args, DUMP_MODE_TO_STRING);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_ujson_dumps_obj, 1, mod_ujson_dumps);
+
+#else
+
STATIC mp_obj_t mod_ujson_dump(mp_obj_t obj, mp_obj_t stream) {
mp_get_stream_raise(stream, MP_STREAM_OP_WRITE);
mp_print_t print = {MP_OBJ_TO_PTR(stream), mp_stream_write_adaptor};
@@ -51,6 +107,8 @@ STATIC mp_obj_t mod_ujson_dumps(mp_obj_t obj) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_ujson_dumps_obj, mod_ujson_dumps);
+#endif
+
// The function below implements a simple non-recursive JSON parser.
//
// The JSON specification is at http://www.ietf.org/rfc/rfc4627.txt
diff --git a/extmod/modure.c b/extmod/modure.c
index 220587b42..738a2b984 100644
--- a/extmod/modure.c
+++ b/extmod/modure.c
@@ -37,7 +37,7 @@
#define re1_5_stack_chk() MP_STACK_CHECK()
-#include "re1.5/re1.5.h"
+#include "lib/re1.5/re1.5.h"
#define FLAG_DEBUG 0x1000
@@ -68,7 +68,7 @@ STATIC mp_obj_t match_group(mp_obj_t self_in, mp_obj_t no_in) {
mp_obj_match_t *self = MP_OBJ_TO_PTR(self_in);
mp_int_t no = mp_obj_get_int(no_in);
if (no < 0 || no >= self->num_matches) {
- nlr_raise(mp_obj_new_exception_arg1(&mp_type_IndexError, no_in));
+ mp_raise_type_arg(&mp_type_IndexError, no_in);
}
const char *start = self->caps[no * 2];
@@ -107,7 +107,7 @@ STATIC void match_span_helper(size_t n_args, const mp_obj_t *args, mp_obj_t span
if (n_args == 2) {
no = mp_obj_get_int(args[1]);
if (no < 0 || no >= self->num_matches) {
- nlr_raise(mp_obj_new_exception_arg1(&mp_type_IndexError, args[1]));
+ mp_raise_type_arg(&mp_type_IndexError, args[1]);
}
}
@@ -334,7 +334,7 @@ STATIC mp_obj_t re_sub_helper(size_t n_args, const mp_obj_t *args) {
}
if (match_no >= (unsigned int)match->num_matches) {
- nlr_raise(mp_obj_new_exception_arg1(&mp_type_IndexError, MP_OBJ_NEW_SMALL_INT(match_no)));
+ mp_raise_type_arg(&mp_type_IndexError, MP_OBJ_NEW_SMALL_INT(match_no));
}
const char *start_match = match->caps[match_no * 2];
@@ -454,11 +454,11 @@ const mp_obj_module_t mp_module_ure = {
// only if module is enabled by config setting.
#define re1_5_fatal(x) assert(!x)
-#include "re1.5/compilecode.c"
+#include "lib/re1.5/compilecode.c"
#if MICROPY_PY_URE_DEBUG
-#include "re1.5/dumpcode.c"
+#include "lib/re1.5/dumpcode.c"
#endif
-#include "re1.5/recursiveloop.c"
-#include "re1.5/charclass.c"
+#include "lib/re1.5/recursiveloop.c"
+#include "lib/re1.5/charclass.c"
#endif // MICROPY_PY_URE
diff --git a/extmod/moduselect.c b/extmod/moduselect.c
index fbd51960d..cf47f02af 100644
--- a/extmod/moduselect.c
+++ b/extmod/moduselect.c
@@ -107,6 +107,7 @@ STATIC mp_uint_t poll_map_poll(mp_map_t *poll_map, size_t *rwx_num) {
return n_ready;
}
+#if MICROPY_PY_USELECT_SELECT
// select(rlist, wlist, xlist[, timeout])
STATIC mp_obj_t select_select(size_t n_args, const mp_obj_t *args) {
// get array data from tuple/list arguments
@@ -173,6 +174,7 @@ STATIC mp_obj_t select_select(size_t n_args, const mp_obj_t *args) {
}
}
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_select_select_obj, 3, 4, select_select);
+#endif // MICROPY_PY_USELECT_SELECT
typedef struct _mp_obj_poll_t {
mp_obj_base_t base;
@@ -355,7 +357,9 @@ MP_DEFINE_CONST_FUN_OBJ_0(mp_select_poll_obj, select_poll);
STATIC const mp_rom_map_elem_t mp_module_select_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uselect) },
+ #if MICROPY_PY_USELECT_SELECT
{ MP_ROM_QSTR(MP_QSTR_select), MP_ROM_PTR(&mp_select_select_obj) },
+ #endif
{ MP_ROM_QSTR(MP_QSTR_poll), MP_ROM_PTR(&mp_select_poll_obj) },
{ MP_ROM_QSTR(MP_QSTR_POLLIN), MP_ROM_INT(MP_STREAM_POLL_RD) },
{ MP_ROM_QSTR(MP_QSTR_POLLOUT), MP_ROM_INT(MP_STREAM_POLL_WR) },
diff --git a/extmod/moduzlib.c b/extmod/moduzlib.c
index ab70d6747..f78c34908 100644
--- a/extmod/moduzlib.c
+++ b/extmod/moduzlib.c
@@ -33,7 +33,7 @@
#if MICROPY_PY_UZLIB
-#include "uzlib/tinf.h"
+#include "lib/uzlib/tinf.h"
#if 0 // print debugging info
#define DEBUG_printf DEBUG_printf
@@ -201,7 +201,7 @@ STATIC mp_obj_t mod_uzlib_decompress(size_t n_args, const mp_obj_t *args) {
return res;
error:
- nlr_raise(mp_obj_new_exception_arg1(&mp_type_ValueError, MP_OBJ_NEW_SMALL_INT(st)));
+ mp_raise_type_arg(&mp_type_ValueError, MP_OBJ_NEW_SMALL_INT(st));
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_uzlib_decompress_obj, 1, 3, mod_uzlib_decompress);
@@ -223,10 +223,10 @@ const mp_obj_module_t mp_module_uzlib = {
// Source files #include'd here to make sure they're compiled in
// only if module is enabled by config setting.
-#include "uzlib/tinflate.c"
-#include "uzlib/tinfzlib.c"
-#include "uzlib/tinfgzip.c"
-#include "uzlib/adler32.c"
-#include "uzlib/crc32.c"
+#include "lib/uzlib/tinflate.c"
+#include "lib/uzlib/tinfzlib.c"
+#include "lib/uzlib/tinfgzip.c"
+#include "lib/uzlib/adler32.c"
+#include "lib/uzlib/crc32.c"
#endif // MICROPY_PY_UZLIB
diff --git a/extmod/network_cyw43.c b/extmod/network_cyw43.c
index adbe427b1..a5ed5d5b8 100644
--- a/extmod/network_cyw43.c
+++ b/extmod/network_cyw43.c
@@ -196,7 +196,7 @@ STATIC mp_obj_t network_cyw43_scan(size_t n_args, const mp_obj_t *pos_args, mp_m
int scan_res = cyw43_wifi_scan(self->cyw, &opts, MP_OBJ_TO_PTR(res), network_cyw43_scan_cb);
if (scan_res < 0) {
- mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("STA must be active"));
+ mp_raise_OSError(-scan_res);
}
// Wait for scan to finish, with a 10s timeout
@@ -240,7 +240,7 @@ STATIC mp_obj_t network_cyw43_connect(size_t n_args, const mp_obj_t *pos_args, m
}
int ret = cyw43_wifi_join(self->cyw, ssid.len, ssid.buf, key.len, key.buf, args[ARG_auth].u_int, bssid.buf, args[ARG_channel].u_int);
if (ret != 0) {
- mp_raise_OSError(ret);
+ mp_raise_OSError(-ret);
}
return mp_const_none;
}
diff --git a/extmod/nimble/hal/hal_uart.c b/extmod/nimble/hal/hal_uart.c
index cd5e49e30..84a964fde 100644
--- a/extmod/nimble/hal/hal_uart.c
+++ b/extmod/nimble/hal/hal_uart.c
@@ -27,6 +27,7 @@
#include "py/runtime.h"
#include "py/mphal.h"
#include "nimble/ble.h"
+#include "extmod/nimble/modbluetooth_nimble.h"
#include "extmod/nimble/hal/hal_uart.h"
#include "extmod/nimble/nimble/nimble_npl_os.h"
#include "extmod/mpbthci.h"
@@ -74,6 +75,11 @@ void hal_uart_start_tx(uint32_t port) {
#endif
mp_bluetooth_hci_uart_write(mp_bluetooth_hci_cmd_buf, len);
+
+ if (len > 0) {
+ // Allow modbluetooth bindings to hook "sent packet" (e.g. to unstall l2cap channels).
+ mp_bluetooth_nimble_sent_hci_packet();
+ }
}
int hal_uart_close(uint32_t port) {
diff --git a/extmod/nimble/modbluetooth_nimble.c b/extmod/nimble/modbluetooth_nimble.c
index f4b9ccb60..e4b4cb68a 100644
--- a/extmod/nimble/modbluetooth_nimble.c
+++ b/extmod/nimble/modbluetooth_nimble.c
@@ -512,6 +512,11 @@ STATIC int central_gap_event_cb(struct ble_gap_event *event, void *arg) {
return 0;
}
+
+ case BLE_GAP_EVENT_SUBSCRIBE: {
+ DEBUG_printf("central_gap_event_cb: subscribe: handle=%d, reason=%d notify=%d indicate=%d \n", event->subscribe.attr_handle, event->subscribe.reason, event->subscribe.cur_notify, event->subscribe.cur_indicate);
+ return 0;
+ }
}
return commmon_gap_event_cb(event, arg);
@@ -1004,11 +1009,15 @@ int mp_bluetooth_gatts_read(uint16_t value_handle, uint8_t **value, size_t *valu
return mp_bluetooth_gatts_db_read(MP_STATE_PORT(bluetooth_nimble_root_pointers)->gatts_db, value_handle, value, value_len);
}
-int mp_bluetooth_gatts_write(uint16_t value_handle, const uint8_t *value, size_t value_len) {
+int mp_bluetooth_gatts_write(uint16_t value_handle, const uint8_t *value, size_t value_len, bool send_update) {
if (!mp_bluetooth_is_active()) {
return ERRNO_BLUETOOTH_NOT_ACTIVE;
}
- return mp_bluetooth_gatts_db_write(MP_STATE_PORT(bluetooth_nimble_root_pointers)->gatts_db, value_handle, value, value_len);
+ int err = mp_bluetooth_gatts_db_write(MP_STATE_PORT(bluetooth_nimble_root_pointers)->gatts_db, value_handle, value, value_len);
+ if (err == 0 && send_update) {
+ ble_gatts_chr_updated(value_handle);
+ }
+ return err;
}
// TODO: Could use ble_gatts_chr_updated to send to all subscribed centrals.
@@ -1392,6 +1401,18 @@ int mp_bluetooth_gattc_exchange_mtu(uint16_t conn_handle) {
#endif // MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT
+#if MICROPY_PY_BLUETOOTH_ENABLE_L2CAP_CHANNELS
+STATIC void unstall_l2cap_channel(void);
+#endif
+
+void mp_bluetooth_nimble_sent_hci_packet(void) {
+ #if MICROPY_PY_BLUETOOTH_ENABLE_L2CAP_CHANNELS
+ if (os_msys_num_free() >= os_msys_count() * 3 / 4) {
+ unstall_l2cap_channel();
+ }
+ #endif
+}
+
#if MICROPY_PY_BLUETOOTH_ENABLE_L2CAP_CHANNELS
// Fortunately NimBLE uses mbuf chains correctly with L2CAP COC (rather than
@@ -1413,6 +1434,7 @@ typedef struct _mp_bluetooth_nimble_l2cap_channel_t {
struct os_mempool sdu_mempool;
struct os_mbuf *rx_pending;
bool irq_in_progress;
+ bool mem_stalled;
uint16_t mtu;
os_membuf_t sdu_mem[];
} mp_bluetooth_nimble_l2cap_channel_t;
@@ -1430,6 +1452,19 @@ STATIC void destroy_l2cap_channel() {
}
}
+STATIC void unstall_l2cap_channel(void) {
+ // Whenever we send an HCI packet and the sys mempool is now less than 1/4 full,
+ // we can unstall the L2CAP channel if it was marked as "mem_stalled" by
+ // mp_bluetooth_l2cap_send. (This happens if the pool is half-empty).
+ mp_bluetooth_nimble_l2cap_channel_t *chan = MP_STATE_PORT(bluetooth_nimble_root_pointers)->l2cap_chan;
+ if (!chan || !chan->mem_stalled) {
+ return;
+ }
+ DEBUG_printf("unstall_l2cap_channel: count %d, free: %d\n", os_msys_count(), os_msys_num_free());
+ chan->mem_stalled = false;
+ mp_bluetooth_on_l2cap_send_ready(chan->chan->conn_handle, chan->chan->scid, 0);
+}
+
STATIC int l2cap_channel_event(struct ble_l2cap_event *event, void *arg) {
DEBUG_printf("l2cap_channel_event: type=%d\n", event->type);
mp_bluetooth_nimble_l2cap_channel_t *chan = (mp_bluetooth_nimble_l2cap_channel_t *)arg;
@@ -1525,9 +1560,13 @@ STATIC int l2cap_channel_event(struct ble_l2cap_event *event, void *arg) {
}
case BLE_L2CAP_EVENT_COC_TX_UNSTALLED: {
DEBUG_printf("l2cap_channel_event: tx_unstalled: conn_handle=%d status=%d\n", event->tx_unstalled.conn_handle, event->tx_unstalled.status);
- ble_l2cap_get_chan_info(event->receive.chan, &info);
- // Map status to {0,1} (i.e. "sent everything", or "partial send").
- mp_bluetooth_on_l2cap_send_ready(event->tx_unstalled.conn_handle, info.scid, event->tx_unstalled.status == 0 ? 0 : 1);
+ assert(event->tx_unstalled.conn_handle == chan->chan->conn_handle);
+ // Don't unstall if we're still waiting for room in the sys pool.
+ if (!chan->mem_stalled) {
+ ble_l2cap_get_chan_info(event->receive.chan, &info);
+ // Map status to {0,1} (i.e. "sent everything", or "partial send").
+ mp_bluetooth_on_l2cap_send_ready(event->tx_unstalled.conn_handle, info.scid, event->tx_unstalled.status == 0 ? 0 : 1);
+ }
break;
}
case BLE_L2CAP_EVENT_COC_RECONFIG_COMPLETED: {
@@ -1675,14 +1714,35 @@ int mp_bluetooth_l2cap_send(uint16_t conn_handle, uint16_t cid, const uint8_t *b
return MP_ENOMEM;
}
+ *stalled = false;
+
err = ble_l2cap_send(chan->chan, sdu_tx);
if (err == BLE_HS_ESTALLED) {
// Stalled means that this one will still send but any future ones
// will fail until we receive an unstalled event.
+ DEBUG_printf("mp_bluetooth_l2cap_send: credit stall\n");
*stalled = true;
err = 0;
} else {
- *stalled = false;
+ if (err) {
+ // Anything except stalled means it won't attempt to send,
+ // so free the mbuf (we're failing the op entirely).
+ os_mbuf_free_chain(sdu_tx);
+ }
+ }
+
+ if (os_msys_num_free() <= os_msys_count() / 2) {
+ // If the sys mempool is less than half-full, then back off sending more
+ // on this channel.
+ DEBUG_printf("mp_bluetooth_l2cap_send: forcing mem stall: count %d, free: %d\n", os_msys_count(), os_msys_num_free());
+ chan->mem_stalled = true;
+ *stalled = true;
+ }
+
+ // Sometimes we see what looks like BLE_HS_EAGAIN (but it's actually
+ // OS_ENOMEM in disguise). Fixed in NimBLE v1.4.
+ if (err == OS_ENOMEM) {
+ err = BLE_HS_ENOMEM;
}
// Other error codes such as BLE_HS_EBUSY (we're stalled) or BLE_HS_EBADDATA (bigger than MTU).
diff --git a/extmod/nimble/modbluetooth_nimble.h b/extmod/nimble/modbluetooth_nimble.h
index 9ed64368b..15648a995 100644
--- a/extmod/nimble/modbluetooth_nimble.h
+++ b/extmod/nimble/modbluetooth_nimble.h
@@ -71,5 +71,8 @@ void mp_bluetooth_nimble_port_start(void);
// Tell the port to stop its background task.
void mp_bluetooth_nimble_port_shutdown(void);
+// --- Called by the HCI UART layer to let us know when packets have been sent.
+void mp_bluetooth_nimble_sent_hci_packet(void);
+
#endif // MICROPY_INCLUDED_EXTMOD_NIMBLE_MODBLUETOOTH_NIMBLE_H
diff --git a/extmod/uasyncio/stream.py b/extmod/uasyncio/stream.py
index 8de2d2599..af3b8feab 100644
--- a/extmod/uasyncio/stream.py
+++ b/extmod/uasyncio/stream.py
@@ -79,8 +79,8 @@ async def open_connection(host, port):
from uerrno import EINPROGRESS
import usocket as socket
- ai = socket.getaddrinfo(host, port)[0] # TODO this is blocking!
- s = socket.socket()
+ ai = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM)[0] # TODO this is blocking!
+ s = socket.socket(ai[0], ai[1], ai[2])
s.setblocking(False)
ss = Stream(s)
try:
diff --git a/extmod/uos_dupterm.c b/extmod/uos_dupterm.c
index b66180387..d55767de2 100644
--- a/extmod/uos_dupterm.c
+++ b/extmod/uos_dupterm.c
@@ -33,7 +33,7 @@
#include "py/objarray.h"
#include "py/stream.h"
#include "extmod/misc.h"
-#include "lib/utils/interrupt_char.h"
+#include "shared/runtime/interrupt_char.h"
#if MICROPY_PY_OS_DUPTERM
diff --git a/extmod/utime_mphal.c b/extmod/utime_mphal.c
index d053cf128..3d1cdfd82 100644
--- a/extmod/utime_mphal.c
+++ b/extmod/utime_mphal.c
@@ -48,7 +48,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(mp_utime_sleep_obj, time_sleep);
STATIC mp_obj_t time_sleep_ms(mp_obj_t arg) {
mp_int_t ms = mp_obj_get_int(arg);
- if (ms > 0) {
+ if (ms >= 0) {
mp_hal_delay_ms(ms);
}
return mp_const_none;
diff --git a/extmod/vfs_fat.c b/extmod/vfs_fat.c
index 644be57ae..41284500b 100644
--- a/extmod/vfs_fat.c
+++ b/extmod/vfs_fat.c
@@ -37,7 +37,7 @@
#include "py/mperrno.h"
#include "lib/oofatfs/ff.h"
#include "extmod/vfs_fat.h"
-#include "lib/timeutils/timeutils.h"
+#include "shared/timeutils/timeutils.h"
#if FF_MAX_SS == FF_MIN_SS
#define SECSIZE(fs) (FF_MIN_SS)
diff --git a/extmod/vfs_lfs.c b/extmod/vfs_lfs.c
index dd78269a4..f6a9a2462 100644
--- a/extmod/vfs_lfs.c
+++ b/extmod/vfs_lfs.c
@@ -26,7 +26,7 @@
#include "py/runtime.h"
#include "py/mphal.h"
-#include "lib/timeutils/timeutils.h"
+#include "shared/timeutils/timeutils.h"
#include "extmod/vfs.h"
#include "extmod/vfs_lfs.h"
diff --git a/extmod/vfs_lfsx.c b/extmod/vfs_lfsx.c
index f865e4606..e1324f82c 100644
--- a/extmod/vfs_lfsx.c
+++ b/extmod/vfs_lfsx.c
@@ -34,7 +34,7 @@
#include "py/objstr.h"
#include "py/mperrno.h"
#include "extmod/vfs.h"
-#include "lib/timeutils/timeutils.h"
+#include "shared/timeutils/timeutils.h"
STATIC int MP_VFS_LFSx(dev_ioctl)(const struct LFSx_API (config) * c, int cmd, int arg, bool must_return_int) {
mp_obj_t ret = mp_vfs_blockdev_ioctl(c->context, cmd, arg);
diff --git a/lib/README.md b/lib/README.md
index e719821bf..fd7cba910 100644
--- a/lib/README.md
+++ b/lib/README.md
@@ -1,2 +1,3 @@
-This directory contains standard, low-level C libraries with emphasis on
-being independent and efficient. They can be used by any port.
+This directory contains third-party, low-level C libraries and SDKs.
+Libraries that do not target any specific platform are generally chosen
+based on them being independent and efficient.
diff --git a/lib/axtls b/lib/axtls
index 43a6e6bd3..531cab9c2 160000
--- a/lib/axtls
+++ b/lib/axtls
@@ -1 +1 @@
-Subproject commit 43a6e6bd3bbc03dc501e16b89fba0ef042ed3ea0
+Subproject commit 531cab9c278c947d268bd4c94ecab9153a961b43
diff --git a/extmod/crypto-algorithms/sha256.c b/lib/crypto-algorithms/sha256.c
similarity index 100%
rename from extmod/crypto-algorithms/sha256.c
rename to lib/crypto-algorithms/sha256.c
diff --git a/extmod/crypto-algorithms/sha256.h b/lib/crypto-algorithms/sha256.h
similarity index 100%
rename from extmod/crypto-algorithms/sha256.h
rename to lib/crypto-algorithms/sha256.h
diff --git a/lib/lv_bindings b/lib/lv_bindings
index f6bbc2f06..9c591daaf 160000
--- a/lib/lv_bindings
+++ b/lib/lv_bindings
@@ -1 +1 @@
-Subproject commit f6bbc2f06aaec67c1520c53edfaa97cea4a1c74b
+Subproject commit 9c591daaf40c0ee713588d69973c7c22884d435a
diff --git a/lib/pico-sdk b/lib/pico-sdk
index fc10a97c3..bfcbefafc 160000
--- a/lib/pico-sdk
+++ b/lib/pico-sdk
@@ -1 +1 @@
-Subproject commit fc10a97c386f65c1a44c68684fe52a56aaf50df0
+Subproject commit bfcbefafc5d2a210551a4d9d80b4303d4ae0adf7
diff --git a/extmod/re1.5/charclass.c b/lib/re1.5/charclass.c
similarity index 100%
rename from extmod/re1.5/charclass.c
rename to lib/re1.5/charclass.c
diff --git a/extmod/re1.5/compilecode.c b/lib/re1.5/compilecode.c
similarity index 100%
rename from extmod/re1.5/compilecode.c
rename to lib/re1.5/compilecode.c
diff --git a/extmod/re1.5/dumpcode.c b/lib/re1.5/dumpcode.c
similarity index 100%
rename from extmod/re1.5/dumpcode.c
rename to lib/re1.5/dumpcode.c
diff --git a/extmod/re1.5/re1.5.h b/lib/re1.5/re1.5.h
similarity index 100%
rename from extmod/re1.5/re1.5.h
rename to lib/re1.5/re1.5.h
diff --git a/extmod/re1.5/recursiveloop.c b/lib/re1.5/recursiveloop.c
similarity index 100%
rename from extmod/re1.5/recursiveloop.c
rename to lib/re1.5/recursiveloop.c
diff --git a/lib/tinyusb b/lib/tinyusb
index 7b62c71dd..d49938d0f 160000
--- a/lib/tinyusb
+++ b/lib/tinyusb
@@ -1 +1 @@
-Subproject commit 7b62c71dd5ec42e61499d2d83902df9484842670
+Subproject commit d49938d0f5052bce70e55c652b657c0a6a7e84fe
diff --git a/lib/utils/stdout_helpers.c b/lib/utils/stdout_helpers.c
deleted file mode 100644
index 3de119757..000000000
--- a/lib/utils/stdout_helpers.c
+++ /dev/null
@@ -1,26 +0,0 @@
-#include
-#include
-#include "py/mpconfig.h"
-#include "py/mphal.h"
-
-/*
- * Extra stdout functions
- * These can be either optimized for a particular port, or reference
- * implementation below can be used.
- */
-
-// Send "cooked" string of given length, where every occurrence of
-// LF character is replaced with CR LF.
-void mp_hal_stdout_tx_strn_cooked(const char *str, size_t len) {
- while (len--) {
- if (*str == '\n') {
- mp_hal_stdout_tx_strn("\r", 1);
- }
- mp_hal_stdout_tx_strn(str++, 1);
- }
-}
-
-// Send zero-terminated string
-void mp_hal_stdout_tx_str(const char *str) {
- mp_hal_stdout_tx_strn(str, strlen(str));
-}
diff --git a/extmod/uzlib/adler32.c b/lib/uzlib/adler32.c
similarity index 100%
rename from extmod/uzlib/adler32.c
rename to lib/uzlib/adler32.c
diff --git a/extmod/uzlib/crc32.c b/lib/uzlib/crc32.c
similarity index 100%
rename from extmod/uzlib/crc32.c
rename to lib/uzlib/crc32.c
diff --git a/extmod/uzlib/defl_static.h b/lib/uzlib/defl_static.h
similarity index 100%
rename from extmod/uzlib/defl_static.h
rename to lib/uzlib/defl_static.h
diff --git a/extmod/uzlib/tinf.h b/lib/uzlib/tinf.h
similarity index 100%
rename from extmod/uzlib/tinf.h
rename to lib/uzlib/tinf.h
diff --git a/extmod/uzlib/tinf_compat.h b/lib/uzlib/tinf_compat.h
similarity index 100%
rename from extmod/uzlib/tinf_compat.h
rename to lib/uzlib/tinf_compat.h
diff --git a/extmod/uzlib/tinfgzip.c b/lib/uzlib/tinfgzip.c
similarity index 100%
rename from extmod/uzlib/tinfgzip.c
rename to lib/uzlib/tinfgzip.c
diff --git a/extmod/uzlib/tinflate.c b/lib/uzlib/tinflate.c
similarity index 100%
rename from extmod/uzlib/tinflate.c
rename to lib/uzlib/tinflate.c
diff --git a/extmod/uzlib/tinfzlib.c b/lib/uzlib/tinfzlib.c
similarity index 100%
rename from extmod/uzlib/tinfzlib.c
rename to lib/uzlib/tinfzlib.c
diff --git a/extmod/uzlib/uzlib.h b/lib/uzlib/uzlib.h
similarity index 100%
rename from extmod/uzlib/uzlib.h
rename to lib/uzlib/uzlib.h
diff --git a/extmod/uzlib/uzlib_conf.h b/lib/uzlib/uzlib_conf.h
similarity index 100%
rename from extmod/uzlib/uzlib_conf.h
rename to lib/uzlib/uzlib_conf.h
diff --git a/mpy-cross/Makefile b/mpy-cross/Makefile
index 971f2f81a..2189dff90 100644
--- a/mpy-cross/Makefile
+++ b/mpy-cross/Makefile
@@ -48,7 +48,7 @@ LDFLAGS = $(LDFLAGS_MOD) $(LDFLAGS_ARCH) -lm $(LDFLAGS_EXTRA)
SRC_C = \
main.c \
gccollect.c \
- lib/utils/gchelper_generic.c \
+ shared/runtime/gchelper_generic.c \
# Add fmode when compiling with mingw gcc
COMPILER_TARGET := $(shell $(CC) -dumpmachine)
diff --git a/mpy-cross/gccollect.c b/mpy-cross/gccollect.c
index 120f1a225..72d4204c2 100644
--- a/mpy-cross/gccollect.c
+++ b/mpy-cross/gccollect.c
@@ -29,7 +29,7 @@
#include "py/mpstate.h"
#include "py/gc.h"
-#include "lib/utils/gchelper.h"
+#include "shared/runtime/gchelper.h"
#if MICROPY_ENABLE_GC
diff --git a/mpy-cross/mpconfigport.h b/mpy-cross/mpconfigport.h
index 96d372656..e7c8edf13 100644
--- a/mpy-cross/mpconfigport.h
+++ b/mpy-cross/mpconfigport.h
@@ -76,6 +76,7 @@
#define MICROPY_CPYTHON_COMPAT (1)
#define MICROPY_USE_INTERNAL_PRINTF (0)
+#define MICROPY_PY_FSTRINGS (1)
#define MICROPY_PY_BUILTINS_STR_UNICODE (1)
#if !(defined(MICROPY_GCREGS_SETJMP) || defined(__x86_64__) || defined(__i386__) || defined(__thumb2__) || defined(__thumb__) || defined(__arm__))
diff --git a/mpy-cross/mpy-cross.vcxproj b/mpy-cross/mpy-cross.vcxproj
index 74a366712..e70b29ae1 100644
--- a/mpy-cross/mpy-cross.vcxproj
+++ b/mpy-cross/mpy-cross.vcxproj
@@ -89,7 +89,7 @@
-
+
MICROPY_GCREGS_SETJMP
@@ -103,4 +103,4 @@
-
\ No newline at end of file
+
diff --git a/ports/bare-arm/lib.c b/ports/bare-arm/lib.c
index ee7c1d765..6ef450bea 100644
--- a/ports/bare-arm/lib.c
+++ b/ports/bare-arm/lib.c
@@ -54,7 +54,7 @@ void free(void *p) {
}
// These standard string functions are needed by the runtime, and can be
-// provided either by the system or lib/libc/string0.c. The implementations
+// provided either by the system or shared/libc/string0.c. The implementations
// here are very simple.
int memcmp(const void *s1, const void *s2, size_t n) {
diff --git a/ports/cc3200/application.mk b/ports/cc3200/application.mk
index 2125274ae..25a9925ea 100644
--- a/ports/cc3200/application.mk
+++ b/ports/cc3200/application.mk
@@ -140,14 +140,18 @@ APP_MAIN_SRC_C = \
APP_LIB_SRC_C = $(addprefix lib/,\
oofatfs/ff.c \
oofatfs/ffunicode.c \
+ )
+
+APP_SHARED_SRC_C = $(addprefix shared/,\
libc/string0.c \
- mp-readline/readline.c \
+ readline/readline.c \
netutils/netutils.c \
timeutils/timeutils.c \
- utils/gchelper_native.c \
- utils/pyexec.c \
- utils/interrupt_char.c \
- utils/sys_stdio_mphal.c \
+ runtime/gchelper_native.c \
+ runtime/pyexec.c \
+ runtime/interrupt_char.c \
+ runtime/stdout_helpers.c \
+ runtime/sys_stdio_mphal.c \
)
APP_STM_SRC_C = $(addprefix ports/stm32/,\
@@ -157,12 +161,12 @@ 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_LIB_SRC_C:.c=.o) $(APP_STM_SRC_C:.c=.o))
-OBJ += $(BUILD)/lib/utils/gchelper_m3.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)/pins.o
# List of sources for qstr extraction
-SRC_QSTR += $(APP_MODS_SRC_C) $(APP_MISC_SRC_C) $(APP_STM_SRC_C)
+SRC_QSTR += $(APP_MODS_SRC_C) $(APP_MISC_SRC_C) $(APP_STM_SRC_C) $(APP_SHARED_SRC_C)
# Append any auto-generated sources that are needed by sources listed in
# SRC_QSTR
SRC_QSTR_AUTO_DEPS +=
diff --git a/ports/cc3200/bootmgr/bootloader.mk b/ports/cc3200/bootmgr/bootloader.mk
index 44f1b7f42..1dc2f8286 100644
--- a/ports/cc3200/bootmgr/bootloader.mk
+++ b/ports/cc3200/bootmgr/bootloader.mk
@@ -65,14 +65,14 @@ BOOT_PY_SRC_C = $(addprefix py/,\
mpprint.c \
)
-BOOT_LIB_SRC_C = $(addprefix lib/,\
+BOOT_SHARED_SRC_C = $(addprefix shared/,\
+ libc/printf.c \
libc/string0.c \
- utils/printf.c \
)
OBJ = $(addprefix $(BUILD)/, $(BOOT_HAL_SRC_C:.c=.o) $(BOOT_SL_SRC_C:.c=.o) $(BOOT_CC3100_SRC_C:.c=.o) $(BOOT_UTIL_SRC_C:.c=.o) $(BOOT_MISC_SRC_C:.c=.o))
OBJ += $(addprefix $(BUILD)/, $(BOOT_MAIN_SRC_C:.c=.o) $(BOOT_MAIN_SRC_S:.s=.o) $(BOOT_PY_SRC_C:.c=.o))
-OBJ += $(addprefix $(BUILD)/, $(BOOT_LIB_SRC_C:.c=.o))
+OBJ += $(addprefix $(BUILD)/, $(BOOT_SHARED_SRC_C:.c=.o))
# Add the linker script
LINKER_SCRIPT = bootmgr/bootmgr.lds
diff --git a/ports/cc3200/fatfs_port.c b/ports/cc3200/fatfs_port.c
index 993684d8c..39b350db6 100644
--- a/ports/cc3200/fatfs_port.c
+++ b/ports/cc3200/fatfs_port.c
@@ -27,7 +27,7 @@
#include "py/runtime.h"
#include "lib/oofatfs/ff.h"
-#include "lib/timeutils/timeutils.h"
+#include "shared/timeutils/timeutils.h"
#include "mods/pybrtc.h"
#if FF_FS_REENTRANT
diff --git a/ports/cc3200/ftp/ftp.c b/ports/cc3200/ftp/ftp.c
index 37680bc93..d999e810d 100644
--- a/ports/cc3200/ftp/ftp.c
+++ b/ports/cc3200/ftp/ftp.c
@@ -28,7 +28,7 @@
#include
#include "py/runtime.h"
-#include "lib/timeutils/timeutils.h"
+#include "shared/timeutils/timeutils.h"
#include "lib/oofatfs/ff.h"
#include "extmod/vfs.h"
#include "extmod/vfs_fat.h"
diff --git a/ports/cc3200/hal/cc3200_hal.c b/ports/cc3200/hal/cc3200_hal.c
index bdb7d33d4..3a35e39e1 100644
--- a/ports/cc3200/hal/cc3200_hal.c
+++ b/ports/cc3200/hal/cc3200_hal.c
@@ -141,10 +141,6 @@ void mp_hal_delay_ms(mp_uint_t delay) {
}
}
-void mp_hal_stdout_tx_str(const char *str) {
- mp_hal_stdout_tx_strn(str, strlen(str));
-}
-
void mp_hal_stdout_tx_strn(const char *str, size_t len) {
if (MP_STATE_PORT(os_term_dup_obj)) {
if (mp_obj_is_type(MP_STATE_PORT(os_term_dup_obj)->stream_o, &pyb_uart_type)) {
@@ -158,25 +154,6 @@ void mp_hal_stdout_tx_strn(const char *str, size_t len) {
telnet_tx_strn(str, len);
}
-void mp_hal_stdout_tx_strn_cooked (const char *str, size_t len) {
- int32_t nslen = 0;
- const char *_str = str;
-
- for (int i = 0; i < len; i++) {
- if (str[i] == '\n') {
- mp_hal_stdout_tx_strn(_str, nslen);
- mp_hal_stdout_tx_strn("\r\n", 2);
- _str += nslen + 1;
- nslen = 0;
- } else {
- nslen++;
- }
- }
- if (_str < str + len) {
- mp_hal_stdout_tx_strn(_str, nslen);
- }
-}
-
int mp_hal_stdin_rx_chr(void) {
for ( ;; ) {
// read telnet first
diff --git a/ports/cc3200/mods/moduos.c b/ports/cc3200/mods/moduos.c
index 53521fe66..8c3dcf696 100644
--- a/ports/cc3200/mods/moduos.c
+++ b/ports/cc3200/mods/moduos.c
@@ -31,7 +31,7 @@
#include "py/objtuple.h"
#include "py/objstr.h"
#include "py/runtime.h"
-#include "lib/timeutils/timeutils.h"
+#include "shared/timeutils/timeutils.h"
#include "lib/oofatfs/ff.h"
#include "lib/oofatfs/diskio.h"
#include "genhdr/mpversion.h"
diff --git a/ports/cc3200/mods/modusocket.c b/ports/cc3200/mods/modusocket.c
index 5dac0a010..51815a31f 100644
--- a/ports/cc3200/mods/modusocket.c
+++ b/ports/cc3200/mods/modusocket.c
@@ -35,7 +35,7 @@
#include "py/runtime.h"
#include "py/stream.h"
#include "py/mphal.h"
-#include "lib/netutils/netutils.h"
+#include "shared/netutils/netutils.h"
#include "modnetwork.h"
#include "modusocket.h"
diff --git a/ports/cc3200/mods/modutime.c b/ports/cc3200/mods/modutime.c
index e77065ef4..c5ff6072f 100644
--- a/ports/cc3200/mods/modutime.c
+++ b/ports/cc3200/mods/modutime.c
@@ -33,7 +33,7 @@
#include "py/obj.h"
#include "py/smallint.h"
#include "py/mphal.h"
-#include "lib/timeutils/timeutils.h"
+#include "shared/timeutils/timeutils.h"
#include "extmod/utime_mphal.h"
#include "inc/hw_types.h"
#include "inc/hw_ints.h"
diff --git a/ports/cc3200/mods/modwlan.c b/ports/cc3200/mods/modwlan.c
index 7aa8f0e2c..920079b58 100644
--- a/ports/cc3200/mods/modwlan.c
+++ b/ports/cc3200/mods/modwlan.c
@@ -35,8 +35,8 @@
#include "py/runtime.h"
#include "py/stream.h"
#include "py/mphal.h"
-#include "lib/timeutils/timeutils.h"
-#include "lib/netutils/netutils.h"
+#include "shared/timeutils/timeutils.h"
+#include "shared/netutils/netutils.h"
#include "modnetwork.h"
#include "modusocket.h"
#include "modwlan.h"
diff --git a/ports/cc3200/mods/pybrtc.c b/ports/cc3200/mods/pybrtc.c
index f0704eecd..6c1918831 100644
--- a/ports/cc3200/mods/pybrtc.c
+++ b/ports/cc3200/mods/pybrtc.c
@@ -29,7 +29,7 @@
#include "py/obj.h"
#include "py/runtime.h"
#include "py/mperrno.h"
-#include "lib/timeutils/timeutils.h"
+#include "shared/timeutils/timeutils.h"
#include "inc/hw_types.h"
#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
diff --git a/ports/cc3200/mods/pybuart.c b/ports/cc3200/mods/pybuart.c
index ac2af7032..b8e8cbb68 100644
--- a/ports/cc3200/mods/pybuart.c
+++ b/ports/cc3200/mods/pybuart.c
@@ -33,7 +33,7 @@
#include "py/objlist.h"
#include "py/stream.h"
#include "py/mphal.h"
-#include "lib/utils/interrupt_char.h"
+#include "shared/runtime/interrupt_char.h"
#include "inc/hw_types.h"
#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
diff --git a/ports/cc3200/mptask.c b/ports/cc3200/mptask.c
index 71b650ff8..b764c4712 100644
--- a/ports/cc3200/mptask.c
+++ b/ports/cc3200/mptask.c
@@ -33,7 +33,7 @@
#include "py/runtime.h"
#include "py/gc.h"
#include "py/mphal.h"
-#include "lib/mp-readline/readline.h"
+#include "shared/readline/readline.h"
#include "lib/oofatfs/ff.h"
#include "lib/oofatfs/diskio.h"
#include "extmod/vfs.h"
@@ -49,8 +49,8 @@
#include "pybuart.h"
#include "pybpin.h"
#include "pybrtc.h"
-#include "lib/utils/pyexec.h"
-#include "lib/utils/gchelper.h"
+#include "shared/runtime/pyexec.h"
+#include "shared/runtime/gchelper.h"
#include "gccollect.h"
#include "mperror.h"
#include "simplelink.h"
diff --git a/ports/cc3200/telnet/telnet.c b/ports/cc3200/telnet/telnet.c
index 9f51d4cd8..c4daac342 100644
--- a/ports/cc3200/telnet/telnet.c
+++ b/ports/cc3200/telnet/telnet.c
@@ -28,7 +28,7 @@
#include "py/runtime.h"
#include "py/mphal.h"
-#include "lib/utils/interrupt_char.h"
+#include "shared/runtime/interrupt_char.h"
#include "telnet.h"
#include "simplelink.h"
#include "modnetwork.h"
diff --git a/ports/cc3200/util/gccollect.c b/ports/cc3200/util/gccollect.c
index eac0c86b0..0ff179e48 100644
--- a/ports/cc3200/util/gccollect.c
+++ b/ports/cc3200/util/gccollect.c
@@ -30,7 +30,7 @@
#include "py/gc.h"
#include "py/mpthread.h"
-#include "lib/utils/gchelper.h"
+#include "shared/runtime/gchelper.h"
#include "gccollect.h"
/******************************************************************************
diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile
index fc1fc9a33..386e8f98b 100644
--- a/ports/esp32/Makefile
+++ b/ports/esp32/Makefile
@@ -34,6 +34,7 @@ endif
all:
idf.py $(IDFPY_FLAGS) build
@$(PYTHON) makeimg.py \
+ $(BUILD)/sdkconfig \
$(BUILD)/bootloader/bootloader.bin \
$(BUILD)/partition_table/partition-table.bin \
$(BUILD)/micropython.bin \
diff --git a/ports/esp32/boards/GENERIC_C3/mpconfigboard.cmake b/ports/esp32/boards/GENERIC_C3/mpconfigboard.cmake
new file mode 100644
index 000000000..4f3188423
--- /dev/null
+++ b/ports/esp32/boards/GENERIC_C3/mpconfigboard.cmake
@@ -0,0 +1,10 @@
+set(IDF_TARGET esp32c3)
+
+set(SDKCONFIG_DEFAULTS
+ boards/sdkconfig.base
+ boards/sdkconfig.ble
+)
+
+if(NOT MICROPY_FROZEN_MANIFEST)
+ set(MICROPY_FROZEN_MANIFEST ${MICROPY_PORT_DIR}/boards/manifest.py)
+endif()
diff --git a/ports/esp32/boards/GENERIC_C3/mpconfigboard.h b/ports/esp32/boards/GENERIC_C3/mpconfigboard.h
new file mode 100644
index 000000000..d403e70e4
--- /dev/null
+++ b/ports/esp32/boards/GENERIC_C3/mpconfigboard.h
@@ -0,0 +1,8 @@
+// This configuration is for a generic ESP32C3 board with 4MiB (or more) of flash.
+
+#define MICROPY_HW_BOARD_NAME "ESP32C3 module"
+#define MICROPY_HW_MCU_NAME "ESP32C3"
+
+#define MICROPY_HW_ENABLE_SDCARD (0)
+#define MICROPY_PY_MACHINE_DAC (0)
+#define MICROPY_PY_MACHINE_I2S (0)
diff --git a/ports/esp32/boards/GENERIC_C3_USB/mpconfigboard.cmake b/ports/esp32/boards/GENERIC_C3_USB/mpconfigboard.cmake
new file mode 100644
index 000000000..2b65121b9
--- /dev/null
+++ b/ports/esp32/boards/GENERIC_C3_USB/mpconfigboard.cmake
@@ -0,0 +1,11 @@
+set(IDF_TARGET esp32c3)
+
+set(SDKCONFIG_DEFAULTS
+ boards/sdkconfig.base
+ boards/sdkconfig.ble
+ boards/GENERIC_C3_USB/sdkconfig.board
+)
+
+if(NOT MICROPY_FROZEN_MANIFEST)
+ set(MICROPY_FROZEN_MANIFEST ${MICROPY_PORT_DIR}/boards/manifest.py)
+endif()
diff --git a/ports/esp32/boards/GENERIC_C3_USB/mpconfigboard.h b/ports/esp32/boards/GENERIC_C3_USB/mpconfigboard.h
new file mode 100644
index 000000000..d403e70e4
--- /dev/null
+++ b/ports/esp32/boards/GENERIC_C3_USB/mpconfigboard.h
@@ -0,0 +1,8 @@
+// This configuration is for a generic ESP32C3 board with 4MiB (or more) of flash.
+
+#define MICROPY_HW_BOARD_NAME "ESP32C3 module"
+#define MICROPY_HW_MCU_NAME "ESP32C3"
+
+#define MICROPY_HW_ENABLE_SDCARD (0)
+#define MICROPY_PY_MACHINE_DAC (0)
+#define MICROPY_PY_MACHINE_I2S (0)
diff --git a/ports/esp32/boards/GENERIC_C3_USB/sdkconfig.board b/ports/esp32/boards/GENERIC_C3_USB/sdkconfig.board
new file mode 100644
index 000000000..f0cbad00e
--- /dev/null
+++ b/ports/esp32/boards/GENERIC_C3_USB/sdkconfig.board
@@ -0,0 +1,9 @@
+CONFIG_ESP32C3_REV_MIN_3=y
+CONFIG_ESP32C3_REV_MIN=3
+CONFIG_ESP32C3_BROWNOUT_DET=y
+CONFIG_ESP32C3_BROWNOUT_DET_LVL_SEL_7=
+CONFIG_ESP32C3_BROWNOUT_DET_LVL_SEL_4=y
+CONFIG_ESP32C3_BROWNOUT_DET_LVL=4
+CONFIG_ESP_CONSOLE_UART_DEFAULT=
+CONFIG_ESP_CONSOLE_USB_CDC=
+CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG=y
diff --git a/ports/esp32/boards/SIL_WESP32/mpconfigboard.cmake b/ports/esp32/boards/SIL_WESP32/mpconfigboard.cmake
new file mode 100644
index 000000000..885d4eaa2
--- /dev/null
+++ b/ports/esp32/boards/SIL_WESP32/mpconfigboard.cmake
@@ -0,0 +1,10 @@
+set(SDKCONFIG_DEFAULTS
+ boards/sdkconfig.base
+ boards/sdkconfig.ble
+ boards/sdkconfig.240mhz
+ boards/SIL_WESP32/sdkconfig.board
+)
+
+if(NOT MICROPY_FROZEN_MANIFEST)
+ set(MICROPY_FROZEN_MANIFEST ${MICROPY_PORT_DIR}/boards/manifest.py)
+endif()
diff --git a/ports/esp32/boards/SIL_WESP32/mpconfigboard.h b/ports/esp32/boards/SIL_WESP32/mpconfigboard.h
new file mode 100644
index 000000000..fc66aac64
--- /dev/null
+++ b/ports/esp32/boards/SIL_WESP32/mpconfigboard.h
@@ -0,0 +1,2 @@
+#define MICROPY_HW_BOARD_NAME "Silicognition wESP32"
+#define MICROPY_HW_MCU_NAME "ESP32"
diff --git a/ports/esp32/boards/SIL_WESP32/sdkconfig.board b/ports/esp32/boards/SIL_WESP32/sdkconfig.board
new file mode 100644
index 000000000..98eef1d10
--- /dev/null
+++ b/ports/esp32/boards/SIL_WESP32/sdkconfig.board
@@ -0,0 +1,22 @@
+# 16 MB flash
+
+CONFIG_ESPTOOLPY_FLASHSIZE_4MB=
+CONFIG_ESPTOOLPY_FLASHSIZE_8MB=
+CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y
+CONFIG_ESPTOOLPY_FLASHSIZE="16MB"
+
+# Fast flash
+
+CONFIG_FLASHMODE_QIO=y
+CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
+CONFIG_ESP32_REV_MIN_1=y
+
+# OTA
+
+CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE=y
+CONFIG_PARTITION_TABLE_CUSTOM=y
+CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions-16MiB-ota.csv"
+
+# Network name
+
+CONFIG_LWIP_LOCAL_HOSTNAME="wESP32"
diff --git a/ports/esp32/boards/manifest.py b/ports/esp32/boards/manifest.py
index b463c131f..1dc1481a4 100644
--- a/ports/esp32/boards/manifest.py
+++ b/ports/esp32/boards/manifest.py
@@ -5,3 +5,4 @@ freeze("$(MPY_DIR)/drivers/dht", "dht.py")
freeze("$(MPY_DIR)/drivers/onewire")
include("$(MPY_DIR)/extmod/uasyncio/manifest.py")
include("$(MPY_DIR)/extmod/webrepl/manifest.py")
+include("$(MPY_DIR)/drivers/neopixel/manifest.py")
diff --git a/ports/esp32/espneopixel.c b/ports/esp32/espneopixel.c
deleted file mode 100644
index a5937b9c6..000000000
--- a/ports/esp32/espneopixel.c
+++ /dev/null
@@ -1,71 +0,0 @@
-// Original version from https://github.com/adafruit/Adafruit_NeoPixel
-// Modifications by dpgeorge to support auto-CPU-frequency detection
-
-// This is a mash-up of the Due show() code + insights from Michael Miller's
-// ESP8266 work for the NeoPixelBus library: github.com/Makuna/NeoPixelBus
-// Needs to be a separate .c file to enforce ICACHE_RAM_ATTR execution.
-
-#include "py/mpconfig.h"
-#include "py/mphal.h"
-#include "modesp.h"
-
-void IRAM_ATTR esp_neopixel_write(uint8_t pin, uint8_t *pixels, uint32_t numBytes, uint8_t timing) {
- uint8_t *p, *end, pix, mask;
- uint32_t t, time0, time1, period, c, startTime, pinMask, gpio_reg_set, gpio_reg_clear;
-
- if (pin < 32) {
- pinMask = 1 << pin;
- gpio_reg_set = GPIO_OUT_W1TS_REG;
- gpio_reg_clear = GPIO_OUT_W1TC_REG;
- } else {
- pinMask = 1 << (pin - 32);
- gpio_reg_set = GPIO_OUT1_W1TS_REG;
- gpio_reg_clear = GPIO_OUT1_W1TC_REG;
- }
- p = pixels;
- end = p + numBytes;
- pix = *p++;
- mask = 0x80;
- startTime = 0;
-
- uint32_t fcpu = ets_get_cpu_frequency();
-
- if (timing == 1) {
- // 800 KHz
- time0 = (fcpu * 350) / 1000; // 0.35us
- time1 = (fcpu * 800) / 1000; // 0.8us
- period = (fcpu * 1250) / 1000; // 1.25us per bit
- } else {
- // 400 KHz
- time0 = (fcpu * 500) / 1000; // 0.5us
- time1 = (fcpu * 1200) / 1000; // 1.2us
- period = (fcpu * 2500) / 1000; // 2.5us per bit
- }
-
- uint32_t irq_state = mp_hal_quiet_timing_enter();
- for (t = time0;; t = time0) {
- if (pix & mask) {
- t = time1; // Bit high duration
- }
- while (((c = mp_hal_ticks_cpu()) - startTime) < period) {
- ; // Wait for bit start
- }
- GPIO_REG_WRITE(gpio_reg_set, pinMask); // Set high
- startTime = c; // Save start time
- while (((c = mp_hal_ticks_cpu()) - startTime) < t) {
- ; // Wait high duration
- }
- GPIO_REG_WRITE(gpio_reg_clear, pinMask); // Set low
- if (!(mask >>= 1)) { // Next bit/byte
- if (p >= end) {
- break;
- }
- pix = *p++;
- mask = 0x80;
- }
- }
- while ((mp_hal_ticks_cpu() - startTime) < period) {
- ; // Wait for last bit
- }
- mp_hal_quiet_timing_exit(irq_state);
-}
diff --git a/ports/esp32/fatfs_port.c b/ports/esp32/fatfs_port.c
index 7fce654c0..b9ad30a12 100644
--- a/ports/esp32/fatfs_port.c
+++ b/ports/esp32/fatfs_port.c
@@ -28,7 +28,7 @@
#include
#include "lib/oofatfs/ff.h"
-#include "lib/timeutils/timeutils.h"
+#include "shared/timeutils/timeutils.h"
DWORD get_fattime(void) {
struct timeval tv;
diff --git a/ports/esp32/gccollect.c b/ports/esp32/gccollect.c
index 7d5da57e7..403a3c7df 100644
--- a/ports/esp32/gccollect.c
+++ b/ports/esp32/gccollect.c
@@ -35,8 +35,10 @@
#include "py/mpthread.h"
#include "gccollect.h"
#include "soc/cpu.h"
-#include "xtensa/hal.h"
+#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
+
+#include "xtensa/hal.h"
static void gc_collect_inner(int level) {
if (level < XCHAL_NUM_AREGS / 8) {
@@ -64,3 +66,18 @@ void gc_collect(void) {
gc_collect_inner(0);
gc_collect_end();
}
+
+#elif CONFIG_IDF_TARGET_ESP32C3
+
+#include "shared/runtime/gchelper.h"
+
+void gc_collect(void) {
+ gc_collect_start();
+ gc_helper_collect_regs_and_stack();
+ #if MICROPY_PY_THREAD
+ mp_thread_gc_others();
+ #endif
+ gc_collect_end();
+}
+
+#endif
diff --git a/ports/esp32/machine_adc.c b/ports/esp32/machine_adc.c
index 739d47da5..5ac05d56b 100644
--- a/ports/esp32/machine_adc.c
+++ b/ports/esp32/machine_adc.c
@@ -52,6 +52,12 @@ STATIC const madc_obj_t madc_obj[] = {
{{&machine_adc_type}, GPIO_NUM_33, ADC1_CHANNEL_5},
{{&machine_adc_type}, GPIO_NUM_34, ADC1_CHANNEL_6},
{{&machine_adc_type}, GPIO_NUM_35, ADC1_CHANNEL_7},
+ #elif CONFIG_IDF_TARGET_ESP32C3
+ {{&machine_adc_type}, GPIO_NUM_0, ADC1_CHANNEL_0},
+ {{&machine_adc_type}, GPIO_NUM_1, ADC1_CHANNEL_1},
+ {{&machine_adc_type}, GPIO_NUM_2, ADC1_CHANNEL_2},
+ {{&machine_adc_type}, GPIO_NUM_3, ADC1_CHANNEL_3},
+ {{&machine_adc_type}, GPIO_NUM_4, ADC1_CHANNEL_4},
#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
{{&machine_adc_type}, GPIO_NUM_1, ADC1_CHANNEL_0},
{{&machine_adc_type}, GPIO_NUM_2, ADC1_CHANNEL_1},
diff --git a/ports/esp32/machine_bitstream.c b/ports/esp32/machine_bitstream.c
new file mode 100644
index 000000000..9d2bb5724
--- /dev/null
+++ b/ports/esp32/machine_bitstream.c
@@ -0,0 +1,86 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Jim Mussared
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+// This is a translation of the cycle counter implementation in ports/stm32/machine_bitstream.c.
+
+#include "py/mpconfig.h"
+#include "py/mphal.h"
+
+#if MICROPY_PY_MACHINE_BITSTREAM
+
+#define NS_TICKS_OVERHEAD (6)
+
+void IRAM_ATTR machine_bitstream_high_low(mp_hal_pin_obj_t pin, uint32_t *timing_ns, const uint8_t *buf, size_t len) {
+ uint32_t pin_mask, gpio_reg_set, gpio_reg_clear;
+ #if !CONFIG_IDF_TARGET_ESP32C3
+ if (pin >= 32) {
+ pin_mask = 1 << (pin - 32);
+ gpio_reg_set = GPIO_OUT1_W1TS_REG;
+ gpio_reg_clear = GPIO_OUT1_W1TC_REG;
+ } else
+ #endif
+ {
+ pin_mask = 1 << pin;
+ gpio_reg_set = GPIO_OUT_W1TS_REG;
+ gpio_reg_clear = GPIO_OUT_W1TC_REG;
+ }
+
+ // Convert ns to cpu ticks [high_time_0, period_0, high_time_1, period_1].
+ uint32_t fcpu_mhz = ets_get_cpu_frequency();
+ for (size_t i = 0; i < 4; ++i) {
+ timing_ns[i] = fcpu_mhz * timing_ns[i] / 1000;
+ if (timing_ns[i] > NS_TICKS_OVERHEAD) {
+ timing_ns[i] -= NS_TICKS_OVERHEAD;
+ }
+ if (i % 2 == 1) {
+ // Convert low_time to period (i.e. add high_time).
+ timing_ns[i] += timing_ns[i - 1];
+ }
+ }
+
+ uint32_t irq_state = mp_hal_quiet_timing_enter();
+
+ for (size_t i = 0; i < len; ++i) {
+ uint8_t b = buf[i];
+ for (size_t j = 0; j < 8; ++j) {
+ GPIO_REG_WRITE(gpio_reg_set, pin_mask);
+ uint32_t start_ticks = mp_hal_ticks_cpu();
+ uint32_t *t = &timing_ns[b >> 6 & 2];
+ while (mp_hal_ticks_cpu() - start_ticks < t[0]) {
+ ;
+ }
+ GPIO_REG_WRITE(gpio_reg_clear, pin_mask);
+ b <<= 1;
+ while (mp_hal_ticks_cpu() - start_ticks < t[1]) {
+ ;
+ }
+ }
+ }
+
+ mp_hal_quiet_timing_exit(irq_state);
+}
+
+#endif // MICROPY_PY_MACHINE_BITSTREAM
diff --git a/ports/esp32/machine_dac.c b/ports/esp32/machine_dac.c
index 146ef60aa..35826d4a9 100644
--- a/ports/esp32/machine_dac.c
+++ b/ports/esp32/machine_dac.c
@@ -27,15 +27,15 @@
#include
-#include "esp_log.h"
-
-#include "driver/gpio.h"
-#include "driver/dac.h"
-
#include "py/runtime.h"
#include "py/mphal.h"
#include "modmachine.h"
+#if MICROPY_PY_MACHINE_DAC
+
+#include "driver/gpio.h"
+#include "driver/dac.h"
+
typedef struct _mdac_obj_t {
mp_obj_base_t base;
gpio_num_t gpio_id;
@@ -111,3 +111,5 @@ const mp_obj_type_t machine_dac_type = {
.make_new = mdac_make_new,
.locals_dict = (mp_obj_t)&mdac_locals_dict,
};
+
+#endif // MICROPY_PY_MACHINE_DAC
diff --git a/ports/esp32/machine_hw_spi.c b/ports/esp32/machine_hw_spi.c
index 98c0abaef..ca530ba94 100644
--- a/ports/esp32/machine_hw_spi.c
+++ b/ports/esp32/machine_hw_spi.c
@@ -53,6 +53,10 @@
#define MP_HW_SPI_MAX_XFER_BYTES (4092)
#define MP_HW_SPI_MAX_XFER_BITS (MP_HW_SPI_MAX_XFER_BYTES * 8) // Has to be an even multiple of 8
+#if CONFIG_IDF_TARGET_ESP32C3
+#define HSPI_HOST SPI2_HOST
+#endif
+
typedef struct _machine_hw_spi_default_pins_t {
int8_t sck;
int8_t mosi;
@@ -144,9 +148,13 @@ STATIC void machine_hw_spi_init_internal(
changed = true;
}
- if (baudrate != -1 && baudrate != self->baudrate) {
- self->baudrate = baudrate;
- changed = true;
+ if (baudrate != -1) {
+ // calculate the actual clock frequency that the SPI peripheral can produce
+ baudrate = spi_get_actual_clock(APB_CLK_FREQ, baudrate, 0);
+ if (baudrate != self->baudrate) {
+ self->baudrate = baudrate;
+ changed = true;
+ }
}
if (polarity != -1 && polarity != self->polarity) {
@@ -213,7 +221,7 @@ STATIC void machine_hw_spi_init_internal(
.clock_speed_hz = self->baudrate,
.mode = self->phase | (self->polarity << 1),
.spics_io_num = -1, // No CS pin
- .queue_size = 1,
+ .queue_size = 2,
.flags = self->firstbit == MICROPY_PY_MACHINE_SPI_LSB ? SPI_DEVICE_TXBIT_LSBFIRST | SPI_DEVICE_RXBIT_LSBFIRST : 0,
.pre_cb = NULL
};
@@ -269,6 +277,17 @@ STATIC void machine_hw_spi_deinit(mp_obj_base_t *self_in) {
}
}
+STATIC mp_uint_t gcd(mp_uint_t x, mp_uint_t y) {
+ while (x != y) {
+ if (x > y) {
+ x -= y;
+ } else {
+ y -= x;
+ }
+ }
+ return x;
+}
+
STATIC void machine_hw_spi_transfer(mp_obj_base_t *self_in, size_t len, const uint8_t *src, uint8_t *dest) {
machine_hw_spi_obj_t *self = MP_OBJ_TO_PTR(self_in);
@@ -277,13 +296,16 @@ STATIC void machine_hw_spi_transfer(mp_obj_base_t *self_in, size_t len, const ui
return;
}
- struct spi_transaction_t transaction = { 0 };
-
// Round to nearest whole set of bits
int bits_to_send = len * 8 / self->bits * self->bits;
+ if (!bits_to_send) {
+ mp_raise_ValueError(MP_ERROR_TEXT("buffer too short"));
+ }
if (len <= 4) {
+ spi_transaction_t transaction = { 0 };
+
if (src != NULL) {
memcpy(&transaction.tx_data, src, len);
}
@@ -298,26 +320,46 @@ STATIC void machine_hw_spi_transfer(mp_obj_base_t *self_in, size_t len, const ui
} else {
int offset = 0;
int bits_remaining = bits_to_send;
+ int optimum_word_size = 8 * self->bits / gcd(8, self->bits);
+ int max_transaction_bits = MP_HW_SPI_MAX_XFER_BITS / optimum_word_size * optimum_word_size;
+ spi_transaction_t *transaction, *result, transactions[2];
+ int i = 0;
+
+ spi_device_acquire_bus(self->spi, portMAX_DELAY);
while (bits_remaining) {
- memset(&transaction, 0, sizeof(transaction));
+ transaction = transactions + i++ % 2;
+ memset(transaction, 0, sizeof(spi_transaction_t));
- transaction.length =
- bits_remaining > MP_HW_SPI_MAX_XFER_BITS ? MP_HW_SPI_MAX_XFER_BITS : bits_remaining;
+ transaction->length =
+ bits_remaining > max_transaction_bits ? max_transaction_bits : bits_remaining;
if (src != NULL) {
- transaction.tx_buffer = src + offset;
+ transaction->tx_buffer = src + offset;
}
if (dest != NULL) {
- transaction.rx_buffer = dest + offset;
+ transaction->rx_buffer = dest + offset;
}
- spi_device_transmit(self->spi, &transaction);
- bits_remaining -= transaction.length;
+ spi_device_queue_trans(self->spi, transaction, portMAX_DELAY);
+ bits_remaining -= transaction->length;
+
+ if (offset > 0) {
+ // wait for previously queued transaction
+ MP_THREAD_GIL_EXIT();
+ spi_device_get_trans_result(self->spi, &result, portMAX_DELAY);
+ MP_THREAD_GIL_ENTER();
+ }
// doesn't need ceil(); loop ends when bits_remaining is 0
- offset += transaction.length / 8;
+ offset += transaction->length / 8;
}
+
+ // wait for last transaction
+ MP_THREAD_GIL_EXIT();
+ spi_device_get_trans_result(self->spi, &result, portMAX_DELAY);
+ MP_THREAD_GIL_ENTER();
+ spi_device_release_bus(self->spi);
}
}
diff --git a/ports/esp32/machine_i2s.c b/ports/esp32/machine_i2s.c
new file mode 100644
index 000000000..c650a33be
--- /dev/null
+++ b/ports/esp32/machine_i2s.c
@@ -0,0 +1,813 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Mike Teachman
+ *
+ * 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
+#include
+
+#include "py/obj.h"
+#include "py/runtime.h"
+#include "py/misc.h"
+#include "py/stream.h"
+#include "py/objstr.h"
+#include "modmachine.h"
+#include "mphalport.h"
+
+#if MICROPY_PY_MACHINE_I2S
+
+#include "driver/i2s.h"
+#include "soc/i2s_reg.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "freertos/queue.h"
+#include "esp_task.h"
+
+// The I2S module has 3 modes of operation:
+//
+// Mode1: Blocking
+// - readinto() and write() methods block until the supplied buffer is filled (read) or emptied (write)
+// - this is the default mode of operation
+//
+// Mode2: Non-Blocking
+// - readinto() and write() methods return immediately.
+// - buffer filling and emptying happens asynchronously to the main MicroPython task
+// - a callback function is called when the supplied buffer has been filled (read) or emptied (write)
+// - non-blocking mode is enabled when a callback is set with the irq() method
+// - a FreeRTOS task is created to implement the asynchronous background operations
+// - a FreeRTOS queue is used to transfer the supplied buffer to the background task
+//
+// Mode3: Uasyncio
+// - implements the stream protocol
+// - uasyncio mode is enabled when the ioctl() function is called
+// - the I2S event queue is used to detect that I2S samples can be read or written from/to DMA memory
+//
+// The samples contained in the app buffer supplied for the readinto() and write() methods have the following convention:
+// Mono: little endian format
+// Stereo: little endian format, left channel first
+//
+// I2S terms:
+// "frame": consists of two audio samples (Left audio sample + Right audio sample)
+//
+// Misc:
+// - for Mono configuration:
+// - readinto method: samples are gathered from the L channel only
+// - write method: every sample is output to both the L and R channels
+// - for readinto method the I2S hardware is read using 8-byte frames
+// (this is standard for almost all I2S hardware, such as MEMS microphones)
+// - all sample data transfers use DMA
+
+#define I2S_TASK_PRIORITY (ESP_TASK_PRIO_MIN + 1)
+#define I2S_TASK_STACK_SIZE (2048)
+
+#define DMA_BUF_LEN_IN_I2S_FRAMES (256)
+
+// The transform buffer is used with the readinto() method to bridge the opaque DMA memory on the ESP devices
+// with the app buffer. It facilitates audio sample transformations. e.g. 32-bits samples to 16-bit samples.
+// The size of 240 bytes is an engineering optimum that balances transfer performance with an acceptable use of heap space
+#define SIZEOF_TRANSFORM_BUFFER_IN_BYTES (240)
+
+#define NUM_I2S_USER_FORMATS (4)
+#define I2S_RX_FRAME_SIZE_IN_BYTES (8)
+
+typedef enum {
+ MONO,
+ STEREO
+} format_t;
+
+typedef enum {
+ BLOCKING,
+ NON_BLOCKING,
+ UASYNCIO
+} io_mode_t;
+
+typedef enum {
+ I2S_TX_TRANSFER,
+ I2S_RX_TRANSFER,
+} direction_t;
+
+typedef struct _non_blocking_descriptor_t {
+ mp_buffer_info_t appbuf;
+ mp_obj_t callback;
+ direction_t direction;
+} non_blocking_descriptor_t;
+
+typedef struct _machine_i2s_obj_t {
+ mp_obj_base_t base;
+ i2s_port_t port;
+ mp_hal_pin_obj_t sck;
+ mp_hal_pin_obj_t ws;
+ mp_hal_pin_obj_t sd;
+ int8_t mode;
+ i2s_bits_per_sample_t bits;
+ format_t format;
+ int32_t rate;
+ int32_t ibuf;
+ mp_obj_t callback_for_non_blocking;
+ io_mode_t io_mode;
+ uint8_t transform_buffer[SIZEOF_TRANSFORM_BUFFER_IN_BYTES];
+ QueueHandle_t i2s_event_queue;
+ QueueHandle_t non_blocking_mode_queue;
+ TaskHandle_t non_blocking_mode_task;
+} machine_i2s_obj_t;
+
+STATIC mp_obj_t machine_i2s_deinit(mp_obj_t self_in);
+
+// The frame map is used with the readinto() method to transform the audio sample data coming
+// from DMA memory (32-bit stereo, with the L and R channels reversed) to the format specified
+// in the I2S constructor. e.g. 16-bit mono
+STATIC const int8_t i2s_frame_map[NUM_I2S_USER_FORMATS][I2S_RX_FRAME_SIZE_IN_BYTES] = {
+ { 6, 7, -1, -1, -1, -1, -1, -1 }, // Mono, 16-bits
+ { 4, 5, 6, 7, -1, -1, -1, -1 }, // Mono, 32-bits
+ { 6, 7, 2, 3, -1, -1, -1, -1 }, // Stereo, 16-bits
+ { 4, 5, 6, 7, 0, 1, 2, 3 }, // Stereo, 32-bits
+};
+
+STATIC machine_i2s_obj_t *machine_i2s_obj[I2S_NUM_MAX];
+
+void machine_i2s_init0() {
+ for (i2s_port_t p = 0; p < I2S_NUM_MAX; p++) {
+ machine_i2s_obj[p] = NULL;
+ }
+}
+
+// The following function takes a sample buffer and swaps L/R channels
+//
+// Background: For 32-bit stereo, the ESP-IDF API has a L/R channel orientation that breaks
+// convention with other ESP32 channel formats
+//
+// appbuf[] = [L_0-7, L_8-15, L_16-23, L_24-31, R_0-7, R_8-15, R_16-23, R_24-31] = [Left channel, Right channel]
+// dma[] = [R_0-7, R_8-15, R_16-23, R_24-31, L_0-7, L_8-15, L_16-23, L_24-31] = [Right channel, Left channel]
+//
+// where:
+// L_0-7 is the least significant byte of the 32 bit sample in the Left channel
+// L_24-31 is the most significant byte of the 32 bit sample in the Left channel
+//
+// Example:
+//
+// appbuf[] = [0x99, 0xBB, 0x11, 0x22, 0x44, 0x55, 0xAB, 0x77] = [Left channel, Right channel]
+// dma[] = [0x44, 0x55, 0xAB, 0x77, 0x99, 0xBB, 0x11, 0x22] = [Right channel, Left channel]
+// where:
+// LEFT Channel = 0x99, 0xBB, 0x11, 0x22
+// RIGHT Channel = 0x44, 0x55, 0xAB, 0x77
+//
+// samples in appbuf are in little endian format:
+// 0x77 is the most significant byte of the 32-bit sample
+// 0x44 is the least significant byte of the 32-bit sample
+STATIC void swap_32_bit_stereo_channels(mp_buffer_info_t *bufinfo) {
+ int32_t swap_sample;
+ int32_t *sample = bufinfo->buf;
+ uint32_t num_samples = bufinfo->len / 4;
+ for (uint32_t i = 0; i < num_samples; i += 2) {
+ swap_sample = sample[i + 1];
+ sample[i + 1] = sample[i];
+ sample[i] = swap_sample;
+ }
+}
+
+STATIC int8_t get_frame_mapping_index(i2s_bits_per_sample_t bits, format_t format) {
+ if (format == MONO) {
+ if (bits == I2S_BITS_PER_SAMPLE_16BIT) {
+ return 0;
+ } else { // 32 bits
+ return 1;
+ }
+ } else { // STEREO
+ if (bits == I2S_BITS_PER_SAMPLE_16BIT) {
+ return 2;
+ } else { // 32 bits
+ return 3;
+ }
+ }
+}
+
+STATIC i2s_bits_per_sample_t get_dma_bits(uint8_t mode, i2s_bits_per_sample_t bits) {
+ if (mode == (I2S_MODE_MASTER | I2S_MODE_TX)) {
+ return bits;
+ } else { // Master Rx
+ // read 32 bit samples for I2S hardware. e.g. MEMS microphones
+ return I2S_BITS_PER_SAMPLE_32BIT;
+ }
+}
+
+STATIC i2s_channel_fmt_t get_dma_format(uint8_t mode, format_t format) {
+ if (mode == (I2S_MODE_MASTER | I2S_MODE_TX)) {
+ if (format == MONO) {
+ return I2S_CHANNEL_FMT_ONLY_LEFT;
+ } else { // STEREO
+ return I2S_CHANNEL_FMT_RIGHT_LEFT;
+ }
+ } else { // Master Rx
+ // read stereo frames for all I2S hardware
+ return I2S_CHANNEL_FMT_RIGHT_LEFT;
+ }
+}
+
+STATIC uint32_t get_dma_buf_count(uint8_t mode, i2s_bits_per_sample_t bits, format_t format, int32_t ibuf) {
+ // calculate how many DMA buffers need to be allocated
+ uint32_t dma_frame_size_in_bytes =
+ (get_dma_bits(mode, bits) / 8) * (get_dma_format(mode, format) == I2S_CHANNEL_FMT_RIGHT_LEFT ? 2: 1);
+
+ uint32_t dma_buf_count = ibuf / (DMA_BUF_LEN_IN_I2S_FRAMES * dma_frame_size_in_bytes);
+
+ return dma_buf_count;
+}
+
+STATIC uint32_t fill_appbuf_from_dma(machine_i2s_obj_t *self, mp_buffer_info_t *appbuf) {
+
+ // copy audio samples from DMA memory to the app buffer
+ // audio samples are read from DMA memory in chunks
+ // loop, reading and copying chunks until the app buffer is filled
+ // For uasyncio mode, the loop will make an early exit if DMA memory becomes empty
+ // Example:
+ // a MicroPython I2S object is configured for 16-bit mono (2 bytes per audio sample).
+ // For every frame coming from DMA (8 bytes), 2 bytes are "cherry picked" and
+ // copied to the supplied app buffer.
+ // Thus, for every 1 byte copied to the app buffer, 4 bytes are read from DMA memory.
+ // If a 8kB app buffer is supplied, 32kB of audio samples is read from DMA memory.
+
+ uint32_t a_index = 0;
+ uint8_t *app_p = appbuf->buf;
+ uint8_t appbuf_sample_size_in_bytes = (self->bits / 8) * (self->format == STEREO ? 2: 1);
+ uint32_t num_bytes_needed_from_dma = appbuf->len * (I2S_RX_FRAME_SIZE_IN_BYTES / appbuf_sample_size_in_bytes);
+ while (num_bytes_needed_from_dma) {
+ size_t num_bytes_requested_from_dma = MIN(sizeof(self->transform_buffer), num_bytes_needed_from_dma);
+ size_t num_bytes_received_from_dma = 0;
+
+ TickType_t delay;
+ if (self->io_mode == UASYNCIO) {
+ delay = 0; // stop i2s_read() operation if DMA memory becomes empty
+ } else {
+ delay = portMAX_DELAY; // block until supplied buffer is filled
+ }
+
+ // read a chunk of audio samples from DMA memory
+ check_esp_err(i2s_read(
+ self->port,
+ self->transform_buffer,
+ num_bytes_requested_from_dma,
+ &num_bytes_received_from_dma,
+ delay));
+
+ // process the transform buffer one frame at a time.
+ // copy selected bytes from the transform buffer into the user supplied appbuf.
+ // Example:
+ // a MicroPython I2S object is configured for 16-bit mono. This configuration associates to
+ // a frame map index of 0 = { 6, 7, -1, -1, -1, -1, -1, -1 } in the i2s_frame_map array
+ // This mapping indicates:
+ // appbuf[x+0] = frame[6]
+ // appbuf[x+1] = frame[7]
+ // frame bytes 0-5 are not used
+
+ uint32_t t_index = 0;
+ uint8_t f_index = get_frame_mapping_index(self->bits, self->format);
+ while (t_index < num_bytes_received_from_dma) {
+ uint8_t *transform_p = self->transform_buffer + t_index;
+
+ for (uint8_t i = 0; i < I2S_RX_FRAME_SIZE_IN_BYTES; i++) {
+ int8_t t_to_a_mapping = i2s_frame_map[f_index][i];
+ if (t_to_a_mapping != -1) {
+ *app_p++ = transform_p[t_to_a_mapping];
+ a_index++;
+ }
+ t_index++;
+ }
+ }
+
+ num_bytes_needed_from_dma -= num_bytes_received_from_dma;
+
+ if ((self->io_mode == UASYNCIO) && (num_bytes_received_from_dma < num_bytes_requested_from_dma)) {
+ // Unable to fill the entire app buffer from DMA memory. This indicates all DMA RX buffers are empty.
+ // Clear the I2S event queue so ioctl() indicates that the I2S object cannot currently
+ // supply more audio samples
+ xQueueReset(self->i2s_event_queue);
+ break;
+ }
+ }
+
+ return a_index;
+}
+
+STATIC size_t copy_appbuf_to_dma(machine_i2s_obj_t *self, mp_buffer_info_t *appbuf) {
+ if ((self->bits == I2S_BITS_PER_SAMPLE_32BIT) && (self->format == STEREO)) {
+ swap_32_bit_stereo_channels(appbuf);
+ }
+
+ size_t num_bytes_written = 0;
+
+ TickType_t delay;
+ if (self->io_mode == UASYNCIO) {
+ delay = 0; // stop i2s_write() operation if DMA memory becomes full
+ } else {
+ delay = portMAX_DELAY; // block until supplied buffer is emptied
+ }
+
+ check_esp_err(i2s_write(self->port, appbuf->buf, appbuf->len, &num_bytes_written, delay));
+
+ if ((self->io_mode == UASYNCIO) && (num_bytes_written < appbuf->len)) {
+ // Unable to empty the entire app buffer into DMA memory. This indicates all DMA TX buffers are full.
+ // Clear the I2S event queue so ioctl() indicates that the I2S object cannot currently
+ // accept more audio samples
+ xQueueReset(self->i2s_event_queue);
+
+ // Undo the swap transformation as the buffer has not been completely emptied.
+ // The uasyncio stream writer will use the same buffer in a future write call.
+ if ((self->bits == I2S_BITS_PER_SAMPLE_32BIT) && (self->format == STEREO)) {
+ swap_32_bit_stereo_channels(appbuf);
+ }
+ }
+ return num_bytes_written;
+}
+
+// FreeRTOS task used for non-blocking mode
+STATIC void task_for_non_blocking_mode(void *self_in) {
+ machine_i2s_obj_t *self = (machine_i2s_obj_t *)self_in;
+
+ non_blocking_descriptor_t descriptor;
+
+ for (;;) {
+ if (xQueueReceive(self->non_blocking_mode_queue, &descriptor, portMAX_DELAY)) {
+ if (descriptor.direction == I2S_TX_TRANSFER) {
+ copy_appbuf_to_dma(self, &descriptor.appbuf);
+ } else { // RX
+ fill_appbuf_from_dma(self, &descriptor.appbuf);
+ }
+ mp_sched_schedule(descriptor.callback, MP_OBJ_FROM_PTR(self));
+ }
+ }
+}
+
+STATIC void machine_i2s_init_helper(machine_i2s_obj_t *self, size_t n_pos_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+
+ enum {
+ ARG_sck,
+ ARG_ws,
+ ARG_sd,
+ ARG_mode,
+ ARG_bits,
+ ARG_format,
+ ARG_rate,
+ ARG_ibuf,
+ };
+
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_sck, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_ws, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_sd, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_mode, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = -1} },
+ { MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = -1} },
+ { MP_QSTR_format, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = -1} },
+ { MP_QSTR_rate, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = -1} },
+ { MP_QSTR_ibuf, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = -1} },
+ };
+
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_pos_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ //
+ // ---- Check validity of arguments ----
+ //
+
+ // are Pins valid?
+ int8_t sck = args[ARG_sck].u_obj == MP_OBJ_NULL ? -1 : mp_hal_get_pin_obj(args[ARG_sck].u_obj);
+ int8_t ws = args[ARG_ws].u_obj == MP_OBJ_NULL ? -1 : mp_hal_get_pin_obj(args[ARG_ws].u_obj);
+ int8_t sd = args[ARG_sd].u_obj == MP_OBJ_NULL ? -1 : mp_hal_get_pin_obj(args[ARG_sd].u_obj);
+
+ // is Mode valid?
+ i2s_mode_t mode = args[ARG_mode].u_int;
+ if ((mode != (I2S_MODE_MASTER | I2S_MODE_RX)) &&
+ (mode != (I2S_MODE_MASTER | I2S_MODE_TX))) {
+ mp_raise_ValueError(MP_ERROR_TEXT("invalid mode"));
+ }
+
+ // is Bits valid?
+ i2s_bits_per_sample_t bits = args[ARG_bits].u_int;
+ if ((bits != I2S_BITS_PER_SAMPLE_16BIT) &&
+ (bits != I2S_BITS_PER_SAMPLE_32BIT)) {
+ mp_raise_ValueError(MP_ERROR_TEXT("invalid bits"));
+ }
+
+ // is Format valid?
+ format_t format = args[ARG_format].u_int;
+ if ((format != STEREO) &&
+ (format != MONO)) {
+ mp_raise_ValueError(MP_ERROR_TEXT("invalid format"));
+ }
+
+ // is Rate valid?
+ // Not checked: ESP-IDF I2S API does not indicate a valid range for sample rate
+
+ // is Ibuf valid?
+ // Not checked: ESP-IDF I2S API will return error if requested buffer size exceeds available memory
+
+ self->sck = sck;
+ self->ws = ws;
+ self->sd = sd;
+ self->mode = mode;
+ self->bits = bits;
+ self->format = format;
+ self->rate = args[ARG_rate].u_int;
+ self->ibuf = args[ARG_ibuf].u_int;
+ self->callback_for_non_blocking = MP_OBJ_NULL;
+ self->i2s_event_queue = NULL;
+ self->non_blocking_mode_queue = NULL;
+ self->non_blocking_mode_task = NULL;
+ self->io_mode = BLOCKING;
+
+ i2s_config_t i2s_config;
+ i2s_config.communication_format = I2S_COMM_FORMAT_I2S;
+ i2s_config.mode = mode;
+ i2s_config.bits_per_sample = get_dma_bits(mode, bits);
+ i2s_config.channel_format = get_dma_format(mode, format);
+ i2s_config.sample_rate = self->rate;
+ i2s_config.intr_alloc_flags = ESP_INTR_FLAG_LOWMED;
+ i2s_config.dma_buf_count = get_dma_buf_count(mode, bits, format, self->ibuf);
+ i2s_config.dma_buf_len = DMA_BUF_LEN_IN_I2S_FRAMES;
+ i2s_config.use_apll = false;
+
+ // I2S queue size equals the number of DMA buffers
+ check_esp_err(i2s_driver_install(self->port, &i2s_config, i2s_config.dma_buf_count, &self->i2s_event_queue));
+
+ // apply low-level workaround for bug in some ESP-IDF versions that swap
+ // the left and right channels
+ // https://github.com/espressif/esp-idf/issues/6625
+ REG_SET_BIT(I2S_CONF_REG(self->port), I2S_TX_MSB_RIGHT);
+ REG_SET_BIT(I2S_CONF_REG(self->port), I2S_RX_MSB_RIGHT);
+
+ i2s_pin_config_t pin_config;
+ pin_config.bck_io_num = self->sck;
+ pin_config.ws_io_num = self->ws;
+
+ if (mode == (I2S_MODE_MASTER | I2S_MODE_RX)) {
+ pin_config.data_in_num = self->sd;
+ pin_config.data_out_num = -1;
+ } else { // TX
+ pin_config.data_in_num = -1;
+ pin_config.data_out_num = self->sd;
+ }
+
+ check_esp_err(i2s_set_pin(self->port, &pin_config));
+}
+
+STATIC void machine_i2s_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
+ machine_i2s_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_printf(print, "I2S(id=%u,\n"
+ "sck="MP_HAL_PIN_FMT ",\n"
+ "ws="MP_HAL_PIN_FMT ",\n"
+ "sd="MP_HAL_PIN_FMT ",\n"
+ "mode=%u,\n"
+ "bits=%u, format=%u,\n"
+ "rate=%d, ibuf=%d)",
+ self->port,
+ mp_hal_pin_name(self->sck),
+ mp_hal_pin_name(self->ws),
+ mp_hal_pin_name(self->sd),
+ self->mode,
+ self->bits, self->format,
+ self->rate, self->ibuf
+ );
+}
+
+STATIC mp_obj_t machine_i2s_make_new(const mp_obj_type_t *type, size_t n_pos_args, size_t n_kw_args, const mp_obj_t *args) {
+ mp_arg_check_num(n_pos_args, n_kw_args, 1, MP_OBJ_FUN_ARGS_MAX, true);
+
+ i2s_port_t port = mp_obj_get_int(args[0]);
+ if (port < 0 || port >= I2S_NUM_MAX) {
+ mp_raise_ValueError(MP_ERROR_TEXT("invalid id"));
+ }
+
+ machine_i2s_obj_t *self;
+ if (machine_i2s_obj[port] == NULL) {
+ self = m_new_obj(machine_i2s_obj_t);
+ machine_i2s_obj[port] = self;
+ self->base.type = &machine_i2s_type;
+ self->port = port;
+ } else {
+ self = machine_i2s_obj[port];
+ machine_i2s_deinit(self);
+ }
+
+ mp_map_t kw_args;
+ mp_map_init_fixed_table(&kw_args, n_kw_args, args + n_pos_args);
+ machine_i2s_init_helper(self, n_pos_args - 1, args + 1, &kw_args);
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+STATIC mp_obj_t machine_i2s_obj_init(size_t n_pos_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ machine_i2s_obj_t *self = pos_args[0];
+ machine_i2s_deinit(self);
+ machine_i2s_init_helper(self, n_pos_args - 1, pos_args + 1, kw_args);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_i2s_init_obj, 1, machine_i2s_obj_init);
+
+STATIC mp_obj_t machine_i2s_deinit(mp_obj_t self_in) {
+ machine_i2s_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ i2s_driver_uninstall(self->port);
+
+ if (self->non_blocking_mode_task != NULL) {
+ vTaskDelete(self->non_blocking_mode_task);
+ self->non_blocking_mode_task = NULL;
+ }
+
+ if (self->non_blocking_mode_queue != NULL) {
+ vQueueDelete(self->non_blocking_mode_queue);
+ self->non_blocking_mode_queue = NULL;
+ }
+
+ self->i2s_event_queue = NULL;
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_i2s_deinit_obj, machine_i2s_deinit);
+
+STATIC mp_obj_t machine_i2s_irq(mp_obj_t self_in, mp_obj_t handler) {
+ machine_i2s_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ if (handler != mp_const_none && !mp_obj_is_callable(handler)) {
+ mp_raise_ValueError(MP_ERROR_TEXT("invalid callback"));
+ }
+
+ if (handler != mp_const_none) {
+ self->io_mode = NON_BLOCKING;
+
+ // create a queue linking the MicroPython task to a FreeRTOS task
+ // that manages the non blocking mode of operation
+ self->non_blocking_mode_queue = xQueueCreate(1, sizeof(non_blocking_descriptor_t));
+
+ // non-blocking mode requires a background FreeRTOS task
+ if (xTaskCreatePinnedToCore(
+ task_for_non_blocking_mode,
+ "i2s_non_blocking",
+ I2S_TASK_STACK_SIZE,
+ self,
+ I2S_TASK_PRIORITY,
+ (TaskHandle_t *)&self->non_blocking_mode_task,
+ MP_TASK_COREID) != pdPASS) {
+
+ mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("failed to create I2S task"));
+ }
+ } else {
+ if (self->non_blocking_mode_task != NULL) {
+ vTaskDelete(self->non_blocking_mode_task);
+ self->non_blocking_mode_task = NULL;
+ }
+
+ if (self->non_blocking_mode_queue != NULL) {
+ vQueueDelete(self->non_blocking_mode_queue);
+ self->non_blocking_mode_queue = NULL;
+ }
+
+ self->io_mode = BLOCKING;
+ }
+
+ self->callback_for_non_blocking = handler;
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(machine_i2s_irq_obj, machine_i2s_irq);
+
+// Shift() is typically used as a volume control.
+// shift=1 increases volume by 6dB, shift=-1 decreases volume by 6dB
+STATIC mp_obj_t machine_i2s_shift(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_buf, ARG_bits, ARG_shift};
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_buf, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ { MP_QSTR_bits, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
+ { MP_QSTR_shift, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
+ };
+
+ // parse args
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(args[ARG_buf].u_obj, &bufinfo, MP_BUFFER_RW);
+
+ int16_t *buf_16 = bufinfo.buf;
+ int32_t *buf_32 = bufinfo.buf;
+
+ uint8_t bits = args[ARG_bits].u_int;
+ int8_t shift = args[ARG_shift].u_int;
+
+ uint32_t num_audio_samples;
+ switch (bits) {
+ case 16:
+ num_audio_samples = bufinfo.len / 2;
+ break;
+
+ case 32:
+ num_audio_samples = bufinfo.len / 4;
+ break;
+
+ default:
+ mp_raise_ValueError(MP_ERROR_TEXT("invalid bits"));
+ break;
+ }
+
+ for (uint32_t i = 0; i < num_audio_samples; i++) {
+ switch (bits) {
+ case 16:
+ if (shift >= 0) {
+ buf_16[i] = buf_16[i] << shift;
+ } else {
+ buf_16[i] = buf_16[i] >> abs(shift);
+ }
+ break;
+ case 32:
+ if (shift >= 0) {
+ buf_32[i] = buf_32[i] << shift;
+ } else {
+ buf_32[i] = buf_32[i] >> abs(shift);
+ }
+ break;
+ }
+ }
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_i2s_shift_fun_obj, 0, machine_i2s_shift);
+STATIC MP_DEFINE_CONST_STATICMETHOD_OBJ(machine_i2s_shift_obj, MP_ROM_PTR(&machine_i2s_shift_fun_obj));
+
+STATIC const mp_rom_map_elem_t machine_i2s_locals_dict_table[] = {
+ // Methods
+ { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_i2s_init_obj) },
+ { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },
+ { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
+ { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&machine_i2s_deinit_obj) },
+ { MP_ROM_QSTR(MP_QSTR_irq), MP_ROM_PTR(&machine_i2s_irq_obj) },
+
+ // Static method
+ { MP_ROM_QSTR(MP_QSTR_shift), MP_ROM_PTR(&machine_i2s_shift_obj) },
+
+ // Constants
+ { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_INT(I2S_MODE_MASTER | I2S_MODE_RX) },
+ { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_INT(I2S_MODE_MASTER | I2S_MODE_TX) },
+ { MP_ROM_QSTR(MP_QSTR_STEREO), MP_ROM_INT(STEREO) },
+ { MP_ROM_QSTR(MP_QSTR_MONO), MP_ROM_INT(MONO) },
+};
+MP_DEFINE_CONST_DICT(machine_i2s_locals_dict, machine_i2s_locals_dict_table);
+
+STATIC mp_uint_t machine_i2s_stream_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, int *errcode) {
+ machine_i2s_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ if (self->mode != (I2S_MODE_MASTER | I2S_MODE_RX)) {
+ *errcode = MP_EPERM;
+ return MP_STREAM_ERROR;
+ }
+
+ uint8_t appbuf_sample_size_in_bytes = (self->bits / 8) * (self->format == STEREO ? 2: 1);
+ if (size % appbuf_sample_size_in_bytes != 0) {
+ *errcode = MP_EINVAL;
+ return MP_STREAM_ERROR;
+ }
+
+ if (size == 0) {
+ return 0;
+ }
+
+ if (self->io_mode == NON_BLOCKING) {
+ non_blocking_descriptor_t descriptor;
+ descriptor.appbuf.buf = (void *)buf_in;
+ descriptor.appbuf.len = size;
+ descriptor.callback = self->callback_for_non_blocking;
+ descriptor.direction = I2S_RX_TRANSFER;
+ // send the descriptor to the task that handles non-blocking mode
+ xQueueSend(self->non_blocking_mode_queue, &descriptor, 0);
+ return size;
+ } else { // blocking or uasyncio mode
+ mp_buffer_info_t appbuf;
+ appbuf.buf = (void *)buf_in;
+ appbuf.len = size;
+ uint32_t num_bytes_read = fill_appbuf_from_dma(self, &appbuf);
+ return num_bytes_read;
+ }
+}
+
+STATIC mp_uint_t machine_i2s_stream_write(mp_obj_t self_in, const void *buf_in, mp_uint_t size, int *errcode) {
+ machine_i2s_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ if (self->mode != (I2S_MODE_MASTER | I2S_MODE_TX)) {
+ *errcode = MP_EPERM;
+ return MP_STREAM_ERROR;
+ }
+
+ if (size == 0) {
+ return 0;
+ }
+
+ if (self->io_mode == NON_BLOCKING) {
+ non_blocking_descriptor_t descriptor;
+ descriptor.appbuf.buf = (void *)buf_in;
+ descriptor.appbuf.len = size;
+ descriptor.callback = self->callback_for_non_blocking;
+ descriptor.direction = I2S_TX_TRANSFER;
+ // send the descriptor to the task that handles non-blocking mode
+ xQueueSend(self->non_blocking_mode_queue, &descriptor, 0);
+ return size;
+ } else { // blocking or uasyncio mode
+ mp_buffer_info_t appbuf;
+ appbuf.buf = (void *)buf_in;
+ appbuf.len = size;
+ size_t num_bytes_written = copy_appbuf_to_dma(self, &appbuf);
+ return num_bytes_written;
+ }
+}
+
+STATIC mp_uint_t machine_i2s_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) {
+ machine_i2s_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_uint_t ret;
+ mp_uint_t flags = arg;
+ self->io_mode = UASYNCIO; // a call to ioctl() is an indication that uasyncio is being used
+
+ if (request == MP_STREAM_POLL) {
+ ret = 0;
+
+ if (flags & MP_STREAM_POLL_RD) {
+ if (self->mode != (I2S_MODE_MASTER | I2S_MODE_RX)) {
+ *errcode = MP_EPERM;
+ return MP_STREAM_ERROR;
+ }
+
+ i2s_event_t i2s_event;
+
+ // check event queue to determine if a DMA buffer has been filled
+ // (which is an indication that at least one DMA buffer is available to be read)
+ // note: timeout = 0 so the call is non-blocking
+ if (xQueueReceive(self->i2s_event_queue, &i2s_event, 0)) {
+ if (i2s_event.type == I2S_EVENT_RX_DONE) {
+ // getting here means that at least one DMA buffer is now full
+ // indicating that audio samples can be read from the I2S object
+ ret |= MP_STREAM_POLL_RD;
+ }
+ }
+ }
+
+ if (flags & MP_STREAM_POLL_WR) {
+ if (self->mode != (I2S_MODE_MASTER | I2S_MODE_TX)) {
+ *errcode = MP_EPERM;
+ return MP_STREAM_ERROR;
+ }
+
+ i2s_event_t i2s_event;
+
+ // check event queue to determine if a DMA buffer has been emptied
+ // (which is an indication that at least one DMA buffer is available to be written)
+ // note: timeout = 0 so the call is non-blocking
+ if (xQueueReceive(self->i2s_event_queue, &i2s_event, 0)) {
+ if (i2s_event.type == I2S_EVENT_TX_DONE) {
+ // getting here means that at least one DMA buffer is now empty
+ // indicating that audio samples can be written to the I2S object
+ ret |= MP_STREAM_POLL_WR;
+ }
+ }
+ }
+ } else {
+ *errcode = MP_EINVAL;
+ ret = MP_STREAM_ERROR;
+ }
+
+ return ret;
+}
+
+STATIC const mp_stream_p_t i2s_stream_p = {
+ .read = machine_i2s_stream_read,
+ .write = machine_i2s_stream_write,
+ .ioctl = machine_i2s_ioctl,
+ .is_text = false,
+};
+
+const mp_obj_type_t machine_i2s_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_I2S,
+ .print = machine_i2s_print,
+ .getiter = mp_identity_getiter,
+ .iternext = mp_stream_unbuffered_iter,
+ .protocol = &i2s_stream_p,
+ .make_new = machine_i2s_make_new,
+ .locals_dict = (mp_obj_dict_t *)&machine_i2s_locals_dict,
+};
+
+#endif // MICROPY_PY_MACHINE_I2S
diff --git a/ports/esp32/machine_pin.c b/ports/esp32/machine_pin.c
index bd623d041..6c1e96879 100644
--- a/ports/esp32/machine_pin.c
+++ b/ports/esp32/machine_pin.c
@@ -40,11 +40,21 @@
#include "machine_rtc.h"
#include "modesp32.h"
+#if CONFIG_IDF_TARGET_ESP32C3
+#include "hal/gpio_ll.h"
+#endif
+
// Used to implement a range of pull capabilities
#define GPIO_PULL_DOWN (1)
#define GPIO_PULL_UP (2)
#define GPIO_PULL_HOLD (4)
+#if CONFIG_IDF_TARGET_ESP32
+#define GPIO_FIRST_NON_OUTPUT (34)
+#elif CONFIG_IDF_TARGET_ESP32S2
+#define GPIO_FIRST_NON_OUTPUT (46)
+#endif
+
typedef struct _machine_pin_obj_t {
mp_obj_base_t base;
gpio_num_t id;
@@ -99,6 +109,36 @@ STATIC const machine_pin_obj_t machine_pin_obj[] = {
{{&machine_pin_type}, GPIO_NUM_38},
{{&machine_pin_type}, GPIO_NUM_39},
+ #elif CONFIG_IDF_TARGET_ESP32C3
+
+ {{&machine_pin_type}, GPIO_NUM_0},
+ {{&machine_pin_type}, GPIO_NUM_1},
+ {{&machine_pin_type}, GPIO_NUM_2},
+ {{&machine_pin_type}, GPIO_NUM_3},
+ {{&machine_pin_type}, GPIO_NUM_4},
+ {{&machine_pin_type}, GPIO_NUM_5},
+ {{&machine_pin_type}, GPIO_NUM_6},
+ {{&machine_pin_type}, GPIO_NUM_7},
+ {{&machine_pin_type}, GPIO_NUM_8},
+ {{&machine_pin_type}, GPIO_NUM_9},
+ {{&machine_pin_type}, GPIO_NUM_10},
+ {{&machine_pin_type}, GPIO_NUM_11},
+ {{&machine_pin_type}, GPIO_NUM_12},
+ {{&machine_pin_type}, GPIO_NUM_13},
+ {{NULL}, -1}, // 14 FLASH
+ {{NULL}, -1}, // 15 FLASH
+ {{NULL}, -1}, // 16 FLASH
+ {{NULL}, -1}, // 17 FLASH
+ #if CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG
+ {{NULL}, -1}, // 18 is for native USB D-
+ {{NULL}, -1}, // 19 is for native USB D+
+ #else
+ {{&machine_pin_type}, GPIO_NUM_18},
+ {{&machine_pin_type}, GPIO_NUM_19},
+ #endif
+ {{&machine_pin_type}, GPIO_NUM_20},
+ {{&machine_pin_type}, GPIO_NUM_21},
+
#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
{{&machine_pin_type}, GPIO_NUM_0},
@@ -213,10 +253,18 @@ STATIC mp_obj_t machine_pin_obj_init_helper(const machine_pin_obj_t *self, size_
// reset the pin to digital if this is a mode-setting init (grab it back from ADC)
if (args[ARG_mode].u_obj != mp_const_none) {
if (rtc_gpio_is_valid_gpio(self->id)) {
+ #if !CONFIG_IDF_TARGET_ESP32C3
rtc_gpio_deinit(self->id);
+ #endif
}
}
+ #if CONFIG_IDF_TARGET_ESP32C3
+ if (self->id == 18 || self->id == 19) {
+ CLEAR_PERI_REG_MASK(USB_DEVICE_CONF0_REG, USB_DEVICE_USB_PAD_ENABLE);
+ }
+ #endif
+
// configure the pin for gpio
gpio_pad_select_gpio(self->id);
@@ -228,11 +276,12 @@ STATIC mp_obj_t machine_pin_obj_init_helper(const machine_pin_obj_t *self, size_
// configure mode
if (args[ARG_mode].u_obj != mp_const_none) {
mp_int_t pin_io_mode = mp_obj_get_int(args[ARG_mode].u_obj);
- if (self->id >= 34 && (pin_io_mode & GPIO_MODE_DEF_OUTPUT)) {
+ #ifdef GPIO_FIRST_NON_OUTPUT
+ if (self->id >= GPIO_FIRST_NON_OUTPUT && (pin_io_mode & GPIO_MODE_DEF_OUTPUT)) {
mp_raise_ValueError(MP_ERROR_TEXT("pin can only be input"));
- } else {
- gpio_set_direction(self->id, pin_io_mode);
}
+ #endif
+ gpio_set_direction(self->id, pin_io_mode);
}
// configure pull
@@ -494,6 +543,31 @@ STATIC const machine_pin_irq_obj_t machine_pin_irq_object[] = {
{{&machine_pin_irq_type}, GPIO_NUM_38},
{{&machine_pin_irq_type}, GPIO_NUM_39},
+ #elif CONFIG_IDF_TARGET_ESP32C3
+
+ {{&machine_pin_irq_type}, GPIO_NUM_0},
+ {{&machine_pin_irq_type}, GPIO_NUM_1},
+ {{&machine_pin_irq_type}, GPIO_NUM_2},
+ {{&machine_pin_irq_type}, GPIO_NUM_3},
+ {{&machine_pin_irq_type}, GPIO_NUM_4},
+ {{&machine_pin_irq_type}, GPIO_NUM_5},
+ {{&machine_pin_irq_type}, GPIO_NUM_6},
+ {{&machine_pin_irq_type}, GPIO_NUM_7},
+ {{&machine_pin_irq_type}, GPIO_NUM_8},
+ {{&machine_pin_irq_type}, GPIO_NUM_9},
+ {{&machine_pin_irq_type}, GPIO_NUM_10},
+ {{&machine_pin_irq_type}, GPIO_NUM_11},
+ {{&machine_pin_irq_type}, GPIO_NUM_12},
+ {{&machine_pin_irq_type}, GPIO_NUM_13},
+ {{&machine_pin_irq_type}, GPIO_NUM_14},
+ {{&machine_pin_irq_type}, GPIO_NUM_15},
+ {{&machine_pin_irq_type}, GPIO_NUM_16},
+ {{&machine_pin_irq_type}, GPIO_NUM_17},
+ {{&machine_pin_irq_type}, GPIO_NUM_18},
+ {{&machine_pin_irq_type}, GPIO_NUM_19},
+ {{&machine_pin_irq_type}, GPIO_NUM_20},
+ {{&machine_pin_irq_type}, GPIO_NUM_21},
+
#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
{{&machine_pin_irq_type}, GPIO_NUM_0},
diff --git a/ports/esp32/machine_rtc.c b/ports/esp32/machine_rtc.c
index 1b6a71b5b..72d7b5c82 100644
--- a/ports/esp32/machine_rtc.c
+++ b/ports/esp32/machine_rtc.c
@@ -36,7 +36,7 @@
#include "py/obj.h"
#include "py/runtime.h"
#include "py/mphal.h"
-#include "lib/timeutils/timeutils.h"
+#include "shared/timeutils/timeutils.h"
#include "modmachine.h"
#include "machine_rtc.h"
@@ -121,7 +121,7 @@ STATIC mp_obj_t machine_rtc_datetime_helper(mp_uint_t n_args, const mp_obj_t *ar
return mp_const_none;
}
}
-STATIC mp_obj_t machine_rtc_datetime(mp_uint_t n_args, const mp_obj_t *args) {
+STATIC mp_obj_t machine_rtc_datetime(size_t n_args, const mp_obj_t *args) {
return machine_rtc_datetime_helper(n_args, args);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_rtc_datetime_obj, 1, 2, machine_rtc_datetime);
@@ -142,7 +142,7 @@ STATIC mp_obj_t machine_rtc_init(mp_obj_t self_in, mp_obj_t date) {
STATIC MP_DEFINE_CONST_FUN_OBJ_2(machine_rtc_init_obj, machine_rtc_init);
#if MICROPY_HW_RTC_USER_MEM_MAX > 0
-STATIC mp_obj_t machine_rtc_memory(mp_uint_t n_args, const mp_obj_t *args) {
+STATIC mp_obj_t machine_rtc_memory(size_t n_args, const mp_obj_t *args) {
if (n_args == 1) {
// read RTC memory
uint8_t rtcram[MICROPY_HW_RTC_USER_MEM_MAX];
diff --git a/ports/esp32/machine_timer.c b/ports/esp32/machine_timer.c
index 696127af7..3b1458149 100644
--- a/ports/esp32/machine_timer.c
+++ b/ports/esp32/machine_timer.c
@@ -229,7 +229,7 @@ STATIC mp_obj_t machine_timer_deinit(mp_obj_t self_in) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_timer_deinit_obj, machine_timer_deinit);
-STATIC mp_obj_t machine_timer_init(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
+STATIC mp_obj_t machine_timer_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
return machine_timer_init_helper(args[0], n_args - 1, args + 1, kw_args);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_timer_init_obj, 1, machine_timer_init);
diff --git a/ports/esp32/machine_uart.c b/ports/esp32/machine_uart.c
index e256b9be4..3c90a7215 100644
--- a/ports/esp32/machine_uart.c
+++ b/ports/esp32/machine_uart.c
@@ -53,6 +53,7 @@
typedef struct _machine_uart_obj_t {
mp_obj_base_t base;
uart_port_t uart_num;
+ uart_hw_flowcontrol_t flowcontrol;
uint8_t bits;
uint8_t parity;
uint8_t stop;
@@ -107,11 +108,25 @@ STATIC void machine_uart_print(const mp_print_t *print, mp_obj_t self_in, mp_pri
mp_printf(print, "INV_CTS");
}
}
+ if (self->flowcontrol) {
+ mp_printf(print, ", flow=");
+ uint32_t flow_mask = self->flowcontrol;
+ if (flow_mask & UART_HW_FLOWCTRL_RTS) {
+ mp_printf(print, "RTS");
+ flow_mask &= ~UART_HW_FLOWCTRL_RTS;
+ if (flow_mask) {
+ mp_printf(print, "|");
+ }
+ }
+ if (flow_mask & UART_HW_FLOWCTRL_CTS) {
+ mp_printf(print, "CTS");
+ }
+ }
mp_printf(print, ")");
}
STATIC void machine_uart_init_helper(machine_uart_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
- enum { ARG_baudrate, ARG_bits, ARG_parity, ARG_stop, ARG_tx, ARG_rx, ARG_rts, ARG_cts, ARG_txbuf, ARG_rxbuf, ARG_timeout, ARG_timeout_char, ARG_invert };
+ enum { ARG_baudrate, ARG_bits, ARG_parity, ARG_stop, ARG_tx, ARG_rx, ARG_rts, ARG_cts, ARG_txbuf, ARG_rxbuf, ARG_timeout, ARG_timeout_char, ARG_invert, ARG_flow };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_baudrate, MP_ARG_INT, {.u_int = 0} },
{ MP_QSTR_bits, MP_ARG_INT, {.u_int = 0} },
@@ -126,6 +141,7 @@ STATIC void machine_uart_init_helper(machine_uart_obj_t *self, size_t n_args, co
{ MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
{ MP_QSTR_timeout_char, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
{ MP_QSTR_invert, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_flow, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
};
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);
@@ -257,6 +273,13 @@ STATIC void machine_uart_init_helper(machine_uart_obj_t *self, size_t n_args, co
}
self->invert = args[ARG_invert].u_int;
uart_set_line_inverse(self->uart_num, self->invert);
+
+ // set hardware flow control
+ if (args[ARG_flow].u_int & ~UART_HW_FLOWCTRL_CTS_RTS) {
+ mp_raise_ValueError(MP_ERROR_TEXT("invalid flow control mask"));
+ }
+ self->flowcontrol = args[ARG_flow].u_int;
+ uart_set_hw_flow_ctrl(self->uart_num, self->flowcontrol, UART_FIFO_LEN - UART_FIFO_LEN / 4);
}
STATIC mp_obj_t machine_uart_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
@@ -400,6 +423,9 @@ STATIC const mp_rom_map_elem_t machine_uart_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_INV_RX), MP_ROM_INT(UART_INV_RX) },
{ MP_ROM_QSTR(MP_QSTR_INV_RTS), MP_ROM_INT(UART_INV_RTS) },
{ MP_ROM_QSTR(MP_QSTR_INV_CTS), MP_ROM_INT(UART_INV_CTS) },
+
+ { MP_ROM_QSTR(MP_QSTR_RTS), MP_ROM_INT(UART_HW_FLOWCTRL_RTS) },
+ { MP_ROM_QSTR(MP_QSTR_CTS), MP_ROM_INT(UART_HW_FLOWCTRL_CTS) },
};
STATIC MP_DEFINE_CONST_DICT(machine_uart_locals_dict, machine_uart_locals_dict_table);
@@ -443,7 +469,7 @@ STATIC mp_uint_t machine_uart_write(mp_obj_t self_in, const void *buf_in, mp_uin
return bytes_written;
}
-STATIC mp_uint_t machine_uart_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) {
+STATIC mp_uint_t machine_uart_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) {
machine_uart_obj_t *self = self_in;
mp_uint_t ret;
if (request == MP_STREAM_POLL) {
diff --git a/ports/esp32/main.c b/ports/esp32/main.c
index bc7b52630..a8ea8f1b5 100644
--- a/ports/esp32/main.c
+++ b/ports/esp32/main.c
@@ -54,10 +54,11 @@
#include "py/repl.h"
#include "py/gc.h"
#include "py/mphal.h"
-#include "lib/mp-readline/readline.h"
-#include "lib/utils/pyexec.h"
+#include "shared/readline/readline.h"
+#include "shared/runtime/pyexec.h"
#include "uart.h"
#include "usb.h"
+#include "usb_serial_jtag.h"
#include "modmachine.h"
#include "modnetwork.h"
#include "mpthreadport.h"
@@ -70,6 +71,13 @@
#define MP_TASK_PRIORITY (ESP_TASK_PRIO_MIN + 1)
#define MP_TASK_STACK_SIZE (32 * 1024)
+// Set the margin for detecting stack overflow, depending on the CPU architecture.
+#if CONFIG_IDF_TARGET_ESP32C3
+#define MP_TASK_STACK_LIMIT_MARGIN (2048)
+#else
+#define MP_TASK_STACK_LIMIT_MARGIN (1024)
+#endif
+
int vprintf_null(const char *format, va_list ap) {
// do nothing: this is used as a log target during raw repl mode
return 0;
@@ -82,6 +90,8 @@ void mp_task(void *pvParameter) {
#endif
#if CONFIG_USB_ENABLED
usb_init();
+ #elif CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG
+ usb_serial_jtag_init();
#else
uart_init();
#endif
@@ -127,7 +137,7 @@ void mp_task(void *pvParameter) {
soft_reset:
// initialise the stack pointer for the main thread
mp_stack_set_top((void *)sp);
- mp_stack_set_limit(MP_TASK_STACK_SIZE - 1024);
+ mp_stack_set_limit(MP_TASK_STACK_SIZE - MP_TASK_STACK_LIMIT_MARGIN);
gc_init(mp_task_heap, mp_task_heap + mp_task_heap_size);
mp_init();
mp_obj_list_init(mp_sys_path, 0);
@@ -138,6 +148,9 @@ soft_reset:
// initialise peripherals
machine_pins_init();
+ #if MICROPY_PY_MACHINE_I2S
+ machine_i2s_init0();
+ #endif
// run boot-up scripts
pyexec_frozen_module("_boot.py");
diff --git a/ports/esp32/main/CMakeLists.txt b/ports/esp32/main/CMakeLists.txt
index 7530e8420..c63e86d6c 100644
--- a/ports/esp32/main/CMakeLists.txt
+++ b/ports/esp32/main/CMakeLists.txt
@@ -15,21 +15,28 @@ set(MICROPY_QSTRDEFS_PORT
${PROJECT_DIR}/qstrdefsport.h
)
+set(MICROPY_SOURCE_SHARED
+ ${MICROPY_DIR}/shared/readline/readline.c
+ ${MICROPY_DIR}/shared/netutils/netutils.c
+ ${MICROPY_DIR}/shared/timeutils/timeutils.c
+ ${MICROPY_DIR}/shared/runtime/interrupt_char.c
+ ${MICROPY_DIR}/shared/runtime/stdout_helpers.c
+ ${MICROPY_DIR}/shared/runtime/sys_stdio_mphal.c
+ ${MICROPY_DIR}/shared/runtime/pyexec.c
+)
+
set(MICROPY_SOURCE_LIB
${MICROPY_DIR}/lib/littlefs/lfs1.c
${MICROPY_DIR}/lib/littlefs/lfs1_util.c
${MICROPY_DIR}/lib/littlefs/lfs2.c
${MICROPY_DIR}/lib/littlefs/lfs2_util.c
${MICROPY_DIR}/lib/mbedtls_errors/mp_mbedtls_errors.c
- ${MICROPY_DIR}/lib/mp-readline/readline.c
- ${MICROPY_DIR}/lib/netutils/netutils.c
${MICROPY_DIR}/lib/oofatfs/ff.c
${MICROPY_DIR}/lib/oofatfs/ffunicode.c
- ${MICROPY_DIR}/lib/timeutils/timeutils.c
- ${MICROPY_DIR}/lib/utils/interrupt_char.c
- ${MICROPY_DIR}/lib/utils/sys_stdio_mphal.c
- ${MICROPY_DIR}/lib/utils/pyexec.c
)
+if(IDF_TARGET STREQUAL "esp32c3")
+ list(APPEND MICROPY_SOURCE_LIB ${MICROPY_DIR}/shared/runtime/gchelper_generic.c)
+endif()
set(MICROPY_SOURCE_DRIVERS
${MICROPY_DIR}/drivers/bus/softspi.c
@@ -40,18 +47,21 @@ set(MICROPY_SOURCE_PORT
${PROJECT_DIR}/main.c
${PROJECT_DIR}/uart.c
${PROJECT_DIR}/usb.c
+ ${PROJECT_DIR}/usb_serial_jtag.c
${PROJECT_DIR}/gccollect.c
${PROJECT_DIR}/mphalport.c
${PROJECT_DIR}/fatfs_port.c
${PROJECT_DIR}/help.c
${PROJECT_DIR}/modutime.c
${PROJECT_DIR}/moduos.c
+ ${PROJECT_DIR}/machine_bitstream.c
${PROJECT_DIR}/machine_timer.c
${PROJECT_DIR}/machine_pin.c
${PROJECT_DIR}/machine_touchpad.c
${PROJECT_DIR}/machine_adc.c
${PROJECT_DIR}/machine_dac.c
${PROJECT_DIR}/machine_i2c.c
+ ${PROJECT_DIR}/machine_i2s.c
${PROJECT_DIR}/machine_pwm.c
${PROJECT_DIR}/machine_uart.c
${PROJECT_DIR}/modmachine.c
@@ -66,7 +76,6 @@ set(MICROPY_SOURCE_PORT
${PROJECT_DIR}/esp32_rmt.c
${PROJECT_DIR}/esp32_ulp.c
${PROJECT_DIR}/modesp32.c
- ${PROJECT_DIR}/espneopixel.c
${PROJECT_DIR}/machine_hw_spi.c
${PROJECT_DIR}/machine_wdt.c
${PROJECT_DIR}/mpthreadport.c
@@ -83,6 +92,7 @@ set(MICROPY_SOURCE_QSTR
${MICROPY_SOURCE_PY}
${MICROPY_SOURCE_EXTMOD}
${MICROPY_SOURCE_USERMOD}
+ ${MICROPY_SOURCE_SHARED}
${MICROPY_SOURCE_LIB}
${MICROPY_SOURCE_PORT}
${LV_SRC}
@@ -136,6 +146,9 @@ endif()
if(IDF_TARGET STREQUAL "esp32")
list(APPEND IDF_COMPONENTS esp32)
+elseif(IDF_TARGET STREQUAL "esp32c3")
+ list(APPEND IDF_COMPONENTS esp32c3)
+ list(APPEND IDF_COMPONENTS riscv)
elseif(IDF_TARGET STREQUAL "esp32s2")
list(APPEND IDF_COMPONENTS esp32s2)
list(APPEND IDF_COMPONENTS tinyusb)
@@ -149,6 +162,7 @@ idf_component_register(
SRCS
${MICROPY_SOURCE_PY}
${MICROPY_SOURCE_EXTMOD}
+ ${MICROPY_SOURCE_SHARED}
${MICROPY_SOURCE_LIB}
${MICROPY_SOURCE_DRIVERS}
${MICROPY_SOURCE_PORT}
diff --git a/ports/esp32/makeimg.py b/ports/esp32/makeimg.py
index fd0458318..0646ce372 100644
--- a/ports/esp32/makeimg.py
+++ b/ports/esp32/makeimg.py
@@ -6,8 +6,17 @@ sys.path.append(os.getenv("IDF_PATH") + "/components/partition_table")
import gen_esp32part
-OFFSET_BOOTLOADER = 0x1000
-OFFSET_PARTITIONS = 0x8000
+OFFSET_BOOTLOADER_DEFAULT = 0x1000
+OFFSET_PARTITIONS_DEFAULT = 0x8000
+
+
+def load_sdkconfig_hex_value(filename, value, default):
+ value = "CONFIG_" + value + "="
+ with open(filename, "r") as f:
+ for line in f:
+ if line.startswith(value):
+ return int(line.split("=", 1)[1], 16)
+ return default
def load_partition_table(filename):
@@ -15,28 +24,47 @@ def load_partition_table(filename):
return gen_esp32part.PartitionTable.from_binary(f.read())
-partition_table = load_partition_table(sys.argv[2])
+# Extract command-line arguments.
+arg_sdkconfig = sys.argv[1]
+arg_bootloader_bin = sys.argv[2]
+arg_partitions_bin = sys.argv[3]
+arg_application_bin = sys.argv[4]
+arg_output_bin = sys.argv[5]
-max_size_bootloader = OFFSET_PARTITIONS - OFFSET_BOOTLOADER
+# Load required sdkconfig values.
+offset_bootloader = load_sdkconfig_hex_value(
+ arg_sdkconfig, "BOOTLOADER_OFFSET_IN_FLASH", OFFSET_BOOTLOADER_DEFAULT
+)
+offset_partitions = load_sdkconfig_hex_value(
+ arg_sdkconfig, "PARTITION_TABLE_OFFSET", OFFSET_PARTITIONS_DEFAULT
+)
+
+# Load the partition table.
+partition_table = load_partition_table(arg_partitions_bin)
+
+max_size_bootloader = offset_partitions - offset_bootloader
max_size_partitions = 0
offset_application = 0
max_size_application = 0
+# Inspect the partition table to find offsets and maximum sizes.
for part in partition_table:
if part.name == "nvs":
- max_size_partitions = part.offset - OFFSET_PARTITIONS
+ max_size_partitions = part.offset - offset_partitions
elif part.type == gen_esp32part.APP_TYPE and offset_application == 0:
offset_application = part.offset
max_size_application = part.size
+# Define the input files, their location and maximum size.
files_in = [
- ("bootloader", OFFSET_BOOTLOADER, max_size_bootloader, sys.argv[1]),
- ("partitions", OFFSET_PARTITIONS, max_size_partitions, sys.argv[2]),
- ("application", offset_application, max_size_application, sys.argv[3]),
+ ("bootloader", offset_bootloader, max_size_bootloader, arg_bootloader_bin),
+ ("partitions", offset_partitions, max_size_partitions, arg_partitions_bin),
+ ("application", offset_application, max_size_application, arg_application_bin),
]
-file_out = sys.argv[4]
+file_out = arg_output_bin
-cur_offset = OFFSET_BOOTLOADER
+# Write output file with combined firmware.
+cur_offset = offset_bootloader
with open(file_out, "wb") as fout:
for name, offset, max_size, file_in in files_in:
assert offset >= cur_offset
diff --git a/ports/esp32/memory.h b/ports/esp32/memory.h
index f3777b0e3..1f07fe409 100644
--- a/ports/esp32/memory.h
+++ b/ports/esp32/memory.h
@@ -1,2 +1,2 @@
-// this is needed for extmod/crypto-algorithms/sha256.c
+// this is needed for lib/crypto-algorithms/sha256.c
#include
diff --git a/ports/esp32/modesp.c b/ports/esp32/modesp.c
index 59a261e8c..8c94e0cf4 100644
--- a/ports/esp32/modesp.c
+++ b/ports/esp32/modesp.c
@@ -112,15 +112,6 @@ STATIC mp_obj_t esp_gpio_matrix_out(size_t n_args, const mp_obj_t *args) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_gpio_matrix_out_obj, 4, 4, esp_gpio_matrix_out);
-STATIC mp_obj_t esp_neopixel_write_(mp_obj_t pin, mp_obj_t buf, mp_obj_t timing) {
- mp_buffer_info_t bufinfo;
- mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_READ);
- esp_neopixel_write(mp_hal_get_pin_obj(pin),
- (uint8_t *)bufinfo.buf, bufinfo.len, mp_obj_get_int(timing));
- return mp_const_none;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_3(esp_neopixel_write_obj, esp_neopixel_write_);
-
STATIC const mp_rom_map_elem_t esp_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_esp) },
@@ -135,7 +126,6 @@ STATIC const mp_rom_map_elem_t esp_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_gpio_matrix_in), MP_ROM_PTR(&esp_gpio_matrix_in_obj) },
{ MP_ROM_QSTR(MP_QSTR_gpio_matrix_out), MP_ROM_PTR(&esp_gpio_matrix_out_obj) },
- { MP_ROM_QSTR(MP_QSTR_neopixel_write), MP_ROM_PTR(&esp_neopixel_write_obj) },
{ MP_ROM_QSTR(MP_QSTR_dht_readinto), MP_ROM_PTR(&dht_readinto_obj) },
// Constants for second arg of osdebug()
@@ -153,4 +143,3 @@ const mp_obj_module_t esp_module = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t *)&esp_module_globals,
};
-
diff --git a/ports/esp32/modesp32.c b/ports/esp32/modesp32.c
index 3ed534338..75e5b3ed8 100644
--- a/ports/esp32/modesp32.c
+++ b/ports/esp32/modesp32.c
@@ -30,7 +30,6 @@
#include
#include
#include "soc/rtc_cntl_reg.h"
-#include "soc/sens_reg.h"
#include "driver/gpio.h"
#include "driver/adc.h"
#include "esp_heap_caps.h"
@@ -40,7 +39,7 @@
#include "py/obj.h"
#include "py/runtime.h"
#include "py/mphal.h"
-#include "lib/timeutils/timeutils.h"
+#include "shared/timeutils/timeutils.h"
#include "modmachine.h"
#include "machine_rtc.h"
#include "modesp32.h"
@@ -109,7 +108,7 @@ STATIC mp_obj_t esp32_wake_on_ext1(size_t n_args, const mp_obj_t *pos_args, mp_m
// Check that all pins are allowed
if (args[ARG_pins].u_obj != mp_const_none) {
- mp_uint_t len = 0;
+ size_t len = 0;
mp_obj_t *elem;
mp_obj_get_array(args[ARG_pins].u_obj, &len, &elem);
ext1_pins = 0;
@@ -134,6 +133,8 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(esp32_wake_on_ext1_obj, 0, esp32_wake_on_ext1)
#if CONFIG_IDF_TARGET_ESP32
+#include "soc/sens_reg.h"
+
STATIC mp_obj_t esp32_raw_temperature(void) {
SET_PERI_REG_BITS(SENS_SAR_MEAS_WAIT2_REG, SENS_FORCE_XPD_SAR, 3, SENS_FORCE_XPD_SAR_S);
SET_PERI_REG_BITS(SENS_SAR_TSENS_CTRL_REG, SENS_TSENS_CLK_DIV, 10, SENS_TSENS_CLK_DIV_S);
diff --git a/ports/esp32/modmachine.c b/ports/esp32/modmachine.c
index bbe7fae03..5f94007d4 100644
--- a/ports/esp32/modmachine.c
+++ b/ports/esp32/modmachine.c
@@ -34,7 +34,6 @@
#include "freertos/task.h"
#include "esp_sleep.h"
#include "esp_pm.h"
-#include "driver/touch_pad.h"
#if CONFIG_IDF_TARGET_ESP32
#include "esp32/rom/rtc.h"
@@ -49,7 +48,8 @@
#include "py/obj.h"
#include "py/runtime.h"
-#include "lib/utils/pyexec.h"
+#include "shared/runtime/pyexec.h"
+#include "extmod/machine_bitstream.h"
#include "extmod/machine_mem.h"
#include "extmod/machine_signal.h"
#include "extmod/machine_pulse.h"
@@ -70,6 +70,10 @@ typedef enum {
STATIC bool is_soft_reset = 0;
+#if CONFIG_IDF_TARGET_ESP32C3
+int esp_clk_cpu_freq(void);
+#endif
+
STATIC mp_obj_t machine_freq(size_t n_args, const mp_obj_t *args) {
if (n_args == 0) {
// get
@@ -82,6 +86,8 @@ STATIC mp_obj_t machine_freq(size_t n_args, const mp_obj_t *args) {
}
#if CONFIG_IDF_TARGET_ESP32
esp_pm_config_esp32_t pm;
+ #elif CONFIG_IDF_TARGET_ESP32C3
+ esp_pm_config_esp32c3_t pm;
#elif CONFIG_IDF_TARGET_ESP32S2
esp_pm_config_esp32s2_t pm;
#endif
@@ -117,6 +123,8 @@ STATIC mp_obj_t machine_sleep_helper(wake_type_t wake_type, size_t n_args, const
esp_sleep_enable_timer_wakeup(((uint64_t)expiry) * 1000);
}
+ #if !CONFIG_IDF_TARGET_ESP32C3
+
if (machine_rtc_config.ext0_pin != -1 && (machine_rtc_config.ext0_wake_types & wake_type)) {
esp_sleep_enable_ext0_wakeup(machine_rtc_config.ext0_pin, machine_rtc_config.ext0_level ? 1 : 0);
}
@@ -133,6 +141,8 @@ STATIC mp_obj_t machine_sleep_helper(wake_type_t wake_type, size_t n_args, const
}
}
+ #endif
+
switch (wake_type) {
case MACHINE_WAKE_SLEEP:
esp_light_sleep_start();
@@ -223,7 +233,9 @@ STATIC mp_obj_t machine_unique_id(void) {
STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_unique_id_obj, machine_unique_id);
STATIC mp_obj_t machine_idle(void) {
+ MP_THREAD_GIL_EXIT();
taskYIELD();
+ MP_THREAD_GIL_ENTER();
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_idle_obj, machine_idle);
@@ -260,7 +272,12 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_disable_irq), MP_ROM_PTR(&machine_disable_irq_obj) },
{ MP_ROM_QSTR(MP_QSTR_enable_irq), MP_ROM_PTR(&machine_enable_irq_obj) },
+ #if MICROPY_PY_MACHINE_BITSTREAM
+ { MP_ROM_QSTR(MP_QSTR_bitstream), MP_ROM_PTR(&machine_bitstream_obj) },
+ #endif
+ #if MICROPY_PY_MACHINE_PULSE
{ MP_ROM_QSTR(MP_QSTR_time_pulse_us), MP_ROM_PTR(&machine_time_pulse_us_obj) },
+ #endif
{ MP_ROM_QSTR(MP_QSTR_Timer), MP_ROM_PTR(&machine_timer_type) },
{ MP_ROM_QSTR(MP_QSTR_WDT), MP_ROM_PTR(&machine_wdt_type) },
@@ -277,9 +294,14 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_TouchPad), MP_ROM_PTR(&machine_touchpad_type) },
#endif
{ MP_ROM_QSTR(MP_QSTR_ADC), MP_ROM_PTR(&machine_adc_type) },
+ #if MICROPY_PY_MACHINE_DAC
{ MP_ROM_QSTR(MP_QSTR_DAC), MP_ROM_PTR(&machine_dac_type) },
+ #endif
{ MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&machine_hw_i2c_type) },
{ MP_ROM_QSTR(MP_QSTR_SoftI2C), MP_ROM_PTR(&mp_machine_soft_i2c_type) },
+ #if MICROPY_PY_MACHINE_I2S
+ { MP_ROM_QSTR(MP_QSTR_I2S), MP_ROM_PTR(&machine_i2s_type) },
+ #endif
{ MP_ROM_QSTR(MP_QSTR_PWM), MP_ROM_PTR(&machine_pwm_type) },
{ MP_ROM_QSTR(MP_QSTR_RTC), MP_ROM_PTR(&machine_rtc_type) },
{ MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&machine_hw_spi_type) },
diff --git a/ports/esp32/modmachine.h b/ports/esp32/modmachine.h
index 3e99e1120..7bf03b0ca 100644
--- a/ports/esp32/modmachine.h
+++ b/ports/esp32/modmachine.h
@@ -18,6 +18,7 @@ extern const mp_obj_type_t machine_dac_type;
extern const mp_obj_type_t machine_pwm_type;
extern const mp_obj_type_t machine_hw_i2c_type;
extern const mp_obj_type_t machine_hw_spi_type;
+extern const mp_obj_type_t machine_i2s_type;
extern const mp_obj_type_t machine_uart_type;
extern const mp_obj_type_t machine_rtc_type;
extern const mp_obj_type_t machine_sdcard_type;
@@ -27,5 +28,6 @@ void machine_deinit(void);
void machine_pins_init(void);
void machine_pins_deinit(void);
void machine_timer_deinit_all(void);
+void machine_i2s_init0();
#endif // MICROPY_INCLUDED_ESP32_MODMACHINE_H
diff --git a/ports/esp32/modnetwork.c b/ports/esp32/modnetwork.c
index e2bd20a1a..2b64105e7 100644
--- a/ports/esp32/modnetwork.c
+++ b/ports/esp32/modnetwork.c
@@ -40,7 +40,7 @@
#include "py/runtime.h"
#include "py/mphal.h"
#include "py/mperrno.h"
-#include "lib/netutils/netutils.h"
+#include "shared/netutils/netutils.h"
#include "esp_eth.h"
#include "esp_wifi.h"
#include "esp_log.h"
@@ -466,7 +466,7 @@ STATIC mp_obj_t esp_scan(mp_obj_t self_in) {
mp_obj_t list = mp_obj_new_list(0, NULL);
wifi_scan_config_t config = { 0 };
- // XXX how do we scan hidden APs (and if we can scan them, are they really hidden?)
+ config.show_hidden = true;
MP_THREAD_GIL_EXIT();
esp_err_t status = esp_wifi_scan_start(&config, 1);
MP_THREAD_GIL_ENTER();
diff --git a/ports/esp32/modsocket.c b/ports/esp32/modsocket.c
index 67b1d7d6f..be950ac1f 100644
--- a/ports/esp32/modsocket.c
+++ b/ports/esp32/modsocket.c
@@ -45,7 +45,7 @@
#include "py/mphal.h"
#include "py/stream.h"
#include "py/mperrno.h"
-#include "lib/netutils/netutils.h"
+#include "shared/netutils/netutils.h"
#include "mdns.h"
#include "modnetwork.h"
diff --git a/ports/esp32/modules/neopixel.py b/ports/esp32/modules/neopixel.py
deleted file mode 100644
index f5c919398..000000000
--- a/ports/esp32/modules/neopixel.py
+++ /dev/null
@@ -1,35 +0,0 @@
-# NeoPixel driver for MicroPython on ESP32
-# MIT license; Copyright (c) 2016 Damien P. George
-
-from esp import neopixel_write
-
-
-class NeoPixel:
- ORDER = (1, 0, 2, 3)
-
- def __init__(self, pin, n, bpp=3, timing=1):
- self.pin = pin
- self.n = n
- self.bpp = bpp
- self.buf = bytearray(n * bpp)
- self.pin.init(pin.OUT)
- self.timing = timing
-
- def __len__(self):
- return self.n
-
- def __setitem__(self, index, val):
- offset = index * self.bpp
- for i in range(self.bpp):
- self.buf[offset + self.ORDER[i]] = val[i]
-
- def __getitem__(self, index):
- offset = index * self.bpp
- return tuple(self.buf[offset + self.ORDER[i]] for i in range(self.bpp))
-
- def fill(self, color):
- for i in range(self.n):
- self[i] = color
-
- def write(self):
- neopixel_write(self.pin, self.buf, self.timing)
diff --git a/ports/esp32/modutime.c b/ports/esp32/modutime.c
index cf7178e0b..f864df678 100644
--- a/ports/esp32/modutime.c
+++ b/ports/esp32/modutime.c
@@ -31,7 +31,7 @@
#include
#include "py/runtime.h"
-#include "lib/timeutils/timeutils.h"
+#include "shared/timeutils/timeutils.h"
#include "extmod/utime_mphal.h"
STATIC mp_obj_t time_localtime(size_t n_args, const mp_obj_t *args) {
diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h
index c6af43a67..75b00eadb 100644
--- a/ports/esp32/mpconfigport.h
+++ b/ports/esp32/mpconfigport.h
@@ -11,13 +11,18 @@
// object representation and NLR handling
#define MICROPY_OBJ_REPR (MICROPY_OBJ_REPR_A)
#define MICROPY_NLR_SETJMP (1)
+#if CONFIG_IDF_TARGET_ESP32C3
+#define MICROPY_GCREGS_SETJMP (1)
+#endif
// memory allocation policies
#define MICROPY_ALLOC_PATH_MAX (128)
// emitters
#define MICROPY_PERSISTENT_CODE_LOAD (1)
+#if !CONFIG_IDF_TARGET_ESP32C3
#define MICROPY_EMIT_XTENSAWIN (1)
+#endif
// compiler configuration
#define MICROPY_COMP_MODULE_CONST (1)
@@ -61,6 +66,7 @@
#define MICROPY_PY_FUNCTION_ATTRS (1)
#define MICROPY_PY_DESCRIPTORS (1)
#define MICROPY_PY_DELATTR_SETATTR (1)
+#define MICROPY_PY_FSTRINGS (1)
#define MICROPY_PY_STR_BYTES_CMP_WARN (1)
#define MICROPY_PY_BUILTINS_STR_UNICODE (1)
#define MICROPY_PY_BUILTINS_STR_CENTER (1)
@@ -77,6 +83,8 @@
#define MICROPY_PY_BUILTINS_RANGE_ATTRS (1)
#define MICROPY_PY_BUILTINS_ROUND_INT (1)
#define MICROPY_PY_ALL_SPECIAL_METHODS (1)
+#define MICROPY_PY_ALL_INPLACE_SPECIAL_METHODS (1)
+#define MICROPY_PY_REVERSE_SPECIAL_METHODS (1)
#define MICROPY_PY_BUILTINS_COMPILE (1)
#define MICROPY_PY_BUILTINS_ENUMERATE (1)
#define MICROPY_PY_BUILTINS_EXECFILE (1)
@@ -148,11 +156,18 @@
#define MICROPY_PY_OS_DUPTERM (1)
#define MICROPY_PY_MACHINE (1)
#define MICROPY_PY_MACHINE_PIN_MAKE_NEW mp_pin_make_new
+#define MICROPY_PY_MACHINE_BITSTREAM (1)
#define MICROPY_PY_MACHINE_PULSE (1)
#define MICROPY_PY_MACHINE_I2C (1)
#define MICROPY_PY_MACHINE_SPI (1)
#define MICROPY_PY_MACHINE_SPI_MSB (0)
#define MICROPY_PY_MACHINE_SPI_LSB (1)
+#ifndef MICROPY_PY_MACHINE_DAC
+#define MICROPY_PY_MACHINE_DAC (1)
+#endif
+#ifndef MICROPY_PY_MACHINE_I2S
+#define MICROPY_PY_MACHINE_I2S (1)
+#endif
#ifndef MICROPY_HW_ENABLE_SDCARD
#define MICROPY_HW_ENABLE_SDCARD (1)
#endif
diff --git a/ports/esp32/mphalport.c b/ports/esp32/mphalport.c
index a0bafb755..de1b173ac 100644
--- a/ports/esp32/mphalport.c
+++ b/ports/esp32/mphalport.c
@@ -35,6 +35,8 @@
#if CONFIG_IDF_TARGET_ESP32
#include "esp32/rom/uart.h"
+#elif CONFIG_IDF_TARGET_ESP32C3
+#include "esp32c3/rom/uart.h"
#elif CONFIG_IDF_TARGET_ESP32S2
#include "esp32s2/rom/uart.h"
#elif CONFIG_IDF_TARGET_ESP32S3
@@ -47,10 +49,11 @@
#include "py/mpstate.h"
#include "py/mphal.h"
#include "extmod/misc.h"
-#include "lib/timeutils/timeutils.h"
-#include "lib/utils/pyexec.h"
+#include "shared/timeutils/timeutils.h"
+#include "shared/runtime/pyexec.h"
#include "mphalport.h"
#include "usb.h"
+#include "usb_serial_jtag.h"
TaskHandle_t mp_main_task_handle;
@@ -108,11 +111,7 @@ int mp_hal_stdin_rx_chr(void) {
}
}
-void mp_hal_stdout_tx_str(const char *str) {
- mp_hal_stdout_tx_strn(str, strlen(str));
-}
-
-void mp_hal_stdout_tx_strn(const char *str, uint32_t len) {
+void mp_hal_stdout_tx_strn(const char *str, size_t len) {
// Only release the GIL if many characters are being sent
bool release_gil = len > 20;
if (release_gil) {
@@ -120,6 +119,8 @@ void mp_hal_stdout_tx_strn(const char *str, uint32_t len) {
}
#if CONFIG_USB_ENABLED
usb_tx_strn(str, len);
+ #elif CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG
+ usb_serial_jtag_tx_strn(str, len);
#else
for (uint32_t i = 0; i < len; ++i) {
uart_tx_one_char(str[i]);
@@ -131,26 +132,6 @@ void mp_hal_stdout_tx_strn(const char *str, uint32_t len) {
mp_uos_dupterm_tx_strn(str, len);
}
-// Efficiently convert "\n" to "\r\n"
-void mp_hal_stdout_tx_strn_cooked(const char *str, size_t len) {
- const char *last = str;
- while (len--) {
- if (*str == '\n') {
- if (str > last) {
- mp_hal_stdout_tx_strn(last, str - last);
- }
- mp_hal_stdout_tx_strn("\r\n", 2);
- ++str;
- last = str;
- } else {
- ++str;
- }
- }
- if (str > last) {
- mp_hal_stdout_tx_strn(last, str - last);
- }
-}
-
uint32_t mp_hal_ticks_ms(void) {
return esp_timer_get_time() / 1000;
}
@@ -164,14 +145,22 @@ void mp_hal_delay_ms(uint32_t ms) {
uint64_t dt;
uint64_t t0 = esp_timer_get_time();
for (;;) {
+ mp_handle_pending(true);
+ MICROPY_PY_USOCKET_EVENTS_HANDLER
+ MP_THREAD_GIL_EXIT();
uint64_t t1 = esp_timer_get_time();
dt = t1 - t0;
if (dt + portTICK_PERIOD_MS * 1000 >= us) {
// doing a vTaskDelay would take us beyond requested delay time
+ taskYIELD();
+ MP_THREAD_GIL_ENTER();
+ t1 = esp_timer_get_time();
+ dt = t1 - t0;
break;
+ } else {
+ ulTaskNotifyTake(pdFALSE, 1);
+ MP_THREAD_GIL_ENTER();
}
- MICROPY_EVENT_POLL_HOOK
- ulTaskNotifyTake(pdFALSE, 1);
}
if (dt < us) {
// do the remaining delay accurately
diff --git a/ports/esp32/mphalport.h b/ports/esp32/mphalport.h
index 60cc308d6..2dad8fa92 100644
--- a/ports/esp32/mphalport.h
+++ b/ports/esp32/mphalport.h
@@ -30,7 +30,7 @@
#define INCLUDED_MPHALPORT_H
#include "py/ringbuf.h"
-#include "lib/utils/interrupt_char.h"
+#include "shared/runtime/interrupt_char.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
@@ -51,7 +51,11 @@ void check_esp_err(esp_err_t code);
uint32_t mp_hal_ticks_us(void);
__attribute__((always_inline)) static inline uint32_t mp_hal_ticks_cpu(void) {
uint32_t ccount;
+ #if CONFIG_IDF_TARGET_ESP32C3
+ __asm__ __volatile__ ("csrr %0, 0x7E2" : "=r" (ccount)); // Machine Performance Counter Value
+ #else
__asm__ __volatile__ ("rsr %0,ccount" : "=a" (ccount));
+ #endif
return ccount;
}
diff --git a/ports/esp32/network_ppp.c b/ports/esp32/network_ppp.c
index db2292ca0..d74283c19 100644
--- a/ports/esp32/network_ppp.c
+++ b/ports/esp32/network_ppp.c
@@ -30,7 +30,7 @@
#include "py/mphal.h"
#include "py/objtype.h"
#include "py/stream.h"
-#include "lib/netutils/netutils.h"
+#include "shared/netutils/netutils.h"
#include "modmachine.h"
#include "netif/ppp/ppp.h"
diff --git a/ports/esp32/partitions-16MiB-ota.csv b/ports/esp32/partitions-16MiB-ota.csv
new file mode 100644
index 000000000..a6f83bc46
--- /dev/null
+++ b/ports/esp32/partitions-16MiB-ota.csv
@@ -0,0 +1,10 @@
+# Partition table for MicroPython with OTA support using 16MB flash
+# Notes: the offset of the partition table itself is set in
+# $IDF_PATH/components/partition_table/Kconfig.projbuild.
+# Name, Type, SubType, Offset, Size, Flags
+nvs, data, nvs, 0x9000, 0x4000,
+otadata, data, ota, 0xd000, 0x2000,
+phy_init, data, phy, 0xf000, 0x1000,
+ota_0, app, ota_0, 0x10000, 0x270000,
+ota_1, app, ota_1, 0x280000, 0x270000,
+vfs, data, fat, 0x4f0000, 0xb10000,
diff --git a/ports/esp32/uart.c b/ports/esp32/uart.c
index c4fe41eaf..480b364a5 100644
--- a/ports/esp32/uart.c
+++ b/ports/esp32/uart.c
@@ -51,7 +51,7 @@ STATIC void IRAM_ATTR uart_irq_handler(void *arg) {
while (uart->status.rxfifo_cnt) {
#if CONFIG_IDF_TARGET_ESP32
uint8_t c = uart->fifo.rw_byte;
- #elif CONFIG_IDF_TARGET_ESP32S2
+ #elif CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S2
uint8_t c = READ_PERI_REG(UART_FIFO_AHB_REG(0)); // UART0
#endif
if (c == mp_interrupt_char) {
diff --git a/ports/esp32/usb_serial_jtag.c b/ports/esp32/usb_serial_jtag.c
new file mode 100644
index 000000000..a7d06a355
--- /dev/null
+++ b/ports/esp32/usb_serial_jtag.c
@@ -0,0 +1,98 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Patrick Van Oosterwijck
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/runtime.h"
+#include "py/mphal.h"
+#include "usb_serial_jtag.h"
+
+#if CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG
+
+#include "hal/usb_serial_jtag_ll.h"
+#include "esp_intr_alloc.h"
+#include "soc/periph_defs.h"
+
+#define USB_SERIAL_JTAG_BUF_SIZE (64)
+
+static uint8_t rx_buf[USB_SERIAL_JTAG_BUF_SIZE];
+static volatile bool terminal_connected = false;
+
+static void usb_serial_jtag_isr_handler(void *arg) {
+ uint32_t flags = usb_serial_jtag_ll_get_intsts_mask();
+
+ if (flags & USB_SERIAL_JTAG_INTR_SOF) {
+ usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_INTR_SOF);
+ }
+
+ if (flags & USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT) {
+ usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT);
+ size_t req_len = ringbuf_free(&stdin_ringbuf);
+ if (req_len > USB_SERIAL_JTAG_BUF_SIZE) {
+ req_len = USB_SERIAL_JTAG_BUF_SIZE;
+ }
+ size_t len = usb_serial_jtag_ll_read_rxfifo(rx_buf, req_len);
+ for (size_t i = 0; i < len; ++i) {
+ if (rx_buf[i] == mp_interrupt_char) {
+ mp_sched_keyboard_interrupt();
+ } else {
+ ringbuf_put(&stdin_ringbuf, rx_buf[i]);
+ }
+ }
+ mp_hal_wake_main_task_from_isr();
+ }
+}
+
+void usb_serial_jtag_init(void) {
+ usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT |
+ USB_SERIAL_JTAG_INTR_SOF);
+ usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT |
+ USB_SERIAL_JTAG_INTR_SOF);
+ ESP_ERROR_CHECK(esp_intr_alloc(ETS_USB_SERIAL_JTAG_INTR_SOURCE, ESP_INTR_FLAG_LEVEL1,
+ usb_serial_jtag_isr_handler, NULL, NULL));
+}
+
+void usb_serial_jtag_tx_strn(const char *str, size_t len) {
+ while (len) {
+ size_t l = len;
+ if (l > USB_SERIAL_JTAG_PACKET_SZ_BYTES) {
+ l = USB_SERIAL_JTAG_PACKET_SZ_BYTES;
+ }
+ portTickType start_tick = xTaskGetTickCount();
+ while (!usb_serial_jtag_ll_txfifo_writable()) {
+ portTickType now_tick = xTaskGetTickCount();
+ if (!terminal_connected || now_tick > (start_tick + pdMS_TO_TICKS(200))) {
+ terminal_connected = false;
+ return;
+ }
+ }
+ terminal_connected = true;
+ l = usb_serial_jtag_ll_write_txfifo((const uint8_t *)str, l);
+ usb_serial_jtag_ll_txfifo_flush();
+ str += l;
+ len -= l;
+ }
+}
+
+#endif // CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG
diff --git a/ports/esp32/usb_serial_jtag.h b/ports/esp32/usb_serial_jtag.h
new file mode 100644
index 000000000..4eebb19e4
--- /dev/null
+++ b/ports/esp32/usb_serial_jtag.h
@@ -0,0 +1,32 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Patrick Van Oosterwijck
+ *
+ * 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_ESP32_USB_SERIAL_JTAG_H
+#define MICROPY_INCLUDED_ESP32_USB_SERIAL_JTAG_H
+
+void usb_serial_jtag_init(void);
+void usb_serial_jtag_tx_strn(const char *str, size_t len);
+
+#endif // MICROPY_INCLUDED_ESP32_USB_SERIAL_JTAG_H
diff --git a/ports/esp8266/Makefile b/ports/esp8266/Makefile
index 02ea05f76..9ea4498f4 100644
--- a/ports/esp8266/Makefile
+++ b/ports/esp8266/Makefile
@@ -91,10 +91,10 @@ SRC_C = \
lexerstr32.c \
uart.c \
esppwm.c \
- espneopixel.c \
espapa102.c \
modpyb.c \
modmachine.c \
+ machine_bitstream.c \
machine_pin.c \
machine_pwm.c \
machine_rtc.c \
@@ -119,33 +119,45 @@ EXTMOD_SRC_C = $(addprefix extmod/,\
)
LIB_SRC_C = $(addprefix lib/,\
- embed/__errno.c \
- libc/string0.c \
libm/math.c \
libm/fmodf.c \
libm/nearbyintf.c \
libm/ef_sqrt.c \
+ libm/erf_lgamma.c \
libm/kf_rem_pio2.c \
libm/kf_sin.c \
libm/kf_cos.c \
libm/kf_tan.c \
libm/ef_rem_pio2.c \
+ libm/sf_erf.c \
libm/sf_sin.c \
libm/sf_cos.c \
libm/sf_tan.c \
libm/sf_frexp.c \
libm/sf_modf.c \
libm/sf_ldexp.c \
+ libm/acoshf.c \
libm/asinfacosf.c \
+ libm/asinhf.c \
libm/atanf.c \
+ libm/atanhf.c \
libm/atan2f.c \
+ libm/log1pf.c \
libm/roundf.c \
- mp-readline/readline.c \
+ libm/wf_lgamma.c \
+ libm/wf_tgamma.c \
+ )
+
+SHARED_SRC_C = $(addprefix shared/,\
+ libc/__errno.c \
+ libc/string0.c \
netutils/netutils.c \
+ readline/readline.c \
+ runtime/interrupt_char.c \
+ runtime/pyexec.c \
+ runtime/stdout_helpers.c \
+ runtime/sys_stdio_mphal.c \
timeutils/timeutils.c \
- utils/pyexec.c \
- utils/interrupt_char.c \
- utils/sys_stdio_mphal.c \
)
DRIVERS_SRC_C = $(addprefix drivers/,\
@@ -161,11 +173,12 @@ OBJ += $(PY_O)
OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o))
OBJ += $(addprefix $(BUILD)/, $(SRC_S:.s=.o))
OBJ += $(addprefix $(BUILD)/, $(EXTMOD_SRC_C:.c=.o))
+OBJ += $(addprefix $(BUILD)/, $(SHARED_SRC_C:.c=.o))
OBJ += $(addprefix $(BUILD)/, $(LIB_SRC_C:.c=.o))
OBJ += $(addprefix $(BUILD)/, $(DRIVERS_SRC_C:.c=.o))
# List of sources for qstr extraction
-SRC_QSTR += $(SRC_C) $(EXTMOD_SRC_C) $(LIB_SRC_C) $(DRIVERS_SRC_C)
+SRC_QSTR += $(SRC_C) $(EXTMOD_SRC_C) $(SHARED_SRC_C) $(DRIVERS_SRC_C)
# Append any auto-generated sources that are needed by sources listed in SRC_QSTR
SRC_QSTR_AUTO_DEPS +=
diff --git a/ports/esp8266/boards/GENERIC_512K/manifest.py b/ports/esp8266/boards/GENERIC_512K/manifest.py
index 5674f280b..ee148c808 100644
--- a/ports/esp8266/boards/GENERIC_512K/manifest.py
+++ b/ports/esp8266/boards/GENERIC_512K/manifest.py
@@ -1,5 +1,6 @@
freeze("$(BOARD_DIR)", "_boot.py", opt=3)
-freeze("$(PORT_DIR)/modules", ("apa102.py", "neopixel.py", "ntptime.py", "port_diag.py"))
+freeze("$(PORT_DIR)/modules", ("apa102.py", "ntptime.py", "port_diag.py"))
freeze("$(MPY_DIR)/drivers/dht", "dht.py")
freeze("$(MPY_DIR)/drivers/onewire")
include("$(MPY_DIR)/extmod/webrepl/manifest.py")
+include("$(MPY_DIR)/drivers/neopixel/manifest.py")
diff --git a/ports/esp8266/boards/esp8266_common.ld b/ports/esp8266/boards/esp8266_common.ld
index c6e37d942..f40ff1e5f 100644
--- a/ports/esp8266/boards/esp8266_common.ld
+++ b/ports/esp8266/boards/esp8266_common.ld
@@ -134,14 +134,14 @@ SECTIONS
*lib/berkeley-db-1.xx/*.o(.literal*, .text*)
*lib/libm/*.o*(.literal*, .text*)
*lib/littlefs/*.o*(.literal*, .text*)
- *lib/mp-readline/*.o(.literal*, .text*)
- *lib/netutils/*.o*(.literal*, .text*)
- *lib/timeutils/*.o*(.literal*, .text*)
- *lib/utils/printf.o*(.literal*, .text*)
- *lib/utils/sys_stdio_mphal.o*(.literal*, .text*)
- *lib/utils/pyexec.o*(.literal*, .text*)
- *lib/utils/stdout_helpers.o*(.literal*, .text*)
- *lib/utils/interrupt_char.o*(.literal*, .text*)
+ *shared/libc/printf.o*(.literal*, .text*)
+ *shared/netutils/*.o*(.literal*, .text*)
+ *shared/readline/*.o(.literal*, .text*)
+ *shared/runtime/interrupt_char.o*(.literal*, .text*)
+ *shared/runtime/pyexec.o*(.literal*, .text*)
+ *shared/runtime/stdout_helpers.o*(.literal*, .text*)
+ *shared/runtime/sys_stdio_mphal.o*(.literal*, .text*)
+ *shared/timeutils/*.o*(.literal*, .text*)
*drivers/bus/*.o(.literal* .text*)
build-*/main.o(.literal* .text*)
diff --git a/ports/esp8266/boards/manifest.py b/ports/esp8266/boards/manifest.py
index de719f8f1..598572d62 100644
--- a/ports/esp8266/boards/manifest.py
+++ b/ports/esp8266/boards/manifest.py
@@ -3,3 +3,4 @@ freeze("$(MPY_DIR)/tools", ("upip.py", "upip_utarfile.py"))
freeze("$(MPY_DIR)/drivers/dht", "dht.py")
freeze("$(MPY_DIR)/drivers/onewire")
include("$(MPY_DIR)/extmod/webrepl/manifest.py")
+include("$(MPY_DIR)/drivers/neopixel/manifest.py")
diff --git a/ports/esp8266/esp_mphal.c b/ports/esp8266/esp_mphal.c
index 54f9611e5..3cb480733 100644
--- a/ports/esp8266/esp_mphal.c
+++ b/ports/esp8266/esp_mphal.c
@@ -34,7 +34,7 @@
#include "py/runtime.h"
#include "py/stream.h"
#include "extmod/misc.h"
-#include "lib/utils/pyexec.h"
+#include "shared/runtime/pyexec.h"
STATIC byte stdin_ringbuf_array[256];
ringbuf_t stdin_ringbuf = {stdin_ringbuf_array, sizeof(stdin_ringbuf_array), 0, 0};
@@ -91,33 +91,10 @@ void mp_hal_debug_str(const char *str) {
}
#endif
-void mp_hal_stdout_tx_str(const char *str) {
- mp_uos_dupterm_tx_strn(str, strlen(str));
-}
-
void mp_hal_stdout_tx_strn(const char *str, uint32_t len) {
mp_uos_dupterm_tx_strn(str, len);
}
-void mp_hal_stdout_tx_strn_cooked(const char *str, uint32_t len) {
- const char *last = str;
- while (len--) {
- if (*str == '\n') {
- if (str > last) {
- mp_uos_dupterm_tx_strn(last, str - last);
- }
- mp_uos_dupterm_tx_strn("\r\n", 2);
- ++str;
- last = str;
- } else {
- ++str;
- }
- }
- if (str > last) {
- mp_uos_dupterm_tx_strn(last, str - last);
- }
-}
-
void mp_hal_debug_tx_strn_cooked(void *env, const char *str, uint32_t len) {
(void)env;
while (len--) {
diff --git a/ports/esp8266/esp_mphal.h b/ports/esp8266/esp_mphal.h
index e9cf7e548..b0351877e 100644
--- a/ports/esp8266/esp_mphal.h
+++ b/ports/esp8266/esp_mphal.h
@@ -26,7 +26,7 @@
#include "user_interface.h"
#include "py/ringbuf.h"
-#include "lib/utils/interrupt_char.h"
+#include "shared/runtime/interrupt_char.h"
#include "xtirq.h"
void mp_sched_keyboard_interrupt(void);
diff --git a/ports/esp8266/espneopixel.c b/ports/esp8266/espneopixel.c
deleted file mode 100644
index d2166a8b0..000000000
--- a/ports/esp8266/espneopixel.c
+++ /dev/null
@@ -1,75 +0,0 @@
-// Original version from https://github.com/adafruit/Adafruit_NeoPixel
-// Modifications by dpgeorge to support auto-CPU-frequency detection
-
-// This is a mash-up of the Due show() code + insights from Michael Miller's
-// ESP8266 work for the NeoPixelBus library: github.com/Makuna/NeoPixelBus
-// Needs to be a separate .c file to enforce ICACHE_RAM_ATTR execution.
-
-#include "py/mpconfig.h"
-#if MICROPY_ESP8266_NEOPIXEL
-
-#include "c_types.h"
-#include "eagle_soc.h"
-#include "user_interface.h"
-#include "espneopixel.h"
-#include "esp_mphal.h"
-
-#define NEO_KHZ400 (1)
-
-void /*ICACHE_RAM_ATTR*/ esp_neopixel_write(uint8_t pin, uint8_t *pixels, uint32_t numBytes, bool is800KHz) {
-
- uint8_t *p, *end, pix, mask;
- uint32_t t, time0, time1, period, c, startTime, pinMask;
-
- pinMask = 1 << pin;
- p = pixels;
- end = p + numBytes;
- pix = *p++;
- mask = 0x80;
- startTime = 0;
-
- uint32_t fcpu = system_get_cpu_freq() * 1000000;
-
- #ifdef NEO_KHZ400
- if (is800KHz) {
- #endif
- time0 = fcpu / 2857143; // 0.35us
- time1 = fcpu / 1250000; // 0.8us
- period = fcpu / 800000; // 1.25us per bit
- #ifdef NEO_KHZ400
-} else { // 400 KHz bitstream
- time0 = fcpu / 2000000; // 0.5uS
- time1 = fcpu / 833333; // 1.2us
- period = fcpu / 400000; // 2.5us per bit
-}
- #endif
-
- uint32_t irq_state = mp_hal_quiet_timing_enter();
- for (t = time0;; t = time0) {
- if (pix & mask) {
- t = time1; // Bit high duration
- }
- while (((c = mp_hal_ticks_cpu()) - startTime) < period) {
- ; // Wait for bit start
- }
- GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, pinMask); // Set high
- startTime = c; // Save start time
- while (((c = mp_hal_ticks_cpu()) - startTime) < t) {
- ; // Wait high duration
- }
- GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, pinMask); // Set low
- if (!(mask >>= 1)) { // Next bit/byte
- if (p >= end) {
- break;
- }
- pix = *p++;
- mask = 0x80;
- }
- }
- while ((mp_hal_ticks_cpu() - startTime) < period) {
- ; // Wait for last bit
- }
- mp_hal_quiet_timing_exit(irq_state);
-}
-
-#endif // MICROPY_ESP8266_NEOPIXEL
diff --git a/ports/esp8266/espneopixel.h b/ports/esp8266/espneopixel.h
deleted file mode 100644
index c444740ff..000000000
--- a/ports/esp8266/espneopixel.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef MICROPY_INCLUDED_ESP8266_ESPNEOPIXEL_H
-#define MICROPY_INCLUDED_ESP8266_ESPNEOPIXEL_H
-
-void esp_neopixel_write(uint8_t pin, uint8_t *pixels, uint32_t numBytes, bool is800KHz);
-
-#endif // MICROPY_INCLUDED_ESP8266_ESPNEOPIXEL_H
diff --git a/ports/esp8266/fatfs_port.c b/ports/esp8266/fatfs_port.c
index bbd105193..3ffc90040 100644
--- a/ports/esp8266/fatfs_port.c
+++ b/ports/esp8266/fatfs_port.c
@@ -25,7 +25,7 @@
*/
#include "py/obj.h"
-#include "lib/timeutils/timeutils.h"
+#include "shared/timeutils/timeutils.h"
#include "lib/oofatfs/ff.h"
#include "modmachine.h"
diff --git a/ports/esp8266/machine_bitstream.c b/ports/esp8266/machine_bitstream.c
new file mode 100644
index 000000000..13666f3d0
--- /dev/null
+++ b/ports/esp8266/machine_bitstream.c
@@ -0,0 +1,74 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Jim Mussared
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+// This is slightly modified from the implementation in ports/esp32/machine_bitstream.c.
+
+#include "py/mpconfig.h"
+#include "py/mphal.h"
+
+#if MICROPY_PY_MACHINE_BITSTREAM
+
+#define NS_TICKS_OVERHEAD (8)
+
+void machine_bitstream_high_low(mp_hal_pin_obj_t pin, uint32_t *timing_ns, const uint8_t *buf, size_t len) {
+ uint32_t pin_mask = 1 << pin;
+
+ // Convert ns to cpu ticks [high_time_0, period_0, high_time_1, period_1].
+ uint32_t fcpu_mhz = system_get_cpu_freq();
+ for (size_t i = 0; i < 4; ++i) {
+ timing_ns[i] = fcpu_mhz * timing_ns[i] / 1000;
+ if (timing_ns[i] > NS_TICKS_OVERHEAD) {
+ timing_ns[i] -= NS_TICKS_OVERHEAD;
+ }
+ if (i % 2 == 1) {
+ // Convert low_time to period (i.e. add high_time).
+ timing_ns[i] += timing_ns[i - 1];
+ }
+ }
+
+ uint32_t irq_state = mp_hal_quiet_timing_enter();
+
+ for (size_t i = 0; i < len; ++i) {
+ uint8_t b = buf[i];
+ for (size_t j = 0; j < 8; ++j) {
+ GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, pin_mask);
+ uint32_t start_ticks = mp_hal_ticks_cpu();
+ uint32_t *t = &timing_ns[b >> 6 & 2];
+ while (mp_hal_ticks_cpu() - start_ticks < t[0]) {
+ ;
+ }
+ GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, pin_mask);
+ b <<= 1;
+ while (mp_hal_ticks_cpu() - start_ticks < t[1]) {
+ ;
+ }
+ }
+ }
+
+ mp_hal_quiet_timing_exit(irq_state);
+}
+
+#endif // MICROPY_PY_MACHINE_BITSTREAM
diff --git a/ports/esp8266/machine_rtc.c b/ports/esp8266/machine_rtc.c
index e7b750fd9..38049ce72 100644
--- a/ports/esp8266/machine_rtc.c
+++ b/ports/esp8266/machine_rtc.c
@@ -28,7 +28,7 @@
#include
#include "py/runtime.h"
-#include "lib/timeutils/timeutils.h"
+#include "shared/timeutils/timeutils.h"
#include "user_interface.h"
#include "modmachine.h"
diff --git a/ports/esp8266/main.c b/ports/esp8266/main.c
index a73fbbcf5..404188346 100644
--- a/ports/esp8266/main.c
+++ b/ports/esp8266/main.c
@@ -39,8 +39,8 @@
#define USE_US_TIMER 1
#include "extmod/misc.h"
-#include "lib/mp-readline/readline.h"
-#include "lib/utils/pyexec.h"
+#include "shared/readline/readline.h"
+#include "shared/runtime/pyexec.h"
#include "gccollect.h"
#include "user_interface.h"
diff --git a/ports/esp8266/modesp.c b/ports/esp8266/modesp.c
index 022447313..eb79d20bc 100644
--- a/ports/esp8266/modesp.c
+++ b/ports/esp8266/modesp.c
@@ -36,7 +36,6 @@
#include "user_interface.h"
#include "mem.h"
#include "ets_alt_task.h"
-#include "espneopixel.h"
#include "espapa102.h"
#include "modmachine.h"
@@ -199,16 +198,6 @@ STATIC mp_obj_t esp_check_fw(void) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp_check_fw_obj, esp_check_fw);
-
-STATIC mp_obj_t esp_neopixel_write_(mp_obj_t pin, mp_obj_t buf, mp_obj_t is800k) {
- mp_buffer_info_t bufinfo;
- mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_READ);
- esp_neopixel_write(mp_obj_get_pin_obj(pin)->phys_port,
- (uint8_t *)bufinfo.buf, bufinfo.len, mp_obj_is_true(is800k));
- return mp_const_none;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_3(esp_neopixel_write_obj, esp_neopixel_write_);
-
#if MICROPY_ESP8266_APA102
STATIC mp_obj_t esp_apa102_write_(mp_obj_t clockPin, mp_obj_t dataPin, mp_obj_t buf) {
mp_buffer_info_t bufinfo;
@@ -363,9 +352,6 @@ STATIC const mp_rom_map_elem_t esp_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_flash_erase), MP_ROM_PTR(&esp_flash_erase_obj) },
{ MP_ROM_QSTR(MP_QSTR_flash_size), MP_ROM_PTR(&esp_flash_size_obj) },
{ MP_ROM_QSTR(MP_QSTR_flash_user_start), MP_ROM_PTR(&esp_flash_user_start_obj) },
- #if MICROPY_ESP8266_NEOPIXEL
- { MP_ROM_QSTR(MP_QSTR_neopixel_write), MP_ROM_PTR(&esp_neopixel_write_obj) },
- #endif
#if MICROPY_ESP8266_APA102
{ MP_ROM_QSTR(MP_QSTR_apa102_write), MP_ROM_PTR(&esp_apa102_write_obj) },
#endif
diff --git a/ports/esp8266/modmachine.c b/ports/esp8266/modmachine.c
index 86c1d728d..6cd458343 100644
--- a/ports/esp8266/modmachine.c
+++ b/ports/esp8266/modmachine.c
@@ -30,11 +30,12 @@
#include "py/obj.h"
#include "py/runtime.h"
-#include "lib/utils/pyexec.h"
+#include "shared/runtime/pyexec.h"
// This needs to be set before we include the RTOS headers
#define USE_US_TIMER 1
+#include "extmod/machine_bitstream.h"
#include "extmod/machine_mem.h"
#include "extmod/machine_signal.h"
#include "extmod/machine_pulse.h"
@@ -411,6 +412,10 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_disable_irq), MP_ROM_PTR(&machine_disable_irq_obj) },
{ MP_ROM_QSTR(MP_QSTR_enable_irq), MP_ROM_PTR(&machine_enable_irq_obj) },
+ #if MICROPY_PY_MACHINE_BITSTREAM
+ { MP_ROM_QSTR(MP_QSTR_bitstream), MP_ROM_PTR(&machine_bitstream_obj) },
+ #endif
+
{ MP_ROM_QSTR(MP_QSTR_time_pulse_us), MP_ROM_PTR(&machine_time_pulse_us_obj) },
{ MP_ROM_QSTR(MP_QSTR_RTC), MP_ROM_PTR(&pyb_rtc_type) },
diff --git a/ports/esp8266/modnetwork.c b/ports/esp8266/modnetwork.c
index 8d153acf0..f0cd83aee 100644
--- a/ports/esp8266/modnetwork.c
+++ b/ports/esp8266/modnetwork.c
@@ -31,7 +31,7 @@
#include "py/objlist.h"
#include "py/runtime.h"
#include "py/mphal.h"
-#include "lib/netutils/netutils.h"
+#include "shared/netutils/netutils.h"
#include "queue.h"
#include "user_interface.h"
#include "espconn.h"
@@ -233,7 +233,9 @@ STATIC mp_obj_t esp_scan(mp_obj_t self_in) {
}
mp_obj_t list = mp_obj_new_list(0, NULL);
esp_scan_list = &list;
- wifi_station_scan(NULL, (scan_done_cb_t)esp_scan_cb);
+ struct scan_config config = {0};
+ config.show_hidden = 1;
+ wifi_station_scan(&config, (scan_done_cb_t)esp_scan_cb);
while (esp_scan_list != NULL) {
// our esp_scan_cb is called via ets_loop_iter so it's safe to set the
// esp_scan_list variable to NULL without disabling interrupts
diff --git a/ports/esp8266/modules/neopixel.py b/ports/esp8266/modules/neopixel.py
deleted file mode 100644
index 9dc153372..000000000
--- a/ports/esp8266/modules/neopixel.py
+++ /dev/null
@@ -1,35 +0,0 @@
-# NeoPixel driver for MicroPython on ESP8266
-# MIT license; Copyright (c) 2016 Damien P. George
-
-from esp import neopixel_write
-
-
-class NeoPixel:
- ORDER = (1, 0, 2, 3)
-
- def __init__(self, pin, n, bpp=3, timing=1):
- self.pin = pin
- self.n = n
- self.bpp = bpp
- self.buf = bytearray(n * bpp)
- self.pin.init(pin.OUT)
- self.timing = timing
-
- def __len__(self):
- return self.n
-
- def __setitem__(self, index, val):
- offset = index * self.bpp
- for i in range(self.bpp):
- self.buf[offset + self.ORDER[i]] = val[i]
-
- def __getitem__(self, index):
- offset = index * self.bpp
- return tuple(self.buf[offset + self.ORDER[i]] for i in range(self.bpp))
-
- def fill(self, color):
- for i in range(self.n):
- self[i] = color
-
- def write(self):
- neopixel_write(self.pin, self.buf, self.timing)
diff --git a/ports/esp8266/modutime.c b/ports/esp8266/modutime.c
index bcfbf7baf..1d4ecc05f 100644
--- a/ports/esp8266/modutime.c
+++ b/ports/esp8266/modutime.c
@@ -32,7 +32,7 @@
#include "py/runtime.h"
#include "py/mphal.h"
#include "py/smallint.h"
-#include "lib/timeutils/timeutils.h"
+#include "shared/timeutils/timeutils.h"
#include "modmachine.h"
#include "user_interface.h"
#include "extmod/utime_mphal.h"
diff --git a/ports/esp8266/mpconfigport.h b/ports/esp8266/mpconfigport.h
index ac47f0aa2..c7e2f4a44 100644
--- a/ports/esp8266/mpconfigport.h
+++ b/ports/esp8266/mpconfigport.h
@@ -79,6 +79,7 @@
#define MICROPY_PY_LWIP_SOCK_RAW (1)
#define MICROPY_PY_MACHINE (1)
#define MICROPY_PY_MACHINE_PIN_MAKE_NEW mp_pin_make_new
+#define MICROPY_PY_MACHINE_BITSTREAM (1)
#define MICROPY_PY_MACHINE_PULSE (1)
#define MICROPY_PY_MACHINE_I2C (1)
#define MICROPY_PY_MACHINE_SPI (1)
@@ -102,7 +103,6 @@
#define MICROPY_FATFS_MAX_SS (4096)
#define MICROPY_FATFS_LFN_CODE_PAGE 437 /* 1=SFN/ANSI 437=LFN/U.S.(OEM) */
#define MICROPY_ESP8266_APA102 (1)
-#define MICROPY_ESP8266_NEOPIXEL (1)
#define MICROPY_EVENT_POLL_HOOK {ets_event_poll();}
#define MICROPY_VM_HOOK_COUNT (10)
@@ -186,6 +186,9 @@ extern const struct _mp_obj_module_t mp_module_onewire;
mp_obj_t pin_irq_handler[16]; \
byte *uart0_rxbuf; \
+// We need an implementation of the log2 function which is not a macro
+#define MP_NEED_LOG2 (1)
+
// We need to provide a declaration/definition of alloca()
#include
diff --git a/ports/esp8266/uart.c b/ports/esp8266/uart.c
index 5ac71da07..978a7efc3 100644
--- a/ports/esp8266/uart.c
+++ b/ports/esp8266/uart.c
@@ -285,7 +285,7 @@ void ICACHE_FLASH_ATTR uart0_set_rxbuf(uint8 *buf, int len) {
// Task-based UART interface
#include "py/obj.h"
-#include "lib/utils/pyexec.h"
+#include "shared/runtime/pyexec.h"
#if MICROPY_REPL_EVENT_DRIVEN
void ICACHE_FLASH_ATTR uart_task_handler(os_event_t *evt) {
diff --git a/ports/javascript/Makefile b/ports/javascript/Makefile
index 9cc45d3ef..3fac114f5 100644
--- a/ports/javascript/Makefile
+++ b/ports/javascript/Makefile
@@ -24,11 +24,11 @@ CFLAGS += -DMICROPY_QSTR_EXTRA_POOL=mp_qstr_frozen_const_pool
CFLAGS += -DMICROPY_MODULE_FROZEN_MPY
endif
-SRC_LIB = $(addprefix lib/,\
- utils/interrupt_char.c \
- utils/stdout_helpers.c \
- utils/pyexec.c \
- mp-readline/readline.c \
+SRC_SHARED = $(addprefix shared/,\
+ runtime/interrupt_char.c \
+ runtime/stdout_helpers.c \
+ runtime/pyexec.c \
+ readline/readline.c \
)
SRC_C = \
@@ -39,11 +39,11 @@ SRC_C = \
SRC_QSTR += $(SRC_C)
OBJ += $(PY_O)
-OBJ += $(addprefix $(BUILD)/, $(SRC_LIB:.c=.o))
+OBJ += $(addprefix $(BUILD)/, $(SRC_SHARED:.c=.o))
OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o))
JSFLAGS += -s ASYNCIFY
-JSFLAGS += -s EXPORTED_FUNCTIONS="['_mp_js_init', '_mp_js_init_repl', '_mp_js_do_str', '_mp_js_process_char', '_mp_hal_get_interrupt_char', '_mp_sched_keyboard_interrupt']" -s EXTRA_EXPORTED_RUNTIME_METHODS="['ccall', 'cwrap']" -s --memory-init-file 0 --js-library library.js
+JSFLAGS += -s EXPORTED_FUNCTIONS="['_mp_js_init', '_mp_js_init_repl', '_mp_js_do_str', '_mp_js_process_char', '_mp_hal_get_interrupt_char', '_mp_sched_keyboard_interrupt']" -s EXPORTED_RUNTIME_METHODS="['ccall', 'cwrap']" -s --memory-init-file 0 --js-library library.js
all: $(BUILD)/micropython.js
diff --git a/ports/javascript/main.c b/ports/javascript/main.c
index c56f1a2cb..7a04b8eea 100644
--- a/ports/javascript/main.c
+++ b/ports/javascript/main.c
@@ -34,7 +34,7 @@
#include "py/repl.h"
#include "py/gc.h"
#include "py/mperrno.h"
-#include "lib/utils/pyexec.h"
+#include "shared/runtime/pyexec.h"
#include "emscripten.h"
#include "library.h"
diff --git a/ports/javascript/modutime.c b/ports/javascript/modutime.c
index d05d832ab..05ff8b22f 100644
--- a/ports/javascript/modutime.c
+++ b/ports/javascript/modutime.c
@@ -32,7 +32,7 @@
#include "py/smallint.h"
#include "py/obj.h"
#include "py/runtime.h"
-#include "lib/timeutils/timeutils.h"
+#include "shared/timeutils/timeutils.h"
#include "extmod/utime_mphal.h"
STATIC const mp_rom_map_elem_t time_module_globals_table[] = {
diff --git a/ports/javascript/mphalport.h b/ports/javascript/mphalport.h
index 614ce8526..3e2c439f3 100644
--- a/ports/javascript/mphalport.h
+++ b/ports/javascript/mphalport.h
@@ -25,7 +25,7 @@
*/
#include "py/obj.h"
-#include "lib/utils/interrupt_char.h"
+#include "shared/runtime/interrupt_char.h"
#define mp_hal_stdin_rx_chr() (0)
void mp_hal_stdout_tx_strn(const char *str, size_t len);
diff --git a/ports/mimxrt/Makefile b/ports/mimxrt/Makefile
index fdb1325fd..818a2a3c8 100644
--- a/ports/mimxrt/Makefile
+++ b/ports/mimxrt/Makefile
@@ -123,6 +123,7 @@ SRC_HAL_IMX_C += \
$(MCU_DIR)/drivers/fsl_gpio.c \
$(MCU_DIR)/drivers/fsl_gpt.c \
$(MCU_DIR)/drivers/fsl_common.c \
+ $(MCU_DIR)/drivers/fsl_lpi2c.c \
$(MCU_DIR)/drivers/fsl_lpspi.c \
$(MCU_DIR)/drivers/fsl_lpspi_edma.c \
$(MCU_DIR)/drivers/fsl_lpuart.c \
@@ -132,7 +133,7 @@ SRC_HAL_IMX_C += \
$(MCU_DIR)/drivers/fsl_snvs_lp.c \
$(MCU_DIR)/drivers/fsl_trng.c \
-SRC_C = \
+SRC_C += \
main.c \
led.c \
pin.c \
@@ -142,6 +143,7 @@ SRC_C = \
dma_channel.c \
$(BOARD_DIR)/flash_config.c \
machine_adc.c \
+ machine_i2c.c \
machine_led.c \
machine_pin.c \
machine_rtc.c \
@@ -154,16 +156,15 @@ SRC_C = \
modmimxrt.c \
moduos.c \
mphalport.c \
- hal/flexspi_nor_flash.c \
- lib/mp-readline/readline.c \
- lib/libc/string0.c \
- lib/timeutils/timeutils.c \
- lib/utils/gchelper_native.c \
- lib/utils/mpirq.c \
- lib/utils/printf.c \
- lib/utils/pyexec.c \
- lib/utils/stdout_helpers.c \
- lib/utils/sys_stdio_mphal.c \
+ shared/libc/printf.c \
+ shared/libc/string0.c \
+ shared/readline/readline.c \
+ shared/runtime/gchelper_native.c \
+ shared/runtime/mpirq.c \
+ shared/runtime/pyexec.c \
+ shared/runtime/stdout_helpers.c \
+ shared/runtime/sys_stdio_mphal.c \
+ shared/timeutils/timeutils.c \
drivers/bus/softspi.c \
extmod/modonewire.c \
$(SRC_TINYUSB_C) \
@@ -264,7 +265,7 @@ endif
SRC_SS = $(MCU_DIR)/gcc/startup_$(MCU_SERIES).S
-SRC_S = lib/utils/gchelper_m3.s \
+SRC_S = shared/runtime/gchelper_m3.s \
# List of sources for qstr extraction
SRC_QSTR += \
@@ -281,8 +282,8 @@ SRC_QSTR += \
modmimxrt.c \
moduos.c \
pin.c \
- lib/utils/mpirq.c \
- lib/utils/sys_stdio_mphal.c \
+ shared/runtime/mpirq.c \
+ shared/runtime/sys_stdio_mphal.c \
extmod/modonewire.c \
$(GEN_PINS_SRC) \
diff --git a/ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.h
index 357670626..2cdb433e1 100644
--- a/ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.h
+++ b/ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.h
@@ -8,6 +8,7 @@
#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin))
#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin))
#define BOARD_FLASH_CONFIG_HEADER_H "evkmimxrt1010_flexspi_nor_config.h"
+#define BOARD_FLASH_OPS_HEADER_H "hal/flexspi_nor_flash.h"
#define MICROPY_HW_NUM_PIN_IRQS (2 * 32)
@@ -33,3 +34,15 @@
#define DMA_REQ_SRC_RX { 0, kDmaRequestMuxLPSPI1Rx, kDmaRequestMuxLPSPI2Rx }
#define DMA_REQ_SRC_TX { 0, kDmaRequestMuxLPSPI1Tx, kDmaRequestMuxLPSPI2Tx }
+
+// Define mapping hardware I2C # to logical I2C #
+// SDA/SCL HW-I2C Logical I2C
+// D14/D15 LPI2C1 -> 0
+// D0/D1 LPI2C2 -> 1
+// D6/D7 LPI2C2 -> 1 Alternatively possible GPIO_AD_01, GPIO_AD_02
+
+#define MICROPY_HW_I2C_INDEX { 1, 2 }
+
+#define IOMUX_TABLE_I2C \
+ { IOMUXC_GPIO_02_LPI2C1_SCL }, { IOMUXC_GPIO_01_LPI2C1_SDA }, \
+ { IOMUXC_GPIO_10_LPI2C2_SCL }, { IOMUXC_GPIO_09_LPI2C2_SDA },
diff --git a/ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.mk b/ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.mk
index ca8efcd5b..ccc8ffeb4 100644
--- a/ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.mk
+++ b/ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.mk
@@ -3,6 +3,9 @@ MCU_VARIANT = MIMXRT1011DAE5A
MICROPY_FLOAT_IMPL = single
+SRC_C += \
+ hal/flexspi_nor_flash.c \
+
JLINK_PATH = /media/RT1010-EVK/
JLINK_COMMANDER_SCRIPT = $(BUILD)/script.jlink
diff --git a/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.h
index 55254d58f..d2a2cbbdb 100644
--- a/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.h
+++ b/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.h
@@ -9,11 +9,13 @@
#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_low(pin))
#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_high(pin))
#define BOARD_FLASH_CONFIG_HEADER_H "evkmimxrt1020_flexspi_nor_config.h"
+#define BOARD_FLASH_OPS_HEADER_H "hal/flexspi_nor_flash.h"
#define MICROPY_HW_NUM_PIN_IRQS (3 * 32)
// Define mapping logical UART # to hardware UART #
-// D3/D5 LPUART1 Not usable, Since D3 is blocked.
+// RX/TX HW-UART Logical UART
+// D3/D5 LPUART1 Not usable, Since D3 is blocked.
// D0/D1 LPUART2 -> 1
// D6/D9 LPUART3 -> 2
// D10/D12 LPUART5 -> 3
@@ -48,3 +50,17 @@
#define DMA_REQ_SRC_TX { 0, kDmaRequestMuxLPSPI1Tx, kDmaRequestMuxLPSPI2Tx, \
kDmaRequestMuxLPSPI3Tx, kDmaRequestMuxLPSPI4Tx }
+
+// Define mapping hardware I2C # to logical I2C #
+// SDA/SCL HW-I2C Logical I2C
+// D14/D15 LPI2C4 -> 0
+// A4/A5 LPI2C1 -> 1
+// D0/D1 LPI2C2 -> 2
+
+#define MICROPY_HW_I2C_INDEX { 4, 1, 2 }
+
+#define IOMUX_TABLE_I2C \
+ { IOMUXC_GPIO_AD_B1_14_LPI2C1_SCL }, { IOMUXC_GPIO_AD_B1_15_LPI2C1_SDA }, \
+ { IOMUXC_GPIO_AD_B1_08_LPI2C2_SCL }, { IOMUXC_GPIO_AD_B1_09_LPI2C2_SDA }, \
+ { 0 }, { 0 }, \
+ { IOMUXC_GPIO_SD_B1_02_LPI2C4_SCL }, { IOMUXC_GPIO_SD_B1_03_LPI2C4_SDA },
diff --git a/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.mk b/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.mk
index b0bbd705c..f8f66b0df 100644
--- a/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.mk
+++ b/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.mk
@@ -3,6 +3,9 @@ MCU_VARIANT = MIMXRT1021DAG5A
MICROPY_FLOAT_IMPL = double
+SRC_C += \
+ hal/flexspi_nor_flash.c \
+
JLINK_PATH ?= /media/RT1020-EVK/
JLINK_COMMANDER_SCRIPT = $(BUILD)/script.jlink
diff --git a/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.h
index db08b1064..af0975bc1 100644
--- a/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.h
+++ b/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.h
@@ -8,6 +8,7 @@
#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_low(pin))
#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_high(pin))
#define BOARD_FLASH_CONFIG_HEADER_H "evkmimxrt1050_flexspi_nor_config.h"
+#define BOARD_FLASH_OPS_HEADER_H "hal/flexspi_nor_flash.h"
#define MICROPY_HW_NUM_PIN_IRQS (4 * 32 + 3)
@@ -41,3 +42,15 @@
#define DMA_REQ_SRC_TX { 0, kDmaRequestMuxLPSPI1Tx, kDmaRequestMuxLPSPI2Tx, \
kDmaRequestMuxLPSPI3Tx, kDmaRequestMuxLPSPI4Tx }
+
+// Define the mapping hardware I2C # to logical I2C #
+// SDA/SCL HW-I2C Logical I2C
+// D14/D15 LPI2C1 -> 0
+// D1/D0 LPI2C3 -> 1
+
+#define MICROPY_HW_I2C_INDEX { 1, 3 }
+
+#define IOMUX_TABLE_I2C \
+ { IOMUXC_GPIO_AD_B1_00_LPI2C1_SCL }, { IOMUXC_GPIO_AD_B1_01_LPI2C1_SDA }, \
+ { 0 }, { 0 }, \
+ { IOMUXC_GPIO_AD_B1_07_LPI2C3_SCL }, { IOMUXC_GPIO_AD_B1_06_LPI2C3_SDA },
diff --git a/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.mk b/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.mk
index e338ec6cf..61826b6f6 100644
--- a/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.mk
+++ b/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.mk
@@ -3,6 +3,9 @@ MCU_VARIANT = MIMXRT1052DVL6B
MICROPY_FLOAT_IMPL = double
+SRC_C += \
+ hal/flexspi_nor_flash.c \
+
JLINK_PATH ?= /media/RT1050-EVK/
deploy: $(BUILD)/firmware.bin
diff --git a/ports/mimxrt/boards/MIMXRT1050_EVKB/MIMXRT1050_EVKB.ld b/ports/mimxrt/boards/MIMXRT1050_EVKB/MIMXRT1050_EVKB.ld
new file mode 100644
index 000000000..f616178a9
--- /dev/null
+++ b/ports/mimxrt/boards/MIMXRT1050_EVKB/MIMXRT1050_EVKB.ld
@@ -0,0 +1 @@
+flash_size = 64M;
\ No newline at end of file
diff --git a/ports/mimxrt/boards/MIMXRT1050_EVKB/evkbmimxrt1050_flexspi_nor_config.h b/ports/mimxrt/boards/MIMXRT1050_EVKB/evkbmimxrt1050_flexspi_nor_config.h
new file mode 100644
index 000000000..02ac394e9
--- /dev/null
+++ b/ports/mimxrt/boards/MIMXRT1050_EVKB/evkbmimxrt1050_flexspi_nor_config.h
@@ -0,0 +1,263 @@
+/*
+ * Copyright 2018 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __EVKMIMXRT1050_FLEXSPI_NOR_CONFIG__
+#define __EVKMIMXRT1050_FLEXSPI_NOR_CONFIG__
+
+#include
+#include
+#include "fsl_flexspi.h"
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief XIP_BOARD driver version 2.0.0. */
+#define FSL_XIP_BOARD_DRIVER_VERSION (MAKE_VERSION(2, 0, 0))
+/*@}*/
+
+/* FLEXSPI memory config block related defintions */
+#define FLEXSPI_CFG_BLK_TAG (0x42464346UL) // ascii "FCFB" Big Endian
+#define FLEXSPI_CFG_BLK_VERSION (0x56010400UL) // V1.4.0
+#define FLEXSPI_CFG_BLK_SIZE (512)
+
+/* FLEXSPI Feature related definitions */
+#define FLEXSPI_FEATURE_HAS_PARALLEL_MODE 1
+
+/* Lookup table related defintions */
+#define CMD_INDEX_READ 0
+#define CMD_INDEX_READSTATUS 1
+#define CMD_INDEX_WRITEENABLE 2
+#define CMD_INDEX_WRITE 4
+
+#define CMD_LUT_SEQ_IDX_READ 0
+#define CMD_LUT_SEQ_IDX_READSTATUS 1
+#define CMD_LUT_SEQ_IDX_WRITEENABLE 3
+#define CMD_LUT_SEQ_IDX_WRITE 9
+
+#define CMD_SDR 0x01
+#define CMD_DDR 0x21
+#define RADDR_SDR 0x02
+#define RADDR_DDR 0x22
+#define CADDR_SDR 0x03
+#define CADDR_DDR 0x23
+#define MODE1_SDR 0x04
+#define MODE1_DDR 0x24
+#define MODE2_SDR 0x05
+#define MODE2_DDR 0x25
+#define MODE4_SDR 0x06
+#define MODE4_DDR 0x26
+#define MODE8_SDR 0x07
+#define MODE8_DDR 0x27
+#define WRITE_SDR 0x08
+#define WRITE_DDR 0x28
+#define READ_SDR 0x09
+#define READ_DDR 0x29
+#define LEARN_SDR 0x0A
+#define LEARN_DDR 0x2A
+#define DATSZ_SDR 0x0B
+#define DATSZ_DDR 0x2B
+#define DUMMY_SDR 0x0C
+#define DUMMY_DDR 0x2C
+#define DUMMY_RWDS_SDR 0x0D
+#define DUMMY_RWDS_DDR 0x2D
+#define JMP_ON_CS 0x1F
+#define STOP 0
+
+#define FLEXSPI_1PAD 0
+#define FLEXSPI_2PAD 1
+#define FLEXSPI_4PAD 2
+#define FLEXSPI_8PAD 3
+
+#define FLEXSPI_LUT_SEQ(cmd0, pad0, op0, cmd1, pad1, op1) \
+ (FLEXSPI_LUT_OPERAND0(op0) | FLEXSPI_LUT_NUM_PADS0(pad0) | FLEXSPI_LUT_OPCODE0(cmd0) | FLEXSPI_LUT_OPERAND1(op1) | \
+ FLEXSPI_LUT_NUM_PADS1(pad1) | FLEXSPI_LUT_OPCODE1(cmd1))
+
+//!@brief Definitions for FlexSPI Serial Clock Frequency
+typedef enum _FlexSpiSerialClockFreq
+{
+ kFlexSpiSerialClk_30MHz = 1,
+ kFlexSpiSerialClk_50MHz = 2,
+ kFlexSpiSerialClk_60MHz = 3,
+ kFlexSpiSerialClk_75MHz = 4,
+ kFlexSpiSerialClk_80MHz = 5,
+ kFlexSpiSerialClk_100MHz = 6,
+ kFlexSpiSerialClk_133MHz = 7,
+ kFlexSpiSerialClk_166MHz = 8,
+} flexspi_serial_clk_freq_t;
+
+//!@brief FlexSPI clock configuration type
+enum
+{
+ kFlexSpiClk_SDR, //!< Clock configure for SDR mode
+ kFlexSpiClk_DDR, //!< Clock configurat for DDR mode
+};
+
+//!@brief FlexSPI Read Sample Clock Source definition
+typedef enum _FlashReadSampleClkSource
+{
+ kFlexSPIReadSampleClk_LoopbackInternally = 0,
+ kFlexSPIReadSampleClk_LoopbackFromDqsPad = 1,
+ kFlexSPIReadSampleClk_LoopbackFromSckPad = 2,
+ kFlexSPIReadSampleClk_ExternalInputFromDqsPad = 3,
+} flexspi_read_sample_clk_t;
+
+//!@brief Misc feature bit definitions
+enum
+{
+ kFlexSpiMiscOffset_DiffClkEnable = 0, //!< Bit for Differential clock enable
+ kFlexSpiMiscOffset_Ck2Enable = 1, //!< Bit for CK2 enable
+ kFlexSpiMiscOffset_ParallelEnable = 2, //!< Bit for Parallel mode enable
+ kFlexSpiMiscOffset_WordAddressableEnable = 3, //!< Bit for Word Addressable enable
+ kFlexSpiMiscOffset_SafeConfigFreqEnable = 4, //!< Bit for Safe Configuration Frequency enable
+ kFlexSpiMiscOffset_PadSettingOverrideEnable = 5, //!< Bit for Pad setting override enable
+ kFlexSpiMiscOffset_DdrModeEnable = 6, //!< Bit for DDR clock confiuration indication.
+};
+
+//!@brief Flash Type Definition
+enum
+{
+ kFlexSpiDeviceType_SerialNOR = 1, //!< Flash devices are Serial NOR
+ kFlexSpiDeviceType_SerialNAND = 2, //!< Flash devices are Serial NAND
+ kFlexSpiDeviceType_SerialRAM = 3, //!< Flash devices are Serial RAM/HyperFLASH
+ kFlexSpiDeviceType_MCP_NOR_NAND = 0x12, //!< Flash device is MCP device, A1 is Serial NOR, A2 is Serial NAND
+ kFlexSpiDeviceType_MCP_NOR_RAM = 0x13, //!< Flash deivce is MCP device, A1 is Serial NOR, A2 is Serial RAMs
+};
+
+//!@brief Flash Pad Definitions
+enum
+{
+ kSerialFlash_1Pad = 1,
+ kSerialFlash_2Pads = 2,
+ kSerialFlash_4Pads = 4,
+ kSerialFlash_8Pads = 8,
+};
+
+//!@brief FlexSPI LUT Sequence structure
+typedef struct _lut_sequence
+{
+ uint8_t seqNum; //!< Sequence Number, valid number: 1-16
+ uint8_t seqId; //!< Sequence Index, valid number: 0-15
+ uint16_t reserved;
+} flexspi_lut_seq_t;
+
+//!@brief Flash Configuration Command Type
+enum
+{
+ kDeviceConfigCmdType_Generic, //!< Generic command, for example: configure dummy cycles, drive strength, etc
+ kDeviceConfigCmdType_QuadEnable, //!< Quad Enable command
+ kDeviceConfigCmdType_Spi2Xpi, //!< Switch from SPI to DPI/QPI/OPI mode
+ kDeviceConfigCmdType_Xpi2Spi, //!< Switch from DPI/QPI/OPI to SPI mode
+ kDeviceConfigCmdType_Spi2NoCmd, //!< Switch to 0-4-4/0-8-8 mode
+ kDeviceConfigCmdType_Reset, //!< Reset device command
+};
+
+//!@brief FlexSPI Memory Configuration Block
+typedef struct _FlexSPIConfig
+{
+ uint32_t tag; //!< [0x000-0x003] Tag, fixed value 0x42464346UL
+ uint32_t version; //!< [0x004-0x007] Version,[31:24] -'V', [23:16] - Major, [15:8] - Minor, [7:0] - bugfix
+ uint32_t reserved0; //!< [0x008-0x00b] Reserved for future use
+ uint8_t readSampleClkSrc; //!< [0x00c-0x00c] Read Sample Clock Source, valid value: 0/1/3
+ uint8_t csHoldTime; //!< [0x00d-0x00d] CS hold time, default value: 3
+ uint8_t csSetupTime; //!< [0x00e-0x00e] CS setup time, default value: 3
+ uint8_t columnAddressWidth; //!< [0x00f-0x00f] Column Address with, for HyperBus protocol, it is fixed to 3, For
+ //! Serial NAND, need to refer to datasheet
+ uint8_t deviceModeCfgEnable; //!< [0x010-0x010] Device Mode Configure enable flag, 1 - Enable, 0 - Disable
+ uint8_t deviceModeType; //!< [0x011-0x011] Specify the configuration command type:Quad Enable, DPI/QPI/OPI switch,
+ //! Generic configuration, etc.
+ uint16_t waitTimeCfgCommands; //!< [0x012-0x013] Wait time for all configuration commands, unit: 100us, Used for
+ //! DPI/QPI/OPI switch or reset command
+ flexspi_lut_seq_t deviceModeSeq; //!< [0x014-0x017] Device mode sequence info, [7:0] - LUT sequence id, [15:8] - LUt
+ //! sequence number, [31:16] Reserved
+ uint32_t deviceModeArg; //!< [0x018-0x01b] Argument/Parameter for device configuration
+ uint8_t configCmdEnable; //!< [0x01c-0x01c] Configure command Enable Flag, 1 - Enable, 0 - Disable
+ uint8_t configModeType[3]; //!< [0x01d-0x01f] Configure Mode Type, similar as deviceModeTpe
+ flexspi_lut_seq_t
+ configCmdSeqs[3]; //!< [0x020-0x02b] Sequence info for Device Configuration command, similar as deviceModeSeq
+ uint32_t reserved1; //!< [0x02c-0x02f] Reserved for future use
+ uint32_t configCmdArgs[3]; //!< [0x030-0x03b] Arguments/Parameters for device Configuration commands
+ uint32_t reserved2; //!< [0x03c-0x03f] Reserved for future use
+ uint32_t controllerMiscOption; //!< [0x040-0x043] Controller Misc Options, see Misc feature bit definitions for more
+ //! details
+ uint8_t deviceType; //!< [0x044-0x044] Device Type: See Flash Type Definition for more details
+ uint8_t sflashPadType; //!< [0x045-0x045] Serial Flash Pad Type: 1 - Single, 2 - Dual, 4 - Quad, 8 - Octal
+ uint8_t serialClkFreq; //!< [0x046-0x046] Serial Flash Frequencey, device specific definitions, See System Boot
+ //! Chapter for more details
+ uint8_t lutCustomSeqEnable; //!< [0x047-0x047] LUT customization Enable, it is required if the program/erase cannot
+ //! be done using 1 LUT sequence, currently, only applicable to HyperFLASH
+ uint32_t reserved3[2]; //!< [0x048-0x04f] Reserved for future use
+ uint32_t sflashA1Size; //!< [0x050-0x053] Size of Flash connected to A1
+ uint32_t sflashA2Size; //!< [0x054-0x057] Size of Flash connected to A2
+ uint32_t sflashB1Size; //!< [0x058-0x05b] Size of Flash connected to B1
+ uint32_t sflashB2Size; //!< [0x05c-0x05f] Size of Flash connected to B2
+ uint32_t csPadSettingOverride; //!< [0x060-0x063] CS pad setting override value
+ uint32_t sclkPadSettingOverride; //!< [0x064-0x067] SCK pad setting override value
+ uint32_t dataPadSettingOverride; //!< [0x068-0x06b] data pad setting override value
+ uint32_t dqsPadSettingOverride; //!< [0x06c-0x06f] DQS pad setting override value
+ uint32_t timeoutInMs; //!< [0x070-0x073] Timeout threshold for read status command
+ uint32_t commandInterval; //!< [0x074-0x077] CS deselect interval between two commands
+ uint16_t dataValidTime[2]; //!< [0x078-0x07b] CLK edge to data valid time for PORT A and PORT B, in terms of 0.1ns
+ uint16_t busyOffset; //!< [0x07c-0x07d] Busy offset, valid value: 0-31
+ uint16_t busyBitPolarity; //!< [0x07e-0x07f] Busy flag polarity, 0 - busy flag is 1 when flash device is busy, 1 -
+ //! busy flag is 0 when flash device is busy
+ uint32_t lookupTable[64]; //!< [0x080-0x17f] Lookup table holds Flash command sequences
+ flexspi_lut_seq_t lutCustomSeq[12]; //!< [0x180-0x1af] Customizable LUT Sequences
+ uint32_t reserved4[4]; //!< [0x1b0-0x1bf] Reserved for future use
+} flexspi_mem_config_t;
+
+/* */
+#define NOR_CMD_LUT_SEQ_IDX_READ_NORMAL 0
+#define NOR_CMD_LUT_SEQ_IDX_READSTATUSREG 1
+#define NOR_CMD_LUT_SEQ_IDX_READ_FAST_QUAD 2
+#define NOR_CMD_LUT_SEQ_IDX_WRITEENABLE 3
+#define NOR_CMD_LUT_SEQ_IDX_READSTATUS_XPI 4
+#define NOR_CMD_LUT_SEQ_IDX_ERASESECTOR 5
+#define NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG 6
+#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_QUAD 7
+#define NOR_CMD_LUT_SEQ_IDX_READID 8
+#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM 9
+#define NOR_CMD_LUT_SEQ_IDX_ENTERQPI 10
+#define NOR_CMD_LUT_SEQ_IDX_CHIPERASE 11
+#define NOR_CMD_LUT_SEQ_IDX_EXITQPI 12
+
+#define HYPERFLASH_CMD_LUT_SEQ_IDX_READDATA 0
+#define HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEDATA 1
+#define HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS 2
+#define HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE 4
+#define HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR 6
+#define HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM 10
+#define HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP 12
+
+/*
+ * Serial NOR configuration block
+ */
+typedef struct _flexspi_nor_config
+{
+ flexspi_mem_config_t memConfig; //!< Common memory configuration info via FlexSPI
+ uint32_t pageSize; //!< Page size of Serial NOR
+ uint32_t sectorSize; //!< Sector size of Serial NOR
+ uint8_t ipcmdSerialClkFreq; //!< Clock frequency for IP command
+ uint8_t isUniformBlockSize; //!< Sector/Block size is the same
+ uint8_t reserved0[2]; //!< Reserved for future use
+ uint8_t serialNorType; //!< Serial NOR Flash type: 0/1/2/3
+ uint8_t needExitNoCmdMode; //!< Need to exit NoCmd mode before other IP command
+ uint8_t halfClkForNonReadCmd; //!< Half the Serial Clock for non-read command: true/false
+ uint8_t needRestoreNoCmdMode; //!< Need to Restore NoCmd mode after IP commmand execution
+ uint32_t blockSize; //!< Block size
+ uint32_t reserve2[11]; //!< Reserved for future use
+} flexspi_nor_config_t;
+
+#define FLASH_BUSY_STATUS_POL 0
+#define FLASH_BUSY_STATUS_OFFSET 0
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __EVKMIMXRT1050_FLEXSPI_NOR_CONFIG__ */
diff --git a/ports/mimxrt/boards/MIMXRT1050_EVKB/flash_config.c b/ports/mimxrt/boards/MIMXRT1050_EVKB/flash_config.c
new file mode 100644
index 000000000..e8190bcb6
--- /dev/null
+++ b/ports/mimxrt/boards/MIMXRT1050_EVKB/flash_config.c
@@ -0,0 +1,186 @@
+/*
+ * Copyright 2018 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "evkbmimxrt1050_flexspi_nor_config.h"
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.xip_board"
+#endif
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+#if defined(XIP_BOOT_HEADER_ENABLE) && (XIP_BOOT_HEADER_ENABLE == 1)
+#if defined(__CC_ARM) || defined(__ARMCC_VERSION) || defined(__GNUC__)
+__attribute__((section(".boot_hdr.conf")))
+#elif defined(__ICCARM__)
+#pragma location = ".boot_hdr.conf"
+#endif
+
+const flexspi_nor_config_t qspiflash_config = {
+ .memConfig =
+ {
+ .tag = FLEXSPI_CFG_BLK_TAG,
+ .version = FLEXSPI_CFG_BLK_VERSION,
+ .readSampleClkSrc = kFlexSPIReadSampleClk_ExternalInputFromDqsPad,
+ .csHoldTime = 3u,
+ .csSetupTime = 3u,
+ .columnAddressWidth = 3u,
+ // Enable DDR mode, Wordaddressable, Safe configuration, Differential clock
+ .controllerMiscOption =
+ (1u << kFlexSpiMiscOffset_DdrModeEnable) | (1u << kFlexSpiMiscOffset_WordAddressableEnable) |
+ (1u << kFlexSpiMiscOffset_SafeConfigFreqEnable) | (1u << kFlexSpiMiscOffset_DiffClkEnable),
+ .sflashPadType = kSerialFlash_8Pads,
+ .serialClkFreq = kFlexSpiSerialClk_133MHz,
+ .sflashA1Size = 64u * 1024u * 1024u,
+ .dataValidTime = {16u, 16u},
+ .lookupTable =
+ {
+ /* 0 Read Data */
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READDATA] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xA0, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READDATA + 1] = FLEXSPI_LUT_SEQ(
+ kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_READ_DDR, kFLEXSPI_8PAD, 0x04),
+
+ /* 1 Write Data */
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEDATA] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEDATA + 1] = FLEXSPI_LUT_SEQ(
+ kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_WRITE_DDR, kFLEXSPI_8PAD, 0x02),
+
+ /* 2 Read Status */
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 1] = FLEXSPI_LUT_SEQ(
+ kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), // ADDR 0x555
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 2] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 3] = FLEXSPI_LUT_SEQ(
+ kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x70), // DATA 0x70
+ // +1
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 4] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xA0, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 5] = FLEXSPI_LUT_SEQ(
+ kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_DUMMY_RWDS_DDR, kFLEXSPI_8PAD, 0x0B),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 6] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_READ_DDR, kFLEXSPI_8PAD, 0x04, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x0),
+
+ /* 4 Write Enable */
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 1] = FLEXSPI_LUT_SEQ(
+ kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), // ADDR 0x555
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 2] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 3] = FLEXSPI_LUT_SEQ(
+ kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), // DATA 0xAA
+ // +1
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 4] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 5] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 6] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x02),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 7] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55),
+
+ /* 6 Erase Sector */
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 1] = FLEXSPI_LUT_SEQ(
+ kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), // ADDR 0x555
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 2] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 3] = FLEXSPI_LUT_SEQ(
+ kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x80), // DATA 0x80
+ // +1
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 4] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 5] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 6] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 7] = FLEXSPI_LUT_SEQ(
+ kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), // ADDR 0x555
+ // +2
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 8] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 9] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 10] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x02),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 11] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55),
+ // +3
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 12] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 13] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 14] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x30, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x00),
+
+ /* 10 program page with word program command sequence */
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 1] = FLEXSPI_LUT_SEQ(
+ kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), // ADDR 0x555
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 2] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 3] = FLEXSPI_LUT_SEQ(
+ kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xA0), // DATA 0xA0
+ // +1
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 4] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 5] = FLEXSPI_LUT_SEQ(
+ kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_WRITE_DDR, kFLEXSPI_8PAD, 0x80),
+
+ /* 12 Erase chip */
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 1] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 2] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 3] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x80),
+ // +1
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 4] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 5] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 6] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 7] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),
+ // +2
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 8] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 9] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 10] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x02),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 11] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55),
+ // +3
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 12] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 13] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 14] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 15] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x10),
+ },
+ },
+ .pageSize = 512u,
+ .sectorSize = 256u * 1024u,
+ .blockSize = 256u * 1024u,
+ .isUniformBlockSize = true,
+};
+
+#endif /* XIP_BOOT_HEADER_ENABLE */
diff --git a/ports/mimxrt/boards/MIMXRT1050_EVKB/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1050_EVKB/mpconfigboard.h
new file mode 100644
index 000000000..518240b03
--- /dev/null
+++ b/ports/mimxrt/boards/MIMXRT1050_EVKB/mpconfigboard.h
@@ -0,0 +1,69 @@
+#define MICROPY_HW_BOARD_NAME "i.MX RT1050 EVKB"
+#define MICROPY_HW_MCU_NAME "MIMXRT1052DVL6B"
+
+#define BOARD_FLASH_SIZE (64 * 1024 * 1024)
+
+// MIMXRT1050_EVKB has 1 user LED
+#define MICROPY_HW_LED1_PIN (pin_GPIO_AD_B0_09)
+#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_low(pin))
+#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_high(pin))
+#define BOARD_FLASH_CONFIG_HEADER_H "evkbmimxrt1050_flexspi_nor_config.h"
+#define BOARD_FLASH_OPS_HEADER_H "hal/flexspi_hyper_flash.h"
+
+#define MICROPY_HW_NUM_PIN_IRQS (4 * 32 + 3)
+
+// Define mapping logical UART # to hardware UART #
+// LPUART3 on D0/D1 -> 1
+// LPUART2 on D7/D6 -> 2
+// LPUART6 on D8/D9 -> 3
+// LPUART8 on A1/A0 -> 4
+
+#define MICROPY_HW_UART_NUM (sizeof(uart_index_table) / sizeof(uart_index_table)[0])
+#define MICROPY_HW_UART_INDEX { 0, 3, 2, 6, 8 }
+
+#define IOMUX_TABLE_UART \
+ { 0 }, { 0 }, \
+ { IOMUXC_GPIO_AD_B1_02_LPUART2_TX }, { IOMUXC_GPIO_AD_B1_03_LPUART2_RX }, \
+ { IOMUXC_GPIO_AD_B1_06_LPUART3_TX }, { IOMUXC_GPIO_AD_B1_07_LPUART3_RX }, \
+ { 0 }, { 0 }, \
+ { 0 }, { 0 }, \
+ { IOMUXC_GPIO_AD_B0_02_LPUART6_TX }, { IOMUXC_GPIO_AD_B0_03_LPUART6_RX }, \
+ { 0 }, { 0 }, \
+ { IOMUXC_GPIO_AD_B1_10_LPUART8_TX }, { IOMUXC_GPIO_AD_B1_11_LPUART8_RX },
+
+#define MICROPY_HW_SPI_INDEX { 1 }
+
+#define IOMUX_TABLE_SPI \
+ { IOMUXC_GPIO_SD_B0_00_LPSPI1_SCK }, { IOMUXC_GPIO_SD_B0_01_LPSPI1_PCS0 }, \
+ { IOMUXC_GPIO_SD_B0_02_LPSPI1_SDO }, { IOMUXC_GPIO_SD_B0_03_LPSPI1_SDI },
+
+#define DMA_REQ_SRC_RX { 0, kDmaRequestMuxLPSPI1Rx, kDmaRequestMuxLPSPI2Rx, \
+ kDmaRequestMuxLPSPI3Rx, kDmaRequestMuxLPSPI4Rx }
+
+#define DMA_REQ_SRC_TX { 0, kDmaRequestMuxLPSPI1Tx, kDmaRequestMuxLPSPI2Tx, \
+ kDmaRequestMuxLPSPI3Tx, kDmaRequestMuxLPSPI4Tx }
+
+// Define the mapping hardware I2C # to logical I2C #
+// SDA/SCL HW-I2C Logical I2C
+// D14/D15 LPI2C1 -> 0
+// D1/D0 LPI2C3 -> 1
+
+#define MICROPY_HW_I2C_INDEX { 1, 3 }
+
+#define IOMUX_TABLE_I2C \
+ { IOMUXC_GPIO_AD_B1_00_LPI2C1_SCL }, { IOMUXC_GPIO_AD_B1_01_LPI2C1_SDA }, \
+ { 0 }, { 0 }, \
+ { IOMUXC_GPIO_AD_B1_07_LPI2C3_SCL }, { IOMUXC_GPIO_AD_B1_06_LPI2C3_SDA },
+
+#define USDHC_DUMMY_PIN NULL , 0
+
+#define MICROPY_USDHC1 \
+ { \
+ .cmd = {GPIO_SD_B0_00_USDHC1_CMD}, \
+ .clk = { GPIO_SD_B0_01_USDHC1_CLK }, \
+ .cd_b = { GPIO_B1_12_USDHC1_CD_B },\
+ .data0 = { GPIO_SD_B0_02_USDHC1_DATA0 },\
+ .data1 = { GPIO_SD_B0_03_USDHC1_DATA1 },\
+ .data2 = { GPIO_SD_B0_04_USDHC1_DATA2 },\
+ .data3 = { GPIO_SD_B0_05_USDHC1_DATA3 },\
+ }
diff --git a/ports/mimxrt/boards/MIMXRT1050_EVKB/mpconfigboard.mk b/ports/mimxrt/boards/MIMXRT1050_EVKB/mpconfigboard.mk
new file mode 100644
index 000000000..c9e32612c
--- /dev/null
+++ b/ports/mimxrt/boards/MIMXRT1050_EVKB/mpconfigboard.mk
@@ -0,0 +1,12 @@
+MCU_SERIES = MIMXRT1052
+MCU_VARIANT = MIMXRT1052DVL6B
+
+MICROPY_FLOAT_IMPL = double
+
+SRC_C += \
+ hal/flexspi_hyper_flash.c \
+
+JLINK_PATH ?= /media/RT1050-EVKB/
+
+deploy: $(BUILD)/firmware.bin
+ cp $< $(JLINK_PATH)
diff --git a/ports/mimxrt/boards/MIMXRT1050_EVKB/pins.csv b/ports/mimxrt/boards/MIMXRT1050_EVKB/pins.csv
new file mode 100644
index 000000000..366a141ff
--- /dev/null
+++ b/ports/mimxrt/boards/MIMXRT1050_EVKB/pins.csv
@@ -0,0 +1,31 @@
+D0,GPIO_AD_B1_07
+D1,GPIO_AD_B1_06
+D2,GPIO_AD_B0_11
+D3,GPIO_AD_B1_08
+D4,GPIO_AD_B0_09
+D5,GPIO_AD_B0_10
+D6,GPIO_AD_B1_02
+D7,GPIO_AD_B1_03
+D8,GPIO_AD_B0_03
+D9,GPIO_AD_B0_02
+D10,GPIO_SD_B0_01
+D11,GPIO_SD_B0_02
+D12,GPIO_SD_B0_03
+D13,GPIO_SD_B0_00
+D14,GPIO_AD_B1_01
+D15,GPIO_AD_B1_00
+A0,GPIO_AD_B1_10
+A1,GPIO_AD_B1_11
+A2,GPIO_AD_B1_04
+A3,GPIO_AD_B1_05
+A4,GPIO_AD_B1_01
+A5,GPIO_AD_B1_00
+RX,GPIO_AD_B1_07
+TX,GPIO_AD_B1_06
+SCL,GPIO_AD_B1_00
+SDA,GPIO_AD_B1_01
+SCK,GPIO_SD_B0_00
+SDI,GPIO_SD_B0_03
+SDO,GPIO_SD_B0_02
+CS,GPIO_SD_B0_01
+LED_GREEN,GPIO_AD_B0_09
diff --git a/ports/mimxrt/boards/MIMXRT1052.ld b/ports/mimxrt/boards/MIMXRT1052.ld
index f78773531..751929794 100644
--- a/ports/mimxrt/boards/MIMXRT1052.ld
+++ b/ports/mimxrt/boards/MIMXRT1052.ld
@@ -8,8 +8,8 @@ ivt_size = 0x00001000;
interrupts_start = 0x60002000;
interrupts_size = 0x00000400;
text_start = 0x60002400;
-text_size = ((((text_start) + 1M) + (4k - 1)) & ~(4k - 1)) - (text_start); /* reserve 1M for code but align on 4k boundary */
-vfs_start = (text_start) + (text_size);
+vfs_start = 0x60100000;
+text_size = ((vfs_start) - (text_start));
vfs_size = ((flash_end) - (vfs_start));
itcm_start = 0x00000000;
itcm_size = 0x00020000;
diff --git a/ports/mimxrt/boards/MIMXRT1060_EVK/MIMXRT1060_EVK.ld b/ports/mimxrt/boards/MIMXRT1060_EVK/MIMXRT1060_EVK.ld
index fd1bf32ed..f616178a9 100644
--- a/ports/mimxrt/boards/MIMXRT1060_EVK/MIMXRT1060_EVK.ld
+++ b/ports/mimxrt/boards/MIMXRT1060_EVK/MIMXRT1060_EVK.ld
@@ -1 +1 @@
-flash_size = 8M;
\ No newline at end of file
+flash_size = 64M;
\ No newline at end of file
diff --git a/ports/mimxrt/boards/MIMXRT1060_EVK/evkmimxrt1060_flexspi_nor_config.h b/ports/mimxrt/boards/MIMXRT1060_EVK/evkmimxrt1060_flexspi_nor_config.h
index 03bdac1f1..cff520e0e 100644
--- a/ports/mimxrt/boards/MIMXRT1060_EVK/evkmimxrt1060_flexspi_nor_config.h
+++ b/ports/mimxrt/boards/MIMXRT1060_EVK/evkmimxrt1060_flexspi_nor_config.h
@@ -10,7 +10,7 @@
#include
#include
-#include "fsl_common.h"
+#include "fsl_flexspi.h"
/*! @name Driver version */
/*@{*/
@@ -224,6 +224,14 @@ typedef struct _FlexSPIConfig
#define NOR_CMD_LUT_SEQ_IDX_CHIPERASE 11
#define NOR_CMD_LUT_SEQ_IDX_EXITQPI 12
+#define HYPERFLASH_CMD_LUT_SEQ_IDX_READDATA 0
+#define HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEDATA 1
+#define HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS 2
+#define HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE 4
+#define HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR 6
+#define HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM 10
+#define HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP 12
+
/*
* Serial NOR configuration block
*/
diff --git a/ports/mimxrt/boards/MIMXRT1060_EVK/flash_config.c b/ports/mimxrt/boards/MIMXRT1060_EVK/flash_config.c
index 3fa584b73..e28f58154 100644
--- a/ports/mimxrt/boards/MIMXRT1060_EVK/flash_config.c
+++ b/ports/mimxrt/boards/MIMXRT1060_EVK/flash_config.c
@@ -25,98 +25,162 @@ __attribute__((section(".boot_hdr.conf")))
const flexspi_nor_config_t qspiflash_config = {
.memConfig =
{
- .tag = FLEXSPI_CFG_BLK_TAG,
- .version = FLEXSPI_CFG_BLK_VERSION,
- .readSampleClkSrc = kFlexSPIReadSampleClk_LoopbackFromDqsPad,
- .csHoldTime = 3u,
- .csSetupTime = 3u,
- .sflashPadType = kSerialFlash_4Pads,
- .serialClkFreq = kFlexSpiSerialClk_100MHz,
- .sflashA1Size = 8u * 1024u * 1024u,
+ .tag = FLEXSPI_CFG_BLK_TAG,
+ .version = FLEXSPI_CFG_BLK_VERSION,
+ .readSampleClkSrc = kFlexSPIReadSampleClk_ExternalInputFromDqsPad,
+ .csHoldTime = 3u,
+ .csSetupTime = 3u,
+ .columnAddressWidth = 3u,
+ // Enable DDR mode, Wordaddressable, Safe configuration, Differential clock
+ .controllerMiscOption =
+ (1u << kFlexSpiMiscOffset_DdrModeEnable) | (1u << kFlexSpiMiscOffset_WordAddressableEnable) |
+ (1u << kFlexSpiMiscOffset_SafeConfigFreqEnable) | (1u << kFlexSpiMiscOffset_DiffClkEnable),
+ .sflashPadType = kSerialFlash_8Pads,
+ .serialClkFreq = kFlexSpiSerialClk_133MHz,
+ .sflashA1Size = 64u * 1024u * 1024u,
+ .dataValidTime = {16u, 16u},
.lookupTable =
{
- // 0 Read LUTs 0 -> 0
- FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0xEB, RADDR_SDR, FLEXSPI_4PAD, 0x18),
- FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_4PAD, 0x06, READ_SDR, FLEXSPI_4PAD, 0x04),
- FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
- FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
+ /* 0 Read Data */
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READDATA] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xA0, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READDATA + 1] = FLEXSPI_LUT_SEQ(
+ kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_READ_DDR, kFLEXSPI_8PAD, 0x04),
- // 1 Read status register -> 1
- FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x05, READ_SDR, FLEXSPI_1PAD, 0x01),
- FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
- FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
- FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
+ /* 1 Write Data */
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEDATA] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEDATA + 1] = FLEXSPI_LUT_SEQ(
+ kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_WRITE_DDR, kFLEXSPI_8PAD, 0x02),
- // 2 Fast read quad mode - SDR
- FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x6B, RADDR_SDR, FLEXSPI_1PAD, 0x18),
- FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_4PAD, 0x08, READ_SDR, FLEXSPI_4PAD, 0x04),
- FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
- FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
+ /* 2 Read Status */
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 1] = FLEXSPI_LUT_SEQ(
+ kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), // ADDR 0x555
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 2] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 3] = FLEXSPI_LUT_SEQ(
+ kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x70), // DATA 0x70
+ // +1
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 4] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xA0, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 5] = FLEXSPI_LUT_SEQ(
+ kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_DUMMY_RWDS_DDR, kFLEXSPI_8PAD, 0x0B),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 6] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_READ_DDR, kFLEXSPI_8PAD, 0x04, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x0),
- // 3 Write Enable -> 3
- FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x06, STOP, FLEXSPI_1PAD, 0),
- FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
- FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
- FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
+ /* 4 Write Enable */
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 1] = FLEXSPI_LUT_SEQ(
+ kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), // ADDR 0x555
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 2] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 3] = FLEXSPI_LUT_SEQ(
+ kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), // DATA 0xAA
+ // +1
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 4] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 5] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 6] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x02),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 7] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55),
- // 4 Read extend parameters
- FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x81, READ_SDR, FLEXSPI_1PAD, 0x04),
- FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
- FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
- FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
+ /* 6 Erase Sector */
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 1] = FLEXSPI_LUT_SEQ(
+ kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), // ADDR 0x555
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 2] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 3] = FLEXSPI_LUT_SEQ(
+ kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x80), // DATA 0x80
+ // +1
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 4] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 5] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 6] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 7] = FLEXSPI_LUT_SEQ(
+ kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), // ADDR 0x555
+ // +2
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 8] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 9] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 10] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x02),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 11] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55),
+ // +3
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 12] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 13] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 14] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x30, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x00),
- // 5 Erase Sector -> 5
- FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x20, RADDR_SDR, FLEXSPI_1PAD, 24),
- FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
- FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
- FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
+ /* 10 program page with word program command sequence */
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 1] = FLEXSPI_LUT_SEQ(
+ kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), // ADDR 0x555
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 2] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 3] = FLEXSPI_LUT_SEQ(
+ kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xA0), // DATA 0xA0
+ // +1
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 4] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 5] = FLEXSPI_LUT_SEQ(
+ kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_WRITE_DDR, kFLEXSPI_8PAD, 0x80),
- // 6 Write Status Reg
- FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x01, WRITE_SDR, FLEXSPI_1PAD, 0x04),
- FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
- FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
- FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
- // 7 Page Program - quad mode (-> 9)
- FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x32, RADDR_SDR, FLEXSPI_1PAD, 0x18),
- FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_4PAD, 0x04, STOP, FLEXSPI_1PAD, 0),
- FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
- FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
- // 8 Read ID
- FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x90, DUMMY_SDR, FLEXSPI_1PAD, 24),
- FLEXSPI_LUT_SEQ(READ_SDR, FLEXSPI_1PAD, 0x00, 0, 0, 0),
- FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
- FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
- // 9 Page Program - single mode -> 9
- FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x02, RADDR_SDR, FLEXSPI_1PAD, 24),
- FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_1PAD, 0, 0, 0, 0),
- FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
- FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
- // 10 Enter QPI mode
- FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x35, STOP, FLEXSPI_1PAD, 0),
- FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
- FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
- FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
- // 11 Erase Chip
- FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x60, STOP, FLEXSPI_1PAD, 0),
- FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
- FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
- FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
- // 12 Exit QPI mode
- FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_4PAD, 0xF5, STOP, FLEXSPI_1PAD, 0),
- FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
- FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
- FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
+ /* 12 Erase chip */
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 1] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 2] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 3] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x80),
+ // +1
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 4] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 5] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 6] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 7] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),
+ // +2
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 8] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 9] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 10] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x02),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 11] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55),
+ // +3
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 12] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 13] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 14] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 15] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x10),
},
},
- .pageSize = 256u,
- .sectorSize = 4u * 1024u,
- .blockSize = 64u * 1024u,
- .isUniformBlockSize = false,
+ .pageSize = 512u,
+ .sectorSize = 256u * 1024u,
+ .blockSize = 256u * 1024u,
+ .isUniformBlockSize = true,
};
+
#endif /* XIP_BOOT_HEADER_ENABLE */
diff --git a/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.h
index 451d53daf..c207da832 100644
--- a/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.h
+++ b/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.h
@@ -8,6 +8,7 @@
#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_low(pin))
#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_high(pin))
#define BOARD_FLASH_CONFIG_HEADER_H "evkmimxrt1060_flexspi_nor_config.h"
+#define BOARD_FLASH_OPS_HEADER_H "hal/flexspi_hyper_flash.h"
#define MICROPY_HW_NUM_PIN_IRQS (4 * 32 + 3)
@@ -41,3 +42,15 @@
#define DMA_REQ_SRC_TX { 0, kDmaRequestMuxLPSPI1Tx, kDmaRequestMuxLPSPI2Tx, \
kDmaRequestMuxLPSPI3Tx, kDmaRequestMuxLPSPI4Tx }
+
+// Define the mapping hardware I2C # to logical I2C #
+// SDA/SCL HW-I2C Logical I2C
+// D14/D15 LPI2C1 -> 0
+// D1/D0 LPI2C3 -> 1
+
+#define MICROPY_HW_I2C_INDEX { 1, 3 }
+
+#define IOMUX_TABLE_I2C \
+ { IOMUXC_GPIO_AD_B1_00_LPI2C1_SCL }, { IOMUXC_GPIO_AD_B1_01_LPI2C1_SDA }, \
+ { 0 }, { 0 }, \
+ { IOMUXC_GPIO_AD_B1_07_LPI2C3_SCL }, { IOMUXC_GPIO_AD_B1_06_LPI2C3_SDA },
diff --git a/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.mk b/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.mk
index b7ea5fcbe..f5eaf3eab 100644
--- a/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.mk
+++ b/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.mk
@@ -3,6 +3,9 @@ MCU_VARIANT = MIMXRT1062DVJ6A
MICROPY_FLOAT_IMPL = double
+SRC_C += \
+ hal/flexspi_hyper_flash.c \
+
JLINK_PATH ?= /media/RT1060-EVK/
JLINK_COMMANDER_SCRIPT = $(BUILD)/script.jlink
diff --git a/ports/mimxrt/boards/MIMXRT1064.ld b/ports/mimxrt/boards/MIMXRT1064.ld
index 236d98429..820393001 100644
--- a/ports/mimxrt/boards/MIMXRT1064.ld
+++ b/ports/mimxrt/boards/MIMXRT1064.ld
@@ -8,8 +8,8 @@ ivt_size = 0x00001000;
interrupts_start = 0x60002000;
interrupts_size = 0x00000400;
text_start = 0x60002400;
-text_size = ((((text_start) + 1M) + (4k - 1)) & ~(4k - 1)) - (text_start); /* reserve 1M for code but align on 4k boundary */
-vfs_start = (text_start) + (text_size);
+vfs_start = 0x60100000;
+text_size = ((vfs_start) - (text_start));
vfs_size = ((flash_end) - (vfs_start));
itcm_start = 0x00000000;
itcm_size = 0x00020000;
@@ -25,4 +25,4 @@ _sstack = __StackLimit;
/* Use second OCRAM bank for GC heap. */
_gc_heap_start = ORIGIN(m_ocrm);
-_gc_heap_end = ORIGIN(m_ocrm) + LENGTH(m_ocrm);
\ No newline at end of file
+_gc_heap_end = ORIGIN(m_ocrm) + LENGTH(m_ocrm);
diff --git a/ports/mimxrt/boards/MIMXRT1064_EVK/MIMXRT1064_EVK.ld b/ports/mimxrt/boards/MIMXRT1064_EVK/MIMXRT1064_EVK.ld
index fd1bf32ed..f616178a9 100644
--- a/ports/mimxrt/boards/MIMXRT1064_EVK/MIMXRT1064_EVK.ld
+++ b/ports/mimxrt/boards/MIMXRT1064_EVK/MIMXRT1064_EVK.ld
@@ -1 +1 @@
-flash_size = 8M;
\ No newline at end of file
+flash_size = 64M;
\ No newline at end of file
diff --git a/ports/mimxrt/boards/MIMXRT1064_EVK/evkmimxrt1064_flexspi_nor_config.h b/ports/mimxrt/boards/MIMXRT1064_EVK/evkmimxrt1064_flexspi_nor_config.h
index 3c433f3be..7560f2483 100644
--- a/ports/mimxrt/boards/MIMXRT1064_EVK/evkmimxrt1064_flexspi_nor_config.h
+++ b/ports/mimxrt/boards/MIMXRT1064_EVK/evkmimxrt1064_flexspi_nor_config.h
@@ -10,7 +10,7 @@
#include
#include
-#include "fsl_common.h"
+#include "fsl_flexspi.h"
/*! @name Driver version */
/*@{*/
@@ -19,9 +19,9 @@
/*@}*/
/* FLEXSPI memory config block related defintions */
-#define FLEXSPI_CFG_BLK_TAG (0x42464346UL) // ascii "FCFB" Big Endian
+#define FLEXSPI_CFG_BLK_TAG (0x42464346UL) // ascii "FCFB" Big Endian
#define FLEXSPI_CFG_BLK_VERSION (0x56010400UL) // V1.4.0
-#define FLEXSPI_CFG_BLK_SIZE (512)
+#define FLEXSPI_CFG_BLK_SIZE (512)
/* FLEXSPI Feature related definitions */
#define FLEXSPI_FEATURE_HAS_PARALLEL_MODE 1
@@ -223,6 +223,15 @@ typedef struct _FlexSPIConfig
#define NOR_CMD_LUT_SEQ_IDX_ENTERQPI 10
#define NOR_CMD_LUT_SEQ_IDX_CHIPERASE 11
#define NOR_CMD_LUT_SEQ_IDX_EXITQPI 12
+
+#define HYPERFLASH_CMD_LUT_SEQ_IDX_READDATA 0
+#define HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEDATA 1
+#define HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS 2
+#define HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE 4
+#define HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR 6
+#define HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM 10
+#define HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP 12
+
/*
* Serial NOR configuration block
*/
diff --git a/ports/mimxrt/boards/MIMXRT1064_EVK/flash_config.c b/ports/mimxrt/boards/MIMXRT1064_EVK/flash_config.c
index 9338c6948..f308b7f8a 100644
--- a/ports/mimxrt/boards/MIMXRT1064_EVK/flash_config.c
+++ b/ports/mimxrt/boards/MIMXRT1064_EVK/flash_config.c
@@ -25,99 +25,162 @@ __attribute__((section(".boot_hdr.conf")))
const flexspi_nor_config_t qspiflash_config = {
.memConfig =
{
- .tag = FLEXSPI_CFG_BLK_TAG,
- .version = FLEXSPI_CFG_BLK_VERSION,
- .readSampleClkSrc = kFlexSPIReadSampleClk_LoopbackFromDqsPad,
- .csHoldTime = 3u,
- .csSetupTime = 3u,
- // Enable DDR mode, Wordaddassable, Safe configuration, Differential clock
- .sflashPadType = kSerialFlash_4Pads,
- .serialClkFreq = kFlexSpiSerialClk_100MHz,
- .sflashA1Size = 8u * 1024u * 1024u,
+ .tag = FLEXSPI_CFG_BLK_TAG,
+ .version = FLEXSPI_CFG_BLK_VERSION,
+ .readSampleClkSrc = kFlexSPIReadSampleClk_ExternalInputFromDqsPad,
+ .csHoldTime = 3u,
+ .csSetupTime = 3u,
+ .columnAddressWidth = 3u,
+ // Enable DDR mode, Wordaddressable, Safe configuration, Differential clock
+ .controllerMiscOption =
+ (1u << kFlexSpiMiscOffset_DdrModeEnable) | (1u << kFlexSpiMiscOffset_WordAddressableEnable) |
+ (1u << kFlexSpiMiscOffset_SafeConfigFreqEnable) | (1u << kFlexSpiMiscOffset_DiffClkEnable),
+ .sflashPadType = kSerialFlash_8Pads,
+ .serialClkFreq = kFlexSpiSerialClk_133MHz,
+ .sflashA1Size = 64u * 1024u * 1024u,
+ .dataValidTime = {16u, 16u},
.lookupTable =
{
- // 0 Read LUTs 0 -> 0
- FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0xEB, RADDR_SDR, FLEXSPI_4PAD, 0x18),
- FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_4PAD, 0x06, READ_SDR, FLEXSPI_4PAD, 0x04),
- FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
- FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
+ /* 0 Read Data */
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READDATA] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xA0, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READDATA + 1] = FLEXSPI_LUT_SEQ(
+ kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_READ_DDR, kFLEXSPI_8PAD, 0x04),
- // 1 Read status register -> 1
- FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x05, READ_SDR, FLEXSPI_1PAD, 0x01),
- FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
- FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
- FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
+ /* 1 Write Data */
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEDATA] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEDATA + 1] = FLEXSPI_LUT_SEQ(
+ kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_WRITE_DDR, kFLEXSPI_8PAD, 0x02),
- // 2 Fast read quad mode - SDR
- FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x6B, RADDR_SDR, FLEXSPI_1PAD, 0x18),
- FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_4PAD, 0x08, READ_SDR, FLEXSPI_4PAD, 0x04),
- FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
- FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
+ /* 2 Read Status */
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 1] = FLEXSPI_LUT_SEQ(
+ kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), // ADDR 0x555
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 2] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 3] = FLEXSPI_LUT_SEQ(
+ kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x70), // DATA 0x70
+ // +1
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 4] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xA0, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 5] = FLEXSPI_LUT_SEQ(
+ kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_DUMMY_RWDS_DDR, kFLEXSPI_8PAD, 0x0B),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 6] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_READ_DDR, kFLEXSPI_8PAD, 0x04, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x0),
- // 3 Write Enable -> 3
- FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x06, STOP, FLEXSPI_1PAD, 0),
- FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
- FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
- FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
+ /* 4 Write Enable */
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 1] = FLEXSPI_LUT_SEQ(
+ kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), // ADDR 0x555
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 2] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 3] = FLEXSPI_LUT_SEQ(
+ kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), // DATA 0xAA
+ // +1
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 4] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 5] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 6] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x02),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 7] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55),
- // 4 Read extend parameters
- FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x81, READ_SDR, FLEXSPI_1PAD, 0x04),
- FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
- FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
- FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
+ /* 6 Erase Sector */
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 1] = FLEXSPI_LUT_SEQ(
+ kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), // ADDR 0x555
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 2] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 3] = FLEXSPI_LUT_SEQ(
+ kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x80), // DATA 0x80
+ // +1
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 4] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 5] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 6] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 7] = FLEXSPI_LUT_SEQ(
+ kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), // ADDR 0x555
+ // +2
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 8] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 9] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 10] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x02),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 11] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55),
+ // +3
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 12] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 13] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 14] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x30, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x00),
- // 5 Erase Sector -> 5
- FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x20, RADDR_SDR, FLEXSPI_1PAD, 24),
- FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
- FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
- FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
+ /* 10 program page with word program command sequence */
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 1] = FLEXSPI_LUT_SEQ(
+ kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), // ADDR 0x555
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 2] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 3] = FLEXSPI_LUT_SEQ(
+ kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xA0), // DATA 0xA0
+ // +1
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 4] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 5] = FLEXSPI_LUT_SEQ(
+ kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_WRITE_DDR, kFLEXSPI_8PAD, 0x80),
- // 6 Write Status Reg
- FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x01, WRITE_SDR, FLEXSPI_1PAD, 0x04),
- FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
- FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
- FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
- // 7 Page Program - quad mode (-> 9)
- FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x32, RADDR_SDR, FLEXSPI_1PAD, 0x18),
- FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_4PAD, 0x04, STOP, FLEXSPI_1PAD, 0),
- FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
- FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
- // 8 Read ID
- FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x90, DUMMY_SDR, FLEXSPI_1PAD, 24),
- FLEXSPI_LUT_SEQ(READ_SDR, FLEXSPI_1PAD, 0x00, 0, 0, 0),
- FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
- FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
- // 9 Page Program - single mode -> 9
- FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x02, RADDR_SDR, FLEXSPI_1PAD, 24),
- FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_1PAD, 0, 0, 0, 0),
- FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
- FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
- // 10 Enter QPI mode
- FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x35, STOP, FLEXSPI_1PAD, 0),
- FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
- FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
- FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
- // 11 Erase Chip
- FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x60, STOP, FLEXSPI_1PAD, 0),
- FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
- FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
- FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
- // 12 Exit QPI mode
- FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_4PAD, 0xF5, STOP, FLEXSPI_1PAD, 0),
- FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
- FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
- FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
+ /* 12 Erase chip */
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 1] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 2] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 3] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x80),
+ // +1
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 4] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 5] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 6] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 7] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),
+ // +2
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 8] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 9] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 10] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x02),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 11] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55),
+ // +3
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 12] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 13] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 14] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
+ [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 15] =
+ FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x10),
},
},
- .pageSize = 256u,
- .sectorSize = 4u * 1024u,
+ .pageSize = 512u,
+ .sectorSize = 256u * 1024u,
.blockSize = 256u * 1024u,
- .isUniformBlockSize = false,
+ .isUniformBlockSize = true,
};
+
#endif /* XIP_BOOT_HEADER_ENABLE */
diff --git a/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.h
index e300efef3..59f28b0e2 100644
--- a/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.h
+++ b/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.h
@@ -6,6 +6,7 @@
#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_low(pin))
#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_high(pin))
#define BOARD_FLASH_CONFIG_HEADER_H "evkmimxrt1064_flexspi_nor_config.h"
+#define BOARD_FLASH_OPS_HEADER_H "hal/flexspi_hyper_flash.h"
#define MICROPY_HW_NUM_PIN_IRQS (4 * 32 + 3)
@@ -39,3 +40,15 @@
#define DMA_REQ_SRC_TX { 0, kDmaRequestMuxLPSPI1Tx, kDmaRequestMuxLPSPI2Tx, \
kDmaRequestMuxLPSPI3Tx, kDmaRequestMuxLPSPI4Tx }
+
+// Define the mapping hardware I2C # to logical I2C #
+// SDA/SCL HW-I2C Logical I2C
+// D14/D15 LPI2C1 -> 0
+// D1/D0 LPI2C3 -> 1
+
+#define MICROPY_HW_I2C_INDEX { 1, 3 }
+
+#define IOMUX_TABLE_I2C \
+ { IOMUXC_GPIO_AD_B1_00_LPI2C1_SCL }, { IOMUXC_GPIO_AD_B1_01_LPI2C1_SDA }, \
+ { 0 }, { 0 }, \
+ { IOMUXC_GPIO_AD_B1_07_LPI2C3_SCL }, { IOMUXC_GPIO_AD_B1_06_LPI2C3_SDA },
diff --git a/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.mk b/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.mk
index bd4c49641..444fe9967 100644
--- a/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.mk
+++ b/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.mk
@@ -3,6 +3,9 @@ MCU_VARIANT = MIMXRT1064DVL6A
MICROPY_FLOAT_IMPL = double
+SRC_C += \
+ hal/flexspi_hyper_flash.c \
+
JLINK_PATH ?= /media/RT1064-EVK/
CFLAGS += -DBOARD_FLASH_SIZE=0x400000
diff --git a/ports/mimxrt/boards/TEENSY40/mpconfigboard.h b/ports/mimxrt/boards/TEENSY40/mpconfigboard.h
index 8b38d047f..aacee4623 100644
--- a/ports/mimxrt/boards/TEENSY40/mpconfigboard.h
+++ b/ports/mimxrt/boards/TEENSY40/mpconfigboard.h
@@ -8,6 +8,7 @@
#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin))
#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin))
#define BOARD_FLASH_CONFIG_HEADER_H "teensy40_flexspi_nor_config.h"
+#define BOARD_FLASH_OPS_HEADER_H "hal/flexspi_nor_flash.h"
#define MICROPY_HW_NUM_PIN_IRQS (4 * 32 + 3)
@@ -42,3 +43,17 @@
#define DMA_REQ_SRC_TX { 0, kDmaRequestMuxLPSPI1Tx, kDmaRequestMuxLPSPI2Tx, \
kDmaRequestMuxLPSPI3Tx, kDmaRequestMuxLPSPI4Tx }
+
+// Define mapping hardware I2C # to logical I2C #
+// SDA/SCL HW-I2C Logical I2C
+// 17/16 LPI2C3 -> 0
+// 18/19 LPI2C1 -> 1
+// 25/24 LPI2C4 -> 2
+
+#define MICROPY_HW_I2C_INDEX { 1, 3, 4 }
+
+#define IOMUX_TABLE_I2C \
+ { IOMUXC_GPIO_AD_B1_00_LPI2C1_SCL }, { IOMUXC_GPIO_AD_B1_01_LPI2C1_SDA }, \
+ { 0 }, { 0 }, \
+ { IOMUXC_GPIO_AD_B1_07_LPI2C3_SCL }, { IOMUXC_GPIO_AD_B1_06_LPI2C3_SDA }, \
+ { IOMUXC_GPIO_AD_B0_12_LPI2C4_SCL }, { IOMUXC_GPIO_AD_B0_13_LPI2C4_SDA },
diff --git a/ports/mimxrt/boards/TEENSY40/mpconfigboard.mk b/ports/mimxrt/boards/TEENSY40/mpconfigboard.mk
index beab16c08..a15dd7812 100644
--- a/ports/mimxrt/boards/TEENSY40/mpconfigboard.mk
+++ b/ports/mimxrt/boards/TEENSY40/mpconfigboard.mk
@@ -3,5 +3,8 @@ MCU_VARIANT = MIMXRT1062DVJ6A
MICROPY_FLOAT_IMPL = double
+SRC_C += \
+ hal/flexspi_nor_flash.c \
+
deploy: $(BUILD)/firmware.hex
teensy_loader_cli --mcu=imxrt1062 -v -w $<
diff --git a/ports/mimxrt/boards/TEENSY41/mpconfigboard.h b/ports/mimxrt/boards/TEENSY41/mpconfigboard.h
index 455bf8d69..a72bd127b 100644
--- a/ports/mimxrt/boards/TEENSY41/mpconfigboard.h
+++ b/ports/mimxrt/boards/TEENSY41/mpconfigboard.h
@@ -8,6 +8,7 @@
#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin))
#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin))
#define BOARD_FLASH_CONFIG_HEADER_H "teensy41_flexspi_nor_config.h"
+#define BOARD_FLASH_OPS_HEADER_H "hal/flexspi_nor_flash.h"
#define MICROPY_HW_NUM_PIN_IRQS (4 * 32 + 3)
@@ -42,3 +43,17 @@
#define DMA_REQ_SRC_TX { 0, kDmaRequestMuxLPSPI1Tx, kDmaRequestMuxLPSPI2Tx, \
kDmaRequestMuxLPSPI3Tx, kDmaRequestMuxLPSPI4Tx }
+
+// Define mapping hardware I2C # to logical I2C #
+// SDA/SCL HW-I2C Logical I2C
+// 17/16 LPI2C3 -> 0
+// 18/19 LPI2C1 -> 1
+// 25/24 LPI2C4 -> 2
+
+#define MICROPY_HW_I2C_INDEX { 1, 3, 4 }
+
+#define IOMUX_TABLE_I2C \
+ { IOMUXC_GPIO_AD_B1_00_LPI2C1_SCL }, { IOMUXC_GPIO_AD_B1_01_LPI2C1_SDA }, \
+ { 0 }, { 0 }, \
+ { IOMUXC_GPIO_AD_B1_07_LPI2C3_SCL }, { IOMUXC_GPIO_AD_B1_06_LPI2C3_SDA }, \
+ { IOMUXC_GPIO_AD_B0_12_LPI2C4_SCL }, { IOMUXC_GPIO_AD_B0_13_LPI2C4_SDA },
diff --git a/ports/mimxrt/boards/TEENSY41/mpconfigboard.mk b/ports/mimxrt/boards/TEENSY41/mpconfigboard.mk
index beab16c08..a15dd7812 100755
--- a/ports/mimxrt/boards/TEENSY41/mpconfigboard.mk
+++ b/ports/mimxrt/boards/TEENSY41/mpconfigboard.mk
@@ -3,5 +3,8 @@ MCU_VARIANT = MIMXRT1062DVJ6A
MICROPY_FLOAT_IMPL = double
+SRC_C += \
+ hal/flexspi_nor_flash.c \
+
deploy: $(BUILD)/firmware.hex
teensy_loader_cli --mcu=imxrt1062 -v -w $<
diff --git a/ports/mimxrt/boards/common.ld b/ports/mimxrt/boards/common.ld
index e5d91f119..6f45da24d 100644
--- a/ports/mimxrt/boards/common.ld
+++ b/ports/mimxrt/boards/common.ld
@@ -178,12 +178,14 @@ SECTIONS
. = ALIGN(4);
__DATA_RAM = .;
__data_start__ = .; /* create a global symbol at data start */
+ __data_section_table = .;
*(m_usb_dma_init_data)
*(.data) /* .data sections */
*(.data*) /* .data* sections */
KEEP(*(.jcr*))
. = ALIGN(4);
__data_end__ = .; /* define a global symbol at data end */
+ __data_section_table_end = .;
} > m_dtcm
__RAM_FUNCTIONS_ROM = __DATA_ROM + (__data_end__ - __data_start__);
@@ -224,12 +226,14 @@ SECTIONS
. = ALIGN(4);
__START_BSS = .;
__bss_start__ = .;
+ __bss_section_table = .;
*(m_usb_dma_noninit_data)
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
__bss_end__ = .;
+ __bss_section_table_end = .;
__END_BSS = .;
} > m_dtcm
@@ -253,6 +257,7 @@ SECTIONS
/* Initializes stack on the end of block */
__StackTop = ORIGIN(m_dtcm) + LENGTH(m_dtcm);
__StackLimit = __StackTop - STACK_SIZE;
+ _vStackTop = __StackTop;
PROVIDE(__stack = __StackTop);
.ARM.attributes 0 : { *(.ARM.attributes) }
diff --git a/ports/mimxrt/hal/flexspi_hyper_flash.c b/ports/mimxrt/hal/flexspi_hyper_flash.c
new file mode 100644
index 000000000..fb71d4d94
--- /dev/null
+++ b/ports/mimxrt/hal/flexspi_hyper_flash.c
@@ -0,0 +1,247 @@
+/*
+ * Copyright (c) 2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2021 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_clock.h"
+#include "flexspi_hyper_flash.h"
+
+// Copy of a few (pseudo-)functions from fsl_clock.h, which were nor reliably
+// inlined when they should be. That caused DEBUG mode to fail.
+// It does not increase the code size, since they were supposed to be inline.
+
+__attribute__((always_inline)) static inline void clock_set_div(clock_div_t divider, uint32_t value) {
+ uint32_t busyShift;
+
+ busyShift = CCM_TUPLE_BUSY_SHIFT(divider);
+ CCM_TUPLE_REG(CCM, divider) = (CCM_TUPLE_REG(CCM, divider) & (~CCM_TUPLE_MASK(divider))) |
+ (((uint32_t)((value) << CCM_TUPLE_SHIFT(divider))) & CCM_TUPLE_MASK(divider));
+
+ /* Clock switch need Handshake? */
+ if (CCM_NO_BUSY_WAIT != busyShift) {
+ /* Wait until CCM internal handshake finish. */
+ while (CCM->CDHIPR & (1U << busyShift)) {}
+ }
+}
+
+__attribute__((always_inline)) static inline void clock_control_gate(clock_ip_name_t name, clock_gate_value_t value) {
+ uint32_t index = ((uint32_t)name) >> 8U;
+ uint32_t shift = ((uint32_t)name) & 0x1FU;
+ volatile uint32_t *reg;
+
+ reg = ((volatile uint32_t *)&CCM->CCGR0) + index;
+ *reg = ((*reg) & ~(3U << shift)) | (((uint32_t)value) << shift);
+}
+
+__attribute__((always_inline)) static inline void clock_enable_clock(clock_ip_name_t name) {
+ clock_control_gate(name, kCLOCK_ClockNeededRunWait);
+}
+
+__attribute__((always_inline)) static inline void clock_disable_clock(clock_ip_name_t name) {
+ clock_control_gate(name, kCLOCK_ClockNotNeeded);
+}
+
+#define DIV_PAGE_PGM 4
+#define DIV_ERASE_PGM 4
+#define DIV_READ 0
+
+static void SetFlexSPIDiv(uint32_t div) __attribute__((section(".ram_functions")));
+static void SetFlexSPIDiv(uint32_t div) {
+ FLEXSPI_Enable(FLEXSPI, false);
+ clock_disable_clock(kCLOCK_FlexSpi);
+ clock_set_div(kCLOCK_FlexspiDiv, div); /* flexspi clock 332M, DDR mode, internal clock 166M. */
+ clock_enable_clock(kCLOCK_FlexSpi);
+ FLEXSPI_Enable(FLEXSPI, true);
+}
+
+status_t flexspi_nor_hyperbus_read(FLEXSPI_Type *base, uint32_t addr, uint32_t *buffer, uint32_t bytes) __attribute__((section(".ram_functions")));
+status_t flexspi_nor_hyperbus_read(FLEXSPI_Type *base, uint32_t addr, uint32_t *buffer, uint32_t bytes) {
+ flexspi_transfer_t flashXfer;
+ status_t status;
+
+ flashXfer.deviceAddress = addr * 2;
+ flashXfer.port = kFLEXSPI_PortA1;
+ flashXfer.cmdType = kFLEXSPI_Read;
+ flashXfer.SeqNumber = 1;
+ flashXfer.seqIndex = HYPERFLASH_CMD_LUT_SEQ_IDX_READDATA;
+ flashXfer.data = buffer;
+ flashXfer.dataSize = bytes;
+ status = FLEXSPI_TransferBlocking(base, &flashXfer);
+
+ return status;
+}
+
+status_t flexspi_nor_hyperbus_write(FLEXSPI_Type *base, uint32_t addr, uint32_t *buffer, uint32_t bytes) __attribute__((section(".ram_functions")));
+status_t flexspi_nor_hyperbus_write(FLEXSPI_Type *base, uint32_t addr, uint32_t *buffer, uint32_t bytes) {
+ flexspi_transfer_t flashXfer;
+ status_t status;
+
+ flashXfer.deviceAddress = addr * 2;
+ flashXfer.port = kFLEXSPI_PortA1;
+ flashXfer.cmdType = kFLEXSPI_Write;
+ flashXfer.SeqNumber = 1;
+ flashXfer.seqIndex = HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEDATA;
+ flashXfer.data = buffer;
+ flashXfer.dataSize = bytes;
+ status = FLEXSPI_TransferBlocking(base, &flashXfer);
+
+ return status;
+}
+
+status_t flexspi_nor_write_enable(FLEXSPI_Type *base, uint32_t baseAddr) __attribute__((section(".ram_functions")));
+status_t flexspi_nor_write_enable(FLEXSPI_Type *base, uint32_t baseAddr) {
+ flexspi_transfer_t flashXfer;
+ status_t status;
+
+ /* Write enable */
+ flashXfer.deviceAddress = baseAddr;
+ flashXfer.port = kFLEXSPI_PortA1;
+ flashXfer.cmdType = kFLEXSPI_Command;
+ flashXfer.SeqNumber = 2;
+ flashXfer.seqIndex = HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE;
+
+ status = FLEXSPI_TransferBlocking(base, &flashXfer);
+
+ return status;
+}
+
+status_t flexspi_nor_wait_bus_busy(FLEXSPI_Type *base) __attribute__((section(".ram_functions")));
+status_t flexspi_nor_wait_bus_busy(FLEXSPI_Type *base) {
+ /* Wait status ready. */
+ bool isBusy;
+ uint32_t readValue;
+ status_t status;
+ flexspi_transfer_t flashXfer;
+
+ flashXfer.deviceAddress = 0;
+ flashXfer.port = kFLEXSPI_PortA1;
+ flashXfer.cmdType = kFLEXSPI_Read;
+ flashXfer.SeqNumber = 2;
+ flashXfer.seqIndex = HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS;
+ flashXfer.data = &readValue;
+ flashXfer.dataSize = 2;
+
+ do {
+ status = FLEXSPI_TransferBlocking(base, &flashXfer);
+
+ if (status != kStatus_Success) {
+ return status;
+ }
+ if (readValue & 0x8000) {
+ isBusy = false;
+ } else {
+ isBusy = true;
+ }
+
+ if (readValue & 0x3200) {
+ status = kStatus_Fail;
+ break;
+ }
+
+ } while (isBusy);
+
+ return status;
+}
+
+status_t flexspi_nor_flash_erase_sector(FLEXSPI_Type *base, uint32_t address) __attribute__((section(".ram_functions")));
+status_t flexspi_nor_flash_erase_sector(FLEXSPI_Type *base, uint32_t address) {
+ status_t status;
+ flexspi_transfer_t flashXfer;
+
+ /* Write enable */
+ status = flexspi_nor_write_enable(base, address);
+
+ if (status != kStatus_Success) {
+ return status;
+ }
+
+ flashXfer.deviceAddress = address;
+ flashXfer.port = kFLEXSPI_PortA1;
+ flashXfer.cmdType = kFLEXSPI_Command;
+ flashXfer.SeqNumber = 4;
+ flashXfer.seqIndex = HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR;
+ status = FLEXSPI_TransferBlocking(base, &flashXfer);
+
+ if (status != kStatus_Success) {
+ return status;
+ }
+
+ status = flexspi_nor_wait_bus_busy(base);
+
+ return status;
+}
+
+status_t flexspi_nor_flash_page_program(FLEXSPI_Type *base, uint32_t address, const uint32_t *src, uint32_t size ) __attribute__((section(".ram_functions")));
+status_t flexspi_nor_flash_page_program(FLEXSPI_Type *base, uint32_t address, const uint32_t *src, uint32_t size) {
+ status_t status;
+ flexspi_transfer_t flashXfer;
+
+ /* Speed down flexspi clock */
+ SetFlexSPIDiv(DIV_PAGE_PGM);
+
+ /* Write enable */
+ status = flexspi_nor_write_enable(base, address);
+
+ if (status != kStatus_Success) {
+ return status;
+ }
+
+ /* Prepare page program command */
+ flashXfer.deviceAddress = address;
+ flashXfer.port = kFLEXSPI_PortA1;
+ flashXfer.cmdType = kFLEXSPI_Write;
+ flashXfer.SeqNumber = 2;
+ flashXfer.seqIndex = HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM;
+ flashXfer.data = (uint32_t *)src;
+ flashXfer.dataSize = size;
+ status = FLEXSPI_TransferBlocking(base, &flashXfer);
+
+ if (status != kStatus_Success) {
+ return status;
+ }
+
+ status = flexspi_nor_wait_bus_busy(base);
+
+ SetFlexSPIDiv(DIV_READ);
+
+ return status;
+}
+
+status_t flexspi_nor_hyperflash_cfi(FLEXSPI_Type *base) __attribute__((section(".ram_functions")));
+status_t flexspi_nor_hyperflash_cfi(FLEXSPI_Type *base) {
+ /*
+ * Read ID-CFI Parameters
+ */
+ // CFI Entry
+ status_t status;
+ uint32_t buffer[2];
+ uint8_t data[4] = {0x00, 0x98};
+ status = flexspi_nor_hyperbus_write(base, 0x555, (uint32_t *)data, 2);
+ if (status != kStatus_Success) {
+ return status;
+ }
+
+ // ID-CFI Read
+ // Read Query Unique ASCII String
+ status = flexspi_nor_hyperbus_read(base, 0x10, &buffer[0], sizeof(buffer));
+ if (status != kStatus_Success) {
+ return status;
+ }
+ buffer[1] &= 0xFFFF;
+ // Check that the data read out is unicode "QRY" in big-endian order
+ if ((buffer[0] != 0x52005100) || (buffer[1] != 0x5900)) {
+ status = kStatus_Fail;
+ return status;
+ }
+ // ASO Exit 0xF000
+ data[1] = 0xF0;
+ status = flexspi_nor_hyperbus_write(base, 0x0, (uint32_t *)data, 2);
+ if (status != kStatus_Success) {
+ return status;
+ }
+
+ return status;
+}
diff --git a/ports/mimxrt/hal/flexspi_hyper_flash.h b/ports/mimxrt/hal/flexspi_hyper_flash.h
new file mode 100644
index 000000000..bba76c132
--- /dev/null
+++ b/ports/mimxrt/hal/flexspi_hyper_flash.h
@@ -0,0 +1,71 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2013, 2014 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef MICROPY_INCLUDED_MIMXRT_HAL_FLEXSPI_HYPER_FLASH_H
+#define MICROPY_INCLUDED_MIMXRT_HAL_FLEXSPI_HYPER_FLASH_H
+
+#include "mpconfigboard.h"
+#include "fsl_flexspi.h"
+#include BOARD_FLASH_CONFIG_HEADER_H
+
+// Defined in boards flash_config.c
+extern flexspi_nor_config_t qspiflash_config;
+
+status_t flexspi_nor_hyperflash_cfi(FLEXSPI_Type *base);
+void flexspi_hyper_flash_init(void);
+void flexspi_nor_update_lut(void);
+status_t flexspi_nor_flash_erase_sector(FLEXSPI_Type *base, uint32_t address);
+status_t flexspi_nor_flash_page_program(FLEXSPI_Type *base, uint32_t address, const uint32_t *src, uint32_t size);
+
+static inline uint32_t flexspi_get_frequency(void) {
+ uint32_t div;
+ uint32_t fre;
+
+ /* Clock divider:
+ 000 divided by 1
+ 001 divided by 2
+ 010 divided by 3
+ 011 divided by 4
+ 100 divided by 5
+ 101 divided by 6
+ 110 divided by 7
+ 111 divided by 8
+ */
+ div = CLOCK_GetDiv(kCLOCK_FlexspiDiv);
+ /* Get frequency */
+ fre = CLOCK_GetFreq(kCLOCK_Usb1PllPfd0Clk) / (div + 0x01U);
+
+ return fre;
+}
+
+#define HYPERFLASH_CMD_LUT_SEQ_IDX_READDATA 0
+#define HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEDATA 1
+#define HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS 2
+#define HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE 4
+#define HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR 6
+#define HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM 10
+#define HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP 12
+
+#endif // MICROPY_INCLUDED_MIMXRT_HAL_FLEXSPI_HYPER_FLASH_H
diff --git a/ports/mimxrt/hal/flexspi_nor_flash.h b/ports/mimxrt/hal/flexspi_nor_flash.h
index a9a9bbe70..c34df7416 100644
--- a/ports/mimxrt/hal/flexspi_nor_flash.h
+++ b/ports/mimxrt/hal/flexspi_nor_flash.h
@@ -39,4 +39,25 @@ void flexspi_nor_update_lut(void);
status_t flexspi_nor_flash_erase_sector(FLEXSPI_Type *base, uint32_t address);
status_t flexspi_nor_flash_page_program(FLEXSPI_Type *base, uint32_t address, const uint32_t *src, uint32_t size);
+static inline uint32_t flexspi_get_frequency(void) {
+ uint32_t div;
+ uint32_t fre;
+
+ /* Clock divider:
+ 000 divided by 1
+ 001 divided by 2
+ 010 divided by 3
+ 011 divided by 4
+ 100 divided by 5
+ 101 divided by 6
+ 110 divided by 7
+ 111 divided by 8
+ */
+ div = CLOCK_GetDiv(kCLOCK_FlexspiDiv);
+ /* Get frequency */
+ fre = CLOCK_GetFreq(kCLOCK_Usb1PllPfd0Clk) / (div + 0x01U);
+
+ return fre;
+}
+
#endif // MICROPY_INCLUDED_MIMXRT_HAL_FLEXSPI_NOR_FLASH_H
diff --git a/ports/mimxrt/machine_i2c.c b/ports/mimxrt/machine_i2c.c
new file mode 100644
index 000000000..618d0a258
--- /dev/null
+++ b/ports/mimxrt/machine_i2c.c
@@ -0,0 +1,217 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020-2021 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/runtime.h"
+#include "py/mphal.h"
+#include "py/mperrno.h"
+#include "extmod/machine_i2c.h"
+#include "modmachine.h"
+
+#include "fsl_iomuxc.h"
+#include "fsl_lpi2c.h"
+
+#define DEFAULT_I2C_FREQ (400000)
+#define DEFAULT_I2C_DRIVE (6)
+
+// Select USB1 PLL (480 MHz) as master lpi2c clock source
+#define LPI2C_CLOCK_SOURCE_SELECT (0U)
+// Clock divider for master lpi2c clock source
+#define LPI2C_CLOCK_SOURCE_DIVIDER (1U)
+// Get frequency of lpi2c clock = 30 MHz
+#define LPI2C_CLOCK_FREQUENCY ((CLOCK_GetFreq(kCLOCK_Usb1PllClk) / 8) / (LPI2C_CLOCK_SOURCE_DIVIDER + 1U))
+
+typedef struct _machine_i2c_obj_t {
+ mp_obj_base_t base;
+ LPI2C_Type *i2c_inst;
+ uint8_t i2c_id;
+ uint8_t i2c_hw_id;
+ bool transfer_busy;
+ status_t transfer_status;
+ lpi2c_master_config_t *master_config;
+} machine_i2c_obj_t;
+
+typedef struct _iomux_table_t {
+ uint32_t muxRegister;
+ uint32_t muxMode;
+ uint32_t inputRegister;
+ uint32_t inputDaisy;
+ uint32_t configRegister;
+} iomux_table_t;
+
+STATIC const uint8_t i2c_index_table[] = MICROPY_HW_I2C_INDEX;
+STATIC LPI2C_Type *i2c_base_ptr_table[] = LPI2C_BASE_PTRS;
+static const iomux_table_t iomux_table[] = { IOMUX_TABLE_I2C };
+
+#define MICROPY_HW_I2C_NUM ARRAY_SIZE(i2c_index_table)
+
+#define SCL (iomux_table[index])
+#define SDA (iomux_table[index + 1])
+
+bool lpi2c_set_iomux(int8_t hw_i2c, uint8_t drive) {
+ int index = (hw_i2c - 1) * 2;
+
+ if (SCL.muxRegister != 0) {
+ IOMUXC_SetPinMux(SCL.muxRegister, SCL.muxMode, SCL.inputRegister, SCL.inputDaisy, SCL.configRegister, 1U);
+ IOMUXC_SetPinConfig(SCL.muxRegister, SCL.muxMode, SCL.inputRegister, SCL.inputDaisy, SCL.configRegister,
+ 0xF880u | drive << IOMUXC_SW_PAD_CTL_PAD_DSE_SHIFT);
+
+ IOMUXC_SetPinMux(SDA.muxRegister, SDA.muxMode, SDA.inputRegister, SDA.inputDaisy, SDA.configRegister, 1U);
+ IOMUXC_SetPinConfig(SDA.muxRegister, SDA.muxMode, SDA.inputRegister, SDA.inputDaisy, SDA.configRegister,
+ 0xF880u | drive << IOMUXC_SW_PAD_CTL_PAD_DSE_SHIFT);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+STATIC void machine_i2c_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
+ machine_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_printf(print, "I2C(%u, freq=%u)",
+ self->i2c_id, self->master_config->baudRate_Hz);
+}
+
+mp_obj_t machine_i2c_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ enum { ARG_id, ARG_freq, ARG_drive};
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_id, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_freq, MP_ARG_INT, {.u_int = DEFAULT_I2C_FREQ} },
+ { MP_QSTR_drive, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = DEFAULT_I2C_DRIVE} },
+ };
+
+ static bool clk_init = true;
+
+ // Parse args.
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ // Get I2C bus.
+ int i2c_id = mp_obj_get_int(args[ARG_id].u_obj);
+ if (i2c_id < 0 || i2c_id >= MICROPY_HW_I2C_NUM) {
+ mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("I2C(%d) doesn't exist"), i2c_id);
+ }
+
+ // Get I2C Object.
+ machine_i2c_obj_t *self = m_new_obj(machine_i2c_obj_t);
+ self->base.type = &machine_i2c_type;
+ self->i2c_id = i2c_id;
+ self->i2c_hw_id = i2c_index_table[i2c_id]; // the hw i2c number 1..n
+ self->i2c_inst = i2c_base_ptr_table[self->i2c_hw_id];
+
+ uint8_t drive = args[ARG_drive].u_int;
+ if (drive < 1 || drive > 7) {
+ drive = DEFAULT_I2C_DRIVE;
+ }
+
+ if (clk_init) {
+ clk_init = false;
+ // Set clock source for LPI2C
+ CLOCK_SetMux(kCLOCK_Lpi2cMux, LPI2C_CLOCK_SOURCE_SELECT); // USB1 PLL (480 MHz)
+ CLOCK_SetDiv(kCLOCK_Lpi2cDiv, LPI2C_CLOCK_SOURCE_DIVIDER);
+ }
+
+ // Initialise the I2C peripheral if any arguments given, or it was not initialised previously.
+ lpi2c_set_iomux(self->i2c_hw_id, drive);
+ self->master_config = m_new_obj(lpi2c_master_config_t);
+ LPI2C_MasterGetDefaultConfig(self->master_config);
+ // Initialise the I2C peripheral.
+ self->master_config->baudRate_Hz = args[ARG_freq].u_int;
+ LPI2C_MasterInit(self->i2c_inst, self->master_config, LPI2C_CLOCK_FREQUENCY);
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+static void lpi2c_master_callback(LPI2C_Type *base, lpi2c_master_handle_t *handle, status_t status, void *self_in) {
+ machine_i2c_obj_t *self = (machine_i2c_obj_t *)self_in;
+
+ self->transfer_busy = false;
+ self->transfer_status = status;
+}
+
+STATIC int machine_i2c_transfer_single(mp_obj_base_t *self_in, uint16_t addr, size_t len, uint8_t *buf, unsigned int flags) {
+ machine_i2c_obj_t *self = (machine_i2c_obj_t *)self_in;
+ status_t ret;
+ lpi2c_master_handle_t g_master_handle;
+ lpi2c_master_transfer_t masterXfer = {0};
+ LPI2C_MasterTransferCreateHandle(self->i2c_inst, &g_master_handle, lpi2c_master_callback, self);
+
+ if (flags & MP_MACHINE_I2C_FLAG_READ) {
+ masterXfer.direction = kLPI2C_Read;
+ } else {
+ masterXfer.direction = kLPI2C_Write;
+ }
+ if (addr < 0x80) { // 7 or 10 bit address?
+ masterXfer.slaveAddress = addr;
+ } else {
+ masterXfer.slaveAddress = 0x78 | ((addr >> 8) & 0x03);
+ masterXfer.subaddress = addr & 0xff;
+ masterXfer.subaddressSize = 1;
+ }
+ masterXfer.data = buf;
+ masterXfer.dataSize = len;
+ if (flags & MP_MACHINE_I2C_FLAG_STOP) {
+ masterXfer.flags = kLPI2C_TransferDefaultFlag;
+ } else {
+ masterXfer.flags = kLPI2C_TransferNoStopFlag;
+ }
+ self->transfer_busy = true;
+
+ // Send master data to slave in non-blocking mode
+ ret = LPI2C_MasterTransferNonBlocking(self->i2c_inst, &g_master_handle, &masterXfer);
+ if (ret != kStatus_Success) {
+ return -MP_EIO;
+ }
+ // Wait for the transfer to complete
+ while (self->transfer_busy) {
+ MICROPY_EVENT_POLL_HOOK
+ }
+
+ // Transfer will not send a stop in case of errors like NAK. So it's done here.
+ if (flags & MP_MACHINE_I2C_FLAG_STOP && self->transfer_status != kStatus_Success) {
+ LPI2C_MasterStop(self->i2c_inst);
+ }
+
+ if (self->transfer_status == kStatus_Success) {
+ return len;
+ } else if (self->transfer_status == kStatus_LPI2C_Nak) {
+ return -MP_ENODEV;
+ } else {
+ return -MP_EIO;
+ }
+}
+
+STATIC const mp_machine_i2c_p_t machine_i2c_p = {
+ .transfer = mp_machine_i2c_transfer_adaptor,
+ .transfer_single = machine_i2c_transfer_single,
+};
+
+const mp_obj_type_t machine_i2c_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_I2C,
+ .print = machine_i2c_print,
+ .make_new = machine_i2c_make_new,
+ .protocol = &machine_i2c_p,
+ .locals_dict = (mp_obj_dict_t *)&mp_machine_i2c_locals_dict,
+};
diff --git a/ports/mimxrt/machine_led.c b/ports/mimxrt/machine_led.c
index 07c7b180a..4082eb34b 100644
--- a/ports/mimxrt/machine_led.c
+++ b/ports/mimxrt/machine_led.c
@@ -44,7 +44,7 @@ STATIC mp_obj_t led_obj_make_new(const mp_obj_type_t *type, size_t n_args, size_
// Check led id is in range
if (!(1 <= led_id && led_id <= NUM_LEDS)) {
- nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "LED(%d) doesn't exist", led_id));
+ mp_raise_msg_varg(&mp_type_ValueError, "LED(%d) doesn't exist", led_id);
}
// Return reference to static object
diff --git a/ports/mimxrt/machine_pin.c b/ports/mimxrt/machine_pin.c
index dc26cdfc1..12975806d 100644
--- a/ports/mimxrt/machine_pin.c
+++ b/ports/mimxrt/machine_pin.c
@@ -31,7 +31,8 @@
#include "py/runtime.h"
#include "py/mphal.h"
-#include "lib/utils/mpirq.h"
+#include "shared/runtime/mpirq.h"
+#include "extmod/virtpin.h"
#include "pin.h"
// Local functions
@@ -425,12 +426,34 @@ STATIC const mp_rom_map_elem_t machine_pin_locals_dict_table[] = {
};
STATIC MP_DEFINE_CONST_DICT(machine_pin_locals_dict, machine_pin_locals_dict_table);
+
+STATIC mp_uint_t machine_pin_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) {
+ (void)errcode;
+ machine_pin_obj_t *self = self_in;
+
+ switch (request) {
+ case MP_PIN_READ: {
+ return mp_hal_pin_read(self);
+ }
+ case MP_PIN_WRITE: {
+ mp_hal_pin_write(self, arg);
+ return 0;
+ }
+ }
+ return -1;
+}
+
+STATIC const mp_pin_p_t machine_pin_obj_protocol = {
+ .ioctl = machine_pin_ioctl,
+};
+
const mp_obj_type_t machine_pin_type = {
{&mp_type_type},
.name = MP_QSTR_Pin,
.print = machine_pin_obj_print,
.call = machine_pin_obj_call,
.make_new = mp_pin_make_new,
+ .protocol = &machine_pin_obj_protocol,
.locals_dict = (mp_obj_dict_t *)&machine_pin_locals_dict,
};
diff --git a/ports/mimxrt/machine_rtc.c b/ports/mimxrt/machine_rtc.c
index d00d139f7..f08e73fa5 100644
--- a/ports/mimxrt/machine_rtc.c
+++ b/ports/mimxrt/machine_rtc.c
@@ -26,7 +26,7 @@
*/
#include "py/runtime.h"
-#include "lib/timeutils/timeutils.h"
+#include "shared/timeutils/timeutils.h"
#include "modmachine.h"
#include "ticks.h"
#include "fsl_snvs_lp.h"
diff --git a/ports/mimxrt/main.c b/ports/mimxrt/main.c
index c93e89c8a..e81974afa 100644
--- a/ports/mimxrt/main.c
+++ b/ports/mimxrt/main.c
@@ -30,9 +30,9 @@
#include "py/gc.h"
#include "py/mperrno.h"
#include "py/stackctrl.h"
-#include "lib/mp-readline/readline.h"
-#include "lib/utils/gchelper.h"
-#include "lib/utils/pyexec.h"
+#include "shared/readline/readline.h"
+#include "shared/runtime/gchelper.h"
+#include "shared/runtime/pyexec.h"
#include "ticks.h"
#include "tusb.h"
#include "led.h"
diff --git a/ports/mimxrt/mimxrt_flash.c b/ports/mimxrt/mimxrt_flash.c
index bf054c87f..79c4e676d 100644
--- a/ports/mimxrt/mimxrt_flash.c
+++ b/ports/mimxrt/mimxrt_flash.c
@@ -30,9 +30,10 @@
#include "py/runtime.h"
#include "extmod/vfs.h"
#include "modmimxrt.h"
-#include "hal/flexspi_nor_flash.h"
+#include BOARD_FLASH_OPS_HEADER_H
// BOARD_FLASH_SIZE is defined in mpconfigport.h
+
#define SECTOR_SIZE_BYTES (qspiflash_config.sectorSize)
#define PAGE_SIZE_BYTES (qspiflash_config.pageSize)
@@ -62,7 +63,7 @@ STATIC mimxrt_flash_obj_t mimxrt_flash_obj = {
};
// flash_erase_block(erase_addr_bytes)
-// erases the 4k sector starting at adddr
+// erases the sector starting at addr. Sector size according to the flash properties.
status_t flash_erase_block(uint32_t erase_addr) __attribute__((section(".ram_functions")));
status_t flash_erase_block(uint32_t erase_addr) {
status_t status;
@@ -77,21 +78,31 @@ status_t flash_erase_block(uint32_t erase_addr) {
// flash_write_block(flash_dest_addr_bytes, data_source, length_bytes)
// writes length_byte data to the destination address
-// length is a multiple of the page size = 256
// the vfs driver takes care for erasing the sector if required
status_t flash_write_block(uint32_t dest_addr, const uint8_t *src, uint32_t length) __attribute__((section(".ram_functions")));
status_t flash_write_block(uint32_t dest_addr, const uint8_t *src, uint32_t length) {
status_t status;
+ uint32_t size;
+ uint32_t next_addr;
+
SCB_CleanInvalidateDCache();
SCB_DisableDCache();
- // write sector in page size chunks
- for (int i = 0; i < length; i += PAGE_SIZE_BYTES) {
+ // write data in chunks not crossing a page boundary
+ while (length > 0) {
+ next_addr = dest_addr - (dest_addr % PAGE_SIZE_BYTES) + PAGE_SIZE_BYTES; // next page boundary
+ size = next_addr - dest_addr; // maximal chunk length
+ if (size > length) { // compare against remaining data size
+ size = length;
+ }
__disable_irq();
- status = flexspi_nor_flash_page_program(FLEXSPI, dest_addr + i, (uint32_t *)(src + i), PAGE_SIZE_BYTES);
+ status = flexspi_nor_flash_page_program(FLEXSPI, dest_addr, (uint32_t *)src, size);
__enable_irq();
if (status != kStatus_Success) {
break;
}
+ length -= size;
+ src += size;
+ dest_addr += size;
}
SCB_EnableDCache();
return status;
@@ -105,7 +116,7 @@ STATIC mp_obj_t mimxrt_flash_make_new(const mp_obj_type_t *type, size_t n_args,
// This should be performed by the boot ROM but for some reason it is not.
FLEXSPI_UpdateLUT(FLEXSPI, 0,
qspiflash_config.memConfig.lookupTable,
- sizeof(qspiflash_config.memConfig.lookupTable) / sizeof(qspiflash_config.memConfig.lookupTable[0]));
+ ARRAY_SIZE(qspiflash_config.memConfig.lookupTable));
// Configure FLEXSPI IP FIFO access.
FLEXSPI->MCR0 &= ~(FLEXSPI_MCR0_ARDFEN_MASK);
diff --git a/ports/mimxrt/modmachine.c b/ports/mimxrt/modmachine.c
index e821f1507..150615ca0 100644
--- a/ports/mimxrt/modmachine.c
+++ b/ports/mimxrt/modmachine.c
@@ -85,6 +85,7 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_Signal), MP_ROM_PTR(&machine_signal_type) },
{ MP_ROM_QSTR(MP_QSTR_SoftI2C), MP_ROM_PTR(&mp_machine_soft_i2c_type) },
{ MP_ROM_QSTR(MP_QSTR_SoftSPI), MP_ROM_PTR(&mp_machine_soft_spi_type) },
+ { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&machine_i2c_type) },
{ MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&machine_spi_type) },
{ MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&machine_uart_type) },
diff --git a/ports/mimxrt/modmachine.h b/ports/mimxrt/modmachine.h
index eba8e6db8..9732093bd 100644
--- a/ports/mimxrt/modmachine.h
+++ b/ports/mimxrt/modmachine.h
@@ -32,6 +32,7 @@
extern const mp_obj_type_t machine_adc_type;
extern const mp_obj_type_t machine_timer_type;
extern const mp_obj_type_t machine_rtc_type;
+extern const mp_obj_type_t machine_i2c_type;
extern const mp_obj_type_t machine_spi_type;
extern const mp_obj_type_t machine_uart_type;
diff --git a/ports/mimxrt/modutime.c b/ports/mimxrt/modutime.c
index 2a88a4224..d3be7c2ea 100644
--- a/ports/mimxrt/modutime.c
+++ b/ports/mimxrt/modutime.c
@@ -26,7 +26,7 @@
*/
#include "py/runtime.h"
-#include "lib/timeutils/timeutils.h"
+#include "shared/timeutils/timeutils.h"
#include "extmod/utime_mphal.h"
#include "fsl_snvs_lp.h"
diff --git a/ports/mimxrt/mpconfigport.h b/ports/mimxrt/mpconfigport.h
index e1e102797..1066b93e1 100644
--- a/ports/mimxrt/mpconfigport.h
+++ b/ports/mimxrt/mpconfigport.h
@@ -145,6 +145,7 @@ __attribute__((always_inline)) static inline void enable_irq(uint32_t state) {
__attribute__((always_inline)) static inline uint32_t disable_irq(void) {
uint32_t state = __get_PRIMASK();
+ __disable_irq();
return state;
}
diff --git a/ports/mimxrt/mphalport.c b/ports/mimxrt/mphalport.c
index 942deae5b..ff7e988df 100644
--- a/ports/mimxrt/mphalport.c
+++ b/ports/mimxrt/mphalport.c
@@ -28,7 +28,7 @@
#include "py/runtime.h"
#include "py/stream.h"
#include "py/mphal.h"
-#include "lib/timeutils/timeutils.h"
+#include "shared/timeutils/timeutils.h"
#include "ticks.h"
#include "tusb.h"
#include "fsl_snvs_lp.h"
diff --git a/ports/mimxrt/pin.h b/ports/mimxrt/pin.h
index ace4d1843..8d80490d1 100644
--- a/ports/mimxrt/pin.h
+++ b/ports/mimxrt/pin.h
@@ -29,7 +29,7 @@
#include
#include "py/obj.h"
-#include "lib/utils/mpirq.h"
+#include "shared/runtime/mpirq.h"
#include "fsl_gpio.h"
// ------------------------------------------------------------------------------------------------------------------ //
diff --git a/ports/mimxrt/tusb_port.c b/ports/mimxrt/tusb_port.c
index 2b1ccabbe..128861a49 100644
--- a/ports/mimxrt/tusb_port.c
+++ b/ports/mimxrt/tusb_port.c
@@ -26,8 +26,10 @@
#include "tusb.h"
-#define USBD_VID (0xf055)
-#define USBD_PID (0x9802)
+#ifndef MICROPY_HW_USB_VID
+#define MICROPY_HW_USB_VID (0xf055)
+#define MICROPY_HW_USB_PID (0x9802)
+#endif
#define USBD_DESC_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN)
#define USBD_MAX_POWER_MA (250)
@@ -57,8 +59,8 @@ static const tusb_desc_device_t usbd_desc_device = {
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
.bDeviceProtocol = MISC_PROTOCOL_IAD,
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
- .idVendor = USBD_VID,
- .idProduct = USBD_PID,
+ .idVendor = MICROPY_HW_USB_VID,
+ .idProduct = MICROPY_HW_USB_PID,
.bcdDevice = 0x0100,
.iManufacturer = USBD_STR_MANUF,
.iProduct = USBD_STR_PRODUCT,
diff --git a/ports/minimal/Makefile b/ports/minimal/Makefile
index bce544ec1..21e3fe3f7 100644
--- a/ports/minimal/Makefile
+++ b/ports/minimal/Makefile
@@ -41,22 +41,37 @@ CFLAGS += -Os -DNDEBUG
CFLAGS += -fdata-sections -ffunction-sections
endif
+# Flags for optional C++ source code
+CXXFLAGS += $(filter-out -std=c99,$(CFLAGS))
+CXXFLAGS += $(CXXFLAGS_MOD)
+
+# Flags for user C modules
+CFLAGS += $(CFLAGS_MOD)
+LDFLAGS += $(LDFLAGS_MOD)
+
LIBS =
SRC_C = \
main.c \
uart_core.c \
- lib/utils/printf.c \
- lib/utils/stdout_helpers.c \
- lib/utils/pyexec.c \
- lib/mp-readline/readline.c \
+ shared/libc/printf.c \
+ shared/readline/readline.c \
+ shared/runtime/pyexec.c \
+ shared/runtime/stdout_helpers.c \
$(BUILD)/_frozen_mpy.c \
ifeq ($(CROSS), 1)
-SRC_C += lib/libc/string0.c
+SRC_C += shared/libc/string0.c
endif
-OBJ = $(PY_CORE_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o))
+SRC_C += $(SRC_MOD)
+
+SRC_CXX += $(SRC_MOD_CXX)
+
+SRC_QSTR += $(SRC_MOD) $(SRC_MOD_CXX)
+
+OBJ += $(PY_CORE_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o))
+OBJ += $(addprefix $(BUILD)/, $(SRC_CXX:.cpp=.o))
ifeq ($(CROSS), 1)
all: $(BUILD)/firmware.dfu
diff --git a/ports/minimal/main.c b/ports/minimal/main.c
index aa6d10ee3..006ca0a4d 100644
--- a/ports/minimal/main.c
+++ b/ports/minimal/main.c
@@ -7,7 +7,7 @@
#include "py/repl.h"
#include "py/gc.h"
#include "py/mperrno.h"
-#include "lib/utils/pyexec.h"
+#include "shared/runtime/pyexec.h"
#if MICROPY_ENABLE_COMPILER
void do_str(const char *src, mp_parse_input_kind_t input_kind) {
diff --git a/ports/nrf/Makefile b/ports/nrf/Makefile
index a3f914dbc..a8a522827 100644
--- a/ports/nrf/Makefile
+++ b/ports/nrf/Makefile
@@ -5,6 +5,8 @@ ifeq ($(wildcard boards/$(BOARD)/.),)
$(error Invalid BOARD specified)
endif
+BOARD_DIR ?= boards/$(BOARD)
+
# If SoftDevice is selected, try to use that one.
SD ?=
SD_LOWER = $(shell echo $(SD) | tr '[:upper:]' '[:lower:]')
@@ -50,6 +52,8 @@ ifeq ($(DEBUG), 0)
MICROPY_ROM_TEXT_COMPRESSION ?= 1
endif
+FROZEN_MANIFEST ?= modules/manifest.py
+
# include py core make definitions
include ../../py/py.mk
@@ -70,7 +74,8 @@ INC += -I./modules/ubluepy
INC += -I./modules/music
INC += -I./modules/ble
INC += -I./modules/board
-INC += -I../../lib/mp-readline
+INC += -I./modules/nrf
+INC += -I../../shared/readline
INC += -I./drivers/bluetooth
INC += -I./drivers
INC += -I../../lib/nrfx/
@@ -129,6 +134,10 @@ LDFLAGS = $(CFLAGS)
LDFLAGS += -Xlinker -Map=$(@:.elf=.map)
LDFLAGS += -mthumb -mabi=aapcs $(addprefix -T,$(LD_FILES)) -L boards/
+ifneq ($(FS_SIZE),)
+LDFLAGS += -Wl,'--defsym=_fs_size=$(FS_SIZE)'
+endif
+
#Debugging/Optimization
ifeq ($(DEBUG), 1)
#ASMFLAGS += -g -gtabs+
@@ -216,12 +225,12 @@ include drivers/secureboot/secureboot.mk
endif
-SRC_LIB += $(addprefix lib/,\
+SRC_LIB += $(addprefix shared/,\
libc/string0.c \
- mp-readline/readline.c \
- utils/pyexec.c \
- utils/sys_stdio_mphal.c \
- utils/interrupt_char.c \
+ readline/readline.c \
+ runtime/pyexec.c \
+ runtime/sys_stdio_mphal.c \
+ runtime/interrupt_char.c \
timeutils/timeutils.c \
)
@@ -322,6 +331,8 @@ DRIVERS_SRC_C += $(addprefix modules/,\
music/modmusic.c \
music/musictunes.c \
ble/modble.c \
+ nrf/modnrf.c \
+ nrf/flashbdev.c \
)
# Custom micropython startup file with smaller interrupt vector table
@@ -530,13 +541,13 @@ GEN_PINS_QSTR = $(BUILD)/pins_qstr.h
GEN_PINS_AF_CONST = $(HEADER_BUILD)/pins_af_const.h
GEN_PINS_AF_PY = $(BUILD)/pins_af.py
-ifneq ($(FROZEN_DIR),)
+ifneq ($(FROZEN_MANIFEST)$(FROZEN_DIR),)
# To use frozen source modules, put your .py files in a subdirectory (eg scripts/)
# and then invoke make with FROZEN_DIR=scripts (be sure to build from scratch).
CFLAGS += -DMICROPY_MODULE_FROZEN_STR
endif
-ifneq ($(FROZEN_MPY_DIR),)
+ifneq ($(FROZEN_MANIFEST)$(FROZEN_MPY_DIR),)
# To use frozen bytecode, put your .py files in a subdirectory (eg frozen/) and
# then invoke make with FROZEN_MPY_DIR=frozen (be sure to build from scratch).
CFLAGS += -DMICROPY_QSTR_EXTRA_POOL=mp_qstr_frozen_const_pool
diff --git a/ports/nrf/README.md b/ports/nrf/README.md
index 0341cd81c..aa8968ff9 100644
--- a/ports/nrf/README.md
+++ b/ports/nrf/README.md
@@ -110,6 +110,22 @@ To use frozen modules, put them in a directory (e.g. `freeze/`) and supply
make BOARD=pca10040 FROZEN_MPY_DIR=freeze
+## Compile with freeze manifest
+
+Freeze manifests can be used by definining `FROZEN_MANIFEST` pointing to a
+`manifest.py`. This can either be done by a `make` invocation or by defining
+it in the specific target board's `mpconfigboard.mk`.
+
+For example:
+
+ make BOARD=pca10040 FROZEN_MANIFEST=path/to/manifest.py
+
+In case of using the target board's makefile, add a line similar to this:
+
+ FROZEN_MANIFEST ?= $(BOARD_DIR)/manifest.py
+
+In these two examples, the manual `make` invocation will have precedence.
+
## Enable MICROPY_VFS_FAT
As the `oofatfs` module is not having header guards that can exclude the implementation compile time, this port provides a flag to enable it explicitly. The MICROPY_VFS_FAT is by default set to 0 and has to be set to 1 if `oofatfs` files should be compiled. This will be in addition of setting `MICROPY_VFS` in mpconfigport.h.
@@ -117,6 +133,34 @@ For example:
make BOARD=pca10040 MICROPY_VFS_FAT=1
+## Enable MICROPY_VFS_LFS1 or MICROPY_VFS_LFS2
+
+In order to enable `littlefs` as device flash filesystem, `MICROPY_VFS_LFS1`
+or `MICROPY_VFS_LFS2` can be set. This will be in addition of setting
+`MICROPY_VFS` in mpconfigport.h or mpconfigboard.h.
+
+For example:
+
+ make BOARD=pca10056 MICROPY_VFS_LFS2=1
+
+## Set file system size
+
+The size of the file system on the internal flash is configured by the linker
+script parameter `_fs_size`. This can either be overriden by the linker script
+or dynamically through the makefile. By seting a value to the `FS_SIZE`.
+The number will be passed directly to the linker scripts in order to calculate
+the start and end of the file system. Note that the parameter value must be in
+linker script syntax as it is passed directly.
+
+For example, if we want to override the default file system size set by the
+linker scripts to use 256K:
+
+ make BOARD=pca10056 MICROPY_VFS_LFS2=1 FS_SIZE=256K
+
+Also note that changing this size between builds might cause loss of files
+present from a previous firmware as it will format the file system due to a new
+location.
+
## Target Boards and Make Flags
Target Board (BOARD) | Bluetooth Stack (SD) | Bluetooth Support | Bootloader | Default Flash Util
diff --git a/ports/nrf/boards/actinius_icarus/mpconfigboard.mk b/ports/nrf/boards/actinius_icarus/mpconfigboard.mk
index c1e05fd30..8e6f75b36 100644
--- a/ports/nrf/boards/actinius_icarus/mpconfigboard.mk
+++ b/ports/nrf/boards/actinius_icarus/mpconfigboard.mk
@@ -4,3 +4,5 @@ MCU_SUB_VARIANT = nrf9160
LD_FILES += boards/nrf9160_1M_256k.ld
NRF_DEFINES += -DNRF9160_XXAA -DNRF_TRUSTZONE_NONSECURE
+
+MICROPY_VFS_LFS2 = 1
diff --git a/ports/nrf/boards/arduino_primo/mpconfigboard.mk b/ports/nrf/boards/arduino_primo/mpconfigboard.mk
index 84685236b..e814d3d55 100644
--- a/ports/nrf/boards/arduino_primo/mpconfigboard.mk
+++ b/ports/nrf/boards/arduino_primo/mpconfigboard.mk
@@ -6,3 +6,5 @@ LD_FILES += boards/nrf52832_512k_64k.ld
FLASHER = pyocd
NRF_DEFINES += -DNRF52832_XXAA
+
+MICROPY_VFS_LFS2 = 1
diff --git a/ports/nrf/boards/blueio_tag_evim/mpconfigboard.mk b/ports/nrf/boards/blueio_tag_evim/mpconfigboard.mk
index 02a317744..c3164c8f0 100644
--- a/ports/nrf/boards/blueio_tag_evim/mpconfigboard.mk
+++ b/ports/nrf/boards/blueio_tag_evim/mpconfigboard.mk
@@ -6,3 +6,5 @@ LD_FILES += boards/nrf52832_512k_64k.ld
FLASHER = idap
NRF_DEFINES += -DNRF52832_XXAA
+
+MICROPY_VFS_LFS2 = 1
diff --git a/ports/nrf/boards/common.ld b/ports/nrf/boards/common.ld
index d2e5eef76..866336fa0 100644
--- a/ports/nrf/boards/common.ld
+++ b/ports/nrf/boards/common.ld
@@ -81,3 +81,5 @@ SECTIONS
/* Define heap and stack areas */
_ram_end = ORIGIN(RAM) + LENGTH(RAM);
_estack = ORIGIN(RAM) + LENGTH(RAM);
+_unused_flash_start = (_sidata + (_edata - _sdata));
+_unused_flash_len = (ORIGIN(FLASH_TEXT) + LENGTH(FLASH_TEXT)) - _unused_flash_start;
diff --git a/ports/nrf/boards/dvk_bl652/mpconfigboard.mk b/ports/nrf/boards/dvk_bl652/mpconfigboard.mk
index 8730d0297..30767d766 100644
--- a/ports/nrf/boards/dvk_bl652/mpconfigboard.mk
+++ b/ports/nrf/boards/dvk_bl652/mpconfigboard.mk
@@ -6,3 +6,5 @@ LD_FILES += boards/nrf52832_512k_64k.ld
NRF_DEFINES += -DNRF52832_XXAA
CFLAGS += -DBLUETOOTH_LFCLK_RC
+
+MICROPY_VFS_LFS2 = 1
diff --git a/ports/nrf/boards/evk_nina_b1/mpconfigboard.mk b/ports/nrf/boards/evk_nina_b1/mpconfigboard.mk
index db64a60dd..96245e3e4 100644
--- a/ports/nrf/boards/evk_nina_b1/mpconfigboard.mk
+++ b/ports/nrf/boards/evk_nina_b1/mpconfigboard.mk
@@ -5,3 +5,5 @@ SOFTDEV_VERSION = 6.1.1
LD_FILES += boards/nrf52832_512k_64k.ld
NRF_DEFINES += -DNRF52832_XXAA
+
+MICROPY_VFS_LFS2 = 1
diff --git a/ports/nrf/boards/feather52/mpconfigboard.mk b/ports/nrf/boards/feather52/mpconfigboard.mk
index 5e0f336da..96245e3e4 100644
--- a/ports/nrf/boards/feather52/mpconfigboard.mk
+++ b/ports/nrf/boards/feather52/mpconfigboard.mk
@@ -6,3 +6,4 @@ LD_FILES += boards/nrf52832_512k_64k.ld
NRF_DEFINES += -DNRF52832_XXAA
+MICROPY_VFS_LFS2 = 1
diff --git a/ports/nrf/boards/ibk_blyst_nano/mpconfigboard.mk b/ports/nrf/boards/ibk_blyst_nano/mpconfigboard.mk
index 02a317744..c3164c8f0 100644
--- a/ports/nrf/boards/ibk_blyst_nano/mpconfigboard.mk
+++ b/ports/nrf/boards/ibk_blyst_nano/mpconfigboard.mk
@@ -6,3 +6,5 @@ LD_FILES += boards/nrf52832_512k_64k.ld
FLASHER = idap
NRF_DEFINES += -DNRF52832_XXAA
+
+MICROPY_VFS_LFS2 = 1
diff --git a/ports/nrf/boards/idk_blyst_nano/mpconfigboard.mk b/ports/nrf/boards/idk_blyst_nano/mpconfigboard.mk
index 02a317744..c3164c8f0 100644
--- a/ports/nrf/boards/idk_blyst_nano/mpconfigboard.mk
+++ b/ports/nrf/boards/idk_blyst_nano/mpconfigboard.mk
@@ -6,3 +6,5 @@ LD_FILES += boards/nrf52832_512k_64k.ld
FLASHER = idap
NRF_DEFINES += -DNRF52832_XXAA
+
+MICROPY_VFS_LFS2 = 1
diff --git a/ports/nrf/boards/microbit/mpconfigboard.mk b/ports/nrf/boards/microbit/mpconfigboard.mk
index 96f430071..6fdd2bc50 100644
--- a/ports/nrf/boards/microbit/mpconfigboard.mk
+++ b/ports/nrf/boards/microbit/mpconfigboard.mk
@@ -2,9 +2,14 @@ MCU_SERIES = m0
MCU_VARIANT = nrf51
MCU_SUB_VARIANT = nrf51822
SOFTDEV_VERSION = 8.0.0
+
ifneq ($(SD),)
LD_FILES += boards/microbit/custom_nrf51822_s110_microbit.ld
+FROZEN_MANIFEST ?=
+else
+MICROPY_VFS_LFS2 = 1
endif
+
LD_FILES += boards/nrf51x22_256k_16k.ld
FLASHER = pyocd
diff --git a/ports/nrf/boards/nrf52840-mdk-usb-dongle/mpconfigboard.mk b/ports/nrf/boards/nrf52840-mdk-usb-dongle/mpconfigboard.mk
index ca437418d..3a26a92b7 100644
--- a/ports/nrf/boards/nrf52840-mdk-usb-dongle/mpconfigboard.mk
+++ b/ports/nrf/boards/nrf52840-mdk-usb-dongle/mpconfigboard.mk
@@ -17,3 +17,5 @@ endif
LD_FILES += boards/nrf52840_1M_256k.ld
NRF_DEFINES += -DNRF52840_XXAA
+
+MICROPY_VFS_LFS2 = 1
diff --git a/ports/nrf/boards/particle_xenon/mpconfigboard.mk b/ports/nrf/boards/particle_xenon/mpconfigboard.mk
index 34bead59f..d28324f76 100644
--- a/ports/nrf/boards/particle_xenon/mpconfigboard.mk
+++ b/ports/nrf/boards/particle_xenon/mpconfigboard.mk
@@ -9,3 +9,5 @@ NRF_DEFINES += -DNRF52840_XXAA
# The nrf52-particle.cfg is not included here, it can be found in the Particle Workbench
# Note: This requires openocd >0.10
OPENOCD_TARGET ?= boards/$(BOARD)/nrf52-particle.cfg
+
+MICROPY_VFS_LFS2 = 1
diff --git a/ports/nrf/boards/pca10000/mpconfigboard.mk b/ports/nrf/boards/pca10000/mpconfigboard.mk
index c0cef5f3a..64cf513c0 100644
--- a/ports/nrf/boards/pca10000/mpconfigboard.mk
+++ b/ports/nrf/boards/pca10000/mpconfigboard.mk
@@ -3,3 +3,9 @@ MCU_VARIANT = nrf51
MCU_SUB_VARIANT = nrf51822
SOFTDEV_VERSION = 8.0.0
LD_FILES += boards/nrf51x22_256k_16k.ld
+
+ifneq ($(SD),)
+FROZEN_MANIFEST ?=
+else
+MICROPY_VFS_LFS2 = 1
+endif
diff --git a/ports/nrf/boards/pca10001/mpconfigboard.mk b/ports/nrf/boards/pca10001/mpconfigboard.mk
index c0cef5f3a..64cf513c0 100644
--- a/ports/nrf/boards/pca10001/mpconfigboard.mk
+++ b/ports/nrf/boards/pca10001/mpconfigboard.mk
@@ -3,3 +3,9 @@ MCU_VARIANT = nrf51
MCU_SUB_VARIANT = nrf51822
SOFTDEV_VERSION = 8.0.0
LD_FILES += boards/nrf51x22_256k_16k.ld
+
+ifneq ($(SD),)
+FROZEN_MANIFEST ?=
+else
+MICROPY_VFS_LFS2 = 1
+endif
diff --git a/ports/nrf/boards/pca10028/mpconfigboard.mk b/ports/nrf/boards/pca10028/mpconfigboard.mk
index b3c8f21ea..83b26a1de 100644
--- a/ports/nrf/boards/pca10028/mpconfigboard.mk
+++ b/ports/nrf/boards/pca10028/mpconfigboard.mk
@@ -3,3 +3,9 @@ MCU_VARIANT = nrf51
MCU_SUB_VARIANT = nrf51822
SOFTDEV_VERSION = 8.0.0
LD_FILES += boards/nrf51x22_256k_32k.ld
+
+ifneq ($(SD),)
+FROZEN_MANIFEST ?=
+else
+MICROPY_VFS_LFS2 = 1
+endif
diff --git a/ports/nrf/boards/pca10031/mpconfigboard.mk b/ports/nrf/boards/pca10031/mpconfigboard.mk
index b3c8f21ea..83b26a1de 100644
--- a/ports/nrf/boards/pca10031/mpconfigboard.mk
+++ b/ports/nrf/boards/pca10031/mpconfigboard.mk
@@ -3,3 +3,9 @@ MCU_VARIANT = nrf51
MCU_SUB_VARIANT = nrf51822
SOFTDEV_VERSION = 8.0.0
LD_FILES += boards/nrf51x22_256k_32k.ld
+
+ifneq ($(SD),)
+FROZEN_MANIFEST ?=
+else
+MICROPY_VFS_LFS2 = 1
+endif
diff --git a/ports/nrf/boards/pca10040/mpconfigboard.mk b/ports/nrf/boards/pca10040/mpconfigboard.mk
index db64a60dd..96245e3e4 100644
--- a/ports/nrf/boards/pca10040/mpconfigboard.mk
+++ b/ports/nrf/boards/pca10040/mpconfigboard.mk
@@ -5,3 +5,5 @@ SOFTDEV_VERSION = 6.1.1
LD_FILES += boards/nrf52832_512k_64k.ld
NRF_DEFINES += -DNRF52832_XXAA
+
+MICROPY_VFS_LFS2 = 1
diff --git a/ports/nrf/boards/pca10056/mpconfigboard.mk b/ports/nrf/boards/pca10056/mpconfigboard.mk
index ca555d393..d8ee0f8a2 100644
--- a/ports/nrf/boards/pca10056/mpconfigboard.mk
+++ b/ports/nrf/boards/pca10056/mpconfigboard.mk
@@ -5,3 +5,5 @@ SOFTDEV_VERSION = 6.1.1
LD_FILES += boards/nrf52840_1M_256k.ld
NRF_DEFINES += -DNRF52840_XXAA
+
+MICROPY_VFS_LFS2 = 1
diff --git a/ports/nrf/boards/pca10059/mpconfigboard.mk b/ports/nrf/boards/pca10059/mpconfigboard.mk
index ca437418d..3a26a92b7 100644
--- a/ports/nrf/boards/pca10059/mpconfigboard.mk
+++ b/ports/nrf/boards/pca10059/mpconfigboard.mk
@@ -17,3 +17,5 @@ endif
LD_FILES += boards/nrf52840_1M_256k.ld
NRF_DEFINES += -DNRF52840_XXAA
+
+MICROPY_VFS_LFS2 = 1
diff --git a/ports/nrf/boards/pca10090/mpconfigboard.mk b/ports/nrf/boards/pca10090/mpconfigboard.mk
index 9363900e2..cc7e7c368 100644
--- a/ports/nrf/boards/pca10090/mpconfigboard.mk
+++ b/ports/nrf/boards/pca10090/mpconfigboard.mk
@@ -4,3 +4,5 @@ MCU_SUB_VARIANT = nrf9160
LD_FILES += boards/nrf9160_1M_256k.ld
NRF_DEFINES += -DNRF9160_XXAA -DNRF_TRUSTZONE_NONSECURE
+
+MICROPY_VFS_LFS2 = 1
diff --git a/ports/nrf/boards/wt51822_s4at/mpconfigboard.mk b/ports/nrf/boards/wt51822_s4at/mpconfigboard.mk
index 515de07f5..d0de24ba4 100644
--- a/ports/nrf/boards/wt51822_s4at/mpconfigboard.mk
+++ b/ports/nrf/boards/wt51822_s4at/mpconfigboard.mk
@@ -5,3 +5,9 @@ SOFTDEV_VERSION = 8.0.0
LD_FILES += boards/nrf51x22_256k_16k.ld
CFLAGS += -DBLUETOOTH_LFCLK_RC
+
+ifneq ($(SD),)
+FROZEN_MANIFEST ?=
+else
+MICROPY_VFS_LFS2 = 1
+endif
diff --git a/ports/nrf/drivers/bluetooth/ble_drv.c b/ports/nrf/drivers/bluetooth/ble_drv.c
index 3a15025cb..004058093 100644
--- a/ports/nrf/drivers/bluetooth/ble_drv.c
+++ b/ports/nrf/drivers/bluetooth/ble_drv.c
@@ -929,7 +929,7 @@ void ble_drv_discover_descriptors(void) {
static void sd_evt_handler(uint32_t evt_id) {
switch (evt_id) {
-#if MICROPY_MBFS
+#if MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE || MICROPY_MBFS
case NRF_EVT_FLASH_OPERATION_SUCCESS:
flash_operation_finished(FLASH_STATE_SUCCESS);
break;
diff --git a/ports/nrf/drivers/bluetooth/ble_uart.c b/ports/nrf/drivers/bluetooth/ble_uart.c
index 96c2025d0..c3712fe8c 100644
--- a/ports/nrf/drivers/bluetooth/ble_uart.c
+++ b/ports/nrf/drivers/bluetooth/ble_uart.c
@@ -30,7 +30,7 @@
#include "ble_uart.h"
#include "ringbuffer.h"
#include "mphalport.h"
-#include "lib/utils/interrupt_char.h"
+#include "shared/runtime/interrupt_char.h"
#include "py/runtime.h"
#if MICROPY_PY_SYS_STDFILES
diff --git a/ports/nrf/drivers/flash.c b/ports/nrf/drivers/flash.c
index 5a7256a0c..85e5f71d6 100644
--- a/ports/nrf/drivers/flash.c
+++ b/ports/nrf/drivers/flash.c
@@ -26,7 +26,7 @@
#include "py/mpconfig.h"
-#if MICROPY_MBFS && BLUETOOTH_SD
+#if (MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE || MICROPY_MBFS) && BLUETOOTH_SD
#include "drivers/flash.h"
#include "drivers/bluetooth/ble_drv.h"
@@ -129,4 +129,4 @@ void flash_write_bytes(uint32_t dst, const uint8_t *src, uint32_t num_bytes) {
}
}
-#endif // MICROPY_MBFS
+#endif // (MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE || MICROPY_MBFS) && BLUETOOTH_SD
diff --git a/ports/nrf/drivers/usb/usb_descriptors.c b/ports/nrf/drivers/usb/usb_descriptors.c
index e9436ded5..b1edfcc18 100644
--- a/ports/nrf/drivers/usb/usb_descriptors.c
+++ b/ports/nrf/drivers/usb/usb_descriptors.c
@@ -26,8 +26,10 @@
#include "tusb.h"
-#define USBD_VID (0xf055)
-#define USBD_PID (0x9802)
+#ifndef MICROPY_HW_USB_VID
+#define MICROPY_HW_USB_VID (0xf055)
+#define MICROPY_HW_USB_PID (0x9802)
+#endif
#define USBD_DESC_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN)
#define USBD_MAX_POWER_MA (250)
@@ -57,8 +59,8 @@ static const tusb_desc_device_t usbd_desc_device = {
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
.bDeviceProtocol = MISC_PROTOCOL_IAD,
.bMaxPacketSize0 = CFG_TUD_ENDOINT0_SIZE,
- .idVendor = USBD_VID,
- .idProduct = USBD_PID,
+ .idVendor = MICROPY_HW_USB_VID,
+ .idProduct = MICROPY_HW_USB_PID,
.bcdDevice = 0x0100,
.iManufacturer = USBD_STR_MANUF,
.iProduct = USBD_STR_PRODUCT,
diff --git a/ports/nrf/main.c b/ports/nrf/main.c
index 86ba83342..254d9491c 100644
--- a/ports/nrf/main.c
+++ b/ports/nrf/main.c
@@ -38,7 +38,7 @@
#include "py/stackctrl.h"
#include "py/gc.h"
#include "py/compile.h"
-#include "lib/utils/pyexec.h"
+#include "shared/runtime/pyexec.h"
#include "readline.h"
#include "gccollect.h"
#include "modmachine.h"
@@ -76,6 +76,13 @@
#include "usb_cdc.h"
#endif
+#if MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE
+#include "extmod/vfs_fat.h"
+#include "lib/oofatfs/ff.h"
+#include "extmod/vfs.h"
+#include "flashbdev.h"
+#endif
+
void do_str(const char *src, mp_parse_input_kind_t input_kind) {
mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0);
if (lex == NULL) {
@@ -99,6 +106,28 @@ void do_str(const char *src, mp_parse_input_kind_t input_kind) {
extern uint32_t _heap_start;
extern uint32_t _heap_end;
+#if MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE
+STATIC int vfs_mount_and_chdir(mp_obj_t bdev, mp_obj_t mount_point) {
+ nlr_buf_t nlr;
+ mp_int_t ret = -MP_EIO;
+ if (nlr_push(&nlr) == 0) {
+ mp_obj_t args[] = { bdev, mount_point };
+ mp_vfs_mount(2, args, (mp_map_t *)&mp_const_empty_map);
+ mp_vfs_chdir(mount_point);
+ ret = 0; // success
+ nlr_pop();
+ } else {
+ mp_obj_base_t *exc = nlr.ret_val;
+ if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(exc->type), MP_OBJ_FROM_PTR(&mp_type_OSError))) {
+ mp_obj_t v = mp_obj_exception_get_value(MP_OBJ_FROM_PTR(exc));
+ mp_obj_get_int_maybe(v, &ret); // get errno value
+ ret = -ret;
+ }
+ }
+ return ret;
+}
+#endif
+
int main(int argc, char **argv) {
@@ -169,6 +198,23 @@ soft_reset:
pin_init0();
+ #if MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE
+ flashbdev_init();
+
+ // Try to mount the flash on "/flash" and chdir to it for the boot-up directory.
+ mp_obj_t mount_point = MP_OBJ_NEW_QSTR(MP_QSTR__slash_flash);
+ int ret = vfs_mount_and_chdir((mp_obj_t)&nrf_flash_obj, mount_point);
+
+ if ((ret == -MP_ENODEV) || (ret == -MP_EIO)) {
+ pyexec_frozen_module("_mkfs.py"); // Frozen script for formatting flash filesystem.
+ ret = vfs_mount_and_chdir((mp_obj_t)&nrf_flash_obj, mount_point);
+ }
+
+ if (ret != 0) {
+ printf("MPY: can't mount flash\n");
+ }
+ #endif
+
#if MICROPY_MBFS
microbit_filesystem_init();
#endif
diff --git a/ports/nrf/modules/board/modboard.c b/ports/nrf/modules/board/modboard.c
index 5f59a52a6..647af5035 100644
--- a/ports/nrf/modules/board/modboard.c
+++ b/ports/nrf/modules/board/modboard.c
@@ -25,7 +25,7 @@
*/
#include "py/builtin.h"
-#include "lib/utils/pyexec.h"
+#include "shared/runtime/pyexec.h"
#include "py/runtime.h"
#include "py/obj.h"
#include "led.h"
diff --git a/ports/nrf/modules/machine/modmachine.c b/ports/nrf/modules/machine/modmachine.c
index 7e45b83df..fb3267e0d 100644
--- a/ports/nrf/modules/machine/modmachine.c
+++ b/ports/nrf/modules/machine/modmachine.c
@@ -33,7 +33,7 @@
#include "extmod/machine_mem.h"
#include "extmod/machine_pulse.h"
#include "extmod/machine_i2c.h"
-#include "lib/utils/pyexec.h"
+#include "shared/runtime/pyexec.h"
#include "lib/oofatfs/ff.h"
#include "lib/oofatfs/diskio.h"
#include "gccollect.h"
diff --git a/ports/nrf/modules/machine/spi.c b/ports/nrf/modules/machine/spi.c
index 2510c2750..880d946a2 100644
--- a/ports/nrf/modules/machine/spi.c
+++ b/ports/nrf/modules/machine/spi.c
@@ -46,18 +46,18 @@
#endif
/// \moduleref machine
-/// \class SPI - a master-driven serial protocol
+/// \class SPI - a controller-driven serial protocol
///
-/// SPI is a serial protocol that is driven by a master. At the physical level
+/// SPI is a serial protocol that is driven by a controller. At the physical level
/// there are 3 lines: SCK, MOSI, MISO.
///
/// See usage model of I2C; SPI is very similar. Main difference is
/// parameters to init the SPI bus:
///
/// from machine import SPI
-/// spi = SPI(1, SPI.MASTER, baudrate=600000, polarity=1, phase=0, crc=0x7)
+/// spi = SPI(1, baudrate=600000, polarity=1, phase=0, crc=0x7)
///
-/// Only required parameter is mode, SPI.MASTER or SPI.SLAVE. Polarity can be
+/// Polarity can be
/// 0 or 1, and is the level the idle clock line sits at. Phase can be 0 or 1
/// to sample data on the first or second clock edge respectively. Crc can be
/// None for no CRC, or a polynomial specifier.
diff --git a/ports/nrf/modules/machine/uart.c b/ports/nrf/modules/machine/uart.c
index af95ae4b8..2cc421aa1 100644
--- a/ports/nrf/modules/machine/uart.c
+++ b/ports/nrf/modules/machine/uart.c
@@ -38,7 +38,7 @@
#include "py/ringbuf.h"
#include "pin.h"
#include "genhdr/pins.h"
-#include "lib/utils/interrupt_char.h"
+#include "shared/runtime/interrupt_char.h"
#include "uart.h"
#include "mpconfigboard.h"
diff --git a/ports/nrf/modules/manifest.py b/ports/nrf/modules/manifest.py
new file mode 100644
index 000000000..4e8482226
--- /dev/null
+++ b/ports/nrf/modules/manifest.py
@@ -0,0 +1 @@
+freeze("$(PORT_DIR)/modules/scripts", "_mkfs.py")
diff --git a/ports/nrf/modules/nrf/flashbdev.c b/ports/nrf/modules/nrf/flashbdev.c
new file mode 100644
index 000000000..7a1296c5d
--- /dev/null
+++ b/ports/nrf/modules/nrf/flashbdev.c
@@ -0,0 +1,205 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Ayke van Laethem
+ * Copyright (c) 2019 Glenn Ruben Bakke
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include
+#include
+#include "py/runtime.h"
+#include "py/mperrno.h"
+
+#if MICROPY_PY_NRF && MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE
+
+#include "flashbdev.h"
+#include "flash.h"
+#include "extmod/vfs.h"
+
+extern byte _fs_start[];
+extern byte _fs_end[];
+
+#define FLASH_BLOCK_START (((uint32_t)_fs_start + (FLASH_PAGESIZE - 1)) / FLASH_PAGESIZE)
+
+typedef struct _nrf_flash_obj_t {
+ mp_obj_base_t base;
+ uint32_t start; // in bytes
+ uint32_t len; // in bytes
+} nrf_flash_obj_t;
+
+// This flash object represents the flash region defined by _fs_start and _fs_end
+// in memory.ld. The start/len entries will be filled in by flashbdev_init().
+nrf_flash_obj_t nrf_flash_obj = {
+ { &nrf_flashbdev_type },
+ 0,
+ 0,
+};
+
+mp_obj_t nrf_flashbdev_readblocks(size_t n_args, const mp_obj_t *args) {
+ nrf_flash_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+ uint32_t block_num = mp_obj_get_int(args[1]);
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(args[2], &bufinfo, MP_BUFFER_WRITE);
+
+ mp_int_t address = self->start + (block_num * FLASH_PAGESIZE);
+
+ if (n_args == 4) {
+ uint32_t offset = mp_obj_get_int(args[3]);
+ address += offset;
+ }
+
+ byte *buf = bufinfo.buf;
+ byte *p = (byte *)address;
+ memcpy(buf, p, bufinfo.len);
+
+ return MP_OBJ_NEW_SMALL_INT(0);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(nrf_flashbdev_readblocks_obj, 3, 4, nrf_flashbdev_readblocks);
+
+mp_obj_t nrf_flashbdev_writeblocks(size_t n_args, const mp_obj_t *args) {
+ nrf_flash_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+ uint32_t block_num = mp_obj_get_int(args[1]);
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(args[2], &bufinfo, MP_BUFFER_WRITE);
+
+ mp_int_t address = self->start + (block_num * FLASH_PAGESIZE);
+
+ if (n_args == 4) {
+ uint32_t offset = mp_obj_get_int(args[3]);
+ address += offset;
+ } else {
+ flash_page_erase(address);
+ }
+
+ flash_write_bytes(address, bufinfo.buf, bufinfo.len);
+
+ return MP_OBJ_NEW_SMALL_INT(0);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(nrf_flashbdev_writeblocks_obj, 3, 4, nrf_flashbdev_writeblocks);
+
+mp_obj_t nrf_flashbdev_ioctl(mp_obj_t self_in, mp_obj_t op_in, mp_obj_t arg_in) {
+ nrf_flash_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_int_t op = mp_obj_get_int(op_in);
+ switch (op) {
+ case MP_BLOCKDEV_IOCTL_INIT: {
+ return MP_OBJ_NEW_SMALL_INT(0);
+ }
+
+ case MP_BLOCKDEV_IOCTL_DEINIT: {
+ return MP_OBJ_NEW_SMALL_INT(0);
+ }
+
+ case MP_BLOCKDEV_IOCTL_SYNC: {
+ return MP_OBJ_NEW_SMALL_INT(0);
+ }
+
+ case MP_BLOCKDEV_IOCTL_BLOCK_COUNT: {
+ return MP_OBJ_NEW_SMALL_INT(self->len / FLASH_PAGESIZE);
+ }
+
+ case MP_BLOCKDEV_IOCTL_BLOCK_SIZE: {
+ return MP_OBJ_NEW_SMALL_INT(FLASH_PAGESIZE);
+ }
+
+ case MP_BLOCKDEV_IOCTL_BLOCK_ERASE: {
+ mp_int_t block_num = mp_obj_get_int(arg_in);
+ mp_int_t address = self->start + (block_num * FLASH_PAGESIZE);
+
+ if ((address & 0x3) || (address % FLASH_PAGESIZE != 0)) {
+ return MP_OBJ_NEW_SMALL_INT(-MP_EIO);
+ }
+
+ flash_page_erase(address);
+ return MP_OBJ_NEW_SMALL_INT(0);
+ }
+
+ default:
+ return mp_const_none;
+ }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(nrf_flashbdev_ioctl_obj, nrf_flashbdev_ioctl);
+
+STATIC const mp_rom_map_elem_t nrf_flashbdev_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_readblocks), MP_ROM_PTR(&nrf_flashbdev_readblocks_obj) },
+ { MP_ROM_QSTR(MP_QSTR_writeblocks), MP_ROM_PTR(&nrf_flashbdev_writeblocks_obj) },
+ { MP_ROM_QSTR(MP_QSTR_ioctl), MP_ROM_PTR(&nrf_flashbdev_ioctl_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(nrf_flashbdev_locals_dict, nrf_flashbdev_locals_dict_table);
+
+STATIC void nrf_flashbdev_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
+ nrf_flash_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_printf(print, "Flash(start=0x%08x, len=%u)", self->start, self->len);
+}
+
+STATIC mp_obj_t nrf_flashbdev_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ // Parse arguments
+ enum { ARG_start, ARG_len };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
+ { MP_QSTR_len, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ if (args[ARG_start].u_int == -1 && args[ARG_len].u_int == -1) {
+ return MP_OBJ_FROM_PTR(&nrf_flash_obj);
+ }
+
+ nrf_flash_obj_t *self = m_new_obj(nrf_flash_obj_t);
+ self->base.type = &nrf_flashbdev_type;
+
+ mp_int_t start = args[ARG_start].u_int;
+ mp_int_t len = args[ARG_len].u_int;
+
+ if ((start == -1) || (start % FLASH_PAGESIZE != 0)) {
+ mp_raise_ValueError(NULL);
+ }
+ if ((len == -1) || (len % FLASH_PAGESIZE != 0)) {
+ mp_raise_ValueError(NULL);
+ }
+
+ self->start = start;
+ self->len = len;
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+const mp_obj_type_t nrf_flashbdev_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_Flash,
+ .print = nrf_flashbdev_print,
+ .make_new = nrf_flashbdev_make_new,
+ .locals_dict = (mp_obj_dict_t *)&nrf_flashbdev_locals_dict,
+};
+
+void flashbdev_init(void) {
+ // Set start to first aligned page from _fs_start.
+ mp_int_t page_start = FLASH_BLOCK_START;
+ nrf_flash_obj.start = page_start * FLASH_PAGESIZE;
+ // Trim len to only count whole pages.
+ mp_int_t page_end = (uint32_t)_fs_end / FLASH_PAGESIZE;
+ mp_int_t num_pages = page_end - page_start;
+ nrf_flash_obj.len = num_pages * FLASH_PAGESIZE;
+}
+
+#endif // MICROPY_PY_NRF && MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE
diff --git a/ports/nrf/modules/nrf/flashbdev.h b/ports/nrf/modules/nrf/flashbdev.h
new file mode 100644
index 000000000..29d7a12ed
--- /dev/null
+++ b/ports/nrf/modules/nrf/flashbdev.h
@@ -0,0 +1,39 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Ayke van Laethem
+ * Copyright (c) 2019 Glenn Ruben Bakke
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_NRF_FLASHBDEV_H
+#define MICROPY_INCLUDED_NRF_FLASHBDEV_H
+
+#include "py/obj.h"
+#include "extmod/vfs_fat.h"
+
+extern const struct _mp_obj_type_t nrf_flashbdev_type;
+extern struct _nrf_flash_obj_t nrf_flash_obj;
+
+void flashbdev_init(void);
+
+#endif // MICROPY_INCLUDED_NRF_FLASHBDEV_H
diff --git a/ports/nrf/modules/nrf/modnrf.c b/ports/nrf/modules/nrf/modnrf.c
new file mode 100644
index 000000000..fc217b1d7
--- /dev/null
+++ b/ports/nrf/modules/nrf/modnrf.c
@@ -0,0 +1,98 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Ayke van Laethem
+ * Copyright (c) 2019 Glenn Ruben Bakke
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/runtime.h"
+
+#if MICROPY_PY_NRF
+
+#include "flashbdev.h"
+#include "flash.h"
+#include "nrf_power.h"
+
+#if BLUETOOTH_SD
+#include "nrf_soc.h"
+#include "ble_drv.h"
+#define BLUETOOTH_STACK_ENABLED() (ble_drv_stack_enabled())
+#endif
+
+#define FLASH_PAGE_ALIGN_UP(addr) (((addr) - 1) + (FLASH_PAGESIZE)-(((addr) - 1) % (FLASH_PAGESIZE)))
+
+extern uint32_t _unused_flash_start;
+extern uint32_t _unused_flash_len;
+
+#if NRF_POWER_HAS_DCDCEN
+STATIC mp_obj_t dcdc(size_t n_args, const mp_obj_t *args) {
+ if (n_args > 0) {
+ bool dcdc_state = mp_obj_is_true(args[0]);
+ #if BLUETOOTH_SD
+ if (BLUETOOTH_STACK_ENABLED()) {
+ sd_power_dcdc_mode_set(dcdc_state);
+ } else
+ #endif
+ {
+ nrf_power_dcdcen_set(NRF_POWER, dcdc_state);
+ }
+ }
+ return mp_obj_new_bool(nrf_power_dcdcen_get(NRF_POWER));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(dcdc_obj, 0, 1, dcdc);
+#endif
+
+#if MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE
+mp_obj_t nrf_modnrf_freeflash_start_aligned(void) {
+ return mp_obj_new_int_from_uint(FLASH_PAGE_ALIGN_UP((uint32_t)&_unused_flash_start));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(nrf_modnrf_freeflash_start_aligned_obj, nrf_modnrf_freeflash_start_aligned);
+
+mp_obj_t nrf_modnrf_freeflash_length_aligned(void) {
+ uint32_t align_diff = FLASH_PAGE_ALIGN_UP((uint32_t)&_unused_flash_start) - ((uint32_t)&_unused_flash_start);
+ uint32_t temp_len = ((uint32_t)&_unused_flash_len) - align_diff;
+ uint32_t len_page_aligned = (temp_len / FLASH_PAGESIZE) * FLASH_PAGESIZE;
+ return mp_obj_new_int_from_uint(len_page_aligned);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(nrf_modnrf_freeflash_length_aligned_obj, nrf_modnrf_freeflash_length_aligned);
+#endif
+
+STATIC const mp_rom_map_elem_t nrf_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_nrf) },
+ #if NRF_POWER_HAS_DCDCEN
+ { MP_ROM_QSTR(MP_QSTR_dcdc), MP_ROM_PTR(&dcdc_obj) },
+ #endif
+ #if MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE
+ { MP_ROM_QSTR(MP_QSTR_Flash), MP_ROM_PTR(&nrf_flashbdev_type) },
+ { MP_ROM_QSTR(MP_QSTR_unused_flash_start), MP_ROM_PTR(&nrf_modnrf_freeflash_start_aligned_obj) },
+ { MP_ROM_QSTR(MP_QSTR_unused_flash_length), MP_ROM_PTR(&nrf_modnrf_freeflash_length_aligned_obj) },
+ #endif
+};
+STATIC MP_DEFINE_CONST_DICT(nrf_module_globals, nrf_module_globals_table);
+
+const mp_obj_module_t nrf_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&nrf_module_globals,
+};
+
+#endif // MICROPY_PY_NRF
diff --git a/ports/nrf/modules/scripts/_mkfs.py b/ports/nrf/modules/scripts/_mkfs.py
new file mode 100644
index 000000000..00522ffbb
--- /dev/null
+++ b/ports/nrf/modules/scripts/_mkfs.py
@@ -0,0 +1,23 @@
+import uos, nrf
+
+try:
+ from uos import VfsLfs1
+
+ uos.VfsLfs1.mkfs(nrf.Flash())
+except ImportError:
+ try:
+ from uos import VfsLfs2
+
+ uos.VfsLfs2.mkfs(nrf.Flash())
+ except ImportError:
+ try:
+ from uos import VfsFat
+
+ uos.VfsFat.mkfs(nrf.Flash())
+ except ImportError:
+ pass
+ except OSError as e:
+ if e.args[0] == 5: # I/O Error
+ flashbdev_size = (nrf.Flash.ioctl(4, 0) * nrf.Flash.ioctl(5, 0)) // 1024
+ print()
+ print("Is `FS_SIZE=%iK` enough for FAT filesystem?" % flashbdev_size)
diff --git a/ports/nrf/modules/uos/moduos.c b/ports/nrf/modules/uos/moduos.c
index 98a5661f4..e8a3790da 100644
--- a/ports/nrf/modules/uos/moduos.c
+++ b/ports/nrf/modules/uos/moduos.c
@@ -36,6 +36,7 @@
#include "modules/uos/microbitfs.h"
#include "extmod/vfs.h"
#include "extmod/vfs_fat.h"
+#include "extmod/vfs_lfs.h"
#include "genhdr/mpversion.h"
#include "uart.h"
@@ -85,10 +86,12 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(os_uname_obj, os_uname);
/// \function sync()
/// Sync all filesystems.
STATIC mp_obj_t os_sync(void) {
+ #if MICROPY_VFS_FAT
for (mp_vfs_mount_t *vfs = MP_STATE_VM(vfs_mount_table); vfs != NULL; vfs = vfs->next) {
// this assumes that vfs->obj is fs_user_mount_t with block device functions
disk_ioctl(MP_OBJ_TO_PTR(vfs->obj), CTRL_SYNC, NULL);
}
+ #endif
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_0(mod_os_sync_obj, os_sync);
@@ -142,6 +145,7 @@ STATIC const mp_rom_map_elem_t os_module_globals_table[] = {
#if MICROPY_VFS
{ MP_ROM_QSTR(MP_QSTR_chdir), MP_ROM_PTR(&mp_vfs_chdir_obj) },
{ MP_ROM_QSTR(MP_QSTR_getcwd), MP_ROM_PTR(&mp_vfs_getcwd_obj) },
+ { MP_ROM_QSTR(MP_QSTR_ilistdir), MP_ROM_PTR(&mp_vfs_ilistdir_obj) },
{ MP_ROM_QSTR(MP_QSTR_listdir), MP_ROM_PTR(&mp_vfs_listdir_obj) },
{ MP_ROM_QSTR(MP_QSTR_mkdir), MP_ROM_PTR(&mp_vfs_mkdir_obj) },
{ MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&mp_vfs_remove_obj) },
@@ -174,7 +178,15 @@ STATIC const mp_rom_map_elem_t os_module_globals_table[] = {
#if MICROPY_VFS
{ MP_ROM_QSTR(MP_QSTR_mount), MP_ROM_PTR(&mp_vfs_mount_obj) },
{ MP_ROM_QSTR(MP_QSTR_umount), MP_ROM_PTR(&mp_vfs_umount_obj) },
+ #if MICROPY_VFS_FAT
{ MP_ROM_QSTR(MP_QSTR_VfsFat), MP_ROM_PTR(&mp_fat_vfs_type) },
+ #endif
+ #if MICROPY_VFS_LFS1
+ { MP_ROM_QSTR(MP_QSTR_VfsLfs1), MP_ROM_PTR(&mp_type_vfs_lfs1) },
+ #endif
+ #if MICROPY_VFS_LFS2
+ { MP_ROM_QSTR(MP_QSTR_VfsLfs2), MP_ROM_PTR(&mp_type_vfs_lfs2) },
+ #endif
#endif
};
diff --git a/ports/nrf/mpconfigdevice_nrf51822.h b/ports/nrf/mpconfigdevice_nrf51822.h
index 2f85c9f4c..67a81d250 100644
--- a/ports/nrf/mpconfigdevice_nrf51822.h
+++ b/ports/nrf/mpconfigdevice_nrf51822.h
@@ -27,15 +27,31 @@
// Board overridable build configuration.
#ifndef MICROPY_MBFS
+#if defined(BLUETOOTH_SD)
#define MICROPY_MBFS (1)
+#else
+#define MICROPY_MBFS (0)
+#endif
#endif
#ifndef MICROPY_VFS
+#if defined(BLUETOOTH_SD)
#define MICROPY_VFS (0)
+#else
+#define MICROPY_VFS (1)
+#endif
#endif
// Board overridable feature configuration.
+#ifndef MICROPY_ENABLE_SOURCE_LINE
+#if defined(BLUETOOTH_SD)
+#define MICROPY_ENABLE_SOURCE_LINE (0)
+#else
+#define MICROPY_ENABLE_SOURCE_LINE (1)
+#endif
+#endif
+
#ifndef MICROPY_PY_ARRAY_SLICE_ASSIGN
#if defined(BLUETOOTH_SD)
#define MICROPY_PY_ARRAY_SLICE_ASSIGN (0)
@@ -59,3 +75,23 @@
#define MICROPY_PY_UBINASCII (1)
#endif
#endif
+
+// Board overridable port specific feature configuration.
+
+#ifndef MICROPY_PY_NRF
+#if defined(BLUETOOTH_SD)
+#define MICROPY_PY_NRF (0)
+#else
+#define MICROPY_PY_NRF (1)
+#endif
+#endif
+
+// Board overridable hardware configuration.
+
+#ifndef MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE
+#if defined(BLUETOOTH_SD)
+#define MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE (0)
+#else
+#define MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE (1)
+#endif
+#endif
diff --git a/ports/nrf/mpconfigdevice_nrf52832.h b/ports/nrf/mpconfigdevice_nrf52832.h
index 2bfd047ca..fa9258f2a 100644
--- a/ports/nrf/mpconfigdevice_nrf52832.h
+++ b/ports/nrf/mpconfigdevice_nrf52832.h
@@ -27,15 +27,19 @@
// Board overridable build configuration.
#ifndef MICROPY_MBFS
-#define MICROPY_MBFS (1)
+#define MICROPY_MBFS (0)
#endif
#ifndef MICROPY_VFS
-#define MICROPY_VFS (0)
+#define MICROPY_VFS (1)
#endif
// Board overridable feature configuration.
+#ifndef MICROPY_ENABLE_SOURCE_LINE
+#define MICROPY_ENABLE_SOURCE_LINE (1)
+#endif
+
#ifndef MICROPY_PY_ARRAY_SLICE_ASSIGN
#define MICROPY_PY_ARRAY_SLICE_ASSIGN (1)
#endif
@@ -47,3 +51,15 @@
#ifndef MICROPY_PY_UBINASCII
#define MICROPY_PY_UBINASCII (1)
#endif
+
+// Board overridable port specific feature configuration.
+
+#ifndef MICROPY_PY_NRF
+#define MICROPY_PY_NRF (1)
+#endif
+
+// Board overridable hardware configuration.
+
+#ifndef MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE
+#define MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE (1)
+#endif
diff --git a/ports/nrf/mpconfigdevice_nrf52840.h b/ports/nrf/mpconfigdevice_nrf52840.h
index 2bfd047ca..581c52ea8 100644
--- a/ports/nrf/mpconfigdevice_nrf52840.h
+++ b/ports/nrf/mpconfigdevice_nrf52840.h
@@ -27,15 +27,29 @@
// Board overridable build configuration.
#ifndef MICROPY_MBFS
-#define MICROPY_MBFS (1)
+#define MICROPY_MBFS (0)
#endif
#ifndef MICROPY_VFS
-#define MICROPY_VFS (0)
+#define MICROPY_VFS (1)
+#endif
+
+// Board overridable emitter configuration.
+
+#ifndef MICROPY_EMIT_THUMB
+#define MICROPY_EMIT_THUMB (1)
+#endif
+
+#ifndef MICROPY_EMIT_INLINE_THUMB
+#define MICROPY_EMIT_INLINE_THUMB (1)
#endif
// Board overridable feature configuration.
+#ifndef MICROPY_ENABLE_SOURCE_LINE
+#define MICROPY_ENABLE_SOURCE_LINE (1)
+#endif
+
#ifndef MICROPY_PY_ARRAY_SLICE_ASSIGN
#define MICROPY_PY_ARRAY_SLICE_ASSIGN (1)
#endif
@@ -47,3 +61,15 @@
#ifndef MICROPY_PY_UBINASCII
#define MICROPY_PY_UBINASCII (1)
#endif
+
+// Board overridable port specific feature configuration.
+
+#ifndef MICROPY_PY_NRF
+#define MICROPY_PY_NRF (1)
+#endif
+
+// Board overridable hardware configuration.
+
+#ifndef MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE
+#define MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE (1)
+#endif
diff --git a/ports/nrf/mpconfigdevice_nrf9160.h b/ports/nrf/mpconfigdevice_nrf9160.h
index 2bfd047ca..581c52ea8 100644
--- a/ports/nrf/mpconfigdevice_nrf9160.h
+++ b/ports/nrf/mpconfigdevice_nrf9160.h
@@ -27,15 +27,29 @@
// Board overridable build configuration.
#ifndef MICROPY_MBFS
-#define MICROPY_MBFS (1)
+#define MICROPY_MBFS (0)
#endif
#ifndef MICROPY_VFS
-#define MICROPY_VFS (0)
+#define MICROPY_VFS (1)
+#endif
+
+// Board overridable emitter configuration.
+
+#ifndef MICROPY_EMIT_THUMB
+#define MICROPY_EMIT_THUMB (1)
+#endif
+
+#ifndef MICROPY_EMIT_INLINE_THUMB
+#define MICROPY_EMIT_INLINE_THUMB (1)
#endif
// Board overridable feature configuration.
+#ifndef MICROPY_ENABLE_SOURCE_LINE
+#define MICROPY_ENABLE_SOURCE_LINE (1)
+#endif
+
#ifndef MICROPY_PY_ARRAY_SLICE_ASSIGN
#define MICROPY_PY_ARRAY_SLICE_ASSIGN (1)
#endif
@@ -47,3 +61,15 @@
#ifndef MICROPY_PY_UBINASCII
#define MICROPY_PY_UBINASCII (1)
#endif
+
+// Board overridable port specific feature configuration.
+
+#ifndef MICROPY_PY_NRF
+#define MICROPY_PY_NRF (1)
+#endif
+
+// Board overridable hardware configuration.
+
+#ifndef MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE
+#define MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE (1)
+#endif
diff --git a/ports/nrf/mpconfigport.h b/ports/nrf/mpconfigport.h
index 183fdf681..8a622d811 100644
--- a/ports/nrf/mpconfigport.h
+++ b/ports/nrf/mpconfigport.h
@@ -43,7 +43,7 @@
#define MICROPY_VFS (0)
#endif
#define MICROPY_ALLOC_PATH_MAX (512)
-#define MICROPY_PERSISTENT_CODE_LOAD (0)
+#define MICROPY_PERSISTENT_CODE_LOAD (1)
#define MICROPY_COMP_MODULE_CONST (0)
#define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (0)
#define MICROPY_READER_VFS (MICROPY_VFS)
@@ -55,7 +55,6 @@
#define MICROPY_REPL_EMACS_KEYS (0)
#define MICROPY_REPL_AUTO_INDENT (1)
#define MICROPY_KBD_EXCEPTION (1)
-#define MICROPY_ENABLE_SOURCE_LINE (0)
#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ)
#if NRF51
#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_NONE)
@@ -75,7 +74,13 @@
#define MICROPY_FATFS_LFN_CODE_PAGE 437 /* 1=SFN/ANSI 437=LFN/U.S.(OEM) */
#define MICROPY_FATFS_USE_LABEL (1)
#define MICROPY_FATFS_RPATH (2)
-#define MICROPY_FATFS_MULTI_PARTITION (1)
+#define MICROPY_FATFS_MULTI_PARTITION (0)
+
+#if NRF51
+ #define MICROPY_FATFS_MAX_SS (1024)
+#else
+ #define MICROPY_FATFS_MAX_SS (4096)
+#endif
// TODO these should be generic, not bound to fatfs
#define mp_type_fileio fatfs_type_fileio
@@ -98,7 +103,7 @@
#define MICROPY_CAN_OVERRIDE_BUILTINS (1)
#define MICROPY_USE_INTERNAL_ERRNO (1)
#define MICROPY_PY_FUNCTION_ATTRS (1)
-#define MICROPY_PY_BUILTINS_STR_UNICODE (0)
+#define MICROPY_PY_BUILTINS_STR_UNICODE (1)
#define MICROPY_PY_BUILTINS_STR_CENTER (0)
#define MICROPY_PY_BUILTINS_STR_PARTITION (0)
#define MICROPY_PY_BUILTINS_STR_SPLITLINES (0)
@@ -120,7 +125,7 @@
#define MICROPY_PY_MATH_SPECIAL_FUNCTIONS (0)
#define MICROPY_PY_CMATH (0)
#define MICROPY_PY_IO (0)
-#define MICROPY_PY_IO_FILEIO (0)
+#define MICROPY_PY_IO_FILEIO (MICROPY_VFS_FAT || MICROPY_VFS_LFS1 || MICROPY_VFS_LFS2)
#define MICROPY_PY_URANDOM (1)
#define MICROPY_PY_URANDOM_EXTRA_FUNCS (1)
#define MICROPY_PY_UCTYPES (0)
@@ -179,6 +184,10 @@
#define MICROPY_PY_TIME_TICKS (1)
#endif
+#ifndef MICROPY_PY_NRF
+#define MICROPY_PY_NRF (0)
+#endif
+
#define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (1)
#define MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE (0)
@@ -212,11 +221,18 @@ typedef long mp_off_t;
// extra built in modules to add to the list of known ones
extern const struct _mp_obj_module_t board_module;
extern const struct _mp_obj_module_t machine_module;
+extern const struct _mp_obj_module_t nrf_module;
extern const struct _mp_obj_module_t mp_module_utime;
extern const struct _mp_obj_module_t mp_module_uos;
extern const struct _mp_obj_module_t mp_module_ubluepy;
extern const struct _mp_obj_module_t music_module;
+#if MICROPY_PY_NRF
+#define NRF_MODULE { MP_ROM_QSTR(MP_QSTR_nrf), MP_ROM_PTR(&nrf_module) },
+#else
+#define NRF_MODULE
+#endif
+
#if MICROPY_PY_UBLUEPY
#define UBLUEPY_MODULE { MP_ROM_QSTR(MP_QSTR_ubluepy), MP_ROM_PTR(&mp_module_ubluepy) },
#else
@@ -255,6 +271,7 @@ extern const struct _mp_obj_module_t ble_module;
MUSIC_MODULE \
UBLUEPY_MODULE \
MICROPY_BOARD_BUILTINS \
+ NRF_MODULE \
#else
@@ -266,6 +283,7 @@ extern const struct _mp_obj_module_t ble_module;
{ MP_ROM_QSTR(MP_QSTR_uos), MP_ROM_PTR(&mp_module_uos) }, \
MUSIC_MODULE \
MICROPY_BOARD_BUILTINS \
+ NRF_MODULE \
#endif // BLUETOOTH_SD
diff --git a/ports/nrf/mphalport.c b/ports/nrf/mphalport.c
index b8e4c2e4d..8ffb25601 100644
--- a/ports/nrf/mphalport.c
+++ b/ports/nrf/mphalport.c
@@ -150,6 +150,10 @@ mp_uint_t mp_hal_ticks_ms(void) {
#endif
+uint64_t mp_hal_time_ns(void) {
+ return 0;
+}
+
// this table converts from HAL_StatusTypeDef to POSIX errno
const byte mp_hal_status_to_errno_table[4] = {
[HAL_OK] = 0,
diff --git a/ports/nrf/mphalport.h b/ports/nrf/mphalport.h
index 5900559b5..1ba4b6e70 100644
--- a/ports/nrf/mphalport.h
+++ b/ports/nrf/mphalport.h
@@ -78,4 +78,3 @@ mp_uint_t mp_hal_ticks_ms(void);
#define mp_hal_ticks_cpu() (0)
#endif
-
diff --git a/ports/nrf/nrfx_glue.h b/ports/nrf/nrfx_glue.h
index b4a60257a..56e1f719d 100644
--- a/ports/nrf/nrfx_glue.h
+++ b/ports/nrf/nrfx_glue.h
@@ -27,8 +27,15 @@
#ifndef NRFX_GLUE_H
#define NRFX_GLUE_H
+#include "py/mpconfig.h"
+#include "py/misc.h"
+
#include
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE MP_ARRAY_SIZE
+#endif
+
#define NRFX_STATIC_ASSERT(expression)
#define NRFX_ASSERT(expression) do { bool res = expression; (void)res; } while (0)
diff --git a/ports/nrf/qstrdefsport.h b/ports/nrf/qstrdefsport.h
index 9608dbb24..3cc2f1e64 100644
--- a/ports/nrf/qstrdefsport.h
+++ b/ports/nrf/qstrdefsport.h
@@ -27,6 +27,12 @@
// qstrs specific to this port
// *FORMAT-OFF*
+// Entries for sys.path
+Q(/flash)
+
+// For uos.sep
+Q(/)
+
Q(a)
Q(a#)
Q(a#:1)
@@ -138,4 +144,3 @@ Q(r4:2)
Q(r:1)
Q(r:2)
Q(r:3)
-
diff --git a/ports/pic16bit/Makefile b/ports/pic16bit/Makefile
index 3c2bd54ea..f0d55ec87 100644
--- a/ports/pic16bit/Makefile
+++ b/ports/pic16bit/Makefile
@@ -39,9 +39,9 @@ SRC_C = \
modpyb.c \
modpybled.c \
modpybswitch.c \
- lib/utils/pyexec.c \
- lib/utils/sys_stdio_mphal.c \
- lib/mp-readline/readline.c \
+ shared/runtime/pyexec.c \
+ shared/runtime/sys_stdio_mphal.c \
+ shared/readline/readline.c \
SRC_S = \
# gchelper.s \
diff --git a/ports/pic16bit/main.c b/ports/pic16bit/main.c
index 07db3f582..adb927607 100644
--- a/ports/pic16bit/main.c
+++ b/ports/pic16bit/main.c
@@ -34,8 +34,8 @@
#include "py/gc.h"
#include "py/mphal.h"
#include "py/mperrno.h"
-#include "lib/utils/pyexec.h"
-#include "lib/mp-readline/readline.h"
+#include "shared/runtime/pyexec.h"
+#include "shared/readline/readline.h"
#include "board.h"
#include "modpyb.h"
diff --git a/ports/powerpc/Makefile b/ports/powerpc/Makefile
index 1f5ec80d4..cca170dc0 100644
--- a/ports/powerpc/Makefile
+++ b/ports/powerpc/Makefile
@@ -34,11 +34,11 @@ LIBS =
SRC_C = \
main.c \
uart_$(UART).c \
- lib/utils/printf.c \
- lib/utils/stdout_helpers.c \
- lib/utils/pyexec.c \
- lib/libc/string0.c \
- lib/mp-readline/readline.c \
+ shared/libc/printf.c \
+ shared/libc/string0.c \
+ shared/readline/readline.c \
+ shared/runtime/pyexec.c \
+ shared/runtime/stdout_helpers.c \
$(BUILD)/_frozen_mpy.c \
OBJ = $(PY_CORE_O)
diff --git a/ports/powerpc/main.c b/ports/powerpc/main.c
index fdeec13ab..a66d737c1 100644
--- a/ports/powerpc/main.c
+++ b/ports/powerpc/main.c
@@ -32,7 +32,7 @@
#include "py/gc.h"
#include "py/mperrno.h"
#include "py/stackctrl.h"
-#include "lib/utils/pyexec.h"
+#include "shared/runtime/pyexec.h"
void __stack_chk_fail(void);
void __stack_chk_fail(void) {
diff --git a/ports/qemu-arm/Makefile b/ports/qemu-arm/Makefile
index 22d0bf39c..4a6d63a01 100644
--- a/ports/qemu-arm/Makefile
+++ b/ports/qemu-arm/Makefile
@@ -16,7 +16,7 @@ ifeq ($(BOARD),netduino2)
CFLAGS += -mthumb -mcpu=cortex-m3 -mfloat-abi=soft
CFLAGS += -DQEMU_SOC_STM32
LDSCRIPT = stm32.ld
-SRC_BOARD_O = lib/utils/gchelper_native.o lib/utils/gchelper_m3.o
+SRC_BOARD_O = shared/runtime/gchelper_native.o shared/runtime/gchelper_m3.o
MPY_CROSS_FLAGS += -march=armv7m
endif
@@ -25,7 +25,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 = lib/utils/gchelper_native.o lib/utils/gchelper_m0.o
+SRC_BOARD_O = shared/runtime/gchelper_native.o shared/runtime/gchelper_m0.o
MPY_CROSS_FLAGS += -march=armv7m
endif
@@ -33,7 +33,7 @@ ifeq ($(BOARD),mps2-an385)
CFLAGS += -mthumb -mcpu=cortex-m3 -mfloat-abi=soft
CFLAGS += -DQEMU_SOC_MPS2
LDSCRIPT = mps2.ld
-SRC_BOARD_O = lib/utils/gchelper_native.o lib/utils/gchelper_m3.o
+SRC_BOARD_O = shared/runtime/gchelper_native.o shared/runtime/gchelper_m3.o
MPY_CROSS_FLAGS += -march=armv7m
endif
@@ -42,7 +42,7 @@ CFLAGS += -mcpu=cortex-a9
CFLAGS += -DQEMU_SOC_IMX6
LDSCRIPT = imx6.ld
QEMU_EXTRA = -m 128M
-SRC_BOARD_O = lib/utils/gchelper_generic.o
+SRC_BOARD_O = shared/runtime/gchelper_generic.o
# It's really armv7a but closest supported value is armv6.
MPY_CROSS_FLAGS += -march=armv6
endif
@@ -79,6 +79,8 @@ SRC_COMMON_C = \
uart.c \
moduos.c \
modmachine.c \
+ shared/libc/string0.c \
+ shared/runtime/sys_stdio_mphal.c \
SRC_RUN_C = \
main.c \
@@ -88,7 +90,6 @@ SRC_TEST_C = \
lib/tinytest/tinytest.c \
LIB_SRC_C += $(addprefix lib/,\
- libc/string0.c \
libm/math.c \
libm/fmodf.c \
libm/nearbyintf.c \
@@ -108,7 +109,6 @@ LIB_SRC_C += $(addprefix lib/,\
libm/atanf.c \
libm/atan2f.c \
libm/roundf.c \
- utils/sys_stdio_mphal.c \
)
OBJ_COMMON =
diff --git a/ports/qemu-arm/Makefile.test b/ports/qemu-arm/Makefile.test
index b4ad6114b..e0f3a5416 100644
--- a/ports/qemu-arm/Makefile.test
+++ b/ports/qemu-arm/Makefile.test
@@ -1,4 +1,4 @@
-LIB_SRC_C = lib/upytesthelper/upytesthelper.c
+LIB_SRC_C = shared/upytesthelper/upytesthelper.c
FROZEN_MANIFEST ?= "freeze('test-frzmpy')"
diff --git a/ports/qemu-arm/mpconfigport.h b/ports/qemu-arm/mpconfigport.h
index 1f05719ca..270995979 100644
--- a/ports/qemu-arm/mpconfigport.h
+++ b/ports/qemu-arm/mpconfigport.h
@@ -74,7 +74,7 @@ extern const struct _mp_obj_module_t mp_module_uos;
#include
#ifdef TEST
-#include "lib/upytesthelper/upytesthelper.h"
+#include "shared/upytesthelper/upytesthelper.h"
#undef MP_PLAT_PRINT_STRN
#define MP_PLAT_PRINT_STRN(str, len) upytest_output(str, len)
#endif
diff --git a/ports/qemu-arm/test_main.c b/ports/qemu-arm/test_main.c
index a59a8de0a..284b28731 100644
--- a/ports/qemu-arm/test_main.c
+++ b/ports/qemu-arm/test_main.c
@@ -11,7 +11,7 @@
#include "py/stackctrl.h"
#include "py/gc.h"
#include "py/mperrno.h"
-#include "lib/utils/gchelper.h"
+#include "shared/runtime/gchelper.h"
#include "lib/tinytest/tinytest.h"
#include "lib/tinytest/tinytest_macros.h"
diff --git a/ports/rp2/CMakeLists.txt b/ports/rp2/CMakeLists.txt
index 2d6037712..fd7ec65e0 100644
--- a/ports/rp2/CMakeLists.txt
+++ b/ports/rp2/CMakeLists.txt
@@ -64,16 +64,16 @@ set(MICROPY_SOURCE_LIB
${MICROPY_DIR}/lib/littlefs/lfs1_util.c
${MICROPY_DIR}/lib/littlefs/lfs2.c
${MICROPY_DIR}/lib/littlefs/lfs2_util.c
- ${MICROPY_DIR}/lib/mp-readline/readline.c
${MICROPY_DIR}/lib/oofatfs/ff.c
${MICROPY_DIR}/lib/oofatfs/ffunicode.c
- ${MICROPY_DIR}/lib/timeutils/timeutils.c
- ${MICROPY_DIR}/lib/utils/gchelper_m0.s
- ${MICROPY_DIR}/lib/utils/gchelper_native.c
- ${MICROPY_DIR}/lib/utils/mpirq.c
- ${MICROPY_DIR}/lib/utils/pyexec.c
- ${MICROPY_DIR}/lib/utils/stdout_helpers.c
- ${MICROPY_DIR}/lib/utils/sys_stdio_mphal.c
+ ${MICROPY_DIR}/shared/readline/readline.c
+ ${MICROPY_DIR}/shared/runtime/gchelper_m0.s
+ ${MICROPY_DIR}/shared/runtime/gchelper_native.c
+ ${MICROPY_DIR}/shared/runtime/mpirq.c
+ ${MICROPY_DIR}/shared/runtime/pyexec.c
+ ${MICROPY_DIR}/shared/runtime/stdout_helpers.c
+ ${MICROPY_DIR}/shared/runtime/sys_stdio_mphal.c
+ ${MICROPY_DIR}/shared/timeutils/timeutils.c
)
set(MICROPY_SOURCE_DRIVERS
@@ -108,8 +108,8 @@ set(MICROPY_SOURCE_QSTR
${MICROPY_SOURCE_PY}
${MICROPY_SOURCE_EXTMOD}
${MICROPY_SOURCE_USERMOD}
- ${MICROPY_DIR}/lib/utils/mpirq.c
- ${MICROPY_DIR}/lib/utils/sys_stdio_mphal.c
+ ${MICROPY_DIR}/shared/runtime/mpirq.c
+ ${MICROPY_DIR}/shared/runtime/sys_stdio_mphal.c
${PROJECT_SOURCE_DIR}/machine_adc.c
${PROJECT_SOURCE_DIR}/machine_i2c.c
${PROJECT_SOURCE_DIR}/machine_pin.c
@@ -163,7 +163,9 @@ set(PICO_SDK_COMPONENTS
# Define mpy-cross flags and frozen manifest
set(MICROPY_CROSS_FLAGS -march=armv7m)
-set(MICROPY_FROZEN_MANIFEST ${PROJECT_SOURCE_DIR}/boards/manifest.py)
+if (NOT MICROPY_FROZEN_MANIFEST)
+ set(MICROPY_FROZEN_MANIFEST ${PROJECT_SOURCE_DIR}/boards/manifest.py)
+endif()
target_sources(${MICROPY_TARGET} PRIVATE
${MICROPY_SOURCE_PY}
@@ -188,6 +190,20 @@ target_compile_options(${MICROPY_TARGET} PRIVATE
-Werror
)
+set_source_files_properties(
+ ${PICO_SDK_PATH}/src/rp2_common/pico_double/double_math.c
+ ${PICO_SDK_PATH}/src/rp2_common/pico_float/float_math.c
+ PROPERTIES
+ COMPILE_OPTIONS "-Wno-error=uninitialized"
+)
+
+set_source_files_properties(
+ ${PICO_TINYUSB_PATH}/src/portable/raspberrypi/rp2040/dcd_rp2040.c
+ ${PICO_TINYUSB_PATH}/src/portable/raspberrypi/rp2040/rp2040_usb.c
+ PROPERTIES
+ COMPILE_OPTIONS "-Wno-error=array-bounds;-Wno-error=unused-but-set-variable"
+)
+
target_compile_definitions(${MICROPY_TARGET} PRIVATE
FFCONF_H=\"${MICROPY_OOFATFS_DIR}/ffconf.h\"
LFS1_NO_MALLOC LFS1_NO_DEBUG LFS1_NO_WARN LFS1_NO_ERROR LFS1_NO_ASSERT
@@ -206,6 +222,13 @@ target_link_libraries(${MICROPY_TARGET}
${PICO_SDK_COMPONENTS}
)
+if (MICROPY_HW_ENABLE_DOUBLE_TAP)
+# Enable double tap reset into bootrom.
+target_link_libraries(${MICROPY_TARGET}
+ pico_bootsel_via_double_reset
+)
+endif()
+
# todo this is a bit brittle, but we want to move a few source files into RAM (which requires
# a linker script modification) until we explicitly add macro calls around the function
# defs to move them into RAM.
diff --git a/ports/rp2/Makefile b/ports/rp2/Makefile
index 246f29dd0..2af13bfbb 100644
--- a/ports/rp2/Makefile
+++ b/ports/rp2/Makefile
@@ -20,3 +20,8 @@ all:
clean:
$(RM) -rf $(BUILD)
+
+GIT_SUBMODULES += lib/pico-sdk lib/tinyusb
+
+submodules:
+ $(MAKE) -f ../../py/mkrules.mk GIT_SUBMODULES="$(GIT_SUBMODULES)" submodules
diff --git a/ports/rp2/README.md b/ports/rp2/README.md
index d49550c5c..5836ac0cd 100644
--- a/ports/rp2/README.md
+++ b/ports/rp2/README.md
@@ -29,6 +29,7 @@ Building of the RP2 firmware is done entirely using CMake, although a simple
Makefile is also provided as a convenience. To build the firmware run (from
this directory):
+ $ make submodules
$ make clean
$ make
diff --git a/ports/rp2/boards/ADAFRUIT_FEATHER_RP2040/mpconfigboard.h b/ports/rp2/boards/ADAFRUIT_FEATHER_RP2040/mpconfigboard.h
index 5068d3554..84d2bf20d 100644
--- a/ports/rp2/boards/ADAFRUIT_FEATHER_RP2040/mpconfigboard.h
+++ b/ports/rp2/boards/ADAFRUIT_FEATHER_RP2040/mpconfigboard.h
@@ -1,3 +1,20 @@
-// Board and hardware specific configuration
-#define MICROPY_HW_BOARD_NAME "Adafruit Feather RP2040"
-#define MICROPY_HW_FLASH_STORAGE_BYTES (3072 * 1024)
+// https://www.adafruit.com/product/4884
+// https://learn.adafruit.com/adafruit-feather-rp2040-pico/pinouts
+
+#define MICROPY_HW_BOARD_NAME "Adafruit Feather RP2040"
+#define MICROPY_HW_FLASH_STORAGE_BYTES (7 * 1024 * 1024)
+
+#define MICROPY_HW_USB_VID (0x239A)
+#define MICROPY_HW_USB_PID (0x80F2)
+
+// STEMMA QT / Qwiic on I2C1
+#define MICROPY_HW_I2C1_SCL (3)
+#define MICROPY_HW_I2C1_SDA (2)
+
+#define MICROPY_HW_SPI0_SCK (18)
+#define MICROPY_HW_SPI0_MOSI (19)
+#define MICROPY_HW_SPI0_MISO (20)
+
+// NeoPixel GPIO16, power not toggleable
+
+// Red user LED GPIO13
diff --git a/ports/rp2/boards/ADAFRUIT_ITSYBITSY_RP2040/mpconfigboard.cmake b/ports/rp2/boards/ADAFRUIT_ITSYBITSY_RP2040/mpconfigboard.cmake
new file mode 100644
index 000000000..711e24ed5
--- /dev/null
+++ b/ports/rp2/boards/ADAFRUIT_ITSYBITSY_RP2040/mpconfigboard.cmake
@@ -0,0 +1 @@
+# cmake file for Adafruit ItsyBitsy RP2040
diff --git a/ports/rp2/boards/ADAFRUIT_ITSYBITSY_RP2040/mpconfigboard.h b/ports/rp2/boards/ADAFRUIT_ITSYBITSY_RP2040/mpconfigboard.h
new file mode 100644
index 000000000..8f5551172
--- /dev/null
+++ b/ports/rp2/boards/ADAFRUIT_ITSYBITSY_RP2040/mpconfigboard.h
@@ -0,0 +1,21 @@
+// https://www.adafruit.com/product/4888
+// https://learn.adafruit.com/adafruit-itsybitsy-rp2040/pinouts
+
+#define MICROPY_HW_BOARD_NAME "Adafruit ItsyBitsy RP2040"
+#define MICROPY_HW_FLASH_STORAGE_BYTES (7 * 1024 * 1024)
+
+#define MICROPY_HW_USB_VID (0x239A)
+#define MICROPY_HW_USB_PID (0x80FE)
+
+#define MICROPY_HW_I2C0_SCL (3)
+#define MICROPY_HW_I2C0_SDA (2)
+
+#define MICROPY_HW_SPI0_SCK (18)
+#define MICROPY_HW_SPI0_MOSI (19)
+#define MICROPY_HW_SPI0_MISO (20)
+
+// NeoPixel data GPIO17, power GPIO16
+
+// Red user LED GPIO11
+
+// Boot button GPIO13
diff --git a/ports/rp2/boards/ADAFRUIT_QTPY_RP2040/mpconfigboard.cmake b/ports/rp2/boards/ADAFRUIT_QTPY_RP2040/mpconfigboard.cmake
new file mode 100644
index 000000000..799ced5cd
--- /dev/null
+++ b/ports/rp2/boards/ADAFRUIT_QTPY_RP2040/mpconfigboard.cmake
@@ -0,0 +1 @@
+# cmake file for Adafruit QT Py RP2040
diff --git a/ports/rp2/boards/ADAFRUIT_QTPY_RP2040/mpconfigboard.h b/ports/rp2/boards/ADAFRUIT_QTPY_RP2040/mpconfigboard.h
new file mode 100644
index 000000000..ca341cedd
--- /dev/null
+++ b/ports/rp2/boards/ADAFRUIT_QTPY_RP2040/mpconfigboard.h
@@ -0,0 +1,28 @@
+// https://www.adafruit.com/product/4900
+// https://learn.adafruit.com/adafruit-qt-py-2040/pinouts
+
+#define MICROPY_HW_BOARD_NAME "Adafruit QT Py RP2040"
+#define MICROPY_HW_FLASH_STORAGE_BYTES (7 * 1024 * 1024)
+
+#define MICROPY_HW_USB_VID (0x239A)
+#define MICROPY_HW_USB_PID (0x80F8)
+
+#define MICROPY_HW_UART1_TX (20)
+#define MICROPY_HW_UART1_RX (5)
+#define MICROPY_HW_UART1_CTS (10)
+#define MICROPY_HW_UART1_RTS (7)
+
+#define MICROPY_HW_I2C0_SCL (25)
+#define MICROPY_HW_I2C0_SDA (24)
+
+// STEMMA QT / Qwiic on I2C1
+#define MICROPY_HW_I2C1_SCL (23)
+#define MICROPY_HW_I2C1_SDA (22)
+
+#define MICROPY_HW_SPI0_SCK (6)
+#define MICROPY_HW_SPI0_MOSI (3)
+#define MICROPY_HW_SPI0_MISO (4)
+
+// NeoPixel data GPIO12, power GPIO11
+
+// Boot button GPIO21
diff --git a/ports/rp2/boards/PIMORONI_PICOLIPO_16MB/mpconfigboard.cmake b/ports/rp2/boards/PIMORONI_PICOLIPO_16MB/mpconfigboard.cmake
new file mode 100644
index 000000000..b98ff4495
--- /dev/null
+++ b/ports/rp2/boards/PIMORONI_PICOLIPO_16MB/mpconfigboard.cmake
@@ -0,0 +1 @@
+# cmake file for Pimoroni Pico LiPo 16MB
diff --git a/ports/rp2/boards/PIMORONI_PICOLIPO_16MB/mpconfigboard.h b/ports/rp2/boards/PIMORONI_PICOLIPO_16MB/mpconfigboard.h
new file mode 100644
index 000000000..68478f761
--- /dev/null
+++ b/ports/rp2/boards/PIMORONI_PICOLIPO_16MB/mpconfigboard.h
@@ -0,0 +1,28 @@
+// https://shop.pimoroni.com/products/pimoroni-pico-lipo?variant=39335427080275
+
+#define MICROPY_HW_BOARD_NAME "Pimoroni Pico LiPo 16MB"
+#define MICROPY_HW_FLASH_STORAGE_BYTES (7 * 1024 * 1024)
+
+#define MICROPY_HW_USB_VID (0x2E8A)
+#define MICROPY_HW_USB_PID (0x1003)
+
+#define MICROPY_HW_UART1_TX (8)
+#define MICROPY_HW_UART1_RX (9)
+#define MICROPY_HW_UART1_CTS (10)
+#define MICROPY_HW_UART1_RTS (11)
+
+// Qwiic on I2C0
+#define MICROPY_HW_I2C0_SCL (4)
+#define MICROPY_HW_I2C0_SDA (5)
+
+#define MICROPY_HW_SPI0_SCK (18)
+#define MICROPY_HW_SPI0_MOSI (19)
+#define MICROPY_HW_SPI0_MISO (16)
+
+// User LED GPIO25
+
+// VBUS_SENSE GPIO24
+
+// BAT_SENSE GPIO29
+
+// Boot button GPIO23
diff --git a/ports/rp2/boards/PIMORONI_PICOLIPO_4MB/mpconfigboard.cmake b/ports/rp2/boards/PIMORONI_PICOLIPO_4MB/mpconfigboard.cmake
new file mode 100644
index 000000000..8da827a17
--- /dev/null
+++ b/ports/rp2/boards/PIMORONI_PICOLIPO_4MB/mpconfigboard.cmake
@@ -0,0 +1 @@
+# cmake file for Pimoroni Pico LiPo 4MB
diff --git a/ports/rp2/boards/PIMORONI_PICOLIPO_4MB/mpconfigboard.h b/ports/rp2/boards/PIMORONI_PICOLIPO_4MB/mpconfigboard.h
new file mode 100644
index 000000000..fd45547e1
--- /dev/null
+++ b/ports/rp2/boards/PIMORONI_PICOLIPO_4MB/mpconfigboard.h
@@ -0,0 +1,28 @@
+// https://shop.pimoroni.com/products/pimoroni-pico-lipo?variant=39386149093459
+
+#define MICROPY_HW_BOARD_NAME "Pimoroni Pico LiPo 4MB"
+#define MICROPY_HW_FLASH_STORAGE_BYTES (3 * 1024 * 1024)
+
+#define MICROPY_HW_USB_VID (0x2E8A)
+#define MICROPY_HW_USB_PID (0x1002)
+
+#define MICROPY_HW_UART1_TX (8)
+#define MICROPY_HW_UART1_RX (9)
+#define MICROPY_HW_UART1_CTS (10)
+#define MICROPY_HW_UART1_RTS (11)
+
+// Qwiic on I2C0
+#define MICROPY_HW_I2C0_SCL (4)
+#define MICROPY_HW_I2C0_SDA (5)
+
+#define MICROPY_HW_SPI0_SCK (18)
+#define MICROPY_HW_SPI0_MOSI (19)
+#define MICROPY_HW_SPI0_MISO (16)
+
+// User LED GPIO25
+
+// VBUS_SENSE GPIO24
+
+// BAT_SENSE GPIO29
+
+// Boot button GPIO23
diff --git a/ports/rp2/boards/PIMORONI_TINY2040/mpconfigboard.cmake b/ports/rp2/boards/PIMORONI_TINY2040/mpconfigboard.cmake
new file mode 100644
index 000000000..b6c4b3efc
--- /dev/null
+++ b/ports/rp2/boards/PIMORONI_TINY2040/mpconfigboard.cmake
@@ -0,0 +1 @@
+# cmake file for Pimoroni Tiny 2040
diff --git a/ports/rp2/boards/PIMORONI_TINY2040/mpconfigboard.h b/ports/rp2/boards/PIMORONI_TINY2040/mpconfigboard.h
new file mode 100644
index 000000000..50cb2bd59
--- /dev/null
+++ b/ports/rp2/boards/PIMORONI_TINY2040/mpconfigboard.h
@@ -0,0 +1,17 @@
+// https://shop.pimoroni.com/products/tiny-2040
+
+#define MICROPY_HW_BOARD_NAME "Pimoroni Tiny 2040"
+#define MICROPY_HW_FLASH_STORAGE_BYTES (7 * 1024 * 1024)
+
+#define MICROPY_HW_USB_VID (0x16D0)
+#define MICROPY_HW_USB_PID (0x08C7)
+
+#define MICROPY_HW_I2C0_SCL (4)
+#define MICROPY_HW_I2C0_SDA (5)
+
+// RGB LED, active low
+// Red LED 18
+// Green LED 19
+// Blue LED 20
+
+// Boot button GPIO23
diff --git a/ports/rp2/boards/SPARKFUN_PROMICRO/mpconfigboard.h b/ports/rp2/boards/SPARKFUN_PROMICRO/mpconfigboard.h
index d6c8007ba..65b29eecd 100644
--- a/ports/rp2/boards/SPARKFUN_PROMICRO/mpconfigboard.h
+++ b/ports/rp2/boards/SPARKFUN_PROMICRO/mpconfigboard.h
@@ -1,3 +1,22 @@
-// Board and hardware specific configuration
-#define MICROPY_HW_BOARD_NAME "SparkFun Pro Micro RP2040"
-#define MICROPY_HW_FLASH_STORAGE_BYTES (15 * 1024 * 1024)
+// https://www.sparkfun.com/products/17717
+
+#define MICROPY_HW_BOARD_NAME "SparkFun Pro Micro RP2040"
+#define MICROPY_HW_FLASH_STORAGE_BYTES (15 * 1024 * 1024)
+
+#define MICROPY_HW_USB_VID (0x1B4F)
+#define MICROPY_HW_USB_PID (0x0026)
+
+#define MICROPY_HW_UART1_TX (8)
+#define MICROPY_HW_UART1_RX (9)
+#define MICROPY_HW_UART1_CTS (10)
+#define MICROPY_HW_UART1_RTS (11)
+
+// Qwiic on I2C0
+#define MICROPY_HW_I2C0_SCL (17)
+#define MICROPY_HW_I2C0_SDA (16)
+
+#define MICROPY_HW_SPI0_SCK (22)
+#define MICROPY_HW_SPI0_MOSI (23)
+#define MICROPY_HW_SPI0_MISO (20)
+
+// NeoPixel data GPIO25, power not toggleable
diff --git a/ports/rp2/boards/SPARKFUN_THINGPLUS/mpconfigboard.h b/ports/rp2/boards/SPARKFUN_THINGPLUS/mpconfigboard.h
index 9749acd25..f88ba5dd6 100644
--- a/ports/rp2/boards/SPARKFUN_THINGPLUS/mpconfigboard.h
+++ b/ports/rp2/boards/SPARKFUN_THINGPLUS/mpconfigboard.h
@@ -1,3 +1,31 @@
-// Board and hardware specific configuration
-#define MICROPY_HW_BOARD_NAME "SparkFun Thing Plus RP2040"
-#define MICROPY_HW_FLASH_STORAGE_BYTES (15 * 1024 * 1024)
+// https://www.sparkfun.com/products/17745
+
+#define MICROPY_HW_BOARD_NAME "SparkFun Thing Plus RP2040"
+#define MICROPY_HW_FLASH_STORAGE_BYTES (15 * 1024 * 1024)
+
+#define MICROPY_HW_USB_VID (0x1B4F)
+#define MICROPY_HW_USB_PID (0x0025)
+
+#define MICROPY_HW_I2C0_SCL (17)
+#define MICROPY_HW_I2C0_SDA (16)
+
+// Qwiic on I2C1
+#define MICROPY_HW_I2C1_SCL (7)
+#define MICROPY_HW_I2C1_SDA (6)
+
+#define MICROPY_HW_SPI0_SCK (2)
+#define MICROPY_HW_SPI0_MOSI (3)
+#define MICROPY_HW_SPI0_MISO (4)
+
+// MicroSD on SPI1
+#define MICROPY_HW_SPI1_SCK (14)
+#define MICROPY_HW_SPI1_MOSI (15)
+#define MICROPY_HW_SPI1_MISO (12)
+
+// Battery fuel guage MAX17048 on I2C1
+// BATT_ALERT GPIO24
+
+// NeoPixel data GPIO8, power not toggleable
+// data out is broken out to a pin
+
+// Blue user LED GPIO25
diff --git a/ports/rp2/machine_i2c.c b/ports/rp2/machine_i2c.c
index 0852cc199..3b895ba4d 100644
--- a/ports/rp2/machine_i2c.c
+++ b/ports/rp2/machine_i2c.c
@@ -33,10 +33,16 @@
#include "hardware/i2c.h"
#define DEFAULT_I2C_FREQ (400000)
-#define DEFAULT_I2C0_SCL (9)
-#define DEFAULT_I2C0_SDA (8)
-#define DEFAULT_I2C1_SCL (7)
-#define DEFAULT_I2C1_SDA (6)
+
+#ifndef MICROPY_HW_I2C0_SCL
+#define MICROPY_HW_I2C0_SCL (9)
+#define MICROPY_HW_I2C0_SDA (8)
+#endif
+
+#ifndef MICROPY_HW_I2C1_SCL
+#define MICROPY_HW_I2C1_SCL (7)
+#define MICROPY_HW_I2C1_SDA (6)
+#endif
// SDA/SCL on even/odd pins, I2C0/I2C1 on even/odd pairs of pins.
#define IS_VALID_SCL(i2c, pin) (((pin) & 1) == 1 && (((pin) & 2) >> 1) == (i2c))
@@ -52,8 +58,8 @@ typedef struct _machine_i2c_obj_t {
} machine_i2c_obj_t;
STATIC machine_i2c_obj_t machine_i2c_obj[] = {
- {{&machine_hw_i2c_type}, i2c0, 0, DEFAULT_I2C0_SCL, DEFAULT_I2C0_SDA, 0},
- {{&machine_hw_i2c_type}, i2c1, 1, DEFAULT_I2C1_SCL, DEFAULT_I2C1_SDA, 0},
+ {{&machine_hw_i2c_type}, i2c0, 0, MICROPY_HW_I2C0_SCL, MICROPY_HW_I2C0_SDA, 0},
+ {{&machine_hw_i2c_type}, i2c1, 1, MICROPY_HW_I2C1_SCL, MICROPY_HW_I2C1_SDA, 0},
};
STATIC void machine_i2c_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
diff --git a/ports/rp2/machine_pin.c b/ports/rp2/machine_pin.c
index 0525e0f9f..aa3cad6ef 100644
--- a/ports/rp2/machine_pin.c
+++ b/ports/rp2/machine_pin.c
@@ -29,7 +29,7 @@
#include "py/runtime.h"
#include "py/mphal.h"
-#include "lib/utils/mpirq.h"
+#include "shared/runtime/mpirq.h"
#include "modmachine.h"
#include "extmod/virtpin.h"
diff --git a/ports/rp2/machine_rtc.c b/ports/rp2/machine_rtc.c
index a7c55b616..9d59124a6 100644
--- a/ports/rp2/machine_rtc.c
+++ b/ports/rp2/machine_rtc.c
@@ -35,7 +35,7 @@
#include "py/runtime.h"
#include "py/mphal.h"
#include "py/mperrno.h"
-#include "lib/timeutils/timeutils.h"
+#include "shared/timeutils/timeutils.h"
#include "hardware/rtc.h"
#include "pico/util/datetime.h"
#include "modmachine.h"
diff --git a/ports/rp2/machine_spi.c b/ports/rp2/machine_spi.c
index 478c06145..332f44694 100644
--- a/ports/rp2/machine_spi.c
+++ b/ports/rp2/machine_spi.c
@@ -38,12 +38,18 @@
#define DEFAULT_SPI_PHASE (0)
#define DEFAULT_SPI_BITS (8)
#define DEFAULT_SPI_FIRSTBIT (SPI_MSB_FIRST)
-#define DEFAULT_SPI0_SCK (6)
-#define DEFAULT_SPI0_MOSI (7)
-#define DEFAULT_SPI0_MISO (4)
-#define DEFAULT_SPI1_SCK (10)
-#define DEFAULT_SPI1_MOSI (11)
-#define DEFAULT_SPI1_MISO (8)
+
+#ifndef MICROPY_HW_SPI0_SCK
+#define MICROPY_HW_SPI0_SCK (6)
+#define MICROPY_HW_SPI0_MOSI (7)
+#define MICROPY_HW_SPI0_MISO (4)
+#endif
+
+#ifndef MICROPY_HW_SPI1_SCK
+#define MICROPY_HW_SPI1_SCK (10)
+#define MICROPY_HW_SPI1_MOSI (11)
+#define MICROPY_HW_SPI1_MISO (8)
+#endif
#define IS_VALID_PERIPH(spi, pin) ((((pin) & 8) >> 3) == (spi))
#define IS_VALID_SCK(spi, pin) (((pin) & 3) == 2 && IS_VALID_PERIPH(spi, pin))
@@ -68,13 +74,13 @@ STATIC machine_spi_obj_t machine_spi_obj[] = {
{
{&machine_spi_type}, spi0, 0,
DEFAULT_SPI_POLARITY, DEFAULT_SPI_PHASE, DEFAULT_SPI_BITS, DEFAULT_SPI_FIRSTBIT,
- DEFAULT_SPI0_SCK, DEFAULT_SPI0_MOSI, DEFAULT_SPI0_MISO,
+ MICROPY_HW_SPI0_SCK, MICROPY_HW_SPI0_MOSI, MICROPY_HW_SPI0_MISO,
0,
},
{
{&machine_spi_type}, spi1, 1,
DEFAULT_SPI_POLARITY, DEFAULT_SPI_PHASE, DEFAULT_SPI_BITS, DEFAULT_SPI_FIRSTBIT,
- DEFAULT_SPI1_SCK, DEFAULT_SPI1_MOSI, DEFAULT_SPI1_MISO,
+ MICROPY_HW_SPI1_SCK, MICROPY_HW_SPI1_MOSI, MICROPY_HW_SPI1_MISO,
0,
},
};
diff --git a/ports/rp2/machine_uart.c b/ports/rp2/machine_uart.c
index 2da3ab41f..a8ec149f4 100644
--- a/ports/rp2/machine_uart.c
+++ b/ports/rp2/machine_uart.c
@@ -38,10 +38,23 @@
#define DEFAULT_UART_BAUDRATE (115200)
#define DEFAULT_UART_BITS (8)
#define DEFAULT_UART_STOP (1)
-#define DEFAULT_UART0_TX (0)
-#define DEFAULT_UART0_RX (1)
-#define DEFAULT_UART1_TX (4)
-#define DEFAULT_UART1_RX (5)
+
+// UART 0 default pins
+#if !defined(MICROPY_HW_UART0_TX)
+#define MICROPY_HW_UART0_TX (0)
+#define MICROPY_HW_UART0_RX (1)
+#define MICROPY_HW_UART0_CTS (2)
+#define MICROPY_HW_UART0_RTS (3)
+#endif
+
+// UART 1 default pins
+#if !defined(MICROPY_HW_UART1_TX)
+#define MICROPY_HW_UART1_TX (4)
+#define MICROPY_HW_UART1_RX (5)
+#define MICROPY_HW_UART1_CTS (6)
+#define MICROPY_HW_UART1_RTS (7)
+#endif
+
#define DEFAULT_BUFFER_SIZE (256)
#define MIN_BUFFER_SIZE (32)
#define MAX_BUFFER_SIZE (32766)
@@ -49,11 +62,16 @@
#define IS_VALID_PERIPH(uart, pin) (((((pin) + 4) & 8) >> 3) == (uart))
#define IS_VALID_TX(uart, pin) (((pin) & 3) == 0 && IS_VALID_PERIPH(uart, pin))
#define IS_VALID_RX(uart, pin) (((pin) & 3) == 1 && IS_VALID_PERIPH(uart, pin))
+#define IS_VALID_CTS(uart, pin) (((pin) & 3) == 2 && IS_VALID_PERIPH(uart, pin))
+#define IS_VALID_RTS(uart, pin) (((pin) & 3) == 3 && IS_VALID_PERIPH(uart, pin))
#define UART_INVERT_TX (1)
#define UART_INVERT_RX (2)
#define UART_INVERT_MASK (UART_INVERT_TX | UART_INVERT_RX)
+#define UART_HWCONTROL_CTS (1)
+#define UART_HWCONTROL_RTS (2)
+
typedef struct _machine_uart_obj_t {
mp_obj_base_t base;
uart_inst_t *const uart;
@@ -64,9 +82,12 @@ typedef struct _machine_uart_obj_t {
uint8_t stop;
uint8_t tx;
uint8_t rx;
+ uint8_t cts;
+ uint8_t rts;
uint16_t timeout; // timeout waiting for first char (in ms)
uint16_t timeout_char; // timeout waiting between chars (in ms)
uint8_t invert;
+ uint8_t flow;
ringbuf_t read_buffer;
bool read_lock;
ringbuf_t write_buffer;
@@ -75,9 +96,11 @@ typedef struct _machine_uart_obj_t {
STATIC machine_uart_obj_t machine_uart_obj[] = {
{{&machine_uart_type}, uart0, 0, 0, DEFAULT_UART_BITS, UART_PARITY_NONE, DEFAULT_UART_STOP,
- DEFAULT_UART0_TX, DEFAULT_UART0_RX, 0, 0, 0, {NULL, 1, 0, 0}, 0, {NULL, 1, 0, 0}, 0},
+ MICROPY_HW_UART0_TX, MICROPY_HW_UART0_RX, MICROPY_HW_UART0_CTS, MICROPY_HW_UART0_RTS,
+ 0, 0, 0, 0, {NULL, 1, 0, 0}, 0, {NULL, 1, 0, 0}, 0},
{{&machine_uart_type}, uart1, 1, 0, DEFAULT_UART_BITS, UART_PARITY_NONE, DEFAULT_UART_STOP,
- DEFAULT_UART1_TX, DEFAULT_UART1_RX, 0, 0, 0, {NULL, 1, 0, 0}, 0, {NULL, 1, 0, 0}, 0,},
+ MICROPY_HW_UART1_TX, MICROPY_HW_UART1_RX, MICROPY_HW_UART1_CTS, MICROPY_HW_UART1_RTS,
+ 0, 0, 0, 0, {NULL, 1, 0, 0}, 0, {NULL, 1, 0, 0}, 0},
};
STATIC const char *_parity_name[] = {"None", "0", "1"};
@@ -140,8 +163,8 @@ STATIC void machine_uart_print(const mp_print_t *print, mp_obj_t self_in, mp_pri
}
STATIC mp_obj_t machine_uart_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
- enum { ARG_id, ARG_baudrate, ARG_bits, ARG_parity, ARG_stop, ARG_tx, ARG_rx,
- ARG_timeout, ARG_timeout_char, ARG_invert, ARG_txbuf, ARG_rxbuf};
+ enum { ARG_id, ARG_baudrate, ARG_bits, ARG_parity, ARG_stop, ARG_tx, ARG_rx, ARG_cts, ARG_rts,
+ ARG_timeout, ARG_timeout_char, ARG_invert, ARG_flow, ARG_txbuf, ARG_rxbuf};
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_id, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
{ MP_QSTR_baudrate, MP_ARG_INT, {.u_int = -1} },
@@ -150,9 +173,12 @@ STATIC mp_obj_t machine_uart_make_new(const mp_obj_type_t *type, size_t n_args,
{ MP_QSTR_stop, MP_ARG_INT, {.u_int = -1} },
{ MP_QSTR_tx, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
{ MP_QSTR_rx, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
+ { MP_QSTR_cts, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
+ { MP_QSTR_rts, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
{ MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
{ MP_QSTR_timeout_char, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
{ MP_QSTR_invert, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
+ { MP_QSTR_flow, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
{ MP_QSTR_txbuf, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
{ MP_QSTR_rxbuf, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
};
@@ -212,6 +238,22 @@ STATIC mp_obj_t machine_uart_make_new(const mp_obj_type_t *type, size_t n_args,
self->rx = rx;
}
+ // Set CTS/RTS pins if configured.
+ if (args[ARG_cts].u_obj != mp_const_none) {
+ int cts = mp_hal_get_pin_obj(args[ARG_cts].u_obj);
+ if (!IS_VALID_CTS(self->uart_id, cts)) {
+ mp_raise_ValueError(MP_ERROR_TEXT("bad CTS pin"));
+ }
+ self->cts = cts;
+ }
+ if (args[ARG_rts].u_obj != mp_const_none) {
+ int rts = mp_hal_get_pin_obj(args[ARG_rts].u_obj);
+ if (!IS_VALID_RTS(self->uart_id, rts)) {
+ mp_raise_ValueError(MP_ERROR_TEXT("bad RTS pin"));
+ }
+ self->rts = rts;
+ }
+
// Set timeout if configured.
if (args[ARG_timeout].u_int >= 0) {
self->timeout = args[ARG_timeout].u_int;
@@ -230,6 +272,14 @@ STATIC mp_obj_t machine_uart_make_new(const mp_obj_type_t *type, size_t n_args,
self->invert = args[ARG_invert].u_int;
}
+ // Set hardware flow control if configured.
+ if (args[ARG_flow].u_int >= 0) {
+ if (args[ARG_flow].u_int & ~(UART_HWCONTROL_CTS | UART_HWCONTROL_RTS)) {
+ mp_raise_ValueError(MP_ERROR_TEXT("bad hardware flow control mask"));
+ }
+ self->flow = args[ARG_flow].u_int;
+ }
+
self->read_lock = false;
// Set the RX buffer size if configured.
@@ -278,6 +328,15 @@ STATIC mp_obj_t machine_uart_make_new(const mp_obj_type_t *type, size_t n_args,
gpio_set_outover(self->tx, GPIO_OVERRIDE_INVERT);
}
+ // Set hardware flow control if configured.
+ if (self->flow & UART_HWCONTROL_CTS) {
+ gpio_set_function(self->cts, GPIO_FUNC_UART);
+ }
+ if (self->flow & UART_HWCONTROL_RTS) {
+ gpio_set_function(self->rts, GPIO_FUNC_UART);
+ }
+ uart_set_hw_flow(self->uart, self->flow & UART_HWCONTROL_CTS, self->flow & UART_HWCONTROL_RTS);
+
// Allocate the RX/TX buffers.
ringbuf_alloc(&(self->read_buffer), rxbuf_len + 1);
MP_STATE_PORT(rp2_uart_rx_buffer[uart_id]) = self->read_buffer.buf;
@@ -333,6 +392,9 @@ STATIC const mp_rom_map_elem_t machine_uart_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_INV_TX), MP_ROM_INT(UART_INVERT_TX) },
{ MP_ROM_QSTR(MP_QSTR_INV_RX), MP_ROM_INT(UART_INVERT_RX) },
+ { MP_ROM_QSTR(MP_QSTR_CTS), MP_ROM_INT(UART_HWCONTROL_CTS) },
+ { MP_ROM_QSTR(MP_QSTR_RTS), MP_ROM_INT(UART_HWCONTROL_RTS) },
+
};
STATIC MP_DEFINE_CONST_DICT(machine_uart_locals_dict, machine_uart_locals_dict_table);
@@ -345,6 +407,13 @@ STATIC mp_uint_t machine_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t siz
for (size_t i = 0; i < size; i++) {
// Wait for the first/next character
while (ringbuf_avail(&self->read_buffer) == 0) {
+ if (uart_is_readable(self->uart)) {
+ // Force a few incoming bytes to the buffer
+ self->read_lock = true;
+ uart_drain_rx_fifo(self);
+ self->read_lock = false;
+ break;
+ }
if (time_us_64() > t) { // timed out
if (i <= 0) {
*errcode = MP_EAGAIN;
@@ -354,10 +423,6 @@ STATIC mp_uint_t machine_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t siz
}
}
MICROPY_EVENT_POLL_HOOK
- // Force a few incoming bytes to the buffer
- self->read_lock = true;
- uart_drain_rx_fifo(self);
- self->read_lock = false;
}
*dest++ = ringbuf_get(&(self->read_buffer));
t = time_us_64() + timeout_char_us;
@@ -415,7 +480,7 @@ STATIC mp_uint_t machine_uart_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint
if (request == MP_STREAM_POLL) {
uintptr_t flags = arg;
ret = 0;
- if ((flags & MP_STREAM_POLL_RD) && ringbuf_avail(&self->read_buffer) > 0) {
+ if ((flags & MP_STREAM_POLL_RD) && (uart_is_readable(self->uart) || ringbuf_avail(&self->read_buffer) > 0)) {
ret |= MP_STREAM_POLL_RD;
}
if ((flags & MP_STREAM_POLL_WR) && ringbuf_free(&self->write_buffer) > 0) {
diff --git a/ports/rp2/main.c b/ports/rp2/main.c
index 8c5772171..d0b89c8d6 100644
--- a/ports/rp2/main.c
+++ b/ports/rp2/main.c
@@ -32,9 +32,9 @@
#include "py/mperrno.h"
#include "py/mphal.h"
#include "py/stackctrl.h"
-#include "lib/mp-readline/readline.h"
-#include "lib/utils/gchelper.h"
-#include "lib/utils/pyexec.h"
+#include "shared/readline/readline.h"
+#include "shared/runtime/gchelper.h"
+#include "shared/runtime/pyexec.h"
#include "tusb.h"
#include "uart.h"
#include "modmachine.h"
@@ -227,4 +227,3 @@ const char rp2_help_text[] =
"For further help on a specific object, type help(obj)\n"
"For a list of available modules, type help('modules')\n"
;
-
diff --git a/ports/rp2/modmachine.c b/ports/rp2/modmachine.c
index 3656a7db5..1b2b2adad 100644
--- a/ports/rp2/modmachine.c
+++ b/ports/rp2/modmachine.c
@@ -26,7 +26,7 @@
#include "py/runtime.h"
#include "py/mphal.h"
-#include "lib/utils/pyexec.h"
+#include "shared/runtime/pyexec.h"
#include "extmod/machine_i2c.h"
#include "extmod/machine_mem.h"
#include "extmod/machine_pulse.h"
diff --git a/ports/rp2/modutime.c b/ports/rp2/modutime.c
index 4835a0ee1..8041ae65b 100644
--- a/ports/rp2/modutime.c
+++ b/ports/rp2/modutime.c
@@ -25,7 +25,7 @@
*/
#include "py/runtime.h"
-#include "lib/timeutils/timeutils.h"
+#include "shared/timeutils/timeutils.h"
#include "extmod/utime_mphal.h"
#include "hardware/rtc.h"
diff --git a/ports/rp2/mpconfigport.h b/ports/rp2/mpconfigport.h
index 85015f3ab..f95d6a470 100644
--- a/ports/rp2/mpconfigport.h
+++ b/ports/rp2/mpconfigport.h
@@ -77,6 +77,7 @@
#define MICROPY_PY_FUNCTION_ATTRS (1)
#define MICROPY_PY_DESCRIPTORS (1)
#define MICROPY_PY_DELATTR_SETATTR (1)
+#define MICROPY_PY_FSTRINGS (1)
#define MICROPY_PY_BUILTINS_STR_UNICODE (1)
#define MICROPY_PY_BUILTINS_STR_CENTER (1)
#define MICROPY_PY_BUILTINS_STR_PARTITION (1)
@@ -203,6 +204,10 @@ extern const struct _mp_obj_module_t mp_module_lodepng;
#define LV_ROOTS
#endif
+#ifndef MICROPY_BOARD_ROOT_POINTERS
+#define MICROPY_BOARD_ROOT_POINTERS
+#endif
+
#define MICROPY_PORT_ROOT_POINTERS \
LV_ROOTS \
void *mp_lv_user_data; \
@@ -212,6 +217,7 @@ extern const struct _mp_obj_module_t mp_module_lodepng;
void *rp2_state_machine_irq_obj[8]; \
void *rp2_uart_rx_buffer[2]; \
void *rp2_uart_tx_buffer[2]; \
+ MICROPY_BOARD_ROOT_POINTERS \
#define MP_STATE_PORT MP_STATE_VM
diff --git a/ports/rp2/mphalport.c b/ports/rp2/mphalport.c
index 1d77bc8f5..3385323db 100644
--- a/ports/rp2/mphalport.c
+++ b/ports/rp2/mphalport.c
@@ -27,7 +27,7 @@
#include "py/runtime.h"
#include "py/stream.h"
#include "py/mphal.h"
-#include "lib/timeutils/timeutils.h"
+#include "shared/timeutils/timeutils.h"
#include "tusb.h"
#include "uart.h"
#include "hardware/rtc.h"
diff --git a/ports/rp2/rp2_flash.c b/ports/rp2/rp2_flash.c
index b89cb6fd8..80bc1dc1d 100644
--- a/ports/rp2/rp2_flash.c
+++ b/ports/rp2/rp2_flash.c
@@ -95,12 +95,20 @@ STATIC mp_obj_t rp2_flash_writeblocks(size_t n_args, const mp_obj_t *args) {
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(args[2], &bufinfo, MP_BUFFER_READ);
if (n_args == 3) {
+ // Flash erase/program must run in an atomic section because the XIP bit gets disabled.
+ 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
// TODO check return value
} else {
offset += mp_obj_get_int(args[3]);
}
+ // Flash erase/program must run in an atomic section because the XIP bit gets disabled.
+ 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
// TODO check return value
return mp_const_none;
}
@@ -122,7 +130,10 @@ STATIC mp_obj_t rp2_flash_ioctl(mp_obj_t self_in, mp_obj_t cmd_in, mp_obj_t arg_
return MP_OBJ_NEW_SMALL_INT(BLOCK_SIZE_BYTES);
case MP_BLOCKDEV_IOCTL_BLOCK_ERASE: {
uint32_t offset = mp_obj_get_int(arg_in) * BLOCK_SIZE_BYTES;
+ // Flash erase/program must run in an atomic section because the XIP bit gets disabled.
+ mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION();
flash_range_erase(self->flash_base + offset, BLOCK_SIZE_BYTES);
+ MICROPY_END_ATOMIC_SECTION(atomic_state);
// TODO check return value
return MP_OBJ_NEW_SMALL_INT(0);
}
diff --git a/ports/rp2/rp2_pio.c b/ports/rp2/rp2_pio.c
index 44928c0a8..414fa8bd7 100644
--- a/ports/rp2/rp2_pio.c
+++ b/ports/rp2/rp2_pio.c
@@ -30,7 +30,7 @@
#include "py/runtime.h"
#include "py/mperrno.h"
#include "py/mphal.h"
-#include "lib/utils/mpirq.h"
+#include "shared/runtime/mpirq.h"
#include "modrp2.h"
#include "hardware/clocks.h"
diff --git a/ports/rp2/tusb_config.h b/ports/rp2/tusb_config.h
index 1402edf37..8c2a9f756 100644
--- a/ports/rp2/tusb_config.h
+++ b/ports/rp2/tusb_config.h
@@ -28,6 +28,7 @@
#define CFG_TUSB_RHPORT0_MODE (OPT_MODE_DEVICE)
#define CFG_TUD_CDC (1)
+#define CFG_TUD_CDC_EP_BUFSIZE (256)
#define CFG_TUD_CDC_RX_BUFSIZE (256)
#define CFG_TUD_CDC_TX_BUFSIZE (256)
diff --git a/ports/rp2/tusb_port.c b/ports/rp2/tusb_port.c
index 874d837b9..8896be907 100644
--- a/ports/rp2/tusb_port.c
+++ b/ports/rp2/tusb_port.c
@@ -27,8 +27,12 @@
#include "tusb.h"
#include "pico/unique_id.h"
-#define USBD_VID (0x2E8A) // Raspberry Pi
-#define USBD_PID (0x0005) // RP2 MicroPython
+#ifndef MICROPY_HW_USB_VID
+#define MICROPY_HW_USB_VID (0x2E8A) // Raspberry Pi
+#endif
+#ifndef MICROPY_HW_USB_PID
+#define MICROPY_HW_USB_PID (0x0005) // RP2 MicroPython
+#endif
#define USBD_DESC_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN)
#define USBD_MAX_POWER_MA (250)
@@ -58,8 +62,8 @@ static const tusb_desc_device_t usbd_desc_device = {
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
.bDeviceProtocol = MISC_PROTOCOL_IAD,
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
- .idVendor = USBD_VID,
- .idProduct = USBD_PID,
+ .idVendor = MICROPY_HW_USB_VID,
+ .idProduct = MICROPY_HW_USB_PID,
.bcdDevice = 0x0100,
.iManufacturer = USBD_STR_MANUF,
.iProduct = USBD_STR_PRODUCT,
diff --git a/ports/samd/Makefile b/ports/samd/Makefile
index ffd0f06a3..a84fc3b12 100644
--- a/ports/samd/Makefile
+++ b/ports/samd/Makefile
@@ -33,7 +33,11 @@ CFLAGS_MCU_SAMD21 = -mtune=cortex-m0plus -mcpu=cortex-m0plus -msoft-float
CFLAGS_MCU_SAMD51 = -mtune=cortex-m4 -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard
CFLAGS = $(INC) -Wall -Werror -std=c99 -nostdlib -mthumb $(CFLAGS_MCU_$(MCU_SERIES)) -fsingle-precision-constant -Wdouble-promotion
CFLAGS += -DMCU_$(MCU_SERIES) -D__$(CMSIS_MCU)__
+CFLAGS += $(CFLAGS_MOD)
+
LDFLAGS = -nostdlib $(addprefix -T,$(LD_FILES)) -Map=$@.map --cref
+LDFLAGS += $(LDFLAGS_MOD)
+
LIBS = $(shell $(CC) $(CFLAGS) -print-libgcc-file-name)
# Tune for Debugging or Optimization
@@ -45,6 +49,14 @@ LDFLAGS += --gc-sections
CFLAGS += -fdata-sections -ffunction-sections
endif
+# Flags for optional C++ source code
+CXXFLAGS += $(filter-out -std=c99,$(CFLAGS))
+CXXFLAGS += $(CXXFLAGS_MOD)
+ifneq ($(SRC_CXX)$(SRC_MOD_CXX),)
+LIBSTDCPP_FILE_NAME = "$(shell $(CXX) $(CXXFLAGS) -print-file-name=libstdc++.a)"
+LDFLAGS += -L"$(shell dirname $(LIBSTDCPP_FILE_NAME))"
+endif
+
SRC_C = \
main.c \
modutime.c \
@@ -53,34 +65,39 @@ SRC_C = \
samd_isr.c \
samd_soc.c \
tusb_port.c \
- lib/libc/string0.c \
lib/libm/ef_sqrt.c \
lib/libm/fmodf.c \
lib/libm/math.c \
lib/libm/nearbyintf.c \
- lib/mp-readline/readline.c \
lib/tinyusb/src/class/cdc/cdc_device.c \
lib/tinyusb/src/common/tusb_fifo.c \
lib/tinyusb/src/device/usbd.c \
lib/tinyusb/src/device/usbd_control.c \
lib/tinyusb/src/portable/microchip/samd/dcd_samd.c \
lib/tinyusb/src/tusb.c \
- lib/utils/gchelper_native.c \
- lib/utils/printf.c \
- lib/utils/pyexec.c \
- lib/utils/stdout_helpers.c \
+ shared/libc/printf.c \
+ shared/libc/string0.c \
+ shared/readline/readline.c \
+ shared/runtime/gchelper_native.c \
+ shared/runtime/pyexec.c \
+ shared/runtime/stdout_helpers.c \
+
+SRC_C += $(SRC_MOD)
+
+SRC_CXX += $(SRC_MOD_CXX)
ifeq ($(MCU_SERIES),SAMD21)
-SRC_S = lib/utils/gchelper_m0.s
+SRC_S = shared/runtime/gchelper_m0.s
else
-SRC_S = lib/utils/gchelper_m3.s
+SRC_S = shared/runtime/gchelper_m3.s
endif
# List of sources for qstr extraction
-SRC_QSTR += modutime.c modmachine.c
+SRC_QSTR += modutime.c modmachine.c $(SRC_MOD) $(SRC_CXX)
OBJ += $(PY_O)
OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o))
+OBJ += $(addprefix $(BUILD)/, $(SRC_CXX:.cpp=.o))
OBJ += $(addprefix $(BUILD)/, $(SRC_S:.s=.o))
# Workaround for bug in older gcc, warning on "static usbd_device_t _usbd_dev = { 0 };"
diff --git a/ports/samd/main.c b/ports/samd/main.c
index 038373ceb..5d84a9e88 100644
--- a/ports/samd/main.c
+++ b/ports/samd/main.c
@@ -29,8 +29,8 @@
#include "py/gc.h"
#include "py/mperrno.h"
#include "py/stackctrl.h"
-#include "lib/utils/gchelper.h"
-#include "lib/utils/pyexec.h"
+#include "shared/runtime/gchelper.h"
+#include "shared/runtime/pyexec.h"
extern uint8_t _sstack, _estack, _sheap, _eheap;
@@ -87,6 +87,11 @@ void nlr_jump_fail(void *val) {
}
}
+void abort(void) {
+ for (;;) {
+ }
+}
+
#ifndef NDEBUG
void MP_WEAK __assert_func(const char *file, int line, const char *func, const char *expr) {
mp_printf(MP_PYTHON_PRINTER, "Assertion '%s' failed, at file %s:%d\n", expr, file, line);
diff --git a/ports/samd/sections.ld b/ports/samd/sections.ld
index cbcad463d..743e70a30 100644
--- a/ports/samd/sections.ld
+++ b/ports/samd/sections.ld
@@ -11,10 +11,20 @@ SECTIONS
*(.rodata*)
. = ALIGN(4);
_etext = .;
- _sidata = _etext;
} >FLASH
- .data : AT ( _sidata )
+ /* For C++ exception handling */
+ .ARM :
+ {
+ __exidx_start = .;
+ *(.ARM.exidx*)
+ __exidx_end = .;
+ } >FLASH
+
+ /* Used by the start-up code to initialise data */
+ _sidata = LOADADDR(.data);
+
+ .data :
{
. = ALIGN(4);
_sdata = .;
@@ -22,7 +32,7 @@ SECTIONS
*(.data*)
. = ALIGN(4);
_edata = .;
- } >RAM
+ } >RAM AT> FLASH
.bss :
{
diff --git a/ports/samd/tusb_port.c b/ports/samd/tusb_port.c
index e96f33246..2098334fb 100644
--- a/ports/samd/tusb_port.c
+++ b/ports/samd/tusb_port.c
@@ -27,8 +27,10 @@
#include "samd_soc.h"
#include "tusb.h"
-#define USBD_VID (0xf055)
-#define USBD_PID (0x9802)
+#ifndef MICROPY_HW_USB_VID
+#define MICROPY_HW_USB_VID (0xf055)
+#define MICROPY_HW_USB_PID (0x9802)
+#endif
#define USBD_DESC_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN)
#define USBD_MAX_POWER_MA (250)
@@ -58,8 +60,8 @@ static const tusb_desc_device_t usbd_desc_device = {
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
.bDeviceProtocol = MISC_PROTOCOL_IAD,
.bMaxPacketSize0 = CFG_TUD_ENDOINT0_SIZE,
- .idVendor = USBD_VID,
- .idProduct = USBD_PID,
+ .idVendor = MICROPY_HW_USB_VID,
+ .idProduct = MICROPY_HW_USB_PID,
.bcdDevice = 0x0100,
.iManufacturer = USBD_STR_MANUF,
.iProduct = USBD_STR_PRODUCT,
diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile
index 3725fff52..8ec130380 100644
--- a/ports/stm32/Makefile
+++ b/ports/stm32/Makefile
@@ -34,7 +34,7 @@ MBOOT_TEXT0_ADDR ?= 0x08000000
# include py core make definitions
include $(TOP)/py/py.mk
-GIT_SUBMODULES = lib/libhydrogen lib/lwip lib/mbedtls lib/mynewt-nimble lib/stm32lib
+GIT_SUBMODULES += lib/libhydrogen lib/lwip lib/mbedtls lib/stm32lib
MCU_SERIES_UPPER = $(shell echo $(MCU_SERIES) | tr '[:lower:]' '[:upper:]')
CMSIS_MCU_LOWER = $(shell echo $(CMSIS_MCU) | tr '[:upper:]' '[:lower:]')
@@ -100,7 +100,7 @@ CFLAGS_MCU_h7 = $(CFLAGS_CORTEX_M) -mtune=cortex-m7 -mcpu=cortex-m7
CFLAGS_MCU_wb = $(CFLAGS_CORTEX_M) -mtune=cortex-m4 -mcpu=cortex-m4
CFLAGS += $(INC) -Wall -Wpointer-arith -Wno-error=format -Werror -Wdouble-promotion -Wfloat-conversion -std=gnu99 -nostdlib $(CFLAGS_MOD) $(CFLAGS_EXTRA)
-CFLAGS += -D$(CMSIS_MCU)
+CFLAGS += -D$(CMSIS_MCU) -DUSE_FULL_LL_DRIVER
CFLAGS += $(CFLAGS_MCU_$(MCU_SERIES))
CFLAGS += $(COPT)
CFLAGS += -I$(BOARD_DIR)
@@ -130,7 +130,7 @@ endif
LDFLAGS = -nostdlib -L $(LD_DIR) $(addprefix -T,$(LD_FILES)) -Map=$(@:.elf=.map) --cref
LDFLAGS += --defsym=_estack_reserve=8
-LIBS = "$(shell $(CC) $(CFLAGS) -print-libgcc-file-name)"
+LIBS += "$(shell $(CC) $(CFLAGS) -print-libgcc-file-name)"
# Remove uncalled code from the final image.
CFLAGS += -fdata-sections -ffunction-sections
@@ -157,18 +157,19 @@ endif
# Options for mpy-cross
MPY_CROSS_FLAGS += -march=armv7m
-LIB_SRC_C += $(addprefix lib/,\
+SHARED_SRC_C += $(addprefix shared/,\
libc/string0.c \
- mp-readline/readline.c \
+ netutils/dhcpserver.c \
netutils/netutils.c \
netutils/trace.c \
- netutils/dhcpserver.c \
+ readline/readline.c \
+ runtime/gchelper_native.c \
+ runtime/interrupt_char.c \
+ runtime/mpirq.c \
+ runtime/pyexec.c \
+ runtime/stdout_helpers.c \
+ runtime/sys_stdio_mphal.c \
timeutils/timeutils.c \
- utils/gchelper_native.c \
- utils/pyexec.c \
- utils/interrupt_char.c \
- utils/sys_stdio_mphal.c \
- utils/mpirq.c \
)
ifeq ($(MICROPY_FLOAT_IMPL),double)
@@ -317,7 +318,9 @@ SRC_C += \
gccollect.c \
help.c \
machine_adc.c \
+ machine_bitstream.c \
machine_i2c.c \
+ machine_i2s.c \
machine_spi.c \
machine_timer.c \
machine_uart.c \
@@ -357,18 +360,18 @@ SRC_O += \
ifeq ($(MCU_SERIES),f0)
SRC_O += \
resethandler_m0.o \
- lib/utils/gchelper_m0.o
+ shared/runtime/gchelper_m0.o
else
ifeq ($(MCU_SERIES),l0)
CSUPEROPT = -Os # save some code space
SRC_O += \
resethandler_m0.o \
- lib/utils/gchelper_m0.o
+ shared/runtime/gchelper_m0.o
else
SRC_O += \
system_stm32.o \
resethandler.o \
- lib/utils/gchelper_m3.o
+ shared/runtime/gchelper_m3.o
endif
endif
@@ -396,6 +399,7 @@ HAL_SRC_C += $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_,\
hal_tim_ex.c \
hal_uart.c \
hal_ltdc.c \
+ ll_utils.c \
)
ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),f4 f7 h7 l0 l4 wb))
@@ -429,6 +433,18 @@ ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),f0 f4 f7 h7 l4))
endif
endif
+ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),f0 f4 f7 l0))
+HAL_SRC_C += $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_,\
+ hal_i2s.c \
+ )
+endif
+
+ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),f4))
+HAL_SRC_C += $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_,\
+ hal_i2s_ex.c \
+ )
+endif
+
USBDEV_SRC_C += $(addprefix $(USBDEV_DIR)/,\
core/src/usbd_core.c \
core/src/usbd_ctlreq.c \
@@ -510,12 +526,14 @@ endif
endif
ifeq ($(MICROPY_BLUETOOTH_NIMBLE),1)
+GIT_SUBMODULES += lib/mynewt-nimble
CFLAGS_MOD += -DMICROPY_PY_BLUETOOTH_ENABLE_L2CAP_CHANNELS=1
include $(TOP)/extmod/nimble/nimble.mk
SRC_C += mpnimbleport.c
endif
ifeq ($(MICROPY_BLUETOOTH_BTSTACK),1)
+GIT_SUBMODULES += lib/btstack
MICROPY_BLUETOOTH_BTSTACK_H4 ?= 1
include $(TOP)/extmod/btstack/btstack.mk
SRC_C += mpbtstackport.c
@@ -543,6 +561,7 @@ endif
OBJ += $(PY_O)
OBJ += $(addprefix $(BUILD)/, $(LIB_SRC_C:.c=.o))
OBJ += $(LIBM_O)
+OBJ += $(addprefix $(BUILD)/, $(SHARED_SRC_C:.c=.o))
OBJ += $(addprefix $(BUILD)/, $(EXTMOD_SRC_C:.c=.o))
OBJ += $(addprefix $(BUILD)/, $(DRIVERS_SRC_C:.c=.o))
OBJ += $(addprefix $(BUILD)/, $(HAL_SRC_C:.c=.o))
@@ -556,7 +575,7 @@ OBJ += $(BUILD)/pins_$(BOARD).o
# This file contains performance critical functions so turn up the optimisation
# level. It doesn't add much to the code size and improves performance a bit.
# Don't use -O3 with this file because gcc tries to optimise memset in terms of itself.
-$(BUILD)/lib/libc/string0.o: COPT += -O2
+$(BUILD)/shared/libc/string0.o: COPT += -O2
# We put several files into the first 16K section with the ISRs.
# If we compile these using -O0 then it won't fit. So if you really want these
@@ -723,13 +742,13 @@ GEN_PINS_AF_PY = $(BUILD)/pins_af.py
INSERT_USB_IDS = $(TOP)/tools/insert-usb-ids.py
FILE2H = $(TOP)/tools/file2h.py
-USB_IDS_FILE = usb.h
+USB_IDS_FILE = mpconfigboard_common.h
CDCINF_TEMPLATE = pybcdc.inf_template
GEN_CDCINF_FILE = $(HEADER_BUILD)/pybcdc.inf
GEN_CDCINF_HEADER = $(HEADER_BUILD)/pybcdc_inf.h
# List of sources for qstr extraction
-SRC_QSTR += $(SRC_C) $(SRC_CXX) $(SRC_MOD) $(LIB_SRC_C) $(EXTMOD_SRC_C)
+SRC_QSTR += $(SRC_C) $(SRC_CXX) $(SRC_MOD) $(LIB_SRC_C) $(SHARED_SRC_C) $(EXTMOD_SRC_C)
# Append any auto-generated sources that are needed by sources listed in
# SRC_QSTR
SRC_QSTR_AUTO_DEPS += $(GEN_CDCINF_HEADER)
diff --git a/ports/stm32/README.md b/ports/stm32/README.md
index f2fdb4dd3..6b5f096d7 100644
--- a/ports/stm32/README.md
+++ b/ports/stm32/README.md
@@ -2,11 +2,13 @@ MicroPython port to STM32 MCUs
==============================
This directory contains the port of MicroPython to ST's line of STM32
-microcontrollers. Supported MCU series are: STM32F0, STM32F4, STM32F7 and
-STM32L4. Parts of the code here utilise the STM32Cube HAL library.
+microcontrollers. Supported MCU series are: STM32F0, STM32F4, STM32F7,
+STM32H7, STM32L0, STM32L4 and STM32WB. Parts of the code here utilise the
+STM32Cube HAL library.
The officially supported boards are the line of pyboards: PYBv1.0 and PYBv1.1
-(both with STM32F405), and PYBLITEv1.0 (with STM32F411). See
+(both with STM32F405), PYBLITEv1.0 (with STM32F411) and PYBD-SFx (with
+STM32F7xx MCUs). See
[micropython.org/pyboard](http://www.micropython.org/pyboard/) for further
details.
@@ -40,18 +42,31 @@ see [here](https://launchpad.net/gcc-arm-embedded) for the main GCC ARM
Embedded page. The compiler can be changed using the `CROSS_COMPILE` variable
when invoking `make`.
-First the submodules must be obtained using:
+Next, the board to build must be selected. The default board is PYBV10 but any
+of the names of the subdirectories in the `boards/` directory is a valid board.
+The board name must be passed as the argument to `BOARD=` when invoking `make`.
- $ make submodules
+All boards require certain submodules to be obtained before they can be built.
+The correct set of submodules can be initialised using (with `PYBV11` as an
+example of the selected board):
-Then to build for a given board, run:
+ $ make BOARD=PYBV11 submodules
+
+Then to build the board's firmware run:
$ make BOARD=PYBV11
-The default board is PYBV10 but any of the names of the subdirectories in the
-`boards/` directory can be passed as the argument to `BOARD=`. The above command
-should produce binary images in the `build-PYBV11/` subdirectory (or the
-equivalent directory for the board specified).
+The above command should produce binary images in the `build-PYBV11/`
+subdirectory (or the equivalent directory for the board specified).
+
+Note that some boards require the mboot bootloader to be built and deployed
+before flashing the main firmware. For such boards an information message
+about this will be printed at the end of the main firmware build. Mboot
+can be built via:
+
+ $ make -C mboot BOARD=STM32F769DISC
+
+For more information about mboot see mboot/README.md.
### Flashing the Firmware using DFU mode
@@ -140,6 +155,11 @@ Accessing the board
-------------------
Once built and deployed, access the MicroPython REPL (the Python prompt) via USB
-serial or UART, depending on the board. For the pyboard you can try:
+serial or UART, depending on the board. There are many ways to do this, one of
+which is via `mpremote` (install it using `pip install mpremote`):
+
+ $ mpremote
+
+Other options are `picocom` and `screen`, for example:
$ picocom /dev/ttyACM0
diff --git a/ports/stm32/adc.c b/ports/stm32/adc.c
index 55dc3083b..09cd3306b 100644
--- a/ports/stm32/adc.c
+++ b/ports/stm32/adc.c
@@ -70,8 +70,6 @@
#if defined(STM32F0)
-#define ADC_FIRST_GPIO_CHANNEL (0)
-#define ADC_LAST_GPIO_CHANNEL (15)
#define ADC_SCALE_V (3.3f)
#define ADC_CAL_ADDRESS (0x1ffff7ba)
#define ADC_CAL1 ((uint16_t *)0x1ffff7b8)
@@ -80,8 +78,6 @@
#elif defined(STM32F4)
-#define ADC_FIRST_GPIO_CHANNEL (0)
-#define ADC_LAST_GPIO_CHANNEL (15)
#define ADC_SCALE_V (3.3f)
#define ADC_CAL_ADDRESS (0x1fff7a2a)
#define ADC_CAL1 ((uint16_t *)(ADC_CAL_ADDRESS + 2))
@@ -90,8 +86,6 @@
#elif defined(STM32F7)
-#define ADC_FIRST_GPIO_CHANNEL (0)
-#define ADC_LAST_GPIO_CHANNEL (15)
#define ADC_SCALE_V (3.3f)
#if defined(STM32F722xx) || defined(STM32F723xx) || \
defined(STM32F732xx) || defined(STM32F733xx)
@@ -106,8 +100,6 @@
#elif defined(STM32H7)
-#define ADC_FIRST_GPIO_CHANNEL (0)
-#define ADC_LAST_GPIO_CHANNEL (16)
#define ADC_SCALE_V (3.3f)
#define ADC_CAL_ADDRESS (0x1FF1E860)
#define ADC_CAL1 ((uint16_t *)(0x1FF1E820))
@@ -116,8 +108,6 @@
#elif defined(STM32L4) || defined(STM32WB)
-#define ADC_FIRST_GPIO_CHANNEL (1)
-#define ADC_LAST_GPIO_CHANNEL (16)
#define ADC_SCALE_V (VREFINT_CAL_VREF / 1000.0f)
#define ADC_CAL_ADDRESS (VREFINT_CAL_ADDR)
#define ADC_CAL1 (TEMPSENSOR_CAL1_ADDR)
@@ -179,7 +169,7 @@
typedef struct _pyb_obj_adc_t {
mp_obj_base_t base;
mp_obj_t pin_name;
- int channel;
+ uint32_t channel;
ADC_HandleTypeDef handle;
} pyb_obj_adc_t;
@@ -308,13 +298,6 @@ STATIC void adcx_init_periph(ADC_HandleTypeDef *adch, uint32_t resolution) {
}
STATIC void adc_init_single(pyb_obj_adc_t *adc_obj) {
-
- if (ADC_FIRST_GPIO_CHANNEL <= adc_obj->channel && adc_obj->channel <= ADC_LAST_GPIO_CHANNEL) {
- // Channels 0-16 correspond to real pins. Configure the GPIO pin in ADC mode.
- const pin_obj_t *pin = pin_adc_table[adc_obj->channel];
- mp_hal_pin_config(pin, MP_HAL_PIN_MODE_ADC, MP_HAL_PIN_PULL_NONE, 0);
- }
-
adc_obj->handle.Instance = ADCx;
adcx_init_periph(&adc_obj->handle, ADC_RESOLUTION_12B);
@@ -431,8 +414,8 @@ STATIC mp_obj_t adc_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_
} else {
const pin_obj_t *pin = pin_find(pin_obj);
if ((pin->adc_num & PIN_ADC_MASK) == 0) {
- // No ADC1 function on that pin
- mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("pin %q does not have ADC capabilities"), pin->name);
+ // No ADC function on the given pin.
+ mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("Pin(%q) doesn't have ADC capabilities"), pin->name);
}
channel = pin->adc_channel;
}
@@ -441,11 +424,11 @@ STATIC mp_obj_t adc_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("not a valid ADC Channel: %d"), channel);
}
-
- if (ADC_FIRST_GPIO_CHANNEL <= channel && channel <= ADC_LAST_GPIO_CHANNEL) {
- // these channels correspond to physical GPIO ports so make sure they exist
- if (pin_adc_table[channel] == NULL) {
- mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("channel %d not available on this board"), channel);
+ // If this channel corresponds to a pin then configure the pin in ADC mode.
+ if (channel < MP_ARRAY_SIZE(pin_adc_table)) {
+ const pin_obj_t *pin = pin_adc_table[channel];
+ if (pin != NULL) {
+ mp_hal_pin_config(pin, MP_HAL_PIN_MODE_ADC, MP_HAL_PIN_PULL_NONE, 0);
}
}
@@ -730,11 +713,10 @@ void adc_init_all(pyb_adc_all_obj_t *adc_all, uint32_t resolution, uint32_t en_m
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("resolution %d not supported"), resolution);
}
- for (uint32_t channel = ADC_FIRST_GPIO_CHANNEL; channel <= ADC_LAST_GPIO_CHANNEL; ++channel) {
+ for (uint32_t channel = 0; channel < MP_ARRAY_SIZE(pin_adcall_table); ++channel) {
// only initialise those channels that are selected with the en_mask
if (en_mask & (1 << channel)) {
- // Channels 0-16 correspond to real pins. Configure the GPIO pin in
- // ADC mode.
+ // If this channel corresponds to a pin then configure the pin in ADC mode.
const pin_obj_t *pin = pin_adcall_table[channel];
if (pin) {
mp_hal_pin_config(pin, MP_HAL_PIN_MODE_ADC, MP_HAL_PIN_PULL_NONE, 0);
diff --git a/ports/stm32/boardctrl.c b/ports/stm32/boardctrl.c
index fa71d8e7f..922f218e9 100644
--- a/ports/stm32/boardctrl.c
+++ b/ports/stm32/boardctrl.c
@@ -26,7 +26,7 @@
#include "py/runtime.h"
#include "py/mphal.h"
-#include "lib/utils/pyexec.h"
+#include "shared/runtime/pyexec.h"
#include "boardctrl.h"
#include "led.h"
#include "usrsw.h"
diff --git a/ports/stm32/boards/B_L072Z_LRWAN1/mpconfigboard.h b/ports/stm32/boards/B_L072Z_LRWAN1/mpconfigboard.h
index 0cded1bc8..dfcca72af 100644
--- a/ports/stm32/boards/B_L072Z_LRWAN1/mpconfigboard.h
+++ b/ports/stm32/boards/B_L072Z_LRWAN1/mpconfigboard.h
@@ -7,6 +7,7 @@
#define MICROPY_EMIT_THUMB (0)
#define MICROPY_EMIT_INLINE_THUMB (0)
+#define MICROPY_OPT_COMPUTED_GOTO (0)
#define MICROPY_PY_BUILTINS_COMPLEX (0)
#define MICROPY_PY_GENERATOR_PEND_THROW (0)
#define MICROPY_PY_MATH (0)
@@ -67,5 +68,5 @@
#define MICROPY_HW_USB_FS (1)
#define MICROPY_HW_USB_MSC (0)
#define MICROPY_HW_USB_HID (0)
-#define USBD_CDC_RX_DATA_SIZE (256)
-#define USBD_CDC_TX_DATA_SIZE (256)
+#define MICROPY_HW_USB_CDC_RX_DATA_SIZE (256)
+#define MICROPY_HW_USB_CDC_TX_DATA_SIZE (256)
diff --git a/ports/stm32/boards/LEGO_HUB_NO6/README.md b/ports/stm32/boards/LEGO_HUB_NO6/README.md
new file mode 100644
index 000000000..0b88cd837
--- /dev/null
+++ b/ports/stm32/boards/LEGO_HUB_NO6/README.md
@@ -0,0 +1,99 @@
+LEGO Hub No.6
+=============
+
+This board definition is for the LEGO Hub No. 6, a LEGO control unit with a 5x5
+LED display, 6 Powered Up ports, speaker, 6-DOF sensor, Bluetooth, external SPI
+flash storage, and a rechargeable battery. The Hub can work without the battery if
+it is plugged in to, and powered by, its USB port. But without the battery the LEDs
+and power on the Powered Up ports will not function.
+
+Features that are currently supported:
+- standard MicroPython
+- machine and bluetooth modules
+- filesystem
+- USB VCP, MSC and HID
+
+The Hub has a bootloader preinstalled at 0x08000000 (which is 32kiB in size) which
+cannot be erased. This bootloader is entered by holding down the Bluetooth button,
+plugging in USB to power it up, then releasing the Bluetooth button after 5 seconds,
+at which point the USB DFU device appears. If the battery is installed then the
+Bluetooth button's RGB LED will cycle colours. When this bootloader is active, the
+flash from 0x08008000 and up can be erased and programmed via USB DFU.
+
+The built-in bootloader has some drawbacks: it cannot be entered programmatically,
+and it does not keep the Hub powered up when running from battery (which requires
+keeping BAT_PWR_EN high). As such, this board is configured to work with mboot as
+a secondary bootloader: mboot is placed at 0x08008000 and the main application
+firmware at 0x08010000. When mboot is installed it can be entered programatically
+via machine.bootloader(), or by holding down the left arrow button when powering
+on the Hub and waiting until the display says "B" before releasing the button.
+
+Backing up original Hub firmware
+--------------------------------
+
+Before install MicroPython it is advised to backup the original LEGO firmware that
+the Hub comes installed with. To do this, enter the built-in bootloader by holding
+down the Bluetooth button for 5 seconds while powering up the Hub via USB. Then
+run the following command from the root of this repository:
+
+ $ cd ports/stm32
+ $ make BOARD=LEGO_HUB_NO6 backup-hub-firmware
+
+This will create a file called `lego_hub_firmware.dfu`. Put this file in a safe
+location. To restore it, enter the built-in bootloader again and run:
+
+ $ make BOARD=LEGO_HUB_NO6 restore-hub-firmware
+
+This will restore the original firmware but not the filesystem. To recreate the
+original filesystem the Hub must be updated using the appropriate LEGO PC
+application.
+
+Installing MicroPython
+----------------------
+
+You first need to build and install mboot, which only needs to be done once. From
+the root of this repository run:
+
+ $ cd ports/stm32/mboot
+ $ make BOARD=LEGO_HUB_NO6
+
+Now enter the built-in bootloader by holding down the Bluetooth button for 5
+seconds while powering up the Hub via USB. Then run:
+
+ $ make BOARD=LEGO_HUB_NO6 deploy
+
+mboot should now be installed. Enter mboot by holding down the left arrow
+button when powering up the Hub. The display will cycle the letters: N, S, F, B.
+When it gets to "B" release the left arrow and it will start mboot. The Hub then
+blinks the centre button red once per second, and appears as a USB DFU device.
+
+Now build MicroPython (start at the root of this repository):
+
+ $ cd mpy-cross
+ $ make
+ $ cd ../ports/stm32
+ $ make submodules
+ $ make BOARD=LEGO_HUB_NO6
+
+And deploy to the Hub (making sure mboot is active, the centre button is blinking
+red):
+
+ $ make BOARD=LEGO_HUB_NO6 deploy
+
+If successful, the Hub should now appear as a USB serial and mass storage device.
+
+Using MicroPython on the Hub
+----------------------------
+
+Access the MicroPython REPL using mpremote (pip install mpremote), or with any
+serial terminal program.
+
+To scan for BLE devices:
+
+ >>> import bluetooth
+ >>> ble = bluetooth.BLE()
+ >>> ble.irq(lambda *x: print(*x))
+ >>> ble.active(1)
+ >>> ble.gap_scan(2000, 625, 625)
+
+Use help("modules") to see available built-in modules.
diff --git a/ports/stm32/boards/LEGO_HUB_NO6/bdev.c b/ports/stm32/boards/LEGO_HUB_NO6/bdev.c
new file mode 100644
index 000000000..a68b812ed
--- /dev/null
+++ b/ports/stm32/boards/LEGO_HUB_NO6/bdev.c
@@ -0,0 +1,64 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/obj.h"
+#include "storage.h"
+#include "spi.h"
+
+#define CMD_EXIT_4_BYTE_ADDRESS_MODE (0xE9)
+
+STATIC const spi_proto_cfg_t spi_bus = {
+ .spi = &spi_obj[1], // SPI2 hardware peripheral
+ .baudrate = 25000000,
+ .polarity = 0,
+ .phase = 0,
+ .bits = 8,
+ .firstbit = SPI_FIRSTBIT_MSB,
+};
+
+STATIC mp_spiflash_cache_t spi_bdev_cache;
+
+const mp_spiflash_config_t spiflash_config = {
+ .bus_kind = MP_SPIFLASH_BUS_SPI,
+ .bus.u_spi.cs = MICROPY_HW_SPIFLASH_CS,
+ .bus.u_spi.data = (void *)&spi_bus,
+ .bus.u_spi.proto = &spi_proto,
+ .cache = &spi_bdev_cache,
+};
+
+spi_bdev_t spi_bdev;
+
+int32_t board_bdev_ioctl(void) {
+ int32_t ret = spi_bdev_ioctl(&spi_bdev, BDEV_IOCTL_INIT, (uint32_t)&spiflash_config);
+
+ // Exit 4-byte address mode
+ uint8_t cmd = CMD_EXIT_4_BYTE_ADDRESS_MODE;
+ mp_hal_pin_write(MICROPY_HW_SPIFLASH_CS, 0);
+ spi_proto.transfer(MP_OBJ_FROM_PTR(&spi_bus), 1, &cmd, NULL);
+ mp_hal_pin_write(MICROPY_HW_SPIFLASH_CS, 1);
+
+ return ret;
+}
diff --git a/ports/stm32/boards/LEGO_HUB_NO6/bluetooth_init_cc2564C_1.5.c b/ports/stm32/boards/LEGO_HUB_NO6/bluetooth_init_cc2564C_1.5.c
new file mode 100644
index 000000000..ec41fdfee
--- /dev/null
+++ b/ports/stm32/boards/LEGO_HUB_NO6/bluetooth_init_cc2564C_1.5.c
@@ -0,0 +1,616 @@
+// This file contains CC256x initialisation code, and was generated by BTstack via:
+// $ cd chipset/cc256x
+// $ make -f Makefile.inc BTSTACK_ROOT=../.. bluetooth_init_cc2564C_1.4.c
+#if !BUILDING_MBOOT
+
+ // init script created from
+// - /Users/dktobthy/Downloads/cc256xc_bt_spv1.5/CC256XC_BT_SP/v1.5/initscripts-TIInit_6.12.26.bts
+// - AKA TIInit_6.12.26.bts
+// - /Users/dktobthy/Downloads/cc256xc_bt_spv1.5/CC256XC_BT_SP/v1.5/initscripts-TIInit_6.12.26_ble_add-on.bts
+#include
+#include "lib/btstack/chipset/cc256x/btstack_chipset_cc256x.h"
+
+
+const uint16_t cc256x_init_script_lmp_subversion = 0x9a1a;
+
+uint16_t btstack_chipset_cc256x_lmp_subversion(void){
+ return cc256x_init_script_lmp_subversion;
+}
+
+#if defined(__GNUC__) && defined(__MSP430X__) && (__MSP430X__ > 0)
+__attribute__((section (".fartext")))
+#endif
+#ifdef __AVR__
+__attribute__((__progmem__))
+#endif
+const uint8_t cc256x_init_script[] = {
+
+ // #--------------------------------------------------------------------------------
+ // # Description : Orca C ROM Initialization Script
+ // #
+ // # Compatibility: Orca, 12.0.26 ROM
+ // #
+ // # Last Updated: 17-May-2021 10:31:30.07
+ // #
+ // # Version : 12_26.24
+ // #
+ // #
+ // #
+ // #
+ // # Notes : Use this script on Orca C, 12.0.26 ROM device only (FW v12.0.26)
+ // #--------------------------------------------------------------------------------
+ // #################################################################
+ // ## START of CC256x Add-On
+ // #################################################################
+ //
+ // ## Change UART baudrate
+ //
+ // #################################################################
+ // ## END of CC256x Add-On
+ // #################################################################
+ //
+ 0x01, 0x37, 0xfe, 0x02, 0x0c, 0x1a,
+
+ //
+ //
+ 0x01, 0x05, 0xff, 0xff, 0xd0, 0x65, 0x08, 0x00, 0xfa, 0x0c, 0x1a, 0x09, 0x18, 0x01, 0x6a,
+ 0xc8, 0x7b, 0x00, 0x02, 0x89, 0x7b, 0x01, 0x43, 0x09, 0x48, 0x51, 0x30, 0x02, 0x88, 0x06,
+ 0x48, 0x91, 0x42, 0x03, 0xd1, 0x04, 0x49, 0x09, 0x78, 0x01, 0x29, 0x01, 0xd0, 0x5d, 0x30,
+ 0xf7, 0x46, 0xff, 0x30, 0xd8, 0x30, 0xf7, 0x46, 0x76, 0x24, 0x08, 0x00, 0xbd, 0x28, 0x02,
+ 0x00, 0x69, 0x53, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb5, 0x00,
+ 0x69, 0xff, 0x21, 0x02, 0x31, 0x09, 0x5c, 0x09, 0x29, 0x05, 0xd1, 0x01, 0x21, 0x00, 0x22,
+ 0x8e, 0x46, 0x6d, 0x4b, 0xfe, 0x44, 0x18, 0x47, 0x00, 0xbd, 0x6c, 0x4a, 0x11, 0x88, 0x01,
+ 0x20, 0x40, 0x03, 0x08, 0x43, 0x10, 0x80, 0xf7, 0x46, 0x30, 0xb5, 0x00, 0x69, 0xf4, 0x21,
+ 0x08, 0x5c, 0x01, 0x28, 0x16, 0xd1, 0xea, 0x48, 0x00, 0x78, 0x03, 0x28, 0x12, 0xd0, 0x00,
+ 0x25, 0x28, 0x1c, 0xe8, 0x49, 0x01, 0x24, 0xa6, 0x46, 0xe7, 0x4a, 0xfe, 0x44, 0x10, 0x47,
+ 0x00, 0x28, 0x08, 0xd0,
+
+ 0x01, 0x05, 0xff, 0xff, 0xca, 0x66, 0x08, 0x00, 0xfa, 0xe6, 0x49, 0xe6, 0x4a, 0xbb, 0x32,
+ 0x20, 0x20, 0x2b, 0x1c, 0xa6, 0x46, 0xe5, 0x4c, 0xfe, 0x44, 0x20, 0x47, 0x30, 0xbd, 0x70,
+ 0xb5, 0x85, 0x69, 0x00, 0x7d, 0x80, 0x1f, 0x11, 0xd0, 0x47, 0x38, 0x2e, 0xd1, 0xa9, 0x79,
+ 0x28, 0x20, 0x48, 0x43, 0xdf, 0x4a, 0x10, 0x18, 0x23, 0x22, 0x12, 0x5c, 0x01, 0x2a, 0x25,
+ 0xd1, 0x80, 0x7b, 0x00, 0x28, 0x22, 0xd0, 0xdb, 0x4a, 0x00, 0x20, 0x50, 0x54, 0x70, 0xbd,
+ 0x01, 0x24, 0xa6, 0x46, 0xd9, 0x48, 0xfe, 0x44, 0x00, 0x47, 0x01, 0x28, 0x05, 0xd0, 0xa6,
+ 0x46, 0xd6, 0x48, 0xfe, 0x44, 0x00, 0x47, 0x04, 0x28, 0x11, 0xd1, 0xe8, 0x78, 0x00, 0x28,
+ 0x0e, 0xd1, 0x0e, 0x26, 0x31, 0x1c, 0xd3, 0x4d, 0x28, 0x1c, 0x14, 0x38, 0xa6, 0x46, 0xd0,
+ 0x4a, 0xfe, 0x44, 0x10, 0x47, 0x28, 0x1c, 0x31, 0x1c, 0xa6, 0x46, 0xcd, 0x4a, 0xfe, 0x44,
+ 0x10, 0x47, 0x70, 0xbd, 0x70, 0xb5, 0x01, 0x1c, 0x88, 0x69, 0x89, 0x8a, 0xcb, 0x4a, 0x89,
+ 0x1a, 0x1c, 0xd0, 0x1c, 0x39, 0x20, 0xd1, 0xc5, 0x7a, 0x01, 0x21, 0x0c, 0x1c, 0x8e, 0x46,
+ 0xc8, 0x4a, 0xfe, 0x44, 0x10, 0x47, 0x06, 0x1c, 0x10, 0x20, 0xa6, 0x46, 0xc6, 0x49, 0xfe,
+ 0x44, 0x08, 0x47, 0x00, 0x2d, 0x11, 0xd0, 0x02, 0x2e, 0x0f, 0xd0, 0xc3, 0x49, 0xc4, 0x4a,
+ 0xd9, 0x32, 0x20, 0x20, 0x00, 0x23, 0xa6, 0x46, 0xb7, 0x4c, 0xfe, 0x44, 0x20, 0x47, 0x70,
+ 0xbd, 0xc0, 0x7a, 0x00, 0x28, 0x02, 0xd1, 0x00, 0x20, 0xbe, 0x49, 0x08, 0x70, 0x70, 0xbd,
+ 0x00, 0xb5, 0x00, 0x69, 0xff, 0x21, 0x04, 0x31, 0x09, 0x5c, 0x06, 0x29, 0x06, 0xd1, 0xff,
+ 0x21, 0x05, 0x31, 0x0a, 0x5c, 0x2c, 0x2a, 0x01, 0xd1, 0x2d, 0x22, 0x0a, 0x54, 0xff, 0x21,
+ 0x05, 0x31, 0x09, 0x5c,
+
+ 0x01, 0x05, 0xff, 0xff, 0xc4, 0x67, 0x08, 0x00, 0xfa, 0x34, 0x29, 0x11, 0xd1, 0xff, 0x21,
+ 0x0b, 0x31, 0x09, 0x5c, 0x91, 0x29, 0x0c, 0xd1, 0xf1, 0x21, 0x09, 0x5c, 0x60, 0x22, 0x4a,
+ 0x43, 0xeb, 0x4b, 0x00, 0x21, 0x99, 0x54, 0x06, 0x21, 0x01, 0x22, 0x96, 0x46, 0xe9, 0x4a,
+ 0xfe, 0x44, 0x10, 0x47, 0x00, 0xbd, 0xf0, 0xb5, 0x06, 0x1c, 0xf7, 0x69, 0x08, 0x20, 0xc0,
+ 0x19, 0x01, 0x24, 0xa6, 0x46, 0xe4, 0x49, 0xfe, 0x44, 0x08, 0x47, 0xc1, 0x7b, 0x09, 0x02,
+ 0x80, 0x7b, 0x08, 0x43, 0x05, 0x04, 0x2d, 0x0c, 0x02, 0x2d, 0x12, 0xd0, 0xef, 0x48, 0x00,
+ 0x88, 0xa8, 0x42, 0x0e, 0xd1, 0xee, 0x48, 0x00, 0x78, 0x01, 0x28, 0x0a, 0xd1, 0xed, 0x48,
+ 0x82, 0x8f, 0x81, 0x6b, 0x08, 0x1c, 0x10, 0x43, 0x04, 0xd0, 0x38, 0x1c, 0xa6, 0x46, 0xea,
+ 0x4b, 0xfe, 0x44, 0x18, 0x47, 0x35, 0x60, 0xe9, 0x48, 0x24, 0x30, 0x30, 0x62, 0xf0, 0xbd,
+ 0xc0, 0x46, 0xdd, 0x9d, 0x00, 0x00, 0x3e, 0xa6, 0x1b, 0x00, 0xf0, 0xb5, 0x86, 0xb0, 0x04,
+ 0x90, 0x81, 0x69, 0x05, 0x91, 0x81, 0x8a, 0xe2, 0x48, 0x09, 0x1a, 0xdc, 0x4d, 0x00, 0xd1,
+ 0xba, 0xe0, 0xe1, 0x4a, 0x89, 0x1a, 0x00, 0xd1, 0xaf, 0xe0, 0x07, 0x38, 0x09, 0x1a, 0x35,
+ 0xd0, 0xde, 0x48, 0x09, 0x1a, 0x28, 0xd0, 0x05, 0x39, 0x26, 0xd0, 0x13, 0x39, 0x33, 0xd1,
+ 0xdc, 0x48, 0x05, 0x1c, 0x84, 0x3d, 0x00, 0x78, 0x02, 0x28, 0x2d, 0xd1, 0x01, 0x24, 0xa6,
+ 0x46, 0xd9, 0x48, 0xfe, 0x44, 0x00, 0x47, 0x00, 0x28, 0x26, 0xd1, 0xa6, 0x46, 0xd7, 0x48,
+ 0xfe, 0x44, 0x00, 0x47, 0x00, 0x28, 0x20, 0xd1, 0xa6, 0x46, 0xd5, 0x48, 0xfe, 0x44, 0x00,
+ 0x47, 0x00, 0x28, 0x1a, 0xd1, 0x28, 0x78, 0x00, 0x28, 0x17, 0xd1, 0xa8, 0x78, 0x00, 0x28,
+ 0x14, 0xd1, 0xa6, 0x20,
+
+ 0x01, 0x05, 0xff, 0xff, 0xbe, 0x68, 0x08, 0x00, 0xfa, 0xa6, 0x46, 0xcf, 0x49, 0xfe, 0x44,
+ 0x08, 0x47, 0xc4, 0xe0, 0x05, 0x98, 0x81, 0x88, 0x41, 0x18, 0x08, 0x7c, 0x02, 0x28, 0x00,
+ 0xda, 0xbd, 0xe0, 0x80, 0x1e, 0x08, 0x74, 0xba, 0xe0, 0x51, 0x3d, 0x28, 0x78, 0x2a, 0x28,
+ 0x02, 0xd0, 0x33, 0x28, 0x00, 0xd0, 0xb3, 0xe0, 0x0e, 0x21, 0x05, 0x98, 0x0f, 0x18, 0x44,
+ 0x20, 0x0c, 0x21, 0x1a, 0x22, 0x01, 0x24, 0xa6, 0x46, 0xc2, 0x4b, 0xfe, 0x44, 0x18, 0x47,
+ 0xc1, 0x4e, 0xb1, 0x78, 0xf2, 0x78, 0xc1, 0x48, 0xa6, 0x46, 0xc1, 0x4b, 0xfe, 0x44, 0x18,
+ 0x47, 0x06, 0x21, 0x05, 0x98, 0x81, 0x80, 0x28, 0x78, 0xbf, 0x4d, 0x2a, 0x28, 0x26, 0xd0,
+ 0x0a, 0x26, 0x3e, 0x70, 0x01, 0x37, 0x38, 0x1c, 0x00, 0x21, 0xa6, 0x46, 0xba, 0x4a, 0xfe,
+ 0x44, 0x10, 0x47, 0x07, 0x1c, 0x3e, 0x70, 0x01, 0x37, 0x38, 0x1c, 0x0d, 0x21, 0xa6, 0x46,
+ 0xb5, 0x4a, 0xfe, 0x44, 0x10, 0x47, 0x07, 0x1c, 0xa6, 0x46, 0xb5, 0x48, 0xfe, 0x44, 0x00,
+ 0x47, 0x81, 0x02, 0xae, 0x48, 0xc0, 0x78, 0x40, 0x06, 0x40, 0x0e, 0x08, 0x43, 0x05, 0x43,
+ 0x29, 0x04, 0x09, 0x0c, 0x38, 0x1c, 0xa6, 0x46, 0xac, 0x4a, 0xfe, 0x44, 0x10, 0x47, 0x08,
+ 0x26, 0x24, 0xe0, 0x08, 0x26, 0x3e, 0x70, 0x01, 0x37, 0x38, 0x1c, 0x00, 0x21, 0xa6, 0x46,
+ 0xa6, 0x4a, 0xfe, 0x44, 0x10, 0x47, 0x07, 0x1c, 0x3e, 0x70, 0x01, 0x37, 0x38, 0x1c, 0x0d,
+ 0x21, 0xa6, 0x46, 0xa2, 0x4a, 0xfe, 0x44, 0x10, 0x47, 0x07, 0x1c, 0xa6, 0x46, 0xa1, 0x48,
+ 0xfe, 0x44, 0x00, 0x47, 0x81, 0x02, 0x9a, 0x48, 0xc0, 0x78, 0x40, 0x06, 0x40, 0x0e, 0x08,
+ 0x43, 0x05, 0x43, 0x29, 0x04, 0x09, 0x0c, 0x38, 0x1c, 0xa6, 0x46, 0x98, 0x4a, 0xfe, 0x44,
+ 0x10, 0x47, 0x05, 0x98,
+
+ 0x01, 0x05, 0xff, 0xff, 0xb8, 0x69, 0x08, 0x00, 0xfa, 0x46, 0x80, 0xff, 0x21, 0x02, 0x31,
+ 0x00, 0x22, 0xa6, 0x46, 0xed, 0x4b, 0xfe, 0x44, 0x18, 0x47, 0x3f, 0xe0, 0xec, 0x49, 0x00,
+ 0x20, 0x08, 0x70, 0x08, 0x74, 0xeb, 0x49, 0x08, 0x70, 0x3c, 0xe0, 0x05, 0x98, 0x00, 0x21,
+ 0x6a, 0x46, 0x01, 0x24, 0xa6, 0x46, 0xe8, 0x4b, 0xfe, 0x44, 0x18, 0x47, 0x02, 0xa8, 0x00,
+ 0x21, 0x06, 0x22, 0xa6, 0x46, 0xe5, 0x4b, 0xfe, 0x44, 0x18, 0x47, 0x00, 0x26, 0x02, 0xe0,
+ 0x70, 0x1c, 0x06, 0x04, 0x36, 0x0c, 0x28, 0x1c, 0x4f, 0x38, 0x00, 0x78, 0x86, 0x42, 0x23,
+ 0xda, 0x11, 0x20, 0x40, 0x01, 0x70, 0x43, 0xea, 0x49, 0x0f, 0x18, 0x10, 0x20, 0xc0, 0x19,
+ 0x69, 0x46, 0xa6, 0x46, 0xe8, 0x4a, 0xfe, 0x44, 0x10, 0x47, 0x00, 0x28, 0xe9, 0xd1, 0x68,
+ 0x46, 0x02, 0xa9, 0xa6, 0x46, 0xe4, 0x4a, 0xfe, 0x44, 0x10, 0x47, 0x00, 0x28, 0xe1, 0xd0,
+ 0xb8, 0x78, 0x01, 0x28, 0xde, 0xd0, 0x05, 0x98, 0x69, 0x49, 0x3a, 0x22, 0xa6, 0x46, 0xdf,
+ 0x4b, 0xfe, 0x44, 0x18, 0x47, 0xec, 0x49, 0xe2, 0x31, 0x04, 0x98, 0x01, 0x62, 0x06, 0xb0,
+ 0xf0, 0xbd, 0xc0, 0x46, 0x18, 0x32, 0x08, 0x00, 0xce, 0x04, 0x00, 0x00, 0x23, 0xb9, 0x02,
+ 0x00, 0x85, 0x71, 0x08, 0x00, 0xfd, 0x79, 0x00, 0x00, 0xc9, 0x70, 0x08, 0x00, 0xd4, 0x1d,
+ 0x08, 0x00, 0x94, 0x54, 0x08, 0x00, 0x8f, 0x8d, 0x01, 0x00, 0xfd, 0x06, 0x05, 0x00, 0x14,
+ 0x05, 0x1a, 0x00, 0xa2, 0xfd, 0x00, 0x00, 0x65, 0x2d, 0x00, 0x00, 0x7d, 0xca, 0x03, 0x00,
+ 0xc5, 0x71, 0x08, 0x00, 0x79, 0x47, 0x00, 0x00, 0x78, 0x24, 0x08, 0x00, 0xf0, 0xb5, 0x07,
+ 0x1c, 0xba, 0x69, 0x50, 0x78, 0xfe, 0x69, 0x25, 0x21, 0x43, 0x1a, 0xe4, 0x49, 0x32, 0xd0,
+ 0x01, 0x3b, 0x68, 0xd1,
+
+ 0x01, 0x05, 0xff, 0xff, 0xb2, 0x6a, 0x08, 0x00, 0xfa, 0x04, 0x23, 0xb3, 0x80, 0x0c, 0x23,
+ 0x9d, 0x19, 0x40, 0x00, 0x12, 0x78, 0x02, 0x43, 0x2a, 0x70, 0x01, 0x35, 0x08, 0x78, 0x2a,
+ 0x28, 0x05, 0xd0, 0x33, 0x28, 0x01, 0xd1, 0x0a, 0x20, 0x02, 0xe0, 0x07, 0x20, 0x00, 0xe0,
+ 0x08, 0x20, 0x28, 0x70, 0x01, 0x35, 0x28, 0x1c, 0x0d, 0x21, 0x01, 0x24, 0xa6, 0x46, 0x4b,
+ 0x4a, 0xfe, 0x44, 0x10, 0x47, 0x05, 0x1c, 0xa6, 0x46, 0x4b, 0x48, 0xfe, 0x44, 0x00, 0x47,
+ 0x82, 0x02, 0xd2, 0x48, 0x00, 0x78, 0x40, 0x06, 0x41, 0x0e, 0x11, 0x43, 0x45, 0x48, 0x08,
+ 0x43, 0x01, 0x04, 0x09, 0x0c, 0x28, 0x1c, 0xa6, 0x46, 0x41, 0x4a, 0xfe, 0x44, 0x10, 0x47,
+ 0x2f, 0xe0, 0x04, 0x23, 0xb3, 0x80, 0x0c, 0x23, 0x9d, 0x19, 0x40, 0x00, 0x12, 0x78, 0x02,
+ 0x43, 0x2a, 0x70, 0x01, 0x35, 0x08, 0x78, 0x2a, 0x28, 0x05, 0xd0, 0x33, 0x28, 0x01, 0xd1,
+ 0x0a, 0x20, 0x02, 0xe0, 0x07, 0x20, 0x00, 0xe0, 0x08, 0x20, 0x28, 0x70, 0x01, 0x35, 0x28,
+ 0x1c, 0x0d, 0x21, 0x01, 0x24, 0xa6, 0x46, 0x33, 0x4a, 0xfe, 0x44, 0x10, 0x47, 0x05, 0x1c,
+ 0xa6, 0x46, 0x32, 0x48, 0xfe, 0x44, 0x00, 0x47, 0x82, 0x02, 0xb9, 0x48, 0x00, 0x78, 0x40,
+ 0x06, 0x41, 0x0e, 0x11, 0x43, 0x2d, 0x48, 0x08, 0x43, 0x01, 0x04, 0x09, 0x0c, 0x28, 0x1c,
+ 0xa6, 0x46, 0x29, 0x4a, 0xfe, 0x44, 0x10, 0x47, 0x06, 0x20, 0x70, 0x80, 0x03, 0x20, 0x30,
+ 0x80, 0xe3, 0x48, 0xe2, 0x49, 0x08, 0x18, 0x38, 0x62, 0xf0, 0xbd, 0xc0, 0x46, 0x76, 0xa0,
+ 0x1b, 0x00, 0xc5, 0x8e, 0x00, 0x00, 0x5b, 0x19, 0x04, 0x00, 0x10, 0xb5, 0xde, 0x48, 0x00,
+ 0x21, 0x01, 0x24, 0xa6, 0x46, 0xdd, 0x4a, 0xfe, 0x44, 0x10, 0x47, 0xdc, 0x49, 0x01, 0x28,
+ 0x01, 0xd0, 0x00, 0x20,
+
+ 0x01, 0x05, 0xff, 0xff, 0xac, 0x6b, 0x08, 0x00, 0xfa, 0x01, 0xe0, 0x08, 0x68, 0x01, 0x30,
+ 0x08, 0x60, 0xa6, 0x46, 0xd9, 0x48, 0xfe, 0x44, 0x00, 0x47, 0x00, 0x28, 0x06, 0xd0, 0x0b,
+ 0x48, 0x00, 0x78, 0x02, 0x28, 0x02, 0xd1, 0x02, 0x20, 0xd5, 0x49, 0x08, 0x80, 0x10, 0xbd,
+ 0xba, 0x53, 0x08, 0x00, 0x90, 0xa1, 0x1b, 0x00, 0xa8, 0x59, 0x08, 0x00, 0x25, 0x6f, 0x04,
+ 0x00, 0x79, 0x6c, 0x04, 0x00, 0x05, 0x04, 0x00, 0x00, 0xfe, 0x07, 0x00, 0x00, 0x05, 0x10,
+ 0x00, 0x00, 0x45, 0x10, 0x08, 0x00, 0xc1, 0x72, 0x03, 0x00, 0x1b, 0x5f, 0x03, 0x00, 0x53,
+ 0x38, 0x02, 0x00, 0x21, 0xf0, 0x04, 0x00, 0xdb, 0x8e, 0x04, 0x00, 0xfc, 0x53, 0x08, 0x00,
+ 0xc6, 0x02, 0x00, 0x00, 0x8d, 0x8f, 0x04, 0x00, 0xf9, 0x2d, 0x00, 0x00, 0x00, 0x82, 0xff,
+ 0xff, 0xa9, 0x57, 0x05, 0x00, 0xf8, 0xb5, 0x80, 0x8a, 0xff, 0x21, 0x0b, 0x31, 0x88, 0x42,
+ 0x5c, 0xd0, 0xff, 0x21, 0x45, 0x31, 0x88, 0x42, 0x16, 0xd1, 0xc1, 0x48, 0x00, 0x78, 0x02,
+ 0x28, 0x12, 0xd1, 0xb9, 0x49, 0xff, 0x20, 0x41, 0x30, 0x40, 0x18, 0x00, 0x90, 0xb8, 0x48,
+ 0x40, 0x5c, 0x00, 0x26, 0x86, 0x42, 0x10, 0xd3, 0x51, 0x25, 0xad, 0x00, 0x28, 0x1c, 0x01,
+ 0x24, 0xa6, 0x46, 0xb4, 0x49, 0xfe, 0x44, 0x08, 0x47, 0x00, 0x28, 0x6d, 0xd1, 0x28, 0x1c,
+ 0xb2, 0x49, 0xa6, 0x46, 0xb2, 0x4a, 0xfe, 0x44, 0x10, 0x47, 0xf8, 0xbd, 0xb1, 0x00, 0x00,
+ 0x98, 0x45, 0x58, 0x00, 0x2d, 0x30, 0xd0, 0xfe, 0x20, 0x40, 0x5d, 0x00, 0x28, 0x2c, 0xd0,
+ 0xf2, 0x20, 0x41, 0x5d, 0x00, 0x29, 0x28, 0xd1, 0xff, 0x20, 0x02, 0x30, 0x40, 0x5d, 0x01,
+ 0x28, 0x23, 0xd0, 0x24, 0x20, 0x01, 0x24, 0xa6, 0x46, 0xa6, 0x4a, 0xfe, 0x44, 0x10, 0x47,
+ 0x00, 0x06, 0x00, 0x0e,
+
+ 0x01, 0x05, 0xff, 0xff, 0xa6, 0x6c, 0x08, 0x00, 0xfa, 0xf3, 0x22, 0x51, 0x5d, 0x81, 0x42,
+ 0x17, 0xd0, 0x50, 0x55, 0x00, 0x28, 0x14, 0xd1, 0x2f, 0x8d, 0x39, 0x1c, 0xe7, 0x48, 0xa6,
+ 0x46, 0xe7, 0x4a, 0xfe, 0x44, 0x10, 0x47, 0x29, 0x8e, 0x79, 0x18, 0x08, 0x1a, 0x40, 0x1e,
+ 0x39, 0x1c, 0xa6, 0x46, 0xe3, 0x4a, 0xfe, 0x44, 0x10, 0x47, 0x40, 0x00, 0x28, 0x86, 0x28,
+ 0x8e, 0x40, 0x08, 0x28, 0x86, 0x01, 0x36, 0xdf, 0x48, 0x00, 0x78, 0xb2, 0xe7, 0x00, 0x20,
+ 0x01, 0x24, 0xa6, 0x46, 0xdd, 0x49, 0xfe, 0x44, 0x08, 0x47, 0x01, 0x1c, 0x00, 0x90, 0xdc,
+ 0x4d, 0x28, 0x68, 0x01, 0x30, 0x28, 0x60, 0x0b, 0x27, 0x7f, 0x01, 0xda, 0x4e, 0xda, 0x48,
+ 0x00, 0x8d, 0x32, 0x68, 0x10, 0x18, 0x80, 0x01, 0x80, 0x09, 0xa6, 0x46, 0xd8, 0x4a, 0xfe,
+ 0x44, 0x10, 0x47, 0x00, 0x28, 0x11, 0xdd, 0x00, 0x98, 0x30, 0x60, 0x28, 0x68, 0x03, 0x28,
+ 0x0a, 0xd9, 0x00, 0x20, 0xa6, 0x46, 0xd3, 0x49, 0xfe, 0x44, 0x08, 0x47, 0xcf, 0x48, 0x38,
+ 0x5c, 0xa6, 0x46, 0xd0, 0x49, 0xfe, 0x44, 0x08, 0x47, 0x00, 0x20, 0x28, 0x60, 0xf8, 0xbd,
+ 0x30, 0xb5, 0x05, 0x69, 0x24, 0x20, 0x00, 0x21, 0x01, 0x24, 0xa6, 0x46, 0x7a, 0x4a, 0xfe,
+ 0x44, 0x10, 0x47, 0xf3, 0x21, 0x48, 0x55, 0x51, 0x25, 0xad, 0x00, 0x28, 0x1c, 0xa6, 0x46,
+ 0x72, 0x49, 0xfe, 0x44, 0x08, 0x47, 0x00, 0x28, 0x05, 0xd1, 0x28, 0x1c, 0x70, 0x49, 0xa6,
+ 0x46, 0x70, 0x4a, 0xfe, 0x44, 0x10, 0x47, 0x30, 0xbd, 0xed, 0x49, 0x02, 0x00, 0xab, 0x11,
+ 0x08, 0x00, 0x63, 0x66, 0x08, 0x00, 0x99, 0x2d, 0x00, 0x00, 0xe9, 0x63, 0x05, 0x00, 0x41,
+ 0x69, 0x00, 0x7e, 0x00, 0x28, 0x11, 0xd1, 0xff, 0x22, 0x04, 0x32, 0x50, 0x5c, 0x01, 0x28,
+ 0x0c, 0xd1, 0xff, 0x20,
+
+ 0x01, 0x05, 0xff, 0xff, 0xa0, 0x6d, 0x08, 0x00, 0xfa, 0x05, 0x30, 0x43, 0x5c, 0x1b, 0x2b,
+ 0x07, 0xd1, 0xff, 0x23, 0x0a, 0x33, 0x5b, 0x5c, 0x01, 0x2b, 0x02, 0xd1, 0x00, 0x23, 0x53,
+ 0x54, 0x43, 0x54, 0xf7, 0x46, 0xc0, 0x46, 0x00, 0x00, 0x08, 0x00, 0x49, 0x8f, 0x03, 0x00,
+ 0x85, 0x48, 0x02, 0x00, 0x10, 0xb5, 0x80, 0x69, 0x00, 0x88, 0x02, 0x28, 0x13, 0xd1, 0x54,
+ 0x48, 0x9c, 0x30, 0x01, 0x79, 0xff, 0x29, 0x0e, 0xd0, 0x00, 0x78, 0x03, 0x28, 0x03, 0xd0,
+ 0x01, 0x28, 0x01, 0xd0, 0x02, 0x28, 0x07, 0xd1, 0x01, 0x20, 0x04, 0x1c, 0x86, 0x46, 0xa2,
+ 0x49, 0xfe, 0x44, 0x08, 0x47, 0xa2, 0x48, 0x04, 0x70, 0x10, 0xbd, 0x25, 0x00, 0x00, 0x00,
+ 0x10, 0xb5, 0xc0, 0x69, 0x80, 0x78, 0x80, 0x38, 0x00, 0x06, 0x00, 0x0e, 0x02, 0x28, 0x13,
+ 0xd1, 0x44, 0x48, 0x9c, 0x30, 0x01, 0x79, 0xff, 0x29, 0x0e, 0xd0, 0x00, 0x78, 0x03, 0x28,
+ 0x03, 0xd0, 0x01, 0x28, 0x01, 0xd0, 0x02, 0x28, 0x07, 0xd1, 0x01, 0x20, 0x04, 0x1c, 0x86,
+ 0x46, 0x93, 0x49, 0xfe, 0x44, 0x08, 0x47, 0x92, 0x48, 0x04, 0x70, 0x10, 0xbd, 0xc0, 0x46,
+ 0x69, 0x53, 0x08, 0x00, 0xff, 0x53, 0x08, 0x00, 0x10, 0xb5, 0x00, 0x69, 0xfe, 0x21, 0x09,
+ 0x5c, 0x02, 0x29, 0x06, 0xd0, 0xd0, 0x21, 0x09, 0x58, 0x82, 0x8d, 0xd2, 0x00, 0x54, 0x23,
+ 0x1b, 0x18, 0x05, 0xe0, 0x54, 0x21, 0x0b, 0x18, 0x02, 0x8d, 0x06, 0x20, 0x42, 0x43, 0xd9,
+ 0x6f, 0x50, 0x18, 0x80, 0x01, 0x81, 0x09, 0xd8, 0x6d, 0x01, 0x24, 0xa6, 0x46, 0x7f, 0x4a,
+ 0xfe, 0x44, 0x10, 0x47, 0x00, 0x28, 0x12, 0xdc, 0x28, 0x48, 0x9c, 0x30, 0x01, 0x79, 0xff,
+ 0x29, 0x0d, 0xd0, 0x00, 0x78, 0x03, 0x28, 0x03, 0xd0, 0x01, 0x28, 0x01, 0xd0, 0x02, 0x28,
+ 0x06, 0xd1, 0x20, 0x1c,
+
+ 0x01, 0x05, 0xff, 0xff, 0x9a, 0x6e, 0x08, 0x00, 0xfa, 0xa6, 0x46, 0x77, 0x49, 0xfe, 0x44,
+ 0x08, 0x47, 0x77, 0x48, 0x04, 0x70, 0x10, 0xbd, 0x10, 0xb5, 0x1b, 0x48, 0x00, 0x68, 0x50,
+ 0x28, 0x06, 0xd9, 0x17, 0x48, 0x00, 0x21, 0x01, 0x22, 0x96, 0x46, 0x78, 0x4a, 0xfe, 0x44,
+ 0x10, 0x47, 0x71, 0x48, 0x00, 0x78, 0xff, 0x21, 0x21, 0x31, 0x41, 0x43, 0x6e, 0x48, 0x41,
+ 0x18, 0x6f, 0x4c, 0x20, 0x78, 0x14, 0x28, 0x0d, 0xda, 0x00, 0x28, 0x14, 0xd0, 0x6d, 0x49,
+ 0x09, 0x78, 0xc9, 0x08, 0x05, 0xd3, 0x01, 0x20, 0x86, 0x46, 0x6b, 0x49, 0xfe, 0x44, 0x08,
+ 0x47, 0x20, 0x78, 0x40, 0x1c, 0x07, 0xe0, 0xff, 0x20, 0x08, 0x70, 0x01, 0x20, 0x86, 0x46,
+ 0x67, 0x48, 0xfe, 0x44, 0x00, 0x47, 0x00, 0x20, 0x20, 0x70, 0x10, 0xbd, 0xc0, 0x46, 0x4e,
+ 0x05, 0x00, 0x00, 0xb5, 0xcc, 0x00, 0x00, 0xf8, 0x21, 0x19, 0x00, 0xb3, 0x08, 0x05, 0x00,
+ 0x5c, 0x66, 0x08, 0x00, 0x71, 0xcd, 0x01, 0x00, 0x4a, 0x24, 0x19, 0x00, 0x54, 0x24, 0x08,
+ 0x00, 0x07, 0x0e, 0x00, 0x00, 0x21, 0xcb, 0x03, 0x00, 0x00, 0x66, 0xe3, 0x01, 0x0b, 0xc9,
+ 0x03, 0x00, 0x2b, 0xf0, 0x04, 0x00, 0x45, 0x10, 0x08, 0x00, 0xf0, 0xb5, 0x06, 0x1c, 0x74,
+ 0x69, 0x30, 0x69, 0x5d, 0x4d, 0x29, 0x78, 0x33, 0x7e, 0x0a, 0x22, 0x9b, 0x1a, 0x6d, 0xd0,
+ 0x06, 0x3b, 0x53, 0xd0, 0x31, 0x3b, 0x2e, 0xd0, 0x3b, 0x3b, 0x03, 0x2b, 0x78, 0xd8, 0xff,
+ 0x21, 0x7d, 0x31, 0x09, 0x5d, 0x02, 0x29, 0x73, 0xd1, 0xff, 0x22, 0x81, 0x32, 0x01, 0x78,
+ 0x11, 0x55, 0xff, 0x21, 0x82, 0x31, 0x09, 0x19, 0x42, 0x78, 0x01, 0x30, 0x0a, 0x70, 0xff,
+ 0x22, 0x83, 0x32, 0x12, 0x19, 0x43, 0x78, 0x13, 0x70, 0x40, 0x78, 0xff, 0x23, 0x25, 0x33,
+ 0x18, 0x55, 0x08, 0x78,
+
+ 0x01, 0x05, 0xff, 0xff, 0x94, 0x6f, 0x08, 0x00, 0xfa, 0x19, 0x28, 0x5d, 0xd1, 0x10, 0x78,
+ 0x37, 0x28, 0x5a, 0xd1, 0x20, 0x1c, 0x05, 0x21, 0x00, 0x22, 0x01, 0x25, 0xae, 0x46, 0x3d,
+ 0x4b, 0xfe, 0x44, 0x18, 0x47, 0x20, 0x1c, 0xae, 0x46, 0x3c, 0x49, 0xfe, 0x44, 0x08, 0x47,
+ 0x48, 0xe0, 0x00, 0x29, 0x0a, 0xd1, 0x8a, 0x20, 0x00, 0x19, 0x3b, 0x49, 0x30, 0x22, 0x01,
+ 0x23, 0x9e, 0x46, 0x3a, 0x4b, 0xfe, 0x44, 0x18, 0x47, 0x00, 0x28, 0x3f, 0xd1, 0xff, 0x20,
+ 0x5d, 0x30, 0x01, 0x5d, 0x05, 0x20, 0x03, 0x1c, 0x20, 0x1c, 0x41, 0x22, 0x01, 0x27, 0xbe,
+ 0x46, 0x34, 0x4f, 0xfe, 0x44, 0x38, 0x47, 0x20, 0x1c, 0x05, 0x21, 0x01, 0x22, 0x96, 0x46,
+ 0x2a, 0x4b, 0xfe, 0x44, 0x18, 0x47, 0x00, 0x20, 0x28, 0x70, 0x25, 0xe0, 0xff, 0x21, 0x7d,
+ 0x31, 0x00, 0x78, 0x08, 0x55, 0x2c, 0x4a, 0x20, 0x1c, 0x09, 0x5c, 0x53, 0x78, 0x99, 0x42,
+ 0x02, 0xdb, 0x12, 0x78, 0x91, 0x42, 0x1c, 0xdd, 0xff, 0x21, 0x79, 0x31, 0x09, 0x5c, 0x10,
+ 0x22, 0x20, 0x23, 0x01, 0x24, 0xa6, 0x46, 0x23, 0x4c, 0xfe, 0x44, 0x20, 0x47, 0x0d, 0xe0,
+ 0x24, 0x48, 0x00, 0x78, 0x33, 0x28, 0x0d, 0xdb, 0xff, 0x20, 0x79, 0x30, 0x01, 0x5d, 0x20,
+ 0x1c, 0x29, 0x23, 0x01, 0x24, 0xa6, 0x46, 0x1c, 0x4c, 0xfe, 0x44, 0x20, 0x47, 0x17, 0x48,
+ 0x16, 0x49, 0x08, 0x18, 0x30, 0x62, 0xf0, 0xbd, 0xc0, 0x46, 0xff, 0xff, 0xff, 0x01, 0x95,
+ 0x49, 0x05, 0x00, 0x5b, 0x32, 0x08, 0x00, 0xd1, 0xa1, 0x04, 0x00, 0x50, 0x66, 0x08, 0x00,
+ 0x54, 0x66, 0x08, 0x00, 0x48, 0x10, 0x08, 0x00, 0x3f, 0xa2, 0x04, 0x00, 0xab, 0xea, 0x01,
+ 0x00, 0x3d, 0x1d, 0x03, 0x00, 0x58, 0x66, 0x08, 0x00, 0xb9, 0x26, 0x08, 0x00, 0x61, 0x66,
+ 0x08, 0x00, 0x60, 0x66,
+
+ 0x01, 0x05, 0xff, 0xff, 0x8e, 0x70, 0x08, 0x00, 0xfa, 0x08, 0x00, 0x35, 0x57, 0x08, 0x00,
+ 0x5d, 0x9a, 0x03, 0x00, 0x43, 0x1c, 0x03, 0x00, 0xfd, 0x06, 0x05, 0x00, 0x7f, 0xa6, 0x01,
+ 0x00, 0xb3, 0x53, 0x04, 0x00, 0xa4, 0x0f, 0x00, 0x00, 0xf9, 0xd2, 0x00, 0x00, 0xdc, 0x0f,
+ 0x08, 0x00, 0x5f, 0x6a, 0x05, 0x00, 0xed, 0xe7, 0x00, 0x00, 0xb2, 0x11, 0x08, 0x00, 0x63,
+ 0x66, 0x08, 0x00, 0x69, 0x53, 0x08, 0x00, 0x40, 0x1e, 0x80, 0x00, 0x8c, 0x4b, 0x19, 0x50,
+ 0x8a, 0x49, 0x0a, 0x50, 0xf7, 0x46, 0xf0, 0xb5, 0x01, 0x1c, 0x88, 0x69, 0x82, 0x88, 0x53,
+ 0x04, 0x5b, 0x0c, 0x88, 0x4e, 0x88, 0x4f, 0x89, 0x4d, 0x03, 0xd0, 0x60, 0x2b, 0x01, 0xdc,
+ 0xb2, 0x42, 0x14, 0xd0, 0x82, 0x88, 0x01, 0x23, 0x1b, 0x03, 0x54, 0x04, 0x64, 0x0f, 0x24,
+ 0x03, 0x9c, 0x42, 0x08, 0xdb, 0x3b, 0x1c, 0x01, 0x33, 0x54, 0x04, 0x24, 0x0d, 0xe4, 0x00,
+ 0x9c, 0x42, 0x01, 0xda, 0xba, 0x42, 0x03, 0xd0, 0xff, 0x20, 0x88, 0x60, 0xe8, 0x1d, 0xf0,
+ 0xbd, 0x01, 0x24, 0xa6, 0x46, 0x7b, 0x49, 0xfe, 0x44, 0x08, 0x47, 0x38, 0x1c, 0xa6, 0x46,
+ 0x7a, 0x49, 0xfe, 0x44, 0x08, 0x47, 0x30, 0x1c, 0xa6, 0x46, 0x77, 0x49, 0xfe, 0x44, 0x08,
+ 0x47, 0xa6, 0x46, 0x76, 0x48, 0xfe, 0x44, 0x00, 0x47, 0x38, 0x1c, 0xa6, 0x46, 0x73, 0x49,
+ 0xfe, 0x44, 0x08, 0x47, 0xe8, 0x48, 0x01, 0x68, 0x30, 0x1c, 0xa6, 0x46, 0x71, 0x4a, 0xfe,
+ 0x44, 0x10, 0x47, 0x71, 0x48, 0x40, 0x19, 0xf0, 0xbd, 0x01, 0x1c, 0x0a, 0x7d, 0x6f, 0x48,
+ 0x00, 0x2a, 0x02, 0xd0, 0xc9, 0x68, 0x01, 0x29, 0x01, 0xd0, 0x4f, 0x30, 0xf7, 0x46, 0x31,
+ 0x30, 0xf7, 0x46, 0x41, 0x68, 0x02, 0x39, 0x41, 0x60, 0xe9, 0x48, 0x3f, 0x30, 0xf7, 0x46,
+ 0x1c, 0xb5, 0x41, 0x68,
+
+ 0x01, 0x05, 0xff, 0xff, 0x88, 0x71, 0x08, 0x00, 0xfa, 0xe8, 0x4c, 0x00, 0x29, 0x17, 0xd0,
+ 0x41, 0x69, 0xb0, 0x20, 0x40, 0x18, 0xb8, 0x31, 0x6a, 0x46, 0x01, 0x23, 0x9e, 0x46, 0xe2,
+ 0x4b, 0xfe, 0x44, 0x18, 0x47, 0x00, 0x99, 0xe2, 0x48, 0xe4, 0x38, 0x41, 0x43, 0x68, 0x46,
+ 0x80, 0x88, 0x41, 0x18, 0xff, 0x20, 0xae, 0x30, 0x81, 0x42, 0x02, 0xd9, 0x20, 0x1c, 0xbf,
+ 0x30, 0x1c, 0xbd, 0x20, 0x1c, 0xdf, 0x30, 0x1c, 0xbd, 0x10, 0xb5, 0x04, 0x1c, 0xc8, 0x68,
+ 0x0a, 0x21, 0x01, 0x22, 0x96, 0x46, 0xe0, 0x4a, 0xfe, 0x44, 0x10, 0x47, 0x00, 0x28, 0x00,
+ 0xd1, 0x8c, 0x20, 0xa0, 0x60, 0xde, 0x48, 0xdb, 0x30, 0x10, 0xbd, 0xde, 0x49, 0x04, 0x39,
+ 0x09, 0x78, 0x00, 0x29, 0x01, 0xd1, 0x00, 0x21, 0x41, 0x60, 0x41, 0x68, 0x42, 0x69, 0x51,
+ 0x1a, 0x41, 0x60, 0xd8, 0x48, 0x55, 0x30, 0xf7, 0x46, 0xd8, 0x49, 0x09, 0x78, 0x00, 0x29,
+ 0x04, 0xd1, 0x01, 0x7d, 0xd5, 0x48, 0x02, 0x30, 0xff, 0x22, 0x42, 0x54, 0xd5, 0x48, 0x4f,
+ 0x30, 0xf7, 0x46, 0x01, 0x1c, 0x8a, 0x69, 0x4b, 0x68, 0xd3, 0x48, 0x9a, 0x42, 0x01, 0xd9,
+ 0x3b, 0x30, 0xf7, 0x46, 0xca, 0x60, 0x79, 0x30, 0xf7, 0x46, 0xd1, 0x48, 0xcf, 0x49, 0x08,
+ 0x80, 0xd0, 0x48, 0xff, 0x30, 0xde, 0x30, 0xf7, 0x46, 0xc2, 0x69, 0xff, 0x21, 0x11, 0x31,
+ 0x8b, 0x5c, 0xcd, 0x49, 0x5b, 0x08, 0x08, 0xd3, 0xff, 0x23, 0x02, 0x33, 0x9a, 0x5c, 0x02,
+ 0x2a, 0x03, 0xd0, 0x01, 0x2a, 0x01, 0xd0, 0x03, 0x2a, 0x02, 0xd1, 0x08, 0x1c, 0x5b, 0x30,
+ 0xf7, 0x46, 0xff, 0x22, 0x42, 0x60, 0x08, 0x1c, 0x39, 0x30, 0xf7, 0x46, 0x00, 0xb5, 0x40,
+ 0x68, 0x01, 0x21, 0x8e, 0x46, 0xc2, 0x49, 0xfe, 0x44, 0x08, 0x47, 0xc2, 0x48, 0x57, 0x30,
+ 0x00, 0xbd, 0x02, 0x8a,
+
+ 0x01, 0x05, 0xff, 0xff, 0x82, 0x72, 0x08, 0x00, 0xfa, 0x01, 0x79, 0x0a, 0x29, 0x00, 0xdb,
+ 0x0a, 0x21, 0xe8, 0x48, 0x8a, 0x42, 0x01, 0xdd, 0x5f, 0x30, 0xf7, 0x46, 0x5b, 0x30, 0xf7,
+ 0x46, 0xf0, 0xb5, 0x01, 0x24, 0xa6, 0x46, 0xe4, 0x48, 0xfe, 0x44, 0x00, 0x47, 0x01, 0x28,
+ 0x05, 0xd0, 0xa6, 0x46, 0xe1, 0x48, 0xfe, 0x44, 0x00, 0x47, 0x04, 0x28, 0x19, 0xd1, 0x02,
+ 0x26, 0xdf, 0x4d, 0x28, 0x79, 0x00, 0x28, 0x11, 0xd0, 0xe8, 0x7a, 0x06, 0x28, 0x0e, 0xd1,
+ 0x0e, 0x20, 0x01, 0x1c, 0xea, 0x4f, 0x38, 0x1c, 0x14, 0x38, 0xa6, 0x46, 0xe7, 0x4a, 0xfe,
+ 0x44, 0x10, 0x47, 0x38, 0x1c, 0x0e, 0x21, 0xa6, 0x46, 0xe4, 0x4a, 0xfe, 0x44, 0x10, 0x47,
+ 0x70, 0x35, 0x01, 0x3e, 0xe7, 0xd1, 0xa6, 0x46, 0xe3, 0x48, 0xfe, 0x44, 0x00, 0x47, 0xe2,
+ 0x49, 0x0b, 0x48, 0x54, 0x30, 0x40, 0x18, 0xf0, 0xbd, 0xc0, 0x46, 0x04, 0xf3, 0x1a, 0x00,
+ 0x80, 0x7b, 0x08, 0x00, 0x03, 0x80, 0x00, 0x00, 0x17, 0x10, 0x00, 0x00, 0xc9, 0xfb, 0x04,
+ 0x00, 0xbb, 0x15, 0x04, 0x00, 0x7d, 0xca, 0x03, 0x00, 0x05, 0x43, 0x02, 0x00, 0x0b, 0xc9,
+ 0x03, 0x00, 0xab, 0x02, 0x00, 0x00, 0xb1, 0x33, 0x02, 0x00, 0xf0, 0xb5, 0x8d, 0xb0, 0x01,
+ 0x90, 0x81, 0x69, 0x02, 0x91, 0x01, 0x7d, 0x03, 0x91, 0x42, 0x68, 0x00, 0x92, 0x80, 0x8b,
+ 0x40, 0x00, 0x04, 0x90, 0x6b, 0x48, 0x83, 0x30, 0x00, 0x78, 0x40, 0x00, 0x05, 0x90, 0x00,
+ 0x29, 0x01, 0xd1, 0x00, 0x20, 0xe1, 0xe0, 0x04, 0x98, 0x02, 0x04, 0x12, 0x0c, 0x06, 0x92,
+ 0x02, 0x98, 0x03, 0x99, 0x6b, 0x46, 0x01, 0x24, 0xa6, 0x46, 0xc6, 0x4d, 0xfe, 0x44, 0x28,
+ 0x47, 0x07, 0x90, 0x00, 0x9e, 0x00, 0x20, 0x08, 0x90, 0x80, 0x48, 0x09, 0x90, 0x0a, 0x90,
+ 0x7f, 0xe0, 0x09, 0x98,
+
+ 0x01, 0x05, 0xff, 0xff, 0x7c, 0x73, 0x08, 0x00, 0xfa, 0x00, 0x28, 0x2b, 0xd0, 0x0b, 0x98,
+ 0x09, 0x90, 0x28, 0xe0, 0x05, 0x98, 0x87, 0x42, 0x25, 0xdb, 0x90, 0x79, 0x03, 0x28, 0x01,
+ 0xd0, 0x01, 0x28, 0x20, 0xd1, 0x79, 0x19, 0x05, 0x98, 0x08, 0x1a, 0x07, 0x99, 0xa6, 0x46,
+ 0xb8, 0x4a, 0xfe, 0x44, 0x10, 0x47, 0x07, 0x1c, 0x28, 0x1c, 0x07, 0x99, 0xa6, 0x46, 0xb5,
+ 0x4a, 0xfe, 0x44, 0x10, 0x47, 0x01, 0x04, 0x09, 0x0c, 0x3a, 0x04, 0x12, 0x0c, 0x00, 0x20,
+ 0xa6, 0x46, 0xb1, 0x4b, 0xfe, 0x44, 0x18, 0x47, 0x00, 0x28, 0x04, 0xd1, 0x0a, 0x98, 0x00,
+ 0x28, 0x03, 0xd0, 0x0a, 0x97, 0x01, 0xe0, 0x00, 0x20, 0x0a, 0x90, 0xb6, 0x68, 0x00, 0x2e,
+ 0x03, 0xd0, 0x30, 0x88, 0x07, 0x99, 0x88, 0x42, 0x49, 0xdb, 0x08, 0x98, 0x00, 0x28, 0x46,
+ 0xd1, 0x61, 0x49, 0x09, 0x98, 0x88, 0x42, 0x42, 0xd1, 0x0a, 0x98, 0x88, 0x42, 0x3f, 0xd1,
+ 0x03, 0x98, 0x00, 0x28, 0x2c, 0xd0, 0x02, 0x9d, 0x03, 0x98, 0x0c, 0x90, 0x00, 0x27, 0x28,
+ 0x88, 0x0b, 0x90, 0x04, 0x99, 0xa6, 0x46, 0x9c, 0x4a, 0xfe, 0x44, 0x10, 0x47, 0x00, 0x28,
+ 0x07, 0xd0, 0x0b, 0x99, 0x04, 0x98, 0xa6, 0x46, 0x98, 0x4a, 0xfe, 0x44, 0x10, 0x47, 0x00,
+ 0x28, 0x11, 0xd1, 0x08, 0x98, 0xb8, 0x42, 0x09, 0xd0, 0x08, 0x98, 0xc1, 0x00, 0x02, 0x98,
+ 0x40, 0x18, 0x29, 0x1c, 0x08, 0x22, 0xa6, 0x46, 0xef, 0x4b, 0xfe, 0x44, 0x18, 0x47, 0x08,
+ 0x98, 0x40, 0x1c, 0x00, 0x06, 0x00, 0x0e, 0x08, 0x90, 0x08, 0x35, 0x01, 0x37, 0x0c, 0x98,
+ 0x01, 0x38, 0x0c, 0x90, 0xd6, 0xd1, 0x08, 0x98, 0x00, 0x28, 0x0c, 0xd0, 0x02, 0x98, 0x08,
+ 0x99, 0x06, 0x9a, 0x6b, 0x46, 0xa6, 0x46, 0x85, 0x4d, 0xfe, 0x44, 0x28, 0x47, 0x07, 0x90,
+ 0x00, 0x9e, 0x3f, 0x48,
+
+ 0x01, 0x05, 0xff, 0xff, 0x76, 0x74, 0x08, 0x00, 0xfa, 0x09, 0x90, 0x0a, 0x90, 0x00, 0x2e,
+ 0x3a, 0xd0, 0x35, 0x88, 0x07, 0x98, 0x85, 0x42, 0x36, 0xda, 0xb0, 0x68, 0x00, 0x28, 0x05,
+ 0xd0, 0x00, 0x88, 0x07, 0x99, 0x88, 0x42, 0x01, 0xdc, 0x47, 0x1b, 0x04, 0xe0, 0x07, 0x98,
+ 0x40, 0x1b, 0x00, 0x99, 0x09, 0x88, 0x0f, 0x18, 0x72, 0x68, 0x91, 0x88, 0x05, 0x98, 0x40,
+ 0x18, 0x87, 0x42, 0x00, 0xda, 0x6a, 0xe7, 0x48, 0x19, 0x07, 0x99, 0xa6, 0x46, 0x73, 0x4a,
+ 0xfe, 0x44, 0x10, 0x47, 0x0b, 0x90, 0x79, 0x19, 0x05, 0x98, 0x08, 0x1a, 0x07, 0x99, 0xa6,
+ 0x46, 0x6e, 0x4a, 0xfe, 0x44, 0x10, 0x47, 0x02, 0x04, 0x12, 0x0c, 0x0b, 0x98, 0x01, 0x04,
+ 0x09, 0x0c, 0x00, 0x20, 0xa6, 0x46, 0x6a, 0x4b, 0xfe, 0x44, 0x18, 0x47, 0x00, 0x28, 0x00,
+ 0xd1, 0x48, 0xe7, 0x00, 0x20, 0x09, 0x90, 0x06, 0xe0, 0xc0, 0x46, 0xe0, 0x31, 0x08, 0x00,
+ 0x1f, 0x48, 0x09, 0x99, 0x81, 0x42, 0x02, 0xd0, 0x09, 0x98, 0x0a, 0x90, 0x02, 0xe0, 0x0a,
+ 0x99, 0x81, 0x42, 0x01, 0xd0, 0x0a, 0x98, 0x04, 0xe0, 0x06, 0x98, 0xa6, 0x46, 0xe8, 0x49,
+ 0xfe, 0x44, 0x08, 0x47, 0x01, 0x99, 0x48, 0x60, 0xe5, 0x48, 0xff, 0x30, 0x10, 0x30, 0x0d,
+ 0xb0, 0xf0, 0xbd, 0xb7, 0x4b, 0x04, 0x00, 0x4f, 0x81, 0x03, 0x00, 0xfd, 0x79, 0x00, 0x00,
+ 0xc6, 0x05, 0x00, 0x00, 0xe0, 0x49, 0x09, 0x78, 0x2a, 0x29, 0x05, 0xd0, 0x33, 0x29, 0x01,
+ 0xd1, 0x0a, 0x21, 0x02, 0xe0, 0x06, 0x21, 0x00, 0xe0, 0x08, 0x21, 0x41, 0x60, 0xf1, 0x48,
+ 0x43, 0x30, 0xf7, 0x46, 0xc0, 0x46, 0x65, 0x2d, 0x00, 0x00, 0x79, 0x47, 0x00, 0x00, 0x0d,
+ 0x13, 0x02, 0x00, 0x76, 0x24, 0x08, 0x00, 0xe0, 0xa0, 0x1b, 0x00, 0x89, 0x28, 0x05, 0x00,
+ 0x3d, 0x39, 0x02, 0x00,
+
+ 0x01, 0x05, 0xff, 0xff, 0x70, 0x75, 0x08, 0x00, 0xfa, 0x60, 0x5b, 0x08, 0x00, 0xff, 0xff,
+ 0x00, 0x00, 0xd9, 0xaa, 0x00, 0x00, 0xd5, 0x75, 0x00, 0x00, 0x23, 0x01, 0x05, 0x00, 0xb3,
+ 0x09, 0x02, 0x00, 0xfc, 0xb5, 0x00, 0x90, 0xe2, 0x48, 0x00, 0x78, 0x02, 0x28, 0x43, 0xd1,
+ 0xe1, 0x49, 0xff, 0x20, 0x41, 0x30, 0x40, 0x18, 0x01, 0x90, 0xe0, 0x48, 0x40, 0x5c, 0x00,
+ 0x26, 0x38, 0xe0, 0xb1, 0x00, 0x01, 0x98, 0x45, 0x58, 0x00, 0x2d, 0x30, 0xd0, 0xfe, 0x20,
+ 0x40, 0x5d, 0x00, 0x28, 0x2c, 0xd0, 0xf2, 0x20, 0x41, 0x5d, 0x00, 0x29, 0x28, 0xd1, 0xff,
+ 0x20, 0x02, 0x30, 0x40, 0x5d, 0x01, 0x28, 0x23, 0xd0, 0x24, 0x20, 0x01, 0x24, 0xa6, 0x46,
+ 0xe7, 0x4a, 0xfe, 0x44, 0x10, 0x47, 0x00, 0x06, 0x00, 0x0e, 0xf3, 0x22, 0x51, 0x5d, 0x81,
+ 0x42, 0x17, 0xd0, 0x50, 0x55, 0x00, 0x28, 0x14, 0xd1, 0x2f, 0x8d, 0x39, 0x1c, 0xe1, 0x48,
+ 0xa6, 0x46, 0x24, 0x4a, 0xfe, 0x44, 0x10, 0x47, 0x29, 0x8e, 0x79, 0x18, 0x08, 0x1a, 0x40,
+ 0x1e, 0x39, 0x1c, 0xa6, 0x46, 0x20, 0x4a, 0xfe, 0x44, 0x10, 0x47, 0x40, 0x00, 0x28, 0x86,
+ 0x28, 0x8e, 0x40, 0x08, 0x28, 0x86, 0x01, 0x36, 0xd8, 0x48, 0x00, 0x78, 0x86, 0x42, 0xc4,
+ 0xd3, 0xff, 0x21, 0x41, 0x31, 0x00, 0x98, 0x41, 0x60, 0xd6, 0x48, 0xd5, 0x49, 0x08, 0x18,
+ 0xfc, 0xbd, 0xf9, 0x97, 0x00, 0x00, 0x8f, 0x8d, 0x01, 0x00, 0xa4, 0x13, 0x08, 0x00, 0x10,
+ 0xb5, 0x00, 0x79, 0x01, 0x28, 0x06, 0xd1, 0x88, 0x8b, 0x09, 0x7d, 0x01, 0x22, 0x96, 0x46,
+ 0xce, 0x4a, 0xfe, 0x44, 0x10, 0x47, 0xce, 0x4c, 0x20, 0x78, 0x01, 0x28, 0x04, 0xd1, 0x01,
+ 0x20, 0x86, 0x46, 0xcc, 0x48, 0xfe, 0x44, 0x00, 0x47, 0x00, 0x20, 0x20, 0x70, 0xca, 0x49,
+ 0xc5, 0x48, 0x88, 0x38,
+
+ 0x01, 0x05, 0xff, 0xff, 0x6a, 0x76, 0x08, 0x00, 0xfa, 0x40, 0x18, 0x10, 0xbd, 0xc0, 0x46,
+ 0xe5, 0x06, 0x05, 0x00, 0x14, 0x05, 0x1a, 0x00, 0x77, 0xc5, 0x01, 0x00, 0xb9, 0xc5, 0x01,
+ 0x00, 0xa1, 0x95, 0x01, 0x00, 0x95, 0x49, 0x05, 0x00, 0x21, 0x96, 0x01, 0x00, 0xf0, 0xb5,
+ 0x86, 0xb0, 0x01, 0x92, 0x02, 0x91, 0x06, 0x1c, 0x88, 0x68, 0x00, 0x6a, 0x03, 0x90, 0x80,
+ 0x00, 0x01, 0x99, 0x44, 0x18, 0x04, 0x94, 0x04, 0x19, 0x05, 0x94, 0x04, 0x19, 0x01, 0x98,
+ 0x03, 0x99, 0x01, 0x25, 0xae, 0x46, 0xb8, 0x4a, 0xfe, 0x44, 0x10, 0x47, 0x04, 0x98, 0x03,
+ 0x99, 0xae, 0x46, 0xb5, 0x4a, 0xfe, 0x44, 0x10, 0x47, 0x05, 0x98, 0x03, 0x99, 0xae, 0x46,
+ 0xb2, 0x4a, 0xfe, 0x44, 0x10, 0x47, 0x02, 0x98, 0x80, 0x68, 0xc7, 0x69, 0x70, 0x68, 0x03,
+ 0x99, 0xae, 0x46, 0xae, 0x4a, 0xfe, 0x44, 0x10, 0x47, 0x00, 0x28, 0x50, 0xd1, 0x30, 0x68,
+ 0x39, 0x1c, 0x03, 0x9a, 0xae, 0x46, 0xab, 0x4b, 0xfe, 0x44, 0x18, 0x47, 0x00, 0x28, 0x47,
+ 0xd5, 0x70, 0x68, 0x39, 0x1c, 0x03, 0x9a, 0xae, 0x46, 0xa6, 0x4b, 0xfe, 0x44, 0x18, 0x47,
+ 0x00, 0x28, 0x3e, 0xd5, 0x30, 0x68, 0x01, 0x99, 0x02, 0x9a, 0x23, 0x1c, 0xae, 0x46, 0xa2,
+ 0x4f, 0xfe, 0x44, 0x38, 0x47, 0x00, 0x94, 0x30, 0x68, 0x01, 0x99, 0x04, 0x9a, 0x02, 0x9b,
+ 0xae, 0x46, 0x9f, 0x4f, 0xfe, 0x44, 0x38, 0x47, 0x00, 0x94, 0x30, 0x68, 0x02, 0x99, 0x89,
+ 0x68, 0xc9, 0x6a, 0x01, 0x9a, 0x02, 0x9b, 0xae, 0x46, 0x99, 0x4f, 0xfe, 0x44, 0x38, 0x47,
+ 0x01, 0x98, 0x04, 0x99, 0x05, 0x9a, 0x02, 0x9b, 0xae, 0x46, 0x96, 0x4f, 0xfe, 0x44, 0x38,
+ 0x47, 0x02, 0x98, 0x80, 0x68, 0x01, 0x6b, 0x05, 0x98, 0x01, 0x9a, 0x02, 0x9b, 0xae, 0x46,
+ 0x91, 0x4f, 0xfe, 0x44,
+
+ 0x01, 0x05, 0xff, 0xff, 0x64, 0x77, 0x08, 0x00, 0xfa, 0x38, 0x47, 0x70, 0x68, 0x04, 0x99,
+ 0x02, 0x9a, 0x23, 0x1c, 0xae, 0x46, 0x8b, 0x4c, 0xfe, 0x44, 0x20, 0x47, 0x01, 0x98, 0x04,
+ 0x99, 0x03, 0x9a, 0xae, 0x46, 0x87, 0x4b, 0xfe, 0x44, 0x18, 0x47, 0x00, 0x28, 0x02, 0xd0,
+ 0x00, 0x20, 0xc0, 0x43, 0x00, 0xe0, 0x00, 0x20, 0x06, 0xb0, 0xf0, 0xbd, 0xf0, 0xb5, 0x85,
+ 0xb0, 0x45, 0x69, 0x86, 0x69, 0xc0, 0x69, 0x02, 0x90, 0x0f, 0x6a, 0x48, 0x6a, 0x03, 0x90,
+ 0x88, 0x6b, 0x04, 0x90, 0x28, 0x1c, 0x00, 0x95, 0x31, 0x6a, 0x89, 0x00, 0x4d, 0x19, 0x01,
+ 0x95, 0x4d, 0x19, 0x31, 0x68, 0x01, 0x29, 0x0d, 0xd1, 0x72, 0x69, 0x39, 0x1c, 0x01, 0x24,
+ 0xa6, 0x46, 0x0d, 0x4b, 0xfe, 0x44, 0x18, 0x47, 0x72, 0x69, 0x01, 0x98, 0xb9, 0x18, 0xa6,
+ 0x46, 0x09, 0x4b, 0xfe, 0x44, 0x18, 0x47, 0x68, 0x46, 0x02, 0x99, 0x2a, 0x1c, 0x01, 0x24,
+ 0xa6, 0x46, 0x71, 0x4b, 0xfe, 0x44, 0x18, 0x47, 0x73, 0x49, 0x70, 0x4d, 0x00, 0x28, 0x06,
+ 0xd0, 0x0c, 0x70, 0x28, 0x1c, 0x21, 0x30, 0x0d, 0xe0, 0xc0, 0x46, 0x5d, 0x5f, 0x05, 0x00,
+ 0x00, 0x20, 0x08, 0x70, 0xb2, 0x69, 0x03, 0x98, 0x04, 0x99, 0xa6, 0x46, 0x69, 0x4b, 0xfe,
+ 0x44, 0x18, 0x47, 0x28, 0x1c, 0xa9, 0x30, 0x05, 0xb0, 0xf0, 0xbd, 0x69, 0x48, 0x00, 0x78,
+ 0x00, 0x07, 0x40, 0x0e, 0x89, 0x6b, 0x49, 0x06, 0x89, 0x0c, 0x08, 0x18, 0x64, 0x49, 0x08,
+ 0x80, 0x65, 0x48, 0xc5, 0x30, 0xf7, 0x46, 0x01, 0x1c, 0x0a, 0x79, 0x63, 0x48, 0x06, 0x2a,
+ 0x03, 0xdb, 0x92, 0x1f, 0x4a, 0x60, 0x2f, 0x30, 0xf7, 0x46, 0x79, 0x30, 0xf7, 0x46, 0x01,
+ 0x1c, 0x88, 0x69, 0x43, 0x78, 0x3e, 0x22, 0x1a, 0x40, 0x5d, 0x48, 0x06, 0x2a, 0x05, 0xdb,
+ 0x9a, 0x06, 0x92, 0x0e,
+
+ 0x01, 0x05, 0xff, 0xff, 0x5e, 0x78, 0x08, 0x00, 0xfa, 0x06, 0x3a, 0x4a, 0x60, 0x23, 0x30,
+ 0xf7, 0x46, 0x49, 0x30, 0xf7, 0x46, 0x30, 0xb5, 0x45, 0x68, 0xff, 0x20, 0x11, 0x30, 0x40,
+ 0x5d, 0x80, 0x09, 0x0c, 0xd3, 0x11, 0x21, 0x09, 0x01, 0x4a, 0x5d, 0xdf, 0x20, 0x10, 0x40,
+ 0x48, 0x55, 0x28, 0x1c, 0x00, 0x21, 0x01, 0x22, 0x96, 0x46, 0x50, 0x4a, 0xfe, 0x44, 0x10,
+ 0x47, 0x01, 0x20, 0x04, 0x1c, 0x86, 0x46, 0x4e, 0x49, 0xfe, 0x44, 0x08, 0x47, 0xa9, 0x8b,
+ 0x28, 0x1c, 0xa6, 0x46, 0x4c, 0x4a, 0xfe, 0x44, 0x10, 0x47, 0x4c, 0x48, 0x9b, 0x30, 0x30,
+ 0xbd, 0x6d, 0x95, 0x00, 0x00, 0x4d, 0x96, 0x01, 0x00, 0x69, 0x53, 0x08, 0x00, 0x10, 0xb5,
+ 0x02, 0x1c, 0x4c, 0x20, 0x43, 0x5a, 0x46, 0x48, 0x06, 0x2b, 0x0d, 0xdb, 0x19, 0x24, 0xe4,
+ 0x01, 0xa3, 0x42, 0x09, 0xdc, 0x54, 0x23, 0x59, 0x5a, 0x0a, 0x29, 0x05, 0xdb, 0xa1, 0x42,
+ 0x03, 0xdc, 0x00, 0x21, 0x51, 0x60, 0x99, 0x30, 0x10, 0xbd, 0x3f, 0x4a, 0x00, 0x21, 0xff,
+ 0x23, 0x21, 0x33, 0x4b, 0x43, 0xd3, 0x5c, 0xff, 0x2b, 0x04, 0xd0, 0x49, 0x1c, 0x09, 0x06,
+ 0x09, 0x0e, 0x0a, 0x29, 0xf4, 0xdb, 0x49, 0x1e, 0x39, 0x4a, 0x11, 0x70, 0x01, 0x21, 0x38,
+ 0x4a, 0x11, 0x70, 0xff, 0x30, 0x26, 0x30, 0x10, 0xbd, 0xc0, 0x46, 0x7b, 0x5e, 0x02, 0x00,
+ 0x45, 0x10, 0x08, 0x00, 0x54, 0x24, 0x08, 0x00, 0x07, 0x0e, 0x00, 0x00, 0x7f, 0xb5, 0x45,
+ 0x69, 0x10, 0x26, 0x32, 0x1c, 0x68, 0x46, 0x00, 0x21, 0x01, 0x24, 0xa6, 0x46, 0x2e, 0x4b,
+ 0xfe, 0x44, 0x18, 0x47, 0xff, 0x20, 0x31, 0x30, 0x40, 0x19, 0x69, 0x46, 0x32, 0x1c, 0xa6,
+ 0x46, 0x2b, 0x4b, 0xfe, 0x44, 0x18, 0x47, 0x00, 0x28, 0x08, 0xd1, 0xff, 0x20, 0x25, 0x30,
+ 0x05, 0x21, 0x41, 0x55,
+
+ 0x01, 0x05, 0xff, 0xff, 0x58, 0x79, 0x08, 0x00, 0xfa, 0x28, 0x1c, 0xa6, 0x46, 0x26, 0x49,
+ 0xfe, 0x44, 0x08, 0x47, 0x26, 0x48, 0x6f, 0x30, 0x00, 0x90, 0x7f, 0xbd, 0x25, 0x48, 0xa5,
+ 0x30, 0xf7, 0x46, 0x2b, 0xf0, 0x04, 0x00, 0xff, 0xff, 0xff, 0x01, 0x5b, 0x32, 0x08, 0x00,
+ 0x8f, 0x02, 0x00, 0x00, 0xcd, 0x92, 0x01, 0x00, 0x6f, 0x4b, 0x02, 0x00, 0x58, 0x66, 0x08,
+ 0x00, 0x43, 0x1c, 0x03, 0x00, 0xf5, 0x70, 0x00, 0x00, 0x21, 0x37, 0x05, 0x00, 0xe9, 0x36,
+ 0x05, 0x00, 0xa9, 0x36, 0x05, 0x00, 0xc3, 0x6c, 0x05, 0x00, 0xa5, 0x6c, 0x05, 0x00, 0xd1,
+ 0x1c, 0x05, 0x00, 0x8d, 0x76, 0x08, 0x00, 0x91, 0x48, 0x05, 0x00, 0x47, 0x37, 0x05, 0x00,
+ 0x63, 0x66, 0x08, 0x00, 0x1c, 0x30, 0x19, 0x00, 0x96, 0xa5, 0x1b, 0x00, 0x61, 0x61, 0x03,
+ 0x00, 0xe1, 0x72, 0x03, 0x00, 0x5f, 0x73, 0x03, 0x00, 0xf5, 0x56, 0x02, 0x00, 0xbb, 0x88,
+ 0x03, 0x00, 0x3b, 0x3b, 0x02, 0x00, 0x9d, 0xcf, 0x02, 0x00, 0x6d, 0x23, 0x03, 0x00, 0xb9,
+ 0x26, 0x08, 0x00, 0x61, 0x66, 0x08, 0x00, 0x60, 0x66, 0x08, 0x00, 0xe9, 0x63, 0x05, 0x00,
+ 0x5f, 0x6a, 0x05, 0x00, 0xd5, 0x12, 0x04, 0x00, 0x5f, 0xde, 0x04, 0x00, 0xbd, 0x65, 0x01,
+ 0x00, 0xff, 0xb5, 0x68, 0x46, 0xff, 0xf7, 0xc0, 0xf9, 0xff, 0xbd, 0xff, 0xb5, 0x68, 0x46,
+ 0xff, 0xf7, 0xd9, 0xf9, 0xff, 0xbd, 0xff, 0xb5, 0x68, 0x46, 0xff, 0xf7, 0x00, 0xf9, 0xff,
+ 0xbd, 0xff, 0xb5, 0x68, 0x46, 0xff, 0xf7, 0xb5, 0xf8, 0xff, 0xbd, 0xff, 0xb5, 0x68, 0x46,
+ 0xff, 0xf7, 0x3a, 0xfa, 0xff, 0xbd, 0xff, 0xb5, 0x68, 0x46, 0xff, 0xf7, 0x81, 0xfa, 0xff,
+ 0xbd, 0xff, 0xb5, 0x68, 0x46, 0xff, 0xf7, 0xdc, 0xf9, 0xff, 0xbd, 0xff, 0xb5, 0x68, 0x46,
+ 0xff, 0xf7, 0xf9, 0xf9,
+
+ 0x01, 0x05, 0xff, 0x6b, 0x52, 0x7a, 0x08, 0x00, 0x66, 0xff, 0xbd, 0xff, 0xb5, 0x68, 0x46,
+ 0xfe, 0xf7, 0x41, 0xfe, 0xff, 0xbd, 0xff, 0xb5, 0x68, 0x46, 0xfe, 0xf7, 0x73, 0xfe, 0xff,
+ 0xbd, 0xff, 0xb5, 0x68, 0x46, 0xfe, 0xf7, 0x19, 0xfe, 0xff, 0xbd, 0xff, 0xb5, 0x68, 0x46,
+ 0xfe, 0xf7, 0xff, 0xfd, 0xff, 0xbd, 0xff, 0xb5, 0x68, 0x46, 0xfe, 0xf7, 0x08, 0xfe, 0xff,
+ 0xbd, 0xff, 0xb5, 0x68, 0x46, 0xff, 0xf7, 0x07, 0xf8, 0xff, 0xbd, 0xff, 0xb5, 0x68, 0x46,
+ 0xff, 0xf7, 0x55, 0xf9, 0xff, 0xbd, 0xff, 0xb5, 0x68, 0x46, 0xfe, 0xf7, 0xd5, 0xfe, 0xff,
+ 0xbd, 0xff, 0xb5, 0x68, 0x46, 0xfe, 0xf7, 0x7b, 0xfe, 0xff, 0xbd, 0xff, 0xb5, 0x68, 0x46,
+ 0xfe, 0xf7, 0x9c, 0xfe, 0xff, 0xbd,
+
+ 0x01, 0x05, 0xff, 0x8d, 0x78, 0x7b, 0x08, 0x00, 0x88, 0x00, 0xb5, 0xf8, 0xf0, 0xe3, 0xfa,
+ 0x00, 0xbd, 0xd7, 0x70, 0x08, 0x00, 0x79, 0x71, 0x08, 0x00, 0x3d, 0x72, 0x08, 0x00, 0x6d,
+ 0x72, 0x08, 0x00, 0x81, 0x72, 0x08, 0x00, 0x99, 0x72, 0x08, 0x00, 0x35, 0x75, 0x08, 0x00,
+ 0x89, 0x75, 0x08, 0x00, 0x95, 0x77, 0x08, 0x00, 0x61, 0x71, 0x08, 0x00, 0xd5, 0x65, 0x08,
+ 0x00, 0xe5, 0x71, 0x08, 0x00, 0x01, 0x72, 0x08, 0x00, 0x19, 0x72, 0x08, 0x00, 0x2f, 0x72,
+ 0x08, 0x00, 0x29, 0x73, 0x08, 0x00, 0x39, 0x76, 0x08, 0x00, 0x1b, 0x78, 0x08, 0x00, 0x35,
+ 0x78, 0x08, 0x00, 0x4b, 0x78, 0x08, 0x00, 0x6b, 0x78, 0x08, 0x00, 0xc5, 0x71, 0x08, 0x00,
+ 0xbd, 0x78, 0x08, 0x00, 0x25, 0x79, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6b, 0x79, 0x08, 0x00,
+
+ 0x01, 0x05, 0xff, 0x85, 0x04, 0xf3, 0x1a, 0x00, 0x80, 0xce, 0xfb, 0x04, 0x00, 0xf4, 0x4b,
+ 0x04, 0x00, 0x0c, 0x76, 0x00, 0x00, 0x06, 0x0a, 0x02, 0x00, 0x50, 0x98, 0x00, 0x00, 0xb4,
+ 0xc6, 0x01, 0x00, 0xb8, 0x5e, 0x02, 0x00, 0x58, 0x95, 0x01, 0x00, 0x2e, 0x49, 0x05, 0x00,
+ 0xde, 0x33, 0x02, 0x00, 0x14, 0x29, 0x02, 0x00, 0x60, 0x13, 0x02, 0x00, 0xd6, 0x28, 0x05,
+ 0x00, 0x74, 0x39, 0x02, 0x00, 0x88, 0xac, 0x00, 0x00, 0x7a, 0x95, 0x00, 0x00, 0xe8, 0x72,
+ 0x00, 0x00, 0x1c, 0x62, 0x03, 0x00, 0x0e, 0x73, 0x03, 0x00, 0x7e, 0x73, 0x03, 0x00, 0x34,
+ 0xd0, 0x02, 0x00, 0x52, 0x48, 0x00, 0x00, 0x04, 0x24, 0x03, 0x00, 0xa0, 0xde, 0x04, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x5a, 0x66,
+ 0x01, 0x00,
+
+ 0x01, 0x05, 0xff, 0xff, 0x00, 0x00, 0x18, 0x00, 0xfa, 0x70, 0xb5, 0x3a, 0x4d, 0xae, 0x7f,
+ 0x01, 0x24, 0xa6, 0x46, 0x36, 0x48, 0xfe, 0x44, 0x00, 0x47, 0xb0, 0x42, 0xf8, 0xd1, 0x03,
+ 0x20, 0x17, 0x21, 0x89, 0x01, 0xa6, 0x46, 0x32, 0x4a, 0xfe, 0x44, 0x10, 0x47, 0xad, 0x7f,
+ 0xa6, 0x46, 0x2f, 0x48, 0xfe, 0x44, 0x00, 0x47, 0xa8, 0x42, 0xf9, 0xd1, 0xfe, 0xe7, 0x30,
+ 0xb5, 0x2e, 0x49, 0x08, 0x1f, 0x2e, 0x4a, 0x10, 0x60, 0x31, 0x48, 0x02, 0x1c, 0x71, 0x3a,
+ 0x93, 0x24, 0x01, 0x23, 0xa3, 0x54, 0x2b, 0x4b, 0x0b, 0x60, 0x02, 0x23, 0x13, 0x71, 0x2a,
+ 0x4b, 0x4b, 0x60, 0x03, 0x23, 0x53, 0x71, 0x29, 0x4b, 0x8b, 0x60, 0x04, 0x23, 0x03, 0x70,
+ 0x29, 0x4b, 0xcb, 0x60, 0x05, 0x23, 0x83, 0x73, 0x28, 0x4b, 0x0b, 0x61, 0x06, 0x23, 0x03,
+ 0x73, 0x27, 0x4b, 0x4b, 0x61, 0x07, 0x23, 0x43, 0x71, 0x26, 0x4b, 0x8b, 0x61, 0x08, 0x24,
+ 0x03, 0x1c, 0x33, 0x3b, 0x1c, 0x70, 0x24, 0x4b, 0xcb, 0x61, 0x09, 0x23, 0xd3, 0x74, 0x23,
+ 0x4b, 0x0b, 0x62, 0x0a, 0x23, 0xd3, 0x71, 0xd3, 0x1d, 0x22, 0x4c, 0x4c, 0x62, 0x0b, 0x24,
+ 0x44, 0x77, 0x21, 0x4c, 0x8c, 0x62, 0x0c, 0x25, 0x04, 0x1c, 0x3d, 0x3c, 0x25, 0x70, 0x1f,
+ 0x4c, 0xcc, 0x62, 0x0f, 0x38, 0x0d, 0x24, 0x04, 0x70, 0x1d, 0x4c, 0x0c, 0x63, 0x0e, 0x24,
+ 0x04, 0x73, 0x1c, 0x4c, 0x4c, 0x63, 0x0f, 0x24, 0x44, 0x73, 0x1b, 0x4c, 0x8c, 0x63, 0x10,
+ 0x24, 0x04, 0x77, 0x1a, 0x48, 0xc8, 0x63, 0x11, 0x20, 0x10, 0x70, 0x19, 0x48, 0x08, 0x64,
+ 0x12, 0x20, 0x98, 0x76, 0x18, 0x48, 0x48, 0x64, 0x30, 0xbd, 0xc0, 0x46, 0x25, 0x86, 0x04,
+ 0x00, 0x1b, 0x90, 0x04, 0x00, 0x6c, 0x52, 0x08, 0x00, 0x08, 0x66, 0x08, 0x00, 0x20, 0x55,
+ 0x08, 0x00, 0x73, 0x7a,
+
+ 0x01, 0x05, 0xff, 0xff, 0xfa, 0x00, 0x18, 0x00, 0xfa, 0x08, 0x00, 0x5f, 0x7a, 0x08, 0x00,
+ 0x55, 0x7a, 0x08, 0x00, 0x95, 0x55, 0x08, 0x00, 0xa5, 0x7a, 0x08, 0x00, 0x7d, 0x7a, 0x08,
+ 0x00, 0x69, 0x7a, 0x08, 0x00, 0xaf, 0x7a, 0x08, 0x00, 0x9b, 0x7a, 0x08, 0x00, 0x87, 0x7a,
+ 0x08, 0x00, 0x19, 0x7a, 0x08, 0x00, 0x91, 0x7a, 0x08, 0x00, 0x23, 0x7a, 0x08, 0x00, 0x05,
+ 0x7a, 0x08, 0x00, 0x0f, 0x7a, 0x08, 0x00, 0x41, 0x7a, 0x08, 0x00, 0x4b, 0x7a, 0x08, 0x00,
+ 0x2d, 0x7a, 0x08, 0x00, 0x37, 0x7a, 0x08, 0x00, 0xf0, 0xb5, 0x31, 0x4e, 0x0c, 0x22, 0x32,
+ 0x70, 0x1a, 0x23, 0x73, 0x70, 0x09, 0x20, 0xb0, 0x70, 0x18, 0x20, 0xf0, 0x70, 0x03, 0x20,
+ 0x2e, 0x4d, 0x29, 0x1c, 0x01, 0x39, 0x01, 0x24, 0xa6, 0x46, 0x2a, 0x4f, 0xfe, 0x44, 0x38,
+ 0x47, 0xb2, 0x78, 0xf3, 0x78, 0x03, 0x20, 0x29, 0x1c, 0xa6, 0x46, 0x26, 0x4e, 0xfe, 0x44,
+ 0x30, 0x47, 0x03, 0x20, 0x29, 0x1c, 0x01, 0x31, 0xa6, 0x46, 0x25, 0x4a, 0xfe, 0x44, 0x10,
+ 0x47, 0xa6, 0x46, 0x24, 0x48, 0xfe, 0x44, 0x00, 0x47, 0x23, 0x4b, 0x00, 0x21, 0x08, 0x1c,
+ 0x1a, 0x68, 0x00, 0x2a, 0x04, 0xd0, 0x02, 0x07, 0x15, 0x0f, 0x22, 0x1c, 0xaa, 0x40, 0x11,
+ 0x43, 0x02, 0x07, 0x12, 0x0f, 0x0f, 0x2a, 0x05, 0xd1, 0xc5, 0x08, 0x06, 0x22, 0x2a, 0x40,
+ 0x1b, 0x4d, 0xa9, 0x52, 0x00, 0x21, 0x04, 0x33, 0x01, 0x30, 0x20, 0x28, 0xe9, 0xd3, 0x1a,
+ 0x48, 0x01, 0x1c, 0x50, 0x31, 0x0c, 0x70, 0x0a, 0x21, 0x16, 0x4a, 0x11, 0x70, 0x33, 0x21,
+ 0x01, 0x70, 0x00, 0x25, 0x16, 0x48, 0x05, 0x60, 0x28, 0x1c, 0xa6, 0x46, 0x16, 0x49, 0xfe,
+ 0x44, 0x08, 0x47, 0x13, 0x49, 0x08, 0x60, 0x14, 0x48, 0x05, 0x60, 0x07, 0x20, 0x14, 0x49,
+ 0x08, 0x70, 0x14, 0x4a,
+
+ 0x01, 0x05, 0xff, 0x65, 0xf4, 0x01, 0x18, 0x00, 0x60, 0x91, 0x78, 0x02, 0x20, 0x08, 0x43,
+ 0x90, 0x70, 0x12, 0x48, 0x05, 0x70, 0x12, 0x48, 0x05, 0x70, 0x12, 0x48, 0x05, 0x70, 0xf0,
+ 0xbd, 0xc0, 0x46, 0xfc, 0x53, 0x08, 0x00, 0x31, 0x90, 0x04, 0x00, 0xc6, 0x05, 0x00, 0x00,
+ 0x1b, 0x90, 0x04, 0x00, 0x33, 0x00, 0x18, 0x00, 0x80, 0x7b, 0x08, 0x00, 0x84, 0xf3, 0x1a,
+ 0x00, 0x6d, 0x22, 0x08, 0x00, 0x69, 0x53, 0x08, 0x00, 0x50, 0x66, 0x08, 0x00, 0x54, 0x66,
+ 0x08, 0x00, 0xd1, 0xa1, 0x04, 0x00, 0x5c, 0x66, 0x08, 0x00, 0xb3, 0x11, 0x08, 0x00, 0xe4,
+ 0x15, 0x08, 0x00, 0x63, 0x66, 0x08, 0x00, 0x60, 0x66, 0x08, 0x00, 0x61, 0x66, 0x08, 0x00,
+
+
+ 0x01, 0x83, 0xff, 0x14, 0x79, 0x7b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ //
+ // ######
+ // ### Set the BT Core spec to 4.2 for Bluetopia stack compatibility
+ // ### Remove below VS command for default BT core spec 5.1
+ 0x01, 0x09, 0xfd, 0x08, 0x68, 0x53, 0x08, 0x00, 0x00, 0x2a, 0x00, 0xff,
+
+ // ######
+ //
+ 0x01, 0x0c, 0xfd, 0x09, 0x01, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x64, 0x00,
+
+ 0x01, 0x09, 0xfd, 0x08, 0x58, 0x60, 0x1a, 0x00, 0x00, 0x10, 0x00, 0x10,
+
+ 0x01, 0x09, 0xfd, 0x08, 0x10, 0x60, 0x1a, 0x00, 0x10, 0x00, 0x10, 0x00,
+
+ 0x01, 0x1c, 0xfd, 0x14, 0xff, 0x88, 0x13, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0x00, 0xfa, 0x00, 0xff, 0xff, 0x00,
+
+ //
+ //
+ // ##--------------------------------------------------------------------------------
+ // ## Description: ORCA_C Commercial PHY FW Initialization Script
+ // ##--------------------------------------------------------------------------------
+ 0x01, 0x76, 0xfd, 0x31, 0x01, 0x21, 0x54, 0x00, 0x00, 0x61, 0x57, 0x00, 0x00, 0x14, 0x05,
+ 0x0a, 0x05, 0x00, 0x07, 0x06, 0x0a, 0x04, 0x05, 0x08, 0x09, 0x0b, 0x0c, 0x0d, 0x0e, 0x10,
+ 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+ 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,
+
+ // BTstack: added HCI_VS_SET_POWER_VECTOR(GFSK) 0xFD82 template
+ 0x01, 0x82, 0xfd, 0x14, 0x00, 0x9c, 0x18, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xdc,
+ 0xe6, 0xf0, 0xfa, 0x04, 0x0e, 0x18, 0xff, 0x00, 0x00,
+
+ // BTstack: added HCI_VS_SET_POWER_VECTOR(EDR2) 0xFD82 template
+ 0x01, 0x82, 0xfd, 0x14, 0x01, 0x9c, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xd8,
+ 0xe2, 0xec, 0xf6, 0x00, 0x0a, 0x14, 0xff, 0x00, 0x00,
+
+ // BTstack: added HCI_VS_SET_POWER_VECTOR(EDR3) 0xFD82 for EDR3 template
+ 0x01, 0x82, 0xfd, 0x14, 0x02, 0x9c, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xd8,
+ 0xe2, 0xec, 0xf6, 0x00, 0x0a, 0x14, 0xff, 0x00, 0x00,
+
+ // BTstack: added HCI_VS_SET_CLASS2_SINGLE_POWER 0xFD87 template
+ 0x01, 0x87, 0xfd, 0x03, 0x0d, 0x0d, 0x0d,
+
+ 0x01, 0x80, 0xfd, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
+
+ 0x01, 0x80, 0xfd, 0x06, 0x3c, 0xf0, 0x5f, 0x00, 0x00, 0x00,
+
+ //
+ //
+ //
+ 0x01, 0x38, 0xfe, 0x00,
+
+ //
+ // #################################################################
+ // ## START of CC2564 Adds-On
+ // #################################################################
+ //
+ // ## Enable fast clock XTAL support
+ 0x01, 0x1c, 0xfd, 0x14, 0x01, 0x88, 0x13, 0x00, 0x00, 0xd0, 0x07, 0x00, 0x00, 0xff, 0xff,
+ 0x04, 0xff, 0xff, 0xff, 0xfa, 0x00, 0x00, 0x00, 0x00,
+
+ //
+ // ## Enable eHCILL
+ 0x01, 0x2b, 0xfd, 0x05, 0x10, 0x00, 0x50, 0x00, 0x96,
+
+ //
+ 0x01, 0x0c, 0xfd, 0x09, 0x01, 0x01, 0x00, 0xff, 0xff, 0xff, 0xff, 0x64, 0x00,
+
+ //
+ // #################################################################
+ // ## END of CC2564 Adds-On
+ // #################################################################
+ 0x01, 0x5b, 0xfd, 0x02, 0x01, 0x01,
+
+ //
+ 0x01, 0xdd, 0xfd, 0x01, 0x01,
+
+};
+
+const uint32_t cc256x_init_script_size = 6771;
+
+#endif
\ No newline at end of file
diff --git a/ports/stm32/boards/LEGO_HUB_NO6/board_init.c b/ports/stm32/boards/LEGO_HUB_NO6/board_init.c
new file mode 100644
index 000000000..3f22bfc8f
--- /dev/null
+++ b/ports/stm32/boards/LEGO_HUB_NO6/board_init.c
@@ -0,0 +1,170 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/mphal.h"
+#include "irq.h"
+
+void board_init(void) {
+ if (query_irq() == IRQ_STATE_DISABLED) {
+ enable_irq(IRQ_STATE_ENABLED);
+ }
+
+ // Enable 3V3 for all ports
+ mp_hal_pin_output(pyb_pin_PORT_3V3_EN);
+ mp_hal_pin_high(pyb_pin_PORT_3V3_EN);
+
+ // Port A
+ // Enable RX/TX buffer
+ mp_hal_pin_output(pyb_pin_PORTA_EN);
+ mp_hal_pin_low(pyb_pin_PORTA_EN);
+
+ // Port B
+ // Enable RX/TX buffer
+ mp_hal_pin_output(pyb_pin_PORTB_EN);
+ mp_hal_pin_low(pyb_pin_PORTB_EN);
+
+ // Port C
+ // Enable RX/TX buffer
+ mp_hal_pin_output(pyb_pin_PORTC_EN);
+ mp_hal_pin_low(pyb_pin_PORTC_EN);
+
+ // Port D
+ // Enable RX/TX buffer
+ mp_hal_pin_output(pyb_pin_PORTD_EN);
+ mp_hal_pin_low(pyb_pin_PORTD_EN);
+
+ // Port E
+ // Enable RX/TX buffer
+ mp_hal_pin_output(pyb_pin_PORTE_EN);
+ mp_hal_pin_low(pyb_pin_PORTE_EN);
+ // Disable RS485 driver
+ mp_hal_pin_output(pyb_pin_PORTE_RTS);
+ mp_hal_pin_low(pyb_pin_PORTE_RTS);
+
+ // Port F
+ // Enable RX/TX buffer
+ mp_hal_pin_output(pyb_pin_PORTF_EN);
+ mp_hal_pin_low(pyb_pin_PORTF_EN);
+ // Disable RS485 driver
+ mp_hal_pin_output(pyb_pin_PORTF_RTS);
+ mp_hal_pin_low(pyb_pin_PORTF_RTS);
+}
+
+#if BUILDING_MBOOT
+
+#include "mboot/mboot.h"
+#include "boardctrl.h"
+#include "adc.h"
+#include "hub_display.h"
+
+#define RESET_MODE_NUM_STATES (4)
+#define RESET_MODE_TIMEOUT_CYCLES (8)
+
+#define PATTERN_B (0x00651946)
+#define PATTERN_F (0x0021184e)
+#define PATTERN_N (0x01296ad2)
+#define PATTERN_S (0x0064104c)
+
+static void board_led_pattern(int reset_mode, uint16_t brightness) {
+ static const uint32_t pixels[] = {
+ 0,
+ PATTERN_N,
+ PATTERN_S,
+ PATTERN_F,
+ PATTERN_B,
+ };
+ uint32_t pixel = pixels[reset_mode];
+ for (int i = 0; i < 25; ++i) {
+ hub_display_set(i, brightness * ((pixel >> i) & 1));
+ }
+ hub_display_update();
+}
+
+static void board_button_init(void) {
+ mp_hal_pin_config(pin_A1, MP_HAL_PIN_MODE_ADC, MP_HAL_PIN_PULL_NONE, 0);
+ adc_config(ADC1, 12);
+}
+
+static int board_button_state(void) {
+ uint16_t value = adc_config_and_read_u16(ADC1, 1, ADC_SAMPLETIME_15CYCLES);
+ return value < 44000;
+}
+
+void board_mboot_cleanup(int reset_mode) {
+ board_led_pattern(0, 0);
+ hub_display_off();
+}
+
+void board_mboot_led_init(void) {
+ hub_display_on();
+}
+
+void board_mboot_led_state(int led, int state) {
+ if (state) {
+ hub_display_set(28, 0x7fff);
+ hub_display_set(31, 0x7fff);
+ } else {
+ hub_display_set(28, 0);
+ hub_display_set(31, 0);
+ }
+ hub_display_update();
+}
+
+int board_mboot_get_reset_mode(void) {
+ board_button_init();
+ int reset_mode = BOARDCTRL_RESET_MODE_NORMAL;
+ if (board_button_state()) {
+ // Cycle through reset modes while USR is held.
+ // Timeout is roughly 20s, where reset_mode=1.
+ systick_init();
+ hub_display_on();
+ reset_mode = 0;
+ for (int i = 0; i < (RESET_MODE_NUM_STATES * RESET_MODE_TIMEOUT_CYCLES + 1) * 32; i++) {
+ if (i % 32 == 0) {
+ if (++reset_mode > RESET_MODE_NUM_STATES) {
+ reset_mode = BOARDCTRL_RESET_MODE_NORMAL;
+ }
+ board_led_pattern(reset_mode, 0x7fff);
+ }
+ if (!board_button_state()) {
+ break;
+ }
+ mp_hal_delay_ms(19);
+ }
+ // Flash the selected reset mode.
+ for (int i = 0; i < 6; i++) {
+ board_led_pattern(reset_mode, 0x0fff);
+ mp_hal_delay_ms(50);
+ board_led_pattern(reset_mode, 0x7fff);
+ mp_hal_delay_ms(50);
+ }
+ mp_hal_delay_ms(300);
+ }
+ board_led_pattern(0, 0);
+ return reset_mode;
+}
+
+#endif
diff --git a/ports/stm32/boards/LEGO_HUB_NO6/cc2564.c b/ports/stm32/boards/LEGO_HUB_NO6/cc2564.c
new file mode 100644
index 000000000..c54daf300
--- /dev/null
+++ b/ports/stm32/boards/LEGO_HUB_NO6/cc2564.c
@@ -0,0 +1,85 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include
+
+#include "py/runtime.h"
+#include "py/mphal.h"
+#include "timer.h"
+#include "extmod/mpbthci.h"
+
+#if !BUILDING_MBOOT
+
+#define CC2564_PIN_CTS (pyb_pin_BT_CTS)
+#define CC2564_PIN_RTS (pyb_pin_BT_RTS)
+#define CC2564_PIN_BT_SLOWCLK (pyb_pin_BT_SLOWCLK)
+#define CC2564_PIN_BT_ENABLE (pyb_pin_BT_ENABLE)
+
+STATIC void cc2564_wait_cts_low(mp_hal_pin_obj_t cts, uint32_t timeout_ms) {
+ for (int i = 0; i < timeout_ms; ++i) {
+ if (mp_hal_pin_read(cts) == 0) {
+ break;
+ }
+ mp_hal_delay_ms(1);
+ }
+}
+
+int mp_bluetooth_hci_controller_init(void) {
+ // Pull BTNSHUTD low to disable chip.
+ mp_hal_pin_output(CC2564_PIN_BT_ENABLE);
+ mp_hal_pin_low(CC2564_PIN_BT_ENABLE);
+
+ // Output a 32768Hz signal on BTSLOWCLK.
+ // tim8 = pyb.Timer(8, freq=32768)
+ // tim8_ch4 = tim8.channel(4, pyb.Timer.PWM, pin=btclk)
+ // tim8_ch4.pulse_width_percent(50)
+ mp_obj_t args[6] = { MP_OBJ_NEW_SMALL_INT(8), MP_OBJ_NEW_QSTR(MP_QSTR_freq), MP_OBJ_NEW_SMALL_INT(32768), MP_OBJ_NULL };
+ mp_obj_t tim8 = pyb_timer_type.make_new(&pyb_timer_type, 1, 1, args);
+ mp_load_method(tim8, MP_QSTR_channel, args);
+ args[2] = MP_OBJ_NEW_SMALL_INT(4);
+ args[3] = MP_OBJ_NEW_SMALL_INT(0); // CHANNEL_MODE_PWM_NORMAL
+ args[4] = MP_OBJ_NEW_QSTR(MP_QSTR_pin);
+ args[5] = (mp_obj_t)CC2564_PIN_BT_SLOWCLK;
+ mp_obj_t tim8_ch4 = mp_call_method_n_kw(2, 1, args);
+ mp_load_method(tim8_ch4, MP_QSTR_pulse_width_percent, args);
+ args[2] = MP_OBJ_NEW_SMALL_INT(50);
+ mp_call_method_n_kw(1, 0, args);
+
+ // Pull BTNSHUTD high to enable chip and wait for CTS to go low to indicate ready.
+ mp_hal_pin_high(CC2564_PIN_BT_ENABLE);
+ cc2564_wait_cts_low(CC2564_PIN_CTS, 500);
+
+ return 0;
+}
+
+int mp_bluetooth_hci_controller_deinit(void) {
+ // Pull BTNSHUTD low to disable chip.
+ mp_hal_pin_low(CC2564_PIN_BT_ENABLE);
+
+ return 0;
+}
+
+#endif
diff --git a/ports/stm32/boards/LEGO_HUB_NO6/hub_display.c b/ports/stm32/boards/LEGO_HUB_NO6/hub_display.c
new file mode 100644
index 000000000..1efc388c7
--- /dev/null
+++ b/ports/stm32/boards/LEGO_HUB_NO6/hub_display.c
@@ -0,0 +1,180 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/mphal.h"
+#include "hub_display.h"
+
+// Map pixel number 0-24, and 25-36 to TLC bit number.
+static const uint8_t hub_display_pixel_map[] = {
+ // 5x5 display
+ 9, 11, 6, 1, 14,
+ 10, 19, 8, 0, 26,
+ 23, 18, 3, 2, 24,
+ 21, 20, 15, 13, 25,
+ 22, 7, 17, 12, 38,
+ // RGB Bluetooth button
+ 27, 28, 29,
+ // RGB middle button (left and right)
+ 39, 40, 41, 42, 43, 44,
+ // RGB battery indicator
+ 45, 46, 47,
+};
+
+static bool hub_display_init;
+static uint8_t hub_display_gs_state[96];
+
+static void hub_display_tim_init(void) {
+ // TLC maximum GSCLK freq: 33MHz
+
+ // tim12, ch2, pwm
+
+ TIM_TypeDef *tim = TIM12;
+
+ __HAL_RCC_TIM12_CLK_ENABLE();
+ tim->CR1 = TIM_CR1_ARPE;
+
+ // Configure PWM mode.
+ uint32_t ch = 1; // ch2
+ uint32_t reg = 6 << TIM_CCMR1_OC1M_Pos // PWM1 mode
+ | 1 << TIM_CCMR1_OC1PE_Pos // preload enabled
+ | 0 << TIM_CCMR1_CC1S_Pos // output mode
+ ;
+ uint32_t shift = 8 * (ch & 1);
+ tim->CCMR1 = (tim->CCMR1 & ~(0xff << shift)) | reg << shift;
+
+ // Enable output on pin, active high for normal channel.
+ reg = TIM_CCER_CC1E;
+ shift = 4 * ch;
+ tim->CCER = (tim->CCER & ~(0xf << shift)) | reg << shift;
+
+ // Enable the timer if it's not already running.
+ tim->CR1 |= TIM_CR1_CEN;
+
+ // fast
+ tim->PSC = 0;
+ tim->ARR = 2;
+
+ // 50% duty
+ tim->CCR2 = 2;
+ tim->EGR = 1; // UG
+
+ mp_hal_pin_config(pin_B15, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, 9);
+}
+
+static void hub_display_spi_init(void) {
+ // TLC maximum SPI freq: 25MHz
+
+ SPI_TypeDef *spi = SPI1;
+
+ __HAL_RCC_SPI1_CLK_ENABLE();
+ spi->CR1 = SPI_CR1_SSM | SPI_CR1_SSI | 0 << SPI_CR1_BR_Pos | SPI_CR1_MSTR;
+ spi->CR1 |= SPI_CR1_SPE;
+
+ mp_hal_pin_config(pin_A5, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, 5);
+ mp_hal_pin_config(pin_A6, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, 5);
+ mp_hal_pin_config(pin_A7, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, 5);
+}
+
+static void hub_display_spi_write(uint8_t value) {
+ SPI_TypeDef *spi = SPI1;
+ spi->DR = value;
+ while (!(spi->SR & SPI_SR_TXE)) {
+ }
+}
+
+// dc: dot control
+// mc: maximum current
+// bc: global brightness control
+// fc: function control
+static void hub_display_latch_ctrl(uint8_t dc, uint32_t mc, uint32_t bc, uint8_t fc) {
+ hub_display_spi_write(1); // bit 768
+ hub_display_spi_write(0x96); // bits 760-767
+ for (int i = 0; i < 48; ++i) {
+ hub_display_spi_write(0);
+ }
+ hub_display_spi_write(fc >> 2); // bits 368-375
+ hub_display_spi_write(fc << 6 | bc >> 15); // bits 360-367
+ hub_display_spi_write(bc >> 7); // bits 352-359
+ hub_display_spi_write(bc << 1 | mc >> 8); // bits 344-351
+ hub_display_spi_write(mc); // bits 336-343
+ for (int i = 0; i < 42; ++i) {
+ hub_display_spi_write(dc);
+ }
+ mp_hal_pin_high(pin_A15);
+ mp_hal_delay_us(1);
+ mp_hal_pin_low(pin_A15);
+}
+
+void hub_display_set(uint8_t led, uint16_t value) {
+ led = hub_display_pixel_map[led];
+ hub_display_gs_state[led * 2] = value;
+ hub_display_gs_state[led * 2 + 1] = value >> 8;
+}
+
+void hub_display_update(void) {
+ if (!hub_display_init) {
+ return;
+ }
+ hub_display_spi_write(0);
+ for (int i = 0; i < 96; ++i) {
+ hub_display_spi_write(hub_display_gs_state[95 - i]);
+ }
+ mp_hal_pin_high(pin_A15);
+ mp_hal_delay_us(1);
+ mp_hal_pin_low(pin_A15);
+}
+
+void hub_display_on(void) {
+ if (hub_display_init) {
+ return;
+ }
+ mp_hal_pin_output(pin_A15);
+ mp_hal_pin_low(pin_A15);
+ hub_display_spi_init();
+ for (int i = 0; i < 2; ++i) {
+ hub_display_latch_ctrl(0xff, 0, 0x1fffff, 0x11);
+ }
+ hub_display_tim_init();
+ hub_display_init = true;
+}
+
+void hub_display_off(void) {
+ if (!hub_display_init) {
+ return;
+ }
+ __HAL_RCC_TIM12_CLK_DISABLE();
+ __HAL_RCC_TIM12_FORCE_RESET();
+ __HAL_RCC_TIM12_RELEASE_RESET();
+ __HAL_RCC_SPI1_CLK_DISABLE();
+ __HAL_RCC_SPI1_FORCE_RESET();
+ __HAL_RCC_SPI1_RELEASE_RESET();
+ mp_hal_pin_config(pin_A5, MP_HAL_PIN_MODE_ANALOG, MP_HAL_PIN_PULL_NONE, 0);
+ mp_hal_pin_config(pin_A6, MP_HAL_PIN_MODE_ANALOG, MP_HAL_PIN_PULL_NONE, 0);
+ mp_hal_pin_config(pin_A7, MP_HAL_PIN_MODE_ANALOG, MP_HAL_PIN_PULL_NONE, 0);
+ mp_hal_pin_config(pin_A15, MP_HAL_PIN_MODE_ANALOG, MP_HAL_PIN_PULL_NONE, 0);
+ mp_hal_pin_config(pin_B15, MP_HAL_PIN_MODE_ANALOG, MP_HAL_PIN_PULL_NONE, 0);
+ hub_display_init = false;
+}
diff --git a/ports/stm32/boards/LEGO_HUB_NO6/hub_display.h b/ports/stm32/boards/LEGO_HUB_NO6/hub_display.h
new file mode 100644
index 000000000..7623e128a
--- /dev/null
+++ b/ports/stm32/boards/LEGO_HUB_NO6/hub_display.h
@@ -0,0 +1,4 @@
+void hub_display_on(void);
+void hub_display_off(void);
+void hub_display_update(void);
+void hub_display_set(uint8_t led, uint16_t value);
diff --git a/ports/stm32/boards/LEGO_HUB_NO6/mboot_memory.ld b/ports/stm32/boards/LEGO_HUB_NO6/mboot_memory.ld
new file mode 100644
index 000000000..dd914c8e8
--- /dev/null
+++ b/ports/stm32/boards/LEGO_HUB_NO6/mboot_memory.ld
@@ -0,0 +1,10 @@
+/*
+ Linker script fragment for mboot on an STM32xxx MCU.
+ This defines the memory sections for the bootloader to use.
+*/
+MEMORY
+{
+ FLASH_BL (rx) : ORIGIN = 0x08008000, LENGTH = 32K
+ RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 120K
+}
+
diff --git a/ports/stm32/boards/LEGO_HUB_NO6/mpconfigboard.h b/ports/stm32/boards/LEGO_HUB_NO6/mpconfigboard.h
new file mode 100644
index 000000000..b3e061efb
--- /dev/null
+++ b/ports/stm32/boards/LEGO_HUB_NO6/mpconfigboard.h
@@ -0,0 +1,141 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ * The MIT License (MIT)
+ * Copyright (c) 2021 Damien P. George
+ */
+
+#include
+
+#define MICROPY_HW_BOARD_NAME "LEGO Technic Hub No.6"
+#define MICROPY_HW_MCU_NAME "STM32F413"
+
+#define MICROPY_HW_HAS_SWITCH (0)
+#define MICROPY_HW_HAS_FLASH (1)
+#define MICROPY_PY_PYB_LEGACY (0)
+#define MICROPY_HW_ENTER_BOOTLOADER_VIA_RESET (0)
+#define MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE (0)
+#define MICROPY_HW_ENABLE_RTC (1)
+#define MICROPY_HW_ENABLE_RNG (1)
+#define MICROPY_HW_ENABLE_DAC (1)
+#define MICROPY_HW_ENABLE_USB (1)
+
+// HSE is 16MHz, CPU freq set to 100MHz, buses at maximum freq
+#define MICROPY_HW_CLK_PLLM (16)
+#define MICROPY_HW_CLK_PLLN (200)
+#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV2)
+#define MICROPY_HW_CLK_PLLQ (4)
+#define MICROPY_HW_CLK_AHB_DIV (RCC_SYSCLK_DIV1)
+#define MICROPY_HW_CLK_APB1_DIV (RCC_HCLK_DIV2)
+#define MICROPY_HW_CLK_APB2_DIV (RCC_HCLK_DIV1)
+
+// For 2.7 to 3.6 V, 75 to 100 MHz: 3 wait states.
+#define MICROPY_HW_FLASH_LATENCY FLASH_LATENCY_3
+
+// UART buses
+// Bluetooth HCI
+#define MICROPY_HW_UART2_CTS (pin_D3)
+#define MICROPY_HW_UART2_RTS (pin_D4)
+#define MICROPY_HW_UART2_TX (pin_D5)
+#define MICROPY_HW_UART2_RX (pin_D6)
+// Port B
+#define MICROPY_HW_UART4_TX (pin_D1)
+#define MICROPY_HW_UART4_RX (pin_D0)
+// Port D
+#define MICROPY_HW_UART5_TX (pin_C12)
+#define MICROPY_HW_UART5_RX (pin_D2)
+// Port A
+#define MICROPY_HW_UART7_TX (pin_E8)
+#define MICROPY_HW_UART7_RX (pin_E7)
+// Port C
+#define MICROPY_HW_UART8_TX (pin_E1)
+#define MICROPY_HW_UART8_RX (pin_E0)
+// Port F
+#define MICROPY_HW_UART9_TX (pin_D15)
+#define MICROPY_HW_UART9_RX (pin_D14)
+// Port E
+#define MICROPY_HW_UART10_TX (pin_E3)
+#define MICROPY_HW_UART10_RX (pin_E2)
+
+// SPI buses
+#define MICROPY_HW_SPI1_NSS (pin_A4) // shared with DAC
+#define MICROPY_HW_SPI1_SCK (pin_A5) // shared with DAC
+#define MICROPY_HW_SPI1_MISO (pin_A6)
+#define MICROPY_HW_SPI1_MOSI (pin_A7)
+#define MICROPY_HW_SPI2_NSS (pin_B12)
+#define MICROPY_HW_SPI2_SCK (pin_B13)
+#define MICROPY_HW_SPI2_MISO (pin_C2)
+#define MICROPY_HW_SPI2_MOSI (pin_C3)
+
+// USB config
+#define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9)
+#define MICROPY_HW_USB_FS (1)
+#define MICROPY_HW_USB_MSC (1)
+
+// Bluetooth config
+#define MICROPY_HW_BLE_UART_ID (PYB_UART_2)
+#define MICROPY_HW_BLE_UART_BAUDRATE (115200)
+#define MICROPY_HW_BLE_UART_BAUDRATE_SECONDARY (921600)
+#define MICROPY_HW_BLE_BTSTACK_CHIPSET_INSTANCE btstack_chipset_cc256x_instance()
+
+// SPI flash, for R/W storage
+// The first 1MiB is skipped because it's used by the built-in bootloader
+// Note: MICROPY_HW_SPIFLASH_OFFSET_BYTES must be a multiple of MP_SPIFLASH_ERASE_BLOCK_SIZE
+#define MICROPY_HW_SPIFLASH_OFFSET_BYTES (1024 * 1024)
+#define MICROPY_HW_SPIFLASH_BLOCKMAP(bl) ((bl) + MICROPY_HW_SPIFLASH_OFFSET_BYTES / FLASH_BLOCK_SIZE)
+#define MICROPY_HW_SPIFLASH_BLOCKMAP_EXT(bl) ((bl) + MICROPY_HW_SPIFLASH_OFFSET_BYTES / MP_SPIFLASH_ERASE_BLOCK_SIZE)
+#define MICROPY_HW_SPIFLASH_ENABLE_CACHE (1)
+#define MICROPY_HW_SPIFLASH_SIZE_BITS (256 * 1024 * 1024 - MICROPY_HW_SPIFLASH_OFFSET_BYTES * 8)
+#define MICROPY_HW_SPIFLASH_CS (MICROPY_HW_SPI2_NSS)
+#define MICROPY_HW_SPIFLASH_SCK (MICROPY_HW_SPI2_SCK)
+#define MICROPY_HW_SPIFLASH_MISO (MICROPY_HW_SPI2_MISO)
+#define MICROPY_HW_SPIFLASH_MOSI (MICROPY_HW_SPI2_MOSI)
+
+// SPI flash, block device config
+extern int32_t board_bdev_ioctl(void);
+extern struct _spi_bdev_t spi_bdev;
+#define MICROPY_HW_BDEV_IOCTL(op, arg) ( \
+ (op) == BDEV_IOCTL_NUM_BLOCKS ? (MICROPY_HW_SPIFLASH_SIZE_BITS / 8 / FLASH_BLOCK_SIZE) : \
+ (op) == BDEV_IOCTL_INIT ? board_bdev_ioctl() : \
+ spi_bdev_ioctl(&spi_bdev, (op), (arg)) \
+ )
+
+// Configuration for stardard block protocol (block size FLASH_BLOCK_SIZE).
+#define MICROPY_HW_BDEV_READBLOCKS(dest, bl, n) \
+ spi_bdev_readblocks(&spi_bdev, (dest), MICROPY_HW_SPIFLASH_BLOCKMAP(bl), (n))
+#define MICROPY_HW_BDEV_WRITEBLOCKS(src, bl, n) \
+ spi_bdev_writeblocks(&spi_bdev, (src), MICROPY_HW_SPIFLASH_BLOCKMAP(bl), (n))
+
+// Configuration for extended block protocol (block size MP_SPIFLASH_ERASE_BLOCK_SIZE).
+#define MICROPY_HW_BDEV_BLOCKSIZE_EXT (MP_SPIFLASH_ERASE_BLOCK_SIZE)
+#define MICROPY_HW_BDEV_READBLOCKS_EXT(dest, bl, off, len) \
+ (spi_bdev_readblocks_raw(&spi_bdev, (dest), MICROPY_HW_SPIFLASH_BLOCKMAP_EXT(bl), (off), (len)))
+#define MICROPY_HW_BDEV_WRITEBLOCKS_EXT(src, bl, off, len) \
+ (spi_bdev_writeblocks_raw(&spi_bdev, (src), MICROPY_HW_SPIFLASH_BLOCKMAP_EXT(bl), (off), (len)))
+#define MICROPY_HW_BDEV_ERASEBLOCKS_EXT(bl, len) \
+ (spi_bdev_eraseblocks_raw(&spi_bdev, MICROPY_HW_SPIFLASH_BLOCKMAP_EXT(bl), (len)))
+
+// Board control config
+#define MICROPY_BOARD_STARTUP board_init
+
+/******************************************************************************/
+// Bootloader configuration
+
+#define MBOOT_LEAVE_BOOTLOADER_VIA_RESET (0)
+
+#define MBOOT_LED1 0
+#define MBOOT_BOARD_LED_INIT board_mboot_led_init
+#define MBOOT_BOARD_LED_STATE board_mboot_led_state
+
+#define MBOOT_BOARD_EARLY_INIT board_init
+#define MBOOT_BOARD_CLEANUP board_mboot_cleanup
+#define MBOOT_BOARD_GET_RESET_MODE board_mboot_get_reset_mode
+
+/******************************************************************************/
+// Function declarations
+
+void board_init(void);
+void board_mboot_cleanup(int reset_mode);
+void board_mboot_led_init(void);
+void board_mboot_led_state(int led, int state);
+int board_mboot_get_reset_mode(void);
+void *btstack_chipset_cc256x_instance(void);
diff --git a/ports/stm32/boards/LEGO_HUB_NO6/mpconfigboard.mk b/ports/stm32/boards/LEGO_HUB_NO6/mpconfigboard.mk
new file mode 100644
index 000000000..8f8695a9c
--- /dev/null
+++ b/ports/stm32/boards/LEGO_HUB_NO6/mpconfigboard.mk
@@ -0,0 +1,45 @@
+MCU_SERIES = f4
+CMSIS_MCU = STM32F413xx
+AF_FILE = boards/stm32f413_af.csv
+LD_FILES = boards/LEGO_HUB_NO6/stm32f413xg.ld boards/common_bl.ld
+TEXT0_ADDR = 0x08010000
+
+BOOTLOADER_DFU_USB_VID ?= 0x0694
+BOOTLOADER_DFU_USB_PID ?= 0x0008
+
+# MicroPython settings
+MICROPY_PY_BLUETOOTH ?= 1
+MICROPY_BLUETOOTH_NIMBLE ?= 0
+MICROPY_BLUETOOTH_BTSTACK ?= 1
+MICROPY_VFS_LFS2 ?= 1
+
+ifneq ($(BUILDING_MBOOT),1)
+LIB_SRC_C += lib/btstack/chipset/cc256x/btstack_chipset_cc256x.c
+endif
+
+# Bootloader settings
+MBOOT_TEXT0_ADDR = 0x08008000
+MBOOT_LD_FILES = ../boards/LEGO_HUB_NO6/mboot_memory.ld stm32_sections.ld
+
+# Backup/restore original Hub firmware
+
+HUB_FIRMWARE = lego_hub_firmware.dfu
+HUB_FIRMWARE_ADDR = $(MBOOT_TEXT0_ADDR)
+HUB_FIRMWARE_SIZE = 0xf8000
+
+backup-hub-firmware:
+ $(Q)$(DFU_UTIL) -a 0 \
+ -d $(BOOTLOADER_DFU_USB_VID):$(BOOTLOADER_DFU_USB_PID) \
+ -U $(HUB_FIRMWARE).bin \
+ -s $(HUB_FIRMWARE_ADDR):$(HUB_FIRMWARE_SIZE)
+ $(Q)$(PYTHON) $(DFU) \
+ -b $(HUB_FIRMWARE_ADDR):$(HUB_FIRMWARE).bin \
+ -D $(BOOTLOADER_DFU_USB_VID):$(BOOTLOADER_DFU_USB_PID) \
+ $(HUB_FIRMWARE)
+ $(Q)$(RM) $(HUB_FIRMWARE).bin
+ $(ECHO) "Backup created in $(HUB_FIRMWARE)"
+
+restore-hub-firmware:
+ $(Q)$(DFU_UTIL) -a 0 \
+ -d $(BOOTLOADER_DFU_USB_VID):$(BOOTLOADER_DFU_USB_PID) \
+ -D $(HUB_FIRMWARE)
diff --git a/ports/stm32/boards/LEGO_HUB_NO6/pins.csv b/ports/stm32/boards/LEGO_HUB_NO6/pins.csv
new file mode 100644
index 000000000..9e56e2c79
--- /dev/null
+++ b/ports/stm32/boards/LEGO_HUB_NO6/pins.csv
@@ -0,0 +1,114 @@
+CHG_ISET_PWM,PA0
+BUTTONS_ADC,PA1
+BT_ENABLE,PA2
+CHG_IMON_ADC,PA3
+SND_DAC,PA4
+TLC_SCLK,PA5
+TLC_SOUT,PA6
+TLC_SIN,PA7
+PORTB_EN,PA8
+USB_VBUS,PA9
+PORTA_EN,PA10
+USB_DM,PA11
+USB_DP,PA12
+BAT_PWR_EN,PA13
+PORT_3V3_EN,PA14
+TLC_LAT,PA15
+BAT_NTC,PB0
+PORTF_M2,PB1
+PORTD_EN,PB2
+LSM6_SDA,PB3
+LSM6_INT1,PB4
+PORTE_EN,PB5
+PORTC_M1,PB6
+PORTC_M2,PB7
+PORTD_M1,PB8
+PORTD_M2,PB9
+LSM6_SCL,PB10
+,PB11
+,PB12
+,PB13
+,PB14
+TLC_GS_CLK,PB15
+BAT_IMON_ADC,PC0
+BAT_VMON_ADC,PC1
+,PC2
+,PC3
+CHGOK_CENBTN_3V3OK_ADC,PC4
+PORTF_EN,PC5
+PORTE_M1,PC6
+PORTE_M2,PC7
+PORTF_M1,PC8
+BT_SLOWCLK,PC9
+SND_AMP_EN,PC10
+,PC11
+PORTD_TX,PC12
+,PC13
+,PC14
+,PC15
+PORTB_RX,PD0
+PORTB_TX,PD1
+PORTD_RX,PD2
+BT_CTS,PD3
+BT_RTS,PD4
+BT_TX,PD5
+BT_RX,PD6
+,PD7
+,PD8
+,PD9
+,PD10
+,PD11
+,PD12
+,PD13
+PORTF_RX,PD14
+PORTF_TX,PD15
+PORTC_RX,PE0
+PORTC_TX,PE1
+PORTE_RX,PE2
+PORTE_TX,PE3
+,PE4
+PORTC_EN,PE5
+,PE6
+PORTA_RX,PE7
+PORTA_TX,PE8
+PORTA_M1,PE9
+PORTE_RTS,PE10
+PORTA_M2,PE11
+,PE12
+PORTB_M1,PE13
+PORTB_M2,PE14
+PORTF_RTS,PE15
+,PF0
+,PF1
+,PF2
+,PF3
+,PF4
+,PF5
+,PF6
+,PF7
+,PF8
+,PF9
+,PF10
+,PF11
+,PF12
+,PF13
+,PF14
+,PF15
+,PG0
+,PG1
+,PG2
+,PG3
+,PG4
+,PG5
+,PG6
+,PG7
+,PG8
+,PG9
+,PG10
+,PG11
+,PG12
+,PG13
+,PG14
+,PG15
+,PH0
+,PH1
diff --git a/ports/stm32/boards/LEGO_HUB_NO6/stm32f413xg.ld b/ports/stm32/boards/LEGO_HUB_NO6/stm32f413xg.ld
new file mode 100644
index 000000000..d3c43a694
--- /dev/null
+++ b/ports/stm32/boards/LEGO_HUB_NO6/stm32f413xg.ld
@@ -0,0 +1,27 @@
+/*
+ GNU linker script for STM32F413xg (1MB flash, 320kB RAM)
+*/
+
+/* Specify the memory areas */
+/* FLASH_FS2 is placed before FLASH_TEXT to support 1MB and 1.5MB FLASH with common code in flashbdev.c */
+MEMORY
+{
+ FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K /* entire flash */
+ FLASH_APP (rx) : ORIGIN = 0x08010000, LENGTH = 976K
+ RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 320K /* SRAM1 + SRAM2 */
+}
+
+/* produce a link error if there is not this amount of RAM for these sections */
+_minimum_stack_size = 2K;
+_minimum_heap_size = 16K;
+
+/* Define the stack. The stack is full descending so begins just above last byte
+ of RAM. Note that EABI requires the stack to be 8-byte aligned for a call. */
+_estack = ORIGIN(RAM) + LENGTH(RAM) - _estack_reserve;
+_sstack = _estack - 12K; /* tunable */
+
+/* RAM extents for the garbage collector */
+_ram_start = ORIGIN(RAM);
+_ram_end = ORIGIN(RAM) + LENGTH(RAM);
+_heap_start = _ebss; /* heap starts just after statically allocated memory */
+_heap_end = _sstack;
diff --git a/ports/stm32/boards/LEGO_HUB_NO6/stm32f4xx_hal_conf.h b/ports/stm32/boards/LEGO_HUB_NO6/stm32f4xx_hal_conf.h
new file mode 100644
index 000000000..7d6344f0a
--- /dev/null
+++ b/ports/stm32/boards/LEGO_HUB_NO6/stm32f4xx_hal_conf.h
@@ -0,0 +1,19 @@
+/* This file is part of the MicroPython project, http://micropython.org/
+ * The MIT License (MIT)
+ * Copyright (c) 2019 Damien P. George
+ */
+#ifndef MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H
+#define MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H
+
+#include "boards/stm32f4xx_hal_conf_base.h"
+
+// Oscillator values in Hz
+#define HSE_VALUE (16000000)
+#define LSE_VALUE (32768)
+#define EXTERNAL_CLOCK_VALUE (12288000)
+
+// Oscillator timeouts in ms
+#define HSE_STARTUP_TIMEOUT (100)
+#define LSE_STARTUP_TIMEOUT (5000)
+
+#endif // MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H
diff --git a/ports/stm32/boards/NUCLEO_F091RC/mpconfigboard.h b/ports/stm32/boards/NUCLEO_F091RC/mpconfigboard.h
index 7333dcd0c..a0bff5996 100644
--- a/ports/stm32/boards/NUCLEO_F091RC/mpconfigboard.h
+++ b/ports/stm32/boards/NUCLEO_F091RC/mpconfigboard.h
@@ -3,6 +3,7 @@
#define MICROPY_EMIT_THUMB (0)
#define MICROPY_EMIT_INLINE_THUMB (0)
+#define MICROPY_OPT_COMPUTED_GOTO (0)
#define MICROPY_PY_USOCKET (0)
#define MICROPY_PY_NETWORK (0)
#define MICROPY_PY_STM (0)
diff --git a/ports/stm32/boards/NUCLEO_F439ZI/mpconfigboard.h b/ports/stm32/boards/NUCLEO_F439ZI/mpconfigboard.h
new file mode 100644
index 000000000..010e3b1f5
--- /dev/null
+++ b/ports/stm32/boards/NUCLEO_F439ZI/mpconfigboard.h
@@ -0,0 +1,81 @@
+#define MICROPY_HW_BOARD_NAME "NUCLEO-F439ZI"
+#define MICROPY_HW_MCU_NAME "STM32F439ZIT6"
+
+#define MICROPY_HW_HAS_SWITCH (1)
+#define MICROPY_HW_HAS_FLASH (1)
+#define MICROPY_HW_ENABLE_RNG (1)
+#define MICROPY_HW_ENABLE_RTC (1)
+#define MICROPY_HW_ENABLE_USB (1)
+
+// HSE is 8MHz from ST-LINK, in bypass mode, run SYSCLK at 168MHz
+#define MICROPY_HW_CLK_USE_BYPASS (1)
+#define MICROPY_HW_CLK_PLLM (8)
+#define MICROPY_HW_CLK_PLLN (336)
+#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV2)
+#define MICROPY_HW_CLK_PLLQ (7)
+#define MICROPY_HW_FLASH_LATENCY FLASH_LATENCY_5
+
+// The board has a 32768Hz crystal for LSE
+#define MICROPY_HW_RTC_USE_LSE (1)
+#define MICROPY_HW_RTC_USE_US (1)
+
+// UART config
+#define MICROPY_HW_UART2_TX (pin_D5)
+#define MICROPY_HW_UART2_RX (pin_D6)
+#define MICROPY_HW_UART2_RTS (pin_D4)
+#define MICROPY_HW_UART2_CTS (pin_D3)
+#define MICROPY_HW_UART3_TX (pin_D8)
+#define MICROPY_HW_UART3_RX (pin_D9)
+#define MICROPY_HW_UART6_TX (pin_G14)
+#define MICROPY_HW_UART6_RX (pin_G9)
+#define MICROPY_HW_UART_REPL PYB_UART_3
+#define MICROPY_HW_UART_REPL_BAUD 115200
+
+// I2C buses
+#define MICROPY_HW_I2C1_SCL (pin_B8)
+#define MICROPY_HW_I2C1_SDA (pin_B9)
+#define MICROPY_HW_I2C2_SCL (pin_F1)
+#define MICROPY_HW_I2C2_SDA (pin_F0)
+
+// SPI buses
+#define MICROPY_HW_SPI1_NSS (pin_D14)
+#define MICROPY_HW_SPI1_SCK (pin_A5)
+#define MICROPY_HW_SPI1_MISO (pin_A6)
+#define MICROPY_HW_SPI1_MOSI (pin_A7)
+#define MICROPY_HW_SPI3_NSS (pin_A4)
+#define MICROPY_HW_SPI3_SCK (pin_B3)
+#define MICROPY_HW_SPI3_MISO (pin_B4)
+#define MICROPY_HW_SPI3_MOSI (pin_B5)
+
+// CAN buses
+#define MICROPY_HW_CAN1_TX (pin_D1)
+#define MICROPY_HW_CAN1_RX (pin_D0)
+
+// USRSW is pulled low; pressing the button makes the input go high.
+#define MICROPY_HW_USRSW_PIN (pin_C13)
+#define MICROPY_HW_USRSW_PULL (GPIO_NOPULL)
+#define MICROPY_HW_USRSW_EXTI_MODE (GPIO_MODE_IT_RISING)
+#define MICROPY_HW_USRSW_PRESSED (1)
+
+// LEDs
+#define MICROPY_HW_LED1 (pin_B0) // green
+#define MICROPY_HW_LED2 (pin_B7) // blue
+#define MICROPY_HW_LED3 (pin_B14) // red
+#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin))
+#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin))
+
+// USB config (CN13 - USB OTG FS)
+#define MICROPY_HW_USB_FS (1)
+#define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9)
+#define MICROPY_HW_USB_OTG_ID_PIN (pin_A10)
+
+// Ethernet via RMII
+#define MICROPY_HW_ETH_MDC (pin_C1)
+#define MICROPY_HW_ETH_MDIO (pin_A2)
+#define MICROPY_HW_ETH_RMII_REF_CLK (pin_A1)
+#define MICROPY_HW_ETH_RMII_CRS_DV (pin_A7)
+#define MICROPY_HW_ETH_RMII_RXD0 (pin_C4)
+#define MICROPY_HW_ETH_RMII_RXD1 (pin_C5)
+#define MICROPY_HW_ETH_RMII_TX_EN (pin_G11)
+#define MICROPY_HW_ETH_RMII_TXD0 (pin_G13)
+#define MICROPY_HW_ETH_RMII_TXD1 (pin_B13)
diff --git a/ports/stm32/boards/NUCLEO_F439ZI/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_F439ZI/mpconfigboard.mk
new file mode 100644
index 000000000..52702b511
--- /dev/null
+++ b/ports/stm32/boards/NUCLEO_F439ZI/mpconfigboard.mk
@@ -0,0 +1,11 @@
+MCU_SERIES = f4
+CMSIS_MCU = STM32F439xx
+AF_FILE = boards/stm32f439_af.csv
+LD_FILES = boards/stm32f439.ld boards/common_ifs.ld
+TEXT0_ADDR = 0x08000000
+TEXT1_ADDR = 0x08020000
+
+# MicroPython settings
+MICROPY_PY_LWIP = 1
+MICROPY_PY_USSL = 1
+MICROPY_SSL_MBEDTLS = 1
diff --git a/ports/stm32/boards/NUCLEO_F439ZI/pins.csv b/ports/stm32/boards/NUCLEO_F439ZI/pins.csv
new file mode 100644
index 000000000..cea3678ed
--- /dev/null
+++ b/ports/stm32/boards/NUCLEO_F439ZI/pins.csv
@@ -0,0 +1,129 @@
+,PA0
+,PA1
+,PA2
+,PA3
+,PA4
+,PA5
+,PA6
+,PA7
+,PA8
+,PA9
+,PA10
+,PA11
+,PA12
+,PA13
+,PA14
+,PA15
+,PB0
+,PB1
+,PB2
+,PB3
+,PB4
+,PB5
+,PB6
+,PB7
+,PB8
+,PB9
+,PB10
+,PB11
+,PB12
+,PB13
+,PB14
+,PB15
+,PC0
+,PC1
+,PC2
+,PC3
+,PC4
+,PC5
+,PC6
+,PC7
+,PC8
+,PC9
+,PC10
+,PC11
+,PC12
+,PC13
+,PC14
+,PC15
+,PD0
+,PD1
+,PD2
+,PD3
+,PD4
+,PD5
+,PD6
+,PD7
+,PD8
+,PD9
+,PD10
+,PD11
+,PD12
+,PD13
+,PD14
+,PD15
+,PE0
+,PE1
+,PE2
+,PE3
+,PE4
+,PE5
+,PE6
+,PE7
+,PE8
+,PE9
+,PE10
+,PE11
+,PE12
+,PE13
+,PE14
+,PE15
+,PF0
+,PF1
+,PF2
+,PF3
+,PF4
+,PF5
+,PF6
+,PF7
+,PF8
+,PF9
+,PF10
+,PF11
+,PF12
+,PF13
+,PF14
+,PF15
+,PG0
+,PG1
+,PG2
+,PG3
+,PG4
+,PG5
+,PG6
+,PG7
+,PG8
+,PG9
+,PG10
+,PG11
+,PG12
+,PG13
+,PG14
+,PG15
+SW,PC13
+LED_GREEN,PB0
+LED_BLUE,PB7
+LED_RED,PB14
+USB_VBUS,PA9
+USB_ID,PA10
+USB_DM,PA11
+USB_DP,PA12
+ETH_MDC,PC1
+ETH_MDIO,PA2
+ETH_RMII_REF_CLK,PA1
+ETH_RMII_CRS_DV,PA7
+ETH_RMII_RXD0,PC4
+ETH_RMII_RXD1,PC5
+ETH_RMII_TX_EN,PG11
+ETH_RMII_TXD0,PG13
+ETH_RMII_TXD1,PB13
diff --git a/ports/stm32/boards/NUCLEO_F439ZI/stm32f4xx_hal_conf.h b/ports/stm32/boards/NUCLEO_F439ZI/stm32f4xx_hal_conf.h
new file mode 100644
index 000000000..de19251e0
--- /dev/null
+++ b/ports/stm32/boards/NUCLEO_F439ZI/stm32f4xx_hal_conf.h
@@ -0,0 +1,19 @@
+/* This file is part of the MicroPython project, http://micropython.org/
+ * The MIT License (MIT)
+ * Copyright (c) 2019 Damien P. George
+ */
+#ifndef MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H
+#define MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H
+
+#include "boards/stm32f4xx_hal_conf_base.h"
+
+// Oscillator values in Hz
+#define HSE_VALUE (8000000)
+#define LSE_VALUE (32768)
+#define EXTERNAL_CLOCK_VALUE (12288000)
+
+// Oscillator timeouts in ms
+#define HSE_STARTUP_TIMEOUT (100)
+#define LSE_STARTUP_TIMEOUT (5000)
+
+#endif // MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H
diff --git a/ports/stm32/boards/NUCLEO_F446RE/mpconfigboard.h b/ports/stm32/boards/NUCLEO_F446RE/mpconfigboard.h
index 27845b33a..681231578 100644
--- a/ports/stm32/boards/NUCLEO_F446RE/mpconfigboard.h
+++ b/ports/stm32/boards/NUCLEO_F446RE/mpconfigboard.h
@@ -25,8 +25,8 @@
#define MICROPY_HW_UART_REPL_BAUD 115200
// I2C buses
-#define MICROPY_HW_I2C1_SCL (pin_B6) // Arduino D10, pin 17 on CN10
-#define MICROPY_HW_I2C1_SDA (pin_B7) // pin 21 on CN7
+#define MICROPY_HW_I2C1_SCL (pin_B8) // Arduino D15, pin 3 on CN10
+#define MICROPY_HW_I2C1_SDA (pin_B9) // Arduino D14, pin 5 on CN10
#define MICROPY_HW_I2C2_SCL (pin_B10) // Arduino D6, pin 25 on CN10
#define MICROPY_HW_I2C2_SDA (pin_B3) // Arduino D3, pin 31 on CN10
#define MICROPY_HW_I2C3_SCL (pin_A8) // Arduino D7, pin 23 on CN10
@@ -53,6 +53,12 @@
#define MICROPY_HW_SPI4_MISO (pin_A1) // pin 30 on CN7
#define MICROPY_HW_SPI4_MOSI (pin_A11) // pin 14 on CN10
+// CAN buses
+#define MICROPY_HW_CAN1_TX (pin_B9) // pin 5 on CN10
+#define MICROPY_HW_CAN1_RX (pin_B8) // pin 3 on CN10
+#define MICROPY_HW_CAN2_TX (pin_B6) // pin 17 on CN10
+#define MICROPY_HW_CAN2_RX (pin_B5) // pin 29 on CN10
+
// USRSW is pulled low. Pressing the button makes the input go high.
#define MICROPY_HW_USRSW_PIN (pin_C13)
#define MICROPY_HW_USRSW_PULL (GPIO_NOPULL)
diff --git a/ports/stm32/boards/NUCLEO_H743ZI/board_init.c b/ports/stm32/boards/NUCLEO_H743ZI/board_init.c
index 04149c37b..40f3730cc 100644
--- a/ports/stm32/boards/NUCLEO_H743ZI/board_init.c
+++ b/ports/stm32/boards/NUCLEO_H743ZI/board_init.c
@@ -2,7 +2,6 @@
void NUCLEO_H743ZI_board_early_init(void) {
// Turn off the USB switch
- #define USB_PowerSwitchOn pin_G6
- mp_hal_pin_output(USB_PowerSwitchOn);
- mp_hal_pin_low(USB_PowerSwitchOn);
+ mp_hal_pin_output(pyb_pin_OTG_FS_POWER);
+ mp_hal_pin_low(pyb_pin_OTG_FS_POWER);
}
diff --git a/ports/stm32/boards/NUCLEO_H743ZI2/board_init.c b/ports/stm32/boards/NUCLEO_H743ZI2/board_init.c
new file mode 100644
index 000000000..04caaaca9
--- /dev/null
+++ b/ports/stm32/boards/NUCLEO_H743ZI2/board_init.c
@@ -0,0 +1 @@
+#include "boards/NUCLEO_H743ZI/board_init.c"
diff --git a/ports/stm32/boards/NUCLEO_H743ZI2/mpconfigboard.h b/ports/stm32/boards/NUCLEO_H743ZI2/mpconfigboard.h
new file mode 100644
index 000000000..22060277d
--- /dev/null
+++ b/ports/stm32/boards/NUCLEO_H743ZI2/mpconfigboard.h
@@ -0,0 +1,25 @@
+#include "boards/NUCLEO_H743ZI/mpconfigboard.h"
+
+#undef MICROPY_HW_BOARD_NAME
+#define MICROPY_HW_BOARD_NAME "NUCLEO_H743ZI2"
+
+// The board has an external 32kHz crystal attached
+#undef MICROPY_HW_RTC_USE_LSE
+#define MICROPY_HW_RTC_USE_LSE (1)
+
+// There is no external HS crystal.
+// JP1 STLNK_RST will disable the incoming 8MHz clock
+// since it is derived from the STLINK's MCO output
+#undef MICROPY_HW_CLK_USE_BYPASS
+#define MICROPY_HW_CLK_USE_BYPASS (1)
+
+#undef MICROPY_HW_LED2
+#define MICROPY_HW_LED2 (pin_E1) // yellow
+
+// only when mboot is used
+// Define the user button for entering mboot
+#if defined(USE_MBOOT)
+#define MBOOT_BOOTPIN_PIN (pin_C13)
+#define MBOOT_BOOTPIN_PULL (MP_HAL_PIN_PULL_DOWN)
+#define MBOOT_BOOTPIN_ACTIVE (1)
+#endif
diff --git a/ports/stm32/boards/NUCLEO_H743ZI2/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_H743ZI2/mpconfigboard.mk
new file mode 100644
index 000000000..e49a4d0d6
--- /dev/null
+++ b/ports/stm32/boards/NUCLEO_H743ZI2/mpconfigboard.mk
@@ -0,0 +1 @@
+include boards/NUCLEO_H743ZI/mpconfigboard.mk
diff --git a/ports/stm32/boards/NUCLEO_H743ZI2/pins.csv b/ports/stm32/boards/NUCLEO_H743ZI2/pins.csv
new file mode 100644
index 000000000..450d6e432
--- /dev/null
+++ b/ports/stm32/boards/NUCLEO_H743ZI2/pins.csv
@@ -0,0 +1,130 @@
+A0,PA3
+A1,PC0
+A2,PC3
+A3,PB1
+A4,PC2
+A5,PF10
+A6,PF4
+A7,PF5
+A8,PF6
+D0,PB7
+D1,PB6
+D2,PG14
+D3,PE13
+D4,PE14
+D5,PE11
+D6,PE9
+D7,PG12
+D8,PF3
+D9,PD15
+D10,PD14
+D11,PB5
+D12,PA6
+D13,PA7
+D14,PB9
+D15,PB8
+D16,PC6
+D17,PB15
+D18,PB13
+D19,PB12
+D20,PA15
+D21,PC7
+D22,PB5
+D23,PB3
+D24,PA4
+D25,PB4
+D26,PG6
+D27,PB2
+D28,PD13
+D29,PD12
+D30,PD11
+D31,PE2
+D32,PA0
+D33,PB0
+D34,PE0
+D35,PB11
+D36,PB10
+D37,PE15
+D38,PE6
+D39,PE12
+D40,PE10
+D41,PE7
+D42,PE8
+D43,PC8
+D44,PC9
+D45,PC10
+D46,PC11
+D47,PC12
+D48,PD2
+D49,PG2
+D50,PG3
+D51,PD7
+D52,PD6
+D53,PD5
+D54,PD4
+D55,PD3
+D56,PE2
+D57,PE4
+D58,PE5
+D59,PE6
+D60,PE3
+D61,PF8
+D62,PF7
+D63,PF9
+D64,PG1
+D65,PG0
+D66,PD1
+D67,PD0
+D68,PF0
+D69,PF1
+D70,PF2
+D71,PE9
+D72,PB2
+DAC1,PA4
+DAC2,PA5
+LED1,PB0
+LED2,PE1
+LED3,PB14
+SW,PC13
+I2C1_SDA,PB9
+I2C1_SCL,PB8
+I2C2_SDA,PF0
+I2C2_SCL,PF1
+I2C4_SCL,PF14
+I2C4_SDA,PF15
+SD_D0,PC8
+SD_D1,PC9
+SD_D2,PC10
+SD_D3,PC11
+SD_CMD,PD2
+SD_CK,PC12
+SD_SW,PG2
+OTG_FS_POWER,PD10
+OTG_FS_OVER_CURRENT,PG7
+USB_VBUS,PA9
+USB_ID,PA10
+USB_DM,PA11
+USB_DP,PA12
+UART2_TX,PD5
+UART2_RX,PD6
+UART2_RTS,PD4
+UART2_CTS,PD3
+UART3_TX,PD8
+UART3_RX,PD9
+UART5_TX,PB6
+UART5_RX,PB12
+UART6_TX,PC6
+UART6_RX,PC7
+UART7_TX,PF7
+UART7_RX,PF6
+UART8_TX,PE1
+UART8_RX,PE0
+ETH_MDC,PC1
+ETH_MDIO,PA2
+ETH_RMII_REF_CLK,PA1
+ETH_RMII_CRS_DV,PA7
+ETH_RMII_RXD0,PC4
+ETH_RMII_RXD1,PC5
+ETH_RMII_TX_EN,PG11
+ETH_RMII_TXD0,PG13
+ETH_RMII_TXD1,PB13
diff --git a/ports/stm32/boards/NUCLEO_H743ZI2/stm32h7xx_hal_conf.h b/ports/stm32/boards/NUCLEO_H743ZI2/stm32h7xx_hal_conf.h
new file mode 100644
index 000000000..61f202e62
--- /dev/null
+++ b/ports/stm32/boards/NUCLEO_H743ZI2/stm32h7xx_hal_conf.h
@@ -0,0 +1 @@
+#include "boards/NUCLEO_H743ZI/stm32h7xx_hal_conf.h"
diff --git a/ports/stm32/boards/NUCLEO_L073RZ/mpconfigboard.h b/ports/stm32/boards/NUCLEO_L073RZ/mpconfigboard.h
index b7f7bc4c8..c8c809eb4 100644
--- a/ports/stm32/boards/NUCLEO_L073RZ/mpconfigboard.h
+++ b/ports/stm32/boards/NUCLEO_L073RZ/mpconfigboard.h
@@ -7,6 +7,7 @@
#define MICROPY_EMIT_THUMB (0)
#define MICROPY_EMIT_INLINE_THUMB (0)
+#define MICROPY_OPT_COMPUTED_GOTO (0)
#define MICROPY_PY_BUILTINS_COMPLEX (0)
#define MICROPY_PY_GENERATOR_PEND_THROW (0)
#define MICROPY_PY_MATH (0)
@@ -19,6 +20,8 @@
#define MICROPY_PY_UHEAPQ (0)
#define MICROPY_PY_UTIMEQ (0)
+#define MICROPY_PY_MACHINE_BITSTREAM (0)
+
#define MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE (0)
#define MICROPY_HW_ENABLE_RTC (1)
#define MICROPY_HW_ENABLE_ADC (0)
diff --git a/ports/stm32/boards/NUCLEO_L432KC/mpconfigboard.h b/ports/stm32/boards/NUCLEO_L432KC/mpconfigboard.h
index 0f1134491..8b3a8f38b 100644
--- a/ports/stm32/boards/NUCLEO_L432KC/mpconfigboard.h
+++ b/ports/stm32/boards/NUCLEO_L432KC/mpconfigboard.h
@@ -67,5 +67,5 @@
#define MICROPY_HW_USB_FS (MICROPY_HW_ENABLE_USB)
#define MICROPY_HW_USB_MSC (0)
#define MICROPY_HW_USB_HID (0)
-#define USBD_CDC_RX_DATA_SIZE (256)
-#define USBD_CDC_TX_DATA_SIZE (256)
+#define MICROPY_HW_USB_CDC_RX_DATA_SIZE (256)
+#define MICROPY_HW_USB_CDC_TX_DATA_SIZE (256)
diff --git a/ports/stm32/boards/NUCLEO_WB55/mpconfigboard.h b/ports/stm32/boards/NUCLEO_WB55/mpconfigboard.h
index 179369d94..a7473b9d6 100644
--- a/ports/stm32/boards/NUCLEO_WB55/mpconfigboard.h
+++ b/ports/stm32/boards/NUCLEO_WB55/mpconfigboard.h
@@ -59,8 +59,8 @@
// USB config
#define MICROPY_HW_USB_FS (1)
-#define USBD_CDC_RX_DATA_SIZE (512)
-#define USBD_CDC_TX_DATA_SIZE (512)
+#define MICROPY_HW_USB_CDC_RX_DATA_SIZE (512)
+#define MICROPY_HW_USB_CDC_TX_DATA_SIZE (512)
// Bluetooth config
#define MICROPY_HW_BLE_UART_ID (0)
diff --git a/ports/stm32/boards/PYBD_SF2/mpconfigboard.h b/ports/stm32/boards/PYBD_SF2/mpconfigboard.h
index 48b3ee3eb..ed76b3f97 100644
--- a/ports/stm32/boards/PYBD_SF2/mpconfigboard.h
+++ b/ports/stm32/boards/PYBD_SF2/mpconfigboard.h
@@ -40,6 +40,7 @@
#define MICROPY_HW_ENABLE_SDCARD (1)
#define MICROPY_HW_ENABLE_MMCARD (1)
#define MICROPY_HW_ENABLE_RF_SWITCH (1)
+#define MICROPY_HW_ENABLE_I2S (1)
#define MICROPY_BOARD_EARLY_INIT board_early_init
#define MICROPY_BOARD_ENTER_STOP board_sleep(1);
@@ -146,6 +147,10 @@ extern struct _spi_bdev_t spi_bdev2;
#define MICROPY_HW_SPI3_MISO (pyb_pin_W50)
#define MICROPY_HW_SPI3_MOSI (pyb_pin_W46)
+// I2S buses
+#define MICROPY_HW_I2S1 (1)
+#define MICROPY_HW_I2S2 (1)
+
// CAN buses
#define MICROPY_HW_CAN1_NAME "X"
#define MICROPY_HW_CAN1_TX (pyb_pin_X10)
diff --git a/ports/stm32/boards/PYBV10/mpconfigboard.h b/ports/stm32/boards/PYBV10/mpconfigboard.h
index 52382f44d..50ef3ae26 100644
--- a/ports/stm32/boards/PYBV10/mpconfigboard.h
+++ b/ports/stm32/boards/PYBV10/mpconfigboard.h
@@ -11,6 +11,7 @@
#define MICROPY_HW_ENABLE_DAC (1)
#define MICROPY_HW_ENABLE_USB (1)
#define MICROPY_HW_ENABLE_SDCARD (1)
+#define MICROPY_HW_ENABLE_I2S (1)
// HSE is 8MHz
#define MICROPY_HW_CLK_PLLM (8)
@@ -64,6 +65,9 @@
#define MICROPY_HW_SPI2_MISO (pin_B14) // Y7
#define MICROPY_HW_SPI2_MOSI (pin_B15) // Y8
+// I2S buses
+#define MICROPY_HW_I2S2 (1)
+
// CAN buses
#define MICROPY_HW_CAN1_NAME "YA"
#define MICROPY_HW_CAN1_TX (pin_B9) // Y4
diff --git a/ports/stm32/boards/PYBV11/mpconfigboard.h b/ports/stm32/boards/PYBV11/mpconfigboard.h
index 8e8469404..aec83d134 100644
--- a/ports/stm32/boards/PYBV11/mpconfigboard.h
+++ b/ports/stm32/boards/PYBV11/mpconfigboard.h
@@ -11,6 +11,7 @@
#define MICROPY_HW_ENABLE_DAC (1)
#define MICROPY_HW_ENABLE_USB (1)
#define MICROPY_HW_ENABLE_SDCARD (1)
+#define MICROPY_HW_ENABLE_I2S (1)
// HSE is 12MHz
#define MICROPY_HW_CLK_PLLM (12)
@@ -64,6 +65,9 @@
#define MICROPY_HW_SPI2_MISO (pin_B14) // Y7
#define MICROPY_HW_SPI2_MOSI (pin_B15) // Y8
+// I2S buses
+#define MICROPY_HW_I2S2 (1)
+
// CAN buses
#define MICROPY_HW_CAN1_NAME "YA"
#define MICROPY_HW_CAN1_TX (pin_B9) // Y4
diff --git a/ports/stm32/boards/SPARKFUN_MICROMOD_STM32/bdev.c b/ports/stm32/boards/SPARKFUN_MICROMOD_STM32/bdev.c
new file mode 100644
index 000000000..18b5b85b1
--- /dev/null
+++ b/ports/stm32/boards/SPARKFUN_MICROMOD_STM32/bdev.c
@@ -0,0 +1,28 @@
+#include "storage.h"
+
+#if !MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE
+
+// External SPI flash uses standard SPI interface
+
+STATIC const mp_soft_spi_obj_t soft_spi_bus = {
+ .delay_half = MICROPY_HW_SOFTSPI_MIN_DELAY,
+ .polarity = 0,
+ .phase = 0,
+ .sck = MICROPY_HW_SPIFLASH_SCK,
+ .mosi = MICROPY_HW_SPIFLASH_MOSI,
+ .miso = MICROPY_HW_SPIFLASH_MISO,
+};
+
+STATIC mp_spiflash_cache_t spi_bdev_cache;
+
+const mp_spiflash_config_t spiflash_config = {
+ .bus_kind = MP_SPIFLASH_BUS_SPI,
+ .bus.u_spi.cs = MICROPY_HW_SPIFLASH_CS,
+ .bus.u_spi.data = (void*)&soft_spi_bus,
+ .bus.u_spi.proto = &mp_soft_spi_proto,
+ .cache = &spi_bdev_cache,
+};
+
+spi_bdev_t spi_bdev;
+
+#endif
diff --git a/ports/stm32/boards/SPARKFUN_MICROMOD_STM32/board_init.c b/ports/stm32/boards/SPARKFUN_MICROMOD_STM32/board_init.c
new file mode 100644
index 000000000..0184bc820
--- /dev/null
+++ b/ports/stm32/boards/SPARKFUN_MICROMOD_STM32/board_init.c
@@ -0,0 +1,11 @@
+#include "py/mphal.h"
+
+void board_early_init(void) {
+
+#if !MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE
+ // set external SPI flash CS pin high
+ mp_hal_pin_output(MICROPY_HW_SPIFLASH_CS);
+ mp_hal_pin_write(MICROPY_HW_SPIFLASH_CS, 1);
+#endif
+
+}
diff --git a/ports/stm32/boards/SPARKFUN_MICROMOD_STM32/mpconfigboard.h b/ports/stm32/boards/SPARKFUN_MICROMOD_STM32/mpconfigboard.h
new file mode 100644
index 000000000..0c451a4db
--- /dev/null
+++ b/ports/stm32/boards/SPARKFUN_MICROMOD_STM32/mpconfigboard.h
@@ -0,0 +1,100 @@
+// The Sparkfun MicroMod spec uses a zero-based peripheral numbering scheme.
+// In cases where the 0th peripheral is the default, the "0" is omitted from
+// the name (e.g. "I2C" instead of "I2C0").
+//
+// Note: UART (UART0) is not present in the edge connector pinout because the
+// primary debug serial port is exposed as a virtual serial port over USB,
+// i.e. Serial.print() should print over USB VCP, not UART_TX1.
+//
+// For more details, see https://www.sparkfun.com/micromod#tech-specs
+
+#define MICROPY_HW_BOARD_NAME "SparkFun STM32 MicroMod Processor"
+#define MICROPY_HW_MCU_NAME "STM32F405RG"
+
+// 1 = use STM32 internal flash (1 MByte)
+// 0 = use onboard external SPI flash (16 MByte)
+#define MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE (0)
+
+#define MICROPY_HW_HAS_FLASH (1)
+#define MICROPY_HW_ENABLE_RNG (1)
+#define MICROPY_HW_ENABLE_RTC (1)
+#define MICROPY_HW_ENABLE_DAC (1)
+#define MICROPY_HW_ENABLE_USB (1)
+
+// External SPI Flash config
+#if !MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE
+
+// 128 Mbit (16 MByte) external SPI flash
+#define MICROPY_HW_SPIFLASH_SIZE_BITS (128 * 1024 * 1024)
+
+#define MICROPY_HW_SPIFLASH_CS (pin_C3)
+#define MICROPY_HW_SPIFLASH_SCK (pin_C10)
+#define MICROPY_HW_SPIFLASH_MOSI (pin_C12)
+#define MICROPY_HW_SPIFLASH_MISO (pin_C11)
+
+#define MICROPY_BOARD_EARLY_INIT board_early_init
+void board_early_init(void);
+
+extern const struct _mp_spiflash_config_t spiflash_config;
+extern struct _spi_bdev_t spi_bdev;
+#define MICROPY_HW_SPIFLASH_ENABLE_CACHE (1)
+#define MICROPY_HW_BDEV_IOCTL(op, arg) ( \
+ (op) == BDEV_IOCTL_NUM_BLOCKS ? (MICROPY_HW_SPIFLASH_SIZE_BITS / 8 / FLASH_BLOCK_SIZE) : \
+ (op) == BDEV_IOCTL_INIT ? spi_bdev_ioctl(&spi_bdev, (op), (uint32_t)&spiflash_config) : \
+ spi_bdev_ioctl(&spi_bdev, (op), (arg)) \
+)
+#define MICROPY_HW_BDEV_READBLOCKS(dest, bl, n) spi_bdev_readblocks(&spi_bdev, (dest), (bl), (n))
+#define MICROPY_HW_BDEV_WRITEBLOCKS(src, bl, n) spi_bdev_writeblocks(&spi_bdev, (src), (bl), (n))
+#define MICROPY_HW_BDEV_SPIFLASH_EXTENDED (&spi_bdev) // for extended block protocol
+
+#endif // !MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE
+
+// STM32 HSE config
+// The module has a 12 MHz crystal for the HSE oscillator.
+#define MICROPY_HW_CLK_PLLM (12)
+#define MICROPY_HW_CLK_PLLN (336)
+#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV2)
+#define MICROPY_HW_CLK_PLLQ (7)
+#define MICROPY_HW_CLK_LAST_FREQ (1)
+
+// STM32 LSE config
+// The module has a 32.768 kHz crystal for the LSE (RTC).
+#define MICROPY_HW_RTC_USE_LSE (1)
+#define MICROPY_HW_RTC_USE_US (0)
+#define MICROPY_HW_RTC_USE_CALOUT (1)
+
+// UART1 config (MicroMod UART1)
+#define MICROPY_HW_UART1_NAME "UART1"
+#define MICROPY_HW_UART1_TX (pin_A2)
+#define MICROPY_HW_UART1_RX (pin_A3)
+
+// CAN1 config (MicroMod CAN)
+#define MICROPY_HW_CAN1_NAME "CAN"
+#define MICROPY_HW_CAN1_TX (pin_B9)
+#define MICROPY_HW_CAN1_RX (pin_B8)
+
+// I2C1 config (MicroMod I2C)
+#define MICROPY_HW_I2C1_NAME "I2C"
+#define MICROPY_HW_I2C1_SCL (pin_B10)
+#define MICROPY_HW_I2C1_SDA (pin_B11)
+
+// I2C2 config (MicroMod I2C1)
+#define MICROPY_HW_I2C2_NAME "I2C1"
+#define MICROPY_HW_I2C2_SCL (pin_B6)
+#define MICROPY_HW_I2C2_SDA (pin_B7)
+
+// SPI1 config (MicroMod SPI)
+#define MICROPY_HW_SPI1_NAME "SPI"
+#define MICROPY_HW_SPI1_NSS (pin_C4)
+#define MICROPY_HW_SPI1_SCK (pin_A5)
+#define MICROPY_HW_SPI1_MISO (pin_A6)
+#define MICROPY_HW_SPI1_MOSI (pin_A7)
+
+// LED1 config
+// The module has a single blue status LED.
+#define MICROPY_HW_LED1 (pin_A15)
+#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin))
+#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin))
+
+// USB device config
+#define MICROPY_HW_USB_FS (1)
diff --git a/ports/stm32/boards/SPARKFUN_MICROMOD_STM32/mpconfigboard.mk b/ports/stm32/boards/SPARKFUN_MICROMOD_STM32/mpconfigboard.mk
new file mode 100644
index 000000000..cb78a7846
--- /dev/null
+++ b/ports/stm32/boards/SPARKFUN_MICROMOD_STM32/mpconfigboard.mk
@@ -0,0 +1,16 @@
+MCU_SERIES = f4
+CMSIS_MCU = STM32F405xx
+AF_FILE = boards/stm32f405_af.csv
+ifeq ($(USE_MBOOT),1)
+# When using Mboot all the text goes together after the filesystem
+LD_FILES = boards/stm32f405.ld boards/common_blifs.ld
+TEXT0_ADDR = 0x08020000
+else
+# When not using Mboot the ISR text goes first, then the rest after the filesystem
+LD_FILES = boards/stm32f405.ld boards/common_ifs.ld
+TEXT0_ADDR = 0x08000000
+TEXT1_ADDR = 0x08020000
+endif
+
+# MicroPython settings
+MICROPY_VFS_LFS2 = 1
diff --git a/ports/stm32/boards/SPARKFUN_MICROMOD_STM32/pins.csv b/ports/stm32/boards/SPARKFUN_MICROMOD_STM32/pins.csv
new file mode 100644
index 000000000..5e77de300
--- /dev/null
+++ b/ports/stm32/boards/SPARKFUN_MICROMOD_STM32/pins.csv
@@ -0,0 +1,57 @@
+G2,PA0
+BUS2,PA0
+BATT_SENSE,PA1
+UART_TX1,PA2
+UART_RX1,PA3
+AUD_LRCLK,PA4
+SPI_SCK,PA5
+SPI_MISO,PA6
+SPI_CIPO,PA6
+SPI_MOSI,PA7
+SPI_COPI,PA7
+G1,PA8
+BUS1,PA8
+USB_DN,PA11
+USB_DP,PA12
+SWDIO,PA13
+SWDCK,PA14
+STATUS_LED,PA15
+A1,PB0
+I2C_INT,PB1
+AUD_BCLK,PB3
+AUD_OUT,PB4
+AUD_IN,PB5
+I2C_SCL1,PB6
+I2C_SDA1,PB7
+CAN_RX,PB8
+CAN_TX,PB9
+I2C_SCL,PB10
+I2C_SDA,PB11
+USB_HOST_ID,PB12
+G11,PB12
+USB_HOST_VBUS,PB13
+G10,PB13
+USB_HOST_DN,PB14
+USB_HOST_DP,PB15
+D0,PC0
+D1,PC1
+G6,PC2
+BUS6,PC2
+SPI_FLASH_CS,PC3
+SPI_CS,PC4
+A0,PC5
+PWM0,PC6
+PWM1,PC7
+G3,PC8
+BUS3,PC8
+G4,PC9
+BUS4,PC9
+SPI_FLASH_SCK,PC10
+SPI_FLASH_MISO,PC11
+SPI_FLASH_MOSI,PC12
+G5,PC13
+BUS5,PC13
+OSC32_IN,PC14
+OSC32_OUT,PC15
+G0,PD2
+BUS0,PD2
diff --git a/ports/stm32/boards/SPARKFUN_MICROMOD_STM32/stm32f4xx_hal_conf.h b/ports/stm32/boards/SPARKFUN_MICROMOD_STM32/stm32f4xx_hal_conf.h
new file mode 100644
index 000000000..9719157e5
--- /dev/null
+++ b/ports/stm32/boards/SPARKFUN_MICROMOD_STM32/stm32f4xx_hal_conf.h
@@ -0,0 +1,19 @@
+/* This file is part of the MicroPython project, http://micropython.org/
+ * The MIT License (MIT)
+ * Copyright (c) 2019 Damien P. George
+ */
+#ifndef MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H
+#define MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H
+
+#include "boards/stm32f4xx_hal_conf_base.h"
+
+// Oscillator values in Hz
+#define HSE_VALUE (12000000)
+#define LSE_VALUE (32768)
+#define EXTERNAL_CLOCK_VALUE (12288000)
+
+// Oscillator timeouts in ms
+#define HSE_STARTUP_TIMEOUT (100)
+#define LSE_STARTUP_TIMEOUT (5000)
+
+#endif // MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H
diff --git a/ports/stm32/boards/STM32F429DISC/mpconfigboard.h b/ports/stm32/boards/STM32F429DISC/mpconfigboard.h
index 95cab08c8..cfd9ef9d0 100644
--- a/ports/stm32/boards/STM32F429DISC/mpconfigboard.h
+++ b/ports/stm32/boards/STM32F429DISC/mpconfigboard.h
@@ -19,8 +19,12 @@
// UART config
#define MICROPY_HW_UART1_TX (pin_A9)
#define MICROPY_HW_UART1_RX (pin_A10)
-#define MICROPY_HW_UART2_TX (pin_D8)
-#define MICROPY_HW_UART2_RX (pin_D9)
+#define MICROPY_HW_UART2_TX (pin_D5)
+#define MICROPY_HW_UART2_RX (pin_D6)
+#define MICROPY_HW_UART3_TX (pin_C10)
+#define MICROPY_HW_UART3_RX (pin_C11)
+#define MICROPY_HW_UART6_TX (pin_C6)
+#define MICROPY_HW_UART6_RX (pin_C7)
// I2C buses
#define MICROPY_HW_I2C3_SCL (pin_A8)
diff --git a/ports/stm32/boards/USBDONGLE_WB55/mpconfigboard.h b/ports/stm32/boards/USBDONGLE_WB55/mpconfigboard.h
index fdb061900..d4b12ae5b 100644
--- a/ports/stm32/boards/USBDONGLE_WB55/mpconfigboard.h
+++ b/ports/stm32/boards/USBDONGLE_WB55/mpconfigboard.h
@@ -43,8 +43,8 @@
// USB config
#define MICROPY_HW_USB_FS (1)
-#define USBD_CDC_RX_DATA_SIZE (512)
-#define USBD_CDC_TX_DATA_SIZE (512)
+#define MICROPY_HW_USB_CDC_RX_DATA_SIZE (512)
+#define MICROPY_HW_USB_CDC_TX_DATA_SIZE (512)
// Bluetooth config
#define MICROPY_HW_BLE_UART_ID (0)
diff --git a/ports/stm32/boards/make-pins.py b/ports/stm32/boards/make-pins.py
index a19532331..d898832f0 100755
--- a/ports/stm32/boards/make-pins.py
+++ b/ports/stm32/boards/make-pins.py
@@ -22,7 +22,7 @@ SUPPORTED_FN = {
CONDITIONAL_VAR = {
"I2C": "MICROPY_HW_I2C{num}_SCL",
- "I2S": "MICROPY_HW_ENABLE_I2S{num}",
+ "I2S": "MICROPY_HW_I2S{num}",
"SPI": "MICROPY_HW_SPI{num}_SCK",
"UART": "MICROPY_HW_UART{num}_TX",
"LPUART": "MICROPY_HW_LPUART{num}_TX",
@@ -287,6 +287,7 @@ class Pins(object):
def __init__(self):
self.cpu_pins = [] # list of NamedPin objects
self.board_pins = [] # list of NamedPin objects
+ self.adc_table_size = {} # maps ADC number X to size of pin_adcX table
def find_pin(self, port_num, pin_num):
for named_pin in self.cpu_pins:
@@ -353,27 +354,27 @@ class Pins(object):
self.print_named("board", self.board_pins)
def print_adc(self, adc_num):
- print("")
- print("const pin_obj_t * const pin_adc{:d}[] = {{".format(adc_num))
- for channel in range(17):
- if channel == 16:
- print("#if defined(STM32L4)")
- adc_found = False
- for named_pin in self.cpu_pins:
- pin = named_pin.pin()
- if (
- pin.is_board_pin()
- and (pin.adc_num & (1 << (adc_num - 1)))
- and (pin.adc_channel == channel)
- ):
- print(" &pin_{:s}_obj, // {:d}".format(pin.cpu_pin_name(), channel))
- adc_found = True
- break
- if not adc_found:
- print(" NULL, // {:d}".format(channel))
- if channel == 16:
- print("#endif")
- print("};")
+ adc_pins = {}
+ for named_pin in self.cpu_pins:
+ pin = named_pin.pin()
+ if (
+ pin.is_board_pin()
+ and not named_pin.is_hidden()
+ and (pin.adc_num & (1 << (adc_num - 1)))
+ ):
+ adc_pins[pin.adc_channel] = pin
+ if adc_pins:
+ table_size = max(adc_pins) + 1
+ self.adc_table_size[adc_num] = table_size
+ print("")
+ print("const pin_obj_t * const pin_adc{:d}[{:d}] = {{".format(adc_num, table_size))
+ for channel in range(table_size):
+ if channel in adc_pins:
+ obj = "&pin_{:s}_obj".format(adc_pins[channel].cpu_pin_name())
+ else:
+ obj = "NULL"
+ print(" [{:d}] = {},".format(channel, obj))
+ print("};")
def print_header(self, hdr_filename, obj_decls):
with open(hdr_filename, "wt") as hdr_file:
@@ -382,9 +383,12 @@ class Pins(object):
pin = named_pin.pin()
if pin.is_board_pin():
pin.print_header(hdr_file)
- hdr_file.write("extern const pin_obj_t * const pin_adc1[];\n")
- hdr_file.write("extern const pin_obj_t * const pin_adc2[];\n")
- hdr_file.write("extern const pin_obj_t * const pin_adc3[];\n")
+ for adc_num, table_size in self.adc_table_size.items():
+ hdr_file.write(
+ "extern const pin_obj_t * const pin_adc{:d}[{:d}];\n".format(
+ adc_num, table_size
+ )
+ )
# provide #define's mapping board to cpu name
for named_pin in self.board_pins:
hdr_file.write(
@@ -569,9 +573,8 @@ def main():
with open(args.prefix_filename, "r") as prefix_file:
print(prefix_file.read())
pins.print()
- pins.print_adc(1)
- pins.print_adc(2)
- pins.print_adc(3)
+ for i in range(1, 4):
+ pins.print_adc(i)
pins.print_header(args.hdr_filename, args.hdr_obj_decls)
pins.print_qstr(args.qstr_filename)
pins.print_af_hdr(args.af_const_filename)
diff --git a/ports/stm32/boards/stm32h7xx_hal_conf_base.h b/ports/stm32/boards/stm32h7xx_hal_conf_base.h
index c07ae93e3..08928ed59 100644
--- a/ports/stm32/boards/stm32h7xx_hal_conf_base.h
+++ b/ports/stm32/boards/stm32h7xx_hal_conf_base.h
@@ -54,6 +54,7 @@
#include "stm32h7xx_hal_usart.h"
#include "stm32h7xx_hal_wwdg.h"
#include "stm32h7xx_ll_adc.h"
+#include "stm32h7xx_ll_lpuart.h"
#include "stm32h7xx_ll_pwr.h"
#include "stm32h7xx_ll_rtc.h"
#include "stm32h7xx_ll_usart.h"
diff --git a/ports/stm32/boards/stm32l0xx_hal_conf_base.h b/ports/stm32/boards/stm32l0xx_hal_conf_base.h
index cc033666a..7b569907e 100644
--- a/ports/stm32/boards/stm32l0xx_hal_conf_base.h
+++ b/ports/stm32/boards/stm32l0xx_hal_conf_base.h
@@ -47,6 +47,7 @@
#include "stm32l0xx_hal_usart.h"
#include "stm32l0xx_hal_wwdg.h"
#include "stm32l0xx_ll_adc.h"
+#include "stm32l0xx_ll_lpuart.h"
#include "stm32l0xx_ll_rtc.h"
#include "stm32l0xx_ll_usart.h"
diff --git a/ports/stm32/boards/stm32l4xx_hal_conf_base.h b/ports/stm32/boards/stm32l4xx_hal_conf_base.h
index 8d77a80a7..4f3a78d50 100644
--- a/ports/stm32/boards/stm32l4xx_hal_conf_base.h
+++ b/ports/stm32/boards/stm32l4xx_hal_conf_base.h
@@ -51,6 +51,7 @@
#include "stm32l4xx_hal_usart.h"
#include "stm32l4xx_hal_wwdg.h"
#include "stm32l4xx_ll_adc.h"
+#include "stm32l4xx_ll_lpuart.h"
#include "stm32l4xx_ll_rtc.h"
#include "stm32l4xx_ll_usart.h"
diff --git a/ports/stm32/boards/stm32wbxx_hal_conf_base.h b/ports/stm32/boards/stm32wbxx_hal_conf_base.h
index 72af0262a..b03ad2686 100644
--- a/ports/stm32/boards/stm32wbxx_hal_conf_base.h
+++ b/ports/stm32/boards/stm32wbxx_hal_conf_base.h
@@ -42,6 +42,7 @@
#include "stm32wbxx_hal_uart.h"
#include "stm32wbxx_hal_usart.h"
#include "stm32wbxx_ll_adc.h"
+#include "stm32wbxx_ll_lpuart.h"
#include "stm32wbxx_ll_rtc.h"
#include "stm32wbxx_ll_usart.h"
diff --git a/ports/stm32/dma.c b/ports/stm32/dma.c
index de3088691..ba09dc170 100644
--- a/ports/stm32/dma.c
+++ b/ports/stm32/dma.c
@@ -103,6 +103,31 @@ static const DMA_InitTypeDef dma_init_struct_spi_i2c = {
#endif
};
+#if MICROPY_HW_ENABLE_I2S
+// Default parameters to dma_init() for i2s; Channel and Direction
+// vary depending on the peripheral instance so they get passed separately
+static const DMA_InitTypeDef dma_init_struct_i2s = {
+ #if defined(STM32F4) || defined(STM32F7)
+ .Channel = 0,
+ #elif defined(STM32H7) || defined(STM32L0) || defined(STM32L4)
+ .Request = 0,
+ #endif
+ .Direction = DMA_MEMORY_TO_PERIPH,
+ .PeriphInc = DMA_PINC_DISABLE,
+ .MemInc = DMA_MINC_ENABLE,
+ .PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD,
+ .MemDataAlignment = DMA_MDATAALIGN_HALFWORD,
+ .Mode = DMA_CIRCULAR,
+ .Priority = DMA_PRIORITY_LOW,
+ #if defined(STM32F4) || defined(STM32F7) || defined(STM32H7)
+ .FIFOMode = DMA_FIFOMODE_DISABLE,
+ .FIFOThreshold = DMA_FIFO_THRESHOLD_FULL,
+ .MemBurst = DMA_MBURST_SINGLE,
+ .PeriphBurst = DMA_PBURST_SINGLE
+ #endif
+};
+#endif
+
#if ENABLE_SDIO && !defined(STM32H7)
// Parameters to dma_init() for SDIO tx and rx.
static const DMA_InitTypeDef dma_init_struct_sdio = {
@@ -242,6 +267,10 @@ const dma_descr_t dma_I2C_3_RX = { DMA1_Stream2, DMA_CHANNEL_3, dma_id_2, &dma
const dma_descr_t dma_I2C_2_RX = { DMA1_Stream2, DMA_CHANNEL_7, dma_id_2, &dma_init_struct_spi_i2c };
const dma_descr_t dma_SPI_2_RX = { DMA1_Stream3, DMA_CHANNEL_0, dma_id_3, &dma_init_struct_spi_i2c };
const dma_descr_t dma_SPI_2_TX = { DMA1_Stream4, DMA_CHANNEL_0, dma_id_4, &dma_init_struct_spi_i2c };
+#if MICROPY_HW_ENABLE_I2S
+const dma_descr_t dma_I2S_2_RX = { DMA1_Stream3, DMA_CHANNEL_0, dma_id_3, &dma_init_struct_i2s };
+const dma_descr_t dma_I2S_2_TX = { DMA1_Stream4, DMA_CHANNEL_0, dma_id_4, &dma_init_struct_i2s };
+#endif
const dma_descr_t dma_I2C_3_TX = { DMA1_Stream4, DMA_CHANNEL_3, dma_id_4, &dma_init_struct_spi_i2c };
#if defined(STM32F7)
const dma_descr_t dma_I2C_4_TX = { DMA1_Stream5, DMA_CHANNEL_2, dma_id_5, &dma_init_struct_spi_i2c };
@@ -266,6 +295,9 @@ const dma_descr_t dma_SDMMC_2 = { DMA2_Stream0, DMA_CHANNEL_11, dma_id_8, &dma_
const dma_descr_t dma_DCMI_0 = { DMA2_Stream1, DMA_CHANNEL_1, dma_id_9, &dma_init_struct_dcmi };
#endif
const dma_descr_t dma_SPI_1_RX = { DMA2_Stream2, DMA_CHANNEL_3, dma_id_10, &dma_init_struct_spi_i2c };
+#if MICROPY_HW_ENABLE_I2S
+const dma_descr_t dma_I2S_1_RX = { DMA2_Stream2, DMA_CHANNEL_3, dma_id_10, &dma_init_struct_i2s };
+#endif
const dma_descr_t dma_SPI_5_RX = { DMA2_Stream3, DMA_CHANNEL_2, dma_id_11, &dma_init_struct_spi_i2c };
#if ENABLE_SDIO
const dma_descr_t dma_SDIO_0 = { DMA2_Stream3, DMA_CHANNEL_4, dma_id_11, &dma_init_struct_sdio };
@@ -275,6 +307,9 @@ const dma_descr_t dma_SPI_5_TX = { DMA2_Stream4, DMA_CHANNEL_2, dma_id_12, &dma
const dma_descr_t dma_SPI_4_TX = { DMA2_Stream4, DMA_CHANNEL_5, dma_id_12, &dma_init_struct_spi_i2c };
const dma_descr_t dma_SPI_6_TX = { DMA2_Stream5, DMA_CHANNEL_1, dma_id_13, &dma_init_struct_spi_i2c };
const dma_descr_t dma_SPI_1_TX = { DMA2_Stream5, DMA_CHANNEL_3, dma_id_13, &dma_init_struct_spi_i2c };
+#if MICROPY_HW_ENABLE_I2S
+const dma_descr_t dma_I2S_1_TX = { DMA2_Stream5, DMA_CHANNEL_3, dma_id_13, &dma_init_struct_i2s };
+#endif
// #if defined(STM32F7) && defined(SDMMC2) && ENABLE_SDIO
// const dma_descr_t dma_SDMMC_2 = { DMA2_Stream5, DMA_CHANNEL_11, dma_id_13, &dma_init_struct_sdio };
// #endif
diff --git a/ports/stm32/dma.h b/ports/stm32/dma.h
index 5a17276a4..8bd101a61 100644
--- a/ports/stm32/dma.h
+++ b/ports/stm32/dma.h
@@ -57,6 +57,10 @@ extern const dma_descr_t dma_SDMMC_2;
extern const dma_descr_t dma_SPI_6_RX;
extern const dma_descr_t dma_SDIO_0;
extern const dma_descr_t dma_DCMI_0;
+extern const dma_descr_t dma_I2S_1_RX;
+extern const dma_descr_t dma_I2S_1_TX;
+extern const dma_descr_t dma_I2S_2_RX;
+extern const dma_descr_t dma_I2S_2_TX;
#elif defined(STM32L0)
diff --git a/ports/stm32/eth.c b/ports/stm32/eth.c
index 79165e119..f174b6af0 100644
--- a/ports/stm32/eth.c
+++ b/ports/stm32/eth.c
@@ -27,7 +27,7 @@
#include
#include "py/mphal.h"
#include "py/mperrno.h"
-#include "lib/netutils/netutils.h"
+#include "shared/netutils/netutils.h"
#include "pin_static_af.h"
#include "modnetwork.h"
#include "mpu.h"
diff --git a/ports/stm32/flashbdev.c b/ports/stm32/flashbdev.c
index 4153a713c..6ed891300 100644
--- a/ports/stm32/flashbdev.c
+++ b/ports/stm32/flashbdev.c
@@ -157,6 +157,7 @@ int32_t flash_bdev_ioctl(uint32_t op, uint32_t arg) {
return 0;
case BDEV_IOCTL_NUM_BLOCKS:
+ // Units are FLASH_BLOCK_SIZE
return FLASH_MEM_SEG1_NUM_BLOCKS + FLASH_MEM_SEG2_NUM_BLOCKS;
case BDEV_IOCTL_IRQ_HANDLER:
diff --git a/ports/stm32/gccollect.c b/ports/stm32/gccollect.c
index 8b47b121e..bd697a2af 100644
--- a/ports/stm32/gccollect.c
+++ b/ports/stm32/gccollect.c
@@ -30,7 +30,7 @@
#include "py/mpstate.h"
#include "py/gc.h"
#include "py/mpthread.h"
-#include "lib/utils/gchelper.h"
+#include "shared/runtime/gchelper.h"
#include "gccollect.h"
#include "softtimer.h"
#include "systick.h"
diff --git a/ports/stm32/machine_bitstream.c b/ports/stm32/machine_bitstream.c
new file mode 100644
index 000000000..6cc367937
--- /dev/null
+++ b/ports/stm32/machine_bitstream.c
@@ -0,0 +1,204 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Jim Mussared
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/runtime.h"
+#include "py/mphal.h"
+#include "extmod/machine_bitstream.h"
+
+#if MICROPY_PY_MACHINE_BITSTREAM
+
+#if __CORTEX_M == 0
+
+// No cycle counter on M0, do manual cycle counting instead.
+
+// STM32F091 @ 48MHz
+#define NS_CYCLES_PER_ITER_HIGH (6)
+#define NS_CYCLES_PER_ITER_LOW (6)
+#define NS_OVERHEAD_CYCLES_HIGH (12)
+#define NS_OVERHEAD_CYCLES_LOW (18)
+
+uint32_t mp_hal_delay_ns_calc(uint32_t ns, bool high) {
+ uint32_t ncycles = SystemCoreClock / 1000000 * ns / 1000;
+ uint32_t overhead = MIN(ncycles, high ? NS_OVERHEAD_CYCLES_HIGH : NS_OVERHEAD_CYCLES_LOW);
+ return MAX(1, MP_ROUND_DIVIDE(ncycles - overhead, high ? NS_CYCLES_PER_ITER_HIGH : NS_CYCLES_PER_ITER_LOW));
+}
+
+void machine_bitstream_high_low(mp_hal_pin_obj_t pin, uint32_t *timing_ns, const uint8_t *buf, size_t len) {
+ const uint32_t high_mask = pin->pin_mask;
+ const uint32_t low_mask = pin->pin_mask << 16;
+ volatile uint32_t *bsrr = &pin->gpio->BSRR;
+
+ // Convert ns to loop iterations [high_time_0, low_time_0, high_time_1, low_time_1].
+ for (size_t i = 0; i < 4; ++i) {
+ timing_ns[i] = mp_hal_delay_ns_calc(timing_ns[i], i % 2 == 0);
+ }
+
+ mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION();
+
+ // Measured timing for F091 at 48MHz (cycle=20.83ns)
+ // timing_ns = (1,1,1,1)
+ // high: 370
+ // low: 500
+ // low8: 660
+ // timing_ns = (2,2,2,2)
+ // high: 490
+ // low: 620
+ // low8: 805
+
+ // --> high is 12 + n*6 cycles
+ // low is 18 + n*6 cycles
+
+ // NeoPixel timing (400, 850, 800, 450) (+/-150ns) gives timing_ns=(1, 4, 4, 1) which in cycles is
+ // (12 + 6, 18 + 24, 12 + 24, 18 + 6) = (18, 42, 36, 24)
+ // --> (375, 875, 750, 500) nanoseconds.
+ // Measured output on logic analyser is (370, 870, 750, 490) (+/-10ns at 100MHz)
+
+ // Note: final low of LSB is longer by 8 cycles (160ns) (due to start of outer loop and fetching next byte).
+ // This is slightly outside spec, but doesn't seem to cause a problem.
+
+ __asm volatile (
+ // Force consistent register assignment.
+ // r6 = len
+ "ldr r6, %0\n"
+ // r4 = buf
+ "ldr r4, %1\n"
+ // r5 = timing_ms
+ "ldr r5, %2\n"
+
+ // Must align for consistent timing.
+ ".align 4\n"
+
+ // Don't increment/decrement before first iteration.
+ "b .outer2\n"
+ ".outer:\n"
+ // ++buf, --len
+ " add r4, #1\n"
+ " sub r6, #1\n"
+
+ // len iterations
+ ".outer2:\n"
+ " cmp r6, #0\n"
+ " beq .done\n"
+
+ // r0 = *buf
+ " ldrb r0, [r4, #0]\n"
+
+ // 8 bits in byte
+ " mov r7, #8\n"
+ " .inner:\n"
+ // *bsrr = high_mask
+ " ldr r1, %3\n"
+ " ldr r2, %4\n"
+ " str r2, [r1, #0]\n"
+
+ // r3 = (r0 >> 4) & 8 (r0 is 8 if high bit is 1 else 0)
+ " mov r8, r6\n"
+ " lsr r3, r0, #4\n"
+ " mov r6, #8\n"
+ " and r3, r6\n"
+ " mov r6, r8\n"
+
+ // r2 = timing_ns[r2]
+ " ldr r2, [r5, r3]\n"
+ " .loop1:\n sub r2, #1\n bne .loop1\n"
+
+ // *bsrr = low_mask
+ " ldr r2, %5\n"
+ " str r2, [r1, #0]\n"
+
+ // r2 = timing_ns[r3 + 4]
+ " add r3, #4\n"
+ " ldr r2, [r5, r3]\n"
+ " .loop2:\n sub r2, #1\n bne .loop2\n"
+
+ // b >>= 1
+ " lsl r0, r0, #1\n"
+
+ " sub r7, #1\n"
+ // end of inner loop
+ " beq .outer\n"
+ // continue inner loop
+ " b .inner\n"
+
+ ".done:\n"
+ :
+ : "m" (len), "m" (buf), "m" (timing_ns), "m" (bsrr), "m" (high_mask), "m" (low_mask)
+ : "r0", "r1", "r2", "r3", "r7", "r8"
+ );
+
+ MICROPY_END_ATOMIC_SECTION(atomic_state);
+}
+
+#else // > CORTEX_M0
+
+// Use cycle counter for timing.
+
+// Measured on PYBV11 at 168MHz & 128MHz and PYBD_SF6 at 128MHz & 144MHz.
+#define NS_CYCLES_OVERHEAD (6)
+
+void machine_bitstream_high_low(mp_hal_pin_obj_t pin, uint32_t *timing_ns, const uint8_t *buf, size_t len) {
+ const uint32_t high_mask = pin->pin_mask;
+ const uint32_t low_mask = pin->pin_mask << 16;
+ volatile uint32_t *bsrr = &pin->gpio->BSRR;
+
+ // Convert ns to cycles [high_time_0, low_time_0, high_time_1, low_time_1].
+ for (size_t i = 0; i < 4; ++i) {
+ timing_ns[i] = SystemCoreClock / 1000000 * timing_ns[i] / 1000;
+ if (timing_ns[i] > NS_CYCLES_OVERHEAD) {
+ timing_ns[i] -= NS_CYCLES_OVERHEAD;
+ }
+ if (i % 2 == 1) {
+ timing_ns[i] += timing_ns[i - 1];
+ }
+ }
+
+ mp_hal_ticks_cpu_enable();
+
+ mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION();
+
+ for (size_t i = 0; i < len; ++i) {
+ uint8_t b = buf[i];
+ for (size_t j = 0; j < 8; ++j) {
+ DWT->CYCCNT = 0;
+ *bsrr = high_mask;
+ uint32_t *t = &timing_ns[b >> 6 & 2];
+ while (DWT->CYCCNT < t[0]) {
+ ;
+ }
+ *bsrr = low_mask;
+ b <<= 1;
+ while (DWT->CYCCNT < t[1]) {
+ ;
+ }
+ }
+ }
+
+ MICROPY_END_ATOMIC_SECTION(atomic_state);
+}
+
+#endif // > CORTEX_M0
+
+#endif // MICROPY_PY_MACHINE_BITSTREAM
diff --git a/ports/stm32/machine_i2s.c b/ports/stm32/machine_i2s.c
new file mode 100644
index 000000000..32167cf4e
--- /dev/null
+++ b/ports/stm32/machine_i2s.c
@@ -0,0 +1,1125 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015 Bryan Morrissey
+ * Copyright (c) 2021 Mike Teachman
+ *
+ * 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
+#include
+
+#include "py/obj.h"
+#include "py/runtime.h"
+#include "py/mphal.h"
+#include "py/misc.h"
+#include "py/stream.h"
+#include "py/objstr.h"
+#include "modmachine.h"
+#include "pin.h"
+#include "dma.h"
+
+#if MICROPY_HW_ENABLE_I2S
+// The I2S module has 3 modes of operation:
+//
+// Mode1: Blocking
+// - readinto() and write() methods block until the supplied buffer is filled (read) or emptied (write)
+// - this is the default mode of operation
+//
+// Mode2: Non-Blocking
+// - readinto() and write() methods return immediately
+// - buffer filling and emptying happens asynchronously to the main MicroPython task
+// - a callback function is called when the supplied buffer has been filled (read) or emptied (write)
+// - non-blocking mode is enabled when a callback is set with the irq() method
+// - the DMA callbacks (1/2 complete and complete) are used to implement the asynchronous background operations
+//
+// Mode3: Uasyncio
+// - implements the stream protocol
+// - uasyncio mode is enabled when the ioctl() function is called
+// - the state of the internal ring buffer is used to detect that I2S samples can be read or written
+//
+// The samples contained in the app buffer supplied for the readinto() and write() methods have the following convention:
+// Mono: little endian format
+// Stereo: little endian format, left channel first
+//
+// I2S terms:
+// "frame": consists of two audio samples (Left audio sample + Right audio sample)
+//
+// Misc:
+// - for Mono configuration:
+// - readinto method: samples are gathered from the L channel only
+// - write method: every sample is output to both the L and R channels
+// - for readinto method the I2S hardware is read using 8-byte frames
+// (this is standard for almost all I2S hardware, such as MEMS microphones)
+// - all 3 Modes of operation are implemented using the HAL I2S Generic Driver
+// - all sample data transfers use DMA
+// - the DMA controller is configured in Circular mode to fulfil continuous and gapless sample flows
+// - the DMA ping-pong buffer needs to be aligned to a cache line size of 32 bytes. 32 byte
+// alignment is needed to use the routines that clean and invalidate D-Cache which work on a
+// 32 byte address boundary. Not all STM32 devices have a D-Cache. Buffer alignment
+// will still happen on these devices to keep this code simple.
+
+#define MAX_I2S_STM32 (2)
+
+// DMA ping-pong buffer size was empirically determined. It is a tradeoff between:
+// 1. memory use (smaller buffer size desirable to reduce memory footprint)
+// 2. interrupt frequency (larger buffer size desirable to reduce interrupt frequency)
+// The sizeof 1/2 of the DMA buffer must be evenly divisible by the cache line size of 32 bytes.
+#define SIZEOF_DMA_BUFFER_IN_BYTES (256)
+#define SIZEOF_HALF_DMA_BUFFER_IN_BYTES (SIZEOF_DMA_BUFFER_IN_BYTES / 2)
+
+// For non-blocking mode, to avoid underflow/overflow, sample data is written/read to/from the ring buffer at a rate faster
+// than the DMA transfer rate
+#define NON_BLOCKING_RATE_MULTIPLIER (4)
+#define SIZEOF_NON_BLOCKING_COPY_IN_BYTES (SIZEOF_HALF_DMA_BUFFER_IN_BYTES * NON_BLOCKING_RATE_MULTIPLIER)
+
+#define NUM_I2S_USER_FORMATS (4)
+#define I2S_RX_FRAME_SIZE_IN_BYTES (8)
+
+typedef enum {
+ MONO,
+ STEREO
+} format_t;
+
+typedef enum {
+ BLOCKING,
+ NON_BLOCKING,
+ UASYNCIO
+} io_mode_t;
+
+typedef enum {
+ TOP_HALF,
+ BOTTOM_HALF
+} ping_pong_t;
+
+typedef struct _ring_buf_t {
+ uint8_t *buffer;
+ size_t head;
+ size_t tail;
+ size_t size;
+} ring_buf_t;
+
+typedef struct _non_blocking_descriptor_t {
+ mp_buffer_info_t appbuf;
+ uint32_t index;
+ bool copy_in_progress;
+} non_blocking_descriptor_t;
+
+typedef struct _machine_i2s_obj_t {
+ mp_obj_base_t base;
+ uint8_t i2s_id;
+ mp_hal_pin_obj_t sck;
+ mp_hal_pin_obj_t ws;
+ mp_hal_pin_obj_t sd;
+ uint16_t mode;
+ int8_t bits;
+ format_t format;
+ int32_t rate;
+ int32_t ibuf;
+ mp_obj_t callback_for_non_blocking;
+ uint8_t dma_buffer[SIZEOF_DMA_BUFFER_IN_BYTES + 0x1f]; // 0x1f related to D-Cache alignment
+ uint8_t *dma_buffer_dcache_aligned;
+ ring_buf_t ring_buffer;
+ uint8_t *ring_buffer_storage;
+ non_blocking_descriptor_t non_blocking_descriptor;
+ io_mode_t io_mode;
+ I2S_HandleTypeDef hi2s;
+ DMA_HandleTypeDef hdma_tx;
+ DMA_HandleTypeDef hdma_rx;
+ const dma_descr_t *dma_descr_tx;
+ const dma_descr_t *dma_descr_rx;
+} machine_i2s_obj_t;
+
+STATIC mp_obj_t machine_i2s_deinit(mp_obj_t self_in);
+
+// The frame map is used with the readinto() method to transform the audio sample data coming
+// from DMA memory (32-bit stereo) to the format specified
+// in the I2S constructor. e.g. 16-bit mono
+STATIC const int8_t i2s_frame_map[NUM_I2S_USER_FORMATS][I2S_RX_FRAME_SIZE_IN_BYTES] = {
+ { 0, 1, -1, -1, -1, -1, -1, -1 }, // Mono, 16-bits
+ { 2, 3, 0, 1, -1, -1, -1, -1 }, // Mono, 32-bits
+ { 0, 1, 4, 5, -1, -1, -1, -1 }, // Stereo, 16-bits
+ { 2, 3, 0, 1, 6, 7, 4, 5 }, // Stereo, 32-bits
+};
+
+STATIC machine_i2s_obj_t *machine_i2s_obj[MAX_I2S_STM32];
+
+void machine_i2s_init0() {
+ for (uint8_t i = 0; i < MAX_I2S_STM32; i++) {
+ machine_i2s_obj[i] = NULL;
+ }
+}
+
+// Ring Buffer
+// Thread safe when used with these constraints:
+// - Single Producer, Single Consumer
+// - Sequential atomic operations
+// One byte of capacity is used to detect buffer empty/full
+
+STATIC void ringbuf_init(ring_buf_t *rbuf, uint8_t *buffer, size_t size) {
+ rbuf->buffer = buffer;
+ rbuf->size = size;
+ rbuf->head = 0;
+ rbuf->tail = 0;
+}
+
+STATIC bool ringbuf_push(ring_buf_t *rbuf, uint8_t data) {
+ size_t next_tail = (rbuf->tail + 1) % rbuf->size;
+
+ if (next_tail != rbuf->head) {
+ rbuf->buffer[rbuf->tail] = data;
+ rbuf->tail = next_tail;
+ return true;
+ }
+
+ // full
+ return false;
+}
+
+STATIC bool ringbuf_pop(ring_buf_t *rbuf, uint8_t *data) {
+ if (rbuf->head == rbuf->tail) {
+ // empty
+ return false;
+ }
+
+ *data = rbuf->buffer[rbuf->head];
+ rbuf->head = (rbuf->head + 1) % rbuf->size;
+ return true;
+}
+
+STATIC bool ringbuf_is_empty(ring_buf_t *rbuf) {
+ return rbuf->head == rbuf->tail;
+}
+
+STATIC bool ringbuf_is_full(ring_buf_t *rbuf) {
+ return ((rbuf->tail + 1) % rbuf->size) == rbuf->head;
+}
+
+STATIC size_t ringbuf_available_data(ring_buf_t *rbuf) {
+ return (rbuf->tail - rbuf->head + rbuf->size) % rbuf->size;
+}
+
+STATIC size_t ringbuf_available_space(ring_buf_t *rbuf) {
+ return rbuf->size - ringbuf_available_data(rbuf) - 1;
+}
+
+// For 32-bit audio samples, the STM32 HAL API expects each 32-bit sample to be encoded
+// in an unusual byte ordering: Byte_2, Byte_3, Byte_0, Byte_1
+// where: Byte_0 is the least significant byte of the 32-bit sample
+//
+// The following function takes a buffer containing 32-bits sample values formatted as little endian
+// and performs an in-place modification into the STM32 HAL API convention
+//
+// Example:
+//
+// wav_samples[] = [L_0-7, L_8-15, L_16-23, L_24-31, R_0-7, R_8-15, R_16-23, R_24-31] = [Left channel, Right channel]
+// stm_api[] = [L_16-23, L_24-31, L_0-7, L_8-15, R_16-23, R_24-31, R_0-7, R_8-15] = [Left channel, Right channel]
+//
+// where:
+// L_0-7 is the least significant byte of the 32 bit sample in the Left channel
+// L_24-31 is the most significant byte of the 32 bit sample in the Left channel
+//
+// wav_samples[] = [0x99, 0xBB, 0x11, 0x22, 0x44, 0x55, 0xAB, 0x77] = [Left channel, Right channel]
+// stm_api[] = [0x11, 0x22, 0x99, 0xBB, 0xAB, 0x77, 0x44, 0x55] = [Left channel, Right channel]
+//
+// where:
+// LEFT Channel = 0x99, 0xBB, 0x11, 0x22
+// RIGHT Channel = 0x44, 0x55, 0xAB, 0x77
+STATIC void reformat_32_bit_samples(int32_t *sample, uint32_t num_samples) {
+ int16_t sample_ms;
+ int16_t sample_ls;
+ for (uint32_t i = 0; i < num_samples; i++) {
+ sample_ls = sample[i] & 0xFFFF;
+ sample_ms = sample[i] >> 16;
+ sample[i] = (sample_ls << 16) + sample_ms;
+ }
+}
+
+STATIC int8_t get_frame_mapping_index(int8_t bits, format_t format) {
+ if (format == MONO) {
+ if (bits == 16) {
+ return 0;
+ } else { // 32 bits
+ return 1;
+ }
+ } else { // STEREO
+ if (bits == 16) {
+ return 2;
+ } else { // 32 bits
+ return 3;
+ }
+ }
+}
+
+STATIC int8_t get_dma_bits(uint16_t mode, int8_t bits) {
+ if (mode == I2S_MODE_MASTER_TX) {
+ if (bits == 16) {
+ return I2S_DATAFORMAT_16B;
+ } else {
+ return I2S_DATAFORMAT_32B;
+ }
+ return bits;
+ } else { // Master Rx
+ // always read 32 bit words for I2S e.g. I2S MEMS microphones
+ return I2S_DATAFORMAT_32B;
+ }
+}
+
+STATIC uint32_t fill_appbuf_from_ringbuf(machine_i2s_obj_t *self, mp_buffer_info_t *appbuf) {
+
+ // copy audio samples from the ring buffer to the app buffer
+ // loop, copying samples until the app buffer is filled
+ // For uasyncio mode, the loop will make an early exit if the ring buffer becomes empty
+ // Example:
+ // a MicroPython I2S object is configured for 16-bit mono (2 bytes per audio sample).
+ // For every frame coming from the ring buffer (8 bytes), 2 bytes are "cherry picked" and
+ // copied to the supplied app buffer.
+ // Thus, for every 1 byte copied to the app buffer, 4 bytes are read from the ring buffer.
+ // If a 8kB app buffer is supplied, 32kB of audio samples is read from the ring buffer.
+
+ uint32_t num_bytes_copied_to_appbuf = 0;
+ uint8_t *app_p = (uint8_t *)appbuf->buf;
+ uint8_t appbuf_sample_size_in_bytes = (self->bits == 16? 2 : 4) * (self->format == STEREO ? 2: 1);
+ uint32_t num_bytes_needed_from_ringbuf = appbuf->len * (I2S_RX_FRAME_SIZE_IN_BYTES / appbuf_sample_size_in_bytes);
+ uint8_t discard_byte;
+ while (num_bytes_needed_from_ringbuf) {
+
+ uint8_t f_index = get_frame_mapping_index(self->bits, self->format);
+
+ for (uint8_t i = 0; i < I2S_RX_FRAME_SIZE_IN_BYTES; i++) {
+ int8_t r_to_a_mapping = i2s_frame_map[f_index][i];
+ if (r_to_a_mapping != -1) {
+ if (self->io_mode == BLOCKING) {
+ // poll the ringbuf until a sample becomes available, copy into appbuf using the mapping transform
+ while (ringbuf_pop(&self->ring_buffer, app_p + r_to_a_mapping) == false) {
+ ;
+ }
+ num_bytes_copied_to_appbuf++;
+ } else if (self->io_mode == UASYNCIO) {
+ if (ringbuf_pop(&self->ring_buffer, app_p + r_to_a_mapping) == false) {
+ // ring buffer is empty, exit
+ goto exit;
+ } else {
+ num_bytes_copied_to_appbuf++;
+ }
+ } else {
+ return 0; // should never get here (non-blocking mode does not use this function)
+ }
+ } else { // r_a_mapping == -1
+ // discard unused byte from ring buffer
+ if (self->io_mode == BLOCKING) {
+ // poll the ringbuf until a sample becomes available
+ while (ringbuf_pop(&self->ring_buffer, &discard_byte) == false) {
+ ;
+ }
+ } else if (self->io_mode == UASYNCIO) {
+ if (ringbuf_pop(&self->ring_buffer, &discard_byte) == false) {
+ // ring buffer is empty, exit
+ goto exit;
+ }
+ } else {
+ return 0; // should never get here (non-blocking mode does not use this function)
+ }
+ }
+ num_bytes_needed_from_ringbuf--;
+ }
+ app_p += appbuf_sample_size_in_bytes;
+ }
+exit:
+ return num_bytes_copied_to_appbuf;
+}
+
+// function is used in IRQ context
+STATIC void fill_appbuf_from_ringbuf_non_blocking(machine_i2s_obj_t *self) {
+
+ // attempt to copy a block of audio samples from the ring buffer to the supplied app buffer.
+ // audio samples will be formatted as part of the copy operation
+
+ uint32_t num_bytes_copied_to_appbuf = 0;
+ uint8_t *app_p = &(((uint8_t *)self->non_blocking_descriptor.appbuf.buf)[self->non_blocking_descriptor.index]);
+
+ uint8_t appbuf_sample_size_in_bytes = (self->bits == 16? 2 : 4) * (self->format == STEREO ? 2: 1);
+ uint32_t num_bytes_remaining_to_copy_to_appbuf = self->non_blocking_descriptor.appbuf.len - self->non_blocking_descriptor.index;
+ uint32_t num_bytes_remaining_to_copy_from_ring_buffer = num_bytes_remaining_to_copy_to_appbuf *
+ (I2S_RX_FRAME_SIZE_IN_BYTES / appbuf_sample_size_in_bytes);
+ uint32_t num_bytes_needed_from_ringbuf = MIN(SIZEOF_NON_BLOCKING_COPY_IN_BYTES, num_bytes_remaining_to_copy_from_ring_buffer);
+ uint8_t discard_byte;
+ if (ringbuf_available_data(&self->ring_buffer) >= num_bytes_needed_from_ringbuf) {
+ while (num_bytes_needed_from_ringbuf) {
+
+ uint8_t f_index = get_frame_mapping_index(self->bits, self->format);
+
+ for (uint8_t i = 0; i < I2S_RX_FRAME_SIZE_IN_BYTES; i++) {
+ int8_t r_to_a_mapping = i2s_frame_map[f_index][i];
+ if (r_to_a_mapping != -1) {
+ ringbuf_pop(&self->ring_buffer, app_p + r_to_a_mapping);
+ num_bytes_copied_to_appbuf++;
+ } else { // r_a_mapping == -1
+ // discard unused byte from ring buffer
+ ringbuf_pop(&self->ring_buffer, &discard_byte);
+ }
+ num_bytes_needed_from_ringbuf--;
+ }
+ app_p += appbuf_sample_size_in_bytes;
+ }
+ self->non_blocking_descriptor.index += num_bytes_copied_to_appbuf;
+
+ if (self->non_blocking_descriptor.index >= self->non_blocking_descriptor.appbuf.len) {
+ self->non_blocking_descriptor.copy_in_progress = false;
+ mp_sched_schedule(self->callback_for_non_blocking, MP_OBJ_FROM_PTR(self));
+ }
+ }
+}
+
+STATIC uint32_t copy_appbuf_to_ringbuf(machine_i2s_obj_t *self, mp_buffer_info_t *appbuf) {
+
+ // copy audio samples from the app buffer to the ring buffer
+ // loop, reading samples until the app buffer is emptied
+ // for uasyncio mode, the loop will make an early exit if the ring buffer becomes full
+
+ uint32_t a_index = 0;
+
+ while (a_index < appbuf->len) {
+ if (self->io_mode == BLOCKING) {
+ // copy a byte to the ringbuf when space becomes available
+ while (ringbuf_push(&self->ring_buffer, ((uint8_t *)appbuf->buf)[a_index]) == false) {
+ ;
+ }
+ a_index++;
+ } else if (self->io_mode == UASYNCIO) {
+ if (ringbuf_push(&self->ring_buffer, ((uint8_t *)appbuf->buf)[a_index]) == false) {
+ // ring buffer is full, exit
+ break;
+ } else {
+ a_index++;
+ }
+ } else {
+ return 0; // should never get here (non-blocking mode does not use this function)
+ }
+ }
+
+ return a_index;
+}
+
+// function is used in IRQ context
+STATIC void copy_appbuf_to_ringbuf_non_blocking(machine_i2s_obj_t *self) {
+
+ // copy audio samples from app buffer into ring buffer
+ uint32_t num_bytes_remaining_to_copy = self->non_blocking_descriptor.appbuf.len - self->non_blocking_descriptor.index;
+ uint32_t num_bytes_to_copy = MIN(SIZEOF_NON_BLOCKING_COPY_IN_BYTES, num_bytes_remaining_to_copy);
+
+ if (ringbuf_available_space(&self->ring_buffer) >= num_bytes_to_copy) {
+ for (uint32_t i = 0; i < num_bytes_to_copy; i++) {
+ ringbuf_push(&self->ring_buffer,
+ ((uint8_t *)self->non_blocking_descriptor.appbuf.buf)[self->non_blocking_descriptor.index + i]);
+ }
+
+ self->non_blocking_descriptor.index += num_bytes_to_copy;
+ if (self->non_blocking_descriptor.index >= self->non_blocking_descriptor.appbuf.len) {
+ self->non_blocking_descriptor.copy_in_progress = false;
+ mp_sched_schedule(self->callback_for_non_blocking, MP_OBJ_FROM_PTR(self));
+ }
+ }
+}
+
+// function is used in IRQ context
+STATIC void empty_dma(machine_i2s_obj_t *self, ping_pong_t dma_ping_pong) {
+ uint16_t dma_buffer_offset = 0;
+
+ if (dma_ping_pong == TOP_HALF) {
+ dma_buffer_offset = 0;
+ } else { // BOTTOM_HALF
+ dma_buffer_offset = SIZEOF_HALF_DMA_BUFFER_IN_BYTES;
+ }
+
+ uint8_t *dma_buffer_p = &self->dma_buffer_dcache_aligned[dma_buffer_offset];
+
+ // flush and invalidate cache so the CPU reads data placed into RAM by DMA
+ MP_HAL_CLEANINVALIDATE_DCACHE(dma_buffer_p, SIZEOF_HALF_DMA_BUFFER_IN_BYTES);
+
+ // when space exists, copy samples into ring buffer
+ if (ringbuf_available_space(&self->ring_buffer) >= SIZEOF_HALF_DMA_BUFFER_IN_BYTES) {
+ for (uint32_t i = 0; i < SIZEOF_HALF_DMA_BUFFER_IN_BYTES; i++) {
+ ringbuf_push(&self->ring_buffer, dma_buffer_p[i]);
+ }
+ }
+}
+
+// function is used in IRQ context
+STATIC void feed_dma(machine_i2s_obj_t *self, ping_pong_t dma_ping_pong) {
+ uint16_t dma_buffer_offset = 0;
+
+ if (dma_ping_pong == TOP_HALF) {
+ dma_buffer_offset = 0;
+ } else { // BOTTOM_HALF
+ dma_buffer_offset = SIZEOF_HALF_DMA_BUFFER_IN_BYTES;
+ }
+
+ uint8_t *dma_buffer_p = &self->dma_buffer_dcache_aligned[dma_buffer_offset];
+
+ // when data exists, copy samples from ring buffer
+ if (ringbuf_available_data(&self->ring_buffer) >= SIZEOF_HALF_DMA_BUFFER_IN_BYTES) {
+
+ // copy a block of samples from the ring buffer to the dma buffer.
+ // STM32 HAL API has a stereo I2S implementation, but not mono
+ // mono format is implemented by duplicating each sample into both L and R channels.
+ if ((self->format == MONO) && (self->bits == 16)) {
+ for (uint32_t i = 0; i < SIZEOF_HALF_DMA_BUFFER_IN_BYTES / 4; i++) {
+ for (uint8_t b = 0; b < sizeof(uint16_t); b++) {
+ ringbuf_pop(&self->ring_buffer, &dma_buffer_p[i * 4 + b]);
+ dma_buffer_p[i * 4 + b + 2] = dma_buffer_p[i * 4 + b]; // duplicated mono sample
+ }
+ }
+ } else if ((self->format == MONO) && (self->bits == 32)) {
+ for (uint32_t i = 0; i < SIZEOF_HALF_DMA_BUFFER_IN_BYTES / 8; i++) {
+ for (uint8_t b = 0; b < sizeof(uint32_t); b++) {
+ ringbuf_pop(&self->ring_buffer, &dma_buffer_p[i * 8 + b]);
+ dma_buffer_p[i * 8 + b + 4] = dma_buffer_p[i * 8 + b]; // duplicated mono sample
+ }
+ }
+ } else { // STEREO, both 16-bit and 32-bit
+ for (uint32_t i = 0; i < SIZEOF_HALF_DMA_BUFFER_IN_BYTES; i++) {
+ ringbuf_pop(&self->ring_buffer, &dma_buffer_p[i]);
+ }
+ }
+
+ // reformat 32 bit samples to match STM32 HAL API format
+ if (self->bits == 32) {
+ reformat_32_bit_samples((int32_t *)dma_buffer_p, SIZEOF_HALF_DMA_BUFFER_IN_BYTES / (sizeof(uint32_t)));
+ }
+ }
+
+ // flush cache to RAM so DMA can read the sample data
+ MP_HAL_CLEAN_DCACHE(dma_buffer_p, SIZEOF_HALF_DMA_BUFFER_IN_BYTES);
+}
+
+STATIC bool i2s_init(machine_i2s_obj_t *self) {
+
+ // init the GPIO lines
+ GPIO_InitTypeDef GPIO_InitStructure;
+ GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
+ GPIO_InitStructure.Speed = GPIO_SPEED_FAST;
+ GPIO_InitStructure.Pull = GPIO_PULLUP;
+
+ if (self->i2s_id == 1) {
+ self->hi2s.Instance = I2S1;
+ __SPI1_CLK_ENABLE();
+ // configure DMA streams
+ if (self->mode == I2S_MODE_MASTER_RX) {
+ self->dma_descr_rx = &dma_I2S_1_RX;
+ } else {
+ self->dma_descr_tx = &dma_I2S_1_TX;
+ }
+ } else if (self->i2s_id == 2) {
+ self->hi2s.Instance = I2S2;
+ __SPI2_CLK_ENABLE();
+ // configure DMA streams
+ if (self->mode == I2S_MODE_MASTER_RX) {
+ self->dma_descr_rx = &dma_I2S_2_RX;
+ } else {
+ self->dma_descr_tx = &dma_I2S_2_TX;
+ }
+ } else {
+ // invalid id number; should not get here as i2s object should not
+ // have been created without setting a valid i2s instance number
+ return false;
+ }
+
+ // GPIO Pin initialization
+ if (self->sck != MP_OBJ_TO_PTR(MP_OBJ_NULL)) {
+ GPIO_InitStructure.Pin = self->sck->pin_mask;
+ const pin_af_obj_t *af = pin_find_af(self->sck, AF_FN_I2S, self->i2s_id);
+ GPIO_InitStructure.Alternate = (uint8_t)af->idx;
+ HAL_GPIO_Init(self->sck->gpio, &GPIO_InitStructure);
+ }
+
+ if (self->ws != MP_OBJ_TO_PTR(MP_OBJ_NULL)) {
+ GPIO_InitStructure.Pin = self->ws->pin_mask;
+ const pin_af_obj_t *af = pin_find_af(self->ws, AF_FN_I2S, self->i2s_id);
+ GPIO_InitStructure.Alternate = (uint8_t)af->idx;
+ HAL_GPIO_Init(self->ws->gpio, &GPIO_InitStructure);
+ }
+
+ if (self->sd != MP_OBJ_TO_PTR(MP_OBJ_NULL)) {
+ GPIO_InitStructure.Pin = self->sd->pin_mask;
+ const pin_af_obj_t *af = pin_find_af(self->sd, AF_FN_I2S, self->i2s_id);
+ GPIO_InitStructure.Alternate = (uint8_t)af->idx;
+ HAL_GPIO_Init(self->sd->gpio, &GPIO_InitStructure);
+ }
+
+ if (HAL_I2S_Init(&self->hi2s) == HAL_OK) {
+ // Reset and initialize Tx and Rx DMA channels
+ if (self->mode == I2S_MODE_MASTER_RX) {
+ dma_invalidate_channel(self->dma_descr_rx);
+ dma_init(&self->hdma_rx, self->dma_descr_rx, DMA_PERIPH_TO_MEMORY, &self->hi2s);
+ self->hi2s.hdmarx = &self->hdma_rx;
+ } else { // I2S_MODE_MASTER_TX
+ dma_invalidate_channel(self->dma_descr_tx);
+ dma_init(&self->hdma_tx, self->dma_descr_tx, DMA_MEMORY_TO_PERIPH, &self->hi2s);
+ self->hi2s.hdmatx = &self->hdma_tx;
+ }
+
+ __HAL_RCC_PLLI2S_ENABLE(); // start I2S clock
+
+ return true;
+ } else {
+ return false;
+ }
+
+}
+
+void HAL_I2S_ErrorCallback(I2S_HandleTypeDef *hi2s) {
+ uint32_t errorCode = HAL_I2S_GetError(hi2s);
+ printf("I2S Error = %ld\n", errorCode);
+}
+
+void HAL_I2S_RxCpltCallback(I2S_HandleTypeDef *hi2s) {
+ machine_i2s_obj_t *self;
+ if (hi2s->Instance == I2S1) {
+ self = machine_i2s_obj[0];
+ } else {
+ self = machine_i2s_obj[1];
+ }
+
+ // bottom half of buffer now filled,
+ // safe to empty the bottom half while the top half of buffer is being filled
+ empty_dma(self, BOTTOM_HALF);
+
+ // for non-blocking operation, this IRQ-based callback handles
+ // the readinto() method requests.
+ if ((self->io_mode == NON_BLOCKING) && (self->non_blocking_descriptor.copy_in_progress)) {
+ fill_appbuf_from_ringbuf_non_blocking(self);
+ }
+}
+
+void HAL_I2S_RxHalfCpltCallback(I2S_HandleTypeDef *hi2s) {
+ machine_i2s_obj_t *self;
+ if (hi2s->Instance == I2S1) {
+ self = machine_i2s_obj[0];
+ } else {
+ self = machine_i2s_obj[1];
+ }
+
+ // top half of buffer now filled,
+ // safe to empty the top half while the bottom half of buffer is being filled
+ empty_dma(self, TOP_HALF);
+
+ // for non-blocking operation, this IRQ-based callback handles
+ // the readinto() method requests.
+ if ((self->io_mode == NON_BLOCKING) && (self->non_blocking_descriptor.copy_in_progress)) {
+ fill_appbuf_from_ringbuf_non_blocking(self);
+ }
+}
+
+void HAL_I2S_TxCpltCallback(I2S_HandleTypeDef *hi2s) {
+ machine_i2s_obj_t *self;
+
+ if (hi2s->Instance == I2S1) {
+ self = machine_i2s_obj[0];
+ } else {
+ self = machine_i2s_obj[1];
+ }
+
+ // for non-blocking operation, this IRQ-based callback handles
+ // the write() method requests.
+ if ((self->io_mode == NON_BLOCKING) && (self->non_blocking_descriptor.copy_in_progress)) {
+ copy_appbuf_to_ringbuf_non_blocking(self);
+ }
+
+ // bottom half of buffer now emptied,
+ // safe to fill the bottom half while the top half of buffer is being emptied
+ feed_dma(self, BOTTOM_HALF);
+}
+
+void HAL_I2S_TxHalfCpltCallback(I2S_HandleTypeDef *hi2s) {
+ machine_i2s_obj_t *self;
+ if (hi2s->Instance == I2S1) {
+ self = machine_i2s_obj[0];
+ } else {
+ self = machine_i2s_obj[1];
+ }
+
+ // for non-blocking operation, this IRQ-based callback handles
+ // the write() method requests.
+ if ((self->io_mode == NON_BLOCKING) && (self->non_blocking_descriptor.copy_in_progress)) {
+ copy_appbuf_to_ringbuf_non_blocking(self);
+ }
+
+ // top half of buffer now emptied,
+ // safe to fill the top half while the bottom half of buffer is being emptied
+ feed_dma(self, TOP_HALF);
+}
+
+STATIC void machine_i2s_init_helper(machine_i2s_obj_t *self, size_t n_pos_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+
+ enum {
+ ARG_sck,
+ ARG_ws,
+ ARG_sd,
+ ARG_mode,
+ ARG_bits,
+ ARG_format,
+ ARG_rate,
+ ARG_ibuf,
+ };
+
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_sck, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_ws, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_sd, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_mode, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = -1} },
+ { MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = -1} },
+ { MP_QSTR_format, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = -1} },
+ { MP_QSTR_rate, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = -1} },
+ { MP_QSTR_ibuf, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = -1} },
+ };
+
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_pos_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ memset(&self->hi2s, 0, sizeof(self->hi2s));
+
+ //
+ // ---- Check validity of arguments ----
+ //
+
+ // are I2S pin assignments valid?
+ const pin_af_obj_t *pin_af;
+
+ // is SCK valid?
+ if (mp_obj_is_type(args[ARG_sck].u_obj, &pin_type)) {
+ pin_af = pin_find_af(MP_OBJ_TO_PTR(args[ARG_sck].u_obj), AF_FN_I2S, self->i2s_id);
+ if (pin_af->type != AF_PIN_TYPE_I2S_CK) {
+ mp_raise_ValueError(MP_ERROR_TEXT("invalid SCK pin"));
+ }
+ } else {
+ mp_raise_ValueError(MP_ERROR_TEXT("SCK not a Pin type"));
+ }
+
+ // is WS valid?
+ if (mp_obj_is_type(args[ARG_ws].u_obj, &pin_type)) {
+ pin_af = pin_find_af(MP_OBJ_TO_PTR(args[ARG_ws].u_obj), AF_FN_I2S, self->i2s_id);
+ if (pin_af->type != AF_PIN_TYPE_I2S_WS) {
+ mp_raise_ValueError(MP_ERROR_TEXT("invalid WS pin"));
+ }
+ } else {
+ mp_raise_ValueError(MP_ERROR_TEXT("WS not a Pin type"));
+ }
+
+ // is SD valid?
+ if (mp_obj_is_type(args[ARG_sd].u_obj, &pin_type)) {
+ pin_af = pin_find_af(MP_OBJ_TO_PTR(args[ARG_sd].u_obj), AF_FN_I2S, self->i2s_id);
+ if (pin_af->type != AF_PIN_TYPE_I2S_SD) {
+ mp_raise_ValueError(MP_ERROR_TEXT("invalid SD pin"));
+ }
+ } else {
+ mp_raise_ValueError(MP_ERROR_TEXT("SD not a Pin type"));
+ }
+
+ // is Mode valid?
+ uint16_t i2s_mode = args[ARG_mode].u_int;
+ if ((i2s_mode != (I2S_MODE_MASTER_RX)) &&
+ (i2s_mode != (I2S_MODE_MASTER_TX))) {
+ mp_raise_ValueError(MP_ERROR_TEXT("invalid mode"));
+ }
+
+ // is Bits valid?
+ int8_t i2s_bits = args[ARG_bits].u_int;
+ if ((i2s_bits != 16) &&
+ (i2s_bits != 32)) {
+ mp_raise_ValueError(MP_ERROR_TEXT("invalid bits"));
+ }
+
+ // is Format valid?
+ format_t i2s_format = args[ARG_format].u_int;
+ if ((i2s_format != MONO) &&
+ (i2s_format != STEREO)) {
+ mp_raise_ValueError(MP_ERROR_TEXT("invalid format"));
+ }
+
+ // is Rate valid?
+ // Not checked
+
+ // is Ibuf valid?
+ int32_t ring_buffer_len = args[ARG_ibuf].u_int;
+ if (ring_buffer_len > 0) {
+ uint8_t *buffer = m_new(uint8_t, ring_buffer_len);
+ self->ring_buffer_storage = buffer;
+ ringbuf_init(&self->ring_buffer, buffer, ring_buffer_len);
+ } else {
+ mp_raise_ValueError(MP_ERROR_TEXT("invalid ibuf"));
+ }
+
+ self->sck = MP_OBJ_TO_PTR(args[ARG_sck].u_obj);
+ self->ws = MP_OBJ_TO_PTR(args[ARG_ws].u_obj);
+ self->sd = MP_OBJ_TO_PTR(args[ARG_sd].u_obj);
+ self->mode = i2s_mode;
+ self->bits = i2s_bits;
+ self->format = i2s_format;
+ self->rate = args[ARG_rate].u_int;
+ self->ibuf = ring_buffer_len;
+ self->callback_for_non_blocking = MP_OBJ_NULL;
+ self->non_blocking_descriptor.copy_in_progress = false;
+ self->io_mode = BLOCKING;
+
+ I2S_InitTypeDef *init = &self->hi2s.Init;
+ init->Mode = i2s_mode;
+ init->Standard = I2S_STANDARD_PHILIPS;
+ init->DataFormat = get_dma_bits(self->mode, self->bits);
+ init->MCLKOutput = I2S_MCLKOUTPUT_DISABLE;
+ init->AudioFreq = args[ARG_rate].u_int;
+ init->CPOL = I2S_CPOL_LOW;
+ init->ClockSource = I2S_CLOCK_PLL;
+
+ // init the I2S bus
+ if (!i2s_init(self)) {
+ mp_raise_msg_varg(&mp_type_OSError, MP_ERROR_TEXT("I2S init failed"));
+ }
+
+ // start DMA. DMA is configured to run continuously, using a circular buffer configuration
+ uint32_t number_of_samples = 0;
+ if (init->DataFormat == I2S_DATAFORMAT_16B) {
+ number_of_samples = SIZEOF_DMA_BUFFER_IN_BYTES / sizeof(uint16_t);
+ } else { // 32 bits
+ number_of_samples = SIZEOF_DMA_BUFFER_IN_BYTES / sizeof(uint32_t);
+ }
+
+ HAL_StatusTypeDef status;
+ if (self->mode == I2S_MODE_MASTER_TX) {
+ status = HAL_I2S_Transmit_DMA(&self->hi2s, (void *)self->dma_buffer_dcache_aligned, number_of_samples);
+ } else { // RX
+ status = HAL_I2S_Receive_DMA(&self->hi2s, (void *)self->dma_buffer_dcache_aligned, number_of_samples);
+ }
+
+ if (status != HAL_OK) {
+ mp_raise_msg_varg(&mp_type_OSError, MP_ERROR_TEXT("DMA init failed"));
+ }
+}
+
+STATIC void machine_i2s_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
+ machine_i2s_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_printf(print, "I2S(id=%u,\n"
+ "sck="MP_HAL_PIN_FMT ",\n"
+ "ws="MP_HAL_PIN_FMT ",\n"
+ "sd="MP_HAL_PIN_FMT ",\n"
+ "mode=%u,\n"
+ "bits=%u, format=%u,\n"
+ "rate=%d, ibuf=%d)",
+ self->i2s_id,
+ mp_hal_pin_name(self->sck),
+ mp_hal_pin_name(self->ws),
+ mp_hal_pin_name(self->sd),
+ self->mode,
+ self->bits, self->format,
+ self->rate, self->ibuf
+ );
+}
+
+STATIC mp_obj_t machine_i2s_make_new(const mp_obj_type_t *type, size_t n_pos_args, size_t n_kw_args, const mp_obj_t *args) {
+ mp_arg_check_num(n_pos_args, n_kw_args, 1, MP_OBJ_FUN_ARGS_MAX, true);
+ uint8_t i2s_id = mp_obj_get_int(args[0]);
+ uint8_t i2s_id_zero_base = 0;
+
+ if (0) {
+ #ifdef MICROPY_HW_I2S1
+ } else if (i2s_id == 1) {
+ i2s_id_zero_base = 0;
+ #endif
+ #ifdef MICROPY_HW_I2S2
+ } else if (i2s_id == 2) {
+ i2s_id_zero_base = 1;
+ #endif
+ } else {
+ mp_raise_ValueError(MP_ERROR_TEXT("invalid id"));
+ }
+
+ machine_i2s_obj_t *self;
+ if (machine_i2s_obj[i2s_id_zero_base] == NULL) {
+ self = m_new_obj(machine_i2s_obj_t);
+ machine_i2s_obj[i2s_id_zero_base] = self;
+ self->base.type = &machine_i2s_type;
+ self->i2s_id = i2s_id;
+ } else {
+ self = machine_i2s_obj[i2s_id_zero_base];
+ machine_i2s_deinit(MP_OBJ_FROM_PTR(self));
+ }
+
+ // align DMA buffer start to the cache line size (32 bytes)
+ self->dma_buffer_dcache_aligned = (uint8_t *)((uint32_t)(self->dma_buffer + 0x1f) & ~0x1f);
+
+ mp_map_t kw_args;
+ mp_map_init_fixed_table(&kw_args, n_kw_args, args + n_pos_args);
+ machine_i2s_init_helper(self, n_pos_args - 1, args + 1, &kw_args);
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+STATIC mp_obj_t machine_i2s_init(size_t n_pos_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ machine_i2s_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+ machine_i2s_deinit(MP_OBJ_FROM_PTR(self));
+ machine_i2s_init_helper(self, n_pos_args - 1, pos_args + 1, kw_args);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_i2s_init_obj, 1, machine_i2s_init);
+
+STATIC mp_obj_t machine_i2s_deinit(mp_obj_t self_in) {
+
+ machine_i2s_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ dma_deinit(self->dma_descr_tx);
+ dma_deinit(self->dma_descr_rx);
+ HAL_I2S_DeInit(&self->hi2s);
+
+ if (self->hi2s.Instance == I2S1) {
+ __SPI1_FORCE_RESET();
+ __SPI1_RELEASE_RESET();
+ __SPI1_CLK_DISABLE();
+ } else if (self->hi2s.Instance == I2S2) {
+ __SPI2_FORCE_RESET();
+ __SPI2_RELEASE_RESET();
+ __SPI2_CLK_DISABLE();
+ }
+
+ m_free(self->ring_buffer_storage);
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_i2s_deinit_obj, machine_i2s_deinit);
+
+STATIC mp_obj_t machine_i2s_irq(mp_obj_t self_in, mp_obj_t handler) {
+ machine_i2s_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ if (handler != mp_const_none && !mp_obj_is_callable(handler)) {
+ mp_raise_ValueError(MP_ERROR_TEXT("invalid callback"));
+ }
+
+ if (handler != mp_const_none) {
+ self->io_mode = NON_BLOCKING;
+ } else {
+ self->io_mode = BLOCKING;
+ }
+
+ self->callback_for_non_blocking = handler;
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(machine_i2s_irq_obj, machine_i2s_irq);
+
+// Shift() is typically used as a volume control.
+// shift=1 increases volume by 6dB, shift=-1 decreases volume by 6dB
+STATIC mp_obj_t machine_i2s_shift(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_buf, ARG_bits, ARG_shift};
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_buf, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_bits, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
+ { MP_QSTR_shift, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
+ };
+
+ // parse args
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(args[ARG_buf].u_obj, &bufinfo, MP_BUFFER_RW);
+
+ int16_t *buf_16 = bufinfo.buf;
+ int32_t *buf_32 = bufinfo.buf;
+
+ uint8_t bits = args[ARG_bits].u_int;
+ int8_t shift = args[ARG_shift].u_int;
+
+ uint32_t num_audio_samples;
+ switch (bits) {
+ case 16:
+ num_audio_samples = bufinfo.len / sizeof(uint16_t);
+ break;
+
+ case 32:
+ num_audio_samples = bufinfo.len / sizeof(uint32_t);
+ break;
+
+ default:
+ mp_raise_ValueError(MP_ERROR_TEXT("invalid bits"));
+ break;
+ }
+
+ for (uint32_t i = 0; i < num_audio_samples; i++) {
+ switch (bits) {
+ case 16:
+ if (shift >= 0) {
+ buf_16[i] = buf_16[i] << shift;
+ } else {
+ buf_16[i] = buf_16[i] >> abs(shift);
+ }
+ break;
+ case 32:
+ if (shift >= 0) {
+ buf_32[i] = buf_32[i] << shift;
+ } else {
+ buf_32[i] = buf_32[i] >> abs(shift);
+ }
+ break;
+ }
+ }
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_i2s_shift_fun_obj, 0, machine_i2s_shift);
+STATIC MP_DEFINE_CONST_STATICMETHOD_OBJ(machine_i2s_shift_obj, MP_ROM_PTR(&machine_i2s_shift_fun_obj));
+
+STATIC const mp_rom_map_elem_t machine_i2s_locals_dict_table[] = {
+ // Methods
+ { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_i2s_init_obj) },
+ { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },
+ { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
+ { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&machine_i2s_deinit_obj) },
+ { MP_ROM_QSTR(MP_QSTR_irq), MP_ROM_PTR(&machine_i2s_irq_obj) },
+
+ // Static method
+ { MP_ROM_QSTR(MP_QSTR_shift), MP_ROM_PTR(&machine_i2s_shift_obj) },
+
+ // Constants
+ { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_INT(I2S_MODE_MASTER_RX) },
+ { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_INT(I2S_MODE_MASTER_TX) },
+ { MP_ROM_QSTR(MP_QSTR_STEREO), MP_ROM_INT(STEREO) },
+ { MP_ROM_QSTR(MP_QSTR_MONO), MP_ROM_INT(MONO) },
+};
+MP_DEFINE_CONST_DICT(machine_i2s_locals_dict, machine_i2s_locals_dict_table);
+
+STATIC mp_uint_t machine_i2s_stream_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, int *errcode) {
+ machine_i2s_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ if (self->mode != I2S_MODE_MASTER_RX) {
+ *errcode = MP_EPERM;
+ return MP_STREAM_ERROR;
+ }
+
+ uint8_t appbuf_sample_size_in_bytes = (self->bits / 8) * (self->format == STEREO ? 2: 1);
+ if (size % appbuf_sample_size_in_bytes != 0) {
+ *errcode = MP_EINVAL;
+ return MP_STREAM_ERROR;
+ }
+
+ if (size == 0) {
+ return 0;
+ }
+
+ if (self->io_mode == NON_BLOCKING) {
+ self->non_blocking_descriptor.appbuf.buf = (void *)buf_in;
+ self->non_blocking_descriptor.appbuf.len = size;
+ self->non_blocking_descriptor.index = 0;
+ self->non_blocking_descriptor.copy_in_progress = true;
+ return size;
+ } else { // blocking or uasyncio mode
+ mp_buffer_info_t appbuf;
+ appbuf.buf = (void *)buf_in;
+ appbuf.len = size;
+ uint32_t num_bytes_read = fill_appbuf_from_ringbuf(self, &appbuf);
+ return num_bytes_read;
+ }
+}
+
+STATIC mp_uint_t machine_i2s_stream_write(mp_obj_t self_in, const void *buf_in, mp_uint_t size, int *errcode) {
+ machine_i2s_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ if (self->mode != I2S_MODE_MASTER_TX) {
+ *errcode = MP_EPERM;
+ return MP_STREAM_ERROR;
+ }
+
+ if (size == 0) {
+ return 0;
+ }
+
+ if (self->io_mode == NON_BLOCKING) {
+ self->non_blocking_descriptor.appbuf.buf = (void *)buf_in;
+ self->non_blocking_descriptor.appbuf.len = size;
+ self->non_blocking_descriptor.index = 0;
+ self->non_blocking_descriptor.copy_in_progress = true;
+ return size;
+ } else { // blocking or uasyncio mode
+ mp_buffer_info_t appbuf;
+ appbuf.buf = (void *)buf_in;
+ appbuf.len = size;
+ uint32_t num_bytes_written = copy_appbuf_to_ringbuf(self, &appbuf);
+ return num_bytes_written;
+ }
+}
+
+STATIC mp_uint_t machine_i2s_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) {
+ machine_i2s_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_uint_t ret;
+ uintptr_t flags = arg;
+ self->io_mode = UASYNCIO; // a call to ioctl() is an indication that uasyncio is being used
+
+ if (request == MP_STREAM_POLL) {
+ ret = 0;
+
+ if (flags & MP_STREAM_POLL_RD) {
+ if (self->mode != I2S_MODE_MASTER_RX) {
+ *errcode = MP_EPERM;
+ return MP_STREAM_ERROR;
+ }
+
+ if (!ringbuf_is_empty(&self->ring_buffer)) {
+ ret |= MP_STREAM_POLL_RD;
+ }
+ }
+
+ if (flags & MP_STREAM_POLL_WR) {
+ if (self->mode != I2S_MODE_MASTER_TX) {
+ *errcode = MP_EPERM;
+ return MP_STREAM_ERROR;
+ }
+
+ if (!ringbuf_is_full(&self->ring_buffer)) {
+ ret |= MP_STREAM_POLL_WR;
+ }
+ }
+ } else {
+ *errcode = MP_EINVAL;
+ ret = MP_STREAM_ERROR;
+ }
+
+ return ret;
+}
+
+STATIC const mp_stream_p_t i2s_stream_p = {
+ .read = machine_i2s_stream_read,
+ .write = machine_i2s_stream_write,
+ .ioctl = machine_i2s_ioctl,
+ .is_text = false,
+};
+
+const mp_obj_type_t machine_i2s_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_I2S,
+ .print = machine_i2s_print,
+ .getiter = mp_identity_getiter,
+ .iternext = mp_stream_unbuffered_iter,
+ .protocol = &i2s_stream_p,
+ .make_new = machine_i2s_make_new,
+ .locals_dict = (mp_obj_dict_t *)&machine_i2s_locals_dict,
+};
+
+#endif // MICROPY_HW_ENABLE_I2S
diff --git a/ports/stm32/machine_uart.c b/ports/stm32/machine_uart.c
index 1b8db2e3e..354a1e26a 100644
--- a/ports/stm32/machine_uart.c
+++ b/ports/stm32/machine_uart.c
@@ -32,8 +32,8 @@
#include "py/stream.h"
#include "py/mperrno.h"
#include "py/mphal.h"
-#include "lib/utils/interrupt_char.h"
-#include "lib/utils/mpirq.h"
+#include "shared/runtime/interrupt_char.h"
+#include "shared/runtime/mpirq.h"
#include "uart.h"
#include "irq.h"
#include "pendsv.h"
diff --git a/ports/stm32/main.c b/ports/stm32/main.c
index 6df7374cc..d55f1a2c3 100644
--- a/ports/stm32/main.c
+++ b/ports/stm32/main.c
@@ -32,8 +32,8 @@
#include "py/gc.h"
#include "py/mperrno.h"
#include "py/mphal.h"
-#include "lib/mp-readline/readline.h"
-#include "lib/utils/pyexec.h"
+#include "shared/readline/readline.h"
+#include "shared/runtime/pyexec.h"
#include "lib/oofatfs/ff.h"
#include "lib/littlefs/lfs1.h"
#include "lib/littlefs/lfs1_util.h"
@@ -404,7 +404,7 @@ void stm32_main(uint32_t reset_mode) {
bool sdram_valid = true;
UNUSED(sdram_valid);
#if MICROPY_HW_SDRAM_STARTUP_TEST
- sdram_valid = sdram_test(true);
+ sdram_valid = sdram_test(false);
#endif
#endif
#if MICROPY_PY_THREAD
@@ -527,6 +527,10 @@ soft_reset:
pyb_usb_init0();
#endif
+ #if MICROPY_HW_ENABLE_I2S
+ machine_i2s_init0();
+ #endif
+
// Initialise the local flash filesystem.
// Create it if needed, mount in on /flash, and set it as current dir.
bool mounted_flash = false;
@@ -578,13 +582,13 @@ soft_reset:
// init USB device to default setting if it was not already configured
if (!(pyb_usb_flags & PYB_USB_FLAG_USB_MODE_CALLED)) {
#if MICROPY_HW_USB_MSC
- const uint16_t pid = USBD_PID_CDC_MSC;
+ const uint16_t pid = MICROPY_HW_USB_PID_CDC_MSC;
const uint8_t mode = USBD_MODE_CDC_MSC;
#else
- const uint16_t pid = USBD_PID_CDC;
+ const uint16_t pid = MICROPY_HW_USB_PID_CDC;
const uint8_t mode = USBD_MODE_CDC;
#endif
- pyb_usb_dev_init(pyb_usb_dev_detect(), USBD_VID, pid, mode, 0, NULL, NULL);
+ pyb_usb_dev_init(pyb_usb_dev_detect(), MICROPY_HW_USB_VID, pid, mode, 0, NULL, NULL);
}
#endif
diff --git a/ports/stm32/mbedtls/mbedtls_port.c b/ports/stm32/mbedtls/mbedtls_port.c
index efb8d2c2a..c31eb744a 100644
--- a/ports/stm32/mbedtls/mbedtls_port.c
+++ b/ports/stm32/mbedtls/mbedtls_port.c
@@ -80,7 +80,7 @@ void m_free_mbedtls(void *ptr_in) {
}
int mbedtls_hardware_poll(void *data, unsigned char *output, size_t len, size_t *olen) {
- uint32_t val;
+ uint32_t val = 0;
int n = 0;
*olen = len;
while (len--) {
diff --git a/ports/stm32/mboot/Makefile b/ports/stm32/mboot/Makefile
index 17de685a6..553fc4ac6 100755
--- a/ports/stm32/mboot/Makefile
+++ b/ports/stm32/mboot/Makefile
@@ -105,19 +105,19 @@ else
COPT += -Os -DNDEBUG
endif
-$(BUILD)/lib/libc/string0.o: CFLAGS += $(CFLAGS_BUILTIN)
+$(BUILD)/shared/libc/string0.o: CFLAGS += $(CFLAGS_BUILTIN)
LIB_SRC_C += \
- lib/libc/string0.c \
+ shared/libc/string0.c \
lib/littlefs/lfs1.c \
lib/littlefs/lfs1_util.c \
lib/littlefs/lfs2.c \
lib/littlefs/lfs2_util.c \
lib/oofatfs/ff.c \
lib/oofatfs/ffunicode.c \
- extmod/uzlib/crc32.c \
- extmod/uzlib/adler32.c \
- extmod/uzlib/tinflate.c \
- extmod/uzlib/tinfgzip.c
+ lib/uzlib/adler32.c \
+ lib/uzlib/crc32.c \
+ lib/uzlib/tinfgzip.c \
+ lib/uzlib/tinflate.c
SRC_C += \
main.c \
diff --git a/ports/stm32/mboot/gzstream.c b/ports/stm32/mboot/gzstream.c
index 652302e42..6ed8a21d9 100644
--- a/ports/stm32/mboot/gzstream.c
+++ b/ports/stm32/mboot/gzstream.c
@@ -27,7 +27,7 @@
#include
#include "py/mphal.h"
-#include "extmod/uzlib/uzlib.h"
+#include "lib/uzlib/uzlib.h"
#include "gzstream.h"
#include "mboot.h"
diff --git a/ports/stm32/mboot/main.c b/ports/stm32/mboot/main.c
index c1e1d59d2..6c7d2c771 100644
--- a/ports/stm32/mboot/main.c
+++ b/ports/stm32/mboot/main.c
@@ -28,7 +28,7 @@
#include
#include "py/mphal.h"
-#include "extmod/crypto-algorithms/sha256.c"
+#include "lib/crypto-algorithms/sha256.c"
#include "boardctrl.h"
#include "usbd_core.h"
#include "storage.h"
diff --git a/ports/stm32/modmachine.c b/ports/stm32/modmachine.c
index aee563ee8..92b80b365 100644
--- a/ports/stm32/modmachine.c
+++ b/ports/stm32/modmachine.c
@@ -33,12 +33,13 @@
#include "py/objstr.h"
#include "py/mperrno.h"
#include "py/mphal.h"
+#include "extmod/machine_bitstream.h"
#include "extmod/machine_mem.h"
#include "extmod/machine_signal.h"
#include "extmod/machine_pulse.h"
#include "extmod/machine_i2c.h"
#include "extmod/machine_spi.h"
-#include "lib/utils/pyexec.h"
+#include "shared/runtime/pyexec.h"
#include "lib/oofatfs/ff.h"
#include "extmod/vfs.h"
#include "extmod/vfs_fat.h"
@@ -406,6 +407,9 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_disable_irq), MP_ROM_PTR(&machine_disable_irq_obj) },
{ MP_ROM_QSTR(MP_QSTR_enable_irq), MP_ROM_PTR(&machine_enable_irq_obj) },
+ #if MICROPY_PY_MACHINE_BITSTREAM
+ { MP_ROM_QSTR(MP_QSTR_bitstream), MP_ROM_PTR(&machine_bitstream_obj) },
+ #endif
#if MICROPY_PY_MACHINE_PULSE
{ MP_ROM_QSTR(MP_QSTR_time_pulse_us), MP_ROM_PTR(&machine_time_pulse_us_obj) },
#endif
@@ -431,6 +435,9 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&machine_hard_spi_type) },
{ MP_ROM_QSTR(MP_QSTR_SoftSPI), MP_ROM_PTR(&mp_machine_soft_spi_type) },
#endif
+ #if MICROPY_HW_ENABLE_I2S
+ { MP_ROM_QSTR(MP_QSTR_I2S), MP_ROM_PTR(&machine_i2s_type) },
+ #endif
{ MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&pyb_uart_type) },
{ MP_ROM_QSTR(MP_QSTR_WDT), MP_ROM_PTR(&pyb_wdt_type) },
{ MP_ROM_QSTR(MP_QSTR_Timer), MP_ROM_PTR(&machine_timer_type) },
@@ -461,4 +468,3 @@ const mp_obj_module_t machine_module = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t *)&machine_module_globals,
};
-
diff --git a/ports/stm32/modmachine.h b/ports/stm32/modmachine.h
index e84620854..0e6c000a8 100644
--- a/ports/stm32/modmachine.h
+++ b/ports/stm32/modmachine.h
@@ -31,9 +31,11 @@
extern const mp_obj_type_t machine_adc_type;
extern const mp_obj_type_t machine_timer_type;
extern const mp_obj_type_t machine_hard_i2c_type;
+extern const mp_obj_type_t machine_i2s_type;
void machine_init(void);
void machine_deinit(void);
+void machine_i2s_init0();
MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(machine_info_obj);
MP_DECLARE_CONST_FUN_OBJ_0(machine_unique_id_obj);
diff --git a/ports/stm32/modnetwork.c b/ports/stm32/modnetwork.c
index 4279df088..06c4eb05d 100644
--- a/ports/stm32/modnetwork.c
+++ b/ports/stm32/modnetwork.c
@@ -31,7 +31,7 @@
#include "py/objlist.h"
#include "py/runtime.h"
#include "py/mphal.h"
-#include "lib/netutils/netutils.h"
+#include "shared/netutils/netutils.h"
#include "systick.h"
#include "pendsv.h"
#include "modnetwork.h"
diff --git a/ports/stm32/modnwcc3k.c b/ports/stm32/modnwcc3k.c
index b52958ba2..07178b65c 100644
--- a/ports/stm32/modnwcc3k.c
+++ b/ports/stm32/modnwcc3k.c
@@ -36,7 +36,7 @@
#include "py/runtime.h"
#include "py/mperrno.h"
#include "py/mphal.h"
-#include "lib/netutils/netutils.h"
+#include "shared/netutils/netutils.h"
#include "modnetwork.h"
#include "pin.h"
#include "spi.h"
diff --git a/ports/stm32/modnwwiznet5k.c b/ports/stm32/modnwwiznet5k.c
index 204b9fcc3..1e18d03ca 100644
--- a/ports/stm32/modnwwiznet5k.c
+++ b/ports/stm32/modnwwiznet5k.c
@@ -33,7 +33,7 @@
#include "py/stream.h"
#include "py/mperrno.h"
#include "py/mphal.h"
-#include "lib/netutils/netutils.h"
+#include "shared/netutils/netutils.h"
#include "modnetwork.h"
#include "pin.h"
#include "spi.h"
diff --git a/ports/stm32/modpyb.c b/ports/stm32/modpyb.c
index c92090699..b9e2bac03 100644
--- a/ports/stm32/modpyb.c
+++ b/ports/stm32/modpyb.c
@@ -29,7 +29,7 @@
#include "py/runtime.h"
#include "py/mphal.h"
-#include "lib/utils/pyexec.h"
+#include "shared/runtime/pyexec.h"
#include "drivers/dht/dht.h"
#include "stm32_it.h"
#include "irq.h"
diff --git a/ports/stm32/moduos.c b/ports/stm32/moduos.c
index 6f9740c64..5b2335272 100644
--- a/ports/stm32/moduos.c
+++ b/ports/stm32/moduos.c
@@ -30,7 +30,7 @@
#include "py/runtime.h"
#include "py/objtuple.h"
#include "py/objstr.h"
-#include "lib/timeutils/timeutils.h"
+#include "shared/timeutils/timeutils.h"
#include "lib/oofatfs/ff.h"
#include "lib/oofatfs/diskio.h"
#include "extmod/misc.h"
diff --git a/ports/stm32/modusocket.c b/ports/stm32/modusocket.c
index 2732d472b..c59fc8522 100644
--- a/ports/stm32/modusocket.c
+++ b/ports/stm32/modusocket.c
@@ -32,7 +32,7 @@
#include "py/runtime.h"
#include "py/stream.h"
#include "py/mperrno.h"
-#include "lib/netutils/netutils.h"
+#include "shared/netutils/netutils.h"
#include "modnetwork.h"
#if MICROPY_PY_USOCKET && !MICROPY_PY_LWIP
diff --git a/ports/stm32/modutime.c b/ports/stm32/modutime.c
index 4bce45eb3..1a22c34b6 100644
--- a/ports/stm32/modutime.c
+++ b/ports/stm32/modutime.c
@@ -30,7 +30,7 @@
#include "py/runtime.h"
#include "py/smallint.h"
#include "py/obj.h"
-#include "lib/timeutils/timeutils.h"
+#include "shared/timeutils/timeutils.h"
#include "extmod/utime_mphal.h"
#include "systick.h"
#include "portmodules.h"
diff --git a/ports/stm32/mpbthciport.c b/ports/stm32/mpbthciport.c
index accb913e1..369c91e30 100644
--- a/ports/stm32/mpbthciport.c
+++ b/ports/stm32/mpbthciport.c
@@ -31,7 +31,7 @@
#include "mpbthciport.h"
#include "softtimer.h"
#include "pendsv.h"
-#include "lib/utils/mpirq.h"
+#include "shared/runtime/mpirq.h"
#if MICROPY_PY_BLUETOOTH
diff --git a/ports/stm32/mpconfigboard_common.h b/ports/stm32/mpconfigboard_common.h
index ce9dbdb0a..0cf6adce3 100644
--- a/ports/stm32/mpconfigboard_common.h
+++ b/ports/stm32/mpconfigboard_common.h
@@ -177,6 +177,87 @@
#define MICROPY_HW_UART_IS_RESERVED(uart_id) (false)
#endif
+/*****************************************************************************/
+// USB configuration
+
+// The USBD_xxx macros have been renamed to MICROPY_HW_USB_xxx.
+#if defined(USBD_VID) \
+ || defined(USBD_LANGID_STRING) \
+ || defined(USBD_MANUFACTURER_STRING) \
+ || defined(USBD_PRODUCT_HS_STRING) \
+ || defined(USBD_PRODUCT_FS_STRING) \
+ || defined(USBD_CONFIGURATION_HS_STRING) \
+ || defined(USBD_INTERFACE_HS_STRING) \
+ || defined(USBD_CONFIGURATION_FS_STRING) \
+ || defined(USBD_INTERFACE_FS_STRING) \
+ || defined(USBD_CDC_RX_DATA_SIZE) \
+ || defined(USBD_CDC_TX_DATA_SIZE)
+#error "Old USBD_xxx configuration option used, renamed to MICROPY_HW_USB_xxx"
+#endif
+
+// Default VID and PID values to use for the USB device. If MICROPY_HW_USB_VID
+// is defined by a board then all needed PID options must also be defined. The
+// VID and PID can also be set dynamically in pyb.usb_mode().
+// Windows needs a different PID to distinguish different device configurations.
+#ifndef MICROPY_HW_USB_VID
+#define MICROPY_HW_USB_VID (0xf055)
+#define MICROPY_HW_USB_PID_CDC_MSC (0x9800)
+#define MICROPY_HW_USB_PID_CDC_HID (0x9801)
+#define MICROPY_HW_USB_PID_CDC (0x9802)
+#define MICROPY_HW_USB_PID_MSC (0x9803)
+#define MICROPY_HW_USB_PID_CDC2_MSC (0x9804)
+#define MICROPY_HW_USB_PID_CDC2 (0x9805)
+#define MICROPY_HW_USB_PID_CDC3 (0x9806)
+#define MICROPY_HW_USB_PID_CDC3_MSC (0x9807)
+#define MICROPY_HW_USB_PID_CDC_MSC_HID (0x9808)
+#define MICROPY_HW_USB_PID_CDC2_MSC_HID (0x9809)
+#define MICROPY_HW_USB_PID_CDC3_MSC_HID (0x980a)
+#endif
+
+#ifndef MICROPY_HW_USB_LANGID_STRING
+#define MICROPY_HW_USB_LANGID_STRING 0x409
+#endif
+
+#ifndef MICROPY_HW_USB_MANUFACTURER_STRING
+#define MICROPY_HW_USB_MANUFACTURER_STRING "MicroPython"
+#endif
+
+#ifndef MICROPY_HW_USB_PRODUCT_HS_STRING
+#define MICROPY_HW_USB_PRODUCT_HS_STRING "Pyboard Virtual Comm Port in HS Mode"
+#endif
+
+#ifndef MICROPY_HW_USB_PRODUCT_FS_STRING
+#define MICROPY_HW_USB_PRODUCT_FS_STRING "Pyboard Virtual Comm Port in FS Mode"
+#endif
+
+#ifndef MICROPY_HW_USB_CONFIGURATION_HS_STRING
+#define MICROPY_HW_USB_CONFIGURATION_HS_STRING "Pyboard Config"
+#endif
+
+#ifndef MICROPY_HW_USB_INTERFACE_HS_STRING
+#define MICROPY_HW_USB_INTERFACE_HS_STRING "Pyboard Interface"
+#endif
+
+#ifndef MICROPY_HW_USB_CONFIGURATION_FS_STRING
+#define MICROPY_HW_USB_CONFIGURATION_FS_STRING "Pyboard Config"
+#endif
+
+#ifndef MICROPY_HW_USB_INTERFACE_FS_STRING
+#define MICROPY_HW_USB_INTERFACE_FS_STRING "Pyboard Interface"
+#endif
+
+// Amount of incoming buffer space for each CDC instance.
+// This must be 2 or greater, and a power of 2.
+#ifndef MICROPY_HW_USB_CDC_RX_DATA_SIZE
+#define MICROPY_HW_USB_CDC_RX_DATA_SIZE (1024)
+#endif
+
+// Amount of outgoing buffer space for each CDC instance.
+// This must be a power of 2 and no greater than 16384.
+#ifndef MICROPY_HW_USB_CDC_TX_DATA_SIZE
+#define MICROPY_HW_USB_CDC_TX_DATA_SIZE (1024)
+#endif
+
/*****************************************************************************/
// General configuration
diff --git a/ports/stm32/mpconfigport.h b/ports/stm32/mpconfigport.h
index 6e341f34d..b6b34e0a7 100644
--- a/ports/stm32/mpconfigport.h
+++ b/ports/stm32/mpconfigport.h
@@ -56,7 +56,9 @@
#define MICROPY_COMP_RETURN_IF_EXPR (1)
// optimisations
+#ifndef MICROPY_OPT_COMPUTED_GOTO
#define MICROPY_OPT_COMPUTED_GOTO (1)
+#endif
#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (0)
#define MICROPY_OPT_MPZ_BITWISE (1)
#define MICROPY_OPT_MATH_FACTORIAL (1)
@@ -91,6 +93,9 @@
#define MICROPY_PY_FUNCTION_ATTRS (1)
#define MICROPY_PY_DESCRIPTORS (1)
#define MICROPY_PY_DELATTR_SETATTR (1)
+#ifndef MICROPY_PY_FSTRINGS
+#define MICROPY_PY_FSTRINGS (1)
+#endif
#define MICROPY_PY_BUILTINS_STR_UNICODE (1)
#define MICROPY_PY_BUILTINS_STR_CENTER (1)
#define MICROPY_PY_BUILTINS_STR_PARTITION (1)
@@ -190,6 +195,9 @@
#define MICROPY_PY_LWIP_SOCK_RAW (MICROPY_PY_LWIP)
#ifndef MICROPY_PY_MACHINE
#define MICROPY_PY_MACHINE (1)
+#ifndef MICROPY_PY_MACHINE_BITSTREAM
+#define MICROPY_PY_MACHINE_BITSTREAM (1)
+#endif
#define MICROPY_PY_MACHINE_PULSE (1)
#define MICROPY_PY_MACHINE_PIN_MAKE_NEW mp_pin_make_new
#define MICROPY_PY_MACHINE_I2C (1)
diff --git a/ports/stm32/mphalport.c b/ports/stm32/mphalport.c
index 0e40911ed..81e84ef93 100644
--- a/ports/stm32/mphalport.c
+++ b/ports/stm32/mphalport.c
@@ -53,10 +53,6 @@ MP_WEAK int mp_hal_stdin_rx_chr(void) {
}
}
-void mp_hal_stdout_tx_str(const char *str) {
- mp_hal_stdout_tx_strn(str, strlen(str));
-}
-
MP_WEAK void mp_hal_stdout_tx_strn(const char *str, size_t len) {
if (MP_STATE_PORT(pyb_stdio_uart) != NULL) {
uart_tx_strn(MP_STATE_PORT(pyb_stdio_uart), str, len);
@@ -67,26 +63,6 @@ MP_WEAK void mp_hal_stdout_tx_strn(const char *str, size_t len) {
mp_uos_dupterm_tx_strn(str, len);
}
-// Efficiently convert "\n" to "\r\n"
-void mp_hal_stdout_tx_strn_cooked(const char *str, size_t len) {
- const char *last = str;
- while (len--) {
- if (*str == '\n') {
- if (str > last) {
- mp_hal_stdout_tx_strn(last, str - last);
- }
- mp_hal_stdout_tx_strn("\r\n", 2);
- ++str;
- last = str;
- } else {
- ++str;
- }
- }
- if (str > last) {
- mp_hal_stdout_tx_strn(last, str - last);
- }
-}
-
#if __CORTEX_M >= 0x03
void mp_hal_ticks_cpu_enable(void) {
if (!(DWT->CTRL & DWT_CTRL_CYCCNTENA_Msk)) {
diff --git a/ports/stm32/network_wiznet5k.c b/ports/stm32/network_wiznet5k.c
index c85ef5e88..bd4c02cb0 100644
--- a/ports/stm32/network_wiznet5k.c
+++ b/ports/stm32/network_wiznet5k.c
@@ -34,7 +34,7 @@
#if MICROPY_PY_WIZNET5K && MICROPY_PY_LWIP
-#include "lib/netutils/netutils.h"
+#include "shared/netutils/netutils.h"
#include "drivers/wiznet5k/ethernet/socket.h"
#include "lwip/err.h"
#include "lwip/dns.h"
diff --git a/ports/stm32/pendsv.c b/ports/stm32/pendsv.c
index c5b2fcf92..d4c4496f1 100644
--- a/ports/stm32/pendsv.c
+++ b/ports/stm32/pendsv.c
@@ -27,7 +27,7 @@
#include
#include "py/runtime.h"
-#include "lib/utils/interrupt_char.h"
+#include "shared/runtime/interrupt_char.h"
#include "pendsv.h"
#include "irq.h"
diff --git a/ports/stm32/pin_defs_stm32.c b/ports/stm32/pin_defs_stm32.c
index a3f9d039d..070005d21 100644
--- a/ports/stm32/pin_defs_stm32.c
+++ b/ports/stm32/pin_defs_stm32.c
@@ -28,4 +28,3 @@ uint32_t pin_get_pull(const pin_obj_t *pin) {
uint32_t pin_get_af(const pin_obj_t *pin) {
return (pin->gpio->AFR[pin->pin >> 3] >> ((pin->pin & 7) * 4)) & 0xf;
}
-
diff --git a/ports/stm32/pin_defs_stm32.h b/ports/stm32/pin_defs_stm32.h
index 9285c190a..20faab4e0 100644
--- a/ports/stm32/pin_defs_stm32.h
+++ b/ports/stm32/pin_defs_stm32.h
@@ -109,6 +109,7 @@ enum {
// some #defines to massage things. Also I2S and SPI share the same
// peripheral.
+#define GPIO_AF5_I2S1 GPIO_AF5_SPI1
#define GPIO_AF5_I2S2 GPIO_AF5_SPI2
#define GPIO_AF5_I2S3 GPIO_AF5_I2S3ext
#define GPIO_AF6_I2S2 GPIO_AF6_I2S2ext
@@ -116,6 +117,7 @@ enum {
#define GPIO_AF7_I2S2 GPIO_AF7_SPI2
#define GPIO_AF7_I2S3 GPIO_AF7_I2S3ext
+#define I2S1 SPI1
#define I2S2 SPI2
#define I2S3 SPI3
@@ -134,4 +136,3 @@ enum {
};
typedef GPIO_TypeDef pin_gpio_t;
-
diff --git a/ports/stm32/powerctrl.c b/ports/stm32/powerctrl.c
index 253f1056c..137312ade 100644
--- a/ports/stm32/powerctrl.c
+++ b/ports/stm32/powerctrl.c
@@ -519,10 +519,103 @@ set_clk:
#elif defined(STM32WB)
+#include "stm32wbxx_ll_utils.h"
+
+#define LPR_THRESHOLD (2000000)
+#define VOS2_THRESHOLD (16000000)
+
+enum {
+ SYSCLK_MODE_NONE,
+ SYSCLK_MODE_MSI,
+ SYSCLK_MODE_HSE_64M,
+};
+
int powerctrl_set_sysclk(uint32_t sysclk, uint32_t ahb, uint32_t apb1, uint32_t apb2) {
- // For now it's not supported to change SYSCLK (only bus dividers).
- if (sysclk != HAL_RCC_GetSysClockFreq()) {
- return -MP_EINVAL;
+ int sysclk_mode = SYSCLK_MODE_NONE;
+ uint32_t msirange = 0;
+ uint32_t sysclk_cur = HAL_RCC_GetSysClockFreq();
+
+ if (sysclk == sysclk_cur) {
+ // SYSCLK does not need changing.
+ } else if (sysclk == 64000000) {
+ sysclk_mode = SYSCLK_MODE_HSE_64M;
+ } else {
+ for (msirange = 0; msirange < MP_ARRAY_SIZE(MSIRangeTable); ++msirange) {
+ if (MSIRangeTable[msirange] != 0 && sysclk == MSIRangeTable[msirange]) {
+ sysclk_mode = SYSCLK_MODE_MSI;
+ break;
+ }
+ }
+
+ if (sysclk_mode == SYSCLK_MODE_NONE) {
+ // Unsupported SYSCLK value.
+ return -MP_EINVAL;
+ }
+ }
+
+ // Exit LPR if SYSCLK will increase beyond threshold.
+ if (LL_PWR_IsEnabledLowPowerRunMode()) {
+ if (sysclk > LPR_THRESHOLD) {
+ if (sysclk_cur < LPR_THRESHOLD) {
+ // Must select MSI=LPR_THRESHOLD=2MHz to exit LPR.
+ LL_RCC_MSI_SetRange(LL_RCC_MSIRANGE_5);
+ }
+
+ // Exit LPR and wait for the regulator to be ready.
+ LL_PWR_ExitLowPowerRunMode();
+ while (!LL_PWR_IsActiveFlag_REGLPF()) {
+ }
+ }
+ }
+
+ // Select VOS1 if SYSCLK will increase beyond threshold.
+ if (sysclk > VOS2_THRESHOLD) {
+ LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE1);
+ while (LL_PWR_IsActiveFlag_VOS()) {
+ }
+ }
+
+ if (sysclk_mode == SYSCLK_MODE_HSE_64M) {
+ SystemClock_Config();
+ } else if (sysclk_mode == SYSCLK_MODE_MSI) {
+ // Set flash latency to maximum to ensure the latency is large enough for
+ // both the current SYSCLK and the SYSCLK that will be selected below.
+ LL_FLASH_SetLatency(LL_FLASH_LATENCY_3);
+ while (LL_FLASH_GetLatency() != LL_FLASH_LATENCY_3) {
+ }
+
+ // Before changing the MSIRANGE value, if MSI is on then it must also be ready.
+ while ((RCC->CR & (RCC_CR_MSIRDY | RCC_CR_MSION)) == RCC_CR_MSION) {
+ }
+ LL_RCC_MSI_SetRange(msirange << RCC_CR_MSIRANGE_Pos);
+
+ // Clock SYSCLK from MSI.
+ LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_MSI);
+ while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_MSI) {
+ }
+
+ // Disable PLL to decrease power consumption.
+ LL_RCC_PLL_Disable();
+ while (LL_RCC_PLL_IsReady() != 0) {
+ }
+ LL_RCC_PLL_DisableDomain_SYS();
+
+ // Select VOS2 if possible.
+ if (sysclk <= VOS2_THRESHOLD) {
+ LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE2);
+ }
+
+ // Enter LPR if possible.
+ if (sysclk <= LPR_THRESHOLD) {
+ LL_PWR_EnterLowPowerRunMode();
+ }
+
+ // Configure flash latency for the new SYSCLK.
+ LL_SetFlashLatency(sysclk);
+
+ // Update HAL state and SysTick.
+ SystemCoreClockUpdate();
+ powerctrl_config_systick();
}
// Return straightaway if the clocks are already at the desired frequency.
diff --git a/ports/stm32/powerctrl.h b/ports/stm32/powerctrl.h
index 9f223e794..eedc448b2 100644
--- a/ports/stm32/powerctrl.h
+++ b/ports/stm32/powerctrl.h
@@ -35,6 +35,7 @@ NORETURN void powerctrl_mcu_reset(void);
NORETURN void powerctrl_enter_bootloader(uint32_t r0, uint32_t bl_addr);
void powerctrl_check_enter_bootloader(void);
+void powerctrl_config_systick(void);
int powerctrl_rcc_clock_config_pll(RCC_ClkInitTypeDef *rcc_init, uint32_t sysclk_mhz, bool need_pllsai);
int powerctrl_set_sysclk(uint32_t sysclk, uint32_t ahb, uint32_t apb1, uint32_t apb2);
void powerctrl_enter_stop_mode(void);
diff --git a/ports/stm32/powerctrlboot.c b/ports/stm32/powerctrlboot.c
index 880e43e04..caa563292 100644
--- a/ports/stm32/powerctrlboot.c
+++ b/ports/stm32/powerctrlboot.c
@@ -28,7 +28,7 @@
#include "irq.h"
#include "powerctrl.h"
-static inline void powerctrl_config_systick(void) {
+void powerctrl_config_systick(void) {
// Configure SYSTICK to run at 1kHz (1ms interval)
SysTick->CTRL |= SYSTICK_CLKSOURCE_HCLK;
SysTick_Config(HAL_RCC_GetHCLKFreq() / 1000);
diff --git a/ports/stm32/pyb_i2c.c b/ports/stm32/pyb_i2c.c
index f0bd38333..dbcf4bcb8 100644
--- a/ports/stm32/pyb_i2c.c
+++ b/ports/stm32/pyb_i2c.c
@@ -49,14 +49,14 @@
/// from pyb import I2C
///
/// i2c = I2C(1) # create on bus 1
-/// i2c = I2C(1, I2C.MASTER) # create and init as a master
-/// i2c.init(I2C.MASTER, baudrate=20000) # init as a master
-/// i2c.init(I2C.SLAVE, addr=0x42) # init as a slave with given address
-/// i2c.deinit() # turn off the peripheral
+/// i2c = I2C(1, I2C.CONTROLLER) # create and init as a controller
+/// i2c.init(I2C.CONTROLLER, baudrate=20000) # init as a controller
+/// i2c.init(I2C.PERIPHERAL, addr=0x42) # init as a peripheral with given address
+/// i2c.deinit() # turn off the I2C unit
///
/// Printing the i2c object gives you information about its configuration.
///
-/// Basic methods for slave are send and recv:
+/// Basic methods for peripheral are send and recv:
///
/// i2c.send('abc') # send 3 bytes
/// i2c.send(0x42) # send a single byte, given by the number
@@ -71,19 +71,19 @@
///
/// i2c.send(b'123', timeout=2000) # timout after 2 seconds
///
-/// A master must specify the recipient's address:
+/// A controller must specify the recipient's address:
///
-/// i2c.init(I2C.MASTER)
-/// i2c.send('123', 0x42) # send 3 bytes to slave with address 0x42
+/// i2c.init(I2C.CONTROLLER)
+/// i2c.send('123', 0x42) # send 3 bytes to peripheral with address 0x42
/// i2c.send(b'456', addr=0x42) # keyword for address
///
/// Master also has other methods:
///
-/// i2c.is_ready(0x42) # check if slave 0x42 is ready
-/// i2c.scan() # scan for slaves on the bus, returning
+/// i2c.is_ready(0x42) # check if peripheral 0x42 is ready
+/// i2c.scan() # scan for peripherals on the bus, returning
/// # a list of valid addresses
-/// i2c.mem_read(3, 0x42, 2) # read 3 bytes from memory of slave 0x42,
-/// # starting at address 2 in the slave
+/// i2c.mem_read(3, 0x42, 2) # read 3 bytes from memory of peripheral 0x42,
+/// # starting at address 2 in the peripheral
/// i2c.mem_write('abc', 0x42, 2, timeout=1000)
#define PYB_I2C_MASTER (0)
#define PYB_I2C_SLAVE (1)
@@ -578,7 +578,7 @@ STATIC void pyb_i2c_print(const mp_print_t *print, mp_obj_t self_in, mp_print_ki
mp_printf(print, "I2C(%u)", i2c_num);
} else {
if (in_master_mode(self)) {
- mp_printf(print, "I2C(%u, I2C.MASTER, baudrate=%u"
+ mp_printf(print, "I2C(%u, I2C.CONTROLLER, baudrate=%u"
#if PYB_I2C_TIMINGR
", timingr=0x%08x"
#endif
@@ -588,7 +588,7 @@ STATIC void pyb_i2c_print(const mp_print_t *print, mp_obj_t self_in, mp_print_ki
#endif
);
} else {
- mp_printf(print, "I2C(%u, I2C.SLAVE, addr=0x%02x)", i2c_num, (self->i2c->Instance->OAR1 >> 1) & 0x7f);
+ mp_printf(print, "I2C(%u, I2C.PERIPHERAL, addr=0x%02x)", i2c_num, (self->i2c->Instance->OAR1 >> 1) & 0x7f);
}
}
}
@@ -597,9 +597,9 @@ STATIC void pyb_i2c_print(const mp_print_t *print, mp_obj_t self_in, mp_print_ki
///
/// Initialise the I2C bus with the given parameters:
///
-/// - `mode` must be either `I2C.MASTER` or `I2C.SLAVE`
-/// - `addr` is the 7-bit address (only sensible for a slave)
-/// - `baudrate` is the SCL clock rate (only sensible for a master)
+/// - `mode` must be either `I2C.CONTROLLER` or `I2C.PERIPHERAL`
+/// - `addr` is the 7-bit address (only sensible for a peripheral)
+/// - `baudrate` is the SCL clock rate (only sensible for a controller)
/// - `gencall` is whether to support general call mode
STATIC mp_obj_t pyb_i2c_init_helper(const pyb_i2c_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
static const mp_arg_t allowed_args[] = {
@@ -621,7 +621,7 @@ STATIC mp_obj_t pyb_i2c_init_helper(const pyb_i2c_obj_t *self, size_t n_args, co
I2C_InitTypeDef *init = &self->i2c->Init;
if (args[0].u_int == PYB_I2C_MASTER) {
- // use a special address to indicate we are a master
+ // use a special address to indicate we are a controller
init->OwnAddress1 = PYB_I2C_MASTER_ADDRESS;
} else {
init->OwnAddress1 = (args[1].u_int << 1) & 0xfe;
@@ -697,12 +697,12 @@ STATIC mp_obj_t pyb_i2c_deinit(mp_obj_t self_in) {
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_i2c_deinit_obj, pyb_i2c_deinit);
/// \method is_ready(addr)
-/// Check if an I2C device responds to the given address. Only valid when in master mode.
+/// Check if an I2C device responds to the given address. Only valid when in controller mode.
STATIC mp_obj_t pyb_i2c_is_ready(mp_obj_t self_in, mp_obj_t i2c_addr_o) {
pyb_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in);
if (!in_master_mode(self)) {
- mp_raise_TypeError(MP_ERROR_TEXT("I2C must be a master"));
+ mp_raise_TypeError(MP_ERROR_TEXT("I2C must be a controller"));
}
mp_uint_t i2c_addr = mp_obj_get_int(i2c_addr_o) << 1;
@@ -720,12 +720,12 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_i2c_is_ready_obj, pyb_i2c_is_ready);
/// \method scan()
/// Scan all I2C addresses from 0x08 to 0x77 and return a list of those that respond.
-/// Only valid when in master mode.
+/// Only valid when in controller mode.
STATIC mp_obj_t pyb_i2c_scan(mp_obj_t self_in) {
pyb_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in);
if (!in_master_mode(self)) {
- mp_raise_TypeError(MP_ERROR_TEXT("I2C must be a master"));
+ mp_raise_TypeError(MP_ERROR_TEXT("I2C must be a controller"));
}
mp_obj_t list = mp_obj_new_list(0, NULL);
@@ -745,7 +745,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_i2c_scan_obj, pyb_i2c_scan);
/// Send data on the bus:
///
/// - `send` is the data to send (an integer to send, or a buffer object)
-/// - `addr` is the address to send to (only required in master mode)
+/// - `addr` is the address to send to (only required in controller mode)
/// - `timeout` is the timeout in milliseconds to wait for the send
///
/// Return value: `None`.
@@ -824,7 +824,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_send_obj, 1, pyb_i2c_send);
///
/// - `recv` can be an integer, which is the number of bytes to receive,
/// or a mutable buffer, which will be filled with received bytes
-/// - `addr` is the address to receive from (only required in master mode)
+/// - `addr` is the address to receive from (only required in controller mode)
/// - `timeout` is the timeout in milliseconds to wait for the receive
///
/// Return value: if `recv` is an integer then a new buffer of the bytes received,
@@ -910,7 +910,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_recv_obj, 1, pyb_i2c_recv);
/// - `addr_size` selects width of memaddr: 8 or 16 bits
///
/// Returns the read data.
-/// This is only valid in master mode.
+/// This is only valid in controller mode.
STATIC const mp_arg_t pyb_i2c_mem_read_allowed_args[] = {
{ MP_QSTR_data, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
{ MP_QSTR_addr, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
@@ -926,7 +926,7 @@ STATIC mp_obj_t pyb_i2c_mem_read(size_t n_args, const mp_obj_t *pos_args, mp_map
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(pyb_i2c_mem_read_allowed_args), pyb_i2c_mem_read_allowed_args, args);
if (!in_master_mode(self)) {
- mp_raise_TypeError(MP_ERROR_TEXT("I2C must be a master"));
+ mp_raise_TypeError(MP_ERROR_TEXT("I2C must be a controller"));
}
// get the buffer to read into
@@ -986,7 +986,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_mem_read_obj, 1, pyb_i2c_mem_read);
/// - `addr_size` selects width of memaddr: 8 or 16 bits
///
/// Returns `None`.
-/// This is only valid in master mode.
+/// This is only valid in controller mode.
STATIC mp_obj_t pyb_i2c_mem_write(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
// parse args (same as mem_read)
pyb_i2c_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
@@ -994,7 +994,7 @@ STATIC mp_obj_t pyb_i2c_mem_write(size_t n_args, const mp_obj_t *pos_args, mp_ma
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(pyb_i2c_mem_read_allowed_args), pyb_i2c_mem_read_allowed_args, args);
if (!in_master_mode(self)) {
- mp_raise_TypeError(MP_ERROR_TEXT("I2C must be a master"));
+ mp_raise_TypeError(MP_ERROR_TEXT("I2C must be a controller"));
}
// get the buffer to write from
@@ -1051,8 +1051,11 @@ STATIC const mp_rom_map_elem_t pyb_i2c_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_mem_write), MP_ROM_PTR(&pyb_i2c_mem_write_obj) },
// class constants
- /// \constant MASTER - for initialising the bus to master mode
- /// \constant SLAVE - for initialising the bus to slave mode
+ /// \constant CONTROLLER - for initialising the bus to controller mode
+ /// \constant PERIPHERAL - for initialising the bus to peripheral mode
+ { MP_ROM_QSTR(MP_QSTR_CONTROLLER), MP_ROM_INT(PYB_I2C_MASTER) },
+ { MP_ROM_QSTR(MP_QSTR_PERIPHERAL), MP_ROM_INT(PYB_I2C_SLAVE) },
+ // TODO - remove MASTER/SLAVE when CONTROLLER/PERIPHERAL gain wide adoption
{ MP_ROM_QSTR(MP_QSTR_MASTER), MP_ROM_INT(PYB_I2C_MASTER) },
{ MP_ROM_QSTR(MP_QSTR_SLAVE), MP_ROM_INT(PYB_I2C_SLAVE) },
};
diff --git a/ports/stm32/pyb_spi.c b/ports/stm32/pyb_spi.c
index 99a1cd77b..abb7ba41d 100644
--- a/ports/stm32/pyb_spi.c
+++ b/ports/stm32/pyb_spi.c
@@ -32,18 +32,18 @@
/******************************************************************************/
// MicroPython bindings for legacy pyb API
-// class pyb.SPI - a master-driven serial protocol
+// class pyb.SPI - a controller-driven serial protocol
//
-// SPI is a serial protocol that is driven by a master. At the physical level
+// SPI is a serial protocol that is driven by a controller. At the physical level
// there are 3 lines: SCK, MOSI, MISO.
//
// See usage model of I2C; SPI is very similar. Main difference is
// parameters to init the SPI bus:
//
// from pyb import SPI
-// spi = SPI(1, SPI.MASTER, baudrate=600000, polarity=1, phase=0, crc=0x7)
+// spi = SPI(1, SPI.CONTROLLER, baudrate=600000, polarity=1, phase=0, crc=0x7)
//
-// Only required parameter is mode, SPI.MASTER or SPI.SLAVE. Polarity can be
+// Only required parameter is mode, SPI.CONTROLLER or SPI.PERIPHERAL. Polarity can be
// 0 or 1, and is the level the idle clock line sits at. Phase can be 0 or 1
// to sample data on the first or second clock edge respectively. Crc can be
// None for no CRC, or a polynomial specifier.
@@ -72,8 +72,8 @@ STATIC void pyb_spi_print(const mp_print_t *print, mp_obj_t self_in, mp_print_ki
// init(mode, baudrate=328125, *, polarity=1, phase=0, bits=8, firstbit=SPI.MSB, ti=False, crc=None)
//
// Initialise the SPI bus with the given parameters:
-// - `mode` must be either `SPI.MASTER` or `SPI.SLAVE`.
-// - `baudrate` is the SCK clock rate (only sensible for a master).
+// - `mode` must be either `SPI.CONTROLLER` or `SPI.PERIPHERAL`.
+// - `baudrate` is the SCK clock rate (only sensible for a controller).
STATIC mp_obj_t pyb_spi_init_helper(const pyb_spi_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_mode, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
@@ -319,10 +319,13 @@ STATIC const mp_rom_map_elem_t pyb_spi_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_send_recv), MP_ROM_PTR(&pyb_spi_send_recv_obj) },
// class constants
- /// \constant MASTER - for initialising the bus to master mode
- /// \constant SLAVE - for initialising the bus to slave mode
+ /// \constant CONTROLLER - for initialising the bus to controller mode
+ /// \constant PERIPHERAL - for initialising the bus to peripheral mode
/// \constant MSB - set the first bit to MSB
/// \constant LSB - set the first bit to LSB
+ { MP_ROM_QSTR(MP_QSTR_CONTROLLER), MP_ROM_INT(SPI_MODE_MASTER) },
+ { MP_ROM_QSTR(MP_QSTR_PERIPHERAL), MP_ROM_INT(SPI_MODE_SLAVE) },
+ // TODO - remove MASTER/SLAVE when CONTROLLER/PERIPHERAL gain wide adoption
{ MP_ROM_QSTR(MP_QSTR_MASTER), MP_ROM_INT(SPI_MODE_MASTER) },
{ MP_ROM_QSTR(MP_QSTR_SLAVE), MP_ROM_INT(SPI_MODE_SLAVE) },
{ MP_ROM_QSTR(MP_QSTR_MSB), MP_ROM_INT(SPI_FIRSTBIT_MSB) },
diff --git a/ports/stm32/rtc.c b/ports/stm32/rtc.c
index 02b0f2dbd..ab8b49e18 100644
--- a/ports/stm32/rtc.c
+++ b/ports/stm32/rtc.c
@@ -27,7 +27,7 @@
#include
#include "py/runtime.h"
-#include "lib/timeutils/timeutils.h"
+#include "shared/timeutils/timeutils.h"
#include "extint.h"
#include "rtc.h"
#include "irq.h"
diff --git a/ports/stm32/sdram.c b/ports/stm32/sdram.c
index 514192519..e0e350083 100644
--- a/ports/stm32/sdram.c
+++ b/ports/stm32/sdram.c
@@ -283,52 +283,106 @@ void sdram_leave_low_power(void) {
#pragma GCC diagnostic ignored "-Wstringop-overflow"
#endif
-bool sdram_test(bool fast) {
+bool __attribute__((optimize("O0"))) sdram_test(bool exhaustive) {
uint8_t const pattern = 0xaa;
uint8_t const antipattern = 0x55;
uint8_t *const mem_base = (uint8_t *)sdram_start();
- /* test data bus */
- for (uint8_t i = 1; i; i <<= 1) {
- *mem_base = i;
- if (*mem_base != i) {
- printf("data bus lines test failed! data (%d)\n", i);
+ #if MICROPY_HW_SDRAM_TEST_FAIL_ON_ERROR
+ char error_buffer[1024];
+ #endif
+
+ #if (__DCACHE_PRESENT == 1)
+ bool i_cache_disabled = false;
+ bool d_cache_disabled = false;
+
+ // Disable caches for testing.
+ if (SCB->CCR & (uint32_t)SCB_CCR_IC_Msk) {
+ SCB_DisableICache();
+ i_cache_disabled = true;
+ }
+
+ if (SCB->CCR & (uint32_t)SCB_CCR_DC_Msk) {
+ SCB_DisableDCache();
+ d_cache_disabled = true;
+ }
+ #endif
+
+ // Test data bus
+ for (uint32_t i = 0; i < MICROPY_HW_SDRAM_MEM_BUS_WIDTH; i++) {
+ *((uint32_t *)mem_base) = (1 << i);
+ if (*((uint32_t *)mem_base) != (1 << i)) {
+ #if MICROPY_HW_SDRAM_TEST_FAIL_ON_ERROR
+ snprintf(error_buffer, sizeof(error_buffer),
+ "Data bus test failed at 0x%p expected 0x%x found 0x%lx",
+ &mem_base[0], (1 << i), ((uint32_t *)mem_base)[0]);
+ __fatal_error(error_buffer);
+ #endif
return false;
}
}
- /* test address bus */
- /* Check individual address lines */
+ // Test address bus
for (uint32_t i = 1; i < MICROPY_HW_SDRAM_SIZE; i <<= 1) {
mem_base[i] = pattern;
if (mem_base[i] != pattern) {
- printf("address bus lines test failed! address (%p)\n", &mem_base[i]);
+ #if MICROPY_HW_SDRAM_TEST_FAIL_ON_ERROR
+ snprintf(error_buffer, sizeof(error_buffer),
+ "Address bus test failed at 0x%p expected 0x%x found 0x%x",
+ &mem_base[i], pattern, mem_base[i]);
+ __fatal_error(error_buffer);
+ #endif
return false;
}
}
- /* Check for aliasing (overlaping addresses) */
+ // Check for aliasing (overlaping addresses)
mem_base[0] = antipattern;
for (uint32_t i = 1; i < MICROPY_HW_SDRAM_SIZE; i <<= 1) {
if (mem_base[i] != pattern) {
- printf("address bus overlap %p\n", &mem_base[i]);
+ #if MICROPY_HW_SDRAM_TEST_FAIL_ON_ERROR
+ snprintf(error_buffer, sizeof(error_buffer),
+ "Address bus overlap at 0x%p expected 0x%x found 0x%x",
+ &mem_base[i], pattern, mem_base[i]);
+ __fatal_error(error_buffer);
+ #endif
return false;
}
}
- /* test all ram cells */
- if (!fast) {
- for (uint32_t i = 0; i < MICROPY_HW_SDRAM_SIZE; ++i) {
+ // Test all RAM cells
+ if (exhaustive) {
+ // Write all memory first then compare, so even if the cache
+ // is enabled, it's not just writing and reading from cache.
+ // Note: This test should also detect refresh rate issues.
+ for (uint32_t i = 0; i < MICROPY_HW_SDRAM_SIZE; i++) {
mem_base[i] = pattern;
+ }
+
+ for (uint32_t i = 0; i < MICROPY_HW_SDRAM_SIZE; i++) {
if (mem_base[i] != pattern) {
- printf("address bus test failed! address (%p)\n", &mem_base[i]);
+ #if MICROPY_HW_SDRAM_TEST_FAIL_ON_ERROR
+ snprintf(error_buffer, sizeof(error_buffer),
+ "Address bus slow test failed at 0x%p expected 0x%x found 0x%x",
+ &mem_base[i], pattern, mem_base[i]);
+ __fatal_error(error_buffer);
+ #endif
return false;
}
}
- } else {
- memset(mem_base, pattern, MICROPY_HW_SDRAM_SIZE);
}
+ #if (__DCACHE_PRESENT == 1)
+ // Re-enable caches if they were enabled before the test started.
+ if (i_cache_disabled) {
+ SCB_EnableICache();
+ }
+
+ if (d_cache_disabled) {
+ SCB_EnableDCache();
+ }
+ #endif
+
return true;
}
diff --git a/ports/stm32/sdram.h b/ports/stm32/sdram.h
index 773a30802..f7a124add 100644
--- a/ports/stm32/sdram.h
+++ b/ports/stm32/sdram.h
@@ -13,5 +13,5 @@ void *sdram_start(void);
void *sdram_end(void);
void sdram_enter_low_power(void);
void sdram_leave_low_power(void);
-bool sdram_test(bool fast);
+bool sdram_test(bool exhaustive);
#endif // __SDRAM_H__
diff --git a/ports/stm32/spi.c b/ports/stm32/spi.c
index d3b3a784e..0ce6b5abc 100644
--- a/ports/stm32/spi.c
+++ b/ports/stm32/spi.c
@@ -640,14 +640,14 @@ void spi_print(const mp_print_t *print, const spi_t *spi_obj, bool legacy) {
#endif
uint baudrate = spi_get_source_freq(spi) >> log_prescaler;
if (legacy) {
- mp_printf(print, ", SPI.MASTER");
+ mp_printf(print, ", SPI.CONTROLLER");
}
mp_printf(print, ", baudrate=%u", baudrate);
if (legacy) {
mp_printf(print, ", prescaler=%u", 1 << log_prescaler);
}
} else {
- mp_printf(print, ", SPI.SLAVE");
+ mp_printf(print, ", SPI.PERIPHERAL");
}
mp_printf(print, ", polarity=%u, phase=%u, bits=%u", spi->Init.CLKPolarity == SPI_POLARITY_LOW ? 0 : 1, spi->Init.CLKPhase == SPI_PHASE_1EDGE ? 0 : 1, spi->Init.DataSize == SPI_DATASIZE_8BIT ? 8 : 16);
if (spi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE) {
diff --git a/ports/stm32/spibdev.c b/ports/stm32/spibdev.c
index 5090b43b1..afa6f4ecd 100644
--- a/ports/stm32/spibdev.c
+++ b/ports/stm32/spibdev.c
@@ -59,13 +59,6 @@ int32_t spi_bdev_ioctl(spi_bdev_t *bdev, uint32_t op, uint32_t arg) {
}
#endif
return 0;
-
- case BDEV_IOCTL_BLOCK_ERASE: {
- uint32_t basepri = raise_irq_pri(IRQ_PRI_FLASH); // prevent cache flushing and USB access
- mp_spiflash_erase_block(&bdev->spiflash, arg * MP_SPIFLASH_ERASE_BLOCK_SIZE);
- restore_irq_pri(basepri);
- return 0;
- }
}
return -MP_EINVAL;
}
@@ -108,4 +101,19 @@ int spi_bdev_writeblocks_raw(spi_bdev_t *bdev, const uint8_t *src, uint32_t bloc
return ret;
}
+int spi_bdev_eraseblocks_raw(spi_bdev_t *bdev, uint32_t block_num, uint32_t num_bytes) {
+ int ret = 0;
+ while (num_bytes >= MP_SPIFLASH_ERASE_BLOCK_SIZE) {
+ uint32_t basepri = raise_irq_pri(IRQ_PRI_FLASH); // prevent cache flushing and USB access
+ ret = mp_spiflash_erase_block(&bdev->spiflash, block_num * MP_SPIFLASH_ERASE_BLOCK_SIZE);
+ restore_irq_pri(basepri);
+ if (ret) {
+ break;
+ }
+ block_num += 1;
+ num_bytes -= MP_SPIFLASH_ERASE_BLOCK_SIZE;
+ }
+ return ret;
+}
+
#endif
diff --git a/ports/stm32/stm32_it.c b/ports/stm32/stm32_it.c
index 3533419d9..fcd5b034a 100644
--- a/ports/stm32/stm32_it.c
+++ b/ports/stm32/stm32_it.c
@@ -625,7 +625,7 @@ void TIM1_TRG_COM_TIM11_IRQHandler(void) {
IRQ_EXIT(TIM1_TRG_COM_TIM11_IRQn);
}
-#if defined(STM32L4)
+#if defined(STM32L4) || defined(STM32WB)
void TIM1_TRG_COM_TIM17_IRQHandler(void) {
IRQ_ENTER(TIM1_TRG_COM_TIM17_IRQn);
timer_irq_handler(17);
diff --git a/ports/stm32/storage.c b/ports/stm32/storage.c
index a71c4a3ea..fcc6d51b3 100644
--- a/ports/stm32/storage.c
+++ b/ports/stm32/storage.c
@@ -234,24 +234,27 @@ int storage_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t num_bl
#ifdef MICROPY_HW_BDEV_SPIFLASH_EXTENDED
// Board defined an external SPI flash for use with extended block protocol
-#define SPIFLASH (MICROPY_HW_BDEV_SPIFLASH_EXTENDED)
-#define PYB_FLASH_NATIVE_BLOCK_SIZE (MP_SPIFLASH_ERASE_BLOCK_SIZE)
-#define MICROPY_HW_BDEV_READBLOCKS_EXT(dest, bl, off, len) (spi_bdev_readblocks_raw(SPIFLASH, (dest), (bl), (off), (len)))
-#define MICROPY_HW_BDEV_WRITEBLOCKS_EXT(dest, bl, off, len) (spi_bdev_writeblocks_raw(SPIFLASH, (dest), (bl), (off), (len)))
+#define MICROPY_HW_BDEV_BLOCKSIZE_EXT (MP_SPIFLASH_ERASE_BLOCK_SIZE)
+#define MICROPY_HW_BDEV_READBLOCKS_EXT(dest, bl, off, len) \
+ (spi_bdev_readblocks_raw(MICROPY_HW_BDEV_SPIFLASH_EXTENDED, (dest), (bl), (off), (len)))
+#define MICROPY_HW_BDEV_WRITEBLOCKS_EXT(src, bl, off, len) \
+ (spi_bdev_writeblocks_raw(MICROPY_HW_BDEV_SPIFLASH_EXTENDED, (src), (bl), (off), (len)))
+#define MICROPY_HW_BDEV_ERASEBLOCKS_EXT(bl, len) \
+ (spi_bdev_eraseblocks_raw(MICROPY_HW_BDEV_SPIFLASH_EXTENDED, (bl), (len)))
#elif (MICROPY_VFS_LFS1 || MICROPY_VFS_LFS2) && MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE
// Board uses littlefs and internal flash, so enable extended block protocol on internal flash
-#define PYB_FLASH_NATIVE_BLOCK_SIZE (FLASH_BLOCK_SIZE)
+#define MICROPY_HW_BDEV_BLOCKSIZE_EXT (FLASH_BLOCK_SIZE)
#define MICROPY_HW_BDEV_READBLOCKS_EXT(dest, bl, off, len) (flash_bdev_readblocks_ext((dest), (bl), (off), (len)))
#define MICROPY_HW_BDEV_WRITEBLOCKS_EXT(dest, bl, off, len) (flash_bdev_writeblocks_ext((dest), (bl), (off), (len)))
#endif
-#ifndef PYB_FLASH_NATIVE_BLOCK_SIZE
-#define PYB_FLASH_NATIVE_BLOCK_SIZE (FLASH_BLOCK_SIZE)
+#ifndef MICROPY_HW_BDEV_BLOCKSIZE_EXT
+#define MICROPY_HW_BDEV_BLOCKSIZE_EXT (FLASH_BLOCK_SIZE)
#endif
#if defined(MICROPY_HW_BDEV_READBLOCKS_EXT)
-// Size of blocks is PYB_FLASH_NATIVE_BLOCK_SIZE
+// Size of blocks is MICROPY_HW_BDEV_BLOCKSIZE_EXT
int storage_readblocks_ext(uint8_t *dest, uint32_t block, uint32_t offset, uint32_t len) {
return MICROPY_HW_BDEV_READBLOCKS_EXT(dest, block, offset, len);
}
@@ -261,9 +264,7 @@ typedef struct _pyb_flash_obj_t {
mp_obj_base_t base;
uint32_t start; // in bytes
uint32_t len; // in bytes
- #if defined(SPIFLASH)
bool use_native_block_size;
- #endif
} pyb_flash_obj_t;
// This Flash object represents the entire available flash, with emulated partition table at start
@@ -299,23 +300,21 @@ STATIC mp_obj_t pyb_flash_make_new(const mp_obj_type_t *type, size_t n_args, siz
pyb_flash_obj_t *self = m_new_obj(pyb_flash_obj_t);
self->base.type = &pyb_flash_type;
- #if defined(SPIFLASH)
self->use_native_block_size = false;
- #endif
uint32_t bl_len = (storage_get_block_count() - FLASH_PART1_START_BLOCK) * FLASH_BLOCK_SIZE;
mp_int_t start = args[ARG_start].u_int;
if (start == -1) {
start = 0;
- } else if (!(0 <= start && start < bl_len && start % PYB_FLASH_NATIVE_BLOCK_SIZE == 0)) {
+ } else if (!(0 <= start && start < bl_len && start % MICROPY_HW_BDEV_BLOCKSIZE_EXT == 0)) {
mp_raise_ValueError(NULL);
}
mp_int_t len = args[ARG_len].u_int;
if (len == -1) {
len = bl_len - start;
- } else if (!(0 < len && start + len <= bl_len && len % PYB_FLASH_NATIVE_BLOCK_SIZE == 0)) {
+ } else if (!(0 < len && start + len <= bl_len && len % MICROPY_HW_BDEV_BLOCKSIZE_EXT == 0)) {
mp_raise_ValueError(NULL);
}
@@ -340,10 +339,10 @@ STATIC mp_obj_t pyb_flash_readblocks(size_t n_args, const mp_obj_t *args) {
else if (self != &pyb_flash_obj) {
// Extended block read on a sub-section of the flash storage
uint32_t offset = mp_obj_get_int(args[3]);
- if ((block_num * PYB_FLASH_NATIVE_BLOCK_SIZE) >= self->len) {
+ if ((block_num * MICROPY_HW_BDEV_BLOCKSIZE_EXT) >= self->len) {
ret = -MP_EFAULT; // Bad address
} else {
- block_num += self->start / PYB_FLASH_NATIVE_BLOCK_SIZE;
+ block_num += self->start / MICROPY_HW_BDEV_BLOCKSIZE_EXT;
ret = MICROPY_HW_BDEV_READBLOCKS_EXT(bufinfo.buf, block_num, offset, bufinfo.len);
}
}
@@ -367,10 +366,10 @@ STATIC mp_obj_t pyb_flash_writeblocks(size_t n_args, const mp_obj_t *args) {
else if (self != &pyb_flash_obj) {
// Extended block write on a sub-section of the flash storage
uint32_t offset = mp_obj_get_int(args[3]);
- if ((block_num * PYB_FLASH_NATIVE_BLOCK_SIZE) >= self->len) {
+ if ((block_num * MICROPY_HW_BDEV_BLOCKSIZE_EXT) >= self->len) {
ret = -MP_EFAULT; // Bad address
} else {
- block_num += self->start / PYB_FLASH_NATIVE_BLOCK_SIZE;
+ block_num += self->start / MICROPY_HW_BDEV_BLOCKSIZE_EXT;
ret = MICROPY_HW_BDEV_WRITEBLOCKS_EXT(bufinfo.buf, block_num, offset, bufinfo.len);
}
}
@@ -390,11 +389,9 @@ STATIC mp_obj_t pyb_flash_ioctl(mp_obj_t self_in, mp_obj_t cmd_in, mp_obj_t arg_
// Will be using extended block protocol
if (self == &pyb_flash_obj) {
ret = -1;
- #if defined(SPIFLASH)
} else {
- // Switch to use native block size of SPI flash
+ // Switch to use native block size of the underlying storage.
self->use_native_block_size = true;
- #endif
}
}
return MP_OBJ_NEW_SMALL_INT(ret);
@@ -411,10 +408,8 @@ STATIC mp_obj_t pyb_flash_ioctl(mp_obj_t self_in, mp_obj_t cmd_in, mp_obj_t arg_
if (self == &pyb_flash_obj) {
// Get true size
n = storage_get_block_count();
- #if defined(SPIFLASH)
} else if (self->use_native_block_size) {
- n = self->len / PYB_FLASH_NATIVE_BLOCK_SIZE;
- #endif
+ n = self->len / MICROPY_HW_BDEV_BLOCKSIZE_EXT;
} else {
n = self->len / FLASH_BLOCK_SIZE;
}
@@ -423,20 +418,19 @@ STATIC mp_obj_t pyb_flash_ioctl(mp_obj_t self_in, mp_obj_t cmd_in, mp_obj_t arg_
case MP_BLOCKDEV_IOCTL_BLOCK_SIZE: {
mp_int_t n = FLASH_BLOCK_SIZE;
- #if defined(SPIFLASH)
if (self->use_native_block_size) {
- n = PYB_FLASH_NATIVE_BLOCK_SIZE;
+ n = MICROPY_HW_BDEV_BLOCKSIZE_EXT;
}
- #endif
return MP_OBJ_NEW_SMALL_INT(n);
}
case MP_BLOCKDEV_IOCTL_BLOCK_ERASE: {
int ret = 0;
- #if defined(SPIFLASH)
+ #if defined(MICROPY_HW_BDEV_ERASEBLOCKS_EXT)
if (self->use_native_block_size) {
- mp_int_t block_num = self->start / PYB_FLASH_NATIVE_BLOCK_SIZE + mp_obj_get_int(arg_in);
- ret = spi_bdev_ioctl(SPIFLASH, BDEV_IOCTL_BLOCK_ERASE, block_num);
+ mp_int_t block_num = self->start / MICROPY_HW_BDEV_BLOCKSIZE_EXT + mp_obj_get_int(arg_in);
+
+ ret = MICROPY_HW_BDEV_ERASEBLOCKS_EXT(block_num, MICROPY_HW_BDEV_BLOCKSIZE_EXT);
}
#endif
return MP_OBJ_NEW_SMALL_INT(ret);
diff --git a/ports/stm32/storage.h b/ports/stm32/storage.h
index 73058aad6..05654855a 100644
--- a/ports/stm32/storage.h
+++ b/ports/stm32/storage.h
@@ -35,8 +35,7 @@
enum {
BDEV_IOCTL_INIT = 1,
BDEV_IOCTL_SYNC = 3,
- BDEV_IOCTL_NUM_BLOCKS = 4,
- BDEV_IOCTL_BLOCK_ERASE = 6,
+ BDEV_IOCTL_NUM_BLOCKS = 4, // units are FLASH_BLOCK_SIZE
BDEV_IOCTL_IRQ_HANDLER = 7,
};
@@ -70,6 +69,7 @@ int spi_bdev_writeblocks(spi_bdev_t *bdev, const uint8_t *src, uint32_t block_nu
// These raw functions bypass the cache and go directly to SPI flash
int spi_bdev_readblocks_raw(spi_bdev_t *bdev, uint8_t *dest, uint32_t block_num, uint32_t block_offset, uint32_t num_bytes);
int spi_bdev_writeblocks_raw(spi_bdev_t *bdev, const uint8_t *src, uint32_t block_num, uint32_t block_offset, uint32_t num_bytes);
+int spi_bdev_eraseblocks_raw(spi_bdev_t *bdev, uint32_t block_num, uint32_t num_bytes);
extern const struct _mp_obj_type_t pyb_flash_type;
extern const struct _pyb_flash_obj_t pyb_flash_obj;
diff --git a/ports/stm32/systick.c b/ports/stm32/systick.c
index d70fc0053..7d1e318ac 100644
--- a/ports/stm32/systick.c
+++ b/ports/stm32/systick.c
@@ -96,12 +96,12 @@ void mp_hal_delay_ms(mp_uint_t Delay) {
// IRQs enabled, so can use systick counter to do the delay
uint32_t start = uwTick;
// Wraparound of tick is taken care of by 2's complement arithmetic.
- while (uwTick - start < Delay) {
+ do {
// This macro will execute the necessary idle behaviour. It may
// raise an exception, switch threads or enter sleep mode (waiting for
// (at least) the SysTick interrupt).
MICROPY_EVENT_POLL_HOOK
- }
+ } while (uwTick - start < Delay);
} else {
// IRQs disabled, so need to use a busy loop for the delay.
// To prevent possible overflow of the counter we use a double loop.
diff --git a/ports/stm32/uart.c b/ports/stm32/uart.c
index 9f7441617..d2953b264 100644
--- a/ports/stm32/uart.c
+++ b/ports/stm32/uart.c
@@ -32,8 +32,8 @@
#include "py/stream.h"
#include "py/mperrno.h"
#include "py/mphal.h"
-#include "lib/utils/interrupt_char.h"
-#include "lib/utils/mpirq.h"
+#include "shared/runtime/interrupt_char.h"
+#include "shared/runtime/mpirq.h"
#include "uart.h"
#include "irq.h"
#include "pendsv.h"
@@ -488,7 +488,7 @@ bool uart_init(pyb_uart_obj_t *uart_obj,
uart_obj->uartx = UARTx;
- // init UARTx
+ // Set the initialisation parameters for the UART.
UART_HandleTypeDef huart;
memset(&huart, 0, sizeof(huart));
huart.Instance = UARTx;
@@ -499,6 +499,26 @@ bool uart_init(pyb_uart_obj_t *uart_obj,
huart.Init.Mode = UART_MODE_TX_RX;
huart.Init.HwFlowCtl = flow;
huart.Init.OverSampling = UART_OVERSAMPLING_16;
+ #if !defined(STM32F4)
+ huart.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
+ #endif
+
+ #if defined(STM32H7) || defined(STM32WB)
+ // Compute the smallest prescaler that will allow the given baudrate.
+ uint32_t presc = UART_PRESCALER_DIV1;
+ if (uart_obj->uart_id == PYB_LPUART_1) {
+ uint32_t source_clk = uart_get_source_freq(uart_obj);
+ for (; presc < UART_PRESCALER_DIV256; ++presc) {
+ uint32_t brr = UART_DIV_LPUART(source_clk, baudrate, presc);
+ if (brr <= LPUART_BRR_MASK) {
+ break;
+ }
+ }
+ }
+ huart.Init.ClockPrescaler = presc;
+ #endif
+
+ // Initialise the UART hardware.
HAL_UART_Init(&huart);
// Disable all individual UART IRQs, but enable the global handler
@@ -746,6 +766,15 @@ uint32_t uart_get_source_freq(pyb_uart_obj_t *self) {
}
uint32_t uart_get_baudrate(pyb_uart_obj_t *self) {
+ #if defined(LPUART1)
+ if (self->uart_id == PYB_LPUART_1) {
+ return LL_LPUART_GetBaudRate(self->uartx, uart_get_source_freq(self)
+ #if defined(STM32H7) || defined(STM32WB)
+ , self->uartx->PRESC
+ #endif
+ );
+ }
+ #endif
return LL_USART_GetBaudRate(self->uartx, uart_get_source_freq(self),
#if defined(STM32H7) || defined(STM32WB)
self->uartx->PRESC,
@@ -754,6 +783,16 @@ uint32_t uart_get_baudrate(pyb_uart_obj_t *self) {
}
void uart_set_baudrate(pyb_uart_obj_t *self, uint32_t baudrate) {
+ #if defined(LPUART1)
+ if (self->uart_id == PYB_LPUART_1) {
+ LL_LPUART_SetBaudRate(self->uartx, uart_get_source_freq(self),
+ #if defined(STM32H7) || defined(STM32WB)
+ LL_LPUART_PRESCALER_DIV1,
+ #endif
+ baudrate);
+ return;
+ }
+ #endif
LL_USART_SetBaudRate(self->uartx, uart_get_source_freq(self),
#if defined(STM32H7) || defined(STM32WB)
LL_USART_PRESCALER_DIV1,
diff --git a/ports/stm32/uart.h b/ports/stm32/uart.h
index 0490a617f..0a268ad46 100644
--- a/ports/stm32/uart.h
+++ b/ports/stm32/uart.h
@@ -26,7 +26,7 @@
#ifndef MICROPY_INCLUDED_STM32_UART_H
#define MICROPY_INCLUDED_STM32_UART_H
-#include "lib/utils/mpirq.h"
+#include "shared/runtime/mpirq.h"
typedef enum {
PYB_UART_NONE = 0,
@@ -88,6 +88,7 @@ void uart_deinit(pyb_uart_obj_t *uart_obj);
void uart_irq_handler(mp_uint_t uart_id);
void uart_attach_to_repl(pyb_uart_obj_t *self, bool attached);
+uint32_t uart_get_source_freq(pyb_uart_obj_t *self);
uint32_t uart_get_baudrate(pyb_uart_obj_t *self);
void uart_set_baudrate(pyb_uart_obj_t *self, uint32_t baudrate);
diff --git a/ports/stm32/usb.c b/ports/stm32/usb.c
index 5e3802651..1ed45592e 100644
--- a/ports/stm32/usb.c
+++ b/ports/stm32/usb.c
@@ -39,7 +39,7 @@
#include "py/stream.h"
#include "py/mperrno.h"
#include "py/mphal.h"
-#include "lib/utils/mpirq.h"
+#include "shared/runtime/mpirq.h"
#include "bufhelper.h"
#include "storage.h"
#include "sdcard.h"
@@ -412,7 +412,7 @@ STATIC mp_obj_t pyb_usb_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t *
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_mode, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
{ MP_QSTR_port, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
- { MP_QSTR_vid, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = USBD_VID} },
+ { MP_QSTR_vid, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = MICROPY_HW_USB_VID} },
{ MP_QSTR_pid, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
#if MICROPY_HW_USB_MSC
{ MP_QSTR_msc, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_empty_tuple_obj)} },
@@ -489,61 +489,61 @@ STATIC mp_obj_t pyb_usb_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t *
uint8_t mode;
if (strcmp(mode_str, "CDC+MSC") == 0 || strcmp(mode_str, "VCP+MSC") == 0) {
if (pid == -1) {
- pid = USBD_PID_CDC_MSC;
+ pid = MICROPY_HW_USB_PID_CDC_MSC;
}
mode = USBD_MODE_CDC_MSC;
} else if (strcmp(mode_str, "VCP+MSC+HID") == 0) {
if (pid == -1) {
- pid = USBD_PID_CDC_MSC_HID;
+ pid = MICROPY_HW_USB_PID_CDC_MSC_HID;
}
mode = USBD_MODE_CDC_MSC_HID;
#if MICROPY_HW_USB_CDC_NUM >= 2
} else if (strcmp(mode_str, "VCP+VCP") == 0) {
if (pid == -1) {
- pid = USBD_PID_CDC2;
+ pid = MICROPY_HW_USB_PID_CDC2;
}
mode = USBD_MODE_CDC2;
} else if (strcmp(mode_str, "VCP+VCP+MSC") == 0) {
if (pid == -1) {
- pid = USBD_PID_CDC2_MSC;
+ pid = MICROPY_HW_USB_PID_CDC2_MSC;
}
mode = USBD_MODE_CDC2_MSC;
} else if (strcmp(mode_str, "2xVCP+MSC+HID") == 0) {
if (pid == -1) {
- pid = USBD_PID_CDC2_MSC_HID;
+ pid = MICROPY_HW_USB_PID_CDC2_MSC_HID;
}
mode = USBD_MODE_CDC2_MSC_HID;
#endif
#if MICROPY_HW_USB_CDC_NUM >= 3
} else if (strcmp(mode_str, "3xVCP") == 0) {
if (pid == -1) {
- pid = USBD_PID_CDC3;
+ pid = MICROPY_HW_USB_PID_CDC3;
}
mode = USBD_MODE_CDC3;
} else if (strcmp(mode_str, "3xVCP+MSC") == 0) {
if (pid == -1) {
- pid = USBD_PID_CDC3_MSC;
+ pid = MICROPY_HW_USB_PID_CDC3_MSC;
}
mode = USBD_MODE_CDC3_MSC;
} else if (strcmp(mode_str, "3xVCP+MSC+HID") == 0) {
if (pid == -1) {
- pid = USBD_PID_CDC3_MSC_HID;
+ pid = MICROPY_HW_USB_PID_CDC3_MSC_HID;
}
mode = USBD_MODE_CDC3_MSC_HID;
#endif
} else if (strcmp(mode_str, "CDC+HID") == 0 || strcmp(mode_str, "VCP+HID") == 0) {
if (pid == -1) {
- pid = USBD_PID_CDC_HID;
+ pid = MICROPY_HW_USB_PID_CDC_HID;
}
mode = USBD_MODE_CDC_HID;
} else if (strcmp(mode_str, "CDC") == 0 || strcmp(mode_str, "VCP") == 0) {
if (pid == -1) {
- pid = USBD_PID_CDC;
+ pid = MICROPY_HW_USB_PID_CDC;
}
mode = USBD_MODE_CDC;
} else if (strcmp(mode_str, "MSC") == 0) {
if (pid == -1) {
- pid = USBD_PID_MSC;
+ pid = MICROPY_HW_USB_PID_MSC;
}
mode = USBD_MODE_MSC;
} else {
diff --git a/ports/stm32/usb.h b/ports/stm32/usb.h
index 295038ebd..3c382887a 100644
--- a/ports/stm32/usb.h
+++ b/ports/stm32/usb.h
@@ -30,22 +30,6 @@
#define PYB_USB_FLAG_USB_MODE_CALLED (0x0002)
-#ifndef USBD_VID
-// Windows needs a different PID to distinguish different device configurations
-#define USBD_VID (0xf055)
-#define USBD_PID_CDC_MSC (0x9800)
-#define USBD_PID_CDC_HID (0x9801)
-#define USBD_PID_CDC (0x9802)
-#define USBD_PID_MSC (0x9803)
-#define USBD_PID_CDC2_MSC (0x9804)
-#define USBD_PID_CDC2 (0x9805)
-#define USBD_PID_CDC3 (0x9806)
-#define USBD_PID_CDC3_MSC (0x9807)
-#define USBD_PID_CDC_MSC_HID (0x9808)
-#define USBD_PID_CDC2_MSC_HID (0x9809)
-#define USBD_PID_CDC3_MSC_HID (0x980a)
-#endif
-
typedef enum {
PYB_USB_STORAGE_MEDIUM_NONE = 0,
PYB_USB_STORAGE_MEDIUM_FLASH,
diff --git a/ports/stm32/usbd_cdc_interface.c b/ports/stm32/usbd_cdc_interface.c
index a1ac5fd22..61a7c8248 100644
--- a/ports/stm32/usbd_cdc_interface.c
+++ b/ports/stm32/usbd_cdc_interface.c
@@ -42,7 +42,7 @@
#include "pendsv.h"
#include "py/obj.h"
-#include "lib/utils/interrupt_char.h"
+#include "shared/runtime/interrupt_char.h"
#include "irq.h"
#if MICROPY_HW_ENABLE_USB
@@ -172,7 +172,7 @@ int8_t usbd_cdc_control(usbd_cdc_state_t *cdc_in, uint8_t cmd, uint8_t *pbuf, ui
}
static inline uint16_t usbd_cdc_tx_buffer_mask(uint16_t val) {
- return val & (USBD_CDC_TX_DATA_SIZE - 1);
+ return val & (MICROPY_HW_USB_CDC_TX_DATA_SIZE - 1);
}
static inline uint16_t usbd_cdc_tx_buffer_size(usbd_cdc_itf_t *cdc) {
@@ -188,18 +188,18 @@ static inline bool usbd_cdc_tx_buffer_will_be_empty(usbd_cdc_itf_t *cdc) {
}
static inline bool usbd_cdc_tx_buffer_full(usbd_cdc_itf_t *cdc) {
- return usbd_cdc_tx_buffer_size(cdc) == USBD_CDC_TX_DATA_SIZE;
+ return usbd_cdc_tx_buffer_size(cdc) == MICROPY_HW_USB_CDC_TX_DATA_SIZE;
}
static uint16_t usbd_cdc_tx_send_length(usbd_cdc_itf_t *cdc) {
- uint16_t to_end = USBD_CDC_TX_DATA_SIZE - usbd_cdc_tx_buffer_mask(cdc->tx_buf_ptr_out);
+ uint16_t to_end = MICROPY_HW_USB_CDC_TX_DATA_SIZE - usbd_cdc_tx_buffer_mask(cdc->tx_buf_ptr_out);
return MIN(usbd_cdc_tx_buffer_size(cdc), to_end);
}
static void usbd_cdc_tx_buffer_put(usbd_cdc_itf_t *cdc, uint8_t data, bool check_overflow) {
cdc->tx_buf[usbd_cdc_tx_buffer_mask(cdc->tx_buf_ptr_in)] = data;
cdc->tx_buf_ptr_in++;
- if (check_overflow && usbd_cdc_tx_buffer_size(cdc) > USBD_CDC_TX_DATA_SIZE) {
+ if (check_overflow && usbd_cdc_tx_buffer_size(cdc) > MICROPY_HW_USB_CDC_TX_DATA_SIZE) {
cdc->tx_buf_ptr_out++;
cdc->tx_buf_ptr_out_next = cdc->tx_buf_ptr_out;
}
@@ -270,7 +270,7 @@ void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd) {
bool usbd_cdc_rx_buffer_full(usbd_cdc_itf_t *cdc) {
int get = cdc->rx_buf_get, put = cdc->rx_buf_put;
- int remaining = (get - put) + (-((int)(get <= put)) & USBD_CDC_RX_DATA_SIZE);
+ int remaining = (get - put) + (-((int)(get <= put)) & MICROPY_HW_USB_CDC_RX_DATA_SIZE);
return remaining < CDC_DATA_MAX_PACKET_SIZE + 1;
}
@@ -298,7 +298,7 @@ int8_t usbd_cdc_receive(usbd_cdc_state_t *cdc_in, size_t len) {
if (cdc->attached_to_repl && *src == mp_interrupt_char) {
pendsv_kbd_intr();
} else {
- uint16_t next_put = (cdc->rx_buf_put + 1) & (USBD_CDC_RX_DATA_SIZE - 1);
+ uint16_t next_put = (cdc->rx_buf_put + 1) & (MICROPY_HW_USB_CDC_RX_DATA_SIZE - 1);
if (next_put == cdc->rx_buf_get) {
// overflow, we just discard the rest of the chars
break;
@@ -322,7 +322,7 @@ int8_t usbd_cdc_receive(usbd_cdc_state_t *cdc_in, size_t len) {
int usbd_cdc_tx_half_empty(usbd_cdc_itf_t *cdc) {
int32_t tx_waiting = usbd_cdc_tx_buffer_size(cdc);
- return tx_waiting <= USBD_CDC_TX_DATA_SIZE / 2;
+ return tx_waiting <= MICROPY_HW_USB_CDC_TX_DATA_SIZE / 2;
}
// Writes only the data that fits if flow & CTS, else writes all data
@@ -405,7 +405,7 @@ void usbd_cdc_tx_always(usbd_cdc_itf_t *cdc, const uint8_t *buf, uint32_t len) {
int usbd_cdc_rx_num(usbd_cdc_itf_t *cdc) {
int32_t rx_waiting = (int32_t)cdc->rx_buf_put - (int32_t)cdc->rx_buf_get;
if (rx_waiting < 0) {
- rx_waiting += USBD_CDC_RX_DATA_SIZE;
+ rx_waiting += MICROPY_HW_USB_CDC_RX_DATA_SIZE;
}
usbd_cdc_rx_check_resume(cdc);
return rx_waiting;
@@ -434,7 +434,7 @@ int usbd_cdc_rx(usbd_cdc_itf_t *cdc, uint8_t *buf, uint32_t len, uint32_t timeou
// Copy byte from device to user buffer
buf[i] = cdc->rx_user_buf[cdc->rx_buf_get];
- cdc->rx_buf_get = (cdc->rx_buf_get + 1) & (USBD_CDC_RX_DATA_SIZE - 1);
+ cdc->rx_buf_get = (cdc->rx_buf_get + 1) & (MICROPY_HW_USB_CDC_RX_DATA_SIZE - 1);
}
usbd_cdc_rx_check_resume(cdc);
diff --git a/ports/stm32/usbd_cdc_interface.h b/ports/stm32/usbd_cdc_interface.h
index 6b510f239..76b5c9e79 100644
--- a/ports/stm32/usbd_cdc_interface.h
+++ b/ports/stm32/usbd_cdc_interface.h
@@ -31,12 +31,7 @@
******************************************************************************
*/
-#ifndef USBD_CDC_RX_DATA_SIZE
-#define USBD_CDC_RX_DATA_SIZE (1024) // this must be 2 or greater, and a power of 2
-#endif
-#ifndef USBD_CDC_TX_DATA_SIZE
-#define USBD_CDC_TX_DATA_SIZE (1024) // This must be a power of 2 and no greater than 16384
-#endif
+#include "py/mpconfig.h"
// Values for connect_state
#define USBD_CDC_CONNECT_STATE_DISCONNECTED (0)
@@ -52,14 +47,14 @@ typedef struct _usbd_cdc_itf_t {
usbd_cdc_state_t base; // state for the base CDC layer
uint8_t rx_packet_buf[CDC_DATA_MAX_PACKET_SIZE]; // received data from USB OUT endpoint is stored in this buffer
- uint8_t rx_user_buf[USBD_CDC_RX_DATA_SIZE]; // received data is buffered here until the user reads it
+ uint8_t rx_user_buf[MICROPY_HW_USB_CDC_RX_DATA_SIZE]; // received data is buffered here until the user reads it
volatile uint16_t rx_buf_put; // circular buffer index
uint16_t rx_buf_get; // circular buffer index
uint8_t rx_buf_full; // rx from host will be blocked while this is true
- uint8_t tx_buf[USBD_CDC_TX_DATA_SIZE]; // data for USB IN endpoind is stored in this buffer
- uint16_t tx_buf_ptr_in; // increment this pointer modulo USBD_CDC_TX_DATA_SIZE when new data is available
- volatile uint16_t tx_buf_ptr_out; // increment this pointer modulo USBD_CDC_TX_DATA_SIZE when data is drained
+ uint8_t tx_buf[MICROPY_HW_USB_CDC_TX_DATA_SIZE]; // data for USB IN endpoind is stored in this buffer
+ uint16_t tx_buf_ptr_in; // increment this pointer modulo MICROPY_HW_USB_CDC_TX_DATA_SIZE when new data is available
+ volatile uint16_t tx_buf_ptr_out; // increment this pointer modulo MICROPY_HW_USB_CDC_TX_DATA_SIZE when data is drained
uint16_t tx_buf_ptr_out_next; // next position of above once transmission finished
uint8_t tx_need_empty_packet; // used to flush the USB IN endpoint if the last packet was exactly the endpoint packet size
diff --git a/ports/stm32/usbd_desc.c b/ports/stm32/usbd_desc.c
index aa6837163..fd50029fc 100644
--- a/ports/stm32/usbd_desc.c
+++ b/ports/stm32/usbd_desc.c
@@ -36,46 +36,14 @@
// need this header just for MP_HAL_UNIQUE_ID_ADDRESS
#include "py/mphal.h"
-// need this header for any overrides to the below constants
+// Need this header for MICROPY_HW_USB_xxx configuration values.
#include "py/mpconfig.h"
-#ifndef USBD_LANGID_STRING
-#define USBD_LANGID_STRING 0x409
-#endif
-
-#ifndef USBD_MANUFACTURER_STRING
-#define USBD_MANUFACTURER_STRING "MicroPython"
-#endif
-
-#ifndef USBD_PRODUCT_HS_STRING
-#define USBD_PRODUCT_HS_STRING "Pyboard Virtual Comm Port in HS Mode"
-#endif
-
-#ifndef USBD_PRODUCT_FS_STRING
-#define USBD_PRODUCT_FS_STRING "Pyboard Virtual Comm Port in FS Mode"
-#endif
-
-#ifndef USBD_CONFIGURATION_HS_STRING
-#define USBD_CONFIGURATION_HS_STRING "Pyboard Config"
-#endif
-
-#ifndef USBD_INTERFACE_HS_STRING
-#define USBD_INTERFACE_HS_STRING "Pyboard Interface"
-#endif
-
-#ifndef USBD_CONFIGURATION_FS_STRING
-#define USBD_CONFIGURATION_FS_STRING "Pyboard Config"
-#endif
-
-#ifndef USBD_INTERFACE_FS_STRING
-#define USBD_INTERFACE_FS_STRING "Pyboard Interface"
-#endif
-
__ALIGN_BEGIN static const uint8_t USBD_LangIDDesc[USB_LEN_LANGID_STR_DESC] __ALIGN_END = {
USB_LEN_LANGID_STR_DESC,
USB_DESC_TYPE_STRING,
- LOBYTE(USBD_LANGID_STRING),
- HIBYTE(USBD_LANGID_STRING),
+ LOBYTE(MICROPY_HW_USB_LANGID_STRING),
+ HIBYTE(MICROPY_HW_USB_LANGID_STRING),
};
// set the VID, PID and device release number
@@ -140,14 +108,14 @@ STATIC uint8_t *USBD_StrDescriptor(USBD_HandleTypeDef *pdev, uint8_t idx, uint16
return (uint8_t *)USBD_LangIDDesc; // the data should only be read from this buf
case USBD_IDX_MFC_STR:
- str = USBD_MANUFACTURER_STRING;
+ str = MICROPY_HW_USB_MANUFACTURER_STRING;
break;
case USBD_IDX_PRODUCT_STR:
if (pdev->dev_speed == USBD_SPEED_HIGH) {
- str = USBD_PRODUCT_HS_STRING;
+ str = MICROPY_HW_USB_PRODUCT_HS_STRING;
} else {
- str = USBD_PRODUCT_FS_STRING;
+ str = MICROPY_HW_USB_PRODUCT_FS_STRING;
}
break;
@@ -174,17 +142,17 @@ STATIC uint8_t *USBD_StrDescriptor(USBD_HandleTypeDef *pdev, uint8_t idx, uint16
case USBD_IDX_CONFIG_STR:
if (pdev->dev_speed == USBD_SPEED_HIGH) {
- str = USBD_CONFIGURATION_HS_STRING;
+ str = MICROPY_HW_USB_CONFIGURATION_HS_STRING;
} else {
- str = USBD_CONFIGURATION_FS_STRING;
+ str = MICROPY_HW_USB_CONFIGURATION_FS_STRING;
}
break;
case USBD_IDX_INTERFACE_STR:
if (pdev->dev_speed == USBD_SPEED_HIGH) {
- str = USBD_INTERFACE_HS_STRING;
+ str = MICROPY_HW_USB_INTERFACE_HS_STRING;
} else {
- str = USBD_INTERFACE_FS_STRING;
+ str = MICROPY_HW_USB_INTERFACE_FS_STRING;
}
break;
diff --git a/ports/teensy/Makefile b/ports/teensy/Makefile
index cf9529442..d1ff42162 100644
--- a/ports/teensy/Makefile
+++ b/ports/teensy/Makefile
@@ -100,12 +100,12 @@ STM_SRC_C = $(addprefix ports/stm32/,\
pin_named_pins.c \
)
-LIB_SRC_C = $(addprefix lib/,\
+SHARED_SRC_C = $(addprefix shared/,\
libc/string0.c \
- mp-readline/readline.c \
- utils/gchelper_native.c \
- utils/pyexec.c \
- utils/sys_stdio_mphal.c \
+ readline/readline.c \
+ runtime/gchelper_native.c \
+ runtime/pyexec.c \
+ runtime/sys_stdio_mphal.c \
)
SRC_TEENSY = $(addprefix core/,\
@@ -120,8 +120,8 @@ SRC_TEENSY = $(addprefix core/,\
)
OBJ = $(PY_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o) $(STM_SRC_C:.c=.o) $(SRC_TEENSY:.c=.o))
-OBJ += $(addprefix $(BUILD)/, $(LIB_SRC_C:.c=.o))
-OBJ += $(BUILD)/lib/utils/gchelper_m3.o
+OBJ += $(addprefix $(BUILD)/, $(SHARED_SRC_C:.c=.o))
+OBJ += $(BUILD)/shared/runtime/gchelper_m3.o
OBJ += $(BUILD)/pins_gen.o
all: hex
@@ -129,13 +129,13 @@ hex: $(BUILD)/micropython.hex
ifeq ($(USE_MEMZIP),1)
SRC_C += \
- lib/memzip/import.c \
- lib/memzip/lexermemzip.c \
- lib/memzip/memzip.c \
+ shared/memzip/import.c \
+ shared/memzip/lexermemzip.c \
+ shared/memzip/memzip.c \
OBJ += $(BUILD)/memzip-files.o
-MAKE_MEMZIP = $(TOP)/lib/memzip/make-memzip.py
+MAKE_MEMZIP = $(TOP)/shared/memzip/make-memzip.py
ifeq ($(MEMZIP_DIR),)
MEMZIP_DIR = memzip_files
endif
@@ -207,7 +207,7 @@ GEN_PINS_AF_CONST = $(HEADER_BUILD)/pins_af_const.h
GEN_PINS_AF_PY = $(BUILD)/pins_af.py
# List of sources for qstr extraction
-SRC_QSTR += $(SRC_C) $(STM_SRC_C) $(LIB_SRC_C)
+SRC_QSTR += $(SRC_C) $(STM_SRC_C) $(SHARED_SRC_C)
# Append any auto-generated sources that are needed by sources listed in
# SRC_QSTR
SRC_QSTR_AUTO_DEPS +=
diff --git a/ports/teensy/main.c b/ports/teensy/main.c
index d4c5f0396..6ebdcde21 100644
--- a/ports/teensy/main.c
+++ b/ports/teensy/main.c
@@ -9,9 +9,9 @@
#include "py/gc.h"
#include "py/mphal.h"
#include "gccollect.h"
-#include "lib/utils/gchelper.h"
-#include "lib/utils/pyexec.h"
-#include "lib/mp-readline/readline.h"
+#include "shared/readline/readline.h"
+#include "shared/runtime/gchelper.h"
+#include "shared/runtime/pyexec.h"
#include "lexermemzip.h"
#include "Arduino.h"
diff --git a/ports/teensy/modpyb.c b/ports/teensy/modpyb.c
index 6671b3abd..f5bb3ea7b 100644
--- a/ports/teensy/modpyb.c
+++ b/ports/teensy/modpyb.c
@@ -33,7 +33,7 @@
#include "py/gc.h"
#include "py/mphal.h"
-#include "lib/utils/pyexec.h"
+#include "shared/runtime/pyexec.h"
#include "gccollect.h"
#include "systick.h"
diff --git a/ports/unix/Makefile b/ports/unix/Makefile
index fbd439227..efcc437e4 100644
--- a/ports/unix/Makefile
+++ b/ports/unix/Makefile
@@ -118,9 +118,9 @@ endif
endif
ifeq ($(MICROPY_USE_READLINE),1)
-INC += -I$(TOP)/lib/mp-readline
+INC += -I$(TOP)/shared/readline
CFLAGS_MOD += -DMICROPY_USE_READLINE=1
-LIB_SRC_C_EXTRA += mp-readline/readline.c
+SHARED_SRC_C_EXTRA += readline/readline.c
endif
ifeq ($(MICROPY_PY_TERMIOS),1)
CFLAGS_MOD += -DMICROPY_PY_TERMIOS=1
@@ -247,8 +247,12 @@ LIB_SRC_C += $(addprefix lib/,\
lv_bindings/driver/SDL/SDL_mouse.c \
lv_bindings/driver/SDL/modSDL.c \
$(LIB_SRC_C_EXTRA) \
+ )
+
+SHARED_SRC_C += $(addprefix shared/,\
+ runtime/gchelper_generic.c \
timeutils/timeutils.c \
- utils/gchelper_generic.c \
+ $(SHARED_SRC_C_EXTRA) \
)
ifneq ($(UNAME_S),Darwin)
@@ -263,11 +267,12 @@ SRC_CXX += \
OBJ = $(PY_O)
OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o))
OBJ += $(addprefix $(BUILD)/, $(SRC_CXX:.cpp=.o))
-OBJ += $(addprefix $(BUILD)/, $(LIB_SRC_C:.c=.o))
+OBJ += $(addprefix $(BUILD)/, $(SHARED_SRC_C:.c=.o))
OBJ += $(addprefix $(BUILD)/, $(EXTMOD_SRC_C:.c=.o))
+OBJ += $(addprefix $(BUILD)/, $(LIB_SRC_C:.c=.o))
# List of sources for qstr extraction
-SRC_QSTR += $(SRC_C) $(SRC_CXX) $(LIB_SRC_C) $(EXTMOD_SRC_C)
+SRC_QSTR += $(SRC_C) $(SRC_CXX) $(LIB_SRC_C) $(SHARED_SRC_C) $(EXTMOD_SRC_C)
# Append any auto-generated sources that are needed by sources listed in
# SRC_QSTR
SRC_QSTR_AUTO_DEPS +=
@@ -299,6 +304,17 @@ else
RUN_TESTS_MPY_CROSS_FLAGS = --mpy-cross-flags='-mcache-lookup-bc'
endif
+ifeq ($(CROSS_COMPILE),arm-linux-gnueabi-)
+# Force disable error text compression when compiling for ARM as the compiler
+# cannot optimise out the giant strcmp list generated for MP_MATCH_COMPRESSED.
+# Checked on:
+# arm-linux-gnueabi-gcc (Ubuntu/Linaro 7.5.0-3ubuntu1~18.04) 7.5.0
+# arm-linux-gnueabi-gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0
+# See https://github.com/micropython/micropython/pull/7659 for details.
+$(info Detected arm-linux-gnueabi-gcc. Disabling error message compression.)
+MICROPY_ROM_TEXT_COMPRESSION = 0
+endif
+
include $(TOP)/py/mkrules.mk
.PHONY: test test_full
diff --git a/ports/unix/gccollect.c b/ports/unix/gccollect.c
index f0441e4ea..79b17663c 100644
--- a/ports/unix/gccollect.c
+++ b/ports/unix/gccollect.c
@@ -29,7 +29,7 @@
#include "py/mpstate.h"
#include "py/gc.h"
-#include "lib/utils/gchelper.h"
+#include "shared/runtime/gchelper.h"
#if MICROPY_ENABLE_GC
diff --git a/ports/unix/input.c b/ports/unix/input.c
index 4a77d1b27..c5bf71973 100644
--- a/ports/unix/input.c
+++ b/ports/unix/input.c
@@ -35,7 +35,7 @@
#include "input.h"
#if MICROPY_USE_READLINE == 1
-#include "lib/mp-readline/readline.h"
+#include "shared/readline/readline.h"
#endif
#if MICROPY_USE_READLINE == 0
diff --git a/ports/unix/main.c b/ports/unix/main.c
index a5db0869d..031bdd75d 100644
--- a/ports/unix/main.c
+++ b/ports/unix/main.c
@@ -159,7 +159,7 @@ STATIC int execute_from_lexer(int source_kind, const void *source, mp_parse_inpu
}
#if MICROPY_USE_READLINE == 1
-#include "lib/mp-readline/readline.h"
+#include "shared/readline/readline.h"
#else
STATIC char *strjoin(const char *s1, int sep_char, const char *s2) {
int l1 = strlen(s1);
diff --git a/ports/unix/modjni.c b/ports/unix/modjni.c
index 74e7221de..bd151050e 100644
--- a/ports/unix/modjni.c
+++ b/ports/unix/modjni.c
@@ -102,9 +102,9 @@ STATIC void check_exception(void) {
mp_obj_t py_e = new_jobject(exc);
JJ1(ExceptionClear);
if (JJ(IsInstanceOf, exc, IndexException_class)) {
- nlr_raise(mp_obj_new_exception_arg1(&mp_type_IndexError, py_e));
+ mp_raise_type_arg(&mp_type_IndexError, py_e);
}
- nlr_raise(mp_obj_new_exception_arg1(&mp_type_Exception, py_e));
+ mp_raise_type_arg(&mp_type_Exception, py_e);
}
}
diff --git a/ports/unix/mpconfigport.h b/ports/unix/mpconfigport.h
index 00c6607f5..b8bfbd2b8 100644
--- a/ports/unix/mpconfigport.h
+++ b/ports/unix/mpconfigport.h
@@ -90,6 +90,7 @@
#define MICROPY_PY_FUNCTION_ATTRS (1)
#define MICROPY_PY_DESCRIPTORS (1)
#define MICROPY_PY_DELATTR_SETATTR (1)
+#define MICROPY_PY_FSTRINGS (1)
#define MICROPY_PY_BUILTINS_STR_UNICODE (1)
#define MICROPY_PY_BUILTINS_STR_CENTER (1)
#define MICROPY_PY_BUILTINS_STR_PARTITION (1)
diff --git a/ports/unix/mphalport.h b/ports/unix/mphalport.h
index 89d23ca5d..510f9d939 100644
--- a/ports/unix/mphalport.h
+++ b/ports/unix/mphalport.h
@@ -52,7 +52,7 @@ static inline int mp_hal_readline(vstr_t *vstr, const char *p) {
#elif MICROPY_PY_BUILTINS_INPUT && MICROPY_USE_READLINE == 1
#include "py/misc.h"
-#include "lib/mp-readline/readline.h"
+#include "shared/readline/readline.h"
// For built-in input() we need to wrap the standard readline() to enable raw mode
#define mp_hal_readline mp_hal_readline
static inline int mp_hal_readline(vstr_t *vstr, const char *p) {
diff --git a/ports/unix/mpthreadport.c b/ports/unix/mpthreadport.c
index d3243b337..63aac1da3 100644
--- a/ports/unix/mpthreadport.c
+++ b/ports/unix/mpthreadport.c
@@ -39,7 +39,7 @@
#include
#include
-#include "lib/utils/gchelper.h"
+#include "shared/runtime/gchelper.h"
// Some platforms don't have SIGRTMIN but if we do have it, use it to avoid
// potential conflict with other uses of the more commonly used SIGUSR1.
diff --git a/ports/unix/variants/dev/mpconfigvariant.h b/ports/unix/variants/dev/mpconfigvariant.h
index a12fb7725..6f54abdf9 100644
--- a/ports/unix/variants/dev/mpconfigvariant.h
+++ b/ports/unix/variants/dev/mpconfigvariant.h
@@ -31,6 +31,8 @@
#define MICROPY_VFS (1)
#define MICROPY_VFS_POSIX (1)
+#define MICROPY_PY_BUILTINS_HELP (1)
+#define MICROPY_PY_BUILTINS_HELP_MODULES (1)
#define MICROPY_PY_SYS_SETTRACE (0)
#define MICROPY_PY_UOS_VFS (1)
#define MICROPY_PY_URANDOM_EXTRA_FUNCS (1)
diff --git a/ports/unix/variants/standard/mpconfigvariant.h b/ports/unix/variants/standard/mpconfigvariant.h
index 79b8fe2a3..3cdcfa8e9 100644
--- a/ports/unix/variants/standard/mpconfigvariant.h
+++ b/ports/unix/variants/standard/mpconfigvariant.h
@@ -24,3 +24,5 @@
* THE SOFTWARE.
*/
+#define MICROPY_PY_BUILTINS_HELP (1)
+#define MICROPY_PY_BUILTINS_HELP_MODULES (1)
diff --git a/ports/windows/.appveyor.yml b/ports/windows/.appveyor.yml
index 1ec72bbb3..40fdff293 100644
--- a/ports/windows/.appveyor.yml
+++ b/ports/windows/.appveyor.yml
@@ -1,10 +1,10 @@
-image: Visual Studio 2013
+image: Visual Studio 2017
clone_depth: 1
skip_tags: true
environment:
# Python version used
- MICROPY_CPYTHON3: c:/python34/python.exe
+ MICROPY_CPYTHON3: c:/python38/python.exe
init:
# Set build version number to commit to be travis-like
@@ -63,10 +63,7 @@ after_test:
throw "$env:MSYSTEM build exited with code $LASTEXITCODE"
}
cd (Join-Path $env:APPVEYOR_BUILD_FOLDER 'mpy-cross')
- # Building of mpy-cross hasn't been fixed across all possible windows/WSL/...
- # variations and the STRIP step tries to strip mpy-cross whereas that should be
- # mpy-cross.exe. Workaround for now by skipping actual strip and size commands.
- C:\msys64\usr\bin\bash.exe -l -c "make -B -j4 V=1 STRIP=echo SIZE=echo"
+ C:\msys64\usr\bin\bash.exe -l -c "make -B -j4 V=1"
if ($LASTEXITCODE -ne 0) {
throw "$env:MSYSTEM mpy_cross build exited with code $LASTEXITCODE"
}
diff --git a/ports/windows/Makefile b/ports/windows/Makefile
index 5ee4bdc8a..c5b5e879e 100644
--- a/ports/windows/Makefile
+++ b/ports/windows/Makefile
@@ -2,7 +2,7 @@ include ../../py/mkenv.mk
-include mpconfigport.mk
# define main target
-PROG = micropython.exe
+PROG = micropython
# qstr definitions (must come before including py.mk)
QSTR_DEFS = ../unix/qstrdefsport.h
@@ -28,8 +28,8 @@ endif
# source files
SRC_C = \
- lib/utils/gchelper_generic.c \
- lib/utils/printf.c \
+ shared/libc/printf.c \
+ shared/runtime/gchelper_generic.c \
ports/unix/main.c \
ports/unix/input.c \
ports/unix/modos.c \
@@ -55,7 +55,7 @@ OBJ += $(addprefix $(BUILD)/, $(LIB_SRC_C:.c=.o))
ifeq ($(MICROPY_USE_READLINE),1)
CFLAGS_MOD += -DMICROPY_USE_READLINE=1
-SRC_C += lib/mp-readline/readline.c
+SRC_C += shared/readline/readline.c
endif
LIB += -lws2_32 -lSDL2
diff --git a/ports/windows/micropython.vcxproj b/ports/windows/micropython.vcxproj
index 73a837a84..1beca9e50 100644
--- a/ports/windows/micropython.vcxproj
+++ b/ports/windows/micropython.vcxproj
@@ -85,8 +85,8 @@
-
-
+
+
@@ -109,4 +109,4 @@
-
\ No newline at end of file
+
diff --git a/ports/windows/mpconfigport.h b/ports/windows/mpconfigport.h
index 0107116c3..a8340e9a2 100644
--- a/ports/windows/mpconfigport.h
+++ b/ports/windows/mpconfigport.h
@@ -67,6 +67,7 @@
#define MICROPY_PY_FUNCTION_ATTRS (1)
#define MICROPY_PY_DESCRIPTORS (1)
#define MICROPY_PY_DELATTR_SETATTR (1)
+#define MICROPY_PY_FSTRINGS (1)
#define MICROPY_PY_BUILTINS_STR_UNICODE (1)
#define MICROPY_PY_BUILTINS_STR_CENTER (1)
#define MICROPY_PY_BUILTINS_STR_PARTITION (1)
diff --git a/ports/zephyr/CMakeLists.txt b/ports/zephyr/CMakeLists.txt
index 80adea5d8..ca18f2cb9 100644
--- a/ports/zephyr/CMakeLists.txt
+++ b/ports/zephyr/CMakeLists.txt
@@ -38,6 +38,7 @@ set(MICROPY_SOURCE_PORT
main.c
help.c
machine_i2c.c
+ machine_spi.c
machine_pin.c
machine_uart.c
modbluetooth_zephyr.c
@@ -53,14 +54,18 @@ set(MICROPY_SOURCE_PORT
)
list(TRANSFORM MICROPY_SOURCE_PORT PREPEND ${MICROPY_PORT_DIR}/)
-set(MICROPY_SOURCE_LIB
+set(MICROPY_SOURCE_SHARED
+ libc/printf.c
+ readline/readline.c
+ runtime/interrupt_char.c
+ runtime/mpirq.c
+ runtime/pyexec.c
+ runtime/stdout_helpers.c
timeutils/timeutils.c
- utils/mpirq.c
- utils/stdout_helpers.c
- utils/printf.c
- utils/pyexec.c
- utils/interrupt_char.c
- mp-readline/readline.c
+)
+list(TRANSFORM MICROPY_SOURCE_SHARED PREPEND ${MICROPY_DIR}/shared/)
+
+set(MICROPY_SOURCE_LIB
oofatfs/ff.c
oofatfs/ffunicode.c
littlefs/lfs1.c
@@ -73,6 +78,7 @@ list(TRANSFORM MICROPY_SOURCE_LIB PREPEND ${MICROPY_DIR}/lib/)
set(MICROPY_SOURCE_QSTR
${MICROPY_SOURCE_PY}
${MICROPY_SOURCE_EXTMOD}
+ ${MICROPY_SOURCE_SHARED}
${MICROPY_SOURCE_LIB}
${MICROPY_SOURCE_PORT}
)
diff --git a/ports/zephyr/README.md b/ports/zephyr/README.md
index 9d6c223b4..e0b02af22 100644
--- a/ports/zephyr/README.md
+++ b/ports/zephyr/README.md
@@ -15,6 +15,7 @@ Features supported at this time:
* `utime` module for time measurements and delays.
* `machine.Pin` class for GPIO control, with IRQ support.
* `machine.I2C` class for I2C control.
+* `machine.SPI` class for SPI control.
* `usocket` module for networking (IPv4/IPv6).
* "Frozen modules" support to allow to bundle Python modules together
with firmware. Including complete applications, including with
@@ -135,6 +136,14 @@ Example of using I2C to scan for I2C slaves:
i2c = I2C("I2C_0")
i2c.scan()
+Example of using SPI to write a buffer to the MOSI pin:
+
+ from machine import SPI
+
+ spi = SPI("SPI_0")
+ spi.init(baudrate=500000, polarity=1, phase=1, bits=8, firstbit=SPI.MSB)
+ spi.write(b'abcd')
+
Minimal build
-------------
diff --git a/ports/zephyr/boards/frdm_k64f.conf b/ports/zephyr/boards/frdm_k64f.conf
index 483e9a29b..c164c0c32 100644
--- a/ports/zephyr/boards/frdm_k64f.conf
+++ b/ports/zephyr/boards/frdm_k64f.conf
@@ -3,6 +3,7 @@ CONFIG_NET_L2_ETHERNET=y
# Hardware features
CONFIG_I2C=y
+CONFIG_SPI=y
# Sensor drivers
CONFIG_FXOS8700=y
diff --git a/ports/zephyr/boards/mimxrt685_evk_cm33.conf b/ports/zephyr/boards/mimxrt685_evk_cm33.conf
new file mode 100644
index 000000000..827222b88
--- /dev/null
+++ b/ports/zephyr/boards/mimxrt685_evk_cm33.conf
@@ -0,0 +1,2 @@
+# Hardware features
+CONFIG_SPI=y
diff --git a/ports/zephyr/machine_pin.c b/ports/zephyr/machine_pin.c
index 34c822c2f..f9da2433c 100644
--- a/ports/zephyr/machine_pin.c
+++ b/ports/zephyr/machine_pin.c
@@ -35,7 +35,7 @@
#include "py/runtime.h"
#include "py/gc.h"
#include "py/mphal.h"
-#include "lib/utils/mpirq.h"
+#include "shared/runtime/mpirq.h"
#include "modmachine.h"
#if MICROPY_PY_MACHINE
diff --git a/ports/zephyr/machine_spi.c b/ports/zephyr/machine_spi.c
new file mode 100644
index 000000000..2add7ff60
--- /dev/null
+++ b/ports/zephyr/machine_spi.c
@@ -0,0 +1,211 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright 2021 NXP
+ *
+ * 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
+#include
+
+#include "py/runtime.h"
+#include "py/gc.h"
+#include "py/mphal.h"
+#include "py/mperrno.h"
+#include "extmod/machine_spi.h"
+#include "modmachine.h"
+
+#if MICROPY_PY_MACHINE_SPI
+
+#define DEFAULT_SPI_BAUDRATE (50000)
+#define DEFAULT_SPI_POLARITY (0)
+#define DEFAULT_SPI_PHASE (0)
+#define DEFAULT_SPI_BITS (8)
+#define DEFAULT_SPI_FIRSTBIT (SPI_TRANSFER_MSB)
+#define SPI_LOOP (0) // For testing, enable loop mode by setting SPI_LOOP (1)
+
+typedef struct _machine_hard_spi_obj_t {
+ mp_obj_base_t base;
+ const struct device *dev;
+ struct spi_config config;
+} machine_hard_spi_obj_t;
+
+STATIC void machine_hard_spi_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
+ machine_hard_spi_obj_t *self = self_in;
+ mp_printf(print, "SPI(%s, baudrate=%u, polarity=%u, phase=%u, bits=%u, firstbit=%s)",
+ self->dev->name,
+ self->config.frequency,
+ (self->config.operation & 0x2) >> 1,
+ (self->config.operation & 0x4) >> 2,
+ (self->config.operation & ~0x1F) >> 5,
+ ((self->config.operation & 0x10) >> 4) == SPI_TRANSFER_MSB ? "MSB" : "LSB");
+}
+
+mp_obj_t machine_hard_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ enum {ARG_id, ARG_baudrate, ARG_polarity, ARG_phase, ARG_bits, ARG_firstbit, ARG_sck, ARG_mosi, ARG_miso};
+
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_id, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_baudrate, MP_ARG_INT, {.u_int = DEFAULT_SPI_BAUDRATE} },
+ { MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = DEFAULT_SPI_POLARITY} },
+ { MP_QSTR_phase, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = DEFAULT_SPI_PHASE} },
+ { MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = DEFAULT_SPI_BITS} },
+ { MP_QSTR_firstbit, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = DEFAULT_SPI_FIRSTBIT} },
+ { MP_QSTR_sck, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_mosi, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_miso, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ };
+
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ const char *dev_name = mp_obj_str_get_str(args[ARG_id].u_obj);
+ const struct device *dev = device_get_binding(dev_name);
+
+ if (dev == NULL) {
+ mp_raise_ValueError(MP_ERROR_TEXT("device not found"));
+ }
+
+ if ((args[ARG_sck].u_obj != MP_OBJ_NULL) || (args[ARG_miso].u_obj != MP_OBJ_NULL) || (args[ARG_mosi].u_obj != MP_OBJ_NULL)) {
+ mp_raise_NotImplementedError(MP_ERROR_TEXT("explicit choice of sck/miso/mosi is not implemented"));
+ }
+
+ struct spi_config cfg = {
+ .frequency = args[ARG_baudrate].u_int,
+ .operation = (SPI_OP_MODE_MASTER |
+ args[ARG_polarity].u_int << 1 |
+ args[ARG_phase].u_int << 2 |
+ SPI_LOOP << 3 |
+ args[ARG_firstbit].u_int << 4 |
+ args[ARG_bits].u_int << 5 |
+ SPI_LINES_SINGLE),
+ .slave = 0,
+ .cs = NULL
+ };
+
+ machine_hard_spi_obj_t *self = m_new_obj(machine_hard_spi_obj_t);
+
+ self->base.type = &machine_hard_spi_type;
+ self->dev = dev;
+ self->config = cfg;
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+STATIC void machine_hard_spi_init(mp_obj_base_t *obj, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum {ARG_baudrate, ARG_polarity, ARG_phase, ARG_bits, ARG_firstbit};
+
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_baudrate, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
+ { MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
+ { MP_QSTR_phase, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
+ { MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
+ { MP_QSTR_firstbit, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
+ };
+
+ 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);
+
+ machine_hard_spi_obj_t *self = (machine_hard_spi_obj_t *)obj;
+
+ uint32_t baudrate;
+ uint16_t operation = self->config.operation;
+
+ if (args[ARG_baudrate].u_int != -1) {
+ baudrate = args[ARG_baudrate].u_int;
+ } else {
+ baudrate = self->config.frequency;
+ }
+
+ if (args[ARG_polarity].u_int != -1) {
+ operation = (operation & ~0x2) | (args[ARG_polarity].u_int << 1);
+ }
+
+ if (args[ARG_phase].u_int != -1) {
+ operation = (operation & ~0x4) | (args[ARG_phase].u_int << 2);
+ }
+
+ if (args[ARG_bits].u_int != -1) {
+ operation = (operation & 0x1F) | (args[ARG_bits].u_int << 5);
+ }
+
+ if (args[ARG_firstbit].u_int != -1) {
+ operation = (operation & ~0x10) | (args[ARG_firstbit].u_int << 4);
+ }
+
+ struct spi_config cfg = {
+ .frequency = baudrate,
+ .operation = operation,
+ .slave = 0,
+ .cs = NULL
+ };
+
+ self->config = cfg;
+}
+
+STATIC void machine_hard_spi_transfer(mp_obj_base_t *obj, size_t len, const uint8_t *src, uint8_t *dest) {
+ machine_hard_spi_obj_t *self = (machine_hard_spi_obj_t *)obj;
+
+ int ret;
+
+ struct spi_buf tx_bufs[1];
+ tx_bufs[0].buf = (uint8_t *)src;
+ tx_bufs[0].len = len;
+ const struct spi_buf_set tx = {
+ .buffers = tx_bufs,
+ .count = ARRAY_SIZE(tx_bufs)
+ };
+
+ struct spi_buf rx_bufs[1];
+ rx_bufs[0].buf = dest;
+ rx_bufs[0].len = len;
+ const struct spi_buf_set rx = {
+ .buffers = rx_bufs,
+ .count = ARRAY_SIZE(rx_bufs)
+ };
+
+ ret = spi_transceive(self->dev, &self->config, &tx, &rx);
+
+ if (ret < 0) {
+ mp_raise_OSError(-ret);
+ }
+}
+
+STATIC const mp_machine_spi_p_t machine_hard_spi_p = {
+ .init = machine_hard_spi_init,
+ .transfer = machine_hard_spi_transfer,
+};
+
+const mp_obj_type_t machine_hard_spi_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_SPI,
+ .print = machine_hard_spi_print,
+ .make_new = machine_hard_spi_make_new,
+ .protocol = &machine_hard_spi_p,
+ .locals_dict = (mp_obj_dict_t *)&mp_machine_spi_locals_dict,
+};
+
+#endif // MICROPY_PY_MACHINE_SPI
diff --git a/ports/zephyr/main.c b/ports/zephyr/main.c
index 38285ad94..63190bd5e 100644
--- a/ports/zephyr/main.c
+++ b/ports/zephyr/main.c
@@ -47,8 +47,8 @@
#include "py/gc.h"
#include "py/mphal.h"
#include "py/stackctrl.h"
-#include "lib/utils/pyexec.h"
-#include "lib/mp-readline/readline.h"
+#include "shared/runtime/pyexec.h"
+#include "shared/readline/readline.h"
#include "extmod/modbluetooth.h"
#if MICROPY_VFS
@@ -59,9 +59,9 @@
#include "modzephyr.h"
#ifdef TEST
-#include "lib/upytesthelper/upytesthelper.h"
+#include "shared/upytesthelper/upytesthelper.h"
#include "lib/tinytest/tinytest.c"
-#include "lib/upytesthelper/upytesthelper.c"
+#include "shared/upytesthelper/upytesthelper.c"
#include TEST
#endif
diff --git a/ports/zephyr/modbluetooth_zephyr.c b/ports/zephyr/modbluetooth_zephyr.c
index 6b3a10d47..5753d7147 100644
--- a/ports/zephyr/modbluetooth_zephyr.c
+++ b/ports/zephyr/modbluetooth_zephyr.c
@@ -308,10 +308,13 @@ int mp_bluetooth_gatts_read(uint16_t value_handle, uint8_t **value, size_t *valu
return mp_bluetooth_gatts_db_read(MP_STATE_PORT(bluetooth_zephyr_root_pointers)->gatts_db, value_handle, value, value_len);
}
-int mp_bluetooth_gatts_write(uint16_t value_handle, const uint8_t *value, size_t value_len) {
+int mp_bluetooth_gatts_write(uint16_t value_handle, const uint8_t *value, size_t value_len, bool send_update) {
if (!mp_bluetooth_is_active()) {
return ERRNO_BLUETOOTH_NOT_ACTIVE;
}
+ if (send_update) {
+ return MP_EOPNOTSUPP;
+ }
return mp_bluetooth_gatts_db_write(MP_STATE_PORT(bluetooth_zephyr_root_pointers)->gatts_db, value_handle, value, value_len);
}
diff --git a/ports/zephyr/modmachine.c b/ports/zephyr/modmachine.c
index 4353083ee..adec9160b 100644
--- a/ports/zephyr/modmachine.c
+++ b/ports/zephyr/modmachine.c
@@ -36,6 +36,7 @@
#include "extmod/machine_signal.h"
#include "extmod/machine_pulse.h"
#include "extmod/machine_i2c.h"
+#include "extmod/machine_spi.h"
#include "modmachine.h"
#if MICROPY_PY_MACHINE
@@ -70,6 +71,9 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = {
#if MICROPY_PY_MACHINE_I2C
{ MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&machine_hard_i2c_type) },
#endif
+ #if MICROPY_PY_MACHINE_SPI
+ { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&machine_hard_spi_type) },
+ #endif
{ MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&machine_uart_type) },
{ MP_ROM_QSTR(MP_QSTR_Pin), MP_ROM_PTR(&machine_pin_type) },
{ MP_ROM_QSTR(MP_QSTR_Signal), MP_ROM_PTR(&machine_signal_type) },
diff --git a/ports/zephyr/modmachine.h b/ports/zephyr/modmachine.h
index 957f2dd4f..a3cdd2b30 100644
--- a/ports/zephyr/modmachine.h
+++ b/ports/zephyr/modmachine.h
@@ -5,6 +5,7 @@
extern const mp_obj_type_t machine_pin_type;
extern const mp_obj_type_t machine_hard_i2c_type;
+extern const mp_obj_type_t machine_hard_spi_type;
extern const mp_obj_type_t machine_uart_type;
MP_DECLARE_CONST_FUN_OBJ_0(machine_info_obj);
diff --git a/ports/zephyr/mpconfigport.h b/ports/zephyr/mpconfigport.h
index e5fb32d6b..1768d2e82 100644
--- a/ports/zephyr/mpconfigport.h
+++ b/ports/zephyr/mpconfigport.h
@@ -29,6 +29,7 @@
#include "autoconf.h"
// Included here to get basic Zephyr environment (macros, etc.)
#include
+#include
// Usually passed from Makefile
#ifndef MICROPY_HEAP_SIZE
@@ -66,6 +67,9 @@
#define MICROPY_PY_MICROPYTHON_MEM_INFO (1)
#define MICROPY_PY_MACHINE (1)
#define MICROPY_PY_MACHINE_I2C (1)
+#define MICROPY_PY_MACHINE_SPI (1)
+#define MICROPY_PY_MACHINE_SPI_MSB (SPI_TRANSFER_MSB)
+#define MICROPY_PY_MACHINE_SPI_LSB (SPI_TRANSFER_LSB)
#define MICROPY_PY_MACHINE_PIN_MAKE_NEW mp_pin_make_new
#define MICROPY_MODULE_WEAK_LINKS (1)
#define MICROPY_PY_STRUCT (0)
diff --git a/ports/zephyr/mpconfigport_bin_testsuite.h b/ports/zephyr/mpconfigport_bin_testsuite.h
index 684b4f41c..4367067af 100644
--- a/ports/zephyr/mpconfigport_bin_testsuite.h
+++ b/ports/zephyr/mpconfigport_bin_testsuite.h
@@ -26,6 +26,6 @@
#include "mpconfigport.h"
#ifdef TEST
-#include "lib/upytesthelper/upytesthelper.h"
+#include "shared/upytesthelper/upytesthelper.h"
#define MP_PLAT_PRINT_STRN(str, len) upytest_output(str, len)
#endif
diff --git a/ports/zephyr/mphalport.h b/ports/zephyr/mphalport.h
index 63a18e138..ba902a76a 100644
--- a/ports/zephyr/mphalport.h
+++ b/ports/zephyr/mphalport.h
@@ -1,5 +1,5 @@
#include
-#include "lib/utils/interrupt_char.h"
+#include "shared/runtime/interrupt_char.h"
void mp_hal_init(void);
void mp_hal_wait_sem(struct k_sem *sem, uint32_t timeout_ms);
diff --git a/py/builtinimport.c b/py/builtinimport.c
index abbeefced..cdee5e407 100644
--- a/py/builtinimport.c
+++ b/py/builtinimport.c
@@ -142,7 +142,7 @@ STATIC void do_load_from_lexer(mp_obj_t module_obj, mp_lexer_t *lex) {
}
#endif
-#if MICROPY_PERSISTENT_CODE_LOAD || MICROPY_MODULE_FROZEN_MPY
+#if (MICROPY_HAS_FILE_READER && MICROPY_PERSISTENT_CODE_LOAD) || MICROPY_MODULE_FROZEN_MPY
STATIC void do_execute_raw_code(mp_obj_t module_obj, mp_raw_code_t *raw_code, const char *source_name) {
(void)source_name;
diff --git a/py/dynruntime.h b/py/dynruntime.h
index a8256c194..fdb91ed37 100644
--- a/py/dynruntime.h
+++ b/py/dynruntime.h
@@ -215,6 +215,7 @@ static inline mp_obj_t mp_obj_len_dyn(mp_obj_t o) {
#define mp_obj_new_exception_arg1(e_type, arg) (mp_obj_new_exception_arg1_dyn((e_type), (arg)))
#define nlr_raise(o) (mp_raise_dyn(o))
+#define mp_raise_type_arg(type, arg) (mp_raise_dyn(mp_obj_new_exception_arg1_dyn((type), (arg))))
#define mp_raise_msg(type, msg) (mp_fun_table.raise_msg((type), (msg)))
#define mp_raise_OSError(er) (mp_raise_OSError_dyn(er))
#define mp_raise_NotImplementedError(msg) (mp_raise_msg(&mp_type_NotImplementedError, (msg)))
diff --git a/py/emitnative.c b/py/emitnative.c
index 425ba2d33..7c7c34283 100644
--- a/py/emitnative.c
+++ b/py/emitnative.c
@@ -841,10 +841,13 @@ STATIC void need_reg_single(emit_t *emit, int reg_needed, int skip_stack_pos) {
}
}
+// Ensures all unsettled registers that hold Python values are copied to the
+// concrete Python stack. All registers are then free to use.
STATIC void need_reg_all(emit_t *emit) {
for (int i = 0; i < emit->stack_size; i++) {
stack_info_t *si = &emit->stack_info[i];
if (si->kind == STACK_REG) {
+ DEBUG_printf(" reg(%u) to local(%u)\n", si->data.u_reg, emit->stack_start + i);
si->kind = STACK_VALUE;
emit_native_mov_state_reg(emit, emit->stack_start + i, si->data.u_reg);
}
@@ -871,23 +874,21 @@ STATIC vtype_kind_t load_reg_stack_imm(emit_t *emit, int reg_dest, const stack_i
}
}
+// Copies all unsettled registers and immediates that are Python values into the
+// concrete Python stack. This ensures the concrete Python stack holds valid
+// values for the current stack_size.
+// This function may clobber REG_TEMP1.
STATIC void need_stack_settled(emit_t *emit) {
DEBUG_printf(" need_stack_settled; stack_size=%d\n", emit->stack_size);
- for (int i = 0; i < emit->stack_size; i++) {
- stack_info_t *si = &emit->stack_info[i];
- if (si->kind == STACK_REG) {
- DEBUG_printf(" reg(%u) to local(%u)\n", si->data.u_reg, emit->stack_start + i);
- si->kind = STACK_VALUE;
- emit_native_mov_state_reg(emit, emit->stack_start + i, si->data.u_reg);
- }
- }
+ need_reg_all(emit);
for (int i = 0; i < emit->stack_size; i++) {
stack_info_t *si = &emit->stack_info[i];
if (si->kind == STACK_IMM) {
DEBUG_printf(" imm(" INT_FMT ") to local(%u)\n", si->data.u_imm, emit->stack_start + i);
si->kind = STACK_VALUE;
- si->vtype = load_reg_stack_imm(emit, REG_TEMP0, si, false);
- emit_native_mov_state_reg(emit, emit->stack_start + i, REG_TEMP0);
+ // using REG_TEMP1 to avoid clobbering REG_TEMP0 (aka REG_RET)
+ si->vtype = load_reg_stack_imm(emit, REG_TEMP1, si, false);
+ emit_native_mov_state_reg(emit, emit->stack_start + i, REG_TEMP1);
}
}
}
diff --git a/py/lexer.c b/py/lexer.c
index 07ea2b96a..69c7d14a7 100644
--- a/py/lexer.c
+++ b/py/lexer.c
@@ -62,6 +62,12 @@ STATIC bool is_char_or3(mp_lexer_t *lex, byte c1, byte c2, byte c3) {
return lex->chr0 == c1 || lex->chr0 == c2 || lex->chr0 == c3;
}
+#if MICROPY_PY_FSTRINGS
+STATIC bool is_char_or4(mp_lexer_t *lex, byte c1, byte c2, byte c3, byte c4) {
+ return lex->chr0 == c1 || lex->chr0 == c2 || lex->chr0 == c3 || lex->chr0 == c4;
+}
+#endif
+
STATIC bool is_char_following(mp_lexer_t *lex, byte c) {
return lex->chr1 == c;
}
@@ -105,7 +111,13 @@ STATIC bool is_following_odigit(mp_lexer_t *lex) {
STATIC bool is_string_or_bytes(mp_lexer_t *lex) {
return is_char_or(lex, '\'', '\"')
+ #if MICROPY_PY_FSTRINGS
+ || (is_char_or4(lex, 'r', 'u', 'b', 'f') && is_char_following_or(lex, '\'', '\"'))
+ || (((is_char_and(lex, 'r', 'f') || is_char_and(lex, 'f', 'r'))
+ && is_char_following_following_or(lex, '\'', '\"')))
+ #else
|| (is_char_or3(lex, 'r', 'u', 'b') && is_char_following_or(lex, '\'', '\"'))
+ #endif
|| ((is_char_and(lex, 'r', 'b') || is_char_and(lex, 'b', 'r'))
&& is_char_following_following_or(lex, '\'', '\"'));
}
@@ -132,9 +144,35 @@ STATIC void next_char(mp_lexer_t *lex) {
++lex->column;
}
+ // shift the input queue forward
lex->chr0 = lex->chr1;
lex->chr1 = lex->chr2;
- lex->chr2 = lex->reader.readbyte(lex->reader.data);
+
+ // and add the next byte from either the fstring args or the reader
+ #if MICROPY_PY_FSTRINGS
+ if (lex->fstring_args_idx) {
+ // if there are saved chars, then we're currently injecting fstring args
+ if (lex->fstring_args_idx < lex->fstring_args.len) {
+ lex->chr2 = lex->fstring_args.buf[lex->fstring_args_idx++];
+ } else {
+ // no more fstring arg bytes
+ lex->chr2 = '\0';
+ }
+
+ if (lex->chr0 == '\0') {
+ // consumed all fstring data, restore saved input queue
+ lex->chr0 = lex->chr0_saved;
+ lex->chr1 = lex->chr1_saved;
+ lex->chr2 = lex->chr2_saved;
+ // stop consuming fstring arg data
+ vstr_reset(&lex->fstring_args);
+ lex->fstring_args_idx = 0;
+ }
+ } else
+ #endif
+ {
+ lex->chr2 = lex->reader.readbyte(lex->reader.data);
+ }
if (lex->chr1 == '\r') {
// CR is a new line, converted to LF
@@ -272,7 +310,7 @@ STATIC bool get_hex(mp_lexer_t *lex, size_t num_digits, mp_uint_t *result) {
return true;
}
-STATIC void parse_string_literal(mp_lexer_t *lex, bool is_raw) {
+STATIC void parse_string_literal(mp_lexer_t *lex, bool is_raw, bool is_fstring) {
// get first quoting character
char quote_char = '\'';
if (is_char(lex, '\"')) {
@@ -293,12 +331,57 @@ STATIC void parse_string_literal(mp_lexer_t *lex, bool is_raw) {
}
size_t n_closing = 0;
+ #if MICROPY_PY_FSTRINGS
+ if (is_fstring) {
+ // assume there's going to be interpolation, so prep the injection data
+ // fstring_args_idx==0 && len(fstring_args)>0 means we're extracting the args.
+ // only when fstring_args_idx>0 will we consume the arg data
+ // note: lex->fstring_args will be empty already (it's reset when finished)
+ vstr_add_str(&lex->fstring_args, ".format(");
+ }
+ #endif
+
while (!is_end(lex) && (num_quotes > 1 || !is_char(lex, '\n')) && n_closing < num_quotes) {
if (is_char(lex, quote_char)) {
n_closing += 1;
vstr_add_char(&lex->vstr, CUR_CHAR(lex));
} else {
n_closing = 0;
+
+ #if MICROPY_PY_FSTRINGS
+ while (is_fstring && is_char(lex, '{')) {
+ next_char(lex);
+ if (is_char(lex, '{')) {
+ // "{{" is passed through unchanged to be handled by str.format
+ vstr_add_byte(&lex->vstr, '{');
+ next_char(lex);
+ } else {
+ // 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
+ // format specifier or closing }.
+ // (MicroPython limitation) note: this is completely unaware of
+ // Python syntax and will not handle any expression containing '}' or ':'.
+ // e.g. f'{"}"}' or f'{foo({})}'.
+ while (!is_end(lex) && !is_char_or(lex, ':', '}')) {
+ // like the default case at the end of this function, stay 8-bit clean
+ vstr_add_byte(&lex->fstring_args, CUR_CHAR(lex));
+ next_char(lex);
+ }
+ if (lex->fstring_args.buf[lex->fstring_args.len - 1] == '=') {
+ // if the last character of the arg was '=', then inject "arg=" before the '{'.
+ // f'{a=}' --> 'a={}'.format(a)
+ vstr_add_strn(&lex->vstr, lex->fstring_args.buf + i, lex->fstring_args.len - i);
+ // remove the trailing '='
+ lex->fstring_args.len--;
+ }
+ // comma-separate args
+ vstr_add_byte(&lex->fstring_args, ',');
+ }
+ vstr_add_byte(&lex->vstr, '{');
+ }
+ #endif
+
if (is_char(lex, '\\')) {
next_char(lex);
unichar c = CUR_CHAR(lex);
@@ -451,6 +534,23 @@ STATIC bool skip_whitespace(mp_lexer_t *lex, bool stop_at_newline) {
}
void mp_lexer_to_next(mp_lexer_t *lex) {
+ #if MICROPY_PY_FSTRINGS
+ if (lex->fstring_args.len && lex->fstring_args_idx == 0) {
+ // moving onto the next token means the literal string is complete.
+ // switch into injecting the format args.
+ vstr_add_byte(&lex->fstring_args, ')');
+ lex->chr0_saved = lex->chr0;
+ lex->chr1_saved = lex->chr1;
+ lex->chr2_saved = lex->chr2;
+ lex->chr0 = lex->fstring_args.buf[0];
+ lex->chr1 = lex->fstring_args.buf[1];
+ lex->chr2 = lex->fstring_args.buf[2];
+ // we've already extracted 3 chars, but setting this non-zero also
+ // means we'll start consuming the fstring data
+ lex->fstring_args_idx = 3;
+ }
+ #endif
+
// start new token text
vstr_reset(&lex->vstr);
@@ -506,6 +606,7 @@ void mp_lexer_to_next(mp_lexer_t *lex) {
do {
// parse type codes
bool is_raw = false;
+ bool is_fstring = false;
mp_token_kind_t kind = MP_TOKEN_STRING;
int n_char = 0;
if (is_char(lex, 'u')) {
@@ -524,7 +625,25 @@ void mp_lexer_to_next(mp_lexer_t *lex) {
kind = MP_TOKEN_BYTES;
n_char = 2;
}
+ #if MICROPY_PY_FSTRINGS
+ if (is_char_following(lex, 'f')) {
+ // raw-f-strings unsupported, immediately return (invalid) token.
+ lex->tok_kind = MP_TOKEN_FSTRING_RAW;
+ break;
+ }
+ #endif
}
+ #if MICROPY_PY_FSTRINGS
+ else if (is_char(lex, 'f')) {
+ if (is_char_following(lex, 'r')) {
+ // raw-f-strings unsupported, immediately return (invalid) token.
+ lex->tok_kind = MP_TOKEN_FSTRING_RAW;
+ break;
+ }
+ n_char = 1;
+ is_fstring = true;
+ }
+ #endif
// Set or check token kind
if (lex->tok_kind == MP_TOKEN_END) {
@@ -543,7 +662,7 @@ void mp_lexer_to_next(mp_lexer_t *lex) {
}
// Parse the literal
- parse_string_literal(lex, is_raw);
+ parse_string_literal(lex, is_raw, is_fstring);
// Skip whitespace so we can check if there's another string following
skip_whitespace(lex, true);
@@ -703,6 +822,9 @@ mp_lexer_t *mp_lexer_new(qstr src_name, mp_reader_t reader) {
lex->num_indent_level = 1;
lex->indent_level = m_new(uint16_t, lex->alloc_indent_level);
vstr_init(&lex->vstr, 32);
+ #if MICROPY_PY_FSTRINGS
+ vstr_init(&lex->fstring_args, 0);
+ #endif
// store sentinel for first indentation level
lex->indent_level[0] = 0;
@@ -756,6 +878,9 @@ void mp_lexer_free(mp_lexer_t *lex) {
if (lex) {
lex->reader.close(lex->reader.data);
vstr_clear(&lex->vstr);
+ #if MICROPY_PY_FSTRINGS
+ vstr_clear(&lex->fstring_args);
+ #endif
m_del(uint16_t, lex->indent_level, lex->alloc_indent_level);
m_del_obj(mp_lexer_t, lex);
}
diff --git a/py/lexer.h b/py/lexer.h
index 91767a44b..e16b9a8ce 100644
--- a/py/lexer.h
+++ b/py/lexer.h
@@ -44,6 +44,10 @@ typedef enum _mp_token_kind_t {
MP_TOKEN_INVALID,
MP_TOKEN_DEDENT_MISMATCH,
MP_TOKEN_LONELY_STRING_OPEN,
+ #if MICROPY_PY_FSTRINGS
+ MP_TOKEN_MALFORMED_FSTRING,
+ MP_TOKEN_FSTRING_RAW,
+ #endif
MP_TOKEN_NEWLINE,
MP_TOKEN_INDENT,
@@ -158,6 +162,9 @@ typedef struct _mp_lexer_t {
mp_reader_t reader; // stream source
unichar chr0, chr1, chr2; // current cached characters from source
+ #if MICROPY_PY_FSTRINGS
+ unichar chr0_saved, chr1_saved, chr2_saved; // current cached characters from alt source
+ #endif
size_t line; // current source line
size_t column; // current source column
@@ -173,6 +180,10 @@ typedef struct _mp_lexer_t {
size_t tok_column; // token source column
mp_token_kind_t tok_kind; // token kind
vstr_t vstr; // token data
+ #if MICROPY_PY_FSTRINGS
+ vstr_t fstring_args; // extracted arguments to pass to .format()
+ size_t fstring_args_idx; // how many bytes of fstring_args have been read
+ #endif
} mp_lexer_t;
mp_lexer_t *mp_lexer_new(qstr src_name, mp_reader_t reader);
diff --git a/py/makeversionhdr.py b/py/makeversionhdr.py
index 2f4bc9182..54b7fa9ab 100644
--- a/py/makeversionhdr.py
+++ b/py/makeversionhdr.py
@@ -23,7 +23,7 @@ def get_version_info_from_git():
# Note: git describe doesn't work if no tag is available
try:
git_tag = subprocess.check_output(
- ["git", "describe", "--dirty", "--always", "--match", "v[1-9].*"],
+ ["git", "describe", "--tags", "--dirty", "--always", "--match", "v[1-9].*"],
stderr=subprocess.STDOUT,
universal_newlines=True,
).strip()
diff --git a/py/misc.h b/py/misc.h
index 953809838..e1d27dc7b 100644
--- a/py/misc.h
+++ b/py/misc.h
@@ -55,6 +55,7 @@ typedef unsigned int uint;
// Round-up integer division
#define MP_CEIL_DIVIDE(a, b) (((a) + (b) - 1) / (b))
+#define MP_ROUND_DIVIDE(a, b) (((a) + (b) / 2) / (b))
/** memory allocation ******************************************/
diff --git a/py/mkenv.mk b/py/mkenv.mk
index d54f0a0d3..2b247974b 100644
--- a/py/mkenv.mk
+++ b/py/mkenv.mk
@@ -55,11 +55,15 @@ AR = $(CROSS_COMPILE)ar
MAKE_MANIFEST = $(PYTHON) $(TOP)/tools/makemanifest.py
MAKE_FROZEN = $(PYTHON) $(TOP)/tools/make-frozen.py
-MPY_CROSS = $(TOP)/mpy-cross/mpy-cross
MPY_TOOL = $(PYTHON) $(TOP)/tools/mpy-tool.py
MPY_LIB_DIR = $(TOP)/../micropython-lib
+ifeq ($(MICROPY_MPYCROSS),)
+MICROPY_MPYCROSS = $(TOP)/mpy-cross/mpy-cross
+MICROPY_MPYCROSS_DEPENDENCY = $(MICROPY_MPYCROSS)
+endif
+
all:
.PHONY: all
diff --git a/py/mkrules.cmake b/py/mkrules.cmake
index 7589255b2..9d0801793 100644
--- a/py/mkrules.cmake
+++ b/py/mkrules.cmake
@@ -129,11 +129,27 @@ if(MICROPY_FROZEN_MANIFEST)
set(MICROPY_LIB_DIR ${MICROPY_DIR}/../micropython-lib)
endif()
+ # If MICROPY_MPYCROSS is not explicitly defined in the environment (which
+ # is what makemanifest.py will use) then create an mpy-cross dependency
+ # to automatically build mpy-cross if needed.
+ set(MICROPY_MPYCROSS $ENV{MICROPY_MPYCROSS})
+ if(NOT MICROPY_MPYCROSS)
+ set(MICROPY_MPYCROSS_DEPENDENCY ${MICROPY_DIR}/mpy-cross/mpy-cross)
+ if(NOT MICROPY_MAKE_EXECUTABLE)
+ set(MICROPY_MAKE_EXECUTABLE make)
+ endif()
+ add_custom_command(
+ OUTPUT ${MICROPY_MPYCROSS_DEPENDENCY}
+ COMMAND ${MICROPY_MAKE_EXECUTABLE} -C ${MICROPY_DIR}/mpy-cross
+ )
+ endif()
+
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}
DEPENDS MICROPY_FORCE_BUILD
${MICROPY_QSTRDEFS_GENERATED}
+ ${MICROPY_MPYCROSS_DEPENDENCY}
VERBATIM
)
endif()
diff --git a/py/mkrules.mk b/py/mkrules.mk
index 038a49329..d0c0a53c2 100644
--- a/py/mkrules.mk
+++ b/py/mkrules.mk
@@ -136,9 +136,15 @@ $(OBJ_DIRS):
$(HEADER_BUILD):
$(MKDIR) -p $@
+ifneq ($(MICROPY_MPYCROSS_DEPENDENCY),)
+# to automatically build mpy-cross, if needed
+$(MICROPY_MPYCROSS_DEPENDENCY):
+ $(MAKE) -C $(dir $@)
+endif
+
ifneq ($(FROZEN_MANIFEST),)
# to build frozen_content.c from a manifest
-$(BUILD)/frozen_content.c: FORCE $(BUILD)/genhdr/qstrdefs.generated.h
+$(BUILD)/frozen_content.c: FORCE $(BUILD)/genhdr/qstrdefs.generated.h | $(MICROPY_MPYCROSS_DEPENDENCY)
$(Q)$(MAKE_MANIFEST) -o $@ -v "MPY_DIR=$(TOP)" -v "MPY_LIB_DIR=$(MPY_LIB_DIR)" -v "PORT_DIR=$(shell pwd)" -v "BOARD_DIR=$(BOARD_DIR)" -b "$(BUILD)" $(if $(MPY_CROSS_FLAGS),-f"$(MPY_CROSS_FLAGS)",) --mpy-tool-flags="$(MPY_TOOL_FLAGS)" $(FROZEN_MANIFEST)
ifneq ($(FROZEN_DIR),)
@@ -164,10 +170,10 @@ FROZEN_MPY_PY_FILES := $(shell find -L $(FROZEN_MPY_DIR) -type f -name '*.py' |
FROZEN_MPY_MPY_FILES := $(addprefix $(BUILD)/frozen_mpy/,$(FROZEN_MPY_PY_FILES:.py=.mpy))
# to build .mpy files from .py files
-$(BUILD)/frozen_mpy/%.mpy: $(FROZEN_MPY_DIR)/%.py
+$(BUILD)/frozen_mpy/%.mpy: $(FROZEN_MPY_DIR)/%.py | $(MICROPY_MPYCROSS_DEPENDENCY)
@$(ECHO) "MPY $<"
$(Q)$(MKDIR) -p $(dir $@)
- $(Q)$(MPY_CROSS) -o $@ -s $(<:$(FROZEN_MPY_DIR)/%=%) $(MPY_CROSS_FLAGS) $<
+ $(Q)$(MICROPY_MPYCROSS) -o $@ -s $(<:$(FROZEN_MPY_DIR)/%=%) $(MPY_CROSS_FLAGS) $<
# to build frozen_mpy.c from all .mpy files
$(BUILD)/frozen_mpy.c: $(FROZEN_MPY_MPY_FILES) $(BUILD)/genhdr/qstrdefs.generated.h
@@ -178,6 +184,13 @@ endif
ifneq ($(PROG),)
# Build a standalone executable (unix does this)
+# The executable should have an .exe extension for builds targetting 'pure'
+# Windows, i.e. msvc or mingw builds, but not when using msys or cygwin's gcc.
+COMPILER_TARGET := $(shell $(CC) -dumpmachine)
+ifneq (,$(findstring mingw,$(COMPILER_TARGET)))
+PROG := $(PROG).exe
+endif
+
all: $(PROG)
$(PROG): $(OBJ)
@@ -186,9 +199,9 @@ $(PROG): $(OBJ)
# we may want to compile using Thumb, but link with non-Thumb libc.
$(Q)$(CC) -o $@ $^ $(LIB) $(LDFLAGS)
ifndef DEBUG
- $(Q)$(STRIP) $(STRIPFLAGS_EXTRA) $(PROG)
+ $(Q)$(STRIP) $(STRIPFLAGS_EXTRA) $@
endif
- $(Q)$(SIZE) $$(find $(BUILD) -path "$(BUILD)/build/frozen*.o") $(PROG)
+ $(Q)$(SIZE) $$(find $(BUILD) -path "$(BUILD)/build/frozen*.o") $@
clean: clean-prog
clean-prog:
@@ -201,6 +214,7 @@ endif
submodules:
$(ECHO) "Updating submodules: $(GIT_SUBMODULES)"
ifneq ($(GIT_SUBMODULES),)
+ $(Q)git submodule sync $(addprefix $(TOP)/,$(GIT_SUBMODULES))
$(Q)git submodule update --init $(addprefix $(TOP)/,$(GIT_SUBMODULES))
endif
.PHONY: submodules
diff --git a/py/modbuiltins.c b/py/modbuiltins.c
index ac41942b9..a7e49a1ed 100644
--- a/py/modbuiltins.c
+++ b/py/modbuiltins.c
@@ -230,7 +230,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_hex_obj, mp_builtin_hex);
#if MICROPY_PY_BUILTINS_INPUT
#include "py/mphal.h"
-#include "lib/mp-readline/readline.h"
+#include "shared/readline/readline.h"
// A port can define mp_hal_readline if they want to use a custom function here
#ifndef mp_hal_readline
@@ -322,7 +322,7 @@ STATIC mp_obj_t mp_builtin_next(size_t n_args, const mp_obj_t *args) {
if (n_args == 1) {
mp_obj_t ret = mp_iternext_allow_raise(args[0]);
if (ret == MP_OBJ_STOP_ITERATION) {
- mp_raise_type(&mp_type_StopIteration);
+ mp_raise_StopIteration(MP_STATE_THREAD(stop_iteration_arg));
} else {
return ret;
}
@@ -336,7 +336,7 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_next_obj, 1, 2, mp_builtin_next);
STATIC mp_obj_t mp_builtin_next(mp_obj_t o) {
mp_obj_t ret = mp_iternext_allow_raise(o);
if (ret == MP_OBJ_STOP_ITERATION) {
- mp_raise_type(&mp_type_StopIteration);
+ mp_raise_StopIteration(MP_STATE_THREAD(stop_iteration_arg));
} else {
return ret;
}
diff --git a/py/modsys.c b/py/modsys.c
index 586b13e74..64349f3c3 100644
--- a/py/modsys.c
+++ b/py/modsys.c
@@ -110,13 +110,11 @@ STATIC const MP_DEFINE_STR_OBJ(mp_sys_platform_obj, MICROPY_PY_SYS_PLATFORM);
// exit([retval]): raise SystemExit, with optional argument given to the exception
STATIC mp_obj_t mp_sys_exit(size_t n_args, const mp_obj_t *args) {
- mp_obj_t exc;
if (n_args == 0) {
- exc = mp_obj_new_exception(&mp_type_SystemExit);
+ mp_raise_type(&mp_type_SystemExit);
} else {
- exc = mp_obj_new_exception_arg1(&mp_type_SystemExit, args[0]);
+ mp_raise_type_arg(&mp_type_SystemExit, args[0]);
}
- nlr_raise(exc);
}
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_sys_exit_obj, 0, 1, mp_sys_exit);
diff --git a/py/mpconfig.h b/py/mpconfig.h
index d40637dfa..71440da39 100644
--- a/py/mpconfig.h
+++ b/py/mpconfig.h
@@ -28,7 +28,7 @@
// Current version of MicroPython
#define MICROPY_VERSION_MAJOR 1
-#define MICROPY_VERSION_MINOR 16
+#define MICROPY_VERSION_MINOR 17
#define MICROPY_VERSION_MICRO 0
// Combined version as a 32-bit number for convenience
@@ -483,7 +483,8 @@
/* Optimisations */
// Whether to use computed gotos in the VM, or a switch
-// Computed gotos are roughly 10% faster, and increase VM code size by a little
+// Computed gotos are roughly 10% faster, and increase VM code size by a little,
+// e.g. ~1kiB on Cortex M4.
// Note: enabling this will use the gcc-specific extensions of ranged designated
// initialisers and addresses of labels, which are not part of the C99 standard.
#ifndef MICROPY_OPT_COMPUTED_GOTO
@@ -875,6 +876,11 @@ typedef double mp_float_t;
#define MICROPY_PY_ASYNC_AWAIT (1)
#endif
+// Support for literal string interpolation, f-strings (see PEP 498, Python 3.6+)
+#ifndef MICROPY_PY_FSTRINGS
+#define MICROPY_PY_FSTRINGS (0)
+#endif
+
// Support for assignment expressions with := (see PEP 572, Python 3.8+)
#ifndef MICROPY_PY_ASSIGN_EXPR
#define MICROPY_PY_ASSIGN_EXPR (1)
@@ -1063,7 +1069,7 @@ typedef double mp_float_t;
#endif
// Whether to provide the built-in input() function. The implementation of this
-// uses mp-readline, so can only be enabled if the port uses this readline.
+// uses shared/readline, so can only be enabled if the port uses this readline.
#ifndef MICROPY_PY_BUILTINS_INPUT
#define MICROPY_PY_BUILTINS_INPUT (0)
#endif
@@ -1316,6 +1322,13 @@ typedef double mp_float_t;
#define MICROPY_PY_USELECT (0)
#endif
+// Whether to enable the select() function in the "uselect" module (baremetal
+// implementation). This is present for compatibility but can be disabled to
+// save space.
+#ifndef MICROPY_PY_USELECT_SELECT
+#define MICROPY_PY_USELECT_SELECT (1)
+#endif
+
// Whether to provide "utime" module functions implementation
// in terms of mp_hal_* functions.
#ifndef MICROPY_PY_UTIME_MP_HAL
@@ -1373,6 +1386,11 @@ typedef double mp_float_t;
#define MICROPY_PY_UJSON (0)
#endif
+// Whether to support the "separators" argument to dump, dumps
+#ifndef MICROPY_PY_UJSON_SEPARATORS
+#define MICROPY_PY_UJSON_SEPARATORS (1)
+#endif
+
#ifndef MICROPY_PY_URE
#define MICROPY_PY_URE (0)
#endif
@@ -1453,6 +1471,11 @@ typedef double mp_float_t;
#define MICROPY_PY_MACHINE (0)
#endif
+// Whether to include: bitstream
+#ifndef MICROPY_PY_MACHINE_BITSTREAM
+#define MICROPY_PY_MACHINE_BITSTREAM (0)
+#endif
+
// Whether to include: time_pulse_us
#ifndef MICROPY_PY_MACHINE_PULSE
#define MICROPY_PY_MACHINE_PULSE (0)
diff --git a/py/mpprint.h b/py/mpprint.h
index aef9015de..0dff9a770 100644
--- a/py/mpprint.h
+++ b/py/mpprint.h
@@ -52,6 +52,14 @@ typedef struct _mp_print_t {
mp_print_strn_t print_strn;
} mp_print_t;
+typedef struct _mp_print_ext_t {
+ mp_print_t base;
+ const char *item_separator;
+ const char *key_separator;
+}mp_print_ext_t;
+
+#define MP_PRINT_GET_EXT(print) ((mp_print_ext_t *)print)
+
// All (non-debug) prints go through one of the two interfaces below.
// 1) Wrapper for platform print function, which wraps MP_PLAT_PRINT_STRN.
extern const mp_print_t mp_plat_print;
diff --git a/py/mpstate.h b/py/mpstate.h
index e42d13fb2..07335bae4 100644
--- a/py/mpstate.h
+++ b/py/mpstate.h
@@ -266,6 +266,9 @@ typedef struct _mp_state_thread_t {
// pending exception object (MP_OBJ_NULL if not pending)
volatile mp_obj_t mp_pending_exception;
+ // If MP_OBJ_STOP_ITERATION is propagated then this holds its argument.
+ mp_obj_t stop_iteration_arg;
+
#if MICROPY_PY_SYS_SETTRACE
mp_obj_t prof_trace_callback;
bool prof_callback_is_executing;
diff --git a/py/obj.h b/py/obj.h
index 86e5d8312..11918ba17 100644
--- a/py/obj.h
+++ b/py/obj.h
@@ -739,7 +739,6 @@ mp_obj_t mp_obj_new_int_from_float(mp_float_t val);
mp_obj_t mp_obj_new_complex(mp_float_t real, mp_float_t imag);
#endif
mp_obj_t mp_obj_new_exception(const mp_obj_type_t *exc_type);
-mp_obj_t mp_obj_new_exception_arg1(const mp_obj_type_t *exc_type, mp_obj_t arg);
mp_obj_t mp_obj_new_exception_args(const mp_obj_type_t *exc_type, size_t n_args, const mp_obj_t *args);
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_NONE
#define mp_obj_new_exception_msg(exc_type, msg) mp_obj_new_exception(exc_type)
@@ -780,9 +779,11 @@ bool mp_obj_is_callable(mp_obj_t o_in);
mp_obj_t mp_obj_equal_not_equal(mp_binary_op_t op, mp_obj_t o1, mp_obj_t o2);
bool mp_obj_equal(mp_obj_t o1, mp_obj_t o2);
+// returns true if o is bool, small int or long int
static inline bool mp_obj_is_integer(mp_const_obj_t o) {
return mp_obj_is_int(o) || mp_obj_is_bool(o);
-} // returns true if o is bool, small int or long int
+}
+
mp_int_t mp_obj_get_int(mp_const_obj_t arg);
mp_int_t mp_obj_get_int_truncated(mp_const_obj_t arg);
bool mp_obj_get_int_maybe(mp_const_obj_t arg, mp_int_t *value);
@@ -825,6 +826,10 @@ mp_obj_t mp_obj_exception_get_value(mp_obj_t self_in);
mp_obj_t mp_obj_exception_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args);
mp_obj_t mp_alloc_emergency_exception_buf(mp_obj_t size_in);
void mp_init_emergency_exception_buf(void);
+static inline mp_obj_t mp_obj_new_exception_arg1(const mp_obj_type_t *exc_type, mp_obj_t arg) {
+ assert(exc_type->make_new == mp_obj_exception_make_new);
+ return mp_obj_exception_make_new(exc_type, 1, 0, &arg);
+}
// str
bool mp_obj_str_equal(mp_obj_t s1, mp_obj_t s2);
diff --git a/py/objdict.c b/py/objdict.c
index aea5952d3..ed4376aa4 100644
--- a/py/objdict.c
+++ b/py/objdict.c
@@ -69,8 +69,15 @@ STATIC mp_map_elem_t *dict_iter_next(mp_obj_dict_t *dict, size_t *cur) {
STATIC void dict_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in);
bool first = true;
+ const char *item_separator = ", ";
+ const char *key_separator = ": ";
if (!(MICROPY_PY_UJSON && kind == PRINT_JSON)) {
kind = PRINT_REPR;
+ } else {
+ #if MICROPY_PY_UJSON_SEPARATORS
+ item_separator = MP_PRINT_GET_EXT(print)->item_separator;
+ key_separator = MP_PRINT_GET_EXT(print)->key_separator;
+ #endif
}
if (MICROPY_PY_COLLECTIONS_ORDEREDDICT && self->base.type != &mp_type_dict && kind != PRINT_JSON) {
mp_printf(print, "%q(", self->base.type->name);
@@ -80,7 +87,7 @@ STATIC void dict_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_
mp_map_elem_t *next = NULL;
while ((next = dict_iter_next(self, &cur)) != NULL) {
if (!first) {
- mp_print_str(print, ", ");
+ mp_print_str(print, item_separator);
}
first = false;
bool add_quote = MICROPY_PY_UJSON && kind == PRINT_JSON && !mp_obj_is_str_or_bytes(next->key);
@@ -91,7 +98,7 @@ STATIC void dict_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_
if (add_quote) {
mp_print_str(print, "\"");
}
- mp_print_str(print, ": ");
+ mp_print_str(print, key_separator);
mp_obj_print_helper(print, next->value, kind);
}
mp_print_str(print, "}");
@@ -190,7 +197,7 @@ mp_obj_t mp_obj_dict_get(mp_obj_t self_in, mp_obj_t index) {
mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in);
mp_map_elem_t *elem = mp_map_lookup(&self->map, index, MP_MAP_LOOKUP);
if (elem == NULL) {
- nlr_raise(mp_obj_new_exception_arg1(&mp_type_KeyError, index));
+ mp_raise_type_arg(&mp_type_KeyError, index);
} else {
return elem->value;
}
@@ -206,7 +213,7 @@ STATIC mp_obj_t dict_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in);
mp_map_elem_t *elem = mp_map_lookup(&self->map, index, MP_MAP_LOOKUP);
if (elem == NULL) {
- nlr_raise(mp_obj_new_exception_arg1(&mp_type_KeyError, index));
+ mp_raise_type_arg(&mp_type_KeyError, index);
} else {
return elem->value;
}
@@ -295,7 +302,7 @@ STATIC mp_obj_t dict_get_helper(size_t n_args, const mp_obj_t *args, mp_map_look
if (elem == NULL || elem->value == MP_OBJ_NULL) {
if (n_args == 2) {
if (lookup_kind == MP_MAP_LOOKUP_REMOVE_IF_FOUND) {
- nlr_raise(mp_obj_new_exception_arg1(&mp_type_KeyError, args[1]));
+ mp_raise_type_arg(&mp_type_KeyError, args[1]);
} else {
value = mp_const_none;
}
diff --git a/py/objexcept.c b/py/objexcept.c
index a10bd2c18..7a86c3647 100644
--- a/py/objexcept.c
+++ b/py/objexcept.c
@@ -111,6 +111,15 @@ mp_obj_t mp_alloc_emergency_exception_buf(mp_obj_t size_in) {
#endif
#endif // MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF
+STATIC mp_obj_exception_t *get_native_exception(mp_obj_t self_in) {
+ assert(mp_obj_is_exception_instance(self_in));
+ if (mp_obj_is_native_exception_instance(self_in)) {
+ return MP_OBJ_TO_PTR(self_in);
+ } else {
+ return MP_OBJ_TO_PTR(((mp_obj_instance_t *)MP_OBJ_TO_PTR(self_in))->subobj[0]);
+ }
+}
+
STATIC void decompress_error_text_maybe(mp_obj_exception_t *o) {
#if MICROPY_ROM_TEXT_COMPRESSION
if (o->args->len == 1 && mp_obj_is_type(o->args->items[0], &mp_type_str)) {
@@ -240,7 +249,7 @@ mp_obj_t mp_obj_exception_make_new(const mp_obj_type_t *type, size_t n_args, siz
// Get exception "value" - that is, first argument, or None
mp_obj_t mp_obj_exception_get_value(mp_obj_t self_in) {
- mp_obj_exception_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_obj_exception_t *self = get_native_exception(self_in);
if (self->args->len == 0) {
return mp_const_none;
} else {
@@ -369,12 +378,6 @@ mp_obj_t mp_obj_new_exception(const mp_obj_type_t *exc_type) {
return mp_obj_exception_make_new(exc_type, 0, 0, NULL);
}
-// "Optimized" version for common(?) case of having 1 exception arg
-mp_obj_t mp_obj_new_exception_arg1(const mp_obj_type_t *exc_type, mp_obj_t arg) {
- assert(exc_type->make_new == mp_obj_exception_make_new);
- return mp_obj_exception_make_new(exc_type, 1, 0, &arg);
-}
-
mp_obj_t mp_obj_new_exception_args(const mp_obj_type_t *exc_type, size_t n_args, const mp_obj_t *args) {
assert(exc_type->make_new == mp_obj_exception_make_new);
return mp_obj_exception_make_new(exc_type, n_args, 0, args);
@@ -559,25 +562,15 @@ bool mp_obj_exception_match(mp_obj_t exc, mp_const_obj_t exc_type) {
// traceback handling functions
-#define GET_NATIVE_EXCEPTION(self, self_in) \
- /* make sure self_in is an exception instance */ \
- assert(mp_obj_is_exception_instance(self_in)); \
- mp_obj_exception_t *self; \
- if (mp_obj_is_native_exception_instance(self_in)) { \
- self = MP_OBJ_TO_PTR(self_in); \
- } else { \
- self = MP_OBJ_TO_PTR(((mp_obj_instance_t *)MP_OBJ_TO_PTR(self_in))->subobj[0]); \
- }
-
void mp_obj_exception_clear_traceback(mp_obj_t self_in) {
- GET_NATIVE_EXCEPTION(self, self_in);
+ mp_obj_exception_t *self = get_native_exception(self_in);
// just set the traceback to the null object
// we don't want to call any memory management functions here
self->traceback_data = NULL;
}
void mp_obj_exception_add_traceback(mp_obj_t self_in, qstr file, size_t line, qstr block) {
- GET_NATIVE_EXCEPTION(self, self_in);
+ mp_obj_exception_t *self = get_native_exception(self_in);
// append this traceback info to traceback data
// if memory allocation fails (eg because gc is locked), just return
@@ -630,7 +623,7 @@ void mp_obj_exception_add_traceback(mp_obj_t self_in, qstr file, size_t line, qs
}
void mp_obj_exception_get_traceback(mp_obj_t self_in, size_t *n, size_t **values) {
- GET_NATIVE_EXCEPTION(self, self_in);
+ mp_obj_exception_t *self = get_native_exception(self_in);
if (self->traceback_data == NULL) {
*n = 0;
diff --git a/py/objgenerator.c b/py/objgenerator.c
index 543685fac..784310092 100644
--- a/py/objgenerator.c
+++ b/py/objgenerator.c
@@ -152,8 +152,9 @@ mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_
mp_check_self(mp_obj_is_type(self_in, &mp_type_gen_instance));
mp_obj_gen_instance_t *self = MP_OBJ_TO_PTR(self_in);
if (self->code_state.ip == 0) {
- // Trying to resume already stopped generator
- *ret_val = MP_OBJ_STOP_ITERATION;
+ // Trying to resume an already stopped generator.
+ // This is an optimised "raise StopIteration(None)".
+ *ret_val = mp_const_none;
return MP_VM_RETURN_NORMAL;
}
@@ -212,6 +213,7 @@ mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_
// subsequent next() may re-execute statements after last yield
// again and again, leading to side effects.
self->code_state.ip = 0;
+ // This is an optimised "raise StopIteration(*ret_val)".
*ret_val = *self->code_state.sp;
break;
@@ -236,16 +238,20 @@ mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_
return ret_kind;
}
-STATIC mp_obj_t gen_resume_and_raise(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t throw_value) {
+STATIC mp_obj_t gen_resume_and_raise(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t throw_value, bool raise_stop_iteration) {
mp_obj_t ret;
switch (mp_obj_gen_resume(self_in, send_value, throw_value, &ret)) {
case MP_VM_RETURN_NORMAL:
default:
- // Optimize return w/o value in case generator is used in for loop
- if (ret == mp_const_none || ret == MP_OBJ_STOP_ITERATION) {
- return MP_OBJ_STOP_ITERATION;
+ // A normal return is a StopIteration, either raise it or return
+ // MP_OBJ_STOP_ITERATION as an optimisation.
+ if (ret == mp_const_none) {
+ ret = MP_OBJ_NULL;
+ }
+ if (raise_stop_iteration) {
+ mp_raise_StopIteration(ret);
} else {
- nlr_raise(mp_obj_new_exception_arg1(&mp_type_StopIteration, ret));
+ return mp_make_stop_iteration(ret);
}
case MP_VM_RETURN_YIELD:
@@ -257,16 +263,11 @@ STATIC mp_obj_t gen_resume_and_raise(mp_obj_t self_in, mp_obj_t send_value, mp_o
}
STATIC mp_obj_t gen_instance_iternext(mp_obj_t self_in) {
- return gen_resume_and_raise(self_in, mp_const_none, MP_OBJ_NULL);
+ return gen_resume_and_raise(self_in, mp_const_none, MP_OBJ_NULL, false);
}
STATIC mp_obj_t gen_instance_send(mp_obj_t self_in, mp_obj_t send_value) {
- mp_obj_t ret = gen_resume_and_raise(self_in, send_value, MP_OBJ_NULL);
- if (ret == MP_OBJ_STOP_ITERATION) {
- mp_raise_type(&mp_type_StopIteration);
- } else {
- return ret;
- }
+ return gen_resume_and_raise(self_in, send_value, MP_OBJ_NULL, true);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(gen_instance_send_obj, gen_instance_send);
@@ -288,12 +289,7 @@ STATIC mp_obj_t gen_instance_throw(size_t n_args, const mp_obj_t *args) {
exc = args[2];
}
- mp_obj_t ret = gen_resume_and_raise(args[0], mp_const_none, exc);
- if (ret == MP_OBJ_STOP_ITERATION) {
- mp_raise_type(&mp_type_StopIteration);
- } else {
- return ret;
- }
+ return gen_resume_and_raise(args[0], mp_const_none, exc, true);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(gen_instance_throw_obj, 2, 4, gen_instance_throw);
diff --git a/py/objgetitemiter.c b/py/objgetitemiter.c
index 2670314ab..31ed4a922 100644
--- a/py/objgetitemiter.c
+++ b/py/objgetitemiter.c
@@ -48,7 +48,6 @@ STATIC mp_obj_t it_iternext(mp_obj_t self_in) {
// an exception was raised
mp_obj_type_t *t = (mp_obj_type_t *)((mp_obj_base_t *)nlr.ret_val)->type;
if (t == &mp_type_StopIteration || t == &mp_type_IndexError) {
- // return MP_OBJ_STOP_ITERATION instead of raising
return MP_OBJ_STOP_ITERATION;
} else {
// re-raise exception
diff --git a/py/objlist.c b/py/objlist.c
index 8c989facc..f431e273d 100644
--- a/py/objlist.c
+++ b/py/objlist.c
@@ -44,13 +44,18 @@ STATIC mp_obj_t list_pop(size_t n_args, const mp_obj_t *args);
STATIC void list_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) {
mp_obj_list_t *o = MP_OBJ_TO_PTR(o_in);
+ const char *item_separator = ", ";
if (!(MICROPY_PY_UJSON && kind == PRINT_JSON)) {
kind = PRINT_REPR;
+ } else {
+ #if MICROPY_PY_UJSON_SEPARATORS
+ item_separator = MP_PRINT_GET_EXT(print)->item_separator;
+ #endif
}
mp_print_str(print, "[");
for (size_t i = 0; i < o->len; i++) {
if (i > 0) {
- mp_print_str(print, ", ");
+ mp_print_str(print, item_separator);
}
mp_obj_print_helper(print, o->items[i], kind);
}
diff --git a/py/objset.c b/py/objset.c
index dac9b1138..d2508bfbf 100644
--- a/py/objset.c
+++ b/py/objset.c
@@ -372,7 +372,7 @@ STATIC mp_obj_t set_remove(mp_obj_t self_in, mp_obj_t item) {
check_set(self_in);
mp_obj_set_t *self = MP_OBJ_TO_PTR(self_in);
if (mp_set_lookup(&self->set, item, MP_MAP_LOOKUP_REMOVE_IF_FOUND) == MP_OBJ_NULL) {
- nlr_raise(mp_obj_new_exception_arg1(&mp_type_KeyError, item));
+ mp_raise_type_arg(&mp_type_KeyError, item);
}
return mp_const_none;
}
diff --git a/py/objstr.c b/py/objstr.c
index 98657bd21..7d7f0e1df 100644
--- a/py/objstr.c
+++ b/py/objstr.c
@@ -1081,7 +1081,7 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar
field_name = lookup;
mp_map_elem_t *key_elem = mp_map_lookup(kwargs, field_q, MP_MAP_LOOKUP);
if (key_elem == NULL) {
- nlr_raise(mp_obj_new_exception_arg1(&mp_type_KeyError, field_q));
+ mp_raise_type_arg(&mp_type_KeyError, field_q);
}
arg = key_elem->value;
}
diff --git a/py/objtuple.c b/py/objtuple.c
index 07a560ac0..67d7bc356 100644
--- a/py/objtuple.c
+++ b/py/objtuple.c
@@ -39,15 +39,19 @@
void mp_obj_tuple_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) {
mp_obj_tuple_t *o = MP_OBJ_TO_PTR(o_in);
+ const char *item_separator = ", ";
if (MICROPY_PY_UJSON && kind == PRINT_JSON) {
mp_print_str(print, "[");
+ #if MICROPY_PY_UJSON_SEPARATORS
+ item_separator = MP_PRINT_GET_EXT(print)->item_separator;
+ #endif
} else {
mp_print_str(print, "(");
kind = PRINT_REPR;
}
for (size_t i = 0; i < o->len; i++) {
if (i > 0) {
- mp_print_str(print, ", ");
+ mp_print_str(print, item_separator);
}
mp_obj_print_helper(print, o->items[i], kind);
}
diff --git a/py/parse.c b/py/parse.c
index da2f5e796..ae3fa8ea6 100644
--- a/py/parse.c
+++ b/py/parse.c
@@ -1152,6 +1152,14 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) {
} else if (lex->tok_kind == MP_TOKEN_DEDENT_MISMATCH) {
exc = mp_obj_new_exception_msg(&mp_type_IndentationError,
MP_ERROR_TEXT("unindent doesn't match any outer indent level"));
+ #if MICROPY_PY_FSTRINGS
+ } else if (lex->tok_kind == MP_TOKEN_MALFORMED_FSTRING) {
+ exc = mp_obj_new_exception_msg(&mp_type_SyntaxError,
+ MP_ERROR_TEXT("malformed f-string"));
+ } else if (lex->tok_kind == MP_TOKEN_FSTRING_RAW) {
+ exc = mp_obj_new_exception_msg(&mp_type_SyntaxError,
+ MP_ERROR_TEXT("raw f-strings are not supported"));
+ #endif
} else {
exc = mp_obj_new_exception_msg(&mp_type_SyntaxError,
MP_ERROR_TEXT("invalid syntax"));
diff --git a/py/py.mk b/py/py.mk
index ee3f28685..787cc8ee8 100644
--- a/py/py.mk
+++ b/py/py.mk
@@ -233,6 +233,7 @@ PY_EXTMOD_O_BASENAME = \
extmod/moducryptolib.o \
extmod/modubinascii.o \
extmod/virtpin.o \
+ extmod/machine_bitstream.o \
extmod/machine_mem.o \
extmod/machine_pinbase.o \
extmod/machine_signal.o \
@@ -258,8 +259,8 @@ PY_EXTMOD_O_BASENAME = \
extmod/vfs_lfs.o \
extmod/utime_mphal.o \
extmod/uos_dupterm.o \
- lib/embed/abort_.o \
- lib/utils/printf.o \
+ shared/libc/abort_.o \
+ shared/libc/printf.o \
# prepend the build destination prefix to the py object files
PY_CORE_O = $(addprefix $(BUILD)/, $(PY_CORE_O_BASENAME))
@@ -321,7 +322,7 @@ $(HEADER_BUILD)/moduledefs.h: $(SRC_QSTR) $(QSTR_GLOBAL_DEPENDENCIES) | $(HEADER
# Standard C functions like memset need to be compiled with special flags so
# the compiler does not optimise these functions in terms of themselves.
CFLAGS_BUILTIN ?= -ffreestanding -fno-builtin -fno-lto
-$(BUILD)/lib/libc/string0.o: CFLAGS += $(CFLAGS_BUILTIN)
+$(BUILD)/shared/libc/string0.o: CFLAGS += $(CFLAGS_BUILTIN)
# Force nlr code to always be compiled with space-saving optimisation so
# that the function preludes are of a minimal and predictable form.
diff --git a/py/pystack.c b/py/pystack.c
index f7323fd74..ea5f0d9d1 100644
--- a/py/pystack.c
+++ b/py/pystack.c
@@ -43,8 +43,7 @@ void *mp_pystack_alloc(size_t n_bytes) {
#endif
if (MP_STATE_THREAD(pystack_cur) + n_bytes > MP_STATE_THREAD(pystack_end)) {
// out of memory in the pystack
- nlr_raise(mp_obj_new_exception_arg1(&mp_type_RuntimeError,
- MP_OBJ_NEW_QSTR(MP_QSTR_pystack_space_exhausted)));
+ mp_raise_type_arg(&mp_type_RuntimeError, MP_OBJ_NEW_QSTR(MP_QSTR_pystack_space_exhausted));
}
void *ptr = MP_STATE_THREAD(pystack_cur);
MP_STATE_THREAD(pystack_cur) += n_bytes;
diff --git a/py/runtime.c b/py/runtime.c
index 261670d4f..27e5bc13e 100644
--- a/py/runtime.c
+++ b/py/runtime.c
@@ -284,6 +284,12 @@ mp_obj_t mp_unary_op(mp_unary_op_t op, mp_obj_t arg) {
return result;
}
}
+ if (op == MP_UNARY_OP_BOOL) {
+ // Type doesn't have unary_op (or didn't handle MP_UNARY_OP_BOOL),
+ // so is implicitly True as this code path is impossible to reach
+ // if arg==mp_const_none.
+ return mp_const_true;
+ }
// With MP_UNARY_OP_INT, mp_unary_op() becomes a fallback for mp_obj_get_int().
// In this case provide a more focused error message to not confuse, e.g. chr(1.0)
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
@@ -1217,6 +1223,7 @@ mp_obj_t mp_getiter(mp_obj_t o_in, mp_obj_iter_buf_t *iter_buf) {
mp_obj_t mp_iternext_allow_raise(mp_obj_t o_in) {
const mp_obj_type_t *type = mp_obj_get_type(o_in);
if (type->iternext != NULL) {
+ MP_STATE_THREAD(stop_iteration_arg) = MP_OBJ_NULL;
return type->iternext(o_in);
} else {
// check for __next__ method
@@ -1242,6 +1249,7 @@ mp_obj_t mp_iternext(mp_obj_t o_in) {
MP_STACK_CHECK(); // enumerate, filter, map and zip can recursively call mp_iternext
const mp_obj_type_t *type = mp_obj_get_type(o_in);
if (type->iternext != NULL) {
+ MP_STATE_THREAD(stop_iteration_arg) = MP_OBJ_NULL;
return type->iternext(o_in);
} else {
// check for __next__ method
@@ -1256,7 +1264,7 @@ mp_obj_t mp_iternext(mp_obj_t o_in) {
return ret;
} else {
if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(((mp_obj_base_t *)nlr.ret_val)->type), MP_OBJ_FROM_PTR(&mp_type_StopIteration))) {
- return MP_OBJ_STOP_ITERATION;
+ return mp_make_stop_iteration(mp_obj_exception_get_value(MP_OBJ_FROM_PTR(nlr.ret_val)));
} else {
nlr_jump(nlr.ret_val);
}
@@ -1272,7 +1280,6 @@ mp_obj_t mp_iternext(mp_obj_t o_in) {
}
}
-// TODO: Unclear what to do with StopIterarion exception here.
mp_vm_return_kind_t mp_resume(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t throw_value, mp_obj_t *ret_val) {
assert((send_value != MP_OBJ_NULL) ^ (throw_value != MP_OBJ_NULL));
const mp_obj_type_t *type = mp_obj_get_type(self_in);
@@ -1282,13 +1289,18 @@ mp_vm_return_kind_t mp_resume(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t th
}
if (type->iternext != NULL && send_value == mp_const_none) {
+ MP_STATE_THREAD(stop_iteration_arg) = MP_OBJ_NULL;
mp_obj_t ret = type->iternext(self_in);
*ret_val = ret;
if (ret != MP_OBJ_STOP_ITERATION) {
return MP_VM_RETURN_YIELD;
} else {
- // Emulate raise StopIteration()
- // Special case, handled in vm.c
+ // The generator is finished.
+ // This is an optimised "raise StopIteration(*ret_val)".
+ *ret_val = MP_STATE_THREAD(stop_iteration_arg);
+ if (*ret_val == MP_OBJ_NULL) {
+ *ret_val = mp_const_none;
+ }
return MP_VM_RETURN_NORMAL;
}
}
@@ -1559,13 +1571,24 @@ NORETURN void mp_raise_NotImplementedError(mp_rom_error_text_t msg) {
#endif
+NORETURN void mp_raise_type_arg(const mp_obj_type_t *exc_type, mp_obj_t arg) {
+ nlr_raise(mp_obj_new_exception_arg1(exc_type, arg));
+}
+
+NORETURN void mp_raise_StopIteration(mp_obj_t arg) {
+ if (arg == MP_OBJ_NULL) {
+ mp_raise_type(&mp_type_StopIteration);
+ } else {
+ mp_raise_type_arg(&mp_type_StopIteration, arg);
+ }
+}
+
NORETURN void mp_raise_OSError(int errno_) {
- nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(errno_)));
+ mp_raise_type_arg(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(errno_));
}
#if MICROPY_STACK_CHECK || MICROPY_ENABLE_PYSTACK
NORETURN void mp_raise_recursion_depth(void) {
- nlr_raise(mp_obj_new_exception_arg1(&mp_type_RuntimeError,
- MP_OBJ_NEW_QSTR(MP_QSTR_maximum_space_recursion_space_depth_space_exceeded)));
+ mp_raise_type_arg(&mp_type_RuntimeError, MP_OBJ_NEW_QSTR(MP_QSTR_maximum_space_recursion_space_depth_space_exceeded));
}
#endif
diff --git a/py/runtime.h b/py/runtime.h
index 7d2cb94e8..f0d41f38d 100644
--- a/py/runtime.h
+++ b/py/runtime.h
@@ -154,6 +154,11 @@ mp_obj_t mp_iternext_allow_raise(mp_obj_t o); // may return MP_OBJ_STOP_ITERATIO
mp_obj_t mp_iternext(mp_obj_t o); // will always return MP_OBJ_STOP_ITERATION instead of raising StopIteration(...)
mp_vm_return_kind_t mp_resume(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t throw_value, mp_obj_t *ret_val);
+static inline mp_obj_t mp_make_stop_iteration(mp_obj_t o) {
+ MP_STATE_THREAD(stop_iteration_arg) = o;
+ return MP_OBJ_STOP_ITERATION;
+}
+
mp_obj_t mp_make_raise_obj(mp_obj_t o);
mp_obj_t mp_import_name(qstr name, mp_obj_t fromlist, mp_obj_t level);
@@ -179,6 +184,8 @@ NORETURN void mp_raise_TypeError(mp_rom_error_text_t msg);
NORETURN void mp_raise_NotImplementedError(mp_rom_error_text_t msg);
#endif
+NORETURN void mp_raise_type_arg(const mp_obj_type_t *exc_type, mp_obj_t arg);
+NORETURN void mp_raise_StopIteration(mp_obj_t arg);
NORETURN void mp_raise_OSError(int errno_);
NORETURN void mp_raise_recursion_depth(void);
diff --git a/py/vm.c b/py/vm.c
index 5365014fc..bbfc9914e 100644
--- a/py/vm.c
+++ b/py/vm.c
@@ -1257,16 +1257,9 @@ yield:
PUSH(ret_value);
goto yield;
} else if (ret_kind == MP_VM_RETURN_NORMAL) {
- // Pop exhausted gen
- sp--;
- if (ret_value == MP_OBJ_STOP_ITERATION) {
- // Optimize StopIteration
- // TODO: get StopIteration's value
- PUSH(mp_const_none);
- } else {
- PUSH(ret_value);
- }
-
+ // The generator has finished, and returned a value via StopIteration
+ // Replace exhausted generator with the returned value
+ SET_TOP(ret_value);
// If we injected GeneratorExit downstream, then even
// if it was swallowed, we re-raise GeneratorExit
GENERATOR_EXIT_IF_NEEDED(t_exc);
diff --git a/shared/README.md b/shared/README.md
new file mode 100644
index 000000000..073187b24
--- /dev/null
+++ b/shared/README.md
@@ -0,0 +1,3 @@
+This directory contains libraries, utilities and helper code developed
+specifically for this project. The code is intended to be portable and
+usable by any port.
diff --git a/lib/embed/__errno.c b/shared/libc/__errno.c
similarity index 100%
rename from lib/embed/__errno.c
rename to shared/libc/__errno.c
diff --git a/lib/embed/abort_.c b/shared/libc/abort_.c
similarity index 100%
rename from lib/embed/abort_.c
rename to shared/libc/abort_.c
diff --git a/lib/utils/printf.c b/shared/libc/printf.c
similarity index 100%
rename from lib/utils/printf.c
rename to shared/libc/printf.c
diff --git a/lib/libc/string0.c b/shared/libc/string0.c
similarity index 100%
rename from lib/libc/string0.c
rename to shared/libc/string0.c
diff --git a/lib/memzip/README.md b/shared/memzip/README.md
similarity index 84%
rename from lib/memzip/README.md
rename to shared/memzip/README.md
index 287d0fc48..3938e3198 100644
--- a/lib/memzip/README.md
+++ b/shared/memzip/README.md
@@ -10,13 +10,13 @@ a C file which contains the data from the zip file.
A typical addition to a makefile would look like:
```
SRC_C += \
- lib/memzip/import.c \
- lib/memzip/lexermemzip.c \
- lib/memzip/memzip.c \
+ shared/memzip/import.c \
+ shared/memzip/lexermemzip.c \
+ shared/memzip/memzip.c \
OBJ += $(BUILD)/memzip-files.o
-MAKE_MEMZIP = ../lib/memzip/make-memzip.py
+MAKE_MEMZIP = ../shared/memzip/make-memzip.py
$(BUILD)/memzip-files.o: $(BUILD)/memzip-files.c
$(call compile_c)
diff --git a/lib/memzip/import.c b/shared/memzip/import.c
similarity index 100%
rename from lib/memzip/import.c
rename to shared/memzip/import.c
diff --git a/lib/memzip/lexermemzip.c b/shared/memzip/lexermemzip.c
similarity index 100%
rename from lib/memzip/lexermemzip.c
rename to shared/memzip/lexermemzip.c
diff --git a/lib/memzip/make-memzip.py b/shared/memzip/make-memzip.py
similarity index 100%
rename from lib/memzip/make-memzip.py
rename to shared/memzip/make-memzip.py
diff --git a/lib/memzip/memzip.c b/shared/memzip/memzip.c
similarity index 100%
rename from lib/memzip/memzip.c
rename to shared/memzip/memzip.c
diff --git a/lib/memzip/memzip.h b/shared/memzip/memzip.h
similarity index 100%
rename from lib/memzip/memzip.h
rename to shared/memzip/memzip.h
diff --git a/lib/netutils/dhcpserver.c b/shared/netutils/dhcpserver.c
similarity index 99%
rename from lib/netutils/dhcpserver.c
rename to shared/netutils/dhcpserver.c
index 7f97ee6e4..9db42b3fd 100644
--- a/lib/netutils/dhcpserver.c
+++ b/shared/netutils/dhcpserver.c
@@ -35,7 +35,7 @@
#if MICROPY_PY_LWIP
-#include "lib/netutils/dhcpserver.h"
+#include "shared/netutils/dhcpserver.h"
#include "lwip/udp.h"
#define DHCPDISCOVER (1)
diff --git a/lib/netutils/dhcpserver.h b/shared/netutils/dhcpserver.h
similarity index 100%
rename from lib/netutils/dhcpserver.h
rename to shared/netutils/dhcpserver.h
diff --git a/lib/netutils/netutils.c b/shared/netutils/netutils.c
similarity index 98%
rename from lib/netutils/netutils.c
rename to shared/netutils/netutils.c
index 40fbd5bca..84b4405c4 100644
--- a/lib/netutils/netutils.c
+++ b/shared/netutils/netutils.c
@@ -30,7 +30,7 @@
#include
#include "py/runtime.h"
-#include "lib/netutils/netutils.h"
+#include "shared/netutils/netutils.h"
// Takes an array with a raw IPv4 address and returns something like '192.168.0.1'.
mp_obj_t netutils_format_ipv4_addr(uint8_t *ip, netutils_endian_t endian) {
diff --git a/lib/netutils/netutils.h b/shared/netutils/netutils.h
similarity index 100%
rename from lib/netutils/netutils.h
rename to shared/netutils/netutils.h
diff --git a/lib/netutils/trace.c b/shared/netutils/trace.c
similarity index 99%
rename from lib/netutils/trace.c
rename to shared/netutils/trace.c
index 1610966c2..a6dfb42c2 100644
--- a/lib/netutils/trace.c
+++ b/shared/netutils/trace.c
@@ -25,7 +25,7 @@
*/
#include "py/mphal.h"
-#include "lib/netutils/netutils.h"
+#include "shared/netutils/netutils.h"
static uint32_t get_be16(const uint8_t *buf) {
return buf[0] << 8 | buf[1];
diff --git a/lib/mp-readline/readline.c b/shared/readline/readline.c
similarity index 99%
rename from lib/mp-readline/readline.c
rename to shared/readline/readline.c
index 296c8aa4a..cad85b4e6 100644
--- a/lib/mp-readline/readline.c
+++ b/shared/readline/readline.c
@@ -31,7 +31,7 @@
#include "py/mpstate.h"
#include "py/repl.h"
#include "py/mphal.h"
-#include "lib/mp-readline/readline.h"
+#include "shared/readline/readline.h"
#if 0 // print debugging info
#define DEBUG_PRINT (1)
diff --git a/lib/mp-readline/readline.h b/shared/readline/readline.h
similarity index 100%
rename from lib/mp-readline/readline.h
rename to shared/readline/readline.h
diff --git a/lib/utils/gchelper.h b/shared/runtime/gchelper.h
similarity index 100%
rename from lib/utils/gchelper.h
rename to shared/runtime/gchelper.h
diff --git a/lib/utils/gchelper_generic.c b/shared/runtime/gchelper_generic.c
similarity index 99%
rename from lib/utils/gchelper_generic.c
rename to shared/runtime/gchelper_generic.c
index 3e7e33ab1..dcd35f9c7 100644
--- a/lib/utils/gchelper_generic.c
+++ b/shared/runtime/gchelper_generic.c
@@ -28,7 +28,7 @@
#include "py/mpstate.h"
#include "py/gc.h"
-#include "lib/utils/gchelper.h"
+#include "shared/runtime/gchelper.h"
#if MICROPY_ENABLE_GC
diff --git a/lib/utils/gchelper_m0.s b/shared/runtime/gchelper_m0.s
similarity index 100%
rename from lib/utils/gchelper_m0.s
rename to shared/runtime/gchelper_m0.s
diff --git a/lib/utils/gchelper_m3.s b/shared/runtime/gchelper_m3.s
similarity index 100%
rename from lib/utils/gchelper_m3.s
rename to shared/runtime/gchelper_m3.s
diff --git a/lib/utils/gchelper_native.c b/shared/runtime/gchelper_native.c
similarity index 97%
rename from lib/utils/gchelper_native.c
rename to shared/runtime/gchelper_native.c
index 6bf386b51..1e4af9c84 100644
--- a/lib/utils/gchelper_native.c
+++ b/shared/runtime/gchelper_native.c
@@ -28,7 +28,7 @@
#include "py/mpstate.h"
#include "py/gc.h"
-#include "lib/utils/gchelper.h"
+#include "shared/runtime/gchelper.h"
#if MICROPY_ENABLE_GC
diff --git a/lib/utils/interrupt_char.c b/shared/runtime/interrupt_char.c
similarity index 100%
rename from lib/utils/interrupt_char.c
rename to shared/runtime/interrupt_char.c
diff --git a/lib/utils/interrupt_char.h b/shared/runtime/interrupt_char.h
similarity index 100%
rename from lib/utils/interrupt_char.h
rename to shared/runtime/interrupt_char.h
diff --git a/lib/utils/mpirq.c b/shared/runtime/mpirq.c
similarity index 99%
rename from lib/utils/mpirq.c
rename to shared/runtime/mpirq.c
index 02139f24d..8e474bf5a 100644
--- a/lib/utils/mpirq.c
+++ b/shared/runtime/mpirq.c
@@ -29,7 +29,7 @@
#include "py/runtime.h"
#include "py/gc.h"
-#include "lib/utils/mpirq.h"
+#include "shared/runtime/mpirq.h"
#if MICROPY_ENABLE_SCHEDULER
diff --git a/lib/utils/mpirq.h b/shared/runtime/mpirq.h
similarity index 100%
rename from lib/utils/mpirq.h
rename to shared/runtime/mpirq.h
diff --git a/lib/utils/pyexec.c b/shared/runtime/pyexec.c
similarity index 99%
rename from lib/utils/pyexec.c
rename to shared/runtime/pyexec.c
index 4446b36b6..006ec096f 100644
--- a/lib/utils/pyexec.c
+++ b/shared/runtime/pyexec.c
@@ -39,8 +39,8 @@
#include "irq.h"
#include "usb.h"
#endif
-#include "lib/mp-readline/readline.h"
-#include "lib/utils/pyexec.h"
+#include "shared/readline/readline.h"
+#include "shared/runtime/pyexec.h"
#include "genhdr/mpversion.h"
pyexec_mode_kind_t pyexec_mode_kind = PYEXEC_MODE_FRIENDLY_REPL;
diff --git a/lib/utils/pyexec.h b/shared/runtime/pyexec.h
similarity index 100%
rename from lib/utils/pyexec.h
rename to shared/runtime/pyexec.h
diff --git a/lib/utils/semihosting.c b/shared/runtime/semihosting.c
similarity index 100%
rename from lib/utils/semihosting.c
rename to shared/runtime/semihosting.c
diff --git a/lib/utils/semihosting.h b/shared/runtime/semihosting.h
similarity index 100%
rename from lib/utils/semihosting.h
rename to shared/runtime/semihosting.h
diff --git a/shared/runtime/stdout_helpers.c b/shared/runtime/stdout_helpers.c
new file mode 100644
index 000000000..6a24cc2eb
--- /dev/null
+++ b/shared/runtime/stdout_helpers.c
@@ -0,0 +1,62 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 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"
+
+/*
+ * Extra stdout functions
+ * These can be either optimized for a particular port, or reference
+ * implementation below can be used.
+ */
+
+// Send "cooked" string of given length, where every occurrence of
+// LF character is replaced with CR LF ("\n" is converted to "\r\n").
+// This is an optimised version to reduce the number of calls made
+// to mp_hal_stdout_tx_strn.
+void mp_hal_stdout_tx_strn_cooked(const char *str, size_t len) {
+ const char *last = str;
+ while (len--) {
+ if (*str == '\n') {
+ if (str > last) {
+ mp_hal_stdout_tx_strn(last, str - last);
+ }
+ mp_hal_stdout_tx_strn("\r\n", 2);
+ ++str;
+ last = str;
+ } else {
+ ++str;
+ }
+ }
+ if (str > last) {
+ mp_hal_stdout_tx_strn(last, str - last);
+ }
+}
+
+// Send zero-terminated string
+void mp_hal_stdout_tx_str(const char *str) {
+ mp_hal_stdout_tx_strn(str, strlen(str));
+}
diff --git a/lib/utils/sys_stdio_mphal.c b/shared/runtime/sys_stdio_mphal.c
similarity index 100%
rename from lib/utils/sys_stdio_mphal.c
rename to shared/runtime/sys_stdio_mphal.c
diff --git a/lib/timeutils/timeutils.c b/shared/timeutils/timeutils.c
similarity index 99%
rename from lib/timeutils/timeutils.c
rename to shared/timeutils/timeutils.c
index 7c74f5fc3..6bf3eca84 100644
--- a/lib/timeutils/timeutils.c
+++ b/shared/timeutils/timeutils.c
@@ -27,7 +27,7 @@
#include "py/obj.h"
-#include "lib/timeutils/timeutils.h"
+#include "shared/timeutils/timeutils.h"
// LEAPOCH corresponds to 2000-03-01, which is a mod-400 year, immediately
// after Feb 29. We calculate seconds as a signed integer relative to that.
diff --git a/lib/timeutils/timeutils.h b/shared/timeutils/timeutils.h
similarity index 100%
rename from lib/timeutils/timeutils.h
rename to shared/timeutils/timeutils.h
diff --git a/lib/upytesthelper/upytesthelper.c b/shared/upytesthelper/upytesthelper.c
similarity index 100%
rename from lib/upytesthelper/upytesthelper.c
rename to shared/upytesthelper/upytesthelper.c
diff --git a/lib/upytesthelper/upytesthelper.h b/shared/upytesthelper/upytesthelper.h
similarity index 100%
rename from lib/upytesthelper/upytesthelper.h
rename to shared/upytesthelper/upytesthelper.h
diff --git a/tests/basics/gen_yield_from_stopped.py b/tests/basics/gen_yield_from_stopped.py
index 468679b61..82feefed0 100644
--- a/tests/basics/gen_yield_from_stopped.py
+++ b/tests/basics/gen_yield_from_stopped.py
@@ -16,3 +16,15 @@ try:
next(run())
except StopIteration:
print("StopIteration")
+
+
+# Where "f" is a native generator
+def run():
+ print((yield from f))
+
+
+f = zip()
+try:
+ next(run())
+except StopIteration:
+ print("StopIteration")
diff --git a/tests/basics/stopiteration.py b/tests/basics/stopiteration.py
new file mode 100644
index 000000000..d4719c9bc
--- /dev/null
+++ b/tests/basics/stopiteration.py
@@ -0,0 +1,63 @@
+# test StopIteration interaction with generators
+
+try:
+ enumerate, exec
+except:
+ print("SKIP")
+ raise SystemExit
+
+
+def get_stop_iter_arg(msg, code):
+ try:
+ exec(code)
+ print("FAIL")
+ except StopIteration as er:
+ print(msg, er.args)
+
+
+class A:
+ def __iter__(self):
+ return self
+
+ def __next__(self):
+ raise StopIteration(42)
+
+
+class B:
+ def __getitem__(self, index):
+ # argument to StopIteration should get ignored
+ raise StopIteration(42)
+
+
+def gen(x):
+ return x
+ yield
+
+
+def gen2(x):
+ try:
+ yield
+ except ValueError:
+ pass
+ return x
+
+
+get_stop_iter_arg("next", "next(A())")
+get_stop_iter_arg("iter", "next(iter(B()))")
+get_stop_iter_arg("enumerate", "next(enumerate(A()))")
+get_stop_iter_arg("map", "next(map(lambda x:x, A()))")
+get_stop_iter_arg("zip", "next(zip(A()))")
+g = gen(None)
+get_stop_iter_arg("generator0", "next(g)")
+get_stop_iter_arg("generator1", "next(g)")
+g = gen(42)
+get_stop_iter_arg("generator0", "next(g)")
+get_stop_iter_arg("generator1", "next(g)")
+get_stop_iter_arg("send", "gen(None).send(None)")
+get_stop_iter_arg("send", "gen(42).send(None)")
+g = gen2(None)
+next(g)
+get_stop_iter_arg("throw", "g.throw(ValueError)")
+g = gen2(42)
+next(g)
+get_stop_iter_arg("throw", "g.throw(ValueError)")
diff --git a/tests/basics/string_fstring.py b/tests/basics/string_fstring.py
new file mode 100644
index 000000000..4f7225fca
--- /dev/null
+++ b/tests/basics/string_fstring.py
@@ -0,0 +1,51 @@
+def f():
+ return 4
+def g(_):
+ return 5
+def h():
+ return 6
+
+print(f'no interpolation')
+print(f"no interpolation")
+print(f"""no interpolation""")
+
+x, y = 1, 2
+print(f'{x}')
+print(f'{x:08x}')
+print(f'a {x} b {y} c')
+print(f'a {x:08x} b {y} c')
+
+print(f'a {"hello"} b')
+print(f'a {f() + g("foo") + h()} b')
+
+def foo(a, b):
+ return f'{x}{y}{a}{b}'
+print(foo(7, 8))
+
+# PEP-0498 specifies that '\\' and '#' must be disallowed explicitly, whereas
+# MicroPython relies on the syntax error as a result of the substitution.
+
+print(f"\\")
+print(f'#')
+try:
+ eval("f'{\}'")
+except SyntaxError:
+ print('SyntaxError')
+try:
+ eval("f'{#}'")
+except SyntaxError:
+ print('SyntaxError')
+
+
+# PEP-0498 specifies that handling of double braces '{{' or '}}' should
+# behave like str.format.
+print(f'{{}}')
+print(f'{{{4*10}}}', '{40}')
+
+# A single closing brace, unlike str.format should raise a syntax error.
+# MicroPython instead raises ValueError at runtime from the substitution.
+try:
+ eval("f'{{}'")
+except (ValueError, SyntaxError):
+ # MicroPython incorrectly raises ValueError here.
+ print('SyntaxError')
diff --git a/tests/basics/string_fstring_debug.py b/tests/basics/string_fstring_debug.py
new file mode 100644
index 000000000..76a448ca0
--- /dev/null
+++ b/tests/basics/string_fstring_debug.py
@@ -0,0 +1,23 @@
+# test f-string debug feature {x=}
+
+
+def f():
+ return 4
+
+
+def g(_):
+ return 5
+
+
+def h():
+ return 6
+
+
+x, y = 1, 2
+print(f"{x=}")
+print(f"{x=:08x}")
+print(f"a {x=} b {y} c")
+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')
diff --git a/tests/basics/string_fstring_debug.py.exp b/tests/basics/string_fstring_debug.py.exp
new file mode 100644
index 000000000..563030f40
--- /dev/null
+++ b/tests/basics/string_fstring_debug.py.exp
@@ -0,0 +1,6 @@
+x=1
+x=00000001
+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
diff --git a/tests/basics/subclass_native3.py b/tests/basics/subclass_native3.py
index ac5aabfed..0c45c4924 100644
--- a/tests/basics/subclass_native3.py
+++ b/tests/basics/subclass_native3.py
@@ -34,6 +34,26 @@ print(MyStopIteration().value)
print(MyStopIteration(1).value)
+class Iter:
+ def __iter__(self):
+ return self
+
+ def __next__(self):
+ # This exception will stop the "yield from", with a value of 3
+ raise MyStopIteration(3)
+
+
+def gen():
+ print((yield from Iter()))
+ return 4
+
+
+try:
+ next(gen())
+except StopIteration as er:
+ print(er.args)
+
+
class MyOSError(OSError):
pass
diff --git a/tests/basics/unary_op.py b/tests/basics/unary_op.py
index bd78a20d0..2239e2b20 100644
--- a/tests/basics/unary_op.py
+++ b/tests/basics/unary_op.py
@@ -23,5 +23,12 @@ print(not A())
# check user instances derived from builtins
class B(int): pass
print(not B())
+print(True if B() else False)
class C(list): pass
print(not C())
+print(True if C() else False)
+# type doesn't define unary_op
+class D(type): pass
+d = D("foo", (), {})
+print(not d)
+print(True if d else False)
diff --git a/tests/cmdline/cmd_parsetree.py b/tests/cmdline/cmd_parsetree.py
index 50da36954..483ea8937 100644
--- a/tests/cmdline/cmd_parsetree.py
+++ b/tests/cmdline/cmd_parsetree.py
@@ -10,3 +10,4 @@ d = b"bytes"
e = b"a very long bytes that will not be interned"
f = 123456789012345678901234567890
g = 123
+h = f"fstring: '{b}'"
diff --git a/tests/cmdline/cmd_parsetree.py.exp b/tests/cmdline/cmd_parsetree.py.exp
index e64f4f782..cc8ba82c0 100644
--- a/tests/cmdline/cmd_parsetree.py.exp
+++ b/tests/cmdline/cmd_parsetree.py.exp
@@ -1,6 +1,6 @@
----------------
-[ 4] \(rule\|file_input_2\)(1) (n=9)
- tok(4)
+[ 4] \(rule\|file_input_2\)(1) (n=10)
+ tok(6)
[ 4] \(rule\|for_stmt\)(22) (n=4)
id(i)
[ 4] \(rule\|atom_paren\)(45) (n=1)
@@ -9,7 +9,7 @@
NULL
[ 6] \(rule\|expr_stmt\)(5) (n=2)
id(a)
- tok(14)
+ tok(16)
[ 7] \(rule\|expr_stmt\)(5) (n=2)
id(b)
str(str)
@@ -28,6 +28,16 @@
[ 12] \(rule\|expr_stmt\)(5) (n=2)
id(g)
int(123)
+[ 13] \(rule\|expr_stmt\)(5) (n=2)
+ id(h)
+[ 13] \(rule\|atom_expr_normal\)(44) (n=2)
+[ 13] literal const(\.\+)
+[ 13] \(rule\|atom_expr_trailers\)(142) (n=2)
+[ 13] \(rule\|trailer_period\)(50) (n=1)
+ id(format)
+[ 13] \(rule\|trailer_paren\)(48) (n=1)
+[ 13] \(rule\|arglist\)(164) (n=1)
+ id(b)
----------------
File cmdline/cmd_parsetree.py, code block '' (descriptor: \.\+, bytecode @\.\+ bytes)
Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+):
@@ -46,6 +56,7 @@ arg names:
bc=32 line=10
bc=37 line=11
bc=42 line=12
+ bc=48 line=13
00 BUILD_TUPLE 0
02 GET_ITER_STACK
03 FOR_ITER 12
@@ -65,8 +76,13 @@ arg names:
39 STORE_NAME f
42 LOAD_CONST_SMALL_INT 123
45 STORE_NAME g
-48 LOAD_CONST_NONE
-49 RETURN_VALUE
+48 LOAD_CONST_OBJ \.\+
+50 LOAD_METHOD format
+53 LOAD_NAME b (cache=0)
+57 CALL_METHOD n=1 nkw=0
+59 STORE_NAME h
+62 LOAD_CONST_NONE
+63 RETURN_VALUE
mem: total=\\d\+, current=\\d\+, peak=\\d\+
stack: \\d\+ out of \\d\+
GC: total: \\d\+, used: \\d\+, free: \\d\+
diff --git a/tests/cpydiff/core_fstring_concat.py b/tests/cpydiff/core_fstring_concat.py
new file mode 100644
index 000000000..fd83527b5
--- /dev/null
+++ b/tests/cpydiff/core_fstring_concat.py
@@ -0,0 +1,12 @@
+"""
+categories: Core
+description: f-strings don't support concatenation with adjacent literals if the adjacent literals contain braces
+cause: MicroPython is optimised for code space.
+workaround: Use the + operator between literal strings when either is an f-string
+"""
+
+x = 1
+print("aa" f"{x}")
+print(f"{x}" "ab")
+print("a{}a" f"{x}")
+print(f"{x}" "a{}b")
diff --git a/tests/cpydiff/core_fstring_parser.py b/tests/cpydiff/core_fstring_parser.py
new file mode 100644
index 000000000..6917f3cfa
--- /dev/null
+++ b/tests/cpydiff/core_fstring_parser.py
@@ -0,0 +1,9 @@
+"""
+categories: Core
+description: f-strings cannot support expressions that require parsing to resolve nested braces
+cause: MicroPython is optimised for code space.
+workaround: Only use simple expressions inside f-strings
+"""
+
+f'{"hello {} world"}'
+f"{repr({})}"
diff --git a/tests/cpydiff/core_fstring_raw.py b/tests/cpydiff/core_fstring_raw.py
new file mode 100644
index 000000000..84e265f70
--- /dev/null
+++ b/tests/cpydiff/core_fstring_raw.py
@@ -0,0 +1,8 @@
+"""
+categories: Core
+description: Raw f-strings are not supported
+cause: MicroPython is optimised for code space.
+workaround: Unknown
+"""
+
+rf"hello"
diff --git a/tests/cpydiff/core_fstring_repr.py b/tests/cpydiff/core_fstring_repr.py
new file mode 100644
index 000000000..fcadcbf1b
--- /dev/null
+++ b/tests/cpydiff/core_fstring_repr.py
@@ -0,0 +1,18 @@
+"""
+categories: Core
+description: f-strings don't support the !r, !s, and !a conversions
+cause: MicroPython is optimised for code space.
+workaround: Use repr(), str(), and ascii() explictly.
+"""
+
+
+class X:
+ def __repr__(self):
+ return "repr"
+
+ def __str__(self):
+ return "str"
+
+
+print(f"{X()!r}")
+print(f"{X()!s}")
diff --git a/tests/cpydiff/modules_struct_whitespace_in_format.py b/tests/cpydiff/modules_struct_whitespace_in_format.py
new file mode 100644
index 000000000..a882b3856
--- /dev/null
+++ b/tests/cpydiff/modules_struct_whitespace_in_format.py
@@ -0,0 +1,13 @@
+"""
+categories: Modules,struct
+description: Struct pack with whitespace in format, whitespace ignored by CPython, error on uPy
+cause: MicroPython is optimised for code size.
+workaround: Don't use spaces in format strings.
+"""
+import struct
+
+try:
+ print(struct.pack("b b", 1, 2))
+ print("Should have worked")
+except:
+ print("struct.error")
diff --git a/tests/extmod/framebuf_palette.py b/tests/extmod/framebuf_palette.py
new file mode 100644
index 000000000..84db834c1
--- /dev/null
+++ b/tests/extmod/framebuf_palette.py
@@ -0,0 +1,35 @@
+# Test blit between different color spaces
+try:
+ import framebuf, usys
+except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+# Monochrome glyph/icon
+w = 8
+h = 8
+cbuf = bytearray(w * h // 8)
+fbc = framebuf.FrameBuffer(cbuf, w, h, framebuf.MONO_HLSB)
+fbc.line(0, 0, 7, 7, 1)
+
+# RGB565 destination
+wd = 16
+hd = 16
+dest = bytearray(wd * hd * 2)
+fbd = framebuf.FrameBuffer(dest, wd, hd, framebuf.RGB565)
+
+wp = 2
+bg = 0x1234
+fg = 0xF800
+pal = bytearray(wp * 2)
+palette = framebuf.FrameBuffer(pal, wp, 1, framebuf.RGB565)
+palette.pixel(0, 0, bg)
+palette.pixel(1, 0, fg)
+
+fbd.blit(fbc, 0, 0, -1, palette)
+
+print(fbd.pixel(0, 0) == fg)
+print(fbd.pixel(7, 7) == fg)
+print(fbd.pixel(8, 8) == 0) # Ouside blit
+print(fbd.pixel(0, 1) == bg)
+print(fbd.pixel(1, 0) == bg)
diff --git a/tests/extmod/framebuf_palette.py.exp b/tests/extmod/framebuf_palette.py.exp
new file mode 100644
index 000000000..2e883c51d
--- /dev/null
+++ b/tests/extmod/framebuf_palette.py.exp
@@ -0,0 +1,5 @@
+True
+True
+True
+True
+True
diff --git a/tests/extmod/ujson_dump_separators.py b/tests/extmod/ujson_dump_separators.py
new file mode 100644
index 000000000..e19b99a26
--- /dev/null
+++ b/tests/extmod/ujson_dump_separators.py
@@ -0,0 +1,62 @@
+try:
+ from uio import StringIO
+ import ujson as json
+except:
+ try:
+ from io import StringIO
+ import json
+ except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+for sep in [
+ None,
+ (", ", ": "),
+ (",", ": "),
+ (",", ":"),
+ [", ", ": "],
+ [",", ": "],
+ [",", ":"],
+]:
+ s = StringIO()
+ json.dump(False, s, separators=sep)
+ print(s.getvalue())
+
+ s = StringIO()
+ json.dump({"a": (2, [3, None])}, s, separators=sep)
+ print(s.getvalue())
+
+ # dump to a small-int not allowed
+ try:
+ json.dump(123, 1, separators=sep)
+ except (AttributeError, OSError): # CPython and uPy have different errors
+ print("Exception")
+
+ # dump to an object not allowed
+ try:
+ json.dump(123, {}, separators=sep)
+ except (AttributeError, OSError): # CPython and uPy have different errors
+ print("Exception")
+
+
+try:
+ s = StringIO()
+ json.dump(False, s, separators={"a": 1})
+except (TypeError, ValueError): # CPython and uPy have different errors
+ print("Exception")
+
+# invalid separator types
+for sep in [1, object()]:
+ try:
+ s = StringIO()
+ json.dump(False, s, separators=sep)
+ except TypeError:
+ print("Exception")
+
+# too many/ not enough separators
+for sep in [(), (",", ":", "?"), (",",), []]:
+ try:
+ s = StringIO()
+ json.dump(False, s, separators=sep)
+ except ValueError:
+ print("Exception")
diff --git a/tests/extmod/ujson_dumps_separators.py b/tests/extmod/ujson_dumps_separators.py
new file mode 100644
index 000000000..efb541fe8
--- /dev/null
+++ b/tests/extmod/ujson_dumps_separators.py
@@ -0,0 +1,60 @@
+try:
+ import ujson as json
+except ImportError:
+ try:
+ import json
+ except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+for sep in [
+ None,
+ (", ", ": "),
+ (",", ": "),
+ (",", ":"),
+ [", ", ": "],
+ [",", ": "],
+ [",", ":"],
+]:
+ print(json.dumps(False, separators=sep))
+ print(json.dumps(True, separators=sep))
+ print(json.dumps(None, separators=sep))
+ print(json.dumps(1, separators=sep))
+ print(json.dumps("abc", separators=sep))
+ print(json.dumps("\x00\x01\x7e", separators=sep))
+ print(json.dumps([], separators=sep))
+ print(json.dumps([1], separators=sep))
+ print(json.dumps([1, 2], separators=sep))
+ print(json.dumps([1, True], separators=sep))
+ print(json.dumps((), separators=sep))
+ print(json.dumps((1,), separators=sep))
+ print(json.dumps((1, 2), separators=sep))
+ print(json.dumps((1, (2, 3)), separators=sep))
+ print(json.dumps({}, separators=sep))
+ print(json.dumps({"a": 1}, separators=sep))
+ print(json.dumps({"a": (2, [3, None])}, separators=sep))
+ print(json.dumps('"quoted"', separators=sep))
+ print(json.dumps("space\n\r\tspace", separators=sep))
+ print(json.dumps({None: -1}, separators=sep))
+ print(json.dumps({False: 0}, separators=sep))
+ print(json.dumps({True: 1}, separators=sep))
+ print(json.dumps({1: 2}, separators=sep))
+
+try:
+ json.dumps(False, separators={"a": 1})
+except (TypeError, ValueError): # CPython and uPy have different errors
+ print("Exception")
+
+# invalid separator types
+for sep in [1, object()]:
+ try:
+ json.dumps(False, separators=sep)
+ except TypeError:
+ print("Exception")
+
+# too many/ not enough separators
+for sep in [(), (",", ":", "?"), (",",), []]:
+ try:
+ json.dumps(False, separators=sep)
+ except ValueError:
+ print("Exception")
diff --git a/tests/extmod/vfs_fat_finaliser.py b/tests/extmod/vfs_fat_finaliser.py
index e30f42f84..b67afc2d9 100644
--- a/tests/extmod/vfs_fat_finaliser.py
+++ b/tests/extmod/vfs_fat_finaliser.py
@@ -56,6 +56,13 @@ micropython.heap_unlock()
# Here we test that the finaliser is actually called during a garbage collection.
import gc
+# Do a large number of single-block allocations to move the GC head forwards,
+# ensuring that the files are allocated from never-before-used blocks and
+# therefore couldn't possibly have any references to them left behind on
+# the stack.
+for i in range(1024):
+ []
+
N = 4
for i in range(N):
n = "x%d" % i
diff --git a/tests/feature_check/fstring.py b/tests/feature_check/fstring.py
new file mode 100644
index 000000000..14792bce0
--- /dev/null
+++ b/tests/feature_check/fstring.py
@@ -0,0 +1,3 @@
+# check whether f-strings (PEP-498) are supported
+a = 1
+print(f"a={a}")
diff --git a/tests/feature_check/fstring.py.exp b/tests/feature_check/fstring.py.exp
new file mode 100644
index 000000000..73cdb8bcc
--- /dev/null
+++ b/tests/feature_check/fstring.py.exp
@@ -0,0 +1 @@
+a=1
diff --git a/tests/micropython/native_misc.py b/tests/micropython/native_misc.py
index 7c5415375..f5ef807fe 100644
--- a/tests/micropython/native_misc.py
+++ b/tests/micropython/native_misc.py
@@ -38,3 +38,13 @@ def f(a):
f(False)
f(True)
+
+
+# stack settling in branch
+@micropython.native
+def f(a):
+ print(1, 2, 3, 4 if a else 5)
+
+
+f(False)
+f(True)
diff --git a/tests/micropython/native_misc.py.exp b/tests/micropython/native_misc.py.exp
index b3e1389ef..8eec04228 100644
--- a/tests/micropython/native_misc.py.exp
+++ b/tests/micropython/native_misc.py.exp
@@ -4,3 +4,5 @@
6
True
False
+1 2 3 5
+1 2 3 4
diff --git a/tests/multi_bluetooth/ble_subscribe.py b/tests/multi_bluetooth/ble_subscribe.py
new file mode 100644
index 000000000..7cbcc6319
--- /dev/null
+++ b/tests/multi_bluetooth/ble_subscribe.py
@@ -0,0 +1,246 @@
+# Test for sending notifications to subscribed clients.
+
+from micropython import const
+import time, machine, bluetooth
+
+TIMEOUT_MS = 5000
+
+_IRQ_CENTRAL_CONNECT = const(1)
+_IRQ_CENTRAL_DISCONNECT = const(2)
+_IRQ_GATTS_WRITE = const(3)
+_IRQ_PERIPHERAL_CONNECT = const(7)
+_IRQ_PERIPHERAL_DISCONNECT = const(8)
+_IRQ_GATTC_CHARACTERISTIC_RESULT = const(11)
+_IRQ_GATTC_CHARACTERISTIC_DONE = const(12)
+_IRQ_GATTC_DESCRIPTOR_RESULT = const(13)
+_IRQ_GATTC_DESCRIPTOR_DONE = const(14)
+_IRQ_GATTC_READ_RESULT = const(15)
+_IRQ_GATTC_READ_DONE = const(16)
+_IRQ_GATTC_WRITE_DONE = const(17)
+_IRQ_GATTC_NOTIFY = const(18)
+_IRQ_GATTC_INDICATE = const(19)
+
+_CCCD_UUID = bluetooth.UUID(const(0x2902))
+
+SERVICE_UUID = bluetooth.UUID("A5A5A5A5-FFFF-9999-1111-5A5A5A5A5A5A")
+CHAR_UUID = bluetooth.UUID("00000000-1111-2222-3333-444444444444")
+CHAR = (
+ CHAR_UUID,
+ bluetooth.FLAG_READ | bluetooth.FLAG_WRITE | bluetooth.FLAG_NOTIFY | bluetooth.FLAG_INDICATE,
+)
+SERVICE = (
+ SERVICE_UUID,
+ (CHAR,),
+)
+SERVICES = (SERVICE,)
+
+waiting_events = {}
+
+
+def irq(event, data):
+ if event == _IRQ_CENTRAL_CONNECT:
+ print("_IRQ_CENTRAL_CONNECT")
+ waiting_events[event] = data[0]
+ elif event == _IRQ_CENTRAL_DISCONNECT:
+ print("_IRQ_CENTRAL_DISCONNECT")
+ elif event == _IRQ_GATTS_WRITE:
+ print("_IRQ_GATTS_WRITE", ble.gatts_read(data[-1]))
+ elif event == _IRQ_PERIPHERAL_CONNECT:
+ print("_IRQ_PERIPHERAL_CONNECT")
+ waiting_events[event] = data[0]
+ elif event == _IRQ_PERIPHERAL_DISCONNECT:
+ print("_IRQ_PERIPHERAL_DISCONNECT")
+ elif event == _IRQ_GATTC_CHARACTERISTIC_RESULT:
+ # conn_handle, def_handle, value_handle, properties, uuid = data
+ if data[-1] == CHAR_UUID:
+ print("_IRQ_GATTC_CHARACTERISTIC_RESULT", data[-1])
+ waiting_events[event] = data[2]
+ else:
+ return
+ elif event == _IRQ_GATTC_CHARACTERISTIC_DONE:
+ print("_IRQ_GATTC_CHARACTERISTIC_DONE")
+ elif event == _IRQ_GATTC_DESCRIPTOR_RESULT:
+ # conn_handle, dsc_handle, uuid = data
+ if data[-1] == _CCCD_UUID:
+ print("_IRQ_GATTC_DESCRIPTOR_RESULT", data[-1])
+ waiting_events[event] = data[1]
+ else:
+ return
+ elif event == _IRQ_GATTC_DESCRIPTOR_DONE:
+ print("_IRQ_GATTC_DESCRIPTOR_DONE")
+ elif event == _IRQ_GATTC_READ_RESULT:
+ print("_IRQ_GATTC_READ_RESULT", bytes(data[-1]))
+ elif event == _IRQ_GATTC_READ_DONE:
+ print("_IRQ_GATTC_READ_DONE", data[-1])
+ elif event == _IRQ_GATTC_WRITE_DONE:
+ print("_IRQ_GATTC_WRITE_DONE", data[-1])
+ elif event == _IRQ_GATTC_NOTIFY:
+ print("_IRQ_GATTC_NOTIFY", bytes(data[-1]))
+ elif event == _IRQ_GATTC_INDICATE:
+ print("_IRQ_GATTC_NOTIFY", bytes(data[-1]))
+
+ if event not in waiting_events:
+ waiting_events[event] = None
+
+
+def wait_for_event(event, timeout_ms):
+ t0 = time.ticks_ms()
+ while time.ticks_diff(time.ticks_ms(), t0) < timeout_ms:
+ if event in waiting_events:
+ return waiting_events.pop(event)
+ machine.idle()
+ raise ValueError("Timeout waiting for {}".format(event))
+
+
+# Acting in peripheral role.
+def instance0():
+ multitest.globals(BDADDR=ble.config("mac"))
+ ((char_handle,),) = ble.gatts_register_services(SERVICES)
+ print("gap_advertise")
+ ble.gap_advertise(20_000, b"\x02\x01\x06\x04\xffMPY") # \x04\x09MPY
+ multitest.next()
+ try:
+ # Write initial characteristic value (will be read by client).
+ ble.gatts_write(char_handle, "periph0") ###
+
+ # Wait for central to connect to us.
+ conn_handle = wait_for_event(_IRQ_CENTRAL_CONNECT, TIMEOUT_MS * 10)
+
+ # A
+ # Wait for a write to the characteristic from the central (to synchronise).
+ wait_for_event(_IRQ_GATTS_WRITE, TIMEOUT_MS)
+ print("sync A")
+ # This should be local-only.
+ ble.gatts_write(char_handle, "periph1")
+ time.sleep_ms(100)
+ # Update local-only, then force notify.
+ ble.gatts_write(char_handle, "periph2")
+ ble.gatts_notify(conn_handle, char_handle) ###
+ time.sleep_ms(100)
+ # Update local and notify subscribers. No notification should be sent.
+ ble.gatts_write(char_handle, "periph3", True)
+ time.sleep_ms(100)
+ multitest.broadcast("A")
+
+ # B
+ # Synchronise with the client (which should now be subscribed for notify).
+ wait_for_event(_IRQ_GATTS_WRITE, TIMEOUT_MS)
+ print("sync B")
+ # This should be local-only (send_update=False).
+ ble.gatts_write(char_handle, "periph4", False)
+ time.sleep_ms(100)
+ # This should notify the subscribed client.
+ ble.gatts_write(char_handle, "periph5", True) ###
+ time.sleep_ms(100)
+ multitest.broadcast("B")
+
+ # C
+ # Synchronise with the client (which should now be subscribed for indicate).
+ wait_for_event(_IRQ_GATTS_WRITE, TIMEOUT_MS)
+ print("sync C")
+ # This should be local-only (send_update=False).
+ ble.gatts_write(char_handle, "periph6", False)
+ time.sleep_ms(100)
+ # This should indicate the subscribed client.
+ ble.gatts_write(char_handle, "periph7", True) ###
+ time.sleep_ms(100)
+ multitest.broadcast("C")
+
+ # D
+ # Synchronise with the client (which should now be unsubscribed).
+ wait_for_event(_IRQ_GATTS_WRITE, TIMEOUT_MS)
+ print("sync D")
+ # This should be local-only (send_update=False).
+ ble.gatts_write(char_handle, "periph8", False)
+ time.sleep_ms(100)
+ # This should be local-only (no more subscribers).
+ ble.gatts_write(char_handle, "periph9", True)
+ time.sleep_ms(100)
+ # Update local-only, then another force notify.
+ ble.gatts_write(char_handle, "periph10")
+ ble.gatts_notify(conn_handle, char_handle) ###
+ time.sleep_ms(100)
+ multitest.broadcast("D")
+
+ # Wait for the central to disconnect.
+ wait_for_event(_IRQ_CENTRAL_DISCONNECT, TIMEOUT_MS)
+ finally:
+ ble.active(0)
+
+
+# Acting in central role.
+def instance1():
+ multitest.next()
+ try:
+ # Connect to peripheral and then disconnect.
+ print("gap_connect")
+ ble.gap_connect(*BDADDR)
+ conn_handle = wait_for_event(_IRQ_PERIPHERAL_CONNECT, TIMEOUT_MS)
+
+ # Discover characteristics.
+ ble.gattc_discover_characteristics(conn_handle, 1, 65535)
+ value_handle = wait_for_event(_IRQ_GATTC_CHARACTERISTIC_RESULT, TIMEOUT_MS)
+ wait_for_event(_IRQ_GATTC_CHARACTERISTIC_DONE, TIMEOUT_MS)
+
+ # Discover CCCD.
+ ble.gattc_discover_descriptors(conn_handle, value_handle, value_handle + 5)
+ cccd_handle = wait_for_event(_IRQ_GATTC_DESCRIPTOR_RESULT, TIMEOUT_MS)
+ wait_for_event(_IRQ_GATTC_DESCRIPTOR_DONE, TIMEOUT_MS)
+
+ # Issue read of characteristic, should get initial value.
+ print("gattc_read")
+ ble.gattc_read(conn_handle, value_handle)
+ wait_for_event(_IRQ_GATTC_READ_RESULT, TIMEOUT_MS)
+
+ # While the four states are active, all incoming notifications
+ # and indications will be printed by the event handler. We
+ # should only expect to see certain ones.
+
+ # Start unsubscribed.
+ # Write to the characteristic (triggers A).
+ print("gattc_write")
+ ble.gattc_write(conn_handle, value_handle, "central0", 1)
+ wait_for_event(_IRQ_GATTC_WRITE_DONE, TIMEOUT_MS)
+ # Wait for A to complete.
+ multitest.wait("A")
+
+ # Subscribe for notify.
+ ble.gattc_write(conn_handle, cccd_handle, b"\x01\x00", 1)
+ wait_for_event(_IRQ_GATTC_WRITE_DONE, TIMEOUT_MS)
+ # Write to the characteristic (triggers B).
+ print("gattc_write")
+ ble.gattc_write(conn_handle, value_handle, "central1", 1)
+ wait_for_event(_IRQ_GATTC_WRITE_DONE, TIMEOUT_MS)
+ # Wait for B to complete.
+ multitest.wait("B")
+
+ # Subscribe for indicate.
+ ble.gattc_write(conn_handle, cccd_handle, b"\x02\x00", 1)
+ wait_for_event(_IRQ_GATTC_WRITE_DONE, TIMEOUT_MS)
+ # Write to the characteristic (triggers C).
+ print("gattc_write")
+ ble.gattc_write(conn_handle, value_handle, "central2", 1)
+ wait_for_event(_IRQ_GATTC_WRITE_DONE, TIMEOUT_MS)
+ # Wait for C to complete.
+ multitest.wait("C")
+
+ # Unsubscribe.
+ ble.gattc_write(conn_handle, cccd_handle, b"\x00\x00", 1)
+ wait_for_event(_IRQ_GATTC_WRITE_DONE, TIMEOUT_MS)
+ # Write to the characteristic (triggers D).
+ print("gattc_write")
+ ble.gattc_write(conn_handle, value_handle, "central3", 1)
+ wait_for_event(_IRQ_GATTC_WRITE_DONE, TIMEOUT_MS)
+ # Wait for D to complete.
+ multitest.wait("D")
+
+ # Disconnect from peripheral.
+ print("gap_disconnect:", ble.gap_disconnect(conn_handle))
+ wait_for_event(_IRQ_PERIPHERAL_DISCONNECT, TIMEOUT_MS)
+ finally:
+ ble.active(0)
+
+
+ble = bluetooth.BLE()
+ble.active(1)
+ble.irq(irq)
diff --git a/tests/multi_bluetooth/ble_subscribe.py.exp b/tests/multi_bluetooth/ble_subscribe.py.exp
new file mode 100644
index 000000000..e0b4ed2f4
--- /dev/null
+++ b/tests/multi_bluetooth/ble_subscribe.py.exp
@@ -0,0 +1,39 @@
+--- instance0 ---
+gap_advertise
+_IRQ_CENTRAL_CONNECT
+_IRQ_GATTS_WRITE b'central0'
+sync A
+_IRQ_GATTS_WRITE b'central1'
+sync B
+_IRQ_GATTS_WRITE b'central2'
+sync C
+_IRQ_GATTS_WRITE b'central3'
+sync D
+_IRQ_CENTRAL_DISCONNECT
+--- instance1 ---
+gap_connect
+_IRQ_PERIPHERAL_CONNECT
+_IRQ_GATTC_CHARACTERISTIC_RESULT UUID('00000000-1111-2222-3333-444444444444')
+_IRQ_GATTC_CHARACTERISTIC_DONE
+_IRQ_GATTC_DESCRIPTOR_RESULT UUID(0x2902)
+_IRQ_GATTC_DESCRIPTOR_DONE
+gattc_read
+_IRQ_GATTC_READ_RESULT b'periph0'
+_IRQ_GATTC_READ_DONE 0
+gattc_write
+_IRQ_GATTC_WRITE_DONE 0
+_IRQ_GATTC_NOTIFY b'periph2'
+_IRQ_GATTC_WRITE_DONE 0
+gattc_write
+_IRQ_GATTC_WRITE_DONE 0
+_IRQ_GATTC_NOTIFY b'periph5'
+_IRQ_GATTC_WRITE_DONE 0
+gattc_write
+_IRQ_GATTC_WRITE_DONE 0
+_IRQ_GATTC_NOTIFY b'periph7'
+_IRQ_GATTC_WRITE_DONE 0
+gattc_write
+_IRQ_GATTC_WRITE_DONE 0
+_IRQ_GATTC_NOTIFY b'periph10'
+gap_disconnect: True
+_IRQ_PERIPHERAL_DISCONNECT
diff --git a/tests/multi_net/udp_data.py b/tests/multi_net/udp_data.py
new file mode 100644
index 000000000..fd3e00918
--- /dev/null
+++ b/tests/multi_net/udp_data.py
@@ -0,0 +1,35 @@
+# Simple test of a UDP server and client transferring data
+
+import socket
+
+NUM_NEW_SOCKETS = 4
+NUM_TRANSFERS = 4
+PORT = 8000
+
+# Server
+def instance0():
+ multitest.globals(IP=multitest.get_network_ip())
+ multitest.next()
+ for i in range(NUM_NEW_SOCKETS):
+ s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+ s.bind(socket.getaddrinfo("0.0.0.0", PORT)[0][-1])
+ multitest.broadcast("server ready")
+ for j in range(NUM_TRANSFERS):
+ data, addr = s.recvfrom(1000)
+ print(data)
+ s.sendto(b"server to client %d %d" % (i, j), addr)
+ s.close()
+
+
+# Client
+def instance1():
+ multitest.next()
+ ai = socket.getaddrinfo(IP, PORT)[0][-1]
+ for i in range(NUM_NEW_SOCKETS):
+ s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+ multitest.wait("server ready")
+ for j in range(NUM_TRANSFERS):
+ s.sendto(b"client to server %d %d" % (i, j), ai)
+ data, addr = s.recvfrom(1000)
+ print(data)
+ s.close()
diff --git a/tests/pyb/i2c.py b/tests/pyb/i2c.py
index bc9dba878..c96884327 100644
--- a/tests/pyb/i2c.py
+++ b/tests/pyb/i2c.py
@@ -11,6 +11,6 @@ for bus in (-1, 0, 1):
i2c = I2C(1)
-i2c.init(I2C.MASTER, baudrate=400000)
+i2c.init(I2C.CONTROLLER, baudrate=400000)
print(i2c.scan())
i2c.deinit()
diff --git a/tests/pyb/i2c_accel.py b/tests/pyb/i2c_accel.py
index 8c74fa60e..8b87d406d 100644
--- a/tests/pyb/i2c_accel.py
+++ b/tests/pyb/i2c_accel.py
@@ -11,7 +11,7 @@ accel_addr = 76
pyb.Accel() # this will init the MMA for us
-i2c = I2C(1, I2C.MASTER, baudrate=400000)
+i2c = I2C(1, I2C.CONTROLLER, baudrate=400000)
print(i2c.scan())
print(i2c.is_ready(accel_addr))
diff --git a/tests/pyb/i2c_error.py b/tests/pyb/i2c_error.py
index b17a26325..1228962f5 100644
--- a/tests/pyb/i2c_error.py
+++ b/tests/pyb/i2c_error.py
@@ -11,7 +11,7 @@ if not hasattr(pyb, "Accel"):
pyb.Accel()
# get I2C bus
-i2c = I2C(1, I2C.MASTER, dma=True)
+i2c = I2C(1, I2C.CONTROLLER, dma=True)
# test polling mem_read
pyb.disable_irq()
diff --git a/tests/pyb/pyb_f405.py b/tests/pyb/pyb_f405.py
index 243381056..d7431a11a 100644
--- a/tests/pyb/pyb_f405.py
+++ b/tests/pyb/pyb_f405.py
@@ -10,7 +10,7 @@ print(pyb.freq())
print(type(pyb.rng()))
# test HAL error specific to F405
-i2c = pyb.I2C(2, pyb.I2C.MASTER)
+i2c = pyb.I2C(2, pyb.I2C.CONTROLLER)
try:
i2c.recv(1, 1)
except OSError as e:
diff --git a/tests/pyb/spi.py b/tests/pyb/spi.py
index 73d39e724..7df6aeb45 100644
--- a/tests/pyb/spi.py
+++ b/tests/pyb/spi.py
@@ -11,12 +11,14 @@ for bus in (-1, 0, 1, 2):
spi = SPI(1)
print(spi)
-spi = SPI(1, SPI.MASTER)
-spi = SPI(1, SPI.MASTER, baudrate=500000)
-spi = SPI(1, SPI.MASTER, 500000, polarity=1, phase=0, bits=8, firstbit=SPI.MSB, ti=False, crc=None)
-print(str(spi)[:28], str(spi)[49:]) # don't print baudrate/prescaler
+spi = SPI(1, SPI.CONTROLLER)
+spi = SPI(1, SPI.CONTROLLER, baudrate=500000)
+spi = SPI(
+ 1, SPI.CONTROLLER, 500000, polarity=1, phase=0, bits=8, firstbit=SPI.MSB, ti=False, crc=None
+)
+print(str(spi)[:32], str(spi)[53:]) # don't print baudrate/prescaler
-spi.init(SPI.SLAVE, phase=1)
+spi.init(SPI.PERIPHERAL, phase=1)
print(spi)
try:
# need to flush input before we get an error (error is what we want to test)
@@ -25,7 +27,7 @@ try:
except OSError:
print("OSError")
-spi.init(SPI.MASTER)
+spi.init(SPI.CONTROLLER)
spi.send(1, timeout=100)
print(spi.recv(1, timeout=100))
print(spi.send_recv(1, timeout=100))
diff --git a/tests/pyb/spi.py.exp b/tests/pyb/spi.py.exp
index 473c173a5..661bace90 100644
--- a/tests/pyb/spi.py.exp
+++ b/tests/pyb/spi.py.exp
@@ -3,8 +3,8 @@ ValueError 0
SPI 1
SPI 2
SPI(1)
-SPI(1, SPI.MASTER, baudrate= , polarity=1, phase=0, bits=8)
-SPI(1, SPI.SLAVE, polarity=1, phase=1, bits=8)
+SPI(1, SPI.CONTROLLER, baudrate= , polarity=1, phase=0, bits=8)
+SPI(1, SPI.PERIPHERAL, polarity=1, phase=1, bits=8)
OSError
b'\xff'
b'\xff'
diff --git a/tests/pybnative/while.py b/tests/pybnative/while.py
index 0f397dd37..10625e871 100644
--- a/tests/pybnative/while.py
+++ b/tests/pybnative/while.py
@@ -1,4 +1,4 @@
-import pyb
+import time, pyb
@micropython.native
@@ -8,7 +8,7 @@ def f(led, n, d):
while i < n:
print(i)
led.toggle()
- pyb.delay(d)
+ time.sleep_ms(d)
i += 1
led.off()
diff --git a/tests/run-multitests.py b/tests/run-multitests.py
index b4afc1e52..34389e429 100755
--- a/tests/run-multitests.py
+++ b/tests/run-multitests.py
@@ -46,6 +46,16 @@ class multitest:
print("NEXT")
multitest.flush()
@staticmethod
+ def broadcast(msg):
+ print("BROADCAST", msg)
+ multitest.flush()
+ @staticmethod
+ def wait(msg):
+ msg = "BROADCAST " + msg
+ while True:
+ if sys.stdin.readline().rstrip() == msg:
+ return
+ @staticmethod
def globals(**gs):
for g in gs:
print("SET {{}} = {{!r}}".format(g, gs[g]))
@@ -126,14 +136,12 @@ class PyInstanceSubProcess(PyInstance):
def start_script(self, script):
self.popen = subprocess.Popen(
- self.argv,
+ self.argv + ["-c", script],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
env=self.env,
)
- self.popen.stdin.write(script)
- self.popen.stdin.close()
self.finished = False
def stop(self):
@@ -141,7 +149,7 @@ class PyInstanceSubProcess(PyInstance):
self.popen.terminate()
def readline(self):
- sel = select.select([self.popen.stdout.raw], [], [], 0.1)
+ sel = select.select([self.popen.stdout.raw], [], [], 0.001)
if not sel[0]:
self.finished = self.popen.poll() is not None
return None, None
@@ -152,6 +160,10 @@ class PyInstanceSubProcess(PyInstance):
else:
return str(out.rstrip(), "ascii"), None
+ def write(self, data):
+ self.popen.stdin.write(data)
+ self.popen.stdin.flush()
+
def is_finished(self):
return self.finished
@@ -220,6 +232,9 @@ class PyInstancePyboard(PyInstance):
err = None
return str(out.rstrip(), "ascii"), err
+ def write(self, data):
+ self.pyb.serial.write(data)
+
def is_finished(self):
return self.finished
@@ -318,7 +333,12 @@ def run_test_on_instances(test_file, num_instances, instances):
last_read_time[idx] = time.time()
if out is not None and not any(m in out for m in IGNORE_OUTPUT_MATCHES):
trace_instance_output(idx, out)
- output[idx].append(out)
+ if out.startswith("BROADCAST "):
+ for instance2 in instances:
+ if instance2 is not instance:
+ instance2.write(bytes(out, "ascii") + b"\r\n")
+ else:
+ output[idx].append(out)
if err is not None:
trace_instance_output(idx, err)
output[idx].append(err)
diff --git a/tests/run-tests.py b/tests/run-tests.py
index 619df5ed3..3e97a7c87 100755
--- a/tests/run-tests.py
+++ b/tests/run-tests.py
@@ -290,6 +290,7 @@ def run_tests(pyb, tests, args, result_dir, num_threads=1):
skip_const = False
skip_revops = False
skip_io_module = False
+ skip_fstring = False
skip_endian = False
has_complex = True
has_coverage = False
@@ -348,6 +349,11 @@ def run_tests(pyb, tests, args, result_dir, num_threads=1):
if output != b"uio\n":
skip_io_module = True
+ # Check if fstring feature is enabled, and skip such tests if it doesn't
+ output = run_feature_check(pyb, args, base_path, "fstring.py")
+ if output != b"a=1\n":
+ skip_fstring = True
+
# Check if emacs repl is supported, and skip such tests if it's not
t = run_feature_check(pyb, args, base_path, "repl_emacs_check.py")
if "True" not in str(t, "ascii"):
@@ -543,6 +549,7 @@ def run_tests(pyb, tests, args, result_dir, num_threads=1):
is_async = test_name.startswith(("async_", "uasyncio_"))
is_const = test_name.startswith("const")
is_io_module = test_name.startswith("io_")
+ is_fstring = test_name.startswith("string_fstring")
skip_it = test_file in skip_tests
skip_it |= skip_native and is_native
@@ -555,6 +562,7 @@ def run_tests(pyb, tests, args, result_dir, num_threads=1):
skip_it |= skip_const and is_const
skip_it |= skip_revops and "reverse_op" in test_name
skip_it |= skip_io_module and is_io_module
+ skip_it |= skip_fstring and is_fstring
if args.list_tests:
if not skip_it:
diff --git a/tools/autobuild/autobuild.sh b/tools/autobuild/autobuild.sh
index 049844381..a14c7890f 100755
--- a/tools/autobuild/autobuild.sh
+++ b/tools/autobuild/autobuild.sh
@@ -4,7 +4,8 @@
#
# Requirements:
# - All toolchains must be in path (arm-none-eabi-gcc, xtensa-lx106-elf)
-# - IDF_PATH_V4 must be set
+# - IDF_PATH_V42 must be set
+# - IDF_PATH_V43 must be set
# - MICROPY_AUTOBUILD_MICROPYTHON_REPO must be set to location of micropython repository
# - MICROPY_AUTOBUILD_MAKE must be set to the make command to use, eg "make -j2"
#
@@ -12,8 +13,13 @@
# - MICROPY_AUTOBUILD_REMOTE_MACHINE can be set to a remote ssh machine to copy files to
# - MICROPY_AUTOBUILD_REMOTE_DIR can be set to destination directory on remote machine
-if [ ! -d "$IDF_PATH_V4" ]; then
- echo "must set IDF_PATH_V4"
+if [ ! -d "$IDF_PATH_V42" ]; then
+ echo "must set IDF_PATH_V42"
+ exit 1
+fi
+
+if [ ! -d "$IDF_PATH_V43" ]; then
+ echo "must set IDF_PATH_V43"
exit 1
fi
@@ -63,7 +69,8 @@ ${AUTODIR}/build-cc3200-latest.sh ${FW_TAG} ${LOCAL_FIRMWARE}
cd ../esp8266
${AUTODIR}/build-esp8266-latest.sh ${FW_TAG} ${LOCAL_FIRMWARE}
cd ../esp32
-${AUTODIR}/build-esp32-latest.sh ${IDF_PATH_V4} ${FW_TAG} ${LOCAL_FIRMWARE}
+${AUTODIR}/build-esp32-latest.sh ${IDF_PATH_V42} ${FW_TAG} ${LOCAL_FIRMWARE}
+${AUTODIR}/build-esp32-latest.sh ${IDF_PATH_V43} ${FW_TAG} ${LOCAL_FIRMWARE}
cd ../rp2
${AUTODIR}/build-rp2-latest.sh ${FW_TAG} ${LOCAL_FIRMWARE}
cd ../mimxrt
diff --git a/tools/autobuild/build-cc3200-latest.sh b/tools/autobuild/build-cc3200-latest.sh
index 3c6d40036..0cbdb9c42 100755
--- a/tools/autobuild/build-cc3200-latest.sh
+++ b/tools/autobuild/build-cc3200-latest.sh
@@ -8,7 +8,7 @@ function do_build() {
shift
echo "building $descr $board"
build_dir=/tmp/cc3200-build-$board
- $MICROPY_AUTOBUILD_MAKE -B $@ BTARGET=application BOARD=$board BUILD=$build_dir || exit 1
+ $MICROPY_AUTOBUILD_MAKE $@ BTARGET=application BOARD=$board BUILD=$build_dir || exit 1
zip $dest_dir/$descr$fw_tag.zip $build_dir/mcuimg.bin
rm -rf $build_dir
}
diff --git a/tools/autobuild/build-esp32-latest.sh b/tools/autobuild/build-esp32-latest.sh
index e433332c9..92a12b2d5 100755
--- a/tools/autobuild/build-esp32-latest.sh
+++ b/tools/autobuild/build-esp32-latest.sh
@@ -39,7 +39,14 @@ fi
source $idf_path/export.sh
-# build the versions
-do_build esp32 GENERIC FROZEN_MANIFEST=$(pwd)/boards/manifest_release.py
-do_build esp32spiram GENERIC_SPIRAM FROZEN_MANIFEST=$(pwd)/boards/manifest_release.py
-do_build tinypico UM_TINYPICO
+# build the boards, based on the IDF version
+if idf.py --version | grep -q v4.2; then
+ do_build esp32 GENERIC FROZEN_MANIFEST=$(pwd)/boards/manifest_release.py
+ do_build esp32spiram GENERIC_SPIRAM FROZEN_MANIFEST=$(pwd)/boards/manifest_release.py
+ do_build tinypico UM_TINYPICO
+ do_build wesp32 SIL_WESP32
+else
+ do_build esp32c3 GENERIC_C3
+ do_build tinys2 UM_TINYS2
+ do_build featherS2 UM_FEATHERS2
+fi
diff --git a/tools/autobuild/build-mimxrt-latest.sh b/tools/autobuild/build-mimxrt-latest.sh
index e36b294ac..4db65c091 100755
--- a/tools/autobuild/build-mimxrt-latest.sh
+++ b/tools/autobuild/build-mimxrt-latest.sh
@@ -34,3 +34,4 @@ fi
do_build TEENSY40 TEENSY40 hex
do_build TEENSY41 TEENSY41 hex
do_build MIMXRT1020_EVK MIMXRT1020_EVK bin
+do_build MIMXRT1050_EVKB MIMXRT1050_EVKB bin
diff --git a/tools/autobuild/build-stm32-latest.sh b/tools/autobuild/build-stm32-latest.sh
index 226c14a41..283c8a45b 100755
--- a/tools/autobuild/build-stm32-latest.sh
+++ b/tools/autobuild/build-stm32-latest.sh
@@ -8,7 +8,7 @@ function do_build() {
shift
echo "building $descr $board"
build_dir=/tmp/stm-build-$board
- $MICROPY_AUTOBUILD_MAKE -B $@ BOARD=$board BUILD=$build_dir || exit 1
+ $MICROPY_AUTOBUILD_MAKE $@ BOARD=$board BUILD=$build_dir || exit 1
mv $build_dir/firmware.dfu $dest_dir/$descr$fw_tag.dfu
rm -rf $build_dir
}
diff --git a/tools/ci.sh b/tools/ci.sh
index 9f2452cac..ac2e0b77d 100755
--- a/tools/ci.sh
+++ b/tools/ci.sh
@@ -86,12 +86,19 @@ function ci_esp32_setup_helper {
git clone https://github.com/espressif/esp-idf.git
git -C esp-idf checkout $1
git -C esp-idf submodule update --init \
- components/bt/controller/lib \
components/bt/host/nimble/nimble \
components/esp_wifi \
components/esptool_py/esptool \
components/lwip/lwip \
components/mbedtls/mbedtls
+ if [ -d esp-idf/components/bt/controller/esp32 ]; then
+ git -C esp-idf submodule update --init \
+ components/bt/controller/lib_esp32 \
+ components/bt/controller/lib_esp32c3_family
+ else
+ git -C esp-idf submodule update --init \
+ components/bt/controller/lib
+ fi
./esp-idf/install.sh
}
@@ -100,7 +107,7 @@ function ci_esp32_idf402_setup {
}
function ci_esp32_idf43_setup {
- ci_esp32_setup_helper v4.3-beta2
+ ci_esp32_setup_helper v4.3
}
function ci_esp32_build {
@@ -110,6 +117,9 @@ function ci_esp32_build {
make ${MAKEOPTS} -C ports/esp32
make ${MAKEOPTS} -C ports/esp32 clean
make ${MAKEOPTS} -C ports/esp32 USER_C_MODULES=../../../examples/usercmodule/micropython.cmake FROZEN_MANIFEST=$(pwd)/ports/esp32/boards/manifest.py
+ # if [ -d $IDF_PATH/components/esp32c3 ]; then
+ # make ${MAKEOPTS} -C ports/esp32 BOARD=GENERIC_C3
+ # fi
# if [ -d $IDF_PATH/components/esp32s2 ]; then
# make ${MAKEOPTS} -C ports/esp32 BOARD=GENERIC_S2
# fi
@@ -180,6 +190,7 @@ function ci_nrf_setup {
function ci_nrf_build {
ports/nrf/drivers/bluetooth/download_ble_stack.sh s140_nrf52_6_1_1
+ make ${MAKEOPTS} -C mpy-cross
make ${MAKEOPTS} -C ports/nrf submodules
make ${MAKEOPTS} -C ports/nrf BOARD=pca10040
make ${MAKEOPTS} -C ports/nrf BOARD=microbit
@@ -258,6 +269,7 @@ function ci_stm32_pyb_build {
make ${MAKEOPTS} -C mpy-cross
make ${MAKEOPTS} -C ports/stm32 submodules
git submodule update --init lib/btstack
+ git submodule update --init lib/mynewt-nimble
make ${MAKEOPTS} -C ports/stm32 BOARD=PYBV11 MICROPY_PY_WIZNET5K=5200 MICROPY_PY_CC3K=1 USER_C_MODULES=../../examples/usercmodule
make ${MAKEOPTS} -C ports/stm32 BOARD=PYBD_SF2
make ${MAKEOPTS} -C ports/stm32 BOARD=PYBD_SF6 NANBOX=1 MICROPY_BLUETOOTH_NIMBLE=0 MICROPY_BLUETOOTH_BTSTACK=1
@@ -268,6 +280,7 @@ function ci_stm32_pyb_build {
function ci_stm32_nucleo_build {
make ${MAKEOPTS} -C mpy-cross
make ${MAKEOPTS} -C ports/stm32 submodules
+ git submodule update --init lib/mynewt-nimble
make ${MAKEOPTS} -C ports/stm32 BOARD=NUCLEO_F091RC
make ${MAKEOPTS} -C ports/stm32 BOARD=NUCLEO_H743ZI CFLAGS_EXTRA='-DMICROPY_PY_THREAD=1'
make ${MAKEOPTS} -C ports/stm32 BOARD=NUCLEO_L073RZ
@@ -394,6 +407,14 @@ function ci_unix_standard_run_perfbench {
(cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=../ports/unix/micropython ./run-perfbench.py 1000 1000)
}
+function ci_unix_dev_build {
+ ci_unix_build_helper VARIANT=dev
+}
+
+function ci_unix_dev_run_tests {
+ ci_unix_run_tests_helper VARIANT=dev
+}
+
function ci_unix_coverage_setup {
sudo pip3 install setuptools
sudo pip3 install pyelftools
@@ -508,6 +529,8 @@ function ci_unix_macos_build {
#make ${MAKEOPTS} -C ports/unix deplibs
make ${MAKEOPTS} -C ports/unix
# check for additional compiler errors/warnings
+ make ${MAKEOPTS} -C ports/unix VARIANT=dev submodules
+ make ${MAKEOPTS} -C ports/unix VARIANT=dev
make ${MAKEOPTS} -C ports/unix VARIANT=coverage submodules
make ${MAKEOPTS} -C ports/unix VARIANT=coverage
}
diff --git a/tools/codeformat.py b/tools/codeformat.py
index 81a3cdcf8..a5d64739a 100755
--- a/tools/codeformat.py
+++ b/tools/codeformat.py
@@ -39,12 +39,13 @@ PATHS = [
"extmod/btstack/*.[ch]",
"extmod/nimble/*.[ch]",
"lib/mbedtls_errors/tester.c",
- "lib/netutils/*.[ch]",
- "lib/timeutils/*.[ch]",
- "lib/utils/*.[ch]",
+ "shared/netutils/*.[ch]",
+ "shared/timeutils/*.[ch]",
+ "shared/runtime/*.[ch]",
"mpy-cross/*.[ch]",
"ports/*/*.[ch]",
"ports/windows/msvc/**/*.[ch]",
+ "ports/nrf/modules/nrf/*.[ch]",
"py/*.[ch]",
# Python
"drivers/**/*.py",
diff --git a/tools/gen-cpydiff.py b/tools/gen-cpydiff.py
index c9f58ec50..1d458d3dc 100644
--- a/tools/gen-cpydiff.py
+++ b/tools/gen-cpydiff.py
@@ -50,7 +50,6 @@ INDEXTEMPLATE = "../docs/differences/index_template.txt"
INDEX = "index.rst"
HEADER = ".. This document was generated by tools/gen-cpydiff.py\n\n"
-UIMPORTLIST = {"struct", "collections", "json"}
CLASSMAP = {"Core": "Core language", "Types": "Builtin types"}
INDEXPRIORITY = ["syntax", "core_language", "builtin_types", "modules"]
RSTCHARS = ["=", "-", "~", "`", ":"]
@@ -94,21 +93,12 @@ def readfiles():
return files
-def uimports(code):
- """converts CPython module names into MicroPython equivalents"""
- for uimport in UIMPORTLIST:
- uimport = bytes(uimport, "utf8")
- code = code.replace(uimport, b"u" + uimport)
- return code
-
-
def run_tests(tests):
"""executes all tests"""
results = []
for test in tests:
with open(TESTPATH + test.name, "rb") as f:
- input_cpy = f.read()
- input_upy = uimports(input_cpy)
+ input_py = f.read()
process = subprocess.Popen(
CPYTHON3,
@@ -117,7 +107,7 @@ def run_tests(tests):
stdin=subprocess.PIPE,
stderr=subprocess.PIPE,
)
- output_cpy = [com.decode("utf8") for com in process.communicate(input_cpy)]
+ output_cpy = [com.decode("utf8") for com in process.communicate(input_py)]
process = subprocess.Popen(
MICROPYTHON,
@@ -126,7 +116,7 @@ def run_tests(tests):
stdin=subprocess.PIPE,
stderr=subprocess.PIPE,
)
- output_upy = [com.decode("utf8") for com in process.communicate(input_upy)]
+ output_upy = [com.decode("utf8") for com in process.communicate(input_py)]
if output_cpy[0] == output_upy[0] and output_cpy[1] == output_upy[1]:
status = "Supported"
diff --git a/tools/insert-usb-ids.py b/tools/insert-usb-ids.py
index b1d848ad4..9b53f3f68 100644
--- a/tools/insert-usb-ids.py
+++ b/tools/insert-usb-ids.py
@@ -8,6 +8,7 @@ import sys
import re
import string
+config_prefix = "MICROPY_HW_USB_"
needed_keys = ("USB_PID_CDC_MSC", "USB_PID_CDC_HID", "USB_PID_CDC", "USB_VID")
@@ -16,10 +17,10 @@ def parse_usb_ids(filename):
for line in open(filename).readlines():
line = line.rstrip("\r\n")
match = re.match("^#define\s+(\w+)\s+\(0x([0-9A-Fa-f]+)\)$", line)
- if match and match.group(1).startswith("USBD_"):
- key = match.group(1).replace("USBD", "USB")
+ if match and match.group(1).startswith(config_prefix):
+ key = match.group(1).replace(config_prefix, "USB_")
val = match.group(2)
- print("key =", key, "val =", val)
+ # print("key =", key, "val =", val)
if key in needed_keys:
rv[key] = val
for k in needed_keys:
diff --git a/tools/mpremote/mpremote/main.py b/tools/mpremote/mpremote/main.py
index d225bf2e4..6e2df5179 100644
--- a/tools/mpremote/mpremote/main.py
+++ b/tools/mpremote/mpremote/main.py
@@ -27,6 +27,7 @@ _PROG = "mpremote"
_BUILTIN_COMMAND_EXPANSIONS = {
# Device connection shortcuts.
+ "devs": "connect list",
"a0": "connect /dev/ttyACM0",
"a1": "connect /dev/ttyACM1",
"a2": "connect /dev/ttyACM2",
@@ -166,7 +167,12 @@ def do_connect(args):
for p in sorted(serial.tools.list_ports.comports()):
print(
"{} {} {:04x}:{:04x} {} {}".format(
- p.device, p.serial_number, p.vid, p.pid, p.manufacturer, p.product
+ p.device,
+ p.serial_number,
+ p.vid if isinstance(p.vid, int) else 0,
+ p.pid if isinstance(p.pid, int) else 0,
+ p.manufacturer,
+ p.product,
)
)
return None
diff --git a/tools/mpremote/mpremote/pyboardextended.py b/tools/mpremote/mpremote/pyboardextended.py
index e3f259b39..ccd3098e3 100644
--- a/tools/mpremote/mpremote/pyboardextended.py
+++ b/tools/mpremote/mpremote/pyboardextended.py
@@ -1,4 +1,4 @@
-import os, re, serial, struct, time
+import io, os, re, serial, struct, time
from errno import EPERM
from .console import VT_ENABLED
@@ -24,26 +24,18 @@ fs_hook_cmds = {
}
fs_hook_code = """\
-import uos, uio, ustruct, micropython, usys
+import uos, uio, ustruct, micropython
+SEEK_SET = 0
class RemoteCommand:
- def __init__(self, use_second_port):
+ def __init__(self):
+ import uselect, usys
self.buf4 = bytearray(4)
- try:
- import pyb
- self.fout = pyb.USB_VCP()
- if use_second_port:
- self.fin = pyb.USB_VCP(1)
- else:
- self.fin = pyb.USB_VCP()
- except:
- import usys
- self.fout = usys.stdout.buffer
- self.fin = usys.stdin.buffer
- import select
- self.poller = select.poll()
- self.poller.register(self.fin, select.POLLIN)
+ self.fout = usys.stdout.buffer
+ self.fin = usys.stdin.buffer
+ self.poller = uselect.poll()
+ self.poller.register(self.fin, uselect.POLLIN)
def poll_in(self):
for _ in self.poller.ipoll(1000):
@@ -213,13 +205,16 @@ class RemoteFile(uio.IOBase):
c.end()
return n
- def seek(self, n):
+ def seek(self, n, whence=SEEK_SET):
c = self.cmd
c.begin(CMD_SEEK)
c.wr_s8(self.fd)
c.wr_s32(n)
+ c.wr_s8(whence)
n = c.rd_s32()
c.end()
+ if n < 0:
+ raise OSError(n)
return n
@@ -313,8 +308,8 @@ class RemoteFS:
return RemoteFile(c, fd, mode.find('b') == -1)
-def __mount(use_second_port):
- uos.mount(RemoteFS(RemoteCommand(use_second_port)), '/remote')
+def __mount():
+ uos.mount(RemoteFS(RemoteCommand()), '/remote')
uos.chdir('/remote')
"""
@@ -459,8 +454,12 @@ class PyboardCommand:
def do_seek(self):
fd = self.rd_s8()
n = self.rd_s32()
+ whence = self.rd_s8()
# self.log_cmd(f"seek {fd} {n}")
- self.data_files[fd][0].seek(n)
+ try:
+ n = self.data_files[fd][0].seek(n, whence)
+ except io.UnsupportedOperation:
+ n = -1
self.wr_s32(n)
def do_write(self):
@@ -563,28 +562,14 @@ class PyboardExtended(Pyboard):
self.device_name = dev
self.mounted = False
- def mount_local(self, path, dev_out=None):
+ def mount_local(self, path):
fout = self.serial
- if dev_out is not None:
- try:
- fout = serial.Serial(dev_out)
- except serial.SerialException:
- port = list(serial.tools.list_ports.grep(dev_out))
- if not port:
- raise
- for p in port:
- try:
- fout = serial.Serial(p.device)
- break
- except serial.SerialException:
- pass
self.mounted = True
if self.eval('"RemoteFS" in globals()') == b"False":
self.exec_(fs_hook_code)
- self.exec_("__mount(%s)" % (dev_out is not None))
+ self.exec_("__mount()")
self.cmd = PyboardCommand(self.serial, fout, path)
self.serial = SerialIntercept(self.serial, self.cmd)
- self.dev_out = dev_out
def soft_reset_with_mount(self, out_callback):
self.serial.write(b"\x04")
@@ -610,7 +595,7 @@ class PyboardExtended(Pyboard):
n = self.serial.inWaiting()
self.serial.write(b"\x01")
self.exec_(fs_hook_code)
- self.exec_("__mount(%s)" % (self.dev_out is not None))
+ self.exec_("__mount()")
self.exit_raw_repl()
self.read_until(4, b">>> ")
self.serial = SerialIntercept(self.serial, self.cmd)
diff --git a/tools/mpremote/setup.cfg b/tools/mpremote/setup.cfg
index 4e78d05a9..261369384 100644
--- a/tools/mpremote/setup.cfg
+++ b/tools/mpremote/setup.cfg
@@ -1,6 +1,6 @@
[metadata]
name = mpremote
-version = 0.0.5
+version = 0.0.6
author = Damien George
author_email = damien@micropython.org
description = Tool for interacting remotely with MicroPython
diff --git a/tools/pyboard.py b/tools/pyboard.py
index e460c69e2..15ddfd745 100755
--- a/tools/pyboard.py
+++ b/tools/pyboard.py
@@ -659,23 +659,37 @@ def main():
group.add_argument(
"--soft-reset",
default=True,
- action=argparse.BooleanOptionalAction,
- help="Whether to perform a soft reset when connecting to the board.",
+ action="store_true",
+ help="Whether to perform a soft reset when connecting to the board [default]",
)
+ group.add_argument(
+ "--no-soft-reset",
+ action="store_false",
+ dest="soft_reset",
+ )
+ group = cmd_parser.add_mutually_exclusive_group()
group.add_argument(
"--follow",
action="store_true",
+ default=None,
help="follow the output after running the scripts [default if no scripts given]",
)
group.add_argument(
"--no-follow",
+ action="store_false",
+ dest="follow",
+ )
+ group = cmd_parser.add_mutually_exclusive_group()
+ group.add_argument(
+ "--exclusive",
action="store_true",
- help="Do not follow the output after running the scripts.",
+ default=True,
+ help="Open the serial device for exclusive access [default]",
)
group.add_argument(
"--no-exclusive",
- action="store_true",
- help="Do not try to open the serial device for exclusive access.",
+ action="store_false",
+ dest="exclusive",
)
cmd_parser.add_argument(
"-f",
@@ -690,7 +704,7 @@ def main():
# open the connection to the pyboard
try:
pyb = Pyboard(
- args.device, args.baudrate, args.user, args.password, args.wait, not args.no_exclusive
+ args.device, args.baudrate, args.user, args.password, args.wait, args.exclusive
)
except PyboardError as er:
print(er)
@@ -709,13 +723,13 @@ def main():
def execbuffer(buf):
try:
- if args.no_follow:
- pyb.exec_raw_no_follow(buf)
- ret_err = None
- else:
+ if args.follow is None or args.follow:
ret, ret_err = pyb.exec_raw(
buf, timeout=None, data_consumer=stdout_write_bytes
)
+ else:
+ pyb.exec_raw_no_follow(buf)
+ ret_err = None
except PyboardError as er:
print(er)
pyb.close()
diff --git a/tools/tinytest-codegen.py b/tools/tinytest-codegen.py
index cba0b9448..f1169a34d 100755
--- a/tools/tinytest-codegen.py
+++ b/tools/tinytest-codegen.py
@@ -99,6 +99,9 @@ exclude_tests = (
"misc/sys_settrace_loop.py",
"misc/sys_settrace_generator.py",
"misc/sys_settrace_features.py",
+ # don't have f-string
+ "basics/string_fstring.py",
+ "basics/string_fstring_debug.py",
)
output = []
diff --git a/tools/uncrustify.cfg b/tools/uncrustify.cfg
index 80542b903..88127112e 100644
--- a/tools/uncrustify.cfg
+++ b/tools/uncrustify.cfg
@@ -1409,11 +1409,11 @@ nl_start_of_file = ignore # ignore/add/remove/force
nl_start_of_file_min = 0 # unsigned number
# Add or remove newline at the end of the file.
-nl_end_of_file = ignore # ignore/add/remove/force
+nl_end_of_file = force # ignore/add/remove/force
# The minimum number of newlines at the end of the file (only used if
# nl_end_of_file is 'add' or 'force').
-nl_end_of_file_min = 0 # unsigned number
+nl_end_of_file_min = 1 # unsigned number
# Add or remove newline between '=' and '{'.
nl_assign_brace = ignore # ignore/add/remove/force