summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Halbert <halbert@halwitz.org>2018-01-02 21:25:41 -0500
committerDan Halbert <halbert@halwitz.org>2018-01-02 21:25:41 -0500
commit065e82015f0d2bd6732c62b7375fcc7af87fa0cf (patch)
treee48fa8caa5675d529d335a2b154e69eba8199cff
parentce81c8dda9686d3cd78d9c5383b6982c148ac7ec (diff)
merge from 2.2.0 + fix up board defs
-rw-r--r--.gitmodules3
-rw-r--r--.readthedocs.yml2
-rw-r--r--docs/troubleshooting.rst24
-rw-r--r--lib/libm/nearbyintf.c2
-rw-r--r--lib/utils/pyexec.c7
-rw-r--r--ports/atmel-samd/Makefile4
-rw-r--r--ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.h36
-rw-r--r--ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.mk13
-rw-r--r--ports/atmel-samd/boards/feather_m0_supersized/board.c38
-rw-r--r--ports/atmel-samd/boards/feather_m0_supersized/conf_access.h115
-rw-r--r--ports/atmel-samd/boards/feather_m0_supersized/conf_board.h14
-rw-r--r--ports/atmel-samd/boards/feather_m0_supersized/conf_clocks.h1
-rw-r--r--ports/atmel-samd/boards/feather_m0_supersized/conf_usb.h220
-rw-r--r--ports/atmel-samd/boards/feather_m0_supersized/mpconfigboard.h34
-rw-r--r--ports/atmel-samd/boards/feather_m0_supersized/mpconfigboard.mk11
-rw-r--r--ports/atmel-samd/boards/feather_m0_supersized/pins.c28
-rw-r--r--ports/atmel-samd/boards/flash_S25FL064L.h55
-rw-r--r--ports/atmel-samd/boards/flash_W25Q80DV.h51
-rw-r--r--ports/atmel-samd/boards/itsybitsy_m0/board.c37
-rw-r--r--ports/atmel-samd/boards/itsybitsy_m0/conf_access.h115
-rw-r--r--ports/atmel-samd/boards/itsybitsy_m0/conf_board.h14
-rw-r--r--ports/atmel-samd/boards/itsybitsy_m0/conf_clocks.h1
-rw-r--r--ports/atmel-samd/boards/itsybitsy_m0/conf_usb.h221
-rw-r--r--ports/atmel-samd/boards/itsybitsy_m0/mpconfigboard.h36
-rw-r--r--ports/atmel-samd/boards/itsybitsy_m0/mpconfigboard.mk11
-rw-r--r--ports/atmel-samd/boards/itsybitsy_m0/pins.c42
-rw-r--r--ports/atmel-samd/boards/samd21x18-bootloader-crystalless.ld3
-rw-r--r--ports/atmel-samd/boards/samd21x18-bootloader-external-flash-crystalless.ld3
-rw-r--r--ports/atmel-samd/boards/samd21x18-bootloader-external-flash.ld3
-rw-r--r--ports/atmel-samd/boards/samd21x18-bootloader.ld3
-rw-r--r--ports/atmel-samd/boards/samd21x18-external-flash.ld1
-rw-r--r--ports/atmel-samd/boards/samd21x18.ld1
-rw-r--r--ports/atmel-samd/boards/samd51x18-bootloader-external-flash.ld3
-rw-r--r--ports/atmel-samd/boards/samd51x19-bootloader-external-flash.ld3
-rw-r--r--ports/atmel-samd/boards/samd51x19-bootloader.ld3
-rw-r--r--ports/atmel-samd/boards/samd51x20-bootloader-external-flash.ld3
-rw-r--r--ports/atmel-samd/boards/samd51x20-bootloader.ld3
-rw-r--r--ports/atmel-samd/boards/samd51x20-external-flash.ld1
-rw-r--r--ports/atmel-samd/boards/samd51x20.ld1
-rw-r--r--ports/atmel-samd/boards/trinket_m0_haxpress/mpconfigboard.mk3
-rw-r--r--ports/atmel-samd/boards/ugame/board.c37
-rw-r--r--ports/atmel-samd/boards/ugame/conf_access.h115
-rw-r--r--ports/atmel-samd/boards/ugame/conf_board.h14
-rw-r--r--ports/atmel-samd/boards/ugame/conf_clocks.h1
-rw-r--r--ports/atmel-samd/boards/ugame/conf_usb.h221
-rw-r--r--ports/atmel-samd/boards/ugame/mpconfigboard.h48
-rw-r--r--ports/atmel-samd/boards/ugame/mpconfigboard.mk11
-rw-r--r--ports/atmel-samd/boards/ugame/pins.c18
-rw-r--r--ports/atmel-samd/common-hal/analogio/AnalogIn.c9
-rw-r--r--ports/atmel-samd/common-hal/audiobusio/PDMIn.c185
-rw-r--r--ports/atmel-samd/common-hal/busio/SPI.c17
-rw-r--r--ports/atmel-samd/common-hal/digitalio/DigitalInOut.c14
-rw-r--r--ports/atmel-samd/common-hal/microcontroller/__init__.c30
-rw-r--r--ports/atmel-samd/reset.c27
-rw-r--r--ports/atmel-samd/reset.h10
-rw-r--r--ports/atmel-samd/shared_dma.c17
-rw-r--r--ports/atmel-samd/shared_dma.h1
-rw-r--r--ports/esp8266/Makefile1
-rw-r--r--ports/esp8266/common-hal/busio/SPI.c20
-rw-r--r--ports/esp8266/common-hal/digitalio/DigitalInOut.c14
-rw-r--r--ports/esp8266/common-hal/microcontroller/__init__.c18
-rw-r--r--ports/nrf/mpconfigport.mk3
-rw-r--r--py/makeversionhdr.py1
-rw-r--r--py/mkenv.mk1
-rw-r--r--py/mkrules.mk6
-rw-r--r--requirements.txt1
-rw-r--r--shared-bindings/_stage/Layer.c130
-rw-r--r--shared-bindings/_stage/Layer.h34
-rw-r--r--shared-bindings/_stage/Text.c109
-rw-r--r--shared-bindings/_stage/Text.h34
-rw-r--r--shared-bindings/_stage/__init__.c97
-rw-r--r--shared-bindings/_stage/__init__.h32
-rw-r--r--shared-bindings/audiobusio/PDMIn.c53
-rw-r--r--shared-bindings/bitbangio/I2C.c7
-rw-r--r--shared-bindings/bitbangio/SPI.c11
-rw-r--r--shared-bindings/busio/I2C.c8
-rw-r--r--shared-bindings/busio/SPI.c92
-rw-r--r--shared-bindings/busio/SPI.h3
-rw-r--r--shared-bindings/digitalio/DigitalInOut.c14
-rw-r--r--shared-bindings/digitalio/DigitalInOut.h14
-rw-r--r--shared-bindings/digitalio/Direction.h4
-rw-r--r--shared-bindings/digitalio/DriveMode.h4
-rw-r--r--shared-bindings/digitalio/Pull.h4
-rw-r--r--shared-bindings/microcontroller/RunMode.c90
-rw-r--r--shared-bindings/microcontroller/RunMode.h47
-rw-r--r--shared-bindings/microcontroller/__init__.c44
-rw-r--r--shared-bindings/microcontroller/__init__.h5
-rw-r--r--shared-module/_stage/Layer.c105
-rw-r--r--shared-module/_stage/Layer.h48
-rw-r--r--shared-module/_stage/Text.c67
-rw-r--r--shared-module/_stage/Text.h46
-rw-r--r--shared-module/_stage/__init__.c76
-rw-r--r--shared-module/_stage/__init__.h42
-rwxr-xr-xtools/build_adafruit_bins.sh2
-rwxr-xr-xtools/preprocess_frozen_modules.py71
m---------tools/python-semver0
96 files changed, 3106 insertions, 196 deletions
diff --git a/.gitmodules b/.gitmodules
index fbb74f013..a7f31837a 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -26,6 +26,9 @@
[submodule "frozen/Adafruit_CircuitPython_BusDevice"]
path = frozen/Adafruit_CircuitPython_BusDevice
url = https://github.com/adafruit/Adafruit_CircuitPython_BusDevice.git
+[submodule "tools/python-semver"]
+ path = tools/python-semver
+ url = https://github.com/k-bx/python-semver.git
[submodule "lib/stm32lib"]
path = lib/stm32lib
url = https://github.com/micropython/stm32lib
diff --git a/.readthedocs.yml b/.readthedocs.yml
new file mode 100644
index 000000000..8b77f690a
--- /dev/null
+++ b/.readthedocs.yml
@@ -0,0 +1,2 @@
+python:
+ version: 3
diff --git a/docs/troubleshooting.rst b/docs/troubleshooting.rst
index 34ee392d2..1c7e87f61 100644
--- a/docs/troubleshooting.rst
+++ b/docs/troubleshooting.rst
@@ -15,19 +15,29 @@ This often happens on Windows when the ``CIRCUITPY`` disk is not safely ejected
before being reset by the button or being disconnected from USB. This can also
happen on Linux and Mac OSX but its less likely.
-.. caution:: Delete ``CIRCUITPY`` filesystem and reload CircuitPython.
+.. caution:: To erase and re-create ``CIRCUITPY`` (for example, to correct a corrupted filesystem),
+ follow one of the procedures below. It's important to note that **any files stored on the**
+ ``CIRCUITPY`` **drive will be erased**.
- To reload CircuitPython (for example, to correct a corrupted filesystem),
- follow the process below. It's important to note that **any files stored on the
- ``CIRCUITPY`` drive will be erased**.
+**For boards with** ``CIRCUITPY`` **stored on a separate SPI flash chip,
+such as Feather M0 Express, Metro M0 Express and Circuit Playground Express:**
-#. Download the appropriate flash erase uf2 from `here <https://github.com/adafruit/Adafruit_SPIFlash/tree/master/examples/flash_erase_express>`_.
+
+#. Download the appropriate flash .erase uf2 from `here <https://github.com/adafruit/Adafruit_SPIFlash/tree/master/examples/flash_erase_express>`_.
#. Double-click the reset button.
#. Copy the appropriate .uf2 to the xxxBOOT drive.
#. The on-board NeoPixel will turn blue, indicating the erase has started.
#. After about 15 seconds, the NexoPixel will start flashing green. If it flashes red, the erase failed.
#. Double-click again and load the appropriate `CircuitPython .uf2 <https://github.com/adafruit/circuitpython/releases/latest>`_.
+**For boards without SPI flash, such as Feather M0 Proto, Gemma M0 and, Trinket M0:**
+
+#. Download the appropriate erase .uf2 from `here <https://github.com/adafruit/Adafruit_Learning_System_Guides/tree/master/uf2_flash_erasers>`_.
+#. Double-click the reset button.
+#. Copy the appropriate .uf2 to the xxxBOOT drive.
+#. The boot LED will start pulsing again, and the xxxBOOT drive will appear again.
+#. Load the appropriate `CircuitPython .uf2 <https://github.com/adafruit/circuitpython/releases/latest>`_.
+
ValueError: Incompatible ``.mpy`` file.
---------------------------------------
@@ -35,9 +45,9 @@ This error occurs when importing a module that is stored as a ``mpy`` binary fil
(rather than a ``py`` text file) that was generated by a different version of
CircuitPython than the one its being loaded into. Most versions are compatible
but, rarely they aren't. In particular, the ``mpy`` binary format changed between
-CircuitPython versions 1.x and 2.x.
+CircuitPython versions 1.x and 2.x, and will change again between 2.x and 3.x.
-So, if you just upgraded to CircuitPython 2.x from 1.x you'll need to download a
+So, for instance, if you just upgraded to CircuitPython 2.x from 1.x you'll need to download a
newer version of the library that triggered the error on ``import``. They are
all available in the
`Adafruit bundle <https://github.com/adafruit/Adafruit_CircuitPython_Bundle/releases/latest>`_
diff --git a/lib/libm/nearbyintf.c b/lib/libm/nearbyintf.c
index 1bb44aa46..5ac3178b5 100644
--- a/lib/libm/nearbyintf.c
+++ b/lib/libm/nearbyintf.c
@@ -18,7 +18,7 @@ float nearbyintf(float x)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-equal"
if (y == 0)
-#pragma GCC diagnostic pop
return s ? -0.0f : 0.0f;
+#pragma GCC diagnostic pop
return y;
}
diff --git a/lib/utils/pyexec.c b/lib/utils/pyexec.c
index df93614a1..f96deb9e1 100644
--- a/lib/utils/pyexec.c
+++ b/lib/utils/pyexec.c
@@ -255,7 +255,8 @@ STATIC int pyexec_friendly_repl_process_char(int c) {
} else if (ret == CHAR_CTRL_B) {
// reset friendly REPL
mp_hal_stdout_tx_str("\r\n");
- mp_hal_stdout_tx_str("Adafruit CircuitPython " MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE "; " MICROPY_HW_BOARD_NAME " with " MICROPY_HW_MCU_NAME "\r\n");
+ mp_hal_stdout_tx_str(MICROPY_FULL_VERSION_INFO);
+ mp_hal_stdout_tx_str("\r\n");
// mp_hal_stdout_tx_str("Type \"help()\" for more information.\r\n");
goto input_restart;
} else if (ret == CHAR_CTRL_C) {
@@ -394,7 +395,9 @@ int pyexec_friendly_repl(void) {
#endif
friendly_repl_reset:
- mp_hal_stdout_tx_str("\r\nAdafruit CircuitPython " MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE "; " MICROPY_HW_BOARD_NAME " with " MICROPY_HW_MCU_NAME "\r\n");
+ mp_hal_stdout_tx_str("\r\n");
+ mp_hal_stdout_tx_str(MICROPY_FULL_VERSION_INFO);
+ mp_hal_stdout_tx_str("\r\n");
// mp_hal_stdout_tx_str("Type \"help()\" for more information.\r\n");
// to test ctrl-C
diff --git a/ports/atmel-samd/Makefile b/ports/atmel-samd/Makefile
index 7a842b9c6..f77910f6a 100644
--- a/ports/atmel-samd/Makefile
+++ b/ports/atmel-samd/Makefile
@@ -76,6 +76,9 @@ BASE_CFLAGS = \
-ffunction-sections \
-fdata-sections \
-fshort-enums \
+ -DCIRCUITPY_SOFTWARE_SAFE_MODE=0x0ADABEEF \
+ -DCIRCUITPY_CANARY_WORD=0xADAF00 \
+ -DCIRCUITPY_SAFE_RESTART_WORD=0xDEADBEEF \
--param max-inline-insns-single=500
# NDEBUG disables assert() statements. This reduces code size pretty dramatically, per tannewt.
@@ -312,6 +315,7 @@ SRC_BINDINGS_ENUMS = \
digitalio/Direction.c \
digitalio/DriveMode.c \
digitalio/Pull.c \
+ microcontroller/RunMode.c \
help.c \
math/__init__.c \
supervisor/__init__.c \
diff --git a/ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.h b/ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.h
index 8648980c0..6b86a6890 100644
--- a/ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.h
+++ b/ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.h
@@ -10,16 +10,29 @@
#define SPI_FLASH_BAUDRATE (8000000)
// On-board flash
-#define SPI_FLASH_MUX_SETTING SPI_SIGNAL_MUX_SETTING_E
-// Use default pinmux for the chip select since we manage it ourselves.
-#define SPI_FLASH_PAD0_PINMUX PINMUX_PA16D_SERCOM3_PAD0 // MISO
-#define SPI_FLASH_PAD1_PINMUX PINMUX_UNUSED // CS
-#define SPI_FLASH_PAD2_PINMUX PINMUX_PA20D_SERCOM3_PAD2 // MOSI
-#define SPI_FLASH_PAD3_PINMUX PINMUX_PA21D_SERCOM3_PAD3 // SCK
-
-#define SPI_FLASH_CS PIN_PB22
-#define SPI_FLASH_SERCOM SERCOM3
-
+#define SPI_FLASH_MOSI_PIN PIN_PA20
+#define SPI_FLASH_MISO_PIN PIN_PA16
+#define SPI_FLASH_SCK_PIN PIN_PA21
+#define SPI_FLASH_CS_PIN PIN_PB22
+
+#define SPI_FLASH_MOSI_PIN_FUNCTION PINMUX_PA20D_SERCOM3_PAD2
+#define SPI_FLASH_MISO_PIN_FUNCTION PINMUX_PA16D_SERCOM3_PAD0
+#define SPI_FLASH_SCK_PIN_FUNCTION PINMUX_PA21D_SERCOM3_PAD3
+#define SPI_FLASH_SERCOM SERCOM3
+#define SPI_FLASH_SERCOM_INDEX 5
+#define SPI_FLASH_MOSI_PAD 2
+#define SPI_FLASH_MISO_PAD 0
+#define SPI_FLASH_SCK_PAD 3
+
+// <o> Transmit Data Pinout
+// <0x0=>PAD[0,1]_DO_SCK
+// <0x1=>PAD[2,3]_DO_SCK
+// <0x2=>PAD[3,1]_DO_SCK
+// <0x3=>PAD[0,3]_DO_SCK
+#define SPI_FLASH_DOPO 1
+#define SPI_FLASH_DIPO 0 // same as MISO PAD
+
+// These are pins not to reset.
// PA24 and PA25 are USB.
#define MICROPY_PORT_A (PORT_PA16 | PORT_PA20 | PORT_PA21 | PORT_PA24 | PORT_PA25)
#define MICROPY_PORT_B (PORT_PB22)
@@ -27,8 +40,7 @@
#define SPEAKER_ENABLE_PIN (&pin_PA30)
-#include "internal_flash.h"
-//#include "spi_flash.h"
+#include "spi_flash.h"
// If you change this, then make sure to update the linker scripts as well to
// make sure you don't overwrite code.
diff --git a/ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.mk b/ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.mk
index 6e975fdc1..1834a0ebe 100644
--- a/ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.mk
+++ b/ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.mk
@@ -4,16 +4,13 @@ USB_PID = 0x8019
USB_PRODUCT = "CircuitPlayground Express"
USB_MANUFACTURER = "Adafruit Industries LLC"
-#SPI_FLASH_FILESYSTEM = 1
-INTERNAL_FLASH_FILESYSTEM = 1
+SPI_FLASH_FILESYSTEM = 1
CHIP_VARIANT = SAMD21G18A
CHIP_FAMILY = samd21
# Include these Python libraries in firmware.
-### TODO(halbert): disable some of these frozen modules; they don't fit in 3.0.0 build while internalfs
-### is in use
-###FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_BusDevice
-###FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_LIS3DH
-###FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_NeoPixel
-###FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_Thermistor
+FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_BusDevice
+FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_LIS3DH
+FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_NeoPixel
+FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_Thermistor
diff --git a/ports/atmel-samd/boards/feather_m0_supersized/board.c b/ports/atmel-samd/boards/feather_m0_supersized/board.c
new file mode 100644
index 000000000..c8e20206a
--- /dev/null
+++ b/ports/atmel-samd/boards/feather_m0_supersized/board.c
@@ -0,0 +1,38 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "boards/board.h"
+
+void board_init(void)
+{
+}
+
+bool board_requests_safe_mode(void) {
+ return false;
+}
+
+void reset_board(void) {
+}
diff --git a/ports/atmel-samd/boards/feather_m0_supersized/conf_access.h b/ports/atmel-samd/boards/feather_m0_supersized/conf_access.h
new file mode 100644
index 000000000..2326bfcdf
--- /dev/null
+++ b/ports/atmel-samd/boards/feather_m0_supersized/conf_access.h
@@ -0,0 +1,115 @@
+/**
+ * \file
+ *
+ * \brief Memory access control configuration file.
+ *
+ * Copyright (c) 2014-2015 Atmel Corporation. All rights reserved.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The name of Atmel may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 4. This software may only be redistributed and used in connection with an
+ * Atmel microcontroller product.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * \asf_license_stop
+ *
+ */
+/*
+ * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
+ */
+
+#ifndef _CONF_ACCESS_H_
+#define _CONF_ACCESS_H_
+
+#include "compiler.h"
+#include "board.h"
+
+
+/*! \name Activation of Logical Unit Numbers
+ */
+//! @{
+#define LUN_0 ENABLE //!< On-Chip Virtual Memory.
+#define LUN_1 DISABLE //!< AT45DBX Data Flash.
+#define LUN_2 DISABLE //!< SD/MMC Card over SPI.
+#define LUN_3 DISABLE //!< SD/MMC Card over MCI Slot 0.
+#define LUN_4 DISABLE
+#define LUN_5 DISABLE
+#define LUN_6 DISABLE
+#define LUN_7 DISABLE
+#define LUN_USB DISABLE //!< Host Mass-Storage Memory.
+//! @}
+
+/*! \name LUN 0 Definitions
+ */
+//! @{
+#define LUN_0_INCLUDE "access_vfs.h"
+#define Lun_0_test_unit_ready vfs_test_unit_ready
+#define Lun_0_read_capacity vfs_read_capacity
+#define Lun_0_unload NULL
+#define Lun_0_wr_protect vfs_wr_protect
+#define Lun_0_removal vfs_removal
+#define Lun_0_usb_read_10 vfs_usb_read_10
+#define Lun_0_usb_write_10 vfs_usb_write_10
+#define LUN_0_NAME "\"CircuitPython VFS[0]\""
+//! @}
+
+#define MEM_USB LUN_USB
+
+/*! \name Actions Associated with Memory Accesses
+ *
+ * Write here the action to associate with each memory access.
+ *
+ * \warning Be careful not to waste time in order not to disturb the functions.
+ */
+//! @{
+#define memory_start_read_action(nb_sectors)
+#define memory_stop_read_action()
+#define memory_start_write_action(nb_sectors)
+#define memory_stop_write_action()
+//! @}
+
+/*! \name Activation of Interface Features
+ */
+//! @{
+#define ACCESS_USB true //!< MEM <-> USB interface.
+#define ACCESS_MEM_TO_RAM false //!< MEM <-> RAM interface.
+#define ACCESS_STREAM false //!< Streaming MEM <-> MEM interface.
+#define ACCESS_STREAM_RECORD false //!< Streaming MEM <-> MEM interface in record mode.
+#define ACCESS_MEM_TO_MEM false //!< MEM <-> MEM interface.
+#define ACCESS_CODEC false //!< Codec interface.
+//! @}
+
+/*! \name Specific Options for Access Control
+ */
+//! @{
+#define GLOBAL_WR_PROTECT false //!< Management of a global write protection.
+//! @}
+
+
+#endif // _CONF_ACCESS_H_
diff --git a/ports/atmel-samd/boards/feather_m0_supersized/conf_board.h b/ports/atmel-samd/boards/feather_m0_supersized/conf_board.h
new file mode 100644
index 000000000..7b88c97fc
--- /dev/null
+++ b/ports/atmel-samd/boards/feather_m0_supersized/conf_board.h
@@ -0,0 +1,14 @@
+/**
+ * \file
+ *
+ * \brief User board configuration template
+ *
+ */
+/*
+ * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
+ */
+
+#ifndef CONF_BOARD_H
+#define CONF_BOARD_H
+
+#endif // CONF_BOARD_H
diff --git a/ports/atmel-samd/boards/feather_m0_supersized/conf_clocks.h b/ports/atmel-samd/boards/feather_m0_supersized/conf_clocks.h
new file mode 100644
index 000000000..d3f3e6496
--- /dev/null
+++ b/ports/atmel-samd/boards/feather_m0_supersized/conf_clocks.h
@@ -0,0 +1 @@
+#include "conf_clocks_external_32k.h"
diff --git a/ports/atmel-samd/boards/feather_m0_supersized/conf_usb.h b/ports/atmel-samd/boards/feather_m0_supersized/conf_usb.h
new file mode 100644
index 000000000..e5e59663c
--- /dev/null
+++ b/ports/atmel-samd/boards/feather_m0_supersized/conf_usb.h
@@ -0,0 +1,220 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "asf/common/services/usb/class/cdc/usb_protocol_cdc.h"
+
+#ifndef CONF_USB_H_INCLUDED
+#define CONF_USB_H_INCLUDED
+
+#define USB_DEVICE_MAJOR_VERSION 1
+#define USB_DEVICE_MINOR_VERSION 0
+#define USB_DEVICE_POWER 100 // Consumption on Vbus line (mA)
+#define USB_DEVICE_ATTR \
+ (USB_CONFIG_ATTR_BUS_POWERED)
+// (USB_CONFIG_ATTR_REMOTE_WAKEUP|USB_CONFIG_ATTR_SELF_POWERED)
+// (USB_CONFIG_ATTR_REMOTE_WAKEUP|USB_CONFIG_ATTR_BUS_POWERED)
+
+//! USB Device string definitions (Optional)
+#ifndef USB_DEVICE_MANUFACTURE_NAME
+# define USB_DEVICE_MANUFACTURE_NAME "Dave Astels"
+#endif
+
+#ifndef USB_DEVICE_PRODUCT_NAME
+# define USB_DEVICE_PRODUCT_NAME "Hacked Feather M0 Express with 8Mbyte SPI flash"
+#endif
+
+#define USB_DEVICE_GET_SERIAL_NAME_POINTER serial_number
+#define USB_DEVICE_GET_SERIAL_NAME_LENGTH 32
+extern char serial_number[USB_DEVICE_GET_SERIAL_NAME_LENGTH];
+
+//! Control endpoint size
+#define USB_DEVICE_EP_CTRL_SIZE 64
+
+//! Interfaces for this device (CDC COM + CDC DATA + MSC + HID mouse + HID kbd)
+#define USB_DEVICE_NB_INTERFACE 5
+
+// (3 | USB_EP_DIR_IN) // CDC Notify endpoint
+// (4 | USB_EP_DIR_IN) // CDC TX
+// (5 | USB_EP_DIR_OUT) // CDC RX
+// (1 | USB_EP_DIR_IN) // MSC IN
+// (2 | USB_EP_DIR_OUT) // MSC OUT
+// (6 | USB_EP_DIR_IN) // HID mouse report
+// (7 | USB_EP_DIR_IN) // HID keyboard report
+#define USB_DEVICE_MAX_EP 7
+
+#define UDI_CDC_PORT_NB 1
+#define UDI_CDC_ENABLE_EXT(port) mp_cdc_enable(port)
+extern bool mp_cdc_enable(uint8_t port);
+#define UDI_CDC_DISABLE_EXT(port) mp_cdc_disable(port)
+extern void mp_cdc_disable(uint8_t port);
+#define UDI_CDC_LOW_RATE
+
+#define UDI_CDC_DEFAULT_RATE 115200
+#define UDI_CDC_DEFAULT_STOPBITS CDC_STOP_BITS_1
+#define UDI_CDC_DEFAULT_PARITY CDC_PAR_NONE
+#define UDI_CDC_DEFAULT_DATABITS 8
+
+#define UDI_CDC_RX_NOTIFY(port) usb_rx_notify()
+void usb_rx_notify(void);
+#define UDI_CDC_SET_CODING_EXT(port,cfg) usb_coding_notify(port, cfg)
+void usb_coding_notify(uint8_t port, usb_cdc_line_coding_t* coding);
+#define UDI_CDC_SET_DTR_EXT(port,set) usb_dtr_notify(port, set)
+void usb_dtr_notify(uint8_t port, bool set);
+#define UDI_CDC_SET_RTS_EXT(port,set) usb_rts_notify(port, set)
+void usb_rts_notify(uint8_t port, bool set);
+
+/**
+ * USB CDC low level configuration
+ * In standalone these configurations are defined by the CDC module.
+ * For composite device, these configuration must be defined here
+ * @{
+ */
+//! Endpoint numbers definition
+
+#define UDI_CDC_COMM_EP_0 (3 | USB_EP_DIR_IN) // Notify endpoint
+#define UDI_CDC_DATA_EP_IN_0 (4 | USB_EP_DIR_IN) // TX
+#define UDI_CDC_DATA_EP_OUT_0 (5 | USB_EP_DIR_OUT) // RX
+
+//! Interface numbers
+#define UDI_CDC_COMM_IFACE_NUMBER_0 0
+#define UDI_CDC_DATA_IFACE_NUMBER_0 1
+
+/**
+ * Configuration of MSC interface
+ * @{
+ */
+//! Vendor name and Product version of MSC interface
+#define UDI_MSC_GLOBAL_VENDOR_ID \
+ 'A', 'T', 'M', 'E', 'L', ' ', ' ', ' '
+#define UDI_MSC_GLOBAL_PRODUCT_VERSION \
+ '1', '.', '0', '0'
+
+//! Interface callback definition
+#define UDI_MSC_ENABLE_EXT() mp_msc_enable()
+extern bool mp_msc_enable(void);
+#define UDI_MSC_DISABLE_EXT() mp_msc_disable()
+extern void mp_msc_disable(void);
+
+//! Enable id string of interface to add an extra USB string
+#define UDI_MSC_STRING_ID 5
+
+/**
+ * USB MSC low level configuration
+ * In standalone these configurations are defined by the MSC module.
+ * For composite device, these configuration must be defined here
+ * @{
+ */
+//! Endpoint numbers definition
+#define UDI_MSC_EP_IN (1 | USB_EP_DIR_IN)
+#define UDI_MSC_EP_OUT (2 | USB_EP_DIR_OUT)
+
+//! Interface number
+#define UDI_MSC_IFACE_NUMBER 2
+/**
+ * Configuration of HID Mouse interface
+ * @{
+ */
+//! Interface callback definition
+#define UDI_HID_MOUSE_ENABLE_EXT() mp_mouse_enable()
+extern bool mp_mouse_enable(void);
+#define UDI_HID_MOUSE_DISABLE_EXT() mp_mouse_disable()
+extern void mp_mouse_disable(void);
+
+//! Enable id string of interface to add an extra USB string
+#define UDI_HID_MOUSE_STRING_ID 6
+
+/**
+ * USB HID Mouse low level configuration
+ * In standalone these configurations are defined by the HID Mouse module.
+ * For composite device, these configuration must be defined here
+ * @{
+ */
+//! Endpoint numbers definition
+#define UDI_HID_MOUSE_EP_IN (6 | USB_EP_DIR_IN)
+
+//! Interface number
+#define UDI_HID_MOUSE_IFACE_NUMBER 3
+//@}
+//@}
+
+/**
+ * Configuration of HID Keyboard interface
+ * @{
+ */
+//! Interface callback definition
+#define UDI_HID_KBD_ENABLE_EXT() mp_keyboard_enable()
+extern bool mp_keyboard_enable(void);
+#define UDI_HID_KBD_DISABLE_EXT() mp_keyboard_disable()
+extern void mp_keyboard_disable(void);
+#define UDI_HID_KBD_CHANGE_LED(value) mp_keyboard_led(value)
+extern void mp_keyboard_led(uint8_t);
+
+//! Enable id string of interface to add an extra USB string
+#define UDI_HID_KBD_STRING_ID 7
+
+/**
+ * USB HID Keyboard low level configuration
+ * In standalone these configurations are defined by the HID Keyboard module.
+ * For composite device, these configuration must be defined here
+ * @{
+ */
+//! Endpoint numbers definition
+#define UDI_HID_KBD_EP_IN (7 | USB_EP_DIR_IN)
+
+//! Interface number
+#define UDI_HID_KBD_IFACE_NUMBER 4
+
+/**
+ * Description of Composite Device
+ * @{
+ */
+//! USB Interfaces descriptor structure
+#define UDI_COMPOSITE_DESC_T \
+ usb_iad_desc_t udi_cdc_iad; \
+ udi_cdc_comm_desc_t udi_cdc_comm; \
+ udi_cdc_data_desc_t udi_cdc_data; \
+ udi_msc_desc_t udi_msc; \
+ udi_hid_mouse_desc_t udi_hid_mouse; \
+ udi_hid_kbd_desc_t udi_hid_kbd
+
+//! USB Interfaces descriptor value for Full Speed
+#define UDI_COMPOSITE_DESC_FS \
+ .udi_cdc_iad = UDI_CDC_IAD_DESC_0, \
+ .udi_cdc_comm = UDI_CDC_COMM_DESC_0, \
+ .udi_cdc_data = UDI_CDC_DATA_DESC_0_FS, \
+ .udi_msc = UDI_MSC_DESC_FS, \
+ .udi_hid_mouse = UDI_HID_MOUSE_DESC, \
+ .udi_hid_kbd = UDI_HID_KBD_DESC
+
+//! USB Interfaces descriptor value for High Speed
+#define UDI_COMPOSITE_DESC_HS \
+ .udi_cdc_iad = UDI_CDC_IAD_DESC_0, \
+ .udi_cdc_comm = UDI_CDC_COMM_DESC_0, \
+ .udi_cdc_data = UDI_CDC_DATA_DESC_0_HS, \
+ .udi_msc = UDI_MSC_DESC_HS, \
+ .udi_hid_mouse = UDI_HID_MOUSE_DESC, \
+ .udi_hid_kbd = UDI_HID_KBD_DESC
+
+//! USB Interface APIs
+#define UDI_COMPOSITE_API \
+ &udi_api_cdc_comm, \
+ &udi_api_cdc_data, \
+ &udi_api_msc, \
+ &udi_api_hid_mouse, \
+ &udi_api_hid_kbd
+//@}
+
+/**
+ * USB Device Driver Configuration
+ * @{
+ */
+//@}
+
+//! The includes of classes and other headers must be done at the end of this file to avoid compile error
+#include "udi_cdc.h"
+#include "udi_msc.h"
+#include "udi_hid_mouse.h"
+#include "udi_hid_kbd.h"
+
+#endif
diff --git a/ports/atmel-samd/boards/feather_m0_supersized/mpconfigboard.h b/ports/atmel-samd/boards/feather_m0_supersized/mpconfigboard.h
new file mode 100644
index 000000000..8eb59d9a0
--- /dev/null
+++ b/ports/atmel-samd/boards/feather_m0_supersized/mpconfigboard.h
@@ -0,0 +1,34 @@
+/* Adafruit Feather M0 Express with an 8MB SPI flash instead of the usual 2MB */
+
+#define USB_REPL
+
+#define MICROPY_HW_BOARD_NAME "Hacked Feather M0 Express with 8Mbyte SPI flash"
+#define MICROPY_HW_MCU_NAME "samd21g18"
+
+#define MICROPY_HW_NEOPIXEL (&pin_PA06)
+
+// Salae reads 12mhz which is the limit even though we set it to the safer 8mhz.
+#define SPI_FLASH_BAUDRATE (8000000)
+
+#define SPI_FLASH_MUX_SETTING SPI_SIGNAL_MUX_SETTING_C
+#define SPI_FLASH_PAD0_PINMUX PINMUX_PA08D_SERCOM2_PAD0 // MOSI
+// Use default pinmux for the chip select since we manage it ourselves.
+#define SPI_FLASH_PAD1_PINMUX PINMUX_PA09D_SERCOM2_PAD1 // SCK
+#define SPI_FLASH_PAD2_PINMUX PINMUX_PA14C_SERCOM2_PAD2 // MISO
+#define SPI_FLASH_PAD3_PINMUX PINMUX_UNUSED // SCK
+#define SPI_FLASH_SERCOM SERCOM2
+
+#define SPI_FLASH_CS PIN_PA13
+
+#define MICROPY_PORT_A (PORT_PA06 | PORT_PA08 | PORT_PA09 | PORT_PA14 | PORT_PA13 | PORT_PA14 | PORT_PA24 | PORT_PA25)
+#define MICROPY_PORT_B ( 0 )
+
+#include "spi_flash.h"
+
+// If you change this, then make sure to update the linker scripts as well to
+// make sure you don't overwrite code.
+#define CIRCUITPY_INTERNAL_NVM_SIZE 256
+
+#define BOARD_FLASH_SIZE (0x00040000 - 0x2000 - CIRCUITPY_INTERNAL_NVM_SIZE)
+
+#include "flash_S25FL064L.h"
diff --git a/ports/atmel-samd/boards/feather_m0_supersized/mpconfigboard.mk b/ports/atmel-samd/boards/feather_m0_supersized/mpconfigboard.mk
new file mode 100644
index 000000000..340421f50
--- /dev/null
+++ b/ports/atmel-samd/boards/feather_m0_supersized/mpconfigboard.mk
@@ -0,0 +1,11 @@
+LD_FILE = boards/samd21x18-bootloader-external-flash.ld
+USB_VID = 0x239A
+USB_PID = 0x8023
+USB_PRODUCT = "Feather M0 Supersized"
+USB_MANUFACTURER = "Dave Astels"
+
+SPI_FLASH_FILESYSTEM = 1
+
+CHIP_VARIANT = SAMD21G18A
+CHIP_FAMILY = samd21
+
diff --git a/ports/atmel-samd/boards/feather_m0_supersized/pins.c b/ports/atmel-samd/boards/feather_m0_supersized/pins.c
new file mode 100644
index 000000000..c5c70ee5d
--- /dev/null
+++ b/ports/atmel-samd/boards/feather_m0_supersized/pins.c
@@ -0,0 +1,28 @@
+#include "samd21_pins.h"
+
+STATIC const mp_rom_map_elem_t board_global_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_PA02) },
+ { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_PB08) },
+ { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_PB09) },
+ { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_PA04) },
+ { MP_ROM_QSTR(MP_QSTR_A4), MP_ROM_PTR(&pin_PA05) },
+ { MP_ROM_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_PB02) },
+ { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_PB11) },
+ { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_PB10) },
+ { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_PA12) },
+ { MP_ROM_QSTR(MP_QSTR_D0), MP_ROM_PTR(&pin_PA11) },
+ { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_PA11) },
+ { MP_ROM_QSTR(MP_QSTR_D1), MP_ROM_PTR(&pin_PA10) },
+ { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_PA10) },
+ { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_PA22) },
+ { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_PA23) },
+ { MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_PA15) },
+ { MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_PA20) },
+ { MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_PA07) },
+ { MP_ROM_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_PA18) },
+ { MP_ROM_QSTR(MP_QSTR_D11), MP_ROM_PTR(&pin_PA16) },
+ { MP_ROM_QSTR(MP_QSTR_D12), MP_ROM_PTR(&pin_PA19) },
+ { MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_PA17) },
+ { MP_ROM_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_PA06) },
+};
+MP_DEFINE_CONST_DICT(board_module_globals, board_global_dict_table);
diff --git a/ports/atmel-samd/boards/flash_S25FL064L.h b/ports/atmel-samd/boards/flash_S25FL064L.h
new file mode 100644
index 000000000..40cfa4cf0
--- /dev/null
+++ b/ports/atmel-samd/boards/flash_S25FL064L.h
@@ -0,0 +1,55 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ * Copyright (c) 2017 Dave Astels
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_ATMEL_SAMD_BOARD_FLASH_S25FL064L_H
+#define MICROPY_INCLUDED_ATMEL_SAMD_BOARD_FLASH_S25FL064L_H
+
+// Settings for the Cypress (was Spansion) S25FL064L 8MiB SPI flash.
+// Datasheet: http://www.cypress.com/file/316661/download
+
+// The total flash size in bytes.
+#define SPI_FLASH_TOTAL_SIZE (1 << 23) // 8 MiB
+
+// The size of the smallest erase unit thats erased with command 0x20.
+#define SPI_FLASH_ERASE_SIZE (1 << 12) // 4 KiB
+
+// The size of a page that is programmed with page program command 0x02.
+#define SPI_FLASH_PAGE_SIZE (256) // 256 bytes
+
+// These are the first three response bytes to the JEDEC ID command 0x9f that is
+// used to confirm we're talking to the flash we expect.
+#ifndef SPI_FLASH_JEDEC_MANUFACTURER
+#define SPI_FLASH_JEDEC_MANUFACTURER 0x01
+#define SPI_FLASH_SECTOR_PROTECTION false
+#else
+#define SPI_FLASH_JEDEC_MANUFACTURER_2 0x013
+#define SPI_FLASH_SECTOR_PROTECTION_2 false
+#endif
+#define SPI_FLASH_JEDEC_MEMORY_TYPE 0x60
+#define SPI_FLASH_JEDEC_CAPACITY 0x17
+
+#endif // MICROPY_INCLUDED_ATMEL_SAMD_BOARD_FLASH_S25FL216K_H
diff --git a/ports/atmel-samd/boards/flash_W25Q80DV.h b/ports/atmel-samd/boards/flash_W25Q80DV.h
new file mode 100644
index 000000000..1e8003867
--- /dev/null
+++ b/ports/atmel-samd/boards/flash_W25Q80DV.h
@@ -0,0 +1,51 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_ATMEL_SAMD_BOARD_FLASH_W25Q80DV_H
+#define MICROPY_INCLUDED_ATMEL_SAMD_BOARD_FLASH_W25Q80DV_H
+
+// The total flash size in bytes.
+#define SPI_FLASH_TOTAL_SIZE (1 << 20) // 1 MiB
+
+// The size of the smallest erase unit thats erased with command 0x20.
+#define SPI_FLASH_ERASE_SIZE (1 << 12) // 4 KiB
+
+// The size of a page that is programmed with page program command 0x02.
+#define SPI_FLASH_PAGE_SIZE (256) // 256 bytes
+
+// These are the first three response bytes to the JEDEC ID command 0x9f that is
+// used to confirm we're talking to the flash we expect.
+#ifndef SPI_FLASH_JEDEC_MANUFACTURER
+#define SPI_FLASH_JEDEC_MANUFACTURER 0xef
+#define SPI_FLASH_SECTOR_PROTECTION false
+#else
+#define SPI_FLASH_JEDEC_MANUFACTURER_2 0xef
+#define SPI_FLASH_SECTOR_PROTECTION_2 false
+#endif
+#define SPI_FLASH_JEDEC_MEMORY_TYPE 0x40
+#define SPI_FLASH_JEDEC_CAPACITY 0x14
+
+#endif // MICROPY_INCLUDED_ATMEL_SAMD_BOARD_FLASH_W25Q80DV_H
diff --git a/ports/atmel-samd/boards/itsybitsy_m0/board.c b/ports/atmel-samd/boards/itsybitsy_m0/board.c
new file mode 100644
index 000000000..d7e856d61
--- /dev/null
+++ b/ports/atmel-samd/boards/itsybitsy_m0/board.c
@@ -0,0 +1,37 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "boards/board.h"
+
+void board_init(void) {
+}
+
+bool board_requests_safe_mode(void) {
+ return false;
+}
+
+void reset_board(void) {
+}
diff --git a/ports/atmel-samd/boards/itsybitsy_m0/conf_access.h b/ports/atmel-samd/boards/itsybitsy_m0/conf_access.h
new file mode 100644
index 000000000..25109b75c
--- /dev/null
+++ b/ports/atmel-samd/boards/itsybitsy_m0/conf_access.h
@@ -0,0 +1,115 @@
+/**
+ * \file
+ *
+ * \brief Memory access control configuration file.
+ *
+ * Copyright (c) 2014-2015 Atmel Corporation. All rights reserved.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The name of Atmel may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 4. This software may only be redistributed and used in connection with an
+ * Atmel microcontroller product.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * \asf_license_stop
+ *
+ */
+/*
+ * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
+ */
+
+#ifndef _CONF_ACCESS_H_
+#define _CONF_ACCESS_H_
+
+#include "compiler.h"
+#include "board.h"
+
+
+/*! \name Activation of Logical Unit Numbers
+ */
+//! @{
+#define LUN_0 ENABLE //!< On-Chip Virtual Memory.
+#define LUN_1 DISABLE //!< AT45DBX Data Flash.
+#define LUN_2 DISABLE //!< SD/MMC Card over SPI.
+#define LUN_3 DISABLE //!< SD/MMC Card over MCI Slot 0.
+#define LUN_4 DISABLE
+#define LUN_5 DISABLE
+#define LUN_6 DISABLE
+#define LUN_7 DISABLE
+#define LUN_USB DISABLE //!< Host Mass-Storage Memory.
+//! @}
+
+/*! \name LUN 0 Definitions
+ */
+//! @{
+#define LUN_0_INCLUDE "access_vfs.h"
+#define Lun_0_test_unit_ready vfs_test_unit_ready
+#define Lun_0_read_capacity vfs_read_capacity
+#define Lun_0_unload NULL
+#define Lun_0_wr_protect vfs_wr_protect
+#define Lun_0_removal vfs_removal
+#define Lun_0_usb_read_10 vfs_usb_read_10
+#define Lun_0_usb_write_10 vfs_usb_write_10
+#define LUN_0_NAME "\"MicroPython VFS[0]\""
+//! @}
+
+#define MEM_USB LUN_USB
+
+/*! \name Actions Associated with Memory Accesses
+ *
+ * Write here the action to associate with each memory access.
+ *
+ * \warning Be careful not to waste time in order not to disturb the functions.
+ */
+//! @{
+#define memory_start_read_action(nb_sectors)
+#define memory_stop_read_action()
+#define memory_start_write_action(nb_sectors)
+#define memory_stop_write_action()
+//! @}
+
+/*! \name Activation of Interface Features
+ */
+//! @{
+#define ACCESS_USB true //!< MEM <-> USB interface.
+#define ACCESS_MEM_TO_RAM false //!< MEM <-> RAM interface.
+#define ACCESS_STREAM false //!< Streaming MEM <-> MEM interface.
+#define ACCESS_STREAM_RECORD false //!< Streaming MEM <-> MEM interface in record mode.
+#define ACCESS_MEM_TO_MEM false //!< MEM <-> MEM interface.
+#define ACCESS_CODEC false //!< Codec interface.
+//! @}
+
+/*! \name Specific Options for Access Control
+ */
+//! @{
+#define GLOBAL_WR_PROTECT false //!< Management of a global write protection.
+//! @}
+
+
+#endif // _CONF_ACCESS_H_
diff --git a/ports/atmel-samd/boards/itsybitsy_m0/conf_board.h b/ports/atmel-samd/boards/itsybitsy_m0/conf_board.h
new file mode 100644
index 000000000..7b88c97fc
--- /dev/null
+++ b/ports/atmel-samd/boards/itsybitsy_m0/conf_board.h
@@ -0,0 +1,14 @@
+/**
+ * \file
+ *
+ * \brief User board configuration template
+ *
+ */
+/*
+ * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
+ */
+
+#ifndef CONF_BOARD_H
+#define CONF_BOARD_H
+
+#endif // CONF_BOARD_H
diff --git a/ports/atmel-samd/boards/itsybitsy_m0/conf_clocks.h b/ports/atmel-samd/boards/itsybitsy_m0/conf_clocks.h
new file mode 100644
index 000000000..9e4f7876b
--- /dev/null
+++ b/ports/atmel-samd/boards/itsybitsy_m0/conf_clocks.h
@@ -0,0 +1 @@
+#include "conf_clocks_crystalless.h"
diff --git a/ports/atmel-samd/boards/itsybitsy_m0/conf_usb.h b/ports/atmel-samd/boards/itsybitsy_m0/conf_usb.h
new file mode 100644
index 000000000..5e8a61b88
--- /dev/null
+++ b/ports/atmel-samd/boards/itsybitsy_m0/conf_usb.h
@@ -0,0 +1,221 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "asf/common/services/usb/class/cdc/usb_protocol_cdc.h"
+
+#ifndef CONF_USB_H_INCLUDED
+#define CONF_USB_H_INCLUDED
+
+#define USB_DEVICE_MAJOR_VERSION 1
+#define USB_DEVICE_MINOR_VERSION 0
+#define USB_DEVICE_POWER 100 // Consumption on Vbus line (mA)
+#define USB_DEVICE_ATTR \
+ (USB_CONFIG_ATTR_BUS_POWERED)
+// (USB_CONFIG_ATTR_REMOTE_WAKEUP|USB_CONFIG_ATTR_SELF_POWERED)
+// (USB_CONFIG_ATTR_REMOTE_WAKEUP|USB_CONFIG_ATTR_BUS_POWERED)
+
+//! USB Device string definitions (Optional)
+#ifndef USB_DEVICE_MANUFACTURE_NAME
+# define USB_DEVICE_MANUFACTURE_NAME "Adafruit Industries"
+#endif
+
+#ifndef USB_DEVICE_PRODUCT_NAME
+# define USB_DEVICE_PRODUCT_NAME "ItsyBitsy M0"
+#endif
+// #define USB_DEVICE_SERIAL_NAME "12...EF"
+#define USB_DEVICE_GET_SERIAL_NAME_POINTER serial_number
+#define USB_DEVICE_GET_SERIAL_NAME_LENGTH 32
+extern char serial_number[USB_DEVICE_GET_SERIAL_NAME_LENGTH];
+
+//! Control endpoint size
+#define USB_DEVICE_EP_CTRL_SIZE 64
+
+//! Interfaces for this device (CDC COM + CDC DATA + MSC + HID mouse + HID kbd)
+#define USB_DEVICE_NB_INTERFACE 5
+
+// (3 | USB_EP_DIR_IN) // CDC Notify endpoint
+// (4 | USB_EP_DIR_IN) // CDC TX
+// (5 | USB_EP_DIR_OUT) // CDC RX
+// (1 | USB_EP_DIR_IN) // MSC IN
+// (2 | USB_EP_DIR_OUT) // MSC OUT
+// (6 | USB_EP_DIR_IN) // HID mouse report
+// (7 | USB_EP_DIR_IN) // HID keyboard report
+#define USB_DEVICE_MAX_EP 7
+
+#define UDI_CDC_PORT_NB 1
+#define UDI_CDC_ENABLE_EXT(port) mp_cdc_enable(port)
+extern bool mp_cdc_enable(uint8_t port);
+#define UDI_CDC_DISABLE_EXT(port) mp_cdc_disable(port)
+extern void mp_cdc_disable(uint8_t port);
+#define UDI_CDC_LOW_RATE
+
+#define UDI_CDC_DEFAULT_RATE 115200
+#define UDI_CDC_DEFAULT_STOPBITS CDC_STOP_BITS_1
+#define UDI_CDC_DEFAULT_PARITY CDC_PAR_NONE
+#define UDI_CDC_DEFAULT_DATABITS 8
+
+#define UDI_CDC_RX_NOTIFY(port) usb_rx_notify()
+void usb_rx_notify(void);
+
+#define UDI_CDC_SET_CODING_EXT(port,cfg) usb_coding_notify(port, cfg)
+void usb_coding_notify(uint8_t port, usb_cdc_line_coding_t* coding);
+#define UDI_CDC_SET_DTR_EXT(port,set) usb_dtr_notify(port, set)
+void usb_dtr_notify(uint8_t port, bool set);
+#define UDI_CDC_SET_RTS_EXT(port,set) usb_rts_notify(port, set)
+void usb_rts_notify(uint8_t port, bool set);
+
+/**
+ * USB CDC low level configuration
+ * In standalone these configurations are defined by the CDC module.
+ * For composite device, these configuration must be defined here
+ * @{
+ */
+//! Endpoint numbers definition
+
+#define UDI_CDC_COMM_EP_0 (3 | USB_EP_DIR_IN) // Notify endpoint
+#define UDI_CDC_DATA_EP_IN_0 (4 | USB_EP_DIR_IN) // TX
+#define UDI_CDC_DATA_EP_OUT_0 (5 | USB_EP_DIR_OUT) // RX
+
+//! Interface numbers
+#define UDI_CDC_COMM_IFACE_NUMBER_0 0
+#define UDI_CDC_DATA_IFACE_NUMBER_0 1
+
+/**
+ * Configuration of MSC interface
+ * @{
+ */
+//! Vendor name and Product version of MSC interface
+#define UDI_MSC_GLOBAL_VENDOR_ID \
+ 'A', 'T', 'M', 'E', 'L', ' ', ' ', ' '
+#define UDI_MSC_GLOBAL_PRODUCT_VERSION \
+ '1', '.', '0', '0'
+
+//! Interface callback definition
+#define UDI_MSC_ENABLE_EXT() mp_msc_enable()
+extern bool mp_msc_enable(void);
+#define UDI_MSC_DISABLE_EXT() mp_msc_disable()
+extern void mp_msc_disable(void);
+
+//! Enable id string of interface to add an extra USB string
+#define UDI_MSC_STRING_ID 5
+
+/**
+ * USB MSC low level configuration
+ * In standalone these configurations are defined by the MSC module.
+ * For composite device, these configuration must be defined here
+ * @{
+ */
+//! Endpoint numbers definition
+#define UDI_MSC_EP_IN (1 | USB_EP_DIR_IN)
+#define UDI_MSC_EP_OUT (2 | USB_EP_DIR_OUT)
+
+//! Interface number
+#define UDI_MSC_IFACE_NUMBER 2
+/**
+ * Configuration of HID Mouse interface
+ * @{
+ */
+//! Interface callback definition
+#define UDI_HID_MOUSE_ENABLE_EXT() mp_mouse_enable()
+extern bool mp_mouse_enable(void);
+#define UDI_HID_MOUSE_DISABLE_EXT() mp_mouse_disable()
+extern void mp_mouse_disable(void);
+
+//! Enable id string of interface to add an extra USB string
+#define UDI_HID_MOUSE_STRING_ID 6
+
+/**
+ * USB HID Mouse low level configuration
+ * In standalone these configurations are defined by the HID Mouse module.
+ * For composite device, these configuration must be defined here
+ * @{
+ */
+//! Endpoint numbers definition
+#define UDI_HID_MOUSE_EP_IN (6 | USB_EP_DIR_IN)
+
+//! Interface number
+#define UDI_HID_MOUSE_IFACE_NUMBER 3
+//@}
+//@}
+
+/**
+ * Configuration of HID Keyboard interface
+ * @{
+ */
+//! Interface callback definition
+#define UDI_HID_KBD_ENABLE_EXT() mp_keyboard_enable()
+extern bool mp_keyboard_enable(void);
+#define UDI_HID_KBD_DISABLE_EXT() mp_keyboard_disable()
+extern void mp_keyboard_disable(void);
+#define UDI_HID_KBD_CHANGE_LED(value) mp_keyboard_led(value)
+extern void mp_keyboard_led(uint8_t);
+
+//! Enable id string of interface to add an extra USB string
+#define UDI_HID_KBD_STRING_ID 7
+
+/**
+ * USB HID Keyboard low level configuration
+ * In standalone these configurations are defined by the HID Keyboard module.
+ * For composite device, these configuration must be defined here
+ * @{
+ */
+//! Endpoint numbers definition
+#define UDI_HID_KBD_EP_IN (7 | USB_EP_DIR_IN)
+
+//! Interface number
+#define UDI_HID_KBD_IFACE_NUMBER 4
+
+/**
+ * Description of Composite Device
+ * @{
+ */
+//! USB Interfaces descriptor structure
+#define UDI_COMPOSITE_DESC_T \
+ usb_iad_desc_t udi_cdc_iad; \
+ udi_cdc_comm_desc_t udi_cdc_comm; \
+ udi_cdc_data_desc_t udi_cdc_data; \
+ udi_msc_desc_t udi_msc; \
+ udi_hid_mouse_desc_t udi_hid_mouse; \
+ udi_hid_kbd_desc_t udi_hid_kbd
+
+//! USB Interfaces descriptor value for Full Speed
+#define UDI_COMPOSITE_DESC_FS \
+ .udi_cdc_iad = UDI_CDC_IAD_DESC_0, \
+ .udi_cdc_comm = UDI_CDC_COMM_DESC_0, \
+ .udi_cdc_data = UDI_CDC_DATA_DESC_0_FS, \
+ .udi_msc = UDI_MSC_DESC_FS, \
+ .udi_hid_mouse = UDI_HID_MOUSE_DESC, \
+ .udi_hid_kbd = UDI_HID_KBD_DESC
+
+//! USB Interfaces descriptor value for High Speed
+#define UDI_COMPOSITE_DESC_HS \
+ .udi_cdc_iad = UDI_CDC_IAD_DESC_0, \
+ .udi_cdc_comm = UDI_CDC_COMM_DESC_0, \
+ .udi_cdc_data = UDI_CDC_DATA_DESC_0_HS, \
+ .udi_msc = UDI_MSC_DESC_HS, \
+ .udi_hid_mouse = UDI_HID_MOUSE_DESC, \
+ .udi_hid_kbd = UDI_HID_KBD_DESC
+
+//! USB Interface APIs
+#define UDI_COMPOSITE_API \
+ &udi_api_cdc_comm, \
+ &udi_api_cdc_data, \
+ &udi_api_msc, \
+ &udi_api_hid_mouse, \
+ &udi_api_hid_kbd
+//@}
+
+/**
+ * USB Device Driver Configuration
+ * @{
+ */
+//@}
+
+//! The includes of classes and other headers must be done at the end of this file to avoid compile error
+#include "udi_cdc.h"
+#include "udi_msc.h"
+#include "udi_hid_mouse.h"
+#include "udi_hid_kbd.h"
+
+#endif
diff --git a/ports/atmel-samd/boards/itsybitsy_m0/mpconfigboard.h b/ports/atmel-samd/boards/itsybitsy_m0/mpconfigboard.h
new file mode 100644
index 000000000..e9fd08a5f
--- /dev/null
+++ b/ports/atmel-samd/boards/itsybitsy_m0/mpconfigboard.h
@@ -0,0 +1,36 @@
+#define USB_REPL
+
+#define MICROPY_HW_BOARD_NAME "Adafruit ItsyBitsy M0"
+#define MICROPY_HW_MCU_NAME "samd21g18"
+
+#define CIRCUITPY_BITBANG_APA102
+#define MICROPY_HW_APA102_MOSI (&pin_PA01)
+#define MICROPY_HW_APA102_SCK (&pin_PA00)
+
+#define MICROPY_PORT_A (PORT_PA00 | PORT_PA01 | PORT_PA27 | PORT_PA24 | PORT_PA25)
+#define MICROPY_PORT_B (PORT_PB22 | PORT_PB23 | PORT_PB03 )
+
+// Salae reads 12mhz which is the limit even though we set it to the safer 8mhz.
+#define SPI_FLASH_BAUDRATE (8000000)
+
+#define SPI_FLASH_MUX_SETTING SPI_SIGNAL_MUX_SETTING_F
+#define SPI_FLASH_PAD2_PINMUX PINMUX_PB22D_SERCOM5_PAD2 // MOSI
+// Use default pinmux for the chip select since we manage it ourselves.
+#define SPI_FLASH_PAD3_PINMUX PINMUX_PB23D_SERCOM5_PAD3 // SCK
+#define SPI_FLASH_PAD1_PINMUX PINMUX_PB03D_SERCOM5_PAD1 // MISO
+#define SPI_FLASH_PAD0_PINMUX PINMUX_UNUSED //
+#define SPI_FLASH_SERCOM SERCOM5
+
+#define SPI_FLASH_CS PIN_PA27
+
+
+#include "spi_flash.h"
+
+// If you change this, then make sure to update the linker scripts as well to
+// make sure you don't overwrite code.
+#define CIRCUITPY_INTERNAL_NVM_SIZE 256
+#define BOARD_FLASH_SIZE (0x00040000 - 0x2000 - CIRCUITPY_INTERNAL_NVM_SIZE)
+
+//#include "flash_S25FL216K.h"
+#include "flash_W25Q80DV.h"
+//#include "flash_GD25Q16C.h"
diff --git a/ports/atmel-samd/boards/itsybitsy_m0/mpconfigboard.mk b/ports/atmel-samd/boards/itsybitsy_m0/mpconfigboard.mk
new file mode 100644
index 000000000..0fb0e38ed
--- /dev/null
+++ b/ports/atmel-samd/boards/itsybitsy_m0/mpconfigboard.mk
@@ -0,0 +1,11 @@
+LD_FILE = boards/samd21x18-bootloader-external-flash-crystalless.ld
+USB_VID = 0x239A
+USB_PID = 0x8012
+USB_PRODUCT = "Itsy Bitsy M0 Express"
+USB_MANUFACTURER = "Adafruit Industries LLC"
+
+SPI_FLASH_FILESYSTEM = 1
+
+CHIP_VARIANT = SAMD21G18A
+CHIP_FAMILY = samd21
+
diff --git a/ports/atmel-samd/boards/itsybitsy_m0/pins.c b/ports/atmel-samd/boards/itsybitsy_m0/pins.c
new file mode 100644
index 000000000..b70bb6a76
--- /dev/null
+++ b/ports/atmel-samd/boards/itsybitsy_m0/pins.c
@@ -0,0 +1,42 @@
+#include "samd21_pins.h"
+
+STATIC const mp_rom_map_elem_t board_global_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_D0), MP_ROM_PTR(&pin_PA11) },
+ { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_PA11) },
+
+ { MP_ROM_QSTR(MP_QSTR_D1), MP_ROM_PTR(&pin_PA10) },
+ { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_PA10) },
+
+ { MP_ROM_QSTR(MP_QSTR_D2), MP_ROM_PTR(&pin_PA14) },
+ { MP_ROM_QSTR(MP_QSTR_D3), MP_ROM_PTR(&pin_PA09) },
+ { MP_ROM_QSTR(MP_QSTR_D4), MP_ROM_PTR(&pin_PA08) },
+ { MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_PA15) },
+ { MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_PA20) },
+ { MP_ROM_QSTR(MP_QSTR_D7), MP_ROM_PTR(&pin_PA21) },
+ { MP_ROM_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_PA06) },
+ { MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_PA07) },
+ { MP_ROM_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_PA18) },
+ { MP_ROM_QSTR(MP_QSTR_D11), MP_ROM_PTR(&pin_PA16) },
+ { MP_ROM_QSTR(MP_QSTR_D12), MP_ROM_PTR(&pin_PA19) },
+
+ { MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_PA17) },
+ { MP_ROM_QSTR(MP_QSTR_L), MP_ROM_PTR(&pin_PA17) }, // a.k.a D13
+
+ { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_PA02) },
+ { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_PB08) },
+ { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_PB09) },
+ { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_PA04) },
+ { MP_ROM_QSTR(MP_QSTR_A4), MP_ROM_PTR(&pin_PA05) },
+ { MP_ROM_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_PB02) },
+
+ { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_PB10) },
+ { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_PA12) },
+ { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_PB11) },
+
+ { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_PA23) },
+ { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_PA22) },
+
+ { MP_ROM_QSTR(MP_QSTR_APA102_MOSI), MP_ROM_PTR(&pin_PA01) },
+ { MP_ROM_QSTR(MP_QSTR_APA102_SCK), MP_ROM_PTR(&pin_PA00) },
+};
+MP_DEFINE_CONST_DICT(board_module_globals, board_global_dict_table);
diff --git a/ports/atmel-samd/boards/samd21x18-bootloader-crystalless.ld b/ports/atmel-samd/boards/samd21x18-bootloader-crystalless.ld
index 56ae5feb4..1d54bb88c 100644
--- a/ports/atmel-samd/boards/samd21x18-bootloader-crystalless.ld
+++ b/ports/atmel-samd/boards/samd21x18-bootloader-crystalless.ld
@@ -11,7 +11,8 @@ MEMORY
}
/* top end of the stack */
-_estack = ORIGIN(RAM) + LENGTH(RAM);
+_estack = ORIGIN(RAM) + LENGTH(RAM) - 4;
+_bootloader_dbl_tap = _estack;
/* define output sections */
SECTIONS
diff --git a/ports/atmel-samd/boards/samd21x18-bootloader-external-flash-crystalless.ld b/ports/atmel-samd/boards/samd21x18-bootloader-external-flash-crystalless.ld
index 1c0424747..81c1e8450 100644
--- a/ports/atmel-samd/boards/samd21x18-bootloader-external-flash-crystalless.ld
+++ b/ports/atmel-samd/boards/samd21x18-bootloader-external-flash-crystalless.ld
@@ -11,7 +11,8 @@ MEMORY
}
/* top end of the stack */
-_estack = ORIGIN(RAM) + LENGTH(RAM);
+_estack = ORIGIN(RAM) + LENGTH(RAM) - 4;
+_bootloader_dbl_tap = _estack;
/* define output sections */
SECTIONS
diff --git a/ports/atmel-samd/boards/samd21x18-bootloader-external-flash.ld b/ports/atmel-samd/boards/samd21x18-bootloader-external-flash.ld
index 4346c170c..8563ed3cb 100644
--- a/ports/atmel-samd/boards/samd21x18-bootloader-external-flash.ld
+++ b/ports/atmel-samd/boards/samd21x18-bootloader-external-flash.ld
@@ -10,7 +10,8 @@ MEMORY
}
/* top end of the stack */
-_estack = ORIGIN(RAM) + LENGTH(RAM);
+_estack = ORIGIN(RAM) + LENGTH(RAM) - 4;
+_bootloader_dbl_tap = _estack;
/* define output sections */
SECTIONS
diff --git a/ports/atmel-samd/boards/samd21x18-bootloader.ld b/ports/atmel-samd/boards/samd21x18-bootloader.ld
index 13a3f75c1..4d2005518 100644
--- a/ports/atmel-samd/boards/samd21x18-bootloader.ld
+++ b/ports/atmel-samd/boards/samd21x18-bootloader.ld
@@ -11,7 +11,8 @@ MEMORY
}
/* top end of the stack */
-_estack = ORIGIN(RAM) + LENGTH(RAM);
+_estack = ORIGIN(RAM) + LENGTH(RAM) - 4;
+_bootloader_dbl_tap = _estack;
/* define output sections */
SECTIONS
diff --git a/ports/atmel-samd/boards/samd21x18-external-flash.ld b/ports/atmel-samd/boards/samd21x18-external-flash.ld
index f5797cf6f..629e190b1 100644
--- a/ports/atmel-samd/boards/samd21x18-external-flash.ld
+++ b/ports/atmel-samd/boards/samd21x18-external-flash.ld
@@ -12,6 +12,7 @@ MEMORY
/* top end of the stack */
_estack = ORIGIN(RAM) + LENGTH(RAM);
+_bootloader_dbl_tap = 0;
/* define output sections */
SECTIONS
diff --git a/ports/atmel-samd/boards/samd21x18.ld b/ports/atmel-samd/boards/samd21x18.ld
index a68094758..9e318e948 100644
--- a/ports/atmel-samd/boards/samd21x18.ld
+++ b/ports/atmel-samd/boards/samd21x18.ld
@@ -12,6 +12,7 @@ MEMORY
/* top end of the stack */
_estack = ORIGIN(RAM) + LENGTH(RAM);
+_bootloader_dbl_tap = 0;
/* define output sections */
SECTIONS
diff --git a/ports/atmel-samd/boards/samd51x18-bootloader-external-flash.ld b/ports/atmel-samd/boards/samd51x18-bootloader-external-flash.ld
index f4ad37c20..73012b200 100644
--- a/ports/atmel-samd/boards/samd51x18-bootloader-external-flash.ld
+++ b/ports/atmel-samd/boards/samd51x18-bootloader-external-flash.ld
@@ -10,7 +10,8 @@ MEMORY
}
/* top end of the stack */
-_estack = ORIGIN(RAM) + LENGTH(RAM);
+_estack = ORIGIN(RAM) + LENGTH(RAM) - 4;
+_bootloader_dbl_tap = _estack;
/* define output sections */
SECTIONS
diff --git a/ports/atmel-samd/boards/samd51x19-bootloader-external-flash.ld b/ports/atmel-samd/boards/samd51x19-bootloader-external-flash.ld
index 4e4e8b002..c9247ec73 100644
--- a/ports/atmel-samd/boards/samd51x19-bootloader-external-flash.ld
+++ b/ports/atmel-samd/boards/samd51x19-bootloader-external-flash.ld
@@ -10,7 +10,8 @@ MEMORY
}
/* top end of the stack */
-_estack = ORIGIN(RAM) + LENGTH(RAM);
+_estack = ORIGIN(RAM) + LENGTH(RAM) - 4;
+_bootloader_dbl_tap = _estack;
/* define output sections */
SECTIONS
diff --git a/ports/atmel-samd/boards/samd51x19-bootloader.ld b/ports/atmel-samd/boards/samd51x19-bootloader.ld
index 63aada408..02f38f39f 100644
--- a/ports/atmel-samd/boards/samd51x19-bootloader.ld
+++ b/ports/atmel-samd/boards/samd51x19-bootloader.ld
@@ -10,7 +10,8 @@ MEMORY
}
/* top end of the stack */
-_estack = ORIGIN(RAM) + LENGTH(RAM);
+_estack = ORIGIN(RAM) + LENGTH(RAM) - 4;
+_bootloader_dbl_tap = _estack;
/* define output sections */
SECTIONS
diff --git a/ports/atmel-samd/boards/samd51x20-bootloader-external-flash.ld b/ports/atmel-samd/boards/samd51x20-bootloader-external-flash.ld
index 57bf299fb..bae25385a 100644
--- a/ports/atmel-samd/boards/samd51x20-bootloader-external-flash.ld
+++ b/ports/atmel-samd/boards/samd51x20-bootloader-external-flash.ld
@@ -10,7 +10,8 @@ MEMORY
}
/* top end of the stack */
-_estack = ORIGIN(RAM) + LENGTH(RAM);
+_estack = ORIGIN(RAM) + LENGTH(RAM) - 4;
+_bootloader_dbl_tap = _estack;
/* define output sections */
SECTIONS
diff --git a/ports/atmel-samd/boards/samd51x20-bootloader.ld b/ports/atmel-samd/boards/samd51x20-bootloader.ld
index 3d6621a5a..ee0dcfd7a 100644
--- a/ports/atmel-samd/boards/samd51x20-bootloader.ld
+++ b/ports/atmel-samd/boards/samd51x20-bootloader.ld
@@ -10,7 +10,8 @@ MEMORY
}
/* top end of the stack */
-_estack = ORIGIN(RAM) + LENGTH(RAM);
+_estack = ORIGIN(RAM) + LENGTH(RAM) - 4;
+_bootloader_dbl_tap = _estack;
/* define output sections */
SECTIONS
diff --git a/ports/atmel-samd/boards/samd51x20-external-flash.ld b/ports/atmel-samd/boards/samd51x20-external-flash.ld
index b0a118507..4889700a4 100644
--- a/ports/atmel-samd/boards/samd51x20-external-flash.ld
+++ b/ports/atmel-samd/boards/samd51x20-external-flash.ld
@@ -11,6 +11,7 @@ MEMORY
/* top end of the stack */
_estack = ORIGIN(RAM) + LENGTH(RAM);
+_bootloader_dbl_tap = 0;
/* define output sections */
SECTIONS
diff --git a/ports/atmel-samd/boards/samd51x20.ld b/ports/atmel-samd/boards/samd51x20.ld
index ed26425f3..a30f4525b 100644
--- a/ports/atmel-samd/boards/samd51x20.ld
+++ b/ports/atmel-samd/boards/samd51x20.ld
@@ -11,6 +11,7 @@ MEMORY
/* top end of the stack */
_estack = ORIGIN(RAM) + LENGTH(RAM);
+_bootloader_dbl_tap = 0;
/* define output sections */
SECTIONS
diff --git a/ports/atmel-samd/boards/trinket_m0_haxpress/mpconfigboard.mk b/ports/atmel-samd/boards/trinket_m0_haxpress/mpconfigboard.mk
index 04dc9e401..a904b2837 100644
--- a/ports/atmel-samd/boards/trinket_m0_haxpress/mpconfigboard.mk
+++ b/ports/atmel-samd/boards/trinket_m0_haxpress/mpconfigboard.mk
@@ -4,8 +4,7 @@ USB_PID = 0x801F
USB_PRODUCT="Trinket M0 Haxpress"
USB_MANUFACTURER="Radomir Dopieralski"
-#SPI_FLASH_FILESYSTEM = 1
-INTERNAL_FLASH_FILESYSTEM = 1
+SPI_FLASH_FILESYSTEM = 1
CHIP_VARIANT = SAMD21E18A
CHIP_FAMILY = samd21
diff --git a/ports/atmel-samd/boards/ugame/board.c b/ports/atmel-samd/boards/ugame/board.c
new file mode 100644
index 000000000..d7e856d61
--- /dev/null
+++ b/ports/atmel-samd/boards/ugame/board.c
@@ -0,0 +1,37 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "boards/board.h"
+
+void board_init(void) {
+}
+
+bool board_requests_safe_mode(void) {
+ return false;
+}
+
+void reset_board(void) {
+}
diff --git a/ports/atmel-samd/boards/ugame/conf_access.h b/ports/atmel-samd/boards/ugame/conf_access.h
new file mode 100644
index 000000000..2326bfcdf
--- /dev/null
+++ b/ports/atmel-samd/boards/ugame/conf_access.h
@@ -0,0 +1,115 @@
+/**
+ * \file
+ *
+ * \brief Memory access control configuration file.
+ *
+ * Copyright (c) 2014-2015 Atmel Corporation. All rights reserved.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The name of Atmel may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 4. This software may only be redistributed and used in connection with an
+ * Atmel microcontroller product.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * \asf_license_stop
+ *
+ */
+/*
+ * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
+ */
+
+#ifndef _CONF_ACCESS_H_
+#define _CONF_ACCESS_H_
+
+#include "compiler.h"
+#include "board.h"
+
+
+/*! \name Activation of Logical Unit Numbers
+ */
+//! @{
+#define LUN_0 ENABLE //!< On-Chip Virtual Memory.
+#define LUN_1 DISABLE //!< AT45DBX Data Flash.
+#define LUN_2 DISABLE //!< SD/MMC Card over SPI.
+#define LUN_3 DISABLE //!< SD/MMC Card over MCI Slot 0.
+#define LUN_4 DISABLE
+#define LUN_5 DISABLE
+#define LUN_6 DISABLE
+#define LUN_7 DISABLE
+#define LUN_USB DISABLE //!< Host Mass-Storage Memory.
+//! @}
+
+/*! \name LUN 0 Definitions
+ */
+//! @{
+#define LUN_0_INCLUDE "access_vfs.h"
+#define Lun_0_test_unit_ready vfs_test_unit_ready
+#define Lun_0_read_capacity vfs_read_capacity
+#define Lun_0_unload NULL
+#define Lun_0_wr_protect vfs_wr_protect
+#define Lun_0_removal vfs_removal
+#define Lun_0_usb_read_10 vfs_usb_read_10
+#define Lun_0_usb_write_10 vfs_usb_write_10
+#define LUN_0_NAME "\"CircuitPython VFS[0]\""
+//! @}
+
+#define MEM_USB LUN_USB
+
+/*! \name Actions Associated with Memory Accesses
+ *
+ * Write here the action to associate with each memory access.
+ *
+ * \warning Be careful not to waste time in order not to disturb the functions.
+ */
+//! @{
+#define memory_start_read_action(nb_sectors)
+#define memory_stop_read_action()
+#define memory_start_write_action(nb_sectors)
+#define memory_stop_write_action()
+//! @}
+
+/*! \name Activation of Interface Features
+ */
+//! @{
+#define ACCESS_USB true //!< MEM <-> USB interface.
+#define ACCESS_MEM_TO_RAM false //!< MEM <-> RAM interface.
+#define ACCESS_STREAM false //!< Streaming MEM <-> MEM interface.
+#define ACCESS_STREAM_RECORD false //!< Streaming MEM <-> MEM interface in record mode.
+#define ACCESS_MEM_TO_MEM false //!< MEM <-> MEM interface.
+#define ACCESS_CODEC false //!< Codec interface.
+//! @}
+
+/*! \name Specific Options for Access Control
+ */
+//! @{
+#define GLOBAL_WR_PROTECT false //!< Management of a global write protection.
+//! @}
+
+
+#endif // _CONF_ACCESS_H_
diff --git a/ports/atmel-samd/boards/ugame/conf_board.h b/ports/atmel-samd/boards/ugame/conf_board.h
new file mode 100644
index 000000000..7b88c97fc
--- /dev/null
+++ b/ports/atmel-samd/boards/ugame/conf_board.h
@@ -0,0 +1,14 @@
+/**
+ * \file
+ *
+ * \brief User board configuration template
+ *
+ */
+/*
+ * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
+ */
+
+#ifndef CONF_BOARD_H
+#define CONF_BOARD_H
+
+#endif // CONF_BOARD_H
diff --git a/ports/atmel-samd/boards/ugame/conf_clocks.h b/ports/atmel-samd/boards/ugame/conf_clocks.h
new file mode 100644
index 000000000..9e4f7876b
--- /dev/null
+++ b/ports/atmel-samd/boards/ugame/conf_clocks.h
@@ -0,0 +1 @@
+#include "conf_clocks_crystalless.h"
diff --git a/ports/atmel-samd/boards/ugame/conf_usb.h b/ports/atmel-samd/boards/ugame/conf_usb.h
new file mode 100644
index 000000000..b881ed149
--- /dev/null
+++ b/ports/atmel-samd/boards/ugame/conf_usb.h
@@ -0,0 +1,221 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "asf/common/services/usb/class/cdc/usb_protocol_cdc.h"
+
+#ifndef CONF_USB_H_INCLUDED
+#define CONF_USB_H_INCLUDED
+
+#define USB_DEVICE_MAJOR_VERSION 1
+#define USB_DEVICE_MINOR_VERSION 0
+#define USB_DEVICE_POWER 100 // Consumption on Vbus line (mA)
+#define USB_DEVICE_ATTR \
+ (USB_CONFIG_ATTR_BUS_POWERED)
+// (USB_CONFIG_ATTR_REMOTE_WAKEUP|USB_CONFIG_ATTR_SELF_POWERED)
+// (USB_CONFIG_ATTR_REMOTE_WAKEUP|USB_CONFIG_ATTR_BUS_POWERED)
+
+//! USB Device string definitions (Optional)
+#ifndef USB_DEVICE_MANUFACTURE_NAME
+# define USB_DEVICE_MANUFACTURE_NAME "Radomir Dopieralski"
+#endif
+
+#ifndef USB_DEVICE_PRODUCT_NAME
+# define USB_DEVICE_PRODUCT_NAME "uGame"
+#endif
+// #define USB_DEVICE_SERIAL_NAME "12...EF"
+#define USB_DEVICE_GET_SERIAL_NAME_POINTER serial_number
+#define USB_DEVICE_GET_SERIAL_NAME_LENGTH 32
+extern char serial_number[USB_DEVICE_GET_SERIAL_NAME_LENGTH];
+
+//! Control endpoint size
+#define USB_DEVICE_EP_CTRL_SIZE 64
+
+//! Interfaces for this device (CDC COM + CDC DATA + MSC + HID mouse + HID kbd)
+#define USB_DEVICE_NB_INTERFACE 5
+
+// (3 | USB_EP_DIR_IN) // CDC Notify endpoint
+// (4 | USB_EP_DIR_IN) // CDC TX
+// (5 | USB_EP_DIR_OUT) // CDC RX
+// (1 | USB_EP_DIR_IN) // MSC IN
+// (2 | USB_EP_DIR_OUT) // MSC OUT
+// (6 | USB_EP_DIR_IN) // HID mouse report
+// (7 | USB_EP_DIR_IN) // HID keyboard report
+#define USB_DEVICE_MAX_EP 7
+
+#define UDI_CDC_PORT_NB 1
+#define UDI_CDC_ENABLE_EXT(port) mp_cdc_enable(port)
+extern bool mp_cdc_enable(uint8_t port);
+#define UDI_CDC_DISABLE_EXT(port) mp_cdc_disable(port)
+extern void mp_cdc_disable(uint8_t port);
+#define UDI_CDC_LOW_RATE
+
+#define UDI_CDC_DEFAULT_RATE 115200
+#define UDI_CDC_DEFAULT_STOPBITS CDC_STOP_BITS_1
+#define UDI_CDC_DEFAULT_PARITY CDC_PAR_NONE
+#define UDI_CDC_DEFAULT_DATABITS 8
+
+#define UDI_CDC_RX_NOTIFY(port) usb_rx_notify()
+void usb_rx_notify(void);
+
+#define UDI_CDC_SET_CODING_EXT(port,cfg) usb_coding_notify(port, cfg)
+void usb_coding_notify(uint8_t port, usb_cdc_line_coding_t* coding);
+#define UDI_CDC_SET_DTR_EXT(port,set) usb_dtr_notify(port, set)
+void usb_dtr_notify(uint8_t port, bool set);
+#define UDI_CDC_SET_RTS_EXT(port,set) usb_rts_notify(port, set)
+void usb_rts_notify(uint8_t port, bool set);
+
+/**
+ * USB CDC low level configuration
+ * In standalone these configurations are defined by the CDC module.
+ * For composite device, these configuration must be defined here
+ * @{
+ */
+//! Endpoint numbers definition
+
+#define UDI_CDC_COMM_EP_0 (3 | USB_EP_DIR_IN) // Notify endpoint
+#define UDI_CDC_DATA_EP_IN_0 (4 | USB_EP_DIR_IN) // TX
+#define UDI_CDC_DATA_EP_OUT_0 (5 | USB_EP_DIR_OUT) // RX
+
+//! Interface numbers
+#define UDI_CDC_COMM_IFACE_NUMBER_0 0
+#define UDI_CDC_DATA_IFACE_NUMBER_0 1
+
+/**
+ * Configuration of MSC interface
+ * @{
+ */
+//! Vendor name and Product version of MSC interface
+#define UDI_MSC_GLOBAL_VENDOR_ID \
+ 'A', 'T', 'M', 'E', 'L', ' ', ' ', ' '
+#define UDI_MSC_GLOBAL_PRODUCT_VERSION \
+ '1', '.', '0', '0'
+
+//! Interface callback definition
+#define UDI_MSC_ENABLE_EXT() mp_msc_enable()
+extern bool mp_msc_enable(void);
+#define UDI_MSC_DISABLE_EXT() mp_msc_disable()
+extern void mp_msc_disable(void);
+
+//! Enable id string of interface to add an extra USB string
+#define UDI_MSC_STRING_ID 5
+
+/**
+ * USB MSC low level configuration
+ * In standalone these configurations are defined by the MSC module.
+ * For composite device, these configuration must be defined here
+ * @{
+ */
+//! Endpoint numbers definition
+#define UDI_MSC_EP_IN (1 | USB_EP_DIR_IN)
+#define UDI_MSC_EP_OUT (2 | USB_EP_DIR_OUT)
+
+//! Interface number
+#define UDI_MSC_IFACE_NUMBER 2
+/**
+ * Configuration of HID Mouse interface
+ * @{
+ */
+//! Interface callback definition
+#define UDI_HID_MOUSE_ENABLE_EXT() mp_mouse_enable()
+extern bool mp_mouse_enable(void);
+#define UDI_HID_MOUSE_DISABLE_EXT() mp_mouse_disable()
+extern void mp_mouse_disable(void);
+
+//! Enable id string of interface to add an extra USB string
+#define UDI_HID_MOUSE_STRING_ID 6
+
+/**
+ * USB HID Mouse low level configuration
+ * In standalone these configurations are defined by the HID Mouse module.
+ * For composite device, these configuration must be defined here
+ * @{
+ */
+//! Endpoint numbers definition
+#define UDI_HID_MOUSE_EP_IN (6 | USB_EP_DIR_IN)
+
+//! Interface number
+#define UDI_HID_MOUSE_IFACE_NUMBER 3
+//@}
+//@}
+
+/**
+ * Configuration of HID Keyboard interface
+ * @{
+ */
+//! Interface callback definition
+#define UDI_HID_KBD_ENABLE_EXT() mp_keyboard_enable()
+extern bool mp_keyboard_enable(void);
+#define UDI_HID_KBD_DISABLE_EXT() mp_keyboard_disable()
+extern void mp_keyboard_disable(void);
+#define UDI_HID_KBD_CHANGE_LED(value) mp_keyboard_led(value)
+extern void mp_keyboard_led(uint8_t);
+
+//! Enable id string of interface to add an extra USB string
+#define UDI_HID_KBD_STRING_ID 7
+
+/**
+ * USB HID Keyboard low level configuration
+ * In standalone these configurations are defined by the HID Keyboard module.
+ * For composite device, these configuration must be defined here
+ * @{
+ */
+//! Endpoint numbers definition
+#define UDI_HID_KBD_EP_IN (7 | USB_EP_DIR_IN)
+
+//! Interface number
+#define UDI_HID_KBD_IFACE_NUMBER 4
+
+/**
+ * Description of Composite Device
+ * @{
+ */
+//! USB Interfaces descriptor structure
+#define UDI_COMPOSITE_DESC_T \
+ usb_iad_desc_t udi_cdc_iad; \
+ udi_cdc_comm_desc_t udi_cdc_comm; \
+ udi_cdc_data_desc_t udi_cdc_data; \
+ udi_msc_desc_t udi_msc; \
+ udi_hid_mouse_desc_t udi_hid_mouse; \
+ udi_hid_kbd_desc_t udi_hid_kbd
+
+//! USB Interfaces descriptor value for Full Speed
+#define UDI_COMPOSITE_DESC_FS \
+ .udi_cdc_iad = UDI_CDC_IAD_DESC_0, \
+ .udi_cdc_comm = UDI_CDC_COMM_DESC_0, \
+ .udi_cdc_data = UDI_CDC_DATA_DESC_0_FS, \
+ .udi_msc = UDI_MSC_DESC_FS, \
+ .udi_hid_mouse = UDI_HID_MOUSE_DESC, \
+ .udi_hid_kbd = UDI_HID_KBD_DESC
+
+//! USB Interfaces descriptor value for High Speed
+#define UDI_COMPOSITE_DESC_HS \
+ .udi_cdc_iad = UDI_CDC_IAD_DESC_0, \
+ .udi_cdc_comm = UDI_CDC_COMM_DESC_0, \
+ .udi_cdc_data = UDI_CDC_DATA_DESC_0_HS, \
+ .udi_msc = UDI_MSC_DESC_HS, \
+ .udi_hid_mouse = UDI_HID_MOUSE_DESC, \
+ .udi_hid_kbd = UDI_HID_KBD_DESC
+
+//! USB Interface APIs
+#define UDI_COMPOSITE_API \
+ &udi_api_cdc_comm, \
+ &udi_api_cdc_data, \
+ &udi_api_msc, \
+ &udi_api_hid_mouse, \
+ &udi_api_hid_kbd
+//@}
+
+/**
+ * USB Device Driver Configuration
+ * @{
+ */
+//@}
+
+//! The includes of classes and other headers must be done at the end of this file to avoid compile error
+#include "udi_cdc.h"
+#include "udi_msc.h"
+#include "udi_hid_mouse.h"
+#include "udi_hid_kbd.h"
+
+#endif
diff --git a/ports/atmel-samd/boards/ugame/mpconfigboard.h b/ports/atmel-samd/boards/ugame/mpconfigboard.h
new file mode 100644
index 000000000..17baf9b0f
--- /dev/null
+++ b/ports/atmel-samd/boards/ugame/mpconfigboard.h
@@ -0,0 +1,48 @@
+#define USB_REPL
+
+#define MICROPY_HW_BOARD_NAME "uGame"
+#define MICROPY_HW_MCU_NAME "samd21e18"
+
+#if 1
+// Salae reads 12mhz which is the limit even though we set it to the
+// safer 8mhz.
+#define SPI_FLASH_BAUDRATE (8000000)
+
+#define SPI_FLASH_MUX_SETTING SPI_SIGNAL_MUX_SETTING_D
+#define SPI_FLASH_PAD0_PINMUX PINMUX_PA16D_SERCOM3_PAD0 // MOSI
+#define SPI_FLASH_PAD1_PINMUX PINMUX_PA17D_SERCOM3_PAD1 // SCK
+#define SPI_FLASH_PAD2_PINMUX PINMUX_UNUSED // Use default pinmux for the chip
+ // select since we manage it
+ // ourselves.
+#define SPI_FLASH_PAD3_PINMUX PINMUX_PA19D_SERCOM3_PAD3 // MISO
+#define SPI_FLASH_SERCOM SERCOM3
+
+#define SPI_FLASH_CS PIN_PA11
+
+#define MICROPY_PORT_A (PORT_PA11 | PORT_PA16 |\
+ PORT_PA17 | PORT_PA18 | PORT_PA19 | PORT_PA24 |\
+ PORT_PA25)
+#define MICROPY_PORT_B (0)
+
+#define CALIBRATE_CRYSTALLESS 1
+
+#include "spi_flash.h"
+
+#define CIRCUITPY_INTERNAL_NVM_SIZE 256
+#define BOARD_FLASH_SIZE (0x00040000 - 0x2000 - CIRCUITPY_INTERNAL_NVM_SIZE)
+
+//#include "flash_W25Q32BV.h"
+#include "flash_S25FL216K.h"
+
+#else
+
+#define MICROPY_PORT_A (PORT_PA24 | PORT_PA25)
+#define MICROPY_PORT_B (0)
+
+#include "internal_flash.h"
+
+#define CIRCUITPY_INTERNAL_NVM_SIZE 0
+#define BOARD_FLASH_SIZE (0x00040000 - 0x2000 - 0x010000)
+
+#endif
+
diff --git a/ports/atmel-samd/boards/ugame/mpconfigboard.mk b/ports/atmel-samd/boards/ugame/mpconfigboard.mk
new file mode 100644
index 000000000..40f1bc06f
--- /dev/null
+++ b/ports/atmel-samd/boards/ugame/mpconfigboard.mk
@@ -0,0 +1,11 @@
+LD_FILE = boards/samd21x18-bootloader-external-flash-crystalless.ld
+#LD_FILE = boards/samd21x18-bootloader.ld
+USB_VID = 0x239A
+USB_PID = 0x801F
+USB_PRODUCT = "UGame"
+USB_MANUFACTURER = "Radomir Dopieralski"
+
+SPI_FLASH_FILESYSTEM = 1
+
+CHIP_VARIANT = SAMD21E18A
+CHIP_FAMILY = samd21
diff --git a/ports/atmel-samd/boards/ugame/pins.c b/ports/atmel-samd/boards/ugame/pins.c
new file mode 100644
index 000000000..b9c8f2386
--- /dev/null
+++ b/ports/atmel-samd/boards/ugame/pins.c
@@ -0,0 +1,18 @@
+#include "samd21_pins.h"
+
+STATIC const mp_rom_map_elem_t board_global_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_X), MP_ROM_PTR(&pin_PA00) },
+ { MP_ROM_QSTR(MP_QSTR_O), MP_ROM_PTR(&pin_PA01) },
+
+ { MP_ROM_QSTR(MP_QSTR_SPEAKER), MP_ROM_PTR(&pin_PA02) },
+
+ { MP_ROM_QSTR(MP_QSTR_UP), MP_ROM_PTR(&pin_PA03) },
+ { MP_ROM_QSTR(MP_QSTR_LEFT), MP_ROM_PTR(&pin_PA04) },
+ { MP_ROM_QSTR(MP_QSTR_DOWN), MP_ROM_PTR(&pin_PA23) },
+ { MP_ROM_QSTR(MP_QSTR_RIGHT), MP_ROM_PTR(&pin_PA05) },
+
+ { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_PA06) },
+ { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_PA07) },
+ { MP_ROM_QSTR(MP_QSTR_DC), MP_ROM_PTR(&pin_PA08) },
+};
+MP_DEFINE_CONST_DICT(board_module_globals, board_global_dict_table);
diff --git a/ports/atmel-samd/common-hal/analogio/AnalogIn.c b/ports/atmel-samd/common-hal/analogio/AnalogIn.c
index 03c502dff..cbb9f5de5 100644
--- a/ports/atmel-samd/common-hal/analogio/AnalogIn.c
+++ b/ports/atmel-samd/common-hal/analogio/AnalogIn.c
@@ -74,8 +74,10 @@ uint16_t common_hal_analogio_analogin_get_value(analogio_analogin_obj_t *self) {
config_adc.reference = ADC_REFERENCE_INTVCC1;
config_adc.gain_factor = ADC_GAIN_FACTOR_DIV2;
config_adc.positive_input = self->pin->adc_input;
- config_adc.resolution = ADC_RESOLUTION_16BIT;
- config_adc.clock_prescaler = ADC_CLOCK_PRESCALER_DIV128;
+ config_adc.resolution = ADC_RESOLUTION_12BIT;
+ // Default input clock is GCLK0 (48 MHz)
+ // 48Mhz / 32 = 1.5MHz. Max ADC clock is 2.1MHz
+ config_adc.clock_prescaler = ADC_CLOCK_PRESCALER_DIV32;
struct adc_module adc_instance;
// ADC must have been disabled before adc_init() is called.
@@ -108,7 +110,8 @@ uint16_t common_hal_analogio_analogin_get_value(analogio_analogin_obj_t *self) {
}
adc_disable(&adc_instance);
- return data;
+ // Scale to 16 bits. In the future we might make this be this be under API control.
+ return data * 16;
}
float common_hal_analogio_analogin_get_reference_voltage(analogio_analogin_obj_t *self) {
diff --git a/ports/atmel-samd/common-hal/audiobusio/PDMIn.c b/ports/atmel-samd/common-hal/audiobusio/PDMIn.c
index db671f213..50d3b180c 100644
--- a/ports/atmel-samd/common-hal/audiobusio/PDMIn.c
+++ b/ports/atmel-samd/common-hal/audiobusio/PDMIn.c
@@ -26,6 +26,7 @@
#include <stdint.h>
#include <string.h>
+#include <math.h>
#include "py/gc.h"
#include "py/mperrno.h"
@@ -42,6 +43,12 @@
#include "shared_dma.h"
#include "tick.h"
+#define OVERSAMPLING 64
+#define SAMPLES_PER_BUFFER 32
+
+// MEMS microphones must be clocked at at least 1MHz.
+#define MIN_MIC_CLOCK 1000000
+
void pdmin_reset(void) {
while (I2S->SYNCBUSY.reg & I2S_SYNCBUSY_ENABLE) {}
I2S->INTENCLR.reg = I2S_INTENCLR_MASK;
@@ -96,8 +103,8 @@ void common_hal_audiobusio_pdmin_construct(audiobusio_pdmin_obj_t* self,
mp_raise_RuntimeError("Unable to allocate audio DMA block counter.");
}
- if (!(bit_depth == 16 || bit_depth == 8) || !mono || oversample != 64) {
- mp_raise_NotImplementedError("Only 8 or 16 bit mono with 64 oversample is supported.");
+ if (!(bit_depth == 16 || bit_depth == 8) || !mono || oversample != OVERSAMPLING) {
+ mp_raise_NotImplementedError("Only 8 or 16 bit mono with " MP_STRINGIFY(OVERSAMPLING) "x oversampling is supported.");
}
// TODO(tannewt): Use the DPLL to get a more precise sampling rate.
@@ -112,12 +119,17 @@ void common_hal_audiobusio_pdmin_construct(audiobusio_pdmin_obj_t* self,
config_clock_unit.clock.mck_out_enable = false;
config_clock_unit.clock.sck_src = I2S_SERIAL_CLOCK_SOURCE_MCKDIV;
- config_clock_unit.clock.sck_div = 8000000 / frequency / oversample;
- self->frequency = 8000000 / config_clock_unit.clock.sck_div / oversample;
+ uint32_t clock_divisor = (uint32_t) roundf( 8000000.0f / frequency / oversample);
+ config_clock_unit.clock.sck_div = clock_divisor;
+ float mic_clock_freq = 8000000.0f / clock_divisor;
+ self->frequency = mic_clock_freq / oversample;
+ if (mic_clock_freq < MIN_MIC_CLOCK || clock_divisor == 0 || clock_divisor > 255) {
+ mp_raise_ValueError("sampling frequency out of range");
+ }
config_clock_unit.frame.number_slots = 2;
config_clock_unit.frame.slot_size = I2S_SLOT_SIZE_16_BIT;
- config_clock_unit.frame.data_delay = I2S_DATA_DELAY_1;
+ config_clock_unit.frame.data_delay = I2S_DATA_DELAY_0;
config_clock_unit.frame.frame_sync.width = I2S_FRAME_SYNC_WIDTH_SLOT;
@@ -141,6 +153,10 @@ void common_hal_audiobusio_pdmin_construct(audiobusio_pdmin_obj_t* self,
i2s_serializer_set_config(&self->i2s_instance, self->serializer, &config_serializer);
i2s_enable(&self->i2s_instance);
+ // Run the serializer all the time. This eliminates startup delay for the microphone.
+ i2s_clock_unit_enable(&self->i2s_instance, self->clock_unit);
+ i2s_serializer_enable(&self->i2s_instance, self->serializer);
+
self->bytes_per_sample = oversample >> 3;
self->bit_depth = bit_depth;
}
@@ -154,6 +170,8 @@ void common_hal_audiobusio_pdmin_deinit(audiobusio_pdmin_obj_t* self) {
return;
}
i2s_disable(&self->i2s_instance);
+ i2s_serializer_disable(&self->i2s_instance, self->serializer);
+ i2s_clock_unit_disable(&self->i2s_instance, self->clock_unit);
i2s_reset(&self->i2s_instance);
reset_pin(self->clock_pin->pin);
reset_pin(self->data_pin->pin);
@@ -195,11 +213,15 @@ static void setup_dma(audiobusio_pdmin_obj_t* self, uint32_t length,
}
dma_descriptor_create(audio_dma.descriptor, &descriptor_config);
+ // Do we need more values than will fit in the first buffer?
+ // If so, set up a second buffer chained to be filled after the first buffer.
if (length * words_per_sample > words_per_buffer) {
block_transfer_count = words_per_buffer;
descriptor_config.next_descriptor_address = ((uint32_t)audio_dma.descriptor);
if (length * words_per_sample < 2 * words_per_buffer) {
- block_transfer_count = 2 * words_per_buffer - length * words_per_sample;
+ // Length needed is more than one buffer but less than two.
+ // Subtract off the size of the first buffer, and what remains is the count we need.
+ block_transfer_count = length * words_per_sample - words_per_buffer;
descriptor_config.next_descriptor_address = 0;
}
descriptor_config.block_transfer_count = block_transfer_count;
@@ -213,117 +235,150 @@ static void setup_dma(audiobusio_pdmin_obj_t* self, uint32_t length,
void start_dma(audiobusio_pdmin_obj_t* self) {
dma_start_transfer_job(&audio_dma);
tc_start_counter(MP_STATE_VM(audiodma_block_counter));
- i2s_clock_unit_enable(&self->i2s_instance, self->clock_unit);
- i2s_serializer_enable(&self->i2s_instance, self->serializer);
I2S->DATA[1].reg = I2S->DATA[1].reg;
}
void stop_dma(audiobusio_pdmin_obj_t* self) {
- // Turn off the I2S clock and serializer. Peripheral is still enabled.
- i2s_serializer_disable(&self->i2s_instance, self->serializer);
- i2s_clock_unit_disable(&self->i2s_instance, self->clock_unit);
-
- // Shutdown the DMA
+ // Shutdown the DMA: serializer keeps running.
tc_stop_counter(MP_STATE_VM(audiodma_block_counter));
dma_abort_job(&audio_dma);
}
-static const uint16_t sinc_filter[64] = {
- 0, 1, 6, 16, 29, 49, 75, 108,
- 149, 200, 261, 334, 418, 514, 622, 742,
- 872, 1012, 1161, 1315, 1472, 1631, 1787, 1938,
- 2081, 2212, 2329, 2429, 2509, 2568, 2604, 2616,
- 2604, 2568, 2509, 2429, 2329, 2212, 2081, 1938,
- 1787, 1631, 1472, 1315, 1161, 1012, 872, 742,
- 622, 514, 418, 334, 261, 200, 149, 108,
- 75, 49, 29, 16, 6, 1, 0, 0
+// a windowed sinc filter for 44 khz, 64 samples
+//
+// This filter is good enough to use for lower sample rates as
+// well. It does not increase the noise enough to be a problem.
+//
+// In the long run we could use a fast filter like this to do the
+// decimation and initial filtering in real time, filtering to a
+// higher sample rate than specified. Then after the audio is
+// recorded, a more expensive filter non-real-time filter could be
+// used to down-sample and low-pass.
+uint16_t sinc_filter [OVERSAMPLING] = {
+ 0, 2, 9, 21, 39, 63, 94, 132,
+ 179, 236, 302, 379, 467, 565, 674, 792,
+ 920, 1055, 1196, 1341, 1487, 1633, 1776, 1913,
+ 2042, 2159, 2263, 2352, 2422, 2474, 2506, 2516,
+ 2506, 2474, 2422, 2352, 2263, 2159, 2042, 1913,
+ 1776, 1633, 1487, 1341, 1196, 1055, 920, 792,
+ 674, 565, 467, 379, 302, 236, 179, 132,
+ 94, 63, 39, 21, 9, 2, 0, 0
};
+#define REPEAT_16_TIMES(X) X X X X X X X X X X X X X X X X
+
static uint16_t filter_sample(uint32_t pdm_samples[4]) {
- uint16_t sample = 0;
- for (uint8_t i = 0; i < 4; i++) {
- uint16_t pdm = pdm_samples[i] & 0xffff;
- for (uint8_t j = 0; j < 16; j++) {
- if ((pdm & 0x8000) != 0) {
- sample += sinc_filter[i * 16 + j];
+ uint16_t running_sum = 0;
+ const uint16_t *filter_ptr = sinc_filter;
+ for (uint8_t i = 0; i < OVERSAMPLING/16; i++) {
+ // The sample is 16-bits right channel in the upper two bytes and 16-bits left channel
+ // in the lower two bytes.
+ // We just ignore the upper bits
+ uint32_t pdm_sample = pdm_samples[i];
+ REPEAT_16_TIMES( {
+ if (pdm_sample & 0x8000) {
+ running_sum += *filter_ptr;
+ }
+ filter_ptr++;
+ pdm_sample <<= 1;
}
- pdm <<= 1;
- }
+ )
}
- return sample;
+ return running_sum;
}
+// output_buffer may be a byte buffer or a halfword buffer.
+// output_buffer_length is the number of slots, not the number of bytes.
uint32_t common_hal_audiobusio_pdmin_record_to_buffer(audiobusio_pdmin_obj_t* self,
- uint16_t* output_buffer, uint32_t length) {
- // Write the wave file header.
-
- // We allocate two 256 byte buffers on the stack to use for double buffering.
- // Our oversample rate is 64 (bits) so each buffer produces 32 samples.
- // TODO(tannewt): Can the compiler optimize better if we fix the size of
- // these buffers?
- uint8_t samples_per_buffer = 32;
+ uint16_t* output_buffer, uint32_t output_buffer_length) {
+ // We allocate two buffers on the stack to use for double buffering.
+ const uint8_t samples_per_buffer = SAMPLES_PER_BUFFER;
// For every word we record, we throw away 2 bytes of a phantom second channel.
- uint8_t words_per_sample = self->bytes_per_sample / 2;
- uint8_t words_per_buffer = samples_per_buffer * words_per_sample;
+ const uint8_t words_per_sample = self->bytes_per_sample / 2;
+ const uint8_t words_per_buffer = samples_per_buffer * words_per_sample;
uint32_t first_buffer[words_per_buffer];
uint32_t second_buffer[words_per_buffer];
COMPILER_ALIGNED(16) DmacDescriptor second_descriptor;
- setup_dma(self, length, &second_descriptor, words_per_buffer,
+ setup_dma(self, output_buffer_length, &second_descriptor, words_per_buffer,
words_per_sample, first_buffer, second_buffer);
start_dma(self);
// Record
uint32_t buffers_processed = 0;
- uint32_t total_bytes = 0;
+ uint32_t values_output = 0;
- uint64_t start_ticks = ticks_ms;
- while (total_bytes < length) {
+ uint32_t remaining_samples_needed = output_buffer_length;
+ while (values_output < output_buffer_length) {
// Wait for the next buffer to fill
- while (tc_get_count_value(MP_STATE_VM(audiodma_block_counter)) == buffers_processed) {
+ uint32_t block_counter;
+ while ((block_counter = tc_get_count_value(MP_STATE_VM(audiodma_block_counter))) == buffers_processed) {
#ifdef MICROPY_VM_HOOK_LOOP
MICROPY_VM_HOOK_LOOP
#endif
}
- if (tc_get_count_value(MP_STATE_VM(audiodma_block_counter)) != (buffers_processed + 1)) {
+ if (block_counter != (buffers_processed + 1)) {
+ // Looks like we aren't keeping up. We shouldn't skip a buffer.
break;
}
- // Throw away the first ~10ms of data because thats during mic start up.
- if (ticks_ms - start_ticks < 10) {
- buffers_processed++;
- continue;
- }
- uint32_t* buffer = first_buffer;
+
+ // The mic is running all the time, so we don't need to wait the usual 10msec or 100msec
+ // for it to start up.
+
+ // Flip back and forth between processing the first and second buffers.
+ uint32_t *buffer = first_buffer;
DmacDescriptor* descriptor = audio_dma.descriptor;
if (buffers_processed % 2 == 1) {
buffer = second_buffer;
descriptor = &second_descriptor;
}
- // Decimate and filter the last buffer
- int32_t samples_gathered = descriptor->BTCNT.reg / words_per_sample;
- for (uint16_t i = 0; i < samples_gathered; i++) {
+ // Decimate and filter the buffer that was just filled.
+ uint32_t samples_gathered = descriptor->BTCNT.reg / words_per_sample;
+ // Don't run off the end of output buffer. Process only as many as needed.
+ uint32_t samples_to_process = min(remaining_samples_needed, samples_gathered);
+ for (uint32_t i = 0; i < samples_to_process; i++) {
+ // Call filter_sample just one place so it can be inlined.
+ uint16_t value = filter_sample(buffer + i * words_per_sample);
if (self->bit_depth == 8) {
- ((uint8_t*) output_buffer)[total_bytes] = filter_sample(buffer + i * words_per_sample) >> 8;
- total_bytes += 1;
- } else if (self->bit_depth == 16) {
- output_buffer[total_bytes / 2] = filter_sample(buffer + i * words_per_sample);
- total_bytes += 2;
+ // Truncate to 8 bits.
+ ((uint8_t*) output_buffer)[values_output] = value >> 8;
+ } else {
+ output_buffer[values_output] = value;
}
+ values_output++;
}
+
buffers_processed++;
- if (length - total_bytes < samples_per_buffer) {
- descriptor->BTCNT.reg = (length - total_bytes) * words_per_sample;
- descriptor->DSTADDR.reg = ((uint32_t) buffer) + (length - total_bytes) * self->bytes_per_sample;
+ // Compute how many more samples we need, and if the last buffer is the last
+ // set of samples needed, adjust the DMA count to only fetch as necessary.
+ remaining_samples_needed = output_buffer_length - values_output;
+ if (remaining_samples_needed <= samples_per_buffer*2 &&
+ remaining_samples_needed > samples_per_buffer) {
+ // Adjust the DMA settings for the current buffer, which will be processed
+ // after the other buffer, which is now receiving samples via DMA.
+ // We don't adjust the DMA in progress, but the one after that.
+ // Timeline:
+ // 1. current buffer (already processed)
+ // 2. alternate buffer (DMA in progress)
+ // 3. current buffer (last set of samples needed)
+
+ // Set up to receive the last set of samples (don't include the alternate buffer, now in use).
+ uint32_t samples_needed_for_last_buffer = remaining_samples_needed - samples_per_buffer;
+ descriptor->BTCNT.reg = samples_needed_for_last_buffer * words_per_sample;
+ descriptor->DSTADDR.reg = ((uint32_t) buffer)
+ + samples_needed_for_last_buffer * words_per_sample * sizeof(buffer[0]);
+
+ // Break chain to alternate buffer.
descriptor->DESCADDR.reg = 0;
}
}
stop_dma(self);
- return total_bytes;
+ return values_output;
}
void common_hal_audiobusio_pdmin_record_to_file(audiobusio_pdmin_obj_t* self, uint8_t* buffer, uint32_t length) {
diff --git a/ports/atmel-samd/common-hal/busio/SPI.c b/ports/atmel-samd/common-hal/busio/SPI.c
index cb6a165de..4414d7ca9 100644
--- a/ports/atmel-samd/common-hal/busio/SPI.c
+++ b/ports/atmel-samd/common-hal/busio/SPI.c
@@ -262,3 +262,20 @@ bool common_hal_busio_spi_read(busio_spi_obj_t *self,
// }
return status >= 0; // Status is number of chars read or an error code < 0.
}
+
+bool common_hal_busio_spi_transfer(busio_spi_obj_t *self, uint8_t *data_out, uint8_t *data_in, size_t len) {
+ if (len == 0) {
+ return true;
+ }
+ int32_t status;
+// if (len >= 16) {
+// status = shared_dma_transfer(self->spi_master_instance.hw, data_out, data_in, len, 0 /*ignored*/);
+// } else {
+ struct spi_xfer xfer;
+ xfer.txbuf = data_out;
+ xfer.rxbuf = data_in;
+ xfer.size = len;
+ status = spi_m_sync_transfer(&self->spi_desc, &xfer);
+// }
+ return status >= 0; // Status is number of chars read or an error code < 0.
+}
diff --git a/ports/atmel-samd/common-hal/digitalio/DigitalInOut.c b/ports/atmel-samd/common-hal/digitalio/DigitalInOut.c
index c5fff4ba2..109f14b04 100644
--- a/ports/atmel-samd/common-hal/digitalio/DigitalInOut.c
+++ b/ports/atmel-samd/common-hal/digitalio/DigitalInOut.c
@@ -58,7 +58,7 @@ void common_hal_digitalio_digitalinout_deinit(digitalio_digitalinout_obj_t* self
}
void common_hal_digitalio_digitalinout_switch_to_input(
- digitalio_digitalinout_obj_t* self, enum digitalio_pull_t pull) {
+ digitalio_digitalinout_obj_t* self, digitalio_pull_t pull) {
self->output = false;
common_hal_digitalio_digitalinout_set_pull(self, pull);
@@ -66,7 +66,7 @@ void common_hal_digitalio_digitalinout_switch_to_input(
void common_hal_digitalio_digitalinout_switch_to_output(
digitalio_digitalinout_obj_t* self, bool value,
- enum digitalio_drive_mode_t drive_mode) {
+ digitalio_drive_mode_t drive_mode) {
const uint8_t pin = self->pin->pin;
gpio_set_pin_pull_mode(pin, GPIO_PULL_OFF);
gpio_set_pin_direction(pin, GPIO_DIRECTION_OUT);
@@ -79,7 +79,7 @@ void common_hal_digitalio_digitalinout_switch_to_output(
common_hal_digitalio_digitalinout_set_value(self, value);
}
-enum digitalio_direction_t common_hal_digitalio_digitalinout_get_direction(
+digitalio_direction_t common_hal_digitalio_digitalinout_get_direction(
digitalio_digitalinout_obj_t* self) {
return self->output? DIRECTION_OUTPUT : DIRECTION_INPUT;
}
@@ -115,7 +115,7 @@ bool common_hal_digitalio_digitalinout_get_value(
void common_hal_digitalio_digitalinout_set_drive_mode(
digitalio_digitalinout_obj_t* self,
- enum digitalio_drive_mode_t drive_mode) {
+ digitalio_drive_mode_t drive_mode) {
bool value = common_hal_digitalio_digitalinout_get_value(self);
self->open_drain = drive_mode == DRIVE_MODE_OPEN_DRAIN;
// True is implemented differently between modes so reset the value to make
@@ -125,7 +125,7 @@ void common_hal_digitalio_digitalinout_set_drive_mode(
}
}
-enum digitalio_drive_mode_t common_hal_digitalio_digitalinout_get_drive_mode(
+digitalio_drive_mode_t common_hal_digitalio_digitalinout_get_drive_mode(
digitalio_digitalinout_obj_t* self) {
if (self->open_drain) {
return DRIVE_MODE_OPEN_DRAIN;
@@ -135,7 +135,7 @@ enum digitalio_drive_mode_t common_hal_digitalio_digitalinout_get_drive_mode(
}
void common_hal_digitalio_digitalinout_set_pull(
- digitalio_digitalinout_obj_t* self, enum digitalio_pull_t pull) {
+ digitalio_digitalinout_obj_t* self, digitalio_pull_t pull) {
enum gpio_pull_mode asf_pull = GPIO_PULL_OFF;
switch (pull) {
case PULL_UP:
@@ -151,7 +151,7 @@ void common_hal_digitalio_digitalinout_set_pull(
gpio_set_pin_pull_mode(self->pin->pin, asf_pull);
}
-enum digitalio_pull_t common_hal_digitalio_digitalinout_get_pull(
+digitalio_pull_t common_hal_digitalio_digitalinout_get_pull(
digitalio_digitalinout_obj_t* self) {
uint32_t pin = self->pin->pin;
if (self->output) {
diff --git a/ports/atmel-samd/common-hal/microcontroller/__init__.c b/ports/atmel-samd/common-hal/microcontroller/__init__.c
index 5c119c439..614fac870 100644
--- a/ports/atmel-samd/common-hal/microcontroller/__init__.c
+++ b/ports/atmel-samd/common-hal/microcontroller/__init__.c
@@ -27,10 +27,13 @@
#include "py/mphal.h"
#include "py/obj.h"
#include "hal/include/hal_atomic.h"
+#include "py/runtime.h"
+#include "reset.h"
#include "samd21_pins.h"
#include "shared-bindings/nvm/ByteArray.h"
+#include "shared-bindings/microcontroller/__init__.h"
#include "shared-bindings/microcontroller/Processor.h"
void common_hal_mcu_delay_us(uint32_t delay) {
@@ -48,9 +51,32 @@ void common_hal_mcu_enable_interrupts(void) {
atomic_leave_critical(&flags);
}
+extern uint32_t _ezero;
+
+void common_hal_mcu_on_next_reset(mcu_runmode_t runmode) {
+ // Set up the defaults.
+ _bootloader_dbl_tap = DBL_TAP_MAGIC;
+ _ezero = CIRCUITPY_CANARY_WORD;
+
+ if (runmode == RUNMODE_BOOTLOADER) {
+ if (!bootloader_available()) {
+ mp_raise_ValueError("Cannot reset into bootloader because no bootloader is present.");
+ }
+ // Pretend to be the first of the two reset presses needed to enter the
+ // bootloader. That way one reset will end in the bootloader.
+ _bootloader_dbl_tap = DBL_TAP_MAGIC;
+ } else if (runmode == RUNMODE_SAFE_MODE) {
+ _ezero = CIRCUITPY_SOFTWARE_SAFE_MODE;
+ }
+}
+
+void common_hal_mcu_reset(void) {
+ reset();
+}
+
// The singleton microcontroller.Processor object, bound to microcontroller.cpu
// It currently only has properties, and no state.
-mcu_processor_obj_t common_hal_mcu_processor_obj = {
+const mcu_processor_obj_t common_hal_mcu_processor_obj = {
.base = {
.type = &mcu_processor_type,
},
@@ -59,7 +85,7 @@ mcu_processor_obj_t common_hal_mcu_processor_obj = {
// NVM is only available on Express boards for now.
#if CIRCUITPY_INTERNAL_NVM_SIZE > 0
// The singleton nvm.ByteArray object.
-// nvm_bytearray_obj_t common_hal_mcu_nvm_obj = {
+// const nvm_bytearray_obj_t common_hal_mcu_nvm_obj = {
// .base = {
// .type = &nvm_bytearray_type,
// },
diff --git a/ports/atmel-samd/reset.c b/ports/atmel-samd/reset.c
index ab940285b..ba5bf9ba1 100644
--- a/ports/atmel-samd/reset.c
+++ b/ports/atmel-samd/reset.c
@@ -24,23 +24,22 @@
* THE SOFTWARE.
*/
-#include "reset.h"
-
#include "include/sam.h"
-#include "supervisor/filesystem.h"
-// Copied from inc/uf2.h in https://github.com/Microsoft/uf2-samd21
-#ifdef SAMD21
-#define DBL_TAP_PTR ((volatile uint32_t *)(HMCRAMC0_ADDR + HMCRAMC0_SIZE - 4))
-#else
- #ifdef SAMD51
- #define DBL_TAP_PTR ((volatile uint32_t *)(HSRAM_ADDR + HSRAM_SIZE - 4))
- #endif
-#endif
-#define DBL_TAP_MAGIC 0xf01669ef // Randomly selected, adjusted to have first and last bit set
+#include "reset.h"
+#include "supervisor/filesystem.h"
-void reset_to_bootloader(void) {
+void reset(void) {
filesystem_flush();
- *DBL_TAP_PTR = DBL_TAP_MAGIC;
NVIC_SystemReset();
}
+
+void reset_to_bootloader(void) {
+ _bootloader_dbl_tap = DBL_TAP_MAGIC;
+ reset();
+}
+
+extern uint32_t _srelocate;
+bool bootloader_available(void) {
+ return &_bootloader_dbl_tap >= &_srelocate;
+}
diff --git a/ports/atmel-samd/reset.h b/ports/atmel-samd/reset.h
index 88140f3b8..ea955c655 100644
--- a/ports/atmel-samd/reset.h
+++ b/ports/atmel-samd/reset.h
@@ -26,6 +26,16 @@
#ifndef MICROPY_INCLUDED_ATMEL_SAMD_RESET_H
#define MICROPY_INCLUDED_ATMEL_SAMD_RESET_H
+#include <stdbool.h>
+#include <stdint.h>
+
+// Copied from inc/uf2.h in https://github.com/Microsoft/uf2-samd21
+#define DBL_TAP_MAGIC 0xf01669ef // Randomly selected, adjusted to have first and last bit set
+
+extern uint32_t _bootloader_dbl_tap;
+
void reset_to_bootloader(void);
+void reset(void);
+bool bootloader_available(void);
#endif // MICROPY_INCLUDED_ATMEL_SAMD_RESET_H
diff --git a/ports/atmel-samd/shared_dma.c b/ports/atmel-samd/shared_dma.c
index f8cef0992..59fca30c8 100644
--- a/ports/atmel-samd/shared_dma.c
+++ b/ports/atmel-samd/shared_dma.c
@@ -106,7 +106,7 @@ int32_t shared_dma_write(Sercom* sercom, const uint8_t* buffer, uint32_t length)
}
dma_configure(general_dma_tx.channel_id, sercom_index(sercom) * 2 + 2, false);
- // Set up TX second.
+ // Set up TX. There is no RX job.
struct dma_descriptor_config descriptor_config;
dma_descriptor_get_config_defaults(&descriptor_config);
descriptor_config.beat_size = DMA_BEAT_SIZE_BYTE;
@@ -141,6 +141,11 @@ int32_t shared_dma_write(Sercom* sercom, const uint8_t* buffer, uint32_t length)
int32_t shared_dma_read(Sercom* sercom, uint8_t* buffer, uint32_t length, uint8_t tx) {
if (general_dma_tx.job_status != ERR_NONE) {
+}
+
+// Do write and read simultaneously. If buffer_out is NULL, write the tx byte over and over.
+// If buffer_out is a real buffer, ignore tx.
+enum status_code shared_dma_transfer(Sercom* sercom, uint8_t* buffer_out, uint8_t* buffer_in, uint32_t length, uint8_t tx) {
return general_dma_tx.job_status;
}
@@ -156,17 +161,19 @@ int32_t shared_dma_read(Sercom* sercom, uint8_t* buffer, uint32_t length, uint8_
descriptor_config.block_transfer_count = length;
// DATA register is consistently addressed across all SERCOM modes.
descriptor_config.source_address = ((uint32_t)&sercom->SPI.DATA.reg);
- descriptor_config.destination_address = ((uint32_t)buffer + length);
+ descriptor_config.destination_address = ((uint32_t)buffer_in + length);
dma_descriptor_create(general_dma_rx.descriptor, &descriptor_config);
- // Set up TX to retransmit the same byte over and over.
+ // Set up TX second.
dma_descriptor_get_config_defaults(&descriptor_config);
descriptor_config.beat_size = DMA_BEAT_SIZE_BYTE;
- descriptor_config.src_increment_enable = false;
+ // Increment write address only if we have a real buffer.
+ descriptor_config.src_increment_enable = buffer_out != NULL;
descriptor_config.dst_increment_enable = false;
descriptor_config.block_transfer_count = length;
- descriptor_config.source_address = ((uint32_t)&tx);
+ //
+ descriptor_config.source_address = ((uint32_t) (buffer_out != NULL ? buffer_out + length : &tx));
// DATA register is consistently addressed across all SERCOM modes.
descriptor_config.destination_address = ((uint32_t)&sercom->SPI.DATA.reg);
diff --git a/ports/atmel-samd/shared_dma.h b/ports/atmel-samd/shared_dma.h
index 1e9240338..2ddd81c4e 100644
--- a/ports/atmel-samd/shared_dma.h
+++ b/ports/atmel-samd/shared_dma.h
@@ -37,6 +37,7 @@ void init_shared_dma(void);
enum status_code shared_dma_write(Sercom* sercom, const uint8_t* buffer, uint32_t length);
enum status_code shared_dma_read(Sercom* sercom, uint8_t* buffer, uint32_t length, uint8_t tx);
+enum status_code shared_dma_transfer(Sercom* sercom, uint8_t* buffer_out, uint8_t* buffer_in, uint32_t length, uint8_t tx);
// Allocate a counter to track how far along we are in a DMA double buffer.
bool allocate_block_counter(void);
diff --git a/ports/esp8266/Makefile b/ports/esp8266/Makefile
index ebb8981ef..70c5c9677 100644
--- a/ports/esp8266/Makefile
+++ b/ports/esp8266/Makefile
@@ -130,6 +130,7 @@ SRC_BINDINGS_ENUMS = \
digitalio/DriveMode.c \
digitalio/Pull.c \
math/__init__.c \
+ microcontroller/RunMode.c \
util.c
SRC_COMMON_HAL_EXPANDED = $(addprefix shared-bindings/, $(SRC_COMMON_HAL)) \
diff --git a/ports/esp8266/common-hal/busio/SPI.c b/ports/esp8266/common-hal/busio/SPI.c
index 50ad03460..aa2b3a354 100644
--- a/ports/esp8266/common-hal/busio/SPI.c
+++ b/ports/esp8266/common-hal/busio/SPI.c
@@ -185,3 +185,23 @@ bool common_hal_busio_spi_read(busio_spi_obj_t *self,
}
return true;
}
+
+bool common_hal_busio_spi_transfer(busio_spi_obj_t *self, uint8_t *data_out, uint8_t *data_in, size_t len) {
+ // Process data in chunks, let the pending tasks run in between
+ size_t chunk_size = 1024; // TODO this should depend on baudrate
+ size_t count = len / chunk_size;
+ size_t i = 0;
+ for (size_t j = 0; j < count; ++j) {
+ for (size_t k = 0; k < chunk_size; ++k) {
+ data_in[i] = spi_transaction(HSPI, 0, 0, 0, 0, 8, data_out[i], 8, 0);
+ ++i;
+ }
+ ets_loop_iter();
+ }
+ while (i < len) {
+ data_in[i] = spi_transaction(HSPI, 0, 0, 0, 0, 8, data_out[i], 8, 0);
+ ++i;
+ }
+ return true;
+
+}
diff --git a/ports/esp8266/common-hal/digitalio/DigitalInOut.c b/ports/esp8266/common-hal/digitalio/DigitalInOut.c
index 70ed207d5..7101e6414 100644
--- a/ports/esp8266/common-hal/digitalio/DigitalInOut.c
+++ b/ports/esp8266/common-hal/digitalio/DigitalInOut.c
@@ -59,7 +59,7 @@ void common_hal_digitalio_digitalinout_deinit(digitalio_digitalinout_obj_t* self
}
void common_hal_digitalio_digitalinout_switch_to_input(
- digitalio_digitalinout_obj_t* self, enum digitalio_pull_t pull) {
+ digitalio_digitalinout_obj_t* self, digitalio_pull_t pull) {
self->output = false;
if (self->pin->gpio_number == 16) {
@@ -75,7 +75,7 @@ void common_hal_digitalio_digitalinout_switch_to_input(
void common_hal_digitalio_digitalinout_switch_to_output(
digitalio_digitalinout_obj_t* self, bool value,
- enum digitalio_drive_mode_t drive_mode) {
+ digitalio_drive_mode_t drive_mode) {
self->output = true;
self->open_drain = drive_mode == DRIVE_MODE_OPEN_DRAIN;
if (self->pin->gpio_number == 16) {
@@ -89,7 +89,7 @@ void common_hal_digitalio_digitalinout_switch_to_output(
common_hal_digitalio_digitalinout_set_value(self, value);
}
-enum digitalio_direction_t common_hal_digitalio_digitalinout_get_direction(
+digitalio_direction_t common_hal_digitalio_digitalinout_get_direction(
digitalio_digitalinout_obj_t* self) {
return self->output? DIRECTION_OUTPUT : DIRECTION_INPUT;
}
@@ -136,7 +136,7 @@ bool common_hal_digitalio_digitalinout_get_value(
void common_hal_digitalio_digitalinout_set_drive_mode(
digitalio_digitalinout_obj_t* self,
- enum digitalio_drive_mode_t drive_mode) {
+ digitalio_drive_mode_t drive_mode) {
bool value = common_hal_digitalio_digitalinout_get_value(self);
self->open_drain = drive_mode == DRIVE_MODE_OPEN_DRAIN;
// True is implemented differently between modes so reset the value to make
@@ -146,7 +146,7 @@ void common_hal_digitalio_digitalinout_set_drive_mode(
}
}
-enum digitalio_drive_mode_t common_hal_digitalio_digitalinout_get_drive_mode(
+digitalio_drive_mode_t common_hal_digitalio_digitalinout_get_drive_mode(
digitalio_digitalinout_obj_t* self) {
if (self->open_drain) {
return DRIVE_MODE_OPEN_DRAIN;
@@ -156,7 +156,7 @@ enum digitalio_drive_mode_t common_hal_digitalio_digitalinout_get_drive_mode(
}
void common_hal_digitalio_digitalinout_set_pull(
- digitalio_digitalinout_obj_t* self, enum digitalio_pull_t pull) {
+ digitalio_digitalinout_obj_t* self, digitalio_pull_t pull) {
if (pull == PULL_DOWN) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError,
"ESP8266 does not support pull down."));
@@ -174,7 +174,7 @@ void common_hal_digitalio_digitalinout_set_pull(
}
}
-enum digitalio_pull_t common_hal_digitalio_digitalinout_get_pull(
+digitalio_pull_t common_hal_digitalio_digitalinout_get_pull(
digitalio_digitalinout_obj_t* self) {
if (self->pin->gpio_number < 16 &&
(READ_PERI_REG(self->pin->peripheral) & PERIPHS_IO_MUX_PULLUP) != 0) {
diff --git a/ports/esp8266/common-hal/microcontroller/__init__.c b/ports/esp8266/common-hal/microcontroller/__init__.c
index 6aef23761..6d446ceac 100644
--- a/ports/esp8266/common-hal/microcontroller/__init__.c
+++ b/ports/esp8266/common-hal/microcontroller/__init__.c
@@ -24,9 +24,12 @@
* THE SOFTWARE.
*/
+#include "py/runtime.h"
+
#include "common-hal/microcontroller/Pin.h"
#include "common-hal/microcontroller/Processor.h"
+#include "shared-bindings/microcontroller/__init__.h"
#include "shared-bindings/microcontroller/Pin.h"
#include "shared-bindings/microcontroller/Processor.h"
@@ -34,6 +37,7 @@
#include "ets_alt_task.h"
#include "etshal.h"
#include "osapi.h"
+#include "user_interface.h"
#include "xtirq.h"
#define ETS_LOOP_ITER_BIT (12)
@@ -54,9 +58,21 @@ void common_hal_mcu_enable_interrupts() {
enable_irq(saved_interrupt_state & ~(1 << ETS_LOOP_ITER_BIT));
}
+void common_hal_mcu_on_next_reset(mcu_runmode_t runmode) {
+ if (runmode == RUNMODE_BOOTLOADER) {
+ mp_raise_ValueError("Cannot reset into bootloader because no bootloader is present.");
+ } else if (runmode == RUNMODE_SAFE_MODE) {
+ mp_raise_ValueError("ESP8226 does not support safe mode.");
+ }
+}
+
+void common_hal_mcu_reset(void) {
+ system_restart();
+}
+
// The singleton microcontroller.Processor object, returned by microcontroller.cpu
// It currently only has properties, and no state.
-mcu_processor_obj_t common_hal_mcu_processor_obj = {
+const mcu_processor_obj_t common_hal_mcu_processor_obj = {
.base = {
.type = &mcu_processor_type,
},
diff --git a/ports/nrf/mpconfigport.mk b/ports/nrf/mpconfigport.mk
index dc29a92cf..17304b783 100644
--- a/ports/nrf/mpconfigport.mk
+++ b/ports/nrf/mpconfigport.mk
@@ -2,3 +2,6 @@
# $(MPY-TOOL) needs to know what kind of longint to use (if any) to freeze long integers.
# This should correspond to the MICROPY_LONGINT_IMPL definition in mpconfigport.h.
MPY_TOOL_LONGINT_IMPL = -mlongint-impl=mpz
+
+INTERNAL_LIBM = (1)
+
diff --git a/py/makeversionhdr.py b/py/makeversionhdr.py
index 30995f937..ebd887445 100644
--- a/py/makeversionhdr.py
+++ b/py/makeversionhdr.py
@@ -86,6 +86,7 @@ def make_version_header(filename):
#define MICROPY_VERSION_MINOR (%s)
#define MICROPY_VERSION_MICRO (%s)
#define MICROPY_VERSION_STRING "%s"
+#define MICROPY_FULL_VERSION_INFO ("Adafruit CircuitPython " MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE "; " MICROPY_HW_BOARD_NAME " with " MICROPY_HW_MCU_NAME)
""" % (git_tag, git_hash, datetime.date.today().strftime("%Y-%m-%d"),
ver[0].replace('v', ''), ver[1], ver[2], version_string)
diff --git a/py/mkenv.mk b/py/mkenv.mk
index 5a118854a..5f8cd902b 100644
--- a/py/mkenv.mk
+++ b/py/mkenv.mk
@@ -70,6 +70,7 @@ endif
MAKE_FROZEN = $(TOP)/tools/make-frozen.py
MPY_CROSS = $(TOP)/mpy-cross/mpy-cross
MPY_TOOL = $(TOP)/tools/mpy-tool.py
+PREPROCESS_FROZEN_MODULES = PYTHONPATH=$(TOP)/tools/python-semver $(TOP)/tools/preprocess_frozen_modules.py
all:
.PHONY: all
diff --git a/py/mkrules.mk b/py/mkrules.mk
index a7a2d492a..7385ad57a 100644
--- a/py/mkrules.mk
+++ b/py/mkrules.mk
@@ -114,13 +114,13 @@ $(MPY_CROSS): $(TOP)/py/*.[ch] $(TOP)/mpy-cross/*.[ch] $(TOP)/ports/windows/fmod
$(Q)$(MAKE) -C $(TOP)/mpy-cross
# Copy all the modules and single python files to freeze to a common area, omitting top-level dirs (the repo names).
-# Remove any conf.py (sphinx config) and setup.py (module install info) files, which are not meant to be frozen.
+# Do any preprocessing necessary: currently, this adds version information, removes examples, and
+# non-library .py files in the modules (setup.py and conf.py)
# Then compile .mpy files from all the .py files, placing them in the same directories as the .py files.
$(BUILD)/frozen_mpy: $(FROZEN_MPY_DIRS)
$(ECHO) FREEZE $(FROZEN_MPY_DIRS)
$(Q)$(MKDIR) -p $@
- $(Q)$(RSYNC) -rL --include="*/" --include='*.py' --exclude="*" $(addsuffix /*,$(FROZEN_MPY_DIRS)) $@
- $(Q)$(RM) -f $@/conf.py $@/setup.py
+ $(Q)$(PREPROCESS_FROZEN_MODULES) -o $@ $(FROZEN_MPY_DIRS)
$(Q)$(CD) $@ && \
$(FIND) -L . -type f -name '*.py' | sed 's=^\./==' | \
xargs -n1 $(abspath $(MPY_CROSS)) $(MPY_CROSS_FLAGS)
diff --git a/requirements.txt b/requirements.txt
deleted file mode 100644
index 75df61718..000000000
--- a/requirements.txt
+++ /dev/null
@@ -1 +0,0 @@
-# dummy file to work around readthedocs bug: https://github.com/rtfd/readthedocs.org/issues/2855
diff --git a/shared-bindings/_stage/Layer.c b/shared-bindings/_stage/Layer.c
new file mode 100644
index 000000000..3e615c497
--- /dev/null
+++ b/shared-bindings/_stage/Layer.c
@@ -0,0 +1,130 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Radomir Dopieralski
+ *
+ * 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 "__init__.h"
+#include "Layer.h"
+
+//| .. currentmodule:: _stage
+//|
+//| :class:`Layer` -- Keep information about a single layer of graphics
+//| ===================================================================
+//|
+//| .. class:: Layer(width, height, graphic, palette, [grid])
+//|
+//| Keep internal information about a layer of graphics (either a
+//| ``Grid`` or a ``Sprite``) in a format suitable for fast rendering
+//| with the ``render()`` function.
+//|
+//| :param int width: The width of the grid in tiles, or 1 for sprites.
+//| :param int height: The height of the grid in tiles, or 1 for sprites.
+//| :param bytearray graphic: The graphic data of the tiles.
+//| :param bytearray palette: The color palette to be used.
+//| :param bytearray grid: The contents of the grid map.
+//|
+//| This class is intended for internal use in the ``stage`` library and
+//| it shouldn't be used on its own.
+//|
+STATIC mp_obj_t layer_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, 4, 5, false);
+
+ layer_obj_t *self = m_new_obj(layer_obj_t);
+ self->base.type = type;
+
+ self->width = mp_obj_get_int(args[0]);
+ self->height = mp_obj_get_int(args[1]);
+ self->x = 0;
+ self->y = 0;
+ self->frame = 0;
+ self->rotation = false;
+
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(args[2], &bufinfo, MP_BUFFER_READ);
+ self->graphic = bufinfo.buf;
+ if (bufinfo.len != 2048) {
+ mp_raise_ValueError("graphic must be 2048 bytes long");
+ }
+
+ mp_get_buffer_raise(args[3], &bufinfo, MP_BUFFER_READ);
+ self->palette = bufinfo.buf;
+ if (bufinfo.len != 32) {
+ mp_raise_ValueError("palette must be 32 bytes long");
+ }
+
+ if (n_args > 4) {
+ mp_get_buffer_raise(args[4], &bufinfo, MP_BUFFER_READ);
+ self->map = bufinfo.buf;
+ if (bufinfo.len < (self->width * self->height) / 2) {
+ mp_raise_ValueError("map buffer too small");
+ }
+ } else {
+ self-> map = NULL;
+ }
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+//| .. method:: move(x, y)
+//|
+//| Set the offset of the layer to the specified values.
+//|
+STATIC mp_obj_t layer_move(mp_obj_t self_in, mp_obj_t x_in, mp_obj_t y_in) {
+ layer_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ self->x = mp_obj_get_int(x_in);
+ self->y = mp_obj_get_int(y_in);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(layer_move_obj, layer_move);
+
+//| .. method:: frame(frame, rotation)
+//|
+//| Set the animation frame of the sprite, and optionally rotation its
+//| graphic.
+//|
+STATIC mp_obj_t layer_frame(mp_obj_t self_in, mp_obj_t frame_in,
+ mp_obj_t rotation_in) {
+ layer_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ self->frame = mp_obj_get_int(frame_in);
+ self->rotation = mp_obj_get_int(rotation_in);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(layer_frame_obj, layer_frame);
+
+
+STATIC const mp_rom_map_elem_t layer_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_move), MP_ROM_PTR(&layer_move_obj) },
+ { MP_ROM_QSTR(MP_QSTR_frame), MP_ROM_PTR(&layer_frame_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(layer_locals_dict, layer_locals_dict_table);
+
+const mp_obj_type_t mp_type_layer = {
+ { &mp_type_type },
+ .name = MP_QSTR_Layer,
+ .make_new = layer_make_new,
+ .locals_dict = (mp_obj_dict_t*)&layer_locals_dict,
+};
diff --git a/shared-bindings/_stage/Layer.h b/shared-bindings/_stage/Layer.h
new file mode 100644
index 000000000..6d15dfb28
--- /dev/null
+++ b/shared-bindings/_stage/Layer.h
@@ -0,0 +1,34 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Radomir Dopieralski
+ *
+ * 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__STAGE_LAYER_H
+#define MICROPY_INCLUDED__STAGE_LAYER_H
+
+#include "shared-module/_stage/Layer.h"
+
+extern const mp_obj_type_t mp_type_layer;
+
+#endif // MICROPY_INCLUDED__STAGE_LAYER
diff --git a/shared-bindings/_stage/Text.c b/shared-bindings/_stage/Text.c
new file mode 100644
index 000000000..c62d22afe
--- /dev/null
+++ b/shared-bindings/_stage/Text.c
@@ -0,0 +1,109 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Radomir Dopieralski
+ *
+ * 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 "__init__.h"
+#include "Text.h"
+
+//| .. currentmodule:: _stage
+//|
+//| :class:`Text` -- Keep information about a single text of text
+//| ==============================================================
+//|
+//| .. class:: Text(width, height, font, palette, chars)
+//|
+//| Keep internal information about a text of text
+//| in a format suitable for fast rendering
+//| with the ``render()`` function.
+//|
+//| :param int width: The width of the grid in tiles, or 1 for sprites.
+//| :param int height: The height of the grid in tiles, or 1 for sprites.
+//| :param bytearray font: The font data of the characters.
+//| :param bytearray palette: The color palette to be used.
+//| :param bytearray chars: The contents of the character grid.
+//|
+//| This class is intended for internal use in the ``stage`` library and
+//| it shouldn't be used on its own.
+//|
+STATIC mp_obj_t text_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, 5, 5, false);
+
+ text_obj_t *self = m_new_obj(text_obj_t);
+ self->base.type = type;
+
+ self->width = mp_obj_get_int(args[0]);
+ self->height = mp_obj_get_int(args[1]);
+ self->x = 0;
+ self->y = 0;
+
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(args[2], &bufinfo, MP_BUFFER_READ);
+ self->font = bufinfo.buf;
+ if (bufinfo.len != 2048) {
+ mp_raise_ValueError("font must be 2048 bytes long");
+ }
+
+ mp_get_buffer_raise(args[3], &bufinfo, MP_BUFFER_READ);
+ self->palette = bufinfo.buf;
+ if (bufinfo.len != 32) {
+ mp_raise_ValueError("palette must be 32 bytes long");
+ }
+
+ mp_get_buffer_raise(args[4], &bufinfo, MP_BUFFER_READ);
+ self->chars = bufinfo.buf;
+ if (bufinfo.len < self->width * self->height) {
+ mp_raise_ValueError("chars buffer too small");
+ }
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+//| .. method:: move(x, y)
+//|
+//| Set the offset of the text to the specified values.
+//|
+STATIC mp_obj_t text_move(mp_obj_t self_in, mp_obj_t x_in, mp_obj_t y_in) {
+ text_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ self->x = mp_obj_get_int(x_in);
+ self->y = mp_obj_get_int(y_in);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(text_move_obj, text_move);
+
+
+STATIC const mp_rom_map_elem_t text_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_move), MP_ROM_PTR(&text_move_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(text_locals_dict, text_locals_dict_table);
+
+const mp_obj_type_t mp_type_text = {
+ { &mp_type_type },
+ .name = MP_QSTR_Text,
+ .make_new = text_make_new,
+ .locals_dict = (mp_obj_dict_t*)&text_locals_dict,
+};
diff --git a/shared-bindings/_stage/Text.h b/shared-bindings/_stage/Text.h
new file mode 100644
index 000000000..77de62a11
--- /dev/null
+++ b/shared-bindings/_stage/Text.h
@@ -0,0 +1,34 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Radomir Dopieralski
+ *
+ * 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__STAGE_TEXT_H
+#define MICROPY_INCLUDED__STAGE_TEXT_H
+
+#include "shared-module/_stage/Text.h"
+
+extern const mp_obj_type_t mp_type_text;
+
+#endif // MICROPY_INCLUDED__STAGE_TEXT
diff --git a/shared-bindings/_stage/__init__.c b/shared-bindings/_stage/__init__.c
new file mode 100644
index 000000000..16e0b58d9
--- /dev/null
+++ b/shared-bindings/_stage/__init__.c
@@ -0,0 +1,97 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Radomir Dopieralski
+ *
+ * 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 "__init__.h"
+#include "py/mperrno.h"
+#include "py/runtime.h"
+#include "shared-bindings/busio/SPI.h"
+#include "shared-module/_stage/__init__.h"
+#include "Layer.h"
+#include "Text.h"
+
+//| .. currentmodule:: _stage
+//|
+//| .. function:: render(x0, y0, x1, y1, layers, buffer, spi)
+//|
+//| Render and send to the display a fragment of the screen.
+//|
+//| :param int x0: Left edge of the fragment.
+//| :param int y0: Top edge of the fragment.
+//| :param int x1: Right edge of the fragment.
+//| :param int y1: Bottom edge of the fragment.
+//| :param list layers: A list of the `Layer` objects.
+//| :param bytearray buffer: A buffer to use for rendering.
+//| :param SPI spi: The SPI device to use.
+//|
+//| Note that this function only sends the raw pixel data. Setting up
+//| the display for receiving it and handling the chip-select and
+//| data-command pins has to be done outside of it.
+//| There are also no sanity checks, outside of the basic overflow
+//| checking. The caller is responsible for making the passed parameters
+//| valid.
+//|
+//| This function is intended for internal use in the ``stage`` library
+//| and all the necessary checks are performed there.
+STATIC mp_obj_t stage_render(size_t n_args, const mp_obj_t *args) {
+ uint8_t x0 = mp_obj_get_int(args[0]);
+ uint8_t y0 = mp_obj_get_int(args[1]);
+ uint8_t x1 = mp_obj_get_int(args[2]);
+ uint8_t y1 = mp_obj_get_int(args[3]);
+
+ size_t layers_size = 0;
+ mp_obj_t *layers;
+ mp_obj_get_array(args[4], &layers_size, &layers);
+
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(args[5], &bufinfo, MP_BUFFER_WRITE);
+ uint16_t *buffer = bufinfo.buf;
+ size_t buffer_size = bufinfo.len / 2; // 16-bit indexing
+
+ busio_spi_obj_t *spi = MP_OBJ_TO_PTR(args[6]);
+
+ if (!render_stage(x0, y0, x1, y1, layers, layers_size,
+ buffer, buffer_size, spi)) {
+ mp_raise_OSError(MP_EIO);
+ }
+
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(stage_render_obj, 7, 7, stage_render);
+
+
+STATIC const mp_rom_map_elem_t stage_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR__stage) },
+ { MP_ROM_QSTR(MP_QSTR_Layer), MP_ROM_PTR(&mp_type_layer) },
+ { MP_ROM_QSTR(MP_QSTR_Text), MP_ROM_PTR(&mp_type_text) },
+ { MP_ROM_QSTR(MP_QSTR_render), MP_ROM_PTR(&stage_render_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(stage_module_globals, stage_module_globals_table);
+
+const mp_obj_module_t stage_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t*)&stage_module_globals,
+};
diff --git a/shared-bindings/_stage/__init__.h b/shared-bindings/_stage/__init__.h
new file mode 100644
index 000000000..2df81cb3b
--- /dev/null
+++ b/shared-bindings/_stage/__init__.h
@@ -0,0 +1,32 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Radomir Dopieralski
+ *
+ * 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__STAGE_H
+#define MICROPY_INCLUDED__STAGE_H
+
+#include "shared-module/_stage/__init__.h"
+
+#endif // MICROPY_INCLUDED__STAGE
diff --git a/shared-bindings/audiobusio/PDMIn.c b/shared-bindings/audiobusio/PDMIn.c
index b43adecba..f273c7a3d 100644
--- a/shared-bindings/audiobusio/PDMIn.c
+++ b/shared-bindings/audiobusio/PDMIn.c
@@ -28,6 +28,7 @@
#include "lib/utils/context_manager_helpers.h"
#include "py/binary.h"
+#include "py/mphal.h"
#include "py/objproperty.h"
#include "py/runtime.h"
#include "shared-bindings/microcontroller/Pin.h"
@@ -41,7 +42,7 @@
//|
//| PDMIn can be used to record an input audio signal on a given set of pins.
//|
-//| .. class:: PDMIn(clock_pin, data_pin, \*, frequency=8000, bit_depth=8, mono=True, oversample=64)
+//| .. class:: PDMIn(clock_pin, data_pin, \*, frequency=16000, bit_depth=8, mono=True, oversample=64, startup_delay=0.11)
//|
//| Create a PDMIn object associated with the given pins. This allows you to
//| record audio signals from the given pins. Individual ports may put further
@@ -51,11 +52,16 @@
//|
//| :param ~microcontroller.Pin clock_pin: The pin to output the clock to
//| :param ~microcontroller.Pin data_pin: The pin to read the data from
-//| :param int frequency: Target frequency in Hz of the resulting samples. Check `frequency` for real value
+//| :param int frequency: Target frequency of the resulting samples. Check `frequency` for actual value.
+//| Minimum frequency is about 16000 Hz.
//| :param int bit_depth: Final number of bits per sample. Must be divisible by 8
//| :param bool mono: True when capturing a single channel of audio, captures two channels otherwise
//| :param int oversample: Number of single bit samples to decimate into a final sample. Must be divisible by 8
+//| :param float startup_delay: seconds to wait after starting microphone clock
+//| to allow microphone to turn on. Most require only 0.01s; some require 0.1s. Longer is safer.
+//| Must be in range 0.0-1.0 seconds.
//|
+
//| Record 8-bit unsigned samples to buffer::
//|
//| import audiobusio
@@ -81,15 +87,19 @@
//| mic.record(b, len(b))
//|
STATIC mp_obj_t audiobusio_pdmin_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *pos_args) {
- enum { ARG_frequency, ARG_bit_depth, ARG_mono, ARG_oversample };
+ enum { ARG_frequency, ARG_bit_depth, ARG_mono, ARG_oversample, ARG_startup_delay };
mp_map_t kw_args;
mp_map_init_fixed_table(&kw_args, n_kw, pos_args + n_args);
static const mp_arg_t allowed_args[] = {
- { MP_QSTR_frequency, MP_ARG_INT, {.u_int = 8000} },
- { MP_QSTR_bit_depth, MP_ARG_INT, {.u_int = 8} },
- { MP_QSTR_mono, MP_ARG_BOOL,{.u_bool = true} },
- { MP_QSTR_oversample, MP_ARG_INT, {.u_int = 64} },
+ { MP_QSTR_frequency, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 16000} },
+ { MP_QSTR_bit_depth, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} },
+ { MP_QSTR_mono, MP_ARG_KW_ONLY | MP_ARG_BOOL,{.u_bool = true} },
+ { MP_QSTR_oversample, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 64} },
+ { MP_QSTR_startup_delay, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
};
+ // Default microphone startup delay is 110msecs. Have seen mics that need 100 msecs plus a bit.
+ static const float STARTUP_DELAY_DEFAULT = 0.110F;
+
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args - 2, pos_args + 2, &kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
@@ -118,8 +128,18 @@ STATIC mp_obj_t audiobusio_pdmin_make_new(const mp_obj_type_t *type, size_t n_ar
}
bool mono = args[ARG_mono].u_bool;
+ float startup_delay = (args[ARG_startup_delay].u_obj == MP_OBJ_NULL)
+ ? STARTUP_DELAY_DEFAULT
+ : mp_obj_get_float(args[ARG_startup_delay].u_obj);
+ if (startup_delay < 0.0 || startup_delay > 1.0) {
+ mp_raise_ValueError("Microphone startup delay must be in range 0.0 to 1.0");
+ }
+
common_hal_audiobusio_pdmin_construct(self, clock_pin, data_pin, frequency,
- bit_depth, mono, oversample);
+ bit_depth, mono, oversample);
+
+ // Wait for the microphone to start up. Some start in 10 msecs; some take as much as 100 msecs.
+ mp_hal_delay_ms(startup_delay * 1000);
return MP_OBJ_FROM_PTR(self);
}
@@ -162,11 +182,14 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(audiobusio_pdmin___exit___obj, 4, 4,
//| audio at the given rate. For internal flash, writing all 1s to the file
//| before recording is recommended to speed up writes.
//|
+//| :return: The number of samples recorded. If this is less than `destination_length`,
+//| some samples were missed due to processing time.
+//|
STATIC mp_obj_t audiobusio_pdmin_obj_record(mp_obj_t self_obj, mp_obj_t destination, mp_obj_t destination_length) {
audiobusio_pdmin_obj_t *self = MP_OBJ_TO_PTR(self_obj);
raise_error_if_deinited(common_hal_audiobusio_pdmin_deinited(self));
- if (!MP_OBJ_IS_SMALL_INT(destination_length)) {
- mp_raise_TypeError("destination_length must be int");
+ if (!MP_OBJ_IS_SMALL_INT(destination_length) || MP_OBJ_SMALL_INT_VALUE(destination_length) < 0) {
+ mp_raise_TypeError("destination_length must be an int >= 0");
}
uint32_t length = MP_OBJ_SMALL_INT_VALUE(destination_length);
@@ -174,8 +197,8 @@ STATIC mp_obj_t audiobusio_pdmin_obj_record(mp_obj_t self_obj, mp_obj_t destinat
if (MP_OBJ_IS_TYPE(destination, &fatfs_type_fileio)) {
mp_raise_NotImplementedError("");
} else if (mp_get_buffer(destination, &bufinfo, MP_BUFFER_WRITE)) {
- if (bufinfo.len < length) {
- mp_raise_ValueError("Target buffer cannot hold destination_length bytes.");
+ if (bufinfo.len / mp_binary_get_size('@', bufinfo.typecode, NULL) < length) {
+ mp_raise_ValueError("Destination capacity is smaller than destination_length.");
}
uint8_t bit_depth = common_hal_audiobusio_pdmin_get_bit_depth(self);
if (bufinfo.typecode != 'H' && bit_depth == 16) {
@@ -183,12 +206,10 @@ STATIC mp_obj_t audiobusio_pdmin_obj_record(mp_obj_t self_obj, mp_obj_t destinat
} else if (bufinfo.typecode != 'B' && bufinfo.typecode != BYTEARRAY_TYPECODE && bit_depth == 8) {
mp_raise_ValueError("destination buffer must be a bytearray or array of type 'B' for bit_depth = 8");
}
- length *= bit_depth / 8;
+ // length is the buffer length in slots, not bytes.
uint32_t length_written =
common_hal_audiobusio_pdmin_record_to_buffer(self, bufinfo.buf, length);
- if (length_written != length) {
- mp_printf(&mp_plat_print, "length mismatch %d %d\n", length_written, length);
- }
+ return MP_OBJ_NEW_SMALL_INT(length_written);
}
return mp_const_none;
}
diff --git a/shared-bindings/bitbangio/I2C.c b/shared-bindings/bitbangio/I2C.c
index 80718090a..f8f60210e 100644
--- a/shared-bindings/bitbangio/I2C.c
+++ b/shared-bindings/bitbangio/I2C.c
@@ -157,6 +157,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(bitbangio_i2c_unlock_obj, bitbangio_i2c_obj_unlock);
//|
//| Read into ``buffer`` from the slave specified by ``address``.
//| The number of bytes read will be the length of ``buffer``.
+//| At least one byte must be read.
//|
//| If ``start`` or ``end`` is provided, then the buffer will be sliced
//| as if ``buffer[start:end]``. This will not cause an allocation like
@@ -186,6 +187,9 @@ STATIC mp_obj_t bitbangio_i2c_readfrom_into(size_t n_args, const mp_obj_t *pos_a
int32_t start = args[ARG_start].u_int;
uint32_t length = bufinfo.len;
normalize_buffer_bounds(&start, args[ARG_end].u_int, &length);
+ if (length == 0) {
+ mp_raise_ValueError("Buffer must be at least length 1");
+ }
uint8_t status = shared_module_bitbangio_i2c_read(self,
args[ARG_address].u_int,
((uint8_t*)bufinfo.buf) + start,
@@ -206,6 +210,9 @@ MP_DEFINE_CONST_FUN_OBJ_KW(bitbangio_i2c_readfrom_into_obj, 3, bitbangio_i2c_rea
//| as if ``buffer[start:end]``. This will not cause an allocation like
//| ``buffer[start:end]`` will so it saves memory.
//|
+//| Writing a buffer or slice of length zero is permitted, as it can be used
+//| to poll for the existence of a device.
+//|
//| :param int address: 7-bit device address
//| :param bytearray buffer: buffer containing the bytes to write
//| :param int start: Index to start writing from
diff --git a/shared-bindings/bitbangio/SPI.c b/shared-bindings/bitbangio/SPI.c
index 6c7bac3e5..5442b9ea2 100644
--- a/shared-bindings/bitbangio/SPI.c
+++ b/shared-bindings/bitbangio/SPI.c
@@ -191,6 +191,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(bitbangio_spi_unlock_obj, bitbangio_spi_obj_unlock);
//| .. method:: SPI.write(buf)
//|
//| Write the data contained in ``buf``. Requires the SPI being locked.
+//| If the buffer is empty, nothing happens.
//|
// TODO(tannewt): Add support for start and end kwargs.
STATIC mp_obj_t bitbangio_spi_write(mp_obj_t self_in, mp_obj_t wr_buf) {
@@ -198,6 +199,9 @@ STATIC mp_obj_t bitbangio_spi_write(mp_obj_t self_in, mp_obj_t wr_buf) {
raise_error_if_deinited(shared_module_bitbangio_spi_deinited(self));
mp_buffer_info_t src;
mp_get_buffer_raise(wr_buf, &src, MP_BUFFER_READ);
+ if (src.len == 0) {
+ return mp_const_none;
+ }
check_lock(self);
bool ok = shared_module_bitbangio_spi_write(self, src.buf, src.len);
if (!ok) {
@@ -210,7 +214,9 @@ MP_DEFINE_CONST_FUN_OBJ_2(bitbangio_spi_write_obj, bitbangio_spi_write);
//| .. method:: SPI.readinto(buf)
//|
-//| Read into the buffer specified by ``buf`` while writing zeroes. Requires the SPI being locked.
+//| Read into the buffer specified by ``buf`` while writing zeroes.
+//| Requires the SPI being locked.
+//| If the number of bytes to read is 0, nothing happens.
//|
// TODO(tannewt): Add support for start and end kwargs.
STATIC mp_obj_t bitbangio_spi_readinto(size_t n_args, const mp_obj_t *args) {
@@ -218,6 +224,9 @@ STATIC mp_obj_t bitbangio_spi_readinto(size_t n_args, const mp_obj_t *args) {
raise_error_if_deinited(shared_module_bitbangio_spi_deinited(self));
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_WRITE);
+ if (bufinfo.len == 0) {
+ return mp_const_none;
+ }
check_lock(args[0]);
bool ok = shared_module_bitbangio_spi_read(self, bufinfo.buf, bufinfo.len);
if (!ok) {
diff --git a/shared-bindings/busio/I2C.c b/shared-bindings/busio/I2C.c
index cdc960f80..b0954d6c8 100644
--- a/shared-bindings/busio/I2C.c
+++ b/shared-bindings/busio/I2C.c
@@ -171,6 +171,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(busio_i2c_unlock_obj, busio_i2c_obj_unlock);
//|
//| Read into ``buffer`` from the slave specified by ``address``.
//| The number of bytes read will be the length of ``buffer``.
+//| At least one byte must be read.
//|
//| If ``start`` or ``end`` is provided, then the buffer will be sliced
//| as if ``buffer[start:end]``. This will not cause an allocation like
@@ -201,6 +202,10 @@ STATIC mp_obj_t busio_i2c_readfrom_into(size_t n_args, const mp_obj_t *pos_args,
int32_t start = args[ARG_start].u_int;
uint32_t length = bufinfo.len;
normalize_buffer_bounds(&start, args[ARG_end].u_int, &length);
+ if (length == 0) {
+ mp_raise_ValueError("Buffer must be at least length 1");
+ }
+
uint8_t status = common_hal_busio_i2c_read(self, args[ARG_address].u_int, ((uint8_t*)bufinfo.buf) + start, length);
if (status != 0) {
mp_raise_OSError(status);
@@ -219,6 +224,9 @@ MP_DEFINE_CONST_FUN_OBJ_KW(busio_i2c_readfrom_into_obj, 3, busio_i2c_readfrom_in
//| as if ``buffer[start:end]``. This will not cause an allocation like
//| ``buffer[start:end]`` will so it saves memory.
//|
+//| Writing a buffer or slice of length zero is permitted, as it can be used
+//| to poll for the existence of a device.
+//|
//| :param int address: 7-bit device address
//| :param bytearray buffer: buffer containing the bytes to write
//| :param int start: Index to start writing from
diff --git a/shared-bindings/busio/SPI.c b/shared-bindings/busio/SPI.c
index 12f888f23..c4c139105 100644
--- a/shared-bindings/busio/SPI.c
+++ b/shared-bindings/busio/SPI.c
@@ -206,11 +206,12 @@ MP_DEFINE_CONST_FUN_OBJ_1(busio_spi_unlock_obj, busio_spi_obj_unlock);
//| .. method:: SPI.write(buffer, \*, start=0, end=len(buffer))
//|
-//| Write the data contained in ``buf``. Requires the SPI being locked.
+//| Write the data contained in ``buffer``. The SPI object must be locked.
+//| If the buffer is empty, nothing happens.
//|
-//| :param bytearray buffer: buffer containing the bytes to write
-//| :param int start: Index to start writing from
-//| :param int end: Index to read up to but not include
+//| :param bytearray buffer: Write out the data in this buffer
+//| :param int start: Start of the slice of ``buffer`` to write out: ``buffer[start:end]``
+//| :param int end: End of the slice; this index is not included
//|
STATIC mp_obj_t busio_spi_write(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_buffer, ARG_start, ARG_end };
@@ -231,6 +232,10 @@ STATIC mp_obj_t busio_spi_write(size_t n_args, const mp_obj_t *pos_args, mp_map_
uint32_t length = bufinfo.len;
normalize_buffer_bounds(&start, args[ARG_end].u_int, &length);
+ if (length == 0) {
+ return mp_const_none;
+ }
+
bool ok = common_hal_busio_spi_write(self, ((uint8_t*)bufinfo.buf) + start, length);
if (!ok) {
mp_raise_OSError(MP_EIO);
@@ -242,12 +247,14 @@ MP_DEFINE_CONST_FUN_OBJ_KW(busio_spi_write_obj, 2, busio_spi_write);
//| .. method:: SPI.readinto(buffer, \*, start=0, end=len(buffer), write_value=0)
//|
-//| Read into the buffer specified by ``buf`` while writing zeroes. Requires the SPI being locked.
+//| Read into ``buffer`` while writing ``write_value`` for each byte read.
+//| The SPI object must be locked.
+//| If the number of bytes to read is 0, nothing happens.
//|
-//| :param bytearray buffer: buffer to write into
-//| :param int start: Index to start writing at
-//| :param int end: Index to write up to but not include
-//| :param int write_value: Value to write reading. (Usually ignored.)
+//| :param bytearray buffer: Read data into this buffer
+//| :param int start: Start of the slice of ``buffer`` to read into: ``buffer[start:end]``
+//| :param int end: End of the slice; this index is not included
+//| :param int write_value: Value to write while reading. (Usually ignored.)
//|
STATIC mp_obj_t busio_spi_readinto(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_buffer, ARG_start, ARG_end, ARG_write_value };
@@ -269,6 +276,10 @@ STATIC mp_obj_t busio_spi_readinto(size_t n_args, const mp_obj_t *pos_args, mp_m
uint32_t length = bufinfo.len;
normalize_buffer_bounds(&start, args[ARG_end].u_int, &length);
+ if (length == 0) {
+ return mp_const_none;
+ }
+
bool ok = common_hal_busio_spi_read(self, ((uint8_t*)bufinfo.buf) + start, length, args[ARG_write_value].u_int);
if (!ok) {
mp_raise_OSError(MP_EIO);
@@ -277,6 +288,68 @@ STATIC mp_obj_t busio_spi_readinto(size_t n_args, const mp_obj_t *pos_args, mp_m
}
MP_DEFINE_CONST_FUN_OBJ_KW(busio_spi_readinto_obj, 2, busio_spi_readinto);
+//| .. method:: SPI.write_readinto(buffer_out, buffer_in, \*, out_start=0, out_end=len(buffer_out), in_start=0, in_end=len(buffer_in))
+//|
+//| Write out the data in ``buffer_out`` while simultaneously reading data into ``buffer_in``.
+//| The SPI object must be locked.
+//| The lengths of the slices defined by ``buffer_out[out_start:out_end]`` and ``buffer_in[in_start:in_end]``
+//| must be equal.
+//| If buffer slice lengths are both 0, nothing happens.
+//|
+//| :param bytearray buffer_out: Write out the data in this buffer
+//| :param bytearray buffer_in: Read data into this buffer
+//| :param int out_start: Start of the slice of buffer_out to write out: ``buffer_out[out_start:out_end]``
+//| :param int out_end: End of the slice; this index is not included
+//| :param int in_start: Start of the slice of ``buffer_in`` to read into: ``buffer_in[in_start:in_end]``
+//| :param int in_end: End of the slice; this index is not included
+//|
+STATIC mp_obj_t busio_spi_write_readinto(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_buffer_out, ARG_buffer_in, ARG_out_start, ARG_out_end, ARG_in_start, ARG_in_end };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_buffer_out, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_buffer_in, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_out_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_out_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} },
+ { MP_QSTR_in_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_in_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} },
+ };
+ busio_spi_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+ raise_error_if_deinited(common_hal_busio_spi_deinited(self));
+ check_lock(self);
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_buffer_info_t buf_out_info;
+ mp_get_buffer_raise(args[ARG_buffer_out].u_obj, &buf_out_info, MP_BUFFER_READ);
+ int32_t out_start = args[ARG_out_start].u_int;
+ uint32_t out_length = buf_out_info.len;
+ normalize_buffer_bounds(&out_start, args[ARG_out_end].u_int, &out_length);
+
+ mp_buffer_info_t buf_in_info;
+ mp_get_buffer_raise(args[ARG_buffer_in].u_obj, &buf_in_info, MP_BUFFER_WRITE);
+ int32_t in_start = args[ARG_in_start].u_int;
+ uint32_t in_length = buf_in_info.len;
+ normalize_buffer_bounds(&in_start, args[ARG_in_end].u_int, &in_length);
+
+ if (out_length != in_length) {
+ mp_raise_ValueError("buffer slices must be of equal length");
+ }
+
+ if (out_length == 0) {
+ return mp_const_none;
+ }
+
+ bool ok = common_hal_busio_spi_transfer(self,
+ ((uint8_t*)buf_out_info.buf) + out_start,
+ ((uint8_t*)buf_in_info.buf) + in_start,
+ out_length);
+ if (!ok) {
+ mp_raise_OSError(MP_EIO);
+ }
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(busio_spi_write_readinto_obj, 2, busio_spi_write_readinto);
+
STATIC const mp_rom_map_elem_t busio_spi_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&busio_spi_deinit_obj) },
{ MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) },
@@ -288,6 +361,7 @@ STATIC const mp_rom_map_elem_t busio_spi_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&busio_spi_readinto_obj) },
{ MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&busio_spi_write_obj) },
+ { MP_ROM_QSTR(MP_QSTR_write_readinto), MP_ROM_PTR(&busio_spi_write_readinto_obj) },
};
STATIC MP_DEFINE_CONST_DICT(busio_spi_locals_dict, busio_spi_locals_dict_table);
diff --git a/shared-bindings/busio/SPI.h b/shared-bindings/busio/SPI.h
index ac31d5060..b6e5c9b1b 100644
--- a/shared-bindings/busio/SPI.h
+++ b/shared-bindings/busio/SPI.h
@@ -55,4 +55,7 @@ extern bool common_hal_busio_spi_write(busio_spi_obj_t *self, const uint8_t *dat
// Reads in len bytes while outputting zeroes.
extern bool common_hal_busio_spi_read(busio_spi_obj_t *self, uint8_t *data, size_t len, uint8_t write_value);
+// Reads and write len bytes simultaneously.
+extern bool common_hal_busio_spi_transfer(busio_spi_obj_t *self, uint8_t *data_out, uint8_t *data_in, size_t len);
+
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BUSIO_SPI_H
diff --git a/shared-bindings/digitalio/DigitalInOut.c b/shared-bindings/digitalio/DigitalInOut.c
index ea2ba0b89..008883b8b 100644
--- a/shared-bindings/digitalio/DigitalInOut.c
+++ b/shared-bindings/digitalio/DigitalInOut.c
@@ -124,7 +124,7 @@ STATIC mp_obj_t digitalio_digitalinout_switch_to_output(size_t n_args, const mp_
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
- enum digitalio_drive_mode_t drive_mode = DRIVE_MODE_PUSH_PULL;
+ digitalio_drive_mode_t drive_mode = DRIVE_MODE_PUSH_PULL;
if (args[ARG_drive_mode].u_rom_obj == &digitalio_drive_mode_open_drain_obj) {
drive_mode = DRIVE_MODE_OPEN_DRAIN;
}
@@ -161,7 +161,7 @@ STATIC mp_obj_t digitalio_digitalinout_switch_to_input(size_t n_args, const mp_o
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
- enum digitalio_pull_t pull = PULL_NONE;
+ digitalio_pull_t pull = PULL_NONE;
if (args[ARG_pull].u_rom_obj == &digitalio_pull_up_obj) {
pull = PULL_UP;
}else if (args[ARG_pull].u_rom_obj == &digitalio_pull_down_obj) {
@@ -191,7 +191,7 @@ extern const digitalio_digitalio_direction_obj_t digitalio_digitalio_direction_o
STATIC mp_obj_t digitalio_digitalinout_obj_get_direction(mp_obj_t self_in) {
digitalio_digitalinout_obj_t *self = MP_OBJ_TO_PTR(self_in);
raise_error_if_deinited(common_hal_digitalio_digitalinout_deinited(self));
- enum digitalio_direction_t direction = common_hal_digitalio_digitalinout_get_direction(self);
+ digitalio_direction_t direction = common_hal_digitalio_digitalinout_get_direction(self);
if (direction == DIRECTION_INPUT) {
return (mp_obj_t)&digitalio_direction_input_obj;
}
@@ -262,7 +262,7 @@ STATIC mp_obj_t digitalio_digitalinout_obj_get_drive_mode(mp_obj_t self_in) {
mp_raise_AttributeError("Drive mode not used when direction is input.");
return mp_const_none;
}
- enum digitalio_drive_mode_t drive_mode = common_hal_digitalio_digitalinout_get_drive_mode(self);
+ digitalio_drive_mode_t drive_mode = common_hal_digitalio_digitalinout_get_drive_mode(self);
if (drive_mode == DRIVE_MODE_PUSH_PULL) {
return (mp_obj_t)&digitalio_drive_mode_push_pull_obj;
}
@@ -277,7 +277,7 @@ STATIC mp_obj_t digitalio_digitalinout_obj_set_drive_mode(mp_obj_t self_in, mp_o
mp_raise_AttributeError("Drive mode not used when direction is input.");
return mp_const_none;
}
- enum digitalio_drive_mode_t c_drive_mode = DRIVE_MODE_PUSH_PULL;
+ digitalio_drive_mode_t c_drive_mode = DRIVE_MODE_PUSH_PULL;
if (drive_mode == &digitalio_drive_mode_open_drain_obj) {
c_drive_mode = DRIVE_MODE_OPEN_DRAIN;
}
@@ -307,7 +307,7 @@ STATIC mp_obj_t digitalio_digitalinout_obj_get_pull(mp_obj_t self_in) {
mp_raise_AttributeError("Pull not used when direction is output.");
return mp_const_none;
}
- enum digitalio_pull_t pull = common_hal_digitalio_digitalinout_get_pull(self);
+ digitalio_pull_t pull = common_hal_digitalio_digitalinout_get_pull(self);
if (pull == PULL_UP) {
return (mp_obj_t)&digitalio_pull_up_obj;
} else if (pull == PULL_DOWN) {
@@ -324,7 +324,7 @@ STATIC mp_obj_t digitalio_digitalinout_obj_set_pull(mp_obj_t self_in, mp_obj_t p
mp_raise_AttributeError("Pull not used when direction is output.");
return mp_const_none;
}
- enum digitalio_pull_t pull = PULL_NONE;
+ digitalio_pull_t pull = PULL_NONE;
if (pull_obj == &digitalio_pull_up_obj) {
pull = PULL_UP;
} else if (pull_obj == &digitalio_pull_down_obj) {
diff --git a/shared-bindings/digitalio/DigitalInOut.h b/shared-bindings/digitalio/DigitalInOut.h
index 74970881b..2aaa31b7f 100644
--- a/shared-bindings/digitalio/DigitalInOut.h
+++ b/shared-bindings/digitalio/DigitalInOut.h
@@ -43,14 +43,14 @@ typedef enum {
digitalinout_result_t common_hal_digitalio_digitalinout_construct(digitalio_digitalinout_obj_t* self, const mcu_pin_obj_t* pin);
void common_hal_digitalio_digitalinout_deinit(digitalio_digitalinout_obj_t* self);
bool common_hal_digitalio_digitalinout_deinited(digitalio_digitalinout_obj_t* self);
-void common_hal_digitalio_digitalinout_switch_to_input(digitalio_digitalinout_obj_t* self, enum digitalio_pull_t pull);
-void common_hal_digitalio_digitalinout_switch_to_output(digitalio_digitalinout_obj_t* self, bool value, enum digitalio_drive_mode_t drive_mode);
-enum digitalio_direction_t common_hal_digitalio_digitalinout_get_direction(digitalio_digitalinout_obj_t* self);
+void common_hal_digitalio_digitalinout_switch_to_input(digitalio_digitalinout_obj_t* self, digitalio_pull_t pull);
+void common_hal_digitalio_digitalinout_switch_to_output(digitalio_digitalinout_obj_t* self, bool value, digitalio_drive_mode_t drive_mode);
+digitalio_direction_t common_hal_digitalio_digitalinout_get_direction(digitalio_digitalinout_obj_t* self);
void common_hal_digitalio_digitalinout_set_value(digitalio_digitalinout_obj_t* self, bool value);
bool common_hal_digitalio_digitalinout_get_value(digitalio_digitalinout_obj_t* self);
-void common_hal_digitalio_digitalinout_set_drive_mode(digitalio_digitalinout_obj_t* self, enum digitalio_drive_mode_t drive_mode);
-enum digitalio_drive_mode_t common_hal_digitalio_digitalinout_get_drive_mode(digitalio_digitalinout_obj_t* self);
-void common_hal_digitalio_digitalinout_set_pull(digitalio_digitalinout_obj_t* self, enum digitalio_pull_t pull);
-enum digitalio_pull_t common_hal_digitalio_digitalinout_get_pull(digitalio_digitalinout_obj_t* self);
+void common_hal_digitalio_digitalinout_set_drive_mode(digitalio_digitalinout_obj_t* self, digitalio_drive_mode_t drive_mode);
+digitalio_drive_mode_t common_hal_digitalio_digitalinout_get_drive_mode(digitalio_digitalinout_obj_t* self);
+void common_hal_digitalio_digitalinout_set_pull(digitalio_digitalinout_obj_t* self, digitalio_pull_t pull);
+digitalio_pull_t common_hal_digitalio_digitalinout_get_pull(digitalio_digitalinout_obj_t* self);
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_DIGITALIO_DIGITALINOUT_H
diff --git a/shared-bindings/digitalio/Direction.h b/shared-bindings/digitalio/Direction.h
index e8fbf181d..d71f48c2e 100644
--- a/shared-bindings/digitalio/Direction.h
+++ b/shared-bindings/digitalio/Direction.h
@@ -29,10 +29,10 @@
#include "py/obj.h"
-enum digitalio_direction_t {
+typedef enum {
DIRECTION_INPUT,
DIRECTION_OUTPUT
-};
+} digitalio_direction_t;
typedef struct {
mp_obj_base_t base;
} digitalio_direction_obj_t;
diff --git a/shared-bindings/digitalio/DriveMode.h b/shared-bindings/digitalio/DriveMode.h
index 959885b1b..47d036b3a 100644
--- a/shared-bindings/digitalio/DriveMode.h
+++ b/shared-bindings/digitalio/DriveMode.h
@@ -29,10 +29,10 @@
#include "py/obj.h"
-enum digitalio_drive_mode_t {
+typedef enum {
DRIVE_MODE_PUSH_PULL,
DRIVE_MODE_OPEN_DRAIN
-};
+} digitalio_drive_mode_t;
typedef struct {
mp_obj_base_t base;
diff --git a/shared-bindings/digitalio/Pull.h b/shared-bindings/digitalio/Pull.h
index 8c88d8673..22fb6cd0e 100644
--- a/shared-bindings/digitalio/Pull.h
+++ b/shared-bindings/digitalio/Pull.h
@@ -29,11 +29,11 @@
#include "py/obj.h"
-enum digitalio_pull_t {
+typedef enum _digitalio_pull_t {
PULL_NONE,
PULL_UP,
PULL_DOWN
-};
+} digitalio_pull_t;
const mp_obj_type_t digitalio_pull_type;
diff --git a/shared-bindings/microcontroller/RunMode.c b/shared-bindings/microcontroller/RunMode.c
new file mode 100644
index 000000000..b27a3c090
--- /dev/null
+++ b/shared-bindings/microcontroller/RunMode.c
@@ -0,0 +1,90 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "shared-bindings/microcontroller/RunMode.h"
+
+//| .. currentmodule:: microcontroller
+//|
+//| :class:`RunMode` -- run state of the microcontroller
+//| =============================================================
+//|
+//| .. class:: microcontroller.RunMode
+//|
+//| Enum-like class to define the run mode of the microcontroller and
+//| CircuitPython.
+//|
+//| .. data:: NORMAL
+//|
+//| Run CircuitPython as normal.
+//|
+//| .. data:: SAFE_MODE
+//|
+//| Run CircuitPython in safe mode. User code will not be run and the
+//| file system will be writeable over USB.
+//|
+//| .. data:: BOOTLOADER
+//|
+//| Run the bootloader.
+//|
+const mp_obj_type_t mcu_runmode_type;
+
+const mcu_runmode_obj_t mcu_runmode_normal_obj = {
+ { &mcu_runmode_type },
+};
+
+const mcu_runmode_obj_t mcu_runmode_safe_mode_obj = {
+ { &mcu_runmode_type },
+};
+
+const mcu_runmode_obj_t mcu_runmode_bootloader_obj = {
+ { &mcu_runmode_type },
+};
+
+STATIC const mp_rom_map_elem_t mcu_runmode_locals_dict_table[] = {
+ {MP_ROM_QSTR(MP_QSTR_NORMAL), MP_ROM_PTR(&mcu_runmode_normal_obj)},
+ {MP_ROM_QSTR(MP_QSTR_SAFE_MODE), MP_ROM_PTR(&mcu_runmode_safe_mode_obj)},
+ {MP_ROM_QSTR(MP_QSTR_BOOTLOADER), MP_ROM_PTR(&mcu_runmode_bootloader_obj)},
+};
+STATIC MP_DEFINE_CONST_DICT(mcu_runmode_locals_dict, mcu_runmode_locals_dict_table);
+
+STATIC void mcu_runmode_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
+ qstr runmode = MP_QSTR_NORMAL;
+ if (MP_OBJ_TO_PTR(self_in) == MP_ROM_PTR(&mcu_runmode_safe_mode_obj)) {
+ runmode = MP_QSTR_SAFE_MODE;
+ } else if (MP_OBJ_TO_PTR(self_in) ==
+ MP_ROM_PTR(&mcu_runmode_bootloader_obj)) {
+ runmode = MP_QSTR_SAFE_MODE;
+ }
+ mp_printf(print, "%q.%q.%q", MP_QSTR_microcontroller, MP_QSTR_RunMode,
+ runmode);
+}
+
+const mp_obj_type_t mcu_runmode_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_RunMode,
+ .print = mcu_runmode_print,
+ .locals_dict = (mp_obj_t)&mcu_runmode_locals_dict,
+};
diff --git a/shared-bindings/microcontroller/RunMode.h b/shared-bindings/microcontroller/RunMode.h
new file mode 100644
index 000000000..5e8b6e646
--- /dev/null
+++ b/shared-bindings/microcontroller/RunMode.h
@@ -0,0 +1,47 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_MICROCONTROLLER_RUNMODE_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_MICROCONTROLLER_RUNMODE_H
+
+#include "py/obj.h"
+
+typedef enum {
+ RUNMODE_NORMAL,
+ RUNMODE_SAFE_MODE,
+ RUNMODE_BOOTLOADER
+} mcu_runmode_t;
+
+const mp_obj_type_t mcu_runmode_type;
+
+typedef struct {
+ mp_obj_base_t base;
+} mcu_runmode_obj_t;
+extern const mcu_runmode_obj_t mcu_runmode_normal_obj;
+extern const mcu_runmode_obj_t mcu_runmode_safe_mode_obj;
+extern const mcu_runmode_obj_t mcu_runmode_bootloader_obj;
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_MICROCONTROLLER_RUNMODE_H
diff --git a/shared-bindings/microcontroller/__init__.c b/shared-bindings/microcontroller/__init__.c
index 58ed876c2..f261178f0 100644
--- a/shared-bindings/microcontroller/__init__.c
+++ b/shared-bindings/microcontroller/__init__.c
@@ -106,6 +106,47 @@ STATIC mp_obj_t mcu_enable_interrupts(void) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(mcu_enable_interrupts_obj, mcu_enable_interrupts);
+//| .. method:: on_next_reset(run_mode)
+//|
+//| Configure the run mode used the next time the microcontroller is reset but
+//| not powered down.
+//|
+//| :param ~microcontroller.RunMode run_mode: The next run mode
+//|
+STATIC mp_obj_t mcu_on_next_reset(mp_obj_t run_mode_obj) {
+ mcu_runmode_t run_mode;
+ if (run_mode_obj == &mcu_runmode_normal_obj) {
+ run_mode = RUNMODE_NORMAL;
+ } else if (run_mode_obj == &mcu_runmode_safe_mode_obj) {
+ run_mode = RUNMODE_SAFE_MODE;
+ } else if (run_mode_obj == &mcu_runmode_bootloader_obj) {
+ run_mode = RUNMODE_BOOTLOADER;
+ } else {
+ mp_raise_ValueError("Invalid run mode.");
+ }
+
+ common_hal_mcu_on_next_reset(run_mode);
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(mcu_on_next_reset_obj, mcu_on_next_reset);
+
+//| .. method:: reset()
+//|
+//| Reset the microcontroller. After reset, the microcontroller will enter the
+//| run mode last set by `one_next_reset`.
+//|
+//| .. warning:: This may result in file system corruption when connected to a
+//| host computer. Be very careful when calling this! Make sure the device
+//| "Safely removed" on Windows or "ejected" on Mac OSX and Linux.
+//|
+STATIC mp_obj_t mcu_reset(void) {
+ common_hal_mcu_reset();
+ // We won't actually get here because we're resetting.
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(mcu_reset_obj, mcu_reset);
+
//| .. attribute:: nvm
//|
//| Available non-volatile memory.
@@ -132,11 +173,14 @@ STATIC const mp_rom_map_elem_t mcu_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_delay_us), MP_ROM_PTR(&mcu_delay_us_obj) },
{ MP_ROM_QSTR(MP_QSTR_disable_interrupts), MP_ROM_PTR(&mcu_disable_interrupts_obj) },
{ MP_ROM_QSTR(MP_QSTR_enable_interrupts), MP_ROM_PTR(&mcu_enable_interrupts_obj) },
+ { MP_ROM_QSTR(MP_QSTR_on_next_reset), MP_ROM_PTR(&mcu_on_next_reset_obj) },
+ { MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&mcu_reset_obj) },
#if CIRCUITPY_INTERNAL_NVM_SIZE > 0
{ MP_ROM_QSTR(MP_QSTR_nvm), MP_ROM_PTR(&common_hal_mcu_nvm_obj) },
#else
{ MP_ROM_QSTR(MP_QSTR_nvm), MP_ROM_PTR(&mp_const_none_obj) },
#endif
+ { MP_ROM_QSTR(MP_QSTR_RunMode), MP_ROM_PTR(&mcu_runmode_type) },
{ MP_ROM_QSTR(MP_QSTR_Pin), MP_ROM_PTR(&mcu_pin_type) },
{ MP_ROM_QSTR(MP_QSTR_pin), MP_ROM_PTR(&mcu_pin_module) },
{ MP_ROM_QSTR(MP_QSTR_Processor), MP_ROM_PTR(&mcu_processor_type) },
diff --git a/shared-bindings/microcontroller/__init__.h b/shared-bindings/microcontroller/__init__.h
index d43db4bf4..e1487c555 100644
--- a/shared-bindings/microcontroller/__init__.h
+++ b/shared-bindings/microcontroller/__init__.h
@@ -33,11 +33,16 @@
#include "common-hal/microcontroller/Processor.h"
+#include "shared-bindings/microcontroller/RunMode.h"
+
extern void common_hal_mcu_delay_us(uint32_t);
extern void common_hal_mcu_disable_interrupts(void);
extern void common_hal_mcu_enable_interrupts(void);
+extern void common_hal_mcu_on_next_reset(mcu_runmode_t runmode);
+extern void common_hal_mcu_reset(void);
+
extern const mp_obj_dict_t mcu_pin_globals;
extern const mcu_processor_obj_t common_hal_mcu_processor_obj;
diff --git a/shared-module/_stage/Layer.c b/shared-module/_stage/Layer.c
new file mode 100644
index 000000000..4c9c46d7c
--- /dev/null
+++ b/shared-module/_stage/Layer.c
@@ -0,0 +1,105 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Radomir Dopieralski
+ *
+ * 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 "Layer.h"
+#include "__init__.h"
+
+
+// Get the color of the pixel on the layer.
+uint16_t get_layer_pixel(layer_obj_t *layer, int16_t x, uint16_t y) {
+
+ // Shift by the layer's position offset.
+ x -= layer->x;
+ y -= layer->y;
+
+ // Bounds check.
+ if ((x < 0) || (x >= layer->width << 4) ||
+ (y < 0) || (y >= layer->height << 4)) {
+ return TRANSPARENT;
+ }
+
+ // Get the tile from the grid location or from sprite frame.
+ uint8_t frame = layer->frame;
+ if (layer->map) {
+ uint8_t tx = x >> 4;
+ uint8_t ty = y >> 4;
+
+ frame = layer->map[(ty * layer->width + tx) >> 1];
+ if (tx & 0x01) {
+ frame &= 0x0f;
+ } else {
+ frame >>= 4;
+ }
+ }
+
+ // Get the position within the tile.
+ x &= 0x0f;
+ y &= 0x0f;
+
+ // Rotate the image.
+ uint8_t ty = y; // Temporary variable for swapping.
+ switch (layer->rotation) {
+ case 1: // 90 degrees clockwise
+ y = 15 - x;
+ x = ty;
+ break;
+ case 2: // 180 degrees
+ y = 15 - ty;
+ x = 15 - x;
+ break;
+ case 3: // 90 degrees counter-clockwise
+ y = x;
+ x = 15 - ty;
+ break;
+ case 4: // 0 degrees, mirrored
+ x = 15 - x;
+ break;
+ case 5: // 90 degrees clockwise, mirrored
+ y = x;
+ x = ty;
+ break;
+ case 6: // 180 degrees, mirrored
+ y = 15 - ty;
+ break;
+ case 7: // 90 degrees counter-clockwise, mirrored
+ y = 15 - x;
+ x = 15 - ty;
+ break;
+ default: // 0 degrees
+ break;
+ }
+
+ // Get the value of the pixel.
+ uint8_t pixel = layer->graphic[(frame << 7) + (y << 3) + (x >> 1)];
+ if (x & 0x01) {
+ pixel &= 0x0f;
+ } else {
+ pixel >>= 4;
+ }
+
+ // Convert to 16-bit color using the palette.
+ return layer->palette[pixel << 1] | layer->palette[(pixel << 1) + 1] << 8;
+}
diff --git a/shared-module/_stage/Layer.h b/shared-module/_stage/Layer.h
new file mode 100644
index 000000000..c46f71349
--- /dev/null
+++ b/shared-module/_stage/Layer.h
@@ -0,0 +1,48 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Radomir Dopieralski
+ *
+ * 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_SHARED_MODULE__STAGE_LAYER_H
+#define MICROPY_INCLUDED_SHARED_MODULE__STAGE_LAYER_H
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include "py/obj.h"
+
+typedef struct {
+ mp_obj_base_t base;
+ uint8_t *map;
+ uint8_t *graphic;
+ uint8_t *palette;
+ int16_t x, y;
+ uint8_t width, height;
+ uint8_t frame;
+ uint8_t rotation;
+} layer_obj_t;
+
+uint16_t get_layer_pixel(layer_obj_t *layer, int16_t x, uint16_t y);
+
+#endif // MICROPY_INCLUDED_SHARED_MODULE__STAGE_LAYER
diff --git a/shared-module/_stage/Text.c b/shared-module/_stage/Text.c
new file mode 100644
index 000000000..307f9bbfa
--- /dev/null
+++ b/shared-module/_stage/Text.c
@@ -0,0 +1,67 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Radomir Dopieralski
+ *
+ * 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 "Text.h"
+#include "__init__.h"
+
+
+// Get the color of the pixel on the text.
+uint16_t get_text_pixel(text_obj_t *text, int16_t x, uint16_t y) {
+
+ // Shift by the text's position offset.
+ x -= text->x;
+ y -= text->y;
+
+ // Bounds check.
+ if ((x < 0) || (x >= text->width << 3) ||
+ (y < 0) || (y >= text->height << 3)) {
+ return TRANSPARENT;
+ }
+
+ // Get the tile from the grid location or from sprite frame.
+ uint8_t tx = x >> 3;
+ uint8_t ty = y >> 3;
+ uint8_t c = text->chars[ty * text->width + tx];
+ uint8_t color_offset = 0;
+ if (c & 0x80) {
+ color_offset = 4;
+ }
+ c &= 0x7f;
+ if (!c) {
+ return TRANSPARENT;
+ }
+
+ // Get the position within the char.
+ x &= 0x07;
+ y &= 0x07;
+
+ // Get the value of the pixel.
+ uint8_t pixel = text->font[(c << 4) + (y << 1) + (x >> 2)];
+ pixel = ((pixel >> ((x & 0x03) << 1)) & 0x03) + color_offset;
+
+ // Convert to 16-bit color using the palette.
+ return text->palette[pixel << 1] | text->palette[(pixel << 1) + 1] << 8;
+}
diff --git a/shared-module/_stage/Text.h b/shared-module/_stage/Text.h
new file mode 100644
index 000000000..bc111e49c
--- /dev/null
+++ b/shared-module/_stage/Text.h
@@ -0,0 +1,46 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Radomir Dopieralski
+ *
+ * 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_SHARED_MODULE__STAGE_TEXT_H
+#define MICROPY_INCLUDED_SHARED_MODULE__STAGE_TEXT_H
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include "py/obj.h"
+
+typedef struct {
+ mp_obj_base_t base;
+ uint8_t *chars;
+ uint8_t *font;
+ uint8_t *palette;
+ int16_t x, y;
+ uint8_t width, height;
+} text_obj_t;
+
+uint16_t get_text_pixel(text_obj_t *text, int16_t x, uint16_t y);
+
+#endif // MICROPY_INCLUDED_SHARED_MODULE__STAGE_TEXT
diff --git a/shared-module/_stage/__init__.c b/shared-module/_stage/__init__.c
new file mode 100644
index 000000000..1931b8940
--- /dev/null
+++ b/shared-module/_stage/__init__.c
@@ -0,0 +1,76 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Radomir Dopieralski
+ *
+ * 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 "Layer.h"
+#include "Text.h"
+#include "__init__.h"
+#include "shared-bindings/_stage/Layer.h"
+#include "shared-bindings/_stage/Text.h"
+
+
+bool render_stage(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1,
+ mp_obj_t *layers, size_t layers_size,
+ uint16_t *buffer, size_t buffer_size,
+ busio_spi_obj_t *spi) {
+
+ // TODO(deshipu): Do a collision check of each layer with the
+ // rectangle, and only process the layers that overlap with it.
+
+ size_t index = 0;
+ for (uint8_t y = y0; y < y1; ++y) {
+ for (uint8_t x = x0; x < x1; ++x) {
+ for (size_t layer = 0; layer < layers_size; ++layer) {
+ uint16_t c = TRANSPARENT;
+ layer_obj_t *obj = MP_OBJ_TO_PTR(layers[layer]);
+ if (obj->base.type == &mp_type_layer) {
+ c = get_layer_pixel(obj, x, y);
+ } else if (obj->base.type == &mp_type_text) {
+ c = get_text_pixel((text_obj_t *)obj, x, y);
+ }
+ if (c != TRANSPARENT) {
+ buffer[index] = c;
+ break;
+ }
+ }
+ index += 1;
+ // The buffer is full, send it.
+ if (index >= buffer_size) {
+ if (!common_hal_busio_spi_write(spi,
+ ((uint8_t*)buffer), buffer_size * 2)) {
+ return false;
+ }
+ index = 0;
+ }
+ }
+ }
+ // Send the remaining data.
+ if (index) {
+ if (!common_hal_busio_spi_write(spi, ((uint8_t*)buffer), index * 2)) {
+ return false;
+ }
+ }
+ return true;
+}
diff --git a/shared-module/_stage/__init__.h b/shared-module/_stage/__init__.h
new file mode 100644
index 000000000..326c72559
--- /dev/null
+++ b/shared-module/_stage/__init__.h
@@ -0,0 +1,42 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Radomir Dopieralski
+ *
+ * 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_SHARED_MODULE__STAGE_H
+#define MICROPY_INCLUDED_SHARED_MODULE__STAGE_H
+
+#include "shared-bindings/busio/SPI.h"
+#include <stdint.h>
+#include <stdbool.h>
+#include "py/obj.h"
+
+#define TRANSPARENT (0x1ff8)
+
+bool render_stage(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1,
+ mp_obj_t *layers, size_t layers_size,
+ uint16_t *buffer, size_t buffer_size,
+ busio_spi_obj_t *spi);
+
+#endif // MICROPY_INCLUDED_SHARED_MODULE__STAGE
diff --git a/tools/build_adafruit_bins.sh b/tools/build_adafruit_bins.sh
index ae9c256d2..4c5be2c85 100755
--- a/tools/build_adafruit_bins.sh
+++ b/tools/build_adafruit_bins.sh
@@ -2,7 +2,7 @@ rm -rf ports/atmel-samd/build*
rm -rf ports/esp8266/build*
rm -rf ports/nrf/build*
-ATMEL_BOARDS="arduino_zero circuitplayground_express feather_m0_basic feather_m0_adalogger feather_m0_express metro_m0_express metro_m4_express trinket_m0 gemma_m0 feather52"
+ATMEL_BOARDS="arduino_zero circuitplayground_express feather_m0_basic feather_m0_adalogger itsybitsy_m0 feather_m0_express metro_m0_express metro_m4_express trinket_m0 gemma_m0 feather52"
ROSIE_SETUPS="rosie-ci"
PARALLEL="-j 5"
diff --git a/tools/preprocess_frozen_modules.py b/tools/preprocess_frozen_modules.py
new file mode 100755
index 000000000..0233fba61
--- /dev/null
+++ b/tools/preprocess_frozen_modules.py
@@ -0,0 +1,71 @@
+#!/usr/bin/env python3
+import argparse
+import os
+import os.path
+from pathlib import Path
+import semver
+import subprocess
+
+# Compatible with Python 3.4 due to travis using trusty as default.
+
+def version_string(path=None, *, valid_semver=False):
+ version = None
+ try:
+ tag = subprocess.check_output('git describe --tags --exact-match', shell=True, cwd=path)
+ version = tag.strip().decode("utf-8", "strict")
+ except subprocess.CalledProcessError:
+ describe = subprocess.check_output("git describe --tags", shell=True, cwd=path)
+ tag, additional_commits, commitish = describe.strip().decode("utf-8", "strict").rsplit("-", maxsplit=2)
+ commitish = commitish[1:]
+ if valid_semver:
+ version_info = semver.parse_version_info(tag)
+ if not version_info.prerelease:
+ version = semver.bump_patch(tag) + "-alpha.0.plus." + additional_commits + "+" + commitish
+ else:
+ version = tag + ".plus." + additional_commits + "+" + commitish
+ else:
+ version = commitish
+ return version
+
+# Visit all the .py files in topdir. Replace any __version__ = "0.0.0-auto.0" type of info
+# with actual version info derived from git.
+def copy_and_process(in_dir, out_dir):
+ for root, subdirs, files in os.walk(in_dir):
+
+ # Skip library examples directories.
+ if Path(root).name == 'examples':
+ continue
+
+ for file in files:
+ # Skip top-level setup.py (module install info) and conf.py (sphinx config),
+ # which are not part of the library
+ if (root == in_dir) and file in ('conf.py', 'setup.py'):
+ continue
+
+ input_file_path = Path(root, file)
+ output_file_path = Path(out_dir, input_file_path.relative_to(in_dir))
+
+ if file.endswith(".py"):
+ if not output_file_path.parent.exists():
+ output_file_path.parent.mkdir(parents=True)
+ with input_file_path.open("r") as input, output_file_path.open("w") as output:
+ for line in input:
+ if line.startswith("__version__"):
+ module_version = version_string(root, valid_semver=True)
+ line = line.replace("0.0.0-auto.0", module_version)
+ output.write(line)
+
+if __name__ == '__main__':
+ argparser = argparse.ArgumentParser(description="""\
+ Copy and pre-process .py files into output directory, before freezing.
+ 1. Remove top-level repo directory.
+ 2. Update __version__ info.
+ 3. Remove examples.
+ 4. Remove non-library setup.py and conf.py""")
+ argparser.add_argument("in_dirs", metavar="input-dir", nargs="+",
+ help="top-level code dirs (may be git repo dirs)")
+ argparser.add_argument("-o", "--out_dir", help="output directory")
+ args = argparser.parse_args()
+
+ for in_dir in args.in_dirs:
+ copy_and_process(in_dir, args.out_dir)
diff --git a/tools/python-semver b/tools/python-semver
new file mode 160000
+Subproject 2001c62d1a0361c44acc7076d8ce91e1d1c6614